1use crate::error::Result;
2use crate::resolve::MaterialWatcher;
3use crate::types::{AuthorizeSpiffeId, authorize_any};
4use crate::verifier::SpiffeServerCertVerifier;
5use rustls::ClientConfig;
6use rustls::client::ResolvesClientCert;
7use spiffe::{TrustDomain, X509Source};
8use std::sync::Arc;
9
10#[derive(Clone)]
12pub struct ClientConfigOptions {
13 pub trust_domain: TrustDomain,
15
16 pub authorize_server: AuthorizeSpiffeId,
20}
21
22impl ClientConfigOptions {
23 pub fn allow_any(trust_domain: TrustDomain) -> Self {
27 Self {
28 trust_domain,
29 authorize_server: authorize_any(),
30 }
31 }
32}
33
34pub struct ClientConfigBuilder {
43 source: Arc<X509Source>,
44 opts: ClientConfigOptions,
45}
46
47impl ClientConfigBuilder {
48 pub fn new(source: Arc<X509Source>, opts: ClientConfigOptions) -> Self {
50 Self { source, opts }
51 }
52
53 pub async fn build(self) -> Result<ClientConfig> {
55 crate::crypto::ensure_crypto_provider_installed();
56
57 let watcher = MaterialWatcher::new(self.source, self.opts.trust_domain).await?;
58
59 let resolver: Arc<dyn ResolvesClientCert> =
60 Arc::new(resolve_client::SpiffeClientCertResolver {
61 watcher: watcher.clone(),
62 });
63
64 let verifier = Arc::new(SpiffeServerCertVerifier::new(
65 Arc::new(watcher.clone()),
66 self.opts.authorize_server,
67 )?);
68
69 let cfg = ClientConfig::builder()
70 .dangerous()
71 .with_custom_certificate_verifier(verifier)
72 .with_client_cert_resolver(resolver);
73
74 Ok(cfg)
75 }
76}
77
78mod resolve_client {
79 use crate::resolve::MaterialWatcher;
80 use rustls::client::ResolvesClientCert;
81 use rustls::sign::CertifiedKey;
82 use std::sync::Arc;
83
84 #[derive(Clone, Debug)]
85 pub(crate) struct SpiffeClientCertResolver {
86 pub watcher: MaterialWatcher,
87 }
88
89 impl ResolvesClientCert for SpiffeClientCertResolver {
90 fn resolve(
91 &self,
92 _acceptable_issuers: &[&[u8]],
93 _sigschemes: &[rustls::SignatureScheme],
94 ) -> Option<Arc<CertifiedKey>> {
95 Some(self.watcher.current().certified_key.clone())
96 }
97
98 fn has_certs(&self) -> bool {
99 true
100 }
101 }
102}