net-ssh 8.0.0.rc3 → 8.0.0.rc5

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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +4 -1
  3. data/.github/pull_request_template.md +1 -0
  4. data/.github/workflows/changelog.yml +43 -0
  5. data/CHANGES.txt +40 -0
  6. data/CONTRIBUTING.md +35 -0
  7. data/README.md +65 -48
  8. data/Rakefile +48 -0
  9. data/changelog.d/README.md +1 -0
  10. data/lib/net/ssh/authentication/agent.rb +4 -1
  11. data/lib/net/ssh/authentication/ed25519.rb +1 -1
  12. data/lib/net/ssh/authentication/key_manager.rb +22 -12
  13. data/lib/net/ssh/authentication/methods/abstract.rb +2 -8
  14. data/lib/net/ssh/authentication/methods/publickey.rb +3 -1
  15. data/lib/net/ssh/authentication/security_key.rb +71 -0
  16. data/lib/net/ssh/authentication/session.rb +29 -17
  17. data/lib/net/ssh/buffer.rb +6 -1
  18. data/lib/net/ssh/buffered_io.rb +40 -3
  19. data/lib/net/ssh/config.rb +16 -1
  20. data/lib/net/ssh/connection/channel.rb +49 -2
  21. data/lib/net/ssh/connection/session.rb +58 -8
  22. data/lib/net/ssh/errors.rb +24 -6
  23. data/lib/net/ssh/key_factory.rb +7 -1
  24. data/lib/net/ssh/known_hosts.rb +18 -8
  25. data/lib/net/ssh/multiplex/client.rb +162 -0
  26. data/lib/net/ssh/multiplex/control_path.rb +120 -0
  27. data/lib/net/ssh/multiplex/proxy_transport.rb +218 -0
  28. data/lib/net/ssh/multiplex.rb +130 -0
  29. data/lib/net/ssh/proxy/jump.rb +40 -2
  30. data/lib/net/ssh/service/forward.rb +26 -21
  31. data/lib/net/ssh/test.rb +2 -1
  32. data/lib/net/ssh/transport/algorithms.rb +71 -23
  33. data/lib/net/ssh/transport/hmac/sha1_etm.rb +12 -0
  34. data/lib/net/ssh/transport/hmac.rb +2 -0
  35. data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +8 -0
  36. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +45 -15
  37. data/lib/net/ssh/transport/openssl.rb +2 -1
  38. data/lib/net/ssh/transport/session.rb +21 -44
  39. data/lib/net/ssh/verifiers/always.rb +0 -3
  40. data/lib/net/ssh/version.rb +1 -1
  41. data/lib/net/ssh.rb +132 -56
  42. data/net-ssh.gemspec +1 -1
  43. data/rakelib/changelog.rb +229 -0
  44. data.tar.gz.sig +0 -0
  45. metadata +23 -6
  46. metadata.gz.sig +0 -0
@@ -320,6 +320,11 @@ module Net
320
320
  session.listen_to(client)
321
321
  channel[:socket] = client
322
322
 
323
+ # Grant window only for data the local end has accepted, so a slow
324
+ # reader stalls the remote sender instead of filling our memory.
325
+ channel.grant_window_on_consume!
326
+ client.on_sent { |bytes| channel.consumed(bytes) }
327
+
323
328
  channel.on_data do |ch, data|
324
329
  debug { "data:#{data.length} on #{type} forwarded channel" }
325
330
  ch[:socket].enqueue(data)
@@ -327,36 +332,36 @@ module Net
327
332
 
328
333
  channel.on_eof do |ch|
329
334
  debug { "eof #{type} on #{type} forwarded channel" }
330
- begin
331
- ch[:socket].send_pending
332
- ch[:socket].shutdown Socket::SHUT_WR
333
- rescue IOError => e
334
- if e.message =~ /closed/ then
335
- debug { "epipe in on_eof => shallowing exception:#{e}" }
336
- else
337
- raise
338
- end
339
- rescue Errno::EPIPE => e
340
- debug { "epipe in on_eof => shallowing exception:#{e}" }
341
- rescue Errno::ENOTCONN => e
342
- debug { "enotconn in on_eof => shallowing exception:#{e}" }
343
- end
335
+ ch[:socket].shutdown_write_when_drained
344
336
  end
345
337
 
346
338
  channel.on_close do |ch|
347
339
  debug { "closing #{type} forwarded channel" }
