diff --git a/src/internal.c b/src/internal.c index a65b2365c..f7ca86595 100644 --- a/src/internal.c +++ b/src/internal.c @@ -146,7 +146,7 @@ static const byte tls13Downgrade[7] = { #ifndef NO_OLD_TLS static int SSL_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz, - int content, int verify); + int padSz, int content, int verify); #endif @@ -11860,173 +11860,6 @@ static int SanityCheckCipherText(WOLFSSL* ssl, word32 encryptSz) return 0; } -#ifndef NO_OLD_TLS - -static INLINE void Md5Rounds(int rounds, const byte* data, int sz) -{ - wc_Md5 md5; - int i; - - wc_InitMd5(&md5); /* no error check on purpose, dummy round */ - - for (i = 0; i < rounds; i++) - wc_Md5Update(&md5, data, sz); - wc_Md5Free(&md5); /* in case needed to release resources */ -} - - - -/* do a dummy sha round */ -static INLINE void ShaRounds(int rounds, const byte* data, int sz) -{ - wc_Sha sha; - int i; - - wc_InitSha(&sha); /* no error check on purpose, dummy round */ - - for (i = 0; i < rounds; i++) - wc_ShaUpdate(&sha, data, sz); - wc_ShaFree(&sha); /* in case needed to release resources */ -} -#endif - -#ifndef WOLFSSL_NO_TLS12 - -#ifndef NO_SHA256 - -static INLINE void Sha256Rounds(int rounds, const byte* data, int sz) -{ - wc_Sha256 sha256; - int i; - - wc_InitSha256(&sha256); /* no error check on purpose, dummy round */ - - for (i = 0; i < rounds; i++) { - wc_Sha256Update(&sha256, data, sz); - /* no error check on purpose, dummy round */ - } - wc_Sha256Free(&sha256); /* in case needed to release resources */ -} - -#endif - - -#ifdef WOLFSSL_SHA384 - -static INLINE void Sha384Rounds(int rounds, const byte* data, int sz) -{ - wc_Sha384 sha384; - int i; - - wc_InitSha384(&sha384); /* no error check on purpose, dummy round */ - - for (i = 0; i < rounds; i++) { - wc_Sha384Update(&sha384, data, sz); - /* no error check on purpose, dummy round */ - } - wc_Sha384Free(&sha384); /* in case needed to release resources */ -} - -#endif - - -#ifdef WOLFSSL_SHA512 - -static INLINE void Sha512Rounds(int rounds, const byte* data, int sz) -{ - wc_Sha512 sha512; - int i; - - wc_InitSha512(&sha512); /* no error check on purpose, dummy round */ - - for (i = 0; i < rounds; i++) { - wc_Sha512Update(&sha512, data, sz); - /* no error check on purpose, dummy round */ - } - wc_Sha512Free(&sha512); /* in case needed to release resources */ -} - -#endif - -#ifdef WOLFSSL_RIPEMD - -static INLINE void RmdRounds(int rounds, const byte* data, int sz) -{ - RipeMd ripemd; - int i; - - (void)wc_InitRipeMd(&ripemd); - - for (i = 0; i < rounds; i++) - (void)wc_RipeMdUpdate(&ripemd, data, sz); -} - -#endif - - -/* Do dummy rounds */ -static INLINE void DoRounds(int type, int rounds, const byte* data, int sz) -{ - (void)rounds; - (void)data; - (void)sz; - - switch (type) { - case no_mac : - break; - -#ifndef NO_OLD_TLS -#ifndef NO_MD5 - case md5_mac : - Md5Rounds(rounds, data, sz); - break; -#endif - -#ifndef NO_SHA - case sha_mac : - ShaRounds(rounds, data, sz); - break; -#endif -#endif - -#ifndef NO_SHA256 - case sha256_mac : - Sha256Rounds(rounds, data, sz); - break; -#endif - -#ifdef WOLFSSL_SHA384 - case sha384_mac : - Sha384Rounds(rounds, data, sz); - break; -#endif - -#ifdef WOLFSSL_SHA512 - case sha512_mac : - Sha512Rounds(rounds, data, sz); - break; -#endif - -#ifdef WOLFSSL_RIPEMD - case rmd_mac : - RmdRounds(rounds, data, sz); - break; -#endif - - default: - WOLFSSL_MSG("Bad round type"); - break; - } -} - - -/* do number of compression rounds on dummy data */ -static INLINE void CompressRounds(WOLFSSL* ssl, int rounds, const byte* dummy) -{ - if (rounds) - DoRounds(ssl->specs.mac_algorithm, rounds, dummy, COMPRESS_LOWER); -} - /* check all length bytes for the pad value, return 0 on success */ static int PadCheck(const byte* a, byte pad, int length) @@ -12042,81 +11875,127 @@ static int PadCheck(const byte* a, byte pad, int length) } -/* get compression extra rounds */ -static INLINE int GetRounds(int pLen, int padLen, int t) +/* Mask the padding bytes with the expected values. + * Constant time implementation - does maximum pad size possible. + * + * data Message data. + * sz Size of the message including MAC and padding and padding length. + * macSz Size of the MAC. + * returns 0 on success, otherwise failure. + */ +static byte MaskPadding(const byte* data, int sz, int macSz) { - int roundL1 = 1; /* round up flags */ - int roundL2 = 1; + int i; + int checkSz = sz - 1; + byte paddingSz = data[sz - 1]; + byte mask; + byte good = ctMaskGT(paddingSz, sz - 1 - macSz); - int L1 = COMPRESS_CONSTANT + pLen - t; - int L2 = COMPRESS_CONSTANT + pLen - padLen - 1 - t; + if (checkSz > TLS_MAX_PAD_SZ) + checkSz = TLS_MAX_PAD_SZ; - L1 -= COMPRESS_UPPER; - L2 -= COMPRESS_UPPER; + for (i = 0; i < checkSz; i++) { + mask = ctMaskLTE(i, paddingSz); + good |= mask & (data[sz - 1 - i] ^ paddingSz); + } - if ( (L1 % COMPRESS_LOWER) == 0) - roundL1 = 0; - if ( (L2 % COMPRESS_LOWER) == 0) - roundL2 = 0; - - L1 /= COMPRESS_LOWER; - L2 /= COMPRESS_LOWER; - - L1 += roundL1; - L2 += roundL2; - - return L1 - L2; + return good; } +/* Mask the MAC in the message with the MAC calculated. + * Constant time implementation - starts looking for MAC where maximum padding + * size has it. + * + * data Message data. + * sz Size of the message including MAC and padding and padding length. + * macSz Size of the MAC data. + * expMac Expected MAC value. + * returns 0 on success, otherwise failure. + */ +static byte MaskMac(const byte* data, int sz, int macSz, byte* expMac) +{ + int i, j; + unsigned char mac[WC_MAX_DIGEST_SIZE]; + int scanStart = sz - 1 - TLS_MAX_PAD_SZ - macSz; + int macEnd = sz - 1 - data[sz - 1]; + int macStart = macEnd - macSz; + int r = 0; + unsigned char started, notEnded; + unsigned char good = 0; + + if (scanStart < 0) + scanStart = 0; + + /* Div on Intel has different speeds depending on value. + * Use a bitwise AND or mod a specific value (converted to mul). */ + if ((macSz & (macSz - 1)) == 0) + r = (macSz - (scanStart - macStart)) & (macSz - 1); +#ifndef NO_SHA + else if (macSz == WC_SHA_DIGEST_SIZE) + r = (macSz - (scanStart - macStart)) % WC_SHA_DIGEST_SIZE; +#endif +#ifdef WOLFSSL_SHA384 + else if (macSz == WC_SHA384_DIGEST_SIZE) + r = (macSz - (scanStart - macStart)) % WC_SHA384_DIGEST_SIZE; +#endif + + XMEMSET(mac, 0, macSz); + for (i = scanStart; i < sz; i += macSz) { + for (j = 0; j < macSz && j + i < sz; j++) { + started = ctMaskGTE(i + j, macStart); + notEnded = ctMaskLT(i + j, macEnd); + mac[j] |= started & notEnded & data[i + j]; + } + } + + if ((macSz & (macSz - 1)) == 0) { + for (i = 0; i < macSz; i++) + good |= expMac[i] ^ mac[(i + r) & (macSz - 1)]; + } +#ifndef NO_SHA + else if (macSz == WC_SHA_DIGEST_SIZE) { + for (i = 0; i < macSz; i++) + good |= expMac[i] ^ mac[(i + r) % WC_SHA_DIGEST_SIZE]; + } +#endif +#ifdef WOLFSSL_SHA384 + else if (macSz == WC_SHA384_DIGEST_SIZE) { + for (i = 0; i < macSz; i++) + good |= expMac[i] ^ mac[(i + r) % WC_SHA384_DIGEST_SIZE]; + } +#endif + + return good; +} /* timing resistant pad/verify check, return 0 on success */ -static int TimingPadVerify(WOLFSSL* ssl, const byte* input, int padLen, int t, - int pLen, int content) +int TimingPadVerify(WOLFSSL* ssl, const byte* input, int padLen, int macSz, + int pLen, int content) { byte verify[WC_MAX_DIGEST_SIZE]; - byte dmy[sizeof(WOLFSSL) >= MAX_PAD_SIZE ? 1 : MAX_PAD_SIZE] = {0}; - byte* dummy = sizeof(dmy) < MAX_PAD_SIZE ? (byte*) ssl : dmy; + byte good; int ret = 0; - (void)dmy; + good = MaskPadding(input, pLen, macSz); + ret = ssl->hmac(ssl, verify, input, pLen - macSz - padLen - 1, padLen, + content, 1); + good |= MaskMac(input, pLen, ssl->specs.hash_size, verify); - if ( (t + padLen + 1) > pLen) { - WOLFSSL_MSG("Plain Len not long enough for pad/mac"); - PadCheck(dummy, (byte)padLen, MAX_PAD_SIZE); - ssl->hmac(ssl, verify, input, pLen - t, content, 1); /* still compare */ - ConstantCompare(verify, input + pLen - t, t); + /* Non-zero on failure. */ + good = ~good; + good &= good >> 4; + good &= good >> 2; + good &= good >> 1; + /* Make ret negative on masking failure. */ + ret -= 1 - good; - return VERIFY_MAC_ERROR; - } - - if (PadCheck(input + pLen - (padLen + 1), (byte)padLen, padLen + 1) != 0) { - WOLFSSL_MSG("PadCheck failed"); - PadCheck(dummy, (byte)padLen, MAX_PAD_SIZE - padLen - 1); - ssl->hmac(ssl, verify, input, pLen - t, content, 1); /* still compare */ - ConstantCompare(verify, input + pLen - t, t); - - return VERIFY_MAC_ERROR; - } - - PadCheck(dummy, (byte)padLen, MAX_PAD_SIZE - padLen - 1); - ret = ssl->hmac(ssl, verify, input, pLen - padLen - 1 - t, content, 1); - - CompressRounds(ssl, GetRounds(pLen, padLen, t), dummy); - - if (ConstantCompare(verify, input + (pLen - padLen - 1 - t), t) != 0) { - WOLFSSL_MSG("Verify MAC compare failed"); - return VERIFY_MAC_ERROR; - } - - /* treat any faulure as verify MAC error */ + /* Treat any faulure as verify MAC error. */ if (ret != 0) ret = VERIFY_MAC_ERROR; return ret; } -#endif /* WOLFSSL_NO_TLS12 */ - int DoApplicationData(WOLFSSL* ssl, byte* input, word32* inOutIdx) { @@ -12368,8 +12247,8 @@ static INLINE int VerifyMac(WOLFSSL* ssl, const byte* input, word32 msgSz, badPadLen = 1; } PadCheck(dummy, (byte)pad, MAX_PAD_SIZE); /* timing only */ - ret = ssl->hmac(ssl, verify, input, msgSz - digestSz - pad - 1, - content, 1); + ret = ssl->hmac(ssl, verify, input, msgSz - digestSz - pad - 1, pad, + content, 1); if (ConstantCompare(verify, input + msgSz - digestSz - pad - 1, digestSz) != 0) return VERIFY_MAC_ERROR; @@ -12378,7 +12257,7 @@ static INLINE int VerifyMac(WOLFSSL* ssl, const byte* input, word32 msgSz, } } else if (ssl->specs.cipher_type == stream) { - ret = ssl->hmac(ssl, verify, input, msgSz - digestSz, content, 1); + ret = ssl->hmac(ssl, verify, input, msgSz - digestSz, -1, content, 1); if (ConstantCompare(verify, input + msgSz - digestSz, digestSz) != 0){ return VERIFY_MAC_ERROR; } @@ -13118,7 +12997,7 @@ int SendChangeCipher(WOLFSSL* ssl) #ifndef NO_OLD_TLS static int SSL_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz, - int content, int verify) + int padLen, int content, int verify) { byte result[WC_MAX_DIGEST_SIZE]; word32 digestSz = ssl->specs.hash_size; /* actual sizes */ @@ -13133,6 +13012,8 @@ static int SSL_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz, byte conLen[ENUM_LEN + LENGTH_SZ]; /* content & length */ const byte* macSecret = wolfSSL_GetMacSecret(ssl, verify); + (void)padLen; + #ifdef HAVE_FUZZER if (ssl->fuzzerCb) ssl->fuzzerCb(ssl, in, sz, FUZZ_HMAC, ssl->fuzzerCtx); @@ -13609,8 +13490,8 @@ int BuildMessage(WOLFSSL* ssl, byte* output, int outSz, const byte* input, ERROR_OUT(MEMORY_E, exit_buildmsg); #endif - ret = ssl->hmac(ssl, hmac, output + args->headerSz + args->ivSz, inSz, - type, 0); + ret = ssl->hmac(ssl, hmac, output + args->headerSz + args->ivSz, + inSz, -1, type, 0); XMEMCPY(output + args->idx, hmac, args->digestSz); #ifdef WOLFSSL_SMALL_STACK @@ -13619,8 +13500,8 @@ int BuildMessage(WOLFSSL* ssl, byte* output, int outSz, const byte* input, } else #endif - ret = ssl->hmac(ssl, output + args->idx, output + args->headerSz + args->ivSz, - inSz, type, 0); + ret = ssl->hmac(ssl, output + args->idx, output + + args->headerSz + args->ivSz, inSz, -1, type, 0); #ifdef WOLFSSL_DTLS if (ssl->options.dtls) DtlsSEQIncrement(ssl, CUR_ORDER); diff --git a/src/tls.c b/src/tls.c index df8ac64f5..efd9bd4e0 100755 --- a/src/tls.c +++ b/src/tls.c @@ -852,13 +852,447 @@ int wolfSSL_SetTlsHmacInner(WOLFSSL* ssl, byte* inner, word32 sz, int content, } -/* TLS type HMAC */ -int TLS_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz, - int content, int verify) +#if !defined(WOLFSSL_NO_HASH_RAW) && !defined(HAVE_FIPS) + +/* Update the hash in the HMAC. + * + * hmac HMAC object. + * data Data to be hashed. + * sz Size of data to hash. + * returns 0 on success, otherwise failure. + */ +static int Hmac_HashUpdate(Hmac* hmac, const byte* data, word32 sz) { - Hmac hmac; - int ret = 0; - byte myInner[WOLFSSL_TLS_HMAC_INNER_SZ]; + int ret = BAD_FUNC_ARG; + + switch (hmac->macType) { + #ifndef NO_SHA + case WC_SHA: + ret = wc_ShaUpdate(&hmac->hash.sha, data, sz); + break; + #endif /* !NO_SHA */ + + #ifndef NO_SHA256 + case WC_SHA256: + ret = wc_Sha256Update(&hmac->hash.sha256, data, sz); + break; + #endif /* !NO_SHA256 */ + + #ifdef WOLFSSL_SHA384 + case WC_SHA384: + ret = wc_Sha384Update(&hmac->hash.sha384, data, sz); + break; + #endif /* WOLFSSL_SHA384 */ + + #ifdef WOLFSSL_SHA512 + case WC_SHA512: + ret = wc_Sha512Update(&hmac->hash.sha512, data, sz); + break; + #endif /* WOLFSSL_SHA512 */ + } + + return ret; +} + +/* Finalize the hash but don't put the EOC, padding or length in. + * + * hmac HMAC object. + * hash Hash result. + * returns 0 on success, otherwise failure. + */ +static int Hmac_HashFinalRaw(Hmac* hmac, unsigned char* hash) +{ + int ret = BAD_FUNC_ARG; + + switch (hmac->macType) { + #ifndef NO_SHA + case WC_SHA: + ret = wc_ShaFinalRaw(&hmac->hash.sha, hash); + break; + #endif /* !NO_SHA */ + + #ifndef NO_SHA256 + case WC_SHA256: + ret = wc_Sha256FinalRaw(&hmac->hash.sha256, hash); + break; + #endif /* !NO_SHA256 */ + + #ifdef WOLFSSL_SHA384 + case WC_SHA384: + ret = wc_Sha384FinalRaw(&hmac->hash.sha384, hash); + break; + #endif /* WOLFSSL_SHA384 */ + + #ifdef WOLFSSL_SHA512 + case WC_SHA512: + ret = wc_Sha512FinalRaw(&hmac->hash.sha512, hash); + break; + #endif /* WOLFSSL_SHA512 */ + } + + return ret; +} + +/* Finalize the HMAC by performing outer hash. + * + * hmac HMAC object. + * mac MAC result. + * returns 0 on success, otherwise failure. + */ +static int Hmac_OuterHash(Hmac* hmac, unsigned char* mac) +{ + int ret = BAD_FUNC_ARG; + + switch (hmac->macType) { + #ifndef NO_SHA + case WC_SHA: + ret = wc_InitSha(&hmac->hash.sha); + if (ret == 0) + ret = wc_ShaUpdate(&hmac->hash.sha, (byte*)hmac->opad, + WC_SHA_BLOCK_SIZE); + if (ret == 0) + ret = wc_ShaUpdate(&hmac->hash.sha, (byte*)hmac->innerHash, + WC_SHA_DIGEST_SIZE); + if (ret == 0) + ret = wc_ShaFinal(&hmac->hash.sha, mac); + break; + #endif /* !NO_SHA */ + + #ifndef NO_SHA256 + case WC_SHA256: + ret = wc_InitSha256(&hmac->hash.sha256); + if (ret == 0) + ret = wc_Sha256Update(&hmac->hash.sha256, (byte*)hmac->opad, + WC_SHA256_BLOCK_SIZE); + if (ret == 0) + ret = wc_Sha256Update(&hmac->hash.sha256, + (byte*)hmac->innerHash, + WC_SHA256_DIGEST_SIZE); + if (ret == 0) + ret = wc_Sha256Final(&hmac->hash.sha256, mac); + break; + #endif /* !NO_SHA256 */ + + #ifdef WOLFSSL_SHA384 + case WC_SHA384: + ret = wc_InitSha384(&hmac->hash.sha384); + if (ret == 0) + ret = wc_Sha384Update(&hmac->hash.sha384, (byte*)hmac->opad, + WC_SHA384_BLOCK_SIZE); + if (ret == 0) + ret = wc_Sha384Update(&hmac->hash.sha384, + (byte*)hmac->innerHash, + WC_SHA384_DIGEST_SIZE); + if (ret == 0) + ret = wc_Sha384Final(&hmac->hash.sha384, mac); + break; + #endif /* WOLFSSL_SHA384 */ + + #ifdef WOLFSSL_SHA512 + case WC_SHA512: + ret = wc_InitSha512(&hmac->hash.sha512); + if (ret == 0) + ret = wc_Sha512Update(&hmac->hash.sha512,(byte*)hmac->opad, + WC_SHA512_BLOCK_SIZE); + if (ret == 0) + ret = wc_Sha512Update(&hmac->hash.sha512, + (byte*)hmac->innerHash, + WC_SHA512_DIGEST_SIZE); + if (ret == 0) + ret = wc_Sha512Final(&hmac->hash.sha512, mac); + break; + #endif /* WOLFSSL_SHA512 */ + } + + return ret; +} + +/* Calculate the HMAC of the header + message data. + * Constant time implementation using wc_Sha*FinalRaw(). + * + * hmac HMAC object. + * digest MAC result. + * in Message data. + * sz Size of the message data. + * header Constructed record header with length of handshake data. + * returns 0 on success, otherwise failure. + */ +static int Hmac_UpdateFinal_CT(Hmac* hmac, byte* digest, const byte* in, + word32 sz, byte* header) +{ + byte lenBytes[8]; + int i, j, k; + int blockBits, blockMask; + int realLen, lastBlockLen, macLen, extraLen, eocIndex; + int blocks, safeBlocks, lenBlock, eocBlock; + int maxLen; + int blockSz, padSz; + int ret; + byte extraBlock; + + switch (hmac->macType) { + #ifndef NO_SHA + case WC_SHA: + blockSz = WC_SHA_BLOCK_SIZE; + blockBits = 6; + macLen = WC_SHA_DIGEST_SIZE; + padSz = WC_SHA_BLOCK_SIZE - WC_SHA_PAD_SIZE + 1; + break; + #endif /* !NO_SHA */ + + #ifndef NO_SHA256 + case WC_SHA256: + blockSz = WC_SHA256_BLOCK_SIZE; + blockBits = 6; + macLen = WC_SHA256_DIGEST_SIZE; + padSz = WC_SHA256_BLOCK_SIZE - WC_SHA256_PAD_SIZE + 1; + break; + #endif /* !NO_SHA256 */ + + #ifdef WOLFSSL_SHA384 + case WC_SHA384: + blockSz = WC_SHA384_BLOCK_SIZE; + blockBits = 7; + macLen = WC_SHA384_DIGEST_SIZE; + padSz = WC_SHA384_BLOCK_SIZE - WC_SHA384_PAD_SIZE + 1; + break; + #endif /* WOLFSSL_SHA384 */ + + #ifdef WOLFSSL_SHA512 + case WC_SHA512: + blockSz = WC_SHA512_BLOCK_SIZE; + blockBits = 7; + macLen = WC_SHA512_DIGEST_SIZE; + padSz = WC_SHA512_BLOCK_SIZE - WC_SHA512_PAD_SIZE + 1; + break; + #endif /* WOLFSSL_SHA512 */ + + default: + return BAD_FUNC_ARG; + } + blockMask = blockSz - 1; + + /* Size of data to HMAC if padding length byte is zero. */ + maxLen = WOLFSSL_TLS_HMAC_INNER_SZ + sz - 1 - macLen; + /* Complete data (including padding) has block for EOC and/or length. */ + extraBlock = ctSetLTE((maxLen + padSz) & blockMask, padSz); + /* Total number of blocks for data including padding. */ + blocks = ((maxLen + blockSz - 1) >> blockBits) + extraBlock; + /* Up to last 6 blocks can be hashed safely. */ + safeBlocks = blocks - 6; + + /* Length of message data. */ + realLen = maxLen - in[sz - 1]; + /* Number of message bytes in last block. */ + lastBlockLen = realLen & blockMask; + /* Number of padding bytes in last block. */ + extraLen = ((blockSz * 2 - padSz - lastBlockLen) & blockMask) + 1; + /* Number of blocks to create for hash. */ + lenBlock = (realLen + extraLen) >> blockBits; + /* Block containing EOC byte. */ + eocBlock = realLen >> blockBits; + /* Index of EOC byte in block. */ + eocIndex = realLen & blockMask; + + /* Add length of hmac's ipad to total length. */ + realLen += blockSz; + /* Length as bits - 8 bytes bigendian. */ + c32toa(realLen >> ((sizeof(word32) * 8) - 3), lenBytes); + c32toa(realLen << 3, lenBytes + sizeof(word32)); + + ret = Hmac_HashUpdate(hmac, (unsigned char*)hmac->ipad, blockSz); + if (ret != 0) + return ret; + + XMEMSET(hmac->innerHash, 0, macLen); + + if (safeBlocks > 0) { + ret = Hmac_HashUpdate(hmac, header, WOLFSSL_TLS_HMAC_INNER_SZ); + if (ret != 0) + return ret; + ret = Hmac_HashUpdate(hmac, in, safeBlocks * blockSz - + WOLFSSL_TLS_HMAC_INNER_SZ); + if (ret != 0) + return ret; + } + else + safeBlocks = 0; + + XMEMSET(digest, 0, macLen); + k = safeBlocks * blockSz; + for (i = safeBlocks; i < blocks; i++) { + unsigned char hashBlock[WC_MAX_BLOCK_SIZE]; + unsigned char isEocBlock = ctMaskEq(i, eocBlock); + unsigned char isOutBlock = ctMaskEq(i, lenBlock); + + for (j = 0; j < blockSz; j++, k++) { + unsigned char atEoc = ctMaskEq(j, eocIndex) & isEocBlock; + unsigned char pastEoc = ctMaskGT(j, eocIndex) & isEocBlock; + unsigned char b = 0; + + if (k < WOLFSSL_TLS_HMAC_INNER_SZ) + b = header[k]; + else if (k < maxLen) + b = in[k - WOLFSSL_TLS_HMAC_INNER_SZ]; + + b = ctMaskSel(atEoc, b, 0x80); + b &= ~pastEoc; + b &= ~isOutBlock | isEocBlock; + + if (j >= blockSz - 8) { + b = ctMaskSel(isOutBlock, b, lenBytes[j - (blockSz - 8)]); + } + + hashBlock[j] = b; + } + + ret = Hmac_HashUpdate(hmac, hashBlock, blockSz); + if (ret != 0) + return ret; + ret = Hmac_HashFinalRaw(hmac, hashBlock); + if (ret != 0) + return ret; + for (j = 0; j < macLen; j++) + ((unsigned char*)hmac->innerHash)[j] |= hashBlock[j] & isOutBlock; + } + + ret = Hmac_OuterHash(hmac, digest); + + return ret; +} + +#endif + +#if defined(WOLFSSL_NO_HASH_RAW) || defined(HAVE_FIPS) || defined(HAVE_BLAKE2) + +/* Calculate the HMAC of the header + message data. + * Constant time implementation using normal hashing operations. + * Update-Final need to be constant time. + * + * hmac HMAC object. + * digest MAC result. + * in Message data. + * sz Size of the message data. + * header Constructed record header with length of handshake data. + * returns 0 on success, otherwise failure. + */ +static int Hmac_UpdateFinal(Hmac* hmac, byte* digest, const byte* in, + word32 sz, byte* header) +{ + byte dummy[WC_MAX_BLOCK_SIZE] = {0}; + int ret; + word32 msgSz, blockSz, macSz, padSz, maxSz, realSz; + word32 currSz, offset; + int msgBlocks, blocks, blockBits; + int i; + + switch (hmac->macType) { + #ifndef NO_SHA + case WC_SHA: + blockSz = WC_SHA_BLOCK_SIZE; + blockBits = 6; + macSz = WC_SHA_DIGEST_SIZE; + padSz = WC_SHA_BLOCK_SIZE - WC_SHA_PAD_SIZE + 1; + break; + #endif /* !NO_SHA */ + + #ifndef NO_SHA256 + case WC_SHA256: + blockSz = WC_SHA256_BLOCK_SIZE; + blockBits = 6; + macSz = WC_SHA256_DIGEST_SIZE; + padSz = WC_SHA256_BLOCK_SIZE - WC_SHA256_PAD_SIZE + 1; + break; + #endif /* !NO_SHA256 */ + + #ifdef WOLFSSL_SHA384 + case WC_SHA384: + blockSz = WC_SHA384_BLOCK_SIZE; + blockBits = 7; + macSz = WC_SHA384_DIGEST_SIZE; + padSz = WC_SHA384_BLOCK_SIZE - WC_SHA384_PAD_SIZE + 1; + break; + #endif /* WOLFSSL_SHA384 */ + + #ifdef WOLFSSL_SHA512 + case WC_SHA512: + blockSz = WC_SHA512_BLOCK_SIZE; + blockBits = 7; + macSz = WC_SHA512_DIGEST_SIZE; + padSz = WC_SHA512_BLOCK_SIZE - WC_SHA512_PAD_SIZE + 1; + break; + #endif /* WOLFSSL_SHA512 */ + + #ifdef HAVE_BLAKE2 + case WC_HASH_TYPE_BLAKE2B: + blockSz = BLAKE2B_BLOCKBYTES; + blockBits = 7; + macSz = BLAKE2B_256; + padSz = 0; + break; + #endif /* HAVE_BLAK2 */ + + default: + return BAD_FUNC_ARG; + } + + msgSz = sz - (1 + in[sz - 1] + macSz); + /* Make negative result 0 */ + msgSz &= ~(0 - (msgSz >> 31)); + realSz = WOLFSSL_TLS_HMAC_INNER_SZ + msgSz; + maxSz = WOLFSSL_TLS_HMAC_INNER_SZ + (sz - 1) - macSz; + + /* Calculate #blocks processed in HMAC for max and real data. */ + blocks = maxSz >> blockBits; + blocks += ((maxSz + padSz) % blockSz) < padSz; + msgBlocks = realSz >> blockBits; + /* #Extra blocks to process. */ + blocks -= msgBlocks + (((realSz + padSz) % blockSz) < padSz); + /* Calculate whole blocks. */ + msgBlocks--; + + ret = wc_HmacUpdate(hmac, header, WOLFSSL_TLS_HMAC_INNER_SZ); + if (ret == 0) { + /* Fill the rest of the block with any available data. */ + currSz = ctMaskLT(msgSz, blockSz) & msgSz; + currSz |= ctMaskGTE(msgSz, blockSz) & blockSz; + currSz -= WOLFSSL_TLS_HMAC_INNER_SZ; + currSz &= ~(0 - (currSz >> 31)); + ret = wc_HmacUpdate(hmac, in, currSz); + offset = currSz; + } + if (ret == 0) { + /* Do the hash operations on a block basis. */ + for (i = 0; i < msgBlocks; i++, offset += blockSz) { + ret = wc_HmacUpdate(hmac, in + offset, blockSz); + if (ret != 0) + break; + } + } + if (ret == 0) + ret = wc_HmacUpdate(hmac, in + offset, msgSz - offset); + if (ret == 0) + ret = wc_HmacFinal(hmac, digest); + if (ret == 0) { + /* Do the dummy hash operations. Do at least one. */ + for (i = 0; i < blocks + 1; i++) { + ret = wc_HmacUpdate(hmac, dummy, blockSz); + if (ret != 0) + break; + } + } + + return ret; +} + +#endif + +int TLS_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz, int padSz, + int content, int verify) +{ + Hmac hmac; + byte myInner[WOLFSSL_TLS_HMAC_INNER_SZ]; + int ret = 0; if (ssl == NULL) return BAD_FUNC_ARG; @@ -875,14 +1309,40 @@ int TLS_hmac(WOLFSSL* ssl, byte* digest, const byte* in, word32 sz, return ret; ret = wc_HmacSetKey(&hmac, wolfSSL_GetHmacType(ssl), - wolfSSL_GetMacSecret(ssl, verify), ssl->specs.hash_size); + wolfSSL_GetMacSecret(ssl, verify), + ssl->specs.hash_size); if (ret == 0) { - ret = wc_HmacUpdate(&hmac, myInner, sizeof(myInner)); - if (ret == 0) - ret = wc_HmacUpdate(&hmac, in, sz); /* content */ - if (ret == 0) - ret = wc_HmacFinal(&hmac, digest); + /* Constant time verification required. */ + if (verify && padSz >= 0) { +#if !defined(WOLFSSL_NO_HASH_RAW) && !defined(HAVE_FIPS) + #ifdef HAVE_BLAKE2 + if (wolfSSL_GetHmacType(ssl) == WC_HASH_TYPE_BLAKE2B) { + ret = Hmac_UpdateFinal(&hmac, digest, in, sz + + ssl->specs.hash_size + padSz + 1, + myInner); + } + else + #endif + { + ret = Hmac_UpdateFinal_CT(&hmac, digest, in, sz + + ssl->specs.hash_size + padSz + 1, + myInner); + } +#else + ret = Hmac_UpdateFinal(&hmac, digest, in, sz + + ssl->specs.hash_size + padSz + 1, + myInner); +#endif + } + else { + ret = wc_HmacUpdate(&hmac, myInner, sizeof(myInner)); + if (ret == 0) + ret = wc_HmacUpdate(&hmac, in, sz); /* content */ + if (ret == 0) + ret = wc_HmacFinal(&hmac, digest); + } } + wc_HmacFree(&hmac); return ret; diff --git a/wolfcrypt/src/misc.c b/wolfcrypt/src/misc.c index 8cfe780ae..f5017e356 100644 --- a/wolfcrypt/src/misc.c +++ b/wolfcrypt/src/misc.c @@ -311,6 +311,48 @@ STATIC INLINE word32 btoi(byte b) } +/* Constant time - mask set when a > b. */ +STATIC INLINE byte ctMaskGT(int a, int b) +{ + return (((word32)a - b - 1) >> 31) - 1; +} + +/* Constant time - mask set when a >= b. */ +STATIC INLINE byte ctMaskGTE(int a, int b) +{ + return (((word32)a - b ) >> 31) - 1; +} + +/* Constant time - mask set when a < b. */ +STATIC INLINE byte ctMaskLT(int a, int b) +{ + return (((word32)b - a - 1) >> 31) - 1; +} + +/* Constant time - mask set when a <= b. */ +STATIC INLINE byte ctMaskLTE(int a, int b) +{ + return (((word32)b - a ) >> 31) - 1; +} + +/* Constant time - mask set when a == b. */ +STATIC INLINE byte ctMaskEq(int a, int b) +{ + return 0 - (a == b); +} + +/* Constant time - select b when mask is set and a otherwise. */ +STATIC INLINE byte ctMaskSel(byte m, byte a, byte b) +{ + return (a & ~m) | (b & m); +} + +/* Constant time - bit set when a <= b. */ +STATIC INLINE byte ctSetLTE(int a, int b) +{ + return ((word32)a - b - 1) >> 31; +} + #undef STATIC diff --git a/wolfcrypt/src/sha.c b/wolfcrypt/src/sha.c index 3a4a97376..15fc5e9a3 100644 --- a/wolfcrypt/src/sha.c +++ b/wolfcrypt/src/sha.c @@ -431,6 +431,20 @@ int wc_ShaUpdate(wc_Sha* sha, const byte* data, word32 len) return 0; } +int wc_ShaFinalRaw(wc_Sha* sha, byte* hash) +{ + if (sha == NULL || hash == NULL) { + return BAD_FUNC_ARG; + } + + XMEMCPY(hash, sha->digest, WC_SHA_DIGEST_SIZE); +#ifdef LITTLE_ENDIAN_ORDER + ByteReverseWords((word32*)hash, (word32*)hash, WC_SHA_DIGEST_SIZE); +#endif + + return 0; +} + int wc_ShaFinal(wc_Sha* sha, byte* hash) { byte* local; diff --git a/wolfcrypt/src/sha256.c b/wolfcrypt/src/sha256.c index 731e1605f..c6be6a40e 100644 --- a/wolfcrypt/src/sha256.c +++ b/wolfcrypt/src/sha256.c @@ -765,6 +765,20 @@ static int InitSha256(wc_Sha256* sha256) return XTRANSFORM(sha256); } + int wc_Sha256FinalRaw(wc_Sha256* sha256, byte* hash) + { + if (sha256 == NULL || hash == NULL) { + return BAD_FUNC_ARG; + } + + XMEMCPY(hash, sha256->digest, WC_SHA256_DIGEST_SIZE); + #if defined(LITTLE_ENDIAN_ORDER) + ByteReverseWords((word32*)hash, (word32*)hash, WC_SHA256_DIGEST_SIZE); + #endif + + return 0; + } + int wc_Sha256Final(wc_Sha256* sha256, byte* hash) { int ret; diff --git a/wolfcrypt/src/sha512.c b/wolfcrypt/src/sha512.c index 9def45576..7b14a59eb 100644 --- a/wolfcrypt/src/sha512.c +++ b/wolfcrypt/src/sha512.c @@ -695,6 +695,20 @@ static INLINE int Sha512Final(wc_Sha512* sha512) return 0; } +int wc_Sha512FinalRaw(wc_Sha512* sha512, byte* hash) +{ + if (sha512 == NULL || hash == NULL) { + return BAD_FUNC_ARG; + } + + XMEMCPY(hash, sha512->digest, WC_SHA512_DIGEST_SIZE); +#if defined(LITTLE_ENDIAN_ORDER) + ByteReverseWords64((word64*)hash, (word64*)hash, WC_SHA512_DIGEST_SIZE); +#endif + + return 0; +} + int wc_Sha512Final(wc_Sha512* sha512, byte* hash) { int ret; @@ -2588,6 +2602,20 @@ int wc_Sha384Update(wc_Sha384* sha384, const byte* data, word32 len) } +int wc_Sha384FinalRaw(wc_Sha384* sha384, byte* hash) +{ + if (sha384 == NULL || hash == NULL) { + return BAD_FUNC_ARG; + } + + XMEMCPY(hash, sha384->digest, WC_SHA384_DIGEST_SIZE); +#if defined(LITTLE_ENDIAN_ORDER) + ByteReverseWords64((word64*)hash, (word64*)hash, WC_SHA384_DIGEST_SIZE); +#endif + + return 0; +} + int wc_Sha384Final(wc_Sha384* sha384, byte* hash) { int ret; diff --git a/wolfssl/internal.h b/wolfssl/internal.h index c9ef6413d..7b15cf307 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -1095,10 +1095,6 @@ enum Misc { PAD_MD5 = 48, /* pad length for finished */ PAD_SHA = 40, /* pad length for finished */ MAX_PAD_SIZE = 256, /* maximum length of padding */ - COMPRESS_DUMMY_SIZE = 64, /* compression dummy round size */ - COMPRESS_CONSTANT = 13, /* compression calc constant */ - COMPRESS_UPPER = 55, /* compression calc numerator */ - COMPRESS_LOWER = 64, /* compression calc denominator */ LENGTH_SZ = 2, /* length field for HMAC, data only */ VERSION_SZ = 2, /* length of proctocol version */ @@ -1181,6 +1177,7 @@ enum Misc { OPAQUE8_LEN + WC_MAX_DIGEST_SIZE, MAX_REQUEST_SZ = 256, /* Maximum cert req len (no auth yet */ SESSION_FLUSH_COUNT = 256, /* Flush session cache unless user turns off */ + TLS_MAX_PAD_SZ = 255, /* Max padding in TLS */ #ifdef HAVE_FIPS MAX_SYM_KEY_SIZE = AES_256_KEY_SIZE, @@ -1550,6 +1547,8 @@ WOLFSSL_LOCAL int DoTls13ServerHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx, word32 helloSz, byte* extMsgType); #endif +int TimingPadVerify(WOLFSSL* ssl, const byte* input, int padLen, int t, + int pLen, int content); enum { @@ -2853,7 +2852,7 @@ WOLFSSL_SESSION* GetSession(WOLFSSL*, byte*, byte); WOLFSSL_LOCAL int SetSession(WOLFSSL*, WOLFSSL_SESSION*); -typedef int (*hmacfp) (WOLFSSL*, byte*, const byte*, word32, int, int); +typedef int (*hmacfp) (WOLFSSL*, byte*, const byte*, word32, int, int, int); #ifndef NO_CLIENT_CACHE WOLFSSL_SESSION* GetSessionClient(WOLFSSL*, const byte*, int); @@ -3942,7 +3941,7 @@ WOLFSSL_LOCAL int GrowInputBuffer(WOLFSSL* ssl, int size, int usedLength); #ifndef NO_TLS WOLFSSL_LOCAL int MakeTlsMasterSecret(WOLFSSL*); WOLFSSL_LOCAL int TLS_hmac(WOLFSSL* ssl, byte* digest, const byte* in, - word32 sz, int content, int verify); + word32 sz, int padSz, int content, int verify); #endif #ifndef NO_WOLFSSL_CLIENT diff --git a/wolfssl/wolfcrypt/misc.h b/wolfssl/wolfcrypt/misc.h index ea86dd707..7cf4cff2a 100644 --- a/wolfssl/wolfcrypt/misc.h +++ b/wolfssl/wolfcrypt/misc.h @@ -91,6 +91,15 @@ void ato24(const byte* c, word32* u24); void ato32(const byte* c, word32* u32); word32 btoi(byte b); + +WOLFSSL_LOCAL byte ctMaskGT(int a, int b); +WOLFSSL_LOCAL byte ctMaskGTE(int a, int b); +WOLFSSL_LOCAL byte ctMaskLT(int a, int b); +WOLFSSL_LOCAL byte ctMaskLTE(int a, int b); +WOLFSSL_LOCAL byte ctMaskEq(int a, int b); +WOLFSSL_LOCAL byte ctMaskSel(byte m, byte a, byte b); +WOLFSSL_LOCAL byte ctSetLTE(int a, int b); + #endif /* NO_INLINE */ diff --git a/wolfssl/wolfcrypt/port/caam/wolfcaam_sha.h b/wolfssl/wolfcrypt/port/caam/wolfcaam_sha.h index cb4b08781..95ddf55bf 100644 --- a/wolfssl/wolfcrypt/port/caam/wolfcaam_sha.h +++ b/wolfssl/wolfcrypt/port/caam/wolfcaam_sha.h @@ -28,6 +28,8 @@ #include +#define WOLFSSL_NO_HASH_RAW + #ifndef WC_CAAM_CTXLEN /* last 8 bytes of context is for length */ #define WC_CAAM_CTXLEN 8 diff --git a/wolfssl/wolfcrypt/port/pic32/pic32mz-crypt.h b/wolfssl/wolfcrypt/port/pic32/pic32mz-crypt.h index 1eae5837a..354c832c4 100644 --- a/wolfssl/wolfcrypt/port/pic32/pic32mz-crypt.h +++ b/wolfssl/wolfcrypt/port/pic32/pic32mz-crypt.h @@ -196,6 +196,8 @@ int wc_Pic32DesCrypt(word32 *key, int keyLen, word32 *iv, int ivLen, #endif #ifdef WOLFSSL_PIC32MZ_HASH +#define WOLFSSL_NO_HASH_RAW + int wc_Pic32Hash(const byte* in, int inLen, word32* out, int outLen, int algo); int wc_Pic32HashCopy(hashUpdCache* src, hashUpdCache* dst); #endif diff --git a/wolfssl/wolfcrypt/port/st/stm32.h b/wolfssl/wolfcrypt/port/st/stm32.h index 2c82b4760..40629aaf6 100644 --- a/wolfssl/wolfcrypt/port/st/stm32.h +++ b/wolfssl/wolfcrypt/port/st/stm32.h @@ -24,6 +24,8 @@ #ifdef STM32_HASH +#define WOLFSSL_NO_HASH_RAW + /* Generic STM32 Hashing Function */ /* Supports CubeMX HAL or Standard Peripheral Library */ diff --git a/wolfssl/wolfcrypt/port/ti/ti-hash.h b/wolfssl/wolfcrypt/port/ti/ti-hash.h index 361993896..d42404e01 100644 --- a/wolfssl/wolfcrypt/port/ti/ti-hash.h +++ b/wolfssl/wolfcrypt/port/ti/ti-hash.h @@ -33,6 +33,8 @@ #define WOLFSSL_MAX_HASH_SIZE 64 #endif +#define WOLFSSL_NO_HASH_RAW + typedef struct { byte *msg; word32 used; diff --git a/wolfssl/wolfcrypt/sha.h b/wolfssl/wolfcrypt/sha.h index 6d08cf5eb..5357cce6f 100644 --- a/wolfssl/wolfcrypt/sha.h +++ b/wolfssl/wolfcrypt/sha.h @@ -122,6 +122,7 @@ typedef struct wc_Sha { WOLFSSL_API int wc_InitSha(wc_Sha*); WOLFSSL_API int wc_InitSha_ex(wc_Sha* sha, void* heap, int devId); WOLFSSL_API int wc_ShaUpdate(wc_Sha*, const byte*, word32); +WOLFSSL_API int wc_ShaFinalRaw(wc_Sha*, byte*); WOLFSSL_API int wc_ShaFinal(wc_Sha*, byte*); WOLFSSL_API void wc_ShaFree(wc_Sha*); diff --git a/wolfssl/wolfcrypt/sha256.h b/wolfssl/wolfcrypt/sha256.h index 3409b5151..4667143fe 100644 --- a/wolfssl/wolfcrypt/sha256.h +++ b/wolfssl/wolfcrypt/sha256.h @@ -139,6 +139,7 @@ typedef struct wc_Sha256 { WOLFSSL_API int wc_InitSha256(wc_Sha256*); WOLFSSL_API int wc_InitSha256_ex(wc_Sha256*, void*, int); WOLFSSL_API int wc_Sha256Update(wc_Sha256*, const byte*, word32); +WOLFSSL_API int wc_Sha256FinalRaw(wc_Sha256*, byte*); WOLFSSL_API int wc_Sha256Final(wc_Sha256*, byte*); WOLFSSL_API void wc_Sha256Free(wc_Sha256*); diff --git a/wolfssl/wolfcrypt/sha512.h b/wolfssl/wolfcrypt/sha512.h index 315f56df0..88ea52457 100644 --- a/wolfssl/wolfcrypt/sha512.h +++ b/wolfssl/wolfcrypt/sha512.h @@ -112,6 +112,7 @@ typedef struct wc_Sha512 { WOLFSSL_API int wc_InitSha512(wc_Sha512*); WOLFSSL_API int wc_InitSha512_ex(wc_Sha512*, void*, int); WOLFSSL_API int wc_Sha512Update(wc_Sha512*, const byte*, word32); +WOLFSSL_API int wc_Sha512FinalRaw(wc_Sha512*, byte*); WOLFSSL_API int wc_Sha512Final(wc_Sha512*, byte*); WOLFSSL_API void wc_Sha512Free(wc_Sha512*); @@ -144,6 +145,7 @@ typedef wc_Sha512 wc_Sha384; WOLFSSL_API int wc_InitSha384(wc_Sha384*); WOLFSSL_API int wc_InitSha384_ex(wc_Sha384*, void*, int); WOLFSSL_API int wc_Sha384Update(wc_Sha384*, const byte*, word32); +WOLFSSL_API int wc_Sha384FinalRaw(wc_Sha384*, byte*); WOLFSSL_API int wc_Sha384Final(wc_Sha384*, byte*); WOLFSSL_API void wc_Sha384Free(wc_Sha384*);