Finish implementing TOFU for Verifier;
TODO: additional checks for certificate validity;
This commit is contained in:
parent
ac5f2c21eb
commit
0d15b8d24b
6 changed files with 73 additions and 36 deletions
36
src/certificate_store.rs
Normal file
36
src/certificate_store.rs
Normal file
|
@ -0,0 +1,36 @@
|
|||
use std::collections::{BTreeMap, HashMap};
|
||||
|
||||
/// An item which stores known certificates
|
||||
pub trait CertificateStore: Send + Sync {
|
||||
fn get_certificate(&self, host: &str) -> Option<String>;
|
||||
fn insert_certificate(&mut self, host: &str, fingerprint: &str) -> Option<String>;
|
||||
fn contains_certificate(&self, host: &str) -> bool;
|
||||
}
|
||||
|
||||
impl CertificateStore for HashMap<String, String> {
|
||||
fn get_certificate(&self, host: &str) -> Option<String> {
|
||||
self.get(host).cloned()
|
||||
}
|
||||
|
||||
fn insert_certificate(&mut self, host: &str, fingerprint: &str) -> Option<String> {
|
||||
self.insert(host.to_string(), fingerprint.to_string())
|
||||
}
|
||||
|
||||
fn contains_certificate(&self, host: &str) -> bool {
|
||||
self.contains_key(host)
|
||||
}
|
||||
}
|
||||
|
||||
impl CertificateStore for BTreeMap<String, String> {
|
||||
fn get_certificate(&self, host: &str) -> Option<String> {
|
||||
self.get(host).cloned()
|
||||
}
|
||||
|
||||
fn insert_certificate(&mut self, host: &str, fingerprint: &str) -> Option<String> {
|
||||
self.insert(host.to_string(), fingerprint.to_string())
|
||||
}
|
||||
|
||||
fn contains_certificate(&self, host: &str) -> bool {
|
||||
self.contains_key(host)
|
||||
}
|
||||
}
|
|
@ -1,8 +1,4 @@
|
|||
use digest::Digest;
|
||||
use rustls::Certificate;
|
||||
use sha2::Sha256;
|
||||
use std::fmt::Write;
|
||||
use x509_parser::prelude::*;
|
||||
use {digest::Digest, rustls::Certificate, sha2::Sha256, std::fmt::Write, x509_parser::prelude::*};
|
||||
|
||||
mod error;
|
||||
pub use error::Error;
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
#![warn(clippy::all, clippy::pedantic)]
|
||||
mod certificate_store;
|
||||
mod fingerprint;
|
||||
mod host;
|
||||
pub mod prelude;
|
||||
pub mod receiver;
|
||||
mod receiver;
|
||||
mod request;
|
||||
mod response;
|
||||
mod sender;
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
pub use super::{
|
||||
certificate_store::CertificateStore,
|
||||
fingerprint::{Error as FingerprintError, Fingerprint},
|
||||
host::{Error as ParseHostError, Host},
|
||||
receiver,
|
||||
//receiver,
|
||||
request::{Error as ParseRequestError, Request},
|
||||
response::{Error as ParseResponseError, Response},
|
||||
sender::{CertificateStore, Error as SenderError, Sender, Verifier},
|
||||
sender::{Error as SenderError, Sender, Verifier},
|
||||
status::{
|
||||
AuthenticationFailure, Error as ParseStatusError, PermanentFailure, Redirect, Status,
|
||||
TemporaryFailure,
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
pub use self::{
|
||||
error::Error,
|
||||
verifier::{CertificateStore, Verifier},
|
||||
pub use self::{error::Error, verifier::Verifier};
|
||||
use {
|
||||
crate::prelude::{CertificateStore, Request, Response},
|
||||
std::io::{Read, Write},
|
||||
};
|
||||
use crate::{request::Request, response::Response};
|
||||
use std::io::{Read, Write};
|
||||
|
||||
mod error;
|
||||
mod verifier;
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
use crate::fingerprint::Fingerprint;
|
||||
use rustls::{
|
||||
use {
|
||||
crate::prelude::{CertificateStore, Fingerprint},
|
||||
rustls::{
|
||||
client::{ServerCertVerified, ServerCertVerifier},
|
||||
Certificate,
|
||||
},
|
||||
std::{
|
||||
borrow::BorrowMut,
|
||||
sync::{Arc, Mutex},
|
||||
time,
|
||||
},
|
||||
};
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
/// An item which stores known certificates
|
||||
pub trait CertificateStore: Send + Sync {
|
||||
fn get(&self, host: &str) -> Option<String>;
|
||||
fn insert(&mut self, host: &str, fingerprint: &str);
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
/// A verifier is used to verify certificates sent by the receiving server
|
||||
|
@ -27,7 +27,7 @@ impl<S: CertificateStore> ServerCertVerifier for Verifier<S> {
|
|||
server_name: &rustls::ServerName,
|
||||
_scts: &mut dyn Iterator<Item = &[u8]>,
|
||||
_ocsp_response: &[u8],
|
||||
_now: std::time::SystemTime,
|
||||
_now: time::SystemTime,
|
||||
) -> Result<ServerCertVerified, rustls::Error> {
|
||||
let fp = end_entity
|
||||
.fingerprint()
|
||||
|
@ -37,18 +37,16 @@ impl<S: CertificateStore> ServerCertVerifier for Verifier<S> {
|
|||
rustls::ServerName::IpAddress(ip) => ip.to_string(),
|
||||
_ => todo!(),
|
||||
};
|
||||
if let Some(fingerprint) = match server_name {
|
||||
rustls::ServerName::DnsName(n) => self.store.lock().unwrap().get(n.as_ref()),
|
||||
rustls::ServerName::IpAddress(ip) => self.store.lock().unwrap().get(&ip.to_string()),
|
||||
_ => todo!(),
|
||||
} {
|
||||
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 {
|
||||
return Ok(ServerCertVerified::assertion());
|
||||
}
|
||||
} else {
|
||||
// todo: need a way to update `self.store`. Probably will require
|
||||
// an Arc<Mutex<T>> for interior mutability.
|
||||
// UPDATE: Now wrapped in Arc<Mutex<T>>
|
||||
if !store.contains_certificate(&name) {
|
||||
let _key = store.borrow_mut().insert_certificate(&name, &fp.1);
|
||||
}
|
||||
}
|
||||
Err(rustls::Error::General(
|
||||
"Unrecognized certificate".to_string(),
|
||||
|
@ -56,10 +54,16 @@ impl<S: CertificateStore> ServerCertVerifier for Verifier<S> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: CertificateStore> Verifier<T> {
|
||||
pub fn new(store: T) -> Self {
|
||||
impl<T: CertificateStore> From<T> for Verifier<T> {
|
||||
fn from(value: T) -> Self {
|
||||
Self {
|
||||
store: Arc::new(Mutex::new(store)),
|
||||
store: Arc::new(Mutex::new(value)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: CertificateStore> Verifier<T> {
|
||||
pub fn new(store: T) -> Self {
|
||||
store.into()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue