net-ssh 4.2.0 → 7.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- 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 +87 -0
- data/.github/workflows/rubocop.yml +13 -0
- data/.gitignore +7 -0
- data/.rubocop.yml +19 -2
- data/.rubocop_todo.yml +619 -667
- data/CHANGES.txt +110 -1
- data/Dockerfile +27 -0
- data/Dockerfile.openssl3 +17 -0
- data/Gemfile +3 -7
- data/{Gemfile.norbnacl → Gemfile.noed25519} +3 -1
- data/Manifest +4 -5
- data/README.md +293 -0
- data/Rakefile +45 -29
- data/appveyor.yml +8 -6
- data/docker-compose.yml +23 -0
- data/lib/net/ssh/authentication/agent.rb +248 -223
- data/lib/net/ssh/authentication/certificate.rb +178 -164
- data/lib/net/ssh/authentication/constants.rb +17 -15
- data/lib/net/ssh/authentication/ed25519.rb +141 -116
- data/lib/net/ssh/authentication/ed25519_loader.rb +28 -28
- data/lib/net/ssh/authentication/key_manager.rb +79 -36
- data/lib/net/ssh/authentication/methods/abstract.rb +62 -47
- data/lib/net/ssh/authentication/methods/hostbased.rb +34 -37
- data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +3 -3
- data/lib/net/ssh/authentication/methods/none.rb +16 -19
- data/lib/net/ssh/authentication/methods/password.rb +15 -16
- data/lib/net/ssh/authentication/methods/publickey.rb +96 -55
- data/lib/net/ssh/authentication/pageant.rb +468 -465
- data/lib/net/ssh/authentication/pub_key_fingerprint.rb +43 -0
- data/lib/net/ssh/authentication/session.rb +131 -122
- data/lib/net/ssh/buffer.rb +385 -332
- data/lib/net/ssh/buffered_io.rb +150 -151
- data/lib/net/ssh/config.rb +316 -239
- data/lib/net/ssh/connection/channel.rb +635 -613
- data/lib/net/ssh/connection/constants.rb +29 -29
- data/lib/net/ssh/connection/event_loop.rb +104 -95
- data/lib/net/ssh/connection/keepalive.rb +55 -51
- data/lib/net/ssh/connection/session.rb +614 -611
- data/lib/net/ssh/connection/term.rb +125 -123
- data/lib/net/ssh/errors.rb +101 -99
- data/lib/net/ssh/key_factory.rb +194 -108
- data/lib/net/ssh/known_hosts.rb +212 -134
- data/lib/net/ssh/loggable.rb +50 -49
- data/lib/net/ssh/packet.rb +83 -79
- data/lib/net/ssh/prompt.rb +51 -51
- data/lib/net/ssh/proxy/command.rb +105 -91
- data/lib/net/ssh/proxy/errors.rb +12 -10
- data/lib/net/ssh/proxy/http.rb +81 -81
- data/lib/net/ssh/proxy/https.rb +37 -36
- data/lib/net/ssh/proxy/jump.rb +49 -48
- data/lib/net/ssh/proxy/socks4.rb +2 -6
- data/lib/net/ssh/proxy/socks5.rb +14 -17
- data/lib/net/ssh/service/forward.rb +365 -362
- data/lib/net/ssh/test/channel.rb +145 -143
- data/lib/net/ssh/test/extensions.rb +131 -127
- data/lib/net/ssh/test/kex.rb +34 -32
- data/lib/net/ssh/test/local_packet.rb +46 -44
- data/lib/net/ssh/test/packet.rb +87 -84
- data/lib/net/ssh/test/remote_packet.rb +32 -30
- data/lib/net/ssh/test/script.rb +155 -155
- data/lib/net/ssh/test/socket.rb +49 -48
- data/lib/net/ssh/test.rb +82 -80
- data/lib/net/ssh/transport/algorithms.rb +433 -364
- data/lib/net/ssh/transport/cipher_factory.rb +95 -91
- data/lib/net/ssh/transport/constants.rb +32 -24
- data/lib/net/ssh/transport/ctr.rb +37 -15
- data/lib/net/ssh/transport/hmac/abstract.rb +81 -63
- data/lib/net/ssh/transport/hmac/md5.rb +0 -2
- data/lib/net/ssh/transport/hmac/md5_96.rb +0 -2
- data/lib/net/ssh/transport/hmac/none.rb +0 -2
- data/lib/net/ssh/transport/hmac/ripemd160.rb +0 -2
- data/lib/net/ssh/transport/hmac/sha1.rb +0 -2
- data/lib/net/ssh/transport/hmac/sha1_96.rb +0 -2
- data/lib/net/ssh/transport/hmac/sha2_256.rb +7 -11
- data/lib/net/ssh/transport/hmac/sha2_256_96.rb +4 -8
- data/lib/net/ssh/transport/hmac/sha2_256_etm.rb +12 -0
- data/lib/net/ssh/transport/hmac/sha2_512.rb +6 -9
- data/lib/net/ssh/transport/hmac/sha2_512_96.rb +4 -8
- data/lib/net/ssh/transport/hmac/sha2_512_etm.rb +12 -0
- data/lib/net/ssh/transport/hmac.rb +14 -12
- data/lib/net/ssh/transport/identity_cipher.rb +54 -52
- data/lib/net/ssh/transport/kex/abstract.rb +130 -0
- data/lib/net/ssh/transport/kex/abstract5656.rb +72 -0
- data/lib/net/ssh/transport/kex/curve25519_sha256.rb +39 -0
- data/lib/net/ssh/transport/kex/curve25519_sha256_loader.rb +30 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +33 -40
- data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
- data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +112 -217
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +53 -63
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +5 -9
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +36 -90
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +18 -10
- data/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +18 -10
- data/lib/net/ssh/transport/kex.rb +15 -12
- data/lib/net/ssh/transport/key_expander.rb +24 -21
- data/lib/net/ssh/transport/openssl.rb +158 -133
- data/lib/net/ssh/transport/packet_stream.rb +223 -191
- data/lib/net/ssh/transport/server_version.rb +55 -56
- data/lib/net/ssh/transport/session.rb +306 -259
- data/lib/net/ssh/transport/state.rb +178 -176
- data/lib/net/ssh/verifiers/accept_new.rb +33 -0
- data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +33 -0
- data/lib/net/ssh/verifiers/always.rb +58 -0
- data/lib/net/ssh/verifiers/never.rb +19 -0
- data/lib/net/ssh/version.rb +55 -53
- data/lib/net/ssh.rb +47 -34
- data/net-ssh-public_cert.pem +18 -19
- data/net-ssh.gemspec +12 -11
- data/support/ssh_tunnel_bug.rb +5 -5
- data.tar.gz.sig +0 -0
- metadata +78 -73
- metadata.gz.sig +0 -0
- data/.travis.yml +0 -51
- data/Gemfile.norbnacl.lock +0 -41
- data/README.rdoc +0 -169
- data/lib/net/ssh/ruby_compat.rb +0 -24
- data/lib/net/ssh/verifiers/lenient.rb +0 -30
- data/lib/net/ssh/verifiers/null.rb +0 -12
- data/lib/net/ssh/verifiers/secure.rb +0 -52
- data/lib/net/ssh/verifiers/strict.rb +0 -24
- data/support/arcfour_check.rb +0 -20
|
@@ -3,62 +3,77 @@ require 'net/ssh/errors'
|
|
|
3
3
|
require 'net/ssh/loggable'
|
|
4
4
|
require 'net/ssh/authentication/constants'
|
|
5
5
|
|
|
6
|
-
module Net
|
|
6
|
+
module Net
|
|
7
|
+
module SSH
|
|
8
|
+
module Authentication
|
|
9
|
+
module Methods
|
|
10
|
+
# The base class of all user authentication methods. It provides a few
|
|
11
|
+
# bits of common functionality.
|
|
12
|
+
class Abstract
|
|
13
|
+
include Loggable
|
|
14
|
+
include Constants
|
|
7
15
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class Abstract
|
|
11
|
-
include Constants, Loggable
|
|
16
|
+
# The authentication session object
|
|
17
|
+
attr_reader :session
|
|
12
18
|
|
|
13
|
-
|
|
14
|
-
|
|
19
|
+
# The key manager object. Not all authentication methods will require
|
|
20
|
+
# this.
|
|
21
|
+
attr_reader :key_manager
|
|
15
22
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
|
19
27
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
+
# Instantiates a new authentication method.
|
|
29
|
+
def initialize(session, options = {})
|
|
30
|
+
@session = session
|
|
31
|
+
@key_manager = options[:key_manager]
|
|
32
|
+
@options = options
|
|
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]
|
|
39
|
+
self.logger = session.logger
|
|
40
|
+
end
|
|
28
41
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
42
|
+
# Returns the session-id, as generated during the first key exchange of
|
|
43
|
+
# an SSH connection.
|
|
44
|
+
def session_id
|
|
45
|
+
session.transport.algorithms.session_id
|
|
46
|
+
end
|
|
34
47
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
48
|
+
# Sends a message via the underlying transport layer abstraction. This
|
|
49
|
+
# will block until the message is completely sent.
|
|
50
|
+
def send_message(msg)
|
|
51
|
+
session.transport.send_message(msg)
|
|
52
|
+
end
|
|
40
53
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
54
|
+
# Creates a new USERAUTH_REQUEST packet. The extra arguments on the end
|
|
55
|
+
# must be either boolean values or strings, and are tacked onto the end
|
|
56
|
+
# of the packet. The new packet is returned, ready for sending.
|
|
57
|
+
def userauth_request(username, next_service, auth_method, *others)
|
|
58
|
+
buffer = Net::SSH::Buffer.from(:byte, USERAUTH_REQUEST,
|
|
59
|
+
:string, username, :string, next_service, :string, auth_method)
|
|
47
60
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
61
|
+
others.each do |value|
|
|
62
|
+
case value
|
|
63
|
+
when true, false then buffer.write_bool(value)
|
|
64
|
+
when String then buffer.write_string(value)
|
|
65
|
+
else raise ArgumentError, "don't know how to write #{value.inspect}"
|
|
66
|
+
end
|
|
67
|
+
end
|
|
55
68
|
|
|
56
|
-
|
|
57
|
-
|
|
69
|
+
buffer
|
|
70
|
+
end
|
|
58
71
|
|
|
59
|
-
|
|
72
|
+
private
|
|
60
73
|
|
|
61
|
-
|
|
74
|
+
attr_reader :prompt
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
62
78
|
end
|
|
63
|
-
|
|
64
|
-
end; end; end; end
|
|
79
|
+
end
|
|
@@ -4,19 +4,18 @@ module Net
|
|
|
4
4
|
module SSH
|
|
5
5
|
module Authentication
|
|
6
6
|
module Methods
|
|
7
|
-
|
|
8
7
|
# Implements the host-based SSH authentication method.
|
|
9
8
|
class Hostbased < Abstract
|
|
10
9
|
include Constants
|
|
11
10
|
|
|
12
11
|
# Attempts to perform host-based authorization of the user by trying
|
|
13
12
|
# all known keys.
|
|
14
|
-
def authenticate(next_service, username, password=nil)
|
|
13
|
+
def authenticate(next_service, username, password = nil)
|
|
15
14
|
return false unless key_manager
|
|
16
15
|
|
|
17
16
|
key_manager.each_identity do |identity|
|
|
18
17
|
return true if authenticate_with(identity, next_service,
|
|
19
|
-
|
|
18
|
+
username, key_manager)
|
|
20
19
|
end
|
|
21
20
|
|
|
22
21
|
return false
|
|
@@ -24,51 +23,49 @@ module Net
|
|
|
24
23
|
|
|
25
24
|
private
|
|
26
25
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
# Attempts to perform host-based authentication of the user, using
|
|
33
|
-
# the given host identity (key).
|
|
34
|
-
def authenticate_with(identity, next_service, username, key_manager)
|
|
35
|
-
debug { "trying hostbased (#{identity.fingerprint})" }
|
|
36
|
-
client_username = ENV['USER'] || username
|
|
26
|
+
# Returns the hostname as reported by the underlying socket.
|
|
27
|
+
def hostname
|
|
28
|
+
session.transport.socket.client_name
|
|
29
|
+
end
|
|
37
30
|
|
|
38
|
-
|
|
39
|
-
|
|
31
|
+
# Attempts to perform host-based authentication of the user, using
|
|
32
|
+
# the given host identity (key).
|
|
33
|
+
def authenticate_with(identity, next_service, username, key_manager)
|
|
34
|
+
debug { "trying hostbased (#{identity.fingerprint})" }
|
|
35
|
+
client_username = ENV['USER'] || username
|
|
40
36
|
|
|
41
|
-
|
|
37
|
+
req = build_request(identity, next_service, username, "#{hostname}.", client_username)
|
|
38
|
+
sig_data = Buffer.from(:string, session_id, :raw, req)
|
|
42
39
|
|
|
43
|
-
|
|
40
|
+
sig = key_manager.sign(identity, sig_data.to_s)
|
|
44
41
|
|
|
45
|
-
|
|
46
|
-
message = session.next_message
|
|
42
|
+
message = Buffer.from(:raw, req, :string, sig)
|
|
47
43
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
info { "hostbased succeeded (#{identity.fingerprint})" }
|
|
51
|
-
return true
|
|
52
|
-
when USERAUTH_FAILURE
|
|
53
|
-
info { "hostbased failed (#{identity.fingerprint})" }
|
|
44
|
+
send_message(message)
|
|
45
|
+
message = session.next_message
|
|
54
46
|
|
|
55
|
-
|
|
56
|
-
|
|
47
|
+
case message.type
|
|
48
|
+
when USERAUTH_SUCCESS
|
|
49
|
+
info { "hostbased succeeded (#{identity.fingerprint})" }
|
|
50
|
+
return true
|
|
51
|
+
when USERAUTH_FAILURE
|
|
52
|
+
info { "hostbased failed (#{identity.fingerprint})" }
|
|
57
53
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
raise Net::SSH::Exception, "unexpected server response to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
|
|
61
|
-
end
|
|
62
|
-
end
|
|
54
|
+
raise Net::SSH::Authentication::DisallowedMethod unless
|
|
55
|
+
message[:authentications].split(/,/).include? 'hostbased'
|
|
63
56
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
Buffer.from(:key, identity).to_s, hostname, client_username).to_s
|
|
57
|
+
return false
|
|
58
|
+
else
|
|
59
|
+
raise Net::SSH::Exception, "unexpected server response to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
|
|
68
60
|
end
|
|
61
|
+
end
|
|
69
62
|
|
|
63
|
+
# Build the "core" hostbased request string.
|
|
64
|
+
def build_request(identity, next_service, username, hostname, client_username)
|
|
65
|
+
userauth_request(username, next_service, "hostbased", identity.ssh_type,
|
|
66
|
+
Buffer.from(:key, identity).to_s, hostname, client_username).to_s
|
|
67
|
+
end
|
|
70
68
|
end
|
|
71
|
-
|
|
72
69
|
end
|
|
73
70
|
end
|
|
74
71
|
end
|
|
@@ -5,14 +5,13 @@ module Net
|
|
|
5
5
|
module SSH
|
|
6
6
|
module Authentication
|
|
7
7
|
module Methods
|
|
8
|
-
|
|
9
8
|
# Implements the "keyboard-interactive" SSH authentication method.
|
|
10
9
|
class KeyboardInteractive < Abstract
|
|
11
10
|
USERAUTH_INFO_REQUEST = 60
|
|
12
11
|
USERAUTH_INFO_RESPONSE = 61
|
|
13
12
|
|
|
14
13
|
# Attempt to authenticate the given user for the given service.
|
|
15
|
-
def authenticate(next_service, username, password=nil)
|
|
14
|
+
def authenticate(next_service, username, password = nil)
|
|
16
15
|
debug { "trying keyboard-interactive" }
|
|
17
16
|
send_message(userauth_request(username, next_service, "keyboard-interactive", "", ""))
|
|
18
17
|
|
|
@@ -32,6 +31,7 @@ module Net
|
|
|
32
31
|
message[:authentications].split(/,/).include? 'keyboard-interactive'
|
|
33
32
|
|
|
34
33
|
return false unless interactive?
|
|
34
|
+
|
|
35
35
|
password = nil
|
|
36
36
|
debug { "retrying keyboard-interactive" }
|
|
37
37
|
send_message(userauth_request(username, next_service, "keyboard-interactive", "", ""))
|
|
@@ -45,7 +45,7 @@ module Net
|
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
_ = message.read_string # lang_tag
|
|
48
|
-
responses =[]
|
|
48
|
+
responses = []
|
|
49
49
|
|
|
50
50
|
message.read_long.times do
|
|
51
51
|
text = message.read_string
|
|
@@ -5,32 +5,29 @@ module Net
|
|
|
5
5
|
module SSH
|
|
6
6
|
module Authentication
|
|
7
7
|
module Methods
|
|
8
|
-
|
|
9
8
|
# Implements the "none" SSH authentication method.
|
|
10
9
|
class None < Abstract
|
|
11
10
|
# Attempt to authenticate as "none"
|
|
12
|
-
def authenticate(next_service, user="", password="")
|
|
13
|
-
send_message(userauth_request(user, next_service, "none"))
|
|
11
|
+
def authenticate(next_service, user = "", password = "")
|
|
12
|
+
send_message(userauth_request(user, next_service, "none"))
|
|
14
13
|
message = session.next_message
|
|
15
|
-
|
|
14
|
+
|
|
16
15
|
case message.type
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
end
|
|
30
|
-
|
|
16
|
+
when USERAUTH_SUCCESS
|
|
17
|
+
debug { "none succeeded" }
|
|
18
|
+
return true
|
|
19
|
+
when USERAUTH_FAILURE
|
|
20
|
+
debug { "none failed" }
|
|
21
|
+
|
|
22
|
+
raise Net::SSH::Authentication::DisallowedMethod unless
|
|
23
|
+
message[:authentications].split(/,/).include? 'none'
|
|
24
|
+
|
|
25
|
+
return false
|
|
26
|
+
else
|
|
27
|
+
raise Net::SSH::Exception, "unexpected reply to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
|
|
28
|
+
end
|
|
31
29
|
end
|
|
32
30
|
end
|
|
33
|
-
|
|
34
31
|
end
|
|
35
32
|
end
|
|
36
33
|
end
|
|
@@ -6,15 +6,14 @@ module Net
|
|
|
6
6
|
module SSH
|
|
7
7
|
module Authentication
|
|
8
8
|
module Methods
|
|
9
|
-
|
|
10
9
|
# Implements the "password" SSH authentication method.
|
|
11
10
|
class Password < Abstract
|
|
12
11
|
# Attempt to authenticate the given user for the given service. If
|
|
13
12
|
# the password parameter is nil, this will ask for password
|
|
14
|
-
def authenticate(next_service, username, password=nil)
|
|
13
|
+
def authenticate(next_service, username, password = nil)
|
|
15
14
|
clear_prompter!
|
|
16
15
|
retries = 0
|
|
17
|
-
max_retries =
|
|
16
|
+
max_retries = get_max_retries
|
|
18
17
|
return false if !password && max_retries == 0
|
|
19
18
|
|
|
20
19
|
begin
|
|
@@ -29,22 +28,23 @@ module Net
|
|
|
29
28
|
|
|
30
29
|
raise Net::SSH::Authentication::DisallowedMethod unless
|
|
31
30
|
message[:authentications].split(/,/).include? 'password'
|
|
31
|
+
|
|
32
32
|
password = nil
|
|
33
33
|
end
|
|
34
34
|
end until (message.type != USERAUTH_FAILURE || retries >= max_retries)
|
|
35
35
|
|
|
36
36
|
case message.type
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
37
|
+
when USERAUTH_SUCCESS
|
|
38
|
+
debug { "password succeeded" }
|
|
39
|
+
@prompter.success if @prompter
|
|
40
|
+
return true
|
|
41
|
+
when USERAUTH_FAILURE
|
|
42
|
+
return false
|
|
43
|
+
when USERAUTH_PASSWD_CHANGEREQ
|
|
44
|
+
debug { "password change request received, failing" }
|
|
45
|
+
return false
|
|
46
|
+
else
|
|
47
|
+
raise Net::SSH::Exception, "unexpected reply to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
|
|
48
48
|
end
|
|
49
49
|
end
|
|
50
50
|
|
|
@@ -59,7 +59,7 @@ module Net
|
|
|
59
59
|
|
|
60
60
|
def ask_password(username)
|
|
61
61
|
host = session.transport.host
|
|
62
|
-
prompt_info = {type: 'password', user: username, host: host}
|
|
62
|
+
prompt_info = { type: 'password', user: username, host: host }
|
|
63
63
|
if @prompt_info != prompt_info
|
|
64
64
|
@prompt_info = prompt_info
|
|
65
65
|
@prompter = prompt.start(prompt_info)
|
|
@@ -74,7 +74,6 @@ module Net
|
|
|
74
74
|
options[:non_interactive] ? 0 : result
|
|
75
75
|
end
|
|
76
76
|
end
|
|
77
|
-
|
|
78
77
|
end
|
|
79
78
|
end
|
|
80
79
|
end
|
|
@@ -6,14 +6,13 @@ module Net
|
|
|
6
6
|
module SSH
|
|
7
7
|
module Authentication
|
|
8
8
|
module Methods
|
|
9
|
-
|
|
10
9
|
# Implements the "publickey" SSH authentication method.
|
|
11
10
|
class Publickey < Abstract
|
|
12
11
|
# Attempts to perform public-key authentication for the given
|
|
13
12
|
# username, trying each identity known to the key manager. If any of
|
|
14
13
|
# them succeed, returns +true+, otherwise returns +false+. This
|
|
15
14
|
# requires the presence of a key manager.
|
|
16
|
-
def authenticate(next_service, username, password=nil)
|
|
15
|
+
def authenticate(next_service, username, password = nil)
|
|
17
16
|
return false unless key_manager
|
|
18
17
|
|
|
19
18
|
key_manager.each_identity do |identity|
|
|
@@ -25,71 +24,113 @@ module Net
|
|
|
25
24
|
|
|
26
25
|
private
|
|
27
26
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
27
|
+
# Builds a packet that contains the request formatted for sending
|
|
28
|
+
# a public-key request to the server.
|
|
29
|
+
def build_request(pub_key, username, next_service, alg, has_sig)
|
|
30
|
+
blob = Net::SSH::Buffer.new
|
|
31
|
+
blob.write_key pub_key
|
|
33
32
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
userauth_request(username, next_service, "publickey", has_sig,
|
|
34
|
+
alg, blob.to_s)
|
|
35
|
+
end
|
|
37
36
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
37
|
+
# Builds and sends a request formatted for a public-key
|
|
38
|
+
# authentication request.
|
|
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?)
|
|
42
|
+
msg.write_string(signature) if signature
|
|
43
|
+
send_message(msg)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def authenticate_with_alg(identity, next_service, username, alg, sig_alg = nil)
|
|
47
|
+
debug { "trying publickey (#{identity.fingerprint})" }
|
|
48
|
+
send_request(identity, username, next_service, alg)
|
|
45
49
|
|
|
46
|
-
|
|
47
|
-
# username, with the given identity (public key). Returns +true+ if
|
|
48
|
-
# successful, or +false+ otherwise.
|
|
49
|
-
def authenticate_with(identity, next_service, username)
|
|
50
|
-
debug { "trying publickey (#{identity.fingerprint})" }
|
|
51
|
-
send_request(identity, username, next_service)
|
|
50
|
+
message = session.next_message
|
|
52
51
|
|
|
52
|
+
case message.type
|
|
53
|
+
when USERAUTH_PK_OK
|
|
54
|
+
buffer = build_request(identity, username, next_service, alg,
|
|
55
|
+
true)
|
|
56
|
+
sig_data = Net::SSH::Buffer.new
|
|
57
|
+
sig_data.write_string(session_id)
|
|
58
|
+
sig_data.append(buffer.to_s)
|
|
59
|
+
|
|
60
|
+
sig_blob = key_manager.sign(identity, sig_data, sig_alg)
|
|
61
|
+
|
|
62
|
+
send_request(identity, username, next_service, alg, sig_blob.to_s)
|
|
53
63
|
message = session.next_message
|
|
54
64
|
|
|
55
65
|
case message.type
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
return true
|
|
71
|
-
when USERAUTH_FAILURE
|
|
72
|
-
debug { "publickey failed (#{identity.fingerprint})" }
|
|
73
|
-
|
|
74
|
-
raise Net::SSH::Authentication::DisallowedMethod unless
|
|
75
|
-
message[:authentications].split(/,/).include? 'publickey'
|
|
76
|
-
|
|
77
|
-
return false
|
|
78
|
-
else
|
|
79
|
-
raise Net::SSH::Exception,
|
|
80
|
-
"unexpected server response to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
|
|
81
|
-
end
|
|
66
|
+
when USERAUTH_SUCCESS
|
|
67
|
+
debug { "publickey succeeded (#{identity.fingerprint})" }
|
|
68
|
+
return true
|
|
69
|
+
when USERAUTH_FAILURE
|
|
70
|
+
debug { "publickey failed (#{identity.fingerprint})" }
|
|
71
|
+
|
|
72
|
+
raise Net::SSH::Authentication::DisallowedMethod unless
|
|
73
|
+
message[:authentications].split(/,/).include? 'publickey'
|
|
74
|
+
|
|
75
|
+
return false
|
|
76
|
+
else
|
|
77
|
+
raise Net::SSH::Exception,
|
|
78
|
+
"unexpected server response to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
|
|
79
|
+
end
|
|
82
80
|
|
|
83
|
-
|
|
84
|
-
|
|
81
|
+
when USERAUTH_FAILURE
|
|
82
|
+
return false
|
|
83
|
+
when USERAUTH_SUCCESS
|
|
84
|
+
return true
|
|
85
85
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
end
|
|
86
|
+
else
|
|
87
|
+
raise Net::SSH::Exception, "unexpected reply to USERAUTH_REQUEST: #{message.type} (#{message.inspect})"
|
|
89
88
|
end
|
|
89
|
+
end
|
|
90
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
|
-
|
|
93
134
|
end
|
|
94
135
|
end
|
|
95
136
|
end
|