net-ssh 5.0.2 → 5.1.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 +5 -5
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.travis.yml +2 -2
- data/CHANGES.txt +12 -0
- data/README.rdoc +25 -0
- data/lib/net/ssh/authentication/agent.rb +9 -3
- data/lib/net/ssh/authentication/ed25519.rb +62 -45
- data/lib/net/ssh/authentication/key_manager.rb +1 -1
- data/lib/net/ssh/authentication/methods/publickey.rb +2 -0
- data/lib/net/ssh/buffer.rb +40 -0
- data/lib/net/ssh/config.rb +17 -5
- data/lib/net/ssh/key_factory.rb +1 -1
- data/lib/net/ssh/test.rb +6 -6
- data/lib/net/ssh/test/extensions.rb +2 -0
- data/lib/net/ssh/transport/algorithms.rb +107 -90
- data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +1 -1
- data/lib/net/ssh/transport/openssl.rb +16 -0
- data/lib/net/ssh/transport/packet_stream.rb +4 -7
- data/lib/net/ssh/transport/session.rb +26 -4
- data/lib/net/ssh/verifiers/accept_new.rb +7 -0
- data/lib/net/ssh/verifiers/always.rb +4 -0
- data/lib/net/ssh/verifiers/never.rb +4 -0
- data/lib/net/ssh/version.rb +3 -3
- metadata +5 -5
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a3fb9e448901ff8c2e48d5c99298ecc3129db153
|
4
|
+
data.tar.gz: dcdb5d927ab46e316b8a87354ee0e5431c2e8aa7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 35f1fa4f2b19ee742ae1e89656919cfbb177175e52b9ec5c1bb6b6254afd1e6341b4d6ba4044a981e381848cdfc8c2670c78ea1119344e6733822f5d03223994
|
7
|
+
data.tar.gz: 59038c63ce9f6882b95538f2c984dcbc0a8b60c66092c22224d2cb605e6bb2f3aae3bb18be6d48fa3aa2ab7e99c616413ea03d07c2118fe31b720808e6d7401d
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data.tar.gz.sig
CHANGED
Binary file
|
data/.travis.yml
CHANGED
@@ -34,13 +34,13 @@ matrix:
|
|
34
34
|
|
35
35
|
install:
|
36
36
|
- export JRUBY_OPTS='--client -J-XX:+TieredCompilation -J-XX:TieredStopAtLevel=1 -Xcext.enabled=false -J-Xss2m -Xcompile.invokedynamic=false'
|
37
|
-
- sudo pip install ansible
|
37
|
+
- sudo pip install ansible urllib3 pyOpenSSL ndg-httpsclient pyasn1
|
38
38
|
- gem install bundler -v "= 1.16"
|
39
39
|
- gem list bundler
|
40
40
|
- bundle _1.16_ install
|
41
41
|
- bundle _1.16_ -v
|
42
42
|
- BUNDLE_GEMFILE=./Gemfile.noed25519 bundle _1.16_ install
|
43
|
-
- sudo ansible-galaxy install
|
43
|
+
- sudo ansible-galaxy install rvm.ruby
|
44
44
|
- sudo chown -R travis:travis /home/travis/.ansible
|
45
45
|
- ansible-playbook ./test/integration/playbook.yml -i "localhost," --become -c local -e 'no_rvm=true' -e 'myuser=travis' -e 'mygroup=travis' -e 'homedir=/home/travis'
|
46
46
|
|
data/CHANGES.txt
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
=== 5.1.0.rc1
|
2
|
+
|
3
|
+
* Support new OpenSSH private key format for rsa - bcrypt for rsa (ed25519 already supported) [#646]
|
4
|
+
* Support IdentityAgent is ssh config [Frank Groeneveld, #645]
|
5
|
+
* Improve Match processin in ssh config [Aleksandrs Ļedovskis, #642]
|
6
|
+
* Ignore signature verification when verify_host_key is never [Piotr Kliczewski, #641]
|
7
|
+
* Alg preference was changed to prefer stronger encryptions [Tray, #637]
|
8
|
+
|
9
|
+
=== 5.0.2
|
10
|
+
|
11
|
+
* fix ctr for jruby [#612]
|
12
|
+
|
1
13
|
=== 5.0.1
|
2
14
|
|
3
15
|
* default_keys were not loaded even if no keys or key_data options specified [#607]
|
data/README.rdoc
CHANGED
@@ -2,6 +2,9 @@
|
|
2
2
|
{<img src="https://badges.gitter.im/net-ssh/net-ssh.svg" alt="Join the chat at https://gitter.im/net-ssh/net-ssh">}[https://gitter.im/net-ssh/net-ssh?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge]
|
3
3
|
{<img src="https://travis-ci.org/net-ssh/net-ssh.svg?branch=master" alt="Build Status" />}[https://travis-ci.org/net-ssh/net-ssh]
|
4
4
|
{<img src="https://codecov.io/gh/net-ssh/net-ssh/branch/master/graph/badge.svg" alt="Coverage status" />}[https://codecov.io/gh/net-ssh/net-ssh]
|
5
|
+
{<img src="https://opencollective.com/net-ssh/backers/badge.svg" alt="Backers on Open Collective" />}[#backers]
|
6
|
+
{<img src="https://opencollective.com/net-ssh/sponsors/badge.svg" alt="Sponsors on Open Collective" />}[#sponsors]
|
7
|
+
|
5
8
|
|
6
9
|
= Net::SSH 5.x
|
7
10
|
|
@@ -142,6 +145,28 @@ For time to time, the public certificate associated to the private key needs to
|
|
142
145
|
mv gem-public_cert.pem net-ssh-public_cert.pem
|
143
146
|
gem cert --add net-ssh-public_cert.pem
|
144
147
|
|
148
|
+
== CREDITS
|
149
|
+
|
150
|
+
=== Contributors
|
151
|
+
|
152
|
+
This project exists thanks to all the people who contribute.
|
153
|
+
|
154
|
+
{<img src="https://opencollective.com/net-ssh/contributors.svg?width=890&button=false" />}["graphs/contributors"]
|
155
|
+
|
156
|
+
|
157
|
+
=== Backers
|
158
|
+
|
159
|
+
Thank you to all our backers! 🙏 {Become a backer}[https://opencollective.com/net-ssh#backer)]
|
160
|
+
|
161
|
+
{<img src="https://opencollective.com/net-ssh/backers.svg?width=890”>}["https://opencollective.com/net-ssh#backers"]
|
162
|
+
|
163
|
+
=== Sponsors
|
164
|
+
|
165
|
+
Support this project by becoming a sponsor. Your logo will show up here with a link to your website. {Become a sponsor}[https://opencollective.com/net-ssh#sponsor]
|
166
|
+
{<img src="https://opencollective.com/net-ssh/sponsor/0/avatar.svg" alt="Sponsor" />}[https://opencollective.com/net-ssh/sponsor/0/website]
|
167
|
+
|
168
|
+
|
169
|
+
|
145
170
|
|
146
171
|
== LICENSE:
|
147
172
|
|
@@ -62,9 +62,9 @@ module Net
|
|
62
62
|
|
63
63
|
# Instantiates a new agent object, connects to a running SSH agent,
|
64
64
|
# negotiates the agent protocol version, and returns the agent object.
|
65
|
-
def self.connect(logger=nil, agent_socket_factory = nil)
|
65
|
+
def self.connect(logger=nil, agent_socket_factory = nil, identity_agent = nil)
|
66
66
|
agent = new(logger)
|
67
|
-
agent.connect!(agent_socket_factory)
|
67
|
+
agent.connect!(agent_socket_factory, identity_agent)
|
68
68
|
agent.negotiate!
|
69
69
|
agent
|
70
70
|
end
|
@@ -79,11 +79,13 @@ module Net
|
|
79
79
|
# given by the attribute writers. If the agent on the other end of the
|
80
80
|
# socket reports that it is an SSH2-compatible agent, this will fail
|
81
81
|
# (it only supports the ssh-agent distributed by OpenSSH).
|
82
|
-
def connect!(agent_socket_factory = nil)
|
82
|
+
def connect!(agent_socket_factory = nil, identity_agent = nil)
|
83
83
|
debug { "connecting to ssh-agent" }
|
84
84
|
@socket =
|
85
85
|
if agent_socket_factory
|
86
86
|
agent_socket_factory.call
|
87
|
+
elsif identity_agent
|
88
|
+
unix_socket_class.open(identity_agent)
|
87
89
|
elsif ENV['SSH_AUTH_SOCK'] && unix_socket_class
|
88
90
|
unix_socket_class.open(ENV['SSH_AUTH_SOCK'])
|
89
91
|
elsif Gem.win_platform? && RUBY_ENGINE != "jruby"
|
@@ -124,6 +126,10 @@ module Net
|
|
124
126
|
comment_str = body.read_string
|
125
127
|
begin
|
126
128
|
key = Buffer.new(key_str).read_key
|
129
|
+
if key.nil?
|
130
|
+
error { "ignoring invalid key: #{comment_str}" }
|
131
|
+
next
|
132
|
+
end
|
127
133
|
key.extend(Comment)
|
128
134
|
key.comment = comment_str
|
129
135
|
identities.push key
|
@@ -22,51 +22,14 @@ module Net
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
-
class
|
26
|
-
include Net::SSH::Authentication::PubKeyFingerprint
|
27
|
-
|
28
|
-
attr_reader :verify_key
|
29
|
-
|
30
|
-
def initialize(data)
|
31
|
-
@verify_key = ::Ed25519::VerifyKey.new(data)
|
32
|
-
end
|
33
|
-
|
34
|
-
def self.read_keyblob(buffer)
|
35
|
-
PubKey.new(buffer.read_string)
|
36
|
-
end
|
37
|
-
|
38
|
-
def to_blob
|
39
|
-
Net::SSH::Buffer.from(:mstring,"ssh-ed25519",:string,@verify_key.to_bytes).to_s
|
40
|
-
end
|
41
|
-
|
42
|
-
def ssh_type
|
43
|
-
"ssh-ed25519"
|
44
|
-
end
|
45
|
-
|
46
|
-
def ssh_signature_type
|
47
|
-
ssh_type
|
48
|
-
end
|
49
|
-
|
50
|
-
def ssh_do_verify(sig,data)
|
51
|
-
@verify_key.verify(sig,data)
|
52
|
-
end
|
53
|
-
|
54
|
-
def to_pem
|
55
|
-
# TODO this is not pem
|
56
|
-
ssh_type + Base64.encode64(@verify_key.to_bytes)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
class PrivKey
|
25
|
+
class OpenSSHPrivateKeyLoader
|
61
26
|
CipherFactory = Net::SSH::Transport::CipherFactory
|
62
27
|
|
63
28
|
MBEGIN = "-----BEGIN OPENSSH PRIVATE KEY-----\n"
|
64
29
|
MEND = "-----END OPENSSH PRIVATE KEY-----\n"
|
65
30
|
MAGIC = "openssh-key-v1"
|
66
31
|
|
67
|
-
|
68
|
-
|
69
|
-
def initialize(datafull,password)
|
32
|
+
def self.read(datafull, password)
|
70
33
|
raise ArgumentError.new("Expected #{MBEGIN} at start of private key") unless datafull.start_with?(MBEGIN)
|
71
34
|
raise ArgumentError.new("Expected #{MEND} at end of private key") unless datafull.end_with?(MEND)
|
72
35
|
datab64 = datafull[MBEGIN.size...-MEND.size]
|
@@ -113,10 +76,64 @@ module Net
|
|
113
76
|
|
114
77
|
raise ArgumentError, "Decrypt failed on private key" if (check1 != check2)
|
115
78
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
79
|
+
type_name = decoded.read_string
|
80
|
+
case type_name
|
81
|
+
when "ssh-ed25519"
|
82
|
+
PrivKey.new(decoded)
|
83
|
+
else
|
84
|
+
decoded.read_private_keyblob(type_name)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class PubKey
|
90
|
+
include Net::SSH::Authentication::PubKeyFingerprint
|
91
|
+
|
92
|
+
attr_reader :verify_key
|
93
|
+
|
94
|
+
def initialize(data)
|
95
|
+
@verify_key = ::Ed25519::VerifyKey.new(data)
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.read_keyblob(buffer)
|
99
|
+
PubKey.new(buffer.read_string)
|
100
|
+
end
|
101
|
+
|
102
|
+
def to_blob
|
103
|
+
Net::SSH::Buffer.from(:mstring,"ssh-ed25519",:string,@verify_key.to_bytes).to_s
|
104
|
+
end
|
105
|
+
|
106
|
+
def ssh_type
|
107
|
+
"ssh-ed25519"
|
108
|
+
end
|
109
|
+
|
110
|
+
def ssh_signature_type
|
111
|
+
ssh_type
|
112
|
+
end
|
113
|
+
|
114
|
+
def ssh_do_verify(sig,data)
|
115
|
+
@verify_key.verify(sig,data)
|
116
|
+
end
|
117
|
+
|
118
|
+
def to_pem
|
119
|
+
# TODO this is not pem
|
120
|
+
ssh_type + Base64.encode64(@verify_key.to_bytes)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
class PrivKey
|
125
|
+
CipherFactory = Net::SSH::Transport::CipherFactory
|
126
|
+
|
127
|
+
MBEGIN = "-----BEGIN OPENSSH PRIVATE KEY-----\n"
|
128
|
+
MEND = "-----END OPENSSH PRIVATE KEY-----\n"
|
129
|
+
MAGIC = "openssh-key-v1"
|
130
|
+
|
131
|
+
attr_reader :sign_key
|
132
|
+
|
133
|
+
def initialize(buffer)
|
134
|
+
pk = buffer.read_string
|
135
|
+
sk = buffer.read_string
|
136
|
+
_comment = buffer.read_string
|
120
137
|
|
121
138
|
@pk = pk
|
122
139
|
@sign_key = SigningKeyFromFile.new(pk,sk)
|
@@ -142,8 +159,8 @@ module Net
|
|
142
159
|
@sign_key.sign(data)
|
143
160
|
end
|
144
161
|
|
145
|
-
def self.read(data,password)
|
146
|
-
|
162
|
+
def self.read(data, password)
|
163
|
+
OpenSSHPrivateKeyLoader.read(data, password)
|
147
164
|
end
|
148
165
|
end
|
149
166
|
end
|
@@ -176,7 +176,7 @@ module Net
|
|
176
176
|
# or if the agent is otherwise not available.
|
177
177
|
def agent
|
178
178
|
return unless use_agent?
|
179
|
-
@agent ||= Agent.connect(logger, options[:agent_socket_factory])
|
179
|
+
@agent ||= Agent.connect(logger, options[:agent_socket_factory], options[:identity_agent])
|
180
180
|
rescue AgentNotAvailable
|
181
181
|
@use_agent = false
|
182
182
|
nil
|
data/lib/net/ssh/buffer.rb
CHANGED
@@ -249,6 +249,46 @@ module Net
|
|
249
249
|
return (type ? read_keyblob(type) : nil)
|
250
250
|
end
|
251
251
|
|
252
|
+
def read_private_keyblob(type)
|
253
|
+
case type
|
254
|
+
when /^ssh-rsa$/
|
255
|
+
key = OpenSSL::PKey::RSA.new
|
256
|
+
n = read_bignum
|
257
|
+
e = read_bignum
|
258
|
+
d = read_bignum
|
259
|
+
iqmp = read_bignum
|
260
|
+
p = read_bignum
|
261
|
+
q = read_bignum
|
262
|
+
_unkown1 = read_bignum
|
263
|
+
_unkown2 = read_bignum
|
264
|
+
dmp1 = d % (p - 1)
|
265
|
+
dmq1 = d % (q - 1)
|
266
|
+
if key.respond_to?(:set_key)
|
267
|
+
key.set_key(n, e, d)
|
268
|
+
else
|
269
|
+
key.e = e
|
270
|
+
key.n = n
|
271
|
+
key.d = d
|
272
|
+
end
|
273
|
+
if key.respond_to?(:set_factors)
|
274
|
+
key.set_factors(p, q)
|
275
|
+
else
|
276
|
+
key.p = p
|
277
|
+
key.q = q
|
278
|
+
end
|
279
|
+
if key.respond_to?(:set_crt_params)
|
280
|
+
key.set_crt_params(dmp1, dmq1, iqmp)
|
281
|
+
else
|
282
|
+
key.dmp1 = dmp1
|
283
|
+
key.dmq1 = dmq1
|
284
|
+
key.iqmp = iqmp
|
285
|
+
end
|
286
|
+
key
|
287
|
+
else
|
288
|
+
raise Exception, "Cannot decode private key of type #{type}"
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
252
292
|
# Read a keyblob of the given type from the buffer, and return it as
|
253
293
|
# a key. Only RSA, DSA, and ECDSA keys are supported.
|
254
294
|
def read_keyblob(type)
|
data/lib/net/ssh/config.rb
CHANGED
@@ -22,6 +22,7 @@ module Net
|
|
22
22
|
# * HostKeyAlias => :host_key_alias
|
23
23
|
# * HostName => :host_name
|
24
24
|
# * IdentityFile => maps to the :keys option
|
25
|
+
# * IdentityAgent => :identity_agent
|
25
26
|
# * IdentitiesOnly => :keys_only
|
26
27
|
# * Macs => maps to the :hmac option
|
27
28
|
# * PasswordAuthentication => maps to the :auth_methods option password
|
@@ -95,7 +96,7 @@ module Net
|
|
95
96
|
next if value.nil?
|
96
97
|
|
97
98
|
key.downcase!
|
98
|
-
value =
|
99
|
+
value = unquote(value)
|
99
100
|
|
100
101
|
value = case value.strip
|
101
102
|
when /^\d+$/ then value.to_i
|
@@ -194,6 +195,7 @@ module Net
|
|
194
195
|
connecttimeout: :timeout,
|
195
196
|
forwardagent: :forward_agent,
|
196
197
|
identitiesonly: :keys_only,
|
198
|
+
identityagent: :identity_agent,
|
197
199
|
globalknownhostsfile: :global_known_hosts_file,
|
198
200
|
hostkeyalias: :host_key_alias,
|
199
201
|
identityfile: :keys,
|
@@ -326,12 +328,17 @@ module Net
|
|
326
328
|
end
|
327
329
|
|
328
330
|
def eval_match_conditions(condition, host, settings)
|
329
|
-
|
331
|
+
# Not using `\s` for whitespace matching as canonical
|
332
|
+
# ssh_config parser implementation (OpenSSH) has specific character set.
|
333
|
+
# Ref: https://github.com/openssh/openssh-portable/blob/2581333d564d8697837729b3d07d45738eaf5a54/misc.c#L237-L239
|
334
|
+
conditions = condition.split(/[ \t\r\n]+|(?<!=)=(?!=)/).reject(&:empty?)
|
330
335
|
return true if conditions == ["all"]
|
331
336
|
|
332
337
|
conditions = conditions.each_slice(2)
|
333
|
-
|
338
|
+
condition_matches = []
|
334
339
|
conditions.each do |(kind,exprs)|
|
340
|
+
exprs = unquote(exprs)
|
341
|
+
|
335
342
|
case kind.downcase
|
336
343
|
when "all"
|
337
344
|
raise "all cannot be mixed with other conditions"
|
@@ -346,12 +353,17 @@ module Net
|
|
346
353
|
exprs.split(",").each do |expr|
|
347
354
|
condition_met = condition_met || host =~ pattern2regex(expr)
|
348
355
|
end
|
349
|
-
|
356
|
+
condition_matches << (true && negated ^ condition_met)
|
350
357
|
# else
|
351
358
|
# warn "net-ssh: Unsupported expr in Match block: #{kind}"
|
352
359
|
end
|
353
360
|
end
|
354
|
-
|
361
|
+
|
362
|
+
!condition_matches.empty? && condition_matches.all?
|
363
|
+
end
|
364
|
+
|
365
|
+
def unquote(string)
|
366
|
+
string =~ /^"(.*)"$/ ? Regexp.last_match(1) : string
|
355
367
|
end
|
356
368
|
end
|
357
369
|
end
|
data/lib/net/ssh/key_factory.rb
CHANGED
@@ -111,7 +111,7 @@ module Net
|
|
111
111
|
def classify_key(data, filename)
|
112
112
|
if data.match(/-----BEGIN OPENSSH PRIVATE KEY-----/)
|
113
113
|
Net::SSH::Authentication::ED25519Loader.raiseUnlessLoaded("OpenSSH keys only supported if ED25519 is available")
|
114
|
-
return ->(key_data, passphrase) { Net::SSH::Authentication::ED25519::
|
114
|
+
return ->(key_data, passphrase) { Net::SSH::Authentication::ED25519::OpenSSHPrivateKeyLoader.read(key_data, passphrase) }, [ArgumentError]
|
115
115
|
elsif OpenSSL::PKey.respond_to?(:read)
|
116
116
|
return ->(key_data, passphrase) { OpenSSL::PKey.read(key_data, passphrase) }, [ArgumentError, OpenSSL::PKey::PKeyError]
|
117
117
|
elsif data.match(/-----BEGIN DSA PRIVATE KEY-----/)
|
data/lib/net/ssh/test.rb
CHANGED
@@ -3,7 +3,7 @@ require 'net/ssh/connection/session'
|
|
3
3
|
require 'net/ssh/test/kex'
|
4
4
|
require 'net/ssh/test/socket'
|
5
5
|
|
6
|
-
module Net
|
6
|
+
module Net
|
7
7
|
module SSH
|
8
8
|
|
9
9
|
# This module may be used in unit tests, for when you want to test that your
|
@@ -54,30 +54,30 @@ module Net
|
|
54
54
|
Net::SSH::Test::Extensions::IO.with_test_extension { yield socket.script if block_given? }
|
55
55
|
return socket.script
|
56
56
|
end
|
57
|
-
|
57
|
+
|
58
58
|
# Returns the test socket instance to use for these tests (see
|
59
59
|
# Net::SSH::Test::Socket).
|
60
60
|
def socket(options={})
|
61
61
|
@socket ||= Net::SSH::Test::Socket.new
|
62
62
|
end
|
63
|
-
|
63
|
+
|
64
64
|
# Returns the connection session (Net::SSH::Connection::Session) for use
|
65
65
|
# in these tests. It is a fully functional SSH session, operating over
|
66
66
|
# a mock socket (#socket).
|
67
67
|
def connection(options={})
|
68
68
|
@connection ||= Net::SSH::Connection::Session.new(transport(options), options)
|
69
69
|
end
|
70
|
-
|
70
|
+
|
71
71
|
# Returns the transport session (Net::SSH::Transport::Session) for use
|
72
72
|
# in these tests. It is a fully functional SSH transport session, operating
|
73
73
|
# over a mock socket (#socket).
|
74
74
|
def transport(options={})
|
75
75
|
@transport ||= Net::SSH::Transport::Session.new(
|
76
76
|
options[:host] || "localhost",
|
77
|
-
options.merge(kex: "test", host_key: "ssh-rsa", verify_host_key:
|
77
|
+
options.merge(kex: "test", host_key: "ssh-rsa", verify_host_key: :never, proxy: socket(options))
|
78
78
|
)
|
79
79
|
end
|
80
|
-
|
80
|
+
|
81
81
|
# First asserts that a story has been described (see #story). Then yields,
|
82
82
|
# and then asserts that all items described in the script have been
|
83
83
|
# processed. Typically, this is called immediately after a story has
|
@@ -8,8 +8,8 @@ require 'net/ssh/transport/kex'
|
|
8
8
|
require 'net/ssh/transport/server_version'
|
9
9
|
require 'net/ssh/authentication/ed25519_loader'
|
10
10
|
|
11
|
-
module Net
|
12
|
-
module SSH
|
11
|
+
module Net
|
12
|
+
module SSH
|
13
13
|
module Transport
|
14
14
|
|
15
15
|
# Implements the higher-level logic behind an SSH key-exchange. It handles
|
@@ -22,92 +22,109 @@ module Net
|
|
22
22
|
class Algorithms
|
23
23
|
include Loggable
|
24
24
|
include Constants
|
25
|
-
|
25
|
+
|
26
26
|
# Define the default algorithms, in order of preference, supported by
|
27
27
|
# Net::SSH.
|
28
28
|
ALGORITHMS = {
|
29
|
-
host_key: %w[ssh-rsa
|
30
|
-
ssh-rsa-cert-
|
31
|
-
ssh-rsa-
|
32
|
-
kex: %w[diffie-hellman-group-exchange-
|
33
|
-
diffie-hellman-
|
29
|
+
host_key: %w[ssh-rsa-cert-v01@openssh.com
|
30
|
+
ssh-rsa-cert-v00@openssh.com
|
31
|
+
ssh-rsa ssh-dss],
|
32
|
+
kex: %w[diffie-hellman-group-exchange-sha256
|
33
|
+
diffie-hellman-group-exchange-sha1
|
34
34
|
diffie-hellman-group14-sha1
|
35
|
-
diffie-hellman-
|
36
|
-
encryption: %w[
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
cast128-ctr
|
41
|
-
|
42
|
-
|
35
|
+
diffie-hellman-group1-sha1],
|
36
|
+
encryption: %w[aes256-ctr aes192-ctr aes128-ctr
|
37
|
+
aes256-cbc aes192-cbc aes128-cbc
|
38
|
+
rijndael-cbc@lysator.liu.se
|
39
|
+
blowfish-ctr blowfish-cbc
|
40
|
+
cast128-ctr cast128-cbc
|
41
|
+
3des-ctr 3des-cbc
|
42
|
+
idea-cbc arcfour256 arcfour128 arcfour
|
43
|
+
none],
|
44
|
+
|
45
|
+
hmac: %w[hmac-sha2-512 hmac-sha2-256
|
46
|
+
hmac-sha2-512-96 hmac-sha2-256-96
|
47
|
+
hmac-sha1 hmac-sha1-96
|
43
48
|
hmac-ripemd160 hmac-ripemd160@openssh.com
|
44
|
-
hmac-
|
45
|
-
|
46
|
-
|
49
|
+
hmac-md5 hmac-md5-96
|
50
|
+
none],
|
51
|
+
|
47
52
|
compression: %w[none zlib@openssh.com zlib],
|
48
53
|
language: %w[]
|
49
54
|
}
|
50
55
|
if defined?(OpenSSL::PKey::EC)
|
51
|
-
ALGORITHMS[:host_key]
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
56
|
+
ALGORITHMS[:host_key].unshift(
|
57
|
+
"ecdsa-sha2-nistp521-cert-v01@openssh.com",
|
58
|
+
"ecdsa-sha2-nistp384-cert-v01@openssh.com",
|
59
|
+
"ecdsa-sha2-nistp256-cert-v01@openssh.com",
|
60
|
+
"ecdsa-sha2-nistp521",
|
61
|
+
"ecdsa-sha2-nistp384",
|
62
|
+
"ecdsa-sha2-nistp256"
|
63
|
+
)
|
64
|
+
if Net::SSH::Authentication::ED25519Loader::LOADED
|
65
|
+
ALGORITHMS[:host_key].unshift(
|
66
|
+
"ssh-ed25519-cert-v01@openssh.com",
|
67
|
+
"ssh-ed25519"
|
68
|
+
)
|
69
|
+
end
|
70
|
+
ALGORITHMS[:kex].unshift(
|
71
|
+
"ecdh-sha2-nistp521",
|
72
|
+
"ecdh-sha2-nistp384",
|
73
|
+
"ecdh-sha2-nistp256"
|
74
|
+
)
|
58
75
|
end
|
59
|
-
|
76
|
+
|
60
77
|
# The underlying transport layer session that supports this object
|
61
78
|
attr_reader :session
|
62
|
-
|
79
|
+
|
63
80
|
# The hash of options used to initialize this object
|
64
81
|
attr_reader :options
|
65
|
-
|
82
|
+
|
66
83
|
# The kex algorithm to use settled on between the client and server.
|
67
84
|
attr_reader :kex
|
68
|
-
|
85
|
+
|
69
86
|
# The type of host key that will be used for this session.
|
70
87
|
attr_reader :host_key
|
71
|
-
|
88
|
+
|
72
89
|
# The type of the cipher to use to encrypt packets sent from the client to
|
73
90
|
# the server.
|
74
91
|
attr_reader :encryption_client
|
75
|
-
|
92
|
+
|
76
93
|
# The type of the cipher to use to decrypt packets arriving from the server.
|
77
94
|
attr_reader :encryption_server
|
78
|
-
|
95
|
+
|
79
96
|
# The type of HMAC to use to sign packets sent by the client.
|
80
97
|
attr_reader :hmac_client
|
81
|
-
|
98
|
+
|
82
99
|
# The type of HMAC to use to validate packets arriving from the server.
|
83
100
|
attr_reader :hmac_server
|
84
|
-
|
101
|
+
|
85
102
|
# The type of compression to use to compress packets being sent by the client.
|
86
103
|
attr_reader :compression_client
|
87
|
-
|
104
|
+
|
88
105
|
# The type of compression to use to decompress packets arriving from the server.
|
89
106
|
attr_reader :compression_server
|
90
|
-
|
107
|
+
|
91
108
|
# The language that will be used in messages sent by the client.
|
92
109
|
attr_reader :language_client
|
93
|
-
|
110
|
+
|
94
111
|
# The language that will be used in messages sent from the server.
|
95
112
|
attr_reader :language_server
|
96
|
-
|
113
|
+
|
97
114
|
# The hash of algorithms preferred by the client, which will be told to
|
98
115
|
# the server during algorithm negotiation.
|
99
116
|
attr_reader :algorithms
|
100
|
-
|
117
|
+
|
101
118
|
# The session-id for this session, as decided during the initial key exchange.
|
102
119
|
attr_reader :session_id
|
103
|
-
|
120
|
+
|
104
121
|
# Returns true if the given packet can be processed during a key-exchange.
|
105
122
|
def self.allowed_packet?(packet)
|
106
123
|
(1..4).include?(packet.type) ||
|
107
124
|
(6..19).include?(packet.type) ||
|
108
125
|
(21..49).include?(packet.type)
|
109
126
|
end
|
110
|
-
|
127
|
+
|
111
128
|
# Instantiates a new Algorithms object, and prepares the hash of preferred
|
112
129
|
# algorithms based on the options parameter and the ALGORITHMS constant.
|
113
130
|
def initialize(session, options={})
|
@@ -119,13 +136,13 @@ module Net
|
|
119
136
|
@client_packet = @server_packet = nil
|
120
137
|
prepare_preferred_algorithms!
|
121
138
|
end
|
122
|
-
|
139
|
+
|
123
140
|
# Start the algorithm negotation
|
124
141
|
def start
|
125
142
|
raise ArgumentError, "Cannot call start if it's negotiation started or done" if @pending || @initialized
|
126
143
|
send_kexinit
|
127
144
|
end
|
128
|
-
|
145
|
+
|
129
146
|
# Request a rekey operation. This will return immediately, and does not
|
130
147
|
# actually perform the rekey operation. It does cause the session to change
|
131
148
|
# state, however--until the key exchange finishes, no new packets will be
|
@@ -135,7 +152,7 @@ module Net
|
|
135
152
|
@initialized = false
|
136
153
|
send_kexinit
|
137
154
|
end
|
138
|
-
|
155
|
+
|
139
156
|
# Called by the transport layer when a KEXINIT packet is received, indicating
|
140
157
|
# that the server wants to exchange keys. This can be spontaneous, or it
|
141
158
|
# can be in response to a client-initiated rekey request (see #rekey!). Either
|
@@ -150,13 +167,13 @@ module Net
|
|
150
167
|
proceed!
|
151
168
|
end
|
152
169
|
end
|
153
|
-
|
170
|
+
|
154
171
|
# A convenience method for accessing the list of preferred types for a
|
155
172
|
# specific algorithm (see #algorithms).
|
156
173
|
def [](key)
|
157
174
|
algorithms[key]
|
158
175
|
end
|
159
|
-
|
176
|
+
|
160
177
|
# Returns +true+ if a key-exchange is pending. This will be true from the
|
161
178
|
# moment either the client or server requests the key exchange, until the
|
162
179
|
# exchange completes. While an exchange is pending, only a limited number
|
@@ -201,7 +218,7 @@ module Net
|
|
201
218
|
session.send_message(packet)
|
202
219
|
proceed! if @server_packet
|
203
220
|
end
|
204
|
-
|
221
|
+
|
205
222
|
# After both client and server have sent their KEXINIT packets, this
|
206
223
|
# will do the algorithm negotiation and key exchange. Once both finish,
|
207
224
|
# the object leaves the pending state and the method returns.
|
@@ -211,7 +228,7 @@ module Net
|
|
211
228
|
exchange_keys
|
212
229
|
@pending = false
|
213
230
|
end
|
214
|
-
|
231
|
+
|
215
232
|
# Prepares the list of preferred algorithms, based on the options hash
|
216
233
|
# that was given when the object was constructed, and the ALGORITHMS
|
217
234
|
# constant. Also, when determining the host_key type to use, the known
|
@@ -220,23 +237,23 @@ module Net
|
|
220
237
|
# communicating with this server.
|
221
238
|
def prepare_preferred_algorithms!
|
222
239
|
options[:compression] = %w[zlib@openssh.com zlib] if options[:compression] == true
|
223
|
-
|
240
|
+
|
224
241
|
ALGORITHMS.each do |algorithm, supported|
|
225
242
|
algorithms[algorithm] = compose_algorithm_list(supported, options[algorithm], options[:append_all_supported_algorithms])
|
226
243
|
end
|
227
|
-
|
244
|
+
|
228
245
|
# for convention, make sure our list has the same keys as the server
|
229
246
|
# list
|
230
|
-
|
247
|
+
|
231
248
|
algorithms[:encryption_client ] = algorithms[:encryption_server ] = algorithms[:encryption]
|
232
249
|
algorithms[:hmac_client ] = algorithms[:hmac_server ] = algorithms[:hmac]
|
233
250
|
algorithms[:compression_client] = algorithms[:compression_server] = algorithms[:compression]
|
234
251
|
algorithms[:language_client ] = algorithms[:language_server ] = algorithms[:language]
|
235
|
-
|
252
|
+
|
236
253
|
if !options.key?(:host_key)
|
237
254
|
# make sure the host keys are specified in preference order, where any
|
238
255
|
# existing known key for the host has preference.
|
239
|
-
|
256
|
+
|
240
257
|
existing_keys = session.host_keys
|
241
258
|
host_keys = existing_keys.map { |key| key.ssh_type }.uniq
|
242
259
|
algorithms[:host_key].each do |name|
|
@@ -245,14 +262,14 @@ module Net
|
|
245
262
|
algorithms[:host_key] = host_keys
|
246
263
|
end
|
247
264
|
end
|
248
|
-
|
265
|
+
|
249
266
|
# Composes the list of algorithms by taking supported algorithms and matching with supplied options.
|
250
267
|
def compose_algorithm_list(supported, option, append_all_supported_algorithms = false)
|
251
268
|
return supported.dup unless option
|
252
|
-
|
269
|
+
|
253
270
|
list = []
|
254
271
|
option = Array(option).compact.uniq
|
255
|
-
|
272
|
+
|
256
273
|
if option.first && option.first.start_with?('+')
|
257
274
|
list = supported.dup
|
258
275
|
list << option.first[1..-1]
|
@@ -260,30 +277,30 @@ module Net
|
|
260
277
|
list.uniq!
|
261
278
|
else
|
262
279
|
list = option
|
263
|
-
|
280
|
+
|
264
281
|
if append_all_supported_algorithms
|
265
282
|
supported.each { |name| list << name unless list.include?(name) }
|
266
283
|
end
|
267
284
|
end
|
268
|
-
|
285
|
+
|
269
286
|
unsupported = []
|
270
287
|
list.select! do |name|
|
271
288
|
is_supported = supported.include?(name)
|
272
289
|
unsupported << name unless is_supported
|
273
290
|
is_supported
|
274
291
|
end
|
275
|
-
|
292
|
+
|
276
293
|
lwarn { %(unsupported algorithm: `#{unsupported}') } unless unsupported.empty?
|
277
|
-
|
294
|
+
|
278
295
|
list
|
279
296
|
end
|
280
|
-
|
297
|
+
|
281
298
|
# Parses a KEXINIT packet from the server.
|
282
299
|
def parse_server_algorithm_packet(packet)
|
283
300
|
data = { raw: packet.content }
|
284
|
-
|
301
|
+
|
285
302
|
packet.read(16) # skip the cookie value
|
286
|
-
|
303
|
+
|
287
304
|
data[:kex] = packet.read_string.split(/,/)
|
288
305
|
data[:host_key] = packet.read_string.split(/,/)
|
289
306
|
data[:encryption_client] = packet.read_string.split(/,/)
|
@@ -294,15 +311,15 @@ module Net
|
|
294
311
|
data[:compression_server] = packet.read_string.split(/,/)
|
295
312
|
data[:language_client] = packet.read_string.split(/,/)
|
296
313
|
data[:language_server] = packet.read_string.split(/,/)
|
297
|
-
|
314
|
+
|
298
315
|
# TODO: if first_kex_packet_follows, we need to try to skip the
|
299
316
|
# actual kexinit stuff and try to guess what the server is doing...
|
300
317
|
# need to read more about this scenario.
|
301
318
|
# first_kex_packet_follows = packet.read_bool
|
302
|
-
|
319
|
+
|
303
320
|
return data
|
304
321
|
end
|
305
|
-
|
322
|
+
|
306
323
|
# Given the #algorithms map of preferred algorithm types, this constructs
|
307
324
|
# a KEXINIT packet to send to the server. It does not actually send it,
|
308
325
|
# it simply builds the packet and returns it.
|
@@ -313,14 +330,14 @@ module Net
|
|
313
330
|
hmac = algorithms[:hmac].join(",")
|
314
331
|
compression = algorithms[:compression].join(",")
|
315
332
|
language = algorithms[:language].join(",")
|
316
|
-
|
333
|
+
|
317
334
|
Net::SSH::Buffer.from(:byte, KEXINIT,
|
318
335
|
:long, [rand(0xFFFFFFFF), rand(0xFFFFFFFF), rand(0xFFFFFFFF), rand(0xFFFFFFFF)],
|
319
336
|
:mstring, [kex, host_key, encryption, encryption, hmac, hmac],
|
320
337
|
:mstring, [compression, compression, language, language],
|
321
338
|
:bool, false, :long, 0)
|
322
339
|
end
|
323
|
-
|
340
|
+
|
324
341
|
# Given the parsed server KEX packet, and the client's preferred algorithm
|
325
342
|
# lists in #algorithms, determine which preferred algorithms each has
|
326
343
|
# in common and set those as the selected algorithms. If, for any algorithm,
|
@@ -336,7 +353,7 @@ module Net
|
|
336
353
|
@compression_server = negotiate(:compression_server)
|
337
354
|
@language_client = negotiate(:language_client) rescue ""
|
338
355
|
@language_server = negotiate(:language_server) rescue ""
|
339
|
-
|
356
|
+
|
340
357
|
debug do
|
341
358
|
"negotiated:\n" +
|
342
359
|
%i[kex host_key encryption_server encryption_client hmac_client hmac_server compression_client compression_server language_client language_server].map do |key|
|
@@ -344,40 +361,40 @@ module Net
|
|
344
361
|
end.join("\n")
|
345
362
|
end
|
346
363
|
end
|
347
|
-
|
364
|
+
|
348
365
|
# Negotiates a single algorithm based on the preferences reported by the
|
349
366
|
# server and those set by the client. This is called by
|
350
367
|
# #negotiate_algorithms.
|
351
368
|
def negotiate(algorithm)
|
352
369
|
match = self[algorithm].find { |item| @server_data[algorithm].include?(item) }
|
353
|
-
|
370
|
+
|
354
371
|
raise Net::SSH::Exception, "could not settle on #{algorithm} algorithm" if match.nil?
|
355
|
-
|
372
|
+
|
356
373
|
return match
|
357
374
|
end
|
358
|
-
|
375
|
+
|
359
376
|
# Considers the sizes of the keys and block-sizes for the selected ciphers,
|
360
377
|
# and the lengths of the hmacs, and returns the largest as the byte requirement
|
361
378
|
# for the key-exchange algorithm.
|
362
379
|
def kex_byte_requirement
|
363
380
|
sizes = [8] # require at least 8 bytes
|
364
|
-
|
381
|
+
|
365
382
|
sizes.concat(CipherFactory.get_lengths(encryption_client))
|
366
383
|
sizes.concat(CipherFactory.get_lengths(encryption_server))
|
367
|
-
|
384
|
+
|
368
385
|
sizes << HMAC.key_length(hmac_client)
|
369
386
|
sizes << HMAC.key_length(hmac_server)
|
370
|
-
|
387
|
+
|
371
388
|
sizes.max
|
372
389
|
end
|
373
|
-
|
390
|
+
|
374
391
|
# Instantiates one of the Transport::Kex classes (based on the negotiated
|
375
392
|
# kex algorithm), and uses it to exchange keys. Then, the ciphers and
|
376
393
|
# HMACs are initialized and fed to the transport layer, to be used in
|
377
394
|
# further communication with the server.
|
378
395
|
def exchange_keys
|
379
396
|
debug { "exchanging keys" }
|
380
|
-
|
397
|
+
|
381
398
|
algorithm = Kex::MAP[kex].new(self, session,
|
382
399
|
client_version_string: Net::SSH::Transport::ServerVersion::PROTO_VERSION,
|
383
400
|
server_version_string: session.server_version.version,
|
@@ -387,46 +404,46 @@ module Net
|
|
387
404
|
minimum_dh_bits: options[:minimum_dh_bits],
|
388
405
|
logger: logger)
|
389
406
|
result = algorithm.exchange_keys
|
390
|
-
|
407
|
+
|
391
408
|
secret = result[:shared_secret].to_ssh
|
392
409
|
hash = result[:session_id]
|
393
410
|
digester = result[:hashing_algorithm]
|
394
|
-
|
411
|
+
|
395
412
|
@session_id ||= hash
|
396
|
-
|
413
|
+
|
397
414
|
key = Proc.new { |salt| digester.digest(secret + hash + salt + @session_id) }
|
398
|
-
|
415
|
+
|
399
416
|
iv_client = key["A"]
|
400
417
|
iv_server = key["B"]
|
401
418
|
key_client = key["C"]
|
402
419
|
key_server = key["D"]
|
403
420
|
mac_key_client = key["E"]
|
404
421
|
mac_key_server = key["F"]
|
405
|
-
|
422
|
+
|
406
423
|
parameters = { shared: secret, hash: hash, digester: digester }
|
407
|
-
|
424
|
+
|
408
425
|
cipher_client = CipherFactory.get(encryption_client, parameters.merge(iv: iv_client, key: key_client, encrypt: true))
|
409
426
|
cipher_server = CipherFactory.get(encryption_server, parameters.merge(iv: iv_server, key: key_server, decrypt: true))
|
410
|
-
|
427
|
+
|
411
428
|
mac_client = HMAC.get(hmac_client, mac_key_client, parameters)
|
412
429
|
mac_server = HMAC.get(hmac_server, mac_key_server, parameters)
|
413
|
-
|
430
|
+
|
414
431
|
session.configure_client cipher: cipher_client, hmac: mac_client,
|
415
432
|
compression: normalize_compression_name(compression_client),
|
416
433
|
compression_level: options[:compression_level],
|
417
434
|
rekey_limit: options[:rekey_limit],
|
418
435
|
max_packets: options[:rekey_packet_limit],
|
419
436
|
max_blocks: options[:rekey_blocks_limit]
|
420
|
-
|
437
|
+
|
421
438
|
session.configure_server cipher: cipher_server, hmac: mac_server,
|
422
439
|
compression: normalize_compression_name(compression_server),
|
423
440
|
rekey_limit: options[:rekey_limit],
|
424
441
|
max_packets: options[:rekey_packet_limit],
|
425
442
|
max_blocks: options[:rekey_blocks_limit]
|
426
|
-
|
443
|
+
|
427
444
|
@initialized = true
|
428
445
|
end
|
429
|
-
|
446
|
+
|
430
447
|
# Given the SSH name for some compression algorithm, return a normalized
|
431
448
|
# name as a symbol.
|
432
449
|
def normalize_compression_name(name)
|
@@ -206,7 +206,7 @@ module Net
|
|
206
206
|
|
207
207
|
hash = @digester.digest(response.to_s)
|
208
208
|
|
209
|
-
raise Net::SSH::Exception, "could not verify server signature" unless result[:server_key].ssh_do_verify(result[:server_sig], hash)
|
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
210
|
|
211
211
|
return hash
|
212
212
|
end
|
@@ -225,6 +225,22 @@ module OpenSSL
|
|
225
225
|
|
226
226
|
return Net::SSH::Buffer.from(:bignum, sig_r, :bignum, sig_s).to_s
|
227
227
|
end
|
228
|
+
|
229
|
+
class Point
|
230
|
+
# Returns the description of this key type used by the
|
231
|
+
# SSH2 protocol, like "ecdsa-sha2-nistp256"
|
232
|
+
def ssh_type
|
233
|
+
"ecdsa-sha2-#{CurveNameAliasInv[self.group.curve_name]}"
|
234
|
+
end
|
235
|
+
|
236
|
+
# Converts the key to a blob, according to the SSH2 protocol.
|
237
|
+
def to_blob
|
238
|
+
@blob ||= Net::SSH::Buffer.from(:string, ssh_type,
|
239
|
+
:string, CurveNameAliasInv[self.group.curve_name],
|
240
|
+
:mstring, self.to_bn.to_s(2)).to_s
|
241
|
+
@blob
|
242
|
+
end
|
243
|
+
end
|
228
244
|
end
|
229
245
|
else
|
230
246
|
class OpenSSL::PKey::ECError < RuntimeError
|
@@ -81,8 +81,8 @@ module Net
|
|
81
81
|
# default), then this will return immediately, whether a packet is
|
82
82
|
# available or not, and will return nil if there is no packet ready to be
|
83
83
|
# returned. If the mode parameter is :block, then this method will block
|
84
|
-
# until a packet is available.
|
85
|
-
def next_packet(mode=:nonblock)
|
84
|
+
# until a packet is available or timeout seconds have passed.
|
85
|
+
def next_packet(mode=:nonblock, timeout=nil)
|
86
86
|
case mode
|
87
87
|
when :nonblock then
|
88
88
|
packet = poll_next_packet
|
@@ -105,11 +105,8 @@ module Net
|
|
105
105
|
packet = poll_next_packet
|
106
106
|
return packet if packet
|
107
107
|
|
108
|
-
|
109
|
-
|
110
|
-
break if result.first.any?
|
111
|
-
end
|
112
|
-
|
108
|
+
result = IO.select([self], nil, nil, timeout)
|
109
|
+
raise Net::SSH::ConnectionTimeout, "timeout waiting for next packet" unless result
|
113
110
|
raise Net::SSH::Disconnect, "connection closed by remote host" if fill <= 0
|
114
111
|
end
|
115
112
|
|
@@ -190,7 +190,7 @@ module Net
|
|
190
190
|
loop do
|
191
191
|
return @queue.shift if consume_queue && @queue.any? && algorithms.allow?(@queue.first)
|
192
192
|
|
193
|
-
packet = socket.next_packet(mode)
|
193
|
+
packet = socket.next_packet(mode, options[:timeout])
|
194
194
|
return nil if packet.nil?
|
195
195
|
|
196
196
|
case packet.type
|
@@ -274,6 +274,23 @@ module Net
|
|
274
274
|
|
275
275
|
private
|
276
276
|
|
277
|
+
# Compatibility verifier which allows users to keep using
|
278
|
+
# custom verifier code without adding new :verify_signature
|
279
|
+
# method.
|
280
|
+
class CompatibleVerifier
|
281
|
+
def initialize(verifier)
|
282
|
+
@verifier
|
283
|
+
end
|
284
|
+
|
285
|
+
def verify(arguments)
|
286
|
+
@verifier.verify(arguments)
|
287
|
+
end
|
288
|
+
|
289
|
+
def verify_signature(&block)
|
290
|
+
yield
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
277
294
|
# Instantiates a new host-key verification class, based on the value of
|
278
295
|
# the parameter.
|
279
296
|
#
|
@@ -285,8 +302,8 @@ module Net
|
|
285
302
|
# - :accept_new (insecure)
|
286
303
|
# - :always (secure)
|
287
304
|
#
|
288
|
-
# If the argument happens to respond to :verify
|
289
|
-
# directly. Otherwise, an exception is raised.
|
305
|
+
# If the argument happens to respond to :verify and :verify_signature,
|
306
|
+
# it is returned directly. Otherwise, an exception is raised.
|
290
307
|
#
|
291
308
|
# Values false, true, and :very were deprecated in
|
292
309
|
# [#595](https://github.com/net-ssh/net-ssh/pull/595)
|
@@ -314,7 +331,12 @@ module Net
|
|
314
331
|
Net::SSH::Verifiers::Always.new
|
315
332
|
else
|
316
333
|
if verifier.respond_to?(:verify)
|
317
|
-
verifier
|
334
|
+
if verifier.respond_to?(:verify_signature)
|
335
|
+
verifier
|
336
|
+
else
|
337
|
+
Kernel.warn("Warning: verifier without :verify_signature is deprecated")
|
338
|
+
CompatibleVerifier.new(verifier)
|
339
|
+
end
|
318
340
|
else
|
319
341
|
raise(
|
320
342
|
ArgumentError,
|
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 = 1
|
53
53
|
|
54
54
|
# The tiny component of this version of the Net::SSH library
|
55
|
-
TINY =
|
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.0.
|
4
|
+
version: 5.1.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-
|
35
|
+
date: 2018-12-12 00:00:00.000000000 Z
|
36
36
|
dependencies:
|
37
37
|
- !ruby/object:Gem::Dependency
|
38
38
|
name: bcrypt_pbkdf
|
@@ -262,12 +262,12 @@ 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
|
-
rubygems_version: 2.
|
270
|
+
rubygems_version: 2.6.8
|
271
271
|
signing_key:
|
272
272
|
specification_version: 4
|
273
273
|
summary: 'Net::SSH: a pure-Ruby implementation of the SSH2 client protocol.'
|
metadata.gz.sig
CHANGED
Binary file
|