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}