tlspretense 0.6.2 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/.travis.yml +5 -0
- data/README.rdoc +25 -16
- data/Rakefile +1 -4
- data/doc/general_setup.rdoc +22 -1
- data/doc/macosx_setup.rdoc +86 -0
- data/lib/packetthief.rb +8 -1
- data/lib/packetthief/handlers/abstract_ssl_handler.rb +1 -2
- data/lib/packetthief/handlers/ssl_server.rb +3 -4
- data/lib/packetthief/handlers/ssl_smart_proxy.rb +3 -3
- data/lib/packetthief/handlers/ssl_transparent_proxy.rb +1 -1
- data/lib/packetthief/handlers/transparent_proxy.rb +1 -2
- data/lib/packetthief/logging.rb +32 -24
- data/lib/tlspretense/app.rb +5 -2
- data/lib/tlspretense/cert_maker.rb +5 -0
- data/lib/tlspretense/cert_maker/certificate_factory.rb +11 -1
- data/lib/tlspretense/cert_maker/certificate_suite_generator.rb +21 -3
- data/lib/tlspretense/cert_maker/subject_alt_name_factory.rb +115 -0
- data/lib/tlspretense/ext_compat/openssl_pkey_read.rb +38 -0
- data/lib/tlspretense/skel/config.yml +194 -17
- data/lib/tlspretense/test_harness/input_handler.rb +6 -2
- data/lib/tlspretense/test_harness/runner.rb +9 -3
- data/lib/tlspretense/test_harness/ssl_test_case.rb +2 -9
- data/lib/tlspretense/test_harness/ssl_test_report.rb +3 -0
- data/lib/tlspretense/test_harness/test_listener.rb +2 -2
- data/lib/tlspretense/test_harness/test_manager.rb +1 -2
- data/lib/tlspretense/version.rb +1 -1
- data/packetthief_examples/ssl_client_simple.rb +7 -0
- data/spec/packetthief/impl/ipfw_spec.rb +4 -2
- data/spec/packetthief/impl/netfilter_spec.rb +4 -2
- data/spec/packetthief/impl/pf_divert_spec.rb +4 -2
- data/spec/packetthief/logging_spec.rb +24 -26
- data/spec/spec_helper.rb +7 -8
- data/spec/tlspretense/cert_maker/subject_alt_name_factory_spec.rb +75 -0
- data/spec/tlspretense/ext_compat/openssl_pkey_read_spec.rb +126 -0
- data/spec/tlspretense/test_harness/runner_spec.rb +3 -5
- data/tlspretense.gemspec +2 -2
- metadata +41 -48
- data/Gemfile.lock +0 -41
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 4ed245d56d277c418ad64f001cfd058c143558fd
|
4
|
+
data.tar.gz: d32fe446d812f2a499df03ee9c955696486a88c2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 282430a23df7618eac0eb73b1078e03738268cec66a9b5031d42ce7bed18f0b814edfc3426a6bfd1f7527347b6e4fcc35aabcf0b9040644d75ac7a93f531fae8
|
7
|
+
data.tar.gz: 709560af229dcc7f6c122321af8d51053a10e31a78a100bb850f2a23758459f6c32dec94ed4bbbdc8a9f41f2b8c3eeab88c2c4c910b8ed9eeab3a7ab76c3710f
|
data/.gitignore
CHANGED
data/README.rdoc
CHANGED
@@ -126,11 +126,12 @@ Or just certain tests (in the order specified):
|
|
126
126
|
though.
|
127
127
|
|
128
128
|
* It currently uses the goodca to re-sign certificates from hostnames that do
|
129
|
-
not match the configured test hostname
|
129
|
+
not match the configured test hostname, instead of silently forwarding the
|
130
|
+
connection.
|
130
131
|
|
131
|
-
* The existing PFDivert rule implementation does not work on Mac OS X 10.7
|
132
|
-
|
133
|
-
|
132
|
+
* The existing PFDivert rule implementation does not work on Mac OS X 10.7 or
|
133
|
+
10.8 (use PFRdr instead). OpenBSD newer than 4.3 and FreeBSD 9 can make use
|
134
|
+
of the newer PF syntax and functionality though.
|
134
135
|
|
135
136
|
== TODO
|
136
137
|
|
@@ -140,25 +141,33 @@ Or just certain tests (in the order specified):
|
|
140
141
|
until the pre-flight finishes. (the SSLClient within SSLTransparentProxy
|
141
142
|
probably also should do this until the client connects)
|
142
143
|
|
143
|
-
*
|
144
|
-
|
145
|
-
or Ruby's OpenSSL.
|
146
|
-
|
147
|
-
* Add wildcard tests
|
144
|
+
* Add wildcard tests (need a hostname that has
|
145
|
+
domain.domain.domain.publicsuffix for all tests)
|
148
146
|
* cert hostname: \*.%PARENTHOSTNAME%
|
149
|
-
* bad hostname: \*.other.com
|
147
|
+
* bad hostname: \*.other.com (reject)
|
150
148
|
* tld hostname: \*.%TLDHOSTNAME% (reject)
|
151
149
|
* do we want to test more complicated wildcards?
|
150
|
+
* http://www.ietf.org/rfc/rfc2818.txt requires wildcards to only match a
|
151
|
+
single subdomain component, not all subdomain components. Eg, *.a.com matches
|
152
|
+
foo.a.com but not bar.foo.a.com
|
152
153
|
|
153
154
|
* Decide how to deal with a wildcard cert at the original destination. If we
|
154
155
|
are testing foo.somehost.com, and the client connects to other hostnames like
|
155
156
|
bar.somehost.com, and they all use a *.somehost.com certificate, then
|
156
157
|
TLSPretense gets confused.
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
158
|
+
* If I allow *.somehost.com from the original server to match a test hostname
|
159
|
+
of foo.somehost.com, and the client then requests bar.somehost.com,
|
160
|
+
TLSPretense would present foo.somehost.com, making a well behaved client
|
161
|
+
reject the hostname mismatch.
|
162
|
+
* If I don't allow *.somehost.com from the original server match a test
|
163
|
+
hostname of foo.somehost.com, then TLSPretense will never successfully run
|
164
|
+
its tests.
|
165
|
+
* If I set the test hostname to *.somehost.com, then tests for wildcards and
|
166
|
+
subdomains wouldn't be valid, but the rest of the tests would work.
|
167
|
+
* Perhaps a better option would be to present a warning if the original
|
168
|
+
host has a wildcard in it, unless the target hostname also has a wildcard
|
169
|
+
in it. (which should present a warning about the sort of tests that won't
|
170
|
+
produce meaningful results)
|
162
171
|
|
163
172
|
* Advanced: Add name constraints tests.
|
164
173
|
* success: dnsName of leaf matches exactly the dnsName permitted constraint
|
@@ -226,6 +235,6 @@ Or just certain tests (in the order specified):
|
|
226
235
|
|
227
236
|
== Copyright
|
228
237
|
|
229
|
-
Copyright (c) 2012 iSEC Partners
|
238
|
+
Copyright (c) 2012-2013 iSEC Partners
|
230
239
|
|
231
240
|
See LICENSE.txt for further details.
|
data/Rakefile
CHANGED
@@ -18,6 +18,7 @@ task :default => :spec
|
|
18
18
|
|
19
19
|
require 'rdoc/task'
|
20
20
|
Rake::RDocTask.new do |rdoc|
|
21
|
+
$: << 'lib'
|
21
22
|
require 'tlspretense/version'
|
22
23
|
version = TLSPretense::VERSION
|
23
24
|
|
@@ -38,7 +39,3 @@ Rake::RDocTask.new do |rdoc|
|
|
38
39
|
end
|
39
40
|
end
|
40
41
|
|
41
|
-
require 'certmaker/tasks'
|
42
|
-
|
43
|
-
desc "Runs certs:clean"
|
44
|
-
task :clean => ['certs:clean']
|
data/doc/general_setup.rdoc
CHANGED
@@ -49,10 +49,28 @@ This setup has the following network topography:
|
|
49
49
|
|
50
50
|
== Installing TLSPretense
|
51
51
|
|
52
|
-
|
52
|
+
=== General Case
|
53
|
+
|
54
|
+
The following assumes that the +gem+ command refers to the Ruby 1.9.3 version
|
55
|
+
of gem. If the Ruby 1.9.3 version on your system has a suffix, use that version
|
56
|
+
of +gem+ instead. Install with rubygems:
|
53
57
|
|
54
58
|
umask 0022 ; sudo gem install tlspretense
|
55
59
|
|
60
|
+
=== Ubuntu 12.04 and Later
|
61
|
+
|
62
|
+
If you are using Ubuntu, The ruby1.9.1 package on Ubuntu 12.04 is actually Ruby
|
63
|
+
1.9.3 (1.9.1 in this case is the ABI version, not the software version).
|
64
|
+
Assuming you haven't already installed Ruby 1.9.3:
|
65
|
+
|
66
|
+
sudo apt-get install ruby1.9.1-full
|
67
|
+
|
68
|
+
then install with rubygems:
|
69
|
+
|
70
|
+
umask 0022 ; sudo gem1.9.1 install tlspretense
|
71
|
+
|
72
|
+
=== Create a TLSPretense Project
|
73
|
+
|
56
74
|
Create a new project:
|
57
75
|
|
58
76
|
tlspretense init myproject
|
@@ -258,6 +276,9 @@ the firewall rule that redirects network traffic itself.
|
|
258
276
|
For a sample Linux-specific configuration, see: {Linux
|
259
277
|
Setup}[rdoc-ref:linux_setup].
|
260
278
|
|
279
|
+
For information on configuring TLSPretense on a Mac OS X system, see: {Mac OS X
|
280
|
+
Setup}[rdoc-ref:macosx_setup]
|
281
|
+
|
261
282
|
|
262
283
|
== Running the tests
|
263
284
|
|
@@ -0,0 +1,86 @@
|
|
1
|
+
= Setting Up Mac OS X for Use With TLSPretense
|
2
|
+
|
3
|
+
To run TLSPretense on Mac OS X, you need a Mac running Mac OS X 10.6 or later,
|
4
|
+
and you need to have at least two network interfaces. If you are using a Mac
|
5
|
+
laptop that only has wifi, you will need to use one or more ethernet adapters.
|
6
|
+
|
7
|
+
The following sections cover how to setup both Mac OS X 10.6 and 10.7.
|
8
|
+
|
9
|
+
== Configuring Internet Sharing
|
10
|
+
|
11
|
+
This example assumes that you want to test software running on a device
|
12
|
+
that uses wifi, such as an iOS or Android app. The sytem hosting TLSPretense
|
13
|
+
will be a Mac running Mac OS X 10.6, 10.7, or 10.8. We
|
14
|
+
will turn our wifi adapter into a wireless access point and then share our
|
15
|
+
Internet connection from a physical ethernet adapter with it.
|
16
|
+
|
17
|
+
First, open System Preferences and ensure that the ethernet connection has
|
18
|
+
Internet access. You may need to authenticate as an admin in order to make
|
19
|
+
changes.
|
20
|
+
|
21
|
+
Then, if your wifi adapter is currently connected to a network, tell it to
|
22
|
+
disconnect.
|
23
|
+
|
24
|
+
Next, go to the Sharing preference pane, and click on "Internet Sharing" to
|
25
|
+
configure it. Set "Share your connection from:" to your Ethernet connection
|
26
|
+
(usually en0), and share it to your airport connection (usually en1). Click on
|
27
|
+
"AirPort Options..." to configure the wireless access point it will create.
|
28
|
+
Finally, click the checkbox next to "Internet Sharing" enable it.
|
29
|
+
|
30
|
+
Internet Sharing will enable +natd+ in Mac OX X 10.6 (uses ipfw), ??? in
|
31
|
+
Mac OS X 10.7 and +natpmpd+ in 10.8 (10.7 and later use Apple's version of PF,
|
32
|
+
which is a much older version of PF than used by FreeBSD and OpenBSD). Both
|
33
|
+
versions of the NAT
|
34
|
+
will forward IPv4 traffic originating from devices connected to the Mac's
|
35
|
+
Airport card, and forward it on to the designated outgoing network device
|
36
|
+
(TODO: Does it handle IPv6 routing?).
|
37
|
+
Internet Sharing will also enable a DHCP server to automatically configure any
|
38
|
+
clients that connect to the internal side of the network.
|
39
|
+
|
40
|
+
TLSPretense uses its PacketThief library to capture the traffic it is
|
41
|
+
configured to intercept, and it will initiate new outgoing connections, usually
|
42
|
+
bypassing the NAT daemon for such traffic. We still want the NAT service because it will
|
43
|
+
forward traffic not intercepted by TLSPretense.
|
44
|
+
|
45
|
+
Once you have Internet Sharing enabled, you should test to make sure it works
|
46
|
+
with your test device.
|
47
|
+
|
48
|
+
== Configure the Test Device
|
49
|
+
|
50
|
+
Next, the system that will run the client code needs to be configured to use
|
51
|
+
the TLSPretense host as its gateway. This usually involves connecting the
|
52
|
+
client system to the new wireless access point or to the ethernet port that
|
53
|
+
represents the internal network. DHCP should automatically configure the
|
54
|
+
address, gateway, subnet mask, and DNS information for the client system, but
|
55
|
+
you may need to manually modify these values if something does not work
|
56
|
+
(wireshark on the system running TLSPretense can help you debug this).
|
57
|
+
|
58
|
+
== Configuring the PF Firewall
|
59
|
+
|
60
|
+
You need to add the following line to the bottom of your system's +/etc/pf.conf+:
|
61
|
+
|
62
|
+
rdr-anchor "packetthief"
|
63
|
+
|
64
|
+
It should be inserted after any NAT rules, but before any other redirect rules
|
65
|
+
(such as Apple's +rdr-anchor+ rule). Once you have added it, you should reload
|
66
|
+
the core ruleset:
|
67
|
+
|
68
|
+
sudo pfctl -f /etc/pf.conf
|
69
|
+
|
70
|
+
|
71
|
+
== Configure TLSPretense
|
72
|
+
|
73
|
+
Mac laptops use en0, en1, etc. for their Unix network interface names. Mac
|
74
|
+
laptops that have both ethernet and wifi built in usually have ethernet on en0
|
75
|
+
and their wifi interface on en1. However, on newer Mac laptops that only have
|
76
|
+
built-in wifi, the wifi is usually +en0+ and devices like Thunderbolt ethernet
|
77
|
+
adaptors will be assigned a higher-numbered interface name.
|
78
|
+
|
79
|
+
On Mac OS X 10.8, with Internet Sharing enabled, the internal LAN's gateway is
|
80
|
+
+bridge0+ rather than the +en*+ interface.
|
81
|
+
|
82
|
+
You should set +in_interface+ in the +packetthief+ section of your config.yml
|
83
|
+
to the network interface name of the correct internal network.
|
84
|
+
|
85
|
+
Aside from that, configure TLSPretense normally, as discussed in the {General
|
86
|
+
Setup}[rdoc-ref:general_setup].
|
data/lib/packetthief.rb
CHANGED
@@ -117,6 +117,14 @@ module PacketThief
|
|
117
117
|
include Logging
|
118
118
|
end
|
119
119
|
|
120
|
+
def self.logger=(log)
|
121
|
+
PacketThief::Logging.logger = log
|
122
|
+
end
|
123
|
+
|
124
|
+
def self.logger
|
125
|
+
PacketThief::Logging.logger
|
126
|
+
end
|
127
|
+
|
120
128
|
def self.implementation; @implementation ; end
|
121
129
|
|
122
130
|
def self.implementation=(newimpl)
|
@@ -155,7 +163,6 @@ module PacketThief
|
|
155
163
|
if self.implementation == nil
|
156
164
|
self.implementation = guess_implementation
|
157
165
|
end
|
158
|
-
implementation.logger = @logger if implementation.respond_to? :logger=
|
159
166
|
self.implementation.send(m, *args, &block)
|
160
167
|
end
|
161
168
|
|
@@ -26,8 +26,7 @@ module PacketThief
|
|
26
26
|
# is applied to the SSLSocket during #tls_begin.
|
27
27
|
attr_accessor :sni_hostname
|
28
28
|
|
29
|
-
def initialize(tcpsocket
|
30
|
-
@logger = logger
|
29
|
+
def initialize(tcpsocket)
|
31
30
|
logdebug "initialize"
|
32
31
|
# Set up initial values
|
33
32
|
@tcpsocket = tcpsocket
|
@@ -103,11 +103,10 @@ module PacketThief
|
|
103
103
|
logdebug "(#{@ssl_class}): Received a new connection, spawning a #{@ssl_class}"
|
104
104
|
sock = @servsocket.accept_nonblock
|
105
105
|
|
106
|
-
::EM.watch sock, @ssl_class, sock, *@args
|
106
|
+
::EM.watch sock, @ssl_class, sock, *@args do |h|
|
107
107
|
logdebug "after initialize"
|
108
108
|
h.server_handler = self
|
109
109
|
h.notify_readable = true
|
110
|
-
h.logger = @logger
|
111
110
|
# Now call the caller's block.
|
112
111
|
@block.call(h) if @block
|
113
112
|
# And finally finish initialization by applying the context to an
|
@@ -145,8 +144,8 @@ module PacketThief
|
|
145
144
|
####
|
146
145
|
|
147
146
|
public
|
148
|
-
def initialize(tcpsocket
|
149
|
-
super(tcpsocket
|
147
|
+
def initialize(tcpsocket)
|
148
|
+
super(tcpsocket)
|
150
149
|
@ctx.servername_cb = proc {|sslsocket, hostname| self.servername_cb(sslsocket, hostname) }
|
151
150
|
end
|
152
151
|
|
@@ -15,8 +15,8 @@ module PacketThief
|
|
15
15
|
# seconds.
|
16
16
|
attr_accessor :preflight_timeout
|
17
17
|
|
18
|
-
def initialize(tcpsocket, ca_chain, key
|
19
|
-
super(tcpsocket
|
18
|
+
def initialize(tcpsocket, ca_chain, key)
|
19
|
+
super(tcpsocket)
|
20
20
|
|
21
21
|
@preflight_timeout = 5
|
22
22
|
if ca_chain.kind_of? Array
|
@@ -53,7 +53,7 @@ module PacketThief
|
|
53
53
|
|
54
54
|
# Requests a certificate from the original destination.
|
55
55
|
def preflight_for_cert(hostname=nil)
|
56
|
-
logdebug "
|
56
|
+
logdebug "preflight for: #{hostname}"
|
57
57
|
begin
|
58
58
|
pfctx = OpenSSL::SSL::SSLContext.new
|
59
59
|
pfctx.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
data/lib/packetthief/logging.rb
CHANGED
@@ -1,48 +1,56 @@
|
|
1
1
|
module PacketThief
|
2
2
|
# Mix-in that provides some private convenience logging functions. Uses the
|
3
|
-
#
|
3
|
+
# logger specified by this module. To set the current logger for all of
|
4
|
+
# PacketThief:
|
5
|
+
#
|
6
|
+
# PacketThief::Logging.logger = Logger.new
|
4
7
|
module Logging
|
5
|
-
# An optional Ruby Logger for debugging output. If it is unset, the log
|
6
|
-
# methods will be silent.
|
7
|
-
attr_accessor :logger
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
9
|
+
class << self
|
10
|
+
|
11
|
+
# An optional Ruby Logger for debugging output. If it is unset, the log
|
12
|
+
# methods will be silent.
|
13
|
+
attr_accessor :logger
|
14
|
+
|
15
|
+
# Print a message at the specified log severity (prefixed with the component),
|
16
|
+
# and display any additional arguments. For example:
|
17
|
+
#
|
18
|
+
# log(Logger::DEBUG, SomeClass, "hello", :somevalue => 'that value")
|
19
|
+
#
|
20
|
+
# Will print the message: "SomeClass: hello: somevalue=that value" at the
|
21
|
+
# debug log level.
|
22
|
+
def log(level, component, msg, args={})
|
23
|
+
if @logger
|
24
|
+
unless args.empty?
|
25
|
+
kvstr = args.map { |pair| pair[0].to_s + ': ' + pair[1].inspect }.sort.join(', ')
|
26
|
+
msg += ": " + kvstr
|
27
|
+
end
|
28
|
+
@logger.log(level, component.to_s + ': ' + msg)
|
23
29
|
end
|
24
|
-
@logger.log(level, component.to_s + ': ' + msg)
|
25
30
|
end
|
31
|
+
|
26
32
|
end
|
27
33
|
|
34
|
+
private
|
35
|
+
|
28
36
|
def logdebug(msg, args={})
|
29
|
-
log(Logger::DEBUG, (([Module, Class].include? self.class) ? self.name : self.class), msg, args)
|
37
|
+
Logging.log(Logger::DEBUG, (([Module, Class].include? self.class) ? self.name : self.class), msg, args)
|
30
38
|
end
|
31
39
|
|
32
40
|
def loginfo(msg, args={})
|
33
|
-
log(Logger::INFO, self.class, msg, args)
|
41
|
+
Logging.log(Logger::INFO, self.class, msg, args)
|
34
42
|
end
|
35
43
|
|
36
44
|
def logwarn(msg, args={})
|
37
|
-
log(Logger::WARN, self.class, msg, args)
|
45
|
+
Logging.log(Logger::WARN, self.class, msg, args)
|
38
46
|
end
|
39
47
|
|
40
48
|
def logerror(msg, args={})
|
41
|
-
log(Logger::ERROR, self.class, msg, args)
|
49
|
+
Logging.log(Logger::ERROR, self.class, msg, args)
|
42
50
|
end
|
43
51
|
|
44
52
|
def logfatal(msg, args={})
|
45
|
-
log(Logger::FATAL, self.class, msg, args)
|
53
|
+
Logging.log(Logger::FATAL, self.class, msg, args)
|
46
54
|
end
|
47
55
|
|
48
56
|
end
|
data/lib/tlspretense/app.rb
CHANGED
@@ -30,7 +30,9 @@ QUOTE
|
|
30
30
|
when 'init'
|
31
31
|
InitRunner.new(@action_args, @stdin, @stdout).run
|
32
32
|
when 'run'
|
33
|
-
TestHarness::Runner.new(@action_args, @stdin, @stdout).run
|
33
|
+
unless TestHarness::Runner.new(@action_args, @stdin, @stdout).run
|
34
|
+
return 1
|
35
|
+
end
|
34
36
|
when 'list', 'ls'
|
35
37
|
TestHarness::Runner.new(['--list'] + @action_args, @stdin, @stdout).run
|
36
38
|
when 'ca'
|
@@ -45,8 +47,9 @@ QUOTE
|
|
45
47
|
rescue CleanExitError => e
|
46
48
|
@stdout.puts ""
|
47
49
|
@stdout.puts "#{e.class}: #{e}"
|
48
|
-
|
50
|
+
return 1
|
49
51
|
end
|
52
|
+
0
|
50
53
|
end
|
51
54
|
end
|
52
55
|
end
|
@@ -4,11 +4,16 @@ require 'yaml'
|
|
4
4
|
|
5
5
|
require 'tlspretense/ext_core/hash_indifferent_fetch'
|
6
6
|
|
7
|
+
# Provide a limited version of OpenSSL::PKey.read for older Ruby versions.
|
8
|
+
require 'tlspretense/ext_compat/openssl_pkey_read'
|
9
|
+
TLSPretense::ExtCompat::OpenSSLPKeyRead.check_and_apply_patch
|
10
|
+
|
7
11
|
module TLSPretense
|
8
12
|
module CertMaker
|
9
13
|
|
10
14
|
autoload :CertificateFactory, 'tlspretense/cert_maker/certificate_factory'
|
11
15
|
autoload :CertificateSuiteGenerator, 'tlspretense/cert_maker/certificate_suite_generator'
|
16
|
+
autoload :SubjectAltNameFactory, 'tlspretense/cert_maker/subject_alt_name_factory'
|
12
17
|
|
13
18
|
|
14
19
|
# Generate certificates and keys using +config+.
|