66 lines
1.6 KiB
Rust
66 lines
1.6 KiB
Rust
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))
|
|
}
|
|
}
|
|
|