tttls1.3 0.1.4 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -0
- data/README.md +35 -13
- data/Rakefile +2 -4
- data/example/helper.rb +30 -7
- data/example/https_client.rb +3 -20
- data/example/https_client_using_0rtt.rb +10 -24
- data/example/https_client_using_hrr.rb +3 -20
- data/example/https_client_using_ticket.rb +3 -20
- data/example/https_server.rb +43 -0
- data/interop/client_spec.rb +111 -22
- data/interop/helper.rb +1 -0
- data/interop/server_spec.rb +182 -0
- data/lib/tttls1.3/client.rb +115 -98
- data/lib/tttls1.3/connection.rb +119 -32
- data/lib/tttls1.3/message/certificate.rb +18 -0
- data/lib/tttls1.3/message/client_hello.rb +38 -0
- data/lib/tttls1.3/message/encrypted_extensions.rb +20 -16
- data/lib/tttls1.3/message/extension/key_share.rb +24 -2
- data/lib/tttls1.3/message/extension/supported_groups.rb +0 -87
- data/lib/tttls1.3/message/extensions.rb +1 -27
- data/lib/tttls1.3/message/new_session_ticket.rb +14 -0
- data/lib/tttls1.3/message/record.rb +23 -20
- data/lib/tttls1.3/message/server_hello.rb +27 -0
- data/lib/tttls1.3/message.rb +35 -2
- data/lib/tttls1.3/named_group.rb +89 -0
- data/lib/tttls1.3/server.rb +439 -0
- data/lib/tttls1.3/transcript.rb +6 -0
- data/lib/tttls1.3/version.rb +1 -1
- data/lib/tttls1.3.rb +3 -0
- data/spec/certificate_spec.rb +28 -1
- data/spec/client_spec.rb +14 -10
- data/spec/connection_spec.rb +43 -13
- data/spec/encrypted_extensions_spec.rb +4 -4
- data/spec/fixtures/rsa_ca.crt +29 -0
- data/spec/fixtures/rsa_ca.key +51 -0
- data/spec/fixtures/rsa_rsa.crt +23 -0
- data/spec/fixtures/rsa_rsa.key +27 -0
- data/spec/fixtures/rsa_secp256r1.crt +19 -0
- data/spec/fixtures/rsa_secp256r1.key +5 -0
- data/spec/fixtures/rsa_secp384r1.crt +19 -0
- data/spec/fixtures/rsa_secp384r1.key +6 -0
- data/spec/fixtures/rsa_secp521r1.crt +20 -0
- data/spec/fixtures/rsa_secp521r1.key +7 -0
- data/spec/server_spec.rb +186 -0
- data/spec/spec_helper.rb +43 -0
- metadata +28 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 39cf5b4e5fd508981bdefedc27502ac14b984699983d44160d9a836b2ab2aa2b
         | 
| 4 | 
            +
              data.tar.gz: 0250c8ad97ef5bef6a52d7b6e22c990b842ce66a8ab6e2d3abc0c6ef90a4eb13
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: e8ef15683ceabb9396eb51e5831f3dc48ed9c4df11871f10458160804891107fe3bff2d0c1810ad294134c8bec4d63534b2aee7cc6c8bff5f7ae07462bf753ef
         | 
| 7 | 
            +
              data.tar.gz: 7baf720c22742962380449ad01372264634e878113858643cdc8a0db55e0f0cf07e0bd45cd80ad461cab9a337c89c7e0ad9c0e0057e02cbcda77a0765f10bdb9
         | 
    
        data/.rubocop.yml
    CHANGED
    
    
    
        data/README.md
    CHANGED
    
    | @@ -12,29 +12,18 @@ Backward compatibility and performance are not an objective. | |
| 12 12 | 
             
            This gem should not be used for production software.
         | 
| 13 13 |  | 
| 14 14 |  | 
| 15 | 
            -
            ## Features
         | 
| 16 | 
            -
             | 
| 17 | 
            -
            tttls1.3 provides client API with the following features:
         | 
| 18 | 
            -
             | 
| 19 | 
            -
            * Simple 1-RTT Handshake
         | 
| 20 | 
            -
            * HelloRetryRequest
         | 
| 21 | 
            -
            * Resumed 0-RTT Handshake (with PSK from ticket)
         | 
| 22 | 
            -
             | 
| 23 | 
            -
            NOT supports X25519, X448, FFDHE, AES-CCM, Client Authentication, Post-Handshake Authentication, KeyUpdate, external PSKs.
         | 
| 24 | 
            -
             | 
| 25 | 
            -
             | 
| 26 15 | 
             
            ## Getting started
         | 
