httpclient 2.8.2.4 → 2.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -39,26 +39,28 @@ class HTTPClient
39
39
  if SSLEnabled
40
40
  include OpenSSL
41
41
 
42
- module ::OpenSSL
43
- module X509
44
- class Store
45
- attr_reader :_httpclient_cert_store_items
46
-
47
- # TODO: use prepend instead when we drop JRuby + 1.9.x support
48
- wrapped = {}
49
-
50
- wrapped[:initialize] = instance_method(:initialize)
51
- define_method(:initialize) do |*args|
52
- wrapped[:initialize].bind(self).call(*args)
53
- @_httpclient_cert_store_items = [ENV['SSL_CERT_FILE'] || :default]
54
- end
42
+ if defined? JRUBY_VERSION
43
+ module ::OpenSSL
44
+ module X509
45
+ class Store
46
+ attr_reader :_httpclient_cert_store_items
47
+
48
+ # TODO: use prepend instead when we drop JRuby + 1.9.x support
49
+ wrapped = {}
50
+
51
+ wrapped[:initialize] = instance_method(:initialize)
52
+ define_method(:initialize) do |*args|
53
+ wrapped[:initialize].bind(self).call(*args)
54
+ @_httpclient_cert_store_items = [ENV['SSL_CERT_FILE'] || :default]
55
+ end
55
56
 
56
- [:add_cert, :add_file, :add_path].each do |m|
57
- wrapped[m] = instance_method(m)
58
- define_method(m) do |cert|
59
- res = wrapped[m].bind(self).call(cert)
60
- @_httpclient_cert_store_items << cert
61
- res
57
+ [:add_cert, :add_file, :add_path].each do |m|
58
+ wrapped[m] = instance_method(m)
59
+ define_method(m) do |cert|
60
+ res = wrapped[m].bind(self).call(cert)
61
+ @_httpclient_cert_store_items << cert
62
+ res
63
+ end
62
64
  end
63
65
  end
64
66
  end
@@ -66,58 +68,81 @@ class HTTPClient
66
68
  end
67
69
  end
68
70
 
71
+ class << self
72
+ private
73
+ def attr_config(symbol)
74
+ name = symbol.to_s
75
+ ivar_name = "@#{name}"
76
+ define_method(name) {
77
+ instance_variable_get(ivar_name)
78
+ }
79
+ define_method("#{name}=") { |rhs|
80
+ if instance_variable_get(ivar_name) != rhs
81
+ instance_variable_set(ivar_name, rhs)
82
+ change_notify
83
+ end
84
+ }
85
+ symbol
86
+ end
87
+ end
88
+
89
+
69
90
  CIPHERS_DEFAULT = "ALL:!aNULL:!eNULL:!SSLv2" # OpenSSL >1.0.0 default
70
91
 
71
92
  # Which TLS protocol version (also called method) will be used. Defaults
72
- # to :auto which means that OpenSSL decides (In my tests this resulted
93
+ # to :auto which means that OpenSSL decides (In my tests this resulted
73
94
  # with always the highest available protocol being used).
74
95
  # String name of OpenSSL's SSL version method name: TLSv1_2, TLSv1_1, TLSv1,
75
96
  # SSLv2, SSLv23, SSLv3 or :auto (and nil) to allow version negotiation (default).
76
97
  # See {OpenSSL::SSL::SSLContext::METHODS} for a list of available versions
77
98
  # in your specific Ruby environment.
78
- attr_reader :ssl_version
99
+ attr_config :ssl_version
79
100
  # OpenSSL::X509::Certificate:: certificate for SSL client authentication.
80
101
  # nil by default. (no client authentication)
81
- attr_reader :client_cert
102
+ attr_config :client_cert
82
103
  # OpenSSL::PKey::PKey:: private key for SSL client authentication.
83
104
  # nil by default. (no client authentication)
84
- attr_reader :client_key
85
- attr_reader :client_key_pass
105
+ attr_config :client_key
106
+ # OpenSSL::PKey::PKey:: private key pass phrase for client_key.
107
+ # nil by default. (no pass phrase)
108
+ attr_config :client_key_pass
86
109
 
