mirror of
https://github.com/lwip-tcpip/lwip.git
synced 2024-08-23 06:35:57 +00:00
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:
parent
3a7c998f91
commit
b67427bd3b
|
@ -142,7 +142,9 @@ SNMPFILES=$(LWIPDIR)/apps/snmp/snmp_asn1.c \
|
||||||
$(LWIPDIR)/apps/snmp/snmp_scalar.c \
|
$(LWIPDIR)/apps/snmp/snmp_scalar.c \
|
||||||
$(LWIPDIR)/apps/snmp/snmp_table.c \
|
$(LWIPDIR)/apps/snmp/snmp_table.c \
|
||||||
$(LWIPDIR)/apps/snmp/snmp_threadsync.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: HTTP server
|
||||||
HTTPDFILES=$(LWIPDIR)/apps/httpd/fs.c \
|
HTTPDFILES=$(LWIPDIR)/apps/httpd/fs.c \
|
||||||
|
|
|
@ -45,15 +45,16 @@
|
||||||
#include "lwip/ip_addr.h"
|
#include "lwip/ip_addr.h"
|
||||||
#include "lwip/stats.h"
|
#include "lwip/stats.h"
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#if LWIP_SNMP_V3
|
#if LWIP_SNMP_V3
|
||||||
#include "snmpv3.h"
|
#include "lwip/apps/snmpv3.h"
|
||||||
|
#include "snmpv3_priv.h"
|
||||||
#ifdef LWIP_SNMPV3_INCLUDE_ENGINE
|
#ifdef LWIP_SNMPV3_INCLUDE_ENGINE
|
||||||
#include LWIP_SNMPV3_INCLUDE_ENGINE
|
#include LWIP_SNMPV3_INCLUDE_ENGINE
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
/* public (non-static) constants */
|
/* public (non-static) constants */
|
||||||
/** SNMP community string */
|
/** SNMP community string */
|
||||||
const char *snmp_community = SNMP_COMMUNITY;
|
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));
|
&u16_value, SNMP_V3_MAX_USER_LENGTH));
|
||||||
request->msg_user_name_len = u16_value;
|
request->msg_user_name_len = u16_value;
|
||||||
/* TODO: Implement unknown user error response */
|
/* 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 */
|
/* msgAuthenticationParameters */
|
||||||
memset(request->msg_authentication_parameters, 0, SNMP_V3_MAX_AUTH_PARAM_LENGTH);
|
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,
|
IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_authentication_parameters,
|
||||||
&u16_value, tlv.value_len));
|
&u16_value, tlv.value_len));
|
||||||
|
|
||||||
#ifdef LWIP_SNMP_V3_CRYPTO
|
#if LWIP_SNMP_V3_CRYPTO
|
||||||
if (request->msg_flags & SNMP_V3_AUTH_FLAG) {
|
if (request->msg_flags & SNMP_V3_AUTH_FLAG) {
|
||||||
/* Rewind stream */
|
/* Rewind stream */
|
||||||
IF_PARSE_EXEC(snmp_pbuf_stream_init(&pbuf_stream, request->inbound_pbuf, 0, request->inbound_pbuf->tot_len));
|
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));
|
IF_PARSE_EXEC(snmp_asn1_enc_raw(&pbuf_stream, zero_arr, tlv.value_len));
|
||||||
|
|
||||||
/* Verify authentication */
|
/* Verify authentication */
|
||||||
u8_t* key;
|
u8_t key[20];
|
||||||
u8_t algo;
|
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;
|
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(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));
|
IF_PARSE_EXEC(snmpv3_auth(&auth_stream, request->inbound_pbuf->tot_len, key, algo, hmac));
|
||||||
/* TODO: Implement error response */
|
/* TODO: Implement error response */
|
||||||
IF_PARSE_EXEC(memcmp(request->msg_authentication_parameters, hmac, SNMP_V3_MAX_AUTH_PARAM_LENGTH));
|
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,
|
IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_privacy_parameters,
|
||||||
&u16_value, SNMP_V3_MAX_PRIV_PARAM_LENGTH));
|
&u16_value, SNMP_V3_MAX_PRIV_PARAM_LENGTH));
|
||||||
|
|
||||||
#ifdef LWIP_SNMP_V3_CRYPTO
|
#if LWIP_SNMP_V3_CRYPTO
|
||||||
/* Decrypt message */
|
/* Decrypt message */
|
||||||
if (request->msg_flags & SNMP_V3_PRIV_FLAG) {
|
if (request->msg_flags & SNMP_V3_PRIV_FLAG) {
|
||||||
u8_t* key;
|
u8_t key[20];
|
||||||
u8_t algo;
|
u8_t algo;
|
||||||
|
|
||||||
IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
|
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);
|
parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv);
|
||||||
IF_PARSE_ASSERT(parent_tlv_value_len > 0);
|
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,
|
IF_PARSE_EXEC(snmpv3_crypt(&pbuf_stream, tlv.value_len, key,
|
||||||
request->msg_privacy_parameters, request->msg_authoritative_engine_boots,
|
request->msg_privacy_parameters, request->msg_authoritative_engine_boots,
|
||||||
request->msg_authoritative_engine_time, algo, SNMP_V3_PRIV_MODE_DECRYPT));
|
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) );
|
OF_BUILD_EXEC( snmp_asn1_enc_raw(pbuf_stream, request->community, request->community_strlen) );
|
||||||
#if LWIP_SNMP_V3
|
#if LWIP_SNMP_V3
|
||||||
} else {
|
} else {
|
||||||
|
const char* id;
|
||||||
|
|
||||||
/* globalData */
|
/* globalData */
|
||||||
request->outbound_msg_global_data_offset = pbuf_stream->offset;
|
request->outbound_msg_global_data_offset = pbuf_stream->offset;
|
||||||
SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, 0);
|
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));
|
OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
|
||||||
|
|
||||||
/* msgAuthoritativeEngineID */
|
/* msgAuthoritativeEngineID */
|
||||||
request->msg_authoritative_engine_id_len = LWIP_SNMPV3_GET_ENGINE_ID_LEN();
|
snmpv3_get_engine_id(&id, &request->msg_authoritative_engine_id_len);
|
||||||
memcpy(request->msg_authoritative_engine_id, LWIP_SNMPV3_GET_ENGINE_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);
|
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_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));
|
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_ans1_enc_tlv(pbuf_stream, &tlv));
|
||||||
OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_user_name, request->msg_user_name_len));
|
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 */
|
/* msgAuthenticationParameters */
|
||||||
if (request->msg_flags & SNMP_V3_AUTH_FLAG) {
|
if (request->msg_flags & SNMP_V3_AUTH_FLAG) {
|
||||||
memset(request->msg_authentication_parameters, 0, SNMP_V3_MAX_AUTH_PARAM_LENGTH);
|
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));
|
OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef LWIP_SNMP_V3_CRYPTO
|
#if LWIP_SNMP_V3_CRYPTO
|
||||||
/* msgPrivacyParameters */
|
/* msgPrivacyParameters */
|
||||||
if (request->msg_flags & SNMP_V3_PRIV_FLAG) {
|
if (request->msg_flags & SNMP_V3_PRIV_FLAG) {
|
||||||
snmpv3_build_priv_param(request->msg_privacy_parameters);
|
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 */
|
/* End of msgSecurityParameters, so we can calculate the length of this sequence later */
|
||||||
request->outbound_msg_security_parameters_end = pbuf_stream->offset;
|
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 */
|
/* For encryption we have to encapsulate the payload in an octet string */
|
||||||
if (request->msg_flags & SNMP_V3_PRIV_FLAG) {
|
if (request->msg_flags & SNMP_V3_PRIV_FLAG) {
|
||||||
request->outbound_scoped_pdu_string_offset = pbuf_stream->offset;
|
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));
|
OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
|
||||||
|
|
||||||
/* contextEngineID */
|
/* contextEngineID */
|
||||||
request->context_engine_id_len = LWIP_SNMPV3_GET_ENGINE_ID_LEN();
|
snmpv3_get_engine_id(&id, &request->context_engine_id_len);
|
||||||
memcpy(request->context_engine_id, LWIP_SNMPV3_GET_ENGINE_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);
|
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_ans1_enc_tlv(pbuf_stream, &tlv));
|
||||||
OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->context_engine_id, request->context_engine_id_len));
|
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;
|
value_value_len = 0;
|
||||||
break;
|
break;
|
||||||
case SNMP_ASN1_TYPE_OBJECT_ID:
|
case SNMP_ASN1_TYPE_OBJECT_ID:
|
||||||
if ((varbind->value_len % sizeof(u32_t)) != 0) {
|
if ((varbind->value_len & 0x03) != 0) {
|
||||||
return ERR_VAL;
|
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;
|
break;
|
||||||
case SNMP_ASN1_TYPE_COUNTER64:
|
case SNMP_ASN1_TYPE_COUNTER64:
|
||||||
if (varbind->value_len != (2 * sizeof(u32_t))) {
|
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;
|
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 */
|
/* Calculate padding for encryption */
|
||||||
if (request->version == SNMP_VERSION_3 && (request->msg_flags & SNMP_V3_PRIV_FLAG)) {
|
if (request->version == SNMP_VERSION_3 && (request->msg_flags & SNMP_V3_PRIV_FLAG)) {
|
||||||
u8_t i;
|
u8_t i;
|
||||||
for (i = 0; i < 8; i++) {
|
outbound_padding = (u8_t)((frame_size - request->outbound_scoped_pdu_seq_offset) & 0x03);
|
||||||
if ((frame_size + i - request->outbound_scoped_pdu_seq_offset) % 8 == 0) {
|
for (i = 0; i < outbound_padding; i++) {
|
||||||
outbound_padding = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
snmp_pbuf_stream_write(&request->outbound_pbuf_stream, 0);
|
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) );
|
OF_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) );
|
||||||
|
|
||||||
/* Authenticate response */
|
/* Authenticate response */
|
||||||
#if LWIP_SNMP_V3 && defined(LWIP_SNMP_V3_CRYPTO)
|
#if LWIP_SNMP_V3 && LWIP_SNMP_V3_CRYPTO
|
||||||
/* Encrypt response */
|
/* Encrypt response */
|
||||||
if (request->version == SNMP_VERSION_3 && (request->msg_flags & SNMP_V3_PRIV_FLAG)) {
|
if (request->version == SNMP_VERSION_3 && (request->msg_flags & SNMP_V3_PRIV_FLAG)) {
|
||||||
u8_t* key;
|
u8_t key[20];
|
||||||
u8_t algo;
|
u8_t algo;
|
||||||
|
|
||||||
/* complete missing length in PDU sequence */
|
/* 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);
|
- request->outbound_scoped_pdu_string_offset - 1 - 3);
|
||||||
OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv));
|
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,
|
OF_BUILD_EXEC(snmpv3_crypt(&request->outbound_pbuf_stream, tlv.value_len, key,
|
||||||
request->msg_privacy_parameters, request->msg_authoritative_engine_boots,
|
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)) {
|
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 algo;
|
||||||
u8_t hmac[20];
|
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),
|
OF_BUILD_EXEC(snmp_pbuf_stream_init(&(request->outbound_pbuf_stream),
|
||||||
request->outbound_pbuf, 0, request->outbound_pbuf->tot_len));
|
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));
|
OF_BUILD_EXEC(snmpv3_auth(&request->outbound_pbuf_stream, frame_size + outbound_padding, key, algo, hmac));
|
||||||
|
|
|
@ -49,7 +49,7 @@
|
||||||
#include "lwip/err.h"
|
#include "lwip/err.h"
|
||||||
|
|
||||||
#if LWIP_SNMP_V3
|
#if LWIP_SNMP_V3
|
||||||
#include "snmpv3.h"
|
#include "snmpv3_priv.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -32,9 +32,8 @@
|
||||||
* Author: Elias Oenal <lwip@eliasoenal.com>
|
* Author: Elias Oenal <lwip@eliasoenal.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "snmpv3.h"
|
#include "snmpv3_priv.h"
|
||||||
#include "arch/cc.h"
|
#include "lwip/apps/snmpv3.h"
|
||||||
#include "snmp_msg.h"
|
|
||||||
#include "lwip/sys.h"
|
#include "lwip/sys.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
@ -44,245 +43,55 @@
|
||||||
#include LWIP_SNMPV3_INCLUDE_ENGINE
|
#include LWIP_SNMPV3_INCLUDE_ENGINE
|
||||||
#endif
|
#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
|
#define SNMP_MAX_TIME_BOOT 2147483647UL
|
||||||
|
|
||||||
/* Engine ID, as specified in RFC3411 */
|
/** Call this if engine has been changed. Has to reset boots, see below */
|
||||||
const char*
|
|
||||||
snmpv3_get_engine_id(void)
|
|
||||||
{
|
|
||||||
return LWIP_SNMPV3_GET_ENGINE_ID();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Has to reset boots, see below */
|
|
||||||
void
|
void
|
||||||
snmpv3_engine_id_changed(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
|
* The number of times that the SNMP engine has
|
||||||
* (re-)initialized itself since snmpEngineID
|
* (re-)initialized itself since snmpEngineID
|
||||||
* was last configured.
|
* was last configured.
|
||||||
*/
|
*/
|
||||||
u32_t
|
u32_t
|
||||||
snmpv3_get_engine_boots(void)
|
snmpv3_get_engine_boots_internal(void)
|
||||||
{
|
{
|
||||||
if (LWIP_SNMPV3_GET_ENGINE_BOOTS() == 0 ||
|
if (snmpv3_get_engine_boots() == 0 ||
|
||||||
LWIP_SNMPV3_GET_ENGINE_BOOTS() < SNMP_MAX_TIME_BOOT) {
|
snmpv3_get_engine_boots() < SNMP_MAX_TIME_BOOT) {
|
||||||
return LWIP_SNMPV3_GET_ENGINE_BOOTS();
|
return snmpv3_get_engine_boots();
|
||||||
}
|
}
|
||||||
|
|
||||||
LWIP_SNMPV3_SET_ENGINE_BOOTS(SNMP_MAX_TIME_BOOT);
|
snmpv3_set_engine_boots(SNMP_MAX_TIME_BOOT);
|
||||||
return LWIP_SNMPV3_GET_ENGINE_BOOTS();
|
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
|
* Once the timer reaches 2147483647 it gets reset to zero and the
|
||||||
* engine boot ups get incremented.
|
* engine boot ups get incremented.
|
||||||
*/
|
*/
|
||||||
u32_t
|
u32_t
|
||||||
snmpv3_get_engine_time(void)
|
snmpv3_get_engine_time_internal(void)
|
||||||
{
|
{
|
||||||
if (LWIP_SNMPV3_GET_ENGINE_TIME() >= SNMP_MAX_TIME_BOOT) {
|
if (snmpv3_get_engine_time() >= SNMP_MAX_TIME_BOOT) {
|
||||||
LWIP_SNMPV3_RESET_ENGINE_TIME();
|
snmpv3_reset_engine_time();
|
||||||
|
|
||||||
if (LWIP_SNMPV3_GET_ENGINE_BOOTS() < SNMP_MAX_TIME_BOOT - 1) {
|
if (snmpv3_get_engine_boots() < SNMP_MAX_TIME_BOOT - 1) {
|
||||||
LWIP_SNMPV3_SET_ENGINE_BOOTS(LWIP_SNMPV3_GET_ENGINE_BOOTS() + 1);
|
snmpv3_set_engine_boots(snmpv3_get_engine_boots() + 1);
|
||||||
} else {
|
} 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
|
#if 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This function ignores the byte order suggestion in RFC3414
|
/* This function ignores the byte order suggestion in RFC3414
|
||||||
* since it simply doesn't influence the effectiveness of an IV.
|
* since it simply doesn't influence the effectiveness of an IV.
|
||||||
|
|
|
@ -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 */
|
|
141
src/apps/snmp/snmpv3_dummy.c
Normal file
141
src/apps/snmp/snmpv3_dummy.c
Normal 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)
|
||||||
|
{
|
||||||
|
}
|
317
src/apps/snmp/snmpv3_mbedtls.c
Normal file
317
src/apps/snmp/snmpv3_mbedtls.c
Normal 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 */
|
66
src/apps/snmp/snmpv3_priv.h
Normal file
66
src/apps/snmp/snmpv3_priv.h
Normal 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 */
|
|
@ -255,5 +255,14 @@
|
||||||
#define SNMP_LWIP_GETBULK_MAX_REPETITIONS 0
|
#define SNMP_LWIP_GETBULK_MAX_REPETITIONS 0
|
||||||
#endif
|
#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 */
|
||||||
|
|
90
src/include/lwip/apps/snmpv3.h
Normal file
90
src/include/lwip/apps/snmpv3.h
Normal 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 */
|
Loading…
Reference in New Issue
Block a user