@@ -9,7 +9,10 @@ use rcgen::{
99use rustls_pki_types:: { CertificateDer , CertificateSigningRequestDer , pem:: PemObject } ;
1010use thiserror:: Error ;
1111use time:: { Duration , OffsetDateTime } ;
12- use x509_parser:: parse_x509_certificate;
12+ use x509_parser:: {
13+ extensions:: { GeneralName , ParsedExtension } ,
14+ parse_x509_certificate,
15+ } ;
1316
1417const CA_NAME : & str = "Defguard CA" ;
1518const NOT_BEFORE_OFFSET_SECS : Duration = Duration :: minutes ( 5 ) ;
@@ -144,6 +147,7 @@ impl CertificateAuthority<'_> {
144147
145148pub struct CertificateInfo {
146149 pub subject_common_name : String ,
150+ pub subject_email : Option < String > ,
147151 pub not_before : NaiveDateTime ,
148152 pub not_after : NaiveDateTime ,
149153 pub serial : String ,
@@ -158,6 +162,19 @@ impl CertificateInfo {
158162
159163 let subject = & parsed. tbs_certificate . subject ;
160164 let serial = parsed. raw_serial_as_string ( ) ;
165+ let subject_email = parsed
166+ . tbs_certificate
167+ . extensions ( )
168+ . iter ( )
169+ . filter_map ( |ext| match ext. parsed_extension ( ) {
170+ ParsedExtension :: SubjectAlternativeName ( san) => Some ( san) ,
171+ _ => None ,
172+ } )
173+ . flat_map ( |san| san. general_names . iter ( ) )
174+ . find_map ( |name| match name {
175+ GeneralName :: RFC822Name ( email) => Some ( email. to_string ( ) ) ,
176+ _ => None ,
177+ } ) ;
161178
162179 let cn = subject
163180 . iter_common_name ( )
@@ -174,6 +191,7 @@ impl CertificateInfo {
174191
175192 Ok ( Self {
176193 subject_common_name : cn. to_string ( ) ,
194+ subject_email,
177195 not_before : chrono:: DateTime :: from_timestamp ( not_before. unix_timestamp ( ) , 0 )
178196 . ok_or_else ( || {
179197 CertificateError :: ParsingError ( format ! (
@@ -425,30 +443,15 @@ mod tests {
425443
426444 #[ test]
427445 fn test_ca_email ( ) {
428- use x509_parser:: parse_x509_certificate;
429-
430446 let expected_email = "contact@defguard.net" ;
431447 let ca = CertificateAuthority :: new ( "Test CA" , expected_email, 365 ) . unwrap ( ) ;
432448
433- let ( _rem , parsed ) = parse_x509_certificate ( ca. cert_der ( ) ) . unwrap ( ) ;
449+ let info = CertificateInfo :: from_der ( ca. cert_der ( ) ) . unwrap ( ) ;
434450
435- let san_ext = parsed
436- . tbs_certificate
437- . extensions ( )
438- . iter ( )
439- . find ( |ext| ext. oid == x509_parser:: oid_registry:: OID_X509_EXT_SUBJECT_ALT_NAME )
440- . expect ( "Subject Alternative Name extension not found" ) ;
441-
442- let san_value = san_ext. value ;
443-
444- let email_bytes = expected_email. as_bytes ( ) ;
445- let email_found = san_value
446- . windows ( email_bytes. len ( ) )
447- . any ( |window| window == email_bytes) ;
448-
449- assert ! (
450- email_found,
451- "Email '{expected_email}' should be present in Subject Alternative Names"
451+ assert_eq ! (
452+ info. subject_email. as_deref( ) ,
453+ Some ( expected_email) ,
454+ "Email should be parsed from Subject Alternative Names"
452455 ) ;
453456 }
454457
0 commit comments