tttls1.3 0.2.4 → 0.2.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +5 -0
- data/README.md +62 -17
- data/Rakefile +12 -10
- data/interop/client_spec.rb +7 -0
- data/interop/server_spec.rb +7 -0
- data/lib/tttls1.3/client.rb +18 -21
- data/lib/tttls1.3/message/record.rb +6 -9
- data/lib/tttls1.3/server.rb +2 -1
- data/lib/tttls1.3/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 99aff91ae6a3b3c49b7492320eca02c45372e58e8cc6fcf636363c767e18870b
|
4
|
+
data.tar.gz: 2c2327dbe62382897b92c2a89b3f74a45735d6ec40ac08f5ca62dc4f07ec8df8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c786c4679ca31d9ac60c1d9954cd2fd4e867cf55126a341409bc1aae294df984534861598d5b22643d2d5ab9acefa18cb85b63d7e5cafb90f04e6b41914bf417
|
7
|
+
data.tar.gz: ec601d3640d8518b0a0d6ae35a1453a9444995db944bfaa48e12c627ca58bc01d31e0ffb0925356d686cd97b7665f556152d3f858a245b501eb981a17ffb8dca
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -8,10 +8,32 @@ tttls1.3 is Ruby implementation of [TLS 1.3](https://tools.ietf.org/html/rfc8446
|
|
8
8
|
tttls1.3 uses [openssl](https://github.com/ruby/openssl) as backend for crypto and X.509 operations.
|
9
9
|
|
10
10
|
It is the purpose of this project to understand the TLS 1.3 protocol and implement the TLS 1.3 protocol using Ruby.
|
11
|
-
Backward compatibility and performance are not
|
11
|
+
Backward compatibility and performance are not objective.
|
12
12
|
This gem should not be used for production software.
|
13
13
|
|
14
14
|
|
15
|
+
## Features
|
16
|
+
|
17
|
+
### Client
|
18
|
+
|
19
|
+
tttls1.3 provides client API with the following features:
|
20
|
+
|
21
|
+
* Simple 1-RTT Handshake
|
22
|
+
* HelloRetryRequest
|
23
|
+
* Resumed 0-RTT Handshake (with PSK from NST)
|
24
|
+
|
25
|
+
**NOT supports** certificate with OID RSASSA-PSS, X25519, X448, FFDHE, AES-CCM, Client Authentication, Post-Handshake Authentication, KeyUpdate, external PSKs.
|
26
|
+
|
27
|
+
### Server
|
28
|
+
|
29
|
+
tttls1.3 provides server API with the following features:
|
30
|
+
|
31
|
+
* Simple 1-RTT Handshake
|
32
|
+
* HelloRetryRequest
|
33
|
+
|
34
|
+
**NOT supports** certificate with OID RSASSA-PSS, X25519, X448, FFDHE, AES-CCM, Client Authentication, Post-Handshake Authentication, KeyUpdate, external PSKs.
|
35
|
+
|
36
|
+
|
15
37
|
## Getting started
|
16
38
|
|
17
39
|
tttls1.3 gem is available at [rubygems.org](https://rubygems.org/gems/tttls1.3). You can install with:
|
@@ -20,7 +42,7 @@ tttls1.3 gem is available at [rubygems.org](https://rubygems.org/gems/tttls1.3).
|
|
20
42
|
$ gem install tttls1.3
|
21
43
|
```
|
22
44
|
|
23
|
-
This implementation provides only minimal API, so your code is responsible for application layer.
|
45
|
+
This implementation provides only minimal API, so your code is responsible for the application layer.
|
24
46
|
Roughly, this works as follows:
|
25
47
|
|
26
48
|
```ruby
|
@@ -39,7 +61,11 @@ client.close
|
|
39
61
|
require 'tttls1.3'
|
40
62
|
|
41
63
|
socket = YourTransport.new
|
42
|
-
server = TTTLS13::Server.new(
|
64
|
+
server = TTTLS13::Server.new(
|
65
|
+
socket.accept,
|
66
|
+
crt_file: '/path/to/crt/file',
|
67
|
+
key_file: '/path/to/key/file'
|
68
|
+
)
|
43
69
|
server.accept
|
44
70
|
|
45
71
|
server.read
|
@@ -50,26 +76,45 @@ server.close
|
|
50
76
|
HTTPS examples are [here](https://github.com/thekuwayama/tttls1.3/tree/master/example).
|
51
77
|
|
52
78
|
|
53
|
-
##
|
79
|
+
## Settings
|
54
80
|
|
55
81
|
### Client
|
56
82
|
|
57
|
-
tttls1.3
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
83
|
+
tttls1.3 client is configurable using keyword arguments.
|
84
|
+
|
85
|
+
| key | type | default value | description |
|
86
|
+
|-----|------|---------------|-------------|
|
87
|
+
| `:ca_file` | String | nil | Path to the additional root CA certificate files. If not needed to add, set nil. |
|
88
|
+
| `:cipher_suites` | Array of TTTLS13::CipherSuite constant | `TLS_AES_256_GCM_SHA384`, `TLS_CHACHA20_POLY1305_SHA256`, `TLS_AES_128_GCM_SHA256` | List of cipher suites offered in ClientHello. |
|
89
|
+
| `:signature_algorithms` | Array of TTTLS13::SignatureScheme constant | `ECDSA_SECP256R1_SHA256`, `ECDSA_SECP384R1_SHA384`, `ECDSA_SECP521R1_SHA512`, `RSA_PSS_RSAE_SHA256`, `RSA_PSS_RSAE_SHA384`, `RSA_PSS_RSAE_SHA512`, `RSA_PKCS1_SHA256`, `RSA_PKCS1_SHA384`, `RSA_PKCS1_SHA512` | List of signature algorithms offered in ClientHello extensions. |
|
90
|
+
| `:signature_algorithms_cert` | Array of TTTLS13::SignatureScheme constant | nil | List of certificate signature algorithms offered in ClientHello extensions. You can set this to signal the difference between the signature algorithm and `:signature_algorithms`. |
|
91
|
+
| `:supported_groups` | Array of TTTLS13::NamedGroup constant | `SECP256R1`, `SECP384R1`, `SECP521R1` | List of named groups offered in ClientHello extensions. |
|
92
|
+
| `:key_share_groups` | Array of TTTLS13::NamedGroup constant | nil | List of named groups offered in KeyShareClientHello. In default, KeyShareClientHello has only a KeyShareEntry of most preferred named group in `:supported_groups`. You can set this to send KeyShareClientHello that has multiple KeyShareEntry. |
|
93
|
+
| `:alpn` | Array of String | nil | List of application protocols offered in ClientHello extensions. If not needed to be present, set nil. |
|
94
|
+
| `:process_new_session_ticket` | Proc | nil | Proc that processes received NewSessionTicket. Its 3 arguments are TTTLS13::Message::NewSessionTicket, resumption master secret and cipher suite. If not needed to process NewSessionTicket, set nil. |
|
95
|
+
| `:ticket` | String | nil | The ticket for PSK. |
|
96
|
+
| `:resumption_master_secret` | String | nil | The resumption master secret. |
|
97
|
+
| `:psk_cipher_suite` | TTTLS13::CipherSuite constant | nil | The cipher suite for PSK. |
|
98
|
+
| `:ticket_nonce` | String | nil | The ticket\_nonce for PSK. |
|
99
|
+
| `:ticket_age_add` | String | nil | The ticket\_age\_add for PSK. |
|
100
|
+
| `:ticket_timestamp` | Integer | nil | The ticket\_timestamp for PSK. |
|
101
|
+
| `:compatibility_mode` | Boolean | true | If needed to send ChangeCipherSpec, set true. |
|
102
|
+
| `:loglevel` | Logger constant | Logger::WARN | If needed to print verbose, set Logger::DEBUG. |
|
64
103
|
|
65
104
|
### Server
|
66
105
|
|
67
|
-
tttls1.3
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
106
|
+
tttls1.3 server is configurable using keyword arguments.
|
107
|
+
|
108
|
+
| key | type | default value | description |
|
109
|
+
|-----|------|---------------|-------------|
|
110
|
+
| `:crt_file` | String | nil | Path to the certificate file. This is a required setting. |
|
111
|
+
| `:key_file` | String | nil | Path to the private key file. This is a required setting. |
|
112
|
+
| `:cipher_suites` | Array of TTTLS13::CipherSuite constant | `TLS_AES_256_GCM_SHA384`, `TLS_CHACHA20_POLY1305_SHA256`, `TLS_AES_128_GCM_SHA256` | List of supported cipher suites. |
|
113
|
+
| `:signature_algorithms` | Array of TTTLS13::SignatureScheme constant | `ECDSA_SECP256R1_SHA256`, `ECDSA_SECP384R1_SHA384`, `ECDSA_SECP521R1_SHA512`, `RSA_PSS_RSAE_SHA256`, `RSA_PSS_RSAE_SHA384`, `RSA_PSS_RSAE_SHA512`, `RSA_PKCS1_SHA256`, `RSA_PKCS1_SHA384`, `RSA_PKCS1_SHA512` | List of supported signature algorithms. |
|
114
|
+
| `:supported_groups` | Array of TTTLS13::NamedGroup constant | `SECP256R1`, `SECP384R1`, `SECP521R1` | List of supported named groups. |
|
115
|
+
| `:alpn` | Array of String | nil | List of supported application protocols. If not needed to check this extension, set nil. |
|
116
|
+
| `:compatibility_mode` | Boolean | true | If needed to send ChangeCipherSpec, set true. |
|
117
|
+
| `:loglevel` | Logger constant | Logger::WARN | If needed to print verbose, set Logger::DEBUG. |
|
73
118
|
|
74
119
|
|
75
120
|
## License
|
data/Rakefile
CHANGED
@@ -129,17 +129,19 @@ end
|
|
129
129
|
RuboCop::RakeTask.new
|
130
130
|
RSpec::Core::RakeTask.new(:spec)
|
131
131
|
|
132
|
-
desc 'interoperability test
|
133
|
-
|
134
|
-
t.pattern = Dir.glob('interop/client_spec.rb')
|
135
|
-
end
|
132
|
+
desc 'interoperability test between openssl'
|
133
|
+
task interop: %i[interop:client interop:server]
|
136
134
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
135
|
+
namespace :interop do
|
136
|
+
desc 'interoperability test: TTTLS13::Client'
|
137
|
+
RSpec::Core::RakeTask.new(:client) do |t|
|
138
|
+
t.pattern = Dir.glob('interop/client_spec.rb')
|
139
|
+
end
|
141
140
|
|
142
|
-
desc 'interoperability test
|
143
|
-
|
141
|
+
desc 'interoperability test: TTTLS13::Server'
|
142
|
+
RSpec::Core::RakeTask.new(:server) do |t|
|
143
|
+
t.pattern = Dir.glob('interop/server_spec.rb')
|
144
|
+
end
|
145
|
+
end
|
144
146
|
|
145
147
|
task default: %i[rubocop spec]
|
data/interop/client_spec.rb
CHANGED
@@ -155,6 +155,13 @@ RSpec.describe Client do
|
|
155
155
|
'rsa_rsa.crt',
|
156
156
|
'rsa_rsa.key',
|
157
157
|
alpn: ['http/1.1']
|
158
|
+
],
|
159
|
+
[
|
160
|
+
true,
|
161
|
+
'',
|
162
|
+
'rsa_rsa.crt',
|
163
|
+
'rsa_rsa.key',
|
164
|
+
compatibility_mode: false
|
158
165
|
]
|
159
166
|
# rubocop: enable Metrics/LineLength
|
160
167
|
].each do |normal, opt, crt, key, settings|
|
data/interop/server_spec.rb
CHANGED
@@ -164,6 +164,13 @@ RSpec.describe Server do
|
|
164
164
|
FIXTURES_DIR + '/rsa_rsa.crt',
|
165
165
|
FIXTURES_DIR + '/rsa_rsa.key',
|
166
166
|
alpn: ['http/1.1']
|
167
|
+
],
|
168
|
+
[
|
169
|
+
true,
|
170
|
+
'-groups P-256:P-384:P-521',
|
171
|
+
FIXTURES_DIR + '/rsa_rsa.crt',
|
172
|
+
FIXTURES_DIR + '/rsa_rsa.key',
|
173
|
+
compatibility_mode: false
|
167
174
|
]
|
168
175
|
# rubocop: enable Metrics/LineLength
|
169
176
|
].each do |normal, opt, crt, key, settings|
|
data/lib/tttls1.3/client.rb
CHANGED
@@ -58,6 +58,7 @@ module TTTLS13
|
|
58
58
|
ticket_nonce: nil,
|
59
59
|
ticket_age_add: nil,
|
60
60
|
ticket_timestamp: nil,
|
61
|
+
compatibility_mode: true,
|
61
62
|
loglevel: Logger::WARN
|
62
63
|
}.freeze
|
63
64
|
private_constant :DEFAULT_CLIENT_SETTINGS
|
@@ -152,7 +153,7 @@ module TTTLS13
|
|
152
153
|
binder_key = (use_psk? ? key_schedule.binder_key_res : nil)
|
153
154
|
transcript[CH] = send_client_hello(extensions, binder_key)
|
154
155
|
|
155
|
-
send_ccs
|
156
|
+
send_ccs if @settings[:compatibility_mode]
|
156
157
|
if use_early_data?
|
157
158
|
e_wcipher = gen_cipher(
|
158
159
|
@settings[:psk_cipher_suite],
|
@@ -293,16 +294,7 @@ module TTTLS13
|
|
293
294
|
message = recv_message(receivable_ccs: true, cipher: hs_rcipher)
|
294
295
|
if message.msg_type == Message::HandshakeType::CERTIFICATE
|
295
296
|
ct = transcript[CT] = message
|
296
|
-
|
297
|
-
|
298
|
-
ch = transcript[CH]
|
299
|
-
terminate(:unsupported_extension) \
|
300
|
-
unless ct.certificate_list.map(&:extensions)
|
301
|
-
.all? { |e| (e.keys - ch.extensions.keys).empty? }
|
302
|
-
|
303
|
-
terminate(:certificate_unknown) \
|
304
|
-
unless trusted_certificate?(ct.certificate_list,
|
305
|
-
@settings[:ca_file], @hostname)
|
297
|
+
terminate_invalid_certificate(ct, transcript[CH])
|
306
298
|
|
307
299
|
@state = ClientState::WAIT_CV
|
308
300
|
elsif message.msg_type == Message::HandshakeType::CERTIFICATE_REQUEST
|
@@ -316,16 +308,7 @@ module TTTLS13
|
|
316
308
|
logger.debug('ClientState::WAIT_EE')
|
317
309
|
|
318
310
|
ct = transcript[CT] = recv_certificate(hs_rcipher)
|
319
|
-
|
320
|
-
|
321
|
-
ch = transcript[CH]
|
322
|
-
terminate(:unsupported_extension) \
|
323
|
-
unless ct.certificate_list.map(&:extensions)
|
324
|
-
.all? { |e| (e.keys - ch.extensions.keys).empty? }
|
325
|
-
|
326
|
-
terminate(:certificate_unknown) \
|
327
|
-
unless trusted_certificate?(ct.certificate_list,
|
328
|
-
@settings[:ca_file], @hostname)
|
311
|
+
terminate_invalid_certificate(ct, transcript[CH])
|
329
312
|
|
330
313
|
@state = ClientState::WAIT_CV
|
331
314
|
when ClientState::WAIT_CV
|
@@ -749,6 +732,20 @@ module TTTLS13
|
|
749
732
|
eoed
|
750
733
|
end
|
751
734
|
|
735
|
+
# @param ct [TTTLS13::Message::Certificate]
|
736
|
+
# @param ch [TTTLS13::Message::ClientHello]
|
737
|
+
def terminate_invalid_certificate(ct, ch)
|
738
|
+
terminate(:illegal_parameter) unless ct.appearable_extensions?
|
739
|
+
|
740
|
+
terminate(:unsupported_extension) \
|
741
|
+
unless ct.certificate_list.map(&:extensions)
|
742
|
+
.all? { |e| (e.keys - ch.extensions.keys).empty? }
|
743
|
+
|
744
|
+
terminate(:certificate_unknown) \
|
745
|
+
unless trusted_certificate?(ct.certificate_list,
|
746
|
+
@settings[:ca_file], @hostname)
|
747
|
+
end
|
748
|
+
|
752
749
|
# @param ct [TTTLS13::Message::Certificate]
|
753
750
|
# @param cv [TTTLS13::Message::CertificateVerify]
|
754
751
|
# @param hash [String]
|
@@ -42,21 +42,18 @@ module TTTLS13
|
|
42
42
|
# @return [String]
|
43
43
|
def serialize(record_size_limit = DEFAULT_RECORD_SIZE_LIMIT)
|
44
44
|
tlsplaintext = @messages.map(&:serialize).join + @surplus_binary
|
45
|
-
if
|
46
|
-
max = cipher.tlsplaintext_length_limit(record_size_limit)
|
45
|
+
if @cipher.is_a?(Cryptograph::Aead)
|
46
|
+
max = @cipher.tlsplaintext_length_limit(record_size_limit)
|
47
47
|
fragments = tlsplaintext.scan(/.{1,#{max}}/m)
|
48
48
|
else
|
49
49
|
fragments = [tlsplaintext]
|
50
50
|
end
|
51
51
|
fragments = [''] if fragments.empty?
|
52
52
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
end
|
58
|
-
|
59
|
-
binary
|
53
|
+
fragments.map do |s|
|
54
|
+
@type + @legacy_record_version \
|
55
|
+
+ @cipher.encrypt(s, messages_type).prefix_uint16_length
|
56
|
+
end.join
|
60
57
|
end
|
61
58
|
|
62
59
|
# NOTE:
|
data/lib/tttls1.3/server.rb
CHANGED
@@ -51,6 +51,7 @@ module TTTLS13
|
|
51
51
|
signature_algorithms: DEFAULT_SP_SIGNATURE_ALGORITHMS,
|
52
52
|
supported_groups: DEFAULT_SP_NAMED_GROUP_LIST,
|
53
53
|
alpn: nil,
|
54
|
+
compatibility_mode: true,
|
54
55
|
loglevel: Logger::WARN
|
55
56
|
}.freeze
|
56
57
|
private_constant :DEFAULT_SERVER_SETTINGS
|
@@ -190,7 +191,7 @@ module TTTLS13
|
|
190
191
|
extensions, priv_key = gen_sh_extensions(@named_group)
|
191
192
|
transcript[SH] = send_server_hello(extensions, @cipher_suite,
|
192
193
|
ch.legacy_session_id)
|
193
|
-
send_ccs
|
194
|
+
send_ccs if @settings[:compatibility_mode]
|
194
195
|
|
195
196
|
# generate shared secret
|
196
197
|
ke = ch.extensions[Message::ExtensionType::KEY_SHARE]
|
data/lib/tttls1.3/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tttls1.3
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- thekuwayama
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-06-
|
11
|
+
date: 2019-06-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -191,7 +191,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
191
191
|
- !ruby/object:Gem::Version
|
192
192
|
version: '0'
|
193
193
|
requirements: []
|
194
|
-
rubygems_version: 3.0.
|
194
|
+
rubygems_version: 3.0.3
|
195
195
|
signing_key:
|
196
196
|
specification_version: 4
|
197
197
|
summary: TLS 1.3 implementation in Ruby
|