【问题标题】:Add Private Key to X509 Certificate before export to p12 in c#在 c# 导出到 p12 之前将私钥添加到 X509 证书
【发布时间】:2016-08-12 05:29:36
【问题描述】:

我正在尝试使用其私钥以编程方式将证书导出到 p12,而不必先将其导入证书存储区。

我试图复制的流程如下:

  1. 在 Mac 上使用钥匙串创建证书签名请求。
  2. 使用它为 iOS 应用程序创建配置证书,使用 苹果的门户。
  3. 然后我下载 Apple 提供的新 .cer 文件 从我的 csr 生成。
  4. 通常你会做的是双击 .cer 和它 将导入 KeyChain Access 并作为一部分出现 创建的原始私钥。
  5. 然后您可以右键单击新的证书条目并导出 这是一个 .p12。

我需要在 c# 中复制最后两个步骤。我有一个来自 Apple 的 .cer,我有公钥和私钥,我需要以某种方式应用私钥,以便当我以编程方式将其导出为 p12 时,它与我在上面手动执行的那个匹配。

我可以像这样导入 .cer:

 X509Certificate2 originalCert = new X509Certificate2(@"c:\temp\aps.cer");
 //then export it like so
 byte[] p12 = originalCert.Export(X509ContentType.Pkcs12, "password");

但是当我将它与我手动创建的 KeyChain 进行比较时,它不匹配,即:

  byte[] p12Bytes = File.ReadAllBytes(@"c:\temp\manual.p12");
  string manual = Convert.ToBase64String(p12Bytes);
  string generated = Convert.ToBase64String(p12);
  Assert.IsTrue(manual == generated);//this fails

当然,我对这一切如何运作的理解可能存在问题:)

我已尝试使用 BouncyCastle 库来执行此操作,但以下代码对最后的输出没有任何作用。

Org.BouncyCastle.X509.X509Certificate cert = Org.BouncyCastle.Security.DotNetUtilities.FromX509Certificate(originalCert);
X509CertificateEntry[] chain = new X509CertificateEntry[1];
X509CertificateEntry entry = new X509CertificateEntry(cert);
        chain[0] = entry;

        AsymmetricKeyEntry keyPair;
        using (StreamReader reader = File.OpenText(@"c:\temp\EXPORTED PRIVATE KEY.p12"))
        {
            Pkcs12Store store = new Pkcs12Store(reader.BaseStream, "Password".ToCharArray());
            foreach (string n in store.Aliases)
            {
                if (store.IsKeyEntry(n))
                {
                    AsymmetricKeyEntry key = store.GetKey(n);

                    if (key.Key.IsPrivate)
                    {
                        keyPair = key;
                        pfx.SetKeyEntry("TEST CERT", key, chain);
                        break;
                    }
                }
            }
        }

谁能指点我正确的方向?

编辑:我又做了一项更改,看起来很有希望,因为键的长度现在几乎匹配了。我现在通过 BouncyCastle 导出 p12,如下所示:

     using (MemoryStream stream = new MemoryStream())
        {
            pfx.Save(stream, "password".ToCharArray(), new SecureRandom());

            byte[] p12Bytes = File.ReadAllBytes(@"c:\temp\newexported.p12");
            string realp12 = Convert.ToBase64String(p12Bytes);

            using (BinaryReader reader = new BinaryReader(stream))
            {
                byte[] p12 = stream.ToArray();
                string generated12 = Convert.ToBase64String(p12);
                Assert.IsTrue(realp12.Length == generated12.Length);
            }
       }

它似乎使用随机生成的字节来执行操作(参见 new SecuredRandom()),我现在很困惑,如果它是随机的,解密是如何发生的?

谢谢。

【问题讨论】:

  • ios?还是 macOS? .NET Core 还是 Mono?你做了什么来制作你认为不匹配的 PFX? (请注意,PFX 中有一个随机 IV,因此相同内容的两代 PFX 仍然会产生不同的结果)。
  • 这是一个使用 .NET 生成 PFX 的 iOS 应用程序。我不明白你关于随机性的最后一点。当我使用 .NET 生成 PFX 时,每次都会返回相同的字符串。
  • 奇怪。我刚刚检查了 Windows Server 2012 R2 上的 .NET Framework 4.6.2,并在同一个对象上调用 X509Certificate2.Export(X509ContentType.Pkcs12, "") 两次会产生不同的输出(相同的长度,不同的值),无论它是公共的+私人对证书或仅公共证书。
  • 是的,你是对的。快速测试中的最后 58 个字符不同,但其余字符完全相同。两者都是 2344 长。当我将它与我生成的手册进行比较时,它的长度为 4460,所以肯定有一些我没有做的事情是钥匙串。很高兴知道它们无论如何都不完全相同,但我希望长度匹配。

标签: c# ios x509certificate


【解决方案1】:

首先我要感谢上面的 bartonjs 帮助解决了这个问题。不同的长度让我以不同的方式思考这个问题。

我上面的编辑解决了它。我假设通过调用:

 pfx.SetKeyEntry("MyKey", key, chain);

它将密钥设置到链中的证书中。相反,我不得不像这样导出它们:

using (MemoryStream stream = new MemoryStream())
{
     pfx.Save(stream, "Password".ToCharArray(), new SecureRandom());//The SecureRandom must be responsible for the different strings/lengths when re-generated.
     using (BinaryReader reader = new BinaryReader(stream))
     {
         byte[] p12 = stream.ToArray();
         //then I can save this off somewhere - in my case the db.
     }
}

现在我有一个附有证书和私钥的 p12,它都适用于 Apple 的推送通知系统。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-09-18
    • 1970-01-01
    • 1970-01-01
    • 2013-05-09
    • 2019-12-06
    • 1970-01-01
    • 1970-01-01
    • 2015-07-02
    相关资源
    最近更新 更多