Flag RSA SHA1 deprecation when loading keys
Set flag on RSA keys of deprecated RSA SHA1 support when loading
keys based on server version of the transport. This ensures keys
are properly flagged. Flag name has been updated to provide context
on usage.
Version matching on the OpenSSH server version has also been updated
to handle customized naming in the version string (as seen in the
Windows port) and to properly handle when no match is found.
Fixes #12344 #12408 #12381
This commit is contained in:
parent
dd99138a90
commit
46aca8be5a
@ -4,32 +4,122 @@ require "net/ssh"
|
||||
# these patches pull 6.1.0 up to the as of now
|
||||
# current 6.2.0 beta
|
||||
if Net::SSH::Version::STRING == "6.1.0"
|
||||
require "net/ssh/authentication/methods/publickey"
|
||||
Net::SSH::Authentication::Methods::Publickey.class_eval do
|
||||
def rsa_compat_build_request(pub_key, *args)
|
||||
s_ver_str = session.transport.server_version.version.match(/OpenSSH_(?<version>\d+\.\d+)/)[:version]
|
||||
begin
|
||||
s_ver = Gem::Version.new(s_ver_str)
|
||||
if s_ver >= Gem::Version.new("7.2") && pub_key.is_a?(OpenSSL::PKey::RSA)
|
||||
pub_key.deprecated_ssh_rsa = true
|
||||
debug { "public key has been marked for deprecated ssh-rsa SHA1 behavior" }
|
||||
info = key_manager.known_identities[pub_key]
|
||||
if info && info[:key]
|
||||
info[:key].deprecated_ssh_rsa = true
|
||||
debug { "private key has been marked for deprecated ssh-rsa SHA1 behavior" }
|
||||
else
|
||||
warn { "cannot deprecate ssh rsa on private key, not loaded (#{info[:file]})" }
|
||||
module DeprecatedRsaSha1
|
||||
module KeyManager
|
||||
def initialize(logger, options={})
|
||||
@deprecated_rsa_sha1 = options.delete(:deprecated_rsa_sha1)
|
||||
super
|
||||
end
|
||||
|
||||
def sign(identity, data)
|
||||
info = known_identities[identity] or raise Net::SSH::Authentication::KeyManager::KeyManagerError, "the given identity is unknown to the key manager"
|
||||
|
||||
if info[:key].nil? && info[:from] == :file
|
||||
begin
|
||||
info[:key] = Net::SSH::KeyFactory.load_private_key(info[:file], options[:passphrase], !options[:non_interactive], options[:password_prompt])
|
||||
if @deprecated_rsa_sha1 && info[:key].respond_to?(:deprecated_rsa_sha1=)
|
||||
info[:key].deprecated_rsa_sha1 = true
|
||||
Vagrant.global_logger.debug("set RSA SHA1 deprecation on private key: #{info[:key].fingerprint}")
|
||||
end
|
||||
rescue OpenSSL::OpenSSLError, Exception => e
|
||||
raise Net::SSH::Authentication::KeyManager::KeyManagerError, "the given identity is known, but the private key could not be loaded: #{e.class} (#{e.message})"
|
||||
end
|
||||
end
|
||||
rescue ArgumentError
|
||||
warn { "failed to parse OpenSSH version (raw: #{session.transport.server_version.version} attempted: #{s_ver_str}" }
|
||||
|
||||
if info[:key]
|
||||
return Net::SSH::Buffer.from(:string, identity.ssh_signature_type,
|
||||
:mstring, info[:key].ssh_do_sign(data.to_s)).to_s
|
||||
end
|
||||
|
||||
if info[:from] == :agent
|
||||
raise Net::SSH::Authentication::KeyManager::KeyManagerError, "the agent is no longer available" unless agent
|
||||
return agent.sign(info[:identity], data.to_s)
|
||||
end
|
||||
|
||||
raise Net::SSH::Authentication::KeyManager::KeyManagerError, "[BUG] can't determine identity origin (#{info.inspect})"
|
||||
end
|
||||
|
||||
def load_identities(identities, ask_passphrase, ignore_decryption_errors)
|
||||
identities.map do |identity|
|
||||
begin
|
||||
case identity[:load_from]
|
||||
when :pubkey_file
|
||||
key = Net::SSH::KeyFactory.load_public_key(identity[:pubkey_file])
|
||||
if @deprecated_rsa_sha1 && key.respond_to?(:deprecated_rsa_sha1=)
|
||||
key.deprecated_rsa_sha1 = true
|
||||
Vagrant.global_logger.debug("set RSA SHA1 deprecation on public key: #{key.fingerprint}")
|
||||
end
|
||||
{ public_key: key, from: :file, file: identity[:privkey_file] }
|
||||
when :privkey_file
|
||||
private_key = Net::SSH::KeyFactory.load_private_key(
|
||||
identity[:privkey_file], options[:passphrase], ask_passphrase, options[:password_prompt]
|
||||
)
|
||||
key = private_key.send(:public_key)
|
||||
if @deprecated_rsa_sha1 && key.respond_to?(:deprecated_rsa_sha1=)
|
||||
key.deprecated_rsa_sha1 = true
|
||||
private_key.deprecated_rsa_sha1 = true
|
||||
Vagrant.global_logger.debug("set RSA SHA1 deprecation on public key: #{key.fingerprint}")
|
||||
Vagrant.global_logger.debug("set RSA SHA1 deprecation on private key: #{private_key.fingerprint}")
|
||||
end
|
||||
{ public_key: key, from: :file, file: identity[:privkey_file], key: private_key }
|
||||
when :data
|
||||
private_key = Net::SSH::KeyFactory.load_data_private_key(
|
||||
identity[:data], options[:passphrase], ask_passphrase, "<key in memory>", options[:password_prompt]
|
||||
)
|
||||
key = private_key.send(:public_key)
|
||||
if @deprecated_rsa_sha1 && key.respond_to?(:deprecated_rsa_sha1=)
|
||||
key.deprecated_rsa_sha1 = true
|
||||
private_key.deprecated_rsa_sha1 = true
|
||||
Vagrant.global_logger.debug("set RSA SHA1 deprecation on public key: #{key.fingerprint}")
|
||||
Vagrant.global_logger.debug("set RSA SHA1 deprecation on private key: #{private_key.fingerprint}")
|
||||
end
|
||||
{ public_key: key, from: :key_data, data: identity[:data], key: private_key }
|
||||
else
|
||||
identity
|
||||
end
|
||||
rescue OpenSSL::PKey::RSAError, OpenSSL::PKey::DSAError, OpenSSL::PKey::ECError, OpenSSL::PKey::PKeyError, ArgumentError => e
|
||||
if ignore_decryption_errors
|
||||
identity
|
||||
else
|
||||
process_identity_loading_error(identity, e)
|
||||
nil
|
||||
end
|
||||
rescue Exception => e
|
||||
process_identity_loading_error(identity, e)
|
||||
nil
|
||||
end
|
||||
end.compact
|
||||
end
|
||||
end
|
||||
|
||||
module AuthenticationSession
|
||||
def initialize(transport, options={})
|
||||
s_ver_str = transport.server_version.version.
|
||||
match(/OpenSSH_.*?(?<version>\d+\.\d+)/)&.[](:version).to_s
|
||||
Vagrant.global_logger.debug("ssh server version detected: #{s_ver_str}")
|
||||
if !s_ver_str.empty?
|
||||
begin
|
||||
ver = Gem::Version.new(s_ver_str)
|
||||
if ver >= Gem::Version.new("7.2")
|
||||
Vagrant.global_logger.debug("ssh server supports deprecation of RSA SHA1, deprecating")
|
||||
options[:deprecated_rsa_sha1] = true
|
||||
else
|
||||
Vagrant.global_logger.debug("ssh server does not support deprecation of RSA SHA1")
|
||||
end
|
||||
rescue ArgumentError => err
|
||||
Vagrant.global_logger.debug("failed to determine valid ssh server version - #{err}")
|
||||
end
|
||||
end
|
||||
super
|
||||
end
|
||||
_raw_build_request(pub_key, *args)
|
||||
end
|
||||
alias_method :_raw_build_request, :build_request
|
||||
alias_method :build_request, :rsa_compat_build_request
|
||||
end
|
||||
|
||||
require "net/ssh/authentication/key_manager"
|
||||
Net::SSH::Authentication::KeyManager.prepend(DeprecatedRsaSha1::KeyManager)
|
||||
require "net/ssh/authentication/session"
|
||||
Net::SSH::Authentication::Session.prepend(DeprecatedRsaSha1::AuthenticationSession)
|
||||
|
||||
require "net/ssh/authentication/agent"
|
||||
# net/ssh/authentication/agent
|
||||
Net::SSH::Authentication::Agent.class_eval do
|
||||
@ -67,7 +157,10 @@ if Net::SSH::Version::STRING == "6.1.0"
|
||||
|
||||
require "net/ssh/transport/algorithms"
|
||||
# net/ssh/transport/algorithms
|
||||
Net::SSH::Transport::Algorithms::DEFAULT_ALGORITHMS[:host_key].push("rsa-sha2-256").push("rsa-sha2-512")
|
||||
Net::SSH::Transport::Algorithms::DEFAULT_ALGORITHMS[:host_key].insert(
|
||||
Net::SSH::Transport::Algorithms::DEFAULT_ALGORITHMS[:host_key].size - 1, "rsa-sha2-256")
|
||||
Net::SSH::Transport::Algorithms::DEFAULT_ALGORITHMS[:host_key].insert(
|
||||
Net::SSH::Transport::Algorithms::DEFAULT_ALGORITHMS[:host_key].size - 1, "rsa-sha2-512")
|
||||
|
||||
require "net/ssh/transport/cipher_factory"
|
||||
# net/ssh/transport/cipher_factory
|
||||
@ -113,7 +206,7 @@ if Net::SSH::Version::STRING == "6.1.0"
|
||||
require "net/ssh/transport/openssl"
|
||||
# net/ssh/transport/openssl
|
||||
OpenSSL::PKey::RSA.class_eval do
|
||||
attr_accessor :deprecated_ssh_rsa
|
||||
attr_accessor :deprecated_rsa_sha1
|
||||
|
||||
def ssh_do_verify(sig, data, options = {})
|
||||
digester =
|
||||
@ -129,7 +222,7 @@ if Net::SSH::Version::STRING == "6.1.0"
|
||||
end
|
||||
|
||||
def ssh_type
|
||||
deprecated_ssh_rsa ? signature_algorithm : "ssh-rsa"
|
||||
deprecated_rsa_sha1 ? signature_algorithm : "ssh-rsa"
|
||||
end
|
||||
|
||||
def signature_algorithm
|
||||
@ -137,7 +230,7 @@ if Net::SSH::Version::STRING == "6.1.0"
|
||||
end
|
||||
|
||||
def ssh_do_sign(data)
|
||||
if deprecated_ssh_rsa
|
||||
if deprecated_rsa_sha1
|
||||
sign(OpenSSL::Digest::SHA256.new, data)
|
||||
else
|
||||
sign(OpenSSL::Digest::SHA1.new, data)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user