tlspretense 0.6.2 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.travis.yml +5 -0
  4. data/README.rdoc +25 -16
  5. data/Rakefile +1 -4
  6. data/doc/general_setup.rdoc +22 -1
  7. data/doc/macosx_setup.rdoc +86 -0
  8. data/lib/packetthief.rb +8 -1
  9. data/lib/packetthief/handlers/abstract_ssl_handler.rb +1 -2
  10. data/lib/packetthief/handlers/ssl_server.rb +3 -4
  11. data/lib/packetthief/handlers/ssl_smart_proxy.rb +3 -3
  12. data/lib/packetthief/handlers/ssl_transparent_proxy.rb +1 -1
  13. data/lib/packetthief/handlers/transparent_proxy.rb +1 -2
  14. data/lib/packetthief/logging.rb +32 -24
  15. data/lib/tlspretense/app.rb +5 -2
  16. data/lib/tlspretense/cert_maker.rb +5 -0
  17. data/lib/tlspretense/cert_maker/certificate_factory.rb +11 -1
  18. data/lib/tlspretense/cert_maker/certificate_suite_generator.rb +21 -3
  19. data/lib/tlspretense/cert_maker/subject_alt_name_factory.rb +115 -0
  20. data/lib/tlspretense/ext_compat/openssl_pkey_read.rb +38 -0
  21. data/lib/tlspretense/skel/config.yml +194 -17
  22. data/lib/tlspretense/test_harness/input_handler.rb +6 -2
  23. data/lib/tlspretense/test_harness/runner.rb +9 -3
  24. data/lib/tlspretense/test_harness/ssl_test_case.rb +2 -9
  25. data/lib/tlspretense/test_harness/ssl_test_report.rb +3 -0
  26. data/lib/tlspretense/test_harness/test_listener.rb +2 -2
  27. data/lib/tlspretense/test_harness/test_manager.rb +1 -2
  28. data/lib/tlspretense/version.rb +1 -1
  29. data/packetthief_examples/ssl_client_simple.rb +7 -0
  30. data/spec/packetthief/impl/ipfw_spec.rb +4 -2
  31. data/spec/packetthief/impl/netfilter_spec.rb +4 -2
  32. data/spec/packetthief/impl/pf_divert_spec.rb +4 -2
  33. data/spec/packetthief/logging_spec.rb +24 -26
  34. data/spec/spec_helper.rb +7 -8
  35. data/spec/tlspretense/cert_maker/subject_alt_name_factory_spec.rb +75 -0
  36. data/spec/tlspretense/ext_compat/openssl_pkey_read_spec.rb +126 -0
  37. data/spec/tlspretense/test_harness/runner_spec.rb +3 -5
  38. data/tlspretense.gemspec +2 -2
  39. metadata +41 -48
  40. data/Gemfile.lock +0 -41
@@ -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
@@ -5,3 +5,4 @@ rdoc
5
5
  .bundle
6
6
  pkg
7
7
  tags
8
+ Gemfile.lock
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2
4
+ - 2.3
5
+ - 2.4
@@ -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 (and
132
- probably not on 10.8 either). OpenBSD 5.0(?) and FreeBSD 9 can make use of
133
- this functionality though.
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
- * Fix the subjectAltName null byte test. It requires manual construction of the
144
- ASN1 encoding due to the null byte causing a truncation somewhere in OpenSSL
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
- * Add extension criticality tests (need an extension oid that nobody knows how to verify)
159
- * If an extension is marked critical and the verifier doesn't know how to
160
- verify, then it should fail. If it is not marked critical, then it is
161
- allowed to skip the extension.
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']
@@ -49,10 +49,28 @@ This setup has the following network topography:
49
49
 
50
50
  == Installing TLSPretense
51
51
 
52
- Install with rubygems:
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].
@@ -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, logger=nil)
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, @logger do |h|
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,logger=nil)
149
- super(tcpsocket, logger)
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, logger=nil)
19
- super(tcpsocket, logger)
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 "prefilight for: #{hostname}"
56
+ logdebug "preflight for: #{hostname}"
57
57
  begin
58
58
  pfctx = OpenSSL::SSL::SSLContext.new
59
59
  pfctx.verify_mode = OpenSSL::SSL::VERIFY_NONE
@@ -83,7 +83,7 @@ module PacketThief
83
83
  # Initially, its verify_mode is set to OpenSSL::SSL::VERIFY_NONE.
84
84
  attr_accessor :dest_ctx
85
85
 
86
- def initialize(tcpsocket, logger=nil)
86
+ def initialize(tcpsocket)
87
87
  super
88
88
  @closed = false
89
89
 
@@ -68,8 +68,7 @@ module PacketThief
68
68
  # When the proxy should connect to a destination.
69
69
  attr_accessor :when_to_connect_to_dest
70
70
 
71
- def initialize(log=nil)
72
- @logger = log
71
+ def initialize
73
72
  end
74
73
 
75
74
  def post_init
@@ -1,48 +1,56 @@
1
1
  module PacketThief
2
2
  # Mix-in that provides some private convenience logging functions. Uses the
3
- # @logger instance variable.
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
- private
10
-
11
- # Print a message at the specified log severity (prefixed with the component),
12
- # and display any additional arguments. For example:
13
- #
14
- # dlog(Logger::DEBUG, SomeClass, "hello", :somevalue => 'that value")
15
- #
16
- # Will print the message: "SomeClass: hello: somevalue=that value" at the
17
- # debug log level.
18
- def log(level, component, msg, args={})
19
- if @logger
20
- unless args.empty?
21
- kvstr = args.map { |pair| pair[0].to_s + ': ' + pair[1].inspect }.sort.join(', ')
22
- msg += ": " + kvstr
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
@@ -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
- exit 1
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+.