From cebfb7a63b0d7306bd65585cefbcb61730385f31 Mon Sep 17 00:00:00 2001 From: Chris Roberts Date: Mon, 26 Jun 2023 15:07:58 -0700 Subject: [PATCH] Use key type supported by server if possible Check the key types supported by the server. If the data is not available, default to the previous behavior which is using the rsa key type. Update insecure key check to match against any key files located within the keys directory. For now, this effectively allows matching either rsa or ed25519 insecure private keys. --- plugins/communicators/ssh/communicator.rb | 58 +++++++++++++++++++++-- 1 file changed, 55 insertions(+), 3 deletions(-) diff --git a/plugins/communicators/ssh/communicator.rb b/plugins/communicators/ssh/communicator.rb index 68d36e44d..e86671651 100644 --- a/plugins/communicators/ssh/communicator.rb +++ b/plugins/communicators/ssh/communicator.rb @@ -185,7 +185,29 @@ module VagrantPlugins @machine.guest.capability?(:remove_public_key) raise Vagrant::Errors::SSHInsertKeyUnsupported if !cap - _pub, priv, openssh = Vagrant::Util::Keypair.create + # Check for supported key type + key_type = catch(:key_type) do + begin + Vagrant::Util::Keypair::PREFER_KEY_TYPES.each do |type_name, type| + throw :key_type, type if supports_key_type?(type_name) + end + nil + rescue => err + @logger.warn("Failed to check key types server supports: #{err}") + nil + end + end + + @logger.debug("Detected key type for new private key: #{key_type}") + + # If no key type was discovered, default to rsa + if key_type.nil? + @logger.debug("Failed to detect supported key type, defaulting to rsa") + key_type = :rsa + end + + @logger.info("Creating new ssh keypair (type: #{key_type.inspect})") + _pub, priv, openssh = Vagrant::Util::Keypair.create(type: key_type) @logger.info("Inserting key to avoid password: #{openssh}") @machine.ui.detail("\n"+I18n.t("vagrant.inserting_random_key")) @@ -748,8 +770,9 @@ module VagrantPlugins def insecure_key?(path) return false if !path return false if !File.file?(path) - source_path = Vagrant.source_root.join("keys", "vagrant") - return File.read(path).chomp == source_path.read.chomp + Dir.glob(Vagrant.source_root.join("keys", "vagrant.key.*")).any? do |source_path| + File.read(path).chomp == File.read(source_path).chomp + end end def create_remote_directory(dir) @@ -759,6 +782,35 @@ module VagrantPlugins def machine_config_ssh @machine.config.ssh end + + protected + + # Check if server supports given key type + # + # @param [String, Symbol] type Key type + # @return [Boolean] + # @note This does not use a stable API and may be subject + # to unexpected breakage on net-ssh updates + def supports_key_type?(type) + if @connection.nil? + raise Vagrant::Errors::SSHNotReady + end + server_data = @connection. + transport&. + algorithms&. + instance_variable_get(:@server_data) + if server_data.nil? + @logger.warn("No server data available for key type support check") + return false + end + if !server_data.is_a?(Hash) + @logger.warn("Server data is not expected type (expecting Hash, got #{server_data.class})") + return false + end + + @logger.debug("server data used for host key support check: #{server_data.inspect}") + server_data[:host_key].include?(type.to_s) + end end end end