net-ssh 6.1.0 → 6.3.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +1 -1
  3. data.tar.gz.sig +0 -0
  4. data/.github/workflows/ci.yml +93 -0
  5. data/.gitignore +2 -0
  6. data/.rubocop.yml +11 -1
  7. data/.rubocop_todo.yml +383 -291
  8. data/.travis.yml +10 -11
  9. data/CHANGES.txt +16 -3
  10. data/Gemfile +2 -0
  11. data/Gemfile.noed25519 +2 -0
  12. data/README.md +2 -2
  13. data/Rakefile +1 -0
  14. data/lib/net/ssh.rb +1 -2
  15. data/lib/net/ssh/authentication/agent.rb +16 -0
  16. data/lib/net/ssh/authentication/certificate.rb +8 -5
  17. data/lib/net/ssh/authentication/constants.rb +0 -1
  18. data/lib/net/ssh/authentication/ed25519.rb +7 -3
  19. data/lib/net/ssh/authentication/ed25519_loader.rb +4 -7
  20. data/lib/net/ssh/authentication/key_manager.rb +28 -29
  21. data/lib/net/ssh/authentication/methods/abstract.rb +0 -1
  22. data/lib/net/ssh/authentication/methods/hostbased.rb +0 -2
  23. data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +1 -1
  24. data/lib/net/ssh/authentication/methods/none.rb +5 -8
  25. data/lib/net/ssh/authentication/methods/password.rb +1 -2
  26. data/lib/net/ssh/authentication/methods/publickey.rb +0 -2
  27. data/lib/net/ssh/authentication/pageant.rb +89 -89
  28. data/lib/net/ssh/authentication/session.rb +14 -15
  29. data/lib/net/ssh/buffer.rb +10 -5
  30. data/lib/net/ssh/buffered_io.rb +18 -19
  31. data/lib/net/ssh/config.rb +29 -16
  32. data/lib/net/ssh/connection/channel.rb +72 -69
  33. data/lib/net/ssh/connection/constants.rb +0 -4
  34. data/lib/net/ssh/connection/event_loop.rb +22 -16
  35. data/lib/net/ssh/connection/keepalive.rb +12 -12
  36. data/lib/net/ssh/connection/session.rb +95 -94
  37. data/lib/net/ssh/connection/term.rb +56 -58
  38. data/lib/net/ssh/errors.rb +10 -10
  39. data/lib/net/ssh/key_factory.rb +0 -1
  40. data/lib/net/ssh/known_hosts.rb +79 -11
  41. data/lib/net/ssh/loggable.rb +8 -9
  42. data/lib/net/ssh/packet.rb +1 -1
  43. data/lib/net/ssh/prompt.rb +8 -10
  44. data/lib/net/ssh/proxy/command.rb +1 -1
  45. data/lib/net/ssh/proxy/errors.rb +2 -4
  46. data/lib/net/ssh/proxy/http.rb +17 -19
  47. data/lib/net/ssh/proxy/https.rb +6 -8
  48. data/lib/net/ssh/proxy/jump.rb +8 -10
  49. data/lib/net/ssh/proxy/socks4.rb +1 -3
  50. data/lib/net/ssh/proxy/socks5.rb +2 -4
  51. data/lib/net/ssh/service/forward.rb +3 -3
  52. data/lib/net/ssh/test.rb +1 -2
  53. data/lib/net/ssh/test/channel.rb +21 -23
  54. data/lib/net/ssh/test/extensions.rb +29 -29
  55. data/lib/net/ssh/test/kex.rb +6 -8
  56. data/lib/net/ssh/test/local_packet.rb +0 -2
  57. data/lib/net/ssh/test/packet.rb +2 -2
  58. data/lib/net/ssh/test/remote_packet.rb +6 -8
  59. data/lib/net/ssh/test/script.rb +22 -24
  60. data/lib/net/ssh/test/socket.rb +11 -14
  61. data/lib/net/ssh/transport/algorithms.rb +5 -2
  62. data/lib/net/ssh/transport/cipher_factory.rb +16 -16
  63. data/lib/net/ssh/transport/constants.rb +3 -3
  64. data/lib/net/ssh/transport/ctr.rb +4 -4
  65. data/lib/net/ssh/transport/hmac/abstract.rb +0 -1
  66. data/lib/net/ssh/transport/hmac/md5.rb +0 -2
  67. data/lib/net/ssh/transport/hmac/md5_96.rb +0 -2
  68. data/lib/net/ssh/transport/hmac/none.rb +0 -2
  69. data/lib/net/ssh/transport/hmac/ripemd160.rb +0 -2
  70. data/lib/net/ssh/transport/hmac/sha1.rb +0 -2
  71. data/lib/net/ssh/transport/hmac/sha1_96.rb +0 -2
  72. data/lib/net/ssh/transport/identity_cipher.rb +10 -12
  73. data/lib/net/ssh/transport/kex.rb +2 -0
  74. data/lib/net/ssh/transport/kex/abstract.rb +9 -2
  75. data/lib/net/ssh/transport/kex/curve25519_sha256.rb +1 -0
  76. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +4 -4
  77. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
  78. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +0 -1
  79. data/lib/net/ssh/transport/key_expander.rb +6 -7
  80. data/lib/net/ssh/transport/openssl.rb +19 -15
  81. data/lib/net/ssh/transport/packet_stream.rb +1 -2
  82. data/lib/net/ssh/transport/server_version.rb +17 -16
  83. data/lib/net/ssh/transport/session.rb +3 -1
  84. data/lib/net/ssh/transport/state.rb +42 -42
  85. data/lib/net/ssh/verifiers/accept_new.rb +0 -2
  86. data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +1 -2
  87. data/lib/net/ssh/verifiers/always.rb +6 -4
  88. data/lib/net/ssh/verifiers/never.rb +0 -2
  89. data/lib/net/ssh/version.rb +2 -2
  90. data/net-ssh-public_cert.pem +8 -8
  91. data/net-ssh.gemspec +2 -2
  92. data/support/ssh_tunnel_bug.rb +3 -3
  93. metadata +17 -15
  94. metadata.gz.sig +0 -0
