module Ronin::Support::Network::SSL

Top-level SSL methods.

Constants

VERIFY

SSL verify modes

VERSIONS

SSL/TLS versions

Public Class Methods

accept(**kwargs) { |ssl_client| ... } click to toggle source

Creates a new SSL socket listening on a given host and port, accepts only one client and then stops listening.

@param [Hash{Symbol => Object}] kwargs

Additional keyword arguments for {server}.

@!macro server_kwargs

@yield [client]

The given block will be passed the newly connected client.
After the block has finished, both the client and the server will
be closed.

@yieldparam [OpenSSL::SSL::SSLSocket] client

The newly connected client.

@return [nil]

@example

ssl_accept(1337) do |client|
  client.puts 'lol'
end

@example Using a self-signed certificate:e

# $ openssl genrsa -out ssl.key 1024
# $ openssl req -new -key ssl.key -x509 -days 3653 -out ssl.crt
# $ cat ssl.key ssl.crt > ssl.pem
# $ chmod 600 ssl.key ssl.pem
SSL.accept(port: 1337, cert: 'ssl.crt', key: 'ssl.key') do |client|
  client.puts 'lol'
end

@api public

@since 1.1.0

# File lib/ronin/support/network/ssl.rb, line 744
def self.accept(**kwargs)
  server_session(**kwargs) do |server|
    ssl_client = server.accept

    yield ssl_client if block_given?
    ssl_client.close
  end
end
banner(host,port,**kwargs) { |banner| ... } click to toggle source

Reads the banner from the service running on the given host and port.

@param [String] host

The host to connect to.

@param [Integer] port

The port to connect to.

@param [Hash{Symbol => Object}] kwargs

Additional keyword arguments for {connect}.

@!macro connect_kwargs

@yield [banner]

If a block is given, it will be passed the grabbed banner.

@yieldparam [String] banner

The grabbed banner.

@return [String]

The grabbed banner.

@example

SSL.banner('smtp.gmail.com',465)
# => "220 mx.google.com ESMTP c20sm3096959rvf.1"

@api public

@since 1.1.0

cert() click to toggle source

The default SSL certificate used for all SSL server sockets.

@return [Crypto::Cert]

The default SSL certificate.
# File lib/ronin/support/network/ssl.rb, line 85
def self.cert
  @cert ||= LocalCert.fetch
end
cert=(new_cert) click to toggle source

Overrides the default SSL certificate.

@param [Crypto::Cert, OpenSSL::X509::Certificate] new_cert

The new SSL certificate.

@return [Crypto::Cert, OpenSSL::X509::Certificate]

The new default SSL certificate.
# File lib/ronin/support/network/ssl.rb, line 98
def self.cert=(new_cert)
  @cert = new_cert
end
connect(host,port, hostname: host, bind_host: nil, bind_port: nil, **kwargs) { |ssl_socket| ... } click to toggle source

Establishes a SSL connection.

@param [String] host

The host to connect to.

@param [Integer] port

The port to connect to.

@param [String, nil] hostname

Sets the hostname used for SNI.

@param [String] bind_host

The local host to bind to.

@param [Integer] bind_port

The local port to bind to.

@param [Hash{Symbol => Object}] kwargs

Additional keyword arguments for {socket}.

@!macro context_kwargs

@yield [ssl_socket]

The given block will be passed the new SSL socket. Once the block
returns the SSL socket will be closed.

@yieldparam [OpenSSL::SSL::SSLSocket] ssl_socket

The new SSL Socket.

@return [OpenSSL::SSL::SSLSocket, nil]

The new SSL Socket. If a block is given, then `nil` will be
returned.

@example

socket = ssl_connect('twitter.com',443)

@example

ssl_connect('twitter.com',443) do |sock|
  sock.write("GET / HTTP/1.1\n\r\n\r")

  sock.each_line { |line| puts line }
end

@see rubydoc.info/stdlib/openssl/OpenSSL/SSL/SSLSocket

@example

socket = SSL.connect('twitter.com',443)

@example

SSL.connect('twitter.com',443) do |sock|
  sock.write("GET / HTTP/1.1\n\r\n\r")

  sock.each_line { |line| puts line }