348
- ch[:socket].close if !client.closed?
349
- session.stop_listening_to(ch[:socket])
340
+ session.close_when_drained(ch[:socket])
350
341
  end
351
342
 
352
343
  channel.on_process do |ch|
353
- if ch[:socket].closed?
344
+ socket = ch[:socket]
345
+ if socket.closed?
354
346
  ch.info { "#{type} forwarded connection closed" }
347
+ session.stop_listening_to(socket)
355
348
  ch.close
356
- elsif ch[:socket].available > 0
357
- data = ch[:socket].read_available(8192)
358
- ch.debug { "read #{data.length} bytes from client, sending over #{type} forwarded connection" }
359
- ch.send_data(data)
349
+ else
350
+ if socket.available > 0
351
+ data = socket.read_available(8192)
352
+ ch.debug { "read #{data.length} bytes from client, sending over #{type} forwarded connection" }
353
+ ch.send_data(data)
354
+ end
355
+
356
+ # Like OpenSSH's channel_pre_open, only read more once the remote
357
+ # window can take what is already queued; writes to the socket keep
358
+ # flowing. ch.output is still unsent here because Channel#process
359
+ # runs this block before enqueue_pending_output.
360
+ if ch.output.length + socket.available < ch.remote_window_size.to_i
361
+ session.resume_reading(socket)
362
+ else
363
+ session.pause_reading(socket)
364
+ end
360
365
  end
361
366
  end
362
367
  end
data/lib/net/ssh/test.rb CHANGED
@@ -73,7 +73,8 @@ module Net
73
73
  def transport(options = {})
74
74
  @transport ||= Net::SSH::Transport::Session.new(
75
75
  options[:host] || "localhost",
76
- options.merge(kex: "test", host_key: "ssh-rsa", append_all_supported_algorithms: true, verify_host_key: :never, proxy: socket(options))
76
+ options.merge(kex: "test", host_key: "ssh-rsa", encryption: "+none", hmac: "+none",
77
+ append_all_supported_algorithms: true, verify_host_key: :never, proxy: socket(options))
77
78
  )
78
79
  end
79
80
 
@@ -8,6 +8,7 @@ require 'net/ssh/transport/kex'
8
8
  require 'net/ssh/transport/kex/curve25519_sha256_loader'
9
9
  require 'net/ssh/transport/server_version'
10
10
  require 'net/ssh/authentication/ed25519_loader'
11
+ require 'net/ssh/authentication/security_key'
11
12
 
12
13
  module Net
13
14
  module SSH
@@ -19,7 +20,7 @@ module Net
19
20
  #
20
21
  # You will never instantiate or reference this directly. It is used
21
22
  # internally by the transport layer.
22
- class Algorithms
23
+ class Algorithms # rubocop:disable Metrics/ClassLength
23
24
  include Loggable
24
25
  include Constants
25
26
 
@@ -31,18 +32,14 @@ module Net
31
32
  ecdsa-sha2-nistp521
32
33
  ecdsa-sha2-nistp384
33
34
  ecdsa-sha2-nistp256
34
- ssh-rsa-cert-v01@openssh.com
35
- ssh-rsa-cert-v00@openssh.com
36
- ssh-rsa
37
- rsa-sha2-256
38
- rsa-sha2-512],
35
+ rsa-sha2-512
36
+ rsa-sha2-256],
39
37
 
40
38
  kex: %w[ecdh-sha2-nistp521
41
39
  ecdh-sha2-nistp384
42
40
  ecdh-sha2-nistp256
43
41
  diffie-hellman-group-exchange-sha256
44
- diffie-hellman-group14-sha256
45
- diffie-hellman-group14-sha1],
42
+ diffie-hellman-group14-sha256],
46
43
 
47
44
  encryption: %w[aes256-ctr
48
45
  aes192-ctr
@@ -51,8 +48,18 @@ module Net
51
48
  aes128-gcm@openssh.com],
52
49
 
