Mirror of metasploit
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ssl_tcp_server.rb 5.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. # -*- coding: binary -*-
  2. require 'rex/socket'
  3. require 'rex/socket/tcp_server'
  4. require 'rex/io/stream_server'
  5. require 'rex/parser/x509_certificate'
  6. ###
  7. #
  8. # This class provides methods for interacting with an SSL wrapped TCP server. It
  9. # implements the StreamServer IO interface.
  10. #
  11. ###
  12. module Rex::Socket::SslTcpServer
  13. @@loaded_openssl = false
  14. begin
  15. require 'openssl'
  16. @@loaded_openssl = true
  17. require 'openssl/nonblock'
  18. rescue ::Exception
  19. end
  20. include Rex::Socket::TcpServer
  21. ##
  22. #
  23. # Factory
  24. #
  25. ##
  26. def self.create(hash = {})
  27. hash['Proto'] = 'tcp'
  28. hash['Server'] = true
  29. hash['SSL'] = true
  30. self.create_param(Rex::Socket::Parameters.from_hash(hash))
  31. end
  32. #
  33. # Wrapper around the base class' creation method that automatically sets
  34. # the parameter's protocol to TCP and sets the server flag to true.
  35. #
  36. def self.create_param(param)
  37. param.proto = 'tcp'
  38. param.server = true
  39. param.ssl = true
  40. Rex::Socket.create_param(param)
  41. end
  42. def initsock(params = nil)
  43. raise RuntimeError, 'No OpenSSL support' unless @@loaded_openssl
  44. if params && params.sslctx && params.sslctx.kind_of?(OpenSSL::SSL::SSLContext)
  45. self.sslctx = params.sslctx
  46. else
  47. self.sslctx = makessl(params)
  48. end
  49. super
  50. end
  51. # (see TcpServer#accept)
  52. def accept(opts = {})
  53. sock = super()
  54. return if not sock
  55. begin
  56. ssl = OpenSSL::SSL::SSLSocket.new(sock, self.sslctx)
  57. if not allow_nonblock?(ssl)
  58. ssl.accept
  59. else
  60. begin
  61. ssl.accept_nonblock
  62. # Ruby 1.8.7 and 1.9.0/1.9.1 uses a standard Errno
  63. rescue ::Errno::EAGAIN, ::Errno::EWOULDBLOCK
  64. IO::select(nil, nil, nil, 0.10)
  65. retry
  66. # Ruby 1.9.2+ uses IO::WaitReadable/IO::WaitWritable
  67. rescue ::Exception => e
  68. if ::IO.const_defined?('WaitReadable') and e.kind_of?(::IO::WaitReadable)
  69. IO::select( [ ssl ], nil, nil, 0.10 )
  70. retry
  71. end
  72. if ::IO.const_defined?('WaitWritable') and e.kind_of?(::IO::WaitWritable)
  73. IO::select( nil, [ ssl ], nil, 0.10 )
  74. retry
  75. end
  76. raise e
  77. end
  78. end
  79. sock.extend(Rex::Socket::SslTcp)
  80. sock.sslsock = ssl
  81. sock.sslctx = self.sslctx
  82. return sock
  83. rescue ::OpenSSL::SSL::SSLError
  84. sock.close
  85. nil
  86. end
  87. end
  88. #
  89. # Parse a certificate in unified PEM format that contains a private key and
  90. # one or more certificates. The first certificate is the primary, while any
  91. # additional certificates are treated as intermediary certificates. This emulates
  92. # the behavior of web servers like nginx.
  93. #
  94. # @param [String] ssl_cert
  95. # @return [String, String, Array]
  96. def self.ssl_parse_pem(ssl_cert)
  97. Rex::Parser::X509Certificate.parse_pem(ssl_cert)
  98. end
  99. #
  100. # Shim for the ssl_parse_pem module method
  101. #
  102. def ssl_parse_pem(ssl_cert)
  103. Rex::Socket::SslTcpServer.ssl_parse_pem(ssl_cert)
  104. end
  105. #
  106. # Generate a realistic-looking but obstensibly fake SSL
  107. # certificate. This matches a typical "snakeoil" cert.
  108. #
  109. # @return [String, String, Array]
  110. def self.ssl_generate_certificate
  111. yr = 24*3600*365
  112. vf = Time.at(Time.now.to_i - rand(yr * 3) - yr)
  113. vt = Time.at(vf.to_i + (10 * yr))
  114. cn = Rex::Text.rand_text_alpha_lower(rand(8)+2)
  115. key = OpenSSL::PKey::RSA.new(2048){ }
  116. cert = OpenSSL::X509::Certificate.new
  117. cert.version = 2
  118. cert.serial = (rand(0xFFFFFFFF) << 32) + rand(0xFFFFFFFF)
  119. cert.subject = OpenSSL::X509::Name.new([["CN", cn]])
  120. cert.issuer = OpenSSL::X509::Name.new([["CN", cn]])
  121. cert.not_before = vf
  122. cert.not_after = vt
  123. cert.public_key = key.public_key
  124. ef = OpenSSL::X509::ExtensionFactory.new(nil,cert)
  125. cert.extensions = [
  126. ef.create_extension("basicConstraints","CA:FALSE")
  127. ]
  128. ef.issuer_certificate = cert
  129. cert.sign(key, OpenSSL::Digest::SHA256.new)
  130. [key, cert, nil]
  131. end
  132. #
  133. # Shim for the ssl_generate_certificate module method
  134. #
  135. def ssl_generate_certificate
  136. Rex::Socket::SslTcpServer.ssl_generate_certificate
  137. end
  138. #
  139. # Create a new ssl context. If +ssl_cert+ is not given, generates a new
  140. # key and a leaf certificate with random values.
  141. #
  142. # @param [Rex::Socket::Parameters] params
  143. # @return [::OpenSSL::SSL::SSLContext]
  144. def makessl(params)
  145. if params.ssl_cert
  146. key, cert, chain = ssl_parse_pem(params.ssl_cert)
  147. else
  148. key, cert, chain = ssl_generate_certificate
  149. end
  150. ctx = OpenSSL::SSL::SSLContext.new()
  151. ctx.key = key
  152. ctx.cert = cert
  153. ctx.extra_chain_cert = chain
  154. ctx.options = 0
  155. if params.ssl_cipher
  156. ctx.ciphers = params.ssl_cipher
  157. end
  158. # Older versions of OpenSSL do not export the OP_NO_COMPRESSION symbol
  159. if defined?(OpenSSL::SSL::OP_NO_COMPRESSION)
  160. # enable/disable the SSL/TLS-level compression
  161. if params.ssl_compression
  162. ctx.options &= ~OpenSSL::SSL::OP_NO_COMPRESSION
  163. else
  164. ctx.options |= OpenSSL::SSL::OP_NO_COMPRESSION
  165. end
  166. end
  167. ctx.session_id_context = Rex::Text.rand_text(16)
  168. return ctx
  169. end
  170. #
  171. # This flag determines whether to use the non-blocking openssl
  172. # API calls when they are available. This is still buggy on
  173. # Linux/Mac OS X, but is required on Windows
  174. #
  175. def allow_nonblock?(sock=self.sock)
  176. avail = sock.respond_to?(:accept_nonblock)
  177. if avail and Rex::Compat.is_windows
  178. return true
  179. end
  180. false
  181. end
  182. attr_accessor :sslctx
  183. end