Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 55 additions & 36 deletions src/wh_server_crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -2348,22 +2348,33 @@ static int _HandleAesCtr(whServerContext* ctx, uint16_t magic, int devId,
ret = wc_AesSetKeyDirect(aes, (byte*)key, (word32)key_len, (byte*)iv,
enc != 0 ? AES_ENCRYPTION : AES_DECRYPTION);
if (ret == WH_ERROR_OK) {
/* do the crypto operation; also restore previous left */
aes->left = left;
memcpy(aes->tmp, tmp, sizeof(aes->tmp));
if (enc != 0) {
ret = wc_AesCtrEncrypt(aes, (byte*)out, (byte*)in, (word32)len);
if (ret == WH_ERROR_OK) {
WH_DEBUG_VERBOSE_HEXDUMP("[AesCtr] Encrypted output",
out, len);
}
/* Reject client-supplied left values outside the valid range.
* wc_AesCtrEncrypt indexes aes->tmp via AES_BLOCK_SIZE - aes->left;
* an out-of-range value causes an out-of-bounds read that could
* disclose server-side memory across the HSM trust boundary. */
if (left > AES_BLOCK_SIZE) {
ret = WH_ERROR_BADARGS;
}
else {
/* CTR uses the same function for encrypt and decrypt */
ret = wc_AesCtrEncrypt(aes, (byte*)out, (byte*)in, (word32)len);
if (ret == WH_ERROR_OK) {
WH_DEBUG_VERBOSE_HEXDUMP("[AesCtr] Decrypted output",
out, len);
/* Restore streaming CTR context from the previous call. */
aes->left = left;
memcpy(aes->tmp, tmp, sizeof(aes->tmp));
if (enc != 0) {
ret = wc_AesCtrEncrypt(aes, (byte*)out, (byte*)in,
(word32)len);
if (ret == WH_ERROR_OK) {
WH_DEBUG_VERBOSE_HEXDUMP("[AesCtr] Encrypted output",
out, len);
}
}
else {
/* CTR uses the same function for encrypt and decrypt */
ret = wc_AesCtrEncrypt(aes, (byte*)out, (byte*)in,
(word32)len);
if (ret == WH_ERROR_OK) {
WH_DEBUG_VERBOSE_HEXDUMP("[AesCtr] Decrypted output",
out, len);
}
}
}
}
Expand Down Expand Up @@ -2509,33 +2520,41 @@ static int _HandleAesCtrDma(whServerContext* ctx, uint16_t magic, int devId,
ret = wc_AesSetKeyDirect(aes, (byte*)key, (word32)keyLen, (byte*)iv,
enc != 0 ? AES_ENCRYPTION : AES_DECRYPTION);
if (ret == WH_ERROR_OK) {
/* do the crypto operation */
/* restore previous left */
aes->left = left;
memcpy(aes->tmp, tmp, sizeof(aes->tmp));
if (enc != 0) {
ret = wc_AesCtrEncrypt(aes, (byte*)outAddr, (byte*)inAddr,
(word32)len);
if (ret == WH_ERROR_OK) {
WH_DEBUG_VERBOSE_HEXDUMP("[AesCtr] Encrypted output",
outAddr, len);
}
/* Reject client-supplied left values outside the valid range.
* wc_AesCtrEncrypt indexes aes->tmp via AES_BLOCK_SIZE - aes->left;
* an out-of-range value causes an out-of-bounds read that could
* disclose server-side memory across the HSM trust boundary. */
if (left > AES_BLOCK_SIZE) {
ret = WH_ERROR_BADARGS;
}
else {
/* CTR uses the same function for encrypt and decrypt */
ret = wc_AesCtrEncrypt(aes, (byte*)outAddr, (byte*)inAddr,
(word32)len);
/* Restore streaming CTR context from the previous call. */
aes->left = left;
memcpy(aes->tmp, tmp, sizeof(aes->tmp));
if (enc != 0) {
ret = wc_AesCtrEncrypt(aes, (byte*)outAddr, (byte*)inAddr,
(word32)len);
if (ret == WH_ERROR_OK) {
WH_DEBUG_VERBOSE_HEXDUMP("[AesCtr] Encrypted output",
outAddr, len);
}
}
else {
/* CTR uses the same function for encrypt and decrypt */
ret = wc_AesCtrEncrypt(aes, (byte*)outAddr, (byte*)inAddr,
(word32)len);
if (ret == WH_ERROR_OK) {
WH_DEBUG_VERBOSE_HEXDUMP("[AesCtr] Decrypted output",
outAddr, len);
}
}
if (ret == WH_ERROR_OK) {
WH_DEBUG_VERBOSE_HEXDUMP("[AesCtr] Decrypted output",
outAddr, len);
left = aes->left;
outSz = len;
memcpy(out_tmp, aes->tmp, AES_BLOCK_SIZE);
memcpy(out_iv, aes->reg, AES_IV_SIZE);
}
}
if (ret == WH_ERROR_OK) {
left = aes->left;
outSz = len;
memcpy(out_tmp, aes->tmp, AES_BLOCK_SIZE);
memcpy(out_iv, aes->reg, AES_IV_SIZE);
}
}
}

Expand Down
86 changes: 86 additions & 0 deletions test-refactor/client-server/wh_test_crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,92 @@ int whTest_CryptoRsaBufferTooSmall(whClientContext* ctx)
#endif /* !NO_RSA */


#if !defined(NO_AES) && defined(WOLFSSL_AES_COUNTER)
/* Verifies that wh_Client_AesCtr (and wh_Client_AesCtrDma when DMA is
* enabled) reject aes->left > AES_BLOCK_SIZE with WH_ERROR_BADARGS.
* wc_AesCtrEncrypt indexes aes->tmp via AES_BLOCK_SIZE - aes->left; an
* oversized value would cause an out-of-bounds read disclosing server-side
* memory across the HSM trust boundary. */
int whTest_CryptoAesCtrLeftOob(whClientContext* ctx)
{
int devId = WH_DEV_ID;
int ret = 0;
int tmp;
Aes aes[1];
uint8_t cipher[AES_BLOCK_SIZE] = {0};
const uint8_t key[] = {0x2b, 0x7e, 0x15, 0x16,
0x28, 0xae, 0xd2, 0xa6,
0xab, 0xf7, 0x15, 0x88,
0x09, 0xcf, 0x4f, 0x3c};
const uint8_t iv[AES_BLOCK_SIZE] = {0x00, 0x01, 0x02, 0x03,
0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b,
0x0c, 0x0d, 0x0e, 0x0f};
const uint8_t plainIn[AES_BLOCK_SIZE] = {0x6b, 0xc1, 0xbe, 0xe2,
0x2e, 0x40, 0x9f, 0x96,
0xe9, 0x3d, 0x7e, 0x11,
0x73, 0x93, 0x17, 0x2a};

ret = wc_AesInit(aes, NULL, devId);
if (ret != 0) {
WH_ERROR_PRINT("Failed to wc_AesInit %d\n", ret);
}
else {
ret = wc_AesSetKeyDirect(aes, key, sizeof(key), iv, AES_ENCRYPTION);
if (ret != 0) {
WH_ERROR_PRINT("Failed to wc_AesSetKeyDirect %d\n", ret);
}
else {
aes->left = AES_BLOCK_SIZE + 1;
tmp = wh_Client_AesCtr(ctx, aes, 1, plainIn, sizeof(plainIn),
cipher);
if (tmp != WH_ERROR_BADARGS) {
WH_ERROR_PRINT(
"AES-CTR: left > AES_BLOCK_SIZE should be BADARGS, "
"got %d\n",
tmp);
ret = -1;
}
}
(void)wc_AesFree(aes);
}

#ifdef WOLFHSM_CFG_DMA
if (ret == 0) {
ret = wc_AesInit(aes, NULL, devId);
if (ret != 0) {
WH_ERROR_PRINT("Failed to wc_AesInit %d\n", ret);
}
else {
ret = wc_AesSetKeyDirect(aes, key, sizeof(key), iv, AES_ENCRYPTION);
if (ret != 0) {
WH_ERROR_PRINT("Failed to wc_AesSetKeyDirect %d\n", ret);
}
else {
aes->left = AES_BLOCK_SIZE + 1;
tmp = wh_Client_AesCtrDma(ctx, aes, 1, plainIn,
sizeof(plainIn), cipher);
if (tmp != WH_ERROR_BADARGS) {
WH_ERROR_PRINT(
"AES-CTR DMA: left > AES_BLOCK_SIZE should be "
"BADARGS, got %d\n",
tmp);
ret = -1;
}
}
(void)wc_AesFree(aes);
}
}
#endif /* WOLFHSM_CFG_DMA */

if (ret == 0) {
WH_TEST_PRINT("AES CTR left OOB DEVID=0x%X SUCCESS\n", devId);
}
return ret;
}
#endif /* !NO_AES && WOLFSSL_AES_COUNTER */


#if defined(HAVE_DILITHIUM) && \
!defined(WOLFSSL_DILITHIUM_NO_SIGN) && \
!defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) && !defined(WOLFSSL_NO_ML_DSA_44)
Expand Down
2 changes: 2 additions & 0 deletions test-refactor/wh_test_list.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ WH_TEST_DECL(whTest_Dma);
WH_TEST_DECL(whTest_CertVerify);
WH_TEST_DECL(whTest_ClientCerts);
WH_TEST_DECL(whTest_CryptoAes);
WH_TEST_DECL(whTest_CryptoAesCtrLeftOob);
WH_TEST_DECL(whTest_CryptoEcc256);
WH_TEST_DECL(whTest_CryptoEd25519BufferTooSmall);
WH_TEST_DECL(whTest_CryptoMlDsaBufferTooSmall);
Expand All @@ -58,6 +59,7 @@ const size_t whTestsServerCount = sizeof(whTestsServer) / sizeof(whTestsServer[0
const whTestCase whTestsClient[] = {
{ "whTest_ClientCerts", whTest_ClientCerts },
{ "whTest_CryptoAes", whTest_CryptoAes },
{ "whTest_CryptoAesCtrLeftOob", whTest_CryptoAesCtrLeftOob },
{ "whTest_CryptoEcc256", whTest_CryptoEcc256 },
{ "whTest_CryptoEd25519BufferTooSmall",
whTest_CryptoEd25519BufferTooSmall },
Expand Down
47 changes: 47 additions & 0 deletions test/wh_test_crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -7375,6 +7375,31 @@ static int whTest_CryptoAesAsync(whClientContext* ctx, int devId, WC_RNG* rng)
}
(void)wc_AesFree(aes);
}

/* CTR: server must reject left > AES_BLOCK_SIZE.
* wc_AesCtrEncrypt indexes aes->tmp via AES_BLOCK_SIZE - aes->left;
* an oversized client-supplied value would cause an out-of-bounds read
* disclosing server-side memory across the HSM trust boundary. */
if (ret == 0) {
int tmp;
ret = wc_AesInit(aes, NULL, devId);
if (ret == 0) {
ret = wc_AesSetKeyDirect(aes, key, sizeof(key), iv, AES_ENCRYPTION);
}
if (ret == 0) {
aes->left = AES_BLOCK_SIZE + 1;
tmp = wh_Client_AesCtr(ctx, aes, 1, plainIn, sizeof(plainIn),
cipher);
if (tmp != WH_ERROR_BADARGS) {
WH_ERROR_PRINT(
"AES-CTR async: left > AES_BLOCK_SIZE should be "
"BADARGS, got %d\n",
tmp);
ret = -1;
}
}
(void)wc_AesFree(aes);
}
if (ret == 0) {
WH_TEST_PRINT("AES CTR ASYNC DEVID=0x%X SUCCESS\n", devId);
}
Expand Down Expand Up @@ -8374,6 +8399,28 @@ static int whTest_CryptoAesDmaAsync(whClientContext* ctx, int devId,
memset(cipher, 0, sizeof(cipher));
memset(plainOut, 0, sizeof(plainOut));
}

/* CTR DMA: same left > AES_BLOCK_SIZE rejection as the non-DMA path. */
if (ret == 0) {
int tmp;
ret = wc_AesInit(aes, NULL, devId);
if (ret == 0) {
ret = wc_AesSetKeyDirect(aes, key, sizeof(key), iv, AES_ENCRYPTION);
}
if (ret == 0) {
aes->left = AES_BLOCK_SIZE + 1;
tmp = wh_Client_AesCtrDma(ctx, aes, 1, plainIn, sizeof(plainIn),
cipher);
if (tmp != WH_ERROR_BADARGS) {
WH_ERROR_PRINT(
"AES-CTR DMA async: left > AES_BLOCK_SIZE should be "
"BADARGS, got %d\n",
tmp);
ret = -1;
}
}
(void)wc_AesFree(aes);
}
if (ret == 0) {
WH_TEST_PRINT("AES CTR DMA ASYNC DEVID=0x%X SUCCESS\n", devId);
}
Expand Down
Loading