Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Respect OpenSSL default certificate store and SSL_CERT_FILE environment #386

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions lib/httpclient/ssl_config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,9 @@ def initialize(client)
return unless SSLEnabled
@client = client
@cert_store = X509::Store.new
@cert_store.set_default_paths
@cacerts_loaded = working_openssl_platform?

@cert_store_crl_items = []
@client_cert = @client_key = @client_key_pass = @client_ca = nil
@verify_mode = SSL::VERIFY_PEER | SSL::VERIFY_FAIL_IF_NO_PEER_CERT
Expand All @@ -162,7 +165,6 @@ def initialize(client)
@options |= OpenSSL::SSL::OP_NO_SSLv3 if defined?(OpenSSL::SSL::OP_NO_SSLv3)
# OpenSSL 0.9.8 default: "ALL:!ADH:!LOW:!EXP:!MD5:+SSLv2:@STRENGTH"
@ciphers = CIPHERS_DEFAULT
@cacerts_loaded = false
end

# Sets certificate and private key for SSL client authentication.
Expand Down Expand Up @@ -413,10 +415,21 @@ def change_notify
nil
end

def working_openssl_platform?
File.exist?(OpenSSL::X509::DEFAULT_CERT_FILE) && Dir.exist?(OpenSSL::X509::DEFAULT_CERT_DIR)
end

# Use 2048 bit certs trust anchor
def load_cacerts(cert_store)
file = File.join(File.dirname(__FILE__), 'cacert.pem')
add_trust_ca_to_store(cert_store, file)
certs = if ENV.key?('SSL_CERT_DIR'.freeze) || ENV.key?('SSL_CERT_FILE')
[ ENV['SSL_CERT_DIR'], ENV['SSL_CERT_FILE'] ].compact
else
[ File.join(File.dirname(__FILE__), 'cacert.pem') ]
end

certs.each do |cert|
add_trust_ca_to_store(cert_store, cert)
end
end
end

Expand Down
3 changes: 2 additions & 1 deletion test/helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
SimpleCov.formatter = SimpleCov::Formatter::RcovFormatter
SimpleCov.start
rescue LoadError
end
end if ENV['CI']

require 'test/unit'

require 'httpclient'
Expand Down
85 changes: 80 additions & 5 deletions test/test_ssl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,42 @@ def test_debug_dev
end

