Bug Summary

File:src/usr.sbin/snmpd/usm.c
Warning:line 250, column 3
Value stored to 'auth' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name usm.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/snmpd/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.sbin/snmpd -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/snmpd/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/snmpd/usm.c
1/* $OpenBSD: usm.c,v 1.24 2022/01/05 17:01:06 tb Exp $ */
2
3/*
4 * Copyright (c) 2012 GeNUA mbH
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#include <sys/queue.h>
20#include <sys/types.h>
21#include <sys/stat.h>
22#include <sys/socket.h>
23#include <sys/un.h>
24#include <sys/tree.h>
25
26#include <net/if.h>
27
28#include <errno(*__errno()).h>
29#include <event.h>
30#include <fcntl.h>
31#include <stdlib.h>
32#include <string.h>
33#include <unistd.h>
34#include <signal.h>
35#ifdef DEBUG
36#include <assert.h>
37#endif
38
39#include <openssl/evp.h>
40#include <openssl/hmac.h>
41
42#include "snmpd.h"
43#include "mib.h"
44
45SLIST_HEAD(, usmuser)struct { struct usmuser *slh_first; } usmuserlist;
46
47const EVP_MD *usm_get_md(enum usmauth);
48size_t usm_get_digestlen(enum usmauth);
49const EVP_CIPHER *usm_get_cipher(enum usmpriv);
50int usm_valid_digestlen(size_t digestlen);
51void usm_cb_digest(void *, size_t);
52int usm_valid_digest(struct snmp_message *, off_t, char *,
53 size_t);
54struct ber_element *usm_decrypt(struct snmp_message *,
55 struct ber_element *);
56ssize_t usm_crypt(struct snmp_message *, u_char *, int,
57 u_char *, int);
58char *usm_passwd2key(const EVP_MD *, char *, int *);
59
60void
61usm_generate_keys(void)
62{
63 struct usmuser *up;
64 const EVP_MD *md;
65 char *key;
66 int len;
67
68 SLIST_FOREACH(up, &usmuserlist, uu_next)for((up) = ((&usmuserlist)->slh_first); (up) != ((void
*)0); (up) = ((up)->uu_next.sle_next))
{
69 if ((md = usm_get_md(up->uu_auth)) == NULL((void *)0))
70 continue;
71
72 /* convert auth password to key */
73 len = 0;
74 key = usm_passwd2key(md, up->uu_authkey, &len);
75 free(up->uu_authkey);
76 up->uu_authkey = key;
77 up->uu_authkeylen = len;
78
79 /* optionally convert privacy password to key */
80 if (up->uu_priv != PRIV_NONE) {
81 arc4random_buf(&up->uu_salt, sizeof(up->uu_salt));
82
83 len = SNMP_CIPHER_KEYLEN16;
84 key = usm_passwd2key(md, up->uu_privkey, &len);
85 free(up->uu_privkey);
86 up->uu_privkey = key;
87 }
88 }
89 return;
90}
91
92const EVP_MD *
93usm_get_md(enum usmauth ua)
94{
95 switch (ua) {
96 case AUTH_MD5:
97 return EVP_md5();
98 case AUTH_SHA1:
99 return EVP_sha1();
100 case AUTH_SHA224:
101 return EVP_sha224();
102 case AUTH_SHA256:
103 return EVP_sha256();
104 case AUTH_SHA384:
105 return EVP_sha384();
106 case AUTH_SHA512:
107 return EVP_sha512();
108 case AUTH_NONE:
109 default:
110 return NULL((void *)0);
111 }
112}
113
114size_t
115usm_get_digestlen(enum usmauth ua)
116{
117 switch (ua) {
118 case AUTH_MD5:
119 case AUTH_SHA1:
120 return 12;
121 case AUTH_SHA224:
122 return 16;
123 case AUTH_SHA256:
124 return 24;
125 case AUTH_SHA384:
126 return 32;
127 case AUTH_SHA512:
128 return 48;
129 case AUTH_NONE:
130 default:
131 return 0;
132 }
133}
134
135const EVP_CIPHER *
136usm_get_cipher(enum usmpriv up)
137{
138 switch (up) {
139 case PRIV_DES:
140 return EVP_des_cbc();
141 case PRIV_AES:
142 return EVP_aes_128_cfb128();
143 case PRIV_NONE:
144 default:
145 return NULL((void *)0);
146 }
147}
148
149int
150usm_valid_digestlen(size_t digestlen)
151{
152 switch (digestlen) {
153 case 0:
154 case 12:
155 case 16:
156 case 24:
157 case 32:
158 case 48:
159 return 1;
160 default:
161 return 0;
162 }
163}
164
165struct usmuser *
166usm_newuser(char *name, const char **errp)
167{
168 struct usmuser *up = usm_finduser(name);
169 if (up != NULL((void *)0)) {
170 *errp = "user redefined";
171 return NULL((void *)0);
172 }
173 if ((up = calloc(1, sizeof(*up))) == NULL((void *)0))
174 fatal("usm");
175 up->uu_name = name;
176 SLIST_INSERT_HEAD(&usmuserlist, up, uu_next)do { (up)->uu_next.sle_next = (&usmuserlist)->slh_first
; (&usmuserlist)->slh_first = (up); } while (0)
;
177 return up;
178}
179
180const struct usmuser *
181usm_check_mincred(int minlevel, const char **errstr)
182{
183 struct usmuser *up;
184
185 if (minlevel == 0)
186 return NULL((void *)0);
187
188 SLIST_FOREACH(up, &usmuserlist, uu_next)for((up) = ((&usmuserlist)->slh_first); (up) != ((void
*)0); (up) = ((up)->uu_next.sle_next))
{
189 if (minlevel & SNMP_MSGFLAG_PRIV0x02 && up->uu_privkey == NULL((void *)0)) {
190 *errstr = "missing enckey";
191 return up;
192 }
193 if (minlevel & SNMP_MSGFLAG_AUTH0x01 && up->uu_authkey == NULL((void *)0)) {
194 *errstr = "missing authkey";
195 return up;
196 }
197 }
198 return NULL((void *)0);
199}
200
201struct usmuser *
202usm_finduser(char *name)
203{
204 struct usmuser *up;
205
206 SLIST_FOREACH(up, &usmuserlist, uu_next)for((up) = ((&usmuserlist)->slh_first); (up) != ((void
*)0); (up) = ((up)->uu_next.sle_next))
{
207 if (!strcmp(up->uu_name, name))
208 return up;
209 }
210 return NULL((void *)0);
211}
212
213int
214usm_checkuser(struct usmuser *up, const char **errp)
215{
216 char *auth = NULL((void *)0), *priv = NULL((void *)0);
217
218 if (up->uu_auth != AUTH_NONE && up->uu_authkey == NULL((void *)0)) {
219 *errp = "missing auth passphrase";
220 goto fail;
221 } else if (up->uu_auth == AUTH_NONE && up->uu_authkey != NULL((void *)0))
222 up->uu_auth = AUTH_DEFAULTAUTH_SHA1;
223
224 if (up->uu_priv != PRIV_NONE && up->uu_privkey == NULL((void *)0)) {
225 *errp = "missing priv passphrase";
226 goto fail;
227 } else if (up->uu_priv == PRIV_NONE && up->uu_privkey != NULL((void *)0))
228 up->uu_priv = PRIV_DEFAULTPRIV_AES;
229
230 if (up->uu_auth == AUTH_NONE && up->uu_priv != PRIV_NONE) {
231 /* Standard prohibits noAuthPriv */
232 *errp = "auth is mandatory with enc";
233 goto fail;
234 }
235
236 switch (up->uu_auth) {
237 case AUTH_NONE:
238 auth = "none";
239 break;
240 case AUTH_MD5:
241 up->uu_seclevel |= SNMP_MSGFLAG_AUTH0x01;
242 auth = "HMAC-MD5-96";
243 break;
244 case AUTH_SHA1:
245 up->uu_seclevel |= SNMP_MSGFLAG_AUTH0x01;
246 auth = "HMAC-SHA1-96";
247 break;
248 case AUTH_SHA224:
249 up->uu_seclevel |= SNMP_MSGFLAG_AUTH0x01;
250 auth = "usmHMAC128SHA224AuthProtocol";
Value stored to 'auth' is never read
251 case AUTH_SHA256:
252 up->uu_seclevel |= SNMP_MSGFLAG_AUTH0x01;
253 auth = "usmHMAC192SHA256AuthProtocol";
254 case AUTH_SHA384:
255 up->uu_seclevel |= SNMP_MSGFLAG_AUTH0x01;
256 auth = "usmHMAC256SHA384AuthProtocol";
257 case AUTH_SHA512:
258 up->uu_seclevel |= SNMP_MSGFLAG_AUTH0x01;
259 auth = "usmHMAC384SHA512AuthProtocol";
260 }
261
262 switch (up->uu_priv) {
263 case PRIV_NONE:
264 priv = "none";
265 break;
266 case PRIV_DES:
267 up->uu_seclevel |= SNMP_MSGFLAG_PRIV0x02;
268 priv = "CBC-DES";
269 break;
270 case PRIV_AES:
271 up->uu_seclevel |= SNMP_MSGFLAG_PRIV0x02;
272 priv = "CFB128-AES-128";
273 break;
274 }
275
276 log_debug("user \"%s\" auth %s enc %s", up->uu_name, auth, priv);
277 return 0;
278
279fail:
280 free(up->uu_name);
281 free(up->uu_authkey);
282 free(up->uu_privkey);
283 SLIST_REMOVE(&usmuserlist, up, usmuser, uu_next)do { if ((&usmuserlist)->slh_first == (up)) { do { ((&
usmuserlist))->slh_first = ((&usmuserlist))->slh_first
->uu_next.sle_next; } while (0); } else { struct usmuser *
curelm = (&usmuserlist)->slh_first; while (curelm->
uu_next.sle_next != (up)) curelm = curelm->uu_next.sle_next
; curelm->uu_next.sle_next = curelm->uu_next.sle_next->
uu_next.sle_next; } ; } while (0)
;
284 free(up);
285 return -1;
286}
287
288struct ber_element *
289usm_decode(struct snmp_message *msg, struct ber_element *elm, const char **errp)
290{
291 struct snmp_stats *stats = &snmpd_env->sc_stats;
292 off_t offs, offs2;
293 char *usmparams;
294 size_t len;
295 size_t enginelen, userlen, digestlen, saltlen;
296 struct ber ber;
297 struct ber_element *usm = NULL((void *)0), *next = NULL((void *)0), *decr;
298 char *engineid;
299 char *user;
300 char *digest, *salt;
301 u_long now;
302 long long engine_boots, engine_time;
303
304 bzero(&ber, sizeof(ber));
305 offs = ober_getpos(elm);
306
307 if (ober_get_nstring(elm, (void *)&usmparams, &len) < 0) {
308 *errp = "cannot decode security params";
309 msg->sm_flags &= SNMP_MSGFLAG_REPORT0x04;
310 goto done;
311 }
312
313 ober_set_readbuf(&ber, usmparams, len);
314 usm = ober_read_elements(&ber, NULL((void *)0));
315 if (usm == NULL((void *)0)) {
316 *errp = "cannot decode security params";
317 msg->sm_flags &= SNMP_MSGFLAG_REPORT0x04;
318 goto done;
319 }
320
321#ifdef DEBUG
322 fprintf(stderr(&__sF[2]), "decode USM parameters:\n");
323 smi_debug_elements(usm);
324#endif
325
326 if (ober_scanf_elements(usm, "{xiixpxx$", &engineid, &enginelen,
327 &engine_boots, &engine_time, &user, &userlen, &offs2,
328 &digest, &digestlen, &salt, &saltlen) != 0) {
329 *errp = "cannot decode USM params";
330 msg->sm_flags &= SNMP_MSGFLAG_REPORT0x04;
331 goto done;
332 }
333
334 log_debug("USM: engineid '%s', engine boots %lld, engine time %lld, "
335 "user '%s'", tohexstr(engineid, enginelen), engine_boots,
336 engine_time, user);
337
338 if (enginelen > SNMPD_MAXENGINEIDLEN32 ||
339 userlen > SNMPD_MAXUSERNAMELEN32 ||
340 !usm_valid_digestlen(digestlen) ||
341 (saltlen != (MSG_HAS_PRIV(msg)(((msg)->sm_flags & 0x02) != 0) ? SNMP_USM_SALTLEN8 : 0))) {
342 *errp = "bad field length";
343 msg->sm_flags &= SNMP_MSGFLAG_REPORT0x04;
344 goto done;
345 }
346
347 if (enginelen != snmpd_env->sc_engineid_len ||
348 memcmp(engineid, snmpd_env->sc_engineid, enginelen) != 0) {
349 *errp = "unknown engine id";
350 msg->sm_usmerr = OIDVAL_usmErrEngineId4;
351 stats->snmp_usmnosuchengine++;
352 msg->sm_flags &= SNMP_MSGFLAG_REPORT0x04;
353 goto done;
354 }
355
356 msg->sm_engine_boots = (u_int32_t)engine_boots;
357 msg->sm_engine_time = (u_int32_t)engine_time;
358
359 memcpy(msg->sm_username, user, userlen);
360 msg->sm_username[userlen] = '\0';
361 msg->sm_user = usm_finduser(msg->sm_username);
362 if (msg->sm_user == NULL((void *)0)) {
363 *errp = "no such user";
364 msg->sm_usmerr = OIDVAL_usmErrUserName3;
365 stats->snmp_usmnosuchuser++;
366 msg->sm_flags &= SNMP_MSGFLAG_REPORT0x04;
367 goto done;
368 }
369 if (MSG_SECLEVEL(msg)((msg)->sm_flags & (0x01 | 0x02)) > msg->sm_user->uu_seclevel) {
370 *errp = "unsupported security model";
371 msg->sm_usmerr = OIDVAL_usmErrSecLevel1;
372 stats->snmp_usmbadseclevel++;
373 msg->sm_flags &= SNMP_MSGFLAG_REPORT0x04;
374 goto done;
375 }
376
377 /*
378 * offs is the offset of the USM string within the serialized msg
379 * and offs2 the offset of the digest within the USM string.
380 */
381 if (!usm_valid_digest(msg, offs + offs2, digest, digestlen)) {
382 *errp = "bad msg digest";
383 msg->sm_usmerr = OIDVAL_usmErrDigest5;
384 stats->snmp_usmwrongdigest++;
385 msg->sm_flags &= SNMP_MSGFLAG_REPORT0x04;
386 goto done;
387 }
388
389 if (MSG_HAS_PRIV(msg)(((msg)->sm_flags & 0x02) != 0)) {
390 memcpy(msg->sm_salt, salt, saltlen);
391 if ((decr = usm_decrypt(msg, elm->be_next)) == NULL((void *)0)) {
392 *errp = "cannot decrypt msg";
393 msg->sm_usmerr = OIDVAL_usmErrDecrypt6;
394 stats->snmp_usmdecrypterr++;
395 msg->sm_flags &= SNMP_MSGFLAG_REPORT0x04;
396 goto done;
397 }
398 ober_replace_elements(elm, decr);
399 }
400
401 now = snmpd_engine_time();
402 if (engine_boots != snmpd_env->sc_engine_boots ||
403 engine_time < (long long)(now - SNMP_MAX_TIMEWINDOW150) ||
404 engine_time > (long long)(now + SNMP_MAX_TIMEWINDOW150)) {
405 *errp = "out of time window";
406 msg->sm_usmerr = OIDVAL_usmErrTimeWindow2;
407 stats->snmp_usmtimewindow++;
408 goto done;
409 }
410
411 next = elm->be_next;
412
413done:
414 ober_free(&ber);
415 if (usm != NULL((void *)0))
416 ober_free_elements(usm);
417 return next;
418}
419
420struct ber_element *
421usm_encode(struct snmp_message *msg, struct ber_element *e)
422{
423 struct ber ber;
424 struct ber_element *usm, *a, *res = NULL((void *)0);
425 void *ptr;
426 char digest[SNMP_USM_MAXDIGESTLEN48];
427 size_t digestlen, saltlen;
428 ssize_t len;
429
430 msg->sm_digest_offs = 0;
431 bzero(&ber, sizeof(ber));
432
433 usm = ober_add_sequence(NULL((void *)0));
434
435 if (MSG_HAS_AUTH(msg)(((msg)->sm_flags & 0x01) != 0)) {
436 /*
437 * Fill in enough zeroes and remember the position within the
438 * messages. The digest will be calculated once the message
439 * is complete.
440 */
441#ifdef DEBUG
442 assert(msg->sm_user != NULL((void *)0));
443#endif
444 bzero(digest, sizeof(digest));
445 digestlen = usm_get_digestlen(msg->sm_user->uu_auth);
446 } else
447 digestlen = 0;
448
449 if (MSG_HAS_PRIV(msg)(((msg)->sm_flags & 0x02) != 0)) {
450#ifdef DEBUG
451 assert(msg->sm_user != NULL((void *)0));
452#endif
453 ++(msg->sm_user->uu_salt);
454 memcpy(msg->sm_salt, &msg->sm_user->uu_salt,
455 sizeof(msg->sm_salt));
456 saltlen = sizeof(msg->sm_salt);
457 } else
458 saltlen = 0;
459
460 msg->sm_engine_boots = (u_int32_t)snmpd_env->sc_engine_boots;
461 msg->sm_engine_time = (u_int32_t)snmpd_engine_time();
462 if ((a = ober_printf_elements(usm, "xdds",
463 snmpd_env->sc_engineid, snmpd_env->sc_engineid_len,
464 msg->sm_engine_boots, msg->sm_engine_time,
465 msg->sm_username)) == NULL((void *)0))
466 goto done;
467
468 if ((a = ober_add_nstring(a, digest, digestlen)) == NULL((void *)0))
469 goto done;
470 if (digestlen > 0)
471 ober_set_writecallback(a, usm_cb_digest, msg);
472
473 if ((a = ober_add_nstring(a, msg->sm_salt, saltlen)) == NULL((void *)0))
474 goto done;
475
476#ifdef DEBUG
477 fprintf(stderr(&__sF[2]), "encode USM parameters:\n");
478 smi_debug_elements(usm);
479#endif
480 len = ober_write_elements(&ber, usm);
481 if (ober_get_writebuf(&ber, &ptr) > 0) {
482 res = ober_add_nstring(e, (char *)ptr, len);
483 if (digestlen > 0)
484 ober_set_writecallback(res, usm_cb_digest, msg);
485 }
486
487done:
488 ober_free(&ber);
489 ober_free_elements(usm);
490 return res;
491}
492
493void
494usm_cb_digest(void *arg, size_t offs)
495{
496 struct snmp_message *msg = arg;
497 msg->sm_digest_offs += offs;
498}
499
500struct ber_element *
501usm_encrypt(struct snmp_message *msg, struct ber_element *pdu)
502{
503 struct ber ber;
504 struct ber_element *encrpdu = NULL((void *)0);
505 void *ptr;
506 ssize_t elen, len;
507 u_char encbuf[READ_BUF_SIZE65535];
508
509 if (!MSG_HAS_PRIV(msg)(((msg)->sm_flags & 0x02) != 0))
510 return pdu;
511
512 bzero(&ber, sizeof(ber));
513
514#ifdef DEBUG
515 fprintf(stderr(&__sF[2]), "encrypted PDU:\n");
516 smi_debug_elements(pdu);
517#endif
518
519 len = ober_write_elements(&ber, pdu);
520 if (ober_get_writebuf(&ber, &ptr) > 0) {
521 elen = usm_crypt(msg, ptr, len, encbuf, 1);
522 if (elen > 0)
523 encrpdu = ober_add_nstring(NULL((void *)0), (char *)encbuf, elen);
524 }
525
526 ober_free(&ber);
527 ober_free_elements(pdu);
528 return encrpdu;
529}
530
531/*
532 * Calculate message digest and replace within message
533 */
534void
535usm_finalize_digest(struct snmp_message *msg, char *buf, ssize_t len)
536{
537 const EVP_MD *md;
538 u_char digest[EVP_MAX_MD_SIZE64];
539 size_t digestlen;
540 unsigned hlen;
541
542 if (msg->sm_resp == NULL((void *)0) ||
543 !MSG_HAS_AUTH(msg)(((msg)->sm_flags & 0x01) != 0) ||
544 msg->sm_user == NULL((void *)0) ||
545 msg->sm_digest_offs == 0 ||
546 len <= 0)
547 return;
548
549 if ((digestlen = usm_get_digestlen(msg->sm_user->uu_auth)) == 0)
550 return;
551 bzero(digest, digestlen);
552#ifdef DEBUG
553 assert(msg->sm_digest_offs + digestlen <= (size_t)len);
554 assert(!memcmp(buf + msg->sm_digest_offs, digest, digestlen));
555#endif
556
557 if ((md = usm_get_md(msg->sm_user->uu_auth)) == NULL((void *)0))
558 return;
559
560 HMAC(md, msg->sm_user->uu_authkey, (int)msg->sm_user->uu_authkeylen,
561 (u_char*)buf, (size_t)len, digest, &hlen);
562
563 memcpy(buf + msg->sm_digest_offs, digest, digestlen);
564 return;
565}
566
567void
568usm_make_report(struct snmp_message *msg)
569{
570 struct ber_oid usmstat = OID(MIB_usmStats, 0, 0){ { 1, 3, 6, 1, 6, 3, 15, 1, 1, 0, 0 } };
571
572 msg->sm_pdutype = SNMP_C_REPORT;
573 usmstat.bo_id[OIDIDX_usmStats9] = msg->sm_usmerr;
574 usmstat.bo_n = OIDIDX_usmStats9 + 2;
575 if (msg->sm_varbindresp != NULL((void *)0))
576 ober_free_elements(msg->sm_varbindresp);
577 msg->sm_varbindresp = ober_add_sequence(NULL((void *)0));
578 mps_getreq(NULL((void *)0), msg->sm_varbindresp, &usmstat, msg->sm_version);
579 return;
580}
581
582int
583usm_valid_digest(struct snmp_message *msg, off_t offs,
584 char *digest, size_t digestlen)
585{
586 const EVP_MD *md;
587 u_char exp_digest[EVP_MAX_MD_SIZE64];
588 unsigned hlen;
589
590 if (!MSG_HAS_AUTH(msg)(((msg)->sm_flags & 0x01) != 0))
591 return 1;
592
593 if (digestlen != usm_get_digestlen(msg->sm_user->uu_auth))
594 return 0;
595
596#ifdef DEBUG
597 assert(offs + digestlen <= msg->sm_datalen);
598 assert(bcmp(&msg->sm_data[offs], digest, digestlen) == 0);
599#endif
600
601 if ((md = usm_get_md(msg->sm_user->uu_auth)) == NULL((void *)0))
602 return 0;
603
604 memset(&msg->sm_data[offs], 0, digestlen);
605 HMAC(md, msg->sm_user->uu_authkey, (int)msg->sm_user->uu_authkeylen,
606 msg->sm_data, msg->sm_datalen, exp_digest, &hlen);
607 /* we don't bother to restore the original message */
608
609 if (hlen < digestlen)
610 return 0;
611
612 return memcmp(digest, exp_digest, digestlen) == 0;
613}
614
615struct ber_element *
616usm_decrypt(struct snmp_message *msg, struct ber_element *encr)
617{
618 u_char *privstr;
619 size_t privlen;
620 u_char buf[READ_BUF_SIZE65535];
621 struct ber ber;
622 struct ber_element *scoped_pdu = NULL((void *)0);
623 ssize_t scoped_pdu_len;
624
625 if (ober_get_nstring(encr, (void *)&privstr, &privlen) < 0)
626 return NULL((void *)0);
627
628 scoped_pdu_len = usm_crypt(msg, privstr, (int)privlen, buf, 0);
629 if (scoped_pdu_len < 0)
630 return NULL((void *)0);
631
632 bzero(&ber, sizeof(ber));
633 ober_set_application(&ber, smi_application);
634 ober_set_readbuf(&ber, buf, scoped_pdu_len);
635 scoped_pdu = ober_read_elements(&ber, NULL((void *)0));
636
637#ifdef DEBUG
638 if (scoped_pdu != NULL((void *)0)) {
639 fprintf(stderr(&__sF[2]), "decrypted scoped PDU:\n");
640 smi_debug_elements(scoped_pdu);
641 }
642#endif
643
644 ober_free(&ber);
645 return scoped_pdu;
646}
647
648ssize_t
649usm_crypt(struct snmp_message *msg, u_char *inbuf, int inlen, u_char *outbuf,
650 int do_encrypt)
651{
652 const EVP_CIPHER *cipher;
653 EVP_CIPHER_CTX *ctx;
654 u_char *privkey;
655 int i;
656 u_char iv[EVP_MAX_IV_LENGTH16];
657 int len, len2;
658 int rv;
659 u_int32_t ivv;
660
661 if ((cipher = usm_get_cipher(msg->sm_user->uu_priv)) == NULL((void *)0))
662 return -1;
663
664 privkey = (u_char *)msg->sm_user->uu_privkey;
665#ifdef DEBUG
666 assert(privkey != NULL((void *)0));
667#endif
668 switch (msg->sm_user->uu_priv) {
669 case PRIV_DES:
670 /* RFC3414, chap 8.1.1.1. */
671 for (i = 0; i < 8; i++)
672 iv[i] = msg->sm_salt[i] ^ privkey[SNMP_USM_SALTLEN8 + i];
673 break;
674 case PRIV_AES:
675 /* RFC3826, chap 3.1.2.1. */
676 ivv = htobe32(msg->sm_engine_boots)(__uint32_t)(__builtin_constant_p(msg->sm_engine_boots) ? (
__uint32_t)(((__uint32_t)(msg->sm_engine_boots) & 0xff
) << 24 | ((__uint32_t)(msg->sm_engine_boots) & 0xff00
) << 8 | ((__uint32_t)(msg->sm_engine_boots) & 0xff0000
) >> 8 | ((__uint32_t)(msg->sm_engine_boots) & 0xff000000
) >> 24) : __swap32md(msg->sm_engine_boots))
;
677 memcpy(iv, &ivv, sizeof(ivv));
678 ivv = htobe32(msg->sm_engine_time)(__uint32_t)(__builtin_constant_p(msg->sm_engine_time) ? (
__uint32_t)(((__uint32_t)(msg->sm_engine_time) & 0xff)
<< 24 | ((__uint32_t)(msg->sm_engine_time) & 0xff00
) << 8 | ((__uint32_t)(msg->sm_engine_time) & 0xff0000
) >> 8 | ((__uint32_t)(msg->sm_engine_time) & 0xff000000
) >> 24) : __swap32md(msg->sm_engine_time))
;
679 memcpy(iv + sizeof(ivv), &ivv, sizeof(ivv));
680 memcpy(iv + 2 * sizeof(ivv), msg->sm_salt, SNMP_USM_SALTLEN8);
681 break;
682 default:
683 return -1;
684 }
685
686 if ((ctx = EVP_CIPHER_CTX_new()) == NULL((void *)0))
687 return -1;
688
689 if (!EVP_CipherInit(ctx, cipher, privkey, iv, do_encrypt)) {
690 EVP_CIPHER_CTX_free(ctx);
691 return -1;
692 }
693
694 if (!do_encrypt)
695 EVP_CIPHER_CTX_set_padding(ctx, 0);
696
697 if (EVP_CipherUpdate(ctx, outbuf, &len, inbuf, inlen) &&
698 EVP_CipherFinal_ex(ctx, outbuf + len, &len2))
699 rv = len + len2;
700 else
701 rv = -1;
702
703 EVP_CIPHER_CTX_free(ctx);
704 return rv;
705}
706
707/*
708 * RFC3414, Password to Key Algorithm
709 */
710char *
711usm_passwd2key(const EVP_MD *md, char *passwd, int *maxlen)
712{
713 EVP_MD_CTX *ctx;
714 int i, count;
715 u_char *pw, *c;
716 u_char pwbuf[2 * EVP_MAX_MD_SIZE64 + SNMPD_MAXENGINEIDLEN32];
717 u_char keybuf[EVP_MAX_MD_SIZE64];
718 unsigned dlen;
719 char *key;
720
721 if ((ctx = EVP_MD_CTX_new()) == NULL((void *)0))
722 return NULL((void *)0);
723 if (!EVP_DigestInit_ex(ctx, md, NULL((void *)0))) {
724 EVP_MD_CTX_free(ctx);
725 return NULL((void *)0);
726 }
727 pw = (u_char *)passwd;
728 for (count = 0; count < 1048576; count += 64) {
729 c = pwbuf;
730 for (i = 0; i < 64; i++) {
731 if (*pw == '\0')
732 pw = (u_char *)passwd;
733 *c++ = *pw++;
734 }
735 if (!EVP_DigestUpdate(ctx, pwbuf, 64)) {
736 EVP_MD_CTX_free(ctx);
737 return NULL((void *)0);
738 }
739 }
740 if (!EVP_DigestFinal_ex(ctx, keybuf, &dlen)) {
741 EVP_MD_CTX_free(ctx);
742 return NULL((void *)0);
743 }
744
745 /* Localize the key */
746#ifdef DEBUG
747 assert(snmpd_env->sc_engineid_len <= SNMPD_MAXENGINEIDLEN32);
748#endif
749 memcpy(pwbuf, keybuf, dlen);
750 memcpy(pwbuf + dlen, snmpd_env->sc_engineid,
751 snmpd_env->sc_engineid_len);
752 memcpy(pwbuf + dlen + snmpd_env->sc_engineid_len, keybuf, dlen);
753
754 if (!EVP_DigestInit_ex(ctx, md, NULL((void *)0)) ||
755 !EVP_DigestUpdate(ctx, pwbuf,
756 2 * dlen + snmpd_env->sc_engineid_len) ||
757 !EVP_DigestFinal_ex(ctx, keybuf, &dlen)) {
758 EVP_MD_CTX_free(ctx);
759 return NULL((void *)0);
760 }
761 EVP_MD_CTX_free(ctx);
762
763 if (*maxlen > 0 && dlen > (unsigned)*maxlen)
764 dlen = (unsigned)*maxlen;
765 if ((key = malloc(dlen)) == NULL((void *)0))
766 fatal("key");
767 memcpy(key, keybuf, dlen);
768 *maxlen = (int)dlen;
769 return key;
770}