1 /*-
2 * Copyright (c) 2010 The FreeBSD Foundation
3 *
4 * This software was developed by Shteryana Sotirova Shopova under
5 * sponsorship from the FreeBSD Foundation.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 * $FreeBSD$
29 */
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <stddef.h>
35 #include <stdarg.h>
36 #ifdef HAVE_STDINT_H
37 #include <stdint.h>
38 #elif defined(HAVE_INTTYPES_H)
39 #include <inttypes.h>
40 #endif
41 #include <string.h>
42 #include <ctype.h>
43 #include <errno.h>
44 #include <netinet/in.h>
45
46 #ifdef HAVE_LIBCRYPTO
47 #include <openssl/evp.h>
48 #endif
49
50 #include "asn1.h"
51 #include "snmp.h"
52 #include "snmppriv.h"
53
54 #define SNMP_PRIV_AES_IV_SIZ 16
55 #define SNMP_EXTENDED_KEY_SIZ 64
56 #define SNMP_AUTH_KEY_LOOPCNT 1048576
57 #define SNMP_AUTH_BUF_SIZE 72
58
59 #ifdef HAVE_LIBCRYPTO
60
61 static const uint8_t ipad = 0x36;
62 static const uint8_t opad = 0x5c;
63
64 static int32_t
snmp_digest_init(const struct snmp_user * user,EVP_MD_CTX * ctx,const EVP_MD ** dtype,uint32_t * keylen)65 snmp_digest_init(const struct snmp_user *user, EVP_MD_CTX *ctx,
66 const EVP_MD **dtype, uint32_t *keylen)
67 {
68 if (user->auth_proto == SNMP_AUTH_HMAC_MD5) {
69 *dtype = EVP_md5();
70 *keylen = SNMP_AUTH_HMACMD5_KEY_SIZ;
71 } else if (user->auth_proto == SNMP_AUTH_HMAC_SHA) {
72 *dtype = EVP_sha1();
73 *keylen = SNMP_AUTH_HMACSHA_KEY_SIZ;
74 } else if (user->auth_proto == SNMP_AUTH_NOAUTH)
75 return (0);
76 else {
77 snmp_error("unknown authentication option - %d",
78 user->auth_proto);
79 return (-1);
80 }
81
82 if (EVP_DigestInit(ctx, *dtype) != 1)
83 return (-1);
84
85 return (1);
86 }
87
88 enum snmp_code
snmp_pdu_calc_digest(const struct snmp_pdu * pdu,uint8_t * digest)89 snmp_pdu_calc_digest(const struct snmp_pdu *pdu, uint8_t *digest)
90 {
91 uint8_t md[EVP_MAX_MD_SIZE], extkey[SNMP_EXTENDED_KEY_SIZ];
92 uint8_t key1[SNMP_EXTENDED_KEY_SIZ], key2[SNMP_EXTENDED_KEY_SIZ];
93 uint32_t i, keylen, olen;
94 int32_t err;
95 const EVP_MD *dtype;
96 EVP_MD_CTX *ctx;
97
98 ctx = EVP_MD_CTX_new();
99 if (ctx == NULL)
100 return (SNMP_CODE_FAILED);
101 err = snmp_digest_init(&pdu->user, ctx, &dtype, &keylen);
102 if (err <= 0)
103 EVP_MD_CTX_free(ctx);
104 if (err < 0)
105 return (SNMP_CODE_BADDIGEST);
106 else if (err == 0)
107 return (SNMP_CODE_OK);
108
109 memset(pdu->digest_ptr, 0, sizeof(pdu->msg_digest));
110 memcpy(extkey, pdu->user.auth_key, keylen);
111 memset(extkey + keylen, 0, sizeof(extkey) - keylen);
112
113 for (i = 0; i < SNMP_EXTENDED_KEY_SIZ; i++) {
114 key1[i] = extkey[i] ^ ipad;
115 key2[i] = extkey[i] ^ opad;
116 }
117
118 if (EVP_DigestUpdate(ctx, key1, SNMP_EXTENDED_KEY_SIZ) != 1 ||
119 EVP_DigestUpdate(ctx, pdu->outer_ptr, pdu->outer_len) != 1 ||
120 EVP_DigestFinal(ctx, md, &olen) != 1)
121 goto failed;
122
123 if (EVP_DigestInit(ctx, dtype) != 1 ||
124 EVP_DigestUpdate(ctx, key2, SNMP_EXTENDED_KEY_SIZ) != 1 ||
125 EVP_DigestUpdate(ctx, md, olen) != 1 ||
126 EVP_DigestFinal(ctx, md, &olen) != 1)
127 goto failed;
128
129 if (olen < SNMP_USM_AUTH_SIZE) {
130 snmp_error("bad digest size - %d", olen);
131 EVP_MD_CTX_free(ctx);
132 return (SNMP_CODE_BADDIGEST);
133 }
134
135 memcpy(digest, md, SNMP_USM_AUTH_SIZE);
136 EVP_MD_CTX_free(ctx);
137 return (SNMP_CODE_OK);
138
139 failed:
140 EVP_MD_CTX_free(ctx);
141 return (SNMP_CODE_BADDIGEST);
142 }
143
144 static int32_t
snmp_pdu_cipher_init(const struct snmp_pdu * pdu,int32_t len,const EVP_CIPHER ** ctype,uint8_t * piv)145 snmp_pdu_cipher_init(const struct snmp_pdu *pdu, int32_t len,
146 const EVP_CIPHER **ctype, uint8_t *piv)
147 {
148 int i;
149 uint32_t netint;
150
151 if (pdu->user.priv_proto == SNMP_PRIV_DES) {
152 if (len % 8 != 0)
153 return (-1);
154 *ctype = EVP_des_cbc();
155 memcpy(piv, pdu->msg_salt, sizeof(pdu->msg_salt));
156 for (i = 0; i < 8; i++)
157 piv[i] = piv[i] ^ pdu->user.priv_key[8 + i];
158 } else if (pdu->user.priv_proto == SNMP_PRIV_AES) {
159 *ctype = EVP_aes_128_cfb128();
160 netint = htonl(pdu->engine.engine_boots);
161 memcpy(piv, &netint, sizeof(netint));
162 piv += sizeof(netint);
163 netint = htonl(pdu->engine.engine_time);
164 memcpy(piv, &netint, sizeof(netint));
165 piv += sizeof(netint);
166 memcpy(piv, pdu->msg_salt, sizeof(pdu->msg_salt));
167 } else if (pdu->user.priv_proto == SNMP_PRIV_NOPRIV)
168 return (0);
169 else {
170 snmp_error("unknown privacy option - %d", pdu->user.priv_proto);
171 return (-1);
172 }
173
174 return (1);
175 }
176
177 enum snmp_code
snmp_pdu_encrypt(const struct snmp_pdu * pdu)178 snmp_pdu_encrypt(const struct snmp_pdu *pdu)
179 {
180 int32_t err, olen;
181 uint8_t iv[SNMP_PRIV_AES_IV_SIZ];
182 const EVP_CIPHER *ctype;
183 EVP_CIPHER_CTX *ctx;
184
185 err = snmp_pdu_cipher_init(pdu, pdu->scoped_len, &ctype, iv);
186 if (err < 0)
187 return (SNMP_CODE_EDECRYPT);
188 else if (err == 0)
189 return (SNMP_CODE_OK);
190
191 ctx = EVP_CIPHER_CTX_new();
192 if (ctx == NULL)
193 return (SNMP_CODE_FAILED);
194 if (EVP_EncryptInit(ctx, ctype, pdu->user.priv_key, iv) != 1)
195 goto failed;
196
197 if (EVP_EncryptUpdate(ctx, pdu->scoped_ptr, &olen, pdu->scoped_ptr,
198 pdu->scoped_len) != 1 ||
199 EVP_EncryptFinal(ctx, pdu->scoped_ptr + olen, &olen) != 1)
200 goto failed;
201
202 EVP_CIPHER_CTX_free(ctx);
203 return (SNMP_CODE_OK);
204
205 failed:
206 EVP_CIPHER_CTX_free(ctx);
207 return (SNMP_CODE_FAILED);
208 }
209
210 enum snmp_code
snmp_pdu_decrypt(const struct snmp_pdu * pdu)211 snmp_pdu_decrypt(const struct snmp_pdu *pdu)
212 {
213 int32_t err, olen;
214 uint8_t iv[SNMP_PRIV_AES_IV_SIZ];
215 const EVP_CIPHER *ctype;
216 EVP_CIPHER_CTX *ctx;
217
218 err = snmp_pdu_cipher_init(pdu, pdu->scoped_len, &ctype, iv);
219 if (err < 0)
220 return (SNMP_CODE_EDECRYPT);
221 else if (err == 0)
222 return (SNMP_CODE_OK);
223
224 ctx = EVP_CIPHER_CTX_new();
225 if (ctx == NULL)
226 return (SNMP_CODE_FAILED);
227 if (EVP_DecryptInit(ctx, ctype, pdu->user.priv_key, iv) != 1 ||
228 EVP_CIPHER_CTX_set_padding(ctx, 0) != 1)
229 goto failed;
230
231 if (EVP_DecryptUpdate(ctx, pdu->scoped_ptr, &olen, pdu->scoped_ptr,
232 pdu->scoped_len) != 1 ||
233 EVP_DecryptFinal(ctx, pdu->scoped_ptr + olen, &olen) != 1)
234 goto failed;
235
236 EVP_CIPHER_CTX_free(ctx);
237 return (SNMP_CODE_OK);
238
239 failed:
240 EVP_CIPHER_CTX_free(ctx);
241 return (SNMP_CODE_EDECRYPT);
242 }
243
244 /* [RFC 3414] - A.2. Password to Key Algorithm */
245 enum snmp_code
snmp_passwd_to_keys(struct snmp_user * user,char * passwd)246 snmp_passwd_to_keys(struct snmp_user *user, char *passwd)
247 {
248 int err, loop, i, pwdlen;
249 uint32_t keylen, olen;
250 const EVP_MD *dtype;
251 EVP_MD_CTX *ctx;
252 uint8_t authbuf[SNMP_AUTH_BUF_SIZE];
253
254 if (passwd == NULL || user == NULL)
255 return (SNMP_CODE_FAILED);
256
257 ctx = EVP_MD_CTX_new();
258 if (ctx == NULL)
259 return (SNMP_CODE_FAILED);
260
261 err = snmp_digest_init(user, ctx, &dtype, &keylen);
262 if (err <= 0)
263 EVP_MD_CTX_free(ctx);
264 if (err < 0)
265 return (SNMP_CODE_BADDIGEST);
266 else if (err == 0)
267 return (SNMP_CODE_OK);
268
269 memset(user->auth_key, 0, sizeof(user->auth_key));
270 pwdlen = strlen(passwd);
271
272 for (loop = 0; loop < SNMP_AUTH_KEY_LOOPCNT; loop += i) {
273 for (i = 0; i < SNMP_EXTENDED_KEY_SIZ; i++)
274 authbuf[i] = passwd[(loop + i) % pwdlen];
275 if (EVP_DigestUpdate(ctx, authbuf, SNMP_EXTENDED_KEY_SIZ) != 1)
276 goto failed;
277 }
278
279 if (EVP_DigestFinal(ctx, user->auth_key, &olen) != 1)
280 goto failed;
281
282 EVP_MD_CTX_free(ctx);
283 return (SNMP_CODE_OK);
284
285 failed:
286 EVP_MD_CTX_free(ctx);
287 return (SNMP_CODE_BADDIGEST);
288 }
289
290 /* [RFC 3414] - 2.6. Key Localization Algorithm */
291 enum snmp_code
snmp_get_local_keys(struct snmp_user * user,uint8_t * eid,uint32_t elen)292 snmp_get_local_keys(struct snmp_user *user, uint8_t *eid, uint32_t elen)
293 {
294 int err;
295 uint32_t keylen, olen;
296 const EVP_MD *dtype;
297 EVP_MD_CTX *ctx;
298 uint8_t authbuf[SNMP_AUTH_BUF_SIZE];
299
300 if (user == NULL || eid == NULL || elen > SNMP_ENGINE_ID_SIZ)
301 return (SNMP_CODE_FAILED);
302
303 ctx = EVP_MD_CTX_new();
304 if (ctx == NULL)
305 return (SNMP_CODE_FAILED);
306
307 memset(user->priv_key, 0, sizeof(user->priv_key));
308 memset(authbuf, 0, sizeof(authbuf));
309
310 err = snmp_digest_init(user, ctx, &dtype, &keylen);
311 if (err <= 0)
312 EVP_MD_CTX_free(ctx);
313 if (err < 0)
314 return (SNMP_CODE_BADDIGEST);
315 else if (err == 0)
316 return (SNMP_CODE_OK);
317
318 memcpy(authbuf, user->auth_key, keylen);
319 memcpy(authbuf + keylen, eid, elen);
320 memcpy(authbuf + keylen + elen, user->auth_key, keylen);
321
322 if (EVP_DigestUpdate(ctx, authbuf, 2 * keylen + elen) != 1 ||
323 EVP_DigestFinal(ctx, user->auth_key, &olen) != 1) {
324 EVP_MD_CTX_free(ctx);
325 return (SNMP_CODE_BADDIGEST);
326 }
327 EVP_MD_CTX_free(ctx);
328
329 if (user->priv_proto != SNMP_PRIV_NOPRIV)
330 memcpy(user->priv_key, user->auth_key, sizeof(user->priv_key));
331
332 return (SNMP_CODE_OK);
333 }
334
335 enum snmp_code
snmp_calc_keychange(struct snmp_user * user,uint8_t * keychange)336 snmp_calc_keychange(struct snmp_user *user, uint8_t *keychange)
337 {
338 int32_t err, rvalue[SNMP_AUTH_HMACSHA_KEY_SIZ / 4];
339 uint32_t i, keylen, olen;
340 const EVP_MD *dtype;
341 EVP_MD_CTX *ctx;
342
343 ctx = EVP_MD_CTX_new();
344 if (ctx == NULL)
345 return (SNMP_CODE_FAILED);
346
347 err = snmp_digest_init(user, ctx, &dtype, &keylen);
348 if (err <= 0)
349 EVP_MD_CTX_free(ctx);
350 if (err < 0)
351 return (SNMP_CODE_BADDIGEST);
352 else if (err == 0)
353 return (SNMP_CODE_OK);
354
355 for (i = 0; i < keylen / 4; i++)
356 rvalue[i] = random();
357
358 memcpy(keychange, user->auth_key, keylen);
359 memcpy(keychange + keylen, rvalue, keylen);
360
361 if (EVP_DigestUpdate(ctx, keychange, 2 * keylen) != 1 ||
362 EVP_DigestFinal(ctx, keychange, &olen) != 1) {
363 EVP_MD_CTX_free(ctx);
364 return (SNMP_CODE_BADDIGEST);
365 }
366
367 EVP_MD_CTX_free(ctx);
368 return (SNMP_CODE_OK);
369 }
370
371 #else /* !HAVE_LIBCRYPTO */
372
373 enum snmp_code
snmp_pdu_calc_digest(const struct snmp_pdu * pdu,uint8_t * digest __unused)374 snmp_pdu_calc_digest(const struct snmp_pdu *pdu, uint8_t *digest __unused)
375 {
376 if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH)
377 return (SNMP_CODE_BADSECLEVEL);
378
379
380 return (SNMP_CODE_OK);
381 }
382
383 enum snmp_code
snmp_pdu_encrypt(const struct snmp_pdu * pdu)384 snmp_pdu_encrypt(const struct snmp_pdu *pdu)
385 {
386 if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV)
387 return (SNMP_CODE_BADSECLEVEL);
388
389 return (SNMP_CODE_OK);
390 }
391
392 enum snmp_code
snmp_pdu_decrypt(const struct snmp_pdu * pdu)393 snmp_pdu_decrypt(const struct snmp_pdu *pdu)
394 {
395 if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV)
396 return (SNMP_CODE_BADSECLEVEL);
397
398 return (SNMP_CODE_OK);
399 }
400
401 enum snmp_code
snmp_passwd_to_keys(struct snmp_user * user,char * passwd __unused)402 snmp_passwd_to_keys(struct snmp_user *user, char *passwd __unused)
403 {
404 if (user->auth_proto == SNMP_AUTH_NOAUTH &&
405 user->priv_proto == SNMP_PRIV_NOPRIV)
406 return (SNMP_CODE_OK);
407
408 errno = EPROTONOSUPPORT;
409
410 return (SNMP_CODE_FAILED);
411 }
412
413 enum snmp_code
snmp_get_local_keys(struct snmp_user * user,uint8_t * eid __unused,uint32_t elen __unused)414 snmp_get_local_keys(struct snmp_user *user, uint8_t *eid __unused,
415 uint32_t elen __unused)
416 {
417 if (user->auth_proto == SNMP_AUTH_NOAUTH &&
418 user->priv_proto == SNMP_PRIV_NOPRIV)
419 return (SNMP_CODE_OK);
420
421 errno = EPROTONOSUPPORT;
422
423 return (SNMP_CODE_FAILED);
424 }
425
426 enum snmp_code
snmp_calc_keychange(struct snmp_user * user __unused,uint8_t * keychange __unused)427 snmp_calc_keychange(struct snmp_user *user __unused,
428 uint8_t *keychange __unused)
429 {
430 errno = EPROTONOSUPPORT;
431 return (SNMP_CODE_FAILED);
432 }
433
434 #endif /* HAVE_LIBCRYPTO */
435