use std::error::Error; use std::io::{Cursor, ErrorKind}; use rustls::{Certificate, PrivateKey}; use rustls_pemfile::Item; /// Parse PEM certificates bytes into a [`rustls::Certificate`] structure /// /// An error is returned if not any certificate could be found pub fn parse_pem_certificates(certs: &[u8]) -> Result, Box> { let certs = rustls_pemfile::certs(&mut Cursor::new(certs)) .map(|c| c.map(|c| Certificate(c.to_vec()))) .collect::, _>>()?; if certs.is_empty() { Err(std::io::Error::new( ErrorKind::InvalidData, "Could not find any certificate!", ))?; unreachable!(); } Ok(certs) } /// Parse PEM private key bytes into a [`rustls::PrivateKey`] structure pub fn parse_pem_private_key(privkey: &[u8]) -> Result> { let key = match rustls_pemfile::read_one(&mut Cursor::new(privkey))? { None => { Err(std::io::Error::new( ErrorKind::Other, "Failed to extract private key!", ))?; unreachable!() } Some(Item::Pkcs8Key(key)) => key.secret_pkcs8_der().to_vec(), Some(Item::Pkcs1Key(key)) => key.secret_pkcs1_der().to_vec(), _ => { Err(std::io::Error::new( ErrorKind::Other, "Unsupported private key type!", ))?; unreachable!(); } }; Ok(PrivateKey(key)) } #[cfg(test)] mod test { use crate::base::cert_utils::{parse_pem_certificates, parse_pem_private_key}; const SAMPLE_CERT: &[u8] = include_bytes!("samples/TCPTunnelTest.crt"); const SAMPLE_KEY: &[u8] = include_bytes!("samples/TCPTunnelTest.key"); #[test] fn parse_valid_cert() { parse_pem_certificates(SAMPLE_CERT).unwrap(); } #[test] fn parse_invalid_cert_1() { parse_pem_certificates("Random content".as_bytes()).unwrap_err(); } #[test] fn parse_invalid_cert_2() { parse_pem_certificates(SAMPLE_KEY).unwrap_err(); } #[test] fn parse_valid_key() { parse_pem_private_key(SAMPLE_KEY).unwrap(); } #[test] fn parse_invalid_key_1() { parse_pem_private_key("Random content".as_bytes()).unwrap_err(); } #[test] fn parse_invalid_key_2() { parse_pem_private_key(SAMPLE_CERT).unwrap_err(); } }