net-ssh 6.0.2 → 7.1.0

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 (107) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +2 -1
  3. data/.dockerignore +6 -0
  4. data/.github/config/rubocop_linter_action.yml +4 -0
  5. data/.github/workflows/ci-with-docker.yml +44 -0
  6. data/.github/workflows/ci.yml +87 -0
  7. data/.github/workflows/rubocop.yml +16 -0
  8. data/.gitignore +2 -0
  9. data/.rubocop.yml +12 -1
  10. data/.rubocop_todo.yml +474 -375
  11. data/CHANGES.txt +51 -3
  12. data/Dockerfile +27 -0
  13. data/Dockerfile.openssl3 +17 -0
  14. data/Gemfile +2 -0
  15. data/Gemfile.noed25519 +2 -0
  16. data/README.md +19 -8
  17. data/Rakefile +59 -0
  18. data/SECURITY.md +4 -0
  19. data/docker-compose.yml +23 -0
  20. data/lib/net/ssh/authentication/agent.rb +29 -13
  21. data/lib/net/ssh/authentication/certificate.rb +14 -11
  22. data/lib/net/ssh/authentication/constants.rb +0 -1
  23. data/lib/net/ssh/authentication/ed25519.rb +12 -7
  24. data/lib/net/ssh/authentication/ed25519_loader.rb +4 -7
  25. data/lib/net/ssh/authentication/key_manager.rb +46 -34
  26. data/lib/net/ssh/authentication/methods/abstract.rb +12 -3
  27. data/lib/net/ssh/authentication/methods/hostbased.rb +3 -5
  28. data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +2 -2
  29. data/lib/net/ssh/authentication/methods/none.rb +6 -9
  30. data/lib/net/ssh/authentication/methods/password.rb +2 -3
  31. data/lib/net/ssh/authentication/methods/publickey.rb +56 -16
  32. data/lib/net/ssh/authentication/pageant.rb +97 -97
  33. data/lib/net/ssh/authentication/pub_key_fingerprint.rb +2 -2
  34. data/lib/net/ssh/authentication/session.rb +18 -17
  35. data/lib/net/ssh/buffer.rb +71 -51
  36. data/lib/net/ssh/buffered_io.rb +24 -25
  37. data/lib/net/ssh/config.rb +33 -20
  38. data/lib/net/ssh/connection/channel.rb +84 -82
  39. data/lib/net/ssh/connection/constants.rb +0 -4
  40. data/lib/net/ssh/connection/event_loop.rb +30 -24
  41. data/lib/net/ssh/connection/keepalive.rb +12 -12
  42. data/lib/net/ssh/connection/session.rb +109 -108
  43. data/lib/net/ssh/connection/term.rb +56 -58
  44. data/lib/net/ssh/errors.rb +12 -12
  45. data/lib/net/ssh/key_factory.rb +7 -8
  46. data/lib/net/ssh/known_hosts.rb +84 -15
  47. data/lib/net/ssh/loggable.rb +8 -9
  48. data/lib/net/ssh/packet.rb +1 -1
  49. data/lib/net/ssh/prompt.rb +9 -11
  50. data/lib/net/ssh/proxy/command.rb +1 -1
  51. data/lib/net/ssh/proxy/errors.rb +2 -4
  52. data/lib/net/ssh/proxy/http.rb +18 -20
  53. data/lib/net/ssh/proxy/https.rb +8 -10
  54. data/lib/net/ssh/proxy/jump.rb +8 -10
  55. data/lib/net/ssh/proxy/socks4.rb +2 -4
  56. data/lib/net/ssh/proxy/socks5.rb +3 -5
  57. data/lib/net/ssh/service/forward.rb +7 -7
  58. data/lib/net/ssh/test/channel.rb +24 -26
  59. data/lib/net/ssh/test/extensions.rb +35 -35
  60. data/lib/net/ssh/test/kex.rb +6 -8
  61. data/lib/net/ssh/test/local_packet.rb +0 -2
  62. data/lib/net/ssh/test/packet.rb +3 -3
  63. data/lib/net/ssh/test/remote_packet.rb +6 -8
  64. data/lib/net/ssh/test/script.rb +25 -27
  65. data/lib/net/ssh/test/socket.rb +12 -15
  66. data/lib/net/ssh/test.rb +4 -5
  67. data/lib/net/ssh/transport/algorithms.rb +37 -21
  68. data/lib/net/ssh/transport/cipher_factory.rb +28 -28
  69. data/lib/net/ssh/transport/constants.rb +3 -3
  70. data/lib/net/ssh/transport/ctr.rb +7 -7
  71. data/lib/net/ssh/transport/hmac/abstract.rb +4 -5
  72. data/lib/net/ssh/transport/hmac/md5.rb +0 -2
  73. data/lib/net/ssh/transport/hmac/md5_96.rb +0 -2
  74. data/lib/net/ssh/transport/hmac/none.rb +0 -2
  75. data/lib/net/ssh/transport/hmac/ripemd160.rb +0 -2
  76. data/lib/net/ssh/transport/hmac/sha1.rb +0 -2
  77. data/lib/net/ssh/transport/hmac/sha1_96.rb +0 -2
  78. data/lib/net/ssh/transport/hmac.rb +12 -12
  79. data/lib/net/ssh/transport/identity_cipher.rb +11 -13
  80. data/lib/net/ssh/transport/kex/abstract.rb +12 -5
  81. data/lib/net/ssh/transport/kex/abstract5656.rb +1 -1
  82. data/lib/net/ssh/transport/kex/curve25519_sha256.rb +2 -1
  83. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +4 -4
  84. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
  85. data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +21 -21
  86. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +1 -2
  87. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +2 -2
  88. data/lib/net/ssh/transport/kex.rb +8 -6
  89. data/lib/net/ssh/transport/key_expander.rb +7 -8
  90. data/lib/net/ssh/transport/openssl.rb +51 -26
  91. data/lib/net/ssh/transport/packet_stream.rb +2 -3
  92. data/lib/net/ssh/transport/server_version.rb +17 -16
  93. data/lib/net/ssh/transport/session.rb +9 -7
  94. data/lib/net/ssh/transport/state.rb +43 -43
  95. data/lib/net/ssh/verifiers/accept_new.rb +0 -2
  96. data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +1 -2
  97. data/lib/net/ssh/verifiers/always.rb +6 -4
  98. data/lib/net/ssh/verifiers/never.rb +0 -2
  99. data/lib/net/ssh/version.rb +3 -3
  100. data/lib/net/ssh.rb +11 -7
  101. data/net-ssh-public_cert.pem +8 -8
  102. data/net-ssh.gemspec +2 -2
  103. data/support/ssh_tunnel_bug.rb +3 -3
  104. data.tar.gz.sig +0 -0
  105. metadata +24 -15
  106. metadata.gz.sig +0 -0
  107. data/.travis.yml +0 -52
