在 c# 中导出到 p12 之前将私钥添加到 X509 证书
Add Private Key to X509 Certificate before export to p12 in c#
我正在尝试以编程方式将证书及其私钥导出到 p12,而不必先将其导入证书存储。
我尝试复制的流程如下:
- 在 Mac 使用钥匙串创建证书签名请求。
- 使用它为 iOS 个应用创建配置证书
Apple 的门户网站。
- 然后我下载 Apple 新的 .cer 文件
从我的 csr 生成。
- 通常你会做的是双击 .cer 然后它
将导入 KeyChain Access 并作为一部分出现
创建的原始私钥。
- 然后您可以右键单击新证书条目并导出
这是一个 .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 的推送通知系统一起使用。
我正在尝试以编程方式将证书及其私钥导出到 p12,而不必先将其导入证书存储。
我尝试复制的流程如下:
- 在 Mac 使用钥匙串创建证书签名请求。
- 使用它为 iOS 个应用创建配置证书 Apple 的门户网站。
- 然后我下载 Apple 新的 .cer 文件 从我的 csr 生成。
- 通常你会做的是双击 .cer 然后它 将导入 KeyChain Access 并作为一部分出现 创建的原始私钥。
- 然后您可以右键单击新证书条目并导出 这是一个 .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 的推送通知系统一起使用。