net-ssh 4.2.0 → 7.0.1

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 (126) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  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 +13 -0
  8. data/.gitignore +7 -0
  9. data/.rubocop.yml +19 -2
  10. data/.rubocop_todo.yml +619 -667
  11. data/CHANGES.txt +110 -1
  12. data/Dockerfile +27 -0
  13. data/Dockerfile.openssl3 +17 -0
  14. data/Gemfile +3 -7
  15. data/{Gemfile.norbnacl → Gemfile.noed25519} +3 -1
  16. data/Manifest +4 -5
  17. data/README.md +293 -0
  18. data/Rakefile +45 -29
  19. data/appveyor.yml +8 -6
  20. data/docker-compose.yml +23 -0
  21. data/lib/net/ssh/authentication/agent.rb +248 -223
  22. data/lib/net/ssh/authentication/certificate.rb +178 -164
  23. data/lib/net/ssh/authentication/constants.rb +17 -15
  24. data/lib/net/ssh/authentication/ed25519.rb +141 -116
  25. data/lib/net/ssh/authentication/ed25519_loader.rb +28 -28
  26. data/lib/net/ssh/authentication/key_manager.rb +79 -36
  27. data/lib/net/ssh/authentication/methods/abstract.rb +62 -47
  28. data/lib/net/ssh/authentication/methods/hostbased.rb +34 -37
  29. data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +3 -3
  30. data/lib/net/ssh/authentication/methods/none.rb +16 -19
  31. data/lib/net/ssh/authentication/methods/password.rb +15 -16
  32. data/lib/net/ssh/authentication/methods/publickey.rb +96 -55
  33. data/lib/net/ssh/authentication/pageant.rb +468 -465
  34. data/lib/net/ssh/authentication/pub_key_fingerprint.rb +43 -0
  35. data/lib/net/ssh/authentication/session.rb +131 -122
  36. data/lib/net/ssh/buffer.rb +385 -332
  37. data/lib/net/ssh/buffered_io.rb +150 -151
  38. data/lib/net/ssh/config.rb +316 -239
  39. data/lib/net/ssh/connection/channel.rb +635 -613
  40. data/lib/net/ssh/connection/constants.rb +29 -29
  41. data/lib/net/ssh/connection/event_loop.rb +104 -95
  42. data/lib/net/ssh/connection/keepalive.rb +55 -51
  43. data/lib/net/ssh/connection/session.rb +614 -611
  44. data/lib/net/ssh/connection/term.rb +125 -123
  45. data/lib/net/ssh/errors.rb +101 -99
  46. data/lib/net/ssh/key_factory.rb +194 -108
  47. data/lib/net/ssh/known_hosts.rb +212 -134
  48. data/lib/net/ssh/loggable.rb +50 -49
  49. data/lib/net/ssh/packet.rb +83 -79
  50. data/lib/net/ssh/prompt.rb +51 -51
  51. data/lib/net/ssh/proxy/command.rb +105 -91
  52. data/lib/net/ssh/proxy/errors.rb +12 -10
  53. data/lib/net/ssh/proxy/http.rb +81 -81
  54. data/lib/net/ssh/proxy/https.rb +37 -36
  55. data/lib/net/ssh/proxy/jump.rb +49 -48
  56. data/lib/net/ssh/proxy/socks4.rb +2 -6
  57. data/lib/net/ssh/proxy/socks5.rb +14 -17
  58. data/lib/net/ssh/service/forward.rb +365 -362
  59. data/lib/net/ssh/test/channel.rb +145 -143
  60. data/lib/net/ssh/test/extensions.rb +131 -127
  61. data/lib/net/ssh/test/kex.rb +34 -32
  62. data/lib/net/ssh/test/local_packet.rb +46 -44
  63. data/lib/net/ssh/test/packet.rb +87 -84
  64. data/lib/net/ssh/test/remote_packet.rb +32 -30
  65. data/lib/net/ssh/test/script.rb +155 -155
  66. data/lib/net/ssh/test/socket.rb +49 -48
  67. data/lib/net/ssh/test.rb +82 -80
  68. data/lib/net/ssh/transport/algorithms.rb +433 -364
  69. data/lib/net/ssh/transport/cipher_factory.rb +95 -91
  70. data/lib/net/ssh/transport/constants.rb +32 -24
  71. data/lib/net/ssh/transport/ctr.rb +37 -15
  72. data/lib/net/ssh/transport/hmac/abstract.rb +81 -63
  73. data/lib/net/ssh/transport/hmac/md5.rb +0 -2
  74. data/lib/net/ssh/transport/hmac/md5_96.rb +0 -2
  75. data/lib/net/ssh/transport/hmac/none.rb +0 -2
  76. data/lib/net/ssh/transport/hmac/ripemd160.rb +0 -2
  77. data/lib/net/ssh/transport/hmac/sha1.rb +0 -2
  78. data/lib/net/ssh/transport/hmac/sha1_96.rb +0 -2
  79. data/lib/net/ssh/transport/hmac/sha2_256.rb +7 -11
  80. data/lib/net/ssh/transport/hmac/sha2_256_96.rb +4 -8
  81. data/lib/net/ssh/transport/hmac/sha2_256_etm.rb +12 -0
  82. data/lib/net/ssh/transport/hmac/sha2_512.rb +6 -9
  83. data/lib/net/ssh/transport/hmac/sha2_512_96.rb +4 -8
  84. data/lib/net/ssh/transport/hmac/sha2_512_etm.rb +12 -0
  85. data/lib/net/ssh/transport/hmac.rb +14 -12
  86. data/lib/net/ssh/transport/identity_cipher.rb +54 -52
  87. data/lib/net/ssh/transport/kex/abstract.rb +130 -0
  88. data/lib/net/ssh/transport/kex/abstract5656.rb +72 -0
  89. data/lib/net/ssh/transport/kex/curve25519_sha256.rb +39 -0
  90. data/lib/net/ssh/transport/kex/curve25519_sha256_loader.rb +30 -0
  91. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +33 -40
  92. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
  93. data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +112 -217
  94. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +53 -63
  95. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +5 -9
  96. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +36 -90
  97. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +18 -10
  98. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +18 -10
  99. data/lib/net/ssh/transport/kex.rb +15 -12
  100. data/lib/net/ssh/transport/key_expander.rb +24 -21
  101. data/lib/net/ssh/transport/openssl.rb +158 -133
  102. data/lib/net/ssh/transport/packet_stream.rb +223 -191
  103. data/lib/net/ssh/transport/server_version.rb +55 -56
  104. data/lib/net/ssh/transport/session.rb +306 -259
  105. data/lib/net/ssh/transport/state.rb +178 -176
  106. data/lib/net/ssh/verifiers/accept_new.rb +33 -0
  107. data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +33 -0
  108. data/lib/net/ssh/verifiers/always.rb +58 -0
  109. data/lib/net/ssh/verifiers/never.rb +19 -0
  110. data/lib/net/ssh/version.rb +55 -53
  111. data/lib/net/ssh.rb +47 -34
  112. data/net-ssh-public_cert.pem +18 -19
  113. data/net-ssh.gemspec +12 -11
  114. data/support/ssh_tunnel_bug.rb +5 -5
  115. data.tar.gz.sig +0 -0
  116. metadata +78 -73
  117. metadata.gz.sig +0 -0
  118. data/.travis.yml +0 -51
  119. data/Gemfile.norbnacl.lock +0 -41
  120. data/README.rdoc +0 -169
  121. data/lib/net/ssh/ruby_compat.rb +0 -24
  122. data/lib/net/ssh/verifiers/lenient.rb +0 -30
  123. data/lib/net/ssh/verifiers/null.rb +0 -12
  124. data/lib/net/ssh/verifiers/secure.rb +0 -52
  125. data/lib/net/ssh/verifiers/strict.rb +0 -24
  126. data/support/arcfour_check.rb +0 -20
