You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 01:30:53