net-ssh 5.2.0 → 6.0.0.beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +7 -4
- data/.rubocop_todo.yml +389 -379
- data/.travis.yml +13 -14
- data/CHANGES.txt +7 -0
- data/README.md +286 -0
- data/Rakefile +1 -2
- data/appveyor.yml +4 -2
- data/lib/net/ssh/authentication/key_manager.rb +7 -3
- data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +3 -1
- data/lib/net/ssh/authentication/pub_key_fingerprint.rb +0 -1
- data/lib/net/ssh/authentication/session.rb +2 -6
- data/lib/net/ssh/buffer.rb +1 -9
- data/lib/net/ssh/config.rb +25 -10
- data/lib/net/ssh/connection/channel.rb +7 -3
- data/lib/net/ssh/connection/session.rb +7 -3
- data/lib/net/ssh/key_factory.rb +6 -8
- data/lib/net/ssh/known_hosts.rb +26 -29
- data/lib/net/ssh/service/forward.rb +2 -1
- data/lib/net/ssh/test.rb +3 -2
- data/lib/net/ssh/transport/algorithms.rb +67 -42
- data/lib/net/ssh/transport/cipher_factory.rb +11 -27
- data/lib/net/ssh/transport/constants.rb +10 -6
- data/lib/net/ssh/transport/ctr.rb +1 -7
- data/lib/net/ssh/transport/hmac.rb +15 -13
- data/lib/net/ssh/transport/hmac/abstract.rb +16 -0
- data/lib/net/ssh/transport/hmac/sha2_256.rb +7 -11
- data/lib/net/ssh/transport/hmac/sha2_256_96.rb +4 -8
- data/lib/net/ssh/transport/hmac/sha2_256_etm.rb +12 -0
- data/lib/net/ssh/transport/hmac/sha2_512.rb +6 -9
- data/lib/net/ssh/transport/hmac/sha2_512_96.rb +4 -8
- data/lib/net/ssh/transport/hmac/sha2_512_etm.rb +12 -0
- data/lib/net/ssh/transport/kex.rb +13 -11
- data/lib/net/ssh/transport/kex/abstract.rb +123 -0
- data/lib/net/ssh/transport/kex/abstract5656.rb +72 -0
- data/lib/net/ssh/transport/kex/curve25519_sha256.rb +38 -0
- data/lib/net/ssh/transport/kex/curve25519_sha256_loader.rb +30 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +1 -15
- data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +9 -118
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +0 -6
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +5 -9
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +18 -79
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +5 -4
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +5 -4
- data/lib/net/ssh/transport/openssl.rb +104 -107
- data/lib/net/ssh/transport/packet_stream.rb +44 -10
- data/lib/net/ssh/transport/state.rb +1 -1
- data/lib/net/ssh/version.rb +3 -3
- data/net-ssh.gemspec +8 -6
- metadata +35 -16
- metadata.gz.sig +0 -0
- data/Gemfile.noed25519.lock +0 -41
- data/README.rdoc +0 -194
- data/support/arcfour_check.rb +0 -20
data/lib/net/ssh/buffer.rb
CHANGED
@@ -323,15 +323,7 @@ module Net
|
|
323
323
|
Net::SSH::Authentication::ED25519Loader.raiseUnlessLoaded("unsupported key type `#{type}'")
|
324
324
|
key = Net::SSH::Authentication::ED25519::PubKey.read_keyblob(self)
|
325
325
|
when /^ecdsa\-sha2\-(\w*)$/
|
326
|
-
|
327
|
-
raise NotImplementedError, "unsupported key type `#{type}'"
|
328
|
-
else
|
329
|
-
begin
|
330
|
-
key = OpenSSL::PKey::EC.read_keyblob($1, self)
|
331
|
-
rescue OpenSSL::PKey::ECError
|
332
|
-
raise NotImplementedError, "unsupported key type `#{type}'"
|
333
|
-
end
|
334
|
-
end
|
326
|
+
key = OpenSSL::PKey::EC.read_keyblob($1, self)
|
335
327
|
else
|
336
328
|
raise NotImplementedError, "unsupported key type `#{type}'"
|
337
329
|
end
|
data/lib/net/ssh/config.rb
CHANGED
@@ -33,6 +33,7 @@ module Net
|
|
33
33
|
# * ProxyJump => maps to the :proxy option
|
34
34
|
# * PubKeyAuthentication => maps to the :auth_methods option
|
35
35
|
# * RekeyLimit => :rekey_limit
|
36
|
+
# * StrictHostKeyChecking => :strict_host_key_checking
|
36
37
|
# * User => :user
|
37
38
|
# * UserKnownHostsFile => :user_known_hosts_file
|
38
39
|
# * NumberOfPasswordPrompts => :number_of_password_prompts
|
@@ -149,6 +150,13 @@ module Net
|
|
149
150
|
settings[key] = value unless settings.key?(key)
|
150
151
|
end
|
151
152
|
end
|
153
|
+
|
154
|
+
# ProxyCommand and ProxyJump override each other so they need to be tracked togeather
|
155
|
+
%w[proxyjump proxycommand].each do |proxy_key|
|
156
|
+
if (proxy_value = settings.delete(proxy_key))
|
157
|
+
settings['proxy'] ||= [proxy_key, proxy_value]
|
158
|
+
end
|
159
|
+
end
|
152
160
|
end
|
153
161
|
|
154
162
|
globals.merge(settings) do |key, oldval, newval|
|
@@ -202,6 +210,7 @@ module Net
|
|
202
210
|
identityfile: :keys,
|
203
211
|
fingerprinthash: :fingerprint_hash,
|
204
212
|
port: :port,
|
213
|
+
stricthostkeychecking: :strict_host_key_checking,
|
205
214
|
user: :user,
|
206
215
|
userknownhostsfile: :user_known_hosts_file,
|
207
216
|
checkhostip: :check_host_ip
|
@@ -250,15 +259,9 @@ module Net
|
|
250
259
|
end
|
251
260
|
when :preferredauthentications
|
252
261
|
hash[:auth_methods] = value.split(/,/) # TODO we should place to preferred_auth_methods rather than auth_methods
|
253
|
-
when :
|
254
|
-
if
|
255
|
-
|
256
|
-
hash[:proxy] = Net::SSH::Proxy::Command.new(value)
|
257
|
-
end
|
258
|
-
when :proxyjump
|
259
|
-
if value
|
260
|
-
require 'net/ssh/proxy/jump'
|
261
|
-
hash[:proxy] = Net::SSH::Proxy::Jump.new(value)
|
262
|
+
when :proxy
|
263
|
+
if (proxy = setup_proxy(*value))
|
264
|
+
hash[:proxy] = proxy
|
262
265
|
end
|
263
266
|
when :pubkeyauthentication
|
264
267
|
if value
|
@@ -278,6 +281,19 @@ module Net
|
|
278
281
|
end
|
279
282
|
end
|
280
283
|
|
284
|
+
def setup_proxy(type, value)
|
285
|
+
case type
|
286
|
+
when 'proxycommand'
|
287
|
+
if value !~ /^none$/
|
288
|
+
require 'net/ssh/proxy/command'
|
289
|
+
Net::SSH::Proxy::Command.new(value)
|
290
|
+
end
|
291
|
+
when 'proxyjump'
|
292
|
+
require 'net/ssh/proxy/jump'
|
293
|
+
Net::SSH::Proxy::Jump.new(value)
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
281
297
|
# Converts an ssh_config pattern into a regex for matching against
|
282
298
|
# host names.
|
283
299
|
def pattern2regex(pattern)
|
@@ -369,6 +385,5 @@ module Net
|
|
369
385
|
end
|
370
386
|
end
|
371
387
|
end
|
372
|
-
|
373
388
|
end
|
374
389
|
end
|
@@ -648,10 +648,14 @@ module Net
|
|
648
648
|
def update_local_window_size(size)
|
649
649
|
@local_window_size -= size
|
650
650
|
if local_window_size < local_maximum_window_size / 2
|
651
|
-
connection.send_message(
|
652
|
-
:long, remote_id, :long, LOCAL_WINDOW_SIZE_INCREMENT)
|
651
|
+
connection.send_message(
|
652
|
+
Buffer.from(:byte, CHANNEL_WINDOW_ADJUST, :long, remote_id, :long, LOCAL_WINDOW_SIZE_INCREMENT)
|
653
|
+
)
|
653
654
|
@local_window_size += LOCAL_WINDOW_SIZE_INCREMENT
|
654
|
-
|
655
|
+
|
656
|
+
if @local_maximum_window_size < @local_window_size || @local_maximum_window_size < GOOD_LOCAL_MAXIUMUM_WINDOW_SIZE
|
657
|
+
@local_maximum_window_size += LOCAL_WINDOW_SIZE_INCREMENT
|
658
|
+
end
|
655
659
|
end
|
656
660
|
end
|
657
661
|
|
@@ -580,8 +580,10 @@ module Net
|
|
580
580
|
info { "global request received: #{packet[:request_type]} #{packet[:want_reply]}" }
|
581
581
|
callback = @on_global_request[packet[:request_type]]
|
582
582
|
result = callback ? callback.call(packet[:request_data], packet[:want_reply]) : false
|
583
|
-
|
584
|
-
|
583
|
+
|
584
|
+
if result != :sent && result != true && result != false
|
585
|
+
raise "expected global request handler for `#{packet[:request_type]}' to return true, false, or :sent, but got #{result.inspect}"
|
586
|
+
end
|
585
587
|
|
586
588
|
if packet[:want_reply] && result != :sent
|
587
589
|
msg = Buffer.from(:byte, result ? REQUEST_SUCCESS : REQUEST_FAILURE)
|
@@ -624,7 +626,9 @@ module Net
|
|
624
626
|
failure = [err.code, err.reason]
|
625
627
|
else
|
626
628
|
channels[local_id] = channel
|
627
|
-
msg = Buffer.from(:byte, CHANNEL_OPEN_CONFIRMATION, :long, channel.remote_id, :long,
|
629
|
+
msg = Buffer.from(:byte, CHANNEL_OPEN_CONFIRMATION, :long, channel.remote_id, :long,
|
630
|
+
channel.local_id, :long, channel.local_maximum_window_size, :long,
|
631
|
+
channel.local_maximum_packet_size)
|
628
632
|
end
|
629
633
|
else
|
630
634
|
failure = [3, "unknown channel type #{channel.type}"]
|
data/lib/net/ssh/key_factory.rb
CHANGED
@@ -18,14 +18,12 @@ module Net
|
|
18
18
|
class KeyFactory
|
19
19
|
# Specifies the mapping of SSH names to OpenSSL key classes.
|
20
20
|
MAP = {
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
'dh' => OpenSSL::PKey::DH,
|
22
|
+
'rsa' => OpenSSL::PKey::RSA,
|
23
|
+
'dsa' => OpenSSL::PKey::DSA,
|
24
|
+
'ecdsa' => OpenSSL::PKey::EC
|
24
25
|
}
|
25
|
-
if defined?
|
26
|
-
MAP["ecdsa"] = OpenSSL::PKey::EC
|
27
|
-
MAP["ed25519"] = Net::SSH::Authentication::ED25519::PrivKey if defined? Net::SSH::Authentication::ED25519
|
28
|
-
end
|
26
|
+
MAP["ed25519"] = Net::SSH::Authentication::ED25519::PrivKey if defined? Net::SSH::Authentication::ED25519
|
29
27
|
|
30
28
|
class <<self
|
31
29
|
# Fetch an OpenSSL key instance by its SSH name. It will be a new,
|
@@ -207,7 +205,7 @@ module Net
|
|
207
205
|
return OpenSSLDSAKeyType
|
208
206
|
elsif data.match(/-----BEGIN RSA PRIVATE KEY-----/)
|
209
207
|
return OpenSSLRSAKeyType
|
210
|
-
elsif data.match(/-----BEGIN EC PRIVATE KEY-----/)
|
208
|
+
elsif data.match(/-----BEGIN EC PRIVATE KEY-----/)
|
211
209
|
return OpenSSLECKeyType
|
212
210
|
elsif data.match(/-----BEGIN (.+) PRIVATE KEY-----/)
|
213
211
|
raise OpenSSL::PKey::PKeyError, "not a supported key type '#{$1}'"
|
data/lib/net/ssh/known_hosts.rb
CHANGED
@@ -41,14 +41,11 @@ module Net
|
|
41
41
|
# This is used internally by Net::SSH, and will never need to be used directly
|
42
42
|
# by consumers of the library.
|
43
43
|
class KnownHosts
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
else
|
50
|
-
SUPPORTED_TYPE = %w[ssh-rsa ssh-dss]
|
51
|
-
end
|
44
|
+
SUPPORTED_TYPE = %w[ssh-rsa ssh-dss
|
45
|
+
ecdsa-sha2-nistp256
|
46
|
+
ecdsa-sha2-nistp384
|
47
|
+
ecdsa-sha2-nistp521]
|
48
|
+
|
52
49
|
SUPPORTED_TYPE.push('ssh-ed25519') if Net::SSH::Authentication::ED25519Loader::LOADED
|
53
50
|
|
54
51
|
class <<self
|
@@ -78,7 +75,9 @@ module Net
|
|
78
75
|
|
79
76
|
files += Array(options[:user_known_hosts_file] || %w[~/.ssh/known_hosts ~/.ssh/known_hosts2]) if which == :all || which == :user
|
80
77
|
|
81
|
-
|
78
|
+
if which == :all || which == :global
|
79
|
+
files += Array(options[:global_known_hosts_file] || %w[/etc/ssh/ssh_known_hosts /etc/ssh/ssh_known_hosts2])
|
80
|
+
end
|
82
81
|
|
83
82
|
return files
|
84
83
|
end
|
@@ -130,27 +129,21 @@ module Net
|
|
130
129
|
host_ip = entries[1]
|
131
130
|
|
132
131
|
File.open(source) do |file|
|
133
|
-
scanner = StringScanner.new("")
|
134
132
|
file.each_line do |line|
|
135
|
-
|
133
|
+
hosts, type, key_content = line.split(' ')
|
134
|
+
next unless hosts || hosts.start_with?('#')
|
136
135
|
|
137
|
-
|
138
|
-
|
136
|
+
hostlist = hosts.split(',')
|
137
|
+
|
138
|
+
next unless SUPPORTED_TYPE.include?(type)
|
139
139
|
|
140
|
-
hostlist = scanner.scan(/\S+/).split(/,/)
|
141
140
|
found = hostlist.any? { |pattern| match(host_name, pattern) } || known_host_hash?(hostlist, entries)
|
142
141
|
next unless found
|
143
142
|
|
144
143
|
found = hostlist.include?(host_ip) if options[:check_host_ip] && entries.size > 1 && hostlist.size > 1
|
145
144
|
next unless found
|
146
145
|
|
147
|
-
|
148
|
-
type = scanner.scan(/\S+/)
|
149
|
-
|
150
|
-
next unless SUPPORTED_TYPE.include?(type)
|
151
|
-
|
152
|
-
scanner.skip(/\s*/)
|
153
|
-
blob = scanner.rest.unpack("m*").first
|
146
|
+
blob = key_content.unpack("m*").first
|
154
147
|
keys << Net::SSH::Buffer.new(blob).read_key
|
155
148
|
end
|
156
149
|
end
|
@@ -159,14 +152,18 @@ module Net
|
|
159
152
|
end
|
160
153
|
|
161
154
|
def match(host, pattern)
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
155
|
+
if pattern.include?('*') || pattern.include?('?')
|
156
|
+
# see man 8 sshd for pattern details
|
157
|
+
pattern_regexp = pattern.split('*').map do |x|
|
158
|
+
x.split('?').map do |y|
|
159
|
+
Regexp.escape(y)
|
160
|
+
end.join('.')
|
161
|
+
end.join('[^.]*')
|
162
|
+
|
163
|
+
host =~ Regexp.new("\\A#{pattern_regexp}\\z")
|
164
|
+
else
|
165
|
+
host == pattern
|
166
|
+
end
|
170
167
|
end
|
171
168
|
|
172
169
|
# Indicates whether one of the entries matches an hostname that has been
|
@@ -85,7 +85,8 @@ module Net
|
|
85
85
|
client = server.accept
|
86
86
|
debug { "received connection on #{socket}" }
|
87
87
|
|
88
|
-
channel = session.open_channel("direct-tcpip", :string, remote_host, :long,
|
88
|
+
channel = session.open_channel("direct-tcpip", :string, remote_host, :long,
|
89
|
+
remote_port, :string, bind_address, local_port_type, local_port) do |achannel|
|
89
90
|
achannel.info { "direct channel established" }
|
90
91
|
end
|
91
92
|
|
data/lib/net/ssh/test.rb
CHANGED
@@ -74,7 +74,7 @@ module Net
|
|
74
74
|
def transport(options={})
|
75
75
|
@transport ||= Net::SSH::Transport::Session.new(
|
76
76
|
options[:host] || "localhost",
|
77
|
-
options.merge(kex: "test", host_key: "ssh-rsa", verify_host_key: :never, proxy: socket(options))
|
77
|
+
options.merge(kex: "test", host_key: "ssh-rsa", append_all_supported_algorithms: true, verify_host_key: :never, proxy: socket(options))
|
78
78
|
)
|
79
79
|
end
|
80
80
|
|
@@ -86,7 +86,8 @@ module Net
|
|
86
86
|
def assert_scripted
|
87
87
|
raise "there is no script to be processed" if socket.script.events.empty?
|
88
88
|
Net::SSH::Test::Extensions::IO.with_test_extension { yield }
|
89
|
-
assert socket.script.events.empty?, "there should not be any remaining scripted events, but there are still
|
89
|
+
assert socket.script.events.empty?, "there should not be any remaining scripted events, but there are still" \
|
90
|
+
"#{socket.script.events.length} pending"
|
90
91
|
end
|
91
92
|
end
|
92
93
|
|
@@ -5,13 +5,13 @@ require 'net/ssh/transport/cipher_factory'
|
|
5
5
|
require 'net/ssh/transport/constants'
|
6
6
|
require 'net/ssh/transport/hmac'
|
7
7
|
require 'net/ssh/transport/kex'
|
8
|
+
require 'net/ssh/transport/kex/curve25519_sha256_loader'
|
8
9
|
require 'net/ssh/transport/server_version'
|
9
10
|
require 'net/ssh/authentication/ed25519_loader'
|
10
11
|
|
11
12
|
module Net
|
12
13
|
module SSH
|
13
14
|
module Transport
|
14
|
-
|
15
15
|
# Implements the higher-level logic behind an SSH key-exchange. It handles
|
16
16
|
# both the initial exchange, as well as subsequent re-exchanges (as needed).
|
17
17
|
# It also encapsulates the negotiation of the algorithms, and provides a
|
@@ -23,56 +23,72 @@ module Net
|
|
23
23
|
include Loggable
|
24
24
|
include Constants
|
25
25
|
|
26
|
-
# Define the default algorithms, in order of preference, supported by
|
27
|
-
|
28
|
-
|
29
|
-
|
26
|
+
# Define the default algorithms, in order of preference, supported by Net::SSH.
|
27
|
+
DEFAULT_ALGORITHMS = {
|
28
|
+
host_key: %w[ecdsa-sha2-nistp521-cert-v01@openssh.com
|
29
|
+
ecdsa-sha2-nistp384-cert-v01@openssh.com
|
30
|
+
ecdsa-sha2-nistp256-cert-v01@openssh.com
|
31
|
+
ecdsa-sha2-nistp521
|
32
|
+
ecdsa-sha2-nistp384
|
33
|
+
ecdsa-sha2-nistp256
|
34
|
+
ssh-rsa-cert-v01@openssh.com
|
30
35
|
ssh-rsa-cert-v00@openssh.com
|
31
|
-
ssh-rsa
|
32
|
-
|
33
|
-
|
34
|
-
|
36
|
+
ssh-rsa],
|
37
|
+
|
38
|
+
kex: %w[ecdh-sha2-nistp521
|
39
|
+
ecdh-sha2-nistp384
|
40
|
+
ecdh-sha2-nistp256
|
41
|
+
diffie-hellman-group-exchange-sha256
|
42
|
+
diffie-hellman-group14-sha1],
|
43
|
+
|
44
|
+
encryption: %w[aes256-ctr aes192-ctr aes128-ctr],
|
45
|
+
|
46
|
+
hmac: %w[hmac-sha2-512-etm@openssh.com hmac-sha2-256-etm@openssh.com
|
47
|
+
hmac-sha2-512 hmac-sha2-256
|
48
|
+
hmac-sha1]
|
49
|
+
}.freeze
|
50
|
+
|
51
|
+
if Net::SSH::Authentication::ED25519Loader::LOADED
|
52
|
+
DEFAULT_ALGORITHMS[:host_key].unshift(
|
53
|
+
'ssh-ed25519-cert-v01@openssh.com',
|
54
|
+
'ssh-ed25519'
|
55
|
+
)
|
56
|
+
end
|
57
|
+
|
58
|
+
if Net::SSH::Transport::Kex::Curve25519Sha256Loader::LOADED
|
59
|
+
DEFAULT_ALGORITHMS[:kex].unshift(
|
60
|
+
'curve25519-sha256',
|
61
|
+
'curve22519-sha256@libssh.org'
|
62
|
+
)
|
63
|
+
end
|
64
|
+
|
65
|
+
# Define all algorithms, with the deprecated, supported by Net::SSH.
|
66
|
+
ALGORITHMS = {
|
67
|
+
host_key: DEFAULT_ALGORITHMS[:host_key] + %w[ssh-dss],
|
68
|
+
|
69
|
+
kex: DEFAULT_ALGORITHMS[:kex] +
|
70
|
+
%w[diffie-hellman-group-exchange-sha1
|
35
71
|
diffie-hellman-group1-sha1],
|
36
|
-
|
37
|
-
|
72
|
+
|
73
|
+
encryption: DEFAULT_ALGORITHMS[:encryption] +
|
74
|
+
%w[aes256-cbc aes192-cbc aes128-cbc
|
38
75
|
rijndael-cbc@lysator.liu.se
|
39
76
|
blowfish-ctr blowfish-cbc
|
40
77
|
cast128-ctr cast128-cbc
|
41
78
|
3des-ctr 3des-cbc
|
42
|
-
idea-cbc
|
79
|
+
idea-cbc
|
43
80
|
none],
|
44
81
|
|
45
|
-
hmac:
|
46
|
-
|
47
|
-
hmac-sha1
|
82
|
+
hmac: DEFAULT_ALGORITHMS[:hmac] +
|
83
|
+
%w[hmac-sha2-512-96 hmac-sha2-256-96
|
84
|
+
hmac-sha1-96
|
48
85
|
hmac-ripemd160 hmac-ripemd160@openssh.com
|
49
86
|
hmac-md5 hmac-md5-96
|
50
87
|
none],
|
51
88
|
|
52
89
|
compression: %w[none zlib@openssh.com zlib],
|
53
90
|
language: %w[]
|
54
|
-
}
|
55
|
-
if defined?(OpenSSL::PKey::EC)
|
56
|
-
ALGORITHMS[:host_key].unshift(
|
57
|
-
"ecdsa-sha2-nistp521-cert-v01@openssh.com",
|
58
|
-
"ecdsa-sha2-nistp384-cert-v01@openssh.com",
|
59
|
-
"ecdsa-sha2-nistp256-cert-v01@openssh.com",
|
60
|
-
"ecdsa-sha2-nistp521",
|
61
|
-
"ecdsa-sha2-nistp384",
|
62
|
-
"ecdsa-sha2-nistp256"
|
63
|
-
)
|
64
|
-
if Net::SSH::Authentication::ED25519Loader::LOADED
|
65
|
-
ALGORITHMS[:host_key].unshift(
|
66
|
-
"ssh-ed25519-cert-v01@openssh.com",
|
67
|
-
"ssh-ed25519"
|
68
|
-
)
|
69
|
-
end
|
70
|
-
ALGORITHMS[:kex].unshift(
|
71
|
-
"ecdh-sha2-nistp521",
|
72
|
-
"ecdh-sha2-nistp384",
|
73
|
-
"ecdh-sha2-nistp256"
|
74
|
-
)
|
75
|
-
end
|
91
|
+
}.freeze
|
76
92
|
|
77
93
|
# The underlying transport layer session that supports this object
|
78
94
|
attr_reader :session
|
@@ -140,6 +156,7 @@ module Net
|
|
140
156
|
# Start the algorithm negotation
|
141
157
|
def start
|
142
158
|
raise ArgumentError, "Cannot call start if it's negotiation started or done" if @pending || @initialized
|
159
|
+
|
143
160
|
send_kexinit
|
144
161
|
end
|
145
162
|
|
@@ -197,8 +214,8 @@ module Net
|
|
197
214
|
|
198
215
|
def host_key_format
|
199
216
|
case host_key
|
200
|
-
when
|
201
|
-
|
217
|
+
when /^([a-z0-9-]+)-cert-v\d{2}@openssh.com$/
|
218
|
+
Regexp.last_match[1]
|
202
219
|
else
|
203
220
|
host_key
|
204
221
|
end
|
@@ -239,7 +256,10 @@ module Net
|
|
239
256
|
options[:compression] = %w[zlib@openssh.com zlib] if options[:compression] == true
|
240
257
|
|
241
258
|
ALGORITHMS.each do |algorithm, supported|
|
242
|
-
algorithms[algorithm] = compose_algorithm_list(
|
259
|
+
algorithms[algorithm] = compose_algorithm_list(
|
260
|
+
supported, options[algorithm] || DEFAULT_ALGORITHMS[algorithm],
|
261
|
+
options[:append_all_supported_algorithms]
|
262
|
+
)
|
243
263
|
end
|
244
264
|
|
245
265
|
# for convention, make sure our list has the same keys as the server
|
@@ -356,7 +376,8 @@ module Net
|
|
356
376
|
|
357
377
|
debug do
|
358
378
|
"negotiated:\n" +
|
359
|
-
%i[kex host_key encryption_server encryption_client hmac_client hmac_server
|
379
|
+
%i[kex host_key encryption_server encryption_client hmac_client hmac_server
|
380
|
+
compression_client compression_server language_client language_server].map do |key|
|
360
381
|
"* #{key}: #{instance_variable_get("@#{key}")}"
|
361
382
|
end.join("\n")
|
362
383
|
end
|
@@ -368,7 +389,11 @@ module Net
|
|
368
389
|
def negotiate(algorithm)
|
369
390
|
match = self[algorithm].find { |item| @server_data[algorithm].include?(item) }
|
370
391
|
|
371
|
-
|
392
|
+
if match.nil?
|
393
|
+
raise Net::SSH::Exception, "could not settle on #{algorithm} algorithm\n"\
|
394
|
+
"Server #{algorithm} preferences: #{@server_data[algorithm].join(',')}\n"\
|
395
|
+
"Client #{algorithm} preferences: #{self[algorithm].join(',')}"
|
396
|
+
end
|
372
397
|
|
373
398
|
return match
|
374
399
|
end
|