@@ -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-
279277otcrypto_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