mls_rs_crypto_rustcrypto/x509/
reader.rs1use mls_rs_identity_x509::{
6 DerCertificate, SubjectAltName as MlsSubjectAltName, SubjectComponent, X509CertificateReader,
7};
8use spki::der::{oid::AssociatedOid, Decode, Encode};
9use x509_cert::{
10 ext::pkix::{name::GeneralNames, SubjectAltName},
11 Certificate,
12};
13
14use crate::{ec::pub_key_to_uncompressed, ec_for_x509::pub_key_from_spki};
15
16use super::{
17 util::{general_names_to_alt_names, parse_x509_name},
18 X509Error,
19};
20
21#[derive(Debug, Clone, Default)]
22#[non_exhaustive]
23pub struct X509Reader {}
24
25impl X509Reader {
26 pub fn new() -> X509Reader {
27 Self {}
28 }
29}
30
31impl X509CertificateReader for X509Reader {
32 type Error = X509Error;
33
34 fn subject_bytes(&self, certificate: &DerCertificate) -> Result<Vec<u8>, Self::Error> {
35 Certificate::from_der(certificate)?
36 .tbs_certificate
37 .subject
38 .to_der()
39 .map_err(Into::into)
40 }
41
42 fn subject_components(
43 &self,
44 certificate: &DerCertificate,
45 ) -> Result<Vec<SubjectComponent>, Self::Error> {
46 parse_x509_name(&Certificate::from_der(certificate)?.tbs_certificate.subject)
47 }
48
49 fn subject_alt_names(
50 &self,
51 certificate: &DerCertificate,
52 ) -> Result<Vec<MlsSubjectAltName>, Self::Error> {
53 Ok(Certificate::from_der(certificate)?
54 .tbs_certificate
55 .extensions
56 .unwrap_or_default()
57 .iter()
58 .filter(|ext| ext.extn_id == SubjectAltName::OID)
59 .map(|ext| {
60 general_names_to_alt_names(&GeneralNames::from_der(ext.extn_value.as_bytes())?)
61 })
62 .collect::<Result<Vec<_>, _>>()?
63 .into_iter()
64 .flatten()
65 .collect::<Vec<_>>())
66 }
67
68 fn public_key(
69 &self,
70 certificate: &DerCertificate,
71 ) -> Result<mls_rs_core::crypto::SignaturePublicKey, Self::Error> {
72 let spki = Certificate::from_der(certificate)?
73 .tbs_certificate
74 .subject_public_key_info;
75
76 let pub_key = pub_key_from_spki(&spki)?;
77
78 pub_key_to_uncompressed(&pub_key)
79 .map_err(Into::into)
80 .map(Into::into)
81 }
82}
83
84#[cfg(test)]
85mod tests {
86 use mls_rs_identity_x509::{SubjectAltName, SubjectComponent, X509CertificateReader};
87 use spki::der::{
88 asn1::{SetOfVec, Utf8StringRef},
89 oid::db::rfc4519,
90 Any, Encode,
91 };
92 use x509_cert::{attr::AttributeTypeAndValue, name::RelativeDistinguishedName};
93
94 use crate::x509::{
95 util::test_utils::{load_github_leaf, load_ip_cert, load_test_ca},
96 X509Reader,
97 };
98
99 #[test]
100 fn subject_parser_bytes() {
101 let test_cert = load_test_ca();
102
103 let expected_type_and_value = AttributeTypeAndValue {
104 oid: rfc4519::CN,
105 value: Any::from(Utf8StringRef::new("CA").unwrap()),
106 };
107
108 let expected_rdn = RelativeDistinguishedName::from(
109 SetOfVec::try_from(vec![expected_type_and_value]).unwrap(),
110 );
111
112 let expected_name = vec![expected_rdn].to_der().unwrap();
113
114 assert_eq!(
115 X509Reader::new().subject_bytes(&test_cert).unwrap(),
116 expected_name
117 );
118 }
119
120 #[test]
121 fn subject_parser_components() {
122 let test_cert = load_github_leaf();
123
124 let expected = vec![
125 SubjectComponent::CountryName(String::from("US")),
126 SubjectComponent::State(String::from("California")),
127 SubjectComponent::Locality(String::from("San Francisco")),
128 SubjectComponent::OrganizationName(String::from("GitHub, Inc.")),
129 SubjectComponent::CommonName(String::from("github.com")),
130 ];
131
132 assert_eq!(
133 X509Reader::new().subject_components(&test_cert).unwrap(),
134 expected
135 )
136 }
137
138 #[test]
139 fn subject_alt_names() {
140 let test_cert = load_github_leaf();
141
142 let expected = vec![
143 SubjectAltName::Dns(String::from("github.com")),
144 SubjectAltName::Dns(String::from("www.github.com")),
145 ];
146
147 assert_eq!(
148 X509Reader::new().subject_alt_names(&test_cert).unwrap(),
149 expected
150 )
151 }
152
153 #[test]
154 fn subject_alt_names_ip() {
155 let test_cert = load_ip_cert();
156
157 let expected = vec![
158 SubjectAltName::Ip(String::from("97.97.97.254")),
159 SubjectAltName::Ip(String::from("97.97.97.253")),
160 ];
161
162 assert_eq!(
163 X509Reader::new().subject_alt_names(&test_cert).unwrap(),
164 expected
165 )
166 }
167}