diff options
author | 2019-09-18 09:52:47 +0000 | |
---|---|---|
committer | 2019-09-18 09:52:47 +0000 | |
commit | 4f098f75638a08c38c3ada34b3434c13c74aec98 (patch) | |
tree | 557adf04bfe665185c4049840cf9c7fc5a415a49 | |
parent | Initial SNMPv3/USM support. (diff) | |
download | wireguard-openbsd-4f098f75638a08c38c3ada34b3434c13c74aec98.tar.xz wireguard-openbsd-4f098f75638a08c38c3ada34b3434c13c74aec98.zip |
Add support for SNMPv3/USM authentication.
net-snmp's -3k is supported via the -k parameter, -3m is not supported.
Feedback and OK jmatthew@
-rw-r--r-- | usr.bin/snmp/Makefile | 6 | ||||
-rw-r--r-- | usr.bin/snmp/snmp.1 | 66 | ||||
-rw-r--r-- | usr.bin/snmp/snmp.c | 31 | ||||
-rw-r--r-- | usr.bin/snmp/snmp.h | 6 | ||||
-rw-r--r-- | usr.bin/snmp/snmpc.c | 62 | ||||
-rw-r--r-- | usr.bin/snmp/usm.c | 233 | ||||
-rw-r--r-- | usr.bin/snmp/usm.h | 11 |
7 files changed, 390 insertions, 25 deletions
diff --git a/usr.bin/snmp/Makefile b/usr.bin/snmp/Makefile index 7fef458a60d..3b666631a44 100644 --- a/usr.bin/snmp/Makefile +++ b/usr.bin/snmp/Makefile @@ -1,9 +1,9 @@ -# $OpenBSD: Makefile,v 1.2 2019/09/18 09:48:14 martijn Exp $ +# $OpenBSD: Makefile,v 1.3 2019/09/18 09:52:47 martijn Exp $ PROG= snmp SRCS= mib.c smi.c snmp.c snmpc.c usm.c -LDADD+= -lutil -DPADD+= ${LIBUTIL} +LDADD+= -lcrypto -lutil +DPADD+= ${LIBCRYPTO} ${LIBUTIL} MAN= snmp.1 diff --git a/usr.bin/snmp/snmp.1 b/usr.bin/snmp/snmp.1 index 95eb26b7a45..a1ab1a65ee0 100644 --- a/usr.bin/snmp/snmp.1 +++ b/usr.bin/snmp/snmp.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: snmp.1,v 1.4 2019/09/18 09:48:14 martijn Exp $ +.\" $OpenBSD: snmp.1,v 1.5 2019/09/18 09:52:47 martijn Exp $ .\" .\" Copyright (c) 2019 Martijn van Duren <martijn@openbsd.org> .\" @@ -23,9 +23,13 @@ .Sh SYNOPSIS .Nm .Cm get | getnext +.Op Fl A Ar authpass +.Op Fl a Ar digest .Op Fl c Ar community .Op Fl E Ar ctxengineid .Op Fl e Ar secengineid +.Op Fl k Ar localauth +.Op Fl l Ar seclevel .Op Fl n Ar ctxname .Op Fl O Cm afnQqSvx .Op Fl r Ar retries @@ -37,9 +41,13 @@ .Ar oid ... .Nm .Cm walk +.Op Fl A Ar authpass +.Op Fl a Ar digest .Op Fl c Ar community .Op Fl E Ar ctxengineid .Op Fl e Ar secengineid +.Op Fl k Ar localauth +.Op Fl l Ar seclevel .Op Fl n Ar ctxname .Op Fl O Cm afnQqSvx .Op Fl r Ar retries @@ -53,9 +61,13 @@ .Op Ar oid .Nm .Cm bulkget +.Op Fl A Ar authpass +.Op Fl a Ar digest .Op Fl c Ar community .Op Fl E Ar ctxengineid .Op Fl e Ar secengineid +.Op Fl k Ar localauth +.Op Fl l Ar seclevel .Op Fl n Ar ctxname .Op Fl O Cm afnQqSvx .Op Fl r Ar retries @@ -68,9 +80,13 @@ .Ar oid ... .Nm .Cm bulkwalk +.Op Fl A Ar authpass +.Op Fl a Ar digest .Op Fl c Ar community .Op Fl E Ar ctxengineid .Op Fl e Ar secengineid +.Op Fl k Ar localauth +.Op Fl l Ar seclevel .Op Fl n Ar ctxname .Op Fl O Cm afnQqSvx .Op Fl r Ar retries @@ -83,9 +99,13 @@ .Op Ar oid .Nm .Cm trap +.Op Fl A Ar authpass +.Op Fl a Ar digest .Op Fl c Ar community .Op Fl E Ar ctxengineid .Op Fl e Ar secengineid +.Op Fl k Ar localauth +.Op Fl l Ar seclevel .Op Fl n Ar ctxname .Op Fl r Ar retries .Op Fl t Ar timeout @@ -170,6 +190,28 @@ Dump the tree of compiled-in MIB objects. .Pp The options are as follows: .Bl -tag -width Ds +.It Fl A Ar authpass +The authentication password for the user. +This will be transformed to +.Ar localauth . +This option is only used by +.Fl v Cm 3 . +.It Fl a Ar digest +Set the digest +.Pq authentication +protocol. +Options are +.Cm MD5 , +.Cm SHA , +.Cm SHA-224 , +.Cm SHA-256 , +.Cm SHA-384 +or +.Cm SHA-512 . +This option defaults to +.Cm MD5 . +This option is only used by +.Fl v Cm 3 . .It Fl C Ar appopt Set the application specific .Ar appopt @@ -260,6 +302,28 @@ The snmpv3 context engine id. Most of the time this value can be safely ignored. This option is only used by .Fl v Cm 3 . +.It Fl k Ar localauth +The localized authentication password for the user in hexadecimal format +.Po +optionally prefixed with a +.Cm 0x +.Pc . +This option is only used by +.Fl v Cm 3 . +.It Fl l Ar seclevel +The security level. +Values can be +.Cm noAuthNoPriv Pq default +or +.Cm authNoPriv +.Po +requires either +.Fl A +or +.Fl k +.Pc . +This option is only used by +.Fl v Cm 3 . .It Fl n Ar ctxname Sets the context name. Defaults to an empty string. diff --git a/usr.bin/snmp/snmp.c b/usr.bin/snmp/snmp.c index 1ccac891b5e..4d04f2df07b 100644 --- a/usr.bin/snmp/snmp.c +++ b/usr.bin/snmp/snmp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: snmp.c,v 1.4 2019/09/18 09:48:14 martijn Exp $ */ +/* $OpenBSD: snmp.c,v 1.5 2019/09/18 09:52:47 martijn Exp $ */ /* * Copyright (c) 2019 Martijn van Duren <martijn@openbsd.org> @@ -39,6 +39,7 @@ static char * static struct ber_element * snmp_unpackage(struct snmp_agent *, char *, size_t); static void snmp_v3_free(struct snmp_v3 *); +static void snmp_v3_secparamsoffset(void *, size_t); struct snmp_v3 * snmp_v3_init(int level, const char *ctxname, size_t ctxnamelen, @@ -358,10 +359,12 @@ static char * snmp_package(struct snmp_agent *agent, struct ber_element *pdu, size_t *len) { struct ber ber; - struct ber_element *message, *scopedpdu = NULL; + struct ber_element *message, *scopedpdu = NULL, *secparams; ssize_t securitysize, ret; + size_t secparamsoffset; char *securityparams = NULL, *packet = NULL; long long msgid; + void *cookie = NULL; bzero(&ber, sizeof(ber)); ber_set_application(&ber, smi_application); @@ -395,7 +398,7 @@ snmp_package(struct snmp_agent *agent, struct ber_element *pdu, size_t *len) } pdu = NULL; if ((securityparams = agent->v3->sec->genparams(agent, - &securitysize)) == NULL) { + &securitysize, &cookie)) == NULL) { ber_free_elements(scopedpdu); goto fail; } @@ -404,6 +407,10 @@ snmp_package(struct snmp_agent *agent, struct ber_element *pdu, size_t *len) (size_t) 1, agent->v3->sec->model, securityparams, securitysize, scopedpdu) == NULL) goto fail; + if (ber_scanf_elements(message, "{SSe", &secparams) == -1) + goto fail; + ber_set_writecallback(secparams, snmp_v3_secparamsoffset, + &secparamsoffset); break; } @@ -414,7 +421,17 @@ snmp_package(struct snmp_agent *agent, struct ber_element *pdu, size_t *len) *len = (size_t) ret; ber_free(&ber); + if (agent->version == SNMP_V3 && packet != NULL) { + if (agent->v3->sec->finalparams(agent, packet, + ret, secparamsoffset, cookie) == -1) { + free(packet); + packet = NULL; + } + } + fail: + if (agent->version == SNMP_V3) + agent->v3->sec->freecookie(cookie); ber_free_elements(message); free(securityparams); return packet; @@ -497,6 +514,14 @@ fail: return NULL; } +static void +snmp_v3_secparamsoffset(void *cookie, size_t offset) +{ + size_t *spoffset = cookie; + + *spoffset = offset; +} + ssize_t ber_copy_writebuf(struct ber *ber, void **buf) { diff --git a/usr.bin/snmp/snmp.h b/usr.bin/snmp/snmp.h index 4895f4cd3cb..fb777223d73 100644 --- a/usr.bin/snmp/snmp.h +++ b/usr.bin/snmp/snmp.h @@ -1,4 +1,4 @@ -/* $OpenBSD: snmp.h,v 1.3 2019/09/18 09:48:14 martijn Exp $ */ +/* $OpenBSD: snmp.h,v 1.4 2019/09/18 09:52:47 martijn Exp $ */ /* * Copyright (c) 2019 Martijn van Duren <martijn@openbsd.org> @@ -113,10 +113,12 @@ struct snmp_agent; struct snmp_sec { enum snmp_security_model model; int (*init)(struct snmp_agent *); - char *(*genparams)(struct snmp_agent *, size_t *); + char *(*genparams)(struct snmp_agent *, size_t *, void **); + int (*finalparams)(struct snmp_agent *, char *, size_t, size_t, void *); int (*parseparams)(struct snmp_agent *, char *, size_t, off_t, char *, size_t, uint8_t); void (*free)(void *); + void (*freecookie)(void *); void *data; }; diff --git a/usr.bin/snmp/snmpc.c b/usr.bin/snmp/snmpc.c index 4150d9d11b1..0f208aaca92 100644 --- a/usr.bin/snmp/snmpc.c +++ b/usr.bin/snmp/snmpc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: snmpc.c,v 1.9 2019/09/18 09:48:14 martijn Exp $ */ +/* $OpenBSD: snmpc.c,v 1.10 2019/09/18 09:52:47 martijn Exp $ */ /* * Copyright (c) 2019 Martijn van Duren <martijn@openbsd.org> @@ -23,6 +23,7 @@ #include <sys/un.h> #include <arpa/inet.h> +#include <openssl/evp.h> #include <ber.h> #include <ctype.h> @@ -41,7 +42,7 @@ #include "snmp.h" #include "usm.h" -#define GETOPT_COMMON "c:E:e:n:O:r:t:u:v:Z:" +#define GETOPT_COMMON "A:a:c:E:e:k:l:n:O:r:t:u:v:Z:" int snmpc_get(int, char *[]); int snmpc_walk(int, char *[]); @@ -96,8 +97,12 @@ enum smi_output_string output_string = smi_os_default; int main(int argc, char *argv[]) { + const EVP_MD *md = NULL; struct snmp_sec *sec; char *user = NULL; + enum usm_key_level authkeylevel; + char *authkey = NULL; + size_t authkeylen = 0; int seclevel = SNMP_MSGFLAG_REPORT; char *ctxname = NULL; char *ctxengineid = NULL, *secengineid = NULL; @@ -143,6 +148,28 @@ main(int argc, char *argv[]) while ((ch = getopt(argc, argv, optstr)) != -1) { switch (ch) { + case 'A': + authkey = optarg; + authkeylen = strlen(authkey); + authkeylevel = USM_KEY_PASSWORD; + break; + case 'a': + if (strcasecmp(optarg, "MD5") == 0) + md = EVP_md5(); + else if (strcasecmp(optarg, "SHA") == 0) + md = EVP_sha1(); + else if (strcasecmp(optarg, "SHA-224") == 0) + md = EVP_sha224(); + else if (strcasecmp(optarg, "SHA-256") == 0) + md = EVP_sha256(); + else if (strcasecmp(optarg, "SHA-384") == 0) + md = EVP_sha384(); + else if (strcasecmp(optarg, "SHA-512") == 0) + md = EVP_sha512(); + else + errx(1, "Invalid authentication protocol " + "specified after -a flag: %s", optarg); + break; case 'c': community = optarg; break; @@ -166,6 +193,25 @@ main(int argc, char *argv[]) err(1, "-3e"); } break; + case 'k': + authkey = snmpc_hex2bin(optarg, &authkeylen); + if (authkey == NULL) { + if (errno == EINVAL) + errx(1, "Bad key value after -k flag."); + err(1, "-k"); + } + authkeylevel = USM_KEY_LOCALIZED; + break; + case 'l': + if (strcasecmp(optarg, "noAuthNoPriv") == 0) + seclevel = SNMP_MSGFLAG_REPORT; + else if (strcasecmp(optarg, "authNoPriv") == 0) + seclevel = SNMP_MSGFLAG_AUTH | + SNMP_MSGFLAG_REPORT; + else + errx(1, "Invalid security level specified " + "after -l flag: %s", optarg); + break; case 'n': ctxname = optarg; break; @@ -348,6 +394,15 @@ main(int argc, char *argv[]) errx(1, "No securityName specified"); if ((sec = usm_init(user, strlen(user))) == NULL) err(1, "usm_init"); + if (seclevel & SNMP_MSGFLAG_AUTH) { + if (md == NULL) + md = EVP_md5(); + if (authkey == NULL) + errx(1, "No authKey or authPassword specified"); + if (usm_setauth(sec, md, authkey, authkeylen, + authkeylevel) == -1) + err(1, "Can't set authkey"); + } if (secengineid != NULL) { if (usm_setengineid(sec, secengineid, secengineidlen) == -1) @@ -1031,7 +1086,8 @@ usage(void) fprintf(stderr, "usage: snmp %s%s%s\n", snmp_app->name, snmp_app->usecommonopt ? - " [-c community] [-e secengineid] [-E ctxengineid] [-n ctxname]\n" + " [-A authpass] [-a digest] [-c community] [-e secengineid]\n" + " [-E ctxengineid] [-k localauth] [-l seclevel] [-n ctxname]\n" " [-O afnqvxSQ] [-r retries] [-t timeout] [-u user] [-v version]\n" " [-Z boots,time]\n" " " : "", diff --git a/usr.bin/snmp/usm.c b/usr.bin/snmp/usm.c index 6fa960797b5..1ca43316b43 100644 --- a/usr.bin/snmp/usm.c +++ b/usr.bin/snmp/usm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: usm.c,v 1.1 2019/09/18 09:48:14 martijn Exp $ */ +/* $OpenBSD: usm.c,v 1.2 2019/09/18 09:52:47 martijn Exp $ */ /* * Copyright (c) 2019 Martijn van Duren <martijn@openbsd.org> @@ -41,6 +41,9 @@ struct usm_sec { int engineidset; char *engineid; size_t engineidlen; + enum usm_key_level authlevel; + const EVP_MD *digest; + char *authkey; int bootsset; uint32_t boots; int timeset; @@ -48,11 +51,20 @@ struct usm_sec { struct timespec timecheck; }; +struct usm_cookie { + size_t digestoffset; +}; + static int usm_doinit(struct snmp_agent *); -static char *usm_genparams(struct snmp_agent *, size_t *); +static char *usm_genparams(struct snmp_agent *, size_t *, void **); +static int usm_finalparams(struct snmp_agent *, char *, size_t, size_t, void *); static int usm_parseparams(struct snmp_agent *, char *, size_t, off_t, char *, size_t, uint8_t); +static void usm_digest_pos(void *, size_t); static void usm_free(void *); +static char *usm_passwd2mkey(const EVP_MD *, const char *); +static char *usm_mkey2lkey(struct usm_sec *, const EVP_MD *, const char *); +static size_t usm_digestlen(const EVP_MD *); struct snmp_sec * usm_init(const char *user, size_t userlen) @@ -84,7 +96,9 @@ usm_init(const char *user, size_t userlen) sec->init = usm_doinit; sec->genparams = usm_genparams; sec->parseparams = usm_parseparams; + sec->finalparams = usm_finalparams; sec->free = usm_free; + sec->freecookie = free; sec->data = usm; return sec; } @@ -119,29 +133,51 @@ usm_doinit(struct snmp_agent *agent) } static char * -usm_genparams(struct snmp_agent *agent, size_t *len) +usm_genparams(struct snmp_agent *agent, size_t *len, void **cookie) { struct ber ber; - struct ber_element *params; + struct ber_element *params, *digestelm; struct usm_sec *usm = agent->v3->sec->data; + char digest[USM_MAX_DIGESTLEN]; + size_t digestlen = 0; char *secparams = NULL; ssize_t berlen = 0; + struct usm_cookie *usmcookie; struct timespec now, timediff; uint32_t boots, time; + bzero(digest, sizeof(digest)); + + if ((usmcookie = calloc(1, sizeof(*usmcookie))) == NULL) + return NULL; + *cookie = usmcookie; + if (usm->timeset) { - if (clock_gettime(CLOCK_MONOTONIC, &now) == -1) + if (clock_gettime(CLOCK_MONOTONIC, &now) == -1) { + free(usmcookie); return NULL; + } timespecsub(&now, &(usm->timecheck), &timediff); time = usm->time + timediff.tv_sec; } else time = 0; boots = usm->boots; - + if (agent->v3->level & SNMP_MSGFLAG_AUTH) + digestlen = usm_digestlen(usm->digest); if ((params = ber_printf_elements(NULL, "{xddxxx}", usm->engineid, - usm->engineidlen, boots, time, usm->user, usm->userlen, NULL, - (size_t) 0, NULL, (size_t) 0)) == NULL) + usm->engineidlen, boots, time, usm->user, usm->userlen, digest, + digestlen, NULL, (size_t) 0)) == NULL) { + free(usmcookie); return NULL; + } + + if (ber_scanf_elements(params, "{SSSSe", &digestelm) == -1) { + ber_free_element(params); + free(usmcookie); + return NULL; + } + + ber_set_writecallback(digestelm, usm_digest_pos, usmcookie); bzero(&ber, sizeof(ber)); ber_set_application(&ber, smi_application); @@ -155,18 +191,44 @@ usm_genparams(struct snmp_agent *agent, size_t *len) } static int +usm_finalparams(struct snmp_agent *agent, char *buf, size_t buflen, + size_t secparamsoffset, void *cookie) +{ + struct usm_sec *usm = agent->v3->sec->data; + struct usm_cookie *usmcookie = cookie; + u_char digest[EVP_MAX_MD_SIZE]; + + if ((agent->v3->level & SNMP_MSGFLAG_AUTH) == 0) + return 0; + + if (usm->authlevel != USM_KEY_LOCALIZED) + return -1; + + if (HMAC(usm->digest, usm->authkey, EVP_MD_size(usm->digest), buf, + buflen, digest, NULL) == NULL) + return -1; + + memcpy(buf + secparamsoffset + usmcookie->digestoffset, digest, + usm_digestlen(usm->digest)); + return 0; +} + +static int usm_parseparams(struct snmp_agent *agent, char *packet, size_t packetlen, off_t secparamsoffset, char *buf, size_t buflen, uint8_t level) { struct usm_sec *usm = agent->v3->sec->data; struct ber ber; struct ber_element *secparams; - char *engineid, *user; - size_t engineidlen, userlen; + char *engineid, *user, *digest; + size_t engineidlen, userlen, digestlen; struct timespec now, timediff; + off_t digestoffset; + char exp_digest[EVP_MAX_MD_SIZE]; uint32_t boots, time; bzero(&ber, sizeof(ber)); + bzero(exp_digest, sizeof(exp_digest)); ber_set_application(&ber, smi_application); ber_set_readbuf(&ber, buf, buflen); @@ -174,8 +236,9 @@ usm_parseparams(struct snmp_agent *agent, char *packet, size_t packetlen, return -1; ber_free(&ber); - if (ber_scanf_elements(secparams, "{xddxSS}", &engineid, &engineidlen, - &boots, &time, &user, &userlen) == -1) + if (ber_scanf_elements(secparams, "{xddxpxS}", &engineid, &engineidlen, + &boots, &time, &user, &userlen, &digestoffset, &digest, + &digestlen) == -1) goto fail; if (!usm->engineidset) { @@ -225,6 +288,22 @@ usm_parseparams(struct snmp_agent *agent, char *packet, size_t packetlen, memcmp(user, usm->user, userlen) != 0) goto fail; + if (level & SNMP_MSGFLAG_AUTH) { + if (digestlen != usm_digestlen(usm->digest)) + goto fail; + } + if ((agent->v3->level & SNMP_MSGFLAG_AUTH)) { + bzero(packet + secparamsoffset + digestoffset, digestlen); + if (HMAC(usm->digest, usm->authkey, EVP_MD_size(usm->digest), packet, + packetlen, exp_digest, NULL) == NULL) + goto fail; + + if (memcmp(exp_digest, digest, digestlen) != 0) + goto fail; + } else + if (digestlen != 0) + goto fail; + ber_free_element(secparams); return 0; @@ -234,19 +313,62 @@ fail: } static void +usm_digest_pos(void *data, size_t offset) +{ + struct usm_cookie *usmcookie = data; + + usmcookie->digestoffset = offset; +} + +static void usm_free(void *data) { struct usm_sec *usm = data; free(usm->user); + free(usm->authkey); free(usm->engineid); free(usm); } int +usm_setauth(struct snmp_sec *sec, const EVP_MD *digest, const char *key, + size_t keylen, enum usm_key_level level) +{ + struct usm_sec *usm = sec->data; + char *lkey; + + /* + * We could transform a master key to a local key here if we already + * have usm_setengineid called. Sine snmpc.c is the only caller at + * the moment there's no need, since it always calls this function + * first. + */ + if (level == USM_KEY_PASSWORD) { + if ((usm->authkey = usm_passwd2mkey(digest, key)) == NULL) + return -1; + level = USM_KEY_MASTER; + keylen = EVP_MD_size(digest); + } else { + if (keylen != (size_t)EVP_MD_size(digest)) { + errno = EINVAL; + return -1; + } + if ((lkey = malloc(keylen)) == NULL) + return -1; + memcpy(lkey, key, keylen); + usm->authkey = lkey; + } + usm->digest = digest; + usm->authlevel = level; + return 0; +} + +int usm_setengineid(struct snmp_sec *sec, char *engineid, size_t engineidlen) { struct usm_sec *usm = sec->data; + char *mkey; if (usm->engineid != NULL) free(usm->engineid); @@ -256,6 +378,17 @@ usm_setengineid(struct snmp_sec *sec, char *engineid, size_t engineidlen) usm->engineidlen = engineidlen; usm->engineidset = 1; + if (usm->authlevel == USM_KEY_MASTER) { + mkey = usm->authkey; + if ((usm->authkey = usm_mkey2lkey(usm, usm->digest, + mkey)) == NULL) { + usm->authkey = mkey; + return -1; + } + free(mkey); + usm->authlevel = USM_KEY_LOCALIZED; + } + return 0; } @@ -273,3 +406,79 @@ usm_setbootstime(struct snmp_sec *sec, uint32_t boots, uint32_t time) usm->timeset = 1; return 0; } + +static char * +usm_passwd2mkey(const EVP_MD *md, const char *passwd) +{ + EVP_MD_CTX ctx; + int i, count; + const u_char *pw; + u_char *c; + u_char keybuf[EVP_MAX_MD_SIZE]; + unsigned dlen; + char *key; + + bzero(&ctx, sizeof(ctx)); + EVP_DigestInit_ex(&ctx, md, NULL); + pw = (const u_char *)passwd; + for (count = 0; count < 1048576; count += 64) { + c = keybuf; + for (i = 0; i < 64; i++) { + if (*pw == '\0') + pw = (const u_char *)passwd; + *c++ = *pw++; + } + EVP_DigestUpdate(&ctx, keybuf, 64); + } + EVP_DigestFinal_ex(&ctx, keybuf, &dlen); + EVP_MD_CTX_cleanup(&ctx); + + if ((key = malloc(dlen)) == NULL) + return NULL; + memcpy(key, keybuf, dlen); + return key; +} + +static char * +usm_mkey2lkey(struct usm_sec *usm, const EVP_MD *md, const char *mkey) +{ + EVP_MD_CTX ctx; + u_char buf[EVP_MAX_MD_SIZE]; + u_char *lkey; + unsigned lklen; + + bzero(&ctx, sizeof(ctx)); + EVP_DigestInit_ex(&ctx, md, NULL); + + EVP_DigestUpdate(&ctx, mkey, EVP_MD_size(md)); + EVP_DigestUpdate(&ctx, usm->engineid, usm->engineidlen); + EVP_DigestUpdate(&ctx, mkey, EVP_MD_size(md)); + + EVP_DigestFinal_ex(&ctx, buf, &lklen); + EVP_MD_CTX_cleanup(&ctx); + + if ((lkey = malloc(lklen)) == NULL) + return NULL; + memcpy(lkey, buf, lklen); + return lkey; +} + +static size_t +usm_digestlen(const EVP_MD *md) +{ + switch (EVP_MD_type(md)) { + case NID_md5: + case NID_sha1: + return 12; + case NID_sha224: + return 16; + case NID_sha256: + return 24; + case NID_sha384: + return 32; + case NID_sha512: + return 48; + default: + return 0; + } +} diff --git a/usr.bin/snmp/usm.h b/usr.bin/snmp/usm.h index aa84290992a..4506ed4c341 100644 --- a/usr.bin/snmp/usm.h +++ b/usr.bin/snmp/usm.h @@ -1,4 +1,4 @@ -/* $OpenBSD: usm.h,v 1.1 2019/09/18 09:48:14 martijn Exp $ */ +/* $OpenBSD: usm.h,v 1.2 2019/09/18 09:52:47 martijn Exp $ */ /* * Copyright (c) 2019 Martijn van Duren <martijn@openbsd.org> @@ -18,6 +18,15 @@ #include "snmp.h" +enum usm_key_level { + USM_KEY_UNSET = 0, + USM_KEY_PASSWORD, + USM_KEY_MASTER, + USM_KEY_LOCALIZED +}; + struct snmp_sec *usm_init(const char *, size_t); +int usm_setauth(struct snmp_sec *, const EVP_MD *, const char *, size_t, + enum usm_key_level); int usm_setengineid(struct snmp_sec *, char *, size_t); int usm_setbootstime(struct snmp_sec *, uint32_t, uint32_t); |