diff --git a/src/wh_server_keystore.c b/src/wh_server_keystore.c index ab8c06cc..565975dd 100644 --- a/src/wh_server_keystore.c +++ b/src/wh_server_keystore.c @@ -997,8 +997,8 @@ static int _AesGcmKeyUnwrap(whServerContext* server, uint16_t serverKeyId, uint8_t* serverKey; uint32_t serverKeySz; whNvmMetadata* serverKeyMetadata; - uint8_t* encBlob = (uint8_t*)wrappedKeyIn + sizeof(iv) + sizeof(authTag); - uint16_t encBlobSz = wrappedKeySz - sizeof(iv) - sizeof(authTag); + uint8_t* encBlob; + uint16_t encBlobSz; uint8_t plainBlob[sizeof(*metadataOut) + WOLFHSM_CFG_KEYWRAP_MAX_KEY_SIZE]; if (server == NULL || wrappedKeyIn == NULL || metadataOut == NULL || @@ -1006,6 +1006,13 @@ static int _AesGcmKeyUnwrap(whServerContext* server, uint16_t serverKeyId, return WH_ERROR_BADARGS; } + if (wrappedKeySz < sizeof(iv) + sizeof(authTag)) { + return WH_ERROR_BADARGS; + } + + encBlob = (uint8_t*)wrappedKeyIn + sizeof(iv) + sizeof(authTag); + encBlobSz = wrappedKeySz - sizeof(iv) - sizeof(authTag); + /* Get the server side key */ ret = wh_Server_KeystoreFreshenKey(server, serverKeyId, @@ -1133,14 +1140,21 @@ static int _AesGcmDataUnwrap(whServerContext* server, uint16_t serverKeyId, uint8_t* serverKey; uint32_t serverKeySz; whNvmMetadata* serverKeyMetadata; - uint8_t* encBlob = (uint8_t*)wrappedDataIn + sizeof(iv) + sizeof(authTag); - uint16_t encBlobSz = wrappedDataSz - sizeof(iv) - sizeof(authTag); + uint8_t* encBlob; + uint16_t encBlobSz; if (server == NULL || wrappedDataIn == NULL || dataOut == NULL || dataSz > WOLFHSM_CFG_KEYWRAP_MAX_DATA_SIZE) { return WH_ERROR_BADARGS; } + if (wrappedDataSz < sizeof(iv) + sizeof(authTag)) { + return WH_ERROR_BADARGS; + } + + encBlob = (uint8_t*)wrappedDataIn + sizeof(iv) + sizeof(authTag); + encBlobSz = wrappedDataSz - sizeof(iv) - sizeof(authTag); + /* Get the server side key */ ret = wh_Server_KeystoreFreshenKey(server, serverKeyId, &serverKey, &serverKeyMetadata); @@ -1306,8 +1320,15 @@ static int _HandleKeyUnwrapAndExportRequest( #ifndef NO_AES #ifdef HAVE_AESGCM case WC_CIPHER_AES_GCM: { - uint16_t keySz = req->wrappedKeySz - - WH_KEYWRAP_AES_GCM_HEADER_SIZE - sizeof(*metadata); + uint16_t keySz; + + if (req->wrappedKeySz < WH_KEYWRAP_AES_GCM_HEADER_SIZE + + sizeof(*metadata)) { + return WH_ERROR_BADARGS; + } + + keySz = req->wrappedKeySz - + WH_KEYWRAP_AES_GCM_HEADER_SIZE - sizeof(*metadata); /* Check if the response data can fit the metadata + key */ if (respDataSz < sizeof(*metadata) + keySz) { @@ -1415,6 +1436,11 @@ static int _HandleKeyUnwrapAndCacheRequest( #ifndef NO_AES #ifdef HAVE_AESGCM case WC_CIPHER_AES_GCM: { + if (req->wrappedKeySz < WH_KEYWRAP_AES_GCM_HEADER_SIZE + + sizeof(metadata)) { + return WH_ERROR_BADARGS; + } + keySz = req->wrappedKeySz - WH_KEYWRAP_AES_GCM_HEADER_SIZE - sizeof(metadata); resp->cipherType = WC_CIPHER_AES_GCM; @@ -1595,8 +1621,13 @@ static int _HandleDataUnwrapRequest(whServerContext* server, #ifndef NO_AES #ifdef HAVE_AESGCM case WC_CIPHER_AES_GCM: { - uint16_t dataSz = - req->wrappedDataSz - WH_KEYWRAP_AES_GCM_HEADER_SIZE; + uint16_t dataSz; + + if (req->wrappedDataSz < WH_KEYWRAP_AES_GCM_HEADER_SIZE) { + return WH_ERROR_BADARGS; + } + + dataSz = req->wrappedDataSz - WH_KEYWRAP_AES_GCM_HEADER_SIZE; /* Check if the response data can fit the unwrapped data */ if (respDataSz < dataSz) { diff --git a/test/wh_test_crypto.c b/test/wh_test_crypto.c index e72ae6a4..f1a3aad0 100644 --- a/test/wh_test_crypto.c +++ b/test/wh_test_crypto.c @@ -5614,9 +5614,11 @@ int whTest_CryptoClientConfig(whClientConfig* config) #ifdef WOLFHSM_CFG_KEYWRAP if (ret == 0) { - /* Test keywrap functionality */ ret = whTest_Client_KeyWrap(client); } + if (ret == 0) { + ret = whTest_Client_DataWrap(client); + } #endif #ifndef NO_AES diff --git a/test/wh_test_keywrap.c b/test/wh_test_keywrap.c index 6d675217..972c9b06 100644 --- a/test/wh_test_keywrap.c +++ b/test/wh_test_keywrap.c @@ -257,6 +257,84 @@ static int _AesGcm_TestDataWrap(whClientContext* client) return ret; } +static int _AesGcm_TestKeyUnwrapUnderflow(whClientContext* client) +{ + int ret; + uint8_t dummyBuf[1] = {0}; + whNvmMetadata tmpMetadata = {0}; + uint8_t tmpKey[WH_TEST_AES_KEYSIZE] = {0}; + uint16_t tmpKeySz = sizeof(tmpKey); + whKeyId wrappedKeyId = WH_KEYID_ERASED; + + /* wrappedKeySz=0: must return WH_ERROR_BADARGS, not underflow */ + ret = wh_Client_KeyUnwrapAndExport(client, WC_CIPHER_AES_GCM, WH_TEST_KEKID, + dummyBuf, 0, &tmpMetadata, tmpKey, + &tmpKeySz); + if (ret != WH_ERROR_BADARGS) { + WH_ERROR_PRINT("KeyUnwrapAndExport(sz=0) expected BADARGS, got %d\n", + ret); + return WH_TEST_FAIL; + } + + /* wrappedKeySz=1: must return WH_ERROR_BADARGS, not underflow */ + tmpKeySz = sizeof(tmpKey); + ret = wh_Client_KeyUnwrapAndExport(client, WC_CIPHER_AES_GCM, WH_TEST_KEKID, + dummyBuf, 1, &tmpMetadata, tmpKey, + &tmpKeySz); + if (ret != WH_ERROR_BADARGS) { + WH_ERROR_PRINT("KeyUnwrapAndExport(sz=1) expected BADARGS, got %d\n", + ret); + return WH_TEST_FAIL; + } + + /* wrappedKeySz=0: test KeyUnwrapAndCache path */ + ret = wh_Client_KeyUnwrapAndCache(client, WC_CIPHER_AES_GCM, WH_TEST_KEKID, + dummyBuf, 0, &wrappedKeyId); + if (ret != WH_ERROR_BADARGS) { + WH_ERROR_PRINT("KeyUnwrapAndCache(sz=0) expected BADARGS, got %d\n", + ret); + return WH_TEST_FAIL; + } + + /* wrappedKeySz=1: test KeyUnwrapAndCache path */ + ret = wh_Client_KeyUnwrapAndCache(client, WC_CIPHER_AES_GCM, WH_TEST_KEKID, + dummyBuf, 1, &wrappedKeyId); + if (ret != WH_ERROR_BADARGS) { + WH_ERROR_PRINT("KeyUnwrapAndCache(sz=1) expected BADARGS, got %d\n", + ret); + return WH_TEST_FAIL; + } + + return WH_ERROR_OK; +} + +static int _AesGcm_TestDataUnwrapUnderflow(whClientContext* client) +{ + int ret; + uint8_t dummyBuf[1] = {0}; + uint8_t outBuf[32] = {0}; + uint32_t outSz = sizeof(outBuf); + + /* wrappedDataSz=0: must return WH_ERROR_BADARGS, not underflow */ + ret = wh_Client_DataUnwrap(client, WC_CIPHER_AES_GCM, WH_TEST_KEKID, + dummyBuf, 0, outBuf, &outSz); + if (ret != WH_ERROR_BADARGS) { + WH_ERROR_PRINT("DataUnwrap(sz=0) expected BADARGS, got %d\n", ret); + return WH_TEST_FAIL; + } + + /* wrappedDataSz=1: must return WH_ERROR_BADARGS, not underflow */ + outSz = sizeof(outBuf); + ret = wh_Client_DataUnwrap(client, WC_CIPHER_AES_GCM, WH_TEST_KEKID, + dummyBuf, 1, outBuf, &outSz); + if (ret != WH_ERROR_BADARGS) { + WH_ERROR_PRINT("DataUnwrap(sz=1) expected BADARGS, got %d\n", ret); + return WH_TEST_FAIL; + } + + return WH_ERROR_OK; +} + #endif /* HAVE_AESGCM */ int whTest_Client_KeyWrap(whClientContext* client) @@ -281,6 +359,14 @@ int whTest_Client_KeyWrap(whClientContext* client) if (ret != WH_ERROR_OK) { WH_ERROR_PRINT("Failed to _AesGcm_TestKeyWrap %d\n", ret); } + + if (ret == WH_ERROR_OK) { + ret = _AesGcm_TestKeyUnwrapUnderflow(client); + if (ret != WH_ERROR_OK) { + WH_ERROR_PRINT("Failed to _AesGcm_TestKeyUnwrapUnderflow %d\n", + ret); + } + } #endif _CleanupServerKek(client); @@ -304,6 +390,14 @@ int whTest_Client_DataWrap(whClientContext* client) if (ret != WH_ERROR_OK) { WH_ERROR_PRINT("Failed to _AesGcm_TestDataWrap %d\n", ret); } + + if (ret == WH_ERROR_OK) { + ret = _AesGcm_TestDataUnwrapUnderflow(client); + if (ret != WH_ERROR_OK) { + WH_ERROR_PRINT("Failed to _AesGcm_TestDataUnwrapUnderflow %d\n", + ret); + } + } #endif _CleanupServerKek(client); diff --git a/test/wh_test_keywrap.h b/test/wh_test_keywrap.h index 94ed032e..955fe8e1 100644 --- a/test/wh_test_keywrap.h +++ b/test/wh_test_keywrap.h @@ -23,6 +23,7 @@ #include "wolfhsm/wh_client.h" int whTest_Client_KeyWrap(whClientContext* ctx); +int whTest_Client_DataWrap(whClientContext* ctx); int whTest_KeyWrapClientConfig(whClientConfig* cf); #endif /* WH_TEST_COMM_H_ */