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.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/.gitignore +1 -0
  5. data/.rubocop.yml +7 -4
  6. data/.rubocop_todo.yml +389 -379
  7. data/.travis.yml +13 -14
  8. data/CHANGES.txt +7 -0
  9. data/README.md +286 -0
  10. data/Rakefile +1 -2
  11. data/appveyor.yml +4 -2
  12. data/lib/net/ssh/authentication/key_manager.rb +7 -3
  13. data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +3 -1
  14. data/lib/net/ssh/authentication/pub_key_fingerprint.rb +0 -1
  15. data/lib/net/ssh/authentication/session.rb +2 -6
  16. data/lib/net/ssh/buffer.rb +1 -9
  17. data/lib/net/ssh/config.rb +25 -10
  18. data/lib/net/ssh/connection/channel.rb +7 -3
  19. data/lib/net/ssh/connection/session.rb +7 -3
  20. data/lib/net/ssh/key_factory.rb +6 -8
  21. data/lib/net/ssh/known_hosts.rb +26 -29
  22. data/lib/net/ssh/service/forward.rb +2 -1
  23. data/lib/net/ssh/test.rb +3 -2
  24. data/lib/net/ssh/transport/algorithms.rb +67 -42
  25. data/lib/net/ssh/transport/cipher_factory.rb +11 -27
  26. data/lib/net/ssh/transport/constants.rb +10 -6
  27. data/lib/net/ssh/transport/ctr.rb +1 -7
  28. data/lib/net/ssh/transport/hmac.rb +15 -13
  29. data/lib/net/ssh/transport/hmac/abstract.rb +16 -0
  30. data/lib/net/ssh/transport/hmac/sha2_256.rb +7 -11
  31. data/lib/net/ssh/transport/hmac/sha2_256_96.rb +4 -8
  32. data/lib/net/ssh/transport/hmac/sha2_256_etm.rb +12 -0
  33. data/lib/net/ssh/transport/hmac/sha2_512.rb +6 -9
  34. data/lib/net/ssh/transport/hmac/sha2_512_96.rb +4 -8
  35. data/lib/net/ssh/transport/hmac/sha2_512_etm.rb +12 -0
  36. data/lib/net/ssh/transport/kex.rb +13 -11
  37. data/lib/net/ssh/transport/kex/abstract.rb +123 -0
  38. data/lib/net/ssh/transport/kex/abstract5656.rb +72 -0
  39. data/lib/net/ssh/transport/kex/curve25519_sha256.rb +38 -0
  40. data/lib/net/ssh/transport/kex/curve25519_sha256_loader.rb +30 -0
  41. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +1 -15
  42. data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +9 -118
  43. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +0 -6
  44. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +5 -9
  45. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +18 -79
  46. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +5 -4
  47. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +5 -4
  48. data/lib/net/ssh/transport/openssl.rb +104 -107
  49. data/lib/net/ssh/transport/packet_stream.rb +44 -10
  50. data/lib/net/ssh/transport/state.rb +1 -1
  51. data/lib/net/ssh/version.rb +3 -3
  52. data/net-ssh.gemspec +8 -6
  53. metadata +35 -16
  54. metadata.gz.sig +0 -0
  55. data/Gemfile.noed25519.lock +0 -41
  56. data/README.rdoc +0 -194
  57. data/support/arcfour_check.rb +0 -20
