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
|
||||
pub enum Error {
|
||||
Fmt,
|
||||
InvalidForDate,
|
||||
X509(X509Error),
|
||||
}
|
||||
|
||||
|
@ -11,6 +12,7 @@ impl fmt::Display for Error {
|
|||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Fmt => write!(f, "FingerPrint: format error"),
|
||||
Self::InvalidForDate => write!(f, "FingerPrint: invalid for date"),
|
||||
Self::X509(e) => write!(f, "FingerPrint: {e}"),
|
||||
}
|
||||
}
|
||||
|
@ -19,8 +21,8 @@ impl fmt::Display for Error {
|
|||
impl std::error::Error for Error {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
match self {
|
||||
Self::Fmt => None,
|
||||
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;
|
||||
pub use error::Error;
|
||||
|
||||
/// Creates an sha256 fingerprint for a certificate
|
||||
pub trait Fingerprint {
|
||||
pub trait GetFingerprint {
|
||||
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;
|
||||
|
||||
fn fingerprint(&self) -> Result<(String, String), Self::Error> {
|
||||
fn fingerprint(&self) -> Result<Fingerprint, Self::Error> {
|
||||
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 mut hasher = Sha256::new();
|
||||
hasher.update(key);
|
||||
|
@ -24,6 +40,6 @@ impl Fingerprint for Certificate {
|
|||
for c in res {
|
||||
write!(s, "{c:02x}")?;
|
||||
}
|
||||
Ok((subject[3..].to_string(), s))
|
||||
Ok(Fingerprint { names, fingerprint: s })
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
pub use super::{
|
||||
certificate_store::CertificateStore,
|
||||
fingerprint::{Error as FingerprintError, Fingerprint},
|
||||
fingerprint::{Error as FingerprintError, Fingerprint, GetFingerprint},
|
||||
host::{Error as ParseHostError, Host},
|
||||
//receiver,
|
||||
request::{Error as ParseRequestError, Request},
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use {
|
||||
crate::prelude::{CertificateStore, Fingerprint},
|
||||
crate::prelude::{CertificateStore, Fingerprint, GetFingerprint},
|
||||
rustls::{
|
||||
client::{ServerCertVerified, ServerCertVerifier},
|
||||
Certificate,
|
||||
|
@ -40,17 +40,22 @@ impl<S: CertificateStore> ServerCertVerifier for Verifier<S> {
|
|||
let mut store = self.store.lock().unwrap();
|
||||
if let Some(fingerprint) = store.get_certificate(&name) {
|
||||
// TODO: needs a lot more checking for certificate validity
|
||||
if fingerprint == fp.1 && name == fp.0 {
|
||||
if fingerprint == fp.fingerprint {
|
||||
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 {
|
||||
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