Skip to main content

rite_sdk/
backend.rs

1//! Backend trait hierarchy for cryptographic hardware abstraction.
2//!
3//! ## Design philosophy
4//!
5//! Backends are **orthogonal to roles and participants**. They represent the
6//! execution mechanism (how an action is implemented), not the human assignment
7//! (who performs the action).
8//!
9//! The four layers of abstraction:
10//! - **Step**: Unit of execution in the workflow
11//! - **Role**: WHO performs the step (human/participant)
12//! - **Action**: WHAT semantic operation happens
13//! - **Backend**: HOW the action is implemented (software/hardware)
14//!
15//! ## Trait composition
16//!
17//! Backends implement only the traits they're capable of. There are no universal
18//! requirements: traits are composable based on backend capabilities.
19//!
20//! Example trait support matrix:
21//! - Software: `KeyStore + Sign + KeyTransport`
22//! - `YubiKey` PIV: `KeyStore + Sign + Piv + Yubikey`
23//! - PKCS#11 HSM: `KeyStore + Sign + KeyTransport + Pkcs11`
24//! - Mock: All traits (for testing)
25
26use std::collections::BTreeMap;
27
28use crate::types::{
29    Attestation, CertRef, KeyId, KeyMetadata, KeySecurityAttributes, KeySpec, PcrValue,
30    PivDeviceInfo, PivSlot, PivSlotInfo, Pkcs11Mechanism, Pkcs11TokenInfo, SignAlgorithm, TpmInfo,
31    WrapAlgorithm, WrappedKey, YubikeySlotMetadata,
32};
33
34/// Implement the `as_*_mut` upcasting helpers on a backend struct.
35///
36/// Each `Backend` implementor must return `Some(self)` for every trait it
37/// supports and `None` for those it does not. Without this macro that is four
38/// lines of boilerplate per capability. The macro expands to those lines
39/// automatically and allows attaching per-capability doc comments.
40///
41/// # Usage
42///
43/// ```ignore
44/// use rite_sdk::{Backend, KeyStoreBackend, SignBackend};
45///
46/// impl Backend for MyBackend {
47///     fn name(&self) -> &str { &self.name }
48///     fn provider(&self) -> &str { "software" }
49///     fn fingerprint(&self) -> String { "...".to_string() }
50///
51///     backend_capabilities!(
52///         /// Supports RSA-2048 through RSA-8192 key generation and storage.
53///         as_keystore_mut: KeyStoreBackend,
54///         as_sign_mut: SignBackend,
55///     );
56/// }
57/// ```
58///
59/// Capabilities not listed here are not overridden, so they inherit the trait's
60/// default doc ("Not supported by this backend.") and return `None`.
61///
62/// The trait names passed to the macro must be in scope at the call site.
63///
64/// Note: `#[macro_export]` places this macro at the crate root
65/// (`rite_sdk::backend_capabilities!`), not in the `backend` module.
66/// This is standard Rust macro scoping.
67#[macro_export]
68macro_rules! backend_capabilities {
69    ($($(#[$attr:meta])* $method:ident : $trait:ident),* $(,)?) => {
70        $(
71            $(#[$attr])*
72            fn $method(&mut self) -> Option<&mut dyn $trait> {
73                Some(self)
74            }
75        )*
76    };
77}
78
79/// Core trait that all backends must implement.
80///
81/// Provides identity and fingerprinting for audit trails.
82///
83/// # Capability downcasting
84///
85/// Rust does not allow downcasting from `dyn Backend` to `dyn KeyStoreBackend`
86/// (or any other subtrait) without explicit support. The `as_*_mut` methods
87/// implement this pattern manually: a backend returns `Some(self)` for each
88/// capability it supports, and `None` for those it does not.
89///
90/// Use the [`backend_capabilities!`] macro to generate these methods without
91/// boilerplate.
92pub trait Backend: Send + Sync {
93    /// Backend name (unique identifier within a ceremony).
94    fn name(&self) -> &str;
95
96    /// Backend provider name (e.g., "software", "yubikey", "pkcs11").
97    fn provider(&self) -> &str;
98
99    /// Fingerprint for audit evidence.
100    ///
101    /// Format examples:
102    /// - Software: `"software-backend=mybackend"`
103    /// - `YubiKey`: `"yubikey-serial=12345678+firmware=5.7.1"`
104    /// - PKCS#11: `"pkcs11-module=/usr/lib/softhsm2.so+slot=0"`
105    fn fingerprint(&self) -> String;
106
107    /// Not supported by this backend, always returns `None`.
108    fn as_keystore_mut(&mut self) -> Option<&mut dyn KeyStoreBackend> {
109        None
110    }
111
112    /// Not supported by this backend, always returns `None`.
113    fn as_sign_mut(&mut self) -> Option<&mut dyn SignBackend> {
114        None
115    }
116
117    /// Not supported by this backend, always returns `None`.
118    fn as_attest_mut(&mut self) -> Option<&mut dyn AttestationBackend> {
119        None
120    }
121
122    /// Not supported by this backend, always returns `None`.
123    fn as_piv_mut(&mut self) -> Option<&mut dyn PivBackend> {
124        None
125    }
126
127    /// Not supported by this backend, always returns `None`.
128    fn as_yubikey_mut(&mut self) -> Option<&mut dyn YubikeyBackend> {
129        None
130    }
131
132    /// Not supported by this backend, always returns `None`.
133    fn as_transport_mut(&mut self) -> Option<&mut dyn KeyTransportBackend> {
134        None
135    }
136
137    /// Not supported by this backend, always returns `None`.
138    fn as_certstore_mut(&mut self) -> Option<&mut dyn CertStoreBackend> {
139        None
140    }
141
142    /// Not supported by this backend, always returns `None`.
143    fn as_random_mut(&mut self) -> Option<&mut dyn RandomBackend> {
144        None
145    }
146
147    /// Not supported by this backend, always returns `None`.
148    fn as_pkcs11_mut(&mut self) -> Option<&mut dyn Pkcs11Backend> {
149        None
150    }
151
152    /// Not supported by this backend, always returns `None`.
153    fn as_pkcs11_admin_mut(&mut self) -> Option<&mut dyn Pkcs11AdminBackend> {
154        None
155    }
156
157    /// Not supported by this backend, always returns `None`.
158    fn as_tpm_mut(&mut self) -> Option<&mut dyn TpmBackend> {
159        None
160    }
161}
162
163/// Key generation and storage operations.
164///
165/// Backends implementing this trait can generate, import, and manage
166/// cryptographic keys.
167pub trait KeyStoreBackend: Backend {
168    /// Generate a new key.
169    ///
170    /// The backend owns the key and returns metadata including an opaque
171    /// `KeyId` reference. For hardware backends, the private key never leaves
172    /// the device.
173    fn generate_key(&mut self, spec: KeySpec) -> Result<KeyMetadata, BackendError>;
174
175    /// Import an existing private key.
176    ///
177    /// Only supported by backends that allow key import (software, some HSMs).
178    /// Hardware security modules may reject key import for security reasons.
179    ///
180    /// `key_bytes` must be in PKCS#8 DER format.
181    fn import_private_key(
182        &mut self,
183        spec: KeySpec,
184        key_bytes: &[u8],
185    ) -> Result<KeyMetadata, BackendError>;
186
187    /// Export the public key for `key_id` in `SubjectPublicKeyInfo` (SPKI) DER format.
188    fn export_public_key(&self, key_id: &KeyId) -> Result<Vec<u8>, BackendError>;
189
190    /// List all keys managed by this backend.
191    fn list_keys(&self) -> Result<Vec<KeyMetadata>, BackendError>;
192
193    /// Delete a key permanently.
194    fn delete_key(&mut self, key_id: &KeyId) -> Result<(), BackendError>;
195}
196
197/// Signing and verification operations.
198pub trait SignBackend: Backend {
199    /// Sign `message` with `key_id` using `algorithm`.
200    ///
201    /// Returns raw signature bytes (format depends on algorithm).
202    fn sign(
203        &mut self,
204        key_id: &KeyId,
205        message: &[u8],
206        algorithm: SignAlgorithm,
207    ) -> Result<Vec<u8>, BackendError>;
208
209    /// Verify `signature` over `message` with `key_id` and `algorithm`.
210    fn verify(
211        &self,
212        key_id: &KeyId,
213        message: &[u8],
214        signature: &[u8],
215        algorithm: SignAlgorithm,
216    ) -> Result<bool, BackendError>;
217}
218
219/// Hardware attestation operations.
220///
221/// Backends that support attestation can cryptographically prove that a key
222/// was generated on a specific hardware device.
223pub trait AttestationBackend: Backend {
224    /// Return a cryptographic proof that `key_id` was generated on this
225    /// backend's hardware and has specific properties.
226    fn attest_key(&self, key_id: &KeyId) -> Result<Attestation, BackendError>;
227}
228
229/// Certificate storage operations.
230///
231/// Backends implementing this trait can store, read, and delete X.509
232/// certificates by reference. This is a unified interface for certificate
233/// management across PIV (slot-based), PKCS#11 (label/ID-based), and
234/// software backends.
235pub trait CertStoreBackend: Backend {
236    /// Store a DER-encoded X.509 certificate.
237    fn store_cert(&mut self, cert_ref: &CertRef, cert_der: &[u8]) -> Result<(), BackendError>;
238
239    /// Read a DER-encoded X.509 certificate.
240    fn read_cert(&self, cert_ref: &CertRef) -> Result<Vec<u8>, BackendError>;
241
242    /// Delete a certificate.
243    fn delete_cert(&mut self, cert_ref: &CertRef) -> Result<(), BackendError>;
244}
245
246/// Hardware or software random number generation.
247///
248/// Backends implementing this trait can generate random bytes. For HSM
249/// backends, this uses the device's internal RNG (e.g., PKCS#11 `C_GenerateRandom`).
250pub trait RandomBackend: Backend {
251    /// Generate `len` random bytes.
252    fn generate_random(&mut self, len: usize) -> Result<Vec<u8>, BackendError>;
253}
254
255/// Key transport (wrapping) operations.
256pub trait KeyTransportBackend: Backend {
257    /// Wrap `key_id` using `wrapping_key_id` with `algorithm`.
258    fn wrap(
259        &mut self,
260        key_id: &KeyId,
261        wrapping_key_id: &KeyId,
262        algorithm: WrapAlgorithm,
263    ) -> Result<WrappedKey, BackendError>;
264
265    /// Unwrap `wrapped` using `unwrapping_key_id`, importing the result with `label`.
266    fn unwrap(
267        &mut self,
268        wrapped: &WrappedKey,
269        unwrapping_key_id: &KeyId,
270        label: &str,
271    ) -> Result<KeyMetadata, BackendError>;
272
273    /// Wrap `key_id` to an external recipient's raw public key.
274    ///
275    /// Default implementation returns `UnsupportedOperation`.
276    fn wrap_to_public(
277        &mut self,
278        key_id: &KeyId,
279        recipient_pub_key: &[u8],
280        algorithm: WrapAlgorithm,
281    ) -> Result<WrappedKey, BackendError> {
282        let _ = (key_id, recipient_pub_key, algorithm);
283        Err(BackendError::UnsupportedOperation(
284            "wrap_to_public not supported".to_string(),
285        ))
286    }
287}
288
289/// PKCS#11 token operations.
290///
291/// Provides access to PKCS#11-specific functionality: token info, key
292/// security attributes, mechanism enumeration, and session login/logout.
293pub trait Pkcs11Backend: Backend {
294    /// Get token information (label, manufacturer, serial, flags).
295    fn token_info(&self) -> Result<Pkcs11TokenInfo, BackendError>;
296
297    /// Read security attributes for `key_id` (`CKA_ALWAYS_SENSITIVE`, etc.).
298    fn key_security_attributes(
299        &self,
300        key_id: &KeyId,
301    ) -> Result<KeySecurityAttributes, BackendError>;
302
303    /// List mechanisms supported by this token.
304    fn supported_mechanisms(&self) -> Result<Vec<Pkcs11Mechanism>, BackendError>;
305
306    /// Log in to the token with a PIN.
307    fn login(&mut self, pin: &[u8]) -> Result<(), BackendError>;
308
309    /// Log out of the token.
310    fn logout(&mut self) -> Result<(), BackendError>;
311}
312
313/// PKCS#11 Security Officer (SO) role operations.
314///
315/// These operations require SO authentication and are typically performed
316/// only during initial token setup.
317pub trait Pkcs11AdminBackend: Backend {
318    /// Initialize a token (`C_InitToken`).
319    fn init_token(&mut self, so_pin: &[u8], label: &str) -> Result<(), BackendError>;
320
321    /// Initialize the user PIN (`C_InitPIN`). Requires SO session.
322    fn init_user_pin(&mut self, so_pin: &[u8], user_pin: &[u8]) -> Result<(), BackendError>;
323}
324
325/// TPM 2.0 operations.
326///
327/// Provides TPM-specific functionality: device info, PCR operations, and
328/// quote generation.
329pub trait TpmBackend: Backend {
330    /// Get TPM information (version, manufacturer, firmware).
331    fn tpm_info(&mut self) -> Result<TpmInfo, BackendError>;
332
333    /// Read PCR (Platform Configuration Register) values for the given PCR indices.
334    ///
335    /// Returns a `BTreeMap` keyed by PCR index for deterministic ordering in transcripts.
336    fn read_pcrs(&mut self, pcrs: &[u8]) -> Result<BTreeMap<u8, PcrValue>, BackendError>;
337
338    /// Extend a PCR register with new data.
339    fn extend_pcr(&mut self, pcr: u8, data: &[u8]) -> Result<(), BackendError>;
340
341    /// Generate a TPM quote (signed attestation over PCR values).
342    fn generate_quote(&mut self, pcrs: &[u8], nonce: &[u8]) -> Result<Attestation, BackendError>;
343}
344
345/// Personal Identity Verification (PIV) smart card operations.
346///
347/// Models the PIV card application interface defined by FIPS 201-3 and
348/// NIST SP 800-73-5. Methods in this trait correspond to PIV card commands
349/// and data model operations; their semantics are defined by the standard
350/// and should not diverge.
351///
352/// Backends implementing `PivBackend` should also implement the generic traits
353/// (`KeyStoreBackend`, `SignBackend`) for interoperability with non-PIV-aware actions.
354///
355/// # Standard references
356/// - FIPS 201-3: Personal Identity Verification of Federal Employees and Contractors
357/// - NIST SP 800-73-5 Part 1: PIV Card Application Data Model
358/// - NIST SP 800-73-5 Part 2: PIV Card Application Card Command Interface
359/// - NIST SP 800-78-5: Cryptographic Algorithms and Key Sizes for PIV
360pub trait PivBackend: Backend {
361    /// List populated PIV slots with metadata.
362    ///
363    /// Enumerates key references defined in SP 800-73-5 Part 1, Table 4b.
364    fn list_slots(&self) -> Result<Vec<PivSlotInfo>, BackendError>;
365
366    /// Verify the PIV Card Application PIN.
367    ///
368    /// Required before private key operations on slots with PIN access rules.
369    /// The PIN is typically 6–8 digits (ASCII-encoded).
370    /// [SP 800-73-5 Part 2, §3.3: VERIFY command]
371    fn verify_pin(&mut self, pin: &[u8]) -> Result<(), BackendError>;
372
373    /// Change the PIV Card Application PIN.
374    ///
375    /// [SP 800-73-5 Part 2, §3.4: CHANGE REFERENCE DATA command]
376    fn change_pin(&mut self, current: &[u8], new: &[u8]) -> Result<(), BackendError>;
377
378    /// Get remaining PIN retry count before lockout.
379    fn pin_retries(&mut self) -> Result<u32, BackendError>;
380
381    /// Reset a blocked PIN using the PUK (PIN Unblocking Key).
382    ///
383    /// [SP 800-73-5 Part 2, §3.4: RESET RETRY COUNTER command]
384    fn unblock_pin(&mut self, puk: &[u8], new_pin: &[u8]) -> Result<(), BackendError>;
385
386    /// Return device identity (serial, firmware version, form factor).
387    ///
388    /// Not all fields are available on every PIV card. Serial number
389    /// retrieval is vendor-specific (not standardized by NIST SP 800-73).
390    fn device_info(&self) -> Result<PivDeviceInfo, BackendError>;
391}
392
393/// `YubiKey`-specific extensions to the PIV interface.
394///
395/// Operations in this trait are Yubico vendor extensions that go beyond
396/// the NIST SP 800-73 standard. They are specific to `YubiKey` hardware
397/// and will not work with generic PIV smart cards.
398///
399/// # Vendor references
400/// - Yubico PIV documentation: <https://developers.yubico.com/PIV/>
401/// - `YubiKey` attestation: key reference F9 (Yubico-proprietary)
402/// - Touch/PIN policy configuration: Yubico-proprietary extensions
403///   to the GENERATE ASYMMETRIC KEY PAIR command
404pub trait YubikeyBackend: PivBackend {
405    /// Generate an attestation certificate for a key in `slot`.
406    ///
407    /// Proves the key was generated on-device (not imported).
408    /// Uses `YubiKey`'s attestation key (slot F9) to sign a certificate
409    /// over the public key in the target slot.
410    /// This is a Yubico extension, not available on generic PIV cards.
411    fn attest_slot(&self, slot: PivSlot) -> Result<Vec<u8>, BackendError>;
412
413    /// Authenticate with the management key (3DES or AES).
414    ///
415    /// Required before administrative operations: key generation,
416    /// certificate import, PIN/PUK retry configuration.
417    fn authenticate_management(&mut self, mgm_key: &[u8]) -> Result<(), BackendError>;
418
419    /// Change the management key.
420    fn change_management_key(&mut self, current: &[u8], new: &[u8]) -> Result<(), BackendError>;
421
422    /// Get `YubiKey`-specific metadata for `slot`.
423    ///
424    /// Returns touch policy, PIN policy, and key origin: information
425    /// not available through standard PIV commands.
426    fn slot_metadata(&self, slot: PivSlot) -> Result<YubikeySlotMetadata, BackendError>;
427
428    /// Block PUK permanently (prevents PIN unblock forever).
429    ///
430    /// High-security operation: once blocked, a forgotten PIN requires
431    /// full device reset (destroying all keys). Irreversible.
432    fn block_puk(&mut self) -> Result<(), BackendError>;
433}
434
435/// Backend-specific errors.
436#[derive(Debug, thiserror::Error)]
437#[non_exhaustive]
438pub enum BackendError {
439    /// Authentication required (not logged in).
440    #[error("Authentication required")]
441    AuthRequired,
442
443    /// PIN required to access backend.
444    #[error("PIN required")]
445    PinRequired,
446
447    /// PIN verification failed (wrong PIN). Contains remaining retries if known.
448    #[error("PIN verification failed ({0} retries remaining)")]
449    PinFailed(u32),
450
451    /// PIN is blocked (too many failed attempts).
452    #[error("PIN blocked")]
453    PinBlocked,
454
455    /// User PIN not initialized (PKCS#11: `C_InitPIN` not yet called).
456    #[error("User PIN not initialized")]
457    UserPinNotInitialized,
458
459    /// Management key authentication required.
460    #[error("Management key authentication required")]
461    ManagementKeyRequired,
462
463    /// Key not found in backend storage.
464    #[error("Key not found: {0}")]
465    KeyNotFound(String),
466
467    /// Object not found (PKCS#11: `find_objects` returned empty).
468    #[error("Object not found: {0}")]
469    ObjectNotFound(String),
470
471    /// PIV slot is empty (no key or certificate).
472    #[error("Slot empty: {0}")]
473    SlotEmpty(String),
474
475    /// Backend storage capacity exceeded.
476    #[error("Capacity exceeded")]
477    CapacityExceeded,
478
479    /// Operation not permitted (key usage flags don't allow this).
480    #[error("Operation not permitted: {0}")]
481    OperationNotPermitted(String),
482
483    /// Attribute is read-only (e.g., tried to set `CKA_ALWAYS_SENSITIVE`).
484    #[error("Attribute is read-only: {0}")]
485    AttributeReadOnly(String),
486
487    /// Algorithm not supported by this backend.
488    #[error("Unsupported algorithm: {0}")]
489    UnsupportedAlgorithm(String),
490
491    /// Operation not supported by this backend.
492    #[error("Unsupported operation: {0}")]
493    UnsupportedOperation(String),
494
495    /// Token not present in slot.
496    #[error("Token not present")]
497    TokenNotPresent,
498
499    /// Hardware failure (device disconnected, I/O error, etc.).
500    #[error("Hardware failure: {0}")]
501    HardwareFailure(String),
502
503    /// Invalid key format or data.
504    #[error("Invalid key format: {0}")]
505    InvalidKeyFormat(String),
506
507    /// Invalid data (malformed input, unexpected encoding, etc.).
508    #[error("Invalid data: {0}")]
509    InvalidData(String),
510
511    /// Backend not found in registry.
512    #[error("Backend not found: {0}")]
513    NotFound(String),
514
515    /// Configuration error (missing or invalid settings).
516    #[error("Configuration error: {0}")]
517    Configuration(String),
518
519    /// Generic backend error.
520    #[error("Backend error: {0}")]
521    Other(String),
522}