summaryrefslogtreecommitdiff
path: root/lib
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 /lib
parent5c31c9dc5f65b151a9195d1d7c307e2f6d155da1 (diff)
parentf99ba4c04b16f7078f56e709cd67f31ed8a4a325 (diff)
downloadnet-ssh-4f21491f2709082fce25fd91f41d785ec45a5f17.tar.gz
Merge pull request #722 from anderscarling/certkeys
Support :certkeys and CertificateFile configuration option
Diffstat (limited to 'lib')
-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
4 files changed, 62 insertions, 26 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