Skip to content

Commit 69c4d28

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 69c4d28

5 files changed

Lines changed: 134 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: 76 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,10 @@ otcrypto_status_t otcrypto_aes_gcm_encrypt(
300290
}
301291
#endif
302292

293+
hardened_bool_t is_sideloaded __attribute__((cleanup(sideload_wipe_guard))) =
294+
kHardenedBoolFalse;
295+
uint32_t hw_cleanup_guard __attribute__((cleanup(aes_wipe_guard))) = 1;
296+
303297
// Ensure the plaintext and ciphertext lengths match.
304298
if (launder32(ciphertext->len) != plaintext->len) {
305299
return OTCRYPTO_BAD_ARGS;
@@ -315,6 +309,9 @@ otcrypto_status_t otcrypto_aes_gcm_encrypt(
315309
// Construct the AES key.
316310
aes_key_t aes_key;
317311
HARDENED_TRY(aes_gcm_key_construct(key, &aes_key));
312+
if (launder32(aes_key.sideload) == kHardenedBoolTrue) {
313+
is_sideloaded = kHardenedBoolTrue;
314+
}
318315
HARDENED_TRY(load_key_if_sideloaded(aes_key));
319316

320317
// Call the core encryption operation.
@@ -323,8 +320,6 @@ otcrypto_status_t otcrypto_aes_gcm_encrypt(
323320
auth_tag->len, key->config.security_level,
324321
auth_tag->data, ciphertext->data));
325322

326-
HARDENED_TRY(clear_key_if_sideloaded(aes_key));
327-
328323
// Verify the input buffers
329324
HARDENED_CHECK_EQ(kHardenedBoolTrue, OTCRYPTO_CHECK_BUF(plaintext));
330325
HARDENED_CHECK_EQ(kHardenedBoolTrue, OTCRYPTO_CHECK_BUF(iv));
@@ -359,9 +354,16 @@ otcrypto_status_t otcrypto_aes_gcm_decrypt(
359354
}
360355
#endif
361356

357+
hardened_bool_t is_sideloaded __attribute__((cleanup(sideload_wipe_guard))) =
358+
kHardenedBoolFalse;
359+
uint32_t hw_cleanup_guard __attribute__((cleanup(aes_wipe_guard))) = 1;
360+
362361
// Construct the AES key.
363362
aes_key_t aes_key;
364363
HARDENED_TRY(aes_gcm_key_construct(key, &aes_key));
364+
if (launder32(aes_key.sideload) == kHardenedBoolTrue) {
365+
is_sideloaded = kHardenedBoolTrue;
366+
}
365367
HARDENED_TRY(load_key_if_sideloaded(aes_key));
366368

367369
// Ensure the plaintext and ciphertext lengths match.
@@ -379,8 +381,6 @@ otcrypto_status_t otcrypto_aes_gcm_decrypt(
379381
auth_tag->len, auth_tag->data, plaintext->data,
380382
key->config.security_level, success));
381383

382-
HARDENED_TRY(clear_key_if_sideloaded(aes_key));
383-
384384
// Verify the input buffers
385385
HARDENED_CHECK_EQ(kHardenedBoolTrue, OTCRYPTO_CHECK_BUF(plaintext));
386386
HARDENED_CHECK_EQ(kHardenedBoolTrue, OTCRYPTO_CHECK_BUF(iv));
@@ -401,19 +401,25 @@ otcrypto_status_t otcrypto_aes_gcm_encrypt_init(
401401
}
402402
#endif
403403

404+
hardened_bool_t is_sideloaded __attribute__((cleanup(sideload_wipe_guard))) =
405+
kHardenedBoolFalse;
406+
uint32_t hw_cleanup_guard __attribute__((cleanup(aes_wipe_guard))) = 1;
407+
404408
// Construct the AES key.
405409
aes_key_t aes_key;
406410
HARDENED_TRY(aes_gcm_key_construct(key, &aes_key));
411+
if (launder32(aes_key.sideload) == kHardenedBoolTrue) {
412+
is_sideloaded = kHardenedBoolTrue;
413+
}
407414
HARDENED_TRY(load_key_if_sideloaded(aes_key));
408415

409416
// Call the internal init operation.
410417
aes_gcm_context_t internal_ctx;
411418
internal_ctx.security_level = key->config.security_level;
412419
HARDENED_TRY(aes_gcm_encrypt_init(aes_key, iv->len, iv->data, &internal_ctx));
413420

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

418424
// Verify the input buffer
419425
HARDENED_CHECK_EQ(kHardenedBoolTrue, OTCRYPTO_CHECK_BUF(iv));
@@ -431,19 +437,25 @@ otcrypto_status_t otcrypto_aes_gcm_decrypt_init(
431437
}
432438
#endif
433439

440+
hardened_bool_t is_sideloaded __attribute__((cleanup(sideload_wipe_guard))) =
441+
kHardenedBoolFalse;
442+
uint32_t hw_cleanup_guard __attribute__((cleanup(aes_wipe_guard))) = 1;
443+
434444
// Construct the AES key.
435445
aes_key_t aes_key;
436446
HARDENED_TRY(aes_gcm_key_construct(key, &aes_key));
447+
if (launder32(aes_key.sideload) == kHardenedBoolTrue) {
448+
is_sideloaded = kHardenedBoolTrue;
449+
}
437450
HARDENED_TRY(load_key_if_sideloaded(aes_key));
438451

439452
// Call the internal init operation.
440453
aes_gcm_context_t internal_ctx;
441454
internal_ctx.security_level = key->config.security_level;
442455
HARDENED_TRY(aes_gcm_decrypt_init(aes_key, iv->len, iv->data, &internal_ctx));
443456

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

448460
// Verify the input buffer
449461
HARDENED_CHECK_EQ(kHardenedBoolTrue, OTCRYPTO_CHECK_BUF(iv));
@@ -465,17 +477,23 @@ otcrypto_status_t otcrypto_aes_gcm_update_aad(
465477
return OTCRYPTO_OK;
466478
}
467479

480+
hardened_bool_t is_sideloaded __attribute__((cleanup(sideload_wipe_guard))) =
481+
kHardenedBoolFalse;
482+
uint32_t hw_cleanup_guard __attribute__((cleanup(aes_wipe_guard))) = 1;
483+
468484
// Restore the AES-GCM context object and load the key if needed.
469485
aes_gcm_context_t internal_ctx;
470486
HARDENED_TRY(gcm_context_restore(ctx, &internal_ctx));
487+
if (launder32(internal_ctx.key.sideload) == kHardenedBoolTrue) {
488+
is_sideloaded = kHardenedBoolTrue;
489+
}
471490
HARDENED_TRY(load_key_if_sideloaded(internal_ctx.key));
472491

473492
// Call the internal update operation.
474493
HARDENED_TRY(aes_gcm_update_aad(&internal_ctx, aad->len, aad->data));
475494

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

480498
// Verify the input buffer
481499
HARDENED_CHECK_EQ(kHardenedBoolTrue, OTCRYPTO_CHECK_BUF(aad));
@@ -500,9 +518,16 @@ otcrypto_status_t otcrypto_aes_gcm_update_encrypted_data(
500518
return OTCRYPTO_OK;
501519
}
502520

521+
hardened_bool_t is_sideloaded __attribute__((cleanup(sideload_wipe_guard))) =
522+
kHardenedBoolFalse;
523+
uint32_t hw_cleanup_guard __attribute__((cleanup(aes_wipe_guard))) = 1;
524+
503525
// Restore the AES-GCM context object and load the key if needed.
504526
aes_gcm_context_t internal_ctx;
505527
HARDENED_TRY(gcm_context_restore(ctx, &internal_ctx));
528+
if (launder32(internal_ctx.key.sideload) == kHardenedBoolTrue) {
529+
is_sideloaded = kHardenedBoolTrue;
530+
}
506531
HARDENED_TRY(load_key_if_sideloaded(internal_ctx.key));
507532
// Remask the key if it is not sideloaded.
508533
HARDENED_TRY(gcm_remask_key(&internal_ctx));
@@ -526,9 +551,8 @@ otcrypto_status_t otcrypto_aes_gcm_update_encrypted_data(
526551
input->data, output_bytes_written,
527552
output->data));
528553

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

533557
// Verify the input buffers
534558
HARDENED_CHECK_EQ(kHardenedBoolTrue, OTCRYPTO_CHECK_BUF(input));
@@ -559,9 +583,16 @@ otcrypto_status_t otcrypto_aes_gcm_encrypt_final(
559583
// Randomize the tag before the operation.
560584
HARDENED_TRY(hardened_memshred(auth_tag->data, auth_tag->len));
561585

586+
hardened_bool_t is_sideloaded __attribute__((cleanup(sideload_wipe_guard))) =
587+
kHardenedBoolFalse;
588+
uint32_t hw_cleanup_guard __attribute__((cleanup(aes_wipe_guard))) = 1;
589+
562590
// Restore the AES-GCM context object and load the key if needed.
563591
aes_gcm_context_t internal_ctx;
564592
HARDENED_TRY(gcm_context_restore(ctx, &internal_ctx));
593+
if (launder32(internal_ctx.key.sideload) == kHardenedBoolTrue) {
594+
is_sideloaded = kHardenedBoolTrue;
595+
}
565596
HARDENED_TRY(load_key_if_sideloaded(internal_ctx.key));
566597
// Remask the key if it is not sideloaded.
567598
HARDENED_TRY(gcm_remask_key(&internal_ctx));
@@ -578,9 +609,8 @@ otcrypto_status_t otcrypto_aes_gcm_encrypt_final(
578609
auth_tag->data, ciphertext_bytes_written,
579610
ciphertext->data));
580611

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

585615
// Verify the input buffers
586616
HARDENED_CHECK_EQ(kHardenedBoolTrue, OTCRYPTO_CHECK_BUF(ciphertext));
@@ -609,9 +639,16 @@ otcrypto_status_t otcrypto_aes_gcm_decrypt_final(
609639
// Check the tag length.
610640
HARDENED_TRY(aes_gcm_check_tag_length(auth_tag->len, tag_len));
611641

642+
hardened_bool_t is_sideloaded __attribute__((cleanup(sideload_wipe_guard))) =
643+
kHardenedBoolFalse;
644+
uint32_t hw_cleanup_guard __attribute__((cleanup(aes_wipe_guard))) = 1;
645+
612646
// Restore the AES-GCM context object and load the key if needed.
613647
aes_gcm_context_t internal_ctx;
614648
HARDENED_TRY(gcm_context_restore(ctx, &internal_ctx));
649+
if (launder32(internal_ctx.key.sideload) == kHardenedBoolTrue) {
650+
is_sideloaded = kHardenedBoolTrue;
651+
}
615652
HARDENED_TRY(load_key_if_sideloaded(internal_ctx.key));
616653
// Remask the key if it is not sideloaded.
617654
HARDENED_TRY(gcm_remask_key(&internal_ctx));
@@ -628,9 +665,8 @@ otcrypto_status_t otcrypto_aes_gcm_decrypt_final(
628665
auth_tag->data, plaintext_bytes_written,
629666
plaintext->data, success));
630667

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

635671
// Verify the input buffers
636672
HARDENED_CHECK_EQ(kHardenedBoolTrue, OTCRYPTO_CHECK_BUF(auth_tag));

0 commit comments

Comments
 (0)