diff options
author | Olivier Verriest <verri@x25.pm> | 2017-07-30 14:07:43 +0000 |
---|---|---|
committer | Anders Broman <a.broman58@gmail.com> | 2017-08-04 05:57:20 +0000 |
commit | 97dcf87a868a51502e1ea6a90cd7a9ee3bbc59cf (patch) | |
tree | 515ca0088d46d38596809d6d4957ecff20ba7120 /epan/dissectors/asn1 | |
parent | dc69a8446ee47fd6d38d4fb4416db89ef5487696 (diff) |
SNMP: add support for USM SHA-2 algorithms (RFC 7860)
Generlize the USM handling and add support for HMAC-SHA-2 authentication
protocols.
Change-Id: I7cca2f24db61620423fded078c680322aff86400
Reviewed-on: https://code.wireshark.org/review/22846
Reviewed-by: Jaap Keuter <jaap.keuter@xs4all.nl>
Petri-Dish: Jaap Keuter <jaap.keuter@xs4all.nl>
Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org>
Reviewed-by: Anders Broman <a.broman58@gmail.com>
Diffstat (limited to 'epan/dissectors/asn1')
-rw-r--r-- | epan/dissectors/asn1/snmp/packet-snmp-template.c | 287 | ||||
-rw-r--r-- | epan/dissectors/asn1/snmp/packet-snmp-template.h | 15 | ||||
-rw-r--r-- | epan/dissectors/asn1/snmp/snmp.cnf | 6 |
3 files changed, 104 insertions, 204 deletions
diff --git a/epan/dissectors/asn1/snmp/packet-snmp-template.c b/epan/dissectors/asn1/snmp/packet-snmp-template.c index 95f8e53066..79b433320d 100644 --- a/epan/dissectors/asn1/snmp/packet-snmp-template.c +++ b/epan/dissectors/asn1/snmp/packet-snmp-template.c @@ -89,28 +89,52 @@ void proto_reg_handoff_snmp(void); void proto_register_smux(void); void proto_reg_handoff_smux(void); -static gboolean snmp_usm_auth_md5(snmp_usm_params_t* p, guint8**, guint*, gchar const**); -static gboolean snmp_usm_auth_sha1(snmp_usm_params_t* p, guint8**, guint*, gchar const**); +static void snmp_usm_password_to_key(const snmp_usm_auth_model_t model, const guint8 *password, guint passwordlen, + const guint8 *engineID, guint engineLength, guint8 *key); static tvbuff_t* snmp_usm_priv_des(snmp_usm_params_t*, tvbuff_t*, packet_info *pinfo, gchar const**); static tvbuff_t* snmp_usm_priv_aes128(snmp_usm_params_t*, tvbuff_t*, packet_info *pinfo, gchar const**); static tvbuff_t* snmp_usm_priv_aes192(snmp_usm_params_t*, tvbuff_t*, packet_info *pinfo, gchar const**); static tvbuff_t* snmp_usm_priv_aes256(snmp_usm_params_t*, tvbuff_t*, packet_info *pinfo, gchar const**); +static gboolean snmp_usm_auth(const snmp_usm_auth_model_t model, snmp_usm_params_t* p, guint8**, guint*, gchar const**); -static void snmp_usm_password_to_key_md5(const guint8 *password, guint passwordlen, const guint8 *engineID, guint engineLength, guint8 *key); -static void snmp_usm_password_to_key_sha1(const guint8 *password, guint passwordlen, const guint8 *engineID, guint engineLength, guint8 *key); +static const value_string auth_types[] = { + {SNMP_USM_AUTH_MD5,"MD5"}, + {SNMP_USM_AUTH_SHA1,"SHA1"}, + {SNMP_USM_AUTH_SHA2_224,"SHA2-224"}, + {SNMP_USM_AUTH_SHA2_256,"SHA2-256"}, + {SNMP_USM_AUTH_SHA2_384,"SHA2-384"}, + {SNMP_USM_AUTH_SHA2_512,"SHA2-512"}, + {0,NULL} +}; +static const guint auth_hash_len[] = { + HASH_MD5_LENGTH, + HASH_SHA1_LENGTH, + HASH_SHA2_224_LENGTH, + HASH_SHA2_256_LENGTH, + HASH_SHA2_384_LENGTH, + HASH_SHA2_512_LENGTH +}; -static snmp_usm_auth_model_t model_md5 = {snmp_usm_password_to_key_md5, snmp_usm_auth_md5, 16}; -static snmp_usm_auth_model_t model_sha1 = {snmp_usm_password_to_key_sha1, snmp_usm_auth_sha1, 20}; +static const guint auth_tag_len[] = { + 12, + 12, + 16, + 24, + 32, + 48 +}; -static const value_string auth_types[] = { - {0,"MD5"}, - {1,"SHA1"}, - {0,NULL} +static const enum gcry_md_algos auth_hash_algo[] = { + GCRY_MD_MD5, + GCRY_MD_SHA1, + GCRY_MD_SHA224, + GCRY_MD_SHA256, + GCRY_MD_SHA384, + GCRY_MD_SHA512 }; -static snmp_usm_auth_model_t* auth_models[] = {&model_md5,&model_sha1}; #define PRIV_DES 0 #define PRIV_AES128 1 @@ -1225,15 +1249,16 @@ dissect_snmp_engineid(proto_tree *tree, packet_info *pinfo, tvbuff_t *tvb, int o static void set_ue_keys(snmp_ue_assoc_t* n ) { - guint key_size = n->user.authModel->key_size; + guint key_size = auth_hash_len[n->user.authModel]; n->user.authKey.data = (guint8 *)g_malloc(key_size); n->user.authKey.len = key_size; - n->user.authModel->pass2key(n->user.authPassword.data, - n->user.authPassword.len, - n->engine.data, - n->engine.len, - n->user.authKey.data); + snmp_usm_password_to_key(n->user.authModel, + n->user.authPassword.data, + n->user.authPassword.len, + n->engine.data, + n->engine.len, + n->user.authKey.data); if (n->priv_proto == PRIV_AES128 || n->priv_proto == PRIV_AES192 || n->priv_proto == PRIV_AES256) { guint need_key_len = @@ -1250,22 +1275,23 @@ static void set_ue_keys(snmp_ue_assoc_t* n ) { n->user.privKey.data = (guint8 *)g_malloc(key_len); n->user.privKey.len = need_key_len; - n->user.authModel->pass2key(n->user.privPassword.data, - n->user.privPassword.len, - n->engine.data, - n->engine.len, - n->user.privKey.data); + snmp_usm_password_to_key(n->user.authModel, + n->user.privPassword.data, + n->user.privPassword.len, + n->engine.data, + n->engine.len, + n->user.privKey.data); key_len = key_size; /* extend key if needed */ while (key_len < need_key_len) { - n->user.authModel->pass2key( - n->user.privKey.data, - key_len, - n->engine.data, - n->engine.len, - n->user.privKey.data + key_len); + snmp_usm_password_to_key(n->user.authModel, + n->user.privKey.data, + key_len, + n->engine.data, + n->engine.len, + n->user.privKey.data + key_len); key_len += key_size; } @@ -1273,11 +1299,12 @@ static void set_ue_keys(snmp_ue_assoc_t* n ) { } else { n->user.privKey.data = (guint8 *)g_malloc(key_size); n->user.privKey.len = key_size; - n->user.authModel->pass2key(n->user.privPassword.data, - n->user.privPassword.len, - n->engine.data, - n->engine.len, - n->user.privKey.data); + snmp_usm_password_to_key(n->user.authModel, + n->user.privPassword.data, + n->user.privPassword.len, + n->engine.data, + n->engine.len, + n->user.privKey.data); } } @@ -1317,7 +1344,7 @@ snmp_users_copy_cb(void* dest, const void* orig, size_t len _U_) snmp_ue_assoc_t* d = (snmp_ue_assoc_t*)dest; d->auth_model = o->auth_model; - d->user.authModel = auth_models[o->auth_model]; + d->user.authModel = (snmp_usm_auth_model_t) o->auth_model; d->priv_proto = o->priv_proto; d->user.privProtocol = priv_protos[o->priv_proto]; @@ -1520,7 +1547,8 @@ get_user_assoc(tvbuff_t* engine_tvb, tvbuff_t* user_tvb) } static gboolean -snmp_usm_auth_md5(snmp_usm_params_t* p, guint8** calc_auth_p, guint* calc_auth_len_p, gchar const** error) +snmp_usm_auth(const snmp_usm_auth_model_t model, snmp_usm_params_t* p, guint8** calc_auth_p, + guint* calc_auth_len_p, gchar const** error) { gint msg_len; guint8* msg; @@ -1546,10 +1574,9 @@ snmp_usm_auth_md5(snmp_usm_params_t* p, guint8** calc_auth_p, guint* calc_auth_l return FALSE; } - auth_len = tvb_captured_length(p->auth_tvb); - if (auth_len != 12) { + if (auth_len != auth_tag_len[model]) { *error = "Authenticator length wrong"; return FALSE; } @@ -1561,93 +1588,26 @@ snmp_usm_auth_md5(snmp_usm_params_t* p, guint8** calc_auth_p, guint* calc_auth_l } msg = (guint8*)tvb_memdup(wmem_packet_scope(),p->msg_tvb,0,msg_len); - auth = (guint8*)tvb_memdup(wmem_packet_scope(),p->auth_tvb,0,auth_len); start = p->auth_offset - p->start_offset; - end = start + auth_len; + end = start + auth_len; /* fill the authenticator with zeros */ for ( i = start ; i < end ; i++ ) { msg[i] = '\0'; } - calc_auth = (guint8*)wmem_alloc(wmem_packet_scope(), HASH_MD5_LENGTH); + calc_auth = (guint8*)wmem_alloc(wmem_packet_scope(), auth_hash_len[model]); - if (ws_hmac_buffer(GCRY_MD_MD5, calc_auth, msg, msg_len, key, key_len)) { + if (ws_hmac_buffer(auth_hash_algo[model], calc_auth, msg, msg_len, key, key_len)) { return FALSE; } if (calc_auth_p) *calc_auth_p = calc_auth; - if (calc_auth_len_p) *calc_auth_len_p = 12; + if (calc_auth_len_p) *calc_auth_len_p = auth_len; - return ( memcmp(auth,calc_auth,12) != 0 ) ? FALSE : TRUE; -} - - -static gboolean -snmp_usm_auth_sha1(snmp_usm_params_t* p _U_, guint8** calc_auth_p, guint* calc_auth_len_p, gchar const** error _U_) -{ - gint msg_len; - guint8* msg; - guint auth_len; - guint8* auth; - guint8* key; - guint key_len; - guint8 *calc_auth; - guint start; - guint end; - guint i; - - if (!p->auth_tvb) { - *error = "No Authenticator"; - return FALSE; - } - - key = p->user_assoc->user.authKey.data; - key_len = p->user_assoc->user.authKey.len; - - if (! key ) { - *error = "User has no authKey"; - return FALSE; - } - - - auth_len = tvb_captured_length(p->auth_tvb); - - - if (auth_len != 12) { - *error = "Authenticator length wrong"; - return FALSE; - } - - msg_len = tvb_captured_length(p->msg_tvb); - if (msg_len <= 0) { - *error = "Not enough data remaining"; - return FALSE; - } - msg = (guint8*)tvb_memdup(wmem_packet_scope(),p->msg_tvb,0,msg_len); - - auth = (guint8*)tvb_memdup(wmem_packet_scope(),p->auth_tvb,0,auth_len); - - start = p->auth_offset - p->start_offset; - end = start + auth_len; - - /* fill the authenticator with zeros */ - for ( i = start ; i < end ; i++ ) { - msg[i] = '\0'; - } - - calc_auth = (guint8*)wmem_alloc(wmem_packet_scope(), HASH_SHA1_LENGTH); - - if (ws_hmac_buffer(GCRY_MD_SHA1, calc_auth, msg, msg_len, key, key_len)) { - return FALSE; - } - - if (calc_auth_p) *calc_auth_p = calc_auth; - if (calc_auth_len_p) *calc_auth_len_p = 12; - - return ( memcmp(auth,calc_auth,12) != 0 ) ? FALSE : TRUE; + return ( memcmp(auth,calc_auth,auth_len) != 0 ) ? FALSE : TRUE; } static tvbuff_t* @@ -2122,86 +2082,26 @@ dissect_smux(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) return dissect_SMUX_PDUs_PDU(tvb, pinfo, smux_tree, data); } - /* - MD5 Password to Key Algorithm - from RFC 3414 A.2.1 + MD5 Password to Key Algorithm from RFC 3414 A.2.1 + SHA1 Password to Key Algorithm from RFC 3414 A.2.2 + SHA2 Password to Key Algorithm from RFC 7860 9.3 */ static void -snmp_usm_password_to_key_md5(const guint8 *password, guint passwordlen, - const guint8 *engineID, guint engineLength, - guint8 *key) +snmp_usm_password_to_key(const snmp_usm_auth_model_t model, const guint8 *password, + guint passwordlen, const guint8 *engineID, guint engineLength, guint8 *key) { - guint8 *cp, password_buf[64]; - guint32 password_index = 0; - guint32 count = 0, i; - guint8 key1[16]; - gcry_md_hd_t md5_handle; - if (gcry_md_open(&md5_handle, GCRY_MD_MD5, 0)) { - return; - } + gcry_md_hd_t hash_handle; + guint8 *cp, password_buf[64]; + guint32 password_index = 0; + guint32 count = 0, i; + guint hash_len; - /**********************************************/ - /* Use while loop until we've done 1 Megabyte */ - /**********************************************/ - while (count < 1048576) { - cp = password_buf; - if (passwordlen != 0) { - for (i = 0; i < 64; i++) { - /*************************************************/ - /* Take the next octet of the password, wrapping */ - /* to the beginning of the password as necessary.*/ - /*************************************************/ - *cp++ = password[password_index++ % passwordlen]; - } - } else { - *cp = 0; - } - gcry_md_write(md5_handle, password_buf, 64); - count += 64; - } - memcpy(key1, gcry_md_read(md5_handle, 0), HASH_MD5_LENGTH); - gcry_md_close(md5_handle); - - /*****************************************************/ - /* Now localize the key with the engineID and pass */ - /* through MD5 to produce final key */ - /* We ignore invalid engineLengths here. More strict */ - /* checking is done in snmp_users_update_cb. */ - /*****************************************************/ - - if (gcry_md_open(&md5_handle, GCRY_MD_MD5, 0)) { + if (gcry_md_open(&hash_handle, auth_hash_algo[model], 0)) { return; } - gcry_md_write(md5_handle, key1, HASH_MD5_LENGTH); - gcry_md_write(md5_handle, engineID, engineLength); - gcry_md_write(md5_handle, key1, HASH_MD5_LENGTH); - memcpy(key, gcry_md_read(md5_handle, 0), HASH_MD5_LENGTH); - gcry_md_close(md5_handle); - - return; -} - - - -/* - SHA1 Password to Key Algorithm COPIED from RFC 3414 A.2.2 - */ - -static void -snmp_usm_password_to_key_sha1(const guint8 *password, guint passwordlen, - const guint8 *engineID, guint engineLength, - guint8 *key) -{ - gcry_md_hd_t sha1_handle; - guint8 *cp, password_buf[64]; - guint32 password_index = 0; - guint32 count = 0, i; - - if (gcry_md_open(&sha1_handle, GCRY_MD_SHA1, 0)) { - return; - } + hash_len = auth_hash_len[model]; /**********************************************/ /* Use while loop until we've done 1 Megabyte */ @@ -2219,29 +2119,28 @@ snmp_usm_password_to_key_sha1(const guint8 *password, guint passwordlen, } else { *cp = 0; } - gcry_md_write(sha1_handle, password_buf, 64); + gcry_md_write(hash_handle, password_buf, 64); count += 64; } - memcpy(key, gcry_md_read(sha1_handle, 0), HASH_SHA1_LENGTH); - gcry_md_close(sha1_handle); + memcpy(key, gcry_md_read(hash_handle, 0), hash_len); + gcry_md_close(hash_handle); /*****************************************************/ - /* Now localize the key with the engineID and pass */ - /* through SHA to produce final key */ + /* Now localise the key with the engineID and pass */ + /* through hash function to produce final key */ /* We ignore invalid engineLengths here. More strict */ /* checking is done in snmp_users_update_cb. */ /*****************************************************/ - if (gcry_md_open(&sha1_handle, GCRY_MD_SHA1, 0)) { + if (gcry_md_open(&hash_handle, auth_hash_algo[model], 0)) { return; } - gcry_md_write(sha1_handle, key, HASH_SHA1_LENGTH); - gcry_md_write(sha1_handle, engineID, engineLength); - gcry_md_write(sha1_handle, key, HASH_SHA1_LENGTH); - memcpy(key, gcry_md_read(sha1_handle, 0), HASH_SHA1_LENGTH); - gcry_md_close(sha1_handle); + gcry_md_write(hash_handle, key, hash_len); + gcry_md_write(hash_handle, engineID, engineLength); + gcry_md_write(hash_handle, key, hash_len); + memcpy(key, gcry_md_read(hash_handle, 0), hash_len); + gcry_md_close(hash_handle); return; - } - +} static void process_prefs(void) diff --git a/epan/dissectors/asn1/snmp/packet-snmp-template.h b/epan/dissectors/asn1/snmp/packet-snmp-template.h index 808b078406..0b516a384a 100644 --- a/epan/dissectors/asn1/snmp/packet-snmp-template.h +++ b/epan/dissectors/asn1/snmp/packet-snmp-template.h @@ -31,20 +31,21 @@ typedef struct _snmp_usm_key { typedef struct _snmp_ue_assoc_t snmp_ue_assoc_t; typedef struct _snmp_usm_params_t snmp_usm_params_t; -typedef gboolean (*snmp_usm_authenticator_t)(snmp_usm_params_t*, guint8** calc_auth, guint* calc_auth_len, gchar const** error); typedef tvbuff_t* (*snmp_usm_decoder_t)(snmp_usm_params_t*, tvbuff_t* encryptedData, packet_info *pinfo, gchar const** error); -typedef void (*snmp_usm_password_to_key_t)(const guint8 *password, guint passwordlen, const guint8 *engineID, guint engineLength, guint8 *key); -typedef struct _snmp_usm_auth_model_t { - snmp_usm_password_to_key_t pass2key; - snmp_usm_authenticator_t authenticate; - guint key_size; +typedef enum _snmp_usm_auth_model_t { + SNMP_USM_AUTH_MD5 = 0, + SNMP_USM_AUTH_SHA1, + SNMP_USM_AUTH_SHA2_224, + SNMP_USM_AUTH_SHA2_256, + SNMP_USM_AUTH_SHA2_384, + SNMP_USM_AUTH_SHA2_512 } snmp_usm_auth_model_t; typedef struct _snmp_user_t { snmp_usm_key_t userName; - snmp_usm_auth_model_t* authModel; + snmp_usm_auth_model_t authModel; snmp_usm_key_t authPassword; snmp_usm_key_t authKey; diff --git a/epan/dissectors/asn1/snmp/snmp.cnf b/epan/dissectors/asn1/snmp/snmp.cnf index ee9dba9326..b717d06d83 100644 --- a/epan/dissectors/asn1/snmp/snmp.cnf +++ b/epan/dissectors/asn1/snmp/snmp.cnf @@ -186,10 +186,10 @@ gint pdu_type=-1; const gchar* error = NULL; proto_item* authen_item; proto_tree* authen_tree = proto_item_add_subtree(usm_p.auth_item,ett_authParameters); - guint8* calc_auth; - guint calc_auth_len; + guint8* calc_auth = NULL; + guint calc_auth_len = 0; - usm_p.authOK = usm_p.user_assoc->user.authModel->authenticate( &usm_p, &calc_auth, &calc_auth_len, &error ); + usm_p.authOK = snmp_usm_auth(usm_p.user_assoc->user.authModel, &usm_p, &calc_auth, &calc_auth_len, &error ); if (error) { expert_add_info_format( actx->pinfo, usm_p.auth_item, &ei_snmp_verify_authentication_error, "Error while verifying Message authenticity: %s", error ); |