In copying over the net-snmp semantics for snmp-v3/USM I got a bit too
lenient in handling the keys. This diff tries to rectify that.

This diff does basically two things:
1) Try to push people to use passphrases from stdin.
2) Clean up keying material (including from the ps listing) as soon as
   possible,

$ ./snmp get -v3 -u test -l authPriv -a SHA -x AES 127.0.0.1 \
> sysServices.0 < /home/martijn/.snmp/localhost
sysServices.0 = INTEGER: 74

OK?

martijn@

Index: snmpc.c
===================================================================
RCS file: /cvs/src/usr.bin/snmp/snmpc.c,v
retrieving revision 1.17
diff -u -p -r1.17 snmpc.c
--- snmpc.c     26 Oct 2019 19:34:15 -0000      1.17
+++ snmpc.c     30 Oct 2019 05:40:53 -0000
@@ -31,6 +31,7 @@
 #include <errno.h>
 #include <netdb.h>
 #include <poll.h>
+#include <readpassphrase.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdint.h>
@@ -122,9 +123,19 @@ main(int argc, char *argv[])
        char *strtolp;
        int ch;
        size_t i;
+       char passphrase[128];
+       int pwdflags = 0;
 
-       if (pledge("stdio inet dns", NULL) == -1)
-               err(1, "pledge");
+       if (isatty(STDIN_FILENO)) {
+               if (unveil("/dev/tty", "rw") == -1)
+                       err(1, "unveil");
+               if (pledge("stdio inet dns rpath wpath tty", NULL) == -1)
+                       err(1, "pledge");
+       } else {
+               if (pledge("stdio inet dns", NULL) == -1)
+                       err(1, "pledge");
+               pwdflags = RPP_STDIN;
+       }
 
        if (argc <= 1)
                usage();
@@ -161,6 +172,7 @@ main(int argc, char *argv[])
                        authkey = optarg;
                        authkeylen = strlen(authkey);
                        authkeylevel = USM_KEY_PASSWORD;
+                       warnx("Use of -A is deprecated");
                        break;
                case 'a':
                        if (strcasecmp(optarg, "MD5") == 0)
@@ -211,7 +223,8 @@ main(int argc, char *argv[])
                                errx(1, "-3K");
                        }
                        privkeylevel = USM_KEY_LOCALIZED;
-                               break;
+                       warnx("Use of -K is deprecated");
+                       break;
                case 'k':
                        authkey = snmpc_hex2bin(optarg, &authkeylen);
                        if (authkey == NULL) {
@@ -220,6 +233,7 @@ main(int argc, char *argv[])
                                err(1, "-k");
                        }
                        authkeylevel = USM_KEY_LOCALIZED;
+                       warnx("Use of -k is deprecated");
                        break;
                case 'l':
                        if (strcasecmp(optarg, "noAuthNoPriv") == 0)
@@ -395,6 +409,7 @@ main(int argc, char *argv[])
                        privkey = optarg;
                        privkeylen = strlen(privkey);
                        privkeylevel = USM_KEY_PASSWORD;
+                       warnx("Use of -X is deprecated");
                        break;
                case 'x':
                        if (strcasecmp(optarg, "DES") == 0)