53
50
  hmac: %w[hmac-sha2-512-etm@openssh.com hmac-sha2-256-etm@openssh.com
51
+ hmac-sha1-etm@openssh.com
54
52
  hmac-sha2-512 hmac-sha2-256
55
- hmac-sha1]
53
+ hmac-sha1],
54
+
55
+ pubkey_algorithms: %w[ssh-ed25519-cert-v01@openssh.com
56
+ ecdsa-sha2-nistp256-cert-v01@openssh.com ecdsa-sha2-nistp384-cert-v01@openssh.com
57
+ ecdsa-sha2-nistp521-cert-v01@openssh.com
58
+ rsa-sha2-512-cert-v01@openssh.com rsa-sha2-256-cert-v01@openssh.com
59
+ ssh-ed25519
60
+ ecdsa-sha2-nistp256 ecdsa-sha2-nistp384 ecdsa-sha2-nistp521] +
61
+ [Authentication::SecurityKey::SK_SSH_ED25519, Authentication::SecurityKey::SK_ECDSA_SHA2_NISTP256] +
62
+ %w[rsa-sha2-512 rsa-sha2-256]
56
63
  }.freeze
57
64
 
58
65
  if Net::SSH::Transport::ChaCha20Poly1305CipherLoader::LOADED
@@ -76,10 +83,12 @@ module Net
76
83
 
77
84
  # Define all algorithms, with the deprecated, supported by Net::SSH.
78
85
  ALGORITHMS = {
79
- host_key: DEFAULT_ALGORITHMS[:host_key] + %w[ssh-dss],
86
+ host_key: DEFAULT_ALGORITHMS[:host_key] +
87
+ %w[ssh-rsa-cert-v01@openssh.com ssh-rsa-cert-v00@openssh.com ssh-rsa ssh-dss],
80
88
 
81
89
  kex: DEFAULT_ALGORITHMS[:kex] +
82
- %w[diffie-hellman-group-exchange-sha1
90
+ %w[diffie-hellman-group14-sha1
91
+ diffie-hellman-group-exchange-sha1
83
92
  diffie-hellman-group1-sha1],
84
93
 
85
94
  encryption: DEFAULT_ALGORITHMS[:encryption] +
@@ -98,10 +107,20 @@ module Net
98
107
  hmac-md5 hmac-md5-96
99
108
  none],
100
109
 
110
+ pubkey_algorithms: DEFAULT_ALGORITHMS[:pubkey_algorithms] + %w[ssh-rsa-cert-v01@openssh.com ssh-rsa ssh-dss],
111
+
101
112
  compression: %w[none zlib@openssh.com zlib],
102
113
  language: %w[]
103
114
  }.freeze
104
115
 
116
+ # Not added by append_all_supported_algorithms; only used when named explicitly.
117
+ EXPLICIT_ONLY_ALGORITHMS = {
118
+ encryption: %w[none],
119
+ hmac: %w[none]
120
+ }.freeze
121
+
122
+ DEPRECATED_HOST_KEY = 'ssh-rsa-cert-v00@openssh.com'.freeze
123
+
105
124
  # The underlying transport layer session that supports this object
106
125
  attr_reader :session
107
126
 
@@ -269,11 +288,16 @@ module Net
269
288
 
270
289
  ALGORITHMS.each do |algorithm, supported|
271
290
  algorithms[algorithm] = compose_algorithm_list(
272
- supported, options[algorithm] || DEFAULT_ALGORITHMS[algorithm],
273
- options[:append_all_supported_algorithms]
291
+ supported,
292
+ DEFAULT_ALGORITHMS[algorithm],
293
+ options[algorithm] || DEFAULT_ALGORITHMS[algorithm],
294
+ options[:append_all_supported_algorithms],
295
+ supported - EXPLICIT_ONLY_ALGORITHMS.fetch(algorithm, [])
274
296
  )
275
297
  end
276
298
 
299
+ warn_deprecated_host_key if host_key_explicitly_named?(DEPRECATED_HOST_KEY)
300
+
277
301
  # for convention, make sure our list has the same keys as the server
278
302
  # list
279
303
 
@@ -287,7 +311,11 @@ module Net
287
311
  # existing known key for the host has preference.
288
312
 
289
313
  existing_keys = session.host_keys
290
- host_keys = existing_keys.flat_map { |key| key.respond_to?(:ssh_types) ? key.ssh_types : [key.ssh_type] }.uniq
314
+ host_keys = existing_keys.flat_map { |key| key.respond_to?(:ssh_types) ? key.ssh_types : [key.ssh_type] }
315
+ # A known ssh-rsa key also verifies with rsa-sha2-*, and must not re-enable disabled SHA-1 algorithms.
316
+ disabled_sha1 = %w[ssh-rsa ssh-rsa-cert-v01@openssh.com ssh-rsa-cert-v00@openssh.com] - algorithms[:host_key]
317
+ host_keys = host_keys.flat_map { |type| type == 'ssh-rsa' ? %w[rsa-sha2-512 rsa-sha2-256 ssh-rsa] : [type] }
318
+ host_keys = (host_keys - disabled_sha1).uniq
291
319
  algorithms[:host_key].each do |name|
