mbed-os for GR-LYCHEE

Dependents:   mbed-os-example-blinky-gr-lychee GR-Boads_Camera_sample GR-Boards_Audio_Recoder GR-Boads_Camera_DisplayApp ... more

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