1#![warn(clippy::all)]
19
20use std::fs::File;
21use std::io::BufReader;
22use std::path::Path;
23
24use log::warn;
25pub use no_debug::{Ellipses, NoDebug, WithTypeInfo};
26use pingora_error::{Error, ErrorType, OrErr, Result};
27
28pub use rustls::server::danger::{ClientCertVerified, ClientCertVerifier};
29pub use rustls::server::{ClientCertVerifierBuilder, WebPkiClientVerifier};
30pub use rustls::{
31 client::WebPkiServerVerifier, version, CertificateError, ClientConfig, DigitallySignedStruct,
32 Error as RusTlsError, KeyLogFile, RootCertStore, ServerConfig, SignatureScheme, Stream,
33};
34pub use rustls_native_certs::load_native_certs;
35use rustls_pemfile::Item;
36pub use rustls_pki_types::{CertificateDer, PrivateKeyDer, ServerName, UnixTime};
37pub use tokio_rustls::client::TlsStream as ClientTlsStream;
38pub use tokio_rustls::server::TlsStream as ServerTlsStream;
39pub use tokio_rustls::{Accept, Connect, TlsAcceptor, TlsConnector, TlsStream};
40
41pub use rustls::client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier};
43
44fn load_file<P>(path: P) -> Result<BufReader<File>>
47where
48 P: AsRef<Path>,
49{
50 File::open(path)
51 .or_err(ErrorType::FileReadError, "Failed to load file")
52 .map(BufReader::new)
53}
54
55fn load_pem_file<P>(path: P) -> Result<Vec<Item>>
57where
58 P: AsRef<Path>,
59{
60 rustls_pemfile::read_all(&mut load_file(path)?)
61 .map(|item_res| {
62 item_res.or_err(
63 ErrorType::InvalidCert,
64 "Certificate in pem file could not be read",
65 )
66 })
67 .collect()
68}
69
70pub fn load_ca_file_into_store<P>(path: P, cert_store: &mut RootCertStore) -> Result<()>
73where
74 P: AsRef<Path>,
75{
76 for pem_item in load_pem_file(path)? {
77 let Item::X509Certificate(content) = pem_item else {
79 return Error::e_explain(
80 ErrorType::InvalidCert,
81 "Pem file contains un-loadable certificate type",
82 );
83 };
84 cert_store.add(content).or_err(
85 ErrorType::InvalidCert,
86 "Failed to load X509 certificate into root store",
87 )?;
88 }
89
90 Ok(())
91}
92
93pub fn load_platform_certs_incl_env_into_store(ca_certs: &mut RootCertStore) -> Result<()> {
95 for cert in load_native_certs()
97 .or_err(ErrorType::InvalidCert, "Failed to load native certificates")?
98 .into_iter()
99 {
100 ca_certs.add(cert).or_err(
101 ErrorType::InvalidCert,
102 "Failed to load native certificate into root store",
103 )?;
104 }
105
106 Ok(())
107}
108
109pub fn load_certs_and_key_files<'a>(
111 cert: &str,
112 key: &str,
113) -> Result<Option<(Vec<CertificateDer<'a>>, PrivateKeyDer<'a>)>> {
114 let certs_file = load_pem_file(cert)?;
115 let key_file = load_pem_file(key)?;
116
117 let certs = certs_file
118 .into_iter()
119 .filter_map(|item| {
120 if let Item::X509Certificate(cert) = item {
121 Some(cert)
122 } else {
123 None
124 }
125 })
126 .collect::<Vec<_>>();
127
128 let private_key_opt = key_file
131 .into_iter()
132 .filter_map(|key_item| match key_item {
133 Item::Pkcs1Key(key) => Some(PrivateKeyDer::from(key)),
134 Item::Pkcs8Key(key) => Some(PrivateKeyDer::from(key)),
135 Item::Sec1Key(key) => Some(PrivateKeyDer::from(key)),
136 _ => None,
137 })
138 .next();
139
140 if let (Some(private_key), false) = (private_key_opt, certs.is_empty()) {
141 Ok(Some((certs, private_key)))
142 } else {
143 Ok(None)
144 }
145}
146
147pub fn load_pem_file_ca(path: &String) -> Result<Vec<u8>> {
149 let mut reader = load_file(path)?;
150 let cas_file_items = rustls_pemfile::certs(&mut reader)
151 .map(|item_res| {
152 item_res.or_err(
153 ErrorType::InvalidCert,
154 "Failed to load certificate from file",
155 )
156 })
157 .collect::<Result<Vec<_>>>()?;
158
159 Ok(cas_file_items
160 .first()
161 .map(|ca| ca.to_vec())
162 .unwrap_or_default())
163}
164
165pub fn load_pem_file_private_key(path: &String) -> Result<Vec<u8>> {
166 Ok(rustls_pemfile::private_key(&mut load_file(path)?)
167 .or_err(
168 ErrorType::InvalidCert,
169 "Failed to load private key from file",
170 )?
171 .map(|key| key.secret_der().to_vec())
172 .unwrap_or_default())
173}
174
175pub fn hash_certificate(cert: &CertificateDer) -> Vec<u8> {
176 let hash = ring::digest::digest(&ring::digest::SHA256, cert.as_ref());
177 hash.as_ref().to_vec()
178}