tlspretense 0.6.2 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/.travis.yml +5 -0
- data/README.rdoc +25 -16
- data/Rakefile +1 -4
- data/doc/general_setup.rdoc +22 -1
- data/doc/macosx_setup.rdoc +86 -0
- data/lib/packetthief.rb +8 -1
- data/lib/packetthief/handlers/abstract_ssl_handler.rb +1 -2
- data/lib/packetthief/handlers/ssl_server.rb +3 -4
- data/lib/packetthief/handlers/ssl_smart_proxy.rb +3 -3
- data/lib/packetthief/handlers/ssl_transparent_proxy.rb +1 -1
- data/lib/packetthief/handlers/transparent_proxy.rb +1 -2
- data/lib/packetthief/logging.rb +32 -24
- data/lib/tlspretense/app.rb +5 -2
- data/lib/tlspretense/cert_maker.rb +5 -0
- data/lib/tlspretense/cert_maker/certificate_factory.rb +11 -1
- data/lib/tlspretense/cert_maker/certificate_suite_generator.rb +21 -3
- data/lib/tlspretense/cert_maker/subject_alt_name_factory.rb +115 -0
- data/lib/tlspretense/ext_compat/openssl_pkey_read.rb +38 -0
- data/lib/tlspretense/skel/config.yml +194 -17
- data/lib/tlspretense/test_harness/input_handler.rb +6 -2
- data/lib/tlspretense/test_harness/runner.rb +9 -3
- data/lib/tlspretense/test_harness/ssl_test_case.rb +2 -9
- data/lib/tlspretense/test_harness/ssl_test_report.rb +3 -0
- data/lib/tlspretense/test_harness/test_listener.rb +2 -2
- data/lib/tlspretense/test_harness/test_manager.rb +1 -2
- data/lib/tlspretense/version.rb +1 -1
- data/packetthief_examples/ssl_client_simple.rb +7 -0
- data/spec/packetthief/impl/ipfw_spec.rb +4 -2
- data/spec/packetthief/impl/netfilter_spec.rb +4 -2
- data/spec/packetthief/impl/pf_divert_spec.rb +4 -2
- data/spec/packetthief/logging_spec.rb +24 -26
- data/spec/spec_helper.rb +7 -8
- data/spec/tlspretense/cert_maker/subject_alt_name_factory_spec.rb +75 -0
- data/spec/tlspretense/ext_compat/openssl_pkey_read_spec.rb +126 -0
- data/spec/tlspretense/test_harness/runner_spec.rb +3 -5
- data/tlspretense.gemspec +2 -2
- metadata +41 -48
- data/Gemfile.lock +0 -41
@@ -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
|