@@ -3,66 +3,63 @@ require 'stringio'
3
3
  require 'net/ssh/test/extensions'
4
4
  require 'net/ssh/test/script'
5
5
 
6
- module Net
7
- module SSH
6
+ module Net
7
+ module SSH
8
8
  module Test
9
-
10
9
  # A mock socket implementation for use in testing. It implements the minimum
11
10
  # necessary interface for interacting with the rest of the Net::SSH::Test
12
11
  # system.
13
12
  class Socket < StringIO
14
13
  attr_reader :host, :port
15
-
14
+
16
15
  # The Net::SSH::Test::Script object in use by this socket. This is the
17
16
  # canonical script instance that should be used for any test depending on
18
17
  # this socket instance.
19
18
  attr_reader :script
20
-
19
+
21
20
  # Create a new test socket. This will also instantiate a new Net::SSH::Test::Script
22
21
  # and seed it with the necessary events to power the initialization of the
23
22
  # connection.
24
23
  def initialize
25
24
  extend(Net::SSH::Transport::PacketStream)
26
25
  super "SSH-2.0-Test\r\n"
27
-
26
+
28
27
  @script = Script.new
29
-
28
+
30
29
  script.sends(:kexinit)
31
30
  script.gets(:kexinit, 1, 2, 3, 4, "test", "ssh-rsa", "none", "none", "none", "none", "none", "none", "", "", false)
32
31
  script.sends(:newkeys)
33
32
  script.gets(:newkeys)
34
33
  end
35
-
34
+
36
35
  # This doesn't actually do anything, since we don't really care what gets
37
36
  # written.
38
37
  def write(data)
39
38
  # black hole, because we don't actually care about what gets written
40
39
  end
41
-
40
+
42
41
  # Allows the socket to also mimic a socket factory, simply returning
43
42
  # +self+.
44
43
  def open(host, port, options={})
45
44
  @host, @port = host, port
46
45
  self
47
46
  end
48
-
47
+
49
48
  # Returns a sockaddr struct for the port and host that were used when the
50
49
  # socket was instantiated.
51
50
  def getpeername
52
51
  ::Socket.sockaddr_in(port, host)
53
52
  end
54
-
53
+
55
54
  # Alias to #read, but never returns nil (returns an empty string instead).
56
55
  def recv(n)
57
56
  read(n) || ""
58
57
  end
59
-
58
+
60
59
  def readpartial(n)
61
60
  recv(n)
62
61
  end
63
-
64
62
  end
65
-
66
63
  end
67
64
  end
68
65
  end
@@ -33,12 +33,15 @@ 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],
@@ -275,7 +278,7 @@ module Net
275
278
  # existing known key for the host has preference.
276
279
 
277
280
  existing_keys = session.host_keys
278
- 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
279
282
  algorithms[:host_key].each do |name|
280
283
  host_keys << name unless host_keys.include?(name)
281
284
  end
@@ -3,10 +3,9 @@ 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
@@ -22,9 +21,9 @@ module Net
22
21
  "3des-ctr" => "des-ede3",
23
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',
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",
28
27
  'cast128-ctr' => 'cast5-ecb',
29
28
 
30
29
  'none' => 'none'
@@ -35,9 +34,10 @@ 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
@@ -46,12 +46,13 @@ module Net
46
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
  #++
@@ -32,7 +32,7 @@ module Net::SSH::Transport
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,7 +89,7 @@ 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
 
@@ -5,7 +5,6 @@ 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
10
  class <<self
@@ -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
@@ -1,7 +1,6 @@
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).
@@ -11,49 +10,48 @@ module Net
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
@@ -1,5 +1,6 @@
1
1
  require 'net/ssh/transport/kex/diffie_hellman_group1_sha1'
2
2
  require 'net/ssh/transport/kex/diffie_hellman_group14_sha1'
3
+ require 'net/ssh/transport/kex/diffie_hellman_group14_sha256'
3
4
  require 'net/ssh/transport/kex/diffie_hellman_group_exchange_sha1'
4
5
  require 'net/ssh/transport/kex/diffie_hellman_group_exchange_sha256'
5
6
  require 'net/ssh/transport/kex/ecdh_sha2_nistp256'
@@ -14,6 +15,7 @@ module Net::SSH::Transport
14
15
  MAP = {
15
16
  'diffie-hellman-group1-sha1' => DiffieHellmanGroup1SHA1,
16
17
  'diffie-hellman-group14-sha1' => DiffieHellmanGroup14SHA1,
18
+ 'diffie-hellman-group14-sha256' => DiffieHellmanGroup14SHA256,
17
19
  'diffie-hellman-group-exchange-sha1' => DiffieHellmanGroupExchangeSHA1,
18
20
  'diffie-hellman-group-exchange-sha256' => DiffieHellmanGroupExchangeSHA256,
19
21
  'ecdh-sha2-nistp256' => EcdhSHA2NistP256,
@@ -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
75
  def verify_server_key(key) #:nodoc:
71
- if key.ssh_type != algorithms.host_key
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
 
@@ -97,7 +102,9 @@ module Net
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