diff --git a/src/Filelists.mk b/src/Filelists.mk index 2f5d54ff..024150c5 100644 --- a/src/Filelists.mk +++ b/src/Filelists.mk @@ -142,7 +142,9 @@ SNMPFILES=$(LWIPDIR)/apps/snmp/snmp_asn1.c \ $(LWIPDIR)/apps/snmp/snmp_scalar.c \ $(LWIPDIR)/apps/snmp/snmp_table.c \ $(LWIPDIR)/apps/snmp/snmp_threadsync.c \ - $(LWIPDIR)/apps/snmp/snmp_traps.c + $(LWIPDIR)/apps/snmp/snmp_traps.c \ + $(LWIPDIR)/apps/snmp/snmpv3_mbedtls.c \ + $(LWIPDIR)/apps/snmp/snmpv3_dummy.c # HTTPDFILES: HTTP server HTTPDFILES=$(LWIPDIR)/apps/httpd/fs.c \ diff --git a/src/apps/snmp/snmp_msg.c b/src/apps/snmp/snmp_msg.c index afd1d654..6cca814e 100644 --- a/src/apps/snmp/snmp_msg.c +++ b/src/apps/snmp/snmp_msg.c @@ -45,15 +45,16 @@ #include "lwip/ip_addr.h" #include "lwip/stats.h" -#include - #if LWIP_SNMP_V3 -#include "snmpv3.h" +#include "lwip/apps/snmpv3.h" +#include "snmpv3_priv.h" #ifdef LWIP_SNMPV3_INCLUDE_ENGINE #include LWIP_SNMPV3_INCLUDE_ENGINE #endif #endif +#include + /* public (non-static) constants */ /** SNMP community string */ const char *snmp_community = SNMP_COMMUNITY; @@ -734,7 +735,7 @@ snmp_parse_inbound_frame(struct snmp_request *request) &u16_value, SNMP_V3_MAX_USER_LENGTH)); request->msg_user_name_len = u16_value; /* TODO: Implement unknown user error response */ - IF_PARSE_EXEC(LWIP_SNMPV3_GET_USER(request->msg_user_name, NULL, NULL, NULL, NULL)); + IF_PARSE_EXEC(snmpv3_get_user((char*)request->msg_user_name, NULL, NULL, NULL, NULL)); /* msgAuthenticationParameters */ memset(request->msg_authentication_parameters, 0, SNMP_V3_MAX_AUTH_PARAM_LENGTH); @@ -750,7 +751,7 @@ snmp_parse_inbound_frame(struct snmp_request *request) IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_authentication_parameters, &u16_value, tlv.value_len)); -#ifdef LWIP_SNMP_V3_CRYPTO +#if LWIP_SNMP_V3_CRYPTO if (request->msg_flags & SNMP_V3_AUTH_FLAG) { /* Rewind stream */ IF_PARSE_EXEC(snmp_pbuf_stream_init(&pbuf_stream, request->inbound_pbuf, 0, request->inbound_pbuf->tot_len)); @@ -760,13 +761,13 @@ snmp_parse_inbound_frame(struct snmp_request *request) IF_PARSE_EXEC(snmp_asn1_enc_raw(&pbuf_stream, zero_arr, tlv.value_len)); /* Verify authentication */ - u8_t* key; + u8_t key[20]; u8_t algo; - u8_t hmac[20]; + u8_t hmac[LWIP_MAX(SNMP_V3_SHA_LEN, SNMP_V3_MD5_LEN)]; struct snmp_pbuf_stream auth_stream; IF_PARSE_EXEC(snmp_pbuf_stream_init(&auth_stream, request->inbound_pbuf, 0, request->inbound_pbuf->tot_len)); - IF_PARSE_EXEC(LWIP_SNMPV3_GET_USER(request->msg_user_name, &algo, &key, NULL, NULL)); + IF_PARSE_EXEC(snmpv3_get_user((char*)request->msg_user_name, &algo, key, NULL, NULL)); IF_PARSE_EXEC(snmpv3_auth(&auth_stream, request->inbound_pbuf->tot_len, key, algo, hmac)); /* TODO: Implement error response */ IF_PARSE_EXEC(memcmp(request->msg_authentication_parameters, hmac, SNMP_V3_MAX_AUTH_PARAM_LENGTH)); @@ -788,10 +789,10 @@ snmp_parse_inbound_frame(struct snmp_request *request) IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_privacy_parameters, &u16_value, SNMP_V3_MAX_PRIV_PARAM_LENGTH)); -#ifdef LWIP_SNMP_V3_CRYPTO +#if LWIP_SNMP_V3_CRYPTO /* Decrypt message */ if (request->msg_flags & SNMP_V3_PRIV_FLAG) { - u8_t* key; + u8_t key[20]; u8_t algo; IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); @@ -799,7 +800,7 @@ snmp_parse_inbound_frame(struct snmp_request *request) parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv); IF_PARSE_ASSERT(parent_tlv_value_len > 0); - IF_PARSE_EXEC(LWIP_SNMPV3_GET_USER(request->msg_user_name, NULL, NULL, &algo, &key)); + IF_PARSE_EXEC(snmpv3_get_user((char*)request->msg_user_name, NULL, NULL, &algo, key)); IF_PARSE_EXEC(snmpv3_crypt(&pbuf_stream, tlv.value_len, key, request->msg_privacy_parameters, request->msg_authoritative_engine_boots, request->msg_authoritative_engine_time, algo, SNMP_V3_PRIV_MODE_DECRYPT)); @@ -1004,6 +1005,8 @@ snmp_prepare_outbound_frame(struct snmp_request *request) OF_BUILD_EXEC( snmp_asn1_enc_raw(pbuf_stream, request->community, request->community_strlen) ); #if LWIP_SNMP_V3 } else { + const char* id; + /* globalData */ request->outbound_msg_global_data_offset = pbuf_stream->offset; SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, 0); @@ -1045,8 +1048,8 @@ snmp_prepare_outbound_frame(struct snmp_request *request) OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); /* msgAuthoritativeEngineID */ - request->msg_authoritative_engine_id_len = LWIP_SNMPV3_GET_ENGINE_ID_LEN(); - memcpy(request->msg_authoritative_engine_id, LWIP_SNMPV3_GET_ENGINE_ID(), request->msg_authoritative_engine_id_len); + snmpv3_get_engine_id(&id, &request->msg_authoritative_engine_id_len); + memcpy(request->msg_authoritative_engine_id, id, request->msg_authoritative_engine_id_len); SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->msg_authoritative_engine_id_len); OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_authoritative_engine_id, request->msg_authoritative_engine_id_len)); @@ -1071,7 +1074,7 @@ snmp_prepare_outbound_frame(struct snmp_request *request) OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_user_name, request->msg_user_name_len)); -#ifdef LWIP_SNMP_V3_CRYPTO +#if LWIP_SNMP_V3_CRYPTO /* msgAuthenticationParameters */ if (request->msg_flags & SNMP_V3_AUTH_FLAG) { memset(request->msg_authentication_parameters, 0, SNMP_V3_MAX_AUTH_PARAM_LENGTH); @@ -1086,7 +1089,7 @@ snmp_prepare_outbound_frame(struct snmp_request *request) OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); } -#ifdef LWIP_SNMP_V3_CRYPTO +#if LWIP_SNMP_V3_CRYPTO /* msgPrivacyParameters */ if (request->msg_flags & SNMP_V3_PRIV_FLAG) { snmpv3_build_priv_param(request->msg_privacy_parameters); @@ -1104,7 +1107,7 @@ snmp_prepare_outbound_frame(struct snmp_request *request) /* End of msgSecurityParameters, so we can calculate the length of this sequence later */ request->outbound_msg_security_parameters_end = pbuf_stream->offset; -#ifdef LWIP_SNMP_V3_CRYPTO +#if LWIP_SNMP_V3_CRYPTO /* For encryption we have to encapsulate the payload in an octet string */ if (request->msg_flags & SNMP_V3_PRIV_FLAG) { request->outbound_scoped_pdu_string_offset = pbuf_stream->offset; @@ -1120,8 +1123,8 @@ snmp_prepare_outbound_frame(struct snmp_request *request) OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); /* contextEngineID */ - request->context_engine_id_len = LWIP_SNMPV3_GET_ENGINE_ID_LEN(); - memcpy(request->context_engine_id, LWIP_SNMPV3_GET_ENGINE_ID(), request->context_engine_id_len); + snmpv3_get_engine_id(&id, &request->context_engine_id_len); + memcpy(request->context_engine_id, id, request->context_engine_id_len); SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->context_engine_id_len); OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->context_engine_id, request->context_engine_id_len)); @@ -1211,10 +1214,10 @@ snmp_append_outbound_varbind(struct snmp_request *request, struct snmp_varbind* value_value_len = 0; break; case SNMP_ASN1_TYPE_OBJECT_ID: - if ((varbind->value_len % sizeof(u32_t)) != 0) { + if ((varbind->value_len & 0x03) != 0) { return ERR_VAL; } - snmp_asn1_enc_oid_cnt((u32_t*)varbind->value, varbind->value_len / sizeof(u32_t), &value_value_len); + snmp_asn1_enc_oid_cnt((u32_t*)varbind->value, varbind->value_len >> 2, &value_value_len); break; case SNMP_ASN1_TYPE_COUNTER64: if (varbind->value_len != (2 * sizeof(u32_t))) { @@ -1344,15 +1347,12 @@ snmp_complete_outbound_frame(struct snmp_request *request) frame_size = request->outbound_pbuf_stream.offset; -#if LWIP_SNMP_V3 && defined(LWIP_SNMP_V3_CRYPTO) +#if LWIP_SNMP_V3 && LWIP_SNMP_V3_CRYPTO /* Calculate padding for encryption */ if (request->version == SNMP_VERSION_3 && (request->msg_flags & SNMP_V3_PRIV_FLAG)) { u8_t i; - for (i = 0; i < 8; i++) { - if ((frame_size + i - request->outbound_scoped_pdu_seq_offset) % 8 == 0) { - outbound_padding = i; - break; - } + outbound_padding = (u8_t)((frame_size - request->outbound_scoped_pdu_seq_offset) & 0x03); + for (i = 0; i < outbound_padding; i++) { snmp_pbuf_stream_write(&request->outbound_pbuf_stream, 0); } } @@ -1456,10 +1456,10 @@ snmp_complete_outbound_frame(struct snmp_request *request) OF_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) ); /* Authenticate response */ -#if LWIP_SNMP_V3 && defined(LWIP_SNMP_V3_CRYPTO) +#if LWIP_SNMP_V3 && LWIP_SNMP_V3_CRYPTO /* Encrypt response */ if (request->version == SNMP_VERSION_3 && (request->msg_flags & SNMP_V3_PRIV_FLAG)) { - u8_t* key; + u8_t key[20]; u8_t algo; /* complete missing length in PDU sequence */ @@ -1469,7 +1469,7 @@ snmp_complete_outbound_frame(struct snmp_request *request) - request->outbound_scoped_pdu_string_offset - 1 - 3); OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv)); - OF_BUILD_EXEC(LWIP_SNMPV3_GET_USER(request->msg_user_name, NULL, NULL, &algo, &key)); + OF_BUILD_EXEC(snmpv3_get_user((char*)request->msg_user_name, NULL, NULL, &algo, key)); OF_BUILD_EXEC(snmpv3_crypt(&request->outbound_pbuf_stream, tlv.value_len, key, request->msg_privacy_parameters, request->msg_authoritative_engine_boots, @@ -1477,11 +1477,11 @@ snmp_complete_outbound_frame(struct snmp_request *request) } if (request->version == SNMP_VERSION_3 && (request->msg_flags & SNMP_V3_AUTH_FLAG)) { - u8_t* key; + u8_t key[20]; u8_t algo; u8_t hmac[20]; - OF_BUILD_EXEC(LWIP_SNMPV3_GET_USER(request->msg_user_name, &algo, &key, NULL, NULL)); + OF_BUILD_EXEC(snmpv3_get_user((char*)request->msg_user_name, &algo, key, NULL, NULL)); OF_BUILD_EXEC(snmp_pbuf_stream_init(&(request->outbound_pbuf_stream), request->outbound_pbuf, 0, request->outbound_pbuf->tot_len)); OF_BUILD_EXEC(snmpv3_auth(&request->outbound_pbuf_stream, frame_size + outbound_padding, key, algo, hmac)); diff --git a/src/apps/snmp/snmp_msg.h b/src/apps/snmp/snmp_msg.h index 8c2e9ebe..73fdf663 100644 --- a/src/apps/snmp/snmp_msg.h +++ b/src/apps/snmp/snmp_msg.h @@ -49,7 +49,7 @@ #include "lwip/err.h" #if LWIP_SNMP_V3 -#include "snmpv3.h" +#include "snmpv3_priv.h" #endif diff --git a/src/apps/snmp/snmpv3.c b/src/apps/snmp/snmpv3.c index d7c8546b..7790ac88 100644 --- a/src/apps/snmp/snmpv3.c +++ b/src/apps/snmp/snmpv3.c @@ -32,9 +32,8 @@ * Author: Elias Oenal */ -#include "snmpv3.h" -#include "arch/cc.h" -#include "snmp_msg.h" +#include "snmpv3_priv.h" +#include "lwip/apps/snmpv3.h" #include "lwip/sys.h" #include @@ -44,245 +43,55 @@ #include LWIP_SNMPV3_INCLUDE_ENGINE #endif -#ifdef LWIP_SNMP_V3_CRYPTO -#ifdef LWIP_INCLUDE_CRYPTO_LIB -#include LWIP_INCLUDE_CRYPTO_LIB -#endif -#ifdef LWIP_INCLUDE_CRYPTO_MD5 -#include LWIP_INCLUDE_CRYPTO_MD5 -#endif -#ifdef LWIP_INCLUDE_CRYPTO_SHA -#include LWIP_INCLUDE_CRYPTO_SHA -#endif -#ifdef LWIP_INCLUDE_CRYPTO_DES -#include LWIP_INCLUDE_CRYPTO_DES -#endif -#ifdef LWIP_INCLUDE_CRYPTO_AES -#include LWIP_INCLUDE_CRYPTO_AES -#endif -#endif - -#ifdef LWIP_SNMP_V3_CRYPTO -#if !defined(LWIP_MD5_HMAC_HANDLE) || !defined(LWIP_MD5_HMAC_INIT) || \ - !defined(LWIP_MD5_HMAC_UPDATE) || !defined(LWIP_MD5_HMAC_FINAL) -#error LWIP_SNMP_V3_CRYPTO requires MD5 HMAC -#endif -#if !defined(LWIP_SHA_HMAC_HANDLE) || !defined(LWIP_SHA_HMAC_INIT) || \ - !defined(LWIP_SHA_HMAC_UPDATE) || !defined(LWIP_SHA_HMAC_FINAL) -#error LWIP_SNMP_V3_CRYPTO requires SHA HMAC -#endif -#if !defined(LWIP_DES_CBC_ENCRYPT_HANDLE) || !defined(LWIP_DES_CBC_ENCRYPT_INIT) || \ - !defined(LWIP_DES_CBC_ENCRYPT_UPDATE) || !defined(LWIP_DES_CBC_ENCRYPT_FINAL) || \ - !defined(LWIP_DES_CBC_DECRYPT_HANDLE) || !defined(LWIP_DES_CBC_DECRYPT_INIT) || \ - !defined(LWIP_DES_CBC_DECRYPT_UPDATE) || !defined(LWIP_DES_CBC_DECRYPT_FINAL) -#error LWIP_SNMP_V3_CRYPTO requires DES CBC -#endif -#if !defined(LWIP_AES_CFB_ENCRYPT_HANDLE) || !defined(LWIP_AES_CFB_ENCRYPT_INIT) || \ - !defined(LWIP_AES_CFB_ENCRYPT_UPDATE) || !defined(LWIP_AES_CFB_ENCRYPT_FINAL) || \ - !defined(LWIP_AES_CFB_DECRYPT_HANDLE) || !defined(LWIP_AES_CFB_DECRYPT_INIT) || \ - !defined(LWIP_AES_CFB_DECRYPT_UPDATE) || !defined(LWIP_AES_CFB_DECRYPT_FINAL) -#error LWIP_SNMP_V3_CRYPTO requires AES CFB -#endif -#endif - #define SNMP_MAX_TIME_BOOT 2147483647UL -/* Engine ID, as specified in RFC3411 */ -const char* -snmpv3_get_engine_id(void) -{ - return LWIP_SNMPV3_GET_ENGINE_ID(); -} - -/* Has to reset boots, see below */ +/** Call this if engine has been changed. Has to reset boots, see below */ void snmpv3_engine_id_changed(void) { - LWIP_SNMPV3_SET_ENGINE_BOOTS(0); + snmpv3_set_engine_boots(0); } -/* According to RFC3414 2.2.2. +/** According to RFC3414 2.2.2. * * The number of times that the SNMP engine has * (re-)initialized itself since snmpEngineID * was last configured. */ u32_t -snmpv3_get_engine_boots(void) +snmpv3_get_engine_boots_internal(void) { - if (LWIP_SNMPV3_GET_ENGINE_BOOTS() == 0 || - LWIP_SNMPV3_GET_ENGINE_BOOTS() < SNMP_MAX_TIME_BOOT) { - return LWIP_SNMPV3_GET_ENGINE_BOOTS(); + if (snmpv3_get_engine_boots() == 0 || + snmpv3_get_engine_boots() < SNMP_MAX_TIME_BOOT) { + return snmpv3_get_engine_boots(); } - LWIP_SNMPV3_SET_ENGINE_BOOTS(SNMP_MAX_TIME_BOOT); - return LWIP_SNMPV3_GET_ENGINE_BOOTS(); + snmpv3_set_engine_boots(SNMP_MAX_TIME_BOOT); + return snmpv3_get_engine_boots(); } -/* RFC3414 2.2.2. +/** RFC3414 2.2.2. * * Once the timer reaches 2147483647 it gets reset to zero and the * engine boot ups get incremented. */ u32_t -snmpv3_get_engine_time(void) +snmpv3_get_engine_time_internal(void) { - if (LWIP_SNMPV3_GET_ENGINE_TIME() >= SNMP_MAX_TIME_BOOT) { - LWIP_SNMPV3_RESET_ENGINE_TIME(); + if (snmpv3_get_engine_time() >= SNMP_MAX_TIME_BOOT) { + snmpv3_reset_engine_time(); - if (LWIP_SNMPV3_GET_ENGINE_BOOTS() < SNMP_MAX_TIME_BOOT - 1) { - LWIP_SNMPV3_SET_ENGINE_BOOTS(LWIP_SNMPV3_GET_ENGINE_BOOTS() + 1); + if (snmpv3_get_engine_boots() < SNMP_MAX_TIME_BOOT - 1) { + snmpv3_set_engine_boots(snmpv3_get_engine_boots() + 1); } else { - LWIP_SNMPV3_SET_ENGINE_BOOTS(SNMP_MAX_TIME_BOOT); + snmpv3_set_engine_boots(SNMP_MAX_TIME_BOOT); } } - return LWIP_SNMPV3_GET_ENGINE_TIME(); + return snmpv3_get_engine_time(); } -#ifdef LWIP_SNMP_V3_CRYPTO -err_t -snmpv3_auth(struct snmp_pbuf_stream* stream, u16_t length, - const u8_t* key, u8_t algo, u8_t* hmac_out) -{ - u32_t i; - u8_t byte; - struct snmp_pbuf_stream read_stream; - snmp_pbuf_stream_init(&read_stream, stream->pbuf, stream->offset, - stream->length); - - if (algo == SNMP_V3_AUTH_ALGO_MD5) { - LWIP_MD5_HMAC_HANDLE mh; - if (LWIP_MD5_HMAC_INIT(&mh, key, SNMP_V3_MD5_LEN)) - return ERR_ARG; - for (i = 0; i < length; i++) { - if (snmp_pbuf_stream_read(&read_stream, &byte)) - return ERR_ARG; - if (LWIP_MD5_HMAC_UPDATE(&mh, &byte, 1)) - return ERR_ARG; - } - if (LWIP_MD5_HMAC_FINAL(&mh, hmac_out)) - return ERR_ARG; - - } else if (algo == SNMP_V3_AUTH_ALGO_SHA) { - LWIP_SHA_HMAC_HANDLE sh; - if (LWIP_SHA_HMAC_INIT(&sh, key, SNMP_V3_SHA_LEN)) - return ERR_ARG; - for (i = 0; i < length; i++) { - if (snmp_pbuf_stream_read(&read_stream, &byte)) - return ERR_ARG; - if (LWIP_SHA_HMAC_UPDATE(&sh, &byte, 1)) - return ERR_ARG; - } - if (LWIP_SHA_HMAC_FINAL(&sh, hmac_out)) - return ERR_ARG; - } else - return ERR_ARG; - - return ERR_OK; -} - -err_t -snmpv3_crypt(struct snmp_pbuf_stream* stream, u16_t length, - const u8_t* key, const u8_t* priv_param, const u32_t engine_boots, - const u32_t engine_time, u8_t algo, u8_t mode) -{ - u8_t in_bytes[8]; - u8_t out_bytes[8]; - u8_t iv_local[16]; - - u32_t i, j; - /* RFC 3414 mandates padding for DES */ - if (algo == SNMP_V3_PRIV_ALGO_DES) { - if (length % 8) - return ERR_ARG; - - for (i = 0; i < 8; i++) - iv_local[i] = priv_param[i] ^ key[i + 8]; - } else if (algo == SNMP_V3_PRIV_ALGO_AES) { - /* - * IV is the big endian concatenation of boots, - * uptime and priv param - see RFC3826. - */ - iv_local[0 + 0] = (engine_boots >> 24) & 0xFF; - iv_local[0 + 1] = (engine_boots >> 16) & 0xFF; - iv_local[0 + 2] = (engine_boots >> 8) & 0xFF; - iv_local[0 + 3] = (engine_boots >> 0) & 0xFF; - iv_local[4 + 0] = (engine_time >> 24) & 0xFF; - iv_local[4 + 1] = (engine_time >> 16) & 0xFF; - iv_local[4 + 2] = (engine_time >> 8) & 0xFF; - iv_local[4 + 3] = (engine_time >> 0) & 0xFF; - memcpy(iv_local + 8, priv_param, 8); - } - - struct snmp_pbuf_stream read_stream; - struct snmp_pbuf_stream write_stream; - snmp_pbuf_stream_init(&read_stream, stream->pbuf, stream->offset, - stream->length); - snmp_pbuf_stream_init(&write_stream, stream->pbuf, stream->offset, - stream->length); - - if (algo == SNMP_V3_PRIV_ALGO_DES && mode == SNMP_V3_PRIV_MODE_ENCRYPT) { - LWIP_DES_CBC_ENCRYPT_HANDLE handle; - LWIP_DES_CBC_ENCRYPT_INIT(&handle, key); - - for (i = 0; i < length; i += 8) { - for (j = 0; j < 8; j++) - snmp_pbuf_stream_read(&read_stream, &in_bytes[j]); - - LWIP_DES_CBC_ENCRYPT_UPDATE(&handle, 8, iv_local, in_bytes, out_bytes); - - for (j = 0; j < 8; j++) - snmp_pbuf_stream_write(&write_stream, out_bytes[j]); - } - - LWIP_DES_CBC_ENCRYPT_FINAL(&handle); - } else if (algo == SNMP_V3_PRIV_ALGO_DES && mode == SNMP_V3_PRIV_MODE_DECRYPT) { - LWIP_DES_CBC_DECRYPT_HANDLE handle; - LWIP_DES_CBC_DECRYPT_INIT(&handle, key); - - for (i = 0; i < length; i += 8) { - for (j = 0; j < 8; j++) - snmp_pbuf_stream_read(&read_stream, &in_bytes[j]); - - LWIP_DES_CBC_DECRYPT_UPDATE(&handle, 8, iv_local, in_bytes, out_bytes); - - for (j = 0; j < 8; j++) - snmp_pbuf_stream_write(&write_stream, out_bytes[j]); - } - - LWIP_DES_CBC_DECRYPT_FINAL(&handle); - } else if (algo == SNMP_V3_PRIV_ALGO_AES && mode == SNMP_V3_PRIV_MODE_ENCRYPT) { - size_t iv_offset = 0; - LWIP_AES_CFB_ENCRYPT_HANDLE handle; - LWIP_AES_CFB_ENCRYPT_INIT(&handle, key); - - for (i = 0; i < length; i++) { - snmp_pbuf_stream_read(&read_stream, &in_bytes[0]); - LWIP_AES_CFB_ENCRYPT_UPDATE(&handle, 1, &iv_offset, iv_local, in_bytes, - out_bytes); - snmp_pbuf_stream_write(&write_stream, out_bytes[0]); - } - - LWIP_AES_CFB_ENCRYPT_FINAL(&handle); - } else if (algo == SNMP_V3_PRIV_ALGO_AES && mode == SNMP_V3_PRIV_MODE_DECRYPT) { - size_t iv_off = 0; - LWIP_AES_CFB_DECRYPT_HANDLE handle; - LWIP_AES_CFB_DECRYPT_INIT(&handle, key); - - for (i = 0; i < length; i++) { - snmp_pbuf_stream_read(&read_stream, &in_bytes[0]); - LWIP_AES_CFB_DECRYPT_UPDATE(&handle, 1, &iv_off, iv_local, in_bytes, - out_bytes); - snmp_pbuf_stream_write(&write_stream, out_bytes[0]); - } - - LWIP_AES_CFB_DECRYPT_FINAL(&handle); - } else - return ERR_ARG; - - return ERR_OK; -} +#if LWIP_SNMP_V3_CRYPTO /* This function ignores the byte order suggestion in RFC3414 * since it simply doesn't influence the effectiveness of an IV. diff --git a/src/apps/snmp/snmpv3.h b/src/apps/snmp/snmpv3.h deleted file mode 100644 index e33b4893..00000000 --- a/src/apps/snmp/snmpv3.h +++ /dev/null @@ -1,124 +0,0 @@ -/** - * @file - * Additional SNMPv3 functionality RFC3414 and RFC3826. - */ - -/* - * Copyright (c) 2016 Elias Oenal. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * Author: Elias Oenal - */ - -#ifndef LWIP_HDR_APPS_SNMP_V3_H -#define LWIP_HDR_APPS_SNMP_V3_H - -#include "lwip/apps/snmp_opts.h" - -#if LWIP_SNMP && LWIP_SNMP_V3 - -#include "snmp_pbuf_stream.h" - -#ifndef LWIP_SNMPV3_GET_ENGINE_BOOTS -/* #warning RFC3414 complicance requires a persistent boot count */ -#define LWIP_SNMPV3_GET_ENGINE_BOOTS() 0 -#endif - -#ifndef LWIP_SNMPV3_SET_ENGINE_BOOTS -/* #warning RFC3414 complicance requires a method to set boot count */ -#define LWIP_SNMPV3_SET_ENGINE_BOOTS(val) -#endif - -#ifndef LWIP_SNMPV3_GET_ENGINE_TIME -/* #warning RFC3414 complicance requires the uptime to count until 2147483647 */ -#define LWIP_SNMPV3_GET_ENGINE_TIME() (sys_now() / 10) -#endif - -#ifndef LWIP_SNMPV3_RESET_ENGINE_TIME -/* #warning RFC3414 complicance requires a method to reset uptime */ -#define LWIP_SNMPV3_RESET_ENGINE_TIME() -#endif - -#ifndef LWIP_SNMPV3_GET_ENGINE_ID -/* #warning RFC3414 complicance requires an engine ID */ -/* Using the one from the test vectors from RFC3414 */ -#define LWIP_SNMPV3_GET_ENGINE_ID() "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02" -#endif - -#ifndef LWIP_SNMPV3_GET_ENGINE_ID_LEN -/* #warning RFC3414 complicance requires an engine ID */ -#define LWIP_SNMPV3_GET_ENGINE_ID_LEN() 12 -#endif - -#ifndef LWIP_SNMPV3_GET_USER -/* #warning Implement user handling */ -/* @param username is a pointer to a string. - * @param auth_algo is a pointer to u8_t. The implementation has to set this if user was found. - * @param auth_key is a pointer to a pointer to a string. Implementation has to set this if user was found. - * @param priv_algo is a pointer to u8_t. The implementation has to set this if user was found. - * @param priv_key is a pointer to a pointer to a string. Implementation has to set this if user was found. - */ -/* Dummy implementation, pretend the user was found if cryptography isn't used */ -#define LWIP_SNMPV3_GET_USER(username, auth_algo, auth_key, priv_algo, priv_key) ((auth_algo || auth_key \ - || priv_algo || priv_key)?1:0) -#endif - -/* According to RFC 3411 */ -#define SNMP_V3_MAX_ENGINE_ID_LENGTH 32 -#define SNMP_V3_MAX_USER_LENGTH 32 - -#define SNMP_V3_MAX_AUTH_PARAM_LENGTH 12 -#define SNMP_V3_MAX_PRIV_PARAM_LENGTH 8 - -#define SNMP_V3_AUTH_FLAG 0x01 -#define SNMP_V3_PRIV_FLAG 0x02 - -#define SNMP_V3_MD5_LEN 16 -#define SNMP_V3_SHA_LEN 20 - -#define SNMP_V3_AUTH_ALGO_INVAL 0 -#define SNMP_V3_AUTH_ALGO_MD5 1 -#define SNMP_V3_AUTH_ALGO_SHA 2 - -#define SNMP_V3_PRIV_ALGO_INVAL 0 -#define SNMP_V3_PRIV_ALGO_DES 1 -#define SNMP_V3_PRIV_ALGO_AES 2 - -#define SNMP_V3_PRIV_MODE_DECRYPT 0 -#define SNMP_V3_PRIV_MODE_ENCRYPT 1 - -const char* snmpv3_get_engine_id(void); -void snmpv3_set_engine_id(const char* id); -u32_t snmpv3_get_engine_boots(void); -u32_t snmpv3_get_engine_time(void); -void snmpv3_engine_id_changed(void); -err_t snmpv3_auth(struct snmp_pbuf_stream* stream, u16_t length, const u8_t* key, u8_t algo, u8_t* hmac_out); -err_t snmpv3_crypt(struct snmp_pbuf_stream* stream, u16_t length, const u8_t* key, - const u8_t* priv_param, const u32_t engine_boots, const u32_t engine_time, u8_t algo, u8_t mode); -err_t snmpv3_build_priv_param(u8_t* priv_param); - -#endif - -#endif /* LWIP_HDR_APPS_SNMP_V3_H */ diff --git a/src/apps/snmp/snmpv3_dummy.c b/src/apps/snmp/snmpv3_dummy.c new file mode 100644 index 00000000..7d3fac46 --- /dev/null +++ b/src/apps/snmp/snmpv3_dummy.c @@ -0,0 +1,141 @@ +/** + * @file + * Dummy SNMPv3 functions. + */ + +/* + * Copyright (c) 2016 Elias Oenal. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Elias Oenal + * Dirk Ziegelmeier + */ + +#include "lwip/apps/snmpv3.h" +#include "snmpv3_priv.h" +#include +#include "lwip/err.h" + +/** + * @param username is a pointer to a string. + * @param auth_algo is a pointer to u8_t. The implementation has to set this if user was found. + * @param auth_key is a pointer to a pointer to a string. Implementation has to set this if user was found. + * @param priv_algo is a pointer to u8_t. The implementation has to set this if user was found. + * @param priv_key is a pointer to a pointer to a string. Implementation has to set this if user was found. + */ +err_t +snmpv3_get_user(const char* username, u8_t *auth_algo, u8_t *auth_key, u8_t *priv_algo, u8_t *priv_key) +{ + const char* engine_id; + u8_t engine_id_len; + + if(strlen(username) == 0) { + return ERR_OK; + } + + if(memcmp(username, "lwip", 4) != 0) { + return ERR_VAL; + } + + snmpv3_get_engine_id(&engine_id, &engine_id_len); + + if(auth_key != NULL) { + snmpv3_password_to_key_sha((const u8_t*)"maplesyrup", 10, + (const u8_t*)engine_id, engine_id_len, + auth_key); + *auth_algo = SNMP_V3_AUTH_ALGO_SHA; + } + if(priv_key != NULL) { + snmpv3_password_to_key_md5((const u8_t*)"maplesyrup", 10, + (const u8_t*)engine_id, engine_id_len, + priv_key); + *priv_algo = SNMP_V3_PRIV_ALGO_DES; + } + return ERR_OK; +} + +/** + * Get engine ID from persistence + * @param id + * @param len + */ +void +snmpv3_get_engine_id(const char **id, u8_t *len) +{ + *id = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02"; + *len = 12; +} + +/** + * Store engine ID in persistence + * @param id + * @param len + */ +err_t +snmpv3_set_engine_id(const char *id, u8_t len) +{ + LWIP_UNUSED_ARG(id); + LWIP_UNUSED_ARG(len); + return ERR_OK; +} + +/** + * Get engine boots from persistence. Must be increased on each boot. + * @return + */ +u32_t +snmpv3_get_engine_boots(void) +{ + return 0; +} + +/** + * Store engine boots in persistence + * @param boots + */ +void +snmpv3_set_engine_boots(u32_t boots) +{ + LWIP_UNUSED_ARG(boots); +} + +/** + * RFC3414 2.2.2. + * Once the timer reaches 2147483647 it gets reset to zero and the + * engine boot ups get incremented. + */ +u32_t +snmpv3_get_engine_time(void) +{ + return 0; +} + +/** + * Reset current engine time to 0 + */ +void +snmpv3_reset_engine_time(void) +{ +} diff --git a/src/apps/snmp/snmpv3_mbedtls.c b/src/apps/snmp/snmpv3_mbedtls.c new file mode 100644 index 00000000..8db20bbf --- /dev/null +++ b/src/apps/snmp/snmpv3_mbedtls.c @@ -0,0 +1,317 @@ +/** + * @file + * SNMPv3 crypto/auth functions implemented for ARM mbedtls. + */ + +/* + * Copyright (c) 2016 Elias Oenal and Dirk Ziegelmeier. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Elias Oenal + * Dirk Ziegelmeier + */ + +#include "lwip/apps/snmpv3.h" +#include "snmpv3_priv.h" +#include "arch/cc.h" +#include "snmp_msg.h" +#include "lwip/sys.h" +#include + +#include "mbedtls/md.h" +#include "mbedtls/cipher.h" + +#include "mbedtls/md5.h" +#include "mbedtls/sha1.h" + +#if LWIP_SNMP && LWIP_SNMP_V3 && LWIP_SNMP_V3_MBEDTLS + +err_t +snmpv3_auth(struct snmp_pbuf_stream* stream, u16_t length, + const u8_t* key, u8_t algo, u8_t* hmac_out) +{ + u32_t i; + u8_t key_len; + const mbedtls_md_info_t *md_info; + mbedtls_md_context_t ctx; + struct snmp_pbuf_stream read_stream; + snmp_pbuf_stream_init(&read_stream, stream->pbuf, stream->offset, stream->length); + + if (algo == SNMP_V3_AUTH_ALGO_MD5) { + md_info = mbedtls_md_info_from_type(MBEDTLS_MD_MD5); + key_len = SNMP_V3_MD5_LEN; + } else if (algo == SNMP_V3_AUTH_ALGO_SHA) { + md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1); + key_len = SNMP_V3_SHA_LEN; + } else { + return ERR_ARG; + } + + mbedtls_md_init(&ctx); + if(mbedtls_md_setup(&ctx, md_info, 1) != 0) { + return ERR_ARG; + } + + if (mbedtls_md_hmac_starts(&ctx, key, key_len) != 0) { + goto free_md; + } + + for (i = 0; i < length; i++) { + u8_t byte; + + if (snmp_pbuf_stream_read(&read_stream, &byte)) { + goto free_md; + } + + if (mbedtls_md_hmac_update(&ctx, &byte, 1) != 0) { + goto free_md; + } + } + + if (mbedtls_md_hmac_finish(&ctx, hmac_out) != 0) { + goto free_md; + } + + mbedtls_md_free(&ctx); + return ERR_OK; + +free_md: + mbedtls_md_free(&ctx); + return ERR_ARG; +} + +err_t +snmpv3_crypt(struct snmp_pbuf_stream* stream, u16_t length, + const u8_t* key, const u8_t* priv_param, const u32_t engine_boots, + const u32_t engine_time, u8_t algo, u8_t mode) +{ + size_t i; + mbedtls_cipher_context_t ctx; + const mbedtls_cipher_info_t *cipher_info; + + struct snmp_pbuf_stream read_stream; + struct snmp_pbuf_stream write_stream; + snmp_pbuf_stream_init(&read_stream, stream->pbuf, stream->offset, stream->length); + snmp_pbuf_stream_init(&write_stream, stream->pbuf, stream->offset, stream->length); + mbedtls_cipher_init(&ctx); + + if (algo == SNMP_V3_PRIV_ALGO_DES) { + u8_t iv_local[8]; + + /* RFC 3414 mandates padding for DES */ + if ((length & 0x07) != 0) { + return ERR_ARG; + } + + cipher_info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_DES_CBC); + if(mbedtls_cipher_setup(&ctx, cipher_info) != 0) { + return ERR_ARG; + } + if(mbedtls_cipher_setkey(&ctx, key, 12*8, (mode == SNMP_V3_PRIV_MODE_ENCRYPT)? MBEDTLS_ENCRYPT : MBEDTLS_DECRYPT) != 0) { + goto error; + } + + /* Prepare IV */ + for (i = 0; i < LWIP_ARRAYSIZE(iv_local); i++) { + iv_local[i] = priv_param[i] ^ key[i + 8]; + } + if(mbedtls_cipher_set_iv(&ctx, iv_local, LWIP_ARRAYSIZE(iv_local)) != 0) { + goto error; + } + + for (i = 0; i < length; i += 8) { + size_t j; + u8_t in_bytes[8]; + u8_t out_bytes[8]; + size_t out_len = LWIP_ARRAYSIZE(out_bytes); + + for (j = 0; j < LWIP_ARRAYSIZE(in_bytes); j++) { + snmp_pbuf_stream_read(&read_stream, &in_bytes[j]); + } + + if(mbedtls_cipher_update(&ctx, in_bytes, LWIP_ARRAYSIZE(in_bytes), out_bytes, &out_len) != 0) { + goto error; + } + + snmp_pbuf_stream_writebuf(&write_stream, out_bytes, out_len); + } + } else if (algo == SNMP_V3_PRIV_ALGO_AES && mode == SNMP_V3_PRIV_MODE_ENCRYPT) { + u8_t iv_local[16]; + + cipher_info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_CFB128); + if(mbedtls_cipher_setup(&ctx, cipher_info) != 0) { + return ERR_ARG; + } + if(mbedtls_cipher_setkey(&ctx, key, 16*8, (mode == SNMP_V3_PRIV_MODE_ENCRYPT)? MBEDTLS_ENCRYPT : MBEDTLS_DECRYPT) != 0) { + goto error; + } + + /* + * IV is the big endian concatenation of boots, + * uptime and priv param - see RFC3826. + */ + iv_local[0 + 0] = (engine_boots >> 24) & 0xFF; + iv_local[0 + 1] = (engine_boots >> 16) & 0xFF; + iv_local[0 + 2] = (engine_boots >> 8) & 0xFF; + iv_local[0 + 3] = (engine_boots >> 0) & 0xFF; + iv_local[4 + 0] = (engine_time >> 24) & 0xFF; + iv_local[4 + 1] = (engine_time >> 16) & 0xFF; + iv_local[4 + 2] = (engine_time >> 8) & 0xFF; + iv_local[4 + 3] = (engine_time >> 0) & 0xFF; + memcpy(iv_local + 8, priv_param, 8); + if(mbedtls_cipher_set_iv(&ctx, iv_local, LWIP_ARRAYSIZE(iv_local)) != 0) { + goto error; + } + + for (i = 0; i < length; i++) { + u8_t in_byte; + u8_t out_byte; + size_t out_len = sizeof(out_byte); + + snmp_pbuf_stream_read(&read_stream, &in_byte); + if(mbedtls_cipher_update(&ctx, &in_byte, sizeof(in_byte), &out_byte, &out_len) != 0) { + goto error; + } + snmp_pbuf_stream_write(&write_stream, out_byte); + } + } else { + return ERR_ARG; + } + + mbedtls_cipher_free(&ctx); + return ERR_OK; + +error: + mbedtls_cipher_free(&ctx); + return ERR_OK; +} + +/* A.2.1. Password to Key Sample Code for MD5 */ +void +snmpv3_password_to_key_md5( + const u8_t *password, /* IN */ + u8_t passwordlen, /* IN */ + const u8_t *engineID, /* IN - pointer to snmpEngineID */ + u8_t engineLength,/* IN - length of snmpEngineID */ + u8_t *key) /* OUT - pointer to caller 16-octet buffer */ +{ + mbedtls_md5_context MD; + u8_t *cp, password_buf[64]; + u32_t password_index = 0; + u8_t i; + u32_t count = 0; + + mbedtls_md5_init(&MD); /* initialize MD5 */ + mbedtls_md5_starts(&MD); + + /**********************************************/ + /* 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]; + } + mbedtls_md5_update(&MD, password_buf, 64); + count += 64; + } + mbedtls_md5_finish(&MD, key); /* 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 */ + /*****************************************************/ + memcpy(password_buf, key, 16); + memcpy(password_buf + 16, engineID, engineLength); + memcpy(password_buf + 16 + engineLength, key, 16); + + mbedtls_md5_starts(&MD); + mbedtls_md5_update(&MD, password_buf, 32 + engineLength); + mbedtls_md5_finish(&MD, key); + + mbedtls_md5_free(&MD); + return; +} + +/* A.2.2. Password to Key Sample Code for SHA */ +void +snmpv3_password_to_key_sha( + const u8_t *password, /* IN */ + u8_t passwordlen, /* IN */ + const u8_t *engineID, /* IN - pointer to snmpEngineID */ + u8_t engineLength,/* IN - length of snmpEngineID */ + u8_t *key) /* OUT - pointer to caller 20-octet buffer */ +{ + mbedtls_sha1_context SH; + u8_t *cp, password_buf[72]; + u32_t password_index = 0; + u8_t i; + u32_t count = 0; + + mbedtls_sha1_init(&SH); /* initialize SHA */ + mbedtls_sha1_starts(&SH); + + /**********************************************/ + /* 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]; + } + mbedtls_sha1_update(&SH, password_buf, 64); + count += 64; + } + mbedtls_sha1_finish(&SH, key); /* 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); + + mbedtls_sha1_starts(&SH); + mbedtls_sha1_update(&SH, password_buf, 40 + engineLength); + mbedtls_sha1_finish(&SH, key); + + mbedtls_sha1_free(&SH); + return; +} + +#endif /* LWIP_SNMP && LWIP_SNMP_V3 && LWIP_SNMP_V3_MBEDTLS */ diff --git a/src/apps/snmp/snmpv3_priv.h b/src/apps/snmp/snmpv3_priv.h new file mode 100644 index 00000000..f12f95c6 --- /dev/null +++ b/src/apps/snmp/snmpv3_priv.h @@ -0,0 +1,66 @@ +/** + * @file + * Additional SNMPv3 functionality RFC3414 and RFC3826. + */ + +/* + * Copyright (c) 2016 Elias Oenal. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Elias Oenal + */ + +#ifndef LWIP_HDR_APPS_SNMP_V3_PRIV_H +#define LWIP_HDR_APPS_SNMP_V3_PRIV_H + +#include "lwip/apps/snmp_opts.h" + +#if LWIP_SNMP && LWIP_SNMP_V3 + +#include "snmp_pbuf_stream.h" + +/* According to RFC 3411 */ +#define SNMP_V3_MAX_ENGINE_ID_LENGTH 32 +#define SNMP_V3_MAX_USER_LENGTH 32 + +#define SNMP_V3_MAX_AUTH_PARAM_LENGTH 12 +#define SNMP_V3_MAX_PRIV_PARAM_LENGTH 8 + +#define SNMP_V3_AUTH_FLAG 0x01 +#define SNMP_V3_PRIV_FLAG 0x02 + +#define SNMP_V3_MD5_LEN 16 +#define SNMP_V3_SHA_LEN 20 + +u32_t snmpv3_get_engine_boots_internal(void); +u32_t snmpv3_get_engine_time_internal(void); +err_t snmpv3_auth(struct snmp_pbuf_stream* stream, u16_t length, const u8_t* key, u8_t algo, u8_t* hmac_out); +err_t snmpv3_crypt(struct snmp_pbuf_stream* stream, u16_t length, const u8_t* key, + const u8_t* priv_param, const u32_t engine_boots, const u32_t engine_time, u8_t algo, u8_t mode); +err_t snmpv3_build_priv_param(u8_t* priv_param); + +#endif + +#endif /* LWIP_HDR_APPS_SNMP_V3_PRIV_H */ diff --git a/src/include/lwip/apps/snmp_opts.h b/src/include/lwip/apps/snmp_opts.h index 910a7563..12275851 100644 --- a/src/include/lwip/apps/snmp_opts.h +++ b/src/include/lwip/apps/snmp_opts.h @@ -255,5 +255,14 @@ #define SNMP_LWIP_GETBULK_MAX_REPETITIONS 0 #endif -#endif /* LWIP_HDR_SNMP_OPTS_H */ +/* + ------------------------------------ + ---------- SNMPv3 options ---------- + ------------------------------------ +*/ +#ifndef LWIP_SNMP_V3_CRYPTO +#define LWIP_SNMP_V3_CRYPTO LWIP_SNMP_V3 +#endif + +#endif /* LWIP_HDR_SNMP_OPTS_H */ diff --git a/src/include/lwip/apps/snmpv3.h b/src/include/lwip/apps/snmpv3.h new file mode 100644 index 00000000..c99fed4e --- /dev/null +++ b/src/include/lwip/apps/snmpv3.h @@ -0,0 +1,90 @@ +/** + * @file + * Additional SNMPv3 functionality RFC3414 and RFC3826. + */ + +/* + * Copyright (c) 2016 Elias Oenal. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Elias Oenal + */ + +#ifndef LWIP_HDR_APPS_SNMP_V3_H +#define LWIP_HDR_APPS_SNMP_V3_H + +#include "lwip/apps/snmp_opts.h" +#include "lwip/err.h" + +#if LWIP_SNMP && LWIP_SNMP_V3 + +#define SNMP_V3_AUTH_ALGO_INVAL 0 +#define SNMP_V3_AUTH_ALGO_MD5 1 +#define SNMP_V3_AUTH_ALGO_SHA 2 + +#define SNMP_V3_PRIV_ALGO_INVAL 0 +#define SNMP_V3_PRIV_ALGO_DES 1 +#define SNMP_V3_PRIV_ALGO_AES 2 + +#define SNMP_V3_PRIV_MODE_DECRYPT 0 +#define SNMP_V3_PRIV_MODE_ENCRYPT 1 + +/* + * The following callback functions must be implemented by the application. + * There is a dummy implementation in snmpv3_dummy.c. + */ + +void snmpv3_get_engine_id(const char **id, u8_t *len); +err_t snmpv3_set_engine_id(const char* id, u8_t len); + +u32_t snmpv3_get_engine_boots(void); +void snmpv3_set_engine_boots(u32_t boots); + +u32_t snmpv3_get_engine_time(void); +void snmpv3_reset_engine_time(void); + +err_t snmpv3_get_user(const char* username, u8_t *auth_algo, u8_t *auth_key, u8_t *priv_algo, u8_t *priv_key); + +/* The following functions are provided by the SNMPv3 agent */ + +void snmpv3_engine_id_changed(void); + +void snmpv3_password_to_key_md5( + const u8_t *password, /* IN */ + u8_t passwordlen, /* IN */ + const u8_t *engineID, /* IN - pointer to snmpEngineID */ + u8_t engineLength, /* IN - length of snmpEngineID */ + u8_t *key); /* OUT - pointer to caller 16-octet buffer */ + +void snmpv3_password_to_key_sha( + const u8_t *password, /* IN */ + u8_t passwordlen, /* IN */ + const u8_t *engineID, /* IN - pointer to snmpEngineID */ + u8_t engineLength, /* IN - length of snmpEngineID */ + u8_t *key); /* OUT - pointer to caller 20-octet buffer */ + +#endif + +#endif /* LWIP_HDR_APPS_SNMP_V3_H */