エラーメッセージ
SSL_do_handshake() failed (SSL: error:0A000418:SSL routines::tlsv1 alert unknown ca:SSL alert number 48)
別の表記
- SSL routines:ssl3_read_bytes:tlsv1 alert unknown ca
- error:0A000418:SSL routines::tlsv1 alert unknown ca
nginx はこれを info レベルで「SSL_do_handshake() failed (SSL: error:0A000418:SSL routines::tlsv1 alert unknown ca:SSL alert number 48) while SSL handshaking, client: …」と記録します。openssl CLI は「…:SSL routines:ssl3_read_bytes:tlsv1 alert unknown ca:…」と出力します。OpenSSL のクライアントは、信頼されていないチェーン、自己署名のチェーン、不完全なチェーンのいずれに対しても、このアラートを送信します。
nginx error log / OpenSSL — TLS alert 48 (unknown_ca) received from the peer
このエラーの意味
接続の相手側が TLS アラート 48(unknown_ca)でハンドシェイクを中止しました。受け取った証明書を、自身が信頼する CA までチェーンでつなげられなかったということです。サーバーのログ(ここでは nginx のもの)では、クライアントがサーバーの証明書を拒否したことを意味します。クライアント側では、相互 TLS でサーバーがクライアント証明書を拒否したことを意味します。アラートを記録している側が、問題のある側であることはありません。原因は、ピアに送った証明書の側にあります。
発生する理由
サーバーのログ:クライアントがサーバーの証明書を信頼していない
よくある自己署名証明書やプライベート CA の証明書、中間証明書の不足、社内用の証明書を一般のクライアントに公開している場合などが該当します。失敗したクライアント(curl、API クライアント、監視)ごとに、このような行が 1 行ずつ残ります。
クライアント側:サーバーがクライアント証明書を信頼していない
よくある相互 TLS において、クライアント証明書の発行元がサーバーで受け入れるよう設定されていない CA であるか、クライアントが自身の中間証明書を送信していない状態です。
スキャナーとプローブ
ときどきインターネット全体を対象とするスキャナーは、何も信頼しない状態で接続し、このアラートで中止します。不明なアドレスからの散発的な行は無害です。
修正方法
- 1.
どの証明書が拒否されたかを特定する
サーバーのログに出ている場合は、外部からサーバーのチェーンをテストしてください。相互 TLS を使うクライアントで出ている場合は、サーバーが想定する CA とクライアント証明書を照合してください。
bash # In a SERVER log: a client rejected the server's certificate (e.g. missing intermediate) openssl s_client -connect api.example.com:443 -servername api.example.com -showcerts </dev/null 2>/dev/null \ | grep -E '^ *[0-9]+ s:|^ *i:|Verify return code' # On a CLIENT: the server rejected your client certificate (mutual TLS) - 2.
サーバー:公的に信頼される完全なチェーンを返す
公開エンドポイントでは、パブリック CA の証明書を使い、完全なチェーンを設定してください。社内エンドポイントでは、すべてのクライアントが社内のルートを持っていることを確認してください。
text # nginx: the chain clients need, leaf first ssl_certificate /etc/nginx/tls/fullchain.pem; ssl_certificate_key /etc/nginx/tls/privkey.pem; - 3.
相互 TLS:信頼される CA からクライアント証明書を発行する
サーバーに設定されている CA(nginx では ssl_client_certificate)でクライアント証明書を検証し、クライアントの中間証明書をその証明書と一緒に送信してください。
bash # Mutual TLS: is the client certificate issued by the CA the server trusts? openssl verify -CAfile server-trusted-client-ca.pem -untrusted client-intermediate.pem client.pem # Send the client's intermediate too, if it has one cat client.pem client-intermediate.pem > client-chain.pem curl --cert client-chain.pem --key client.key https://mtls.example.com/
関連するエラー
SSL routines:ssl3_read_bytes:ssl/tls alert bad certificateOpenSSLSSL routines:ssl3_read_bytes:tlsv13 alert certificate requiredOpenSSL (client side)curl: (60) SSL certificate problem: unable to get local issuer certificatecurl (OpenSSL backend)remote error: tls: unknown certificate authorityGo crypto/tls