httpclient 2.8.2.4 → 2.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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)