使用C语言实现SSL证书验证及间接CRL检查的技术咨询
C语言实现SSL证书验证及间接CRL检查的技术咨询
老哥,我看你已经通过OpenSSL命令行搞定了证书链的基础验证,现在想把这套逻辑搬到C代码里,还得处理CRL检查——尤其是遇到那种由另一个中间CA(CA2)签发的CRL情况,对吧?我给你梳理下具体的实现思路和关键代码片段,应该能帮到你:
一、先搞定基础的证书链验证
首先咱们用OpenSSL库来实现证书链验证,核心是用X509_STORE构建信任池,然后通过X509_verify_cert()完成验证。给你写个极简的示例代码:
#include <openssl/x509.h> #include <openssl/x509_vfy.h> #include <openssl/pem.h> #include <stdio.h> // 加载PEM格式证书 X509* load_cert(const char* cert_path) { FILE* fp = fopen(cert_path, "r"); if (!fp) { perror("Failed to open cert file"); return NULL; } X509* cert = PEM_read_X509(fp, NULL, NULL, NULL); fclose(fp); return cert; } // 验证证书链 int verify_cert_chain(X509* target_cert, X509_STORE* trust_store) { X509_STORE_CTX* ctx = X509_STORE_CTX_new(); if (!ctx) return -1; // 初始化验证上下文 int ret = X509_STORE_CTX_init(ctx, trust_store, target_cert, NULL); if (ret != 1) { fprintf(stderr, "Failed to init verify ctx\n"); X509_STORE_CTX_free(ctx); return -1; } // 执行验证 ret = X509_verify_cert(ctx); if (ret != 1) { fprintf(stderr, "Verification failed: %s\n", X509_verify_cert_error_string(ret)); } X509_STORE_CTX_free(ctx); return ret; } int main() { // 初始化OpenSSL环境 OpenSSL_add_all_algorithms(); ERR_load_crypto_strings(); // 加载信任链和目标证书 X509_STORE* trust_store = X509_STORE_new(); X509* root_cert = load_cert("root.pem"); X509* ca1_cert = load_cert("ca1.pem"); X509* my_cert = load_cert("mycert.pem"); if (!root_cert || !ca1_cert || !my_cert) { fprintf(stderr, "Failed to load one or more certificates\n"); return 1; } // 将信任证书加入存储池 X509_STORE_add_cert(trust_store, root_cert); X509_STORE_add_cert(trust_store, ca1_cert); // 验证证书链 int verify_result = verify_cert_chain(my_cert, trust_store); if (verify_result == 1) { printf("Certificate chain verification passed!\n"); } // 清理资源(一定要记得释放,避免内存泄漏) X509_free(root_cert); X509_free(ca1_cert); X509_free(my_cert); X509_STORE_free(trust_store); EVP_cleanup(); ERR_free_strings(); return verify_result == 1 ? 0 : 1; }
二、CRL检查的关键实现
你的场景里有两个CRL,其中crl.pem是由CA2签发的,这就需要咱们先验证CRL本身的合法性,再检查证书是否被吊销。
1. 加载并验证CRL的合法性
CRL本身也需要被验证——得确保它是由可信CA签发的。咱们先写个加载和验证CRL的函数:
// 加载PEM格式CRL X509_CRL* load_crl(const char* crl_path) { FILE* fp = fopen(crl_path, "r"); if (!fp) { perror("Failed to open CRL file"); return NULL; } X509_CRL* crl = PEM_read_X509_CRL(fp, NULL, NULL, NULL); fclose(fp); return crl; } // 验证CRL是否合法(由可信CA签发) int verify_crl(X509_CRL* crl, X509_STORE* trust_store) { // 获取CRL的签发者名称 X509_NAME* crl_issuer = X509_CRL_get_issuer(crl); if (!crl_issuer) return 0; // 从信任池中查找签发者的证书 X509* issuer_cert = X509_STORE_get_by_subject_name(trust_store, crl_issuer); if (!issuer_cert) { fprintf(stderr, "Cannot find issuer certificate for CRL\n"); return 0; } // 验证CRL的签名 int ret = X509_CRL_verify(crl, X509_get_pubkey(issuer_cert)); X509_free(issuer_cert); return ret == 1; }
2. 检查证书是否被吊销
验证完CRL合法后,就可以检查目标证书的序列号是否在CRL的吊销列表里了:
// 检查证书是否被CRL吊销 int is_cert_revoked(X509* cert, X509_CRL* crl) { ASN1_INTEGER* cert_serial = X509_get_serialNumber(cert); // 根据序列号查找是否在吊销列表中 X509_REVOKED* revoked_entry = X509_CRL_get_by_serial(crl, cert_serial); return revoked_entry != NULL; }
3. 适配你的多中间CA场景
因为crl.pem是CA2签发的,所以你需要把CA2的证书也加入到信任池中,这样才能验证这个CRL的合法性。完整的流程应该是:
- 加载
root.pem、ca1.pem、ca2.pem到信任池; - 验证
mycert.pem的证书链; - 加载
crl.pem,验证其合法性(用CA2的证书); - 检查
mycert.pem是否在crl.pem中被吊销; - 加载
ca_crl.pem,验证其合法性(用Root证书); - 检查
ca1.pem是否在ca_crl.pem中被吊销;
三、几个容易踩坑的注意事项
- CRL有效期别忘查:一定要检查CRL本身是否过期,用
X509_CRL_get_lastUpdate()和X509_CRL_get_nextUpdate()对比当前系统时间; - 自动获取CRL分发点:如果需要从证书的CRL分发点自动下载CRL,可以用
X509_get_ext_d2i()解析证书的CRL_DIST_POINTS扩展,拿到URL后进行下载; - 错误排查要到位:OpenSSL的函数出错时,可以用
ERR_get_error()和ERR_error_string()打印详细错误信息,方便排查; - 内存管理要严谨:OpenSSL的所有资源(X509、X509_CRL、X509_STORE等)用完必须释放,不然会有内存泄漏问题。
备注:内容来源于stack exchange,提问作者antou




