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.
- 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
@@ -8,12 +8,16 @@ module TestHarness
|
|
8
8
|
@actions = {}
|
9
9
|
|
10
10
|
# Set the term to accept keystrokes immediately.
|
11
|
-
@stdin.
|
11
|
+
if @stdin.tty?
|
12
|
+
@stdin.enable_raw_chars
|
13
|
+
end
|
12
14
|
end
|
13
15
|
|
14
16
|
def unbind
|
15
17
|
# Clean up by resotring the old termios
|
16
|
-
@stdin.
|
18
|
+
if @stdin.tty?
|
19
|
+
@stdin.disable_raw_chars
|
20
|
+
end
|
17
21
|
end
|
18
22
|
|
19
23
|
# Receives one character at a time.
|
@@ -20,6 +20,7 @@ module TestHarness
|
|
20
20
|
@logger.formatter = proc do |severity, datetime, progname, msg|
|
21
21
|
"#{datetime}:#{severity}: #{msg}\n"
|
22
22
|
end
|
23
|
+
PacketThief.logger = @logger
|
23
24
|
@app_context = AppContext.new(@config, cert_manager, @logger)
|
24
25
|
|
25
26
|
@report = SSLTestReport.new
|
@@ -46,18 +47,24 @@ module TestHarness
|
|
46
47
|
stop_packetthief
|
47
48
|
|
48
49
|
@report.print_results(@stdout)
|
50
|
+
|
51
|
+
if @report.fail?
|
52
|
+
@stdout.puts 'FAIL'
|
53
|
+
else
|
54
|
+
@stdout.puts 'PASS'
|
55
|
+
end
|
56
|
+
!@report.fail?
|
49
57
|
else
|
50
58
|
raise "Unknown action: #{opts[:action]}"
|
51
59
|
end
|
52
60
|
end
|
53
61
|
|
54
62
|
def run_tests(testlist)
|
55
|
-
test_manager = TestManager.new(@app_context, testlist, @report
|
63
|
+
test_manager = TestManager.new(@app_context, testlist, @report)
|
56
64
|
EM.run do
|
57
65
|
# @listener handles the initial server socket, not the accepted connections.
|
58
66
|
# h in the code block is for each accepted connection.
|
59
67
|
@listener = TestListener.start('', @config.listener_port, test_manager)
|
60
|
-
@listener.logger = @logger
|
61
68
|
@keyboard = EM.open_keyboard InputHandler do |h|
|
62
69
|
h.on(' ') { test_manager.test_completed(test_manager.current_test, :skipped) }
|
63
70
|
h.on('q') { test_manager.stop_testing }
|
@@ -72,7 +79,6 @@ module TestHarness
|
|
72
79
|
# preconfigured destination, and external for when PT does not manage the
|
73
80
|
# firewall rules but still needs to know how to discover the destination.
|
74
81
|
def init_packetthief
|
75
|
-
PacketThief.logger = @logger
|
76
82
|
if @config.packetthief.has_key? 'implementation'
|
77
83
|
impl = @config.packetthief['implementation']
|
78
84
|
case impl
|
@@ -29,18 +29,11 @@ module TestHarness
|
|
29
29
|
@description = @raw['name']
|
30
30
|
@certchainalias = @raw['certchain']
|
31
31
|
@expected_result = @raw['expected_result']
|
32
|
-
|
33
|
-
|
34
|
-
def certchain
|
32
|
+
# ensure that the certificate exists
|
35
33
|
@certchain ||= @appctx.cert_manager.get_chain(@certchainalias)
|
36
|
-
end
|
37
|
-
|
38
|
-
def keychain
|
39
34
|
@keychain ||= @appctx.cert_manager.get_keychain(@certchainalias)
|
40
|
-
end
|
41
|
-
|
42
|
-
def hosttotest
|
43
35
|
@hosttotest ||= @appctx.config.hosttotest
|
36
|
+
nil
|
44
37
|
end
|
45
38
|
|
46
39
|
end
|
@@ -25,7 +25,7 @@ module TestHarness
|
|
25
25
|
# present when the client attempts to connect to hostname.
|
26
26
|
# * _keytotest_ [OpenSSL::PKey::PKey] The key corresponding to the leaf
|
27
27
|
# node in _chaintotest_.
|
28
|
-
def initialize(tcpsocket, test_manager
|
28
|
+
def initialize(tcpsocket, test_manager)
|
29
29
|
@test_manager = test_manager
|
30
30
|
|
31
31
|
if @test_manager.paused?
|
@@ -40,7 +40,7 @@ module TestHarness
|
|
40
40
|
@extrachain = chain
|
41
41
|
end
|
42
42
|
# Use the goodca for hosts we don't care to test against.
|
43
|
-
super(tcpsocket, @test_manager.goodcacert, @test_manager.goodcakey
|
43
|
+
super(tcpsocket, @test_manager.goodcacert, @test_manager.goodcakey)
|
44
44
|
|
45
45
|
@test_status = :running
|
46
46
|
@testing_host = false
|
@@ -12,11 +12,10 @@ module TestHarness
|
|
12
12
|
attr_accessor :goodcacert
|
13
13
|
attr_accessor :goodcakey
|
14
14
|
|
15
|
-
def initialize(context, testlist, report
|
15
|
+
def initialize(context, testlist, report)
|
16
16
|
@appctx = context
|
17
17
|
@testlist = testlist
|
18
18
|
@report = report
|
19
|
-
@logger = logger
|
20
19
|
@remaining_tests = @testlist.dup
|
21
20
|
|
22
21
|
@goodcacert = @appctx.cert_manager.get_cert("goodca")
|
data/lib/tlspretense/version.rb
CHANGED
@@ -11,6 +11,13 @@ require 'rubygems'
|
|
11
11
|
require 'eventmachine'
|
12
12
|
require 'packetthief' # needs root
|
13
13
|
|
14
|
+
Signal.trap('ABRT') do
|
15
|
+
puts 'catching abort'
|
16
|
+
end
|
17
|
+
|
18
|
+
log = Logger.new(STDOUT)
|
19
|
+
log.level = Logger::DEBUG
|
20
|
+
PacketThief.logger = log
|
14
21
|
|
15
22
|
EM.run do
|
16
23
|
|
@@ -77,7 +77,8 @@ module Impl
|
|
77
77
|
context "when passed an object that implements Socket's #getsockname" do
|
78
78
|
it "returns the destination socket's details" do
|
79
79
|
@socket = double("socket")
|
80
|
-
@socket.stub(:getsockname).and_return("\020\002?2\ne`a\000\000\000\000\000\000\000\000")
|
80
|
+
# @socket.stub(:getsockname).and_return("\020\002?2\ne`a\000\000\000\000\000\000\000\000")
|
81
|
+
@socket.stub(:getsockname).and_return(Socket.pack_sockaddr_in(16178, "10.101.96.97"))
|
81
82
|
|
82
83
|
Ipfw.original_dest(@socket).should == [16178, "10.101.96.97"]
|
83
84
|
end
|
@@ -86,7 +87,8 @@ module Impl
|
|
86
87
|
context "when passed an object that implements EM::Connection's #getsockname" do
|
87
88
|
it "returns the destination connection's details" do
|
88
89
|
@socket = double("EM::Connection")
|
89
|
-
@socket.stub(:get_sockname).and_return("\020\002?2\ne`a\000\000\000\000\000\000\000\000")
|
90
|
+
# @socket.stub(:get_sockname).and_return("\020\002?2\ne`a\000\000\000\000\000\000\000\000")
|
91
|
+
@socket.stub(:get_sockname).and_return(Socket.pack_sockaddr_in(16178, "10.101.96.97"))
|
90
92
|
|
91
93
|
Ipfw.original_dest(@socket).should == [16178, "10.101.96.97"]
|
92
94
|
end
|
@@ -44,7 +44,8 @@ module Impl
|
|
44
44
|
context "when passed an object that implements Socket's #getsockopt" do
|
45
45
|
it "returns the destination socket's details" do
|
46
46
|
@socket = double("socket")
|
47
|
-
@socket.should_receive(:getsockopt).with(Socket::IPPROTO_IP, Netfilter::SO_ORIGINAL_DST).and_return("\020\002?2\ne`a\000\000\000\000\000\000\000\000")
|
47
|
+
# @socket.should_receive(:getsockopt).with(Socket::IPPROTO_IP, Netfilter::SO_ORIGINAL_DST).and_return("\020\002?2\ne`a\000\000\000\000\000\000\000\000")
|
48
|
+
@socket.should_receive(:getsockopt).with(Socket::IPPROTO_IP, Netfilter::SO_ORIGINAL_DST).and_return(Socket.pack_sockaddr_in(16178, "10.101.96.97"))
|
48
49
|
|
49
50
|
Netfilter.original_dest(@socket).should == [16178, "10.101.96.97"]
|
50
51
|
end
|
@@ -53,7 +54,8 @@ module Impl
|
|
53
54
|
context "when passed an object that implements EM::Connection's #get_sock_opt" do
|
54
55
|
it "returns the destination connection's details" do
|
55
56
|
@socket = double("EM::Connection")
|
56
|
-
@socket.should_receive(:get_sock_opt).with(Socket::IPPROTO_IP, Netfilter::SO_ORIGINAL_DST).and_return("\020\002?2\ne`a\000\000\000\000\000\000\000\000")
|
57
|
+
# @socket.should_receive(:get_sock_opt).with(Socket::IPPROTO_IP, Netfilter::SO_ORIGINAL_DST).and_return("\020\002?2\ne`a\000\000\000\000\000\000\000\000")
|
58
|
+
@socket.should_receive(:get_sock_opt).with(Socket::IPPROTO_IP, Netfilter::SO_ORIGINAL_DST).and_return(Socket.pack_sockaddr_in(16178, "10.101.96.97"))
|
57
59
|
|
58
60
|
Netfilter.original_dest(@socket).should == [16178, "10.101.96.97"]
|
59
61
|
end
|
@@ -61,7 +61,8 @@ module Impl
|
|
61
61
|
context "when passed an object that implements Socket's #getsockname" do
|
62
62
|
it "returns the destination socket's details" do
|
63
63
|
@socket = double("socket")
|
64
|
-
@socket.stub(:getsockname).and_return("\020\002?2\ne`a\000\000\000\000\000\000\000\000")
|
64
|
+
# @socket.stub(:getsockname).and_return("\020\002?2\ne`a\000\000\000\000\000\000\000\000")
|
65
|
+
@socket.stub(:getsockname).and_return(Socket.pack_sockaddr_in(16178, "10.101.96.97"))
|
65
66
|
|
66
67
|
subject.original_dest(@socket).should == [16178, "10.101.96.97"]
|
67
68
|
end
|
@@ -70,7 +71,8 @@ module Impl
|
|
70
71
|
context "when passed an object that implements EM::Connection's #getsockname" do
|
71
72
|
it "returns the destination connection's details" do
|
72
73
|
@socket = double("EM::Connection")
|
73
|
-
@socket.stub(:get_sockname).and_return("\020\002?2\ne`a\000\000\000\000\000\000\000\000")
|
74
|
+
# @socket.stub(:get_sockname).and_return("\020\002?2\ne`a\000\000\000\000\000\000\000\000")
|
75
|
+
@socket.stub(:get_sockname).and_return(Socket.pack_sockaddr_in(16178, "10.101.96.97"))
|
74
76
|
|
75
77
|
subject.original_dest(@socket).should == [16178, "10.101.96.97"]
|
76
78
|
end
|
@@ -6,37 +6,39 @@ module PacketThief
|
|
6
6
|
include Logging
|
7
7
|
end
|
8
8
|
|
9
|
-
subject { LoggingObj.new }
|
10
|
-
|
11
9
|
let(:logger) { Logger.new(nil) }
|
10
|
+
before(:each) { Logging.logger = logger }
|
12
11
|
|
13
|
-
|
14
|
-
|
15
|
-
end
|
12
|
+
describe "an object that has included PacketThief::Logging" do
|
13
|
+
subject { LoggingObj.new }
|
16
14
|
|
17
|
-
|
18
|
-
|
15
|
+
it "does not expose its log methods" do
|
16
|
+
expect { subject.logdebug("some message") }.to raise_error NoMethodError
|
17
|
+
end
|
19
18
|
|
20
|
-
|
21
|
-
|
19
|
+
context "when Logging.logger is unset" do
|
20
|
+
before(:each) { Logging.logger = nil }
|
22
21
|
|
23
|
-
|
24
|
-
|
22
|
+
it { expect { subject.send(:logdebug, "some message")}.to_not raise_error }
|
23
|
+
end
|
25
24
|
|
26
|
-
|
27
|
-
logger.should_receive(:log).with(Logger::DEBUG, subject.class.to_s + ": hello world!")
|
25
|
+
context "when Logging.logger is set" do
|
28
26
|
|
29
|
-
|
30
|
-
|
31
|
-
it "prints an optional argument to the logger" do
|
32
|
-
logger.should_receive(:log).with(Logger::DEBUG, subject.class.to_s + ": a message: data: 12345")
|
27
|
+
it "sends a message with the classname to the logger" do
|
28
|
+
logger.should_receive(:log).with(Logger::DEBUG, subject.class.to_s + ": hello world!")
|
33
29
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
30
|
+
subject.send(:logdebug, 'hello world!')
|
31
|
+
end
|
32
|
+
it "prints an optional argument to the logger" do
|
33
|
+
logger.should_receive(:log).with(Logger::DEBUG, subject.class.to_s + ": a message: data: 12345")
|
34
|
+
|
35
|
+
subject.send(:logdebug, 'a message', :data => 12345)
|
36
|
+
end
|
37
|
+
it "prints multiple optional arguments to the logger in sorted order" do
|
38
|
+
logger.should_receive(:log).with(Logger::DEBUG, /#{subject.class.to_s}: a message: astring: ['"]inspect this['"], data: 12345/)
|
38
39
|
|
39
|
-
|
40
|
+
subject.send(:logdebug, 'a message', :data => 12345, :astring => "inspect this")
|
41
|
+
end
|
40
42
|
end
|
41
43
|
end
|
42
44
|
|
@@ -49,8 +51,6 @@ module PacketThief
|
|
49
51
|
|
50
52
|
subject { ClassToTest }
|
51
53
|
|
52
|
-
before(:each) { subject.logger = logger }
|
53
|
-
|
54
54
|
it "sets component to the class name" do
|
55
55
|
logger.should_receive(:log).with(Logger::DEBUG, "#{subject.name}: a message")
|
56
56
|
|
@@ -66,8 +66,6 @@ module PacketThief
|
|
66
66
|
|
67
67
|
subject { ModToTest }
|
68
68
|
|
69
|
-
before(:each) { subject.logger = logger }
|
70
|
-
|
71
69
|
it "sets component to the module name" do
|
72
70
|
logger.should_receive(:log).with(Logger::DEBUG, "#{subject.name}: a message")
|
73
71
|
|
data/spec/spec_helper.rb
CHANGED
@@ -17,15 +17,14 @@ require 'tlspretense'
|
|
17
17
|
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
18
18
|
|
19
19
|
RSpec.configure do |config|
|
20
|
-
config.
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
]
|
27
|
-
|
20
|
+
config.expect_with :rspec do |expectations|
|
21
|
+
expectations.syntax = [:should, :expect]
|
22
|
+
end
|
23
|
+
config.mock_with :rspec do |mocks|
|
24
|
+
mocks.syntax = :should
|
25
|
+
end
|
28
26
|
end
|
27
|
+
RSpec::Expectations.configuration.on_potential_false_positives = :nothing
|
29
28
|
|
30
29
|
def with_constants(constants, &block)
|
31
30
|
saved_constants = {}
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__),'..','..','spec_helper'))
|
2
|
+
|
3
|
+
module TLSPretense
|
4
|
+
module CertMaker
|
5
|
+
describe SubjectAltNameFactory do
|
6
|
+
|
7
|
+
describe "the created extension" do
|
8
|
+
subject { SubjectAltNameFactory.new.create_san_with_dns(arg) }
|
9
|
+
|
10
|
+
context "when created with www.isecpartners.com" do
|
11
|
+
let(:arg) { 'www.isecpartners.com' }
|
12
|
+
it "is a subjectAltName Extension" do
|
13
|
+
subject.oid.should == 'subjectAltName'
|
14
|
+
end
|
15
|
+
it "its der encoding contains www.isecpartners.com" do
|
16
|
+
subject.to_der.should match /www\.isecpartners\.com/
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'when passed "www.isecpartners.com\0foo.com"' do
|
21
|
+
let(:arg) { "www.isecpartners.com\0foo.com" }
|
22
|
+
it 'its der encoding contains www.isecpartners.com\0foo.com' do
|
23
|
+
subject.to_der.should match /www\.isecpartners\.com\0foo\.com/
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "the created extension" do
|
29
|
+
subject { SubjectAltNameFactory.new.create_san_ext(arg) }
|
30
|
+
|
31
|
+
context 'when the descriptor is "subjectAltName=DNS:www.isecpartners.com"' do
|
32
|
+
let(:arg) { "subjectAltName=DNS:www.isecpartners.com" }
|
33
|
+
it "the oid is 'subjectAltName'" do
|
34
|
+
subject.oid.should == 'subjectAltName'
|
35
|
+
end
|
36
|
+
it "the der encoding contains www.isecpartners.com" do
|
37
|
+
subject.to_der.should match /www\.isecpartners\.com/
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'when the descriptor is "subjectAltName=DNS:www.isecpartners.com, DNS:foo.com"' do
|
42
|
+
let(:arg) { "subjectAltName=DNS:www.isecpartners.com, DNS:foo.com" }
|
43
|
+
it "the der encoding contains www.isecpartners.com" do
|
44
|
+
subject.to_der.should match /www\.isecpartners\.com/
|
45
|
+
end
|
46
|
+
it "the der encoding contains foo.com" do
|
47
|
+
subject.to_der.should match /foo\.com/
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'when the descriptor is "subjectAltName=DNS:www.isecpartners.com\0foo.com, DNS:bar.com"' do
|
52
|
+
let(:arg) { "subjectAltName=DNS:www.isecpartners.com\0foo.com, DNS:bar.com" }
|
53
|
+
it 'the der encoding contains www.isecpartners.com\0foo.com' do
|
54
|
+
subject.to_der.should match /www\.isecpartners\.com\0foo\.com/
|
55
|
+
end
|
56
|
+
it "the der encoding contains bar.com" do
|
57
|
+
subject.to_der.should match /bar\.com/
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'when the descriptor is "subjectAltName=DNS:www.isecpartners.com\0.foo.com, DNS:bar.com\0.foo.com"' do
|
62
|
+
let(:arg) { "subjectAltName=DNS:www.isecpartners.com\0.foo.com, DNS:bar.com\0.foo.com" }
|
63
|
+
it 'the der encoding contains www.isecpartners.com\0.foo.com' do
|
64
|
+
subject.to_der.should match /www\.isecpartners\.com\0\.foo\.com/
|
65
|
+
end
|
66
|
+
it "the der encoding contains bar.com\0.foo.com" do
|
67
|
+
subject.to_der.should match /bar\.com\0\.foo\.com/
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__),'..','..','spec_helper'))
|
2
|
+
require 'tlspretense/ext_compat/openssl_pkey_read'
|
3
|
+
|
4
|
+
module TLSPretense
|
5
|
+
module ExtCompat
|
6
|
+
describe OpenSSLPKeyRead do
|
7
|
+
subject { a = Object.new ; a.extend(OpenSSLPKeyRead) ; a }
|
8
|
+
|
9
|
+
describe "#read" do
|
10
|
+
context "when given a PEM-encoded RSA key" do
|
11
|
+
let(:pkey) do (<<-QUOTE).gsub(/^\s*/,'')
|
12
|
+
-----BEGIN RSA PRIVATE KEY-----
|
13
|
+
MIIEpAIBAAKCAQEAzRehpS5qO9LuW2dqm/Pc2YyPTOE3LMzoZSukguefwFuZqi8K
|
14
|
+
VWpn+4Tk5xACaZYnAKMQEHb3F9aC4REU3p3L6WiuEmarxvnfxAFahEIlsmJSSiE6
|
15
|
+
TaAxg3mXL3C5QiQxK/N9zjPGXW8QPlCCCs7CKQQ4RIQTIkoOn4OvSDbpRWrPZ1H4
|
16
|
+
ZBiCrAfqDQOSqzmHMTchUfhvezSWwDcFUQCfYGBdBkjzFEcrtEG6lFjx3aVHZfZm
|
17
|
+
uTKfki0fCEQCRsSd2l+/ZFJHIIphL0M2L/6VvCCDiaziHMwxVitnsQ5JURvje7QR
|
18
|
+
AXTKjArIgUl9h/IdfrIT9pbLKDNsDQMx2txfkQIDAQABAoIBAQC49fbx4Uotaa1N
|
19
|
+
AZdDzkn+aKVT0EjSPnnXw+Q5qmqIMBQFRycqoSvlyZQmTmnej2vdRzHVp3RwKyUd
|
20
|
+
lSodGnIrrhxOvAlvCSqkuhPH81/L4KAV+qF6IF6HE8ElJ6Pr4nf2C0IKFOdwnBkq
|
21
|
+
GbEtzgmMtCGKqRIYenF1qm0J03vM/Ugn3Xvq9qIUJjLEoX32z0m1x3+QQKmG4k2U
|
22
|
+
AZK2Ngs3J3dHNmCjAOzWhJ7yeIEiPPAznP6MV9JCvv3+dAZGMZmQUbNkrXuEy+LG
|
23
|
+
tQh7C5GMSj1wrB3q7o+1V2MGdZUu8uNkxaPlCnc3MnjbCHw3WydAJHW1lgurqlv5
|
24
|
+
cwDd2BgBAoGBAPh4IdffVxlIRx2CR7++9O1D2UED+zXJjMFHok3sPhrONb/qOzaQ
|
25
|
+
ectQFxzznObz4zUEnb9TLCVhkfMyFQ3L/CabLHPa21+ucMigObk8HdZ7nPtf7Xo0
|
26
|
+
v54vISFhH7rlpBi73fOf69+bzd7ECEPOvfI639ltfJRv8LgSW6GdoaR5AoGBANNO
|
27
|
+
8DbvicZ7+Qq6U05QJLhl4HyLziCS+Rr0Arz5KnbKxjPYoiV3Ujpzec3DAazTCRho
|
28
|
+
OCRgzNMO2dEQCp7ZEYK+HK/J6UA2DYExYHcPyfYskrxwQVo5N20oiLa6jLisk5Jf
|
29
|
+
vsq6Lbuq5PgYcykXfcX3ZnB6XAt32nC9dzcu2F3ZAoGAbYa/HGKWCU4EEyzvpcVu
|
30
|
+
P/yNkwxHOzGKO1TxZboCslw980g0K9xJ4+Z9GcUFYAUYHbHYO5NVPXEiHfrwrvFB
|
31
|
+
SF9UnAlYdHf3vWhrqYyndnls/J4Pl7QS147c4tLmYsOBr2l48ECJgDs058KwBfvn
|
32
|
+
XRS4wiZyKRijGvD0tWw/6bkCgYEAv1crjZM6XtDDokM2TCOmHJOjwyOVc0mi6BUs
|
33
|
+
pZG6MfdLoob3zJVPkD4gfYGncqdmBQPaUpaU4kkAU58C/vPwN0OPFl7vJ4XKlMHx
|
34
|
+
Z96UMqYJ+Ths9RX6ao3Zvh0Ob+tVdaXdThVodBc7XqxFG2B6M1jjGdayom/VDWGD
|
35
|
+
IiT5J4ECgYBhEHnaEepaK+Z++yMdGD4oZCtrKkY+2FiR3yK4scldzkKp+FLLBSD0
|
36
|
+
nD0rF9hlhvpzlWa8HASrHHt2IB+rhKkljNpBuHSk1pK1q2KVYLCePOIunai9O/Mo
|
37
|
+
JWJnWLSeS/Fd3rXB9jnNhiudElJRXzkof0jKSm0xnDbxWvWztBUnkA==
|
38
|
+
-----END RSA PRIVATE KEY-----
|
39
|
+
QUOTE
|
40
|
+
end
|
41
|
+
|
42
|
+
it "returns an RSA key" do
|
43
|
+
subject.read(pkey).should be_a OpenSSL::PKey::RSA
|
44
|
+
end
|
45
|
+
end
|
46
|
+
context "when given a PEM-encoded DSA key" do
|
47
|
+
let(:pkey) do (<<-QUOTE).gsub(/^\s*/,'')
|
48
|
+
-----BEGIN DSA PRIVATE KEY-----
|
49
|
+
MIIDVgIBAAKCAQEA1nTwWYrSmUNZalLgB7hW5F/K7GLpc+8GyNJ+F7XVY6lbrKlY
|
50
|
+
4xylX/kOUHvYgq/3C4Mn0lkME7lrvLKkh7rPybCNe1p40olQXB9JPfYc6QiiGLGL
|
51
|
+
WlbD1K4MNf1kftpBFB6x/Rs76NE6f8C3Wopp0TnbQhmlZskKo41mD+/MQl0j+d2w
|
52
|
+
fKsbLAo+kkW/znMqC2PLWNlOFE3bFrRzGQkU1Bu8HrBYrJT35bCtqbSJoyBkHPgI
|
53
|
+
SkYYdn/OuOD8swPO8xlgTxHBIZpwjqkyF3bzkroYOsCyAodu+xqHuTVzn+n/FWpf
|
54
|
+
vR3Lx5GRxBdEBqotpfxNBfF11B0fRWsAMUSQJQIhAO8V8dLdD/SYRsKUKUHD8eGC
|
55
|
+
ex6/ado7HluBizTjMI/NAoIBAC79cQQwFXb+ODfXTdG5QVYa9Q7fQ9oQZ1yDO1ab
|
56
|
+
eZu+awH2E5/PbwVqJEBVOWCF7Suq3CXGrINaInu4zsM6Seo/V61hBTZpWkdt+Xr4
|
57
|
+
ILlqQIw0UwaAwtE7Ynymk8Vx9MTFfekChi+Xu/4ReUDqRGKxzO89biZbd9XTOUVb
|
58
|
+
W4T4nNE/ONQJ4CKa10E+g7w9Af4quV88JDVfwaTKhC9N5It8N52Pze8cxDYKQPFs
|
59
|
+
5LUCjtfACxK6YBplkeF0nWdRkIz97dhMQgvfF70YKPikX5JymLbxLiBqUZkWc3Jv
|
60
|
+
JzqOyvn08imGBZJmf6dEYhHDChKJ4OVALL4MpeStLQ01U5MCggEBALwAH7EnbbC/
|
61
|
+
G2GziHq0XvhfmDQKCYBcAO5Mmwl7qsyMeECQ639MKcNJmX9rmC4JFC/TB4TQA80d
|
62
|
+
YEwbFwlYJkUbJyM20oh7NMP0bsrn0Jzt8nYosRRfVZKman7tIE24QnVnZuEwOTQY
|
63
|
+
0C4QLoq+m4jUumm6QsqclipuMzVUH1n0ngJYbx9nyvDU4nxd6j4MfmqHrQRUXIPH
|
64
|
+
5namqyq/xELwpRy0i5kOh5Hs/KuyrMSesRzYcty8NwcYOcM1/whspsYAdX/psDjG
|
65
|
+
FNdknGUPM5ioDR2in6CA5z6iPDEAuFFQIUHt34Ujv+F4FNFXqnfiCa95BrjaCKNd
|
66
|
+
3bRVzJDprc4CICImpd+oInjzy7PeCkbpUxwa4P3A4fHhRp0arIbId6jj
|
67
|
+
-----END DSA PRIVATE KEY-----
|
68
|
+
QUOTE
|
69
|
+
end
|
70
|
+
|
71
|
+
it "returns a DSA key" do
|
72
|
+
subject.read(pkey).should be_a OpenSSL::PKey::DSA
|
73
|
+
end
|
74
|
+
end
|
75
|
+
context "when given a PEM-encoded EC key" do
|
76
|
+
|
77
|
+
let(:pkey) do (<<-QUOTE).gsub(/^\s*/,'')
|
78
|
+
-----BEGIN EC PRIVATE KEY-----
|
79
|
+
MF8CAQEEGFpS6x8iOTNWBDNTO9nrqvyQjUvoaO7uaqAKBggqhkjOPQMBAaE0AzIA
|
80
|
+
BLOLCjnMg4a1++NZS5/XTeT2vv8JEANpctfJMjsoG12Uv7fwe8lldQwFFl0XQQZk
|
81
|
+
kg==
|
82
|
+
-----END EC PRIVATE KEY-----
|
83
|
+
QUOTE
|
84
|
+
end
|
85
|
+
|
86
|
+
it "returns an EC key" do
|
87
|
+
subject.read(pkey).should be_a OpenSSL::PKey::EC
|
88
|
+
end
|
89
|
+
end
|
90
|
+
context "when given a PEM-encoded ENCRYPTED key" do
|
91
|
+
let(:pkey) do (<<-QUOTE).gsub(/^\s*/,'')
|
92
|
+
-----BEGIN ENCRYPTED PRIVATE KEY-----
|
93
|
+
MIICzzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQIBjDVSsSRDgwCAggA
|
94
|
+
MB0GCWCGSAFlAwQBAgQQp6si6kZjtBV0mh+IfcThUQSCAoB6djj/BwG1lHkYw9o1
|
95
|
+
AS4pDo+wF3VCDca26OCrMRK41lxsQ52Kdg1mDgkuLdBeAxx3uyuD4ZoytWhgv+st
|
96
|
+
oLPypCl85xA7yvYsw3UiR4HaS27KiLIsLu4ex2bkS+wOLOw4t9tjPHLvmZJgVneA
|
97
|
+
QFFdRH03woJfQaMHueseI6ok+p58Qs8xNbUetPJC47kwNtzD4tirrbGIsSPC0Mw9
|
98
|
+
THsP/UPMYYbfgBi9hOzoznzpDie7Siv/VM5UCFHJuA9JKisliX8Gc9elmZMc5iD8
|
99
|
+
QUo5XfquJCTGgdKpz3dLHsHK85kfXX+CpYzDLshIM8Qucf2Zx+fsW5h/1VrAR+H7
|
100
|
+
Oft7zeyP01fGxwi1jVXdLpi5emvd1/tVUF/wasXisvQRsicNxE2nmPVrdFYRCisp
|
101
|
+
6hIAqgkMUMbz5LGwGSfCqVLLezsC20lk4oVhszG+Jyx64bx5pUVupkuTghm8wZgJ
|
102
|
+
ZnLKQIz+Bge+ZbNk3TzN1Z4O/Lpfs0wKbUaI+/glM10zl6s/tG0F+kNDRCp1xhWy
|
103
|
+
m1Dq6AE9H+Q8BBYrwR//p9vP6xvFXo3Ie5b3zx1am2WWmgQqlnI4C+W1ThUdf68+
|
104
|
+
eh1Qc/P8c5xwfS15kATbZT6lL6eBzkEFJYEN/5b1y2Bipsqn1Rjpcvu9VUOmFKyo
|
105
|
+
AsFK2e6QvvhCngRxgLT1O4kNlDACJx65e20qMFXMLWqdXGOzy7VXattEzSs4sV7W
|
106
|
+
3c/u+bv0rqaIYn+JcZ9hqukH3i3eyKLHfmbYxERUgQIh6cZjds+46sODsi/7J3R4
|
107
|
+
ytZbBGZPeoS23Go6cfA2NEdN4hPH9k2CM0hol4W4ztWmPNoLmkhlFEhZHrdVoMR0
|
108
|
+
Tw07
|
109
|
+
-----END ENCRYPTED PRIVATE KEY-----
|
110
|
+
QUOTE
|
111
|
+
end
|
112
|
+
context "when given the right password" do
|
113
|
+
it "decrypts the key" do
|
114
|
+
subject.read(pkey, 'hello').should be_a OpenSSL::PKey::RSA
|
115
|
+
end
|
116
|
+
end
|
117
|
+
context "when given the wrong password" do
|
118
|
+
it "raises a generic error" do
|
119
|
+
expect { subject.read(pkey, 'hell') }.to raise_error
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|