diff options
author | Josh Snyder <josh.snyder@robinhood.com> | 2021-10-14 18:29:37 -0700 |
---|---|---|
committer | Jeff Forcier <jeff@bitprophet.org> | 2021-11-28 20:24:17 -0500 |
commit | 2c574ea29456726177eece3d8f740182ea34f0b4 (patch) | |
tree | 8da9da8ddc7bb958e35a9601f51e9ab6a63d77ea | |
parent | 0344146de514ab1f2643bad5bfce0a92d4dcf1ee (diff) | |
download | paramiko-2c574ea29456726177eece3d8f740182ea34f0b4.tar.gz |
Check all data on keys when comparing for equality
This eliminates the possibility that a hash collision results in two PKey
objects that == each other.
-rw-r--r-- | paramiko/agent.py | 4 | ||||
-rw-r--r-- | paramiko/dsskey.py | 5 | ||||
-rw-r--r-- | paramiko/ecdsakey.py | 15 | ||||
-rw-r--r-- | paramiko/ed25519key.py | 5 | ||||
-rw-r--r-- | paramiko/pkey.py | 14 |
5 files changed, 29 insertions, 14 deletions
diff --git a/paramiko/agent.py b/paramiko/agent.py index 622b95e4..c7c8b7cb 100644 --- a/paramiko/agent.py +++ b/paramiko/agent.py @@ -407,6 +407,10 @@ class AgentKey(PKey): def get_name(self): return self.name + @property + def _fields(self): + raise NotImplementedError + def sign_ssh_data(self, data): msg = Message() msg.add_byte(cSSH2_AGENTC_SIGN_REQUEST) diff --git a/paramiko/dsskey.py b/paramiko/dsskey.py index 7e74836c..09d6f648 100644 --- a/paramiko/dsskey.py +++ b/paramiko/dsskey.py @@ -92,8 +92,9 @@ class DSSKey(PKey): def __str__(self): return self.asbytes() - def __hash__(self): - return hash((self.get_name(), self.p, self.q, self.g, self.y)) + @property + def _fields(self): + return (self.get_name(), self.p, self.q, self.g, self.y) def get_name(self): return "ssh-dss" diff --git a/paramiko/ecdsakey.py b/paramiko/ecdsakey.py index 3d3d09be..a59017f5 100644 --- a/paramiko/ecdsakey.py +++ b/paramiko/ecdsakey.py @@ -194,14 +194,13 @@ class ECDSAKey(PKey): def __str__(self): return self.asbytes() - def __hash__(self): - return hash( - ( - self.get_name(), - self.verifying_key.public_numbers().x, - self.verifying_key.public_numbers().y, - ) - ) + @property + def _fields(self): + return ( + self.get_name(), + self.verifying_key.public_numbers().x, + self.verifying_key.public_numbers().y, + ) def get_name(self): return self.ecdsa_curve.key_format_identifier diff --git a/paramiko/ed25519key.py b/paramiko/ed25519key.py index b584f521..7b19e352 100644 --- a/paramiko/ed25519key.py +++ b/paramiko/ed25519key.py @@ -174,12 +174,13 @@ class Ed25519Key(PKey): m.add_string(v.encode()) return m.asbytes() - def __hash__(self): + @property + def _fields(self): if self.can_sign(): v = self._signing_key.verify_key else: v = self._verifying_key - return hash((self.get_name(), v)) + return (self.get_name(), v) def get_name(self): return "ssh-ed25519" diff --git a/paramiko/pkey.py b/paramiko/pkey.py index a54d502d..fed68da8 100644 --- a/paramiko/pkey.py +++ b/paramiko/pkey.py @@ -20,6 +20,9 @@ Common API for all public keys. """ +from abc import ABC +from abc import abstractproperty +from abc import abstractmethod import base64 from binascii import unhexlify import os @@ -59,7 +62,7 @@ def _unpad_openssh(data): return data[:-padding_length] -class PKey(object): +class PKey(ABC): """ Base class for public keys. """ @@ -140,7 +143,14 @@ class PKey(object): return cmp(self.asbytes(), other.asbytes()) # noqa def __eq__(self, other): - return hash(self) == hash(other) + return self._fields == other._fields + + def __hash__(self): + return hash(self._fields) + + @abstractproperty + def _fields(self): + pass def get_name(self): """ |