postgres_rustls

Rustls-based library for postgres.
git clone https://git.philomathiclife.com/repos/postgres_rustls
Log | Files | Refs | README

lib.rs (28014B)


      1 //! [![git]](https://git.philomathiclife.com/postgres_rustls/log.html) [![crates-io]](https://crates.io/crates/postgres_rustls) [![docs-rs]](crate)
      2 //!
      3 //! [git]: https://git.philomathiclife.com/git_badge.svg
      4 //! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
      5 //! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs
      6 //!
      7 //! `postgres_rustls` is a library that adds TLS support to [`tokio_postgres`] using [`tokio_rustls`].
      8 #![cfg_attr(docsrs, feature(doc_cfg))]
      9 #![expect(
     10     clippy::multiple_crate_versions,
     11     reason = "dependencies haven't updated to newest crates"
     12 )]
     13 #![expect(
     14     clippy::doc_paragraphs_missing_punctuation,
     15     reason = "false positive for crate documentation having image links"
     16 )]
     17 #![cfg_attr(test, expect(dead_code_pub_in_binary, reason = "ignore for tests"))]
     18 use core::{
     19     pin::Pin,
     20     task::{Context, Poll},
     21 };
     22 use sha2::{
     23     Sha224, Sha256, Sha384, Sha512,
     24     digest::{Digest as _, OutputSizeUser, array::Array},
     25 };
     26 use std::io::{self, IoSlice};
     27 pub use tokio;
     28 use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
     29 pub use tokio_postgres;
     30 #[cfg(feature = "runtime")]
     31 use tokio_postgres::tls::MakeTlsConnect;
     32 use tokio_postgres::tls::{ChannelBinding, TlsConnect as PgTlsConnect, TlsStream as PgTlsStream};
     33 pub use tokio_rustls;
     34 use tokio_rustls::{
     35     Connect,
     36     client::TlsStream as RustlsStream,
     37     rustls::{
     38         ClientConfig,
     39         pki_types::{InvalidDnsNameError, ServerName},
     40     },
     41 };
     42 /// Unit tests.
     43 #[cfg(test)]
     44 mod tests;
     45 /// Hash for the leaf certificate provided by the PostgreSQL server.
     46 #[expect(clippy::doc_markdown, reason = "PostgreSQL is correct")]
     47 enum Hash {
     48     /// SHA-256 hash.
     49     Sha256(Array<u8, <Sha256 as OutputSizeUser>::OutputSize>),
     50     /// SHA-384 hash.
     51     Sha384(Array<u8, <Sha384 as OutputSizeUser>::OutputSize>),
     52     /// SHA-512 hash.
     53     Sha512(Array<u8, <Sha512 as OutputSizeUser>::OutputSize>),
     54     /// SHA-224 hash.
     55     Sha224(Array<u8, <Sha224 as OutputSizeUser>::OutputSize>),
     56 }
     57 impl From<Hash> for Vec<u8> {
     58     #[inline]
     59     fn from(value: Hash) -> Self {
     60         match value {
     61             Hash::Sha256(hash) => hash.to_vec(),
     62             Hash::Sha384(hash) => hash.to_vec(),
     63             Hash::Sha512(hash) => hash.to_vec(),
     64             Hash::Sha224(hash) => hash.to_vec(),
     65         }
     66     }
     67 }
     68 impl Hash {
     69     /// Parses `cert` as a DER-encoded X.509 v3 certifcate extracting the signature algorithm and using it to hash
     70     /// `cert` (based on the underlying hash algorithm of the signature algorithm).
     71     ///
     72     /// Note this will return `Some` for certain invalid payloads; however when the payload is a valid
     73     /// DER-encoded X.509 v3 certificate, then it is guaranteed to produce the correct hash. The idea is that
     74     /// in the event the leaf certificate is invalid, then it will be rejected by `rustls` anyway thus what
     75     /// this returns won't matter. We do this for simplicity and performance reasons since it allows us to
     76     /// avoid parsing the entire certificate and instead _only_ care about the signature algorithm.
     77     ///
     78     /// The only signature algorithms supported are the following:
     79     ///
     80     /// * id-Ed25519
     81     /// * ecdsa-with-SHA256
     82     /// * sha256WithRSAEncryption
     83     /// * ecdsa-with-SHA384
     84     /// * sha384WithRSAEncryption
     85     /// * ecdsa-with-SHA512
     86     /// * sha512WithRSAEncryption
     87     /// * ecdsa-with-SHA224
     88     /// * sha224WithRSAEncryption
     89     /// * dsa-with-SHA256
     90     /// * dsa-with-SHA224
     91     /// * dsa-with-SHA1
     92     /// * sha1WithRSAEncryption
     93     ///
     94     /// More may be added; but for ones that require additional dependencies, they will be hidden behind a feature.
     95     /// Additionally new ones must be supported by PostgreSQL, `tokio-postgres`, and `rustls`.
     96     //
     97     // [RFC 5280 § 4.1](https://www.rfc-editor.org/rfc/rfc5280#section-4.1) describes the ASN.1 format
     98     // of an X.509 v3 Certificate:
     99     //
    100     // ```asn
    101     // Certificate  ::=  SEQUENCE  {
    102     //   tbsCertificate       TBSCertificate,
    103     //   signatureAlgorithm   AlgorithmIdentifier,
    104     //   signatureValue       BIT STRING  }
    105     //
    106     // TBSCertificate  ::=  SEQUENCE  { … }
    107     //
    108     // AlgorithmIdentifier  ::=  SEQUENCE  {
    109     //   algorithm               OBJECT IDENTIFIER,
    110     //   parameters              ANY DEFINED BY algorithm OPTIONAL  }
    111     // ```
    112     //
    113     // [ITU-T X.690](https://www.itu.int/rec/T-REC-X.690-202102-I/en)
    114     // describes how DER-encoding works.
    115     #[expect(
    116         clippy::arithmetic_side_effects,
    117         clippy::big_endian_bytes,
    118         clippy::indexing_slicing,
    119         reason = "comments justify their correctness"
    120     )]
    121     #[expect(clippy::too_many_lines, reason = "inflated by the const slices")]
    122     #[expect(clippy::doc_markdown, reason = "PostgreSQL is correct")]
    123     fn from_der_cert(cert: &[u8]) -> Option<Self> {
    124         /// [RFC 8410 § 9](https://www.rfc-editor.org/rfc/rfc8410#section-9)
    125         /// defines id-Ed25519 as 1.3.101.112. This is encoded as below per X.690 § 8.19.
    126         const ED25519: &[u8] = [43, 101, 112].as_slice();
    127         /// [RFC 5912 § 6](https://www.rfc-editor.org/rfc/rfc5912.html#section-6)
    128         /// defines ecdsa-with-SHA256 as 1.2.840.10045.4.3.2. This is encoded as
    129         /// below per X.690 § 8.19.
    130         const ECDSA_SHA256: &[u8] = [42, 134, 72, 206, 61, 4, 3, 2].as_slice();
    131         /// [RFC 8017 § Appendix C](https://www.rfc-editor.org/rfc/rfc8017#appendix-C)
    132         /// defines sha256WithRSAEncryption as 1.2.840.113549.1.1.11. This is encoded as
    133         /// below per X.690 § 8.19.
    134         const RSA_SHA256: &[u8] = [42, 134, 72, 134, 247, 13, 1, 1, 11].as_slice();
    135         /// [RFC 5912 § 6](https://www.rfc-editor.org/rfc/rfc5912.html#section-6)
    136         /// defines dsa-with-SHA256 as 2.16.840.1.101.3.4.3.2. This is encoded as
    137         /// below per X.690 § 8.19.
    138         const DSA_SHA256: &[u8] = [96, 134, 72, 1, 101, 3, 4, 3, 2].as_slice();
    139         /// [RFC 5912 § 6](https://www.rfc-editor.org/rfc/rfc5912.html#section-6)
    140         /// defines dsa-with-SHA1 as 1.2.840.10040.4.3. This is encoded as
    141         /// below per X.690 § 8.19.
    142         const DSA_SHA1: &[u8] = [42, 134, 72, 206, 56, 4, 3].as_slice();
    143         /// [RFC 8017 § Appendix C](https://www.rfc-editor.org/rfc/rfc8017#appendix-C)
    144         /// defines sha1WithRSAEncryption as 1.2.840.113549.1.1.5. This is encoded as
    145         /// below per X.690 § 8.19.
    146         const RSA_SHA1: &[u8] = [42, 134, 72, 134, 247, 13, 1, 1, 5].as_slice();
    147         /// [RFC 5912 § 6](https://www.rfc-editor.org/rfc/rfc5912.html#section-6)
    148         /// defines ecdsa-with-SHA384 as 1.2.840.10045.4.3.3. This is encoded as
    149         /// below per X.690 § 8.19.
    150         const ECDSA_SHA384: &[u8] = [42, 134, 72, 206, 61, 4, 3, 3].as_slice();
    151         /// [RFC 8017 § Appendix C](https://www.rfc-editor.org/rfc/rfc8017#appendix-C)
    152         /// defines sha384WithRSAEncryption as 1.2.840.113549.1.1.12. This is encoded as
    153         /// below per X.690 § 8.19.
    154         const RSA_SHA384: &[u8] = [42, 134, 72, 134, 247, 13, 1, 1, 12].as_slice();
    155         /// [RFC 5912 § 6](https://www.rfc-editor.org/rfc/rfc5912.html#section-6)
    156         /// defines ecdsa-with-SHA512 as 1.2.840.10045.4.3.4. This is encoded as
    157         /// below per X.690 § 8.19.
    158         const ECDSA_SHA512: &[u8] = [42, 134, 72, 206, 61, 4, 3, 4].as_slice();
    159         /// [RFC 8017 § Appendix C](https://www.rfc-editor.org/rfc/rfc8017#appendix-C)
    160         /// defines sha512WithRSAEncryption as 1.2.840.113549.1.1.13. This is encoded as
    161         /// below per X.690 § 8.19.
    162         const RSA_SHA512: &[u8] = [42, 134, 72, 134, 247, 13, 1, 1, 13].as_slice();
    163         /// [RFC 5912 § 6](https://www.rfc-editor.org/rfc/rfc5912.html#section-6)
    164         /// defines ecdsa-with-SHA224 as 1.2.840.10045.4.3.1. This is encoded as
    165         /// below per X.690 § 8.19.
    166         const ECDSA_SHA224: &[u8] = [42, 134, 72, 206, 61, 4, 3, 1].as_slice();
    167         /// [RFC 8017 § Appendix C](https://www.rfc-editor.org/rfc/rfc8017#appendix-C)
    168         /// defines sha224WithRSAEncryption as 1.2.840.113549.1.1.14. This is encoded as
    169         /// below per X.690 § 8.19.
    170         const RSA_SHA224: &[u8] = [42, 134, 72, 134, 247, 13, 1, 1, 14].as_slice();
    171         /// [RFC 5912 § 6](https://www.rfc-editor.org/rfc/rfc5912.html#section-6)
    172         /// defines dsa-with-SHA224 as 2.16.840.1.101.3.4.3.1. This is encoded as
    173         /// below per X.690 § 8.19.
    174         const DSA_SHA224: &[u8] = [96, 134, 72, 1, 101, 3, 4, 3, 1].as_slice();
    175         // The first octet represents a constructed sequence (i.e., 0x30) and the second octet represents
    176         // the (possibly encoded) length of the remaining payload.
    177         cert.split_at_checked(2).and_then(|(cert_seq, cert_rem)| {
    178             // This won't `panic` since `cert_seq.len() == 2`.
    179             // This represents the (possibly encoded) length.
    180             //
    181             // We don't care about the actual length of the payload. We only care about the number of bytes
    182             // we need to skip until the (possibly encoded) length of the constructed sequence of
    183             // tbsCertificate.
    184             match cert_seq[1] {
    185                 // The length of the payload is represented with this byte; thus we only need to skip
    186                 // the constructed sequence byte (i.e., 0x30) of tbsCertificate.
    187                 ..=127 => Some(1),
    188                 // The length of the payload is invalid since DER-encoded lengths must use the minimum
    189                 // number of bytes possible. The high bit is set iff one or more octets are needed to encode
    190                 // the actual length. The number of octets is represented by the remaining bits; thus this
    191                 // means there are 0 bytes to encode the length, but then it should have been encoded as
    192                 // `0` and not `128`.
    193                 //
    194                 // 255 is not allowed to be used per § 8.1.3.5.
    195                 128 | 255 => None,
    196                 // The remaining bits represent the number of bytes that it takes to encode the length;
    197                 // thus we subtract 128 and add 1 to account for the constructed sequence byte (i.e., 0x30)
    198                 // of tbsCertificate. This is the same as just subtracting 127.
    199                 //
    200                 // Underflow clearly cannot occur since `len` is at least 129.
    201                 len @ 129.. => Some(usize::from(len) - 127),
    202             }
    203             .and_then(|skip| {
    204                 cert_rem.get(skip..).and_then(|tbs_rem_with_len| {
    205                     // Remaining payload starting from the (possibly encoded) length of tbsCertificate.
    206                     tbs_rem_with_len
    207                         // Extract the (possibly encoded) length of tbsCertificate.
    208                         .split_first()
    209                         .and_then(|(tbs_enc_len, tbs_rem)| {
    210                             // We need to extract how many bytes make up tbsCertificate that way
    211                             // we can skip it and get to the (possibly encoded) length of
    212                             // signatureAlgorithm.
    213                             match *tbs_enc_len {
    214                                 // tbsCertificate is encoded in `len` bytes. We need to skip that many
    215                                 // bytes taking into account the constructed sequence byte (i.e., 0x30)
    216                                 // of signatureAlgorithm.
    217                                 //
    218                                 // This won't overflow since `len` is at most 127; thus this maxes at 128
    219                                 // which is <= `usize::MAX`.
    220                                 len @ ..=127 => Some(usize::from(len) + 1),
    221                                 // The number of bytes tbsCertificate is encoded in takes 1 byte to encode
    222                                 // We get that one byte since that is how many bytes we need to skip taking
    223                                 // into account the byte and the constructed sequence byte (i.e., 0x30) of
    224                                 // signatureAlgorithm.
    225                                 //
    226                                 // This won't overflow since this maxes at 255 + 2 = 257 <= usize::MAX.
    227                                 129 => tbs_rem.first().map(|len| usize::from(*len) + 2),
    228                                 // The number of bytes tbsCertificate is encoded in takes 2 bytes to encode.
    229                                 // We get the two bytes since that is how many bytes we need to skip.
    230                                 130 => tbs_rem.get(..2).and_then(|enc_len| {
    231                                     let mut big_endian_len = [0; 2];
    232                                     // This won't `panic` since `enc_len.len() == 2`.
    233                                     big_endian_len.copy_from_slice(enc_len);
    234                                     // Multi-byte lengths are encoded in big-endian.
    235                                     u16::from_be_bytes(big_endian_len)
    236                                         // We need to account for the two bytes and the constructed sequence byte
    237                                         // (i.e., 0x30) of signatureAlgorithm.
    238                                         .checked_add(3)
    239                                         // We don't support payloads larger than 65,535 since that is more than
    240                                         // enough for a single certificate.
    241                                         .map(usize::from)
    242                                 }),
    243                                 // We arbitrarily cap the size of payloads we accept to simplify decoding.
    244                                 // If this is more than 130, then the payload is at least 16,777,216 bytes
    245                                 // which is obscenely large for a single certificate. 128 is invalid.
    246                                 _ => None,
    247                             }
    248                             .and_then(|tbs_len| {
    249                                 tbs_rem.get(tbs_len..).and_then(|alg_rem_with_len| {
    250                                     // Remaining payload starting from the (possibly encoded) length of
    251                                     // signatureAlgorithm.
    252                                     alg_rem_with_len
    253                                         // Extract the (possibly encoded) length of signatureAlgorithm.
    254                                         .split_first()
    255                                         .and_then(|(alg_enc_len, alg_rem)| {
    256                                             // We need to extract how many bytes make up signatureAlgorithm that way
    257                                             // we can skip it and get to the (possibly encoded) length of algorithm.
    258                                             match *alg_enc_len {
    259                                                 // The length of the payload is represented with this byte; thus we
    260                                                 // only need to skip the object identifier byte (i.e., 0x06) of
    261                                                 // algorithm.
    262                                                 ..=127 => Some(1),
    263                                                 // The length of the payload is invalid.
    264                                                 128 | 255 => None,
    265                                                 // The remaining bits represents the number of bytes that it takes to
    266                                                 // encode the length; thus we subtract 128 and add 1 to account for
    267                                                 // the object identifier byte (i.e., 0x06) of algorithm.
    268                                                 // This is the same as just subtracting 127.
    269                                                 //
    270                                                 // Underflow clearly cannot occur since `len` is at least 129.
    271                                                 len @ 129.. => Some(usize::from(len) - 127),
    272                                             }
    273                                             .and_then(
    274                                                 |alg_skip| {
    275                                                     alg_rem.get(alg_skip..).and_then(|oid_rem| {
    276                                                         // Remaining payload starting from the (possibly encoded)
    277                                                         // length of algorithm, and we extract the
    278                                                         // (possibly encoded) length of algorithm.
    279                                                         oid_rem.split_first().and_then(
    280                                                             |(oid_enc_len, rem)| {
    281                                                                 // Extract the algorithm.
    282                                                                 // Recall we don't care if the certificate is
    283                                                                 // invalid, and we only support algorithms of
    284                                                                 // length at most 127. As a result, we treat
    285                                                                 // `oid_enc_len` as is.
    286                                                                 rem.get(..usize::from(*oid_enc_len))
    287                                                                     .and_then(|oid| match oid {
    288                                                                         ED25519 | ECDSA_SHA256
    289                                                                         | RSA_SHA256 | DSA_SHA256
    290                                                                         // [RFC 5929 § 4.1](https://www.rfc-editor.org/rfc/rfc5929#section-4.1)
    291                                                                         // mandates that SHA-1 based signatures
    292                                                                         // use SHA-256.
    293                                                                         | DSA_SHA1 | RSA_SHA1 => {
    294                                                                             Some(Self::Sha256(
    295                                                                                 Sha256::digest(
    296                                                                                     cert,
    297                                                                                 ),
    298                                                                             ))
    299                                                                         }
    300                                                                         ECDSA_SHA384
    301                                                                         | RSA_SHA384 => {
    302                                                                             Some(Self::Sha384(
    303                                                                                 Sha384::digest(
    304                                                                                     cert,
    305                                                                                 ),
    306                                                                             ))
    307                                                                         }
    308                                                                         ECDSA_SHA512
    309                                                                         | RSA_SHA512 => {
    310                                                                             Some(Self::Sha512(
    311                                                                                 Sha512::digest(
    312                                                                                     cert,
    313                                                                                 ),
    314                                                                             ))
    315                                                                         }
    316                                                                         ECDSA_SHA224
    317                                                                         | RSA_SHA224
    318                                                                         | DSA_SHA224 => {
    319                                                                             Some(Self::Sha224(
    320                                                                                 Sha224::digest(
    321                                                                                     cert,
    322                                                                                 ),
    323                                                                             ))
    324                                                                         }
    325                                                                         _ => None,
    326                                                                     })
    327                                                             },
    328                                                         )
    329                                                     })
    330                                                 },
    331                                             )
    332                                         })
    333                                 })
    334                             })
    335                         })
    336                 })
    337             })
    338         })
    339     }
    340 }
    341 /// The [`TlsConnector::Stream`] returned from [`TlsConnectorFuture::poll`].
    342 #[derive(Debug)]
    343 pub struct TlsStream<S>(RustlsStream<S>);
    344 impl<S: AsyncRead + AsyncWrite + Unpin> AsyncRead for TlsStream<S> {
    345     #[inline]
    346     fn poll_read(
    347         mut self: Pin<&mut Self>,
    348         cx: &mut Context<'_>,
    349         buf: &mut ReadBuf<'_>,
    350     ) -> Poll<io::Result<()>> {
    351         Pin::new(&mut self.0).poll_read(cx, buf)
    352     }
    353 }
    354 impl<S: AsyncRead + AsyncWrite + Unpin> AsyncWrite for TlsStream<S> {
    355     #[inline]
    356     fn poll_write(
    357         mut self: Pin<&mut Self>,
    358         cx: &mut Context<'_>,
    359         buf: &[u8],
    360     ) -> Poll<Result<usize, io::Error>> {
    361         Pin::new(&mut self.0).poll_write(cx, buf)
    362     }
    363     #[inline]
    364     fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
    365         Pin::new(&mut self.0).poll_flush(cx)
    366     }
    367     #[inline]
    368     fn poll_shutdown(
    369         mut self: Pin<&mut Self>,
    370         cx: &mut Context<'_>,
    371     ) -> Poll<Result<(), io::Error>> {
    372         Pin::new(&mut self.0).poll_shutdown(cx)
    373     }
    374     #[inline]
    375     fn poll_write_vectored(
    376         mut self: Pin<&mut Self>,
    377         cx: &mut Context<'_>,
    378         bufs: &[IoSlice<'_>],
    379     ) -> Poll<Result<usize, io::Error>> {
    380         Pin::new(&mut self.0).poll_write_vectored(cx, bufs)
    381     }
    382     #[inline]
    383     fn is_write_vectored(&self) -> bool {
    384         self.0.is_write_vectored()
    385     }
    386 }
    387 impl<S: AsyncRead + AsyncWrite + Unpin> PgTlsStream for TlsStream<S> {
    388     /// Returns the [`ChannelBinding`] based on the X.509 v3 certificate sent from the PostgreSQL server.
    389     ///
    390     /// Note when this returns [`ChannelBinding::tls_server_end_point`], it _does not_ mean the certificate
    391     /// is valid. In certain circumstances, this will return that even for an invalid certificate. This should
    392     /// not matter since the certificate being invalid will cause the certificate to be rejected anyway. When
    393     /// the certificate is valid and uses a supported signature algorithm, then this will always return the
    394     /// correct value.
    395     ///
    396     /// The only supported signature algorithms are the following:
    397     ///
    398     /// * id-Ed25519
    399     /// * ecdsa-with-SHA256
    400     /// * sha256WithRSAEncryption
    401     /// * ecdsa-with-SHA384
    402     /// * sha384WithRSAEncryption
    403     /// * ecdsa-with-SHA512
    404     /// * sha512WithRSAEncryption
    405     /// * ecdsa-with-SHA224
    406     /// * sha224WithRSAEncryption
    407     /// * dsa-with-SHA256
    408     /// * dsa-with-SHA224
    409     /// * dsa-with-SHA1
    410     /// * sha1WithRSAEncryption
    411     ///
    412     /// Note it is strongly recommended that TLS 1.3 be used; thus while signature algorithms that are not
    413     /// part of TLS 1.3 are supported, you should avoid them.
    414     /// See [RFC 9266 § 4.2](https://www.rfc-editor.org/rfc/rfc9266#section-4.2).
    415     /// Additionally some of the supported signature algorithms may not be supported by PostgreSQL
    416     /// (e.g., id-Ed25519).
    417     #[expect(clippy::doc_markdown, reason = "PostgreSQL is correct")]
    418     #[inline]
    419     fn channel_binding(&self) -> ChannelBinding {
    420         self.0
    421             .get_ref()
    422             .1
    423             .peer_certificates()
    424             .and_then(|certs| {
    425                 certs.first().and_then(|fst| {
    426                     Hash::from_der_cert(fst)
    427                         .map(|hash| ChannelBinding::tls_server_end_point(hash.into()))
    428                 })
    429             })
    430             .unwrap_or_else(ChannelBinding::none)
    431     }
    432 }
    433 /// [`TlsConnector::Future`] returned from [`TlsConnector::connect`].
    434 #[expect(
    435     missing_debug_implementations,
    436     reason = "Connect does not implement Debug, so we don't"
    437 )]
    438 pub struct TlsConnectorFuture<S>(Connect<S>);
    439 impl<S: AsyncRead + AsyncWrite + Unpin> Future for TlsConnectorFuture<S> {
    440     type Output = io::Result<TlsStream<S>>;
    441     #[inline]
    442     fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
    443         Pin::new(&mut self.0).poll(cx).map_ok(TlsStream)
    444     }
    445 }
    446 /// Connects to the PostgreSQL server.
    447 #[expect(
    448     missing_debug_implementations,
    449     reason = "TlsConnector does not implement Debug, so we don't"
    450 )]
    451 #[expect(clippy::doc_markdown, reason = "PostgreSQL is correct")]
    452 pub struct TlsConnector<'domain> {
    453     /// Used to connect to the PostgreSQL server.
    454     #[expect(clippy::doc_markdown, reason = "PostgreSQL is correct")]
    455     connector: tokio_rustls::TlsConnector,
    456     /// The domain or IP of the PostgreSQL server.
    457     #[expect(clippy::doc_markdown, reason = "PostgreSQL is correct")]
    458     dom: ServerName<'domain>,
    459 }
    460 impl<'domain> TlsConnector<'domain> {
    461     /// Returns `Self` based on `connector` and `domain`.
    462     ///
    463     /// # Errors
    464     ///
    465     /// Errors iff [`ServerName::try_from`] does when passed `domain`.
    466     #[expect(single_use_lifetimes, reason = "false positive")]
    467     #[inline]
    468     pub fn new<'dom: 'domain>(
    469         connector: tokio_rustls::TlsConnector,
    470         domain: &'dom str,
    471     ) -> Result<Self, InvalidDnsNameError> {
    472         ServerName::try_from(domain).map(|dom| Self { connector, dom })
    473     }
    474 }
    475 impl<S: AsyncRead + AsyncWrite + Unpin> PgTlsConnect<S> for TlsConnector<'static> {
    476     type Stream = TlsStream<S>;
    477     type Error = io::Error;
    478     type Future = TlsConnectorFuture<S>;
    479     #[inline]
    480     fn connect(self, stream: S) -> Self::Future {
    481         TlsConnectorFuture(self.connector.connect(self.dom, stream))
    482     }
    483 }
    484 /// [`MakeTlsConnect`] based on [`tokio_rustls::TlsConnector`].
    485 #[expect(
    486     missing_debug_implementations,
    487     reason = "TlsConnector does not implement Debug, so we don't"
    488 )]
    489 #[cfg(feature = "runtime")]
    490 #[derive(Clone)]
    491 pub struct MakeTlsConnector(tokio_rustls::TlsConnector);
    492 #[cfg(feature = "runtime")]
    493 impl MakeTlsConnector {
    494     /// Constructs `Self` based on `connector`.
    495     #[inline]
    496     #[must_use]
    497     pub const fn new(connector: tokio_rustls::TlsConnector) -> Self {
    498         Self(connector)
    499     }
    500 }
    501 #[cfg(feature = "runtime")]
    502 impl<S: AsyncRead + AsyncWrite + Unpin> MakeTlsConnect<S> for MakeTlsConnector {
    503     type Stream = TlsStream<S>;
    504     type TlsConnect = TlsConnector<'static>;
    505     type Error = InvalidDnsNameError;
    506     #[inline]
    507     fn make_tls_connect(&mut self, domain: &str) -> Result<Self::TlsConnect, Self::Error> {
    508         ServerName::try_from(domain).map(|dom| TlsConnector {
    509             connector: self.0.clone(),
    510             dom: dom.to_owned(),
    511         })
    512     }
    513 }
    514 /// Removes any ALPN values and adds the `b"postgresql"` ALPN.
    515 #[inline]
    516 pub fn set_postgresql_alpn(config: &mut ClientConfig) {
    517     config.alpn_protocols.clear();
    518     config.alpn_protocols.push(vec![
    519         b'p', b'o', b's', b't', b'g', b'r', b'e', b's', b'q', b'l',
    520     ]);
    521 }