Skip to main content

kube_client/client/
tls.rs

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