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>
This commit is contained in:
Olivier Verriest 2017-07-30 14:07:43 +00:00 committed by Anders Broman
parent dc69a8446e
commit 97dcf87a86
6 changed files with 223 additions and 419 deletions

View File

@ -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 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 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 gboolean snmp_usm_auth(const snmp_usm_auth_model_t model, snmp_usm_params_t* p, guint8**, guint*, gchar const**);
static const value_string auth_types[] = {
{0,"MD5"},
{1,"SHA1"},
{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 snmp_usm_auth_model_t* auth_models[] = {&model_md5,&model_sha1};
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 const guint auth_tag_len[] = {
12,
12,
16,
24,
32,
48
};
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
};
#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,77 +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) {
*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_MD5_LENGTH);
if (ws_hmac_buffer(GCRY_MD_MD5, 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;
}
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) {
if (auth_len != auth_tag_len[model]) {
*error = "Authenticator length wrong";
return FALSE;
}
@ -1631,23 +1591,23 @@ snmp_usm_auth_sha1(snmp_usm_params_t* p _U_, guint8** calc_auth_p, guint* calc_a
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_SHA1_LENGTH);
calc_auth = (guint8*)wmem_alloc(wmem_packet_scope(), auth_hash_len[model]);
if (ws_hmac_buffer(GCRY_MD_SHA1, 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;
return ( memcmp(auth,calc_auth,auth_len) != 0 ) ? FALSE : TRUE;
}
static tvbuff_t*
@ -2122,25 +2082,27 @@ 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)) {
gcry_md_hd_t hash_handle;
guint8 *cp, password_buf[64];
guint32 password_index = 0;
guint32 count = 0, i;
guint hash_len;
if (gcry_md_open(&hash_handle, auth_hash_algo[model], 0)) {
return;
}
hash_len = auth_hash_len[model];
/**********************************************/
/* Use while loop until we've done 1 Megabyte */
/**********************************************/
@ -2157,92 +2119,29 @@ snmp_usm_password_to_key_md5(const guint8 *password, guint passwordlen,
} else {
*cp = 0;
}
gcry_md_write(md5_handle, password_buf, 64);
gcry_md_write(hash_handle, password_buf, 64);
count += 64;
}
memcpy(key1, gcry_md_read(md5_handle, 0), HASH_MD5_LENGTH);
gcry_md_close(md5_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 MD5 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(&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);
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;
}
/*
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;
}
/**********************************************/
/* 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(sha1_handle, password_buf, 64);
count += 64;
}
memcpy(key, gcry_md_read(sha1_handle, 0), HASH_SHA1_LENGTH);
gcry_md_close(sha1_handle);
/*****************************************************/
/* Now localize the key with the engineID and pass */
/* through SHA 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)) {
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);
return;
}
static void
process_prefs(void)
{

View File

@ -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;

View File

@ -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 );

View File

@ -97,28 +97,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 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 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 gboolean snmp_usm_auth(const snmp_usm_auth_model_t model, snmp_usm_params_t* p, guint8**, guint*, gchar const**);
static const value_string auth_types[] = {
{0,"MD5"},
{1,"SHA1"},
{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 snmp_usm_auth_model_t* auth_models[] = {&model_md5,&model_sha1};
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 const guint auth_tag_len[] = {
12,
12,
16,
24,
32,
48
};
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
};
#define PRIV_DES 0
#define PRIV_AES128 1
@ -291,7 +315,7 @@ static int hf_snmp_priority = -1; /* INTEGER_M1_2147483647 */
static int hf_snmp_operation = -1; /* T_operation */
/*--- End of included file: packet-snmp-hf.c ---*/
#line 217 "./asn1/snmp/packet-snmp-template.c"
#line 241 "./asn1/snmp/packet-snmp-template.c"
/* Initialize the subtree pointers */
static gint ett_smux = -1;
@ -331,7 +355,7 @@ static gint ett_snmp_SimpleOpen_U = -1;
static gint ett_snmp_RReqPDU_U = -1;
/*--- End of included file: packet-snmp-ett.c ---*/
#line 233 "./asn1/snmp/packet-snmp-template.c"
#line 257 "./asn1/snmp/packet-snmp-template.c"
static expert_field ei_snmp_failed_decrypted_data_pdu = EI_INIT;
static expert_field ei_snmp_decrypted_data_bad_formatted = EI_INIT;
@ -1327,15 +1351,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 =
@ -1352,22 +1377,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;
}
@ -1375,11 +1401,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);
}
}
@ -1419,7 +1446,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];
@ -1622,7 +1649,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;
@ -1648,77 +1676,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) {
*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_MD5_LENGTH);
if (ws_hmac_buffer(GCRY_MD_MD5, 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;
}
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) {
if (auth_len != auth_tag_len[model]) {
*error = "Authenticator length wrong";
return FALSE;
}
@ -1733,23 +1693,23 @@ snmp_usm_auth_sha1(snmp_usm_params_t* p _U_, guint8** calc_auth_p, guint* calc_a
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_SHA1_LENGTH);
calc_auth = (guint8*)wmem_alloc(wmem_packet_scope(), auth_hash_len[model]);
if (ws_hmac_buffer(GCRY_MD_SHA1, 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;
return ( memcmp(auth,calc_auth,auth_len) != 0 ) ? FALSE : TRUE;
}
static tvbuff_t*
@ -2742,10 +2702,10 @@ dissect_snmp_SNMPv3Message(gboolean implicit_tag _U_, tvbuff_t *tvb _U_, int off
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 );
@ -3048,7 +3008,7 @@ static int dissect_SMUX_PDUs_PDU(tvbuff_t *tvb _U_, packet_info *pinfo _U_, prot
/*--- End of included file: packet-snmp-fn.c ---*/
#line 1843 "./asn1/snmp/packet-snmp-template.c"
#line 1803 "./asn1/snmp/packet-snmp-template.c"
guint
@ -3331,25 +3291,27 @@ 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)) {
gcry_md_hd_t hash_handle;
guint8 *cp, password_buf[64];
guint32 password_index = 0;
guint32 count = 0, i;
guint hash_len;
if (gcry_md_open(&hash_handle, auth_hash_algo[model], 0)) {
return;
}
hash_len = auth_hash_len[model];
/**********************************************/
/* Use while loop until we've done 1 Megabyte */
/**********************************************/
@ -3366,92 +3328,29 @@ snmp_usm_password_to_key_md5(const guint8 *password, guint passwordlen,
} else {
*cp = 0;
}
gcry_md_write(md5_handle, password_buf, 64);
gcry_md_write(hash_handle, password_buf, 64);
count += 64;
}
memcpy(key1, gcry_md_read(md5_handle, 0), HASH_MD5_LENGTH);
gcry_md_close(md5_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 MD5 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(&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);
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;
}
/*
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;
}
/**********************************************/
/* 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(sha1_handle, password_buf, 64);
count += 64;
}
memcpy(key, gcry_md_read(sha1_handle, 0), HASH_SHA1_LENGTH);
gcry_md_close(sha1_handle);
/*****************************************************/
/* Now localize the key with the engineID and pass */
/* through SHA 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)) {
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);
return;
}
static void
process_prefs(void)
{
@ -3876,7 +3775,7 @@ void proto_register_snmp(void) {
NULL, HFILL }},
/*--- End of included file: packet-snmp-hfarr.c ---*/
#line 2406 "./asn1/snmp/packet-snmp-template.c"
#line 2305 "./asn1/snmp/packet-snmp-template.c"
};
/* List of subtrees */
@ -3916,7 +3815,7 @@ void proto_register_snmp(void) {
&ett_snmp_RReqPDU_U,
/*--- End of included file: packet-snmp-ettarr.c ---*/
#line 2422 "./asn1/snmp/packet-snmp-template.c"
#line 2321 "./asn1/snmp/packet-snmp-template.c"
};
static ei_register_info ei[] = {
{ &ei_snmp_failed_decrypted_data_pdu, { "snmp.failed_decrypted_data_pdu", PI_MALFORMED, PI_WARN, "Failed to decrypt encryptedPDU", EXPFILL }},

View File

@ -39,20 +39,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;

View File

@ -37,8 +37,12 @@ DIAG_OFF(deprecated-declarations)
DIAG_ON(deprecated-declarations)
#define HASH_MD5_LENGTH 16
#define HASH_SHA1_LENGTH 20
#define HASH_MD5_LENGTH 16
#define HASH_SHA1_LENGTH 20
#define HASH_SHA2_224_LENGTH 28
#define HASH_SHA2_256_LENGTH 32
#define HASH_SHA2_384_LENGTH 48
#define HASH_SHA2_512_LENGTH 64
/* Convenience function to calculate the HMAC from the data in BUFFER
of size LENGTH with key KEY of size KEYLEN using the algorithm ALGO avoiding the creating of a