こんにちは、最近あまりWebの話をしていないwakです。IISをあれこれ触ってリハビリをしようと試みていたのですが、同僚がSSL回りで苦しんでいたので復習がてら表題の件を試してみました。
通信の盗み見、改竄、なりすまし、おいしくないカリカリを許さない鋭い視線の猫
1行でまとめると
こういう証明書を作成するのが目的です。
まずは基礎知識
SSLの目的と機能
SSLには2つの機能があります。
- 通信を暗号化して、のぞき見や改竄を防ぐ
- 通信相手が本物であることを保証する
たとえば公衆Wi-Fiに紛れて偽Wi-Fiアクセスポイントを設置した悪者がいたとします。このアクセスポイントは悪者の支配下にありますから、ここに接続してしまった人は全ての通信内容を見られてしまいますし、通信内容は改竄され放題です。「mizuhobank.co.jp」にアクセスしていたつもりなのに、実際にはフィッシングサイトに接続させられていたということも起こり得ます(これではいくら通信が暗号化されていても意味がありません!)。こういった状況でも、
- 暗号化によって通信をのぞき見を防ぐ
- もし偽の相手と通信していたらそれを検知できる
ようにして安全にインターネットを利用できるようにするのがSSLの役割です。
SSLが安全を保証する仕組み
- ブラウザはサーバーと通信を開始すると、まず最初にサーバー証明書をチェックします。サーバー証明書には、「私は本物のexample.comです」とAさんの署名つきで書いてあります。
- そこでブラウザはAさんに「ああ言ってるけど君は誰? 信頼できる人なの?」と聞きにいきます。Aさんは「私は本物のAです。Bさんの署名もあります」という証明書を示します。
- そこでブラウザはBさんに「ああ言ってるけど君は誰? 信頼できる人なの?」と聞きに行きます。Bさんは「私は本物のBです。Cさんの署名もあります」という証明書を示します。
- そこでブラウザはCさんに「ああ言ってるけど君は誰? 信頼できる人なの?」と聞きに行きます。Cさんは「私は本物のCです。Dさんの署名もあります」という証明書を示します。
- そこでブラウザはDさんに「ああ言って
このたらい回しはいつ終わるのでしょうか。その答えは、OSまたはブラウザに内蔵された「この人は絶対に信用できる人だ」という署名のリスト=ルート証明局にあります(これはWindowsインストール時、Windows update、ブラウザのインストール時などに導入されます)。たらい回しをずっと続けていくと、いつかは必ず、このルート証明局の署名が入った証明書にぶつかります。続けてみましょう。
……そこでブラウザはDさんに「ああ言ってるけど君は誰? 信頼できる人なの?」と聞きに行きます。Dさんは「私は本物のDです。ルート証明局の署名もあります」という証明書を示します。するとブラウザは、
- Dさんは信頼できる
- Dさんが署名したCさんの証明書も信頼できる→Cさんは信頼できる
- Cさんが署名したBさんの証明書も信頼できる→Bさんは信頼できる
- Bさんが署名したAさんの証明書も信頼できる→Aさんは信頼できる
- Aさんが署名したexample.comの証明書も信頼できる
- じゃあこのサーバー証明書を持ってるexample.comは本物だ!
と結論づけることができます。めでたしめでたし。
公開鍵暗号
SSLでは公開鍵暗号というものを利用します。どんな暗号でも必ず鍵が必要ですが(例:アルファベットを2文字後ろにずらす、全てのデータに01101001
でXORをかけるなど)、公開鍵暗号では鍵を決めるときに必ず「秘密鍵」「暗号鍵」のペアを作ります。この鍵には次の性質があります。
つまり公開鍵だけを知っていても、文書を暗号化することができるだけです。暗号化された文書を復号することはできません。*1
証明書を作る
オレオレ証明書
まず「自己署名入り証明書」、通称「オレオレ証明書」を作りましょう。これは「俺は○○です。署名は自分でした。俺を信じろ」という全く信頼の置けない証明書です。とはいえ、全てのルート証明書はこのタイプですから重要です(他の誰かに署名してもらおうとすればまたさっきのたらい回しが始まってしまいます)。
まず、乱数を使って秘密鍵を作ります。これは誰にも秘密の鍵で、「この鍵を知っている」ことが「自分が自分である」ことの証明となります。また、秘密鍵があれば対応する公開鍵はいつでも取り出せます。
openssl genrsa 2048 > ca.key
次にこの秘密鍵(に対応する公開鍵)と、組織名・サーバー名(コモンネーム)などの情報とを混ぜ合わせて「CSR(Certificate Signing Request)」を作成します。これは次の手続きのために一時的な必要なだけの情報です。また、-subj
オプションは指定しなければ対話式で聞かれます。
openssl req -new -key ca.key -subj "/C=JP/ST=Tokyo-to/L=Minato-ku/O=Sanwa System/OU=IT dept./CN=Sanwa System CA" > ca.csr
最後に、-sinkey
オプションを使ってこのCSRに自己署名を追加してサーバー証明書を作成します。
openssl x509 -days 365 -req -signkey ca.key < ca.csr > ca.crt
本来であれば最後のステップは信頼できる証明局にお願いして実施してもらう作業です。そのことにより、
証明局は信頼できる
↓
証明局によって署名されたサーバー証明書も信頼できる(偽造されていない)
↓
そのサーバー証明書に含まれる公開鍵で何か適当なフレーズを暗号化する
↓
通信相手がその暗号を解読できるか試してみる
↓
解読できたなら通信相手のサーバーは秘密鍵を知っている
↓
信頼できる
というチェーンが完成します。
WindowsPCに証明書をインストール
これで生成された証明書をWindows PCに持ってきてダブルクリックで開くとインストールするかどうかを聞かれます。
インストールしましょう。
これでこのPCはこの秘密鍵によって署名された証明書を無条件で信頼するようになり、
- SSLで保護されたWebサイトの署名
- PowerShellのスクリプトの署名
- exeファイルに添付された署名
などが全部通るようになります。そしてこの証明書の中核はさっき作った秘密鍵(つまりca.key
というファイルの中身)ですから、これが誰かにバレたら大変なことになります。
サーバー証明書を作る
続いてサーバー証明書を作り、ルート証明局、つまりさっきの証明書の秘密鍵で署名してみましょう。CSRを作るところまでは同じです。
openssl genrsa 2048 > server.key openssl req -new -key server.key -subj "/C=JP/ST=Tokyo-to/L=Minato-ku/O=Sanwa System/OU=IT dept./CN=*.ssc-aws.com" > server.csr
普通はこれをルート証明局に送付して署名してもらうのですが、今回は自分で署名します。
CSRに署名する
手順が若干面倒です。まずOpenSSLの設定ファイル、/usr/lib/ssl/openssl.cnf
を開くと次のような行があるはずです。
dir = ./demoCA # Where everything is kept
OpenSSLコマンドは単にCSRファイルに署名を行うだけではなく、その証明書を管理する機能も持ち合わせています。そのためのファイルを配置する場所がこの行です。そこでこの行に従い、どこかに次のようなディレクトリを作成してください。(なぜか相対パスで書いてあるので、気持ちが悪ければ絶対パスに書き換えても構いません)
-./ +-demoCA <dir> +-private <dir> +-crl <dir> +-certs <dir> +-newcerts <dir> +-index.txt +-serial
いずれも設定ファイルに書いてある通りです。ファイル2つは手で作ります。
echo "01" > serial touch index.txt
こうした上で、demoCAの親ディレクトリで署名コマンドを実行します。
openssl ca -days 365 -cert ca.crt -keyfile ca.key -in server.csr > server.crt
これでサーバーの証明書が生成されました。この証明書は自作のルート証明局にぶら下がっているので、問題なく検証が成功します。
証明書の管理
署名を行うと、demoCA
ディレクトリ以下のファイルがいくつか更新されます。これはOpenSSLが認証局としての仕事を行うため、いつ、どんな証明書に署名したかを管理しておく必要があるからです。たとえば先ほど作成したindex.txt
はこんな内容で更新されます。
V 160830133444Z 01 unknown /C=JP/ST=Tokyo-to/O=Sanwa System/OU=IT dept./CN=*.ssc-aws.com
このように、現在どのような証明書が有効なのか、その証明書の内容はどんなものか、などが分かるようになっています。必要があれば失効させ、問い合わせを受けたとき*2には「もう無効になっていますよ」と答えて利用者の安全を確保するわけです。
まとめ
初歩的な内容のはずでしたが意外に知識に抜けがあって手間取ってしまいました。ときには足元を見直すのも大切です。