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.
- data/.document +6 -0
- data/.gitignore +7 -0
- data/.rspec +1 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +41 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +231 -0
- data/Rakefile +44 -0
- data/bin/makeder.sh +6 -0
- data/bin/tlspretense +7 -0
- data/bin/view.sh +3 -0
- data/doc/general_setup.rdoc +288 -0
- data/doc/linux_setup.rdoc +64 -0
- data/lib/certmaker.rb +61 -0
- data/lib/certmaker/certificate_factory.rb +106 -0
- data/lib/certmaker/certificate_suite_generator.rb +120 -0
- data/lib/certmaker/ext_core/hash_indifferent_fetch.rb +12 -0
- data/lib/certmaker/runner.rb +27 -0
- data/lib/certmaker/tasks.rb +20 -0
- data/lib/packetthief.rb +167 -0
- data/lib/packetthief/handlers.rb +14 -0
- data/lib/packetthief/handlers/abstract_ssl_handler.rb +249 -0
- data/lib/packetthief/handlers/proxy_redirector.rb +26 -0
- data/lib/packetthief/handlers/ssl_client.rb +87 -0
- data/lib/packetthief/handlers/ssl_server.rb +174 -0
- data/lib/packetthief/handlers/ssl_smart_proxy.rb +143 -0
- data/lib/packetthief/handlers/ssl_transparent_proxy.rb +225 -0
- data/lib/packetthief/handlers/transparent_proxy.rb +183 -0
- data/lib/packetthief/impl.rb +11 -0
- data/lib/packetthief/impl/ipfw.rb +140 -0
- data/lib/packetthief/impl/manual.rb +54 -0
- data/lib/packetthief/impl/netfilter.rb +109 -0
- data/lib/packetthief/impl/pf_divert.rb +168 -0
- data/lib/packetthief/impl/pf_rdr.rb +192 -0
- data/lib/packetthief/logging.rb +49 -0
- data/lib/packetthief/redirect_rule.rb +29 -0
- data/lib/packetthief/util.rb +36 -0
- data/lib/ssl_test.rb +21 -0
- data/lib/ssl_test/app_context.rb +17 -0
- data/lib/ssl_test/certificate_manager.rb +33 -0
- data/lib/ssl_test/config.rb +79 -0
- data/lib/ssl_test/ext_core/io_raw_input.rb +31 -0
- data/lib/ssl_test/input_handler.rb +35 -0
- data/lib/ssl_test/runner.rb +110 -0
- data/lib/ssl_test/runner_options.rb +68 -0
- data/lib/ssl_test/ssl_test_case.rb +46 -0
- data/lib/ssl_test/ssl_test_report.rb +24 -0
- data/lib/ssl_test/ssl_test_result.rb +30 -0
- data/lib/ssl_test/test_listener.rb +140 -0
- data/lib/ssl_test/test_manager.rb +116 -0
- data/lib/tlspretense.rb +13 -0
- data/lib/tlspretense/app.rb +52 -0
- data/lib/tlspretense/init_runner.rb +115 -0
- data/lib/tlspretense/skel/ca/goodcacert.pem +19 -0
- data/lib/tlspretense/skel/ca/goodcakey.pem +27 -0
- data/lib/tlspretense/skel/config.yml +523 -0
- data/lib/tlspretense/version.rb +3 -0
- data/packetthief_examples/em_ssl_test.rb +73 -0
- data/packetthief_examples/redirector.rb +29 -0
- data/packetthief_examples/setup_iptables.sh +24 -0
- data/packetthief_examples/ssl_client_simple.rb +27 -0
- data/packetthief_examples/ssl_server_simple.rb +44 -0
- data/packetthief_examples/ssl_smart_proxy.rb +115 -0
- data/packetthief_examples/ssl_transparent_proxy.rb +97 -0
- data/packetthief_examples/transparent_proxy.rb +56 -0
- data/spec/packetthief/impl/ipfw_spec.rb +98 -0
- data/spec/packetthief/impl/manual_spec.rb +65 -0
- data/spec/packetthief/impl/netfilter_spec.rb +66 -0
- data/spec/packetthief/impl/pf_divert_spec.rb +82 -0
- data/spec/packetthief/impl/pf_rdr_spec.rb +133 -0
- data/spec/packetthief/logging_spec.rb +78 -0
- data/spec/packetthief_spec.rb +47 -0
- data/spec/spec_helper.rb +53 -0
- data/spec/ssl_test/certificate_manager_spec.rb +222 -0
- data/spec/ssl_test/config_spec.rb +76 -0
- data/spec/ssl_test/runner_spec.rb +360 -0
- data/spec/ssl_test/ssl_test_case_spec.rb +113 -0
- data/spec/ssl_test/test_listener_spec.rb +199 -0
- data/spec/ssl_test/test_manager_spec.rb +324 -0
- data/tlspretense.gemspec +35 -0
- 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
|
data/lib/tlspretense.rb
ADDED
@@ -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
|
+
|