如何从 X509 证书中提取 RSA 公钥

问题描述 投票:0回答:1

我是 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-----\n".to_owned();
certStr.push_str(&test.certificate);
certStr.push_str("\n-----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 cryptography rsa x509
1个回答
2
投票

您也可以使用 openssl crate 支持您需要的所有任务:import PEM 证书,extraction 公钥和 export 作为 PKCS 中的 PEM 编码公钥# 1 格式(以及各种其他格式和编码):

use openssl::x509::X509;
use std::str;

fn main() {

    let cert_b64_der = "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";

    // Convert certificate to PEM, import PEM certificate
    let mut cert_pem: String = "-----BEGIN CERTIFICATE-----\n".to_owned();
    cert_pem.push_str(&cert_b64_der);
    cert_pem.push_str("\n-----END CERTIFICATE-----");
    let cert = &X509::from_pem(cert_pem.as_bytes()).unwrap();
    
    // Pick public key
    let public_pkey = cert.public_key().unwrap();

    // Export public key as PEM encoded public key in PKCS#1 format
    let public_pkcs1_pem = public_pkey.rsa().unwrap().public_key_to_pem_pkcs1().unwrap();
 
    println!("PEM encoded PKCS#1 key:\n{}", str::from_utf8(public_pkcs1_pem.as_slice()).unwrap());
}

您的证书似乎可以作为 Base64 编码的 ASN.1/DER 编码证书使用,因此直接将其作为 DER 导入并通过 PEM 编码省去弯路可能更方便。为此,只需将

Convert certificate to PEM
代码块替换为:

use base64::{engine::general_purpose, Engine as _};
...
// Convert certificate to DER, import DER certificate
let cert_der = general_purpose::STANDARD.decode(&cert_b64_der).unwrap();
let cert = &X509::from_der(cert_der.as_slice()).unwrap();

导出的公钥确实对应于证书中的密钥并且密钥格式正确可以使用 ASN.1 解析器最容易地检查,例如https://lapo.it/asn1js/.

© www.soinside.com 2019 - 2024. All rights reserved.