Saltar al contenido
ecdsa.com
Python ssl module (OpenSSL host check)cryptography de Python

Mensaje de error

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

También se muestra como

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

El nombre entre comillas es el host al que te conectas. Para direcciones IP, Python dice «IP address mismatch, certificate is not valid for '…'.» Tras el mensaje aparece una ubicación en el código fuente, como «(_ssl.c:1082)».

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

Qué significa

La cadena de certificados es de confianza, pero el nombre que se pidió a Python que verificara (el host de la URL o server_hostname) no está entre los nombres alternativos del sujeto del certificado. Desde Python 3.7, la comprobación la hace OpenSSL durante el handshake, así que aparece como un fallo de verificación del certificado y no como el antiguo ssl.CertificateError.

Por qué ocurre

Cómo solucionarlo

  1. 1.

    Listar los nombres que cubre el certificado

    Compara las entradas de subjectAltName con el host que pasas a 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.

    Volver a emitir con todos los nombres en subjectAltName

    Añade todos los nombres DNS y, para el acceso por IP, entradas IP. Los nombres que solo figuran en el nombre común (CN) no se usan para la comparación.

    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 el nombre del certificado al conectarse a una dirección

    Cuando tengas que llegar a una dirección concreta (un nodo de un balanceador de carga, un túnel), mantén server_hostname con el nombre que figura en el certificado en lugar de desactivar la comprobación del nombre de 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())

Errores relacionados

Explorar toda la base de datos de errores de firma