/*******************************************************************-o-****** * generate_Ku * * Parameters: * *hashtype MIB OID for the transform type for hashing. * hashtype_len Length of OID value. * *P Pre-allocated bytes of passpharase. * pplen Length of passphrase. * *Ku Buffer to contain Ku. * *kulen Length of Ku buffer. * * Returns: * SNMPERR_SUCCESS Success. * SNMPERR_GENERR All errors. * * * Convert a passphrase into a master user key, Ku, according to the * algorithm given in RFC 2274 concerning the SNMPv3 User Security Model (USM) * as follows: * * Expand the passphrase to fill the passphrase buffer space, if necessary, * concatenation as many duplicates as possible of P to itself. If P is * larger than the buffer space, truncate it to fit. * * Then hash the result with the given hashtype transform. Return * the result as Ku. * * If successful, kulen contains the size of the hash written to Ku. * * NOTE Passphrases less than USM_LENGTH_P_MIN characters in length * cause an error to be returned. * (Punt this check to the cmdline apps? XXX) */ int generate_Ku(const oid * hashtype, u_int hashtype_len, const u_char * P, size_t pplen, u_char * Ku, size_t * kulen) #if defined(NETSNMP_USE_INTERNAL_MD5) || defined(NETSNMP_USE_OPENSSL) || defined(NETSNMP_USE_INTERNAL_CRYPTO) { int rval = SNMPERR_SUCCESS, nbytes = USM_LENGTH_EXPANDED_PASSPHRASE; #if !defined(NETSNMP_USE_OPENSSL) && \ defined(NETSNMP_USE_INTERNAL_MD5) || defined(NETSNMP_USE_INTERNAL_CRYPTO) int ret; #endif u_int i, pindex = 0; u_char buf[USM_LENGTH_KU_HASHBLOCK], *bufp; #ifdef NETSNMP_USE_OPENSSL EVP_MD_CTX *ctx = NULL; #elif NETSNMP_USE_INTERNAL_CRYPTO SHA_CTX csha1; MD5_CTX cmd5; char cryptotype = 0; #define TYPE_MD5 1 #define TYPE_SHA1 2 #else MDstruct MD; #endif /* * Sanity check. */ if (!hashtype || !P || !Ku || !kulen || (*kulen <= 0) || (hashtype_len != USM_LENGTH_OID_TRANSFORM)) { QUITFUN(SNMPERR_GENERR, generate_Ku_quit); } if (pplen < USM_LENGTH_P_MIN) { snmp_log(LOG_ERR, "Error: passphrase chosen is below the length " "requirements of the USM (min=%d).\n",USM_LENGTH_P_MIN); snmp_set_detail("The supplied password length is too short."); QUITFUN(SNMPERR_GENERR, generate_Ku_quit); } /* * Setup for the transform type. */ #ifdef NETSNMP_USE_OPENSSL #ifdef HAVE_EVP_MD_CTX_CREATE ctx = EVP_MD_CTX_create(); #else ctx = malloc(sizeof(*ctx)); EVP_MD_CTX_init(ctx); #endif #ifndef NETSNMP_DISABLE_MD5 if (ISTRANSFORM(hashtype, HMACMD5Auth)) EVP_DigestInit(ctx, EVP_md5()); else #endif if (ISTRANSFORM(hashtype, HMACSHA1Auth)) EVP_DigestInit(ctx, EVP_sha1()); else QUITFUN(SNMPERR_GENERR, generate_Ku_quit); #elif NETSNMP_USE_INTERNAL_CRYPTO #ifndef NETSNMP_DISABLE_MD5 if (ISTRANSFORM(hashtype, HMACMD5Auth)) { MD5_Init(&cmd5); cryptotype = TYPE_MD5; } else #endif if (ISTRANSFORM(hashtype, HMACSHA1Auth)) { SHA1_Init(&csha1); cryptotype = TYPE_SHA1; } else { return (SNMPERR_GENERR); } #else MDbegin(&MD); #endif /* NETSNMP_USE_OPENSSL */ while (nbytes > 0) { bufp = buf; for (i = 0; i < USM_LENGTH_KU_HASHBLOCK; i++) { *bufp++ = P[pindex++ % pplen]; } #ifdef NETSNMP_USE_OPENSSL EVP_DigestUpdate(ctx, buf, USM_LENGTH_KU_HASHBLOCK); #elif NETSNMP_USE_INTERNAL_CRYPTO if (TYPE_SHA1 == cryptotype) { rval = !SHA1_Update(&csha1, buf, USM_LENGTH_KU_HASHBLOCK); } else { rval = !MD5_Update(&cmd5, buf, USM_LENGTH_KU_HASHBLOCK); } if (rval != 0) { return SNMPERR_USM_ENCRYPTIONERROR; } #elif NETSNMP_USE_INTERNAL_MD5 if (MDupdate(&MD, buf, USM_LENGTH_KU_HASHBLOCK * 8)) { rval = SNMPERR_USM_ENCRYPTIONERROR; goto md5_fin; } #endif /* NETSNMP_USE_OPENSSL */ nbytes -= USM_LENGTH_KU_HASHBLOCK; } #ifdef NETSNMP_USE_OPENSSL { unsigned int tmp_len; tmp_len = *kulen; EVP_DigestFinal(ctx, (unsigned char *) Ku, &tmp_len); *kulen = tmp_len; /* * what about free() */ } #elif NETSNMP_USE_INTERNAL_CRYPTO if (TYPE_SHA1 == cryptotype) { SHA1_Final(Ku, &csha1); } else { MD5_Final(Ku, &cmd5); } ret = sc_get_properlength(hashtype, hashtype_len); if (ret == SNMPERR_GENERR) return SNMPERR_GENERR; *kulen = ret; #elif NETSNMP_USE_INTERNAL_MD5 if (MDupdate(&MD, buf, 0)) { rval = SNMPERR_USM_ENCRYPTIONERROR; goto md5_fin; } ret = sc_get_properlength(hashtype, hashtype_len); if (ret == SNMPERR_GENERR) return SNMPERR_GENERR; *kulen = ret; MDget(&MD, Ku, *kulen); md5_fin: memset(&MD, 0, sizeof(MD)); #endif /* NETSNMP_USE_INTERNAL_MD5 */ #ifdef NETSNMP_ENABLE_TESTING_CODE DEBUGMSGTL(("generate_Ku", "generating Ku (from %s): ", P)); for (i = 0; i < *kulen; i++) DEBUGMSG(("generate_Ku", "%02x", Ku[i])); DEBUGMSG(("generate_Ku", "\n")); #endif /* NETSNMP_ENABLE_TESTING_CODE */ generate_Ku_quit: memset(buf, 0, sizeof(buf)); #ifdef NETSNMP_USE_OPENSSL if (ctx) { #ifdef HAVE_EVP_MD_CTX_DESTROY EVP_MD_CTX_destroy(ctx); #else EVP_MD_CTX_cleanup(ctx); free(ctx); #endif } #endif return rval; } /* end generate_Ku() */
/*******************************************************************-o-****** * generate_Ku * * Parameters: * *hashtype MIB OID for the transform type for hashing. * hashtype_len Length of OID value. * *P Pre-allocated bytes of passpharase. * pplen Length of passphrase. * *Ku Buffer to contain Ku. * *kulen Length of Ku buffer. * * Returns: * SNMPERR_SUCCESS Success. * SNMPERR_GENERR All errors. * * * Convert a passphrase into a master user key, Ku, according to the * algorithm given in RFC 2274 concerning the SNMPv3 User Security Model (USM) * as follows: * * Expand the passphrase to fill the passphrase buffer space, if necessary, * concatenation as many duplicates as possible of P to itself. If P is * larger than the buffer space, truncate it to fit. * * Then hash the result with the given hashtype transform. Return * the result as Ku. * * If successful, kulen contains the size of the hash written to Ku. * * NOTE Passphrases less than USM_LENGTH_P_MIN characters in length * cause an error to be returned. * (Punt this check to the cmdline apps? XXX) */ int generate_Ku( oid *hashtype, u_int hashtype_len, u_char *P, size_t pplen, u_char *Ku, size_t *kulen) #if defined(USE_INTERNAL_MD5) || defined(USE_OPENSSL) { int rval = SNMPERR_SUCCESS, nbytes = USM_LENGTH_EXPANDED_PASSPHRASE; u_int i, pindex = 0; u_char buf[USM_LENGTH_KU_HASHBLOCK], *bufp; #ifdef USE_OPENSSL EVP_MD_CTX *ctx = malloc(sizeof(EVP_MD_CTX)); #else MDstruct MD; #endif /* * Sanity check. */ if ( !hashtype || !P || !Ku || !kulen || (*kulen<=0) || (hashtype_len != USM_LENGTH_OID_TRANSFORM) ) { QUITFUN(SNMPERR_GENERR, generate_Ku_quit); } if (pplen < USM_LENGTH_P_MIN) { #ifdef SNMP_TESTING_CODE snmp_log(LOG_WARNING, "Warning: passphrase chosen is below the length requiremnts of the USM.\n"); #else snmp_set_detail("Password length too short."); QUITFUN(SNMPERR_GENERR, generate_Ku_quit); #endif } /* * Setup for the transform type. */ #ifdef USE_OPENSSL if (ISTRANSFORM(hashtype, HMACMD5Auth)) EVP_DigestInit(ctx, EVP_md5()); else if (ISTRANSFORM(hashtype, HMACSHA1Auth)) EVP_DigestInit(ctx, EVP_sha1()); else { free(ctx); return (SNMPERR_GENERR); } #else MDbegin(&MD); #endif /* USE_OPENSSL */ while (nbytes > 0) { bufp = buf; for (i = 0; i < USM_LENGTH_KU_HASHBLOCK; i++) { *bufp++ = P[pindex++ % pplen]; } #ifdef USE_OPENSSL EVP_DigestUpdate(ctx, buf, USM_LENGTH_KU_HASHBLOCK); #else if (MDupdate(&MD, buf, USM_LENGTH_KU_HASHBLOCK*8)) { rval = SNMPERR_USM_ENCRYPTIONERROR; goto md5_fin; } #endif /* USE_OPENSSL */ nbytes -= USM_LENGTH_KU_HASHBLOCK; } #ifdef USE_OPENSSL EVP_DigestFinal(ctx, (unsigned char *) Ku, (unsigned int *) kulen); /* what about free() */ #else if (MDupdate(&MD, buf, 0)) { rval = SNMPERR_USM_ENCRYPTIONERROR; goto md5_fin; } *kulen = sc_get_properlength(hashtype, hashtype_len); MDget(&MD, Ku, *kulen); md5_fin: memset(&MD, 0, sizeof(MD)); #endif /* USE_OPENSSL */ #ifdef SNMP_TESTING_CODE DEBUGMSGTL(("generate_Ku", "generating Ku (from %s): ", P)); for(i=0; i < *kulen; i++) DEBUGMSG(("generate_Ku", "%02x",Ku[i])); DEBUGMSG(("generate_Ku","\n")); #endif /* SNMP_TESTING_CODE */ generate_Ku_quit: memset(buf, 0, sizeof(buf)); #ifdef USE_OPENSSL free(ctx); #endif return rval; } /* end generate_Ku() */