Skip to content

Commit b0e2e17

Browse files
committedDec 3, 2018
read_agentproto_idcomments() to read loaded IDs from an SSH agent
This will be used to query an agent for the loaded keys so that we don't try to reload ones that are already there.
1 parent 6db0114 commit b0e2e17

File tree

2 files changed

+98
-1
lines changed

2 files changed

+98
-1
lines changed
 

‎bin/ckssh.py

+50
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#!/usr/bin/env python3
22

33
from argparse import ArgumentParser
4+
from binascii import hexlify
45
from collections import namedtuple as ntup
56
from os import path
67
from pathlib import Path
@@ -13,6 +14,55 @@
1314
CONFIG_FILE = '~/.ssh/ckssh_config'
1415
DEVNULL = open(os.devnull, 'w')
1516

17+
############################################################
18+
# SSH agent protocol functions
19+
20+
class SSHAgentProtoError(RuntimeError):
21+
pass
22+
23+
def read_agentproto_int(stream, length):
24+
bs = stream.read(length)
25+
if len(bs) != length:
26+
raise SSHAgentProtoError('Short int: {}'.format(bs))
27+
return int.from_bytes(bs, byteorder='big')
28+
29+
def read_agentproto_bstr(stream):
30+
length = read_agentproto_int(stream, 4)
31+
bs = stream.read(length)
32+
if len(bs) != length:
33+
raise SSHAgentProtoError('Short string: {}'.format(bs))
34+
return bs
35+
36+
def read_agentproto_idcomments(stream):
37+
''' From the given I/O stream, Read and parse an
38+
``SSH2_AGENT_IDENTITIES_ANSWER`` response to an
39+
``SSH2_AGENTC_REQUEST_IDENTITIES`` request.
40+
Return a list with the comment for each identity.
41+
42+
For protocol details see section 2.5.2 of
43+
<http://api.libssh.org/rfc/PROTOCOL.agent>.
44+
'''
45+
# We don't actually use the message length, instead relying on
46+
# the count of keys and string lengths, but we parse it to make
47+
# sure this isn't a bad message.
48+
msglen = read_agentproto_int(stream, 4)
49+
50+
msgtype = read_agentproto_int(stream, 1)
51+
if msgtype != 0xC:
52+
raise SSHAgentProtoError(
53+
'Unknown message type: {}'.format(msgtype))
54+
55+
keycount = read_agentproto_int(stream, 4)
56+
comments = []
57+
for i in range(0, keycount):
58+
read_agentproto_bstr(stream) # key blob
59+
bs = read_agentproto_bstr(stream) # key comment
60+
comments.append(bs.decode('ascii'))
61+
return comments
62+
63+
raise SSHAgentProtoError()
64+
return []
65+
1666
############################################################
1767
# Compartment classes and functions
1868

‎t/unit.py

+48-1
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,59 @@
1-
from io import StringIO
1+
from io import BytesIO, StringIO
2+
from binascii import unhexlify
23
from pathlib import Path
34
import pytest
45

56
import ckssh
67
from ckssh import (
8+
SSHAgentProtoError, read_agentproto_idcomments,
79
runtimedir, Compartment, parseconfig, canexec, evalwrite, CK,
810
)
911

12+
####################################################################
13+
# SSH agent protocol
14+
15+
def test_ssh2_ids_answer_decode_0():
16+
answer0 = (
17+
0, 0, 0, 5, # message length
18+
0xC, # SSH2_AGENT_IDENTITIES_ANSWER
19+
0, 0, 0, 0, # identities count: 0
20+
)
21+
assert [] == read_agentproto_idcomments(BytesIO(bytes(answer0)))
22+
23+
def test_ssh2_ids_answer_decode_2():
24+
answer2 = (
25+
b''
26+
b'\0\0\0\5' # message length
27+
b'\x0C' # SSH2_AGENT_IDENTITIES_ANSWER
28+
b'\0\0\0\2' # identities count: 2
29+
30+
b'\0\0\0\1' # 1st answer blob length: 1
31+
b'\x7E'
32+
b'\0\0\0\3' # 1st answer comment length: 3
33+
b'foo'
34+
35+
b'\0\0\0\0' # 2nd answer blob length: 0
36+
b''
37+
b'\0\0\0\7' # 2nd answer comment length: 7
38+
b'bar baz'
39+
)
40+
assert ['foo', 'bar baz'] \
41+
== read_agentproto_idcomments(BytesIO(bytes(answer2)))
42+
43+
@pytest.mark.parametrize('badmsg', (
44+
'',
45+
'00000001', # no response type
46+
'0000000102', # bad response type
47+
'000000020C', # bad length
48+
))
49+
def test_ssh2_ids_answer_decode_err(badmsg):
50+
bs = unhexlify(badmsg) # Convert printable test param to bytes
51+
with pytest.raises(SSHAgentProtoError):
52+
read_agentproto_idcomments(BytesIO(bs))
53+
54+
####################################################################
55+
# ckssh stuff
56+
1057
TESTDIR = Path(__file__).parent
1158
CONFIGFILE = Path(TESTDIR, 'mock_home/.ssh/ckssh_config')
1259

0 commit comments

Comments
 (0)
Please sign in to comment.