Add handling of certs with multiple common names; Check certs for
validity against current date;
This commit is contained in:
parent
0d15b8d24b
commit
2b7119610c
4 changed files with 39 additions and 16 deletions
|
@ -4,6 +4,7 @@ use {std::fmt, x509_parser::prelude::X509Error};
|
||||||
/// Errors which can occur when fingerprinting a certificate
|
/// Errors which can occur when fingerprinting a certificate
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
Fmt,
|
Fmt,
|
||||||
|
InvalidForDate,
|
||||||
X509(X509Error),
|
X509(X509Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +12,7 @@ impl fmt::Display for Error {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::Fmt => write!(f, "FingerPrint: format error"),
|
Self::Fmt => write!(f, "FingerPrint: format error"),
|
||||||
|
Self::InvalidForDate => write!(f, "FingerPrint: invalid for date"),
|
||||||
Self::X509(e) => write!(f, "FingerPrint: {e}"),
|
Self::X509(e) => write!(f, "FingerPrint: {e}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,8 +21,8 @@ impl fmt::Display for Error {
|
||||||
impl std::error::Error for Error {
|
impl std::error::Error for Error {
|
||||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||||
match self {
|
match self {
|
||||||
Self::Fmt => None,
|
|
||||||
Self::X509(e) => Some(e),
|
Self::X509(e) => Some(e),
|
||||||
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,37 @@
|
||||||
use {digest::Digest, rustls::Certificate, sha2::Sha256, std::fmt::Write, x509_parser::prelude::*};
|
use {digest::Digest, rustls::Certificate, sha2::Sha256, std::{io::Read, fmt::Write}, x509_parser::prelude::*};
|
||||||
|
|
||||||
mod error;
|
mod error;
|
||||||
pub use error::Error;
|
pub use error::Error;
|
||||||
|
|
||||||
/// Creates an sha256 fingerprint for a certificate
|
/// Creates an sha256 fingerprint for a certificate
|
||||||
pub trait Fingerprint {
|
pub trait GetFingerprint {
|
||||||
type Error;
|
type Error;
|
||||||
|
|
||||||
fn fingerprint(&self) -> Result<(String, String), Self::Error>;
|
fn fingerprint(&self) -> Result<Fingerprint, Self::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Fingerprint for Certificate {
|
pub struct Fingerprint {
|
||||||
|
pub names: Vec<String>,
|
||||||
|
pub fingerprint: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetFingerprint for Certificate {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn fingerprint(&self) -> Result<(String, String), Self::Error> {
|
fn fingerprint(&self) -> Result<Fingerprint, Self::Error> {
|
||||||
let (_, pk) = X509Certificate::from_der(self.as_ref())?;
|
let (_, pk) = X509Certificate::from_der(self.as_ref())?;
|
||||||
let subject = pk.subject().to_string();
|
let subject = pk.subject();
|
||||||
|
let mut names = vec![];
|
||||||
|
subject.iter_common_name().for_each(|n| {
|
||||||
|
let mut val = n.attr_value().data;
|
||||||
|
let mut name = String::new();
|
||||||
|
if let Ok(_) = val.read_to_string(&mut name) {
|
||||||
|
names.push(name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if !pk.validity().is_valid() {
|
||||||
|
return Err(Error::InvalidForDate);
|
||||||
|
}
|
||||||
let key = pk.public_key().subject_public_key.as_ref();
|
let key = pk.public_key().subject_public_key.as_ref();
|
||||||
let mut hasher = Sha256::new();
|
let mut hasher = Sha256::new();
|
||||||
hasher.update(key);
|
hasher.update(key);
|
||||||
|
@ -24,6 +40,6 @@ impl Fingerprint for Certificate {
|
||||||
for c in res {
|
for c in res {
|
||||||
write!(s, "{c:02x}")?;
|
write!(s, "{c:02x}")?;
|
||||||
}
|
}
|
||||||
Ok((subject[3..].to_string(), s))
|
Ok(Fingerprint { names, fingerprint: s })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
pub use super::{
|
pub use super::{
|
||||||
certificate_store::CertificateStore,
|
certificate_store::CertificateStore,
|
||||||
fingerprint::{Error as FingerprintError, Fingerprint},
|
fingerprint::{Error as FingerprintError, Fingerprint, GetFingerprint},
|
||||||
host::{Error as ParseHostError, Host},
|
host::{Error as ParseHostError, Host},
|
||||||
//receiver,
|
//receiver,
|
||||||
request::{Error as ParseRequestError, Request},
|
request::{Error as ParseRequestError, Request},
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use {
|
use {
|
||||||
crate::prelude::{CertificateStore, Fingerprint},
|
crate::prelude::{CertificateStore, Fingerprint, GetFingerprint},
|
||||||
rustls::{
|
rustls::{
|
||||||
client::{ServerCertVerified, ServerCertVerifier},
|
client::{ServerCertVerified, ServerCertVerifier},
|
||||||
Certificate,
|
Certificate,
|
||||||
|
@ -40,17 +40,22 @@ impl<S: CertificateStore> ServerCertVerifier for Verifier<S> {
|
||||||
let mut store = self.store.lock().unwrap();
|
let mut store = self.store.lock().unwrap();
|
||||||
if let Some(fingerprint) = store.get_certificate(&name) {
|
if let Some(fingerprint) = store.get_certificate(&name) {
|
||||||
// TODO: needs a lot more checking for certificate validity
|
// TODO: needs a lot more checking for certificate validity
|
||||||
if fingerprint == fp.1 && name == fp.0 {
|
if fingerprint == fp.fingerprint {
|
||||||
return Ok(ServerCertVerified::assertion());
|
for n in fp.names {
|
||||||
|
if n == name {
|
||||||
|
return Ok(ServerCertVerified::assertion());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(rustls::Error::InvalidCertificate(rustls::CertificateError::NotValidForName))
|
||||||
|
} else {
|
||||||
|
Err(rustls::Error::InvalidCertificate(rustls::CertificateError::NotValidForName))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if !store.contains_certificate(&name) {
|
if !store.contains_certificate(&name) {
|
||||||
let _key = store.borrow_mut().insert_certificate(&name, &fp.1);
|
let _key = store.borrow_mut().insert_certificate(&name, &fp.fingerprint);
|
||||||
}
|
}
|
||||||
|
return Ok(ServerCertVerified::assertion());
|
||||||
}
|
}
|
||||||
Err(rustls::Error::General(
|
|
||||||
"Unrecognized certificate".to_string(),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue