本文へスキップ
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 のリリース(ecdsa.com のテストでは 8.22.0)では「SSL certificate OpenSSL verify result: self-signed certificate in certificate chain (19)」と表記されます。Windows の Schannel でビルドされた curl は、このケースを「SEC_E_UNTRUSTED_ROOT」として報告します。

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

このエラーの意味

curl はサーバーが送ったチェーンを自己署名のルート証明書までたどりましたが、そのルートが curl の CA バンドルに含まれていません。「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.

    社内またはプロキシのルートをシステムのストアに追加する

    IT 部門からルート証明書を入手し(または管理対象マシンのトラストストアからエクスポートし)、curl が使う OS のバンドルにインストールしてください。コンテナーではビルド時に必要です。WSL では Windows だけでなく、Linux ディストリビューションの中にも必要です。

    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.

    1 つのコマンドまたは 1 つの環境に限ってルートを信頼する

    --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:'

関連するエラー

署名エラーデータベースをすべて見る