Annotation of src/usr.bin/snmp/usm.c, Revision 1.6
1.6 ! tb 1: /* $OpenBSD: usm.c,v 1.5 2019/10/24 12:39:26 tb Exp $ */
1.1 martijn 2:
3: /*
4: * Copyright (c) 2019 Martijn van Duren <martijn@openbsd.org>
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/time.h>
20:
21: #include <openssl/evp.h>
22: #include <openssl/hmac.h>
23:
24: #include <ber.h>
25: #include <errno.h>
26: #include <string.h>
27: #include <time.h>
28:
29: #include "smi.h"
30: #include "snmp.h"
31: #include "usm.h"
32:
33: #define USM_MAX_DIGESTLEN 48
34: #define USM_MAX_TIMEWINDOW 150
35: #define USM_SALTOFFSET 8
36:
37: struct usm_sec {
38: struct snmp_sec snmp;
39: char *user;
40: size_t userlen;
41: int engineidset;
42: char *engineid;
43: size_t engineidlen;
1.2 martijn 44: enum usm_key_level authlevel;
45: const EVP_MD *digest;
46: char *authkey;
1.3 martijn 47: enum usm_key_level privlevel;
48: const EVP_CIPHER *cipher;
49: char *privkey;
1.1 martijn 50: int bootsset;
51: uint32_t boots;
52: int timeset;
53: uint32_t time;
54: struct timespec timecheck;
55: };
56:
1.2 martijn 57: struct usm_cookie {
58: size_t digestoffset;
1.3 martijn 59: long long salt;
60: uint32_t boots;
61: uint32_t time;
1.2 martijn 62: };
63:
1.1 martijn 64: static int usm_doinit(struct snmp_agent *);
1.2 martijn 65: static char *usm_genparams(struct snmp_agent *, size_t *, void **);
66: static int usm_finalparams(struct snmp_agent *, char *, size_t, size_t, void *);
1.3 martijn 67: static struct ber_element *usm_encpdu(struct snmp_agent *agent,
68: struct ber_element *pdu, void *cookie);
69: static char *usm_crypt(const EVP_CIPHER *, int, char *, struct usm_cookie *,
70: char *, size_t, size_t *);
1.1 martijn 71: static int usm_parseparams(struct snmp_agent *, char *, size_t, off_t, char *,
1.3 martijn 72: size_t, uint8_t, void **);
73: struct ber_element *usm_decpdu(struct snmp_agent *, char *, size_t, void *);
1.2 martijn 74: static void usm_digest_pos(void *, size_t);
1.1 martijn 75: static void usm_free(void *);
1.2 martijn 76: static char *usm_passwd2mkey(const EVP_MD *, const char *);
77: static char *usm_mkey2lkey(struct usm_sec *, const EVP_MD *, const char *);
78: static size_t usm_digestlen(const EVP_MD *);
1.1 martijn 79:
80: struct snmp_sec *
81: usm_init(const char *user, size_t userlen)
82: {
83: struct snmp_sec *sec;
84: struct usm_sec *usm;
85:
86: if (user == NULL || user[0] == '\0') {
87: errno = EINVAL;
88: return NULL;
89: }
90:
91: if ((sec = malloc(sizeof(*sec))) == NULL)
92: return NULL;
93:
94: if ((usm = calloc(1, sizeof(struct usm_sec))) == NULL) {
95: free(sec);
96: return NULL;
97: }
98: if ((usm->user = malloc(userlen)) == NULL) {
99: free(sec);
100: free(usm);
101: return NULL;
102: }
103: memcpy(usm->user, user, userlen);
104: usm->userlen = userlen;
105:
106: sec->model = SNMP_SEC_USM;
107: sec->init = usm_doinit;
108: sec->genparams = usm_genparams;
1.3 martijn 109: sec->encpdu = usm_encpdu;
1.1 martijn 110: sec->parseparams = usm_parseparams;
1.3 martijn 111: sec->decpdu = usm_decpdu;
1.2 martijn 112: sec->finalparams = usm_finalparams;
1.1 martijn 113: sec->free = usm_free;
1.2 martijn 114: sec->freecookie = free;
1.1 martijn 115: sec->data = usm;
116: return sec;
117: }
118:
119: static int
120: usm_doinit(struct snmp_agent *agent)
121: {
122: struct ber_element *ber;
123: struct usm_sec *usm = agent->v3->sec->data;
124: int level;
125: size_t userlen;
126:
127: if (usm->engineidset && usm->bootsset && usm->timeset)
128: return 0;
129:
130: level = agent->v3->level;
131: agent->v3->level = SNMP_MSGFLAG_REPORT;
132: userlen = usm->userlen;
133: usm->userlen = 0;
134:
135: if ((ber = snmp_get(agent, NULL, 0)) == NULL) {
136: agent->v3->level = level;
137: usm->userlen = userlen;
138: return -1;
139: }
1.5 tb 140: ober_free_element(ber);
1.1 martijn 141:
142: agent->v3->level = level;
143: usm->userlen = userlen;
144:
1.4 martijn 145: /*
146: * Ugly hack for HP Laserjet:
147: * This device returns the engineid on probing, but only returns boots
148: * and time after a packet has been sent with full auth/enc.
149: */
150: if (!usm->engineidset || !usm->bootsset || !usm->timeset) {
151: if ((ber = snmp_get(agent, NULL, 0)) == NULL)
152: return -1;
1.5 tb 153: ober_free_element(ber);
1.4 martijn 154: }
1.1 martijn 155: return 0;
156: }
157:
158: static char *
1.2 martijn 159: usm_genparams(struct snmp_agent *agent, size_t *len, void **cookie)
1.1 martijn 160: {
161: struct ber ber;
1.2 martijn 162: struct ber_element *params, *digestelm;
1.1 martijn 163: struct usm_sec *usm = agent->v3->sec->data;
1.2 martijn 164: char digest[USM_MAX_DIGESTLEN];
1.3 martijn 165: size_t digestlen = 0, saltlen = 0;
1.1 martijn 166: char *secparams = NULL;
167: ssize_t berlen = 0;
1.2 martijn 168: struct usm_cookie *usmcookie;
1.1 martijn 169: struct timespec now, timediff;
170:
1.2 martijn 171: bzero(digest, sizeof(digest));
172:
173: if ((usmcookie = calloc(1, sizeof(*usmcookie))) == NULL)
174: return NULL;
175: *cookie = usmcookie;
176:
1.3 martijn 177: arc4random_buf(&(usmcookie->salt), sizeof(usmcookie->salt));
1.1 martijn 178: if (usm->timeset) {
1.2 martijn 179: if (clock_gettime(CLOCK_MONOTONIC, &now) == -1) {
180: free(usmcookie);
1.1 martijn 181: return NULL;
1.2 martijn 182: }
1.1 martijn 183: timespecsub(&now, &(usm->timecheck), &timediff);
1.3 martijn 184: usmcookie->time = usm->time + timediff.tv_sec;
1.1 martijn 185: } else
1.3 martijn 186: usmcookie->time = 0;
187: usmcookie->boots = usm->boots;
188:
1.2 martijn 189: if (agent->v3->level & SNMP_MSGFLAG_AUTH)
190: digestlen = usm_digestlen(usm->digest);
1.3 martijn 191: if (agent->v3->level & SNMP_MSGFLAG_PRIV)
192: saltlen = sizeof(usmcookie->salt);
193:
1.5 tb 194: if ((params = ober_printf_elements(NULL, "{xddxxx}", usm->engineid,
1.3 martijn 195: usm->engineidlen, usmcookie->boots, usmcookie->time, usm->user,
196: usm->userlen, digest, digestlen, &(usmcookie->salt),
197: saltlen)) == NULL) {
1.2 martijn 198: free(usmcookie);
199: return NULL;
200: }
1.1 martijn 201:
1.5 tb 202: if (ober_scanf_elements(params, "{SSSSe", &digestelm) == -1) {
203: ober_free_element(params);
1.2 martijn 204: free(usmcookie);
1.1 martijn 205: return NULL;
1.2 martijn 206: }
207:
1.5 tb 208: ober_set_writecallback(digestelm, usm_digest_pos, usmcookie);
1.1 martijn 209:
210: bzero(&ber, sizeof(ber));
1.5 tb 211: ober_set_application(&ber, smi_application);
212: if (ober_write_elements(&ber, params) != -1)
1.1 martijn 213: berlen = ber_copy_writebuf(&ber, (void **)&secparams);
214:
215: *len = berlen;
1.5 tb 216: ober_free_element(params);
217: ober_free(&ber);
1.1 martijn 218: return secparams;
219: }
220:
1.3 martijn 221: static struct ber_element *
222: usm_encpdu(struct snmp_agent *agent, struct ber_element *pdu, void *cookie)
223: {
224: struct usm_sec *usm = agent->v3->sec->data;
225: struct usm_cookie *usmcookie = cookie;
226: struct ber ber;
227: struct ber_element *retpdu;
228: char *serialpdu, *encpdu;
229: ssize_t pdulen;
230: size_t encpdulen;
231:
232: bzero(&ber, sizeof(ber));
1.5 tb 233: ober_set_application(&ber, smi_application);
234: pdulen = ober_write_elements(&ber, pdu);
1.3 martijn 235: if (pdulen == -1)
236: return NULL;
237:
1.5 tb 238: ober_get_writebuf(&ber, (void **)&serialpdu);
1.3 martijn 239:
240: encpdu = usm_crypt(usm->cipher, 1, usm->privkey, usmcookie, serialpdu,
241: pdulen, &encpdulen);
1.5 tb 242: ober_free(&ber);
1.3 martijn 243: if (encpdu == NULL)
244: return NULL;
245:
1.5 tb 246: retpdu = ober_add_nstring(NULL, encpdu, encpdulen);
1.3 martijn 247: free(encpdu);
248: return retpdu;
249: }
250:
251: static char *
252: usm_crypt(const EVP_CIPHER *cipher, int do_enc, char *key,
253: struct usm_cookie *cookie, char *serialpdu, size_t pdulen, size_t *outlen)
254: {
1.6 ! tb 255: EVP_CIPHER_CTX *ctx;
1.3 martijn 256: size_t i;
257: char iv[EVP_MAX_IV_LENGTH];
258: char *salt = (char *)&(cookie->salt);
259: char *outtext;
260: int len, len2, bs;
261: uint32_t ivv;
262:
263: switch (EVP_CIPHER_type(cipher)) {
264: case NID_des_cbc:
265: /* RFC3414, chap 8.1.1.1. */
266: for (i = 0; i < 8; i++)
267: iv[i] = salt[i] ^ key[USM_SALTOFFSET + i];
268: break;
269: case NID_aes_128_cfb128:
270: /* RFC3826, chap 3.1.2.1. */
271: ivv = htobe32(cookie->boots);
272: memcpy(iv, &ivv, sizeof(ivv));
273: ivv = htobe32(cookie->time);
274: memcpy(iv + sizeof(ivv), &ivv, sizeof(ivv));
275: memcpy(iv + 2 * sizeof(ivv), &(cookie->salt),
276: sizeof(cookie->salt));
277: break;
278: default:
279: return NULL;
280: }
281:
1.6 ! tb 282: if ((ctx = EVP_CIPHER_CTX_new()) == NULL)
1.3 martijn 283: return NULL;
284:
1.6 ! tb 285: if (!EVP_CipherInit(ctx, cipher, key, iv, do_enc)) {
! 286: EVP_CIPHER_CTX_free(ctx);
! 287: return NULL;
! 288: }
! 289:
! 290: EVP_CIPHER_CTX_set_padding(ctx, do_enc);
1.3 martijn 291:
292: bs = EVP_CIPHER_block_size(cipher);
293: /* Maximum output size */
294: *outlen = pdulen + (bs - (pdulen % bs));
295:
1.6 ! tb 296: if ((outtext = malloc(*outlen)) == NULL) {
! 297: EVP_CIPHER_CTX_free(ctx);
1.3 martijn 298: return NULL;
1.6 ! tb 299: }
1.3 martijn 300:
1.6 ! tb 301: if (EVP_CipherUpdate(ctx, outtext, &len, serialpdu, pdulen) &&
! 302: EVP_CipherFinal_ex(ctx, outtext + len, &len2))
1.3 martijn 303: *outlen = len + len2;
304: else {
305: free(outtext);
306: outtext = NULL;
307: }
308:
1.6 ! tb 309: EVP_CIPHER_CTX_free(ctx);
1.3 martijn 310:
311: return outtext;
312: }
313:
1.1 martijn 314: static int
1.2 martijn 315: usm_finalparams(struct snmp_agent *agent, char *buf, size_t buflen,
316: size_t secparamsoffset, void *cookie)
317: {
318: struct usm_sec *usm = agent->v3->sec->data;
319: struct usm_cookie *usmcookie = cookie;
320: u_char digest[EVP_MAX_MD_SIZE];
321:
322: if ((agent->v3->level & SNMP_MSGFLAG_AUTH) == 0)
323: return 0;
324:
325: if (usm->authlevel != USM_KEY_LOCALIZED)
326: return -1;
327:
328: if (HMAC(usm->digest, usm->authkey, EVP_MD_size(usm->digest), buf,
329: buflen, digest, NULL) == NULL)
330: return -1;
331:
332: memcpy(buf + secparamsoffset + usmcookie->digestoffset, digest,
333: usm_digestlen(usm->digest));
334: return 0;
335: }
336:
337: static int
1.1 martijn 338: usm_parseparams(struct snmp_agent *agent, char *packet, size_t packetlen,
1.3 martijn 339: off_t secparamsoffset, char *buf, size_t buflen, uint8_t level,
340: void **cookie)
1.1 martijn 341: {
342: struct usm_sec *usm = agent->v3->sec->data;
343: struct ber ber;
344: struct ber_element *secparams;
1.3 martijn 345: char *engineid, *user, *digest, *salt;
346: size_t engineidlen, userlen, digestlen, saltlen;
1.1 martijn 347: struct timespec now, timediff;
1.2 martijn 348: off_t digestoffset;
349: char exp_digest[EVP_MAX_MD_SIZE];
1.3 martijn 350: struct usm_cookie *usmcookie;
1.1 martijn 351:
352: bzero(&ber, sizeof(ber));
1.2 martijn 353: bzero(exp_digest, sizeof(exp_digest));
1.1 martijn 354:
1.5 tb 355: ober_set_application(&ber, smi_application);
356: ober_set_readbuf(&ber, buf, buflen);
357: if ((secparams = ober_read_elements(&ber, NULL)) == NULL)
1.1 martijn 358: return -1;
1.5 tb 359: ober_free(&ber);
1.1 martijn 360:
1.3 martijn 361: if ((usmcookie = malloc(sizeof(*usmcookie))) == NULL)
362: goto fail;
363: *cookie = usmcookie;
364:
1.5 tb 365: if (ober_scanf_elements(secparams, "{xddxpxx}", &engineid, &engineidlen,
1.3 martijn 366: &(usmcookie->boots), &(usmcookie->time), &user, &userlen,
367: &digestoffset, &digest, &digestlen, &salt, &saltlen) == -1)
368: goto fail;
369: if (saltlen != sizeof(usmcookie->salt) && saltlen != 0)
1.1 martijn 370: goto fail;
1.3 martijn 371: memcpy(&(usmcookie->salt), salt, saltlen);
1.1 martijn 372:
373: if (!usm->engineidset) {
374: if (usm_setengineid(agent->v3->sec, engineid,
375: engineidlen) == -1)
376: goto fail;
377: } else {
378: if (usm->engineidlen != engineidlen)
379: goto fail;
380: if (memcmp(usm->engineid, engineid, engineidlen) != 0)
381: goto fail;
382: }
383:
384: if (!usm->bootsset) {
1.3 martijn 385: usm->boots = usmcookie->boots;
1.1 martijn 386: usm->bootsset = 1;
387: } else {
1.3 martijn 388: if (usmcookie->boots < usm->boots)
1.1 martijn 389: goto fail;
1.3 martijn 390: if (usmcookie->boots > usm->boots) {
1.1 martijn 391: usm->bootsset = 0;
392: usm->timeset = 0;
393: usm_doinit(agent);
394: goto fail;
395: }
396: }
397:
398: if (!usm->timeset) {
1.3 martijn 399: usm->time = usmcookie->time;
1.1 martijn 400: if (clock_gettime(CLOCK_MONOTONIC, &usm->timecheck) == -1)
401: goto fail;
402: usm->timeset = 1;
403: } else {
404: if (clock_gettime(CLOCK_MONOTONIC, &now) == -1)
405: goto fail;
406: timespecsub(&now, &(usm->timecheck), &timediff);
1.3 martijn 407: if (usmcookie->time <
408: usm->time + timediff.tv_sec - USM_MAX_TIMEWINDOW ||
409: usmcookie->time >
410: usm->time + timediff.tv_sec + USM_MAX_TIMEWINDOW) {
1.1 martijn 411: usm->bootsset = 0;
412: usm->timeset = 0;
413: usm_doinit(agent);
414: goto fail;
415: }
1.4 martijn 416: }
417: /*
418: * Don't assume these are set if both are zero.
419: * Ugly hack for HP Laserjet
420: */
421: if (usm->boots == 0 && usm->time == 0) {
422: usm->bootsset = 0;
423: usm->timeset = 0;
1.1 martijn 424: }
425:
426: if (userlen != usm->userlen ||
427: memcmp(user, usm->user, userlen) != 0)
428: goto fail;
429:
1.2 martijn 430: if (level & SNMP_MSGFLAG_AUTH) {
431: if (digestlen != usm_digestlen(usm->digest))
432: goto fail;
433: }
434: if ((agent->v3->level & SNMP_MSGFLAG_AUTH)) {
435: bzero(packet + secparamsoffset + digestoffset, digestlen);
436: if (HMAC(usm->digest, usm->authkey, EVP_MD_size(usm->digest), packet,
437: packetlen, exp_digest, NULL) == NULL)
438: goto fail;
439:
440: if (memcmp(exp_digest, digest, digestlen) != 0)
441: goto fail;
442: } else
443: if (digestlen != 0)
444: goto fail;
445:
1.5 tb 446: ober_free_element(secparams);
1.1 martijn 447: return 0;
448:
449: fail:
1.3 martijn 450: free(usmcookie);
1.5 tb 451: ober_free_element(secparams);
1.1 martijn 452: return -1;
453: }
454:
1.3 martijn 455: struct ber_element *
456: usm_decpdu(struct snmp_agent *agent, char *encpdu, size_t encpdulen, void *cookie)
457: {
458: struct usm_sec *usm = agent->v3->sec->data;
459: struct usm_cookie *usmcookie = cookie;
460: struct ber ber;
461: struct ber_element *scopedpdu;
462: char *rawpdu;
463: size_t rawpdulen;
464:
465: if ((rawpdu = usm_crypt(usm->cipher, 0, usm->privkey, usmcookie,
466: encpdu, encpdulen, &rawpdulen)) == NULL)
467: return NULL;
468:
469: bzero(&ber, sizeof(ber));
1.5 tb 470: ober_set_application(&ber, smi_application);
471: ober_set_readbuf(&ber, rawpdu, rawpdulen);
472: scopedpdu = ober_read_elements(&ber, NULL);
473: ober_free(&ber);
1.3 martijn 474: free(rawpdu);
475:
476: return scopedpdu;
477: }
478:
1.1 martijn 479: static void
1.2 martijn 480: usm_digest_pos(void *data, size_t offset)
481: {
482: struct usm_cookie *usmcookie = data;
483:
484: usmcookie->digestoffset = offset;
485: }
486:
487: static void
1.1 martijn 488: usm_free(void *data)
489: {
490: struct usm_sec *usm = data;
491:
492: free(usm->user);
1.2 martijn 493: free(usm->authkey);
1.3 martijn 494: free(usm->privkey);
1.1 martijn 495: free(usm->engineid);
496: free(usm);
497: }
498:
499: int
1.2 martijn 500: usm_setauth(struct snmp_sec *sec, const EVP_MD *digest, const char *key,
501: size_t keylen, enum usm_key_level level)
502: {
503: struct usm_sec *usm = sec->data;
504: char *lkey;
505:
506: /*
507: * We could transform a master key to a local key here if we already
508: * have usm_setengineid called. Sine snmpc.c is the only caller at
509: * the moment there's no need, since it always calls this function
510: * first.
511: */
512: if (level == USM_KEY_PASSWORD) {
513: if ((usm->authkey = usm_passwd2mkey(digest, key)) == NULL)
514: return -1;
515: level = USM_KEY_MASTER;
516: keylen = EVP_MD_size(digest);
517: } else {
518: if (keylen != (size_t)EVP_MD_size(digest)) {
519: errno = EINVAL;
520: return -1;
521: }
522: if ((lkey = malloc(keylen)) == NULL)
523: return -1;
524: memcpy(lkey, key, keylen);
525: usm->authkey = lkey;
526: }
527: usm->digest = digest;
528: usm->authlevel = level;
529: return 0;
530: }
531:
532: int
1.3 martijn 533: usm_setpriv(struct snmp_sec *sec, const EVP_CIPHER *cipher, const char *key,
534: size_t keylen, enum usm_key_level level)
535: {
536: struct usm_sec *usm = sec->data;
537: char *lkey;
538:
539: if (usm->digest == NULL) {
540: errno = EINVAL;
541: return -1;
542: }
543:
544: /*
545: * We could transform a master key to a local key here if we already
546: * have usm_setengineid called. Sine snmpc.c is the only caller at
547: * the moment there's no need, since it always calls us first.
548: */
549: if (level == USM_KEY_PASSWORD) {
550: if ((usm->privkey = usm_passwd2mkey(usm->digest, key)) == NULL)
551: return -1;
552: level = USM_KEY_MASTER;
553: keylen = EVP_MD_size(usm->digest);
554: } else {
555: if (keylen != (size_t)EVP_MD_size(usm->digest)) {
556: errno = EINVAL;
557: return -1;
558: }
559: if ((lkey = malloc(keylen)) == NULL)
560: return -1;
561: memcpy(lkey, key, keylen);
562: usm->privkey = lkey;
563: }
564: usm->cipher = cipher;
565: usm->privlevel = level;
566: return 0;
567: }
568:
569: int
1.1 martijn 570: usm_setengineid(struct snmp_sec *sec, char *engineid, size_t engineidlen)
571: {
572: struct usm_sec *usm = sec->data;
1.2 martijn 573: char *mkey;
1.1 martijn 574:
575: if (usm->engineid != NULL)
576: free(usm->engineid);
577: if ((usm->engineid = malloc(engineidlen)) == NULL)
578: return -1;
579: memcpy(usm->engineid, engineid, engineidlen);
580: usm->engineidlen = engineidlen;
581: usm->engineidset = 1;
582:
1.2 martijn 583: if (usm->authlevel == USM_KEY_MASTER) {
584: mkey = usm->authkey;
585: if ((usm->authkey = usm_mkey2lkey(usm, usm->digest,
586: mkey)) == NULL) {
587: usm->authkey = mkey;
588: return -1;
589: }
590: free(mkey);
591: usm->authlevel = USM_KEY_LOCALIZED;
1.3 martijn 592: }
593: if (usm->privlevel == USM_KEY_MASTER) {
594: mkey = usm->privkey;
595: if ((usm->privkey = usm_mkey2lkey(usm, usm->digest,
596: mkey)) == NULL) {
597: usm->privkey = mkey;
598: return -1;
599: }
600: free(mkey);
601: usm->privlevel = USM_KEY_LOCALIZED;
1.2 martijn 602: }
603:
1.1 martijn 604: return 0;
605: }
606:
607: int
608: usm_setbootstime(struct snmp_sec *sec, uint32_t boots, uint32_t time)
609: {
610: struct usm_sec *usm = sec->data;
611:
612: if (clock_gettime(CLOCK_MONOTONIC, &(usm->timecheck)) == -1)
613: return -1;
614:
615: usm->boots = boots;
616: usm->bootsset = 1;
617: usm->time = time;
618: usm->timeset = 1;
619: return 0;
1.2 martijn 620: }
621:
622: static char *
623: usm_passwd2mkey(const EVP_MD *md, const char *passwd)
624: {
1.6 ! tb 625: EVP_MD_CTX *ctx;
1.2 martijn 626: int i, count;
627: const u_char *pw;
628: u_char *c;
629: u_char keybuf[EVP_MAX_MD_SIZE];
630: unsigned dlen;
631: char *key;
632:
1.6 ! tb 633: if ((ctx = EVP_MD_CTX_new()) == NULL)
! 634: return NULL;
! 635: EVP_DigestInit_ex(ctx, md, NULL);
1.2 martijn 636: pw = (const u_char *)passwd;
637: for (count = 0; count < 1048576; count += 64) {
638: c = keybuf;
639: for (i = 0; i < 64; i++) {
640: if (*pw == '\0')
641: pw = (const u_char *)passwd;
642: *c++ = *pw++;
643: }
1.6 ! tb 644: EVP_DigestUpdate(ctx, keybuf, 64);
1.2 martijn 645: }
1.6 ! tb 646: EVP_DigestFinal_ex(ctx, keybuf, &dlen);
! 647: EVP_MD_CTX_free(ctx);
1.2 martijn 648:
649: if ((key = malloc(dlen)) == NULL)
650: return NULL;
651: memcpy(key, keybuf, dlen);
652: return key;
653: }
654:
655: static char *
656: usm_mkey2lkey(struct usm_sec *usm, const EVP_MD *md, const char *mkey)
657: {
1.6 ! tb 658: EVP_MD_CTX *ctx;
1.2 martijn 659: u_char buf[EVP_MAX_MD_SIZE];
660: u_char *lkey;
661: unsigned lklen;
662:
1.6 ! tb 663: if ((ctx = EVP_MD_CTX_new()) == NULL)
! 664: return NULL;
! 665: EVP_DigestInit_ex(ctx, md, NULL);
1.2 martijn 666:
1.6 ! tb 667: EVP_DigestUpdate(ctx, mkey, EVP_MD_size(md));
! 668: EVP_DigestUpdate(ctx, usm->engineid, usm->engineidlen);
! 669: EVP_DigestUpdate(ctx, mkey, EVP_MD_size(md));
1.2 martijn 670:
1.6 ! tb 671: EVP_DigestFinal_ex(ctx, buf, &lklen);
! 672: EVP_MD_CTX_free(ctx);
1.2 martijn 673:
674: if ((lkey = malloc(lklen)) == NULL)
675: return NULL;
676: memcpy(lkey, buf, lklen);
677: return lkey;
678: }
679:
680: static size_t
681: usm_digestlen(const EVP_MD *md)
682: {
683: switch (EVP_MD_type(md)) {
684: case NID_md5:
685: case NID_sha1:
686: return 12;
687: case NID_sha224:
688: return 16;
689: case NID_sha256:
690: return 24;
691: case NID_sha384:
692: return 32;
693: case NID_sha512:
694: return 48;
695: default:
696: return 0;
697: }
1.1 martijn 698: }