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 }