rustls_cert_file_reader/
pem.rs

1//! Parse the PEM file format.
2
3use std::io::ErrorKind;
4
5use rustls_pemfile::{read_one, Item};
6
7/// Parse the certificates from PEM.
8pub fn parse_certs(
9    rd: &mut dyn std::io::BufRead,
10) -> Result<Vec<rustls_pki_types::CertificateDer<'static>>, std::io::Error> {
11    let mut certs = Vec::new();
12
13    loop {
14        let Some(item) = read_one(rd)? else {
15            return Ok(certs);
16        };
17        if let Item::X509Certificate(cert) = item {
18            certs.push(cert);
19        }
20    }
21}
22
23/// Parse the signle private key from PEM (PKCS8).
24pub fn parse_key(
25    rd: &mut dyn std::io::BufRead,
26) -> Result<rustls_pki_types::PrivateKeyDer<'static>, std::io::Error> {
27    let key = loop {
28        let Some(item) = read_one(rd)? else {
29            return Err(std::io::Error::new(
30                ErrorKind::NotFound,
31                "no key found in the given data".to_string(),
32            ));
33        };
34        if let Some(key) = private_key_from_pemfile_item(item) {
35            break key;
36        }
37    };
38
39    // Assert there are no more keys present in the data.
40    loop {
41        let Some(item) = read_one(rd)? else {
42            break;
43        };
44
45        if private_key_from_pemfile_item(item).is_some() {
46            return Err(std::io::Error::new(
47                ErrorKind::InvalidInput,
48                "more than one key".to_string(),
49            ));
50        }
51    }
52
53    Ok(key)
54}
55
56/// Obtain the private key from a the pemfile item.
57/// If the item is not a private key - returns None.
58fn private_key_from_pemfile_item(
59    item: rustls_pemfile::Item,
60) -> Option<rustls_pki_types::PrivateKeyDer<'static>> {
61    Some(match item {
62        Item::Pkcs1Key(key) => key.into(),
63        Item::Pkcs8Key(key) => key.into(),
64        Item::Sec1Key(key) => key.into(),
65        _ => return None,
66    })
67}