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}