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
> 

Reply via email to