跳到主要内容
ecdsa.com
curl (OpenSSL backend)curl

错误信息

curl: (60) SSL certificate problem: self-signed certificate in certificate chain

也可能输出为

  • curl: (60) SSL certificate problem: self signed certificate in certificate chain
  • curl: (60) SSL certificate OpenSSL verify result: self-signed certificate in certificate chain (19)

OpenSSL 3.0 及更高版本打印“self-signed”;OpenSSL 1.1.1 打印不带连字符的“self signed”,因此日志和搜索结果中两种拼写都会出现。较新的 curl 版本(我们测试的是 8.22.0)会写作“SSL certificate OpenSSL verify result: self-signed certificate in certificate chain (19)”。Windows 上基于 Schannel 构建的 curl 会把这种情况报告为“SEC_E_UNTRUSTED_ROOT”。

curl (OpenSSL backend) — CURLE_PEER_FAILED_VERIFICATION, X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN (19)

含义

curl 沿着服务器发送的证书链一直追溯到一张自签名根证书,而这张根证书不在 curl 的 CA 证书包中。与“unable to get local issuer certificate”不同,这里的证书链是完整的:curl 能看到根证书,只是没有理由信任它。实际上,这个根证书几乎总是属于公司 CA 或拦截 TLS 的代理。

原因

修复方法

  1. 1.

    弄清这是谁的根证书

    查看证书链中的最后一张证书。如果主体是代理或安全厂商,或者是你所在公司的名称,解决办法是在这台机器上信任该根证书。如果在你无法控制的网络上看到意料之外的名称,就停下来:有人正在拦截连接。

    bash
    # Print the subject and issuer of every certificate the server (or the proxy) sends
    openssl s_client -connect api.example.com:443 -servername api.example.com -showcerts </dev/null 2>/dev/null \
      | grep -E '^ *[0-9]+ s:|^ *i:'
    # The last entry has s: == i: — that self-signed root is what curl does not trust.
  2. 2.

    将公司或代理的根证书添加到系统证书存储

    从 IT 部门获取根证书(或从受管机器的信任库中导出),并安装到 curl 使用的操作系统证书包中。容器需要在构建时安装;WSL 需要在 Linux 发行版内部安装,而不只是装在 Windows 中。

    bash
    # Debian, Ubuntu, Alpine
    sudo cp corp-root-ca.pem /usr/local/share/ca-certificates/corp-root-ca.crt
    sudo update-ca-certificates
    
    # RHEL, Fedora, Amazon Linux
    sudo cp corp-root-ca.pem /etc/pki/ca-trust/source/anchors/
    sudo update-ca-trust
  3. 3.

    只在单条命令或单个环境中信任该根证书

    --cacert 和 CURL_CA_BUNDLE 会替换 curl 的默认证书包,因此如果同一个进程也要访问公共网站,就要让它们指向一个同时包含公共根证书和私有根证书的文件。

    bash
    curl --cacert corp-root-ca.pem https://api.example.com/
    
    # Keep public roots too: build one bundle with both
    cat /etc/ssl/certs/ca-certificates.crt corp-root-ca.pem > /opt/certs/bundle.pem
    export CURL_CA_BUNDLE=/opt/certs/bundle.pem
  4. 4.

    服务器所有者:不要依赖发送根证书

    提供叶子证书和中间证书;私有根证书则改为通过配置管理分发到客户端。附带根证书只会浪费字节,永远不会让不受信任的根证书变得受信任。

    bash
    # Serve leaf + intermediates only; clients must already have the root
    cat api.example.com.crt intermediate.crt > fullchain.pem
  5. 5.

    临时诊断:关闭验证以查看颁发者

    -k 会禁用证书检查,让详细输出能够显示服务器出示的主体和颁发者。只用它来识别根证书。如果把 -k 留在脚本中,传输路径上的任何人都能读取和篡改流量,包括令牌和下载的安装程序。

    bash
    # Diagnostic only: shows who issued the certificate even though curl distrusts it
    curl -sv -k -o /dev/null https://api.example.com/ 2>&1 | grep -E 'subject:|issuer:'

相关错误

浏览完整的签名错误库