Class: SshTresor::Agent
- Inherits:
-
Object
- Object
- SshTresor::Agent
- Defined in:
- lib/ssh_tresor/agent.rb
Constant Summary collapse
- SSH_AGENT_FAILURE =
5- SSH_AGENTC_REQUEST_IDENTITIES =
11- SSH_AGENT_IDENTITIES_ANSWER =
12- SSH_AGENTC_SIGN_REQUEST =
13- SSH_AGENT_SIGN_RESPONSE =
14- SSH_AGENT_SIGN_REQUEST_RSA_SHA2_256 =
2
Class Method Summary collapse
Instance Method Summary collapse
- #find_key(fingerprint) ⇒ Object
- #find_key_by_fingerprint_bytes(fingerprint_bytes) ⇒ Object
- #first_key ⇒ Object
-
#initialize(socket) ⇒ Agent
constructor
A new instance of Agent.
- #list_keys ⇒ Object
- #sign(key, data) ⇒ Object
Constructor Details
#initialize(socket) ⇒ Agent
Returns a new instance of Agent.
96 97 98 |
# File 'lib/ssh_tresor/agent.rb', line 96 def initialize(socket) @socket = socket end |
Class Method Details
.bit_length(bytes) ⇒ Object
89 90 91 92 93 94 |
# File 'lib/ssh_tresor/agent.rb', line 89 def self.bit_length(bytes) trimmed = bytes.b.sub(/\A\x00+/n, "") return 0 if trimmed.empty? ((trimmed.bytesize - 1) * 8) + trimmed.getbyte(0).bit_length end |
.connect ⇒ Object
55 56 57 58 59 60 61 62 |
# File 'lib/ssh_tresor/agent.rb', line 55 def self.connect socket_path = ENV["SSH_AUTH_SOCK"] raise AgentError, "SSH agent not available\nHint: Is SSH_AUTH_SOCK set? Try running: eval $(ssh-agent) && ssh-add" if socket_path.nil? || socket_path.empty? new(UNIXSocket.new(socket_path)) rescue SystemCallError => e raise AgentError, "Failed to connect to SSH agent: #{e.}" end |
.format_key_type(blob) ⇒ Object
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/ssh_tresor/agent.rb', line 64 def self.format_key_type(blob) reader = SSHEncoding::Reader.new(blob) type = reader.string case type when "ssh-ed25519" "ED25519" when "ssh-rsa" reader.string n = reader.string "RSA-#{bit_length(n)}" when /\Aecdsa-sha2-/ curve = reader.string "ECDSA-#{curve.delete_prefix("nistp")}" when "sk-ssh-ed25519@openssh.com" "SK-ED25519" when "sk-ecdsa-sha2-nistp256@openssh.com" "SK-ECDSA-256" else type.upcase end rescue Error "UNKNOWN" end |
Instance Method Details
#find_key(fingerprint) ⇒ Object
120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/ssh_tresor/agent.rb', line 120 def find_key(fingerprint) matches = list_keys.select { |key| key.matches_fingerprint?(fingerprint) } case matches.length when 0 raise KeyNotFound, "Key not found: #{fingerprint}\nHint: Use 'ssh-tresor list-keys' to see available keys" when 1 matches.first else raise KeyNotFound, "Key not found: #{fingerprint} (ambiguous: #{matches.length} keys match this prefix, please be more specific)" end end |
#find_key_by_fingerprint_bytes(fingerprint_bytes) ⇒ Object
133 134 135 136 |
# File 'lib/ssh_tresor/agent.rb', line 133 def find_key_by_fingerprint_bytes(fingerprint_bytes) list_keys.find { |key| key.fingerprint_bytes == fingerprint_bytes } || raise(KeyNotFound, "Key not found: SHA256:#{Base64.strict_encode64(fingerprint_bytes).delete("=")}") end |
#first_key ⇒ Object
116 117 118 |
# File 'lib/ssh_tresor/agent.rb', line 116 def first_key list_keys.first || raise(KeyNotFound, "No keys available in SSH agent\nHint: Try running: ssh-add") end |
#list_keys ⇒ Object
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/ssh_tresor/agent.rb', line 100 def list_keys response = request(SSHEncoding.byte(SSH_AGENTC_REQUEST_IDENTITIES)) reader = SSHEncoding::Reader.new(response) type = reader.byte raise AgentError, "SSH agent refused identity request" if type == SSH_AGENT_FAILURE raise AgentError, "Unexpected SSH agent response type #{type}" unless type == SSH_AGENT_IDENTITIES_ANSWER count = reader.uint32 Array.new(count) do blob = reader.string comment = reader.string.force_encoding(Encoding::UTF_8) comment = comment.valid_encoding? ? comment : comment.b.inspect AgentKey.new(blob: blob, comment: comment) end end |
#sign(key, data) ⇒ Object
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/ssh_tresor/agent.rb', line 138 def sign(key, data) flags = key.ssh_type == "ssh-rsa" ? SSH_AGENT_SIGN_REQUEST_RSA_SHA2_256 : 0 payload = SSHEncoding.byte(SSH_AGENTC_SIGN_REQUEST) + SSHEncoding.string(key.blob) + SSHEncoding.string(data) + SSHEncoding.uint32(flags) response = request(payload) reader = SSHEncoding::Reader.new(response) type = reader.byte raise AgentError, "SSH agent refused signing request" if type == SSH_AGENT_FAILURE raise AgentError, "Unexpected SSH agent response type #{type}" unless type == SSH_AGENT_SIGN_RESPONSE signature_blob = reader.string signature_reader = SSHEncoding::Reader.new(signature_blob) signature_reader.string signature_reader.string end |