Skip to content

Commit 8949da0

Browse files
Zero DMA destination buffer on server WRITE_PRE
1 parent 2d1b25a commit 8949da0

7 files changed

Lines changed: 864 additions & 23 deletions

File tree

src/wh_server_cert.c

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1273,18 +1273,8 @@ int wh_Server_HandleCertRequest(whServerContext* server, uint16_t magic,
12731273
wh_MessageCert_TranslateReadTrustedDmaRequest(
12741274
magic, (whMessageCert_ReadTrustedDmaRequest*)req_packet,
12751275
&req);
1276-
1277-
/* Process client address */
1278-
resp.rc = wh_Server_DmaProcessClientAddress(
1279-
server, req.cert_addr, &cert_data, req.cert_len,
1280-
WH_DMA_OPER_CLIENT_WRITE_PRE, (whServerDmaFlags){0});
1281-
if (resp.rc == WH_ERROR_OK) {
1282-
cert_dma_pre_ok = 1;
1283-
}
12841276
}
12851277
if (resp.rc == WH_ERROR_OK) {
1286-
/* Deny reading non-exportable or server-only (trusted KEK)
1287-
* objects; see the non-DMA path above. */
12881278
resp.rc = WH_SERVER_NVM_LOCK(server);
12891279
if (resp.rc == WH_ERROR_OK) {
12901280
resp.rc = wh_Nvm_GetMetadata(server->nvm, req.id, &meta);
@@ -1293,23 +1283,48 @@ int wh_Server_HandleCertRequest(whServerContext* server, uint16_t magic,
12931283
WH_NVM_FLAGS_SERVER_ONLY)) != 0) {
12941284
resp.rc = WH_ERROR_ACCESS;
12951285
}
1296-
else {
1297-
/* Clamp cert_len to actual stored length */
1298-
cert_len = req.cert_len;
1299-
resp.rc = wh_Server_CertReadTrusted(
1300-
server, req.id, cert_data, &cert_len);
1286+
}
1287+
/* wh_Server_CertReadTrusted() calls the unchecked
1288+
* wh_Nvm_Read(), so the check above is the only gate, and
1289+
* it precedes the bound and the map. */
1290+
if (resp.rc == WH_ERROR_OK &&
1291+
req.cert_len > WOLFHSM_CFG_MAX_CERT_SIZE) {
1292+
resp.rc = WH_ERROR_BADARGS;
1293+
}
1294+
if (resp.rc == WH_ERROR_OK) {
1295+
resp.rc = wh_Server_DmaProcessClientAddress(
1296+
server, req.cert_addr, &cert_data, req.cert_len,
1297+
WH_DMA_OPER_CLIENT_WRITE_PRE,
1298+
(whServerDmaFlags){0});
1299+
if (resp.rc == WH_ERROR_OK) {
1300+
cert_dma_pre_ok = 1;
1301+
/* POST sends cert_len but the read fills only
1302+
* meta.len, so zero the whole buffer first. */
1303+
if (cert_data == NULL) {
1304+
resp.rc = WH_ERROR_BADARGS;
1305+
}
1306+
else {
1307+
memset(cert_data, 0, req.cert_len);
1308+
}
13011309
}
13021310
}
1311+
if (resp.rc == WH_ERROR_OK) {
1312+
cert_len = req.cert_len;
1313+
resp.rc = wh_Server_CertReadTrusted(
1314+
server, req.id, cert_data, &cert_len);
1315+
}
13031316

13041317
(void)WH_SERVER_NVM_UNLOCK(server);
13051318
} /* WH_SERVER_NVM_LOCK() */
1306-
}
1307-
/* Always call POST for successful PRE, regardless of operation
1308-
* result */
1309-
if (cert_dma_pre_ok) {
1310-
(void)wh_Server_DmaProcessClientAddress(
1311-
server, req.cert_addr, &cert_data, req.cert_len,
1312-
WH_DMA_OPER_CLIENT_WRITE_POST, (whServerDmaFlags){0});
1319+
1320+
/* Always call POST for successful PRE, regardless of
1321+
* operation result. Runs outside the lock: only the PRE has
1322+
* to be ordered against the deny check. */
1323+
if (cert_dma_pre_ok) {
1324+
(void)wh_Server_DmaProcessClientAddress(
1325+
server, req.cert_addr, &cert_data, req.cert_len,
1326+
WH_DMA_OPER_CLIENT_WRITE_POST, (whServerDmaFlags){0});
1327+
}
13131328
}
13141329

13151330
/* Convert the response struct */

