summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklós Fazekas <mfazekas@szemafor.com>2020-01-19 11:41:07 +0100
committerGitHub <noreply@github.com>2020-01-19 11:41:07 +0100
commit4f21491f2709082fce25fd91f41d785ec45a5f17 (patch)
tree1e5f05a2ca7b04252c943742837b5fc3d7f524e9
parent5c31c9dc5f65b151a9195d1d7c307e2f6d155da1 (diff)
parentf99ba4c04b16f7078f56e709cd67f31ed8a4a325 (diff)
downloadnet-ssh-4f21491f2709082fce25fd91f41d785ec45a5f17.tar.gz
Merge pull request #722 from anderscarling/certkeys
Support :certkeys and CertificateFile configuration option
-rw-r--r--lib/net/ssh.rb4
-rw-r--r--lib/net/ssh/authentication/key_manager.rb29
-rw-r--r--lib/net/ssh/authentication/session.rb7
-rw-r--r--lib/net/ssh/config.rb48
-rw-r--r--test/authentication/test_key_manager.rb203
-rw-r--r--test/configs/exact_match4
-rw-r--r--test/integration/test_cert_user_auth.rb58
-rw-r--r--test/test_config.rb3
8 files changed, 279 insertions, 77 deletions
diff --git a/lib/net/ssh.rb b/lib/net/ssh.rb
index a0734c6..542c757 100644
--- a/lib/net/ssh.rb
+++ b/lib/net/ssh.rb
@@ -66,7 +66,7 @@ module Net
auth_methods bind_address compression compression_level config
encryption forward_agent hmac host_key remote_user
keepalive keepalive_interval keepalive_maxcount kex keys key_data
- languages logger paranoid password port proxy
+ keycerts languages logger paranoid password port proxy
rekey_blocks_limit rekey_limit rekey_packet_limit timeout verbose
known_hosts global_known_hosts_file user_known_hosts_file host_key_alias
host_name user properties passphrase keys_only max_pkt_size
@@ -144,6 +144,8 @@ module Net
# * :kex => the key exchange algorithm (or algorithms) to use
# * :keys => an array of file names of private keys to use for publickey
# and hostbased authentication
+ # * :keycerts => an array of file names of key certificates to use
+ # with publickey authentication
# * :key_data => an array of strings, with each element of the array being
# a raw private key in PEM format.
# * :keys_only => set to +true+ to use only private keys from +keys+ and
diff --git a/lib/net/ssh/authentication/key_manager.rb b/lib/net/ssh/authentication/key_manager.rb
index 52192f2..242d5d5 100644
--- a/lib/net/ssh/authentication/key_manager.rb
+++ b/lib/net/ssh/authentication/key_manager.rb
@@ -30,6 +30,9 @@ module Net
# The list of user key data that will be examined
attr_reader :key_data
+ # The list of user key certificate files that will be examined
+ attr_reader :keycert_files
+
# The map of loaded identities
attr_reader :known_identities
@@ -43,6 +46,7 @@ module Net
self.logger = logger
@key_files = []
@key_data = []
+ @keycert_files = []
@use_agent = options[:use_agent] != false
@known_identities = {}
@agent = nil
@@ -66,6 +70,12 @@ module Net
self
end
+ # Add the given keycert_file to the list of keycert files that will be used.
+ def add_keycert(keycert_file)
+ keycert_files.push(File.expand_path(keycert_file)).uniq!
+ self
+ end
+
# Add the given key_file to the list of keys that will be used.
def add_key_data(key_data_)
key_data.push(key_data_).uniq!
@@ -108,7 +118,7 @@ module Net
user_identities.delete(corresponding_user_identity) if corresponding_user_identity
if !options[:keys_only] || corresponding_user_identity
- known_identities[key] = { from: :agent }
+ known_identities[key] = { from: :agent, identity: key }
yield key
end
end
@@ -122,6 +132,21 @@ module Net
yield key
end
+ known_identity_blobs = known_identities.keys.map(&:to_blob)
+ keycert_files.each do |keycert_file|
+ keycert = KeyFactory.load_public_key(keycert_file)
+ next if known_identity_blobs.include?(keycert.to_blob)
+
+ (_, corresponding_identity) = known_identities.detect { |public_key, _|
+ public_key.to_pem == keycert.to_pem
+ }
+
+ if corresponding_identity
+ known_identities[keycert] = corresponding_identity
+ yield keycert
+ end
+ end
+
self
end
@@ -152,7 +177,7 @@ module Net
if info[:from] == :agent
raise KeyManagerError, "the agent is no longer available" unless agent
- return agent.sign(identity, data.to_s)
+ return agent.sign(info[:identity], data.to_s)
end
raise KeyManagerError, "[BUG] can't determine identity origin (#{info.inspect})"
diff --git a/lib/net/ssh/authentication/session.rb b/lib/net/ssh/authentication/session.rb
index 0baacc3..dfc5c06 100644
--- a/lib/net/ssh/authentication/session.rb
+++ b/lib/net/ssh/authentication/session.rb
@@ -63,6 +63,7 @@ module Net
key_manager = KeyManager.new(logger, options)
keys.each { |key| key_manager.add(key) } unless keys.empty?
+ keycerts.each { |keycert| key_manager.add_keycert(keycert) } unless keycerts.empty?
key_data.each { |key2| key_manager.add_key_data(key2) } unless key_data.empty?
default_keys.each { |key| key_manager.add(key) } unless options.key?(:keys) || options.key?(:key_data)
@@ -146,6 +147,12 @@ module Net
Array(options[:keys])
end
+ # Returns an array of paths to the keycert files that should be used when
+ # attempting any key-based authentication mechanism.
+ def keycerts
+ Array(options[:keycerts])
+ end
+
# Returns an array of the key data that should be used when
# attempting any key-based authentication mechanism.
def key_data
diff --git a/lib/net/ssh/config.rb b/lib/net/ssh/config.rb
index d998a58..5c81e61 100644
--- a/lib/net/ssh/config.rb
+++ b/lib/net/ssh/config.rb
@@ -11,6 +11,7 @@ module Net
#
# * ChallengeResponseAuthentication => maps to the :auth_methods option challenge-response (then coleasced into keyboard-interactive)
# * KbdInteractiveAuthentication => maps to the :auth_methods keyboard-interactive
+ # * CertificateFile => maps to the :keycerts option
# * Ciphers => maps to the :encryption option
# * Compression => :compression
# * CompressionLevel => :compression_level
@@ -129,7 +130,7 @@ module Net
block_seen = true
elsif !block_seen
case key
- when 'identityfile'
+ when 'identityfile', 'certificatefile'
(globals[key] ||= []) << value
when 'include'
included_file_paths(base_dir, value).each do |file_path|
@@ -140,7 +141,7 @@ module Net
end
elsif block_matched
case key
- when 'identityfile'
+ when 'identityfile', 'certificatefile'
(settings[key] ||= []) << value
when 'include'
included_file_paths(base_dir, value).each do |file_path|
@@ -161,7 +162,7 @@ module Net
globals.merge(settings) do |key, oldval, newval|
case key
- when 'identityfile'
+ when 'identityfile', 'certificatefile'
oldval + newval
else
newval
@@ -196,25 +197,26 @@ module Net
private
+ TRANSLATE_CONFIG_KEY_RENAME_MAP = {
+ bindaddress: :bind_address,
+ compression: :compression,
+ compressionlevel: :compression_level,
+ certificatefile: :keycerts,
+ connecttimeout: :timeout,
+ forwardagent: :forward_agent,
+ identitiesonly: :keys_only,
+ identityagent: :identity_agent,
+ globalknownhostsfile: :global_known_hosts_file,
+ hostkeyalias: :host_key_alias,
+ identityfile: :keys,
+ fingerprinthash: :fingerprint_hash,
+ port: :port,
+ stricthostkeychecking: :strict_host_key_checking,
+ user: :user,
+ userknownhostsfile: :user_known_hosts_file,
+ checkhostip: :check_host_ip
+ }.freeze
def translate_config_key(hash, key, value, settings)
- rename = {
- bindaddress: :bind_address,
- compression: :compression,
- compressionlevel: :compression_level,
- connecttimeout: :timeout,
- forwardagent: :forward_agent,
- identitiesonly: :keys_only,
- identityagent: :identity_agent,
- globalknownhostsfile: :global_known_hosts_file,
- hostkeyalias: :host_key_alias,
- identityfile: :keys,
- fingerprinthash: :fingerprint_hash,
- port: :port,
- stricthostkeychecking: :strict_host_key_checking,
- user: :user,
- userknownhostsfile: :user_known_hosts_file,
- checkhostip: :check_host_ip
- }
case key
when :ciphers
hash[:encryption] = value.split(/,/)
@@ -276,8 +278,8 @@ module Net
hash[:send_env] = multi_send_env.map { |e| Regexp.new pattern2regex(e).source, false }
when :numberofpasswordprompts
hash[:number_of_password_prompts] = value.to_i
- when *rename.keys
- hash[rename[key]] = value
+ when *TRANSLATE_CONFIG_KEY_RENAME_MAP.keys
+ hash[TRANSLATE_CONFIG_KEY_RENAME_MAP[key]] = value
end
end
diff --git a/test/authentication/test_key_manager.rb b/test/authentication/test_key_manager.rb
index f9299a9..c40779f 100644
--- a/test/authentication/test_key_manager.rb
+++ b/test/authentication/test_key_manager.rb
@@ -9,6 +9,10 @@ module Authentication
assert manager.known_identities.empty?
end
+ def test_keycert_files_are_empty_by_default
+ assert manager.keycert_files.empty?
+ end
+
def test_assume_agent_is_available_by_default
assert manager.use_agent?
end
@@ -23,6 +27,16 @@ module Authentication
assert_equal %w[first second third], final_files
end
+ def test_add_ensures_keycert_list_is_unique
+ manager.add_keycert "/first"
+ manager.add_keycert "/second"
+ manager.add_keycert "/third"
+ manager.add_keycert "/second"
+ assert_equal 3, manager.keycert_files.length
+ final_files = manager.keycert_files.map {|item| item.split('/').last}
+ assert_equal %w[first second third], final_files
+ end
+
def test_use_agent_should_be_set_to_false_if_agent_could_not_be_found
Net::SSH::Authentication::Agent.expects(:connect).raises(Net::SSH::Authentication::AgentNotAvailable)
assert manager.use_agent?
@@ -42,8 +56,8 @@ module Authentication
manager.stubs(:agent).returns(nil)
first = File.expand_path("/first")
second = File.expand_path("/second")
- stub_file_private_key first, rsa
- stub_file_private_key second, dsa
+ stub_file_private_key first, rsa, rsa_pk
+ stub_file_private_key second, dsa, dsa_pk
identities = []
manager.each_identity { |identity| identities << identity }
@@ -52,27 +66,57 @@ module Authentication
assert_equal rsa.to_blob, identities.first.to_blob
assert_equal dsa.to_blob, identities.last.to_blob
- assert_equal({ from: :file, file: first, key: rsa }, manager.known_identities[rsa])
- assert_equal({ from: :file, file: second, key: dsa }, manager.known_identities[dsa])
+ assert_equal({ from: :file, file: first, key: rsa }, manager.known_identities[rsa_pk])
+ assert_equal({ from: :file, file: second, key: dsa }, manager.known_identities[dsa_pk])
end
- def test_each_identity_should_load_form_cert_file
+ def test_each_identity_should_load_from_implicit_cert_file
manager.stubs(:agent).returns(nil)
first = File.expand_path("/first")
- stub_file_cert first, rsa
+ stub_implicit_file_cert first, rsa, rsa_cert
identities = []
manager.each_identity { |identity| identities << identity }
assert_equal 1, identities.length
+ assert_equal rsa_cert.to_blob, identities.first.to_blob
+ assert_equal({ from: :file, file: first }, manager.known_identities[rsa_cert])
+ end
+
+ def test_each_identity_should_load_from_explicit_cert_file_given_matching_key_is_loaded
+ manager.stubs(:agent).returns(nil)
+ stub_explicit_file_cert File.expand_path("/rsa-cert"), rsa_cert
+ first = File.expand_path("/first")
+ stub_file_private_key first, rsa, rsa_pk
+
+ identities = []
+ manager.each_identity { |identity| identities << identity }
+
+ assert_equal 2, identities.length
assert_equal rsa.to_blob, identities.first.to_blob
- assert_equal({ from: :file, file: first }, manager.known_identities[rsa])
+ assert_equal rsa_cert.to_blob, identities.last.to_blob
+ assert_equal({ from: :file, file: first, key: rsa }, manager.known_identities[rsa_pk])
+ assert_equal({ from: :file, file: first, key: rsa }, manager.known_identities[rsa_cert])
+ end
+
+ def test_each_identity_should_ignore_explicit_cert_file_unless_matching_key_is_avaiable
+ manager.stubs(:agent).returns(nil)
+ stub_explicit_file_cert File.expand_path("/rsa-cert"), rsa_cert
+ first = File.expand_path("/first")
+ stub_file_private_key first, dsa, dsa_pk
+
+ identities = []
+ manager.each_identity { |identity| identities << identity }
+
+ assert_equal 1, identities.length
+ assert_equal dsa.to_blob, identities.first.to_blob
+ assert_equal({ from: :file, file: first, key: dsa }, manager.known_identities[dsa_pk])
end
def test_each_identity_should_not_prompt_for_passphrase_in_non_interactive_mode
manager(non_interactive: true).stubs(:agent).returns(nil)
first = File.expand_path("/first")
- stub_file_private_key first, rsa, passphrase: :should_not_be_asked
+ stub_file_private_key first, rsa, rsa_pk, passphrase: :should_not_be_asked
identities = []
manager.each_identity { |identity| identities << identity }
assert_equal(identities, [])
@@ -85,11 +129,28 @@ module Authentication
manager.each_identity { |identity| identities << identity }
assert_equal 2, identities.length
- assert_equal rsa.to_blob, identities.first.to_blob
- assert_equal dsa.to_blob, identities.last.to_blob
+ assert_equal rsa_pk.to_blob, identities.first.to_blob
+ assert_equal dsa_pk.to_blob, identities.last.to_blob
+
+ assert_equal({ from: :agent, identity: rsa_pk }, manager.known_identities[rsa_pk])
+ assert_equal({ from: :agent, identity: dsa_pk }, manager.known_identities[dsa_pk])
+ end
+
+ def test_each_identity_should_match_explicit_keycert_with_agent_provided_identity
+ manager.stubs(:agent).returns(agent)
+ stub_explicit_file_cert File.expand_path("/cert"), rsa_cert
- assert_equal({ from: :agent }, manager.known_identities[rsa])
- assert_equal({ from: :agent }, manager.known_identities[dsa])
+ identities = []
+ manager.each_identity { |identity| identities << identity }
+
+ assert_equal 3, identities.length
+ assert_equal rsa_pk.to_blob, identities[0].to_blob
+ assert_equal dsa_pk.to_blob, identities[1].to_blob
+ assert_equal rsa_cert.to_blob, identities[2].to_blob
+
+ assert_equal({ from: :agent, identity: rsa_pk }, manager.known_identities[rsa_pk])
+ assert_equal({ from: :agent, identity: dsa_pk }, manager.known_identities[dsa_pk])
+ assert_equal({ from: :agent, identity: rsa_pk }, manager.known_identities[rsa_cert])
end
def test_identities_with_ecdsa_should_load_from_agent
@@ -99,32 +160,32 @@ module Authentication
manager.each_identity { |identity| identities << identity }
assert_equal 5, identities.length
- assert_equal rsa.to_blob, identities[0].to_blob
- assert_equal dsa.to_blob, identities[1].to_blob
- assert_equal ecdsa_sha2_nistp256.to_blob, identities[2].to_blob
- assert_equal ecdsa_sha2_nistp384.to_blob, identities[3].to_blob
- assert_equal ecdsa_sha2_nistp521.to_blob, identities[4].to_blob
-
- assert_equal({ from: :agent }, manager.known_identities[rsa])
- assert_equal({ from: :agent }, manager.known_identities[dsa])
- assert_equal({ from: :agent }, manager.known_identities[ecdsa_sha2_nistp256])
- assert_equal({ from: :agent }, manager.known_identities[ecdsa_sha2_nistp384])
- assert_equal({ from: :agent }, manager.known_identities[ecdsa_sha2_nistp521])
+ assert_equal rsa_pk.to_blob, identities[0].to_blob
+ assert_equal dsa_pk.to_blob, identities[1].to_blob
+ assert_equal ecdsa_sha2_nistp256_pk.to_blob, identities[2].to_blob
+ assert_equal ecdsa_sha2_nistp384_pk.to_blob, identities[3].to_blob
+ assert_equal ecdsa_sha2_nistp521_pk.to_blob, identities[4].to_blob
+
+ assert_equal({ from: :agent, identity: rsa_pk }, manager.known_identities[rsa_pk])
+ assert_equal({ from: :agent, identity: dsa_pk }, manager.known_identities[dsa_pk])
+ assert_equal({ from: :agent, identity: ecdsa_sha2_nistp256_pk }, manager.known_identities[ecdsa_sha2_nistp256_pk])
+ assert_equal({ from: :agent, identity: ecdsa_sha2_nistp384_pk }, manager.known_identities[ecdsa_sha2_nistp384_pk])
+ assert_equal({ from: :agent, identity: ecdsa_sha2_nistp521_pk }, manager.known_identities[ecdsa_sha2_nistp521_pk])
end
def test_only_identities_with_key_files_should_load_from_agent_of_keys_only_set
manager(keys_only: true).stubs(:agent).returns(agent)
first = File.expand_path("/first")
- stub_file_private_key first, rsa
+ stub_file_private_key first, rsa, rsa_pk
identities = []
manager.each_identity { |identity| identities << identity }
assert_equal 1, identities.length
- assert_equal rsa.to_blob, identities.first.to_blob
+ assert_equal rsa_pk.to_blob, identities.first.to_blob
- assert_equal({ from: :agent }, manager.known_identities[rsa])
+ assert_equal({ from: :agent, identity: rsa_pk }, manager.known_identities[rsa_pk])
assert manager.use_agent?
end
@@ -132,9 +193,9 @@ module Authentication
manager.stubs(:agent).returns(agent)
first = File.expand_path("/first")
- stub_file_public_key first, rsa
+ stub_file_private_key first, rsa, rsa_pk
second = File.expand_path("/second")
- stub_file_private_key second, dsa, passphrase: :should_not_be_asked
+ stub_file_private_key second, dsa, dsa_pk, passphrase: :should_not_be_asked
identities = []
manager.each_identity do |identity|
@@ -143,23 +204,31 @@ module Authentication
end
assert_equal 1, identities.length
- assert_equal rsa.to_blob, identities.first.to_blob
+ assert_equal rsa_pk.to_blob, identities.first.to_blob
end
def test_sign_with_agent_originated_key_should_request_signature_from_agent
manager.stubs(:agent).returns(agent)
manager.each_identity { |identity| } # preload the known_identities
- agent.expects(:sign).with(rsa, "hello, world").returns("abcxyz123")
- assert_equal "abcxyz123", manager.sign(rsa, "hello, world")
+ agent.expects(:sign).with(rsa_pk, "hello, world").returns("abcxyz123")
+ assert_equal "abcxyz123", manager.sign(rsa_pk, "hello, world")
+ end
+
+ def test_sign_with_agent_originated_key_should_be_signable_through_explicitly_loaded_cert
+ stub_explicit_file_cert File.expand_path("/cert"), rsa_cert
+ manager.stubs(:agent).returns(agent)
+ manager.each_identity { |identity| } # preload the known_identities
+ agent.expects(:sign).with(rsa_pk, "hello, world").returns("abcxyz123")
+ assert_equal "abcxyz123", manager.sign(rsa_cert, "hello, world")
end
def test_sign_with_file_originated_key_should_load_private_key_and_sign_with_it
manager.stubs(:agent).returns(nil)
first = File.expand_path("/first")
- stub_file_private_key first, rsa(512)
+ stub_file_private_key first, rsa(512), rsa_pk
rsa.expects(:ssh_do_sign).with("hello, world").returns("abcxyz123")
manager.each_identity { |identity| } # preload the known_identities
- assert_equal "\0\0\0\assh-rsa\0\0\0\011abcxyz123", manager.sign(rsa, "hello, world")
+ assert_equal "\0\0\0\assh-rsa\0\0\0\011abcxyz123", manager.sign(rsa_pk, "hello, world")
end
def test_sign_with_file_originated_key_should_raise_key_manager_error_if_unloadable
@@ -180,7 +249,7 @@ module Authentication
private
- def stub_file_private_key(name, key, options = {})
+ def stub_file_private_key(name, key, public_key, options = {})
manager.add(name)
File.stubs(:file?).with(name).returns(true)
File.stubs(:readable?).with(name).returns(true)
@@ -199,9 +268,9 @@ module Authentication
Net::SSH::KeyFactory.expects(:load_private_key).with(name, nil, any_of(true, false), prompt).returns(key).at_least_once
end
- # do not override OpenSSL::PKey::EC#public_key
- # (it will be called in transport/openssl.rb.)
- key.stubs(:public_key).returns(key) unless key.public_key.is_a?(OpenSSL::PKey::EC::Point)
+ # We need to stub #public_key as we rely on object identity to
+ # access #known_identities by private_key
+ key.stubs(:public_key).returns(public_key)
end
def stub_file_public_key(name, key)
@@ -215,7 +284,7 @@ module Authentication
Net::SSH::KeyFactory.expects(:load_public_key).with(name + ".pub").returns(key).at_least_once
end
- def stub_file_cert(name, key)
+ def stub_implicit_file_cert(name, key, cert)
manager.add(name)
File.stubs(:file?).with(name).returns(true)
File.stubs(:readable?).with(name).returns(true)
@@ -224,7 +293,33 @@ module Authentication
File.stubs(:file?).with(name + "-cert.pub").returns(true)
File.stubs(:readable?).with(name + "-cert.pub").returns(true)
- Net::SSH::KeyFactory.expects(:load_public_key).with(name + "-cert.pub").returns(key).at_least_once
+ Net::SSH::KeyFactory.expects(:load_public_key).with(name + "-cert.pub").returns(cert).at_least_once
+ end
+
+ def stub_explicit_file_cert(name, cert)
+ manager.add_keycert(name)
+ File.stubs(:file?).with(name).returns(true)
+ File.stubs(:readable?).with(name).returns(true)
+
+ Net::SSH::KeyFactory.expects(:load_public_key).with(name).returns(cert).at_least_once
+ end
+
+ def rsa_cert
+ @cert ||= begin
+ cert = Net::SSH::Authentication::Certificate.new
+ cert.type = :user
+ cert.key = rsa_pk
+ cert.serial = 1
+ cert.key_id = "test key"
+ cert.valid_principals = %w[test user]
+ cert.valid_before = Time.now - 86400
+ cert.valid_after = Time.now + 86400
+ cert.critical_options = {}
+ cert.extensions = {}
+ cert.reserved = ''
+ cert.sign!(OpenSSL::PKey::DSA.new(512))
+ cert
+ end
end
def rsa(size=512)
@@ -247,15 +342,35 @@ module Authentication
@ecdsa_sha2_nistp521 ||= OpenSSL::PKey::EC.new('secp521r1').generate_key
end
+ def rsa_pk
+ @rsa_pk ||= rsa.public_key
+ end
+
+ def dsa_pk
+ @dsa_pk ||= dsa.public_key
+ end
+
+ def ecdsa_sha2_nistp256_pk
+ @ecdsa_sha2_nistp256_pk ||= ecdsa_sha2_nistp256.public_key
+ end
+
+ def ecdsa_sha2_nistp384_pk
+ @ecdsa_sha2_nistp384_pk ||= ecdsa_sha2_nistp521.public_key
+ end
+
+ def ecdsa_sha2_nistp521_pk
+ @ecdsa_sha2_nistp521_pk ||= ecdsa_sha2_nistp521.public_key
+ end
+
def agent
- @agent ||= stub("agent", identities: [rsa, dsa])
+ @agent ||= stub("agent", identities: [rsa_pk, dsa_pk])
end
def agent_with_ecdsa_keys
- @agent ||= stub("agent", identities: [rsa, dsa,
- ecdsa_sha2_nistp256,
- ecdsa_sha2_nistp384,
- ecdsa_sha2_nistp521])
+ @agent ||= stub("agent", identities: [rsa_pk, dsa_pk,
+ ecdsa_sha2_nistp256_pk,
+ ecdsa_sha2_nistp384_pk,
+ ecdsa_sha2_nistp521_pk])
end
def prompt
diff --git a/test/configs/exact_match b/test/configs/exact_match
index 908d631..911f750 100644
--- a/test/configs/exact_match
+++ b/test/configs/exact_match
@@ -5,4 +5,6 @@ Host other.host
Host test.host
Compression yes
ForwardAgent yes
- Port 1234 \ No newline at end of file
+ Port 1234
+ CertificateFile ~/.ssh/id_rsa-my-cert.pub
+ CertificateFile ~/.ssh/cert.pub
diff --git a/test/integration/test_cert_user_auth.rb b/test/integration/test_cert_user_auth.rb
index 963665f..b975d0a 100644
--- a/test/integration/test_cert_user_auth.rb
+++ b/test/integration/test_cert_user_auth.rb
@@ -9,22 +9,68 @@ unless ENV['NET_SSH_NO_ED25519']
class TestCertUserAuth < NetSSHTest
include IntegrationTestHelpers
-
- def test_ed25519_with_cert
+
+ def test_ed25519_with_implicit_cert
Dir.mktmpdir do |dir|
sh "rm -rf #{dir}/id_rsa_ed25519 #{dir}/id_rsa_ed25519.pub"
sh "ssh-keygen -q -f #{dir}/id_rsa_ed25519 -t ed25519 -N ''"
sign_user_key('net_ssh_1',"#{dir}/id_rsa_ed25519.pub")
-
- # sshopts = '-vvvv -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'
- # sh "ssh -i #{dir}/id_rsa_ed25519 #{sshopts} net_ssh_1@localhost echo 'hello'"
-
+
ret = Net::SSH.start("localhost", "net_ssh_1", keys: "#{dir}/id_rsa_ed25519") do |ssh|
ssh.exec! 'echo "hello from:$USER"'
end
assert_equal "hello from:net_ssh_1\n", ret
end
end
+
+ def test_ed25519_with_explicit_cert
+ Dir.mktmpdir do |dir|
+ sh "rm -rf #{dir}/id_rsa_ed25519 #{dir}/id_rsa_ed25519.pub"
+ sh "ssh-keygen -q -f #{dir}/id_rsa_ed25519 -t ed25519 -N ''"
+ sign_user_key('net_ssh_1',"#{dir}/id_rsa_ed25519.pub")
+ sh "mv #{dir}/id_rsa_ed25519-cert.pub #{dir}/cert"
+
+ ret = Net::SSH.start("localhost", "net_ssh_1", keys: "#{dir}/id_rsa_ed25519", keycerts: "#{dir}/cert") do |ssh|
+ ssh.exec! 'echo "hello from:$USER"'
+ end
+ assert_equal "hello from:net_ssh_1\n", ret
+ end
+ end
+
+ def test_ed25519_with_cert_in_agent
+ Dir.mktmpdir do |dir|
+ with_agent do
+ sh "rm -rf #{dir}/id_rsa_ed25519 #{dir}/id_rsa_ed25519.pub"
+ sh "ssh-keygen -q -f #{dir}/id_rsa_ed25519 -t ed25519 -N 'pwd'"
+ sign_user_key('net_ssh_1',"#{dir}/id_rsa_ed25519.pub")
+ ssh_add("#{dir}/id_rsa_ed25519", "pwd")
+ sh "rm -rf #{dir}/id_rsa_ed25519 #{dir}/id_rsa_ed25519.pub #{dir}/id_rsa_ed25519-cert.pub"
+
+ ret = Net::SSH.start("localhost", "net_ssh_1") do |ssh|
+ ssh.exec! 'echo "hello from:$USER"'
+ end
+ assert_equal "hello from:net_ssh_1\n", ret
+ end
+ end
+ end
+
+ def test_ed25519_with_key_in_agent_and_explicit_cert
+ Dir.mktmpdir do |dir|
+ with_agent do
+ sh "rm -rf #{dir}/id_rsa_ed25519 #{dir}/id_rsa_ed25519.pub"
+ sh "ssh-keygen -q -f #{dir}/id_rsa_ed25519 -t ed25519 -N ''"
+ # add key before signing cert
+ ssh_add("#{dir}/id_rsa_ed25519", "pwd")
+ sign_user_key('net_ssh_1',"#{dir}/id_rsa_ed25519.pub")
+ sh "rm -rf #{dir}/id_rsa_ed25519 #{dir}/id_rsa_ed25519.pub"
+
+ ret = Net::SSH.start("localhost", "net_ssh_1", keycerts: "#{dir}/id_rsa_ed25519-cert.pub") do |ssh|
+ ssh.exec! 'echo "hello from:$USER"'
+ end
+ assert_equal "hello from:net_ssh_1\n", ret
+ end
+ end
+ end
end
end
diff --git a/test/test_config.rb b/test/test_config.rb
index 67b7c86..eab6d7f 100644
--- a/test/test_config.rb
+++ b/test/test_config.rb
@@ -89,6 +89,7 @@ class TestConfig < NetSSHTest
assert config[:compression]
assert config[:forward_agent]
assert_equal %w(~/.ssh/id_dsa), config[:keys]
+ assert_equal %w(~/.ssh/id_rsa-my-cert.pub ~/.ssh/cert.pub), config[:keycerts]
assert !config.key?(:rekey_limit)
end
@@ -131,6 +132,7 @@ class TestConfig < NetSSHTest
'hostkeyalgorithms' => "d,e,f",
'identityfile' => %w(g h i),
'macs' => "j,k,l",
+ 'certificatefile' => %w(m n o),
'passwordauthentication' => true,
'port' => 1234,
'pubkeyauthentication' => true,
@@ -155,6 +157,7 @@ class TestConfig < NetSSHTest
assert_equal %w(d e f), net_ssh[:host_key]
assert_equal %w(g h i), net_ssh[:keys]
assert_equal %w(j k l), net_ssh[:hmac]
+ assert_equal %w(m n o), net_ssh[:keycerts]
assert_equal 1234, net_ssh[:port]
assert_equal 1024, net_ssh[:rekey_limit]
assert_equal "127.0.0.1", net_ssh[:bind_address]