本文へスキップ
ecdsa.com
Python ssl module (OpenSSL host check)Python の cryptography

エラーメッセージ

[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: Hostname mismatch, certificate is not valid for 'api.example.com'.

別の表記

  • [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: IP address mismatch, certificate is not valid for '127.0.0.1'.

引用符内の名前は、接続先のホストです。IP アドレスの場合、Python は「IP address mismatch, certificate is not valid for '…'.」と出力します。メッセージの後には「(_ssl.c:1082)」のようなソースの位置が続きます。

Python ssl module (OpenSSL host check) — ssl.SSLCertVerificationError, X509_V_ERR_HOSTNAME_MISMATCH (62)

このエラーの意味

証明書チェーンは信頼されていますが、Python に検証を指示した名前(URL のホスト、または server_hostname)が、証明書のサブジェクト代替名に含まれていません。Python 3.7 以降、このチェックはハンドシェイク中に OpenSSL が行うため、以前の ssl.CertificateError ではなく、証明書の検証エラーとして表面化します。

発生する理由

修正方法

  1. 1.

    証明書が対象とする名前を一覧表示する

    subjectAltName のエントリと、Python に渡しているホストを比較してください。

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

    すべての名前を subjectAltName に含めて再発行する

    すべての DNS 名を追加し、IP アドレスでアクセスする場合は IP エントリも追加してください。コモンネームにしかない名前は、照合に使われません。

    bash
    # Include every DNS name and IP address clients use
    openssl req -new -key server.key -out server.csr -subj "/CN=api.example.com" \
      -addext "subjectAltName=DNS:api.example.com,DNS:api.internal.example.com,IP:10.0.0.5"
  3. 3.

    アドレスに接続しつつ、証明書の名前を検証する

    特定のアドレス(ロードバランサーのノード、トンネル)に接続しなければならない場合は、ホスト名のチェックを無効にするのではなく、server_hostname を証明書に記載された名前に設定したままにしてください。

    python
    import socket, ssl
    
    # Connect to an address, but verify (and send SNI) for the certificate's name
    ctx = ssl.create_default_context()
    with socket.create_connection(("10.0.0.5", 443)) as raw:
        with ctx.wrap_socket(raw, server_hostname="api.example.com") as tls:
            print(tls.version())

関連するエラー

署名エラーデータベースをすべて見る