module Rex::Socket::SslTcpServer

This class provides methods for interacting with an SSL wrapped TCP server. It implements the StreamServer IO interface.

Attributes

sslctx[RW]

Public Class Methods

create(hash = {}) click to toggle source

Factory

# File lib/rex/socket/ssl_tcp_server.rb, line 31
def self.create(hash = {})
  hash['Proto']  = 'tcp'
  hash['Server'] = true
  hash['SSL']    = true
  self.create_param(Rex::Socket::Parameters.from_hash(hash))
end
create_param(param) click to toggle source

Wrapper around the base class' creation method that automatically sets the parameter's protocol to TCP and sets the server flag to true.

# File lib/rex/socket/ssl_tcp_server.rb, line 42
def self.create_param(param)
  param.proto  = 'tcp'
  param.server = true
  param.ssl    = true
  Rex::Socket.create_param(param)
end
ssl_generate_certificate() click to toggle source

Generate a realistic-looking but obstensibly fake SSL certificate. This matches a typical “snakeoil” cert.

@return [String, String, Array]

# File lib/rex/socket/ssl_tcp_server.rb, line 132
def self.ssl_generate_certificate
  yr   = 24*3600*365
  vf   = Time.at(Time.now.to_i - rand(yr * 3) - yr)
  vt   = Time.at(vf.to_i + (10 * yr))
  cn   = Rex::Text.rand_text_alpha_lower(rand(8)+2)
  key  = OpenSSL::PKey::RSA.new(2048){ }
  cert = OpenSSL::X509::Certificate.new
  cert.version    = 2
  cert.serial     = (rand(0xFFFFFFFF) << 32) + rand(0xFFFFFFFF)
  cert.subject    = OpenSSL::X509::Name.new([["CN", cn]])
  cert.issuer     = OpenSSL::X509::Name.new([["CN", cn]])
  cert.not_before = vf
  cert.not_after  = vt
  cert.public_key = key.public_key

  ef = OpenSSL::X509::ExtensionFactory.new(nil,cert)
  cert.extensions = [
    ef.create_extension("basicConstraints","CA:FALSE")
  ]
  ef.issuer_certificate = cert

  cert.sign(key, OpenSSL::Digest::SHA256.new)

  [key, cert, nil]
end
ssl_parse_pem(ssl_cert) click to toggle source

Parse a certificate in unified PEM format that contains a private key and one or more certificates. The first certificate is the primary, while any additional certificates are treated as intermediary certificates. This emulates the behavior of web servers like nginx.

@param [String] ssl_cert @return [String, String, Array]

# File lib/rex/socket/ssl_tcp_server.rb, line 116
def self.ssl_parse_pem(ssl_cert)
  Rex::Parser::X509Certificate.parse_pem(ssl_cert)
end

Public Instance Methods

accept(opts = {}) click to toggle source

(see TcpServer#accept)

Calls superclass method Rex::Socket::TcpServer#accept
# File lib/rex/socket/ssl_tcp_server.rb, line 62
def accept(opts = {})
  sock = super()
  return if not sock

  begin
    ssl = OpenSSL::SSL::SSLSocket.new(sock, self.sslctx)

    if not allow_nonblock?(ssl)
      ssl.accept
    else
      begin
        ssl.accept_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( [ ssl ], nil, nil, 0.10 )
          retry
        end

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

        raise e
      end
    end

    sock.extend(Rex::Socket::SslTcp)
    sock.sslsock = ssl
    sock.sslctx  = self.sslctx

    return sock

  rescue ::OpenSSL::SSL::SSLError
    sock.close
    nil
  end
end
allow_nonblock?(sock=self.sock) 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_server.rb, line 205
def allow_nonblock?(sock=self.sock)
  avail = sock.respond_to?(:accept_nonblock)
  if avail and Rex::Compat.is_windows
    return true
  end
  false
end
initsock(params = nil) click to toggle source
Calls superclass method
# File lib/rex/socket/ssl_tcp_server.rb, line 49
def initsock(params = nil)
  raise RuntimeError, 'No OpenSSL support' unless @@loaded_openssl

  if params && params.sslctx && params.sslctx.kind_of?(OpenSSL::SSL::SSLContext)
    self.sslctx = params.sslctx
  else
    self.sslctx  = makessl(params)
  end

  super
end
makessl(params) click to toggle source

Create a new ssl context. If ssl_cert is not given, generates a new key and a leaf certificate with random values.

@param [Rex::Socket::Parameters] params @return [::OpenSSL::SSL::SSLContext]

# File lib/rex/socket/ssl_tcp_server.rb, line 171
def makessl(params)

  if params.ssl_cert
    key, cert, chain = ssl_parse_pem(params.ssl_cert)
  else
    key, cert, chain = ssl_generate_certificate
  end

  ctx = OpenSSL::SSL::SSLContext.new()
  ctx.key = key
  ctx.cert = cert
  ctx.extra_chain_cert = chain
  ctx.options = 0

  # Older versions of OpenSSL do not export the OP_NO_COMPRESSION symbol
  if defined?(OpenSSL::SSL::OP_NO_COMPRESSION)
    # enable/disable the SSL/TLS-level compression
    if params.ssl_compression
      ctx.options &= ~OpenSSL::SSL::OP_NO_COMPRESSION
    else
      ctx.options |= OpenSSL::SSL::OP_NO_COMPRESSION
    end
  end

  ctx.session_id_context = Rex::Text.rand_text(16)

  return ctx
end
ssl_generate_certificate() click to toggle source

Shim for the ssl_generate_certificate module method

# File lib/rex/socket/ssl_tcp_server.rb, line 161
def ssl_generate_certificate
  Rex::Socket::SslTcpServer.ssl_generate_certificate
end
ssl_parse_pem(ssl_cert) click to toggle source

Shim for the ssl_parse_pem module method

# File lib/rex/socket/ssl_tcp_server.rb, line 123
def ssl_parse_pem(ssl_cert)
  Rex::Socket::SslTcpServer.ssl_parse_pem(ssl_cert)
end