Hello community, here is the log from the commit of package rubygem-net-ssh for openSUSE:Factory checked in at 2017-03-21 22:50:40 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/rubygem-net-ssh (Old) and /work/SRC/openSUSE:Factory/.rubygem-net-ssh.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "rubygem-net-ssh" Tue Mar 21 22:50:40 2017 rev:24 rq:479684 version:4.1.0 Changes: -------- --- /work/SRC/openSUSE:Factory/rubygem-net-ssh/rubygem-net-ssh.changes 2017-01-25 23:27:35.372293963 +0100 +++ /work/SRC/openSUSE:Factory/.rubygem-net-ssh.new/rubygem-net-ssh.changes 2017-03-21 22:50:47.608227636 +0100 @@ -1,0 +2,17 @@ +Sun Feb 19 05:32:48 UTC 2017 - co...@suse.com + +- updated to version 4.1.0 + see installed CHANGES.txt + + === 4.1.0 + === 4.1.0.rc1 + + * ProxyJump support [Ryan McGeary, #500] + * Fix agent detection on Windows [Christian Koehler, #495] + + === 4.1.0.beta1 + + * Fix nil error when libsodium is not there [chapmajs ,#488] + * SSH certificate support for client auth [David Bartley, #485] + +------------------------------------------------------------------- Old: ---- net-ssh-4.0.1.gem New: ---- net-ssh-4.1.0.gem ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ rubygem-net-ssh.spec ++++++ --- /var/tmp/diff_new_pack.zQXdqX/_old 2017-03-21 22:50:48.468106073 +0100 +++ /var/tmp/diff_new_pack.zQXdqX/_new 2017-03-21 22:50:48.476104943 +0100 @@ -24,7 +24,7 @@ # Name: rubygem-net-ssh -Version: 4.0.1 +Version: 4.1.0 Release: 0 %define mod_name net-ssh %define mod_full_name %{mod_name}-%{version} ++++++ net-ssh-4.0.1.gem -> net-ssh-4.1.0.gem ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/.travis.yml new/.travis.yml --- old/.travis.yml 2017-01-07 15:36:27.000000000 +0100 +++ new/.travis.yml 2017-02-18 18:23:34.000000000 +0100 @@ -2,6 +2,10 @@ sudo: true dist: trusty +addon: + hosts: + gateway.netssh + rvm: - 2.0 - 2.1 @@ -40,6 +44,7 @@ - ansible-playbook ./test/integration/playbook.yml -i "localhost," --become -c local -e 'no_rvm=true' -e 'myuser=travis' -e 'mygroup=travis' -e 'homedir=/home/travis' script: + - ssh -V - bundle _1.13.7_ exec rake test - BUNDLE_GEMFILE=./Gemfile.norbnacl bundle _1.13.7_ exec rake test - bundle _1.13.7_ exec rake test_test diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/CHANGES.txt new/CHANGES.txt --- old/CHANGES.txt 2017-01-07 15:36:27.000000000 +0100 +++ new/CHANGES.txt 2017-02-18 18:23:34.000000000 +0100 @@ -1,3 +1,14 @@ +=== 4.1.0 +=== 4.1.0.rc1 + + * ProxyJump support [Ryan McGeary, #500] + * Fix agent detection on Windows [Christian Koehler, #495] + +=== 4.1.0.beta1 + + * Fix nil error when libsodium is not there [chapmajs ,#488] + * SSH certificate support for client auth [David Bartley, #485] + === 4.0.1 === 4.0.1.rc2 Binary files old/checksums.yaml.gz and new/checksums.yaml.gz differ Binary files old/checksums.yaml.gz.sig and new/checksums.yaml.gz.sig differ Binary files old/data.tar.gz.sig and new/data.tar.gz.sig differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/net/ssh/authentication/agent.rb new/lib/net/ssh/authentication/agent.rb --- old/lib/net/ssh/authentication/agent.rb 2017-01-07 15:36:27.000000000 +0100 +++ new/lib/net/ssh/authentication/agent.rb 2017-02-18 18:23:34.000000000 +0100 @@ -29,20 +29,28 @@ attr_accessor :comment end - SSH2_AGENT_REQUEST_VERSION = 1 - SSH2_AGENT_REQUEST_IDENTITIES = 11 - SSH2_AGENT_IDENTITIES_ANSWER = 12 - SSH2_AGENT_SIGN_REQUEST = 13 - SSH2_AGENT_SIGN_RESPONSE = 14 - SSH2_AGENT_FAILURE = 30 - SSH2_AGENT_VERSION_RESPONSE = 103 + SSH2_AGENT_REQUEST_VERSION = 1 + SSH2_AGENT_REQUEST_IDENTITIES = 11 + SSH2_AGENT_IDENTITIES_ANSWER = 12 + SSH2_AGENT_SIGN_REQUEST = 13 + SSH2_AGENT_SIGN_RESPONSE = 14 + SSH2_AGENT_ADD_IDENTITY = 17 + SSH2_AGENT_REMOVE_IDENTITY = 18 + SSH2_AGENT_REMOVE_ALL_IDENTITIES = 19 + SSH2_AGENT_ADD_ID_CONSTRAINED = 25 + SSH2_AGENT_FAILURE = 30 + SSH2_AGENT_VERSION_RESPONSE = 103 - SSH_COM_AGENT2_FAILURE = 102 + SSH_COM_AGENT2_FAILURE = 102 SSH_AGENT_REQUEST_RSA_IDENTITIES = 1 SSH_AGENT_RSA_IDENTITIES_ANSWER1 = 2 SSH_AGENT_RSA_IDENTITIES_ANSWER2 = 5 SSH_AGENT_FAILURE = 5 + SSH_AGENT_SUCCESS = 6 + + SSH_AGENT_CONSTRAIN_LIFETIME = 1 + SSH_AGENT_CONSTRAIN_CONFIRM = 2 # The underlying socket being used to communicate with the SSH agent. attr_reader :socket @@ -71,7 +79,7 @@ @socket = if agent_socket_factory agent_socket_factory.call - elsif ENV['SSH_AUTH_SOCK'] && defined?(unix_socket_class) + elsif ENV['SSH_AUTH_SOCK'] && unix_socket_class unix_socket_class.open(ENV['SSH_AUTH_SOCK']) elsif Gem.win_platform? && RUBY_ENGINE != "jruby" Pageant::Socket.open @@ -139,10 +147,41 @@ return reply.read_string end + # Adds the private key with comment to the agent. + # If lifetime is given, the key will automatically be removed after lifetime + # seconds. + # If confirm is true, confirmation will be required for each agent signing + # operation. + def add_identity(priv_key, comment, lifetime: nil, confirm: false) + constraints = Buffer.new + if lifetime + constraints.write_byte(SSH_AGENT_CONSTRAIN_LIFETIME) + constraints.write_long(lifetime) + end + constraints.write_byte(SSH_AGENT_CONSTRAIN_CONFIRM) if confirm + + req_type = constraints.empty? ? SSH2_AGENT_ADD_IDENTITY : SSH2_AGENT_ADD_ID_CONSTRAINED + type, = send_and_wait(req_type, :string, priv_key.ssh_type, :raw, blob_for_add(priv_key), + :string, comment, :raw, constraints) + raise AgentError, "could not add identity to agent" if type != SSH_AGENT_SUCCESS + end + + # Removes key from the agent. + def remove_identity(key) + type, = send_and_wait(SSH2_AGENT_REMOVE_IDENTITY, :string, key.to_blob) + raise AgentError, "could not remove identity from agent" if type != SSH_AGENT_SUCCESS + end + + # Removes all identities from the agent. + def remove_all_identities + type, = send_and_wait(SSH2_AGENT_REMOVE_ALL_IDENTITIES) + raise AgentError, "could not remove all identity from agent" if type != SSH_AGENT_SUCCESS + end + private def unix_socket_class - UNIXSocket + defined?(UNIXSocket) && UNIXSocket end # Send a new packet of the given type, with the associated data. @@ -178,6 +217,40 @@ type == SSH2_AGENT_FAILURE || type == SSH_COM_AGENT2_FAILURE end + + def blob_for_add(priv_key) + # Ideally we'd have something like `to_private_blob` on the various key types, but the + # nuances with encoding (e.g. `n` and `e` are reversed for RSA keys) make this impractical. + case priv_key.ssh_type + when /^ssh-dss$/ + Net::SSH::Buffer.from(:bignum, priv_key.p, :bignum, priv_key.q, :bignum, priv_key.g, + :bignum, priv_key.pub_key, :bignum, priv_key.priv_key).to_s + when /^ssh-dss-cert-v01@openssh\.com$/ + Net::SSH::Buffer.from(:string, priv_key.to_blob, :bignum, priv_key.key.priv_key).to_s + when /^ecdsa\-sha2\-(\w*)$/ + curve_name = OpenSSL::PKey::EC::CurveNameAliasInv[priv_key.group.curve_name] + Net::SSH::Buffer.from(:string, curve_name, :mstring, priv_key.public_key.to_bn.to_s(2), + :bignum, priv_key.private_key).to_s + when /^ecdsa\-sha2\-(\w*)-cert-v01@openssh\.com$/ + Net::SSH::Buffer.from(:string, priv_key.to_blob, :bignum, priv_key.key.private_key).to_s + when /^ssh-ed25519$/ + Net::SSH::Buffer.from(:string, priv_key.public_key.verify_key.to_bytes, + :string, priv_key.sign_key.keypair_bytes).to_s + when /^ssh-ed25519-cert-v01@openssh\.com$/ + # Unlike the other certificate types, the public key is included after the certifiate. + Net::SSH::Buffer.from(:string, priv_key.to_blob, + :string, priv_key.key.public_key.verify_key.to_bytes, + :string, priv_key.key.sign_key.keypair_bytes).to_s + when /^ssh-rsa$/ + # `n` and `e` are reversed compared to the ordering in `OpenSSL::PKey::RSA#to_blob`. + Net::SSH::Buffer.from(:bignum, priv_key.n, :bignum, priv_key.e, :bignum, priv_key.d, + :bignum, priv_key.iqmp, :bignum, priv_key.p, :bignum, priv_key.q).to_s + when /^ssh-rsa-cert-v01@openssh\.com$/ + Net::SSH::Buffer.from(:string, priv_key.to_blob, :bignum, priv_key.key.d, + :bignum, priv_key.key.iqmp, :bignum, priv_key.key.p, + :bignum, priv_key.key.q).to_s + end + end end end; end; end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/net/ssh/authentication/certificate.rb new/lib/net/ssh/authentication/certificate.rb --- old/lib/net/ssh/authentication/certificate.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/lib/net/ssh/authentication/certificate.rb 2017-02-18 18:23:34.000000000 +0100 @@ -0,0 +1,169 @@ +require 'securerandom' + +module Net; module SSH; module Authentication + # Class for representing an SSH certificate. + # + # http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/usr.bin/ssh/PROTOCOL.certkeys?rev=1.10&content-type=text/plain + class Certificate + attr_accessor :nonce + attr_accessor :key + attr_accessor :serial + attr_accessor :type + attr_accessor :key_id + attr_accessor :valid_principals + attr_accessor :valid_after + attr_accessor :valid_before + attr_accessor :critical_options + attr_accessor :extensions + attr_accessor :reserved + attr_accessor :signature_key + attr_accessor :signature + + # Read a certificate blob associated with a key of the given type. + def self.read_certblob(buffer, type) + cert = Certificate.new + cert.nonce = buffer.read_string + cert.key = buffer.read_keyblob(type) + cert.serial = buffer.read_int64 + cert.type = type_symbol(buffer.read_long) + cert.key_id = buffer.read_string + cert.valid_principals = buffer.read_buffer.read_all(&:read_string) + cert.valid_after = Time.at(buffer.read_int64) + cert.valid_before = Time.at(buffer.read_int64) + cert.critical_options = read_options(buffer) + cert.extensions = read_options(buffer) + cert.reserved = buffer.read_string + cert.signature_key = buffer.read_buffer.read_key + cert.signature = buffer.read_string + cert + end + + def ssh_type + key.ssh_type + "-cert-...@openssh.com" + end + + def ssh_signature_type + key.ssh_type + end + + # Serializes the certificate (and key). + def to_blob + Buffer.from( + :raw, to_blob_without_signature, + :string, signature + ).to_s + end + + def ssh_do_sign(data) + key.ssh_do_sign(data) + end + + def ssh_do_verify(sig, data) + key.ssh_do_verify(sig, data) + end + + def to_pem + key.to_pem + end + + def fingerprint + key.fingerprint + end + + # Signs the certificate with key. + def sign!(key, sign_nonce=nil) + # ssh-keygen uses 32 bytes of nonce. + self.nonce = sign_nonce || SecureRandom.random_bytes(32) + self.signature_key = key + self.signature = Net::SSH::Buffer.from( + :string, key.ssh_signature_type, + :mstring, key.ssh_do_sign(to_blob_without_signature) + ).to_s + self + end + + def sign(key, sign_nonce=nil) + cert = clone + cert.sign!(key, sign_nonce) + end + + # Checks whether the certificate's signature was signed by signature key. + def signature_valid? + buffer = Buffer.new(signature) + buffer.read_string # skip signature format + signature_key.ssh_do_verify(buffer.read_string, to_blob_without_signature) + end + + def self.read_options(buffer) + names = [] + options = buffer.read_buffer.read_all do |b| + name = b.read_string + names << name + data = b.read_string + data = Buffer.new(data).read_string unless data.empty? + [name, data] + end + + if names.sort != names + raise ArgumentError, "option/extension names must be in sorted order" + end + + Hash[options] + end + private_class_method :read_options + + def self.type_symbol(type) + types = {1 => :user, 2 => :host} + raise ArgumentError("unsupported type: #{type}") unless types.include?(type) + types.fetch(type) + end + private_class_method :type_symbol + + private + + def type_value(type) + types = {user: 1, host: 2} + raise ArgumentError("unsupported type: #{type}") unless types.include?(type) + types.fetch(type) + end + + def ssh_time(t) + # Times in certificates are represented as a uint64. + [[t.to_i, 0].max, 2<<64 - 1].min + end + + def to_blob_without_signature + Buffer.from( + :string, ssh_type, + :string, nonce, + :raw, key_without_type, + :int64, serial, + :long, type_value(type), + :string, key_id, + :string, valid_principals.inject(Buffer.new) { |acc, elem| acc.write_string(elem) }.to_s, + :int64, ssh_time(valid_after), + :int64, ssh_time(valid_before), + :string, options_to_blob(critical_options), + :string, options_to_blob(extensions), + :string, reserved, + :string, signature_key.to_blob + ).to_s + end + + def key_without_type + # key.to_blob gives us e.g. "ssh-rsa,<key>" but we just want "<key>". + tmp = Buffer.new(key.to_blob) + tmp.read_string # skip the underlying key type + tmp.read + end + + def options_to_blob(options) + options.keys.sort.inject(Buffer.new) do |b, name| + b.write_string(name) + data = options.fetch(name) + data = Buffer.from(:string, data).to_s unless data.empty? + b.write_string(data) + end.to_s + end + end +end; end; end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/net/ssh/authentication/ed25519.rb new/lib/net/ssh/authentication/ed25519.rb --- old/lib/net/ssh/authentication/ed25519.rb 2017-01-07 15:36:27.000000000 +0100 +++ new/lib/net/ssh/authentication/ed25519.rb 2017-02-18 18:23:34.000000000 +0100 @@ -1,7 +1,11 @@ gem 'rbnacl', '>= 3.2.0', '< 5.0' gem 'bcrypt_pbkdf', '~> 1.0' unless RUBY_PLATFORM == "java" -require 'rbnacl/libsodium' +begin + require 'rbnacl/libsodium' +rescue LoadError # rubocop:disable Lint/HandleExceptions +end + require 'rbnacl' require 'rbnacl/signatures/ed25519/verify_key' require 'rbnacl/signatures/ed25519/signing_key' @@ -23,6 +27,8 @@ end class PubKey + attr_reader :verify_key + def initialize(data) @verify_key = RbNaCl::Signatures::Ed25519::VerifyKey.new(data) end @@ -39,6 +45,10 @@ "ssh-ed25519" end + def ssh_signature_type + ssh_type + end + def ssh_do_verify(sig,data) @verify_key.verify(sig,data) end @@ -60,6 +70,8 @@ MEND = "-----END OPENSSH PRIVATE KEY-----\n" MAGIC = "openssh-key-v1" + attr_reader :sign_key + def initialize(datafull,password) raise ArgumentError.new("Expected #{MBEGIN} at start of private key") unless datafull.start_with?(MBEGIN) raise ArgumentError.new("Expected #{MEND} at end of private key") unless datafull.end_with?(MEND) @@ -116,6 +128,18 @@ @sign_key = SigningKeyFromFile.new(pk,sk) end + def to_blob + public_key.to_blob + end + + def ssh_type + "ssh-ed25519" + end + + def ssh_signature_type + ssh_type + end + def public_key PubKey.new(@pk) end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/net/ssh/authentication/ed25519_loader.rb new/lib/net/ssh/authentication/ed25519_loader.rb --- old/lib/net/ssh/authentication/ed25519_loader.rb 2017-01-07 15:36:27.000000000 +0100 +++ new/lib/net/ssh/authentication/ed25519_loader.rb 2017-02-18 18:23:34.000000000 +0100 @@ -14,7 +14,7 @@ end def self.raiseUnlessLoaded(message) - description = dependenciesRequiredForED25519 if ERROR.is_a?(Gem::LoadError) + description = ERROR.is_a?(LoadError) ? dependenciesRequiredForED25519 : '' description << "#{ERROR.class} : \"#{ERROR.message}\"\n" if ERROR raise NotImplementedError, "#{message}\n#{description}" unless LOADED end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/net/ssh/authentication/key_manager.rb new/lib/net/ssh/authentication/key_manager.rb --- old/lib/net/ssh/authentication/key_manager.rb 2017-01-07 15:36:27.000000000 +0100 +++ new/lib/net/ssh/authentication/key_manager.rb 2017-02-18 18:23:34.000000000 +0100 @@ -146,7 +146,7 @@ end if info[:key] - return Net::SSH::Buffer.from(:string, identity.ssh_type, + return Net::SSH::Buffer.from(:string, identity.ssh_signature_type, :mstring, info[:key].ssh_do_sign(data.to_s)).to_s end @@ -189,8 +189,12 @@ key_files.map do |file| if readable_file?(file) identity = {} + cert_file = file + "-cert.pub" public_key_file = file + ".pub" - if readable_file?(public_key_file) + if readable_file?(cert_file) + identity[:load_from] = :pubkey_file + identity[:pubkey_file] = cert_file + elsif readable_file?(public_key_file) identity[:load_from] = :pubkey_file identity[:pubkey_file] = public_key_file else diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/net/ssh/buffer.rb new/lib/net/ssh/buffer.rb --- old/lib/net/ssh/buffer.rb 2017-01-07 15:36:28.000000000 +0100 +++ new/lib/net/ssh/buffer.rb 2017-02-18 18:23:34.000000000 +0100 @@ -1,6 +1,7 @@ require 'net/ssh/ruby_compat' require 'net/ssh/transport/openssl' +require 'net/ssh/authentication/certificate' require 'net/ssh/authentication/ed25519_loader' module Net; module SSH @@ -186,6 +187,11 @@ data end + # Calls block(self) until the buffer is empty, and returns all results. + def read_all(&block) + Enumerator.new { |e| e << yield(self) until eof? }.to_a + end + # Return the next 8 bytes as a 64-bit integer (in network byte order). # Returns nil if there are less than 8 bytes remaining to be read in the # buffer. @@ -246,7 +252,9 @@ # a key. Only RSA, DSA, and ECDSA keys are supported. def read_keyblob(type) case type - when /^ssh-dss(-cert-v01@openssh\.com)?$/ + when /^(.*)-cert-v01@openssh\.com$/ + key = Net::SSH::Authentication::Certificate.read_certblob(self, $1) + when /^ssh-dss$/ key = OpenSSL::PKey::DSA.new if key.respond_to?(:set_pqg) key.set_pqg(read_bignum, read_bignum, read_bignum) @@ -260,8 +268,7 @@ else key.pub_key = read_bignum end - - when /^ssh-rsa(-cert-v01@openssh\.com)?$/ + when /^ssh-rsa$/ key = OpenSSL::PKey::RSA.new if key.respond_to?(:set_key) e = read_bignum diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/net/ssh/config.rb new/lib/net/ssh/config.rb --- old/lib/net/ssh/config.rb 2017-01-07 15:36:28.000000000 +0100 +++ new/lib/net/ssh/config.rb 2017-02-18 18:23:34.000000000 +0100 @@ -27,6 +27,7 @@ # * Port => :port # * PreferredAuthentications => maps to the :auth_methods option # * ProxyCommand => maps to the :proxy option + # * ProxyJump => maps to the :proxy option # * PubKeyAuthentication => maps to the :auth_methods option # * RekeyLimit => :rekey_limit # * User => :user @@ -156,93 +157,7 @@ auth_methods = default_auth_methods.clone (auth_methods << 'challenge-response').uniq! ret = settings.inject({auth_methods: auth_methods}) do |hash, (key, value)| - case key - when 'bindaddress' then - hash[:bind_address] = value - when 'ciphers' then - hash[:encryption] = value.split(/,/) - when 'compression' then - hash[:compression] = value - when 'compressionlevel' then - hash[:compression_level] = value - when 'connecttimeout' then - hash[:timeout] = value - when 'forwardagent' then - hash[:forward_agent] = value - when 'identitiesonly' then - hash[:keys_only] = value - when 'globalknownhostsfile' - hash[:global_known_hosts_file] = value - when 'hostbasedauthentication' then - if value - (hash[:auth_methods] << "hostbased").uniq! - else - hash[:auth_methods].delete("hostbased") - end - when 'hostkeyalgorithms' then - hash[:host_key] = value.split(/,/) - when 'hostkeyalias' then - hash[:host_key_alias] = value - when 'hostname' then - hash[:host_name] = value.gsub(/%h/, settings['host']) - when 'identityfile' then - hash[:keys] = value - when 'macs' then - hash[:hmac] = value.split(/,/) - when 'serveralivecountmax' - hash[:keepalive_maxcount] = value.to_i if value - when 'serveraliveinterval' - if value && value.to_i > 0 - hash[:keepalive] = true - hash[:keepalive_interval] = value.to_i - else - hash[:keepalive] = false - end - when 'passwordauthentication' - if value - (hash[:auth_methods] << 'password').uniq! - else - hash[:auth_methods].delete('password') - end - when 'challengeresponseauthentication' - if value - (hash[:auth_methods] << 'challenge-response').uniq! - else - hash[:auth_methods].delete('challenge-response') - end - when 'kbdinteractiveauthentication' - if value - (hash[:auth_methods] << 'keyboard-interactive').uniq! - else - hash[:auth_methods].delete('keyboard-interactive') - end - when 'port' - hash[:port] = value - when 'preferredauthentications' - hash[:auth_methods] = value.split(/,/) # TODO we should place to preferred_auth_methods rather than auth_methods - when 'proxycommand' - if value and !(value =~ /^none$/) - require 'net/ssh/proxy/command' - hash[:proxy] = Net::SSH::Proxy::Command.new(value) - end - when 'pubkeyauthentication' - if value - (hash[:auth_methods] << 'publickey').uniq! - else - hash[:auth_methods].delete('publickey') - end - when 'rekeylimit' - hash[:rekey_limit] = interpret_size(value) - when 'user' - hash[:user] = value - when 'userknownhostsfile' - hash[:user_known_hosts_file] = value - when 'sendenv' - multi_send_env = value.to_s.split(/\s+/) - hash[:send_env] = multi_send_env.map { |e| Regexp.new pattern2regex(e).source, false } - when 'numberofpasswordprompts' - hash[:number_of_password_prompts] = value.to_i - end + translate_config_key(hash, key.to_sym, value, settings) hash end merge_challenge_response_with_keyboard_interactive(ret) @@ -262,6 +177,93 @@ private + 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, + globalknownhostsfile: :global_known_hosts_file, + hostkeyalias: :host_key_alias, + identityfile: :keys, + port: :port, + user: :user, + userknownhostsfile: :user_known_hosts_file + } + case key + when :ciphers + hash[:encryption] = value.split(/,/) + when :hostbasedauthentication + if value + (hash[:auth_methods] << "hostbased").uniq! + else + hash[:auth_methods].delete("hostbased") + end + when :hostkeyalgorithms + hash[:host_key] = value.split(/,/) + when :hostname + hash[:host_name] = value.gsub(/%h/, settings['host']) + when :macs + hash[:hmac] = value.split(/,/) + when :serveralivecountmax + hash[:keepalive_maxcount] = value.to_i if value + when :serveraliveinterval + if value && value.to_i > 0 + hash[:keepalive] = true + hash[:keepalive_interval] = value.to_i + else + hash[:keepalive] = false + end + when :passwordauthentication + if value + (hash[:auth_methods] << 'password').uniq! + else + hash[:auth_methods].delete('password') + end + when :challengeresponseauthentication + if value + (hash[:auth_methods] << 'challenge-response').uniq! + else + hash[:auth_methods].delete('challenge-response') + end + when :kbdinteractiveauthentication + if value + (hash[:auth_methods] << 'keyboard-interactive').uniq! + else + hash[:auth_methods].delete('keyboard-interactive') + end + when :preferredauthentications + hash[:auth_methods] = value.split(/,/) # TODO we should place to preferred_auth_methods rather than auth_methods + when :proxycommand + if value and !(value =~ /^none$/) + require 'net/ssh/proxy/command' + hash[:proxy] = Net::SSH::Proxy::Command.new(value) + end + when :proxyjump + if value + require 'net/ssh/proxy/jump' + hash[:proxy] = Net::SSH::Proxy::Jump.new(value) + end + when :pubkeyauthentication + if value + (hash[:auth_methods] << 'publickey').uniq! + else + hash[:auth_methods].delete('publickey') + end + when :rekeylimit + hash[:rekey_limit] = interpret_size(value) + when :sendenv + multi_send_env = value.to_s.split(/\s+/) + 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 + end + end + # Converts an ssh_config pattern into a regex for matching against # host names. def pattern2regex(pattern) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/net/ssh/connection/channel.rb new/lib/net/ssh/connection/channel.rb --- old/lib/net/ssh/connection/channel.rb 2017-01-07 15:36:28.000000000 +0100 +++ new/lib/net/ssh/connection/channel.rb 2017-02-18 18:23:34.000000000 +0100 @@ -613,7 +613,7 @@ if callback = pending_requests.shift callback.call(self, false) else - error { "channel failure recieved with no pending request to handle it (bug?)" } + error { "channel failure received with no pending request to handle it (bug?)" } end end @@ -623,7 +623,7 @@ if callback = pending_requests.shift callback.call(self, true) else - error { "channel success recieved with no pending request to handle it (bug?)" } + error { "channel success received with no pending request to handle it (bug?)" } end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/net/ssh/key_factory.rb new/lib/net/ssh/key_factory.rb --- old/lib/net/ssh/key_factory.rb 2017-01-07 15:36:28.000000000 +0100 +++ new/lib/net/ssh/key_factory.rb 2017-02-18 18:23:34.000000000 +0100 @@ -93,7 +93,7 @@ blob = nil begin blob = fields.shift - end while !blob.nil? && !/^(ssh-(rsa|dss|ed25519)|ecdsa-sha2-nistp\d+)$/.match(blob) + end while !blob.nil? && !/^(ssh-(rsa|dss|ed25519)|ecdsa-sha2-nistp\d+)(-cert-v01@openssh\.com)?$/.match(blob) blob = fields.shift raise Net::SSH::Exception, "public key at #{filename} is not valid" if blob.nil? diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/net/ssh/proxy/jump.rb new/lib/net/ssh/proxy/jump.rb --- old/lib/net/ssh/proxy/jump.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/lib/net/ssh/proxy/jump.rb 2017-02-18 18:23:34.000000000 +0100 @@ -0,0 +1,53 @@ +require 'uri' +require 'net/ssh/proxy/command' + +module Net; module SSH; module Proxy + + # An implementation of a jump proxy. To use it, instantiate it, + # then pass the instantiated object via the :proxy key to + # Net::SSH.start: + # + # require 'net/ssh/proxy/jump' + # + # proxy = Net::SSH::Proxy::Jump.new('user@proxy') + # Net::SSH.start('host', 'user', :proxy => proxy) do |ssh| + # ... + # end + class Jump < Command + + # The jump proxies + attr_reader :jump_proxies + + # Create a new socket factory that tunnels via multiple jump proxes as + # [user@]host[:port]. + def initialize(jump_proxies) + @jump_proxies = jump_proxies + end + + # Return a new socket connected to the given host and port via the jump + # proxy that was requested when the socket factory was instantiated. + def open(host, port, connection_options = nil) + build_proxy_command_equivalent(connection_options) + super + end + + # We cannot build the ProxyCommand template until we know if the :config + # option was specified during `Net::SSH.start`. + def build_proxy_command_equivalent(connection_options = nil) + first_jump, extra_jumps = jump_proxies.split(",", 2) + config = connection_options && connection_options[:config] + uri = URI.parse("ssh://#{first_jump}") + + template = "ssh" + template << " -l #{uri.user}" if uri.user + template << " -p #{uri.port}" if uri.port + template << " -J #{extra_jumps}" if extra_jumps + template << " -F #{config}" if config != true && config + template << " -W %h:%p " + template << uri.host + + @command_line_template = template + end + end + +end; end; end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/net/ssh/transport/algorithms.rb new/lib/net/ssh/transport/algorithms.rb --- old/lib/net/ssh/transport/algorithms.rb 2017-01-07 15:36:28.000000000 +0100 +++ new/lib/net/ssh/transport/algorithms.rb 2017-02-18 18:23:34.000000000 +0100 @@ -121,7 +121,7 @@ # Start the algorithm negotation def start - raise ArgumentError, "Cannot call start if it's negoitation started or done" if @pending || @initialized + raise ArgumentError, "Cannot call start if it's negotiation started or done" if @pending || @initialized send_kexinit end @@ -135,7 +135,7 @@ send_kexinit end - # Called by the transport layer when a KEXINIT packet is recieved, indicating + # Called by the transport layer when a KEXINIT packet is received, indicating # that the server wants to exchange keys. This can be spontaneous, or it # can be in response to a client-initiated rekey request (see #rekey!). Either # way, this will block until the key exchange completes. @@ -263,7 +263,7 @@ is_supported end - lwarn { "unsupported #{algorithm} algorithm: `#{unsupported}'" } unless unsupported.empty? + lwarn { %(unsupported algorithm: `#{unsupported}') } unless unsupported.empty? list end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/net/ssh/transport/openssl.rb new/lib/net/ssh/transport/openssl.rb --- old/lib/net/ssh/transport/openssl.rb 2017-01-07 15:36:28.000000000 +0100 +++ new/lib/net/ssh/transport/openssl.rb 2017-02-18 18:23:34.000000000 +0100 @@ -60,6 +60,10 @@ "ssh-rsa" end + def ssh_signature_type + ssh_type + end + # Converts the key to a blob, according to the SSH2 protocol. def to_blob @blob ||= Net::SSH::Buffer.from(:string, ssh_type, :bignum, e, :bignum, n).to_s @@ -87,6 +91,10 @@ "ssh-dss" end + def ssh_signature_type + ssh_type + end + # Converts the key to a blob, according to the SSH2 protocol. def to_blob @blob ||= Net::SSH::Buffer.from(:string, ssh_type, @@ -165,6 +173,10 @@ "ecdsa-sha2-#{CurveNameAliasInv[self.group.curve_name]}" end + def ssh_signature_type + ssh_type + end + def digester if self.group.curve_name =~ /^[a-z]+(\d+)\w*\z/ curve_size = $1.to_i diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/net/ssh/transport/session.rb new/lib/net/ssh/transport/session.rb --- old/lib/net/ssh/transport/session.rb 2017-01-07 15:36:28.000000000 +0100 +++ new/lib/net/ssh/transport/session.rb 2017-02-18 18:23:34.000000000 +0100 @@ -198,7 +198,7 @@ raise Net::SSH::Disconnect, "disconnected: #{packet[:description]} (#{packet[:reason_code]})" when IGNORE - debug { "IGNORE packet recieved: #{packet[:data].inspect}" } + debug { "IGNORE packet received: #{packet[:data].inspect}" } when UNIMPLEMENTED lwarn { "UNIMPLEMENTED: #{packet[:number]}" } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/net/ssh/version.rb new/lib/net/ssh/version.rb --- old/lib/net/ssh/version.rb 2017-01-07 15:36:28.000000000 +0100 +++ new/lib/net/ssh/version.rb 2017-02-18 18:23:34.000000000 +0100 @@ -48,10 +48,10 @@ MAJOR = 4 # The minor component of this version of the Net::SSH library - MINOR = 0 + MINOR = 1 # The tiny component of this version of the Net::SSH library - TINY = 1 + TINY = 0 # The prerelease component of this version of the Net::SSH library # nil allowed diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/metadata new/metadata --- old/metadata 2017-01-07 15:36:27.000000000 +0100 +++ new/metadata 2017-02-18 18:23:34.000000000 +0100 @@ -1,7 +1,7 @@ --- !ruby/object:Gem::Specification name: net-ssh version: !ruby/object:Gem::Version - version: 4.0.1 + version: 4.1.0 platform: ruby authors: - Jamis Buck @@ -32,7 +32,7 @@ L4d54WIy4HkZCqQXoTSiK5HZMIdXkPk3F1bZdJ8Dy1sMRru0rUkkM5mW7TQ75mfW Zp0QrZyNZhtitrXFbZneGRrIA/8G2Krft5Ly/A== -----END CERTIFICATE----- -date: 2017-01-07 00:00:00.000000000 Z +date: 2017-02-18 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency requirement: !ruby/object:Gem::Requirement @@ -166,6 +166,7 @@ - appveyor.yml - lib/net/ssh.rb - lib/net/ssh/authentication/agent.rb +- lib/net/ssh/authentication/certificate.rb - lib/net/ssh/authentication/constants.rb - lib/net/ssh/authentication/ed25519.rb - lib/net/ssh/authentication/ed25519_loader.rb @@ -197,6 +198,7 @@ - lib/net/ssh/proxy/errors.rb - lib/net/ssh/proxy/http.rb - lib/net/ssh/proxy/https.rb +- lib/net/ssh/proxy/jump.rb - lib/net/ssh/proxy/socks4.rb - lib/net/ssh/proxy/socks5.rb - lib/net/ssh/ruby_compat.rb Binary files old/metadata.gz.sig and new/metadata.gz.sig differ