diff --git a/tests/sys_fido2_ctap/Makefile b/tests/sys_fido2_ctap/Makefile index f36e2c2ee5195..66a265adb2eb6 100644 --- a/tests/sys_fido2_ctap/Makefile +++ b/tests/sys_fido2_ctap/Makefile @@ -1,37 +1,17 @@ -BOARD ?= nrf52840dk -#BOARD ?= nrf52840dongle - include ../Makefile.tests_common -USEMODULE += fido2_ctap_transport_hid -USEPKG += fido2_tests +# same as CTAP_STACKSIZE +CFLAGS += -DTHREAD_STACKSIZE_MAIN=15000 + +# Add unittest framework +USEMODULE += embunit -USB_VID ?= $(USB_VID_TESTING) -USB_PID ?= $(USB_PID_TESTING) +USEMODULE += fido2_ctap # Disable user presence tests -# Should be used when running fido2-test to make them run quicker -#CFLAGS += -DCONFIG_FIDO2_CTAP_DISABLE_UP=1 +CFLAGS += -DCONFIG_FIDO2_CTAP_DISABLE_UP=1 # Disable user LED animation -#CFLAGS += -DCONFIG_FIDO2_CTAP_DISABLE_LED=1 - -# FIDO2 tests except for the ones requiring user presence -# -# Use env -i because fido2-test has a depedency (pyscard) that needs to be -# compiled natively (x86-64). Therefore we need to clear the flags set by e.g. -# BOARD = nrf52840dk -fido2-test: - env -i PATH=$(PATH) $(MAKE) -C $(RIOTBASE)/build/pkg/fido2_tests - -# FIDO2 user presence tests. -# -# Make sure to enable user presence tests by uncommenting CFLAGS += -DCONFIG_FIDO2_CTAP_DISABLE_UP=1 -# -# Use env -i because fido2-test has a depedency (pyscard) that needs to be -# compiled natively (x86-64). Therefore we need to clear the flags set by e.g. -# BOARD = nrf52840dk -fido2-test-up: - env -i PATH=$(PATH) $(MAKE) -C $(RIOTBASE)/build/pkg/fido2_tests up-tests +CFLAGS += -DCONFIG_FIDO2_CTAP_DISABLE_LED=1 include $(RIOTBASE)/Makefile.include diff --git a/tests/sys_fido2_ctap/README.md b/tests/sys_fido2_ctap/README.md index 726866ee7ff59..e73745fec986a 100644 --- a/tests/sys_fido2_ctap/README.md +++ b/tests/sys_fido2_ctap/README.md @@ -1,59 +1,16 @@ -# Test Application for FIDO2 CTAP +# Overview -This test aims to test the FIDO2 CTAP implementation by creating a FIDO2 -authenticator which uses CTAPHID as communication protocol. +This test application tests FIDO2 CTAP2 functionality without a transport layer being used. -Note: -* This test application has only been tested on an nrf52840 DK. +To execute the test run e.g. -The test application requires at least 16536 bytes of stack memory which are -divided as follows: -* 512 bytes isr_stack -* 1024 usbus -* 15000 bytes FIDO2 CTAP +``` +BOARD = nrf52840dk make flash test +``` -## Usage -The FIDO2 authenticator can be tested in two ways: +To generate a new test case array run: +* Note: This requires the [python-fido lib](https://github.com/Yubico/python-fido2) -### Functional testing -1. Flash the device with `make flash`. -2. Test the authenticator on a website like [Webauthn.io](https://webauthn.io/). - -Note: -* Due to limited support of FIDO2 CTAP in browsers as of now, make sure to use the - Chromium or Google Chrome browser when testing on [Webauthn.io](https://webauthn.io/). -* When registering and authenticating on [Webauthn.io](https://webauthn.io/) you -will need to push button 1 on your device in order to show user presence. - -**Resetting the authenticator** -* To reset the authenticator, meaning that all credentials and state information -will be deleted, execute the `reset.py` file located in this directory. - * This requires you to install the python fido2 package. To install run: - `pip install fido2==0.8.1`. - -### Unit testing -Unit testing is based on the `fido2_tests` package. - -There are two test targets (fido2-test, fido2-test-up). The former requires no user -interaction the latter does. - -Note: -* The tests require python 3.6+. -* The tests require [swig](http://www.swig.org/) to be installed on your host computer. -* Running the tests for the first time will setup a virtual python environment (venv) and install python dependencies of the tests. To check the dependencies please refer to the `requirements.txt` of the [fido2-tests repository](https://github.com/solokeys/fido2-tests). -* The unit tests will require you to reboot the authenticator multiple times. Be patient before continuing as it takes a few seconds for the connection between OS and authenticator to be re-established. -* If you keep getting errors while trying to run the tests try changing to another git branch and back e.g. `git checkout branch1 && git checkout -` in order to remove build artifacts. Then re-flash the device with `make flash term` and try to run the tests again with `make fido2-test` or `make fido2-test-up`. - -fido2-test - -1. To make benchmarking faster disable user presence tests by enabling the CFLAG - `CONFIG_FIDO2_CTAP_DISABLE_UP` in the Makefile or through KConfig. -2. Flash the device with `make flash`. -3. Run the unit tests by running `make fido2-test`. - -fido2-test-up - -1. Make sure that the CFLAG `CONFIG_FIDO2_CTAP_DISABLE_UP` is disabled as this test target - requires user interaction. -2. Flash the device with `make flash`. -3. Run the unit tests by running `make fido2-test-up` and follow the instructions. E.g. when `.ACTIVATE UP ONCE` is displayed, press the configured UP button (default button 1) once. +``` +python3 gen_test_case.py +``` \ No newline at end of file diff --git a/tests/sys_fido2_ctap/gen_test_case.py b/tests/sys_fido2_ctap/gen_test_case.py new file mode 100644 index 0000000000000..0a5a96ce06f0d --- /dev/null +++ b/tests/sys_fido2_ctap/gen_test_case.py @@ -0,0 +1,64 @@ +from fido2.ctap2 import CTAP2 +from fido2 import cbor +from fido2.client import Fido2Client +from fido2.server import Fido2Server +from unittest import mock + + +def mock_device(): + device = mock.MagicMock() + return CTAP2(device) + + +def get_cbor(data): + request = b"" + if data is not None: + request += cbor.encode(data) + + return request + + +def args(*params): + """Constructs a dict from a list of arguments for sending a CBOR command. + None elements will be omitted. + """ + return dict((i, v) for i, v in enumerate(params, 1) if v is not None) + + +def print_req(req): + print("static uint8_t mc_data[] = {", end='') + print("".join(f"{hex(x)}, " for x in req), end='') + print("};") + + +def gen_mc_req(): + dev = mock_device() + dev.capabilities = 0 + user = {"id": b"user_id", "name": "A. User"} + client = Fido2Client(dev, "https://example.com") + server = Fido2Server({"id": "example.com", "name": "Example RP"}, attestation="direct") + + create_options, _ = server.register_begin(user) + create_options = create_options['publicKey'] + client_data = client._build_client_data("webauthn.create", create_options['challenge']) + + options = {} + options["rk"] = True + + return get_cbor( + args( + client_data.hash, + create_options["rp"], + create_options["user"], + create_options["pubKeyCredParams"], + None, # exclude list + None, # extensions + options, + None, # pin_auth + None, # pin protocol version + )) + + +if __name__ == "__main__": + req = gen_mc_req() + print_req(req) diff --git a/tests/sys_fido2_ctap/main.c b/tests/sys_fido2_ctap/main.c index 31ffbc44efd9b..def607e6c5295 100644 --- a/tests/sys_fido2_ctap/main.c +++ b/tests/sys_fido2_ctap/main.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 Freie Universität Berlin + * Copyright (C) 2022 Freie Universität Berlin * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -10,27 +10,67 @@ * @ingroup tests * @{ * @file - * @brief FIDO2 CTAP test application that creates an authenticator - * which uses CTAPHID as underlying communication protocol + * @brief FIDO2 CTAP test application that tests CTAP functionality + * without transport layer. * - * @author Nils Ollrogge + * @author Nils Ollrogge * @} */ - #include #include -#define ENABLE_DEBUG (0) -#include "debug.h" - -#include "xtimer.h" +#include "embUnit.h" #include "fido2/ctap.h" -#include "fido2/ctap/transport/ctap_transport.h" + +/** + * To generate a new array simply run the gen_test_case.py script + */ +static uint8_t mc_data[] = {0xa5, 0x1, 0x58, 0x20, 0x7f, 0x1, 0xda, 0xe5, 0xa5, 0xd6, 0x7a, 0xaa, 0x98, 0x8, 0x8c, 0xad, 0x1e, 0xcc, 0xb3, 0xf3, 0x46, 0x6, 0xe7, 0x54, 0x10, 0x8b, 0xd3, 0x98, 0x51, 0x7a, 0x1a, 0x70, 0xd9, 0xb3, 0xe4, 0x2b, 0x2, 0xa2, 0x62, 0x69, 0x64, 0x6b, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x64, 0x6e, 0x61, 0x6d, 0x65, 0x6a, 0x45, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x20, 0x52, 0x50, 0x3, 0xa2, 0x62, 0x69, 0x64, 0x47, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x64, 0x6e, 0x61, 0x6d, 0x65, 0x67, 0x41, 0x2e, 0x20, 0x55, 0x73, 0x65, 0x72, 0x4, 0x84, 0xa2, 0x63, 0x61, 0x6c, 0x67, 0x26, 0x64, 0x74, 0x79, 0x70, 0x65, 0x6a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2d, 0x6b, 0x65, 0x79, 0xa2, 0x63, 0x61, 0x6c, 0x67, 0x27, 0x64, 0x74, 0x79, 0x70, 0x65, 0x6a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2d, 0x6b, 0x65, 0x79, 0xa2, 0x63, 0x61, 0x6c, 0x67, 0x38, 0x24, 0x64, 0x74, 0x79, 0x70, 0x65, 0x6a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2d, 0x6b, 0x65, 0x79, 0xa2, 0x63, 0x61, 0x6c, 0x67, 0x39, 0x1, 0x0, 0x64, 0x74, 0x79, 0x70, 0x65, 0x6a, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2d, 0x6b, 0x65, 0x79, 0x7, 0xa1, 0x62, 0x72, 0x6b, 0xf5, }; + +/** + * Only testing MakeCredential request because GetAssertion depends on a + * credential ID we can statically generate +*/ +static void test_ctap_mc(void) +{ + ctap_req_t req = {0}; + ctap_resp_t resp = {0}; + + /* reset authenticator */ + req.method = CTAP_RESET; + req.buf = NULL; + req.len = 0x0; + fido2_ctap_handle_request(&req, &resp); + + TEST_ASSERT(resp.status == CTAP2_OK); + + /* create new credential */ + req.method = CTAP_MAKE_CREDENTIAL; + req.buf = mc_data; + req.len = sizeof(mc_data); + fido2_ctap_handle_request(&req, &resp); + + TEST_ASSERT(resp.status == CTAP2_OK); +} + +Test *ctap_tests(void) +{ + EMB_UNIT_TESTFIXTURES(fixtures) { + new_TestFixture(test_ctap_mc), + }; + + EMB_UNIT_TESTCALLER(ctap_tests, NULL, NULL, fixtures); + + return (Test *)&ctap_tests; +} int main(void) { - /* sleep in order to see early DEBUG outputs */ - xtimer_sleep(3); - fido2_ctap_transport_init(); + TESTS_START(); + TESTS_RUN(ctap_tests()); + TESTS_END(); + + return 0; } +/** @} */ diff --git a/tests/sys_fido2_ctap/tests/01-run.py b/tests/sys_fido2_ctap/tests/01-run.py new file mode 100755 index 0000000000000..06365aea55a39 --- /dev/null +++ b/tests/sys_fido2_ctap/tests/01-run.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 + +# Copyright (C) 2022 Freie Universität Berlin +# +# This file is subject to the terms and conditions of the GNU Lesser +# General Public License v2.1. See the file LICENSE in the top level +# directory for more details. + +import sys +from testrunner import run_check_unittests + + +if __name__ == "__main__": + sys.exit(run_check_unittests()) diff --git a/tests/sys_fido2_ctap_hid/Makefile b/tests/sys_fido2_ctap_hid/Makefile new file mode 100644 index 0000000000000..51b1153a933e9 --- /dev/null +++ b/tests/sys_fido2_ctap_hid/Makefile @@ -0,0 +1,37 @@ +BOARD ?= nrf52840dk +#BOARD ?= nrf52840dongle + +include ../Makefile.tests_common + +USEMODULE += fido2_ctap_transport_hid +USEPKG += fido2_tests + +USB_VID ?= $(USB_VID_TESTING) +USB_PID ?= $(USB_PID_TESTING) + +# Disable user presence tests +# Should be used when running fido2-test to make them run quicker +CFLAGS += -DCONFIG_FIDO2_CTAP_DISABLE_UP=1 + +# Disable user LED animation +CFLAGS += -DCONFIG_FIDO2_CTAP_DISABLE_LED=1 + +# FIDO2 tests except for the ones requiring user presence +# +# Use env -i because fido2-test has a depedency (pyscard) that needs to be +# compiled natively (x86-64). Therefore we need to clear the flags set by e.g. +# BOARD = nrf52840dk +fido2-test: + env -i PATH=$(PATH) $(MAKE) -C $(RIOTBASE)/build/pkg/fido2_tests + +# FIDO2 user presence tests. +# +# Make sure to enable user presence tests by uncommenting CFLAGS += -DCONFIG_FIDO2_CTAP_DISABLE_UP=1 +# +# Use env -i because fido2-test has a depedency (pyscard) that needs to be +# compiled natively (x86-64). Therefore we need to clear the flags set by e.g. +# BOARD = nrf52840dk +fido2-test-up: + env -i PATH=$(PATH) $(MAKE) -C $(RIOTBASE)/build/pkg/fido2_tests up-tests + +include $(RIOTBASE)/Makefile.include diff --git a/tests/sys_fido2_ctap_hid/README.md b/tests/sys_fido2_ctap_hid/README.md new file mode 100644 index 0000000000000..5846b7da8f9af --- /dev/null +++ b/tests/sys_fido2_ctap_hid/README.md @@ -0,0 +1,59 @@ +# Test Application for FIDO2 CTAP using USB HID transport binding + +This test aims to test the FIDO2 CTAP implementation by creating a FIDO2 +authenticator which uses CTAPHID as communication protocol. + +Note: +* This test application has only been tested on an nrf52840 DK. + +The test application requires at least 16536 bytes of stack memory which are +divided as follows: +* 512 bytes isr_stack +* 1024 usbus +* 15000 bytes FIDO2 CTAP + +## Usage +The FIDO2 authenticator can be tested in two ways: + +### Functional testing +1. Flash the device with `make flash`. +2. Test the authenticator on a website like [Webauthn.io](https://webauthn.io/). + +Note: +* Due to limited support of FIDO2 CTAP in browsers as of now, make sure to use the + Chromium or Google Chrome browser when testing on [Webauthn.io](https://webauthn.io/). +* When registering and authenticating on [Webauthn.io](https://webauthn.io/) you +will need to push button 1 on your device in order to show user presence. + +**Resetting the authenticator** +* To reset the authenticator, meaning that all credentials and state information +will be deleted, execute the `reset.py` file located in this directory. + * This requires you to install the python fido2 package. To install run: + `pip install fido2==0.8.1`. + +### Unit testing +Unit testing is based on the `fido2_tests` package. + +There are two test targets (fido2-test, fido2-test-up). The former requires no user +interaction the latter does. + +Note: +* The tests require python 3.6+. +* The tests require [swig](http://www.swig.org/) to be installed on your host computer. +* Running the tests for the first time will setup a virtual python environment (venv) and install python dependencies of the tests. To check the dependencies please refer to the `requirements.txt` of the [fido2-tests repository](https://github.com/solokeys/fido2-tests). +* The unit tests will require you to reboot the authenticator multiple times. Be patient before continuing as it takes a few seconds for the connection between OS and authenticator to be re-established. +* If you keep getting errors while trying to run the tests try changing to another git branch and back e.g. `git checkout branch1 && git checkout -` in order to remove build artifacts. Then re-flash the device with `make flash term` and try to run the tests again with `make fido2-test` or `make fido2-test-up`. + +fido2-test + +1. To make benchmarking faster disable user presence tests by enabling the CFLAG + `CONFIG_FIDO2_CTAP_DISABLE_UP` in the Makefile or through KConfig. +2. Flash the device with `make flash`. +3. Run the unit tests by running `make fido2-test`. + +fido2-test-up + +1. Make sure that the CFLAG `CONFIG_FIDO2_CTAP_DISABLE_UP` is disabled as this test target + requires user interaction. +2. Flash the device with `make flash`. +3. Run the unit tests by running `make fido2-test-up` and follow the instructions. E.g. when `.ACTIVATE UP ONCE` is displayed, press the configured UP button (default button 1) once. diff --git a/tests/sys_fido2_ctap/app.config.test b/tests/sys_fido2_ctap_hid/app.config.test similarity index 100% rename from tests/sys_fido2_ctap/app.config.test rename to tests/sys_fido2_ctap_hid/app.config.test diff --git a/tests/sys_fido2_ctap_hid/main.c b/tests/sys_fido2_ctap_hid/main.c new file mode 100644 index 0000000000000..21df207c20d33 --- /dev/null +++ b/tests/sys_fido2_ctap_hid/main.c @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2022 Freie Universität Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup tests + * @{ + * @file + * @brief FIDO2 CTAP test application that creates an authenticator + * which uses CTAPHID as underlying communication protocol + * + * @author Nils Ollrogge + * @} + */ + +#include +#include + +#define ENABLE_DEBUG (0) +#include "debug.h" + +#include "xtimer.h" + +#include "fido2/ctap.h" +#include "fido2/ctap/transport/ctap_transport.h" + +int main(void) +{ + /* sleep in order to see early DEBUG outputs */ + xtimer_sleep(3); + fido2_ctap_transport_init(); +} diff --git a/tests/sys_fido2_ctap/reset.py b/tests/sys_fido2_ctap_hid/reset.py similarity index 100% rename from tests/sys_fido2_ctap/reset.py rename to tests/sys_fido2_ctap_hid/reset.py