2005/10/02更新
高木浩光@自宅の日記を拝見するにつけ、PKI としての SSL が 中途半端な理解により台無しにされている場面が多いように思えます。そこで(セキュリティの専門家ではないものの)私が理解している範囲で自分なりに入門解説を書いてみました。
ちなみに、SSL v3 に少しの改良を加えたものが TLS v1.0 ですが、技術的な細かい点を気にしない 場合は、SSLと総称されています。 ここでも、そんな細かいことは気にしていないので SSL と総称しています。
まず、SSLを理解するために必要な用語を解説し、次に SSLが PKI としてどのような構成要素で安全な通信路を形成しているか解説します。
コンピューターで暗号化というと、暗号化する前のデータ (以下、「平文(ひらぶん)」と呼びます)と鍵となるデータ(以下「鍵」と呼びます) を使って、平文を推定できないデータへ変換することを言います。 暗号化したデータは、同じく鍵となるデータを使って元の平文に復号化できます。
![]() 平文 |
![]() |
![]() 暗号文 |
![]() |
![]() 平文 |
||
大昔(第2次大戦以前)には、暗号化アルゴリズムが秘密にされていましたが、 現在は、一部の例外を除き暗号化アルゴリズムは公開されていて 、アルゴリズムが公開されていない暗号は、第三者による検証ができないので一般に危険であると考えられています。
暗号化の方式に大きく分けて暗号化と復号化に同じ鍵を使う共通鍵暗号方式と 公開鍵と秘密鍵という異なる鍵で暗号化と復号化を行う公開鍵暗号方式があります。上の図で言うと、「鍵1」と「鍵2」が同じものが共通鍵暗号方式、「鍵1」と「鍵2」が異なるものが公開鍵暗号方式となります。
共通鍵暗号方式の最大の問題は、暗号通信をしたい二者(以下では、仮に Alice と Bob とします)の間で、安全に鍵を共有するのが難しいということです。また、Aliceが Bobのほかに Charlie とも暗号による通信を行いたい場合は、Bobと行っているのと異なる鍵を、つまり通信相手の数だけ鍵を持たなくてはならないことも問題です。
公開鍵暗号方式の秘密鍵は自分(例えば Webサーバー)だけが知りうる鍵で、公開鍵は誰でも知りうる(公開している) 鍵です。秘密鍵と公開鍵は一対をなすもので、秘密鍵で暗号化した暗号文は公開鍵で復号でき、公開鍵で暗号化した暗号文は秘密鍵で復号できるようになっています。
例えば、Alice が秘密鍵を持っていてそれに対する公開鍵を Bobが入手できるものとします。このとき、 Bobに公開鍵で暗号化した暗号文を送ってもらうことにより Aliceは暗号文を復号できますが、秘密鍵を持っていないほかの人は暗号文を 復号できません。
公開鍵暗号方式はまた、電子的な「署名」を行う場合にも使うことができます。 上の例で Alice が自分の秘密鍵で暗号化した暗号文は公開鍵を使うことにより (だれでも)復号することができます。復元できることにより、そのデータは Aliceが暗号化(署名)した ものであることがわかります(秘密鍵は Aliceしか知らないのですから)。
共通鍵暗号方式では、3DES, RC4, AES などが有名です。 公開鍵暗号方式では RSA が有名です。
公開鍵暗号の処理は、共通鍵暗号方式の処理に比べて時間がかかるため、SSLでは、公開鍵暗号方式で共通鍵の受け渡しをして、実際のデータのやり取りは共通鍵暗号方式で行うような工夫をしています。
データをもとに演算すると、一定の長さのチェックサムが生成され、生成された
チェックサムから元のデータや、同じチェックサムを生成する別のデータ
を推測することが困難なアルゴリズムがあります。
このチェックサムデータを元データに対するメッセージダイジェストと呼び 元データが改変されていないことを確認・証明するために使います。
メッセージダイジェストのアルゴリズムで有名なものには MD5,SHA1 があります。
公開鍵を使った安全な通信路を形成するための基盤のことを公開鍵基盤(PKI:Public Key Infrastructure)と呼び、SSL
も PKI の一種です。
Webサーバー上
には、サーバー証明書と秘密鍵があり、クライアントはサーバー証明書が取得できるようになっています。サーバー証明書は、公開鍵に、信頼できる機関である認証局(以下
CA)が署名したものです。
クライアントは、サーバー証明書が信頼できる CAにより署名されていることを確認することにより、上の Aliceと
Bobの例でいうと、Bobが受け取ったのが、確かに Aliceの公開鍵であると確信できます。
それでは、サーバー証明書に署名している CAが信用できると、どうやって確信することができるのでしょうか?
実は、 CA他のCAに署名してもらっていて
その CA は・・・と、CA をさかのぼっていくことができ、
CAの親玉であるルート認証局(以下ルートCA)がいくつかあって、
それらルート CAの証明書はあらかじめWebブラウザに組み込まれているのです。
サーバー証明書にある CA の署名からルートCAにたどれない CAが認証した
サーバー証明書をブラウザが受け取った場合は、ブラウザが警告を出します。
現実世界でどんなに立派な会社でも、あらかじめブラウザに登録されている
CA で無ければ信用してはいけません。
誰かが、その認証局を「信用できる」と言ったとしても、その人が信用できるので
しょうか?信用できる人であったとしても、その人が信用できると言っている
根拠はなんなのでしょうか?
(その人が信用できると思っているだけの人に言われたのかもしれませんし、だまされているのかもしれません)
結局のところ署名者をさかのぼって行くと、ルート CA に最終的に署名されている CA に署名してもらわないと ダメなのです(現実には、ダメな例があまりに多いのですが) 。
身内が使うための通信路を秘密にしたい場合に自分で署名したサーバー証明書を
使うことはありますが、第三者に大丈夫だといって使わせるのはやめましょう。
それは、PKI としての意味をなしていないからです。
ところで、ブラウザは、サーバー証明書に入っている Common Name と接続している ドメインを比較して、サーバー証明書に書いてあるものと違うドメインの
Webサーバーに接続しようとしている場合は、警告を出します。
ユーザーは、ブラウザのアドレスバーを見ることによって、自分が意図している
ドメインのサーバーと接続していることを確認できます。
いくら他者にわからない暗号化された通信であっても、相手が 自分の意図しているのと違うサーバーであれば意味がありません。自分が意図しているサーバーかどうかを、ユーザーが判断するのはドメイン名です。
そのため、 Webサイト作成者は SSLで保護されたページで アドレスバーを隠すようなことはしてはいけません。
ここまでで、SSL は公開鍵暗号方式により、安全に通信できることを説明して来ましたが、公開鍵暗号方式は共通鍵暗号方式に比べて処理速度が遅いので、SSLのプロトコル内では、共通鍵暗号で使う共有鍵だけを公開鍵暗号でやり取りして、実際のデータのやり取りは 共通鍵暗号方式で行うなどのさまざまな工夫をしています。
Webサーバーが https をしゃべるようにするためには、
の2つのファイルを作成する必要があります。
Web サーバーの設定で、その2つのファイルを指定するのですが、
その手順は、それぞれのWebサーバーのドキュメントを見ていただくとして、
以下では上記2つのファイルの作り方を OpenSSL の場合で例示します。
まず、秘密鍵を作成するためには、シード値(ランダムなデータ)と、 パスフレーズ(俗に言うところのパスワードに相当)が必要になります。 パスフレーズは、後の手順で必要(再度入力が必要になる)ですが、 シード値は秘密鍵を推測するのがより困難になるために、ここで一時的に 使われるだけのものです。
| # openssl md5 * >seed.data |
この例では、カレントディレクトリのファイルの MD5ハッシュ値をシード値にしています。
別の予測つかない値でも構いませんが、上記の例で問題ないと思います。
| # openssl genrsa -rand seed.data -des3 1024 >secret-key.pem |
先ほどのシード値を使って、秘密鍵ファイル secret-key.pem が作成されます。
このとき、パスフレーズの入力が促されますので、パスフレーズを入力します。
上記の例では、トリプルDES で暗号化された 1024 bit の鍵長の秘密鍵を
作っています。
この時のできるファイル secret-key.pem は -----BEGIN RSA
PRIVATE KEY-----で始まって-----END RSA PRIVATE KEY----- で終わっています。
サーバー証明書ファイルを取得するためには、まず CA 署名してもらう CSRファイルを作成します。次に、 CSRファイルを CAに送って、署名してもらったものがサーバー証明書ファイル になります。
CA は、送付元の身元を確認してから署名する必要があるため CSR送付→サーバー証明書の受領の間に、会社が確かに存在しているという証明(会社の登記等)を求めてきます。
| # openssl req -new -key secret-key.pem -out csr.pem |
いろいろ聞かれますが、 extra 以降聞かれることは答えなくても良いようです。 Email アドレスも入力しなくて良いようです。具体的にどんなことを書けばよいかは、サーバー証明書を発行してくれる機関のサイトを見てください。
これで、csr.pem というファイルができます。
この時のできるファイル csr.pem は -----BEGIN CERTIFICATE REQUEST-----で始まって-----END CERTIFICATE REQUEST----- で終わっています。
これを CA
に送付すると(最近では、Webフォームから送信するようです)署名されたファイルが送り返されてきます。
受信されたサーバID通知メール中の -----BEGIN CERTIFICATE----- から
-----END CERTIFICATE----- までを
切り取って、ファイルに保存します。
上でも述べているように、信頼できる第三者である CA に署名してもらわなくては 、第三者に使ってもらうためには意味が無いのですが、サーバーにテスト的に証明書を入れる場合や、身内だけで SSLを使う場合も
| # openssl x509 -in csr.pem -out server.cert -req -signkey secret-key.pem |
これで、サーバー証明書ファイル server.cert ができます。
上記の手順で、秘密鍵ファイルが出来上がりそれを Webサーバーに組み込むとSSLサーバーとして使用することができるのですが、このままだと、Webサーバーの
起動時に、秘密鍵を作成した時のパスフレーズを聞いてきます。
これにより、万一秘密鍵ファイルが盗まれた場合でも、パスフレーズを知らなければ
なりすますことができないことになります。
しかし、これでは Webサーバーを自動的に起動したい場合は不便です。そこで、
| # openssl rsa -in secret-key.pem -out secret-key-nopass.pem |
を実行することにより、パスフレーズを必要としない(暗号化されていない)
秘密鍵 secret-key-nopass.pem が作成されます。
これを、secret-key.pem と置き換えれば、Webサーバー起動時にパスフレーズを
聞いてくることはなくなります。
また、秘密鍵ファイルを作成する時に -des3 オプションをつけなければ、最初から
暗号化されない秘密鍵ファイルを取得することもできます。
いずれにせよ、暗号化していない秘密鍵を置く場合は、秘密鍵を盗まれないように
厳重に注意する必要があります。ファイルの権限等を正しく設定していても、(バッファーオーバーフローのような)プログラムのバグにより
rootの権限が奪取されることにより、秘密鍵が奪取される可能性があることは、心に留めておく必要があります。