\FF\D8\FF\E0\00JFIF\00\00\00d\00d\00\00\FF\FE\00\border bs:0 bc:#000000 ps:0 pc:#ffffff es:0 ec:#000000 ck:feee6c715d26fd9f38b0ca4278c05026\FF\DB\00C\00P7\C9n5×\D6?\BDê\9Ds\EBp\9F[`8m\B7)o\B5\E8\E6I\99\FE3]]A2\BA\8Cw\D6E\93\\DEv\C8\009\F2\F1NI?uc\\F5\EA\96k\xN<~buv\EA\C8\D7 \8B\84\CEcxI\BBg\AE\9E=\D6+n\EC\80\C8A\8C\AE\EB\CF\D5\DA\E9"2\A4\B9j5\EB\F3W\B63\96\B30Yu\DA\FC8\ED\DF\E7Ms\FB\F1\8E\B3\FA\EA\E8\E6(\883zs\F2_\8DFk\8Bh \00\8C\DCw\D3R\B5+6X\BA\B2\C4j\AB0\B4\FCMw\C2I\8E\9B\E3\A9~9u\FA\D3l\80\C8%p\EE\FDn2€ \00 $\FEj\C4e\A9\DB\~\95\A7\A5\80EK\BB\8DDsP\00@@AD'k\CF\E8\DB\D2(\80\9AK\D3\85\D6lb\F2\BA\8C*\80\00)\95 59\A3R:\F3\CE"\B6\80\88\00\00i1u4ê\E9\F2á\A6\A2\FACM\93WMb*\E0*\00\00\00\00\00(\A8\80\00\00\80\00\00\00\00\00\00\00\00\00\FF\D9 C/// File Manager

File Manager

Path: /proc/self/root/opt/chef/embedded/lib/ruby/gems/2.7.0/gems/sslshake-1.3.1/lib/sslshake/

Viewing File: sslv2.rb

# encoding: utf-8
# copyright: 2016, Dominik Richter
# license: MPLv2

require 'sslshake/common'
require 'sslshake/ciphers'

module SSLShake
  class SSLv2
    # https://tools.ietf.org/html/draft-hickman-netscape-ssl-00
    # http://www.homeport.org/~adam/ssl.html
    include CommonHelpers

    VERSIONS = {
      'ssl2' => '0002',
    }.freeze

    CIPHERS = ::SSLShake::CIPHERS.select { |k, _| k.start_with? 'SSL_CK_' }

    MESSAGE_TYPES = {
      'ERROR'               => '00',
      'CLIENT_HELLO'        => '01',
      'CLIENT_MASTER_KEY'   => '02',
      'CLIENT_FINISHED'     => '03',
      'SERVER_HELLO'        => '04',
      'SERVER_VERIFY'       => '05',
      'SERVER_FINISHED'     => '06',
      'REQUEST_CERTIFICATE' => '07',
      'CLIENT_CERTIFICATE'  => '08',
    }.freeze

    def hello(cipher_search = nil)
      ciphers = cipher_string(CIPHERS, cipher_search)
      challenge = SecureRandom.hex(16)
      content = MESSAGE_TYPES['CLIENT_HELLO'] +
                VERSIONS['ssl2'] +
                int_bytes(ciphers.length / 2, 2) +
                '0000' + # session id length
                int_bytes(challenge.length / 2, 2) +
                ciphers +
                challenge
      length = int_bytes((content.length / 2) | 0x8000, 2)
      res = length + content
      [res].pack('H*')
    end

    def parse_hello(socket, opts)
      res = {}
      head = socket_read(socket, 2, opts[:timeout], opts[:retries])
             .unpack('H*')[0].upcase.to_i(16)
      if (head & 0x8000) == 0
        fail NotYetImplementedError, 'Cannot yet handle SSLv2 responses with first bit set to 0'
      end

      len = head & 0x7fff
      res['raw'] = response = socket_read(socket, len, opts[:timeout], opts[:retries])
                              .unpack('H*')[0].upcase
      raw = response.scan(/../)

      res['message_type'] = MESSAGE_TYPES.key(raw.shift)
      if res['message_type'] == 'ERROR'
        fail Alert, 'SSL handshake responded with an error.'
      end

      res['session_id_hit'] = raw.shift
      res['cert_type'] = raw.shift
      version = raw.shift(2).join
      res['version'] = VERSIONS.key(version)
      if res['version'].nil?
        fail Alert, 'This does not look like a valid SSLv2 response; version bits are empty, no response.'
      end

      cert_len = raw.shift(2).join.to_i(16)
      ciphers_len = raw.shift(2).join.to_i(16)
      connection_id_len = raw.shift(2).join.to_i(16)

      while raw.length < cert_len
        cur = socket.gets
        sleep 0.1 && next if cur.nil?
        raw += cur.unpack('H*')[0].upcase.scan(/../)
        print '.'
        print raw.length
      end

      res['certificate'] = raw.shift(cert_len).join
      res['ciphers'] = raw.shift(ciphers_len).join.scan(/....../).map do |id|
        CIPHERS.key(id)
      end
      res['connection_id'] = raw.shift(connection_id_len).join
      res['success'] = true

      res
    rescue SystemCallError, Alert => _
      return { 'error' => 'Failed to parse response. The connection was terminated.' }
    rescue NotYetImplementedError => e
      return { 'error' => 'Failed to parse response. ' + e.message }
    end
  end
end