From 99d96246bdd0296503f1c5887cffd67b7c5ab658 Mon Sep 17 00:00:00 2001 From: David Garske Date: Tue, 22 Sep 2020 15:04:30 -0700 Subject: [PATCH] Fix for STM32 issue with some Cube HAL versions (such as F777) which could modify non-block aligned bytes in the output buffer during decrypt. For TLS these bytes are the authentication tag. Workaround is to save off the incoming expected authentication tag. ZD 10961. --- wolfcrypt/src/aes.c | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/wolfcrypt/src/aes.c b/wolfcrypt/src/aes.c index 27b2130f8..5b0338f60 100644 --- a/wolfcrypt/src/aes.c +++ b/wolfcrypt/src/aes.c @@ -6347,12 +6347,12 @@ static int wc_AesGcmDecrypt_STM32(Aes* aes, byte* out, word32 keySize; word32 partial = sz % AES_BLOCK_SIZE; word32 tag[AES_BLOCK_SIZE/sizeof(word32)]; + word32 tagExpected[AES_BLOCK_SIZE/sizeof(word32)]; word32 partialBlock[AES_BLOCK_SIZE/sizeof(word32)]; word32 ctr[AES_BLOCK_SIZE/sizeof(word32)]; - word32 ctrInit[AES_BLOCK_SIZE/sizeof(word32)]; word32 authhdr[AES_BLOCK_SIZE/sizeof(word32)]; byte* authInPadded = NULL; - int authPadSz, wasAlloc = 0; + int authPadSz, wasAlloc = 0, tagComputed = 0; ret = wc_AesGetKeySize(aes, &keySize); if (ret != 0) @@ -6373,7 +6373,19 @@ static int wc_AesGcmDecrypt_STM32(Aes* aes, byte* out, else { GHASH(aes, NULL, 0, iv, ivSz, (byte*)ctr, AES_BLOCK_SIZE); } - XMEMCPY(ctrInit, ctr, sizeof(ctr)); /* save off initial counter for GMAC */ + + /* Make copy of expected authTag, which could get corrupted in some + * Cube HAL versions without proper partial block support. + * For TLS blocks the authTag is after the output buffer, so save it */ + XMEMCPY(tagExpected, authTag, authTagSz); + + /* for cases where hardware cannot be used for authTag calculate it */ + if (sz == 0 || partial != 0 || ivSz != GCM_NONCE_MID_SZ) { + GHASH(aes, authIn, authInSz, in, sz, (byte*)tag, sizeof(tag)); + wc_AesEncrypt(aes, (byte*)ctr, (byte*)partialBlock); + xorbuf(tag, partialBlock, sizeof(tag)); + tagComputed = 1; + } /* Authentication buffer - must be 4-byte multiple zero padded */ authPadSz = authInSz % sizeof(word32); @@ -6419,7 +6431,7 @@ static int wc_AesGcmDecrypt_STM32(Aes* aes, byte* out, /* GCM payload phase - can handle partial blocks */ status = HAL_CRYP_Decrypt(&hcryp, (uint32_t*)in, (blocks * AES_BLOCK_SIZE) + partial, (uint32_t*)out, STM32_HAL_TIMEOUT); - if (status == HAL_OK) { + if (status == HAL_OK && tagComputed == 0) { /* Compute the authTag */ status = HAL_CRYPEx_AESGCM_GenerateAuthTAG(&hcryp, (uint32_t*)tag, STM32_HAL_TIMEOUT); @@ -6457,7 +6469,7 @@ static int wc_AesGcmDecrypt_STM32(Aes* aes, byte* out, (byte*)partialBlock, STM32_HAL_TIMEOUT); XMEMCPY(out + (blocks * AES_BLOCK_SIZE), partialBlock, partial); } - if (status == HAL_OK) { + if (status == HAL_OK && tagComputed == 0) { /* GCM final phase */ hcryp.Init.GCMCMACPhase = CRYP_FINAL_PHASE; status = HAL_CRYPEx_AES_Auth(&hcryp, NULL, sz, (byte*)tag, STM32_HAL_TIMEOUT); @@ -6478,7 +6490,7 @@ static int wc_AesGcmDecrypt_STM32(Aes* aes, byte* out, (byte*)partialBlock, STM32_HAL_TIMEOUT); XMEMCPY(out + (blocks * AES_BLOCK_SIZE), partialBlock, partial); } - if (status == HAL_OK) { + if (status == HAL_OK && tagComputed == 0) { /* Compute the authTag */ status = HAL_CRYPEx_AESGCM_Finish(&hcryp, sz, (byte*)tag, STM32_HAL_TIMEOUT); } @@ -6495,25 +6507,21 @@ static int wc_AesGcmDecrypt_STM32(Aes* aes, byte* out, /* Input size and auth size need to be the actual sizes, even though * they are not block aligned, because this length (in bits) is used * in the final GHASH. */ + XMEMSET(partialBlock, 0, sizeof(partialBlock)); /* use this to get tag */ status = CRYP_AES_GCM(MODE_DECRYPT, (uint8_t*)ctr, (uint8_t*)keyCopy, keySize * 8, (uint8_t*)in, sz, (uint8_t*)authInPadded, authInSz, - (uint8_t*)out, (uint8_t*)tag); + (uint8_t*)out, (uint8_t*)partialBlock); if (status != SUCCESS) ret = AES_GCM_AUTH_E; + if (tagComputed == 0) + XMEMCPY(tag, partialBlock, authTagSz); #endif /* WOLFSSL_STM32_CUBEMX */ wolfSSL_CryptHwMutexUnLock(); - /* For STM32 GCM fallback to software if partial AES block or IV != 12 */ - if (sz == 0 || partial != 0 || ivSz != GCM_NONCE_MID_SZ) { - GHASH(aes, authIn, authInSz, in, sz, (byte*)tag, sizeof(tag)); - wc_AesEncrypt(aes, (byte*)ctrInit, (byte*)partialBlock); - xorbuf(tag, partialBlock, sizeof(tag)); - } - /* Check authentication tag */ - if (ConstantCompare(authTag, (byte*)tag, authTagSz) != 0) { + if (ConstantCompare((const byte*)tagExpected, (byte*)tag, authTagSz) != 0) { ret = AES_GCM_AUTH_E; }