Constant time padding and HMAC verification in TLS

pull/1573/head
Sean Parkinson 2018-05-11 16:11:01 +10:00
parent cc58d3160f
commit e684156a1e
15 changed files with 708 additions and 249 deletions

View File

@ -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);

484
src/tls.c
View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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 */

View File

@ -28,6 +28,8 @@
#include <wolfssl/wolfcrypt/types.h>
#define WOLFSSL_NO_HASH_RAW
#ifndef WC_CAAM_CTXLEN
/* last 8 bytes of context is for length */
#define WC_CAAM_CTXLEN 8

View File

@ -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

View File

@ -24,6 +24,8 @@
#ifdef STM32_HASH
#define WOLFSSL_NO_HASH_RAW
/* Generic STM32 Hashing Function */
/* Supports CubeMX HAL or Standard Peripheral Library */

View File

@ -33,6 +33,8 @@
#define WOLFSSL_MAX_HASH_SIZE 64
#endif
#define WOLFSSL_NO_HASH_RAW
typedef struct {
byte *msg;
word32 used;

View File

@ -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*);

View File

@ -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*);

View File

@ -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*);