initial AES support.
git-svn-id: file:///home/hardaker/lib/sf-bkups/net-snmp-convert-svnrepo/trunk@7470 06827809-a52a-0410-b366-d66718629ded
diff --git a/include/net-snmp/library/transform_oids.h b/include/net-snmp/library/transform_oids.h
index 7539e9d..071a2d7 100644
--- a/include/net-snmp/library/transform_oids.h
+++ b/include/net-snmp/library/transform_oids.h
@@ -16,12 +16,21 @@
extern oid usmNoPrivProtocol[10]; /* == { 1,3,6,1,6,3,10,1,2,1 }; */
extern oid usmDESPrivProtocol[10]; /* == { 1,3,6,1,6,3,10,1,2,2 }; */
+/* XXX: OIDs not defined yet */
+extern oid usmAES128PrivProtocol[10]; /* == { XXX, 1, 2 }; */
+extern oid usmAES192PrivProtocol[10]; /* == { XXX, 1, 3 }; */
+extern oid usmAES256PrivProtocol[10]; /* == { XXX, 1, 4 }; */
+
#define USM_AUTH_PROTO_NOAUTH_LEN 10
#define USM_AUTH_PROTO_MD5_LEN 10
#define USM_AUTH_PROTO_SHA_LEN 10
#define USM_PRIV_PROTO_NOPRIV_LEN 10
#define USM_PRIV_PROTO_DES_LEN 10
+#define USM_PRIV_PROTO_AES128_LEN 10
+#define USM_PRIV_PROTO_AES192_LEN 10
+#define USM_PRIV_PROTO_AES256_LEN 10
+
#ifdef __cplusplus
}
#endif
diff --git a/snmplib/snmp_parse_args.c b/snmplib/snmp_parse_args.c
index d3591c0..58d85d7 100644
--- a/snmplib/snmp_parse_args.c
+++ b/snmplib/snmp_parse_args.c
@@ -103,7 +103,11 @@
" -l LEVEL\t\tset security level (noAuthNoPriv|authNoPriv|authPriv)\n");
fprintf(outf, " -n CONTEXT\t\tset context name (e.g. bridge1)\n");
fprintf(outf, " -u USER-NAME\t\tset security name (e.g. bert)\n");
+#ifdef HAVE_AES
+ fprintf(outf, " -x PROTOCOL\t\tset privacy protocol (DES|AES)\n");
+#else
fprintf(outf, " -x PROTOCOL\t\tset privacy protocol (DES)\n");
+#endif
fprintf(outf, " -X PASSPHRASE\t\tset privacy protocol pass phrase\n");
fprintf(outf,
" -Z BOOTS,TIME\t\tset destination engine boots/time\n");
@@ -449,6 +453,17 @@
if (!strcasecmp(optarg, "DES")) {
session->securityPrivProto = usmDESPrivProtocol;
session->securityPrivProtoLen = USM_PRIV_PROTO_DES_LEN;
+#ifdef HAVE_AES
+ } else if (!strcasecmp(optarg, "AES128")) {
+ session->securityPrivProto = usmAES128PrivProtocol;
+ session->securityPrivProtoLen = USM_PRIV_PROTO_AES128_LEN;
+ } else if (!strcasecmp(optarg, "AES192")) {
+ session->securityPrivProto = usmAES192PrivProtocol;
+ session->securityPrivProtoLen = USM_PRIV_PROTO_AES192_LEN;
+ } else if (!strcasecmp(optarg, "AES256")) {
+ session->securityPrivProto = usmAES256PrivProtocol;
+ session->securityPrivProtoLen = USM_PRIV_PROTO_AES256_LEN;
+#endif
} else {
fprintf(stderr,
"Invalid privacy protocol specified after -x flag: %s\n",
diff --git a/snmplib/snmpusm.c b/snmplib/snmpusm.c
index 3905c46..649cff9 100644
--- a/snmplib/snmpusm.c
+++ b/snmplib/snmpusm.c
@@ -71,6 +71,9 @@
{ 1, 3, 6, 1, 6, 3, 10, 1, 1, 3 };
oid usmNoPrivProtocol[10] = { 1, 3, 6, 1, 6, 3, 10, 1, 2, 1 };
oid usmDESPrivProtocol[10] = { 1, 3, 6, 1, 6, 3, 10, 1, 2, 2 };
+oid usmAES128PrivProtocol[10] = { 1, 3, 6, 1, 4, 1, 8072, 876,876,128 };
+oid usmAES192PrivProtocol[10] = { 1, 3, 6, 1, 4, 1, 8072, 876,876,192 };
+oid usmAES256PrivProtocol[10] = { 1, 3, 6, 1, 4, 1, 8072, 876,876,256 };
static u_int dummy_etime, dummy_eboot; /* For ISENGINEKNOWN(). */
@@ -78,6 +81,9 @@
* Globals.
*/
static u_int salt_integer;
+#ifdef HAVE_AES
+static u_int salt_integer64_1, salt_integer64_2;
+#endif
/*
* 1/2 of seed for the salt. Cf. RFC2274, Sect 8.1.1.1.
*/
@@ -583,7 +589,7 @@
size_t * iv_length,
u_char * priv_salt, size_t priv_salt_length, u_char * msgSalt)
{
- size_t propersize_salt = BYTESIZE(USM_MAX_SALT_LENGTH);
+ size_t propersize_salt = BYTESIZE(USM_DES_SALT_LENGTH);
int net_boots;
int net_salt_int;
/*
@@ -625,6 +631,66 @@
} /* end usm_set_salt() */
+#ifdef HAVE_AES
+/*******************************************************************-o-******
+ * usm_set_aes_iv
+ *
+ * Parameters:
+ * *iv (O) Buffer to contain IV.
+ * *iv_length (O) Length of iv.
+ * net_boots (I) the network byte order of the authEng boots val
+ * net_time (I) the network byte order of the authEng time val
+ * *salt (O) A buffer for the outgoing salt (= 8 bytes of iv)
+ *
+ * Returns:
+ * 0 On success,
+ * -1 Otherwise.
+ *
+ * Determine the initialization vector for AES encryption.
+ * (draft-blumenthal-aes-usm-03.txt, 3.1.2.2)
+ *
+ * iv is defined as the concatenation of engineBoots, engineTime
+ and a 64 bit salt-integer.
+ * The 64 bit salt integer is incremented.
+ * The resulting salt is copied into the salt buffer.
+ * The IV result is returned individually for further use.
+ */
+int
+usm_set_aes_iv(u_char * iv,
+ size_t * iv_length,
+ u_int net_boots,
+ u_int net_time,
+ u_char * salt)
+{
+ /*
+ * net_* should be encoded in network byte order.
+ */
+ int net_salt_int1, net_salt_int2;
+#define PROPER_AES_IV_SIZE 64
+
+ /*
+ * Sanity check.
+ */
+ if (!iv || !iv_length) {
+ return -1;
+ }
+
+ net_salt_int1 = htonl(salt_integer64_1);
+ net_salt_int2 = htonl(salt_integer64_2);
+
+ if ((salt_integer64_2 += 1) == 0)
+ salt_integer64_2 += 1;
+
+ /* XXX: warning: hard coded proper lengths */
+ memcpy(iv, &net_boots, 4);
+ memcpy(iv+4, &net_time, 4);
+ memcpy(iv+8, &net_salt_int1, 4);
+ memcpy(iv+12, &net_salt_int2, 4);
+
+ memcpy(salt, iv+8, 8); /* only copy the needed portion */
+ return 0;
+} /* end usm_set_salt() */
+#endif /* HAVE_AES */
int
usm_secmod_generate_out_msg(struct snmp_secmod_outgoing_params *parms)
@@ -931,6 +997,20 @@
/*
* XXX Hardwired to seek into a 1DES private key!
*/
+#ifdef HAVE_AES
+ if (ISTRANSFORM(thePrivProtocol, AES128Priv) &&
+ ISTRANSFORM(thePrivProtocol, AES192Priv) &&
+ ISTRANSFORM(thePrivProtocol, AES256Priv)) {
+ if (!thePrivKey ||
+ usm_set_aes_iv(salt, &salt_length,
+ htonl(boots_uint), htonl(time_uint),
+ &ptr[privParamsOffset]) == -1) {
+ DEBUGMSGTL(("usm", "Can't set AES iv.\n"));
+ usm_free_usmStateReference(secStateRef);
+ return SNMPERR_USM_GENERICERROR;
+ }
+ } else if (ISTRANSFORM(thePrivProtocol, DESPriv)) {
+#endif
if (!thePrivKey ||
(usm_set_salt(salt, &salt_length,
thePrivKey + 8, thePrivKeyLength - 8,
@@ -940,6 +1020,9 @@
usm_free_usmStateReference(secStateRef);
return SNMPERR_USM_GENERICERROR;
}
+#ifdef HAVE_AES
+ }
+#endif
if (sc_encrypt(thePrivProtocol, thePrivProtocolLength,
thePrivKey, thePrivKeyLength,
@@ -1252,7 +1335,7 @@
u_int thePrivProtocolLength = 0;
int theSecLevel = 0; /* No defined const for bad
* value (other then err). */
- size_t salt_length = 0;
+ size_t salt_length = 0, save_salt_length = 0, save_salt_offset = 0;
u_char salt[BYTESIZE(USM_MAX_SALT_LENGTH)];
u_char authParams[USM_MAX_AUTHSIZE];
u_char iv[BYTESIZE(USM_MAX_SALT_LENGTH)];
@@ -1395,16 +1478,39 @@
/*
* XXX Hardwired to seek into a 1DES private key!
*/
- salt_length = BYTESIZE(USM_MAX_SALT_LENGTH);
- if (!thePrivKey || (usm_set_salt(salt, &salt_length,
- thePrivKey + 8,
- thePrivKeyLength - 8,
- iv) == -1)) {
- DEBUGMSGTL(("usm", "Can't set DES-CBC salt.\n"));
- usm_free_usmStateReference(secStateRef);
- free(ciphertext);
- return SNMPERR_USM_GENERICERROR;
+#ifdef HAVE_AES
+ if (ISTRANSFORM(thePrivProtocol, AES128Priv) ||
+ ISTRANSFORM(thePrivProtocol, AES192Priv) ||
+ ISTRANSFORM(thePrivProtocol, AES256Priv)) {
+ salt_length = BYTESIZE(USM_AES_SALT_LENGTH);
+ save_salt_length = BYTESIZE(USM_AES_SALT_LENGTH)/2;
+ save_salt_offset = 0;
+ if (!thePrivKey ||
+ usm_set_aes_iv(salt, &salt_length,
+ htonl(boots_uint), htonl(time_uint),
+ iv) == -1) {
+ DEBUGMSGTL(("usm", "Can't set AES iv.\n"));
+ usm_free_usmStateReference(secStateRef);
+ free(ciphertext);
+ return SNMPERR_USM_GENERICERROR;
+ }
+ } else if (ISTRANSFORM(thePrivProtocol, DESPriv)) {
+#endif
+ salt_length = BYTESIZE(USM_DES_SALT_LENGTH);
+ save_salt_length = BYTESIZE(USM_DES_SALT_LENGTH);
+ save_salt_offset = 0;
+ if (!thePrivKey || (usm_set_salt(salt, &salt_length,
+ thePrivKey + 8,
+ thePrivKeyLength - 8,
+ iv) == -1)) {
+ DEBUGMSGTL(("usm", "Can't set DES-CBC salt.\n"));
+ usm_free_usmStateReference(secStateRef);
+ free(ciphertext);
+ return SNMPERR_USM_GENERICERROR;
+ }
+#ifdef HAVE_AES
}
+#endif
#ifdef SNMP_TESTING_CODE
if (debug_is_token_registered("usm/dump") == SNMPERR_SUCCESS) {
dump_chunk("usm/dump", "This data was encrypted:",
@@ -1465,8 +1571,9 @@
*/
rc = asn_realloc_rbuild_string(wholeMsg, wholeMsgLen, offset, 1,
(u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE
- | ASN_OCTET_STR), iv,
- salt_length);
+ | ASN_OCTET_STR),
+ iv,
+ save_salt_length);
DEBUGINDENTLESS();
if (rc == 0) {
DEBUGMSGTL(("usm", "building privParams failed.\n"));
@@ -2152,8 +2259,8 @@
{ /* IN - v3 Message flags. */
size_t remaining = wholeMsgLen - (u_int)
((u_long) * secParams - (u_long) * wholeMsg);
- u_int boots_uint;
- u_int time_uint;
+ u_int boots_uint, net_boots;
+ u_int time_uint, net_time;
u_char signature[BYTESIZE(USM_MAX_KEYEDHASH_LENGTH)];
size_t signature_length = BYTESIZE(USM_MAX_KEYEDHASH_LENGTH);
u_char salt[BYTESIZE(USM_MAX_SALT_LENGTH)];
@@ -2418,37 +2525,52 @@
return SNMPERR_USM_PARSEERROR;
}
- /*
- * From RFC2574:
- *
- * "Before decryption, the encrypted data length is verified.
- * If the length of the OCTET STRING to be decrypted is not
- * an integral multiple of 8 octets, the decryption process
- * is halted and an appropriate exception noted."
- */
+ if (ISTRANSFORM(user->privProtocol, DESPriv)) {
+ /*
+ * From RFC2574:
+ *
+ * "Before decryption, the encrypted data length is verified.
+ * If the length of the OCTET STRING to be decrypted is not
+ * an integral multiple of 8 octets, the decryption process
+ * is halted and an appropriate exception noted."
+ */
- if (remaining % 8 != 0) {
- DEBUGMSGTL(("usm",
- "Ciphertext is %lu bytes, not an integer multiple of 8 (rem %d)\n",
- remaining, remaining % 8));
- if (snmp_increment_statistic(STAT_USMSTATSDECRYPTIONERRORS) ==
- 0) {
- DEBUGMSGTL(("usm", "%s\n", "Failed increment statistic."));
+ if (remaining % 8 != 0) {
+ DEBUGMSGTL(("usm",
+ "Ciphertext is %lu bytes, not an integer multiple of 8 (rem %d)\n",
+ remaining, remaining % 8));
+ if (snmp_increment_statistic(STAT_USMSTATSDECRYPTIONERRORS) ==
+ 0) {
+ DEBUGMSGTL(("usm", "%s\n", "Failed increment statistic."));
+ }
+ usm_free_usmStateReference(*secStateRef);
+ *secStateRef = NULL;
+ return SNMPERR_USM_DECRYPTIONERROR;
}
- usm_free_usmStateReference(*secStateRef);
- *secStateRef = NULL;
- return SNMPERR_USM_DECRYPTIONERROR;
+
+ end_of_overhead = value_ptr;
+
+ /*
+ * XOR the salt with the last (iv_length) bytes
+ * of the priv_key to obtain the IV.
+ */
+ iv_length = BYTESIZE(USM_DES_SALT_LENGTH);
+ for (i = 0; i < (int) iv_length; i++)
+ iv[i] = salt[i] ^ user->privKey[iv_length + i];
}
-
- end_of_overhead = value_ptr;
-
- /*
- * XOR the salt with the last (iv_length) bytes
- * of the priv_key to obtain the IV.
- */
- for (i = 0; i < (int) iv_length; i++)
- iv[i] = salt[i] ^ user->privKey[iv_length + i];
-
+#ifdef HAVE_AES
+ else if (ISTRANSFORM(user->privProtocol, AES128Priv) ||
+ ISTRANSFORM(user->privProtocol, AES192Priv) ||
+ ISTRANSFORM(user->privProtocol, AES256Priv)) {
+ iv_length = BYTESIZE(USM_AES_SALT_LENGTH);
+ net_boots = ntohl(boots_uint);
+ net_time = ntohl(time_uint);
+ memcpy(iv, &net_boots, 4);
+ memcpy(iv+4, &net_time, 4);
+ memcpy(iv+8, salt, salt_length);
+ }
+#endif
+
if (sc_decrypt(user->privProtocol, user->privProtocolLen,
user->privKey, user->privKeyLen,
iv, iv_length,
@@ -2472,7 +2594,6 @@
}
#endif
}
-
/*
* sPDU is plaintext.
*/
@@ -2544,9 +2665,23 @@
SNMPERR_SUCCESS) {
DEBUGMSGTL(("usm", "sc_random() failed: using time() as salt.\n"));
salt_integer = (u_int) time(NULL);
- salt_integer_len = sizeof(salt_integer);
}
+#ifdef HAVE_AES
+ salt_integer_len = sizeof (salt_integer64_1);
+ if (sc_random((u_char *) & salt_integer64_1, &salt_integer_len) !=
+ SNMPERR_SUCCESS) {
+ DEBUGMSGTL(("usm", "sc_random() failed: using time() as aes1 salt.\n"));
+ salt_integer64_1 = (u_int) time(NULL);
+ }
+ salt_integer_len = sizeof (salt_integer64_1);
+ if (sc_random((u_char *) & salt_integer64_2, &salt_integer_len) !=
+ SNMPERR_SUCCESS) {
+ DEBUGMSGTL(("usm", "sc_random() failed: using time() as aes2 salt.\n"));
+ salt_integer64_2 = (u_int) time(NULL);
+ }
+#endif
+
noNameUser = usm_create_initial_user("", usmHMACMD5AuthProtocol,
USM_LENGTH_OID_TRANSFORM,
usmDESPrivProtocol,
diff --git a/snmplib/snmpv3.c b/snmplib/snmpv3.c
index deb0d47..a579d87 100644
--- a/snmplib/snmpv3.c
+++ b/snmplib/snmpv3.c
@@ -126,7 +126,16 @@
snmpv3_privtype_conf(const char *word, char *cptr)
{
if (strcasecmp(cptr, "DES") == 0)
- defaultPrivType = SNMP_DEFAULT_PRIV_PROTO;
+ defaultPrivType = usmDESPrivProtocol;
+#if HAVE_AES
+ /* XXX AES: assumes oid length == des oid length */
+ else if (strcasecmp(cptr, "AES128") == 0)
+ defaultPrivType = usmAES128PrivProtocol;
+ else if (strcasecmp(cptr, "AES192") == 0)
+ defaultPrivType = usmAES192PrivProtocol;
+ else if (strcasecmp(cptr, "AES256") == 0)
+ defaultPrivType = usmAES256PrivProtocol;
+#endif
else
config_perror("Unknown privacy type");
defaultPrivTypeLen = SNMP_DEFAULT_PRIV_PROTOLEN;
@@ -320,6 +329,17 @@
if (!strcasecmp(optarg, "DES")) {
session->securityPrivProto = usmDESPrivProtocol;
session->securityPrivProtoLen = USM_PRIV_PROTO_DES_LEN;
+#ifdef HAVE_AES
+ } else if (!strcasecmp(optarg, "AES128")) {
+ session->securityPrivProto = usmAES128PrivProtocol;
+ session->securityPrivProtoLen = USM_PRIV_PROTO_AES128_LEN;
+ } else if (!strcasecmp(optarg, "AES192")) {
+ session->securityPrivProto = usmAES192PrivProtocol;
+ session->securityPrivProtoLen = USM_PRIV_PROTO_AES192_LEN;
+ } else if (!strcasecmp(optarg, "AES256")) {
+ session->securityPrivProto = usmAES256PrivProtocol;
+ session->securityPrivProtoLen = USM_PRIV_PROTO_AES256_LEN;
+#endif
} else {
fprintf(stderr,
"Invalid privacy protocol specified after -3x flag: %s\n",
@@ -714,6 +734,17 @@
if (strncmp(cp, "DES", 3) == 0) {
memcpy(newuser->privProtocol, usmDESPrivProtocol,
sizeof(usmDESPrivProtocol));
+#ifdef HAVE_AES
+ } else if (strncmp(cp, "AES128", 3) == 0) {
+ memcpy(newuser->privProtocol, usmAES128PrivProtocol,
+ sizeof(usmAES128PrivProtocol));
+ } else if (strncmp(cp, "AES192", 3) == 0) {
+ memcpy(newuser->privProtocol, usmAES192PrivProtocol,
+ sizeof(usmAES192PrivProtocol));
+ } else if (strncmp(cp, "AES256", 3) == 0) {
+ memcpy(newuser->privProtocol, usmAES256PrivProtocol,
+ sizeof(usmAES256PrivProtocol));
+#endif
} else {
config_perror("Unknown privacy protocol");
usm_free_user(newuser);
@@ -1010,7 +1041,11 @@
NULL, "MD5|SHA");
register_config_handler("snmp", "defPrivType", snmpv3_privtype_conf,
NULL,
- "DES (currently the only possible value)");
+#ifdef HAVE_AES
+ "DES (AES support not available)");
+#else
+ "DES|AES128|AES192|AES256");
+#endif
register_config_handler("snmp", "defSecurityLevel",
snmpv3_secLevel_conf, NULL,
"noAuthNoPriv|authNoPriv|authPriv");