292
320
  host_keys << name unless host_keys.include?(name)
293
321
  end
@@ -296,21 +324,27 @@ module Net
296
324
  end
297
325
 
298
326
  # Composes the list of algorithms by taking supported algorithms and matching with supplied options.
299
- def compose_algorithm_list(supported, option, append_all_supported_algorithms = false)
327
+ def compose_algorithm_list(supported, defaults, option, append_all_supported_algorithms = false, appendable = supported)
300
328
  return supported.dup unless option
301
329
 
302
330
  list = []
303
331
  option = Array(option).compact.uniq
304
332
 
305
- if option.first && option.first.start_with?('+', '-')
306
- list = supported.dup
307
-
308
- appends = option.select { |opt| opt.start_with?('+') }.map { |opt| opt[1..-1] }
309
- deletions = option.select { |opt| opt.start_with?('-') }.map { |opt| opt[1..-1] }
333
+ if option.first && option.first.start_with?('+', '-', '^')
334
+ ops = { '^' => [], '+' => [], '-' => [] }
335
+ cur_list = nil
336
+ option.each do |cur_opt|
337
+ if ops.key?(cur_opt[0])
338
+ cur_list = ops[cur_opt[0]]
339
+ cur_opt = cur_opt[1..-1]
340
+ end
341
+ cur_list << cur_opt
342
+ end
310
343
 
311
- list.concat(appends)
344
+ list = ops['^'] + defaults + ops['+']
345
+ list.concat(appendable) if append_all_supported_algorithms
312
346
 
313
- deletions.each do |opt|
347
+ ops['-'].each do |opt|
314
348
  if opt.include?('*')
315
349
  opt_escaped = Regexp.escape(opt)
316
350
  algo_re = /\A#{opt_escaped.gsub('\*', '[A-Za-z\d\-@\.]*')}\z/
@@ -325,7 +359,7 @@ module Net
325
359
  list = option
326
360
 
327
361
  if append_all_supported_algorithms
328
- supported.each { |name| list << name unless list.include?(name) }
362
+ appendable.each { |name| list << name unless list.include?(name) }
329
363
  end
330
364
  end
331
365
 
@@ -341,6 +375,19 @@ module Net
341
375
  list
342
376
  end
343
377
 
378
+ def host_key_explicitly_named?(name)
379
+ algorithms[:host_key].include?(name) &&
380
+ Array(options[:host_key]).any? { |opt| opt.to_s.delete_prefix('+').delete_prefix('^') == name }
381
+ end
382
+
383
+ def warn_deprecated_host_key
384
+ return if @deprecated_host_key_warned
385
+
386
+ @deprecated_host_key_warned = true
387
+ Kernel.warn("#{DEPRECATED_HOST_KEY} is deprecated and will be removed in a future version; " \
388
+ "net-ssh cannot parse v00 certificates, use ssh-rsa-cert-v01@openssh.com or a modern host key type instead")
389
+ end
390
+
344
391
  # Parses a KEXINIT packet from the server.
345
392
  def parse_server_algorithm_packet(packet)
346
393
  data = { raw: packet.content }
@@ -398,6 +445,7 @@ module Net
398
445
  def negotiate_algorithms
399
446
  @kex = negotiate(:kex)
400
447
  @host_key = negotiate(:host_key)
448
+ warn_deprecated_host_key if @host_key == DEPRECATED_HOST_KEY
401
449
  @encryption_client = negotiate(:encryption_client)
402
450
  @encryption_server = negotiate(:encryption_server)
403
451
  @hmac_client = negotiate(:hmac_client)
@@ -0,0 +1,12 @@
1
+ require 'net/ssh/transport/hmac/abstract'
2
+
3
+ module Net::SSH::Transport::HMAC
4
+ # The SHA1 Encrypt-Then-Mac HMAC algorithm. This has a mac and
5
+ # key length of 20, and uses the SHA1 digest algorithm.
6
+ class SHA1_Etm < Abstract
7
+ etm true
8
+ mac_length 20
9
+ key_length 20
10
+ digest_class OpenSSL::Digest::SHA1
11
+ end
12
+ end
@@ -9,6 +9,7 @@ require 'net/ssh/transport/hmac/sha2_512'
9
9
  require 'net/ssh/transport/hmac/sha2_512_96'
