nginxのssl_trusted_certificateメモ
nginxのssl_trusted_certificate
(およびssl_client_certificate
)は異なるコンテキストから利用されている。
クライアント証明書を検証する際に信頼する証明書は ssl_trusted_certificate
で指定されるが、この命令で定義されるtrust storeはOCSP Staplingの応答の検証を ssl_stapling_verify
で有効にした時にも利用される。
すなわち、nginxでは同一セクションでクライアント証明書の検証とOCSPの検証を同時に有効にすることはできない。
クライアント証明書のtrust store
TLSではクライアント(つまりウェブブラウザ)が証明書を提示して認証とすることができる。
クライアント証明書は通常、ユーザー認証の代わりに使われプライベートな認証局を立てそこからクライアント毎に発行する。 StartcomのSSL・S/MIME証明書を取得した経験のある人はブラウザに入っているはず。
nginxではssl_verify_client
で検証を有効にすることができ、ssl_trusted_certificate
で検証コンテキスト、OpenSSLでいうtrust store、となるCA証明書リストを設定できる。
ここで設定する証明書リストにはユーザーに対して証明書を発行したCAだけを含めることになる。
OCSP Staplingでのtrust store
OCSP Staplingとは、証明書の失効状態をクライアントが認証局のサーバーに問い合わせるOCSP(RFC6960)の応答を、サーバー側でキャッシュしてクライアントに渡すTLSのオプション。
OCSPの応答にはCRL(証明書失効リスト)同様認証局側の署名が付いているのでTLSサーバーがプロキシ・キャッシュしても問題ないが、OCSPサーバーとの通信は平文なので改ざんされている可能性があり、有効でない(署名検証に失敗する)OCSPレスポンスをキャッシュさせられるとパフォーマンスの劣化が生じうる。
考えうる最悪のケースとしてクライアントの(不適切な)実装によって、不正な署名が含まれるとして接続そのものを拒否してしまうかもしれない。
nginxではssl_stapling_verify
でOCSPレスポンスをクライアントに渡す前に検証することができるが、ここで署名の検証に使うtrust storeにssl_trusted_certificate
が共用されている。
OCSPの検証はサーバー自身の証明書の信頼チェーン上位、通常は公的に信頼されたパブリックなCAから署名されていることを検証する必要があり、プライベートなCAから発行する事が多いクライアント証明書とは検証コンテキストが異なる。
結論
ssl_trusted_certificate
が共通な以上、コンテキストが異なるクライアント証明書検証とOCSPレスポンス検証は同時に使えない。
こんにちのウェブでクライアント証明書を使うことは稀なので問題になるとは考えにくいものの、複数のコンテキストでtrust storeを一つで済ますというのはバグと運用ミスの元になり設計として好ましくない。TLS関連のコードを書くなら他山の石としたい。
なおproxyモジュールなどは、バックエンドとの通信でTLSでリモートを検証する際にproxy_ssl_trusted_certificate
のように個別のtrust storeを参照するため、影響はない。(nginx 1.7.8以降)