diff options
author | Zdenek Zambersky <zzambers@redhat.com> | 2021-05-06 13:50:20 +0200 |
---|---|---|
committer | Florian Wininger <fw.centrale@gmail.com> | 2021-10-25 15:59:19 +0200 |
commit | 91254c72586179469ee59e4b0bd1d54960ce8d88 (patch) | |
tree | 2a2b52c5bf7ac31804d1d6f018a4b5ddf805ca79 /lib/net/ssh/authentication | |
parent | 0150d054f0cd0beacd4ba1000c6df6d8636a2c18 (diff) | |
download | net-ssh-rsa-sha2.tar.gz |
Added support for RSA client authentication with SHA-2rsa-sha2
Diffstat (limited to 'lib/net/ssh/authentication')
-rw-r--r-- | lib/net/ssh/authentication/certificate.rb | 4 | ||||
-rw-r--r-- | lib/net/ssh/authentication/ed25519.rb | 2 | ||||
-rw-r--r-- | lib/net/ssh/authentication/key_manager.rb | 21 | ||||
-rw-r--r-- | lib/net/ssh/authentication/methods/abstract.rb | 10 | ||||
-rw-r--r-- | lib/net/ssh/authentication/methods/publickey.rb | 66 | ||||
-rw-r--r-- | lib/net/ssh/authentication/session.rb | 4 |
6 files changed, 87 insertions, 20 deletions
diff --git a/lib/net/ssh/authentication/certificate.rb b/lib/net/ssh/authentication/certificate.rb index c9619fa..5250789 100644 --- a/lib/net/ssh/authentication/certificate.rb +++ b/lib/net/ssh/authentication/certificate.rb @@ -66,8 +66,8 @@ module Net ).to_s end - def ssh_do_sign(data) - key.ssh_do_sign(data) + def ssh_do_sign(data, sig_alg = nil) + key.ssh_do_sign(data, sig_alg) end def ssh_do_verify(sig, data, options = {}) diff --git a/lib/net/ssh/authentication/ed25519.rb b/lib/net/ssh/authentication/ed25519.rb index c2a117a..dccc64f 100644 --- a/lib/net/ssh/authentication/ed25519.rb +++ b/lib/net/ssh/authentication/ed25519.rb @@ -171,7 +171,7 @@ module Net PubKey.new(@pk) end - def ssh_do_sign(data) + def ssh_do_sign(data, sig_alg = nil) @sign_key.sign(data) end diff --git a/lib/net/ssh/authentication/key_manager.rb b/lib/net/ssh/authentication/key_manager.rb index ac86cc8..563702c 100644 --- a/lib/net/ssh/authentication/key_manager.rb +++ b/lib/net/ssh/authentication/key_manager.rb @@ -158,7 +158,7 @@ module Net # Regardless of the identity's origin or who does the signing, this # will always return the signature in an SSH2-specified "signature # blob" format. - def sign(identity, data) + def sign(identity, data, sig_alg = nil) info = known_identities[identity] or raise KeyManagerError, "the given identity is unknown to the key manager" if info[:key].nil? && info[:from] == :file @@ -170,14 +170,27 @@ module Net end if info[:key] - return Net::SSH::Buffer.from(:string, identity.ssh_signature_type, - :mstring, info[:key].ssh_do_sign(data.to_s)).to_s + if sig_alg.nil? + signed = info[:key].ssh_do_sign(data.to_s) + sig_alg = identity.ssh_signature_type + else + signed = info[:key].ssh_do_sign(data.to_s, sig_alg) + end + return Net::SSH::Buffer.from(:string, sig_alg, + :mstring, signed).to_s end if info[:from] == :agent raise KeyManagerError, "the agent is no longer available" unless agent - return agent.sign(info[:identity], data.to_s) + case sig_alg + when "rsa-sha2-512" + return agent.sign(info[:identity], data.to_s, Net::SSH::Authentication::Agent::SSH_AGENT_RSA_SHA2_512) + when "rsa-sha2-256" + return agent.sign(info[:identity], data.to_s, Net::SSH::Authentication::Agent::SSH_AGENT_RSA_SHA2_256) + else + return agent.sign(info[:identity], data.to_s) + end end raise KeyManagerError, "[BUG] can't determine identity origin (#{info.inspect})" diff --git a/lib/net/ssh/authentication/methods/abstract.rb b/lib/net/ssh/authentication/methods/abstract.rb index 07aa5f3..f023011 100644 --- a/lib/net/ssh/authentication/methods/abstract.rb +++ b/lib/net/ssh/authentication/methods/abstract.rb @@ -20,12 +20,22 @@ module Net # this. attr_reader :key_manager + # So far only affects algorithms used for rsa keys, but can be + # extended to other keys, e.g after reading of + # PubkeyAcceptedAlgorithms option from ssh_config file is implemented. + attr_reader :pubkey_algorithms + # Instantiates a new authentication method. def initialize(session, options = {}) @session = session @key_manager = options[:key_manager] @options = options @prompt = options[:password_prompt] + @pubkey_algorithms = options[:pubkey_algorithms] \ + || %w[rsa-sha2-256-cert-v01@openssh.com + ssh-rsa-cert-v01@openssh.com + rsa-sha2-256 + ssh-rsa] self.logger = session.logger end diff --git a/lib/net/ssh/authentication/methods/publickey.rb b/lib/net/ssh/authentication/methods/publickey.rb index eb4d740..48a56ab 100644 --- a/lib/net/ssh/authentication/methods/publickey.rb +++ b/lib/net/ssh/authentication/methods/publickey.rb @@ -26,41 +26,40 @@ module Net # Builds a packet that contains the request formatted for sending # a public-key request to the server. - def build_request(pub_key, username, next_service, has_sig) + def build_request(pub_key, username, next_service, alg, has_sig) blob = Net::SSH::Buffer.new blob.write_key pub_key userauth_request(username, next_service, "publickey", has_sig, - pub_key.ssh_type, blob.to_s) + alg, blob.to_s) end # Builds and sends a request formatted for a public-key # authentication request. - def send_request(pub_key, username, next_service, signature = nil) - msg = build_request(pub_key, username, next_service, !signature.nil?) + def send_request(pub_key, username, next_service, alg, signature = nil) + msg = build_request(pub_key, username, next_service, alg, + !signature.nil?) msg.write_string(signature) if signature send_message(msg) end - # Attempts to perform public-key authentication for the given - # username, with the given identity (public key). Returns +true+ if - # successful, or +false+ otherwise. - def authenticate_with(identity, next_service, username) + def authenticate_with_alg(identity, next_service, username, alg, sig_alg = nil) debug { "trying publickey (#{identity.fingerprint})" } - send_request(identity, username, next_service) + send_request(identity, username, next_service, alg) message = session.next_message case message.type when USERAUTH_PK_OK - buffer = build_request(identity, username, next_service, true) + buffer = build_request(identity, username, next_service, alg, + true) sig_data = Net::SSH::Buffer.new sig_data.write_string(session_id) sig_data.append(buffer.to_s) - sig_blob = key_manager.sign(identity, sig_data) + sig_blob = key_manager.sign(identity, sig_data, sig_alg) - send_request(identity, username, next_service, sig_blob.to_s) + send_request(identity, username, next_service, alg, sig_blob.to_s) message = session.next_message case message.type @@ -88,6 +87,49 @@ module Net raise Net::SSH::Exception, "unexpected reply to USERAUTH_REQUEST: #{message.type} (#{message.inspect})" end end + + # Attempts to perform public-key authentication for the given + # username, with the given identity (public key). Returns +true+ if + # successful, or +false+ otherwise. + def authenticate_with(identity, next_service, username) + type = identity.ssh_type + if type == "ssh-rsa" + pubkey_algorithms.each do |pk_alg| + case pk_alg + when "rsa-sha2-512", "rsa-sha2-256", "ssh-rsa" + if authenticate_with_alg(identity, next_service, username, pk_alg, pk_alg) + # success + return true + end + end + end + elsif type == "ssh-rsa-cert-v01@openssh.com" + pubkey_algorithms.each do |pk_alg| + case pk_alg + when "rsa-sha2-512-cert-v01@openssh.com" + if authenticate_with_alg(identity, next_service, username, pk_alg, "rsa-sha2-512") + # success + return true + end + when "rsa-sha2-256-cert-v01@openssh.com" + if authenticate_with_alg(identity, next_service, username, pk_alg, "rsa-sha2-256") + # success + return true + end + when "ssh-rsa-cert-v01@openssh.com" + if authenticate_with_alg(identity, next_service, username, pk_alg) + # success + return true + end + end + end + elsif authenticate_with_alg(identity, next_service, username, type) + # success + return true + end + # failure + return false + end end end end diff --git a/lib/net/ssh/authentication/session.rb b/lib/net/ssh/authentication/session.rb index e4fc648..773d704 100644 --- a/lib/net/ssh/authentication/session.rb +++ b/lib/net/ssh/authentication/session.rb @@ -76,7 +76,9 @@ module Net debug { "trying #{name}" } begin auth_class = Methods.const_get(name.split(/\W+/).map { |p| p.capitalize }.join) - method = auth_class.new(self, key_manager: key_manager, password_prompt: options[:password_prompt]) + method = auth_class.new(self, + key_manager: key_manager, password_prompt: options[:password_prompt], + pubkey_algorithms: options[:pubkey_algorithms] || nil) rescue NameError debug {"Mechanism #{name} was requested, but isn't a known type. Ignoring it."} next |