OpenSSLライブラリを使ってプログラミング(2) 証明書・検証についての予備知識

OpenSSLライブラリを使ってプログラミング(1)の続き。
証明書と検証に関することで、特にOpenSSL固有というわけではない一般的なことをまとめておく。付け焼き刃の知識だけど。

証明書(公開鍵証明書)とは

公開鍵と公開鍵に関する色々な情報が載っていてそれに署名がされたもの。だいたい次のようなデータを含んでいる。

  • 公開鍵
  • 公開鍵に関するデータ(使用アルゴリズム等)
  • 公開鍵の所有者のデータ
  • 証明書の発行者のデータ
  • 証明書のデータ(有効期限など)
  • 上のデータに対する(発行者による)デジタル署名

一行で表すと

KeyA :「KeyAはAさんの公開鍵です」「発行者はBです」 :色々な情報 :Bの署名

みたいなかんじ。SSL証明書と呼ばれたりする場合もあるみたいだけど、別にSSL/TLS専用のものではない。

なぜ証明書を送る(受け取る)のか

  • 公開鍵を送るため。暗号化通信を始めるために公開鍵を送る。ただし暗号化通信のためだけなら、公開鍵を使わずに鍵を交換する方法がありそれを使うこともできる。
  • 通信したい相手と正しく通信していることを保証・確認するため。中間者攻撃などをされていないことを保証する。なりすましをした相手と通信していたり中間者攻撃をされていると暗号化していても無駄(中間者攻撃用のツールもいろいろあるみたい)。

証明書の検証

送られてきた公開鍵が通信したい相手の鍵なら、その鍵を使うことで、通信路から他人に情報が漏れることなく相手と情報のやりとりがおこなえる。でももしも別人の公開鍵だったら、その別人に情報が漏洩したり通信の改竄が可能になってしまう。
だから、送られてきた公開鍵が本当に通信したい相手のものであることを確認する必要がある。証明書には公開鍵の持ち主の名前(あるいはそれに類するもの)が書かれている。でも、それを素直に信用して良いわけではない。
証明書には発行者の署名がされている。これは「この鍵は誰々の公開鍵ですよ」ということを発行者が認めているということを意味する。だから、

  1. 証明書の署名が、確かに発行者による署名であること。
  2. その発行者が信頼できること(いいかげんに署名をおこなったりしないこと)。

がわかれば、証明書に書かれている持ち主が実際に公開鍵の正しい持ち主だと信じることができる。

1.正しい署名であることの検証

1.の正しい署名であることは、発行者の公開鍵があれば確認できる(署名は私密鍵(private key)によっておこなわれ、署名の検証は公開鍵(public key)によっておこなわれる)。したがって署名の確認のためには、発行者の公開鍵(公開鍵証明書)を入手する必要がある。
でも発行者の公開鍵を入手しても、さっきと同じく、それは本当にその人の公開鍵なのかという問題がおこる。よって再び、1.公開鍵証明書の署名が正しい署名であること、2.その署名者が信頼できること、を確かめる必要がでてくる。以下同様に続く。
このように発行者の署名の正しさを確認する作業を続けていっても、署名が正しいことを確信できる地点に到着することはない。結局どこかの地点で、署名を検証するのとは無関係に、証明書の正しさを認めるしかない。で通常、この「署名の検証と無関係に証明書の正しさを認める」(かどうかを判断する)地点となるのが、自己署名証明書と呼ばれるもの(別名:ルート証明書)に到達したところ。
自己署名証明書というのは、証明書をその鍵自身で署名したもの。この場合、署名の検証は楽におこなえる。検証に必要な公開鍵がその証明書自体に含まれているわけだから。でもその署名を検証しても何の確信の足しにもならない。自己署名証明書の正しさの確認は、署名にたよらずにしないといけない(たとえばネットワークを介さず入手したとか、証明書の正しさを電話で確認したとか)。
多くのウェブブラウザにはあらかじめ、広く知られたCA(認証機関)の自己署名証明書が組み込まれていて、それらの証明書に到達すれば証明書が検証できたことになる。ただし配布されたソフトを入手した場合、そもそも入手したソフトが本物でない(例えば通信に介入され、組み込みの自己署名証明書をすり替えられたソフトを手に入れたのかもしれない)という可能性はある。
(疑問: 正しいと確信している証明書に到達しさえすれば、別にそれが自己署名証明書でなくても検証できたことにして良い気がする。だけど標準的な検証では、最後が自己署名証明書でないといけないみたい。OpenSSLでの検証もそうなっている。どこが問題なのか。
http://en.wikipedia.org/wiki/Certification_path_validation_algorithm
http://www.openssl.org/docs/apps/verify.html#VERIFY_OPERATION)

2.発行者が信頼できることの検証

各証明書の署名が正しいものあることが確認できた(+自己署名証明書も信頼できる)としても、それだけでは証明書が検証できたことにはならない。例えば次のふたつの証明書がある場合を考えてみる。

証明書A: KeyA:「KeyAはAさんの鍵です」: 発行者B: Bの署名
証明書B: KeyB:「KeyBはBさんの鍵です」: 発行者C: Cの署名

ここでCの署名については、正しく確認できることにしておく(例えば自分がCだと考えても良い)。Bの署名についてもKeyBを使って確認できたとする。
このときKeyAをAの鍵だと信じて良いかというと、そうとは限らない。証明書Bは、KeyBはBの鍵であると言っているだけで、Bが信頼できる(いいかげんに署名をおこなったりしない)と言っているわけではない。もしかするとBはすごくいいかげんだとか騙されやすいとかで、別人の持っている鍵に対して「これはAの鍵です」という証明書を出したのかもしれない。
だから、証明書の正しさを検証するには、署名の検証とは別に、証明書の発行者(=署名者)がいいかげんな署名をおこなったりしないことを検証しないといけない。
これを本気で確かめようとするとすごく大変なことになってしまう。なので、証明書に「この鍵はCA(認証機関)の鍵ですよ(署名に使ってよい鍵ですよ)」という補助的な情報を書き加えるというやり方が使われている(X.509証明書の拡張領域basicConstraintsのCA属性をtrueにする)。この場合、その証明書は「これは誰々の鍵だよ」と言っているだけでなく「この鍵で署名された証明書も信頼して良いよ」と言っていることになる。したがって2.の検証のために、証明書を検証するとき、CAの鍵かどうかの確認もおこなわれる。
以上のようなやり方で、あらかじめ信頼している自己署名証明書から始めて、証明書と署名のチェックを繰り返しおこなっていくことにより相手の証明書を検証する。


まだちゃんと理解していないことも多いけど、とりあえず検証についてはこれくらい。

OpenSSLでの場合

OpenSSLライブラリの使い方が本題だったのだけど、それはまた別にまとめることにする。

続き