ReactOS 0.4.16-dev-814-g656a5dc
snmpv3_mbedtls.c
Go to the documentation of this file.
1
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
52snmpv3_auth(struct snmp_pbuf_stream *stream, u16_t length,
53 const u8_t *key, snmpv3_auth_algo_t algo, u8_t *hmac_out)
54{
55 u32_t i;
56 u8_t key_len;
57 const mbedtls_md_info_t *md_info;
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) {
64 key_len = SNMP_V3_MD5_LEN;
65 } else if (algo == SNMP_V3_AUTH_ALGO_SHA) {
67 key_len = SNMP_V3_SHA_LEN;
68 } else {
69 return ERR_ARG;
70 }
71
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
98 return ERR_OK;
99
100free_md:
102 return ERR_ARG;
103}
104
105#if LWIP_SNMP_V3_CRYPTO
106
107err_t
108snmpv3_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, snmpv3_priv_algo_t algo, snmpv3_priv_mode_t mode)
111{
112 size_t i;
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);
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
133 if (mbedtls_cipher_setup(&ctx, cipher_info) != 0) {
134 return ERR_ARG;
135 }
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 if (snmp_pbuf_stream_read(&read_stream, &in_bytes[j]) != ERR_OK) {
158 goto error;
159 }
160 }
161
162 if (mbedtls_cipher_update(&ctx, in_bytes, LWIP_ARRAYSIZE(in_bytes), out_bytes, &out_len) != 0) {
163 goto error;
164 }
165
166 if (snmp_pbuf_stream_writebuf(&write_stream, out_bytes, (u16_t)out_len) != ERR_OK) {
167 goto error;
168 }
169 }
170
171 out_len = LWIP_ARRAYSIZE(out_bytes);
172 if (mbedtls_cipher_finish(&ctx, out_bytes, &out_len) != 0) {
173 goto error;
174 }
175
176 if (snmp_pbuf_stream_writebuf(&write_stream, out_bytes, (u16_t)out_len) != ERR_OK) {
177 goto error;
178 }
179 } else if (algo == SNMP_V3_PRIV_ALGO_AES) {
180 u8_t iv_local[16];
181
183 if (mbedtls_cipher_setup(&ctx, cipher_info) != 0) {
184 return ERR_ARG;
185 }
186 if (mbedtls_cipher_setkey(&ctx, key, 16 * 8, (mode == SNMP_V3_PRIV_MODE_ENCRYPT) ? MBEDTLS_ENCRYPT : MBEDTLS_DECRYPT) != 0) {
187 goto error;
188 }
189
190 /*
191 * IV is the big endian concatenation of boots,
192 * uptime and priv param - see RFC3826.
193 */
194 iv_local[0 + 0] = (engine_boots >> 24) & 0xFF;
195 iv_local[0 + 1] = (engine_boots >> 16) & 0xFF;
196 iv_local[0 + 2] = (engine_boots >> 8) & 0xFF;
197 iv_local[0 + 3] = (engine_boots >> 0) & 0xFF;
198 iv_local[4 + 0] = (engine_time >> 24) & 0xFF;
199 iv_local[4 + 1] = (engine_time >> 16) & 0xFF;
200 iv_local[4 + 2] = (engine_time >> 8) & 0xFF;
201 iv_local[4 + 3] = (engine_time >> 0) & 0xFF;
202 SMEMCPY(iv_local + 8, priv_param, 8);
203 if (mbedtls_cipher_set_iv(&ctx, iv_local, LWIP_ARRAYSIZE(iv_local)) != 0) {
204 goto error;
205 }
206
207 for (i = 0; i < length; i++) {
208 u8_t in_byte;
209 u8_t out_byte;
210 size_t out_len = sizeof(out_byte);
211
212 if (snmp_pbuf_stream_read(&read_stream, &in_byte) != ERR_OK) {
213 goto error;
214 }
215 if (mbedtls_cipher_update(&ctx, &in_byte, sizeof(in_byte), &out_byte, &out_len) != 0) {
216 goto error;
217 }
218 if (snmp_pbuf_stream_write(&write_stream, out_byte) != ERR_OK) {
219 goto error;
220 }
221 }
222 } else {
223 return ERR_ARG;
224 }
225
227 return ERR_OK;
228
229error:
231 return ERR_OK;
232}
233
234#endif /* LWIP_SNMP_V3_CRYPTO */
235
236/* A.2.1. Password to Key Sample Code for MD5 */
237void
238snmpv3_password_to_key_md5(
239 const u8_t *password, /* IN */
240 size_t passwordlen, /* IN */
241 const u8_t *engineID, /* IN - pointer to snmpEngineID */
242 u8_t engineLength,/* IN - length of snmpEngineID */
243 u8_t *key) /* OUT - pointer to caller 16-octet buffer */
244{
246 u8_t *cp, password_buf[64];
247 u32_t password_index = 0;
248 u8_t i;
249 u32_t count = 0;
250
251 mbedtls_md5_init(&MD); /* initialize MD5 */
253
254 /**********************************************/
255 /* Use while loop until we've done 1 Megabyte */
256 /**********************************************/
257 while (count < 1048576) {
258 cp = password_buf;
259 for (i = 0; i < 64; i++) {
260 /*************************************************/
261 /* Take the next octet of the password, wrapping */
262 /* to the beginning of the password as necessary.*/
263 /*************************************************/
264 *cp++ = password[password_index++ % passwordlen];
265 }
266 mbedtls_md5_update(&MD, password_buf, 64);
267 count += 64;
268 }
269 mbedtls_md5_finish(&MD, key); /* tell MD5 we're done */
270
271 /*****************************************************/
272 /* Now localize the key with the engineID and pass */
273 /* through MD5 to produce final key */
274 /* May want to ensure that engineLength <= 32, */
275 /* otherwise need to use a buffer larger than 64 */
276 /*****************************************************/
277 SMEMCPY(password_buf, key, 16);
278 MEMCPY(password_buf + 16, engineID, engineLength);
279 SMEMCPY(password_buf + 16 + engineLength, key, 16);
280
282 mbedtls_md5_update(&MD, password_buf, 32 + engineLength);
284
285 mbedtls_md5_free(&MD);
286 return;
287}
288
289/* A.2.2. Password to Key Sample Code for SHA */
290void
291snmpv3_password_to_key_sha(
292 const u8_t *password, /* IN */
293 size_t passwordlen, /* IN */
294 const u8_t *engineID, /* IN - pointer to snmpEngineID */
295 u8_t engineLength,/* IN - length of snmpEngineID */
296 u8_t *key) /* OUT - pointer to caller 20-octet buffer */
297{
299 u8_t *cp, password_buf[72];
300 u32_t password_index = 0;
301 u8_t i;
302 u32_t count = 0;
303
304 mbedtls_sha1_init(&SH); /* initialize SHA */
306
307 /**********************************************/
308 /* Use while loop until we've done 1 Megabyte */
309 /**********************************************/
310 while (count < 1048576) {
311 cp = password_buf;
312 for (i = 0; i < 64; i++) {
313 /*************************************************/
314 /* Take the next octet of the password, wrapping */
315 /* to the beginning of the password as necessary.*/
316 /*************************************************/
317 *cp++ = password[password_index++ % passwordlen];
318 }
319 mbedtls_sha1_update(&SH, password_buf, 64);
320 count += 64;
321 }
322 mbedtls_sha1_finish(&SH, key); /* tell SHA we're done */
323
324 /*****************************************************/
325 /* Now localize the key with the engineID and pass */
326 /* through SHA to produce final key */
327 /* May want to ensure that engineLength <= 32, */
328 /* otherwise need to use a buffer larger than 72 */
329 /*****************************************************/
330 SMEMCPY(password_buf, key, 20);
331 MEMCPY(password_buf + 20, engineID, engineLength);
332 SMEMCPY(password_buf + 20 + engineLength, key, 20);
333
335 mbedtls_sha1_update(&SH, password_buf, 40 + engineLength);
337
339 return;
340}
341
342#endif /* LWIP_SNMP && LWIP_SNMP_V3 && LWIP_SNMP_V3_MBEDTLS */
HRESULT read_stream(BSCallback *, IStream *, void *, DWORD, DWORD *) DECLSPEC_HIDDEN
Definition: navigate.c:602
This file contains an abstraction interface for use with the cipher primitives provided by the librar...
int mbedtls_cipher_setup(mbedtls_cipher_context_t *ctx, const mbedtls_cipher_info_t *cipher_info)
This function initializes and fills the cipher-context structure with the appropriate values....
@ MBEDTLS_CIPHER_AES_128_CFB128
Definition: cipher.h:138
@ MBEDTLS_CIPHER_DES_CBC
Definition: cipher.h:163
int mbedtls_cipher_setkey(mbedtls_cipher_context_t *ctx, const unsigned char *key, int key_bitlen, const mbedtls_operation_t operation)
This function sets the key to use with the given context.
int mbedtls_cipher_set_iv(mbedtls_cipher_context_t *ctx, const unsigned char *iv, size_t iv_len)
This function sets the initialization vector (IV) or nonce.
@ MBEDTLS_PADDING_NONE
Definition: cipher.h:227
int mbedtls_cipher_finish(mbedtls_cipher_context_t *ctx, unsigned char *output, size_t *olen)
The generic cipher finalization function. If data still needs to be flushed from an incomplete block,...
void mbedtls_cipher_init(mbedtls_cipher_context_t *ctx)
This function initializes a cipher_context as NONE.
void mbedtls_cipher_free(mbedtls_cipher_context_t *ctx)
This function frees and clears the cipher-specific context of ctx. Freeing ctx itself remains the res...
int mbedtls_cipher_update(mbedtls_cipher_context_t *ctx, const unsigned char *input, size_t ilen, unsigned char *output, size_t *olen)
The generic cipher update function. It encrypts or decrypts using the given cipher context....
@ MBEDTLS_DECRYPT
Definition: cipher.h:233
@ MBEDTLS_ENCRYPT
Definition: cipher.h:234
int mbedtls_cipher_set_padding_mode(mbedtls_cipher_context_t *ctx, mbedtls_cipher_padding_t mode)
This function sets the padding mode, for cipher modes that use padding.
#define LWIP_ARRAYSIZE(x)
Definition: def.h:69
#define byte(x, n)
Definition: tomcrypt.h:118
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLenum mode
Definition: glext.h:6217
GLuint GLsizei GLsizei * length
Definition: glext.h:6040
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
uint32_t u32_t
Definition: arch.h:129
uint8_t u8_t
Definition: arch.h:125
uint16_t u16_t
Definition: arch.h:127
s8_t err_t
Definition: err.h:96
@ ERR_OK
Definition: err.h:55
@ ERR_ARG
Definition: err.h:88
#define SMEMCPY(dst, src, len)
Definition: opt.h:145
#define MEMCPY(DST, SRC, BYTES)
Definition: macros.h:231
POINT cp
Definition: magnifier.c:59
This file contains the generic message-digest wrapper.
int mbedtls_md_setup(mbedtls_md_context_t *ctx, const mbedtls_md_info_t *md_info, int hmac)
This function selects the message digest algorithm to use, and allocates internal structures.
@ MBEDTLS_MD_MD5
Definition: md.h:87
@ MBEDTLS_MD_SHA1
Definition: md.h:88
int mbedtls_md_hmac_finish(mbedtls_md_context_t *ctx, unsigned char *output)
This function finishes the HMAC operation, and writes the result to the output buffer.
int mbedtls_md_hmac_update(mbedtls_md_context_t *ctx, const unsigned char *input, size_t ilen)
This function feeds an input buffer into an ongoing HMAC computation.
int mbedtls_md_hmac_starts(mbedtls_md_context_t *ctx, const unsigned char *key, size_t keylen)
This function sets the HMAC key and prepares to authenticate a new message.
void mbedtls_md_init(mbedtls_md_context_t *ctx)
This function initializes a message-digest context without binding it to a particular message-digest ...
void mbedtls_md_free(mbedtls_md_context_t *ctx)
This function clears the internal structure of ctx and frees any embedded internal structure,...
#define error(str)
Definition: mkdosfs.c:1605
static WCHAR password[]
Definition: url.c:33
#define mbedtls_md_info_from_type
#define mbedtls_cipher_info_from_type
MD5 message digest algorithm (hash function)
void mbedtls_md5_free(mbedtls_md5_context *ctx)
Clear MD5 context.
MBEDTLS_DEPRECATED void mbedtls_md5_starts(mbedtls_md5_context *ctx)
MD5 context setup.
MBEDTLS_DEPRECATED void mbedtls_md5_finish(mbedtls_md5_context *ctx, unsigned char output[16])
MD5 final digest.
void mbedtls_md5_init(mbedtls_md5_context *ctx)
Initialize MD5 context.
MBEDTLS_DEPRECATED void mbedtls_md5_update(mbedtls_md5_context *ctx, const unsigned char *input, size_t ilen)
MD5 process buffer.
This file contains SHA-1 definitions and functions.
MBEDTLS_DEPRECATED void mbedtls_sha1_finish(mbedtls_sha1_context *ctx, unsigned char output[20])
This function finishes the SHA-1 operation, and writes the result to the output buffer.
void mbedtls_sha1_free(mbedtls_sha1_context *ctx)
This function clears a SHA-1 context.
MBEDTLS_DEPRECATED void mbedtls_sha1_starts(mbedtls_sha1_context *ctx)
This function starts a SHA-1 checksum calculation.
MBEDTLS_DEPRECATED void mbedtls_sha1_update(mbedtls_sha1_context *ctx, const unsigned char *input, size_t ilen)
This function feeds an input buffer into an ongoing SHA-1 checksum calculation.
void mbedtls_sha1_init(mbedtls_sha1_context *ctx)
This function initializes a SHA-1 context.
static HRESULT write_stream(IStream *dst, IStream *src)
Definition: streams.c:562
Definition: copy.c:22
MD5 context structure.
Definition: md5.h:85
The SHA-1 context structure.
Definition: sha1.h:89
Definition: parse.h:23