Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / third_party / lwip / repo / lwip / src / apps / snmp / snmpv3_mbedtls.c
1 /**
2  * @file
3  * SNMPv3 crypto/auth functions implemented for ARM mbedtls.
4  */
5
6 /*
7  * Copyright (c) 2016 Elias Oenal and Dirk Ziegelmeier.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without modification,
11  * are permitted provided that the following conditions are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright notice,
14  *    this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright notice,
16  *    this list of conditions and the following disclaimer in the documentation
17  *    and/or other materials provided with the distribution.
18  * 3. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
22  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
24  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
26  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
30  * OF SUCH DAMAGE.
31  *
32  * Author: Elias Oenal <lwip@eliasoenal.com>
33  *         Dirk Ziegelmeier <dirk@ziegelmeier.net>
34  */
35
36 #include "lwip/apps/snmpv3.h"
37 #include "snmpv3_priv.h"
38 #include "lwip/arch.h"
39 #include "snmp_msg.h"
40 #include "lwip/sys.h"
41 #include <string.h>
42
43 #if LWIP_SNMP && LWIP_SNMP_V3 && LWIP_SNMP_V3_MBEDTLS
44
45 #include "mbedtls/md.h"
46 #include "mbedtls/cipher.h"
47
48 #include "mbedtls/md5.h"
49 #include "mbedtls/sha1.h"
50
51 err_t
52 snmpv3_auth(struct snmp_pbuf_stream* stream, u16_t length,
53     const u8_t* key, u8_t algo, u8_t* hmac_out)
54 {
55   u32_t i;
56   u8_t key_len;
57   const mbedtls_md_info_t *md_info;
58   mbedtls_md_context_t ctx;
59   struct snmp_pbuf_stream read_stream;
60   snmp_pbuf_stream_init(&read_stream, stream->pbuf, stream->offset, stream->length);
61
62   if (algo == SNMP_V3_AUTH_ALGO_MD5) {
63     md_info = mbedtls_md_info_from_type(MBEDTLS_MD_MD5);
64     key_len = SNMP_V3_MD5_LEN;
65   } else if (algo == SNMP_V3_AUTH_ALGO_SHA) {
66     md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
67     key_len = SNMP_V3_SHA_LEN;
68   } else {
69     return ERR_ARG;
70   }
71
72   mbedtls_md_init(&ctx);
73   if(mbedtls_md_setup(&ctx, md_info, 1) != 0) {
74     return ERR_ARG;
75   }
76           
77   if (mbedtls_md_hmac_starts(&ctx, key, key_len) != 0) {
78     goto free_md;
79   }
80
81   for (i = 0; i < length; i++) {
82     u8_t byte;
83
84     if (snmp_pbuf_stream_read(&read_stream, &byte)) {
85       goto free_md;
86     }
87
88     if (mbedtls_md_hmac_update(&ctx, &byte, 1) != 0) {
89       goto free_md;
90     }
91   }
92
93   if (mbedtls_md_hmac_finish(&ctx, hmac_out) != 0) {
94     goto free_md;
95   }
96
97   mbedtls_md_free(&ctx);
98   return ERR_OK;
99   
100 free_md:
101   mbedtls_md_free(&ctx);
102   return ERR_ARG;
103 }
104
105 #if LWIP_SNMP_V3_CRYPTO
106
107 err_t
108 snmpv3_crypt(struct snmp_pbuf_stream* stream, u16_t length,
109     const u8_t* key, const u8_t* priv_param, const u32_t engine_boots,
110     const u32_t engine_time, u8_t algo, u8_t mode)
111 {
112   size_t i;
113   mbedtls_cipher_context_t ctx;
114   const mbedtls_cipher_info_t *cipher_info;
115
116   struct snmp_pbuf_stream read_stream;
117   struct snmp_pbuf_stream write_stream;
118   snmp_pbuf_stream_init(&read_stream, stream->pbuf, stream->offset, stream->length);
119   snmp_pbuf_stream_init(&write_stream, stream->pbuf, stream->offset, stream->length);
120   mbedtls_cipher_init(&ctx);
121
122   if (algo == SNMP_V3_PRIV_ALGO_DES) {
123     u8_t iv_local[8];
124     u8_t out_bytes[8];
125     size_t out_len;
126
127     /* RFC 3414 mandates padding for DES */
128     if ((length & 0x07) != 0) {
129       return ERR_ARG;
130     }
131
132     cipher_info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_DES_CBC);
133     if(mbedtls_cipher_setup(&ctx, cipher_info) != 0) {
134       return ERR_ARG;
135     }
136     if(mbedtls_cipher_set_padding_mode(&ctx, MBEDTLS_PADDING_NONE) != 0) {
137       return ERR_ARG;
138     }
139     if(mbedtls_cipher_setkey(&ctx, key, 8*8, (mode == SNMP_V3_PRIV_MODE_ENCRYPT)? MBEDTLS_ENCRYPT : MBEDTLS_DECRYPT) != 0) {
140       goto error;
141     }
142
143     /* Prepare IV */    
144     for (i = 0; i < LWIP_ARRAYSIZE(iv_local); i++) {
145       iv_local[i] = priv_param[i] ^ key[i + 8];
146     }
147     if(mbedtls_cipher_set_iv(&ctx, iv_local, LWIP_ARRAYSIZE(iv_local)) != 0) {
148       goto error;
149     }
150
151     for (i = 0; i < length; i += 8) {
152       size_t j;
153       u8_t in_bytes[8];
154       out_len = LWIP_ARRAYSIZE(out_bytes) ;
155       
156       for (j = 0; j < LWIP_ARRAYSIZE(in_bytes); j++) {
157         snmp_pbuf_stream_read(&read_stream, &in_bytes[j]);
158       }
159
160       if(mbedtls_cipher_update(&ctx, in_bytes, LWIP_ARRAYSIZE(in_bytes), out_bytes, &out_len) != 0) {
161         goto error;
162       }
163
164       snmp_pbuf_stream_writebuf(&write_stream, out_bytes, out_len);
165     }
166     
167     out_len = LWIP_ARRAYSIZE(out_bytes);
168     if(mbedtls_cipher_finish(&ctx, out_bytes, &out_len) != 0) {
169       goto error;
170     }
171     snmp_pbuf_stream_writebuf(&write_stream, out_bytes, out_len);
172   } else if (algo == SNMP_V3_PRIV_ALGO_AES) {
173     u8_t iv_local[16];
174
175     cipher_info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_CFB128);
176     if(mbedtls_cipher_setup(&ctx, cipher_info) != 0) {
177       return ERR_ARG;
178     }
179     if(mbedtls_cipher_setkey(&ctx, key, 16*8, (mode == SNMP_V3_PRIV_MODE_ENCRYPT)? MBEDTLS_ENCRYPT : MBEDTLS_DECRYPT) != 0) {
180       goto error;
181     }
182
183     /*
184      * IV is the big endian concatenation of boots,
185      * uptime and priv param - see RFC3826.
186      */
187     iv_local[0 + 0] = (engine_boots >> 24) & 0xFF;
188     iv_local[0 + 1] = (engine_boots >> 16) & 0xFF;
189     iv_local[0 + 2] = (engine_boots >>  8) & 0xFF;
190     iv_local[0 + 3] = (engine_boots >>  0) & 0xFF;
191     iv_local[4 + 0] = (engine_time  >> 24) & 0xFF;
192     iv_local[4 + 1] = (engine_time  >> 16) & 0xFF;
193     iv_local[4 + 2] = (engine_time  >>  8) & 0xFF;
194     iv_local[4 + 3] = (engine_time  >>  0) & 0xFF;
195     SMEMCPY(iv_local + 8, priv_param, 8);
196     if(mbedtls_cipher_set_iv(&ctx, iv_local, LWIP_ARRAYSIZE(iv_local)) != 0) {
197       goto error;
198     }
199
200     for (i = 0; i < length; i++) {
201       u8_t in_byte;
202       u8_t out_byte;
203       size_t out_len = sizeof(out_byte);
204       
205       snmp_pbuf_stream_read(&read_stream, &in_byte);
206       if(mbedtls_cipher_update(&ctx, &in_byte, sizeof(in_byte), &out_byte, &out_len) != 0) {
207         goto error;
208       }
209       snmp_pbuf_stream_write(&write_stream, out_byte);
210     }
211   } else {
212     return ERR_ARG;
213   }
214
215   mbedtls_cipher_free(&ctx);
216   return ERR_OK;
217
218 error:
219   mbedtls_cipher_free(&ctx);
220   return ERR_OK;
221 }
222
223 #endif /* LWIP_SNMP_V3_CRYPTO */
224
225 /* A.2.1. Password to Key Sample Code for MD5 */
226 void 
227 snmpv3_password_to_key_md5(
228     const u8_t *password,    /* IN */
229     u8_t        passwordlen, /* IN */
230     const u8_t *engineID,    /* IN  - pointer to snmpEngineID  */
231     u8_t        engineLength,/* IN  - length of snmpEngineID */
232     u8_t       *key)         /* OUT - pointer to caller 16-octet buffer */
233 {
234   mbedtls_md5_context MD;
235   u8_t *cp, password_buf[64];
236   u32_t password_index = 0;
237   u8_t i;
238   u32_t count = 0;
239
240   mbedtls_md5_init(&MD); /* initialize MD5 */
241   mbedtls_md5_starts(&MD);
242
243   /**********************************************/
244   /* Use while loop until we've done 1 Megabyte */
245   /**********************************************/
246   while (count < 1048576) {
247     cp = password_buf;
248     for (i = 0; i < 64; i++) {
249       /*************************************************/
250       /* Take the next octet of the password, wrapping */
251       /* to the beginning of the password as necessary.*/
252       /*************************************************/
253       *cp++ = password[password_index++ % passwordlen];
254     }
255     mbedtls_md5_update(&MD, password_buf, 64);
256     count += 64;
257   }
258   mbedtls_md5_finish(&MD, key); /* tell MD5 we're done */
259
260   /*****************************************************/
261   /* Now localize the key with the engineID and pass   */
262   /* through MD5 to produce final key                  */
263   /* May want to ensure that engineLength <= 32,       */
264   /* otherwise need to use a buffer larger than 64     */
265   /*****************************************************/
266   SMEMCPY(password_buf, key, 16);
267   MEMCPY(password_buf + 16, engineID, engineLength);
268   SMEMCPY(password_buf + 16 + engineLength, key, 16);
269
270   mbedtls_md5_starts(&MD);
271   mbedtls_md5_update(&MD, password_buf, 32 + engineLength);
272   mbedtls_md5_finish(&MD, key);
273
274   mbedtls_md5_free(&MD);
275   return;
276 }
277
278 /* A.2.2. Password to Key Sample Code for SHA */
279 void 
280 snmpv3_password_to_key_sha(
281     const u8_t *password,    /* IN */
282     u8_t        passwordlen, /* IN */
283     const u8_t *engineID,    /* IN  - pointer to snmpEngineID  */
284     u8_t        engineLength,/* IN  - length of snmpEngineID */
285     u8_t       *key)         /* OUT - pointer to caller 20-octet buffer */
286 {
287   mbedtls_sha1_context SH;
288   u8_t *cp, password_buf[72];
289   u32_t password_index = 0;
290   u8_t i;
291   u32_t count = 0;
292
293   mbedtls_sha1_init(&SH); /* initialize SHA */
294   mbedtls_sha1_starts(&SH);
295
296   /**********************************************/
297   /* Use while loop until we've done 1 Megabyte */
298   /**********************************************/
299   while (count < 1048576) {
300     cp = password_buf;
301     for (i = 0; i < 64; i++) {
302       /*************************************************/
303       /* Take the next octet of the password, wrapping */
304       /* to the beginning of the password as necessary.*/
305       /*************************************************/
306       *cp++ = password[password_index++ % passwordlen];
307     }
308     mbedtls_sha1_update(&SH, password_buf, 64);
309     count += 64;
310   }
311   mbedtls_sha1_finish(&SH, key); /* tell SHA we're done */
312
313   /*****************************************************/
314   /* Now localize the key with the engineID and pass   */
315   /* through SHA to produce final key                  */
316   /* May want to ensure that engineLength <= 32,       */
317   /* otherwise need to use a buffer larger than 72     */
318   /*****************************************************/
319   SMEMCPY(password_buf, key, 20);
320   MEMCPY(password_buf + 20, engineID, engineLength);
321   SMEMCPY(password_buf + 20 + engineLength, key, 20);
322
323   mbedtls_sha1_starts(&SH);
324   mbedtls_sha1_update(&SH, password_buf, 40 + engineLength);
325   mbedtls_sha1_finish(&SH, key);
326   
327   mbedtls_sha1_free(&SH);
328   return;
329 }
330
331 #endif /* LWIP_SNMP && LWIP_SNMP_V3 && LWIP_SNMP_V3_MBEDTLS */