87
110
  # A number which represents OpenSSL's verify mode. Default value is
88
111
  # OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT.
89
- attr_reader :verify_mode
112
+ attr_config :verify_mode
90
113
  # A number of verify depth. Certification path which length is longer than
91
114
  # this depth is not allowed.
92
115
  # CAUTION: this is OpenSSL specific option and ignored on JRuby.
93
- attr_reader :verify_depth
116
+ attr_config :verify_depth
94
117
  # A callback handler for custom certificate verification. nil by default.
95
118
  # If the handler is set, handler.call is invoked just after general
96
119
  # OpenSSL's verification. handler.call is invoked with 2 arguments,
97
120
  # ok and ctx; ok is a result of general OpenSSL's verification. ctx is a
98
121
  # OpenSSL::X509::StoreContext.
99
- attr_reader :verify_callback
122
+ attr_config :verify_callback
100
123
  # SSL timeout in sec. nil by default.
101
- attr_reader :timeout
124
+ attr_config :timeout
102
125
  # A number of OpenSSL's SSL options. Default value is
103
126
  # OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_SSLv2
104
127
  # CAUTION: this is OpenSSL specific option and ignored on JRuby.
105
128
  # Use ssl_version to specify the TLS version you want to use.
106
- attr_reader :options
129
+ attr_config :options
107
130
  # A String of OpenSSL's cipher configuration. Default value is
108
131
  # ALL:!ADH:!LOW:!EXP:!MD5:+SSLv2:@STRENGTH
109
132
  # See ciphers(1) man in OpenSSL for more detail.
110
- attr_reader :ciphers
133
+ attr_config :ciphers
111
134
 
112
135
  # OpenSSL::X509::X509::Store used for verification. You can reset the
113
136
  # store with clear_cert_store and set the new store with cert_store=.
114
137
  attr_reader :cert_store # don't use if you don't know what it is.
115
138
 
116
139
  # For server side configuration. Ignore this.
117
- attr_reader :client_ca # :nodoc:
140
+ attr_config :client_ca # :nodoc:
118
141
 
119
142
  # These array keeps original files/dirs that was added to @cert_store
120
- def cert_store_items; @cert_store._httpclient_cert_store_items; end
143
+ if defined? JRUBY_VERSION
144
+ def cert_store_items; @cert_store._httpclient_cert_store_items; end
145
+ end
121
146
  attr_reader :cert_store_crl_items
122
147
 
123
148
  # Creates a SSLConfig.
@@ -126,7 +151,7 @@ class HTTPClient
126
151
  @client = client
127
152
  @cert_store = X509::Store.new
128
153
  @cert_store_crl_items = []
129
- @client_cert = @client_key = @client_ca = nil
154
+ @client_cert = @client_key = @client_key_pass = @client_ca = nil
130
155
  @verify_mode = SSL::VERIFY_PEER | SSL::VERIFY_FAIL_IF_NO_PEER_CERT
131
156
  @verify_depth = nil
132
157
  @verify_callback = nil
@@ -144,42 +169,18 @@ class HTTPClient
144
169
  @cacerts_loaded = false
145
170
  end
146
171
 
147
- # Sets SSL version method String. Possible values: "SSLv2" for SSL2,
148
- # "SSLv3" for SSL3 and TLS1.x, "SSLv23" for SSL3 with fallback to SSL2.
149
- def ssl_version=(ssl_version)
150
- @ssl_version = ssl_version
151
- change_notify
152
- end
153
-
154
- # Sets certificate (OpenSSL::X509::Certificate) for SSL client
155
- # authentication.
156
- # client_key and client_cert must be a pair.
157
- #
158
- # Calling this method resets all existing sessions.
159
- def client_cert=(client_cert)
160
- @client_cert = client_cert
161
- change_notify
162
- end
163
-
164
- # Sets private key (OpenSSL::PKey::PKey) for SSL client authentication.
165
- # client_key and client_cert must be a pair.
166
- #
167
- # Calling this method resets all existing sessions.
168
- def client_key=(client_key)
169
- @client_key = client_key
170
- change_notify
171
- end
172
-
173
172
  # Sets certificate and private key for SSL client authentication.
