kutil_http/tls/
resolver.rs

1use {
2    bytestring::*,
3    kutil_std::collections::*,
4    rustls::{server::*, sign::*},
5    std::sync::*,
6};
7
8//
9// SniResolver
10//
11
12/// [ResolvesServerCert] that can select the target by client SNI (Server Name Indication).
13///
14/// Also has an optimized mode for when there is only one target, which skips checking the SNI.
15///
16/// See [ResolvesServerCertUsingSni] for a simpler version.
17#[derive(Clone, Debug)]
18pub enum SniResolver {
19    /// Select [SniResolverTarget] by SNI.
20    BySNI(FastHashMap<ByteString, SniResolverTarget>),
21
22    /// Single [SniResolverTarget].
23    Single(SniResolverTarget),
24}
25
26impl ResolvesServerCert for SniResolver {
27    fn resolve(&self, client_hello: ClientHello<'_>) -> Option<Arc<CertifiedKey>> {
28        match self {
29            Self::BySNI(targets) => match client_hello.server_name() {
30                Some(sni) => match targets.get(sni) {
31                    Some(target) => {
32                        tracing::trace!("SNI: {}", sni);
33                        target.resolve(client_hello)
34                    }
35
36                    None => {
37                        tracing::warn!("unknown SNI: {}", sni);
38                        None
39                    }
40                },
41
42                // Client did not provide an SNI
43                None => {
44                    tracing::trace!("no SNI");
45                    None
46                }
47            },
48
49            Self::Single(target) => {
50                tracing::trace!("single");
51                target.resolve(client_hello)
52            }
53        }
54    }
55}
56
57//
58// SniResolverTarget
59//
60
61/// Target for [SniResolver].
62#[derive(Clone, Debug)]
63pub enum SniResolverTarget {
64    /// Key.
65    Key(Arc<CertifiedKey>),
66
67    /// Delegate.
68    Delegate(Arc<dyn ResolvesServerCert>),
69}
70
71impl ResolvesServerCert for SniResolverTarget {
72    fn resolve(&self, client_hello: ClientHello<'_>) -> Option<Arc<rustls::sign::CertifiedKey>> {
73        match self {
74            Self::Key(certified_key) => {
75                tracing::trace!("key");
76                Some(certified_key.clone())
77            }
78
79            Self::Delegate(delegate) => {
80                tracing::trace!("delegate");
81                delegate.resolve(client_hello)
82            }
83        }
84    }
85}