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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 26abf6610ea39c5b35e874bab7e1226afee77c3209dd2ddde497d731bb6fc64b
4
- data.tar.gz: 13a8a522e126dc29993f6bfef96a59556f043910541decf7224c15db84cfb28d
3
+ metadata.gz: 99aff91ae6a3b3c49b7492320eca02c45372e58e8cc6fcf636363c767e18870b
4
+ data.tar.gz: 2c2327dbe62382897b92c2a89b3f74a45735d6ec40ac08f5ca62dc4f07ec8df8
5
5
  SHA512:
6
- metadata.gz: 879a7c9be73deec93e4eff0ee0a0339c2464ad6c4139d5c8da4ad8da06cf8fcdf9bbd6ecef6baeda2f35483d88c91b61deaed17e7ca7a2d25cc105f339d242ce
7
- data.tar.gz: 44ad60dff635a9ac7a980605ab736f52b67b94d806fa186e86ff022ff82bc712abf9ce215714052787188b35617e1f527534115d6fbb2cc880d5b32dce9df591
6
+ metadata.gz: c786c4679ca31d9ac60c1d9954cd2fd4e867cf55126a341409bc1aae294df984534861598d5b22643d2d5ab9acefa18cb85b63d7e5cafb90f04e6b41914bf417
7
+ data.tar.gz: ec601d3640d8518b0a0d6ae35a1453a9444995db944bfaa48e12c627ca58bc01d31e0ffb0925356d686cd97b7665f556152d3f858a245b501eb981a17ffb8dca
data/.travis.yml CHANGED
@@ -6,6 +6,11 @@ rvm:
6
6
  - 2.6.1
7
7
  - 2.6.2
8
8
  - 2.6.3
9
+ - ruby-head
10
+
11
+ matrix:
12
+ allow_failures:
13
+ - rvm: ruby-head
9
14
 
10
15
  before_install:
11
16
  - gem install bundler -v 2.0.1
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 an objective.
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(socket.accept)
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
- ## Features
79
+ ## Settings
54
80
 
55
81
  ### Client
56
82
 
57
- tttls1.3 provides client API with the following features:
58
-
59
- * Simple 1-RTT Handshake
60
- * HelloRetryRequest
61
- * Resumed 0-RTT Handshake (with PSK from ticket)
62
-
63
- **NOT supports** certificate with OID RSASSA-PSS, X25519, X448, FFDHE, AES-CCM, Client Authentication, Post-Handshake Authentication, KeyUpdate, external PSKs.
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 provides server API with the following features:
68
-
69
- * Simple 1-RTT Handshake
70
- * HelloRetryRequest
71
-
72
- **NOT supports** certificate with OID RSASSA-PSS, X25519, X448, FFDHE, AES-CCM, Client Authentication, Post-Handshake Authentication, KeyUpdate, external PSKs.
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: TTTLS13::Client'
133
- RSpec::Core::RakeTask.new(:interop_client) do |t|
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
- desc 'interoperability test: TTTLS13::Server'
138
- RSpec::Core::RakeTask.new(:interop_server) do |t|
139
- t.pattern = Dir.glob('interop/server_spec.rb')
140
- end
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 between openssl'
143
- task interop: %i[interop_client interop_server]
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]
@@ -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|
@@ -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|
@@ -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 # compatibility mode
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
- terminate(:illegal_parameter) unless ct.appearable_extensions?
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
- terminate(:illegal_parameter) unless ct.appearable_extensions?
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 messages_type == ContentType::APPLICATION_DATA
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
- binary = ''
54
- fragments.each do |s|
55
- binary += @type + @legacy_record_version
56
- binary += @cipher.encrypt(s, messages_type).prefix_uint16_length
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:
@@ -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 # compatibility mode
194
+ send_ccs if @settings[:compatibility_mode]
194
195
 
195
196
  # generate shared secret
196
197
  ke = ch.extensions[Message::ExtensionType::KEY_SHARE]
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TTTLS13
4
- VERSION = '0.2.4'
4
+ VERSION = '0.2.5'
5
5
  end
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
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-12 00:00:00.000000000 Z
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.1
194
+ rubygems_version: 3.0.3
195
195
  signing_key:
196
196
  specification_version: 4
197
197
  summary: TLS 1.3 implementation in Ruby