tlspretense 0.6.1

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 (81) hide show
  1. data/.document +6 -0
  2. data/.gitignore +7 -0
  3. data/.rspec +1 -0
  4. data/Gemfile +2 -0
  5. data/Gemfile.lock +41 -0
  6. data/LICENSE.txt +20 -0
  7. data/README.rdoc +231 -0
  8. data/Rakefile +44 -0
  9. data/bin/makeder.sh +6 -0
  10. data/bin/tlspretense +7 -0
  11. data/bin/view.sh +3 -0
  12. data/doc/general_setup.rdoc +288 -0
  13. data/doc/linux_setup.rdoc +64 -0
  14. data/lib/certmaker.rb +61 -0
  15. data/lib/certmaker/certificate_factory.rb +106 -0
  16. data/lib/certmaker/certificate_suite_generator.rb +120 -0
  17. data/lib/certmaker/ext_core/hash_indifferent_fetch.rb +12 -0
  18. data/lib/certmaker/runner.rb +27 -0
  19. data/lib/certmaker/tasks.rb +20 -0
  20. data/lib/packetthief.rb +167 -0
  21. data/lib/packetthief/handlers.rb +14 -0
  22. data/lib/packetthief/handlers/abstract_ssl_handler.rb +249 -0
  23. data/lib/packetthief/handlers/proxy_redirector.rb +26 -0
  24. data/lib/packetthief/handlers/ssl_client.rb +87 -0
  25. data/lib/packetthief/handlers/ssl_server.rb +174 -0
  26. data/lib/packetthief/handlers/ssl_smart_proxy.rb +143 -0
  27. data/lib/packetthief/handlers/ssl_transparent_proxy.rb +225 -0
  28. data/lib/packetthief/handlers/transparent_proxy.rb +183 -0
  29. data/lib/packetthief/impl.rb +11 -0
  30. data/lib/packetthief/impl/ipfw.rb +140 -0
  31. data/lib/packetthief/impl/manual.rb +54 -0
  32. data/lib/packetthief/impl/netfilter.rb +109 -0
  33. data/lib/packetthief/impl/pf_divert.rb +168 -0
  34. data/lib/packetthief/impl/pf_rdr.rb +192 -0
  35. data/lib/packetthief/logging.rb +49 -0
  36. data/lib/packetthief/redirect_rule.rb +29 -0
  37. data/lib/packetthief/util.rb +36 -0
  38. data/lib/ssl_test.rb +21 -0
  39. data/lib/ssl_test/app_context.rb +17 -0
  40. data/lib/ssl_test/certificate_manager.rb +33 -0
  41. data/lib/ssl_test/config.rb +79 -0
  42. data/lib/ssl_test/ext_core/io_raw_input.rb +31 -0
  43. data/lib/ssl_test/input_handler.rb +35 -0
  44. data/lib/ssl_test/runner.rb +110 -0
  45. data/lib/ssl_test/runner_options.rb +68 -0
  46. data/lib/ssl_test/ssl_test_case.rb +46 -0
  47. data/lib/ssl_test/ssl_test_report.rb +24 -0
  48. data/lib/ssl_test/ssl_test_result.rb +30 -0
  49. data/lib/ssl_test/test_listener.rb +140 -0
  50. data/lib/ssl_test/test_manager.rb +116 -0
  51. data/lib/tlspretense.rb +13 -0
  52. data/lib/tlspretense/app.rb +52 -0
  53. data/lib/tlspretense/init_runner.rb +115 -0
  54. data/lib/tlspretense/skel/ca/goodcacert.pem +19 -0
  55. data/lib/tlspretense/skel/ca/goodcakey.pem +27 -0
  56. data/lib/tlspretense/skel/config.yml +523 -0
  57. data/lib/tlspretense/version.rb +3 -0
  58. data/packetthief_examples/em_ssl_test.rb +73 -0
  59. data/packetthief_examples/redirector.rb +29 -0
  60. data/packetthief_examples/setup_iptables.sh +24 -0
  61. data/packetthief_examples/ssl_client_simple.rb +27 -0
  62. data/packetthief_examples/ssl_server_simple.rb +44 -0
  63. data/packetthief_examples/ssl_smart_proxy.rb +115 -0
  64. data/packetthief_examples/ssl_transparent_proxy.rb +97 -0
  65. data/packetthief_examples/transparent_proxy.rb +56 -0
  66. data/spec/packetthief/impl/ipfw_spec.rb +98 -0
  67. data/spec/packetthief/impl/manual_spec.rb +65 -0
  68. data/spec/packetthief/impl/netfilter_spec.rb +66 -0
  69. data/spec/packetthief/impl/pf_divert_spec.rb +82 -0
  70. data/spec/packetthief/impl/pf_rdr_spec.rb +133 -0
  71. data/spec/packetthief/logging_spec.rb +78 -0
  72. data/spec/packetthief_spec.rb +47 -0
  73. data/spec/spec_helper.rb +53 -0
  74. data/spec/ssl_test/certificate_manager_spec.rb +222 -0
  75. data/spec/ssl_test/config_spec.rb +76 -0
  76. data/spec/ssl_test/runner_spec.rb +360 -0
  77. data/spec/ssl_test/ssl_test_case_spec.rb +113 -0
  78. data/spec/ssl_test/test_listener_spec.rb +199 -0
  79. data/spec/ssl_test/test_manager_spec.rb +324 -0
  80. data/tlspretense.gemspec +35 -0
  81. metadata +262 -0