174
173
  # cert_file:: must be a filename of PEM/DER formatted file.
175
174
  # key_file:: must be a filename of PEM/DER formatted file. Key must be an
176
175
  # RSA key. If you want to use other PKey algorithm,
177
176
  # use client_key=.
178
177
  #
179
- # Calling this method resets all existing sessions.
178
+ # Calling this method resets all existing sessions if value is changed.
180
179
  def set_client_cert_file(cert_file, key_file, pass = nil)
181
- @client_cert, @client_key, @client_key_pass = cert_file, key_file, pass
182
- change_notify
180
+ if (@client_cert != cert_file) || (@client_key != key_file) || (@client_key_pass != pass)
181
+ @client_cert, @client_key, @client_key_pass = cert_file, key_file, pass
182
+ change_notify
183
+ end
183
184
  end
184
185
 
185
186
  # Sets OpenSSL's default trusted CA certificates. Generally, OpenSSL is
@@ -207,7 +208,9 @@ class HTTPClient
207
208
  def clear_cert_store
208
209
  @cacerts_loaded = true # avoid lazy override
209
210
  @cert_store = X509::Store.new
210
- @cert_store._httpclient_cert_store_items.clear
211
+ if defined? JRUBY_VERSION
212
+ @cert_store._httpclient_cert_store_items.clear
213
+ end
211
214
  change_notify
212
215
  end
213
216
 
@@ -216,9 +219,12 @@ class HTTPClient
216
219
  #
217
220
  # Calling this method resets all existing sessions.
218
221
  def cert_store=(cert_store)
219
- @cacerts_loaded = true # avoid lazy override
220
- @cert_store = cert_store
221
- change_notify
222
+ # This is object equality check, since OpenSSL::X509::Store doesn't overload ==
223
+ if !@cacerts_loaded || (@cert_store != cert_store)
224
+ @cacerts_loaded = true # avoid lazy override
225
+ @cert_store = cert_store
226
+ change_notify
227
+ end
222
228
  end
223
229
 
224
230
  # Sets trust anchor certificate(s) for verification.
@@ -276,62 +282,6 @@ class HTTPClient
276
282
  end
277
283
  alias set_crl add_crl
278
284
 
279
- # Sets verify mode of OpenSSL. New value must be a combination of
280
- # constants OpenSSL::SSL::VERIFY_*
281
- #
282
- # Calling this method resets all existing sessions.
283
- def verify_mode=(verify_mode)
284
- @verify_mode = verify_mode
285
- change_notify
286
- end
287
-
288
- # Sets verify depth. New value must be a number.
289
- #
290
- # Calling this method resets all existing sessions.
291
- def verify_depth=(verify_depth)
292
- @verify_depth = verify_depth
293
- change_notify
294
- end
295
-
296
- # Sets callback handler for custom certificate verification.
297
- # See verify_callback.
298
- #
299
- # Calling this method resets all existing sessions.
300
- def verify_callback=(verify_callback)
301
- @verify_callback = verify_callback
302
- change_notify
303
- end
304
-
305
- # Sets SSL timeout in sec.
306
- #
307
- # Calling this method resets all existing sessions.
308
- def timeout=(timeout)
309
- @timeout = timeout
310
- change_notify
311
- end
312
-
313
- # Sets SSL options. New value must be a combination of # constants
314
- # OpenSSL::SSL::OP_*
315
- #
316
- # Calling this method resets all existing sessions.
317
- def options=(options)
318
- @options = options
319
- change_notify
320
- end
321
-
322
- # Sets cipher configuration. New value must be a String.
323
- #
324
- # Calling this method resets all existing sessions.
325
- def ciphers=(ciphers)
326
- @ciphers = ciphers
327
- change_notify
328
- end
329
-
330
- def client_ca=(client_ca) # :nodoc:
331
- @client_ca = client_ca
332
- change_notify
333
- end
334
-
335
285
  def verify?