def test_verification_without_httpclient
raw_cert = "-----BEGIN CERTIFICATE-----\nMIIDOTCCAiGgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBCMRMwEQYKCZImiZPyLGQB\nGRYDb3JnMRkwFwYKCZImiZPyLGQBGRYJcnVieS1sYW5nMRAwDgYDVQQDDAdSdWJ5\nIENBMB4XDTE2MDgxMDE3MjEzNFoXDTE3MDgxMDE3MjEzNFowSzETMBEGCgmSJomT\n8ixkARkWA29yZzEZMBcGCgmSJomT8ixkARkWCXJ1YnktbGFuZzEZMBcGA1UEAwwQ\nUnVieSBjZXJ0aWZpY2F0ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\nAJCfsSXpSMpmZCVa+ZCM+QDgomnhDlvnrGDq6pasTaIspGTXgws+7r8Dt/cNe6EH\nHJpRH2cGRiO4yPcfcT9eS4X7k8OC4f33wHfACOmLu6LeoNE8ujmSk6L6WzLUI+sE\nnLZbFrXxoAo4XHsm8vEG9C+jEoXZ1p+47wrAGaDwDQTnzlMy4dT9pRQEJP2G/Rry\nUkuZn8SUWmh3/YS78iaSzsNF1cgE1ealHOrPPFDjiCGDaH/LHyUPYlbFSLZ/B7Qx\nLxi5sePLcywWq/EJrmWpgeVTDjtNijsdKv/A3qkY+fm/oD0pzt7XsfJaP9YKNyJO\nQFdxWZeiPcDF+Hwf+IwSr+kCAwEAAaMxMC8wDgYDVR0PAQH/BAQDAgeAMB0GA1Ud\nDgQWBBQNvzYzJyXemGhxbA8NMXLolDnPyjANBgkqhkiG9w0BAQsFAAOCAQEARIJV\noKejGlOTn71QutnNnu07UtTu0IHs6YqjYzzND+m4JXLN+wvYm72AFUG0b1L7dRg0\niK8XjQrlNQNVqP1Mc6tffchy20neOPOHeiO6qTdRU8P2S8D3Uwe+1qhgxjfE+cWc\nwZmWxYK4HA8c58PxWMqrkr2QqXDplG9KWLvOgrtPGiLLZcQSKhvvB63QzItHBDU6\nRayiJY3oPkK/HrIvFlySqFqzWmuyknkciOFywEHQMz/tcSFJ2QFpPj/tBz9VXohH\nZ8KscmfhZrTPBjo+ky1lz/WraWoz4LMiLnkC2ABczWLRSawu+v3Irx1NFJngt05e\npqwtqIUeg7j+JLiTaA==\n-----END CERTIFICATE-----"
raw_ca_cert = "-----BEGIN CERTIFICATE-----\nMIIDYjCCAkqgAwIBAgIBATANBgkqhkiG9w0BAQsFADBCMRMwEQYKCZImiZPyLGQB\nGRYDb3JnMRkwFwYKCZImiZPyLGQBGRYJcnVieS1sYW5nMRAwDgYDVQQDDAdSdWJ5\nIENBMB4XDTE2MDgxMDE3MjA1NFoXDTE4MDgxMDE3MjA1NFowQjETMBEGCgmSJomT\n8ixkARkWA29yZzEZMBcGCgmSJomT8ixkARkWCXJ1YnktbGFuZzEQMA4GA1UEAwwH\nUnVieSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALKGwyM3Ejtl\npo7CqaDlS71gDZn3gm6IwWpmRMLJofSI9LCwAbjijSC2HvO0xUWoYW40FbzjnnEi\ngszsWyPwuQIx9t0bhuAyllNIfImmkaQkrikXKBKzia4jPnbc4iXPnfjuThjESFWl\ntfbN6y1B5TjKhD1KelfakUO+iMu8WlIA9NKQZYfJ/F3QSpP5Iqb3KN/jVifFbDV8\nbAl3Ln4rT2kTCKrZZcl1jmWsJv8jBw6+P7hk0/Mu0JeHAITsjbNbpHd8UXpCfbVs\nsNGZrBU4uJdZ2YTG+Y27/t25jFNQwb+TWbvig7rfdX2sjssuxa00BBxarC08tIVj\nZprM37KcNn8CAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC\nAQYwHQYDVR0OBBYEFA2/NjMnJd6YaHFsDw0xcuiUOc/KMB8GA1UdIwQYMBYEFA2/\nNjMnJd6YaHFsDw0xcuiUOc/KMA0GCSqGSIb3DQEBCwUAA4IBAQAJSOw49XqvUll0\n3vU9EAO6yUdeZSsQENIfYbRMQgapbnN1vTyrUjPZkGC5hIE1pVdoHtEoUEICxIwy\nr6BKxiSLBDLp+rvIuDdzMkXIWdUVvTZguVRyKtM2gfnpsPLpVnv+stBmAW2SMyxm\nkymhOpkjdv3He+45uorB3tdfBS9VVomDEUJdg38UE1b5eXRQ3D6gG0iCPFzKszXg\nLoAYhGxtjCJaKlbzduMK0YO6aelgW1+XnVIKcA7DJ9egk5d/dFZBPFfwumwr9hTH\nh7/fp3Fr87weI+CkfmFyJZrsEBlXJBVuvPesMVHTh3Whm5kmCdWcBJU0QmSq42ZL\n72U0PXLR\n-----END CERTIFICATE-----"
ca_cert = ::OpenSSL::X509::Certificate.new(raw_ca_cert)
cert = ::OpenSSL::X509::Certificate.new(raw_cert)
ca_cert = ::OpenSSL::X509::Certificate.new(%w[-----BEGIN\ CERTIFICATE-----
MIIC3jCCAcYCCQCUWi3t8e122TANBgkqhkiG9w0BAQsFADAxMQ0wCwYDVQQKDARS
dWJ5MRMwEQYDVQQLDApodHRwY2xpZW50MQswCQYDVQQDDAJDQTAeFw0xODAyMjcx
MTM0NDRaFw0yODAyMjUxMTM0NDRaMDExDTALBgNVBAoMBFJ1YnkxEzARBgNVBAsM
Cmh0dHBjbGllbnQxCzAJBgNVBAMMAkNBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEAs6FPPj8PVl1uxsMZas4VC/ibRvtyXQkfrEa7TO032Kh+ETsOQNS8
QJedhw/BMHuoVbU0/b6PZ//LJTUDN/C77/QWHKzcMoxkNye5PC2cJlSQMosaKjYG
1ERYmJ+FBiMMSpcLOCS5cYoP2fJHGtHqZPkxIPYy+IKQ7WuP3tUXkVC+ftpD6H4V
6MUnfLwagpaAAbRoFUJQoZISmH2+F5GOKX9KKiMBI94yqRRN4K/B9iqXgld45Hmg
67vX0ckRbqBhrz1CwPtaETLFB4hZT2ouBkMQYtrvpNXv80p7vcz+BwORo8b2Ns9B
4FqtpjMaS9Mf95z4Mn+NG7lanYtsHO2svwIDAQABMA0GCSqGSIb3DQEBCwUAA4IB
AQBu614zHB5SS+ORYrRwl7tICKUipWHdCJfYsJOQy/FKwe7vedwd/Uclfe06GU+m
bNv0y22/oF7vrM3EfnxFe2DNIKXTndszrQSLpT6OPBe4mAOSJxnIMy6B6/PyhK6I
D7TWFSVlYX9a4OfolsoE0gQtxhyLud4rvJgXyAq9kRZ1FcNfI75cImk67rCa8jRY
TJOTidKq1Kcn6RY7d8cf581HP7y/eK887K6lBvGiQE1aFDSLe2ZLY+rxS9GSMYfK
81XhUX2QKytGYch2y95ThMwOljVTg6fKDrtKGwj9mSsnlfTFX3gikvLLtB/o7JPR
2pWBic8PX7gnANQqH/4ahv1M
-----END\ CERTIFICATE-----].join("\n"))
cert = ::OpenSSL::X509::Certificate.new(%w[-----BEGIN\ CERTIFICATE-----
MIIC5zCCAc8CCQCz/lMJNLxQDjANBgkqhkiG9w0BAQsFADAxMQ0wCwYDVQQKDARS
dWJ5MRMwEQYDVQQLDApodHRwY2xpZW50MQswCQYDVQQDDAJDQTAeFw0xODAyMjcx
MTM1MTNaFw0yNzExMjcxMTM1MTNaMDoxDTALBgNVBAoMBFJ1YnkxEzARBgNVBAsM
Cmh0dHBjbGllbnQxFDASBgNVBAMMC0NlcnRpZmljYXRlMIIBIjANBgkqhkiG9w0B
AQEFAAOCAQ8AMIIBCgKCAQEAo/zP4oPyqerNyJYNTKzAGGQR8uKmP9wLnLm/yTf/
jwzVLj3rvunw54aw89V3R4LLwBBMgFlE9OrUa+2zCvZJ8ykSoltU+w9E2EdXnXAR
C/GW678MA06NPBuMNQyf+7Lv7dipdv+0hUNXFarwGiJkCms0zcmTonkOC8Bh7stZ
EykkvQs5zmYVd+G26D5un8Wzjl6OckbBDcKTS9u9H1YveRcnN7odsh+qI4PjDmKG
PXR8Gz/loNYN/I55Hqe7vkQJZ7r1PjSBp/fIcb4pNEkKS9DAcNWkoHF2j5nBNdOq
mH3WR36vKlw5S4HLzDXQDeueFbtk3QGrWY2MWrpJNapeAQIDAQABMA0GCSqGSIb3
DQEBCwUAA4IBAQB2CiGKAvHjr4kjOavWqGfPv115N4fhmBcPH4YAeJB9mHTzpoPV
BCm0ouRG5Oqj/DJhm+mckFKSorZFSgVb/G92w0uXRvBMPJb4wyIbp5ld6K3138cn
DtmeON3gbHwh3or741LdD6GIaulA9CL/qI3bbiyrJrHAZuHbpA6UqHfTKTBVi0uq
kv8qmA8FrzI2itDqdp0dq3QMNGnG40OM8NSDX+8A9wMahPh+Oe3TePSvDTahXIU1
o+dzaUEIVhUWEikQBnfeEnxzN8B/qtt3wEpliAip9Z3LuN0pVFb81Mx1wEZls2Bd
Kj83iBw7flO651USNPnkOkU3DegNtcpTaT5M
-----END\ CERTIFICATE-----].join("\n"))
store = ::OpenSSL::X509::Store.new
store.add_cert(ca_cert)
assert(store.verify(cert))
Expand Down Expand Up @@ -245,6 +277,35 @@ def test_set_default_paths
end
end

