diff options
author | Miklós Fazekas <mfazekas@szemafor.com> | 2020-01-19 11:41:07 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-01-19 11:41:07 +0100 |
commit | 4f21491f2709082fce25fd91f41d785ec45a5f17 (patch) | |
tree | 1e5f05a2ca7b04252c943742837b5fc3d7f524e9 /lib | |
parent | 5c31c9dc5f65b151a9195d1d7c307e2f6d155da1 (diff) | |
parent | f99ba4c04b16f7078f56e709cd67f31ed8a4a325 (diff) | |
download | net-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.rb | 4 | ||||
-rw-r--r-- | lib/net/ssh/authentication/key_manager.rb | 29 | ||||
-rw-r--r-- | lib/net/ssh/authentication/session.rb | 7 | ||||
-rw-r--r-- | lib/net/ssh/config.rb | 48 |
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 |