class HTTPClient::SSLConfig
Represents SSL configuration for HTTPClient
instance. The implementation depends on OpenSSL
.
Trust Anchor Control¶ ↑
SSLConfig
loads ‘httpclient/cacert.pem’ as a trust anchor (trusted certificate(s)) with add_trust_ca
in initialization time. This means that HTTPClient
instance trusts some CA certificates by default, like Web browsers. ‘httpclient/cacert.pem’ is downloaded from curl web site by the author and included in released package.
On JRuby, HTTPClient
uses Java runtime’s trusted CA certificates, not cacert.pem by default. You can load cacert.pem by calling SSLConfig#load_trust_ca
manually like:
HTTPClient.new { self.ssl_config.load_trust_ca }.get("https://...")
You may want to change trust anchor by yourself. Call clear_cert_store
then add_trust_ca
for that purpose.
Constants
- CIPHERS_DEFAULT
Attributes
OpenSSL::X509::X509::Store used for verification. You can reset the store with clear_cert_store
and set the new store with cert_store
=.
Public Class Methods
Creates a SSLConfig
.
# File lib/httpclient/ssl_config.rb, line 145 def initialize(client) return unless SSLEnabled @client = client @cert_store = X509::Store.new @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 @verify_depth = nil @verify_callback = nil @dest = nil @timeout = nil @ssl_version = :auto # Follow ruby-ossl's definition @options = OpenSSL::SSL::OP_ALL @options &= ~OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS if defined?(OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS) @options |= OpenSSL::SSL::OP_NO_COMPRESSION if defined?(OpenSSL::SSL::OP_NO_COMPRESSION) @options |= OpenSSL::SSL::OP_NO_SSLv2 if defined?(OpenSSL::SSL::OP_NO_SSLv2) @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
Private Class Methods
# File lib/httpclient/ssl_config.rb, line 71 def attr_config(symbol) name = symbol.to_s ivar_name = "@#{name}" define_method(name) { instance_variable_get(ivar_name) } define_method("#{name}=") { |rhs| if instance_variable_get(ivar_name) != rhs instance_variable_set(ivar_name, rhs) change_notify end } symbol end
Public Instance Methods
Adds CRL for verification.
- crl
-
a OpenSSL::X509::CRL or a filename of a PEM/DER formatted OpenSSL::X509::CRL.
On JRuby, instead of setting CRL by yourself you can set following options to let HTTPClient
to perform revocation check with CRL and OCSP: -J-Dcom.sun.security.enableCRLDP=true -J-Dcom.sun.net.ssl.checkRevocation=true ex. jruby -J-Dcom.sun.security.enableCRLDP=true -J-Dcom.sun.net.ssl.checkRevocation=true app.rb
Revoked cert example: test-sspev.verisign.com:2443/test-SSPEV-revoked-verisign.html
Calling this method resets all existing sessions.
# File lib/httpclient/ssl_config.rb, line 268 def add_crl(crl) unless crl.is_a?(X509::CRL) crl = X509::CRL.new(File.open(crl) { |f| f.read }) end @cert_store.add_crl(crl) @cert_store_crl_items << crl @cert_store.flags = X509::V_FLAG_CRL_CHECK | X509::V_FLAG_CRL_CHECK_ALL change_notify end
Sets trust anchor certificate(s) for verification.
- trust_ca_file_or_hashed_dir
-
a filename of a PEM/DER formatted
OpenSSL::X509::Certificate
or a ‘c-rehash’eddirectory name which stores trusted certificate files.
Calling this method resets all existing sessions.
# File lib/httpclient/ssl_config.rb, line 231 def add_trust_ca(trust_ca_file_or_hashed_dir) unless File.exist?(trust_ca_file_or_hashed_dir) trust_ca_file_or_hashed_dir = File.join(File.dirname(__FILE__), trust_ca_file_or_hashed_dir) end @cacerts_loaded = true # avoid lazy override add_trust_ca_to_store(@cert_store, trust_ca_file_or_hashed_dir) change_notify end
# File lib/httpclient/ssl_config.rb, line 241 def add_trust_ca_to_store(cert_store, trust_ca_file_or_hashed_dir) if FileTest.directory?(trust_ca_file_or_hashed_dir) cert_store.add_path(trust_ca_file_or_hashed_dir) else cert_store.add_file(trust_ca_file_or_hashed_dir) end end
Sets new certificate store (OpenSSL::X509::Store
). don’t use if you don’t know what it is.
Calling this method resets all existing sessions.
# File lib/httpclient/ssl_config.rb, line 215 def cert_store=(cert_store) # This is object equality check, since OpenSSL::X509::Store doesn't overload == if !@cacerts_loaded || (@cert_store != cert_store) @cacerts_loaded = true # avoid lazy override @cert_store = cert_store change_notify end end
These array keeps original files/dirs that was added to @cert_store
# File lib/httpclient/ssl_config.rb, line 141 def cert_store_items; @cert_store._httpclient_cert_store_items; end
Drops current certificate store (OpenSSL::X509::Store
) for SSL and create new one for the next session.
Calling this method resets all existing sessions.
# File lib/httpclient/ssl_config.rb, line 204 def clear_cert_store @cacerts_loaded = true # avoid lazy override @cert_store = X509::Store.new @cert_store._httpclient_cert_store_items.clear change_notify end
Default callback for verification: only dumps error.
# File lib/httpclient/ssl_config.rb, line 338 def default_verify_callback(is_ok, ctx) if $DEBUG if is_ok warn("ok: #{ctx.current_cert.subject.to_s.dump}") else warn("ng: #{ctx.current_cert.subject.to_s.dump} at depth #{ctx.error_depth} - #{ctx.error}: #{ctx.error_string} in #{ctx.chain.inspect}") end warn(ctx.current_cert.to_text) warn(ctx.current_cert.to_pem) end if !is_ok depth = ctx.error_depth code = ctx.error msg = ctx.error_string warn("at depth #{depth} - #{code}: #{msg}") if $DEBUG end is_ok end
Loads default trust anchors. Calling this method resets all existing sessions.
# File lib/httpclient/ssl_config.rb, line 251 def load_trust_ca load_cacerts(@cert_store) change_notify end
Sample callback method: CAUTION: does not check CRL/ARL.
# File lib/httpclient/ssl_config.rb, line 358 def sample_verify_callback(is_ok, ctx) unless is_ok depth = ctx.error_depth code = ctx.error msg = ctx.error_string warn("at depth #{depth} - #{code}: #{msg}") if $DEBUG return false end cert = ctx.current_cert self_signed = false ca = false pathlen = nil server_auth = true self_signed = (cert.subject.cmp(cert.issuer) == 0) # Check extensions whatever its criticality is. (sample) cert.extensions.each do |ex| case ex.oid when 'basicConstraints' /CA:(TRUE|FALSE), pathlen:(\d+)/ =~ ex.value ca = ($1 == 'TRUE') pathlen = $2.to_i when 'keyUsage' usage = ex.value.split(/\s*,\s*/) ca = usage.include?('Certificate Sign') server_auth = usage.include?('Key Encipherment') when 'extendedKeyUsage' usage = ex.value.split(/\s*,\s*/) server_auth = usage.include?('Netscape Server Gated Crypto') when 'nsCertType' usage = ex.value.split(/\s*,\s*/) ca = usage.include?('SSL CA') server_auth = usage.include?('SSL Server') end end if self_signed warn('self signing CA') if $DEBUG return true elsif ca warn('middle level CA') if $DEBUG return true elsif server_auth warn('for server authentication') if $DEBUG return true end return false end
Sets certificate and private key for SSL client authentication.
- cert_file
-
must be a filename of PEM/DER formatted file.
- key_file
-
must be a filename of PEM/DER formatted file. Key must be an RSA key. If you want to use other PKey algorithm, use client_key=.
Calling this method resets all existing sessions if value is changed.
# File lib/httpclient/ssl_config.rb, line 175 def set_client_cert_file(cert_file, key_file, pass = nil) if (@client_cert != cert_file) || (@client_key != key_file) || (@client_key_pass != pass) @client_cert, @client_key, @client_key_pass = cert_file, key_file, pass change_notify end end
Sets OpenSSL’s default trusted CA certificates. Generally, OpenSSL
is configured to use OS’s trusted CA certificates located at /etc/pki/certs or /etc/ssl/certs. Unfortunately OpenSSL’s Windows build does not work with Windows Certificate Storage.
On Windows or when you build OpenSSL
manually, you can set the CA certificates directory by SSL_CERT_DIR env variable at runtime.
SSL_CERT_DIR=/etc/ssl/certs ruby -rhttpclient -e "..."
Calling this method resets all existing sessions.
# File lib/httpclient/ssl_config.rb, line 193 def set_default_paths @cacerts_loaded = true # avoid lazy override @cert_store = X509::Store.new @cert_store.set_default_paths change_notify end
# File lib/httpclient/ssl_config.rb, line 279 def verify? @verify_mode && (@verify_mode & OpenSSL::SSL::VERIFY_PEER != 0) end
Private Instance Methods
# File lib/httpclient/ssl_config.rb, line 411 def change_notify @client.reset_all nil end
Use 2048 bit certs trust anchor
# File lib/httpclient/ssl_config.rb, line 417 def load_cacerts(cert_store) file = File.join(File.dirname(__FILE__), 'cacert.pem') add_trust_ca_to_store(cert_store, file) end