【问题标题】:C# - Generate X509 Certificate based on a given issuer certificate in byte[]C# - 根据字节[] 中的给定颁发者证书生成 X509 证书
【发布时间】:2021-11-13 13:39:16
【问题描述】:

我想从 C# 代码创建 iothub 设备证书。根 CA 作为 .pfx 存储在 keyvault 中,作为字符串提取,然后从 base 64 转换以获得证书字节,因为它是存储在 keyvault 中的证书所需的:Azure Key Vault Certificates does not have the Private Key when retrieved via IKeyVaultClient.GetCertificateAsync

我想编写一个函数,它将接收这些字节以及一个主题名称(用于叶证书),并将创建一个 x509 证书(带有公钥和私钥),该证书将以颁发者为根。

这是我目前所画的:

public static X509Certificate2 GenerateCertificateBasedOnIssuer(string subjectName, byte[] issuerByteCert)
        {
            var issuerCertificate = new X509Certificate2(issuerByteCert);

            RSA keyProvider = issuerCertificate.GetRSAPrivateKey();

            CertificateRequest certificateRequest = new CertificateRequest($"CN={subjectName}", keyProvider, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);

            CryptoApiRandomGenerator randomGenerator = new CryptoApiRandomGenerator();
            SecureRandom random = new SecureRandom(randomGenerator);
            BigInteger serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random);

            var publicOnlyDeviceCertificate = certificateRequest.Create(issuerCertificate, issuerCertificate.NotBefore, issuerCertificate.NotAfter, serialNumber.ToByteArray());

            return publicOnlyDeviceCertificate; // oh no ! :(

        }

我在使用此解决方案时遇到的问题是创建的证书仅包含一个公钥。

我使用BouncyCastle's X509V3CertificateGeneratorGenerate a self-signed certificate on the fly 找到了另一个解决方案,似乎可以解决我在另一个 Stack Overflow 问题上的问题:Generate a self-signed certificate on the fly

这个解决方案的问题是我无法将我的 rootCA 证书的私钥转换为 AsymmetricKeyParameterX509V3CertificateGenerator.Generate 方法的第一个参数)。我尝试使用以下解决方案将颁发者的密钥转换为AsymmetricKeyParameter convert PEM encoded RSA public key to AsymmetricKeyParameter,但出现无效操作异常。

我想知道我是否走在正确的道路上(据了解),以及是否有办法根据我目前拥有的代码生成带有私钥(和公钥)的证书。

更新:我已经能够通过硬编码密钥将私钥转换为 AsymmetricKeyParameter,如下所示:

 string testKey = @"-----BEGIN PRIVATE KEY-----
<THE KEY>
-----END PRIVATE KEY-----
";
 var stringReader = new StringReader(testKey);
 var pemReader = new PemReader(stringReader);
 var pemObject = pemReader.ReadObject(); 
 var keyParam = ((AsymmetricKeyParameter)pemObject);

Azure 密钥库以 pfx 格式存储证书。我正在考虑将私钥存储为秘密字符串。在找到可行的解决方案之前,我将继续使用硬编码密钥进行测试。

我现在正在使用 BouncyCastle 进行测试,如果可行,我会提供可行的解决方案!

【问题讨论】:

    标签: c# ssl bouncycastle x509certificate x509certificate2


    【解决方案1】:

    您传递给CertificateRequest 的密钥用作证书中的公钥...所以您想传递一个新密钥,而不是颁发者的密钥。

    然后,一旦您现在有了主题密钥,您就可以在最后使用 CopyWithPrivateKey 将它们粘合在一起。

    public static X509Certificate2 GenerateCertificateBasedOnIssuer(string subjectName, byte[] issuerByteCert)
    {
        using (var issuerCertificate = new X509Certificate2(issuerByteCert))
        using (RSA subjectKey = RSA.Create(2048))
        {
            CertificateRequest certificateRequest = new CertificateRequest($"CN={subjectName}", subjectKey, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
    
            CryptoApiRandomGenerator randomGenerator = new CryptoApiRandomGenerator();
            SecureRandom random = new SecureRandom(randomGenerator);
            BigInteger serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random);
    
            var publicOnlyDeviceCertificate = certificateRequest.Create(issuerCertificate, issuerCertificate.NotBefore, issuerCertificate.NotAfter, serialNumber.ToByteArray());
    
            using (publicOnlyDeviceCertificate)
            {
                return publicOnlyDeviceCertificate.CopyWithPrivateKey(subjectKey);
            }
        }
    

    【讨论】:

    • 实际上效果很好,谢谢!但是,叶子证书似乎与根证书具有相同的私钥。有没有办法拥有一组完全不同的键?谢谢!
    • @vitonimal 如果您使用如图所示的代码(制作新密钥,而不是获得对发行者密钥的引用),那么它们的密钥将不同......除非您赢得了随机数生成器彩票并制作了两次相同的 RSA 密钥。
    • 你是对的!看来我只是没看清楚!非常感谢!这是我在过去几天看到的关于该主题的最佳和最直接的答案!
    猜你喜欢
    • 1970-01-01
    • 2012-03-25
    • 2013-07-09
    • 1970-01-01
    • 2021-04-22
    • 2021-04-13
    • 1970-01-01
    • 1970-01-01
    • 2017-10-01
    相关资源
    最近更新 更多