跳到主要内容
ecdsa.com
rustls (via reqwest, ureq, hyper-rustls, tonic)Rust

错误信息

invalid peer certificate: UnknownIssuer

也可能输出为

  • InvalidCertificate(UnknownIssuer)

reqwest 会把它打印在错误来源链的末尾:“error sending request for url (…): client error (Connect): invalid peer certificate: UnknownIssuer”;Debug 输出显示为 InvalidCertificate(UnknownIssuer)。ureq 打印的是“io: invalid peer certificate: UnknownIssuer”。基于 rustls 构建的原生二进制程序(pnpm 12 和许多 CLI)显示的也是同样的文本。

rustls (via reqwest, ureq, hyper-rustls, tonic) — rustls::Error::InvalidCertificate(CertificateError::UnknownIssuer)

含义

rustls 无法为服务器证书构建出通往任一已配置信任锚的证书链。UnknownIssuer 是 rustls 对所有路径构建失败统一使用的错误码:私有 CA 或代理 CA、缺失的中间证书,或者自签名证书。哪些根证书被视为受信任,取决于 crate 的构建方式:平台验证器(操作系统证书存储)、rustls-native-certs(启动时加载的操作系统根证书)或 webpki-roots(编译进程序的 Mozilla 列表)。

原因

修复方法

  1. 1.

    在客户端中添加根证书

    ClientBuilder::add_root_certificate 会添加一个信任锚,同时保留完整的验证(名称、日期)。

    rust
    // Trust a private root for this client (in addition to the default roots)
    let pem = std::fs::read("corp-root-ca.pem")?;
    let client = reqwest::Client::builder()
        .add_root_certificate(reqwest::Certificate::from_pem(&pem)?)
        .build()?;
  2. 2.

    将根证书安装到操作系统的证书存储

    使用平台验证器(reqwest 0.13 的默认设置)时,操作系统证书存储中的根证书会被信任;在 Linux 上,运行 update-ca-certificates 就够了。

    bash
    # reqwest 0.13 verifies with the platform verifier: install the root in the OS store
    sudo cp corp-root-ca.pem /usr/local/share/ca-certificates/corp-root-ca.crt
    sudo update-ca-certificates
  3. 3.

    检查编译进程序的是哪种根证书来源

    cargo tree 会显示使用的是 webpki-roots 还是 rustls-native-certs;如果必须使用操作系统的证书存储,就切换 Cargo 特性。

    bash
    # Which root source is compiled into this binary? (a crate that is absent reports no match)
    cargo tree -e features -i rustls-platform-verifier   # OS verifier (reqwest 0.13 default)
    cargo tree -e features -i rustls-native-certs        # OS roots loaded at start-up
    cargo tree -e features -i webpki-roots               # Mozilla roots compiled in, OS store ignored
  4. 4.

    服务器管理员:发送中间证书

    如果握手中只有一张证书,而它的颁发者是中间 CA,就说明服务器配置不完整。

    bash
    openssl s_client -connect api.example.com:443 -servername api.example.com -showcerts </dev/null 2>/dev/null \
      | grep -E '^ *[0-9]+ s:|^ *i:'

相关错误

浏览完整的签名错误库