1use crate::error::Result;
2use crate::resolve::MaterialWatcher;
3use crate::types::{authorize_any, AuthorizeSpiffeId};
4use crate::verifier::SpiffeServerCertVerifier;
5use rustls::client::ResolvesClientCert;
6use rustls::ClientConfig;
7use spiffe::{TrustDomain, X509Source};
8use std::sync::Arc;
9
10#[derive(Clone)]
14pub struct ClientConfigOptions {
15 pub trust_domain: TrustDomain,
17
18 pub authorize_server: AuthorizeSpiffeId,
23}
24
25impl ClientConfigOptions {
26 pub fn allow_any(trust_domain: TrustDomain) -> Self {
31 Self {
32 trust_domain,
33 authorize_server: authorize_any(),
34 }
35 }
36}
37
38pub struct ClientConfigBuilder {
59 source: Arc<X509Source>,
60 opts: ClientConfigOptions,
61}
62
63impl ClientConfigBuilder {
64 pub fn new(source: Arc<X509Source>, opts: ClientConfigOptions) -> Self {
66 Self { source, opts }
67 }
68
69 pub async fn build(self) -> Result<ClientConfig> {
71 crate::crypto::ensure_crypto_provider_installed();
72
73 let watcher = MaterialWatcher::new(self.source, self.opts.trust_domain).await?;
74
75 let resolver: Arc<dyn ResolvesClientCert> =
76 Arc::new(resolve_client::SpiffeClientCertResolver {
77 watcher: watcher.clone(),
78 });
79
80 let verifier = Arc::new(SpiffeServerCertVerifier::new(
81 Arc::new(watcher.clone()),
82 self.opts.authorize_server,
83 )?);
84
85 let cfg = ClientConfig::builder()
86 .dangerous()
87 .with_custom_certificate_verifier(verifier)
88 .with_client_cert_resolver(resolver);
89
90 Ok(cfg)
91 }
92}
93
94mod resolve_client {
95 use crate::resolve::MaterialWatcher;
96 use rustls::client::ResolvesClientCert;
97 use rustls::sign::CertifiedKey;
98 use std::sync::Arc;
99
100 #[derive(Clone, Debug)]
101 pub(crate) struct SpiffeClientCertResolver {
102 pub watcher: MaterialWatcher,
103 }
104
105 impl ResolvesClientCert for SpiffeClientCertResolver {
106 fn resolve(
107 &self,
108 _acceptable_issuers: &[&[u8]],
109 _sigschemes: &[rustls::SignatureScheme],
110 ) -> Option<Arc<CertifiedKey>> {
111 Some(self.watcher.current().certified_key.clone())
112 }
113
114 fn has_certs(&self) -> bool {
115 true
116 }
117 }
118}