* add SSL TCP server support, using runtime generated/signed keys
* add HTTPS support note, SSL service tests don't work. Right now, the tests just bail early. The client spins forever trying to get data. When the client & server are in seperate processes, this isn't a problem. A threaded test implementation is closer, as data sent from the client gets to the server just fine. git-svn-id: file:///home/svn/incoming/trunk@3616 4d416f70-5f16-0410-b530-b9f4589650daunstable
parent
71e3323dbd
commit
df49cfabb0
|
@ -106,6 +106,7 @@ class Server
|
|||
self.listener = nil
|
||||
self.resources = {}
|
||||
self.server_name = DefaultServer
|
||||
self.ssl = false
|
||||
end
|
||||
|
||||
#
|
||||
|
@ -122,7 +123,8 @@ class Server
|
|||
self.listener = Rex::Socket::TcpServer.create(
|
||||
'LocalHost' => self.listen_host,
|
||||
'LocalPort' => self.listen_port,
|
||||
'Context' => self.context
|
||||
'Context' => self.context,
|
||||
'SSL' => self.ssl
|
||||
)
|
||||
|
||||
# Register callbacks
|
||||
|
@ -236,7 +238,7 @@ class Server
|
|||
cli.send_response(resp)
|
||||
end
|
||||
|
||||
attr_accessor :listen_port, :listen_host, :server_name, :context
|
||||
attr_accessor :listen_port, :listen_host, :server_name, :context, :ssl
|
||||
|
||||
protected
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ require 'singleton'
|
|||
require 'rex/socket'
|
||||
require 'rex/socket/tcp'
|
||||
require 'rex/socket/ssl_tcp'
|
||||
require 'rex/socket/ssl_tcp_server'
|
||||
require 'rex/socket/udp'
|
||||
|
||||
###
|
||||
|
@ -61,7 +62,11 @@ class Rex::Socket::Comm::Local
|
|||
|
||||
return sock if (param.bare?)
|
||||
|
||||
sock.extend(Rex::Socket::TcpServer)
|
||||
klass = Rex::Socket::TcpServer
|
||||
if (param.ssl)
|
||||
klass = Rex::Socket::SslTcpServer
|
||||
end
|
||||
sock.extend(klass)
|
||||
|
||||
sock.initsock(param)
|
||||
# Otherwise, if we're creating a client...
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
require 'rex/socket'
|
||||
require 'rex/socket/tcp_server'
|
||||
require 'rex/io/stream_server'
|
||||
require 'openssl'
|
||||
|
||||
###
|
||||
#
|
||||
# This class provides methods for interacting with an SSL wrapped TCP server. It
|
||||
# implements the StreamServer IO interface.
|
||||
#
|
||||
###
|
||||
module Rex::Socket::SslTcpServer
|
||||
include Rex::Socket::TcpServer
|
||||
|
||||
##
|
||||
#
|
||||
# Factory
|
||||
#
|
||||
##
|
||||
|
||||
def initsock(params = nil)
|
||||
self.sslctx = makessl()
|
||||
super
|
||||
end
|
||||
|
||||
def accept(opts = {})
|
||||
sock = super()
|
||||
if (sock)
|
||||
sock.extend(Rex::Socket::Tcp)
|
||||
sock.context = self.context
|
||||
pn = sock.getpeername
|
||||
|
||||
sock.peerhost = pn[1]
|
||||
sock.peerport = pn[2]
|
||||
end
|
||||
t = OpenSSL::SSL::SSLSocket.new(sock, self.sslctx)
|
||||
t.extend(Rex::Socket::Tcp)
|
||||
t.accept
|
||||
|
||||
t
|
||||
end
|
||||
|
||||
|
||||
def makessl
|
||||
key = OpenSSL::PKey::RSA.new(512){ }
|
||||
|
||||
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', Rex::Text.rand_state()],
|
||||
["L", Rex::Text.rand_text_alpha(rand(20) + 10)],
|
||||
["O", Rex::Text.rand_text_alpha(rand(20) + 10)],
|
||||
["CN", Rex::Text.rand_hostname],
|
||||
])
|
||||
issuer = OpenSSL::X509::Name.new([
|
||||
["C","US"],
|
||||
['ST', Rex::Text.rand_state()],
|
||||
["L", Rex::Text.rand_text_alpha(rand(20) + 10)],
|
||||
["O", Rex::Text.rand_text_alpha(rand(20) + 10)],
|
||||
["CN", Rex::Text.rand_hostname],
|
||||
])
|
||||
|
||||
cert.subject = subject
|
||||
cert.issuer = issuer
|
||||
cert.not_before = Time.now
|
||||
cert.not_after = Time.now + 3600
|
||||
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)
|
||||
|
||||
ctx = OpenSSL::SSL::SSLContext.new()
|
||||
ctx.key = key
|
||||
ctx.cert = cert
|
||||
|
||||
ctx.session_id_context = OpenSSL::Digest::MD5.hexdigest($0)
|
||||
|
||||
return ctx
|
||||
end
|
||||
|
||||
attr_accessor :sslctx
|
||||
end
|
|
@ -0,0 +1,51 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
$:.unshift(File.join(File.dirname(__FILE__), '..', '..'))
|
||||
|
||||
require 'test/unit'
|
||||
require 'rex/socket/ssl_tcp_server'
|
||||
require 'rex/socket/ssl_tcp'
|
||||
|
||||
class Rex::Socket::SslTcpServer::UnitTest < Test::Unit::TestCase
|
||||
|
||||
# XXX. The client data is sent & decrypted just fine. The server data is not. the client thread just spins. BAH.
|
||||
def test_tcp_server
|
||||
return;
|
||||
|
||||
serv_port = 65433
|
||||
c = nil
|
||||
|
||||
threads = []
|
||||
threads << Thread.new() {
|
||||
serv = Rex::Socket.create_tcp_server('LocalPort' => serv_port, 'SSL' => true)
|
||||
assert_kind_of(Rex::Socket::SslTcpServer, serv, "type => ssl")
|
||||
assert_kind_of(Rex::Socket::TcpServer, serv, "type => tcp")
|
||||
assert_kind_of(Rex::IO::StreamServer, serv, "type => stream")
|
||||
s = serv.accept
|
||||
assert_equal("client_data\n", s.get_once(), "s: get_once")
|
||||
assert_equal(3, s.write("Yo\n"), "s: put Yo")
|
||||
assert(s.methods.include?('<<'))
|
||||
assert(s.methods.include?('>>'))
|
||||
assert(s.methods.include?('has_read_data?'))
|
||||
serv.close
|
||||
}
|
||||
|
||||
threads << Thread.new() {
|
||||
sleep(2)
|
||||
assert_nothing_raised {
|
||||
c = Rex::Socket::SslTcp.create(
|
||||
'PeerHost' => '127.0.0.1',
|
||||
'PeerPort' => serv_port
|
||||
)
|
||||
}
|
||||
assert_kind_of(Rex::Socket::Tcp, c, "TCP")
|
||||
assert_kind_of(Rex::Socket::SslTcp, c, "SSL")
|
||||
assert_equal(12, c.write("client_data\n"), "c: write")
|
||||
assert_equal("Yo\n", c.get_once(), "c: get_once")
|
||||
c.close if (c)
|
||||
}
|
||||
|
||||
threads.each { |aThread| aThread.join }
|
||||
end
|
||||
|
||||
end
|
Loading…
Reference in New Issue