Skip to content

Commit

Permalink
Fips test suite tests (#1594)
Browse files Browse the repository at this point in the history
  • Loading branch information
nquarton authored Jul 18, 2024
1 parent ae6fe80 commit 9909652
Show file tree
Hide file tree
Showing 28 changed files with 2,646 additions and 100 deletions.
6 changes: 6 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 10 additions & 3 deletions builder/src/firmware.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ pub const ROM_FAKE_WITH_UART: FwId = FwId {
features: &["emu", "fake-rom"],
};

pub const ROM_WITH_UART_FIPS_TEST_HOOKS: FwId = FwId {
pub const ROM_WITH_FIPS_TEST_HOOKS: FwId = FwId {
crate_name: "caliptra-rom",
bin_name: "caliptra-rom",
features: &["emu", "fips-test-hooks"],
features: &["fips-test-hooks"],
};

pub const FMC_WITH_UART: FwId = FwId {
Expand All @@ -63,6 +63,12 @@ pub const APP_WITH_UART: FwId = FwId {
features: &["emu", "fips_self_test"],
};

pub const APP_WITH_UART_FIPS_TEST_HOOKS: FwId = FwId {
crate_name: "caliptra-runtime",
bin_name: "caliptra-runtime",
features: &["emu", "fips_self_test", "fips-test-hooks"],
};

pub const APP_WITH_UART_FPGA: FwId = FwId {
crate_name: "caliptra-runtime",
bin_name: "caliptra-runtime",
Expand Down Expand Up @@ -374,11 +380,12 @@ pub const REGISTERED_FW: &[&FwId] = &[
&ROM,
&ROM_WITH_UART,
&ROM_FAKE_WITH_UART,
&ROM_WITH_UART_FIPS_TEST_HOOKS,
&ROM_WITH_FIPS_TEST_HOOKS,
&FMC_WITH_UART,
&FMC_FAKE_WITH_UART,
&APP,
&APP_WITH_UART,
&APP_WITH_UART_FIPS_TEST_HOOKS,
&APP_WITH_UART_FPGA,
&caliptra_builder_tests::FWID,
&hw_model_tests::MAILBOX_RESPONDER,
Expand Down
30 changes: 30 additions & 0 deletions drivers/src/ecc384.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,15 @@ impl Ecc384 {

// Pairwise consistency check.
let digest = Array4x12::new([0u32; 12]);

#[cfg(feature = "fips-test-hooks")]
let pub_key = unsafe {
crate::FipsTestHook::corrupt_data_if_hook_set(
crate::FipsTestHook::ECC384_PAIRWISE_CONSISTENCY_ERROR,
&pub_key,
)
};

match self.sign(&priv_key.into(), &pub_key, &digest, trng) {
Ok(mut sig) => sig.zeroize(),
Err(_) => {
Expand Down Expand Up @@ -405,6 +414,13 @@ impl Ecc384 {
data: &Ecc384Scalar,
trng: &mut Trng,
) -> CaliptraResult<Ecc384Signature> {
#[cfg(feature = "fips-test-hooks")]
unsafe {
crate::FipsTestHook::error_if_hook_set(
crate::FipsTestHook::ECC384_SIGNATURE_GENERATE_FAILURE,
)?
}

let mut sig_result = self.sign_internal(priv_key, data, trng);
let sig = okmutref(&mut sig_result)?;

Expand All @@ -413,6 +429,15 @@ impl Ecc384 {
// Not using standard error flow here for increased CFI safety
// An error here will end up reporting the CFI assert failure
caliptra_cfi_lib::cfi_assert_eq_12_words(&r.0, &sig.r.0);

#[cfg(feature = "fips-test-hooks")]
let sig_result = unsafe {
crate::FipsTestHook::corrupt_data_if_hook_set(
crate::FipsTestHook::ECC384_CORRUPT_SIGNATURE,
&sig_result,
)
};

sig_result
}

Expand Down Expand Up @@ -473,6 +498,11 @@ impl Ecc384 {
digest: &Ecc384Scalar,
signature: &Ecc384Signature,
) -> CaliptraResult<Array4xN<12, 48>> {
#[cfg(feature = "fips-test-hooks")]
unsafe {
crate::FipsTestHook::error_if_hook_set(crate::FipsTestHook::ECC384_VERIFY_FAILURE)?
}

// If R or S are not in the range [1, N-1], signature check must fail
if !Self::scalar_range_check(&signature.r) || !Self::scalar_range_check(&signature.s) {
return Err(CaliptraError::DRIVER_ECC384_SCALAR_RANGE_CHECK_FAILED);
Expand Down
64 changes: 62 additions & 2 deletions drivers/src/fips_test_hooks.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Licensed under the Apache-2.0 license

use caliptra_error::CaliptraResult;
use caliptra_registers::soc_ifc::SocIfcReg;

pub struct FipsTestHook;
Expand All @@ -11,8 +12,38 @@ impl FipsTestHook {
// Set by external test
pub const CONTINUE: u8 = 0x10;
pub const HALT_SELF_TESTS: u8 = 0x21;
pub const SHA384_ERROR: u8 = 0x22;
pub const LMS_ERROR: u8 = 0x23;
pub const SHA1_CORRUPT_DIGEST: u8 = 0x22;
pub const SHA256_CORRUPT_DIGEST: u8 = 0x23;
pub const SHA384_CORRUPT_DIGEST: u8 = 0x24;
pub const SHA2_512_384_ACC_CORRUPT_DIGEST_512: u8 = 0x25;
pub const ECC384_CORRUPT_SIGNATURE: u8 = 0x26;
pub const HMAC384_CORRUPT_TAG: u8 = 0x27;
pub const LMS_CORRUPT_INPUT: u8 = 0x28;
pub const ECC384_PAIRWISE_CONSISTENCY_ERROR: u8 = 0x29;
pub const HALT_FW_LOAD: u8 = 0x2A;
pub const HALT_SHUTDOWN_RT: u8 = 0x2B;

pub const SHA1_DIGEST_FAILURE: u8 = 0x40;
pub const SHA256_DIGEST_FAILURE: u8 = 0x41;
pub const SHA384_DIGEST_FAILURE: u8 = 0x42;
pub const SHA2_512_384_ACC_DIGEST_512_FAILURE: u8 = 0x43;
pub const SHA2_512_384_ACC_START_OP_FAILURE: u8 = 0x44;
pub const ECC384_SIGNATURE_GENERATE_FAILURE: u8 = 0x45;
pub const ECC384_VERIFY_FAILURE: u8 = 0x46;
pub const HMAC384_FAILURE: u8 = 0x47;
pub const LMS_VERIFY_FAILURE: u8 = 0x48;

// FW Load Errors
pub const FW_LOAD_VENDOR_PUB_KEY_DIGEST_FAILURE: u8 = 0x50;
pub const FW_LOAD_OWNER_PUB_KEY_DIGEST_FAILURE: u8 = 0x51;
pub const FW_LOAD_HEADER_DIGEST_FAILURE: u8 = 0x52;
pub const FW_LOAD_VENDOR_ECC_VERIFY_FAILURE: u8 = 0x53;
pub const FW_LOAD_OWNER_ECC_VERIFY_FAILURE: u8 = 0x54;
pub const FW_LOAD_OWNER_TOC_DIGEST_FAILURE: u8 = 0x55;
pub const FW_LOAD_FMC_DIGEST_FAILURE: u8 = 0x56;
pub const FW_LOAD_RUNTIME_DIGEST_FAILURE: u8 = 0x57;
pub const FW_LOAD_VENDOR_LMS_VERIFY_FAILURE: u8 = 0x58;
pub const FW_LOAD_OWNER_LMS_VERIFY_FAILURE: u8 = 0x59;

/// # Safety
///
Expand Down Expand Up @@ -50,6 +81,35 @@ impl FipsTestHook {

*data
}

/// # Safety
///
/// This function enables a different test hook to allow for basic state machines
/// (Only when the hook_cmd matches the value from get_fips_test_hook_code)
pub unsafe fn update_hook_cmd_if_hook_set(hook_cmd: u8, new_hook_cmd: u8) {
if get_fips_test_hook_code() == hook_cmd {
set_fips_test_hook_code(new_hook_cmd);
}
}

/// # Safety
///
/// This function calls other unsafe functions to check the test hook code
pub unsafe fn hook_cmd_is_set(hook_cmd: u8) -> bool {
get_fips_test_hook_code() == hook_cmd
}

/// # Safety
///
/// This function checks the current hook code and returns the
/// FIPS_HOOKS_INJECTED_ERROR if enabled
pub unsafe fn error_if_hook_set(hook_cmd: u8) -> CaliptraResult<()> {
if get_fips_test_hook_code() == hook_cmd {
Err(caliptra_error::CaliptraError::FIPS_HOOKS_INJECTED_ERROR)
} else {
Ok(())
}
}
}

/// # Safety
Expand Down
9 changes: 9 additions & 0 deletions drivers/src/hmac384.rs
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,15 @@ impl<'a> Hmac384Op<'a> {

// Calculate the hmac of the final block
let buf = &self.buf[..self.buf_idx];

#[cfg(feature = "fips-test-hooks")]
let buf = unsafe {
crate::FipsTestHook::corrupt_data_if_hook_set(
crate::FipsTestHook::HMAC384_CORRUPT_TAG,
&buf,
)
};

self.hmac_engine.hmac_partial_block(
buf,
self.is_first(),
Expand Down
5 changes: 5 additions & 0 deletions drivers/src/hmac384_kdf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ pub fn hmac384_kdf(
trng: &mut Trng,
output: Hmac384Tag,
) -> CaliptraResult<()> {
#[cfg(feature = "fips-test-hooks")]
unsafe {
crate::FipsTestHook::error_if_hook_set(crate::FipsTestHook::HMAC384_FAILURE)?
}

let mut hmac_op = hmac.hmac_init(&key, trng, output)?;

hmac_op.update(&1_u32.to_be_bytes())?;
Expand Down
7 changes: 6 additions & 1 deletion drivers/src/lms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,7 @@ impl Lms {
#[cfg(feature = "fips-test-hooks")]
let input_string = unsafe {
crate::FipsTestHook::corrupt_data_if_hook_set(
crate::FipsTestHook::LMS_ERROR,
crate::FipsTestHook::LMS_CORRUPT_INPUT,
&input_string,
)
};
Expand Down Expand Up @@ -514,6 +514,11 @@ impl Lms {
lms_public_key: &LmsPublicKey<N>,
lms_sig: &LmsSignature<N, P, H>,
) -> CaliptraResult<HashValue<N>> {
#[cfg(feature = "fips-test-hooks")]
unsafe {
crate::FipsTestHook::error_if_hook_set(crate::FipsTestHook::LMS_VERIFY_FAILURE)?
}

if lms_sig.ots.ots_type != lms_public_key.otstype {
return Err(CaliptraError::DRIVER_LMS_SIGNATURE_LMOTS_DOESNT_MATCH_PUBKEY_LMOTS);
}
Expand Down
15 changes: 15 additions & 0 deletions drivers/src/sha1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ impl Sha1 {
/// * `buf` - Buffer to calculate the digest over
#[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)]
pub fn digest(&mut self, buf: &[u8]) -> CaliptraResult<Array4x5> {
#[cfg(feature = "fips-test-hooks")]
unsafe {
crate::FipsTestHook::error_if_hook_set(crate::FipsTestHook::SHA1_DIGEST_FAILURE)?
}

// Check if the buffer is not large
if buf.len() > SHA1_MAX_DATA_SIZE {
return Err(CaliptraError::DRIVER_SHA1_MAX_DATA);
Expand Down Expand Up @@ -90,6 +95,16 @@ impl Sha1 {
}
}

#[cfg(feature = "fips-test-hooks")]
{
self.compressor.hash = unsafe {
crate::FipsTestHook::corrupt_data_if_hook_set(
crate::FipsTestHook::SHA1_CORRUPT_DIGEST,
&self.compressor.hash,
)
};
}

Ok(self.compressor.hash().into())
}

Expand Down
13 changes: 13 additions & 0 deletions drivers/src/sha256.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,11 @@ impl Sha256Alg for Sha256 {
///
/// * `buf` - Buffer to calculate the digest over
fn digest(&mut self, buf: &[u8]) -> CaliptraResult<Array4x8> {
#[cfg(feature = "fips-test-hooks")]
unsafe {
crate::FipsTestHook::error_if_hook_set(crate::FipsTestHook::SHA256_DIGEST_FAILURE)?
}

// Check if the buffer is not large
if buf.len() > SHA256_MAX_DATA_SIZE {
return Err(CaliptraError::DRIVER_SHA256_MAX_DATA);
Expand Down Expand Up @@ -123,6 +128,14 @@ impl Sha256Alg for Sha256 {

let digest = Array4x8::read_from_reg(self.sha256.regs().digest());

#[cfg(feature = "fips-test-hooks")]
let digest = unsafe {
crate::FipsTestHook::corrupt_data_if_hook_set(
crate::FipsTestHook::SHA256_CORRUPT_DIGEST,
&digest,
)
};

self.zeroize_internal();

Ok(digest)
Expand Down
26 changes: 26 additions & 0 deletions drivers/src/sha2_512_384acc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,15 @@ impl Sha2_512_384Acc {
) -> CaliptraResult<Option<Sha2_512_384AccOp>> {
let sha_acc = self.sha512_acc.regs();

#[cfg(feature = "fips-test-hooks")]
if unsafe {
crate::FipsTestHook::hook_cmd_is_set(
crate::FipsTestHook::SHA2_512_384_ACC_START_OP_FAILURE,
)
} {
return Ok(None);
}

match assumed_lock_state {
ShaAccLockState::NotAcquired => {
if sha_acc.lock().read().lock() {
Expand Down Expand Up @@ -247,6 +256,13 @@ impl Sha2_512_384AccOp<'_> {
maintain_data_endianess: bool,
digest: Sha512Digest,
) -> CaliptraResult<()> {
#[cfg(feature = "fips-test-hooks")]
unsafe {
crate::FipsTestHook::error_if_hook_set(
crate::FipsTestHook::SHA2_512_384_ACC_DIGEST_512_FAILURE,
)?
}

self.digest_generic(
dlen,
start_address,
Expand All @@ -258,6 +274,16 @@ impl Sha2_512_384AccOp<'_> {
let sha_acc = self.sha512_acc.regs();
*digest = Array4x16::read_from_reg(sha_acc.digest());

#[cfg(feature = "fips-test-hooks")]
{
*digest = unsafe {
crate::FipsTestHook::corrupt_data_if_hook_set(
crate::FipsTestHook::SHA2_512_384_ACC_CORRUPT_DIGEST_512,
digest,
)
};
}

// Zeroize the hardware registers.
self.sha512_acc
.regs_mut()
Expand Down
7 changes: 6 additions & 1 deletion drivers/src/sha384.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ impl Sha384 {
///
#[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)]
pub fn digest(&mut self, buf: &[u8]) -> CaliptraResult<Array4x12> {
#[cfg(feature = "fips-test-hooks")]
unsafe {
crate::FipsTestHook::error_if_hook_set(crate::FipsTestHook::SHA384_DIGEST_FAILURE)?
}

// Check if the buffer is not large
if buf.len() > SHA384_MAX_DATA_SIZE {
return Err(CaliptraError::DRIVER_SHA384_MAX_DATA_ERR);
Expand Down Expand Up @@ -105,7 +110,7 @@ impl Sha384 {
#[cfg(feature = "fips-test-hooks")]
let digest = unsafe {
crate::FipsTestHook::corrupt_data_if_hook_set(
crate::FipsTestHook::SHA384_ERROR,
crate::FipsTestHook::SHA384_CORRUPT_DIGEST,
&digest,
)
};
Expand Down
4 changes: 4 additions & 0 deletions error/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,10 @@ impl CaliptraError {
pub const KAT_LMS_DIGEST_MISMATCH: CaliptraError = CaliptraError::new_const(0x90070002);

pub const ROM_INTEGRITY_FAILURE: CaliptraError = CaliptraError::new_const(0x90080001);

// TODO: What base value is right for this?
// FIPS Hooks
pub const FIPS_HOOKS_INJECTED_ERROR: CaliptraError = CaliptraError::new_const(0x90100000);
}

impl From<core::num::NonZeroU32> for crate::CaliptraError {
Expand Down
1 change: 1 addition & 0 deletions image/verify/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ caliptra-cfi-lib = { workspace = true, features = ["cfi-test" ] }
default = ["std"]
std = ["caliptra-image-types/std"]
no-cfi = []
fips-test-hooks = []
Loading

0 comments on commit 9909652

Please sign in to comment.