[1] [DFN[[[クライアント認証]]]]は、 [[TLSクライアント]]から [[TLSサーバー]]へ[DFN[[[クライアント証明書]]]]を送信することで[[サーバー]]において[[認証]]を行う[[認証方式]]です。

[34] [[HTTPS]] で使われることが多いですが、それ以外でも [[TLS]]
を使う[[アプリケーション]]で利用できます。

* 呼称

[56] 
[[TLS]]
の機能であることを明確にするため、
[DFN[TLSクライアント認証]]、
[DFN[TLSクライアント証明書]]のようにいうことがあります。

[57] 
[[TLS]] は古くは [[SSL]] と呼ばれていました。未だに
[DFN[SSLクライアント認証]]、
[DFN[SSLクライアント証明書]]のようにいうことがありますし、
[DFN[SSL/TLSクライアント認証]]、
[DFN[SSL/TLSクライアント証明書]]のようにいうことがあります。
厳密に言えば、
現在となっては [[SSL]]
が使われることはまずありません。
[SEE[ [[SSL]] ]]


* プロトコル

[54] 
[[TLS]]
では、
[[サーバー]]は[[サーバー証明書]]を[[クライアント]]を送信することになっていますが、
[[クライアント]]は[[クライアント証明書]]を用意しなければならない義務はありません。
[[サーバー]]の求めがある時、[[クライアント]]は[[クライアント証明書]]を[[サーバー]]に送信します。

[55] 
[[サーバー]]は、[[クライアント証明書]]を検査して、
接続を継続するか、中断するか選択できます。
[[クライアント証明書]]がない場合や、
[[クライアント証明書]]が適切でない場合、
そのまま接続を継続することも選択できますし、
中断することもできます。
([[サーバー]]の動作は、[[サーバー]]の実装や設定によって変わります。)


[FIG(short list)[ [41] [[TLSクライアント認証]]の[[プロトコル]]
- [[TLS [CODE[Certificate]]]]
- [[TLS [CODE[CertificateRequest]]]]
- [[TLS [CODE[CertificateVerify]]]]
- [[証明書]]
- [[秘密鍵]]
- [CODE(MIME)@en[[[application/x-x509-user-cert]]]]
- [CODE(HTMLe)@en[[[keygen]]]] [[要素]]
- [CODE(DOMm)@en[[[importUserCertificates]]]]
]FIG]

** 再折衝

[29] [[クライアント認証]]は、 [[TLS handshake]] で[[サーバー]]からの要求に応じて[[クライアント]]が[[サーバー]]へと[[証明書]]を送信するものです。

[30] この [[TLS handshake]] は、 [[TLS]] を開始する最初のものであっても構いませんし、
その後の任意のタイミングで行っても構いません ([[再折衝]])。

[EG[
[31] [[Apache]] の [[mod_ssl]] は [[HTTP]] [[応答]]を返すに当たり、
[[ディレクトリー]]ごとに[[クライアント認証]]の設定を行うことができます。
[[要求]]の処理の時点でその[[ディレクトリー]]に必要な[[クライアント証明書]]を受け取っていないことに気づいたら、
[[サーバー]]は[[クライアント]]に対して[[再折衝]]を求めます。
[[クライアント]]が適切な[[証明書]]を提示できれば、
[[サーバー]]は[[応答]]を送ります。

[32] [[サーバー]]がどのように[[クライアント認証]]を行うかは[[ディレクトリー]]がわかるまで決められませんが、
どの[[ディレクトリー]]へのアクセスなのかは [[HTTP要求]]を受信するまでわかりません。
[[HTTP要求]]を受信するためには最初の [[TLS handshake]]
は終わっている必要があります。つまりこの [[Apache]] の方法を実現するには、
[[再折衝]]を使うしかありません。
]EG]

[33] [[クライアント認証]]のための[[再折衝]]は、上位のプロトコルで適当なタイミング
([[HTTP要求]]を受信して[[HTTP応答]]を送る前など) で行われるのが普通ですが、
[[TLS]] と上位のプロトコルとの間でこのタイミングを調整する方法はないので、
それは保証されません。

;; >>27 のように扱いは実装によります。

[49] 
[[HTTP]] における扱いについては、 [[HTTPS]] を参照。


* 文脈

[2] 多くの [[Webブラウザー]]や、その他の[[HTTPS]] [[クライアント]]が対応しています。

[3] 公開された [[Webサイト]]では滅多に使われませんが、組織内等の[[イントラネット]]系
[[Webアプリケーション]]ではしばしば用いられています。

* 証明書

[58] 
[[TLSクライアント証明書]]のような言い方をしますが、
[[TLSクライアント認証]]に使われる[[証明書]]という、
利用目的を表す語です。

