Marco Zecchini
/
Example_RTOS
Rtos API example
Embed:
(wiki syntax)
Show/hide line numbers
lwip_snmpv3_mbedtls.c
Go to the documentation of this file.
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 00051 err_t 00052 snmpv3_auth(struct snmp_pbuf_stream* stream, u16_t length, 00053 const u8_t* key, u8_t algo, u8_t* hmac_out) 00054 { 00055 u32_t i; 00056 u8_t key_len; 00057 const mbedtls_md_info_t *md_info; 00058 mbedtls_md_context_t ctx; 00059 struct snmp_pbuf_stream read_stream; 00060 snmp_pbuf_stream_init(&read_stream, stream->pbuf, stream->offset, stream->length); 00061 00062 if (algo == SNMP_V3_AUTH_ALGO_MD5) { 00063 md_info = mbedtls_md_info_from_type(MBEDTLS_MD_MD5); 00064 key_len = SNMP_V3_MD5_LEN; 00065 } else if (algo == SNMP_V3_AUTH_ALGO_SHA) { 00066 md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1); 00067 key_len = SNMP_V3_SHA_LEN; 00068 } else { 00069 return ERR_ARG; 00070 } 00071 00072 mbedtls_md_init(&ctx); 00073 if(mbedtls_md_setup(&ctx, md_info, 1) != 0) { 00074 return ERR_ARG; 00075 } 00076 00077 if (mbedtls_md_hmac_starts(&ctx, key, key_len) != 0) { 00078 goto free_md; 00079 } 00080 00081 for (i = 0; i < length; i++) { 00082 u8_t byte; 00083 00084 if (snmp_pbuf_stream_read(&read_stream, &byte)) { 00085 goto free_md; 00086 } 00087 00088 if (mbedtls_md_hmac_update(&ctx, &byte, 1) != 0) { 00089 goto free_md; 00090 } 00091 } 00092 00093 if (mbedtls_md_hmac_finish(&ctx, hmac_out) != 0) { 00094 goto free_md; 00095 } 00096 00097 mbedtls_md_free(&ctx); 00098 return ERR_OK; 00099 00100 free_md: 00101 mbedtls_md_free(&ctx); 00102 return ERR_ARG; 00103 } 00104 00105 #if LWIP_SNMP_V3_CRYPTO 00106 00107 err_t 00108 snmpv3_crypt(struct snmp_pbuf_stream* stream, u16_t length, 00109 const u8_t* key, const u8_t* priv_param, const u32_t engine_boots, 00110 const u32_t engine_time, u8_t algo, u8_t mode) 00111 { 00112 size_t i; 00113 mbedtls_cipher_context_t ctx; 00114 const mbedtls_cipher_info_t *cipher_info; 00115 00116 struct snmp_pbuf_stream read_stream; 00117 struct snmp_pbuf_stream write_stream; 00118 snmp_pbuf_stream_init(&read_stream, stream->pbuf, stream->offset, stream->length); 00119 snmp_pbuf_stream_init(&write_stream, stream->pbuf, stream->offset, stream->length); 00120 mbedtls_cipher_init(&ctx); 00121 00122 if (algo == SNMP_V3_PRIV_ALGO_DES) { 00123 u8_t iv_local[8]; 00124 u8_t out_bytes[8]; 00125 size_t out_len; 00126 00127 /* RFC 3414 mandates padding for DES */ 00128 if ((length & 0x07) != 0) { 00129 return ERR_ARG; 00130 } 00131 00132 cipher_info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_DES_CBC); 00133 if(mbedtls_cipher_setup(&ctx, cipher_info) != 0) { 00134 return ERR_ARG; 00135 } 00136 if(mbedtls_cipher_set_padding_mode(&ctx, MBEDTLS_PADDING_NONE) != 0) { 00137 return ERR_ARG; 00138 } 00139 if(mbedtls_cipher_setkey(&ctx, key, 8*8, (mode == SNMP_V3_PRIV_MODE_ENCRYPT)? MBEDTLS_ENCRYPT : MBEDTLS_DECRYPT) != 0) { 00140 goto error; 00141 } 00142 00143 /* Prepare IV */ 00144 for (i = 0; i < LWIP_ARRAYSIZE(iv_local); i++) { 00145 iv_local[i] = priv_param[i] ^ key[i + 8]; 00146 } 00147 if(mbedtls_cipher_set_iv(&ctx, iv_local, LWIP_ARRAYSIZE(iv_local)) != 0) { 00148 goto error; 00149 } 00150 00151 for (i = 0; i < length; i += 8) { 00152 size_t j; 00153 u8_t in_bytes[8]; 00154 out_len = LWIP_ARRAYSIZE(out_bytes) ; 00155 00156 for (j = 0; j < LWIP_ARRAYSIZE(in_bytes); j++) { 00157 snmp_pbuf_stream_read(&read_stream, &in_bytes[j]); 00158 } 00159 00160 if(mbedtls_cipher_update(&ctx, in_bytes, LWIP_ARRAYSIZE(in_bytes), out_bytes, &out_len) != 0) { 00161 goto error; 00162 } 00163 00164 snmp_pbuf_stream_writebuf(&write_stream, out_bytes, out_len); 00165 } 00166 00167 out_len = LWIP_ARRAYSIZE(out_bytes); 00168 if(mbedtls_cipher_finish(&ctx, out_bytes, &out_len) != 0) { 00169 goto error; 00170 } 00171 snmp_pbuf_stream_writebuf(&write_stream, out_bytes, out_len); 00172 } else if (algo == SNMP_V3_PRIV_ALGO_AES) { 00173 u8_t iv_local[16]; 00174 00175 cipher_info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_CFB128); 00176 if(mbedtls_cipher_setup(&ctx, cipher_info) != 0) { 00177 return ERR_ARG; 00178 } 00179 if(mbedtls_cipher_setkey(&ctx, key, 16*8, (mode == SNMP_V3_PRIV_MODE_ENCRYPT)? MBEDTLS_ENCRYPT : MBEDTLS_DECRYPT) != 0) { 00180 goto error; 00181 } 00182 00183 /* 00184 * IV is the big endian concatenation of boots, 00185 * uptime and priv param - see RFC3826. 00186 */ 00187 iv_local[0 + 0] = (engine_boots >> 24) & 0xFF; 00188 iv_local[0 + 1] = (engine_boots >> 16) & 0xFF; 00189 iv_local[0 + 2] = (engine_boots >> 8) & 0xFF; 00190 iv_local[0 + 3] = (engine_boots >> 0) & 0xFF; 00191 iv_local[4 + 0] = (engine_time >> 24) & 0xFF; 00192 iv_local[4 + 1] = (engine_time >> 16) & 0xFF; 00193 iv_local[4 + 2] = (engine_time >> 8) & 0xFF; 00194 iv_local[4 + 3] = (engine_time >> 0) & 0xFF; 00195 SMEMCPY(iv_local + 8, priv_param, 8); 00196 if(mbedtls_cipher_set_iv(&ctx, iv_local, LWIP_ARRAYSIZE(iv_local)) != 0) { 00197 goto error; 00198 } 00199 00200 for (i = 0; i < length; i++) { 00201 u8_t in_byte; 00202 u8_t out_byte; 00203 size_t out_len = sizeof(out_byte); 00204 00205 snmp_pbuf_stream_read(&read_stream, &in_byte); 00206 if(mbedtls_cipher_update(&ctx, &in_byte, sizeof(in_byte), &out_byte, &out_len) != 0) { 00207 goto error; 00208 } 00209 snmp_pbuf_stream_write(&write_stream, out_byte); 00210 } 00211 } else { 00212 return ERR_ARG; 00213 } 00214 00215 mbedtls_cipher_free(&ctx); 00216 return ERR_OK; 00217 00218 error: 00219 mbedtls_cipher_free(&ctx); 00220 return ERR_OK; 00221 } 00222 00223 #endif /* LWIP_SNMP_V3_CRYPTO */ 00224 00225 /* A.2.1. Password to Key Sample Code for MD5 */ 00226 void 00227 snmpv3_password_to_key_md5( 00228 const u8_t *password, /* IN */ 00229 u8_t passwordlen, /* IN */ 00230 const u8_t *engineID, /* IN - pointer to snmpEngineID */ 00231 u8_t engineLength,/* IN - length of snmpEngineID */ 00232 u8_t *key) /* OUT - pointer to caller 16-octet buffer */ 00233 { 00234 mbedtls_md5_context MD; 00235 u8_t *cp, password_buf[64]; 00236 u32_t password_index = 0; 00237 u8_t i; 00238 u32_t count = 0; 00239 00240 mbedtls_md5_init(&MD); /* initialize MD5 */ 00241 mbedtls_md5_starts(&MD); 00242 00243 /**********************************************/ 00244 /* Use while loop until we've done 1 Megabyte */ 00245 /**********************************************/ 00246 while (count < 1048576) { 00247 cp = password_buf; 00248 for (i = 0; i < 64; i++) { 00249 /*************************************************/ 00250 /* Take the next octet of the password, wrapping */ 00251 /* to the beginning of the password as necessary.*/ 00252 /*************************************************/ 00253 *cp++ = password[password_index++ % passwordlen]; 00254 } 00255 mbedtls_md5_update(&MD, password_buf, 64); 00256 count += 64; 00257 } 00258 mbedtls_md5_finish(&MD, key); /* tell MD5 we're done */ 00259 00260 /*****************************************************/ 00261 /* Now localize the key with the engineID and pass */ 00262 /* through MD5 to produce final key */ 00263 /* May want to ensure that engineLength <= 32, */ 00264 /* otherwise need to use a buffer larger than 64 */ 00265 /*****************************************************/ 00266 SMEMCPY(password_buf, key, 16); 00267 MEMCPY(password_buf + 16, engineID, engineLength); 00268 SMEMCPY(password_buf + 16 + engineLength, key, 16); 00269 00270 mbedtls_md5_starts(&MD); 00271 mbedtls_md5_update(&MD, password_buf, 32 + engineLength); 00272 mbedtls_md5_finish(&MD, key); 00273 00274 mbedtls_md5_free(&MD); 00275 return; 00276 } 00277 00278 /* A.2.2. Password to Key Sample Code for SHA */ 00279 void 00280 snmpv3_password_to_key_sha( 00281 const u8_t *password, /* IN */ 00282 u8_t passwordlen, /* IN */ 00283 const u8_t *engineID, /* IN - pointer to snmpEngineID */ 00284 u8_t engineLength,/* IN - length of snmpEngineID */ 00285 u8_t *key) /* OUT - pointer to caller 20-octet buffer */ 00286 { 00287 mbedtls_sha1_context SH; 00288 u8_t *cp, password_buf[72]; 00289 u32_t password_index = 0; 00290 u8_t i; 00291 u32_t count = 0; 00292 00293 mbedtls_sha1_init(&SH); /* initialize SHA */ 00294 mbedtls_sha1_starts(&SH); 00295 00296 /**********************************************/ 00297 /* Use while loop until we've done 1 Megabyte */ 00298 /**********************************************/ 00299 while (count < 1048576) { 00300 cp = password_buf; 00301 for (i = 0; i < 64; i++) { 00302 /*************************************************/ 00303 /* Take the next octet of the password, wrapping */ 00304 /* to the beginning of the password as necessary.*/ 00305 /*************************************************/ 00306 *cp++ = password[password_index++ % passwordlen]; 00307 } 00308 mbedtls_sha1_update(&SH, password_buf, 64); 00309 count += 64; 00310 } 00311 mbedtls_sha1_finish(&SH, key); /* tell SHA we're done */ 00312 00313 /*****************************************************/ 00314 /* Now localize the key with the engineID and pass */ 00315 /* through SHA to produce final key */ 00316 /* May want to ensure that engineLength <= 32, */ 00317 /* otherwise need to use a buffer larger than 72 */ 00318 /*****************************************************/ 00319 SMEMCPY(password_buf, key, 20); 00320 MEMCPY(password_buf + 20, engineID, engineLength); 00321 SMEMCPY(password_buf + 20 + engineLength, key, 20); 00322 00323 mbedtls_sha1_starts(&SH); 00324 mbedtls_sha1_update(&SH, password_buf, 40 + engineLength); 00325 mbedtls_sha1_finish(&SH, key); 00326 00327 mbedtls_sha1_free(&SH); 00328 return; 00329 } 00330 00331 #endif /* LWIP_SNMP && LWIP_SNMP_V3 && LWIP_SNMP_V3_MBEDTLS */
Generated on Sun Jul 17 2022 08:25:25 by 1.7.2