Hello community,

here is the log from the commit of package python-asyncssh for openSUSE:Factory 
checked in at 2019-04-23 14:38:50
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-asyncssh (Old)
 and      /work/SRC/openSUSE:Factory/.python-asyncssh.new.5536 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-asyncssh"

Tue Apr 23 14:38:50 2019 rev:6 rq:697004 version:1.16.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-asyncssh/python-asyncssh.changes  
2019-04-02 09:22:51.184731969 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-asyncssh.new.5536/python-asyncssh.changes    
    2019-04-23 14:38:58.697576472 +0200
@@ -1,0 +2,6 @@
+Tue Apr 23 08:29:31 UTC 2019 - Ondřej Súkup <[email protected]>
+
+- add old_openssl.patch - return support for ed25519/448 via libnacl
+  on systems with older openSSL
+
+-------------------------------------------------------------------

New:
----
  old_openssl.patch

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-asyncssh.spec ++++++
--- /var/tmp/diff_new_pack.PmVmlH/_old  2019-04-23 14:39:00.453577376 +0200
+++ /var/tmp/diff_new_pack.PmVmlH/_new  2019-04-23 14:39:00.457577378 +0200
@@ -26,6 +26,7 @@
 Group:          Development/Languages/Python
 Url:            http://asyncssh.timeheart.net
 Source:         
https://files.pythonhosted.org/packages/source/a/asyncssh/asyncssh-%{version}.tar.gz
+Patch0:         old_openssl.patch 
 BuildRequires:  %{python_module bcrypt >= 3.1.3}
 BuildRequires:  %{python_module cryptography >= 2.6.1}
 BuildRequires:  %{python_module gssapi >= 1.2.0}
@@ -52,6 +53,7 @@
 
 %prep
 %setup -q -n asyncssh-%{version}
+%patch0 -p1
 
 %build
 %python_build

++++++ old_openssl.patch ++++++
>From 1dee113bb3e4a6888de562b0413e9abd6a0f0f04 Mon Sep 17 00:00:00 2001
From: Ron Frederick <[email protected]>
Date: Fri, 19 Apr 2019 16:19:43 -0700
Subject: [PATCH] Restore libnacl support for curve25519/ed25519 as a fallback
 for PyCA

This commit restores the ability to use libnacl/libsodium for
curve25519/ed25519 when the version of OpenSSL available through
the cryptography package does not have this support.

This commit also fixes a bug where ed25519 and ed448 were being
registered as valid host key algorithms even when support for them was
not available on the system.
---
 asyncssh/crypto/ed.py | 273 +++++++++++++++++++++++++++++++-----------
 asyncssh/eddsa.py     |  16 ++-
 docs/api.rst          |  10 +-
 3 files changed, 219 insertions(+), 80 deletions(-)

Index: asyncssh-1.16.1/asyncssh/crypto/ed.py
===================================================================
--- asyncssh-1.16.1.orig/asyncssh/crypto/ed.py
+++ asyncssh-1.16.1/asyncssh/crypto/ed.py
@@ -18,7 +18,10 @@
 # Contributors:
 #     Ron Frederick - initial implementation, API, and documentation
 
-"""A shim around PyCA for Edwards-curve keys and key exchange"""
+"""A shim around PyCA and libnacl for Edwards-curve keys and key exchange"""
+
+import ctypes
+import os
 
 from cryptography.exceptions import InvalidSignature
 from cryptography.hazmat.backends.openssl import backend
@@ -38,112 +41,240 @@ curve25519_available = backend.x25519_su
 curve448_available = backend.x448_supported()
 
 
-class _EdKey(PyCAKey):
-    """Base class for shim around PyCA for Ed25519/Ed448 keys"""
+if ed25519_available: # pragma: no branch
+    class _EdKey(PyCAKey):
+        """Base class for shim around PyCA for Ed25519/Ed448 keys"""
 
-    def __init__(self, pyca_key, pub, priv=None):
-        super().__init__(pyca_key)
+        def __init__(self, pyca_key, pub, priv=None):
+            super().__init__(pyca_key)
 
