Ssl And Openssl For Beginner

apacheにてSSLの実装と苦戦している中、nakagami氏のメモを拝読しました。
非常に役に立つ、説明の部分を引用させていただきます。
それに自分試行錯誤をメモに残したいと思います。


SSL入門

nakagami 2005/10/02更新
http://www005.upp.so-net.ne.jp/nakagami/Memo/SSL/

 高木浩光@自宅の日記を拝見するにつけ、PKI としての SSL が 中途半端な理解により台無しにされている場面が多いように思えます。そこで(セキュリティの専門家ではないものの)私が理解している範囲で自分なりに入門解説を書いてみました。

 ちなみに、SSL v3 に少しの改良を加えたものが TLS v1.0 ですが、技術的な細かい点を気にしない 場合は、SSLと総称されています。 ここでも、そんな細かいことは気にしていないので 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 があります。
 

SSLの仕組み

公開鍵を使った安全な通信路を形成するための基盤のことを公開鍵基盤(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が認証した サーバー証明書をブラウザが受け取った場合は、ブラウザが警告を出します。

http://www.atmarkit.co.jp/fnetwork/rensai/pki02/pki01.html

  現実世界でどんなに立派な会社でも、あらかじめブラウザに登録されている CA で無ければ信用してはいけません。
  誰かが、その認証局を「信用できる」と言ったとしても、その人が信用できるので しょうか?信用できる人であったとしても、その人が信用できると言っている 根拠はなんなのでしょうか? (その人が信用できると思っているだけの人に言われたのかもしれませんし、だまされているのかもしれません)

 結局のところ署名者をさかのぼって行くと、ルート CA に最終的に署名されている CA に署名してもらわないと ダメなのです(現実には、ダメな例があまりに多いのですが) 。

http://takagi-hiromitsu.jp/diary/20041017.html
http://takagi-hiromitsu.jp/diary/20041027.html#p2

  身内が使うための通信路を秘密にしたい場合に自分で署名したサーバー証明書を 使うことはありますが、第三者に大丈夫だといって使わせるのはやめましょう。 それは、PKI としての意味をなしていないからです。

  ところで、ブラウザは、サーバー証明書に入っている Common Name と接続している ドメインを比較して、サーバー証明書に書いてあるものと違うドメインの Webサーバーに接続しようとしている場合は、警告を出します。 ユーザーは、ブラウザのアドレスバーを見ることによって、自分が意図している ドメインのサーバーと接続していることを確認できます。

  いくら他者にわからない暗号化された通信であっても、相手が 自分の意図しているのと違うサーバーであれば意味がありません。自分が意図しているサーバーかどうかを、ユーザーが判断するのはドメイン名です。

 そのため、 Webサイト作成者は SSLで保護されたページで アドレスバーを隠すようなことはしてはいけません。

http://takagi-hiromitsu.jp/diary/20041215.html#p01

 ここまでで、SSL は公開鍵暗号方式により、安全に通信できることを説明して来ましたが、公開鍵暗号方式は共通鍵暗号方式に比べて処理速度が遅いので、SSLのプロトコル内では、共通鍵暗号で使う共有鍵だけを公開鍵暗号でやり取りして、実際のデータのやり取りは 共通鍵暗号方式で行うなどのさまざまな工夫をしています。
参考

5分で絶対にわかるPKI
http://www.atmarkit.co.jp/fsecurity/special/02fivemin/fivemin00.html

秘密鍵とサーバー証明書の作り方(OpenSSL 編)

Webサーバーが https をしゃべるようにするためには、

秘密鍵ファイル
サーバー証明書ファイル

の2つのファイルを作成する必要があります。

  Web サーバーの設定で、その2つのファイルを指定するのですが、 その手順は、それぞれのWebサーバーのドキュメントを見ていただくとして、 以下では上記2つのファイルの作り方を OpenSSL の場合で例示します。

秘密鍵ファイルの生成

  まず、秘密鍵を作成するためには、シード値(ランダムなデータ)と、 パスフレーズ(俗に言うところのパスワードに相当)が必要になります。 パスフレーズは、後の手順で必要(再度入力が必要になる)ですが、 シード値は秘密鍵を推測するのがより困難になるために、ここで一時的に 使われるだけのものです。
シード値の生成

  1. openssl md5 * >seed.data

この例では、カレントディレクトリのファイルの MD5ハッシュ値をシード値にしています。
別の予測つかない値でも構いませんが、上記の例で問題ないと思います。
 

秘密鍵の生成
  1. 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送付→サーバー証明書の受領の間に、会社が確かに存在しているという証明(会社の登記等)を求めてきます。

CSR ファイルの作成
  1. 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を使う場合も

  1. openssl x509 -in csr.pem -out server.cert -req -signkey secret-key.pem

これで、サーバー証明書ファイル server.cert ができます。
 

サーバー秘密鍵ファイルの復号(暗号化しない秘密鍵ファイルの作成)

 上記の手順で、秘密鍵ファイルが出来上がりそれを Webサーバーに組み込むとSSLサーバーとして使用することができるのですが、このままだと、Webサーバーの 起動時に、秘密鍵を作成した時のパスフレーズを聞いてきます。
  これにより、万一秘密鍵ファイルが盗まれた場合でも、パスフレーズを知らなければ なりすますことができないことになります。

 しかし、これでは Webサーバーを自動的に起動したい場合は不便です。そこで、

  1. openssl rsa -in secret-key.pem -out secret-key-nopass.pem

を実行することにより、パスフレーズを必要としない(暗号化されていない) 秘密鍵 secret-key-nopass.pem が作成されます。
これを、secret-key.pem と置き換えれば、Webサーバー起動時にパスフレーズを 聞いてくることはなくなります。
また、秘密鍵ファイルを作成する時に -des3 オプションをつけなければ、最初から 暗号化されない秘密鍵ファイルを取得することもできます。

  いずれにせよ、暗号化していない秘密鍵を置く場合は、秘密鍵を盗まれないように 厳重に注意する必要があります。ファイルの権限等を正しく設定していても、(バッファーオーバーフローのような)プログラムのバグにより rootの権限が奪取されることにより、秘密鍵が奪取される可能性があることは、心に留めておく必要があります。


OpenSSLで自己証明書の作成

下記はPlamo Linuxから引用してきたものです。
http://www.bnote.net/linux/self_ca.shtml


OpenSSLで自己認証局と証明書の作成

まず、OpenSSLがインストールされているとして進めます。

本来、信頼のある認証局に認証してもらいますが 今回は、自分で認証するための自己認証局を作成します。 CAの作成は、/usr/local/ssl/CAに行います。 あらかじめディレクトリを作成しておきます。

OpenSSLがインストールされているディレクトリにある miscディレクトリにCA.shというスクリプトがあります。 このスクリプトで認証局を構築することができます。

CA.shをCAの作成場所にコピーします。

cp CA.sh /usr/local/ssl/CA

構築する場所等を変更するためスクリプトを少し修正します。 openssl.cnfの[CA_default]-dirも同様に修正します。

DAYS="-day 3650"

CATOP=/usr/local/ssl/CA
CAKEY=./cakey.pem
CACERT=./cacert.pem

これで、認証局の構築準備ができたので

CA.sh -newca

を実行します。 スクリプト内部では、ディレクトリの作成とコマンドが実行されます。

openssl req -new x509 -keyout /usr/local/CA/private/cakey.pem -out /usr/local/CA/cacert.pem -days 3650

コマンドを実行すると、以下のように入力が求められます。

CA certificate filename (or enter to create) 【Enter】
Making CA certificate …
Using configuration from /usr/local/ssl/openssl.cnf
Generating a 1024 bit RSA private key
……………………..++++++
………………………….++++++
writing new private key to './demoCA/private/./cakey.pem'
Enter PEM pass phrase: 【適当なパスフレーズ】
Verifying password - Enter PEM pass phrase: 【パスフレーズの確認】


You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Namer or a DN.
There are quite a few fields bur you can leave some blank
For some fields there will be a default value,
If you enter '.' the field will be left blank.


Country Name (2 letter code)[AU]: 【JP:国名】
State or Province Name (full name)[Some-State]:【Tokyo:都道府県名】
Locality Name (eg, city)[]:【Chofu-shi:市区町村】
Organization Name(eg, company)[Internet Widgits Pty Ltd]:【bnote:組織名(法人名)】
Organization Unit Name (eg, section)[]:【System:部署名】
Common Name (eg, your name or your server's hostname)[]:【bnote.sample.jp:サーバのホスト名(FQDN)等】
Email Address []:【pj.elpmas|retsam#pj.elpmas|retsam:メールアドレス】

これで/usr/local/CAに認証局の証明書(cacert.pem)と /usr/local/CA/privateに認証局の秘密鍵(cakey.pem)が 作成されます。

作成した証明書は、以下のコマンドで内容が確認できます。

openssl x509 -in cacert.pem -text

この証明書をバイナリー(DER)フォーマットにするには

openssl x509 -in cacert.pem -outform DER -out cacert.der

を実行します。 バイナリーにする方法にはBER,DER,PERなどがあるそうです。

参考:デジタル証明書の形式 PEMとはメールを暗号化するために規定されたものです。 PEMにおいては暗号化情報をメールで送るためにこれを テキスト形式で表現します。この暗号化情報のテキスト形式 のことをPEM形式と呼びます。多くの場合、DER形式の X509証明書をこの PEM形式に変換したものが用いられるようです。

証明書、CSR、および暗号化鍵のいずれも、 base64でエンコード により作られるこの形式で保存することができます。 このテキスト形式のファイルはHTTPサーバなどでも、この形式の ファイルを使う場合が多いようです。
サーバの秘密鍵を作成する

サーバの秘密鍵や証明書は、/usr/local/ssl/SERVERに作成することとします。

mkdir /usr/local/ssl/SERVER
chmod 600 /usr/local/ssl/SERVER

openssl genrsa -rand 適当なFile -des3 -out serverkey.pem 1024
又は
openssl genrsa -des3 -out serverkey.pem 1024

コマンドを実行すると、以下のように入力を求められます。

Enter PEM pass phrase:(パスフレーズ入力) Verifying password - Enter PEM pass phrase:(パスフレーズ再入力)

これで、サーバの秘密鍵の完成です。 Apacheで使用する場合、Apacheを起動するたびにパスフレーズが 必要となるので、パスフレーズを解除します。 (セキュリティー上好ましくはないですね。)

openssl rsa -in serverkey.pem -out servernopasskey.pem

これでパスフレーズの外れた秘密鍵が出来上がります。
認証局への署名要求書(CSR,申請書)を作成する

先ほど作成したサーバ鍵を基に認証局への署名要求書ファイルを 作成します。認証局は、この署名要求書ファイルを基に署名付の 証明書を作成してくれます。

openssl req -new -days 365 -key serverkey.pem -out csr.pem

コマンドを実行すると以下のように入力を求められます。 (同一ホストの自己認証局を利用する場合は、以下の情報はCA構築時 とまったく同じ内容で作成してください)

Country Name (2 letter code)[AU]: 【JP:国名】
State or Province Name (full name)[Some-State]:【Tokyo:都道府県名】
Locality Name (eg, city)[]:【Chofu-shi:市区町村】
Organization Name(eg, company)[Internet Widgits Pty Ltd]:【bnote:組織名(法人名)】
Organization Unit Name (eg, section)[]:【System:部署名】
Common Name (eg, your name or your server's hostname)[]:【bnote.sample.jp:サーバのホスト名(FQDN)等】
Email Address []:【pj.elpmas|retsam#pj.elpmas|retsam:メールアドレス】

これで署名要求書の作成は終了です。

次は、ここで作成した署名要求書を基にCAに署名して証明書を 発行してもらいます。
サーバ証明書の作成

先ほど作成したサーバの署名要求書を基にCA(自己認証局)が署名し、 サーバの証明書を作成します。

cd /usr/local/ssl/CA
openssl ca -in /usr/local/ssl/SERVER/csr.pem -keyfile private/cakey.pem -cert cacert.pem -out /usr/local/ssl/SERVER/cert.pem

これでサーバ証明書の作成は終了です。
apacheで使用する

Apache 2系はconfigureでenable-sslを指定してコンパイルしてください。 Apache 1.3系はmod_sslを入手してコンパイルしてください。 下記例は1.3系です。

/usr/local/apache/confにあるhttpd.confを編集します。

SSLEngine on
SSLCertificateFile /usr/local/ssl/SERVER/cert.pem
SSLCertificateKeyFile /usr/local/ssl/SERVER/servernopasskey.pem

とりあえず、ApacheのSSLの設定は終了です。 あとは、/usr/local/apache/bin/apachectl startsslでSSLを有効にして Apacheを起動します。


Reference:
http://www.fc-lab.com/network/server/pki/server.html
http://se-suganuma.blogspot.jp/2009/08/opensslcaapachemodssl.html