From 1b1e86fe14cecc9056af40d7022645ffc5d0fb9e Mon Sep 17 00:00:00 2001 From: matszpk Date: Sat, 11 Jun 2022 11:32:09 +0200 Subject: [PATCH] Add ALPN support to TlsAcceptor - add accept_alpn to TlsAcceptorBuilder and setup in TlsAcceptor. --- src/imp/openssl.rs | 23 +++++++++++++++++++++++ src/lib.rs | 14 ++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/src/imp/openssl.rs b/src/imp/openssl.rs index 389caa5e..24dae673 100644 --- a/src/imp/openssl.rs +++ b/src/imp/openssl.rs @@ -368,6 +368,29 @@ impl TlsAcceptor { let mut acceptor = SslAcceptor::mozilla_intermediate(SslMethod::tls())?; acceptor.set_private_key(&builder.identity.0.pkey)?; acceptor.set_certificate(&builder.identity.0.cert)?; + #[cfg(feature = "alpn")] + if !builder.alpn.is_empty() { + use self::openssl::ssl::SslRef; + // Wire format is each alpn preceded by its length as a byte. + let mut alpn_wire_format = Vec::with_capacity( + builder + .alpn + .iter() + .map(|s| s.as_bytes().len()) + .sum::() + + builder.alpn.len(), + ); + for alpn in builder.alpn.iter().map(|s| s.as_bytes()) { + alpn_wire_format.push(alpn.len() as u8); + alpn_wire_format.extend(alpn); + } + acceptor.set_alpn_protos(&alpn_wire_format)?; + // set uo ALPN selection routine - as select_next_proto + acceptor.set_alpn_select_callback(move |_: &mut SslRef, list: &[u8]| { + openssl::ssl::select_next_proto(&alpn_wire_format, list).ok_or( + openssl::ssl::AlpnError::NOACK) + }); + } for cert in builder.identity.0.chain.iter() { // https://www.openssl.org/docs/manmaster/man3/SSL_CTX_add_extra_chain_cert.html // specifies that "When sending a certificate chain, extra chain certificates are diff --git a/src/lib.rs b/src/lib.rs index 14dabb7b..01d712ae 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -522,6 +522,8 @@ pub struct TlsAcceptorBuilder { identity: Identity, min_protocol: Option, max_protocol: Option, + #[cfg(feature = "alpn")] + alpn: Vec, } impl TlsAcceptorBuilder { @@ -544,6 +546,16 @@ impl TlsAcceptorBuilder { self.max_protocol = protocol; self } + + /// Accept specific protocols through ALPN (Application-Layer Protocol Negotiation). + /// + /// Defaults to empty. + #[cfg(feature = "alpn")] + #[cfg_attr(docsrs, doc(cfg(feature = "alpn")))] + pub fn accept_alpn(&mut self, protocols: &[&str]) -> &mut TlsAcceptorBuilder { + self.alpn = protocols.iter().map(|s| (*s).to_owned()).collect(); + self + } /// Creates a new `TlsAcceptor`. pub fn build(&self) -> Result { @@ -609,6 +621,8 @@ impl TlsAcceptor { identity, min_protocol: Some(Protocol::Tlsv10), max_protocol: None, + #[cfg(feature = "alpn")] + alpn: vec![], } }