10
10
  require 'net/ssh/transport/hmac/sha2_256_etm'
11
11
  require 'net/ssh/transport/hmac/sha2_512_etm'
12
+ require 'net/ssh/transport/hmac/sha1_etm'
12
13
  require 'net/ssh/transport/hmac/ripemd160'
13
14
  require 'net/ssh/transport/hmac/none'
14
15
 
@@ -27,6 +28,7 @@ module Net::SSH::Transport::HMAC
27
28
  'hmac-sha2-512-96' => SHA2_512_96,
28
29
  'hmac-sha2-256-etm@openssh.com' => SHA2_256_Etm,
29
30
  'hmac-sha2-512-etm@openssh.com' => SHA2_512_Etm,
31
+ 'hmac-sha1-etm@openssh.com' => SHA1_Etm,
30
32
  'hmac-ripemd160' => RIPEMD160,
31
33
  'hmac-ripemd160@openssh.com' => RIPEMD160,
32
34
  'none' => None
@@ -102,6 +102,7 @@ module Net
102
102
  result[:key_blob] = buffer.read_string
103
103
  result[:server_key] = Net::SSH::Buffer.new(result[:key_blob]).read_key
104
104
  result[:server_dh_pubkey] = buffer.read_bignum
105
+ validate_server_dh_pubkey(result[:server_dh_pubkey])
105
106
  result[:shared_secret] = OpenSSL::BN.new(dh.compute_key(result[:server_dh_pubkey]), 2)
106
107
 
107
108
  sig_buffer = Net::SSH::Buffer.new(buffer.read_string)
@@ -115,6 +116,13 @@ module Net
115
116
 
116
117
  return result
117
118
  end
119
+
120
+ # Rejects degenerate values that would let the server force a
121
+ # predictable shared secret, as OpenSSH's dh_pub_is_valid.
122
+ def validate_server_dh_pubkey(pub)
123
+ valid = pub > 1 && pub < dh.p - 1 && pub.to_i.to_s(2).count("1") >= 4
124
+ raise Net::SSH::Exception, "server's DH public value is invalid" unless valid
125
+ end
118
126
  end
119
127
  end
120
128
  end
@@ -6,26 +6,43 @@ module Net::SSH::Transport::Kex
6
6
  # A key-exchange service implementing the
7
7
  # "diffie-hellman-group-exchange-sha1" key-exchange algorithm.
8
8
  class DiffieHellmanGroupExchangeSHA1 < DiffieHellmanGroup1SHA1
9
- MINIMUM_BITS = 1024
9
+ MINIMUM_BITS = 2048
10
10
  MAXIMUM_BITS = 8192
11
+ CISCO_MAXIMUM_NEED_BITS = 4096
11
12
 
12
13
  private
13
14
 
14
- # Compute the number of bits needed for the given number of bytes.
15
+ # Computes the minimum, preferred and maximum group sizes to request,
16
+ # like OpenSSH's kexgex_client.
15
17
  def compute_need_bits
16
- # for Compatibility: OpenSSH requires (need_bits * 2 + 1) length of parameter
17
- need_bits = data[:need_bytes] * 8 * 2 + 1
18
-
19
18
  data[:minimum_dh_bits] ||= MINIMUM_BITS
19
+ data[:maximum_dh_bits] = [MAXIMUM_BITS, data[:minimum_dh_bits]].max
20
+ data[:need_bits] = estimate_group_bits(data[:need_bytes] * 8).clamp(data[:minimum_dh_bits], maximum_need_bits)
21
+ end
20
22
 
21
- if need_bits < data[:minimum_dh_bits]
22
- need_bits = data[:minimum_dh_bits]
23
- elsif need_bits > MAXIMUM_BITS
24
- need_bits = MAXIMUM_BITS
25
- end
23
+ # Some Cisco servers fail instead of returning their 4096-bit group when asked for more (OpenSSH bz#2209).
24
+ def maximum_need_bits
25
+ return data[:maximum_dh_bits] unless cisco_server?
26
+
27
+ [CISCO_MAXIMUM_NEED_BITS, data[:minimum_dh_bits]].max
28
+ end
29
+
30
+ def cisco_server?
31
+ data[:server_version_string].to_s.match?(/\ASSH-[\d.]+-Cisco-1\./)
32
+ end
26
33
 
