@@ -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,7 @@ mod async_callbacks;
110
111
mod bio;
111
112
mod callbacks;
112
113
mod connector;
114
+ mod ech;
113
115
mod error;
114
116
mod mut_only;
115
117
#[ cfg( test) ]
@@ -1956,6 +1958,15 @@ impl SslContextBuilder {
1956
1958
}
1957
1959
}
1958
1960
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
+
1959
1970
/// Consumes the builder, returning a new `SslContext`.
1960
1971
pub fn build ( self ) -> SslContext {
1961
1972
self . ctx
@@ -3623,6 +3634,73 @@ impl SslRef {
3623
3634
pub fn add_chain_cert ( & mut self , cert : & X509Ref ) -> Result < ( ) , ErrorStack > {
3624
3635
unsafe { cvt ( ffi:: SSL_add1_chain_cert ( self . as_ptr ( ) , cert. as_ptr ( ) ) ) . map ( |_| ( ) ) }
3625
3636
}
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
+ }
3626
3704
}
3627
3705
3628
3706
/// An SSL stream midway through the handshake process.
0 commit comments