Skip to main content

identity_kit/keys/
signer.rs

1//! `KeySigner`: a key of a `KeyStore` as a `jose::Signer`.
2
3use core::fmt;
4
5use super::{KeyId, KeyStore, KeyStoreError};
6use crate::jose::{Jwk, JwsAlgorithm, SignError, Signer};
7
8/// A [`Signer`] over one key of a [`KeyStore`].
9///
10/// The signer looks the key up once, when it is created, and keeps the public [`Jwk`] so that a
11/// caller building a DID document or a JWS header never round-trips to the store for it
12/// ([`KeySigner::public_jwk`]). Signing goes to the store on every call.
13///
14/// [`Signer::kid`] is the key id, unless [`KeySigner::with_kid`] set another value, such as the
15/// DID URL of the verification method the key backs.
16///
17/// # Examples
18///
19/// ```
20/// # #[cfg(feature = "in-memory")]
21/// # tokio::runtime::Builder::new_current_thread().build()?.block_on(async {
22/// use identity_kit::jose::{CompactJws, DefaultVerifier, JwsAlgorithm, JwsHeader, KeyType, encode_compact};
23/// use identity_kit::keys::{InMemoryKeyStore, KeySigner, KeySpec, KeyStore};
24///
25/// let store = InMemoryKeyStore::new();
26/// let key = store.generate(KeySpec::new(KeyType::Ed25519, JwsAlgorithm::EdDSA)).await?;
27/// let signer = KeySigner::new(&store, key, JwsAlgorithm::EdDSA).await?;
28///
29/// let header = JwsHeader::new(JwsAlgorithm::EdDSA).with_kid(signer.key_id().as_str());
30/// let token = encode_compact(&header, b"{}", &signer).await?;
31/// let jws = CompactJws::decode(&token)?;
32/// jws.verify(&DefaultVerifier, signer.public_jwk())?;
33/// # Ok::<(), Box<dyn std::error::Error>>(())
34/// # })?;
35/// # Ok::<(), Box<dyn std::error::Error>>(())
36/// ```
37pub struct KeySigner<'a> {
38    store: &'a dyn KeyStore,
39    key: KeyId,
40    alg: JwsAlgorithm,
41    public: Jwk,
42    kid: Option<String>,
43}
44
45impl<'a> KeySigner<'a> {
46    /// A signer over `key` of `store`, signing with `alg`.
47    ///
48    /// # Errors
49    ///
50    /// [`KeyStoreError::UnsupportedAlgorithm`] when the store does not advertise `alg`,
51    /// [`KeyStoreError::NotFound`] when the key does not exist,
52    /// [`KeyStoreError::AlgorithmMismatch`] when the key's public JWK names another algorithm,
53    /// and whatever else the store reports.
54    pub async fn new(
55        store: &'a dyn KeyStore,
56        key: KeyId,
57        alg: JwsAlgorithm,
58    ) -> Result<Self, KeyStoreError> {
59        if !store.capabilities().supports(alg) {
60            return Err(KeyStoreError::UnsupportedAlgorithm(alg));
61        }
62        let public = store.public_jwk(&key).await?;
63        if let Some(key_alg) = public.alg() {
64            let key_alg: JwsAlgorithm = key_alg.parse().map_err(|_| KeyStoreError::InvalidKey {
65                key: key.clone(),
66                reason: format!("unknown algorithm `{key_alg}` in its public JWK"),
67            })?;
68            if key_alg != alg {
69                return Err(KeyStoreError::AlgorithmMismatch {
70                    key,
71                    key_alg,
72                    requested: alg,
73                });
74            }
75        }
76        Ok(Self {
77            store,
78            key,
79            alg,
80            public,
81            kid: None,
82        })
83    }
84
85    /// This signer with [`Signer::kid`] set to `kid` instead of the key id.
86    #[must_use]
87    pub fn with_kid(mut self, kid: impl Into<String>) -> Self {
88        self.kid = Some(kid.into());
89        self
90    }
91
92    /// The store the key lives in.
93    pub fn store(&self) -> &'a dyn KeyStore {
94        self.store
95    }
96
97    /// The key this signer signs with.
98    pub fn key_id(&self) -> &KeyId {
99        &self.key
100    }
101
102    /// The public key, as the store reported it when the signer was created.
103    pub fn public_jwk(&self) -> &Jwk {
104        &self.public
105    }
106}
107
108impl fmt::Debug for KeySigner<'_> {
109    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
110        f.debug_struct("KeySigner")
111            .field("key", &self.key)
112            .field("alg", &self.alg)
113            .field("public", &self.public)
114            .field("kid", &self.kid)
115            .finish_non_exhaustive()
116    }
117}
118
119#[async_trait::async_trait]
120impl Signer for KeySigner<'_> {
121    fn alg(&self) -> JwsAlgorithm {
122        self.alg
123    }
124
125    fn kid(&self) -> Option<&str> {
126        Some(self.kid.as_deref().unwrap_or(self.key.as_str()))
127    }
128
129    async fn sign(&self, signing_input: &[u8]) -> Result<Vec<u8>, SignError> {
130        self.store
131            .sign(&self.key, self.alg, signing_input)
132            .await
133            .map_err(SignError::new)
134    }
135}