ruby-tls 2.0.1 → 2.1.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.
- checksums.yaml +4 -4
- data/README.md +3 -1
- data/lib/ruby-tls/ssl.rb +133 -21
- data/lib/ruby-tls/version.rb +1 -1
- data/spec/alpn_spec.rb +415 -0
- data/spec/comms_spec.rb +2 -2
- data/spec/verify_spec.rb +3 -3
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: acce3678093f001d9085b46b4c163c4036a6dee0
|
|
4
|
+
data.tar.gz: 1f7ab340aa973063db130f597334ccf7505d45a8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: edbee0e101783904e9fdadf6fdc1fccfc7785b3b69a798223ba36656ed71af5e475407a04a72a1c195688b3f6a6909a3e1ef20fd931db46309a4622e77fc56cb
|
|
7
|
+
data.tar.gz: 43dd6bb0b6a323bb282cdbdef4a2b81623cf01dfdc88ea28cb2df1cb66fc27d3caf8b8cf8c4659f51e8b574f60968b2a27fd03cd672472df853817864b94f33e
|
data/README.md
CHANGED
|
@@ -34,6 +34,8 @@ class transport
|
|
|
34
34
|
private_key: '/file/path.pem',
|
|
35
35
|
cert_chain: '/file/path.crt',
|
|
36
36
|
ciphers: 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-RC4-SHA:ECDHE-RSA-AES128-SHA:AES128-GCM-SHA256:RC4:HIGH:!MD5:!aNULL:!EDH:!CAMELLIA:@STRENGTH' # (default)
|
|
37
|
+
# protocols: ["h2", "http/1.1"], # Can be used where OpenSSL >= 1.0.2 (Application Level Protocol negotiation)
|
|
38
|
+
# fallback: "http/1.1" # Optional fallback to a default protocol when either client or server doesn't support ALPN
|
|
37
39
|
}
|
|
38
40
|
@ssl_layer = RubyTls::SSL::Box.new(is_server, callback_obj, options)
|
|
39
41
|
end
|
|
@@ -51,7 +53,7 @@ class transport
|
|
|
51
53
|
# @tcp.send data
|
|
52
54
|
end
|
|
53
55
|
|
|
54
|
-
def handshake_cb
|
|
56
|
+
def handshake_cb(protocol)
|
|
55
57
|
puts "initial handshake has completed"
|
|
56
58
|
end
|
|
57
59
|
|
data/lib/ruby-tls/ssl.rb
CHANGED
|
@@ -147,7 +147,30 @@ module RubyTls
|
|
|
147
147
|
attach_function :SSL_CTX_set_cipher_list, [:ssl_ctx, :string], :int
|
|
148
148
|
attach_function :SSL_CTX_set_session_id_context, [:ssl_ctx, :string, :buffer_length], :int
|
|
149
149
|
|
|
150
|
-
#
|
|
150
|
+
# OpenSSL before 1.0.2 do not have these methods
|
|
151
|
+
begin
|
|
152
|
+
attach_function :SSL_CTX_set_alpn_protos, [:ssl_ctx, :string, :uint], :int
|
|
153
|
+
|
|
154
|
+
SSL_TLSEXT_ERR_OK = 0
|
|
155
|
+
SSL_TLSEXT_ERR_ALERT_WARNING = 1
|
|
156
|
+
SSL_TLSEXT_ERR_ALERT_FATAL = 2
|
|
157
|
+
SSL_TLSEXT_ERR_NOACK = 3
|
|
158
|
+
|
|
159
|
+
OPENSSL_NPN_UNSUPPORTED = 0
|
|
160
|
+
OPENSSL_NPN_NEGOTIATED = 1
|
|
161
|
+
OPENSSL_NPN_NO_OVERLAP = 2
|
|
162
|
+
|
|
163
|
+
attach_function :SSL_select_next_proto, [:pointer, :pointer, :string, :uint, :string, :uint], :int
|
|
164
|
+
|
|
165
|
+
# array of str, unit8 out,uint8 in, *arg
|
|
166
|
+
callback :alpn_select_cb, [:ssl, :pointer, :pointer, :string, :uint, :pointer], :int
|
|
167
|
+
attach_function :SSL_CTX_set_alpn_select_cb, [:ssl_ctx, :alpn_select_cb, :pointer], :void
|
|
168
|
+
|
|
169
|
+
attach_function :SSL_get0_alpn_selected, [:ssl, :pointer, :pointer], :void
|
|
170
|
+
ALPN_SUPPORTED = true
|
|
171
|
+
rescue FFI::NotFoundError
|
|
172
|
+
ALPN_SUPPORTED = false
|
|
173
|
+
end
|
|
151
174
|
|
|
152
175
|
|
|
153
176
|
# Deconstructor
|
|
@@ -201,19 +224,23 @@ keystr
|
|
|
201
224
|
8
|
|
202
225
|
end
|
|
203
226
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
else
|
|
209
|
-
# Unlock a lock
|
|
210
|
-
SSL_LOCKS[type].unlock
|
|
211
|
-
end
|
|
212
|
-
end
|
|
227
|
+
# Locking isn't provided as long as all writes are done on the same thread.
|
|
228
|
+
# This is my main use case. Happy to enable it if someone requires it and can
|
|
229
|
+
# get it to work on MRI Ruby (Currently only works on JRuby and Rubinius)
|
|
230
|
+
# as MRI callbacks occur on a thread pool?
|
|
213
231
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
232
|
+
#CRYPTO_LOCK = 0x1
|
|
233
|
+
#LockingCB = FFI::Function.new(:void, [:int, :int, :string, :int]) do |mode, type, file, line|
|
|
234
|
+
# if (mode & CRYPTO_LOCK) != 0
|
|
235
|
+
# SSL_LOCKS[type].lock
|
|
236
|
+
# else
|
|
237
|
+
# Unlock a lock
|
|
238
|
+
# SSL_LOCKS[type].unlock
|
|
239
|
+
# end
|
|
240
|
+
#end
|
|
241
|
+
#ThreadIdCB = FFI::Function.new(:ulong, []) do
|
|
242
|
+
# Thread.current.object_id
|
|
243
|
+
#end
|
|
217
244
|
|
|
218
245
|
|
|
219
246
|
# INIT CODE
|
|
@@ -262,6 +289,29 @@ keystr
|
|
|
262
289
|
CIPHERS = 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-RC4-SHA:ECDHE-RSA-AES128-SHA:AES128-GCM-SHA256:RC4:HIGH:!MD5:!aNULL:!EDH:!CAMELLIA:@STRENGTH'.freeze
|
|
263
290
|
SESSION = 'ruby-tls'.freeze
|
|
264
291
|
|
|
292
|
+
|
|
293
|
+
ALPN_LOOKUP = ThreadSafe::Cache.new
|
|
294
|
+
ALPN_Select_CB = FFI::Function.new(:int, [
|
|
295
|
+
# array of str, unit8 out,uint8 in, *arg
|
|
296
|
+
:pointer, :pointer, :pointer, :string, :uint, :pointer
|
|
297
|
+
]) do |ssl_p, out, outlen, inp, inlen, arg|
|
|
298
|
+
ssl = Box::InstanceLookup[ssl_p.address]
|
|
299
|
+
return SSL::SSL_TLSEXT_ERR_ALERT_FATAL unless ssl
|
|
300
|
+
|
|
301
|
+
protos = ssl.context.alpn_str
|
|
302
|
+
status = SSL.SSL_select_next_proto(out, outlen, protos, protos.length, inp, inlen)
|
|
303
|
+
ssl.negotiated
|
|
304
|
+
|
|
305
|
+
case status
|
|
306
|
+
when SSL::OPENSSL_NPN_UNSUPPORTED
|
|
307
|
+
SSL::SSL_TLSEXT_ERR_ALERT_FATAL
|
|
308
|
+
when SSL::OPENSSL_NPN_NEGOTIATED
|
|
309
|
+
SSL::SSL_TLSEXT_ERR_OK
|
|
310
|
+
when SSL::OPENSSL_NPN_NO_OVERLAP
|
|
311
|
+
SSL::SSL_TLSEXT_ERR_ALERT_WARNING
|
|
312
|
+
end
|
|
313
|
+
end
|
|
314
|
+
|
|
265
315
|
def initialize(server, options = {})
|
|
266
316
|
@is_server = server
|
|
267
317
|
@ssl_ctx = SSL.SSL_CTX_new(server ? SSL.SSLv23_server_method : SSL.SSLv23_client_method)
|
|
@@ -274,16 +324,27 @@ keystr
|
|
|
274
324
|
end
|
|
275
325
|
|
|
276
326
|
SSL.SSL_CTX_set_cipher_list(@ssl_ctx, options[:ciphers] || CIPHERS)
|
|
327
|
+
@alpn_set = false
|
|
277
328
|
|
|
278
329
|
if @is_server
|
|
279
330
|
SSL.SSL_CTX_sess_set_cache_size(@ssl_ctx, 128)
|
|
280
331
|
SSL.SSL_CTX_set_session_id_context(@ssl_ctx, SESSION, 8)
|
|
332
|
+
|
|
333
|
+
if SSL::ALPN_SUPPORTED && options[:protocols]
|
|
334
|
+
@alpn_str = Context.build_alpn_string(options[:protocols])
|
|
335
|
+
SSL.SSL_CTX_set_alpn_select_cb(@ssl_ctx, ALPN_Select_CB, nil)
|
|
336
|
+
@alpn_set = true
|
|
337
|
+
end
|
|
281
338
|
else
|
|
282
339
|
set_private_key(options[:private_key])
|
|
283
340
|
set_certificate(options[:cert_chain])
|
|
284
|
-
end
|
|
285
341
|
|
|
286
|
-
|
|
342
|
+
# Check for ALPN support
|
|
343
|
+
if SSL::ALPN_SUPPORTED && options[:protocols]
|
|
344
|
+
protocols = Context.build_alpn_string(options[:protocols])
|
|
345
|
+
@alpn_set = SSL.SSL_CTX_set_alpn_protos(@ssl_ctx, protocols, protocols.length) == 0
|
|
346
|
+
end
|
|
347
|
+
end
|
|
287
348
|
end
|
|
288
349
|
|
|
289
350
|
def cleanup
|
|
@@ -295,11 +356,23 @@ keystr
|
|
|
295
356
|
|
|
296
357
|
attr_reader :is_server
|
|
297
358
|
attr_reader :ssl_ctx
|
|
359
|
+
attr_reader :alpn_set
|
|
360
|
+
attr_reader :alpn_str
|
|
298
361
|
|
|
299
362
|
|
|
300
363
|
private
|
|
301
364
|
|
|
302
365
|
|
|
366
|
+
def self.build_alpn_string(protos)
|
|
367
|
+
protocols = ''.force_encoding('ASCII-8BIT')
|
|
368
|
+
protos.each do |prot|
|
|
369
|
+
protocol = prot.to_s
|
|
370
|
+
protocols << protocol.length
|
|
371
|
+
protocols << protocol
|
|
372
|
+
end
|
|
373
|
+
protocols
|
|
374
|
+
end
|
|
375
|
+
|
|
303
376
|
def set_private_key(key)
|
|
304
377
|
err = if key.is_a? FFI::Pointer
|
|
305
378
|
SSL.SSL_CTX_use_PrivateKey(@ssl_ctx, key)
|
|
@@ -338,6 +411,8 @@ keystr
|
|
|
338
411
|
|
|
339
412
|
|
|
340
413
|
class Box
|
|
414
|
+
InstanceLookup = ThreadSafe::Cache.new
|
|
415
|
+
|
|
341
416
|
READ_BUFFER = 2048
|
|
342
417
|
|
|
343
418
|
SSL_VERIFY_PEER = 0x01
|
|
@@ -347,6 +422,7 @@ keystr
|
|
|
347
422
|
|
|
348
423
|
@handshake_completed = false
|
|
349
424
|
@handshake_signaled = false
|
|
425
|
+
@negotiated = false
|
|
350
426
|
@transport = transport
|
|
351
427
|
|
|
352
428
|
@read_buffer = FFI::MemoryPointer.new(:char, READ_BUFFER, false)
|
|
@@ -360,11 +436,9 @@ keystr
|
|
|
360
436
|
|
|
361
437
|
@write_queue = []
|
|
362
438
|
|
|
363
|
-
# TODO:: if server && options[:alpn_string]
|
|
364
|
-
# SSL_CTX_set_alpn_select_cb
|
|
365
|
-
|
|
366
439
|
InstanceLookup[@ssl.address] = self
|
|
367
440
|
|
|
441
|
+
@alpn_fallback = options[:fallback]
|
|
368
442
|
if options[:verify_peer]
|
|
369
443
|
SSL.SSL_set_verify(@ssl, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, VerifyCB)
|
|
370
444
|
end
|
|
@@ -374,6 +448,7 @@ keystr
|
|
|
374
448
|
|
|
375
449
|
|
|
376
450
|
attr_reader :is_server
|
|
451
|
+
attr_reader :context
|
|
377
452
|
attr_reader :handshake_completed
|
|
378
453
|
|
|
379
454
|
|
|
@@ -382,6 +457,22 @@ keystr
|
|
|
382
457
|
SSL.SSL_get_peer_certificate(@ssl)
|
|
383
458
|
end
|
|
384
459
|
|
|
460
|
+
def negotiated_protocol
|
|
461
|
+
return nil unless @context.alpn_set
|
|
462
|
+
|
|
463
|
+
proto = FFI::MemoryPointer.new(:pointer, 1, true)
|
|
464
|
+
len = FFI::MemoryPointer.new(:uint, 1, true)
|
|
465
|
+
SSL.SSL_get0_alpn_selected(@ssl, proto, len)
|
|
466
|
+
|
|
467
|
+
resp = proto.get_pointer(0)
|
|
468
|
+
if resp.address == 0
|
|
469
|
+
:failed
|
|
470
|
+
else
|
|
471
|
+
length = len.get_uint(0)
|
|
472
|
+
resp.read_string(length).to_sym
|
|
473
|
+
end
|
|
474
|
+
end
|
|
475
|
+
|
|
385
476
|
def start
|
|
386
477
|
return unless @ready
|
|
387
478
|
|
|
@@ -435,7 +526,30 @@ keystr
|
|
|
435
526
|
|
|
436
527
|
def signal_handshake
|
|
437
528
|
@handshake_signaled = true
|
|
438
|
-
|
|
529
|
+
|
|
530
|
+
# Check protocol support here
|
|
531
|
+
if @context.alpn_set
|
|
532
|
+
proto = negotiated_protocol
|
|
533
|
+
|
|
534
|
+
if proto == :failed
|
|
535
|
+
if @negotiated
|
|
536
|
+
# We should shutdown if this is the case
|
|
537
|
+
@transport.close_cb
|
|
538
|
+
return
|
|
539
|
+
elsif @alpn_fallback
|
|
540
|
+
# Client or Server with a client that doesn't support ALPN
|
|
541
|
+
proto = @alpn_fallback.to_sym
|
|
542
|
+
end
|
|
543
|
+
end
|
|
544
|
+
else
|
|
545
|
+
proto = nil
|
|
546
|
+
end
|
|
547
|
+
|
|
548
|
+
@transport.handshake_cb(proto)
|
|
549
|
+
end
|
|
550
|
+
|
|
551
|
+
def negotiated
|
|
552
|
+
@negotiated = true
|
|
439
553
|
end
|
|
440
554
|
|
|
441
555
|
SSL_RECEIVED_SHUTDOWN = 2
|
|
@@ -474,8 +588,6 @@ keystr
|
|
|
474
588
|
end
|
|
475
589
|
end
|
|
476
590
|
|
|
477
|
-
|
|
478
|
-
InstanceLookup = ThreadSafe::Cache.new
|
|
479
591
|
VerifyCB = FFI::Function.new(:int, [:int, :pointer]) do |preverify_ok, x509_store|
|
|
480
592
|
x509 = SSL.X509_STORE_CTX_get_current_cert(x509_store)
|
|
481
593
|
ssl = SSL.X509_STORE_CTX_get_ex_data(x509_store, SSL.SSL_get_ex_data_X509_STORE_CTX_idx)
|
data/lib/ruby-tls/version.rb
CHANGED
data/spec/alpn_spec.rb
ADDED
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
require 'ruby-tls'
|
|
2
|
+
|
|
3
|
+
if RubyTls::SSL::ALPN_SUPPORTED
|
|
4
|
+
|
|
5
|
+
describe RubyTls do
|
|
6
|
+
|
|
7
|
+
describe RubyTls::SSL::Box do
|
|
8
|
+
|
|
9
|
+
it "should be able to negotiate a protocol" do
|
|
10
|
+
@server_data = []
|
|
11
|
+
@client_data = []
|
|
12
|
+
@interleaved = []
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class Client3
|
|
16
|
+
def initialize(client_data, interleaved)
|
|
17
|
+
@client_data = client_data
|
|
18
|
+
@interleaved = interleaved
|
|
19
|
+
@ssl = RubyTls::SSL::Box.new(false, self, {
|
|
20
|
+
protocols: ["http/1.1", :h2]
|
|
21
|
+
})
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
attr_reader :ssl
|
|
25
|
+
attr_accessor :stop
|
|
26
|
+
attr_accessor :server
|
|
27
|
+
|
|
28
|
+
def close_cb
|
|
29
|
+
@client_data << 'client stopped'
|
|
30
|
+
@interleaved << 'client stopped'
|
|
31
|
+
@stop = true
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def dispatch_cb(data)
|
|
35
|
+
@client_data << data
|
|
36
|
+
@interleaved << data
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def transmit_cb(data)
|
|
40
|
+
if not @server.started
|
|
41
|
+
@server.started = true
|
|
42
|
+
@server.ssl.start
|
|
43
|
+
end
|
|
44
|
+
@server.ssl.decrypt(data) unless @stop
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def handshake_cb(protocol)
|
|
48
|
+
@client_data << protocol
|
|
49
|
+
@interleaved << 'client ready'
|
|
50
|
+
|
|
51
|
+
sending = 'client request'
|
|
52
|
+
@ssl.encrypt(sending) unless @stop
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class Server3
|
|
58
|
+
def initialize(client, server_data, interleaved)
|
|
59
|
+
@client = client
|
|
60
|
+
@server_data = server_data
|
|
61
|
+
@interleaved = interleaved
|
|
62
|
+
@ssl = RubyTls::SSL::Box.new(true, self, {
|
|
63
|
+
protocols: [:h2, "http/1.1"]
|
|
64
|
+
})
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
attr_reader :ssl
|
|
68
|
+
attr_accessor :started
|
|
69
|
+
attr_accessor :stop
|
|
70
|
+
|
|
71
|
+
def close_cb
|
|
72
|
+
@server_data << 'server stop'
|
|
73
|
+
@interleaved << 'server stop'
|
|
74
|
+
@stop = true
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def dispatch_cb(data)
|
|
78
|
+
@server_data << data
|
|
79
|
+
@interleaved << data
|
|
80
|
+
|
|
81
|
+
sending = 'server response'
|
|
82
|
+
@ssl.encrypt(sending) unless @stop
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def transmit_cb(data)
|
|
86
|
+
@client.ssl.decrypt(data) unless @stop
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def handshake_cb(protocol)
|
|
90
|
+
@server_data << protocol
|
|
91
|
+
@interleaved << 'server ready'
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@client = Client3.new(@client_data, @interleaved)
|
|
97
|
+
@server = Server3.new(@client, @server_data, @interleaved)
|
|
98
|
+
@client.server = @server
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
@client.ssl.start
|
|
102
|
+
@client.ssl.cleanup
|
|
103
|
+
@server.ssl.cleanup
|
|
104
|
+
|
|
105
|
+
expect(@server_data).to eq([:h2, 'client request'])
|
|
106
|
+
expect(@client_data).to eq([:h2, 'server response'])
|
|
107
|
+
expect(@interleaved).to eq(['server ready', 'client ready', 'client request', 'server response'])
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
it "should stop the server when a protocol cannot be negotiated" do
|
|
112
|
+
@server_data = []
|
|
113
|
+
@client_data = []
|
|
114
|
+
@interleaved = []
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class Client4
|
|
118
|
+
def initialize(client_data, interleaved)
|
|
119
|
+
@client_data = client_data
|
|
120
|
+
@interleaved = interleaved
|
|
121
|
+
@ssl = RubyTls::SSL::Box.new(false, self, {
|
|
122
|
+
protocols: ["h2c"]
|
|
123
|
+
})
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
attr_reader :ssl
|
|
127
|
+
attr_accessor :stop
|
|
128
|
+
attr_accessor :server
|
|
129
|
+
|
|
130
|
+
def close_cb
|
|
131
|
+
@client_data << 'client stopped'
|
|
132
|
+
@interleaved << 'client stopped'
|
|
133
|
+
@stop = true
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def dispatch_cb(data)
|
|
137
|
+
@client_data << data
|
|
138
|
+
@interleaved << data
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def transmit_cb(data)
|
|
142
|
+
if not @server.started
|
|
143
|
+
@server.started = true
|
|
144
|
+
@server.ssl.start
|
|
145
|
+
end
|
|
146
|
+
@server.ssl.decrypt(data) unless @stop
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def handshake_cb(protocol)
|
|
150
|
+
@client_data << 'ready'
|
|
151
|
+
@interleaved << 'client ready'
|
|
152
|
+
|
|
153
|
+
sending = 'client request'
|
|
154
|
+
@ssl.encrypt(sending) unless @stop
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
class Server4
|
|
160
|
+
def initialize(client, server_data, interleaved)
|
|
161
|
+
@client = client
|
|
162
|
+
@server_data = server_data
|
|
163
|
+
@interleaved = interleaved
|
|
164
|
+
@ssl = RubyTls::SSL::Box.new(true, self, {
|
|
165
|
+
protocols: ["http/1.1", "h2"]
|
|
166
|
+
})
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
attr_reader :ssl
|
|
170
|
+
attr_accessor :started
|
|
171
|
+
attr_accessor :stop
|
|
172
|
+
|
|
173
|
+
def close_cb
|
|
174
|
+
@server_data << 'server stop'
|
|
175
|
+
@interleaved << 'server stop'
|
|
176
|
+
@stop = true
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def dispatch_cb(data)
|
|
180
|
+
@server_data << data
|
|
181
|
+
@interleaved << data
|
|
182
|
+
|
|
183
|
+
sending = 'server response'
|
|
184
|
+
@ssl.encrypt(sending) unless @stop
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def transmit_cb(data)
|
|
188
|
+
@client.ssl.decrypt(data) unless @stop
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def handshake_cb(protocol)
|
|
192
|
+
@server_data << 'ready'
|
|
193
|
+
@interleaved << 'server ready'
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
@client = Client4.new(@client_data, @interleaved)
|
|
199
|
+
@server = Server4.new(@client, @server_data, @interleaved)
|
|
200
|
+
@client.server = @server
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
@client.ssl.start
|
|
204
|
+
@client.ssl.cleanup
|
|
205
|
+
@server.ssl.cleanup
|
|
206
|
+
|
|
207
|
+
expect(@server_data).to eq(['server stop'])
|
|
208
|
+
expect(@client_data).to eq([])
|
|
209
|
+
expect(@interleaved).to eq(['server stop'])
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
it "should not stop the client if the server doesn't support ALPN" do
|
|
214
|
+
@server_data = []
|
|
215
|
+
@client_data = []
|
|
216
|
+
@interleaved = []
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
class Client5
|
|
220
|
+
def initialize(client_data, interleaved)
|
|
221
|
+
@client_data = client_data
|
|
222
|
+
@interleaved = interleaved
|
|
223
|
+
@ssl = RubyTls::SSL::Box.new(false, self, {
|
|
224
|
+
protocols: ["h2c"]
|
|
225
|
+
})
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
attr_reader :ssl
|
|
229
|
+
attr_accessor :stop
|
|
230
|
+
attr_accessor :server
|
|
231
|
+
|
|
232
|
+
def close_cb
|
|
233
|
+
@client_data << 'client stopped'
|
|
234
|
+
@interleaved << 'client stopped'
|
|
235
|
+
@stop = true
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
def dispatch_cb(data)
|
|
239
|
+
@client_data << data
|
|
240
|
+
@interleaved << data
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
def transmit_cb(data)
|
|
244
|
+
if not @server.started
|
|
245
|
+
@server.started = true
|
|
246
|
+
@server.ssl.start
|
|
247
|
+
end
|
|
248
|
+
@server.ssl.decrypt(data) unless @stop
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
def handshake_cb(protocol)
|
|
252
|
+
@client_data << protocol
|
|
253
|
+
@interleaved << 'client ready'
|
|
254
|
+
|
|
255
|
+
sending = 'client request'
|
|
256
|
+
@ssl.encrypt(sending) unless @stop
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
class Server5
|
|
262
|
+
def initialize(client, server_data, interleaved)
|
|
263
|
+
@client = client
|
|
264
|
+
@server_data = server_data
|
|
265
|
+
@interleaved = interleaved
|
|
266
|
+
@ssl = RubyTls::SSL::Box.new(true, self)
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
attr_reader :ssl
|
|
270
|
+
attr_accessor :started
|
|
271
|
+
attr_accessor :stop
|
|
272
|
+
|
|
273
|
+
def close_cb
|
|
274
|
+
@server_data << 'server stop'
|
|
275
|
+
@interleaved << 'server stop'
|
|
276
|
+
@stop = true
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
def dispatch_cb(data)
|
|
280
|
+
@server_data << data
|
|
281
|
+
@interleaved << data
|
|
282
|
+
|
|
283
|
+
sending = 'server response'
|
|
284
|
+
@ssl.encrypt(sending) unless @stop
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
def transmit_cb(data)
|
|
288
|
+
@client.ssl.decrypt(data) unless @stop
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
def handshake_cb(protocol)
|
|
292
|
+
@server_data << protocol
|
|
293
|
+
@interleaved << 'server ready'
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
@client = Client5.new(@client_data, @interleaved)
|
|
299
|
+
@server = Server5.new(@client, @server_data, @interleaved)
|
|
300
|
+
@client.server = @server
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
@client.ssl.start
|
|
304
|
+
@client.ssl.cleanup
|
|
305
|
+
@server.ssl.cleanup
|
|
306
|
+
|
|
307
|
+
expect(@client_data).to eq([:failed, 'server response'])
|
|
308
|
+
expect(@server_data).to eq([nil, 'client request'])
|
|
309
|
+
expect(@interleaved).to eq(['server ready', 'client ready', 'client request', 'server response'])
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
it "should not stop the server if the client doesn't support ALPN" do
|
|
314
|
+
@server_data = []
|
|
315
|
+
@client_data = []
|
|
316
|
+
@interleaved = []
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
class Client6
|
|
320
|
+
def initialize(client_data, interleaved)
|
|
321
|
+
@client_data = client_data
|
|
322
|
+
@interleaved = interleaved
|
|
323
|
+
@ssl = RubyTls::SSL::Box.new(false, self)
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
attr_reader :ssl
|
|
327
|
+
attr_accessor :stop
|
|
328
|
+
attr_accessor :server
|
|
329
|
+
|
|
330
|
+
def close_cb
|
|
331
|
+
@client_data << 'client stopped'
|
|
332
|
+
@interleaved << 'client stopped'
|
|
333
|
+
@stop = true
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
def dispatch_cb(data)
|
|
337
|
+
@client_data << data
|
|
338
|
+
@interleaved << data
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
def transmit_cb(data)
|
|
342
|
+
if not @server.started
|
|
343
|
+
@server.started = true
|
|
344
|
+
@server.ssl.start
|
|
345
|
+
end
|
|
346
|
+
@server.ssl.decrypt(data) unless @stop
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
def handshake_cb(protocol)
|
|
350
|
+
@client_data << protocol
|
|
351
|
+
@interleaved << 'client ready'
|
|
352
|
+
|
|
353
|
+
sending = 'client request'
|
|
354
|
+
@ssl.encrypt(sending) unless @stop
|
|
355
|
+
end
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
class Server6
|
|
360
|
+
def initialize(client, server_data, interleaved)
|
|
361
|
+
@client = client
|
|
362
|
+
@server_data = server_data
|
|
363
|
+
@interleaved = interleaved
|
|
364
|
+
@ssl = RubyTls::SSL::Box.new(true, self, {
|
|
365
|
+
protocols: ["h2", "http/1.1"],
|
|
366
|
+
fallback: "http/1.1"
|
|
367
|
+
})
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
attr_reader :ssl
|
|
371
|
+
attr_accessor :started
|
|
372
|
+
attr_accessor :stop
|
|
373
|
+
|
|
374
|
+
def close_cb
|
|
375
|
+
@server_data << 'server stop'
|
|
376
|
+
@interleaved << 'server stop'
|
|
377
|
+
@stop = true
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
def dispatch_cb(data)
|
|
381
|
+
@server_data << data
|
|
382
|
+
@interleaved << data
|
|
383
|
+
|
|
384
|
+
sending = 'server response'
|
|
385
|
+
@ssl.encrypt(sending) unless @stop
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
def transmit_cb(data)
|
|
389
|
+
@client.ssl.decrypt(data) unless @stop
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
def handshake_cb(protocol)
|
|
393
|
+
@server_data << protocol
|
|
394
|
+
@interleaved << 'server ready'
|
|
395
|
+
end
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
@client = Client6.new(@client_data, @interleaved)
|
|
400
|
+
@server = Server6.new(@client, @server_data, @interleaved)
|
|
401
|
+
@client.server = @server
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
@client.ssl.start
|
|
405
|
+
@client.ssl.cleanup
|
|
406
|
+
@server.ssl.cleanup
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
expect(@server_data).to eq([:"http/1.1", 'client request'])
|
|
410
|
+
expect(@client_data).to eq([nil, 'server response'])
|
|
411
|
+
expect(@interleaved).to eq(['server ready', 'client ready', 'client request', 'server response'])
|
|
412
|
+
end
|
|
413
|
+
end
|
|
414
|
+
end
|
|
415
|
+
end
|
data/spec/comms_spec.rb
CHANGED
|
@@ -40,7 +40,7 @@ describe RubyTls do
|
|
|
40
40
|
@server.ssl.decrypt(data) unless @stop
|
|
41
41
|
end
|
|
42
42
|
|
|
43
|
-
def handshake_cb
|
|
43
|
+
def handshake_cb(protocol)
|
|
44
44
|
@client_data << 'ready'
|
|
45
45
|
@interleaved << 'client ready'
|
|
46
46
|
|
|
@@ -80,7 +80,7 @@ describe RubyTls do
|
|
|
80
80
|
@client.ssl.decrypt(data) unless @stop
|
|
81
81
|
end
|
|
82
82
|
|
|
83
|
-
def handshake_cb
|
|
83
|
+
def handshake_cb(protocol)
|
|
84
84
|
@server_data << 'ready'
|
|
85
85
|
@interleaved << 'server ready'
|
|
86
86
|
end
|
data/spec/verify_spec.rb
CHANGED
|
@@ -30,7 +30,7 @@ describe RubyTls do
|
|
|
30
30
|
@server.ssl.decrypt(data) unless @stop
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
-
def handshake_cb
|
|
33
|
+
def handshake_cb(protocol)
|
|
34
34
|
@client_data << 'ready'
|
|
35
35
|
end
|
|
36
36
|
end
|
|
@@ -71,7 +71,7 @@ describe RubyTls do
|
|
|
71
71
|
@client.ssl.decrypt(data) unless @stop
|
|
72
72
|
end
|
|
73
73
|
|
|
74
|
-
def handshake_cb
|
|
74
|
+
def handshake_cb(protocol)
|
|
75
75
|
@server_data << 'ready'
|
|
76
76
|
end
|
|
77
77
|
|
|
@@ -126,7 +126,7 @@ describe RubyTls do
|
|
|
126
126
|
@client.ssl.decrypt(data) unless @stop
|
|
127
127
|
end
|
|
128
128
|
|
|
129
|
-
def handshake_cb
|
|
129
|
+
def handshake_cb(protocol)
|
|
130
130
|
@server_data << 'ready'
|
|
131
131
|
end
|
|
132
132
|
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ruby-tls
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.0
|
|
4
|
+
version: 2.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Stephen von Takach
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2015-03-
|
|
11
|
+
date: 2015-03-24 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: ffi-compiler
|
|
@@ -80,6 +80,7 @@ files:
|
|
|
80
80
|
- lib/ruby-tls/ssl.rb
|
|
81
81
|
- lib/ruby-tls/version.rb
|
|
82
82
|
- ruby-tls.gemspec
|
|
83
|
+
- spec/alpn_spec.rb
|
|
83
84
|
- spec/client.crt
|
|
84
85
|
- spec/client.key
|
|
85
86
|
- spec/comms_spec.rb
|
|
@@ -109,6 +110,7 @@ signing_key:
|
|
|
109
110
|
specification_version: 4
|
|
110
111
|
summary: Abstract TLS for Ruby
|
|
111
112
|
test_files:
|
|
113
|
+
- spec/alpn_spec.rb
|
|
112
114
|
- spec/client.crt
|
|
113
115
|
- spec/client.key
|
|
114
116
|
- spec/comms_spec.rb
|