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