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

C#仅用RSA公钥模与指数通过CertificateRequest生成CSR求助

无本地私钥(私钥存储在HSM)场景下生成CSR的实现方案

报错根因

  • 通过RSA.Create()导入仅包含模数、指数的公钥参数得到的RSA实例,仅存储公钥材料,Windows CNG层判定该实例无关联签名私钥,调用依赖私钥的签名方法时直接抛出Key does not exist异常。
  • 无参CreateSigningRequest()方法默认会从CertificateRequest绑定的密钥对象中提取私钥完成签名,纯公钥对象无对应私钥,且未传入自定义签名实现时,就会抛出要求使用带X509SignatureGenerator参数重载的异常。

实现思路

私钥全程存储在HSM不需要导出到本地,只需要自定义继承X509SignatureGenerator的签名实现类,将待签名的摘要数据转发给HSM完成签名运算,再将HSM返回的签名结果回传给证书请求对象即可,所有私钥运算全部在HSM内部完成。

具体实现代码

1. 构造纯公钥RSA对象

public static RSA BuildPublicKeyOnlyRsa(byte[] modulus, byte[] exponent)
{
    RSA rsa = RSA.Create();
    RSAParameters pubKeyParams = new RSAParameters
    {
        Modulus = modulus,
        Exponent = exponent
    };
    rsa.ImportParameters(pubKeyParams);
    return rsa;
}

调用该方法得到RSA实例后,直接提取PublicKey对象用于构造证书请求:

using var rsaPubInstance = BuildPublicKeyOnlyRsa(modulus, exponent);
PublicKey certPublicKey = rsaPubInstance.GetPublicKey();

2. 自定义对接HSM的签名生成器

public class HsmRsaSignatureGenerator : X509SignatureGenerator
{
    private readonly PublicKey _publicKey;
    private readonly HashAlgorithmName _hashAlgorithm;
    private readonly RSASignaturePadding _paddingMode;
    // 可根据对接的HSM SDK,新增HSM会话、私钥句柄等字段
    // private readonly IntPtr _hsmKeyHandle;

    public HsmRsaSignatureGenerator(PublicKey publicKey, HashAlgorithmName hashAlgorithm, RSASignaturePadding paddingMode)
    {
        _publicKey = publicKey;
        _hashAlgorithm = hashAlgorithm;
        _paddingMode = paddingMode;
        // 初始化HSM连接、获取对应私钥句柄的逻辑可写在这里
    }

    protected override PublicKey BuildPublicKey() => _publicKey;

    public override byte[] GetSignatureAlgorithmIdentifier(HashAlgorithmName hashAlgorithm)
    {
        // 返回对应签名算法的DER编码标识,以下为常用组合示例,可根据实际使用的算法补充
        if (_paddingMode == RSASignaturePadding.Pkcs1)
        {
            if (hashAlgorithm == HashAlgorithmName.SHA256)
                // sha256WithRSAEncryption OID: 1.2.840.113549.1.1.11
                return new byte[] { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00 };
            if (hashAlgorithm == HashAlgorithmName.SHA384)
                // sha384WithRSAEncryption OID: 1.2.840.113549.1.1.12
                return new byte[] { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0C, 0x05, 0x00 };
            if (hashAlgorithm == HashAlgorithmName.SHA512)
                // sha512WithRSAEncryption OID: 1.2.840.113549.1.1.13
                return new byte[] { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0D, 0x05, 0x00 };
        }
        // RSA-PSS等其他padding模式的算法标识可根据实际场景补充
        throw new NotSupportedException("当前指定的签名算法组合不被支持");
    }

    public override byte[] SignData(byte[] data, HashAlgorithmName hashAlgorithm)
    {
        // 替换为实际HSM签名调用逻辑:
        // 1. 将待签名数据data、指定的哈希算法、padding模式、HSM内存储的私钥句柄传入HSM SDK
        // 2. 直接返回HSM输出的签名二进制结果即可,本地不需要持有或运算私钥
        // 伪代码示例:
        // return HsmSdk.RsaSign(_hsmKeyHandle, data, hashAlgorithm, _paddingMode);
        throw new NotImplementedException("请替换为实际的HSM签名接口调用逻辑");
    }
}

3. 生成CSR

var subjectName = new X500DistinguishedName("CN=你的证书通用名称");
var signatureGenerator = new HsmRsaSignatureGenerator(certPublicKey, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
var certRequest = new CertificateRequest(subjectName, certPublicKey, HashAlgorithmName.SHA256);
// 必须传入自定义签名生成器调用重载方法,不能使用无参的CreateSigningRequest
byte[] csrDerBytes = certRequest.CreateSigningRequest(signatureGenerator);

// 如需PEM格式CSR,可做如下转换:
string pemCsr = PemEncoding.Write("CERTIFICATE REQUEST", csrDerBytes);

注意:代码中配置的哈希算法、签名padding模式必须和HSM侧实际使用的签名参数完全一致,否则CA侧会验签失败,拒绝签发证书。

内容的提问来源于stack exchange,提问作者user1912383

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 08:42:14