rustls_cert_file_reader/
pem.rs

1//! Parse the PEM file format.
2
3use std::io::ErrorKind;
4
5/// Parse the certificates from PEM.
6pub fn parse_certs(
7    rd: &mut dyn std::io::BufRead,
8) -> Result<Vec<rustls_pki_types::CertificateDer<'static>>, std::io::Error> {
9    let mut certs = Vec::new();
10
11    loop {
12        let Some(item) = read_one(rd)? else {
13            return Ok(certs);
14        };
15        if let Some(cert) = cert_from_pemfile_item(item) {
16            certs.push(cert);
17        }
18    }
19}
20
21/// Parse the single private key from PEM (PKCS8).
22pub fn parse_key(
23    rd: &mut dyn std::io::BufRead,
24) -> Result<rustls_pki_types::PrivateKeyDer<'static>, std::io::Error> {
25    let key = loop {
26        let Some(item) = read_one(rd)? else {
27            return Err(std::io::Error::new(
28                ErrorKind::NotFound,
29                "no key found in the given data".to_string(),
30            ));
31        };
32        if let Some(key) = private_key_from_pemfile_item(item) {
33            break key;
34        }
35    };
36
37    // Assert there are no more keys present in the data.
38    loop {
39        let Some(item) = read_one(rd)? else {
40            break;
41        };
42
43        if private_key_from_pemfile_item(item).is_some() {
44            return Err(std::io::Error::new(
45                ErrorKind::InvalidInput,
46                "more than one key".to_string(),
47            ));
48        }
49    }
50
51    Ok(key)
52}
53
54/// A type representing a generic PEM file data item.
55type PemObjectTuple = (rustls_pki_types::pem::SectionKind, Vec<u8>);
56
57/// Read one item from a PEM file.
58fn read_one(rd: &mut dyn std::io::BufRead) -> Result<Option<PemObjectTuple>, std::io::Error> {
59    match rustls_pki_types::pem::from_buf(rd) {
60        Ok(item) => Ok(item),
61        Err(rustls_pki_types::pem::Error::Io(error)) => Err(error),
62        // Should not be possible, but we fallback here if it actually happens.
63        Err(error) => Err(std::io::Error::other(error)),
64    }
65}
66
67/// Obtain the private key from a the pemfile item.
68/// If the item is not a private key - returns None.
69fn private_key_from_pemfile_item(
70    (kind, der): PemObjectTuple,
71) -> Option<rustls_pki_types::PrivateKeyDer<'static>> {
72    <rustls_pki_types::PrivateKeyDer<'static> as rustls_pki_types::pem::PemObject>::from_pem(
73        kind, der,
74    )
75}
76
77/// Obtain the certificate from a the pemfile item.
78/// If the item is not a certificate - returns None.
79fn cert_from_pemfile_item(
80    (kind, der): PemObjectTuple,
81) -> Option<rustls_pki_types::CertificateDer<'static>> {
82    <rustls_pki_types::CertificateDer<'static> as rustls_pki_types::pem::PemObject>::from_pem(
83        kind, der,
84    )
85}