echspec 0.0.1
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/.github/workflows/ci.yml +30 -0
 - data/.gitignore +17 -0
 - data/.rubocop.yml +36 -0
 - data/.ruby-version +1 -0
 - data/Gemfile +13 -0
 - data/LICENSE.txt +21 -0
 - data/README.md +272 -0
 - data/Rakefile +8 -0
 - data/docs/echspec-demo.png +0 -0
 - data/echspec.gemspec +26 -0
 - data/exe/echspec +7 -0
 - data/fixtures/echconfigs.pem +7 -0
 - data/fixtures/server.crt +20 -0
 - data/fixtures/server.key +27 -0
 - data/lib/echspec/cli.rb +97 -0
 - data/lib/echspec/error.rb +9 -0
 - data/lib/echspec/log.rb +85 -0
 - data/lib/echspec/result.rb +26 -0
 - data/lib/echspec/spec/5.1-10.rb +222 -0
 - data/lib/echspec/spec/5.1-9.rb +108 -0
 - data/lib/echspec/spec/7-5.rb +242 -0
 - data/lib/echspec/spec/7.1-11.rb +93 -0
 - data/lib/echspec/spec/7.1-14.2.1.rb +133 -0
 - data/lib/echspec/spec/7.1.1-2.rb +142 -0
 - data/lib/echspec/spec/7.1.1-5.rb +83 -0
 - data/lib/echspec/spec/9.rb +113 -0
 - data/lib/echspec/spec.rb +170 -0
 - data/lib/echspec/spec_case.rb +10 -0
 - data/lib/echspec/spec_group.rb +10 -0
 - data/lib/echspec/tls13_client.rb +167 -0
 - data/lib/echspec/utils.rb +21 -0
 - data/lib/echspec/version.rb +3 -0
 - data/lib/echspec.rb +16 -0
 - data/spec/9_spec.rb +13 -0
 - data/spec/log_spec.rb +58 -0
 - data/spec/spec_helper.rb +12 -0
 - data/spec/with_socket_spec.rb +77 -0
 - metadata +141 -0
 
    
        checksums.yaml
    ADDED
    
    | 
         @@ -0,0 +1,7 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            ---
         
     | 
| 
      
 2 
     | 
    
         
            +
            SHA256:
         
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 942fd582bb741ca465bb5255b458ef3cbf3ff8cd09f20b45957df8c64d32f55a
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: e5748a921bc1ab45c053884690fe0e7f5718b8847c6376f87100f22173f8dd9c
         
     | 
| 
      
 5 
     | 
    
         
            +
            SHA512:
         
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: a9597e9295d2b6a8d2b836a59a9ec1013edb42b2fc605e2dacd9ba274510ccb9982f1971d6aa4d092f1896da19a4d2317386d72f9d690639049e288e96fe1fe5
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: d104c73ca8124af91cbaeb172757d8353e3a328668c89a9d1b66f01281ac6d8e5bacd298ac96b05fa27d1b70dadceb9a216c8b873db9607286a7e0767f304c58
         
     | 
| 
         @@ -0,0 +1,30 @@ 
     | 
|
| 
      
 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@v4
         
     | 
| 
      
 19 
     | 
    
         
            +
                  - name: Set up Ruby
         
     | 
| 
      
 20 
     | 
    
         
            +
                    uses: ruby/setup-ruby@v1
         
     | 
| 
      
 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
    ADDED
    
    
    
        data/.rubocop.yml
    ADDED
    
    | 
         @@ -0,0 +1,36 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            AllCops:
         
     | 
| 
      
 2 
     | 
    
         
            +
              TargetRubyVersion: 3.2
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            Layout/LineLength:
         
     | 
| 
      
 5 
     | 
    
         
            +
              Max: 200
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            Metrics/AbcSize:
         
     | 
| 
      
 8 
     | 
    
         
            +
              Max: 30
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            Metrics/BlockLength:
         
     | 
| 
      
 11 
     | 
    
         
            +
              Exclude:
         
     | 
| 
      
 12 
     | 
    
         
            +
                - 'spec/*.rb'
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            Metrics/ClassLength:
         
     | 
| 
      
 15 
     | 
    
         
            +
              Max: 200
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            Metrics/MethodLength:
         
     | 
| 
      
 18 
     | 
    
         
            +
              Max: 30
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
            Naming/MethodParameterName:
         
     | 
| 
      
 21 
     | 
    
         
            +
              MinNameLength: 1
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            Naming/FileName:
         
     | 
| 
      
 24 
     | 
    
         
            +
              Enabled: false
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
            Naming/ClassAndModuleCamelCase:
         
     | 
| 
      
 27 
     | 
    
         
            +
              Enabled: false
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
            Semicolon:
         
     | 
| 
      
 30 
     | 
    
         
            +
              AllowAsExpressionSeparator: true
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
            Style/Documentation:
         
     | 
| 
      
 33 
     | 
    
         
            +
              Enabled: false
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
            Style/FrozenStringLiteralComment:
         
     | 
| 
      
 36 
     | 
    
         
            +
              Enabled: false
         
     | 
    
        data/.ruby-version
    ADDED
    
    | 
         @@ -0,0 +1 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            3.3.6
         
     | 
    
        data/Gemfile
    ADDED
    
    
    
        data/LICENSE.txt
    ADDED
    
    | 
         @@ -0,0 +1,21 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            The MIT License (MIT)
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            Copyright (c) 2024 Tomoya Kuwayama
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            Permission is hereby granted, free of charge, to any person obtaining a copy
         
     | 
| 
      
 6 
     | 
    
         
            +
            of this software and associated documentation files (the "Software"), to deal
         
     | 
| 
      
 7 
     | 
    
         
            +
            in the Software without restriction, including without limitation the rights
         
     | 
| 
      
 8 
     | 
    
         
            +
            to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
         
     | 
| 
      
 9 
     | 
    
         
            +
            copies of the Software, and to permit persons to whom the Software is
         
     | 
| 
      
 10 
     | 
    
         
            +
            furnished to do so, subject to the following conditions:
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            The above copyright notice and this permission notice shall be included in
         
     | 
| 
      
 13 
     | 
    
         
            +
            all copies or substantial portions of the Software.
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
         
     | 
| 
      
 16 
     | 
    
         
            +
            IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
         
     | 
| 
      
 17 
     | 
    
         
            +
            FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
         
     | 
| 
      
 18 
     | 
    
         
            +
            AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
         
     | 
| 
      
 19 
     | 
    
         
            +
            LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
         
     | 
| 
      
 20 
     | 
    
         
            +
            OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
         
     | 
