tttls1.3 0.2.12 → 0.2.13
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/.github/workflows/main.yml +15 -10
- data/.rubocop.yml +1 -1
- data/Gemfile +1 -1
- data/README.md +1 -0
- data/example/helper.rb +3 -3
- data/example/https_client_using_0rtt.rb +1 -1
- data/example/https_client_using_hrr_and_ticket.rb +1 -1
- data/example/https_client_using_status_request.rb +1 -1
- data/example/https_client_using_ticket.rb +1 -1
- data/example/https_server.rb +1 -1
- data/lib/tttls1.3/client.rb +21 -23
- data/lib/tttls1.3/connection.rb +14 -6
- data/lib/tttls1.3/cryptograph.rb +1 -1
- data/lib/tttls1.3/message.rb +1 -1
- data/lib/tttls1.3/message/alert.rb +2 -2
- data/lib/tttls1.3/message/extensions.rb +29 -20
- data/lib/tttls1.3/server.rb +29 -13
- data/lib/tttls1.3/version.rb +1 -1
- data/spec/extensions_spec.rb +16 -0
- data/spec/server_hello_spec.rb +1 -1
- metadata +2 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: d292d936d6b26ed1f6307bde684a4f982ea1ee2a7f287eeb306d33b048f855a3
         | 
| 4 | 
            +
              data.tar.gz: ef33ef7ce5bd53425d7feb6d7ebf4bca2a3803cf50f930375a441cef0543ab0e
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 815f58f7d9d0d7c64911979b01304826601767d1397cdeda326856916b15f2d5c8e42b38379d91e9f720c29f2c71f6bdbe308d42e70428413fad345f553e1c42
         | 
| 7 | 
            +
              data.tar.gz: fcffc6d40024429db1f4a4c5573b0680ce4fb603aa06d9876f274a202726e72078f538222cf0ea974a7bf444b11821350510fb7a89b1384c0bb25ce05ba7877f
         | 
    
        data/.github/workflows/main.yml
    CHANGED
    
    | @@ -11,15 +11,20 @@ on: | |
| 11 11 | 
             
            jobs:
         | 
| 12 12 | 
             
              ci:
         | 
| 13 13 | 
             
                runs-on: ubuntu-latest
         | 
| 14 | 
            +
                strategy:
         | 
| 15 | 
            +
                  matrix:
         | 
| 16 | 
            +
                    ruby-version: ['2.6.x']
         | 
| 14 17 | 
             
                steps:
         | 
| 15 | 
            -
                  - uses: actions/checkout@v1
         | 
| 16 | 
            -
                  - uses: actions/setup-ruby@v1
         | 
| 17 18 | 
             
                  - uses: thekuwayama/openssl@master
         | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 20 | 
            -
                  -  | 
| 21 | 
            -
                  -  | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 24 | 
            -
             | 
| 25 | 
            -
                  -  | 
| 19 | 
            +
                  - name: Set up Ruby
         | 
| 20 | 
            +
                    uses: actions/setup-ruby@v1
         | 
| 21 | 
            +
                  - uses: actions/checkout@v1
         | 
| 22 | 
            +
                  - name: Install dependencies
         | 
| 23 | 
            +
                    run: |
         | 
| 24 | 
            +
                      gem install bundler
         | 
| 25 | 
            +
                      bundle install
         | 
| 26 | 
            +
                  - name: Run test
         | 
| 27 | 
            +
                    run: |
         | 
| 28 | 
            +
                      bundle exec rake
         | 
| 29 | 
            +
                      bundle exec rake interop:client
         | 
| 30 | 
            +
                      bundle exec rake interop:server
         | 
    
        data/.rubocop.yml
    CHANGED
    
    
    
        data/Gemfile
    CHANGED
    
    
    
        data/README.md
    CHANGED
    
    | @@ -119,6 +119,7 @@ tttls1.3 server is configurable using keyword arguments. | |
| 119 119 | 
             
            | `:signature_algorithms` | Array of TTTLS13::SignatureScheme constant | `ECDSA_SECP256R1_SHA256`, `ECDSA_SECP384R1_SHA384`, `ECDSA_SECP521R1_SHA512`, `RSA_PSS_RSAE_SHA256`, `RSA_PSS_RSAE_SHA384`, `RSA_PSS_RSAE_SHA512`, `RSA_PKCS1_SHA256`, `RSA_PKCS1_SHA384`, `RSA_PKCS1_SHA512` | List of supported signature algorithms. |
         | 
| 120 120 | 
             
            | `:supported_groups` | Array of TTTLS13::NamedGroup constant | `SECP256R1`, `SECP384R1`, `SECP521R1` | List of supported named groups. |
         | 
| 121 121 | 
             
            | `:alpn` | Array of String | nil | List of supported application protocols. If not needed to check this extension, set nil. |
         | 
| 122 | 
            +
            | `:process_ocsp_response` | Proc | nil | Proc that gets OpenSSL::OCSP::Response. If not needed to staple OCSP::Response, set nil. |
         | 
| 122 123 | 
             
            | `:compatibility_mode` | Boolean | true | If needed to send ChangeCipherSpec, set true. |
         | 
