Skip to content

Commit faed04c

Browse files
committed
[crypto/aes] Cleanup on failures
Use the cleanup attribute in order to attach cleanup functions to sensitive variables together with a guard to cleanup the hardware. These functions are called when the variables go out of scope. Hence, we clear sensitive variables (hardened_memshred) or 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 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 manuallt call the clean in drivers). Signed-off-by: Siemen Dhooghe <sdhooghe@google.com>
1 parent b64522c commit faed04c

3 files changed

Lines changed: 55 additions & 21 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: 43 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,28 @@ otcrypto_status_t otcrypto_aes_padded_plaintext_length(
279279
return OTCRYPTO_OK;
280280
}
281281

282+
/**
283+
* Consolidated state for AES operations.
284+
* Grouping these reduces the compiler RAII tracking overhead to a single
285+
* variable.
286+
*/
287+
typedef struct {
288+
aes_key_t key;
289+
aes_block_t iv;
290+
aes_block_t block_in;
291+
aes_block_t block_out;
292+
} aes_impl_state_t;
293+
294+
/**
295+
* Cleanup function.
296+
*/
297+
static void cleanup_aes_state(aes_impl_state_t *state) {
298+
(void)aes_clear();
299+
(void)keymgr_sideload_clear_aes();
300+
hardened_memshred((uint32_t *)state,
301+
sizeof(aes_impl_state_t) / sizeof(uint32_t));
302+
}
303+
282304
/**
283305
* Performs the AES operation.
284306
*
@@ -297,6 +319,10 @@ static otcrypto_status_t otcrypto_aes_impl(
297319
otcrypto_aes_mode_t aes_mode, otcrypto_aes_operation_t aes_operation,
298320
const otcrypto_const_byte_buf_t *cipher_input,
299321
otcrypto_aes_padding_t aes_padding, otcrypto_byte_buf_t *cipher_output) {
322+
// Set the attribute with the state to clean up all sensitive variables and
323+
// clear the HW upon exit.
324+
aes_impl_state_t state __attribute__((cleanup(cleanup_aes_state))) = {0};
325+
300326
// Calculate the number of blocks for the input, including the padding for
301327
// encryption.
302328
size_t input_nblocks;
@@ -324,7 +350,6 @@ static otcrypto_status_t otcrypto_aes_impl(
324350

325351
// Construct the IV and check its length. ECB mode will ignore the IV, so in
326352
// this case it is left uninitialized.
327-
aes_block_t aes_iv;
328353
if (aes_mode == kAesCipherModeEcb) {
329354
HARDENED_CHECK_EQ(launder32(aes_mode), kAesCipherModeEcb);
330355
} else {
@@ -335,23 +360,22 @@ static otcrypto_status_t otcrypto_aes_impl(
335360
return OTCRYPTO_BAD_ARGS;
336361
}
337362
HARDENED_CHECK_EQ(launder32(iv->len), kAesBlockNumWords);
338-
HARDENED_TRY(hardened_memcpy(aes_iv.data, iv->data, kAesBlockNumWords));
363+
HARDENED_TRY(hardened_memcpy(state.iv.data, iv->data, kAesBlockNumWords));
339364
}
340365

341366
// Parse the AES key.
342-
aes_key_t aes_key;
343-
HARDENED_TRY(aes_key_construct(key, aes_mode, &aes_key));
367+
HARDENED_TRY(aes_key_construct(key, aes_mode, &state.key));
344368

345369
// Start the operation (encryption or decryption).
346370
otcrypto_aes_operation_t aes_operation_started = launder32(0);
347371
switch (aes_operation) {
348372
case kOtcryptoAesOperationEncrypt:
349-
HARDENED_TRY(aes_encrypt_begin(aes_key, &aes_iv));
373+
HARDENED_TRY(aes_encrypt_begin(state.key, &state.iv));
350374
aes_operation_started =
351375
launder32(aes_operation_started) | kOtcryptoAesOperationEncrypt;
352376
break;
353377
case kOtcryptoAesOperationDecrypt:
354-
HARDENED_TRY(aes_decrypt_begin(aes_key, &aes_iv));
378+
HARDENED_TRY(aes_decrypt_begin(state.key, &state.iv));
355379
aes_operation_started =
356380
launder32(aes_operation_started) | kOtcryptoAesOperationDecrypt;
357381
break;
@@ -389,45 +413,44 @@ static otcrypto_status_t otcrypto_aes_impl(
389413
//
390414
// See the AES driver for details.
391415
const size_t block_offset = input_nblocks >= 3 ? 2 : 1;
392-
aes_block_t block_in;
393-
aes_block_t block_out;
394416
size_t i;
395417

396418
// Provide the first `block_offset` number of input blocks and call the AES
397419
// cipher.
398420
for (i = 0; launder32(i) < block_offset; ++i) {
399-
HARDENED_TRY(get_block(cipher_input, aes_padding, i, &block_in));
400-
HARDENED_TRY(aes_update(/*dest=*/NULL, &block_in));
421+
HARDENED_TRY(get_block(cipher_input, aes_padding, i, &state.block_in));
422+
HARDENED_TRY(aes_update(/*dest=*/NULL, &state.block_in));
401423
}
402424
// Check that the loop ran for the correct number of iterations.
403425
HARDENED_CHECK_EQ(i, block_offset);
404426

