RubyのNet::HTTPで独自のCertificateを設定する

とある会社のAPIに接続するため、その会社が発行した証明書・秘密鍵を用いて アクセスをする必要がありました。

いつもと違って独自のCERT/Private keyでアクセスする必要があり、 RubyのNet::HTTPでハマってしまったのでここにメモを残します。

いつものHTTPSのやり方

url = "http://example.com/foo/bar"
uri = URI.parse(url)
req = Net::HTTP::Post.new(uri.path)
params = {your_data: 1}
req.set_form_data(params)

https = Net::HTTP.new(uri.host, uri.port)
https.use_ssl = true
res = https.start { |h| h.request(req) }
puts res.code
puts res.body

こんな風にしてあげれば、良い感じにできます。 ポイントは、https.use_ssl = true でhttpsを設定してあげる事 ぐらいでしょうか。

独自の証明書や秘密鍵でSSL接続する

色々とネットを調べてみたのですが、情報が散乱してて意外とハマってしまいまいした。

パスフレーズ付きの秘密鍵をdecrypt(復号)する

パスフレーズで復号するのを忘れて、随分時間を無駄にしてしまいました…orz

cert_file_path = "path/to/your_cert.pem"
passphrase = "YourPassphrase"
key = OpenSSL::PKey::RSA.new(File.read(cert_file_path), passphrase)

このように、OpenSSL::PKey::RSA.new にCertファイルとパスフレーズを渡してあげると復号してくれます。

keycertを設定してあげる

https.key = OpenSSL::PKey::RSA.new(File.read(cert_file_path), passphrase)
https.cert = OpenSSL::X509::Certificate.new(File.read(cert_file_path))

https.ca_file = "/path/to/your_cert.pem" のようにファイルをそのまま渡してしまう例が多かったのですが、 今回はパスフレーズで秘密鍵を復号化しないといけなかったので、上記のように直接 https.keyhttps.certを自分で設定するようにしました。 (* 今回のCERTファイルはPEMファイルで、中にCertificateとPrivate keyの両方が含まれるタイプでした。)

最終的に以下のようにする事でうまく行きました。

url = "http://example.com/foo/bar"
uri = URI.parse(url)
req = Net::HTTP::Post.new(uri.path)
params = {your_data: 1}
req.set_form_data(params)

https = Net::HTTP.new(uri.host, uri.port)
https.use_ssl = true
cert_file_path = "path/to/your_cert.pem"
passphrase = "YourPassphrase" # Change to your passphrase
https.key = OpenSSL::PKey::RSA.new(File.read(cert_file_path), passphrase)
https.cert = OpenSSL::X509::Certificate.new(File.read(cert_file_path))
https.verify_mode = OpenSSL::SSL::VERIFY_PEER
https.verify_depth = 5
res = https.start { |h| h.request(req) }
puts res.code
puts res.body

よく使うNet::HTTPですが、思いがけずハマってしまいました。

これが誰かの役に立てば幸いです。

参考リンク

@takp