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

使用x509_cert创建X.509证书遇类型错误,如何适配OpenSSL/Ring?

x509_cert与加密库签名器兼容问题

在实现x509_cert的基础示例时,遇到签名器类型不兼容的问题,代码如下:

use openssl::pkey::{PKey, Private};
use openssl::sign::Signer;
use std::str::FromStr;
use std::time::Duration;
use x509_cert::builder::{CertificateBuilder, Profile};
use x509_cert::name::Name;
use x509_cert::serial_number::SerialNumber;
use x509_cert::spki::SubjectPublicKeyInfoOwned;
use x509_cert::time::Validity;

fn test() -> Result<(), Box<dyn std::error::Error>> {
    // 创建新的RSA私钥
    // let rsa = Rsa::generate(2048)?;
    // let key: PKey<Private> = PKey::from_rsa(rsa);

    let key: PKey<Private> = PKey::generate_ed25519()?;
    let public_key = key.raw_public_key()?;
    let public_key_der = key.public_key_to_der()?;

    let serial_number = SerialNumber::from(42u32);
    let validity = Validity::from_now(Duration::new(5, 0)).unwrap();
    let profile = Profile::Root;
    let subject =
        Name::from_str("CN=World domination corporation,O=World domination Inc,C=US").unwrap();

    let pub_key = SubjectPublicKeyInfoOwned::try_from(&public_key_der[..])?;
    let signer = Signer::new_without_digest(&key)?;
    // let signer = SigningKey::new(key);

    let builder =
        CertificateBuilder::new(profile, serial_number, validity, subject, pub_key, &signer)?;
}

编译时出现以下错误:

the trait bound `Signer<'_>: spki::SignatureAlgorithmIdentifier` is not satisfied
the trait bound `Signer<'_>: signature::keypair::KeypairRef` is not satisfied

以下是具体解决方案:

一、适配OpenSSL的解决方案

x509_cert的CertificateBuilder依赖signature crate定义的KeypairRef和SignatureAlgorithmIdentifier trait,OpenSSL的Signer未实现这些trait,需手动封装适配层:

  1. 先更新Cargo.toml依赖:
[dependencies]
x509-cert = "0.10"
openssl = "0.10"
signature = "2.2"
spki = "0.7"
  1. 实现适配代码:
use openssl::pkey::{PKey, Private};
use openssl::sign::Signer;
use signature::{KeypairRef, Signature, SignatureEncoding};
use spki::SignatureAlgorithmIdentifier;
use x509_cert::builder::{CertificateBuilder, Profile};
use x509_cert::name::Name;
use x509_cert::serial_number::SerialNumber;
use x509_cert::spki::SubjectPublicKeyInfoOwned;
use x509_cert::time::Validity;
use std::str::FromStr;
use std::time::Duration;

// 自定义签名类型,适配OpenSSL签名结果
struct OpenSSLSignature(Vec<u8>);

impl Signature for OpenSSLSignature {
    fn from_bytes(bytes: &[u8]) -> Result<Self, signature::Error> {
        Ok(Self(bytes.to_vec()))
    }
}

impl SignatureEncoding for OpenSSLSignature {
    fn to_bytes(&self) -> Vec<u8> {
        self.0.clone()
    }
}

// 自定义签名器包装,实现x509_cert所需trait
struct OpenSSLKeypair<'a>(&'a PKey<Private>);

impl<'a> KeypairRef for OpenSSLKeypair<'a> {
    type VerifyingKey = ();
    type Signature = OpenSSLSignature;

    fn verifying_key(&self) -> &Self::VerifyingKey {
        &()
    }

    fn try_sign(&self, msg: &[u8]) -> Result<Self::Signature, signature::Error> {
        let mut signer = Signer::new_without_digest(self.0)
            .map_err(|e| signature::Error::from_source(e))?;
        signer.update(msg)
            .map_err(|e| signature::Error::from_source(e))?;
        let sig = signer.sign_to_vec()
            .map_err(|e| signature::Error::from_source(e))?;
        Ok(OpenSSLSignature(sig))
    }
}

impl<'a> SignatureAlgorithmIdentifier for OpenSSLKeypair<'a> {
    fn signature_algorithm_identifier(&self) -> spki::AlgorithmIdentifierOwned {
        // Ed25519对应的OID
        spki::AlgorithmIdentifierOwned {
            oid: spki::ObjectIdentifier::from_string("1.3.101.112").unwrap(),
            parameters: None,
        }
    }
}

fn test() -> Result<(), Box<dyn std::error::Error>> {
    let key: PKey<Private> = PKey::generate_ed25519()?;
    let public_key_der = key.public_key_to_der()?;

    let serial_number = SerialNumber::from(42u32);
    let validity = Validity::from_now(Duration::new(5, 0)).unwrap();
    let profile = Profile::Root;
    let subject = Name::from_str("CN=World domination corporation,O=World domination Inc,C=US")?;

    let pub_key = SubjectPublicKeyInfoOwned::try_from(&public_key_der[..])?;
    let signer = OpenSSLKeypair(&key);

    let builder = CertificateBuilder::new(profile, serial_number, validity, subject, pub_key, &signer)?;
    let cert_der = builder.build()?;
    Ok(())
}

二、用Ring实现的方案

Ring是rustls团队维护的加密库,x509_cert通过特性直接支持其签名器,无需手动适配:

  1. 更新Cargo.toml依赖:
[dependencies]
x509-cert = { version = "0.10", features = ["ring"] }
ring = "0.17"
  1. 实现代码:
use ring::signature::{Ed25519KeyPair, KeyPair};
use std::str::FromStr;
use std::time::Duration;
use x509_cert::builder::{CertificateBuilder, Profile};
use x509_cert::name::Name;
use x509_cert::serial_number::SerialNumber;
use x509_cert::spki::SubjectPublicKeyInfoOwned;
use x509_cert::time::Validity;

fn test() -> Result<(), Box<dyn std::error::Error>> {
    // 生成Ed25519密钥对
    let rng = ring::rand::SystemRandom::new();
    let pkcs8_bytes = Ed25519KeyPair::generate_pkcs8(&rng)?;
    let key_pair = Ed25519KeyPair::from_pkcs8(pkcs8_bytes.as_ref())?;

    // 提取公钥SPKI
    let pub_key = SubjectPublicKeyInfoOwned::try_from(key_pair.public_key().as_ref())?;

    let serial_number = SerialNumber::from(42u32);
    let validity = Validity::from_now(Duration::new(5, 0)).unwrap();
    let profile = Profile::Root;
    let subject = Name::from_str("CN=World domination corporation,O=World domination Inc,C=US")?;

    // 直接使用Ring的KeyPair作为签名器
    let builder = CertificateBuilder::new(profile, serial_number, validity, subject, pub_key, &key_pair)?;
    let cert_der = builder.build()?;
    Ok(())
}

三、其他推荐的加密库

  • rustls-webpki:rustls生态下的WebPKI库,专门处理X.509证书,适合TLS相关场景。
  • p256/secp256k1:纯Rust实现的ECC算法库,实现了signature trait,可直接与x509_cert配合使用。
  • rsa:纯Rust实现的RSA库,同样兼容signature trait,适合无需依赖OpenSSL的场景。

内容的提问来源于stack exchange,提问作者Sean Clark Hess

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 00:37:56