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
use rustls::{Certificate, PrivateKey};
use std::fmt;
use std::io::Cursor;

#[derive(Clone)]
pub struct ClientCertInfo {
    certificates: Vec<Certificate>,
    key: PrivateKey,
}

impl fmt::Debug for ClientCertInfo {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.certs().fmt(f)
    }
}

#[derive(Debug, thiserror::Error)]
pub enum ClientCertError {
    #[error("Certificate/key read error: {0}")]
    CertificateRead(#[from] std::io::Error),
    #[error("No keys found for client certificate")]
    NoKeysFound,
    #[error("Too many keys found for client certificate (found {0})")]
    TooManyKeys(usize),
}

impl ClientCertInfo {
    pub fn new(certificate_bytes: &[u8], certificate_key: &[u8]) -> Result<Self, ClientCertError> {
        let mut certificate_bytes_reader = Cursor::new(certificate_bytes);
        let mut key_bytes_reader = Cursor::new(certificate_key);
        let cert_info = rustls_pemfile::read_all(&mut certificate_bytes_reader)?;
        let key_info = rustls_pemfile::read_all(&mut key_bytes_reader)?;

        let mut certificates = Vec::new();
        let mut keys = Vec::new();

        for item in cert_info.into_iter().chain(key_info) {
            match item {
                rustls_pemfile::Item::X509Certificate(x) => certificates.push(Certificate(x)),
                rustls_pemfile::Item::RSAKey(x) => keys.push(PrivateKey(x)),
                rustls_pemfile::Item::PKCS8Key(x) => keys.push(PrivateKey(x)),
                rustls_pemfile::Item::ECKey(x) => keys.push(PrivateKey(x)),
                _ => {}
            }
        }

        let key = if keys.is_empty() {
            return Err(ClientCertError::NoKeysFound);
        } else if keys.len() > 1 {
            return Err(ClientCertError::TooManyKeys(keys.len()));
        } else {
            keys.remove(0)
        };

        Ok(ClientCertInfo { certificates, key })
    }

    pub fn certs(&self) -> Vec<Certificate> {
        self.certificates.clone()
    }

    pub fn key(&self) -> PrivateKey {
        self.key.clone()
    }
}