@@ -21,8 +21,8 @@ use pingora_error::{
21
21
OrErr , Result ,
22
22
} ;
23
23
use pingora_rustls:: {
24
- load_ca_file_into_store, load_certs_key_file , load_platform_certs_incl_env_into_store, version ,
25
- CertificateDer , ClientConfig as RusTlsClientConfig , PrivateKeyDer , RootCertStore ,
24
+ load_ca_file_into_store, load_certs_and_key_files , load_platform_certs_incl_env_into_store,
25
+ version , CertificateDer , ClientConfig as RusTlsClientConfig , PrivateKeyDer , RootCertStore ,
26
26
TlsConnector as RusTlsConnector ,
27
27
} ;
28
28
@@ -37,18 +37,21 @@ pub struct Connector {
37
37
}
38
38
39
39
impl Connector {
40
+ /// Create a new connector based on the optional configurations. If no
41
+ /// configurations are provided, no customized certificates or keys will be
42
+ /// used
40
43
pub fn new ( config_opt : Option < ConnectorOptions > ) -> Self {
41
- TlsConnector :: build_connector ( config_opt)
44
+ TlsConnector :: build_connector ( config_opt) . unwrap ( )
42
45
}
43
46
}
44
47
45
48
pub ( crate ) struct TlsConnector {
46
- config : RusTlsClientConfig ,
47
- ca_certs : RootCertStore ,
49
+ config : Arc < RusTlsClientConfig > ,
50
+ ca_certs : Arc < RootCertStore > ,
48
51
}
49
52
50
53
impl TlsConnector {
51
- pub ( crate ) fn build_connector ( options : Option < ConnectorOptions > ) -> Connector
54
+ pub ( crate ) fn build_connector ( options : Option < ConnectorOptions > ) -> Result < Connector >
52
55
where
53
56
Self : Sized ,
54
57
{
@@ -65,16 +68,16 @@ impl TlsConnector {
65
68
66
69
if let Some ( conf) = options. as_ref ( ) {
67
70
if let Some ( ca_file_path) = conf. ca_file . as_ref ( ) {
68
- load_ca_file_into_store ( ca_file_path, & mut ca_certs) ;
71
+ load_ca_file_into_store ( ca_file_path, & mut ca_certs) ? ;
69
72
} else {
70
- load_platform_certs_incl_env_into_store ( & mut ca_certs) ;
73
+ load_platform_certs_incl_env_into_store ( & mut ca_certs) ? ;
71
74
}
72
75
if let Some ( ( cert, key) ) = conf. cert_key_file . as_ref ( ) {
73
- certs_key = load_certs_key_file ( cert, key) ;
76
+ certs_key = load_certs_and_key_files ( cert, key) ? ;
74
77
}
75
78
// TODO: support SSLKEYLOGFILE
76
79
} else {
77
- load_platform_certs_incl_env_into_store ( & mut ca_certs) ;
80
+ load_platform_certs_incl_env_into_store ( & mut ca_certs) ? ;
78
81
}
79
82
80
83
( ca_certs, certs_key)
@@ -92,19 +95,19 @@ impl TlsConnector {
92
95
Err ( err) => {
93
96
// TODO: is there a viable alternative to the panic?
94
97
// falling back to no client auth... does not seem to be reasonable.
95
- panic ! (
96
- "{}" ,
97
- format!( "Failed to configure client auth cert/key. Error: {}" , err)
98
- ) ;
98
+ panic ! ( "Failed to configure client auth cert/key. Error: {}" , err) ;
99
99
}
100
100
}
101
101
}
102
102
None => builder. with_no_client_auth ( ) ,
103
103
} ;
104
104
105
- Connector {
106
- ctx : Arc :: new ( TlsConnector { config, ca_certs } ) ,
107
- }
105
+ Ok ( Connector {
106
+ ctx : Arc :: new ( TlsConnector {
107
+ config : Arc :: new ( config) ,
108
+ ca_certs : Arc :: new ( ca_certs) ,
109
+ } ) ,
110
+ } )
108
111
}
109
112
}
110
113
@@ -118,96 +121,81 @@ where
118
121
T : IO ,
119
122
P : Peer + Send + Sync ,
120
123
{
121
- let mut config = tls_ctx. config . clone ( ) ;
124
+ let config = & tls_ctx. config ;
122
125
123
126
// TODO: setup CA/verify cert store from peer
124
- // looks like the fields are always None
125
- // peer.get_ca()
126
-
127
+ // peer.get_ca() returns None by default. It must be replaced by the
128
+ // implementation of `peer`
127
129
let key_pair = peer. get_client_cert_key ( ) ;
128
- let updated_config : Option < RusTlsClientConfig > = match key_pair {
130
+ let mut updated_config_opt : Option < RusTlsClientConfig > = match key_pair {
129
131
None => None ,
130
132
Some ( key_arc) => {
131
133
debug ! ( "setting client cert and key" ) ;
132
134
133
135
let mut cert_chain = vec ! [ ] ;
134
136
debug ! ( "adding leaf certificate to mTLS cert chain" ) ;
135
- cert_chain. push ( key_arc. leaf ( ) . to_owned ( ) ) ;
137
+ cert_chain. push ( key_arc. leaf ( ) ) ;
136
138
137
139
debug ! ( "adding intermediate certificates to mTLS cert chain" ) ;
138
140
key_arc
139
141
. intermediates ( )
140
142
. to_owned ( )
141
143
. iter ( )
142
- . map ( |i| i . to_vec ( ) )
144
+ . copied ( )
143
145
. for_each ( |i| cert_chain. push ( i) ) ;
144
146
145
- let certs: Vec < CertificateDer > = cert_chain
146
- . into_iter ( )
147
- . map ( |c| c. as_slice ( ) . to_owned ( ) . into ( ) )
148
- . collect ( ) ;
147
+ let certs: Vec < CertificateDer > = cert_chain. into_iter ( ) . map ( |c| c. into ( ) ) . collect ( ) ;
149
148
let private_key: PrivateKeyDer =
150
149
key_arc. key ( ) . as_slice ( ) . to_owned ( ) . try_into ( ) . unwrap ( ) ;
151
150
152
151
let builder = RusTlsClientConfig :: builder_with_protocol_versions ( & [
153
152
& version:: TLS12 ,
154
153
& version:: TLS13 ,
155
154
] )
156
- . with_root_certificates ( tls_ctx. ca_certs . clone ( ) ) ;
157
-
158
- let updated_config = builder
159
- . with_client_auth_cert ( certs, private_key)
160
- . explain_err ( InvalidCert , |e| {
161
- format ! (
162
- "Failed to use peer cert/key to update Rustls config: {:?}" ,
163
- e
164
- )
165
- } ) ?;
155
+ . with_root_certificates ( Arc :: clone ( & tls_ctx. ca_certs ) ) ;
156
+ debug ! ( "added root ca certificates" ) ;
157
+
158
+ let updated_config = builder. with_client_auth_cert ( certs, private_key) . or_err (
159
+ InvalidCert ,
160
+ "Failed to use peer cert/key to update Rustls config" ,
161
+ ) ?;
166
162
Some ( updated_config)
167
163
}
168
164
} ;
169
165
170
166
if let Some ( alpn) = alpn_override. as_ref ( ) . or ( peer. get_alpn ( ) ) {
171
- config. alpn_protocols = alpn. to_wire_protocols ( ) ;
167
+ let alpn_protocols = alpn. to_wire_protocols ( ) ;
168
+ if let Some ( updated_config) = updated_config_opt. as_mut ( ) {
169
+ updated_config. alpn_protocols = alpn_protocols;
170
+ } else {
171
+ let mut updated_config = RusTlsClientConfig :: clone ( config) ;
172
+ updated_config. alpn_protocols = alpn_protocols;
173
+ updated_config_opt = Some ( updated_config) ;
174
+ }
172
175
}
173
176
174
177
// TODO: curve setup from peer
175
178
// - second key share from peer, currently only used in boringssl with PQ features
176
179
177
- let tls_conn = if let Some ( cfg) = updated_config {
180
+ let tls_conn = if let Some ( cfg) = updated_config_opt {
178
181
RusTlsConnector :: from ( Arc :: new ( cfg) )
179
182
} else {
180
- RusTlsConnector :: from ( Arc :: new ( config) )
183
+ RusTlsConnector :: from ( Arc :: clone ( config) )
181
184
} ;
182
185
183
- // TODO: for consistent behaviour between TLS providers some additions are required
186
+ // TODO: for consistent behavior between TLS providers some additions are required
184
187
// - allowing to disable verification
185
- // - the validation/replace logic would need adjustments to match the boringssl/openssl behaviour
186
- // implementing a custom certificate_verifier could be used to achieve matching behaviour
188
+ // - the validation/replace logic would need adjustments to match the boringssl/openssl behavior
189
+ // implementing a custom certificate_verifier could be used to achieve matching behavior
187
190
//let d_conf = config.dangerous();
188
191
//d_conf.set_certificate_verifier(...);
189
192
190
193
let mut domain = peer. sni ( ) . to_string ( ) ;
191
- if peer. sni ( ) . is_empty ( ) {
192
- // use ip in case SNI is not present
193
- // TODO: disable validation
194
- domain = peer. address ( ) . as_inet ( ) . unwrap ( ) . ip ( ) . to_string ( )
195
- }
196
-
197
194
if peer. verify_cert ( ) && peer. verify_hostname ( ) {
198
195
// TODO: streamline logic with replacing first underscore within TLS implementations
199
196
if let Some ( sni_s) = replace_leftmost_underscore ( peer. sni ( ) ) {
200
197
domain = sni_s;
201
198
}
202
- if let Some ( alt_cn) = peer. alternative_cn ( ) {
203
- if !alt_cn. is_empty ( ) {
204
- domain = alt_cn. to_string ( ) ;
205
- // TODO: streamline logic with replacing first underscore within TLS implementations
206
- if let Some ( alt_cn_s) = replace_leftmost_underscore ( alt_cn) {
207
- domain = alt_cn_s;
208
- }
209
- }
210
- }
211
199
}
212
200
213
201
let connect_future = handshake ( & tls_conn, & domain, stream) ;
0 commit comments