class Net::SSH::Authentication::Agent

  1. lib/net/ssh/authentication/agent/socket.rb
Parent: Authentication

This class implements a simple client for the ssh-agent protocol. It does not implement any specific protocol, but instead copies the behavior of the ssh-agent functions in the OpenSSH library (3.8).

This means that although it behaves like a SSH1 client, it also has some SSH2 functionality (like signing data).

Methods

Public Class

  1. connect
  2. new

Public Instance

  1. close
  2. connect!
  3. identities
  4. negotiate!
  5. sign
  6. socket

Included modules

  1. Loggable

Constants

SSH2_AGENT_FAILURE = 30  
SSH2_AGENT_IDENTITIES_ANSWER = 12  
SSH2_AGENT_REQUEST_IDENTITIES = 11  
SSH2_AGENT_REQUEST_VERSION = 1  
SSH2_AGENT_SIGN_REQUEST = 13  
SSH2_AGENT_SIGN_RESPONSE = 14  
SSH2_AGENT_VERSION_RESPONSE = 103  
SSH_AGENT_FAILURE = 5  
SSH_AGENT_REQUEST_RSA_IDENTITIES = 1  
SSH_AGENT_RSA_IDENTITIES_ANSWER1 = 2  
SSH_AGENT_RSA_IDENTITIES_ANSWER2 = 5  
SSH_COM_AGENT2_FAILURE = 102  

Attributes

socket [R]

The underlying socket being used to communicate with the SSH agent.

Public Class methods

connect (logger=nil)

Instantiates a new agent object, connects to a running SSH agent, negotiates the agent protocol version, and returns the agent object.

[show source]
# File lib/net/ssh/authentication/agent/socket.rb, line 45
def self.connect(logger=nil)
  agent = new(logger)
  agent.connect!
  agent.negotiate!
  agent
end
new (logger=nil)

Creates a new Agent object, using the optional logger instance to report status.

[show source]
# File lib/net/ssh/authentication/agent/socket.rb, line 54
def initialize(logger=nil)
  self.logger = logger
end

Public Instance methods

close ()

Closes this socket. This agent reference is no longer able to query the agent.

[show source]
# File lib/net/ssh/authentication/agent/socket.rb, line 108
def close
  @socket.close
end
connect! ()

Connect to the agent process using the socket factory and socket name given by the attribute writers. If the agent on the other end of the socket reports that it is an SSH2-compatible agent, this will fail (it only supports the ssh-agent distributed by OpenSSH).

[show source]
# File lib/net/ssh/authentication/agent/socket.rb, line 62
def connect!
  begin
    debug { "connecting to ssh-agent" }
    @socket = agent_socket_factory.open(ENV['SSH_AUTH_SOCK'])
  rescue
    error { "could not connect to ssh-agent" }
    raise AgentNotAvailable, $!.message
  end
end
identities ()

Return an array of all identities (public keys) known to the agent. Each key returned is augmented with a comment property which is set to the comment returned by the agent for that key.

[show source]
# File lib/net/ssh/authentication/agent/socket.rb, line 90
def identities
  type, body = send_and_wait(SSH2_AGENT_REQUEST_IDENTITIES)
  raise AgentError, "could not get identity count" if agent_failed(type)
  raise AgentError, "bad authentication reply: #{type}" if type != SSH2_AGENT_IDENTITIES_ANSWER

  identities = []
  body.read_long.times do
    key = Buffer.new(body.read_string).read_key
    key.extend(Comment)
    key.comment = body.read_string
    identities.push key
  end

  return identities
end
negotiate! ()

Attempts to negotiate the SSH agent protocol version. Raises an error if the version could not be negotiated successfully.

[show source]
# File lib/net/ssh/authentication/agent/socket.rb, line 74
def negotiate!
  # determine what type of agent we're communicating with
  type, body = send_and_wait(SSH2_AGENT_REQUEST_VERSION, :string, Transport::ServerVersion::PROTO_VERSION)

  if type == SSH2_AGENT_VERSION_RESPONSE
    raise AgentNotAvailable, "SSH2 agents are not yet supported"
  elsif type == SSH2_AGENT_FAILURE
    debug { "Unexpected response type==#{type}, this will be ignored" }
  elsif type != SSH_AGENT_RSA_IDENTITIES_ANSWER1 && type != SSH_AGENT_RSA_IDENTITIES_ANSWER2
    raise AgentNotAvailable, "unknown response from agent: #{type}, #{body.to_s.inspect}"
  end
end
sign (key, data)

Using the agent and the given public key, sign the given data. The signature is returned in SSH2 format.

[show source]
# File lib/net/ssh/authentication/agent/socket.rb, line 114
def sign(key, data)
  type, reply = send_and_wait(SSH2_AGENT_SIGN_REQUEST, :string, Buffer.from(:key, key), :string, data, :long, 0)

  if agent_failed(type)
    raise AgentError, "agent could not sign data with requested identity"
  elsif type != SSH2_AGENT_SIGN_RESPONSE
    raise AgentError, "bad authentication response #{type}"
  end

  return reply.read_string
end