diff --git a/doc/dox_comments/header_files/ssl.h b/doc/dox_comments/header_files/ssl.h index c0a88c101..1d6227da7 100644 --- a/doc/dox_comments/header_files/ssl.h +++ b/doc/dox_comments/header_files/ssl.h @@ -6738,7 +6738,7 @@ WOLFSSL_API int wolfSSL_SetMinEccKey_Sz(WOLFSSL*, short); of the p_hash function. \param len an unsigned integer that represents the length of the msk variable. - \param label a constant char pointer that is copied from in PRF(). + \param label a constant char pointer that is copied from in wc_PRF(). _Example_ \code @@ -6750,9 +6750,7 @@ WOLFSSL_API int wolfSSL_SetMinEccKey_Sz(WOLFSSL*, short); return wolfSSL_make_eap_keys(ssl, msk, len, label); \endcode - \sa PRF - \sa doPRF - \sa p_hash + \sa wc_PRF \sa wc_HmacFinal \sa wc_HmacUpdate */ @@ -11085,7 +11083,7 @@ WOLFSSL_API int wolfSSL_get_session_stats(unsigned int* active, \ingroup TLS \brief This function copies the values of cr and sr then passes through to - PRF (pseudo random function) and returns that value. + wc_PRF (pseudo random function) and returns that value. \return 0 on success \return BUFFER_E returned if there will be an error @@ -11121,9 +11119,7 @@ WOLFSSL_API int wolfSSL_get_session_stats(unsigned int* active, } \endcode - \sa PRF - \sadoPRF - \sa p_hash + \sa wc_PRF \sa MakeTlsMasterSecret */ WOLFSSL_API @@ -11143,7 +11139,7 @@ int wolfSSL_MakeTlsMasterSecret(unsigned char* ms, unsigned int msLen, \return MEMORY_E returned if the allocation of memory failed. \param key_data a byte pointer that is allocateded in DeriveTlsKeys - and passed through to PRF to hold the final hash. + and passed through to wc_PRF to hold the final hash. \param keyLen a word32 type that is derived in DeriveTlsKeys from the WOLFSSL structure’s specs member. \param ms a constant pointer type holding the master secret @@ -11169,8 +11165,7 @@ int wolfSSL_MakeTlsMasterSecret(unsigned char* ms, unsigned int msLen, } \endcode - \sa PRF - \sa doPRF + \sa wc_PRF \sa DeriveTlsKeys \sa IsAtLeastTLSv1_2 */ diff --git a/src/internal.c b/src/internal.c index 43f7b2eab..6a231e306 100644 --- a/src/internal.c +++ b/src/internal.c @@ -15775,6 +15775,9 @@ const char* wolfSSL_ERR_reason_error_string(unsigned long e) case UNSUPPORTED_EXTENSION: return "TLS Extension not requested by the client"; + case PRF_MISSING: + return "Pseudo-random function is not enabled"; + case KEY_SHARE_ERROR: return "Key share extension did not contain a valid named group"; diff --git a/src/tls.c b/src/tls.c index 98b03b880..8b7ee4ddc 100644 --- a/src/tls.c +++ b/src/tls.c @@ -108,291 +108,6 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions); #ifndef WOLFSSL_NO_TLS12 -#ifdef WOLFSSL_SHA384 - #define P_HASH_MAX_SIZE WC_SHA384_DIGEST_SIZE -#else - #define P_HASH_MAX_SIZE WC_SHA256_DIGEST_SIZE -#endif - -/* compute p_hash for MD5, SHA-1, SHA-256, or SHA-384 for TLSv1 PRF */ -static int p_hash(byte* result, word32 resLen, const byte* secret, - word32 secLen, const byte* seed, word32 seedLen, int hash, - void* heap, int devId) -{ - word32 len = P_HASH_MAX_SIZE; - word32 times; - word32 lastLen; - word32 lastTime; - word32 i; - word32 idx = 0; - int ret = 0; -#ifdef WOLFSSL_SMALL_STACK - byte* previous; - byte* current; - Hmac* hmac; -#else - byte previous[P_HASH_MAX_SIZE]; /* max size */ - byte current[P_HASH_MAX_SIZE]; /* max size */ - Hmac hmac[1]; -#endif - -#ifdef WOLFSSL_SMALL_STACK - previous = (byte*)XMALLOC(P_HASH_MAX_SIZE, heap, DYNAMIC_TYPE_DIGEST); - current = (byte*)XMALLOC(P_HASH_MAX_SIZE, heap, DYNAMIC_TYPE_DIGEST); - hmac = (Hmac*)XMALLOC(sizeof(Hmac), heap, DYNAMIC_TYPE_HMAC); - - if (previous == NULL || current == NULL || hmac == NULL) { - if (previous) XFREE(previous, heap, DYNAMIC_TYPE_DIGEST); - if (current) XFREE(current, heap, DYNAMIC_TYPE_DIGEST); - if (hmac) XFREE(hmac, heap, DYNAMIC_TYPE_HMAC); - - return MEMORY_E; - } -#endif - - switch (hash) { - #ifndef NO_MD5 - case md5_mac: - hash = WC_MD5; - len = WC_MD5_DIGEST_SIZE; - break; - #endif - - #ifndef NO_SHA256 - case sha256_mac: - hash = WC_SHA256; - len = WC_SHA256_DIGEST_SIZE; - break; - #endif - - #ifdef WOLFSSL_SHA384 - case sha384_mac: - hash = WC_SHA384; - len = WC_SHA384_DIGEST_SIZE; - break; - #endif - - #ifndef NO_SHA - case sha_mac: - default: - hash = WC_SHA; - len = WC_SHA_DIGEST_SIZE; - break; - #endif - } - - times = resLen / len; - lastLen = resLen % len; - - if (lastLen) - times += 1; - - lastTime = times - 1; - - ret = wc_HmacInit(hmac, heap, devId); - if (ret == 0) { - ret = wc_HmacSetKey(hmac, hash, secret, secLen); - if (ret == 0) - ret = wc_HmacUpdate(hmac, seed, seedLen); /* A0 = seed */ - if (ret == 0) - ret = wc_HmacFinal(hmac, previous); /* A1 */ - if (ret == 0) { - for (i = 0; i < times; i++) { - ret = wc_HmacUpdate(hmac, previous, len); - if (ret != 0) - break; - ret = wc_HmacUpdate(hmac, seed, seedLen); - if (ret != 0) - break; - ret = wc_HmacFinal(hmac, current); - if (ret != 0) - break; - - if ((i == lastTime) && lastLen) - XMEMCPY(&result[idx], current, - min(lastLen, P_HASH_MAX_SIZE)); - else { - XMEMCPY(&result[idx], current, len); - idx += len; - ret = wc_HmacUpdate(hmac, previous, len); - if (ret != 0) - break; - ret = wc_HmacFinal(hmac, previous); - if (ret != 0) - break; - } - } - } - wc_HmacFree(hmac); - } - - ForceZero(previous, P_HASH_MAX_SIZE); - ForceZero(current, P_HASH_MAX_SIZE); - ForceZero(hmac, sizeof(Hmac)); - -#ifdef WOLFSSL_SMALL_STACK - XFREE(previous, heap, DYNAMIC_TYPE_DIGEST); - XFREE(current, heap, DYNAMIC_TYPE_DIGEST); - XFREE(hmac, heap, DYNAMIC_TYPE_HMAC); -#endif - - return ret; -} - -#undef P_HASH_MAX_SIZE - -#endif /* !WOLFSSL_NO_TLS12 */ - - -#ifndef NO_OLD_TLS - -/* calculate XOR for TLSv1 PRF */ -static WC_INLINE void get_xor(byte *digest, word32 digLen, byte* md5, byte* sha) -{ - word32 i; - - for (i = 0; i < digLen; i++) - digest[i] = md5[i] ^ sha[i]; -} - - -/* compute TLSv1 PRF (pseudo random function using HMAC) */ -static int doPRF(byte* digest, word32 digLen, const byte* secret,word32 secLen, - const byte* label, word32 labLen, const byte* seed, - word32 seedLen, void* heap, int devId) -{ - int ret = 0; - word32 half = (secLen + 1) / 2; - -#ifdef WOLFSSL_SMALL_STACK - byte* md5_half; - byte* sha_half; - byte* md5_result; - byte* sha_result; -#else - byte md5_half[MAX_PRF_HALF]; /* half is real size */ - byte sha_half[MAX_PRF_HALF]; /* half is real size */ - byte md5_result[MAX_PRF_DIG]; /* digLen is real size */ - byte sha_result[MAX_PRF_DIG]; /* digLen is real size */ -#endif -#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH) - DECLARE_VAR(labelSeed, byte, MAX_PRF_LABSEED, heap); - if (labelSeed == NULL) - return MEMORY_E; -#else - byte labelSeed[MAX_PRF_LABSEED]; -#endif - - if (half > MAX_PRF_HALF || - labLen + seedLen > MAX_PRF_LABSEED || - digLen > MAX_PRF_DIG) - { - #if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH) - FREE_VAR(labelSeed, heap); - #endif - return BUFFER_E; - } - -#ifdef WOLFSSL_SMALL_STACK - md5_half = (byte*)XMALLOC(MAX_PRF_HALF, heap, DYNAMIC_TYPE_DIGEST); - sha_half = (byte*)XMALLOC(MAX_PRF_HALF, heap, DYNAMIC_TYPE_DIGEST); - md5_result = (byte*)XMALLOC(MAX_PRF_DIG, heap, DYNAMIC_TYPE_DIGEST); - sha_result = (byte*)XMALLOC(MAX_PRF_DIG, heap, DYNAMIC_TYPE_DIGEST); - - if (md5_half == NULL || sha_half == NULL || md5_result == NULL || - sha_result == NULL) { - if (md5_half) XFREE(md5_half, heap, DYNAMIC_TYPE_DIGEST); - if (sha_half) XFREE(sha_half, heap, DYNAMIC_TYPE_DIGEST); - if (md5_result) XFREE(md5_result, heap, DYNAMIC_TYPE_DIGEST); - if (sha_result) XFREE(sha_result, heap, DYNAMIC_TYPE_DIGEST); - #if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH) - FREE_VAR(labelSeed, heap); - #endif - - return MEMORY_E; - } -#endif - - XMEMSET(md5_result, 0, digLen); - XMEMSET(sha_result, 0, digLen); - - XMEMCPY(md5_half, secret, half); - XMEMCPY(sha_half, secret + half - secLen % 2, half); - - XMEMCPY(labelSeed, label, labLen); - XMEMCPY(labelSeed + labLen, seed, seedLen); - - if ((ret = p_hash(md5_result, digLen, md5_half, half, labelSeed, - labLen + seedLen, md5_mac, heap, devId)) == 0) { - if ((ret = p_hash(sha_result, digLen, sha_half, half, labelSeed, - labLen + seedLen, sha_mac, heap, devId)) == 0) { - get_xor(digest, digLen, md5_result, sha_result); - } - } - -#ifdef WOLFSSL_SMALL_STACK - XFREE(md5_half, heap, DYNAMIC_TYPE_DIGEST); - XFREE(sha_half, heap, DYNAMIC_TYPE_DIGEST); - XFREE(md5_result, heap, DYNAMIC_TYPE_DIGEST); - XFREE(sha_result, heap, DYNAMIC_TYPE_DIGEST); -#endif - -#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH) - FREE_VAR(labelSeed, heap); -#endif - - return ret; -} - -#endif - - -#ifndef WOLFSSL_NO_TLS12 - -/* Wrapper to call straight thru to p_hash in TSL 1.2 cases to remove stack - use */ -static int PRF(byte* digest, word32 digLen, const byte* secret, word32 secLen, - const byte* label, word32 labLen, const byte* seed, word32 seedLen, - int useAtLeastSha256, int hash_type, void* heap, int devId) -{ - int ret = 0; - - if (useAtLeastSha256) { - #if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH) - DECLARE_VAR(labelSeed, byte, MAX_PRF_LABSEED, heap); - if (labelSeed == NULL) - return MEMORY_E; - #else - byte labelSeed[MAX_PRF_LABSEED]; - #endif - - if (labLen + seedLen > MAX_PRF_LABSEED) - return BUFFER_E; - - XMEMCPY(labelSeed, label, labLen); - XMEMCPY(labelSeed + labLen, seed, seedLen); - - /* If a cipher suite wants an algorithm better than sha256, it - * should use better. */ - if (hash_type < sha256_mac || hash_type == blake2b_mac) - hash_type = sha256_mac; - ret = p_hash(digest, digLen, secret, secLen, labelSeed, - labLen + seedLen, hash_type, heap, devId); - - #if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH) - FREE_VAR(labelSeed, heap); - #endif - } -#ifndef NO_OLD_TLS - else { - ret = doPRF(digest, digLen, secret, secLen, label, labLen, seed, - seedLen, heap, devId); - } -#endif - - return ret; -} - #ifdef WOLFSSL_SHA384 #define HSHASH_SZ WC_SHA384_DIGEST_SIZE #else @@ -459,10 +174,19 @@ int BuildTlsFinished(WOLFSSL* ssl, Hashes* hashes, const byte* sender) else side = tls_server; - ret = PRF((byte*)hashes, TLS_FINISHED_SZ, ssl->arrays->masterSecret, +#ifdef WOLFSSL_HAVE_PRF + ret = wc_PRF_TLS((byte*)hashes, TLS_FINISHED_SZ, ssl->arrays->masterSecret, SECRET_LEN, side, FINISHED_LABEL_SZ, handshake_hash, hashSz, IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm, ssl->heap, ssl->devId); +#else + /* Pseudo random function must be enabled in the configuration. */ + ret = PRF_MISSING; + WOLFSSL_MSG("Pseudo-random function is not enabled"); + + (void)side; + (void)hashes; +#endif } #if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH) @@ -555,8 +279,28 @@ static int _DeriveTlsKeys(byte* key_dig, word32 key_dig_len, XMEMCPY(seed, sr, RAN_LEN); XMEMCPY(seed + RAN_LEN, cr, RAN_LEN); - ret = PRF(key_dig, key_dig_len, ms, msLen, key_label, KEY_LABEL_SZ, +#ifdef WOLFSSL_HAVE_PRF + ret = wc_PRF_TLS(key_dig, key_dig_len, ms, msLen, key_label, KEY_LABEL_SZ, seed, SEED_LEN, tls1_2, hash_type, heap, devId); +#else + /* Pseudo random function must be enabled in the configuration. */ + ret = PRF_MISSING; + WOLFSSL_MSG("Pseudo-random function is not enabled"); + + (void)key_dig; + (void)key_dig_len; + (void)ms; + (void)msLen; + (void)tls1_2; + (void)hash_type; + (void)heap; + (void)devId; + (void)key_label; + (void)master_label; +#ifdef HAVE_EXTENDED_MASTER + (void)ext_master_label; +#endif +#endif #if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH) FREE_VAR(seed, heap); @@ -628,8 +372,23 @@ static int _MakeTlsMasterSecret(byte* ms, word32 msLen, XMEMCPY(seed, cr, RAN_LEN); XMEMCPY(seed + RAN_LEN, sr, RAN_LEN); - ret = PRF(ms, msLen, pms, pmsLen, master_label, MASTER_LABEL_SZ, +#ifdef WOLFSSL_HAVE_PRF + ret = wc_PRF_TLS(ms, msLen, pms, pmsLen, master_label, MASTER_LABEL_SZ, seed, SEED_LEN, tls1_2, hash_type, heap, devId); +#else + /* Pseudo random function must be enabled in the configuration. */ + ret = PRF_MISSING; + WOLFSSL_MSG("Pseudo-random function is not enabled"); + + (void)ms; + (void)msLen; + (void)pms; + (void)pmsLen; + (void)tls1_2; + (void)hash_type; + (void)heap; + (void)devId; +#endif #if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH) FREE_VAR(seed, heap); @@ -657,8 +416,28 @@ static int _MakeTlsExtendedMasterSecret(byte* ms, word32 msLen, int tls1_2, int hash_type, void* heap, int devId) { - return PRF(ms, msLen, pms, pmsLen, ext_master_label, EXT_MASTER_LABEL_SZ, + int ret; + +#ifdef WOLFSSL_HAVE_PRF + ret = wc_PRF_TLS(ms, msLen, pms, pmsLen, ext_master_label, EXT_MASTER_LABEL_SZ, sHash, sHashLen, tls1_2, hash_type, heap, devId); +#else + /* Pseudo random function must be enabled in the configuration. */ + ret = PRF_MISSING; + WOLFSSL_MSG("Pseudo-random function is not enabled"); + + (void)ms; + (void)msLen; + (void)pms; + (void)pmsLen; + (void)sHash; + (void)sHashLen; + (void)tls1_2; + (void)hash_type; + (void)heap; + (void)devId; +#endif + return ret; } /* External facing wrapper so user can call as well, 0 on success */ @@ -786,10 +565,20 @@ int wolfSSL_make_eap_keys(WOLFSSL* ssl, void* msk, unsigned int len, XMEMCPY(seed, ssl->arrays->clientRandom, RAN_LEN); XMEMCPY(seed + RAN_LEN, ssl->arrays->serverRandom, RAN_LEN); - ret = PRF((byte*)msk, len, ssl->arrays->masterSecret, SECRET_LEN, +#ifdef WOLFSSL_HAVE_PRF + ret = wc_PRF_TLS((byte*)msk, len, ssl->arrays->masterSecret, SECRET_LEN, (const byte *)label, (word32)XSTRLEN(label), seed, SEED_LEN, IsAtLeastTLSv1_2(ssl), ssl->specs.mac_algorithm, ssl->heap, ssl->devId); +#else + /* Pseudo random function must be enabled in the configuration. */ + ret = PRF_MISSING; + WOLFSSL_MSG("Pseudo-random function is not enabled"); + + (void)msk; + (void)len; + (void)label; +#endif #ifdef WOLFSSL_SMALL_STACK XFREE(seed, ssl->heap, DYNAMIC_TYPE_SEED); diff --git a/wolfcrypt/src/hash.c b/wolfcrypt/src/hash.c index aa1c21f4c..6013db0ce 100644 --- a/wolfcrypt/src/hash.c +++ b/wolfcrypt/src/hash.c @@ -32,7 +32,14 @@ #endif #include +#include +#ifdef NO_INLINE + #include +#else + #define WOLFSSL_MISC_INCLUDED + #include +#endif #if !defined(NO_ASN) || !defined(NO_DH) || defined(HAVE_ECC) @@ -48,18 +55,6 @@ enum Hash_Sum { }; #endif /* !NO_ASN */ -#ifdef HAVE_SELFTEST -enum { - /* CAVP selftest includes these in hmac.h instead of sha3.h, - copied here for that build */ - WC_SHA3_224_BLOCK_SIZE = 144, - WC_SHA3_256_BLOCK_SIZE = 136, - WC_SHA3_384_BLOCK_SIZE = 104, - WC_SHA3_512_BLOCK_SIZE = 72, -}; -#endif - - /* function converts int hash type to enum */ enum wc_HashType wc_HashTypeConvert(int hashType) { @@ -928,3 +923,275 @@ int wc_HashFree(wc_HashAlg* hash, enum wc_HashType type) return ret; } #endif /* WOLFSSL_SHA384 */ + + +#ifdef WOLFSSL_HAVE_PRF + +#ifdef WOLFSSL_SHA384 + #define P_HASH_MAX_SIZE WC_SHA384_DIGEST_SIZE +#else + #define P_HASH_MAX_SIZE WC_SHA256_DIGEST_SIZE +#endif + +/* Pseudo Random Function for MD5, SHA-1, SHA-256, or SHA-384 */ +int wc_PRF(byte* result, word32 resLen, const byte* secret, + word32 secLen, const byte* seed, word32 seedLen, int hash, + void* heap, int devId) +{ + word32 len = P_HASH_MAX_SIZE; + word32 times; + word32 lastLen; + word32 lastTime; + word32 i; + word32 idx = 0; + int ret = 0; +#ifdef WOLFSSL_SMALL_STACK + byte* previous; + byte* current; + Hmac* hmac; +#else + byte previous[P_HASH_MAX_SIZE]; /* max size */ + byte current[P_HASH_MAX_SIZE]; /* max size */ + Hmac hmac[1]; +#endif + +#ifdef WOLFSSL_SMALL_STACK + previous = (byte*)XMALLOC(P_HASH_MAX_SIZE, heap, DYNAMIC_TYPE_DIGEST); + current = (byte*)XMALLOC(P_HASH_MAX_SIZE, heap, DYNAMIC_TYPE_DIGEST); + hmac = (Hmac*)XMALLOC(sizeof(Hmac), heap, DYNAMIC_TYPE_HMAC); + + if (previous == NULL || current == NULL || hmac == NULL) { + if (previous) XFREE(previous, heap, DYNAMIC_TYPE_DIGEST); + if (current) XFREE(current, heap, DYNAMIC_TYPE_DIGEST); + if (hmac) XFREE(hmac, heap, DYNAMIC_TYPE_HMAC); + + return MEMORY_E; + } +#endif + + switch (hash) { + #ifndef NO_MD5 + case md5_mac: + hash = WC_MD5; + len = WC_MD5_DIGEST_SIZE; + break; + #endif + + #ifndef NO_SHA256 + case sha256_mac: + hash = WC_SHA256; + len = WC_SHA256_DIGEST_SIZE; + break; + #endif + + #ifdef WOLFSSL_SHA384 + case sha384_mac: + hash = WC_SHA384; + len = WC_SHA384_DIGEST_SIZE; + break; + #endif + + #ifndef NO_SHA + case sha_mac: + default: + hash = WC_SHA; + len = WC_SHA_DIGEST_SIZE; + break; + #endif + } + + times = resLen / len; + lastLen = resLen % len; + + if (lastLen) + times += 1; + + lastTime = times - 1; + + ret = wc_HmacInit(hmac, heap, devId); + if (ret == 0) { + ret = wc_HmacSetKey(hmac, hash, secret, secLen); + if (ret == 0) + ret = wc_HmacUpdate(hmac, seed, seedLen); /* A0 = seed */ + if (ret == 0) + ret = wc_HmacFinal(hmac, previous); /* A1 */ + if (ret == 0) { + for (i = 0; i < times; i++) { + ret = wc_HmacUpdate(hmac, previous, len); + if (ret != 0) + break; + ret = wc_HmacUpdate(hmac, seed, seedLen); + if (ret != 0) + break; + ret = wc_HmacFinal(hmac, current); + if (ret != 0) + break; + + if ((i == lastTime) && lastLen) + XMEMCPY(&result[idx], current, + min(lastLen, P_HASH_MAX_SIZE)); + else { + XMEMCPY(&result[idx], current, len); + idx += len; + ret = wc_HmacUpdate(hmac, previous, len); + if (ret != 0) + break; + ret = wc_HmacFinal(hmac, previous); + if (ret != 0) + break; + } + } + } + wc_HmacFree(hmac); + } + + ForceZero(previous, P_HASH_MAX_SIZE); + ForceZero(current, P_HASH_MAX_SIZE); + ForceZero(hmac, sizeof(Hmac)); + +#ifdef WOLFSSL_SMALL_STACK + XFREE(previous, heap, DYNAMIC_TYPE_DIGEST); + XFREE(current, heap, DYNAMIC_TYPE_DIGEST); + XFREE(hmac, heap, DYNAMIC_TYPE_HMAC); +#endif + + return ret; +} +#undef P_HASH_MAX_SIZE + +/* compute PRF (pseudo random function) using SHA1 and MD5 for TLSv1 */ +int wc_PRF_TLSv1(byte* digest, word32 digLen, const byte* secret, + word32 secLen, const byte* label, word32 labLen, + const byte* seed, word32 seedLen, void* heap, int devId) +{ + int ret = 0; + word32 half = (secLen + 1) / 2; + +#ifdef WOLFSSL_SMALL_STACK + byte* md5_half; + byte* sha_half; + byte* md5_result; + byte* sha_result; +#else + byte md5_half[MAX_PRF_HALF]; /* half is real size */ + byte sha_half[MAX_PRF_HALF]; /* half is real size */ + byte md5_result[MAX_PRF_DIG]; /* digLen is real size */ + byte sha_result[MAX_PRF_DIG]; /* digLen is real size */ +#endif +#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH) + DECLARE_VAR(labelSeed, byte, MAX_PRF_LABSEED, heap); + if (labelSeed == NULL) + return MEMORY_E; +#else + byte labelSeed[MAX_PRF_LABSEED]; +#endif + + if (half > MAX_PRF_HALF || + labLen + seedLen > MAX_PRF_LABSEED || + digLen > MAX_PRF_DIG) + { + #if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH) + FREE_VAR(labelSeed, heap); + #endif + return BUFFER_E; + } + +#ifdef WOLFSSL_SMALL_STACK + md5_half = (byte*)XMALLOC(MAX_PRF_HALF, heap, DYNAMIC_TYPE_DIGEST); + sha_half = (byte*)XMALLOC(MAX_PRF_HALF, heap, DYNAMIC_TYPE_DIGEST); + md5_result = (byte*)XMALLOC(MAX_PRF_DIG, heap, DYNAMIC_TYPE_DIGEST); + sha_result = (byte*)XMALLOC(MAX_PRF_DIG, heap, DYNAMIC_TYPE_DIGEST); + + if (md5_half == NULL || sha_half == NULL || md5_result == NULL || + sha_result == NULL) { + if (md5_half) XFREE(md5_half, heap, DYNAMIC_TYPE_DIGEST); + if (sha_half) XFREE(sha_half, heap, DYNAMIC_TYPE_DIGEST); + if (md5_result) XFREE(md5_result, heap, DYNAMIC_TYPE_DIGEST); + if (sha_result) XFREE(sha_result, heap, DYNAMIC_TYPE_DIGEST); + #if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH) + FREE_VAR(labelSeed, heap); + #endif + + return MEMORY_E; + } +#endif + + XMEMSET(md5_result, 0, digLen); + XMEMSET(sha_result, 0, digLen); + + XMEMCPY(md5_half, secret, half); + XMEMCPY(sha_half, secret + half - secLen % 2, half); + + XMEMCPY(labelSeed, label, labLen); + XMEMCPY(labelSeed + labLen, seed, seedLen); + + if ((ret = wc_PRF(md5_result, digLen, md5_half, half, labelSeed, + labLen + seedLen, md5_mac, heap, devId)) == 0) { + if ((ret = wc_PRF(sha_result, digLen, sha_half, half, labelSeed, + labLen + seedLen, sha_mac, heap, devId)) == 0) { + /* calculate XOR for TLSv1 PRF */ + XMEMCPY(digest, md5_result, digLen); + xorbuf(digest, sha_result, digLen); + } + } + +#ifdef WOLFSSL_SMALL_STACK + XFREE(md5_half, heap, DYNAMIC_TYPE_DIGEST); + XFREE(sha_half, heap, DYNAMIC_TYPE_DIGEST); + XFREE(md5_result, heap, DYNAMIC_TYPE_DIGEST); + XFREE(sha_result, heap, DYNAMIC_TYPE_DIGEST); +#endif + +#if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH) + FREE_VAR(labelSeed, heap); +#endif + + return ret; +} + +/* Wrapper for TLS 1.2 and TLSv1 cases to calculate PRF */ +/* In TLS 1.2 case call straight thru to wc_PRF */ +int wc_PRF_TLS(byte* digest, word32 digLen, const byte* secret, word32 secLen, + const byte* label, word32 labLen, const byte* seed, word32 seedLen, + int useAtLeastSha256, int hash_type, void* heap, int devId) +{ + int ret = 0; + + if (useAtLeastSha256) { + #if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH) + DECLARE_VAR(labelSeed, byte, MAX_PRF_LABSEED, heap); + if (labelSeed == NULL) + return MEMORY_E; + #else + byte labelSeed[MAX_PRF_LABSEED]; + #endif + + if (labLen + seedLen > MAX_PRF_LABSEED) + return BUFFER_E; + + XMEMCPY(labelSeed, label, labLen); + XMEMCPY(labelSeed + labLen, seed, seedLen); + + /* If a cipher suite wants an algorithm better than sha256, it + * should use better. */ + if (hash_type < sha256_mac || hash_type == blake2b_mac) + hash_type = sha256_mac; + /* compute PRF for MD5, SHA-1, SHA-256, or SHA-384 for TLSv1.2 PRF */ + ret = wc_PRF(digest, digLen, secret, secLen, labelSeed, + labLen + seedLen, hash_type, heap, devId); + + #if defined(WOLFSSL_ASYNC_CRYPT) && !defined(WC_ASYNC_NO_HASH) + FREE_VAR(labelSeed, heap); + #endif + } +#ifndef NO_OLD_TLS + else { + /* compute TLSv1 PRF (pseudo random function using HMAC) */ + ret = wc_PRF_TLSv1(digest, digLen, secret, secLen, label, labLen, seed, + seedLen, heap, devId); + } +#endif + + return ret; +} +#endif /* WOLFSSL_HAVE_PRF */ diff --git a/wolfssl/error-ssl.h b/wolfssl/error-ssl.h index 04c4a8552..1fd9520f3 100644 --- a/wolfssl/error-ssl.h +++ b/wolfssl/error-ssl.h @@ -162,6 +162,7 @@ enum wolfSSL_ErrorCodes { ALERT_COUNT_E = -427, /* Alert Count exceeded err */ EXT_MISSING = -428, /* Required extension not found */ UNSUPPORTED_EXTENSION = -429, /* TLSX not requested by client */ + PRF_MISSING = -430, /* PRF not compiled in */ /* add strings to wolfSSL_ERR_reason_error_string in internal.c !!!!! */ /* begin negotiation parameter errors */ diff --git a/wolfssl/internal.h b/wolfssl/internal.h index b835a4e92..a03e86f8c 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1255,9 +1255,6 @@ enum Misc { EXT_MASTER_LABEL_SZ = 22, /* TLS extended master secret label sz */ MASTER_LABEL_SZ = 13, /* TLS master secret label sz */ KEY_LABEL_SZ = 13, /* TLS key block expansion sz */ - MAX_PRF_HALF = 256, /* Maximum half secret len */ - MAX_PRF_LABSEED = 128, /* Maximum label + seed len */ - MAX_PRF_DIG = 224, /* Maximum digest len */ PROTOCOL_LABEL_SZ = 9, /* Length of the protocol label */ MAX_LABEL_SZ = 34, /* Maximum length of a label */ MAX_HKDF_LABEL_SZ = OPAQUE16_LEN + @@ -2768,20 +2765,6 @@ typedef struct CipherSpecs { void InitCipherSpecs(CipherSpecs* cs); -/* Supported Message Authentication Codes from page 43 */ -enum MACAlgorithm { - no_mac, - md5_mac, - sha_mac, - sha224_mac, - sha256_mac, /* needs to match external KDF_MacAlgorithm */ - sha384_mac, - sha512_mac, - rmd_mac, - blake2b_mac -}; - - /* Supported Key Exchange Protocols */ enum KeyExchangeAlgorithm { no_kea, diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 331896e75..898680453 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -1902,7 +1902,7 @@ enum BulkCipherAlgorithm { /* for KDF TLS 1.2 mac types */ enum KDF_MacAlgorithm { - wolfssl_sha256 = 4, /* needs to match internal MACAlgorithm */ + wolfssl_sha256 = 4, /* needs to match hash.h wc_MACAlgorithm */ wolfssl_sha384, wolfssl_sha512 }; diff --git a/wolfssl/wolfcrypt/hash.h b/wolfssl/wolfcrypt/hash.h index db16d41d1..95be9f773 100644 --- a/wolfssl/wolfcrypt/hash.h +++ b/wolfssl/wolfcrypt/hash.h @@ -63,6 +63,20 @@ #endif +/* Supported Message Authentication Codes from page 43 */ +enum wc_MACAlgorithm { + no_mac, + md5_mac, + sha_mac, + sha224_mac, + sha256_mac, /* needs to match external KDF_MacAlgorithm */ + sha384_mac, + sha512_mac, + rmd_mac, + blake2b_mac +}; + + typedef union { #ifndef NO_MD5 wc_Md5 md5; @@ -166,6 +180,25 @@ WOLFSSL_API int wc_Sha384Hash(const byte*, word32, byte*); WOLFSSL_API int wc_Sha512Hash(const byte*, word32, byte*); #endif /* WOLFSSL_SHA512 */ +enum max_prf { + MAX_PRF_HALF = 256, /* Maximum half secret len */ + MAX_PRF_LABSEED = 128, /* Maximum label + seed len */ + MAX_PRF_DIG = 224 /* Maximum digest len */ +}; + +#ifdef WOLFSSL_HAVE_PRF +WOLFSSL_API int wc_PRF(byte* result, word32 resLen, const byte* secret, + word32 secLen, const byte* seed, word32 seedLen, int hash, + void* heap, int devId); +WOLFSSL_API int wc_PRF_TLSv1(byte* digest, word32 digLen, const byte* secret, + word32 secLen, const byte* label, word32 labLen, + const byte* seed, word32 seedLen, void* heap, int devId); +WOLFSSL_API int wc_PRF_TLS(byte* digest, word32 digLen, const byte* secret, + word32 secLen, const byte* label, word32 labLen, + const byte* seed, word32 seedLen, int useAtLeastSha256, + int hash_type, void* heap, int devId); +#endif /* WOLFSSL_HAVE_PRF */ + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index e3a44eddd..147999e89 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -1831,8 +1831,13 @@ extern void uITRON4_free(void *p) ; #define WOLFSSL_NO_WORD64_OPS #endif +#if !defined(WOLFCRYPT_ONLY) && !defined(WOLFSSL_NO_TLS12) + #undef WOLFSSL_HAVE_PRF + #define WOLFSSL_HAVE_PRF +#endif + #if defined(NO_AES) && defined(NO_DES3) && !defined(HAVE_CAMELLIA) && \ - defined(NO_PWDBASED) && !defined(HAVE_IDEA) + !defined(WOLFSSL_HAVE_PRF) && defined(NO_PWDBASED) && !defined(HAVE_IDEA) #undef WOLFSSL_NO_XOR_OPS #define WOLFSSL_NO_XOR_OPS #endif