使用Openssl.net创建PKCS12文件

时间:2013-10-21 17:47:02

标签: .net ssl openssl xamarin

我正在尝试使用OpenSSL.NET从证书和密钥生成P12文件(也使用openssl.net生成)。 我的功能如下:

GenerateP12(string pwd, RSA key, string pemcert)
{
    BIO certbio = new BIO(pemcert);
    X509Certificate x = new X509Certificate(certbio);
    CryptoKey crytokey = new CryptoKey(key);
    PKCS12 p12 = new PKCS12(pwd, cryptokey, x, ca);
    BIO a = BIO.MemoryBuffer();
    p12.write(a);
    // Write 'a' to some file.
}

但是,当我尝试将该密钥导入.NET X509Certificate2对象时,我得到“输入数据无法编码为有效证书”。

如果我以pem格式获取私钥,请使用:

key.PrivateKeyAsPEM

并将其与cert pem一起写入文件,然后从终端运行以下openssl命令:

openssl pkcs12 -export -aes256 -in cert.pem -inkey key.pem -out outfile.crt

导入X509Certificate2对象可以正常工作。

有谁知道如何使用OpenSSL.NET生成PKCS12,这会给我一个与使用openssl命令行工具时生成的文件类似的文件?

谢谢,

更新 看起来我在代码中生成的P12格式不正确;如果我将它导出到一个文件,然后尝试使用openssl命令行获取信息:

openssl pkcs12 -info -in myp12.p12

我收到以下错误:

140735263351648:error:0D07209B:asn1 encoding routines:ASN1_get_object:too long:asn1_lib.c:142:
140735263351648:error:0D068066:asn1 encoding routines:ASN1_CHECK_TLEN:bad object header:tasn_dec.c:1306:
140735263351648:error:0D06C03A:asn1 encoding routines:ASN1_D2I_EX_PRIMITIVE:nested asn1 error:tasn_dec.c:831:
140735263351648:error:0D08303A:asn1 encoding routines:ASN1_TEMPLATE_NOEXP_D2I:nested asn1 error:tasn_dec.c:751:Field=version, Type=PKCS12

这解释了为什么尝试将其导入.NET X509Certificate2对象失败。 我还更改了我正在使用的Openssl.NET API,因此我的代码现在看起来如下:

string GenerateP12(string pwd, CryptoKey key, string cert)
{
    BIO certbio = new BIO(cert);
    BIO a = BIO.MemoryBuffer();
    X509Certificate x = new X509Certificate(certbio);
    Stack<X509Certificate>ca = new Stack<X509Certificate>();
    PKCS12 p12 = new PKCS12(pwd, "test", key, x, ca, SHA1_3DES, SHA1_RC2_40, 0, KEY_DEFAULT);
    p12.Write(a);
    return a.ReadString();
}

(我正在使用扩展功能,因为我需要指定要使用的算法,默认值与我需要的不同)。

3 个答案:

答案 0 :(得分:2)

您可以使用此链接来了解如何将证书和密钥转换为PKCS#12文件。

https://www.sslshopper.com/ssl-converter.html

希望它有所帮助! :)

答案 1 :(得分:0)

如果有人遇到类似的问题,我最终做的是,不是使用BIO对象将内容导出到字符串,我最终将其直接写入文件:

BIO certbio = new BIO(cert);
BIO a = BIO.File(myfile, "wb");
X509Certificate x = new X509Certificate(certbio);
Stack<X509Certificate>ca = new Stack<X509Certificate>();
PKCS12 p12 = new PKCS12(pwd, "test", key, x, ca, SHA1_3DES, SHA1_RC2_40, 0, KEY_DEFAULT);
p12.Write(a);
byte []data = System.IO.File.ReadAllBytes(myfile);
return data;

此流程按预期工作。它确实有额外的步骤,必须首先将数据写入文件,但至少这一点指向我最初导出的方式是罪魁祸首。

答案 2 :(得分:0)

由于这篇文章是在寻找同一问题的解决方案时遇到的,我想分享一种如何在不首先保存到文件系统的情况下完成此任务的方法。

我完成这项工作的最简单方法:

 ...
 using (var p12 = new PKCS12(...))
 using (var bio = BIO.MemoryBuffer())
 {
      p12.Write(bio);
      return bio.ReadBytes((int) bio.BytesPending).Array; // returns byte[]
 }
 ...

 // return value can be saved like this
 File.WriteAllBytes("filename", result);

从p12获取字节的另一种方法是使用MemoryStream

 ...
 using (var p12 = new PKCS12(...))
 using (var bio = BIO.MemoryBuffer())
 {
     p12.Write(bio);
     const int bufferSize = 4096;
     using (var memoryStream = new MemoryStream())
     {
         while (bio.BytesPending > 0)
         {
             var segment = bio.ReadBytes(bufferSize);
             memoryStream.Write(segment.Array, 0, segment.Count);
         }
         return memoryStream.ToArray(); // returns byte[]
     }
 }
 ...

 // return value can be saved like this
 File.WriteAllBytes("filename", result);

我可能更喜欢第一种解决方案,因为它更短,并且不会创建如此多的中间数组。我想知道这些证书到底有多大。我的方案总是低于4 KB。希望这有助于某人。