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

错误信息

invalid peer certificate: certificate not valid for name "api.example.com"; certificate is only valid for DnsName("www.example.com")

期望的名称和证书提供的名称列表会根据每次失败的情况填入;IP 地址显示为 IpAddress(…)。早期的 rustls 版本只打印变体名称(“invalid peer certificate: NotValidForName”)。

rustls 0.23 (via reqwest, ureq, hyper-rustls) — CertificateError::NotValidForNameContext

含义

证书链是受信任的,但客户端所连接的名称不在证书的主题备用名称(SAN)中。rustls 0.23 会把两者都列出来:期望的名称,以及证书提供的每一个名称(DnsName、IpAddress 条目),因此不匹配之处一目了然。

原因

修复方法

  1. 1.

    将证书提供的名称与 URL 对比

    错误消息中已经列出了这些名称;用 openssl 可以确认服务器实际发送的内容。

    bash
    echo | openssl s_client -connect api.example.com:443 -servername api.example.com 2>/dev/null \
      | openssl x509 -noout -ext subjectAltName
  2. 2.

    覆盖地址,而不是名称

    reqwest 的 ClientBuilder::resolve 会把主机名固定解析到某个套接字地址,因此验证时仍使用证书上的名称。

    rust
    // Keep the certificate's name in the URL and send the connection to a specific address
    let addr: std::net::SocketAddr = "10.0.0.5:443".parse()?;
    let client = reqwest::Client::builder().resolve("www.example.com", addr).build()?;
    let resp = client.get("https://www.example.com/health").send().await?;
  3. 3.

    重新签发包含所有在用名称的证书

    把缺少的 DNS 名称(或 IP 条目)添加到证书中。

    bash
    openssl req -new -key server.key -out server.csr -subj "/CN=api.example.com" \
      -addext "subjectAltName=DNS:api.example.com,DNS:www.example.com"

相关错误

浏览完整的签名错误库