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] std::io::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_pemfile::Item;
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        for item in rustls_pemfile::read_all(&mut reader)
107            .collect::<Result<Vec<_>, _>>()
108            .map_err(Error::InvalidIdentityPem)?
109        {
110            match item {
111                Item::X509Certificate(cert) => cert_chain.push(cert),
112                Item::Pkcs8Key(key) => pkcs8_key = Some(PrivateKeyDer::Pkcs8(key)),
113                Item::Pkcs1Key(key) => pkcs1_key = Some(PrivateKeyDer::from(key)),
114                Item::Sec1Key(key) => sec1_key = Some(PrivateKeyDer::from(key)),
115                _ => return Err(Error::UnknownPrivateKeyFormat),
116            }
117        }
118
119        let private_key = pkcs8_key
120            .or(pkcs1_key)
121            .or(sec1_key)
122            .ok_or(Error::MissingPrivateKey)?;
123        if cert_chain.is_empty() {
124            return Err(Error::MissingCertificate);
125        }
126        Ok((cert_chain, private_key))
127    }
128
129    #[derive(Debug)]
130    struct NoCertificateVerification {}
131
132    impl ServerCertVerifier for NoCertificateVerification {
133        fn verify_server_cert(
134            &self,
135            _end_entity: &CertificateDer,
136            _intermediates: &[CertificateDer],
137            _server_name: &ServerName,
138            _ocsp_response: &[u8],
139            _now: rustls::pki_types::UnixTime,
140        ) -> Result<ServerCertVerified, rustls::Error> {
141            tracing::warn!("Server cert bypassed");
142            Ok(ServerCertVerified::assertion())
143        }
144
145        fn verify_tls13_signature(
146            &self,
147            _message: &[u8],
148            _cert: &CertificateDer,
149            _dss: &DigitallySignedStruct,
150        ) -> Result<HandshakeSignatureValid, rustls::Error> {
151            Ok(HandshakeSignatureValid::assertion())
152        }
153
154        fn verify_tls12_signature(
155            &self,
156            _message: &[u8],
157            _cert: &CertificateDer,
158            _dss: &DigitallySignedStruct,
159        ) -> Result<HandshakeSignatureValid, rustls::Error> {
160            Ok(HandshakeSignatureValid::assertion())
161        }
162
163        fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
164            use rustls::SignatureScheme;
165            vec![
166                SignatureScheme::RSA_PKCS1_SHA1,
167                SignatureScheme::ECDSA_SHA1_Legacy,
168                SignatureScheme::RSA_PKCS1_SHA256,
169                SignatureScheme::ECDSA_NISTP256_SHA256,
170                SignatureScheme::RSA_PKCS1_SHA384,
171                SignatureScheme::ECDSA_NISTP384_SHA384,
172                SignatureScheme::RSA_PKCS1_SHA512,
173                SignatureScheme::ECDSA_NISTP521_SHA512,
174                SignatureScheme::RSA_PSS_SHA256,
175                SignatureScheme::RSA_PSS_SHA384,
176                SignatureScheme::RSA_PSS_SHA512,
177                SignatureScheme::ED25519,
178                SignatureScheme::ED448,
179            ]
180        }
181    }
182}
183
184#[cfg(feature = "openssl-tls")]
185pub mod openssl_tls {
186    use openssl::{
187        pkey::PKey,
188        ssl::{SslConnector, SslConnectorBuilder, SslMethod},
189        x509::X509,
190    };
191    use thiserror::Error;
192
193    /// Errors from OpenSSL TLS
194    #[derive(Debug, Error)]
195    pub enum Error {
196        /// Failed to create OpenSSL HTTPS connector
197        #[error("failed to create OpenSSL HTTPS connector: {0}")]
198        CreateHttpsConnector(#[source] openssl::error::ErrorStack),
199
200        /// Failed to create OpenSSL SSL connector
201        #[error("failed to create OpenSSL SSL connector: {0}")]
202        CreateSslConnector(#[source] SslConnectorError),
203    }
204
205    /// Errors from creating a `SslConnectorBuilder`
206    #[derive(Debug, Error)]
207    pub enum SslConnectorError {
208        /// Failed to build SslConnectorBuilder
209        #[error("failed to build SslConnectorBuilder: {0}")]
210        CreateBuilder(#[source] openssl::error::ErrorStack),
211
212        /// Failed to deserialize PEM-encoded chain of certificates
213        #[error("failed to deserialize PEM-encoded chain of certificates: {0}")]
214        DeserializeCertificateChain(#[source] openssl::error::ErrorStack),
215
216        /// Failed to deserialize PEM-encoded private key
217        #[error("failed to deserialize PEM-encoded private key: {0}")]
218        DeserializePrivateKey(#[source] openssl::error::ErrorStack),
219
220        /// Failed to set private key
221        #[error("failed to set private key: {0}")]
222        SetPrivateKey(#[source] openssl::error::ErrorStack),
223
224        /// Failed to get a leaf certificate, the certificate chain is empty
225        #[error("failed to get a leaf certificate, the certificate chain is empty")]
226        GetLeafCertificate,
227
228        /// Failed to set the leaf certificate
229        #[error("failed to set the leaf certificate: {0}")]
230        SetLeafCertificate(#[source] openssl::error::ErrorStack),
231
232        /// Failed to append a certificate to the chain
233        #[error("failed to append a certificate to the chain: {0}")]
234        AppendCertificate(#[source] openssl::error::ErrorStack),
235
236        /// Failed to deserialize DER-encoded root certificate
237        #[error("failed to deserialize DER-encoded root certificate: {0}")]
238        DeserializeRootCertificate(#[source] openssl::error::ErrorStack),
239
240        /// Failed to add a root certificate
241        #[error("failed to add a root certificate: {0}")]
242        AddRootCertificate(#[source] openssl::error::ErrorStack),
243    }
244
245    /// Create `openssl::ssl::SslConnectorBuilder` required for `hyper_openssl::HttpsConnector`.
246    pub fn ssl_connector_builder(
247        identity_pem: Option<&Vec<u8>>,
248        root_certs: Option<&Vec<Vec<u8>>>,
249    ) -> Result<SslConnectorBuilder, SslConnectorError> {
250        let mut builder =
251            SslConnector::builder(SslMethod::tls()).map_err(SslConnectorError::CreateBuilder)?;
252        if let Some(pem) = identity_pem {
253            let mut chain = X509::stack_from_pem(pem)
254                .map_err(SslConnectorError::DeserializeCertificateChain)?
255                .into_iter();
256            let leaf_cert = chain.next().ok_or(SslConnectorError::GetLeafCertificate)?;
257            builder
258                .set_certificate(&leaf_cert)
259                .map_err(SslConnectorError::SetLeafCertificate)?;
260            for cert in chain {
261                builder
262                    .add_extra_chain_cert(cert)
263                    .map_err(SslConnectorError::AppendCertificate)?;
264            }
265
266            let pkey = PKey::private_key_from_pem(pem).map_err(SslConnectorError::DeserializePrivateKey)?;
267            builder
268                .set_private_key(&pkey)
269                .map_err(SslConnectorError::SetPrivateKey)?;
270        }
271
272        if let Some(ders) = root_certs {
273            for der in ders {
274                let cert = X509::from_der(der).map_err(SslConnectorError::DeserializeRootCertificate)?;
275                builder
276                    .cert_store_mut()
277                    .add_cert(cert)
278                    .map_err(SslConnectorError::AddRootCertificate)?;
279            }
280        }
281
282        Ok(builder)
283    }
284}