Skip to main content

cratestack_cose/auth/
signer_member.rs

1//! [`CoseSignerProvider`]: the COSE-verified signer as an [`AuthProvider`]
2//! of its own, the member of [`CoseAuthProvider`](super::CoseAuthProvider)'s
3//! first-success chain that reads the signer (cratestack#1243, ADR 0021 ยง5).
4//!
5//! Its credential is the [`VerifiedSigner`] the envelope layer recorded in
6//! the request's extensions: present when there is one, absent otherwise.
7//! A signer whose key a registry still holds authenticates (see
8//! `CoseAuthProvider`'s rule 3); an unknown or revoked key, or a device key
9//! while device authentication is off, is anonymous; a failing registry that
10//! is asked is an `Err` (`500`).
11
12use std::sync::Arc;
13
14use cratestack_auth::DeviceKeyResolver;
15use cratestack_core::{
16    AuthProvider, CratestackContext, CratestackError, Credential, RequestContext, VerifiedSigner,
17};
18
19use super::signer_principal::{SignerRegistries, authenticated};
20use crate::keys::CoseVerifierResolver;
21
22/// The COSE-verified signer as an [`AuthProvider`]. Compose it with another
23/// provider through `cratestack::first_success(...).or(...)`, or use
24/// [`CoseAuthProvider`](super::CoseAuthProvider), which does exactly that.
25/// The "Security" sections of `CoseAuthProvider` apply unchanged.
26#[derive(Clone)]
27pub struct CoseSignerProvider {
28    registries: SignerRegistries,
29}
30
31impl CoseSignerProvider {
32    /// `devices` (its thumbprint lookup) is asked only after
33    /// [`authenticate_devices(true)`](Self::authenticate_devices).
34    pub fn new(devices: Arc<dyn DeviceKeyResolver>) -> Self {
35        Self {
36            registries: SignerRegistries::new(devices),
37        }
38    }
39
40    /// See `CoseAuthProvider::authenticate_devices`.
41    pub fn authenticate_devices(mut self, enabled: bool) -> Self {
42        self.registries = self.registries.with_devices_enabled(enabled);
43        self
44    }
45
46    /// See `CoseAuthProvider::with_service_keys`: service keys only.
47    pub fn with_service_keys(mut self, services: Arc<dyn CoseVerifierResolver>) -> Self {
48        self.registries = self.registries.with_services(services);
49        self
50    }
51}
52
53impl std::fmt::Debug for CoseSignerProvider {
54    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55        f.debug_struct("CoseSignerProvider").finish_non_exhaustive()
56    }
57}
58
59impl AuthProvider for CoseSignerProvider {
60    type Error = CratestackError;
61
62    async fn authenticate(
63        &self,
64        request: &RequestContext<'_>,
65    ) -> Result<CratestackContext, CratestackError> {
66        let Some(signer) = request.extensions.get::<VerifiedSigner>() else {
67            return Ok(CratestackContext::anonymous());
68        };
69        Ok(match self.registries.vouch(signer).await? {
70            Some(kind) => authenticated(signer, kind),
71            None => CratestackContext::anonymous(),
72        })
73    }
74
75    /// Present when the envelope layer recorded a verified signer. Only the
76    /// extensions are read: nothing on the wire can set one.
77    fn credential<'r>(&self, request: &RequestContext<'r>) -> Credential<'r> {
78        if request.extensions.get::<VerifiedSigner>().is_some() {
79            Credential::Present { redact: None }
80        } else {
81            Credential::Absent
82        }
83    }
84}