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
=== modified file 'src/lazr/sshserver/NEWS.txt'
--- src/lazr/sshserver/NEWS.txt 2015-11-29 12:33:03 +0000
+++ src/lazr/sshserver/NEWS.txt 2017-12-21 11:41:35 +0000
@@ -2,6 +2,15 @@
2NEWS for lazr.sshserver2NEWS for lazr.sshserver
3=======================3=======================
44
50.1.5
6=====
7
8- Work around a bug in paramiko < 2.0.0: if the most significant byte of an
9 RSA signature is zero, then it strips leading zero bytes rather than
10 zero-padding it to the correct length. This previously caused sporadic
11 failures when running with Twisted >= 16.0.0, since cryptography is
12 pickier about this than PyCrypto was.
13
50.1.4 (2015-11-29)140.1.4 (2015-11-29)
6==================15==================
716
817
=== modified file 'src/lazr/sshserver/auth.py'
--- src/lazr/sshserver/auth.py 2017-12-21 11:04:23 +0000
+++ src/lazr/sshserver/auth.py 2017-12-21 11:41:35 +0000
@@ -244,6 +244,16 @@
244 algName, blob, rest = getNS(packet[1:], 2)244 algName, blob, rest = getNS(packet[1:], 2)
245 pubKey = keys.Key.fromString(blob).keyObject245 pubKey = keys.Key.fromString(blob).keyObject
246 signature = hasSig and getNS(rest)[0] or None246 signature = hasSig and getNS(rest)[0] or None
247 # Work around a bug in paramiko < 2.0.0: if the most significant
248 # byte of an RSA signature is zero, then it strips leading zero
249 # bytes rather than zero-padding it to the correct length.
250 if algName == 'ssh-rsa':
251 signatureType, rawSignature, rest = getNS(signature, 2)
252 pubKeyLen = (pubKey.size() + 7) // 8
253 if len(rawSignature) < pubKeyLen:
254 rawSignature = (
255 b'\x00' * (pubKeyLen - len(rawSignature)) + rawSignature)
256 signature = NS(signatureType) + NS(rawSignature) + rest
247 if hasSig:257 if hasSig:
248 b = NS(self.transport.sessionID) + \258 b = NS(self.transport.sessionID) + \
249 chr(userauth.MSG_USERAUTH_REQUEST) + NS(self.user) + \259 chr(userauth.MSG_USERAUTH_REQUEST) + NS(self.user) + \
250260
=== modified file 'src/lazr/sshserver/tests/test_auth.py'
--- src/lazr/sshserver/tests/test_auth.py 2017-12-20 14:40:54 +0000
+++ src/lazr/sshserver/tests/test_auth.py 2017-12-21 11:41:35 +0000
@@ -188,6 +188,35 @@
188 self.user_auth.tryAuth = tryAuth188 self.user_auth.tryAuth = tryAuth
189 self.user_auth._ebBadAuth = _ebBadAuth189 self.user_auth._ebBadAuth = _ebBadAuth
190190
191 def test_worksAroundShortParamikoSignatures(self):
192 # paramiko < 2.0.0 truncates RSA signatures whose most significant
193 # byte is zero. auth_publickey tolerates this.
194 class MockLogin(object):
195 def __call__(self, credentials, mind, *interfaces):
196 self.credentials = credentials
197 return defer.succeed(None)
198
199 self.transport.sessionID = ''
200 self.portal.login = MockLogin()
201 keydir = sibpath(__file__, 'keys')
202 public_key = Key.fromString(
203 open(os.path.join(keydir, 'ssh_host_key_rsa.pub'), 'rb').read())
204 public_key_len = (public_key.keyObject.size() + 7) // 8
205 signature = b'\x01' * (public_key_len - 1)
206 packet = (
207 NS('user') + NS('') + NS('publickey') +
208 chr(1) + NS('ssh-rsa') + NS(public_key.blob()) +
209 NS(NS('ssh-rsa') + NS(signature)))
210 self.user_auth.serviceStarted()
211 self.user_auth.supportedAuthentications.append(b'publickey')
212 try:
213 self.user_auth.ssh_USERAUTH_REQUEST(packet)
214 self.assertEqual(
215 NS('ssh-rsa') + NS(b'\x00' + signature),
216 self.portal.login.credentials.signature)
217 finally:
218 self.user_auth.serviceStopped()
219
191220
192class MockChecker(SSHPublicKeyDatabase):221class MockChecker(SSHPublicKeyDatabase):
193 """A very simple public key checker which rejects all offered credentials.222 """A very simple public key checker which rejects all offered credentials.

Subscribers

People subscribed via source and target branches

to status/vote changes: