跳到主要内容
ecdsa.com
Ruby openssl (Net::HTTP verify_hostname, default true)Ruby

错误信息

state=error: certificate verify failed (hostname mismatch)

也可能输出为

  • OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 peeraddr=127.0.0.1:8443 state=error: certificate verify failed (hostname mismatch)

完整消息:“SSL_connect returned=1 errno=0 peeraddr=<ip>:<port> state=error: certificate verify failed (hostname mismatch)”。消息中不包含主机名本身;把 URL 与证书对比。

Ruby openssl (Net::HTTP verify_hostname, default true) — OpenSSL::SSL::SSLError from SSL_connect

含义

证书链是受信任的,但 Net::HTTP 所连接的主机名没有出现在证书的主题备用名称中。当前的 Ruby 版本让 OpenSSL 在握手期间检查主机名(verify_hostname),因此问题表现为证书验证失败;较旧的 Ruby 则会在连接后单独抛出“hostname … does not match the server certificate”错误。

原因

修复方法

  1. 1.

    将 SAN 列表与主机对比

    消息中不包含这些名称,因此要从证书中把它们打印出来。

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

    使用证书中的名称,并固定地址

    Net::HTTP#ipaddr= 让连接指向指定的 IP,而 SNI 和验证仍使用主机名。

    ruby
    # Connect to a specific address but verify the certificate's name (Net::HTTP#ipaddr=)
    http = Net::HTTP.new("www.example.com", 443)
    http.ipaddr = "10.0.0.5"
    http.use_ssl = true
    http.get("/health")
  3. 3.

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

    把缺失的名称添加到 subjectAltName 中。

    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"

相关错误

浏览完整的签名错误库