| 
      
 21 
     | 
    
         
            +
            THE SOFTWARE.
         
     | 
    
        data/README.md
    ADDED
    
    | 
         @@ -0,0 +1,272 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # echspec
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            [](https://badge.fury.io/rb/echspec)
         
     | 
| 
      
 4 
     | 
    
         
            +
            [](https://github.com/thekuwayama/echspec/actions/workflows/ci.yml)
         
     | 
| 
      
 5 
     | 
    
         
            +
            [](LICENSE.txt)
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            `echspec` is a conformance testing tool for ECH implementation.
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            - https://datatracker.ietf.org/doc/html/draft-ietf-tls-esni-22
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            ## Initial Setup
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            The gem is available at [rubygems.org](https://rubygems.org/gems/echspec). You can install it the following:
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
            ```sh-session
         
     | 
| 
      
 19 
     | 
    
         
            +
            $ gem install echspec
         
     | 
| 
      
 20 
     | 
    
         
            +
            ```
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            ## Usage
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
            ```sh-session
         
     | 
| 
      
 26 
     | 
    
         
            +
            $ echspec --help
         
     | 
| 
      
 27 
     | 
    
         
            +
            Usage: echspec [OPTIONS] <HOSTNAME>
         
     | 
| 
      
 28 
     | 
    
         
            +
                -f, --file FILE                  path to ECHConfigs PEM file       (default resolve ECHConfigs via DNS)
         
     | 
| 
      
 29 
     | 
    
         
            +
                -p, --port VALUE                 server port number                (default 443)
         
     | 
| 
      
 30 
     | 
    
         
            +
                -n, --not-force-compliant-hpke   not force compliant ECHConfig HPKE cipher suite
         
     | 
| 
      
 31 
     | 
    
         
            +
                -v, --verbose                    verbose mode; prints message stack if raised an error
         
     | 
| 
      
 32 
     | 
    
         
            +
                -s, --sections SECTIONS          sections to test; by the default, test all sections
         
     | 
| 
      
 33 
     | 
    
         
            +
            ```
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
            You can run it the following:
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
            ```sh-session
         
     | 
| 
      
 38 
     | 
    
         
            +
            $ echspec research.cloudflare.com
         
     | 
| 
      
 39 
     | 
    
         
            +
            TLS Encrypted Client Hello Server
         
     | 
| 
      
 40 
     | 
    
         
            +
                    ✔ MUST implement the following HPKE cipher suite: KEM: DHKEM(X25519, HKDF-SHA256), KDF: HKDF-SHA256 and AEAD: AES-128-GCM. [9]
         
     | 
| 
      
 41 
     | 
    
         
            +
                    ✔ MUST abort with an "illegal_parameter" alert, if EncodedClientHelloInner is padded with non-zero values. [5.1-9]
         
     | 
| 
      
 42 
     | 
    
         
            +
                    ✔ MUST abort with an "illegal_parameter" alert, if any referenced extension is missing in ClientHelloOuter. [5.1-10]
         
     | 
| 
      
 43 
     | 
    
         
            +
                    ✔ MUST abort with an "illegal_parameter" alert, if any extension is referenced in OuterExtensions more than once. [5.1-10]
         
     | 
| 
      
 44 
     | 
    
         
            +
                    ✔ MUST abort with an "illegal_parameter" alert, if "encrypted_client_hello" is referenced in OuterExtensions. [5.1-10]
         
     | 
| 
      
 45 
     | 
    
         
            +
                    ✔ MUST abort with an "illegal_parameter" alert, if the extensions in ClientHelloOuter corresponding to those in OuterExtensions do not occur in the same order. [5.1-10]
         
     | 
| 
      
 46 
     | 
    
         
            +
                    ✔ MUST abort with an "illegal_parameter" alert, if ECHClientHello.type is not a valid ECHClientHelloType in ClientHelloInner. [7-5]
         
     | 
| 
      
 47 
     | 
    
         
            +
                    ✔ MUST abort with an "illegal_parameter" alert, if ECHClientHello.type is not a valid ECHClientHelloType in ClientHelloOuter. [7-5]
         
     | 
| 
      
 48 
     | 
    
         
            +
                    ✔ MUST abort with an "illegal_parameter" alert, if ClientHelloInner offers TLS 1.2 or below. [7.1-11]
         
     | 
| 
      
 49 
     | 
    
         
            +
                    ✔ MUST include the "encrypted_client_hello" extension in its EncryptedExtensions with the "retry_configs" field set to one or more ECHConfig. [7.1-14.2.1]
         
     | 
| 
      
 50 
     | 
    
         
            +
                    ✔ MUST abort with a "missing_extension" alert, if 2nd ClientHelloOuter does not contains the "encrypted_client_hello" extension. [7.1.1-2]
         
     | 
| 
      
 51 
     | 
    
         
            +
                    ✔ MUST abort with an "illegal_parameter" alert, if 2nd ClientHelloOuter "encrypted_client_hello" enc is empty. [7.1.1-2]
         
     | 
| 
      
 52 
     | 
    
         
            +
                    ✔ MUST abort with a "decrypt_error" alert, if fails to decrypt 2nd ClientHelloOuter. [7.1.1-5]
         
     | 
| 
      
 53 
     | 
    
         
            +
            ```
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
            By default, `echspec` retrieves ECHConfigs via HTTPS records. By using the `-f, --file FILE` option, you can specify an ECHConfig pem file. If you need to test the server on localhost, you can run it the following:
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
            ```sh-session
         
     | 
| 
      
 58 
     | 
    
         
            +
            $ echspec -f fixtures/echconfigs.pem -p 4433 localhost
         
     | 
| 
      
 59 
     | 
    
         
            +
            ```
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
            By default, `echspec` uses the following HPKE cipher suite
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
            - KEM
         
     | 
| 
      
 64 
     | 
    
         
            +
              - DHKEM(X25519, HKDF-SHA256)
         
     | 
| 
      
 65 
     | 
    
         
            +
            - KDF
         
     | 
| 
      
 66 
     | 
    
         
            +
              - HKDF-SHA256
         
     | 
| 
      
 67 
     | 
    
         
            +
            - AEAD
         
     | 
| 
      
 68 
     | 
    
         
            +
              - AES-128-GCM
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
            Using the `-n` or `--not-force-compliant-hpke`, you can not enforce the HPKE cipher suite.
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
            ```sh-session
         
     | 
| 
      
 73 
     | 
    
         
            +
            $ echspec -f fixtures/echconfigs.pem -p 4433 -n localhost
         
     | 
| 
      
 74 
     | 
    
         
            +
            ```
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
            If you specify the SECTIONS, you can run only SECTIONS the following:
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
            ```sh-session
         
     | 
| 
      
 79 
     | 
    
         
            +
            $ echspec -f fixtures/echconfigs.pem -p 4433 -n -s 7.1.1-2,7.1.1-5 localhost
         
     | 
| 
      
 80 
     | 
    
         
            +
            TLS Encrypted Client Hello Server
         
     | 
| 
      
 81 
     | 
    
         
            +
                    ✔ MUST abort with a "missing_extension" alert, if 2nd ClientHelloOuter does not contains the "encrypted_client_hello" extension. [7.1.1-2]
         
     | 
| 
      
 82 
     | 
    
         
            +
                    ✔ MUST abort with an "illegal_parameter" alert, if 2nd ClientHelloOuter "encrypted_client_hello" enc is empty. [7.1.1-2]
         
     | 
| 
      
 83 
     | 
    
         
            +
                    ✔ MUST abort with a "decrypt_error" alert, if fails to decrypt 2nd ClientHelloOuter. [7.1.1-5]
         
     | 
| 
      
 84 
     | 
    
         
            +
            ```
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
            Using the `-v` or `--verbose` option provides a message stack if an error occurs. The message stack is formatted as JSON.
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
            ```sh-session
         
     | 
| 
      
 89 
     | 
    
         
            +
            $ echspec -s 7-5 -v research.cloudflare.com 2>&1 > /dev/null | jq .
         
     | 
| 
      
 90 
     | 
    
         
            +
            ````
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
            <details>
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
            ```json
         
     | 
| 
      
 95 
     | 
    
         
            +
            {
         
     | 
| 
      
 96 
     | 
    
         
            +
              "Alert": {
         
     | 
| 
      
 97 
     | 
    
         
            +
                "level": "0x02",
         
     | 
| 
      
 98 
     | 
    
         
            +
                "description": "0x32"
         
     | 
| 
      
 99 
     | 
    
         
            +
              },
         
     | 
| 
      
 100 
     | 
    
         
            +
              "ClientHello": {
         
     | 
| 
      
 101 
     | 
    
         
            +
                "msg_type": "0x01",
         
     | 
| 
      
 102 
     | 
    
         
            +
                "legacy_version": "0x0303",
         
     | 
| 
      
 103 
     | 
    
         
            +
                "random": "0x29142f95eb55066cdb496267d3154628685ad1dbbe5b877e66eda4af20df2c69",
         
     | 
| 
      
 104 
     | 
    
         
            +
                "legacy_session_id": "0x9c557bc381f62d73ba3b99629f8fe6e347787be66c56fa99db4f6bc6fd06fd5f",
         
     | 
| 
      
 105 
     | 
    
         
            +
                "cipher_suites": [
         
     | 
| 
      
 106 
     | 
    
         
            +
                  "0x1302",
         
     | 
| 
      
 107 
     | 
    
         
            +
                  "0x1303",
         
     | 
| 
      
 108 
     | 
    
         
            +
                  "0x1301"
         
     | 
| 
      
 109 
     | 
    
         
            +
                ],
         
     | 
| 
      
 110 
     | 
    
         
            +
                "legacy_compression_methods": [
         
     | 
| 
      
 111 
     | 
    
         
            +
                  "0x00"
         
     | 
| 
      
 112 
     | 
    
         
            +
                ],
         
     | 
| 
      
 113 
     | 
    
         
            +
                "extensions": {
         
     | 
| 
      
 114 
     | 
    
         
            +
                  "0x0000": {
         
     | 
| 
      
 115 
     | 
    
         
            +
                    "extension_type": "0x0000",
         
     | 
| 
      
 116 
     | 
    
         
            +
                    "server_name": "0x636c6f7564666c6172652d6563682e636f6d"
         
     | 
| 
      
 117 
     | 
    
         
            +
                  },
         
     | 
| 
      
 118 
     | 
    
         
            +
                  "0x002b": {
         
     | 
| 
      
 119 
     | 
    
         
            +
                    "extension_type": "0x002b",
         
     | 
| 
      
 120 
     | 
    
         
            +
                    "msg_type": "0x01",
         
     | 
| 
      
 121 
     | 
    
         
            +
                    "versions": [
         
     | 
| 
      
 122 
     | 
    
         
            +
                      "0x0304"
         
     | 
| 
      
 123 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 124 
     | 
    
         
            +
                  },
         
     | 
| 
      
 125 
     | 
    
         
            +
                  "0x000d": {
         
     | 
| 
      
 126 
     | 
    
         
            +
                    "extension_type": "0x000d",
         
     | 
| 
      
 127 
     | 
    
         
            +
                    "supported_signature_algorithms": [
         
     | 
| 
      
 128 
     | 
    
         
            +
                      "0x0403",
         
     | 
| 
      
 129 
     | 
    
         
            +
                      "0x0503",
         
     | 
| 
      
 130 
     | 
    
         
            +
                      "0x0603",
         
     | 
| 
      
 131 
     | 
    
         
            +
                      "0x0804",
         
     | 
| 
      
 132 
     | 
    
         
            +
                      "0x0805",
         
     | 
| 
      
 133 
     | 
    
         
            +
                      "0x0806",
         
     | 
| 
      
 134 
     | 
    
         
            +
                      "0x0401",
         
     | 
| 
      
 135 
     | 
    
         
            +
                      "0x0501",
         
     | 
| 
      
 136 
     | 
    
         
            +
                      "0x0601"
         
     | 
| 
      
 137 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 138 
     | 
    
         
            +
                  },
         
     | 
| 
      
 139 
     | 
    
         
            +
                  "0x000a": {
         
     | 
| 
      
 140 
     | 
    
         
            +
                    "extension_type": "0x000a",
         
     | 
| 
      
 141 
     | 
    
         
            +
                    "named_group_list": [
         
     | 
| 
      
 142 
     | 
    
         
            +
                      "0x0017",
         
     | 
| 
      
 143 
     | 
    
         
            +
                      "0x0018",
         
     | 
| 
      
 144 
     | 
    
         
            +
                      "0x0019"
         
     | 
| 
      
 145 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 146 
     | 
    
         
            +
                  },
         
     | 
| 
      
 147 
     | 
    
         
            +
                  "0x0033": {
         
     | 
| 
      
 148 
     | 
    
         
            +
                    "extension_type": "0x0033",
         
     | 
| 
      
 149 
     | 
    
         
            +
                    "msg_type": "0x01",
         
     | 
| 
      
 150 
     | 
    
         
            +
                    "key_share_entry": [
         
     | 
| 
      
 151 
     | 
    
         
            +
                      {
         
     | 
| 
      
 152 
     | 
    
         
            +
                        "group": "0x0017",
         
     | 
| 
      
 153 
     | 
    
         
            +
                        "key_exchange": "0x0421747aa4234dbefc61906c165b8f1050b3346bb67f2c4ad8af9f58135888354a631b9b5c68f8ec1b6d6e67485a971bd3ff0ba6ab46da08f1524d7a4a3578c110"
         
     | 
| 
      
 154 
     | 
    
         
            +
                      },
         
     | 
| 
      
 155 
     | 
    
         
            +
                      {
         
     | 
| 
      
 156 
     | 
    
         
            +
                        "group": "0x0018",
         
     | 
| 
      
 157 
     | 
    
         
            +
                        "key_exchange": "0x046d374a61f2b75717b28b47b3fa227b51e09bb7a4ce0ea24b3cd3c946e9d4da2d54186b76812a74eb53adaa8a4451573201613b2f6301c05efb79bb6a782e88150dc3ac14aad702b8268aa8f3435d1a404166133216467aeb933247f994035fa0"
         
     | 
| 
      
 158 
     | 
    
         
            +
                      },
         
     | 
| 
      
 159 
     | 
    
         
            +
                      {
         
     | 
| 
      
 160 
     | 
    
         
            +
                        "group": "0x0019",
         
     | 
| 
      
 161 
     | 
    
         
            +
                        "key_exchange": "0x0401c90f95f64dc1e8d7d3f29f8a9103308835a2b56f5581ffc2837a1f9fcf6b23db824f01d6e4efccec78d6858aaad2fde8f02c2acc66a463c14b78e5e323b23d1b1301725b4f757811b7a31b4b5ee8016891ecb55b3fb997dd5738f6e610388f9bc85a4515efd04ab1d456e56d4e6e4a3a1e58a58ed6cf86f5dc9d7ace20afcd0af6b23b"
         
     | 
| 
      
 162 
     | 
    
         
            +
                      }
         
     | 
| 
      
 163 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 164 
     | 
    
         
            +
                  },
         
     | 
| 
      
 165 
     | 
    
         
            +
                  "0xfe0d": {
         
     | 
| 
      
 166 
     | 
    
         
            +
                    "extension_type": "0xfe0d",
         
     | 
| 
      
 167 
     | 
    
         
            +
                    "type": "0x02",
         
     | 
| 
      
 168 
     | 
    
         
            +
                    "cipher_suite": {
         
     | 
| 
      
 169 
     | 
    
         
            +
                      "kdf_id": {
         
     | 
| 
      
 170 
     | 
    
         
            +
                        "uint16": 1
         
     | 
| 
      
 171 
     | 
    
         
            +
                      },
         
     | 
| 
      
 172 
     | 
    
         
            +
                      "aead_id": {
         
     | 
| 
      
 173 
     | 
    
         
            +
                        "uint16": 1
         
     | 
| 
      
 174 
     | 
    
         
            +
                      }
         
     | 
| 
      
 175 
     | 
    
         
            +
                    },
         
     | 
| 
      
 176 
     | 
    
         
            +
                    "config_id": 9,
         
     | 
| 
      
 177 
     | 
    
         
            +
                    "enc": "0xe951022abd85cc53f16c92378ba736ea9d28b3a4106a6f2865323ea04fdf4075",
         
     | 
| 
      
 178 
     | 
    
         
            +
                    "payload": "0xbeef20fb3063fd807f6327213a5c5e37a0d355fc67c4c3a10362f947c7b72f06514db0e6bf470efb87d0db30669331caa3723441fb2850190851a9179b8b42e1e7f78bd0d281daf631872d9f7008624e24baef48ac8e18951fed9ad7d80def0b1bec492d5c5c2c532c4c8ec32b6dd3a34522c70c64e21ca639c7f54d2c3ad72c65ffda0dc1f82df5abf0857586eb17f0df08a15770a91d5c3640cff59b49b0fb3d19cf77137cd27416470e19db21519751c3d0ae417a62641903731408b4b81e008fff641d22a3300f92c8b9330d260055677c545a8d561076ecc3a4de5639120f6c67736df87a464ca221373c3bbe8e74dfe795eb43593f1d03d8668d49c4a9a73ed6d3264d7126bcfc93a975c8848170c57322b7c1bef210235bc79fd58bb4ff202d9e75bec3d2251a2429e11e5c7876edcca0685d52e1b99f51b46d0e723975a7c9d894e5674ef8debf380e799d75bff93c13e4917296242e2cb7b99bfcb0fc7cd8f98f414ceb0ef3a63fa29efc722194b91beb354efff5215b1804b9c555d4aad36a85e6eb3536b0b66fea50c9b055fa8441a36fc61a2228e0d4cb3c5ecb1662c641adf30a70c3b1104fb9b0f9b2c3130dc52939e9695a470774bee6dabc2691d06f870d01fe249199d831258583"
         
     | 
| 
      
 179 
     | 
    
         
            +
                  }
         
     | 
| 
      
 180 
     | 
    
         
            +
                }
         
     | 
| 
      
 181 
     | 
    
         
            +
              },
         
     | 
| 
      
 182 
     | 
    
         
            +
              "ClientHelloInner": {
         
     | 
| 
      
 183 
     | 
    
         
            +
                "msg_type": "0x01",
         
     | 
| 
      
 184 
     | 
    
         
            +
                "legacy_version": "0x0303",
         
     | 
| 
      
 185 
     | 
    
         
            +
                "random": "0x99f21aebeff5838b88011e581ade4de4eb334e5528efaf223dfa33c55d7bc20b",
         
     | 
| 
      
 186 
     | 
    
         
            +
                "legacy_session_id": "0x9c557bc381f62d73ba3b99629f8fe6e347787be66c56fa99db4f6bc6fd06fd5f",
         
     | 
| 
      
 187 
     | 
    
         
            +
                "cipher_suites": [
         
     | 
| 
      
 188 
     | 
    
         
            +
                  "0x1302",
         
     | 
| 
      
 189 
     | 
    
         
            +
                  "0x1303",
         
     | 
| 
      
 190 
     | 
    
         
            +
                  "0x1301"
         
     | 
| 
      
 191 
     | 
    
         
            +
                ],
         
     | 
| 
      
 192 
     | 
    
         
            +
                "legacy_compression_methods": [
         
     | 
| 
      
 193 
     | 
    
         
            +
                  "0x00"
         
     | 
| 
      
 194 
     | 
    
         
            +
                ],
         
     | 
| 
      
 195 
     | 
    
         
            +
                "extensions": {
         
     | 
| 
      
 196 
     | 
    
         
            +
                  "0x0000": {
         
     | 
| 
      
 197 
     | 
    
         
            +
                    "extension_type": "0x0000",
         
     | 
| 
      
 198 
     | 
    
         
            +
                    "server_name": "0x72657365617263682e636c6f7564666c6172652e636f6d"
         
     | 
| 
      
 199 
     | 
    
         
            +
                  },
         
     | 
| 
      
 200 
     | 
    
         
            +
                  "0x002b": {
         
     | 
| 
      
 201 
     | 
    
         
            +
                    "extension_type": "0x002b",
         
     | 
| 
      
 202 
     | 
    
         
            +
                    "msg_type": "0x01",
         
     | 
| 
      
 203 
     | 
    
         
            +
                    "versions": [
         
     | 
| 
      
 204 
     | 
    
         
            +
                      "0x0304"
         
     | 
| 
      
 205 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 206 
     | 
    
         
            +
                  },
         
     | 
| 
      
 207 
     | 
    
         
            +
                  "0x000d": {
         
     | 
| 
      
 208 
     | 
    
         
            +
                    "extension_type": "0x000d",
         
     | 
| 
      
 209 
     | 
    
         
            +
                    "supported_signature_algorithms": [
         
     | 
| 
      
 210 
     | 
    
         
            +
                      "0x0403",
         
     | 
| 
      
 211 
     | 
    
         
            +
                      "0x0503",
         
     | 
| 
      
 212 
     | 
    
         
            +
                      "0x0603",
         
     | 
| 
      
 213 
     | 
    
         
            +
                      "0x0804",
         
     | 
| 
      
 214 
     | 
    
         
            +
                      "0x0805",
         
     | 
| 
      
 215 
     | 
    
         
            +
                      "0x0806",
         
     | 
| 
      
 216 
     | 
    
         
            +
                      "0x0401",
         
     | 
| 
      
 217 
     | 
    
         
            +
                      "0x0501",
         
     | 
| 
      
 218 
     | 
    
         
            +
                      "0x0601"
         
     | 
| 
      
 219 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 220 
     | 
    
         
            +
                  },
         
     | 
| 
      
 221 
     | 
    
         
            +
                  "0x000a": {
         
     | 
| 
      
 222 
     | 
    
         
            +
                    "extension_type": "0x000a",
         
     | 
| 
      
 223 
     | 
    
         
            +
                    "named_group_list": [
         
     | 
| 
      
 224 
     | 
    
         
            +
                      "0x0017",
         
     | 
| 
      
 225 
     | 
    
         
            +
                      "0x0018",
         
     | 
| 
      
 226 
     | 
    
         
            +
                      "0x0019"
         
     | 
| 
      
 227 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 228 
     | 
    
         
            +
                  },
         
     | 
| 
      
 229 
     | 
    
         
            +
                  "0x0033": {
         
     | 
| 
      
 230 
     | 
    
         
            +
                    "extension_type": "0x0033",
         
     | 
| 
      
 231 
     | 
    
         
            +
                    "msg_type": "0x01",
         
     | 
| 
      
 232 
     | 
    
         
            +
                    "key_share_entry": [
         
     | 
| 
      
 233 
     | 
    
         
            +
                      {
         
     | 
| 
      
 234 
     | 
    
         
            +
                        "group": "0x0017",
         
     | 
| 
      
 235 
     | 
    
         
            +
                        "key_exchange": "0x0421747aa4234dbefc61906c165b8f1050b3346bb67f2c4ad8af9f58135888354a631b9b5c68f8ec1b6d6e67485a971bd3ff0ba6ab46da08f1524d7a4a3578c110"
         
     | 
| 
      
 236 
     | 
    
         
            +
                      },
         
     | 
| 
      
 237 
     | 
    
         
            +
                      {
         
     | 
| 
      
 238 
     | 
    
         
            +
                        "group": "0x0018",
         
     | 
| 
      
 239 
     | 
    
         
            +
                        "key_exchange": "0x046d374a61f2b75717b28b47b3fa227b51e09bb7a4ce0ea24b3cd3c946e9d4da2d54186b76812a74eb53adaa8a4451573201613b2f6301c05efb79bb6a782e88150dc3ac14aad702b8268aa8f3435d1a404166133216467aeb933247f994035fa0"
         
     | 
| 
      
 240 
     | 
    
         
            +
                      },
         
     | 
| 
      
 241 
     | 
    
         
            +
                      {
         
     | 
| 
      
 242 
     | 
    
         
            +
                        "group": "0x0019",
         
     | 
| 
      
 243 
     | 
    
         
            +
                        "key_exchange": "0x0401c90f95f64dc1e8d7d3f29f8a9103308835a2b56f5581ffc2837a1f9fcf6b23db824f01d6e4efccec78d6858aaad2fde8f02c2acc66a463c14b78e5e323b23d1b1301725b4f757811b7a31b4b5ee8016891ecb55b3fb997dd5738f6e610388f9bc85a4515efd04ab1d456e56d4e6e4a3a1e58a58ed6cf86f5dc9d7ace20afcd0af6b23b"
         
     | 
| 
      
 244 
     | 
    
         
            +
                      }
         
     | 
| 
      
 245 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 246 
     | 
    
         
            +
                  },
         
     | 
| 
      
 247 
     | 
    
         
            +
                  "0xfe0d": {
         
     | 
| 
      
 248 
     | 
    
         
            +
                    "extension_type": "0xfe0d",
         
     | 
| 
      
 249 
     | 
    
         
            +
                    "type": "0x01",
         
     | 
| 
      
 250 
     | 
    
         
            +
                    "cipher_suite": null,
         
     | 
| 
      
 251 
     | 
    
         
            +
                    "config_id": null,
         
     | 
| 
      
 252 
     | 
    
         
            +
                    "enc": null,
         
     | 
| 
      
 253 
     | 
    
         
            +
                    "payload": null
         
     | 
| 
      
 254 
     | 
    
         
            +
                  }
         
     | 
| 
      
 255 
     | 
    
         
            +
                }
         
     | 
| 
      
 256 
     | 
    
         
            +
              }
         
     | 
| 
      
 257 
     | 
    
         
            +
            }
         
     | 
| 
      
 258 
     | 
    
         
            +
            ```
         
     | 
| 
      
 259 
     | 
    
         
            +
             
     | 
| 
      
 260 
     | 
    
         
            +
            </details>
         
     | 
| 
      
 261 
     | 
    
         
            +
             
     | 
| 
      
 262 
     | 
    
         
            +
             
     | 
| 
      
 263 
     | 
    
         
            +
            ## Note
         
     | 
| 
      
 264 
     | 
    
         
            +
             
     | 
| 
      
 265 
     | 
    
         
            +
            `echspec` is inspired by:
         
     | 
| 
      
 266 
     | 
    
         
            +
             
     | 
| 
      
 267 
     | 
    
         
            +
            - https://github.com/summerwind/h2spec
         
     | 
| 
      
 268 
     | 
    
         
            +
             
     | 
| 
      
 269 
     | 
    
         
            +
             
     | 
| 
      
 270 
     | 
    
         
            +
            ## License
         
     | 
| 
      
 271 
     | 
    
         
            +
             
     | 
| 
      
 272 
     | 
    
         
            +
            `echspec` is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
         
     | 
    
        data/Rakefile
    ADDED
    
    
| 
         Binary file 
     | 
    
        data/echspec.gemspec
    ADDED
    
    | 
         @@ -0,0 +1,26 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            lib = File.expand_path('lib', __dir__)
         
     | 
| 
      
 2 
     | 
    
         
            +
            $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'echspec/version'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            Gem::Specification.new do |spec|
         
     | 
| 
      
 6 
     | 
    
         
            +
              spec.name          = 'echspec'
         
     | 
| 
      
 7 
     | 
    
         
            +
              spec.version       = EchSpec::VERSION
         
     | 
| 
      
 8 
     | 
    
         
            +
              spec.authors       = ['thekuwayama']
         
     | 
| 
      
 9 
     | 
    
         
            +
              spec.email         = ['thekuwayama@gmail.com']
         
     | 
| 
      
 10 
     | 
    
         
            +
              spec.summary       = 'A conformance testing tool for ECH implementation'
         
     | 
| 
      
 11 
     | 
    
         
            +
              spec.description   = spec.summary
         
     | 
| 
      
 12 
     | 
    
         
            +
              spec.homepage      = 'https://github.com/thekuwayama/echspec'
         
     | 
| 
      
 13 
     | 
    
         
            +
              spec.license       = 'MIT'
         
     | 
| 
      
 14 
     | 
    
         
            +
              spec.required_ruby_version = '>=3.2'
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
              spec.files         = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
         
     | 
| 
      
 17 
     | 
    
         
            +
              spec.test_files    = spec.files.grep(%r{^(test|spec|features)/})
         
     | 
| 
      
 18 
     | 
    
         
            +
              spec.require_paths = ['lib']
         
     | 
| 
      
 19 
     | 
    
         
            +
              spec.bindir        = 'exe'
         
     | 
| 
      
 20 
     | 
    
         
            +
              spec.executables   = ['echspec']
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
              spec.add_development_dependency 'bundler'
         
     | 
| 
      
 23 
     | 
    
         
            +
              spec.add_dependency             'base64'
         
     | 
| 
      
 24 
     | 
    
         
            +
              spec.add_dependency             'resolv', '> 0.4.0'
         
     | 
| 
      
 25 
     | 
    
         
            +
              spec.add_dependency             'tttls1.3', '~> 0.3.4'
         
     | 
| 
      
 26 
     | 
    
         
            +
            end
         
     | 
    
        data/exe/echspec
    ADDED
    
    
| 
         @@ -0,0 +1,7 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            -----BEGIN PRIVATE KEY-----
         
     | 
| 
      
 2 
     | 
    
         
            +
            MC4CAQAwBQYDK2VuBCIEICjd4yGRdsoP9gU7YT7My8DHx1Tjme8GYDXrOMCi8v1V
         
     | 
| 
      
 3 
     | 
    
         
            +
            -----END PRIVATE KEY-----
         
     | 
| 
      
 4 
     | 
    
         
            +
            -----BEGIN ECHCONFIG-----
         
     | 
| 
      
 5 
     | 
    
         
            +
            AD7+DQA65wAgACA8wVN2BtscOl3vQheUzHeIkVmKIiydUhDCliA4iyQRCwAEAAEA
         
     | 
| 
      
 6 
     | 
    
         
            +
            AQALZXhhbXBsZS5jb20AAA==
         
     | 
| 
      
 7 
     | 
    
         
            +
            -----END ECHCONFIG-----
         
     | 
    
        data/fixtures/server.crt
    ADDED
    
    | 
         @@ -0,0 +1,20 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            -----BEGIN CERTIFICATE-----
         
     | 
| 
      
 2 
     | 
    
         
            +
            MIIDOzCCAiOgAwIBAgIJAOOHBGEtaVlUMA0GCSqGSIb3DQEBCwUAMBwxGjAYBgNV
         
     | 
| 
      
 3 
     | 
    
         
            +
            BAMMEXRlc3QtaW50ZXJtZWRpYXRlMB4XDTI0MDUwMzIyNTgzOVoXDTI1MDUwMzIy
         
     | 
| 
      
 4 
     | 
    
         
            +
            NTgzOVowFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOC
         
     | 
| 
      
 5 
     | 
    
         
            +
            AQ8AMIIBCgKCAQEAyJ0/RY8esNtOCfdi3iR1VhPKpteACMybSZL+yvCr7HVWSIAF
         
     | 
| 
      
 6 
     | 
    
         
            +
            TK+sCN5ODdG+rnICvmmaLLF1aVwz9Jn0uW+MX3tejsDftw6CH7z/xblqPmEl2gTW
         
     | 
| 
      
 7 
     | 
    
         
            +
            vOdDSfJttaqSf1F+XQMadVov4YFweRAAI8uY4BTV4TLEfIK06xNNFqcMv5EmUyrv
         
     | 
| 
      
 8 
     | 
    
         
            +
            XEVW3ki7+7nOqMUH7nfNymR8ENU1YX8y4WpyfEyKw1Gk3PQH3iIQ5J7gqoDqlBYG
         
     | 
| 
      
 9 
     | 
    
         
            +
            083eLJau5qVDM/Q9Ro002tfmdpnJg+g59q9KstOQbTHKBYTP8YIotJhDOCl/fgoP
         
     | 
| 
      
 10 
     | 
    
         
            +
            g+r3gP6EAnMaE4XjsQTp7YDRiVnvF2lMqYC0QwIDAQABo4GHMIGEMAkGA1UdEwQC
         
     | 
| 
      
 11 
     | 
    
         
            +
            MAAwCwYDVR0PBAQDAgWgMBQGA1UdEQQNMAuCCWxvY2FsaG9zdDBUBggrBgEFBQcB
         
     | 
| 
      
 12 
     | 
    
         
            +
            AQRIMEYwIQYIKwYBBQUHMAKGFWh0dHA6Ly9sb2NhbGhvc3Q6ODA4MDAhBggrBgEF
         
     | 
| 
      
 13 
     | 
    
         
            +
            BQcwAYYVaHR0cDovL2xvY2FsaG9zdDo4MDgwMA0GCSqGSIb3DQEBCwUAA4IBAQA2
         
     | 
| 
      
 14 
     | 
    
         
            +
            ZuJuzDr3JARfqpi5C2yktW0Hiv0Dzx3g1vLeOGl6ZPPIxChxHKQ79BACM2FsVYcu
         
     | 
| 
      
 15 
     | 
    
         
            +
            ZGK7qGXpCMuzOuMjoCcfydXwjmoMlLtjAwXSKv5/ZT+SXWkO4weMKVQsovfBYDvr
         
     | 
| 
      
 16 
     | 
    
         
            +
            ktiHjJJV1ToPa1R4FsXIyNQDTByyT8D+8Fj3+et/I+JyxNrm65Rv6l+qapP6J5Fn
         
     | 
| 
      
 17 
     | 
    
         
            +
            oAVxoE7JFLcqvvRLH7/ggqMhUgftN4olzhUT2d6sThevsA9D6PWkcRuGvPWFMXkY
         
     | 
| 
      
 18 
     | 
    
         
            +
            R1ABD5sQynFvkcjjCcl+m7tOyqcmvwFFlS9X+ql4LLT8MHOOXhAGfxcD6qquVmvL
         
     | 
| 
      
 19 
     | 
    
         
            +
            Is1FlMw33rZEkugXwT0w
         
     | 
| 
      
 20 
     | 
    
         
            +
            -----END CERTIFICATE-----
         
     | 
    
        data/fixtures/server.key
    ADDED
    
    | 
         @@ -0,0 +1,27 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            -----BEGIN RSA PRIVATE KEY-----
         
     | 
| 
      
 2 
     | 
    
         
            +
            MIIEpAIBAAKCAQEAyJ0/RY8esNtOCfdi3iR1VhPKpteACMybSZL+yvCr7HVWSIAF
         
     | 
| 
      
 3 
     | 
    
         
            +
            TK+sCN5ODdG+rnICvmmaLLF1aVwz9Jn0uW+MX3tejsDftw6CH7z/xblqPmEl2gTW
         
     | 
| 
      
 4 
     | 
    
         
            +
            vOdDSfJttaqSf1F+XQMadVov4YFweRAAI8uY4BTV4TLEfIK06xNNFqcMv5EmUyrv
         
     | 
| 
      
 5 
     | 
    
         
            +
            XEVW3ki7+7nOqMUH7nfNymR8ENU1YX8y4WpyfEyKw1Gk3PQH3iIQ5J7gqoDqlBYG
         
     | 
| 
      
 6 
     | 
    
         
            +
            083eLJau5qVDM/Q9Ro002tfmdpnJg+g59q9KstOQbTHKBYTP8YIotJhDOCl/fgoP
         
     | 
| 
      
 7 
     | 
    
         
            +
            g+r3gP6EAnMaE4XjsQTp7YDRiVnvF2lMqYC0QwIDAQABAoIBAAzYZ2e9zUTyazcf
         
     | 
| 
      
 8 
     | 
    
         
            +
            fFjQVCRfKg0FeXDsIPlUtzR+tT4ebpg/0kG3HI3eJiNOYyY/rfChSbpDi/VjblQ4
         
     | 
| 
      
 9 
     | 
    
         
            +
            KL+tkSW//C2p0z6hEts+D9E07m+batVglUYNN3VxrMKtbv9F/uWtFYb0GmLBwKuP
         
     | 
| 
      
 10 
     | 
    
         
            +
            xw0uXoCNSlCcHpFWZofdeYR8zR0q7L64P8EsqjrYGOTeyQWKshHIxAAks6Xb19zW
         
     | 
| 
      
 11 
     | 
    
         
            +
            h4f3aBTZ3tWHCMAZj8LsGVG4O2Nx9esuKwybe0vBMkv/esyEVXEPm+RDjQtlKGqQ
         
     | 
| 
      
 12 
     | 
    
         
            +
            i4V03ykI6LbIwi8bk3H7jItGKX8fNK9CNMi0ZEyYgvVe5HQciJBtcaWUiBUEHhum
         
     | 
| 
      
 13 
     | 
    
         
            +
            N0Np7uECgYEA6jsG72P5GleyRIBAUNrN/a1yIc9b9RXZS63lCb5UMMW6rYuP8wRe
         
     | 
| 
      
 14 
     | 
    
         
            +
            1ARzCNhkzYoKxay3ZQHPW8deDasTXCPiIkJqRDfDRr464OQ29qBEWx4aWtVbAsuH
         
     | 
| 
      
 15 
     | 
    
         
            +
            8/SJK45YpvdCSxT3wBzTzzff4bAIF7yFYBJjVBEs948TrtGePlvpyBMCgYEA20Jl
         
     | 
| 
      
 16 
     | 
    
         
            +
            xpQUorhEXn4JOjC65FHj3hJgPus8JgPSLpjpuDs9WZBN3mRt7GIZ0Tb6gA/Yv2wn
         
     | 
| 
      
 17 
     | 
    
         
            +
            Ps0u2iCe7uGKC5XEQ84KrtcM+rk7mRGsdWxQqnJp6tbZbHqGqF0Y9uBqOgRiJJTm
         
     | 
| 
      
 18 
     | 
    
         
            +
            i9L1QiHnkrtlwMdlQRXQvPvwG4Z5OU/W4D7/SRECgYEAr/wZgdPDXZ92OTGDITzE
         
     | 
| 
      
 19 
     | 
    
         
            +
            eEzQ68Y4eTQpR0soQuHVr69gSvQI+7XU6cdOBt9PHX8SCON0B1gMzBBHAk3/BcOQ
         
     | 
| 
      
 20 
     | 
    
         
            +
            K91qqkabWZOj+UR+Z16S/ULo2kZjUv5I72pThX417XzpOjBO1PDT02VPuOnhqrPi
         
     | 
| 
      
 21 
     | 
    
         
            +
            IgSuzIL7HiVJzJeCJag5RjECgYBhAiuNhI7sv6JgPFtQx6aoxiKPaonyzJk8KIyh
         
     | 
| 
      
 22 
     | 
    
         
            +
            2T3vKSanrdUGBGEuKOlLS4vhhSFc8Dkc7CNClxQ6lMdDAOxpI4xOdw9jDvlzbAJl
         
     | 
| 
      
 23 
     | 
    
         
            +
            oZq/DwgVwyFHgZ56d1ZIRFo7eR0DGm42hwvESsPug8MtXAtMlJ5aPw2o4AJafRyQ
         
     | 
| 
      
 24 
     | 
    
         
            +
            8s54QQKBgQCnaQcbPdoNrnn1giz6s1XNKMayIfod8tPS+xnKJpGzjyDVQzEDWA05
         
     | 
| 
      
 25 
     | 
    
         
            +
            pEp1GFMaNXjUa8ICj/DeZ630ZfODDboTp3JVKLe+QW3U89H60AJz/0UnZ8k/fNwA
         
     | 
| 
      
 26 
     | 
    
         
            +
            39CfIk3ukQS4oAWpMua2s2e9Vf7zXHM/sm07R8BKo0wtoUEg3RtCYQ==
         
     | 
| 
      
 27 
     | 
    
         
            +
            -----END RSA PRIVATE KEY-----
         
     | 
    
        data/lib/echspec/cli.rb
    ADDED
    
    | 
         @@ -0,0 +1,97 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module EchSpec
         
     | 
| 
      
 2 
     | 
    
         
            +
              class CLI
         
     | 
| 
      
 3 
     | 
    
         
            +
                # rubocop: disable Metrics/AbcSize
         
     | 
| 
      
 4 
     | 
    
         
            +
                # rubocop: disable Metrics/MethodLength
         
     | 
| 
      
 5 
     | 
    
         
            +
                def parse_options(argv = ARGV)
         
     | 
| 
      
 6 
     | 
    
         
            +
                  op = OptionParser.new
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  # default value
         
     | 
| 
      
 9 
     | 
    
         
            +
                  fpath = nil
         
     | 
| 
      
 10 
     | 
    
         
            +
                  port = 443
         
     | 
| 
      
 11 
     | 
    
         
            +
                  force_compliant = true
         
     | 
| 
      
 12 
     | 
    
         
            +
                  verbose = false
         
     | 
| 
      
 13 
     | 
    
         
            +
                  sections = nil
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  op.on(
         
     | 
| 
      
 16 
     | 
    
         
            +
                    '-f',
         
     | 
| 
      
 17 
     | 
    
         
            +
                    '--file FILE',
         
     | 
| 
      
 18 
     | 
    
         
            +
                    'path to ECHConfigs PEM file       (default resolve ECHConfigs via DNS)'
         
     | 
| 
      
 19 
     | 
    
         
            +
                  ) do |v|
         
     | 
| 
      
 20 
     | 
    
         
            +
                    fpath = v
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                  op.on(
         
     | 
| 
      
 24 
     | 
    
         
            +
                    '-p',
         
     | 
| 
      
 25 
     | 
    
         
            +
                    '--port VALUE',
         
     | 
| 
      
 26 
     | 
    
         
            +
                    "server port number                (default #{port})"
         
     | 
| 
      
 27 
     | 
    
         
            +
                  ) do |v|
         
     | 
| 
      
 28 
     | 
    
         
            +
                    port = v
         
     | 
| 
      
 29 
     | 
    
         
            +
                  end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                  op.on(
         
     | 
| 
      
 32 
     | 
    
         
            +
                    '-n',
         
     | 
| 
      
 33 
     | 
    
         
            +
                    '--not-force-compliant-hpke',
         
     | 
| 
      
 34 
     | 
    
         
            +
                    'not force compliant ECHConfig HPKE cipher suite'
         
     | 
| 
      
 35 
     | 
    
         
            +
                  ) do
         
     | 
| 
      
 36 
     | 
    
         
            +
                    force_compliant = false
         
     | 
| 
      
 37 
     | 
    
         
            +
                  end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  op.on(
         
     | 
| 
      
 40 
     | 
    
         
            +
                    '-v',
         
     | 
| 
      
 41 
     | 
    
         
            +
                    '--verbose',
         
     | 
| 
      
 42 
     | 
    
         
            +
                    'verbose mode; prints message stack if raised an error'
         
     | 
| 
      
 43 
     | 
    
         
            +
                  ) do
         
     | 
| 
      
 44 
     | 
    
         
            +
                    verbose = true
         
     | 
| 
      
 45 
     | 
    
         
            +
                  end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                  op.on(
         
     | 
| 
      
 48 
     | 
    
         
            +
                    '-s',
         
     | 
| 
      
 49 
     | 
    
         
            +
                    '--sections SECTIONS',
         
     | 
| 
      
 50 
     | 
    
         
            +
                    'sections to test; by the default, test all sections'
         
     | 
| 
      
 51 
     | 
    
         
            +
                  ) do |v|
         
     | 
| 
      
 52 
     | 
    
         
            +
                    sections = v.split(',')
         
     | 
| 
      
 53 
     | 
    
         
            +
                  end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                  op.banner = 'Usage: echspec [OPTIONS] <HOSTNAME>'
         
     | 
| 
      
 56 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 57 
     | 
    
         
            +
                    args = op.parse(argv)
         
     | 
| 
      
 58 
     | 
    
         
            +
                  rescue OptionParser::InvalidOption, OptionParser::MissingArgument => e
         
     | 
| 
      
 59 
     | 
    
         
            +
                    warn op
         
     | 
| 
      
 60 
     | 
    
         
            +
                    warn "** #{e.message}"
         
     | 
| 
      
 61 
     | 
    
         
            +
                    exit 1
         
     | 
| 
      
 62 
     | 
    
         
            +
                  end
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                  if !fpath.nil? && !File.exist?(fpath)
         
     | 
| 
      
 65 
     | 
    
         
            +
                    warn '** <FILE> is not found'
         
     | 
| 
      
 66 
     | 
    
         
            +
                    exit 1
         
     | 
| 
      
 67 
     | 
    
         
            +
                  end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                  unknowns = sections.nil? ? [] : sections - Spec.sections
         
     | 
| 
      
 70 
     | 
    
         
            +
                  unless unknowns.empty?
         
     | 
| 
      
 71 
     | 
    
         
            +
                    warn "** #{unknowns} are unknown sections"
         
     | 
| 
      
 72 
     | 
    
         
            +
                    exit 1
         
     | 
| 
      
 73 
     | 
    
         
            +
                  end
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
                  if args.length != 1
         
     | 
| 
      
 76 
     | 
    
         
            +
                    warn op
         
     | 
| 
      
 77 
     | 
    
         
            +
                    warn '** <HOSTNAME> argument is not specified'
         
     | 
| 
      
 78 
     | 
    
         
            +
                    exit 1
         
     | 
| 
      
 79 
     | 
    
         
            +
                  end
         
     | 
| 
      
 80 
     | 
    
         
            +
                  hostname = args[0]
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
                  [fpath, port, force_compliant, verbose, hostname, sections]
         
     | 
| 
      
 83 
     | 
    
         
            +
                end
         
     | 
| 
      
 84 
     | 
    
         
            +
                # rubocop: enable Metrics/AbcSize
         
     | 
| 
      
 85 
     | 
    
         
            +
                # rubocop: enable Metrics/MethodLength
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                def run
         
     | 
| 
      
 88 
     | 
    
         
            +
                  fpath, port, force_compliant, verbose, hostname, sections = parse_options
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
                  if sections.nil?
         
     | 
| 
      
 91 
     | 
    
         
            +
                    Spec.run(fpath, port, hostname, force_compliant, verbose)
         
     | 
| 
      
 92 
     | 
    
         
            +
                  else
         
     | 
| 
      
 93 
     | 
    
         
            +
                    Spec.run_only(fpath, port, hostname, sections, verbose)
         
     | 
| 
      
 94 
     | 
    
         
            +
                  end
         
     | 
| 
      
 95 
     | 
    
         
            +
                end
         
     | 
| 
      
 96 
     | 
    
         
            +
              end
         
     | 
| 
      
 97 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,9 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module EchSpec
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Error
         
     | 
| 
      
 3 
     | 
    
         
            +
                # Generic error, common for all classes under EchSpec::Error module.
         
     | 
| 
      
 4 
     | 
    
         
            +
                class Error < StandardError; end
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                # Raised if the server behaves unintended before the target situation.
         
     | 
| 
      
 7 
     | 
    
         
            +
                class BeforeTargetSituationError < Error; end
         
     | 
| 
      
 8 
     | 
    
         
            +
              end
         
     | 
| 
      
 9 
     | 
    
         
            +
            end
         
     |