From 6bfd80923b68ecfeeb83023d7cf28a0dd766260e Mon Sep 17 00:00:00 2001 From: Nick Quarton <139178705+nquarton@users.noreply.github.com> Date: Tue, 16 Jul 2024 07:31:03 -0700 Subject: [PATCH] Adding ECC error checking during waits (#1610) --- FROZEN_IMAGES.sha384sum | 4 +- drivers/src/ecc384.rs | 44 +++++++++++++++---- error/src/lib.rs | 1 + .../runtime_integration_tests/test_ecdsa.rs | 29 ++++++++++++ sw-emulator/lib/periph/src/asym_ecc384.rs | 10 +++++ 5 files changed, 77 insertions(+), 11 deletions(-) diff --git a/FROZEN_IMAGES.sha384sum b/FROZEN_IMAGES.sha384sum index 2574d00c08..7971239a1d 100644 --- a/FROZEN_IMAGES.sha384sum +++ b/FROZEN_IMAGES.sha384sum @@ -1,3 +1,3 @@ # WARNING: Do not update this file without the approval of the Caliptra TAC -e3c62ff9b5ca7873001e516a22b62a3090bc470ddb4664ac6feef2ebabb0b65d880a5a38ff31b5250817a39c79d3a68e caliptra-rom-no-log.bin -cefa26982b60ad32595053ef8e516137642a7760434481b1fe4371b4fbaeeb1528b15e8523f8d8c2c9cc9d5920fe9e9b caliptra-rom-with-log.bin +5a97c3e30c2ceaad209745367a5dfd583e6a0ad4f43a6f4254c03d6e929db671c26ac6ffe738a843b98684761f2241b4 caliptra-rom-no-log.bin +8b08a1ce76fd8411bee31c9453c16ab841e3c6ae5716c10a08bb6891f233523e2bd3b263b73e83aa54e6545ab35322fb caliptra-rom-with-log.bin diff --git a/drivers/src/ecc384.rs b/drivers/src/ecc384.rs index 6bf4ecfea5..1333c0ad1c 100644 --- a/drivers/src/ecc384.rs +++ b/drivers/src/ecc384.rs @@ -19,7 +19,7 @@ use crate::{ }; #[cfg(not(feature = "no-cfi"))] use caliptra_cfi_derive::cfi_impl_fn; -use caliptra_registers::ecc::EccReg; +use caliptra_registers::ecc::{EccReg, RegisterBlock}; use core::cmp::Ordering; use zerocopy::{AsBytes, FromBytes}; use zeroize::Zeroize; @@ -182,6 +182,32 @@ impl Ecc384 { false } + // Wait on the provided condition OR the error condition defined in this function + // In the event of the error condition being set, clear the error bits and return an error + fn wait(regs: RegisterBlock, condition: F) -> CaliptraResult<()> + where + F: Fn() -> bool, + { + let err_condition = || { + (u32::from(regs.intr_block_rf().error_global_intr_r().read()) != 0) + || (u32::from(regs.intr_block_rf().error_internal_intr_r().read()) != 0) + }; + + // Wait for either the given condition or the error condition + wait::until(|| (condition() || err_condition())); + + if err_condition() { + // Clear the errors + // error_global_intr_r is RO + regs.intr_block_rf() + .error_internal_intr_r() + .write(|_| u32::from(regs.intr_block_rf().error_internal_intr_r().read()).into()); + return Err(CaliptraError::DRIVER_ECC384_HW_ERROR); + } + + Ok(()) + } + /// Generate ECC-384 Key Pair /// /// # Arguments @@ -206,7 +232,7 @@ impl Ecc384 { let mut priv_key = priv_key; // Wait for hardware ready - wait::until(|| ecc.status().read().ready()); + Ecc384::wait(ecc, || ecc.status().read().ready())?; // Configure hardware to route keys to user specified hardware blocks match &mut priv_key { @@ -245,7 +271,7 @@ impl Ecc384 { ecc.ctrl().write(|w| w.ctrl(|w| w.keygen())); // Wait for command to complete - wait::until(|| ecc.status().read().valid()); + Ecc384::wait(ecc, || ecc.status().read().valid())?; // Copy the private key match &mut priv_key { @@ -290,7 +316,7 @@ impl Ecc384 { let ecc = self.ecc.regs_mut(); // Wait for hardware ready - wait::until(|| ecc.status().read().ready()); + Ecc384::wait(ecc, || ecc.status().read().ready())?; // Generate an IV. let iv = trng.generate()?; @@ -299,7 +325,7 @@ impl Ecc384 { ecc.ctrl().write(|w| w.pcr_sign(true).ctrl(|w| w.signing())); // Wait for command to complete - wait::until(|| ecc.status().read().valid()); + Ecc384::wait(ecc, || ecc.status().read().valid())?; // Copy signature let signature = Ecc384Signature { @@ -322,7 +348,7 @@ impl Ecc384 { let ecc = self.ecc.regs_mut(); // Wait for hardware ready - wait::until(|| ecc.status().read().ready()); + Ecc384::wait(ecc, || ecc.status().read().ready())?; // Copy private key match priv_key { @@ -344,7 +370,7 @@ impl Ecc384 { ecc.ctrl().write(|w| w.ctrl(|w| w.signing())); // Wait for command to complete - wait::until(|| ecc.status().read().valid()); + Ecc384::wait(ecc, || ecc.status().read().valid())?; // Copy signature let signature = Ecc384Signature { @@ -455,7 +481,7 @@ impl Ecc384 { let ecc = self.ecc.regs_mut(); // Wait for hardware ready - wait::until(|| ecc.status().read().ready()); + Ecc384::wait(ecc, || ecc.status().read().ready())?; // Copy public key to registers pub_key.x.write_to_reg(ecc.pubkey_x()); @@ -472,7 +498,7 @@ impl Ecc384 { ecc.ctrl().write(|w| w.ctrl(|w| w.verifying())); // Wait for command to complete - wait::until(|| ecc.status().read().valid()); + Ecc384::wait(ecc, || ecc.status().read().valid())?; // Copy the random value let verify_r = Array4x12::read_from_reg(ecc.verify_r()); diff --git a/error/src/lib.rs b/error/src/lib.rs index c0179e1eca..169894872e 100644 --- a/error/src/lib.rs +++ b/error/src/lib.rs @@ -113,6 +113,7 @@ impl CaliptraError { pub const DRIVER_ECC384_SCALAR_RANGE_CHECK_FAILED: CaliptraError = CaliptraError::new_const(0x0005000f); pub const DRIVER_ECC384_KEYGEN_BAD_USAGE: CaliptraError = CaliptraError::new_const(0x00050010); + pub const DRIVER_ECC384_HW_ERROR: CaliptraError = CaliptraError::new_const(0x00050011); pub const DRIVER_KV_ERASE_USE_LOCK_SET_FAILURE: CaliptraError = CaliptraError::new_const(0x00060001); diff --git a/runtime/tests/runtime_integration_tests/test_ecdsa.rs b/runtime/tests/runtime_integration_tests/test_ecdsa.rs index b5dbc229bf..c3b646e23c 100644 --- a/runtime/tests/runtime_integration_tests/test_ecdsa.rs +++ b/runtime/tests/runtime_integration_tests/test_ecdsa.rs @@ -248,3 +248,32 @@ fn test_ecdsa_verify_bad_chksum() { resp, ); } + +// HW errors are not supported on the SW emulator yet +#[cfg(any(feature = "verilator", feature = "fpga_realtime"))] +#[test] +fn test_ecdsa_hw_failure() { + let mut model = run_rt_test(None, None, None); + + let mut cmd = MailboxReq::EcdsaVerify(EcdsaVerifyReq { + hdr: MailboxReqHeader { chksum: 0 }, + pub_key_x: [0u8; 48], + pub_key_y: [0u8; 48], + signature_r: [0xa5u8; 48], + signature_s: [0xa5u8; 48], + }); + cmd.populate_chksum().unwrap(); + + let resp = model + .mailbox_execute( + u32::from(CommandId::ECDSA384_VERIFY), + cmd.as_bytes().unwrap(), + ) + .unwrap_err(); + + assert_error( + &mut model, + caliptra_drivers::CaliptraError::DRIVER_ECC384_HW_ERROR, + resp, + ); +} diff --git a/sw-emulator/lib/periph/src/asym_ecc384.rs b/sw-emulator/lib/periph/src/asym_ecc384.rs index c715565837..859890a200 100644 --- a/sw-emulator/lib/periph/src/asym_ecc384.rs +++ b/sw-emulator/lib/periph/src/asym_ecc384.rs @@ -204,6 +204,14 @@ pub struct AsymEcc384 { #[register(offset = 0x0000_0614)] key_write_status: ReadOnlyRegister, + /// Error Global Intr register + #[register(offset = 0x0000_080c)] + error_global_intr: ReadOnlyRegister, + + /// Error Internal Intr register + #[register(offset = 0x0000_0814)] + error_internal_intr: ReadOnlyRegister, + /// Key Vault key_vault: KeyVault, @@ -272,6 +280,8 @@ impl AsymEcc384 { op_key_read_complete_action: None, op_seed_read_complete_action: None, op_key_write_complete_action: None, + error_global_intr: ReadOnlyRegister::new(0), + error_internal_intr: ReadOnlyRegister::new(0), } }