net-ssh 6.3.0.beta1 → 7.0.0.beta1
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 +0 -0
- data/.dockerignore +6 -0
- data/.github/config/rubocop_linter_action.yml +4 -0
- data/.github/workflows/ci-with-docker.yml +44 -0
- data/.github/workflows/ci.yml +4 -10
- data/.github/workflows/rubocop.yml +13 -0
- data/.rubocop.yml +2 -1
- data/.rubocop_todo.yml +244 -237
- data/Dockerfile +27 -0
- data/Dockerfile.openssl3 +17 -0
- data/README.md +7 -1
- data/Rakefile +4 -0
- data/docker-compose.yml +23 -0
- data/lib/net/ssh/authentication/agent.rb +13 -13
- data/lib/net/ssh/authentication/certificate.rb +4 -4
- data/lib/net/ssh/authentication/ed25519.rb +5 -5
- data/lib/net/ssh/authentication/key_manager.rb +18 -5
- data/lib/net/ssh/authentication/methods/abstract.rb +12 -2
- data/lib/net/ssh/authentication/methods/hostbased.rb +3 -3
- data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +1 -1
- data/lib/net/ssh/authentication/methods/none.rb +1 -1
- data/lib/net/ssh/authentication/methods/password.rb +1 -1
- data/lib/net/ssh/authentication/methods/publickey.rb +56 -14
- data/lib/net/ssh/authentication/pageant.rb +8 -8
- data/lib/net/ssh/authentication/pub_key_fingerprint.rb +2 -2
- data/lib/net/ssh/authentication/session.rb +5 -3
- data/lib/net/ssh/buffer.rb +41 -26
- data/lib/net/ssh/buffered_io.rb +6 -6
- data/lib/net/ssh/config.rb +4 -4
- data/lib/net/ssh/connection/channel.rb +13 -13
- data/lib/net/ssh/connection/event_loop.rb +8 -8
- data/lib/net/ssh/connection/session.rb +13 -13
- data/lib/net/ssh/errors.rb +2 -2
- data/lib/net/ssh/key_factory.rb +7 -7
- data/lib/net/ssh/known_hosts.rb +5 -4
- data/lib/net/ssh/prompt.rb +1 -1
- data/lib/net/ssh/proxy/http.rb +1 -1
- data/lib/net/ssh/proxy/https.rb +2 -2
- data/lib/net/ssh/proxy/socks4.rb +1 -1
- data/lib/net/ssh/proxy/socks5.rb +1 -1
- data/lib/net/ssh/service/forward.rb +4 -4
- data/lib/net/ssh/test/channel.rb +3 -3
- data/lib/net/ssh/test/extensions.rb +6 -6
- data/lib/net/ssh/test/packet.rb +1 -1
- data/lib/net/ssh/test/script.rb +3 -3
- data/lib/net/ssh/test/socket.rb +1 -1
- data/lib/net/ssh/test.rb +3 -3
- data/lib/net/ssh/transport/algorithms.rb +12 -12
- data/lib/net/ssh/transport/cipher_factory.rb +15 -15
- data/lib/net/ssh/transport/ctr.rb +3 -3
- data/lib/net/ssh/transport/hmac/abstract.rb +4 -4
- data/lib/net/ssh/transport/hmac.rb +12 -12
- data/lib/net/ssh/transport/identity_cipher.rb +1 -1
- data/lib/net/ssh/transport/kex/abstract.rb +3 -3
- data/lib/net/ssh/transport/kex/abstract5656.rb +1 -1
- data/lib/net/ssh/transport/kex/curve25519_sha256.rb +1 -1
- data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +21 -21
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +1 -1
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +2 -2
- data/lib/net/ssh/transport/kex.rb +7 -7
- data/lib/net/ssh/transport/key_expander.rb +1 -1
- data/lib/net/ssh/transport/openssl.rb +32 -11
- data/lib/net/ssh/transport/packet_stream.rb +1 -1
- data/lib/net/ssh/transport/session.rb +6 -6
- data/lib/net/ssh/transport/state.rb +1 -1
- data/lib/net/ssh/version.rb +2 -2
- data/lib/net/ssh.rb +3 -3
- data/net-ssh.gemspec +2 -2
- data.tar.gz.sig +0 -0
- metadata +13 -7
- metadata.gz.sig +1 -2
- data/.travis.yml +0 -51
data/Dockerfile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
ARG RUBY_VERSION=3.1
|
2
|
+
FROM ruby:${RUBY_VERSION}
|
3
|
+
|
4
|
+
RUN apt update && apt install -y openssh-server sudo netcat \
|
5
|
+
&& useradd --create-home --shell '/bin/bash' --comment 'NetSSH' 'net_ssh_1' \
|
6
|
+
&& useradd --create-home --shell '/bin/bash' --comment 'NetSSH' 'net_ssh_2' \
|
7
|
+
&& echo net_ssh_1:foopwd | chpasswd \
|
8
|
+
&& echo net_ssh_2:foo2pwd | chpasswd \
|
9
|
+
&& mkdir -p /home/net_ssh_1/.ssh \
|
10
|
+
&& mkdir -p /home/net_ssh_2/.ssh \
|
11
|
+
&& echo "net_ssh_1 ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers \
|
12
|
+
&& echo "net_ssh_2 ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers \
|
13
|
+
&& ssh-keygen -f /etc/ssh/users_ca -N ''
|
14
|
+
|
15
|
+
ENV INSTALL_PATH="/netssh"
|
16
|
+
|
17
|
+
WORKDIR $INSTALL_PATH
|
18
|
+
|
19
|
+
COPY Gemfile net-ssh.gemspec $INSTALL_PATH/
|
20
|
+
|
21
|
+
COPY lib/net/ssh/version.rb $INSTALL_PATH/lib/net/ssh/version.rb
|
22
|
+
|
23
|
+
RUN gem install bundler && bundle install
|
24
|
+
|
25
|
+
COPY . $INSTALL_PATH/
|
26
|
+
|
27
|
+
CMD service ssh start && rake test && NET_SSH_NO_ED25519=1 rake test
|
data/Dockerfile.openssl3
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
FROM ubuntu:22.04
|
2
|
+
|
3
|
+
ENV INSTALL_PATH="/netssh"
|
4
|
+
|
5
|
+
RUN apt update && apt install -y openssl ruby ruby-dev git build-essential
|
6
|
+
|
7
|
+
WORKDIR $INSTALL_PATH
|
8
|
+
|
9
|
+
COPY Gemfile net-ssh.gemspec $INSTALL_PATH/
|
10
|
+
|
11
|
+
COPY lib/net/ssh/version.rb $INSTALL_PATH/lib/net/ssh/version.rb
|
12
|
+
|
13
|
+
RUN ls -l && gem install bundler && bundle install
|
14
|
+
|
15
|
+
COPY . $INSTALL_PATH/
|
16
|
+
|
17
|
+
CMD openssl version && ruby -ropenssl -e 'puts OpenSSL::OPENSSL_VERSION' && rake test
|
data/README.md
CHANGED
@@ -211,13 +211,19 @@ Run the test suite from the net-ssh directory with the following command:
|
|
211
211
|
bundle exec rake test
|
212
212
|
```
|
213
213
|
|
214
|
+
NOTE : you can run test on all ruby versions with docker :
|
215
|
+
|
216
|
+
```
|
217
|
+
docker-compose up --build
|
218
|
+
```
|
219
|
+
|
214
220
|
Run a single test file like this:
|
215
221
|
|
216
222
|
```sh
|
217
223
|
ruby -Ilib -Itest test/transport/test_server_version.rb
|
218
224
|
```
|
219
225
|
|
220
|
-
To run integration tests see test/integration/README.
|
226
|
+
To run integration tests see [here](test/integration/README.md)
|
221
227
|
|
222
228
|
### BUILDING GEM
|
223
229
|
|
data/Rakefile
CHANGED
@@ -95,6 +95,10 @@ Rake::TestTask.new do |t|
|
|
95
95
|
t.test_files = test_files
|
96
96
|
end
|
97
97
|
|
98
|
+
# We need to enable the OpenSSL 3.0 legacy providers for our test suite
|
99
|
+
require 'openssl'
|
100
|
+
ENV['OPENSSL_CONF'] = 'test/openssl3.conf' if OpenSSL::OPENSSL_LIBRARY_VERSION.start_with? "OpenSSL 3"
|
101
|
+
|
98
102
|
desc "Run tests of Net::SSH:Test"
|
99
103
|
Rake::TestTask.new do |t|
|
100
104
|
t.name = "test_test"
|
data/docker-compose.yml
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
version: '3'
|
2
|
+
|
3
|
+
services:
|
4
|
+
ruby-3.1:
|
5
|
+
build:
|
6
|
+
context: .
|
7
|
+
args:
|
8
|
+
RUBY_VERSION: 3.1
|
9
|
+
ruby-3.0:
|
10
|
+
build:
|
11
|
+
context: .
|
12
|
+
args:
|
13
|
+
RUBY_VERSION: 3.0
|
14
|
+
ruby-2.7:
|
15
|
+
build:
|
16
|
+
context: .
|
17
|
+
args:
|
18
|
+
RUBY_VERSION: 2.7
|
19
|
+
ruby-2.6:
|
20
|
+
build:
|
21
|
+
context: .
|
22
|
+
args:
|
23
|
+
RUBY_VERSION: 2.6
|
@@ -65,7 +65,7 @@ module Net
|
|
65
65
|
|
66
66
|
# Instantiates a new agent object, connects to a running SSH agent,
|
67
67
|
# negotiates the agent protocol version, and returns the agent object.
|
68
|
-
def self.connect(logger=nil, agent_socket_factory = nil, identity_agent = nil)
|
68
|
+
def self.connect(logger = nil, agent_socket_factory = nil, identity_agent = nil)
|
69
69
|
agent = new(logger)
|
70
70
|
agent.connect!(agent_socket_factory, identity_agent)
|
71
71
|
agent.negotiate!
|
@@ -74,7 +74,7 @@ module Net
|
|
74
74
|
|
75
75
|
# Creates a new Agent object, using the optional logger instance to
|
76
76
|
# report status.
|
77
|
-
def initialize(logger=nil)
|
77
|
+
def initialize(logger = nil)
|
78
78
|
self.logger = logger
|
79
79
|
end
|
80
80
|
|
@@ -88,9 +88,9 @@ module Net
|
|
88
88
|
if agent_socket_factory
|
89
89
|
agent_socket_factory.call
|
90
90
|
elsif identity_agent
|
91
|
-
unix_socket_class.open(identity_agent)
|
91
|
+
unix_socket_class.open(File.expand_path(identity_agent))
|
92
92
|
elsif ENV['SSH_AUTH_SOCK'] && unix_socket_class
|
93
|
-
unix_socket_class.open(ENV['SSH_AUTH_SOCK'])
|
93
|
+
unix_socket_class.open(File.expand_path(ENV['SSH_AUTH_SOCK']))
|
94
94
|
elsif Gem.win_platform? && RUBY_ENGINE != "jruby"
|
95
95
|
Pageant::Socket.open
|
96
96
|
else
|
@@ -177,7 +177,7 @@ module Net
|
|
177
177
|
|
178
178
|
req_type = constraints.empty? ? SSH2_AGENT_ADD_IDENTITY : SSH2_AGENT_ADD_ID_CONSTRAINED
|
179
179
|
type, = send_and_wait(req_type, :string, priv_key.ssh_type, :raw, blob_for_add(priv_key),
|
180
|
-
|
180
|
+
:string, comment, :raw, constraints)
|
181
181
|
raise AgentError, "could not add identity to agent" if type != SSH_AGENT_SUCCESS
|
182
182
|
end
|
183
183
|
|
@@ -251,31 +251,31 @@ module Net
|
|
251
251
|
case priv_key.ssh_type
|
252
252
|
when /^ssh-dss$/
|
253
253
|
Net::SSH::Buffer.from(:bignum, priv_key.p, :bignum, priv_key.q, :bignum, priv_key.g,
|
254
|
-
|
254
|
+
:bignum, priv_key.pub_key, :bignum, priv_key.priv_key).to_s
|
255
255
|
when /^ssh-dss-cert-v01@openssh\.com$/
|
256
256
|
Net::SSH::Buffer.from(:string, priv_key.to_blob, :bignum, priv_key.key.priv_key).to_s
|
257
257
|
when /^ecdsa\-sha2\-(\w*)$/
|
258
258
|
curve_name = OpenSSL::PKey::EC::CurveNameAliasInv[priv_key.group.curve_name]
|
259
259
|
Net::SSH::Buffer.from(:string, curve_name, :mstring, priv_key.public_key.to_bn.to_s(2),
|
260
|
-
|
260
|
+
:bignum, priv_key.private_key).to_s
|
261
261
|
when /^ecdsa\-sha2\-(\w*)-cert-v01@openssh\.com$/
|
262
262
|
Net::SSH::Buffer.from(:string, priv_key.to_blob, :bignum, priv_key.key.private_key).to_s
|
263
263
|
when /^ssh-ed25519$/
|
264
264
|
Net::SSH::Buffer.from(:string, priv_key.public_key.verify_key.to_bytes,
|
265
|
-
|
265
|
+
:string, priv_key.sign_key.keypair).to_s
|
266
266
|
when /^ssh-ed25519-cert-v01@openssh\.com$/
|
267
267
|
# Unlike the other certificate types, the public key is included after the certifiate.
|
268
268
|
Net::SSH::Buffer.from(:string, priv_key.to_blob,
|
269
|
-
|
270
|
-
|
269
|
+
:string, priv_key.key.public_key.verify_key.to_bytes,
|
270
|
+
:string, priv_key.key.sign_key.keypair).to_s
|
271
271
|
when /^ssh-rsa$/
|
272
272
|
# `n` and `e` are reversed compared to the ordering in `OpenSSL::PKey::RSA#to_blob`.
|
273
273
|
Net::SSH::Buffer.from(:bignum, priv_key.n, :bignum, priv_key.e, :bignum, priv_key.d,
|
274
|
-
|
274
|
+
:bignum, priv_key.iqmp, :bignum, priv_key.p, :bignum, priv_key.q).to_s
|
275
275
|
when /^ssh-rsa-cert-v01@openssh\.com$/
|
276
276
|
Net::SSH::Buffer.from(:string, priv_key.to_blob, :bignum, priv_key.key.d,
|
277
|
-
|
278
|
-
|
277
|
+
:bignum, priv_key.key.iqmp, :bignum, priv_key.key.p,
|
278
|
+
:bignum, priv_key.key.q).to_s
|
279
279
|
end
|
280
280
|
end
|
281
281
|
end
|
@@ -66,8 +66,8 @@ module Net
|
|
66
66
|
).to_s
|
67
67
|
end
|
68
68
|
|
69
|
-
def ssh_do_sign(data)
|
70
|
-
key.ssh_do_sign(data)
|
69
|
+
def ssh_do_sign(data, sig_alg = nil)
|
70
|
+
key.ssh_do_sign(data, sig_alg)
|
71
71
|
end
|
72
72
|
|
73
73
|
def ssh_do_verify(sig, data, options = {})
|
@@ -83,7 +83,7 @@ module Net
|
|
83
83
|
end
|
84
84
|
|
85
85
|
# Signs the certificate with key.
|
86
|
-
def sign!(key, sign_nonce=nil)
|
86
|
+
def sign!(key, sign_nonce = nil)
|
87
87
|
# ssh-keygen uses 32 bytes of nonce.
|
88
88
|
self.nonce = sign_nonce || SecureRandom.random_bytes(32)
|
89
89
|
self.signature_key = key
|
@@ -94,7 +94,7 @@ module Net
|
|
94
94
|
self
|
95
95
|
end
|
96
96
|
|
97
|
-
def sign(key, sign_nonce=nil)
|
97
|
+
def sign(key, sign_nonce = nil)
|
98
98
|
cert = clone
|
99
99
|
cert.sign!(key, sign_nonce)
|
100
100
|
end
|
@@ -14,7 +14,7 @@ module Net
|
|
14
14
|
module Authentication
|
15
15
|
module ED25519
|
16
16
|
class SigningKeyFromFile < SimpleDelegator
|
17
|
-
def initialize(pk,sk)
|
17
|
+
def initialize(pk, sk)
|
18
18
|
key = ::Ed25519::SigningKey.from_keypair(sk)
|
19
19
|
raise ArgumentError, "pk does not match sk" unless pk == key.verify_key.to_bytes
|
20
20
|
|
@@ -116,7 +116,7 @@ module Net
|
|
116
116
|
end
|
117
117
|
|
118
118
|
def to_blob
|
119
|
-
Net::SSH::Buffer.from(:mstring,"ssh-ed25519".dup
|
119
|
+
Net::SSH::Buffer.from(:mstring, "ssh-ed25519".dup, :string, @verify_key.to_bytes).to_s
|
120
120
|
end
|
121
121
|
|
122
122
|
def ssh_type
|
@@ -128,7 +128,7 @@ module Net
|
|
128
128
|
end
|
129
129
|
|
130
130
|
def ssh_do_verify(sig, data, options = {})
|
131
|
-
@verify_key.verify(sig,data)
|
131
|
+
@verify_key.verify(sig, data)
|
132
132
|
end
|
133
133
|
|
134
134
|
def to_pem
|
@@ -152,7 +152,7 @@ module Net
|
|
152
152
|
_comment = buffer.read_string
|
153
153
|
|
154
154
|
@pk = pk
|
155
|
-
@sign_key = SigningKeyFromFile.new(pk,sk)
|
155
|
+
@sign_key = SigningKeyFromFile.new(pk, sk)
|
156
156
|
end
|
157
157
|
|
158
158
|
def to_blob
|
@@ -171,7 +171,7 @@ module Net
|
|
171
171
|
PubKey.new(@pk)
|
172
172
|
end
|
173
173
|
|
174
|
-
def ssh_do_sign(data)
|
174
|
+
def ssh_do_sign(data, sig_alg = nil)
|
175
175
|
@sign_key.sign(data)
|
176
176
|
end
|
177
177
|
|
@@ -41,7 +41,7 @@ module Net
|
|
41
41
|
# Create a new KeyManager. By default, the manager will
|
42
42
|
# use the ssh-agent if it is running and the `:use_agent` option
|
43
43
|
# is not false.
|
44
|
-
def initialize(logger, options={})
|
44
|
+
def initialize(logger, options = {})
|
45
45
|
self.logger = logger
|
46
46
|
@key_files = []
|
47
47
|
@key_data = []
|
@@ -158,7 +158,7 @@ module Net
|
|
158
158
|
# Regardless of the identity's origin or who does the signing, this
|
159
159
|
# will always return the signature in an SSH2-specified "signature
|
160
160
|
# blob" format.
|
161
|
-
def sign(identity, data)
|
161
|
+
def sign(identity, data, sig_alg = nil)
|
162
162
|
info = known_identities[identity] or raise KeyManagerError, "the given identity is unknown to the key manager"
|
163
163
|
|
164
164
|
if info[:key].nil? && info[:from] == :file
|
@@ -170,14 +170,27 @@ module Net
|
|
170
170
|
end
|
171
171
|
|
172
172
|
if info[:key]
|
173
|
-
|
174
|
-
|
173
|
+
if sig_alg.nil?
|
174
|
+
signed = info[:key].ssh_do_sign(data.to_s)
|
175
|
+
sig_alg = identity.ssh_signature_type
|
176
|
+
else
|
177
|
+
signed = info[:key].ssh_do_sign(data.to_s, sig_alg)
|
178
|
+
end
|
179
|
+
return Net::SSH::Buffer.from(:string, sig_alg,
|
180
|
+
:mstring, signed).to_s
|
175
181
|
end
|
176
182
|
|
177
183
|
if info[:from] == :agent
|
178
184
|
raise KeyManagerError, "the agent is no longer available" unless agent
|
179
185
|
|
180
|
-
|
186
|
+
case sig_alg
|
187
|
+
when "rsa-sha2-512"
|
188
|
+
return agent.sign(info[:identity], data.to_s, Net::SSH::Authentication::Agent::SSH_AGENT_RSA_SHA2_512)
|
189
|
+
when "rsa-sha2-256"
|
190
|
+
return agent.sign(info[:identity], data.to_s, Net::SSH::Authentication::Agent::SSH_AGENT_RSA_SHA2_256)
|
191
|
+
else
|
192
|
+
return agent.sign(info[:identity], data.to_s)
|
193
|
+
end
|
181
194
|
end
|
182
195
|
|
183
196
|
raise KeyManagerError, "[BUG] can't determine identity origin (#{info.inspect})"
|
@@ -20,12 +20,22 @@ module Net
|
|
20
20
|
# this.
|
21
21
|
attr_reader :key_manager
|
22
22
|
|
23
|
+
# So far only affects algorithms used for rsa keys, but can be
|
24
|
+
# extended to other keys, e.g after reading of
|
25
|
+
# PubkeyAcceptedAlgorithms option from ssh_config file is implemented.
|
26
|
+
attr_reader :pubkey_algorithms
|
27
|
+
|
23
28
|
# Instantiates a new authentication method.
|
24
|
-
def initialize(session, options={})
|
29
|
+
def initialize(session, options = {})
|
25
30
|
@session = session
|
26
31
|
@key_manager = options[:key_manager]
|
27
32
|
@options = options
|
28
33
|
@prompt = options[:password_prompt]
|
34
|
+
@pubkey_algorithms = options[:pubkey_algorithms] \
|
35
|
+
|| %w[rsa-sha2-256-cert-v01@openssh.com
|
36
|
+
ssh-rsa-cert-v01@openssh.com
|
37
|
+
rsa-sha2-256
|
38
|
+
ssh-rsa]
|
29
39
|
self.logger = session.logger
|
30
40
|
end
|
31
41
|
|
@@ -46,7 +56,7 @@ module Net
|
|
46
56
|
# of the packet. The new packet is returned, ready for sending.
|
47
57
|
def userauth_request(username, next_service, auth_method, *others)
|
48
58
|
buffer = Net::SSH::Buffer.from(:byte, USERAUTH_REQUEST,
|
49
|
-
|
59
|
+
:string, username, :string, next_service, :string, auth_method)
|
50
60
|
|
51
61
|
others.each do |value|
|
52
62
|
case value
|
@@ -10,12 +10,12 @@ module Net
|
|
10
10
|
|
11
11
|
# Attempts to perform host-based authorization of the user by trying
|
12
12
|
# all known keys.
|
13
|
-
def authenticate(next_service, username, password=nil)
|
13
|
+
def authenticate(next_service, username, password = nil)
|
14
14
|
return false unless key_manager
|
15
15
|
|
16
16
|
key_manager.each_identity do |identity|
|
17
17
|
return true if authenticate_with(identity, next_service,
|
18
|
-
|
18
|
+
username, key_manager)
|
19
19
|
end
|
20
20
|
|
21
21
|
return false
|
@@ -63,7 +63,7 @@ module Net
|
|
63
63
|
# Build the "core" hostbased request string.
|
64
64
|
def build_request(identity, next_service, username, hostname, client_username)
|
65
65
|
userauth_request(username, next_service, "hostbased", identity.ssh_type,
|
66
|
-
|
66
|
+
Buffer.from(:key, identity).to_s, hostname, client_username).to_s
|
67
67
|
end
|
68
68
|
end
|
69
69
|
end
|
@@ -11,7 +11,7 @@ module Net
|
|
11
11
|
USERAUTH_INFO_RESPONSE = 61
|
12
12
|
|
13
13
|
# Attempt to authenticate the given user for the given service.
|
14
|
-
def authenticate(next_service, username, password=nil)
|
14
|
+
def authenticate(next_service, username, password = nil)
|
15
15
|
debug { "trying keyboard-interactive" }
|
16
16
|
send_message(userauth_request(username, next_service, "keyboard-interactive", "", ""))
|
17
17
|
|
@@ -8,7 +8,7 @@ module Net
|
|
8
8
|
# Implements the "none" SSH authentication method.
|
9
9
|
class None < Abstract
|
10
10
|
# Attempt to authenticate as "none"
|
11
|
-
def authenticate(next_service, user="", password="")
|
11
|
+
def authenticate(next_service, user = "", password = "")
|
12
12
|
send_message(userauth_request(user, next_service, "none"))
|
13
13
|
message = session.next_message
|
14
14
|
|
@@ -10,7 +10,7 @@ module Net
|
|
10
10
|
class Password < Abstract
|
11
11
|
# Attempt to authenticate the given user for the given service. If
|
12
12
|
# the password parameter is nil, this will ask for password
|
13
|
-
def authenticate(next_service, username, password=nil)
|
13
|
+
def authenticate(next_service, username, password = nil)
|
14
14
|
clear_prompter!
|
15
15
|
retries = 0
|
16
16
|
max_retries = get_max_retries
|
@@ -12,7 +12,7 @@ module Net
|
|
12
12
|
# username, trying each identity known to the key manager. If any of
|
13
13
|
# them succeed, returns +true+, otherwise returns +false+. This
|
14
14
|
# requires the presence of a key manager.
|
15
|
-
def authenticate(next_service, username, password=nil)
|
15
|
+
def authenticate(next_service, username, password = nil)
|
16
16
|
return false unless key_manager
|
17
17
|
|
18
18
|
key_manager.each_identity do |identity|
|
@@ -26,41 +26,40 @@ module Net
|
|
26
26
|
|
27
27
|
# Builds a packet that contains the request formatted for sending
|
28
28
|
# a public-key request to the server.
|
29
|
-
def build_request(pub_key, username, next_service, has_sig)
|
29
|
+
def build_request(pub_key, username, next_service, alg, has_sig)
|
30
30
|
blob = Net::SSH::Buffer.new
|
31
31
|
blob.write_key pub_key
|
32
32
|
|
33
33
|
userauth_request(username, next_service, "publickey", has_sig,
|
34
|
-
|
34
|
+
alg, blob.to_s)
|
35
35
|
end
|
36
36
|
|
37
37
|
# Builds and sends a request formatted for a public-key
|
38
38
|
# authentication request.
|
39
|
-
def send_request(pub_key, username, next_service, signature=nil)
|
40
|
-
msg = build_request(pub_key, username, next_service,
|
39
|
+
def send_request(pub_key, username, next_service, alg, signature = nil)
|
40
|
+
msg = build_request(pub_key, username, next_service, alg,
|
41
|
+
!signature.nil?)
|
41
42
|
msg.write_string(signature) if signature
|
42
43
|
send_message(msg)
|
43
44
|
end
|
44
45
|
|
45
|
-
|
46
|
-
# username, with the given identity (public key). Returns +true+ if
|
47
|
-
# successful, or +false+ otherwise.
|
48
|
-
def authenticate_with(identity, next_service, username)
|
46
|
+
def authenticate_with_alg(identity, next_service, username, alg, sig_alg = nil)
|
49
47
|
debug { "trying publickey (#{identity.fingerprint})" }
|
50
|
-
send_request(identity, username, next_service)
|
48
|
+
send_request(identity, username, next_service, alg)
|
51
49
|
|
52
50
|
message = session.next_message
|
53
51
|
|
54
52
|
case message.type
|
55
53
|
when USERAUTH_PK_OK
|
56
|
-
buffer = build_request(identity, username, next_service,
|
54
|
+
buffer = build_request(identity, username, next_service, alg,
|
55
|
+
true)
|
57
56
|
sig_data = Net::SSH::Buffer.new
|
58
57
|
sig_data.write_string(session_id)
|
59
58
|
sig_data.append(buffer.to_s)
|
60
59
|
|
61
|
-
sig_blob = key_manager.sign(identity, sig_data)
|
60
|
+
sig_blob = key_manager.sign(identity, sig_data, sig_alg)
|
62
61
|
|
63
|
-
send_request(identity, username, next_service, sig_blob.to_s)
|
62
|
+
send_request(identity, username, next_service, alg, sig_blob.to_s)
|
64
63
|
message = session.next_message
|
65
64
|
|
66
65
|
case message.type
|
@@ -76,7 +75,7 @@ module Net
|
|
76
75
|
return false
|
77
76
|
else
|
78
77
|
raise Net::SSH::Exception,
|
79
|
-
|
78
|
+
"unexpected server response to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
|
80
79
|
end
|
81
80
|
|
82
81
|
when USERAUTH_FAILURE
|
@@ -88,6 +87,49 @@ module Net
|
|
88
87
|
raise Net::SSH::Exception, "unexpected reply to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
|
89
88
|
end
|
90
89
|
end
|
90
|
+
|
91
|
+
# Attempts to perform public-key authentication for the given
|
92
|
+
# username, with the given identity (public key). Returns +true+ if
|
93
|
+
# successful, or +false+ otherwise.
|
94
|
+
def authenticate_with(identity, next_service, username)
|
95
|
+
type = identity.ssh_type
|
96
|
+
if type == "ssh-rsa"
|
97
|
+
pubkey_algorithms.each do |pk_alg|
|
98
|
+
case pk_alg
|
99
|
+
when "rsa-sha2-512", "rsa-sha2-256", "ssh-rsa"
|
100
|
+
if authenticate_with_alg(identity, next_service, username, pk_alg, pk_alg)
|
101
|
+
# success
|
102
|
+
return true
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
elsif type == "ssh-rsa-cert-v01@openssh.com"
|
107
|
+
pubkey_algorithms.each do |pk_alg|
|
108
|
+
case pk_alg
|
109
|
+
when "rsa-sha2-512-cert-v01@openssh.com"
|
110
|
+
if authenticate_with_alg(identity, next_service, username, pk_alg, "rsa-sha2-512")
|
111
|
+
# success
|
112
|
+
return true
|
113
|
+
end
|
114
|
+
when "rsa-sha2-256-cert-v01@openssh.com"
|
115
|
+
if authenticate_with_alg(identity, next_service, username, pk_alg, "rsa-sha2-256")
|
116
|
+
# success
|
117
|
+
return true
|
118
|
+
end
|
119
|
+
when "ssh-rsa-cert-v01@openssh.com"
|
120
|
+
if authenticate_with_alg(identity, next_service, username, pk_alg)
|
121
|
+
# success
|
122
|
+
return true
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
elsif authenticate_with_alg(identity, next_service, username, type)
|
127
|
+
# success
|
128
|
+
return true
|
129
|
+
end
|
130
|
+
# failure
|
131
|
+
return false
|
132
|
+
end
|
91
133
|
end
|
92
134
|
end
|
93
135
|
end
|
@@ -50,13 +50,13 @@ module Net
|
|
50
50
|
SIZEOF_DWORD = DL.sizeof('L')
|
51
51
|
elsif RUBY_VERSION < "2.1"
|
52
52
|
extend DL::Importer
|
53
|
-
dlload 'user32.dll','kernel32.dll', 'advapi32.dll'
|
53
|
+
dlload 'user32.dll', 'kernel32.dll', 'advapi32.dll'
|
54
54
|
include DL::Win32Types
|
55
55
|
|
56
56
|
SIZEOF_DWORD = DL::SIZEOF_LONG
|
57
57
|
else
|
58
58
|
extend Fiddle::Importer
|
59
|
-
dlload 'user32.dll','kernel32.dll', 'advapi32.dll'
|
59
|
+
dlload 'user32.dll', 'kernel32.dll', 'advapi32.dll'
|
60
60
|
include Fiddle::Win32Types
|
61
61
|
SIZEOF_DWORD = Fiddle::SIZEOF_LONG
|
62
62
|
end
|
@@ -240,7 +240,7 @@ module Net
|
|
240
240
|
end
|
241
241
|
|
242
242
|
def self.set_ptr_data(ptr, data)
|
243
|
-
DL::CPtr.new(ptr)[0,data.size] = data
|
243
|
+
DL::CPtr.new(ptr)[0, data.size] = data
|
244
244
|
end
|
245
245
|
end
|
246
246
|
|
@@ -281,7 +281,7 @@ module Net
|
|
281
281
|
|
282
282
|
def self.ptr_to_dword(ptr)
|
283
283
|
first = ptr.ptr.to_i
|
284
|
-
second = ptr_to_s(ptr,Win::SIZEOF_DWORD).unpack('L')[0]
|
284
|
+
second = ptr_to_s(ptr, Win::SIZEOF_DWORD).unpack('L')[0]
|
285
285
|
raise "Error" unless first == second
|
286
286
|
|
287
287
|
first
|
@@ -296,7 +296,7 @@ module Net
|
|
296
296
|
end
|
297
297
|
|
298
298
|
def self.get_sid(user)
|
299
|
-
ptr_to_s(user.to_ptr.ptr,Win::SIZEOF_DWORD).unpack('L')[0]
|
299
|
+
ptr_to_s(user.to_ptr.ptr, Win::SIZEOF_DWORD).unpack('L')[0]
|
300
300
|
end
|
301
301
|
|
302
302
|
def self.get_sid_ptr(user)
|
@@ -332,7 +332,7 @@ module Net
|
|
332
332
|
token_handle = open_process_token(Win.GetCurrentProcess,
|
333
333
|
Win::TOKEN_QUERY)
|
334
334
|
token_user = get_token_information(token_handle,
|
335
|
-
|
335
|
+
Win::TOKEN_USER_INFORMATION_CLASS)
|
336
336
|
return token_user
|
337
337
|
end
|
338
338
|
|
@@ -404,7 +404,7 @@ module Net
|
|
404
404
|
|
405
405
|
if @win.to_i == 0
|
406
406
|
raise Net::SSH::Exception,
|
407
|
-
|
407
|
+
"pageant process not running"
|
408
408
|
end
|
409
409
|
|
410
410
|
@input_buffer = Net::SSH::Buffer.new
|
@@ -458,7 +458,7 @@ module Net
|
|
458
458
|
|
459
459
|
if filemap == 0 || filemap == Win::INVALID_HANDLE_VALUE
|
460
460
|
raise Net::SSH::Exception,
|
461
|
-
|
461
|
+
"Creation of file mapping failed with error: #{Win.GetLastError}"
|
462
462
|
end
|
463
463
|
|
464
464
|
ptr = Win.MapViewOfFile(filemap, Win::FILE_MAP_WRITE, 0, 0,
|
@@ -22,12 +22,12 @@ module Net
|
|
22
22
|
# returned by OpenSSH's <tt>`ssh-add -l -E SHA256`</tt>, i.e.,
|
23
23
|
# trailing base64 padding '=' characters are stripped and the
|
24
24
|
# literal string +SHA256:+ is prepended.
|
25
|
-
def fingerprint(algorithm='MD5')
|
25
|
+
def fingerprint(algorithm = 'MD5')
|
26
26
|
@fingerprint ||= {}
|
27
27
|
@fingerprint[algorithm] ||= PubKeyFingerprint.fingerprint(to_blob, algorithm)
|
28
28
|
end
|
29
29
|
|
30
|
-
def self.fingerprint(blob, algorithm='MD5')
|
30
|
+
def self.fingerprint(blob, algorithm = 'MD5')
|
31
31
|
case algorithm.to_s.upcase
|
32
32
|
when 'MD5'
|
33
33
|
OpenSSL::Digest.hexdigest(algorithm, blob).scan(/../).join(":")
|
@@ -41,7 +41,7 @@ module Net
|
|
41
41
|
|
42
42
|
# Instantiates a new Authentication::Session object over the given
|
43
43
|
# transport layer abstraction.
|
44
|
-
def initialize(transport, options={})
|
44
|
+
def initialize(transport, options = {})
|
45
45
|
self.logger = transport.logger
|
46
46
|
@transport = transport
|
47
47
|
|
@@ -54,7 +54,7 @@ module Net
|
|
54
54
|
# Attempts to authenticate the given user, in preparation for the next
|
55
55
|
# service request. Returns true if an authentication method succeeds in
|
56
56
|
# authenticating the user, and false otherwise.
|
57
|
-
def authenticate(next_service, username, password=nil)
|
57
|
+
def authenticate(next_service, username, password = nil)
|
58
58
|
debug { "beginning authentication of `#{username}'" }
|
59
59
|
|
60
60
|
transport.send_message(transport.service_request("ssh-userauth"))
|
@@ -76,7 +76,9 @@ module Net
|
|
76
76
|
debug { "trying #{name}" }
|
77
77
|
begin
|
78
78
|
auth_class = Methods.const_get(name.split(/\W+/).map { |p| p.capitalize }.join)
|
79
|
-
method = auth_class.new(self,
|
79
|
+
method = auth_class.new(self,
|
80
|
+
key_manager: key_manager, password_prompt: options[:password_prompt],
|
81
|
+
pubkey_algorithms: options[:pubkey_algorithms] || nil)
|
80
82
|
rescue NameError
|
81
83
|
debug {"Mechanism #{name} was requested, but isn't a known type. Ignoring it."}
|
82
84
|
next
|