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

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

curl: (60) SSL certificate problem: self-signed certificate in certificate chain

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

  • curl: (60) SSL certificate problem: self signed certificate in certificate chain
  • curl: (60) SSL certificate OpenSSL verify result: self-signed certificate in certificate chain (19)

OpenSSL 3.0 и новее выводят «self-signed», OpenSSL 1.1.1 — «self signed» без дефиса, поэтому в журналах и результатах поиска встречаются оба написания. Более новые версии curl (8.22.0 в нашей проверке) формулируют это как «SSL certificate OpenSSL verify result: self-signed certificate in certificate chain (19)». Сборки curl с Schannel в Windows сообщают об этой ситуации как «SEC_E_UNTRUSTED_ROOT».

curl (OpenSSL backend) — CURLE_PEER_FAILED_VERIFICATION, X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN (19)

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

curl прошёл по цепочке, которую отправил сервер, до самоподписанного корневого сертификата, а этого корневого сертификата нет в пакете сертификатов CA (CA bundle), которым пользуется curl. В отличие от ошибки «unable to get local issuer certificate», цепочка здесь полная: curl видит корневой сертификат, но у него просто нет причин ему доверять. На практике корневой сертификат почти всегда принадлежит корпоративному CA или прокси, который перехватывает TLS.

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

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

  1. 1.

    Выясните, чей это корневой сертификат

    Посмотрите на последний сертификат цепочки. Если в субъекте указан производитель прокси или средств защиты либо название вашей компании, решение — доверять этому корневому сертификату на этой машине. Если там неожиданное имя, а сеть вам не подконтрольна, остановитесь: кто-то перехватывает соединение.

    bash
    # Print the subject and issuer of every certificate the server (or the proxy) sends
    openssl s_client -connect api.example.com:443 -servername api.example.com -showcerts </dev/null 2>/dev/null \
      | grep -E '^ *[0-9]+ s:|^ *i:'
    # The last entry has s: == i: — that self-signed root is what curl does not trust.
  2. 2.

    Добавьте корневой сертификат компании или прокси в системное хранилище

    Получите корневой сертификат у ИТ-отдела (или экспортируйте его из хранилища доверенных сертификатов управляемой машины) и установите в системный пакет сертификатов, который использует curl. В контейнерах его нужно добавлять при сборке образа, в WSL — внутри дистрибутива Linux, а не только в Windows.

    bash
    # Debian, Ubuntu, Alpine
    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
  3. 3.

    Настройте доверие корневому сертификату для одной команды или одного окружения

    --cacert и CURL_CA_BUNDLE заменяют пакет сертификатов curl по умолчанию, поэтому, если тот же процесс обращается и к публичным сайтам, указывайте в них файл, где есть и публичные корневые сертификаты, и частный.

    bash
    curl --cacert corp-root-ca.pem https://api.example.com/
    
    # Keep public roots too: build one bundle with both
    cat /etc/ssl/certs/ca-certificates.crt corp-root-ca.pem > /opt/certs/bundle.pem
    export CURL_CA_BUNDLE=/opt/certs/bundle.pem
  4. 4.

    Владельцам серверов: не рассчитывайте на отправку корневого сертификата

    Отдавайте конечный сертификат и промежуточные, а частный корневой сертификат распространяйте на клиенты через систему управления конфигурациями. Включение корневого сертификата в цепочку только тратит байты и никогда не делает недоверенный корневой сертификат доверенным.

    bash
    # Serve leaf + intermediates only; clients must already have the root
    cat api.example.com.crt intermediate.crt > fullchain.pem
  5. 5.

    Временная диагностика: посмотрите издателя с отключённой проверкой

    -k отключает проверку сертификатов, чтобы в подробном выводе можно было увидеть субъект и издателя, которые предъявляет сервер. Используйте этот флаг только для того, чтобы определить корневой сертификат. Если оставить -k в скриптах, любой на пути трафика сможет читать и изменять его, включая токены и скачиваемые установщики.

    bash
    # Diagnostic only: shows who issued the certificate even though curl distrusts it
    curl -sv -k -o /dev/null https://api.example.com/ 2>&1 | grep -E 'subject:|issuer:'

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

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