@@ -0,0 +1,43 @@
1
+ require 'openssl'
2
+
3
+ module Net
4
+ module SSH
5
+ module Authentication
6
+ # Public key fingerprinting utility module - internal not part of API.
7
+ # This is included in pubkey classes and called from there. All RSA, DSA, and ECC keys
8
+ # are supported.
9
+ #
10
+ # require 'net/ssh'
11
+ # my_pubkey_text = File.read('/path/to/id_ed25519.pub')
12
+ # #=> "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDB2NBh4GJPPUN1kXPMu8b633Xcv55WoKC3OkBjFAbzJ alice@example.com"
13
+ # my_pubkey = Net::SSH::KeyFactory.load_data_public_key(my_pubkey_text)
14
+ # #=> #<Net::SSH::Authentication::ED25519::PubKey:0x00007fc8e91819b0
15
+ # my_pubkey.fingerprint
16
+ # #=> "2f:7f:97:21:76:a4:0f:38:c4:fe:d8:b4:6a:39:72:30"
17
+ # my_pubkey.fingerprint('SHA256')
18
+ # #=> "SHA256:u6mXnY8P1b0FODGp8mckqOB33u8+jvkSCtJbD5Q9klg"
19
+ module PubKeyFingerprint # :nodoc:
20
+ # Return the key's fingerprint. Algorithm may be either +MD5+ (default),
21
+ # or +SHA256+. For +SHA256+, fingerprints are in the same format
22
+ # returned by OpenSSH's <tt>`ssh-add -l -E SHA256`</tt>, i.e.,
23
+ # trailing base64 padding '=' characters are stripped and the
24
+ # literal string +SHA256:+ is prepended.
25
+ def fingerprint(algorithm = 'MD5')
26
+ @fingerprint ||= {}
27
+ @fingerprint[algorithm] ||= PubKeyFingerprint.fingerprint(to_blob, algorithm)
28
+ end
29
+
30
+ def self.fingerprint(blob, algorithm = 'MD5')
31
+ case algorithm.to_s.upcase
32
+ when 'MD5'
33
+ OpenSSL::Digest.hexdigest(algorithm, blob).scan(/../).join(":")
34
+ when 'SHA256'
35
+ "SHA256:#{Base64.encode64(OpenSSL::Digest.digest(algorithm, blob)).chomp.gsub(/=+\z/, '')}"
36
+ else
37
+ raise OpenSSL::Digest::DigestError, "unsupported ssh key digest #{algorithm}"
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -8,149 +8,158 @@ require 'net/ssh/authentication/methods/hostbased'
8
8
  require 'net/ssh/authentication/methods/password'
