module Rex::Socket::SslTcp

This class provides methods for interacting with an SSL TCP client connection.

Public Class Methods

create(hash = {}) click to toggle source

Creates an SSL TCP instance.

# File lib/rex/socket/ssl_tcp.rb, line 32
def self.create(hash = {})
  raise RuntimeError, "No OpenSSL support" if not @@loaded_openssl
  hash['SSL'] = true
  self.create_param(Rex::Socket::Parameters.from_hash(hash))
end
create_param(param) click to toggle source

Set the SSL flag to true and call the base class's create_param routine.

# File lib/rex/socket/ssl_tcp.rb, line 41
def self.create_param(param)
  param.ssl   = true
  Rex::Socket::Tcp.create_param(param)
end
supported_ssl_methods() click to toggle source
# File lib/rex/socket/ssl_tcp.rb, line 61
def self.supported_ssl_methods
  @@methods ||= ['Auto', 'TLS'] + system_ssl_methods
    .reject { |method| method.match(/server|client/) }
    .select {|m| OpenSSL::SSL::SSLContext.new(m) && true rescue false} \
    .map {|m| m.to_s.sub(/v/, '').sub('_', '.')}
end
system_ssl_methods() click to toggle source

Class initialization

# File lib/rex/socket/ssl_tcp.rb, line 52
def self.system_ssl_methods
  ssl_context = OpenSSL::SSL::SSLContext
  if ssl_context.const_defined? :METHODS_MAP
    ssl_context.const_get(:METHODS_MAP).keys
  else
    ssl_context::METHODS
  end
end

Public Instance Methods

allow_nonblock?() click to toggle source

This flag determines whether to use the non-blocking openssl API calls when they are available. This is still buggy on Linux/Mac OS X, but is required on Windows

# File lib/rex/socket/ssl_tcp.rb, line 359
def allow_nonblock?
  avail = self.sslsock.respond_to?(:accept_nonblock)
  if avail and Rex::Compat.is_windows
    return true
  end
  false
end
cipher() click to toggle source

Access to the current cipher

# File lib/rex/socket/ssl_tcp.rb, line 336
def cipher
  sslsock.cipher if sslsock
end
close() click to toggle source

Closes the SSL socket.

Calls superclass method
# File lib/rex/socket/ssl_tcp.rb, line 306
def close
  sslsock.close rescue nil
  super
end
initsock(params = nil) click to toggle source

Initializes the SSL socket.

Calls superclass method
# File lib/rex/socket/ssl_tcp.rb, line 71
def initsock(params = nil)
  super

  # Default to SSLv23 (automatically negotiate)
  version = :SSLv23

  # Let the caller specify a particular SSL/TLS version
  if params
    case params.ssl_version
    when 'SSL2', :SSLv2
      version = :SSLv2
    # 'TLS' will be the new name for autonegotation with newer versions of OpenSSL
    when 'SSL23', :SSLv23, 'TLS'
      version = :SSLv23
    when 'SSL3', :SSLv3
      version = :SSLv3
    when 'TLS1','TLS1.0', :TLSv1
      version = :TLSv1
    when 'TLS1.1', :TLSv1_1
      version = :TLSv1_1
    when 'TLS1.2', :TLSv1_2
      version = :TLSv1_2
    end
  end

  # Raise an error if no selected versions are supported
  unless Rex::Socket::SslTcp.system_ssl_methods.include? version
    raise ArgumentError,
      "This version of Ruby does not support the requested SSL/TLS version #{params.ssl_version}"
  end

  # Try intializing the socket with this SSL/TLS version
  # This will throw an exception if it fails
  initsock_with_ssl_version(params, version)

  # Track the SSL version
  self.ssl_negotiated_version = version
end
initsock_with_ssl_version(params, version) click to toggle source
# File lib/rex/socket/ssl_tcp.rb, line 110
def initsock_with_ssl_version(params, version)
  # Build the SSL connection
  self.sslctx  = OpenSSL::SSL::SSLContext.new(version)

  # Configure the SSL context
  # TODO: Allow the user to specify the verify mode callback
  # Valid modes:
  #  VERIFY_CLIENT_ONCE
  #  VERIFY_FAIL_IF_NO_PEER_CERT
  #  VERIFY_NONE
  #  VERIFY_PEER
  if params.ssl_verify_mode
    self.sslctx.verify_mode = OpenSSL::SSL.const_get("VERIFY_#{params.ssl_verify_mode}".intern)
  else
    # Could also do this as graceful faildown in case a passed verify_mode is not supported
    self.sslctx.verify_mode = OpenSSL::SSL::VERIFY_PEER
  end

  self.sslctx.options = OpenSSL::SSL::OP_ALL

  if params.ssl_cipher
    self.sslctx.ciphers = params.ssl_cipher
  end

  # Set the verification callback
  self.sslctx.verify_callback = Proc.new do |valid, store|
    self.peer_verified = valid
    true
  end

  # Tie the context to a socket
  self.sslsock = OpenSSL::SSL::SSLSocket.new(self, self.sslctx)

  # Force a negotiation timeout
  begin
  Timeout.timeout(params.timeout) do
    if not allow_nonblock?
      self.sslsock.connect
    else
      begin
        self.sslsock.connect_nonblock
      # Ruby 1.8.7 and 1.9.0/1.9.1 uses a standard Errno
      rescue ::Errno::EAGAIN, ::Errno::EWOULDBLOCK
          IO::select(nil, nil, nil, 0.10)
          retry

      # Ruby 1.9.2+ uses IO::WaitReadable/IO::WaitWritable
      rescue ::Exception => e
        if ::IO.const_defined?('WaitReadable') and e.kind_of?(::IO::WaitReadable)
          IO::select( [ self.sslsock ], nil, nil, 0.10 )
          retry
        end

        if ::IO.const_defined?('WaitWritable') and e.kind_of?(::IO::WaitWritable)
          IO::select( nil, [ self.sslsock ], nil, 0.10 )
          retry
        end

        raise e
      end
    end
  end

  rescue ::Timeout::Error
    raise Rex::ConnectionTimeout.new(params.peerhost, params.peerport)
  end
