tttls1.3 0.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 +7 -0
- data/.gitignore +16 -0
- data/.rspec +3 -0
- data/.rubocop.yml +16 -0
- data/.travis.yml +8 -0
- data/Gemfile +13 -0
- data/LICENSE.txt +21 -0
- data/README.md +52 -0
- data/Rakefile +133 -0
- data/example/helper.rb +17 -0
- data/example/https_client.rb +32 -0
- data/example/https_client_using_0rtt.rb +64 -0
- data/example/https_client_using_hrr.rb +35 -0
- data/example/https_client_using_ticket.rb +56 -0
- data/lib/tttls1.3/cipher_suites.rb +102 -0
- data/lib/tttls1.3/client.rb +745 -0
- data/lib/tttls1.3/connection.rb +380 -0
- data/lib/tttls1.3/cryptograph/aead.rb +118 -0
- data/lib/tttls1.3/cryptograph/passer.rb +22 -0
- data/lib/tttls1.3/cryptograph.rb +3 -0
- data/lib/tttls1.3/error.rb +22 -0
- data/lib/tttls1.3/key_schedule.rb +242 -0
- data/lib/tttls1.3/message/alert.rb +86 -0
- data/lib/tttls1.3/message/application_data.rb +27 -0
- data/lib/tttls1.3/message/certificate.rb +121 -0
- data/lib/tttls1.3/message/certificate_verify.rb +59 -0
- data/lib/tttls1.3/message/change_cipher_spec.rb +26 -0
- data/lib/tttls1.3/message/client_hello.rb +100 -0
- data/lib/tttls1.3/message/encrypted_extensions.rb +65 -0
- data/lib/tttls1.3/message/end_of_early_data.rb +29 -0
- data/lib/tttls1.3/message/extension/alpn.rb +70 -0
- data/lib/tttls1.3/message/extension/cookie.rb +47 -0
- data/lib/tttls1.3/message/extension/early_data_indication.rb +58 -0
- data/lib/tttls1.3/message/extension/key_share.rb +236 -0
- data/lib/tttls1.3/message/extension/pre_shared_key.rb +205 -0
- data/lib/tttls1.3/message/extension/psk_key_exchange_modes.rb +54 -0
- data/lib/tttls1.3/message/extension/record_size_limit.rb +46 -0
- data/lib/tttls1.3/message/extension/server_name.rb +91 -0
- data/lib/tttls1.3/message/extension/signature_algorithms.rb +69 -0
- data/lib/tttls1.3/message/extension/signature_algorithms_cert.rb +25 -0
- data/lib/tttls1.3/message/extension/status_request.rb +106 -0
- data/lib/tttls1.3/message/extension/supported_groups.rb +145 -0
- data/lib/tttls1.3/message/extension/supported_versions.rb +98 -0
- data/lib/tttls1.3/message/extension/unknown_extension.rb +38 -0
- data/lib/tttls1.3/message/extensions.rb +173 -0
- data/lib/tttls1.3/message/finished.rb +44 -0
- data/lib/tttls1.3/message/new_session_ticket.rb +89 -0
- data/lib/tttls1.3/message/record.rb +232 -0
- data/lib/tttls1.3/message/server_hello.rb +116 -0
- data/lib/tttls1.3/message.rb +48 -0
- data/lib/tttls1.3/sequence_number.rb +31 -0
- data/lib/tttls1.3/signature_scheme.rb +31 -0
- data/lib/tttls1.3/transcript.rb +69 -0
- data/lib/tttls1.3/utils.rb +91 -0
- data/lib/tttls1.3/version.rb +5 -0
- data/lib/tttls1.3.rb +16 -0
- data/spec/aead_spec.rb +95 -0
- data/spec/alert_spec.rb +54 -0
- data/spec/alpn_spec.rb +55 -0
- data/spec/application_data_spec.rb +26 -0
- data/spec/certificate_spec.rb +55 -0
- data/spec/certificate_verify_spec.rb +51 -0
- data/spec/change_cipher_spec_spec.rb +26 -0
- data/spec/cipher_suites_spec.rb +39 -0
- data/spec/client_hello_spec.rb +83 -0
- data/spec/client_spec.rb +319 -0
- data/spec/connection_spec.rb +114 -0
- data/spec/cookie_spec.rb +98 -0
- data/spec/early_data_indication_spec.rb +64 -0
- data/spec/encrypted_extensions_spec.rb +94 -0
- data/spec/error_spec.rb +18 -0
- data/spec/extensions_spec.rb +170 -0
- data/spec/finished_spec.rb +55 -0
- data/spec/key_schedule_spec.rb +198 -0
- data/spec/key_share_spec.rb +199 -0
- data/spec/new_session_ticket_spec.rb +80 -0
- data/spec/pre_shared_key_spec.rb +167 -0
- data/spec/psk_key_exchange_modes_spec.rb +45 -0
- data/spec/record_size_limit_spec.rb +61 -0
- data/spec/record_spec.rb +105 -0
- data/spec/server_hello_spec.rb +101 -0
- data/spec/server_name_spec.rb +110 -0
- data/spec/signature_algorithms_cert_spec.rb +73 -0
- data/spec/signature_algorithms_spec.rb +100 -0
- data/spec/spec_helper.rb +872 -0
- data/spec/status_request_spec.rb +73 -0
- data/spec/supported_groups_spec.rb +79 -0
- data/spec/supported_versions_spec.rb +136 -0
- data/spec/transcript_spec.rb +69 -0
- data/spec/unknown_extension_spec.rb +90 -0
- data/spec/utils_spec.rb +215 -0
- data/tttls1.3.gemspec +25 -0
- metadata +197 -0
@@ -0,0 +1,80 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'spec_helper'
|
5
|
+
using Refinements
|
6
|
+
|
7
|
+
RSpec.describe NewSessionTicket do
|
8
|
+
context 'new_session_ticket' do
|
9
|
+
let(:ticket_lifetime) do
|
10
|
+
7200 # two_hours
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:ticket_age_add) do
|
14
|
+
OpenSSL::Random.random_bytes(4)
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:ticket_nonce) do
|
18
|
+
"\x00" * 255
|
19
|
+
end
|
20
|
+
|
21
|
+
let(:ticket) do
|
22
|
+
OpenSSL::Random.random_bytes(255)
|
23
|
+
end
|
24
|
+
|
25
|
+
let(:message) do
|
26
|
+
NewSessionTicket.new(ticket_lifetime: ticket_lifetime,
|
27
|
+
ticket_age_add: ticket_age_add,
|
28
|
+
ticket_nonce: ticket_nonce,
|
29
|
+
ticket: ticket)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should be generated' do
|
33
|
+
expect(message.msg_type).to eq HandshakeType::NEW_SESSION_TICKET
|
34
|
+
expect(message.ticket_lifetime).to eq ticket_lifetime
|
35
|
+
expect(message.ticket_age_add).to eq ticket_age_add
|
36
|
+
expect(message.ticket_nonce).to eq ticket_nonce
|
37
|
+
expect(message.ticket).to eq ticket
|
38
|
+
expect(message.extensions).to be_empty
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should be serialized' do
|
42
|
+
expect(message.serialize).to eq HandshakeType::NEW_SESSION_TICKET \
|
43
|
+
+ 523.to_uint24 \
|
44
|
+
+ ticket_lifetime.to_uint32 \
|
45
|
+
+ ticket_age_add \
|
46
|
+
+ ticket_nonce.prefix_uint8_length \
|
47
|
+
+ ticket.prefix_uint16_length \
|
48
|
+
+ Extensions.new.serialize
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'new_session_ticket, invalid ticket_age_add,' do
|
53
|
+
let(:message) do
|
54
|
+
NewSessionTicket.new(ticket_lifetime: 60 * 60 * 2, # 2 hours
|
55
|
+
ticket_age_add: OpenSSL::Random.random_bytes(32),
|
56
|
+
ticket_nonce: "\x00" * 255,
|
57
|
+
ticket: OpenSSL::Random.random_bytes(255))
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'should not be generated' do
|
61
|
+
expect { message }.to raise_error(ErrorAlerts)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'valid new_session_ticket binary' do
|
66
|
+
let(:message) do
|
67
|
+
NewSessionTicket.deserialize(TESTBINARY_NEW_SESSION_TICKET)
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'should generate object' do
|
71
|
+
expect(message.msg_type).to eq HandshakeType::NEW_SESSION_TICKET
|
72
|
+
expect(message.ticket_lifetime).to eq 30
|
73
|
+
expect(message.ticket_nonce).to eq "\x00\x00"
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'should generate serializable object' do
|
77
|
+
expect(message.serialize).to eq TESTBINARY_NEW_SESSION_TICKET
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'spec_helper'
|
5
|
+
using Refinements
|
6
|
+
|
7
|
+
RSpec.describe PreSharedKey do
|
8
|
+
context 'valid pre_shared_key of ClientHello' do
|
9
|
+
let(:identity) do
|
10
|
+
OpenSSL::Random.random_bytes(32)
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:obfuscated_ticket_age) do
|
14
|
+
OpenSSL::BN.rand_range(1 << 32).to_i
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:binders) do
|
18
|
+
[
|
19
|
+
OpenSSL::Random.random_bytes(32)
|
20
|
+
]
|
21
|
+
end
|
22
|
+
|
23
|
+
let(:identities) do
|
24
|
+
[
|
25
|
+
PskIdentity.new(
|
26
|
+
identity: identity,
|
27
|
+
obfuscated_ticket_age: obfuscated_ticket_age
|
28
|
+
)
|
29
|
+
]
|
30
|
+
end
|
31
|
+
|
32
|
+
let(:offered_psks) do
|
33
|
+
OfferedPsks.new(
|
34
|
+
identities: identities,
|
35
|
+
binders: binders
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
39
|
+
let(:extension) do
|
40
|
+
PreSharedKey.new(msg_type: HandshakeType::CLIENT_HELLO,
|
41
|
+
offered_psks: offered_psks)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should be generated' do
|
45
|
+
expect(extension.msg_type).to eq HandshakeType::CLIENT_HELLO
|
46
|
+
expect(extension.extension_type).to eq ExtensionType::PRE_SHARED_KEY
|
47
|
+
expect(extension.offered_psks).to eq offered_psks
|
48
|
+
expect(extension.selected_identity).to be_nil
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'should be serialized' do
|
52
|
+
expect(extension.serialize).to eq ExtensionType::PRE_SHARED_KEY \
|
53
|
+
+ 75.to_uint16 \
|
54
|
+
+ 38.to_uint16 \
|
55
|
+
+ 32.to_uint16 \
|
56
|
+
+ identity \
|
57
|
+
+ obfuscated_ticket_age.to_uint32 \
|
58
|
+
+ 33.to_uint16 \
|
59
|
+
+ "\x20" \
|
60
|
+
+ binders.join
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context 'valid pre_shared_key, ClientHello,' do
|
65
|
+
let(:identity_1) do
|
66
|
+
OpenSSL::Random.random_bytes(32)
|
67
|
+
end
|
68
|
+
let(:identity_2) do
|
69
|
+
OpenSSL::Random.random_bytes(32)
|
70
|
+
end
|
71
|
+
|
72
|
+
let(:obfuscated_ticket_age_1) do
|
73
|
+
OpenSSL::BN.rand_range(1 << 32).to_i
|
74
|
+
end
|
75
|
+
let(:obfuscated_ticket_age_2) do
|
76
|
+
OpenSSL::BN.rand_range(1 << 32).to_i
|
77
|
+
end
|
78
|
+
|
79
|
+
let(:binders) do
|
80
|
+
[
|
81
|
+
OpenSSL::Random.random_bytes(32),
|
82
|
+
OpenSSL::Random.random_bytes(32)
|
83
|
+
]
|
84
|
+
end
|
85
|
+
|
86
|
+
let(:identities) do
|
87
|
+
[
|
88
|
+
PskIdentity.new(
|
89
|
+
identity: identity_1,
|
90
|
+
obfuscated_ticket_age: obfuscated_ticket_age_1
|
91
|
+
),
|
92
|
+
PskIdentity.new(
|
93
|
+
identity: identity_2,
|
94
|
+
obfuscated_ticket_age: obfuscated_ticket_age_2
|
95
|
+
)
|
96
|
+
]
|
97
|
+
end
|
98
|
+
|
99
|
+
let(:offered_psks) do
|
100
|
+
OfferedPsks.new(
|
101
|
+
identities: identities,
|
102
|
+
binders: binders
|
103
|
+
)
|
104
|
+
end
|
105
|
+
|
106
|
+
let(:extension) do
|
107
|
+
PreSharedKey.new(msg_type: HandshakeType::CLIENT_HELLO,
|
108
|
+
offered_psks: offered_psks)
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'should be generated' do
|
112
|
+
expect(extension.msg_type).to eq HandshakeType::CLIENT_HELLO
|
113
|
+
expect(extension.extension_type).to eq ExtensionType::PRE_SHARED_KEY
|
114
|
+
expect(extension.offered_psks).to eq offered_psks
|
115
|
+
expect(extension.selected_identity).to be_nil
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'should be serialized' do
|
119
|
+
expect(extension.serialize).to eq ExtensionType::PRE_SHARED_KEY \
|
120
|
+
+ 146.to_uint16 \
|
121
|
+
+ 76.to_uint16 \
|
122
|
+
+ identity_1.prefix_uint16_length \
|
123
|
+
+ obfuscated_ticket_age_1.to_uint32 \
|
124
|
+
+ identity_2.prefix_uint16_length \
|
125
|
+
+ obfuscated_ticket_age_2.to_uint32 \
|
126
|
+
+ 66.to_uint16 \
|
127
|
+
+ binders[0].prefix_uint8_length \
|
128
|
+
+ binders[1].prefix_uint8_length
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
context 'valid pre_shared_key binary, ClientHello,' do
|
133
|
+
let(:extension) do
|
134
|
+
PreSharedKey.deserialize(TESTBINARY_PRE_SHARED_KEY_CH,
|
135
|
+
HandshakeType::CLIENT_HELLO)
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'should generate valid object' do
|
139
|
+
expect(extension.msg_type).to eq HandshakeType::CLIENT_HELLO
|
140
|
+
expect(extension.extension_type).to eq ExtensionType::PRE_SHARED_KEY
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'should generate valid serializable object' do
|
144
|
+
expect(extension.serialize)
|
145
|
+
.to eq ExtensionType::PRE_SHARED_KEY \
|
146
|
+
+ TESTBINARY_PRE_SHARED_KEY_CH.prefix_uint16_length
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
context 'valid pre_shared_key binary, ServerHello,' do
|
151
|
+
let(:extension) do
|
152
|
+
PreSharedKey.deserialize(TESTBINARY_PRE_SHARED_KEY_SH,
|
153
|
+
HandshakeType::SERVER_HELLO)
|
154
|
+
end
|
155
|
+
|
156
|
+
it 'should generate valid object' do
|
157
|
+
expect(extension.msg_type).to eq HandshakeType::SERVER_HELLO
|
158
|
+
expect(extension.extension_type).to eq ExtensionType::PRE_SHARED_KEY
|
159
|
+
end
|
160
|
+
|
161
|
+
it 'should generate valid serializable object' do
|
162
|
+
expect(extension.serialize)
|
163
|
+
.to eq ExtensionType::PRE_SHARED_KEY \
|
164
|
+
+ TESTBINARY_PRE_SHARED_KEY_SH.prefix_uint16_length
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'spec_helper'
|
5
|
+
using Refinements
|
6
|
+
|
7
|
+
RSpec.describe PskKeyExchangeModes do
|
8
|
+
context 'valid psk_key_exchange_modes' do
|
9
|
+
let(:extension) do
|
10
|
+
PskKeyExchangeModes.new([PskKeyExchangeMode::PSK_KE,
|
11
|
+
PskKeyExchangeMode::PSK_DHE_KE])
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should generate valid psk_key_exchange_modes' do
|
15
|
+
expect(extension.extension_type)
|
16
|
+
.to eq ExtensionType::PSK_KEY_EXCHANGE_MODES
|
17
|
+
expect(extension.ke_modes).to eq [PskKeyExchangeMode::PSK_KE,
|
18
|
+
PskKeyExchangeMode::PSK_DHE_KE]
|
19
|
+
expect(extension.serialize)
|
20
|
+
.to eq ExtensionType::PSK_KEY_EXCHANGE_MODES \
|
21
|
+
+ 3.to_uint16 \
|
22
|
+
+ [PskKeyExchangeMode::PSK_KE,
|
23
|
+
PskKeyExchangeMode::PSK_DHE_KE].join.prefix_uint8_length
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'valid psk_key_exchange_modes binary' do
|
28
|
+
let(:extension) do
|
29
|
+
PskKeyExchangeModes.deserialize(TESTBINARY_PSK_KEY_EXCHANGE_MODES)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should generate valid object' do
|
33
|
+
expect(extension.extension_type)
|
34
|
+
.to eq ExtensionType::PSK_KEY_EXCHANGE_MODES
|
35
|
+
expect(extension.ke_modes).to eq [PskKeyExchangeMode::PSK_KE,
|
36
|
+
PskKeyExchangeMode::PSK_DHE_KE]
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should generate serializable object' do
|
40
|
+
expect(extension.serialize)
|
41
|
+
.to eq ExtensionType::PSK_KEY_EXCHANGE_MODES \
|
42
|
+
+ TESTBINARY_PSK_KEY_EXCHANGE_MODES.prefix_uint16_length
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'spec_helper'
|
5
|
+
using Refinements
|
6
|
+
|
7
|
+
RSpec.describe RecordSizeLimit do
|
8
|
+
context 'vailid record_size_limit' do
|
9
|
+
let(:extension) do
|
10
|
+
RecordSizeLimit.new(2**14)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should be generated' do
|
14
|
+
expect(extension.extension_type).to eq ExtensionType::RECORD_SIZE_LIMIT
|
15
|
+
expect(extension.record_size_limit).to eq 2**14
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should be serialized' do
|
19
|
+
expect(extension.serialize).to eq ExtensionType::RECORD_SIZE_LIMIT \
|
20
|
+
+ 2.to_uint16 \
|
21
|
+
+ (2**14).to_uint16
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'invalid record_size_limit' do
|
26
|
+
let(:extension) do
|
27
|
+
RecordSizeLimit.new(63)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should not generated' do
|
31
|
+
expect { extension }.to raise_error(ErrorAlerts)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'valid record_size_limit binary' do
|
36
|
+
let(:extension) do
|
37
|
+
RecordSizeLimit.deserialize(TESTBINARY_RECORD_SIZE_LIMIT)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should generate valid object' do
|
41
|
+
expect(extension.extension_type).to eq ExtensionType::RECORD_SIZE_LIMIT
|
42
|
+
expect(extension.record_size_limit).to eq 2**14
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should generate serializable object' do
|
46
|
+
expect(extension.serialize)
|
47
|
+
.to eq ExtensionType::RECORD_SIZE_LIMIT \
|
48
|
+
+ TESTBINARY_RECORD_SIZE_LIMIT.prefix_uint16_length
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'invalid record_size_limit binary, too short record_size_limit,' do
|
53
|
+
let(:extension) do
|
54
|
+
RecordSizeLimit.deserialize(63.to_uint16)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'should not generate object' do
|
58
|
+
expect { extension }.to raise_error(ErrorAlerts)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/spec/record_spec.rb
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'spec_helper'
|
5
|
+
using Refinements
|
6
|
+
|
7
|
+
RSpec.describe Record do
|
8
|
+
context 'valid record' do
|
9
|
+
let(:record) do
|
10
|
+
Record.new(
|
11
|
+
type: ContentType::CCS,
|
12
|
+
legacy_record_version: ProtocolVersion::TLS_1_2,
|
13
|
+
messages: [ChangeCipherSpec.new],
|
14
|
+
cipher: Passer.new
|
15
|
+
)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should be generated' do
|
19
|
+
expect(record.type).to eq ContentType::CCS
|
20
|
+
expect(record.legacy_record_version).to eq ProtocolVersion::TLS_1_2
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should be serialized' do
|
24
|
+
expect(record.serialize).to eq ContentType::CCS \
|
25
|
+
+ ProtocolVersion::TLS_1_2 \
|
26
|
+
+ 1.to_uint16 \
|
27
|
+
+ ChangeCipherSpec.new.serialize
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'valid record binary' do
|
32
|
+
let(:record) do
|
33
|
+
Record.deserialize(TESTBINARY_RECORD_CCS, Passer.new)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should generate valid record header and ChangeCipherSpec' do
|
37
|
+
expect(record.type).to eq ContentType::CCS
|
38
|
+
expect(record.legacy_record_version).to eq ProtocolVersion::TLS_1_2
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should generate valid serializable object' do
|
42
|
+
expect(record.serialize).to eq ContentType::CCS \
|
43
|
+
+ ProtocolVersion::TLS_1_2 \
|
44
|
+
+ 1.to_uint16 \
|
45
|
+
+ ChangeCipherSpec.new.serialize
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'invalid record binary, too short,' do
|
50
|
+
let(:record) do
|
51
|
+
Record.deserialize(TESTBINARY_RECORD_CCS[0...-1],
|
52
|
+
Passer.new)
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should not generate object' do
|
56
|
+
expect { record }.to raise_error(ErrorAlerts)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'invalid record binary, nil,' do
|
61
|
+
let(:record) do
|
62
|
+
Record.deserialize(nil, Passer.new)
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'should not generate object' do
|
66
|
+
expect { record }.to raise_error(ErrorAlerts)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'server parameters record binary' do
|
71
|
+
let(:record) do
|
72
|
+
cipher = Cryptograph::Aead.new(
|
73
|
+
cipher_suite: CipherSuite::TLS_AES_128_GCM_SHA256,
|
74
|
+
write_key: TESTBINARY_SERVER_PARAMETERS_WRITE_KEY,
|
75
|
+
write_iv: TESTBINARY_SERVER_PARAMETERS_WRITE_IV,
|
76
|
+
sequence_number: SequenceNumber.new
|
77
|
+
)
|
78
|
+
Record.deserialize(TESTBINARY_SERVER_PARAMETERS_RECORD, cipher)
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'should generate valid record header' do
|
82
|
+
expect(record.type).to eq ContentType::APPLICATION_DATA
|
83
|
+
expect(record.legacy_record_version).to eq ProtocolVersion::TLS_1_2
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'should generate valid server parameters' do
|
87
|
+
expect(record.messages[0].msg_type)
|
88
|
+
.to eq HandshakeType::ENCRYPTED_EXTENSIONS
|
89
|
+
expect(record.messages[0].serialize)
|
90
|
+
.to eq TESTBINARY_ENCRYPTED_EXTENSIONS
|
91
|
+
expect(record.messages[1].msg_type)
|
92
|
+
.to eq HandshakeType::CERTIFICATE
|
93
|
+
expect(record.messages[1].serialize)
|
94
|
+
.to eq TESTBINARY_CERTIFICATE
|
95
|
+
expect(record.messages[2].msg_type)
|
96
|
+
.to eq HandshakeType::CERTIFICATE_VERIFY
|
97
|
+
expect(record.messages[2].serialize)
|
98
|
+
.to eq TESTBINARY_CERTIFICATE_VERIFY
|
99
|
+
expect(record.messages[3].msg_type)
|
100
|
+
.to eq HandshakeType::FINISHED
|
101
|
+
expect(record.messages[3].serialize)
|
102
|
+
.to eq TESTBINARY_SERVER_FINISHED
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'spec_helper'
|
5
|
+
using Refinements
|
6
|
+
|
7
|
+
RSpec.describe ServerHello do
|
8
|
+
context 'default server_hello' do
|
9
|
+
let(:random) do
|
10
|
+
OpenSSL::Random.random_bytes(32)
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:legacy_session_id_echo) do
|
14
|
+
Array.new(32, 0).map(&:chr).join
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:cipher_suite) do
|
18
|
+
CipherSuite::TLS_AES_256_GCM_SHA384
|
19
|
+
end
|
20
|
+
|
21
|
+
let(:message) do
|
22
|
+
ServerHello.new(random: random,
|
23
|
+
legacy_session_id_echo: legacy_session_id_echo,
|
24
|
+
cipher_suite: cipher_suite)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should be generated' do
|
28
|
+
expect(message.msg_type).to eq HandshakeType::SERVER_HELLO
|
29
|
+
expect(message.legacy_version).to eq ProtocolVersion::TLS_1_2
|
30
|
+
expect(message.random).to eq random
|
31
|
+
expect(message.legacy_session_id_echo).to eq legacy_session_id_echo
|
32
|
+
expect(message.cipher_suite).to eq CipherSuite::TLS_AES_256_GCM_SHA384
|
33
|
+
expect(message.legacy_compression_method).to eq "\x00"
|
34
|
+
expect(message.extensions).to be_empty
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should be serialized' do
|
38
|
+
expect(message.serialize).to eq HandshakeType::SERVER_HELLO \
|
39
|
+
+ 72.to_uint24 \
|
40
|
+
+ ProtocolVersion::TLS_1_2 \
|
41
|
+
+ random \
|
42
|
+
+ legacy_session_id_echo.length.to_uint8 \
|
43
|
+
+ legacy_session_id_echo \
|
44
|
+
+ cipher_suite \
|
45
|
+
+ "\x00" \
|
46
|
+
+ Extensions.new.serialize
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'valid server_hello binary' do
|
51
|
+
let(:message) do
|
52
|
+
ServerHello.deserialize(TESTBINARY_SERVER_HELLO)
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should generate valid object' do
|
56
|
+
expect(message.msg_type).to eq HandshakeType::SERVER_HELLO
|
57
|
+
expect(message.legacy_version).to eq ProtocolVersion::TLS_1_2
|
58
|
+
expect(message.cipher_suite).to eq CipherSuite::TLS_AES_128_GCM_SHA256
|
59
|
+
expect(message.legacy_compression_method).to eq "\x00"
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'should generate valid serializable object' do
|
63
|
+
expect(message.serialize).to eq TESTBINARY_SERVER_HELLO
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'hello_retry_request binary' do
|
68
|
+
let(:message) do
|
69
|
+
ServerHello.deserialize(TESTBINARY_HRR_HELLO_RETRY_REQUEST)
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'should generate valid object' do
|
73
|
+
expect(message.msg_type).to eq HandshakeType::SERVER_HELLO
|
74
|
+
expect(message.legacy_version).to eq ProtocolVersion::TLS_1_2
|
75
|
+
expect(message.cipher_suite).to eq CipherSuite::TLS_AES_128_GCM_SHA256
|
76
|
+
expect(message.legacy_compression_method).to eq "\x00"
|
77
|
+
expect(message.hrr?).to be true
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'should generate valid serializable object' do
|
81
|
+
expect(message.serialize).to eq TESTBINARY_HRR_HELLO_RETRY_REQUEST
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context 'valid server_hello binary, 0-RTT,' do
|
86
|
+
let(:message) do
|
87
|
+
ServerHello.deserialize(TESTBINARY_0_RTT_SERVER_HELLO)
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'should generate valid object' do
|
91
|
+
expect(message.msg_type).to eq HandshakeType::SERVER_HELLO
|
92
|
+
expect(message.legacy_version).to eq ProtocolVersion::TLS_1_2
|
93
|
+
expect(message.cipher_suite).to eq CipherSuite::TLS_AES_128_GCM_SHA256
|
94
|
+
expect(message.legacy_compression_method).to eq "\x00"
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'should generate valid serializable object' do
|
98
|
+
expect(message.serialize).to eq TESTBINARY_0_RTT_SERVER_HELLO
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'spec_helper'
|
5
|
+
using Refinements
|
6
|
+
|
7
|
+
RSpec.describe ServerName do
|
8
|
+
context 'valid server_name, example.com,' do
|
9
|
+
let(:extension) do
|
10
|
+
ServerName.new('example.com')
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should be generated' do
|
14
|
+
expect(extension.extension_type).to eq ExtensionType::SERVER_NAME
|
15
|
+
expect(extension.server_name).to eq 'example.com'
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should be serialized' do
|
19
|
+
expect(extension.serialize).to eq ExtensionType::SERVER_NAME \
|
20
|
+
+ 16.to_uint16 \
|
21
|
+
+ 14.to_uint16 \
|
22
|
+
+ NameType::HOST_NAME \
|
23
|
+
+ 11.to_uint16 \
|
24
|
+
+ 'example.com'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'valid server_name, empty HostName,' do
|
29
|
+
let(:extension) do
|
30
|
+
ServerName.new('')
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should be generated' do
|
34
|
+
expect(extension.extension_type).to eq ExtensionType::SERVER_NAME
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should be serialized' do
|
38
|
+
expect(extension.serialize).to eq ExtensionType::SERVER_NAME \
|
39
|
+
+ 0.to_uint16
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'invalid server_name, too long HostName,' do
|
44
|
+
let(:extension) do
|
45
|
+
ServerName.new('a' * (2**16 - 4))
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should not be generated' do
|
49
|
+
expect { extension }.to raise_error(ErrorAlerts)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'valid server_name binary' do
|
54
|
+
let(:extension) do
|
55
|
+
ServerName.deserialize(TESTBINARY_SERVER_NAME)
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'should generate valid object' do
|
59
|
+
expect(extension.extension_type).to eq ExtensionType::SERVER_NAME
|
60
|
+
expect(extension.server_name).to eq 'github.com'
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'should generate serializable object' do
|
64
|
+
expect(extension.serialize)
|
65
|
+
.to eq ExtensionType::SERVER_NAME \
|
66
|
+
+ TESTBINARY_SERVER_NAME.prefix_uint16_length
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'invalid server_name binary, malformed binary,' do
|
71
|
+
let(:extension) do
|
72
|
+
ServerName.deserialize(TESTBINARY_SERVER_NAME[0...-1])
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'should return nil' do
|
76
|
+
expect(extension).to be nil
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context 'invalid server_name binary, unknown NameType,' do
|
81
|
+
let(:testbinary) do
|
82
|
+
name_type = "\xff"
|
83
|
+
binary = name_type + 'example.com'.prefix_uint16_length
|
84
|
+
binary.prefix_uint16_length.prefix_uint16_length
|
85
|
+
end
|
86
|
+
|
87
|
+
let(:extension) do
|
88
|
+
ServerName.deserialize(testbinary)
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'should return nil' do
|
92
|
+
expect(extension).to be nil
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context 'invalid server_name binary, empty HostName,' do
|
97
|
+
let(:testbinary) do
|
98
|
+
binary = NameType::HOST_NAME + ''.prefix_uint16_length
|
99
|
+
binary.prefix_uint16_length.prefix_uint16_length
|
100
|
+
end
|
101
|
+
|
102
|
+
let(:extension) do
|
103
|
+
ServerName.deserialize(testbinary)
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'should return nil' do
|
107
|
+
expect(extension).to be nil
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|