net-ssh 5.2.0 → 6.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|