@@ -0,0 +1,72 @@
1
+ require 'net/ssh/transport/kex/abstract'
2
+
3
+ module Net
4
+ module SSH
5
+ module Transport
6
+ module Kex
7
+ # Implement key-exchange algorithm from Elliptic Curve Algorithm Integration
8
+ # in the Secure Shell Transport Layer (RFC 5656)
9
+ class Abstract5656 < Abstract
10
+ alias ecdh dh
11
+
12
+ def curve_name
13
+ raise NotImplementedError, 'abstract class: curve_name not implemented'
14
+ end
15
+
16
+ private
17
+
18
+ def get_message_types
19
+ [KEXECDH_INIT, KEXECDH_REPLY]
20
+ end
21
+
22
+ def build_signature_buffer(result)
23
+ response = Net::SSH::Buffer.new
24
+ response.write_string data[:client_version_string],
25
+ data[:server_version_string],
26
+ data[:client_algorithm_packet],
27
+ data[:server_algorithm_packet],
28
+ result[:key_blob],
29
+ ecdh_public_key_bytes,
30
+ result[:server_ecdh_pubkey]
31
+ response.write_bignum result[:shared_secret]
32
+ response
33
+ end
34
+
35
+ def send_kexinit #:nodoc:
36
+ init, reply = get_message_types
37
+
38
+ # send the KEXECDH_INIT message
39
+ ## byte SSH_MSG_KEX_ECDH_INIT
40
+ ## string Q_C, client's ephemeral public key octet string
41
+ buffer = Net::SSH::Buffer.from(:byte, init, :mstring, ecdh_public_key_bytes)
42
+ connection.send_message(buffer)
43
+
44
+ # expect the following KEXECDH_REPLY message
45
+ ## byte SSH_MSG_KEX_ECDH_REPLY
46
+ ## string K_S, server's public host key
47
+ ## string Q_S, server's ephemeral public key octet string
48
+ ## string the signature on the exchange hash
49
+ buffer = connection.next_message
50
+ raise Net::SSH::Exception, 'expected REPLY' unless buffer.type == reply
51
+
52
+ result = {}
53
+ result[:key_blob] = buffer.read_string
54
+ result[:server_key] = Net::SSH::Buffer.new(result[:key_blob]).read_key
55
+ result[:server_ecdh_pubkey] = buffer.read_string
56
+ result[:shared_secret] = compute_shared_secret(result[:server_ecdh_pubkey])
57
+
58
+ sig_buffer = Net::SSH::Buffer.new(buffer.read_string)
59
+ sig_type = sig_buffer.read_string
60
+ if sig_type != algorithms.host_key_format
61
+ raise Net::SSH::Exception, "host key algorithm mismatch for signature '#{sig_type}' != '#{algorithms.host_key_format}'"
62
+ end
63
+
64
+ result[:server_sig] = sig_buffer.read_string
65
+
66
+ result
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,38 @@
1
+ gem 'x25519' # raise if the gem x25519 is not installed
2
+
3
+ require 'x25519'
4
+ require 'net/ssh/transport/constants'
5
+ require 'net/ssh/transport/kex/abstract5656'
6
+
7
+ module Net
8
+ module SSH
9
+ module Transport
10
+ module Kex
11
+ # A key-exchange service implementing the "curve25519-sha256@libssh.org"
12
+ # key-exchange algorithm. (defined in https://tools.ietf.org/html/draft-ietf-curdle-ssh-curves-06)
13
+ class Curve25519Sha256 < Abstract5656
14
+ def digester
15
+ OpenSSL::Digest::SHA256
16
+ end
17
+
18
+ private
19
+
20
+ def generate_key #:nodoc:
21
+ ::X25519::Scalar.generate
22
+ end
23
+
24
+ ## string Q_C, client's ephemeral public key octet string
25
+ def ecdh_public_key_bytes
26
+ ecdh.public_key.to_bytes
27
+ end
28
+
29
+ # compute shared secret from server's public key and client's private key
30
+ def compute_shared_secret(server_ecdh_pubkey)
31
+ pk = ::X25519::MontgomeryU.new(server_ecdh_pubkey)
32
+ OpenSSL::BN.new(ecdh.diffie_hellman(pk).to_bytes, 2)
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,30 @@
1
+ module Net
2
+ module SSH
3
+ module Transport
4
+ module Kex
5
+ # Loads Curve25519Sha256 support which requires optinal dependencies
6
+ module Curve25519Sha256Loader
7
+ begin
8
+ require 'net/ssh/transport/kex/curve25519_sha256'
9
+ LOADED = true
10
+ ERROR = nil
11
+ rescue LoadError => e
12
+ ERROR = e
13
+ LOADED = false
14
+ end
15
+
16
+ def self.raiseUnlessLoaded(message)
17
+ description = ERROR.is_a?(LoadError) ? dependenciesRequiredForX25519 : ''
18
+ description << "#{ERROR.class} : \"#{ERROR.message}\"\n" if ERROR
19
+ raise NotImplementedError, "#{message}\n#{description}" unless LOADED
20
+ end
21
+
22
+ def self.dependenciesRequiredForX25519
23
+ result = "net-ssh requires the following gems for x25519 support:\n"
24
+ result << " * x25519\n"
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -4,13 +4,9 @@ module Net
4
4
  module SSH
5
5
  module Transport
6
6
  module Kex
7
-
8
7
  # A key-exchange service implementing the "diffie-hellman-group14-sha1"
