kube_client/client/
tls.rs

1#[cfg(feature = "rustls-tls")]
2pub mod rustls_tls {
3    use hyper_rustls::ConfigBuilderExt;
4    use rustls::{
5        self,
6        client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier},
7        pki_types::{CertificateDer, InvalidDnsNameError, PrivateKeyDer, ServerName},
8        ClientConfig, DigitallySignedStruct,
9    };
10    use thiserror::Error;
11
12    /// Errors from Rustls
13    #[derive(Debug, Error)]
14    pub enum Error {
15        /// Identity PEM is invalid
16        #[error("identity PEM is invalid: {0}")]
17        InvalidIdentityPem(#[source] rustls::pki_types::pem::Error),
18
19        /// Identity PEM is missing a private key: the key must be PKCS8 or RSA/PKCS1
20        #[error("identity PEM is missing a private key: the key must be PKCS8 or RSA/PKCS1")]
21        MissingPrivateKey,
22
23        /// Identity PEM is missing certificate
24        #[error("identity PEM is missing certificate")]
25        MissingCertificate,
26
27        /// Invalid private key
28        #[error("invalid private key: {0}")]
29        InvalidPrivateKey(#[source] rustls::Error),
30
31        /// Unknown private key format
32        #[error("unknown private key format")]
33        UnknownPrivateKeyFormat,
34
35        // Using type-erased error to avoid depending on webpki
36        /// Failed to add a root certificate
37        #[error("failed to add a root certificate: {0}")]
38        AddRootCertificate(#[source] Box<dyn std::error::Error + Send + Sync>),
39
40        /// No valid native root CA certificates found
41        #[error("no valid native root CA certificates found")]
42        NoValidNativeRootCA(#[source] std::io::Error),
43
44        /// Invalid server name
45        #[error("invalid server name: {0}")]
46        InvalidServerName(#[source] InvalidDnsNameError),
47    }
48
49    /// Create `rustls::ClientConfig`.
50    pub fn rustls_client_config(
51        identity_pem: Option<&[u8]>,
52        root_certs: Option<&[Vec<u8>]>,
53        accept_invalid: bool,
54    ) -> Result<ClientConfig, Error> {
55        let config_builder = if let Some(certs) = root_certs {
56            ClientConfig::builder().with_root_certificates(root_store(certs)?)
57        } else {
58            #[cfg(feature = "webpki-roots")]
59            {
60                // Use WebPKI roots.
61                ClientConfig::builder().with_webpki_roots()
62            }
63            #[cfg(not(feature = "webpki-roots"))]
64            {
65                // Use native roots. This will panic on Android and iOS.
66                ClientConfig::builder()
67                    .with_native_roots()
68                    .map_err(Error::NoValidNativeRootCA)?
69            }
70        };
71
72        let mut client_config = if let Some((chain, pkey)) = identity_pem.map(client_auth).transpose()? {
73            config_builder
74                .with_client_auth_cert(chain, pkey)
75                .map_err(Error::InvalidPrivateKey)?
76        } else {
77            config_builder.with_no_client_auth()
78        };
79
80        if accept_invalid {
81            client_config
82                .dangerous()
83                .set_certificate_verifier(std::sync::Arc::new(NoCertificateVerification {}));
84        }
85        Ok(client_config)
86    }
87
88    fn root_store(root_certs: &[Vec<u8>]) -> Result<rustls::RootCertStore, Error> {
89        let mut root_store = rustls::RootCertStore::empty();
90        for der in root_certs {
91            root_store
92                .add(CertificateDer::from(der.to_owned()))
93                .map_err(|e| Error::AddRootCertificate(Box::new(e)))?;
94        }
95        Ok(root_store)
96    }
97
98    fn client_auth(data: &[u8]) -> Result<(Vec<CertificateDer<'static>>, PrivateKeyDer<'static>), Error> {
99        use rustls::pki_types::pem::{self, SectionKind};
100
101        let mut cert_chain = Vec::new();
102        let mut pkcs8_key = None;
103        let mut pkcs1_key = None;
104        let mut sec1_key = None;
105        let mut reader = std::io::Cursor::new(data);
106        while let Some((kind, der)) = pem::from_buf(&mut reader).map_err(Error::InvalidIdentityPem)? {
107            match kind {
108                SectionKind::Certificate => cert_chain.push(der.into()),
109                SectionKind::PrivateKey => pkcs8_key = Some(PrivateKeyDer::Pkcs8(der.into())),
110                SectionKind::RsaPrivateKey => pkcs1_key = Some(PrivateKeyDer::Pkcs1(der.into())),
111                SectionKind::EcPrivateKey => sec1_key = Some(PrivateKeyDer::Sec1(der.into())),
112                _ => return Err(Error::UnknownPrivateKeyFormat),
113            }
114        }
115
116        let private_key = pkcs8_key
117            .or(pkcs1_key)
118            .or(sec1_key)
119            .ok_or(Error::MissingPrivateKey)?;
120        if cert_chain.is_empty() {
121            return Err(Error::MissingCertificate);
122        }
123        Ok((cert_chain, private_key))
124    }
125
126    #[derive(Debug)]
127    struct NoCertificateVerification {}
128
129    impl ServerCertVerifier for NoCertificateVerification {
130        fn verify_server_cert(
131            &self,
132            _end_entity: &CertificateDer,
133            _intermediates: &[CertificateDer],
134            _server_name: &ServerName,
135            _ocsp_response: &[u8],
136            _now: rustls::pki_types::UnixTime,
137        ) -> Result<ServerCertVerified, rustls::Error> {
138            tracing::warn!("Server cert bypassed");
139            Ok(ServerCertVerified::assertion())
140        }
141
142        fn verify_tls13_signature(
143            &self,
144            _message: &[u8],
145            _cert: &CertificateDer,
146            _dss: &DigitallySignedStruct,
147        ) -> Result<HandshakeSignatureValid, rustls::Error> {
148            Ok(HandshakeSignatureValid::assertion())
149        }
150
151        fn verify_tls12_signature(
152            &self,
153            _message: &[u8],
154            _cert: &CertificateDer,
155            _dss: &DigitallySignedStruct,
156        ) -> Result<HandshakeSignatureValid, rustls::Error> {
157            Ok(HandshakeSignatureValid::assertion())
158        }
159
160        fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
161            use rustls::SignatureScheme;
162            vec![
163                SignatureScheme::RSA_PKCS1_SHA1,
164                SignatureScheme::ECDSA_SHA1_Legacy,
165                SignatureScheme::RSA_PKCS1_SHA256,
166                SignatureScheme::ECDSA_NISTP256_SHA256,
167                SignatureScheme::RSA_PKCS1_SHA384,
168                SignatureScheme::ECDSA_NISTP384_SHA384,
169                SignatureScheme::RSA_PKCS1_SHA512,
170                SignatureScheme::ECDSA_NISTP521_SHA512,
171                SignatureScheme::RSA_PSS_SHA256,
172                SignatureScheme::RSA_PSS_SHA384,
173                SignatureScheme::RSA_PSS_SHA512,
174                SignatureScheme::ED25519,
175                SignatureScheme::ED448,
176            ]
177        }
178    }
179}
180
181#[cfg(feature = "openssl-tls")]
182pub mod openssl_tls {
183    use openssl::{
184        pkey::PKey,
185        ssl::{SslConnector, SslConnectorBuilder, SslMethod},
186        x509::X509,
187    };
188    use thiserror::Error;
189
190    /// Errors from OpenSSL TLS
191    #[derive(Debug, Error)]
192    pub enum Error {
193        /// Failed to create OpenSSL HTTPS connector
194        #[error("failed to create OpenSSL HTTPS connector: {0}")]
195        CreateHttpsConnector(#[source] openssl::error::ErrorStack),
196
197        /// Failed to create OpenSSL SSL connector
198        #[error("failed to create OpenSSL SSL connector: {0}")]
199        CreateSslConnector(#[source] SslConnectorError),
200    }
201
202    /// Errors from creating a `SslConnectorBuilder`
203    #[derive(Debug, Error)]
204    pub enum SslConnectorError {
205        /// Failed to build SslConnectorBuilder
206        #[error("failed to build SslConnectorBuilder: {0}")]
207        CreateBuilder(#[source] openssl::error::ErrorStack),
208
209        /// Failed to deserialize PEM-encoded chain of certificates
210        #[error("failed to deserialize PEM-encoded chain of certificates: {0}")]
211        DeserializeCertificateChain(#[source] openssl::error::ErrorStack),
212
213        /// Failed to deserialize PEM-encoded private key
214        #[error("failed to deserialize PEM-encoded private key: {0}")]
215        DeserializePrivateKey(#[source] openssl::error::ErrorStack),
216
217        /// Failed to set private key
218        #[error("failed to set private key: {0}")]
219        SetPrivateKey(#[source] openssl::error::ErrorStack),
220
221        /// Failed to get a leaf certificate, the certificate chain is empty
222        #[error("failed to get a leaf certificate, the certificate chain is empty")]
223        GetLeafCertificate,
224
225        /// Failed to set the leaf certificate
226        #[error("failed to set the leaf certificate: {0}")]
227        SetLeafCertificate(#[source] openssl::error::ErrorStack),
228
229        /// Failed to append a certificate to the chain
230        #[error("failed to append a certificate to the chain: {0}")]
231        AppendCertificate(#[source] openssl::error::ErrorStack),
232
233        /// Failed to deserialize DER-encoded root certificate
234        #[error("failed to deserialize DER-encoded root certificate: {0}")]
235        DeserializeRootCertificate(#[source] openssl::error::ErrorStack),
236
237        /// Failed to add a root certificate
238        #[error("failed to add a root certificate: {0}")]
239        AddRootCertificate(#[source] openssl::error::ErrorStack),
240    }
241
242    /// Create `openssl::ssl::SslConnectorBuilder` required for `hyper_openssl::HttpsConnector`.
243    pub fn ssl_connector_builder(
244        identity_pem: Option<&Vec<u8>>,
245        root_certs: Option<&Vec<Vec<u8>>>,
246    ) -> Result<SslConnectorBuilder, SslConnectorError> {
247        let mut builder =
248            SslConnector::builder(SslMethod::tls()).map_err(SslConnectorError::CreateBuilder)?;
249        if let Some(pem) = identity_pem {
250            let mut chain = X509::stack_from_pem(pem)
251                .map_err(SslConnectorError::DeserializeCertificateChain)?
252                .into_iter();
253            let leaf_cert = chain.next().ok_or(SslConnectorError::GetLeafCertificate)?;
254            builder
255                .set_certificate(&leaf_cert)
256                .map_err(SslConnectorError::SetLeafCertificate)?;
257            for cert in chain {
258                builder
259                    .add_extra_chain_cert(cert)
260                    .map_err(SslConnectorError::AppendCertificate)?;
261            }
262
263            let pkey = PKey::private_key_from_pem(pem).map_err(SslConnectorError::DeserializePrivateKey)?;
264            builder
265                .set_private_key(&pkey)
266                .map_err(SslConnectorError::SetPrivateKey)?;
267        }
268
269        if let Some(ders) = root_certs {
270            for der in ders {
271                let cert = X509::from_der(der).map_err(SslConnectorError::DeserializeRootCertificate)?;
272                builder
273                    .cert_store_mut()
274                    .add_cert(cert)
275                    .map_err(SslConnectorError::AddRootCertificate)?;
276            }
277        }
278
279        Ok(builder)
280    }
281}