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