9
9
  require 'net/ssh/authentication/methods/keyboard_interactive'
10
10
 
11
- module Net; module SSH; module Authentication
12
-
13
- # Raised if the current authentication method is not allowed
14
- class DisallowedMethod < Net::SSH::Exception
15
- end
11
+ module Net
12
+ module SSH
13
+ module Authentication
14
+ # Raised if the current authentication method is not allowed
15
+ class DisallowedMethod < Net::SSH::Exception
16
+ end
16
17
 
17
- # Represents an authentication session. It manages the authentication of
18
- # a user over an established connection (the "transport" object, see
19
- # Net::SSH::Transport::Session).
20
- #
21
- # The use of an authentication session to manage user authentication is
22
- # internal to Net::SSH (specifically Net::SSH.start). Consumers of the
23
- # Net::SSH library will never need to access this class directly.
24
- class Session
25
- include Transport::Constants, Constants, Loggable
18
+ # Represents an authentication session. It manages the authentication of
19
+ # a user over an established connection (the "transport" object, see
20
+ # Net::SSH::Transport::Session).
21
+ #
22
+ # The use of an authentication session to manage user authentication is
23
+ # internal to Net::SSH (specifically Net::SSH.start). Consumers of the
24
+ # Net::SSH library will never need to access this class directly.
25
+ class Session
26
+ include Loggable
27
+ include Constants
28
+ include Transport::Constants
26
29
 
27
- # transport layer abstraction
28
- attr_reader :transport
30
+ # transport layer abstraction
31
+ attr_reader :transport
29
32
 
30
- # the list of authentication methods to try
31
- attr_reader :auth_methods
33
+ # the list of authentication methods to try
34
+ attr_reader :auth_methods
32
35
 
33
- # the list of authentication methods that are allowed
34
- attr_reader :allowed_auth_methods
36
+ # the list of authentication methods that are allowed
37
+ attr_reader :allowed_auth_methods
35
38
 
36
- # a hash of options, given at construction time
37
- attr_reader :options
39
+ # a hash of options, given at construction time
40
+ attr_reader :options
38
41
 
39
- # Instantiates a new Authentication::Session object over the given
40
- # transport layer abstraction.
41
- def initialize(transport, options={})
42
- self.logger = transport.logger
43
- @transport = transport
42
+ # Instantiates a new Authentication::Session object over the given
43
+ # transport layer abstraction.
44
+ def initialize(transport, options = {})
45
+ self.logger = transport.logger
46
+ @transport = transport
44
47
 
