在导出到c12中的p12之前,将私钥添加到X509证书

时间:2016-08-12 05:29:36

标签: c# ios x509certificate

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

我想要复制的流程如下:

  1. 在Mac上使用Keychain创建证书签名请求。
  2. 使用此选项为iOS应用程序创建配置证书 Apple的门户网站。
  3. 然后我下载Apple拥有的新.cer文件     从我的csr生成。
  4. 通常你要做的就是双击.cer和它 将导入到KeyChain Access中,并作为一个部分出现 已创建的原始私钥。
  5. 然后,您可以右键单击新证书条目并导出 这是一个.p12。
  6. 我需要复制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);
                }
           }
    

    似乎使用随机生成的字节来执行操作(请参阅新的SecuredRandom()),现在我对如果在某种程度上随机化解密会如何发生感到困惑?

    感谢。

1 个答案:

答案 0 :(得分: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的推送通知系统。