Pular para o conteúdo
ecdsa.com
Python ssl module (OpenSSL host check)Python (cryptography)

Mensagem de erro

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

Também aparece como

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

O nome entre aspas é o host ao qual você se conectou. Para endereços IP, o Python diz “IP address mismatch, certificate is not valid for '…'.” Depois da mensagem vem uma localização no código-fonte, como “(_ssl.c:1082)”.

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

O que significa

A cadeia de certificados é confiável, mas o nome que o Python precisava verificar (o host da URL ou server_hostname) não está entre os Subject Alternative Names do certificado. Desde o Python 3.7, a verificação é feita pelo OpenSSL durante o handshake, por isso aparece como falha na verificação do certificado, e não como o antigo ssl.CertificateError.

Por que acontece

Como corrigir

  1. 1.

    Listar os nomes que o certificado cobre

    Compare as entradas de subjectAltName com o host que você passa ao 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.

    Reemitir com todos os nomes no subjectAltName

    Adicione todos os nomes DNS e, para acesso por IP, entradas de IP. Nomes que estão apenas no Common Name não são usados na correspondência.

    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.

    Verificar o nome do certificado ao se conectar a um endereço

    Quando você precisar acessar um endereço específico (um nó do balanceador de carga, um túnel), mantenha server_hostname definido com o nome do certificado em vez de desativar a verificação do nome do host.

    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())

Erros relacionados

Ver toda a base de erros de assinatura