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 let watcher = MaterialWatcher::new(self.source, self.opts.trust_domain).await?;
58 let mat = watcher.current();
59
60 let resolver: Arc<dyn ResolvesClientCert> =
61 Arc::new(resolve_client::SpiffeClientCertResolver { watcher });
62
63 let verifier = Arc::new(SpiffeServerCertVerifier::new(
64 mat.roots.clone(),
65 self.opts.authorize_server,
66 )?);
67
68 let cfg = ClientConfig::builder()
69 .dangerous()
70 .with_custom_certificate_verifier(verifier)
71 .with_client_cert_resolver(resolver);
72
73 Ok(cfg)
74 }
75}
76
77mod resolve_client {
78 use crate::resolve::MaterialWatcher;
79 use rustls::client::ResolvesClientCert;
80 use rustls::sign::CertifiedKey;
81 use std::sync::Arc;
82
83 #[derive(Clone, Debug)]
84 pub(crate) struct SpiffeClientCertResolver {
85 pub watcher: MaterialWatcher,
86 }
87
88 impl ResolvesClientCert for SpiffeClientCertResolver {
89 fn resolve(
90 &self,
91 _acceptable_issuers: &[&[u8]],
92 _sigschemes: &[rustls::SignatureScheme],
93 ) -> Option<Arc<CertifiedKey>> {
94 Some(self.watcher.current().certified_key.clone())
95 }
96
97 fn has_certs(&self) -> bool {
98 true
99 }
100 }
101}