@@ -13,7 +13,7 @@ use core::ptr::NonNull;
13
13
use mbedtls_sys:: types:: raw_types:: { c_char, c_void} ;
14
14
use mbedtls_sys:: * ;
15
15
16
- use crate :: alloc:: { mbedtls_calloc, Box as MbedtlsBox , List as MbedtlsList } ;
16
+ use crate :: alloc:: { mbedtls_calloc, Box as MbedtlsBox , CString , List as MbedtlsList } ;
17
17
#[ cfg( not( feature = "std" ) ) ]
18
18
use crate :: alloc_prelude:: * ;
19
19
use crate :: error:: { Error , IntoResult , Result } ;
@@ -224,6 +224,7 @@ impl Certificate {
224
224
ca_crl : Option < & mut Crl > ,
225
225
err_info : Option < & mut String > ,
226
226
cb : Option < F > ,
227
+ expected_common_name : Option < & str > ,
227
228
) -> Result < ( ) >
228
229
where
229
230
F : VerifyCallback + ' static ,
@@ -236,20 +237,25 @@ impl Certificate {
236
237
} else {
237
238
( None , :: core:: ptr:: null_mut ( ) )
238
239
} ;
240
+
241
+ let cn = expected_common_name. map ( |cn| CString :: new ( cn) ) ;
239
242
let mut flags = 0 ;
240
243
let result = unsafe {
241
244
x509_crt_verify (
242
245
chain. inner_ffi_mut ( ) ,
243
246
trust_ca. inner_ffi_mut ( ) ,
244
247
ca_crl. map_or ( :: core:: ptr:: null_mut ( ) , |crl| crl. handle_mut ( ) ) ,
245
- :: core:: ptr:: null ( ) ,
248
+ cn . as_ref ( ) . map_or ( :: core:: ptr:: null ( ) , |cn| cn . as_ptr ( ) ) ,
246
249
& mut flags,
247
250
f_vrfy,
248
251
p_vrfy,
249
252
)
250
253
}
251
254
. into_result ( ) ;
252
255
256
+ // Asserts cn is still alive here. Prevents bugs (e.g., forgetting to insert `.as_ref()` when using cn)
257
+ drop ( cn) ;
258
+
253
259
if result. is_err ( ) {
254
260
if let Some ( err_info) = err_info {
255
261
let verify_info = crate :: private:: alloc_string_repeat ( |buf, size| unsafe {
@@ -270,7 +276,32 @@ impl Certificate {
270
276
ca_crl : Option < & mut Crl > ,
271
277
err_info : Option < & mut String > ,
272
278
) -> Result < ( ) > {
273
- Self :: verify_ex ( chain, trust_ca, ca_crl, err_info, None :: < & dyn VerifyCallback > )
279
+ Self :: verify_ex ( chain, trust_ca, ca_crl, err_info, None :: < & dyn VerifyCallback > , None )
280
+ }
281
+
282
+ /// Like `verify`, optionally accepts an `expected_common_name` arg.
283
+ ///
284
+ /// * `expected_common_name`
285
+ /// (From mbedtls documentation) The expected Common Name. This will be checked to be present in the certificate’s
286
+ /// subjectAltNames extension or, if this extension is absent, as a CN component in its Subject name. DNS names
287
+ /// and IP addresses are fully supported, while the URI subtype is partially supported: only exact matching,
288
+ /// without any normalization procedures described in 7.4 of RFC5280, will result in a positive URI verification.
289
+ /// This may be `None` if the CN need not be verified.
290
+ pub fn verify_with_expected_common_name (
291
+ chain : & MbedtlsList < Certificate > ,
292
+ trust_ca : & MbedtlsList < Certificate > ,
293
+ ca_crl : Option < & mut Crl > ,
294
+ err_info : Option < & mut String > ,
295
+ expected_common_name : Option < & str > ,
296
+ ) -> Result < ( ) > {
297
+ Self :: verify_ex (
298
+ chain,
299
+ trust_ca,
300
+ ca_crl,
301
+ err_info,
302
+ None :: < & dyn VerifyCallback > ,
303
+ expected_common_name,
304
+ )
274
305
}
275
306
276
307
pub fn verify_with_callback < F > (
@@ -283,7 +314,29 @@ impl Certificate {
283
314
where
284
315
F : VerifyCallback + ' static ,
285
316
{
286
- Self :: verify_ex ( chain, trust_ca, ca_crl, err_info, Some ( cb) )
317
+ Self :: verify_ex ( chain, trust_ca, ca_crl, err_info, Some ( cb) , None )
318
+ }
319
+
320
+ /// Like `verify_with_callback`, optionally accepts an `expected_common_name` arg.
321
+ ///
322
+ /// * `expected_common_name`
323
+ /// (From mbedtls documentation) The expected Common Name. This will be checked to be present in the certificate’s
324
+ /// subjectAltNames extension or, if this extension is absent, as a CN component in its Subject name. DNS names
325
+ /// and IP addresses are fully supported, while the URI subtype is partially supported: only exact matching,
326
+ /// without any normalization procedures described in 7.4 of RFC5280, will result in a positive URI verification.
327
+ /// This may be `None` if the CN need not be verified.
328
+ pub fn verify_with_callback_expected_common_name < F > (
329
+ chain : & MbedtlsList < Certificate > ,
330
+ trust_ca : & MbedtlsList < Certificate > ,
331
+ ca_crl : Option < & mut Crl > ,
332
+ err_info : Option < & mut String > ,
333
+ cb : F ,
334
+ expected_common_name : Option < & str > ,
335
+ ) -> Result < ( ) >
336
+ where
337
+ F : VerifyCallback + ' static ,
338
+ {
339
+ Self :: verify_ex ( chain, trust_ca, ca_crl, err_info, Some ( cb) , expected_common_name)
287
340
}
288
341
}
289
342
@@ -1489,4 +1542,36 @@ cYp0bH/RcPTC0Z+ZaqSWMtfxRrk63MJQF9EXpDCdvQRcTMD9D85DJrMKn8aumq0M
1489
1542
) ;
1490
1543
assert_eq ! ( err, "The certificate has been revoked (is on a CRL)\n " ) ;
1491
1544
}
1545
+
1546
+ #[ test]
1547
+ fn expected_common_name_test ( ) {
1548
+ const C_CERT : & ' static str = concat ! ( include_str!( "../../tests/data/certificate.crt" ) , "\0 " ) ;
1549
+ const C_ROOT : & ' static str = concat ! ( include_str!( "../../tests/data/root.crt" ) , "\0 " ) ;
1550
+
1551
+ let mut certs = MbedtlsList :: new ( ) ;
1552
+ certs. push ( Certificate :: from_pem ( & C_CERT . as_bytes ( ) ) . unwrap ( ) ) ;
1553
+ let mut roots = MbedtlsList :: new ( ) ;
1554
+ roots. push ( Certificate :: from_pem ( & C_ROOT . as_bytes ( ) ) . unwrap ( ) ) ;
1555
+
1556
+ let mut err = String :: new ( ) ;
1557
+ assert ! (
1558
+ Certificate :: verify_with_expected_common_name( & certs, & roots, None , Some ( & mut err) , Some ( "example.com" ) ) . is_ok( ) ,
1559
+ ) ;
1560
+ }
1561
+
1562
+ #[ test]
1563
+ fn expected_common_name_wrong_name_test ( ) {
1564
+ const C_CERT : & ' static str = concat ! ( include_str!( "../../tests/data/certificate.crt" ) , "\0 " ) ;
1565
+ const C_ROOT : & ' static str = concat ! ( include_str!( "../../tests/data/root.crt" ) , "\0 " ) ;
1566
+
1567
+ let mut certs = MbedtlsList :: new ( ) ;
1568
+ certs. push ( Certificate :: from_pem ( & C_CERT . as_bytes ( ) ) . unwrap ( ) ) ;
1569
+ let mut roots = MbedtlsList :: new ( ) ;
1570
+ roots. push ( Certificate :: from_pem ( & C_ROOT . as_bytes ( ) ) . unwrap ( ) ) ;
1571
+
1572
+ let mut err = String :: new ( ) ;
1573
+ assert ! (
1574
+ Certificate :: verify_with_expected_common_name( & certs, & roots, None , Some ( & mut err) , Some ( "notit.com" ) ) . is_err( )
1575
+ ) ;
1576
+ }
1492
1577
}
0 commit comments