Skip to main content

identity_kit/identity/
key_store.rs

1//! `KeyStoreIdentity`: an [`Identity`] over any `KeyStore` and the `DidProducer`s registered with
2//! it.
3
4use core::fmt;
5use std::sync::{Arc, PoisonError, RwLock};
6
7use super::{Identifier, Identity, IdentityError, IdentityKind};
8use crate::did::{DidMethod, DidUrl};
9use crate::jose::{Jwk, JwsAlgorithm, KeyType, SignError, Signer};
10use crate::keys::{KeyId, KeySigner, KeySpec, KeyStore, KeyStoreError};
11use crate::resolver::DidProducer;
12
13/// An [`Identity`] over the keys of a [`KeyStore`], vendor-agnostic: a KMS or HSM backend that
14/// implements [`KeyStore`] works without glue.
15///
16/// A key of the store is bound to a `(kind, alg)` pair with [`bind`](Self::bind), which derives
17/// the identifier: the thumbprint of the key for [`IdentityKind::JwkThumbprint`], and for
18/// [`IdentityKind::Did`] the DID of the document that the producer registered for the method
19/// (see [`with_producer`](Self::with_producer)) makes for the key, with its first verification
20/// method as the `kid`. A DID that no registered producer can make, such as a `did:web` whose
21/// producer needs an origin, is bound with [`bind_did_url`](Self::bind_did_url).
22///
23/// # Key generation is opt-in
24///
25/// By default an unbound pair is an error, so that a production deployment never mints keys
26/// silently. With [`generate_missing(true)`](Self::generate_missing) the identity asks the store
27/// for a new key the first time an unbound pair is used, binds it, and reuses it from then on.
28/// Bindings live in memory only: an application that generates keys this way stores
29/// [`bindings`](Self::bindings) and binds them again on the next start.
30///
31/// # Examples
32///
33/// ```
34/// # #[cfg(all(feature = "in-memory", feature = "did-key", feature = "did-jwk"))]
35/// # tokio::runtime::Builder::new_current_thread().build()?.block_on(async {
36/// use std::sync::Arc;
37///
38/// use identity_kit::did::DidMethod;
39/// use identity_kit::identity::{Identity, IdentityKind, KeyStoreIdentity};
40/// use identity_kit::jose::JwsAlgorithm;
41/// use identity_kit::keys::InMemoryKeyStore;
42/// use identity_kit::methods::{DidJwk, DidKey};
43///
44/// let identity = KeyStoreIdentity::new(Arc::new(InMemoryKeyStore::new()))
45///     .with_producer(DidKey::default())
46///     .with_producer(DidJwk)
47///     .generate_missing(true);
48///
49/// let kind = IdentityKind::Did(DidMethod::new("jwk")?);
50/// let did = identity.identifier(&kind, JwsAlgorithm::ES256).await?;
51/// assert!(did.to_string().starts_with("did:jwk:"));
52/// // The key was generated once and is reused.
53/// assert_eq!(identity.identifier(&kind, JwsAlgorithm::ES256).await?, did);
54/// assert_eq!(identity.bindings().len(), 1);
55/// # Ok::<(), Box<dyn std::error::Error>>(())
56/// # })?;
57/// # Ok::<(), Box<dyn std::error::Error>>(())
58/// ```
59pub struct KeyStoreIdentity {
60    store: Arc<dyn KeyStore>,
61    producers: Vec<Arc<dyn DidProducer<Params = ()>>>,
62    generate_missing: bool,
63    bindings: RwLock<Vec<Binding>>,
64}
65
66/// A key bound to a `(kind, alg)` pair, with what was derived from it.
67#[derive(Clone)]
68struct Binding {
69    kind: IdentityKind,
70    signer: KeySigner<Arc<dyn KeyStore>>,
71    identifier: Identifier,
72    kid: Option<String>,
73}
74
75impl KeyStoreIdentity {
76    /// An identity over `store`, with no producer, no binding and key generation off.
77    pub fn new(store: Arc<dyn KeyStore>) -> Self {
78        Self {
79            store,
80            producers: Vec::new(),
81            generate_missing: false,
82            bindings: RwLock::new(Vec::new()),
83        }
84    }
85
86    /// This identity with `producer` making the DIDs of its method, replacing a producer
87    /// registered for the same method before.
88    ///
89    /// Only producers that need no parameters (`Params = ()`) are registered: those whose DID
90    /// follows from the key, such as `did:key` and `did:jwk`. A DID made with parameters, such as
91    /// a `did:web` from its origin, is bound with [`bind_did_url`](Self::bind_did_url).
92    #[must_use]
93    pub fn with_producer(mut self, producer: impl DidProducer<Params = ()> + 'static) -> Self {
94        self.producers
95            .retain(|registered| registered.method() != producer.method());
96        self.producers.push(Arc::new(producer));
97        self
98    }
99
100    /// This identity generating a key the first time an unbound pair is used, when `enabled`
101    /// and the store can generate keys for the algorithm. Off by default; see the
102    /// [type documentation](Self#key-generation-is-opt-in).
103    #[must_use]
104    pub fn generate_missing(mut self, enabled: bool) -> Self {
105        self.generate_missing = enabled;
106        self
107    }
108
109    /// Binds `key` of the store to `(kind, alg)`, replacing a key bound to the pair before, and
110    /// returns the identifier derived from it.
111    ///
112    /// # Errors
113    ///
114    /// - [`IdentityError::UnsupportedAlgorithm`] when the store does not sign with `alg`;
115    /// - [`IdentityError::KeyStore`] when the key does not exist or is not a key for `alg`;
116    /// - [`IdentityError::UnsupportedKind`] when no registered producer makes DIDs of the
117    ///   method, or the DID it made is not in the namespace of `kind`;
118    /// - [`IdentityError::Produce`] when the producer refuses the key;
119    /// - [`IdentityError::NoVerificationMethod`] when its document has no verification method.
120    pub async fn bind(
121        &self,
122        kind: IdentityKind,
123        alg: JwsAlgorithm,
124        key: KeyId,
125    ) -> Result<Identifier, IdentityError> {
126        let binding = self.derive(kind, alg, key).await?;
127        let identifier = binding.identifier.clone();
128        self.insert(binding, true);
129        Ok(identifier)
130    }
131
132    /// Binds `key` of the store to `(kind, alg)` as the verification method `url`, replacing a
133    /// key bound to the pair before, and returns the DID of `url`.
134    ///
135    /// This is how a DID that no registered producer makes is used: a `did:web`, or a DID of a
136    /// registry method that the application created. The caller vouches that the published
137    /// document of the DID has `url` as a verification method with the public key of `key`;
138    /// the identity cannot tell without resolving it.
139    ///
140    /// # Errors
141    ///
142    /// [`IdentityError::UnsupportedKind`] when `kind` is not a DID kind that the DID of `url`
143    /// matches, and as [`bind`](Self::bind) for the key.
144    pub async fn bind_did_url(
145        &self,
146        kind: IdentityKind,
147        alg: JwsAlgorithm,
148        key: KeyId,
149        url: DidUrl,
150    ) -> Result<Identifier, IdentityError> {
151        match &kind {
152            IdentityKind::Did(method) if method.matches(url.did()) => {}
153            _ => return Err(IdentityError::UnsupportedKind(kind)),
154        }
155        let signer = self.signer_for(alg, key).await?;
156        let identifier = Identifier::Did(url.did().clone());
157        self.insert(
158            Binding {
159                kind,
160                signer,
161                identifier: identifier.clone(),
162                kid: Some(url.to_string()),
163            },
164            true,
165        );
166        Ok(identifier)
167    }
168
169    /// The bound pairs and their keys, in the order they were bound, for an application to
170    /// store and bind again on the next start.
171    pub fn bindings(&self) -> Vec<(IdentityKind, JwsAlgorithm, KeyId)> {
172        self.read()
173            .iter()
174            .map(|binding| {
175                (
176                    binding.kind.clone(),
177                    binding.signer.alg(),
178                    binding.signer.key_id().clone(),
179                )
180            })
181            .collect()
182    }
183
184    /// A signer over `key` for `alg`, which checks that the store signs with `alg` and that
185    /// `key` exists and is a key for it.
186    async fn signer_for(
187        &self,
188        alg: JwsAlgorithm,
189        key: KeyId,
190    ) -> Result<KeySigner<Arc<dyn KeyStore>>, IdentityError> {
191        KeySigner::new(Arc::clone(&self.store), key, alg)
192            .await
193            .map_err(|error| match error {
194                KeyStoreError::UnsupportedAlgorithm(alg) => {
195                    IdentityError::UnsupportedAlgorithm(alg)
196                }
197                error => IdentityError::KeyStore(error),
198            })
199    }
200
201    /// The binding of `key` to `(kind, alg)`, with its identifier and `kid`.
202    async fn derive(
203        &self,
204        kind: IdentityKind,
205        alg: JwsAlgorithm,
206        key: KeyId,
207    ) -> Result<Binding, IdentityError> {
208        let producer = match &kind {
209            IdentityKind::Did(method) => Some(
210                self.producer(method)
211                    .ok_or_else(|| IdentityError::UnsupportedKind(kind.clone()))?,
212            ),
213            IdentityKind::JwkThumbprint => None,
214        };
215        let signer = self.signer_for(alg, key).await?;
216        let public = signer.public_jwk().public();
217        let (identifier, kid) = match (&kind, producer) {
218            (IdentityKind::Did(method), Some(producer)) => {
219                let document = producer.produce(&[public], ()).await?;
220                if !method.matches(&document.id) {
221                    return Err(IdentityError::UnsupportedKind(kind));
222                }
223                let kid = document
224                    .methods(None)
225                    .next()
226                    .map(|method| method.id.to_string())
227                    .ok_or_else(|| IdentityError::NoVerificationMethod(document.id.clone()))?;
228                (Identifier::Did(document.id), Some(kid))
229            }
230            _ => (Identifier::JwkThumbprint(public.thumbprint_sha256()?), None),
231        };
232        Ok(Binding {
233            kind,
234            signer,
235            identifier,
236            kid,
237        })
238    }
239
240    /// The registered producer for the method of `method`.
241    fn producer(&self, method: &DidMethod) -> Option<&Arc<dyn DidProducer<Params = ()>>> {
242        self.producers
243            .iter()
244            .find(|producer| producer.method() == method.name())
245    }
246
247    /// The binding of `(kind, alg)`, generating a key for it when that is enabled.
248    async fn binding(
249        &self,
250        kind: &IdentityKind,
251        alg: JwsAlgorithm,
252    ) -> Result<Binding, IdentityError> {
253        if let Some(binding) = self.find(kind, alg) {
254            return Ok(binding);
255        }
256        if !self.generate_missing {
257            return Err(if self.read().iter().any(|binding| binding.kind == *kind) {
258                IdentityError::UnsupportedAlgorithm(alg)
259            } else {
260                IdentityError::UnsupportedKind(kind.clone())
261            });
262        }
263        if let IdentityKind::Did(method) = kind
264            && self.producer(method).is_none()
265        {
266            return Err(IdentityError::UnsupportedKind(kind.clone()));
267        }
268        let capabilities = self.store.capabilities();
269        let Some(key_type) = key_type_for(alg).filter(|_| capabilities.supports(alg)) else {
270            return Err(IdentityError::UnsupportedAlgorithm(alg));
271        };
272        if !capabilities.can_generate {
273            return Err(KeyStoreError::Unsupported("generate").into());
274        }
275        let key = self.store.generate(KeySpec::new(key_type, alg)).await?;
276        let binding = match self.derive(kind.clone(), alg, key.clone()).await {
277            Ok(binding) => binding,
278            Err(error) => {
279                self.discard(&key).await;
280                return Err(error);
281            }
282        };
283        let kept = self.insert(binding, false);
284        // Another call generated a key for the pair at the same time and won.
285        if kept.signer.key_id() != &key {
286            self.discard(&key).await;
287        }
288        Ok(kept)
289    }
290
291    /// Deletes a key this identity generated and does not use, when the store can.
292    async fn discard(&self, key: &KeyId) {
293        if self.store.capabilities().can_delete {
294            // Best effort: the key is unused either way.
295            let _ = self.store.delete(key).await;
296        }
297    }
298
299    fn find(&self, kind: &IdentityKind, alg: JwsAlgorithm) -> Option<Binding> {
300        self.read()
301            .iter()
302            .find(|binding| binding.kind == *kind && binding.signer.alg() == alg)
303            .cloned()
304    }
305
306    /// Stores `binding`. A binding of the same pair is replaced when `replace`, and kept
307    /// otherwise; returns the binding the pair has afterwards.
308    fn insert(&self, binding: Binding, replace: bool) -> Binding {
309        let mut bindings = self
310            .bindings
311            .write()
312            .unwrap_or_else(PoisonError::into_inner);
313        let existing = bindings
314            .iter_mut()
315            .find(|bound| bound.kind == binding.kind && bound.signer.alg() == binding.signer.alg());
316        match existing {
317            Some(bound) if replace => {
318                *bound = binding.clone();
319                binding
320            }
321            Some(bound) => bound.clone(),
322            None => {
323                bindings.push(binding.clone());
324                binding
325            }
326        }
327    }
328
329    fn read(&self) -> std::sync::RwLockReadGuard<'_, Vec<Binding>> {
330        self.bindings.read().unwrap_or_else(PoisonError::into_inner)
331    }
332}
333
334/// The key type generated for `alg`: `None` for ES384, which no [`KeyType`] of this crate is,
335/// and the 2048-bit key for the RSA algorithms.
336fn key_type_for(alg: JwsAlgorithm) -> Option<KeyType> {
337    match alg {
338        JwsAlgorithm::EdDSA => Some(KeyType::Ed25519),
339        JwsAlgorithm::ES256 => Some(KeyType::P256),
340        JwsAlgorithm::ES256K => Some(KeyType::Secp256k1),
341        JwsAlgorithm::RS256 | JwsAlgorithm::PS256 => Some(KeyType::Rsa2048),
342        JwsAlgorithm::ES384 => None,
343    }
344}
345
346impl fmt::Debug for KeyStoreIdentity {
347    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
348        let producers: Vec<&str> = self
349            .producers
350            .iter()
351            .map(|producer| producer.method())
352            .collect();
353        f.debug_struct("KeyStoreIdentity")
354            .field("producers", &producers)
355            .field("generate_missing", &self.generate_missing)
356            .field("bindings", &self.bindings())
357            .finish_non_exhaustive()
358    }
359}
360
361#[async_trait::async_trait]
362impl Identity for KeyStoreIdentity {
363    /// The bound pairs, then, when key generation is on and the store can generate, every pair
364    /// of a registered producer's method or the thumbprint with an algorithm the store
365    /// generates keys for. A generated pair can still fail when the producer refuses the key
366    /// type.
367    fn capabilities(&self) -> Vec<(IdentityKind, JwsAlgorithm)> {
368        let mut pairs: Vec<(IdentityKind, JwsAlgorithm)> = self
369            .read()
370            .iter()
371            .map(|binding| (binding.kind.clone(), binding.signer.alg()))
372            .collect();
373        let capabilities = self.store.capabilities();
374        if self.generate_missing && capabilities.can_generate {
375            let kinds = self
376                .producers
377                .iter()
378                .filter_map(|producer| DidMethod::new(producer.method()).ok())
379                .map(IdentityKind::Did)
380                .chain([IdentityKind::JwkThumbprint]);
381            for kind in kinds {
382                for &alg in &capabilities.algorithms {
383                    if key_type_for(alg).is_some() && !pairs.contains(&(kind.clone(), alg)) {
384                        pairs.push((kind.clone(), alg));
385                    }
386                }
387            }
388        }
389        pairs
390    }
391
392    async fn identifier(
393        &self,
394        kind: &IdentityKind,
395        alg: JwsAlgorithm,
396    ) -> Result<Identifier, IdentityError> {
397        Ok(self.binding(kind, alg).await?.identifier)
398    }
399
400    async fn public_jwk(
401        &self,
402        kind: &IdentityKind,
403        alg: JwsAlgorithm,
404    ) -> Result<Jwk, IdentityError> {
405        Ok(self.binding(kind, alg).await?.signer.public_jwk().public())
406    }
407
408    async fn signer(
409        &self,
410        kind: &IdentityKind,
411        alg: JwsAlgorithm,
412    ) -> Result<Box<dyn Signer + '_>, IdentityError> {
413        let binding = self.binding(kind, alg).await?;
414        Ok(Box::new(BoundSigner {
415            signer: binding.signer,
416            kid: binding.kid,
417        }))
418    }
419}
420
421/// A [`KeySigner`] whose [`Signer::kid`] is the verification method of a DID, or `None` for a
422/// thumbprint.
423struct BoundSigner {
424    signer: KeySigner<Arc<dyn KeyStore>>,
425    kid: Option<String>,
426}
427
428#[async_trait::async_trait]
429impl Signer for BoundSigner {
430    fn alg(&self) -> JwsAlgorithm {
431        self.signer.alg()
432    }
433
434    fn kid(&self) -> Option<&str> {
435        self.kid.as_deref()
436    }
437
438    async fn sign(&self, signing_input: &[u8]) -> Result<Vec<u8>, SignError> {
439        self.signer.sign(signing_input).await
440    }
441}