src/wh_server_nvm.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,16 @@ int wh_Server_HandleNvmRequest(whServerContext* server,
457457
if (rc == WH_ERROR_OK) {
458458
rc = wh_Nvm_GetMetadata(server->nvm, req.id, &meta);
459459

460+
if (rc == 0) {
461+
/* Refuse before the bound and the map, so a denied read
462+
* reports ACCESS whatever the offset and never touches
463+
* client memory. wh_Nvm_ReadChecked still enforces it. */
464+
if ((meta.flags & (WH_NVM_FLAGS_NONEXPORTABLE |
465+
WH_NVM_FLAGS_TRUSTED)) != 0) {
466+
rc = WH_ERROR_ACCESS;
467+
}
468+
}
469+
460470
if (rc == 0) {
461471
if (req.offset >= meta.len) {
462472
rc = WH_ERROR_BADARGS;
@@ -481,6 +491,14 @@ int wh_Server_HandleNvmRequest(whServerContext* server,
481491
WH_DMA_OPER_CLIENT_WRITE_PRE, (whServerDmaFlags){0});
482492
if (rc == 0) {
483493
data_dma_pre_ok = 1;
494+
/* POST sends data_len but the read fills only
495+
* read_len, so zero the whole buffer first. */
496+
if (data == NULL) {
497+
rc = WH_ERROR_BADARGS;
498+
}
499+
else {
500+
memset(data, 0, req.data_len);
501+
}
484502
}
485503
}
486504
if (rc == 0) {

test-refactor/client-server/wh_test_crypto_aes.c

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1102,6 +1102,146 @@ int whTest_CryptoAesKeyUsagePolicies(whClientContext* ctx)
11021102
return ret;
11031103
}
11041104

1105+
#if defined(WOLFHSM_CFG_DMA) && \
1106+
(defined(HAVE_AES_CBC) || defined(WOLFSSL_AES_COUNTER) || \
1107+
defined(HAVE_AES_ECB))
1108+
/* One buffer as both input and output must match out-of-place. Also fails if
1109+
* a zero-fill moves into wh_Server_DmaProcessClientAddress(): in and out map
1110+
* to one address here, so a central memset would erase the plaintext. */
1111+
static int whTest_CryptoAesDmaInPlace(whClientContext* ctx)
1112+
{
1113+
int devId = WH_CLIENT_DEVID(ctx);
1114+
int ret = 0;
1115+
Aes aes[1];
1116+
uint8_t inplace[AES_BLOCK_SIZE * 2];
1117+
uint8_t refcipher[AES_BLOCK_SIZE * 2];
1118+
const uint8_t key[] = {0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
1119+
0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c};
1120+
#if defined(HAVE_AES_CBC) || defined(WOLFSSL_AES_COUNTER)
1121+
const uint8_t iv[AES_BLOCK_SIZE] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
1122+
0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
1123+
0x0c, 0x0d, 0x0e, 0x0f};
1124+
#endif
1125+
const uint8_t plainIn[AES_BLOCK_SIZE * 2] = {
1126+
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e,
1127+
0x11, 0x73, 0x93, 0x17, 0x2a, 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03,
1128+
0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51};
1129+
1130+
#ifdef HAVE_AES_CBC
1131+
if (ret == 0) {
1132+
ret = wc_AesInit(aes, NULL, devId);
1133+
if (ret == 0) {
1134+
ret = wc_AesSetKey(aes, key, sizeof(key), iv, AES_ENCRYPTION);
1135+
if (ret == 0) {
1136+
ret = wh_Client_AesCbcDma(ctx, aes, 1, plainIn, sizeof(plainIn),
1137+
refcipher);
1138+
}
1139+
(void)wc_AesFree(aes);
1140+
}
1141+
}
1142+
if (ret == 0) {
1143+
ret = wc_AesInit(aes, NULL, devId);
1144+
if (ret == 0) {
1145+
ret = wc_AesSetKey(aes, key, sizeof(key), iv, AES_ENCRYPTION);
1146+
if (ret == 0) {
1147+
memcpy(inplace, plainIn, sizeof(plainIn));
1148+
ret = wh_Client_AesCbcDma(ctx, aes, 1, inplace, sizeof(inplace),
1149+
inplace);
1150+
}
1151+
(void)wc_AesFree(aes);
1152+
}
1153+
}
1154+
if (ret == 0 && memcmp(inplace, refcipher, sizeof(refcipher)) != 0) {
1155+
WH_ERROR_PRINT("AES-CBC DMA in-place != out-of-place\n");
1156+
ret = -1;
1157+
}
1158+
/* Decrypt is the harder direction: each ciphertext block is the next
1159+
* block's IV, so it must be captured before the output overwrites it. */
1160+
if (ret == 0) {
1161+
ret = wc_AesInit(aes, NULL, devId);
1162+
if (ret == 0) {
1163+
ret = wc_AesSetKey(aes, key, sizeof(key), iv, AES_DECRYPTION);
1164+
if (ret == 0) {
1165+
memcpy(inplace, refcipher, sizeof(refcipher));
1166+
ret = wh_Client_AesCbcDma(ctx, aes, 0, inplace, sizeof(inplace),
1167+
inplace);
1168+
}
1169+
(void)wc_AesFree(aes);
1170+
}
1171+
}
1172+
if (ret == 0 && memcmp(inplace, plainIn, sizeof(plainIn)) != 0) {
1173+
WH_ERROR_PRINT("AES-CBC DMA in-place decrypt != plaintext\n");
1174+
ret = -1;
1175+
}
1176+
#endif /* HAVE_AES_CBC */
1177+
1178+
#ifdef WOLFSSL_AES_COUNTER
1179+
if (ret == 0) {
1180+
ret = wc_AesInit(aes, NULL, devId);
1181+
if (ret == 0) {
1182+
ret = wc_AesSetKeyDirect(aes, key, sizeof(key), iv, AES_ENCRYPTION);
1183+
if (ret == 0) {
1184+
ret = wh_Client_AesCtrDma(ctx, aes, 1, plainIn, sizeof(plainIn),
1185+
refcipher);
1186+
}
1187+
(void)wc_AesFree(aes);
1188+
}
1189+
}
1190+
if (ret == 0) {
1191+
ret = wc_AesInit(aes, NULL, devId);
1192+
if (ret == 0) {
1193+
ret = wc_AesSetKeyDirect(aes, key, sizeof(key), iv, AES_ENCRYPTION);
1194+
if (ret == 0) {
1195+
memcpy(inplace, plainIn, sizeof(plainIn));
1196+
ret = wh_Client_AesCtrDma(ctx, aes, 1, inplace, sizeof(inplace),
1197+
inplace);
1198+
}
1199+
(void)wc_AesFree(aes);
1200+
}
1201+
}
1202+
if (ret == 0 && memcmp(inplace, refcipher, sizeof(refcipher)) != 0) {
1203+
WH_ERROR_PRINT("AES-CTR DMA in-place != out-of-place\n");
1204+
ret = -1;
1205+
}
1206+
#endif /* WOLFSSL_AES_COUNTER */
1207+
1208+
#ifdef HAVE_AES_ECB
1209+
if (ret == 0) {
1210+
ret = wc_AesInit(aes, NULL, devId);
1211+
if (ret == 0) {
1212+
ret = wc_AesSetKey(aes, key, sizeof(key), NULL, AES_ENCRYPTION);
1213+
if (ret == 0) {
1214+
ret = wh_Client_AesEcbDma(ctx, aes, 1, plainIn, sizeof(plainIn),
1215+
refcipher);
1216+
}
1217+
(void)wc_AesFree(aes);
1218+
}
1219+
}
1220+
if (ret == 0) {
1221+
ret = wc_AesInit(aes, NULL, devId);
1222+
if (ret == 0) {
1223+
ret = wc_AesSetKey(aes, key, sizeof(key), NULL, AES_ENCRYPTION);
1224+
if (ret == 0) {
1225+
memcpy(inplace, plainIn, sizeof(plainIn));
1226+
ret = wh_Client_AesEcbDma(ctx, aes, 1, inplace, sizeof(inplace),
1227+
inplace);
1228+
}
1229+
(void)wc_AesFree(aes);
1230+
}
1231+
}
1232+
if (ret == 0 && memcmp(inplace, refcipher, sizeof(refcipher)) != 0) {
1233+
WH_ERROR_PRINT("AES-ECB DMA in-place != out-of-place\n");
1234+
ret = -1;
1235+
}
1236+
#endif /* HAVE_AES_ECB */
1237+
1238+
if (ret == 0) {
1239+
WH_TEST_PRINT("AES DMA in-place aliasing DEVID=0x%X SUCCESS\n", devId);
1240+
}
1241+
return ret;
1242+
}
1243+
#endif /* WOLFHSM_CFG_DMA */
1244+
11051245
int whTest_Crypto_Aes(whClientContext* ctx)
11061246
{
11071247
int i;
@@ -1123,6 +1263,11 @@ int whTest_Crypto_Aes(whClientContext* ctx)
11231263
#endif
11241264
#ifdef WOLFSSL_AES_COUNTER
11251265
WH_TEST_RETURN_ON_FAIL(whTest_CryptoAesCtrLeftOob(ctx));
1266+
#endif
1267+
#if defined(WOLFHSM_CFG_DMA) && \
1268+
(defined(HAVE_AES_CBC) || defined(WOLFSSL_AES_COUNTER) || \
1269+
defined(HAVE_AES_ECB))
1270+
WH_TEST_RETURN_ON_FAIL(whTest_CryptoAesDmaInPlace(ctx));
11261271
#endif
11271272
/* TODO: port legacy AES async + DMA-async coverage (comm-buffer & DMA, round-trip & KAT) -- the only remaining legacy crypto parity gap; deferred to follow-up PR. */
11281273
return 0;

0 commit comments

Comments
 (0)