summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChikanaga Tomoyuki <nagachika00@gmail.com>2012-09-05 01:54:31 +0900
committerChikanaga Tomoyuki <nagachika00@gmail.com>2012-09-05 01:54:31 +0900
commit5917c90e3d8dcd04f7f1401fac3b54dd9e857331 (patch)
tree8cdeacc8bdf087f485e8781b8b5fb102e61324ff
parentcfecf2bc74521d52de57dbc453cde70d266c2fd6 (diff)
downloadnet-ssh-5917c90e3d8dcd04f7f1401fac3b54dd9e857331.tar.gz
Use OpenSSL::PKey.read to read arbitrary private key from DER-/PEM-encoded file.
OpenSSL::PKey.read was introduced from 1.9.3. This helps to load private keys generated by `openssl req -newkey` command.
-rw-r--r--lib/net/ssh/key_factory.rb35
-rw-r--r--test/test_key_factory.rb56
2 files changed, 78 insertions, 13 deletions
diff --git a/lib/net/ssh/key_factory.rb b/lib/net/ssh/key_factory.rb
index 2072188..b4b696c 100644
--- a/lib/net/ssh/key_factory.rb
+++ b/lib/net/ssh/key_factory.rb
@@ -48,24 +48,37 @@ module Net; module SSH
# encrypted (requiring a passphrase to use), the user will be
# prompted to enter their password unless passphrase works.
def load_data_private_key(data, passphrase=nil, ask_passphrase=true, filename="")
- if data.match(/-----BEGIN DSA PRIVATE KEY-----/)
- key_type = OpenSSL::PKey::DSA
- elsif data.match(/-----BEGIN RSA PRIVATE KEY-----/)
- key_type = OpenSSL::PKey::RSA
- elsif data.match(/-----BEGIN EC PRIVATE KEY-----/) && defined?(OpenSSL::PKey::EC)
- key_type = OpenSSL::PKey::EC
- elsif data.match(/-----BEGIN (.*) PRIVATE KEY-----/)
- raise OpenSSL::PKey::PKeyError, "not a supported key type '#{$1}'"
+ if OpenSSL::PKey.respond_to?(:read)
+ pkey_read = true
+ error_class = ArgumentError
else
- raise OpenSSL::PKey::PKeyError, "not a private key (#{filename})"
+ pkey_read = false
+ if data.match(/-----BEGIN DSA PRIVATE KEY-----/)
+ key_type = OpenSSL::PKey::DSA
+ error_class = OpenSSL::PKey::DSAError
+ elsif data.match(/-----BEGIN RSA PRIVATE KEY-----/)
+ key_type = OpenSSL::PKey::RSA
+ error_class = OpenSSL::PKey::RSAError
+ elsif data.match(/-----BEGIN EC PRIVATE KEY-----/) && defined?(OpenSSL::PKey::EC)
+ key_type = OpenSSL::PKey::EC
+ error_class = OpenSSL::PKey::RCError
+ elsif data.match(/-----BEGIN (.+) PRIVATE KEY-----/)
+ raise OpenSSL::PKey::PKeyError, "not a supported key type '#{$1}'"
+ else
+ raise OpenSSL::PKey::PKeyError, "not a private key (#{filename})"
+ end
end
encrypted_key = data.match(/ENCRYPTED/)
tries = 0
begin
- return key_type.new(data, passphrase || 'invalid')
- rescue OpenSSL::PKey::RSAError, OpenSSL::PKey::DSAError, OpenSSL::PKey::ECError => e
+ if pkey_read
+ return OpenSSL::PKey.read(data, passphrase || 'invalid')
+ else
+ return key_type.new(data, passphrase || 'invalid')
+ end
+ rescue error_class
if encrypted_key && ask_passphrase
tries += 1
if tries <= 3
diff --git a/test/test_key_factory.rb b/test/test_key_factory.rb
index aac00fd..d5c6416 100644
--- a/test/test_key_factory.rb
+++ b/test/test_key_factory.rb
@@ -41,13 +41,23 @@ class TestKeyFactory < Test::Unit::TestCase
def test_load_encrypted_private_key_should_give_three_tries_for_the_password_and_then_raise_exception
File.expects(:read).with(@key_file).returns(encrypted(rsa_key, "password"))
Net::SSH::KeyFactory.expects(:prompt).times(3).with("Enter passphrase for #{@key_file}:", false).returns("passwod","passphrase","passwd")
- assert_raises(OpenSSL::PKey::RSAError) { Net::SSH::KeyFactory.load_private_key(@key_file) }
+ if OpenSSL::PKey.respond_to?(:read)
+ error_class = ArgumentError
+ else
+ error_class = OpenSSL::PKey::RSAError
+ end
+ assert_raises(error_class) { Net::SSH::KeyFactory.load_private_key(@key_file) }
end
def test_load_encrypted_private_key_should_raise_exception_without_asking_passphrase
File.expects(:read).with(@key_file).returns(encrypted(rsa_key, "password"))
Net::SSH::KeyFactory.expects(:prompt).never
- assert_raises(OpenSSL::PKey::RSAError) { Net::SSH::KeyFactory.load_private_key(@key_file, nil, false) }
+ if OpenSSL::PKey.respond_to?(:read)
+ error_class = ArgumentError
+ else
+ error_class = OpenSSL::PKey::RSAError
+ end
+ assert_raises(error_class) { Net::SSH::KeyFactory.load_private_key(@key_file, nil, false) }
end
def test_load_public_rsa_key_should_return_key
@@ -83,6 +93,15 @@ class TestKeyFactory < Test::Unit::TestCase
end
end
+ def test_load_anonymous_private_key_should_return_key_or_raise_exception
+ File.expects(:read).with(@key_file).returns(anonymous_private_key)
+ if OpenSSL::PKey.respond_to?(:read)
+ assert_equal OpenSSL::PKey::RSA.new(anonymous_private_key).to_der, Net::SSH::KeyFactory.load_private_key(@key_file).to_der
+ else
+ assert_raises(OpenSSL::PKey::PKeyError) { Net::SSH::KeyFactory.load_private_key(@key_file) }
+ end
+ end
+
private
def rsa_key
@@ -109,6 +128,39 @@ class TestKeyFactory < Test::Unit::TestCase
end
end
+ def anonymous_private_key
+ @anonymous_key = <<-EOF
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC3id5gZ6bglJth
+yli8JNaRxhsqKwwPlReEI/mplzz5IP6gWQ92LogXbdBXtHf9ZpA53BeLmtcNBEY0
+Ygd7sPBhlHABS5D5///zltSSX2+L5GCEiC6dpfGsySjqymWF+SZ2PaqfZbkWLmCD
+9u4ysueaHf7xbF6txGprNp69efttWxdy+vU5tno7HVxemMZQUalpShFrdAYKKXEo
+cV7MtbkQjzubS14gaWGpWCXIl9uNKQeHpLKtre1Qn5Ft/zVpCHmhLQcYDuB1LAj9
+7eoev4rIiOE2sfdkvKDlmFxvzq3myYH4o27WwAg9OZ5SBusn2zesKkRCBBEZ55rl
+uVknOGHXAgMBAAECggEAZE0U2OxsNxkfXS6+lXswQ5PW7pF90towcsdSPgrniGIu
+pKRnHbfKKbuaewOl+zZcpTIRL/rbgUKPtzrHSiJlC36aQyrvvJ/ZWV5ZJvC+vd19
+nY/qob65NyrrkHwxRSjmiwGiR9/IaUXI+vUsMUqx5Ph1hawqhZ3sZlEAKR4LeDO8
+M+OguG77jLaqj5/SNfi+GwyUDe85de4VfEG4S9HrMQk2Cp66rx0BqDnCLacyFQaI
+R0VczMXTU52q0uETmgUr8G9A1SaRc5ZWKAfZwxJTvqdIImWC9E+CY7wm+mZD4FE6
+iVzVC0ngcdEd596kTDdU2BPVMluWzLkfqIrTt/5CeQKBgQDzgRzCPNxFtai6RAIi
+ekBSHqrDnrbeTaw32GVq5ACk1Zfk2I0svctz1iQ9qJ2SRINpygQhcyJKQ4r/LXi1
+7Av9H/d6QV4T2AZzS4WcqBkxxRXFUfARtnKChzuCzNt9tNz4EZiv75RyQmztGZjV
+i94+ZvCyqup5be4Svf4MBxin9QKBgQDA9P4nHzFWZakTMei78LGb/4Auc+r0rZp7
+8xg8Z92tvrDeJjMdesdhiFrPP1qiSYHnQ81MSWpn6BycBsHZqitejQmYnYput/s4
+qG+m7SrkN8WL6rijYsbB+U14VDjMlBlOgcEgjlSNU2oeS+68u+uVI/fgyXcXn4Jq
+33TSWSgfGwKBgA2tRdE/G9wqfOShZ0FKfoxePpcoNfs8f5zPYbrkPYkEmjh3VU6b
+Bm9mKrjv3JHXmU3608qRLe7f5lG42xvUu0OnZP4P59nTe2FEb6fB5VBfUn63wHUu
+OzZLpDMPkJB59SNV0a6oFT1pr7aNhoEQDxaQL5rJcMwLOaEB3OAOEft1AoGASz7+
+4Zi7b7rDPVYIMUpCqNfxT6wqovIUPWPmPqAuhXPIm0kAQ+2+VN2MtCc7m+/Ydawu
+IiK7GPweNAY6kDxZH00WweolstmSYVzl9Y2lXUwWgGKvUB/T7I7g1Bzb7YOPftsA
+ykZW2Kn/xwLLfdQ2oXleT82g4Jh2jmDHuMPF7qMCgYEA6QF45PvOgnrJessgmwO/
+dEmkLl07PQYJPGZLaZteuWrvfMrn+AiW5aAdHzhzNaOtNy5B3T7zGUHtgxXegqgd
+/QdCVCJgnZUO/zdAxkr22dDn+WEXkL4wgBVStQvvnQp9C2NJcoOExvex5PLzKWQg
+WEKt5v3QsUEgVrzkM4K9UbI=
+-----END PRIVATE KEY-----
+ EOF
+ end
+
def encrypted(key, password)
key.export(OpenSSL::Cipher::Cipher.new("des-ede3-cbc"), password)
end