Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
lwip_snmpv3_mbedtls.c
00001 /** 00002 * @file 00003 * SNMPv3 crypto/auth functions implemented for ARM mbedtls. 00004 */ 00005 00006 /* 00007 * Copyright (c) 2016 Elias Oenal and Dirk Ziegelmeier. 00008 * All rights reserved. 00009 * 00010 * Redistribution and use in source and binary forms, with or without modification, 00011 * are permitted provided that the following conditions are met: 00012 * 00013 * 1. Redistributions of source code must retain the above copyright notice, 00014 * this list of conditions and the following disclaimer. 00015 * 2. Redistributions in binary form must reproduce the above copyright notice, 00016 * this list of conditions and the following disclaimer in the documentation 00017 * and/or other materials provided with the distribution. 00018 * 3. The name of the author may not be used to endorse or promote products 00019 * derived from this software without specific prior written permission. 00020 * 00021 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 00022 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 00023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 00024 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00025 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 00026 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00027 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00028 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 00029 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 00030 * OF SUCH DAMAGE. 00031 * 00032 * Author: Elias Oenal <lwip@eliasoenal.com> 00033 * Dirk Ziegelmeier <dirk@ziegelmeier.net> 00034 */ 00035 00036 #include "lwip/apps/snmpv3.h" 00037 #include "snmpv3_priv.h" 00038 #include "lwip/arch.h" 00039 #include "snmp_msg.h" 00040 #include "lwip/sys.h" 00041 #include <string.h> 00042 00043 #if LWIP_SNMP && LWIP_SNMP_V3 && LWIP_SNMP_V3_MBEDTLS 00044 00045 #include "mbedtls/md.h" 00046 #include "mbedtls/cipher.h" 00047 00048 #include "mbedtls/md5.h" 00049 #include "mbedtls/sha1.h" 00050 #include "mbedtls/platform.h" 00051 00052 err_t 00053 snmpv3_auth(struct snmp_pbuf_stream *stream, u16_t length, 00054 const u8_t *key, snmpv3_auth_algo_t algo, u8_t *hmac_out) 00055 { 00056 u32_t i; 00057 u8_t key_len; 00058 const mbedtls_md_info_t *md_info; 00059 mbedtls_md_context_t ctx; 00060 struct snmp_pbuf_stream read_stream; 00061 snmp_pbuf_stream_init(&read_stream, stream->pbuf, stream->offset, stream->length); 00062 00063 #if defined(MBEDTLS_PLATFORM_C) 00064 if (mbedtls_platform_setup(NULL) != 0) { 00065 return ERR_ARG; 00066 } 00067 #endif /* MBEDTLS_PLATFORM_C */ 00068 if (algo == SNMP_V3_AUTH_ALGO_MD5) { 00069 md_info = mbedtls_md_info_from_type(MBEDTLS_MD_MD5); 00070 key_len = SNMP_V3_MD5_LEN; 00071 } else if (algo == SNMP_V3_AUTH_ALGO_SHA) { 00072 md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1); 00073 key_len = SNMP_V3_SHA_LEN; 00074 } else { 00075 goto platform_teardown; 00076 } 00077 00078 mbedtls_md_init(&ctx); 00079 if(mbedtls_md_setup(&ctx, md_info, 1) != 0) { 00080 goto platform_teardown; 00081 } 00082 00083 if (mbedtls_md_hmac_starts(&ctx, key, key_len) != 0) { 00084 goto free_md; 00085 } 00086 00087 for (i = 0; i < length; i++) { 00088 u8_t byte; 00089 00090 if (snmp_pbuf_stream_read(&read_stream, &byte)) { 00091 goto free_md; 00092 } 00093 00094 if (mbedtls_md_hmac_update(&ctx, &byte, 1) != 0) { 00095 goto free_md; 00096 } 00097 } 00098 00099 if (mbedtls_md_hmac_finish(&ctx, hmac_out) != 0) { 00100 goto free_md; 00101 } 00102 00103 mbedtls_md_free(&ctx); 00104 #if defined(MBEDTLS_PLATFORM_C) 00105 mbedtls_platform_teardown(NULL); 00106 #endif /* MBEDTLS_PLATFORM_C */ 00107 return ERR_OK; 00108 00109 free_md: 00110 mbedtls_md_free(&ctx); 00111 platform_teardown: 00112 #if defined(MBEDTLS_PLATFORM_C) 00113 mbedtls_platform_teardown(NULL); 00114 #endif /* MBEDTLS_PLATFORM_C */ 00115 return ERR_ARG; 00116 } 00117 00118 #if LWIP_SNMP_V3_CRYPTO 00119 00120 err_t 00121 snmpv3_crypt(struct snmp_pbuf_stream *stream, u16_t length, 00122 const u8_t *key, const u8_t *priv_param, const u32_t engine_boots, 00123 const u32_t engine_time, snmpv3_priv_algo_t algo, snmpv3_priv_mode_t mode) 00124 { 00125 size_t i; 00126 mbedtls_cipher_context_t ctx; 00127 const mbedtls_cipher_info_t *cipher_info; 00128 00129 struct snmp_pbuf_stream read_stream; 00130 struct snmp_pbuf_stream write_stream; 00131 snmp_pbuf_stream_init(&read_stream, stream->pbuf, stream->offset, stream->length); 00132 snmp_pbuf_stream_init(&write_stream, stream->pbuf, stream->offset, stream->length); 00133 #if defined(MBEDTLS_PLATFORM_C) 00134 if (mbedtls_platform_setup(NULL) != 0) { 00135 return ERR_ARG; 00136 } 00137 #endif /* MBEDTLS_PLATFORM_C */ 00138 mbedtls_cipher_init(&ctx); 00139 00140 if (algo == SNMP_V3_PRIV_ALGO_DES) { 00141 u8_t iv_local[8]; 00142 u8_t out_bytes[8]; 00143 size_t out_len; 00144 00145 /* RFC 3414 mandates padding for DES */ 00146 if ((length & 0x07) != 0) { 00147 goto platform_teardown; 00148 } 00149 00150 cipher_info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_DES_CBC); 00151 if(mbedtls_cipher_setup(&ctx, cipher_info) != 0) { 00152 goto platform_teardown 00153 } 00154 if(mbedtls_cipher_set_padding_mode(&ctx, MBEDTLS_PADDING_NONE) != 0) { 00155 goto platform_teardown; 00156 } 00157 if (mbedtls_cipher_setkey(&ctx, key, 8 * 8, (mode == SNMP_V3_PRIV_MODE_ENCRYPT) ? MBEDTLS_ENCRYPT : MBEDTLS_DECRYPT) != 0) { 00158 goto error; 00159 } 00160 00161 /* Prepare IV */ 00162 for (i = 0; i < LWIP_ARRAYSIZE(iv_local); i++) { 00163 iv_local[i] = priv_param[i] ^ key[i + 8]; 00164 } 00165 if (mbedtls_cipher_set_iv(&ctx, iv_local, LWIP_ARRAYSIZE(iv_local)) != 0) { 00166 goto error; 00167 } 00168 00169 for (i = 0; i < length; i += 8) { 00170 size_t j; 00171 u8_t in_bytes[8]; 00172 out_len = LWIP_ARRAYSIZE(out_bytes) ; 00173 00174 for (j = 0; j < LWIP_ARRAYSIZE(in_bytes); j++) { 00175 if (snmp_pbuf_stream_read(&read_stream, &in_bytes[j]) != ERR_OK) { 00176 goto error; 00177 } 00178 } 00179 00180 if (mbedtls_cipher_update(&ctx, in_bytes, LWIP_ARRAYSIZE(in_bytes), out_bytes, &out_len) != 0) { 00181 goto error; 00182 } 00183 00184 if (snmp_pbuf_stream_writebuf(&write_stream, out_bytes, (u16_t)out_len) != ERR_OK) { 00185 goto error; 00186 } 00187 } 00188 00189 out_len = LWIP_ARRAYSIZE(out_bytes); 00190 if (mbedtls_cipher_finish(&ctx, out_bytes, &out_len) != 0) { 00191 goto error; 00192 } 00193 00194 if (snmp_pbuf_stream_writebuf(&write_stream, out_bytes, (u16_t)out_len) != ERR_OK) { 00195 goto error; 00196 } 00197 } else if (algo == SNMP_V3_PRIV_ALGO_AES) { 00198 u8_t iv_local[16]; 00199 00200 cipher_info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_CFB128); 00201 if(mbedtls_cipher_setup(&ctx, cipher_info) != 0) { 00202 goto platform_teardown; 00203 } 00204 if (mbedtls_cipher_setkey(&ctx, key, 16 * 8, (mode == SNMP_V3_PRIV_MODE_ENCRYPT) ? MBEDTLS_ENCRYPT : MBEDTLS_DECRYPT) != 0) { 00205 goto error; 00206 } 00207 00208 /* 00209 * IV is the big endian concatenation of boots, 00210 * uptime and priv param - see RFC3826. 00211 */ 00212 iv_local[0 + 0] = (engine_boots >> 24) & 0xFF; 00213 iv_local[0 + 1] = (engine_boots >> 16) & 0xFF; 00214 iv_local[0 + 2] = (engine_boots >> 8) & 0xFF; 00215 iv_local[0 + 3] = (engine_boots >> 0) & 0xFF; 00216 iv_local[4 + 0] = (engine_time >> 24) & 0xFF; 00217 iv_local[4 + 1] = (engine_time >> 16) & 0xFF; 00218 iv_local[4 + 2] = (engine_time >> 8) & 0xFF; 00219 iv_local[4 + 3] = (engine_time >> 0) & 0xFF; 00220 SMEMCPY(iv_local + 8, priv_param, 8); 00221 if (mbedtls_cipher_set_iv(&ctx, iv_local, LWIP_ARRAYSIZE(iv_local)) != 0) { 00222 goto error; 00223 } 00224 00225 for (i = 0; i < length; i++) { 00226 u8_t in_byte; 00227 u8_t out_byte; 00228 size_t out_len = sizeof(out_byte); 00229 00230 if (snmp_pbuf_stream_read(&read_stream, &in_byte) != ERR_OK) { 00231 goto error; 00232 } 00233 if (mbedtls_cipher_update(&ctx, &in_byte, sizeof(in_byte), &out_byte, &out_len) != 0) { 00234 goto error; 00235 } 00236 if (snmp_pbuf_stream_write(&write_stream, out_byte) != ERR_OK) { 00237 goto error; 00238 } 00239 } 00240 } else { 00241 goto platform_teardown; 00242 } 00243 00244 mbedtls_cipher_free(&ctx); 00245 return ERR_OK; 00246 00247 error: 00248 mbedtls_cipher_free(&ctx); 00249 platform_teardown: 00250 #if defined(MBEDTLS_PLATFORM_C) 00251 mbedtls_platform_teardown(NULL); 00252 #endif /* MBEDTLS_PLATFORM_C */ 00253 return ERR_ARG; 00254 } 00255 00256 #endif /* LWIP_SNMP_V3_CRYPTO */ 00257 00258 /* A.2.1. Password to Key Sample Code for MD5 */ 00259 void 00260 snmpv3_password_to_key_md5( 00261 const u8_t *password, /* IN */ 00262 size_t passwordlen, /* IN */ 00263 const u8_t *engineID, /* IN - pointer to snmpEngineID */ 00264 u8_t engineLength,/* IN - length of snmpEngineID */ 00265 u8_t *key) /* OUT - pointer to caller 16-octet buffer */ 00266 { 00267 mbedtls_md5_context MD; 00268 u8_t *cp, password_buf[64]; 00269 u32_t password_index = 0; 00270 u8_t i; 00271 u32_t count = 0; 00272 00273 #if defined(MBEDTLS_PLATFORM_C) 00274 if (mbedtls_platform_setup(NULL) != 0) { 00275 goto end; 00276 } 00277 #endif /* MBEDTLS_PLATFORM_C */ 00278 mbedtls_md5_init(&MD); /* initialize MD5 */ 00279 mbedtls_md5_starts(&MD); 00280 00281 /**********************************************/ 00282 /* Use while loop until we've done 1 Megabyte */ 00283 /**********************************************/ 00284 while (count < 1048576) { 00285 cp = password_buf; 00286 for (i = 0; i < 64; i++) { 00287 /*************************************************/ 00288 /* Take the next octet of the password, wrapping */ 00289 /* to the beginning of the password as necessary.*/ 00290 /*************************************************/ 00291 *cp++ = password[password_index++ % passwordlen]; 00292 } 00293 mbedtls_md5_update(&MD, password_buf, 64); 00294 count += 64; 00295 } 00296 mbedtls_md5_finish(&MD, key); /* tell MD5 we're done */ 00297 00298 /*****************************************************/ 00299 /* Now localize the key with the engineID and pass */ 00300 /* through MD5 to produce final key */ 00301 /* May want to ensure that engineLength <= 32, */ 00302 /* otherwise need to use a buffer larger than 64 */ 00303 /*****************************************************/ 00304 SMEMCPY(password_buf, key, 16); 00305 MEMCPY(password_buf + 16, engineID, engineLength); 00306 SMEMCPY(password_buf + 16 + engineLength, key, 16); 00307 00308 mbedtls_md5_starts(&MD); 00309 mbedtls_md5_update(&MD, password_buf, 32 + engineLength); 00310 mbedtls_md5_finish(&MD, key); 00311 00312 mbedtls_md5_free(&MD); 00313 00314 end: 00315 #if defined(MBEDTLS_PLATFORM_C) 00316 mbedtls_platform_teardown(NULL); 00317 #endif /* MBEDTLS_PLATFORM_C */ 00318 return; 00319 } 00320 00321 /* A.2.2. Password to Key Sample Code for SHA */ 00322 void 00323 snmpv3_password_to_key_sha( 00324 const u8_t *password, /* IN */ 00325 size_t passwordlen, /* IN */ 00326 const u8_t *engineID, /* IN - pointer to snmpEngineID */ 00327 u8_t engineLength,/* IN - length of snmpEngineID */ 00328 u8_t *key) /* OUT - pointer to caller 20-octet buffer */ 00329 { 00330 mbedtls_sha1_context SH; 00331 u8_t *cp, password_buf[72]; 00332 u32_t password_index = 0; 00333 u8_t i; 00334 u32_t count = 0; 00335 00336 #if defined(MBEDTLS_PLATFORM_C) 00337 if (mbedtls_platform_setup(NULL) != 0) { 00338 goto end; 00339 } 00340 #endif /* MBEDTLS_PLATFORM_C */ 00341 mbedtls_sha1_init(&SH); /* initialize SHA */ 00342 mbedtls_sha1_starts(&SH); 00343 00344 /**********************************************/ 00345 /* Use while loop until we've done 1 Megabyte */ 00346 /**********************************************/ 00347 while (count < 1048576) { 00348 cp = password_buf; 00349 for (i = 0; i < 64; i++) { 00350 /*************************************************/ 00351 /* Take the next octet of the password, wrapping */ 00352 /* to the beginning of the password as necessary.*/ 00353 /*************************************************/ 00354 *cp++ = password[password_index++ % passwordlen]; 00355 } 00356 mbedtls_sha1_update(&SH, password_buf, 64); 00357 count += 64; 00358 } 00359 mbedtls_sha1_finish(&SH, key); /* tell SHA we're done */ 00360 00361 /*****************************************************/ 00362 /* Now localize the key with the engineID and pass */ 00363 /* through SHA to produce final key */ 00364 /* May want to ensure that engineLength <= 32, */ 00365 /* otherwise need to use a buffer larger than 72 */ 00366 /*****************************************************/ 00367 SMEMCPY(password_buf, key, 20); 00368 MEMCPY(password_buf + 20, engineID, engineLength); 00369 SMEMCPY(password_buf + 20 + engineLength, key, 20); 00370 00371 mbedtls_sha1_starts(&SH); 00372 mbedtls_sha1_update(&SH, password_buf, 40 + engineLength); 00373 mbedtls_sha1_finish(&SH, key); 00374 00375 mbedtls_sha1_free(&SH); 00376 00377 end: 00378 #if defined(MBEDTLS_PLATFORM_C) 00379 mbedtls_platform_teardown(NULL); 00380 #endif /* MBEDTLS_PLATFORM_C */ 00381 return; 00382 } 00383 00384 #endif /* LWIP_SNMP && LWIP_SNMP_V3 && LWIP_SNMP_V3_MBEDTLS */
Generated on Tue Jul 12 2022 13:54:30 by
