Class: Arachni::HTTP::ProxyServer::SSLInterceptor

Inherits:
Connection
  • Object
show all
Includes:
UI::Output, TLS
Defined in:
lib/arachni/http/proxy_server/ssl_interceptor.rb

Constant Summary collapse

CA_CERTIFICATE =
File.dirname( __FILE__ ) + '/ssl-interceptor-cacert.pem'
CA_KEY =
File.dirname( __FILE__ ) + '/ssl-interceptor-cakey.pem'

Constants inherited from Connection

Connection::SKIP_HEADERS

Instance Attribute Summary

Attributes inherited from Connection

#parent, #request

Instance Method Summary collapse

Methods included from UI::Output

#caller_location, #debug?, #debug_level, #debug_level_1?, #debug_level_2?, #debug_level_3?, #debug_level_4?, #debug_off, #debug_on, #disable_only_positives, #error_buffer, #error_log_fd, #error_logfile, #has_error_log?, #included, #log_error, #mute, #muted?, #only_positives, #only_positives?, #print_bad, #print_debug, #print_debug_backtrace, #print_debug_exception, #print_debug_level_1, #print_debug_level_2, #print_debug_level_3, #print_debug_level_4, #print_error, #print_error_backtrace, #print_exception, #print_info, #print_line, #print_ok, #print_status, #print_verbose, #reroute_to_file, #reroute_to_file?, reset_output_options, #set_error_logfile, #unmute, #verbose?, #verbose_off, #verbose_on

Methods inherited from Connection

#cleanup_request_headers, #cleanup_response_headers, #handle_connect, #handle_request, #handle_response, #handle_upgrade, #http_opts, #http_version, #on_flush, #on_read, #sanitize_url, #start_interceptor, #write

Constructor Details

#initialize(options) ⇒ SSLInterceptor

Returns a new instance of SSLInterceptor.


22
23
24
25
26
# File 'lib/arachni/http/proxy_server/ssl_interceptor.rb', line 22

def initialize( options )
    super

    @origin_host = options[:origin_host]
end

Instance Method Details

#on_close(reason = nil) ⇒ Object


33
34
35
36
# File 'lib/arachni/http/proxy_server/ssl_interceptor.rb', line 33

def on_close( reason = nil )
    print_debug_level_3 "Closed because: [#{reason.class}] #{reason}"
    @parent.mark_connection_inactive self
end

#on_connectObject


28
29
30
31
# File 'lib/arachni/http/proxy_server/ssl_interceptor.rb', line 28

def on_connect
    print_debug_level_3 'Connected, starting SSL handshake.'
    start_tls
end

#start_tlsObject


38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
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/arachni/http/proxy_server/ssl_interceptor.rb', line 38

def start_tls
    if @socket.is_a? OpenSSL::SSL::SSLSocket
        @ssl_context = @socket.context
        return
    end

    if @role == :server
        ca     = OpenSSL::X509::Certificate.new( File.read( CA_CERTIFICATE ) )
        ca_key = OpenSSL::PKey::RSA.new( File.read( CA_KEY ) )

        keypair = OpenSSL::PKey::RSA.new( 1024 )

        req            = OpenSSL::X509::Request.new
        req.version    = 0
        req.subject    = OpenSSL::X509::Name.parse(
            "CN=#{@origin_host}/subjectAltName=#{@origin_host}/O=Arachni/OU=Proxy/L=Athens/ST=Attika/C=GR"
        )
        req.public_key = keypair.public_key
        req.sign( keypair, OpenSSL::Digest::SHA1.new )

        cert            = OpenSSL::X509::Certificate.new
        cert.version    = 2
        cert.serial     = rand( 999999 )
        cert.not_before = Time.new
        cert.not_after  = cert.not_before + (60 * 60 * 24 * 365)
        cert.public_key = req.public_key
        cert.subject    = req.subject
        cert.issuer     = ca.subject

        ef = OpenSSL::X509::ExtensionFactory.new
        ef.subject_certificate = cert
        ef.issuer_certificate  = ca

        cert.extensions = [
            ef.create_extension( 'basicConstraints', 'CA:FALSE', true ),
            ef.create_extension( 'extendedKeyUsage', 'serverAuth', false ),
            ef.create_extension( 'subjectKeyIdentifier', 'hash' ),
            ef.create_extension( 'authorityKeyIdentifier', 'keyid:always,issuer:always' ),
            ef.create_extension( 'keyUsage',
                                 'nonRepudiation,digitalSignature,keyEncipherment,dataEncipherment',
                                 true
            )
        ]
        cert.sign( ca_key, OpenSSL::Digest::SHA1.new )

        @ssl_context = OpenSSL::SSL::SSLContext.new
        @ssl_context.cert = cert
        @ssl_context.key  = keypair

        @socket = OpenSSL::SSL::SSLServer.new( @socket, @ssl_context )
    else
        @socket = OpenSSL::SSL::SSLSocket.new( @socket, @ssl_context )
        @socket.sync_close = true

        # We've switched to SSL, a connection needs to be re-established
        # via the SSL handshake.
        @connected         = false
    end

    @socket
end