2

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

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();
}

(我使用的是扩展函数,因为我需要指定要使用的算法,并且默认值与我需要的不一样)。

4

2 回答 2

2

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

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

 ...
 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。希望这可以帮助某人。

于 2017-07-23T14:45:57.950 回答
1

如果有人遇到类似的问题,我最终要做的是,我没有使用 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;

这个流程按预期工作。它确实有必须首先将数据写入文件的额外步骤,但至少这表明我最初作为罪魁祸首进行导出的方式。

于 2013-12-19T22:58:41.477 回答