summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Forcier <jeff@bitprophet.org>2021-11-27 22:13:23 -0500
committerJeff Forcier <jeff@bitprophet.org>2021-11-28 20:24:17 -0500
commitaca7613171937334c47377faf0cf2e4a9126c0d4 (patch)
tree37d8fa745f98ffeb3efba2ae8c36a6f7046c3b5d
parentf4b5ce36e75a2aca2b11ef54b0ce04e1188f667c (diff)
downloadparamiko-aca7613171937334c47377faf0cf2e4a9126c0d4.tar.gz
Pre-patch test proving security flaw re: 32bit key hash comparisons
-rw-r--r--tests/badhash_key1.ed25519.key7
-rw-r--r--tests/badhash_key2.ed25519.key7
-rw-r--r--tests/test_pkey.py18
-rw-r--r--tests/util.py19
4 files changed, 49 insertions, 2 deletions
diff --git a/tests/badhash_key1.ed25519.key b/tests/badhash_key1.ed25519.key
new file mode 100644
index 00000000..3e33781b
--- /dev/null
+++ b/tests/badhash_key1.ed25519.key
@@ -0,0 +1,7 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZWQyNTUx
+OQAAACCULQjdmVfwpbDAFYz4mhKo6aCiAfkbaC+dEdq5eP1R9QAAAIjXZhzv12Yc7wAAAAtzc2gt
+ZWQyNTUxOQAAACCULQjdmVfwpbDAFYz4mhKo6aCiAfkbaC+dEdq5eP1R9QAAAEByeJbhZUBL2aJ6
+wP85amzQuqDJRrNyAGMtDBJ43SURxpQtCN2ZV/ClsMAVjPiaEqjpoKIB+RtoL50R2rl4/VH1AAAA
+AAECAwQF
+-----END OPENSSH PRIVATE KEY-----
diff --git a/tests/badhash_key2.ed25519.key b/tests/badhash_key2.ed25519.key
new file mode 100644
index 00000000..bf48edac
--- /dev/null
+++ b/tests/badhash_key2.ed25519.key
@@ -0,0 +1,7 @@
+-----BEGIN OPENSSH PRIVATE KEY-----
+b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZWQyNTUx
+OQAAACACJbNmFu2Bk34HArxhiRYajoIN03Vr0umfNvsc9atE0AAAAIi5+po1ufqaNQAAAAtzc2gt
+ZWQyNTUxOQAAACACJbNmFu2Bk34HArxhiRYajoIN03Vr0umfNvsc9atE0AAAAECh/ZzZJDOZGnil
+BxJMm+nOhBpc07IVBjU1ii+S8zqFaAIls2YW7YGTfgcCvGGJFhqOgg3TdWvS6Z82+xz1q0TQAAAA
+AAECAwQF
+-----END OPENSSH PRIVATE KEY-----
diff --git a/tests/test_pkey.py b/tests/test_pkey.py
index 18c27bbe..caa6d7b3 100644
--- a/tests/test_pkey.py
+++ b/tests/test_pkey.py
@@ -31,8 +31,9 @@ from paramiko.py3compat import StringIO, byte_chr, b, bytes, PY2
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateNumbers
from mock import patch
+import pytest
-from .util import _support
+from .util import _support, is_low_entropy
# from openssh's ssh-keygen
@@ -551,6 +552,21 @@ class KeyTest(unittest.TestCase):
self.assertTrue(not pub.can_sign())
self.assertEqual(key, pub)
+ # No point testing on systems that never exhibited the bug originally
+ @pytest.mark.skipif(
+ not is_low_entropy(), reason="Not a low-entropy system"
+ )
+ def test_ed25519_32bit_collision(self):
+ # Re: 2021.10.19 security report email: two different private keys
+ # which Paramiko compared as equal on low-entropy platforms.
+ original = Ed25519Key.from_private_key_file(
+ _support("badhash_key1.ed25519.key")
+ )
+ generated = Ed25519Key.from_private_key_file(
+ _support("badhash_key2.ed25519.key")
+ )
+ assert original != generated
+
def test_ed25519_nonbytes_password(self):
# https://github.com/paramiko/paramiko/issues/1039
Ed25519Key.from_private_key_file(
diff --git a/tests/util.py b/tests/util.py
index 9057f516..1355ce8a 100644
--- a/tests/util.py
+++ b/tests/util.py
@@ -1,11 +1,12 @@
from os.path import dirname, realpath, join
import os
+import struct
import sys
import unittest
import pytest
-from paramiko.py3compat import builtins
+from paramiko.py3compat import builtins, PY2
from paramiko.ssh_gss import GSS_AUTH_AVAILABLE
@@ -127,3 +128,19 @@ def k5shell(args=None):
if not args:
args = [os.environ.get("SHELL", "bash")]
sys.exit(subprocess.call(args))
+
+
+def is_low_entropy():
+ """
+ Attempts to detect whether running interpreter is low-entropy.
+
+ Classified as being in 32-bit mode under Python 2, or 32-bit mode and with
+ the hash seed set to zero under Python 3.
+ """
+ is_32bit = struct.calcsize("P") == 32 / 8
+ if PY2:
+ return is_32bit
+ else:
+ # I don't see a way to tell internally if the hash seed was set this
+ # way, but env should be plenty sufficient, this is only for testing.
+ return is_32bit and os.environ.get("PYTHONHASHSEED", None) == "0"