@@ -13,7 +13,7 @@ use core::ptr::NonNull;
1313use mbedtls_sys:: types:: raw_types:: { c_char, c_void} ;
1414use mbedtls_sys:: * ;
1515
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 } ;
1717#[ cfg( not( feature = "std" ) ) ]
1818use crate :: alloc_prelude:: * ;
1919use crate :: error:: { Error , IntoResult , Result } ;
@@ -224,6 +224,7 @@ impl Certificate {
224224 ca_crl : Option < & mut Crl > ,
225225 err_info : Option < & mut String > ,
226226 cb : Option < F > ,
227+ expected_common_name : Option < & str > ,
227228 ) -> Result < ( ) >
228229 where
229230 F : VerifyCallback + ' static ,
@@ -236,20 +237,25 @@ impl Certificate {
236237 } else {
237238 ( None , :: core:: ptr:: null_mut ( ) )
238239 } ;
240+
241+ let cn = expected_common_name. map ( |cn| CString :: new ( cn) ) ;
239242 let mut flags = 0 ;
240243 let result = unsafe {
241244 x509_crt_verify (
242245 chain. inner_ffi_mut ( ) ,
243246 trust_ca. inner_ffi_mut ( ) ,
244247 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 ( ) ) ,
246249 & mut flags,
247250 f_vrfy,
248251 p_vrfy,
249252 )
250253 }
251254 . into_result ( ) ;
252255
256+ // Asserts cn is still alive here. Prevents bugs (e.g., forgetting to insert `.as_ref()` when using cn)
257+ drop ( cn) ;
258+
253259 if result. is_err ( ) {
254260 if let Some ( err_info) = err_info {
255261 let verify_info = crate :: private:: alloc_string_repeat ( |buf, size| unsafe {
@@ -270,7 +276,32 @@ impl Certificate {
270276 ca_crl : Option < & mut Crl > ,
271277 err_info : Option < & mut String > ,
272278 ) -> 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+ )
274305 }
275306
276307 pub fn verify_with_callback < F > (
@@ -283,7 +314,29 @@ impl Certificate {
283314 where
284315 F : VerifyCallback + ' static ,
285316 {
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)
287340 }
288341}
289342
@@ -1489,4 +1542,36 @@ cYp0bH/RcPTC0Z+ZaqSWMtfxRrk63MJQF9EXpDCdvQRcTMD9D85DJrMKn8aumq0M
14891542 ) ;
14901543 assert_eq ! ( err, "The certificate has been revoked (is on a CRL)\n " ) ;
14911544 }
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+ }
14921577}
0 commit comments