Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lwip_snmpv3_mbedtls.c Source File

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