end

@api public

@since 1.1.0

# File lib/ronin/support/network/ssl.rb, line 375
def self.connect(host,port, hostname: host,
                            bind_host: nil,
                            bind_port: nil,
                            **kwargs)
  socket     = TCP.connect(host,port,bind_host: bind_host,
                                     bind_port: bind_port)
  ssl_socket = self.socket(socket,**kwargs)

  ssl_socket.hostname = hostname
  ssl_socket.connect

  if block_given?
    yield ssl_socket
    ssl_socket.close
  else
    return ssl_socket
  end
end
connect_and_send(data,host,port,**kwargs) { |socket| ... } click to toggle source

Creates a new SSL connection and sends the given data.

@param [String] data

The data to send through the connection.

@param [String] host

The host to connect to.

@param [Integer] port

The port to connect to.

@param [Hash{Symbol => Object}] kwargs

Additional keyword arguments for {connect}.

@!macro connect_kwargs

@yield [ssl_socket]

The given block will be passed the newly created SSL Socket.

@yieldparam [OpenSSL::SSL::SSLSocket] ssl_socket

The newly created SSL Socket.

@api public

@since 1.1.0

# File lib/ronin/support/network/ssl.rb, line 421
def self.connect_and_send(data,host,port,**kwargs)
  socket = connect(host,port,**kwargs)
  socket.write(data)

  yield socket if block_given?
  return socket
end
context(version: nil, min_version: nil, max_version: nil, verify: :none, key: nil, key_file: nil, cert: nil, cert_file: nil, ca_bundle: nil) click to toggle source

Creates a new SSL Context.

@param [1, 1.1, 1.2, 1.3, Symbol, nil] version

The SSL version to use.

@param [1, 1.1, 1.2, 1.3, Symbol, nil] min_version

The minimum SSL version to use.

@param [1, 1.1, 1.2, 1.3, Symbol, nil] max_version

The maximum SSL version to use.

@param [Symbol, Boolean] verify

Specifies whether to verify the SSL certificate.
May be one of the following:

* `:none`
* `:peer`
* `:fail_if_no_peer_cert`
* `:client_once`

@param [Crypto::Key::RSA, OpenSSL::PKey::RSA, nil] key

The RSA key to use for the SSL context.

@param [String, nil] key_file

The path to the RSA `.key` file.

@param [Crypto::Cert, OpenSSL::X509::Certificate, nil] cert

The X509 certificate to use for the SSL context.

@param [String, nil] cert_file

The path to the SSL `.crt` or `.pem` file.

@param [String, nil] ca_bundle

Path to the CA bundle file or directory.

@return [OpenSSL::SSL::SSLContext]

The newly created SSL Context.

@raise [ArgumentError]

`cert_file:` or `cert:` keyword arguments also require a `key_file:`
or `key:` keyword argument.

@api semipublic

@since 1.0.0

# File lib/ronin/support/network/ssl.rb, line 149
def self.context(version:     nil,
                 min_version: nil,
                 max_version: nil,
                 verify:      :none,
                 key:         nil,
                 key_file:    nil,
                 cert:        nil,
                 cert_file:   nil,
                 ca_bundle:   nil)
  context = OpenSSL::SSL::SSLContext.new

  if version
    version = VERSIONS.fetch(version,version)

    context.min_version = context.max_version = version
  else min_version || max_version
    if min_version
      context.min_version = VERSIONS.fetch(min_version,min_version)
    end

    if max_version
      context.max_version = VERSIONS.fetch(max_version,max_version)
    end
  end

  context.verify_mode = VERIFY[verify]

  if (key_file || key) && (cert_file || cert)
    context.key  = if key_file then Crypto::Key.load_file(key_file)
                   else             key
                   end

    context.cert = if cert_file then Crypto::Cert.load_file(cert_file)
                   else              cert
                   end
  elsif (key_file || key) || (cert_file || cert)
    raise(ArgumentError,"cert_file: and cert: keyword arguments also require a key_file: or key: keyword argument")
  end

  if ca_bundle
    if File.file?(ca_bundle)
      context.ca_file = ca_bundle
    elsif File.directory?(ca_bundle)
      context.ca_path = ca_bundle
    end
  end

  return context
end
get_cert(host,port,**kwargs) click to toggle source

Connects to the host and port and returns the server’s certificate.

@param [String] host

The host to connect to.

@param [Integer] port

The port to connect to.

@param [Hash{Symbol => Object}] kwargs

Additional keyword arguments for {connect}.

@!macro connect_kwargs

@return [Crypto::Cert]

The server's certificate.

@api public

@since 1.1.0

# File lib/ronin/support/network/ssl.rb, line 450
def self.get_cert(host,port,**kwargs)
  socket = connect(host,port,**kwargs)
  cert   = Crypto::Cert(socket.peer_cert)

  socket.close
  return cert
end
key() click to toggle source

The default RSA key used for all SSL server sockets.

@return [Crypto::Key::RSA]

The default RSA key.
# File lib/ronin/support/network/ssl.rb, line 62
def self.key
  @key ||= LocalKey.fetch
end
key=(new_key) click to toggle source

Overrides the default RSA key.

@param [Crypto::Key::RSA, OpenSSL::PKey::RSA] new_key

The new RSA key.

@return [Crypto::Key::RSA, OpenSSL::PKey::RSA]

The new default RSA key.
# File lib/ronin/support/network/ssl.rb, line 75
def self.key=(new_key)
  @key = new_key
end
open?(host,port, timeout: 5, **kwargs) click to toggle source

Tests whether a remote SSLed TCP port is open.

@param [String] host

The host to connect to.

@param [Integer] port

The port to connect to.

@param [Integer] timeout (5)

The maximum time to attempt connecting.

@param [Hash{Symbol => Object}] kwargs

Additional keyword arguments for {connect}.

@!macro connect_kwargs

@return [Boolean, nil]

Specifies whether the remote SSLed TCP port is open.
If the connection was not accepted, `nil` will be returned.

@example

ssl_open?('www.bankofamerica.com',443)

@example Using a timeout:

ssl_open?('example.com',80, timeout: 5)
# => nil

@api public

@since 1.1.0

# File lib/ronin/support/network/ssl.rb, line 303
def self.open?(host,port, timeout: 5, **kwargs)
  Timeout.timeout(timeout) do
    connect(host,port,**kwargs)
  end

  return true
rescue Timeout::Error
  return nil
rescue SocketError, SystemCallError
  return false
end
send(data,host,port,**kwargs) click to toggle source

Connects to a specified host and port, sends the given data and then closes the connection.

@param [String] data

The data to send through the connection.

@param [String] host

The host to connect to.

@param [Integer] port

The port to connect to.

@param [Hash{Symbol => Object}] kwargs

Additional keyword arguments for {connect}.

@!macro connect_kwargs

@return [true]

The data was successfully sent.

@example

buffer = "GET /#{'A' * 4096}\n\r"
SSL.send(buffer,'victim.com',443)
# => true

@api public

@since 1.1.0

# File lib/ronin/support/network/ssl.rb, line 531
def self.send(data,host,port,**kwargs)
  connect(host,port,**kwargs) do |socket|
    socket.write(data)
  end

  return true
end
server(port: 0, host: nil, backlog: 5, key: Network::SSL.key, cert: Network::SSL.cert, **kwargs) { |ssl_server| ... } click to toggle source

Creates a new SSL server listening on a given host and port.

@param [Integer] port

The local port to listen on.

@param [String, nil] host

The host to bind to.

@param [Integer] backlog (5)

The maximum backlog of pending connections.

@param [Crypto::Key::RSA, OpenSSL::PKey::RSA, nil] key

The RSA key to use for the SSL context.

@param [Crypto::Cert, OpenSSL::X509::Certificate, nil] cert

The X509 certificate to use for the SSL context.

@!macro context_kwargs

@yield [server]

The given block will be passed the newly created SSL server.

@yieldparam [OpenSSL::SSL::SSLServer] server

The newly created SSL server.

@return [OpenSSL::SSL::SSLServer]

The newly created SSL server.

@api public

@since 1.1.0

# File lib/ronin/support/network/ssl.rb, line 602
def self.server(port:    0,
                host:    nil,
                backlog: 5,
                key:     Network::SSL.key,
                cert:    Network::SSL.cert,
                **kwargs)
  context    = self.context(key: key, cert: cert, **kwargs)
  tcp_server = TCP.server(port: port, host: host, backlog: backlog)
  ssl_server = OpenSSL::SSL::SSLServer.new(tcp_server,context)

  yield ssl_server if block_given?
  return ssl_server
end
server_loop(**kwargs) { |ssl_client| ... } click to toggle source

Creates a new SSL socket listening on a given host and port, accepting clients in a loop.

@param [Hash{Symbol => Object}] kwargs

Additional keyword arguments for {server}.

@!macro server_kwargs

@yield [client]

The given block will be passed the newly connected client.
After the block has finished, the client will be closed.

@yieldparam [OpenSSL::SSL::SSLSocket] client

A newly connected client.

@return [nil]

@example

# $ openssl genrsa -out ssl.key 1024
# $ openssl req -new -key ssl.key -x509 -days 3653 -out ssl.crt
# $ cat ssl.key ssl.crt > ssl.pem
# $ chmod 600 ssl.key ssl.pem
SSL.server_loop(port: 1337, cert: 'ssl.crt', key: 'ssl.key') do |sock|
  sock.puts 'lol'
end

@api public

@since 1.1.0

# File lib/ronin/support/network/ssl.rb, line 696
def self.server_loop(**kwargs)
  server(**kwargs) do |ssl_server|
    loop do
      ssl_client = ssl_server.accept

      yield ssl_client if block_given?
      ssl_client.close
    end
  end
end
server_session(**kwargs,&block) click to toggle source

Creates a new temporary SSL server listening on a given host and port.

@param [Hash{Symbol => Object}] kwargs

Additional keyword arguments for {server}.

@!macro server_kwargs

@yield [server]

The given block will be passed the newly created SSL server.
Once the block has finished, the server will be closed.

@yieldparam [OpenSSL::SSL::SSLServer] server

The newly created SSL server.

@return [OpenSSL::SSL::SSLServer]

The newly created SSL server.

@api public

@since 1.1.0

# File lib/ronin/support/network/ssl.rb, line 659
def self.server_session(**kwargs,&block)
  ssl_server = self.server(**kwargs,&block)
  ssl_server.close
  return ssl_server
end
server_socket(socket, key: Network::SSL.key, cert: Network::SSL.cert, **kwargs) click to toggle source

Accepts an SSL session from an existing TCP socket.

@param [TCPSocket] socket

The existing TCP socket.

@param [Crypto::Key::RSA, OpenSSL::PKey::RSA, nil] key

The RSA key to use for the SSL context.

@param [Crypto::Cert, OpenSSL::X509::Certificate, nil] cert

The X509 certificate to use for the SSL context.

@param [Hash{Symbol => Object}] kwargs

Additional keyword arguments for {socket}.

@!macro context_kwargs

@return [OpenSSL::SSL::SSLSocket]

The new SSL Socket.

@api public

@since 1.1.0

# File lib/ronin/support/network/ssl.rb, line 563
def self.server_socket(socket, key:  Network::SSL.key,
                               cert: Network::SSL.cert,
                               **kwargs)
  socket(socket, cert: cert, key: key, **kwargs)
end
socket(socket,**kwargs) click to toggle source

Initiates an SSL session with an existing TCP socket.

@param [TCPSocket] socket

The existing TCP socket.

@param [Hash{Symbol => Object}] kwargs

Additional keyword arguments for {context}.

@!macro context_kwargs

@return [OpenSSL::SSL::SSLSocket]

The new SSL Socket.

@api public

@since 1.1.0

# File lib/ronin/support/network/ssl.rb, line 253
def self.socket(socket,**kwargs)
  ssl_socket = OpenSSL::SSL::SSLSocket.new(socket,context(**kwargs))

  ssl_socket.sync_close = true
  return ssl_socket
end