diff --git a/.github/workflows/boards_build.yml b/.github/workflows/boards_build.yml index 0a8fbebb7e1886443fc9a6e67ef36d4f53adca0d..50a29d5a3b4faf98802b82445e9b61f965aad08e 100644 --- a/.github/workflows/boards_build.yml +++ b/.github/workflows/boards_build.yml @@ -27,15 +27,11 @@ jobs: - name: Set up OpenSK run: ./setup.sh + - name: Building board nrf52840dk + run: ./deploy.py --board=nrf52840dk --no-app --programmer=none + - name: Building board nrf52840_dongle + run: ./deploy.py --board=nrf52840_dongle --no-app --programmer=none - name: Building board nrf52840_dongle_dfu run: ./deploy.py --board=nrf52840_dongle_dfu --no-app --programmer=none - name: Building board nrf52840_mdk_dfu run: ./deploy.py --board=nrf52840_mdk_dfu --no-app --programmer=none - - - name: Create a long build directory - run: mkdir this-is-a-long-build-directory-0123456789abcdefghijklmnopqrstuvwxyz && mv third_party this-is-a-long-build-directory-0123456789abcdefghijklmnopqrstuvwxyz/ - - - name: Building board nrf52840dk - run: make -C this-is-a-long-build-directory-0123456789abcdefghijklmnopqrstuvwxyz/third_party/tock/boards/nordic/nrf52840dk - - name: Building board nrf52840_dongle - run: make -C this-is-a-long-build-directory-0123456789abcdefghijklmnopqrstuvwxyz/third_party/tock/boards/nordic/nrf52840_dongle diff --git a/.github/workflows/cargo_check.yml b/.github/workflows/cargo_check.yml index a6c4c4696cca73994152d3ee1422399374e7f768..c54fc9e34ab5309e19d28dc4f9894bbcba72637f 100644 --- a/.github/workflows/cargo_check.yml +++ b/.github/workflows/cargo_check.yml @@ -64,17 +64,23 @@ jobs: command: check args: --target thumbv7em-none-eabi --release --features ram_storage + - name: Check OpenSK verbose + uses: actions-rs/cargo@v1 + with: + command: check + args: --target thumbv7em-none-eabi --release --features verbose + - name: Check OpenSK debug_ctap,with_ctap1 uses: actions-rs/cargo@v1 with: command: check args: --target thumbv7em-none-eabi --release --features debug_ctap,with_ctap1 - - name: Check OpenSK debug_ctap,with_ctap1,panic_console,debug_allocations + - name: Check OpenSK debug_ctap,with_ctap1,panic_console,debug_allocations,verbose uses: actions-rs/cargo@v1 with: command: check - args: --target thumbv7em-none-eabi --release --features debug_ctap,with_ctap1,panic_console,debug_allocations + args: --target thumbv7em-none-eabi --release --features debug_ctap,with_ctap1,panic_console,debug_allocations,verbose - name: Check examples uses: actions-rs/cargo@v1 diff --git a/.github/workflows/cargo_fmt.yml b/.github/workflows/cargo_fmt.yml index 00589ca0dcc175c0533eb8d6a7d1dd5538838b05..df466b384e7adfc9296a4eb4a669ecde2c7f9833 100644 --- a/.github/workflows/cargo_fmt.yml +++ b/.github/workflows/cargo_fmt.yml @@ -20,6 +20,7 @@ jobs: - uses: actions-rs/toolchain@v1 with: target: thumbv7em-none-eabi + components: rustfmt - uses: actions/setup-python@v1 with: python-version: 3.7 diff --git a/Cargo.toml b/Cargo.toml index 3155106e9d79fc478ea7c9669c79fefd6124b884..1d1ad6e18f6a1651f9c5a59a5d4d4f70640e6c5c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,12 +18,13 @@ arrayref = "0.3.6" subtle = { version = "2.2", default-features = false, features = ["nightly"] } [features] -std = ["cbor/std", "crypto/std", "crypto/derive_debug"] +debug_allocations = ["libtock/debug_allocations"] debug_ctap = ["crypto/derive_debug"] -with_ctap1 = ["crypto/with_ctap1"] panic_console = ["libtock/panic_console"] -debug_allocations = ["libtock/debug_allocations"] +std = ["cbor/std", "crypto/std", "crypto/derive_debug"] ram_storage = [] +verbose = ["debug_ctap"] +with_ctap1 = ["crypto/with_ctap1"] [dev-dependencies] elf2tab = "0.4.0" diff --git a/boards/nordic/nrf52840_dongle_dfu/Cargo.toml b/boards/nordic/nrf52840_dongle_dfu/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..35eab8a848640da82ba78e50fafe0acd46264304 --- /dev/null +++ b/boards/nordic/nrf52840_dongle_dfu/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "nrf52840_dongle_dfu" +version = "0.1.0" +authors = ["Tock Project Developers <tock-dev@googlegroups.com>"] +build = "build.rs" +edition = "2018" + +[[bin]] +path = "../nrf52840_dongle/src/main.rs" +name = "nrf52840_dongle_dfu" + +[dependencies] +components = { path = "../../components" } +cortexm4 = { path = "../../../arch/cortex-m4" } +capsules = { path = "../../../capsules" } +kernel = { path = "../../../kernel" } +nrf52840 = { path = "../../../chips/nrf52840" } +nrf52dk_base = { path = "../nrf52dk_base" } diff --git a/boards/nrf52840_dongle_dfu/Makefile b/boards/nordic/nrf52840_dongle_dfu/Makefile similarity index 81% rename from boards/nrf52840_dongle_dfu/Makefile rename to boards/nordic/nrf52840_dongle_dfu/Makefile index 723ba0af1570d50a7e1257bce4aa3d39108e4bf5..58771b3a640ae3cc9edc1f6e0764aeb619da57f7 100644 --- a/boards/nrf52840_dongle_dfu/Makefile +++ b/boards/nordic/nrf52840_dongle_dfu/Makefile @@ -4,7 +4,7 @@ TOCK_ARCH=cortex-m4 TARGET=thumbv7em-none-eabi PLATFORM=nrf52840_dongle_dfu -include ../../third_party/tock/boards/Makefile.common +include ../../Makefile.common TOCKLOADER=tockloader @@ -20,10 +20,10 @@ TOCKLOADER_JTAG_FLAGS = --jlink --arch $(TOCK_ARCH) --board $(PLATFORM) --page-s # Upload the kernel over JTAG .PHONY: flash -flash: target/$(TARGET)/release/$(PLATFORM).bin +flash: $(TOCK_ROOT_DIRECTORY)target/$(TARGET)/release/$(PLATFORM).bin $(TOCKLOADER) $(TOCKLOADER_GENERAL_FLAGS) flash --address $(KERNEL_ADDRESS) $(TOCKLOADER_JTAG_FLAGS) $< # Upload the kernel over serial/bootloader .PHONY: program -program: target/$(TARGET)/release/$(PLATFORM).hex +program: $(TOCK_ROOT_DIRECTORY)target/$(TARGET)/release/$(PLATFORM).hex $(error Cannot program nRF52 Dongle over USB. Use \`make flash\` and JTAG) diff --git a/boards/nordic/nrf52840_dongle_dfu/build.rs b/boards/nordic/nrf52840_dongle_dfu/build.rs new file mode 100644 index 0000000000000000000000000000000000000000..1fdd4924f0a125f565133842a274c5e2067ce21f --- /dev/null +++ b/boards/nordic/nrf52840_dongle_dfu/build.rs @@ -0,0 +1,4 @@ +fn main() { + println!("cargo:rerun-if-changed=layout.ld"); + println!("cargo:rerun-if-changed=../../kernel_layout.ld"); +} diff --git a/boards/nrf52840_mdk_dfu/layout.ld b/boards/nordic/nrf52840_dongle_dfu/layout.ld similarity index 76% rename from boards/nrf52840_mdk_dfu/layout.ld rename to boards/nordic/nrf52840_dongle_dfu/layout.ld index 834133c00b8d0adb87c9e8eb355ed0b2e91c0582..41ae608ac5d17b9ff7334f769472e1b9c458f466 100644 --- a/boards/nrf52840_mdk_dfu/layout.ld +++ b/boards/nordic/nrf52840_dongle_dfu/layout.ld @@ -7,4 +7,4 @@ MEMORY MPU_MIN_ALIGN = 8K; -INCLUDE ../../third_party/tock/boards/kernel_layout.ld +INCLUDE ../../kernel_layout.ld diff --git a/boards/nordic/nrf52840_mdk_dfu/Cargo.toml b/boards/nordic/nrf52840_mdk_dfu/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..c0cb7af33a7349efc49cdcd6304ad56b5756f9d3 --- /dev/null +++ b/boards/nordic/nrf52840_mdk_dfu/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "nrf52840_mdk_dfu" +version = "0.1.0" +authors = ["Yihui Xiong <yihui.xiong@hotmail.com>"] +build = "build.rs" +edition = "2018" + +[dependencies] +components = { path = "../../components" } +cortexm4 = { path = "../../../arch/cortex-m4" } +capsules = { path = "../../../capsules" } +kernel = { path = "../../../kernel" } +nrf52840 = { path = "../../../chips/nrf52840" } +nrf52dk_base = { path = "../nrf52dk_base" } diff --git a/boards/nrf52840_mdk_dfu/Makefile b/boards/nordic/nrf52840_mdk_dfu/Makefile similarity index 74% rename from boards/nrf52840_mdk_dfu/Makefile rename to boards/nordic/nrf52840_mdk_dfu/Makefile index e915141d9174e55cb67deccc607d9dc1ae49300a..a179ffb4b2c9eb870392037c5fff971f5b8c44fb 100644 --- a/boards/nrf52840_mdk_dfu/Makefile +++ b/boards/nordic/nrf52840_mdk_dfu/Makefile @@ -4,7 +4,7 @@ TOCK_ARCH=cortex-m4 TARGET=thumbv7em-none-eabi PLATFORM=nrf52840_mdk_dfu -include ../../third_party/tock/boards/Makefile.common +include ../../Makefile.common TOCKLOADER=tockloader @@ -20,10 +20,10 @@ TOCKLOADER_JTAG_FLAGS = --jlink --arch $(TOCK_ARCH) --board $(PLATFORM) --page-s # Upload the kernel over JTAG .PHONY: flash -flash: target/$(TARGET)/release/$(PLATFORM).bin +flash: $(TOCK_ROOT_DIRECTORY)target/$(TARGET)/release/$(PLATFORM).bin $(TOCKLOADER) $(TOCKLOADER_GENERAL_FLAGS) flash --address $(KERNEL_ADDRESS) $(TOCKLOADER_JTAG_FLAGS) $< # Upload the kernel over serial/bootloader .PHONY: program -program: target/$(TARGET)/release/$(PLATFORM).hex - $(error Cannot program nRF52 Dongle over USB. Use \`make flash\` and JTAG) +program: $(TOCK_ROOT_DIRECTORY)target/$(TARGET)/release/$(PLATFORM).hex + $(error Cannot program nRF52840-MDK over USB. Use \`make flash\` and JTAG) diff --git a/boards/nordic/nrf52840_mdk_dfu/build.rs b/boards/nordic/nrf52840_mdk_dfu/build.rs new file mode 100644 index 0000000000000000000000000000000000000000..1fdd4924f0a125f565133842a274c5e2067ce21f --- /dev/null +++ b/boards/nordic/nrf52840_mdk_dfu/build.rs @@ -0,0 +1,4 @@ +fn main() { + println!("cargo:rerun-if-changed=layout.ld"); + println!("cargo:rerun-if-changed=../../kernel_layout.ld"); +} diff --git a/boards/nrf52840_dongle_dfu/layout.ld b/boards/nordic/nrf52840_mdk_dfu/layout.ld similarity index 76% rename from boards/nrf52840_dongle_dfu/layout.ld rename to boards/nordic/nrf52840_mdk_dfu/layout.ld index 834133c00b8d0adb87c9e8eb355ed0b2e91c0582..41ae608ac5d17b9ff7334f769472e1b9c458f466 100644 --- a/boards/nrf52840_dongle_dfu/layout.ld +++ b/boards/nordic/nrf52840_mdk_dfu/layout.ld @@ -7,4 +7,4 @@ MEMORY MPU_MIN_ALIGN = 8K; -INCLUDE ../../third_party/tock/boards/kernel_layout.ld +INCLUDE ../../kernel_layout.ld diff --git a/boards/nrf52840_mdk_dfu/src/io.rs b/boards/nordic/nrf52840_mdk_dfu/src/io.rs similarity index 100% rename from boards/nrf52840_mdk_dfu/src/io.rs rename to boards/nordic/nrf52840_mdk_dfu/src/io.rs diff --git a/boards/nrf52840_mdk_dfu/src/main.rs b/boards/nordic/nrf52840_mdk_dfu/src/main.rs similarity index 100% rename from boards/nrf52840_mdk_dfu/src/main.rs rename to boards/nordic/nrf52840_mdk_dfu/src/main.rs diff --git a/boards/nrf52840_dongle_dfu/Cargo.toml b/boards/nrf52840_dongle_dfu/Cargo.toml deleted file mode 100644 index 6944eb33fc308caba08ec539d5d6af5783d4e3be..0000000000000000000000000000000000000000 --- a/boards/nrf52840_dongle_dfu/Cargo.toml +++ /dev/null @@ -1,30 +0,0 @@ -[package] -name = "nrf52840_dongle_dfu" -version = "0.1.0" -authors = ["Tock Project Developers <tock-dev@googlegroups.com>"] -build = "build.rs" -edition = "2018" - -[profile.dev] -panic = "abort" -lto = false -opt-level = "z" -debug = true - -[profile.release] -panic = "abort" -lto = true -opt-level = "z" -debug = true - -[[bin]] -path = "../../third_party/tock/boards/nordic/nrf52840_dongle/src/main.rs" -name = "nrf52840_dongle_dfu" - -[dependencies] -components = { path = "../../third_party/tock/boards/components" } -cortexm4 = { path = "../../third_party/tock/arch/cortex-m4" } -capsules = { path = "../../third_party/tock/capsules" } -kernel = { path = "../../third_party/tock/kernel" } -nrf52840 = { path = "../../third_party/tock/chips/nrf52840" } -nrf52dk_base = { path = "../../third_party/tock/boards/nordic/nrf52dk_base" } diff --git a/boards/nrf52840_dongle_dfu/build.rs b/boards/nrf52840_dongle_dfu/build.rs deleted file mode 100644 index 2631dccb75f21f432f5186b17215367490e2d3f2..0000000000000000000000000000000000000000 --- a/boards/nrf52840_dongle_dfu/build.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn main() { - println!("cargo:rerun-if-changed=layout.ld"); - println!("cargo:rerun-if-changed=../../third_party/tock/boards/kernel_layout.ld"); -} diff --git a/boards/nrf52840_mdk_dfu/Cargo.toml b/boards/nrf52840_mdk_dfu/Cargo.toml deleted file mode 100644 index 1047869ba67c2d46b0af09d0ec7dd214a051fa43..0000000000000000000000000000000000000000 --- a/boards/nrf52840_mdk_dfu/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -name = "nrf52840_mdk_dfu" -version = "0.1.0" -authors = ["Yihui Xiong <yihui.xiong@hotmail.com>"] -build = "build.rs" -edition = "2018" - -[profile.dev] -panic = "abort" -lto = false -opt-level = "z" -debug = true - -[profile.release] -panic = "abort" -lto = true -opt-level = "z" -debug = true - -[dependencies] -components = { path = "../../third_party/tock/boards/components" } -cortexm4 = { path = "../../third_party/tock/arch/cortex-m4" } -capsules = { path = "../../third_party/tock/capsules" } -kernel = { path = "../../third_party/tock/kernel" } -nrf52840 = { path = "../../third_party/tock/chips/nrf52840" } -nrf52dk_base = { path = "../../third_party/tock/boards/nordic/nrf52dk_base" } diff --git a/boards/nrf52840_mdk_dfu/build.rs b/boards/nrf52840_mdk_dfu/build.rs deleted file mode 100644 index 2631dccb75f21f432f5186b17215367490e2d3f2..0000000000000000000000000000000000000000 --- a/boards/nrf52840_mdk_dfu/build.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn main() { - println!("cargo:rerun-if-changed=layout.ld"); - println!("cargo:rerun-if-changed=../../third_party/tock/boards/kernel_layout.ld"); -} diff --git a/deploy.py b/deploy.py index 639b70bb45d118a92c05f15697aeb8c2f99a6cb8..6b552faad1e6c6dd474bf0b924ec1da2e2fbb786 100755 --- a/deploy.py +++ b/deploy.py @@ -115,7 +115,7 @@ SUPPORTED_BOARDS = { ), "nrf52840_dongle_dfu": OpenSKBoard( - path="boards/nrf52840_dongle_dfu", + path="third_party/tock/boards/nordic/nrf52840_dongle_dfu", arch="thumbv7em-none-eabi", page_size=4096, kernel_address=0x1000, @@ -132,7 +132,7 @@ SUPPORTED_BOARDS = { ), "nrf52840_mdk_dfu": OpenSKBoard( - path="boards/nrf52840_mdk_dfu", + path="third_party/tock/boards/nordic/nrf52840_mdk_dfu", arch="thumbv7em-none-eabi", page_size=4096, kernel_address=0x1000, @@ -304,7 +304,8 @@ class OpenSKInstaller: def build_tockos(self): info("Building Tock OS for board {}".format(self.args.board)) props = SUPPORTED_BOARDS[self.args.board] - out_directory = os.path.join(props.path, "target", props.arch, "release") + out_directory = os.path.join("third_party", "tock", "target", props.arch, + "release") os.makedirs(out_directory, exist_ok=True) self.checked_command_output(["make"], cwd=props.path) @@ -418,8 +419,9 @@ class OpenSKInstaller: def install_tock_os(self): board_props = SUPPORTED_BOARDS[self.args.board] - kernel_file = os.path.join(board_props.path, "target", board_props.arch, - "release", "{}.bin".format(self.args.board)) + kernel_file = os.path.join("third_party", "tock", "target", + board_props.arch, "release", + "{}.bin".format(self.args.board)) info("Flashing file {}.".format(kernel_file)) with open(kernel_file, "rb") as f: kernel = f.read() @@ -481,8 +483,9 @@ class OpenSKInstaller: if self.args.tockos: # Process kernel - kernel_path = os.path.join(board_props.path, "target", board_props.arch, - "release", "{}.bin".format(self.args.board)) + kernel_path = os.path.join("third_party", "tock", "target", + board_props.arch, "release", + "{}.bin".format(self.args.board)) with open(kernel_path, "rb") as kernel: kern_hex = intelhex.IntelHex() kern_hex.frombytes(kernel.read(), offset=board_props.kernel_address) @@ -705,6 +708,15 @@ if __name__ == "__main__": "output messages before starting blinking the LEDs on the " "board."), ) + main_parser.add_argument( + "--debug", + action="append_const", + const="debug_ctap", + dest="features", + help=("Compiles and installs the OpenSK application in debug mode " + "(i.e. more debug messages will be sent over the console port " + "such as hexdumps of packets)."), + ) main_parser.add_argument( "--debug-allocations", action="append_const", @@ -713,6 +725,14 @@ if __name__ == "__main__": help=("The console will be used to output allocator statistics every " "time an allocation/deallocation happens."), ) + main_parser.add_argument( + "--verbose", + action="append_const", + const="verbose", + dest="features", + help=("The console will be used to output verbose information about the " + "OpenSK application. This also automatically activates --debug."), + ) main_parser.add_argument( "--no-u2f", action=RemoveConstAction, @@ -731,15 +751,6 @@ if __name__ == "__main__": "This is useful to allow flashing multiple OpenSK authenticators " "in a row without them being considered clones."), ) - main_parser.add_argument( - "--debug", - action="append_const", - const="debug_ctap", - dest="features", - help=("Compiles and installs the OpenSK application in debug mode " - "(i.e. more debug messages will be sent over the console port " - "such as hexdumps of packets)."), - ) main_parser.add_argument( "--no-persistent-storage", action="append_const", diff --git a/docs/install.md b/docs/install.md index 5b5763b1b83ee2c58da2c1006a1d581e6c1daca7..cf355fac54fefdad8907618480f49b770ea873b9 100644 --- a/docs/install.md +++ b/docs/install.md @@ -50,8 +50,9 @@ In order to compile and flash a working OpenSK firmware, you will need the following: * rustup (can be installed with [Rustup](https://rustup.rs/)) -* python3 and pip -* the OpenSSL command line tool +* python3 and pip (can be installed with the `python3-pip` package on Debian) +* the OpenSSL command line tool (can be installed with the `libssl-dev` + package on Debian) The scripts provided in this project have been tested under Linux and OS X. We haven't tested them on Windows and other platforms. diff --git a/patches/tock/04-additional-boards.patch b/patches/tock/04-additional-boards.patch new file mode 100644 index 0000000000000000000000000000000000000000..88cd1c3db38e11462467ecfdb7216b8a5ad12871 --- /dev/null +++ b/patches/tock/04-additional-boards.patch @@ -0,0 +1,13 @@ +diff --git a/Cargo.toml b/Cargo.toml +index 18f4a10d..db88dc1d 100644 +--- a/Cargo.toml ++++ b/Cargo.toml +@@ -13,6 +13,8 @@ members = [ + "boards/launchxl", + "boards/nordic/nrf52840dk", + "boards/nordic/nrf52840_dongle", ++ "boards/nordic/nrf52840_dongle_dfu", ++ "boards/nordic/nrf52840_mdk_dfu", + "boards/nordic/nrf52dk", + "boards/nucleo_f429zi", + "boards/nucleo_f446re", diff --git a/patches/tock/04-nrf52-bootloader.patch b/patches/tock/04-nrf52-bootloader.patch deleted file mode 100644 index 02f57be6552ce9ca2b09c1c98475015db6c08494..0000000000000000000000000000000000000000 --- a/patches/tock/04-nrf52-bootloader.patch +++ /dev/null @@ -1,21 +0,0 @@ -diff --git a/chips/nrf52/src/crt1.rs b/chips/nrf52/src/crt1.rs -index 9703aac..281ceeb 100644 ---- a/chips/nrf52/src/crt1.rs -+++ b/chips/nrf52/src/crt1.rs -@@ -1,4 +1,4 @@ --use cortexm4::{generic_isr, hard_fault_handler, nvic, svc_handler, systick_handler}; -+use cortexm4::{generic_isr, hard_fault_handler, nvic, scb, svc_handler, systick_handler}; - use tock_rt0; - - /* -@@ -168,5 +168,9 @@ pub unsafe extern "C" fn init() { - tock_rt0::init_data(&mut _etext, &mut _srelocate, &mut _erelocate); - tock_rt0::zero_bss(&mut _szero, &mut _ezero); - -+ // Ensure that we are compatible with a bootloader. -+ // For this we need to offset our vector table -+ scb::set_vector_table_offset(BASE_VECTORS.as_ptr() as *const ()); -+ - nvic::enable_all(); - } - diff --git a/run_desktop_tests.sh b/run_desktop_tests.sh index 864b8fecca526ddc56726348472de28b8876a347..36bde36da10d929257197db4316cc2aa11f96b2b 100755 --- a/run_desktop_tests.sh +++ b/run_desktop_tests.sh @@ -34,8 +34,9 @@ cargo check --release --target=thumbv7em-none-eabi --features debug_ctap cargo check --release --target=thumbv7em-none-eabi --features panic_console cargo check --release --target=thumbv7em-none-eabi --features debug_allocations cargo check --release --target=thumbv7em-none-eabi --features ram_storage +cargo check --release --target=thumbv7em-none-eabi --features verbose cargo check --release --target=thumbv7em-none-eabi --features debug_ctap,with_ctap1 -cargo check --release --target=thumbv7em-none-eabi --features debug_ctap,with_ctap1,panic_console,debug_allocations +cargo check --release --target=thumbv7em-none-eabi --features debug_ctap,with_ctap1,panic_console,debug_allocations,verbose echo "Checking that examples build properly..." cargo check --release --target=thumbv7em-none-eabi --examples @@ -49,8 +50,16 @@ make -C third_party/tock/boards/nordic/nrf52840dk make -C third_party/tock/boards/nordic/nrf52840_dongle echo "Checking that other boards build properly..." -make -C boards/nrf52840_dongle_dfu -make -C boards/nrf52840_mdk_dfu +make -C third_party/tock/boards/nordic/nrf52840_dongle_dfu +make -C third_party/tock/boards/nordic/nrf52840_mdk_dfu + +echo "Checking deployment of supported boards..." +./deploy.py --board=nrf52840dk --no-app --programmer=none +./deploy.py --board=nrf52840_dongle --no-app --programmer=none + +echo "Checking deployment of other boards..." +./deploy.py --board=nrf52840_dongle_dfu --no-app --programmer=none +./deploy.py --board=nrf52840_mdk_dfu --no-app --programmer=none if [ -z "${TRAVIS_OS_NAME}" -o "${TRAVIS_OS_NAME}" = "linux" ] then diff --git a/setup.sh b/setup.sh index 1c6fe37cfc1fb467cf04d7e759e08784b97949a7..c4297adc9ccae692ed06aa5e588285e7a1046129 100755 --- a/setup.sh +++ b/setup.sh @@ -46,6 +46,11 @@ EOF exit 1 } +# Copy additional boards to the kernel. +echo -n '[-] Copying additional boards to Tock... ' +cp -r boards/* third_party/tock/boards +echo $done_text + # Apply patches to kernel. Do that in a sub-shell ( cd third_party/tock/ && \ diff --git a/src/ctap/data_formats.rs b/src/ctap/data_formats.rs index 5049d1cb5528d6e0606bc08eebce931d9c66648e..3a2bed91e85089124c5780dd399b39bbd42902d4 100644 --- a/src/ctap/data_formats.rs +++ b/src/ctap/data_formats.rs @@ -462,6 +462,8 @@ pub struct CoseKey(pub BTreeMap<cbor::KeyType, cbor::Value>); // here: https://www.iana.org/assignments/cose/cose.xhtml#algorithms // In fact, this is just used for compatibility with older specification versions. const ECDH_ALGORITHM: i64 = -25; +// This is the identifier used by OpenSSH. To be compatible, we accept both. +const ES256_ALGORITHM: i64 = -7; const EC2_KEY_TYPE: i64 = 2; const P_256_CURVE: i64 = 1; @@ -497,7 +499,7 @@ impl TryFrom<CoseKey> for ecdh::PubKey { return Err(Ctap2StatusCode::CTAP2_ERR_UNSUPPORTED_ALGORITHM); } let algorithm = read_integer(ok_or_missing(cose_key.0.get(&cbor_int!(3)))?)?; - if algorithm != ECDH_ALGORITHM { + if algorithm != ECDH_ALGORITHM && algorithm != ES256_ALGORITHM { return Err(Ctap2StatusCode::CTAP2_ERR_UNSUPPORTED_ALGORITHM); } let curve = read_integer(ok_or_missing(cose_key.0.get(&cbor_int!(-1)))?)?; diff --git a/src/ctap/storage.rs b/src/ctap/storage.rs index 8f2c2b57aea76e3b2180fa4234f8b4c6495fe9aa..f0a2ca4ff0bfb3ec85e1859d44009af8c0a6ee29 100644 --- a/src/ctap/storage.rs +++ b/src/ctap/storage.rs @@ -198,6 +198,7 @@ impl PersistentStore { .insert(StoreEntry { tag: MASTER_KEYS, data: &master_keys, + sensitive: true, }) .unwrap(); } @@ -206,6 +207,7 @@ impl PersistentStore { .insert(StoreEntry { tag: PIN_RETRIES, data: &[MAX_PIN_RETRIES], + sensitive: false, }) .unwrap(); } @@ -245,6 +247,7 @@ impl PersistentStore { let new_entry = StoreEntry { tag: TAG_CREDENTIAL, data: &credential, + sensitive: true, }; match old_entry { None => self.store.insert(new_entry)?, @@ -299,6 +302,7 @@ impl PersistentStore { .insert(StoreEntry { tag: GLOBAL_SIGNATURE_COUNTER, data: &buffer, + sensitive: false, }) .unwrap(); } @@ -312,6 +316,7 @@ impl PersistentStore { StoreEntry { tag: GLOBAL_SIGNATURE_COUNTER, data: &buffer, + sensitive: false, }, ) .unwrap(); @@ -339,6 +344,7 @@ impl PersistentStore { let entry = StoreEntry { tag: PIN_HASH, data: pin_hash, + sensitive: true, }; match self.store.find_one(&Key::PinHash) { None => self.store.insert(entry).unwrap(), @@ -368,6 +374,7 @@ impl PersistentStore { StoreEntry { tag: PIN_RETRIES, data: &[new_value], + sensitive: false, }, ) .unwrap(); @@ -381,6 +388,7 @@ impl PersistentStore { StoreEntry { tag: PIN_RETRIES, data: &[MAX_PIN_RETRIES], + sensitive: false, }, ) .unwrap(); @@ -466,9 +474,9 @@ mod test { let storage = Storage::new(store, options); let store = embedded_flash::Store::new(storage, Config).unwrap(); // We can replace 3 bytes with minimal overhead. - assert_eq!(store.replace_len(0), 2 * WORD_SIZE); - assert_eq!(store.replace_len(3), 2 * WORD_SIZE); - assert_eq!(store.replace_len(4), 3 * WORD_SIZE); + assert_eq!(store.replace_len(false, 0), 2 * WORD_SIZE); + assert_eq!(store.replace_len(false, 3), 3 * WORD_SIZE); + assert_eq!(store.replace_len(false, 4), 3 * WORD_SIZE); } #[test] diff --git a/src/embedded_flash/store/bitfield.rs b/src/embedded_flash/store/bitfield.rs index 60c6f869b583e4cf2fb6d4ff35040fe579dc0efb..797c78bd2b2cd12554c2248318e98d68e49f3c33 100644 --- a/src/embedded_flash/store/bitfield.rs +++ b/src/embedded_flash/store/bitfield.rs @@ -55,6 +55,11 @@ impl ByteGap { bit + 8 * self.length } } + + /// Returns the slice of `data` corresponding to the gap. + pub fn slice(self, data: &[u8]) -> &[u8] { + &data[self.start..self.start + self.length] + } } /// Returns whether a bit is set in a sequence of bits. diff --git a/src/embedded_flash/store/format.rs b/src/embedded_flash/store/format.rs index cbef61f5e5981cae5b257bedc919ace462ed9449..447506c513b95ed6a234731018a38c6f83275514 100644 --- a/src/embedded_flash/store/format.rs +++ b/src/embedded_flash/store/format.rs @@ -59,6 +59,17 @@ pub struct Format { /// - 1 for insert entries. replace_bit: usize, + /// Whether a user entry has sensitive data. + /// + /// - 0 for sensitive data. + /// - 1 for non-sensitive data. + /// + /// When a user entry with sensitive data is deleted, the data is overwritten with zeroes. This + /// feature is subject to the same guarantees as all other features of the store, in particular + /// deleting a sensitive entry is atomic. See the store module-level documentation for more + /// information. + sensitive_bit: usize, + /// The data length of a user entry. length_range: bitfield::BitRange, @@ -138,8 +149,9 @@ impl Format { let deleted_bit = present_bit + 1; let internal_bit = deleted_bit + 1; let replace_bit = internal_bit + 1; + let sensitive_bit = replace_bit + 1; let length_range = bitfield::BitRange { - start: replace_bit + 1, + start: sensitive_bit + 1, length: byte_bits, }; let tag_range = bitfield::BitRange { @@ -182,6 +194,7 @@ impl Format { deleted_bit, internal_bit, replace_bit, + sensitive_bit, length_range, tag_range, replace_page_range, @@ -196,10 +209,11 @@ impl Format { // Make sure all the following conditions hold: // - The page header is one word. // - The internal entry is one word. - // - The entry header fits in one word. + // - The entry header fits in one word (which is equivalent to the entry header size being + // exactly one word for sensitive entries). if format.page_header_size() != word_size || format.internal_entry_size() != word_size - || format.header_size() > word_size + || format.header_size(true) != word_size { return None; } @@ -220,28 +234,46 @@ impl Format { /// Returns the entry header length in bytes. /// /// This is the smallest number of bytes necessary to store all fields of the entry info up to - /// and including `length`. - pub fn header_size(&self) -> usize { - self.bits_to_bytes(self.length_range.end()) + /// and including `length`. For sensitive entries, the result is word-aligned. + pub fn header_size(&self, sensitive: bool) -> usize { + let mut size = self.bits_to_bytes(self.length_range.end()); + if sensitive { + // We need to align to the next word boundary so that wiping the user data will not + // count as a write to the header. + size = self.align_word(size); + } + size + } + + /// Returns the entry header length in bytes. + /// + /// This is a convenience function for `header_size` above. + fn header_offset(&self, entry: &[u8]) -> usize { + self.header_size(self.is_sensitive(entry)) } /// Returns the entry info length in bytes. /// /// This is the number of bytes necessary to store all fields of the entry info. This also - /// includes the internal padding to protect the `committed` bit from the `deleted` bit. - fn info_size(&self, is_replace: IsReplace) -> usize { + /// includes the internal padding to protect the `committed` bit from the `deleted` bit and to + /// protect the entry info from the user data for sensitive entries. + fn info_size(&self, is_replace: IsReplace, sensitive: bool) -> usize { let suffix_bits = 2; // committed + complete let info_bits = match is_replace { IsReplace::Replace => self.replace_byte_range.end() + suffix_bits, IsReplace::Insert => self.tag_range.end() + suffix_bits, }; - let info_size = self.bits_to_bytes(info_bits); + let mut info_size = self.bits_to_bytes(info_bits); // If the suffix bits would end up in the header, we need to add one byte for them. - if info_size == self.header_size() { - info_size + 1 - } else { - info_size + let header_size = self.header_size(sensitive); + if info_size <= header_size { + info_size = header_size + 1; + } + // If the entry is sensitive, we need to align to the next word boundary. + if sensitive { + info_size = self.align_word(info_size); } + info_size } /// Returns the length in bytes of an entry. @@ -249,8 +281,8 @@ impl Format { /// This depends on the length of the user data and whether the entry replaces an old entry or /// is an insertion. This also includes the internal padding to protect the `committed` bit from /// the `deleted` bit. - pub fn entry_size(&self, is_replace: IsReplace, length: usize) -> usize { - let mut entry_size = length + self.info_size(is_replace); + pub fn entry_size(&self, is_replace: IsReplace, sensitive: bool, length: usize) -> usize { + let mut entry_size = length + self.info_size(is_replace, sensitive); let word_size = self.word_size; entry_size = self.align_word(entry_size); // The entry must be at least 2 words such that the `committed` and `deleted` bits are on @@ -308,6 +340,14 @@ impl Format { bitfield::set_zero(self.replace_bit, header, bitfield::NO_GAP) } + pub fn is_sensitive(&self, header: &[u8]) -> bool { + bitfield::is_zero(self.sensitive_bit, header, bitfield::NO_GAP) + } + + pub fn set_sensitive(&self, header: &mut [u8]) { + bitfield::set_zero(self.sensitive_bit, header, bitfield::NO_GAP) + } + pub fn get_length(&self, header: &[u8]) -> usize { bitfield::get_range(self.length_range, header, bitfield::NO_GAP) } @@ -317,16 +357,19 @@ impl Format { } pub fn get_data<'a>(&self, entry: &'a [u8]) -> &'a [u8] { - &entry[self.header_size()..][..self.get_length(entry)] + &entry[self.header_offset(entry)..][..self.get_length(entry)] } /// Returns the span of user data in an entry. /// /// The complement of this gap in the entry is exactly the entry info. The header is before the /// gap and the footer is after the gap. - fn entry_gap(&self, entry: &[u8]) -> bitfield::ByteGap { - let start = self.header_size(); - let length = self.get_length(entry); + pub fn entry_gap(&self, entry: &[u8]) -> bitfield::ByteGap { + let start = self.header_offset(entry); + let mut length = self.get_length(entry); + if self.is_sensitive(entry) { + length = self.align_word(length); + } bitfield::ByteGap { start, length } } @@ -406,16 +449,23 @@ impl Format { /// Builds an entry for replace or insert operations. pub fn build_entry(&self, replace: Option<Index>, user_entry: StoreEntry) -> Vec<u8> { - let StoreEntry { tag, data } = user_entry; + let StoreEntry { + tag, + data, + sensitive, + } = user_entry; let is_replace = match replace { None => IsReplace::Insert, Some(_) => IsReplace::Replace, }; - let entry_len = self.entry_size(is_replace, data.len()); + let entry_len = self.entry_size(is_replace, sensitive, data.len()); let mut entry = Vec::with_capacity(entry_len); // Build the header. - entry.resize(self.header_size(), 0xff); + entry.resize(self.header_size(sensitive), 0xff); self.set_present(&mut entry[..]); + if sensitive { + self.set_sensitive(&mut entry[..]); + } self.set_length(&mut entry[..], data.len()); // Add the data. entry.extend_from_slice(data); diff --git a/src/embedded_flash/store/mod.rs b/src/embedded_flash/store/mod.rs index 0431073009286219699fcce75307c66b1a957e5d..c5cf8386aad0cbe5cfcf71272b424db9c22028ea 100644 --- a/src/embedded_flash/store/mod.rs +++ b/src/embedded_flash/store/mod.rs @@ -43,6 +43,28 @@ //! The data-structure can be configured with the `StoreConfig` trait. By implementing this trait, //! the number of possible tags and the association between keys and entries are defined. //! +//! # Properties +//! +//! The data-structure provides the following properties: +//! - When an operation returns success, then the represented multi-set is updated accordingly. For +//! example, an inserted entry can be found without alteration until replaced or deleted. +//! - When an operation returns an error, the resulting multi-set state is described in the error +//! documentation. +//! - When power is lost before an operation returns, the operation will either succeed or be +//! rolled-back on the next initialization. So the multi-set would be either left unchanged or +//! updated accordingly. +//! +//! Those properties rely on the following assumptions: +//! - Writing a word to flash is atomic. When power is lost, the word is either fully written or not +//! written at all. +//! - Reading a word from flash is deterministic. When power is lost while writing or erasing a word +//! (erasing a page containing that word), reading that word repeatedly returns the same result +//! (until it is written or its page is erased). +//! - To decide whether a page has been erased, it is enough to test if all its bits are equal to 1. +//! +//! The properties may still hold outside those assumptions but with weaker probabilities as the +//! usage diverges from the assumptions. +//! //! # Implementation //! //! The store is a page-aligned sequence of bits. It matches the following grammar: @@ -57,7 +79,7 @@ //! new_page:page_bits //! Padding(word) //! Entry := Header Data Footer -//! // Let X be the byte following `length` in `Info`. +//! // Let X be the byte (word-aligned for sensitive queries) following `length` in `Info`. //! Header := Info[..X] // must fit in one word //! Footer := Info[X..] // must fit in one word //! Info := @@ -65,6 +87,7 @@ //! deleted:1 //! internal=1 //! replace:1 +//! sensitive:1 //! length:byte_bits //! tag:tag_bits //! [ // present if `replace` is 0 @@ -109,15 +132,16 @@ //! 0.1 deleted //! 0.2 internal //! 0.3 replace -//! 0.4 length (9 bits) -//! 1.5 tag (least significant 3 bits out of 5) +//! 0.4 sensitive +//! 0.5 length (9 bits) +//! 1.6 tag (least significant 2 bits out of 5) //! (the header ends at the first byte boundary after `length`) //! 2.0 <user data> (2 bytes in this example) //! (the footer starts immediately after the user data) -//! 4.0 tag (most significant 2 bits out of 5) -//! 4.2 replace_page (6 bits) -//! 5.0 replace_byte (9 bits) -//! 6.1 padding (make sure the 2 properties below hold) +//! 4.0 tag (most significant 3 bits out of 5) +//! 4.3 replace_page (6 bits) +//! 5.1 replace_byte (9 bits) +//! 6.2 padding (make sure the 2 properties below hold) //! 7.6 committed //! 7.7 complete (on a different word than `present`) //! 8.0 <end> (word-aligned) @@ -203,6 +227,11 @@ pub struct StoreEntry<'a> { /// The data of the entry. pub data: &'a [u8], + + /// Whether the data is sensitive. + /// + /// Sensitive data is overwritten with zeroes when the entry is deleted. + pub sensitive: bool, } /// Implements a configurable multi-set on top of any storage. @@ -262,6 +291,7 @@ impl<S: Storage, C: StoreConfig> Store<S, C> { StoreEntry { tag: self.format.get_tag(entry), data: self.format.get_data(entry), + sensitive: self.format.is_sensitive(entry), }, )) } else { @@ -326,7 +356,7 @@ impl<S: Storage, C: StoreConfig> Store<S, C> { self.format.validate_entry(new)?; let mut old_index = old.index; // Find a slot. - let entry_len = self.replace_len(new.data.len()); + let entry_len = self.replace_len(new.sensitive, new.data.len()); let index = self.find_slot_for_write(entry_len, Some(&mut old_index))?; // Build a new entry replacing the old one. let entry = self.format.build_entry(Some(old_index), new); @@ -360,17 +390,20 @@ impl<S: Storage, C: StoreConfig> Store<S, C> { /// Returns the byte cost of a replace operation. /// /// Computes the length in bytes that would be used in the storage if a replace operation is - /// executed provided the data of the new entry has `length` bytes. - pub fn replace_len(&self, length: usize) -> usize { - self.format.entry_size(IsReplace::Replace, length) + /// executed provided the data of the new entry has `length` bytes and whether this data is + /// sensitive. + pub fn replace_len(&self, sensitive: bool, length: usize) -> usize { + self.format + .entry_size(IsReplace::Replace, sensitive, length) } /// Returns the byte cost of an insert operation. /// /// Computes the length in bytes that would be used in the storage if an insert operation is - /// executed provided the data of the inserted entry has `length` bytes. - pub fn insert_len(&self, length: usize) -> usize { - self.format.entry_size(IsReplace::Insert, length) + /// executed provided the data of the inserted entry has `length` bytes and whether this data is + /// sensitive. + pub fn insert_len(&self, sensitive: bool, length: usize) -> usize { + self.format.entry_size(IsReplace::Insert, sensitive, length) } /// Returns the erase count of all pages. @@ -410,8 +443,11 @@ impl<S: Storage, C: StoreConfig> Store<S, C> { let entry_index = index; let entry = self.read_entry(index); index.byte += entry.len(); - if !self.format.is_alive(entry) { - // Skip deleted entries (or the page padding). + if !self.format.is_present(entry) { + // Reached the end of the page. + } else if self.format.is_deleted(entry) { + // Wipe sensitive data if needed. + self.wipe_sensitive_data(entry_index); } else if self.format.is_internal(entry) { // Finish page compaction. self.erase_page(entry_index); @@ -449,6 +485,31 @@ impl<S: Storage, C: StoreConfig> Store<S, C> { /// The provided index must point to the beginning of an entry. fn delete_index(&mut self, index: Index) { self.update_word(index, |format, word| format.set_deleted(word)); + self.wipe_sensitive_data(index); + } + + /// Wipes the data of a sensitive entry. + /// + /// If the entry at the provided index is sensitive, overwrites the data with zeroes. Otherwise, + /// does nothing. + fn wipe_sensitive_data(&mut self, mut index: Index) { + let entry = self.read_entry(index); + debug_assert!(self.format.is_present(entry)); + debug_assert!(self.format.is_deleted(entry)); + if self.format.is_internal(entry) || !self.format.is_sensitive(entry) { + // No need to wipe the data. + return; + } + let gap = self.format.entry_gap(entry); + let data = gap.slice(entry); + if data.iter().all(|&byte| byte == 0x00) { + // The data is already wiped. + return; + } + index.byte += gap.start; + self.storage + .write_slice(index, &vec![0; gap.length]) + .unwrap(); } /// Finds a page with enough free space. @@ -555,10 +616,13 @@ impl<S: Storage, C: StoreConfig> Store<S, C> { } else if self.format.is_internal(first_byte) { self.format.internal_entry_size() } else { - let header = self.read_slice(index, self.format.header_size()); + // We don't know if the entry is sensitive or not, but it doesn't matter here. We just + // need to read the replace, sensitive, and length fields. + let header = self.read_slice(index, self.format.header_size(false)); let replace = self.format.is_replace(header); + let sensitive = self.format.is_sensitive(header); let length = self.format.get_length(header); - self.format.entry_size(replace, length) + self.format.entry_size(replace, sensitive, length) }; // Truncate the length to fit the page. This can only happen in case of corruption or // partial writes. @@ -673,7 +737,7 @@ impl<S: Storage, C: StoreConfig> Store<S, C> { // Save the old page index and erase count to the new page. let erase_index = new_index; let erase_entry = self.format.build_erase_entry(old_page, erase_count); - self.storage.write_slice(new_index, &erase_entry).unwrap(); + self.write_entry(new_index, &erase_entry); // Erase the page. self.erase_page(erase_index); // Increase generation. @@ -728,6 +792,25 @@ impl<C: StoreConfig> Store<BufferStorage, C> { pub fn set_erase_count(&mut self, page: usize, erase_count: usize) { self.initialize_page(page, erase_count); } + + /// Returns whether all deleted sensitive entries have been wiped. + pub fn deleted_entries_are_wiped(&self) -> bool { + for (_, entry) in Iter::new(self) { + if !self.format.is_present(entry) + || !self.format.is_deleted(entry) + || self.format.is_internal(entry) + || !self.format.is_sensitive(entry) + { + continue; + } + let gap = self.format.entry_gap(entry); + let data = gap.slice(entry); + if !data.iter().all(|&byte| byte == 0x00) { + return false; + } + } + true + } } /// Maps an index from an old page to a new page if needed. @@ -843,7 +926,27 @@ mod tests { let tag = 0; let key = 1; let data = &[key, 2]; - let entry = StoreEntry { tag, data }; + let entry = StoreEntry { + tag, + data, + sensitive: false, + }; + store.insert(entry).unwrap(); + assert_eq!(store.iter().count(), 1); + assert_eq!(store.find_one(&key).unwrap().1, entry); + } + + #[test] + fn insert_sensitive_ok() { + let mut store = new_store(); + let tag = 0; + let key = 1; + let data = &[key, 4]; + let entry = StoreEntry { + tag, + data, + sensitive: true, + }; store.insert(entry).unwrap(); assert_eq!(store.iter().count(), 1); assert_eq!(store.find_one(&key).unwrap().1, entry); @@ -857,6 +960,25 @@ mod tests { let entry = StoreEntry { tag, data: &[key, 2], + sensitive: false, + }; + store.insert(entry).unwrap(); + assert_eq!(store.find_all(&key).count(), 1); + let (index, _) = store.find_one(&key).unwrap(); + store.delete(index).unwrap(); + assert_eq!(store.find_all(&key).count(), 0); + assert_eq!(store.iter().count(), 0); + } + + #[test] + fn delete_sensitive_ok() { + let mut store = new_store(); + let tag = 0; + let key = 1; + let entry = StoreEntry { + tag, + data: &[key, 2], + sensitive: true, }; store.insert(entry).unwrap(); assert_eq!(store.find_all(&key).count(), 1); @@ -864,6 +986,7 @@ mod tests { store.delete(index).unwrap(); assert_eq!(store.find_all(&key).count(), 0); assert_eq!(store.iter().count(), 0); + assert!(store.deleted_entries_are_wiped()); } #[test] @@ -875,6 +998,7 @@ mod tests { .insert(StoreEntry { tag, data: &[key, 0], + sensitive: false, }) .is_ok() { @@ -892,6 +1016,7 @@ mod tests { .insert(StoreEntry { tag, data: &[key, 0], + sensitive: false, }) .is_ok() { @@ -903,6 +1028,7 @@ mod tests { .insert(StoreEntry { tag: 0, data: &[key, 0], + sensitive: false, }) .unwrap(); for k in 1..=key { @@ -916,7 +1042,11 @@ mod tests { let tag = 0; let key = 1; let data = &[key, 2]; - let entry = StoreEntry { tag, data }; + let entry = StoreEntry { + tag, + data, + sensitive: false, + }; store.insert(entry).unwrap(); // Reboot the store. @@ -934,10 +1064,12 @@ mod tests { let old_entry = StoreEntry { tag, data: &[key, 2, 3, 4, 5, 6], + sensitive: false, }; let new_entry = StoreEntry { tag, data: &[key, 7, 8, 9], + sensitive: false, }; let mut delay = 0; loop { @@ -973,6 +1105,7 @@ mod tests { .insert(StoreEntry { tag, data: &[key, 0], + sensitive: false, }) .is_ok() { @@ -983,7 +1116,14 @@ mod tests { let (index, _) = store.find_one(&1).unwrap(); store.arm_snapshot(delay); store - .replace(index, StoreEntry { tag, data: &[1, 1] }) + .replace( + index, + StoreEntry { + tag, + data: &[1, 1], + sensitive: false, + }, + ) .unwrap(); let (complete, store) = match store.get_snapshot() { Err(_) => (true, store.get_storage()), @@ -995,7 +1135,11 @@ mod tests { assert_eq!(store.find_all(&k).count(), 1); assert_eq!( store.find_one(&k).unwrap().1, - StoreEntry { tag, data: &[k, 0] } + StoreEntry { + tag, + data: &[k, 0], + sensitive: false, + } ); } assert_eq!(store.find_all(&1).count(), 1); @@ -1012,7 +1156,11 @@ mod tests { #[test] fn invalid_tag() { let mut store = new_store(); - let entry = StoreEntry { tag: 1, data: &[] }; + let entry = StoreEntry { + tag: 1, + data: &[], + sensitive: false, + }; assert_eq!(store.insert(entry), Err(StoreError::InvalidTag)); } @@ -1022,6 +1170,7 @@ mod tests { let entry = StoreEntry { tag: 0, data: &[0; PAGE_SIZE], + sensitive: false, }; assert_eq!(store.insert(entry), Err(StoreError::StoreFull)); } diff --git a/src/usb_ctap_hid.rs b/src/usb_ctap_hid.rs index 421e70b08e13a5a7d8e61dbf4dbac535fbec6e25..7e63754e24df7be59b20a2c73f0ad623186f25d6 100644 --- a/src/usb_ctap_hid.rs +++ b/src/usb_ctap_hid.rs @@ -165,6 +165,57 @@ pub fn send_or_recv(buf: &mut [u8; 64]) -> SendOrRecvStatus { pub fn recv_with_timeout( buf: &mut [u8; 64], timeout_delay: Duration<isize>, +) -> Option<SendOrRecvStatus> { + #[cfg(feature = "verbose")] + writeln!( + Console::new(), + "Receiving packet with timeout of {}ms", + timeout_delay.ms(), + ) + .unwrap(); + + let result = recv_with_timeout_detail(buf, timeout_delay); + + #[cfg(feature = "verbose")] + { + if let Some(SendOrRecvStatus::Received) = result { + writeln!(Console::new(), "Received packet = {:02x?}", buf as &[u8]).unwrap(); + } + } + + result +} + +// Same as send_or_recv, but with a timeout. +// If the timeout elapses, return None. +pub fn send_or_recv_with_timeout( + buf: &mut [u8; 64], + timeout_delay: Duration<isize>, +) -> Option<SendOrRecvStatus> { + #[cfg(feature = "verbose")] + writeln!( + Console::new(), + "Sending packet with timeout of {}ms = {:02x?}", + timeout_delay.ms(), + buf as &[u8] + ) + .unwrap(); + + let result = send_or_recv_with_timeout_detail(buf, timeout_delay); + + #[cfg(feature = "verbose")] + { + if let Some(SendOrRecvStatus::Received) = result { + writeln!(Console::new(), "Received packet = {:02x?}", buf as &[u8]).unwrap(); + } + } + + result +} + +fn recv_with_timeout_detail( + buf: &mut [u8; 64], + timeout_delay: Duration<isize>, ) -> Option<SendOrRecvStatus> { let result = syscalls::allow(DRIVER_NUMBER, allow_nr::RECEIVE, buf); if result.is_err() { @@ -225,7 +276,7 @@ pub fn recv_with_timeout( // Cancel USB transaction if necessary. if status.get().is_none() { - #[cfg(feature = "debug_ctap")] + #[cfg(feature = "verbose")] writeln!(Console::new(), "Cancelling USB receive due to timeout").unwrap(); let result_code = unsafe { syscalls::command(DRIVER_NUMBER, command_nr::CANCEL, 0, 0) }; match result_code { @@ -249,9 +300,7 @@ pub fn recv_with_timeout( status.get() } -// Same as send_or_recv, but with a timeout. -// If the timeout elapses, return None. -pub fn send_or_recv_with_timeout( +fn send_or_recv_with_timeout_detail( buf: &mut [u8; 64], timeout_delay: Duration<isize>, ) -> Option<SendOrRecvStatus> { @@ -317,7 +366,7 @@ pub fn send_or_recv_with_timeout( // Cancel USB transaction if necessary. if status.get().is_none() { - #[cfg(feature = "debug_ctap")] + #[cfg(feature = "verbose")] writeln!(Console::new(), "Cancelling USB transaction due to timeout").unwrap(); let result_code = unsafe { syscalls::command(DRIVER_NUMBER, command_nr::CANCEL, 0, 0) }; match result_code { diff --git a/third_party/tock b/third_party/tock index 3139864d391ab654bfb9c27ca8dcd3e4e9a2d58e..ba44dd690f2db52ab9c928975f85c34c1c6f5bea 160000 --- a/third_party/tock +++ b/third_party/tock @@ -1 +1 @@ -Subproject commit 3139864d391ab654bfb9c27ca8dcd3e4e9a2d58e +Subproject commit ba44dd690f2db52ab9c928975f85c34c1c6f5bea