Compare commits
3 Commits
| Author | SHA256 | Date | |
|---|---|---|---|
| 5c0428d01e | |||
| 3d65dbf307 | |||
| a6f5a0a391 |
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:450fe13bb8d86a8f4e7d7b5fafce7791181ca3e7c92e15bbc45dfb25866e48b3
|
||||
size 539740
|
||||
3
asyncssh-2.21.1.tar.gz
Normal file
3
asyncssh-2.21.1.tar.gz
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:9943802955e2131536c2b1e71aacc68f56973a399937ed0b725086d7461c990c
|
||||
size 540515
|
||||
176
fido2-compat.patch
Normal file
176
fido2-compat.patch
Normal file
@@ -0,0 +1,176 @@
|
||||
From b9e58a3914c7d1df7f2c096e8c1c0220799e247f Mon Sep 17 00:00:00 2001
|
||||
From: Ron Frederick <ronf@timeheart.net>
|
||||
Date: Fri, 3 Oct 2025 17:44:39 -0700
|
||||
Subject: [PATCH] Update asycnssh to use version 2 of the fido2 package
|
||||
|
||||
---
|
||||
asyncssh/sk.py | 33 ++++++++++++++++++++++-----------
|
||||
pyproject.toml | 2 +-
|
||||
tests/sk_stub.py | 26 +++++++++++++++++++++-----
|
||||
3 files changed, 44 insertions(+), 17 deletions(-)
|
||||
|
||||
diff --git a/asyncssh/sk.py b/asyncssh/sk.py
|
||||
index ca5aef7..bb02ed2 100644
|
||||
--- a/asyncssh/sk.py
|
||||
+++ b/asyncssh/sk.py
|
||||
@@ -128,7 +128,9 @@ def _ctap2_enroll(dev: 'CtapHidDevice', alg: int, application: str,
|
||||
def _win_enroll(alg: int, application: str, user: str) -> Tuple[bytes, bytes]:
|
||||
"""Enroll a new security key using Windows WebAuthn API"""
|
||||
|
||||
- client = WindowsClient(application, verify=_verify_rp_id)
|
||||
+ data_collector = DefaultClientDataCollector(origin=application,
|
||||
+ verify=_verify_rp_id)
|
||||
+ client = WindowsClient(data_collector)
|
||||
|
||||
rp = {'id': application, 'name': application}
|
||||
user_cred = {'id': user.encode('utf-8'), 'name': user}
|
||||
@@ -137,7 +139,8 @@ def _win_enroll(alg: int, application: str, user: str) -> Tuple[bytes, bytes]:
|
||||
'pubKeyCredParams': key_params}
|
||||
|
||||
result = client.make_credential(options)
|
||||
- cdata = result.attestation_object.auth_data.credential_data
|
||||
+ response = result.response
|
||||
+ cdata = response.attestation_object.auth_data.credential_data
|
||||
|
||||
# pylint: disable=no-member
|
||||
return _decode_public_key(alg, cdata.public_key), cdata.credential_id
|
||||
@@ -188,17 +191,20 @@ def _win_sign(data: bytes, application: str,
|
||||
key_handle: bytes) -> Tuple[int, int, bytes, bytes]:
|
||||
"""Sign a message with a security key using Windows WebAuthn API"""
|
||||
|
||||
- client = WindowsClient(application, verify=_verify_rp_id)
|
||||
+ data_collector = DefaultClientDataCollector(origin=application,
|
||||
+ verify=_verify_rp_id)
|
||||
+ client = WindowsClient(data_collector)
|
||||
|
||||
creds = [{'type': 'public-key', 'id': key_handle}]
|
||||
options = {'challenge': data, 'rpId': application,
|
||||
'allowCredentials': creds}
|
||||
|
||||
result = client.get_assertion(options).get_response(0)
|
||||
- auth_data = result.authenticator_data
|
||||
+ response = result.response
|
||||
+ auth_data = response.authenticator_data
|
||||
|
||||
return auth_data.flags, auth_data.counter, \
|
||||
- result.signature, bytes(result.client_data)
|
||||
+ response.signature, bytes(response.client_data)
|
||||
|
||||
|
||||
def sk_webauthn_prefix(data: bytes, application: str) -> bytes:
|
||||
@@ -327,7 +333,7 @@ def sk_get_resident(application: str, user: Optional[str],
|
||||
|
||||
|
||||
try:
|
||||
- from fido2.client import WindowsClient
|
||||
+ from fido2.client import DefaultClientDataCollector
|
||||
from fido2.ctap import CtapError
|
||||
from fido2.ctap1 import Ctap1, APDU, ApduError
|
||||
from fido2.ctap2 import Ctap2, ClientPin, PinProtocolV1
|
||||
@@ -335,13 +341,8 @@ def sk_get_resident(application: str, user: Optional[str],
|
||||
from fido2.hid import CtapHidDevice
|
||||
|
||||
sk_available = True
|
||||
-
|
||||
- sk_use_webauthn = WindowsClient.is_available() and \
|
||||
- hasattr(ctypes, 'windll') and \
|
||||
- not ctypes.windll.shell32.IsUserAnAdmin()
|
||||
except (ImportError, OSError, AttributeError): # pragma: no cover
|
||||
sk_available = False
|
||||
- sk_use_webauthn = False
|
||||
|
||||
def _sk_not_available(*args: object, **kwargs: object) -> NoReturn:
|
||||
"""Report that security key support is unavailable"""
|
||||
@@ -351,3 +352,13 @@ def _sk_not_available(*args: object, **kwargs: object) -> NoReturn:
|
||||
sk_enroll = _sk_not_available
|
||||
sk_sign = _sk_not_available
|
||||
sk_get_resident = _sk_not_available
|
||||
+
|
||||
+try:
|
||||
+ from fido2.client.windows import WindowsClient
|
||||
+
|
||||
+ sk_use_webauthn = WindowsClient.is_available() and \
|
||||
+ hasattr(ctypes, 'windll') and \
|
||||
+ not ctypes.windll.shell32.IsUserAnAdmin()
|
||||
+except ImportError:
|
||||
+ WindowsClient = None
|
||||
+ sk_use_webauthn = False
|
||||
diff --git a/pyproject.toml b/pyproject.toml
|
||||
index ea30886..2f4f113 100644
|
||||
--- a/pyproject.toml
|
||||
+++ b/pyproject.toml
|
||||
@@ -35,7 +35,7 @@ dynamic = ['version']
|
||||
|
||||
[project.optional-dependencies]
|
||||
bcrypt = ['bcrypt >= 3.1.3']
|
||||
-fido2 = ['fido2 >= 0.9.2, < 2']
|
||||
+fido2 = ['fido2 >= 2']
|
||||
gssapi = ['gssapi >= 1.2.0']
|
||||
libnacl = ['libnacl >= 1.4.2']
|
||||
pkcs11 = ['python-pkcs11 >= 0.7.0']
|
||||
diff --git a/tests/sk_stub.py b/tests/sk_stub.py
|
||||
index 0926e4e..090f150 100644
|
||||
--- a/tests/sk_stub.py
|
||||
+++ b/tests/sk_stub.py
|
||||
@@ -93,6 +93,13 @@ def __init__(self, attestation_object):
|
||||
self.attestation_object = attestation_object
|
||||
|
||||
|
||||
+class _RegistrationResponse:
|
||||
+ """Security key registration response"""
|
||||
+
|
||||
+ def __init__(self, attestation_response):
|
||||
+ self.response = attestation_response
|
||||
+
|
||||
+
|
||||
class _AuthenticatorData:
|
||||
"""Security key authenticator data in aseertion"""
|
||||
|
||||
@@ -110,6 +117,13 @@ def __init__(self, client_data, auth_data, signature):
|
||||
self.signature = signature
|
||||
|
||||
|
||||
+class _AuthenticationResponse:
|
||||
+ """Security key authentication response"""
|
||||
+
|
||||
+ def __init__(self, response):
|
||||
+ self.response = response
|
||||
+
|
||||
+
|
||||
class _AssertionSelection:
|
||||
"""Security key assertion response list"""
|
||||
|
||||
@@ -261,9 +275,9 @@ def get_assertions(self, application, message_hash, allow_creds, options):
|
||||
class WindowsClient(_CtapStub):
|
||||
"""Stub for unit testing U2F security keys via Windows WebAuthn"""
|
||||
|
||||
- def __init__(self, origin, verify):
|
||||
- self._origin = origin
|
||||
- self._verify = verify
|
||||
+ def __init__(self, data_collector):
|
||||
+ self._origin = data_collector._origin
|
||||
+ self._verify = data_collector._verify
|
||||
|
||||
def make_credential(self, options):
|
||||
"""Make a credential using Windows WebAuthN API"""
|
||||
@@ -275,8 +289,9 @@ def make_credential(self, options):
|
||||
public_key, key_handle = self._enroll(alg)
|
||||
|
||||
cdata = _CredentialData(alg, public_key, key_handle)
|
||||
+ attestation_object = _Credential(_CredentialAuthData(cdata))
|
||||
|
||||
- return _AttestationResponse(_Credential(_CredentialAuthData(cdata)))
|
||||
+ return _RegistrationResponse(_AttestationResponse(attestation_object))
|
||||
|
||||
def get_assertion(self, options):
|
||||
"""Get assertion using Windows WebAuthN API"""
|
||||
@@ -297,7 +312,8 @@ def get_assertion(self, options):
|
||||
key_handle, flags)
|
||||
|
||||
auth_data = _AuthenticatorData(flags, counter)
|
||||
- assertion = _AssertionResponse(data, auth_data, sig)
|
||||
+ response = _AssertionResponse(data, auth_data, sig)
|
||||
+ assertion = _AuthenticationResponse(response)
|
||||
|
||||
return _AssertionSelection([assertion])
|
||||
|
||||
@@ -1,3 +1,28 @@
|
||||
-------------------------------------------------------------------
|
||||
Fri Oct 10 11:51:00 UTC 2025 - Nico Krapp <nico.krapp@suse.com>
|
||||
|
||||
- Add fido2-compat.patch to restore compatibility with python-fido2 >= 2
|
||||
- Update requirements from pyproject.toml
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Thu Oct 9 12:26:08 UTC 2025 - John Paul Adrian Glaubitz <adrian.glaubitz@suse.com>
|
||||
|
||||
- Update to 2.21.1
|
||||
* Added the capability to defer invoking passphrase callback until
|
||||
an encrypted private key is actually used in a signing operation,
|
||||
rather than triggering the callback when keys are loaded. This
|
||||
will only work when a public key is provided with an encrypted
|
||||
private key either explicitly or as part of the key format (such
|
||||
as in OpenSSH's private key format).
|
||||
* Improved handling of KeyboardInterrupt and task cancellation in
|
||||
SCP. Thanks go to Viktor Kertesz for reporting this issue and
|
||||
helping to understand the behavior in various versions of Python.
|
||||
* Fixed the env option to support mappings other than dict. Thanks
|
||||
go to Boris Pavlovic for reporting this issue.
|
||||
* Fixed a potential race condition in SSHForwarder cleanup. Thanks
|
||||
go to GitHub user misa-hase for reporting this issue and helping
|
||||
to test the fix.
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Sat Jul 12 17:35:09 UTC 2025 - Dirk Müller <dmueller@suse.com>
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#
|
||||
# spec file for package python-asyncssh
|
||||
#
|
||||
# Copyright (c) 2025 SUSE LLC
|
||||
# Copyright (c) 2025 SUSE LLC and contributors
|
||||
#
|
||||
# All modifications and additions to the file contributed by third parties
|
||||
# remain the property of their copyright owners, unless otherwise agreed
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
%{?sle15_python_module_pythons}
|
||||
Name: python-asyncssh
|
||||
Version: 2.21.0
|
||||
Version: 2.21.1
|
||||
Release: 0
|
||||
Summary: Asynchronous SSHv2 client and server library
|
||||
License: EPL-2.0 OR GPL-2.0-or-later
|
||||
@@ -26,31 +26,31 @@ Group: Development/Languages/Python
|
||||
URL: https://github.com/ronf/asyncssh
|
||||
Source: https://files.pythonhosted.org/packages/source/a/asyncssh/asyncssh-%{version}.tar.gz
|
||||
Patch0: gss_test.patch
|
||||
# PATCH-FIX-UPSTREAM fido2-compat.patch
|
||||
Patch1: fido2-compat.patch
|
||||
# SECTION test requirements
|
||||
BuildRequires: %{python_module bcrypt >= 3.1.3}
|
||||
BuildRequires: %{python_module cryptography >= 2.8}
|
||||
BuildRequires: %{python_module fido2 >= 0.8.1}
|
||||
BuildRequires: %{python_module cryptography >= 39.0}
|
||||
BuildRequires: %{python_module fido2 >= 2}
|
||||
BuildRequires: %{python_module gssapi >= 1.2.0}
|
||||
BuildRequires: %{python_module pip}
|
||||
BuildRequires: %{python_module pyOpenSSL >= 17.0.0}
|
||||
BuildRequires: %{python_module pytest}
|
||||
BuildRequires: %{python_module setuptools}
|
||||
BuildRequires: %{python_module typing_extensions}
|
||||
BuildRequires: %{python_module uvloop >= 0.9.1}
|
||||
BuildRequires: %{python_module typing_extensions >= 4.0.0}
|
||||
BuildRequires: %{python_module wheel}
|
||||
BuildRequires: openssh
|
||||
BuildRequires: openssl
|
||||
BuildRequires: (libnettle8 if python38-base)
|
||||
# /SECTION
|
||||
BuildRequires: fdupes
|
||||
BuildRequires: python-rpm-macros
|
||||
Requires: python-bcrypt >= 3.1.3
|
||||
Requires: python-cryptography >= 2.8
|
||||
Requires: python-gssapi >= 1.2.0
|
||||
Requires: python-libnacl >= 1.4.2
|
||||
Requires: python-pyOpenSSL >= 17.0.0
|
||||
Recommends: libnettle8
|
||||
Recommends: python-fido2 >= 0.8.1
|
||||
Requires: python-cryptography >= 39.0
|
||||
Requires: python-typing_extensions >= 4.0.0
|
||||
Recommends: python-bcrypt >= 3.1.3
|
||||
Recommends: python-fido2 >= 2
|
||||
Recommends: python-gssapi >= 1.2.0
|
||||
Recommends: python-libnacl >= 1.4.2
|
||||
Recommends: python-pyOpenSSL >= 23.0.0
|
||||
BuildArch: noarch
|
||||
|
||||
%python_subpackages
|
||||
|
||||
Reference in New Issue
Block a user