45
- @auth_methods = options[:auth_methods] || Net::SSH::Config.default_auth_methods
46
- @options = options
48
+ @auth_methods = options[:auth_methods] || Net::SSH::Config.default_auth_methods
49
+ @options = options
47
50
 
48
- @allowed_auth_methods = @auth_methods
49
- end
51
+ @allowed_auth_methods = @auth_methods
52
+ end
50
53
 
51
- # Attempts to authenticate the given user, in preparation for the next
52
- # service request. Returns true if an authentication method succeeds in
53
- # authenticating the user, and false otherwise.
54
- def authenticate(next_service, username, password=nil)
55
- debug { "beginning authentication of `#{username}'" }
56
-
57
- transport.send_message(transport.service_request("ssh-userauth"))
58
- expect_message(SERVICE_ACCEPT)
59
-
60
- key_manager = KeyManager.new(logger, options)
61
- keys.each { |key| key_manager.add(key) } unless keys.empty?
62
- key_data.each { |key2| key_manager.add_key_data(key2) } unless key_data.empty?
63
-
64
- attempted = []
65
-
66
- @auth_methods.each do |name|
67
- begin
68
- next unless @allowed_auth_methods.include?(name)
69
- attempted << name
70
-
71
- debug { "trying #{name}" }
72
- begin
73
- auth_class = Methods.const_get(name.split(/\W+/).map { |p| p.capitalize }.join)
74
- method = auth_class.new(self, key_manager: key_manager, password_prompt: options[:password_prompt])
75
- rescue NameError
76
- debug{"Mechanism #{name} was requested, but isn't a known type. Ignoring it."}
77
- next
54
+ # Attempts to authenticate the given user, in preparation for the next
55
+ # service request. Returns true if an authentication method succeeds in
56
+ # authenticating the user, and false otherwise.
57
+ def authenticate(next_service, username, password = nil)
58
+ debug { "beginning authentication of `#{username}'" }
59
+
60
+ transport.send_message(transport.service_request("ssh-userauth"))
61
+ expect_message(SERVICE_ACCEPT)
62
+
63
+ key_manager = KeyManager.new(logger, options)
64
+ keys.each { |key| key_manager.add(key) } unless keys.empty?
65
+ keycerts.each { |keycert| key_manager.add_keycert(keycert) } unless keycerts.empty?
66
+ key_data.each { |key2| key_manager.add_key_data(key2) } unless key_data.empty?
67
+ default_keys.each { |key| key_manager.add(key) } unless options.key?(:keys) || options.key?(:key_data)
68
+
69
+ attempted = []
70
+
71
+ @auth_methods.each do |name|
72
+ next unless @allowed_auth_methods.include?(name)
73
+
74
+ attempted << name
75
+
76
+ debug { "trying #{name}" }
77
+ begin
78
+ auth_class = Methods.const_get(name.split(/\W+/).map { |p| p.capitalize }.join)
79
+ method = auth_class.new(self,
80
+ key_manager: key_manager, password_prompt: options[:password_prompt],
81
+ pubkey_algorithms: options[:pubkey_algorithms] || nil)
82
+ rescue NameError
83
+ debug {"Mechanism #{name} was requested, but isn't a known type. Ignoring it."}
84
+ next
85
+ end
86
+
87
+ return true if method.authenticate(next_service, username, password)
88
+ rescue Net::SSH::Authentication::DisallowedMethod
78
89
  end
79
90
 
80
- return true if method.authenticate(next_service, username, password)
81
- rescue Net::SSH::Authentication::DisallowedMethod
91
+ error { "all authorization methods failed (tried #{attempted.join(', ')})" }
92
+ return false
93
+ ensure
94
+ key_manager.finish if key_manager
82
95
  end
83
- end
84
96
 
