import python-paramiko-2.12.0-2.el9

i9ce changed/i9ce/python-paramiko-2.12.0-2.el9
Sergey Cherevko 6 months ago
commit 216d19f7b9
Signed by: scherevko
GPG Key ID: D87CBBC16D2E4A72

1
.gitignore vendored

@ -0,0 +1 @@
SOURCES/paramiko-2.12.0.tar.gz

@ -0,0 +1 @@
c8f18401ebcfc7aee9132eaa71bf33c76bf9301e SOURCES/paramiko-2.12.0.tar.gz

@ -0,0 +1,67 @@
--- a/dev-requirements.txt
+++ b/dev-requirements.txt
@@ -2,7 +2,6 @@
invoke==1.6.0
invocations==2.6.0
pytest==4.4.2
-pytest-relaxed==1.1.5
# pytest-xdist for test dir watching and the inv guard task
pytest-xdist==1.28.0
mock==2.0.0
--- a/pytest.ini
+++ b/pytest.ini
@@ -1,7 +1,4 @@
[pytest]
-# We use pytest-relaxed just for its utils at the moment, so disable it at the
-# plugin level until we adapt test organization to really use it.
-addopts = -p no:relaxed
# Loop on failure
looponfailroots = tests paramiko
# Ignore some warnings we cannot easily handle.
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -34,7 +34,6 @@ import weakref
from tempfile import mkstemp
import pytest
-from pytest_relaxed import raises
from mock import patch, Mock
import paramiko
@@ -787,11 +786,11 @@ class PasswordPassphraseTests(ClientTest
# TODO: more granular exception pending #387; should be signaling "no auth
# methods available" because no key and no password
- @raises(SSHException)
@requires_sha1_signing
def test_passphrase_kwarg_not_used_for_password_auth(self):
- # Using the "right" password in the "wrong" field shouldn't work.
- self._test_connection(passphrase="pygmalion")
+ with pytest.raises(SSHException):
+ # Using the "right" password in the "wrong" field shouldn't work.
+ self._test_connection(passphrase="pygmalion")
@requires_sha1_signing
def test_passphrase_kwarg_used_for_key_passphrase(self):
@@ -811,15 +810,15 @@ class PasswordPassphraseTests(ClientTest
password="television",
)
- @raises(AuthenticationException) # TODO: more granular
@requires_sha1_signing
def test_password_kwarg_not_used_for_passphrase_when_passphrase_kwarg_given( # noqa
self
):
# Sanity: if we're given both fields, the password field is NOT used as
# a passphrase.
- self._test_connection(
- key_filename=_support("test_rsa_password.key"),
- password="television",
- passphrase="wat? lol no",
- )
+ with pytest.raises(AuthenticationException):
+ self._test_connection(
+ key_filename=_support("test_rsa_password.key"),
+ password="television",
+ passphrase="wat? lol no",
+ )

@ -0,0 +1,117 @@
Prefer and use built-in unittest.mock in Python 3.3+ instead
of unnecessarily requiring the external mock package. This helps
distributions that are phasing out Python 2 to remove redundant
packages.
--- a/dev-requirements.txt
+++ b/dev-requirements.txt
@@ -4,7 +4,7 @@ invocations==2.6.0
pytest==4.4.2
# pytest-xdist for test dir watching and the inv guard task
pytest-xdist==1.28.0
-mock==2.0.0
+mock==2.0.0;python_version<"3.3"
# Linting!
flake8==3.8.3
# Formatting!
--- a/tests/test_channelfile.py
+++ b/tests/test_channelfile.py
@@ -1,4 +1,7 @@
-from mock import patch, MagicMock
+try:
+ from unittest.mock import patch, MagicMock
+except ImportError:
+ from mock import patch, MagicMock
from paramiko import Channel, ChannelFile, ChannelStderrFile, ChannelStdinFile
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -34,7 +34,10 @@ import weakref
from tempfile import mkstemp
import pytest
-from mock import patch, Mock
+try:
+ from unittest.mock import patch, Mock
+except ImportError:
+ from mock import patch, Mock
import paramiko
from paramiko import SSHClient
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -11,7 +11,11 @@ try:
except ImportError:
Result = None
-from mock import patch
+try:
+ from unittest.mock import patch
+except ImportError:
+ from mock import patch
+
from pytest import raises, mark, fixture
from paramiko import (
--- a/tests/test_kex.py
+++ b/tests/test_kex.py
@@ -24,7 +24,11 @@ from binascii import hexlify, unhexlify
import os
import unittest
-from mock import Mock, patch
+try:
+ from unittest.mock import Mock, patch
+except ImportError:
+ from mock import Mock, patch
+
import pytest
from cryptography.hazmat.backends import default_backend
--- a/tests/test_pkey.py
+++ b/tests/test_pkey.py
@@ -41,7 +41,12 @@ from paramiko.common import o600
from cryptography.exceptions import UnsupportedAlgorithm
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateNumbers
-from mock import patch, Mock
+
+try:
+ from unittest.mock import patch, Mock
+except ImportError:
+ from mock import patch, Mock
+
import pytest
from .util import _support, is_low_entropy, requires_sha1_signing
--- a/tests/test_proxy.py
+++ b/tests/test_proxy.py
@@ -1,7 +1,11 @@
import signal
import socket
-from mock import patch
+try:
+ from unittest.mock import patch
+except ImportError:
+ from mock import patch
+
from pytest import raises
from paramiko import ProxyCommand, ProxyCommandFailure
--- a/tests/test_transport.py
+++ b/tests/test_transport.py
@@ -30,7 +30,11 @@ import time
import threading
import random
import unittest
-from mock import Mock
+
+try:
+ from unittest.mock import Mock
+except ImportError:
+ from mock import Mock
from paramiko import (
AuthHandler,

@ -0,0 +1,62 @@
--- a/paramiko/agent.py
+++ b/paramiko/agent.py
@@ -415,9 +415,6 @@ class AgentKey(PKey):
def asbytes(self):
return self.blob
- def __str__(self):
- return self.asbytes()
-
def get_name(self):
return self.name
--- a/paramiko/message.py
+++ b/paramiko/message.py
@@ -53,10 +53,7 @@ class Message(object):
else:
self.packet = BytesIO()
- def __str__(self):
- """
- Return the byte stream content of this message, as a string/bytes obj.
- """
+ def __bytes__(self):
return self.asbytes()
def __repr__(self):
--- a/paramiko/pkey.py
+++ b/paramiko/pkey.py
@@ -118,7 +119,7 @@ class PKey(object):
"""
return bytes()
- def __str__(self):
+ def __bytes__(self):
return self.asbytes()
# noinspection PyUnresolvedReferences
--- a/tests/test_agent.py
+++ b/tests/test_agent.py
@@ -48,3 +48,10 @@ class AgentTests(unittest.TestCase):
kwargs=dict(algorithm="rsa-sha2-512"),
expectation=SSH_AGENT_RSA_SHA2_512,
)
+
+ def test_agent_key_str_kinda_fixed(self):
+ # Tests for a missed spot in Python 3 upgrades: AgentKey.__str__ was
+ # returning bytes, as if under Python 2. When bug present, this
+ # explodes with "__str__ returned non-string".
+ key = AgentKey(ChaosAgent(), b("secret!!!"))
+ assert str(key) == repr(key)
--- a/tests/test_message.py
+++ b/tests/test_message.py
@@ -105,3 +105,9 @@ class MessageTest(unittest.TestCase):
self.assertEqual(msg.get_adaptive_int(), 5)
self.assertEqual(msg.get_so_far(), self.__d[:4])
self.assertEqual(msg.get_remainder(), self.__d[4:])
+
+ def test_bytes_str_and_repr(self):
+ msg = Message(self.__d)
+ assert str(msg) == f"paramiko.Message({self.__d!r})"
+ assert repr(msg) == str(msg)
+ assert bytes(msg) == msg.asbytes() == self.__d

@ -0,0 +1,717 @@
--- a/paramiko/__init__.py
+++ b/paramiko/__init__.py
@@ -19,12 +19,15 @@
# flake8: noqa
import sys
from paramiko._version import __version__, __version_info__
-from paramiko.transport import SecurityOptions, Transport
+from paramiko.transport import (
+ SecurityOptions,
+ Transport,
+)
from paramiko.client import (
- SSHClient,
- MissingHostKeyPolicy,
AutoAddPolicy,
+ MissingHostKeyPolicy,
RejectPolicy,
+ SSHClient,
WarningPolicy,
)
from paramiko.auth_handler import AuthHandler
@@ -43,6 +46,7 @@ from paramiko.ssh_exception import (
ConfigParseError,
CouldNotCanonicalize,
IncompatiblePeer,
+ MessageOrderError,
PasswordRequiredException,
ProxyCommandFailure,
SSHException,
--- a/paramiko/packet.py
+++ b/paramiko/packet.py
@@ -86,6 +86,7 @@ class Packetizer(object):
self.__need_rekey = False
self.__init_count = 0
self.__remainder = bytes()
+ self._initial_kex_done = False
# used for noticing when to re-key:
self.__sent_bytes = 0
@@ -130,6 +131,12 @@ class Packetizer(object):
def closed(self):
return self.__closed
+ def reset_seqno_out(self):
+ self.__sequence_number_out = 0
+
+ def reset_seqno_in(self):
+ self.__sequence_number_in = 0
+
def set_log(self, log):
"""
Set the Python log object to use for logging.
@@ -425,9 +432,12 @@ class Packetizer(object):
out += compute_hmac(
self.__mac_key_out, payload, self.__mac_engine_out
)[: self.__mac_size_out]
- self.__sequence_number_out = (
- self.__sequence_number_out + 1
- ) & xffffffff
+ next_seq = (self.__sequence_number_out + 1) & xffffffff
+ if next_seq == 0 and not self._initial_kex_done:
+ raise SSHException(
+ "Sequence number rolled over during initial kex!"
+ )
+ self.__sequence_number_out = next_seq
self.write_all(out)
self.__sent_bytes += len(out)
@@ -531,7 +541,12 @@ class Packetizer(object):
msg = Message(payload[1:])
msg.seqno = self.__sequence_number_in
- self.__sequence_number_in = (self.__sequence_number_in + 1) & xffffffff
+ next_seq = (self.__sequence_number_in + 1) & xffffffff
+ if next_seq == 0 and not self._initial_kex_done:
+ raise SSHException(
+ "Sequence number rolled over during initial kex!"
+ )
+ self.__sequence_number_in = next_seq
# check for rekey
raw_packet_size = packet_size + self.__mac_size_in + 4
--- a/paramiko/ssh_exception.py
+++ b/paramiko/ssh_exception.py
@@ -235,3 +235,13 @@ class ConfigParseError(SSHException):
"""
pass
+
+
+class MessageOrderError(SSHException):
+ """
+ Out-of-order protocol messages were received, violating "strict kex" mode.
+
+ .. versionadded:: 3.4
+ """
+
+ pass
--- a/paramiko/transport.py
+++ b/paramiko/transport.py
@@ -106,11 +106,12 @@ from paramiko.ecdsakey import ECDSAKey
from paramiko.server import ServerInterface
from paramiko.sftp_client import SFTPClient
from paramiko.ssh_exception import (
- SSHException,
BadAuthenticationType,
ChannelException,
IncompatiblePeer,
+ MessageOrderError,
ProxyCommandFailure,
+ SSHException,
)
from paramiko.util import retry_on_signal, ClosingContextManager, clamp_value
@@ -329,6 +330,8 @@ class Transport(threading.Thread, Closin
gss_deleg_creds=True,
disabled_algorithms=None,
server_sig_algs=True,
+ strict_kex=True,
+ packetizer_class=None,
):
"""
Create a new SSH session over an existing socket, or socket-like
@@ -395,6 +398,13 @@ class Transport(threading.Thread, Closin
Whether to send an extra message to compatible clients, in server
mode, with a list of supported pubkey algorithms. Default:
``True``.
+ :param bool strict_kex:
+ Whether to advertise (and implement, if client also advertises
+ support for) a "strict kex" mode for safer handshaking. Default:
+ ``True``.
+ :param packetizer_class:
+ Which class to use for instantiating the internal packet handler.
+ Default: ``None`` (i.e.: use `Packetizer` as normal).
.. versionchanged:: 1.15
Added the ``default_window_size`` and ``default_max_packet_size``
@@ -405,10 +415,16 @@ class Transport(threading.Thread, Closin
Added the ``disabled_algorithms`` kwarg.
.. versionchanged:: 2.9
Added the ``server_sig_algs`` kwarg.
+ .. versionchanged:: 3.4
+ Added the ``strict_kex`` kwarg.
+ .. versionchanged:: 3.4
+ Added the ``packetizer_class`` kwarg.
"""
self.active = False
self.hostname = None
self.server_extensions = {}
+ self.advertise_strict_kex = strict_kex
+ self.agreed_on_strict_kex = False
if isinstance(sock, string_types):
# convert "host:port" into (host, port)
@@ -450,7 +466,7 @@ class Transport(threading.Thread, Closin
self.sock.settimeout(self._active_check_timeout)
# negotiated crypto parameters
- self.packetizer = Packetizer(sock)
+ self.packetizer = (packetizer_class or Packetizer)(sock)
self.local_version = "SSH-" + self._PROTO_ID + "-" + self._CLIENT_ID
self.remote_version = ""
self.local_cipher = self.remote_cipher = ""
@@ -524,6 +540,20 @@ class Transport(threading.Thread, Closin
self.server_accept_cv = threading.Condition(self.lock)
self.subsystem_table = {}
+ # Handler table, now set at init time for easier per-instance
+ # manipulation and subclass twiddling.
+ self._handler_table = {
+ MSG_EXT_INFO: self._parse_ext_info,
+ MSG_NEWKEYS: self._parse_newkeys,
+ MSG_GLOBAL_REQUEST: self._parse_global_request,
+ MSG_REQUEST_SUCCESS: self._parse_request_success,
+ MSG_REQUEST_FAILURE: self._parse_request_failure,
+ MSG_CHANNEL_OPEN_SUCCESS: self._parse_channel_open_success,
+ MSG_CHANNEL_OPEN_FAILURE: self._parse_channel_open_failure,
+ MSG_CHANNEL_OPEN: self._parse_channel_open,
+ MSG_KEXINIT: self._negotiate_keys,
+ }
+
def _filter_algorithm(self, type_):
default = getattr(self, "_preferred_{}".format(type_))
return tuple(
@@ -2067,6 +2097,20 @@ class Transport(threading.Thread, Closin
# be empty.)
return reply
+ def _enforce_strict_kex(self, ptype):
+ """
+ Conditionally raise `MessageOrderError` during strict initial kex.
+
+ This method should only be called inside code that handles non-KEXINIT
+ messages; it does not interrogate ``ptype`` besides using it to log
+ more accurately.
+ """
+ if self.agreed_on_strict_kex and not self.initial_kex_done:
+ name = MSG_NAMES.get(ptype, f"msg {ptype}")
+ raise MessageOrderError(
+ f"In strict-kex mode, but was sent {name!r}!"
+ )
+
def run(self):
# (use the exposed "run" method, because if we specify a thread target
# of a private method, threading.Thread will keep a reference to it
@@ -2111,16 +2155,21 @@ class Transport(threading.Thread, Closin
except NeedRekeyException:
continue
if ptype == MSG_IGNORE:
+ self._enforce_strict_kex(ptype)
continue
elif ptype == MSG_DISCONNECT:
self._parse_disconnect(m)
break
elif ptype == MSG_DEBUG:
+ self._enforce_strict_kex(ptype)
self._parse_debug(m)
continue
if len(self._expected_packet) > 0:
if ptype not in self._expected_packet:
- raise SSHException(
+ exc_class = SSHException
+ if self.agreed_on_strict_kex:
+ exc_class = MessageOrderError
+ raise exc_class(
"Expecting packet from {!r}, got {:d}".format(
self._expected_packet, ptype
)
@@ -2135,7 +2184,7 @@ class Transport(threading.Thread, Closin
if error_msg:
self._send_message(error_msg)
else:
- self._handler_table[ptype](self, m)
+ self._handler_table[ptype](m)
elif ptype in self._channel_handler_table:
chanid = m.get_int()
chan = self._channels.get(chanid)
@@ -2342,12 +2391,18 @@ class Transport(threading.Thread, Closin
)
else:
available_server_keys = self.preferred_keys
- # Signal support for MSG_EXT_INFO.
+ # Signal support for MSG_EXT_INFO so server will send it to us.
# NOTE: doing this here handily means we don't even consider this
# value when agreeing on real kex algo to use (which is a common
# pitfall when adding this apparently).
kex_algos.append("ext-info-c")
+ # Similar to ext-info, but used in both server modes, so done outside
+ # of above if/else.
+ if self.advertise_strict_kex:
+ which = "s" if self.server_mode else "c"
+ kex_algos.append(f"kex-strict-{which}-v00@openssh.com")
+
m = Message()
m.add_byte(cMSG_KEXINIT)
m.add_bytes(os.urandom(16))
@@ -2388,7 +2443,8 @@ class Transport(threading.Thread, Closin
def _get_latest_kex_init(self):
return self._really_parse_kex_init(
- Message(self._latest_kex_init), ignore_first_byte=True
+ Message(self._latest_kex_init),
+ ignore_first_byte=True,
)
def _parse_kex_init(self, m):
@@ -2427,10 +2483,39 @@ class Transport(threading.Thread, Closin
self._log(DEBUG, "kex follows: {}".format(kex_follows))
self._log(DEBUG, "=== Key exchange agreements ===")
- # Strip out ext-info "kex algo"
+ # Record, and strip out, ext-info and/or strict-kex non-algorithms
self._remote_ext_info = None
- if kex_algo_list[-1].startswith("ext-info-"):
- self._remote_ext_info = kex_algo_list.pop()
+ self._remote_strict_kex = None
+ to_pop = []
+ for i, algo in enumerate(kex_algo_list):
+ if algo.startswith("ext-info-"):
+ self._remote_ext_info = algo
+ to_pop.insert(0, i)
+ elif algo.startswith("kex-strict-"):
+ # NOTE: this is what we are expecting from the /remote/ end.
+ which = "c" if self.server_mode else "s"
+ expected = f"kex-strict-{which}-v00@openssh.com"
+ # Set strict mode if agreed.
+ self.agreed_on_strict_kex = (
+ algo == expected and self.advertise_strict_kex
+ )
+ self._log(
+ DEBUG, f"Strict kex mode: {self.agreed_on_strict_kex}"
+ )
+ to_pop.insert(0, i)
+ for i in to_pop:
+ kex_algo_list.pop(i)
+
+ # CVE mitigation: expect zeroed-out seqno anytime we are performing kex
+ # init phase, if strict mode was negotiated.
+ if (
+ self.agreed_on_strict_kex
+ and not self.initial_kex_done
+ and m.seqno != 0
+ ):
+ raise MessageOrderError(
+ "In strict-kex mode, but KEXINIT was not the first packet!"
+ )
# as a server, we pick the first item in the client's list that we
# support.
@@ -2631,6 +2716,13 @@ class Transport(threading.Thread, Closin
):
self._log(DEBUG, "Switching on inbound compression ...")
self.packetizer.set_inbound_compressor(compress_in())
+ # Reset inbound sequence number if strict mode.
+ if self.agreed_on_strict_kex:
+ self._log(
+ DEBUG,
+ "Resetting inbound seqno after NEWKEYS due to strict mode",
+ )
+ self.packetizer.reset_seqno_in()
def _activate_outbound(self):
"""switch on newly negotiated encryption parameters for
@@ -2638,6 +2730,13 @@ class Transport(threading.Thread, Closin
m = Message()
m.add_byte(cMSG_NEWKEYS)
self._send_message(m)
+ # Reset outbound sequence number if strict mode.
+ if self.agreed_on_strict_kex:
+ self._log(
+ DEBUG,
+ "Resetting outbound seqno after NEWKEYS due to strict mode",
+ )
+ self.packetizer.reset_seqno_out()
block_size = self._cipher_info[self.local_cipher]["block-size"]
if self.server_mode:
IV_out = self._compute_key("B", block_size)
@@ -2728,7 +2827,9 @@ class Transport(threading.Thread, Closin
self.auth_handler = AuthHandler(self)
if not self.initial_kex_done:
# this was the first key exchange
- self.initial_kex_done = True
+ # (also signal to packetizer as it sometimes wants to know this
+ # status as well, eg when seqnos rollover)
+ self.initial_kex_done = self.packetizer._initial_kex_done = True
# send an event?
if self.completion_event is not None:
self.completion_event.set()
@@ -2982,18 +3083,6 @@ class Transport(threading.Thread, Closin
finally:
self.lock.release()
- _handler_table = {
- MSG_EXT_INFO: _parse_ext_info,
- MSG_NEWKEYS: _parse_newkeys,
- MSG_GLOBAL_REQUEST: _parse_global_request,
- MSG_REQUEST_SUCCESS: _parse_request_success,
- MSG_REQUEST_FAILURE: _parse_request_failure,
- MSG_CHANNEL_OPEN_SUCCESS: _parse_channel_open_success,
- MSG_CHANNEL_OPEN_FAILURE: _parse_channel_open_failure,
- MSG_CHANNEL_OPEN: _parse_channel_open,
- MSG_KEXINIT: _negotiate_keys,
- }
-
_channel_handler_table = {
MSG_CHANNEL_SUCCESS: Channel._request_success,
MSG_CHANNEL_FAILURE: Channel._request_failed,
--- a/tests/test_transport.py
+++ b/tests/test_transport.py
@@ -23,12 +23,14 @@ Some unit tests for the ssh2 protocol in
from __future__ import with_statement
from binascii import hexlify
+import itertools
from contextlib import contextmanager
import select
import socket
import time
import threading
import random
+import sys
import unittest
try:
@@ -37,14 +39,15 @@ except ImportError:
from mock import Mock
from paramiko import (
+ AuthenticationException,
AuthHandler,
ChannelException,
DSSKey,
+ IncompatiblePeer,
+ MessageOrderError,
Packetizer,
RSAKey,
SSHException,
- AuthenticationException,
- IncompatiblePeer,
SecurityOptions,
ServerInterface,
Transport,
@@ -57,7 +60,11 @@ from paramiko.common import (
MAX_WINDOW_SIZE,
MIN_PACKET_SIZE,
MIN_WINDOW_SIZE,
+ MSG_CHANNEL_OPEN,
+ MSG_DEBUG,
+ MSG_IGNORE,
MSG_KEXINIT,
+ MSG_UNIMPLEMENTED,
MSG_USERAUTH_SUCCESS,
cMSG_CHANNEL_WINDOW_ADJUST,
cMSG_UNIMPLEMENTED,
@@ -67,6 +74,7 @@ from paramiko.message import Message
from .util import needs_builtin, _support, requires_sha1_signing, slow
from .loop import LoopSocket
+from pytest import mark, raises
LONG_BANNER = """\
@@ -154,6 +162,10 @@ class NullServer(ServerInterface):
self._tcpip_dest = destination
return OPEN_SUCCEEDED
+# Faux 'packet type' we do not implement and are unlikely ever to (but which is
+# technically "within spec" re RFC 4251
+MSG_FUGGEDABOUTIT = 253
+
class TransportTest(unittest.TestCase):
def setUp(self):
@@ -1119,6 +1131,16 @@ class TransportTest(unittest.TestCase):
# Real fix's behavior
self._expect_unimplemented()
+ def test_can_override_packetizer_used(self):
+ class MyPacketizer(Packetizer):
+ pass
+
+ # control case
+ assert Transport(sock=LoopSocket()).packetizer.__class__ is Packetizer
+ # overridden case
+ tweaked = Transport(sock=LoopSocket(), packetizer_class=MyPacketizer)
+ assert tweaked.packetizer.__class__ is MyPacketizer
+
class AlgorithmDisablingTests(unittest.TestCase):
def test_preferred_lists_default_to_private_attribute_contents(self):
@@ -1202,10 +1224,17 @@ def server(
connect=None,
pubkeys=None,
catch_error=False,
+ transport_factory=None,
+ server_transport_factory=None,
+ defer=False,
+ skip_verify=False,
):
"""
SSH server contextmanager for testing.
+ Yields a tuple of ``(tc, ts)`` (client- and server-side `Transport`
+ objects), or ``(tc, ts, err)`` when ``catch_error==True``.
+
:param hostkey:
Host key to use for the server; if None, loads
``test_rsa.key``.
@@ -1222,6 +1251,17 @@ def server(
:param catch_error:
Whether to capture connection errors & yield from contextmanager.
Necessary for connection_time exception testing.
+ :param transport_factory:
+ Like the same-named param in SSHClient: which Transport class to use.
+ :param server_transport_factory:
+ Like ``transport_factory``, but only impacts the server transport.
+ :param bool defer:
+ Whether to defer authentication during connecting.
+
+ This is really just shorthand for ``connect={}`` which would do roughly
+ the same thing. Also: this implies skip_verify=True automatically!
+ :param bool skip_verify:
+ Whether NOT to do the default "make sure auth passed" check.
"""
if init is None:
init = {}
@@ -1230,12 +1270,21 @@ def server(
if client_init is None:
client_init = {}
if connect is None:
- connect = dict(username="slowdive", password="pygmalion")
+ # No auth at all please
+ if defer:
+ connect = dict()
+ # Default username based auth
+ else:
+ connect = dict(username="slowdive", password="pygmalion")
socks = LoopSocket()
sockc = LoopSocket()
sockc.link(socks)
- tc = Transport(sockc, **dict(init, **client_init))
- ts = Transport(socks, **dict(init, **server_init))
+ if transport_factory is None:
+ transport_factory = Transport
+ if server_transport_factory is None:
+ server_transport_factory = transport_factory
+ tc = transport_factory(sockc, **dict(init, **client_init))
+ ts = server_transport_factory(socks, **dict(init, **server_init))
if hostkey is None:
hostkey = RSAKey.from_private_key_file(_support("test_rsa.key"))
@@ -1354,10 +1403,14 @@ class TestSHA2SignatureKeyExchange(unitt
class TestExtInfo(unittest.TestCase):
- def test_ext_info_handshake(self):
+ def test_ext_info_handshake_exposed_in_client_kexinit(self):
with server() as (tc, _):
+ # NOTE: this is latest KEXINIT /sent by us/ (Transport retains it)
kex = tc._get_latest_kex_init()
- assert kex["kex_algo_list"][-1] == "ext-info-c"
+ # flag in KexAlgorithms list
+ assert "ext-info-c" in kex["kex_algo_list"]
+ # data stored on Transport after hearing back from a compatible
+ # server (such as ourselves in server mode)
assert tc.server_extensions == {
"server-sig-algs": b"ssh-ed25519,ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521,rsa-sha2-512,rsa-sha2-256,ssh-rsa,ssh-dss" # noqa
}
@@ -1463,3 +1516,187 @@ class TestSHA2SignaturePubkeys(unittest.
) as (tc, ts):
assert tc.is_authenticated()
assert tc._agreed_pubkey_algorithm == "rsa-sha2-256"
+
+
+class BadSeqPacketizer(Packetizer):
+ def read_message(self):
+ cmd, msg = super().read_message()
+ # Only mess w/ seqno if kexinit.
+ if cmd is MSG_KEXINIT:
+ # NOTE: this is /only/ the copy of the seqno which gets
+ # transmitted up from Packetizer; it's not modifying
+ # Packetizer's own internal seqno. For these tests,
+ # modifying the latter isn't required, and is also harder
+ # to do w/o triggering MAC mismatches.
+ msg.seqno = 17 # arbitrary nonzero int
+ return cmd, msg
+
+
+class TestStrictKex:
+ def test_kex_algos_includes_kex_strict_c(self):
+ with server() as (tc, _):
+ kex = tc._get_latest_kex_init()
+ assert "kex-strict-c-v00@openssh.com" in kex["kex_algo_list"]
+
+ @mark.parametrize(
+ "server_active,client_active",
+ itertools.product([True, False], repeat=2),
+ )
+ def test_mode_agreement(self, server_active, client_active):
+ with server(
+ server_init=dict(strict_kex=server_active),
+ client_init=dict(strict_kex=client_active),
+ ) as (tc, ts):
+ if server_active and client_active:
+ assert tc.agreed_on_strict_kex is True
+ assert ts.agreed_on_strict_kex is True
+ else:
+ assert tc.agreed_on_strict_kex is False
+ assert ts.agreed_on_strict_kex is False
+
+ def test_mode_advertised_by_default(self):
+ # NOTE: no explicit strict_kex overrides...
+ with server() as (tc, ts):
+ assert all(
+ (
+ tc.advertise_strict_kex,
+ tc.agreed_on_strict_kex,
+ ts.advertise_strict_kex,
+ ts.agreed_on_strict_kex,
+ )
+ )
+
+ @mark.parametrize(
+ "ptype",
+ (
+ # "normal" but definitely out-of-order message
+ MSG_CHANNEL_OPEN,
+ # Normally ignored, but not in this case
+ MSG_IGNORE,
+ # Normally triggers debug parsing, but not in this case
+ MSG_DEBUG,
+ # Normally ignored, but...you get the idea
+ MSG_UNIMPLEMENTED,
+ # Not real, so would normally trigger us /sending/
+ # MSG_UNIMPLEMENTED, but...
+ MSG_FUGGEDABOUTIT,
+ ),
+ )
+ def test_MessageOrderError_non_kex_messages_in_initial_kex(self, ptype):
+ class AttackTransport(Transport):
+ # Easiest apparent spot on server side which is:
+ # - late enough for both ends to have handshook on strict mode
+ # - early enough to be in the window of opportunity for Terrapin
+ # attack; essentially during actual kex, when the engine is
+ # waiting for things like MSG_KEXECDH_REPLY (for eg curve25519).
+ def _negotiate_keys(self, m):
+ self.clear_to_send_lock.acquire()
+ try:
+ self.clear_to_send.clear()
+ finally:
+ self.clear_to_send_lock.release()
+ if self.local_kex_init is None:
+ # remote side wants to renegotiate
+ self._send_kex_init()
+ self._parse_kex_init(m)
+ # Here, we would normally kick over to kex_engine, but instead
+ # we want the server to send the OOO message.
+ m = Message()
+ m.add_byte(byte_chr(ptype))
+ # rest of packet unnecessary...
+ self._send_message(m)
+
+ with raises(MessageOrderError):
+ with server(server_transport_factory=AttackTransport) as (tc, _):
+ pass # above should run and except during connect()
+
+ def test_SSHException_raised_on_out_of_order_messages_when_not_strict(
+ self,
+ ):
+ # This is kind of dumb (either situation is still fatal!) but whatever,
+ # may as well be strict with our new strict flag...
+ with raises(SSHException) as info: # would be true either way, but
+ with server(
+ client_init=dict(strict_kex=False),
+ ) as (tc, _):
+ tc._expect_packet(MSG_KEXINIT)
+ tc.open_session()
+ assert info.type is SSHException # NOT MessageOrderError!
+
+ def test_error_not_raised_when_kexinit_not_seq_0_but_unstrict(self):
+ with server(
+ client_init=dict(
+ # Disable strict kex
+ strict_kex=False,
+ # Give our clientside a packetizer that sets all kexinit
+ # Message objects to have .seqno==17, which would trigger the
+ # new logic if we'd forgotten to wrap it in strict-kex check
+ packetizer_class=BadSeqPacketizer,
+ ),
+ ):
+ pass # kexinit happens at connect...
+
+ def test_MessageOrderError_raised_when_kexinit_not_seq_0_and_strict(self):
+ with raises(MessageOrderError):
+ with server(
+ # Give our clientside a packetizer that sets all kexinit
+ # Message objects to have .seqno==17, which should trigger the
+ # new logic (given we are NOT disabling strict-mode)
+ client_init=dict(packetizer_class=BadSeqPacketizer),
+ ):
+ pass # kexinit happens at connect...
+
+ def test_sequence_numbers_reset_on_newkeys_when_strict(self):
+ with server(defer=True) as (tc, ts):
+ # When in strict mode, these should all be zero or close to it
+ # (post-kexinit, pre-auth).
+ # Server->client will be 1 (EXT_INFO got sent after NEWKEYS)
+ assert tc.packetizer._Packetizer__sequence_number_in == 1
+ assert ts.packetizer._Packetizer__sequence_number_out == 1
+ # Client->server will be 0
+ assert tc.packetizer._Packetizer__sequence_number_out == 0
+ assert ts.packetizer._Packetizer__sequence_number_in == 0
+
+ def test_sequence_numbers_not_reset_on_newkeys_when_not_strict(self):
+ with server(defer=True, client_init=dict(strict_kex=False)) as (
+ tc,
+ ts,
+ ):
+ # When not in strict mode, these will all be ~3-4 or so
+ # (post-kexinit, pre-auth). Not encoding exact values as it will
+ # change anytime we mess with the test harness...
+ assert tc.packetizer._Packetizer__sequence_number_in != 0
+ assert tc.packetizer._Packetizer__sequence_number_out != 0
+ assert ts.packetizer._Packetizer__sequence_number_in != 0
+ assert ts.packetizer._Packetizer__sequence_number_out != 0
+
+ def test_sequence_number_rollover_detected(self):
+ class RolloverTransport(Transport):
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ # Induce an about-to-rollover seqno, such that it rolls over
+ # during initial kex.
+ setattr(
+ self.packetizer,
+ "_Packetizer__sequence_number_in",
+ sys.maxsize,
+ )
+ setattr(
+ self.packetizer,
+ "_Packetizer__sequence_number_out",
+ sys.maxsize,
+ )
+
+ with raises(
+ SSHException,
+ match=r"Sequence number rolled over during initial kex!",
+ ):
+ with server(
+ client_init=dict(
+ # Disable strict kex - this should happen always
+ strict_kex=False,
+ ),
+ # Transport which tickles its packetizer seqno's
+ transport_factory=RolloverTransport,
+ ):
+ pass # kexinit happens at connect...

@ -0,0 +1,799 @@
%global srcname paramiko
Name: python-%{srcname}
Version: 2.12.0
Release: 2%{?dist}
Summary: SSH2 protocol library for python
# No version specified
License: LGPL-2.1-or-later
URL: https://github.com/paramiko/paramiko
Source0: %{url}/archive/%{version}/%{srcname}-%{version}.tar.gz
# Remove pytest-relaxed, which depends on pytest4
Patch3: 0003-remove-pytest-relaxed-dep.patch
# Avoid use of deprecated python-mock by using unittest.mock instead
Patch4: 0004-remove-mock-dep.patch
# A handful of lower-level classes (notably 'paramiko.message.Message' and
# 'paramiko.pkey.PKey') previously returned 'bytes' objects from their
# implementation of '__str__', even under Python 3, and there was never any
# '__bytes__' method; these issues have been fixed by renaming '__str__' to
# '__bytes__' and relying on Python's default "stringification returns the
# output of '__repr__'" behavior re: any real attempts to 'str()' such objects
# (backported from version 3.2)
Patch5: 0005-classes__str__.patch
# Address CVE 2023-48795 (a.k.a. the "Terrapin Attack", a vulnerability found
# in the SSH protocol re: treatment of packet sequence numbers)
# (backported from version 3.4)
Patch6: 0006-terrapin.patch
BuildArch: noarch
%global paramiko_desc \
Paramiko (a combination of the Esperanto words for "paranoid" and "friend") is\
a module for python 2.3 or greater that implements the SSH2 protocol for secure\
(encrypted and authenticated) connections to remote machines. Unlike SSL (aka\
TLS), the SSH2 protocol does not require hierarchical certificates signed by a\
powerful central authority. You may know SSH2 as the protocol that replaced\
telnet and rsh for secure access to remote shells, but the protocol also\
includes the ability to open arbitrary channels to remote services across an\
encrypted tunnel (this is how sftp works, for example).
%description
%{paramiko_desc}
%package -n python%{python3_pkgversion}-%{srcname}
Summary: SSH2 protocol library for python
BuildRequires: python%{python3_pkgversion}-devel
BuildRequires: %{py3_dist bcrypt} >= 3.1.3
BuildRequires: %{py3_dist cryptography} >= 2.5
BuildRequires: %{py3_dist pyasn1} >= 0.1.7
BuildRequires: %{py3_dist pynacl} >= 1.0.1
BuildRequires: %{py3_dist pytest}
BuildRequires: %{py3_dist setuptools}
BuildRequires: %{py3_dist six}
Recommends: %{py3_dist pyasn1} >= 0.1.7
%description -n python%{python3_pkgversion}-%{srcname}
%{paramiko_desc}
Python 3 version.
%package doc
Summary: Docs and demo for SSH2 protocol library for python
BuildRequires: /usr/bin/sphinx-build
Requires: %{name} = %{version}-%{release}
%description doc
%{paramiko_desc}
This is the documentation and demos.
%prep
%autosetup -p1 -n %{srcname}-%{version}
chmod -c a-x demos/*
sed -i -e '/^#!/,1d' demos/*
%build
%py3_build
%install
%py3_install
sphinx-build -b html sites/docs/ html/
rm html/.buildinfo
%check
PYTHONPATH=%{buildroot}%{python3_sitelib} pytest-%{python3_version}
%files -n python%{python3_pkgversion}-%{srcname}
%license LICENSE
%doc NEWS README.rst
%{python3_sitelib}/%{srcname}-*.egg-info/
%{python3_sitelib}/%{srcname}/
%files doc
%doc html/ demos/
%changelog
* Tue Jul 30 2024 Sergey Cherevko <s.cherevko@msvsphere-os.ru> - 2.12.0-2
- Rebuilt for MSVSphere 9.4
* Fri Dec 29 2023 Paul Howarth <paul@city-fan.org> - 2.12.0-2
- Address CVE 2023-48795 (a.k.a. the "Terrapin Attack", a vulnerability found
in the SSH protocol re: treatment of packet sequence numbers) as follows:
- The vulnerability only impacts encrypt-then-MAC digest algorithms in tandem
with CBC ciphers, and ChaCha20-poly1305; of these, Paramiko currently only
implements ``hmac-sha2-(256|512)-etm`` in tandem with 'AES-CBC'
- As the fix for the vulnerability requires both ends of the connection to
cooperate, the below changes will only take effect when the remote end is
OpenSSH ≥ 9.6 (or equivalent, such as Paramiko in server mode, as of this
patch version) and configured to use the new "strict kex" mode
- Paramiko will always attempt to use "strict kex" mode if offered by the
server, unless you override this by specifying 'strict_kex=False' in
'Transport.__init__'
- Paramiko will now raise an 'SSHException' subclass ('MessageOrderError')
when protocol messages are received in unexpected order; this includes
situations like receiving 'MSG_DEBUG' or 'MSG_IGNORE' during initial key
exchange, which are no longer allowed during strict mode
- Key (re)negotiation, i.e. 'MSG_NEWKEYS', whenever it is encountered, now
resets packet sequence numbers (this should be invisible to users during
normal operation, only causing exceptions if the exploit is encountered,
which will usually result in, again, 'MessageOrderError')
- Sequence number rollover will now raise 'SSHException' if it occurs during
initial key exchange (regardless of strict mode status)
- Tweak 'ext-info-(c|s)' detection during KEXINIT protocol phase; the original
implementation made assumptions based on an OpenSSH implementation detail
- 'Transport' grew a new 'packetizer_class' kwarg for overriding the
packet-handler class used internally; this is mostly for testing, but advanced
users may find this useful when doing deep hacks
- A handful of lower-level classes (notably 'paramiko.message.Message' and
'paramiko.pkey.PKey') previously returned 'bytes' objects from their
implementation of '__str__', even under Python 3, and there was never any
'__bytes__' method; these issues have been fixed by renaming '__str__' to
'__bytes__' and relying on Python's default "stringification returns the
output of '__repr__'" behavior re: any real attempts to 'str()' such objects
* Sun Nov 6 2022 Paul Howarth <paul@city-fan.org> - 2.12.0-1
- Update to 2.12.0 (rhbz#2140281)
- Add a 'transport_factory' kwarg to 'SSHClient.connect' for advanced users
to gain more control over early Transport setup and manipulation (GH#2054,
GH#2125)
- Update '~paramiko.client.SSHClient' so it explicitly closes its wrapped
socket object upon encountering socket errors at connection time; this
should help somewhat with certain classes of memory leaks, resource
warnings, and/or errors (though we hasten to remind everyone that Client
and Transport have their own '.close()' methods for use in non-error
situations!) (GH#1822)
- Raise '~paramiko.ssh_exception.SSHException' explicitly when blank private
key data is loaded, instead of the natural result of 'IndexError'; this
should help more bits of Paramiko or Paramiko-adjacent codebases to
correctly handle this class of error (GH#1599, GH#1637)
- Use SPDX-format license tag
* Fri Jul 22 2022 Fedora Release Engineering <releng@fedoraproject.org> - 2.11.0-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild
* Tue Jun 14 2022 Python Maint <python-maint@redhat.com> - 2.11.0-2
- Rebuilt for Python 3.11
* Tue May 17 2022 Paul Howarth <paul@city-fan.org> - 2.11.0-1
- Update to 2.11.0
- Align signature verification algorithm with OpenSSH re: zero-padding
signatures that don't match their nominal size/length; this shouldn't
affect most users, but will help Paramiko-implemented SSH servers handle
poorly behaved clients such as PuTTY (GH#1933)
- OpenSSH 7.7 and older has a bug preventing it from understanding how to
perform SHA2 signature verification for RSA certificates (specifically
certs - not keys), so when we added SHA2 support it broke all clients using
RSA certificates with these servers; this has been fixed in a manner similar
to what OpenSSH's own client does - a version check is performed and the
algorithm used is downgraded if needed (GH#2017)
- Recent versions of Cryptography have deprecated Blowfish algorithm support;
in lieu of an easy method for users to remove it from the list of
algorithms Paramiko tries to import and use, we've decided to remove it
from our "preferred algorithms" list, which will both discourage use of a
weak algorithm, and avoid warnings (GH#2038, GH#2039)
- Windows-native SSH agent support as merged in 2.10 could encounter
'Errno 22' 'OSError' exceptions in some scenarios (e.g. server not cleanly
closing a relevant named pipe); this has been worked around and should be
less problematic (GH#2008, GH#2010)
- Add SSH config token expansion (eg '%%h', '%%p') when parsing 'ProxyJump'
directives (GH#1951)
- Apply unittest 'skipIf' to tests currently using SHA1 in their critical
path, to avoid failures on systems starting to disable SHA1 outright in
their crypto backends (e.g. RHEL 9) (GH#2004, GH#2011)
* Tue Apr 26 2022 Paul Howarth <paul@city-fan.org> - 2.10.4-1
- Update to 2.10.4
- Update 'camelCase' method calls against the 'threading' module to be
'snake_case'; this and related tweaks should fix some deprecation warnings
under Python 3.10 (GH#1838, GH#1870, GH#2028)
- '~paramiko.pkey.PKey' instances' '__eq__' did not have the usual safety
guard in place to ensure they were being compared to another 'PKey' object,
causing occasional spurious 'BadHostKeyException', among other things
(GH#1964, GH#2023, GH#2024)
- Servers offering certificate variants of hostkey algorithms (e.g.
'ssh-rsa-cert-v01@openssh.com') could not have their host keys verified by
Paramiko clients, as it only ever considered non-cert key types for that
part of connection handshaking (GH#2035)
* Mon Mar 21 2022 Paul Howarth <paul@city-fan.org> - 2.10.3-2
- Skip tests that would fail without SHA-1 signing support in backend, such as
on EL-9 (GH#2011)
* Sat Mar 19 2022 Paul Howarth <paul@city-fan.org> - 2.10.3-1
- Update to 2.10.3
- Certificate-based pubkey auth was inadvertently broken when adding SHA2
support in version 2.9.0 (GH#1963, GH#1977)
- Switch from module-global to thread-local storage when recording thread IDs
for a logging helper; this should avoid one flavor of memory leak for
long-running processes (GH#2002, GH#2003)
* Tue Mar 15 2022 Paul Howarth <paul@city-fan.org> - 2.10.2-1
- Update to 2.10.2
- Fix Python 2 compatibility breakage introduced in 2.10.1 (GH#2001)
- Re-enable sftp tests, no longer failing under mock
* Sun Mar 13 2022 Paul Howarth <paul@city-fan.org> - 2.10.1-1
- Update to 2.10.1
- CVE-2022-24302: Creation of new private key files using
'~paramiko.pkey.PKey' subclasses was subject to a race condition between
file creation and mode modification, which could be exploited by an
attacker with knowledge of where the Paramiko-using code would write out
such files; this has been patched by using 'os.open' and 'os.fdopen' to
ensure new files are opened with the correct mode immediately (we've left
the subsequent explicit 'chmod' in place to minimize any possible
disruption, though it may get removed in future backwards-incompatible
updates)
- Add support for the '%%C' token when parsing SSH config files (GH#1976)
- Add support for OpenSSH's Windows agent as a fallback when Putty/WinPageant
isn't available or functional (GH#1509, GH#1837, GH#1868)
- Significantly speed up low-level read/write actions on
'~paramiko.sftp_file.SFTPFile' objects by using 'bytearray'/'memoryview'
(GH#892); this is unlikely to change anything for users of the higher level
methods like 'SFTPClient.get' or 'SFTPClient.getfo', but users of
'SFTPClient.open' will likely see orders of magnitude improvements for
files larger than a few megabytes in size
- Add 'six' explicitly to install-requires; it snuck into active use at some
point but has only been indicated by transitive dependency on 'bcrypt'
until they somewhat-recently dropped it (GH#1985); this will be short-lived
until we drop Python 2 support
* Fri Jan 21 2022 Fedora Release Engineering <releng@fedoraproject.org> - 2.9.2-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild
* Fri Jan 14 2022 Paul Howarth <paul@city-fan.org> - 2.9.2-2
- Avoid use of deprecated python-mock by using unittest.mock instead
https://github.com/paramiko/paramiko/pull/1666
* Sat Jan 8 2022 Paul Howarth <paul@city-fan.org> - 2.9.2-1
- Update to 2.9.2
- Connecting to servers that support 'server-sig-algs' but which have no
overlap between that list and what a Paramiko client supports, now raise
an exception instead of defaulting to 'rsa-sha2-512' (since the use of
'server-sig-algs' allows us to know what the server supports)
- Enhanced log output when connecting to servers that do not support
'server-sig-algs' extensions, making the new-as-of-2.9 defaulting to SHA2
pubkey algorithms more obvious when it kicks in
* Sat Dec 25 2021 Paul Howarth <paul@city-fan.org> - 2.9.1-1
- Update to 2.9.1
- Server-side support for 'rsa-sha2-256' and 'ssh-rsa' wasn't fully operable
after 2.9.0's release (signatures for RSA pubkeys were always run through
'rsa-sha2-512' instead) (GH#1935)
* Fri Dec 24 2021 Paul Howarth <paul@city-fan.org> - 2.9.0-1
- Update to 2.9.0
- Add support for SHA-2 variants of RSA key verification algorithms (as
described in RFC 8332) as well as limited SSH extension negotiation (RFC
8308) (GH#1326, GH#1643, GH#1644, GH#1925)
How SSH servers/clients decide when and how to use this functionality can be
complicated; Paramiko's support is as follows:
- Client verification of server host key during key exchange will now prefer
rsa-sha2-512, rsa-sha2-256, and legacy ssh-rsa algorithms, in that order,
instead of just ssh-rsa
- Note that the preference order of other algorithm families such as
ed25519 and ecdsa has not changed; for example, those two groups are still
preferred over RSA
- Server mode will now offer all 3 RSA algorithms for host key verification
during key exchange, similar to client mode, if it has been configured
with an RSA host key
- Client mode key exchange now sends the ext-info-c flag signaling support
for MSG_EXT_INFO, and support for parsing the latter (specifically, its
server-sig-algs flag) has been added
- Client mode, when performing public key authentication with an RSA key or
cert, will act as follows:
- In all cases, the list of algorithms to consider is based on the new
preferred_pubkeys list and disabled_algorithms; this list, like with
host keys, prefers SHA2-512, SHA2-256 and SHA1, in that order
- When the server does not send server-sig-algs, Paramiko will attempt
the first algorithm in the above list; clients connecting to legacy
servers should thus use disabled_algorithms to turn off SHA2
- When the server does send server-sig-algs, the first algorithm
supported by both ends is used, or if there is none, it falls back to
the previous behavior
- SSH agent support grew the ability to specify algorithm flags when
requesting private key signatures; this is now used to forward SHA2
algorithms when appropriate
- Server mode is now capable of pubkey auth involving SHA-2 signatures from
clients, provided one's server implementation actually provides for doing
so; this includes basic support for sending MSG_EXT_INFO (containing
server-sig-algs only) to clients advertising ext-info-c in their key
exchange list
In order to implement the above, the following API additions were made:
- 'PKey.sign_ssh_data <paramiko.pkey.PKey>': Grew an extra, optional
'algorithm' keyword argument (defaulting to 'None' for most subclasses,
and to "ssh-rsa" for '~paramiko.rsakey.RSAKey')
- A new '~paramiko.ssh_exception.SSHException' subclass was added,
'~paramiko.ssh_exception.IncompatiblePeer', and is raised in all spots
where key exchange aborts due to algorithmic incompatibility; like all
other exceptions in that module, it inherits from 'SSHException', and as
nothing else was changed about the raising (i.e. the attributes and
message text are the same) this change is backwards compatible
- '~paramiko.transport.Transport' grew a '_preferred_pubkeys' attribute and
matching 'preferred_pubkeys' property to match the other, kex-focused,
such members; this allows client pubkey authentication to honor the
'disabled_algorithms' feature
* Mon Nov 29 2021 Paul Howarth <paul@city-fan.org> - 2.8.1-1
- Update to 2.8.1
- Fix listdir failure when server uses a locale (GH#985, GH#992); now on
Python 2.7 SFTPAttributes will decode abbreviated month names correctly
rather than raise 'UnicodeDecodeError'
- Deleting items from '~paramiko.hostkeys.HostKeys' would incorrectly raise
'KeyError' even for valid keys, due to a logic bug (GH#1024)
- Update RSA and ECDSA key decoding subroutines to correctly catch exception
types thrown by modern versions of Cryptography (specifically 'TypeError'
and its internal 'UnsupportedAlgorithm') (GH#1257, GH#1266); these
exception classes will now become '~paramiko.ssh_exception.SSHException'
instances instead of bubbling up
- Update '~paramiko.pkey.PKey' and subclasses to compare ('__eq__') via
direct field/attribute comparison instead of hashing (while retaining the
existing behavior of '__hash__' via a slight refactor) (GH#908)
Warning:
This fixes a security flaw! If you are running Paramiko on 32-bit systems
with low entropy (such as any 32-bit Python 2, or a 32-bit Python 3 that is
running with 'PYTHONHASHSEED=0') it is possible for an attacker to craft a
new keypair from an exfiltrated public key, which Paramiko would consider
equal to the original key.
This could enable attacks such as, but not limited to, the following:
- Paramiko server processes would incorrectly authenticate the attacker
(using their generated private key) as if they were the victim. We see
this as the most plausible attack using this flaw.
- Paramiko client processes would incorrectly validate a connected server
(when host key verification is enabled) while subjected to a
man-in-the-middle attack. This impacts more users than the server-side
version, but also carries higher requirements for the attacker, namely
successful DNS poisoning or other MITM techniques.
* Mon Oct 11 2021 Paul Howarth <paul@city-fan.org> - 2.8.0-1
- Update to 2.8.0
- Administrivia overhaul, including but not limited to:
- Migrate CI to CircleCI
- Primary dev branch is now 'main' (renamed)
- Many README edits for clarity, modernization etc.; including a bunch more
(and consistent) status badges and unification with main project site
index
- PyPI page much more fleshed out (long_description is now filled in with
the README; sidebar links expanded; etc.)
- flake8, pytest configs split out of setup.cfg into their own files
- Invoke/invocations (used by maintainers/contributors) upgraded to modern
versions
- Newer server-side key exchange algorithms not intended to use SHA1
(diffie-hellman-group14-sha256, diffie-hellman-group16-sha512) were
incorrectly using SHA1 after all, due to a bug causing them to ignore the
'hash_algo' class attribute; this has been corrected (GH#1452, GH#1882)
- Add a 'prefetch' keyword argument to 'SFTPClient.get'/'SFTPClient.getfo' so
that users who need to skip SFTP prefetching are able to conditionally turn
it off (GH#1846)
* Fri Jul 23 2021 Fedora Release Engineering <releng@fedoraproject.org> - 2.7.2-6
- Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild
* Fri Jun 04 2021 Python Maint <python-maint@redhat.com> - 2.7.2-5
- Rebuilt for Python 3.10
* Wed Mar 3 2021 Paul Howarth <paul@city-fan.org> - 2.7.2-4
- Drop invoke dependencies as it requires ancient pytest and we can't expect
it to remain around
* Tue Mar 02 2021 Dan Radez <dradez@redhat.com> - 2.7.2-3
- Removing the python-relax dep using upstream patch
https://github.com/paramiko/paramiko/pull/1665/
* Wed Jan 27 2021 Fedora Release Engineering <releng@fedoraproject.org> - 2.7.2-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild
* Mon Aug 31 2020 Paul Howarth <paul@city-fan.org> - 2.7.2-1
- Update to 2.7.2
- Update our CI to catch issues with sdist generation, installation and
testing
- Add missing test suite fixtures directory to MANIFEST.in, reinstating the
ability to run Paramiko's tests from an sdist tarball (GH#1727)
- Remove leading whitespace from OpenSSH RSA test suite static key fixture,
to conform better to spec. (GH#1722)
- Fix incorrect string formatting causing unhelpful error message annotation
when using Kerberos/GSSAPI
- Fix incorrectly swapped order of 'p' and 'q' numbers when loading
OpenSSH-format RSA private keys; at minimum this should address a slowdown
when using such keys, and it also means Paramiko works with Cryptography
3.1 and above, which complains strenuously when this problem appears
(GH#1723)
* Wed Jul 29 2020 Fedora Release Engineering <releng@fedoraproject.org> - 2.7.1-5
- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild
* Sat May 30 2020 Paul Howarth <paul@city-fan.org> - 2.7.1-4
- Avoid FTBFS with pytest 5 (pytest-relaxed pulls in pytest 4)
- Drop explicit dependencies for things that the python dependency generator
finds by itself
* Sun May 24 2020 Miro Hrončok <mhroncok@redhat.com> - 2.7.1-3
- Rebuilt for Python 3.9
* Thu Jan 30 2020 Fedora Release Engineering <releng@fedoraproject.org> - 2.7.1-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild
* Wed Dec 11 2019 Paul Howarth <paul@city-fan.org> - 2.7.1-1
- Update to 2.7.1
- The new-style private key format (added in 2.7.0) suffered from an
unpadding bug that had been fixed earlier for Ed25519 (as that key type has
always used the newer format); that fix has been refactored and applied to
the base key class (GH#1567)
- Fix a bug in support for ECDSA keys under the newly-supported OpenSSH key
format (GH#1565, GH#1566)
* Wed Dec 4 2019 Paul Howarth <paul@city-fan.org> - 2.7.0-1
- Update to 2.7.0
- Implement support for OpenSSH 6.5-style private key files (typically
denoted as having 'BEGIN OPENSSH PRIVATE KEY' headers instead of PEM
format's 'BEGIN RSA PRIVATE KEY' or similar); if you were getting any sort
of weird auth error from "modern" keys generated on newer operating system
releases (such as macOS Mojave), this is the first update to try (GH#602,
GH#618, GH#1313, GH#1343)
- Token expansion in 'ssh_config' used a different method of determining the
local username ('$USER' environment variable), compared to what the (much
older) client connection code does ('getpass.getuser', which includes
'$USER' but may check other variables first, and is generally much more
comprehensive); both modules now use 'getpass.getuser'
- A couple of outright '~paramiko.config.SSHConfig' parse errors were
previously represented as vanilla 'Exception' instances; as part of recent
feature work a more specific exception class,
'~paramiko.ssh_exception.ConfigParseError', has been created; it is now
also used in those older spots, which is naturally backwards compatible
- Implement support for the 'Match' keyword in 'ssh_config' files;
previously, this keyword was simply ignored and keywords inside such blocks
were treated as if they were part of the previous block (GH#717)
- Note: this feature adds a new optional install dependency 'Invoke'
(https://www.pyinvoke.org), for managing 'Match exec' subprocesses
- Additional installation 'extras_require' "flavors" ('ed25519', 'invoke',
and 'all') have been added to our packaging metadata
- Paramiko's use of 'subprocess' for 'ProxyCommand' support is conditionally
imported to prevent issues on limited interpreter platforms like Google
Compute Engine; however, any resulting 'ImportError' was lost instead of
preserved for raising (in the rare cases where a user tried leveraging
'ProxyCommand' in such an environment); this has been fixed
- Perform deduplication of 'IdentityFile' contents during 'ssh_config'
parsing; previously, if your config would result in the same value being
encountered more than once, 'IdentityFile' would contain that many copies
of the same string
- Implement most 'canonical hostname' 'ssh_config' functionality
('CanonicalizeHostname', 'CanonicalDomains', 'CanonicalizeFallbackLocal',
and 'CanonicalizeMaxDots'; 'CanonicalizePermittedCNAMEs' has *not* yet
been implemented) - all were previously silently ignored (GH#897)
- Explicitly document which ssh_config features we currently support;
previously users just had to guess, which is simply no good
- Add new convenience classmethod constructors to
'~paramiko.config.SSHConfig': '~paramiko.config.SSHConfig.from_text',
'~paramiko.config.SSHConfig.from_file', and
'~paramiko.config.SSHConfig.from_path'; no more annoying two-step process!
- Add Recommends: of python3-invoke and python3-pyasn1 for optional
functionality
* Sun Oct 06 2019 Othman Madjoudj <athmane@fedoraproject.org> - 2.6.0-5
- Drop python2 subpackage since it's eol-ed
* Thu Oct 03 2019 Miro Hrončok <mhroncok@redhat.com> - 2.6.0-4
- Rebuilt for Python 3.8.0rc1 (#1748018)
* Mon Aug 19 2019 Miro Hrončok <mhroncok@redhat.com> - 2.6.0-3
- Rebuilt for Python 3.8
* Fri Jul 26 2019 Fedora Release Engineering <releng@fedoraproject.org> - 2.6.0-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild
* Thu Jun 27 2019 Paul Howarth <paul@city-fan.org> - 2.6.0-1
- Update to 2.6.0
- Add a new keyword argument to 'SSHClient.connect' and
'~paramiko.transport.Transport', 'disabled_algorithms', which allows
selectively disabling one or more kex/key/cipher/etc algorithms; this can
be useful when disabling algorithms your target server (or client) does not
support cleanly, or to work around unpatched bugs in Paramiko's own
implementation thereof (GH#1463)
- Tweak many exception classes so their string representations are more
human-friendly; this also includes incidental changes to some 'super()'
calls (GH#1440, GH#1460)
- Add backwards-compatible support for the 'gssapi' GSSAPI library, as the
previous backend ('python-gssapi') has become defunct (GH#584, GH#1166,
GH#1311)
- 'SSHClient.exec_command' now returns a new subclass,
'~paramiko.channel.ChannelStdinFile', rather than a naïve
'~paramiko.channel.ChannelFile' object for its 'stdin' value, which fixes
issues such as hangs when running remote commands that read from stdin
(GH#322)
- Drop gssapi patch as it's no longer needed
- Drop pytest-relaxed patch as it's no longer needed
* Thu Jun 27 2019 Paul Howarth <paul@city-fan.org> - 2.5.1-1
- Update to 2.5.1
- Fix Ed25519 key handling so certain key comment lengths don't cause
'SSHException("Invalid key")' (GH#1306, GH#1400)
* Mon Jun 10 2019 Paul Howarth <paul@city-fan.org> - 2.5.0-1
- Update to 2.5.0
- Add support for encrypt-then-MAC (ETM) schemes and two newer Diffie-Hellman
group key exchange algorithms ('group14', using SHA256; and 'group16',
using SHA512)
- Add support for Curve25519 key exchange
- Raise Cryptography dependency requirement to version 2.5 (from 1.5) and
update some deprecated uses of its API
- Add support for the modern (as of Python 3.3) import location of
'MutableMapping' (used in host key management) to avoid the old location
becoming deprecated in Python 3.8
- Drop hard dependency on pyasn1 as it's only needed for optional GSSAPI
functionality
* Sat Feb 02 2019 Fedora Release Engineering <releng@fedoraproject.org> - 2.4.2-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild
* Tue Oct 9 2018 Paul Howarth <paul@city-fan.org> - 2.4.2-1
- Update to 2.4.2
- Fix exploit (GH#1283, CVE-2018-1000805) in Paramikos server mode (not
client mode) where hostile clients could trick the server into thinking
they were authenticated without actually submitting valid authentication
- Modify protocol message handling such that Transport does not respond to
MSG_UNIMPLEMENTED with its own MSG_UNIMPLEMENTED; this behavior probably
didnt cause any outright errors, but it doesnt seem to conform to the
RFCs and could cause (non-infinite) feedback loops in some scenarios
(usually those involving Paramiko on both ends)
- Add *.pub files to the MANIFEST so distributed source packages contain
some necessary test assets (GH#1262)
- Test suite now requires mock ≥ 2.0.0
* Sat Jul 14 2018 Fedora Release Engineering <releng@fedoraproject.org> - 2.4.1-5
- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild
* Wed Jun 20 2018 Miro Hrončok <mhroncok@redhat.com> - 2.4.1-4
- Rebuilt for Python 3.7
- Remove dependency on on pytest-relaxed
* Fri Mar 16 2018 Paul Howarth <paul@city-fan.org> - 2.4.1-1
- Update to 2.4.1
- Fix a security flaw (GH#1175, CVE-2018-7750) in Paramiko's server mode
(this does not impact client use) where authentication status was not
checked before processing channel-open and other requests typically only
sent after authenticating
- Ed25519 auth key decryption raised an unexpected exception when given a
unicode password string (typical in python 3) (GH#1039)
* Fri Feb 09 2018 Fedora Release Engineering <releng@fedoraproject.org> - 2.4.0-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild
* Sat Nov 18 2017 Athmane Madjoudj <athmane@fedoraproject.org> - 2.4.0-2
- Add gssapi patch back since 2.4.0 still not compatible
- Add missing BR (lost during merge)
* Fri Nov 17 2017 Igor Gnatenko <ignatenkobrain@fedoraproject.org> - 2.4.0-1
- Update to 2.4.0
* Wed Nov 15 2017 Athmane Madjoudj <athmane@fedoraproject.org> - 2.4.0-1
- Update to 2.4.0 (rhbz #1513208)
- Revamp check section
* Sun Oct 29 2017 Athmane Madjoudj <athmane@fedoraproject.org> - 2.3.1-3
- Add a patch to disable gssapi on unsupported version (rhbz #1507174)
* Tue Sep 26 2017 Athmane Madjoudj <athmane@fedoraproject.org> - 2.3.1-2
- Remove weak deps, paramiko does not support recent gssapi (rhbz #1496148)
* Sat Sep 23 2017 Athmane Madjoudj <athmane@fedoraproject.org> - 2.3.1-1
- Update to 2.3.1 (rhbz #1494764)
* Wed Sep 20 2017 Paul Howarth <paul@city-fan.org> - 2.3.0-1
- 2.3.0.
* Thu Jul 27 2017 Fedora Release Engineering <releng@fedoraproject.org> - 2.2.1-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild
* Wed Jun 14 2017 Paul Howarth <paul@city-fan.org> - 2.2.1-1
- 2.2.1.
* Sun Jun 11 2017 Paul Howarth <paul@city-fan.org> - 2.2.0-1
- 2.2.0.
* Wed Feb 22 2017 Paul Howarth <paul@city-fan.org> - 2.1.2-1
- 2.1.2.
* Sat Feb 11 2017 Fedora Release Engineering <releng@fedoraproject.org> - 2.1.1-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild
* Mon Dec 19 2016 Miro Hrončok <mhroncok@redhat.com> - 2.1.1-2
- Rebuild for Python 3.6
* Fri Dec 16 2016 Jon Ciesla <limburgher@gmail.com> - 2.1.1-1
- 2.1.1.
* Fri Dec 09 2016 Jon Ciesla <limburgher@gmail.com> - 2.1.0-1
- 2.1.0.
* Fri Dec 09 2016 Jon Ciesla <limburgher@gmail.com> - 2.0.2-1
- 2.0.2.
* Tue Jul 19 2016 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 2.0.0-2
- https://fedoraproject.org/wiki/Changes/Automatic_Provides_for_Python_RPM_Packages
* Fri Apr 29 2016 Igor Gnatenko <ignatenko@redhat.com> - 2.0.0-1
- Update to 2.0.0 (RHBZ #1331737)
* Sun Mar 27 2016 Igor Gnatenko <i.gnatenko.brain@gmail.com> - 1.16.0-1
- Update to 1.16.0
- Adopt to new packaging guidelines
* Thu Feb 04 2016 Fedora Release Engineering <releng@fedoraproject.org> - 1.15.2-5
- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild
* Tue Nov 10 2015 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.15.2-4
- Rebuilt for https://fedoraproject.org/wiki/Changes/python3.5
* Thu Jun 18 2015 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.15.2-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild
* Sun Mar 22 2015 Peter Robinson <pbrobinson@fedoraproject.org> 1.15.2-2
- Use %%license
- Move duplicated docs to single doc sub package
- Remove old F-15 conditionals
* Tue Dec 23 2014 Athmane Madjoudj <athmane@fedoraproject.org> 1.15.2-1
- Update to 1.15.2
* Mon Nov 24 2014 Athmane Madjoudj <athmane@fedoraproject.org> 1.15.1-5
- Add conditional to exclude EL since does not have py3
* Sat Nov 15 2014 Athmane Madjoudj <athmane@fedoraproject.org> 1.15.1-4
- py3dir creation should be in prep section
* Fri Nov 14 2014 Athmane Madjoudj <athmane@fedoraproject.org> 1.15.1-3
- Build each pkg in a clean dir
* Fri Nov 14 2014 Athmane Madjoudj <athmane@fedoraproject.org> 1.15.1-2
- Add support for python3
- Add BR -devel for python macros.
* Fri Oct 17 2014 Jeffrey C. Ollie <jeff@ocjtech.us> - 1.15.1-1
- Update to 1.15.1
* Fri Jun 13 2014 Orion Poplawski <orion@cora.nwra.com> - 1.12.4-1
- Update to 1.12.4
* Sat Jun 07 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.12.2-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild
* Tue Feb 25 2014 Orion Poplawski <orion@cora.nwra.com> - 1.12.2-1
- Update to 1.12.2
* Wed Jan 22 2014 Orion Poplawski <orion@cora.nwra.com> - 1.11.3-1
- Update to 1.11.3
* Mon Oct 21 2013 Orion Poplawski <orion@cora.nwra.com> - 1.11.0-1
- Update to 1.11.0
* Sun Aug 04 2013 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.10.1-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild
* Thu May 9 2013 Jeffrey Ollie <jeff@ocjtech.us> - 1.10.1-1
- Update to 1.10.1
* Thu Feb 14 2013 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.9.0-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild
* Wed Jan 2 2013 Jeffrey Ollie <jeff@ocjtech.us> - 1.9.0-1
- Update to 1.9.0
* Sat Jul 21 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.7.7.1-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild
* Sat Jan 14 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.7.7.1-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild
* Wed Jul 6 2011 Jeffrey C. Ollie <jeff@ocjtech.us> - 1.7.7.1-1
- v1.7.7.1 (George) 21may11
- -------------------------
- * Make the verification phase of SFTP.put optional (Larry Wright)
- * Patches to fix AIX support (anonymous)
- * Patch from Michele Bertoldi to allow compression to be turned on in the
- client constructor.
- * Patch from Shad Sharma to raise an exception if the transport isn't active
- when you try to open a new channel.
- * Stop leaking file descriptors in the SSH agent (John Adams)
- * More fixes for Windows address family support (Andrew Bennetts)
- * Use Crypto.Random rather than Crypto.Util.RandomPool
- (Gary van der Merwe, #271791)
- * Support for openssl keys (tehfink)
- * Fix multi-process support by calling Random.atfork (sugarc0de)
* Tue Feb 08 2011 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.7.6-4
- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild
* Tue Jan 4 2011 Toshio Kuratomi <toshio@fedoraproject.org> - 1.7.6-3
- Patch to address deprecation warning from pycrypto
- Simplify build as shown in new python guidelines
- Enable test suite
* Thu Jul 22 2010 David Malcolm <dmalcolm@redhat.com> - 1.7.6-2
- Rebuilt for https://fedoraproject.org/wiki/Features/Python_2.7/MassRebuild
* Mon Nov 2 2009 Jeffrey C. Ollie <jeff@ocjtech.us> - 1.7.6-1
- v1.7.6 (Fanny) 1nov09
- ---------------------
- * fixed bugs 411099 (sftp chdir isn't unicode-safe), 363163 & 411910 (more
- IPv6 problems on windows), 413850 (race when server closes the channel),
- 426925 (support port numbers in host keys)
* Tue Oct 13 2009 Jeremy Katz <katzj@fedoraproject.org> - 1.7.5-2
- Fix race condition (#526341)
* Thu Jul 23 2009 Jeffrey C. Ollie <jeff@ocjtech.us> - 1.7.5-1
- v1.7.5 (Ernest) 19jul09
- -----------------------
- * added support for ARC4 cipher and CTR block chaining (Denis Bernard)
- * made transport threads daemonize, to fix python 2.6 atexit behavior
- * support unicode hostnames, and IP6 addresses (Maxime Ripard, Shikhar
- Bhushan)
- * various small bug fixes
* Thu Feb 26 2009 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 1.7.4-5
- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild
* Mon Feb 16 2009 Jeffrey C. Ollie <jeff@ocjtech.us> - 1.7.4-4
- Add demos as documentation. BZ#485742
* Sat Nov 29 2008 Ignacio Vazquez-Abrams <ivazqueznet+rpm@gmail.com> - 1.7.4-3
- Rebuild for Python 2.6
* Wed Sep 3 2008 Tom "spot" Callaway <tcallawa@redhat.com> - 1.7.4-2
- fix license tag
* Sun Jul 6 2008 Jeffrey C. Ollie <jeff@ocjtech.us> - 1.7.4-1
- Update to 1.7.4
* Mon Mar 24 2008 Jeffrey C. Ollie <jeff@ocjtech.us> - 1.7.3-1
- Update to 1.7.3.
* Tue Jan 22 2008 Jeffrey C. Ollie <jeff@ocjtech.us> - 1.7.2-1
- Update to 1.7.2.
- Remove upstreamed patch.
* Mon Jan 14 2008 Jeffrey C. Ollie <jeff@ocjtech.us> - 1.7.1-3
- Update to latest Python packaging guidelines.
- Apply patch that fixes insecure use of RandomPool.
* Thu Jul 19 2007 Jeffrey C. Ollie <jeff@ocjtech.us> - 1.7.1-2
- Bump rev
* Thu Jul 19 2007 Jeffrey C. Ollie <jeff@ocjtech.us> - 1.7.1-1
- Update to 1.7.1
* Sat Dec 09 2006 Toshio Kuratomi <toshio@tiki-lounge.com> - 1.6.4-1
- Update to 1.6.4
- Upstream is now shipping tarballs
- Bump for python 2.5 in devel
* Mon Oct 9 2006 Jeffrey C. Ollie <jeff@ocjtech.us> - 1.6.2-1
- Update to 1.6.2
* Sat Sep 16 2006 Shahms E. King <shahms@shahms.com> 1.6.1-3
- Rebuild for FC6
* Fri Aug 11 2006 Shahms E. King <shahms@shahms.com> 1.6.1-2
- Include, don't ghost .pyo files per new guidelines
* Tue Aug 08 2006 Shahms E. King <shahms@shahms.com> 1.6.1-1
- Update to new upstream version
* Fri Jun 02 2006 Shahms E. King <shahms@shahms.com> 1.6-1
- Update to new upstream version
- ghost the .pyo files
* Fri May 05 2006 Shahms E. King <shahms@shahms.com> 1.5.4-2
- Fix source line and rebuild
* Fri May 05 2006 Shahms E. King <shahms@shahms.com> 1.5.4-1
- Update to new upstream version
* Wed Apr 12 2006 Shahms E. King <shahms@shahms.com> 1.5.3-1
- Initial package
Loading…
Cancel
Save