diff options
author | Luis Ontanon <luis.ontanon@gmail.com> | 2007-01-09 18:38:55 +0000 |
---|---|---|
committer | Luis Ontanon <luis.ontanon@gmail.com> | 2007-01-09 18:38:55 +0000 |
commit | f7a79f43e7f2b98231c7e64902c1086ec9726549 (patch) | |
tree | 3344c1f1304ecd4699a6851d0aae3996780d5fea /asn1 | |
parent | d9465f6b1234f7d030e5882ff2448066bb0bf0d3 (diff) |
SNMPv3 USM decryption/authentication phase 1
svn path=/trunk/; revision=20353
Diffstat (limited to 'asn1')
-rw-r--r-- | asn1/snmp/packet-snmp-template.c | 444 | ||||
-rw-r--r-- | asn1/snmp/packet-snmp-template.h | 73 | ||||
-rw-r--r-- | asn1/snmp/snmp.cnf | 127 |
3 files changed, 614 insertions, 30 deletions
diff --git a/asn1/snmp/packet-snmp-template.c b/asn1/snmp/packet-snmp-template.c index 962ea5d708..c67bfdb7d3 100644 --- a/asn1/snmp/packet-snmp-template.c +++ b/asn1/snmp/packet-snmp-template.c @@ -12,6 +12,8 @@ * Updated to use the asn2wrs compiler made by Tomas Kukosa * Copyright (C) 2005 - 2006 Anders Broman [AT] ericsson.com * + * See RFC 3414 for User-based Security Model for SNMPv3 + * Copyright (C) 2007 Luis E. Garcia Ontanon <luis.ontanon@gmail.com> * * $Id$ * @@ -58,8 +60,13 @@ #include <epan/sminmpec.h> #include <epan/emem.h> #include <epan/next_tvb.h> +#include <epan/crypt/hmac.h> +#include <epan/expert.h> +#include <epan/report_err.h> #include "packet-ipx.h" #include "packet-hpext.h" +#include <epan/crypt/airpdcap_sha1.h> +#include <epan/crypt/crypt-md5.h> #include "packet-ber.h" @@ -90,10 +97,14 @@ # define VALTYPE_COUNTER64 ASN_COUNTER64 #endif /* HAVE_NET_SNMP */ - #include "packet-snmp.h" #include "format-oid.h" +#ifdef HAVE_LIBGCRYPT +#include <gcrypt.h> +#endif + + /* Take a pointer that may be null and return a pointer that's not null by turning null pointers into pointers to the above null string, and, if the argument pointer wasn't null, make sure we handle @@ -131,6 +142,11 @@ static const gchar *mib_modules = DEF_MIB_MODULES; static gboolean display_oid = TRUE; static gboolean snmp_var_in_tree = TRUE; +static const gchar* ue_assocs_filename = ""; +static const gchar* ue_assocs_filename_loaded = ""; +static snmp_ue_assoc_t* ue_assocs = NULL; +static snmp_usm_params_t usm_p = {FALSE,FALSE,0,0,NULL,NULL,NULL,NULL,NULL,NULL,NULL}; + /* Subdissector tables */ static dissector_table_t variable_oid_dissector_table; @@ -166,6 +182,8 @@ static int hf_snmp_engineid_text = -1; static int hf_snmp_engineid_time = -1; static int hf_snmp_engineid_data = -1; static int hf_snmp_counter64 = -1; +static int hf_snmp_decryptedPDU = -1; +static int hf_snmp_msgAuthentication = -1; #include "packet-snmp-hf.c" @@ -177,9 +195,18 @@ static gint ett_smux = -1; static gint ett_snmp = -1; static gint ett_engineid = -1; static gint ett_msgFlags = -1; +static gint ett_encryptedPDU = -1; +static gint ett_decrypted = -1; +static gint ett_authParameters = -1; #include "packet-snmp-ett.c" + +static const true_false_string auth_flags = { + "OK", + "Failed" +}; + /* defined in net-SNMP; include/net-snmp/library/snmp.h */ #undef SNMP_MSG_GET #undef SNMP_MSG_SET @@ -822,7 +849,7 @@ snmp_variable_decode(tvbuff_t *tvb, proto_tree *snmp_tree, packet_info *pinfo,tv switch (vb_type) { case SNMP_INTEGER: - offset = dissect_ber_integer(FALSE, pinfo, NULL, tvb, start, -1, &vb_integer_value); + offset = dissect_ber_integer(FALSE, pinfo, NULL, tvb, start, -1, &(vb_integer_value)); length = offset - vb_value_start; if (snmp_tree) { #ifdef HAVE_NET_SNMP @@ -1020,8 +1047,219 @@ snmp_variable_decode(tvbuff_t *tvb, proto_tree *snmp_tree, packet_info *pinfo,tv return; } +static snmp_ue_assoc_t* get_user_assoc(tvbuff_t* engine_tvb, tvbuff_t* user_tvb) { + static snmp_ue_assoc_t* a; + guint given_username_len; + guint8* given_username; + guint given_engine_len; + guint8* given_engine; + + if ( ! ue_assocs ) return NULL; + + if (! ( user_tvb && engine_tvb ) ) return NULL; + + given_username_len = tvb_length_remaining(user_tvb,0); + given_username = ep_tvb_memdup(user_tvb,0,-1); + given_engine_len = tvb_length_remaining(engine_tvb,0); + given_engine = ep_tvb_memdup(engine_tvb,0,-1); + + for(a = ue_assocs; a->user.userName.data; a++) { + guint username_len = a->user.userName.len; + + if ( given_username_len == username_len + && memcmp(a->user.userName.data, given_username, given_username_len) == 0 ) { + + const guint8* engine_data = a->engine.data; + guint engine_len = a->engine.len; + + if ( engine_data ) { + if ( engine_len == given_engine_len + && memcmp(given_engine,engine_data,engine_len) == 0 ) { + return a; + } + } else { + return a; + } + } + } + + return NULL; +} + +#ifdef DEBUG_USM +#define DUMP_DATA(n,b,l) { unsigned i; printf("%s: ",n); for (i=0;i<(unsigned)l;i++) printf("%.2x",b[i]); printf("\n"); } +#define D(p) printf p +#else +#define DUMP_DATA(n,b,l) +#define D(p) +#endif + +gboolean snmp_usm_auth_md5(snmp_usm_params_t* p, gchar** error) { + guint msg_len; + guint8* msg; + guint auth_len; + guint8* auth; + guint8* key; + guint key_len; + guint8 calc_auth[16]; + 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_length_remaining(p->auth_tvb,0); + + if (auth_len != 12) { + *error = "Authenticator length wrong"; + return FALSE; + } + + msg_len = tvb_length_remaining(p->msg_tvb,0); + msg = ep_tvb_memdup(p->msg_tvb,0,msg_len); + + + auth = ep_tvb_memdup(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'; + } + + md5_hmac(msg, msg_len, key, key_len, calc_auth); + + return ( memcmp(auth,calc_auth,12) != 0 ) ? FALSE : TRUE; +} + + +gboolean snmp_usm_auth_sha1(snmp_usm_params_t* p _U_, gchar** error _U_) { + *error = "SHA1 authentication Not Yet Implemented"; + return FALSE; +} + +tvbuff_t* snmp_usm_priv_des(snmp_usm_params_t* p _U_, tvbuff_t* encryptedData _U_, gchar** error _U_) { +#ifdef HAVE_LIBGCRYPT + gcry_error_t err; + gcry_cipher_hd_t hd = NULL; + + guint8* cleartext; + guint8* des_key = p->user_assoc->user.privKey.data; /* first 8 bytes */ + guint8* pre_iv = &(p->user_assoc->user.privKey.data[8]); /* last 8 bytes */ + guint8* salt; + gint salt_len; + gint cryptgrm_len; + guint8* cryptgrm; + tvbuff_t* clear_tvb; + guint8 iv[8];; + guint i; + + + salt_len = tvb_length_remaining(p->priv_tvb,0); + D(("salt_len=%d\n",salt_len)); + + if (salt_len != 8) { + *error = "msgPrivacyParameters lenght != 8"; + return NULL; + } + + salt = ep_tvb_memdup(p->priv_tvb,0,salt_len); + + DUMP_DATA("salt",salt,salt_len); + DUMP_DATA("pre_iv",iv,8); + + /* + The resulting "salt" is XOR-ed with the pre-IV to obtain the IV. + */ + for (i=0; i<8; i++) { + iv[i] = pre_iv[i] ^ salt[i]; + } + + DUMP_DATA("iv",iv,8); + DUMP_DATA("des_key",des_key,8); + + cryptgrm_len = tvb_length_remaining(encryptedData,0); + D(("cryptgrm_len=%d\n",cryptgrm_len)); + + if (cryptgrm_len % 8) { + *error = "the length of the encrypted data is noty a mutiple of 8"; + return NULL; + } + + cryptgrm = ep_tvb_memdup(encryptedData,0,-1); + DUMP_DATA("cryptgrm",cryptgrm,cryptgrm_len); + + cleartext = ep_alloc(cryptgrm_len); + + err = gcry_cipher_open(&hd, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_CBC, 0); + if (err != GPG_ERR_NO_ERROR) goto on_gcry_error; + + err = gcry_cipher_setiv(hd, iv, 8); + if (err != GPG_ERR_NO_ERROR) goto on_gcry_error; + + err = gcry_cipher_setkey(hd,des_key,8); + if (err != GPG_ERR_NO_ERROR) goto on_gcry_error; + + err = gcry_cipher_decrypt(hd, cleartext, cryptgrm_len, cryptgrm, cryptgrm_len); + if (err != GPG_ERR_NO_ERROR) goto on_gcry_error; + + gcry_cipher_close(hd); + + DUMP_DATA("cleartext",cryptgrm,cryptgrm_len); + + /* + ??? + The first ciphertext block is decrypted, the decryption output is + XOR-ed with the Initialization Vector, and the result is the first + plaintext block. + + For each subsequent block, the ciphertext block is decrypted, the + decryption output is XOR-ed with the previous ciphertext block and + the result is the plaintext block. + */ + + + clear_tvb = tvb_new_real_data(cleartext, cryptgrm_len, cryptgrm_len); + + return clear_tvb; + +on_gcry_error: + *error = (void*)gpg_strerror(err); + if (hd) gcry_cipher_close(hd); + return NULL; +#else + *error = "libgcrypt not present, cannot decrypt"; + return NULL; +#endif +} + +tvbuff_t* snmp_usm_priv_aes(snmp_usm_params_t* p _U_, tvbuff_t* encryptedData _U_, gchar** error _U_) { +#ifdef HAVE_LIBGCRYPT + *error = "AES decryption Not Yet Implemented"; + return NULL; +#else + *error = "libgcrypt not present, cannot decrypt"; + return NULL; +#endif +} + #include "packet-snmp-fn.c" + guint dissect_snmp_pdu(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree, int proto, gint ett, gboolean is_tcp) @@ -1039,6 +1277,18 @@ dissect_snmp_pdu(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *snmp_tree = NULL; proto_item *item = NULL; + usm_p.msg_tvb = tvb; + usm_p.start_offset = offset_from_real_beginning(tvb,0) ; + usm_p.engine_tvb = NULL; + usm_p.user_tvb = NULL; + usm_p.auth_item = NULL; + usm_p.auth_tvb = NULL; + usm_p.auth_offset = 0; + usm_p.priv_tvb = NULL; + usm_p.user_assoc = NULL; + usm_p.authenticated = FALSE; + usm_p.encrypted = FALSE; + /* * This will throw an exception if we don't have any data left. * That's what we want. (See "tcp_dissect_pdus()", which is @@ -1268,6 +1518,132 @@ dissect_smux(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) dissect_SMUX_PDUs_PDU(tvb, pinfo, tree); } + +/* + MD5 Password to Key Algorithm + from RFC 3414 A.2.1 +*/ +void snmp_usm_password_to_key_md5( + guint8 *password, /* IN */ + guint passwordlen, /* IN */ + guint8 *engineID, /* IN - pointer to snmpEngineID */ + guint engineLength,/* IN - length of snmpEngineID */ + guint8 *key) /* OUT - pointer to caller 16-octet buffer */ + + { + md5_state_t MD; + guint8 *cp, password_buf[64]; + guint32 password_index = 0; + guint32 count = 0, i; + guint8 key1[16]; + md5_init(&MD); /* initialize MD5 */ + + /**********************************************/ + /* Use while loop until we've done 1 Megabyte */ + /**********************************************/ + while (count < 1048576) { + cp = password_buf; + 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]; + } + md5_append(&MD, password_buf, 64); + count += 64; + } + md5_finish(&MD, key1); /* tell MD5 we're done */ + + /*****************************************************/ + /* Now localize the key with the engineID and pass */ + /* through MD5 to produce final key */ + /* May want to ensure that engineLength <= 32, */ + /* otherwise need to use a buffer larger than 64 */ + /*****************************************************/ + + md5_init(&MD); + md5_append(&MD, key1, 16); + md5_append(&MD, engineID, engineLength); + md5_append(&MD, key1, 16); + md5_finish(&MD, key); + + return; +} + + + + +/* + SHA1 Password to Key Algorithm COPIED from RFC 3414 A.2.2 + */ +#define SHAUpdate(c,b,l) sha1_loop((c),(b),(l)) +#define SHAFinal(d,c) sha1_result((c),(d)) + +void snmp_usm_password_to_key_sha1( + guint8 *password, /* IN */ + guint passwordlen, /* IN */ + guint8 *engineID, /* IN - pointer to snmpEngineID */ + guint engineLength,/* IN - length of snmpEngineID */ + guint8 *key) /* OUT - pointer to caller 20-octet buffer */ + { + SHA1_CONTEXT SH; + guint8 *cp, password_buf[72]; + guint32 password_index = 0; + guint32 count = 0, i; + + sha1_init (&SH); /* initialize SHA */ + + /**********************************************/ + /* Use while loop until we've done 1 Megabyte */ + /**********************************************/ + while (count < 1048576) { + cp = password_buf; + 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]; + } + SHAUpdate (&SH, password_buf, 64); + count += 64; + } + SHAFinal (key, &SH); /* tell SHA we're done */ + + /*****************************************************/ + /* Now localize the key with the engineID and pass */ + /* through SHA to produce final key */ + /* May want to ensure that engineLength <= 32, */ + /* otherwise need to use a buffer larger than 72 */ + /*****************************************************/ + memcpy(password_buf, key, 20); + memcpy(password_buf+20, engineID, engineLength); + memcpy(password_buf+20+engineLength, key, 20); + + sha1_init(&SH); + SHAUpdate(&SH, password_buf, 40+engineLength); + SHAFinal(key, &SH); + return; + } + + + +static void destroy_ue_assocs(snmp_ue_assoc_t* assocs) { + if (assocs) { + snmp_ue_assoc_t* a; + + for(a = assocs; a->user.userName.data; a++) { + g_free(a->user.userName.data); + if (a->user.authKey.data) g_free(a->user.authKey.data); + if (a->user.privKey.data) g_free(a->user.privKey.data); + if (a->engine.data) g_free(a->engine.data); + } + + g_free(ue_assocs); + } +} + static void process_prefs(void) { @@ -1322,17 +1698,55 @@ process_prefs(void) read_configs(); mibs_loaded = TRUE; #endif /* HAVE_NET_SNMP */ + + if ( g_str_equal(ue_assocs_filename_loaded,ue_assocs_filename) ) return; + ue_assocs_filename_loaded = ue_assocs_filename; + + if (ue_assocs) destroy_ue_assocs(ue_assocs); + + if ( *ue_assocs_filename ) { + gchar* err = load_snmp_users_file(ue_assocs_filename,&ue_assocs); + if (err) report_failure("Error while loading SNMP's users file:\n%s",err); + } + +#ifdef DUMP_USMDATA + { + GString* s = g_string_new(">>"); + g_string_sprintfa(s,"File: %s\n",ue_assocs_filename); + +#define DUMP(s,n,b,l) { unsigned i; g_string_sprintfa(s,"%s: ",n); for (i=0;i<l;i++) g_string_sprintfa(s,"%.2x",b[i]); g_string_sprintfa(s,"\n"); } + if (ue_assocs) { + snmp_ue_assoc_t* a; + + for(a = ue_assocs; a->user.userName.data; a++) { + if (a->engine.data) DUMP(s,"engine",a->engine.data,a->engine.len); + DUMP(s,"userName",a->user.userName.data,a->user.userName.len); + DUMP(s,"authPassword",a->user.authPassword.data,a->user.authPassword.len); + if (a->user.authKey.data) DUMP(s,"authKey",a->user.authKey.data,a->user.authKey.len); + DUMP(s,"privPassword",a->user.privPassword.data,a->user.privPassword.len); + if (a->user.privKey.data) DUMP(s,"privKey",a->user.privKey.data,a->user.privKey.len); + g_string_sprintfa(s,"\n"); + } + + } + + report_failure("%s",s->str); + g_string_free(s,TRUE); + } +#endif } -/*--- proto_register_snmp -------------------------------------------*/ -void proto_register_snmp(void) { - + + + + /*--- proto_register_snmp -------------------------------------------*/ +void proto_register_snmp(void) { #if defined(_WIN32) && defined(HAVE_NET_SNMP) char *mib_path; int mib_path_len; #define MIB_PATH_APPEND "snmp\\mibs" #endif gchar *tmp_mib_modules; - + /* List of fields */ static hf_register_info hf[] = { { &hf_snmp_v3_flags_auth, @@ -1374,7 +1788,13 @@ void proto_register_snmp(void) { { &hf_snmp_counter64, { "Value", "snmp.counter64", FT_INT64, BASE_DEC, NULL, 0, "A counter64 value", HFILL }}, - + { &hf_snmp_msgAuthentication, + { "Authentication OK", "snmp.v3.authOK", FT_BOOLEAN, 8, + TFS(&auth_flags), 0, "", HFILL }}, + { &hf_snmp_decryptedPDU, { + "Decrypted PDU", "snmp.decryptedPdu", FT_BYTES, BASE_HEX, + NULL, 0, "Decrypted PDU", HFILL }}, + #include "packet-snmp-hfarr.c" }; @@ -1383,7 +1803,10 @@ void proto_register_snmp(void) { &ett_snmp, &ett_engineid, &ett_msgFlags, - + &ett_encryptedPDU, + &ett_decrypted, + &ett_authParameters, + #include "packet-snmp-ettarr.c" }; module_t *snmp_module; @@ -1459,6 +1882,11 @@ void proto_register_snmp(void) { "ON - display dissected variables inside SNMP tree, OFF - display dissected variables in root tree after SNMP", &snmp_var_in_tree); + prefs_register_string_preference(snmp_module, "users_file", + "USMuserTable", + "The filename of the user table used for authentication/decryption", + &ue_assocs_filename); + variable_oid_dissector_table = register_dissector_table("snmp.variable_oid", "SNMP Variable OID", FT_STRING, BASE_NONE); diff --git a/asn1/snmp/packet-snmp-template.h b/asn1/snmp/packet-snmp-template.h index 60db62ca31..5c99f70d8e 100644 --- a/asn1/snmp/packet-snmp-template.h +++ b/asn1/snmp/packet-snmp-template.h @@ -25,6 +25,61 @@ #ifndef PACKET_SNMP_H #define PACKET_SNMP_H +typedef struct _snmp_usm_key { + guint8* data; + guint len; +} snmp_usm_key_t; + +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*, gchar** error); +typedef tvbuff_t* (*snmp_usm_decoder_t)(snmp_usm_params_t*, tvbuff_t* encryptedData, gchar** error); +typedef void (*snmp_usm_password_to_key_t)(guint8 *password, guint passwordlen, 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; +} snmp_usm_auth_model_t; + +typedef struct _snmp_user_t { + snmp_usm_key_t userName; + + snmp_usm_auth_model_t* authModel; + snmp_usm_key_t authPassword; + snmp_usm_key_t authKey; + + snmp_usm_decoder_t privProtocol; + snmp_usm_key_t privPassword; + snmp_usm_key_t privKey; +} snmp_user_t; + +typedef struct { + guint8* data; + guint len; +} snmp_engine_id_t; + +struct _snmp_ue_assoc_t { + snmp_user_t user; + snmp_engine_id_t engine; +}; + +struct _snmp_usm_params_t { + gboolean authenticated; + gboolean encrypted; + guint start_offset; + guint auth_offset; + + tvbuff_t* engine_tvb; + tvbuff_t* user_tvb; + proto_item* auth_item; + tvbuff_t* auth_tvb; + tvbuff_t* priv_tvb; + tvbuff_t* msg_tvb; + snmp_ue_assoc_t* user_assoc; +}; + /* * Guts of the SNMP dissector - exported for use by protocols such as * ILMI. @@ -33,6 +88,24 @@ extern guint dissect_snmp_pdu(tvbuff_t *, int, packet_info *, proto_tree *tree, int, gint, gboolean); extern int dissect_snmp_engineid(proto_tree *, tvbuff_t *, int, int); +/* SNMPv3 USM authentication functions */ +gboolean snmp_usm_auth_md5(snmp_usm_params_t* p, gchar**); +gboolean snmp_usm_auth_sha1(snmp_usm_params_t* p, gchar**); + +/* SNMPv3 USM privacy functions */ +tvbuff_t* snmp_usm_priv_des(snmp_usm_params_t*, tvbuff_t*, gchar**); +tvbuff_t* snmp_usm_priv_aes(snmp_usm_params_t*, tvbuff_t*, gchar**); + + +void snmp_usm_password_to_key_md5(guint8 *password, guint passwordlen, guint8 *engineID, guint engineLength, guint8 *key); +void snmp_usm_password_to_key_sha1(guint8 *password, guint passwordlen, guint8 *engineID, guint engineLength, guint8 *key); + + +/* defined in load_snmp_users_file.l */ +/* returns NULL when OK or else the error string */ +extern gchar* load_snmp_users_file(const char* filename, snmp_ue_assoc_t** assocs); + + /*#include "packet-snmp-exp.h"*/ #endif /* PACKET_SNMP_H */ diff --git a/asn1/snmp/snmp.cnf b/asn1/snmp/snmp.cnf index 7803ec938e..9af11329e7 100644 --- a/asn1/snmp/snmp.cnf +++ b/asn1/snmp/snmp.cnf @@ -8,6 +8,13 @@ SMUX-PDUs #.NO_EMIT +GetNextRequest-PDU +GetResponse-PDU +SetRequest-PDU +GetRequest-PDU +Gauge32 +NotificationName +SnmpEngineID #.TYPE_RENAME @@ -20,7 +27,6 @@ BulkPDU/request-id bulkPDU_request-id VAL_PTR = &pdu_type #.FN_BODY PDUs - gint pdu_type; %(DEFAULT_BODY)s @@ -167,32 +173,105 @@ gint pdu_type; VAL_PTR = &MsgSecurityModel -#.FN_BODY SNMPv3Message/msgSecurityParameters +#.FN_BODY UsmSecurityParameters/msgAuthoritativeEngineID + tvbuff_t *parameter_tvb = NULL; - switch(MsgSecurityModel){ - case SNMP_SEC_USM: /* 3 */ - offset = dissect_snmp_UsmSecurityParameters(FALSE, tvb, offset+2, pinfo, tree, -1); - break; - case SNMP_SEC_ANY: /* 0 */ - case SNMP_SEC_V1: /* 1 */ - case SNMP_SEC_V2C: /* 2 */ - default: - %(DEFAULT_BODY)s - break; + offset = dissect_ber_octet_string(implicit_tag, pinfo, tree, tvb, offset, hf_index, + &usm_p.engine_tvb); + if (parameter_tvb) { + proto_tree* engine_tree = proto_item_add_subtree(get_ber_last_created_item(),ett_engineid); + dissect_snmp_engineid(engine_tree, usm_p.engine_tvb, 0, tvb_length_remaining(usm_p.engine_tvb,0)); } -#.FN_PARS SnmpEngineID +#.FN_PARS UsmSecurityParameters/msgUserName + VAL_PTR = &usm_p.user_tvb + +#.FN_BODY UsmSecurityParameters/msgAuthenticationParameters + offset = dissect_ber_octet_string(FALSE, pinfo, tree, tvb, offset, hf_index, &usm_p.auth_tvb); + if (usm_p.auth_tvb) { + usm_p.auth_item = get_ber_last_created_item(); + usm_p.auth_offset = offset_from_real_beginning(usm_p.auth_tvb,0); + } +#.FN_PARS UsmSecurityParameters/msgPrivacyParameters + VAL_PTR = &usm_p.priv_tvb + +#.FN_BODY ScopedPduData/encryptedPDU + tvbuff_t* crypt_tvb; + offset = dissect_ber_octet_string(FALSE, pinfo, tree, tvb, offset, hf_snmp_encryptedPDU, &crypt_tvb); + + if( usm_p.encrypted && crypt_tvb + && usm_p.user_assoc + && usm_p.user_assoc->user.privProtocol ) { + gchar* error = NULL; + + tvbuff_t* cleartext_tvb = usm_p.user_assoc->user.privProtocol(&usm_p, + crypt_tvb, + &error ); + + if (! cleartext_tvb) { + proto_item* item = get_ber_last_created_item(); + expert_add_info_format( pinfo, item, PI_UNDECODED, PI_WARN, "Failed to decrypt encryptedPDU: %%s", error ); + } else { + proto_tree* decrypted_tree = proto_item_add_subtree(get_ber_last_created_item(),ett_decrypted); + + add_new_data_source(pinfo, cleartext_tvb, "Decrypted ScopedPDU"); + tvb_set_child_real_data_tvbuff(tvb, cleartext_tvb); + dissect_snmp_ScopedPDU(FALSE, cleartext_tvb, 0, pinfo, decrypted_tree, -1); + } - VAL_PTR = ¶meter_tvb + } -#.FN_BODY SnmpEngineID - tvbuff_t *parameter_tvb = NULL; - proto_tree *engineid_tree = NULL; - proto_item *item = NULL; +#.FN_BODY SNMPv3Message/msgSecurityParameters - %(DEFAULT_BODY)s - if (parameter_tvb) - dissect_snmp_engineid(tree, parameter_tvb, 0, tvb_length_remaining(parameter_tvb,0)); +// printf(">msgSecurityParameters\n"); + switch(MsgSecurityModel){ + case SNMP_SEC_USM: /* 3 */ + offset = dissect_snmp_UsmSecurityParameters(FALSE, tvb, offset+2, pinfo, tree, -1); + usm_p.user_assoc = get_user_assoc(usm_p.engine_tvb, usm_p.user_tvb); + break; + case SNMP_SEC_ANY: /* 0 */ + case SNMP_SEC_V1: /* 1 */ + case SNMP_SEC_V2C: /* 2 */ + default: + %(DEFAULT_BODY)s + break; + } + +#.FN_FTR SNMPv3Message + + if( usm_p.authenticated + && usm_p.user_assoc + && usm_p.user_assoc->user.authModel ) { + gchar* error = NULL; + proto_item* authen_item; + proto_tree* authen_tree = proto_item_add_subtree(usm_p.auth_item,ett_authParameters); + + gboolean authen_ok = usm_p.user_assoc->user.authModel->authenticate( + &usm_p, + &error ); + + if (error) { + authen_item = proto_tree_add_text(authen_tree,tvb,0,0,"Error while verifying Messsage authenticity: %s", error); + PROTO_ITEM_SET_GENERATED(authen_item); + expert_add_info_format( pinfo, authen_item, PI_MALFORMED, PI_ERROR, "Error while verifying Messsage authenticity: %s", error ); + } else { + int severity; + gchar* fmt; + + authen_item = proto_tree_add_boolean(authen_tree, hf_snmp_msgAuthentication, tvb, 0, 0, authen_ok); + PROTO_ITEM_SET_GENERATED(authen_item); + + if (authen_ok) { + fmt = "SNMP Authentication OK"; + severity = PI_CHAT; + } else { + fmt = "SNMP Authentication Error"; + severity = PI_WARN; + } + + expert_add_info_format( pinfo, authen_item, PI_CHECKSUM, severity, fmt ); + } + } #.FN_PARS HeaderData/msgFlags @@ -203,10 +282,14 @@ gint pdu_type; %(DEFAULT_BODY)s if (parameter_tvb){ - + guint8 v3_flags = tvb_get_guint8(parameter_tvb, 0); + proto_tree_add_item(tree, hf_snmp_v3_flags_report, parameter_tvb, 0, 1, FALSE); proto_tree_add_item(tree, hf_snmp_v3_flags_crypt, parameter_tvb, 0, 1, FALSE); proto_tree_add_item(tree, hf_snmp_v3_flags_auth, parameter_tvb, 0, 1, FALSE); + + usm_p.encrypted = v3_flags & TH_CRYPT ? TRUE : FALSE; + usm_p.authenticated = v3_flags & TH_AUTH ? TRUE : FALSE; } #.FN_BODY VarBind |