diff -Nru paramiko-2.4.1/debian/changelog paramiko-2.4.1/debian/changelog --- paramiko-2.4.1/debian/changelog 2018-10-11 18:42:03.000000000 +0000 +++ paramiko-2.4.1/debian/changelog 2018-10-26 18:05:07.000000000 +0000 @@ -1,3 +1,22 @@ +paramiko (2.4.1-0ubuntu3.2) cosmic-security; urgency=medium + + * debian/tests/control: fix autopkgtest by adding python-mock and + python3-mock to Depends. + + -- Marc Deslauriers Fri, 26 Oct 2018 14:05:07 -0400 + +paramiko (2.4.1-0ubuntu3.1) cosmic-security; urgency=medium + + * SECURITY UPDATE: server-side authentication vulnerability + - debian/patches/CVE-2018-1000805-pre.patch: fix MSG_UNIMPLEMENTED in + paramiko/transport.py, added tests to tests/test_transport.py. + - debian/patches/CVE-2018-1000805.patch: split messages dict in + paramiko/auth_handler.py, added tests to tests/test_transport.py. + - debian/control: added python-mock and python3-mock Build-Depends. + - CVE-2018-1000805 + + -- Marc Deslauriers Tue, 16 Oct 2018 08:26:18 -0400 + paramiko (2.4.1-0ubuntu3) cosmic; urgency=medium * disable-gssapi-on-unsupported-version.patch: Add a patch from Fedora diff -Nru paramiko-2.4.1/debian/control paramiko-2.4.1/debian/control --- paramiko-2.4.1/debian/control 2018-08-23 15:56:07.000000000 +0000 +++ paramiko-2.4.1/debian/control 2018-10-16 12:26:18.000000000 +0000 @@ -1,7 +1,8 @@ Source: paramiko Section: python Priority: optional -Maintainer: Jeremy T. Bouse +Maintainer: Ubuntu Developers +XSBC-Original-Maintainer: Jeremy T. Bouse Uploaders: Guido Guenther X-Python-Version: >= 2.6 X-Python3-Version: >= 3.2 @@ -12,6 +13,7 @@ python-cryptography (>= 1.5), python-ecdsa (>= 0.11), python-bcrypt (>= 3.1.3), + python-mock, python-nacl (>= 1.0.1), python-pyasn1 (>= 0.1.7), python-setuptools, @@ -20,6 +22,7 @@ python3-cryptography (>= 1.5), python3-ecdsa (>= 0.11), python3-bcrypt (>= 3.1.3), + python3-mock, python3-nacl (>= 1.0.1), python3-pyasn1 (>= 0.1.7), python3-setuptools diff -Nru paramiko-2.4.1/debian/patches/CVE-2018-1000805.patch paramiko-2.4.1/debian/patches/CVE-2018-1000805.patch --- paramiko-2.4.1/debian/patches/CVE-2018-1000805.patch 1970-01-01 00:00:00.000000000 +0000 +++ paramiko-2.4.1/debian/patches/CVE-2018-1000805.patch 2018-10-16 12:26:18.000000000 +0000 @@ -0,0 +1,150 @@ +Backport of: + +From 56c96a659658acdbb873aef8809a7b508434dcce Mon Sep 17 00:00:00 2001 +From: Jeff Forcier +Date: Tue, 18 Sep 2018 19:59:16 -0700 +Subject: [PATCH] Fix and changelog re #1283 + +--- + paramiko/auth_handler.py | 36 ++++++++++++++++++++++++---- + sites/www/changelog.rst | 12 ++++++++++ + tests/test_transport.py | 51 +++++++++++++++++++++++++++++++++++++++- + 3 files changed, 94 insertions(+), 5 deletions(-) + +Index: paramiko-2.4.1/paramiko/auth_handler.py +=================================================================== +--- paramiko-2.4.1.orig/paramiko/auth_handler.py 2018-10-16 09:44:41.574032493 -0400 ++++ paramiko-2.4.1/paramiko/auth_handler.py 2018-10-16 09:44:41.574032493 -0400 +@@ -664,17 +664,39 @@ Error Message: {} + self.auth_event.set() + return + +- _handler_table = { ++ # TODO: do the same to the other tables, in Transport. ++ # TODO 3.0: MAY make sense to make these tables into actual ++ # classes/instances that can be fed a mode bool or whatever. Or, ++ # alternately (both?) make the message types small classes or enums that ++ # embed this info within themselves (which could also then tidy up the ++ # current 'integer -> human readable short string' stuff in common.py). ++ # TODO: if we do that, also expose 'em publicly. ++ ++ # Messages which should be handled _by_ servers (sent by clients) ++ _server_handler_table = { + MSG_SERVICE_REQUEST: _parse_service_request, +- MSG_SERVICE_ACCEPT: _parse_service_accept, + MSG_USERAUTH_REQUEST: _parse_userauth_request, ++ MSG_USERAUTH_INFO_RESPONSE: _parse_userauth_info_response, ++ } ++ ++ # Messages which should be handled _by_ clients (sent by servers) ++ _client_handler_table = { ++ MSG_SERVICE_ACCEPT: _parse_service_accept, + MSG_USERAUTH_SUCCESS: _parse_userauth_success, + MSG_USERAUTH_FAILURE: _parse_userauth_failure, + MSG_USERAUTH_BANNER: _parse_userauth_banner, + MSG_USERAUTH_INFO_REQUEST: _parse_userauth_info_request, +- MSG_USERAUTH_INFO_RESPONSE: _parse_userauth_info_response, + } + ++ # NOTE: prior to the fix for #1283, this was a static dict instead of a ++ # property. Should be backwards compatible in most/all cases. ++ @property ++ def _handler_table(self): ++ if self.transport.server_mode: ++ return self._server_handler_table ++ else: ++ return self._client_handler_table ++ + + class GssapiWithMicAuthHandler(object): + """A specialized Auth handler for gssapi-with-mic +@@ -767,9 +789,15 @@ class GssapiWithMicAuthHandler(object): + self._restore_delegate_auth_handler() + return self._delegate._parse_userauth_request(m) + +- _handler_table = { ++ __handler_table = { + MSG_SERVICE_REQUEST: _parse_service_request, + MSG_USERAUTH_REQUEST: _parse_userauth_request, + MSG_USERAUTH_GSSAPI_TOKEN: _parse_userauth_gssapi_token, + MSG_USERAUTH_GSSAPI_MIC: _parse_userauth_gssapi_mic, + } ++ ++ @property ++ def _handler_table(self): ++ # TODO: determine if we can cut this up like we did for the primary ++ # AuthHandler class. ++ return self.__handler_table +Index: paramiko-2.4.1/tests/test_transport.py +=================================================================== +--- paramiko-2.4.1.orig/tests/test_transport.py 2018-10-16 09:44:41.574032493 -0400 ++++ paramiko-2.4.1/tests/test_transport.py 2018-10-16 09:46:27.138337445 -0400 +@@ -34,7 +34,7 @@ from mock import Mock + + from paramiko import ( + Transport, SecurityOptions, ServerInterface, RSAKey, DSSKey, SSHException, +- ChannelException, Packetizer, Channel, ++ ChannelException, Packetizer, Channel, AuthHandler, + ) + from paramiko import AUTH_FAILED, AUTH_SUCCESSFUL + from paramiko import OPEN_SUCCEEDED, OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED +@@ -42,8 +42,9 @@ from paramiko.common import ( + MSG_KEXINIT, cMSG_CHANNEL_WINDOW_ADJUST, cMSG_UNIMPLEMENTED, + MIN_PACKET_SIZE, MIN_WINDOW_SIZE, + MAX_WINDOW_SIZE, DEFAULT_WINDOW_SIZE, DEFAULT_MAX_PACKET_SIZE, ++ MSG_NAMES, MSG_UNIMPLEMENTED, MSG_USERAUTH_SUCCESS, + ) +-from paramiko.py3compat import bytes ++from paramiko.py3compat import bytes, byte_chr + from paramiko.message import Message + + from .util import needs_builtin, _support, slow +@@ -999,3 +1000,48 @@ class TransportTest(unittest.TestCase): + + def test_client_does_not_respond_to_MSG_UNIMPLEMENTED(self): + self._send_unimplemented(server_is_sender=True) ++ ++ def _send_client_message(self, message_type): ++ self.setup_test_server(connect_kwargs={}) ++ self.ts._send_message = Mock() ++ # NOTE: this isn't 100% realistic (most of these message types would ++ # have actual other fields in 'em) but it suffices to test the level of ++ # message dispatch we're interested in here. ++ msg = Message() ++ # TODO: really not liking the whole cMSG_XXX vs MSG_XXX duality right ++ # now, esp since the former is almost always just byte_chr(the ++ # latter)...but since that's the case... ++ msg.add_byte(byte_chr(message_type)) ++ self.tc._send_message(msg) ++ # No good way to actually wait for server action (see above tests re: ++ # MSG_UNIMPLEMENTED). Grump. ++ time.sleep(0.1) ++ ++ def _expect_unimplemented(self): ++ # Ensure MSG_UNIMPLEMENTED was sent (implies it hit end of loop instead ++ # of truly handling the given message). ++ # NOTE: When bug present, this will actually be the first thing that ++ # fails (since in many cases actual message handling doesn't involve ++ # sending a message back right away). ++ assert self.ts._send_message.call_count == 1 ++ reply = self.ts._send_message.call_args[0][0] ++ reply.rewind() # Because it's pre-send, not post-receive ++ assert reply.get_byte() == cMSG_UNIMPLEMENTED ++ ++ def test_server_transports_reject_client_message_types(self): ++ # TODO: handle Transport's own tables too, not just its inner auth ++ # handler's table. See TODOs in auth_handler.py ++ for message_type in AuthHandler._client_handler_table: ++ self._send_client_message(message_type) ++ self._expect_unimplemented() ++ # Reset for rest of loop ++ self.tearDown() ++ self.setUp() ++ ++ def test_server_rejects_client_MSG_USERAUTH_SUCCESS(self): ++ self._send_client_message(MSG_USERAUTH_SUCCESS) ++ # Sanity checks ++ assert not self.ts.authenticated ++ assert not self.ts.auth_handler.authenticated ++ # Real fix's behavior ++ self._expect_unimplemented() diff -Nru paramiko-2.4.1/debian/patches/CVE-2018-1000805-pre.patch paramiko-2.4.1/debian/patches/CVE-2018-1000805-pre.patch --- paramiko-2.4.1/debian/patches/CVE-2018-1000805-pre.patch 1970-01-01 00:00:00.000000000 +0000 +++ paramiko-2.4.1/debian/patches/CVE-2018-1000805-pre.patch 2018-10-16 12:26:18.000000000 +0000 @@ -0,0 +1,105 @@ +Backport of: + +From 852176d2d776b183a39e100009d3e18b6896323b Mon Sep 17 00:00:00 2001 +From: Jeff Forcier +Date: Tue, 18 Sep 2018 18:21:33 -0700 +Subject: [PATCH] Fix a pseudo-bug re: responding to MSG_UNIMPLEMENTED w/ + itself + +--- + dev-requirements.txt | 1 + + paramiko/transport.py | 23 ++++++++++++++++++----- + sites/www/changelog.rst | 5 +++++ + tests/test_transport.py | 25 +++++++++++++++++++++++++ + 4 files changed, 49 insertions(+), 5 deletions(-) + +Index: paramiko-2.4.1/paramiko/transport.py +=================================================================== +--- paramiko-2.4.1.orig/paramiko/transport.py 2018-10-16 09:42:45.901700311 -0400 ++++ paramiko-2.4.1/paramiko/transport.py 2018-10-16 09:44:02.493920012 -0400 +@@ -51,6 +51,7 @@ from paramiko.common import ( + MSG_CHANNEL_WINDOW_ADJUST, MSG_CHANNEL_REQUEST, MSG_CHANNEL_EOF, + MSG_CHANNEL_CLOSE, MIN_WINDOW_SIZE, MIN_PACKET_SIZE, MAX_WINDOW_SIZE, + DEFAULT_WINDOW_SIZE, DEFAULT_MAX_PACKET_SIZE, HIGHEST_USERAUTH_MESSAGE_ID, ++ MSG_UNIMPLEMENTED, MSG_NAMES, + ) + from paramiko.compress import ZlibCompressor, ZlibDecompressor + from paramiko.dsskey import DSSKey +@@ -1950,12 +1951,22 @@ class Transport(threading.Thread, Closin + if len(self._expected_packet) > 0: + continue + else: +- err = 'Oops, unhandled type {:d}'.format(ptype) +- self._log(WARNING, err) +- msg = Message() +- msg.add_byte(cMSG_UNIMPLEMENTED) +- msg.add_int(m.seqno) +- self._send_message(msg) ++ # Respond with "I don't implement this particular ++ # message type" message (unless the message type was ++ # itself literally MSG_UNIMPLEMENTED, in which case, we ++ # just shut up to avoid causing a useless loop). ++ name = MSG_NAMES[ptype] ++ self._log( ++ WARNING, ++ "Oops, unhandled type {} ({!r})".format( ++ ptype, name ++ ), ++ ) ++ if ptype != MSG_UNIMPLEMENTED: ++ msg = Message() ++ msg.add_byte(cMSG_UNIMPLEMENTED) ++ msg.add_int(m.seqno) ++ self._send_message(msg) + self.packetizer.complete_handshake() + except SSHException as e: + self._log(ERROR, 'Exception: ' + str(e)) +Index: paramiko-2.4.1/tests/test_transport.py +=================================================================== +--- paramiko-2.4.1.orig/tests/test_transport.py 2018-10-16 09:42:45.901700311 -0400 ++++ paramiko-2.4.1/tests/test_transport.py 2018-10-16 09:44:25.637986597 -0400 +@@ -30,6 +30,7 @@ import threading + import random + from hashlib import sha1 + import unittest ++from mock import Mock + + from paramiko import ( + Transport, SecurityOptions, ServerInterface, RSAKey, DSSKey, SSHException, +@@ -38,7 +39,8 @@ from paramiko import ( + from paramiko import AUTH_FAILED, AUTH_SUCCESSFUL + from paramiko import OPEN_SUCCEEDED, OPEN_FAILED_ADMINISTRATIVELY_PROHIBITED + from paramiko.common import ( +- MSG_KEXINIT, cMSG_CHANNEL_WINDOW_ADJUST, MIN_PACKET_SIZE, MIN_WINDOW_SIZE, ++ MSG_KEXINIT, cMSG_CHANNEL_WINDOW_ADJUST, cMSG_UNIMPLEMENTED, ++ MIN_PACKET_SIZE, MIN_WINDOW_SIZE, + MAX_WINDOW_SIZE, DEFAULT_WINDOW_SIZE, DEFAULT_MAX_PACKET_SIZE, + ) + from paramiko.py3compat import bytes +@@ -974,3 +976,26 @@ class TransportTest(unittest.TestCase): + assert "forwarding request denied" in str(e) + else: + assert False, "Did not raise SSHException!" ++ ++ def _send_unimplemented(self, server_is_sender): ++ self.setup_test_server() ++ sender, recipient = self.tc, self.ts ++ if server_is_sender: ++ sender, recipient = self.ts, self.tc ++ recipient._send_message = Mock() ++ msg = Message() ++ msg.add_byte(cMSG_UNIMPLEMENTED) ++ sender._send_message(msg) ++ # TODO: I hate this but I literally don't see a good way to know when ++ # the recipient has received the sender's message (there are no ++ # existing threading events in play that work for this), esp in this ++ # case where we don't WANT a response (as otherwise we could ++ # potentially try blocking on the sender's receipt of a reply...maybe). ++ time.sleep(0.1) ++ assert not recipient._send_message.called ++ ++ def test_server_does_not_respond_to_MSG_UNIMPLEMENTED(self): ++ self._send_unimplemented(server_is_sender=False) ++ ++ def test_client_does_not_respond_to_MSG_UNIMPLEMENTED(self): ++ self._send_unimplemented(server_is_sender=True) diff -Nru paramiko-2.4.1/debian/patches/series paramiko-2.4.1/debian/patches/series --- paramiko-2.4.1/debian/patches/series 2018-10-11 18:39:34.000000000 +0000 +++ paramiko-2.4.1/debian/patches/series 2018-10-16 12:26:18.000000000 +0000 @@ -1,3 +1,5 @@ drop-pytest-relaxed.patch add-missing-pub-keys.patch disable-gssapi-on-unsupported-version.patch +CVE-2018-1000805-pre.patch +CVE-2018-1000805.patch diff -Nru paramiko-2.4.1/debian/tests/control paramiko-2.4.1/debian/tests/control --- paramiko-2.4.1/debian/tests/control 2018-08-23 15:56:07.000000000 +0000 +++ paramiko-2.4.1/debian/tests/control 2018-10-26 18:05:07.000000000 +0000 @@ -1,3 +1,3 @@ Tests: upstream -Depends: @, python-pytest, python3-pytest +Depends: @, python-pytest, python3-pytest, python-mock, python3-mock Restrictions: allow-stderr