echspec 0.0.2 → 0.0.3
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/.rubocop.yml +2 -1
- data/.ruby-version +1 -1
- data/Gemfile +2 -1
- data/README.md +2 -2
- data/Rakefile +41 -0
- data/echspec.gemspec +8 -4
- data/lib/echspec/spec/5.1-10.rb +2 -2
- data/lib/echspec/spec/5.1-9.rb +5 -5
- data/lib/echspec/spec/7-5.rb +7 -3
- data/lib/echspec/spec/7.1-11.rb +1 -1
- data/lib/echspec/spec/7.1-14.2.1.rb +3 -3
- data/lib/echspec/spec/7.1.1-2.rb +2 -2
- data/lib/echspec/spec/7.1.1-5.rb +3 -3
- data/lib/echspec/spec/9.rb +5 -5
- data/lib/echspec/spec.rb +5 -5
- data/lib/echspec/version.rb +1 -1
- data/lib/echspec.rb +11 -10
- metadata +20 -16
- data/.github/workflows/ci.yml +0 -30
- data/.gitignore +0 -17
- data/spec/9_spec.rb +0 -13
- data/spec/log_spec.rb +0 -58
- data/spec/spec_helper.rb +0 -12
- data/spec/with_socket_spec.rb +0 -77
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4ff77e42c8a7e2d787372fe6f96f3c00619fb6bcb3feea8df89c5400a838aef6
|
|
4
|
+
data.tar.gz: d317448071982052658909b19a99f535ce99e1c9f063de65be9cecae1ab4179f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7c4eea37fd0a7002bf6fd2a68b0a5c299bf84b43a71933053fb6cf2df59aedc17836e3299e809d1e5889130ccfcbd6ec19a276ffda556da8cf58b9e28042e211
|
|
7
|
+
data.tar.gz: c56a875c0547d3456958a5cbd9b8d3ec7d4e921033d176c2b2835b80657b59d9d207e9dc0342564506f89d9cee313168427e906e9d6249f6298a0e90d6a9a5cf
|
data/.rubocop.yml
CHANGED
data/.ruby-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
4.0.1
|
data/Gemfile
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
source 'https://rubygems.org'
|
|
2
2
|
|
|
3
3
|
gem 'base64'
|
|
4
|
+
gem 'ech_config', github: 'thekuwayama/ech_config'
|
|
4
5
|
gem 'resolv', '> 0.4.0'
|
|
5
6
|
gem 'tttls1.3', github: 'thekuwayama/tttls1.3'
|
|
6
7
|
|
|
7
8
|
group :development do
|
|
8
9
|
gem 'rake', '13.2.1'
|
|
9
10
|
gem 'rspec'
|
|
10
|
-
gem 'rubocop', '1.
|
|
11
|
+
gem 'rubocop', '1.82.1'
|
|
11
12
|
end
|
|
12
13
|
|
|
13
14
|
gemspec
|
data/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|