85
- error { "all authorization methods failed (tried #{attempted.join(', ')})" }
86
- return false
87
- ensure
88
- key_manager.finish if key_manager
89
- end
90
-
91
- # Blocks until a packet is received. It silently handles USERAUTH_BANNER
92
- # packets, and will raise an error if any packet is received that is not
93
- # valid during user authentication.
94
- def next_message
95
- loop do
96
- packet = transport.next_message
97
-
98
- case packet.type
99
- when USERAUTH_BANNER
100
- info { packet[:message] }
101
- # TODO add a hook for people to retrieve the banner when it is sent
102
-
103
- when USERAUTH_FAILURE
104
- @allowed_auth_methods = packet[:authentications].split(/,/)
105
- debug { "allowed methods: #{packet[:authentications]}" }
106
- return packet
107
-
108
- when USERAUTH_METHOD_RANGE, SERVICE_ACCEPT
109
- return packet
97
+ # Blocks until a packet is received. It silently handles USERAUTH_BANNER
98
+ # packets, and will raise an error if any packet is received that is not
99
+ # valid during user authentication.
100
+ def next_message
101
+ loop do
102
+ packet = transport.next_message
103
+
104
+ case packet.type
105
+ when USERAUTH_BANNER
106
+ info { packet[:message] }
107
+ # TODO add a hook for people to retrieve the banner when it is sent
108
+
109
+ when USERAUTH_FAILURE
110
+ @allowed_auth_methods = packet[:authentications].split(/,/)
111
+ debug { "allowed methods: #{packet[:authentications]}" }
112
+ return packet
113
+
114
+ when USERAUTH_METHOD_RANGE, SERVICE_ACCEPT
115
+ return packet
116
+
117
+ when USERAUTH_SUCCESS
118
+ transport.hint :authenticated
119
+ return packet
120
+
121
+ else
122
+ raise Net::SSH::Exception, "unexpected message #{packet.type} (#{packet})"
123
+ end
124
+ end
125
+ end
110
126
 
111
- when USERAUTH_SUCCESS
112
- transport.hint :authenticated
113
- return packet
127
+ # Blocks until a packet is received, and returns it if it is of the given
128
+ # type. If it is not, an exception is raised.
129
+ def expect_message(type)
130
+ message = next_message
131
+ raise Net::SSH::Exception, "expected #{type}, got #{message.type} (#{message})" unless message.type == type
114
132
 
115
- else
116
- raise Net::SSH::Exception, "unexpected message #{packet.type} (#{packet})"
133
+ message
117
134
  end
118
- end
119
- end
120
135
 
121
- # Blocks until a packet is received, and returns it if it is of the given
122
- # type. If it is not, an exception is raised.
123
- def expect_message(type)
124
- message = next_message
125
- unless message.type == type
126
- raise Net::SSH::Exception, "expected #{type}, got #{message.type} (#{message})"
127
- end
128
- message
129
- end
136
+ private
130
137
 
131
- private
138
+ # Returns an array of paths to the key files usually defined
139
+ # by system default.
140
+ def default_keys
141
+ %w[~/.ssh/id_ed25519 ~/.ssh/id_rsa ~/.ssh/id_dsa ~/.ssh/id_ecdsa
142
+ ~/.ssh2/id_ed25519 ~/.ssh2/id_rsa ~/.ssh2/id_dsa ~/.ssh2/id_ecdsa]
143
+ end
132
144
 
133
- # Returns an array of paths to the key files usually defined
134
- # by system default.
135
- def default_keys
136
- if defined?(OpenSSL::PKey::EC)
137
- %w(~/.ssh/id_ed25519 ~/.ssh/id_rsa ~/.ssh/id_dsa ~/.ssh/id_ecdsa
138
- ~/.ssh2/id_ed25519 ~/.ssh2/id_rsa ~/.ssh2/id_dsa ~/.ssh2/id_ecdsa)
139
- else
140
- %w(~/.ssh/id_dsa ~/.ssh/id_rsa ~/.ssh2/id_dsa ~/.ssh2/id_rsa)
145
+ # Returns an array of paths to the key files that should be used when
146
+ # attempting any key-based authentication mechanism.
147
+ def keys
148
+ Array(options[:keys])
141
149
  end
142
- end
143
150
 
144
- # Returns an array of paths to the key files that should be used when
145
- # attempting any key-based authentication mechanism.
146
- def keys
147
- Array(options[:keys] || default_keys)
148
- end
151
+ # Returns an array of paths to the keycert files that should be used when
152
+ # attempting any key-based authentication mechanism.
153
+ def keycerts
154
+ Array(options[:keycerts])
155
+ end
149
156
 
150
- # Returns an array of the key data that should be used when
151
- # attempting any key-based authentication mechanism.
152
- def key_data
153
- Array(options[:key_data])
157
+ # Returns an array of the key data that should be used when
158
+ # attempting any key-based authentication mechanism.
159
+ def key_data
160
+ Array(options[:key_data])
161
+ end
154
162
  end
163
+ end
155
164
  end
156
- end; end; end
165
+ end