Skip to content

Commit

Permalink
[fix] Update ECC384 and LMS verify function signatures
Browse files Browse the repository at this point in the history
This PR changes return types on ECC384 and LMS verify to
return verify_r and candidate key values respectively. The callers
of these functions now compare the values with the expected to determine
if the signature verification succeded.
  • Loading branch information
mhatrevi committed Aug 24, 2023
1 parent b7348b3 commit e62d770
Show file tree
Hide file tree
Showing 15 changed files with 153 additions and 69 deletions.
50 changes: 39 additions & 11 deletions drivers/src/ecc384.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Abstract:

use crate::kv_access::{KvAccess, KvAccessErr};
use crate::{
array_concat3, okmutref, wait, Array4x12, CaliptraError, CaliptraResult, KeyReadArgs,
array_concat3, okmutref, wait, Array4x12, Array4xN, CaliptraError, CaliptraResult, KeyReadArgs,
KeyWriteArgs, Trng,
};
use caliptra_registers::ecc::EccReg;
Expand Down Expand Up @@ -365,7 +365,9 @@ impl Ecc384 {
/// * `digest` - digest to verify
/// * `signature` - Signature to verify
///
/// Note: Use this function only if glitch protection is not needed.
/// If glitch protection is needed, use `verify_r` instead.
///
///
/// # Result
///
Expand All @@ -376,9 +378,42 @@ impl Ecc384 {
digest: &Ecc384Scalar,
signature: &Ecc384Signature,
) -> CaliptraResult<Ecc384Result> {
// Get the verify r result
let mut verify_r = self.verify_r(pub_key, digest, signature)?;

// compare the hardware generate `r` with one in signature
let result = if verify_r == signature.r {
Ecc384Result::Success
} else {
Ecc384Result::SigVerifyFailed
};

verify_r.0.fill(0);
Ok(result)
}

/// Returns the R value of the signature with specified public key and digest.
/// Caller is expected to compare the returned R value against the provided signature's
/// R value to determine whether the signature is valid.
///
/// # Arguments
///
/// * `pub_key` - Public key
/// * `digest` - digest to verify
/// * `signature` - Signature to verify
///
/// # Result
///
/// * `Array4xN<12, 48>` - verify R value
pub fn verify_r(
&mut self,
pub_key: &Ecc384PubKey,
digest: &Ecc384Scalar,
signature: &Ecc384Signature,
) -> CaliptraResult<Array4xN<12, 48>> {
// 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 Ok(Ecc384Result::SigVerifyFailed);
return Err(CaliptraError::DRIVER_ECC384_SCALAR_RANGE_CHECK_FAILED);
}

let ecc = self.ecc.regs_mut();
Expand Down Expand Up @@ -406,16 +441,9 @@ impl Ecc384 {
// Copy the random value
let verify_r = Array4x12::read_from_reg(ecc.verify_r());

// compare the hardware generate `r` with one in signature
let result = if verify_r == signature.r {
Ecc384Result::Success
} else {
Ecc384Result::SigVerifyFailed
};

self.zeroize_internal();

Ok(result)
Ok(verify_r)
}

/// Zeroize the hardware registers.
Expand Down
27 changes: 21 additions & 6 deletions drivers/src/lms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -377,13 +377,33 @@ impl Lms {
Ok(result)
}

/// Note: Use this function only if glitch protection is not needed.
/// If glitch protection is needed, use `verify_lms_signature_cfi` instead.
pub fn verify_lms_signature<const N: usize, const P: usize, const H: usize>(
&self,
sha256_driver: &mut Sha256,
input_string: &[u8],
lms_public_key: &LmsPublicKey<N>,
lms_sig: &LmsSignature<N, P, H>,
) -> CaliptraResult<LmsResult> {
let mut candidate_key =
self.verify_lms_signature_cfi(sha256_driver, input_string, lms_public_key, lms_sig)?;
let result = if candidate_key != HashValue::from(lms_public_key.digest) {
Ok(LmsResult::SigVerifyFailed)
} else {
Ok(LmsResult::Success)
};
candidate_key.0.fill(0);
result
}

pub fn verify_lms_signature_cfi<const N: usize, const P: usize, const H: usize>(
&self,
sha256_driver: &mut Sha256,
input_string: &[u8],
lms_public_key: &LmsPublicKey<N>,
lms_sig: &LmsSignature<N, P, H>,
) -> CaliptraResult<HashValue<N>> {
if lms_sig.ots.ots_type != lms_public_key.otstype {
return Err(CaliptraError::DRIVER_LMS_SIGNATURE_LMOTS_DOESNT_MATCH_PUBKEY_LMOTS);
}
Expand Down Expand Up @@ -463,12 +483,7 @@ impl Lms {
i += 1;
digest.0.fill(0);
}
let candidate_key = &temp;
if *candidate_key != HashValue::from(lms_public_key.digest) {
return Ok(LmsResult::SigVerifyFailed);
}
digest.0.fill(0);
temp.0.fill(0);
Ok(LmsResult::Success)
Ok(temp)
}
}
33 changes: 33 additions & 0 deletions drivers/test-fw/src/bin/ecc384_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,38 @@ fn test_verify() {
assert_eq!(result.unwrap(), Ecc384Result::Success);
}