@@ -33,17 +33,21 @@ module Net
33
33
  ecdsa-sha2-nistp256
34
34
  ssh-rsa-cert-v01@openssh.com
35
35
  ssh-rsa-cert-v00@openssh.com
36
- ssh-rsa],
36
+ ssh-rsa
37
+ rsa-sha2-256
38
+ rsa-sha2-512],
37
39
 
38
40
  kex: %w[ecdh-sha2-nistp521
39
41
  ecdh-sha2-nistp384
40
42
  ecdh-sha2-nistp256
41
43
  diffie-hellman-group-exchange-sha256
44
+ diffie-hellman-group14-sha256
42
45
  diffie-hellman-group14-sha1],
43
46
 
44
47
  encryption: %w[aes256-ctr aes192-ctr aes128-ctr],
45
48
 
46
- hmac: %w[hmac-sha2-512 hmac-sha2-256
49
+ hmac: %w[hmac-sha2-512-etm@openssh.com hmac-sha2-256-etm@openssh.com
50
+ hmac-sha2-512 hmac-sha2-256
47
51
  hmac-sha1]
48
52
  }.freeze
49
53
 
@@ -83,9 +87,7 @@ module Net
83
87
  hmac-sha1-96
84
88
  hmac-ripemd160 hmac-ripemd160@openssh.com
85
89
  hmac-md5 hmac-md5-96
86
- none] +
87
- %w[hmac-sha2-256-etm@openssh.com
88
- hmac-sha2-512-etm@openssh.com],
90
+ none],
89
91
 
