You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenSSL:如何用C语言实现CA对CSR的签名

C语言实现OpenSSL CA对CSR的签名步骤

下面是基于OpenSSL库实现CA签名CSR的完整流程,包含关键代码片段和注意事项:

1. 加载CA证书与私钥

首先从PEM文件中读取CA的证书和对应私钥,这是签名的核心凭证:

#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <time.h>

// 加载CA证书
X509* load_ca_cert(const char* cert_path) {
    FILE* fp = fopen(cert_path, "r");
    if (!fp) return NULL;
    X509* ca_cert = PEM_read_X509(fp, NULL, NULL, NULL);
    fclose(fp);
    return ca_cert;
}

// 加载CA私钥
EVP_PKEY* load_ca_privkey(const char* key_path) {
    FILE* fp = fopen(key_path, "r");
    if (!fp) return NULL;
    EVP_PKEY* ca_privkey = PEM_read_PrivateKey(fp, NULL, NULL, NULL);
    fclose(fp);
    return ca_privkey;
}

2. 处理程序内的CSR对象

你已在程序中生成X509_REQ* csr对象,可直接使用。推荐先验证CSR签名合法性:

// 验证CSR签名
int verify_csr(X509_REQ* csr) {
    EVP_PKEY* csr_pubkey = X509_REQ_get_pubkey(csr);
    int ret = X509_REQ_verify(csr, csr_pubkey);
    EVP_PKEY_free(csr_pubkey);
    return ret == 1; // 返回1表示验证通过
}

3. 初始化待签名的证书结构

创建新X509证书对象,填充必要字段:

X509* create_signed_cert(X509_REQ* csr, X509* ca_cert, EVP_PKEY* ca_privkey) {
    X509* cert = X509_new();
    if (!cert) return NULL;

    // 设置证书版本(X509_V3对应版本3)
    X509_set_version(cert, X509_V3);

    // 设置唯一序列号(示例用时间戳,生产环境建议用自增序列或加密随机数)
    ASN1_INTEGER_set(X509_get_serialNumber(cert), (long)time(NULL));

    // 设置有效期:起始为当前时间,结束为1年后
    X509_gmtime_adj(X509_get_notBefore(cert), 0);
    X509_gmtime_adj(X509_get_notAfter(cert), 365*24*3600L);

    // 设置颁发者(与CA证书一致)
    X509_set_issuer_name(cert, X509_get_subject_name(ca_cert));

    // 设置主体(从CSR复制)
    X509_set_subject_name(cert, X509_REQ_get_subject_name(csr));

    // 设置公钥(从CSR提取)
    EVP_PKEY* csr_pubkey = X509_REQ_get_pubkey(csr);
    if (!X509_set_pubkey(cert, csr_pubkey)) {
        EVP_PKEY_free(csr_pubkey);
        X509_free(cert);
        return NULL;
    }
    EVP_PKEY_free(csr_pubkey);

    // 添加基本约束扩展(标记为终端实体,非CA)
    X509V3_CTX ctx;
    X509V3_set_ctx_nodb(&ctx);
    X509V3_set_ctx(&ctx, ca_cert, cert, csr, NULL, 0);
    X509_add_ext(cert, X509V3_EXT_conf_nid(NULL, &ctx, NID_basic_constraints, "critical,CA:FALSE"), -1);

    // 用CA私钥签名证书,算法采用SHA256withRSA
    if (X509_sign(cert, ca_privkey, EVP_sha256()) <= 0) {
        X509_free(cert);
        return NULL;
    }

    return cert;
}

4. 保存签名后的证书

将生成的证书写入PEM文件:

int save_cert(X509* cert, const char* output_path) {
    FILE* fp = fopen(output_path, "w");
    if (!fp) return 0;
    int ret = PEM_write_X509(fp, cert);
    fclose(fp);
    return ret;
}

5. 主流程与错误处理

整合上述函数,添加错误打印逻辑:

int main() {
    // 初始化OpenSSL错误处理
    ERR_load_crypto_strings();
    OpenSSL_add_all_algorithms();

    // 加载CA凭证
    X509* ca_cert = load_ca_cert("ca.crt");
    EVP_PKEY* ca_privkey = load_ca_privkey("ca.key");
    if (!ca_cert || !ca_privkey) {
        fprintf(stderr, "加载CA证书/私钥失败\n");
        ERR_print_errors_fp(stderr);
        goto cleanup;
    }

    // 此处替换为你程序中生成的CSR对象
    X509_REQ* csr = ...;

    // 验证CSR
    if (!verify_csr(csr)) {
        fprintf(stderr, "CSR签名验证失败\n");
        goto cleanup;
    }

    // 签名证书
    X509* signed_cert = create_signed_cert(csr, ca_cert, ca_privkey);
    if (!signed_cert) {
        fprintf(stderr, "签名CSR失败\n");
        ERR_print_errors_fp(stderr);
        goto cleanup;
    }

    // 保存证书
    if (!save_cert(signed_cert, "signed.crt")) {
        fprintf(stderr, "保存签名证书失败\n");
        goto cleanup;
    }

cleanup:
    // 释放所有OpenSSL资源
    X509_free(ca_cert);
    EVP_PKEY_free(ca_privkey);
    X509_REQ_free(csr);
    X509_free(signed_cert);
    ERR_free_strings();
    return 0;
}

注意事项

  • 序列号必须唯一,避免重复使用引发安全问题,生产环境建议使用自增序列或加密安全随机数。
  • 证书有效期按需调整,避免设置过长。
  • 可根据需求添加更多扩展项(如密钥用法、主题备用名称等)。
  • 所有OpenSSL资源使用后必须调用对应free函数释放,防止内存泄漏。
  • 编译时需链接OpenSSL库,例如:gcc your_code.c -o sign_csr -lcrypto

内容的提问来源于stack exchange,提问作者Pepepotamo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 01:45:40