Ruby, iOS, and Other Development

A place to share useful code snippets, ideas, and techniques

All code in posted articles shall be considered public domain unless otherwise noted.
Comments remain the property of their authors.

2008-03-08

SSL Certificates and Net::HTTPS

I was getting tired of seeing "warning: peer certificate won't be verified in this SSL session" from Ruby's net/https library, so I started looking around for how to get it to actually verify the SSL certificate. I found lots of links on how to tell it not to bother verifying, but it wasn't until I found someone's Japanese blog that I found the clue I was looking for. Now, I don't know Japanese, but I can read Ruby. For the benefit of other English speakers/readers out there, I now present the solution.

First off, I'm giving a full example request using basic authentication (not that GMail uses basic authentication, but this is an example) because I was unable to find a good example elsewhere and made it this far by trial and error. The following will produce the warning I mentioned:

require 'net/http'
require 'net/https'
require 'uri'

url = URI.parse 'https://myname:mypass@mail.google.com/'
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = (url.scheme == 'https')
request = Net::HTTP::Get.new(url.path)
request.basic_auth url.user, url.password
response = http.request(request)

To avoid the warning, we can either tell it not to warn us and blithely accept whatever certificate we receive, or we can give it enough information to authenticate the certificate against the root CA certificates. In the following example, we'll do both. If we find the file /usr/share/curl/curl-ca-bundle.crt then we will verify, otherwise we will silently ignore the issue:

require 'net/http'
require 'net/https'
require 'uri'

RootCA = '/usr/share/curl/curl-ca-bundle.crt'

url = URI.parse 'https://myname:mypass@mail.google.com/'
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = (url.scheme == 'https')
if File.exist? RootCA
 http.ca_file = RootCA
 http.verify_mode = OpenSSL::SSL::VERIFY_PEER
 http.verify_depth = 5
else
 http.verify_mode = OpenSSL::SSL::VERIFY_NONE
end
request = Net::HTTP::Get.new(url.path)
request.basic_auth url.user, url.password
response = http.request(request)

And there you have it. Not all that complicated, but poorly documented. Now it's more findably (i.e. Googleably) documented. Enjoy!

Update 2009-05-21: Thanks to a comment from Chewi, here's an even better approach:

require 'net/http'
require 'net/https'
require 'uri'

RootCA = '/etc/ssl/certs'

url = URI.parse 'https://myname:mypass@mail.google.com/'
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = (url.scheme == 'https')
if File.directory? RootCA
  http.ca_path = RootCA
  http.verify_mode = OpenSSL::SSL::VERIFY_PEER
  http.verify_depth = 5
else
  http.verify_mode = OpenSSL::SSL::VERIFY_NONE
end
request = Net::HTTP::Get.new(url.path)
request.basic_auth url.user, url.password
response = http.request(request)

Labels: ,

7 Comments:

  • At 8/07/2008 06:27:00 AM, Blogger Unknown said…

    That's the ticket! Thanks for posting this, its a great help.

     
  • At 8/12/2008 03:39:00 AM, Anonymous Anonymous said…

    Thanks man!

    I went through the exact same experience as you did: finding a million ways to neuter ssl verification and ignore the warning, rather than actually get it to work properly.

    Thankfully, I didn't have to look any farther than your blog.

    A tip for Debian and Ubuntu users: You can find the root certs in the file

    /etc/ssl/certs/ca-certificates.crt

    thanks again!

     
  • At 8/19/2008 06:49:00 AM, Blogger James Le Cuirot said…

    Thanks for this! Though, an even better property to use is ca_path. I point that to /etc/ssl/certs, which should exist on any distro.

     
  • At 5/20/2009 01:25:00 PM, Blogger Mario Ruiz said…

    Yeahhh this is working!!!

    but how could you get another page with the user logged into the website... for example the account page of the user.

     
  • At 7/14/2009 05:56:00 AM, Anonymous dubek said…

    Thanks a lot! Really helped.

    In my machine the file is at:

    /etc/pki/tls/certs/ca-bundle.crt

    Running

    curl -v https://www.google.com/

    will show you which CA file curl is using.

     
  • At 2/18/2010 09:29:00 AM, Anonymous Anonymous said…

    thank you very much

     
  • At 2/13/2017 02:17:00 AM, Anonymous Anonymous said…

    will this solution work if i am getting URL(some file to download) as the response from server. Before starting my download, i have to verify SSL certificate

     

Post a Comment

<< Home