@@ 3,7 3,7 @@
// SPDX-License-Identifier: EUPL-1.2
//! Helpers used for advanced TLS configuration.
-use std::{fs::File, io::BufReader, num::ParseIntError, path::Path, sync::Arc};
+use std::{fs::File, io::BufReader, path::Path, sync::Arc};
use anyhow::{bail, Context};
use rustls::{
@@ 14,16 14,22 @@ use sha2::{Digest, Sha256};
/// Verifies that the fingerprint of a certificate matches.
pub(crate) struct FingerprintVerifier {
- fingerprint: Vec<u8>,
+ fingerprint: [u8; 32],
}
impl FingerprintVerifier {
- // Create a new verifier from a hexadecimal fingerprint representation.
+ /// Create a new verifier from a hexadecimal fingerprint representation.
+ ///
+ /// Fingerprints must not include any colons or separators; only hexadecimal characters.
pub(crate) fn new(hex_fingerprint: &str) -> anyhow::Result<Self> {
- let fingerprint = (0..hex_fingerprint.len())
- .step_by(2)
- .map(|i| u8::from_str_radix(&hex_fingerprint[i..=i + 1], 16))
- .collect::<Result<Vec<u8>, ParseIntError>>()?;
+ if hex_fingerprint.len() != 64 {
+ bail!("fingerprint must be 64 bytes long");
+ }
+
+ let mut fingerprint = [0u8; 32];
+ for i in 0..32 {
+ fingerprint[i] = u8::from_str_radix(&hex_fingerprint[i * 2..=(i * 2) + 1], 16)?;
+ }
Ok(FingerprintVerifier { fingerprint })
}
@@ 39,24 45,36 @@ impl ServerCertVerifier for FingerprintVerifier {
_ocsp_response: &[u8],
_now: std::time::SystemTime,
) -> Result<rustls::client::ServerCertVerified, rustls::Error> {
- let fingerprint = Sha256::digest(&end_entity.0).to_vec();
+ let mut fingerprint = [0u8; 32];
+ let mut hasher = Sha256::new();
+ hasher.update(&end_entity.0);
+ fingerprint.copy_from_slice(&hasher.finalize());
if self.fingerprint == fingerprint {
Ok(ServerCertVerified::assertion())
} else {
Err(rustls::Error::InvalidCertificate(CertificateError::Other(
- Arc::from(FingerprintError),
+ Arc::from(FingerprintError {
+ expected: self.fingerprint.clone(),
+ received: fingerprint,
+ }),
)))
}
}
}
#[derive(Debug)]
-struct FingerprintError;
+struct FingerprintError {
+ expected: [u8; 32],
+ received: [u8; 32],
+}
impl std::fmt::Display for FingerprintError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- f.write_str("certificate fingerprint does not match expectation")
+ f.write_fmt(format_args!(
+ "received certificate fingerprint ({:?}) does not match expectation ({:?})",
+ self.received, self.expected,
+ ))
}
}