diff --git a/hal/blocking/src/ecdsa.rs b/hal/blocking/src/ecdsa.rs index 65ab7a7..8111cfb 100644 --- a/hal/blocking/src/ecdsa.rs +++ b/hal/blocking/src/ecdsa.rs @@ -348,7 +348,7 @@ pub trait PrivateKey: Zeroize { /// - `Ok(())`: The private key is valid /// - `Err(ErrorKind::WeakKey)`: The key is zero, equal to curve order, or otherwise weak /// - `Err(ErrorKind::InvalidKeyFormat)`: The key format is invalid - fn validate(&self) -> Result<(), ErrorKind>; + fn validate(&self, curve: &C) -> Result<(), ErrorKind>; } /// A trait representing an abstract elliptic curve with associated types for cryptographic operations. @@ -579,18 +579,21 @@ pub trait SerializableSignature: Signature + IntoBytes + FromBytes /// Trait for ECDSA key generation over a specific elliptic curve. /// /// This trait enables generation of cryptographically secure ECDSA key pairs -/// using a cryptographic random number generator. +/// using a cryptographic random number generator. Keys can be generated either +/// as standalone objects or stored directly in a key vault for enhanced security. /// /// # Security Requirements /// /// - Must use a cryptographically secure random number generator /// - Generated keys must be uniformly distributed over the valid scalar range /// - Private keys must be properly zeroized after use +/// - Key vault storage should be preferred for hardware-backed security /// /// # Example /// /// ```rust,ignore -/// use openprot_hal_blocking::ecdsa::{EcdsaKeyGen, Curve, ErrorKind}; +/// use openprot_hal_blocking::ecdsa::{EcdsaKeyGen, Curve, generate_and_store_keypair}; +/// use openprot_hal_blocking::key_vault::{KeyLifecycle, KeyStore}; /// use rand_core::{RngCore, CryptoRng}; /// /// struct MyKeyGenerator; @@ -608,6 +611,20 @@ pub trait SerializableSignature: Signature + IntoBytes + FromBytes /// unimplemented!() /// } /// } +/// +/// // Usage example with standalone function: +/// let mut key_gen = MyKeyGenerator; +/// let mut vault = MyKeyVault::new(); +/// let mut rng = MyRng::new(); +/// +/// let public_key = generate_and_store_keypair( +/// &mut key_gen, +/// &mut vault, +/// KeyId::new(42), +/// KeyUsage::SIGNING, +/// KeyMetadata::default(), +/// &mut rng +/// )?; /// ``` pub trait EcdsaKeyGen: ErrorType { /// The type representing the private key for the curve. @@ -630,6 +647,76 @@ pub trait EcdsaKeyGen: ErrorType { R: rand_core::RngCore + rand_core::CryptoRng; } +/// Generates an ECDSA key pair and stores the private key in a key vault. +/// +/// This function provides integrated key generation and secure storage, ensuring +/// that private keys are immediately stored in a secure vault rather than +/// being exposed in memory. Only the public key is returned to the caller. +/// +/// # Parameters +/// - `key_gen`: The key generator implementation +/// - `vault`: The key vault for secure private key storage +/// - `key_id`: Unique identifier for the key in the vault +/// - `usage`: Usage permissions for the stored key +/// - `metadata`: Additional metadata to store with the key +/// - `rng`: A cryptographically secure random number generator +/// +/// # Returns +/// The generated public key (private key is securely stored in vault) +/// +/// # Security Benefits +/// - Private key is never exposed to caller +/// - Immediate secure storage reduces attack surface +/// - Usage permissions are set atomically with storage +/// - Vault locking mechanisms can be applied immediately +/// +/// # Example +/// ```rust,ignore +/// use openprot_hal_blocking::ecdsa::{generate_and_store_keypair, P256}; +/// use openprot_hal_blocking::key_vault::{KeyLifecycle, KeyStore}; +/// +/// let mut key_gen = MyKeyGenerator::new(); +/// let mut vault = MyKeyVault::new(); +/// let mut rng = MyRng::new(); +/// +/// let public_key = generate_and_store_keypair::( +/// &mut key_gen, +/// &mut vault, +/// KeyId::new(42), +/// KeyUsage::SIGNING, +/// KeyMetadata::default(), +/// &mut rng +/// )?; +/// ``` +pub fn generate_and_store_keypair( + key_gen: &mut G, + vault: &mut V, + key_id: ::KeyId, + usage: ::KeyUsage, + metadata: ::KeyMetadata, + rng: &mut R, +) -> Result +where + C: Curve, + G: EcdsaKeyGen, + R: rand_core::RngCore + rand_core::CryptoRng, + V: crate::key_vault::KeyLifecycle + crate::key_vault::KeyStore, + ::KeyId: From<::KeyId>, + G::Error: From, +{ + // Generate key pair + let (private_key, public_key) = key_gen.generate_keypair(rng)?; + + // Store private key in vault with metadata + let lifecycle_key_id = ::KeyId::from(key_id); + vault + .store_key(lifecycle_key_id, private_key, metadata) + .map_err(G::Error::from)?; + vault.set_key_usage(key_id, usage).map_err(G::Error::from)?; + + Ok(public_key) +} + /// Trait for ECDSA signing using a digest algorithm. /// /// This trait provides ECDSA signature generation from message digests. diff --git a/hal/blocking/src/key_vault.rs b/hal/blocking/src/key_vault.rs new file mode 100644 index 0000000..b899fd3 --- /dev/null +++ b/hal/blocking/src/key_vault.rs @@ -0,0 +1,209 @@ +// Licensed under the Apache-2.0 license + +/// Error kind for key management operations. +/// +/// This represents a common set of key management operation errors that can occur across +/// different implementations. The enum is `#[non_exhaustive]` to allow for future +/// additions without breaking API compatibility. +/// +/// Implementations are free to define more specific or additional error types. +/// However, by providing a mapping to these common errors through the [`Error::kind`] +/// method, generic code can still react to them appropriately. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[non_exhaustive] +pub enum ErrorKind { + /// The operation is busy and cannot be completed + /// + /// This indicates that the hardware or implementation is currently + /// busy with another operation. The caller should retry later. + Busy, + + /// The specified key was not found + /// + /// Returned when attempting to access a key that does not exist + /// in the storage backend. + KeyNotFound, + + /// Access to the key was denied + /// + /// This could indicate insufficient permissions, key usage policy + /// violations, or other access control restrictions. + AccessDenied, + + /// Invalid key usage specification + /// + /// Returned when the specified key usage constraints are invalid + /// or incompatible with the key or storage backend. + InvalidUsage, + + /// Hardware fault or failure + /// + /// Indicates a hardware-level error in secure storage elements, + /// HSMs, or other hardware-backed key storage. + HardwareFault, + + /// Other implementation-specific error + /// + /// Catch-all for errors that don't fit other categories. + Other, +} + +impl core::fmt::Display for ErrorKind { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + Self::Busy => write!(f, "key storage hardware is busy"), + Self::KeyNotFound => write!(f, "specified key was not found"), + Self::AccessDenied => write!(f, "access to key was denied"), + Self::InvalidUsage => write!(f, "invalid key usage specification"), + Self::HardwareFault => write!(f, "hardware fault during key operation"), + Self::Other => write!(f, "key management operation failed"), + } + } +} +/// Common interface for key management errors. +/// +/// This trait provides a standardized way to categorize and handle errors +/// from different key management implementations. +pub trait Error: core::fmt::Debug { + /// Convert error to a generic error kind + /// + /// By using this method, errors freely defined by HAL implementations + /// can be converted to a set of generic errors upon which generic + /// code can act. + fn kind(&self) -> ErrorKind; +} + +/// Trait for associating a type with a key management error type. +/// +/// This trait is used throughout the key management module to associate operations +/// with their specific error types while maintaining type safety. +pub trait ErrorType { + /// Error type. + type Error: Error; +} + +/// Configuration and setup operations for key vaults +/// +/// This trait provides methods for configuring key vault implementations +/// with runtime parameters and checking their configuration state. +pub trait KeyVaultSetup: ErrorType { + /// Configuration type for the key vault + /// + /// This type contains all the runtime parameters needed to configure + /// the key vault implementation. + type KeyVaultConfig; + + /// Configure the key vault with runtime parameters + /// + /// This method applies the provided configuration to the key vault, + /// setting up any necessary resources, security policies, or hardware + /// initialization required for operation. + /// + /// # Parameters + /// + /// - `config`: Configuration parameters specific to this key vault implementation + /// + /// # Errors + /// + /// - `ErrorKind::InvalidUsage`: Invalid configuration parameters + /// - `ErrorKind::HardwareFault`: Hardware initialization failed + /// - `ErrorKind::AccessDenied`: Insufficient permissions for configuration + /// - `ErrorKind::Busy`: Key vault is currently busy and cannot be reconfigured + fn configure(&mut self, config: Self::KeyVaultConfig) -> Result<(), Self::Error>; + + /// Check if the key vault is properly configured + /// + /// Returns `true` if the key vault has been successfully configured + /// and is ready for key operations, `false` otherwise. + /// + /// # Note + /// + /// This method is infallible as it only checks internal state. + /// It does not perform any hardware operations that could fail. + fn is_configured(&self) -> bool; +} + +/// Core key vault operations +pub trait KeyStore: ErrorType { + /// Type representing a key identifier + type KeyId: Copy + Clone + PartialEq + Eq; + /// Type representing key usage permissions + type KeyUsage: Copy + Clone + PartialEq + Eq; + + /// Erase a specific key + fn erase_key(&mut self, id: Self::KeyId) -> Result<(), Self::Error>; + + /// Erase all keys that are not locked + fn erase_all_keys(&mut self) -> Result<(), Self::Error>; + + /// Check if a key exists and is valid + fn key_exists(&self, id: Self::KeyId) -> Result; + + /// Get the usage permissions for a key + fn get_key_usage(&self, id: Self::KeyId) -> Result; + + /// Set the usage permissions for a key + fn set_key_usage(&mut self, id: Self::KeyId, usage: Self::KeyUsage) -> Result<(), Self::Error>; +} + +/// Key locking mechanisms for security +pub trait KeyLocking: ErrorType { + /// Type representing a key identifier + type KeyId: Copy + Clone + PartialEq + Eq; + + /// Check if key has write lock + fn is_write_locked(&self, id: Self::KeyId) -> Result; + + /// Set write lock on key + fn set_write_lock(&mut self, id: Self::KeyId) -> Result<(), Self::Error>; + + /// Clear write lock on key + fn clear_write_lock(&mut self, id: Self::KeyId) -> Result<(), Self::Error>; + + /// Check if key has use lock + fn is_use_locked(&self, id: Self::KeyId) -> Result; + + /// Set use lock on key + fn set_use_lock(&mut self, id: Self::KeyId) -> Result<(), Self::Error>; + + /// Clear use lock on key + fn clear_use_lock(&mut self, id: Self::KeyId) -> Result<(), Self::Error>; +} + +/// Key lifecycle management +/// Complete key lifecycle from creation to retrieval +pub trait KeyLifecycle: ErrorType { + /// Type representing a key identifier + type KeyId: Copy + Clone + PartialEq + Eq; + + /// Type representing key data + type KeyData; + + /// Type representing key metadata + type KeyMetadata; + + /// Store a key with metadata + fn store_key( + &mut self, + id: Self::KeyId, + data: Self::KeyData, + metadata: Self::KeyMetadata, + ) -> Result<(), Self::Error>; + + /// Retrieve key data (if permitted) + fn retrieve_key(&self, id: Self::KeyId) -> Result; + + /// Get key metadata + fn get_key_metadata(&self, id: Self::KeyId) -> Result; + + /// Update key metadata + fn update_key_metadata( + &mut self, + id: Self::KeyId, + metadata: Self::KeyMetadata, + ) -> Result<(), Self::Error>; +} + +/// Blanket trait implementation for types that implement key vsault setup, core operations, and locking +pub trait KeyVault: KeyVaultSetup + KeyStore + KeyLocking {} +impl KeyVault for T where T: KeyVaultSetup + KeyStore + KeyLocking {} diff --git a/hal/blocking/src/lib.rs b/hal/blocking/src/lib.rs index a321508..02217ae 100644 --- a/hal/blocking/src/lib.rs +++ b/hal/blocking/src/lib.rs @@ -29,6 +29,9 @@ pub mod mac; /// Reset and clocking traits for OpenPRoT HAL pub mod system_control; +/// Key management traits +pub mod key_vault; + // Re-export embedded-hal 1.0 traits pub use embedded_hal::delay::DelayNs; pub use embedded_hal::digital::{InputPin, OutputPin, StatefulOutputPin}; diff --git a/hal/blocking/src/mac.rs b/hal/blocking/src/mac.rs index b3e49df..874d90c 100644 --- a/hal/blocking/src/mac.rs +++ b/hal/blocking/src/mac.rs @@ -272,3 +272,71 @@ impl MacAlgorithm for HmacSha2_512 { type MacOutput = Digest<{ Self::OUTPUT_BITS / 32 }>; type Key = SecureKey<64>; } + +/// Computes a MAC using a key retrieved from a key vault. +/// +/// This function provides integrated MAC computation with secure key storage, +/// ensuring that MAC keys are retrieved from a secure vault and used for +/// authentication operations without exposing the key material. +/// +/// # Parameters +/// - `mac_impl`: The MAC implementation to use +/// - `vault`: The key vault containing the MAC key +/// - `key_id`: Unique identifier for the key in the vault +/// - `algorithm`: The MAC algorithm to use (zero-sized type) +/// - `data`: The data to authenticate +/// +/// # Returns +/// The computed MAC output +/// +/// # Security Notes +/// - MAC key is never exposed to caller +/// - Key retrieval and MAC computation are atomic +/// - Supports vault access control and locking mechanisms +/// - Automatic key zeroization after use +/// +/// # Example +/// ```rust,ignore +/// use openprot_hal_blocking::mac::{compute_mac_with_vault, HmacSha2_256, verify_mac_constant_time}; +/// use openprot_hal_blocking::key_vault::{KeyLifecycle}; +/// +/// let mut mac_impl = MyMacImplementation::new(); +/// let vault = MyKeyVault::new(); +/// let data = b"Hello, world!"; +/// +/// // Compute MAC with vault-stored key +/// let mac_output = compute_mac_with_vault( +/// &mut mac_impl, +/// &vault, +/// KeyId::new(42), +/// HmacSha2_256, +/// data +/// )?; +/// +/// ``` +pub fn compute_mac_with_vault( + mac_impl: &mut M, + vault: &V, + key_id: ::KeyId, + algorithm: A, + data: &[u8], +) -> Result +where + A: MacAlgorithm, + M: MacInit, + V: crate::key_vault::KeyLifecycle, + E: From + From, + for<'a> as ErrorType>::Error: Into, +{ + // Retrieve key from vault + let key = vault.retrieve_key(key_id).map_err(E::from)?; + + // Initialize MAC operation + let mut mac_ctx = mac_impl.init(algorithm, &key).map_err(E::from)?; + + // Update with data + mac_ctx.update(data).map_err(Into::into)?; + + // Finalize and return MAC + mac_ctx.finalize().map_err(Into::into) +}