Skip to content

Commit

Permalink
Merge branch 'trunk' into patch-1
Browse files Browse the repository at this point in the history
  • Loading branch information
glyph committed Jul 21, 2023
2 parents 08745d7 + 949f4b6 commit ca1a794
Show file tree
Hide file tree
Showing 27 changed files with 742 additions and 603 deletions.
3 changes: 0 additions & 3 deletions docs/installation/howto/optional.rst
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ The following optional dependencies are supported:

* `cryptography`_

* **conch-nacl** - **conch** options and `PyNaCl`_ to support Ed25519 keys on systems with OpenSSL < 1.1.1b.

* **soap** - the `SOAPpy`_ package to work with SOAP.

* **serial** - the `pyserial`_ package to work with serial data.
Expand Down Expand Up @@ -65,7 +63,6 @@ The following optional dependencies are supported:
.. _pyOpenSSL: https://pypi.python.org/pypi/pyOpenSSL
.. _service_identity: https://pypi.python.org/pypi/service_identity
.. _cryptography: https://pypi.python.org/pypi/cryptography
.. _PyNaCl: https://pypi.python.org/pypi/PyNaCl
.. _SOAPpy: https://pypi.python.org/pypi/SOAPpy
.. _pyserial: https://pypi.python.org/pypi/pyserial
.. _pyobjc: https://pypi.python.org/pypi/pyobjc
Expand Down
2 changes: 1 addition & 1 deletion docs/web/howto/using-twistedweb.rst
Original file line number Diff line number Diff line change
Expand Up @@ -770,7 +770,7 @@ exists.
There is a small set of known mime types and encodings which augment the default mime types provided by the Python standard library `mimetypes`.
You can always modify the content type and encoding mappings by manipulating the instance variables.

For example to recognize WOFF File Format 2.0 and set the right Content-Type header you can modify the `contentTypes` member of an instance::
For example to recognize WOFF File Format 2.0 and set the right Content-Type header you can modify the `contentTypes` member of an instance:

.. code-block:: python
Expand Down
8 changes: 1 addition & 7 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,6 @@ conch = [
"bcrypt >= 3.1.3",
]

conch-nacl = [
"twisted[conch]",
# Used to support Ed25519 keys on systems with OpenSSL < 1.1.1b
"PyNaCl",
]

serial = [
"pyserial >= 3.0",
"pywin32 != 226; platform_system == 'Windows'",
Expand Down Expand Up @@ -140,7 +134,7 @@ gtk-platform = [
]

mypy = [
"twisted[dev,all-non-platform,conch-nacl]",
"twisted[dev,all-non-platform]",
"mypy==0.981",
"mypy-zope==0.3.11",
"mypy-extensions==0.4.3",
Expand Down
1 change: 1 addition & 0 deletions src/twisted/conch/newsfragments/11871.removal
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Due to changes in the way raw private key byte serialization are handled in Cryptography, and widespread support for Ed25519 in current versions of OpenSSL, we no longer support PyNaCl as a fallback for Ed25519 keys in Conch.
104 changes: 0 additions & 104 deletions src/twisted/conch/ssh/_keys_pynacl.py

This file was deleted.

15 changes: 2 additions & 13 deletions src/twisted/conch/ssh/keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import warnings
from base64 import b64encode, decodebytes, encodebytes
from hashlib import md5, sha256
from typing import Optional, Type

import bcrypt
from cryptography import utils
Expand Down Expand Up @@ -61,18 +60,8 @@
}


Ed25519PublicKey: Optional[Type[ed25519.Ed25519PublicKey]]
Ed25519PrivateKey: Optional[Type[ed25519.Ed25519PrivateKey]]

if default_backend().ed25519_supported():
Ed25519PublicKey = ed25519.Ed25519PublicKey
Ed25519PrivateKey = ed25519.Ed25519PrivateKey
else: # pragma: no cover
try:
from twisted.conch.ssh._keys_pynacl import Ed25519PrivateKey, Ed25519PublicKey
except ImportError:
Ed25519PublicKey = None
Ed25519PrivateKey = None
Ed25519PublicKey = ed25519.Ed25519PublicKey
Ed25519PrivateKey = ed25519.Ed25519PrivateKey


class BadKeyError(Exception):
Expand Down
157 changes: 1 addition & 156 deletions src/twisted/conch/test/test_keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,15 @@
if cryptography is None:
skipCryptography = "Cannot run without cryptography."

_keys_pynacl = requireModule("twisted.conch.ssh._keys_pynacl")


if cryptography:
from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding

from twisted.conch.ssh import common, keys, sexpy

ED25519_SUPPORTED = (
default_backend().ed25519_supported() or _keys_pynacl is not None
)
ED25519_SUPPORTED = default_backend().ed25519_supported()
else:
ED25519_SUPPORTED = False

Expand Down Expand Up @@ -1665,156 +1660,6 @@ def test_reprPrivateEd25519(self):
)


class PyNaClKeyTests(KeyTests):
"""
Key tests, but forcing the use of C{PyNaCl}.
"""

if cryptography is None:
skip = skipCryptography
if _keys_pynacl is None:
skip = "Cannot run without PyNaCl"

def setUp(self):
super().setUp()
self.patch(keys, "Ed25519PublicKey", _keys_pynacl.Ed25519PublicKey)
self.patch(keys, "Ed25519PrivateKey", _keys_pynacl.Ed25519PrivateKey)

