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

C# 在导出到c中的p12之前,将私钥添加到X509证书#,c#,ios,x509certificate,C#,Ios,X509certificate,我试图以编程方式将证书导出到具有私钥的p12,而不必首先将其导入证书存储 我尝试复制的流程如下所示: 在Mac上,使用密钥链创建证书签名请求 使用此选项可使用为iOS应用创建配置证书 苹果的门户网站 然后我下载苹果公司新的.cer文件 由我的csr生成 通常,您接下来要做的是双击.cer并单击它 将导入到KeyChain Access中,并作为一部分显示 创建的原始私钥的 然后右键单击新证书条目并导出 这是一个.p12 我需要复制c#中的最后两个步骤。我有一个来自苹果的.cer,我有公钥和私钥,

我试图以编程方式将证书导出到具有私钥的p12,而不必首先将其导入证书存储

我尝试复制的流程如下所示:

  • 在Mac上,使用密钥链创建证书签名请求
  • 使用此选项可使用为iOS应用创建配置证书 苹果的门户网站
  • 然后我下载苹果公司新的.cer文件 由我的csr生成
  • 通常,您接下来要做的是双击.cer并单击它 将导入到KeyChain Access中,并作为一部分显示 创建的原始私钥的
  • 然后右键单击新证书条目并导出 这是一个.p12
  • 我需要复制c#中的最后两个步骤。我有一个来自苹果的.cer,我有公钥和私钥,我需要以某种方式应用私钥,以便当我以编程方式将其导出为p12时,它与我上面手动执行的方式相匹配

    我可以像这样导入.cer:

     X509Certificate2 originalCert = new X509Certificate2(@"c:\temp\aps.cer");
     //then export it like so
     byte[] p12 = originalCert.Export(X509ContentType.Pkcs12, "password");
    
    但当我将其与我用钥匙链手动创建的钥匙链进行比较时,它不匹配,即:

      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()),我现在很困惑,如果它是随机的,解密是如何发生的


    谢谢。

    首先,我要感谢上面提到的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,它可以与苹果的推送通知系统一起工作。

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