net-ssh 5.1.0 → 5.2.0.rc1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e14e949eb49846743dae609d76bb3ff8e7e26332
4
- data.tar.gz: b373032655d4f986f1695d231eafc1d7f3a7fffd
3
+ metadata.gz: f322b0b79581a7d7b24a917b79ddabc8563b5a5c
4
+ data.tar.gz: a9e3a2c9cfa281f1b91a335bda58f4b6dcc568fd
5
5
  SHA512:
6
- metadata.gz: 073c77cec7e4420dec75779906809319fb65f8163a4b99cfd3fbafaa1f1fce1e209ac96cb8ac22c82c182835f1ff7609625492108612f2158c1ba26fffd828a1
7
- data.tar.gz: 293eb2965ccb35840c5bc29abc8c5be3ae78ab55461ce7ca42cc21045ed3ef02bcf44356e2bb33ef115e479ef1c11e269e88cd8d6f260a79b6e75273fe869175
6
+ metadata.gz: fcd0f1c4c2a6833e75509523cf19195cbb2320860f5f20800ce780f785d52093ae24331b27ac3dcfd49d62de341048ed611078f15449f3052830cf7c1630e309
7
+ data.tar.gz: 3b3fa8989372dbbe9a84fdfdbc22dde5b9ea69fcb206b9e859aa83f6a46b729b117dfe024c49a1fe969a2fedc2dbacbc190d2b5764603efe6780c10f15b31f58
@@ -1,3 +1 @@
1
- *�6+3T�t~
2
- ��k�)��Ȗ0��cq�?�J�k��d�_�@����&%y]ȋt�������V��Z���SdQ%n�4"U�8�ȯ5�ud�9���wO�'"7�׻
3
- =�BH6¾ !n�'Pi���վQB3�U�� �l�M�L~�-���m���M4��J�~��-�X�π͋�P��e7��s@��#�`>Wٌ���M���G�@$Ke�P�N\kn8x^��\
1
+ 4�QQ�t���UPSG*�˩�rMd�"\B���b2�b�n����!�8����)�a,�(k��2$��.cKKS���U@T�~g�� &�0v)��Z�%���/H-�z�˺�{v�1j�~�_*M/f��J�feѬ*p������M]��&��|ϕO�yA'F��ha� Z������CZe�^�t���X�,eJ%&u_zwn- ;tx�H��,�N�HYs���iL���J�~�1�� 6��\���� A
data.tar.gz.sig CHANGED
Binary file
@@ -3,3 +3,6 @@ inherit_from: .rubocop_todo.yml
3
3
  AllCops:
4
4
  Exclude:
5
5
  - 'tryout/**/*'
