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_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 \
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
#include "lwip/err.h"
|
||||
|
||||
#if LWIP_SNMP_V3
|
||||
#include "snmpv3.h"
|
||||
#include "snmpv3_priv.h"
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
#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