Skip to content

Commit a4f7dbe

Browse files
committed
[crypto/aes] Cleanup on failures
Use the cleanup attribute in order to attach a guard to cleanup the hardware. These functions are called when the variables go out of scope. Hence, we clear the hardware on both the succesful execution (as it was before) and on bad status output (which is new). Apply this new setting to the AES, CMAC, and GCM where we split the driver to no longer clean the HW when calling aes_end. Instead, we always call it from impl (and users using the drivers still can manually call the clean in drivers). Signed-off-by: Siemen Dhooghe <sdhooghe@google.com>
1 parent b64522c commit a4f7dbe

5 files changed

Lines changed: 135 additions & 42 deletions

File tree

sw/device/lib/crypto/drivers/aes.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,10 @@ status_t aes_end(aes_block_t *iv) {
343343
HARDENED_CHECK_EQ(i, ARRAYSIZE(iv->data));
344344
}
345345

346+
return spin_until(AES_STATUS_IDLE_BIT);
347+
}
348+
349+
status_t aes_clear(void) {
346350
uint32_t trigger_reg = 0;
347351
trigger_reg = bitfield_bit32_write(
348352
trigger_reg, AES_TRIGGER_KEY_IV_DATA_IN_CLEAR_BIT, true);

sw/device/lib/crypto/drivers/aes.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,14 @@ status_t aes_update(aes_block_t *dest, const aes_block_t *src);
173173
OT_WARN_UNUSED_RESULT
174174
status_t aes_end(aes_block_t *iv);
175175

176+
/**
177+
* Clears the AES hardware data registers and triggers.
178+
*
179+
* @return The result of the operation.
180+
*/
181+
OT_WARN_UNUSED_RESULT
182+
status_t aes_clear(void);
183+
176184
/**
177185
* Compute the checksum of an AES key.
178186
*

sw/device/lib/crypto/impl/aes.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,14 @@ otcrypto_status_t otcrypto_aes_padded_plaintext_length(
279279
return OTCRYPTO_OK;
280280
}
281281

282+
/**
283+
* Hardware cleanup guard.
284+
*/
285+
static void hw_wipe_guard(uint32_t *dummy) {
286+
(void)aes_clear();
287+
(void)keymgr_sideload_clear_aes();
288+
}
289+
282290
/**
283291
* Performs the AES operation.
284292
*
@@ -297,6 +305,9 @@ static otcrypto_status_t otcrypto_aes_impl(
297305
otcrypto_aes_mode_t aes_mode, otcrypto_aes_operation_t aes_operation,
298306
const otcrypto_const_byte_buf_t *cipher_input,
299307
otcrypto_aes_padding_t aes_padding, otcrypto_byte_buf_t *cipher_output) {
308+
// Guarantees hw_wipe_guard() is called on exit.
309+
uint32_t hw_cleanup_guard __attribute__((cleanup(hw_wipe_guard))) = 1;
310+
300311
// Calculate the number of blocks for the input, including the padding for
301312
// encryption.
302313
size_t input_nblocks;
@@ -450,8 +461,7 @@ static otcrypto_status_t otcrypto_aes_impl(
450461
HARDENED_TRY(hardened_memcpy(iv->data, aes_iv.data, kAesBlockNumWords));
451462
}
452463

453-
// In case the key was sideloaded, clear it.
454-
return otcrypto_eval_exit(keymgr_sideload_clear_aes());
464+
return otcrypto_eval_exit(OTCRYPTO_OK);
455465
}
456466

457467
otcrypto_status_t otcrypto_aes_padding_strip(

sw/device/lib/crypto/impl/aes_gcm.c

Lines changed: 77 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,20 @@ enum {
4242
kAesGcmContextNumWords = sizeof(aes_gcm_context_t) / sizeof(uint32_t),
4343
};
4444

45+
/**
46+
* AES cleanup guard.
47+
*/
48+
static void aes_wipe_guard(uint32_t *dummy) { (void)aes_clear(); }
49+
50+
/**
51+
* Sideload cleanup guard.
52+
*/
53+
static void sideload_wipe_guard(hardened_bool_t *is_sideloaded) {
54+
if (*is_sideloaded == kHardenedBoolTrue) {
55+
(void)keymgr_sideload_clear_aes();
56+
}
57+
}
58+
4559
/**
4660
* Save an AES-GCM context.
4761
*
@@ -252,30 +266,6 @@ static status_t load_key_if_sideloaded(const aes_key_t key) {
252266
return keymgr_generate_key_aes(diversification);
253267
}
254268

255-
/**
256-
* Clear the sideload slot if the AES key was sideloaded.
257-
*
258-
* It is important to clear the sideload slot before returning to the caller so
259-
* that other applications can't access the key in between operations.
260-
*
261-
* If the key is not a sideloaded key, this function does nothing.
262-
*
263-
* @param key Key that was possibly loaded.
264-
* @return OK or errror.
265-
*/
266-
static status_t clear_key_if_sideloaded(const aes_key_t key) {
267-
if (launder32(key.sideload) == kHardenedBoolFalse) {
268-
HARDENED_CHECK_EQ(key.sideload, launder32(kHardenedBoolFalse));
269-
return OTCRYPTO_OK;
270-
} else if (launder32(key.sideload) != kHardenedBoolTrue) {
271-
// COVERAGE (SW ERR) This is an internal function, the aes key's sideload is
272-
// set internal by good parameters.
273-
return OTCRYPTO_BAD_ARGS;
274-
}
275-
HARDENED_CHECK_EQ(key.sideload, launder32(kHardenedBoolTrue));
276-
return keymgr_sideload_clear_aes();
277-
}
278-
279269
otcrypto_status_t otcrypto_aes_gcm_encrypt(
280270
otcrypto_blinded_key_t *key, const otcrypto_const_byte_buf_t *plaintext,
281271
const otcrypto_const_word32_buf_t *iv, const otcrypto_const_byte_buf_t *aad,
@@ -300,6 +290,11 @@ otcrypto_status_t otcrypto_aes_gcm_encrypt(
300290
}
301291
#endif
302292

293+
// LIFO Cleanup: aes_clear() executes before sideload_clear().
294+
hardened_bool_t is_sideloaded __attribute__((cleanup(sideload_wipe_guard))) =
295+
kHardenedBoolFalse;
296+
uint32_t hw_cleanup_guard __attribute__((cleanup(aes_wipe_guard))) = 1;
297+
303298
// Ensure the plaintext and ciphertext lengths match.
304299
if (launder32(ciphertext->len) != plaintext->len) {
305300
return OTCRYPTO_BAD_ARGS;
@@ -315,6 +310,9 @@ otcrypto_status_t otcrypto_aes_gcm_encrypt(
315310
// Construct the AES key.
316311
aes_key_t aes_key;
317312
HARDENED_TRY(aes_gcm_key_construct(key, &aes_key));
313+
if (launder32(aes_key.sideload) == kHardenedBoolTrue) {
314+
is_sideloaded = kHardenedBoolTrue;
315+
}
318316
HARDENED_TRY(load_key_if_sideloaded(aes_key));
319317

320318
// Call the core encryption operation.
@@ -323,8 +321,6 @@ otcrypto_status_t otcrypto_aes_gcm_encrypt(
323321
auth_tag->len, key->config.security_level,
324322
auth_tag->data, ciphertext->data));
325323

326-
HARDENED_TRY(clear_key_if_sideloaded(aes_key));
327-
328324
// Verify the input buffers
329325
HARDENED_CHECK_EQ(kHardenedBoolTrue, OTCRYPTO_CHECK_BUF(plaintext));
330326
HARDENED_CHECK_EQ(kHardenedBoolTrue, OTCRYPTO_CHECK_BUF(iv));
@@ -359,9 +355,16 @@ otcrypto_status_t otcrypto_aes_gcm_decrypt(
359355
}
360356
#endif
361357

358+
hardened_bool_t is_sideloaded __attribute__((cleanup(sideload_wipe_guard))) =
359+
kHardenedBoolFalse;
360+
uint32_t hw_cleanup_guard __attribute__((cleanup(aes_wipe_guard))) = 1;
361+
362362
// Construct the AES key.
363363
aes_key_t aes_key;
364364
HARDENED_TRY(aes_gcm_key_construct(key, &aes_key));
365+
if (launder32(aes_key.sideload) == kHardenedBoolTrue) {
366+
is_sideloaded = kHardenedBoolTrue;
367+
}
365368
HARDENED_TRY(load_key_if_sideloaded(aes_key));
366369

367370
// Ensure the plaintext and ciphertext lengths match.
@@ -379,8 +382,6 @@ otcrypto_status_t otcrypto_aes_gcm_decrypt(
379382
auth_tag->len, auth_tag->data, plaintext->data,
380383
key->config.security_level, success));
381384

382-
HARDENED_TRY(clear_key_if_sideloaded(aes_key));
383-
384385
// Verify the input buffers
385386
HARDENED_CHECK_EQ(kHardenedBoolTrue, OTCRYPTO_CHECK_BUF(plaintext));
386387
HARDENED_CHECK_EQ(kHardenedBoolTrue, OTCRYPTO_CHECK_BUF(iv));
@@ -401,19 +402,25 @@ otcrypto_status_t otcrypto_aes_gcm_encrypt_init(
401402
}
402403
#endif
403404

405+
hardened_bool_t is_sideloaded __attribute__((cleanup(sideload_wipe_guard))) =
406+
kHardenedBoolFalse;
407+
uint32_t hw_cleanup_guard __attribute__((cleanup(aes_wipe_guard))) = 1;
408+
404409
// Construct the AES key.
405410
aes_key_t aes_key;
406411
HARDENED_TRY(aes_gcm_key_construct(key, &aes_key));
412+
if (launder32(aes_key.sideload) == kHardenedBoolTrue) {
413+
is_sideloaded = kHardenedBoolTrue;
414+
}
407415
HARDENED_TRY(load_key_if_sideloaded(aes_key));
408416

409417
// Call the internal init operation.
410418
aes_gcm_context_t internal_ctx;
411419
internal_ctx.security_level = key->config.security_level;
412420
HARDENED_TRY(aes_gcm_encrypt_init(aes_key, iv->len, iv->data, &internal_ctx));
413421

414-
// Save the context and clear the key if needed.
422+
// Save the context.
415423
HARDENED_TRY(gcm_context_save(&internal_ctx, ctx));
416-
HARDENED_TRY(clear_key_if_sideloaded(internal_ctx.key));
417424

418425
// Verify the input buffer
419426
HARDENED_CHECK_EQ(kHardenedBoolTrue, OTCRYPTO_CHECK_BUF(iv));
@@ -431,19 +438,25 @@ otcrypto_status_t otcrypto_aes_gcm_decrypt_init(
431438
}
432439
#endif
433440

441+
hardened_bool_t is_sideloaded __attribute__((cleanup(sideload_wipe_guard))) =
442+
kHardenedBoolFalse;
443+
uint32_t hw_cleanup_guard __attribute__((cleanup(aes_wipe_guard))) = 1;
444+
434445
// Construct the AES key.
435446
aes_key_t aes_key;
436447
HARDENED_TRY(aes_gcm_key_construct(key, &aes_key));
448+
if (launder32(aes_key.sideload) == kHardenedBoolTrue) {
449+
is_sideloaded = kHardenedBoolTrue;
450+
}
437451
HARDENED_TRY(load_key_if_sideloaded(aes_key));
438452

439453
// Call the internal init operation.
440454
aes_gcm_context_t internal_ctx;
441455
internal_ctx.security_level = key->config.security_level;
442456
HARDENED_TRY(aes_gcm_decrypt_init(aes_key, iv->len, iv->data, &internal_ctx));
443457

444-
// Save the context and clear the key if needed.
458+
// Save the context.
445459
HARDENED_TRY(gcm_context_save(&internal_ctx, ctx));
446-
HARDENED_TRY(clear_key_if_sideloaded(internal_ctx.key));
447460

448461
// Verify the input buffer
449462
HARDENED_CHECK_EQ(kHardenedBoolTrue, OTCRYPTO_CHECK_BUF(iv));
@@ -465,17 +478,23 @@ otcrypto_status_t otcrypto_aes_gcm_update_aad(
465478
return OTCRYPTO_OK;
466479
}
467480

481+
hardened_bool_t is_sideloaded __attribute__((cleanup(sideload_wipe_guard))) =
482+
kHardenedBoolFalse;
483+
uint32_t hw_cleanup_guard __attribute__((cleanup(aes_wipe_guard))) = 1;
484+
468485
// Restore the AES-GCM context object and load the key if needed.
469486
aes_gcm_context_t internal_ctx;
470487
HARDENED_TRY(gcm_context_restore(ctx, &internal_ctx));
488+
if (launder32(internal_ctx.key.sideload) == kHardenedBoolTrue) {
489+
is_sideloaded = kHardenedBoolTrue;
490+
}
471491
HARDENED_TRY(load_key_if_sideloaded(internal_ctx.key));
472492

473493
// Call the internal update operation.
474494
HARDENED_TRY(aes_gcm_update_aad(&internal_ctx, aad->len, aad->data));
475495

476-
// Save the context and clear the key if needed.
496+
// Save the context.
477497
HARDENED_TRY(gcm_context_save(&internal_ctx, ctx));
478-
HARDENED_TRY(clear_key_if_sideloaded(internal_ctx.key));
479498

480499
// Verify the input buffer
481500
HARDENED_CHECK_EQ(kHardenedBoolTrue, OTCRYPTO_CHECK_BUF(aad));
@@ -500,9 +519,16 @@ otcrypto_status_t otcrypto_aes_gcm_update_encrypted_data(
500519
return OTCRYPTO_OK;
501520
}
502521

522+
hardened_bool_t is_sideloaded __attribute__((cleanup(sideload_wipe_guard))) =
523+
kHardenedBoolFalse;
524+
uint32_t hw_cleanup_guard __attribute__((cleanup(aes_wipe_guard))) = 1;
525+
503526
// Restore the AES-GCM context object and load the key if needed.
504527
aes_gcm_context_t internal_ctx;
505528
HARDENED_TRY(gcm_context_restore(ctx, &internal_ctx));
529+
if (launder32(internal_ctx.key.sideload) == kHardenedBoolTrue) {
530+
is_sideloaded = kHardenedBoolTrue;
531+
}
506532
HARDENED_TRY(load_key_if_sideloaded(internal_ctx.key));
507533
// Remask the key if it is not sideloaded.
508534
HARDENED_TRY(gcm_remask_key(&internal_ctx));
@@ -526,9 +552,8 @@ otcrypto_status_t otcrypto_aes_gcm_update_encrypted_data(
526552
input->data, output_bytes_written,
527553
output->data));
528554

529-
// Save the context and clear the key if needed.
555+
// Save the context.
530556
HARDENED_TRY(gcm_context_save(&internal_ctx, ctx));
531-
HARDENED_TRY(clear_key_if_sideloaded(internal_ctx.key));
532557

533558
// Verify the input buffers
534559
HARDENED_CHECK_EQ(kHardenedBoolTrue, OTCRYPTO_CHECK_BUF(input));
@@ -559,9 +584,16 @@ otcrypto_status_t otcrypto_aes_gcm_encrypt_final(
559584
// Randomize the tag before the operation.
560585
HARDENED_TRY(hardened_memshred(auth_tag->data, auth_tag->len));
561586

587+
hardened_bool_t is_sideloaded __attribute__((cleanup(sideload_wipe_guard))) =
588+
kHardenedBoolFalse;
589+
uint32_t hw_cleanup_guard __attribute__((cleanup(aes_wipe_guard))) = 1;
590+
562591
// Restore the AES-GCM context object and load the key if needed.
563592
aes_gcm_context_t internal_ctx;
564593
HARDENED_TRY(gcm_context_restore(ctx, &internal_ctx));
594+
if (launder32(internal_ctx.key.sideload) == kHardenedBoolTrue) {
595+
is_sideloaded = kHardenedBoolTrue;
596+
}
565597
HARDENED_TRY(load_key_if_sideloaded(internal_ctx.key));
566598
// Remask the key if it is not sideloaded.
567599
HARDENED_TRY(gcm_remask_key(&internal_ctx));
@@ -578,9 +610,8 @@ otcrypto_status_t otcrypto_aes_gcm_encrypt_final(
578610
auth_tag->data, ciphertext_bytes_written,
579611
ciphertext->data));
580612

581-
// Clear the context and the key if needed.
613+
// Clear the context.
582614
HARDENED_TRY(hardened_memshred(ctx->data, ARRAYSIZE(ctx->data)));
583-
HARDENED_TRY(clear_key_if_sideloaded(internal_ctx.key));
584615

585616
// Verify the input buffers
586617
HARDENED_CHECK_EQ(kHardenedBoolTrue, OTCRYPTO_CHECK_BUF(ciphertext));
@@ -609,9 +640,16 @@ otcrypto_status_t otcrypto_aes_gcm_decrypt_final(
609640
// Check the tag length.
610641
HARDENED_TRY(aes_gcm_check_tag_length(auth_tag->len, tag_len));
611642

643+
hardened_bool_t is_sideloaded __attribute__((cleanup(sideload_wipe_guard))) =
644+
kHardenedBoolFalse;
645+
uint32_t hw_cleanup_guard __attribute__((cleanup(aes_wipe_guard))) = 1;
646+
612647
// Restore the AES-GCM context object and load the key if needed.
613648
aes_gcm_context_t internal_ctx;
614649
HARDENED_TRY(gcm_context_restore(ctx, &internal_ctx));
650+
if (launder32(internal_ctx.key.sideload) == kHardenedBoolTrue) {
651+
is_sideloaded = kHardenedBoolTrue;
652+
}
615653
HARDENED_TRY(load_key_if_sideloaded(internal_ctx.key));
616654
// Remask the key if it is not sideloaded.
617655
HARDENED_TRY(gcm_remask_key(&internal_ctx));
@@ -628,9 +666,8 @@ otcrypto_status_t otcrypto_aes_gcm_decrypt_final(
628666
auth_tag->data, plaintext_bytes_written,
629667
plaintext->data, success));
630668

631-
// Clear the context and the key if needed.
669+
// Clear the context.
632670
HARDENED_TRY(hardened_memshred(ctx->data, ARRAYSIZE(ctx->data)));
633-
HARDENED_TRY(clear_key_if_sideloaded(internal_ctx.key));
634671

635672
// Verify the input buffers
636673
HARDENED_CHECK_EQ(kHardenedBoolTrue, OTCRYPTO_CHECK_BUF(auth_tag));

0 commit comments

Comments
 (0)