私が愛した openssl (PKI 編 その 1)
id:blooper:20120904 の続きです。前回は cryptographic primitives 関連のコマンドの使い方でした。
"PKI" は "Public Key Infrastructure" の頭文字で WikiPedia だとwikipedia:公開鍵基盤となっていますが、何のことだか名前だけでは分からないですよね〜。知りたい! 場合には前回引用した #mailerstudy 02 暗号入門 (2012-02-22更新) を見てもいいですしググってもいいです。適当に本並べとくんで適当にご購入下さい。1 冊目は前回も出ました。2 冊目は暗号技術を使うとどんなことができるのか・どんなことが考えられてるかがざっくり分かる素敵な本です。3 冊目は読んでないけどいいらしい。いいらしいけど読んでない。あと画像が引っ張れなかったんだけど「企業システムのためのPKI―公開鍵インフラストラクチャの構築・導入・運用」ってのもあります。
と思ったけど一応用語だけ並べときます。
- 秘密鍵
- 秘密にする鍵。良い乱数を使うことにより同じものが二つとないことが確保できていそうなもの。とある秘密鍵を持っている人はこの世に一人だけ、という前提。
- 公開鍵
- 公開する鍵。主に暗号化に使われるが RSA の場合秘密鍵で暗号化したものの復号ができてしまうし、もちろん公開鍵で暗号化したのは秘密鍵で復号できる。
- ハッシュ関数
- ハッシュドビーフのハッシュ。任意のバイト列を引数にとり、固定長のバイト列を返す関数。とてもランダムな値を返し、その値を返すような元の引数はそう簡単には作れない、という前提。
- MD4,MD5,SHA1,SHA2
- ハッシュ関数で流通しているものたち。上で言う固定長がそれぞれ 128bit,128bit,160bit と SHA2 は 224,256,384,512 が用意されてる。
- (電子)署名
- RSA を用いた電子署名は、署名したいバイト列のハッシュ値を取り、秘密にしてる方の鍵で暗号化したバイト列。文章と署名を受けとった人は、「文章のハッシュ値」と「署名を公開されてる鍵で復号した値」を比較して一致したら OK。ここでは公開鍵と秘密鍵の暗号と復号の立場が入れ換わっている。一般的には、秘密鍵で署名という操作を、公開鍵で検証という操作をする。
- 公開鍵証明書
- 公開鍵を公開しても誰のものだか保証がない。なので「身元情報」と「公開鍵」を連結したものに「署名」をして足して「公開鍵の持ち主を証明」する証明書。でも、その署名を確認するにはやっぱり誰かの公開鍵が必要なので、最初に誰かの公開鍵を信じなくてはいけない。Windows やら OS X やら Firefox には最初から証明書ベンダーの証明書がインストールされていて、それらソフトを使うことはそれらベンダーを信じることになっている。最初からまとめて信じるってわけじゃない信頼構築の仕組みもある。
- 認証局
- PKI だと信頼の階層が木構造になっているのかな? で、署名権限を下部組織に移譲したりします。証明書発行者のことなんだけど、そもそも発行者を信じるかどうかも貴方次第で、認証局に対して別の認証局が署名して証明書発行したりします。残念ながら私は心の中で「発行者 (Issuer)」くらいの簡単な意味に読み替えています。
- PKCS
- Public-Key Cryptography Standards。wikipedia:PKCS を見るんだ! RSA 社が作った PKI 関係の規格の名前。PKCS#12 みたいに名前がついている。数字で分かりづらい。openssl genrsa でできるのは PKCS#1 の RSA 鍵だ。
- OID
- Object IDentifier。SNMP とかで見たことある方も多いかと。持ち主情報の「国」とか「名前」とか「メールアドレス」という項目に OID が振られています。OID Repository - Home で探せる.
- 鍵交換
- インターネットなど盗聴される可能性があるところで秘密の byte 列を共有すること。RSA を使えば簡単。暗号化して送ればいい。他に Diffie-Hellman などもある。
ぐおぉぉぉ、だめだ、長くなる。
req
request の頭。CSR (Certificate Signing Request) を作ったり見たりするコマンド。PKCS#10 形式で作る。EXAMPLE という節があるのでちゃんと man req した方が幸せになれるよ。
証明書は公開鍵の持ち主を証明するのだったので、公開鍵と持ち主情報が必要です。で、CSR を作ったのが確かに秘密鍵の持ち主であることなど確認できるよう CSR にも証明依頼内容に対する署名がくっつきます。
とりあえず CSR を作ると、
$ openssl req -new -key private.key -out foo.csr 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) [AU]:JP State or Province Name (full name) [Some-State]:Tokyo Locality Name (eg, city) []:Chiyoda-ku Organization Name (eg, company) [Internet Widgits Pty Ltd]:My Company Organizational Unit Name (eg, section) []:Information Technology Common Name (eg, YOUR name) []:www.mymymy.co.jp Email Address []: Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: An optional company name []: $ head -n 2 foo.csr -----BEGIN CERTIFICATE REQUEST----- MIICyTCCAbECAQAwgYMxCzAJBgNVBAYTAkpQMQ4wDAYDVQQIDAVUb2t5bzETMBEG
持ち主情報が問われるので入力すると、それら情報と秘密鍵を用いて CSR が作成されます。CSR = "持ち主情報" + "公開鍵" + "持ち主情報 + 公開鍵 の秘密鍵による署名" です。(あと、署名方法も書いてあります、SH1 と RSA を使うとかね)。UTF-8 使いたい! って場合には -utf8 ってオプションもあったりします。
この持ち主情報で聞かれる内容などは openssl の設定ファイルに書かれています。Ubuntu だと /etc/ssl/openssl.cnf にありますが
(snip) [ req ] default_bits = 1024 default_keyfile = privkey.pem distinguished_name = req_distinguished_name attributes = req_attributes x509_extensions = v3_ca # The extentions to add to the self signed cert (snip) [ req_distinguished_name ] countryName = Country Name (2 letter code) countryName_default = AU countryName_min = 2 countryName_max = 2 stateOrProvinceName = State or Province Name (full name) stateOrProvinceName_default = Some-State localityName = Locality Name (eg, city) 0.organizationName = Organization Name (eg, company) 0.organizationName_default = Internet Widgits Pty Ltd # we can do this but it is not needed normally :-) #1.organizationName = Second Organization Name (eg, company) #1.organizationName_default = World Wide Web Pty Ltd organizationalUnitName = Organizational Unit Name (eg, section) #organizationalUnitName_default = commonName = Common Name (eg, YOUR name) commonName_max = 64 emailAddress = Email Address emailAddress_max = 64 (snip)
何聞くか、何文字か、などの情報が入っとるわけです。ちなみに、countryName などは OpenSSL の中でハードコードされてて OID とか書いてあるんですが、自前で追加することも可能です。oid_section という変数で指定されてる section で定義できます。
CSR 作成はバッチ処理でもできて、foo_csr.cnf として
[ req ] distinguished_name = req_distinguished_name prompt = no utf8 = yes [ req_distinguished_name ] C = JP ST = Okinawa L = Ishigaki O = Genkotsu LLC. OU = Very Hungry Div. CN = genkotsu
というファイルを作っておいて
openssl req -new -config foo_csr.cnf -key private.key -----BEGIN CERTIFICATE REQUEST----- MIICvTCCAaUCAQAweDELMAkGA1UEBhMCSlAxEDAOBgNVBAgTB09raW5hd2ExETAP (snip)
でも CSR を作ることができます。これだとまだ UTF-8 使おうって気になりますね。
CSR の中身を見るには
$ openssl req -in foo.csr -noout -text Certificate Request: Data: Version: 0 (0x0) Subject: C=JP, ST=Tokyo, L=Chiyoda-ku, O=My Company, OU=Information Technology, CN=www.mymymy.co.jp Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (2048 bit) Modulus: 00:e0:29:03:77:9f:ad:2c:ba:8a:1f:a0:10:eb:0f: (snip)
さっき入力した情報とか公開鍵の情報とか入っています。Subject が持ち主っつーか依頼主ね。
$ openssl req -in foo.csr -noout -modulus Modulus=E02903779FAD2CBA8A1FA010EB0FAEF5CC4EA8EAF0C07756D4A45463CB3E626A3FD341AE4912C029F6125FC44E1D38D3C87EE440AA89100CD73E29D628945FD6D35E97C6BB31F7213B0DF5D6629B89FF068E081E1F1200101681FEEE827DBB6D60BD13F7DA60A9B4AB375DEC3BEA3A4232704DCC8A65C6EC2CD7673E6D908D7E93355CA254E270442EFECA8A96C839CE7F2B60FB7B93E842C02422DAC60BF45470EDC90CD09B6638F0CAF9DFDA45C2E2B7F7BE93B3E7FA6B6DE1DAE7C84ADF8C2333336D2E0663FFF87F8F4B7EAF9C0CDA4649CA2A780D4E68EE6B86B65B1AE458804D40F5DB06BED1E9D052EA40F8192B94907D55B892D22304BEAF72C9B093
rsa と同様公開鍵の modulus が取り出せて秘密鍵とのペアリングの確認もできます。
-x509 というオプションもあって、これは証明書の形式 X.509 のことなのですが、これを足すと CSR を作るんじゃなくって自己署名証明書 (署名の秘密鍵が内容の公開鍵とペアの証明書) を作ります。とりあえず証明書さえあれば! という場合には簡単に作れるってことですね!!
-nameopt というオプションもあって、CSR を -text で読める形にするときの parse の方法や表示形式をいろいろいじれるんですが、詳細は man x509 しれ (と man に書いてあります)。
x509
X.509 は証明書の形式の名前で、いまはバージョン 3 で X.509v3 と書いたりします。そもそも ITU-T の X シリーズってのがあってその 500 番台が DAP (LDAP の DAP, Lightweight じゃないのね) の定義? で、X.509 で証明書が定義されています。最新は RFC 5280 を見ましょう。
man x509 の EXAMPLES もとても豊富なので是非一度見てみるといいよ!
証明書の中身を見る
証明書が欲しいのでちょっと証明書を取ってきましょう。
$ openssl s_client -connect www.google.com:443 < /dev/null > google.crt depth=1 C = ZA, O = Thawte Consulting (Pty) Ltd., CN = Thawte SGC CA verify error:num=20:unable to get local issuer certificate verify return:0 DONE $ openssl x509 -in google.crt -noout -text Certificate: Data: Version: 3 (0x2) Serial Number: 4f:9d:96:d9:66:b0:99:2b:54:c2:95:7c:b4:15:7d:4d Signature Algorithm: sha1WithRSAEncryption Issuer: C=ZA, O=Thawte Consulting (Pty) Ltd., CN=Thawte SGC CA Validity Not Before: Oct 26 00:00:00 2011 GMT Not After : Sep 30 23:59:59 2013 GMT Subject: C=US, ST=California, L=Mountain View, O=Google Inc, CN=www.google.com Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (1024 bit) Modulus: 00:de:b7:26:43:a6:99:85:cd:38:a7:15:09:b9:cf: 0f:c9:c3:55:8c:88:ee:8c:8d:28:27:24:4b:2a:5e: a0:d8:16:fa:61:18:4b:cf:6d:60:80:d3:35:40:32: 72:c0:8f:12:d8:e5:4e:8f:b9:b2:f6:d9:15:5e:5a: 86:31:a3:ba:86:aa:6b:c8:d9:71:8c:cc:cd:27:13: 1e:9d:42:5d:38:f6:a7:ac:ef:fa:62:f3:18:81:d4: 24:46:7f:01:77:7c:c6:2a:89:14:99:bb:98:39:1d: a8:19:fb:39:00:44:7d:1b:94:6a:78:2d:69:ad:c0: 7a:2c:fa:d0:da:20:12:98:d3 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: critical CA:FALSE X509v3 CRL Distribution Points: Full Name: URI:http://crl.thawte.com/ThawteSGCCA.crl X509v3 Extended Key Usage: TLS Web Server Authentication, TLS Web Client Authentication, Netscape Server Gated Crypto Authority Information Access: OCSP - URI:http://ocsp.thawte.com CA Issuers - URI:http://www.thawte.com/repository/Thawte_SGC_CA.crt Signature Algorithm: sha1WithRSAEncryption 21:ac:d5:ae:ca:34:89:5a:c2:ab:52:d2:b2:34:66:9d:7a:ab: ee:e6:7c:d5:7e:c2:5c:28:bb:74:00:c9:10:1f:42:13:fc:69: 8a:1e:24:a0:02:00:e9:ba:5b:ca:19:04:b2:d3:af:01:b2:7e: 5f:14:db:a6:db:52:b9:9a:f3:12:7f:7c:a2:9c:3b:6f:99:7d: ea:50:0d:76:23:12:ff:f7:66:73:29:b7:95:0a:ad:d8:8b:b2: de:20:e9:0a:70:64:11:08:c8:5a:f1:7d:9e:ec:69:a5:a5:d5: 82:d7:27:1e:9e:56:cd:d2:76:d5:79:2b:f7:25:43:1c:69:f0: b8:f9
上から順に
- 署名対象
- version
- 証明書発行者に対して一意なシリアルナンバー
- 署名アルゴリズム
- 証明書発行者
- 有効期間
- 証明書発行対象
- 公開鍵情報 (1024bit だと!?)
- 証明書拡張
- 署名方式と署名
となっています。
x509 にこそ -nameopt が使えて出力形式も色々いじれます。
個別にも出せます。
$ openssl x509 -in google.crt -noout -serial -issuer -startdate -enddate -subject -modulus serial=4F9D96D966B0992B54C2957CB4157D4D issuer= /C=ZA/O=Thawte Consulting (Pty) Ltd./CN=Thawte SGC CA notBefore=Oct 26 00:00:00 2011 GMT notAfter=Sep 30 23:59:59 2013 GMT subject= /C=US/ST=California/L=Mountain View/O=Google Inc/CN=www.google.com Modulus=DEB72643A69985CD38A71509B9CF0FC9C3558C88EE8C8D2827244B2A5EA0D816FA61184BCF6D6080D335403272C08F12D8E54E8FB9B2F6D9155E5A8631A3BA86AA6BC8D9718CCCCD27131E9D425D38F6A7ACEFFA62F31881D424467F01777CC62A891499BB98391DA819FB3900447D1B946A782D69ADC07A2CFAD0DA201298D3
結局オプションを沢山書いて一辺に指定しましたが、1 項目だけでも出せます。あと -dates とか他にもオプション満載です。
RFC 5280 の中には拡張として BasicConstraint/KeyUsage/ExtendedKeyUsage など定義されているのですが、これらを用いて認証局となれる (他の CSR への署名が許された) 証明書か、クライアント認証に用いて良いか、などが記述できます。
$ openssl x509 -in google.crt -noout -purpose Certificate purposes: SSL client : Yes SSL client CA : No SSL server : Yes SSL server CA : No Netscape SSL server : Yes Netscape SSL server CA : No S/MIME signing : No S/MIME signing CA : No S/MIME encryption : No S/MIME encryption CA : No CRL signing : Yes CRL signing CA : No Any Purpose : Yes Any Purpose CA : Yes OCSP helper : Yes OCSP helper CA : No Time Stamp signing : No Time Stamp signing CA : No
と -purpose を用いると見ることができます。この内容も含めて署名されるので、つまり署名した Issuer がこれらの用途を認めてるっつーことになります。
証明書を作る (CSR に署名する)
CSR への署名も可能です。-req を付けると「入力が CSR = 署名して出力」、ということになります。面倒になってきたから man x509 から引用
$ openssl x509 -req -in req.pem -extfile openssl.cnf -extensions v3_usr -CA cacert.pem -CAkey key.pem -CAcreateserial
- CSR は req.pem
- Issuer の証明書は cacert.pem でこれの Subject が新証明書の Issuer になる
- Issuer の秘密鍵は key.pem でこれで署名する
- 設定ファイル openssl.cnf の v3_usr という項目にある証明書拡張を付ける
- シリアルナンバーは cacert.srl に保存される
といった塩梅で署名が可能です。でもまぁ、これだけだと管理が大変ですね、ということで openssl ca や CA.sh など色々なコマンド、スクリプトが別途用意されています。拡張を決める設定ファイルの項目の書き方は man x509v3_config を参照。
asn1parse
ASN.1 っつーのは X.509 などで用いられているバイナリフォーマットの形式です。wikipedia:Abstract_Syntax_Notation_One を見てちょ。で、ここで定義されてるうち DER っつーのを使っています。CSR も X.509 証明書も次に出てくる CRL も DER でエンコードされています。で、今までそれは BASE64 でテキストにされていました。このテキストにされたフォーマットを PEM と呼んでいる、っつっていいのかな?
Privacy-enhanced Mail の略なんだけど。http://en.wikipedia.org/wiki/Privacy-enhanced_Electronic_Mail むむーん。
でまぁ、ともかく、パースしてくれます。
$ openssl x509 -in google.crt | openssl asn1parse 0:d=0 hl=4 l= 801 cons: SEQUENCE 4:d=1 hl=4 l= 650 cons: SEQUENCE 8:d=2 hl=2 l= 3 cons: cont [ 0 ] 10:d=3 hl=2 l= 1 prim: INTEGER :02 13:d=2 hl=2 l= 16 prim: INTEGER :4F9D96D966B0992B54C2957CB4157D4D 31:d=2 hl=2 l= 13 cons: SEQUENCE 33:d=3 hl=2 l= 9 prim: OBJECT :sha1WithRSAEncryption 44:d=3 hl=2 l= 0 prim: NULL 46:d=2 hl=2 l= 76 cons: SEQUENCE 48:d=3 hl=2 l= 11 cons: SET 50:d=4 hl=2 l= 9 cons: SEQUENCE 52:d=5 hl=2 l= 3 prim: OBJECT :countryName 57:d=5 hl=2 l= 2 prim: PRINTABLESTRING :ZA 61:d=3 hl=2 l= 37 cons: SET 63:d=4 hl=2 l= 35 cons: SEQUENCE 65:d=5 hl=2 l= 3 prim: OBJECT :organizationName 70:d=5 hl=2 l= 28 prim: PRINTABLESTRING :Thawte Consulting (Pty) Ltd. 100:d=3 hl=2 l= 22 cons: SET 102:d=4 hl=2 l= 20 cons: SEQUENCE 104:d=5 hl=2 l= 3 prim: OBJECT :commonName 109:d=5 hl=2 l= 13 prim: PRINTABLESTRING :Thawte SGC CA 124:d=2 hl=2 l= 30 cons: SEQUENCE 126:d=3 hl=2 l= 13 prim: UTCTIME :111026000000Z (snip)
ちょっとゴミが多くて google.crt がそのまま使えなかったので openssl x509 で綺麗にしてみました。-i オプションを付けると出力にインデントをしてくれます。。何バイトのところから何が始まってるかとか、人の目で見えるようにするとどうなるかなどが書いてあります。INTEGER / SEQUENCE / OBJECT / PRINTABLESTRING / UTCTIME などは ASN.1 の中で定義されているものです。
で、DER や PEM を扱うコマンドは -inform や -outform といった入力や出力の形式を指定するオプションを持っていて、der やら pem やらを指定することができます。自動判別しろよ、って思いますよね。でもしてくれません。デフォルトは pem なので、今まで出てきませんでした。
crl
CRL は Certificate Revocation List の頭文字です。これもやっぱり X.509 だというか RFC 5280 で定義されています。証明書を失効 (無効化) したいことがあります。社員に出してた証明書を、社員の退職に伴い無効化したいというのは良くある話です。また対となる秘密鍵が漏洩してしまった証明書をいつまでも有効なままにしておくと悪用される危険性があるのでやっぱり無効化したいです。なので認証局は CRL を定期的に発行して発行した証明書全体を健全な状態に保ちます。
Google の証明書の拡張の部分に
X509v3 CRL Distribution Points: Full Name: URI:http://crl.thawte.com/ThawteSGCCA.crl
ってのがありました。認証局がしっかり CRL の場所を記載しています。
$ wget http://crl.thawte.com/ThawteSGCCA.crl $ openssl crl -in ThawteSGCCA.crl -inform der -noout -text Certificate Revocation List (CRL): Version 1 (0x0) Signature Algorithm: sha1WithRSAEncryption Issuer: /C=ZA/O=Thawte Consulting (Pty) Ltd./CN=Thawte SGC CA Last Update: Sep 5 09:00:50 2012 GMT Next Update: Sep 15 09:00:50 2012 GMT Revoked Certificates: Serial Number: 01478912B47F5ABE8BFC3043864D7B85 Revocation Date: Sep 28 10:21:25 2009 GMT Serial Number: 01A56766526CD4591600448A1A2EEB39 Revocation Date: May 18 23:53:47 2010 GMT (snip)
やっぱり「誰が発行したか」「有効期限はいつか」「失効された証明書のシリアル」あと省略しましたが「CRL に対する署名」が記載されています。「失効しちゃったよ!」という偽情報をばらまかれることを防ぐために CRL にも Issuer が署名をします。この Issuer は元の証明書の Issuer ですね。
とある証明書が失効されてるかどうか調べるには
- CRL がある場所を確認して
- CRL 取得して
- 有効期間と署名を確認して
- その証明書のシリアルが含まれているかどうか調べる
という手順になります。
crl では CRL は作れないのですが、ca を用いると CRL が作成できます。
まとめ
req, x509, crl, asn1parse を見ました。まだまだ PKI 関連のコマンドあるので以下次回。