在 c# 中导出到 p12 之前将私钥添加到 X509 证书

Add Private Key to X509 Certificate before export to p12 in c#

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

我尝试复制的流程如下:

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

我需要在 C# 中复制最后 2 个步骤。我有一个来自 Apple 的 .cer,我有 public 和私钥,我需要以某种方式应用私钥,以便当我以编程方式将其导出为 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);
            }
       }

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

谢谢。

首先感谢上面的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 的推送通知系统一起使用。