tttls1.3 0.2.4 → 0.2.5
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/.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
|