mTLS introduction
Introduction
相互TLSという規格があります。 これは、サーバー側の身元を検証する機能を持つTLSに対して、サーバー側だけでなくクライアント側の身元も検証する機能を持つものです。 この記事では、証明書を使ってどのように相互TLSを実現するかを説明します。
Preparation
前提として公開鍵基盤(PKI)という仕組みを知る必要があります。 公開鍵暗号方式では、公開鍵を用いた暗号化により機密性を確保でき、また秘密鍵による署名と公開鍵による検証により改ざん検出や真正性の確認も可能になります。 その上で、そもそもその公開鍵が正しいかや送り先が正しいかを事前に検証する必要があります。送り先が正しくなければ、暗号化は意味がないですからね。
我々は公開鍵基盤を実際に運用し、TLS(およびHTTPS)を実現しています。 公開鍵と身元の情報を紐づけて、この公開鍵は、この人(組織)のものであると認めてもらう必要があります。 この認める側に当たるのが認証局です。 この認証局は公的に認められた企業が担っていたり、プライベートに作成することも可能です。
認証局には、ルートCAとその配下の中間CAがあります。 なお、Root CA が直接サーバー証明書を発行することは稀で、セキュリティ上の理由から中間CAが発行を担当する構造になっています。 この仕組みを使うことで、公開鍵を検証する側は、検証のためにルートCA証明書だけを持っているだけで十分になります。 サーバーから送られてきた公開鍵には、ルートCAに至るまでのCA階層が記載されており、検証に使うべきルートCA証明書がわかるようになっているからです。これらのルートCA証明書はデフォルトでOSやブラウザに入っています。
Topics of mTLS
Client Certificate
すでにお分かりかもしれませんが、相互TLSではクライアント側(通信を開始する側)も身元を証明するための証明書が必要になります。
証明書はサーバー証明書とクライアント証明書では区別することができ、Extended Key Usageの項目に、Client Authentication (1.3.6.1.5.5.7.3.2)という値を指定する必要があります。
RFC5280によると
If the extension is present, then the certificate MUST only be used for one of the purposes indicated.
とありますので、EKUが指定されている場合は明確に利用用途が限定されるべきであるとのことです。 逆に、EKUを指定しない場合は、用途が限定されないため、クライアント証明書としても利用できそうです。(ここは受け入れ側のポリシー次第かと)
AWSのACMでは、Amazon.comをルート認証局としたパブリック証明書を発行することができますが、Extended Key Usageの値はServer Authentication (1.3.6.1.5.5.7.3.1)固定となっており変更することはできず、サーバー証明書の用途しか想定されていません。
AWSでクライアント証明書を発行するには、AWS PrivateCAを使用し、自身でルートCAを構築する必要があります。
Steps in Client Side
TLSとの違いとしては、クライアント側がサーバー証明書をCA証明書で検証した後に、クライアント側が Certificate, ClientKeyExchange, CertificateVerify のステップを踏むことです。(TLS1.2の場合)
詳細はここでは記載しませんが、重要なのは、クライアント証明書作成の元となった秘密鍵を用いて署名を作成する必要があることです。 この署名がサーバー側に送られ検証されることで、クライアントの身元を証明します。
Closing Thought
Extended Key Usageで明確にサーバー証明書とクライアント証明書を分ける必要があると考えていたのですが、実態としては必須ではないようです。多くの実装では、それらを区別しないみたいです。セキュリティ要件や設計次第ですね。