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 ($err:expr $(,)?) => {
22 return Err(TlsError::Generic(anyhow::anyhow!($err)))
23 };
24}
25
26#[derive(Debug, thiserror::Error)]
28pub enum TlsError {
29 #[error(transparent)]
31 Generic(#[from] anyhow::Error),
32 #[error(transparent)]
34 OpenSsl(#[from] openssl::error::ErrorStack),
35}
36
37pub fn make_tls(config: &tokio_postgres::Config) -> Result<MakeTlsConnector, TlsError> {
39 let mut builder = SslConnector::builder(SslMethod::tls_client())?;
40 let (verify_mode, verify_hostname) = match config.get_ssl_mode() {
46 SslMode::Disable | SslMode::Prefer => (SslVerifyMode::NONE, false),
47 SslMode::Require => match config.get_ssl_root_cert() {
48 Some(_) => (SslVerifyMode::PEER, false),
54 None => (SslVerifyMode::NONE, false),
55 },
56 SslMode::VerifyCa => (SslVerifyMode::PEER, false),
57 SslMode::VerifyFull => (SslVerifyMode::PEER, true),
58 _ => panic!("unexpected sslmode {:?}", config.get_ssl_mode()),
59 };
60
61 builder.set_verify(verify_mode);
63
64 match (config.get_ssl_cert(), config.get_ssl_key()) {
66 (Some(ssl_cert), Some(ssl_key)) => {
67 builder.set_certificate(&*X509::from_pem(ssl_cert)?)?;
68 builder.set_private_key(&*PKey::private_key_from_pem(ssl_key)?)?;
69 }
70 (None, Some(_)) => {
71 bail_generic!("must provide both sslcert and sslkey, but only provided sslkey")
72 }
73 (Some(_), None) => {
74 bail_generic!("must provide both sslcert and sslkey, but only provided sslcert")
75 }
76 _ => {}
77 }
78 if let Some(ssl_root_cert) = config.get_ssl_root_cert() {
79 for cert in X509::stack_from_pem(ssl_root_cert)? {
80 builder.cert_store_mut().add_cert(cert)?;
81 }
82 }
83
84 let mut tls_connector = MakeTlsConnector::new(builder.build());
85
86 match (verify_mode, verify_hostname) {
88 (SslVerifyMode::PEER, false) => tls_connector.set_callback(|connect, _| {
89 connect.set_verify_hostname(false);
90 Ok(())
91 }),
92 _ => {}
93 }
94
95 Ok(tls_connector)
96}
97
98pub struct Pkcs12Archive {
99 pub der: Vec<u8>,
100 pub pass: String,
101}
102
103pub fn pkcs12der_from_pem(
105 key: &[u8],
106 cert: &[u8],
107) -> Result<Pkcs12Archive, openssl::error::ErrorStack> {
108 let mut buf = Vec::new();
109 buf.extend(key);
110 buf.push(b'\n');
111 buf.extend(cert);
112 let pem = buf.as_slice();
113 let pkey = PKey::private_key_from_pem(pem)?;
114 let mut certs = Stack::new()?;
115
116 let mut cert_iter = X509::stack_from_pem(pem)?.into_iter();
126 let cert = match cert_iter.next() {
127 Some(cert) => cert,
128 None => X509::from_pem(pem)?,
129 };
130 for cert in cert_iter {
131 certs.push(cert)?;
132 }
133 let pass = String::new();
137 let friendly_name = "";
138 let der = Pkcs12::builder()
139 .name(friendly_name)
140 .pkey(&pkey)
141 .cert(&cert)
142 .ca(certs)
143 .build2(&pass)?
144 .to_der()?;
145 Ok(Pkcs12Archive { der, pass })
146}