summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Snyder <josh.snyder@robinhood.com>2021-10-14 18:29:37 -0700
committerJeff Forcier <jeff@bitprophet.org>2021-11-28 20:24:17 -0500
commit2c574ea29456726177eece3d8f740182ea34f0b4 (patch)
tree8da9da8ddc7bb958e35a9601f51e9ab6a63d77ea
parent0344146de514ab1f2643bad5bfce0a92d4dcf1ee (diff)
downloadparamiko-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.py4
-rw-r--r--paramiko/dsskey.py5
-rw-r--r--paramiko/ecdsakey.py15
-rw-r--r--paramiko/ed25519key.py5
-rw-r--r--paramiko/pkey.py14
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):
"""