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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 08:22:20