evil-proxy 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f4c501bef2b64e58b8393c8cc73a6516739f8b87
4
- data.tar.gz: 9f8c54251a54e7f68cb47b04363ea746ed0956e1
3
+ metadata.gz: 53684305896f9e807ca7a800ce16365d1075047b
4
+ data.tar.gz: 9f3436b932cd284a97d572630b8eef0c82f8ccba
5
5
  SHA512:
6
- metadata.gz: dc6113ee6f3043cc8ddd8e70dc4423dc717281c5eb589cbc878531fa2019b280b09d1fbb8c9ae789d7b2c1ce8d93d4ad44f061a7c6ff8b67506838c44dc85b4c
7
- data.tar.gz: c598d95d33cdbaf4ec131697f3b95015f39f5a31dda3fe8043522d912d9ed9bbf0a0ad903fa51e251def4f3f7829facaa4af45aa4bc20f5873028408312cc8e1
6
+ metadata.gz: f4ab48b584aedfb81bdd292a29764fbcd17a2b55f91ad648ef1c07f572ccc5a8552bcea270a088c5766dc806bbf6f1243b6d77e0c34e4e9ed9fcc70503ff15f8
7
+ data.tar.gz: 6f4f16d5c257a680e7e13a6b8090ffa2bc561f324e75e7b29d302ee36f5dcd146ba761333942066042ffdd6af54900b2e34f2e30da7cfe4ead31d7fa9f3852fa
data/.gitignore CHANGED
@@ -10,6 +10,7 @@ coverage
10
10
  doc/
11
11
  lib/bundler/man
12
12
  pkg
13
+ certs
13
14
  rdoc
14
15
  spec/reports
15
16
  test/tmp
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # EvilProxy
2
2
 
3
- A ruby http proxy to do :imp: things.
3
+ A ruby http/https proxy, with SSL MITM support to do :imp: things.
4
4
 
5
5
  ## Installation
6
6
 
@@ -18,6 +18,45 @@ Or install it yourself as:
18
18
 
19
19
  ## Usage
20
20
 
21
+ #### MITMProxyServer
22
+ `MITMProxyServer` is a subclass of `HTTPProxyServer`, so it also has the callback & plugin system, this proxy will embed a mini CA, which generates certificates on the fly, so you may need to import the CA certificate (./certs/CA/cacert.pem) into your browser.
23
+
24
+ ```ruby
25
+ require 'evil-proxy'
26
+
27
+ proxy = EvilProxy::MITMProxyServer.new Port: 8080
28
+ proxy.start
29
+ ```
30
+
31
+ Without import the CA certificate
32
+ ```shell
33
+ $ https_proxy=http://localhost:8080 curl https://github.com
34
+ # =>
35
+ # curl: (60) SSL certificate problem: Invalid certificate chain
36
+ # More details here: http://curl.haxx.se/docs/sslcerts.html
37
+ #
38
+ # curl performs SSL certificate verification by default, using a "bundle"
39
+ # of Certificate Authority (CA) public keys (CA certs). If the default
40
+ # bundle file isn't adequate, you can specify an alternate file
41
+ # using the --cacert option.
42
+ # If this HTTPS server uses a certificate signed by a CA represented in
43
+ # the bundle, the certificate verification probably failed due to a
44
+ # problem with the certificate (it might be expired, or the name might
45
+ # not match the domain name in the URL).
46
+ # If you'd like to turn off curl's verification of the certificate, use
47
+ # the -k (or --insecure) option.
48
+ ```
49
+
50
+ ```shell
51
+ $ https_proxy=http://localhost:8080 curl https://github.com --insecure
52
+ # =>
53
+ # <!DOCTYPE html>
54
+ # <html lang="en" class="">
55
+ # ...
56
+ ```
57
+
58
+ So you can intercept and modify https traffic, ie: requests & responses.
59
+
21
60
  #### Basic usage: hooks
22
61
 
