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

cert_store[R]

OpenSSL::X509::X509::Store used for verification. You can reset the store with clear_cert_store and set the new store with cert_store=.

cert_store_crl_items[R]

Public Class Methods

new(client) click to toggle source

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

attr_config(symbol) click to toggle source
# 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

add_crl(crl) click to toggle source

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
Also aliased as: set_crl
add_trust_ca(trust_ca_file_or_hashed_dir) click to toggle source

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
Also aliased as: set_trust_ca
add_trust_ca_to_store(cert_store, trust_ca_file_or_hashed_dir) click to toggle source
# 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
cert_store=(cert_store) click to toggle source

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
cert_store_items() click to toggle source

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
clear_cert_store() click to toggle source

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_verify_callback(is_ok, ctx) click to toggle source

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
load_trust_ca() click to toggle source

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_verify_callback(is_ok, ctx) click to toggle source

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
set_client_cert_file(cert_file, key_file, pass = nil) click to toggle source

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
set_crl(crl)
Alias for: add_crl
set_default_paths() click to toggle source

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
set_trust_ca(trust_ca_file_or_hashed_dir)
Alias for: add_trust_ca
verify?() click to toggle source
# File lib/httpclient/ssl_config.rb, line 279
def verify?
  @verify_mode && (@verify_mode & OpenSSL::SSL::VERIFY_PEER != 0)
end

Private Instance Methods

change_notify() click to toggle source
# File lib/httpclient/ssl_config.rb, line 411
def change_notify
  @client.reset_all
  nil
end
load_cacerts(cert_store) click to toggle source

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