@@ -434,20 +449,38 @@ main(int argc, char *argv[])
                if (seclevel & SNMP_MSGFLAG_AUTH) {
                        if (md == NULL)
                                md = EVP_md5();
-                       if (authkey == NULL)
-                               errx(1, "No authKey or authPassword specified");
+                       if (authkey == NULL) {
+                               if ((authkey = readpassphrase("\rAuthpass: ",
+                                   passphrase, sizeof(passphrase),
+                                   pwdflags)) == NULL)
+                                       err(1, "Couldn't read Authpass");
+                               authkeylen = strlen(authkey);
+                               authkeylevel = USM_KEY_PASSWORD;
+                       }
                        if (usm_setauth(sec, md, authkey, authkeylen,
-                           authkeylevel) == -1)
+                           authkeylevel) == -1) {
+                               explicit_bzero(authkey, authkeylen);
                                err(1, "Can't set authkey");
+                       }
+                       explicit_bzero(authkey, authkeylen);
                }
                if (seclevel & SNMP_MSGFLAG_PRIV) {
                        if (cipher == NULL)
                                cipher = EVP_des_cbc();
-                       if (privkey == NULL)
-                               errx(1, "No privKey or privPassword specified");
+                       if (privkey == NULL) {
+                               if ((privkey = readpassphrase("\rPrivpass: ",
+                                   passphrase, sizeof(passphrase),
+                                   pwdflags)) == NULL)
+                                       err(1, "Couldn't read passphrase");
+                               privkeylen = strlen(privkey);
+                               privkeylevel = USM_KEY_PASSWORD;
+                       }
                        if (usm_setpriv(sec, cipher, privkey, privkeylen,
-                           privkeylevel) == -1)
+                           privkeylevel) == -1) {
+                               explicit_bzero(privkey, privkeylen);
                                err(1, "Can't set authkey");
+                       }
+                       explicit_bzero(privkey, privkeylen);
                }
                if (secengineid != NULL) {
                        if (usm_setengineid(sec, secengineid,
Index: usm.c
===================================================================
RCS file: /cvs/src/usr.bin/snmp/usm.c,v
retrieving revision 1.5
diff -u -p -r1.5 usm.c
--- usm.c       24 Oct 2019 12:39:26 -0000      1.5
+++ usm.c       30 Oct 2019 05:40:53 -0000
@@ -44,9 +44,11 @@ struct usm_sec {
        enum usm_key_level authlevel;
        const EVP_MD *digest;
        char *authkey;
+       size_t authkeylen;
        enum usm_key_level privlevel;
        const EVP_CIPHER *cipher;
        char *privkey;
+       size_t privkeylen;
        int bootsset;
        uint32_t boots;
        int timeset;
@@ -319,7 +321,7 @@ usm_finalparams(struct snmp_agent *agent
        if (usm->authlevel != USM_KEY_LOCALIZED)
                return -1;
 
-       if (HMAC(usm->digest, usm->authkey, EVP_MD_size(usm->digest), buf,
+       if (HMAC(usm->digest, usm->authkey, usm->authkeylen, buf,
            buflen, digest, NULL) == NULL)
                return -1;
 
@@ -427,7 +429,7 @@ usm_parseparams(struct snmp_agent *agent
        }
        if ((agent->v3->level & SNMP_MSGFLAG_AUTH)) {
                bzero(packet + secparamsoffset + digestoffset, digestlen);
-               if (HMAC(usm->digest, usm->authkey, EVP_MD_size(usm->digest), 
packet,
+               if (HMAC(usm->digest, usm->authkey, usm->authkeylen, packet,
                    packetlen, exp_digest, NULL) == NULL)
                        goto fail;
 
@@ -484,7 +486,9 @@ usm_free(void *data)
        struct usm_sec *usm = data;
 
        free(usm->user);
+       explicit_bzero(usm->authkey, usm->authkeylen);
        free(usm->authkey);
+       explicit_bzero(usm->privkey, usm->privkeylen);
        free(usm->privkey);
        free(usm->engineid);
        free(usm);
@@ -507,7 +511,7 @@ usm_setauth(struct snmp_sec *sec, const 
                if ((usm->authkey = usm_passwd2mkey(digest, key)) == NULL)
                        return -1;
                level = USM_KEY_MASTER;
-               keylen = EVP_MD_size(digest);
+               usm->authkeylen = EVP_MD_size(digest);
        } else {
                if (keylen != (size_t)EVP_MD_size(digest)) {
                        errno = EINVAL;
@@ -517,6 +521,7 @@ usm_setauth(struct snmp_sec *sec, const 
                        return -1;
                memcpy(lkey, key, keylen);
                usm->authkey = lkey;
+               usm->authkeylen = keylen;
        }
        usm->digest = digest;
        usm->authlevel = level;
@@ -544,7 +549,7 @@ usm_setpriv(struct snmp_sec *sec, const 
                if ((usm->privkey = usm_passwd2mkey(usm->digest, key)) == NULL)
                        return -1;
                level = USM_KEY_MASTER;
-               keylen = EVP_MD_size(usm->digest);
+               usm->privkeylen = EVP_MD_size(usm->digest);
        } else {
                if (keylen != (size_t)EVP_MD_size(usm->digest)) {
                        errno = EINVAL;
@@ -554,6 +559,7 @@ usm_setpriv(struct snmp_sec *sec, const 
                        return -1;
                memcpy(lkey, key, keylen);
                usm->privkey = lkey;
+               usm->privkeylen = keylen;
        }
        usm->cipher = cipher;
        usm->privlevel = level;
@@ -581,7 +587,9 @@ usm_setengineid(struct snmp_sec *sec, ch
                        usm->authkey = mkey;
                        return -1;
                }
+               explicit_bzero(mkey, usm->authkeylen);
                free(mkey);
+               usm->authkeylen = EVP_MD_size(usm->digest);
                usm->authlevel = USM_KEY_LOCALIZED;
        }
        if (usm->privlevel == USM_KEY_MASTER) {
@@ -591,7 +599,9 @@ usm_setengineid(struct snmp_sec *sec, ch
                        usm->privkey = mkey;
                        return -1;
                }
+               explicit_bzero(mkey, usm->privkeylen);
                free(mkey);
+               usm->privkeylen = EVP_MD_size(usm->digest);
                usm->privlevel = USM_KEY_LOCALIZED;
        }
 

Reply via email to