如何在Rust中从X509证书提取RSA公钥(免OpenSSL依赖)
Rust从X509证书提取RSA公钥并验证JWT
问题描述
我是Rust新手,想要从X509证书中提取RSA公钥。我持有格式为-----BEGIN CERTIFICATE-----MII......-----END CERTIFICATE-----的证书字符串,希望从中提取出-----BEGIN RSA PUBLIC KEY-----MIII......-----END RSA PUBLIC KEY-----格式的公钥。
尝试使用pem crate和x509_certificate crate后得到无效格式的密钥,相关代码如下:
let mut certStr: String = "-----BEGIN CERTIFICATE----- ".to_owned(); certStr.push_str(&test.certificate); certStr.push_str(" -----END CERTIFICATE-----"); let rsa_cert = &X509Certificate::from_pem(certStr.as_bytes()).unwrap(); let pKey = &X509Certificate::public_key_data(&rsa_cert); // Invalid format Key let pem = parse(&certStr).unwrap(); // This has 2 properties -> tag and contents. Not sure how to extract p
补充说明:希望尽量避免依赖OpenSSL,提取公钥的目的是验证由对应私钥加密的JWT令牌,求安全直接的Rust实现方法。
解决方案
以下是纯Rust实现的方案,不依赖OpenSSL,涵盖公钥提取和JWT验证两个部分:
1. 添加依赖到Cargo.toml
[dependencies] x509-parser = "0.15" rsa = "0.9" pem = "1.1" der = "0.7" jsonwebtoken = "8.3" serde = { version = "1.0", features = ["derive"] }
2. 提取RSA公钥到目标PEM格式
use x509_parser::prelude::*; use rsa::RsaPublicKey; use pem::{encode, Pem}; use der::Decode; fn extract_rsa_public_key_pem(cert_pem: &str) -> Result<String, Box<dyn std::error::Error>> { // 解析X509证书PEM let (_, cert) = X509Certificate::from_pem(cert_pem.as_bytes())?; // 获取公钥的原始DER编码数据 let pub_key_der = cert.public_key().raw.to_vec(); // 从DER解码出RSA公钥实例 let rsa_pub_key = RsaPublicKey::from_public_key_der(&pub_key_der)?; // 将公钥编码为PKCS#1格式的DER(对应BEGIN RSA PUBLIC KEY的PEM格式) let pkcs1_der = rsa_pub_key.to_pkcs1_der()?; // 封装为PEM字符串 let pem = Pem { tag: "RSA PUBLIC KEY".to_string(), contents: pkcs1_der.as_bytes().to_vec(), }; Ok(encode(&pem)) }
3. 用提取的公钥验证JWT
假设你的JWT使用RS256算法签名,验证代码如下:
use jsonwebtoken::{decode, Validation, Algorithm}; use serde::Deserialize; // 根据你的JWT payload结构自定义Claims结构体 #[derive(Debug, Deserialize)] struct Claims { sub: String, exp: usize, // 添加你需要的其他字段 } fn verify_jwt(jwt_token: &str, rsa_pub_key_pem: &str) -> Result<Claims, Box<dyn std::error::Error>> { let validation = Validation::new(Algorithm::RS256); let decoded = decode::<Claims>(jwt_token, rsa_pub_key_pem.as_bytes(), &validation)?; Ok(decoded.claims) }
4. 完整使用示例
fn main() -> Result<(), Box<dyn std::error::Error>> { // 构造完整的证书PEM字符串 let mut cert_str = "-----BEGIN CERTIFICATE----- ".to_owned(); cert_str.push_str(&test.certificate); // test.certificate是证书的Base64主体部分 cert_str.push_str(" -----END CERTIFICATE-----"); // 提取RSA公钥PEM let rsa_pub_pem = extract_rsa_public_key_pem(&cert_str)?; println!("提取的RSA公钥:\n{}", rsa_pub_pem); // 验证JWT令牌 let jwt_token = "your-jwt-token-string-here"; let claims = verify_jwt(jwt_token, &rsa_pub_pem)?; println!("验证通过的Claims: {:?}", claims); Ok(()) }
关键说明
x509-parser:负责解析X509证书,提取公钥的原始DER数据;rsa:将公钥DER转换为PKCS#1格式(这是BEGIN RSA PUBLIC KEY对应的标准格式,区别于PKCS#8的BEGIN PUBLIC KEY);pem:将DER数据封装为标准PEM字符串;jsonwebtoken:直接支持用RSA公钥PEM验证JWT,无需额外处理签名逻辑。
内容的提问来源于stack exchange,提问作者Tarun Jain
相关产品推荐
相关产品推荐

