下記コードから生成される「amazon.pem」と FireFox から取得する PEM (証明書パスを含む X509 証明書)の内容が異なるのは何故でしょうか? Ruby で取得した PEM を指定して、net/https を使うとエラーが出ます。後者の PEM はエラーが発生しません。
文字数制限のため詳細を掲載できませんが、Ruby は2つの証明書、FireFoxは3つの証明書ができていました。
あと PEM とか DER、 CER 等いまいち理解していないので、参考になる WEB サイトを教えて頂けると幸いです。
---------- Ruby のコード ----------
require 'socket'
require 'openssl'
require 'uri'
include OpenSSL
uri = URI('https://affiliate.amazon.co.jp/gp/associates/join/landing/main.html')
soc = TCPSocket.new(uri.host, 443)
ssl = SSL::SSLSocket.new(soc)
ssl.connect
ssl.write("GET #{uri.request_uri} HTTP/1.0\n")
ssl.write("User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9.0.4) Gecko/2008102920 Firefox/3.0.4\n")
ssl.write("Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\n")
ssl.write("Accept-Language: ja,en-us;q=0.7,en;q=0.3\n")
ssl.write("Accept-Charset: Shift_JIS,utf-8;q=0.7,*;q=0.7\n")
ssl.write("\r\n\r\n")
pem = ssl.peer_cert_chain.to_s
ssl.close
soc.close
fp = File.open('amazon.pem', 'w+')
fp.puts pem
fp.close
http://www.ipa.go.jp/security/pki/index.html
の「5.3 階層型モデル」になっているようで、SSLの接続相手から送られてくる証明書は「図 5-6」の「CA11とH2」や「CA12とH3」にあたります。
Firefoxはあらかじめルート証明書がいくつか入っていて、その中の「VeriSign, Inc.のClass 3 Public Primary Certification Authority」が使われています。
OpenSSL::X509::Certificate#to_textなどでIssuerやSubjectを見てみれば
という証明書チェーンになっていて、サーバの証明書H3と中間証明書CA12がpeer_cert_chainで取り出せていると言うことがわかるのではないでしょうか。
詳しいことはIPAの http://www.ipa.go.jp/security/pki/index.html やベリサインの http://www.verisign.co.jp/basic/index.html などから見ていくといいのではないかと思います。
やはり R1 の証明書の取得はできませんでした。
いろいろ調べたのですが、Ruby Cookbook にそれらしい記述がありましたので、そちらを試してみたいと思います。
さらに調べるきっかけになりましたので、大変助かりました。
ssl.peer_cert_chain.to_s で接続相手の証明書からルート CA の証明書までのリストを取得しないと、Net::HTTPS.https.ca_file で認証できないとエラーが発生するようです。
ですので、ssl.peer_cert.to_s ではなく ssl.peer_cert_chain.to_s を使っています。