使用OpenSSL在C语言中从PEM格式证书链文件中提取单个证书
从PEM格式证书链中逐个提取证书的实现方法
嘿,既然你已经搞定了PKCS#12文件的证书提取,那处理PEM格式的证书链其实更直接——OpenSSL提供了专门的PEM读取函数,可以循环读取链中的每一个X509证书,和你处理PKCS#12的逻辑能很好地对应上。
核心思路
PEM格式的证书链本质是多个独立的PEM证书拼接而成,每个证书都以-----BEGIN CERTIFICATE-----开头、-----END CERTIFICATE-----结尾。我们可以用PEM_read_X509函数循环读取文件,直到没有更多证书为止,读取到的每个证书都可以像你处理PKCS#12提取出的证书一样操作(比如转DER格式、存入证书栈等)。
完整代码示例
下面是和你之前PKCS#12代码风格一致的实现:
#include <stdio.h> #include <openssl/x509.h> #include <openssl/pem.h> #include <openssl/err.h> int main() { FILE *pem_file; STACK_OF(X509) *cert_chain = sk_X509_new_null(); // 创建存储证书的栈,和你用的additional_certs结构一致 X509 *single_cert = NULL; // 打开PEM证书链文件(PEM是ASCII格式,用文本模式r即可) pem_file = fopen("/etc/certs/chain.pem", "r"); if (!pem_file) { perror("Failed to open PEM certificate chain file"); return -1; } // 循环读取每个证书,直到文件结束 while ((single_cert = PEM_read_X509(pem_file, NULL, NULL, NULL)) != NULL) { // 将证书存入栈中,方便后续批量处理 sk_X509_push(cert_chain, single_cert); // 这里可以直接处理当前证书,比如转换成DER格式(和你之前i2d_X509的用法完全一样) unsigned char *der_cert = NULL; int der_len = i2d_X509(single_cert, &der_cert); if (der_len > 0) { // 示例:打印DER数据长度,你可以换成保存到文件等操作 printf("Extracted certificate DER length: %d\n", der_len); OPENSSL_free(der_cert); // 务必释放i2d_X509分配的内存 } else { fprintf(stderr, "Failed to convert certificate to DER\n"); ERR_print_errors_fp(stderr); // 打印OpenSSL错误信息便于排查 } } fclose(pem_file); // 遍历证书栈,和你处理PKCS#12的additional_certs逻辑一致 int cert_count = sk_X509_num(cert_chain); printf("Total extracted certificates: %d\n", cert_count); for (int i = 0; i < cert_count; i++) { X509 *cert = sk_X509_value(cert_chain, i); // 这里可以对每个证书执行你需要的操作,比如获取证书主题、有效期等 // ... } // 释放所有资源:sk_X509_pop_free会自动释放栈内的所有X509对象 sk_X509_pop_free(cert_chain, X509_free); ERR_free_strings(); return 0; }
关键细节说明
- 证书读取函数:
PEM_read_X509会自动识别文件中的PEM格式证书,跳过无关内容(如果有的话),每次调用返回一个X509*对象,直到返回NULL表示没有更多证书。 - 内存管理:
- 用
sk_X509_new_null()创建证书栈,和你处理PKCS#12时的additional_certs结构完全兼容,遍历方式也一样。 sk_X509_pop_free是释放证书栈的最佳方式,它会一次性释放栈本身以及栈内所有的X509对象,避免内存泄漏。i2d_X509分配的内存必须用OPENSSL_free释放,不能用普通的free。
- 用
- 错误排查:如果读取或转换证书失败,可以用
ERR_print_errors_fp(stderr)打印OpenSSL的详细错误信息,帮助定位问题。
内容的提问来源于stack exchange,提问作者APdUG
相关产品推荐
相关产品推荐