end
peer_cert() click to toggle source

Access to peer cert

# File lib/rex/socket/ssl_tcp.rb, line 322
def peer_cert
  sslsock.peer_cert if sslsock
end
peer_cert_chain() click to toggle source

Access to peer cert chain

# File lib/rex/socket/ssl_tcp.rb, line 329
def peer_cert_chain
  sslsock.peer_cert_chain if sslsock
end
read(length = nil, opts = {}) click to toggle source

Reads data from the SSL socket.

# File lib/rex/socket/ssl_tcp.rb, line 247
def read(length = nil, opts = {})
  if not allow_nonblock?
    length = 16384 unless length
    begin
      return sslsock.sysread(length)
    rescue ::IOError, ::Errno::EPIPE, ::OpenSSL::SSL::SSLError
      return nil
    end
    return
  end


  begin
    while true
      s = Rex::ThreadSafe.select( [ self.sslsock ], nil, nil, 0.10 )
      if( s == nil || s[0] == nil )
        next
      end
      return sslsock.read_nonblock( length )
    end

  rescue ::IOError, ::Errno::EPIPE
    return nil

  # Ruby 1.8.7 and 1.9.0/1.9.1 uses a standard Errno
  rescue ::Errno::EAGAIN, ::Errno::EWOULDBLOCK
    # Sleep for a tenth a second, or until we can read again
    Rex::ThreadSafe.select( [ self.sslsock ], nil, nil, 0.10 )
    # Decrement the block size to handle full sendQs better
    block_size = 1024
    # Try to write the data again
    retry

  # Ruby 1.9.2+ uses IO::WaitReadable/IO::WaitWritable
  rescue ::Exception => e
    if ::IO.const_defined?('WaitReadable') and e.kind_of?(::IO::WaitReadable)
      IO::select( [ self.sslsock ], nil, nil, 0.5 )
      retry
    end

    if ::IO.const_defined?('WaitWritable') and e.kind_of?(::IO::WaitWritable)
      IO::select( nil, [ self.sslsock ], nil, 0.5 )
      retry
    end

    # Another form of SSL error, this is always fatal
    if e.kind_of?(::OpenSSL::SSL::SSLError)
      return nil
    end

    raise e
  end

end
shutdown(how=0) click to toggle source

Ignore shutdown requests

# File lib/rex/socket/ssl_tcp.rb, line 314
def shutdown(how=0)
  # Calling shutdown() on an SSL socket can lead to bad things
  # Cause of http://metasploit.com/dev/trac/ticket/102
end
sysread(*args) click to toggle source

Prevent a sysread from the bare socket

# File lib/rex/socket/ssl_tcp.rb, line 343
def sysread(*args)
  raise RuntimeError, "Invalid sysread() call on SSL socket"
end
syswrite(*args) click to toggle source

Prevent a sysread from the bare socket

# File lib/rex/socket/ssl_tcp.rb, line 350
def syswrite(*args)
  raise RuntimeError, "Invalid syswrite() call on SSL socket"
end
type?() click to toggle source
# File lib/rex/socket/ssl_tcp.rb, line 371
def type?
  return 'tcp-ssl'
end
write(buf, opts = {}) click to toggle source

Writes data over the SSL socket.

# File lib/rex/socket/ssl_tcp.rb, line 187
def write(buf, opts = {})
  return sslsock.write(buf) if not allow_nonblock?

  total_sent   = 0
  total_length = buf.length
  block_size   = 16384
  retry_time   = 0.5

  begin
    while( total_sent < total_length )
      s = Rex::ThreadSafe.select( nil, [ self.sslsock ], nil, 0.25 )
      if( s == nil || s[0] == nil )
        next
      end
      data = buf[total_sent, block_size]
      sent = sslsock.write_nonblock( data )
      if sent > 0
        total_sent += sent
      end
    end

  rescue ::IOError, ::Errno::EPIPE
    return nil

  # Ruby 1.8.7 and 1.9.0/1.9.1 uses a standard Errno
  rescue ::Errno::EAGAIN, ::Errno::EWOULDBLOCK
    # Sleep for a half a second, or until we can write again
    Rex::ThreadSafe.select( nil, [ self.sslsock ], nil, retry_time )
    # Decrement the block size to handle full sendQs better
    block_size = 1024
    # Try to write the data again
    retry

  # Ruby 1.9.2+ uses IO::WaitReadable/IO::WaitWritable
  rescue ::Exception => e
    if ::IO.const_defined?('WaitReadable') and e.kind_of?(::IO::WaitReadable)
      IO::select( [ self.sslsock ], nil, nil, retry_time )
      retry
    end

    if ::IO.const_defined?('WaitWritable') and e.kind_of?(::IO::WaitWritable)
      IO::select( nil, [ self.sslsock ], nil, retry_time )
      retry
    end

    # Another form of SSL error, this is always fatal
    if e.kind_of?(::OpenSSL::SSL::SSLError)
      return nil
    end

    # Bubble the event up to the caller otherwise
    raise e
  end

  total_sent
end