1. はじめに
本ブログ記事では、クライアント証明書を用いたクライアント認証 (以下、クライアント証明書認証) が一体どういうものなのかを解説したいと思います。
この記事では、一旦Oktaのことは脇に置いておき、「TLS (Transport Layer Security)」というプロトコルにおけるクライアント証明書認証がどういうものなのか、という一般的な内容にフォーカスします。
クライアント証明書認証という言葉はよく聞くけど「それってどんな動きをしてるんだろう?」という疑問を持ちつつも、「どの説明を見ても、イマイチ理解できない。。。」と、悶々とした日々を過ごしているエンジニアの方も結構いらっしゃるのではないかと思います。
この記事が、その悩み解決の一助となれば幸いです。
======Tips======
Oktaには、PIV/CAC と呼ばれるスマートカードAuthenticatorがありますが、この機能は、以降で説明する「TLSにおけるクライアント証明書認証」の機能を応用したものです。
よってこの記事では、まずは包括的に理解できる一般的なTLSに言及しておこう、という趣旨で作成しました。
ちなみにPIV/CACは以下のようなものです。
・PIV (Personal Identity Verification): アメリカの連邦政府職員・委託業者向けの公式IDカードの規格。
・CAC (Common Access Card): 主に、アメリカ国防総省(DoD)向けのIDカードの呼び方。
ただ、クライアント証明書は「必ずIDカードのICチップに入っていなくてはならない」ということはなく、クライアントPC内部のユーザー証明書ストアに保存されているものも利用できます。
===============
2. そもそも証明書ってなに?
証明書は、次のような性質を持つものです。
◼︎ 数百バイト〜数キロバイト程度のデータで構成されています。
◼︎ 国際標準でフォーマットが厳密に定義されています (X.509 など) 。
◼︎ 実体はバイナリ形式のファイルであり、用途によっては Base64 でエンコードされ、テキストとして扱われることもあります (PEM 形式など) 。
◼︎ Windows PC では、ユーザーストアやコンピューターストアといった専用の領域に格納されます。
◼︎ 本来は、ユーザーが意識しないところで、OS やアプリケーションによって自動的に追加・更新されています。
◼︎ 必要に応じて、TLS (HTTPS) 通信の中で、相手に対して提出します。
======Tips======
皆さんが、https://〜で始まるURLのWebサーバ (例: https://www.okta.com) にアクセスする際には、「TLSハンドシェイク」と呼ばれる下図の処理が、皆さんの見えないところで行われています。
この場合、クライアントがアクセスしたWebサーバが正当なのかどうかを確認するために、クライアントがWebサーバから「サーバ証明書」を受け取って検証するので「サーバ認証」と呼ばれます。
一方、クライアントとサーバの双方が明確に特定される必要がある特殊な用途において、上記の「サーバ認証」に加え、Webサーバがクライアントから「クライアント証明書」を受け取って検証する「クライアント認証」が用いられます。
(この場合、上記の「TLSハンドシェイク」処理に、下図の (4), (6), (8) が追加されます。)
このように「クライアント証明書認証」は、TLSハンドシェイクのオプション的な位置付けとなっています。
また、クライアント証明書もサーバ証明書もどちらも一般に「デジタル証明書」と呼ばれますが、正式名称は「公開鍵証明書」です。
上図のように、証明書には公開鍵が含まれており、正式名称からも類推されるように、証明書は「公開鍵の真正な所有者」であること (「この公開鍵は全く怪しくないですよ!」ということ) を第三者に証明するための仕組みです。
現段階ではピンと来ないと思いますので、後の章でこれがどういうことなのかを説明します。
===============
3. クライアント証明書認証をざっくり理解する
クライアント証明書認証では「公開鍵を用いた電子署名の検証」がポイントになりますので、そこを掴んでおきましょう。
「公開鍵を用いた電子署名の検証」は、対 (ペア) となる「公開鍵」と「秘密鍵」が使われます。
「公開鍵」というのは名前の通り公開されているものなので、誰でも入手できます。
一方、「秘密鍵」は名前の通り秘密とされるものであり、公開されることはありません (公開してはいけません) 。
この前提で、「公開鍵」と「秘密鍵」のペアを使った署名の検証がどういうものなのかを見てみましょう。
以降、少々厳密さは欠けますが、あくまで「大枠で理解する」という気持ちで見ていただければと思います。
3.1. クライアント証明書を信用する流れ
クライアント証明書は何を以て信用されるのか、という流れについて説明します。
(唐突に「認証局」という言葉が出てきますが、「クライアント証明書を発行する人」とご理解ください。)
Aさんは、Bさんへのアクセスを許可してもらいたいと思っています。
Bさんは、「クライアント証明書が正当であると判断できたらアクセスを許可しますよ。」という条件をつけている、とします。
その条件を満たすために、Aさんは以下のことを行います。
(1) Aさんは、「Aさんの情報」と「Aさんの公開鍵」をセットにした「元データ」を作ります。
(「Aさんの公開鍵」は、この説明の序盤では役割がありませんが、後ほど活躍します。)
(2) Aさんは、「認証局01」に元データを送付して「認証局01の秘密鍵」で署名してもらうことで、「クライアント証明書」が生成されます。
(3) Aさんは、Bさんに「クライアント証明書」を送ります。
(4) Bさんは、「認証局01の公開鍵」を使って、署名値を復元してデータを取り出します (= 図中の「復元データ」がそれです) 。
(5) Bさんは、クライアント証明書の「元データ」と「復元データ」を比較して、それらが一致したら、このクライアント証明書を信頼します。
これが、「秘密鍵」と「公開鍵」を使った署名検証の基本となる動作です。
このことで、以下のように悪意ある第三者 (ここでは「Waruさん」とします) がクライアント証明書を書き換える (改ざんする) ような不正が起きても「元データ」と「復元データ」が一致しないので、Waruさんの不正は失敗します。
3.2. トラストアンカー (信頼の起点)
今度はWaruさんは、「じゃ、Aさんの情報を使ってクライアント証明書を生成してやろう。」と思い付きます。いわゆる「なりすまし」です。
Waruさんは、審査の緩い「認証局XX」に依頼することで、クライアント証明書が生成できてしまいました。
Bさんが、「認証局XXの公開鍵」を使って、Waruさんから送られてきたクライアント証明書の署名値から「復元データ」を取り出して「元データ」と比較したら一致しますので、この場合は不正が成功してしまいます。
これは非常によろしくありません。
これを防ぐには、Bさんは「どの認証局でも信用する」のではなく、Bさんが「信用する認証局を限定する」ことです。
これを「トラストアンカー (信頼の起点)」と呼びます。
難しい言葉のように聞こえますが、ただ単に「信用する認証局はコレだ、と決める」というだけです。
このことで、「認証局01」の公開鍵だけが信用され、「認証局XX」の公開鍵は信用されないようになります。
3.3. クライアント証明書認証には「クライアントの秘密鍵」も必須
クライアント証明書認証を行うには、クライアントは「クライアント証明書」だけでなく、「クライアントの秘密鍵」も必須で所持する必要があります。
それはなぜなのかを見ていきましょう。
今度はWaruさんは、「Aさんからのクライアント証明書を盗聴して、それをBさんに送ってやろう。」と思い付きます。「盗聴+なりすまし」です。
(クライアント証明書は秘密にするものではなく、AさんからBさんにそのまま送るようなデータなので、入手は比較的容易です。)
もし、クライアント証明書認証が「クライアント証明書しか使わない」のであれば、下図のようにこの不正は成功してしまいます。
ここで、「クライアントの秘密鍵」の登場です。
Waruさんは「Aさんの秘密鍵」は持っていませんから、「Waruさんの秘密鍵」を使う必要がある (使うしかない) ので、ここで不正が暴かれます。
(6) ここに至るまでにWaruさんとBさんは何往復かの通信を行っているので、それをデータとしてまとめます。
(7) そのデータに対してWaruさんは「クライアントの秘密鍵=Waruさんの秘密鍵」で署名します。
(8) Waruさんは、その署名データをBさんに送ります。
(9) Bさんは「Aさんの公開鍵」を使って、署名値から「復元データ」を取り出します。
(10) Bさんも(6)と同じ情報を持っているので、「(6)のデータ」と「復元データ」を比較します。
結果、2つの値が一致しないので「正しい秘密鍵を持っていないな」=「これは不正だ」ということがわかり、Waruさんのクライアント証明書認証は成功しません。
念の為、Aさんのクライアント証明書認証が成功する、正常な場合も見ておきましょう。
(6)からの流れは先ほどと同じですが、「Aさんの秘密鍵」で署名したものを「Aさんの公開鍵」で復元しますから、(10)の判定が一致するので、Aさんのクライアント証明書認証が成功します。
ということで、クライアント証明書認証を行うには、クライアントは証明書だけでなく、秘密鍵も所持する必要があるのです。
4. 証明書と認証局について
この章では、証明書とそれを発行する認証局がどのようなものかについて少し踏み込んで解説します。
認証局 (OKTAJ-CA) が、ATKO社のasaku.akawa (asaku.akawa@atko.email) に対して、クライアント証明書を発行する、と仮定します。
このことによって、「クライアント証明書」〜「認証局証明書」の間で、証明書と証明書が連鎖する「証明書チェーン」が構成されます。
4.1. クライアント証明書とは?
ATKO社が、asaku.akawaのためのクライアント証明書を得るためには、認証局から発行してもらう必要があります。
そのためには、まずATKO社にて「署名リクエスト (CSR)」というものを生成し、それを認証局で署名してもらう、というステップが必要です。
ATKO社が署名リクエスト (CSR) を作る際には、例えば以下のような値を使います。
証明書の項目 | 意味 | 値 |
countryName | 国 | JP |
stateOrProvinceName | 都道府県 | Kanagawa |
localityName | 区市町村 | Yokohama |
organizationName | 会社名 | ATKO-Corp, Ltd. |
organizationalUnitName | 組織名 | Systems Engineer |
commonName | 共有名 | asaku.akawa@atko.email |
subjectAltName | 代替名 | asaku.akawa@atko.email |
以下は、署名リクエスト (CSR) の作成〜クライアント証明書が発行されるまでのイメージです。
(1) ATKO社は、asaku.akawaの秘密鍵を生成します。(asaku.akawa-key.pem)
(2) ATKO社は、asaku.akawaの「署名リクエスト (CSR)」を生成します。(asaku.akawa-req.pem)
(この(1)と(2)は同時に行われます。)
(3) ATKO社は、その「署名リクエスト (CSR)」 を認証局 (OKTAJ-CA) に送ります。(秘密鍵は送りません。)
(4) OKTAJ-CAは、「署名リクエスト (CSR) 」に対して、認証局自身の情報 (OKTAJ-CA自身の情報) や有効期間などを追加して、それを「tbsCertificate」とします。
(5) この「tbsCertificate」に対して、(例えばSHA-2を使って) ハッシュ値を計算します。
(6) そのハッシュ値を、OKTAJ-CAの秘密鍵を使って、(例えばRSAで) 署名します。
(7)「tbsCertificate」と「署名」を一まとまりにしたものが、asaku.akawaのクライアント証明書です。
(8) OKTAJ-CAは、そのクライアント証明書をATKO社へ送ります。
ここまでで、クライアント証明書の作成と発行は完了です。
以下は、クライアントPCへクライアント証明書と秘密鍵をインポートする方法の一例です。
(9) ATKO社は、asaku.akawa用の証明書と秘密鍵のセットを、Windowsへインポートしやすいように、PKCS#12形式に変換し、Windows PCへインポートします。
4.2. 認証局とは?
認証局の役割は上記でお伝え済みの通り、「証明書を発行する機関」です。
上図の認証局 (OKTAJ-CA) は、ルート認証局と呼ばれる構成になっています。
認証局も証明書を持っています。ルート認証局の証明書は「ルート証明書」とも呼ばれます。
クライアント証明書は認証局に署名してもらいますが、ルート証明書は根元なので、上位の認証局が存在しません。
では、「ルート認証局の署名は誰が行うのか?」と言いますと、「ルート認証局が、自分自身の秘密鍵で署名する」という形式を取ります。
これを「自己署名」と呼んだりします (下図の④) 。
「ん?そんなことでいいのか?それが信用できるのか?」という疑問が沸くと思います。
その疑問はご尤もであり、この「自分で自分の署名をする」という証明書を持つ認証局が商用で利用できるようになるには、 WebTrust for CAs (または ETSI) の第三者監査に合格するなど、厳しい基準を満たす必要があります。
また、クライアント証明書を発行するルート認証局は自社内に設置する場合も多いので、その場合においては自社内でルールを設けて、厳格に管理する必要があります。
5. クライアント証明書を使った認証の流れ (詳細)
では、クライアント証明書を使った認証がどのように行われるのかを、少し詳細に解説します。
Webサーバは、クライアント証明書を受け取ると、以下の (A) と (B) をAND条件でチェックします。
(A)「証明書チェーンの検証」: Webサーバが保有している認証局証明書 (ルート証明書) =トラストアンカーの公開鍵で、署名検証が成功するか?
(B)「秘密鍵保有の証明」: クライアントが秘密鍵で署名した情報を受け取り、その署名検証が成功するか?
以下は、TLS1.2、署名検証はRSAをベースに記載します。
======Tips======
TLS 1.3の場合、往復回数が減ったり、登場メッセージの名称や順序が少し違ったりしますが、クライアント証明書認証は、 (A)「証明書チェーンの検証」と (B)「秘密鍵保有の証明」という2本柱で判定する、という点は同じです。
ちなみに、本記事執筆時点 (2025/12現在) において、OktaはTLS1.3は未サポートです。
===============