27
- data[:need_bits] = need_bits
28
- data[:need_bytes] = need_bits / 8
34
+ # Group size giving at least the given bits of security (NIST SP 800-57),
35
+ # as OpenSSH's dh_estimate.
36
+ def estimate_group_bits(security_bits)
37
+ if security_bits <= 112
38
+ 2048
39
+ elsif security_bits <= 128
40
+ 3072
41
+ elsif security_bits <= 192
42
+ 7680
43
+ else
44
+ 8192
45
+ end
29
46
  end
30
47
 
31
48
  # Returns the DH key parameters for the given session.
@@ -34,7 +51,7 @@ module Net::SSH::Transport::Kex
34
51
 
35
52
  # request the DH key parameters for the given number of bits.
36
53
  buffer = Net::SSH::Buffer.from(:byte, KEXDH_GEX_REQUEST, :long, data[:minimum_dh_bits],
37
- :long, data[:need_bits], :long, MAXIMUM_BITS)
54
+ :long, data[:need_bits], :long, data[:maximum_dh_bits])
38
55
  connection.send_message(buffer)
39
56
 
40
57
  buffer = connection.next_message
@@ -43,9 +60,22 @@ module Net::SSH::Transport::Kex
43
60
  p = buffer.read_bignum
44
61
  g = buffer.read_bignum
45
62
 
63
+ validate_group(p, g)
64
+
46
65
  [p, g]
47
66
  end
48
67
 
68
+ def validate_group(prime, generator)
69
+ bits = prime.num_bits
70
+ if bits < data[:minimum_dh_bits]
71
+ raise Net::SSH::Exception,
72
+ "server's DH group is #{bits} bits, below the minimum of #{data[:minimum_dh_bits]}; " \
73
+ "pass minimum_dh_bits: #{bits} to allow it"
74
+ end
75
+ raise Net::SSH::Exception, "server's DH group is #{bits} bits, above the maximum of #{data[:maximum_dh_bits]}" if bits > data[:maximum_dh_bits]
76
+ raise Net::SSH::Exception, "server's DH group generator is invalid" unless generator > 1 && generator < prime - 1
77
+ end
78
+
49
79
  # Returns the INIT/REPLY constants used by this algorithm.
50
80
  def get_message_types
51
81
  [KEXDH_GEX_INIT, KEXDH_GEX_REPLY]
@@ -60,9 +90,9 @@ module Net::SSH::Transport::Kex
60
90
  data[:client_algorithm_packet],
61
91
  data[:server_algorithm_packet],
62
92
  result[:key_blob]
63
- response.write_long MINIMUM_BITS,
93
+ response.write_long data[:minimum_dh_bits],
64
94
  data[:need_bits],
65
- MAXIMUM_BITS
95
+ data[:maximum_dh_bits]
66
96
  response.write_bignum dh.p, dh.g, dh.pub_key,
67
97
  result[:server_dh_pubkey],
68
98
  result[:shared_secret]
@@ -1,4 +1,5 @@
1
1
  require 'openssl'
2
+ require 'net/ssh/errors'
2
3
  require 'net/ssh/authentication/pub_key_fingerprint'
3
4
 
4
5
  module OpenSSL
@@ -178,7 +179,7 @@ module OpenSSL
178
179
 
179
180
  return key
180
181
  rescue OpenSSL::PKey::ECError
181
- raise NotImplementedError, "unsupported key type `#{type}'"
182
+ raise Net::SSH::UnsupportedKeyType, "unsupported key type `ecdsa-sha2-#{curve_name_in_type}'"
182
183
  end
183
184
  end
184
185
 
@@ -107,6 +107,10 @@ module Net
107
107
  end
108
108
  end
109
109
 
110
+ def pubkey_algorithms
111
+ algorithms[:pubkey_algorithms]
112
+ end
113
+
110
114
  # Returns the host (and possibly IP address) in a format compatible with
111
115
  # SSH known-host files.
112
116
  def host_as_string
@@ -313,22 +317,12 @@ module Net
313
317
  socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
314
318
  end
315
319
 
