Skip to content

Commit

Permalink
Adding LMS verify service to runtime (#1420)
Browse files Browse the repository at this point in the history
  • Loading branch information
nquarton authored Apr 8, 2024
1 parent b4f3e28 commit cc31e5f
Show file tree
Hide file tree
Showing 9 changed files with 1,037 additions and 5 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

25 changes: 25 additions & 0 deletions api/src/mailbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ impl CommandId {
pub const GET_FMC_ALIAS_CERT: Self = Self(0x43455246); // "CERF"
pub const GET_RT_ALIAS_CERT: Self = Self(0x43455252); // "CERR"
pub const ECDSA384_VERIFY: Self = Self(0x53494756); // "SIGV"
pub const LMS_VERIFY: Self = Self(0x4C4D5356); // "LMSV"
pub const STASH_MEASUREMENT: Self = Self(0x4D454153); // "MEAS"
pub const INVOKE_DPE: Self = Self(0x44504543); // "DPEC"
pub const DISABLE_ATTESTATION: Self = Self(0x4453424C); // "DSBL"
Expand Down Expand Up @@ -218,6 +219,7 @@ impl Default for MailboxResp {
#[allow(clippy::large_enum_variant)]
pub enum MailboxReq {
EcdsaVerify(EcdsaVerifyReq),
LmsVerify(LmsVerifyReq),
GetLdevCert(GetLdevCertReq),
StashMeasurement(StashMeasurementReq),
InvokeDpeCommand(InvokeDpeReq),
Expand All @@ -240,6 +242,7 @@ impl MailboxReq {
pub fn as_bytes(&self) -> CaliptraResult<&[u8]> {
match self {
MailboxReq::EcdsaVerify(req) => Ok(req.as_bytes()),
MailboxReq::LmsVerify(req) => Ok(req.as_bytes()),
MailboxReq::StashMeasurement(req) => Ok(req.as_bytes()),
MailboxReq::InvokeDpeCommand(req) => req.as_bytes_partial(),
MailboxReq::FipsVersion(req) => Ok(req.as_bytes()),
Expand All @@ -262,6 +265,7 @@ impl MailboxReq {
pub fn as_bytes_mut(&mut self) -> CaliptraResult<&mut [u8]> {
match self {
MailboxReq::EcdsaVerify(req) => Ok(req.as_bytes_mut()),
MailboxReq::LmsVerify(req) => Ok(req.as_bytes_mut()),
MailboxReq::GetLdevCert(req) => Ok(req.as_bytes_mut()),
MailboxReq::StashMeasurement(req) => Ok(req.as_bytes_mut()),
MailboxReq::InvokeDpeCommand(req) => req.as_bytes_partial_mut(),
Expand All @@ -284,6 +288,7 @@ impl MailboxReq {
pub fn cmd_code(&self) -> CommandId {
match self {
MailboxReq::EcdsaVerify(_) => CommandId::ECDSA384_VERIFY,
MailboxReq::LmsVerify(_) => CommandId::LMS_VERIFY,
MailboxReq::GetLdevCert(_) => CommandId::GET_LDEV_CERT,
MailboxReq::StashMeasurement(_) => CommandId::STASH_MEASUREMENT,
MailboxReq::InvokeDpeCommand(_) => CommandId::INVOKE_DPE,
Expand Down Expand Up @@ -512,6 +517,26 @@ impl Request for EcdsaVerifyReq {
}
// No command-specific output args

// LMS_SIGNATURE_VERIFY
#[repr(C)]
#[derive(Debug, AsBytes, FromBytes, PartialEq, Eq)]
pub struct LmsVerifyReq {
pub hdr: MailboxReqHeader,
pub pub_key_tree_type: u32,
pub pub_key_ots_type: u32,
pub pub_key_id: [u8; 16],
pub pub_key_digest: [u8; 24],
pub signature_q: u32,
pub signature_ots: [u8; 1252],
pub signature_tree_type: u32,
pub signature_tree_path: [u8; 360],
}
impl Request for LmsVerifyReq {
const ID: CommandId = CommandId::LMS_VERIFY;
type Resp = MailboxRespHeader;
}
// No command-specific output args

// STASH_MEASUREMENT
#[repr(C)]
#[derive(Debug, AsBytes, FromBytes, PartialEq, Eq)]
Expand Down
5 changes: 5 additions & 0 deletions error/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,11 @@ impl CaliptraError {
CaliptraError::new_const(0x000E0040);
pub const RUNTIME_DPE_RESPONSE_SERIALIZATION_FAILED: CaliptraError =
CaliptraError::new_const(0x000E0041);
pub const RUNTIME_LMS_VERIFY_FAILED: CaliptraError = CaliptraError::new_const(0x000E0042);
pub const RUNTIME_LMS_VERIFY_INVALID_LMS_ALGORITHM: CaliptraError =
CaliptraError::new_const(0x000E0043);
pub const RUNTIME_LMS_VERIFY_INVALID_LMOTS_ALGORITHM: CaliptraError =
CaliptraError::new_const(0x000E0044);

/// FMC Errors
pub const FMC_GLOBAL_NMI: CaliptraError = CaliptraError::new_const(0x000F0001);
Expand Down
1 change: 1 addition & 0 deletions runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ caliptra-drivers = { workspace = true, features = ["runtime"] }
caliptra-error = { workspace = true, default-features = false }
caliptra-image-types = { workspace = true, default-features = false }
caliptra-kat.workspace = true
caliptra-lms-types.workspace = true
caliptra-registers.workspace = true
caliptra-x509 = { workspace = true, default-features = false }
dpe.workspace = true
Expand Down
7 changes: 7 additions & 0 deletions runtime/doc/test-coverage.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,13 @@ Test Scenario| Test Name | Runtime Error Code
Tests some common ECDSA problems | **ecdsa_cmd_run_wycheproof** | N/A
Streams a test message to a hashing accelerator and calls the ecdsa_verify mailbox command to verify the test signature | **test_ecdsa_verify_cmd** | N/A
Checks that the ecdsa_verify mailbox command fails if provided an invalid checksum | **test_ecdsa_verify_bad_chksum** | RUNTIME_INVALID_CHECKSUM
Streams 2 different test messages to the SHA accelerator and calls the lms_signature_verify mailbox command to verify several test signatures for each message | **test_lms_verify_cmd** | N/A
Checks that the lms_signature_verify mailbox command correctly returns an error for an invalid LMS signature | **test_lms_verify_failure** | RUNTIME_LMS_VERIFY_FAILED
Checks that the correct error is returned when an unsupported LMS algorithm type is provided in the signature to the lms_signature_verify mailbox command | **test_lms_verify_invalid_sig_lms_type** | RUNTIME_LMS_VERIFY_INVALID_LMS_ALGORITHM
Checks that the correct error is returned when an unsupported LMS algorithm type is provided in the public key to the lms_signature_verify mailbox command | **test_lms_verify_invalid_key_lms_type** | RUNTIME_LMS_VERIFY_INVALID_LMS_ALGORITHM
Checks that the correct error is returned when an unsupported LMS OTS algorithm type is provided to the lms_signature_verify mailbox command | **test_lms_verify_invalid_lmots_type** | RUNTIME_LMS_VERIFY_INVALID_LMOTS_ALGORITHM



<br><br>
# **Populate IDev Tests**
Expand Down
3 changes: 2 additions & 1 deletion runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ pub use info::{FwInfoCmd, IDevIdInfoCmd};
pub use invoke_dpe::InvokeDpeCmd;
pub use pcr::IncrementPcrResetCounterCmd;
pub use stash_measurement::StashMeasurementCmd;
pub use verify::EcdsaVerifyCmd;
pub use verify::{EcdsaVerifyCmd, LmsVerifyCmd};
pub mod packet;
use caliptra_common::mailbox_api::{CommandId, MailboxResp};
use packet::Packet;
Expand Down Expand Up @@ -172,6 +172,7 @@ fn handle_command(drivers: &mut Drivers) -> CaliptraResult<MboxStatusE> {
CommandId::GET_LDEV_CERT => GetLdevCertCmd::execute(drivers),
CommandId::INVOKE_DPE => InvokeDpeCmd::execute(drivers, cmd_bytes),
CommandId::ECDSA384_VERIFY => EcdsaVerifyCmd::execute(drivers, cmd_bytes),
CommandId::LMS_VERIFY => LmsVerifyCmd::execute(drivers, cmd_bytes),
CommandId::EXTEND_PCR => ExtendPcrCmd::execute(drivers, cmd_bytes),
CommandId::STASH_MEASUREMENT => StashMeasurementCmd::execute(drivers, cmd_bytes),
CommandId::DISABLE_ATTESTATION => DisableAttestationCmd::execute(drivers),
Expand Down
78 changes: 74 additions & 4 deletions runtime/src/verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,16 @@ Abstract:

use crate::Drivers;
use caliptra_cfi_derive_git::cfi_impl_fn;
use caliptra_common::mailbox_api::{EcdsaVerifyReq, MailboxResp};
use caliptra_common::mailbox_api::{EcdsaVerifyReq, LmsVerifyReq, MailboxResp};
use caliptra_drivers::{
Array4x12, CaliptraError, CaliptraResult, Ecc384PubKey, Ecc384Result, Ecc384Scalar,
Ecc384Signature,
Ecc384Signature, LmsResult,
};

use zerocopy::FromBytes;
use caliptra_lms_types::{
LmotsAlgorithmType, LmotsSignature, LmsAlgorithmType, LmsPublicKey, LmsSignature,
};
use zerocopy::AsBytes;
use zerocopy::{BigEndian, FromBytes, LittleEndian, U32};

pub struct EcdsaVerifyCmd;
impl EcdsaVerifyCmd {
Expand Down Expand Up @@ -55,3 +58,70 @@ impl EcdsaVerifyCmd {
Ok(MailboxResp::default())
}
}

pub struct LmsVerifyCmd;
impl LmsVerifyCmd {
#[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)]
pub(crate) fn execute(drivers: &mut Drivers, cmd_args: &[u8]) -> CaliptraResult<MailboxResp> {
// Constants from fixed LMS param set
const LMS_N: usize = 6;
const LMS_P: usize = 51;
const LMS_H: usize = 15;
const LMS_ALGORITHM_TYPE: LmsAlgorithmType = LmsAlgorithmType::new(12);
const LMOTS_ALGORITHM_TYPE: LmotsAlgorithmType = LmotsAlgorithmType::new(7);

if let Some(cmd) = LmsVerifyReq::read_from(cmd_args) {
// Get the digest from the SHA accelerator
let msg_digest_be = drivers.sha_acc.regs().digest().truncate::<12>().read();
// Flip the endianness since LMS treats this as raw message bytes
let mut msg_digest = [0u8; 48];
for (i, src_word) in msg_digest_be.iter().enumerate() {
msg_digest[i * 4..][..4].copy_from_slice(&src_word.to_be_bytes());
}

let lms_pub_key: LmsPublicKey<LMS_N> = LmsPublicKey {
id: cmd.pub_key_id,
digest: <[U32<LittleEndian>; LMS_N]>::read_from(&cmd.pub_key_digest[..])
.ok_or(CaliptraError::RUNTIME_INSUFFICIENT_MEMORY)?,
tree_type: LmsAlgorithmType::new(cmd.pub_key_tree_type),
otstype: LmotsAlgorithmType::new(cmd.pub_key_ots_type),
};

let lms_sig: LmsSignature<LMS_N, LMS_P, LMS_H> = LmsSignature {
q: <U32<BigEndian>>::from(cmd.signature_q),
ots: <LmotsSignature<LMS_N, LMS_P>>::read_from(&cmd.signature_ots[..])
.ok_or(CaliptraError::RUNTIME_INSUFFICIENT_MEMORY)?,
tree_type: LmsAlgorithmType::new(cmd.signature_tree_type),
tree_path: <[[U32<LittleEndian>; LMS_N]; LMS_H]>::read_from(
&cmd.signature_tree_path[..],
)
.ok_or(CaliptraError::RUNTIME_INSUFFICIENT_MEMORY)?,
};

// Check that fixed params are correct
if lms_pub_key.tree_type != LMS_ALGORITHM_TYPE {
return Err(CaliptraError::RUNTIME_LMS_VERIFY_INVALID_LMS_ALGORITHM);
}
if lms_pub_key.otstype != LMOTS_ALGORITHM_TYPE {
return Err(CaliptraError::RUNTIME_LMS_VERIFY_INVALID_LMOTS_ALGORITHM);
}
if lms_sig.tree_type != LMS_ALGORITHM_TYPE {
return Err(CaliptraError::RUNTIME_LMS_VERIFY_INVALID_LMS_ALGORITHM);
}

let success = drivers.lms.verify_lms_signature(
&mut drivers.sha256,
&msg_digest,
&lms_pub_key,
&lms_sig,
)?;
if success != LmsResult::Success {
return Err(CaliptraError::RUNTIME_LMS_VERIFY_FAILED);
}
} else {
return Err(CaliptraError::RUNTIME_INSUFFICIENT_MEMORY);
};

Ok(MailboxResp::default())
}
}
1 change: 1 addition & 0 deletions runtime/tests/runtime_integration_tests/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ mod test_ecdsa;
mod test_fips;
mod test_info;
mod test_invoke_dpe;
mod test_lms;
mod test_mailbox;
mod test_panic_missing;
mod test_pauser_privilege_levels;
Expand Down
Loading

0 comments on commit cc31e5f

Please sign in to comment.