Linux/OpenSSL

OpenSSL(2014-12-28)


SSLについて色々できるオープンなやつ((Apacheライセンスです。フリーウェアで、わりと自由に使っていいよというもの。


まず初めに

そもそも、CAって何?公開鍵って何?という話が初耳の方はさっぱり分からないですよね。

私も書いてて初めて気づいたんですが、とにかくコマンドのオプションだけでも多い!
(なので、このページでも一部抜粋しているだけです)
まだSSLについて理解できていない事が多いのが改めて分かりましたが、まぁ、追々おぼえて行こうと思います。

基本的な標準コマンド

・・・というか、今回抜粋してみたものは以下になります。

dgstメッセージダイジェストを計算する
enc共通鍵暗号方式で暗号化する
genrsaRSA秘密鍵を生成する
rsaRSA秘密鍵と公開鍵のセットを生成したり管理したりする
rsautl生成した鍵でデータを暗号化/復号化、署名したりする
req証明書署名要求(CSR)を生成、管理する
x509X.509証明書データを管理する
ca認証局の証明書を管理する
s_clientSSLのクライアントとして、指定サーバへ接続する
s_serverSSLサーバとして、接続を受け付ける

用語:拡張子について

各コマンドで使用される拡張子・ファイル形式について

  • PEM(Privacy Enhanced Mail)
    Base64で符号化されたテキスト形式のデータ。符号化前に暗号化する場合もある。
    RFC1421で規定されたメッセージ規格で、暗号鍵の保存やX.509証明書で使用される。
    1つのPEM形式ファイルに複数のデータを保存することが可能で
    「-----BEGIN なんとか-----」でデータが始まり
    「-----END なんとか-----」で終わる
  • DER(Distinguished Encoding Rules) バイナリ形式のファイル。
    ASN.1で規定されたメッセージ規格で、暗号鍵の保存やX.509証明書で使用される。
    1つのDER形式ファイルには1つのデータしか保存できない。
    テキストでやりとりする電子メール等には向かないが、ネットワーク転送等に適している。
  • CER(Canonical Encoding Rules) バイナリ形式のファイル。
    ASN.1で規定されたメッセージ規格で、暗号鍵の保存やX.509証明書で使用される。
    Wikiみても仕様がいまいち分からないので、一旦割愛・・・
  • P7C/P12/PFX
    PKCS(Public-Key Cryptography Standards)に則った規格。
    名前の通り、公開鍵暗号の標準規格。
  • .key/.pkey
    暗号鍵につける一般的な拡張子。(別にそういう規則は無い、慣例的な話)
    この時点ではテキスト形式で、暗号化して.pemや.derに変換する。
  • .crt/.cer
    証明書を格納したファイル全般の一般的な拡張子。
    中身の形式はPEMだったりDERだったりする。

  • CSR(Certificate Signing Request)
    CA(認証局)に提出する証明書要求データ。後述のreqコマンドで生成する。

dst: ダイジェスト計算

ハッシュ値の計算や、データへの署名実行、署名検証を行います。 ハッシュ値計算の例として

$ cat IROHA.txt
いろはにほへとちりぬるを(中略)ひもせす!
$ openssl dgst -md5 IROHA.txt
MD5(IROHA.txt)= 9c027e1a2a67967d26c6f4434f4086b5
$ md5sum IROHA.txt  # こうやっても同じ結果になりますね。-sha1 と sha1sum も似たイメージ
9c027e1a2a67967d26c6f4434f4086b5  IROHA.txt

enc: 共通鍵暗号による暗号化、復号化の実行

-in ファイル名
-out ファイル名
入力元/出力先ファイル名を指定する。
省略時は標準入力/標準出力なのでリダイレクション(<とか>)を使っても可
-pass pass:パスワード復号/暗号化に使うパスワードを指定する
省略時は対話式で入力

後述のオプションにも-pass形式は沢山出てくるが書式は以下で共通
 pass:パスワード
 env:環境変数
 file:ファイル名
 fd:ファイルディスクリプタ
-e
-d
暗号化(e)と復号化(d)の指定。デフォルトは e
-salt
-S 16進数のソルト値
-nosalt
(ソルト)をかけたりかけなかったりする
デフォルトが-nosaltなので、特別な事情が無い限りは
-salt指定すること*1
-a暗号文をbase64形式にする
(暗号化時はbase64へ変換、復号時はbase64として読込む)
デフォルトは、暗号文はバイナリ形式になる
-des
-des3
-idea
-aes256
-camellia256
など
暗号化に使う方式を指定する
暗号化方式にどのオプションが使えるか調べる方法が知りたいのですが・・・(-aes256とか)
とりあえず間違ったコマンドを起動するとusageの中で確認できます
(例:openssl enc usage とか)*2
-kfile 鍵とIVのファイル
-K 16進数の鍵
-iv 16進数のIV
暗号化に使う鍵やIVを自分で指定する、玄人向け?のオプション
こだわりが無ければ openssl に自動生成して貰いましょう [smile]

まず暗号化の例

$ cat IROHA.txt
いろはにほへとちりぬるを(中略)ひもせす!
$ openssl enc -aes256 -salt -in IROHA.txt -out enctxt.bin
enter aes-256-cbc encryption password:                 # 今回は123456789[Enter]で
Verifying - enter aes-256-cbc encryption password:     # 同じく123456789[Enter]で
$ cat -v IROHA.txt
M-cM-^AM-^DM-cM-^BM-^MM-cM-^AM-/M-cM-(以下省略)

ご覧の通り、暗号文enctxt.binはバイナリファイルです。
(cat -v は制御文字を可読文字に置き換えるオプション)
これらをテキスト形式にしたい場合は -a を指定します。
次は、今のテキストを復号化します。-passでパスワードも指定。

$ openssl enc -d -aes256 -in enctxt.bin -pass pass:123456789
いろはにほへとちりぬるをわかよたれそつねならむうゐのおくやまけふこえてあさきゆめみしゑひもせす!

なお、後述の公開鍵もそうですが、
安全な暗号化方式についてはCRYPTRECで確認しましょう。

補足:公開鍵の生成~証明書作成の流れ

ここから先、かなり混乱したので、一旦整理しておきます。
たぶん、こんな感じ

ZU_OpenSSL1.png

genrsa: RSA鍵の生成

公開鍵方式の一つ、RSA鍵を生成するオプションです。
gendsa(DSA鍵)もありますが、セキュリティ強度が高いRSAについてのみメモしておきます。

-out ファイル名鍵の出力先ファイル名を指定する。
省略時は標準出力なのでリダイレクション(>)を使っても可
-passout pass:パスワード生成する秘密鍵にパスワードを付ける。
パスワード取得元を指定して使う
-des
-des3
-idea
-aes256
-camellia256
など
鍵の暗号化に使う方式を指定する。省略時は秘密鍵は暗号化されずに出力される
暗号化方式にどのオプションが使えるか調べる方法が知りたいのですが・・・(-aes256とか)
とりあえず間違ったコマンドを起動するとusageの中で確認できます
(例:openssl genrsa usage とか)
-rand /dev/urandom暗号化に使う乱数を指定する*3
最後に数字鍵の長さをbit数で指定。十分な長さにしましょう

以下、実行例
秘密鍵をcamelliaで暗号化して作成しています。

$ openssl genrsa -camellia256 -out private_key.pem -rand /dev/urandom -passout pass:123456789 2048
2048 semi-random bytes loaded
Generating RSA private key, 2048 bit long modulus
....+++
..............................................+++
e is 65537 (0x10001)
$ cat private_key.pem
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: CAMELLIA-256-CBC,E8B472860EDE6C7E3C85EA32FAE8EB3B

txKaxEtSwc2jKnqFJL5CfyYHtaHqr4IbDbAvrqRE4kBuUcfGUQ7p4jtJK3pF3Qqn
(長いので中略)
W8C6EfPf5GUr4zs4r8gQZka0NeyzyfDr1y7BzilBus0GXYwluLssgtJ40biHZAol
Mq/RzGRngcn5MTiFxbR/fT+ebRMo/tvKz6ugUdE+z358jFFUrlmPzTHymM6d33tP
-----END RSA PRIVATE KEY-----
$

普通はやらないですが(セキュリティ上、危ないので)、
個人レベルで試験運用する際に、秘密鍵のパスワードが邪魔になることがあります。
(例:ApacheでSSL設定した場合に、起動の度に秘密鍵のパスワードを入力しなければならなくなる)
その場合は鍵の暗号化方式(上記で言うと -camellia256)を指定せずに秘密鍵を作成して
その鍵を、後述のopenssl rsa -in とかで渡せば、パスワード無しの鍵セットを作れます。

rsa: 秘密鍵の操作、公開鍵の生成

-in ファイル名
-out ファイル名
鍵の入力元/出力先ファイル名を指定する。
省略時は標準入力/標準出力なのでリダイレクション(<とか>)を使っても可
-pubin
-pubout
入力元/出力先ファイルを公開鍵とみなして処理する
-inform DER|PEM
-outform DER|PEM
入力/出力として読込む鍵の形式を指定する。省略時はPEM
-passin pass:パスワード
-passout pass:パスワード
入力鍵の復号/出力鍵の暗号化に使うパスワードを指定する。
-des
-des3
-idea
-aes256
-camellia256
秘密鍵の暗号化に使う方式を指定する。省略時は秘密鍵は暗号化されずに出力される
-text入力した鍵を、分かりやすい形式に整形して出力する

前述の秘密鍵から公開鍵をRSAで生成します。

$ openssl rsa -in private_key.pem -pubout -out pub_key.pem -passin pass:123456789 
writing RSA key
$ cat pub_key.pem
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtAI+xWJkfafdlDrprefP
(中略)
kU8DCf1QYMIEt0n6NxxKiNFQK4rhMM2Fqc775mKKtTmTIWGDUFo2GDs5faPca7qf
/QIDAQAB
-----END PUBLIC KEY-----
$ openssl rsa -text -pubin -in pub_key.pem
Public-Key: (2048 bit)
Modulus:
    00:b4:02:3e:c5:62:64:7d:a7:dd:94:3a:e9:ad:e7:
    (中略)
    93:21:61:83:50:5a:36:18:3b:39:7d:a3:dc:6b:ba:
    9f:fd
Exponent: 65537 (0x10001)
writing RSA key
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtAI+xWJkfafdlDrprefP
(中略)
kU8DCf1QYMIEt0n6NxxKiNFQK4rhMM2Fqc775mKKtTmTIWGDUFo2GDs5faPca7qf
/QIDAQAB
-----END PUBLIC KEY-----
$

rsautl: 鍵を使った運用

-in ファイル名
-out ファイル名
鍵の入力元/出力先ファイル名を指定する。
省略時は標準入力/標準出力なのでリダイレクション(<とか>)を使っても可
-inkey 鍵ファイル名使用する鍵を指定する
-pubininkeyを公開鍵とみなして処理する
-certininkeyを公開鍵証明書とみなして処理する
-passin pass:パスワードinkeyの復号に使うパスワードを指定する。
-pkcs
-oaep
-ssl
-raw
使用するパディングの方式を指定する。デフォルトはpkcs(PKCS1-v1.5)

余談として、これはコマンドラインだから良いが、アプリの実装としてならば
pkcsやoaepを選ぶべき。sslを選ぶとパディングオラクル攻撃に捕まる
-sign
-verify
署名の実施(sign)と署名の検証(verify)をそれぞれ行う
-encrypt
-decrypt
暗号化、復号化を行う

以下、動作確認の例
まずは暗号化にも復号化にも、おなじprivate_key.pemを使っています。(ある意味、共通鍵方式?)

$ echo "OpenSSL PrivateKey Test" |\
  openssl rsautl -encrypt -inkey private_key.pem -out pri_enc.data -passin pass:123456789
$ openssl rsautl -in pri_enc.data -decrypt -inkey private_key.pem  -passin pass:123456789
OpenSSL PrivateKey Test

次に、公開鍵暗号方式としての動作確認
暗号化はpub_key.pem、復号化にはprivate_key.pemと鍵を使い分けています。

$ echo "OpenSSL PublicKey Test" |\
  openssl rsautl -encrypt -pubin -inkey pub_key.pem -out pub_enc.data
$ openssl rsautl -in pub_enc.data -decrypt -inkey private_key.pem  -passin pass:123456789
OpenSSL PublicKey Test

req:証明書署名要求CSR(Certificate Signing Request)を作成する

-in ファイル名
-out ファイル名
証明書要求の入力元/出力先ファイル名を指定する。
作成済みのファイルを-inで指定、新規なら-newや-newkeyでまず作る。
省略時は標準入力/標準出力なのでリダイレクション(<とか>)を使っても可
-new -key 秘密鍵ファイル
-newkey rsa:長さ
-newkey dsa:設定ファイル
鍵を新規作成する。
-new指定で-key無しだと適当なRSA鍵を新規作成する模様
-pubin
-pubout
入力元/出力先ファイルを公開鍵とみなして処理する
-inform DER|PEM
-outform DER|PEM
入力/出力として読込む鍵の形式を指定する。省略時はPEM
-passin pass:パスワード
-passout pass:パスワード
入力鍵の復号/出力鍵の暗号化に使うパスワードを指定する。
-text入力した鍵を、分かりやすい形式に整形して出力する
-conf 設定ファイル名
-reqexts セクション名
証明書署名要求の各パラメータを読込む為の設定ファイル/設定ファイル内のセクションを指定する。
省略時はOPENSSL_CONFから読み取る
-x509
-days 有効日数
-set_serial シリアル番号
証明書署名要求ではなく、自己署名証明書(ルート証明書)を出力する

今さらですが、そもそもCSRって一体何物かというと、
CAに渡して、CAから証明書を発行して貰う為の情報になります。
言い換えると、自分が使おうとしている暗号通信(鍵セット)に公的機関(CA)からお墨付きを貰うイメージですね。

  1. まず自分のWebサイトでセキュアな通信(HTTPS)を使いたいとします
    個人情報や商取引を扱うサイトではセキュアな通信は必須ですよね
  2. その際には、HTTPSに必要な秘密鍵、公開鍵のセットを用意しなければなりません
  3. まず秘密鍵と、その秘密鍵に紐づくCSRを自分で用意します
  4. CSRをシマンテックとかジオトラストとか、いわゆるCAを運営している会社に送付します
  5. CAは、証明書(≒公開鍵)を発行します*4
  6. これで自前の秘密鍵と、お墨付きの証明書(公開鍵)が手に入ったので、
    これらをApacheとかに設定すればHTTPSが使えるようになります

では前述の秘密鍵からCSRを生成してみます。
(島根県出雲市にお住まいの八百万会社の邪神部門さんで登録します)
メールアドレスや拡張属性は省略。基本的に、省略した場合は[]の中の値が入ります。

$ openssl req -new -key private_key.pem -out test.csr -passin pass:123456789
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 Name or a DN.
There are quite a few fields but 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) [XX]:JP                  #日本(JP)でEnter
State or Province Name (full name) []:Shimane         #島根でEnter
Locality Name (eg, city) [Default City]:Izumo         #出雲でEnter
Organization Name (eg, company) [Default Company Ltd]:Yaoyorozu, Inc. #八百万でEnter
Organizational Unit Name (eg, section) []:Jashin      #うーん、センスない。Enter
Common Name (eg, your name or your server's hostname) []:null-i.net   #サイト名でEnter
Email Address []:  #メールアドレスは省略して、Enter

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:       #拡張オプションは今回は要らない。そのままEnter
An optional company name []:   #おなじく、そのままEnter
$ cat test.csr
-----BEGIN CERTIFICATE REQUEST-----
MIICtDCCAZwCAQAwbzELMAkGA1UEBhMCSlAxEDAOBgNVBAgMB1NoaW1hbmUxDjAM
BgNVBAcMBUl6dW1vMRgwFgYDVQQKDA9ZYW95b3JvenUsIEluYy4xDzANBgNVBAsM
(中略)
d89fK+4M9lgwJXRFgPsyCT8djcR/dBkYPbFzfvVVad4JkuSw1AaH7gUGQ3pvoYFx
2v5zb30VzM7BnUsOGFaEaEl5bB2EjIjt
-----END CERTIFICATE REQUEST-----
$ openssl req -in test.csr -text -noout
Certificate Request:
   Data:
       Version: 0 (0x0)
       Subject: C=JP, ST=Shimane, L=Izumo, O=Yaoyorozu, Inc., OU=Jashin, CN=null-i.net
       Subject Public Key Info:
           Public Key Algorithm: rsaEncryption
               Public-Key: (2048 bit)
               Modulus:
                   00:ba:e8:65:4b:17:bd:d1:93:87:25:3c:c7:fc:2a:
(以下省略)

対話式で入れている各値のデフォルト値は 環境変数 OPENSSL_CONF で指定した設定ファイルから読み込まれますが、
これらを変えたい場合は「-conf ファイル名」 で別のファイルを指定します。

元になる鍵もまとめて作るなら -newkeyが使えます。

$ openssl req -newkey rsa:2048 -out test2.csr

自分自身がルートCAとなるならば必要なのはルート証明書なので、作成オプションは-x509に変わります。
いわゆる「オレオレ証明書」っていうのも、これの事です。

$ openssl req -x509 -new -key private_key.pem -out cacert.pem -passin pass:123456789
(作る部分は前述の req -new と同じなので省略)
(次はのコマンドは、中身の確認)
$ openssl x509 -in cacert.pem -text -noout
Certificate:
   Data:
       Version: 3 (0x2)
       Serial Number: 14270986686045102946 (0xc60cbac7b00c2362)
   Signature Algorithm: sha1WithRSAEncryption
       Issuer: C=JP, ST=Shimane, L=Izumo, O=Yaoyorozu Inc., OU=Jashin, CN=null-i.net
       Validity
           Not Before: Dec 27 04:43:16 2014 GMT
           Not After : Jan 26 04:43:16 2015 GMT
       Subject: C=JP, ST=Shimane, L=Izumo, O=Yaoyorozu Inc., OU=Jashin, CN=null-i.net
       Subject Public Key Info:
(以下省略)

ちなみに有効期限(-days)未指定だと、デフォルトのValidityが1カ月っぽいですね。

x509: 証明書の確認や操作を行う

-inform DER|PEM|NET
-outform DER|PEM|NET
入力/出力として読込む鍵の形式を指定する。省略時はPEM
-in ファイル名
-out ファイル名
鍵の入力元/出力先ファイル名を指定する。
省略時は標準入力/標準出力なのでリダイレクション(<とか>)を使っても可
-text証明書を分かりやすく表示
表示オプションが沢山あるので、とりあえずこれだけ記載
-pubkey証明書から公開鍵を抜き出す
証明書自体の表示を削るためには-nooutも併用する

試しにジオトラストから証明書を取得して、表示してみたのが以下です。

$ cat GeoTrust_Global_CA.pem
-----BEGIN CERTIFICATE-----
MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
(中略)
hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV
5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==
-----END CERTIFICATE-----
$ openssl x509 -in GeoTrust_Global_CA.pem -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 144470 (0x23456)
    Signature Algorithm: sha1WithRSAEncryption
        Issuer: C=US, O=GeoTrust Inc., CN=GeoTrust Global CA
        Validity
            Not Before: May 21 04:00:00 2002 GMT
            Not After : May 21 04:00:00 2022 GMT
        Subject: C=US, O=GeoTrust Inc., CN=GeoTrust Global CA
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:da:cc:18:63:30:fd:f4:17:23:1a:56:7e:5b:df:
(以下省略)

ca: 認証局の証明書を管理する

なんか、このオプションあんまり個人で使う機会は無い気がします。
自己証明書は前述の req -x509で作りますし、
企業でCAを運用するにしても、OpenSSLではなくて高機能な製品を使うのではないか?と。

-in ファイル名
-out ファイル名
CAが署名する証明書要求/CAが作成した証明書(あるいは失効リスト)出力先ファイル名を指定する。
省略時は標準入力/標準出力なのでリダイレクション(<とか>)を使っても可
-infiles ファイル1 ファイル2 ...-in の複数バージョン。このオプションは最後に指定しなければならないので注意
-conf 設定ファイル名各パラメータを読込む為の設定ファイルを指定する。省略時はOPENSSL_CONFから読み取る
-outdir 出力先ディレクトリ証明書は指定したディレクトリに、証明書のシリアル番号+.pemというファイル名で作成される。
省略時は設定ファイルの new_certs_dirキーが出力先
-cert CAの証明書ファイルCAの証明書(前述のreq -x509で作ったファイル)が格納されている場所を指定する。
省略時は設定ファイルのcertificateキー
-keyfile 秘密鍵
-passin パスワード
CAの秘密鍵ファイルと、その復号パスワードを指定する。
鍵の省略時は設定ファイルのprivate_keyキーで指定した鍵
-startdate 開始日
-enddtate 終了日
-days 有効日数
発行する証明書の開始終了日や有効日数を指定する。
これらも省略時は設定ファイルのキー
default_startdate/default_enddate/default_daysとなる
-revoke 失効させたい証明書
-gencrl
-crldays 日数
-crlhours 時間数
証明書失効リストの作成、次のCRLの生成までの日数/時間数を指定する
-crl_reason 失効理由
-crl_hold 保留OID
-crl_compromise 危殆化時刻*5
失効理由を色々と設定できる。色々あるので省略

CSRから証明書を発行するにはこう。 CAのもつデータベース(configのdatabaseキーで指定)が更新される。

openssl ca -in test.csr -passin pass:CAの秘密鍵のパスワード
あるいは
openssl ca  -passin pass:CAの秘密鍵のパスワード -infiles CSR1個目 CSR2個目 ...

ここで出た標準出力、あるいは-outや-outdirで出て来た証明書を、CSR発送者に返してあげることになります。

失効は以下。
前述の証明書発行が「failed to update database」になった場合とかは一旦失効させる必要がある。

openssl ca -revoke /etc/pki/CA/newcerts/証明書

あと失効リスト(CRL)の作成と、その内容の確認

$ openssl ca -gencrl -out test.crl
$ openssl crl -in test.crl -text -noout

s_client: SSLクライアントの実行

-connect アドレスやホスト名:ポート接続先を指定。省略した場合は127.0.0.1:443、つまり自身のWebサーバにHTTPSで接続
-cert クライアント証明書
-key 秘密鍵
クライアント証明を行う場合は必要なセットをこれで指定する
-verify 証明書チェーンの深さ
-CAfile 証明書
-CApath ディレクトリ
サーバ証明書の検証で、信頼済みの証明書と、中間証明書を辿っていく深さを指定する
-CApath でおくファイル名は「ハッシュ.0」*6とするルールがある
つまり、このオプションを指定しないと例えば
18:self signed certificate(自己証明書の場合)
とか
20:unable to get local issuer certificate(信頼できない証明書の場合)
とか、とりあえず証明書の検証エラーが出る
-quiet
-debug
表示を簡潔にしたい、繋がったか分かれば良い程度ならば-quiet
逆に色々出すなら-debug
-ssl2
-ssl3
-tls1
-no_ssl2など
SSLプロトコルの有効無効を選択。デフォルトは全部有効。

とりあえず、googleに繋いでみる場合

$ openssl s_client -connect www.google.co.jp:443
CONNECTED(00000003)
depth=3 C = US, O = Equifax, OU = Equifax Secure Certificate Authority
verify return:1
depth=2 C = US, O = GeoTrust Inc., CN = GeoTrust Global CA
verify return:1
depth=1 C = US, O = Google Inc, CN = Google Internet Authority G2
verify return:1
depth=0 C = US, ST = California, L = Mountain View, O = Google Inc, CN = google.com
verify return:1
---
Certificate chain
 0 s:/C=US/ST=California/L=Mountain View/O=Google Inc/CN=google.com
   i:/C=US/O=Google Inc/CN=Google Internet Authority G2
 1 s:/C=US/O=Google Inc/CN=Google Internet Authority G2
   i:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
 2 s:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
   i:/C=US/O=Equifax/OU=Equifax Secure Certificate Authority
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIfIzCCHgugAwIBAgIIEXRBFbfctNAwDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE
(とても長いので中略)

    Start Time: 1419747551
    Timeout   : 300 (sec)
    Verify return code: 0 (ok)
---

こんなかんじで、一旦ここで出力が止まります。そこで、

  • 「Q」で終了
  • 「R」で再接続
  • あるいはHTTPなりSMTPなり、繋いでいるプロトコル構文を打ちます

今回は、HTTPなので以下の例では 「GET~close[Enter][Enter]」と入力して、サイトを取得し切断を試みます。 「HTTP/1.1 200 OK」から先が応答です。

(上記のつづき)

---
GET https://www.google.co.jp/ HTTP/1.1
Host: www.google.co.jp
Connection: close

HTTP/1.1 200 OK
Date: Sun, 28 Dec 2014 06:19:22 GMT
(中略)
Connection: close

<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="ja"><
(以下省略)

・・・まぁ、だいぶ省略しましたが。
余談ですが、Googleのトップページで「ソースコードの表示」とかやった事あります?
ようはアレが全部表示されるという事ですね。
こんな感じで接続の可否や証明書の内容など、色々検証できます。

s_server: SSLサーバの再現

-accept ポート接続ポートを指定。省略した場合は4433
-cert サーバ証明書
-key 秘密鍵
サーバ証明を指定する
デフォルトはカレントのserver.pemファイルを使用しようとする
-dcert 追加サーバ証明書
-dkey 追加秘密鍵
追加で使うサーバ証明を指定する
RSAとDSAの両方を使う、とかのケースで便利らしい
-verify 証明書チェーンの深さ
-Verify 証明書チェーンの深さ
-CAfile 証明書
-CApath ディレクトリ
クライアント証明書を要求する場合に使用する
その際の信頼済みの証明書と、中間証明書を辿っていく深さを指定する
-Verify(大文字)の方は、検証失敗の場合に処理を中断する。小文字は検証失敗でも続行
-CApath でおくファイル名は「ハッシュ.0」とするルールがある
-quiet
-debug
表示を簡潔にしたい、繋がったか分かれば良い程度ならば-quiet
逆に色々出すなら-debug
-ssl2
-ssl3
-tls1
-no_ssl2など
SSLプロトコルの有効無効を選択。デフォルトは全部有効。
-www
-WWW
-HTTP
Webサーバをエミュレートする
-wwwは自動でメッセージを返す
-WWWはカレントからの相対PATHにあるファイルを返す
-HTTPは更にそのファイルに、HTTPレスポンスも含む

試しに、仮想のWebサーバを立てます。
通常は起動時に秘密鍵のパスワードを聞いてくると思いますが、今回はパス無しで作ってます。

$ openssl s_server -accept 12345 -www -cert server.crt -key server.key
Using default temp DH parameters
Using default temp ECDH parameters
ACCEPT

で、Webブラウザで「https://上記コマンドを入力したサーバ:12345/」にアクセスすると
Webブラウザ画面上にはこんな感じのメッセージが出力されました。

s_server -accept 12345 -www -cert server.crt -key server.key 
Secure Renegotiation IS supported
Ciphers supported in s_server binary
TLSv1/SSLv3:ECDHE-RSA-AES256-GCM-SHA384TLSv1/SSLv3:ECDHE-ECDSA-AES256-GCM-SHA384
TLSv1/SSLv3:ECDHE-RSA-AES256-SHA384  TLSv1/SSLv3:ECDHE-ECDSA-AES256-SHA384
TLSv1/SSLv3:ECDHE-RSA-AES256-SHA     TLSv1/SSLv3:ECDHE-ECDSA-AES256-SHA   
(以下省略)

では、次に -HTTPで起動した場合。事前に test.html は作成しておきます。

$ cat -v test.html
HTTP/1.1 200 OK^M
Content-Length: 40^M
^M
<html><body>
hello world
</body></html>
$ openssl s_server -accept 12345 -HTTP -cert server.crt -key server.key
Using default temp DH parameters
Using default temp ECDH parameters
ACCEPT

test.htmlの中身が復帰改行(上記で「^M」)になっていることに注意。HTTPの構文上のルールです。
で、Webブラウザで「https://上記コマンドを入力したサーバ:12345/test.html」にアクセスすると
hello world と表示されるはずです。

これらを全部手入力でやる場合が以下。(-wwwも-HTTPも指定せずに起動)

$ openssl s_server -accept 12345 -cert server.crt -key server.key
Using default temp DH parameters
Using default temp ECDH parameters
ACCEPT

この状態で、「https://上記コマンドを入力したサーバ:12345/test.html」にアクセスすると、 opensslを実行している画面上には以下の表示が出力されます

-----BEGIN SSL SESSION PARAMETERS-----
MIGDAgEBAgIDAQQCAC8EIB27C9y3O0qehMdtgcZDNSNjwOU8U1iNbbsQ3gGq0sGU
(中略)
AjWhBgIEVJ+xv6IEAgIBLKQGBAQBAAAApgwECm51bGwtaS5uZXQ=
-----END SSL SESSION PARAMETERS-----
Shared ciphers:AES128-SHA:AES256-SHA:(中略)
CIPHER is AES128-SHA
Secure Renegotiation IS supported
GET /test.html HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
Accept-Language: ja
User-Agent: Mozilla/X.0 (compatible; MSIE X.0; Windows NT X.0; Trident/X.0)
Accept-Encoding: gzip, deflate
Host: 起動したサーバ名:12345
Connection: Keep-Alive

リクエストの内容が全て表示されて、サーバ側の入力待ちになるので、何らかを入力します。

S現在のステータスを表示
rSSLセッションの再接続をクライアントへ要求
RSSLセッションの再接続と、クライアント証明書を要求
q現在のコネクションを終了する
ちなみにクライアントがWebブラウザとかなら大抵は再リクエストしてくる
Qサーバを終了
その他あるいはHTTPなりSMTPなり、繋いでいるプロトコル構文を打ちます

Webブラウザはサーバの応答を待っている状態のままなので、以下を慌てて入力。

HTTP/1.1 200 OK
Content-Length: 37
Connection: close
 
<html><body>
HELLO!!
</body></html>

すると、WebブラウザにHELLOが出ます。
そのプロトコル構文(今回はHTTP)が分かっていれば、色々なことが試せます。

そんなこんなで

コマンドのオプションは上記以外にも山ほどあるので、省略。
あとは、色々プログラミングでも使えます。
C言語とか、perlだとSSLeayを使って試験ツール作ったりしましたが、それはまた後日まとめたいです。


*1 ソルトは、暗号化時にランダム要素を加える為の文字列(いわゆる調味料?)の事です。ソルト抜きの場合はレインボーテーブル等の手法で解読される可能性が上がってしまいます。
*2 一応、openssl ciphers で暗号リストは一式得られますが、欲しいのはコマンドラインなんですよね。
*3 あえてurandomにした意図はないですが、ただ /dev/random は特定の条件下だと読み込み時にロックがかかるという仕様があります。でもurandomは「疑似」乱数なので真の乱数では無いというデメリット?があります。ケースバイケースで使い分けましょう。
*4 証明書の中に公開鍵が含まれる。証明書の内容は公開鍵基盤の公開鍵証明書の欄を参照
*5 時間が経つと脆くなるという概念。最新のものにしましょうという話はIT用語/CRYPTRECを参照
*6 つまりファイル名は、`openssl x509 -in 証明書ファイル -hash -noout`.0