x509_parser/validate/
structure.rs1use super::{Logger, Validator, X509NameStructureValidator};
2use crate::certificate::*;
3use crate::extensions::{GeneralName, ParsedExtension};
4use crate::public_key::PublicKey;
5use crate::x509::{SubjectPublicKeyInfo, X509Version};
6
7#[derive(Debug, Default)]
49pub struct X509StructureValidator;
50
51impl<'a> Validator<'a> for X509StructureValidator {
52 type Item = X509Certificate<'a>;
53
54 fn validate<L: Logger>(&self, item: &'a Self::Item, l: &'_ mut L) -> bool {
55 let mut res = true;
56 res &= TbsCertificateStructureValidator.validate(&item.tbs_certificate, l);
57 res
58 }
59}
60
61#[derive(Debug, Default)]
63pub struct TbsCertificateStructureValidator;
64
65impl<'a> Validator<'a> for TbsCertificateStructureValidator {
66 type Item = TbsCertificate<'a>;
67
68 fn validate<L: Logger>(&self, item: &'a Self::Item, l: &'_ mut L) -> bool {
69 let mut res = true;
70 if item.version.0 >= 3 {
72 l.err("Invalid version");
73 res = false;
74 }
75 let b = item.raw_serial();
76 if b.is_empty() {
77 l.err("Serial is empty");
78 res = false;
79 } else {
80 if b[0] & 0x80 != 0 {
82 l.warn("Serial number is negative");
83 }
84 if b.len() > 1 && b[0] == 0 && b[1] & 0x80 == 0 {
86 l.warn("Leading zeroes in serial number");
87 }
88 }
89 res &= X509NameStructureValidator.validate(&item.subject, l);
91 res &= X509NameStructureValidator.validate(&item.issuer, l);
92 res &= X509PublicKeyValidator.validate(&item.subject_pki, l);
94 let validity = item.validity();
96 let year_notbefore = validity.not_before.to_datetime().year();
97 if year_notbefore <= 2049 {
98 if !validity.not_before.is_utctime() {
99 l.warn("year <= 2049 should use UTCTime (notBefore)");
100 }
101 } else if !validity.not_before.is_generalizedtime() {
102 l.warn("year >= 2050 should use GeneralizedTime (notBefore)");
103 }
104 let year_notafter = validity.not_after.to_datetime().year();
105 if year_notafter <= 2049 {
106 if !validity.not_after.is_utctime() {
107 l.warn("year <= 2049 should use UTCTime (notAfter)");
108 }
109 } else if !validity.not_after.is_generalizedtime() {
110 l.warn("year >= 2050 should use GeneralizedTime (notAfter)");
111 }
112 if item.version == X509Version::V1 {
113 if item.issuer_uid.is_some() {
115 l.warn("issuerUniqueID present but version 1");
116 }
117 if item.subject_uid.is_some() {
118 l.warn("subjectUniqueID present but version 1");
119 }
120 }
121 if !item.extensions().is_empty() && item.version != X509Version::V3 {
123 l.err("Extensions present but version is not 3");
124 res = false;
125 }
126 for ext in item.extensions() {
128 if let ParsedExtension::UnsupportedExtension { .. } = &ext.parsed_extension {
129 l.warn(&format!("Unsupported extension {}", ext.oid));
130 }
131 if let ParsedExtension::ParseError { error } = &ext.parsed_extension {
132 l.err(&format!("Parse error in extension {}: {}", ext.oid, error));
133 res = false;
134 }
135 }
136 for ext in item.extensions() {
138 if let ParsedExtension::SubjectAlternativeName(san) = ext.parsed_extension() {
141 for name in &san.general_names {
142 match name {
143 GeneralName::DNSName(ref s) | GeneralName::RFC822Name(ref s) => {
144 if !s.as_bytes().iter().all(u8::is_ascii) {
146 l.warn(&format!("Invalid charset in 'SAN' entry '{}'", s));
147 }
148 }
149 _ => (),
150 }
151 }
152 }
153 }
154 res
155 }
156}
157
158#[derive(Debug, Default)]
159pub struct X509PublicKeyValidator;
160
161impl<'a> Validator<'a> for X509PublicKeyValidator {
162 type Item = SubjectPublicKeyInfo<'a>;
163
164 fn validate<L: Logger>(&self, item: &'a Self::Item, l: &'_ mut L) -> bool {
165 let mut res = true;
166 match item.parsed() {
168 Ok(PublicKey::RSA(rsa)) => {
169 if rsa.modulus[0] & 0x80 != 0 {
170 l.warn("Public key: (RSA) modulus is negative");
171 }
172 if rsa.exponent[0] & 0x80 != 0 {
173 l.warn("Public key: (RSA) exponent is negative");
174 }
175 }
176 Ok(PublicKey::Unknown(_b)) => {
177 l.warn("Unknown public key type");
178 }
179 Ok(_) => {}
180 Err(_) => {
181 l.err("Invalid public key");
182 res = false;
183 }
184 }
185 res
186 }
187}