Class: HTTPClient::SSLConfig
- Inherits:
-
Object
- Object
- HTTPClient::SSLConfig
- Defined in:
- lib/httpclient/ssl_config.rb
Overview
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.
Constant Summary collapse
- CIPHERS_DEFAULT =
OpenSSL >1.0.0 default
"ALL:!aNULL:!eNULL:!SSLv2"
Instance Attribute Summary collapse
-
#cert_store ⇒ Object
OpenSSL::X509::X509::Store used for verification.
-
#cert_store_crl_items ⇒ Object
readonly
Returns the value of attribute cert_store_crl_items.
Instance Method Summary collapse
-
#add_crl(crl) ⇒ Object
(also: #set_crl)
Adds CRL for verification.
-
#add_trust_ca(trust_ca_file_or_hashed_dir) ⇒ Object
(also: #set_trust_ca)
Sets trust anchor certificate(s) for verification.
- #add_trust_ca_to_store(cert_store, trust_ca_file_or_hashed_dir) ⇒ Object
- #cert_store_items ⇒ Object
-
#clear_cert_store ⇒ Object
Drops current certificate store (OpenSSL::X509::Store) for SSL and create new one for the next session.
-
#default_verify_callback(is_ok, ctx) ⇒ Object
Default callback for verification: only dumps error.
-
#initialize(client) ⇒ SSLConfig
constructor
Creates a SSLConfig.
-
#load_trust_ca ⇒ Object
Loads default trust anchors.
-
#post_connection_check(peer_cert, hostname) ⇒ Object
post connection check proc for ruby < 1.8.5.
-
#sample_verify_callback(is_ok, ctx) ⇒ Object
Sample callback method: CAUTION: does not check CRL/ARL.
-
#set_client_cert_file(cert_file, key_file, pass = nil) ⇒ Object
Sets certificate and private key for SSL client authentication.
-
#set_context(ctx) ⇒ Object
interfaces for SSLSocket.
-
#set_default_paths ⇒ Object
Sets OpenSSL’s default trusted CA certificates.
- #verify? ⇒ Boolean
Methods included from Util
#argument_to_hash, hash_find_value, #http?, #https?, #keyword_argument, try_require, uri_dirname, uri_part_of, urify, #warning
Constructor Details
#initialize(client) ⇒ SSLConfig
Creates a SSLConfig.
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/httpclient/ssl_config.rb', line 149 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 |
Instance Attribute Details
#cert_store ⇒ Object
OpenSSL::X509::X509::Store used for verification. You can reset the store with clear_cert_store and set the new store with cert_store=.
137 138 139 |
# File 'lib/httpclient/ssl_config.rb', line 137 def cert_store @cert_store end |
#cert_store_crl_items ⇒ Object (readonly)
Returns the value of attribute cert_store_crl_items.
146 147 148 |
# File 'lib/httpclient/ssl_config.rb', line 146 def cert_store_crl_items @cert_store_crl_items end |
Instance Method Details
#add_crl(crl) ⇒ Object Also known as: set_crl
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.
274 275 276 277 278 279 280 281 282 |
# File 'lib/httpclient/ssl_config.rb', line 274 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 |
#add_trust_ca(trust_ca_file_or_hashed_dir) ⇒ Object Also known as: set_trust_ca
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.
237 238 239 240 241 242 243 244 |
# File 'lib/httpclient/ssl_config.rb', line 237 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 |
#add_trust_ca_to_store(cert_store, trust_ca_file_or_hashed_dir) ⇒ Object
247 248 249 250 251 252 253 |
# File 'lib/httpclient/ssl_config.rb', line 247 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_items ⇒ Object
144 |
# File 'lib/httpclient/ssl_config.rb', line 144 def cert_store_items; @cert_store._httpclient_cert_store_items; end |
#clear_cert_store ⇒ Object
Drops current certificate store (OpenSSL::X509::Store) for SSL and create new one for the next session.
Calling this method resets all existing sessions.
208 209 210 211 212 213 214 215 |
# File 'lib/httpclient/ssl_config.rb', line 208 def clear_cert_store @cacerts_loaded = true # avoid lazy override @cert_store = X509::Store.new if defined? JRUBY_VERSION @cert_store._httpclient_cert_store_items.clear end change_notify end |
#default_verify_callback(is_ok, ctx) ⇒ Object
Default callback for verification: only dumps error.
344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 |
# File 'lib/httpclient/ssl_config.rb', line 344 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 ⇒ Object
Loads default trust anchors. Calling this method resets all existing sessions.
257 258 259 260 |
# File 'lib/httpclient/ssl_config.rb', line 257 def load_trust_ca load_cacerts(@cert_store) change_notify end |
#post_connection_check(peer_cert, hostname) ⇒ Object
post connection check proc for ruby < 1.8.5. this definition must match with the one in ext/openssl/lib/openssl/ssl.rb
316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 |
# File 'lib/httpclient/ssl_config.rb', line 316 def post_connection_check(peer_cert, hostname) # :nodoc: check_common_name = true cert = peer_cert cert.extensions.each{|ext| next if ext.oid != "subjectAltName" ext.value.split(/,\s+/).each{|general_name| if /\ADNS:(.*)/ =~ general_name check_common_name = false reg = Regexp.escape($1).gsub(/\\\*/, "[^.]+") return true if /\A#{reg}\z/i =~ hostname elsif /\AIP Address:(.*)/ =~ general_name check_common_name = false return true if $1 == hostname end } } if check_common_name cert.subject.to_a.each{|oid, value| if oid == "CN" reg = Regexp.escape(value).gsub(/\\\*/, "[^.]+") return true if /\A#{reg}\z/i =~ hostname end } end raise SSL::SSLError, "hostname was not match with the server certificate" end |
#sample_verify_callback(is_ok, ctx) ⇒ Object
Sample callback method: CAUTION: does not check CRL/ARL.
364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 |
# File 'lib/httpclient/ssl_config.rb', line 364 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 if pathlen > 2 warn('pathlen > 2') if $DEBUG end return false end |
#set_client_cert_file(cert_file, key_file, pass = nil) ⇒ Object
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.
179 180 181 182 183 184 |
# File 'lib/httpclient/ssl_config.rb', line 179 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_context(ctx) ⇒ Object
interfaces for SSLSocket.
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 |
# File 'lib/httpclient/ssl_config.rb', line 290 def set_context(ctx) # :nodoc: load_trust_ca unless @cacerts_loaded @cacerts_loaded = true # Verification: Use Store#verify_callback instead of SSLContext#verify*? ctx.cert_store = @cert_store ctx.verify_mode = @verify_mode ctx.verify_depth = @verify_depth if @verify_depth ctx.verify_callback = @verify_callback || method(:default_verify_callback) # SSL config if @client_cert ctx.cert = @client_cert.is_a?(X509::Certificate) ? @client_cert : X509::Certificate.new(File.open(@client_cert) { |f| f.read }) end if @client_key ctx.key = @client_key.is_a?(PKey::PKey) ? @client_key : PKey::RSA.new(File.open(@client_key) { |f| f.read }, @client_key_pass) end ctx.client_ca = @client_ca ctx.timeout = @timeout ctx. = @options ctx.ciphers = @ciphers ctx.ssl_version = @ssl_version unless @ssl_version == :auto end |
#set_default_paths ⇒ Object
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.
197 198 199 200 201 202 |
# File 'lib/httpclient/ssl_config.rb', line 197 def set_default_paths @cacerts_loaded = true # avoid lazy override @cert_store = X509::Store.new @cert_store.set_default_paths change_notify end |
#verify? ⇒ Boolean
285 286 287 |
# File 'lib/httpclient/ssl_config.rb', line 285 def verify? @verify_mode && (@verify_mode & OpenSSL::SSL::VERIFY_PEER != 0) end |