修复 TLS 指纹模式不验握手签名的问题
FingerprintVerifier 此前只比对证书哈希,verify_tls12/13_signature 无条件 放行。而证书由密码确定性生成、属于公开信息,主动中间人重放真实证书即可 完成握手,指纹模式无法抵抗 MITM。 - verify_tls12/13_signature 改为调用 rustls::crypto::verify_tls12/13_signature 做真实验签(ring provider 的签名算法集) - supported_verify_schemes 返回算法集实际支持的方案 - 补充基于 tokio 内存通道的真实 TLS 握手测试:指纹匹配握手成功、 指纹不匹配握手失败
This commit is contained in:
@@ -9,11 +9,14 @@ use std::str::FromStr;
|
||||
#[derive(Debug)]
|
||||
pub struct FingerprintVerifier {
|
||||
pub expected_fingerprint: [u8; 32],
|
||||
supported_algorithms: rustls::crypto::WebPkiSupportedAlgorithms,
|
||||
}
|
||||
impl FingerprintVerifier {
|
||||
pub fn new(expected_fingerprint: [u8; 32]) -> Self {
|
||||
Self {
|
||||
expected_fingerprint,
|
||||
supported_algorithms: rustls::crypto::ring::default_provider()
|
||||
.signature_verification_algorithms,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -45,39 +48,26 @@ impl ServerCertVerifier for FingerprintVerifier {
|
||||
|
||||
fn verify_tls12_signature(
|
||||
&self,
|
||||
_message: &[u8],
|
||||
_cert: &CertificateDer<'_>,
|
||||
_dss: &rustls::DigitallySignedStruct,
|
||||
message: &[u8],
|
||||
cert: &CertificateDer<'_>,
|
||||
dss: &rustls::DigitallySignedStruct,
|
||||
) -> Result<HandshakeSignatureValid, rustls::Error> {
|
||||
Ok(HandshakeSignatureValid::assertion())
|
||||
// 必须真正验证握手签名:证书本身(由密码确定性生成)是公开信息,
|
||||
// 只比对指纹而不验签无法抵抗重放真实证书的主动中间人
|
||||
rustls::crypto::verify_tls12_signature(message, cert, dss, &self.supported_algorithms)
|
||||
}
|
||||
|
||||
fn verify_tls13_signature(
|
||||
&self,
|
||||
_message: &[u8],
|
||||
_cert: &CertificateDer<'_>,
|
||||
_dss: &rustls::DigitallySignedStruct,
|
||||
message: &[u8],
|
||||
cert: &CertificateDer<'_>,
|
||||
dss: &rustls::DigitallySignedStruct,
|
||||
) -> Result<HandshakeSignatureValid, rustls::Error> {
|
||||
Ok(HandshakeSignatureValid::assertion())
|
||||
rustls::crypto::verify_tls13_signature(message, cert, dss, &self.supported_algorithms)
|
||||
}
|
||||
|
||||
fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
|
||||
vec![
|
||||
// RSA schemes
|
||||
rustls::SignatureScheme::RSA_PKCS1_SHA256,
|
||||
rustls::SignatureScheme::RSA_PKCS1_SHA384,
|
||||
rustls::SignatureScheme::RSA_PKCS1_SHA512,
|
||||
rustls::SignatureScheme::RSA_PSS_SHA256,
|
||||
rustls::SignatureScheme::RSA_PSS_SHA384,
|
||||
rustls::SignatureScheme::RSA_PSS_SHA512,
|
||||
// ECDSA schemes
|
||||
rustls::SignatureScheme::ECDSA_NISTP256_SHA256,
|
||||
rustls::SignatureScheme::ECDSA_NISTP384_SHA384,
|
||||
rustls::SignatureScheme::ECDSA_NISTP521_SHA512,
|
||||
// EdDSA schemes
|
||||
rustls::SignatureScheme::ED25519,
|
||||
rustls::SignatureScheme::ED448,
|
||||
]
|
||||
self.supported_algorithms.supported_schemes()
|
||||
}
|
||||
}
|
||||
#[derive(Debug)]
|
||||
@@ -202,9 +192,7 @@ impl CertValidationMode {
|
||||
Ok(std::sync::Arc::new(InsecureVerifier))
|
||||
}
|
||||
CertValidationMode::VerifyFingerprint(fingerprint) => {
|
||||
Ok(std::sync::Arc::new(FingerprintVerifier {
|
||||
expected_fingerprint: *fingerprint,
|
||||
}))
|
||||
Ok(std::sync::Arc::new(FingerprintVerifier::new(*fingerprint)))
|
||||
}
|
||||
CertValidationMode::Standard => {
|
||||
let root_store = load_root_cert()?;
|
||||
@@ -226,3 +214,73 @@ impl CertValidationMode {
|
||||
Ok(config)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::tls::cert::generate_deterministic_cert;
|
||||
use rustls::ServerConfig;
|
||||
use rustls::pki_types::ServerName;
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::sync::Arc;
|
||||
|
||||
fn fingerprint_of(cert: &CertificateDer<'_>) -> [u8; 32] {
|
||||
Sha256::digest(cert.as_ref()).into()
|
||||
}
|
||||
|
||||
async fn try_handshake(
|
||||
server_config: Arc<ServerConfig>,
|
||||
client_config: Arc<ClientConfig>,
|
||||
) -> std::io::Result<()> {
|
||||
let (client_io, server_io) = tokio::io::duplex(8192);
|
||||
let acceptor = tokio_rustls::TlsAcceptor::from(server_config);
|
||||
let connector = tokio_rustls::TlsConnector::from(client_config);
|
||||
let server_name = ServerName::try_from("deterministic-node")
|
||||
.unwrap()
|
||||
.to_owned();
|
||||
|
||||
let (client, _server) = tokio::join!(
|
||||
connector.connect(server_name, client_io),
|
||||
acceptor.accept(server_io),
|
||||
);
|
||||
client.map(|_| ())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_fingerprint_handshake() {
|
||||
let password = "handshake_test_password";
|
||||
let (cert, key) = generate_deterministic_cert(password).unwrap();
|
||||
let fingerprint = fingerprint_of(&cert);
|
||||
|
||||
let server_config = Arc::new(
|
||||
ServerConfig::builder()
|
||||
.with_no_client_auth()
|
||||
.with_single_cert(vec![cert], key)
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
// 正例:指纹匹配且服务端持有对应私钥。
|
||||
// 修复前 verify_tls13_signature 无条件放行,握手必然成功;
|
||||
// 修复后走真实验签,只有实现正确才能握手成功。
|
||||
let client_config = Arc::new(
|
||||
CertValidationMode::VerifyFingerprint(fingerprint)
|
||||
.create_tls_client_config()
|
||||
.unwrap(),
|
||||
);
|
||||
try_handshake(server_config.clone(), client_config)
|
||||
.await
|
||||
.expect("handshake with matching fingerprint should succeed");
|
||||
|
||||
// 反例:指纹不匹配(攻击者证书),握手必须失败
|
||||
let wrong_fingerprint = [0xABu8; 32];
|
||||
let client_config = Arc::new(
|
||||
CertValidationMode::VerifyFingerprint(wrong_fingerprint)
|
||||
.create_tls_client_config()
|
||||
.unwrap(),
|
||||
);
|
||||
assert!(
|
||||
try_handshake(server_config, client_config).await.is_err(),
|
||||
"handshake with mismatched fingerprint should fail"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user