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

Mensagem de erro

[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate

Também aparece como

  • ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate

O Python acrescenta a localização no código-fonte em C, por exemplo, “(_ssl.c:1082)”; o número muda com a versão do Python e não significa nada para o diagnóstico. O urllib encapsula o erro como “<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] …>”, e o requests e o urllib3, como “Max retries exceeded … (Caused by SSLError(…))”.

Python ssl module (OpenSSL) — ssl.SSLCertVerificationError, X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY (20)

O que significa

O módulo ssl do Python pediu ao OpenSSL que verificasse o certificado do servidor, e o OpenSSL não encontrou o emissor do último certificado da cadeia entre os certificados de CA que este SSLContext carregou. O servidor não está necessariamente mal configurado: muitas vezes este Python simplesmente consulta um bundle de CAs diferente (ou vazio) daquele que seu navegador ou seu sistema operacional usa.

Por que acontece

Como corrigir

  1. 1.

    Builds do python.org para macOS: executar Install Certificates.command

    O script instala o certifi e o vincula como bundle do OpenSSL desse Python. Ele precisa ser executado de novo depois da instalação de outra versão do Python.

    bash
    # macOS, python.org installer: run once per installed Python version
    "/Applications/Python 3.14/Install Certificates.command"
  2. 2.

    Usar o trust store do sistema operacional com o truststore

    O truststore faz o ssl.SSLContext verificar pelo sistema operacional (o chaveiro no macOS, o repositório de certificados do Windows, o bundle do sistema no Linux), de modo que as raízes implantadas pelo seu departamento de TI também funcionem no Python. Ele também cobre o urllib3, o requests e o pip, que o usa por padrão desde o pip 24.2.

    python
    # pip install truststore==0.10.5  — verify with the OS trust store (Keychain, Windows store, Linux bundle)
    import truststore
    truststore.inject_into_ssl()   # call once at start-up, before creating connections
    
    import urllib.request
    urllib.request.urlopen("https://api.example.com/")
  3. 3.

    Carregar a CA explicitamente para um único cliente

    Passe cafile (ou cadata) para ssl.create_default_context() no código que se comunica com um serviço privado. O contexto continua verificando nomes de host e datas.

    python
    import ssl, urllib.request
    
    ctx = ssl.create_default_context(cafile="/etc/ssl/private-ca/corp-root-ca.pem")
    urllib.request.urlopen("https://api.example.com/", context=ctx)
  4. 4.

    Conferir e definir o caminho do bundle padrão

    ssl.get_default_verify_paths() mostra qual arquivo e qual diretório o OpenSSL usa. SSL_CERT_FILE e SSL_CERT_DIR substituem esses valores para o processo; aponte essas variáveis para um bundle que contenha tanto as raízes públicas quanto a sua CA.

    bash
    # Where does this Python look by default?
    python3 -c "import ssl; print(ssl.get_default_verify_paths())"
    # Point OpenSSL-based clients at a bundle that includes your CA
    export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
  5. 5.

    Donos do servidor: enviar a cadeia completa

    Se o handshake contém só um certificado e o emissor dele é um intermediário público, configure o servidor com o arquivo da cadeia completa.

    bash
    # Server side: 1 certificate in the handshake = intermediate missing
    openssl s_client -connect api.example.com:443 -servername api.example.com -showcerts </dev/null 2>/dev/null \
      | grep -c 'BEGIN CERTIFICATE'

Erros relacionados

Ver toda a base de erros de assinatura