-        self._pub = pub
-        self._priv = priv
+            self._pub = pub
+            self._priv = priv
 
-    @property
-    def public_value(self):
-        """Return the public value encoded as a byte string"""
+        @property
+        def public_value(self):
+            """Return the public value encoded as a byte string"""
 
-        return self._pub
+            return self._pub
 
-    @property
-    def private_value(self):
-        """Return the private value encoded as a byte string"""
+        @property
+        def private_value(self):
+            """Return the private value encoded as a byte string"""
 
-        return self._priv
+            return self._priv
 
 
-class EdDSAPrivateKey(_EdKey):
-    """A shim around PyCA for EdDSA private keys"""
+    class EdDSAPrivateKey(_EdKey):
+        """A shim around PyCA for EdDSA private keys"""
 
-    _priv_classes = {b'ed25519': ed25519.Ed25519PrivateKey,
-                     b'ed448': ed448.Ed448PrivateKey}
+        _priv_classes = {b'ed25519': ed25519.Ed25519PrivateKey,
+                         b'ed448': ed448.Ed448PrivateKey}
 
-    @classmethod
-    def construct(cls, curve_id, priv):
-        """Construct an EdDSA private key"""
+        @classmethod
+        def construct(cls, curve_id, priv):
+            """Construct an EdDSA private key"""
 
-        priv_cls = cls._priv_classes[curve_id]
-        priv_key = priv_cls.from_private_bytes(priv)
-        pub_key = priv_key.public_key()
-        pub = pub_key.public_bytes(Encoding.Raw, PublicFormat.Raw)
+            priv_cls = cls._priv_classes[curve_id]
+            priv_key = priv_cls.from_private_bytes(priv)
+            pub_key = priv_key.public_key()
+            pub = pub_key.public_bytes(Encoding.Raw, PublicFormat.Raw)
 
-        return cls(priv_key, pub, priv)
+            return cls(priv_key, pub, priv)
 
-    @classmethod
-    def generate(cls, curve_id):
-        """Generate a new ECDSA private key"""
+        @classmethod
+        def generate(cls, curve_id):
+            """Generate a new EdDSA private key"""
 
-        priv_cls = cls._priv_classes[curve_id]
-        priv_key = priv_cls.generate()
-        priv = priv_key.private_bytes(Encoding.Raw, PrivateFormat.Raw,
-                                      NoEncryption())
+            priv_cls = cls._priv_classes[curve_id]
+            priv_key = priv_cls.generate()
+            priv = priv_key.private_bytes(Encoding.Raw, PrivateFormat.Raw,
+                                          NoEncryption())
 
-        pub_key = priv_key.public_key()
-        pub = pub_key.public_bytes(Encoding.Raw, PublicFormat.Raw)
+            pub_key = priv_key.public_key()
+            pub = pub_key.public_bytes(Encoding.Raw, PublicFormat.Raw)
 
-        return cls(priv_key, pub, priv)
+            return cls(priv_key, pub, priv)
 
-    def sign(self, data):
-        """Sign a block of data"""
+        def sign(self, data):
+            """Sign a block of data"""
 
-        return self.pyca_key.sign(data)
+            return self.pyca_key.sign(data)
 
 
-class EdDSAPublicKey(_EdKey):
-    """A shim around PyCA for EdDSA public keys"""
+    class EdDSAPublicKey(_EdKey):
+        """A shim around PyCA for EdDSA public keys"""
 
-    _pub_classes = {b'ed25519': ed25519.Ed25519PublicKey,
-                    b'ed448': ed448.Ed448PublicKey}
+        _pub_classes = {b'ed25519': ed25519.Ed25519PublicKey,
+                        b'ed448': ed448.Ed448PublicKey}
 
-    @classmethod
-    def construct(cls, curve_id, pub):
-        """Construct an ECDSA public key"""
+        @classmethod
+        def construct(cls, curve_id, pub):
+            """Construct an EdDSA public key"""
 
