如何从 .NET 标准中的 PEM 文件加载带有私钥的证书 [英] How to load a certificate with private key from PEM files in .NET standard

查看:40
本文介绍了如何从 .NET 标准中的 PEM 文件加载带有私钥的证书的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试从 .NET 标准库中的 PEM 文件加载 X509Certificate2.

I'm trying to load an X509Certificate2 from PEM files in a .NET standard library.

我使用 openssl 创建了一个自签名证书,如下所示:

I created a self-signed certificate using openssl like so:

openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -nodes -subj /CN=localhost -days 365

我将生成的 PEM 文件加载到项目中的嵌入字符串资源中,并尝试使用以下代码加载它们:

I loaded the resulting PEM files into embedded string resources within the project and am trying to load them with the following code:

private X509Certificate2 GetCertificate()
{
    try
    {
        byte[] pubPem = System.Text.Encoding.UTF8.GetBytes(Properties.Resources.DefaultPublicPem.Trim());
        var cert = new X509Certificate2(pubPem);
        var rsa = GetRSAFromPem(Properties.Resources.DefaultPrivatePem.Trim());
        cert.PrivateKey = rsa;
        return cert;
    }

    catch (Exception ex)
    {
        // ignore errors
        return null;
    }
}

public static RSA GetRSAFromPem(String pemstr)
{
    RSA rsaKey = RSA.Create();
    Func<RSA, RsaKeyParameters, RSA> MakePublicRCSP = (RSA rcsp, RsaKeyParameters rkp) =>
    {
        RSAParameters rsaParameters = DotNetUtilities.ToRSAParameters(rkp);
        rcsp.ImportParameters(rsaParameters);
        return rsaKey;
    };

    Func<RSA, RsaPrivateCrtKeyParameters, RSA> MakePrivateRCSP = (RSA rcsp, RsaPrivateCrtKeyParameters rkp) =>
    {
        RSAParameters rsaParameters = DotNetUtilities.ToRSAParameters(rkp);
        rcsp.ImportParameters(rsaParameters);
        return rsaKey;
    };

    PemReader reader = new PemReader(new StringReader(pemstr));
    object kp = reader.ReadObject();

    // If object has Private/Public property, we have a Private PEM
    var hasPrivate = kp.GetType().GetProperty("Private") != null;
    var isPrivate = kp is RsaPrivateCrtKeyParameters;
    return isPrivate ? MakePrivateRCSP(rsaKey, (RsaPrivateCrtKeyParameters)kp) : hasPrivate ? MakePrivateRCSP(rsaKey, (RsaPrivateCrtKeyParameters)(((AsymmetricCipherKeyPair)kp).Private)) : MakePublicRCSP(rsaKey, (RsaKeyParameters)kp);
}

我在 Android 上进行了测试,效果很好.

I tested it on Android and it works great.

在 iOS 上我还没有测试过,但在 UWP 上它失败了,我在尝试在证书上设置私钥时收到 PlatformNotSupported 异常.

On iOS I haven't tested yet, but on UWP it fails and I get a PlatformNotSupported Exception while trying to set the PrivateKey on the certificate.

所以我想知道什么不受支持,以及我是否做得不对.

So I'm wondering what's not supported, and whether I'm not doing it right.

推荐答案

根据this,.net core 不支持在现有证书上设置私钥:

According to this, setting the private key on an existing certificate is not supported in .net core:

PrivateKey 属性将回到 netstandard2.0 (#12295),但是它将为 .NET Core 投入使用.

The PrivateKey property will be back in netstandard2.0 (#12295), but it will throw on set for .NET Core.

set_PrivateKey 在 .NET Framework 中有很多细微差别(取决于你如何使用它,你最终可能会产生副作用在机器重新启动后持续存在),并将该级别的细微差别反映到Windows 以外的平台非常棘手,这就是为什么我们不支持一下.

set_PrivateKey has a large amount of nuance in .NET Framework (depending on how you use it you can end up with side effects that persist across machine reboots), and mirroring that level of nuance to platforms other than Windows is awfully tricky, which is why we don't support it.

在 .NET Core 上获得带有私钥的证书的唯一支持方式是通过 PFX/PKCS12 文件(或已经是通过 X509Store 关联).

The only supported way to have a cert with a private key on .NET Core is through a PFX/PKCS12 file (or the cert+key pair to already be associated via X509Store).

因此,解决此问题的一种方法是将公私对合并到 PFX 文件中,将其作为资源嵌入,然后从该 PFX 初始化 X509Certificate2.

So one way to solve this was to merge public-private pair to a PFX file, embed it as a resource, and initialize the X509Certificate2 from that PFX.

我最终使用的另一种方法是在 UWP 上使用 RSACertificateExtensions.CopyWithPrivateKey 方法.

Another way, which I ended up using, is to use the method RSACertificateExtensions.CopyWithPrivateKey on UWP.

所以基本上我最终构建了一个平台特定的接口来加载证书.在 UWP 上,它是这样实现的:

So basically I ended up building a platform specific interface for loading the certificates. On UWP it was implemented like this:

public class UWPCertificateBuilder : ICertificateBuilder
{
    public X509Certificate2 GetCertificate(X509Certificate2 cert, RSA key)
    {
        return cert.CopyWithPrivateKey(key);
    }
}

在 Android 上它是这样实现的:

On Android it was implemented like this:

public class DroidCertificateBuilder : ICertificateBuilder
{
    public X509Certificate2 GetCertificate(X509Certificate2 cert, RSA key)
    {
        cert.PrivateKey = key;
        return cert;
    }
}

这篇关于如何从 .NET 标准中的 PEM 文件加载带有私钥的证书的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