Skip to content

Commit e8f93ca

Browse files
committed
[crypto/gcm] Cleanup GCM
Cleanup the HW and sensitive variables in the GCM logic also when a bad status is thrown. Signed-off-by: Siemen Dhooghe <sdhooghe@google.com>
1 parent faed04c commit e8f93ca

3 files changed

Lines changed: 295 additions & 175 deletions

File tree

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

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

45+
/**
46+
* Consolidated state for AES-GCM operations.
47+
*/
48+
typedef struct {
49+
aes_key_t aes_key;
50+
aes_gcm_context_t internal_ctx;
51+
} aes_gcm_impl_state_t;
52+
53+
static_assert(
54+
sizeof(aes_gcm_impl_state_t) % sizeof(uint32_t) == 0,
55+
"GCM State struct must be a multiple of the word size for memshred.");
56+
57+
/**
58+
* Cleanup function for AES-GCM.
59+
*/
60+
static void cleanup_gcm_state(aes_gcm_impl_state_t *state) {
61+
(void)aes_clear();
62+
(void)keymgr_sideload_clear_aes();
63+
hardened_memshred((uint32_t *)state,
64+
sizeof(aes_gcm_impl_state_t) / sizeof(uint32_t));
65+
}
66+
4567
/**
4668
* Save an AES-GCM context.
4769
*
@@ -252,30 +274,6 @@ static status_t load_key_if_sideloaded(const aes_key_t key) {
252274
return keymgr_generate_key_aes(diversification);
253275
}
254276

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-
279277
otcrypto_status_t otcrypto_aes_gcm_encrypt(
280278
otcrypto_blinded_key_t *key, const otcrypto_const_byte_buf_t *plaintext,
281279
const otcrypto_const_word32_buf_t *iv, const otcrypto_const_byte_buf_t *aad,
@@ -300,6 +298,8 @@ otcrypto_status_t otcrypto_aes_gcm_encrypt(
300298
}
301299
#endif
302300

301+
aes_gcm_impl_state_t state __attribute__((cleanup(cleanup_gcm_state))) = {0};
302+
303303
// Ensure the plaintext and ciphertext lengths match.
304304
if (launder32(ciphertext->len) != plaintext->len) {
305305
return OTCRYPTO_BAD_ARGS;
@@ -313,18 +313,15 @@ otcrypto_status_t otcrypto_aes_gcm_encrypt(
313313
HARDENED_TRY(hardened_memshred(auth_tag->data, auth_tag->len));
314314

315315
// Construct the AES key.
316-
aes_key_t aes_key;
317-
HARDENED_TRY(aes_gcm_key_construct(key, &aes_key));
318-
HARDENED_TRY(load_key_if_sideloaded(aes_key));
316+
HARDENED_TRY(aes_gcm_key_construct(key, &state.aes_key));
317+
HARDENED_TRY(load_key_if_sideloaded(state.aes_key));
319318

320319
// Call the core encryption operation.
321-
HARDENED_TRY(aes_gcm_encrypt(aes_key, iv->len, iv->data, plaintext->len,
320+
HARDENED_TRY(aes_gcm_encrypt(state.aes_key, iv->len, iv->data, plaintext->len,
322321
plaintext->data, aad->len, aad->data,
323322
auth_tag->len, key->config.security_level,
324323
auth_tag->data, ciphertext->data));
325324

326-
HARDENED_TRY(clear_key_if_sideloaded(aes_key));
327-
328325
// Verify the input buffers
329326
HARDENED_CHECK_EQ(kHardenedBoolTrue, OTCRYPTO_CHECK_BUF(plaintext));
330327
HARDENED_CHECK_EQ(kHardenedBoolTrue, OTCRYPTO_CHECK_BUF(iv));
@@ -359,10 +356,11 @@ otcrypto_status_t otcrypto_aes_gcm_decrypt(
359356
}
360357
#endif
361358

359+
aes_gcm_impl_state_t state __attribute__((cleanup(cleanup_gcm_state))) = {0};
360+
362361
// Construct the AES key.
363-
aes_key_t aes_key;
364-
HARDENED_TRY(aes_gcm_key_construct(key, &aes_key));
365-
HARDENED_TRY(load_key_if_sideloaded(aes_key));
362+
HARDENED_TRY(aes_gcm_key_construct(key, &state.aes_key));
363+
HARDENED_TRY(load_key_if_sideloaded(state.aes_key));
366364

367365
// Ensure the plaintext and ciphertext lengths match.
368366
if (launder32(ciphertext->len) != plaintext->len) {
@@ -374,12 +372,10 @@ otcrypto_status_t otcrypto_aes_gcm_decrypt(
374372
HARDENED_TRY(aes_gcm_check_tag_length(auth_tag->len, tag_len));
375373

376374
// Call the core decryption operation.
377-
HARDENED_TRY(aes_gcm_decrypt(aes_key, iv->len, iv->data, ciphertext->len,
378-
ciphertext->data, aad->len, aad->data,
379-
auth_tag->len, auth_tag->data, plaintext->data,
380-
key->config.security_level, success));
381-
382-
HARDENED_TRY(clear_key_if_sideloaded(aes_key));
375+
HARDENED_TRY(aes_gcm_decrypt(
376+
state.aes_key, iv->len, iv->data, ciphertext->len, ciphertext->data,
377+
aad->len, aad->data, auth_tag->len, auth_tag->data, plaintext->data,
378+
key->config.security_level, success));
383379

384380
// Verify the input buffers
385381
HARDENED_CHECK_EQ(kHardenedBoolTrue, OTCRYPTO_CHECK_BUF(plaintext));
@@ -401,19 +397,19 @@ otcrypto_status_t otcrypto_aes_gcm_encrypt_init(
401397
}
402398
#endif
403399

400+
aes_gcm_impl_state_t state __attribute__((cleanup(cleanup_gcm_state))) = {0};
401+
404402
// Construct the AES key.
405-
aes_key_t aes_key;
406-
HARDENED_TRY(aes_gcm_key_construct(key, &aes_key));
407-
HARDENED_TRY(load_key_if_sideloaded(aes_key));
403+
HARDENED_TRY(aes_gcm_key_construct(key, &state.aes_key));
404+
HARDENED_TRY(load_key_if_sideloaded(state.aes_key));
408405

409406
// Call the internal init operation.
410-
aes_gcm_context_t internal_ctx;
411-
internal_ctx.security_level = key->config.security_level;
412-
HARDENED_TRY(aes_gcm_encrypt_init(aes_key, iv->len, iv->data, &internal_ctx));
407+
state.internal_ctx.security_level = key->config.security_level;
408+
HARDENED_TRY(aes_gcm_encrypt_init(state.aes_key, iv->len, iv->data,
409+
&state.internal_ctx));
413410

414-
// Save the context and clear the key if needed.
415-
HARDENED_TRY(gcm_context_save(&internal_ctx, ctx));
416-
HARDENED_TRY(clear_key_if_sideloaded(internal_ctx.key));
411+
// Save the context.
412+
HARDENED_TRY(gcm_context_save(&state.internal_ctx, ctx));
417413

418414
// Verify the input buffer
419415
HARDENED_CHECK_EQ(kHardenedBoolTrue, OTCRYPTO_CHECK_BUF(iv));
@@ -431,19 +427,19 @@ otcrypto_status_t otcrypto_aes_gcm_decrypt_init(
431427
}
432428
#endif
433429

430+
aes_gcm_impl_state_t state __attribute__((cleanup(cleanup_gcm_state))) = {0};
431+
434432
// Construct the AES key.
435-
aes_key_t aes_key;
436-
HARDENED_TRY(aes_gcm_key_construct(key, &aes_key));
437-
HARDENED_TRY(load_key_if_sideloaded(aes_key));
433+
HARDENED_TRY(aes_gcm_key_construct(key, &state.aes_key));
434+
HARDENED_TRY(load_key_if_sideloaded(state.aes_key));
438435

439436
// Call the internal init operation.
440-
aes_gcm_context_t internal_ctx;
441-
internal_ctx.security_level = key->config.security_level;
442-
HARDENED_TRY(aes_gcm_decrypt_init(aes_key, iv->len, iv->data, &internal_ctx));
437+
state.internal_ctx.security_level = key->config.security_level;
438+
HARDENED_TRY(aes_gcm_decrypt_init(state.aes_key, iv->len, iv->data,
439+
&state.internal_ctx));
443440

444-
// Save the context and clear the key if needed.
445-
HARDENED_TRY(gcm_context_save(&internal_ctx, ctx));
446-
HARDENED_TRY(clear_key_if_sideloaded(internal_ctx.key));
441+
// Save the context.
442+
HARDENED_TRY(gcm_context_save(&state.internal_ctx, ctx));
447443

448444
// Verify the input buffer
449445
HARDENED_CHECK_EQ(kHardenedBoolTrue, OTCRYPTO_CHECK_BUF(iv));
@@ -465,17 +461,17 @@ otcrypto_status_t otcrypto_aes_gcm_update_aad(
465461
return OTCRYPTO_OK;
466462
}
467463

464+
aes_gcm_impl_state_t state __attribute__((cleanup(cleanup_gcm_state))) = {0};
465+
468466
// Restore the AES-GCM context object and load the key if needed.
469-
aes_gcm_context_t internal_ctx;
470-
HARDENED_TRY(gcm_context_restore(ctx, &internal_ctx));
471-
HARDENED_TRY(load_key_if_sideloaded(internal_ctx.key));
467+
HARDENED_TRY(gcm_context_restore(ctx, &state.internal_ctx));
468+
HARDENED_TRY(load_key_if_sideloaded(state.internal_ctx.key));
472469

473470
// Call the internal update operation.
474-
HARDENED_TRY(aes_gcm_update_aad(&internal_ctx, aad->len, aad->data));
471+
HARDENED_TRY(aes_gcm_update_aad(&state.internal_ctx, aad->len, aad->data));
475472

476-
// Save the context and clear the key if needed.
477-
HARDENED_TRY(gcm_context_save(&internal_ctx, ctx));
478-
HARDENED_TRY(clear_key_if_sideloaded(internal_ctx.key));
473+
// Save the context.
474+
HARDENED_TRY(gcm_context_save(&state.internal_ctx, ctx));
479475

480476
// Verify the input buffer
481477
HARDENED_CHECK_EQ(kHardenedBoolTrue, OTCRYPTO_CHECK_BUF(aad));
@@ -500,16 +496,17 @@ otcrypto_status_t otcrypto_aes_gcm_update_encrypted_data(
500496
return OTCRYPTO_OK;
501497
}
502498

499+
aes_gcm_impl_state_t state __attribute__((cleanup(cleanup_gcm_state))) = {0};
500+
503501
// Restore the AES-GCM context object and load the key if needed.
504-
aes_gcm_context_t internal_ctx;
505-
HARDENED_TRY(gcm_context_restore(ctx, &internal_ctx));
506-
HARDENED_TRY(load_key_if_sideloaded(internal_ctx.key));
502+
HARDENED_TRY(gcm_context_restore(ctx, &state.internal_ctx));
503+
HARDENED_TRY(load_key_if_sideloaded(state.internal_ctx.key));
507504
// Remask the key if it is not sideloaded.
508-
HARDENED_TRY(gcm_remask_key(&internal_ctx));
505+
HARDENED_TRY(gcm_remask_key(&state.internal_ctx));
509506

510507
// The output buffer must be long enough to hold all full blocks that will
511508
// exist after `input` is added.
512-
size_t partial_block_len = internal_ctx.input_len % kAesBlockNumBytes;
509+
size_t partial_block_len = state.internal_ctx.input_len % kAesBlockNumBytes;
513510
if (input->len > UINT32_MAX - partial_block_len) {
514511
// COVERAGE (MISSING) We do not cover too short output buffers.
515512
return OTCRYPTO_BAD_ARGS;
@@ -522,13 +519,12 @@ otcrypto_status_t otcrypto_aes_gcm_update_encrypted_data(
522519
}
523520

524521
// Call the internal update operation.
525-
HARDENED_TRY(aes_gcm_update_encrypted_data(&internal_ctx, input->len,
522+
HARDENED_TRY(aes_gcm_update_encrypted_data(&state.internal_ctx, input->len,
526523
input->data, output_bytes_written,
527524
output->data));
528525

529-
// Save the context and clear the key if needed.
530-
HARDENED_TRY(gcm_context_save(&internal_ctx, ctx));
531-
HARDENED_TRY(clear_key_if_sideloaded(internal_ctx.key));
526+
// Save the context.
527+
HARDENED_TRY(gcm_context_save(&state.internal_ctx, ctx));
532528

533529
// Verify the input buffers
534530
HARDENED_CHECK_EQ(kHardenedBoolTrue, OTCRYPTO_CHECK_BUF(input));
@@ -559,28 +555,28 @@ otcrypto_status_t otcrypto_aes_gcm_encrypt_final(
559555
// Randomize the tag before the operation.
560556
HARDENED_TRY(hardened_memshred(auth_tag->data, auth_tag->len));
561557

558+
aes_gcm_impl_state_t state __attribute__((cleanup(cleanup_gcm_state))) = {0};
559+
562560
// Restore the AES-GCM context object and load the key if needed.
563-
aes_gcm_context_t internal_ctx;
564-
HARDENED_TRY(gcm_context_restore(ctx, &internal_ctx));
565-
HARDENED_TRY(load_key_if_sideloaded(internal_ctx.key));
561+
HARDENED_TRY(gcm_context_restore(ctx, &state.internal_ctx));
562+
HARDENED_TRY(load_key_if_sideloaded(state.internal_ctx.key));
566563
// Remask the key if it is not sideloaded.
567-
HARDENED_TRY(gcm_remask_key(&internal_ctx));
564+
HARDENED_TRY(gcm_remask_key(&state.internal_ctx));
568565

569566
// If the partial block is nonempty, the output must be at least as long as
570567
// the partial block.
571-
size_t partial_block_len = internal_ctx.input_len % kAesBlockNumBytes;
568+
size_t partial_block_len = state.internal_ctx.input_len % kAesBlockNumBytes;
572569
if (ciphertext->len < partial_block_len) {
573570
return OTCRYPTO_BAD_ARGS;
574571
}
575572

576573
// Call the internal final operation.
577-
HARDENED_TRY(aes_gcm_encrypt_final(&internal_ctx, auth_tag->len,
574+
HARDENED_TRY(aes_gcm_encrypt_final(&state.internal_ctx, auth_tag->len,
578575
auth_tag->data, ciphertext_bytes_written,
579576
ciphertext->data));
580577

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

585581
// Verify the input buffers
586582
HARDENED_CHECK_EQ(kHardenedBoolTrue, OTCRYPTO_CHECK_BUF(ciphertext));
@@ -609,28 +605,28 @@ otcrypto_status_t otcrypto_aes_gcm_decrypt_final(
609605
// Check the tag length.
610606
HARDENED_TRY(aes_gcm_check_tag_length(auth_tag->len, tag_len));
611607

608+
aes_gcm_impl_state_t state __attribute__((cleanup(cleanup_gcm_state))) = {0};
609+
612610
// Restore the AES-GCM context object and load the key if needed.
613-
aes_gcm_context_t internal_ctx;
614-
HARDENED_TRY(gcm_context_restore(ctx, &internal_ctx));
615-
HARDENED_TRY(load_key_if_sideloaded(internal_ctx.key));
611+
HARDENED_TRY(gcm_context_restore(ctx, &state.internal_ctx));
612+
HARDENED_TRY(load_key_if_sideloaded(state.internal_ctx.key));
616613
// Remask the key if it is not sideloaded.
617-
HARDENED_TRY(gcm_remask_key(&internal_ctx));
614+
HARDENED_TRY(gcm_remask_key(&state.internal_ctx));
618615

619616
// If the partial block is nonempty, the output must be at least as long as
620617
// the partial block.
621-
size_t partial_block_len = internal_ctx.input_len % kAesBlockNumBytes;
618+
size_t partial_block_len = state.internal_ctx.input_len % kAesBlockNumBytes;
622619
if (plaintext->len < partial_block_len) {
623620
return OTCRYPTO_BAD_ARGS;
624621
}
625622

626623
// Call the internal final operation.
627-
HARDENED_TRY(aes_gcm_decrypt_final(&internal_ctx, auth_tag->len,
624+
HARDENED_TRY(aes_gcm_decrypt_final(&state.internal_ctx, auth_tag->len,
628625
auth_tag->data, plaintext_bytes_written,
629626
plaintext->data, success));
630627

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

635631
// Verify the input buffers
636632
HARDENED_CHECK_EQ(kHardenedBoolTrue, OTCRYPTO_CHECK_BUF(auth_tag));

0 commit comments

Comments
 (0)