90
92
  compression: %w[none zlib@openssh.com zlib],
91
93
  language: %w[]
@@ -144,7 +146,7 @@ module Net
144
146
 
145
147
  # Instantiates a new Algorithms object, and prepares the hash of preferred
146
148
  # algorithms based on the options parameter and the ALGORITHMS constant.
147
- def initialize(session, options={})
149
+ def initialize(session, options = {})
148
150
  @session = session
149
151
  @logger = session.logger
150
152
  @options = options
@@ -276,7 +278,7 @@ module Net
276
278
  # existing known key for the host has preference.
277
279
 
278
280
  existing_keys = session.host_keys
279
- host_keys = existing_keys.map { |key| key.ssh_type }.uniq
281
+ host_keys = existing_keys.flat_map { |key| key.respond_to?(:ssh_types) ? key.ssh_types : [key.ssh_type] }.uniq
280
282
  algorithms[:host_key].each do |name|
281
283
  host_keys << name unless host_keys.include?(name)
282
284
  end
@@ -291,10 +293,24 @@ module Net
291
293
  list = []
292
294
  option = Array(option).compact.uniq
293
295
 
294
- if option.first && option.first.start_with?('+')
296
+ if option.first && option.first.start_with?('+', '-')
295
297
  list = supported.dup
296
- list << option.first[1..-1]
297
- list.concat(option[1..-1])
298
+
299
+ appends = option.select { |opt| opt.start_with?('+') }.map { |opt| opt[1..-1] }
300
+ deletions = option.select { |opt| opt.start_with?('-') }.map { |opt| opt[1..-1] }
301
+
302
+ list.concat(appends)
303
+
304
+ deletions.each do |opt|
305
+ if opt.include?('*')
306
+ opt_escaped = Regexp.escape(opt)
307
+ algo_re = /\A#{opt_escaped.gsub('\*', '[A-Za-z\d\-@\.]*')}\z/
308
+ list.delete_if { |existing_opt| algo_re.match(existing_opt) }
309
+ else
310
+ list.delete(opt)
311
+ end
312
+ end
313
+
298
314
  list.uniq!
299
315
  else
300
316
  list = option
@@ -353,10 +369,10 @@ module Net
353
369
  language = algorithms[:language].join(",")
354
370
 
355
371
  Net::SSH::Buffer.from(:byte, KEXINIT,
356
- :long, [rand(0xFFFFFFFF), rand(0xFFFFFFFF), rand(0xFFFFFFFF), rand(0xFFFFFFFF)],
357
- :mstring, [kex, host_key, encryption, encryption, hmac, hmac],
358
- :mstring, [compression, compression, language, language],
359
- :bool, false, :long, 0)
372
+ :long, [rand(0xFFFFFFFF), rand(0xFFFFFFFF), rand(0xFFFFFFFF), rand(0xFFFFFFFF)],
373
+ :mstring, [kex, host_key, encryption, encryption, hmac, hmac],
374
+ :mstring, [compression, compression, language, language],
375
+ :bool, false, :long, 0)
360
376
  end
361
377
 
362
378
  # Given the parsed server KEX packet, and the client's preferred algorithm
@@ -422,13 +438,13 @@ module Net
422
438
  debug { "exchanging keys" }
423
439
 
424
440
  algorithm = Kex::MAP[kex].new(self, session,
425
- client_version_string: Net::SSH::Transport::ServerVersion::PROTO_VERSION,
426
- server_version_string: session.server_version.version,
427
- server_algorithm_packet: @server_packet,
428
- client_algorithm_packet: @client_packet,
429
- need_bytes: kex_byte_requirement,
430
- minimum_dh_bits: options[:minimum_dh_bits],
431
- logger: logger)
441
+ client_version_string: Net::SSH::Transport::ServerVersion::PROTO_VERSION,
442
+ server_version_string: session.server_version.version,
443
+ server_algorithm_packet: @server_packet,
444
+ client_algorithm_packet: @client_packet,
445
+ need_bytes: kex_byte_requirement,
446
+ minimum_dh_bits: options[:minimum_dh_bits],
447
+ logger: logger)
432
448
  result = algorithm.exchange_keys
433
449
 
434
450
  secret = result[:shared_secret].to_ssh
