Commit Elias Oenal's SNMPv3 work, with some restructuring:

- The abstraction from crypto framework was not well suitable to MBEDTLS, so I decided to move everything into an own file.
- I removed several #defines and created function prototypes instead - this is more type-safe, and users don't need to reinvent the function signatures.
- Header files were splitted into a public and a private part.
- Only SNMPv3 authentication was tested, privacy not yet.
This commit is contained in:
Dirk Ziegelmeier 2016-04-04 18:55:32 +02:00
parent 3a7c998f91
commit b67427bd3b
10 changed files with 679 additions and 369 deletions

View File

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

View File

@ -45,15 +45,16 @@
#include "lwip/ip_addr.h"
#include "lwip/stats.h"
#include <string.h>
#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 <string.h>
/* 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));

View File

@ -49,7 +49,7 @@
#include "lwip/err.h"
#if LWIP_SNMP_V3
#include "snmpv3.h"
#include "snmpv3_priv.h"
#endif

View File

@ -32,9 +32,8 @@
* Author: Elias Oenal <lwip@eliasoenal.com>
*/
#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 <string.h>
@ -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.

View File

@ -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 <lwip@eliasoenal.com>
*/
#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 */

View File

@ -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 <lwip@eliasoenal.com>
* Dirk Ziegelmeier <dirk@ziegelmeier.net>
*/
#include "lwip/apps/snmpv3.h"
#include "snmpv3_priv.h"
#include <string.h>
#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)
{
}

View File

@ -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 <lwip@eliasoenal.com>
* Dirk Ziegelmeier <dirk@ziegelmeier.net>
*/
#include "lwip/apps/snmpv3.h"
#include "snmpv3_priv.h"
#include "arch/cc.h"
#include "snmp_msg.h"
#include "lwip/sys.h"
#include <string.h>
#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 */

View File

@ -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 <lwip@eliasoenal.com>
*/
#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 */

View File

@ -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 */

View File

@ -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 <lwip@eliasoenal.com>
*/
#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 */