def test_naclPrivateBytes(self):
"""
L{_keys_pynacl.Ed25519PrivateKey.private_bytes} and
L{_keys_pynacl.Ed25519PrivateKey.from_private_bytes} round-trip.
"""
from cryptography.hazmat.primitives import serialization

key = _keys_pynacl.Ed25519PrivateKey.generate()
key_bytes = key.private_bytes(
serialization.Encoding.Raw,
serialization.PrivateFormat.Raw,
serialization.NoEncryption(),
)
self.assertIsInstance(key_bytes, bytes)
self.assertEqual(
key, _keys_pynacl.Ed25519PrivateKey.from_private_bytes(key_bytes)
)

def test_naclPrivateBytesInvalidParameters(self):
"""
L{_keys_pynacl.Ed25519PrivateKey.private_bytes} only accepts certain parameters.
"""
from cryptography.hazmat.primitives import serialization

key = _keys_pynacl.Ed25519PrivateKey.generate()
self.assertRaises(
ValueError,
key.private_bytes,
serialization.Encoding.PEM,
serialization.PrivateFormat.Raw,
serialization.NoEncryption(),
)
self.assertRaises(
ValueError,
key.private_bytes,
serialization.Encoding.Raw,
serialization.PrivateFormat.PKCS8,
serialization.NoEncryption(),
)
self.assertRaises(
ValueError,
key.private_bytes,
serialization.Encoding.Raw,
serialization.PrivateFormat.Raw,
serialization.BestAvailableEncryption(b"password"),
)

def test_naclPrivateHash(self):
"""
L{_keys_pynacl.Ed25519PrivateKey.__hash__} allows instances to be hashed.
"""
key = _keys_pynacl.Ed25519PrivateKey.generate()
d = {key: True}
self.assertTrue(d[key])

def test_naclPrivateEquality(self):
"""
L{_keys_pynacl.Ed25519PrivateKey} implements equality test methods.
"""
key1 = _keys_pynacl.Ed25519PrivateKey.generate()
key2 = _keys_pynacl.Ed25519PrivateKey.generate()
self.assertEqual(key1, key1)
self.assertNotEqual(key1, key2)
self.assertNotEqual(key1, bytes(key1))

def test_naclPublicBytes(self):
"""
L{_keys_pynacl.Ed25519PublicKey.public_bytes} and
L{_keys_pynacl.Ed25519PublicKey.from_public_bytes} round-trip.
"""
from cryptography.hazmat.primitives import serialization

key = _keys_pynacl.Ed25519PrivateKey.generate().public_key()
key_bytes = key.public_bytes(
serialization.Encoding.Raw, serialization.PublicFormat.Raw
)
self.assertIsInstance(key_bytes, bytes)
self.assertEqual(
key, _keys_pynacl.Ed25519PublicKey.from_public_bytes(key_bytes)
)

def test_naclPublicBytesInvalidParameters(self):
"""
L{_keys_pynacl.Ed25519PublicKey.public_bytes} only accepts certain parameters.
"""
from cryptography.hazmat.primitives import serialization

key = _keys_pynacl.Ed25519PrivateKey.generate().public_key()
self.assertRaises(
ValueError,
key.public_bytes,
serialization.Encoding.PEM,
serialization.PublicFormat.Raw,
)
self.assertRaises(
ValueError,
key.public_bytes,
serialization.Encoding.Raw,
serialization.PublicFormat.PKCS1,
)

def test_naclPublicHash(self):
"""
L{_keys_pynacl.Ed25519PublicKey.__hash__} allows instances to be hashed.
"""
key = _keys_pynacl.Ed25519PrivateKey.generate().public_key()
d = {key: True}
self.assertTrue(d[key])

def test_naclPublicEquality(self):
"""
L{_keys_pynacl.Ed25519PublicKey} implements equality test methods.
"""
key1 = _keys_pynacl.Ed25519PrivateKey.generate().public_key()
key2 = _keys_pynacl.Ed25519PrivateKey.generate().public_key()
self.assertEqual(key1, key1)
self.assertNotEqual(key1, key2)
self.assertNotEqual(key1, bytes(key1))

def test_naclVerify(self):
"""
L{_keys_pynacl.Ed25519PublicKey.verify} raises appropriate exceptions.
"""
key = _keys_pynacl.Ed25519PrivateKey.generate()
self.assertIsInstance(key, keys.Ed25519PrivateKey)
signature = key.sign(b"test data")
self.assertIsNone(key.public_key().verify(signature, b"test data"))
self.assertRaises(
InvalidSignature, key.public_key().verify, signature, b"wrong data"
)
self.assertRaises(
InvalidSignature, key.public_key().verify, b"0" * 64, b"test data"
)


class PersistentRSAKeyTests(unittest.TestCase):
"""
Tests for L{keys._getPersistentRSAKey}.
Expand Down
4 changes: 2 additions & 2 deletions src/twisted/conch/test/test_tap.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
Tests for L{twisted.conch.tap}.
"""

from typing import Any
from typing import Any, Tuple, Union

from twisted.application.internet import StreamServerEndpointService
from twisted.cred import error
Expand Down Expand Up @@ -131,7 +131,7 @@ def test_authSuccess(self) -> Deferred[None]:
correct = UsernamePassword(*self.usernamePassword)
d = checker.requestAvatarId(correct)

def checkSuccess(username: bytes) -> None:
def checkSuccess(username: Union[bytes, Tuple[()]]) -> None:
self.assertEqual(username, correct.username)

return d.addCallback(checkSuccess)
Expand Down

0 comments on commit ca1a794

Please sign in to comment.