fn test_verify_r() {
let mut ecc = unsafe { Ecc384::new(EccReg::new()) };
let mut trng = unsafe {
Trng::new(
CsrngReg::new(),
EntropySrcReg::new(),
SocIfcTrngReg::new(),
&SocIfcReg::new(),
)
.unwrap()
};
let digest = Array4x12::new([0u32; 12]);
let result = ecc.sign(
&Ecc384PrivKeyIn::from(&Array4x12::from(PRIV_KEY)),
&Ecc384PubKey {
x: Ecc384Scalar::from(PUB_KEY_X),
y: Ecc384Scalar::from(PUB_KEY_Y),
},
&digest,
&mut trng,
);
assert!(result.is_ok());
let signature = result.unwrap();
let pub_key = Ecc384PubKey {
x: Ecc384Scalar::from(PUB_KEY_X),
y: Ecc384Scalar::from(PUB_KEY_Y),
};
let result = ecc.verify_r(&pub_key, &Ecc384Scalar::from(digest), &signature);
assert!(result.is_ok());
assert_eq!(result.unwrap(), signature.r);
}

fn test_verify_failure() {
let mut ecc = unsafe { Ecc384::new(EccReg::new()) };
let mut trng = unsafe {
Expand Down Expand Up @@ -481,6 +513,7 @@ test_suite! {
test_sign,
test_sign_validation_failure,
test_verify,
test_verify_r,
test_verify_failure,
test_kv_seed_from_input_msg_from_input,
test_kv_seed_from_kv_msg_from_input,
Expand Down
5 changes: 5 additions & 0 deletions drivers/test-fw/src/bin/lms_24_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,11 @@ fn test_lms_24_height_15() {
.verify_lms_signature(&mut sha256, &MESSAGE, &LMS_PUBLIC_KEY, &LMS_SIG)
.unwrap();
assert_eq!(result, LmsResult::Success);

let candidate_key = Lms::default()
.verify_lms_signature_cfi(&mut sha256, &MESSAGE, &LMS_PUBLIC_KEY, &LMS_SIG)
.unwrap();
assert_eq!(candidate_key, HashValue::from(LMS_PUBLIC_KEY.digest));
}

test_suite! {
Expand Down
5 changes: 5 additions & 0 deletions drivers/test-fw/src/bin/lms_32_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,11 @@ fn test_lms_lower_32() {
.verify_lms_signature(&mut sha256, &MESSAGE, &LMS_PUBLIC_KEY, &FINAL_LMS_SIG)
.unwrap();
assert_eq!(final_result, LmsResult::Success);

let candidate_key = Lms::default()
.verify_lms_signature_cfi(&mut sha256, &MESSAGE, &LMS_PUBLIC_KEY, &FINAL_LMS_SIG)
.unwrap();
assert_eq!(candidate_key, HashValue::from(LMS_PUBLIC_KEY.digest));
}

// from https://www.rfc-editor.org/rfc/rfc8554#page-49
Expand Down
2 changes: 2 additions & 0 deletions error/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ impl CaliptraError {
CaliptraError::new_const(0x0005000d);
pub const DRIVER_ECC384_SIGN_VALIDATION_FAILED: CaliptraError =
CaliptraError::new_const(0x0005000e);
pub const DRIVER_ECC384_SCALAR_RANGE_CHECK_FAILED: CaliptraError =
CaliptraError::new_const(0x0005000f);

pub const DRIVER_KV_ERASE_USE_LOCK_SET_FAILURE: CaliptraError =
CaliptraError::new_const(0x00060001);
Expand Down
4 changes: 2 additions & 2 deletions image/verify/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,15 +111,15 @@ pub trait ImageVerificationEnv {
digest: &ImageDigest,
pub_key: &ImageEccPubKey,
sig: &ImageEccSignature,
) -> CaliptraResult<Ecc384Result>;
) -> CaliptraResult<Array4xN<12, 48>>;

/// Perform LMS Verification
fn lms_verify(
&mut self,
digest: &ImageDigest,
pub_key: &ImageLmsPublicKey,
sig: &ImageLmsSignature,
) -> CaliptraResult<LmsResult>;
) -> CaliptraResult<HashValue<SHA192_DIGEST_WORD_SIZE>>;

/// Get Vendor Public Key Digest
fn vendor_pub_key_digest(&self) -> ImageDigest;
Expand Down
34 changes: 16 additions & 18 deletions image/verify/src/verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -404,13 +404,12 @@ impl<Env: ImageVerificationEnv> ImageVerifier<Env> {
Err(CaliptraError::IMAGE_VERIFIER_ERR_OWNER_ECC_SIGNATURE_INVALID_ARG)?;
}

let result = self
let verify_r = self
.env
.ecc384_verify(digest, pub_key, sig)
.map_err(|_| CaliptraError::IMAGE_VERIFIER_ERR_OWNER_ECC_VERIFY_FAILURE)?;

// [TODO][CFI]
if result != Ecc384Result::Success {
if verify_r != caliptra_drivers::Array4xN(sig.r) {
Err(CaliptraError::IMAGE_VERIFIER_ERR_OWNER_ECC_SIGNATURE_INVALID)?;
}

Expand All @@ -432,24 +431,23 @@ impl<Env: ImageVerificationEnv> ImageVerifier<Env> {
Err(CaliptraError::IMAGE_VERIFIER_ERR_VENDOR_ECC_SIGNATURE_INVALID_ARG)?;
}

let result = self
let verify_r = self
.env
.ecc384_verify(digest, ecc_pub_key, ecc_sig)
.map_err(|_| CaliptraError::IMAGE_VERIFIER_ERR_VENDOR_ECC_VERIFY_FAILURE)?;

// [TODO][CFI]
if result != Ecc384Result::Success {
if verify_r != caliptra_drivers::Array4xN(ecc_sig.r) {
Err(CaliptraError::IMAGE_VERIFIER_ERR_VENDOR_ECC_SIGNATURE_INVALID)?;
}

if self.env.lms_verify_enabled() {
if let Some(info) = lms_info {
let (lms_pub_key, lms_sig) = info;
let result = self
let candidate_key = self
.env
.lms_verify(digest, lms_pub_key, lms_sig)
.map_err(|_| CaliptraError::IMAGE_VERIFIER_ERR_VENDOR_LMS_VERIFY_FAILURE)?;
if result != LmsResult::Success {
if candidate_key != HashValue::from(lms_pub_key.digest) {
return Err(CaliptraError::IMAGE_VERIFIER_ERR_VENDOR_LMS_SIGNATURE_INVALID);
}
}
Expand All @@ -465,12 +463,12 @@ impl<Env: ImageVerificationEnv> ImageVerifier<Env> {
lms_pub_key: &ImageLmsPublicKey,
lms_sig: &ImageLmsSignature,
) -> CaliptraResult<()> {
let result = self
let candidate_key = self
.env
.lms_verify(digest, lms_pub_key, lms_sig)
.map_err(|_| CaliptraError::IMAGE_VERIFIER_ERR_OWNER_LMS_VERIFY_FAILURE)?;

if result != LmsResult::Success {
if candidate_key != HashValue::from(lms_pub_key.digest) {
return Err(CaliptraError::IMAGE_VERIFIER_ERR_OWNER_LMS_SIGNATURE_INVALID);
}

Expand Down Expand Up @@ -1728,25 +1726,25 @@ mod tests {
&mut self,
_digest: &ImageDigest,
_pub_key: &ImageEccPubKey,
_sig: &ImageEccSignature,
) -> CaliptraResult<Ecc384Result> {
sig: &ImageEccSignature,
) -> CaliptraResult<Array4xN<12, 48>> {
if self.verify_result {
Ok(Ecc384Result::Success)
Ok(Array4x12::from(sig.r))
} else {
Ok(Ecc384Result::SigVerifyFailed)
Ok(Array4x12::from(&[0xFF; 48]))
}
}

fn lms_verify(
&mut self,
_digest: &ImageDigest,
_pub_key: &ImageLmsPublicKey,
pub_key: &ImageLmsPublicKey,
_sig: &ImageLmsSignature,
) -> CaliptraResult<LmsResult> {
) -> CaliptraResult<HashValue<SHA192_DIGEST_WORD_SIZE>> {
if self.verify_lms_result {
Ok(LmsResult::Success)
Ok(HashValue::from(pub_key.digest))
} else {
Ok(LmsResult::SigVerifyFailed)
Ok(HashValue::from(&[0xDEADBEEF; 6]))
}
}

Expand Down
2 changes: 1 addition & 1 deletion rom/dev/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ The following sections define the various cryptographic primitives used by Calip
| | `hmac384_mac(kv_slot,data,mac_kv_slot)` | Calculate the mac using a caller provided key and data. The resultant mac is stored in key vault slot <br>**Input**: <br>***kv_slot*** - key vault slot to use the key from<br>***data*** - data<br>***mac_kv_slot*** - key vault slot to store the mac to |
| Elliptic Curve Cryptography | `ecc384_keygen(seed_kv_slot, priv_kv_slot) -> pub_key` | Generate ECC384 Key Pair.<br>**Input**:<br>***seed_key_slot*** - key vault slot to use as seed for key generation<br>***priv_kv_slot*** - key vault slot to store the private key to<br>**Output**:<br>***pub-key*** - public key associated with the private key |
| | `ecc384_sign(priv_kv_slot, data) -> sig` | ECC384 signing operation<br>**Input**:<br>***priv_kv_slot*** - key vault slot to use a private key from<br>***data*** - data to sign<br>**Output**:<br>***sig*** - signature |
| | `ecc384_verify(pub_key, data, sig) -> Ecc384Result` | ECC384 verify operation<br>**Input**:<br>***pub-key*** -public key<br>data - data to verify<br>sig - signature<br>**Output**:<br>***Ecc384Result*** - Ecc384Result::Success if signature verification succeeded else an error |
| | `ecc384_verify(pub_key, data, sig) -> CaliptraResult<Array4xN<12, 48>>` | ECC384 verify operation<br>**Input**:<br>***pub-key*** -public key<br>data - data to verify<br>sig - signature<br>**Output**:<br>***Ecc384Result*** - verify.r value on success, else an error |
| Secure Hash Algorithm | `sha384_digest(data) -> digest` | Calculate the digest of the data<br>**Input**:<br>***data*** - data to verify<br>**Output**:<br>***digest*** - digest of the data |
| Key Vault | `kv_clear(kv_slot)` | Key Vault slot to clear<br>**Input**:<br>***kv_slot*** - key vault slot to clear |
| Data Vault | `dv48_store(data, dv_slot)` | Store the 48-byte data in the specified data vault slot<br>**Input**:<br>***data*** - data to store<br>***dv_slot*** - data vault slot |
Expand Down
6 changes: 3 additions & 3 deletions rom/dev/src/flow/cold_reset/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,16 +243,16 @@ impl Crypto {
///
/// # Returns
///
/// `Ecc384Result` - Ecc384Result::Success if the signature verification passed else an error code.
/// * `Array4xN<12, 48>` - verify R value
#[cfg_attr(not(feature = "no-cfi"), cfi_impl_fn)]
pub fn ecdsa384_verify(
env: &mut RomEnv,
pub_key: &Ecc384PubKey,
data: &[u8],
sig: &Ecc384Signature,
) -> CaliptraResult<Ecc384Result> {
) -> CaliptraResult<Array4xN<12, 48>> {
let mut digest = Self::sha384_digest(env, data);
let digest = okmutref(&mut digest)?;
env.ecc384.verify(pub_key, digest, sig)
env.ecc384.verify_r(pub_key, digest, sig)
}
}
14 changes: 6 additions & 8 deletions rom/dev/src/flow/cold_reset/fmc_alias.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,7 @@ use caliptra_common::dice;
use caliptra_common::keyids::{KEY_ID_FMC_PRIV_KEY, KEY_ID_ROM_FMC_CDI};
use caliptra_common::pcr::PCR_ID_FMC_CURRENT;
use caliptra_common::RomBootStatus::*;
use caliptra_drivers::{
okmutref, report_boot_status, Array4x12, CaliptraResult, Ecc384Result, KeyId, Lifecycle,
};
use caliptra_drivers::{okmutref, report_boot_status, Array4x12, CaliptraResult, KeyId, Lifecycle};
use caliptra_error::CaliptraError;
use caliptra_x509::{FmcAliasCertTbs, FmcAliasCertTbsParams};

Expand Down Expand Up @@ -191,13 +189,13 @@ impl FmcAliasLayer {
env.key_vault.erase_key(auth_priv_key)?;

// Verify the signature of the `To Be Signed` portion
let result = Crypto::ecdsa384_verify(env, auth_pub_key, tbs.tbs(), sig)?;
if cfi_launder(result) == Ecc384Result::Success {
cfi_assert!(result == Ecc384Result::Success);
} else {
cfi_assert!(result != Ecc384Result::Success);
let mut verify_r = Crypto::ecdsa384_verify(env, auth_pub_key, tbs.tbs(), sig)?;
if cfi_launder(&verify_r) != &sig.r {
return Err(CaliptraError::FMC_ALIAS_CERT_VERIFY);
} else {
cfi_assert!(cfi_launder(&verify_r) == &sig.r);
}
verify_r.0.fill(0);

let _pub_x: [u8; 48] = (&pub_key.x).into();
let _pub_y: [u8; 48] = (&pub_key.y).into();
Expand Down
10 changes: 5 additions & 5 deletions rom/dev/src/flow/cold_reset/idev_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,13 +245,13 @@ impl InitDevIdLayer {
let sig = okmutref(&mut sig)?;

// Verify the signature of the `To Be Signed` portion
let result = Crypto::ecdsa384_verify(env, &key_pair.pub_key, tbs.tbs(), sig)?;
if cfi_launder(result) == Ecc384Result::Success {
cfi_assert!(result == Ecc384Result::Success);
} else {
cfi_assert!(result != Ecc384Result::Success);
let mut verify_r = Crypto::ecdsa384_verify(env, &key_pair.pub_key, tbs.tbs(), sig)?;
if cfi_launder(&verify_r) != &sig.r {
return Err(CaliptraError::ROM_IDEVID_CSR_VERIFICATION_FAILURE);
} else {
cfi_assert!(cfi_launder(&verify_r) == &sig.r);
}
verify_r.0.fill(0);

let _pub_x: [u8; 48] = key_pair.pub_key.x.into();
let _pub_y: [u8; 48] = key_pair.pub_key.y.into();
Expand Down
Loading

0 comments on commit e62d770

Please sign in to comment.