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 +4 -4
- checksums.yaml.gz.sig +1 -3
- data.tar.gz.sig +0 -0
- data/.rubocop.yml +3 -0
- data/CHANGES.txt +8 -1
- data/lib/net/ssh.rb +5 -1
- data/lib/net/ssh/authentication/ed25519.rb +12 -1
- data/lib/net/ssh/key_factory.rb +98 -9
- data/lib/net/ssh/known_hosts.rb +21 -6
- data/lib/net/ssh/transport/session.rb +1 -1
- data/lib/net/ssh/version.rb +2 -2
- metadata +4 -4
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f322b0b79581a7d7b24a917b79ddabc8563b5a5c
|
4
|
+
data.tar.gz: a9e3a2c9cfa281f1b91a335bda58f4b6dcc568fd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fcd0f1c4c2a6833e75509523cf19195cbb2320860f5f20800ce780f785d52093ae24331b27ac3dcfd49d62de341048ed611078f15449f3052830cf7c1630e309
|
7
|
+
data.tar.gz: 3b3fa8989372dbbe9a84fdfdbc22dde5b9ea69fcb206b9e859aa83f6a46b729b117dfe024c49a1fe969a2fedc2dbacbc190d2b5764603efe6780c10f15b31f58
|
checksums.yaml.gz.sig
CHANGED
@@ -1,3 +1 @@
|
|
1
|
-
|
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
|
data/.rubocop.yml
CHANGED
data/CHANGES.txt
CHANGED
@@ -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
|
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
|
|
data/lib/net/ssh.rb
CHANGED
@@ -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
|
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
|
data/lib/net/ssh/key_factory.rb
CHANGED
@@ -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
|
-
|
53
|
+
key_type = classify_key(data, filename)
|
54
54
|
|
55
|
-
encrypted_key =
|
55
|
+
encrypted_key = nil
|
56
56
|
tries = 0
|
57
57
|
|
58
58
|
prompter = nil
|
59
59
|
result =
|
60
60
|
begin
|
61
|
-
|
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
|
203
|
+
return OpenSSHPrivateKeyType
|
115
204
|
elsif OpenSSL::PKey.respond_to?(:read)
|
116
|
-
return
|
205
|
+
return OpenSSLPKeyType
|
117
206
|
elsif data.match(/-----BEGIN DSA PRIVATE KEY-----/)
|
118
|
-
return
|
207
|
+
return OpenSSLDSAKeyType
|
119
208
|
elsif data.match(/-----BEGIN RSA PRIVATE KEY-----/)
|
120
|
-
return
|
209
|
+
return OpenSSLRSAKeyType
|
121
210
|
elsif data.match(/-----BEGIN EC PRIVATE KEY-----/) && defined?(OpenSSL::PKey::EC)
|
122
|
-
return
|
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
|
data/lib/net/ssh/known_hosts.rb
CHANGED
@@ -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 =
|
138
|
-
|
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)
|
data/lib/net/ssh/version.rb
CHANGED
@@ -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 =
|
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 =
|
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.
|
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:
|
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:
|
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
|