繁体   English   中英

如何在 .NET Standard 2.0/Core 2.1 中使用 PrivateKey 创建 X509Certificate2?

[英]How to create X509Certificate2 with PrivateKey in .NET Standard 2.0/Core 2.1?

我们正在生成一些自签名证书以使用 BouncyCastle 进行测试,但是当我们尝试向证书添加私钥时,代码会引发异常。 这是有问题的代码:

private static X509Certificate2 CreateCertificate(string subject, DateTimeOffset notBefore, DataTimeOffset notAfter, string issuer, AsymmetricKeyParamter issuerPrivateKey)
{
        // Setup
        X509V3CertificateGenerator certGenerator = new X509V3CertificateGenerator();
        SecureRandom random = new SecureRandom(new CryptoApiRandomGenerator());

        RsaKeyPairGenerator keyPairGenerator = new RsaKeyPairGenerator();
        keyPairGenerator.Init(new KeyGenerationParameters(random, KeyStrength));

        // Randomly generate a serial number
        BigInteger serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(long.MaxValue), random);
        certGenerator.SetSerialNumber(serialNumber);

        // Set the issuer and subject names
        X509Name issuerName = new X509Name(issuer);
        X509Name subjectName = new X509Name(subject);
        certGenerator.SetIssuerDN(issuerName);
        certGenerator.SetSubjectDN(subjectName);

        // Set the validity period
        certGenerator.SetNotBefore(notBefore.UtcDateTime);
        certGenerator.SetNotAfter(notAfter.UtcDateTime);

        // Randomly generate the public key
        AsymmetricCipherKeyPair subjectKeyPair = keyPairGenerator.GenerateKeyPair();
        certGenerator.SetPublicKey(subjectKeyPair.Public);

        // Generate the signed certificate
        ISignatureFactory signatureFactory = new Asn1SignatureFactory(SHA256RSASignatureAlgorithm, issuerPrivateKey ?? subjectKeyPair.Private, random);
        X509Certificate2 certificate = new X509Certificate2(certGenerator.Generate(signatureFactory).GetEncoded());

        // Include the private key with the response
        // ERROR HERE!
        certificate.PrivateKey = DotNetUtilities.ToRSA(subjectKeyPair.Private as RsaPrivateCrtKeyParameters);

        return certificate;
}

此代码位于面向 .NET Standard 2.0 的库中,该库是两个不同应用程序的依赖项:一个面向 .NET Core 2.1,另一个面向 .NET Framework 4.7.2。 我相信这在 .NET Framework 应用程序中工作正常,但在 .NET Core 应用程序中,我在上面指示的行中收到此消息的异常:

此平台不支持操作。

显然, 这是 .NET Core 中的预期行为 我知道这个问题中提到的CopyWithPrivateKey方法,理论上我应该使用它。 但是, .NET Standard 2.0 不支持此方法(请注意页面顶部指示重定向的错误)。 此外,由于 .NET Framework 的其他一些依赖项,.NET Framework 应用程序目前无法转换为 .NET Core。 根据此矩阵,.NET Framework 根本不支持 .NET Standard 2.1,这意味着我无法升级到 .NET Standard 2.1并使用CopyWithPrivateKey

如何以与 .NET Core 兼容的方式在 .NET Standard 2.0 中创建带有私钥的X509Certificate2

经过大量挖掘,我找到的唯一解决方案是将证书转换为 PKCS12 格式的字节数组,附加私钥,然后将其读回X509Certificate2对象。 这很糟糕,但据我所知,在 .NET Core 中,您可以使用私钥获取私钥的唯一方法是调用CopyWithPrivateKey (如问题中所述,在 .NET Standard 2.0 中不可用)或加载包含私钥。 下面的代码可以做到这一点:

    private static X509Certificate2 AddPrivateKeyPlatformIndependent(Org.BouncyCastle.X509.X509Certificate bouncyCastleCert, AsymmetricKeyParameter privateKey)
    {
        string alias = bouncyCastleCert.SubjectDN.ToString();
        Pkcs12Store store = new Pkcs12StoreBuilder().Build();

        X509CertificateEntry certEntry = new X509CertificateEntry(bouncyCastleCert);
        store.SetCertificateEntry(alias, certEntry);

        // TODO: This needs extra logic to support a certificate chain
        AsymmetricKeyEntry keyEntry = new AsymmetricKeyEntry(privateKey);
        store.SetKeyEntry(alias, keyEntry, new X509CertificateEntry[] { certEntry });

        byte[] certificateData;
        string password = GenerateRandomString();
        using (MemoryStream memoryStream = new MemoryStream())
        {
            store.Save(memoryStream, password.ToCharArray(), new SecureRandom());
            memoryStream.Flush();
            certificateData = memoryStream.ToArray();
        }

        return new X509Certificate2(certificateData, password, X509KeyStorageFlags.Exportable);
    }

使用它代替问题代码中的最后两行,而不是使用certGenerator创建X509Certificate2certGenerator使用它来创建等效的 Bouncy Castle Type 以传递给它: Org.BouncyCastle.X509.X509Certificate bouncyCastleCert = certGenerator.Generate(signatureFactory);


由于有关 Bouncy Castle 和 .NET 证书的文档充其量很少,因此我在此过程中发现了一些怪癖:

  • PKCS12 容器中证书条目和密钥条目的别名必须相同。 否则,您将在尝试使用私钥时收到“密钥集不存在”异常。

  • 加载字节数组时必须使用X509KeyStorageFlags.Exportable ,否则根据您使用证书的方式,您可能会收到“密钥在指定状态下无效”异常。 这也意味着您必须提供密码,因为没有它就不会过载,但您可以使用任何旧字符串,因为它是临时密码。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM