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 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