Merge lp:~cjwatson/lazr.sshserver/work-around-short-paramiko-signatures into lp:lazr.sshserver

Proposed by Colin Watson
Status: Merged
Merged at revision: 67
Proposed branch: lp:~cjwatson/lazr.sshserver/work-around-short-paramiko-signatures
Merge into: lp:lazr.sshserver
Diff against target: 80 lines (+48/-0)
3 files modified
src/lazr/sshserver/NEWS.txt (+9/-0)
src/lazr/sshserver/auth.py (+10/-0)
src/lazr/sshserver/tests/test_auth.py (+29/-0)
To merge this branch: bzr merge lp:~cjwatson/lazr.sshserver/work-around-short-paramiko-signatures
Reviewer Review Type Date Requested Status
William Grant code Approve
Review via email: mp+335515@code.launchpad.net

Commit message

Work around RSA signature truncation bug in paramiko < 2.0.0.

To post a comment you must log in.
Revision history for this message
William Grant (wgrant) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/lazr/sshserver/NEWS.txt'
2--- src/lazr/sshserver/NEWS.txt 2015-11-29 12:33:03 +0000
3+++ src/lazr/sshserver/NEWS.txt 2017-12-21 11:41:35 +0000
4@@ -2,6 +2,15 @@
5 NEWS for lazr.sshserver
6 =======================
7
8+0.1.5
9+=====
10+
11+- Work around a bug in paramiko < 2.0.0: if the most significant byte of an
12+ RSA signature is zero, then it strips leading zero bytes rather than
13+ zero-padding it to the correct length. This previously caused sporadic
14+ failures when running with Twisted >= 16.0.0, since cryptography is
15+ pickier about this than PyCrypto was.
16+
17 0.1.4 (2015-11-29)
18 ==================
19
20
21=== modified file 'src/lazr/sshserver/auth.py'
22--- src/lazr/sshserver/auth.py 2017-12-21 11:04:23 +0000
23+++ src/lazr/sshserver/auth.py 2017-12-21 11:41:35 +0000
24@@ -244,6 +244,16 @@
25 algName, blob, rest = getNS(packet[1:], 2)
26 pubKey = keys.Key.fromString(blob).keyObject
27 signature = hasSig and getNS(rest)[0] or None
28+ # Work around a bug in paramiko < 2.0.0: if the most significant
29+ # byte of an RSA signature is zero, then it strips leading zero
30+ # bytes rather than zero-padding it to the correct length.
31+ if algName == 'ssh-rsa':
32+ signatureType, rawSignature, rest = getNS(signature, 2)
33+ pubKeyLen = (pubKey.size() + 7) // 8
34+ if len(rawSignature) < pubKeyLen:
35+ rawSignature = (
36+ b'\x00' * (pubKeyLen - len(rawSignature)) + rawSignature)
37+ signature = NS(signatureType) + NS(rawSignature) + rest
38 if hasSig:
39 b = NS(self.transport.sessionID) + \
40 chr(userauth.MSG_USERAUTH_REQUEST) + NS(self.user) + \
41
42=== modified file 'src/lazr/sshserver/tests/test_auth.py'
43--- src/lazr/sshserver/tests/test_auth.py 2017-12-20 14:40:54 +0000
44+++ src/lazr/sshserver/tests/test_auth.py 2017-12-21 11:41:35 +0000
45@@ -188,6 +188,35 @@
46 self.user_auth.tryAuth = tryAuth
47 self.user_auth._ebBadAuth = _ebBadAuth
48
49+ def test_worksAroundShortParamikoSignatures(self):
50+ # paramiko < 2.0.0 truncates RSA signatures whose most significant
51+ # byte is zero. auth_publickey tolerates this.
52+ class MockLogin(object):
53+ def __call__(self, credentials, mind, *interfaces):
54+ self.credentials = credentials
55+ return defer.succeed(None)
56+
57+ self.transport.sessionID = ''
58+ self.portal.login = MockLogin()
59+ keydir = sibpath(__file__, 'keys')
60+ public_key = Key.fromString(
61+ open(os.path.join(keydir, 'ssh_host_key_rsa.pub'), 'rb').read())
62+ public_key_len = (public_key.keyObject.size() + 7) // 8
63+ signature = b'\x01' * (public_key_len - 1)
64+ packet = (
65+ NS('user') + NS('') + NS('publickey') +
66+ chr(1) + NS('ssh-rsa') + NS(public_key.blob()) +
67+ NS(NS('ssh-rsa') + NS(signature)))
68+ self.user_auth.serviceStarted()
69+ self.user_auth.supportedAuthentications.append(b'publickey')
70+ try:
71+ self.user_auth.ssh_USERAUTH_REQUEST(packet)
72+ self.assertEqual(
73+ NS('ssh-rsa') + NS(b'\x00' + signature),
74+ self.portal.login.credentials.signature)
75+ finally:
76+ self.user_auth.serviceStopped()
77+
78
79 class MockChecker(SSHPublicKeyDatabase):
80 """A very simple public key checker which rejects all offered credentials.

Subscribers

People subscribed via source and target branches

to status/vote changes: