Перейти к содержимому
ecdsa.com
curl (OpenSSL backend)curl

Сообщение об ошибке

curl: (60) SSL certificate problem: unable to get local issuer certificate

Также выводится как

  • curl: (60) SSL certificate OpenSSL verify result: unable to get local issuer certificate (20)
  • SSL certificate problem: unable to get local issuer certificate

curl на базе OpenSSL (Linux, Homebrew в macOS, Git for Windows) выводит этот текст; более новые версии (8.22.0 в нашей проверке, тогда как 8.14.1 ещё выводил текст выше) формулируют его как «SSL certificate OpenSSL verify result: unable to get local issuer certificate (20)», добавляя код проверки OpenSSL. curl, собранный с Schannel в Windows, сообщает о той же ситуации как «schannel: SEC_E_UNTRUSTED_ROOT (0x80090325)», а libcurl на базе GnuTLS (её использует git в Debian и Ubuntu) — как «server verification failed: certificate signer not trusted». Инструменты на основе libcurl, например PHP и git, выводят часть после «(60) » со своим префиксом.

curl (OpenSSL backend) — CURLE_PEER_FAILED_VERIFICATION, X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY (20)

Что это означает

curl получил сертификаты сервера, но не нашёл в своём пакете сертификатов CA (CA bundle) сертификат, которым выпущен последний сертификат цепочки. Сам сертификат может быть полностью действительным: curl просто не может связать его ни с одним корневым сертификатом, которому доверяет, поэтому отказывается устанавливать соединение (код завершения 60). Недостающее звено — либо промежуточный сертификат, который сервер забыл отправить, либо корневой CA, которого нет на вашей машине.

Почему это происходит

Как исправить

  1. 1.

    Посмотрите, что на самом деле отправляет сервер

    Выведите список сертификатов в рукопожатии. Если там только один (глубина 0) и его издатель — промежуточный CA, конфигурация сервера неполна и её обязательно нужно исправить на сервере. Если цепочка заканчивается корневым сертификатом компании или самостоятельно созданным корневым сертификатом, на клиенте не хватает этого корневого сертификата.

    bash
    # Which certificates does the server send, and who issued the last one?
    openssl s_client -connect api.example.com:443 -servername api.example.com -showcerts </dev/null 2>/dev/null \
      | grep -E '^ *[0-9]+ s:|^ *i:'
    #  0 s:CN=api.example.com
    #    i:C=US, O=Example Trust Services, CN=Example TLS Issuing CA   <- leaf only: intermediate missing
  2. 2.

    Исправьте сервер: отдавайте полную цепочку

    Укажите веб-серверу файл цепочки, в котором за конечным сертификатом следуют все промежуточные. Это сразу исправляет ошибку для всех клиентов, включая мобильные приложения и API-клиенты, которые вы не контролируете.

    bash
    # Leaf first, then each intermediate in order; the root itself is optional
    cat api.example.com.crt intermediate.crt > fullchain.pem
    
    # nginx:   ssl_certificate     /etc/nginx/tls/fullchain.pem;
    # Apache:  SSLCertificateFile  /etc/apache2/tls/fullchain.pem
    # certbot: use live/<name>/fullchain.pem, never cert.pem
  3. 3.

    Установите частный корневой CA в системное хранилище

    Если цепочка правомерно заканчивается корневым сертификатом компании или внутренним корневым сертификатом, добавьте его в пакет сертификатов операционной системы. Получите корневой сертификат у ИТ-отдела или платформенной команды либо у самого CA, но никогда не берите его из сертификата, который предъявило проблемное соединение: именно ему вы пока и не можете доверять.

    bash
    # Debian, Ubuntu, Alpine (the file must end in .crt)
    sudo cp corp-root-ca.pem /usr/local/share/ca-certificates/corp-root-ca.crt
    sudo update-ca-certificates
    
    # RHEL, Fedora, Amazon Linux
    sudo cp corp-root-ca.pem /etc/pki/ca-trust/source/anchors/
    sudo update-ca-trust
  4. 4.

    Укажите curl пакет сертификатов для одной команды или одного сеанса оболочки

    --cacert добавляет доверие для одного вызова, не затрагивая систему; CURL_CA_BUNDLE задаёт пакет сертификатов для всех вызовов curl в окружении. Файл может содержать несколько PEM-сертификатов.

    bash
    curl --cacert corp-root-ca.pem https://api.example.com/
    
    # or for every curl command in this shell (a file may hold several PEM certificates)
    export CURL_CA_BUNDLE=/opt/certs/corp-and-public-roots.pem
  5. 5.

    Установите пакет сертификатов CA в минимальные контейнеры

    Если внутри контейнера ошибку дают даже публичные сайты, в образе нет пакета сертификатов. Установите ca-certificates в образ (или скопируйте /etc/ssl/certs/ca-certificates.crt из стадии сборки), а не отключайте проверку.

    bash
    # Debian/Ubuntu-based images
    apt-get update && apt-get install -y --no-install-recommends ca-certificates
    # Alpine
    apk add --no-cache ca-certificates
  6. 6.

    Временная диагностика: убедитесь, что проблема в доверии

    -k (--insecure) отключает проверку сертификатов, поэтому успешный ответ лишь доказывает, что сетевой путь работает, а сбой связан с доверием. Никогда не оставляйте этот флаг в скриптах: с -k любой на пути трафика может читать и изменять его, включая учётные данные и скачиваемый код.

    bash
    # Diagnostic only: if this works, the problem is trust, not the network.
    curl -sS -k -o /dev/null -w '%{http_code}\n' https://api.example.com/

Связанные ошибки

Открыть всю базу ошибок подписей