1use openssl::pkcs12::Pkcs12;
13use openssl::pkey::PKey;
14use openssl::ssl::{SslConnector, SslMethod, SslVerifyMode};
15use openssl::stack::Stack;
16use openssl::x509::X509;
17use postgres_openssl::MakeTlsConnector;
18use tokio_postgres::config::SslMode;
19
20macro_rules! bail_generic {
21 ($fmt:expr, $($arg:tt)*) => {
22 return Err(TlsError::Generic(anyhow::anyhow!($fmt, $($arg)*)))
23 };
24 ($err:expr $(,)?) => {
25 return Err(TlsError::Generic(anyhow::anyhow!($err)))
26 };
27}
28
29#[derive(Debug, thiserror::Error)]
31pub enum TlsError {
32 #[error(transparent)]
34 Generic(#[from] anyhow::Error),
35 #[error(transparent)]
37 OpenSsl(#[from] openssl::error::ErrorStack),
38}
39
40pub fn make_tls(config: &tokio_postgres::Config) -> Result<MakeTlsConnector, TlsError> {
42 let mut builder = SslConnector::builder(SslMethod::tls_client())?;
43 let (verify_mode, verify_hostname) = match config.get_ssl_mode() {
49 SslMode::Disable | SslMode::Prefer => (SslVerifyMode::NONE, false),
50 SslMode::Require => match config.get_ssl_root_cert() {
51 Some(_) => (SslVerifyMode::PEER, false),
57 None => (SslVerifyMode::NONE, false),
58 },
59 SslMode::VerifyCa => (SslVerifyMode::PEER, false),
60 SslMode::VerifyFull => (SslVerifyMode::PEER, true),
61 _ => panic!("unexpected sslmode {:?}", config.get_ssl_mode()),
62 };
63
64 builder.set_verify(verify_mode);
66
67 match (config.get_ssl_cert(), config.get_ssl_key()) {
69 (Some(ssl_cert), Some(ssl_key)) => {
70 builder.set_certificate(&*X509::from_pem(ssl_cert)?)?;
71 builder.set_private_key(&*PKey::private_key_from_pem(ssl_key)?)?;
72 }
73 (None, Some(_)) => {
74 bail_generic!("must provide both sslcert and sslkey, but only provided sslkey")
75 }
76 (Some(_), None) => {
77 bail_generic!("must provide both sslcert and sslkey, but only provided sslcert")
78 }
79 _ => {}
80 }
81 if let Some(ssl_root_cert) = config.get_ssl_root_cert() {
82 builder
83 .cert_store_mut()
84 .add_cert(X509::from_pem(ssl_root_cert)?)?;
85 }
86
87 let mut tls_connector = MakeTlsConnector::new(builder.build());
88
89 match (verify_mode, verify_hostname) {
91 (SslVerifyMode::PEER, false) => tls_connector.set_callback(|connect, _| {
92 connect.set_verify_hostname(false);
93 Ok(())
94 }),
95 _ => {}
96 }
97
98 Ok(tls_connector)
99}
100
101pub struct Pkcs12Archive {
102 pub der: Vec<u8>,
103 pub pass: String,
104}
105
106pub fn pkcs12der_from_pem(
108 key: &[u8],
109 cert: &[u8],
110) -> Result<Pkcs12Archive, openssl::error::ErrorStack> {
111 let mut buf = Vec::new();
112 buf.extend(key);
113 buf.push(b'\n');
114 buf.extend(cert);
115 let pem = buf.as_slice();
116 let pkey = PKey::private_key_from_pem(pem)?;
117 let mut certs = Stack::new()?;
118
119 let mut cert_iter = X509::stack_from_pem(pem)?.into_iter();
129 let cert = match cert_iter.next() {
130 Some(cert) => cert,
131 None => X509::from_pem(pem)?,
132 };
133 for cert in cert_iter {
134 certs.push(cert)?;
135 }
136 let pass = String::new();
140 let friendly_name = "";
141 let der = Pkcs12::builder()
142 .name(friendly_name)
143 .pkey(&pkey)
144 .cert(&cert)
145 .ca(certs)
146 .build2(&pass)?
147 .to_der()?;
148 Ok(Pkcs12Archive { der, pass })
149}