简体   繁体   English

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

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

We are generating some self-signed certificates for testing using BouncyCastle, but the code throws an exception when we try to add a private key to the certificate.我们正在生成一些自签名证书以使用 BouncyCastle 进行测试,但是当我们尝试向证书添加私钥时,代码会引发异常。 Here's the code in question:这是有问题的代码:

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;
}

This code is in a library that targets .NET Standard 2.0, and the library is a dependency of two different applications: one targeting .NET Core 2.1 and the other targeting .NET Framework 4.7.2.此代码位于面向 .NET Standard 2.0 的库中,该库是两个不同应用程序的依赖项:一个面向 .NET Core 2.1,另一个面向 .NET Framework 4.7.2。 I believe this works fine in the .NET Framework app, but in the .NET Core app I'm getting an exception with this message on the indicated line above:我相信这在 .NET Framework 应用程序中工作正常,但在 .NET Core 应用程序中,我在上面指示的行中收到此消息的异常:

Operation is not supported on this platform.此平台不支持操作。

Apparently this is expected behavior in .NET Core .显然, 这是 .NET Core 中的预期行为 I am aware of the CopyWithPrivateKey method as mentioned in this question , which in theory is what I should be using.我知道这个问题中提到的CopyWithPrivateKey方法,理论上我应该使用它。 However, this method is not supported in .NET Standard 2.0 (note the error at the top of the page indicating the redirect).但是, .NET Standard 2.0 不支持此方法(请注意页面顶部指示重定向的错误)。 Furthermore, the .NET Framework app cannot be converted to .NET Core at the moment because of some other dependencies which are .NET Framework.此外,由于 .NET Framework 的其他一些依赖项,.NET Framework 应用程序目前无法转换为 .NET Core。 According tothis matrix , .NET Standard 2.1 is not supported by .NET Framework at all, which means I cannot upgrade to .NET Standard 2.1 and use CopyWithPrivateKey !根据此矩阵,.NET Framework 根本不支持 .NET Standard 2.1,这意味着我无法升级到 .NET Standard 2.1并使用CopyWithPrivateKey

How can I create an X509Certificate2 with a private key in .NET Standard 2.0 in a way that's compatible with .NET Core?如何以与 .NET Core 兼容的方式在 .NET Standard 2.0 中创建带有私钥的X509Certificate2

After much digging, the only solution I found was to convert the certificate to a PKCS12-formatted byte array, append the private key, and then read it back into an X509Certificate2 object.经过大量挖掘,我找到的唯一解决方案是将证书转换为 PKCS12 格式的字节数组,附加私钥,然后将其读回X509Certificate2对象。 It sucks, but from what I can tell in .NET Core the only way you can get one with the private key is to either call CopyWithPrivateKey (unavailable in .NET Standard 2.0 as mentioned in the question) or to load PKCS12 data which contains the private key.这很糟糕,但据我所知,在 .NET Core 中,您可以使用私钥获取私钥的唯一方法是调用CopyWithPrivateKey (如问题中所述,在 .NET Standard 2.0 中不可用)或加载包含私钥。 The following code can do that:下面的代码可以做到这一点:

    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);
    }

Use this in place of the last two lines in the question code, and instead of creating an X509Certificate2 with certGenerator , use this to create the equivalent Bouncy Castle Type to pass to it: Org.BouncyCastle.X509.X509Certificate bouncyCastleCert = certGenerator.Generate(signatureFactory);使用它代替问题代码中的最后两行,而不是使用certGenerator创建X509Certificate2certGenerator使用它来创建等效的 Bouncy Castle Type 以传递给它: Org.BouncyCastle.X509.X509Certificate bouncyCastleCert = certGenerator.Generate(signatureFactory);


Since documentation on Bouncy Castle and .NET certificates is sparse at best, here are some quirks I found during this process:由于有关 Bouncy Castle 和 .NET 证书的文档充其量很少,因此我在此过程中发现了一些怪癖:

  • The aliases for the certificate entry and the key entry in the PKCS12 container must be the same. PKCS12 容器中证书条目和密钥条目的别名必须相同。 Otherwise, you will get a "Keyset does not exist" exception when trying to use the private key.否则,您将在尝试使用私钥时收到“密钥集不存在”异常。

  • You must use X509KeyStorageFlags.Exportable when loading the byte array, otherwise you may get a "Key not valid for use in specified state" exception depending on how you use the cert.加载字节数组时必须使用X509KeyStorageFlags.Exportable ,否则根据您使用证书的方式,您可能会收到“密钥在指定状态下无效”异常。 This also means you have to supply a password because there's no overload without it, but you can use any old string since it's a temporary password.这也意味着您必须提供密码,因为没有它就不会过载,但您可以使用任何旧字符串,因为它是临时密码。

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

相关问题 BouncyCastle PrivateKey 到 X509Certificate2 PrivateKey - BouncyCastle PrivateKey To X509Certificate2 PrivateKey 从 .NET Core 中的 PEM 文件创建 X509Certificate2 - Create X509Certificate2 from PEM file in .NET Core 在x509certificate2中清空PrivateKey - Empty PrivateKey in x509certificate2 设置 X509Certificate2 PrivateKey 时出错 - Error setting X509Certificate2 PrivateKey 如何以编程方式创建有效的自签名X509Certificate2,而不是从.NET Core中的文件加载 - How to create a valid, self-signed X509Certificate2 programmatically, not loading from file in .NET Core BouncyCastle PrivateKey 到 X509Certificate2 PrivateKey (ECC) - BouncyCastle PrivateKey To X509Certificate2 PrivateKey (ECC) .NET Core ChannelFactory-将X509Certificate2设置为客户端证书 - .NET Core ChannelFactory - Set a X509Certificate2 as Client Certificate 如何在保留私钥的同时将 BouncyCastle X509Certificate 转换为 .NET Standard X509Certificate2? - How to convert BouncyCastle X509Certificate to .NET Standard X509Certificate2 while retaining the private key? .NET Framework x509Certificate2类,HasPrivateKey == true && PrivateKey == null? - .NET Framework x509Certificate2 Class, HasPrivateKey == true && PrivateKey == null? X509Certificate2:使用私钥解密时访问被拒绝 - X509Certificate2: Access denined when decrypting with privatekey
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM