jayniz-net-ssh 2.0.15

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.
Files changed (108) hide show
  1. data/CHANGELOG.rdoc +161 -0
  2. data/Manifest +107 -0
  3. data/README.rdoc +140 -0
  4. data/Rakefile +79 -0
  5. data/Rudyfile +110 -0
  6. data/THANKS.rdoc +16 -0
  7. data/lib/net/ssh/authentication/agent.rb +176 -0
  8. data/lib/net/ssh/authentication/constants.rb +18 -0
  9. data/lib/net/ssh/authentication/key_manager.rb +193 -0
  10. data/lib/net/ssh/authentication/methods/abstract.rb +60 -0
  11. data/lib/net/ssh/authentication/methods/hostbased.rb +71 -0
  12. data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +66 -0
  13. data/lib/net/ssh/authentication/methods/password.rb +39 -0
  14. data/lib/net/ssh/authentication/methods/publickey.rb +92 -0
  15. data/lib/net/ssh/authentication/pageant.rb +183 -0
  16. data/lib/net/ssh/authentication/session.rb +134 -0
  17. data/lib/net/ssh/buffer.rb +340 -0
  18. data/lib/net/ssh/buffered_io.rb +150 -0
  19. data/lib/net/ssh/config.rb +185 -0
  20. data/lib/net/ssh/connection/channel.rb +625 -0
  21. data/lib/net/ssh/connection/constants.rb +33 -0
  22. data/lib/net/ssh/connection/session.rb +597 -0
  23. data/lib/net/ssh/connection/term.rb +178 -0
  24. data/lib/net/ssh/errors.rb +85 -0
  25. data/lib/net/ssh/key_factory.rb +102 -0
  26. data/lib/net/ssh/known_hosts.rb +129 -0
  27. data/lib/net/ssh/loggable.rb +61 -0
  28. data/lib/net/ssh/packet.rb +102 -0
  29. data/lib/net/ssh/prompt.rb +93 -0
  30. data/lib/net/ssh/proxy/errors.rb +14 -0
  31. data/lib/net/ssh/proxy/http.rb +94 -0
  32. data/lib/net/ssh/proxy/socks4.rb +70 -0
  33. data/lib/net/ssh/proxy/socks5.rb +142 -0
  34. data/lib/net/ssh/ruby_compat.rb +43 -0
  35. data/lib/net/ssh/service/forward.rb +267 -0
  36. data/lib/net/ssh/test/channel.rb +129 -0
  37. data/lib/net/ssh/test/extensions.rb +152 -0
  38. data/lib/net/ssh/test/kex.rb +44 -0
  39. data/lib/net/ssh/test/local_packet.rb +51 -0
  40. data/lib/net/ssh/test/packet.rb +81 -0
  41. data/lib/net/ssh/test/remote_packet.rb +38 -0
  42. data/lib/net/ssh/test/script.rb +157 -0
  43. data/lib/net/ssh/test/socket.rb +59 -0
  44. data/lib/net/ssh/test.rb +89 -0
  45. data/lib/net/ssh/transport/algorithms.rb +384 -0
  46. data/lib/net/ssh/transport/cipher_factory.rb +97 -0
  47. data/lib/net/ssh/transport/constants.rb +30 -0
  48. data/lib/net/ssh/transport/hmac/abstract.rb +79 -0
  49. data/lib/net/ssh/transport/hmac/md5.rb +12 -0
  50. data/lib/net/ssh/transport/hmac/md5_96.rb +11 -0
  51. data/lib/net/ssh/transport/hmac/none.rb +15 -0
  52. data/lib/net/ssh/transport/hmac/sha1.rb +13 -0
  53. data/lib/net/ssh/transport/hmac/sha1_96.rb +11 -0
  54. data/lib/net/ssh/transport/hmac.rb +31 -0
  55. data/lib/net/ssh/transport/identity_cipher.rb +55 -0
  56. data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +208 -0
  57. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +77 -0
  58. data/lib/net/ssh/transport/kex.rb +13 -0
  59. data/lib/net/ssh/transport/openssl.rb +128 -0
  60. data/lib/net/ssh/transport/packet_stream.rb +232 -0
  61. data/lib/net/ssh/transport/server_version.rb +70 -0
  62. data/lib/net/ssh/transport/session.rb +276 -0
  63. data/lib/net/ssh/transport/state.rb +206 -0
  64. data/lib/net/ssh/verifiers/lenient.rb +30 -0
  65. data/lib/net/ssh/verifiers/null.rb +12 -0
  66. data/lib/net/ssh/verifiers/strict.rb +53 -0
  67. data/lib/net/ssh/version.rb +62 -0
  68. data/lib/net/ssh.rb +215 -0
  69. data/net-ssh.gemspec +131 -0
  70. data/setup.rb +1585 -0
  71. data/support/arcfour_check.rb +20 -0
  72. data/test/authentication/methods/common.rb +28 -0
  73. data/test/authentication/methods/test_abstract.rb +51 -0
  74. data/test/authentication/methods/test_hostbased.rb +114 -0
  75. data/test/authentication/methods/test_keyboard_interactive.rb +98 -0
  76. data/test/authentication/methods/test_password.rb +50 -0
  77. data/test/authentication/methods/test_publickey.rb +127 -0
  78. data/test/authentication/test_agent.rb +205 -0
  79. data/test/authentication/test_key_manager.rb +105 -0
  80. data/test/authentication/test_session.rb +93 -0
  81. data/test/common.rb +107 -0
  82. data/test/configs/eqsign +3 -0
  83. data/test/configs/exact_match +8 -0
  84. data/test/configs/multihost +4 -0
  85. data/test/configs/wild_cards +14 -0
  86. data/test/connection/test_channel.rb +452 -0
  87. data/test/connection/test_session.rb +488 -0
  88. data/test/test_all.rb +8 -0
  89. data/test/test_buffer.rb +336 -0
  90. data/test/test_buffered_io.rb +63 -0
  91. data/test/test_config.rb +99 -0
  92. data/test/test_key_factory.rb +67 -0
  93. data/test/transport/hmac/test_md5.rb +39 -0
  94. data/test/transport/hmac/test_md5_96.rb +25 -0
  95. data/test/transport/hmac/test_none.rb +34 -0
  96. data/test/transport/hmac/test_sha1.rb +34 -0
  97. data/test/transport/hmac/test_sha1_96.rb +25 -0
  98. data/test/transport/kex/test_diffie_hellman_group1_sha1.rb +146 -0
  99. data/test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb +92 -0
  100. data/test/transport/test_algorithms.rb +302 -0
  101. data/test/transport/test_cipher_factory.rb +213 -0
  102. data/test/transport/test_hmac.rb +34 -0
  103. data/test/transport/test_identity_cipher.rb +40 -0
  104. data/test/transport/test_packet_stream.rb +441 -0
  105. data/test/transport/test_server_version.rb +68 -0
  106. data/test/transport/test_session.rb +315 -0
  107. data/test/transport/test_state.rb +173 -0
  108. metadata +168 -0
