如何以编程方式在 OpenSSL 中加载 PKCS#12 文件?

Posted

技术标签:

【中文标题】如何以编程方式在 OpenSSL 中加载 PKCS#12 文件?【英文标题】:How to load a PKCS#12 file in OpenSSL programmatically? 【发布时间】:2011-09-16 08:07:40 【问题描述】:

在基于 OpenSSL 的 SSL 服务器应用程序中,我们如何以编程方式加载 PKCS#12 文件?

另外,我可以在 OpenSSL 的同一文件中加载具有证书、密钥和 CA 的 PKCS#12 文件吗?

【问题讨论】:

【参考方案1】:

试试man SSL,它会为您提供 OpenSSL 函数列表。 SSL_load_client_CA_file 之类的东西可能适合您的需求;这取决于证书是在磁盘上的文件中还是已经在内存中。有很多辅助函数,其中一个可以解决问题。另请查看man PEM 了解 PEM 处理例程。

编辑:嗯,也许d2i_PKCS12_fpPKCS12_parse 的组合(两者都可从<openssl/pkcs12.h> 获得)让您从文件中读取证书并解析它。

【讨论】:

【参考方案2】:

是的,您可以使用 OpenSSL 在同一个文件中加载包含证书、密钥和 CA 的 PKCS#12 文件。

使用d2i_PKCS12_fp()d2i_PKCS12_bio() 加载PKCS#12 文件。 可选择使用PKCS12_verify_mac() 来验证密码。 使用PKCS12_parse() 为您解密和提取密钥、证书和CA 链。

来自openssl-1.0.0d/demos/pkcs12/pkread.c:

#include <stdio.h>
#include <stdlib.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/pkcs12.h>

/* Simple PKCS#12 file reader */

int main(int argc, char **argv)

    FILE *fp;
    EVP_PKEY *pkey;
    X509 *cert;
    STACK_OF(X509) *ca = NULL;
    PKCS12 *p12;
    int i;
    if (argc != 4) 
        fprintf(stderr, "Usage: pkread p12file password opfile\n");
        exit (1);
    
    OpenSSL_add_all_algorithms();
    ERR_load_crypto_strings();
    if (!(fp = fopen(argv[1], "rb"))) 
        fprintf(stderr, "Error opening file %s\n", argv[1]);
        exit(1);
    
    p12 = d2i_PKCS12_fp(fp, NULL);
    fclose (fp);
    if (!p12) 
        fprintf(stderr, "Error reading PKCS#12 file\n");
        ERR_print_errors_fp(stderr);
        exit (1);
    
    if (!PKCS12_parse(p12, argv[2], &pkey, &cert, &ca)) 
        fprintf(stderr, "Error parsing PKCS#12 file\n");
        ERR_print_errors_fp(stderr);
        exit (1);
    
    PKCS12_free(p12);
    if (!(fp = fopen(argv[3], "w"))) 
        fprintf(stderr, "Error opening file %s\n", argv[1]);
        exit(1);
    
    if (pkey) 
        fprintf(fp, "***Private Key***\n");
        PEM_write_PrivateKey(fp, pkey, NULL, NULL, 0, NULL, NULL);
    
    if (cert) 
        fprintf(fp, "***User Certificate***\n");
        PEM_write_X509_AUX(fp, cert);
    
    if (ca && sk_X509_num(ca)) 
        fprintf(fp, "***Other Certificates***\n");
        for (i = 0; i < sk_X509_num(ca); i++) 
            PEM_write_X509_AUX(fp, sk_X509_value(ca, i));
    

    sk_X509_pop_free(ca, X509_free);
    X509_free(cert);
    EVP_PKEY_free(pkey);

    fclose(fp);
    return 0;

【讨论】:

@Mathias 您提供的上述代码用于读取 DER 编码 P12 证书。是否有任何 API 可以读取 PEM 编码的 P12 证书 @Balamurugan:我从未见过 PEM 编码的 PKCS#12 文件或支持它的软件。 我想知道你是否可以扩展这个答案,以便它解析 PKCS12 结构而不会泄漏内存(即,它适合在长时间运行的程序中使用)。特别是,PKCS12_parse 似乎泄漏了大约 4kB。 @Jean-PaulCalderone:我添加了对 ca、cert 和 pkey 的额外清理。我仍然有 OpenSSL 0.9.8 的泄漏,但没有 1.0.1。【参考方案3】:

请注意,代码会将证书作为可信证书(加密)写出。 如果您想要未加密的证书,请将对 PEM_write_X509_AUX() 的调用更改为 PEM_write_X509()。

【讨论】:

该文本确实应该在 cmets 中。 这是我的问题,标签是 BEGIN TRUSTED CERTIFICATE 而不是 BEGIN CERTIFICATE

以上是关于如何以编程方式在 OpenSSL 中加载 PKCS#12 文件?的主要内容,如果未能解决你的问题,请参考以下文章

使用 OpenSSL 以编程方式将 .PEM 证书转换为 .PFX

以编程方式从 PEM 获取 KeyStore

Xampp:作曲家安装问题:模块 openssl 已在第 0 行的未知中加载

如何以编程方式加载 UIViewController?

用于 openSSL 的 PKCS#11 引擎

如果我在 OpenSSL 中加载新证书,证书是不是会更改 SSL 连接/状态“点”?