336
286
  @verify_mode && (@verify_mode & OpenSSL::SSL::VERIFY_PEER != 0)
337
287
  end
@@ -459,6 +409,9 @@ class HTTPClient
459
409
  return true
460
410
  end
461
411
 
412
+ if pathlen > 2
413
+ warn('pathlen > 2') if $DEBUG
414
+ end
462
415
  return false
463
416
  end
464
417
 
@@ -471,7 +424,6 @@ class HTTPClient
471
424
 
472
425
  # Use 2048 bit certs trust anchor
473
426
  def load_cacerts(cert_store)
474
- ver = OpenSSL::OPENSSL_VERSION
475
427
  file = File.join(File.dirname(__FILE__), 'cacert.pem')
476
428
  add_trust_ca_to_store(cert_store, file)
477
429
  end
@@ -14,43 +14,31 @@ class HTTPClient
14
14
  # Wraps up OpenSSL::SSL::SSLSocket and offers debugging features.
15
15
  class SSLSocket
16
16
  def self.create_socket(session)
17
+ opts = {
18
+ :debug_dev => session.debug_dev
19
+ }
17
20
  site = session.proxy || session.dest
18
21
  socket = session.create_socket(site.host, site.port)
19
22
  begin
20
23
  if session.proxy
21
24
  session.connect_ssl_proxy(socket, Util.urify(session.dest.to_s))
22
25
  end
23
- ssl_socket = new(socket, session.ssl_config, session.debug_dev)
24
- ssl_socket.ssl_connect(session.dest.host)
25
- ssl_socket
26
+ new(socket, session.dest, session.ssl_config, opts)
26
27
  rescue
27
28
  socket.close
28
29
  raise
29
30
  end
30
31
  end
31
32
 
32
- def initialize(socket, context, debug_dev = nil)
33
+ def initialize(socket, dest, config, opts = {})
33
34
  unless SSLEnabled
34
35
  raise ConfigurationError.new('Ruby/OpenSSL module is required')
35
36
  end
36
37
  @socket = socket
37
- @context = context
38
+ @config = config
38
39
  @ssl_socket = create_openssl_socket(@socket)
39
- @debug_dev = debug_dev
40
- end
41
-
42
- def ssl_connect(hostname = nil)
43
- if hostname && @ssl_socket.respond_to?(:hostname=)
44
- @ssl_socket.hostname = hostname
45
- end
46
- @ssl_socket.connect
47
- if $DEBUG
48
- if @ssl_socket.respond_to?(:ssl_version)
49
- warn("Protocol version: #{@ssl_socket.ssl_version}")
50
- end
51
- warn("Cipher: #{@ssl_socket.cipher.inspect}")
52
- end
53
- post_connection_check(hostname)
40
+ @debug_dev = opts[:debug_dev]
41
+ ssl_connect(dest.host)
54
42
  end
55
43
 
56
44
  def peer_cert
@@ -108,8 +96,22 @@ class HTTPClient
108
96
 
109
97
  private
110
98
 
99
+ def ssl_connect(hostname = nil)
100
+ if hostname && @ssl_socket.respond_to?(:hostname=)
101
+ @ssl_socket.hostname = hostname
102
+ end
103
+ @ssl_socket.connect
104
+ if $DEBUG
105
+ if @ssl_socket.respond_to?(:ssl_version)
106
+ warn("Protocol version: #{@ssl_socket.ssl_version}")
107
+ end
108
+ warn("Cipher: #{@ssl_socket.cipher.inspect}")
109
+ end
110
+ post_connection_check(hostname)
111
+ end
112
+
111
113
  def post_connection_check(hostname)
112
- verify_mode = @context.verify_mode || OpenSSL::SSL::VERIFY_NONE
114
+ verify_mode = @config.verify_mode || OpenSSL::SSL::VERIFY_NONE
113
115
  if verify_mode == OpenSSL::SSL::VERIFY_NONE
114
116
  return