data/Rudyfile ADDED
@@ -0,0 +1,110 @@
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_rubyforge do
56
+ remote :root do
57
+ gem_install 'net-ssh', '--version', '2.0.7'
58
+ gem_install 'net-ssh'
59
+ end
60
+ end
61
+
62
+ install_github do
63
+ remote :root do
64
+ gem_sources :a, "http://gems.github.com"
65
+ gem_install 'net-ssh-net-ssh'
66
+ end
67
+ end
68
+
69
+ install_gem do
70
+ before :package_gem
71
+ remote :root do
72
+ disable_safe_mode
73
+ file_upload "pkg/net-ssh-*.gem", "/tmp/"
74
+ gem_install "/tmp/net-ssh-*.gem"
75
+ end
76
+ end
77
+
78
+ package_gem do
79
+ local do
80
+ rm :r, :f, 'pkg'
81
+ rake 'package'
82
+ end
83
+ end
84
+
85
+ remove do
86
+ remote :root do
87
+ gem_uninstall 'net-ssh'
88
+ end
89
+ end
90
+
91
+ installdeps do
92
+ remote :root do
93
+ gem_install "rye", "test-unit", "mocha"
94
+ rye 'authorize-local'
95
+ end
96
+ end
97
+
98
+ sysupdate do
99
+ remote :root do
100
+ apt_get "update"
101
+ apt_get "install", "build-essential", "git-core"
102
+ apt_get "install", "ruby1.8-dev", "rdoc", "libzlib-ruby", "rubygems"
103
+ mkdir :p, "/var/lib/gems/1.8/bin" # Doesn't get created, but causes Rubygems to fail
104
+ gem_install "builder", "session"
105
+ gem_install 'rubygems-update', "-v=1.3.4" # circular issue with 1.3.5 and hoe
106
+ update_rubygems
107
+ end
108
+ end
109
+ end
110
+
data/THANKS.rdoc ADDED
@@ -0,0 +1,16 @@
1
+ Net::SSH was originally written by Jamis Buck <jamis@37signals.com>. In
2
+ addition, the following individuals are gratefully acknowledged for their
3
+ contributions:
4
+
5
+ GOTOU Yuuzou <gotoyuzo@notwork.org>
6
+ * help and code related to OpenSSL
7
+
8
+ Guillaume Mar�ais <guillaume.marcais@free.fr>
9
+ * support for communicating with the the PuTTY "pageant" process
10
+
11
+ Daniel Berger <djberg96@yahoo.com>
12
+ * help getting unit tests in earlier Net::SSH versions to pass in Windows
13
+ * initial version of Net::SSH::Config provided inspiration and encouragement
14
+
15
+ Chris Andrews <chris@nodnol.org> and Lee Jensen <lee@outerim.com>
16
+ * support for ssh agent forwarding
@@ -0,0 +1,176 @@
1
+ require 'net/ssh/buffer'
2
+ require 'net/ssh/errors'
3
+ require 'net/ssh/loggable'
4
+ require 'net/ssh/transport/server_version'
5
+
6
+ require 'net/ssh/authentication/pageant' if File::ALT_SEPARATOR && !(RUBY_PLATFORM =~ /java/)
7
+
8
+ module Net; module SSH; module Authentication
9
+
10
+ # A trivial exception class for representing agent-specific errors.
11
+ class AgentError < Net::SSH::Exception; end
12
+
13
+ # An exception for indicating that the SSH agent is not available.
14
+ class AgentNotAvailable < AgentError; end
15
+
16
+ # This class implements a simple client for the ssh-agent protocol. It
17
+ # does not implement any specific protocol, but instead copies the
18
+ # behavior of the ssh-agent functions in the OpenSSH library (3.8).
19
+ #
20
+ # This means that although it behaves like a SSH1 client, it also has
21
+ # some SSH2 functionality (like signing data).
22
+ class Agent
23
+ include Loggable
24
+
25
+ # A simple module for extending keys, to allow comments to be specified
26
+ # for them.
27
+ module Comment
28
+ attr_accessor :comment
29
+ end
30
+
31
+ SSH2_AGENT_REQUEST_VERSION = 1
32
+ SSH2_AGENT_REQUEST_IDENTITIES = 11
33
+ SSH2_AGENT_IDENTITIES_ANSWER = 12
34
+ SSH2_AGENT_SIGN_REQUEST = 13
35
+ SSH2_AGENT_SIGN_RESPONSE = 14
36
+ SSH2_AGENT_FAILURE = 30
37
+ SSH2_AGENT_VERSION_RESPONSE = 103
38
+
39
+ SSH_COM_AGENT2_FAILURE = 102
40
+
41
+ SSH_AGENT_REQUEST_RSA_IDENTITIES = 1
42
+ SSH_AGENT_RSA_IDENTITIES_ANSWER1 = 2
43
+ SSH_AGENT_RSA_IDENTITIES_ANSWER2 = 5
44
+ SSH_AGENT_FAILURE = 5
45
+
46
+ # The underlying socket being used to communicate with the SSH agent.
47
+ attr_reader :socket
48
+
49
+ # Instantiates a new agent object, connects to a running SSH agent,
50
+ # negotiates the agent protocol version, and returns the agent object.
51
+ def self.connect(logger=nil)
52
+ agent = new(logger)
53
+ agent.connect!
54
+ agent.negotiate!
55
+ agent
56
+ end
57
+
58
+ # Creates a new Agent object, using the optional logger instance to
59
+ # report status.
60
+ def initialize(logger=nil)
61
+ self.logger = logger
62
+ end
63
+
64
+ # Connect to the agent process using the socket factory and socket name
65
+ # given by the attribute writers. If the agent on the other end of the
66
+ # socket reports that it is an SSH2-compatible agent, this will fail
67
+ # (it only supports the ssh-agent distributed by OpenSSH).
68
+ def connect!
69
+ begin
70
+ debug { "connecting to ssh-agent" }
71
+ @socket = agent_socket_factory.open(ENV['SSH_AUTH_SOCK'])
72
+ rescue
73
+ error { "could not connect to ssh-agent" }
74
+ raise AgentNotAvailable, $!.message
75
+ end
76
+ end
77
+
78
+ # Attempts to negotiate the SSH agent protocol version. Raises an error
79
+ # if the version could not be negotiated successfully.
80
+ def negotiate!
81
+ # determine what type of agent we're communicating with
82
+ type, body = send_and_wait(SSH2_AGENT_REQUEST_VERSION, :string, Transport::ServerVersion::PROTO_VERSION)
83
+
84
+ if type == SSH2_AGENT_VERSION_RESPONSE
85
+ raise NotImplementedError, "SSH2 agents are not yet supported"
86
+ elsif type != SSH_AGENT_RSA_IDENTITIES_ANSWER1 && type != SSH_AGENT_RSA_IDENTITIES_ANSWER2
87
+ raise AgentError, "unknown response from agent: #{type}, #{body.to_s.inspect}"
88
+ end
89
+ end
90
+
91
+ # Return an array of all identities (public keys) known to the agent.
92
+ # Each key returned is augmented with a +comment+ property which is set
93
+ # to the comment returned by the agent for that key.
94
+ def identities
95
+ type, body = send_and_wait(SSH2_AGENT_REQUEST_IDENTITIES)
96
+ raise AgentError, "could not get identity count" if agent_failed(type)
97
+ raise AgentError, "bad authentication reply: #{type}" if type != SSH2_AGENT_IDENTITIES_ANSWER
98
+
99
+ identities = []
100
+ body.read_long.times do
101
+ key = Buffer.new(body.read_string).read_key
102
+ key.extend(Comment)
103
+ key.comment = body.read_string
104
+ identities.push key
105
+ end
106
+
107
+ return identities
108
+ end
109
+
110
+ # Closes this socket. This agent reference is no longer able to
111
+ # query the agent.
112
+ def close
113
+ @socket.close
114
+ end
115
+
116
+ # Using the agent and the given public key, sign the given data. The
117
+ # signature is returned in SSH2 format.
118
+ def sign(key, data)
119
+ type, reply = send_and_wait(SSH2_AGENT_SIGN_REQUEST, :string, Buffer.from(:key, key), :string, data, :long, 0)
120
+
121
+ if agent_failed(type)
122
+ raise AgentError, "agent could not sign data with requested identity"
123
+ elsif type != SSH2_AGENT_SIGN_RESPONSE
124
+ raise AgentError, "bad authentication response #{type}"
125
+ end
126
+
127
+ return reply.read_string
128
+ end
129
+
130
+ private
131
+
132
+ # Returns the agent socket factory to use.
133
+ def agent_socket_factory
134
+ if File::ALT_SEPARATOR
135
+ Pageant::Socket
136
+ else
137
+ UNIXSocket
138
+ end
139
+ end
140
+
141
+ # Send a new packet of the given type, with the associated data.
142
+ def send_packet(type, *args)
143
+ buffer = Buffer.from(*args)
144
+ data = [buffer.length + 1, type.to_i, buffer.to_s].pack("NCA*")
145
+ debug { "sending agent request #{type} len #{buffer.length}" }
146
+ @socket.send data, 0
147
+ end
148
+
149
+ # Read the next packet from the agent. This will return a two-part
150
+ # tuple consisting of the packet type, and the packet's body (which
151
+ # is returned as a Net::SSH::Buffer).
152
+ def read_packet
153
+ buffer = Net::SSH::Buffer.new(@socket.read(4))
154
+ buffer.append(@socket.read(buffer.read_long))
155
+ type = buffer.read_byte
156
+ debug { "received agent packet #{type} len #{buffer.length-4}" }
157
+ return type, buffer
158
+ end
159
+
160
+ # Send the given packet and return the subsequent reply from the agent.
161
+ # (See #send_packet and #read_packet).
162
+ def send_and_wait(type, *args)
163
+ send_packet(type, *args)
164
+ read_packet
165
+ end
166
+
167
+ # Returns +true+ if the parameter indicates a "failure" response from
168
+ # the agent, and +false+ otherwise.
169
+ def agent_failed(type)
170
+ type == SSH_AGENT_FAILURE ||
171
+ type == SSH2_AGENT_FAILURE ||
172
+ type == SSH_COM_AGENT2_FAILURE
173
+ end
174
+ end
175
+
176
+ end; end; end
@@ -0,0 +1,18 @@
1
+ module Net; module SSH; module Authentication
2
+
3
+ # Describes the constants used by the Net::SSH::Authentication components
4
+ # of the Net::SSH library. Individual authentication method implemenations
5
+ # may define yet more constants that are specific to their implementation.
6
+ module Constants
7
+ USERAUTH_REQUEST = 50
8
+ USERAUTH_FAILURE = 51
9
+ USERAUTH_SUCCESS = 52
10
+ USERAUTH_BANNER = 53
11
+
12
+ USERAUTH_PASSWD_CHANGEREQ = 60
13
+ USERAUTH_PK_OK = 60
14
+
15
+ USERAUTH_METHOD_RANGE = 60..79
16
+ end
17
+
18
+ end; end; end
@@ -0,0 +1,193 @@
1
+ require 'net/ssh/errors'
2
+ require 'net/ssh/key_factory'
3
+ require 'net/ssh/loggable'
4
+ require 'net/ssh/authentication/agent'
5
+
6
+ module Net
7
+ module SSH
8
+ module Authentication
9
+
10
+ # A trivial exception class used to report errors in the key manager.
11
+ class KeyManagerError < Net::SSH::Exception; end
12
+
13
+ # This class encapsulates all operations done by clients on a user's
14
+ # private keys. In practice, the client should never need a reference
15
+ # to a private key; instead, they grab a list of "identities" (public
16
+ # keys) that are available from the KeyManager, and then use
17
+ # the KeyManager to do various private key operations using those
18
+ # identities.
19
+ #
20
+ # The KeyManager also uses the Agent class to encapsulate the
21
+ # ssh-agent. Thus, from a client's perspective it is completely
22
+ # hidden whether an identity comes from the ssh-agent or from a file
23
+ # on disk.
24
+ class KeyManager
25
+ include Loggable
26
+
27
+ # The list of user key files that will be examined
28
+ attr_reader :key_files
29
+
30
+ # The list of user key data that will be examined
31
+ attr_reader :key_data
32
+
33
+ # The map of loaded identities
34
+ attr_reader :known_identities
35
+
36
+ # The map of options that were passed to the key-manager
37
+ attr_reader :options
38
+
39
+ # Create a new KeyManager. By default, the manager will
40
+ # use the ssh-agent (if it is running).
41
+ def initialize(logger, options={})
42
+ self.logger = logger
43
+ @key_files = []
44
+ @key_data = []
45
+ @use_agent = true
46
+ @known_identities = {}
47
+ @agent = nil
48
+ @options = options
49
+ end
50
+
51
+ # Clear all knowledge of any loaded user keys. This also clears the list
52
+ # of default identity files that are to be loaded, thus making it
53
+ # appropriate to use if a client wishes to NOT use the default identity
54
+ # files.
55
+ def clear!
56
+ key_files.clear
57
+ key_data.clear
58
+ known_identities.clear
59
+ self
60
+ end
61
+
62
+ # Add the given key_file to the list of key files that will be used.
63
+ def add(key_file)
64
+ key_files.push(File.expand_path(key_file)).uniq!
65
+ self
66
+ end
67
+
68
+ # Add the given key_file to the list of keys that will be used.
69
+ def add_key_data(key_data_)
70
+ key_data.push(key_data_).uniq!
71
+ self
72
+ end
73
+
74
+ # This is used as a hint to the KeyManager indicating that the agent
75
+ # connection is no longer needed. Any other open resources may be closed
76
+ # at this time.
77
+ #
78
+ # Calling this does NOT indicate that the KeyManager will no longer
79
+ # be used. Identities may still be requested and operations done on
80
+ # loaded identities, in which case, the agent will be automatically
81
+ # reconnected. This method simply allows the client connection to be
82
+ # closed when it will not be used in the immediate future.
83
+ def finish
84
+ @agent.close if @agent
85
+ @agent = nil
86
+ end
87
+
88
+ # Iterates over all available identities (public keys) known to this
89
+ # manager. As it finds one, it will then yield it to the caller.
90
+ # The origin of the identities may be from files on disk or from an
91
+ # ssh-agent. Note that identities from an ssh-agent are always listed
92
+ # first in the array, with other identities coming after.
93
+ def each_identity
94
+ if agent
95
+ agent.identities.each do |key|
96
+ known_identities[key] = { :from => :agent }
97
+ yield key
98
+ end
99
+ end
100
+
101
+ key_files.each do |file|
102
+ public_key_file = file + ".pub"
103
+ if File.readable?(public_key_file)
104
+ begin
105
+ key = KeyFactory.load_public_key(public_key_file)
106
+ known_identities[key] = { :from => :file, :file => file }
107
+ yield key
108
+ rescue Exception => e
109
+ error { "could not load public key file `#{public_key_file}': #{e.class} (#{e.message})" }
110
+ end
111
+ elsif File.readable?(file)
112
+ begin
113
+ private_key = KeyFactory.load_private_key(file, options[:passphrase])
114
+ key = private_key.send(:public_key)
115
+ known_identities[key] = { :from => :file, :file => file, :key => private_key }
116
+ yield key
117
+ rescue Exception => e
118
+ error { "could not load private key file `#{file}': #{e.class} (#{e.message})" }
119
+ end
120
+ end
121
+ end
122
+
123
+ key_data.each do |data|
124
+ private_key = KeyFactory.load_data_private_key(data)
125
+ key = private_key.send(:public_key)
126
+ known_identities[key] = { :from => :key_data, :data => data, :key => private_key }
127
+ yield key
128
+ end
129
+
130
+ self
131
+ end
132
+
133
+ # Sign the given data, using the corresponding private key of the given
134
+ # identity. If the identity was originally obtained from an ssh-agent,
135
+ # then the ssh-agent will be used to sign the data, otherwise the
136
+ # private key for the identity will be loaded from disk (if it hasn't
137
+ # been loaded already) and will then be used to sign the data.
138
+ #
139
+ # Regardless of the identity's origin or who does the signing, this
140
+ # will always return the signature in an SSH2-specified "signature
141
+ # blob" format.
142
+ def sign(identity, data)
143
+ info = known_identities[identity] or raise KeyManagerError, "the given identity is unknown to the key manager"
144
+
145
+ if info[:key].nil? && info[:from] == :file
146
+ begin
147
+ info[:key] = KeyFactory.load_private_key(info[:file], options[:passphrase])
148
+ rescue Exception => e
149
+ raise KeyManagerError, "the given identity is known, but the private key could not be loaded: #{e.class} (#{e.message})"
150
+ end
151
+ end
152
+
153
+ if info[:key]
154
+ return Net::SSH::Buffer.from(:string, identity.ssh_type,
155
+ :string, info[:key].ssh_do_sign(data.to_s)).to_s
156
+ end
157
+
158
+ if info[:from] == :agent
159
+ raise KeyManagerError, "the agent is no longer available" unless agent
160
+ return agent.sign(identity, data.to_s)
161
+ end
162
+
163
+ raise KeyManagerError, "[BUG] can't determine identity origin (#{info.inspect})"
164
+ end
165
+
166
+ # Identifies whether the ssh-agent will be used or not.
167
+ def use_agent?
168
+ @use_agent
169
+ end
170
+
171
+ # Toggles whether the ssh-agent will be used or not. If true, an
172
+ # attempt will be made to use the ssh-agent. If false, any existing
173
+ # connection to an agent is closed and the agent will not be used.
174
+ def use_agent=(use_agent)
175
+ finish if !use_agent
176
+ @use_agent = use_agent
177
+ end
178
+
179
+ # Returns an Agent instance to use for communicating with an SSH
180
+ # agent process. Returns nil if use of an SSH agent has been disabled,
181
+ # or if the agent is otherwise not available.
182
+ def agent
183
+ return unless use_agent?
184
+ @agent ||= Agent.connect(logger)
185
+ rescue AgentNotAvailable
186
+ @use_agent = false
187
+ nil
188
+ end
189
+ end
190
+
191
+ end
192
+ end
193
+ end