-        pub_cls = cls._pub_classes[curve_id]
-        pub_key = pub_cls.from_public_bytes(pub)
+            pub_cls = cls._pub_classes[curve_id]
+            pub_key = pub_cls.from_public_bytes(pub)
 
-        return cls(pub_key, pub)
+            return cls(pub_key, pub)
 
-    def verify(self, data, sig):
-        """Verify the signature on a block of data"""
+        def verify(self, data, sig):
+            """Verify the signature on a block of data"""
 
-        try:
-            self.pyca_key.verify(sig, data)
-            return True
-        except InvalidSignature:
-            return False
+            try:
+                self.pyca_key.verify(sig, data)
+                return True
+            except InvalidSignature:
+                return False
+else: # pragma: no cover
+    class _EdKey:
+        """Base class for shim around libnacl for Ed25519 keys"""
 
+        def __init__(self, pub, priv=None):
+            self._pub = pub
+            self._priv = priv
 
-class Curve25519DH:
-    """Curve25519 Diffie Hellman implementation"""
+        @property
+        def public_value(self):
+            """Return the public value encoded as a byte string"""
 
-    def __init__(self):
-        self._priv_key = x25519.X25519PrivateKey.generate()
+            return self._pub
+
+        @property
+        def private_value(self):
+            """Return the private value encoded as a byte string"""
+
+            return self._priv[:-len(self._pub)] if self._priv else None
+
+
+    class EdDSAPrivateKey(_EdKey):
+        """A shim around libnacl for Ed25519 private keys"""
+
+        @classmethod
+        def construct(cls, curve_id, priv):
+            """Construct an EdDSA private key"""
+
+            # pylint: disable=unused-argument
+
+            return cls(*_ed25519_construct_keypair(priv))
+
+        @classmethod
+        def generate(cls, curve_id):
+            """Generate a new EdDSA private key"""
+
+            # pylint: disable=unused-argument
+
+            return cls(*_ed25519_generate_keypair())
+
+        def sign(self, data):
+            """Sign a block of data"""
+
+            return _ed25519_sign(data, self._priv)[:-len(data)]
+
+
+    class EdDSAPublicKey(_EdKey):
+        """A shim around libnacl for Ed25519 public keys"""
+
+        @classmethod
+        def construct(cls, curve_id, pub):
+            """Construct an EdDSA public key"""
+
+            # pylint: disable=unused-argument
+
+            if len(pub) != _ED25519_PUBLIC_BYTES:
+                raise ValueError('Invalid Ed25519 public key')
+
+            return cls(pub)
+
+        def verify(self, data, sig):
+            """Verify the signature on a block of data"""
+
+            try:
+                return _ed25519_verify(sig + data, self._pub) == data
+            except ValueError:
+                return False
+
+    try:
+        import libnacl
+
+        _ED25519_PUBLIC_BYTES = libnacl.crypto_sign_ed25519_PUBLICKEYBYTES
+
+        _ed25519_construct_keypair = libnacl.crypto_sign_seed_keypair
+        _ed25519_generate_keypair = libnacl.crypto_sign_keypair
+        _ed25519_sign = libnacl.crypto_sign
+        _ed25519_verify = libnacl.crypto_sign_open
+
+        ed25519_available = True
+    except (ImportError, OSError, AttributeError):
+        pass
+
+
+if curve25519_available: # pragma: no branch
+    class Curve25519DH:
+        """Curve25519 Diffie Hellman implementation based on PyCA"""
+
+        def __init__(self):
+            self._priv_key = x25519.X25519PrivateKey.generate()
+
+        def get_public(self):
+            """Return the public key to send in the handshake"""
+
+            return self._priv_key.public_key().public_bytes(Encoding.Raw,
+                                                            PublicFormat.Raw)
+
+        def get_shared(self, peer_public):
+            """Return the shared key from the peer's public key"""
+
+            peer_key = x25519.X25519PublicKey.from_public_bytes(peer_public)
+            shared = self._priv_key.exchange(peer_key)
+            return int.from_bytes(shared, 'big')
+else: # pragma: no cover
+    class Curve25519DH:
+        """Curve25519 Diffie Hellman implementation based on libnacl"""
+
+        def __init__(self):
+            self._private = os.urandom(_CURVE25519_SCALARBYTES)
+
+        def get_public(self):
+            """Return the public key to send in the handshake"""
+
+            public = ctypes.create_string_buffer(_CURVE25519_BYTES)
+
+            if _curve25519_base(public, self._private) != 0:
+                # This error is never returned by libsodium
+                raise ValueError('Curve25519 failed') # pragma: no cover
+
+            return public.raw
+
+        def get_shared(self, peer_public):
+            """Return the shared key from the peer's public key"""
+
+            if len(peer_public) != _CURVE25519_BYTES:
+                raise ValueError('Invalid curve25519 public key size')
+
+            shared = ctypes.create_string_buffer(_CURVE25519_BYTES)
+
+            if _curve25519(shared, self._private, peer_public) != 0:
+                # This error is never returned by libsodium
+                raise ValueError('Curve25519 failed') # pragma: no cover
+
+            return int.from_bytes(shared.raw, 'big')
 