115
117
  elsif @ssl_socket.peer_cert.nil? and
@@ -119,7 +121,7 @@ class HTTPClient
119
121
  if @ssl_socket.respond_to?(:post_connection_check) and RUBY_VERSION > "1.8.4"
120
122
  @ssl_socket.post_connection_check(hostname)
121
123
  else
122
- @context.post_connection_check(@ssl_socket.peer_cert, hostname)
124
+ @config.post_connection_check(@ssl_socket.peer_cert, hostname)
123
125
  end
124
126
  end
125
127
 
@@ -131,11 +133,11 @@ class HTTPClient
131
133
  ssl_socket = nil
132
134
  if OpenSSL::SSL.const_defined?("SSLContext")
133
135
  ctx = OpenSSL::SSL::SSLContext.new
134
- @context.set_context(ctx)
136
+ @config.set_context(ctx)
135
137
  ssl_socket = OpenSSL::SSL::SSLSocket.new(socket, ctx)
136
138
  else
137
139
  ssl_socket = OpenSSL::SSL::SSLSocket.new(socket)
138
- @context.set_context(ssl_socket)
140
+ @config.set_context(ssl_socket)
139
141
  end
140
142
  ssl_socket
141
143
  end
@@ -64,7 +64,7 @@ class HTTPClient
64
64
  # Overwrites the original definition just for one line...
65
65
  def authority
