use core::fmt;
use std::sync::Arc;
use serde::{Deserialize, Serialize};
use crate::jose::{Jwk, JwsAlgorithm};
mod error;
#[cfg(feature = "in-memory")]
mod in_memory;
#[cfg(any(feature = "in-memory", feature = "software"))]
mod local;
mod signer;
#[cfg(feature = "software")]
mod software;
#[cfg(feature = "test-vectors")]
#[cfg_attr(docsrs, doc(cfg(feature = "test-vectors")))]
pub mod testsuite;
pub use crate::jose::KeyType;
pub use error::KeyStoreError;
#[cfg(feature = "in-memory")]
#[cfg_attr(docsrs, doc(cfg(feature = "in-memory")))]
pub use in_memory::InMemoryKeyStore;
pub use signer::KeySigner;
#[cfg(feature = "software")]
#[cfg_attr(docsrs, doc(cfg(feature = "software")))]
pub use software::{SoftwareKeyStore, SoftwareKeyStoreOptions};
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
#[serde(transparent)]
pub struct KeyId(String);
impl KeyId {
pub fn new(id: impl Into<String>) -> Self {
Self(id.into())
}
pub fn as_str(&self) -> &str {
&self.0
}
}
impl From<&str> for KeyId {
fn from(id: &str) -> Self {
Self::new(id)
}
}
impl From<String> for KeyId {
fn from(id: String) -> Self {
Self(id)
}
}
impl From<KeyId> for String {
fn from(id: KeyId) -> Self {
id.0
}
}
impl AsRef<str> for KeyId {
fn as_ref(&self) -> &str {
&self.0
}
}
impl fmt::Debug for KeyId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(&self.0, f)
}
}
impl fmt::Display for KeyId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.0)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct KeySpec {
pub key_type: KeyType,
pub alg: JwsAlgorithm,
pub label: Option<String>,
}
impl KeySpec {
pub fn new(key_type: KeyType, alg: JwsAlgorithm) -> Self {
Self {
key_type,
alg,
label: None,
}
}
#[must_use]
pub fn with_label(mut self, label: impl Into<String>) -> Self {
self.label = Some(label.into());
self
}
pub fn validate(&self) -> Result<(), KeyStoreError> {
if algorithm_fits(self.key_type, self.alg) {
Ok(())
} else {
Err(KeyStoreError::InvalidSpec {
key_type: self.key_type,
alg: self.alg,
})
}
}
}
fn algorithm_fits(key_type: KeyType, alg: JwsAlgorithm) -> bool {
match key_type {
KeyType::Ed25519 => alg == JwsAlgorithm::EdDSA,
KeyType::P256 => alg == JwsAlgorithm::ES256,
KeyType::Secp256k1 => alg == JwsAlgorithm::ES256K,
KeyType::Rsa2048 | KeyType::Rsa4096 => {
matches!(alg, JwsAlgorithm::RS256 | JwsAlgorithm::PS256)
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct KeyStoreCapabilities {
pub can_generate: bool,
pub can_delete: bool,
pub remote: bool,
pub algorithms: Vec<JwsAlgorithm>,
}
impl KeyStoreCapabilities {
pub fn new(algorithms: impl IntoIterator<Item = JwsAlgorithm>) -> Self {
let mut deduplicated: Vec<JwsAlgorithm> = Vec::new();
for alg in algorithms {
if !deduplicated.contains(&alg) {
deduplicated.push(alg);
}
}
Self {
can_generate: false,
can_delete: false,
remote: false,
algorithms: deduplicated,
}
}
#[must_use]
pub fn with_generate(mut self) -> Self {
self.can_generate = true;
self
}
#[must_use]
pub fn with_delete(mut self) -> Self {
self.can_delete = true;
self
}
#[must_use]
pub fn remote(mut self) -> Self {
self.remote = true;
self
}
pub fn supports(&self, alg: JwsAlgorithm) -> bool {
self.algorithms.contains(&alg)
}
}
#[async_trait::async_trait]
pub trait KeyStore: Send + Sync {
fn capabilities(&self) -> KeyStoreCapabilities;
async fn public_jwk(&self, key: &KeyId) -> Result<Jwk, KeyStoreError>;
async fn sign(
&self,
key: &KeyId,
alg: JwsAlgorithm,
data: &[u8],
) -> Result<Vec<u8>, KeyStoreError>;
async fn exists(&self, key: &KeyId) -> Result<bool, KeyStoreError>;
async fn generate(&self, spec: KeySpec) -> Result<KeyId, KeyStoreError> {
let _ = spec;
Err(KeyStoreError::Unsupported("generate"))
}
async fn delete(&self, key: &KeyId) -> Result<(), KeyStoreError> {
let _ = key;
Err(KeyStoreError::Unsupported("delete"))
}
}
macro_rules! forward_key_store {
($($ty:ty),* $(,)?) => {
$(
#[async_trait::async_trait]
impl<T: KeyStore + ?Sized> KeyStore for $ty {
fn capabilities(&self) -> KeyStoreCapabilities {
(**self).capabilities()
}
async fn public_jwk(&self, key: &KeyId) -> Result<Jwk, KeyStoreError> {
(**self).public_jwk(key).await
}
async fn sign(
&self,
key: &KeyId,
alg: JwsAlgorithm,
data: &[u8],
) -> Result<Vec<u8>, KeyStoreError> {
(**self).sign(key, alg, data).await
}
async fn exists(&self, key: &KeyId) -> Result<bool, KeyStoreError> {
(**self).exists(key).await
}
async fn generate(&self, spec: KeySpec) -> Result<KeyId, KeyStoreError> {
(**self).generate(spec).await
}
async fn delete(&self, key: &KeyId) -> Result<(), KeyStoreError> {
(**self).delete(key).await
}
}
)*
};
}
forward_key_store!(&T, Box<T>, Arc<T>);