9
8
  # key-exchange algorithm. (defined in RFC 4253)
10
9
  class DiffieHellmanGroup14SHA1 < DiffieHellmanGroup1SHA1
11
- include Loggable
12
- include Constants
13
-
14
10
  # The value of 'P', as a string, in hexadecimal
15
11
  P_s = "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" +
16
12
  "C4C6628B" "80DC1CD1" "29024E08" "8A67CC74" +
@@ -31,19 +27,9 @@ module Net
31
27
 
32
28
  # The radix in which P_s represents the value of P
33
29
  P_r = 16
34
-
30
+
35
31
  # The group constant
36
32
  G = 2
37
-
38
- private
39
-
40
- def get_p
41
- OpenSSL::BN.new(P_s, P_r)
42
- end
43
-
44
- def get_g
45
- G
46
- end
47
33
  end
48
34
  end
49
35
  end
@@ -1,20 +1,12 @@
1
- require 'net/ssh/buffer'
2
- require 'net/ssh/errors'
3
- require 'net/ssh/loggable'
4
- require 'net/ssh/transport/openssl'
5
- require 'net/ssh/transport/constants'
1
+ require 'net/ssh/transport/kex/abstract'
6
2
 
7
3
  module Net
8
4
  module SSH
9
5
  module Transport
10
6
  module Kex
11
-
12
7
  # A key-exchange service implementing the "diffie-hellman-group1-sha1"
13
8
  # key-exchange algorithm.
14
- class DiffieHellmanGroup1SHA1
15
- include Loggable
16
- include Constants
17
-
9
+ class DiffieHellmanGroup1SHA1 < Abstract
18
10
  # The value of 'P', as a string, in hexadecimal
19
11
  P_s = "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" +
20
12
  "C4C6628B" "80DC1CD1" "29024E08" "8A67CC74" +
@@ -31,67 +23,18 @@ module Net
31
23
  # The group constant
32
24
  G = 2
33
25
 
34
- attr_reader :p
35
- attr_reader :g
36
- attr_reader :digester
37
- attr_reader :algorithms
38
- attr_reader :connection
39
- attr_reader :data
40
- attr_reader :dh
41
-
42
- # Create a new instance of the DiffieHellmanGroup1SHA1 algorithm.
43
- # The data is a Hash of symbols representing information
44
- # required by this algorithm, which was acquired during earlier
45
- # processing.
46
- def initialize(algorithms, connection, data)
47
- @p = get_p
48
- @g = get_g
49
-
50
- @digester = OpenSSL::Digest::SHA1
51
- @algorithms = algorithms
52
- @connection = connection
53
-
54
- @data = data.dup
55
- @dh = generate_key
56
- @logger = @data.delete(:logger)
57
- end
58
-
59
- # Perform the key-exchange for the given session, with the given
60
- # data. This method will return a hash consisting of the
61
- # following keys:
62
- #
63
- # * :session_id
64
- # * :server_key
65
- # * :shared_secret
66
- # * :hashing_algorithm
67
- #
68
- # The caller is expected to be able to understand how to use these
69
- # deliverables.
70
- def exchange_keys
71
- result = send_kexinit
72
- verify_server_key(result[:server_key])
73
- session_id = verify_signature(result)
74
- confirm_newkeys
75
-
76
- return { session_id: session_id,
77
- server_key: result[:server_key],
78
- shared_secret: result[:shared_secret],
79
- hashing_algorithm: digester }
26
+ def digester
27
+ OpenSSL::Digest::SHA1
80
28
  end
81
29
 
82
30
  private
83
31
 
84
- def get_p
85
- OpenSSL::BN.new(P_s, P_r)
86
- end
87
-
88
- def get_g
89
- G
90
- end
91
-
92
- # Returns the DH key parameters for the current connection.
32
+ # Returns the DH key parameters for the current connection. [p, q]
93
33
  def get_parameters
94
- [p, g]
34
+ [
35
+ OpenSSL::BN.new(self.class::P_s, self.class::P_r),
36
+ self.class::G
37
+ ]
95
38
  end
96
39
 
97
40
  # Returns the INIT/REPLY constants used by this algorithm.
@@ -172,59 +115,7 @@ module Net
172
115
 
173
116
  return result
174
117
  end
