net-ssh 2.7.0 → 7.3.0
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 +7 -0
- checksums.yaml.gz.sig +0 -0
- data/.dockerignore +6 -0
- data/.github/FUNDING.yml +1 -0
- data/.github/config/rubocop_linter_action.yml +4 -0
- data/.github/workflows/ci-with-docker.yml +44 -0
- data/.github/workflows/ci.yml +94 -0
- data/.github/workflows/rubocop.yml +16 -0
- data/.gitignore +15 -0
- data/.rubocop.yml +22 -0
- data/.rubocop_todo.yml +1081 -0
- data/CHANGES.txt +387 -0
- data/DEVELOPMENT.md +23 -0
- data/Dockerfile +29 -0
- data/Dockerfile.openssl3 +17 -0
- data/Gemfile +13 -0
- data/Gemfile.noed25519 +12 -0
- data/Gemfile.norbnacl +12 -0
- data/ISSUE_TEMPLATE.md +30 -0
- data/Manifest +4 -5
- data/README.md +303 -0
- data/Rakefile +174 -40
- data/SECURITY.md +4 -0
- data/THANKS.txt +25 -0
- data/appveyor.yml +58 -0
- data/docker-compose.yml +25 -0
- data/lib/net/ssh/authentication/agent.rb +279 -18
- data/lib/net/ssh/authentication/certificate.rb +183 -0
- data/lib/net/ssh/authentication/constants.rb +17 -15
- data/lib/net/ssh/authentication/ed25519.rb +184 -0
- data/lib/net/ssh/authentication/ed25519_loader.rb +31 -0
- data/lib/net/ssh/authentication/key_manager.rb +125 -54
- data/lib/net/ssh/authentication/methods/abstract.rb +67 -48
- data/lib/net/ssh/authentication/methods/hostbased.rb +34 -37
- data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +19 -12
- data/lib/net/ssh/authentication/methods/none.rb +16 -19
- data/lib/net/ssh/authentication/methods/password.rb +56 -19
- data/lib/net/ssh/authentication/methods/publickey.rb +96 -55
- data/lib/net/ssh/authentication/pageant.rb +483 -246
- data/lib/net/ssh/authentication/pub_key_fingerprint.rb +43 -0
- data/lib/net/ssh/authentication/session.rb +138 -120
- data/lib/net/ssh/buffer.rb +399 -300
- data/lib/net/ssh/buffered_io.rb +154 -150
- data/lib/net/ssh/config.rb +361 -166
- data/lib/net/ssh/connection/channel.rb +640 -596
- data/lib/net/ssh/connection/constants.rb +29 -29
- data/lib/net/ssh/connection/event_loop.rb +123 -0
- data/lib/net/ssh/connection/keepalive.rb +59 -0
- data/lib/net/ssh/connection/session.rb +628 -548
- data/lib/net/ssh/connection/term.rb +125 -123
- data/lib/net/ssh/errors.rb +101 -95
- data/lib/net/ssh/key_factory.rb +198 -100
- data/lib/net/ssh/known_hosts.rb +221 -98
- data/lib/net/ssh/loggable.rb +50 -49
- data/lib/net/ssh/packet.rb +83 -79
- data/lib/net/ssh/prompt.rb +50 -81
- data/lib/net/ssh/proxy/command.rb +108 -60
- data/lib/net/ssh/proxy/errors.rb +12 -10
- data/lib/net/ssh/proxy/http.rb +82 -78
- data/lib/net/ssh/proxy/https.rb +50 -0
- data/lib/net/ssh/proxy/jump.rb +54 -0
- data/lib/net/ssh/proxy/socks4.rb +5 -8
- data/lib/net/ssh/proxy/socks5.rb +18 -20
- data/lib/net/ssh/service/forward.rb +383 -255
- data/lib/net/ssh/test/channel.rb +145 -136
- data/lib/net/ssh/test/extensions.rb +131 -110
- 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 +89 -70
- data/lib/net/ssh/test/remote_packet.rb +32 -30
- data/lib/net/ssh/test/script.rb +156 -142
- data/lib/net/ssh/test/socket.rb +49 -48
- data/lib/net/ssh/test.rb +82 -77
- data/lib/net/ssh/transport/aes128_gcm.rb +40 -0
- data/lib/net/ssh/transport/aes256_gcm.rb +40 -0
- data/lib/net/ssh/transport/algorithms.rb +472 -348
- data/lib/net/ssh/transport/chacha20_poly1305_cipher.rb +117 -0
- data/lib/net/ssh/transport/chacha20_poly1305_cipher_loader.rb +17 -0
- data/lib/net/ssh/transport/cipher_factory.rb +124 -100
- data/lib/net/ssh/transport/constants.rb +32 -24
- data/lib/net/ssh/transport/ctr.rb +42 -22
- data/lib/net/ssh/transport/gcm_cipher.rb +207 -0
- data/lib/net/ssh/transport/hmac/abstract.rb +97 -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 -44
- 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 +119 -213
- data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +53 -61
- 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 -20
- data/lib/net/ssh/transport/openssl.rb +161 -124
- data/lib/net/ssh/transport/openssl_cipher_extensions.rb +8 -0
- data/lib/net/ssh/transport/packet_stream.rb +246 -183
- data/lib/net/ssh/transport/server_version.rb +57 -51
- data/lib/net/ssh/transport/session.rb +307 -235
- 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 +57 -51
- data/lib/net/ssh.rb +140 -40
- data/net-ssh-public_cert.pem +21 -0
- data/net-ssh.gemspec +39 -184
- data/support/ssh_tunnel_bug.rb +5 -5
- data.tar.gz.sig +0 -0
- metadata +205 -99
- metadata.gz.sig +0 -0
- data/README.rdoc +0 -219
- data/Rudyfile +0 -96
- data/gem-public_cert.pem +0 -20
- data/lib/net/ssh/authentication/agent/java_pageant.rb +0 -85
- data/lib/net/ssh/authentication/agent/socket.rb +0 -170
- data/lib/net/ssh/ruby_compat.rb +0 -51
- 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 -54
- data/lib/net/ssh/verifiers/strict.rb +0 -24
- data/setup.rb +0 -1585
- data/support/arcfour_check.rb +0 -20
- data/test/README.txt +0 -47
- data/test/authentication/methods/common.rb +0 -28
- data/test/authentication/methods/test_abstract.rb +0 -51
- data/test/authentication/methods/test_hostbased.rb +0 -114
- data/test/authentication/methods/test_keyboard_interactive.rb +0 -100
- data/test/authentication/methods/test_none.rb +0 -41
- data/test/authentication/methods/test_password.rb +0 -52
- data/test/authentication/methods/test_publickey.rb +0 -148
- data/test/authentication/test_agent.rb +0 -205
- data/test/authentication/test_key_manager.rb +0 -218
- data/test/authentication/test_session.rb +0 -108
- data/test/common.rb +0 -108
- data/test/configs/eqsign +0 -3
- data/test/configs/exact_match +0 -8
- data/test/configs/host_plus +0 -10
- data/test/configs/multihost +0 -4
- data/test/configs/nohost +0 -19
- data/test/configs/numeric_host +0 -4
- data/test/configs/send_env +0 -2
- data/test/configs/substitutes +0 -8
- data/test/configs/wild_cards +0 -14
- data/test/connection/test_channel.rb +0 -467
- data/test/connection/test_session.rb +0 -526
- data/test/known_hosts/github +0 -1
- data/test/manual/test_forward.rb +0 -223
- data/test/start/test_options.rb +0 -36
- data/test/start/test_transport.rb +0 -28
- data/test/test_all.rb +0 -11
- data/test/test_buffer.rb +0 -433
- data/test/test_buffered_io.rb +0 -63
- data/test/test_config.rb +0 -151
- data/test/test_key_factory.rb +0 -173
- data/test/test_known_hosts.rb +0 -13
- data/test/transport/hmac/test_md5.rb +0 -41
- data/test/transport/hmac/test_md5_96.rb +0 -27
- data/test/transport/hmac/test_none.rb +0 -34
- data/test/transport/hmac/test_ripemd160.rb +0 -36
- data/test/transport/hmac/test_sha1.rb +0 -36
- data/test/transport/hmac/test_sha1_96.rb +0 -27
- data/test/transport/hmac/test_sha2_256.rb +0 -37
- data/test/transport/hmac/test_sha2_256_96.rb +0 -27
- data/test/transport/hmac/test_sha2_512.rb +0 -37
- data/test/transport/hmac/test_sha2_512_96.rb +0 -27
- data/test/transport/kex/test_diffie_hellman_group14_sha1.rb +0 -13
- data/test/transport/kex/test_diffie_hellman_group1_sha1.rb +0 -146
- data/test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb +0 -92
- data/test/transport/kex/test_diffie_hellman_group_exchange_sha256.rb +0 -34
- data/test/transport/kex/test_ecdh_sha2_nistp256.rb +0 -161
- data/test/transport/kex/test_ecdh_sha2_nistp384.rb +0 -38
- data/test/transport/kex/test_ecdh_sha2_nistp521.rb +0 -38
- data/test/transport/test_algorithms.rb +0 -330
- data/test/transport/test_cipher_factory.rb +0 -443
- data/test/transport/test_hmac.rb +0 -34
- data/test/transport/test_identity_cipher.rb +0 -40
- data/test/transport/test_packet_stream.rb +0 -1755
- data/test/transport/test_server_version.rb +0 -78
- data/test/transport/test_session.rb +0 -319
- data/test/transport/test_state.rb +0 -181
data/Rudyfile
DELETED
@@ -1,96 +0,0 @@
|
|
1
|
-
# Rudyfile
|
2
|
-
#
|
3
|
-
# This configuration is used to test installing
|
4
|
-
# and running net-ssh on a clean machine.
|
5
|
-
#
|
6
|
-
# Usage:
|
7
|
-
#
|
8
|
-
# $ rudy -vv startup
|
9
|
-
# $ rudy -vv testsuite
|
10
|
-
# $ rudy -vv shutdown
|
11
|
-
#
|
12
|
-
# Requires: Rudy 0.9 (http://code.google.com/p/rudy/)
|
13
|
-
#
|
14
|
-
|
15
|
-
defaults do
|
16
|
-
color true
|
17
|
-
environment :test
|
18
|
-
role :netssh
|
19
|
-
end
|
20
|
-
|
21
|
-
machines do
|
22
|
-
region :'us-east-1' do
|
23
|
-
ami 'ami-e348af8a' # Alestic Debian 5.0, 32-bit (US)
|
24
|
-
end
|
25
|
-
env :test do
|
26
|
-
role :netssh do
|
27
|
-
user :root
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
commands do
|
33
|
-
allow :apt_get, "apt-get", :y, :q
|
34
|
-
allow :gem_install, "/usr/bin/gem", "install", :n, '/usr/bin', :y, :V, "--no-rdoc", "--no-ri"
|
35
|
-
allow :gem_sources, "/usr/bin/gem", "sources"
|
36
|
-
allow :gem_uninstall, "/usr/bin/gem", "uninstall", :V
|
37
|
-
allow :update_rubygems
|
38
|
-
allow :rm
|
39
|
-
end
|
40
|
-
|
41
|
-
routines do
|
42
|
-
|
43
|
-
testsuite do
|
44
|
-
before :sysupdate, :installdeps, :install_gem
|
45
|
-
|
46
|
-
remote :root do
|
47
|
-
directory_upload 'test', '/tmp/'
|
48
|
-
cd '/tmp'
|
49
|
-
ruby :I, 'lib/', :I, 'test/', :r, 'rubygems', 'test/test_all.rb'
|
50
|
-
end
|
51
|
-
|
52
|
-
after :install_rubyforge, :install_github
|
53
|
-
end
|
54
|
-
|
55
|
-
install_gem do
|
56
|
-
before :package_gem
|
57
|
-
remote :root do
|
58
|
-
disable_safe_mode
|
59
|
-
file_upload "pkg/net-ssh-*.gem", "/tmp/"
|
60
|
-
gem_install "/tmp/net-ssh-*.gem"
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
package_gem do
|
65
|
-
local do
|
66
|
-
rm :r, :f, 'pkg'
|
67
|
-
rake 'package'
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
remove do
|
72
|
-
remote :root do
|
73
|
-
gem_uninstall 'net-ssh'
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
installdeps do
|
78
|
-
remote :root do
|
79
|
-
gem_install "rye", "test-unit", "mocha"
|
80
|
-
rye 'authorize-local'
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
sysupdate do
|
85
|
-
remote :root do
|
86
|
-
apt_get "update"
|
87
|
-
apt_get "install", "build-essential", "git-core"
|
88
|
-
apt_get "install", "ruby1.8-dev", "rdoc", "libzlib-ruby", "rubygems"
|
89
|
-
mkdir :p, "/var/lib/gems/1.8/bin" # Doesn't get created, but causes Rubygems to fail
|
90
|
-
gem_install "builder", "session"
|
91
|
-
gem_install 'rubygems-update', "-v=1.3.4" # circular issue with 1.3.5 and hoe
|
92
|
-
update_rubygems
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
data/gem-public_cert.pem
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
-----BEGIN CERTIFICATE-----
|
2
|
-
MIIDNjCCAh6gAwIBAgIBADANBgkqhkiG9w0BAQUFADBBMQ8wDQYDVQQDDAZkZWxh
|
3
|
-
bm8xGTAXBgoJkiaJk/IsZAEZFglzb2x1dGlvdXMxEzARBgoJkiaJk/IsZAEZFgNj
|
4
|
-
b20wHhcNMTMwMjA2MTE1NzQ1WhcNMTQwMjA2MTE1NzQ1WjBBMQ8wDQYDVQQDDAZk
|
5
|
-
ZWxhbm8xGTAXBgoJkiaJk/IsZAEZFglzb2x1dGlvdXMxEzARBgoJkiaJk/IsZAEZ
|
6
|
-
FgNjb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDg1hMtl0XsMuUK
|
7
|
-
AKTgYWv3gjj7vuEsE2EjT+vyBg8/LpqVVwZziiaebJT9IZiQ+sCFqbiakj0b53pI
|
8
|
-
hg1yOaBEmH6/W0L7rwzqaRV9sW1eJs9JxFYQCnd67zUnzj8nnRlOjG+hhIG+Vsij
|
9
|
-
npsGbt28pefuNZJjO5q2clAlfSniIIHfIsU7/StEYu6FUGOjnwryZ0r5yJlr9RrE
|
10
|
-
Gs+q0DW8QnZ9UpAfuDFQZuIqeKQFFLE7nMmCGaA+0BN1nLl3fVHNbLHq7Avk8+Z+
|
11
|
-
ZuuvkdscbHlO/l+3xCNQ5nUnHwq0ADAbMLOlmiYYzqXoWLjmeI6me/clktJCfN2R
|
12
|
-
oZG3UQvvAgMBAAGjOTA3MAkGA1UdEwQCMAAwHQYDVR0OBBYEFMSJOEtHzE4l0azv
|
13
|
-
M0JK0kKNToK1MAsGA1UdDwQEAwIEsDANBgkqhkiG9w0BAQUFAAOCAQEAtOdE73qx
|
14
|
-
OH2ydi9oT2hS5f9G0y1Z70Tlwh+VGExyfxzVE9XwC+iPpJxNraiHYgF/9/oky7ZZ
|
15
|
-
R9q0/tJneuhAenZdiQkX7oi4O3v9wRS6YHoWBxMPFKVRLNTzvVJsbmfpCAlp5/5g
|
16
|
-
ps4wQFy5mibElGVlOobf/ghqZ25HS9J6kd0/C/ry0AUtTogsL7TxGwT4kbCx63ub
|
17
|
-
3vywEEhsJUzfd97GCABmtQfRTldX/j7F1z/5wd8p+hfdox1iibds9ZtfaZA3KzKn
|
18
|
-
kchWN9B6zg9r1XMQ8BM2Jz0XoPanPe354+lWwjpkRKbFow/ZbQHcCLCq24+N6b6g
|
19
|
-
dgKfNDzwiDpqCA==
|
20
|
-
-----END CERTIFICATE-----
|
@@ -1,85 +0,0 @@
|
|
1
|
-
require 'jruby_pageant'
|
2
|
-
|
3
|
-
module Net; module SSH; module Authentication
|
4
|
-
|
5
|
-
# This class implements an agent for JRuby + Pageant.
|
6
|
-
#
|
7
|
-
# Written by Artūras Šlajus <arturas.slajus@gmail.com>
|
8
|
-
class Agent
|
9
|
-
include Loggable
|
10
|
-
include JRubyPageant
|
11
|
-
|
12
|
-
# A simple module for extending keys, to allow blobs and comments to be
|
13
|
-
# specified for them.
|
14
|
-
module Key
|
15
|
-
# :blob is used by OpenSSL::PKey::RSA#to_blob
|
16
|
-
attr_accessor :java_blob
|
17
|
-
attr_accessor :comment
|
18
|
-
end
|
19
|
-
|
20
|
-
# Instantiates a new agent object, connects to a running SSH agent,
|
21
|
-
# negotiates the agent protocol version, and returns the agent object.
|
22
|
-
def self.connect(logger=nil)
|
23
|
-
agent = new(logger)
|
24
|
-
agent.connect!
|
25
|
-
agent
|
26
|
-
end
|
27
|
-
|
28
|
-
# Creates a new Agent object, using the optional logger instance to
|
29
|
-
# report status.
|
30
|
-
def initialize(logger=nil)
|
31
|
-
self.logger = logger
|
32
|
-
end
|
33
|
-
|
34
|
-
# Connect to the agent process using the socket factory and socket name
|
35
|
-
# given by the attribute writers. If the agent on the other end of the
|
36
|
-
# socket reports that it is an SSH2-compatible agent, this will fail
|
37
|
-
# (it only supports the ssh-agent distributed by OpenSSH).
|
38
|
-
def connect!
|
39
|
-
debug { "connecting to Pageant ssh-agent (via java connector)" }
|
40
|
-
@agent_proxy = JRubyPageant.create
|
41
|
-
unless @agent_proxy.is_running
|
42
|
-
raise AgentNotAvailable, "Pageant is not running!"
|
43
|
-
end
|
44
|
-
debug { "connection to Pageant ssh-agent (via java connector) succeeded" }
|
45
|
-
rescue AgentProxyException => e
|
46
|
-
error { "could not connect to Pageant ssh-agent (via java connector)" }
|
47
|
-
raise AgentNotAvailable, e.message, e.backtrace
|
48
|
-
end
|
49
|
-
|
50
|
-
# Return an array of all identities (public keys) known to the agent.
|
51
|
-
# Each key returned is augmented with a +comment+ property which is set
|
52
|
-
# to the comment returned by the agent for that key.
|
53
|
-
def identities
|
54
|
-
debug { "getting identities from Pageant" }
|
55
|
-
@agent_proxy.get_identities.map do |identity|
|
56
|
-
blob = identity.get_blob
|
57
|
-
key = Buffer.new(String.from_java_bytes(blob)).read_key
|
58
|
-
key.extend(Key)
|
59
|
-
key.java_blob = blob
|
60
|
-
key.comment = String.from_java_bytes(identity.get_comment)
|
61
|
-
key
|
62
|
-
end
|
63
|
-
rescue AgentProxyException => e
|
64
|
-
raise AgentError, "Cannot get identities: #{e.message}", e.backtrace
|
65
|
-
end
|
66
|
-
|
67
|
-
# Simulate agent close. This agent reference is no longer able to
|
68
|
-
# query the agent.
|
69
|
-
def close
|
70
|
-
@agent_proxy = nil
|
71
|
-
end
|
72
|
-
|
73
|
-
# Using the agent and the given public key, sign the given data. The
|
74
|
-
# signature is returned in SSH2 format.
|
75
|
-
def sign(key, data)
|
76
|
-
signed = @agent_proxy.sign(key.java_blob, data.to_java_bytes)
|
77
|
-
String.from_java_bytes(signed)
|
78
|
-
rescue AgentProxyException => e
|
79
|
-
raise AgentError,
|
80
|
-
"agent could not sign data with requested identity: #{e.message}",
|
81
|
-
e.backtrace
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
end; end; end
|
@@ -1,170 +0,0 @@
|
|
1
|
-
require 'net/ssh/transport/server_version'
|
2
|
-
|
3
|
-
# Only load pageant on Windows
|
4
|
-
if Net::SSH::Authentication::PLATFORM == :win32
|
5
|
-
require 'net/ssh/authentication/pageant'
|
6
|
-
end
|
7
|
-
|
8
|
-
module Net; module SSH; module Authentication
|
9
|
-
|
10
|
-
# This class implements a simple client for the ssh-agent protocol. It
|
11
|
-
# does not implement any specific protocol, but instead copies the
|
12
|
-
# behavior of the ssh-agent functions in the OpenSSH library (3.8).
|
13
|
-
#
|
14
|
-
# This means that although it behaves like a SSH1 client, it also has
|
15
|
-
# some SSH2 functionality (like signing data).
|
16
|
-
class Agent
|
17
|
-
include Loggable
|
18
|
-
|
19
|
-
# A simple module for extending keys, to allow comments to be specified
|
20
|
-
# for them.
|
21
|
-
module Comment
|
22
|
-
attr_accessor :comment
|
23
|
-
end
|
24
|
-
|
25
|
-
SSH2_AGENT_REQUEST_VERSION = 1
|
26
|
-
SSH2_AGENT_REQUEST_IDENTITIES = 11
|
27
|
-
SSH2_AGENT_IDENTITIES_ANSWER = 12
|
28
|
-
SSH2_AGENT_SIGN_REQUEST = 13
|
29
|
-
SSH2_AGENT_SIGN_RESPONSE = 14
|
30
|
-
SSH2_AGENT_FAILURE = 30
|
31
|
-
SSH2_AGENT_VERSION_RESPONSE = 103
|
32
|
-
|
33
|
-
SSH_COM_AGENT2_FAILURE = 102
|
34
|
-
|
35
|
-
SSH_AGENT_REQUEST_RSA_IDENTITIES = 1
|
36
|
-
SSH_AGENT_RSA_IDENTITIES_ANSWER1 = 2
|
37
|
-
SSH_AGENT_RSA_IDENTITIES_ANSWER2 = 5
|
38
|
-
SSH_AGENT_FAILURE = 5
|
39
|
-
|
40
|
-
# The underlying socket being used to communicate with the SSH agent.
|
41
|
-
attr_reader :socket
|
42
|
-
|
43
|
-
# Instantiates a new agent object, connects to a running SSH agent,
|
44
|
-
# negotiates the agent protocol version, and returns the agent object.
|
45
|
-
def self.connect(logger=nil)
|
46
|
-
agent = new(logger)
|
47
|
-
agent.connect!
|
48
|
-
agent.negotiate!
|
49
|
-
agent
|
50
|
-
end
|
51
|
-
|
52
|
-
# Creates a new Agent object, using the optional logger instance to
|
53
|
-
# report status.
|
54
|
-
def initialize(logger=nil)
|
55
|
-
self.logger = logger
|
56
|
-
end
|
57
|
-
|
58
|
-
# Connect to the agent process using the socket factory and socket name
|
59
|
-
# given by the attribute writers. If the agent on the other end of the
|
60
|
-
# socket reports that it is an SSH2-compatible agent, this will fail
|
61
|
-
# (it only supports the ssh-agent distributed by OpenSSH).
|
62
|
-
def connect!
|
63
|
-
begin
|
64
|
-
debug { "connecting to ssh-agent" }
|
65
|
-
@socket = agent_socket_factory.open(ENV['SSH_AUTH_SOCK'])
|
66
|
-
rescue
|
67
|
-
error { "could not connect to ssh-agent" }
|
68
|
-
raise AgentNotAvailable, $!.message
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
# Attempts to negotiate the SSH agent protocol version. Raises an error
|
73
|
-
# if the version could not be negotiated successfully.
|
74
|
-
def negotiate!
|
75
|
-
# determine what type of agent we're communicating with
|
76
|
-
type, body = send_and_wait(SSH2_AGENT_REQUEST_VERSION, :string, Transport::ServerVersion::PROTO_VERSION)
|
77
|
-
|
78
|
-
if type == SSH2_AGENT_VERSION_RESPONSE
|
79
|
-
raise NotImplementedError, "SSH2 agents are not yet supported"
|
80
|
-
elsif type != SSH_AGENT_RSA_IDENTITIES_ANSWER1 && type != SSH_AGENT_RSA_IDENTITIES_ANSWER2
|
81
|
-
raise AgentError, "unknown response from agent: #{type}, #{body.to_s.inspect}"
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
# Return an array of all identities (public keys) known to the agent.
|
86
|
-
# Each key returned is augmented with a +comment+ property which is set
|
87
|
-
# to the comment returned by the agent for that key.
|
88
|
-
def identities
|
89
|
-
type, body = send_and_wait(SSH2_AGENT_REQUEST_IDENTITIES)
|
90
|
-
raise AgentError, "could not get identity count" if agent_failed(type)
|
91
|
-
raise AgentError, "bad authentication reply: #{type}" if type != SSH2_AGENT_IDENTITIES_ANSWER
|
92
|
-
|
93
|
-
identities = []
|
94
|
-
body.read_long.times do
|
95
|
-
key = Buffer.new(body.read_string).read_key
|
96
|
-
key.extend(Comment)
|
97
|
-
key.comment = body.read_string
|
98
|
-
identities.push key
|
99
|
-
end
|
100
|
-
|
101
|
-
return identities
|
102
|
-
end
|
103
|
-
|
104
|
-
# Closes this socket. This agent reference is no longer able to
|
105
|
-
# query the agent.
|
106
|
-
def close
|
107
|
-
@socket.close
|
108
|
-
end
|
109
|
-
|
110
|
-
# Using the agent and the given public key, sign the given data. The
|
111
|
-
# signature is returned in SSH2 format.
|
112
|
-
def sign(key, data)
|
113
|
-
type, reply = send_and_wait(SSH2_AGENT_SIGN_REQUEST, :string, Buffer.from(:key, key), :string, data, :long, 0)
|
114
|
-
|
115
|
-
if agent_failed(type)
|
116
|
-
raise AgentError, "agent could not sign data with requested identity"
|
117
|
-
elsif type != SSH2_AGENT_SIGN_RESPONSE
|
118
|
-
raise AgentError, "bad authentication response #{type}"
|
119
|
-
end
|
120
|
-
|
121
|
-
return reply.read_string
|
122
|
-
end
|
123
|
-
|
124
|
-
private
|
125
|
-
|
126
|
-
# Returns the agent socket factory to use.
|
127
|
-
def agent_socket_factory
|
128
|
-
if Net::SSH::Authentication::PLATFORM == :win32
|
129
|
-
Pageant::socket_factory
|
130
|
-
else
|
131
|
-
UNIXSocket
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
# Send a new packet of the given type, with the associated data.
|
136
|
-
def send_packet(type, *args)
|
137
|
-
buffer = Buffer.from(*args)
|
138
|
-
data = [buffer.length + 1, type.to_i, buffer.to_s].pack("NCA*")
|
139
|
-
debug { "sending agent request #{type} len #{buffer.length}" }
|
140
|
-
@socket.send data, 0
|
141
|
-
end
|
142
|
-
|
143
|
-
# Read the next packet from the agent. This will return a two-part
|
144
|
-
# tuple consisting of the packet type, and the packet's body (which
|
145
|
-
# is returned as a Net::SSH::Buffer).
|
146
|
-
def read_packet
|
147
|
-
buffer = Net::SSH::Buffer.new(@socket.read(4))
|
148
|
-
buffer.append(@socket.read(buffer.read_long))
|
149
|
-
type = buffer.read_byte
|
150
|
-
debug { "received agent packet #{type} len #{buffer.length-4}" }
|
151
|
-
return type, buffer
|
152
|
-
end
|
153
|
-
|
154
|
-
# Send the given packet and return the subsequent reply from the agent.
|
155
|
-
# (See #send_packet and #read_packet).
|
156
|
-
def send_and_wait(type, *args)
|
157
|
-
send_packet(type, *args)
|
158
|
-
read_packet
|
159
|
-
end
|
160
|
-
|
161
|
-
# Returns +true+ if the parameter indicates a "failure" response from
|
162
|
-
# the agent, and +false+ otherwise.
|
163
|
-
def agent_failed(type)
|
164
|
-
type == SSH_AGENT_FAILURE ||
|
165
|
-
type == SSH2_AGENT_FAILURE ||
|
166
|
-
type == SSH_COM_AGENT2_FAILURE
|
167
|
-
end
|
168
|
-
end
|
169
|
-
|
170
|
-
end; end; end
|
data/lib/net/ssh/ruby_compat.rb
DELETED
@@ -1,51 +0,0 @@
|
|
1
|
-
require 'thread'
|
2
|
-
|
3
|
-
class String
|
4
|
-
if RUBY_VERSION < "1.9"
|
5
|
-
def getbyte(index)
|
6
|
-
self[index]
|
7
|
-
end
|
8
|
-
def setbyte(index, c)
|
9
|
-
self[index] = c
|
10
|
-
end
|
11
|
-
end
|
12
|
-
if RUBY_VERSION < "1.8.7"
|
13
|
-
def bytesize
|
14
|
-
self.size
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
module Net; module SSH
|
20
|
-
|
21
|
-
# This class contains miscellaneous patches and workarounds
|
22
|
-
# for different ruby implementations.
|
23
|
-
class Compat
|
24
|
-
|
25
|
-
# A workaround for an IO#select threading bug in certain versions of MRI 1.8.
|
26
|
-
# See: http://net-ssh.lighthouseapp.com/projects/36253/tickets/1-ioselect-threading-bug-in-ruby-18
|
27
|
-
# The root issue is documented here: http://redmine.ruby-lang.org/issues/show/1993
|
28
|
-
if RUBY_VERSION >= '1.9' || RUBY_PLATFORM == 'java'
|
29
|
-
def self.io_select(*params)
|
30
|
-
IO.select(*params)
|
31
|
-
end
|
32
|
-
else
|
33
|
-
SELECT_MUTEX = Mutex.new
|
34
|
-
def self.io_select(*params)
|
35
|
-
# It should be safe to wrap calls in a mutex when the timeout is 0
|
36
|
-
# (that is, the call is not supposed to block).
|
37
|
-
# We leave blocking calls unprotected to avoid causing deadlocks.
|
38
|
-
# This should still catch the main case for Capistrano users.
|
39
|
-
if params[3] == 0
|
40
|
-
SELECT_MUTEX.synchronize do
|
41
|
-
IO.select(*params)
|
42
|
-
end
|
43
|
-
else
|
44
|
-
IO.select(*params)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
end
|
50
|
-
|
51
|
-
end; end
|
@@ -1,30 +0,0 @@
|
|
1
|
-
require 'net/ssh/verifiers/strict'
|
2
|
-
|
3
|
-
module Net; module SSH; module Verifiers
|
4
|
-
|
5
|
-
# Basically the same as the Strict verifier, but does not try to actually
|
6
|
-
# verify a connection if the server is the localhost and the port is a
|
7
|
-
# nonstandard port number. Those two conditions will typically mean the
|
8
|
-
# connection is being tunnelled through a forwarded port, so the known-hosts
|
9
|
-
# file will not be helpful (in general).
|
10
|
-
class Lenient < Strict
|
11
|
-
# Tries to determine if the connection is being tunnelled, and if so,
|
12
|
-
# returns true. Otherwise, performs the standard strict verification.
|
13
|
-
def verify(arguments)
|
14
|
-
return true if tunnelled?(arguments)
|
15
|
-
super
|
16
|
-
end
|
17
|
-
|
18
|
-
private
|
19
|
-
|
20
|
-
# A connection is potentially being tunnelled if the port is not 22,
|
21
|
-
# and the ip refers to the localhost.
|
22
|
-
def tunnelled?(args)
|
23
|
-
return false if args[:session].port == Net::SSH::Transport::Session::DEFAULT_PORT
|
24
|
-
|
25
|
-
ip = args[:session].peer[:ip]
|
26
|
-
return ip == "127.0.0.1" || ip == "::1"
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
end; end; end
|
@@ -1,12 +0,0 @@
|
|
1
|
-
module Net; module SSH; module Verifiers
|
2
|
-
|
3
|
-
# The Null host key verifier simply allows every key it sees, without
|
4
|
-
# bothering to verify. This is simple, but is not particularly secure.
|
5
|
-
class Null
|
6
|
-
# Returns true.
|
7
|
-
def verify(arguments)
|
8
|
-
true
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
end; end; end
|
@@ -1,54 +0,0 @@
|
|
1
|
-
require 'net/ssh/errors'
|
2
|
-
require 'net/ssh/known_hosts'
|
3
|
-
|
4
|
-
module Net; module SSH; module Verifiers
|
5
|
-
|
6
|
-
# Does a strict host verification, looking the server up in the known
|
7
|
-
# host files to see if a key has already been seen for this server. If this
|
8
|
-
# server does not appear in any host file, an exception will be raised
|
9
|
-
# (HostKeyUnknown). This is in contrast to the "Strict" class, which will
|
10
|
-
# silently add the key to your known_hosts file. If the server does appear at
|
11
|
-
# least once, but the key given does not match any known for the server, an
|
12
|
-
# exception will be raised (HostKeyMismatch).
|
13
|
-
# Otherwise, this returns true.
|
14
|
-
class Secure
|
15
|
-
def verify(arguments)
|
16
|
-
options = arguments[:session].options
|
17
|
-
host = options[:host_key_alias] || arguments[:session].host_as_string
|
18
|
-
matches = Net::SSH::KnownHosts.search_for(host, arguments[:session].options)
|
19
|
-
|
20
|
-
# We've never seen this host before, so raise an exception.
|
21
|
-
if matches.empty?
|
22
|
-
process_cache_miss(host, arguments, HostKeyUnknown, "is unknown")
|
23
|
-
end
|
24
|
-
|
25
|
-
# If we found any matches, check to see that the key type and
|
26
|
-
# blob also match.
|
27
|
-
found = matches.any? do |key|
|
28
|
-
key.ssh_type == arguments[:key].ssh_type &&
|
29
|
-
key.to_blob == arguments[:key].to_blob
|
30
|
-
end
|
31
|
-
|
32
|
-
# If a match was found, return true. Otherwise, raise an exception
|
33
|
-
# indicating that the key was not recognized.
|
34
|
-
unless found
|
35
|
-
process_cache_miss(host, arguments, HostKeyMismatch, "does not match")
|
36
|
-
end
|
37
|
-
|
38
|
-
found
|
39
|
-
end
|
40
|
-
|
41
|
-
private
|
42
|
-
|
43
|
-
def process_cache_miss(host, args, exc_class, message)
|
44
|
-
exception = exc_class.new("fingerprint #{args[:fingerprint]} " +
|
45
|
-
"#{message} for #{host.inspect}")
|
46
|
-
exception.data = args
|
47
|
-
exception.callback = Proc.new do
|
48
|
-
Net::SSH::KnownHosts.add(host, args[:key], args[:session].options)
|
49
|
-
end
|
50
|
-
raise exception
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
end; end; end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
require 'net/ssh/errors'
|
2
|
-
require 'net/ssh/known_hosts'
|
3
|
-
require 'net/ssh/verifiers/secure'
|
4
|
-
|
5
|
-
module Net; module SSH; module Verifiers
|
6
|
-
|
7
|
-
# Does a strict host verification, looking the server up in the known
|
8
|
-
# host files to see if a key has already been seen for this server. If this
|
9
|
-
# server does not appear in any host file, this will silently add the
|
10
|
-
# server. If the server does appear at least once, but the key given does
|
11
|
-
# not match any known for the server, an exception will be raised (HostKeyMismatch).
|
12
|
-
# Otherwise, this returns true.
|
13
|
-
class Strict < Secure
|
14
|
-
def verify(arguments)
|
15
|
-
begin
|
16
|
-
super
|
17
|
-
rescue HostKeyUnknown => err
|
18
|
-
err.remember_host!
|
19
|
-
return true
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
end; end; end
|