23
62
  ```ruby
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'evil-proxy'
4
+
5
+ logger = WEBrick::Log.new(nil, 5)
6
+
7
+ proxy = EvilProxy::MITMProxyServer.new Port: 8080, Logger: logger
8
+ proxy.start
@@ -8,8 +8,8 @@ Gem::Specification.new do |spec|
8
8
  spec.version = EvilProxy::VERSION
9
9
  spec.authors = ["Theo"]
10
10
  spec.email = ["bbtfrr@gmail.com"]
11
- spec.summary = %q{A ruby http proxy to do EVIL things.}
12
- spec.description = %q{A ruby http proxy to do EVIL things.}
11
+ spec.summary = %q{A ruby http/https proxy to do EVIL things.}
12
+ spec.description = %q{A ruby http/https proxy, with SSL MITM support.}
13
13
  spec.homepage = "https://github.com/bbtfr/evil-proxy"
14
14
  spec.license = "MIT"
15
15
 
@@ -20,4 +20,5 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_development_dependency "bundler", "~> 1.6"
22
22
  spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "pry-byebug"
23
24
  end
@@ -1,5 +1,6 @@
1
1
  require "evil-proxy/version"
2
2
  require "evil-proxy/httpproxy"
3
+ require "evil-proxy/mitmproxy"
3
4
  require "evil-proxy/httprequest"
4
5
 
5
6
  module EvilProxy
@@ -0,0 +1,54 @@
1
+ require 'webrick'
2
+ require 'webrick/https'
3
+ require 'webrick/httpproxy'
4
+ require 'openssl'
5
+
6
+ require 'pry-byebug'
7
+
8
+ class EvilProxy::AgentProxyServer < EvilProxy::HTTPProxyServer
9
+
10
+ def initialize_callbacks config
11
+ @mitm_server = config[:MITMProxyServer]
12
+ end
13
+
14
+ def fire key, *args
15
+ @mitm_server.fire key, *args, self
16
+ end
17
+
18
+ def perform_proxy_request(req, res)
19
+ uri = req.request_uri
20
+ path = uri.path.dup
21
+ path << "?" << uri.query if uri.query
22
+ header = Hash.new
23
+ choose_header(req, header)
24
+ response = nil
25
+
26
+ http = Net::HTTP.new(uri.host, uri.port)
27
+ http.use_ssl = true
28
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
29
+ http.start do
30
+ if @config[:ProxyTimeout]
31
+ ################################## these issues are
32
+ http.open_timeout = 30 # secs # necessary (maybe because
33
+ http.read_timeout = 60 # secs # Ruby's bug, but why?)
34
+ ##################################
35
+ end
36
+
37
+ response = yield(http, path, header)
38
+ end
39
+
40
+ # Persistent connection requirements are mysterious for me.
41
+ # So I will close the connection in every response.
42
+ res['proxy-connection'] = "close"
43
+ res['connection'] = "close"
44
+
45
+ # Convert Net::HTTP::HTTPResponse to WEBrick::HTTPResponse
46
+ res.status = response.code.to_i
47
+ choose_header(response, res)
48
+ set_cookie(response, res)
49
+ res.body = response.body
50
+ end
51
+
52
+ alias_method :service, :proxy_service
53
+
54
+ end
@@ -2,12 +2,14 @@ require 'webrick'
2
2
  require 'webrick/httpproxy'
3
3
 
4
4
  class EvilProxy::HTTPProxyServer < WEBrick::HTTPProxyServer
5
+ attr_reader :callbacks
6
+
5
7
  VALID_CALBACKS = Array.new
6
8
  DEFAULT_CALLBACKS = Hash.new
7
9
 
8
- def initialize *args
9
- initialize_callbacks
10
- fire :when_initialize, *args
10
+ def initialize config = {}, default = WEBrick::Config::HTTP
11
+ initialize_callbacks config
12
+ fire :when_initialize, config, default
11
13
  super
12
14
  end
13
15
 
@@ -27,7 +29,7 @@ class EvilProxy::HTTPProxyServer < WEBrick::HTTPProxyServer
27
29
  end
28
30
  end
29
31
 
30
- def proxy_service req, res
32
+ def service req, res
31
33
  fire :before_request, req
32
34
  super
33
35
  fire :before_response, req, res
@@ -64,7 +66,7 @@ class EvilProxy::HTTPProxyServer < WEBrick::HTTPProxyServer
64
66
  end
65
67
 
66
68
  private
67
- def initialize_callbacks
69
+ def initialize_callbacks config
68
70
  @callbacks = Hash.new
69
71
  DEFAULT_CALLBACKS.each do |key, callbacks|
70
72
  @callbacks[key] = callbacks.clone
@@ -1,11 +1,5 @@
1
- WEBrick::HTTPRequest.class_eval do
2
- alias_method :original_body, :body
3
- def body
4
- @evil_body || original_body
5
- end
6
-
7
- def body= body
8
- @evil_body = body
9
- end
1
+ require 'webrick/httprequest'
10
2
 
3
+ WEBrick::HTTPRequest.class_eval do
4
+ attr_writer :body, :unparsed_uri
11
5
  end
@@ -0,0 +1,116 @@
1
+ require 'evil-proxy/httpproxy'
2
+ require 'evil-proxy/agentproxy'
3
+ require 'evil-proxy/quickcert'
4
+
5
+ class EvilProxy::MITMProxyServer < EvilProxy::HTTPProxyServer
6
+
7
+ def initialize config
8
+ super
9
+ @mitm_servers = {}
10
+ @mitm_port = 4433
11
+ end
12
+
13
+ def ca
14
+ return @ca if @ca
15
+ logger.info "Create CA"
16
+
17
+ ca_config = {}
18
+ ca_config[:hostname] = 'ca'
19
+ ca_config[:domainname] = 'mitm.proxy'
20
+ ca_config[:password] = 'password'
21
+ ca_config[:CA_dir] ||= File.join(Dir.pwd, "certs/CA")
22
+
23
+ ca_config[:keypair_file] ||= File.join ca_config[:CA_dir], "private/cakeypair.pem"
24
+ ca_config[:cert_file] ||= File.join ca_config[:CA_dir], "cacert.pem"
25
+ ca_config[:serial_file] ||= File.join ca_config[:CA_dir], "serial"
26
+ ca_config[:new_certs_dir] ||= File.join ca_config[:CA_dir], "newcerts"
27
+ ca_config[:new_keypair_dir] ||= File.join ca_config[:CA_dir], "private/keypair_backup"
28
+ ca_config[:crl_dir] ||= File.join ca_config[:CA_dir], "crl"
29
+
30
+ ca_config[:ca_cert_days] ||= 5 * 365 # five years
31
+ ca_config[:ca_rsa_key_length] ||= 2048
32
+
33
+ ca_config[:cert_days] ||= 365 # one year
34
+ ca_config[:cert_key_length_min] ||= 1024
35
+ ca_config[:cert_key_length_max] ||= 2048
36
+
37
+ ca_config[:crl_file] ||= File.join ca_config[:crl_dir], "#{ca_config[:hostname]}.crl"
38
+ ca_config[:crl_pem_file] ||= File.join ca_config[:crl_dir], "#{ca_config[:hostname]}.pem"
39
+ ca_config[:crl_days] ||= 14
40
+
41
+ if ca_config[:name].nil?
42
+ ca_config[:name] = [
43
+ ['C', 'US', OpenSSL::ASN1::PRINTABLESTRING],
44
+ ['O', ca_config[:domainname], OpenSSL::ASN1::UTF8STRING],
45
+ ['OU', ca_config[:hostname], OpenSSL::ASN1::UTF8STRING],
46
+ ]
47
+ end
48
+
49
+ @ca = QuickCert.new ca_config
50
+ end
51
+
52
+ def create_self_signed_cert host
53
+ cn = [["C", "US"], ["O", host], ["CN", host]]
54
+ comment = "Generated by Ruby/OpenSSL/MITMProxyServer"
55
+ name = OpenSSL::X509::Name.new(cn)
56
+ hostname = name.to_s.scan(/CN=([\w.]+)/)[0][0]
57
+
58
+ logger.info "Create cert for #{hostname}"
59
+ cert_config = { type: 'server', hostname: hostname }
60
+ cert_file, cert, key = ca.create_cert(cert_config)
61
+
62
+ return cert, key
63
+ end
64
+
65
+ def retry_start_agent_server config
66
+ mitm_server = nil
67
+ 10.times do
68
+ begin
69
+ # XXX: ask system for an unused port
70
+ config = config.merge(Port: @mitm_port)
71
+ mitm_server = EvilProxy::AgentProxyServer.new config
72
+ rescue Errno::EADDRINUSE
73
+ ensure
74
+ @mitm_port += 1
75
+ return mitm_server if mitm_server
76
+ end
77
+ end
78
+ raise RuntimeError, "No avaliable port found, stop retrying"
79
+ end
80
+
81
+ def start_mitm_server unparsed_uri, host, port
82
+ if @mitm_servers[unparsed_uri]
83
+ return @mitm_servers[unparsed_uri].config[:Port]
84
+ else
85
+ cert, key = create_self_signed_cert host
86
+ agent_config = self.config.merge(
87
+ MITMProxyServer: self,
88
+ SSLEnable: true,
89
+ SSLVerifyClient: OpenSSL::SSL::VERIFY_NONE,
90
+ SSLCertificate: cert,
91
+ SSLPrivateKey: key,
92
+ )
93
+ mitm_server = retry_start_agent_server agent_config
94
+
95
+ @mitm_servers[unparsed_uri] = mitm_server
96
+
97
+ Thread.new do mitm_server.start end
98
+ return mitm_server.config[:Port]
99
+ end
100
+ end
101
+
102
+ def do_MITM req, res
103
+ unparsed_uri = req.unparsed_uri
104
+ host, port = unparsed_uri.split(":")
105
+ port ||= 443
106
+
107
+ mitm_port = start_mitm_server unparsed_uri, host, port
108
+ req.unparsed_uri = "127.0.0.1:#{mitm_port}"
109
+ end
110
+
111
+ def do_CONNECT req, res
112
+ do_MITM req, res
113
+ super
114
+ end
115
+
116
+ end
@@ -0,0 +1,349 @@
1
+ require 'openssl'
2
+ # QuickCert from http://segment7.net/projects/ruby/QuickCert/
3
+ # QuickCert allows you to quickly and easily create SSL
4
+ # certificates. It uses a simple configuration file to generate
5
+ # self-signed client and server certificates.
6
+ #
7
+ # QuickCert is a compilation of NAKAMURA Hiroshi's post to
8
+ # ruby-talk number 89917:
9
+ #
10
+ # http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/89917
11
+ #
12
+ # the example scripts referenced in the above post, and
13
+ # gen_csr.rb from Ruby's OpenSSL examples.
14
+ #
15
+ # A simple QuickCert configuration file looks like:
16
+ #
17
+ # full_hostname = `hostname`.strip
18
+ # domainname = full_hostname.split('.')[1..-1].join('.')
19
+ # hostname = full_hostname.split('.')[0]
20
+ #
21
+ # CA[:hostname] = hostname
22
+ # CA[:domainname] = domainname
23
+ # CA[:CA_dir] = File.join Dir.pwd, "CA"
24
+ # CA[:password] = '1234'
25
+ #
26
+ # CERTS << {
27
+ # :type => 'server',
28
+ # :hostname => 'uriel',
29
+ # :password => '5678',
30
+ # }
31
+ #
32
+ # CERTS << {
33
+ # :type => 'client',
34
+ # :user => 'drbrain',
35
+ # :email => 'drbrain@segment7.net',
36
+ # }
37
+ #
38
+ # This configuration will create a Certificate Authority in a
39
+ # 'CA' directory in the current directory, a server certificate
40
+ # with password '5678' for the server 'uriel' in a directory
41
+ # named 'uriel', and a client certificate for drbrain in the
42
+ # directory 'drbrain' with no password.
43
+ #
44
+ # There are additional SSL knobs you can tweak in the
45
+ # qc_defaults.rb file.
46
+ #
47
+ # To generate the certificates, simply create a qc_config file
48
+ # where you want the certificate directories to be created, then
49
+ # run QuickCert.
50
+ #
51
+ # QuickCert's homepage is:
52
+ # http://segment7.net/projects/ruby/QuickCert/
53
+
54
+ class QuickCert
55
+
56
+ ##
57
+ # QuickCert Version
58
+
59
+ VERSION = "1.0.2"
60
+ CERT_DIR = File.join(Dir.pwd, "certs")
61
+ Dir.mkdir(CERT_DIR) unless File.exists?(CERT_DIR)
62
+
63
+ ##
64
+ # Creates a new QuickCert instance using the Certificate
65
+ # Authority described in +ca_config+. If there is no CA at
66
+ # ca_config[:CA_dir], then QuickCert will initialize a new one.
67
+
68
+ def initialize(ca_config)
69
+ @ca_config = ca_config
70
+
71
+ create_ca
72
+ end
73
+
74
+ ##
75
+ # Creates a new certificate from +cert_config+ that is signed
76
+ # by the CA.
77
+
78
+ def create_cert(cert_config)
79
+ dest = cert_config[:hostname] || cert_config[:user]
80
+ key_file = "#{CERT_DIR}/#{dest}/#{dest}_keypair.pem"
81
+ cert_file = "#{CERT_DIR}/#{dest}/cert_#{dest}.pem"
82
+ if File.exists?(cert_file) && File.exists?(key_file)
83
+ key = OpenSSL::PKey::RSA.new(File.read(key_file))
84
+ cert = OpenSSL::X509::Certificate.new(File.read(cert_file))
85
+ else
86
+ cert_keypair, key = create_key(cert_config)
87
+ cert_csr = create_csr(cert_config, cert_keypair)
88
+ cert_file, cert = sign_cert(cert_config, cert_keypair, cert_csr)
89
+ end
90
+ return cert_file, cert, key
91
+ end
92
+
93
+ ##
94
+ # Creates a new Certificate Authority from @ca_config if it
95
+ # does not already exist at ca_config[:CA_dir].
96
+
97
+ def create_ca
98
+ return if File.exists? @ca_config[:CA_dir]
99
+
100
+ Dir.mkdir @ca_config[:CA_dir]
101
+
102
+ Dir.mkdir File.join(@ca_config[:CA_dir], 'private'), 0700
103
+ Dir.mkdir File.join(@ca_config[:CA_dir], 'newcerts')
104
+ Dir.mkdir File.join(@ca_config[:CA_dir], 'crl')
105
+
106
+ File.open @ca_config[:serial_file], 'w' do |f| f << "#{Time.now.to_i}" end
107
+
108
+ puts "Generating CA keypair" if $DEBUG
109
+ keypair = OpenSSL::PKey::RSA.new @ca_config[:ca_rsa_key_length]
110
+
111
+ cert = OpenSSL::X509::Certificate.new
112
+ name = @ca_config[:name].dup << ['CN', 'CA']
113
+ cert.subject = cert.issuer = OpenSSL::X509::Name.new(name)
114
+ cert.not_before = Time.now
115
+ cert.not_after = Time.now + @ca_config[:ca_cert_days] * 24 * 60 * 60
116
+ cert.public_key = keypair.public_key
117
+ cert.serial = 0x0
118
+ cert.version = 2 # X509v3
119
+
120
+ ef = OpenSSL::X509::ExtensionFactory.new
121
+ ef.subject_certificate = cert
122
+ ef.issuer_certificate = cert
123
+ cert.extensions = [
124
+ ef.create_extension("basicConstraints","CA:TRUE", true),
125
+ ef.create_extension("nsComment","Ruby/OpenSSL Generated Certificate"),
126
+ ef.create_extension("subjectKeyIdentifier", "hash"),
127
+ ef.create_extension("keyUsage", "cRLSign,keyCertSign", true),
128
+ ]
129
+ cert.add_extension ef.create_extension("authorityKeyIdentifier",
130
+ "keyid:always,issuer:always")
131
+ cert.sign(keypair, OpenSSL::Digest::SHA1.new)
132
+
133
+ keypair_export = keypair.export(OpenSSL::Cipher::DES.new(:EDE3, :CBC), @ca_config[:password])
134
+
135
+ puts "Writing keypair to #{@ca_config[:keypair_file]}" if $DEBUG
136
+ File.open @ca_config[:keypair_file], "w", 0400 do |fp|
137
+ fp << keypair_export
138
+ end
139
+
140
+ puts "Writing cert to #{@ca_config[:cert_file]}" if $DEBUG
141
+ File.open @ca_config[:cert_file], "w", 0644 do |f|
142
+ f << cert.to_pem
143
+ end
144
+
145
+ puts "Done generating certificate for #{cert.subject}" if $DEBUG
146
+ end
147
+
148
+ ##
149
+ # Creates a new RSA key from +cert_config+.
150
+
151
+ def create_key(cert_config)
152
+ dest = cert_config[:hostname] || cert_config[:user]
153
+ keypair_file = "#{CERT_DIR}/#{dest}/#{dest}_keypair.pem"
154
+ if File.exists?(keypair_file)
155
+ keypair = OpenSSL::PKey::RSA.new(File.read(keypair_file),
156
+ cert_config[:password])
157
+ return keypair_file, keypair
158
+ end
159
+ Dir.mkdir("#{CERT_DIR}/#{dest}", 0700) unless File.exists?("#{CERT_DIR}/#{dest}")
160
+
161
+ puts "Generating RSA keypair" if $DEBUG
162
+ keypair = OpenSSL::PKey::RSA.new 1024
163
+
164
+ if cert_config[:password].nil? then
165
+ File.open keypair_file, "w", 0400 do |f|
166
+ f << keypair.to_pem
167
+ end
168
+ else
169
+ keypair_export = keypair.export(OpenSSL::Cipher::DES.new(:EDE3, :CBC),
170
+ cert_config[:password])
171
+
172
+ puts "Writing keypair to #{keypair_file}" if $DEBUG
173
+ File.open keypair_file, "w", 0400 do |f|
174
+ f << keypair_export
175
+ end
176
+ end
177
+
178
+ return keypair_file, keypair
179
+ end
180
+
181
+ ##
182
+ # Creates a new Certificate Signing Request for the keypair in
183
+ # +keypair_file+, generating and saving new keypair if nil.
184
+
185
+ def create_csr(cert_config, keypair_file = nil)
186
+ keypair = nil
187
+ dest = cert_config[:hostname] || cert_config[:user]
188
+ csr_file = "#{CERT_DIR}/#{dest}/csr_#{dest}.pem"
189
+
190
+ name = @ca_config[:name].dup
191
+ case cert_config[:type]
192
+ when 'server' then
193
+ name << ['OU', 'CA']
194
+ name << ['CN', cert_config[:hostname]]
195
+ when 'client' then
196
+ name << ['CN', cert_config[:user]]
197
+ name << ['emailAddress', cert_config[:email]]
198
+ end
199
+ name = OpenSSL::X509::Name.new name
200
+
201
+ if File.exists? keypair_file then
202
+ keypair = OpenSSL::PKey::RSA.new(File.read(keypair_file),
203
+ cert_config[:password])
204
+ else
205
+ keypair = create_key cert_config
206
+ end
207
+
208
+ puts "Generating CSR for #{name}" if $DEBUG
209
+
210
+ req = OpenSSL::X509::Request.new
211
+ req.version = 0
212
+ req.subject = name
213
+ req.public_key = keypair.public_key
214
+ req.sign keypair, OpenSSL::Digest::MD5.new
215
+
216
+ puts "Writing CSR to #{csr_file}" if $DEBUG
217
+ File.open csr_file, "w" do |f|
218
+ f << req.to_pem
219
+ end
220
+
221
+ return csr_file
222
+ end
223
+
224
+ ##
225
+ # Signs the certificate described in +cert_config+ and
226
+ # +csr_file+, saving it to +cert_file+.
227
+
228
+ def sign_cert(cert_config, cert_file, csr_file)
229
+ csr = OpenSSL::X509::Request.new File.read(csr_file)
230
+
231
+ raise "CSR sign verification failed." unless csr.verify csr.public_key
232
+
233
+ if csr.public_key.n.num_bits < @ca_config[:cert_key_length_min] then
234
+ raise "Key length too short"
235
+ end
236
+
237
+ if csr.public_key.n.num_bits > @ca_config[:cert_key_length_max] then
238
+ raise "Key length too long"
239
+ end
240
+
241
+ if csr.subject.to_a[0, @ca_config[:name].size] != @ca_config[:name] then
242
+ raise "DN does not match"
243
+ end
244
+
245
+ # Only checks signature here. You must verify CSR according to your
246
+ # CP/CPS.
247
+
248
+ # CA setup
249
+
250
+ puts "Reading CA cert from #{@ca_config[:cert_file]}" if $DEBUG
251
+ ca = OpenSSL::X509::Certificate.new File.read(@ca_config[:cert_file])
252
+
253
+ puts "Reading CA keypair from #{@ca_config[:keypair_file]}" if $DEBUG
254
+ ca_keypair = OpenSSL::PKey::RSA.new File.read(@ca_config[:keypair_file]),
255
+ @ca_config[:password]
256
+
257
+ serial = File.read(@ca_config[:serial_file]).chomp.hex
258
+ File.open @ca_config[:serial_file], "w" do |f|
259
+ f << "%04X" % (serial + 1)
260
+ end
261
+
262
+ puts "Generating cert" if $DEBUG
263
+
264
+ cert = OpenSSL::X509::Certificate.new
265
+ from = Time.now
266
+ cert.subject = csr.subject
267
+ cert.issuer = ca.subject
268
+ cert.not_before = from
269
+ cert.not_after = from + @ca_config[:cert_days] * 24 * 60 * 60
270
+ cert.public_key = csr.public_key
271
+ cert.serial = serial
272
+ cert.version = 2 # X509v3
273
+
274
+ basic_constraint = nil
275
+ key_usage = []
276
+ ext_key_usage = []
277
+
278
+ case cert_config[:type]
279
+ when "ca" then
280
+ basic_constraint = "CA:TRUE"
281
+ key_usage << "cRLSign" << "keyCertSign"
282
+ when "terminalsubca" then
283
+ basic_constraint = "CA:TRUE,pathlen:0"
284
+ key_usage << "cRLSign" << "keyCertSign"
285
+ when "server" then
286
+ basic_constraint = "CA:FALSE"
287
+ key_usage << "digitalSignature" << "keyEncipherment"
288
+ ext_key_usage << "serverAuth"
289
+ when "ocsp" then
290
+ basic_constraint = "CA:FALSE"
291
+ key_usage << "nonRepudiation" << "digitalSignature"
292
+ ext_key_usage << "serverAuth" << "OCSPSigning"
293
+ when "client" then
294
+ basic_constraint = "CA:FALSE"
295
+ key_usage << "nonRepudiation" << "digitalSignature" << "keyEncipherment"
296
+ ext_key_usage << "clientAuth" << "emailProtection"
297
+ else
298
+ raise "unknonw cert type \"#{cert_config[:type]}\""
299
+ end
300
+
301
+ ef = OpenSSL::X509::ExtensionFactory.new
302
+ ef.subject_certificate = cert
303
+ ef.issuer_certificate = ca
304
+ ex = []
305
+ ex << ef.create_extension("basicConstraints", basic_constraint, true)
306
+ ex << ef.create_extension("nsComment",
307
+ "Ruby/OpenSSL Generated Certificate")
308
+ ex << ef.create_extension("subjectKeyIdentifier", "hash")
309
+ #ex << ef.create_extension("nsCertType", "client,email")
310
+ unless key_usage.empty? then
311
+ ex << ef.create_extension("keyUsage", key_usage.join(","))
312
+ end
313
+ #ex << ef.create_extension("authorityKeyIdentifier",
314
+ # "keyid:always,issuer:always")
315
+ #ex << ef.create_extension("authorityKeyIdentifier", "keyid:always")
316
+ unless ext_key_usage.empty? then
317
+ ex << ef.create_extension("extendedKeyUsage", ext_key_usage.join(","))
318
+ end
319
+
320
+ if @ca_config[:cdp_location] then
321
+ ex << ef.create_extension("crlDistributionPoints",
322
+ @ca_config[:cdp_location])
323
+ end
324
+
325
+ if @ca_config[:ocsp_location] then
326
+ ex << ef.create_extension("authorityInfoAccess",
327
+ "OCSP;" << @ca_config[:ocsp_location])
328
+ end
329
+ cert.extensions = ex
330
+ cert.sign(ca_keypair, OpenSSL::Digest::SHA1.new)
331
+
332
+ backup_cert_file = @ca_config[:new_certs_dir] + "/cert_#{cert.serial}.pem"
333
+ puts "Writing backup cert to #{backup_cert_file}" if $DEBUG
334
+ File.open backup_cert_file, "w", 0644 do |f|
335
+ f << cert.to_pem
336
+ end
337
+
338
+ # Write cert
339
+ dest = cert_config[:hostname] || cert_config[:user]
340
+ cert_file = "#{CERT_DIR}/#{dest}/cert_#{dest}.pem"
341
+ puts "Writing cert to #{cert_file}" if $DEBUG
342
+ File.open cert_file, "w", 0644 do |f|
343
+ f << cert.to_pem
344
+ end
345
+
346
+ return cert_file, cert
347
+ end
348
+
349
+ end # class QuickCert
@@ -1,3 +1,3 @@
1
1
  module EvilProxy
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: evil-proxy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Theo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-05 00:00:00.000000000 Z
11
+ date: 2015-11-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -38,10 +38,25 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
- description: A ruby http proxy to do EVIL things.
41
+ - !ruby/object:Gem::Dependency
42
+ name: pry-byebug
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: A ruby http/https proxy, with SSL MITM support.
42
56
  email:
43
57
  - bbtfrr@gmail.com
44
- executables: []
58
+ executables:
59
+ - evil-proxy
45
60
  extensions: []
46
61
  extra_rdoc_files: []
47
62
  files:
@@ -50,11 +65,15 @@ files:
50
65
  - LICENSE.txt
51
66
  - README.md
52
67
  - Rakefile
68
+ - bin/evil-proxy
53
69
  - evil-proxy.gemspec
54
70
  - lib/evil-proxy.rb
71
+ - lib/evil-proxy/agentproxy.rb
55
72
  - lib/evil-proxy/async.rb
56
73
  - lib/evil-proxy/httpproxy.rb
57
74
  - lib/evil-proxy/httprequest.rb
75
+ - lib/evil-proxy/mitmproxy.rb
76
+ - lib/evil-proxy/quickcert.rb
58
77
  - lib/evil-proxy/selenium.rb
59
78
  - lib/evil-proxy/store.rb
60
79
  - lib/evil-proxy/version.rb
@@ -81,5 +100,5 @@ rubyforge_project:
81
100
  rubygems_version: 2.4.6
82
101
  signing_key:
83
102
  specification_version: 4
84
- summary: A ruby http proxy to do EVIL things.
103
+ summary: A ruby http/https proxy to do EVIL things.
85
104
  test_files: []