[59] 
[[TLSクライアント認証]]に適した形の[[証明書]]、
という条件は考えられなくもないですが、
特別に定められた技術的な絶対要件があるというものではありません。

[EG[
[60] 
[[サーバー証明書]]として発行されたものを[[クライアント証明書]]として使うことも、
技術的には可能です。 (それに意味があるか、
使いやすいかどうかはまた別の問題です。)
]EG]

* 証明書データベース

[13] 多くの [[Webブラウザー]]は[[証明書データベース]]に[[クライアント証明書]]と[[秘密鍵]]
(および[[ルート証明書]]や必要があれば[[中間証明書]]) を保持しています。

[14] [[PKCS #12]] などのファイルを手動で[[利用者]]が追加することもできますし、 [DEL[[CODE(HTMLe)@en[keygen]] および]][[証明書ダウンロード]]により半自動で追加することもできます。
[SEE[ [[証明書データベース]] ]]

[15] [[TLSクライアント]]は、[[サーバー]]から[[クライアント証明書]]を要求された場合、
その条件に該当する[[証明書]]が見つかればそれを送信します。

;; 要求は [CODE[[[CertificateRequest]]]] [[メッセージ]]により行います。
送信するべき[[証明書]]の条件もそこに記述されています。

[62] 
[[Webブラウザー]]は[[ダイアログ]]を表示して適切な[[証明書]]を[[利用者]]に選択させます
(>>20)。 (自動選択させるオプションが用意されていることもあります。)

[63] 
その他の[[ライブラリー]]やそれを使う専用の[[アプリケーション]]などは、
それ以外の[[プログラム]]的な方法で[[証明書]]を選択するように設計されているかもしれません。
[SEE[ [[証明書データベース]] ]]


[36] 実装上は[[クライアント証明書]]のことを[[個人証明書]]などと呼ぶようです。

* ダイアログ

[20] [[Webブラウザー]]は[[クライアント証明書]]の求めがあると、
[[モーダルダイアログ]]を表示します。これは初回の [[handshake]] だけでなく、
[[再折衝]]であってもです。[[ダイアログ]]では利用可能な[[証明書]]のリストか、
[[証明書]]なしを選ぶことができます。

[23] ただし利用できる[[証明書]] (サーバーが指定した条件に合致する[[個人証明書]]) がまったくなければ、自動的に[[証明書]]なしとなります。

[22] [[Webブラウザー]]は[[証明書]]の選択 (または無選択) を記憶しています。
[[Firefox]] は[[ホスト名]]ごとに覚えているようです。
[[Chrome]] と [[IE]] は[[ホスト名]]と[[ポート番号]]の組ごとに覚えているようです。
[TIME[2015-09-07T13:59:17.00Z]]

[21] [[Firefox]] では、記憶させずにその場限りで選択するオプションが[[ダイアログ]]に表示されます。

[24] 一旦記憶させるとその後ずっと (認証失敗しても) 同じものを選択し続けます。

[25] [[Firefox]] では[[サーバー]]から求められた「組織」と「発行者」がダイアログに表示されます。

[26] 選択後、まだ接続が有効なら、そのまま選択した[[証明書]]を使って処理を継続します。
接続が既に無効になっていれば、改めて接続します。そちらで[[サーバー]]が[[証明書]]を要求して来れば、
記憶している選択された[[証明書]]を使います。

[27] [[Chrome]] は[[HTTPヘッダー]]後の[[空行]]より前で[[再折衝]]があればダイアログを表示し、
それ以降なら[[ネットワークエラー]]として扱うようです。[[本体]]終了後なら無視するようです。
[[Firefox]] と [[IE]] は[[本体]]終了後も含めてどこであってもダイアログを表示するようです。 [TIME[2015-09-07T15:55:14.800Z]]

[28] [[Firefox]] で選択を記憶させないようにすると、同じ[[要求]]の処理中の複数回の[[再折衝]]でもそれぞれダイアログを表示するように見えます。 [TIME[2015-09-07T16:03:35.000Z]]

* 他の認証方式との比較

[16] [[TLSクライアント認証]]は[[利用者]]に[[パスワード]]を入力させる必要がないという意味で安全な[[認証]]方式です。

[17] [[TLSクライアント認証]]は[[証明書]]の管理が必要という点で、
[[利用者]]にとってはハードルが高いかもしれません。

[47] かつての [CODE(HTMLe)@en[[[keygen]]]]
と[[証明書ダウンロード]]を使うと[[利用者]]がほとんど意識することなく
[[Webブラウザー]]に[[証明書]]と[[秘密鍵]]の管理を委ねられますが、
他の [[Webブラウザー]]を使ったり、他の[[装置]]上で動作する [[Webブラウザー]]を使ったりしたい時に、
[[証明書]]と[[秘密鍵]]を安全に共有することは平均的な[[利用者]]には困難かもしれません。

[48] 
それ以外の場合、管理者と[[利用者]]の間で安全な方法で鍵と[[証明書]]の受け渡しを行い、
[[利用者]]の [[Webブラウザー]]にインストールさせる必要がありますが、
これも平均的な[[利用者]]には難しい作業です。
ある程度の訓練を受けた管理者でないと、鍵の発行や管理と[[利用者]]の手引きも大変でしょう。

-*-*-

[18] [[HTTP認証]]
([[基本認証]]など)
や[[クッキー認証]]では、[[認証]]失敗時の [[HTTP応答]]で[[アカウント登録]]や[[パスワード]]の再発行などの回復手段を案内することができます。
しかし [[TLSクライアント認証]]は [[TLS]] のセッション開始前に接続を閉じてしまうため、
同様の案内の機会がありません。
そのため [[Webブラウザー]]は一般的な認証エラーの表示しか行えません。

;; [19] 理論上は[[TLSサーバー]]は認証に失敗しても未認証状態で接続を継続し、
[[HTTP応答]]等の方法でエラーを伝えることはできます。しかしそのような利用方法が実際になされているのかどうかは不明です。

[35] [[Apache]] には[[クライアント証明書]]を必須とするオプションの他に、
[[証明書]]の提示は求めるが必須とはしないオプションもあります。
[[証明書]]の有無により異なる[[応答]]を返すことにすれば、
認証エラーの表示を行えます。

[61] 
この不便が、[[クライアント認証]]が使われる場面が少ない理由の1つでもあります。
一方で、外部の者に案内すら晒さないことをむしろ好ましいとして採用する理由の1つにもなっています。



* 関連

[4] [[OAuth 2.0クライアント認証]]とは無関係です。

* メモ


[5] [CITE@en[RFC 4681 - TLS User Mapping Extension]]
([TIME[2015-02-01 19:05:39 +09:00]] 版)
<http://tools.ietf.org/html/rfc4681>

[FIG(quote)[
[FIGCAPTION[
[6] [CITE[Transport Layer Security (TLS) Parameters]]
([TIME[2015-02-27 12:03:35 +09:00]] 版)
<http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-14>
]FIGCAPTION]

> 
> CSV
> table-tls-parameters-14-range
> Range 	Registration Procedures 
> 0-63	Standards Action
> 64-223	Specification Required
> 224-255	Reserved for Private Use

]FIG]


[7] [CITE@ja[Chrome 搭載デバイスのクライアント証明書を管理する - Chrome for Business ヘルプ]]
([TIME[2015-04-14 13:47:25 +09:00]] 版)
<https://support.google.com/chrome/a/answer/6080885?hl=ja>

[8] [CITE[chrome.platformKeys - Google Chrome]]
([TIME[2015-04-14 13:48:42 +09:00]] 版)
<https://developer.chrome.com/extensions/platformKeys>

[9] [CITE[chrome.enterprise.platformKeys - Google Chrome]]
([TIME[2015-04-14 13:48:50 +09:00]] 版)
<https://developer.chrome.com/extensions/enterprise_platformKeys>

[10] [CITE[Developer Guide: Certificate Management Extension API on Chrome OS - The Chromium Projects]]
([TIME[2015-04-14 09:20:04 +09:00]] 版)
<http://www.chromium.org/administrators/certificate-management-extension-api-on-chrome-os>

[11] [CITE@ja[クライアント証明書の登録方法 | サイボウズ製品 マニュアルサイト]]
([TIME[2014-08-16 02:59:55 +09:00]] 版)
<https://manual.cybozu.co.jp/tech/webbrowser/certificate.html>

[12] [CITE@en[draft-agl-tls-encryptedclientcerts-00 - Transport Layer Security (TLS) Encrypted Client Certificates]]
([TIME[2015-01-27 14:46:10 +09:00]] 版)
<https://tools.ietf.org/html/draft-agl-tls-encryptedclientcerts-00>

[FIG(quote)[
[FIGCAPTION[
[37] [CITE@en[RFC 6546 - Transport of Real-time Inter-network Defense (RID) Messages over HTTP/TLS]]
([TIME[2016-01-08 21:27:35 +09:00]] 版)
<https://tools.ietf.org/html/rfc6546>
]FIGCAPTION]

> RID systems MUST use mutual authentication; that is, both RID systems
>    acting as HTTPS clients and RID systems acting as HTTPS servers MUST
>    be identified by an X.509 certificate '''['''RFC5280''']'''.  Mutual
>    authentication requires full path validation on each certificate, as
>    defined in '''['''RFC5280''']'''.

]FIG]


[38] [CITE@en[Keygen and Client Certificates]]
([TIME[2015-12-01 07:01:19 +09:00]] 版)
<https://w3ctag.github.io/client-certificates/>

[39] [CITE@en[Fix #222: no credentials, no TLS client certificate · whatwg/fetch@bef06e1]]
([TIME[2016-03-15 11:36:54 +09:00]] 版)
<https://github.com/whatwg/fetch/commit/bef06e11e3b3b7589d23c0c892057c5cd5174c2a>

[40] [CITE@en[21013 – Credentials and HTTP authentication]]
([TIME[2016-03-15 11:41:02 +09:00]] 版)
<https://www.w3.org/Bugs/Public/show_bug.cgi?id=21013>

[FIG(quote)[
[FIGCAPTION[
[42] [CITE@en[RFC 8075 - Guidelines for Mapping Implementations: HTTP to the Constrained Application Protocol (CoAP)]]
([TIME[2017-03-01 17:25:23 +09:00]])
<https://tools.ietf.org/html/rfc8075#section-10>
]FIGCAPTION]

> An HC Proxy MUST implement Transport Layer Security (TLS) with a Pre-
>    Shared Key (PSK) '''['''RFC4279''']''' and SHOULD implement TLS '''['''RFC5246''']''' with
>    support for client authentication using X.509 certificates.  

]FIG]


[FIG(quote)[
[FIGCAPTION[
[43] [CITE@en[RFC 8040 - RESTCONF Protocol]]
([TIME[2017-03-27 23:03:09 +09:00]])
<https://tools.ietf.org/html/rfc8040#section-2.5>
]FIGCAPTION]

> To authenticate a client, a RESTCONF server SHOULD require
>    authentication based on TLS client certificates (Section 7.4.6 of
>    '''['''RFC5246''']''').  If certificate-based authentication is not feasible
>    (e.g., because one cannot build the required PKI for clients), then
>    HTTP authentication MAY be used. 

]FIG]


[FIG(quote)[
[FIGCAPTION[
[44] [CITE@ja-jp[Web アプリの TLS 相互認証を構成する方法 | Microsoft Docs]]
([[naziml]]著, [TIME[2017-04-24 19:07:24 +09:00]])
<https://docs.microsoft.com/ja-jp/azure/app-service-web/app-service-web-configure-tls-mutual-auth>
]FIGCAPTION]

> さまざまな種類の認証を有効にすることで、Azure Web アプリへのアクセスを制限できます。 これを行う 1 つの方法は、要求が TLS と SSL を経由するときに、クライアント証明書を使用して認証することです。 このメカニズムは、TLS 相互認証またはクライアント証明書認証と呼ばれます。

]FIG]


[FIG(quote)[
[FIGCAPTION[
[45] [CITE@en[Configuring TLS Mutual Authentication]]
([TIME[2016-06-09 21:40:54 +09:00]])
<http://docs.oracle.com/cd/E74890_01/books/Secur/secur_dataencrypt005.htm>
]FIGCAPTION]

> In TLS mutual authentication, the client is authenticated to the server and the server is authenticated to the client during the TLS handshake, using digital certificates issued by certificate authorities.

]FIG]


[46] [CITE@en-US[TLS Mutual Auth in GoLang – Bite-Code]]
([TIME[2017-04-24 20:26:02 +09:00]])
<http://www.bite-code.com/2015/06/25/tls-mutual-auth-in-golang/>

[50] [CITE@en[775438 - Chrome sends TLS client certificates in CORS preflight, in violation of spec requirements - chromium - Monorail]]
([TIME[2017-11-08 22:45:51 +09:00]])
<https://bugs.chromium.org/p/chromium/issues/detail?id=775438>

[51] [CITE@en[/docs/man1.1.0/ssl/SSL_CTX_set_client_cert_cb.html]]
([[OpenSSL Foundation, Inc.]]著, [TIME[2018-09-30 23:41:23 +09:00]])
<https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_client_cert_cb.html>

[52] [CITE@en[/docs/manmaster/man3/SSL_CTX_set_client_CA_list.html]]
([[OpenSSL Foundation, Inc.]]著, [TIME[2018-09-30 23:57:21 +09:00]])
<https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_client_CA_list.html>

[53] [CITE@en[/docs/manmaster/man3/SSL_get_client_CA_list.html]]
([[OpenSSL Foundation, Inc.]]著, [TIME[2018-09-30 23:58:35 +09:00]])
<https://www.openssl.org/docs/manmaster/man3/SSL_get_client_CA_list.html>