use async_trait::async_trait;
use basil_proto::{AeadAlgorithm, CiphertextEnvelope, KeyMaterial, KeyType};
use zeroize::Zeroizing;
#[cfg(feature = "aws-kms")]
pub mod aws_kms;
#[cfg(feature = "gcp-kms")]
pub mod gcp_kms;
#[cfg(feature = "keystore-backend")]
pub mod keystore;
pub mod spiffe;
pub mod vault;
mod kms_common;
mod pki;
mod svid;
mod transit;
#[derive(Debug, Clone)]
pub struct NewKey {
pub key_id: String,
pub public_key: Vec<u8>,
}
#[derive(Debug, Clone)]
pub struct KvValue {
pub value: Vec<u8>,
pub version: u32,
}
#[derive(Debug)]
pub struct KvSecret {
pub value: Zeroizing<Vec<u8>>,
pub version: u32,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NativeAlgorithm {
MlDsa44,
MlDsa65,
MlDsa87,
}
#[derive(Debug, Clone)]
pub struct PublicKey {
pub public_key: Vec<u8>,
pub key_type: KeyType,
pub version: u32,
}
#[derive(Debug, Clone)]
pub struct KeyMetadata {
pub key_type: Option<KeyType>,
pub latest_version: u32,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum SignOptions {
#[default]
Default,
Rs256Pkcs1v15Sha256,
Es256,
Es384,
Es512,
}
#[derive(Debug, Clone)]
pub struct X509Svid {
pub cert_chain_der: Vec<Vec<u8>>,
pub leaf_private_key_der: Zeroizing<Vec<u8>>,
pub bundle_der: Vec<Vec<u8>>,
}
#[derive(Debug, Clone, Default)]
pub struct X509CertRequest {
pub common_name: String,
pub dns_sans: Vec<String>,
pub ip_sans: Vec<String>,
pub ttl_seconds: u64,
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct X509Bundle {
pub bundle_der: Vec<Vec<u8>>,
pub crl_der: Vec<u8>,
}
#[derive(Debug, thiserror::Error)]
pub enum BackendError {
#[error("unsupported key type: {0}")]
UnsupportedKeyType(KeyType),
#[error("key not found: {0}")]
KeyNotFound(String),
#[error("operation not supported by this backend: {0}")]
Unsupported(&'static str),
#[error("decrypt failed")]
DecryptFailed,
#[error("unsupported AEAD algorithm: {0}")]
UnsupportedAlgorithm(AeadAlgorithm),
#[error("backend transport error: {0}")]
Transport(String),
#[error("backend error: {0}")]
Backend(String),
#[error("malformed backend response: {0}")]
Protocol(String),
}
#[async_trait]
pub trait Backend: Send + Sync {
fn kind(&self) -> &'static str;
async fn new_key(&self, key_type: KeyType) -> Result<NewKey, BackendError>;
async fn create_named_key(
&self,
key_id: &str,
key_type: KeyType,
) -> Result<NewKey, BackendError> {
let _ = (key_id, key_type);
Err(BackendError::Unsupported("create_named_key"))
}
async fn create_named_aead(
&self,
key_id: &str,
aead: AeadAlgorithm,
) -> Result<(), BackendError> {
let _ = (key_id, aead);
Err(BackendError::Unsupported("create_named_aead"))
}
async fn public_key(&self, key_id: &str) -> Result<Vec<u8>, BackendError>;
async fn public_key_with_meta(&self, key_id: &str) -> Result<PublicKey, BackendError> {
let _ = key_id;
Err(BackendError::Unsupported("get_public_key"))
}
async fn key_metadata(&self, key_id: &str) -> Result<KeyMetadata, BackendError> {
let _ = key_id;
Err(BackendError::Unsupported("list"))
}
async fn public_keys(
&self,
key_id: &str,
) -> Result<std::collections::BTreeMap<u32, Vec<u8>>, BackendError> {
let version = match self.key_metadata(key_id).await {
Ok(meta) => meta.latest_version,
Err(BackendError::Unsupported(_)) => 1,
Err(e) => return Err(e),
};
let public = self.public_key(key_id).await?;
Ok(std::collections::BTreeMap::from([(version, public)]))
}
async fn import(
&self,
key_id: &str,
key_type: KeyType,
material: &KeyMaterial,
) -> Result<NewKey, BackendError> {
let _ = (key_id, key_type, material);
Err(BackendError::Unsupported("import"))
}
async fn sign(&self, key_id: &str, message: &[u8]) -> Result<Vec<u8>, BackendError>;
async fn sign_with_options(
&self,
key_id: &str,
message: &[u8],
options: SignOptions,
) -> Result<Vec<u8>, BackendError> {
match options {
SignOptions::Default => self.sign(key_id, message).await,
SignOptions::Rs256Pkcs1v15Sha256 => {
let _ = (key_id, message);
Err(BackendError::Unsupported("sign rs256_pkcs1v15_sha256"))
}
SignOptions::Es256 => {
let _ = (key_id, message);
Err(BackendError::Unsupported("sign es256"))
}
SignOptions::Es384 => {
let _ = (key_id, message);
Err(BackendError::Unsupported("sign es384"))
}
SignOptions::Es512 => {
let _ = (key_id, message);
Err(BackendError::Unsupported("sign es512"))
}
}
}
async fn verify(
&self,
key_id: &str,
message: &[u8],
signature: &[u8],
) -> Result<bool, BackendError>;
async fn verify_with_options(
&self,
key_id: &str,
message: &[u8],
signature: &[u8],
options: SignOptions,
) -> Result<bool, BackendError> {
match options {
SignOptions::Default => self.verify(key_id, message, signature).await,
SignOptions::Rs256Pkcs1v15Sha256 => {
let _ = (key_id, message, signature);
Err(BackendError::Unsupported("verify rs256_pkcs1v15_sha256"))
}
SignOptions::Es256 => {
let _ = (key_id, message, signature);
Err(BackendError::Unsupported("verify es256"))
}
SignOptions::Es384 => {
let _ = (key_id, message, signature);
Err(BackendError::Unsupported("verify es384"))
}
SignOptions::Es512 => {
let _ = (key_id, message, signature);
Err(BackendError::Unsupported("verify es512"))
}
}
}
fn supports_native_algorithm(&self, algorithm: NativeAlgorithm) -> bool {
let _ = algorithm;
false
}
async fn create_named_pqc_key(
&self,
key_id: &str,
algorithm: NativeAlgorithm,
) -> Result<NewKey, BackendError> {
let _ = (key_id, algorithm);
Err(BackendError::Unsupported("create_named_pqc_key"))
}
async fn sign_pqc(
&self,
key_id: &str,
message: &[u8],
algorithm: NativeAlgorithm,
) -> Result<Vec<u8>, BackendError> {
let _ = (key_id, message, algorithm);
Err(BackendError::Unsupported("sign_pqc"))
}
async fn verify_pqc(
&self,
key_id: &str,
message: &[u8],
signature: &[u8],
algorithm: NativeAlgorithm,
) -> Result<bool, BackendError> {
let _ = (key_id, message, signature, algorithm);
Err(BackendError::Unsupported("verify_pqc"))
}
async fn encrypt(
&self,
key_id: &str,
algorithm: AeadAlgorithm,
plaintext: &[u8],
aad: Option<&[u8]>,
) -> Result<CiphertextEnvelope, BackendError> {
let _ = (key_id, algorithm, plaintext, aad);
Err(BackendError::Unsupported("encrypt"))
}
async fn decrypt(
&self,
key_id: &str,
envelope: &CiphertextEnvelope,
aad: Option<&[u8]>,
) -> Result<Vec<u8>, BackendError> {
let _ = (key_id, envelope, aad);
Err(BackendError::Unsupported("decrypt"))
}
async fn rotate(&self, key_id: &str) -> Result<u32, BackendError> {
let _ = key_id;
Err(BackendError::Unsupported("rotate"))
}
async fn kv_get(&self, key_id: &str, version: Option<u32>) -> Result<KvValue, BackendError> {
let _ = (key_id, version);
Err(BackendError::Unsupported("get"))
}
async fn kv_get_secret(
&self,
key_id: &str,
version: Option<u32>,
) -> Result<KvSecret, BackendError> {
let _ = (key_id, version);
Err(BackendError::Unsupported("kv_get_secret"))
}
async fn kv_put(&self, key_id: &str, value: &[u8]) -> Result<u32, BackendError> {
let _ = (key_id, value);
Err(BackendError::Unsupported("rotate"))
}
async fn configure_versions(
&self,
key_id: &str,
min_decryption_version: Option<u32>,
min_available_version: Option<u32>,
) -> Result<(), BackendError> {
let _ = (key_id, min_decryption_version, min_available_version);
Err(BackendError::Unsupported("configure_versions"))
}
async fn issue_x509_svid(
&self,
key_id: &str,
spiffe_id: &str,
ttl_seconds: u64,
) -> Result<X509Svid, BackendError> {
let _ = (key_id, spiffe_id, ttl_seconds);
Err(BackendError::Unsupported("issue_x509_svid"))
}
async fn issue_x509_cert(
&self,
key_id: &str,
request: &X509CertRequest,
) -> Result<X509Svid, BackendError> {
let _ = (key_id, request);
Err(BackendError::Unsupported("issue_x509_cert"))
}
async fn x509_bundle(&self, key_id: &str) -> Result<X509Bundle, BackendError> {
let _ = key_id;
Err(BackendError::Unsupported("x509_bundle"))
}
}