x509_parser/validate/mod.rs
1mod certificate;
2mod extensions;
3mod loggers;
4mod name;
5mod structure;
6use std::marker::PhantomData;
7
8pub use certificate::*;
9pub use extensions::*;
10pub use loggers::*;
11pub use name::*;
12pub use structure::*;
13
14/// Trait for validating item (for ex. validate X.509 structure)
15///
16/// # Examples
17///
18/// Using callbacks:
19///
20/// ```
21/// use x509_parser::certificate::X509Certificate;
22/// # #[allow(deprecated)]
23/// use x509_parser::validate::Validate;
24/// # #[allow(deprecated)]
25/// #[cfg(feature = "validate")]
26/// fn validate_certificate(x509: &X509Certificate<'_>) -> Result<(), &'static str> {
27/// println!(" Subject: {}", x509.subject());
28/// // validate and print warnings and errors to stderr
29/// let ok = x509.validate(
30/// |msg| {
31/// eprintln!(" [W] {}", msg);
32/// },
33/// |msg| {
34/// eprintln!(" [E] {}", msg);
35/// },
36/// );
37/// print!("Structure validation status: ");
38/// if ok {
39/// println!("Ok");
40/// Ok(())
41/// } else {
42/// println!("FAIL");
43/// Err("validation failed")
44/// }
45/// }
46/// ```
47///
48/// Collecting warnings and errors to `Vec`:
49///
50/// ```
51/// use x509_parser::certificate::X509Certificate;
52/// # #[allow(deprecated)]
53/// use x509_parser::validate::Validate;
54///
55/// # #[allow(deprecated)]
56/// #[cfg(feature = "validate")]
57/// fn validate_certificate(x509: &X509Certificate<'_>) -> Result<(), &'static str> {
58/// println!(" Subject: {}", x509.subject());
59/// // validate and print warnings and errors to stderr
60/// let (ok, warnings, errors) = x509.validate_to_vec();
61/// print!("Structure validation status: ");
62/// if ok {
63/// println!("Ok");
64/// } else {
65/// println!("FAIL");
66/// }
67/// for warning in &warnings {
68/// eprintln!(" [W] {}", warning);
69/// }
70/// for error in &errors {
71/// eprintln!(" [E] {}", error);
72/// }
73/// println!();
74/// if !errors.is_empty() {
75/// return Err("validation failed");
76/// }
77/// Ok(())
78/// }
79/// ```
80#[deprecated(since = "0.13.0", note = "please use `X509StructureValidator` instead")]
81pub trait Validate {
82 /// Attempts to validate current item.
83 ///
84 /// Returns `true` if item was validated.
85 ///
86 /// Call `warn()` if a non-fatal error was encountered, and `err()`
87 /// if the error is fatal. These fucntions receive a description of the error.
88 fn validate<W, E>(&self, warn: W, err: E) -> bool
89 where
90 W: FnMut(&str),
91 E: FnMut(&str);
92
93 /// Attempts to validate current item, storing warning and errors in `Vec`.
94 ///
95 /// Returns the validation result (`true` if validated), the list of warnings,
96 /// and the list of errors.
97 fn validate_to_vec(&self) -> (bool, Vec<String>, Vec<String>) {
98 let mut warn_list = Vec::new();
99 let mut err_list = Vec::new();
100 let res = self.validate(
101 |s| warn_list.push(s.to_owned()),
102 |s| err_list.push(s.to_owned()),
103 );
104 (res, warn_list, err_list)
105 }
106}
107
108/// Trait for build item validators (for ex. validate X.509 structure)
109///
110/// See [`X509StructureValidator`] for a default implementation, validating the
111/// DER structure of a X.509 Certificate.
112///
113/// See implementors of the [`Logger`] trait for methods to collect or handle warnings and errors.
114///
115/// # Examples
116///
117/// Collecting warnings and errors to `Vec`:
118///
119/// ```
120/// use x509_parser::certificate::X509Certificate;
121/// use x509_parser::validate::*;
122///
123/// # #[allow(deprecated)]
124/// #[cfg(feature = "validate")]
125/// fn validate_certificate(x509: &X509Certificate<'_>) -> Result<(), &'static str> {
126/// let mut logger = VecLogger::default();
127/// println!(" Subject: {}", x509.subject());
128/// // validate and print warnings and errors to stderr
129/// let ok = X509StructureValidator.validate(&x509, &mut logger);
130/// print!("Structure validation status: ");
131/// if ok {
132/// println!("Ok");
133/// } else {
134/// println!("FAIL");
135/// }
136/// for warning in logger.warnings() {
137/// eprintln!(" [W] {}", warning);
138/// }
139/// for error in logger.errors() {
140/// eprintln!(" [E] {}", error);
141/// }
142/// println!();
143/// if !logger.errors().is_empty() {
144/// return Err("validation failed");
145/// }
146/// Ok(())
147/// }
148/// ```
149pub trait Validator<'a> {
150 /// The item to validate
151 type Item;
152
153 /// Attempts to validate current item.
154 ///
155 /// Returns `true` if item was validated.
156 ///
157 /// Call `l.warn()` if a non-fatal error was encountered, and `l.err()`
158 /// if the error is fatal. These functions receive a description of the error.
159 fn validate<L: Logger>(&self, item: &'a Self::Item, l: &'_ mut L) -> bool;
160
161 fn chain<V2>(self, v2: V2) -> ChainValidator<'a, Self, V2, Self::Item>
162 where
163 Self: Sized,
164 V2: Validator<'a, Item = Self::Item>,
165 {
166 ChainValidator {
167 v1: self,
168 v2,
169 _p: PhantomData,
170 }
171 }
172}
173
174#[derive(Debug)]
175pub struct ChainValidator<'a, A, B, I>
176where
177 A: Validator<'a, Item = I>,
178 B: Validator<'a, Item = I>,
179{
180 v1: A,
181 v2: B,
182 _p: PhantomData<&'a ()>,
183}
184
185impl<'a, A, B, I> Validator<'a> for ChainValidator<'a, A, B, I>
186where
187 A: Validator<'a, Item = I>,
188 B: Validator<'a, Item = I>,
189{
190 type Item = I;
191
192 fn validate<L: Logger>(&'_ self, item: &'a Self::Item, l: &'_ mut L) -> bool {
193 self.v1.validate(item, l) & self.v2.validate(item, l)
194 }
195}
196
197#[allow(deprecated)]
198#[cfg(test)]
199mod tests {
200 use crate::validate::*;
201
202 struct V1 {
203 a: u32,
204 }
205
206 impl Validate for V1 {
207 fn validate<W, E>(&self, mut warn: W, _err: E) -> bool
208 where
209 W: FnMut(&str),
210 E: FnMut(&str),
211 {
212 if self.a > 10 {
213 warn("a is greater than 10");
214 }
215 true
216 }
217 }
218
219 struct V1Validator;
220
221 impl<'a> Validator<'a> for V1Validator {
222 type Item = V1;
223
224 fn validate<L: Logger>(&self, item: &'a Self::Item, l: &'_ mut L) -> bool {
225 if item.a > 10 {
226 l.warn("a is greater than 10");
227 }
228 true
229 }
230 }
231
232 #[test]
233 fn validate_warn() {
234 let v1 = V1 { a: 1 };
235 let (res, warn, err) = v1.validate_to_vec();
236 assert!(res);
237 assert!(warn.is_empty());
238 assert!(err.is_empty());
239 // same, with one warning
240 let v20 = V1 { a: 20 };
241 let (res, warn, err) = v20.validate_to_vec();
242 assert!(res);
243 assert_eq!(warn, vec!["a is greater than 10".to_string()]);
244 assert!(err.is_empty());
245 }
246
247 #[test]
248 fn validator_warn() {
249 let mut logger = VecLogger::default();
250 let v1 = V1 { a: 1 };
251 let res = V1Validator.validate(&v1, &mut logger);
252 assert!(res);
253 assert!(logger.warnings().is_empty());
254 assert!(logger.errors().is_empty());
255 // same, with one warning
256 let v20 = V1 { a: 20 };
257 let res = V1Validator.validate(&v20, &mut logger);
258 assert!(res);
259 assert_eq!(logger.warnings(), &["a is greater than 10".to_string()]);
260 assert!(logger.errors().is_empty());
261 }
262}