On 6/7/19 9:50 AM, Martijn van Duren wrote: > Hello tech@, > > I managed to get SHA-2 support working for snmpd, based on RFC7860 and > tested with net-snmp commandline tools. > > I split the diff up in 2 steps for readability. > Step 1: Don't assume the digestlength is always 12 bytes. This is only > true for MD5 and SHA-1. > > OK?
ok gerhard@ > > martijn@ > > diff --git a/snmpd.h b/snmpd.h > index 5d5adfd..0f7cf70 100644 > --- a/snmpd.h > +++ b/snmpd.h > @@ -59,7 +59,7 @@ > #define SNMPD_MAXUSERNAMELEN 32 > #define SNMPD_MAXCONTEXNAMELEN 32 > > -#define SNMP_USM_DIGESTLEN 12 > +#define SNMP_USM_MAXDIGESTLEN 12 > #define SNMP_USM_SALTLEN 8 > #define SNMP_USM_KEYLEN 64 > #define SNMP_CIPHER_KEYLEN 16 > diff --git a/usm.c b/usm.c > index 811235c..80229f3 100644 > --- a/usm.c > +++ b/usm.c > @@ -45,7 +45,9 @@ > SLIST_HEAD(, usmuser) usmuserlist; > > const EVP_MD *usm_get_md(enum usmauth); > +size_t usm_get_digestlen(enum usmauth); > const EVP_CIPHER *usm_get_cipher(enum usmpriv); > +int usm_valid_digestlen(size_t digestlen); > void usm_cb_digest(void *, size_t); > int usm_valid_digest(struct snmp_message *, off_t, char *, > size_t); > @@ -101,6 +103,19 @@ usm_get_md(enum usmauth ua) > } > } > > +size_t > +usm_get_digestlen(enum usmauth ua) > +{ > + switch (ua) { > + case AUTH_MD5: > + case AUTH_SHA1: > + return 12; > + case AUTH_NONE: > + default: > + return 0; > + } > +} > + > const EVP_CIPHER * > usm_get_cipher(enum usmpriv up) > { > @@ -115,6 +130,18 @@ usm_get_cipher(enum usmpriv up) > } > } > > +int > +usm_valid_digestlen(size_t digestlen) > +{ > + switch (digestlen) { > + case 0: > + case 12: > + return 1; > + default: > + return 0; > + } > +} > + > struct usmuser * > usm_newuser(char *name, const char **errp) > { > @@ -257,7 +284,7 @@ usm_decode(struct snmp_message *msg, struct ber_element > *elm, const char **errp) > > if (enginelen > SNMPD_MAXENGINEIDLEN || > userlen > SNMPD_MAXUSERNAMELEN || > - (digestlen != (MSG_HAS_AUTH(msg) ? SNMP_USM_DIGESTLEN : 0)) || > + !usm_valid_digestlen(digestlen) || > (saltlen != (MSG_HAS_PRIV(msg) ? SNMP_USM_SALTLEN : 0))) { > *errp = "bad field length"; > msg->sm_flags &= SNMP_MSGFLAG_REPORT; > @@ -343,7 +370,7 @@ usm_encode(struct snmp_message *msg, struct ber_element > *e) > struct ber ber; > struct ber_element *usm, *a, *res = NULL; > void *ptr; > - char digest[SNMP_USM_DIGESTLEN]; > + char digest[SNMP_USM_MAXDIGESTLEN]; > size_t digestlen, saltlen; > ssize_t len; > > @@ -362,7 +389,7 @@ usm_encode(struct snmp_message *msg, struct ber_element > *e) > assert(msg->sm_user != NULL); > #endif > bzero(digest, sizeof(digest)); > - digestlen = sizeof(digest); > + digestlen = usm_get_digestlen(msg->sm_user->uu_auth); > } else > digestlen = 0; > > @@ -456,6 +483,7 @@ usm_finalize_digest(struct snmp_message *msg, char *buf, > ssize_t len) > { > const EVP_MD *md; > u_char digest[EVP_MAX_MD_SIZE]; > + size_t digestlen; > unsigned hlen; > > if (msg->sm_resp == NULL || > @@ -464,10 +492,13 @@ usm_finalize_digest(struct snmp_message *msg, char > *buf, ssize_t len) > msg->sm_digest_offs == 0 || > len <= 0) > return; > - bzero(digest, SNMP_USM_DIGESTLEN); > + > + if ((digestlen = usm_get_digestlen(msg->sm_user->uu_auth)) == 0) > + return; > + bzero(digest, digestlen); > #ifdef DEBUG > - assert(msg->sm_digest_offs + SNMP_USM_DIGESTLEN <= (size_t)len); > - assert(!memcmp(buf + msg->sm_digest_offs, digest, SNMP_USM_DIGESTLEN)); > + assert(msg->sm_digest_offs + digestlen <= (size_t)len); > + assert(!memcmp(buf + msg->sm_digest_offs, digest, digestlen)); > #endif > > if ((md = usm_get_md(msg->sm_user->uu_auth)) == NULL) > @@ -476,7 +507,7 @@ usm_finalize_digest(struct snmp_message *msg, char *buf, > ssize_t len) > HMAC(md, msg->sm_user->uu_authkey, (int)msg->sm_user->uu_authkeylen, > (u_char*)buf, (size_t)len, digest, &hlen); > > - memcpy(buf + msg->sm_digest_offs, digest, SNMP_USM_DIGESTLEN); > + memcpy(buf + msg->sm_digest_offs, digest, digestlen); > return; > } > > @@ -506,7 +537,7 @@ usm_valid_digest(struct snmp_message *msg, off_t offs, > if (!MSG_HAS_AUTH(msg)) > return 1; > > - if (digestlen != SNMP_USM_DIGESTLEN) > + if (digestlen != usm_get_digestlen(msg->sm_user->uu_auth)) > return 0; > > #ifdef DEBUG >