| 27 16 |  | 
| 28 17 | 
             
            tttls1.3 gem is available at [rubygems.org](https://rubygems.org/gems/tttls1.3). You can install with:
         | 
| 29 18 |  | 
| 30 | 
            -
            ```
         | 
| 19 | 
            +
            ```bash
         | 
| 31 20 | 
             
            $ gem install tttls1.3
         | 
| 32 21 | 
             
            ```
         | 
| 33 22 |  | 
| 34 23 | 
             
            This implementation provides only minimal API, so your code is responsible for application layer.
         | 
| 35 24 | 
             
            Roughly, this works as follows:
         | 
| 36 25 |  | 
| 37 | 
            -
            ```
         | 
| 26 | 
            +
            ```ruby
         | 
| 38 27 | 
             
            require 'tttls1.3'
         | 
| 39 28 |  | 
| 40 29 | 
             
            socket = YourTransport.new
         | 
| @@ -46,9 +35,42 @@ client.read | |
| 46 35 | 
             
            client.close
         | 
| 47 36 | 
             
            ```
         | 
| 48 37 |  | 
| 38 | 
            +
            ```ruby
         | 
| 39 | 
            +
            require 'tttls1.3'
         | 
| 40 | 
            +
             | 
| 41 | 
            +
            socket = YourTransport.new
         | 
| 42 | 
            +
            server = TTTLS13::Server.new(socket.accept)
         | 
| 43 | 
            +
            server.accept
         | 
| 44 | 
            +
             | 
| 45 | 
            +
            server.read
         | 
| 46 | 
            +
            server.write(YOUR_MESSAGE)
         | 
| 47 | 
            +
            server.close
         | 
| 48 | 
            +
            ```
         | 
| 49 | 
            +
             | 
| 49 50 | 
             
            HTTPS examples are [here](https://github.com/thekuwayama/tttls1.3/tree/master/example).
         | 
| 50 51 |  | 
| 51 52 |  | 
| 53 | 
            +
            ## Features
         | 
| 54 | 
            +
             | 
| 55 | 
            +
            ### Client
         | 
| 56 | 
            +
             | 
| 57 | 
            +
            tttls1.3 provides client API with the following features:
         | 
| 58 | 
            +
             | 
| 59 | 
            +
            * Simple 1-RTT Handshake
         | 
| 60 | 
            +
            * HelloRetryRequest
         | 
| 61 | 
            +
            * Resumed 0-RTT Handshake (with PSK from ticket)
         | 
| 62 | 
            +
             | 
| 63 | 
            +
            **NOT supports** certificate with OID RSASSA-PSS, X25519, X448, FFDHE, AES-CCM, Client Authentication, Post-Handshake Authentication, KeyUpdate, external PSKs.
         | 
| 64 | 
            +
             | 
| 65 | 
            +
            ### Server
         | 
| 66 | 
            +
             | 
| 67 | 
            +
            tttls1.3 provides server API with the following features:
         | 
| 68 | 
            +
             | 
| 69 | 
            +
            * Simple 1-RTT Handshake
         | 
| 70 | 
            +
             | 
| 71 | 
            +
            **NOT supports** certificate with OID RSASSA-PSS, X25519, X448, FFDHE, AES-CCM, Client Authentication, Post-Handshake Authentication, KeyUpdate, external PSKs.
         | 
| 72 | 
            +
             | 
| 73 | 
            +
             | 
| 52 74 | 
             
            ## License
         | 
| 53 75 |  | 
| 54 76 | 
             
            The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
         | 
    
        data/Rakefile
    CHANGED
    
    | @@ -6,8 +6,6 @@ require 'rspec/core/rake_task' | |
| 6 6 | 
             
            require 'openssl'
         | 
| 7 7 | 
             
            require 'fileutils'
         | 
| 8 8 |  | 
| 9 | 
            -
            RuboCop::RakeTask.new
         | 
| 10 | 
            -
             | 
| 11 9 | 
             
            TMP_DIR    = __dir__ + '/tmp'
         | 
| 12 10 | 
             
            CA_KEY     = TMP_DIR + '/ca.key'
         | 
| 13 11 | 
             
            CA_CRT     = TMP_DIR + '/ca.crt'
         | 
| @@ -128,6 +126,6 @@ task :del_certs do | |
| 128 126 | 
             
              end
         | 
| 129 127 | 
             
            end
         | 
| 130 128 |  | 
| 131 | 
            -
             | 
| 132 | 
            -
             | 
| 129 | 
            +
            RuboCop::RakeTask.new
         | 
| 130 | 
            +
            RSpec::Core::RakeTask.new(:spec)
         | 
| 133 131 | 
             
            task default: %i[rubocop spec]
         | 
    
        data/example/helper.rb
    CHANGED
    
    | @@ -4,13 +4,36 @@ $LOAD_PATH << __dir__ + '/../lib' | |
| 4 4 |  | 
| 5 5 | 
             
            require 'socket'
         | 
| 6 6 | 
             
            require 'tttls1.3'
         | 
| 7 | 
            +
            require 'webrick'
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            def simple_http_request(hostname)
         | 
| 10 | 
            +
              s = <<~BIN
         | 
| 11 | 
            +
                GET / HTTP/1.1
         | 
| 12 | 
            +
                Host: #{hostname}
         | 
| 13 | 
            +
                User-Agent: https_client
         | 
| 14 | 
            +
                Accept: */*
         | 
| 7 15 |  | 
| 8 | 
            -
            def http_get(hostname)
         | 
| 9 | 
            -
              <<~BIN
         | 
| 10 | 
            -
                GET / HTTP/1.1\r
         | 
| 11 | 
            -
                Host: #{hostname}\r
         | 
| 12 | 
            -
                User-Agent: https_client\r
         | 
| 13 | 
            -
                Accept: */*\r
         | 
| 14 | 
            -
                \r
         | 
| 15 16 | 
             
              BIN
         | 
| 17 | 
            +
              s.gsub("\n", "\r\n")
         | 
| 18 | 
            +
            end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            def recv_http_response(client)
         | 
| 21 | 
            +
              # status line, header
         | 
| 22 | 
            +
              buf = ''
         | 
| 23 | 
            +
              buf += client.read until buf.include?(WEBrick::CRLF * 2)
         | 
| 24 | 
            +
              header = buf.split(WEBrick::CRLF * 2).first
         | 
| 25 | 
            +
              # header; Content-Length
         | 
| 26 | 
            +
              cl_line = header.split(WEBrick::CRLF).find { |s| s.match(/Content-Length:/i) }
         | 
| 27 | 
            +
             | 
| 28 | 
            +
              # body
         | 
| 29 | 
            +
              unless cl_line.nil?
         | 
| 30 | 
            +
                cl = cl_line.split(':').last.to_i
         | 
| 31 | 
            +
                buf = buf.split(WEBrick::CRLF * 2)[1..].join
         | 
| 32 | 
            +
                while buf.length < cl
         | 
| 33 | 
            +
                  s = client.read
         | 
| 34 | 
            +
                  buf += s
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
              end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
              header + WEBrick::CRLF * 2 + buf
         | 
| 16 39 | 
             
            end
         | 
    
        data/example/https_client.rb
    CHANGED
    
    | @@ -4,29 +4,12 @@ | |
| 4 4 | 
             
            require_relative 'helper'
         | 
| 5 5 |  | 
| 6 6 | 
             
            hostname, port = (ARGV[0] || 'localhost:4433').split(':')
         | 
| 7 | 
            -
             | 
| 7 | 
            +
            req = simple_http_request(hostname)
         | 
| 8 8 |  | 
| 9 9 | 
             
            socket = TCPSocket.new(hostname, port)
         | 
| 10 10 | 
             
            settings = { ca_file: __dir__ + '/../tmp/ca.crt' }
         | 
| 11 11 | 
             
            client = TTTLS13::Client.new(socket, hostname, settings)
         | 
| 12 12 | 
             
            client.connect
         | 
| 13 | 
            -
            client.write( | 
| 14 | 
            -
             | 
| 15 | 
            -
            # status line, header
         | 
| 16 | 
            -
            buffer = ''
         | 
| 17 | 
            -
            buffer += client.read until buffer.include?("\r\n\r\n")
         | 
| 18 | 
            -
            print header = buffer.split("\r\n\r\n").first
         | 
| 19 | 
            -
            # header; Content-Length
         | 
| 20 | 
            -
            cl_line = header.split("\r\n").find { |s| s.match(/Content-Length:/i) }
         | 
| 21 | 
            -
             | 
| 22 | 
            -
            # body
         | 
| 23 | 
            -
            unless cl_line.nil?
         | 
| 24 | 
            -
              cl = cl_line.split(':').last.to_i
         | 
| 25 | 
            -
              print buffer = buffer.split("\r\n\r\n")[1..].join
         | 
| 26 | 
            -
              while buffer.length < cl
         | 
| 27 | 
            -
                print s = client.read
         | 
| 28 | 
            -
                buffer += s
         | 
| 29 | 
            -
              end
         | 
| 30 | 
            -
            end
         | 
| 31 | 
            -
             | 
| 13 | 
            +
            client.write(req)
         | 
| 14 | 
            +
            print recv_http_response(client)
         | 
| 32 15 | 
             
            client.close
         | 
| @@ -4,7 +4,7 @@ | |
| 4 4 | 
             
            require_relative 'helper'
         | 
| 5 5 |  | 
| 6 6 | 
             
            hostname, port = (ARGV[0] || 'localhost:4433').split(':')
         | 
| 7 | 
            -
             | 
| 7 | 
            +
            req = simple_http_request(hostname)
         | 
| 8 8 |  | 
| 9 9 | 
             
            settings_2nd = {
         | 
| 10 10 | 
             
              ca_file: __dir__ + '/../tmp/ca.crt'
         | 
| @@ -23,7 +23,9 @@ settings_1st = { | |
| 23 23 | 
             
              ca_file: __dir__ + '/../tmp/ca.crt',
         | 
| 24 24 | 
             
              process_new_session_ticket: process_new_session_ticket
         | 
| 25 25 | 
             
            }
         | 
| 26 | 
            -
             | 
| 26 | 
            +
             | 
| 27 | 
            +
            succeed_early_data = false
         | 
| 28 | 
            +
             | 
| 27 29 | 
             
            [
         | 
| 28 30 | 
             
              # Initial Handshake:
         | 
| 29 31 | 
             
              settings_1st,
         | 
| @@ -34,31 +36,15 @@ accepted_early_data = false | |
| 34 36 | 
             
              client = TTTLS13::Client.new(socket, hostname, settings)
         | 
| 35 37 |  | 
| 36 38 | 
             
              # send message using early data; 0-RTT
         | 
| 37 | 
            -
              client.early_data( | 
| 39 | 
            +
              client.early_data(req) if i == 1 && settings.include?(:ticket)
         | 
| 38 40 | 
             
              client.connect
         | 
| 39 41 | 
             
              # send message after Simple 1-RTT Handshake
         | 
| 40 | 
            -
              client.write( | 
| 41 | 
            -
             | 
| 42 | 
            -
              # status line, header
         | 
| 43 | 
            -
              buffer = ''
         | 
| 44 | 
            -
              buffer += client.read until buffer.include?("\r\n\r\n")
         | 
| 45 | 
            -
              print header = buffer.split("\r\n\r\n").first
         | 
| 46 | 
            -
              # header; Content-Length
         | 
| 47 | 
            -
              cl_line = header.split("\r\n").find { |s| s.match(/Content-Length:/i) }
         | 
| 48 | 
            -
             | 
| 49 | 
            -
              # body
         | 
| 50 | 
            -
              unless cl_line.nil?
         | 
| 51 | 
            -
                cl = cl_line.split(':').last.to_i
         | 
| 52 | 
            -
                print buffer = buffer.split("\r\n\r\n")[1..].join
         | 
| 53 | 
            -
                while buffer.length < cl
         | 
| 54 | 
            -
                  print s = client.read
         | 
| 55 | 
            -
                  buffer += s
         | 
| 56 | 
            -
                end
         | 
| 57 | 
            -
              end
         | 
| 58 | 
            -
             | 
| 42 | 
            +
              client.write(req) if i.zero? || !client.succeed_early_data?
         | 
| 43 | 
            +
              print recv_http_response(client)
         | 
| 59 44 | 
             
              client.close
         | 
| 60 | 
            -
             | 
| 45 | 
            +
             | 
| 46 | 
            +
              succeed_early_data = client.succeed_early_data?
         | 
| 61 47 | 
             
            end
         | 
| 62 48 |  | 
| 63 49 | 
             
            puts "\n" + '-' * 10
         | 
| 64 | 
            -
            puts "early data of 2nd handshake: #{ | 
| 50 | 
            +
            puts "early data of 2nd handshake: #{succeed_early_data}"
         | 
| @@ -4,7 +4,7 @@ | |
| 4 4 | 
             
            require_relative 'helper'
         | 
| 5 5 |  | 
| 6 6 | 
             
            hostname, port = (ARGV[0] || 'localhost:4433').split(':')
         | 
| 7 | 
            -
             | 
| 7 | 
            +
            req = simple_http_request(hostname)
         | 
| 8 8 |  | 
| 9 9 | 
             
            socket = TCPSocket.new(hostname, port)
         | 
| 10 10 | 
             
            settings = {
         | 
| @@ -13,23 +13,6 @@ settings = { | |
| 13 13 | 
             
            }
         | 
| 14 14 | 
             
            client = TTTLS13::Client.new(socket, hostname, settings)
         | 
| 15 15 | 
             
            client.connect
         | 
| 16 | 
            -
            client.write( | 
| 17 | 
            -
             | 
| 18 | 
            -
            # status line, header
         | 
| 19 | 
            -
            buffer = ''
         | 
| 20 | 
            -
            buffer += client.read until buffer.include?("\r\n\r\n")
         | 
| 21 | 
            -
            print header = buffer.split("\r\n\r\n").first
         | 
| 22 | 
            -
            # header; Content-Length
         | 
| 23 | 
            -
            cl_line = header.split("\r\n").find { |s| s.match(/Content-Length:/i) }
         | 
| 24 | 
            -
             | 
| 25 | 
            -
            # body
         | 
| 26 | 
            -
            unless cl_line.nil?
         | 
| 27 | 
            -
              cl = cl_line.split(':').last.to_i
         | 
| 28 | 
            -
              print buffer = buffer.split("\r\n\r\n")[1..].join
         | 
| 29 | 
            -
              while buffer.length < cl
         | 
| 30 | 
            -
                print s = client.read
         | 
| 31 | 
            -
                buffer += s
         | 
| 32 | 
            -
              end
         | 
| 33 | 
            -
            end
         | 
| 34 | 
            -
             | 
| 16 | 
            +
            client.write(req)
         | 
| 17 | 
            +
            print recv_http_response(client)
         | 
| 35 18 | 
             
            client.close
         | 
| @@ -4,7 +4,7 @@ | |
| 4 4 | 
             
            require_relative 'helper'
         | 
| 5 5 |  | 
| 6 6 | 
             
            hostname, port = (ARGV[0] || 'localhost:4433').split(':')
         | 
| 7 | 
            -
             | 
| 7 | 
            +
            req = simple_http_request(hostname)
         | 
| 8 8 |  | 
| 9 9 | 
             
            settings_2nd = {
         | 
| 10 10 | 
             
              ca_file: __dir__ + '/../tmp/ca.crt'
         | 
| @@ -33,24 +33,7 @@ settings_1st = { | |
| 33 33 | 
             
              socket = TCPSocket.new(hostname, port)
         | 
| 34 34 | 
             
              client = TTTLS13::Client.new(socket, hostname, settings)
         | 
| 35 35 | 
             
              client.connect
         | 
| 36 | 
            -
              client.write( | 
| 37 | 
            -
             | 
| 38 | 
            -
              # status line, header
         | 
| 39 | 
            -
              buffer = ''
         | 
| 40 | 
            -
              buffer += client.read until buffer.include?("\r\n\r\n")
         | 
| 41 | 
            -
              print header = buffer.split("\r\n\r\n").first
         | 
| 42 | 
            -
              # header; Content-Length
         | 
| 43 | 
            -
              cl_line = header.split("\r\n").find { |s| s.match(/Content-Length:/i) }
         | 
| 44 | 
            -
             | 
| 45 | 
            -
              # body
         | 
| 46 | 
            -
              unless cl_line.nil?
         | 
| 47 | 
            -
                cl = cl_line.split(':').last.to_i
         | 
| 48 | 
            -
                print buffer = buffer.split("\r\n\r\n")[1..].join
         | 
| 49 | 
            -
                while buffer.length < cl
         | 
| 50 | 
            -
                  print s = client.read
         | 
| 51 | 
            -
                  buffer += s
         | 
| 52 | 
            -
                end
         | 
| 53 | 
            -
              end
         | 
| 54 | 
            -
             | 
| 36 | 
            +
              client.write(req)
         | 
| 37 | 
            +
              print recv_http_response(client)
         | 
| 55 38 | 
             
              client.close
         | 
| 56 39 | 
             
            end
         | 
| @@ -0,0 +1,43 @@ | |
| 1 | 
            +
            # encoding: ascii-8bit
         | 
| 2 | 
            +
            # frozen_string_literal: true
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            require_relative 'helper'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            port = ARGV[0] || 4433
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            tcpserver = TCPServer.open(port)
         | 
| 9 | 
            +
            settings = { crt_file: __dir__ + '/../tmp/server.crt',
         | 
| 10 | 
            +
                         key_file: __dir__ + '/../tmp/server.key' }
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            # rubocop: disable Metrics/BlockLength
         | 
| 13 | 
            +
            loop do
         | 
| 14 | 
            +
              socket = tcpserver.accept
         | 
| 15 | 
            +
              Thread.start(socket) do |s|
         | 
| 16 | 
            +
                Timeout.timeout(5) do
         | 
| 17 | 
            +
                  server = TTTLS13::Server.new(s, settings)
         | 
| 18 | 
            +
                  server.accept
         | 
| 19 | 
            +
                  buffer = ''
         | 
| 20 | 
            +
                  buffer += server.read until buffer.include?(WEBrick::CRLF * 2)
         | 
| 21 | 
            +
                  req = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP)
         | 
| 22 | 
            +
                  req.parse(StringIO.new(buffer))
         | 
| 23 | 
            +
                  puts req.to_s
         | 
| 24 | 
            +
                  res = WEBrick::HTTPResponse.new(WEBrick::Config::HTTP)
         | 
| 25 | 
            +
                  res.status = 200
         | 
| 26 | 
            +
                  res.body = 'Hello'
         | 
| 27 | 
            +
                  res.content_length = 5
         | 
| 28 | 
            +
                  res.content_type = 'text/html'
         | 
| 29 | 
            +
                  server.write(
         | 
| 30 | 
            +
                    res.status_line \
         | 
| 31 | 
            +
                    + res.header.map { |k, v| k + ': ' + v }.join(WEBrick::CRLF) \
         | 
| 32 | 
            +
                    + WEBrick::CRLF * 2 \
         | 
| 33 | 
            +
                    + res.body
         | 
| 34 | 
            +
                  )
         | 
| 35 | 
            +
                  server.close
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
              rescue Timeout::Error => e
         | 
| 38 | 
            +
                puts e.to_s + "\n\n"
         | 
| 39 | 
            +
              ensure
         | 
| 40 | 
            +
                s.close
         | 
| 41 | 
            +
              end
         | 
| 42 | 
            +
            end
         | 
| 43 | 
            +
            # rubocop: enable Metrics/BlockLength
         | 
    
        data/interop/client_spec.rb
    CHANGED
    
    | @@ -3,61 +3,144 @@ | |
| 3 3 |  | 
| 4 4 | 
             
            require_relative 'helper'
         | 
| 5 5 |  | 
| 6 | 
            -
             | 
| 6 | 
            +
            FIXTURES_DIR = __dir__ + '/../spec/fixtures'
         | 
| 7 7 |  | 
| 8 8 | 
             
            RSpec.describe Client do
         | 
| 9 9 | 
             
              # testcases
         | 
| 10 | 
            +
              # normal [Boolean] Is this nominal scenarios?
         | 
| 11 | 
            +
              # opt [String] openssl s_server options
         | 
| 12 | 
            +
              # crt [String] server crt file path
         | 
| 13 | 
            +
              # key [String] server key file path
         | 
| 14 | 
            +
              # settings [Hash] TTTLS13::Server settings
         | 
| 10 15 | 
             
              [
         | 
| 16 | 
            +
                # rubocop: disable Metrics/LineLength
         | 
| 11 17 | 
             
                [
         | 
| 12 | 
            -
                   | 
| 18 | 
            +
                  true,
         | 
| 19 | 
            +
                  '-ciphersuites TLS_AES_256_GCM_SHA384',
         | 
| 20 | 
            +
                  'rsa_rsa.crt',
         | 
| 21 | 
            +
                  'rsa_rsa.key',
         | 
| 13 22 | 
             
                  cipher_suites: [CipherSuite::TLS_AES_256_GCM_SHA384]
         | 
| 14 23 | 
             
                ],
         | 
| 15 24 | 
             
                [
         | 
| 16 | 
            -
                   | 
| 25 | 
            +
                  true,
         | 
| 26 | 
            +
                  '-ciphersuites TLS_CHACHA20_POLY1305_SHA256',
         | 
| 27 | 
            +
                  'rsa_rsa.crt',
         | 
| 28 | 
            +
                  'rsa_rsa.key',
         | 
| 17 29 | 
             
                  cipher_suites: [CipherSuite::TLS_CHACHA20_POLY1305_SHA256]
         | 
| 18 30 | 
             
                ],
         | 
| 19 31 | 
             
                [
         | 
| 20 | 
            -
                   | 
| 32 | 
            +
                  true,
         | 
| 33 | 
            +
                  '-ciphersuites TLS_AES_128_GCM_SHA256',
         | 
| 34 | 
            +
                  'rsa_rsa.crt',
         | 
| 35 | 
            +
                  'rsa_rsa.key',
         | 
| 21 36 | 
             
                  cipher_suites: [CipherSuite::TLS_AES_128_GCM_SHA256]
         | 
| 22 37 | 
             
                ],
         | 
| 23 38 | 
             
                [
         | 
| 24 | 
            -
                   | 
| 39 | 
            +
                  false,
         | 
| 40 | 
            +
                  '-ciphersuites TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256',
         | 
| 41 | 
            +
                  'rsa_rsa.crt',
         | 
| 42 | 
            +
                  'rsa_rsa.key',
         | 
| 43 | 
            +
                  cipher_suites: [CipherSuite::TLS_AES_128_GCM_SHA256]
         | 
| 44 | 
            +
                ],
         | 
| 45 | 
            +
                [
         | 
| 46 | 
            +
                  true,
         | 
| 47 | 
            +
                  '-groups P-256',
         | 
| 48 | 
            +
                  'rsa_rsa.crt',
         | 
| 49 | 
            +
                  'rsa_rsa.key',
         | 
| 25 50 | 
             
                  supported_groups: [NamedGroup::SECP256R1]
         | 
| 26 51 | 
             
                ],
         | 
| 27 52 | 
             
                [
         | 
| 28 | 
            -
                   | 
| 53 | 
            +
                  true,
         | 
| 54 | 
            +
                  '-groups P-384',
         | 
| 55 | 
            +
                  'rsa_rsa.crt',
         | 
| 56 | 
            +
                  'rsa_rsa.key',
         | 
| 29 57 | 
             
                  supported_groups: [NamedGroup::SECP384R1]
         | 
| 30 58 | 
             
                ],
         | 
| 31 59 | 
             
                [
         | 
| 32 | 
            -
                   | 
| 60 | 
            +
                  true,
         | 
| 61 | 
            +
                  '-groups P-521',
         | 
| 62 | 
            +
                  'rsa_rsa.crt',
         | 
| 63 | 
            +
                  'rsa_rsa.key',
         | 
| 33 64 | 
             
                  supported_groups: [NamedGroup::SECP521R1]
         | 
| 34 65 | 
             
                ],
         | 
| 35 66 | 
             
                [
         | 
| 36 | 
            -
                   | 
| 67 | 
            +
                  false,
         | 
| 68 | 
            +
                  '-groups P-256:P-384',
         | 
| 69 | 
            +
                  'rsa_rsa.crt',
         | 
| 70 | 
            +
                  'rsa_rsa.key',
         | 
| 71 | 
            +
                  supported_groups: [NamedGroup::SECP521R1]
         | 
| 72 | 
            +
                ],
         | 
| 73 | 
            +
                [
         | 
| 74 | 
            +
                  true,
         | 
| 75 | 
            +
                  '-sigalgs RSA-PSS+SHA256',
         | 
| 76 | 
            +
                  'rsa_rsa.crt',
         | 
| 77 | 
            +
                  'rsa_rsa.key',
         | 
| 37 78 | 
             
                  signature_algorithms_cert: [SignatureScheme::RSA_PKCS1_SHA256],
         | 
| 38 79 | 
             
                  signature_algorithms: [SignatureScheme::RSA_PSS_RSAE_SHA256]
         | 
| 39 80 | 
             
                ],
         | 
| 40 81 | 
             
                [
         | 
| 41 | 
            -
                   | 
| 82 | 
            +
                  true,
         | 
| 83 | 
            +
                  '-sigalgs RSA-PSS+SHA384',
         | 
| 84 | 
            +
                  'rsa_rsa.crt',
         | 
| 85 | 
            +
                  'rsa_rsa.key',
         | 
| 42 86 | 
             
                  signature_algorithms_cert: [SignatureScheme::RSA_PKCS1_SHA256],
         | 
| 43 87 | 
             
                  signature_algorithms: [SignatureScheme::RSA_PSS_RSAE_SHA384]
         | 
| 44 88 | 
             
                ],
         | 
| 45 89 | 
             
                [
         | 
| 46 | 
            -
                   | 
| 90 | 
            +
                  true,
         | 
| 91 | 
            +
                  '-sigalgs RSA-PSS+SHA512',
         | 
| 92 | 
            +
                  'rsa_rsa.crt',
         | 
| 93 | 
            +
                  'rsa_rsa.key',
         | 
| 47 94 | 
             
                  signature_algorithms_cert: [SignatureScheme::RSA_PKCS1_SHA256],
         | 
| 48 95 | 
             
                  signature_algorithms: [SignatureScheme::RSA_PSS_RSAE_SHA512]
         | 
| 49 96 | 
             
                ],
         | 
| 50 97 | 
             
                [
         | 
| 51 | 
            -
                   | 
| 98 | 
            +
                  true,
         | 
| 99 | 
            +
                  '-sigalgs ECDSA+SHA256',
         | 
| 100 | 
            +
                  'rsa_secp256r1.crt',
         | 
| 101 | 
            +
                  'rsa_secp256r1.key',
         | 
| 102 | 
            +
                  signature_algorithms_cert: [SignatureScheme::RSA_PKCS1_SHA256],
         | 
| 103 | 
            +
                  signature_algorithms: [SignatureScheme::ECDSA_SECP256R1_SHA256]
         | 
| 104 | 
            +
                ],
         | 
| 105 | 
            +
                [
         | 
| 106 | 
            +
                  true,
         | 
| 107 | 
            +
                  '-sigalgs ECDSA+SHA384',
         | 
| 108 | 
            +
                  'rsa_secp384r1.crt',
         | 
| 109 | 
            +
                  'rsa_secp384r1.key',
         | 
| 110 | 
            +
                  signature_algorithms_cert: [SignatureScheme::RSA_PKCS1_SHA256],
         | 
| 111 | 
            +
                  signature_algorithms: [SignatureScheme::ECDSA_SECP384R1_SHA384]
         | 
| 112 | 
            +
                ],
         | 
| 113 | 
            +
                [
         | 
| 114 | 
            +
                  true,
         | 
| 115 | 
            +
                  '-sigalgs ECDSA+SHA512',
         | 
| 116 | 
            +
                  'rsa_secp521r1.crt',
         | 
| 117 | 
            +
                  'rsa_secp521r1.key',
         | 
| 118 | 
            +
                  signature_algorithms_cert: [SignatureScheme::RSA_PKCS1_SHA256],
         | 
| 119 | 
            +
                  signature_algorithms: [SignatureScheme::ECDSA_SECP521R1_SHA512]
         | 
| 120 | 
            +
                ],
         | 
| 121 | 
            +
                [
         | 
| 122 | 
            +
                  false,
         | 
| 123 | 
            +
                  '-sigalgs ECDSA+SHA256:ECDSA+SHA384:RSA-PSS+SHA256:RSA-PSS+SHA384:RSA-PSS+SHA512:RSA+SHA256',
         | 
| 124 | 
            +
                  'rsa_secp521r1.crt',
         | 
| 125 | 
            +
                  'rsa_secp521r1.key',
         | 
| 126 | 
            +
                  signature_algorithms_cert: [SignatureScheme::RSA_PKCS1_SHA256],
         | 
| 127 | 
            +
                  signature_algorithms: [SignatureScheme::ECDSA_SECP521R1_SHA512]
         | 
| 128 | 
            +
                ],
         | 
| 129 | 
            +
                [
         | 
| 130 | 
            +
                  true,
         | 
| 131 | 
            +
                  '-record_padding 8446',
         | 
| 132 | 
            +
                  'rsa_rsa.crt',
         | 
| 133 | 
            +
                  'rsa_rsa.key',
         | 
| 52 134 | 
             
                  {}
         | 
| 53 135 | 
             
                ]
         | 
| 54 | 
            -
             | 
| 136 | 
            +
                # rubocop: enable Metrics/LineLength
         | 
| 137 | 
            +
              ].each do |normal, opt, crt, key, settings|
         | 
| 55 138 | 
             
                context 'client interop' do
         | 
| 56 139 | 
             
                  before do
         | 
| 57 | 
            -
                    cmd = "docker run -v #{ | 
| 140 | 
            +
                    cmd = "docker run -v #{FIXTURES_DIR}:/tmp -p 4433:4433 -it openssl " \
         | 
| 58 141 | 
             
                          + 'openssl s_server ' \
         | 
| 59 | 
            -
                          +  | 
| 60 | 
            -
                          +  | 
| 142 | 
            +
                          + "-cert /tmp/#{crt} " \
         | 
| 143 | 
            +
                          + "-key /tmp/#{key} " \
         | 
| 61 144 | 
             
                          + '-tls1_3 ' \
         | 
| 62 145 | 
             
                          + '-www ' \
         | 
| 63 146 | 
             
                          + '-quiet ' \
         | 
| @@ -65,13 +148,13 @@ RSpec.describe Client do | |
| 65 148 | 
             
                    pid = spawn(cmd)
         | 
| 66 149 | 
             
                    Process.detach(pid)
         | 
| 67 150 |  | 
| 68 | 
            -
                    sleep(2) # waiting for openssl s_server
         | 
| 151 | 
            +
                    sleep(2.5) # waiting for openssl s_server
         | 
| 69 152 | 
             
                  end
         | 
| 70 153 |  | 
| 71 154 | 
             
                  let(:client) do
         | 
| 72 155 | 
             
                    hostname = 'localhost'
         | 
| 73 156 | 
             
                    @socket = TCPSocket.new(hostname, 4433)
         | 
| 74 | 
            -
                    settings[:ca_file] =  | 
| 157 | 
            +
                    settings[:ca_file] = FIXTURES_DIR + '/rsa_ca.crt'
         | 
| 75 158 | 
             
                    Client.new(@socket, hostname, settings)
         | 
| 76 159 | 
             
                  end
         | 
| 77 160 |  | 
| @@ -80,11 +163,17 @@ RSpec.describe Client do | |
| 80 163 | 
             
                    `docker ps -ql | xargs docker stop`
         | 
| 81 164 | 
             
                  end
         | 
| 82 165 |  | 
| 83 | 
            -
                   | 
| 84 | 
            -
                     | 
| 85 | 
            -
             | 
| 86 | 
            -
             | 
| 87 | 
            -
             | 
| 166 | 
            +
                  if normal
         | 
| 167 | 
            +
                    it "should connect with openssl s_server ...#{opt}" do
         | 
| 168 | 
            +
                      expect { client.connect }.to_not raise_error
         | 
| 169 | 
            +
                      expect { client.write("GET / HTTP/1.0\r\n\r\n") }.to_not raise_error
         | 
| 170 | 
            +
                      expect(client.read).to include "HTTP/1.0 200 ok\r\n"
         | 
| 171 | 
            +
                      expect { client.close }.to_not raise_error
         | 
| 172 | 
            +
                    end
         | 
| 173 | 
            +
                  else # exceptions scenarios
         | 
| 174 | 
            +
                    it "should NOT connect with openssl s_server ...#{opt}" do
         | 
| 175 | 
            +
                      expect { client.connect }.to raise_error ErrorAlerts
         | 
| 176 | 
            +
                    end
         | 
| 88 177 | 
             
                  end
         | 
| 89 178 | 
             
                end
         | 
| 90 179 | 
             
              end
         |