def test_load_cacerts
omit_if(RUBY_ENGINE == 'jruby', 'SSL_CERT_FILE environment does not work on JRuby')

# disables loading default openssl paths
stub_x509_const(:DEFAULT_CERT_FILE, '/invalid') do
assert_raise(OpenSSL::SSL::SSLError) do
@client.get(@url)
end

setup_client

escape_env do
ENV['SSL_CERT_FILE'] = File.join(DIR, 'ca-chain.pem')
@client.get(@url)
end
end
end

def test_default_paths
assert_raise(OpenSSL::SSL::SSLError) do
@client.get(@url)
end
escape_env do
ENV['SSL_CERT_FILE'] = File.join(DIR, 'ca-chain.pem')
setup_client
@client.get(@url)
end
end

def test_no_sslv3
teardown_server
setup_server_with_ssl_version(:SSLv3)
Expand All @@ -264,7 +325,7 @@ def test_allow_tlsv1
end

def test_use_higher_TLS
omit('TODO: it does not pass with Java 7 or old openssl ')
# TODO: it does not pass with Java 7 or old openssl
teardown_server
setup_server_with_ssl_version('TLSv1_2')
assert_nothing_raised do
Expand Down Expand Up @@ -429,6 +490,20 @@ def test_timeout

private

def stub_x509_const(name, value)
OpenSSL::X509.module_eval do
begin
original = remove_const(name)
const_set(name, value)

yield
ensure
remove_const(name)
const_set(name, original)
end
end
end

def cert(filename)
OpenSSL::X509::Certificate.new(File.read(File.join(DIR, filename)))
end
Expand Down