Rust中如何计算rcgen生成证书与OpenSSL一致的SHA256指纹
问题描述
我尝试使用sha2 crate为rcgen crate生成的证书计算SHA256指纹,但通过OpenSSL命令生成的同证书SHA256指纹与程序计算结果不一致。根据我的理解,证书指纹是DER编码证书的SHA256哈希值,请问我的操作存在什么问题?
测试代码如下:
use rcgen::{date_time_ymd, Certificate, CertificateParams, DistinguishedName, DnType}; use sha2::{Digest, Sha256}; use std::fs::File; use std::io::Write; use std::process::Command; fn main() -> std::io::Result<()> { // Create a certificate with rcgen let mut params: CertificateParams = Default::default(); params.not_before = date_time_ymd(2022, 6, 1); params.not_after = date_time_ymd(2023, 6, 1); params.distinguished_name = DistinguishedName::new(); params.distinguished_name .push(DnType::CommonName, "my_common_name"); let cert = Certificate::from_params(params).unwrap(); let key_pem = cert.serialize_pem().unwrap(); // Write the pem certificate to a file let mut f = File::create("/tmp/cert.crt")?; f.write_all(key_pem.as_bytes()).unwrap(); // openssl x509 -in /tmp/cert.crt -noout -fingerprint -sha256 let openssl_fingerprint = Command::new("openssl") .args(["x509", "-in", "/tmp/cert.crt", "-noout", "-fingerprint", "-sha256", ]).output()?; println!( "OpenSSL SHA256: {}", String::from_utf8(openssl_fingerprint.stdout).unwrap() ); // Create fingerprint from der certificate: let cert_der = cert.serialize_der().unwrap(); let mut hasher = Sha256::new(); hasher.update(cert_der); let res = hasher.finalize(); println!("SHA256: {:x?}", res); Ok(()) }
项目Cargo.toml配置如下:
[package] name = "cert-fingerprint-test" version = "0.1.0" edition = "2021" [dependencies] rcgen="0.9" sha2="0.10.2"
运行示例输出:
OpenSSL SHA256: SHA256 Fingerprint=D4:61:B6:2E:50:43:AB:B1:7C:43:EF:23:9A:48:BA:BF:CF:2E:99:5A:C4:F4:77:65:51:C4:7A:F5:A5:70:6C:9E SHA256: [eb, ab, 31, 9, 9a, 47, bb, d8, 50, a5, 9c, 46, 90, ba, ba, 71, b9, 79, 91, 93, 1b, 83, 2f, d1, 18, 88, ef, 1b, 5f, 4b, e4, a4]
二者输出格式存在差异属于正常情况,但预期对应的十六进制哈希值应当完全一致。
问题原因
核心问题出在rcgen 0.9版本的序列化逻辑:
- 你没有在
CertificateParams中手动设置固定的serial_number(证书序列号),该参数默认值为None - 这种情况下,每次调用
serialize_pem()或serialize_der()方法时,rcgen都会自动生成一个新的随机20字节序列号,两次序列化得到的根本不是内容完全相同的证书 - 第一次调用
serialize_pem()写到文件里给OpenSSL计算哈希的证书,和第二次调用serialize_der()拿到的证书序列号不一致,DER编码内容存在差异,计算出来的SHA256哈希自然不匹配。
修复方案
两种方案选其一即可:
- 只做一次序列化,先拿到DER编码内容,再从DER转成PEM格式写入文件,保证两边计算的是同一份字节内容:
// 引入pem依赖做格式转换,Cargo.toml添加pem = "1.0" // 先序列化一次DER let cert_der = cert.serialize_der().unwrap(); // 从DER转PEM写入文件,不要单独调用serialize_pem let cert_pem = pem::encode(&pem::Pem::new("CERTIFICATE", cert_der.clone())); let mut f = File::create("/tmp/cert.crt")?; f.write_all(cert_pem.as_bytes()).unwrap(); // 后续哈希直接复用cert_der计算即可 - 生成证书参数时手动指定固定的序列号,这样无论调用多少次序列化方法,生成的证书内容都一致:
use rcgen::SerialNumber; // 设置参数时指定固定序列号 params.serial_number = Some(SerialNumber::from_slice(&[1, 2, 3, 4])); // 替换为实际使用的序列号
内容的提问来源于stack exchange,提问作者JanSc
相关产品推荐
相关产品推荐

