summaryrefslogtreecommitdiff
path: root/sshagent.py
diff options
context:
space:
mode:
Diffstat (limited to 'sshagent.py')
-rw-r--r--sshagent.py75
1 files changed, 75 insertions, 0 deletions
diff --git a/sshagent.py b/sshagent.py
new file mode 100644
index 0000000..2a43f5f
--- /dev/null
+++ b/sshagent.py
@@ -0,0 +1,75 @@
1# vim: set filencoding=utf8
2"""
3SSH Agent Management
4
5@author: Mike Crute (mcrute@gmail.com)
6@organization: SoftGroup Interactive, Inc.
7@date: May 05, 2010
8"""
9import os
10import socket
11import struct
12
13from structutils import pack_string, pack_int
14from structutils import unpack_int, unpack_string, unpack_mp_int
15
16
17class SSHAgent(object):
18 """
19 SSH Agent communication protocol for signing only.
20 """
21
22 SSH2_AGENT_SIGN_RESPONSE = 14
23 SSH2_AGENTC_SIGN_REQUEST = 13
24
25 def __init__(self, socket_path):
26 default_path = os.environ.get('SSH_AUTH_SOCK')
27 socket_path = default_path if not socket_path else socket_path
28
29 if not socket_path:
30 raise ValueError("Could not find an ssh agent.")
31
32 self.socket = None
33
34 def connect(self):
35 self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
36 self.socket.connect(self.socket_path)
37
38 def _build_packet(self, data, key):
39 key = pack_string(key)
40 data = pack_string(data)
41 flags = pack_int(0)
42
43 to_send = ''.join([chr(SSHAgent.SSH2_AGENTC_SIGN_REQUEST),
44 key, data, flags])
45 pkt_length = len(to_send)
46 packet = pack_int(pkg_length) + to_send
47
48 return packet
49
50 def _parse_response(self):
51 response_length = unpack_int(self.socket.recv(4, socket.MSG_WAITALL))[0]
52 if response_length == 1:
53 raise ValueError("Agent failed")
54
55 response = auth_sock.recv(response_length, socket.MSG_WAITALL)
56
57 status = ord(response[0])
58 if status != SSHAgent.SSH2_AGENT_SIGN_RESPONSE:
59 raise ValueError("Invalid response from agent")
60
61 _, remainder = unpack_int(response[1:])
62 _, remainder = unpack_string(remainder)
63 response, _ = unpack_mp_int(remainder)
64
65 return response
66
67 def sign(self, data, key):
68 packet = self._build_packet(data, key)
69
70 remaining = 0
71 while remaining < len(packet):
72 sent = self.socket.send(packet[remaining:])
73 remaining += sent
74
75 return self._parse_response()