Module: SSLScan::Socket::SslTcpServer

Includes:
TcpServer
Defined in:
lib/ssl_scan/socket/ssl_tcp_server.rb

Overview

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

Constant Summary collapse

@@loaded_openssl =
false

Constants included from SSLScan::Socket

MATCH_IPV4, MATCH_IPV4_PRIVATE, MATCH_IPV6

Instance Attribute Summary collapse

Attributes included from IO::StreamServer

#client_waiter, #clients, #clients_thread, #listener_thread, #on_client_close_proc, #on_client_connect_proc, #on_client_data_proc

Attributes included from SSLScan::Socket

#context, #ipv, #localhost, #localport, #peerhost, #peerport

Class Method Summary collapse

Instance Method Summary collapse

Methods included from IO::StreamServer

#close_client, #on_client_close, #on_client_connect, #on_client_data, #start, #stop, #wait

Methods included from SSLScan::Socket

addr_atoc, addr_atoi, addr_atoi_list, addr_aton, addr_ctoa, addr_itoa, addr_iton, addr_ntoa, addr_ntoi, bit2netmask, cidr_crack, compress_address, create_ip, create_tcp, create_tcp_server, create_udp, dotted_ip?, eth_aton, eth_ntoa, #fd, from_sockaddr, getaddress, getaddresses, gethostbyname, #getlocalname, #getpeername, #getsockname, ipv6_link_address, ipv6_mac, is_internal?, is_ipv4?, is_ipv6?, net2bitmask, portlist_to_portspec, portspec_crack, portspec_to_portlist, resolv_nbo, resolv_nbo_i, resolv_nbo_i_list, resolv_nbo_list, resolv_to_dotted, source_address, support_ipv6?, tcp_socket_pair, to_sockaddr, #type?, udp_socket_pair

Instance Attribute Details

#sslctxObject

Returns the value of attribute sslctx.



184
185
186
# File 'lib/ssl_scan/socket/ssl_tcp_server.rb', line 184

def sslctx
  @sslctx
end

Class Method Details

.create(hash = {}) ⇒ Object

Factory



29
30
31
32
33
34
# File 'lib/ssl_scan/socket/ssl_tcp_server.rb', line 29

def self.create(hash = {})
  hash['Proto']  = 'tcp'
  hash['Server'] = true
  hash['SSL']    = true
  self.create_param(SSLScan::Socket::Parameters.from_hash(hash))
end

.create_param(param) ⇒ Object

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



40
41
42
43
44
45
# File 'lib/ssl_scan/socket/ssl_tcp_server.rb', line 40

def self.create_param(param)
  param.proto  = 'tcp'
  param.server = true
  param.ssl    = true
  SSLScan::Socket.create_param(param)
end

Instance Method Details

#accept(opts = {}) ⇒ Object

Accepts a child connection.



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/ssl_scan/socket/ssl_tcp_server.rb', line 54

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(SSLScan::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) ⇒ Boolean

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

Returns:

  • (Boolean)


176
177
178
179
180
181
182
# File 'lib/ssl_scan/socket/ssl_tcp_server.rb', line 176

def allow_nonblock?(sock=self.sock)
  avail = sock.respond_to?(:accept_nonblock)
  if avail and SSLScan::Compat.is_windows
    return true
  end
  false
end

#initsock(params = nil) ⇒ Object

Raises:



47
48
49
50
51
# File 'lib/ssl_scan/socket/ssl_tcp_server.rb', line 47

def initsock(params = nil)
  raise RuntimeError, "No OpenSSL support" if not @@loaded_openssl
  self.sslctx  = makessl(params)
  super
end

#makessl(params) ⇒ ::OpenSSL::SSL::SSLContext

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

Parameters:

Returns:

  • (::OpenSSL::SSL::SSLContext)


107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/ssl_scan/socket/ssl_tcp_server.rb', line 107

def makessl(params)
  ssl_cert = params.ssl_cert
  if ssl_cert
    cert = OpenSSL::X509::Certificate.new(ssl_cert)
    key = OpenSSL::PKey::RSA.new(ssl_cert)
  else
    key = OpenSSL::PKey::RSA.new(1024){ }
    cert = OpenSSL::X509::Certificate.new
    cert.version = 2
    cert.serial = rand(0xFFFFFFFF)
    # name = OpenSSL::X509::Name.new([["C","JP"],["O","TEST"],["CN","localhost"]])
    subject = OpenSSL::X509::Name.new([
        ["C","US"],
        ['ST', SSLScan::Text.rand_state()],
        ["L", SSLScan::Text.rand_text_alpha(rand(20) + 10)],
        ["O", SSLScan::Text.rand_text_alpha(rand(20) + 10)],
        ["CN", SSLScan::Text.rand_hostname],
      ])
    issuer = OpenSSL::X509::Name.new([
        ["C","US"],
        ['ST', SSLScan::Text.rand_state()],
        ["L", SSLScan::Text.rand_text_alpha(rand(20) + 10)],
        ["O", SSLScan::Text.rand_text_alpha(rand(20) + 10)],
        ["CN", SSLScan::Text.rand_hostname],
      ])

    cert.subject = subject
    cert.issuer = issuer
    cert.not_before = Time.now - (3600 * 365)
    cert.not_after = Time.now + (3600 * 365)
    cert.public_key = key.public_key
    ef = OpenSSL::X509::ExtensionFactory.new(nil,cert)
    cert.extensions = [
      ef.create_extension("basicConstraints","CA:FALSE"),
      ef.create_extension("subjectKeyIdentifier","hash"),
      ef.create_extension("extendedKeyUsage","serverAuth"),
      ef.create_extension("keyUsage","keyEncipherment,dataEncipherment,digitalSignature")
    ]
    ef.issuer_certificate = cert
    cert.add_extension ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always")
    cert.sign(key, OpenSSL::Digest::SHA1.new)
  end

  ctx = OpenSSL::SSL::SSLContext.new()
  ctx.key = key
  ctx.cert = cert
  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 = SSLScan::Text.rand_text(16)

  return ctx
end