Skip to content

Commit

Permalink
fido2/ctap: add test for ctap without transport layer
Browse files Browse the repository at this point in the history
  • Loading branch information
Ollrogge committed Oct 16, 2022
1 parent 43c650f commit 9f341f9
Show file tree
Hide file tree
Showing 10 changed files with 282 additions and 95 deletions.
36 changes: 8 additions & 28 deletions tests/sys_fido2_ctap/Makefile
Original file line number Diff line number Diff line change
@@ -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
65 changes: 11 additions & 54 deletions tests/sys_fido2_ctap/README.md
Original file line number Diff line number Diff line change
@@ -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
```
64 changes: 64 additions & 0 deletions tests/sys_fido2_ctap/gen_test_case.py
Original file line number Diff line number Diff line change
@@ -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)
66 changes: 53 additions & 13 deletions tests/sys_fido2_ctap/main.c
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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 <nils-ollrogge@outlook.de>
* @author Nils Ollrogge <nils.ollrogge@fu-berlin.de>
* @}
*/

#include <stdio.h>
#include <stdlib.h>

#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;
}
/** @} */
14 changes: 14 additions & 0 deletions tests/sys_fido2_ctap/tests/01-run.py
Original file line number Diff line number Diff line change
@@ -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())
37 changes: 37 additions & 0 deletions tests/sys_fido2_ctap_hid/Makefile
Original file line number Diff line number Diff line change
@@ -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
59 changes: 59 additions & 0 deletions tests/sys_fido2_ctap_hid/README.md
Original file line number Diff line number Diff line change
@@ -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.
File renamed without changes.
Loading

0 comments on commit 9f341f9

Please sign in to comment.