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

生成自签名证书搭建HTTPS代理服务器遇证书信任错误排查

问题分析与修复方案

你的代码存在几个核心错误,导致浏览器无法识别证书由信任的CA签发,具体问题和修复方式如下:

1. 错误复用CA的密钥对

你直接将CA的公钥绑定到域名证书,还把CA私钥作为域名证书的私钥使用:

X509_set_pubkey(cert.get(), X509_get_pubkey(ca_cert));
// ...
SSL_use_PrivateKey(ssl, ca_pkey);

每个域名证书需要独立的密钥对,CA私钥仅用于签名域名证书,不能作为域名证书的私钥。

2. 证书序列号与CA重复

X509_set_serialNumber(cert.get(), X509_get_serialNumber(ca_cert));

X.509标准要求每个证书的序列号必须唯一,和CA证书复用序列号会被浏览器判定为无效。

3. 颁发者名称设置错误

X509_set_issuer_name(cert.get(), name);

你把颁发者设为当前域名证书的主体名称,导致证书变成自签名状态。正确做法是将颁发者设置为CA证书的主体名称,这样浏览器才能验证证书链到已安装的信任CA。


修复后的代码示例

static bool generateX509(const std::shared_ptr<CA>& ca, SSL *ssl, const char * domain)
{
    auto ca_cert = ca->ca_crt.get();
    auto ca_pkey = ca->ca_key.get();

    // 生成域名证书专属密钥对
    std::unique_ptr<EVP_PKEY, void (*)(EVP_PKEY *)> domain_pkey{EVP_PKEY_new(), EVP_PKEY_free};
    std::unique_ptr<RSA, void (*)(RSA *)> rsa{RSA_generate_key(2048, RSA_F4, nullptr, nullptr), RSA_free};
    if (!rsa || !EVP_PKEY_assign_RSA(domain_pkey.get(), rsa.release())) {
        return false;
    }

    // 初始化域名证书
    std::unique_ptr<X509, void (*)(X509 *)> cert{X509_new(), X509_free};
    
    // 继承CA的有效期
    X509_set_notBefore(cert.get(), X509_get_notBefore(ca_cert));
    X509_set_notAfter(cert.get(), X509_get_notAfter(ca_cert));
    
    // 生成唯一序列号(示例用时间戳+随机数,实际可改用加密安全随机数)
    ASN1_INTEGER *serial = ASN1_INTEGER_new();
    ASN1_INTEGER_set(serial, time(nullptr) + rand());
    X509_set_serialNumber(cert.get(), serial);
    ASN1_INTEGER_free(serial);
    
    // 绑定域名证书自己的公钥
    X509_set_pubkey(cert.get(), domain_pkey.get());
    
    X509_set_version(cert.get(), 2);
    
    const unsigned char country[] = "RU";
    const unsigned char company[] = "MyCompany, PLC";
    
    // 设置域名证书的主体信息
    X509_name_st* subject_name = X509_get_subject_name(cert.get());
    X509_NAME_add_entry_by_txt(subject_name, "C",  MBSTRING_ASC, country, -1, -1, 0);
    X509_NAME_add_entry_by_txt(subject_name, "O",  MBSTRING_ASC, company, -1, -1, 0);
    X509_NAME_add_entry_by_txt(subject_name, "CN", MBSTRING_ASC, (const unsigned char *)domain, -1, -1, 0);
    
    // 设置颁发者为CA的主体信息
    X509_set_issuer_name(cert.get(), X509_get_subject_name(ca_cert));
    
    // 添加SAN扩展(兼容现代浏览器要求)
    X509_EXTENSION *Extension;
    char Buffer[512];
    sprintf(Buffer, "DNS:%s", domain);
    Extension = X509V3_EXT_conf_nid(nullptr, nullptr, NID_subject_alt_name, Buffer);
    if (Extension) {
        X509_add_ext(cert.get(), Extension, -1);
        X509_EXTENSION_free(Extension);
    }
    
    // 用CA私钥签名域名证书
    X509_sign(cert.get(), ca_pkey, EVP_sha256());
    
    // 绑定域名证书和它自己的私钥到SSL
    SSL_use_certificate(ssl, cert.get());
    SSL_use_PrivateKey(ssl, domain_pkey.get());
    // 验证证书与私钥匹配
    if (!SSL_check_private_key(ssl)) {
        return false;
    }
    
    return true;
}

额外注意事项

  • 确保CA证书已正确安装到系统的受信任根证书颁发机构存储中,不同系统/浏览器的安装路径需对应操作。
  • 序列号生成可改用加密安全的随机数(如RAND_bytes),避免冲突风险。
  • 密钥长度建议使用2048位以上,符合现代安全标准。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 20:55:20