This diff adds support for authNoPriv.

diff --git a/Makefile b/Makefile
index 9eb684b..102582b 100644
--- a/Makefile
+++ b/Makefile
@@ -2,8 +2,8 @@
 
 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/snmp.1 b/snmp.1
index 523fd16..e810560 100644
--- a/snmp.1
+++ b/snmp.1
@@ -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/snmp.c b/snmp.c
index 7165976..57b40e3 100644
--- a/snmp.c
+++ b/snmp.c
@@ -37,6 +37,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,
@@ -356,10 +357,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, *buf, *packet = NULL;
        long long msgid;
+       void *cookie = NULL;
 
        bzero(&ber, sizeof(ber));
        ber_set_application(&ber, smi_application);
@@ -393,7 +396,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;
                }
@@ -402,6 +405,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;
        }
 
@@ -413,7 +420,17 @@ snmp_package(struct snmp_agent *agent, struct ber_element 
*pdu, size_t *len)
                memcpy(packet, buf, 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;
@@ -493,3 +510,11 @@ fail:
        ber_free_elements(message);
        return NULL;
 }
+
+static void
+snmp_v3_secparamsoffset(void *cookie, size_t offset)
+{
+       size_t *spoffset = cookie;
+
+       *spoffset = offset;
+}
diff --git a/snmp.h b/snmp.h
index 1cfd8aa..df20f0d 100644
--- a/snmp.h
+++ b/snmp.h
@@ -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/snmpc.c b/snmpc.c
index 4c09405..edaa50c 100644
--- a/snmpc.c
+++ b/snmpc.c
@@ -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 (strcmp(optarg, "noAuthNoPriv") == 0)
+                               seclevel = SNMP_MSGFLAG_REPORT;
+                       else if (strcmp(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/usm.c b/usm.c
index c51cf7d..df9a53d 100644
--- a/usm.c
+++ b/usm.c
@@ -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,19 +133,29 @@ 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];
        char *secparams = NULL, *buf;
        ssize_t berlen;
+       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
@@ -139,9 +163,20 @@ usm_genparams(struct snmp_agent *agent, size_t *len)
        boots = usm->boots;
 
        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,
+           agent->v3->level & SNMP_MSGFLAG_AUTH ? usm_digestlen(usm->digest) :
+           (size_t) 0, 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,6 +190,29 @@ usm_genparams(struct snmp_agent *agent, size_t *len)
        return secparams;
 }
 
+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)
@@ -162,12 +220,15 @@ usm_parseparams(struct snmp_agent *agent, char *packet, 
size_t packetlen,
        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);
@@ -175,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) {
@@ -226,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,20 +312,63 @@ fail:
        return -1;
 }
 
+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);
@@ -257,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;
 }
 
@@ -274,3 +406,81 @@ 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 > 64 ? EVP_MAX_MD_SIZE : 64];
+       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/usm.h b/usm.h
index 1def439..636cd0e 100644
--- a/usm.h
+++ b/usm.h
@@ -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);

Reply via email to