| 123 124 | 
             
            | `:loglevel` | Logger constant | Logger::WARN | If needed to print verbose, set Logger::DEBUG. |
         | 
| 124 125 |  | 
    
        data/example/helper.rb
    CHANGED
    
    | @@ -36,7 +36,7 @@ def recv_http_response(client) | |
| 36 36 | 
             
              parser = HTTP::Parser.new
         | 
| 37 37 | 
             
              buf = nil
         | 
| 38 38 |  | 
| 39 | 
            -
              parser.on_headers_complete =  | 
| 39 | 
            +
              parser.on_headers_complete = lambda do |headers|
         | 
| 40 40 | 
             
                buf =
         | 
| 41 41 | 
             
                  [
         | 
| 42 42 | 
             
                    'HTTP/' + parser.http_version.join('.'),
         | 
| @@ -47,11 +47,11 @@ def recv_http_response(client) | |
| 47 47 | 
             
                  + WEBrick::CRLF
         | 
| 48 48 | 
             
              end
         | 
| 49 49 |  | 
| 50 | 
            -
              parser.on_body =  | 
| 50 | 
            +
              parser.on_body = lambda do |chunk|
         | 
| 51 51 | 
             
                buf += chunk
         | 
| 52 52 | 
             
              end
         | 
| 53 53 |  | 
| 54 | 
            -
              parser.on_message_complete =  | 
| 54 | 
            +
              parser.on_message_complete = lambda do
         | 
| 55 55 | 
             
                client.close
         | 
| 56 56 | 
             
              end
         | 
| 57 57 |  | 
| @@ -11,7 +11,7 @@ settings_2nd = { | |
| 11 11 | 
             
              ca_file: File.exist?(ca_file) ? ca_file : nil,
         | 
| 12 12 | 
             
              alpn: ['http/1.1']
         | 
| 13 13 | 
             
            }
         | 
| 14 | 
            -
            process_new_session_ticket =  | 
| 14 | 
            +
            process_new_session_ticket = lambda do |nst, rms, cs|
         | 
| 15 15 | 
             
              return if Time.now.to_i - nst.timestamp > nst.ticket_lifetime
         | 
| 16 16 |  | 
| 17 17 | 
             
              settings_2nd[:ticket] = nst.ticket
         | 
| @@ -11,7 +11,7 @@ settings_2nd = { | |
| 11 11 | 
             
              ca_file: File.exist?(ca_file) ? ca_file : nil,
         | 
| 12 12 | 
             
              alpn: ['http/1.1']
         | 
| 13 13 | 
             
            }
         | 
| 14 | 
            -
            process_new_session_ticket =  | 
| 14 | 
            +
            process_new_session_ticket = lambda do |nst, rms, cs|
         | 
| 15 15 | 
             
              return if Time.now.to_i - nst.timestamp > nst.ticket_lifetime
         | 
| 16 16 |  | 
| 17 17 | 
             
              settings_2nd[:key_share_groups] = [] # empty KeyShareClientHello.client_shares
         | 
| @@ -7,7 +7,7 @@ hostname, port = (ARGV[0] || 'localhost:4433').split(':') | |
| 7 7 | 
             
            ca_file = __dir__ + '/../tmp/ca.crt'
         | 
| 8 8 | 
             
            req = simple_http_request(hostname)
         | 
| 9 9 |  | 
| 10 | 
            -
            process_certificate_status =  | 
| 10 | 
            +
            process_certificate_status = lambda do |res, cert, chain|
         | 
| 11 11 | 
             
              puts 'stapled OCSPResponse: '
         | 
| 12 12 | 
             
              puts res.basic.status.pretty_inspect unless res.nil?
         | 
| 13 13 | 
             
              puts '-' * 10
         | 
| @@ -11,7 +11,7 @@ settings_2nd = { | |
| 11 11 | 
             
              ca_file: File.exist?(ca_file) ? ca_file : nil,
         | 
| 12 12 | 
             
              alpn: ['http/1.1']
         | 
| 13 13 | 
             
            }
         | 
| 14 | 
            -
            process_new_session_ticket =  | 
| 14 | 
            +
            process_new_session_ticket = lambda do |nst, rms, cs|
         | 
| 15 15 | 
             
              return if Time.now.to_i - nst.timestamp > nst.ticket_lifetime
         | 
| 16 16 |  | 
| 17 17 | 
             
              settings_2nd[:ticket] = nst.ticket
         | 
    
        data/example/https_server.rb
    CHANGED
    
    | @@ -26,7 +26,7 @@ Etc.nprocessors.times do | |
| 26 26 | 
             
                    server = TTTLS13::Server.new(s, settings)
         | 
| 27 27 | 
             
                    parser = HTTP::Parser.new
         | 
| 28 28 |  | 
| 29 | 
            -
                    parser.on_message_complete =  | 
| 29 | 
            +
                    parser.on_message_complete = lambda do
         | 
| 30 30 | 
             
                      if !parser.http_method.nil?
         | 
| 31 31 | 
             
                        logger.info 'Receive Request'
         | 
| 32 32 | 
             
                        server.write(simple_http_response('TEST'))
         | 
    
        data/lib/tttls1.3/client.rb
    CHANGED
    
    | @@ -403,23 +403,16 @@ module TTTLS13 | |
| 403 403 | 
             
                # @return [Boolean]
         | 
| 404 404 | 
             
                #
         | 
| 405 405 | 
             
                # @example
         | 
| 406 | 
            -
                #    | 
| 406 | 
            +
                #   m = Client.method(:softfail_check_certificate_status)
         | 
| 407 407 | 
             
                #   Client.new(
         | 
| 408 408 | 
             
                #     socket,
         | 
| 409 409 | 
             
                #     hostname,
         | 
| 410 410 | 
             
                #     check_certificate_status: true,
         | 
| 411 | 
            -
                #     process_certificate_status:  | 
| 411 | 
            +
                #     process_certificate_status: m
         | 
| 412 412 | 
             
                #   )
         | 
| 413 | 
            -
                # rubocop: disable Metrics/AbcSize
         | 
| 414 | 
            -
                # rubocop: disable Metrics/CyclomaticComplexity
         | 
| 415 | 
            -
                # rubocop: disable Metrics/PerceivedComplexity
         | 
| 416 413 | 
             
                def self.softfail_check_certificate_status(res, cert, chain)
         | 
| 417 414 | 
             
                  ocsp_response = res
         | 
| 418 | 
            -
                   | 
| 419 | 
            -
                  store.set_default_paths
         | 
| 420 | 
            -
                  context = OpenSSL::X509::StoreContext.new(store, cert, chain)
         | 
| 421 | 
            -
                  context.verify
         | 
| 422 | 
            -
                  cid = OpenSSL::OCSP::CertificateId.new(cert, context.chain[1])
         | 
| 415 | 
            +
                  cid = OpenSSL::OCSP::CertificateId.new(cert, chain.first)
         | 
| 423 416 |  | 
| 424 417 | 
             
                  # When NOT received OCSPResponse in TLS handshake, this method will
         | 
| 425 418 | 
             
                  # send OCSPRequest. If ocsp_uri is NOT presented in Certificate, return
         | 
| @@ -430,23 +423,25 @@ module TTTLS13 | |
| 430 423 | 
             
                    return true if uri.nil?
         | 
| 431 424 |  | 
| 432 425 | 
             
                    begin
         | 
| 433 | 
            -
                       | 
| 426 | 
            +
                      # send OCSP::Request
         | 
| 427 | 
            +
                      ocsp_request = gen_ocsp_request(cid)
         | 
| 428 | 
            +
                      Timeout.timeout(2) do
         | 
| 429 | 
            +
                        ocsp_response = send_ocsp_request(ocsp_request, uri)
         | 
| 430 | 
            +
                      end
         | 
| 431 | 
            +
             | 
| 432 | 
            +
                      # check nonce of OCSP::Response
         | 
| 433 | 
            +
                      check_nonce = ocsp_request.check_nonce(ocsp_response.basic)
         | 
| 434 | 
            +
                      return true unless [-1, 1].include?(check_nonce)
         | 
| 434 435 | 
             
                    rescue StandardError
         | 
| 435 436 | 
             
                      return true
         | 
| 436 437 | 
             
                    end
         | 
| 437 438 | 
             
                  end
         | 
| 438 | 
            -
                  return  | 
| 439 | 
            +
                  return true \
         | 
| 439 440 | 
             
                    if ocsp_response.status != OpenSSL::OCSP::RESPONSE_STATUS_SUCCESSFUL
         | 
| 440 441 |  | 
| 441 442 | 
             
                  status = ocsp_response.basic.status.find { |s| s.first.cmp(cid) }
         | 
| 442 | 
            -
                   | 
| 443 | 
            -
                  return false if !status[3].nil? && status[3] < Time.now
         | 
| 444 | 
            -
             | 
| 445 | 
            -
                  ocsp_response.basic.verify(chain, store)
         | 
| 443 | 
            +
                  status[1] != OpenSSL::OCSP::V_CERTSTATUS_REVOKED
         | 
| 446 444 | 
             
                end
         | 
| 447 | 
            -
                # rubocop: enable Metrics/AbcSize
         | 
| 448 | 
            -
                # rubocop: enable Metrics/CyclomaticComplexity
         | 
| 449 | 
            -
                # rubocop: enable Metrics/PerceivedComplexity
         | 
| 450 445 |  | 
| 451 446 | 
             
                private
         | 
| 452 447 |  | 
| @@ -479,6 +474,9 @@ module TTTLS13 | |
| 479 474 | 
             
                  rsl = @settings[:record_size_limit]
         | 
| 480 475 | 
             
                  return false if !rsl.nil? && (rsl < 64 || rsl > 2**14 + 1)
         | 
| 481 476 |  | 
| 477 | 
            +
                  return false if @settings[:check_certificate_status] &&
         | 
| 478 | 
            +
                                  @settings[:process_certificate_status].nil?
         | 
| 479 | 
            +
             | 
| 482 480 | 
             
                  true
         | 
| 483 481 | 
             
                end
         | 
| 484 482 | 
             
                # rubocop: enable Metrics/AbcSize
         | 
| @@ -530,7 +528,7 @@ module TTTLS13 | |
| 530 528 | 
             
                # rubocop: disable Metrics/MethodLength
         | 
| 531 529 | 
             
                # rubocop: disable Metrics/PerceivedComplexity
         | 
| 532 530 | 
             
                def gen_ch_extensions
         | 
| 533 | 
            -
                  exs =  | 
| 531 | 
            +
                  exs = Message::Extensions.new
         | 
| 534 532 | 
             
                  # server_name
         | 
| 535 533 | 
             
                  exs << Message::Extension::ServerName.new(@hostname)
         | 
| 536 534 |  | 
| @@ -580,7 +578,7 @@ module TTTLS13 | |
| 580 578 | 
             
                  exs << Message::Extension::OCSPStatusRequest.new \
         | 
| 581 579 | 
             
                    if @settings[:check_certificate_status]
         | 
| 582 580 |  | 
| 583 | 
            -
                  [ | 
| 581 | 
            +
                  [exs, priv_keys]
         | 
| 584 582 | 
             
                end
         | 
| 585 583 | 
             
                # rubocop: enable Metrics/AbcSize
         | 
| 586 584 | 
             
                # rubocop: enable Metrics/CyclomaticComplexity
         | 
| @@ -673,7 +671,7 @@ module TTTLS13 | |
| 673 671 | 
             
                # @return [TTTLS13::Message::Extensions]
         | 
| 674 672 | 
             
                # @return [Hash of NamedGroup => OpenSSL::PKey::EC.$Object]
         | 
| 675 673 | 
             
                def gen_newch_extensions(ch1, hrr)
         | 
| 676 | 
            -
                  exs =  | 
| 674 | 
            +
                  exs = Message::Extensions.new
         | 
| 677 675 | 
             
                  # key_share
         | 
| 678 676 | 
             
                  if hrr.extensions.include?(Message::ExtensionType::KEY_SHARE)
         | 
| 679 677 | 
             
                    group = hrr.extensions[Message::ExtensionType::KEY_SHARE]
         | 
| @@ -695,7 +693,7 @@ module TTTLS13 | |
| 695 693 | 
             
                    if hrr.extensions.include?(Message::ExtensionType::COOKIE)
         | 
| 696 694 |  | 
| 697 695 | 
             
                  # early_data
         | 
| 698 | 
            -
                  new_exs = ch1.extensions.merge( | 
| 696 | 
            +
                  new_exs = ch1.extensions.merge(exs)
         | 
| 699 697 | 
             
                  new_exs.delete(Message::ExtensionType::EARLY_DATA)
         | 
| 700 698 |  | 
| 701 699 | 
             
                  [new_exs, priv_keys]
         | 
    
        data/lib/tttls1.3/connection.rb
    CHANGED
    
    | @@ -541,19 +541,27 @@ module TTTLS13 | |
| 541 541 |  | 
| 542 542 | 
             
                class << self
         | 
| 543 543 | 
             
                  # @param cid [OpenSSL::OCSP::CertificateId]
         | 
| 544 | 
            -
                  # @param uri [String]
         | 
| 545 544 | 
             
                  #
         | 
| 546 | 
            -
                  # @return [OpenSSL::OCSP:: | 
| 547 | 
            -
                  def  | 
| 548 | 
            -
                    # generate OCSPRequest
         | 
| 545 | 
            +
                  # @return [OpenSSL::OCSP::Request]
         | 
| 546 | 
            +
                  def gen_ocsp_request(cid)
         | 
| 549 547 | 
             
                    ocsp_request = OpenSSL::OCSP::Request.new
         | 
| 550 548 | 
             
                    ocsp_request.add_certid(cid)
         | 
| 551 549 | 
             
                    ocsp_request.add_nonce
         | 
| 550 | 
            +
                    ocsp_request
         | 
| 551 | 
            +
                  end
         | 
| 552 | 
            +
             | 
| 553 | 
            +
                  # @param ocsp_request [OpenSSL::OCSP::Request]
         | 
| 554 | 
            +
                  # @param uri_string [String]
         | 
| 555 | 
            +
                  #
         | 
| 556 | 
            +
                  # @raise [Net::OpenTimeout, OpenSSL::OCSP::OCSPError, URI::$Exception]
         | 
| 557 | 
            +
                  #
         | 
| 558 | 
            +
                  # @return [OpenSSL::OCSP::Response, n
         | 
| 559 | 
            +
                  def send_ocsp_request(ocsp_request, uri_string)
         | 
| 552 560 | 
             
                    # send HTTP POST
         | 
| 553 | 
            -
                    uri = URI.parse( | 
| 561 | 
            +
                    uri = URI.parse(uri_string)
         | 
| 554 562 | 
             
                    path = uri.path
         | 
| 555 563 | 
             
                    path = '/' if path.nil? || path.empty?
         | 
| 556 | 
            -
                    http_response = Net::HTTP.start | 
| 564 | 
            +
                    http_response = Net::HTTP.start(uri.host, uri.port) do |http|
         | 
| 557 565 | 
             
                      http.post(
         | 
| 558 566 | 
             
                        path,
         | 
| 559 567 | 
             
                        ocsp_request.to_der,
         | 
    
        data/lib/tttls1.3/cryptograph.rb
    CHANGED
    
    
    
        data/lib/tttls1.3/message.rb
    CHANGED
    
    
| @@ -8,7 +8,7 @@ module TTTLS13 | |
| 8 8 | 
             
                  FATAL   = "\x02"
         | 
| 9 9 | 
             
                end
         | 
| 10 10 |  | 
| 11 | 
            -
                # rubocop: disable Layout/ | 
| 11 | 
            +
                # rubocop: disable Layout/HashAlignment
         | 
| 12 12 | 
             
                ALERT_DESCRIPTION = {
         | 
| 13 13 | 
             
                  close_notify:                    "\x00",
         | 
| 14 14 | 
             
                  unexpected_message:              "\x0a",
         | 
| @@ -38,7 +38,7 @@ module TTTLS13 | |
| 38 38 | 
             
                  certificate_required:            "\x74",
         | 
| 39 39 | 
             
                  no_application_protocol:         "\x78"
         | 
| 40 40 | 
             
                }.freeze
         | 
| 41 | 
            -
                # rubocop: enable Layout/ | 
| 41 | 
            +
                # rubocop: enable Layout/HashAlignment
         | 
| 42 42 |  | 
| 43 43 | 
             
                class Alert
         | 
| 44 44 | 
             
                  attr_reader :level
         | 
| @@ -44,10 +44,11 @@ module TTTLS13 | |
| 44 44 | 
             
                  #
         | 
| 45 45 | 
             
                  # @return [TTTLS13::Message::Extensions]
         | 
| 46 46 | 
             
                  # rubocop: disable Metrics/CyclomaticComplexity
         | 
| 47 | 
            +
                  # rubocop: disable Metrics/PerceivedComplexity
         | 
| 47 48 | 
             
                  def self.deserialize(binary, msg_type)
         | 
| 48 49 | 
             
                    raise Error::ErrorAlerts, :internal_error if binary.nil?
         | 
| 49 50 |  | 
| 50 | 
            -
                     | 
| 51 | 
            +
                    exs = Extensions.new
         | 
| 51 52 | 
             
                    i = 0
         | 
| 52 53 | 
             
                    while i < binary.length
         | 
| 53 54 | 
             
                      raise Error::ErrorAlerts, :decode_error if i + 4 > binary.length
         | 
| @@ -66,32 +67,41 @@ module TTTLS13 | |
| 66 67 | 
             
                        ex = Extension::UnknownExtension.new(extension_type: extension_type,
         | 
| 67 68 | 
             
                                                             extension_data: ex_bin)
         | 
| 68 69 | 
             
                      end
         | 
| 69 | 
            -
             | 
| 70 | 
            +
             | 
| 71 | 
            +
                      # There MUST NOT be more than one extension of the same type in a
         | 
| 72 | 
            +
                      # given extension block.
         | 
| 73 | 
            +
                      raise Error::ErrorAlerts, :unsupported_extension \
         | 
| 74 | 
            +
                        if exs.include?(extension_type)
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                      exs[extension_type] = ex
         | 
| 70 77 | 
             
                      i += ex_len
         | 
| 71 78 | 
             
                    end
         | 
| 72 79 | 
             
                    raise Error::ErrorAlerts, :decode_error unless i == binary.length
         | 
| 73 80 |  | 
| 74 | 
            -
                     | 
| 81 | 
            +
                    exs
         | 
| 75 82 | 
             
                  end
         | 
| 76 83 | 
             
                  # rubocop: enable Metrics/CyclomaticComplexity
         | 
| 84 | 
            +
                  # rubocop: enable Metrics/PerceivedComplexity
         | 
| 77 85 |  | 
| 78 86 | 
             
                  # @param key [TTTLS13::Message::ExtensionType]
         | 
| 87 | 
            +
                  # @param default
         | 
| 79 88 | 
             
                  #
         | 
| 80 89 | 
             
                  # @return [TTTLS13::Message::Extension::$Object]
         | 
| 81 | 
            -
                  def  | 
| 90 | 
            +
                  def fetch(key, default = nil)
         | 
| 82 91 | 
             
                    return nil if super_fetch(key, nil).is_a?(Extension::UnknownExtension)
         | 
| 83 92 |  | 
| 84 | 
            -
                    super_fetch(key,  | 
| 93 | 
            +
                    super_fetch(key, default)
         | 
| 85 94 | 
             
                  end
         | 
| 86 95 |  | 
| 87 | 
            -
                   | 
| 88 | 
            -
             | 
| 96 | 
            +
                  def [](key)
         | 
| 97 | 
            +
                    fetch(key)
         | 
| 98 | 
            +
                  end
         | 
| 99 | 
            +
             | 
| 100 | 
            +
                  # @param ex [TTTLS13::Message::Extension::$Object]
         | 
| 89 101 | 
             
                  #
         | 
| 90 102 | 
             
                  # @return [TTTLS13::Message::Extension::$Object]
         | 
| 91 | 
            -
                  def  | 
| 92 | 
            -
                     | 
| 93 | 
            -
             | 
| 94 | 
            -
                    super_fetch(key, default)
         | 
| 103 | 
            +
                  def <<(ex)
         | 
| 104 | 
            +
                    store(ex.extension_type, ex)
         | 
| 95 105 | 
             
                  end
         | 
| 96 106 |  | 
| 97 107 | 
             
                  class << self
         | 
| @@ -111,7 +121,6 @@ module TTTLS13 | |
| 111 121 | 
             
                    # @return [TTTLS13::Message::Extension::$Object, nil]
         | 
| 112 122 | 
             
                    # rubocop: disable Metrics/CyclomaticComplexity
         | 
| 113 123 | 
             
                    # rubocop: disable Metrics/MethodLength
         | 
| 114 | 
            -
                    # rubocop: disable Metrics/PerceivedComplexity
         | 
| 115 124 | 
             
                    def deserialize_extension(binary, extension_type, msg_type)
         | 
| 116 125 | 
             
                      raise Error::ErrorAlerts, :internal_error if binary.nil?
         | 
| 117 126 |  | 
| @@ -119,14 +128,15 @@ module TTTLS13 | |
| 119 128 | 
             
                      when ExtensionType::SERVER_NAME
         | 
| 120 129 | 
             
                        Extension::ServerName.deserialize(binary)
         | 
| 121 130 | 
             
                      when ExtensionType::STATUS_REQUEST
         | 
| 122 | 
            -
                        if msg_type == HandshakeType::CLIENT_HELLO | 
| 123 | 
            -
                           | 
| 124 | 
            -
                          Extension::OCSPStatusRequest.deserialize(binary)
         | 
| 125 | 
            -
                        elsif msg_type == HandshakeType::CERTIFICATE
         | 
| 126 | 
            -
                          Extension::OCSPResponse.deserialize(binary)
         | 
| 127 | 
            -
                        else
         | 
| 128 | 
            -
                          return nil
         | 
| 131 | 
            +
                        if msg_type == HandshakeType::CLIENT_HELLO
         | 
| 132 | 
            +
                          return Extension::OCSPStatusRequest.deserialize(binary)
         | 
| 129 133 | 
             
                        end
         | 
| 134 | 
            +
             | 
| 135 | 
            +
                        if msg_type == HandshakeType::CERTIFICATE
         | 
| 136 | 
            +
                          return Extension::OCSPResponse.deserialize(binary)
         | 
| 137 | 
            +
                        end
         | 
| 138 | 
            +
             | 
| 139 | 
            +
                        Extension::UnknownExtension.deserialize(binary, extension_type)
         | 
| 130 140 | 
             
                      when ExtensionType::SUPPORTED_GROUPS
         | 
| 131 141 | 
             
                        Extension::SupportedGroups.deserialize(binary)
         | 
| 132 142 | 
             
                      when ExtensionType::SIGNATURE_ALGORITHMS
         | 
| @@ -155,7 +165,6 @@ module TTTLS13 | |
| 155 165 | 
             
                    end
         | 
| 156 166 | 
             
                    # rubocop: enable Metrics/CyclomaticComplexity
         | 
| 157 167 | 
             
                    # rubocop: enable Metrics/MethodLength
         | 
| 158 | 
            -
                    # rubocop: enable Metrics/PerceivedComplexity
         | 
| 159 168 | 
             
                  end
         | 
| 160 169 | 
             
                end
         | 
| 161 170 | 
             
              end
         | 
    
        data/lib/tttls1.3/server.rb
    CHANGED
    
    | @@ -52,6 +52,7 @@ module TTTLS13 | |
| 52 52 | 
             
                signature_algorithms: DEFAULT_SP_SIGNATURE_ALGORITHMS,
         | 
| 53 53 | 
             
                supported_groups: DEFAULT_SP_NAMED_GROUP_LIST,
         | 
| 54 54 | 
             
                alpn: nil,
         | 
| 55 | 
            +
                process_ocsp_response: nil,
         | 
| 55 56 | 
             
                compatibility_mode: true,
         | 
| 56 57 | 
             
                loglevel: Logger::WARN
         | 
| 57 58 | 
             
              }.freeze
         | 
| @@ -236,10 +237,14 @@ module TTTLS13 | |
| 236 237 |  | 
| 237 238 | 
             
                      ch = transcript[CH]
         | 
| 238 239 | 
             
                      rsl = @send_record_size \
         | 
| 239 | 
            -
                         | 
| 240 | 
            +
                        if ch.extensions.include?(Message::ExtensionType::RECORD_SIZE_LIMIT)
         | 
| 240 241 | 
             
                      ee = transcript[EE] = gen_encrypted_extensions(ch, @alpn, rsl)
         | 
| 241 242 | 
             
                      # TODO: [Send CertificateRequest]
         | 
| 242 | 
            -
             | 
| 243 | 
            +
             | 
| 244 | 
            +
                      # status_request
         | 
| 245 | 
            +
                      ocsp_response = fetch_ocsp_response \
         | 
| 246 | 
            +
                        if ch.extensions.include?(Message::ExtensionType::STATUS_REQUEST)
         | 
| 247 | 
            +
                      ct = transcript[CT] = gen_certificate(@crt, @chain, ocsp_response)
         | 
| 243 248 | 
             
                      digest = CipherSuite.digest(@cipher_suite)
         | 
| 244 249 | 
             
                      cv = transcript[CV] = gen_certificate_verify(
         | 
| 245 250 | 
             
                        @key,
         | 
| @@ -350,7 +355,7 @@ module TTTLS13 | |
| 350 355 | 
             
                #
         | 
| 351 356 | 
             
                # @return [TTTLS13::Message::ServerHello]
         | 
| 352 357 | 
             
                def send_hello_retry_request(ch1, cipher_suite)
         | 
| 353 | 
            -
                  exs =  | 
| 358 | 
            +
                  exs = Message::Extensions.new
         | 
| 354 359 | 
             
                  # supported_versions
         | 
| 355 360 | 
             
                  exs << Message::Extension::SupportedVersions.new(
         | 
| 356 361 | 
             
                    msg_type: Message::HandshakeType::SERVER_HELLO
         | 
| @@ -372,7 +377,7 @@ module TTTLS13 | |
| 372 377 | 
             
                    random: Message::HRR_RANDOM,
         | 
| 373 378 | 
             
                    legacy_session_id_echo: ch1.legacy_session_id,
         | 
| 374 379 | 
             
                    cipher_suite: cipher_suite,
         | 
| 375 | 
            -
                    extensions:  | 
| 380 | 
            +
                    extensions: exs
         | 
| 376 381 | 
             
                  )
         | 
| 377 382 | 
             
                  send_handshakes(Message::ContentType::HANDSHAKE, [sh],
         | 
| 378 383 | 
             
                                  Cryptograph::Passer.new)
         | 
| @@ -404,11 +409,16 @@ module TTTLS13 | |
| 404 409 |  | 
| 405 410 | 
             
                # @param crt [OpenSSL::X509::Certificate]
         | 
| 406 411 | 
             
                # @param chain [Array of OpenSSL::X509::Certificate]
         | 
| 412 | 
            +
                # @param ocsp_response [OpenSSL::OCSP::Response]
         | 
| 407 413 | 
             
                #
         | 
| 408 414 | 
             
                # @return [TTTLS13::Message::Certificate, nil]
         | 
| 409 | 
            -
                def gen_certificate(crt, chain = [])
         | 
| 410 | 
            -
                   | 
| 411 | 
            -
                   | 
| 415 | 
            +
                def gen_certificate(crt, chain = [], ocsp_response = nil)
         | 
| 416 | 
            +
                  exs = Message::Extensions.new
         | 
| 417 | 
            +
                  # status_request
         | 
| 418 | 
            +
                  exs << Message::Extension::OCSPResponse.new(ocsp_response) \
         | 
| 419 | 
            +
                    unless ocsp_response.nil?
         | 
| 420 | 
            +
                  ces = [Message::CertificateEntry.new(crt, exs)] \
         | 
| 421 | 
            +
                        + (chain || []).map { |c| Message::CertificateEntry.new(c) }
         | 
| 412 422 | 
             
                  Message::Certificate.new(certificate_list: ces)
         | 
| 413 423 | 
             
                end
         | 
| 414 424 |  | 
| @@ -444,7 +454,7 @@ module TTTLS13 | |
| 444 454 | 
             
                # @return [TTTLS13::Message::Extensions]
         | 
| 445 455 | 
             
                # @return [OpenSSL::PKey::EC.$Object]
         | 
| 446 456 | 
             
                def gen_sh_extensions(named_group)
         | 
| 447 | 
            -
                  exs =  | 
| 457 | 
            +
                  exs = Message::Extensions.new
         | 
| 448 458 | 
             
                  # supported_versions: only TLS 1.3
         | 
| 449 459 | 
             
                  exs << Message::Extension::SupportedVersions.new(
         | 
| 450 460 | 
             
                    msg_type: Message::HandshakeType::SERVER_HELLO
         | 
| @@ -455,7 +465,7 @@ module TTTLS13 | |
| 455 465 | 
             
                             = Message::Extension::KeyShare.gen_sh_key_share(named_group)
         | 
| 456 466 | 
             
                  exs << key_share
         | 
| 457 467 |  | 
| 458 | 
            -
                  [ | 
| 468 | 
            +
                  [exs, priv_key]
         | 
| 459 469 | 
             
                end
         | 
| 460 470 |  | 
| 461 471 | 
             
                # @param ch [TTTLS13::Message::ClientHello]
         | 
| @@ -464,15 +474,16 @@ module TTTLS13 | |
| 464 474 | 
             
                #
         | 
| 465 475 | 
             
                # @return [TTTLS13::Message::Extensions]
         | 
| 466 476 | 
             
                def gen_ee_extensions(ch, alpn, record_size_limit)
         | 
| 467 | 
            -
                  exs =  | 
| 477 | 
            +
                  exs = Message::Extensions.new
         | 
| 468 478 |  | 
| 469 479 | 
             
                  # server_name
         | 
| 470 480 | 
             
                  exs << Message::Extension::ServerName.new('') \
         | 
| 471 481 | 
             
                    if ch.extensions.include?(Message::ExtensionType::SERVER_NAME)
         | 
| 472 482 |  | 
| 473 483 | 
             
                  # supported_groups
         | 
| 474 | 
            -
                  exs  | 
| 475 | 
            -
             | 
| 484 | 
            +
                  exs << Message::Extension::SupportedGroups.new(
         | 
| 485 | 
            +
                    @settings[:supported_groups]
         | 
| 486 | 
            +
                  )
         | 
| 476 487 |  | 
| 477 488 | 
             
                  # alpn
         | 
| 478 489 | 
             
                  exs << Message::Extension::Alpn.new([alpn]) unless alpn.nil?
         | 
| @@ -481,7 +492,7 @@ module TTTLS13 | |
| 481 492 | 
             
                  exs << Message::Extension::RecordSizeLimit.new(record_size_limit) \
         | 
| 482 493 | 
             
                    unless record_size_limit.nil?
         | 
| 483 494 |  | 
| 484 | 
            -
                   | 
| 495 | 
            +
                  exs
         | 
| 485 496 | 
             
                end
         | 
| 486 497 |  | 
| 487 498 | 
             
                # @param key [OpenSSL::PKey::PKey]
         | 
| @@ -543,6 +554,11 @@ module TTTLS13 | |
| 543 554 |  | 
| 544 555 | 
             
                  matching_san?(crt, server_name)
         | 
| 545 556 | 
             
                end
         | 
| 557 | 
            +
             | 
| 558 | 
            +
                # @return [OpenSSL::OCSP::Response, nil]
         | 
| 559 | 
            +
                def fetch_ocsp_response
         | 
| 560 | 
            +
                  @settings[:process_ocsp_response]&.call
         | 
| 561 | 
            +
                end
         | 
| 546 562 | 
             
              end
         | 
| 547 563 | 
             
              # rubocop: enable Metrics/ClassLength
         | 
| 548 564 | 
             
            end
         | 
    
        data/lib/tttls1.3/version.rb
    CHANGED
    
    
    
        data/spec/extensions_spec.rb
    CHANGED
    
    | @@ -2,6 +2,7 @@ | |
| 2 2 | 
             
            # frozen_string_literal: true
         | 
| 3 3 |  | 
| 4 4 | 
             
            require_relative 'spec_helper'
         | 
| 5 | 
            +
            using Refinements
         | 
| 5 6 |  | 
| 6 7 | 
             
            RSpec.describe Extensions do
         | 
| 7 8 | 
             
              context 'empty extensions' do
         | 
| @@ -167,4 +168,19 @@ RSpec.describe Extensions do | |
| 167 168 | 
             
                  expect(extensions).to include ExtensionType::RECORD_SIZE_LIMIT
         | 
| 168 169 | 
             
                end
         | 
| 169 170 | 
             
              end
         | 
| 171 | 
            +
             | 
| 172 | 
            +
              context 'duplicated extension_type' do
         | 
| 173 | 
            +
                let(:server_name) do
         | 
| 174 | 
            +
                  ServerName.new('example.com')
         | 
| 175 | 
            +
                end
         | 
| 176 | 
            +
             | 
| 177 | 
            +
                let(:testbinary) do
         | 
| 178 | 
            +
                  server_name.serialize * 2
         | 
| 179 | 
            +
                end
         | 
| 180 | 
            +
             | 
| 181 | 
            +
                it 'should raise error, if extension_type get duplicated' do
         | 
| 182 | 
            +
                  expect { Extensions.deserialize(testbinary, HandshakeType::CLIENT_HELLO) }
         | 
| 183 | 
            +
                    .to raise_error(ErrorAlerts)
         | 
| 184 | 
            +
                end
         | 
| 185 | 
            +
              end
         | 
| 170 186 | 
             
            end
         | 
    
        data/spec/server_hello_spec.rb
    CHANGED
    
    | @@ -187,7 +187,7 @@ RSpec.describe ServerHello do | |
| 187 187 | 
             
                let(:message) do
         | 
| 188 188 | 
             
                  sh = ServerHello.deserialize(TESTBINARY_SERVER_HELLO)
         | 
| 189 189 | 
             
                  extensions = sh.instance_variable_get(:@extensions)
         | 
| 190 | 
            -
                  extensions | 
| 190 | 
            +
                  extensions.delete(ExtensionType::SUPPORTED_VERSIONS)
         | 
| 191 191 | 
             
                  sh.instance_variable_set(:@extensions, extensions)
         | 
| 192 192 | 
             
                  sh
         | 
| 193 193 | 
             
                end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: tttls1.3
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.2. | 
| 4 | 
            +
              version: 0.2.13
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - thekuwayama
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2020-01- | 
| 11 | 
            +
            date: 2020-01-08 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: bundler
         |