Improve error handling in client certificate handling
Yield errors instead of panicking. Avoid unnecessary allocations/cloning.
This commit is contained in:
parent
af7911cbc3
commit
cbd9fd84aa
|
@ -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()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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()),
|
||||||
|
|
Loading…
Reference in New Issue