OpenSSL与C开发:生成CSR时如何正确加载配置文件
问题分析与解决
你遇到的核心问题是:仅将配置加载到OSSL_LIB_CTX并不会自动把req_attributes段的内容注入到X509_REQ对象中。命令行工具openssl req内部会自动处理配置中的属性段,但C API需要手动完成这一步。
具体解决步骤
1. 加载配置并获取req_attributes段
加载配置后,需要通过CONF对象提取req_attributes段的键值对:
#include <openssl/conf.h> #include <openssl/x509.h> #include <openssl/x509v3.h> #include <openssl/pem.h> // 初始化上下文并加载配置 OSSL_LIB_CTX *ctx = OSSL_LIB_CTX_new(); if (!ctx || !OSSL_LIB_CTX_load_config(ctx, "./client.config")) { // 错误处理,比如打印错误信息 goto cleanup; } // 获取配置对象 CONF *conf = OSSL_LIB_CTX_get0_config(ctx); if (!conf) { // 错误处理 goto cleanup; } // 提取req_attributes段的配置项 STACK_OF(CONF_VALUE) *attrs = NCONF_get_section(conf, "req_attributes"); if (!attrs) { // 错误处理,比如段不存在 goto cleanup; }
2. 将属性添加到X509_REQ对象
遍历req_attributes段的每个配置项,转换为X.509标准属性并添加到CSR:
// 创建CSR对象 X509_REQ *p_x509_req = X509_REQ_new_ex(ctx, NULL); if (!p_x509_req) { // 错误处理 goto cleanup; } // 逐个添加属性 for (int i = 0; i < sk_CONF_VALUE_num(attrs); i++) { CONF_VALUE *val = sk_CONF_VALUE_value(attrs, i); // 根据属性名称获取对应的NID(比如challengePassword对应NID_pkcs9_challengePassword) int nid = OBJ_sn2nid(val->name); if (nid == NID_undef) { // 跳过未知属性,或做自定义处理 continue; } // 将属性添加到CSR if (!X509_REQ_add1_attr_by_NID(p_x509_req, nid, MBSTRING_UTF8, (const unsigned char *)val->value, -1)) { // 错误处理 goto cleanup; } }
3. 加载私钥并签名CSR
命令行工具会自动完成私钥加载和CSR签名,C代码需要手动实现:
// 加载私钥(PEM格式示例) EVP_PKEY *key = NULL; FILE *key_file = fopen("./my-key.pem", "r"); if (!key_file || !(key = PEM_read_PrivateKey(key_file, NULL, NULL, NULL))) { // 错误处理 goto cleanup; } fclose(key_file); // 设置CSR公钥并签名 if (!X509_REQ_set_pubkey(p_x509_req, key) || !X509_REQ_sign(p_x509_req, key, EVP_sha256())) { // 错误处理 goto cleanup; } // 保存CSR到文件 FILE *csr_file = fopen("./certreq.csr", "w"); if (csr_file) { PEM_write_X509_REQ(csr_file, p_x509_req); fclose(csr_file); } // 资源清理 cleanup: X509_REQ_free(p_x509_req); EVP_PKEY_free(key); OSSL_LIB_CTX_free(ctx);
关键说明
OSSL_LIB_CTX仅提供配置和算法的上下文环境,不会自动将配置内容绑定到具体的X509_REQ对象,必须手动读取配置段并应用。X509_REQ_add1_attr_by_NID是将配置属性转换为X.509标准属性的核心函数,需确保配置中的属性名称(如challengePassword)对应正确的NID。
内容的提问来源于stack exchange,提问作者Matteo Prinetti
相关产品推荐
相关产品推荐

