使用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,需手动封装适配层:
- 先更新
Cargo.toml依赖:
[dependencies] x509-cert = "0.10" openssl = "0.10" signature = "2.2" spki = "0.7"
- 实现适配代码:
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通过特性直接支持其签名器,无需手动适配:
- 更新
Cargo.toml依赖:
[dependencies] x509-cert = { version = "0.10", features = ["ring"] } ring = "0.17"
- 实现代码:
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算法库,实现了
signaturetrait,可直接与x509_cert配合使用。 - rsa:纯Rust实现的RSA库,同样兼容
signaturetrait,适合无需依赖OpenSSL的场景。
内容的提问来源于stack exchange,提问作者Sean Clark Hess
相关产品推荐
相关产品推荐

