From b2fe8ba0d286dc795448a729014ffb311e21c974 Mon Sep 17 00:00:00 2001 From: Zach Halvorsen Date: Tue, 8 Aug 2023 07:26:04 -0700 Subject: [PATCH] Add ACVP feature. There is some functionality that is helpful when running ACVP tests, but that functionality should not be allowed during regular operation. For example, we shouldn't need to create an ECDH secret key from raw bytes. They should always be from random. But, ACVP tests require testing specific scenarios so it provides keys that need to be tested. --- libraries/crypto/Cargo.toml | 1 + libraries/crypto/src/ecdh.rs | 12 ++++++++++++ libraries/crypto/src/ecdsa.rs | 4 ++-- libraries/opensk/Cargo.toml | 1 + libraries/opensk/src/api/crypto/ecdh.rs | 6 +++++- libraries/opensk/src/api/crypto/ecdsa.rs | 2 +- libraries/opensk/src/api/crypto/software_crypto.rs | 7 ++++++- libraries/opensk/src/ctap/hid/receive.rs | 1 + 8 files changed, 29 insertions(+), 5 deletions(-) diff --git a/libraries/crypto/Cargo.toml b/libraries/crypto/Cargo.toml index 989a8dee..cf66bd46 100644 --- a/libraries/crypto/Cargo.toml +++ b/libraries/crypto/Cargo.toml @@ -25,3 +25,4 @@ zeroize = { version = "1.5.7", features = ["derive"] } [features] std = ["hex", "ring", "untrusted", "serde", "serde_json", "regex", "rand_core/getrandom"] with_ctap1 = [] +acvp = [] diff --git a/libraries/crypto/src/ecdh.rs b/libraries/crypto/src/ecdh.rs index ed5bec03..28772fbe 100644 --- a/libraries/crypto/src/ecdh.rs +++ b/libraries/crypto/src/ecdh.rs @@ -78,6 +78,18 @@ impl SecKey { p.getx().to_int().to_bin(&mut x); x } + + /// Creates a private key from the exponent's bytes, or None if checks fail. + #[cfg(any(feature = "std", feature = "acvp"))] + pub fn from_bytes(bytes: &[u8; 32]) -> Option { + let a = NonZeroExponentP256::from_int_checked(Int256::from_bin(bytes)); + // The branching here is fine because all this reveals is whether the key was invalid. + if bool::from(a.is_none()) { + return None; + } + let a = a.unwrap(); + Some(SecKey { a }) + } } impl PubKey { diff --git a/libraries/crypto/src/ecdsa.rs b/libraries/crypto/src/ecdsa.rs index f4e66211..cdf7c54e 100644 --- a/libraries/crypto/src/ecdsa.rs +++ b/libraries/crypto/src/ecdsa.rs @@ -19,7 +19,7 @@ use super::ec::point::PointP256; use super::Hash256; use alloc::vec; use alloc::vec::Vec; -#[cfg(feature = "std")] +#[cfg(any(feature = "std", feature = "acvp"))] use arrayref::array_mut_ref; use arrayref::{array_ref, mut_array_refs}; use core::marker::PhantomData; @@ -220,7 +220,7 @@ impl Signature { Some(Signature { r, s }) } - #[cfg(feature = "std")] + #[cfg(any(feature = "std", feature = "acvp"))] pub fn to_bytes(&self, bytes: &mut [u8; Signature::BYTES_LENGTH]) { self.r .to_int() diff --git a/libraries/opensk/Cargo.toml b/libraries/opensk/Cargo.toml index 707af94e..8909f28a 100644 --- a/libraries/opensk/Cargo.toml +++ b/libraries/opensk/Cargo.toml @@ -45,6 +45,7 @@ vendor_hid = [] fuzz = ["arbitrary", "std"] ed25519 = ["ed25519-compact"] rust_crypto = ["p256", "sha2", "hmac", "hkdf", "aes", "cbc"] +acvp = ["crypto/acvp"] [dev-dependencies] enum-iterator = "0.6.0" diff --git a/libraries/opensk/src/api/crypto/ecdh.rs b/libraries/opensk/src/api/crypto/ecdh.rs index 1c4b74fb..b6010ae7 100644 --- a/libraries/opensk/src/api/crypto/ecdh.rs +++ b/libraries/opensk/src/api/crypto/ecdh.rs @@ -23,7 +23,7 @@ pub trait Ecdh { } /// ECDH ephemeral key. -pub trait SecretKey { +pub trait SecretKey: Sized { type PublicKey: PublicKey; type SharedSecret: SharedSecret; @@ -35,6 +35,10 @@ pub trait SecretKey { /// Computes the shared secret when using Elliptic-curve Diffie–Hellman. fn diffie_hellman(&self, public_key: &Self::PublicKey) -> Self::SharedSecret; + + /// Creates a signing key from its representation in bytes. + #[cfg(feature = "acvp")] + fn from_slice(bytes: &[u8; EC_FIELD_SIZE]) -> Option; } /// ECDH public key. diff --git a/libraries/opensk/src/api/crypto/ecdsa.rs b/libraries/opensk/src/api/crypto/ecdsa.rs index 1dad533b..e6e38c28 100644 --- a/libraries/opensk/src/api/crypto/ecdsa.rs +++ b/libraries/opensk/src/api/crypto/ecdsa.rs @@ -73,7 +73,7 @@ pub trait Signature: Sized { fn from_slice(bytes: &[u8; EC_SIGNATURE_SIZE]) -> Option; /// Writes the signature bytes into the passed in parameter. - #[cfg(feature = "std")] + #[cfg(any(feature = "std", feature = "acvp"))] fn to_slice(&self, bytes: &mut [u8; EC_SIGNATURE_SIZE]); /// Encodes the signatures as ASN1 DER. diff --git a/libraries/opensk/src/api/crypto/software_crypto.rs b/libraries/opensk/src/api/crypto/software_crypto.rs index f0cd2216..2f9ff356 100644 --- a/libraries/opensk/src/api/crypto/software_crypto.rs +++ b/libraries/opensk/src/api/crypto/software_crypto.rs @@ -69,6 +69,11 @@ impl ecdh::SecretKey for SoftwareEcdhSecretKey { let shared_secret = self.sec_key.exchange_x(&public_key.pub_key); SoftwareEcdhSharedSecret { shared_secret } } + + #[cfg(feature = "acvp")] + fn from_slice(bytes: &[u8; EC_FIELD_SIZE]) -> Option { + crypto::ecdh::SecKey::from_bytes(bytes).map(|k| Self { sec_key: k }) + } } pub struct SoftwareEcdhPublicKey { @@ -169,7 +174,7 @@ impl ecdsa::Signature for SoftwareEcdsaSignature { crypto::ecdsa::Signature::from_bytes(bytes).map(|s| SoftwareEcdsaSignature { signature: s }) } - #[cfg(feature = "std")] + #[cfg(any(feature = "std", feature = "acvp"))] fn to_slice(&self, bytes: &mut [u8; EC_SIGNATURE_SIZE]) { self.signature.to_bytes(bytes); } diff --git a/libraries/opensk/src/ctap/hid/receive.rs b/libraries/opensk/src/ctap/hid/receive.rs index c3689c31..3d07c066 100644 --- a/libraries/opensk/src/ctap/hid/receive.rs +++ b/libraries/opensk/src/ctap/hid/receive.rs @@ -83,6 +83,7 @@ impl MessageAssembler { let (cid, processed_packet) = CtapHid::::process_single_packet(packet); if let Some(locked_cid) = locked_cid { if locked_cid != cid { + #[cfg(not(feature = "acvp"))] return Err((cid, CtapHidError::ChannelBusy)); } }