175
-
176
- # Verify that the given key is of the expected type, and that it
177
- # really is the key for the session's host. Raise Net::SSH::Exception
178
- # if it is not.
179
- def verify_server_key(key) #:nodoc:
180
- if key.ssh_type != algorithms.host_key
181
- raise Net::SSH::Exception,
182
- "host key algorithm mismatch " +
183
- "'#{key.ssh_type}' != '#{algorithms.host_key}'"
184
- end
185
-
186
- blob, fingerprint = generate_key_fingerprint(key)
187
-
188
- raise Net::SSH::Exception, "host key verification failed" unless connection.host_key_verifier.verify(key: key, key_blob: blob, fingerprint: fingerprint, session: connection)
189
- end
190
-
191
- def generate_key_fingerprint(key)
192
- blob = Net::SSH::Buffer.from(:key, key).to_s
193
-
194
- fingerprint = Net::SSH::Authentication::PubKeyFingerprint.fingerprint(blob, @connection.options[:fingerprint_hash] || 'SHA256')
195
-
196
- [blob, fingerprint]
197
- rescue ::Exception => e
198
- [nil, "(could not generate fingerprint: #{e.message})"]
199
- end
200
-
201
- # Verify the signature that was received. Raise Net::SSH::Exception
202
- # if the signature could not be verified. Otherwise, return the new
203
- # session-id.
204
- def verify_signature(result) #:nodoc:
205
- response = build_signature_buffer(result)
206
-
207
- hash = @digester.digest(response.to_s)
208
-
209
- raise Net::SSH::Exception, "could not verify server signature" unless connection.host_key_verifier.verify_signature { result[:server_key].ssh_do_verify(result[:server_sig], hash) }
210
-
211
- return hash
212
- end
213
-
214
- # Send the NEWKEYS message, and expect the NEWKEYS message in
215
- # reply.
216
- def confirm_newkeys #:nodoc:
217
- # send own NEWKEYS message first (the wodSSHServer won't send first)
218
- response = Net::SSH::Buffer.new
219
- response.write_byte(NEWKEYS)
220
- connection.send_message(response)
221
-
222
- # wait for the server's NEWKEYS message
223
- buffer = connection.next_message
224
- raise Net::SSH::Exception, "expected NEWKEYS" unless buffer.type == NEWKEYS
225
- end
226
118
  end
227
-
228
119
  end
229
120
  end
230
121
  end
@@ -3,18 +3,12 @@ require 'net/ssh/transport/constants'
3
3
  require 'net/ssh/transport/kex/diffie_hellman_group1_sha1'
4
4
 
5
5
  module Net::SSH::Transport::Kex
6
-
7
6
  # A key-exchange service implementing the
8
7
  # "diffie-hellman-group-exchange-sha1" key-exchange algorithm.
9
8
  class DiffieHellmanGroupExchangeSHA1 < DiffieHellmanGroup1SHA1
10
9
  MINIMUM_BITS = 1024
11
10
  MAXIMUM_BITS = 8192
12
11
 
13
- KEXDH_GEX_GROUP = 31
14
- KEXDH_GEX_INIT = 32
15
- KEXDH_GEX_REPLY = 33
16
- KEXDH_GEX_REQUEST = 34
17
-
18
12
  private
19
13
 
20
14
  # Compute the number of bits needed for the given number of bytes.
@@ -1,15 +1,11 @@
1
1
  require 'net/ssh/transport/kex/diffie_hellman_group_exchange_sha1'
2
2
 
3
3
  module Net::SSH::Transport::Kex
4
- if defined?(OpenSSL::Digest::SHA256)
5
- # A key-exchange service implementing the
6
- # "diffie-hellman-group-exchange-sha256" key-exchange algorithm.
7
- class DiffieHellmanGroupExchangeSHA256 < DiffieHellmanGroupExchangeSHA1
8
- def initialize(*args)
9
- super(*args)
10
-
11
- @digester = OpenSSL::Digest::SHA256
12
- end
4
+ # A key-exchange service implementing the
5
+ # "diffie-hellman-group-exchange-sha256" key-exchange algorithm.
6
+ class DiffieHellmanGroupExchangeSHA256 < DiffieHellmanGroupExchangeSHA1
7
+ def digester
8
+ OpenSSL::Digest::SHA256
13
9
  end
14
10
  end
15
11
  end
@@ -1,97 +1,36 @@
1
- require 'net/ssh/transport/constants'
2
- require 'net/ssh/transport/kex/diffie_hellman_group1_sha1'
1
+ require 'net/ssh/transport/kex/abstract5656'
3
2
 