6
+
7
+ Style/DoubleNegation:
8
+ Enabled: false
@@ -1,8 +1,15 @@
1
+ === 5.2.0.rc1
2
+
3
+ * Interpret * and ? in know_hosts file [Romain Tartière, #660]
4
+ * New :check_host_ip so ip checking can be disabled in known hosts [Romain Tartière, #656]
5
+
6
+ === 5.1.0
7
+
1
8
  === 5.1.0.rc1
2
9
 
3
10
  * Support new OpenSSH private key format for rsa - bcrypt for rsa (ed25519 already supported) [#646]
4
11
  * Support IdentityAgent is ssh config [Frank Groeneveld, #645]
5
- * Improve Match processin in ssh config [Aleksandrs Ļedovskis, #642]
12
+ * Improve Match processing in ssh config [Aleksandrs Ļedovskis, #642]
6
13
  * Ignore signature verification when verify_host_key is never [Piotr Kliczewski, #641]
7
14
  * Alg preference was changed to prefer stronger encryptions [Tray, #637]
8
15
 
@@ -73,7 +73,7 @@ module Net
73
73
  max_win_size send_env use_agent number_of_password_prompts
74
74
  append_all_supported_algorithms non_interactive password_prompt
75
75
  agent_socket_factory minimum_dh_bits verify_host_key
76
- fingerprint_hash
76
+ fingerprint_hash check_host_ip
77
77
  ]
78
78
 
79
79
  # The standard means of starting a new SSH connection. When used with a
@@ -108,6 +108,8 @@ module Net
108
108
  # * :bind_address => the IP address on the connecting machine to use in
109
109
  # establishing connection. (:bind_address is discarded if :proxy
110
110
  # is set.)
111
+ # * :check_host_ip => Also ckeck IP address when connecting to remote host.
112
+ # Defaults to +true+.
111
113
  # * :compression => the compression algorithm to use, or +true+ to use
112
114
  # whatever is supported.
113
115
  # * :compression_level => the compression level to use when sending data
@@ -290,6 +292,8 @@ module Net
290
292
  %i[password passphrase].each do |key|
291
293
  options.delete(key) if options.key?(key) && options[key].nil?
292
294
  end
295
+
296
+ options[:check_host_ip] = true unless options.key?(:check_host_ip)
293
297
  end
294
298
 
295
299
  def self._sanitize_options(options)
@@ -29,6 +29,17 @@ module Net
29
29
  MEND = "-----END OPENSSH PRIVATE KEY-----\n"
30
30
  MAGIC = "openssh-key-v1"
31
31
 
32
+ class DecryptError < ArgumentError
33
+ def initialize(message, encrypted_key: false)
34
+ super(message)
35
+ @encrypted_key = encrypted_key
36
+ end
37
+
38
+ def encrypted_key?
39
+ return @encrypted_key
40
+ end
41
+ end
42
+
32
43
  def self.read(datafull, password)
33
44
  raise ArgumentError.new("Expected #{MBEGIN} at start of private key") unless datafull.start_with?(MBEGIN)
34
45
  raise ArgumentError.new("Expected #{MEND} at end of private key") unless datafull.end_with?(MEND)
@@ -74,7 +85,7 @@ module Net
74
85
  check1 = decoded.read_long
75
86
  check2 = decoded.read_long
76
87
 
77
- raise ArgumentError, "Decrypt failed on private key" if (check1 != check2)
88
+ raise DecryptError.new("Decrypt failed on private key", encrypted_key: kdfname == 'bcrypt') if (check1 != check2)
78
89
 
79
90
  type_name = decoded.read_string
80
91
  case type_name
@@ -50,16 +50,17 @@ module Net
50
50
  # encrypted (requiring a passphrase to use), the user will be
51
51
  # prompted to enter their password unless passphrase works.
52
52
  def load_data_private_key(data, passphrase=nil, ask_passphrase=true, filename="", prompt=Prompt.default)
53
- key_read, error_classes = classify_key(data, filename)
53
+ key_type = classify_key(data, filename)
54
54
 
55
- encrypted_key = data.match(/ENCRYPTED/)
55
+ encrypted_key = nil
56
56
  tries = 0
57
57
 
58
58
  prompter = nil
59
59
  result =
60
60
  begin
61
- key_read[data, passphrase || 'invalid']
62
- rescue *error_classes
61
+ key_type.read(data, passphrase || 'invalid')
62
+ rescue *key_type.error_classes => e
63
+ encrypted_key = !!key_type.encrypted_key?(data, e) if encrypted_key.nil?
63
64
  if encrypted_key && ask_passphrase
64
65
  tries += 1
65
66
  if tries <= 3
@@ -106,20 +107,108 @@ module Net
106
107
 
107
108
  private
108
109
 
110
+ # rubocop:disable Style/Documentation, Lint/DuplicateMethods
111
+ class KeyType
112
+ def self.read(key_data, passphrase)
113
+ raise Exception, "TODO subclasses should implement read"
114
+ end
115
+
116
+ def self.error_classes
117
+ raise Exception, "TODO subclasses should implement read"
118
+ end
119
+
120
+ def self.encrypted_key?(data, error)
121
+ raise Exception, "TODO subclasses should implement is_encrypted_key"
122
+ end
123
+ end
124
+
125
+ class OpenSSHPrivateKeyType < KeyType
126
+ def self.read(key_data, passphrase)
127
+ Net::SSH::Authentication::ED25519::OpenSSHPrivateKeyLoader.read(key_data, passphrase)
128
+ end
129
+
130
+ def self.error_classes
131
+ [Net::SSH::Authentication::ED25519::OpenSSHPrivateKeyLoader::DecryptError]
132
+ end
133
+
134
+ def self.encrypted_key?(key_data, decode_error)
135
+ decode_error.is_a?(Net::SSH::Authentication::ED25519::OpenSSHPrivateKeyLoader::DecryptError) && decode_error.encrypted_key?
136
+ end
137
+ end
138
+
139
+ class OpenSSLKeyTypeBase < KeyType
140
+ def self.open_ssl_class
141
+ raise Exception, "TODO: subclasses should implement"
142
+ end
143
+
144
+ def self.read(key_data, passphrase)
145
+ open_ssl_class.new(key_data, passphrase)
146
+ end
147
+
148
+ def self.encrypted_key?(key_data, error)
149
+ key_data.match(/ENCRYPTED/)
150
+ end
151
+ end
152
+
153
+ class OpenSSLPKeyType < OpenSSLKeyTypeBase
154
+ def self.read(key_data, passphrase)
155
+ open_ssl_class.read(key_data, passphrase)
156
+ end
157
+
158
+ def self.open_ssl_class
159
+ OpenSSL::PKey
160
+ end
161
+
162
+ def self.error_classes
163
+ [ArgumentError, OpenSSL::PKey::PKeyError]
164
+ end
165
+ end
166
+
167
+ class OpenSSLDSAKeyType < OpenSSLKeyTypeBase
168
+ def self.open_ssl_class
169
+ OpenSSL::PKey::DSA
170
+ end
171
+
172
+ def self.error_classes
173
+ [OpenSSL::PKey::DSAError]
174
+ end
175
+ end
176
+
177
+ class OpenSSLRSAKeyType < OpenSSLKeyTypeBase
178
+ def self.open_ssl_class
179
+ OpenSSL::PKey::RSA
180
+ end
181
+
182
+ def self.error_classes
183
+ [OpenSSL::PKey::RSAError]
184
+ end
185
+ end
186
+
187
+ class OpenSSLECKeyType < OpenSSLKeyTypeBase
188
+ def self.open_ssl_class
189
+ OpenSSL::PKey::EC
190
+ end
191
+
192
+ def self.error_classes
193
+ [OpenSSL::PKey::ECError]
194
+ end
195
+ end
196
+ # rubocop:enable Style/Documentation, Lint/DuplicateMethods
197
+
109
198
  # Determine whether the file describes an RSA or DSA key, and return how load it
110
199
  # appropriately.
111
200
  def classify_key(data, filename)
112
201
  if data.match(/-----BEGIN OPENSSH PRIVATE KEY-----/)
113
202
  Net::SSH::Authentication::ED25519Loader.raiseUnlessLoaded("OpenSSH keys only supported if ED25519 is available")
114
- return ->(key_data, passphrase) { Net::SSH::Authentication::ED25519::OpenSSHPrivateKeyLoader.read(key_data, passphrase) }, [ArgumentError]
203
+ return OpenSSHPrivateKeyType
115
204
  elsif OpenSSL::PKey.respond_to?(:read)
116
- return ->(key_data, passphrase) { OpenSSL::PKey.read(key_data, passphrase) }, [ArgumentError, OpenSSL::PKey::PKeyError]
205
+ return OpenSSLPKeyType
117
206
  elsif data.match(/-----BEGIN DSA PRIVATE KEY-----/)
118
- return ->(key_data, passphrase) { OpenSSL::PKey::DSA.new(key_data, passphrase) }, [OpenSSL::PKey::DSAError]
207
+ return OpenSSLDSAKeyType
119
208
  elsif data.match(/-----BEGIN RSA PRIVATE KEY-----/)
120
- return ->(key_data, passphrase) { OpenSSL::PKey::RSA.new(key_data, passphrase) }, [OpenSSL::PKey::RSAError]
209
+ return OpenSSLRSAKeyType
121
210
  elsif data.match(/-----BEGIN EC PRIVATE KEY-----/) && defined?(OpenSSL::PKey::EC)
122
- return ->(key_data, passphrase) { OpenSSL::PKey::EC.new(key_data, passphrase) }, [OpenSSL::PKey::ECError]
211
+ return OpenSSLECKeyType
123
212
  elsif data.match(/-----BEGIN (.+) PRIVATE KEY-----/)
124
213
  raise OpenSSL::PKey::PKeyError, "not a supported key type '#{$1}'"
125
214
  else
@@ -53,13 +53,13 @@ module Net
53
53
  # Searches all known host files (see KnownHosts.hostfiles) for all keys
54
54
  # of the given host. Returns an enumerable of keys found.
55
55
  def search_for(host, options={})
56
- HostKeys.new(search_in(hostfiles(options), host), host, self, options)
56
+ HostKeys.new(search_in(hostfiles(options), host, options), host, self, options)
57
57
  end
58
58
 
59
59
  # Search for all known keys for the given host, in every file given in
60
60
  # the +files+ array. Returns the list of keys.
61
- def search_in(files, host)
62
- files.flat_map { |file| KnownHosts.new(file).keys_for(host) }
61
+ def search_in(files, host, options = {})
62
+ files.flat_map { |file| KnownHosts.new(file).keys_for(host, options) }
63
63
  end
64
64
 
65
65
  # Looks in the given +options+ hash for the :user_known_hosts_file and
@@ -119,11 +119,13 @@ module Net
119
119
  # "[net.ssh.test]:5555"
120
120
  # "[1,2,3,4]:5555"
121
121
  # "[net.ssh.test]:5555,[1.2.3.4]:5555
122
- def keys_for(host)
122
+ def keys_for(host, options = {})
123
123
  keys = []
124
124
  return keys unless File.readable?(source)
125
125
 
126
126
  entries = host.split(/,/)
127
+ host_name = entries[0]
128
+ host_ip = entries[1]
127
129
 
128
130
  File.open(source) do |file|
129
131
  scanner = StringScanner.new("")
@@ -134,8 +136,10 @@ module Net
134
136
  next if scanner.match?(/$|#/)
135
137
 
136
138
  hostlist = scanner.scan(/\S+/).split(/,/)
137
- found = entries.all? { |entry| hostlist.include?(entry) } ||
138
- known_host_hash?(hostlist, entries)
139
+ found = hostlist.any? { |pattern| match(host_name, pattern) } || known_host_hash?(hostlist, entries)
140
+ next unless found
141
+
142
+ found = hostlist.include?(host_ip) if options[:check_host_ip] && entries.size > 1 && hostlist.size > 1
139
143
  next unless found
140
144
 
141
145
  scanner.skip(/\s*/)
@@ -152,6 +156,17 @@ module Net
152
156
  keys
153
157
  end
154
158
 
159
+ def match(host, pattern)
160
+ # see man 8 sshd for pattern details
161
+ pattern_regexp = pattern.split('*').map do |x|
162
+ x.split('?').map do |y|
163
+ Regexp.escape(y)
164
+ end.join('.')
165
+ end.join('[^.]*')
166
+
167
+ host =~ Regexp.new("\\A#{pattern_regexp}\\z")
168
+ end
169
+
155
170
  # Indicates whether one of the entries matches an hostname that has been
156
171
  # stored as a HMAC-SHA1 hash in the known hosts.
157
172
  def known_host_hash?(hostlist, entries)
@@ -279,7 +279,7 @@ module Net
279
279
  # method.
280
280
  class CompatibleVerifier
281
281
  def initialize(verifier)
282
- @verifier
282
+ @verifier = verifier
283
283
  end
284
284
 
285
285
  def verify(arguments)
@@ -49,14 +49,14 @@ module Net
49
49
  MAJOR = 5
50
50
 
51
51
  # The minor component of this version of the Net::SSH library
52
- MINOR = 1
52
+ MINOR = 2
53
53
 
54
54
  # The tiny component of this version of the Net::SSH library
55
55
  TINY = 0
56
56
 
57
57
  # The prerelease component of this version of the Net::SSH library
58
58
  # nil allowed
59
- PRE = nil
59
+ PRE = "rc1"
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)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: net-ssh
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.1.0
4
+ version: 5.2.0.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jamis Buck
@@ -32,7 +32,7 @@ cert_chain:
32
32
  ZFwoIuXKeDmTTpryd/vI7sdLXDuV6MbWOLGh6gXn9RDDXG1EqEXW0bjovATBMpdH
33
33
  9OGohJvAFzcvhDTWPwT6w3PG5B80pqb9j1hEAg==
34
34
  -----END CERTIFICATE-----
35
- date: 2018-12-28 00:00:00.000000000 Z
35
+ date: 2019-03-02 00:00:00.000000000 Z
36
36
  dependencies:
37
37
  - !ruby/object:Gem::Dependency
38
38
  name: bcrypt_pbkdf
@@ -262,9 +262,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
262
262
  version: 2.2.6
263
263
  required_rubygems_version: !ruby/object:Gem::Requirement
264
264
  requirements:
265
- - - ">="
265
+ - - ">"
266
266
  - !ruby/object:Gem::Version
267
- version: '0'
267
+ version: 1.3.1
268
268
  requirements: []
269
269
  rubyforge_project:
270
270
  rubygems_version: 2.6.8
metadata.gz.sig CHANGED
Binary file