|
19 | 19 | /* |
20 | 20 | * test-refactor/client-server/wh_test_keywrap.c |
21 | 21 | * |
22 | | - * Keywrap policy coverage that runs against any server (no trusted KEK |
23 | | - * needed on the positive paths, and the negatives prove a client cannot |
24 | | - * mint one): |
25 | | - * _whTest_KeywrapSwKekRoundTrip - wrap a plaintext key under a plain |
26 | | - * client-cached KEK and unwrap-and-export |
27 | | - * it back (only unwrap-and-cache and |
28 | | - * wrap-export require a trusted KEK) |
| 22 | + * Keywrap policy and input-validation coverage that runs against any server: |
| 23 | + * the negatives prove a client cannot mint a trusted KEK or slip an |
| 24 | + * undersized blob past the size checks. |
29 | 25 | * _whTest_KeywrapTrustedKekPolicy - wrap-export and unwrap-and-cache must |
30 | 26 | * refuse a plain client KEK, and a client |
31 | 27 | * cannot forge WH_NVM_FLAGS_TRUSTED via the |
32 | 28 | * NVM add, HKDF cache, or key cache paths |
33 | 29 | * _whTest_KeywrapDataWrapUsage - data wrap requires USAGE_WRAP on the KEK |
| 30 | + * _whTest_KeywrapKeyUnwrapUnderflow - undersized wrapped-key blobs must |
| 31 | + * return WH_ERROR_BADARGS, not underflow |
| 32 | + * _whTest_KeywrapDataUnwrapUnderflow - undersized wrapped-data blobs must |
| 33 | + * return WH_ERROR_BADARGS, not underflow |
34 | 34 | * |
35 | | - * The trusted-KEK positive paths (wrap-export round-trip, unwrap-and-cache) |
36 | | - * live in misc/wh_test_hwkeystore.c against the hardware KEK, and in |
| 35 | + * The positive wrap/unwrap-and-export round trip under a plain client KEK |
| 36 | + * lives in wh_test_crypto_keywrap.c. The trusted-KEK positive paths |
| 37 | + * (wrap-export round-trip, unwrap-and-cache) live in |
| 38 | + * misc/wh_test_hwkeystore.c against the hardware KEK, and in |
37 | 39 | * misc/wh_test_multiclient.c against an NVM-provisioned KEK. |
38 | 40 | */ |
39 | 41 |
|
@@ -92,68 +94,6 @@ static int _CacheSwKek(whClientContext* client, whKeyId* outKekId) |
92 | 94 | return WH_ERROR_OK; |
93 | 95 | } |
94 | 96 |
|
95 | | -/* Positive software-KEK round trip; needs no trusted KEK. Wrap a plaintext key |
96 | | - * under the plain KEK, unwrap-and-export the blob, and confirm the key |
97 | | - * material and metadata come back unchanged */ |
98 | | -static int _whTest_KeywrapSwKekRoundTrip(whClientContext* client) |
99 | | -{ |
100 | | - int ret; |
101 | | - whKeyId kekId = WH_KEYID_ERASED; |
102 | | - uint8_t plainKey[WH_TEST_KW_KEYSIZE]; |
103 | | - uint8_t tmpPlainKey[WH_TEST_KW_KEYSIZE]; |
104 | | - uint16_t tmpPlainKeySz = sizeof(tmpPlainKey); |
105 | | - uint8_t wrappedKey[WH_TEST_KW_WRAPPED_KEYSIZE]; |
106 | | - uint16_t wrappedKeySz = sizeof(wrappedKey); |
107 | | - whNvmMetadata metadata = {0}; |
108 | | - whNvmMetadata tmpMetadata = {0}; |
109 | | - size_t i; |
110 | | - |
111 | | - metadata.id = WH_CLIENT_KEYID_MAKE_WRAPPED_META(client->comm->client_id, |
112 | | - WH_TEST_KW_META_ID); |
113 | | - metadata.len = WH_TEST_KW_KEYSIZE; |
114 | | - metadata.flags = WH_NVM_FLAGS_USAGE_ANY; |
115 | | - memcpy(metadata.label, "SwKek Key Label", sizeof("SwKek Key Label")); |
116 | | - |
117 | | - for (i = 0; i < sizeof(plainKey); i++) { |
118 | | - plainKey[i] = (uint8_t)(0x7B ^ i); |
119 | | - } |
120 | | - |
121 | | - WH_TEST_RETURN_ON_FAIL(_CacheSwKek(client, &kekId)); |
122 | | - |
123 | | - /* Wrap the plaintext key under the plain software KEK */ |
124 | | - ret = wh_Client_KeyWrap(client, WC_CIPHER_AES_GCM, kekId, plainKey, |
125 | | - sizeof(plainKey), &metadata, wrappedKey, |
126 | | - &wrappedKeySz); |
127 | | - if (ret != WH_ERROR_OK) { |
128 | | - WH_ERROR_PRINT("sw-kek: KeyWrap failed %d\n", ret); |
129 | | - (void)wh_Client_KeyEvict(client, kekId); |
130 | | - return ret; |
131 | | - } |
132 | | - |
133 | | - /* Unwrap-and-export the blob and confirm the material round-trips */ |
134 | | - ret = wh_Client_KeyUnwrapAndExport(client, WC_CIPHER_AES_GCM, kekId, |
135 | | - wrappedKey, wrappedKeySz, &tmpMetadata, |
136 | | - tmpPlainKey, &tmpPlainKeySz); |
137 | | - (void)wh_Client_KeyEvict(client, kekId); |
138 | | - if (ret != WH_ERROR_OK) { |
139 | | - WH_ERROR_PRINT("sw-kek: KeyUnwrapAndExport failed %d\n", ret); |
140 | | - return ret; |
141 | | - } |
142 | | - |
143 | | - if (tmpPlainKeySz != sizeof(plainKey) || |
144 | | - memcmp(plainKey, tmpPlainKey, sizeof(plainKey)) != 0) { |
145 | | - WH_ERROR_PRINT("sw-kek: unwrapped key material mismatch\n"); |
146 | | - return WH_ERROR_ABORTED; |
147 | | - } |
148 | | - |
149 | | - if (memcmp(&metadata, &tmpMetadata, sizeof(metadata)) != 0) { |
150 | | - WH_ERROR_PRINT("sw-kek: unwrapped metadata mismatch\n"); |
151 | | - return WH_ERROR_ABORTED; |
152 | | - } |
153 | | - |
154 | | - return WH_ERROR_OK; |
155 | | -} |
156 | | - |
157 | 97 | /* The wrap-export and unwrap-and-cache operations require a trusted KEK (HW or |
158 | 98 | * WH_NVM_FLAGS_TRUSTED). Prove that (a) a plain client-cached USAGE_WRAP key is |
159 | 99 | * refused as their KEK, and that a client cannot forge a trusted KEK by |
@@ -397,11 +337,89 @@ static int _whTest_KeywrapDataWrapUsage(whClientContext* client) |
397 | 337 | return WH_ERROR_OK; |
398 | 338 | } |
399 | 339 |
|
| 340 | +/* A wrapped blob smaller than its own header must be refused with |
| 341 | + * WH_ERROR_BADARGS rather than underflowing the payload length. A usable KEK |
| 342 | + * is cached first so the rejection can only come from the size check, not |
| 343 | + * from KEK resolution */ |
| 344 | +static int _whTest_KeywrapKeyUnwrapUnderflow(whClientContext* client) |
| 345 | +{ |
| 346 | + const uint16_t shortSizes[] = {0, 1}; |
| 347 | + int ret = WH_ERROR_OK; |
| 348 | + whKeyId kekId = WH_KEYID_ERASED; |
| 349 | + uint8_t blob[1] = {0}; |
| 350 | + size_t i; |
| 351 | + |
| 352 | + WH_TEST_RETURN_ON_FAIL(_CacheSwKek(client, &kekId)); |
| 353 | + |
| 354 | + for (i = 0; i < sizeof(shortSizes) / sizeof(shortSizes[0]); i++) { |
| 355 | + whNvmMetadata meta = {0}; |
| 356 | + uint8_t keyOut[WH_TEST_KW_KEYSIZE] = {0}; |
| 357 | + uint16_t keyOutSz = sizeof(keyOut); |
| 358 | + uint16_t cachedId = WH_KEYID_ERASED; |
| 359 | + |
| 360 | + ret = wh_Client_KeyUnwrapAndExport(client, WC_CIPHER_AES_GCM, kekId, |
| 361 | + blob, shortSizes[i], &meta, keyOut, |
| 362 | + &keyOutSz); |
| 363 | + if (ret != WH_ERROR_BADARGS) { |
| 364 | + WH_ERROR_PRINT("KeyUnwrapAndExport(sz=%u) expected BADARGS, " |
| 365 | + "got %d\n", |
| 366 | + (unsigned)shortSizes[i], ret); |
| 367 | + ret = WH_ERROR_ABORTED; |
| 368 | + break; |
| 369 | + } |
| 370 | + |
| 371 | + ret = wh_Client_KeyUnwrapAndCache(client, WC_CIPHER_AES_GCM, kekId, |
| 372 | + blob, shortSizes[i], &cachedId); |
| 373 | + if (ret != WH_ERROR_BADARGS) { |
| 374 | + WH_ERROR_PRINT("KeyUnwrapAndCache(sz=%u) expected BADARGS, " |
| 375 | + "got %d\n", |
| 376 | + (unsigned)shortSizes[i], ret); |
| 377 | + ret = WH_ERROR_ABORTED; |
| 378 | + break; |
| 379 | + } |
| 380 | + ret = WH_ERROR_OK; |
| 381 | + } |
| 382 | + |
| 383 | + (void)wh_Client_KeyEvict(client, kekId); |
| 384 | + return ret; |
| 385 | +} |
| 386 | + |
| 387 | +/* Same underflow guard on the opaque data path */ |
| 388 | +static int _whTest_KeywrapDataUnwrapUnderflow(whClientContext* client) |
| 389 | +{ |
| 390 | + const uint32_t shortSizes[] = {0, 1}; |
| 391 | + int ret = WH_ERROR_OK; |
| 392 | + whKeyId kekId = WH_KEYID_ERASED; |
| 393 | + uint8_t blob[1] = {0}; |
| 394 | + size_t i; |
| 395 | + |
| 396 | + WH_TEST_RETURN_ON_FAIL(_CacheSwKek(client, &kekId)); |
| 397 | + |
| 398 | + for (i = 0; i < sizeof(shortSizes) / sizeof(shortSizes[0]); i++) { |
| 399 | + uint8_t dataOut[WH_TEST_KW_KEYSIZE] = {0}; |
| 400 | + uint32_t dataOutSz = sizeof(dataOut); |
| 401 | + |
| 402 | + ret = wh_Client_DataUnwrap(client, WC_CIPHER_AES_GCM, kekId, blob, |
| 403 | + shortSizes[i], dataOut, &dataOutSz); |
| 404 | + if (ret != WH_ERROR_BADARGS) { |
| 405 | + WH_ERROR_PRINT("DataUnwrap(sz=%u) expected BADARGS, got %d\n", |
| 406 | + (unsigned)shortSizes[i], ret); |
| 407 | + ret = WH_ERROR_ABORTED; |
| 408 | + break; |
| 409 | + } |
| 410 | + ret = WH_ERROR_OK; |
| 411 | + } |
| 412 | + |
| 413 | + (void)wh_Client_KeyEvict(client, kekId); |
| 414 | + return ret; |
| 415 | +} |
| 416 | + |
400 | 417 | int whTest_KeyWrap(whClientContext* ctx) |
401 | 418 | { |
402 | | - WH_TEST_RETURN_ON_FAIL(_whTest_KeywrapSwKekRoundTrip(ctx)); |
403 | 419 | WH_TEST_RETURN_ON_FAIL(_whTest_KeywrapTrustedKekPolicy(ctx)); |
404 | 420 | WH_TEST_RETURN_ON_FAIL(_whTest_KeywrapDataWrapUsage(ctx)); |
| 421 | + WH_TEST_RETURN_ON_FAIL(_whTest_KeywrapKeyUnwrapUnderflow(ctx)); |
| 422 | + WH_TEST_RETURN_ON_FAIL(_whTest_KeywrapDataUnwrapUnderflow(ctx)); |
405 | 423 |
|
406 | 424 | WH_TEST_PRINT("KEYWRAP POLICY SUCCESS\n"); |
407 | 425 | return 0; |
|
0 commit comments