316
- # Compatibility verifier which allows users to keep using
317
- # custom verifier code without adding new :verify_signature
318
- # method.
319
- class CompatibleVerifier
320
- def initialize(verifier)
321
- @verifier = verifier
322
- end
323
-
324
- def verify(arguments)
325
- @verifier.verify(arguments)
326
- end
327
-
328
- def verify_signature(&block)
329
- yield
330
- end
331
- end
320
+ REMOVED_VERIFY_HOST_KEY_VALUES = {
321
+ false => :never,
322
+ true => :accept_new_or_local_tunnel,
323
+ very: :accept_new,
324
+ secure: :always
325
+ }.freeze
332
326
 
333
327
  # Instantiates a new host-key verification class, based on the value of
334
328
  # the parameter.
@@ -343,46 +337,29 @@ module Net
343
337
  #
344
338
  # If the argument happens to respond to :verify and :verify_signature,
345
339
  # it is returned directly. Otherwise, an exception is raised.
346
- #
347
- # Values false, true, and :very were deprecated in
348
- # [#595](https://github.com/net-ssh/net-ssh/pull/595)
349
340
  def select_host_key_verifier(verifier)
350
341
  case verifier
351
- when false
352
- Kernel.warn('verify_host_key: false is deprecated, use :never')
353
- Net::SSH::Verifiers::Never.new
354
342
  when :never then
355
343
  Net::SSH::Verifiers::Never.new
356
- when true
357
- Kernel.warn('verify_host_key: true is deprecated, use :accept_new_or_local_tunnel')
358
- Net::SSH::Verifiers::AcceptNewOrLocalTunnel.new
359
344
  when :accept_new_or_local_tunnel, nil then
360
345
  Net::SSH::Verifiers::AcceptNewOrLocalTunnel.new
361
- when :very
362
- Kernel.warn('verify_host_key: :very is deprecated, use :accept_new')
363
- Net::SSH::Verifiers::AcceptNew.new
364
346
  when :accept_new then
365
347
  Net::SSH::Verifiers::AcceptNew.new
366
- when :secure then
367
- Kernel.warn('verify_host_key: :secure is deprecated, use :always')
368
- Net::SSH::Verifiers::Always.new
369
348
  when :always then
370
349
  Net::SSH::Verifiers::Always.new
350
+ when *REMOVED_VERIFY_HOST_KEY_VALUES.keys
351
+ raise ArgumentError,
352
+ "verify_host_key: #{verifier.inspect} has been removed, use #{REMOVED_VERIFY_HOST_KEY_VALUES[verifier].inspect}"
371
353
  else
372
- if verifier.respond_to?(:verify)
373
- if verifier.respond_to?(:verify_signature)
374
- verifier
375
- else
376
- Kernel.warn("Warning: verifier without :verify_signature is deprecated")
377
- CompatibleVerifier.new(verifier)
378
- end
379
- else
380
- raise(
381
- ArgumentError,
382
- "Invalid argument to :verify_host_key (or deprecated " \
383
- ":paranoid): #{verifier.inspect}"
384
- )
354
+ raise ArgumentError, "Invalid argument to :verify_host_key: #{verifier.inspect}" unless verifier.respond_to?(:verify)
355
+
356
+ unless verifier.respond_to?(:verify_signature)
357
+ raise ArgumentError,
358
+ "verify_host_key verifier #{verifier.inspect} must implement verify_signature(&block): " \
359
+ "yield to the block, which checks the server's host key signature, and return its result"
385
360
  end
361
+
362
+ verifier
386
363
  end
387
364
  end
388
365
  end
@@ -51,9 +51,6 @@ module Net
51
51
  # implement them (Net::SSH::HostKeyEntries::CertAuthority). Non-certificate
52
52
  # entries do not respond to these predicates and are left untouched.
53
53
  def verify_certificate!(entry, host_keys, arguments)
54
- # Plain keys carry no certificate constraints, and respond_to? on this delegator prints a deprecation warning (#1026).
55
- return if entry.is_a?(Net::SSH::HostKeyEntries::PubKey)
56
-
57
54
  cert = arguments[:key]
58
55
 
59
56
  if entry.respond_to?(:matches_validity?) && !entry.matches_validity?(cert)
@@ -56,7 +56,7 @@ module Net
56
56
 
57
57
  # The prerelease component of this version of the Net::SSH library
58
58
  # nil allowed
59
- PRE = "rc3"
59
+ PRE = "rc5"
60
60
 
61
61
  # The current version of the Net::SSH library as a Version instance
62
62
  CURRENT = new(*[MAJOR, MINOR, TINY, PRE].compact)