/* * Determine transform type. */ c = malloc(sizeof(HMAC_CTX)); if (c == NULL) return (SNMPERR_GENERR); if (ISTRANSFORM(hashtype, HMACMD5Auth)) { EVP_DigestInit(&c->md_ctx, (const EVP_MD *) EVP_md5()); } else if (ISTRANSFORM(hashtype, HMACSHA1Auth)) { EVP_DigestInit(&c->md_ctx, (const EVP_MD *) EVP_sha1()); } else { return(SNMPERR_GENERR); } EVP_DigestUpdate(&c->md_ctx, buf, buf_len); EVP_DigestFinal(&(c->md_ctx), MAC, MAC_len); free(c); return (rval); #else /* USE_INTERNAL_MD5 */ if (MDchecksum(buf, buf_len, MAC, *MAC_len)) { return SNMPERR_GENERR; } if (*MAC_len > 16) *MAC_len = 16; return SNMPERR_SUCCESS; #endif /* USE_OPENSSL */ } #else /* !defined(USE_OPENSSL) && !defined(USE_INTERNAL_MD5) */ _SCAPI_NOT_CONFIGURED #endif /* !defined(USE_OPENSSL) && !defined(USE_INTERNAL_MD5) */ /*******************************************************************-o-****** * sc_check_keyed_hash * * Parameters: * authtype Transform type of authentication hash. * *key Key bits in a string of bytes. * keylen Length of key in bytes. * *message Message for which to check the hash. * msglen Length of message. * *MAC Given hash. * maclen Length of given hash; indicates truncation if it is * shorter than the normal size of output for * given hash transform. * Returns: * SNMPERR_SUCCESS Success. * SNMP_SC_GENERAL_FAILURE Any error * * * Check the hash given in MAC against the hash of message. If the length * of MAC is less than the length of the transform hash output, only maclen * bytes are compared. The length of MAC cannot be greater than the * length of the hash transform output. */ int sc_check_keyed_hash( oid *authtype, size_t authtypelen, u_char *key, u_int keylen, u_char *message, u_int msglen, u_char *MAC, u_int maclen) #if defined(USE_INTERNAL_MD5) || defined(USE_OPENSSL) { int rval = SNMPERR_SUCCESS; size_t buf_len = SNMP_MAXBUF_SMALL; u_char buf[SNMP_MAXBUF_SMALL]; DEBUGTRACE; #ifdef SNMP_TESTING_CODE { int i; DEBUGMSG(("scapi", "sc_check_keyed_hash(): key=0x")); for(i=0; i< keylen; i++) DEBUGMSG(("scapi", "%02x", key[i] & 0xff)); DEBUGMSG(("scapi"," (%d)\n", keylen)); } #endif /* SNMP_TESTING_CODE */ /* * Sanity check. */ if ( !authtype || !key || !message || !MAC || (keylen<=0) || (msglen<=0) || (maclen<=0) || (authtypelen != USM_LENGTH_OID_TRANSFORM) ) { QUITFUN(SNMPERR_GENERR, sc_check_keyed_hash_quit); } /* * Generate a full hash of the message, then compare * the result with the given MAC which may shorter than * the full hash length. */ rval = sc_generate_keyed_hash( authtype, authtypelen, key, keylen, message, msglen, buf, &buf_len); QUITFUN(rval, sc_check_keyed_hash_quit); if (maclen > msglen) { QUITFUN(SNMPERR_GENERR, sc_check_keyed_hash_quit); } else if ( memcmp(buf, MAC, maclen) != 0 ) { QUITFUN(SNMPERR_GENERR, sc_check_keyed_hash_quit); } sc_check_keyed_hash_quit: SNMP_ZERO(buf, SNMP_MAXBUF_SMALL); return rval; } /* end sc_check_keyed_hash() */
/*******************************************************************-o-****** * test_dokeyedhash * * Returns: * Number of failures. * * * Test keyed hashes with a variety of MAC length requests. * * * NOTE Both tests intentionally use the same secret * * FIX Get input or output from some other package which hashes... * XXX Could cut this in half with a little indirection... */ int test_dokeyedhash(void) { int rval = SNMPERR_SUCCESS, failcount = 0, bigstring_len = strlen(BIGSTRING), secret_len = strlen(BIGSECRET), properlength, mlcount = 0, /* MAC Length count. */ hblen; /* Hash Buffer length. */ u_int hashbuf_len[MLCOUNT_MAX] = { LOCAL_MAXBUF, BYTESIZE(SNMP_TRANS_AUTHLEN_HMACSHA1), BYTESIZE(SNMP_TRANS_AUTHLEN_HMACMD5), BYTESIZE(SNMP_TRANS_AUTHLEN_HMAC96), 7, 0, }; u_char hashbuf[LOCAL_MAXBUF]; char *s; test_dokeyedhash_again: OUTPUT("Keyed hash test using MD5 --"); memset(hashbuf, 0, LOCAL_MAXBUF); hblen = hashbuf_len[mlcount]; properlength = BYTESIZE(SNMP_TRANS_AUTHLEN_HMACMD5); rval = sc_generate_keyed_hash(usmHMACMD5AuthProtocol, USM_LENGTH_OID_TRANSFORM, BIGSECRET, secret_len, BIGSTRING, bigstring_len, hashbuf, &hblen); FAILED(rval, "sc_generate_keyed_hash()."); if (hashbuf_len[mlcount] > properlength) { if (hblen != properlength) { FAILED(SNMPERR_GENERR, "Wrong MD5 hash length returned. (1)"); } } else if (hblen != hashbuf_len[mlcount]) { FAILED(SNMPERR_GENERR, "Wrong MD5 hash length returned. (2)"); } rval = sc_check_keyed_hash(usmHMACMD5AuthProtocol, USM_LENGTH_OID_TRANSFORM, BIGSECRET, secret_len, BIGSTRING, bigstring_len, hashbuf, hblen); FAILED(rval, "sc_check_keyed_hash()."); binary_to_hex(hashbuf, hblen, &s); fprintf(stdout, "hash buffer (len=%d, request=%d): %s\n", hblen, hashbuf_len[mlcount], s); SNMP_FREE(s); SUCCESS("Keyed hash test using MD5."); OUTPUT("Keyed hash test using SHA1 --"); memset(hashbuf, 0, LOCAL_MAXBUF); hblen = hashbuf_len[mlcount]; properlength = BYTESIZE(SNMP_TRANS_AUTHLEN_HMACSHA1); rval = sc_generate_keyed_hash(usmHMACSHA1AuthProtocol, USM_LENGTH_OID_TRANSFORM, BIGSECRET, secret_len, BIGSTRING, bigstring_len, hashbuf, &hblen); FAILED(rval, "sc_generate_keyed_hash()."); if (hashbuf_len[mlcount] > properlength) { if (hblen != properlength) { FAILED(SNMPERR_GENERR, "Wrong SHA1 hash length returned. (1)"); } } else if (hblen != hashbuf_len[mlcount]) { FAILED(SNMPERR_GENERR, "Wrong SHA1 hash length returned. (2)"); } rval = sc_check_keyed_hash(usmHMACSHA1AuthProtocol, USM_LENGTH_OID_TRANSFORM, BIGSECRET, secret_len, BIGSTRING, bigstring_len, hashbuf, hblen); FAILED(rval, "sc_check_keyed_hash()."); binary_to_hex(hashbuf, hblen, &s); fprintf(stdout, "hash buffer (len=%d, request=%d): %s\n", hblen, hashbuf_len[mlcount], s); SNMP_FREE(s); SUCCESS("Keyed hash test using SHA1."); /* * Run the basic hash tests but vary the size MAC requests. */ if (hashbuf_len[++mlcount] != 0) { goto test_dokeyedhash_again; } return failcount; } /* end test_dokeyedhash() */