|
|
10
10
|
|
|
11
|
-
- https://datatracker.ietf.org/doc/html/
|
|
11
|
+
- https://datatracker.ietf.org/doc/html/rfc9849
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
## Installation
|
|
@@ -54,7 +54,7 @@ TLS Encrypted Client Hello Server
|
|
|
54
54
|
Failures:
|
|
55
55
|
|
|
56
56
|
1) MUST abort with an "illegal_parameter" alert, if ECHClientHello.type is not a valid ECHClientHelloType in ClientHelloOuter. [7-5]
|
|
57
|
-
https://datatracker.ietf.org/doc/html/
|
|
57
|
+
https://datatracker.ietf.org/doc/html/rfc9849#section-7-5
|
|
58
58
|
did not send expected alert: illegal_parameter
|
|
59
59
|
|
|
60
60
|
1 failure
|
data/Rakefile
CHANGED
|
@@ -1,8 +1,49 @@
|
|
|
1
1
|
require 'bundler/gem_tasks'
|
|
2
|
+
require 'ech_config'
|
|
3
|
+
require 'hpke'
|
|
4
|
+
require 'openssl'
|
|
2
5
|
require 'rspec/core/rake_task'
|
|
3
6
|
require 'rubocop/rake_task'
|
|
4
7
|
|
|
5
8
|
RuboCop::RakeTask.new
|
|
6
9
|
RSpec::Core::RakeTask.new(:spec)
|
|
7
10
|
|
|
11
|
+
TMP_DIR = "#{__dir__}/tmp".freeze
|
|
12
|
+
ECHCONFIGS = "#{TMP_DIR}/echconfigs.pem".freeze
|
|
13
|
+
|
|
14
|
+
directory TMP_DIR
|
|
15
|
+
|
|
16
|
+
file ECHCONFIGS => TMP_DIR do
|
|
17
|
+
puts "generate #{ECHCONFIGS}..."
|
|
18
|
+
|
|
19
|
+
key = OpenSSL::PKey.generate_key('X25519')
|
|
20
|
+
echconfigs = ECHConfigList.new(
|
|
21
|
+
[
|
|
22
|
+
ECHConfig.new(
|
|
23
|
+
"\xfe\x0d".b,
|
|
24
|
+
ECHConfig::ECHConfigContents.new(
|
|
25
|
+
ECHConfig::ECHConfigContents::HpkeKeyConfig.new(
|
|
26
|
+
123,
|
|
27
|
+
ECHConfig::ECHConfigContents::HpkeKeyConfig::HpkeKemId.new(HPKE::DHKEM_X25519_HKDF_SHA256),
|
|
28
|
+
ECHConfig::ECHConfigContents::HpkeKeyConfig::HpkePublicKey.new(key.raw_public_key),
|
|
29
|
+
[
|
|
30
|
+
ECHConfig::ECHConfigContents::HpkeKeyConfig::HpkeSymmetricCipherSuite.new(
|
|
31
|
+
ECHConfig::ECHConfigContents::HpkeKeyConfig::HpkeSymmetricCipherSuite::HpkeKdfId.new(HPKE::HKDF_SHA256),
|
|
32
|
+
ECHConfig::ECHConfigContents::HpkeKeyConfig::HpkeSymmetricCipherSuite::HpkeAeadId.new(HPKE::AES_128_GCM)
|
|
33
|
+
)
|
|
34
|
+
]
|
|
35
|
+
),
|
|
36
|
+
32,
|
|
37
|
+
'localhost'.b,
|
|
38
|
+
ECHConfig::ECHConfigContents::Extensions.new('')
|
|
39
|
+
)
|
|
40
|
+
)
|
|
41
|
+
]
|
|
42
|
+
)
|
|
43
|
+
File.write(ECHCONFIGS, key.private_to_pem + echconfigs.to_pem)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
desc 'generate echconfigs file'
|
|
47
|
+
task gen_echconfigs: ECHCONFIGS
|
|
48
|
+
|
|
8
49
|
task default: %i[rubocop spec]
|
data/echspec.gemspec
CHANGED
|
@@ -11,16 +11,20 @@ Gem::Specification.new do |spec|
|
|
|
11
11
|
spec.description = spec.summary
|
|
12
12
|
spec.homepage = 'https://github.com/thekuwayama/echspec'
|
|
13
13
|
spec.license = 'MIT'
|
|
14
|
-
spec.required_ruby_version = '>=
|
|
14
|
+
spec.required_ruby_version = '>=4.0'
|
|
15
15
|
|
|
16
|
-
spec.files
|
|
17
|
-
|
|
16
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
|
17
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
|
18
|
+
(f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
|
|
19
|
+
end
|
|
20
|
+
end
|
|
18
21
|
spec.require_paths = ['lib']
|
|
19
22
|
spec.bindir = 'exe'
|
|
20
23
|
spec.executables = ['echspec']
|
|
21
24
|
|
|
22
25
|
spec.add_development_dependency 'bundler'
|
|
23
26
|
spec.add_dependency 'base64'
|
|
27
|
+
spec.add_dependency 'ech_config', '~> 0.0.4'
|
|
24
28
|
spec.add_dependency 'resolv', '> 0.4.0'
|
|
25
|
-
spec.add_dependency 'tttls1.3', '~> 0.3.
|
|
29
|
+
spec.add_dependency 'tttls1.3', '~> 0.3.6'
|
|
26
30
|
end
|
data/lib/echspec/spec/5.1-10.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module EchSpec
|
|
2
2
|
module Spec
|
|
3
3
|
class Spec5_1_10 < WithSocket
|
|
4
|
-
# Next it makes a copy of the client_hello field and copies the
|
|
4
|
+
# Next, it makes a copy of the client_hello field and copies the
|
|
5
5
|
# legacy_session_id field from ClientHelloOuter. It then looks for an
|
|
6
6
|
# "ech_outer_extensions" extension. If found, it replaces the extension
|
|
7
7
|
# with the corresponding sequence of extensions in the
|
|
@@ -14,7 +14,7 @@ module EchSpec
|
|
|
14
14
|
# * The extensions in ClientHelloOuter corresponding to those in
|
|
15
15
|
# OuterExtensions do not occur in the same order.
|
|
16
16
|
#
|
|
17
|
-
# https://datatracker.ietf.org/doc/html/
|
|
17
|
+
# https://datatracker.ietf.org/doc/html/rfc9849#section-5.1-10
|
|
18
18
|
|
|
19
19
|
# @return [EchSpec::SpecGroup]
|
|
20
20
|
def self.spec_group
|
data/lib/echspec/spec/5.1-9.rb
CHANGED
|
@@ -2,12 +2,12 @@ module EchSpec
|
|
|
2
2
|
module Spec
|
|
3
3
|
class Spec5_1_9 < WithSocket
|
|
4
4
|
# The client-facing server computes ClientHelloInner by reversing this
|
|
5
|
-
# process. First it parses EncodedClientHelloInner, interpreting all
|
|
6
|
-
# bytes after client_hello as padding. If any padding byte is non-
|
|
7
|
-
#
|
|
8
|
-
#
|
|
5
|
+
# process. First, it parses EncodedClientHelloInner, interpreting all
|
|
6
|
+
# bytes after client_hello as padding. If any padding byte is non-zero,
|
|
7
|
+
# the server MUST abort the connection with an "illegal_parameter"
|
|
8
|
+
# alert.
|
|
9
9
|
#
|
|
10
|
-
# https://datatracker.ietf.org/doc/html/
|
|
10
|
+
# https://datatracker.ietf.org/doc/html/rfc9849#section-5.1-9
|
|
11
11
|
|
|
12
12
|
# @return [EchSpec::SpecGroup]
|
|
13
13
|
def self.spec_group
|
data/lib/echspec/spec/7-5.rb
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
module EchSpec
|
|
2
2
|
module Spec
|
|
3
3
|
class Spec7_5 < WithSocket
|
|
4
|
-
#
|
|
5
|
-
#
|
|
4
|
+
# In shared mode, a server plays both roles, first decrypting the
|
|
5
|
+
# ClientHelloOuter and then using the contents of the ClientHelloInner.
|
|
6
|
+
# A shared mode server which receives a ClientHello with
|
|
7
|
+
# ECHClientHello.type of inner MUST abort with an "illegal_parameter"
|
|
8
|
+
# alert, because such a ClientHello should never be received directly
|
|
9
|
+
# from the network.
|
|
6
10
|
#
|
|
7
|
-
# https://datatracker.ietf.org/doc/html/
|
|
11
|
+
# https://datatracker.ietf.org/doc/html/rfc9849#section-7-5
|
|
8
12
|
|
|
9
13
|
# @return [EchSpec::SpecGroup]
|
|
10
14
|
def self.spec_group
|
data/lib/echspec/spec/7.1-11.rb
CHANGED
|
@@ -7,7 +7,7 @@ module EchSpec
|
|
|
7
7
|
# offer TLS 1.2 or below. If either of these checks fails, the client-
|
|
8
8
|
# facing server MUST abort with an "illegal_parameter" alert.
|
|
9
9
|
#
|
|
10
|
-
# https://datatracker.ietf.org/doc/html/
|
|
10
|
+
# https://datatracker.ietf.org/doc/html/rfc9849#section-7.1-11
|
|
11
11
|
|
|
12
12
|
# @return [SpecGroup]
|
|
13
13
|
def self.spec_group
|
|
@@ -3,8 +3,8 @@ module EchSpec
|
|
|
3
3
|
class Spec7_1_14_2_1 < WithSocket
|
|
4
4
|
# Otherwise, if all candidate ECHConfig values fail to decrypt the
|
|
5
5
|
# extension, the client-facing server MUST ignore the extension and
|
|
6
|
-
# proceed with the connection using ClientHelloOuter
|
|
7
|
-
#
|
|
6
|
+
# proceed with the connection using ClientHelloOuter with the following
|
|
7
|
+
# modifications:
|
|
8
8
|
#
|
|
9
9
|
# * If the server is configured with any ECHConfigs, it MUST include
|
|
10
10
|
# the "encrypted_client_hello" extension in its EncryptedExtensions
|
|
@@ -13,7 +13,7 @@ module EchSpec
|
|
|
13
13
|
# ECHConfig values of different versions. This allows a server to
|
|
14
14
|
# support multiple versions at once.
|
|
15
15
|
#
|
|
16
|
-
# https://datatracker.ietf.org/doc/html/
|
|
16
|
+
# https://datatracker.ietf.org/doc/html/rfc9849#section-7.1-14.2.1
|
|
17
17
|
|
|
18
18
|
# @return [EchSpec::SpecGroup]
|
|
19
19
|
def self.spec_group
|
data/lib/echspec/spec/7.1.1-2.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module EchSpec
|
|
2
2
|
module Spec
|
|
3
3
|
class Spec7_1_1_2 < WithSocket
|
|
4
|
-
# If the client-facing server accepted ECH, it checks the second
|
|
4
|
+
# If the client-facing server accepted ECH, it checks that the second
|
|
5
5
|
# ClientHelloOuter also contains the "encrypted_client_hello"
|
|
6
6
|
# extension. If not, it MUST abort the handshake with a
|
|
7
7
|
# "missing_extension" alert. Otherwise, it checks that
|
|
@@ -9,7 +9,7 @@ module EchSpec
|
|
|
9
9
|
# unchanged, and that ECHClientHello.enc is empty. If not, it MUST
|
|
10
10
|
# abort the handshake with an "illegal_parameter" alert.
|
|
11
11
|
#
|
|
12
|
-
# https://datatracker.ietf.org/doc/html/
|
|
12
|
+
# https://datatracker.ietf.org/doc/html/rfc9849#section-7.1.1-2
|
|
13
13
|
|
|
14
14
|
# @return [EchSpec::SpecGroup]
|
|
15
15
|
def self.spec_group
|
data/lib/echspec/spec/7.1.1-5.rb
CHANGED
|
@@ -5,10 +5,10 @@ module EchSpec
|
|
|
5
5
|
# using the second ClientHelloOuter. If decryption fails, the client-
|
|
6
6
|
# facing server MUST abort the handshake with a "decrypt_error" alert.
|
|
7
7
|
# Otherwise, it reconstructs the second ClientHelloInner from the new
|
|
8
|
-
# EncodedClientHelloInner as described in Section 5.1, using the
|
|
9
|
-
#
|
|
8
|
+
# EncodedClientHelloInner as described in Section 5.1, using the second
|
|
9
|
+
# ClientHelloOuter for any referenced extensions.
|
|
10
10
|
#
|
|
11
|
-
# https://datatracker.ietf.org/doc/html/
|
|
11
|
+
# https://datatracker.ietf.org/doc/html/rfc9849#section-7.1.1-5
|
|
12
12
|
|
|
13
13
|
# @return [EchSpec::SpecGroup]
|
|
14
14
|
def self.spec_group
|
data/lib/echspec/spec/9.rb
CHANGED
|
@@ -9,7 +9,7 @@ module EchSpec
|
|
|
9
9
|
# * KDF: HKDF-SHA256 (see Section 7.2 of [HPKE])
|
|
10
10
|
# * AEAD: AES-128-GCM (see Section 7.3 of [HPKE])
|
|
11
11
|
#
|
|
12
|
-
# https://datatracker.ietf.org/doc/html/
|
|
12
|
+
# https://datatracker.ietf.org/doc/html/rfc9849#section-9
|
|
13
13
|
@section = '9'
|
|
14
14
|
@description = 'MUST implement the following HPKE cipher suite: KEM: DHKEM(X25519, HKDF-SHA256), KDF: HKDF-SHA256 and AEAD: AES-128-GCM.'
|
|
15
15
|
class << self
|
|
@@ -47,9 +47,9 @@ module EchSpec
|
|
|
47
47
|
def validate_compliant_ech_configs(ech_configs)
|
|
48
48
|
ech_config = ech_configs.find do |c|
|
|
49
49
|
kconfig = c.echconfig_contents.key_config
|
|
50
|
-
valid_kem_id = kconfig.kem_id.uint16 ==
|
|
50
|
+
valid_kem_id = kconfig.kem_id.uint16 == HPKE::DHKEM_X25519_HKDF_SHA256
|
|
51
51
|
valid_cipher_suite = kconfig.cipher_suites.any? do |cs|
|
|
52
|
-
cs.kdf_id.uint16 ==
|
|
52
|
+
cs.kdf_id.uint16 == HPKE::HKDF_SHA256 && cs.aead_id.uint16 == HPKE::AES_128_GCM
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
valid_kem_id && valid_cipher_suite
|
|
@@ -72,7 +72,7 @@ module EchSpec
|
|
|
72
72
|
return Err.new(e.message, nil)
|
|
73
73
|
end
|
|
74
74
|
|
|
75
|
-
# https://datatracker.ietf.org/doc/html/
|
|
75
|
+
# https://datatracker.ietf.org/doc/html/rfc9934#section-3
|
|
76
76
|
ech = 5
|
|
77
77
|
return Err.new("HTTPS resource record for #{hostname} does NOT have ech SvcParams.", nil) if rr.params[ech].nil?
|
|
78
78
|
|
|
@@ -95,7 +95,7 @@ module EchSpec
|
|
|
95
95
|
ech_configs = ECHConfig.decode_vectors(b.slice(2..))
|
|
96
96
|
Ok.new(ech_configs)
|
|
97
97
|
rescue StandardError
|
|
98
|
-
# https://datatracker.ietf.org/doc/html/
|
|
98
|
+
# https://datatracker.ietf.org/doc/html/rfc9934#section-3
|
|
99
99
|
example = <<~PEM
|
|
100
100
|
-----BEGIN PRIVATE KEY-----
|
|
101
101
|
MC4CAQAwBQYDK2VuBCIEICjd4yGRdsoP9gU7YT7My8DHx1Tjme8GYDXrOMCi8v1V
|
data/lib/echspec/spec.rb
CHANGED
|
@@ -14,7 +14,7 @@ module EchSpec
|
|
|
14
14
|
|
|
15
15
|
ResultDescURL = Struct.new(:result, :desc, :url)
|
|
16
16
|
|
|
17
|
-
# @param
|
|
17
|
+
# @param rdus [Array<ResultDescURL>] result: EchSpec::Ok | Err, desc: String, url: URI
|
|
18
18
|
# @param verbose [Boolean]
|
|
19
19
|
def print_results(rdus, verbose)
|
|
20
20
|
rdus.each { |rdu| print_summary(rdu.result, rdu.desc) }
|
|
@@ -148,7 +148,7 @@ module EchSpec
|
|
|
148
148
|
#
|
|
149
149
|
# @return [String]
|
|
150
150
|
def url(section)
|
|
151
|
-
"https://datatracker.ietf.org/doc/html/
|
|
151
|
+
"https://datatracker.ietf.org/doc/html/rfc9849#section-#{section}"
|
|
152
152
|
end
|
|
153
153
|
|
|
154
154
|
# @param fpath [String | NilClass]
|
|
@@ -157,7 +157,7 @@ module EchSpec
|
|
|
157
157
|
#
|
|
158
158
|
# @return [ECHConfig]
|
|
159
159
|
def try_get_ech_config(fpath, hostname, force_compliant)
|
|
160
|
-
# https://datatracker.ietf.org/doc/html/
|
|
160
|
+
# https://datatracker.ietf.org/doc/html/rfc9849#section-9
|
|
161
161
|
result = Spec9.try_get_ech_config(fpath, hostname, force_compliant)
|
|
162
162
|
desc = desc(Spec9.description, Spec9.section)
|
|
163
163
|
url = url(Spec9.section)
|
|
@@ -175,10 +175,10 @@ module EchSpec
|
|
|
175
175
|
end
|
|
176
176
|
|
|
177
177
|
def spec_groups
|
|
178
|
-
# https://datatracker.ietf.org/doc/html/
|
|
178
|
+
# https://datatracker.ietf.org/doc/html/rfc9849#section-5
|
|
179
179
|
groups = [Spec5_1_9, Spec5_1_10]
|
|
180
180
|
|
|
181
|
-
# https://datatracker.ietf.org/doc/html/
|
|
181
|
+
# https://datatracker.ietf.org/doc/html/rfc9849#section-7
|
|
182
182
|
groups += [Spec7_5, Spec7_1_11, Spec7_1_14_2_1, Spec7_1_1_2, Spec7_1_1_5]
|
|
183
183
|
|
|
184
184
|
groups.map(&:spec_group)
|
data/lib/echspec/version.rb
CHANGED
data/lib/echspec.rb
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
require 'base64'
|
|
2
2
|
require 'optparse'
|
|
3
|
+
require 'pp'
|
|
3
4
|
require 'resolv'
|
|
4
5
|
require 'timeout'
|
|
5
6
|
require 'tttls1.3'
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
8
|
+
require_relative 'echspec/version'
|
|
9
|
+
require_relative 'echspec/utils'
|
|
10
|
+
require_relative 'echspec/log'
|
|
11
|
+
require_relative 'echspec/error'
|
|
12
|
+
require_relative 'echspec/result'
|
|
13
|
+
require_relative 'echspec/tls13_client'
|
|
14
|
+
require_relative 'echspec/spec_case'
|
|
15
|
+
require_relative 'echspec/spec_group'
|
|
16
|
+
require_relative 'echspec/spec'
|
|
17
|
+
require_relative 'echspec/cli'
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: echspec
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- thekuwayama
|
|
@@ -37,6 +37,20 @@ dependencies:
|
|
|
37
37
|
- - ">="
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
39
|
version: '0'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: ech_config
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - "~>"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: 0.0.4
|
|
47
|
+
type: :runtime
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - "~>"
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: 0.0.4
|
|
40
54
|
- !ruby/object:Gem::Dependency
|
|
41
55
|
name: resolv
|
|
42
56
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -57,14 +71,14 @@ dependencies:
|
|
|
57
71
|
requirements:
|
|
58
72
|
- - "~>"
|
|
59
73
|
- !ruby/object:Gem::Version
|
|
60
|
-
version: 0.3.
|
|
74
|
+
version: 0.3.6
|
|
61
75
|
type: :runtime
|
|
62
76
|
prerelease: false
|
|
63
77
|
version_requirements: !ruby/object:Gem::Requirement
|
|
64
78
|
requirements:
|
|
65
79
|
- - "~>"
|
|
66
80
|
- !ruby/object:Gem::Version
|
|
67
|
-
version: 0.3.
|
|
81
|
+
version: 0.3.6
|
|
68
82
|
description: A conformance testing tool for ECH implementation
|
|
69
83
|
email:
|
|
70
84
|
- thekuwayama@gmail.com
|
|
@@ -73,8 +87,6 @@ executables:
|
|
|
73
87
|
extensions: []
|
|
74
88
|
extra_rdoc_files: []
|
|
75
89
|
files:
|
|
76
|
-
- ".github/workflows/ci.yml"
|
|
77
|
-
- ".gitignore"
|
|
78
90
|
- ".rubocop.yml"
|
|
79
91
|
- ".ruby-version"
|
|
80
92
|
- Gemfile
|
|
@@ -106,10 +118,6 @@ files:
|
|
|
106
118
|
- lib/echspec/tls13_client.rb
|
|
107
119
|
- lib/echspec/utils.rb
|
|
108
120
|
- lib/echspec/version.rb
|
|
109
|
-
- spec/9_spec.rb
|
|
110
|
-
- spec/log_spec.rb
|
|
111
|
-
- spec/spec_helper.rb
|
|
112
|
-
- spec/with_socket_spec.rb
|
|
113
121
|
homepage: https://github.com/thekuwayama/echspec
|
|
114
122
|
licenses:
|
|
115
123
|
- MIT
|
|
@@ -121,18 +129,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
121
129
|
requirements:
|
|
122
130
|
- - ">="
|
|
123
131
|
- !ruby/object:Gem::Version
|
|
124
|
-
version: '
|
|
132
|
+
version: '4.0'
|
|
125
133
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
126
134
|
requirements:
|
|
127
135
|
- - ">="
|
|
128
136
|
- !ruby/object:Gem::Version
|
|
129
137
|
version: '0'
|
|
130
138
|
requirements: []
|
|
131
|
-
rubygems_version:
|
|
139
|
+
rubygems_version: 4.0.7
|
|
132
140
|
specification_version: 4
|
|
133
141
|
summary: A conformance testing tool for ECH implementation
|
|
134
|
-
test_files:
|
|
135
|
-
- spec/9_spec.rb
|
|
136
|
-
- spec/log_spec.rb
|
|
137
|
-
- spec/spec_helper.rb
|
|
138
|
-
- spec/with_socket_spec.rb
|
|
142
|
+
test_files: []
|
data/.github/workflows/ci.yml
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
name: lint & test
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches:
|
|
6
|
-
- main
|
|
7
|
-
pull_request:
|
|
8
|
-
branches:
|
|
9
|
-
- '*'
|
|
10
|
-
|
|
11
|
-
jobs:
|
|
12
|
-
ci:
|
|
13
|
-
runs-on: ubuntu-latest
|
|
14
|
-
strategy:
|
|
15
|
-
matrix:
|
|
16
|
-
ruby-version: ['3.2', '3.3', '3.4']
|
|
17
|
-
steps:
|
|
18
|
-
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
19
|
-
- name: Set up Ruby
|
|
20
|
-
uses: ruby/setup-ruby@eaecf785f6a34567a6d97f686bbb7bccc1ac1e5c # v1.237.0
|
|
21
|
-
with:
|
|
22
|
-
ruby-version: ${{ matrix.ruby-version }}
|
|
23
|
-
- name: Install dependencies
|
|
24
|
-
run: |
|
|
25
|
-
gem --version
|
|
26
|
-
gem install bundler
|
|
27
|
-
bundle --version
|
|
28
|
-
bundle install
|
|
29
|
-
- name: Run rubocop & rspec
|
|
30
|
-
run: bundle exec rake
|
data/.gitignore
DELETED
data/spec/9_spec.rb
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
require_relative 'spec_helper'
|
|
2
|
-
|
|
3
|
-
RSpec.describe EchSpec::Spec::Spec9 do
|
|
4
|
-
context 'parse_pem' do
|
|
5
|
-
let(:pem) do
|
|
6
|
-
File.open("#{__dir__}/../fixtures/echconfigs.pem").read
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
it 'could parse' do
|
|
10
|
-
expect(EchSpec::Spec::Spec9.send(:parse_pem, pem)).to be_a EchSpec::Ok
|
|
11
|
-
end
|
|
12
|
-
end
|
|
13
|
-
end
|
data/spec/log_spec.rb
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
require_relative 'spec_helper'
|
|
2
|
-
|
|
3
|
-
RSpec.describe EchSpec::Log::MessageStack do
|
|
4
|
-
context 'obj2json' do
|
|
5
|
-
let(:crt) do
|
|
6
|
-
File.open("#{__dir__}/../fixtures/server.crt").read
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
it 'should convert' do
|
|
10
|
-
expect(EchSpec::Log::MessageStack.obj2json(OpenSSL::X509::Certificate.new(crt)))
|
|
11
|
-
.to eq "#{crt.split("\n").join('\n')}\\n"
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
it 'should convert' do
|
|
15
|
-
expect(EchSpec::Log::MessageStack.obj2json(1)).to eq '1'
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
it 'should convert' do
|
|
19
|
-
expect(EchSpec::Log::MessageStack.obj2json(0.1)).to eq '0.1'
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
it 'should convert' do
|
|
23
|
-
expect(EchSpec::Log::MessageStack.obj2json(true)).to eq 'true'
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
it 'should convert' do
|
|
27
|
-
expect(EchSpec::Log::MessageStack.obj2json(false)).to eq 'false'
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
it 'should convert' do
|
|
31
|
-
expect(EchSpec::Log::MessageStack.obj2json('')).to eq '""'
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
it 'should convert' do
|
|
35
|
-
expect(EchSpec::Log::MessageStack.obj2json('string')).to eq '"0x737472696e67"'
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
it 'should convert' do
|
|
39
|
-
expect(EchSpec::Log::MessageStack.obj2json(nil)).to eq 'null'
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
it 'should convert' do
|
|
43
|
-
expect(EchSpec::Log::MessageStack.obj2json([1, true, '', 'string', nil])).to eq '[1,true,"","0x737472696e67",null]'
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
it 'should convert' do
|
|
47
|
-
expect(EchSpec::Log::MessageStack.obj2json(1 => true, '' => 'string', nil => [])).to eq '{1:true,"":"0x737472696e67",null:[]}'
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
it 'should convert' do
|
|
51
|
-
expect(EchSpec::Log::MessageStack.obj2json(C.new('string'))).to eq '{"name":"0x737472696e67"}'
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
it 'should convert' do
|
|
55
|
-
expect(EchSpec::Log::MessageStack.obj2json(D.new)).to eq '"$D"'
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
end
|
data/spec/spec_helper.rb
DELETED
data/spec/with_socket_spec.rb
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
require_relative 'spec_helper'
|
|
2
|
-
|
|
3
|
-
module EchSpec
|
|
4
|
-
module Spec
|
|
5
|
-
class SpecX < WithSocket
|
|
6
|
-
def validate(hostname, port)
|
|
7
|
-
with_socket(hostname, port) do |_socket|
|
|
8
|
-
# not return
|
|
9
|
-
end
|
|
10
|
-
end
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
class SpecY < WithSocket
|
|
14
|
-
def validate(hostname, port)
|
|
15
|
-
with_socket(hostname, port) do |_socket|
|
|
16
|
-
return EchSpec::Ok.new(1)
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
class SpecZ < WithSocket
|
|
22
|
-
def validate(hostname, port)
|
|
23
|
-
with_socket(hostname, port) do |_socket|
|
|
24
|
-
msg = TTTLS13::Message::Alert.new(
|
|
25
|
-
level: TTTLS13::Message::AlertLevel::FATAL,
|
|
26
|
-
description: "\x0a"
|
|
27
|
-
)
|
|
28
|
-
return EchSpec::Err.new('details', [msg])
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
class SpecW < WithSocket
|
|
34
|
-
def validate(hostname, port)
|
|
35
|
-
with_socket(hostname, port) do |_socket|
|
|
36
|
-
raise EchSpec::Error::BeforeTargetSituationError, 'not received ClientHello'
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
RSpec.describe EchSpec::Spec::WithSocket do
|
|
44
|
-
context 'with_socket' do
|
|
45
|
-
before do
|
|
46
|
-
socket = StringIO.new
|
|
47
|
-
allow(TCPSocket).to receive(:new).and_return(socket)
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
it 'should return nil' do
|
|
51
|
-
result = EchSpec::Spec::SpecX.new.validate('localhost', 4433)
|
|
52
|
-
expect(result).to eq nil
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
it 'should return Ok(1)' do
|
|
56
|
-
result = EchSpec::Spec::SpecY.new.validate('localhost', 4433)
|
|
57
|
-
expect(result).to be_a EchSpec::Ok
|
|
58
|
-
expect(result.obj).to eq 1
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
it 'should return Err(details, message_stack)' do
|
|
62
|
-
result = EchSpec::Spec::SpecZ.new.validate('localhost', 4433)
|
|
63
|
-
expect(result).to be_a EchSpec::Err
|
|
64
|
-
expect(result.details).to eq 'details'
|
|
65
|
-
expect(result.message_stack.length).to be 1
|
|
66
|
-
expect(result.message_stack.first.level).to be TTTLS13::Message::AlertLevel::FATAL
|
|
67
|
-
expect(result.message_stack.first.description).to eq "\x0a"
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
it 'should return Err(details, message_stack), raised BeforeTargetSituationError' do
|
|
71
|
-
result = EchSpec::Spec::SpecW.new.validate('localhost', 4433)
|
|
72
|
-
expect(result).to be_a EchSpec::Err
|
|
73
|
-
expect(result.details).to eq 'not received ClientHello'
|
|
74
|
-
expect(result.message_stack).to eq '{}'
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
end
|