From 0d15b8d24beed26c9c5f992e8e91ba0ee67a592a Mon Sep 17 00:00:00 2001 From: Nathan Fisher Date: Wed, 24 May 2023 17:37:44 -0400 Subject: [PATCH] Finish implementing TOFU for Verifier; TODO: additional checks for certificate validity; --- src/certificate_store.rs | 36 +++++++++++++++++++++++++++++ src/fingerprint/mod.rs | 6 +---- src/lib.rs | 3 ++- src/prelude.rs | 5 ++-- src/sender/mod.rs | 9 ++++---- src/sender/verifier.rs | 50 ++++++++++++++++++++++------------------ 6 files changed, 73 insertions(+), 36 deletions(-) create mode 100644 src/certificate_store.rs diff --git a/src/certificate_store.rs b/src/certificate_store.rs new file mode 100644 index 0000000..c258680 --- /dev/null +++ b/src/certificate_store.rs @@ -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; + fn insert_certificate(&mut self, host: &str, fingerprint: &str) -> Option; + fn contains_certificate(&self, host: &str) -> bool; +} + +impl CertificateStore for HashMap { + fn get_certificate(&self, host: &str) -> Option { + self.get(host).cloned() + } + + fn insert_certificate(&mut self, host: &str, fingerprint: &str) -> Option { + self.insert(host.to_string(), fingerprint.to_string()) + } + + fn contains_certificate(&self, host: &str) -> bool { + self.contains_key(host) + } +} + +impl CertificateStore for BTreeMap { + fn get_certificate(&self, host: &str) -> Option { + self.get(host).cloned() + } + + fn insert_certificate(&mut self, host: &str, fingerprint: &str) -> Option { + self.insert(host.to_string(), fingerprint.to_string()) + } + + fn contains_certificate(&self, host: &str) -> bool { + self.contains_key(host) + } +} diff --git a/src/fingerprint/mod.rs b/src/fingerprint/mod.rs index 2d339ed..d25c7c8 100644 --- a/src/fingerprint/mod.rs +++ b/src/fingerprint/mod.rs @@ -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; diff --git a/src/lib.rs b/src/lib.rs index 779971d..6a4b595 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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; diff --git a/src/prelude.rs b/src/prelude.rs index f772101..3b93bf8 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -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, diff --git a/src/sender/mod.rs b/src/sender/mod.rs index 0fd84d9..69d9fbb 100644 --- a/src/sender/mod.rs +++ b/src/sender/mod.rs @@ -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; diff --git a/src/sender/verifier.rs b/src/sender/verifier.rs index 4478f08..f1893b4 100644 --- a/src/sender/verifier.rs +++ b/src/sender/verifier.rs @@ -1,15 +1,15 @@ -use crate::fingerprint::Fingerprint; -use rustls::{ - client::{ServerCertVerified, ServerCertVerifier}, - Certificate, +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; - 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 ServerCertVerifier for Verifier { server_name: &rustls::ServerName, _scts: &mut dyn Iterator, _ocsp_response: &[u8], - _now: std::time::SystemTime, + _now: time::SystemTime, ) -> Result { let fp = end_entity .fingerprint() @@ -37,18 +37,16 @@ impl ServerCertVerifier for Verifier { 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> for interior mutability. - // UPDATE: Now wrapped in Arc> + 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 ServerCertVerifier for Verifier { } } -impl Verifier { - pub fn new(store: T) -> Self { +impl From for Verifier { + fn from(value: T) -> Self { Self { - store: Arc::new(Mutex::new(store)), + store: Arc::new(Mutex::new(value)), } } } + +impl Verifier { + pub fn new(store: T) -> Self { + store.into() + } +}