Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-pynitrokey for openSUSE:Factory checked in at 2024-07-16 22:04:14 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-pynitrokey (Old) and /work/SRC/openSUSE:Factory/.python-pynitrokey.new.17339 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-pynitrokey" Tue Jul 16 22:04:14 2024 rev:10 rq:1187698 version:0.4.48 Changes: -------- --- /work/SRC/openSUSE:Factory/python-pynitrokey/python-pynitrokey.changes 2024-04-21 20:28:26.048459901 +0200 +++ /work/SRC/openSUSE:Factory/.python-pynitrokey.new.17339/python-pynitrokey.changes 2024-07-16 22:04:15.345878909 +0200 @@ -1,0 +2,10 @@ +Sat Jul 13 12:07:09 UTC 2024 - Johannes Kastl <opensuse_buildserv...@ojkastl.de> + +- update to 0.4.48: + * nethsm: Improve base64 handling and add key import from PEM by + @robin-nitrokey in #539 + * fido2: Add get-info subcommand by @robin-nitrokey in #545 + * nk3/update: add pre_bootloader_hint for update process by + @daringer in #546 + +------------------------------------------------------------------- Old: ---- pynitrokey-0.4.47.tar.gz New: ---- pynitrokey-0.4.48.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-pynitrokey.spec ++++++ --- /var/tmp/diff_new_pack.dGdZs3/_old 2024-07-16 22:04:16.105906647 +0200 +++ /var/tmp/diff_new_pack.dGdZs3/_new 2024-07-16 22:04:16.109906793 +0200 @@ -23,7 +23,7 @@ %endif Name: python-pynitrokey -Version: 0.4.47 +Version: 0.4.48 Release: 0 Summary: Python Library for Nitrokey devices License: Apache-2.0 OR MIT @@ -46,7 +46,7 @@ BuildRequires: %{python_module frozendict >= 2.3.4} # "fido2 >=1.1.0,<2" BuildRequires: %{python_module fido2 >= 1.1.0 with %python-fido2 < 2} -BuildRequires: %{python_module nethsm >= 1.0.0 with %python-nethsm < 2} +BuildRequires: %{python_module nethsm >= 1.1.0 with %python-nethsm < 2} BuildRequires: %{python_module nkdfu} #"python-dateutil ~= 2.7.0" BuildRequires: %{python_module python-dateutil >= 2.7.0} @@ -86,7 +86,7 @@ Requires: python-typing_extensions >= 4.3.0 Requires: python-urllib3 >= 1.26.7 Requires: (python-fido2 >= 1.1.0 with python-fido2 < 2) -Requires: (python-nethsm >= 0.5.0 with python-nethsm < 2) +Requires: (python-nethsm >= 1.1.0 with python-nethsm < 2) Requires: (python-spsdk >= 2.0 with python-spsdk < 2.2) Requires(post): update-alternatives Requires(postun): update-alternatives ++++++ pynitrokey-0.4.47.tar.gz -> pynitrokey-0.4.48.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pynitrokey-0.4.47/PKG-INFO new/pynitrokey-0.4.48/PKG-INFO --- old/pynitrokey-0.4.47/PKG-INFO 1970-01-01 01:00:00.000000000 +0100 +++ new/pynitrokey-0.4.48/PKG-INFO 1970-01-01 01:00:00.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: pynitrokey -Version: 0.4.47 +Version: 0.4.48 Summary: Python Library for Nitrokey devices. Author-email: Nitrokey <p...@nitrokey.com> Requires-Python: >=3.9 @@ -33,7 +33,7 @@ Requires-Dist: protobuf >=3.17.3, < 4.0.0 Requires-Dist: click-aliases Requires-Dist: semver -Requires-Dist: nethsm >= 1.0.0,<2 +Requires-Dist: nethsm >= 1.1.0,<2 Requires-Dist: black >=22.1.0,<23 ; extra == "dev" Requires-Dist: flake8 ; extra == "dev" Requires-Dist: flit >=3.2,<4 ; extra == "dev" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pynitrokey-0.4.47/pynitrokey/VERSION new/pynitrokey-0.4.48/pynitrokey/VERSION --- old/pynitrokey-0.4.47/pynitrokey/VERSION 2024-04-17 13:42:18.000000000 +0200 +++ new/pynitrokey-0.4.48/pynitrokey/VERSION 2024-07-10 11:06:44.000000000 +0200 @@ -1 +1 @@ -0.4.47 +0.4.48 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pynitrokey-0.4.47/pynitrokey/cli/fido2.py new/pynitrokey-0.4.48/pynitrokey/cli/fido2.py --- old/pynitrokey-0.4.47/pynitrokey/cli/fido2.py 2024-04-17 13:42:18.000000000 +0200 +++ new/pynitrokey-0.4.48/pynitrokey/cli/fido2.py 2024-07-10 11:06:44.000000000 +0200 @@ -12,6 +12,7 @@ import platform import struct import sys +from dataclasses import fields from time import sleep, time from typing import List, Literal, Optional @@ -25,10 +26,11 @@ from fido2.client import ClientError as Fido2ClientError from fido2.ctap import CtapError from fido2.ctap1 import ApduError -from fido2.ctap2.base import Ctap2 +from fido2.ctap2.base import Ctap2, Info from fido2.ctap2.credman import CredentialManagement from fido2.ctap2.pin import ClientPin, PinProtocol from fido2.hid import CtapHidDevice +from fido2.webauthn import Aaguid import pynitrokey import pynitrokey.fido2 as nkfido2 @@ -206,6 +208,35 @@ "--serial", help="Serial number of Nitrokey to use. Prefix with 'device=' to provide device file, e.g. 'device=/dev/hidraw5'.", ) +def get_info(serial: Optional[str]) -> None: + """Execute the CTAP2 GET_INFO command and print the response.""" + p = nkfido2.find(serial) + if p.ctap2 is None: + print("CTAP2 not supported") + return + + info = p.ctap2.send_cbor(Ctap2.CMD.GET_INFO) + for i, field in enumerate(fields(Info)): + key = i + 1 + if key in info: + value = info[i + 1] + + if field.name == "aaguid": + if isinstance(value, bytes): + try: + value = Aaguid(value) + except: + value = value.hex() + + print(f"{field.name}: {value}") + + +@click.command() +@click.option( + "-s", + "--serial", + help="Serial number of Nitrokey to use. Prefix with 'device=' to provide device file, e.g. 'device=/dev/hidraw5'.", +) @click.option("--pin", help="provide PIN instead of asking the user", default=None) def list_credentials(serial: str, pin: str) -> None: """List all credentials saved on the key as well as the amount of remaining slots.""" @@ -850,6 +881,7 @@ fido2.add_command(reboot) fido2.add_command(list) +fido2.add_command(get_info) fido2.add_command(list_credentials) fido2.add_command(delete_credential) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pynitrokey-0.4.47/pynitrokey/cli/nethsm.py new/pynitrokey-0.4.48/pynitrokey/cli/nethsm.py --- old/pynitrokey-0.4.47/pynitrokey/cli/nethsm.py 2024-04-17 13:42:18.000000000 +0200 +++ new/pynitrokey-0.4.48/pynitrokey/cli/nethsm.py 2024-07-10 11:06:44.000000000 +0200 @@ -37,6 +37,10 @@ return click.Choice([variant.value for variant in enum_cls], case_sensitive=False) +def base64_input(s: str) -> Base64: + return Base64.from_encoded(s, ignore_whitespace=True) + + API_CERTIFICATE_MIME_TYPE = "application/x-pem-file" KEY_CERTIFICATE_MIME_TYPES = [ "application/x-pem-file", @@ -688,9 +692,9 @@ if not public_exponent: public_exponent = prompt_str("Public exponent") private_key = nethsm_sdk.RsaPrivateKey( - prime_p=Base64.from_encoded(prime_p), - prime_q=Base64.from_encoded(prime_q), - public_exponent=Base64.from_encoded(public_exponent), + prime_p=base64_input(prime_p), + prime_q=base64_input(prime_q), + public_exponent=base64_input(public_exponent), ) else: if prime_p: @@ -703,7 +707,7 @@ ) if not data: data = prompt_str("Key data") - private_key = nethsm_sdk.GenericPrivateKey(data=Base64.from_encoded(data)) + private_key = nethsm_sdk.GenericPrivateKey(data=base64_input(data)) with connect(ctx) as nethsm: key_id = nethsm.add_key( @@ -718,6 +722,56 @@ @nethsm.command() @click.option( + "-m", + "--mechanism", + "mechanisms", + type=MECHANISM_TYPE, + multiple=True, + help="The mechanisms for the new key", +) +@click.option( + "--tags", + type=str, + multiple=True, + help="The tags for the new key", +) +@click.option( + "-k", + "--key-id", + help="The ID of the new key", +) +@click.argument("filename") +@click.pass_context +def import_key( + ctx: Context, + mechanisms: list[str], + tags: list[str], + key_id: Optional[str], + filename: str, +) -> None: + """Import a key pair from a PEM file into the NetHSM. + + If the key ID is not set, it is generated by the NetHSM. + + This command requires authentication as a user with the Administrator + role.""" + mechanisms = list(mechanisms) + + with open(filename) as f: + private_key = f.read() + + with connect(ctx) as nethsm: + key_id = nethsm.add_key_pem( + key_id=key_id, + mechanisms=[nethsm_sdk.KeyMechanism.from_string(m) for m in mechanisms], + tags=tags, + private_key=private_key, + ) + print(f"Key {key_id} added to NetHSM {nethsm.host}") + + +@nethsm.command() +@click.option( "type", "-t", "--type", @@ -1543,9 +1597,9 @@ with connect(ctx) as nethsm: encrypted = nethsm.encrypt( key_id, - Base64.from_encoded(data), + base64_input(data), nethsm_sdk.EncryptMode.from_string(mode), - iv=Base64.from_encoded(iv) if iv else None, + iv=base64_input(iv) if iv else None, ) print(f"Encrypted: {encrypted.encrypted.data}") print(f"Initialization vector: {encrypted.iv.data}") @@ -1586,9 +1640,9 @@ with connect(ctx) as nethsm: decrypted = nethsm.decrypt( key_id, - Base64.from_encoded(data), + base64_input(data), nethsm_sdk.DecryptMode.from_string(mode), - Base64.from_encoded(iv) if iv else None, + base64_input(iv) if iv else None, ) print(decrypted.data) @@ -1620,6 +1674,6 @@ This command requires authentication as a user with the Operator role.""" with connect(ctx) as nethsm: signature = nethsm.sign( - key_id, Base64.from_encoded(data), nethsm_sdk.SignMode.from_string(mode) + key_id, base64_input(data), nethsm_sdk.SignMode.from_string(mode) ) print(signature.data) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pynitrokey-0.4.47/pynitrokey/cli/nk3/update.py new/pynitrokey-0.4.48/pynitrokey/cli/nk3/update.py --- old/pynitrokey-0.4.47/pynitrokey/cli/nk3/update.py 2024-04-17 13:42:18.000000000 +0200 +++ new/pynitrokey-0.4.48/pynitrokey/cli/nk3/update.py 2024-07-10 11:06:44.000000000 +0200 @@ -95,6 +95,9 @@ ) return Abort() + def pre_bootloader_hint(self) -> None: + pass + def request_bootloader_confirmation(self) -> None: local_print("") local_print( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pynitrokey-0.4.47/pynitrokey/nk3/updates.py new/pynitrokey-0.4.48/pynitrokey/nk3/updates.py --- old/pynitrokey-0.4.47/pynitrokey/nk3/updates.py 2024-04-17 13:42:18.000000000 +0200 +++ new/pynitrokey-0.4.48/pynitrokey/nk3/updates.py 2024-07-10 11:06:44.000000000 +0200 @@ -126,7 +126,11 @@ pass @abstractmethod - def request_repeated_update(self) -> Exception: + def request_repeated_update(self) -> Optional[Exception]: + pass + + @abstractmethod + def pre_bootloader_hint(self) -> None: pass @abstractmethod @@ -329,11 +333,14 @@ # needed for udev to properly handle new device time.sleep(1) - if platform.system() == "Darwin": + maybe_exc = self.ui.request_repeated_update() + if platform.system() == "Darwin" and maybe_exc is not None: # Currently there is an issue with device enumeration after reboot on macOS, see # <https://github.com/Nitrokey/pynitrokey/issues/145>. To avoid this issue, we # cancel the command now and ask the user to run it again. - raise self.ui.request_repeated_update() + raise maybe_exc + + self.ui.pre_bootloader_hint() exc = None for t in Retries(3): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pynitrokey-0.4.47/pyproject.toml new/pynitrokey-0.4.48/pyproject.toml --- old/pynitrokey-0.4.47/pyproject.toml 2024-04-17 13:42:18.000000000 +0200 +++ new/pynitrokey-0.4.48/pyproject.toml 2024-07-10 11:06:44.000000000 +0200 @@ -40,7 +40,7 @@ "protobuf >=3.17.3, < 4.0.0", "click-aliases", "semver", - "nethsm >= 1.0.0,<2", + "nethsm >= 1.1.0,<2", ] dynamic = ["version", "description"]