4
- module Net
5
- module SSH
6
- module Transport
3
+ module Net
4
+ module SSH
5
+ module Transport
7
6
  module Kex
8
-
9
7
  # A key-exchange service implementing the "ecdh-sha2-nistp256"
10
8
  # key-exchange algorithm. (defined in RFC 5656)
11
- class EcdhSHA2NistP256 < DiffieHellmanGroup1SHA1
12
- include Loggable
13
- include Constants
14
-
15
- attr_reader :ecdh
16
-
9
+ class EcdhSHA2NistP256 < Abstract5656
17
10
  def digester
18
11
  OpenSSL::Digest::SHA256
19
12
  end
20
-
13
+
21
14
  def curve_name
22
15
  OpenSSL::PKey::EC::CurveNameAlias['nistp256']
23
16
  end
24
-
25
- def initialize(algorithms, connection, data)
26
- @algorithms = algorithms
27
- @connection = connection
28
-
29
- @digester = digester
30
- @data = data.dup
31
- @ecdh = generate_key
32
- @logger = @data.delete(:logger)
33
- end
34
-
17
+
35
18
  private
36
-
37
- def get_message_types
38
- [KEXECDH_INIT, KEXECDH_REPLY]
39
- end
40
-
41
- def build_signature_buffer(result)
42
- response = Net::SSH::Buffer.new
43
- response.write_string data[:client_version_string],
44
- data[:server_version_string],
45
- data[:client_algorithm_packet],
46
- data[:server_algorithm_packet],
47
- result[:key_blob],
48
- ecdh.public_key.to_bn.to_s(2),
49
- result[:server_ecdh_pubkey]
50
- response.write_bignum result[:shared_secret]
51
- response
52
- end
53
-
19
+
54
20
  def generate_key #:nodoc:
55
21
  OpenSSL::PKey::EC.new(curve_name).generate_key
56
22
  end
57
-
58
- def send_kexinit #:nodoc:
59
- init, reply = get_message_types
60
-
61
- # send the KEXECDH_INIT message
62
- ## byte SSH_MSG_KEX_ECDH_INIT
63
- ## string Q_C, client's ephemeral public key octet string
64
- buffer = Net::SSH::Buffer.from(:byte, init, :mstring, ecdh.public_key.to_bn.to_s(2))
65
- connection.send_message(buffer)
66
-
67
- # expect the following KEXECDH_REPLY message
68
- ## byte SSH_MSG_KEX_ECDH_REPLY
69
- ## string K_S, server's public host key
70
- ## string Q_S, server's ephemeral public key octet string
71
- ## string the signature on the exchange hash
72
- buffer = connection.next_message
73
- raise Net::SSH::Exception, "expected REPLY" unless buffer.type == reply
74
-
75
- result = Hash.new
76
- result[:key_blob] = buffer.read_string
77
- result[:server_key] = Net::SSH::Buffer.new(result[:key_blob]).read_key
78
- result[:server_ecdh_pubkey] = buffer.read_string
79
-
80
- # compute shared secret from server's public key and client's private key
23
+
24
+ # compute shared secret from server's public key and client's private key
25
+ def compute_shared_secret(server_ecdh_pubkey)
81
26
  pk = OpenSSL::PKey::EC::Point.new(OpenSSL::PKey::EC.new(curve_name).group,
82
- OpenSSL::BN.new(result[:server_ecdh_pubkey], 2))
83
- result[:shared_secret] = OpenSSL::BN.new(ecdh.dh_compute_key(pk), 2)
84
-
85
- sig_buffer = Net::SSH::Buffer.new(buffer.read_string)
86
- sig_type = sig_buffer.read_string
87
- if sig_type != algorithms.host_key_format
88
- raise Net::SSH::Exception,
89
- "host key algorithm mismatch for signature " +
90
- "'#{sig_type}' != '#{algorithms.host_key_format}'"
91
- end
92
- result[:server_sig] = sig_buffer.read_string
93
-
94
- return result
27
+ OpenSSL::BN.new(server_ecdh_pubkey, 2))
28
+ OpenSSL::BN.new(ecdh.dh_compute_key(pk), 2)
29
+ end
30
+
31
+ ## string Q_C, client's ephemeral public key octet string
32
+ def ecdh_public_key_bytes
33
+ ecdh.public_key.to_bn.to_s(2)
95
34
  end
96
35
  end
97
36
  end