1
+ use std:: borrow:: Cow ;
1
2
use std:: convert:: { TryFrom , TryInto } ;
2
3
use std:: ffi:: { CStr , OsStr } ;
3
4
use std:: fs:: File ;
@@ -176,12 +177,15 @@ impl rustls_client_config_builder {
176
177
177
178
/// Input to a custom certificate verifier callback. See
178
179
/// rustls_client_config_builder_dangerous_set_certificate_verifier().
180
+ ///
181
+ /// server_name can contain a hostname, an IPv4 address in textual form, or an
182
+ /// IPv6 address in textual form.
179
183
#[ allow( non_camel_case_types) ]
180
184
#[ repr( C ) ]
181
185
pub struct rustls_verify_server_cert_params < ' a > {
182
186
pub end_entity_cert_der : rustls_slice_bytes < ' a > ,
183
187
pub intermediate_certs_der : & ' a rustls_slice_slice_bytes < ' a > ,
184
- pub dns_name : rustls_str < ' a > ,
188
+ pub server_name : rustls_str < ' a > ,
185
189
pub ocsp_response : rustls_slice_bytes < ' a > ,
186
190
}
187
191
@@ -233,11 +237,12 @@ impl rustls::client::ServerCertVerifier for Verifier {
233
237
_now : SystemTime ,
234
238
) -> Result < ServerCertVerified , rustls:: Error > {
235
239
let cb = self . callback ;
236
- let dns_name: & str = match server_name {
237
- rustls:: ServerName :: DnsName ( n) => n. as_ref ( ) ,
240
+ let server_name: Cow < ' _ , str > = match server_name {
241
+ rustls:: ServerName :: DnsName ( n) => n. as_ref ( ) . into ( ) ,
242
+ rustls:: ServerName :: IpAddress ( ip) => ip. to_string ( ) . into ( ) ,
238
243
_ => return Err ( rustls:: Error :: General ( "unknown name type" . to_string ( ) ) ) ,
239
244
} ;
240
- let dns_name : rustls_str = match dns_name . try_into ( ) {
245
+ let server_name : rustls_str = match server_name . as_ref ( ) . try_into ( ) {
241
246
Ok ( r) => r,
242
247
Err ( NulByte { } ) => return Err ( rustls:: Error :: General ( "NUL byte in SNI" . to_string ( ) ) ) ,
243
248
} ;
@@ -251,7 +256,7 @@ impl rustls::client::ServerCertVerifier for Verifier {
251
256
let params = rustls_verify_server_cert_params {
252
257
end_entity_cert_der : end_entity. as_ref ( ) . into ( ) ,
253
258
intermediate_certs_der : & intermediates,
254
- dns_name ,
259
+ server_name ,
255
260
ocsp_response : ocsp_response. into ( ) ,
256
261
} ;
257
262
let userdata = userdata_get ( ) . map_err ( |_| {
@@ -282,18 +287,10 @@ impl rustls_client_config_builder {
282
287
/// to make such mutation safe.
283
288
///
284
289
/// The callback receives certificate chain information as raw bytes.
285
- /// Currently this library offers no functions for C code to parse the
286
- /// certificates, so you'll need to bring your own certificate parsing library
290
+ /// Currently this library offers no functions to parse the certificates,
291
+ /// so you'll need to bring your own certificate parsing library
287
292
/// if you need to parse them.
288
293
///
289
- /// If you intend to write a verifier that accepts all certificates, be aware
290
- /// that special measures are required for IP addresses. Rustls currently
291
- /// (0.20.0) doesn't support building a ClientConnection with an IP address
292
- /// (because it's not a valid DnsNameRef). One workaround is to detect IP
293
- /// addresses and rewrite them to `example.invalid`, and _also_ to disable
294
- /// SNI via rustls_client_config_builder_set_enable_sni (IP addresses don't
295
- /// need SNI).
296
- ///
297
294
/// If the custom verifier accepts the certificate, it should return
298
295
/// RUSTLS_RESULT_OK. Otherwise, it may return any other rustls_result error.
299
296
/// Feel free to use an appropriate error from the RUSTLS_RESULT_CERT_*
@@ -534,25 +531,29 @@ impl rustls_client_config {
534
531
/// non-error, the memory pointed to by `conn_out` is modified to point at a
535
532
/// valid rustls_connection. The caller now owns the rustls_connection and must
536
533
/// call `rustls_connection_free` when done with it.
534
+ ///
535
+ /// The server_name parameter can contain a hostname or an IP address in
536
+ /// textual form (IPv4 or IPv6). This function will return an error if it
537
+ /// cannot be parsed as one of those types.
537
538
#[ no_mangle]
538
539
pub extern "C" fn rustls_client_connection_new (
539
540
config : * const rustls_client_config ,
540
- hostname : * const c_char ,
541
+ server_name : * const c_char ,
541
542
conn_out : * mut * mut rustls_connection ,
542
543
) -> rustls_result {
543
544
ffi_panic_boundary ! {
544
- let hostname : & CStr = unsafe {
545
- if hostname . is_null( ) {
545
+ let server_name : & CStr = unsafe {
546
+ if server_name . is_null( ) {
546
547
return NullParameter ;
547
548
}
548
- CStr :: from_ptr( hostname )
549
+ CStr :: from_ptr( server_name )
549
550
} ;
550
551
let config: Arc <ClientConfig > = try_arc_from_ptr!( config) ;
551
- let hostname : & str = match hostname . to_str( ) {
552
+ let server_name : & str = match server_name . to_str( ) {
552
553
Ok ( s) => s,
553
554
Err ( std:: str :: Utf8Error { .. } ) => return rustls_result:: InvalidDnsNameError ,
554
555
} ;
555
- let server_name: rustls:: ServerName = match hostname . try_into( ) {
556
+ let server_name: rustls:: ServerName = match server_name . try_into( ) {
556
557
Ok ( sn) => sn,
557
558
Err ( _) => return rustls_result:: InvalidDnsNameError ,
558
559
} ;
@@ -645,4 +646,21 @@ mod tests {
645
646
) ;
646
647
rustls_connection:: rustls_connection_free ( conn) ;
647
648
}
649
+
650
+ #[ test]
651
+ #[ cfg_attr( miri, ignore) ]
652
+ fn test_client_connection_new_ipaddress ( ) {
653
+ let builder: * mut rustls_client_config_builder =
654
+ rustls_client_config_builder:: rustls_client_config_builder_new ( ) ;
655
+ let config = rustls_client_config_builder:: rustls_client_config_builder_build ( builder) ;
656
+ let mut conn: * mut rustls_connection = null_mut ( ) ;
657
+ let result = rustls_client_config:: rustls_client_connection_new (
658
+ config,
659
+ "198.51.100.198\0 " . as_ptr ( ) as * const c_char ,
660
+ & mut conn,
661
+ ) ;
662
+ if !matches ! ( result, rustls_result:: Ok ) {
663
+ panic ! ( "expected RUSTLS_RESULT_OK, got {:?}" , result) ;
664
+ }
665
+ }
648
666
}
0 commit comments