405427
// Call the AES cipher while providing new input and copying data to the
406428
// output buffer.
407429
for (i = block_offset; launder32(i) < input_nblocks; ++i) {
408-
HARDENED_TRY(get_block(cipher_input, aes_padding, i, &block_in));
409-
HARDENED_TRY(hardened_memshred(block_out.data, ARRAYSIZE(block_out.data)));
410-
HARDENED_TRY(aes_update(&block_out, &block_in));
430+
HARDENED_TRY(get_block(cipher_input, aes_padding, i, &state.block_in));
431+
HARDENED_TRY(hardened_memshred(state.block_out.data,
432+
ARRAYSIZE(state.block_out.data)));
433+
HARDENED_TRY(aes_update(&state.block_out, &state.block_in));
411434
// Byte buffers passed as input may not be word-aligned, so we cannot
412435
// use `hardened_memcpy`.
413436
// Hence, use `randomized_bytecopy` instead.
414437
HARDENED_TRY(randomized_bytecopy(
415438
&cipher_output->data[(i - block_offset) * kAesBlockNumBytes],
416-
block_out.data, kAesBlockNumBytes));
439+
state.block_out.data, kAesBlockNumBytes));
417440
}
418441
// Check that the loop ran for the correct number of iterations.
419442
HARDENED_CHECK_EQ(i, input_nblocks);
420443

421444
// Retrieve the output from the final `block_offset` blocks (providing no
422445
// input).
423446
for (i = block_offset; i > 0; --i) {
424-
HARDENED_TRY(aes_update(&block_out, /*src=*/NULL));
447+
HARDENED_TRY(aes_update(&state.block_out, /*src=*/NULL));
425448
// Byte buffers passed as input may not be word-aligned, so we cannot
426449
// use `hardened_memcpy`.
427450
// Hence, use `randomized_bytecopy` instead.
428451
HARDENED_TRY(randomized_bytecopy(
429452
&cipher_output->data[(input_nblocks - i) * kAesBlockNumBytes],
430-
block_out.data, kAesBlockNumBytes));
453+
state.block_out.data, kAesBlockNumBytes));
431454
}
432455
// Check that the loop ran for the correct number of iterations.
433456
HARDENED_CHECK_EQ(launder32(i), 0);
@@ -439,19 +462,18 @@ static otcrypto_status_t otcrypto_aes_impl(
439462
hardened_bool_t encrypt = kHardenedBoolTrue;
440463
if (aes_operation == kOtcryptoAesOperationDecrypt)
441464
encrypt = kHardenedBoolFalse;
442-
HARDENED_TRY(aes_verify_ctrl_reg(aes_key, encrypt));
465+
HARDENED_TRY(aes_verify_ctrl_reg(state.key, encrypt));
443466
HARDENED_TRY(aes_verify_ctrl_aux_reg());
444467

445468
// Deinitialize the AES block and update the IV (in ECB mode, skip the IV).
446469
if (aes_mode == kAesCipherModeEcb) {
447470
HARDENED_TRY(aes_end(NULL));
448471
} else {
449-
HARDENED_TRY(aes_end(&aes_iv));
450-
HARDENED_TRY(hardened_memcpy(iv->data, aes_iv.data, kAesBlockNumWords));
472+
HARDENED_TRY(aes_end(&state.iv));
473+
HARDENED_TRY(hardened_memcpy(iv->data, state.iv.data, kAesBlockNumWords));
451474
}
452475

453-
// In case the key was sideloaded, clear it.
454-
return otcrypto_eval_exit(keymgr_sideload_clear_aes());
476+
return otcrypto_eval_exit(OTCRYPTO_OK);
455477
}
456478

457479
otcrypto_status_t otcrypto_aes_padding_strip(

0 commit comments

Comments
 (0)