Line data Source code
1 : pub mod client_config;
2 : pub mod postgres_rustls;
3 : pub mod server_config;
4 :
5 : use anyhow::Context;
6 : use rustls::pki_types::CertificateDer;
7 : use sha2::{Digest, Sha256};
8 : use tracing::{error, info};
9 : use x509_parser::oid_registry;
10 :
11 : /// <https://github.com/postgres/postgres/blob/ca481d3c9ab7bf69ff0c8d71ad3951d407f6a33c/src/include/libpq/pqcomm.h#L159>
12 : pub const PG_ALPN_PROTOCOL: &[u8] = b"postgresql";
13 :
14 : /// Channel binding parameter
15 : ///
16 : /// <https://www.rfc-editor.org/rfc/rfc5929#section-4>
17 : /// Description: The hash of the TLS server's certificate as it
18 : /// appears, octet for octet, in the server's Certificate message. Note
19 : /// that the Certificate message contains a certificate_list, in which
20 : /// the first element is the server's certificate.
21 : ///
22 : /// The hash function is to be selected as follows:
23 : ///
24 : /// * if the certificate's signatureAlgorithm uses a single hash
25 : /// function, and that hash function is either MD5 or SHA-1, then use SHA-256;
26 : ///
27 : /// * if the certificate's signatureAlgorithm uses a single hash
28 : /// function and that hash function neither MD5 nor SHA-1, then use
29 : /// the hash function associated with the certificate's
30 : /// signatureAlgorithm;
31 : ///
32 : /// * if the certificate's signatureAlgorithm uses no hash functions or
33 : /// uses multiple hash functions, then this channel binding type's
34 : /// channel bindings are undefined at this time (updates to is channel
35 : /// binding type may occur to address this issue if it ever arises).
36 : #[derive(Debug, Clone, Copy)]
37 : pub enum TlsServerEndPoint {
38 : Sha256([u8; 32]),
39 : Undefined,
40 : }
41 :
42 : impl TlsServerEndPoint {
43 33 : pub fn new(cert: &CertificateDer<'_>) -> anyhow::Result<Self> {
44 33 : let sha256_oids = [
45 33 : // I'm explicitly not adding MD5 or SHA1 here... They're bad.
46 33 : oid_registry::OID_SIG_ECDSA_WITH_SHA256,
47 33 : oid_registry::OID_PKCS1_SHA256WITHRSA,
48 33 : ];
49 :
50 33 : let pem = x509_parser::parse_x509_certificate(cert)
51 33 : .context("Failed to parse PEM object from cerficiate")?
52 : .1;
53 :
54 33 : info!(subject = %pem.subject, "parsing TLS certificate");
55 :
56 33 : let reg = oid_registry::OidRegistry::default().with_all_crypto();
57 33 : let oid = pem.signature_algorithm.oid();
58 33 : let alg = reg.get(oid);
59 33 : if sha256_oids.contains(oid) {
60 33 : let tls_server_end_point: [u8; 32] = Sha256::new().chain_update(cert).finalize().into();
61 33 : info!(subject = %pem.subject, signature_algorithm = alg.map(|a| a.description()), tls_server_end_point = %base64::encode(tls_server_end_point), "determined channel binding");
62 33 : Ok(Self::Sha256(tls_server_end_point))
63 : } else {
64 0 : error!(subject = %pem.subject, signature_algorithm = alg.map(|a| a.description()), "unknown channel binding");
65 0 : Ok(Self::Undefined)
66 : }
67 33 : }
68 :
69 16 : pub fn supported(&self) -> bool {
70 16 : !matches!(self, TlsServerEndPoint::Undefined)
71 16 : }
72 : }
|