LCOV - code coverage report
Current view: top level - proxy/src/tls - mod.rs (source / functions) Coverage Total Hit
Test: 07bee600374ccd486c69370d0972d9035964fe68.info Lines: 90.9 % 22 20
Test Date: 2025-02-20 13:11:02 Functions: 33.3 % 6 2

            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              : }
        

Generated by: LCOV version 2.1-beta