dory/src/fingerprint.rs

67 lines
1.6 KiB
Rust
Raw Normal View History

use digest::Digest;
use rustls::Certificate;
use sha2::Sha256;
use std::fmt::{Write, self};
use x509_parser::prelude::*;
pub trait Fingerprint {
type Error;
fn fingerprint(&self) -> Result<(String, String), Self::Error>;
}
#[derive(Clone, Debug, PartialEq)]
pub enum Error {
Fmt,
X509(X509Error),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Fmt => write!(f, "FingerPrint: format error"),
Self::X509(e) => write!(f, "FingerPrint: {e}"),
}
}
}
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),
}
}
}
impl From<fmt::Error> for Error {
fn from(_value: fmt::Error) -> Self {
Self::Fmt
}
}
impl From<x509_parser::nom::Err<x509_parser::error::X509Error>> for Error {
fn from(value: x509_parser::nom::Err<x509_parser::error::X509Error>) -> Self {
Self::X509(value.into())
}
}
impl Fingerprint for Certificate {
type Error = Error;
fn fingerprint(&self) -> Result<(String, String), Self::Error> {
let (_, pk) = X509Certificate::from_der(self.as_ref())?;
let subject = pk.subject().to_string();
let key = pk.public_key().subject_public_key.as_ref();
let mut hasher = Sha256::new();
hasher.update(key);
let res = hasher.finalize();
let mut s = String::with_capacity(res.len());
for c in res {
write!(s, "{c:02x}")?;
}
Ok((subject[3..].to_string(), s))
}
}