66
66
  self.host && @authority ||= (begin
67
- authority = ""
67
+ authority = "".dup
68
68
  if self.userinfo != nil
69
69
  authority << "#{self.userinfo}@"
70
70
  end
@@ -1,3 +1,3 @@
1
1
  class HTTPClient
2
- VERSION = '2.8.2.4'
2
+ VERSION = '2.9.0'
3
3
  end
data/lib/httpclient.rb CHANGED
@@ -355,6 +355,8 @@ class HTTPClient
355
355
  # if your ruby is older than 2005-09-06, do not set socket_sync = false to
356
356
  # avoid an SSL socket blocking bug in openssl/buffering.rb.
357
357
  attr_proxy(:socket_sync, true)
358
+ # Enables TCP keepalive; no timing settings exist at present
359
+ attr_proxy(:tcp_keepalive, true)
358
360
  # User-Agent header in HTTP request.
359
361
  attr_proxy(:agent_name, true)
360
362
  # From header in HTTP request.
@@ -751,6 +753,10 @@ class HTTPClient
751
753
  request(:patch, uri, new_args, &block)
752
754
  end
753
755
 
756
+ # :call-seq:
757
+ # post(uri, {query: query, body: body, header: header, follow_redirect: follow_redirect}) -> HTTP::Message
758
+ # post(uri, body, header, follow_redirect) -> HTTP::Message
759
+ #
754
760
  # Sends POST request to the specified URL. See request for arguments.
755
761
  # You should not depend on :follow_redirect => true for POST method. It
756
762
  # sends the same POST method to the new location which is prohibited in HTTP spec.
@@ -1234,7 +1240,7 @@ private
1234
1240
  conn.push(res)
1235
1241
  return res
1236
1242
  end
1237
- content = block ? nil : ''
1243
+ content = block ? nil : ''.dup
1238
1244
  res = HTTP::Message.new_response(content, req.header)
1239
1245
  @debug_dev << "= Request\n\n" if @debug_dev
1240
1246
  sess = @session_manager.query(req, proxy)
data/lib/jsonclient.rb CHANGED
@@ -2,7 +2,7 @@ require 'httpclient'
2
2
  require 'json'
3
3
 
4
4
  # JSONClient auto-converts Hash <-> JSON in request and response.
5
- # * For POST or PUT request, convert Hash body to JSON String with 'application/json; charset=utf-8' header.
5
+ # * For PATCH, POST or PUT request, convert Hash body to JSON String with 'application/json; charset=utf-8' header.
6
6
  # * For response, convert JSON String to Hash when content-type is '(application|text)/(x-)?json'
7
7
  class JSONClient < HTTPClient
8
8
  CONTENT_TYPE_JSON_REGEX = /(application|text)\/(x-)?json/i
@@ -17,6 +17,10 @@ class JSONClient < HTTPClient
17
17
  @content_type_json_response_regex = CONTENT_TYPE_JSON_REGEX
18
18
  end
19
19
 
20
+ def patch(uri, *args, &block)
21
+ request(:patch, uri, argument_to_hash_for_json(args), &block)
22
+ end
23
+
20
24
  def post(uri, *args, &block)
21
25
  request(:post, uri, argument_to_hash_for_json(args), &block)
22
26
  end
@@ -37,7 +41,7 @@ private
37
41
 
38
42
  def argument_to_hash_for_json(args)
39
43
  hash = argument_to_hash(args, :body, :header, :follow_redirect)
40
- if hash[:body].is_a?(Hash)
44
+ if hash[:body].is_a?(Hash) || hash[:body].is_a?(Array)
41
45
  hash[:header] = json_header(hash[:header])
42
46
  hash[:body] = JSON.generate(hash[:body])
43
47
  end
@@ -47,11 +51,10 @@ private
47
51
  def json_header(header)
48
52
  header ||= {}
49
53
  if header.is_a?(Hash)
50
- header['Content-Type'] = @content_type_json_request
54
+ header.merge('Content-Type' => @content_type_json_request)
51
55
  else
52
- header << ['Content-Type', @content_type_json_request]
56
+ header + [['Content-Type', @content_type_json_request]]
53
57
  end
54
- header
55
58
  end
56
59
 
57
60
  def wrap_json_response(original)
data/sample/auth.rb CHANGED
@@ -7,5 +7,5 @@ c.debug_dev = STDOUT
7
7
  #c.set_proxy_auth("admin", "admin")
8
8
 
9
9
  # for WWW authentication: supports Basic, Digest and Negotiate.
10
- c.set_auth("http://dev.ctor.org/http-access2/", "user", "user")
10
+ c.set_auth("http://dev.ctor.org/http-access2/", "username", "password")
11
11
  p c.get("http://dev.ctor.org/http-access2/login")
@@ -0,0 +1,99 @@
1
+ require "openssl"
2
+
3
+ def build_ca
4
+ root_key = OpenSSL::PKey::RSA.new 2048 # the CA's public/private key
5
+ root_ca = OpenSSL::X509::Certificate.new
6
+ root_ca.version = 2 # cf. RFC 5280 - to make it a "v3" certificate
7
+ root_ca.serial = 1
8
+ root_ca.subject = OpenSSL::X509::Name.parse "C=JP,O=JIN.GR.JP,OU=RRR,CN=CA"
9
+ root_ca.issuer = root_ca.subject # root CA's are "self-signed"
10
+ root_ca.public_key = root_key.public_key
11
+ root_ca.not_before = Time.now
12
+ root_ca.not_after = root_ca.not_before + 10 * 365 * 24 * 60 * 60 # 10 years validity
13
+ ef = OpenSSL::X509::ExtensionFactory.new
14
+ ef.subject_certificate = root_ca
15
+ ef.issuer_certificate = root_ca
16
+ root_ca.add_extension(ef.create_extension("basicConstraints","CA:TRUE",true))
17
+ root_ca.add_extension(ef.create_extension("keyUsage","keyCertSign, cRLSign", true))
18
+ root_ca.add_extension(ef.create_extension("subjectKeyIdentifier","hash",false))
19
+ root_ca.add_extension(ef.create_extension("authorityKeyIdentifier","keyid:always",false))
20
+ root_ca.sign(root_key, OpenSSL::Digest::SHA256.new)
21
+ [root_key, root_ca]
22
+ end
23
+
24
+ root_key, root_ca = build_ca
25
+
26
+ File.write("test/ca.cert", root_ca.to_s)
27
+ File.write("test/ca.key", root_key.to_s)
28
+
29
+ def sub_cert(root_key, root_ca, cn, intermediate: false)
30
+ key = OpenSSL::PKey::RSA.new 2048
31
+ cert = OpenSSL::X509::Certificate.new
32
+ cert.version = 2
33
+ cert.serial = 2
34
+ cert.subject = OpenSSL::X509::Name.parse "C=JP,O=JIN.GR.JP,OU=RRR,CN=#{cn}"
35
+ cert.issuer = root_ca.subject # root CA is the issuer
36
+ cert.public_key = key.public_key
37
+ cert.not_before = Time.now
38
+ cert.not_after = cert.not_before + 9 * 365 * 24 * 60 * 60 # 9 years validity
39
+ ef = OpenSSL::X509::ExtensionFactory.new
40
+ ef.subject_certificate = cert
41
+ ef.issuer_certificate = root_ca
42
+ cert.add_extension(ef.create_extension("subjectKeyIdentifier","hash",false))
43
+ if intermediate
44
+ cert.add_extension(ef.create_extension("keyUsage","keyCertSign, cRLSign", true))
45
+ cert.add_extension(ef.create_extension("basicConstraints","CA:TRUE",true))
46
+ else
47
+ cert.add_extension(ef.create_extension("keyUsage","digitalSignature, keyEncipherment", true))
48
+ cert.add_extension(ef.create_extension("extendedKeyUsage", "serverAuth"))
49
+ end
50
+ cert.sign(root_key, OpenSSL::Digest::SHA256.new)
51
+ [key, cert]
52
+ end
53
+
54
+ sub_key, sub_cert = sub_cert(root_key, root_ca, "SubCA", intermediate: true)
55
+ File.write("test/subca.cert", sub_cert.to_s)
56
+ File.write("test/subca.key", sub_key.to_s)
57
+
58
+ server_key, server_cert = sub_cert(sub_key, sub_cert, "localhost")
59
+ File.write("test/server.cert", server_cert.to_s)
60
+ File.write("test/server.key", server_key.to_s)
61
+
62
+ client_key, client_cert = sub_cert(root_key, root_ca, "localhost")
63
+ File.write("test/client.cert", client_cert.to_s)
64
+ File.write("test/client.key", client_key.to_s)
65
+
66
+ system(
67
+ "openssl", "rsa", "-aes256",
68
+ "-in", "test/client.key",
69
+ "-out", "test/client-pass.key",
70
+ "-passout", "pass:pass4key",
71
+ )
72
+
73
+ File.write("test/ca-chain.pem", root_ca.to_s + sub_cert.to_s)
74
+
75
+ verify_key = OpenSSL::PKey::RSA.new 2048
76
+ File.write("test/fixtures/verify.key", verify_key.to_s)
77
+
78
+ def build_self_signed(key, cn)
79
+ cert = OpenSSL::X509::Certificate.new
80
+ cert.version = 2
81
+ cert.serial = 2
82
+ cert.subject = OpenSSL::X509::Name.parse "C=JP,O=JIN.GR.JP,OU=RRR,CN=#{cn}"
83
+ cert.issuer = cert.subject
84
+ cert.public_key = key.public_key
85
+ cert.not_before = Time.now
86
+ cert.not_after = cert.not_before + 9 * 365 * 24 * 60 * 60 # 9 years validity
87
+ ef = OpenSSL::X509::ExtensionFactory.new
88
+ ef.subject_certificate = cert
89
+ ef.issuer_certificate = cert
90
+ cert.add_extension(ef.create_extension("subjectKeyIdentifier","hash",false))
91
+ cert.add_extension(ef.create_extension("keyUsage","digitalSignature, keyEncipherment", true))
92
+ cert.add_extension(ef.create_extension("extendedKeyUsage", "serverAuth"))
93
+ cert.sign(key, OpenSSL::Digest::SHA256.new)
94
+ cert
95
+ end
96
+
97
+ File.write("test/fixtures/verify.localhost.cert", build_self_signed(verify_key, "localhost").to_s)
98
+ File.write("test/fixtures/verify.foo.cert", build_self_signed(verify_key, "foo").to_s)
99
+ File.write("test/fixtures/verify.alt.cert", build_self_signed(verify_key, "alt").to_s)