Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update FIDO2 certificate hash for nkpk #501

Merged
merged 1 commit into from
Feb 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 0 additions & 17 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -77,20 +77,3 @@ jobs:
run: |
. venv/bin/activate
make check-typing
test-documentation:
name: Run documentation tests
runs-on: ubuntu-latest
container: python:3.9-slim
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Install required packages
run: |
apt update
apt install -y gcc libpcsclite-dev make swig git
- name: Create virtual environment
run: make init
- name: Check code static typing
run: |
. venv/bin/activate
make check-doctest
5 changes: 1 addition & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,7 @@ check-typing:
@echo "Note: run semi-clean target in case this fails without any proper reason"
$(PYTHON3_VENV) -m mypy $(PACKAGE_NAME)/

check-doctest:
$(PYTHON3_VENV) -m doctest $(PACKAGE_NAME)/nk3/utils.py

check: check-format check-import-sorting check-style check-typing check-doctest
check: check-format check-import-sorting check-style check-typing

# automatic code fixes
fix:
Expand Down
5 changes: 2 additions & 3 deletions pynitrokey/cli/trussed/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,9 @@
from pynitrokey.cli.trussed.test import TestContext, TestResult, TestStatus, test_case
from pynitrokey.fido2.client import NKFido2Client
from pynitrokey.helpers import local_print
from pynitrokey.nk3.utils import Fido2Certs
from pynitrokey.trussed.base import NitrokeyTrussedBase
from pynitrokey.trussed.device import NitrokeyTrussedDevice
from pynitrokey.trussed.utils import Uuid, Version
from pynitrokey.trussed.utils import Fido2Certs, Uuid, Version

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -400,7 +399,7 @@ def request_uv(self, permissions: Any, rd_id: Any) -> bool:

firmware_version = ctx.firmware_version or device.admin.version()
if firmware_version:
expected_certs = Fido2Certs.get(firmware_version)
expected_certs = Fido2Certs.get(device.fido2_certs, firmware_version)
if expected_certs and cert_hash not in expected_certs.hashes:
return TestResult(
TestStatus.FAILURE,
Expand Down
24 changes: 23 additions & 1 deletion pynitrokey/nk3/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,31 @@
from fido2.hid import CtapHidDevice

from pynitrokey.trussed.device import NitrokeyTrussedDevice
from pynitrokey.trussed.utils import Fido2Certs, Version

FIDO2_CERTS = [
Fido2Certs(
start=Version(0, 1, 0),
hashes=[
"ad8fd1d16f59104b9e06ef323cc03f777ed5303cd421a101c9cb00bb3fdf722d",
],
),
Fido2Certs(
start=Version(1, 0, 3),
hashes=[
"aa1cb760c2879530e7d7fed3da75345d25774be9cfdbbcbd36fdee767025f34b", # NK3xN/lpc55
"4c331d7af869fd1d8217198b917a33d1fa503e9778da7638504a64a438661ae0", # NK3AM/nrf52
"f1ed1aba24b16e8e3fabcda72b10cbfa54488d3b778bda552162d60c6dd7b4fa", # NK3AM/nrf52 test
],
),
]


class Nitrokey3Device(NitrokeyTrussedDevice):
"""A Nitrokey 3 device running the firmware."""

def __init__(self, device: CtapHidDevice) -> None:
super().__init__(device)
super().__init__(device, FIDO2_CERTS)

@property
def pid(self) -> int:
Expand All @@ -27,3 +45,7 @@ def pid(self) -> int:
@property
def name(self) -> str:
return "Nitrokey 3"

@classmethod
def from_device(cls, device: CtapHidDevice) -> "Nitrokey3Device":
return cls(device)
60 changes: 0 additions & 60 deletions pynitrokey/nk3/utils.py

This file was deleted.

16 changes: 15 additions & 1 deletion pynitrokey/nkpk.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,24 @@
from pynitrokey.trussed.base import NitrokeyTrussedBase
from pynitrokey.trussed.bootloader.nrf52 import NitrokeyTrussedBootloaderNrf52
from pynitrokey.trussed.device import NitrokeyTrussedDevice
from pynitrokey.trussed.utils import Fido2Certs, Version

PID_NITROKEY_PASSKEY_DEVICE = 0x42F3
PID_NITROKEY_PASSKEY_BOOTLOADER = 0x42F4

FIDO2_CERTS = [
Fido2Certs(
start=Version(0, 1, 0),
hashes=[
"c7512dfcd15ffc5a7b4000e4898e5956ee858027794c5086cc137a02cd15d123",
],
),
]


class NitrokeyPasskeyDevice(NitrokeyTrussedDevice):
def __init__(self, device: CtapHidDevice) -> None:
super().__init__(device)
super().__init__(device, FIDO2_CERTS)

@property
def pid(self) -> int:
Expand All @@ -32,6 +42,10 @@ def pid(self) -> int:
def name(self) -> str:
return "Nitrokey Passkey"

@classmethod
def from_device(cls, device: CtapHidDevice) -> "NitrokeyPasskeyDevice":
return cls(device)


class NitrokeyPasskeyBootloader(NitrokeyTrussedBootloaderNrf52):
@property
Expand Down
18 changes: 13 additions & 5 deletions pynitrokey/trussed/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@
import sys
from abc import abstractmethod
from enum import Enum
from typing import Optional, TypeVar
from typing import Optional, Sequence, TypeVar

from fido2.hid import CtapHidDevice, open_device

from pynitrokey.fido2 import device_path_to_str

from .base import NitrokeyTrussedBase
from .utils import Uuid, Version
from .utils import Fido2Certs, Uuid, Version

T = TypeVar("T", bound="NitrokeyTrussedDevice")

Expand All @@ -37,10 +37,13 @@ class App(Enum):


class NitrokeyTrussedDevice(NitrokeyTrussedBase):
def __init__(self, device: CtapHidDevice) -> None:
def __init__(
self, device: CtapHidDevice, fido2_certs: Sequence[Fido2Certs]
) -> None:
self.validate_vid_pid(device.descriptor.vid, device.descriptor.pid)

self.device = device
self.fido2_certs = fido2_certs
self._path = device_path_to_str(device.descriptor.path)
self.logger = logger.getChild(self._path)

Expand Down Expand Up @@ -90,6 +93,11 @@ def _call_app(
) -> bytes:
return self._call(app.value, app.name, response_len, data)

@classmethod
@abstractmethod
def from_device(cls: type[T], device: CtapHidDevice) -> T:
...

@classmethod
def open(cls: type[T], path: str) -> Optional[T]:
try:
Expand All @@ -101,7 +109,7 @@ def open(cls: type[T], path: str) -> Optional[T]:
logger.warn(f"No CTAPHID device at path {path}", exc_info=sys.exc_info())
return None
try:
return cls(device)
return cls.from_device(device)
except ValueError:
logger.warn(f"No Nitrokey device at path {path}", exc_info=sys.exc_info())
return None
Expand All @@ -111,7 +119,7 @@ def list(cls: type[T]) -> list[T]:
devices = []
for device in CtapHidDevice.list_devices():
try:
devices.append(cls(device))
devices.append(cls.from_device(device))
except ValueError:
# not the correct device type, skip
pass
Expand Down
16 changes: 15 additions & 1 deletion pynitrokey/trussed/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import dataclasses
from dataclasses import dataclass, field
from functools import total_ordering
from typing import Optional
from typing import Optional, Sequence

from spsdk.sbfile.misc import BcdVersion3

Expand Down Expand Up @@ -231,3 +231,17 @@ def from_v_str(cls, s: str) -> "Version":
@classmethod
def from_bcd_version(cls, version: BcdVersion3) -> "Version":
return cls(major=version.major, minor=version.minor, patch=version.service)


@dataclass
class Fido2Certs:
start: Version
hashes: list[str]

@staticmethod
def get(certs: Sequence["Fido2Certs"], version: Version) -> Optional["Fido2Certs"]:
matching_certs = [c for c in certs if version >= c.start]
if matching_certs:
return max(matching_certs, key=lambda c: c.start)
else:
return None
Loading