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のSSLS/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_verifyOCSPレスポンスをクライアントに渡す前に検証することができるが、ここで署名の検証に使う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以降)