@@ -3,31 +3,30 @@ require 'net/ssh/transport/ctr.rb'
3
3
  require 'net/ssh/transport/key_expander'
4
4
  require 'net/ssh/transport/identity_cipher'
5
5
 
6
- module Net
7
- module SSH
6
+ module Net
7
+ module SSH
8
8
  module Transport
9
-
10
9
  # Implements a factory of OpenSSL cipher algorithms.
11
10
  class CipherFactory
12
11
  # Maps the SSH name of a cipher to it's corresponding OpenSSL name
13
12
  SSH_TO_OSSL = {
14
- "3des-cbc" => "des-ede3-cbc",
15
- "blowfish-cbc" => "bf-cbc",
16
- "aes256-cbc" => "aes-256-cbc",
17
- "aes192-cbc" => "aes-192-cbc",
18
- "aes128-cbc" => "aes-128-cbc",
19
- "idea-cbc" => "idea-cbc",
20
- "cast128-cbc" => "cast-cbc",
13
+ "3des-cbc" => "des-ede3-cbc",
14
+ "blowfish-cbc" => "bf-cbc",
15
+ "aes256-cbc" => "aes-256-cbc",
16
+ "aes192-cbc" => "aes-192-cbc",
17
+ "aes128-cbc" => "aes-128-cbc",
18
+ "idea-cbc" => "idea-cbc",
19
+ "cast128-cbc" => "cast-cbc",
21
20
  "rijndael-cbc@lysator.liu.se" => "aes-256-cbc",
22
- "3des-ctr" => "des-ede3",
23
- "blowfish-ctr" => "bf-ecb",
21
+ "3des-ctr" => "des-ede3",
22
+ "blowfish-ctr" => "bf-ecb",
24
23
 
25
- 'aes256-ctr' => 'aes-256-ctr',
26
- 'aes192-ctr' => 'aes-192-ctr',
27
- 'aes128-ctr' => 'aes-128-ctr',
28
- 'cast128-ctr' => 'cast5-ecb',
24
+ "aes256-ctr" => ::OpenSSL::Cipher.ciphers.include?("aes-256-ctr") ? "aes-256-ctr" : "aes-256-ecb",
25
+ "aes192-ctr" => ::OpenSSL::Cipher.ciphers.include?("aes-192-ctr") ? "aes-192-ctr" : "aes-192-ecb",
26
+ "aes128-ctr" => ::OpenSSL::Cipher.ciphers.include?("aes-128-ctr") ? "aes-128-ctr" : "aes-128-ecb",
27
+ 'cast128-ctr' => 'cast5-ecb',
29
28
 
30
- 'none' => 'none'
29
+ 'none' => 'none'
31
30
  }
32
31
 
33
32
  # Returns true if the underlying OpenSSL library supports the given cipher,
@@ -35,23 +34,25 @@ module Net
35
34
  def self.supported?(name)
36
35
  ossl_name = SSH_TO_OSSL[name] or raise NotImplementedError, "unimplemented cipher `#{name}'"
37
36
  return true if ossl_name == "none"
37
+
38
38
  return OpenSSL::Cipher.ciphers.include?(ossl_name)
39
39
  end
40
-
40
+
41
41
  # Retrieves a new instance of the named algorithm. The new instance
42
42
  # will be initialized using an iv and key generated from the given
43
43
  # iv, key, shared, hash and digester values. Additionally, the
44
44
  # cipher will be put into encryption or decryption mode, based on the
45
45
  # value of the +encrypt+ parameter.
46
- def self.get(name, options={})
46
+ def self.get(name, options = {})
47
47
  ossl_name = SSH_TO_OSSL[name] or raise NotImplementedError, "unimplemented cipher `#{name}'"
48
48
  return IdentityCipher if ossl_name == "none"
49
+
49
50
  cipher = OpenSSL::Cipher.new(ossl_name)
50
-
51
+
51
52
  cipher.send(options[:encrypt] ? :encrypt : :decrypt)
52
-
53
+
53
54
  cipher.padding = 0
54
-
55
+
55
56
  if name =~ /-ctr(@openssh.org)?$/
56
57
  if ossl_name !~ /-ctr/
57
58
  cipher.extend(Net::SSH::Transport::CTR)
@@ -60,14 +61,14 @@ module Net
60
61
  end
61
62
  end
62
63
  cipher.iv = Net::SSH::Transport::KeyExpander.expand_key(cipher.iv_len, options[:iv], options)
63
-
64
+
64
65
  key_len = cipher.key_len
65
66
  cipher.key_len = key_len
66
67
  cipher.key = Net::SSH::Transport::KeyExpander.expand_key(key_len, options[:key], options)
67
-
68
+
68
69
  return cipher
69
70
  end
70
-
71
+
71
72
  # Returns a two-element array containing the [ key-length,
72
73
  # block-size ] for the named cipher algorithm. If the cipher
73
74
  # algorithm is unknown, or is "none", 0 is returned for both elements
@@ -82,7 +83,7 @@ module Net
82
83
  cipher = OpenSSL::Cipher.new(ossl_name)
83
84
  key_len = cipher.key_len
84
85
  cipher.key_len = key_len
85
-
86
+
86
87
  block_size =
87
88
  case ossl_name
88
89
  when /\-ctr/
@@ -90,14 +91,13 @@ module Net
90
91
  else
91
92
  cipher.block_size
92
93
  end
93
-
94
+
94
95
  result = [key_len, block_size]
95
96
  result << cipher.iv_len if options[:iv_len]
96
97
  end
97
98
  result
98
99
  end
99
100
  end
100
-
101
101
  end
102
102
  end
103
103
  end
@@ -1,5 +1,5 @@
1
- module Net
2
- module SSH
1
+ module Net
2
+ module SSH
3
3
  module Transport
4
4
  module Constants
5
5
  #--
@@ -12,7 +12,7 @@ module Net
12
12
  DEBUG = 4
13
13
  SERVICE_REQUEST = 5
14
14
  SERVICE_ACCEPT = 6
15
-
15
+
16
16
  #--
17
17
  # Algorithm negotiation messages
18
18
  #++
@@ -2,7 +2,7 @@ require 'openssl'
2
2
  require 'delegate'
3
3
 
4
4
  module Net::SSH::Transport
5
- #:nodoc:
5
+ # :nodoc:
6
6
  class OpenSSLAESCTR < SimpleDelegator
7
7
  def initialize(original)
8
8
  super
@@ -26,13 +26,13 @@ module Net::SSH::Transport
26
26
  end
27
27
  end
28
28
 
29
- #:nodoc:
29
+ # :nodoc:
30
30
  # Pure-Ruby implementation of Stateful Decryption Counter(SDCTR) Mode
31
31
  # for Block Ciphers. See RFC4344 for detail.
32
32
  module CTR
33
33
  def self.extended(orig)
34
34
  orig.instance_eval {
35
- @remaining = ""
35
+ @remaining = String.new
36
36
  @counter = nil
37
37
  @counter_len = orig.block_size
38
38
  orig.encrypt
@@ -67,13 +67,13 @@ module Net::SSH::Transport
67
67
  end
68
68
 
69
69
  def reset
70
- @remaining = ""
70
+ @remaining = String.new
71
71
  end
72
72
 
73
73
  def update(data)
74
74
  @remaining += data
75
75
 
76
- encrypted = ""
76
+ encrypted = String.new
77
77
 
78
78
  offset = 0
79
79
  while (@remaining.bytesize - offset) >= block_size
@@ -89,13 +89,13 @@ module Net::SSH::Transport
89
89
 
90
90
  def final
91
91
  s = @remaining.empty? ? '' : xor!(@remaining, _update(@counter))
92
- @remaining = ""
92
+ @remaining = String.new
93
93
  s
94
94
  end
95
95
 
96
96
  def xor!(s1, s2)
97
97
  s = []
98
- s1.unpack('Q*').zip(s2.unpack('Q*')) {|a,b| s.push(a ^ b) }
98
+ s1.unpack('Q*').zip(s2.unpack('Q*')) {|a, b| s.push(a ^ b) }
99
99
  s.pack('Q*')
100
100
  end
101
101
  singleton_class.send(:private, :xor!)
@@ -5,10 +5,9 @@ module Net
5
5
  module SSH
6
6
  module Transport
7
7
  module HMAC
8
-
9
8
  # The base class of all OpenSSL-based HMAC algorithm wrappers.
10
9
  class Abstract
11
- class <<self
10
+ class << self
12
11
  def etm(*v)
13
12
  @etm = false if !defined?(@etm)
14
13
  if v.empty?
@@ -77,19 +76,19 @@ module Net
77
76
  # The key in use for this instance.
78
77
  attr_reader :key
79
78
 
80
- def initialize(key=nil)
79
+ def initialize(key = nil)
81
80
  self.key = key
82
81
  end
83
82
 
84
83
  # Sets the key to the given value, truncating it so that it is the correct
85
84
  # length.
86
85
  def key=(value)
87
- @key = value ? value.to_s[0,key_length] : nil
86
+ @key = value ? value.to_s[0, key_length] : nil
88
87
  end
89
88
 
90
89
  # Compute the HMAC digest for the given data string.
91
90
  def digest(data)
92
- OpenSSL::HMAC.digest(digest_class.new, key, data)[0,mac_length]
91
+ OpenSSL::HMAC.digest(digest_class.new, key, data)[0, mac_length]
93
92
  end
94
93
  end
95
94
  end
@@ -1,12 +1,10 @@
1
1
  require 'net/ssh/transport/hmac/abstract'
2
2
 
3
3
  module Net::SSH::Transport::HMAC
4
-
5
4
  # The MD5 HMAC algorithm.
6
5
  class MD5 < Abstract
7
6
  mac_length 16
8
7
  key_length 16
9
8
  digest_class OpenSSL::Digest::MD5
10
9
  end
11
-
12
10
  end
@@ -1,11 +1,9 @@
1
1
  require 'net/ssh/transport/hmac/md5'
2
2
 
3
3
  module Net::SSH::Transport::HMAC
4
-
5
4
  # The MD5-96 HMAC algorithm. This returns only the first 12 bytes of
6
5
  # the digest.
7
6
  class MD5_96 < MD5
8
7
  mac_length 12
9
8
  end
10
-
11
9
  end
@@ -1,7 +1,6 @@
1
1
  require 'net/ssh/transport/hmac/abstract'
2
2
 
3
3
  module Net::SSH::Transport::HMAC
4
-
5
4
  # The "none" algorithm. This has a key and mac length of 0.
6
5
  class None < Abstract
7
6
  key_length 0
@@ -11,5 +10,4 @@ module Net::SSH::Transport::HMAC
11
10
  ""
12
11
  end
13
12
  end
14
-
15
13
  end
@@ -1,7 +1,6 @@
1
1
  require 'net/ssh/transport/hmac/abstract'
2
2
 
3
3
  module Net::SSH::Transport::HMAC
4
-
5
4
  # The RIPEMD-160 HMAC algorithm. This has a mac and key length of 20, and
6
5
  # uses the RIPEMD-160 digest algorithm.
7
6
  class RIPEMD160 < Abstract
@@ -9,5 +8,4 @@ module Net::SSH::Transport::HMAC
9
8
  key_length 20
10
9
  digest_class OpenSSL::Digest::RIPEMD160
11
10
  end
12
-
13
11
  end
@@ -1,7 +1,6 @@
1
1
  require 'net/ssh/transport/hmac/abstract'
2
2
 
3
3
  module Net::SSH::Transport::HMAC
4
-
5
4
  # The SHA1 HMAC algorithm. This has a mac and key length of 20, and
6
5
  # uses the SHA1 digest algorithm.
7
6
  class SHA1 < Abstract
@@ -9,5 +8,4 @@ module Net::SSH::Transport::HMAC
9
8
  key_length 20
10
9
  digest_class OpenSSL::Digest::SHA1
11
10
  end
12
-
13
11
  end
@@ -1,11 +1,9 @@
1
1
  require 'net/ssh/transport/hmac/sha1'
2
2
 
3
3
  module Net::SSH::Transport::HMAC
4
-
5
4
  # The SHA1-96 HMAC algorithm. This returns only the first 12 bytes of
6
5
  # the digest.
7
6
  class SHA1_96 < SHA1
8
7
  mac_length 12
9
8
  end
10
-
11
9
  end
@@ -17,24 +17,24 @@ require 'net/ssh/transport/hmac/none'
17
17
  module Net::SSH::Transport::HMAC
18
18
  # The mapping of SSH hmac algorithms to their implementations
19
19
  MAP = {
20
- 'hmac-md5' => MD5,
21
- 'hmac-md5-96' => MD5_96,
22
- 'hmac-sha1' => SHA1,
23
- 'hmac-sha1-96' => SHA1_96,
24
- 'hmac-sha2-256' => SHA2_256,
25
- 'hmac-sha2-256-96' => SHA2_256_96,
26
- 'hmac-sha2-512' => SHA2_512,
27
- 'hmac-sha2-512-96' => SHA2_512_96,
20
+ 'hmac-md5' => MD5,
21
+ 'hmac-md5-96' => MD5_96,
22
+ 'hmac-sha1' => SHA1,
23
+ 'hmac-sha1-96' => SHA1_96,
24
+ 'hmac-sha2-256' => SHA2_256,
25
+ 'hmac-sha2-256-96' => SHA2_256_96,
26
+ 'hmac-sha2-512' => SHA2_512,
27
+ 'hmac-sha2-512-96' => SHA2_512_96,
28
28
  'hmac-sha2-256-etm@openssh.com' => SHA2_256_Etm,
29
29
  'hmac-sha2-512-etm@openssh.com' => SHA2_512_Etm,
30
- 'hmac-ripemd160' => RIPEMD160,
31
- 'hmac-ripemd160@openssh.com' => RIPEMD160,
32
- 'none' => None
30
+ 'hmac-ripemd160' => RIPEMD160,
31
+ 'hmac-ripemd160@openssh.com' => RIPEMD160,
32
+ 'none' => None
33
33
  }
34
34
 
35
35
  # Retrieves a new hmac instance of the given SSH type (+name+). If +key+ is
36
36
  # given, the new instance will be initialized with that key.
37
- def self.get(name, key="", parameters = {})
37
+ def self.get(name, key = "", parameters = {})
38
38
  impl = MAP[name] or raise ArgumentError, "hmac not found: #{name.inspect}"
39
39
  impl.new(Net::SSH::Transport::KeyExpander.expand_key(impl.key_length, key, parameters))
40
40
  end
@@ -1,59 +1,57 @@
1
- module Net
2
- module SSH
1
+ module Net
2
+ module SSH
3
3
  module Transport
4
-
5
4
  # A cipher that does nothing but pass the data through, unchanged. This
6
5
  # keeps things in the code nice and clean when a cipher has not yet been
7
6
  # determined (i.e., during key exchange).
8
7
  class IdentityCipher
9
- class <<self
8
+ class << self
10
9
  # A default block size of 8 is required by the SSH2 protocol.
11
10
  def block_size
12
11
  8
13
12
  end
14
-
13
+
15
14
  # Returns an arbitrary integer.
16
15
  def iv_len
17
16
  4
18
17
  end
19
-
18
+
20
19
  # Does nothing. Returns self.
21
20
  def encrypt
22
21
  self
23
22
  end
24
-
23
+
25
24
  # Does nothing. Returns self.
26
25
  def decrypt
27
26
  self
28
27
  end
29
-
28
+
30
29
  # Passes its single argument through unchanged.
31
30
  def update(text)
32
31
  text
33
32
  end
34
-
33
+
35
34
  # Returns the empty string.
36
35
  def final
37
36
  ""
38
37
  end
39
-
38
+
40
39
  # The name of this cipher, which is "identity".
41
40
  def name
42
41
  "identity"
43
42
  end
44
-
43
+
45
44
  # Does nothing. Returns nil.
46
45
  def iv=(v)
47
46
  nil
48
47
  end
49
-
48
+
50
49
  # Does nothing. Returns self.
51
50
  def reset
52
51
  self
53
52
  end
54
53
  end
55
54
  end
56
-
57
55
  end
58
56
  end
59
57
  end
@@ -64,11 +64,16 @@ module Net
64
64
 
65
65
  private
66
66
 
67
+ def matching?(key_ssh_type, host_key_alg)
68
+ return true if key_ssh_type == host_key_alg
69
+ return true if key_ssh_type == 'ssh-rsa' && ['rsa-sha2-512', 'rsa-sha2-256'].include?(host_key_alg)
70
+ end
71
+
67
72
  # Verify that the given key is of the expected type, and that it
68
73
  # really is the key for the session's host. Raise Net::SSH::Exception
69
74
  # if it is not.
70
- def verify_server_key(key) #:nodoc:
71
- if key.ssh_type != algorithms.host_key
75
+ def verify_server_key(key) # :nodoc:
76
+ unless matching?(key.ssh_type, algorithms.host_key)
72
77
  raise Net::SSH::Exception, "host key algorithm mismatch '#{key.ssh_type}' != '#{algorithms.host_key}'"
73
78
  end
74
79
 
@@ -92,12 +97,14 @@ module Net
92
97
  # Verify the signature that was received. Raise Net::SSH::Exception
93
98
  # if the signature could not be verified. Otherwise, return the new
94
99
  # session-id.
95
- def verify_signature(result) #:nodoc:
100
+ def verify_signature(result) # :nodoc:
96
101
  response = build_signature_buffer(result)
97
102
 
98
103
  hash = digester.digest(response.to_s)
99
104
 
100
- unless connection.host_key_verifier.verify_signature { result[:server_key].ssh_do_verify(result[:server_sig], hash) }
105
+ server_key = result[:server_key]
106
+ server_sig = result[:server_sig]
107
+ unless connection.host_key_verifier.verify_signature { server_key.ssh_do_verify(server_sig, hash, host_key: algorithms.host_key) }
101
108
  raise Net::SSH::Exception, 'could not verify server signature'
102
109
  end
103
110
 
@@ -106,7 +113,7 @@ module Net
106
113
 
107
114
  # Send the NEWKEYS message, and expect the NEWKEYS message in
108
115
  # reply.
109
- def confirm_newkeys #:nodoc:
116
+ def confirm_newkeys # :nodoc:
110
117
  # send own NEWKEYS message first (the wodSSHServer won't send first)
111
118
  response = Net::SSH::Buffer.new
112
119
  response.write_byte(NEWKEYS)
@@ -32,7 +32,7 @@ module Net
32
32
  response
33
33
  end
34
34
 
35
- def send_kexinit #:nodoc:
35
+ def send_kexinit # :nodoc:
36
36
  init, reply = get_message_types
37
37
 
38
38
  # send the KEXECDH_INIT message
@@ -1,6 +1,7 @@
1
1
  gem 'x25519' # raise if the gem x25519 is not installed
2
2
 
3
3
  require 'x25519'
4
+
4
5
  require 'net/ssh/transport/constants'
5
6
  require 'net/ssh/transport/kex/abstract5656'
6
7
 
@@ -17,7 +18,7 @@ module Net
17
18
 
18
19
  private
19
20
 
20
- def generate_key #:nodoc:
21
+ def generate_key # :nodoc:
21
22
  ::X25519::Scalar.generate
22
23
  end
23
24
 
@@ -1,8 +1,8 @@
1
1
  require 'net/ssh/transport/kex/diffie_hellman_group1_sha1'
2
2
 
3
- module Net
4
- module SSH
5
- module Transport
3
+ module Net
4
+ module SSH
5
+ module Transport
6
6
  module Kex
7
7
  # A key-exchange service implementing the "diffie-hellman-group14-sha1"
8
8
  # key-exchange algorithm. (defined in RFC 4253)
@@ -24,7 +24,7 @@ module Net
24
24
  "B5C55DF0" "6F4C52C9" "DE2BCBF6" "95581718" +
25
25
  "3995497C" "EA956AE5" "15D22618" "98FA0510" +
26
26
  "15728E5A" "8AACAA68" "FFFFFFFF" "FFFFFFFF"
27
-
27
+
28
28
  # The radix in which P_s represents the value of P
29
29
  P_r = 16
30
30
 
@@ -0,0 +1,11 @@
1
+ require 'net/ssh/transport/kex/diffie_hellman_group14_sha1'
2
+
3
+ module Net::SSH::Transport::Kex
4
+ # A key-exchange service implementing the "diffie-hellman-group14-sha256"
5
+ # key-exchange algorithm.
6
+ class DiffieHellmanGroup14SHA256 < DiffieHellmanGroup14SHA1
7
+ def digester
8
+ OpenSSL::Digest::SHA256
9
+ end
10
+ end
11
+ end