@@ -87,6 +87,7 @@ use crate::pkey::{HasPrivate, PKeyRef, Params, Private};
8787use crate :: srtp:: { SrtpProtectionProfile , SrtpProtectionProfileRef } ;
8888use crate :: ssl:: bio:: BioMethod ;
8989use crate :: ssl:: callbacks:: * ;
90+ use crate :: ssl:: ech:: SslEchKeys ;
9091use crate :: ssl:: error:: InnerError ;
9192use crate :: stack:: { Stack , StackRef , Stackable } ;
9293use crate :: x509:: store:: { X509Store , X509StoreBuilderRef , X509StoreRef } ;
@@ -110,6 +111,7 @@ mod async_callbacks;
110111mod bio;
111112mod callbacks;
112113mod connector;
114+ mod ech;
113115mod error;
114116mod mut_only;
115117#[ cfg( test) ]
@@ -1956,6 +1958,15 @@ impl SslContextBuilder {
19561958 }
19571959 }
19581960
1961+ /// Registers a list of ECH keys on the context. This list should contain new and old
1962+ /// ECHConfigs to allow stale DNS caches to update. Unlike most `SSL_CTX` APIs, this function
1963+ /// is safe to call even after the `SSL_CTX` has been associated with connections on various
1964+ /// threads.
1965+ #[ corresponds( SSL_CTX_set1_ech_keys ) ]
1966+ pub fn set_ech_keys ( & mut self , keys : SslEchKeys ) -> Result < ( ) , ErrorStack > {
1967+ unsafe { cvt ( ffi:: SSL_CTX_set1_ech_keys ( self . as_ptr ( ) , keys. as_ptr ( ) ) ) . map ( |_| ( ) ) }
1968+ }
1969+
19591970 /// Consumes the builder, returning a new `SslContext`.
19601971 pub fn build ( self ) -> SslContext {
19611972 self . ctx
@@ -3623,6 +3634,73 @@ impl SslRef {
36233634 pub fn add_chain_cert ( & mut self , cert : & X509Ref ) -> Result < ( ) , ErrorStack > {
36243635 unsafe { cvt ( ffi:: SSL_add1_chain_cert ( self . as_ptr ( ) , cert. as_ptr ( ) ) ) . map ( |_| ( ) ) }
36253636 }
3637+
3638+ /// Configures `ech_config_list` on `SSL` for offering ECH during handshakes. If the server
3639+ /// cannot decrypt the encrypted ClientHello, `SSL` will instead handshake using
3640+ /// the cleartext parameters of the ClientHelloOuter.
3641+ ///
3642+ /// Clients should use `get_ech_name_override` to verify the server certificate in case of ECH
3643+ /// rejection, and follow up with `get_ech_retry_configs` to retry the connection with a fresh
3644+ /// set of ECHConfigs. If the retry also fails, clients should report a connection failure.
3645+ #[ corresponds( SSL_set1_ech_config_list ) ]
3646+ pub fn set_ech_config_list ( & mut self , ech_config_list : & [ u8 ] ) -> Result < ( ) , ErrorStack > {
3647+ unsafe {
3648+ cvt_0i ( ffi:: SSL_set1_ech_config_list (
3649+ self . as_ptr ( ) ,
3650+ ech_config_list. as_ptr ( ) ,
3651+ ech_config_list. len ( ) ,
3652+ ) )
3653+ . map ( |_| ( ) )
3654+ }
3655+ }
3656+
3657+ /// This function returns a serialized `ECHConfigList` as provided by the
3658+ /// server, if one exists.
3659+ ///
3660+ /// Clients should call this function when handling an `SSL_R_ECH_REJECTED` error code to
3661+ /// recover from potential key mismatches. If the result is `Some`, the client should retry the
3662+ /// connection using the returned `ECHConfigList`.
3663+ #[ corresponds( SSL_get0_ech_retry_configs ) ]
3664+ pub fn get_ech_retry_configs ( & self ) -> Option < & [ u8 ] > {
3665+ unsafe {
3666+ let mut data = ptr:: null ( ) ;
3667+ let mut len: usize = 0 ;
3668+ ffi:: SSL_get0_ech_retry_configs ( self . as_ptr ( ) , & mut data, & mut len) ;
3669+
3670+ if data. is_null ( ) {
3671+ None
3672+ } else {
3673+ Some ( slice:: from_raw_parts ( data, len) )
3674+ }
3675+ }
3676+ }
3677+
3678+ /// If `SSL` is a client and the server rejects ECH, this function returns the public name
3679+ /// associated with the ECHConfig that was used to attempt ECH.
3680+ ///
3681+ /// Clients should call this function during the certificate verification callback to
3682+ /// ensure the server's certificate is valid for the public name, which is required to
3683+ /// authenticate retry configs.
3684+ #[ corresponds( SSL_get0_ech_name_override ) ]
3685+ pub fn get_ech_name_override ( & self ) -> Option < & [ u8 ] > {
3686+ unsafe {
3687+ let mut data: * const c_char = ptr:: null ( ) ;
3688+ let mut len: usize = 0 ;
3689+ ffi:: SSL_get0_ech_name_override ( self . as_ptr ( ) , & mut data, & mut len) ;
3690+
3691+ if data. is_null ( ) {
3692+ None
3693+ } else {
3694+ Some ( slice:: from_raw_parts ( data as * const u8 , len) )
3695+ }
3696+ }
3697+ }
3698+
3699+ // Whether or not `SSL` negotiated ECH.
3700+ #[ corresponds( SSL_ech_accepted ) ]
3701+ pub fn ech_accepted ( & self ) -> bool {
3702+ unsafe { ffi:: SSL_ech_accepted ( self . as_ptr ( ) ) != 0 }
3703+ }
36263704}
36273705
36283706/// An SSL stream midway through the handshake process.
0 commit comments