aboutsummaryrefslogtreecommitdiffstats
path: root/asn1
diff options
context:
space:
mode:
authorLuis Ontanon <luis.ontanon@gmail.com>2007-01-09 18:38:55 +0000
committerLuis Ontanon <luis.ontanon@gmail.com>2007-01-09 18:38:55 +0000
commitf7a79f43e7f2b98231c7e64902c1086ec9726549 (patch)
tree3344c1f1304ecd4699a6851d0aae3996780d5fea /asn1
parentd9465f6b1234f7d030e5882ff2448066bb0bf0d3 (diff)
SNMPv3 USM decryption/authentication phase 1
svn path=/trunk/; revision=20353
Diffstat (limited to 'asn1')
-rw-r--r--asn1/snmp/packet-snmp-template.c444
-rw-r--r--asn1/snmp/packet-snmp-template.h73
-rw-r--r--asn1/snmp/snmp.cnf127
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 = &parameter_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