1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
use thiserror::Error;
use x509_parser::{self, error as x509_errors, nom::Err as NomErr, pem::Pem};
pub use x509_parser::certificate::X509Certificate;
#[derive(Debug, Error)]
pub enum X509Error {
#[error("PEM content could not be parsed: {0}")]
PEMError(#[from] x509_errors::PEMError),
#[error("X509 content could not be parsed: {0}")]
X509Error(#[from] NomErr<x509_errors::X509Error>),
#[error("PEM is not a certificate: {0}")]
WrongPEMType(String),
#[error("no certificate was found in PEM")]
EmptyPEM,
}
pub fn parse_certificate_chain(pem_bytes: &[u8]) -> Result<Vec<Pem>, X509Error> {
let pems: Vec<Pem> = Pem::iter_from_buffer(pem_bytes)
.map(|res| match res {
Ok(pem) => {
if pem.label != "CERTIFICATE" {
return Err(X509Error::WrongPEMType(pem.label));
}
Ok(pem)
}
Err(e) => Err(e.into()),
})
.collect::<Result<Vec<Pem>, _>>()?
.into_iter()
.rev()
.collect();
if pems.is_empty() {
return Err(X509Error::EmptyPEM);
}
Ok(pems)
}
pub fn parse_x509_certificate(pem: &Pem) -> Result<X509Certificate, X509Error> {
let (_, cert) = x509_parser::parse_x509_certificate(&pem.contents)?;
Ok(cert)
}
#[cfg(test)]
mod tests {
use super::parse_certificate_chain;
#[test]
fn test_bad_pem_content() {
let expectations: Vec<(&str, &str)> = vec![
("", "no certificate was found in PEM"),
("1", "no certificate was found in PEM"),
("%^", "no certificate was found in PEM"),
(
"\
-----BEGIN ENCRYPTED PRIVATE KEY-----
bGxhIEFNTyBQcm9kdWN0aW9uIFNpZ25pbmcgU2VydmljZTFFMEMGA1UEAww8Q29u
-----END ENCRYPTED PRIVATE KEY-----",
"PEM is not a certificate: ENCRYPTED",
),
(
"\
-----BEGIN CERTIFICATE-----
invalidCertificate
-----END CERTIFICATE-----",
"PEM content could not be parsed: base64 decode error",
),
(
"\
-----BEGIN CERTIFICATE-----
bGxhIEFNTyBQcm9kdWN0aW9uIFNp
-----BEGIN CERTIFICATE-----",
"PEM content could not be parsed: incomplete PEM",
),
];
for (input, error) in expectations {
let err = parse_certificate_chain(input.as_bytes()).unwrap_err();
assert_eq!(err.to_string(), error);
}
}
}