Improve error handling in client certificate handling

Yield errors instead of panicking. Avoid unnecessary allocations/cloning.
This commit is contained in:
Dirkjan Ochtman 2021-12-01 14:00:04 +01:00 committed by masalachai
parent af7911cbc3
commit cbd9fd84aa
2 changed files with 44 additions and 40 deletions

View File

@ -40,12 +40,15 @@
//! let tls = registry.tls_files().unwrap(); //! let tls = registry.tls_files().unwrap();
//! ``` //! ```
use std::collections::HashMap;
use std::fs::File;
use std::io::{BufReader, Seek, SeekFrom};
use rustls::{Certificate, PrivateKey}; use rustls::{Certificate, PrivateKey};
use rustls_pemfile; use rustls_pemfile;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::io::{Seek, SeekFrom}; use crate::error::Error;
use std::{fs, io};
/// Paths to the client certificate and client key PEM files /// Paths to the client certificate and client key PEM files
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
@ -85,51 +88,52 @@ impl EppClientConnection {
self.ext_uris.as_ref() self.ext_uris.as_ref()
} }
/// Returns the parsed client certificate and private key for client TLS auth /// Returns the parsed client certificate and private key for client TLS auth
pub fn tls_files(&self) -> Option<(Vec<Certificate>, PrivateKey)> { pub fn tls_files(&self) -> Result<Option<(Vec<Certificate>, PrivateKey)>, Error> {
let certificates = self.client_certificate(); match (self.client_certificate()?, self.key()?) {
let key = self.key(); (Some(certificates), Some(key)) => Ok(Some((certificates, key))),
_ => Ok(None),
if certificates == None || key == None {
None
} else {
Some((certificates.unwrap(), key.unwrap()))
} }
} }
/// Parses the client certificate chain /// Parses the client certificate chain
fn client_certificate(&self) -> Option<Vec<Certificate>> { fn client_certificate(&self) -> Result<Option<Vec<Certificate>>, Error> {
self.tls_files.as_ref().map(|tls| { let certs_file = match &self.tls_files {
rustls_pemfile::certs(&mut io::BufReader::new( Some(files) => &files.cert_chain,
fs::File::open(tls.cert_chain.to_string()).unwrap(), None => return Ok(None),
)) };
.unwrap()
.iter() Ok(Some(
.map(|v| Certificate(v.clone())) rustls_pemfile::certs(&mut BufReader::new(File::open(certs_file)?))?
.collect() .into_iter()
}) .map(Certificate)
.collect::<Vec<_>>(),
))
} }
/// Parses the client private key /// Parses the client private key
fn key(&self) -> Option<PrivateKey> { fn key(&self) -> Result<Option<PrivateKey>, Error> {
self.tls_files.as_ref().map(|tls| { let key_file = match &self.tls_files {
let mut r = io::BufReader::new(fs::File::open(tls.key.to_string()).unwrap()); Some(files) => &files.key,
None => return Ok(None),
};
let rsa_keys = rustls_pemfile::rsa_private_keys(&mut r).unwrap(); let mut r = BufReader::new(File::open(key_file).unwrap());
if rsa_keys.len() > 1 {
warn!("Multiple RSA keys found in PEM file {}", tls.key);
} else if !rsa_keys.is_empty() {
return rustls::PrivateKey(rsa_keys[0].clone());
}
r.seek(SeekFrom::Start(0)).unwrap(); let mut rsa_keys = rustls_pemfile::rsa_private_keys(&mut r).unwrap();
if rsa_keys.len() > 1 {
warn!("Multiple RSA keys found in PEM file {}", key_file);
} else if let Some(key) = rsa_keys.pop() {
return Ok(Some(rustls::PrivateKey(key)));
}
let pkcs8_keys = rustls_pemfile::pkcs8_private_keys(&mut r).unwrap(); r.seek(SeekFrom::Start(0))?;
if pkcs8_keys.len() > 1 {
warn!("Multiple PKCS8 keys found in PEM file {}", tls.key);
} else if !pkcs8_keys.is_empty() {
return rustls::PrivateKey(pkcs8_keys[0].clone());
}
panic!("No private key found in PEM file"); let mut pkcs8_keys = rustls_pemfile::pkcs8_private_keys(&mut r).unwrap();
}) if pkcs8_keys.len() > 1 {
warn!("Multiple PKCS8 keys found in PEM file {}", key_file);
} else if let Some(key) = pkcs8_keys.pop() {
return Ok(Some(rustls::PrivateKey(key)));
}
Err(Error::Other("No private key found in PEM file".to_owned()))
} }
} }

View File

@ -137,7 +137,7 @@ pub async fn epp_connect(
.with_safe_defaults() .with_safe_defaults()
.with_root_certificates(roots); .with_root_certificates(roots);
let config = match registry_creds.tls_files() { let config = match registry_creds.tls_files()? {
Some((cert_chain, key)) => match builder.with_single_cert(cert_chain, key) { Some((cert_chain, key)) => match builder.with_single_cert(cert_chain, key) {
Ok(config) => config, Ok(config) => config,
Err(e) => return Err(format!("Failed to set client TLS credentials: {}", e).into()), Err(e) => return Err(format!("Failed to set client TLS credentials: {}", e).into()),