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

如何为X509_req对象设置颁发者名称?C++签名CSR咨询

Great question! Let's clear up the confusion first, then walk through a straightforward C++ implementation using OpenSSL.

Clarification on Issuer Names for X509_REQ

First off, you’re right that x509_set_issuer_name() only works with X509 objects—but here’s the key insight: you don’t need to set an issuer name on the X509_REQ (CSR) itself.

A CSR is a request from a certificate applicant; it only contains the applicant’s subject details, public key, and their own signature. The issuer name is a field that belongs to the final signed X509 certificate, not the CSR. When you sign the CSR with your CA’s private key, you’ll create a new X509 object and set the issuer name there using your CA’s subject name.

C++ Implementation to Sign a CSR with a CA Private Key

Below is a practical, clean approach using OpenSSL (with RAII to avoid memory leaks and simplify resource management). This assumes you’re using OpenSSL 1.1.1 or later (adjustments for 3.0 are noted at the end).

Step-by-Step Explanation + Code

We’ll use smart pointers with custom deleters to handle OpenSSL objects safely, then walk through loading the CA assets, processing the CSR, and generating the signed certificate.

#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <stdexcept>
#include <memory>
#include <cstdio>

// Custom deleters for RAII management of OpenSSL objects
struct X509Deleter { void operator()(X509* p) { if (p) X509_free(p); } };
struct X509ReqDeleter { void operator()(X509_REQ* p) { if (p) X509_REQ_free(p); } };
struct EVP_PKEYDeleter { void operator()(EVP_PKEY* p) { if (p) EVP_PKEY_free(p); } };
struct ASN1_INTEGERDeleter { void operator()(ASN1_INTEGER* p) { if (p) ASN1_INTEGER_free(p); } };

using X509Ptr = std::unique_ptr<X509, X509Deleter>;
using X509ReqPtr = std::unique_ptr<X509_REQ, X509ReqDeleter>;
using EVP_PKEYPtr = std::unique_ptr<EVP_PKEY, EVP_PKEYDeleter>;
using ASN1_INTEGERPtr = std::unique_ptr<ASN1_INTEGER, ASN1_INTEGERDeleter>;

// Helper to generate a cryptographically secure serial number
ASN1_INTEGERPtr generate_serial_number() {
    ASN1_INTEGERPtr serial(ASN1_INTEGER_new());
    if (!serial) throw std::runtime_error("Failed to create serial number");
    
    // Generate 16 bytes of random data for the serial (adjust size as needed)
    unsigned char buf[16];
    if (RAND_bytes(buf, sizeof(buf)) != 1) {
        throw std::runtime_error("Failed to generate random serial number");
    }
    
    if (!ASN1_INTEGER_set(serial.get(), (const BIGNUM*)buf)) {
        throw std::runtime_error("Failed to set serial number value");
    }
    return serial;
}

X509Ptr sign_csr(const std::string& csr_path, 
                 const std::string& ca_cert_path, 
                 const std::string& ca_key_path, 
                 const std::string& output_cert_path) {
    // Load CA certificate
    FILE* ca_cert_fp = fopen(ca_cert_path.c_str(), "r");
    if (!ca_cert_fp) throw std::runtime_error("Could not open CA certificate file");
    X509Ptr ca_cert(PEM_read_X509(ca_cert_fp, nullptr, nullptr, nullptr));
    fclose(ca_cert_fp);
    if (!ca_cert) throw std::runtime_error("Failed to load CA certificate");

    // Load CA private key (add password argument if key is encrypted)
    FILE* ca_key_fp = fopen(ca_key_path.c_str(), "r");
    if (!ca_key_fp) throw std::runtime_error("Could not open CA private key file");
    EVP_PKEYPtr ca_key(PEM_read_PrivateKey(ca_key_fp, nullptr, nullptr, nullptr));
    fclose(ca_key_fp);
    if (!ca_key) throw std::runtime_error("Failed to load CA private key");

    // Load CSR
    FILE* csr_fp = fopen(csr_path.c_str(), "r");
    if (!csr_fp) throw std::runtime_error("Could not open CSR file");
    X509ReqPtr csr(PEM_read_X509_REQ(csr_fp, nullptr, nullptr, nullptr));
    fclose(csr_fp);
    if (!csr) throw std::runtime_error("Failed to load CSR");

    // Create new X509 certificate
    X509Ptr cert(X509_new());
    if (!cert) throw std::runtime_error("Failed to create new X509 certificate");

    // Set certificate version (X509v3 = version 2 in OpenSSL's indexing)
    if (!X509_set_version(cert.get(), 2)) {
        throw std::runtime_error("Failed to set certificate version");
    }

    // Set secure serial number
    ASN1_INTEGERPtr serial = generate_serial_number();
    X509_set_serialNumber(cert.get(), serial.get());

    // Set validity period: start now, valid for 1 year
    X509_gmtime_adj(X509_get_notBefore(cert.get()), 0);
    X509_gmtime_adj(X509_get_notAfter(cert.get()), 365 * 24 * 3600);

    // Copy subject name from CSR to certificate
    if (!X509_set_subject_name(cert.get(), X509_REQ_get_subject_name(csr.get()))) {
        throw std::runtime_error("Failed to set certificate subject name");
    }

    // Set issuer name from CA certificate
    if (!X509_set_issuer_name(cert.get(), X509_get_subject_name(ca_cert.get()))) {
        throw std::runtime_error("Failed to set certificate issuer name");
    }

    // Extract public key from CSR and attach to certificate
    EVP_PKEYPtr pubkey(X509_REQ_get_pubkey(csr.get()));
    if (!pubkey) throw std::runtime_error("Failed to extract public key from CSR");
    if (!X509_set_pubkey(cert.get(), pubkey.get())) {
        throw std::runtime_error("Failed to attach public key to certificate");
    }

    // Sign the certificate with CA private key (using SHA-256 for security)
    if (!X509_sign(cert.get(), ca_key.get(), EVP_sha256())) {
        throw std::runtime_error("Failed to sign certificate with CA private key");
    }

    // Save the signed certificate to file
    FILE* output_fp = fopen(output_cert_path.c_str(), "w");
    if (!output_fp) throw std::runtime_error("Could not open output certificate file");
    PEM_write_X509(output_fp, cert.get());
    fclose(output_fp);

    return cert;
}

// Example usage
int main() {
    try {
        auto signed_cert = sign_csr("my_request.csr", "ca_cert.crt", "ca_private.key", "signed_cert.crt");
        printf("Successfully signed CSR! Output saved to signed_cert.crt\n");
    } catch (const std::exception& e) {
        fprintf(stderr, "Error: %s\n", e.what());
        // Optional: Print detailed OpenSSL errors
        ERR_print_errors_fp(stderr);
        return 1;
    }
    return 0;
}

Key Notes for Production

  • Serial Numbers: The example uses a random 16-byte serial number—this is critical for security (avoid sequential numbers that can be predicted).
  • Encrypted CA Keys: If your CA private key is encrypted, pass a password string or password callback as the 4th argument to PEM_read_PrivateKey().
  • Hash Algorithms: Stick to SHA-256 or higher (SHA-1 is deprecated and insecure).
  • OpenSSL 3.0 Compatibility: For OpenSSL 3.0, replace X509_REQ_get_pubkey() with X509_REQ_get0_pubkey() (the latter returns a const pointer without incrementing the reference count).
  • Error Handling: Add ERR_print_errors_fp(stderr) to debug OpenSSL-specific errors when things go wrong.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 03:33:12