-    def get_public(self):
-        """Return the public key to send in the handshake"""
+    try:
+        from libnacl import nacl
 
-        return self._priv_key.public_key().public_bytes(Encoding.Raw,
-                                                        PublicFormat.Raw)
+        _CURVE25519_BYTES = nacl.crypto_scalarmult_curve25519_bytes()
+        _CURVE25519_SCALARBYTES = \
+            nacl.crypto_scalarmult_curve25519_scalarbytes()
 
-    def get_shared(self, peer_public):
-        """Return the shared key from the peer's public key"""
+        _curve25519 = nacl.crypto_scalarmult_curve25519
+        _curve25519_base = nacl.crypto_scalarmult_curve25519_base
 
-        peer_key = x25519.X25519PublicKey.from_public_bytes(peer_public)
-        shared = self._priv_key.exchange(peer_key)
-        return int.from_bytes(shared, 'big')
+        curve25519_available = True
+    except (ImportError, OSError, AttributeError):
+        pass
 
 
 class Curve448DH:
-    """Curve448 Diffie Hellman implementation"""
+    """Curve448 Diffie Hellman implementation based on PyCA"""
 
     def __init__(self):
         self._priv_key = x448.X448PrivateKey.generate()
Index: asyncssh-1.16.1/asyncssh/eddsa.py
===================================================================
--- asyncssh-1.16.1.orig/asyncssh/eddsa.py
+++ asyncssh-1.16.1/asyncssh/eddsa.py
@@ -22,6 +22,7 @@
 
 from .asn1 import ASN1DecodeError, ObjectIdentifier, der_encode, der_decode
 from .crypto import EdDSAPrivateKey, EdDSAPublicKey
+from .crypto import ed25519_available, ed448_available
 from .packet import String
 from .public_key import OMIT, SSHKey, SSHOpenSSHCertificateV01
 from .public_key import KeyImportError, KeyExportError
@@ -186,10 +187,15 @@ class _Ed448Key(_EdKey):
     all_sig_algorithms = set(sig_algorithms)
 
 
-for _cls in (_Ed25519Key, _Ed448Key):
-    _cert_algorithm = _cls.algorithm + b'[email protected]'
+if ed25519_available: # pragma: no branch
+    register_public_key_alg(b'ssh-ed25519', _Ed25519Key)
 
-    register_public_key_alg(_cls.algorithm, _cls)
+    register_certificate_alg(1, b'ssh-ed25519',
+                             b'[email protected]',
+                             _Ed25519Key, SSHOpenSSHCertificateV01)
 
-    register_certificate_alg(1, _cls.algorithm, _cert_algorithm,
-                             _cls, SSHOpenSSHCertificateV01)
+if ed448_available: # pragma: no branch
+    register_public_key_alg(b'ssh-ed448', _Ed448Key)
+
+    register_certificate_alg(1, b'ssh-ed448', 
b'[email protected]',
+                             _Ed448Key, SSHOpenSSHCertificateV01)

Reply via email to