@@ -0,0 +1,116 @@
1
+ module SSLTest
2
+ # Tracks testing state and handles reporting for the TestListener.
3
+ class TestManager
4
+ include PacketThief::Logging
5
+
6
+ attr_accessor :current_test
7
+ attr_reader :remaining_tests
8
+
9
+ attr_accessor :listener
10
+
11
+ attr_accessor :goodcacert
12
+ attr_accessor :goodcakey
13
+
14
+ def initialize(context, testlist, report, logger=nil)
15
+ @appctx = context
16
+ @testlist = testlist
17
+ @report = report
18
+ @logger = logger
19
+ @remaining_tests = @testlist.dup
20
+
21
+ @goodcacert = @appctx.cert_manager.get_cert("goodca")
22
+ @goodcakey = @appctx.cert_manager.get_key("goodca")
23
+
24
+ @pause = false
25
+ prepare_next_test(true)
26
+ end
27
+
28
+ # grabs the next test. Returns it, or nil if we are out of tests.
29
+ def prepare_next_test(first=false)
30
+ @current_test = @remaining_tests.shift
31
+
32
+ if current_test == nil
33
+ stop_testing
34
+ elsif @appctx.config.pause? and not first
35
+ pause
36
+ else
37
+ loginfo "Starting test: #{current_test.id}"
38
+ end
39
+
40
+ @start_time = Time.now
41
+ end
42
+
43
+ # Called when a test completes or is skipped. It adds an SSLTestResult to
44
+ # the report, and it cleans up after itself.
45
+ #
46
+ # :connected, :rejected, :sentdata
47
+ def test_completed(test, actual_result)
48
+ logdebug "test_completed", :actual_result => actual_result, :expected_result => test.expected_result, :test => test.id
49
+ return if actual_result == :running
50
+
51
+ passed = if @appctx.config.testing_method == 'tlshandshake'
52
+ case test.expected_result.to_s
53
+ when 'connected', :connected
54
+ %w{connected sentdata}.include? actual_result.to_s
55
+ when 'rejected', :rejected
56
+ actual_result == :rejected
57
+ else
58
+ raise "Unknown expected_result: #{test.expected_result}"
59
+ end
60
+ else # senddata, which requires data to be sent for it to pass.
61
+ case test.expected_result
62
+ when 'connected'
63
+ actual_result == :sentdata
64
+ when 'rejected'
65
+ %w{rejected connected}.include? actual_result.to_s
66
+ else
67
+ raise "Unknown expected_result: #{test.expected_result}"
68
+ end
69
+ end
70
+
71
+ str = SSLTestResult.new(test.id, passed)
72
+ str.description = test.description
73
+ str.expected_result = test.expected_result
74
+ str.actual_result = actual_result.to_s
75
+ str.start_time = @start_time
76
+ str.stop_time = Time.now
77
+
78
+ @report.add_result(str)
79
+
80
+ if actual_result == :skipped
81
+ loginfo "#{test.id}: Skipping test"
82
+ else
83
+ loginfo "#{test.id}: Finished test"
84
+ end
85
+
86
+ prepare_next_test if current_test == test
87
+ end
88
+
89
+ def stop_testing
90
+ loginfo "Stopping"
91
+ @listener.stop_server if @listener
92
+ EM.stop_event_loop
93
+ end
94
+
95
+ def paused?
96
+ @pause
97
+ end
98
+
99
+ def pause
100
+ @pause = true
101
+ loginfo "Press Enter to continue."
102
+ end
103
+
104
+ def unpause
105
+ if paused?
106
+ loginfo "Starting test: #{current_test.id}"
107
+ @pause = false
108
+ end
109
+ end
110
+
111
+ def testing_method
112
+ @appctx.config.testing_method
113
+ end
114
+
115
+ end
116
+ end
@@ -0,0 +1,13 @@
1
+ require 'fileutils'
2
+
3
+ require 'ssl_test'
4
+ require 'certmaker'
5
+ require 'certmaker/runner'
6
+
7
+ module TLSPretense
8
+ class CleanExitError < StandardError ; end
9
+
10
+ autoload :App, 'tlspretense/app'
11
+ autoload :InitRunner, 'tlspretense/init_runner'
12
+ autoload :VERSION, 'tlspretense/version'
13
+ end
@@ -0,0 +1,52 @@
1
+ module TLSPretense
2
+ class App
3
+ def initialize(args, stdin, stdout)
4
+ @args = args
5
+ @stdin = stdin
6
+ @stdout = stdout
7
+ @action_args = args.dup
8
+ @action = @action_args.shift
9
+ end
10
+
11
+ def usage
12
+ @stdout.puts <<-QUOTE
13
+ Usage: #{0} action arguments...
14
+
15
+ Actions:
16
+ init PATH Creates a new TLSPretense working directory. This includes
17
+ configuration files and test certificates.
18
+ run Run all or some of the test cases. Call `run -h` for more
19
+ information.
20
+ list, ls List all or some of the test cases (equivalent to `run -l`).
21
+ ca Checks for a ca, and generates it if needed.
22
+ certs (Re)generate a suite of test certificates.
23
+ cleancerts Remove the certs directory.
24
+ QUOTE
25
+ end
26
+
27
+ def run
28
+ begin
29
+ case @action
30
+ when 'init'
31
+ InitRunner.new(@action_args, @stdin, @stdout).run
32
+ when 'run'
33
+ SSLTest::Runner.new(@action_args, @stdin, @stdout).run
34
+ when 'list', 'ls'
35
+ SSLTest::Runner.new(['--list'] + @action_args, @stdin, @stdout).run
36
+ when 'ca'
37
+ CertMaker::Runner.new.ca
38
+ when 'certs'
39
+ CertMaker::Runner.new.certs
40
+ when 'cleancerts'
41
+ CertMaker::Runner.new.clean
42
+ else
43
+ usage
44
+ end
45
+ rescue CleanExitError => e
46
+ @stdout.puts ""
47
+ @stdout.puts "#{e.class}: #{e}"
48
+ exit 1
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,115 @@
1
+ module TLSPretense
2
+ class InitRunner
3
+ include FileUtils
4
+
5
+ class InitError < CleanExitError ; end
6
+
7
+ def initialize(args, stdin, stdout)
8
+ @args = args
9
+ @stdin = stdin
10
+ @stdout = stdout
11
+ end
12
+
13
+ def run
14
+ if @args.length != 1
15
+ usage
16
+ return
17
+ end
18
+ path = @args[0]
19
+ check_environment
20
+ init_project(path)
21
+ end
22
+
23
+ def check_environment
24
+ @stdout.puts "Ruby and OpenSSL compatibility check..."
25
+ # Ruby check:
26
+ # TODO: detect non-MRI versions of Ruby such as jruby, ironruby
27
+ if ruby_version[:major] < 1 or ruby_version[:minor] < 9 or ruby_version[:patch] < 3
28
+ @stdout.puts <<-QUOTE.gsub(/^ /,'')
29
+ Warning: You are running TLSPretense on an unsupported version of Ruby:
30
+
31
+ RUBY_DESCRIPTION: #{RUBY_DESCRIPTION}
32
+
33
+ Use it at your own risk! TLSPretense was developed and tested on MRI Ruby
34
+ 1.9.3. However, bug reports are welcome for Ruby 1.8.7 and later to try and
35
+ improve compatibility.
36
+
37
+ QUOTE
38
+ end
39
+ unless openssl_supports_sni?
40
+ @stdout.puts <<-QUOTE.gsub(/^ /,'')
41
+
42
+ Warning: Your version of Ruby and/or OpenSSL does not have the ability to set
43
+ the SNI hostname on outgoing SSL/TLS connections.
44
+
45
+ Testing might work fine, but if the client being tested sends the SNI TLS
46
+ extension to request the certificate for a certain hostname, TLSPretense will
47
+ be unable to request the correct certificate from the destination, which may
48
+ adversely affect testing.
49
+
50
+ QUOTE
51
+ end
52
+ end
53
+
54
+ def ruby_version
55
+ @ruby_version ||= (
56
+ v = {}
57
+ m = /^(.+)\.(.+)\.(.+)$/.match(RUBY_VERSION)
58
+ v[:major] = m[1].to_i
59
+ v[:minor] = m[2].to_i
60
+ v[:patch] = m[3].to_i
61
+ v
62
+ )
63
+ end
64
+
65
+ def openssl_supports_sni?
66
+ OpenSSL::SSL::SSLSocket.public_instance_methods.include? :hostname=
67
+ end
68
+
69
+ def init_project(path)
70
+ @stdout.print "Creating #{path}... "
71
+ raise InitError, "#{path} already exists!" if File.exist? path
72
+ mkdir_p path
73
+ @stdout.puts "Done"
74
+
75
+ @stdout.puts "Populating #{path}... "
76
+ skeldir = File.join(File.dirname(__FILE__), 'skel')
77
+ @stdout.print ' ' ; cp_r Dir.glob(File.join(skeldir,'*')), path, :verbose => true
78
+ @stdout.puts "Done"
79
+
80
+ @stdout.puts <<-QUOTE.gsub(/^ /,'')
81
+ Finished!
82
+
83
+ Now cd to #{path} and edit config.yml to suit your needs.
84
+
85
+ If you have an existing CA certificate and key you would like to use, you
86
+ should copy the PEM encoded certificate to:
87
+
88
+ #{path}/ca/goodcacert.pem
89
+
90
+ And you should copy the PEM encoded private key to:
91
+
92
+ #{path}/ca/goodcakey.pem
93
+
94
+ Otherwise you can use the preinstalled CA certificate or delete the ca
95
+ directory and run:
96
+
97
+ tlspretense ca
98
+
99
+ to generate a new CA (which you will then need to install so that the software
100
+ you are testing will trust it).
101
+
102
+ Refer to the guides on http://isecpartners.github.com/tlspretense/ for more
103
+ information on configuring your host to run TLSPretense.
104
+ QUOTE
105
+ end
106
+
107
+ def usage
108
+ @stdout.puts <<-QUOTE.gsub(/^ /,'')
109
+ Usage: #{0} init PATH
110
+
111
+ Creates a new TLSPretense working directory at PATH.
112
+ QUOTE
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,19 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIDJTCCAg2gAwIBAgIECy0y7TANBgkqhkiG9w0BAQUFADAiMQswCQYDVQQGEwJV
3
+ UzETMBEGA1UEAwwKVHJ1c3RlZCBDQTAeFw0xMjEwMDUyMjIwMjFaFw0xMzEwMDUy
4
+ MjIwMjFaMCIxCzAJBgNVBAYTAlVTMRMwEQYDVQQDDApUcnVzdGVkIENBMIIBIjAN
5
+ BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6clG32L98j4S9CqddFeup+NyxZmd
6
+ SPuEqJpIJHPQn/oGDmqXg8qmDr+DayAKa2ZHVD0+p0ymBJ74kZlFg6apcE55WWet
7
+ VfE6L491zfAyIqgVET//OPmDd0pgiBo78NXgwVoThMZ/79/fa0BddV02xqqLNuD5
8
+ 0lXYB918wEoN909y7kOtldcqSL0N8Ts0SHxXrT3zmh+t2Oz007khsq99W50VrYO+
9
+ qzmeUpf1lJopFwRkBpkw1JoXwUL36Kfzqp0KgjEcgdxJU2DsfDIIcqcZEkCFEU9x
10
+ dkaEq6pIAVT4Qegqb7oeLbMEyvRc253cMd5PkjITMa4DgbBeWrrm1QFm7wIDAQAB
11
+ o2MwYTAOBgNVHQ8BAf8EBAMCAgQwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU
12
+ DmhEoCTfJPfISxh9gBtZNVTDZikwHwYDVR0jBBgwFoAUDmhEoCTfJPfISxh9gBtZ
13
+ NVTDZikwDQYJKoZIhvcNAQEFBQADggEBAEoG5up12jtiNII8MU4dziExht/xnJCa
14
+ ZwlVfsnY9coJ8BDw26T3Qk4qYZuWlQz/XVl3ERquHqRITE5ltcLpjgADWIIa09AT
15
+ eZC2lay/Bprevo4DbSRw+nfHF1YOECIRSPfIiA15/f3XsNoB/8kV+vvLxZbQ1Sfi
16
+ C3YXgiqXBtN72kxCfMwpekBXO77p+//Fu2UYiqbyd+W5U79l7B+U6c6CfqfGLhhW
17
+ Up6KBNu9znx9FJUMtQi3qGqb3JFgKZKAdusb3DYDvssWiXRsjFKtswQXwuBH97f1
18
+ cEr7mv5mLsBfgQrAJCZXwpaUIxLMHwAsRfgktiO5iqFalB9Gf4q7YIo=
19
+ -----END CERTIFICATE-----
@@ -0,0 +1,27 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ MIIEpAIBAAKCAQEA6clG32L98j4S9CqddFeup+NyxZmdSPuEqJpIJHPQn/oGDmqX
3
+ g8qmDr+DayAKa2ZHVD0+p0ymBJ74kZlFg6apcE55WWetVfE6L491zfAyIqgVET//
4
+ OPmDd0pgiBo78NXgwVoThMZ/79/fa0BddV02xqqLNuD50lXYB918wEoN909y7kOt
5
+ ldcqSL0N8Ts0SHxXrT3zmh+t2Oz007khsq99W50VrYO+qzmeUpf1lJopFwRkBpkw
6
+ 1JoXwUL36Kfzqp0KgjEcgdxJU2DsfDIIcqcZEkCFEU9xdkaEq6pIAVT4Qegqb7oe
7
+ LbMEyvRc253cMd5PkjITMa4DgbBeWrrm1QFm7wIDAQABAoIBAAZIK0hbX5l/w4Ce
8
+ GIcEyCOov+/BVfGdGI5zPtcD6aoyzLDcel/HNTkWOlDJlp4WLHp9/s3+CEP9hY5c
9
+ APstokXrReV6HLU/eyHGCBNVjfNScuZ4wsHkKn0tGXTux4eMJ7LqWbXqo4tth5JZ
10
+ M2mw7ITgFkeOOghF2D013WFJXCC2C6jgJ/QIK2RYehNlPFUbjWrBFIh3Jg1nbfg9
11
+ WuextjpQqB8dA+1t5FzqhaWXmubIvBvYMjdRuYa63WgCN3VOaI6qqi+bVIbE2SyE
12
+ KNOAT0Lj4F/svJ3O8J1a28eaLKJ370K8x3FLfAgu+NzZG7JI1o3bdsDXmPm3yMwF
13
+ HP8K6lECgYEA+oXOhGFo9X6zph7EFLik9XRZkOTwM2E/FjaaObwuQll84e/3mx/G
14
+ CsPc3+Oc+bhbUn94lAqSNFROASukE1/4yHr8lJdABOmarJpOXm7luSPl/dug85XR
15
+ gpz2u9/lVtiXc/4iLM0UENrTWgmZ9rhh1PSD8ZbA5EXxGNnFfAzqqWcCgYEA7uXL
16
+ iWno1qieyWKhB6vE/ZSMrz1MxKwWoOD2U4futPixgrX32oDdlS889yWKajBW8upf
17
+ Qkr7/YbGtzqr27WCZ/WVOYWAe1lwMpm8gmCg2I+NFD/XaG2IR/A/9QWtO9krPv7j
18
+ p874BLQ8MFkR6xZDzq9pt7rbacNqAjmYFgHQeTkCgYBgFNeKwA1QMkLWUHBlfheO
19
+ KAx93MAfBIn8i/6EbB7VxZp20OEG9p2u3UWl/Jbk04b60fa92HwQY9Dy8/jekW1J
20
+ /plGp+eeurVew2ORJjkm05TO0uAc6/XJgUfD8G/16eXUT8BtrE2o1TRAEPSiwj6L
21
+ PSgpjOb35bc9D7CFDjMluwKBgQDN2ZabjnYCWYORNfpZmMoCUzkyWtjGcx6Ae7fl
22
+ XDD1IYIbhl7OmdHVFcIrl96AB600XX29qs0dtT+PbO/fPrTijXuK+B0wrG2APHZx
23
+ xX9ze6Zt92DOa+tNSZhisgSGmGeqPYm+9BlEPGXMp0NIVYQSGZY3qbwckzTKPARv
24
+ mhqgCQKBgQCGQMrlWCb/mEvoroQ8JsTltsXuB1qbVtYudlkOWTMTGdw82lQQFVQ8
25
+ r9rIDSOoTS/70aCvpQg3jFipJ5vFkPucYspM2jE22LvwqncaUg3KJ0hWcbzZJSxE
26
+ tPLj+I5PQWOR8Gljsik4OhstpU9GOumOyL+EL1MG1+8woArH3P0cTA==
27
+ -----END RSA PRIVATE KEY-----
@@ -0,0 +1,523 @@
1
+ ---
2
+ # This hostname is the one that the test runner will actually perform its test
3
+ # against. All other intercepted SSL connections will use the original
4
+ # certificate, but doctored to use the goodca. For this hostname, the SSL
5
+ # interceptor will present the configured certificate chain of generated
6
+ # certificates.
7
+ #
8
+ # Additionally, the defaultsubject and defaultsubjectwithnull strings will
9
+ # replace %HOSTNAME% with this value during certificate generation.
10
+ #hostname: my.hostname.com
11
+ hostname: www.isecpartners.com
12
+
13
+ # Configuration options to pass to PacketThief to configure your firewall.
14
+ packetthief:
15
+ # Explicitly declare what firewall implementation to use for intercepting
16
+ # traffic. It is also needed to discover the original destination of
17
+ # intercepted network traffic. There are two special implementations: the
18
+ # 'manual' implementation is meant for when you don't use a firewall at all.
19
+ # In this case, you must explicitly provide an original destination for the
20
+ # proxy to forward all intercepted traffic to.
21
+ #
22
+ # The second special implementation is 'external'. This means that you are
23
+ # using a supported firewall, but you want to configure the redirection rule
24
+ # outside of TLSPretense. In this case, you need to name an actual firewall
25
+ # implementation so that the socket that receives the intercepted connection
26
+ # can acquire the original destination (redirected connections provide their
27
+ # original destination through various standard socket APIs).
28
+ #
29
+ # It the implementation is left commented out, then TLSPretense will guess
30
+ # which implementation to use.
31
+ #
32
+ # Options:
33
+ #
34
+ # - netfilter Linux netfilter
35
+ #
36
+ # - ipfw MacOSX10.6/BSD ipfw
37
+ #
38
+ # - pfrdr MacOSX10.7(and 10.8)'s version of PF
39
+ #
40
+ # - manual(destination) If you choose manual, you must also choose a
41
+ # default destination address or hostname.
42
+ #
43
+ # - external(implementation) Use firewall rules that are not managed by the
44
+ # test harness, but that might provide us with
45
+ # the original destination.
46
+ #implementation: manual(www.isecpartners.com)
47
+
48
+ # The remaining options are used to construct the firewall rule:
49
+ protocol: tcp
50
+ dest_port: 443
51
+ # Linux-like interface:
52
+ in_interface: eth1
53
+ # Mac OS X-like interface:
54
+ #in_interface: en1
55
+
56
+ # The port that PacketThief should redirect traffic to, and the port that the
57
+ # SSL interceptor will run on during each test.
58
+ listener_port: 54321
59
+
60
+ # The testing_method is used to determine whether the client has accepted or
61
+ # rejected a certificate. If you find any of these to be unreliable, then you
62
+ # will need to determine pass/fail yourself.
63
+ #
64
+ # - tlshandshake We say that the client accepts a test if it completes the
65
+ # TLS handshake, and it rejects a request if it does not
66
+ # complete the handshake.
67
+ # - senddata We say that the client accepts a test if it sends data,
68
+ # instead of whether it completes the TLS handshake. This may
69
+ # be necessary for Android and probably other Java-based SSL
70
+ # using code.
71
+ testing_method: senddata
72
+
73
+ # Meta-configuration for certificate generation. These values affect the
74
+ # default settings for certificate generation.
75
+ certmaker:
76
+ # The default subject string used by the generated certificates. Note that
77
+ # the substring %HOSTNAME% will be replaced with the value of hostname.
78
+ defaultsubject: &defaultsubject "C=US, CN=%HOSTNAME%"
79
+
80
+ # The default subject string for the null in subject certificate test.
81
+ # Intended to be almost identical to the defaultsubject.
82
+ defaultsubjectwithnull: &defaultsubjectwithnull "C=US, CN=%HOSTNAME%\0.foo.com"
83
+
84
+ # a subject string, but with the the hostname's parent domain instead of its
85
+ # domain. A test that should fail.
86
+ defaultparentsubject: &defaultparentsubject "C=US, CN=%PARENTHOSTNAME%"
87
+
88
+ # The directory where pregenerated certificates should be stored.
89
+ outdir: certs
90
+
91
+ # If a serial number is not explicitly set on a certificate definition, then
92
+ # this value helps decide how the certificate factory generates the
93
+ # certificate. Possible values:
94
+ #
95
+ # * <a number> Use this predefined value as the serial number. Note that
96
+ # some SSL clients (eg, Firefox) will detect duplicate serial
97
+ # numbers during a single run of the application.
98
+ #
99
+ # * random randomly generate a serial number
100
+ missing_serial_generation: random
101
+
102
+ # customgoodca allows you to load a CA certificate and key from a file. If it
103
+ # is commented out, then CertMaker will generate a new CA every time it is
104
+ # run. If this entry exists, but the files do not exist, then the first time
105
+ # goodca is generated, it will also be copied to these file locations in
106
+ # order to reuse it in the future.
107
+ customgoodca:
108
+ # The path to the PEM encoded certificate:
109
+ certfile: ca/goodcacert.pem
110
+ # The path to the PEM encoded key:
111
+ keyfile: ca/goodcakey.pem
112
+ # Uncomment keypass and set the password only if your key needs a password.
113
+ # If there is no password, leave it commented out. Note that the copy of
114
+ # the CA that will be created in the certs directory will not have any
115
+ # password protection.
116
+ #keypass: changeme
117
+
118
+ logger:
119
+ level: INFO
120
+ file: '-'
121
+
122
+ certs:
123
+ goodca: &goodca
124
+ subject: "C=US, CN=Trusted CA"
125
+ issuer: self
126
+ not_before: now
127
+ not_after: +365
128
+ extensions:
129
+ - "keyUsage = critical, keyCertSign" # can sign certificates
130
+ - "basicConstraints = critical,CA:true"
131
+ - "subjectKeyIdentifier=hash"
132
+ - "authorityKeyIdentifier=keyid:always"
133
+ key_type: RSA
134
+ key_size: 1024
135
+ signing_alg: SHA1
136
+
137
+ unknownca: &unknownca
138
+ <<: *goodca
139
+ subject: "C=US, CN=Unknown CA"
140
+
141
+ goodintermediate: &goodintermediate
142
+ <<: *goodca
143
+ subject: "C=US, CN=Intermediate Cert"
144
+ issuer: goodca
145
+
146
+ baseline: &baseline
147
+ subject: *defaultsubject
148
+ issuer: goodca
149
+ not_before: now
150
+ not_after: +365
151
+ extensions:
152
+ - "keyUsage=digitalSignature, keyEncipherment" # can sign data and can encrypt symmetric keys
153
+ - "extendedKeyUsage=serverAuth, clientAuth" # can be used as both a www server cert and www client cert
154
+ - "authorityKeyIdentifier=keyid:always"
155
+ - "subjectKeyIdentifier=hash"
156
+ - "basicConstraints = critical,CA:FALSE"
157
+ key_type: RSA
158
+ key_size: 1024
159
+ signing_alg: SHA1
160
+
161
+ wrongcname: &wrongcname
162
+ <<: *baseline
163
+ subject: "C=US, CN=www.foo.com"
164
+
165
+ parentcname: &parentcname
166
+ <<: *baseline
167
+ subject: *defaultparentsubject
168
+
169
+ nullincname: &nullincname
170
+ <<: *baseline
171
+ subject: *defaultsubjectwithnull
172
+
173
+ baselinesubjectaltname: &baselinesubjectaltname
174
+ <<: *baseline
175
+ addextensions:
176
+ - "subjectAltName=DNS:%HOSTNAME%"
177
+
178
+ subjectaltnameonly: &subjectaltnameonly
179
+ <<: *baseline
180
+ subject: "C=US, O=My Awesome Organization"
181
+ addextensions:
182
+ - "subjectAltName=DNS:%HOSTNAME%"
183
+
184
+ wrongsubjectaltnamerightsubject: &wrongsubjectaltnamerightsubject
185
+ <<: *baseline
186
+ addextensions:
187
+ - "subjectAltName=DNS:www.foo.com"
188
+
189
+ wrongsubjectaltnamewrongsubject: &wrongsubjectaltnamewrongsubject
190
+ <<: *baseline
191
+ subject: "C=US, CN=www.foo.com"
192
+ addextensions:
193
+ - "subjectAltName=DNS:www.foo.com"
194
+
195
+ # This fails to generate as desired. the null byte truncates the
196
+ # subjectAltName somewhere within OpenSSL. We need to manually construct the
197
+ # ASN1 encoding ourselves.
198
+ # nullinsubjectaltname: &nullinsubjectaltname
199
+ # <<: *subjectaltnameonly
200
+ # addextensions:
201
+ # - "subjectAltName=DNS:%HOSTNAME%\x00.foo.com, DNS:another.com"
202
+
203
+ parentinsubjectaltname: &parentinsubjectaltname
204
+ <<: *subjectaltnameonly
205
+ addextensions:
206
+ - "subjectAltName=DNS:%PARENTHOSTNAME%"
207
+
208
+ # extended key usage specifies code signing instead of serverAuth
209
+ wrongextendedkeyusage: &wrongextendedkeyusage
210
+ <<: *baseline
211
+ blockextensions:
212
+ - extendedKeyUsage
213
+ addextensions:
214
+ - "extendedKeyUsage = codeSigning"
215
+
216
+ rightextendedkeyusagecrit: &rightextendedkeyusagecrit
217
+ <<: *baseline
218
+ blockextensions:
219
+ - extendedKeyUsage
220
+ addextensions:
221
+ - "extendedKeyUsage = critical,serverAuth"
222
+ wrongextendedkeyusagecrit: &wrongextendedkeyusagecrit
223
+ <<: *baseline
224
+ blockextensions:
225
+ - extendedKeyUsage
226
+ addextensions:
227
+ - "extendedKeyUsage = critical,codeSigning"
228
+
229
+ selfsigned: &selfsigned
230
+ <<: *baseline
231
+ issuer: self
232
+ blockextensions:
233
+ - authorityKeyIdentifier
234
+
235
+ unknowncacert: &unknowncacert
236
+ <<: *baseline
237
+ issuer: unknownca
238
+
239
+ badsignature: &badsignature
240
+ <<: *baseline
241
+ signing_key: unknownca # signing_key defaults to the issuer unless added.
242
+
243
+ # we should probably also check for bad keyUsage, since keyUsage=keyCertSign also grants CA abilities
244
+ cafalseintermediate: &cafalseintermediate
245
+ <<: *baseline
246
+ subject: "C=US, CN=Intermediate with BasicConstraints CA:FALSE"
247
+
248
+ signedbycafalseint: &signedbycafalseint
249
+ <<: *baseline
250
+ issuer: cafalseintermediate
251
+
252
+ # we should probably also check for bad keyUsage, since keyUsage=keyCertSign also grants CA abilities
253
+ nobcintermediate: &nobcintermediate
254
+ <<: *baseline
255
+ subject: "C=US, CN=Intermediate with no basicConstraints"
256
+ blockextensions:
257
+ - basicconstraints
258
+
259
+ signedbynobcint:
260
+ <<: *baseline
261
+ issuer: nobcintermediate
262
+
263
+ badsigintermediate:
264
+ <<: *goodintermediate
265
+ subject: "C=US, CN=Intermediate with bad signature"
266
+ signing_key: unknownca # signing_key defaults to the issuer unless added
267
+
268
+ signedbybadsigintermediate:
269
+ <<: *baseline
270
+ issuer: badsigintermediate
271
+
272
+ # identical to goodca, but with its own key
273
+ cawithdifferentkey:
274
+ <<: *goodca
275
+
276
+ signedbydifferentkey:
277
+ <<: *baseline
278
+ issuer: cawithdifferentkey
279
+
280
+ expiredcert:
281
+ <<: *baseline
282
+ not_before: -365
283
+ not_after: -30
284
+
285
+ notyetvalidcert:
286
+ <<: *baseline
287
+ not_before: 365
288
+ not_after: 730
289
+
290
+ expiredintermediate:
291
+ <<: *goodintermediate
292
+ subject: "C=US, CN=Expired Intermediate"
293
+ not_before: -365
294
+ not_after: -30
295
+
296
+ signedbyexpiredint:
297
+ <<: *baseline
298
+ issuer: expiredintermediate
299
+
300
+ signedwithmd5:
301
+ <<: *baseline
302
+ signing_alg: MD5
303
+
304
+ signedwithmd4:
305
+ <<: *baseline
306
+ signing_alg: MD4
307
+
308
+ expiredca: &expiredca
309
+ <<: *goodca
310
+ subject: "C=US, CN=Expired CA"
311
+ not_before: -365
312
+ not_after: -30
313
+
314
+ signedbyexpiredca:
315
+ <<: *baseline
316
+ issuer: expiredca
317
+
318
+
319
+ tests:
320
+ # baseline
321
+ - alias: baseline
322
+ name: Baseline Happy Test
323
+ certchain:
324
+ - baseline
325
+ - goodca
326
+ expected_result: connected
327
+
328
+ # cname tests
329
+ - alias: wrongcname
330
+ name: Wrong CNAME
331
+ certchain:
332
+ - wrongcname
333
+ - goodca
334
+ expected_result: rejected
335
+
336
+ # cname tests
337
+ - alias: parentcname
338
+ name: "Parent domain's CNAME"
339
+ certchain:
340
+ - parentcname
341
+ - goodca
342
+ expected_result: rejected
343
+
344
+ - alias: nullincname
345
+ name: Null character in CNAME
346
+ certchain:
347
+ - nullincname
348
+ - goodca
349
+ expected_result: rejected
350
+
351
+ # subjectAltName tests
352
+ - alias: happysubjectaltname
353
+ name: Hostname is a dnsName in subjectAltName and in subject
354
+ certchain:
355
+ - baselinesubjectaltname
356
+ - goodca
357
+ expected_result: connected
358
+
359
+ - alias: happysubjectaltnameonly
360
+ name: hostname only a dnsName subjectAltName
361
+ certchain:
362
+ - subjectaltnameonly
363
+ - goodca
364
+ expected_result: connected
365
+
366
+ - alias: wrongsubjectaltnamewrongsubject
367
+ name: hostname in neither subjectAltName nor subject
368
+ certchain:
369
+ - wrongsubjectaltnamewrongsubject
370
+ - goodca
371
+ expected_result: rejected
372
+
373
+ - alias: wrongsubjectaltnamerightsubject
374
+ name: hostname in subject but not in subjectAltName
375
+ certchain:
376
+ - wrongsubjectaltnamerightsubject
377
+ - goodca
378
+ expected_result: rejected
379
+
380
+ #- alias: nullinsubjectaltname
381
+ # name: "null byte in subjectAltName"
382
+ # certchain:
383
+ # - nullinsubjectaltname
384
+ # - goodca
385
+ # expected_result: rejected
386
+ #
387
+ - alias: parentinsubjectaltname
388
+ name: "parent domain in subjectAltName"
389
+ certchain:
390
+ - parentinsubjectaltname
391
+ - goodca
392
+ expected_result: rejected
393
+
394
+ # key usage
395
+ - alias: wrongextendedkeyusage
396
+ name: extendedKeyUsage lacks serverAuth
397
+ certchain:
398
+ - wrongextendedkeyusage
399
+ - goodca
400
+ expected_result: rejected
401
+
402
+ - alias: rightextendedkeyusagecrit
403
+ name: extendedKeyUsage lacks serverAuth
404
+ certchain:
405
+ - rightextendedkeyusagecrit
406
+ - goodca
407
+ expected_result: connected
408
+
409
+ #####################
410
+ # This one fails against Java/Android's standard SSL client code.
411
+ - alias: wrongextendedkeyusagecrit
412
+ name: extendedKeyUsage lacks serverAuth
413
+ certchain:
414
+ - wrongextendedkeyusagecrit
415
+ - goodca
416
+ expected_result: rejected
417
+ #####################
418
+
419
+ # cert chain issues
420
+ - alias: selfsigned
421
+ name: Selfsigned certificate
422
+ certchain:
423
+ - selfsigned
424
+ expected_result: rejected
425
+
426
+ - alias: unknownca
427
+ name: Signed by an untrusted CA
428
+ certchain:
429
+ - unknowncacert
430
+ - unknownca
431
+ expected_result: rejected
432
+
433
+ - alias: differentkeyca
434
+ name: Signed by an untrusted CA (provided in the chain) with the same name but a different key
435
+ certchain:
436
+ - signedbydifferentkey
437
+ - cawithdifferentkey
438
+ expected_result: rejected
439
+
440
+ - alias: badsignature
441
+ name: Bad signature
442
+ certchain:
443
+ - badsignature
444
+ - goodca
445
+ expected_result: rejected
446
+
447
+ - alias: cafalseintermediate
448
+ name: "Intermediate certificate where BasicConstraints sets CA:FALSE"
449
+ certchain:
450
+ - signedbycafalseint
451
+ - cafalseintermediate
452
+ - goodca
453
+ expected_result: rejected
454
+
455
+ - alias: nobcintermediate
456
+ name: Intermediate certificate lacks BasicConstraints
457
+ certchain:
458
+ - signedbynobcint
459
+ - nobcintermediate
460
+ - goodca
461
+ expected_result: rejected
462
+
463
+ - alias: badsigonintermediate
464
+ name: Intermediate certificate has bad signature from CA
465
+ certchain:
466
+ - signedbybadsigintermediate
467
+ - badsigintermediate
468
+ - goodca
469
+ expected_result: rejected
470
+
471
+ - alias: signedwithmd5
472
+ name: Certificate signed with MD5
473
+ certchain:
474
+ - signedwithmd5
475
+ - goodca
476
+ expected_result: rejected
477
+
478
+ - alias: signedwithmd4
479
+ name: Certificate signed with MD4
480
+ certchain:
481
+ - signedwithmd4
482
+ - goodca
483
+ expected_result: rejected
484
+
485
+ ## Need OpenSSL built with MD2 support
486
+ #- alias: signedwithmd2
487
+ # name: Certificate signed with MD2
488
+ # certchain:
489
+ # - signedwithmd2
490
+ # - goodca
491
+ # expected_result: rejected
492
+
493
+ - alias: expiredcert
494
+ name: Certificate that has expired
495
+ certchain:
496
+ - expiredcert
497
+ - goodca
498
+ expected_result: rejected
499
+
500
+ - alias: notyetvalidcert
501
+ name: Certificate that is valid in the future
502
+ certchain:
503
+ - notyetvalidcert
504
+ - goodca
505
+ expected_result: rejected
506
+
507
+ - alias: expiredintermediate
508
+ name: Certificate signed by an intermediate that has expired
509
+ certchain:
510
+ - signedbyexpiredint
511
+ - expiredintermediate
512
+ - goodca
513
+ expected_result: rejected
514
+
515
+ # This requires installing the expired CA that is also installed into the
516
+ # client's trusted root store.
517
+ #- alias: expiredca
518
+ # name: "Certificate signed by a trusted, but expired CA"
519
+ # certchain:
520
+ # - signedbyexpiredca
521
+ # - expiredca
522
+ # expected_result: rejected
523
+