You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用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.pemca1.pemca2.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

火山引擎 最新活动