use std::collections::BTreeMap;
use crate::types::{
Attestation, CertRef, KeyId, KeyMetadata, KeySecurityAttributes, KeySpec, PcrValue,
PivDeviceInfo, PivSlot, PivSlotInfo, Pkcs11Mechanism, Pkcs11TokenInfo, SignAlgorithm, TpmInfo,
WrapAlgorithm, WrappedKey, YubikeySlotMetadata,
};
#[macro_export]
macro_rules! backend_capabilities {
($($(#[$attr:meta])* $method:ident : $trait:ident),* $(,)?) => {
$(
$(#[$attr])*
fn $method(&mut self) -> Option<&mut dyn $trait> {
Some(self)
}
)*
};
}
pub trait Backend: Send + Sync {
fn name(&self) -> &str;
fn provider(&self) -> &str;
fn fingerprint(&self) -> String;
fn as_keystore_mut(&mut self) -> Option<&mut dyn KeyStoreBackend> {
None
}
fn as_sign_mut(&mut self) -> Option<&mut dyn SignBackend> {
None
}
fn as_attest_mut(&mut self) -> Option<&mut dyn AttestationBackend> {
None
}
fn as_piv_mut(&mut self) -> Option<&mut dyn PivBackend> {
None
}
fn as_yubikey_mut(&mut self) -> Option<&mut dyn YubikeyBackend> {
None
}
fn as_transport_mut(&mut self) -> Option<&mut dyn KeyTransportBackend> {
None
}
fn as_certstore_mut(&mut self) -> Option<&mut dyn CertStoreBackend> {
None
}
fn as_random_mut(&mut self) -> Option<&mut dyn RandomBackend> {
None
}
fn as_pkcs11_mut(&mut self) -> Option<&mut dyn Pkcs11Backend> {
None
}
fn as_pkcs11_admin_mut(&mut self) -> Option<&mut dyn Pkcs11AdminBackend> {
None
}
fn as_tpm_mut(&mut self) -> Option<&mut dyn TpmBackend> {
None
}
}
pub trait KeyStoreBackend: Backend {
fn generate_key(&mut self, spec: KeySpec) -> Result<KeyMetadata, BackendError>;
fn import_private_key(
&mut self,
spec: KeySpec,
key_bytes: &[u8],
) -> Result<KeyMetadata, BackendError>;
fn export_public_key(&self, key_id: &KeyId) -> Result<Vec<u8>, BackendError>;
fn list_keys(&self) -> Result<Vec<KeyMetadata>, BackendError>;
fn delete_key(&mut self, key_id: &KeyId) -> Result<(), BackendError>;
}
pub trait SignBackend: Backend {
fn sign(
&mut self,
key_id: &KeyId,
message: &[u8],
algorithm: SignAlgorithm,
) -> Result<Vec<u8>, BackendError>;
fn verify(
&self,
key_id: &KeyId,
message: &[u8],
signature: &[u8],
algorithm: SignAlgorithm,
) -> Result<bool, BackendError>;
}
pub trait AttestationBackend: Backend {
fn attest_key(&self, key_id: &KeyId) -> Result<Attestation, BackendError>;
}
pub trait CertStoreBackend: Backend {
fn store_cert(&mut self, cert_ref: &CertRef, cert_der: &[u8]) -> Result<(), BackendError>;
fn read_cert(&self, cert_ref: &CertRef) -> Result<Vec<u8>, BackendError>;
fn delete_cert(&mut self, cert_ref: &CertRef) -> Result<(), BackendError>;
}
pub trait RandomBackend: Backend {
fn generate_random(&mut self, len: usize) -> Result<Vec<u8>, BackendError>;
}
pub trait KeyTransportBackend: Backend {
fn wrap(
&mut self,
key_id: &KeyId,
wrapping_key_id: &KeyId,
algorithm: WrapAlgorithm,
) -> Result<WrappedKey, BackendError>;
fn unwrap(
&mut self,
wrapped: &WrappedKey,
unwrapping_key_id: &KeyId,
label: &str,
) -> Result<KeyMetadata, BackendError>;
fn wrap_to_public(
&mut self,
key_id: &KeyId,
recipient_pub_key: &[u8],
algorithm: WrapAlgorithm,
) -> Result<WrappedKey, BackendError> {
let _ = (key_id, recipient_pub_key, algorithm);
Err(BackendError::UnsupportedOperation(
"wrap_to_public not supported".to_string(),
))
}
}
pub trait Pkcs11Backend: Backend {
fn token_info(&self) -> Result<Pkcs11TokenInfo, BackendError>;
fn key_security_attributes(
&self,
key_id: &KeyId,
) -> Result<KeySecurityAttributes, BackendError>;
fn supported_mechanisms(&self) -> Result<Vec<Pkcs11Mechanism>, BackendError>;
fn login(&mut self, pin: &[u8]) -> Result<(), BackendError>;
fn logout(&mut self) -> Result<(), BackendError>;
}
pub trait Pkcs11AdminBackend: Backend {
fn init_token(&mut self, so_pin: &[u8], label: &str) -> Result<(), BackendError>;
fn init_user_pin(&mut self, so_pin: &[u8], user_pin: &[u8]) -> Result<(), BackendError>;
}
pub trait TpmBackend: Backend {
fn tpm_info(&mut self) -> Result<TpmInfo, BackendError>;
fn read_pcrs(&mut self, pcrs: &[u8]) -> Result<BTreeMap<u8, PcrValue>, BackendError>;
fn extend_pcr(&mut self, pcr: u8, data: &[u8]) -> Result<(), BackendError>;
fn generate_quote(&mut self, pcrs: &[u8], nonce: &[u8]) -> Result<Attestation, BackendError>;
}
pub trait PivBackend: Backend {
fn list_slots(&self) -> Result<Vec<PivSlotInfo>, BackendError>;
fn verify_pin(&mut self, pin: &[u8]) -> Result<(), BackendError>;
fn change_pin(&mut self, current: &[u8], new: &[u8]) -> Result<(), BackendError>;
fn pin_retries(&mut self) -> Result<u32, BackendError>;
fn unblock_pin(&mut self, puk: &[u8], new_pin: &[u8]) -> Result<(), BackendError>;
fn device_info(&self) -> Result<PivDeviceInfo, BackendError>;
}
pub trait YubikeyBackend: PivBackend {
fn attest_slot(&self, slot: PivSlot) -> Result<Vec<u8>, BackendError>;
fn authenticate_management(&mut self, mgm_key: &[u8]) -> Result<(), BackendError>;
fn change_management_key(&mut self, current: &[u8], new: &[u8]) -> Result<(), BackendError>;
fn slot_metadata(&self, slot: PivSlot) -> Result<YubikeySlotMetadata, BackendError>;
fn block_puk(&mut self) -> Result<(), BackendError>;
}
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum BackendError {
#[error("Authentication required")]
AuthRequired,
#[error("PIN required")]
PinRequired,
#[error("PIN verification failed ({0} retries remaining)")]
PinFailed(u32),
#[error("PIN blocked")]
PinBlocked,
#[error("User PIN not initialized")]
UserPinNotInitialized,
#[error("Management key authentication required")]
ManagementKeyRequired,
#[error("Key not found: {0}")]
KeyNotFound(String),
#[error("Object not found: {0}")]
ObjectNotFound(String),
#[error("Slot empty: {0}")]
SlotEmpty(String),
#[error("Capacity exceeded")]
CapacityExceeded,
#[error("Operation not permitted: {0}")]
OperationNotPermitted(String),
#[error("Attribute is read-only: {0}")]
AttributeReadOnly(String),
#[error("Unsupported algorithm: {0}")]
UnsupportedAlgorithm(String),
#[error("Unsupported operation: {0}")]
UnsupportedOperation(String),
#[error("Token not present")]
TokenNotPresent,
#[error("Hardware failure: {0}")]
HardwareFailure(String),
#[error("Invalid key format: {0}")]
InvalidKeyFormat(String),
#[error("Invalid data: {0}")]
InvalidData(String),
#[error("Backend not found: {0}")]
NotFound(String),
#[error("Configuration error: {0}")]
Configuration(String),
#[error("Backend error: {0}")]
Other(String),
}