From 2c574ea29456726177eece3d8f740182ea34f0b4 Mon Sep 17 00:00:00 2001 From: Josh Snyder Date: Thu, 14 Oct 2021 18:29:37 -0700 Subject: 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. --- paramiko/agent.py | 4 ++++ paramiko/dsskey.py | 5 +++-- paramiko/ecdsakey.py | 15 +++++++-------- paramiko/ed25519key.py | 5 +++-- 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): """ -- cgit v1.2.3