Skip to content

Instantly share code, notes, and snippets.

@pmeinhardt
Last active November 11, 2017 07:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pmeinhardt/8c746ebe8d7397a2a07dabb1ba7ab30c to your computer and use it in GitHub Desktop.
Save pmeinhardt/8c746ebe8d7397a2a07dabb1ba7ab30c to your computer and use it in GitHub Desktop.
# Example code for connecting to OpenSSH ssh-agent and retrieving key information,
# quickly hacked together so please excuse bad naming and style etc.
#
# This is just intended to provide a starting point
#
# http://api.libssh.org/rfc/PROTOCOL.agent
# https://github.com/paramiko/paramiko/blob/master/paramiko/agent.py
# Message constants
ssh2_agentc_request_identities = 11
ssh2_agent_identities_answer = 12
# Set up connection
address = {:local, System.get_env("SSH_AUTH_SOCK")}
sockopts = [:local, :binary, {:packet, 4}, {:active, false}]
defmodule SSHAgent do
defmodule Message do
@type t :: %__MODULE__{type: integer, data: binary}
defstruct [:type, :data]
@spec init(integer) :: Message.t
def init(type), do: init(type, <<>>)
@spec init(integer, binary) :: Message.t
def init(type, data), do: %Message{type: type, data: data}
@spec decode(binary) :: Message.t
def decode(<<type::integer-size(8), data::binary>>), do: %Message{type: type, data: data}
@spec encode(%{type: integer, data: binary}) :: binary
def encode(%{type: type, data: data}), do: <<type::integer-size(8), data::binary>>
end
defmodule Key do
defstruct [:blob, :comment]
def read_all(data, count), do: read_all(data, count, [])
def read_all(_, 0, list), do: list
def read_all(data, count, list) do
<<len1::unsigned-big-integer-size(32), rem1::binary>> = data
<<blob::binary-size(len1), rem2::binary>> = rem1
<<len2::unsigned-big-integer-size(32), rem3::binary>> = rem2
<<comment::binary-size(len2), rest::binary>> = rem3
key = %Key{blob: blob, comment: comment}
read_all(rest, count - 1, [key | list])
end
end
end
alias SSHAgent.{Key,Message}
req = Message.init(ssh2_agentc_request_identities)
with {:ok, sock} <- :gen_tcp.connect(address, 0, sockopts),
:ok <- :gen_tcp.send(sock, Message.encode(req)) do
# IO.inspect :inet.getstat(sock)
case :gen_tcp.recv(sock, 0) do
{:ok, packet} ->
with msg <- Message.decode(packet) do
case msg.type do
^ssh2_agent_identities_answer ->
<<count::integer-size(32), keydata::binary>> = msg.data
keys = Key.read_all(keydata, count)
Enum.each(keys, fn key ->
IO.puts "Comment: #{key.comment}"
IO.puts Base.encode64(key.blob)
end)
_ -> IO.puts "could not get keys from ssh-agent"
end
end
other ->
IO.inspect other
end
# IO.inspect :inet.getstat(sock)
:ok = :gen_tcp.close(sock)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment