57 Commits

Author SHA1 Message Date
kaczmarczyck
893faa5113 Ask contributors to go to develop (#677)
* Ask contributors to go to develop

* Enables CI on other branches
2024-01-15 14:57:58 +01:00
kaczmarczyck
5bfd198278 Corrects the README for the 2.1 branch. (#664) 2023-11-09 17:32:14 +01:00
kaczmarczyck
c160b034ef Latest compiler and package versions (#663)
* Move to latest compiler and package versions

We also add cargo audit to the desktop tests.

* Install cargo audit differently in workflow

* Removes leftover nightly references

* Removes install check from deploy.py

The toolchain should be correctly setup after setup.sh.

* Removes rust component install from workflow

Now that the nightly version is fixed, this should work ootb.

* Moves cargo audit install to setup.sh

* Updates cargo bloat workflow to default features
2023-11-09 15:00:37 +01:00
kaczmarczyck
6ed83c34c7 Fixes cargo audit (#662) 2023-11-09 10:37:36 +01:00
kaczmarczyck
e5ba9db644 Reworks workflows into script (#661)
* Reworks some workflows to run a script instead

Advantages are:
- Only one set of tests needs maintenance.
- Local results match workflows, no surprises.
- Reduced reliance on GitHub actions.

Fixes #50, #168, #169, #171, #507

* Adds macos to the test matrix
2023-11-08 17:24:15 +01:00
kaczmarczyck
3a5adfc5af Reworks the README (#659)
* Reworks the README

Takes over content from the archived 2.0 branch. Some of it will need
another update after forking off 2.1.

Fixes #391 and replaces #652.

* Rewording README
2023-11-08 16:59:49 +01:00
kaczmarczyck
09a6b3ce1a Updates the metadata to MDS 3 (#655) 2023-11-08 00:45:39 +01:00
kaczmarczyck
778102712f venv for Python setup (#653)
* Python uses venv

* Small fixes to python calls
2023-11-07 05:13:21 +01:00
kaczmarczyck
67e3d46291 Cleans up warnings, unused functions and features (#643) 2023-08-14 13:59:54 +02:00
kaczmarczyck
8a53986961 CBOR API changes (#639)
* adds extract_* functions to CBOR library

* hides Value implementation details

* CBOR API fixes

* README adapted to API changes
2023-08-11 17:28:59 +02:00
kaczmarczyck
87f0711284 New key wrapping API (#642)
* New key wrapping API

Allows key wrapping to be different between persistent and server-side
storage.

To accomplish this, the PrivateKey now always stores the fully
reconstructed key, and has different methods to serialize it for the
respective use case.

* Cleans up legacy credential parsing

This is a backwards incompatible change. This PR already introduces
backwards incompatible new credential parsing, and therefore we can also
remove all other legacy parsing.

* Correct credential minimum size

* wider public interface to allow custom PrivateKey construction
2023-08-10 14:20:39 +02:00
Zach Halvorsen
96af5e81a5 Add more transparency into some EC structures. (#641)
This adds the ability to create ECDH keys from raw bytes and export
signatures as raw bytes.
2023-08-09 17:48:05 +02:00
Jean-Michel Picod
e3d2e7d778 Fix USB enumeration on OS X (#640)
Hopefully without breaking the others.

Summary of the changes:
- Device descriptor reports the device is bus powered and requires
  100mA max.
- HID descriptor version bumped to 1.11 (was 1.10)
- Added string index for Interface and HID descriptors (which seems to
  make OS X happy)
2023-07-26 14:21:55 +02:00
Zach Halvorsen
8868752e37 Remove duplicated alarm syscall. (#636)
The alarm syscall is implemented in libtock-rs, but was duplicated here.
This removes the duplicated code and changes the references to point to
libtock-rs directly.

Co-authored-by: kaczmarczyck <43844792+kaczmarczyck@users.noreply.github.com>
2023-07-11 17:42:50 +02:00
Zach Halvorsen
a274a512f7 Add ability to get more storage information. (#637)
This adds parameters to the storage location syscalls to specify which
storage location to get the address and size for.
2023-06-29 19:46:36 +02:00
kaczmarczyck
f0e87ee813 resolves old TODO unlocked by new compiler and spec (#634) 2023-06-13 15:31:54 +02:00
kaczmarczyck
3813cacea7 moves storage syscalls to libtock-drivers (#633) 2023-06-12 23:50:10 +02:00
kaczmarczyck
e9ea05f888 fixes new clippy lints (#632) 2023-06-12 11:11:00 +02:00
kaczmarczyck
55f7e47423 Only requires enabling EP when the command exists (#630) 2023-05-10 13:27:13 +02:00
kaczmarczyck
fbf07d7476 Fixes credProtect checking in CTAP1 (#629)
We accidentally lost this check in #516. I refactored some of the
filters for better style.

The actual difference in logic is just one line in CTAP1 authenticate,
everything else is style, a test and the order in which we convert and
filter the credentials:

```
let credential_source = filter_listed_credential(credential_source, false)
            .ok_or(Ctap1StatusCode::SW_WRONG_DATA)?;
```
2023-05-09 22:44:29 +02:00
kaczmarczyck
6fb7e194eb Compile flag for AuthenticatorConfig (#628)
* Adds a compile flag for AuthenticatorConfig

The command can be disabled for authenticators that don't want users to
change their configuration.

* adds tool for calling Config

* std now implies config_command

* removes obsolete comment
2023-05-08 15:45:32 +02:00
kaczmarczyck
94b0beed4b macos-latest for GitHub workflows (#626)
Workflows stopped running since we were on old MacOS versions. Using
latest should fix this longer-term.
2023-05-07 04:36:13 +02:00
kaczmarczyck
99f81adc55 RustCrypto in TockEnv (#625)
* Adds a rust_crypto feature to Tock

* -O3 for RustCrypto
2023-05-05 22:38:56 +02:00
kaczmarczyck
cae2088f36 Credential wrapping in Env (#624)
* Moves credential wrapping to Env

* visibility of constants

* moves PrivateKey to api

* fixes docs and imports
2023-05-05 17:09:31 +02:00
kaczmarczyck
f25cdd6acc Tock V2 port - rebased and updated (#620)
* Changes from #580

* fixes USB cancel panic

* style fixes

* Update src/env/tock/storage.rs

Co-authored-by: Zach Halvorsen <zhalvorsen@google.com>

---------

Co-authored-by: Zach Halvorsen <zhalvorsen@google.com>
2023-05-05 09:55:16 +02:00
kaczmarczyck
645c1ba3a7 Vendor Command + HID fix (#618)
* Fixes CBOR message passing through Vendor HID

I did all my tests on hardware with this fix, and now I'm surprised that
it didn't end up on develop. So should have been part of a former PR.

* vendor channel test

* forward vendor HID correctly for upgrades

* fixes cargo fmt

* removes script and updates documentation to match
2023-04-26 14:59:22 +02:00
kaczmarczyck
bcd382e5e9 Moves CTAP secrets to the key store (#617)
The PIN hash can be encrypted and decrypted, and CredRandom is part of
the master secrets.
2023-04-21 16:32:58 +02:00
kaczmarczyck
a88a1b2a22 Adds a hardware failure state for user presence (#616)
Introduced in https://github.com/google/OpenSK/pull/580

The conversion to libtock's ErrorCode has to happen outside of the
library.
2023-04-21 08:03:46 +02:00
kaczmarczyck
5f7eb3177b Cryptographic Secret type (#615)
* Adds a type for cryptographic secrets

* default implementations and zeroize documentation

* removes whitespace
2023-04-19 18:02:48 +02:00
kaczmarczyck
3091b5a29d Moves vendor commands into TockEnv (#614)
This move changes the Env trait: It removes all functionality that is
used only in vendor commands (`FirmwareProtection`, `UpgradeStorage`)
and adds a function to call when parsing CBOR commands.

The abstraction necessary to test these commands is instead realized
through compile flags. The mock upgrade storage is active when compiled
for std for example.
2023-04-17 00:17:37 +02:00
kaczmarczyck
a1d6ed0223 Makes our CredRandom derivation FIPS compliant (#613)
* Makes our CredRandom derivation FIPS compliant

This change breaks existing usage of CredRandom.

* fixes rust_crypto and HKDF test style
2023-04-11 14:48:42 +02:00
kaczmarczyck
be42b47caf Replaces Rng256 with new Rng API (#612)
* Replaces the Rng256 with RngCore from rand_core

The old trait was designed with our software crypto in mind. We should
use a more standard API going forward.

- Removes libraries/rng256/
- Ports libraries/crypto/ to rand_core
- Moves the used RNG trait to api/

* Use StdRng directy in TestEnv
2023-04-11 10:23:38 +02:00
kaczmarczyck
4cc1b4fddf Adds AES256 to the Crypto trait (#611) 2023-04-06 10:27:33 +02:00
kaczmarczyck
d0cdbec5ce Adds HKDF to the Crypto trait (#610) 2023-04-04 17:48:56 +02:00
kaczmarczyck
22192a37d2 SHA and HMAC for the Crypto trait (#609)
* Implements SHA256 into the Crypto trait

* Fixes documentation

* Descriptive documentation
2023-04-04 17:12:05 +02:00
kaczmarczyck
c168141b60 Adds a trait for crypto, porting EC first (#606)
* Adds a trait for crypto, porting EC first

* Moves crypto implementation next to its trait

* Renames constants and types
2023-04-04 13:54:41 +02:00
kaczmarczyck
80b82ffd42 LTO fix and toml cleanup (#608)
* Removes redundant entries from Cargo.toml

This also fixes a compilation problem we have in debug mode with LTO
enabled.

* fix output-path triple dash
2023-04-04 13:40:42 +02:00
kaczmarczyck
6d5ea16f2d CTAP HID Lock (#605)
* Implements the CTAP HID Lock command

This is a direct translation of our internal implementation.

* adds more HID Lock tests
2023-03-17 17:22:36 +01:00
kaczmarczyck
2560b6661c Fixes configuration failure modes in deploy.py (#604) 2023-03-11 10:12:20 +01:00
kaczmarczyck
752db8cc90 Fixes new clippy lints on the latest nightly (#603)
* Fixes new clippy lints on the latest nightly

We didn't see these before because of our old Rust toolchain.

* fixes nit
2023-03-09 12:08:34 +01:00
kaczmarczyck
ca65902a8f CTAP library move (#602)
* Moves all CTAP logic into its own library

* workflows fix test

* more coveralls workflow tests
2023-03-07 15:56:46 +01:00
kaczmarczyck
03031e6970 Maintenance PR for clippy, license and authors (#601)
* Maintenance PR for clippy, license and authors

* remove author from libraries
2023-03-06 12:45:01 +01:00
kaczmarczyck
7769e783bb AAGUID customization (#600)
* Moves the AAGUID to Customization

* Removes the AAGUID from storage

The commit is optional on top of the Customization move. I didn't see
the point in storing the AAGUID in persistent storage anymore, so I
removed it.
2023-03-06 11:42:56 +01:00
kaczmarczyck
3135c13e6b Moves the TockEnv implementation of RNG to env/ (#599)
This change removes the tock dependencies from non-Tock envs.
2023-03-06 11:21:48 +01:00
kaczmarczyck
d8512b4417 Moves Endpoint from libtock to API (#598)
The main benefit is that we removed all mentions of "tock" from all
source code that is not `main.rs` or inside `env/`.

This change makes libtock-drivers oblivious to how many endpoints are
supported. The endpoint is now checked a bit later in the stack.
2023-03-01 14:58:40 +01:00
kaczmarczyck
9a2ef0bf75 Removes timer updates from CTAP API (#597)
* Removes timer updates from CTAP API

* helper function for timer check
2023-03-01 14:30:04 +01:00
kaczmarczyck
73c60d8740 Clock trait (#596)
* adds generic Env parameters

* adds Clock type to Env

* use new Clock

* TockTimer improvements

* new Clock interface

* addressed comments

* renames constants to milliseconds, other style fixes

* removes all cargo fmt artifacts
2023-02-28 17:35:42 +01:00
kaczmarczyck
963549f9bb Removes nrfutil from default install (#595)
* remove nrfutil from the default install

* run CI Fuzz after merging, so changes are reflected
2023-02-13 17:49:29 +01:00
kaczmarczyck
98ecdec453 fixes parameter order for config (#594) 2023-02-13 17:03:08 +01:00
kaczmarczyck
a222986995 adds requirements.txt for setup (#591) 2023-02-08 11:36:01 +01:00
kaczmarczyck
8733d6585f Version string for CTAP 2.1 (#590)
* new version string for 2.1

* fixes new Python linter problems
2023-02-08 09:20:59 +01:00
浅香ジュン
684d37fa03 error-message: fix the incorrect output of low nrfutil version. (#581) 2023-01-25 15:32:37 +01:00
kaczmarczyck
0db393bd1e adds style fix and updates Cargo.lock (#576) 2023-01-04 15:19:26 +01:00
kaczmarczyck
6b5f6e53eb upgrades linked_list_allocator (#574) 2022-12-12 16:42:49 +01:00
Julien Cretin
f6e9e00b87 Add linear view into a storage (#571) 2022-12-07 13:00:41 +01:00
Julien Cretin
0d0460f016 Fix pylint versions (#572) 2022-12-07 09:53:31 +01:00
L0g4n
9ab3bc977c Respect CARGO_TARGET_DIR env var (#564)
* Respect `CARGO_TARGET_DIR` env var

This change resolves `CARGO_TARGET_DIR` when set instead of hardcoding
Cargos `target/` dir.

* Fix pylint offenses

* Simplify env query

* Fix yapf offenses
2022-10-24 06:30:32 +02:00
256 changed files with 13218 additions and 22127 deletions

View File

@@ -1,38 +0,0 @@
---
name: Build supported boards
on:
push:
paths:
- 'patches/tock/*'
- 'third_party/tock/**'
pull_request:
types: [opened, synchronize, reopened]
jobs:
build_boards:
strategy:
matrix:
os: [ubuntu-latest, macos-10.15]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
with:
submodules: "true"
- name: Install Rust toolchain
run: rustup show
- uses: actions/setup-python@v1
with:
python-version: 3.7
- name: Install Python dependencies
run: python -m pip install --upgrade pip setuptools wheel
- name: Set up OpenSK
run: ./setup.sh
- name: Building board nrf52840dk_opensk
run: ./deploy.py --board=nrf52840dk_opensk --no-app --programmer=none
- name: Building board nrf52840_dongle_opensk
run: ./deploy.py --board=nrf52840_dongle_opensk --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

View File

@@ -11,13 +11,9 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with: with:
submodules: "true" submodules: "true"
- name: Install Rust toolchain
run: rustup show
- uses: actions/setup-python@v1 - uses: actions/setup-python@v1
with: with:
python-version: 3.7 python-version: "3.10"
- name: Install Python dependencies
run: python -m pip install --upgrade pip setuptools wheel
- name: Set up OpenSK - name: Set up OpenSK
run: ./setup.sh run: ./setup.sh
- uses: actions-rs/audit-check@v1 - uses: actions-rs/audit-check@v1

View File

@@ -8,9 +8,7 @@ jobs:
# Setup # Setup
- uses: actions/setup-python@v1 - uses: actions/setup-python@v1
with: with:
python-version: 3.7 python-version: "3.10"
- name: Install Python dependencies
run: python -m pip install --upgrade pip setuptools wheel
- uses: actions-rs/cargo@v1 - uses: actions-rs/cargo@v1
with: with:
command: install command: install
@@ -20,12 +18,10 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with: with:
submodules: true submodules: true
- name: Install Rust toolchain
run: rustup show
- name: Set up OpenSK - name: Set up OpenSK
run: ./setup.sh run: ./setup.sh
- name: Run bloat on the PR - name: Run bloat on the PR
run: RUSTFLAGS="-C link-arg=-icf=all -C force-frame-pointers=no" cargo bloat --release --target=thumbv7em-none-eabi --features=with_ctap1,vendor_hid --crates >> .github/workflows/bloat_output_new.txt run: RUSTFLAGS="-C link-arg=-icf=all -C force-frame-pointers=no -C link-arg=-Tnrf52840_layout.ld" cargo bloat --release --target=thumbv7em-none-eabi --features=config_command,with_ctap1 --crates >> .github/workflows/bloat_output_new.txt
# Second run: PR # Second run: PR
- uses: actions/checkout@v2 - uses: actions/checkout@v2
@@ -33,15 +29,12 @@ jobs:
submodules: true submodules: true
ref: ${{ github.base_ref }} ref: ${{ github.base_ref }}
path: OpenSK_base path: OpenSK_base
- name: Install old Rust toolchain
working-directory: ./OpenSK_base
run: rustup show
- name: Set up OpenSK - name: Set up OpenSK
working-directory: ./OpenSK_base working-directory: ./OpenSK_base
run: ./setup.sh run: ./setup.sh
- name: Run bloat on base - name: Run bloat on base
working-directory: ./OpenSK_base working-directory: ./OpenSK_base
run: RUSTFLAGS="-C link-arg=-icf=all -C force-frame-pointers=no" cargo bloat --release --target=thumbv7em-none-eabi --features=with_ctap1,vendor_hid --crates >> "$GITHUB_WORKSPACE/.github/workflows/bloat_output_old.txt" run: RUSTFLAGS="-C link-arg=-icf=all -C force-frame-pointers=no -C link-arg=-Tnrf52840_layout.ld" cargo bloat --release --target=thumbv7em-none-eabi --features=config_command,with_ctap1 --crates >> "$GITHUB_WORKSPACE/.github/workflows/bloat_output_old.txt"
- name: Run output formatter to echo workflow command - name: Run output formatter to echo workflow command
run: ./.github/workflows/bloat_formatter.sh bloat_output_new.txt bloat_output_old.txt bloat_comment.md run: ./.github/workflows/bloat_formatter.sh bloat_output_new.txt bloat_output_old.txt bloat_comment.md

View File

@@ -1,96 +0,0 @@
name: Cargo check
on:
push:
paths:
- 'examples/*.rs'
- 'libraries/**/*.rs'
- 'src/**/*.rs'
- 'patches/**'
- '**/Cargo.toml'
- '.cargo/config'
- '!third_party/**'
pull_request:
types: [opened, synchronize, reopened]
jobs:
cargo_check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
submodules: "true"
- name: Install Rust toolchain
run: rustup show
- uses: actions/setup-python@v1
with:
python-version: 3.7
- name: Install Python dependencies
run: python -m pip install --upgrade pip setuptools wheel
- name: Set up OpenSK
run: ./setup.sh
- name: Check OpenSK w/o features
uses: actions-rs/cargo@v1
with:
command: check
args: --target thumbv7em-none-eabi --release
- name: Check OpenSK with_ctap1
uses: actions-rs/cargo@v1
with:
command: check
args: --target thumbv7em-none-eabi --release --features with_ctap1
- name: Check OpenSK vendor_hid
uses: actions-rs/cargo@v1
with:
command: check
args: --target thumbv7em-none-eabi --release --features vendor_hid
- name: Check OpenSK ed25519
uses: actions-rs/cargo@v1
with:
command: check
args: --target thumbv7em-none-eabi --release --features ed25519
- name: Check OpenSK debug_ctap
uses: actions-rs/cargo@v1
with:
command: check
args: --target thumbv7em-none-eabi --release --features debug_ctap
- name: Check OpenSK panic_console
uses: actions-rs/cargo@v1
with:
command: check
args: --target thumbv7em-none-eabi --release --features panic_console
- name: Check OpenSK debug_allocations
uses: actions-rs/cargo@v1
with:
command: check
args: --target thumbv7em-none-eabi --release --features debug_allocations
- 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,vendor_hid,ed25519,panic_console,debug_allocations,verbose
uses: actions-rs/cargo@v1
with:
command: check
args: --target thumbv7em-none-eabi --release --features debug_ctap,with_ctap1,vendor_hid,ed25519,panic_console,debug_allocations,verbose
- name: Check examples
uses: actions-rs/cargo@v1
with:
command: check
args: --target thumbv7em-none-eabi --release --examples

View File

@@ -1,34 +0,0 @@
---
name: Cargo Clippy
on:
push:
pull_request:
types: [opened, synchronize, reopened]
jobs:
cargo_clippy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
submodules: "true"
- name: Install Rust toolchain
run: rustup show
- uses: actions/setup-python@v1
with:
python-version: 3.7
- name: Install Python dependencies
run: python -m pip install --upgrade pip setuptools wheel
- name: Set up OpenSK
run: ./setup.sh
- uses: actions-rs/clippy-check@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
args: --all-targets --features std
- name: Deny Clippy warnings (std)
run: cargo clippy --all-targets --features std -- -A clippy::new_without_default -D warnings
- name: Deny Clippy warnings (all)
run: cargo clippy --all-targets --features std,with_ctap1,ed25519,vendor_hid -- -A clippy::new_without_default -D warnings
- name: Deny Clippy warnings (all, nfc)
run: cargo clippy --all-targets --features std,with_ctap1,with_nfc,ed25519,vendor_hid -- -A clippy::new_without_default -D warnings

View File

@@ -1,79 +0,0 @@
name: Cargo format
on:
push:
paths:
- 'examples/*.rs'
- 'libraries/**/*.rs'
- 'src/**/*.rs'
- 'tools/**/*.rs'
- 'patches/**'
- '**/Cargo.toml'
- '.cargo/config'
- '!third_party/**'
pull_request:
types: [opened, synchronize, reopened]
jobs:
cargo_format:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
submodules: "true"
- name: Install Rust toolchain
run: rustup show
- uses: actions/setup-python@v1
with:
python-version: 3.7
- name: Install Python dependencies
run: python -m pip install --upgrade pip setuptools wheel
- name: Set up OpenSK
run: ./setup.sh
- name: Cargo format src/
uses: actions-rs/cargo@v1
with:
command: fmt
args: --all -- --check
- name: Cargo format fuzz/
uses: actions-rs/cargo@v1
with:
command: fmt
args: --manifest-path fuzz/Cargo.toml --all -- --check
- name: Cargo format libraries/cbor
uses: actions-rs/cargo@v1
with:
command: fmt
args: --manifest-path libraries/cbor/Cargo.toml --all -- --check
- name: Cargo format libraries/cbor/fuzz
uses: actions-rs/cargo@v1
with:
command: fmt
args: --manifest-path libraries/cbor/fuzz/Cargo.toml --all -- --check
- name: Cargo format libraries/crypto
uses: actions-rs/cargo@v1
with:
command: fmt
args: --manifest-path libraries/crypto/Cargo.toml --all -- --check
- name: Cargo format libraries/persistent_store
uses: actions-rs/cargo@v1
with:
command: fmt
args: --manifest-path libraries/persistent_store/Cargo.toml --all -- --check
- name: Cargo format tools/heapviz
uses: actions-rs/cargo@v1
with:
command: fmt
args: --manifest-path tools/heapviz/Cargo.toml --all -- --check
- name: Cargo format bootloader
uses: actions-rs/cargo@v1
with:
command: fmt
args: --manifest-path bootloader/Cargo.toml --all -- --check

View File

@@ -1,32 +0,0 @@
---
name: Cargo fuzz build
on:
push:
pull_request:
types: [opened, synchronize, reopened]
jobs:
build_fuzzing:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
submodules: "true"
- name: Install Rust toolchain
run: rustup show
- uses: actions/setup-python@v1
with:
python-version: 3.7
- name: Install Python dependencies
run: python -m pip install --upgrade pip setuptools wheel
- name: Set up OpenSK
run: ./setup.sh
- name: Set up fuzzing
run: ./fuzzing_setup.sh
- name: Cargo fuzz build
run: cargo fuzz build
- name: Cargo fuzz build (libraries/cbor)
run: cd libraries/cbor && cargo fuzz build && cd ../..
- name: Cargo fuzz build (libraries/persistent_store)
run: cd libraries/persistent_store && cargo fuzz build && cd ../..

View File

@@ -1,37 +0,0 @@
---
name: CBOR tests
on:
push:
paths:
- 'libraries/cbor/**'
pull_request:
types: [opened, synchronize, reopened]
jobs:
cbor_test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
submodules: "true"
- name: Install Rust toolchain
run: rustup show
- uses: actions/setup-python@v1
with:
python-version: 3.7
- name: Install Python dependencies
run: python -m pip install --upgrade pip setuptools wheel
- name: Set up OpenSK
run: ./setup.sh
- name: Unit testing of CBOR library (release mode)
uses: actions-rs/cargo@v1
with:
command: test
args: --manifest-path libraries/cbor/Cargo.toml --release
- name: Unit testing of CBOR library (debug mode)
uses: actions-rs/cargo@v1
with:
command: test
args: --manifest-path libraries/cbor/Cargo.toml

30
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,30 @@
name: Continuous Integration
on:
push:
branches:
- develop
pull_request:
types: [opened, synchronize, reopened]
schedule:
- cron: 30 1 * * 2 # every Tuesday at 1:30 UTC
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
runtests:
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
runs-on: ${{ matrix.os }}
permissions:
contents: read
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v1
with:
python-version: "3.10"
- run: ./setup.sh
- run: ./run_desktop_tests.sh

View File

@@ -1,6 +1,6 @@
name: CIFuzz name: CIFuzz
on: on:
pull_request: push:
branches: branches:
- develop - develop
jobs: jobs:

View File

@@ -3,7 +3,6 @@ name: OpenSK code coverage report
on: on:
push: push:
paths: paths:
- 'src/**/*.rs'
- 'libraries/**/*.rs' - 'libraries/**/*.rs'
pull_request: pull_request:
types: [opened, synchronize, reopened] types: [opened, synchronize, reopened]
@@ -21,28 +20,28 @@ jobs:
run: rustup show run: rustup show
- uses: actions/setup-python@v1 - uses: actions/setup-python@v1
with: with:
python-version: 3.7 python-version: "3.10"
- name: Install Python dependencies
run: python -m pip install --upgrade pip setuptools wheel
- name: Set up OpenSK - name: Set up OpenSK
run: ./setup.sh run: ./setup.sh
- name: Install llvm tools - name: Install llvm tools
run: rustup component add llvm-tools-preview run: rustup +nightly component add llvm-tools-preview
- name: Install grcov - name: Install grcov
run: if [[ ! -e ~/.cargo/bin/grcov ]]; then cargo +stable install grcov; fi run: if [[ ! -e ~/.cargo/bin/grcov ]]; then cargo +stable install grcov; fi
- uses: actions-rs/cargo@v1 - uses: actions-rs/cargo@v1
with: with:
toolchain: nightly
command: test command: test
args: --features "with_ctap1,vendor_hid,ed25519,with_nfc,std" --no-fail-fast args: --manifest-path libraries/opensk/Cargo.toml --features "std,with_ctap1,vendor_hid,ed25519" --no-fail-fast
env: env:
RUSTFLAGS: "-Zinstrument-coverage" RUSTFLAGS: "-Cinstrument-coverage"
LLVM_PROFILE_FILE: "opensk-%p-%m.profraw" LLVM_PROFILE_FILE: "opensk-%p-%m.profraw"
- name: Run grcov - name: Run grcov
run: grcov . --binary-path ./target/debug/ --source-dir . --output-type lcov --ignore-not-existing ---output-path ./lcov.info --ignore "/*" --ignore "examples/*" --ignore "third_party/*" run: RUSTUP_TOOLCHAIN=nightly grcov . --binary-path ./libraries/opensk/target/debug/ --source-dir libraries/opensk/ --output-type lcov --ignore-not-existing --output-path ./lcov.info --ignore "/*" --ignore "examples/*" --ignore "third_party/*"
- uses: coverallsapp/github-action@1.1.3 - uses: coverallsapp/github-action@1.1.3
name: upload report to coveralls name: upload report to coveralls
with: with:
github-token: ${{ secrets.GITHUB_TOKEN }} github-token: ${{ secrets.GITHUB_TOKEN }}
path-to-lcov: "./lcov.info" path-to-lcov: "./lcov.info"
base-path: "libraries/opensk"

View File

@@ -1,41 +0,0 @@
---
name: Crypto library tests
on:
push:
paths:
- 'libraries/crypto/**'
pull_request:
types: [opened, synchronize, reopened]
paths:
- 'libraries/crypto/**'
jobs:
crypto_test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
submodules: "true"
- name: Install Rust toolchain
run: rustup show
- uses: actions/setup-python@v1
with:
python-version: 3.7
- name: Install Python dependencies
run: python -m pip install --upgrade pip setuptools wheel
- name: Set up OpenSK
run: ./setup.sh
- run: echo "RUSTFLAGS=-C target-feature=+aes" >> $GITHUB_ENV
- name: Unit testing of crypto library (release mode)
uses: actions-rs/cargo@v1
with:
command: test
args: --manifest-path libraries/crypto/Cargo.toml --release --features std
- name: Unit testing of crypto library (debug mode)
uses: actions-rs/cargo@v1
with:
command: test
args: --manifest-path libraries/crypto/Cargo.toml --features std

View File

@@ -1,34 +0,0 @@
---
name: Heapviz tool tests
on:
push:
paths:
- 'tools/heapviz/**'
pull_request:
types: [opened, synchronize, reopened]
jobs:
heapviz_test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install ncurses
run: sudo apt-get install libncurses-dev
- name: Check heapviz tool
uses: actions-rs/cargo@v1
with:
command: check
args: --manifest-path tools/heapviz/Cargo.toml
- name: Unit testing of heapviz tool (debug mode)
uses: actions-rs/cargo@v1
with:
command: test
args: --manifest-path tools/heapviz/Cargo.toml
- name: Unit testing of heapviz tool (release mode)
uses: actions-rs/cargo@v1
with:
command: test
args: --manifest-path tools/heapviz/Cargo.toml --release

View File

@@ -1,40 +0,0 @@
---
name: OpenSK build
on:
push:
pull_request:
types: [opened, synchronize, reopened]
jobs:
build_ctap2:
strategy:
matrix:
os: [ubuntu-latest, macos-10.15]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
with:
submodules: "true"
- name: Install Rust toolchain
run: rustup show
- uses: actions/setup-python@v1
with:
python-version: 3.7
- name: Install Python dependencies
run: python -m pip install --upgrade pip setuptools wheel
- name: Set up OpenSK
run: ./setup.sh
- name: Building sha256sum tool
uses: actions-rs/cargo@v1
with:
command: build
args: --manifest-path third_party/tock/tools/sha256sum/Cargo.toml
- name: Building OpenSK
uses: actions-rs/cargo@v1
with:
command: build
args: --release --target=thumbv7em-none-eabi --features with_ctap1,vendor_hid
- name: Compute SHA-256 sum
run: ./third_party/tock/tools/sha256sum/target/debug/sha256sum target/thumbv7em-none-eabi/release/ctap2

View File

@@ -1,52 +0,0 @@
---
name: OpenSK tests
on:
push:
paths:
- 'src/**/*.rs'
pull_request:
types: [opened, synchronize, reopened]
jobs:
ctap2_test:
name: CTAP2 unit tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
submodules: "true"
- name: Install Rust toolchain
run: rustup show
- uses: actions/setup-python@v1
with:
python-version: 3.7
- name: Install Python dependencies
run: python -m pip install --upgrade pip setuptools wheel
- name: Set up OpenSK
run: ./setup.sh
- name: Unit testing of CTAP2 (release mode)
uses: actions-rs/cargo@v1
with:
command: test
args: --release --features std
- name: Unit testing of CTAP2 (debug mode)
uses: actions-rs/cargo@v1
with:
command: test
args: --features std
- name: Unit testing of CTAP2 (release mode + CTAP1)
uses: actions-rs/cargo@v1
with:
command: test
args: --release --features std,with_ctap1
- name: Unit testing of CTAP2 (debug mode + CTAP1)
uses: actions-rs/cargo@v1
with:
command: test
args: --features std,with_ctap1

View File

@@ -1,29 +0,0 @@
---
name: Persistent store tests
on:
push:
paths:
- 'libraries/peristent_store/**'
pull_request:
types: [opened, synchronize, reopened]
jobs:
persistent_store_test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install Rust toolchain
run: rustup show
- name: Unit testing of Persistent store library (release mode)
uses: actions-rs/cargo@v1
with:
command: test
args: --manifest-path libraries/persistent_store/Cargo.toml --release --features=std
- name: Unit testing of Persistent store library (debug mode)
uses: actions-rs/cargo@v1
with:
command: test
args: --manifest-path libraries/persistent_store/Cargo.toml --features=std

View File

@@ -1,46 +0,0 @@
name: pylint
on:
push:
paths:
- '**/*.py'
- '.pylintrc'
- '!third_party/**'
pull_request:
types: [opened, synchronize, reopened]
jobs:
pylint:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.6, 3.7, 3.8, 3.9]
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip setuptools wheel
pip install 'tockloader==1.5' pylint
- name: Register matcher
run: echo ::add-matcher::./.github/python_matcher.json
- name: Test code with pylint
run: ./tools/run_pylint.sh
yapf:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python 3.7
uses: actions/setup-python@v1
with:
python-version: 3.7
- name: Install dependencies
run: |
python -m pip install --upgrade pip setuptools wheel
pip install 'yapf>=0.30.0' tockloader
- name: Test code formatting with yapf
run: |
echo ::add-matcher::./.github/python_matcher.json
yapf --style=yapf --recursive --exclude third_party --diff .

View File

@@ -9,7 +9,7 @@ jobs:
check_hashes: check_hashes:
strategy: strategy:
matrix: matrix:
os: [ubuntu-latest, macos-10.15] os: [ubuntu-latest, macos-latest]
fail-fast: false fail-fast: false
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
@@ -20,9 +20,7 @@ jobs:
run: rustup show run: rustup show
- uses: actions/setup-python@v1 - uses: actions/setup-python@v1
with: with:
python-version: 3.7 python-version: "3.10"
- name: Install Python dependencies
run: python -m pip install --upgrade pip setuptools wheel
- name: Set up OpenSK - name: Set up OpenSK
run: ./setup.sh run: ./setup.sh

View File

@@ -1,39 +0,0 @@
---
name: RNG library tests
on:
push:
paths:
- 'libraries/rng256/**'
pull_request:
types: [opened, synchronize, reopened]
paths:
- 'libraries/rng256/**'
jobs:
rng256_test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
submodules: "true"
- name: Install Rust toolchain
run: rustup show
- uses: actions/setup-python@v1
with:
python-version: 3.7
- name: Install Python dependencies
run: python -m pip install --upgrade pip setuptools wheel
- name: Set up OpenSK
run: ./setup.sh
- name: Unit testing of rng256library (release mode)
uses: actions-rs/cargo@v1
with:
command: test
args: --manifest-path libraries/rng256/Cargo.toml --release --features std
- name: Unit testing of rng256 library (debug mode)
uses: actions-rs/cargo@v1
with:
command: test
args: --manifest-path libraries/rng256/Cargo.toml --features std

6
.gitignore vendored
View File

@@ -1,7 +1,7 @@
fuzz/artifacts libraries/**/Cargo.lock
fuzz/corpus
fuzz/coverage
target/ target/
/build/
/py_virtual_env/
# Local installation of elf2tab. # Local installation of elf2tab.
/elf2tab/ /elf2tab/

View File

@@ -437,6 +437,6 @@ valid-metaclass-classmethod-first-arg=mcs
# Exceptions that will emit a warning when being caught. Defaults to # Exceptions that will emit a warning when being caught. Defaults to
# "Exception" # "Exception"
overgeneral-exceptions=StandardError, overgeneral-exceptions=builtins.StandardError,
Exception, builtins.Exception,
BaseException builtins.BaseException

27
CITATION.cff Normal file
View File

@@ -0,0 +1,27 @@
cff-version: 1.2.0
message: "If you use this software, please cite it as below."
repository-code: "https://github.com/google/OpenSK"
license: "Apache-2.0"
preferred-citation:
type: article
authors:
- family-names: "Ghinea"
given-names: "Diana"
- family-names: "Kaczmarczyck"
given-names: "Fabian"
- family-names: "Pullman"
given-names: "Jennifer"
- family-names: "Cretin"
given-names: "Julien"
- family-names: "Kölbl"
given-names: "Stefan"
- family-names: "Invernizzi"
given-names: "Luca"
- family-names: "Bursztein"
given-names: "Elie"
- family-names: "Picod"
given-names: "Jean-Michel"
title: "Hybrid Post-Quantum Signatures in Hardware Security Keys"
journal: "4th ACNS Workshop on Secure Cryptographic Implementation"
year: 2023
month: 6

837
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -5,38 +5,46 @@ authors = [
"Fabian Kaczmarczyck <kaczmarczyck@google.com>", "Fabian Kaczmarczyck <kaczmarczyck@google.com>",
"Guillaume Endignoux <guillaumee@google.com>", "Guillaume Endignoux <guillaumee@google.com>",
"Jean-Michel Picod <jmichel@google.com>", "Jean-Michel Picod <jmichel@google.com>",
"Julien Cretin <cretin@google.com>",
] ]
license = "Apache-2.0" license = "Apache-2.0"
edition = "2018" edition = "2018"
[target.'cfg(any(target_arch = "arm", target_arch = "riscv32"))'.dependencies.libtock_runtime]
path = "third_party/libtock-rs/runtime"
default-features = false
features = ["no_auto_layout", "no_debug_memop"]
[dependencies] [dependencies]
libtock_core = { path = "third_party/libtock-rs/core" } libtock_buttons = { path = "third_party/libtock-rs/apis/buttons" }
libtock_platform = { path = "third_party/libtock-rs/platform" }
libtock_drivers = { path = "third_party/libtock-drivers" } libtock_drivers = { path = "third_party/libtock-drivers" }
libtock_alarm = { path = "third_party/libtock-rs/apis/alarm" }
libtock_console = { path = "third_party/libtock-rs/apis/console" }
libtock_leds = { path = "third_party/libtock-rs/apis/leds" }
lang_items = { path = "third_party/lang-items" } lang_items = { path = "third_party/lang-items" }
opensk = { path = "libraries/opensk", default-features = false }
sk-cbor = { path = "libraries/cbor" } sk-cbor = { path = "libraries/cbor" }
crypto = { path = "libraries/crypto" } crypto = { path = "libraries/crypto" }
rng256 = { path = "libraries/rng256" }
persistent_store = { path = "libraries/persistent_store" } persistent_store = { path = "libraries/persistent_store" }
libtock_unittest = { path = "third_party/libtock-rs/unittest", optional = true }
byteorder = { version = "1", default-features = false } byteorder = { version = "1", default-features = false }
arrayref = "0.3.6" arrayref = "0.3.6"
subtle = { version = "2.2", default-features = false, features = ["nightly"] } rand_core = "0.6.4"
embedded-time = "0.12.1"
arbitrary = { version = "0.4.7", features = ["derive"], optional = true }
rand = { version = "0.8.4", optional = true }
ed25519-compact = { version = "1", default-features = false, optional = true } ed25519-compact = { version = "1", default-features = false, optional = true }
dilithium = { path = "third_party/dilithium" }
[features] [features]
config_command = ["opensk/config_command"]
debug_allocations = ["lang_items/debug_allocations"] debug_allocations = ["lang_items/debug_allocations"]
debug_ctap = ["libtock_drivers/debug_ctap"] debug_ctap = ["libtock_drivers/debug_ctap", "opensk/debug_ctap"]
panic_console = ["lang_items/panic_console"] panic_console = ["lang_items/panic_console"]
std = ["crypto/std", "dilithium/std", "lang_items/std", "persistent_store/std", "rng256/std", "rand"] std = ["crypto/std", "lang_items/std", "persistent_store/std", "opensk/std", "libtock_unittest"]
verbose = ["debug_ctap", "libtock_drivers/verbose_usb"] verbose = ["debug_ctap", "libtock_drivers/verbose_usb"]
with_ctap1 = ["crypto/with_ctap1"] with_ctap1 = ["opensk/with_ctap1"]
with_nfc = ["libtock_drivers/with_nfc"] with_nfc = ["libtock_drivers/with_nfc"]
vendor_hid = ["libtock_drivers/vendor_hid"] vendor_hid = ["opensk/vendor_hid"]
fuzz = ["arbitrary", "std"] ed25519 = ["ed25519-compact", "opensk/ed25519"]
ed25519 = ["ed25519-compact"] rust_crypto = ["opensk/rust_crypto"]
[dev-dependencies] [dev-dependencies]
enum-iterator = "0.6.0" enum-iterator = "0.6.0"
@@ -44,7 +52,7 @@ enum-iterator = "0.6.0"
[build-dependencies] [build-dependencies]
sk-cbor = { path = "libraries/cbor" } sk-cbor = { path = "libraries/cbor" }
uuid = { version = "0.8", features = ["v4"] } uuid = { version = "0.8", features = ["v4"] }
openssl = "0.10.36" openssl = "0.10.55"
[profile.dev] [profile.dev]
panic = "abort" panic = "abort"
@@ -55,3 +63,8 @@ panic = "abort"
lto = true # Link Time Optimization usually reduces size of binaries and static libraries lto = true # Link Time Optimization usually reduces size of binaries and static libraries
opt-level = "z" opt-level = "z"
codegen-units = 1 codegen-units = 1
[profile.release.package]
aes = { opt-level = 3 }
sha2 = { opt-level = 3 }
p256 = { opt-level = 3 }

180
README.md
View File

@@ -1,114 +1,116 @@
# <img alt="OpenSK logo" src="docs/img/OpenSK.svg" width="200px"> # <img alt="OpenSK logo" src="docs/img/OpenSK.svg" width="200px">
![markdownlint](https://github.com/google/OpenSK/workflows/markdownlint/badge.svg?branch=2.1)
[![Coverage Status](https://coveralls.io/repos/github/google/OpenSK/badge.svg?branch=2.1)](https://coveralls.io/github/google/OpenSK?branch=2.1)
*News:*
- 2023-08-24: [PQC paper reference](#Research)
## OpenSK ## OpenSK
This is an OpenSK fork that allows signing with a PQC Hybrid scheme. If you are looking for the original documentation, please check the This repository contains a Rust implementation of a
[develop branch of its GitHub page](https://github.com/google/OpenSK/tree/develop). [FIDO2](https://fidoalliance.org/fido2/) security key.
Security keys are external devices that can be used for signing in on websites.
You can see OpenSK in action in this
[video on YouTube](https://www.youtube.com/watch?v=klEozvpw0xg)!
We intend to bring a full open source experience to security keys, from
application to operating system. You can even 3D print your own open source
enclosure!
<img src="docs/img/enclosure.jpg" alt="OpenSK Enclosure" width="200"/>
You can run OpenSK as a [Tock OS](https://tockos.org) application, or use the
library to bring OpenSK to your own hardware.
You are viewing the CTAP 2.1 version. This branch fixes bugs, but doesn't
implement new features. If you want to contribute, go to the
[develop branch](https://github.com/google/OpenSK/tree/develop).
### FIDO2
OpenSK's version that implemented CTAP 2.0 was certified by the FIDO Alliance.
This branch implements version 2.1 of the
[CTAP specification](https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-errata-20220621.html).
This branch is not FIDO certified.
OpenSK supports U2F, and non-discoverable credentials created with either
protocol are compatible with the other.
### :warning: Disclaimer
This project is **proof-of-concept and a research platform**. It is **NOT**
meant for a daily usage. This branch is under development, and therefore less
rigorously tested than the numbered branches.
We're still in the process of integrating the
[ARM&reg; CryptoCell-310](https://developer.arm.com/ip-products/security-ip/cryptocell-300-family)
embedded in the
[Nordic nRF52840 chip](https://infocenter.nordicsemi.com/index.jsp?topic=%2Fps_nrf52840%2Fcryptocell.html)
to enable hardware-accelerated cryptography.
In the meantime, there are 2 options for cryptography implementations:
* Our own placeholder implementation. The code is research quality and doesn't
provide constant-time guarantees.
* The [RustCrypto](https://github.com/RustCrypto) interface. Deploy with
`--rust-crypto`. Note that our own ECC implementation is faster and has
smaller binary size, so not all boards support RustCrypto yet.
## Hardware ## Hardware
You will need a You will need one the following supported boards:
[Nordic nRF52840-DK](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52840-DK)
development kit. * [Nordic nRF52840-DK](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52840-DK)
development kit. This board is more convenient for development and debug
scenarios as the JTAG probe is already on the board.
* [Nordic nRF52840 Dongle](https://www.nordicsemi.com/Software-and-tools/Development-Kits/nRF52840-Dongle)
to have a more practical form factor.
* [Makerdiary nRF52840-MDK USB dongle](https://wiki.makerdiary.com/nrf52840-mdk/).
* [Feitian OpenSK dongle](https://feitiantech.github.io/OpenSK_USB/).
## Installation ## Installation
To install OpenSK, To install OpenSK,
1. follow the [general setup steps](docs/install.md), 1. follow the [general setup steps](docs/install.md),
1. then continue with the instructions for your specific hardware: 1. then continue with the instructions for your specific hardware:
[Nordic nRF52840-DK](docs/boards/nrf52840dk.md) * [Nordic nRF52840-DK](docs/boards/nrf52840dk.md)
* [Nordic nRF52840 Dongle](docs/boards/nrf52840_dongle.md)
* [Makerdiary nRF52840-MDK USB dongle](docs/boards/nrf52840_mdk.md)
* [Feitian OpenSK dongle](docs/boards/nrf52840_feitian.md)
## PQC Experiments To test whether the installation was successful, visit a
[demo website](https://webauthn.io/) and try to register and login.
Please check our [Troubleshooting and Debugging](docs/debugging.md) section if you
have problems with the installation process or during development. To find out what
else you can do with your OpenSK, see [Customization](docs/customization.md).
### Modes ## Research
The Dilithium mode is set at compile time. If you want to perform experiments for different modes, We implemented post-quantum cryptography on OpenSK. The code is released under
you will need to recompile. The mode is a feature, defined in the [hybrid-pqc tag](https://github.com/google/OpenSK/releases/tag/hybrid-pqc).
`third_party/dilithium/Cargo.toml`. By default, it is set to Our [paper](https://eprint.iacr.org/2022/1225) was published in the ACNS
`default = [ "dilithium5", "optimize_stack" ]`. You can change the default mode by either changing Secure Cryptographic Implementation workshop 2023 and won the best paper award.
the number 5 to 2 or 3. Or you remove the feature for stack optimizations, e.g.
`default = [ "dilithium2" ]`.
Note that some benchmarks will not run in all modes without stack optimizations. You can try to <details>
play with the stack size in these cases. As an example, stack painting for speed mode Dilithium2 <summary>Bibtex reference</summary>
works if you apply the following changes:
* `APP_HEAP_SIZE = 16384` in `deploy.py`
* `libtock_core::stack_size! {0x1A000}` in `examples/measure_stack.rs`
* `STACK_SIZE = 106496;` in `nrf52840_layout.ld`
* Change the app break from `70 * 1024` to `104 * 1024` in `patches/tock/07-app-break-fix.patch`.
For your convenience, you can also simply try:
``` ```
git apply increase_stack.patch @InProceedings{Ghinea2023hybrid,
author= {Diana Ghinea and Fabian Kaczmarczyck and Jennifer Pullman and Julien Cretin and Rafael Misoczki and Stefan Kölbl and Luca Invernizzi and Elie Bursztein and Jean-Michel Picod},
title= {{Hybrid Post-Quantum Signatures in Hardware Security Keys}},
booktitle= {{4th ACNS Workshop on Secure Cryptographic Implementation, Kyoto, Japan}},
month= {June},
year= {2023},
}
``` ```
### Compiler flags </details>
To trade binary size for speed, you can play with `[profile.release]` in `Cargo.toml`. ## Contributing
For example, try a different compiler optimization level:
``` See [Contributing.md](docs/contributing.md).
opt-level = 3
```
### Debug output ## Reporting a Vulnerability
Only the CTAP commands tests are measured end to end on the host. All other experiments are
measured on the embedded device itself and output over RTT. You can either use a client to print
results by running the following commands in different terminals:
```
JLinkExe -device nrf52 -if swd -speed 1000 -autoconnect 1
JLinkRTTClient
```
Or you directly output all messages to a file:
```
JLinkRTTLogger -device NRF52840_XXAA -if swd -speed 1000 -RTTchannel 0
```
### Perform Experiments
The paper contains the following experiments:
#### Crypto benchmarks
Deploy the `crypto_bench` example and read the debug output with one of the methods above:
```
./deploy.py --board=nrf52840dk_opensk --crypto_bench
```
#### CTAP benchmarks
To measure the speed of FIDO commands, run:
```
python benchmarks.py --runs=2000
```
Aggregate results will be printed, and the raw data is written to `make_durations.txt` and
`get_durations.txt`.
#### Stack painting
Deploy the `measure_stack` example and read the debug output with one of the methods above:
```
./deploy.py --board=nrf52840dk_opensk --measure_stack
```
#### x86 benchmarks
You don't need your embedded hardware for those, run:
```
cd third_party/dilithium/
cargo bench --features std
```
See [SECURITY.md](SECURITY.md).

View File

@@ -1,167 +0,0 @@
#!/usr/bin/env python3
# Copyright 2022 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Lint as: python3
"""Script to benchmark CTAP commands using Dilithium Hybrid signatures."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import argparse
import datetime
from subprocess import DEVNULL, STDOUT, check_call
import sys
from time import sleep
from typing import Any
import uuid
import colorama
from tqdm.auto import tqdm
from fido2 import ctap
from fido2.webauthn import PublicKeyCredentialRpEntity, PublicKeyCredentialUserEntity, PublicKeyCredentialParameters
from fido2 import hid
from tools.configure import fatal, info, get_opensk_devices
ES256_ALGORITHM = PublicKeyCredentialParameters("public-key", -7)
HYBRID_ALGORITHM = PublicKeyCredentialParameters("public-key", -65537)
def error(message: str):
tqdm.write(message)
def check_info(authenticator: Any):
"""Checks if the assumed upgrade info matches the authenticator's."""
try:
info("Reading info...")
if HYBRID_ALGORITHM not in authenticator.info.algorithms:
fatal("The device does not support hybrid signatures.")
except ctap.CtapError as ex:
error(f"Failed to read OpenSK info (error: {ex}")
def f_args(*params):
"""Constructs a dict from a list of arguments for sending a CBOR command.
None elements will be omitted.
:param params: Arguments, in order, to add to the command.
:return: The input parameters as a dict.
"""
return dict((i, v) for i, v in enumerate(params, 1) if v is not None)
def compute_stats(elapsed):
n = len(elapsed)
mean = sum(elapsed) / n
variance = sum((x - mean)**2 for x in elapsed) / n
std_dev = variance**0.5
return (mean, std_dev)
def get_authenticator():
devices = None
while not devices:
try:
devices = get_opensk_devices(False)
except Exception as e: # pylint: disable=broad-except
error(str(e))
check_call(["nrfjprog", "--reset", "--family", "NRF52"],
stdout=DEVNULL,
stderr=STDOUT)
sleep(0.1)
return devices[0]
def main(args):
colorama.init()
authenticator = get_authenticator()
# If the device supports it, wink to show which device we use.
if authenticator.device.capabilities & hid.CAPABILITY.WINK:
authenticator.device.wink()
aaguid = uuid.UUID(bytes=authenticator.get_info().aaguid)
check_info(authenticator)
info(f"Testing OpenSK device AAGUID {aaguid} ({authenticator.device}).")
make_durations = []
get_durations = []
for _ in tqdm(range(args.runs), file=sys.stdout):
authenticator = get_authenticator()
try:
start = datetime.datetime.now()
result = authenticator.make_credential(
client_data_hash=bytes(32),
rp=PublicKeyCredentialRpEntity(id="example.com", name="Example"),
user=PublicKeyCredentialUserEntity(id=b"diana", name="Diana"),
key_params=[HYBRID_ALGORITHM],
)
end = datetime.datetime.now()
make_delta = (end - start).total_seconds() * 1000.0
make_durations.append(make_delta)
credential_data = result.auth_data.credential_data
credential_id_length = 256 * credential_data[16] + credential_data[17]
credential_id = credential_data[18:18 + credential_id_length]
allow_list = [{"type": "public-key", "id": credential_id}]
start = datetime.datetime.now()
_ = authenticator.get_assertion(
rp_id="example.com",
client_data_hash=bytes(32),
allow_list=allow_list,
)
end = datetime.datetime.now()
get_delta = (end - start).total_seconds() * 1000.0
get_durations.append(get_delta)
with open("make_durations.txt", "a", encoding="utf-8") as file_make:
file_make.write(str(make_delta) + ",\n")
with open("get_durations.txt", "a", encoding="utf-8") as file_get:
file_get.write(str(get_delta) + ",\n")
except ctap.CtapError as ex:
message = "Failed to make a hybrid signature with OpenSK"
if ex.code.value == ctap.CtapError.ERR.INVALID_COMMAND:
error(f"{message} (unsupported command).")
elif ex.code.value == ctap.CtapError.ERR.INVALID_PARAMETER:
error(f"{message} (invalid parameter, maybe a wrong byte array size?).")
elif ex.code.value == 0xF2: # VENDOR_INTERNAL_ERROR
error(f"{message} (internal conditions not met).")
elif ex.code.value == 0xF3: # VENDOR_HARDWARE_FAILURE
error(f"{message} (internal hardware error).")
else:
error(f"{message} (unexpected error: {ex})")
except Exception as e: # pylint: disable=broad-except
error(str(e))
info(f"Successful operations: {len(make_durations)} and {len(get_durations)}")
info("\nMake Credential benchmark:")
(mean, std_dev) = compute_stats(make_durations)
info(f"Average: {mean} ms/iter (standard deviation: {std_dev} ms/iter)")
info("\nGet Assertion benchmark:")
(mean, std_dev) = compute_stats(get_durations)
info(f"Average: {mean} ms/iter (standard deviation: {std_dev} ms/iter)")
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument(
"--runs",
type=int,
default=1000,
help=("How many iterations to use."),
)
main(parser.parse_args())

View File

@@ -7,8 +7,7 @@ use kernel::hil::led;
use kernel::hil::uart::{self, Configure}; use kernel::hil::uart::{self, Configure};
use nrf52840::gpio::Pin; use nrf52840::gpio::Pin;
use crate::CHIP; use crate::{CHIP, PROCESSES, PROCESS_PRINTER};
use crate::PROCESSES;
struct Writer { struct Writer {
initialized: bool, initialized: bool,
@@ -31,7 +30,7 @@ impl IoWrite for Writer {
let uart = nrf52840::uart::Uarte::new(); let uart = nrf52840::uart::Uarte::new();
if !self.initialized { if !self.initialized {
self.initialized = true; self.initialized = true;
uart.configure(uart::Parameters { let _ = uart.configure(uart::Parameters {
baud_rate: 115200, baud_rate: 115200,
stop_bits: uart::StopBits::One, stop_bits: uart::StopBits::One,
parity: uart::Parity::None, parity: uart::Parity::None,
@@ -64,5 +63,6 @@ pub unsafe extern "C" fn panic_fmt(pi: &PanicInfo) -> ! {
&cortexm4::support::nop, &cortexm4::support::nop,
&PROCESSES, &PROCESSES,
&CHIP, &CHIP,
&PROCESS_PRINTER,
) )
} }

View File

@@ -7,15 +7,18 @@
// Disable this attribute when documenting, as a workaround for // Disable this attribute when documenting, as a workaround for
// https://github.com/rust-lang/rust/issues/62184. // https://github.com/rust-lang/rust/issues/62184.
#![cfg_attr(not(doc), no_main)] #![cfg_attr(not(doc), no_main)]
#![feature(const_in_array_repeat_expressions)]
#![deny(missing_docs)] #![deny(missing_docs)]
use kernel::common::dynamic_deferred_call::{DynamicDeferredCall, DynamicDeferredCallClientState}; use capsules::virtual_alarm::VirtualMuxAlarm;
use kernel::component::Component; use kernel::component::Component;
use kernel::dynamic_deferred_call::{DynamicDeferredCall, DynamicDeferredCallClientState};
use kernel::hil::led::LedLow; use kernel::hil::led::LedLow;
use kernel::hil::time::Counter; use kernel::hil::time::Counter;
use kernel::platform::{KernelResources, SyscallDriverLookup, SyscallFilter};
use kernel::scheduler::round_robin::RoundRobinSched;
#[allow(unused_imports)] #[allow(unused_imports)]
use kernel::{capabilities, create_capability, debug, debug_gpio, debug_verbose, static_init}; use kernel::{capabilities, create_capability, debug, debug_gpio, debug_verbose, static_init};
use kernel::{StorageLocation, StorageType};
use nrf52840::gpio::Pin; use nrf52840::gpio::Pin;
use nrf52840::interrupt_service::Nrf52840DefaultPeripherals; use nrf52840::interrupt_service::Nrf52840DefaultPeripherals;
use nrf52_components::{self, UartChannel, UartPins}; use nrf52_components::{self, UartChannel, UartPins};
@@ -52,34 +55,43 @@ static STRINGS: &'static [&'static str] = &[
"OpenSK", "OpenSK",
// Serial number // Serial number
"v1.0", "v1.0",
// Interface description + main HID string
"FIDO2",
// vendor HID string
"Vendor HID",
]; ];
// State for loading and holding applications. // State for loading and holding applications.
// How should the kernel respond when a process faults. // How should the kernel respond when a process faults.
const FAULT_RESPONSE: kernel::procs::FaultResponse = kernel::procs::FaultResponse::Panic; const FAULT_RESPONSE: kernel::process::PanicFaultPolicy = kernel::process::PanicFaultPolicy {};
// Number of concurrent processes this platform supports. // Number of concurrent processes this platform supports.
const NUM_PROCS: usize = 8; const NUM_PROCS: usize = 8;
static mut PROCESSES: [Option<&'static dyn kernel::procs::ProcessType>; NUM_PROCS] = static mut PROCESSES: [Option<&'static dyn kernel::process::Process>; NUM_PROCS] =
[None; NUM_PROCS]; [None; NUM_PROCS];
static mut STORAGE_LOCATIONS: [kernel::StorageLocation; 2] = [ static mut STORAGE_LOCATIONS: [StorageLocation; 2] = [
// We implement NUM_PAGES = 20 as 16 + 4 to satisfy the MPU. // We implement NUM_PAGES = 20 as 16 + 4 to satisfy the MPU.
kernel::StorageLocation { StorageLocation {
address: 0xC0000, address: 0xC0000,
size: 0x10000, // 16 pages size: 0x10000, // 16 pages
storage_type: kernel::StorageType::Store, storage_type: StorageType::Store,
}, },
kernel::StorageLocation { StorageLocation {
address: 0xD0000, address: 0xD0000,
size: 0x4000, // 4 pages size: 0x4000, // 4 pages
storage_type: kernel::StorageType::Store, storage_type: StorageType::Store,
}, },
]; ];
// Static reference to chip for panic dumps // Static reference to chip for panic dumps
static mut CHIP: Option<&'static nrf52840::chip::NRF52<Nrf52840DefaultPeripherals>> = None; static mut CHIP: Option<&'static nrf52840::chip::NRF52<Nrf52840DefaultPeripherals>> = None;
// Static reference to process printer for panic dumps
static mut PROCESS_PRINTER: Option<&'static kernel::process::ProcessPrinterText> = None;
/// Flash buffer for the custom nvmc driver
static mut APP_FLASH_BUFFER: [u8; 0x1000] = [0; 0x1000];
/// Dummy buffer that causes the linker to reserve enough space for the stack. /// Dummy buffer that causes the linker to reserve enough space for the stack.
#[no_mangle] #[no_mangle]
@@ -91,6 +103,7 @@ pub struct Platform {
button: &'static capsules::button::Button<'static, nrf52840::gpio::GPIOPin<'static>>, button: &'static capsules::button::Button<'static, nrf52840::gpio::GPIOPin<'static>>,
pconsole: &'static capsules::process_console::ProcessConsole< pconsole: &'static capsules::process_console::ProcessConsole<
'static, 'static,
VirtualMuxAlarm<'static, nrf52840::rtc::Rtc<'static>>,
components::process_console::Capability, components::process_console::Capability,
>, >,
console: &'static capsules::console::Console<'static>, console: &'static capsules::console::Console<'static>,
@@ -98,9 +111,10 @@ pub struct Platform {
led: &'static capsules::led::LedDriver< led: &'static capsules::led::LedDriver<
'static, 'static,
LedLow<'static, nrf52840::gpio::GPIOPin<'static>>, LedLow<'static, nrf52840::gpio::GPIOPin<'static>>,
4,
>, >,
rng: &'static capsules::rng::RngDriver<'static>, rng: &'static capsules::rng::RngDriver<'static>,
ipc: kernel::ipc::IPC<NUM_PROCS>, ipc: kernel::ipc::IPC<{ NUM_PROCS as u8 }>,
analog_comparator: &'static capsules::analog_comparator::AnalogComparator< analog_comparator: &'static capsules::analog_comparator::AnalogComparator<
'static, 'static,
nrf52840::acomp::Comparator<'static>, nrf52840::acomp::Comparator<'static>,
@@ -109,19 +123,20 @@ pub struct Platform {
'static, 'static,
capsules::virtual_alarm::VirtualMuxAlarm<'static, nrf52840::rtc::Rtc<'static>>, capsules::virtual_alarm::VirtualMuxAlarm<'static, nrf52840::rtc::Rtc<'static>>,
>, >,
scheduler: &'static RoundRobinSched<'static>,
systick: cortexm4::systick::SysTick,
nvmc: &'static nrf52840::nvmc::SyscallDriver, nvmc: &'static nrf52840::nvmc::SyscallDriver,
usb: &'static capsules::usb::usb_ctap::CtapUsbSyscallDriver< usb: &'static capsules::usb::usb_ctap::CtapUsbSyscallDriver<
'static, 'static,
'static, 'static,
nrf52840::usbd::Usbd<'static>, nrf52840::usbd::Usbd<'static>,
>, >,
crp: &'static capsules::firmware_protection::FirmwareProtection<nrf52840::uicr::Uicr>,
} }
impl kernel::Platform for Platform { impl SyscallDriverLookup for Platform {
fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
where where
F: FnOnce(Option<&dyn kernel::Driver>) -> R, F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R,
{ {
match driver_num { match driver_num {
capsules::console::DRIVER_NUM => f(Some(self.console)), capsules::console::DRIVER_NUM => f(Some(self.console)),
@@ -133,45 +148,88 @@ impl kernel::Platform for Platform {
capsules::analog_comparator::DRIVER_NUM => f(Some(self.analog_comparator)), capsules::analog_comparator::DRIVER_NUM => f(Some(self.analog_comparator)),
nrf52840::nvmc::DRIVER_NUM => f(Some(self.nvmc)), nrf52840::nvmc::DRIVER_NUM => f(Some(self.nvmc)),
capsules::usb::usb_ctap::DRIVER_NUM => f(Some(self.usb)), capsules::usb::usb_ctap::DRIVER_NUM => f(Some(self.usb)),
capsules::firmware_protection::DRIVER_NUM => f(Some(self.crp)),
kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)), kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)),
_ => f(None), _ => f(None),
} }
} }
}
impl SyscallFilter for Platform {
fn filter_syscall( fn filter_syscall(
&self, &self,
process: &dyn kernel::procs::ProcessType, process: &dyn kernel::process::Process,
syscall: &kernel::syscall::Syscall, syscall: &kernel::syscall::Syscall,
) -> Result<(), kernel::ReturnCode> { ) -> Result<(), kernel::errorcode::ErrorCode> {
use kernel::syscall::Syscall; use kernel::syscall::Syscall;
match *syscall { match *syscall {
Syscall::COMMAND { Syscall::Command {
driver_number: nrf52840::nvmc::DRIVER_NUM, driver_number: nrf52840::nvmc::DRIVER_NUM,
subdriver_number: cmd, subdriver_number: cmd,
arg0: ptr, arg0: ptr,
arg1: len, arg1: len,
} if (cmd == 2 || cmd == 3) && !process.fits_in_storage_location(ptr, len) => { } if (cmd == 2 || cmd == 3) && !process.fits_in_storage_location(ptr, len) => {
Err(kernel::ReturnCode::EINVAL) Err(kernel::ErrorCode::INVAL)
} }
_ => Ok(()), _ => Ok(()),
} }
} }
} }
/// Entry point in the vector table called on hard reset. impl KernelResources<nrf52840::chip::NRF52<'static, Nrf52840DefaultPeripherals<'static>>>
#[no_mangle] for Platform
pub unsafe fn reset_handler() { {
// Loads relocations and clears BSS type SyscallDriverLookup = Self;
nrf52840::init(); type SyscallFilter = Self;
type ProcessFault = ();
type Scheduler = RoundRobinSched<'static>;
type SchedulerTimer = cortexm4::systick::SysTick;
type WatchDog = ();
type ContextSwitchCallback = ();
let ppi = static_init!(nrf52840::ppi::Ppi, nrf52840::ppi::Ppi::new()); fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
&self
}
fn syscall_filter(&self) -> &Self::SyscallFilter {
&self
}
fn process_fault(&self) -> &Self::ProcessFault {
&()
}
fn scheduler(&self) -> &Self::Scheduler {
self.scheduler
}
fn scheduler_timer(&self) -> &Self::SchedulerTimer {
&self.systick
}
fn watchdog(&self) -> &Self::WatchDog {
&()
}
fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
&()
}
}
/// This is in a separate, inline(never) function so that its stack frame is
/// removed when this function returns. Otherwise, the stack space used for
/// these static_inits is wasted.
#[inline(never)]
unsafe fn get_peripherals() -> &'static mut Nrf52840DefaultPeripherals<'static> {
// Initialize chip peripheral drivers // Initialize chip peripheral drivers
let nrf52840_peripherals = static_init!( let nrf52840_peripherals = static_init!(
Nrf52840DefaultPeripherals, Nrf52840DefaultPeripherals,
Nrf52840DefaultPeripherals::new(ppi) Nrf52840DefaultPeripherals::new()
); );
nrf52840_peripherals
}
/// Main function called after RAM initialized.
#[no_mangle]
pub unsafe fn main() {
nrf52840::init();
let nrf52840_peripherals = get_peripherals();
// set up circular peripheral dependencies // set up circular peripheral dependencies
nrf52840_peripherals.init(); nrf52840_peripherals.init();
let base_peripherals = &nrf52840_peripherals.nrf52; let base_peripherals = &nrf52840_peripherals.nrf52;
@@ -184,6 +242,7 @@ pub unsafe fn reset_handler() {
// GPIOs // GPIOs
let gpio = components::gpio::GpioComponent::new( let gpio = components::gpio::GpioComponent::new(
board_kernel, board_kernel,
capsules::gpio::DRIVER_NUM,
components::gpio_component_helper!( components::gpio_component_helper!(
nrf52840::gpio::GPIOPin, nrf52840::gpio::GPIOPin,
// left side of the USB plug // left side of the USB plug
@@ -219,6 +278,7 @@ pub unsafe fn reset_handler() {
let button = components::button::ButtonComponent::new( let button = components::button::ButtonComponent::new(
board_kernel, board_kernel,
capsules::button::DRIVER_NUM,
components::button_component_helper!( components::button_component_helper!(
nrf52840::gpio::GPIOPin, nrf52840::gpio::GPIOPin,
( (
@@ -230,15 +290,12 @@ pub unsafe fn reset_handler() {
) )
.finalize(components::button_component_buf!(nrf52840::gpio::GPIOPin)); .finalize(components::button_component_buf!(nrf52840::gpio::GPIOPin));
let led = components::led::LedsComponent::new(components::led_component_helper!( let led = components::led::LedsComponent::new().finalize(components::led_component_helper!(
LedLow<'static, nrf52840::gpio::GPIOPin>, LedLow<'static, nrf52840::gpio::GPIOPin>,
LedLow::new(&nrf52840_peripherals.gpio_port[LED1_PIN]), LedLow::new(&nrf52840_peripherals.gpio_port[LED1_PIN]),
LedLow::new(&nrf52840_peripherals.gpio_port[LED2_R_PIN]), LedLow::new(&nrf52840_peripherals.gpio_port[LED2_R_PIN]),
LedLow::new(&nrf52840_peripherals.gpio_port[LED2_G_PIN]), LedLow::new(&nrf52840_peripherals.gpio_port[LED2_G_PIN]),
LedLow::new(&nrf52840_peripherals.gpio_port[LED2_B_PIN]), LedLow::new(&nrf52840_peripherals.gpio_port[LED2_B_PIN]),
))
.finalize(components::led_component_buf!(
LedLow<'static, nrf52840::gpio::GPIOPin>
)); ));
let chip = static_init!( let chip = static_init!(
@@ -272,10 +329,14 @@ pub unsafe fn reset_handler() {
); );
let rtc = &base_peripherals.rtc; let rtc = &base_peripherals.rtc;
rtc.start(); let _ = rtc.start();
let mux_alarm = components::alarm::AlarmMuxComponent::new(rtc) let mux_alarm = components::alarm::AlarmMuxComponent::new(rtc)
.finalize(components::alarm_mux_component_helper!(nrf52840::rtc::Rtc)); .finalize(components::alarm_mux_component_helper!(nrf52840::rtc::Rtc));
let alarm = components::alarm::AlarmDriverComponent::new(board_kernel, mux_alarm) let alarm = components::alarm::AlarmDriverComponent::new(
board_kernel,
capsules::alarm::DRIVER_NUM,
mux_alarm,
)
.finalize(components::alarm_component_helper!(nrf52840::rtc::Rtc)); .finalize(components::alarm_component_helper!(nrf52840::rtc::Rtc));
let uart_channel = UartChannel::Pins(UartPins::new(UART_RTS, UART_TXD, UART_CTS, UART_RXD)); let uart_channel = UartChannel::Pins(UartPins::new(UART_RTS, UART_TXD, UART_CTS, UART_RXD));
let channel = nrf52_components::UartChannelComponent::new( let channel = nrf52_components::UartChannelComponent::new(
@@ -293,21 +354,41 @@ pub unsafe fn reset_handler() {
); );
DynamicDeferredCall::set_global_instance(dynamic_deferred_caller); DynamicDeferredCall::set_global_instance(dynamic_deferred_caller);
let process_printer =
components::process_printer::ProcessPrinterTextComponent::new().finalize(());
PROCESS_PRINTER = Some(process_printer);
// Create a shared UART channel for the console and for kernel debug. // Create a shared UART channel for the console and for kernel debug.
let uart_mux = let uart_mux =
components::console::UartMuxComponent::new(channel, 115200, dynamic_deferred_caller) components::console::UartMuxComponent::new(channel, 115200, dynamic_deferred_caller)
.finalize(()); .finalize(());
let pconsole = let pconsole = components::process_console::ProcessConsoleComponent::new(
components::process_console::ProcessConsoleComponent::new(board_kernel, uart_mux) board_kernel,
.finalize(()); uart_mux,
mux_alarm,
process_printer,
)
.finalize(components::process_console_component_helper!(
nrf52840::rtc::Rtc<'static>
));
// Setup the console. // Setup the console.
let console = components::console::ConsoleComponent::new(board_kernel, uart_mux).finalize(()); let console = components::console::ConsoleComponent::new(
board_kernel,
capsules::console::DRIVER_NUM,
uart_mux,
)
.finalize(components::console_component_helper!());
// Create the debugger object that handles calls to `debug!()`. // Create the debugger object that handles calls to `debug!()`.
components::debug_writer::DebugWriterComponent::new(uart_mux).finalize(()); components::debug_writer::DebugWriterComponent::new(uart_mux).finalize(());
let rng = components::rng::RngComponent::new(board_kernel, &base_peripherals.trng).finalize(()); let rng = components::rng::RngComponent::new(
board_kernel,
capsules::rng::DRIVER_NUM,
&base_peripherals.trng,
)
.finalize(());
// Initialize AC using AIN5 (P0.29) as VIN+ and VIN- as AIN0 (P0.02) // Initialize AC using AIN5 (P0.29) as VIN+ and VIN- as AIN0 (P0.02)
// These are hardcoded pin assignments specified in the driver // These are hardcoded pin assignments specified in the driver
@@ -317,6 +398,8 @@ pub unsafe fn reset_handler() {
nrf52840::acomp::Channel, nrf52840::acomp::Channel,
&nrf52840::acomp::CHANNEL_AC0 &nrf52840::acomp::CHANNEL_AC0
), ),
board_kernel,
capsules::analog_comparator::DRIVER_NUM,
) )
.finalize(components::acomp_component_buf!( .finalize(components::acomp_component_buf!(
nrf52840::acomp::Comparator nrf52840::acomp::Comparator
@@ -326,8 +409,9 @@ pub unsafe fn reset_handler() {
nrf52840::nvmc::SyscallDriver, nrf52840::nvmc::SyscallDriver,
nrf52840::nvmc::SyscallDriver::new( nrf52840::nvmc::SyscallDriver::new(
&base_peripherals.nvmc, &base_peripherals.nvmc,
board_kernel.create_grant(&memory_allocation_capability), board_kernel.create_grant(nrf52840::nvmc::DRIVER_NUM, &memory_allocation_capability),
dynamic_deferred_caller, dynamic_deferred_caller,
&mut APP_FLASH_BUFFER,
) )
); );
nvmc.set_deferred_handle( nvmc.set_deferred_handle(
@@ -339,24 +423,20 @@ pub unsafe fn reset_handler() {
// Configure USB controller // Configure USB controller
let usb = components::usb_ctap::UsbCtapComponent::new( let usb = components::usb_ctap::UsbCtapComponent::new(
board_kernel, board_kernel,
capsules::usb::usb_ctap::DRIVER_NUM,
&nrf52840_peripherals.usbd, &nrf52840_peripherals.usbd,
capsules::usb::usbc_client::MAX_CTRL_PACKET_SIZE_NRF52840, capsules::usb::usbc_client::MAX_CTRL_PACKET_SIZE_NRF52840,
VENDOR_ID, VENDOR_ID,
PRODUCT_ID, PRODUCT_ID,
STRINGS, STRINGS,
) )
.finalize(components::usb_ctap_component_buf!(nrf52840::usbd::Usbd)); .finalize(components::usb_ctap_component_helper!(nrf52840::usbd::Usbd));
let crp = components::firmware_protection::FirmwareProtectionComponent::new(
board_kernel,
nrf52840::uicr::Uicr::new(),
)
.finalize(components::firmware_protection_component_helper!(
nrf52840::uicr::Uicr
));
nrf52_components::NrfClockComponent::new(&base_peripherals.clock).finalize(()); nrf52_components::NrfClockComponent::new(&base_peripherals.clock).finalize(());
let scheduler = components::sched::round_robin::RoundRobinComponent::new(&PROCESSES)
.finalize(components::rr_component_helper!(NUM_PROCS));
let platform = Platform { let platform = Platform {
button, button,
pconsole, pconsole,
@@ -368,15 +448,20 @@ pub unsafe fn reset_handler() {
analog_comparator, analog_comparator,
nvmc, nvmc,
usb, usb,
crp, ipc: kernel::ipc::IPC::new(
ipc: kernel::ipc::IPC::new(board_kernel, &memory_allocation_capability), board_kernel,
kernel::ipc::DRIVER_NUM,
&memory_allocation_capability,
),
scheduler,
systick: cortexm4::systick::SysTick::new_with_calibration(6400_0000),
}; };
platform.pconsole.start(); let _ = platform.pconsole.start();
debug!("Initialization complete. Entering main loop\r"); debug!("Initialization complete. Entering main loop\r");
debug!("{}", &nrf52840::ficr::FICR_INSTANCE); debug!("{}", &nrf52840::ficr::FICR_INSTANCE);
/// These symbols are defined in the linker script. // These symbols are defined in the linker script.
extern "C" { extern "C" {
/// Beginning of the ROM region containing app images. /// Beginning of the ROM region containing app images.
static _sapps: u8; static _sapps: u8;
@@ -388,7 +473,7 @@ pub unsafe fn reset_handler() {
static _eappmem: u8; static _eappmem: u8;
} }
kernel::procs::load_processes( kernel::process::load_processes(
board_kernel, board_kernel,
chip, chip,
core::slice::from_raw_parts( core::slice::from_raw_parts(
@@ -400,7 +485,7 @@ pub unsafe fn reset_handler() {
&_eappmem as *const u8 as usize - &_sappmem as *const u8 as usize, &_eappmem as *const u8 as usize - &_sappmem as *const u8 as usize,
), ),
&mut PROCESSES, &mut PROCESSES,
FAULT_RESPONSE, &FAULT_RESPONSE,
&process_management_capability, &process_management_capability,
) )
.unwrap_or_else(|err| { .unwrap_or_else(|err| {
@@ -408,13 +493,5 @@ pub unsafe fn reset_handler() {
debug!("{:?}", err); debug!("{:?}", err);
}); });
let scheduler = components::sched::round_robin::RoundRobinComponent::new(&PROCESSES) board_kernel.kernel_loop(&platform, chip, Some(&platform.ipc), &main_loop_capability);
.finalize(components::rr_component_helper!(NUM_PROCS));
board_kernel.kernel_loop(
&platform,
chip,
Some(&platform.ipc),
scheduler,
&main_loop_capability,
);
} }

View File

@@ -7,8 +7,7 @@ use kernel::hil::led;
use kernel::hil::uart::{self, Configure}; use kernel::hil::uart::{self, Configure};
use nrf52840::gpio::Pin; use nrf52840::gpio::Pin;
use crate::CHIP; use crate::{CHIP, PROCESSES, PROCESS_PRINTER};
use crate::PROCESSES;
struct Writer { struct Writer {
initialized: bool, initialized: bool,
@@ -31,7 +30,7 @@ impl IoWrite for Writer {
let uart = nrf52840::uart::Uarte::new(); let uart = nrf52840::uart::Uarte::new();
if !self.initialized { if !self.initialized {
self.initialized = true; self.initialized = true;
uart.configure(uart::Parameters { let _ = uart.configure(uart::Parameters {
baud_rate: 115200, baud_rate: 115200,
stop_bits: uart::StopBits::One, stop_bits: uart::StopBits::One,
parity: uart::Parity::None, parity: uart::Parity::None,
@@ -64,5 +63,6 @@ pub unsafe extern "C" fn panic_fmt(pi: &PanicInfo) -> ! {
&cortexm4::support::nop, &cortexm4::support::nop,
&PROCESSES, &PROCESSES,
&CHIP, &CHIP,
&PROCESS_PRINTER,
) )
} }

View File

@@ -7,13 +7,15 @@
// Disable this attribute when documenting, as a workaround for // Disable this attribute when documenting, as a workaround for
// https://github.com/rust-lang/rust/issues/62184. // https://github.com/rust-lang/rust/issues/62184.
#![cfg_attr(not(doc), no_main)] #![cfg_attr(not(doc), no_main)]
#![feature(const_in_array_repeat_expressions)]
#![deny(missing_docs)] #![deny(missing_docs)]
use kernel::common::dynamic_deferred_call::{DynamicDeferredCall, DynamicDeferredCallClientState}; use capsules::virtual_alarm::VirtualMuxAlarm;
use kernel::component::Component; use kernel::component::Component;
use kernel::dynamic_deferred_call::{DynamicDeferredCall, DynamicDeferredCallClientState};
use kernel::hil::led::LedLow; use kernel::hil::led::LedLow;
use kernel::hil::time::Counter; use kernel::hil::time::Counter;
use kernel::platform::{KernelResources, SyscallDriverLookup, SyscallFilter};
use kernel::scheduler::round_robin::RoundRobinSched;
#[allow(unused_imports)] #[allow(unused_imports)]
use kernel::{capabilities, create_capability, debug, debug_gpio, debug_verbose, static_init}; use kernel::{capabilities, create_capability, debug, debug_gpio, debug_verbose, static_init};
use nrf52840::gpio::Pin; use nrf52840::gpio::Pin;
@@ -46,16 +48,20 @@ static STRINGS: &'static [&'static str] = &[
"OpenSK", "OpenSK",
// Serial number // Serial number
"v1.0", "v1.0",
// Interface description + main HID string
"FIDO2",
// vendor HID string
"Vendor HID",
]; ];
// State for loading and holding applications. // State for loading and holding applications.
// How should the kernel respond when a process faults. // How should the kernel respond when a process faults.
const FAULT_RESPONSE: kernel::procs::FaultResponse = kernel::procs::FaultResponse::Panic; const FAULT_RESPONSE: kernel::process::PanicFaultPolicy = kernel::process::PanicFaultPolicy {};
// Number of concurrent processes this platform supports. // Number of concurrent processes this platform supports.
const NUM_PROCS: usize = 8; const NUM_PROCS: usize = 8;
static mut PROCESSES: [Option<&'static dyn kernel::procs::ProcessType>; NUM_PROCS] = static mut PROCESSES: [Option<&'static dyn kernel::process::Process>; NUM_PROCS] =
[None; NUM_PROCS]; [None; NUM_PROCS];
static mut STORAGE_LOCATIONS: [kernel::StorageLocation; 2] = [ static mut STORAGE_LOCATIONS: [kernel::StorageLocation; 2] = [
@@ -74,6 +80,9 @@ static mut STORAGE_LOCATIONS: [kernel::StorageLocation; 2] = [
// Static reference to chip for panic dumps // Static reference to chip for panic dumps
static mut CHIP: Option<&'static nrf52840::chip::NRF52<Nrf52840DefaultPeripherals>> = None; static mut CHIP: Option<&'static nrf52840::chip::NRF52<Nrf52840DefaultPeripherals>> = None;
static mut PROCESS_PRINTER: Option<&'static kernel::process::ProcessPrinterText> = None;
/// Flash buffer for the custom nvmc driver
static mut APP_FLASH_BUFFER: [u8; 0x1000] = [0; 0x1000];
/// Dummy buffer that causes the linker to reserve enough space for the stack. /// Dummy buffer that causes the linker to reserve enough space for the stack.
#[no_mangle] #[no_mangle]
@@ -85,16 +94,18 @@ pub struct Platform {
button: &'static capsules::button::Button<'static, nrf52840::gpio::GPIOPin<'static>>, button: &'static capsules::button::Button<'static, nrf52840::gpio::GPIOPin<'static>>,
pconsole: &'static capsules::process_console::ProcessConsole< pconsole: &'static capsules::process_console::ProcessConsole<
'static, 'static,
VirtualMuxAlarm<'static, nrf52840::rtc::Rtc<'static>>,
components::process_console::Capability, components::process_console::Capability,
>, >,
console: &'static capsules::console::Console<'static>, console: &'static capsules::console::Console<'static>,
gpio: &'static capsules::gpio::GPIO<'static, nrf52840::gpio::GPIOPin<'static>>, gpio: &'static capsules::gpio::GPIO<'static, nrf52840::gpio::GPIOPin<'static>>,
led: &'static capsules::led::LedDriver< led: &'static capsules::led::LedDriver<
'static, 'static,
LedLow<'static, nrf52840::gpio::GPIOPin<'static>>, kernel::hil::led::LedLow<'static, nrf52840::gpio::GPIOPin<'static>>,
3,
>, >,
rng: &'static capsules::rng::RngDriver<'static>, rng: &'static capsules::rng::RngDriver<'static>,
ipc: kernel::ipc::IPC<NUM_PROCS>, ipc: kernel::ipc::IPC<{ NUM_PROCS as u8 }>,
analog_comparator: &'static capsules::analog_comparator::AnalogComparator< analog_comparator: &'static capsules::analog_comparator::AnalogComparator<
'static, 'static,
nrf52840::acomp::Comparator<'static>, nrf52840::acomp::Comparator<'static>,
@@ -103,6 +114,8 @@ pub struct Platform {
'static, 'static,
capsules::virtual_alarm::VirtualMuxAlarm<'static, nrf52840::rtc::Rtc<'static>>, capsules::virtual_alarm::VirtualMuxAlarm<'static, nrf52840::rtc::Rtc<'static>>,
>, >,
scheduler: &'static RoundRobinSched<'static>,
systick: cortexm4::systick::SysTick,
nvmc: &'static nrf52840::nvmc::SyscallDriver, nvmc: &'static nrf52840::nvmc::SyscallDriver,
usb: &'static capsules::usb::usb_ctap::CtapUsbSyscallDriver< usb: &'static capsules::usb::usb_ctap::CtapUsbSyscallDriver<
'static, 'static,
@@ -111,10 +124,10 @@ pub struct Platform {
>, >,
} }
impl kernel::Platform for Platform { impl SyscallDriverLookup for Platform {
fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
where where
F: FnOnce(Option<&dyn kernel::Driver>) -> R, F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R,
{ {
match driver_num { match driver_num {
capsules::console::DRIVER_NUM => f(Some(self.console)), capsules::console::DRIVER_NUM => f(Some(self.console)),
@@ -130,39 +143,82 @@ impl kernel::Platform for Platform {
_ => f(None), _ => f(None),
} }
} }
}
impl SyscallFilter for Platform {
fn filter_syscall( fn filter_syscall(
&self, &self,
process: &dyn kernel::procs::ProcessType, process: &dyn kernel::process::Process,
syscall: &kernel::syscall::Syscall, syscall: &kernel::syscall::Syscall,
) -> Result<(), kernel::ReturnCode> { ) -> Result<(), kernel::errorcode::ErrorCode> {
use kernel::syscall::Syscall; use kernel::syscall::Syscall;
match *syscall { match *syscall {
Syscall::COMMAND { Syscall::Command {
driver_number: nrf52840::nvmc::DRIVER_NUM, driver_number: nrf52840::nvmc::DRIVER_NUM,
subdriver_number: cmd, subdriver_number: cmd,
arg0: ptr, arg0: ptr,
arg1: len, arg1: len,
} if (cmd == 2 || cmd == 3) && !process.fits_in_storage_location(ptr, len) => { } if (cmd == 2 || cmd == 3) && !process.fits_in_storage_location(ptr, len) => {
Err(kernel::ReturnCode::EINVAL) Err(kernel::ErrorCode::INVAL)
} }
_ => Ok(()), _ => Ok(()),
} }
} }
} }
/// Entry point in the vector table called on hard reset. /// This is in a separate, inline(never) function so that its stack frame is
#[no_mangle] /// removed when this function returns. Otherwise, the stack space used for
pub unsafe fn reset_handler() { /// these static_inits is wasted.
// Loads relocations and clears BSS #[inline(never)]
nrf52840::init(); unsafe fn get_peripherals() -> &'static mut Nrf52840DefaultPeripherals<'static> {
let ppi = static_init!(nrf52840::ppi::Ppi, nrf52840::ppi::Ppi::new());
// Initialize chip peripheral drivers // Initialize chip peripheral drivers
let nrf52840_peripherals = static_init!( let nrf52840_peripherals = static_init!(
Nrf52840DefaultPeripherals, Nrf52840DefaultPeripherals,
Nrf52840DefaultPeripherals::new(ppi) Nrf52840DefaultPeripherals::new()
); );
nrf52840_peripherals
}
impl KernelResources<nrf52840::chip::NRF52<'static, Nrf52840DefaultPeripherals<'static>>>
for Platform
{
type SyscallDriverLookup = Self;
type SyscallFilter = Self;
type ProcessFault = ();
type Scheduler = RoundRobinSched<'static>;
type SchedulerTimer = cortexm4::systick::SysTick;
type WatchDog = ();
type ContextSwitchCallback = ();
fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
&self
}
fn syscall_filter(&self) -> &Self::SyscallFilter {
&self
}
fn process_fault(&self) -> &Self::ProcessFault {
&()
}
fn scheduler(&self) -> &Self::Scheduler {
self.scheduler
}
fn scheduler_timer(&self) -> &Self::SchedulerTimer {
&self.systick
}
fn watchdog(&self) -> &Self::WatchDog {
&()
}
fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
&()
}
}
/// Main function called after RAM initialized.
#[no_mangle]
pub unsafe fn main() {
// Loads relocations and clears BSS
nrf52840::init();
// Initialize chip peripheral drivers
let nrf52840_peripherals = get_peripherals();
// set up circular peripheral dependencies // set up circular peripheral dependencies
nrf52840_peripherals.init(); nrf52840_peripherals.init();
@@ -175,6 +231,7 @@ pub unsafe fn reset_handler() {
// GPIOs // GPIOs
let gpio = components::gpio::GpioComponent::new( let gpio = components::gpio::GpioComponent::new(
board_kernel, board_kernel,
capsules::gpio::DRIVER_NUM,
components::gpio_component_helper!( components::gpio_component_helper!(
nrf52840::gpio::GPIOPin, nrf52840::gpio::GPIOPin,
// left side of the USB plug. Right side is used for UART // left side of the USB plug. Right side is used for UART
@@ -189,6 +246,7 @@ pub unsafe fn reset_handler() {
let button = components::button::ButtonComponent::new( let button = components::button::ButtonComponent::new(
board_kernel, board_kernel,
capsules::button::DRIVER_NUM,
components::button_component_helper!( components::button_component_helper!(
nrf52840::gpio::GPIOPin, nrf52840::gpio::GPIOPin,
( (
@@ -200,14 +258,11 @@ pub unsafe fn reset_handler() {
) )
.finalize(components::button_component_buf!(nrf52840::gpio::GPIOPin)); .finalize(components::button_component_buf!(nrf52840::gpio::GPIOPin));
let led = components::led::LedsComponent::new(components::led_component_helper!( let led = components::led::LedsComponent::new().finalize(components::led_component_helper!(
LedLow<'static, nrf52840::gpio::GPIOPin>, LedLow<'static, nrf52840::gpio::GPIOPin>,
LedLow::new(&nrf52840_peripherals.gpio_port[LED1_R_PIN]), LedLow::new(&nrf52840_peripherals.gpio_port[LED1_R_PIN]),
LedLow::new(&nrf52840_peripherals.gpio_port[LED1_G_PIN]), LedLow::new(&nrf52840_peripherals.gpio_port[LED1_G_PIN]),
LedLow::new(&nrf52840_peripherals.gpio_port[LED1_B_PIN]), LedLow::new(&nrf52840_peripherals.gpio_port[LED1_B_PIN]),
))
.finalize(components::led_component_buf!(
LedLow<'static, nrf52840::gpio::GPIOPin>
)); ));
let chip = static_init!( let chip = static_init!(
@@ -233,10 +288,14 @@ pub unsafe fn reset_handler() {
); );
let rtc = &base_peripherals.rtc; let rtc = &base_peripherals.rtc;
rtc.start(); let _ = rtc.start();
let mux_alarm = components::alarm::AlarmMuxComponent::new(rtc) let mux_alarm = components::alarm::AlarmMuxComponent::new(rtc)
.finalize(components::alarm_mux_component_helper!(nrf52840::rtc::Rtc)); .finalize(components::alarm_mux_component_helper!(nrf52840::rtc::Rtc));
let alarm = components::alarm::AlarmDriverComponent::new(board_kernel, mux_alarm) let alarm = components::alarm::AlarmDriverComponent::new(
board_kernel,
capsules::alarm::DRIVER_NUM,
mux_alarm,
)
.finalize(components::alarm_component_helper!(nrf52840::rtc::Rtc)); .finalize(components::alarm_component_helper!(nrf52840::rtc::Rtc));
let uart_channel = UartChannel::Pins(UartPins::new(UART_RTS, UART_TXD, UART_CTS, UART_RXD)); let uart_channel = UartChannel::Pins(UartPins::new(UART_RTS, UART_TXD, UART_CTS, UART_RXD));
let channel = nrf52_components::UartChannelComponent::new( let channel = nrf52_components::UartChannelComponent::new(
@@ -253,22 +312,40 @@ pub unsafe fn reset_handler() {
DynamicDeferredCall::new(dynamic_deferred_call_clients) DynamicDeferredCall::new(dynamic_deferred_call_clients)
); );
DynamicDeferredCall::set_global_instance(dynamic_deferred_caller); DynamicDeferredCall::set_global_instance(dynamic_deferred_caller);
let process_printer =
components::process_printer::ProcessPrinterTextComponent::new().finalize(());
PROCESS_PRINTER = Some(process_printer);
// Create a shared UART channel for the console and for kernel debug. // Create a shared UART channel for the console and for kernel debug.
let uart_mux = let uart_mux =
components::console::UartMuxComponent::new(channel, 115200, dynamic_deferred_caller) components::console::UartMuxComponent::new(channel, 115200, dynamic_deferred_caller)
.finalize(()); .finalize(());
let pconsole = let pconsole = components::process_console::ProcessConsoleComponent::new(
components::process_console::ProcessConsoleComponent::new(board_kernel, uart_mux) board_kernel,
.finalize(()); uart_mux,
mux_alarm,
process_printer,
)
.finalize(components::process_console_component_helper!(
nrf52840::rtc::Rtc<'static>
));
// Setup the console. // Setup the console.
let console = components::console::ConsoleComponent::new(board_kernel, uart_mux).finalize(()); let console = components::console::ConsoleComponent::new(
board_kernel,
capsules::console::DRIVER_NUM,
uart_mux,
)
.finalize(components::console_component_helper!());
// Create the debugger object that handles calls to `debug!()`. // Create the debugger object that handles calls to `debug!()`.
components::debug_writer::DebugWriterComponent::new(uart_mux).finalize(()); components::debug_writer::DebugWriterComponent::new(uart_mux).finalize(());
let rng = components::rng::RngComponent::new(
let rng = components::rng::RngComponent::new(board_kernel, &base_peripherals.trng).finalize(()); board_kernel,
capsules::rng::DRIVER_NUM,
&base_peripherals.trng,
)
.finalize(());
// Initialize AC using AIN5 (P0.29) as VIN+ and VIN- as AIN0 (P0.02) // Initialize AC using AIN5 (P0.29) as VIN+ and VIN- as AIN0 (P0.02)
// These are hardcoded pin assignments specified in the driver // These are hardcoded pin assignments specified in the driver
@@ -278,6 +355,8 @@ pub unsafe fn reset_handler() {
nrf52840::acomp::Channel, nrf52840::acomp::Channel,
&nrf52840::acomp::CHANNEL_AC0 &nrf52840::acomp::CHANNEL_AC0
), ),
board_kernel,
capsules::analog_comparator::DRIVER_NUM,
) )
.finalize(components::acomp_component_buf!( .finalize(components::acomp_component_buf!(
nrf52840::acomp::Comparator nrf52840::acomp::Comparator
@@ -287,8 +366,9 @@ pub unsafe fn reset_handler() {
nrf52840::nvmc::SyscallDriver, nrf52840::nvmc::SyscallDriver,
nrf52840::nvmc::SyscallDriver::new( nrf52840::nvmc::SyscallDriver::new(
&base_peripherals.nvmc, &base_peripherals.nvmc,
board_kernel.create_grant(&memory_allocation_capability), board_kernel.create_grant(nrf52840::nvmc::DRIVER_NUM, &memory_allocation_capability),
dynamic_deferred_caller, dynamic_deferred_caller,
&mut APP_FLASH_BUFFER,
) )
); );
nvmc.set_deferred_handle( nvmc.set_deferred_handle(
@@ -300,16 +380,20 @@ pub unsafe fn reset_handler() {
// Configure USB controller // Configure USB controller
let usb = components::usb_ctap::UsbCtapComponent::new( let usb = components::usb_ctap::UsbCtapComponent::new(
board_kernel, board_kernel,
capsules::usb::usb_ctap::DRIVER_NUM,
&nrf52840_peripherals.usbd, &nrf52840_peripherals.usbd,
capsules::usb::usbc_client::MAX_CTRL_PACKET_SIZE_NRF52840, capsules::usb::usbc_client::MAX_CTRL_PACKET_SIZE_NRF52840,
VENDOR_ID, VENDOR_ID,
PRODUCT_ID, PRODUCT_ID,
STRINGS, STRINGS,
) )
.finalize(components::usb_ctap_component_buf!(nrf52840::usbd::Usbd)); .finalize(components::usb_ctap_component_helper!(nrf52840::usbd::Usbd));
nrf52_components::NrfClockComponent::new(&base_peripherals.clock).finalize(()); nrf52_components::NrfClockComponent::new(&base_peripherals.clock).finalize(());
let scheduler = components::sched::round_robin::RoundRobinComponent::new(&PROCESSES)
.finalize(components::rr_component_helper!(NUM_PROCS));
let platform = Platform { let platform = Platform {
button, button,
pconsole, pconsole,
@@ -321,14 +405,20 @@ pub unsafe fn reset_handler() {
analog_comparator, analog_comparator,
nvmc, nvmc,
usb, usb,
ipc: kernel::ipc::IPC::new(board_kernel, &memory_allocation_capability), ipc: kernel::ipc::IPC::new(
board_kernel,
kernel::ipc::DRIVER_NUM,
&memory_allocation_capability,
),
scheduler,
systick: cortexm4::systick::SysTick::new_with_calibration(64000000),
}; };
platform.pconsole.start(); let _ = platform.pconsole.start();
debug!("Initialization complete. Entering main loop\r"); debug!("Initialization complete. Entering main loop\r");
debug!("{}", &nrf52840::ficr::FICR_INSTANCE); debug!("{}", &nrf52840::ficr::FICR_INSTANCE);
/// These symbols are defined in the linker script. // These symbols are defined in the linker script.
extern "C" { extern "C" {
/// Beginning of the ROM region containing app images. /// Beginning of the ROM region containing app images.
static _sapps: u8; static _sapps: u8;
@@ -340,7 +430,7 @@ pub unsafe fn reset_handler() {
static _eappmem: u8; static _eappmem: u8;
} }
kernel::procs::load_processes( kernel::process::load_processes(
board_kernel, board_kernel,
chip, chip,
core::slice::from_raw_parts( core::slice::from_raw_parts(
@@ -352,7 +442,7 @@ pub unsafe fn reset_handler() {
&_eappmem as *const u8 as usize - &_sappmem as *const u8 as usize, &_eappmem as *const u8 as usize - &_sappmem as *const u8 as usize,
), ),
&mut PROCESSES, &mut PROCESSES,
FAULT_RESPONSE, &FAULT_RESPONSE,
&process_management_capability, &process_management_capability,
) )
.unwrap_or_else(|err| { .unwrap_or_else(|err| {
@@ -360,13 +450,5 @@ pub unsafe fn reset_handler() {
debug!("{:?}", err); debug!("{:?}", err);
}); });
let scheduler = components::sched::round_robin::RoundRobinComponent::new(&PROCESSES) board_kernel.kernel_loop(&platform, chip, Some(&platform.ipc), &main_loop_capability);
.finalize(components::rr_component_helper!(NUM_PROCS));
board_kernel.kernel_loop(
&platform,
chip,
Some(&platform.ipc),
scheduler,
&main_loop_capability,
);
} }

View File

@@ -10,6 +10,7 @@ use nrf52840::gpio::Pin;
use crate::CHIP; use crate::CHIP;
use crate::PROCESSES; use crate::PROCESSES;
use crate::PROCESS_PRINTER;
enum Writer { enum Writer {
WriterUart(/* initialized */ bool), WriterUart(/* initialized */ bool),
@@ -48,7 +49,7 @@ impl IoWrite for Writer {
let uart = nrf52840::uart::Uarte::new(); let uart = nrf52840::uart::Uarte::new();
if !*initialized { if !*initialized {
*initialized = true; *initialized = true;
uart.configure(uart::Parameters { let _ = uart.configure(uart::Parameters {
baud_rate: 115200, baud_rate: 115200,
stop_bits: uart::StopBits::One, stop_bits: uart::StopBits::One,
parity: uart::Parity::None, parity: uart::Parity::None,
@@ -102,5 +103,6 @@ pub unsafe extern "C" fn panic_fmt(pi: &PanicInfo) -> ! {
&cortexm4::support::nop, &cortexm4::support::nop,
&PROCESSES, &PROCESSES,
&CHIP, &CHIP,
&PROCESS_PRINTER,
) )
} }

View File

@@ -64,14 +64,16 @@
// Disable this attribute when documenting, as a workaround for // Disable this attribute when documenting, as a workaround for
// https://github.com/rust-lang/rust/issues/62184. // https://github.com/rust-lang/rust/issues/62184.
#![cfg_attr(not(doc), no_main)] #![cfg_attr(not(doc), no_main)]
#![feature(const_in_array_repeat_expressions)]
#![deny(missing_docs)] #![deny(missing_docs)]
use capsules::virtual_alarm::VirtualMuxAlarm;
use core::env; use core::env;
use kernel::common::dynamic_deferred_call::{DynamicDeferredCall, DynamicDeferredCallClientState};
use kernel::component::Component; use kernel::component::Component;
use kernel::dynamic_deferred_call::{DynamicDeferredCall, DynamicDeferredCallClientState};
use kernel::hil::led::LedLow; use kernel::hil::led::LedLow;
use kernel::hil::time::Counter; use kernel::hil::time::Counter;
use kernel::platform::{KernelResources, SyscallDriverLookup, SyscallFilter};
use kernel::scheduler::round_robin::RoundRobinSched;
#[allow(unused_imports)] #[allow(unused_imports)]
use kernel::{capabilities, create_capability, debug, debug_gpio, debug_verbose, static_init}; use kernel::{capabilities, create_capability, debug, debug_gpio, debug_verbose, static_init};
use nrf52840::gpio::Pin; use nrf52840::gpio::Pin;
@@ -117,32 +119,41 @@ static STRINGS: &'static [&'static str] = &[
"OpenSK", "OpenSK",
// Serial number // Serial number
"v1.0", "v1.0",
// Interface description + main HID string
"FIDO2",
// vendor HID string
"Vendor HID",
]; ];
// State for loading and holding applications. // State for loading and holding applications.
// How should the kernel respond when a process faults. // How should the kernel respond when a process faults.
const FAULT_RESPONSE: kernel::procs::FaultResponse = kernel::procs::FaultResponse::Panic; const FAULT_RESPONSE: kernel::process::PanicFaultPolicy = kernel::process::PanicFaultPolicy {};
// Number of concurrent processes this platform supports. // Number of concurrent processes this platform supports.
const NUM_PROCS: usize = 8; const NUM_PROCS: usize = 8;
static mut PROCESSES: [Option<&'static dyn kernel::procs::ProcessType>; NUM_PROCS] = static mut PROCESSES: [Option<&'static dyn kernel::process::Process>; NUM_PROCS] =
[None; NUM_PROCS]; [None; NUM_PROCS];
include!(concat!(env!("OUT_DIR"), "/locations.rs")); include!(concat!(env!("OUT_DIR"), "/locations.rs"));
static mut CHIP: Option<&'static nrf52840::chip::NRF52<Nrf52840DefaultPeripherals>> = None; static mut CHIP: Option<&'static nrf52840::chip::NRF52<Nrf52840DefaultPeripherals>> = None;
static mut PROCESS_PRINTER: Option<&'static kernel::process::ProcessPrinterText> = None;
/// Flash buffer for the custom nvmc driver
static mut APP_FLASH_BUFFER: [u8; 0x1000] = [0; 0x1000];
/// Dummy buffer that causes the linker to reserve enough space for the stack. /// Dummy buffer that causes the linker to reserve enough space for the stack.
#[no_mangle] #[no_mangle]
#[link_section = ".stack_buffer"] #[link_section = ".stack_buffer"]
pub static mut STACK_MEMORY: [u8; 0x1000] = [0; 0x1000]; pub static mut STACK_MEMORY: [u8; 0x2000] = [0; 0x2000];
/// Supported drivers by the platform /// Supported drivers by the platform
pub struct Platform { pub struct Platform {
button: &'static capsules::button::Button<'static, nrf52840::gpio::GPIOPin<'static>>, button: &'static capsules::button::Button<'static, nrf52840::gpio::GPIOPin<'static>>,
pconsole: &'static capsules::process_console::ProcessConsole< pconsole: &'static capsules::process_console::ProcessConsole<
'static, 'static,
VirtualMuxAlarm<'static, nrf52840::rtc::Rtc<'static>>,
components::process_console::Capability, components::process_console::Capability,
>, >,
console: &'static capsules::console::Console<'static>, console: &'static capsules::console::Console<'static>,
@@ -150,9 +161,10 @@ pub struct Platform {
led: &'static capsules::led::LedDriver< led: &'static capsules::led::LedDriver<
'static, 'static,
kernel::hil::led::LedLow<'static, nrf52840::gpio::GPIOPin<'static>>, kernel::hil::led::LedLow<'static, nrf52840::gpio::GPIOPin<'static>>,
4,
>, >,
rng: &'static capsules::rng::RngDriver<'static>, rng: &'static capsules::rng::RngDriver<'static>,
ipc: kernel::ipc::IPC<NUM_PROCS>, ipc: kernel::ipc::IPC<{ NUM_PROCS as u8 }>,
analog_comparator: &'static capsules::analog_comparator::AnalogComparator< analog_comparator: &'static capsules::analog_comparator::AnalogComparator<
'static, 'static,
nrf52840::acomp::Comparator<'static>, nrf52840::acomp::Comparator<'static>,
@@ -167,13 +179,14 @@ pub struct Platform {
'static, 'static,
nrf52840::usbd::Usbd<'static>, nrf52840::usbd::Usbd<'static>,
>, >,
crp: &'static capsules::firmware_protection::FirmwareProtection<nrf52840::uicr::Uicr>, scheduler: &'static RoundRobinSched<'static>,
systick: cortexm4::systick::SysTick,
} }
impl kernel::Platform for Platform { impl SyscallDriverLookup for Platform {
fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
where where
F: FnOnce(Option<&dyn kernel::Driver>) -> R, F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R,
{ {
match driver_num { match driver_num {
capsules::console::DRIVER_NUM => f(Some(self.console)), capsules::console::DRIVER_NUM => f(Some(self.console)),
@@ -185,44 +198,89 @@ impl kernel::Platform for Platform {
capsules::analog_comparator::DRIVER_NUM => f(Some(self.analog_comparator)), capsules::analog_comparator::DRIVER_NUM => f(Some(self.analog_comparator)),
nrf52840::nvmc::DRIVER_NUM => f(Some(self.nvmc)), nrf52840::nvmc::DRIVER_NUM => f(Some(self.nvmc)),
capsules::usb::usb_ctap::DRIVER_NUM => f(Some(self.usb)), capsules::usb::usb_ctap::DRIVER_NUM => f(Some(self.usb)),
capsules::firmware_protection::DRIVER_NUM => f(Some(self.crp)),
kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)), kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)),
_ => f(None), _ => f(None),
} }
} }
}
impl SyscallFilter for Platform {
fn filter_syscall( fn filter_syscall(
&self, &self,
process: &dyn kernel::procs::ProcessType, process: &dyn kernel::process::Process,
syscall: &kernel::syscall::Syscall, syscall: &kernel::syscall::Syscall,
) -> Result<(), kernel::ReturnCode> { ) -> Result<(), kernel::errorcode::ErrorCode> {
use kernel::syscall::Syscall; use kernel::syscall::Syscall;
match *syscall { match *syscall {
Syscall::COMMAND { Syscall::Command {
driver_number: nrf52840::nvmc::DRIVER_NUM, driver_number: nrf52840::nvmc::DRIVER_NUM,
subdriver_number: cmd, subdriver_number: cmd,
arg0: ptr, arg0: ptr,
arg1: len, arg1: len,
} if (cmd == 2 || cmd == 3) && !process.fits_in_storage_location(ptr, len) => { } if (cmd == 2 || cmd == 3) && !process.fits_in_storage_location(ptr, len) => {
Err(kernel::ReturnCode::EINVAL) Err(kernel::ErrorCode::INVAL)
} }
_ => Ok(()), _ => Ok(()),
} }
} }
} }
/// Entry point in the vector table called on hard reset. /// This is in a separate, inline(never) function so that its stack frame is
#[no_mangle] /// removed when this function returns. Otherwise, the stack space used for
pub unsafe fn reset_handler() { /// these static_inits is wasted.
// Loads relocations and clears BSS #[inline(never)]
nrf52840::init(); unsafe fn get_peripherals() -> &'static mut Nrf52840DefaultPeripherals<'static> {
let ppi = static_init!(nrf52840::ppi::Ppi, nrf52840::ppi::Ppi::new());
// Initialize chip peripheral drivers // Initialize chip peripheral drivers
let nrf52840_peripherals = static_init!( let nrf52840_peripherals = static_init!(
Nrf52840DefaultPeripherals, Nrf52840DefaultPeripherals,
Nrf52840DefaultPeripherals::new(ppi) Nrf52840DefaultPeripherals::new()
); );
nrf52840_peripherals
}
impl KernelResources<nrf52840::chip::NRF52<'static, Nrf52840DefaultPeripherals<'static>>>
for Platform
{
type SyscallDriverLookup = Self;
type SyscallFilter = Self;
type ProcessFault = ();
type Scheduler = RoundRobinSched<'static>;
type SchedulerTimer = cortexm4::systick::SysTick;
type WatchDog = ();
type ContextSwitchCallback = ();
fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
&self
}
fn syscall_filter(&self) -> &Self::SyscallFilter {
&self
}
fn process_fault(&self) -> &Self::ProcessFault {
&()
}
fn scheduler(&self) -> &Self::Scheduler {
self.scheduler
}
fn scheduler_timer(&self) -> &Self::SchedulerTimer {
&self.systick
}
fn watchdog(&self) -> &Self::WatchDog {
&()
}
fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
&()
}
}
/// Main function called after RAM initialized.
#[no_mangle]
pub unsafe fn main() {
// Loads relocations and clears BSS
nrf52840::init();
// Initialize chip peripheral drivers
let nrf52840_peripherals = get_peripherals();
// set up circular peripheral dependencies // set up circular peripheral dependencies
nrf52840_peripherals.init(); nrf52840_peripherals.init();
let base_peripherals = &nrf52840_peripherals.nrf52; let base_peripherals = &nrf52840_peripherals.nrf52;
@@ -249,6 +307,7 @@ pub unsafe fn reset_handler() {
let gpio = components::gpio::GpioComponent::new( let gpio = components::gpio::GpioComponent::new(
board_kernel, board_kernel,
capsules::gpio::DRIVER_NUM,
components::gpio_component_helper!( components::gpio_component_helper!(
nrf52840::gpio::GPIOPin, nrf52840::gpio::GPIOPin,
0 => &nrf52840_peripherals.gpio_port[Pin::P1_01], 0 => &nrf52840_peripherals.gpio_port[Pin::P1_01],
@@ -273,6 +332,7 @@ pub unsafe fn reset_handler() {
let button = components::button::ButtonComponent::new( let button = components::button::ButtonComponent::new(
board_kernel, board_kernel,
capsules::button::DRIVER_NUM,
components::button_component_helper!( components::button_component_helper!(
nrf52840::gpio::GPIOPin, nrf52840::gpio::GPIOPin,
( (
@@ -299,15 +359,12 @@ pub unsafe fn reset_handler() {
) )
.finalize(components::button_component_buf!(nrf52840::gpio::GPIOPin)); .finalize(components::button_component_buf!(nrf52840::gpio::GPIOPin));
let led = components::led::LedsComponent::new(components::led_component_helper!( let led = components::led::LedsComponent::new().finalize(components::led_component_helper!(
LedLow<'static, nrf52840::gpio::GPIOPin>, LedLow<'static, nrf52840::gpio::GPIOPin>,
LedLow::new(&nrf52840_peripherals.gpio_port[LED1_PIN]), LedLow::new(&nrf52840_peripherals.gpio_port[LED1_PIN]),
LedLow::new(&nrf52840_peripherals.gpio_port[LED2_PIN]), LedLow::new(&nrf52840_peripherals.gpio_port[LED2_PIN]),
LedLow::new(&nrf52840_peripherals.gpio_port[LED3_PIN]), LedLow::new(&nrf52840_peripherals.gpio_port[LED3_PIN]),
LedLow::new(&nrf52840_peripherals.gpio_port[LED4_PIN]), LedLow::new(&nrf52840_peripherals.gpio_port[LED4_PIN]),
))
.finalize(components::led_component_buf!(
LedLow<'static, nrf52840::gpio::GPIOPin>
)); ));
let chip = static_init!( let chip = static_init!(
@@ -339,10 +396,14 @@ pub unsafe fn reset_handler() {
); );
let rtc = &base_peripherals.rtc; let rtc = &base_peripherals.rtc;
rtc.start(); let _ = rtc.start();
let mux_alarm = components::alarm::AlarmMuxComponent::new(rtc) let mux_alarm = components::alarm::AlarmMuxComponent::new(rtc)
.finalize(components::alarm_mux_component_helper!(nrf52840::rtc::Rtc)); .finalize(components::alarm_mux_component_helper!(nrf52840::rtc::Rtc));
let alarm = components::alarm::AlarmDriverComponent::new(board_kernel, mux_alarm) let alarm = components::alarm::AlarmDriverComponent::new(
board_kernel,
capsules::alarm::DRIVER_NUM,
mux_alarm,
)
.finalize(components::alarm_component_helper!(nrf52840::rtc::Rtc)); .finalize(components::alarm_component_helper!(nrf52840::rtc::Rtc));
let channel = nrf52_components::UartChannelComponent::new( let channel = nrf52_components::UartChannelComponent::new(
@@ -359,22 +420,41 @@ pub unsafe fn reset_handler() {
DynamicDeferredCall::new(dynamic_deferred_call_clients) DynamicDeferredCall::new(dynamic_deferred_call_clients)
); );
DynamicDeferredCall::set_global_instance(dynamic_deferred_caller); DynamicDeferredCall::set_global_instance(dynamic_deferred_caller);
let process_printer =
components::process_printer::ProcessPrinterTextComponent::new().finalize(());
PROCESS_PRINTER = Some(process_printer);
// Create a shared UART channel for the console and for kernel debug. // Create a shared UART channel for the console and for kernel debug.
let uart_mux = let uart_mux =
components::console::UartMuxComponent::new(channel, 115200, dynamic_deferred_caller) components::console::UartMuxComponent::new(channel, 115200, dynamic_deferred_caller)
.finalize(()); .finalize(());
let pconsole = let pconsole = components::process_console::ProcessConsoleComponent::new(
components::process_console::ProcessConsoleComponent::new(board_kernel, uart_mux) board_kernel,
.finalize(()); uart_mux,
mux_alarm,
process_printer,
)
.finalize(components::process_console_component_helper!(
nrf52840::rtc::Rtc<'static>
));
// Setup the console. // Setup the console.
let console = components::console::ConsoleComponent::new(board_kernel, uart_mux).finalize(()); let console = components::console::ConsoleComponent::new(
board_kernel,
capsules::console::DRIVER_NUM,
uart_mux,
)
.finalize(components::console_component_helper!());
// Create the debugger object that handles calls to `debug!()`. // Create the debugger object that handles calls to `debug!()`.
components::debug_writer::DebugWriterComponent::new(uart_mux).finalize(()); components::debug_writer::DebugWriterComponent::new(uart_mux).finalize(());
let rng = components::rng::RngComponent::new(board_kernel, &base_peripherals.trng).finalize(()); let rng = components::rng::RngComponent::new(
board_kernel,
capsules::rng::DRIVER_NUM,
&base_peripherals.trng,
)
.finalize(());
base_peripherals.spim0.configure( base_peripherals.spim0.configure(
nrf52840::pinmux::Pinmux::new(SPI_MOSI as u32), nrf52840::pinmux::Pinmux::new(SPI_MOSI as u32),
@@ -390,6 +470,8 @@ pub unsafe fn reset_handler() {
nrf52840::acomp::Channel, nrf52840::acomp::Channel,
&nrf52840::acomp::CHANNEL_AC0 &nrf52840::acomp::CHANNEL_AC0
), ),
board_kernel,
capsules::analog_comparator::DRIVER_NUM,
) )
.finalize(components::acomp_component_buf!( .finalize(components::acomp_component_buf!(
nrf52840::acomp::Comparator nrf52840::acomp::Comparator
@@ -399,8 +481,9 @@ pub unsafe fn reset_handler() {
nrf52840::nvmc::SyscallDriver, nrf52840::nvmc::SyscallDriver,
nrf52840::nvmc::SyscallDriver::new( nrf52840::nvmc::SyscallDriver::new(
&base_peripherals.nvmc, &base_peripherals.nvmc,
board_kernel.create_grant(&memory_allocation_capability), board_kernel.create_grant(nrf52840::nvmc::DRIVER_NUM, &memory_allocation_capability),
dynamic_deferred_caller, dynamic_deferred_caller,
&mut APP_FLASH_BUFFER,
) )
); );
nvmc.set_deferred_handle( nvmc.set_deferred_handle(
@@ -412,21 +495,17 @@ pub unsafe fn reset_handler() {
// Configure USB controller // Configure USB controller
let usb = components::usb_ctap::UsbCtapComponent::new( let usb = components::usb_ctap::UsbCtapComponent::new(
board_kernel, board_kernel,
capsules::usb::usb_ctap::DRIVER_NUM,
&nrf52840_peripherals.usbd, &nrf52840_peripherals.usbd,
capsules::usb::usbc_client::MAX_CTRL_PACKET_SIZE_NRF52840, capsules::usb::usbc_client::MAX_CTRL_PACKET_SIZE_NRF52840,
VENDOR_ID, VENDOR_ID,
PRODUCT_ID, PRODUCT_ID,
STRINGS, STRINGS,
) )
.finalize(components::usb_ctap_component_buf!(nrf52840::usbd::Usbd)); .finalize(components::usb_ctap_component_helper!(nrf52840::usbd::Usbd));
let crp = components::firmware_protection::FirmwareProtectionComponent::new( let scheduler = components::sched::round_robin::RoundRobinComponent::new(&PROCESSES)
board_kernel, .finalize(components::rr_component_helper!(NUM_PROCS));
nrf52840::uicr::Uicr::new(),
)
.finalize(components::firmware_protection_component_helper!(
nrf52840::uicr::Uicr
));
nrf52_components::NrfClockComponent::new(&base_peripherals.clock).finalize(()); nrf52_components::NrfClockComponent::new(&base_peripherals.clock).finalize(());
@@ -441,15 +520,20 @@ pub unsafe fn reset_handler() {
analog_comparator, analog_comparator,
nvmc, nvmc,
usb, usb,
crp, ipc: kernel::ipc::IPC::new(
ipc: kernel::ipc::IPC::new(board_kernel, &memory_allocation_capability), board_kernel,
kernel::ipc::DRIVER_NUM,
&memory_allocation_capability,
),
scheduler,
systick: cortexm4::systick::SysTick::new_with_calibration(64000000),
}; };
platform.pconsole.start(); let _ = platform.pconsole.start();
debug!("Initialization complete. Entering main loop\r"); debug!("Initialization complete. Entering main loop\r");
debug!("{}", &nrf52840::ficr::FICR_INSTANCE); debug!("{}", &nrf52840::ficr::FICR_INSTANCE);
/// These symbols are defined in the linker script. // These symbols are defined in the linker script.
extern "C" { extern "C" {
/// Beginning of the ROM region containing app images. /// Beginning of the ROM region containing app images.
static _sapps: u8; static _sapps: u8;
@@ -461,7 +545,7 @@ pub unsafe fn reset_handler() {
static _eappmem: u8; static _eappmem: u8;
} }
kernel::procs::load_processes( kernel::process::load_processes(
board_kernel, board_kernel,
chip, chip,
core::slice::from_raw_parts( core::slice::from_raw_parts(
@@ -473,7 +557,7 @@ pub unsafe fn reset_handler() {
&_eappmem as *const u8 as usize - &_sappmem as *const u8 as usize, &_eappmem as *const u8 as usize - &_sappmem as *const u8 as usize,
), ),
&mut PROCESSES, &mut PROCESSES,
FAULT_RESPONSE, &FAULT_RESPONSE,
&process_management_capability, &process_management_capability,
) )
.unwrap_or_else(|err| { .unwrap_or_else(|err| {
@@ -481,13 +565,5 @@ pub unsafe fn reset_handler() {
debug!("{:?}", err); debug!("{:?}", err);
}); });
let scheduler = components::sched::round_robin::RoundRobinComponent::new(&PROCESSES) board_kernel.kernel_loop(&platform, chip, Some(&platform.ipc), &main_loop_capability);
.finalize(components::rr_component_helper!(NUM_PROCS));
board_kernel.kernel_loop(
&platform,
chip,
Some(&platform.ipc),
scheduler,
&main_loop_capability,
);
} }

56
bootloader/Cargo.lock generated
View File

@@ -19,7 +19,7 @@ checksum = "45403b49e3954a4b8428a0ac21a4b7afadccf92bfd96273f1a58cd4812496ae0"
dependencies = [ dependencies = [
"generic-array 0.12.4", "generic-array 0.12.4",
"generic-array 0.13.3", "generic-array 0.13.3",
"generic-array 0.14.6", "generic-array 0.14.7",
"stable_deref_trait", "stable_deref_trait",
] ]
@@ -53,9 +53,9 @@ dependencies = [
[[package]] [[package]]
name = "byteorder" name = "byteorder"
version = "1.4.3" version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]] [[package]]
name = "cortex-m" name = "cortex-m"
@@ -66,15 +66,15 @@ dependencies = [
"aligned", "aligned",
"bare-metal", "bare-metal",
"bitfield", "bitfield",
"cortex-m 0.7.6", "cortex-m 0.7.7",
"volatile-register", "volatile-register",
] ]
[[package]] [[package]]
name = "cortex-m" name = "cortex-m"
version = "0.7.6" version = "0.7.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70858629a458fdfd39f9675c4dc309411f2a3f83bede76988d81bf1a0ecee9e0" checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9"
dependencies = [ dependencies = [
"bare-metal", "bare-metal",
"bitfield", "bitfield",
@@ -84,9 +84,9 @@ dependencies = [
[[package]] [[package]]
name = "cortex-m-rt" name = "cortex-m-rt"
version = "0.7.1" version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c433da385b720d5bb9f52362fa2782420798e68d40d67bfe4b0d992aba5dfe7" checksum = "ee84e813d593101b1723e13ec38b6ab6abbdbaaa4546553f5395ed274079ddb1"
dependencies = [ dependencies = [
"cortex-m-rt-macros", "cortex-m-rt-macros",
] ]
@@ -132,9 +132,9 @@ dependencies = [
[[package]] [[package]]
name = "generic-array" name = "generic-array"
version = "0.14.6" version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [ dependencies = [
"typenum", "typenum",
"version_check", "version_check",
@@ -146,14 +146,14 @@ version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f"
dependencies = [ dependencies = [
"nb 1.0.0", "nb 1.1.0",
] ]
[[package]] [[package]]
name = "nb" name = "nb"
version = "1.0.0" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae" checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d"
[[package]] [[package]]
name = "panic-abort" name = "panic-abort"
@@ -163,18 +163,18 @@ checksum = "4e20e6499bbbc412f280b04a42346b356c6fa0753d5fd22b7bd752ff34c778ee"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.43" version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.21" version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
@@ -185,7 +185,7 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "065d6058bb1204f51a562a67209e1817cf714759d5cf845aa45c75fa7b0b9d9b" checksum = "065d6058bb1204f51a562a67209e1817cf714759d5cf845aa45c75fa7b0b9d9b"
dependencies = [ dependencies = [
"cortex-m 0.7.6", "cortex-m 0.7.7",
"ufmt-write", "ufmt-write",
] ]
@@ -221,9 +221,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.100" version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52205623b1b0f064a4e71182c3b18ae902267282930c6d5462c91b859668426e" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -232,15 +232,15 @@ dependencies = [
[[package]] [[package]]
name = "tock-registers" name = "tock-registers"
version = "0.6.0" version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f521a79accce68c417c9c77ce22108056b626126da1932f7e2e9b5bbffee0cea" checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e"
[[package]] [[package]]
name = "typenum" name = "typenum"
version = "1.15.0" version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]] [[package]]
name = "ufmt-write" name = "ufmt-write"
@@ -250,9 +250,9 @@ checksum = "e87a2ed6b42ec5e28cc3b94c09982969e9227600b2e3dcbc1db927a84c06bd69"
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.4" version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]] [[package]]
name = "vcell" name = "vcell"
@@ -274,9 +274,9 @@ checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
[[package]] [[package]]
name = "volatile-register" name = "volatile-register"
version = "0.2.1" version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ee8f19f9d74293faf70901bc20ad067dc1ad390d2cbf1e3f75f721ffee908b6" checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc"
dependencies = [ dependencies = [
"vcell", "vcell",
] ]

View File

@@ -15,7 +15,7 @@ cortex-m-rt = "*"
cortex-m-rt-macros = "*" cortex-m-rt-macros = "*"
panic-abort = "0.3.2" panic-abort = "0.3.2"
rtt-target = { version = "*", features = ["cortex-m"] } rtt-target = { version = "*", features = ["cortex-m"] }
tock-registers = { version = "0.6.0", features = ["no_std_unit_tests"] } tock-registers = "0.7.0"
[profile.dev] [profile.dev]
panic = "abort" panic = "abort"

View File

@@ -1,4 +0,0 @@
[toolchain]
channel = "nightly-2021-03-25"
components = ["clippy", "rustfmt"]
targets = ["thumbv7em-none-eabi"]

View File

@@ -26,6 +26,7 @@ use super::static_ref::StaticRef;
use core::cell::Cell; use core::cell::Cell;
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
use rtt_target::rprintln; use rtt_target::rprintln;
use tock_registers::interfaces::{Readable, Writeable};
const SHA256_INIT_VALUE: [u32; 8] = [ const SHA256_INIT_VALUE: [u32; 8] = [
0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19, 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19,

View File

@@ -40,7 +40,7 @@ impl<T> Copy for StaticRef<T> {}
impl<T> Deref for StaticRef<T> { impl<T> Deref for StaticRef<T> {
type Target = T; type Target = T;
fn deref(&self) -> &'static T { fn deref(&self) -> &T {
unsafe { &*self.ptr } unsafe { &*self.ptr }
} }
} }

View File

@@ -24,7 +24,7 @@ use uuid::Uuid;
fn main() { fn main() {
const UPGRADE_FILE: &str = "crypto_data/opensk_upgrade_pub.pem"; const UPGRADE_FILE: &str = "crypto_data/opensk_upgrade_pub.pem";
println!("cargo:rerun-if-changed=crypto_data/aaguid.txt"); println!("cargo:rerun-if-changed=crypto_data/aaguid.txt");
println!("cargo:rerun-if-changed={}", UPGRADE_FILE); println!("cargo:rerun-if-changed={UPGRADE_FILE}");
println!("cargo:rerun-if-changed=layout.ld"); println!("cargo:rerun-if-changed=layout.ld");
println!("cargo:rerun-if-changed=nrf52840_layout.ld"); println!("cargo:rerun-if-changed=nrf52840_layout.ld");
println!("cargo:rerun-if-changed=nrf52840_layout_a.ld"); println!("cargo:rerun-if-changed=nrf52840_layout_a.ld");
@@ -33,7 +33,7 @@ fn main() {
let out_dir = env::var_os("OUT_DIR").unwrap(); let out_dir = env::var_os("OUT_DIR").unwrap();
let aaguid_bin_path = Path::new(&out_dir).join("opensk_aaguid.bin"); let aaguid_bin_path = Path::new(&out_dir).join("opensk_aaguid.bin");
let mut aaguid_bin_file = File::create(&aaguid_bin_path).unwrap(); let mut aaguid_bin_file = File::create(aaguid_bin_path).unwrap();
let mut aaguid_txt_file = File::open("crypto_data/aaguid.txt").unwrap(); let mut aaguid_txt_file = File::open("crypto_data/aaguid.txt").unwrap();
let mut content = String::new(); let mut content = String::new();
aaguid_txt_file.read_to_string(&mut content).unwrap(); aaguid_txt_file.read_to_string(&mut content).unwrap();
@@ -52,6 +52,6 @@ fn main() {
.to_bytes(&group, conversion_form, &mut ctx) .to_bytes(&group, conversion_form, &mut ctx)
.unwrap(); .unwrap();
let upgrade_pubkey_path = Path::new(&out_dir).join("opensk_upgrade_pubkey.bin"); let upgrade_pubkey_path = Path::new(&out_dir).join("opensk_upgrade_pubkey.bin");
let mut upgrade_pub_bin_file = File::create(&upgrade_pubkey_path).unwrap(); let mut upgrade_pub_bin_file = File::create(upgrade_pubkey_path).unwrap();
upgrade_pub_bin_file.write_all(&raw_bytes).unwrap(); upgrade_pub_bin_file.write_all(&raw_bytes).unwrap();
} }

147
deploy.py
View File

@@ -1,5 +1,5 @@
#!/usr/bin/env python3 #!py_virtual_env/bin/python3
# Copyright 2019 Google LLC # Copyright 2019-2023 Google LLC
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@@ -156,7 +156,11 @@ SUPPORTED_BOARDS = {
), ),
} }
APP_HEAP_SIZE = 32768 # The following value must match the one used in the file
# `src/entry_point.rs`
APP_HEAP_SIZE = 90_000
CARGO_TARGET_DIR = os.environ.get("CARGO_TARGET_DIR", "target")
def get_supported_boards() -> Tuple[str]: def get_supported_boards() -> Tuple[str]:
@@ -252,7 +256,7 @@ class OpenSKInstaller:
def __init__(self, args): def __init__(self, args):
self.args = args self.args = args
# Where all the TAB files should go # Where all the TAB files should go
self.tab_folder = os.path.join("target", "tab") self.tab_folder = os.path.join(CARGO_TARGET_DIR, "tab")
board = SUPPORTED_BOARDS[self.args.board] board = SUPPORTED_BOARDS[self.args.board]
self.tockloader_default_args = argparse.Namespace( self.tockloader_default_args = argparse.Namespace(
app_address=board.app_address, app_address=board.app_address,
@@ -318,46 +322,6 @@ class OpenSKInstaller:
# Unreachable because fatal() will exit # Unreachable because fatal() will exit
return cmd_output.decode() return cmd_output.decode()
def update_rustc_if_needed(self):
"""Updates the Rust and installs the necessary target toolchain."""
target_toolchain_fullstring = "stable"
with open("rust-toolchain", "r", encoding="utf-8") as f:
content = f.readlines()
if len(content) == 1:
# Old format, only the build is stored
target_toolchain_fullstring = content[0].strip()
else:
# New format
for line in content:
if line.startswith("channel"):
channel = line.strip().split("=", maxsplit=1)[1].strip()
target_toolchain_fullstring = channel.strip('"')
target_toolchain = target_toolchain_fullstring.split("-", maxsplit=1)
if len(target_toolchain) == 1:
# If we target the stable version of rust, we won't have a date
# associated to the version and split will only return 1 item.
# To avoid failing later when accessing the date, we insert an
# empty value.
target_toolchain.append("")
current_version = self.checked_command_output(["rustc", "--version"])
if not (target_toolchain[0] in current_version and
target_toolchain[1] in current_version):
info(f"Updating rust toolchain to {'-'.join(target_toolchain)}")
# Need to update
rustup_install = ["rustup"]
if self.args.verbose_build:
rustup_install.append("--verbose")
rustup_install.extend(["install", target_toolchain_fullstring])
self.checked_command(rustup_install)
rustup_target = ["rustup"]
if self.args.verbose_build:
rustup_target.append("--verbose")
rustup_target.extend(
["target", "add", SUPPORTED_BOARDS[self.args.board].arch])
self.checked_command(rustup_target)
info("Rust toolchain up-to-date")
def build_tockos(self): def build_tockos(self):
"""Buids Tock OS with the parameters specified in args.""" """Buids Tock OS with the parameters specified in args."""
info(f"Building Tock OS for board {self.args.board}") info(f"Building Tock OS for board {self.args.board}")
@@ -399,7 +363,8 @@ class OpenSKInstaller:
env["RUSTFLAGS"] = " ".join(rust_flags) env["RUSTFLAGS"] = " ".join(rust_flags)
cargo_command = ["cargo", "build", "--release", f"--target={props.arch}"] cargo_command = ["cargo", "build", "--release", f"--target={props.arch}"]
self.checked_command(cargo_command, cwd="bootloader", env=env) self.checked_command(cargo_command, cwd="bootloader", env=env)
binary_path = os.path.join("target", props.arch, "release", "bootloader") binary_path = os.path.join(CARGO_TARGET_DIR, props.arch, "release",
"bootloader")
objcopy_command = [ objcopy_command = [
"llvm-objcopy", "-O", "binary", binary_path, f"{binary_path}.bin" "llvm-objcopy", "-O", "binary", binary_path, f"{binary_path}.bin"
] ]
@@ -461,7 +426,7 @@ class OpenSKInstaller:
if self.args.verbose_build: if self.args.verbose_build:
command.append("--verbose") command.append("--verbose")
self.checked_command(command, env=env) self.checked_command(command, env=env)
app_path = os.path.join("target", props.arch, "release") app_path = os.path.join(CARGO_TARGET_DIR, props.arch, "release")
if is_example: if is_example:
app_path = os.path.join(app_path, "examples") app_path = os.path.join(app_path, "examples")
app_path = os.path.join(app_path, self.args.application) app_path = os.path.join(app_path, self.args.application)
@@ -497,14 +462,16 @@ class OpenSKInstaller:
elf2tab_ver = self.checked_command_output( elf2tab_ver = self.checked_command_output(
["elf2tab/bin/elf2tab", "--version"]).split( ["elf2tab/bin/elf2tab", "--version"]).split(
"\n", maxsplit=1)[0] "\n", maxsplit=1)[0]
if elf2tab_ver != "elf2tab 0.7.0": if elf2tab_ver != "elf2tab 0.10.2":
error(("Detected unsupported elf2tab version {elf2tab_ver!a}. The " error(("Detected unsupported elf2tab version {elf2tab_ver!a}! The "
"following commands may fail. Please use 0.7.0 instead.")) "following commands may fail. Please use 0.10.2 instead."))
os.makedirs(self.tab_folder, exist_ok=True) os.makedirs(self.tab_folder, exist_ok=True)
tab_filename = os.path.join(self.tab_folder, f"{self.args.application}.tab") tab_filename = os.path.join(self.tab_folder, f"{self.args.application}.tab")
supported_kernel = (2, 1)
elf2tab_args = [ elf2tab_args = [
"elf2tab/bin/elf2tab", "--deterministic", "--package-name", "elf2tab/bin/elf2tab", "--deterministic", "--package-name",
self.args.application, "-o", tab_filename self.args.application, f"--kernel-major={supported_kernel[0]}",
f"--kernel-minor={supported_kernel[1]}", "-o", tab_filename
] ]
if self.args.verbose_build: if self.args.verbose_build:
elf2tab_args.append("--verbose") elf2tab_args.append("--verbose")
@@ -522,10 +489,11 @@ class OpenSKInstaller:
stack_sizes.add(required_stack_size) stack_sizes.add(required_stack_size)
if len(stack_sizes) != 1: if len(stack_sizes) != 1:
error("Detected different stack sizes across tab files.") error("Detected different stack sizes across tab files.")
# `protected-region-size` must match the `TBF_HEADER_SIZE`
# (currently 0x60 = 96 bytes)
elf2tab_args.extend([ elf2tab_args.extend([
f"--stack={stack_sizes.pop()}", f"--app-heap={APP_HEAP_SIZE}", f"--stack={stack_sizes.pop()}", f"--app-heap={APP_HEAP_SIZE}",
"--kernel-heap=1024", "--protected-region-size=64" "--kernel-heap=1024", "--protected-region-size=96"
]) ])
if self.args.elf2tab_output: if self.args.elf2tab_output:
output = self.checked_command_output(elf2tab_args) output = self.checked_command_output(elf2tab_args)
@@ -606,7 +574,7 @@ class OpenSKInstaller:
return return
kernel = self.read_kernel() kernel = self.read_kernel()
app_tab_path = "target/tab/ctap2.tab" app_tab_path = f"{CARGO_TARGET_DIR}/tab/ctap2.tab"
if not os.path.exists(app_tab_path): if not os.path.exists(app_tab_path):
fatal(f"File not found: {app_tab_path}") fatal(f"File not found: {app_tab_path}")
app_tab = tab.TAB(app_tab_path) app_tab = tab.TAB(app_tab_path)
@@ -700,17 +668,18 @@ class OpenSKInstaller:
final_hex.merge(padding_hex, overlap="error") final_hex.merge(padding_hex, overlap="error")
# Now we can add the application from the TAB file # Now we can add the application from the TAB file
app_tab_path = f"target/tab/{self.args.application}.tab" app_tab_path = f"{CARGO_TARGET_DIR}/tab/{self.args.application}.tab"
assert os.path.exists(app_tab_path) assert os.path.exists(app_tab_path)
app_tab = tab.TAB(app_tab_path) app_tab = tab.TAB(app_tab_path)
if board_props.arch not in app_tab.get_supported_architectures(): if board_props.arch not in app_tab.get_supported_architectures():
fatal(("It seems that the TAB file was not produced for the " fatal(("It seems that the TAB file was not produced for the "
"architecture {board_props.arch}")) "architecture {board_props.arch}"))
app_hex = intelhex.IntelHex() app_hex = intelhex.IntelHex()
app_hex.frombytes( tab_bytes = app_tab.extract_app(board_props.arch).get_binary(
app_tab.extract_app(board_props.arch).get_binary( board_props.app_address)
board_props.app_address), if tab_bytes is None:
offset=board_props.app_address) fatal("The extracted bytes from the TAB file are none")
app_hex.frombytes(tab_bytes, offset=board_props.app_address)
final_hex.merge(app_hex) final_hex.merge(app_hex)
info(f"Generating all-merged HEX file: {dest_file}") info(f"Generating all-merged HEX file: {dest_file}")
final_hex.tofile(dest_file, format="hex") final_hex.tofile(dest_file, format="hex")
@@ -740,7 +709,8 @@ class OpenSKInstaller:
nrfutil_version = __import__("nordicsemi.version").version.NRFUTIL_VERSION nrfutil_version = __import__("nordicsemi.version").version.NRFUTIL_VERSION
if not nrfutil_version.startswith("6."): if not nrfutil_version.startswith("6."):
fatal(("You need to install nrfutil python3 package v6.0 or above. " fatal(("You need to install nrfutil python3 package v6.0 or above. "
"Found: {nrfutil_version}")) f"Found: v{nrfutil_version}. If you use Python >= 3.11, please "
"try version 3.10."))
if not SUPPORTED_BOARDS[self.args.board].nordic_dfu: if not SUPPORTED_BOARDS[self.args.board].nordic_dfu:
fatal("This board doesn't support flashing over DFU.") fatal("This board doesn't support flashing over DFU.")
@@ -764,7 +734,6 @@ class OpenSKInstaller:
def run(self) -> int: def run(self) -> int:
"""Reads args to decide and run all required tasks.""" """Reads args to decide and run all required tasks."""
self.check_prerequisites() self.check_prerequisites()
self.update_rustc_if_needed()
if not (self.args.tockos or self.args.application or if not (self.args.tockos or self.args.application or
self.args.clear_storage or self.args.configure): self.args.clear_storage or self.args.configure):
@@ -789,6 +758,7 @@ class OpenSKInstaller:
info("No application selected.") info("No application selected.")
else: else:
self.build_example() self.build_example()
self.args.configure = False
# Erase persistent storage # Erase persistent storage
if self.args.clear_storage: if self.args.clear_storage:
@@ -808,7 +778,8 @@ class OpenSKInstaller:
# Install padding and application if needed # Install padding and application if needed
if self.args.application: if self.args.application:
self.install_padding() self.install_padding()
self.install_tab_file(f"target/tab/{self.args.application}.tab") self.install_tab_file(
f"{CARGO_TARGET_DIR}/tab/{self.args.application}.tab")
self.install_metadata() self.install_metadata()
if not self.verify_flashed_app(self.args.application): if not self.verify_flashed_app(self.args.application):
error(("It seems that something went wrong. App/example not found " error(("It seems that something went wrong. App/example not found "
@@ -817,8 +788,8 @@ class OpenSKInstaller:
return 1 return 1
elif self.args.programmer in ("pyocd", "nordicdfu", "none"): elif self.args.programmer in ("pyocd", "nordicdfu", "none"):
dest_file = f"target/{self.args.board}_merged.hex" dest_file = f"{CARGO_TARGET_DIR}/{self.args.board}_merged.hex"
os.makedirs("target", exist_ok=True) os.makedirs(CARGO_TARGET_DIR, exist_ok=True)
self.create_hex_file(dest_file) self.create_hex_file(dest_file)
if self.args.programmer == "pyocd": if self.args.programmer == "pyocd":
@@ -829,7 +800,7 @@ class OpenSKInstaller:
]) ])
if self.args.programmer == "nordicdfu": if self.args.programmer == "nordicdfu":
info("Creating DFU package") info("Creating DFU package")
dfu_pkg_file = f"target/{self.args.board}_dfu.zip" dfu_pkg_file = f"{CARGO_TARGET_DIR}/{self.args.board}_dfu.zip"
self.checked_command([ self.checked_command([
"nrfutil", "pkg", "generate", "--hw-version=52", "--sd-req=0", "nrfutil", "pkg", "generate", "--hw-version=52", "--sd-req=0",
"--application-version=1", f"--application={dest_file}", "--application-version=1", f"--application={dest_file}",
@@ -881,6 +852,18 @@ class OpenSKInstaller:
self.configure() self.configure()
return 0 return 0
def print_configure_help(self):
vendor_hid = " --vendor-hid" if "vendor_hid" in self.args.features else ""
info("Your device is not yet configured, and lacks some functionality. "
"You can check its configuration status with:\n\n"
f"./tools/configure.py{vendor_hid}\n\n"
"If you run into issues, this command might help:\n\n"
f"./tools/configure.py{vendor_hid} \\\n"
" --certificate=crypto_data/opensk_cert.pem \\\n"
" --private-key=crypto_data/opensk.key\n\n"
"Please read the Certificate considerations in docs/customization.md"
" to understand the privacy trade-off.")
def configure(self): def configure(self):
info("Configuring device.") info("Configuring device.")
# Trying to check or configure the device. Booting might take some time. # Trying to check or configure the device. Booting might take some time.
@@ -892,6 +875,7 @@ class OpenSKInstaller:
break break
if not devices: if not devices:
self.print_configure_help()
fatal("No device to configure found.") fatal("No device to configure found.")
status = self.configure_device() status = self.configure_device()
if not status: if not status:
@@ -900,13 +884,7 @@ class OpenSKInstaller:
if status["cert"] and status["pkey"]: if status["cert"] and status["pkey"]:
info("You're all set!") info("You're all set!")
else: else:
info("Your device is not yet configured, and lacks some functionality. " self.print_configure_help()
"If you run into issues, this command might help:\n\n"
"./tools/configure.py \\\n"
" --certificate=crypto_data/opensk_cert.pem \\\n"
" --private-key=crypto_data/opensk.key\n\n"
"Please read the Certificate considerations in docs/customization.md"
" to understand the privacy trade-off.")
return 0 return 0
@@ -975,7 +953,8 @@ if __name__ == "__main__":
dest="lock_device", dest="lock_device",
help=("Try to disable JTAG at the end of the operations. This " help=("Try to disable JTAG at the end of the operations. This "
"operation may fail if the device is already locked or if " "operation may fail if the device is already locked or if "
"the certificate/private key are not programmed."), "the certificate/private key are not programmed."
"Currently not implemented on nrf52840 and always fails."),
) )
main_parser.add_argument( main_parser.add_argument(
"--inject-certificate", "--inject-certificate",
@@ -1071,6 +1050,20 @@ if __name__ == "__main__":
help=("Compiles the OpenSK application without backward compatible " help=("Compiles the OpenSK application without backward compatible "
"support for U2F/CTAP1 protocol."), "support for U2F/CTAP1 protocol."),
) )
main_parser.add_argument(
"--no-config-command",
action=RemoveConstAction,
const="config_command",
dest="features",
help=("Removes the AuthenticatorConfig command."),
)
main_parser.add_argument(
"--rust-crypto",
action="append_const",
const="rust_crypto",
dest="features",
help=("Compiles the OpenSK application with RustCrypto implementations."),
)
main_parser.add_argument( main_parser.add_argument(
"--nfc", "--nfc",
action="append_const", action="append_const",
@@ -1147,14 +1140,14 @@ if __name__ == "__main__":
help=("Firmware version that is built."), help=("Firmware version that is built."),
) )
main_parser.set_defaults(features=["with_ctap1"]) main_parser.set_defaults(features=["with_ctap1", "config_command"])
# Start parsing to know if we're going to list things or not. # Start parsing to know if we're going to list things or not.
partial_args, _ = main_parser.parse_known_args() partial_args, _ = main_parser.parse_known_args()
# We only need the apps_group if we have a board set # We only need the apps_group if we have a board set
apps_group = main_parser.add_mutually_exclusive_group( apps_group = main_parser.add_mutually_exclusive_group(
required=(partial_args.board is not None)) required=partial_args.board is not None)
apps_group.add_argument( apps_group.add_argument(
"--no-app", "--no-app",
dest="application", dest="application",
@@ -1175,12 +1168,6 @@ if __name__ == "__main__":
const="crypto_bench", const="crypto_bench",
help=("Compiles and installs the crypto_bench example that benchmarks " help=("Compiles and installs the crypto_bench example that benchmarks "
"the performance of the cryptographic algorithms on the board.")) "the performance of the cryptographic algorithms on the board."))
apps_group.add_argument(
"--measure_stack",
dest="application",
action="store_const",
const="measure_stack",
help=("Measures stack usage of Dilithium."))
apps_group.add_argument( apps_group.add_argument(
"--store_latency", "--store_latency",
dest="application", dest="application",

View File

@@ -19,7 +19,7 @@ After general setup, you still need these steps:
1. Run the script: 1. Run the script:
```shell ```shell
python3 uf2conv.py -c -f 0xada52840 -o target/opensk.uf2 target/nrf52840_mdk_dfu_merged.hex py_virtual_env/bin/python3 uf2conv.py -c -f 0xada52840 -o target/opensk.uf2 target/nrf52840_mdk_dfu_merged.hex
``` ```
1. Boot into DFU mode. Keep the user button pressed on your hardware while 1. Boot into DFU mode. Keep the user button pressed on your hardware while

View File

@@ -62,19 +62,24 @@ firmware. You can bootstrap an upgradable board using one of the two commands:
Afterwards, you can upgrade the other partition with Afterwards, you can upgrade the other partition with
```shell ```shell
./tools/perform_upgrade.sh nrf52840dk_opensk_b --version=1 # Board A -> B
./tools/perform_upgrade.sh nrf52840dk_opensk_a --version=1 ./deploy.py --board=nrf52840dk_opensk_b --opensk --programmer=none --version=1
py_virtual_env/bin/python3 -m tools.deploy_partition --board=nrf52840dk_opensk_b --version=1
# Board B -> A
./deploy.py --board=nrf52840dk_opensk_a --opensk --programmer=none --version=1
py_virtual_env/bin/python3 -m tools.deploy_partition --board=nrf52840dk_opensk_a --version=1
``` ```
respectively. You can only upgrade the partition that is not currently running, respectively. You can only upgrade the partition that is not currently running,
so always alternate your calls to `perform_upgrade.sh`. Otherwise, this script otherwise your deploy attempts will fail. You can call `deploy_partition` after
works like `deploy.py`. You can call it even after you locked down your device, you locked down your device, to deploy changes to your development board.
to deploy changes to your development board. Upgrades only apply after a reboot.
If you deploy with `--vendor-hid`, also add this flag to `perform_upgrade.sh`, If you want to use Vendor HID, add the `--vendor-hid` flag to all calls,
for example: for example:
```shell ```shell
./deploy.py --board=nrf52840dk_opensk_a --opensk --version=0 --vendor-hid ./deploy.py --board=nrf52840dk_opensk_a --opensk --version=0 --vendor-hid
./tools/perform_upgrade.sh nrf52840dk_opensk_b --version=1 --vendor-hid ./deploy.py --board=nrf52840dk_opensk_b --opensk --programmer=none --version=1 --vendor-hid
py_virtual_env/bin/python3 -m tools.deploy_partition --board=nrf52840dk_opensk_b --version=1 --vendor-hid
``` ```

View File

@@ -1,7 +1,8 @@
# How to Contribute # How to Contribute
We'd love to accept your patches and contributions to this project. There are We'd love to accept your patches and contributions to this project.
just a few small guidelines you need to follow. Please base your pull requests on the `develop` branch.
There are just a few small guidelines you need to follow.
## Contributor License Agreement ## Contributor License Agreement

View File

@@ -85,7 +85,7 @@ OpenSK is fuzzed with the [OSS-Fuzz](https://github.com/google/oss-fuzz)
project. You can also run fuzzing locally. First install: project. You can also run fuzzing locally. First install:
```shell ```shell
cargo +stable install cargo-fuzz --version 0.10.2 ./fuzzing_setup.sh
``` ```
Then choose a fuzz target from `fuzz/fuzz_targets/`, e.g.: Then choose a fuzz target from `fuzz/fuzz_targets/`, e.g.:

View File

@@ -28,7 +28,7 @@ following:
* `nrfutil` (can be installed using `pip3 install nrfutil`) if you want to flash * `nrfutil` (can be installed using `pip3 install nrfutil`) if you want to flash
a device with DFU a device with DFU
* `uuid-runtime` if you are missing the `uuidgen` command. * `uuid-runtime` if you are missing the `uuidgen` command.
* `llvm` if you want to use the upgradability feature. * `llvm` and `gcc-arm-none-eabi` if you want to use the upgradability feature.
The proprietary software to use the default programmer can be found on the The proprietary software to use the default programmer can be found on the
[Segger website](https://www.segger.com/downloads/jlink). Please follow their [Segger website](https://www.segger.com/downloads/jlink). Please follow their
@@ -37,6 +37,11 @@ instructions to appropriate binaries for your system.
The scripts provided in this project have been tested under Linux and OS X. We The scripts provided in this project have been tested under Linux and OS X. We
haven't tested them on Windows and other platforms. haven't tested them on Windows and other platforms.
If you use Python newer than 3.10, then nrfutil for flashing over DFU is
currently not supported. Please use Python 3.10, or play around with [Nordic's
new tool](https://www.nordicsemi.com/Products/Development-tools/nrf-util)
instead.
### Compiling the firmware ### Compiling the firmware
If this is your first time installing OpenSK, please skip directly to If this is your first time installing OpenSK, please skip directly to

View File

@@ -12,24 +12,32 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#![no_main]
#![no_std] #![no_std]
extern crate lang_items; extern crate lang_items;
use libtock_drivers::console::{Console, BUFFER_SIZE}; use libtock_console::Console;
use libtock_drivers::result::FlexUnwrap;
use libtock_runtime::{set_main, stack_size, TockSyscalls};
libtock_core::stack_size! {0x800} stack_size! {0x800}
set_main! {main}
type Syscalls = TockSyscalls;
fn main() { fn main() {
// Write messages of length up to the console driver's buffer size. // Write messages of length up to the console driver's buffer size.
let mut buf = [0; BUFFER_SIZE]; let mut buf = [0; 1024];
loop { loop {
for i in 1..buf.len() { for i in 1..buf.len() {
for byte in buf.iter_mut().take(i) { for byte in buf.iter_mut().take(i) {
*byte = b'0' + ((i % 10) as u8); *byte = b'0' + ((i % 10) as u8);
} }
buf[i] = b'\n'; buf[i] = b'\n';
Console::write_unbuffered(&mut buf[..(i + 1)]); Console::<Syscalls>::write(&buf[..(i + 1)])
.map_err(|e| e.into())
.flex_unwrap();
} }
} }
} }

View File

@@ -12,182 +12,146 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#![no_main]
#![no_std] #![no_std]
extern crate alloc; extern crate alloc;
extern crate lang_items; extern crate lang_items;
use alloc::format;
use alloc::vec::Vec;
use core::fmt::Write; use core::fmt::Write;
use crypto::sha256::Sha256; use core::hint::black_box;
use crypto::{ecdsa, hybrid}; use ctap2::env::tock::{TockEnv, TockRng};
use libtock_drivers::console::Console; use libtock_console::{Console, ConsoleWriter};
use libtock_drivers::result::FlexUnwrap; use libtock_drivers::result::FlexUnwrap;
use libtock_drivers::timer; use libtock_drivers::timer;
use libtock_drivers::timer::{Timer, Timestamp}; use libtock_drivers::timer::{Timer, Timestamp};
use rng256::Rng256; use libtock_runtime::{set_main, stack_size, TockSyscalls};
// use ctap2::env::tock::{take_storage, TockStorage}; use opensk::api::crypto::aes256::Aes256;
// use persistent_store::Store; use opensk::api::crypto::ecdsa::SecretKey as _;
use opensk::api::crypto::sha256::Sha256;
use opensk::env::{AesKey, EcdsaSk, Sha};
libtock_core::stack_size! {0x11800} stack_size! {0x2000}
set_main! {main}
/*fn boot_store(mut storage: TockStorage, erase: bool) -> Store<TockStorage> { type Syscalls = TockSyscalls;
use persistent_store::Storage;
let num_pages = storage.num_pages();
if erase {
for page in 0..num_pages {
storage.erase_page(page).unwrap();
}
}
Store::new(storage).ok().unwrap()
}*/
fn main() { fn main() {
// Fix to be faster. let mut console = Console::<Syscalls>::writer();
//let storage = take_storage().unwrap();
//let mut _store = boot_store(storage, true);
let mut console = Console::new();
let mut rng = rng256::TockRng256 {};
// Setup the timer with a dummy callback (we only care about reading the current time, but the // Setup the timer with a dummy callback (we only care about reading the current time, but the
// API forces us to set an alarm callback too). // API forces us to set an alarm callback too).
let mut with_callback = timer::with_callback(|_, _| {}); let mut with_callback = timer::with_callback(|_| {});
let timer = with_callback.init().flex_unwrap(); let timer = with_callback.init().flex_unwrap();
let mut rng = TockRng::<Syscalls>::default();
writeln!(console, "****************************************").unwrap(); writeln!(console, "****************************************").unwrap();
writeln!( writeln!(console, "Clock frequency: {:?} Hz", timer.clock_frequency()).unwrap();
console,
"Clock frequency: {} Hz",
timer.clock_frequency().hz()
)
.unwrap();
custom_bench( // AES
bench(&mut console, &timer, "Aes256::new", || {
black_box(AesKey::<TockEnv<Syscalls>>::new(&[0; 32]));
});
let aes_key = AesKey::<TockEnv<Syscalls>>::new(&[0; 32]);
bench(&mut console, &timer, "Aes256::encrypt_block", || {
aes_key.encrypt_block(&mut [0; 16]);
});
bench(&mut console, &timer, "Aes256::decrypt_block", || {
aes_key.decrypt_block(&mut [0; 16]);
});
// CBC
let mut blocks = Vec::new();
for i in 0..6 {
blocks.resize(1 << (i + 4), 0);
bench(
&mut console, &mut console,
&timer, &timer,
"ECDSA keygen", &format!("Aes256::encrypt_cbc({} bytes)", blocks.len()),
1000,
|| {},
|()| {
let k = ecdsa::SecKey::gensk(&mut rng);
k.genpk();
},
);
custom_bench(
&mut console,
&timer,
"ECDSA sign",
1000,
|| { || {
let k = ecdsa::SecKey::gensk(&mut rng); aes_key.encrypt_cbc(&[0; 16], &mut blocks);
let mut m = [0; 64];
rng.fill_bytes(&mut m);
(k, m)
},
|(k, m)| {
k.sign_rfc6979::<Sha256>(&m);
}, },
); );
}
drop(blocks);
custom_bench( let mut blocks = Vec::new();
for i in 0..6 {
blocks.resize(1 << (i + 4), 0);
bench(
&mut console, &mut console,
&timer, &timer,
"dilithium::SecKey::gensk_with_pk", &format!("Aes256::decrypt_cbc({} bytes)", blocks.len()),
1000,
|| {},
|()| {
dilithium::sign::SecKey::gensk_with_pk(&mut rng);
},
);
custom_bench(
&mut console,
&timer,
"dilithium::SecKey::sign",
1000,
|| { || {
let sk = dilithium::sign::SecKey::gensk(&mut rng); aes_key.decrypt_cbc(&[0; 16], &mut blocks);
let mut m = [0; 64];
rng.fill_bytes(&mut m);
(sk, m)
},
|(sk, m)| {
sk.sign(&m);
}, },
); );
}
drop(blocks);
custom_bench( // SHA-256
let mut contents = Vec::new();
for i in 0..6 {
contents.resize(16 << i, 0);
bench(
&mut console, &mut console,
&timer, &timer,
"hybrid::SecKey::gensk_with_pk", &format!("Sha256::digest({} bytes)", contents.len()),
1000,
|| {},
|()| {
hybrid::SecKey::gensk_with_pk(&mut rng);
},
);
custom_bench(
&mut console,
&timer,
"hybrid::SecKey::sign",
1000,
|| { || {
let sk = hybrid::SecKey::gensk(&mut rng); Sha::<TockEnv<Syscalls>>::digest(&contents);
let mut m = [0; 64];
rng.fill_bytes(&mut m);
(sk, m)
},
|(sk, m)| {
sk.sign_rfc6979::<Sha256>(&m).to_asn1_der();
}, },
); );
}
drop(contents);
// ECDSA
bench(&mut console, &timer, "Ecdsa::SecretKey::random", || {
EcdsaSk::<TockEnv<Syscalls>>::random(&mut rng);
});
let sk = EcdsaSk::<TockEnv<Syscalls>>::random(&mut rng);
bench(&mut console, &timer, "Ecdsa::SecretKey::public_key", || {
black_box(sk.public_key());
});
bench(&mut console, &timer, "Ecdsa::SecretKey::sign", || {
sk.sign(&[]);
});
writeln!(console, "****************************************").unwrap();
writeln!(console, "All the benchmarks are done.\nHave a nice day!").unwrap();
writeln!(console, "****************************************").unwrap();
} }
fn custom_bench<I, O, F, S>( fn bench<F>(console: &mut ConsoleWriter<Syscalls>, timer: &Timer<Syscalls>, title: &str, mut f: F)
console: &mut Console, where
timer: &Timer, F: FnMut(),
title: &str,
iter_count: usize,
mut setup: S,
mut f: F,
) where
S: FnMut() -> I,
F: FnMut(I) -> O,
{ {
writeln!(console, "****************************************").unwrap(); writeln!(console, "****************************************").unwrap();
writeln!(console, "Benchmarking: {}", title).unwrap(); writeln!(console, "Benchmarking: {}", title).unwrap();
writeln!(console, "----------------------------------------").unwrap(); writeln!(console, "----------------------------------------").unwrap();
let mut count = 1;
let mut elapsed = 0.0; for _ in 0..30 {
let start =
for _ in 1..(iter_count + 1) { Timestamp::<f64>::from_clock_value(timer.get_current_counter_ticks().flex_unwrap());
let inputs = setup(); for _ in 0..count {
let start = Timestamp::<f64>::from_clock_value(timer.get_current_clock().flex_unwrap()); f();
f(inputs);
let end = Timestamp::<f64>::from_clock_value(timer.get_current_clock().flex_unwrap());
let mut run_duration = (end - start).ms();
// After 512 seconds, we get a negative difference between the start
// time and the end time.
if run_duration < 0.0 {
run_duration += 512.0 * 1000.0;
} }
let end =
elapsed += run_duration; Timestamp::<f64>::from_clock_value(timer.get_current_counter_ticks().flex_unwrap());
let elapsed = (end - start).ms();
writeln!(console, "{},", run_duration).unwrap();
console.flush();
}
writeln!( writeln!(
console, console,
"Total: {} ms elapsed for {} iterations ({} ms/iter)", "{} ms elapsed for {} iterations ({} ms/iter)",
elapsed, elapsed,
iter_count, count,
elapsed / (iter_count as f64) elapsed / (count as f64)
) )
.unwrap(); .unwrap();
console.flush(); if elapsed > 1000.0 {
break;
}
count <<= 1;
}
} }

View File

@@ -12,18 +12,25 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#![no_main]
#![no_std] #![no_std]
extern crate lang_items; extern crate lang_items;
use core::fmt::Write; use core::fmt::Write;
use ctap2::env::tock::take_storage; use ctap2::env::tock::take_storage;
use libtock_drivers::console::Console; use libtock_console::Console;
use libtock_drivers::led;
use libtock_drivers::result::FlexUnwrap; use libtock_drivers::result::FlexUnwrap;
use libtock_leds::Leds;
use libtock_platform as platform;
use libtock_runtime::{set_main, stack_size, TockSyscalls};
use persistent_store::{Storage, StorageIndex}; use persistent_store::{Storage, StorageIndex};
use platform::DefaultConfig;
libtock_core::stack_size! {0x800} stack_size! {0x800}
set_main! {main}
type Syscalls = TockSyscalls;
fn is_page_erased(storage: &dyn Storage, page: usize) -> bool { fn is_page_erased(storage: &dyn Storage, page: usize) -> bool {
let index = StorageIndex { page, byte: 0 }; let index = StorageIndex { page, byte: 0 };
@@ -36,20 +43,21 @@ fn is_page_erased(storage: &dyn Storage, page: usize) -> bool {
} }
fn main() { fn main() {
led::get(1).flex_unwrap().on().flex_unwrap(); // red on dongle Leds::<Syscalls>::on(1).map_err(|e| e.into()).flex_unwrap(); // red on dongle
let mut storage = take_storage().unwrap(); let mut storage = take_storage::<Syscalls, DefaultConfig>().unwrap();
let num_pages = storage.num_pages(); let num_pages = storage.num_pages();
writeln!(Console::new(), "Erase {} pages of storage:", num_pages).unwrap(); let mut console = Console::<Syscalls>::writer();
writeln!(console, "Erase {} pages of storage:", num_pages).unwrap();
for page in 0..num_pages { for page in 0..num_pages {
write!(Console::new(), "- Page {} ", page).unwrap(); write!(console, "- Page {} ", page).unwrap();
if is_page_erased(&storage, page) { if is_page_erased(&storage, page) {
writeln!(Console::new(), "skipped (was already erased).").unwrap(); writeln!(console, "skipped (was already erased).").unwrap();
} else { } else {
storage.erase_page(page).unwrap(); storage.erase_page(page).unwrap();
writeln!(Console::new(), "erased.").unwrap(); writeln!(console, "erased.").unwrap();
} }
} }
writeln!(Console::new(), "Done.").unwrap(); writeln!(console, "Done.").unwrap();
led::get(1).flex_unwrap().off().flex_unwrap(); Leds::<Syscalls>::on(1).map_err(|e| e.into()).flex_unwrap();
led::get(0).flex_unwrap().on().flex_unwrap(); // green on dongle Leds::<Syscalls>::off(0).map_err(|e| e.into()).flex_unwrap(); // green on dongle
} }

View File

@@ -1,184 +0,0 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#![no_std]
#![feature(asm)]
#![feature(llvm_asm)]
#![allow(dead_code)]
extern crate alloc;
extern crate lang_items;
use core::fmt::Write;
use core::ptr;
use crypto::sha256::Sha256;
use crypto::{ecdsa, hybrid, sha256};
use libtock_drivers::console::Console;
libtock_core::stack_size! {0x11800}
#[inline(never)]
fn read_stack_pointer() -> u32 {
let x = 1u32;
let address = &x as *const u32;
address as u32
}
#[inline(never)]
fn print_stack_pointer(console: &mut Console) {
let x = 1u32;
writeln!(console, "Stack pointer: {:?}", &x as *const u32).unwrap();
}
/// Writes a byte pattern to a memory range.
///
/// Since the stack grows to lower addresses, end < start.
/// Addresses after start must be unused, i.e. start must be at least the current stack pointer.
/// Addresses until end should be within the stack area.
unsafe fn paint_memory(start: u32, end: u32) {
for address in (end..start).step_by(4) {
let p = address as *const u32;
ptr::write(p as *mut u32, 0xCDCDCDCD);
}
}
/// Find the lowest address that does not have the 0xCD pattern.
unsafe fn find_border(start: u32, end: u32) -> u32 {
for address in (end..start).step_by(4) {
let p = address as *const u32;
if ptr::read(p) != 0xCDCDCDCD {
return address;
}
}
start
}
#[inline(never)]
pub fn black_box<T>(dummy: T) -> T {
unsafe { llvm_asm!("" : : "r"(&dummy)) }
dummy
}
#[inline(never)]
fn keygen_ecdsa(rng: &mut rng256::TockRng256) {
let sk = ecdsa::SecKey::gensk(rng);
black_box(sk);
}
#[inline(never)]
fn keygen_dilithium(rng: &mut rng256::TockRng256) {
let sk = dilithium::sign::SecKey::gensk(rng);
black_box(sk);
}
#[inline(never)]
fn keygen_hybrid(rng: &mut rng256::TockRng256) {
let sk = hybrid::SecKey::gensk_with_pk(rng);
black_box(sk);
}
#[inline(never)]
fn sign_ecdsa(rng: &mut rng256::TockRng256, sk: &ecdsa::SecKey) {
let sig = sk.sign_rng::<sha256::Sha256, _>(&[], rng);
black_box(sig);
}
fn sign_dilithium(sk: &dilithium::sign::SecKey) {
let sig = sk.sign(&[]);
black_box(sig);
}
#[inline(never)]
fn sign_hybrid(sk: &hybrid::SecKey) {
let sig = sk.sign_rfc6979::<Sha256>(&[]);
black_box(sig);
}
// Measure the stack usage of the method itself, plus a u32.
#[inline(never)]
fn dummy_test() {
let x = 1u32;
black_box(x);
}
// Tests whether input parameters are correctly ignored in the measurement.
#[inline(never)]
fn param_test(big_param: &mut [u8; 0x1000]) {
let x = 0x01;
big_param[0] = x;
black_box(x);
}
fn write_result(console: &mut Console, text: &str, size: u32) {
writeln!(console, "{} size: 0x{:08X}", text, size).unwrap();
}
fn main() {
let mut console = Console::new();
let x = 1u32;
let sp = &x as *const u32;
// Should be safe to write from here.
let start = sp as u32 - 0x100u32;
writeln!(console, "Search start address: 0x{:08X}", start).unwrap();
print_stack_pointer(&mut console);
let mut rng = rng256::TockRng256 {};
unsafe { paint_memory(start, 0x20020000) };
keygen_ecdsa(&mut rng);
let min_address1 = unsafe { find_border(start, 0x20020000) };
unsafe { paint_memory(start, 0x20020000) };
keygen_dilithium(&mut rng);
let min_address2 = unsafe { find_border(start, 0x20020000) };
unsafe { paint_memory(start, 0x20020000) };
keygen_hybrid(&mut rng);
let min_address3 = unsafe { find_border(start, 0x20020000) };
let sk = ecdsa::SecKey::gensk(&mut rng);
unsafe { paint_memory(start, 0x20020000) };
sign_ecdsa(&mut rng, &sk);
let min_address4 = unsafe { find_border(start, 0x20020000) };
let sk = dilithium::sign::SecKey::gensk(&mut rng);
unsafe { paint_memory(start, 0x20020000) };
sign_dilithium(&sk);
let min_address5 = unsafe { find_border(start, 0x20020000) };
let sk = hybrid::SecKey::gensk(&mut rng);
unsafe { paint_memory(start, 0x20020000) };
sign_hybrid(&sk);
let min_address6 = unsafe { find_border(start, 0x20020000) };
let mut param = [0; 0x1000];
unsafe { paint_memory(start, 0x20020000) };
param_test(&mut param);
let min_address7 = unsafe { find_border(start, 0x20020000) };
unsafe { paint_memory(start, 0x20020000) };
dummy_test();
let min_address8 = unsafe { find_border(start, 0x20020000) };
let main_end = read_stack_pointer();
write_result(&mut console, " keygen_ecdsa", main_end - min_address1);
write_result(&mut console, "keygen_dilithium", main_end - min_address2);
write_result(&mut console, " keygen_hybrid", main_end - min_address3);
write_result(&mut console, " sign_ecdsa", main_end - min_address4);
write_result(&mut console, " sign_dilithium", main_end - min_address5);
write_result(&mut console, " sign_hybrid", main_end - min_address6);
write_result(&mut console, " test dummy", main_end - min_address7);
write_result(&mut console, " test input", main_end - min_address8);
}

View File

@@ -1,3 +1,4 @@
#![no_main]
#![no_std] #![no_std]
extern crate alloc; extern crate alloc;
@@ -5,27 +6,32 @@ extern crate lang_items;
extern crate libtock_drivers; extern crate libtock_drivers;
use core::fmt::Write; use core::fmt::Write;
use libtock_drivers::console::Console; use libtock_console::{Console, ConsoleWriter};
use libtock_runtime::{set_main, stack_size, TockSyscalls};
libtock_core::stack_size! {0x4000} stack_size! {0x4000}
set_main! {main}
type Syscalls = TockSyscalls;
#[cfg(not(feature = "with_nfc"))] #[cfg(not(feature = "with_nfc"))]
mod example { mod example {
use super::{Console, Write}; use super::{ConsoleWriter, Syscalls, Write};
pub fn nfc(console: &mut Console) { pub fn nfc(console: &mut ConsoleWriter<Syscalls>) {
writeln!(console, "NFC feature flag is missing!").unwrap(); writeln!(console, "NFC feature flag is missing!").unwrap();
} }
} }
#[cfg(feature = "with_nfc")] #[cfg(feature = "with_nfc")]
mod example { mod example {
use super::{Console, Write}; use super::{Console, ConsoleWriter, Write};
use libtock_core::result::CommandError; use crate::Syscalls;
use libtock_drivers::nfc::{NfcTag, RecvOp}; use libtock_drivers::nfc::{NfcTag, RecvOp};
use libtock_drivers::result::{FlexUnwrap, TockError}; use libtock_drivers::result::{FlexUnwrap, TockError};
use libtock_drivers::timer; use libtock_drivers::timer;
use libtock_drivers::timer::{Timer, Timestamp}; use libtock_drivers::timer::{Timer, Timestamp};
use libtock_platform::{DefaultConfig, ErrorCode};
#[derive(Copy, Clone, Debug, PartialEq)] #[derive(Copy, Clone, Debug, PartialEq)]
#[allow(clippy::upper_case_acronyms)] #[allow(clippy::upper_case_acronyms)]
@@ -48,16 +54,15 @@ mod example {
ENOSUPPORT, ENOSUPPORT,
} }
impl From<isize> for ReturnCode { impl From<ErrorCode> for ReturnCode {
fn from(original: isize) -> ReturnCode { fn from(original: ErrorCode) -> ReturnCode {
match original { match original {
0 => ReturnCode::SUCCESS, ErrorCode::Fail => ReturnCode::FAIL,
-1 => ReturnCode::FAIL, ErrorCode::Busy => ReturnCode::EBUSY,
-2 => ReturnCode::EBUSY, ErrorCode::Off => ReturnCode::EOFF,
-4 => ReturnCode::EOFF, ErrorCode::Invalid => ReturnCode::EINVAL,
-6 => ReturnCode::EINVAL, ErrorCode::Cancel => ReturnCode::ECANCEL,
-8 => ReturnCode::ECANCEL, ErrorCode::NoMem => ReturnCode::ENOMEM,
-9 => ReturnCode::ENOMEM,
_ => ReturnCode::ENOSUPPORT, _ => ReturnCode::ENOSUPPORT,
} }
} }
@@ -66,34 +71,32 @@ mod example {
/// Helper function to write on console the received packet. /// Helper function to write on console the received packet.
fn print_rx_buffer(buf: &mut [u8]) { fn print_rx_buffer(buf: &mut [u8]) {
if let Some((last, bytes)) = buf.split_last() { if let Some((last, bytes)) = buf.split_last() {
let mut console = Console::new(); let mut console = Console::<Syscalls>::writer();
write!(console, "RX:").unwrap(); write!(console, "RX:").unwrap();
for byte in bytes { for byte in bytes {
write!(console, " {:02x?}", byte).unwrap(); write!(console, " {:02x?}", byte).unwrap();
} }
writeln!(console, " {:02x?}", last).unwrap(); writeln!(console, " {:02x?}", last).unwrap();
console.flush();
} }
} }
/// Function to identify the time elapsed for a transmission request. /// Function to identify the time elapsed for a transmission request.
fn bench_transmit( fn bench_transmit(
console: &mut Console, console: &mut ConsoleWriter<Syscalls>,
timer: &Timer, timer: &Timer<Syscalls>,
title: &str, title: &str,
mut buf: &mut [u8], buf: &mut [u8],
) -> ReturnCode { ) -> ReturnCode {
let amount = buf.len(); let amount = buf.len();
let start = Timestamp::<f64>::from_clock_value(timer.get_current_clock().flex_unwrap()); let start =
match NfcTag::transmit(&mut buf, amount) { Timestamp::<f64>::from_clock_value(timer.get_current_counter_ticks().flex_unwrap());
match NfcTag::<Syscalls, DefaultConfig>::transmit(buf, amount as u32) {
Ok(_) => (), Ok(_) => (),
Err(TockError::Command(CommandError { Err(TockError::Command(ErrorCode::Cancel)) => return ReturnCode::ECANCEL,
return_code: -8, /* ECANCEL: No Field*/ Err(_) => writeln!(console, " -- tx error!").unwrap(),
..
})) => return ReturnCode::ECANCEL,
Err(_) => writeln!(Console::new(), " -- tx error!").unwrap(),
} }
let end = Timestamp::<f64>::from_clock_value(timer.get_current_clock().flex_unwrap()); let end =
Timestamp::<f64>::from_clock_value(timer.get_current_counter_ticks().flex_unwrap());
let elapsed = (end - start).ms(); let elapsed = (end - start).ms();
writeln!( writeln!(
console, console,
@@ -104,21 +107,21 @@ mod example {
(amount as f64) / elapsed * 8. (amount as f64) / elapsed * 8.
) )
.unwrap(); .unwrap();
console.flush();
ReturnCode::SUCCESS ReturnCode::SUCCESS
} }
fn receive_packet(console: &mut Console, mut buf: &mut [u8; 256]) -> ReturnCode { fn receive_packet(console: &mut ConsoleWriter<Syscalls>, buf: &mut [u8; 256]) -> ReturnCode {
match NfcTag::receive(&mut buf) { match NfcTag::<Syscalls, DefaultConfig>::receive(buf) {
Ok(RecvOp { Ok(RecvOp {
recv_amount: amount, recv_amount: amount,
.. ..
}) => { }) => {
if amount <= buf.len() { if amount <= buf.len() as u32 {
print_rx_buffer(&mut buf[..amount]); print_rx_buffer(&mut buf[..amount as usize]);
} }
} }
Err(TockError::Command(CommandError { return_code, .. })) => return return_code.into(), Err(TockError::Command(code)) => return code.into(),
Err(_) => { Err(_) => {
writeln!(console, " -- RX Err").unwrap(); writeln!(console, " -- RX Err").unwrap();
return ReturnCode::ECANCEL; return ReturnCode::ECANCEL;
@@ -127,54 +130,58 @@ mod example {
ReturnCode::SUCCESS ReturnCode::SUCCESS
} }
fn transmit_reply(mut console: &mut Console, timer: &Timer, buf: &[u8]) -> ReturnCode { fn transmit_reply(
console: &mut ConsoleWriter<Syscalls>,
timer: &Timer<Syscalls>,
buf: &[u8],
) -> ReturnCode {
let mut return_code = ReturnCode::SUCCESS; let mut return_code = ReturnCode::SUCCESS;
match buf[0] { match buf[0] {
0xe0 /* RATS */=> { 0xe0 /* RATS */=> {
let mut answer_to_select = [0x05, 0x78, 0x80, 0xB1, 0x00]; let mut answer_to_select = [0x05, 0x78, 0x80, 0xB1, 0x00];
return_code = bench_transmit(&mut console, timer, "TX: ATS", &mut answer_to_select); return_code = bench_transmit(console, timer, "TX: ATS", &mut answer_to_select);
} }
0xc2 /* DESELECT */ => { 0xc2 /* DESELECT */ => {
// Ignore the request // Ignore the request
let mut command_error = [0x6A, 0x81]; let mut command_error = [0x6A, 0x81];
return_code = bench_transmit(&mut console, timer, "TX: DESELECT", &mut command_error); return_code = bench_transmit(console, timer, "TX: DESELECT", &mut command_error);
} }
0x02 | 0x03 /* APDU Prefix */ => match buf[2] { 0x02 | 0x03 /* APDU Prefix */ => match buf[2] {
// If the received packet is applet selection command (FIDO 2) // If the received packet is applet selection command (FIDO 2)
0xa4 /* SELECT */ => if buf[3] == 0x04 && buf[5] == 0x08 && buf[6] == 0xa0 { 0xa4 /* SELECT */ => if buf[3] == 0x04 && buf[5] == 0x08 && buf[6] == 0xa0 {
// Vesion: "FIDO_2_0" // Vesion: "FIDO_2_0"
let mut reply = [buf[0], 0x46, 0x49, 0x44, 0x4f, 0x5f, 0x32, 0x5f, 0x30, 0x90, 0x00,]; let mut reply = [buf[0], 0x46, 0x49, 0x44, 0x4f, 0x5f, 0x32, 0x5f, 0x30, 0x90, 0x00,];
return_code = bench_transmit(&mut console, timer, "TX: Version Str", &mut reply); return_code = bench_transmit(console, timer, "TX: Version Str", &mut reply);
} else if (buf[6] == 0xd2 && buf[7] == 0x76) || (buf[6] == 0xe1 && (buf[7] == 0x03 || buf[7] == 0x04)){ } else if (buf[6] == 0xd2 && buf[7] == 0x76) || (buf[6] == 0xe1 && (buf[7] == 0x03 || buf[7] == 0x04)){
let mut reply = [buf[0], 0x90, 0x00]; let mut reply = [buf[0], 0x90, 0x00];
return_code = bench_transmit(&mut console, timer, "TX: 0x9000", &mut reply); return_code = bench_transmit(console, timer, "TX: 0x9000", &mut reply);
} else /* Unknown file */ { } else /* Unknown file */ {
let mut reply = [buf[0], 0x6a, 0x82]; let mut reply = [buf[0], 0x6a, 0x82];
return_code = bench_transmit(&mut console, timer, "TX: 0x6A82", &mut reply); return_code = bench_transmit(console, timer, "TX: 0x6A82", &mut reply);
} }
0xb0 /* READ */ => match buf[5] { 0xb0 /* READ */ => match buf[5] {
0x02 => { 0x02 => {
let mut reply = [buf[0], 0x12, 0x90, 0x00,]; let mut reply = [buf[0], 0x12, 0x90, 0x00,];
return_code = bench_transmit(&mut console, timer, "TX: File Size", &mut reply); return_code = bench_transmit(console, timer, "TX: File Size", &mut reply);
} }
0x12 => { 0x12 => {
let mut reply = [buf[0], 0xd1, 0x01, 0x0e, 0x55, 0x77, 0x77, 0x77, 0x2e, 0x6f, 0x70, 0x65, let mut reply = [buf[0], 0xd1, 0x01, 0x0e, 0x55, 0x77, 0x77, 0x77, 0x2e, 0x6f, 0x70, 0x65,
0x6e, 0x73, 0x6b, 0x2e, 0x64, 0x65, 0x76, 0x90, 0x00,]; 0x6e, 0x73, 0x6b, 0x2e, 0x64, 0x65, 0x76, 0x90, 0x00,];
return_code = bench_transmit(&mut console, timer, "TX: NDEF", &mut reply); return_code = bench_transmit(console, timer, "TX: NDEF", &mut reply);
} }
0x0f => { 0x0f => {
let mut reply = [buf[0], 0x00, 0x0f, 0x20, 0x00, 0x7f, 0x00, 0x7f, 0x04, 0x06, 0xe1, 0x04, let mut reply = [buf[0], 0x00, 0x0f, 0x20, 0x00, 0x7f, 0x00, 0x7f, 0x04, 0x06, 0xe1, 0x04,
0x00, 0x7f, 0x00, 0x00, 0x90, 0x00,]; 0x00, 0x7f, 0x00, 0x00, 0x90, 0x00,];
return_code = bench_transmit(&mut console, timer, "TX: CC", &mut reply); return_code = bench_transmit(console, timer, "TX: CC", &mut reply);
} }
_ => { _ => {
let mut reply = [buf[0], 0x90, 0x00]; let mut reply = [buf[0], 0x90, 0x00];
return_code = bench_transmit(&mut console, timer, "TX: 0x9000", &mut reply); return_code = bench_transmit(console, timer, "TX: 0x9000", &mut reply);
} }
} }
_ => { _ => {
let mut reply = [buf[0], 0x90, 0x00]; let mut reply = [buf[0], 0x90, 0x00];
return_code = bench_transmit(&mut console, timer, "TX: 0x9000", &mut reply); return_code = bench_transmit(console, timer, "TX: 0x9000", &mut reply);
} }
} }
0x26 | 0x52 | 0x50 /* REQA | WUPA | Halt */ => { 0x26 | 0x52 | 0x50 /* REQA | WUPA | Halt */ => {
@@ -185,31 +192,27 @@ mod example {
return_code return_code
} }
pub fn nfc(mut console: &mut Console) { pub fn nfc(console: &mut ConsoleWriter<Syscalls>) {
// Setup the timer with a dummy callback (we only care about reading the current time, but the // Setup the timer with a dummy callback (we only care about reading the current time, but the
// API forces us to set an alarm callback too). // API forces us to set an alarm callback too).
let mut with_callback = timer::with_callback(|_, _| {}); let mut with_callback = timer::with_callback(|_| {});
let timer = with_callback.init().flex_unwrap(); let timer = with_callback.init().flex_unwrap();
writeln!( writeln!(console, "Clock frequency: {:?} Hz", timer.clock_frequency()).unwrap();
console,
"Clock frequency: {} Hz",
timer.clock_frequency().hz()
)
.unwrap();
let mut state_change_counter = 0; let mut state_change_counter = 0;
loop { loop {
let mut rx_buf = [0; 256]; let mut rx_buf = [0; 256];
match receive_packet(&mut console, &mut rx_buf) { match receive_packet(console, &mut rx_buf) {
ReturnCode::EOFF => { ReturnCode::EOFF => {
// Not configured // Not configured
while !NfcTag::enable_emulation() {} while !NfcTag::<Syscalls, DefaultConfig>::enable_emulation() {}
// Configure Type 4 tag // Configure Type 4 tag
while !NfcTag::configure(4) {} while !NfcTag::<Syscalls, DefaultConfig>::configure(4) {}
} }
ReturnCode::ECANCEL /* field lost */ => { ReturnCode::ECANCEL /* field lost */ => {
NfcTag::disable_emulation(); NfcTag::<Syscalls, DefaultConfig>::disable_emulation();
} }
ReturnCode::EBUSY /* awaiting select*/ => (), ReturnCode::EBUSY /* awaiting select*/ => (),
ReturnCode::ENOMEM => { ReturnCode::ENOMEM => {
@@ -220,9 +223,9 @@ mod example {
ReturnCode::ENOSUPPORT => (), ReturnCode::ENOSUPPORT => (),
ReturnCode::SUCCESS => { ReturnCode::SUCCESS => {
// If the reader restarts the communication then disable the tag. // If the reader restarts the communication then disable the tag.
match transmit_reply(&mut console, &timer, &rx_buf) { match transmit_reply(console, &timer, &rx_buf) {
ReturnCode::ECANCEL | ReturnCode::EOFF => { ReturnCode::ECANCEL | ReturnCode::EOFF => {
if NfcTag::disable_emulation() { if NfcTag::<Syscalls, DefaultConfig>::disable_emulation() {
writeln!(console, " -- TAG DISABLED").unwrap(); writeln!(console, " -- TAG DISABLED").unwrap();
} }
state_change_counter += 1; state_change_counter += 1;
@@ -239,7 +242,7 @@ mod example {
} }
fn main() { fn main() {
let mut console = Console::new(); let mut console = Console::<Syscalls>::writer();
writeln!(console, "****************************************").unwrap(); writeln!(console, "****************************************").unwrap();
writeln!(console, "nfct_test application is installed").unwrap(); writeln!(console, "nfct_test application is installed").unwrap();
example::nfc(&mut console); example::nfc(&mut console);

View File

@@ -12,24 +12,30 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#![no_main]
#![no_std] #![no_std]
extern crate alloc; extern crate alloc;
extern crate lang_items; extern crate lang_items;
libtock_core::stack_size! {0x800}
use alloc::vec::Vec; use alloc::vec::Vec;
use core::fmt::Write; use core::fmt::Write;
use libtock_drivers::console::Console; use libtock_console::Console;
use libtock_runtime::{set_main, stack_size, TockSyscalls};
stack_size! {0x800}
set_main! {main}
type Syscalls = TockSyscalls;
fn main() { fn main() {
writeln!(Console::new(), "****************************************").unwrap(); let mut console = Console::<Syscalls>::writer();
writeln!(console, "****************************************").unwrap();
for i in 0.. { for i in 0.. {
writeln!(Console::new(), "Allocating {} bytes...", 1 << i).unwrap(); writeln!(console, "Allocating {} bytes...", 1 << i).unwrap();
let x: Vec<u8> = Vec::with_capacity(1 << i); let x: Vec<u8> = Vec::with_capacity(1 << i);
writeln!(Console::new(), "Allocated!").unwrap(); writeln!(console, "Allocated!").unwrap();
drop(x); drop(x);
writeln!(Console::new(), "Dropped!").unwrap(); writeln!(console, "Dropped!").unwrap();
} }
} }

View File

@@ -12,11 +12,15 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#![no_main]
#![no_std] #![no_std]
extern crate lang_items; extern crate lang_items;
libtock_core::stack_size! {0x800} use libtock_runtime::{set_main, stack_size};
stack_size! {0x800}
set_main! {main}
fn main() { fn main() {
panic!("Bye world!") panic!("Bye world!")

View File

@@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#![no_main]
#![no_std] #![no_std]
extern crate alloc; extern crate alloc;
@@ -21,26 +22,34 @@ use alloc::string::{String, ToString};
use alloc::vec::Vec; use alloc::vec::Vec;
use alloc::{format, vec}; use alloc::{format, vec};
use core::fmt::Write; use core::fmt::Write;
use ctap2::env::tock::{take_storage, TockStorage}; use ctap2::env::tock::{take_storage, Storage};
use libtock_drivers::console::Console; use libtock_console::Console;
use libtock_drivers::result::FlexUnwrap;
use libtock_drivers::timer::{self, Duration, Timer, Timestamp}; use libtock_drivers::timer::{self, Duration, Timer, Timestamp};
use persistent_store::Store; use libtock_platform::DefaultConfig;
use libtock_runtime::{set_main, stack_size, TockSyscalls};
use persistent_store::{Storage as _, Store};
libtock_core::stack_size! {0x2000} stack_size! {0x800}
set_main! {main}
fn timestamp(timer: &Timer) -> Timestamp<f64> { type Syscalls = TockSyscalls;
Timestamp::<f64>::from_clock_value(timer.get_current_clock().ok().unwrap())
fn timestamp(timer: &Timer<Syscalls>) -> Timestamp<f64> {
Timestamp::<f64>::from_clock_value(timer.get_current_counter_ticks().ok().unwrap())
} }
fn measure<T>(timer: &Timer, operation: impl FnOnce() -> T) -> (T, Duration<f64>) { fn measure<T>(timer: &Timer<Syscalls>, operation: impl FnOnce() -> T) -> (T, Duration<f64>) {
let before = timestamp(timer); let before = timestamp(timer);
let result = operation(); let result = operation();
let after = timestamp(timer); let after = timestamp(timer);
(result, after - before) (result, after - before)
} }
fn boot_store(mut storage: TockStorage, erase: bool) -> Store<TockStorage> { fn boot_store(
use persistent_store::Storage; mut storage: Storage<Syscalls, DefaultConfig>,
erase: bool,
) -> Store<Storage<Syscalls, DefaultConfig>> {
let num_pages = storage.num_pages(); let num_pages = storage.num_pages();
if erase { if erase {
for page in 0..num_pages { for page in 0..num_pages {
@@ -55,8 +64,7 @@ struct StorageConfig {
num_pages: usize, num_pages: usize,
} }
fn storage_config(storage: &TockStorage) -> StorageConfig { fn storage_config(storage: &Storage<Syscalls, DefaultConfig>) -> StorageConfig {
use persistent_store::Storage;
StorageConfig { StorageConfig {
num_pages: storage.num_pages(), num_pages: storage.num_pages(),
} }
@@ -73,19 +81,19 @@ struct Stat {
} }
fn compute_latency( fn compute_latency(
storage: TockStorage, storage: Storage<Syscalls, DefaultConfig>,
timer: &Timer, timer: &Timer<Syscalls>,
num_pages: usize, num_pages: usize,
key_increment: usize, key_increment: usize,
word_length: usize, word_length: usize,
) -> (TockStorage, Stat) { ) -> (Storage<Syscalls, DefaultConfig>, Stat) {
let mut stat = Stat { let mut stat = Stat {
key_increment, key_increment,
entry_length: word_length, entry_length: word_length,
..Default::default() ..Default::default()
}; };
let mut console = Console::new(); let mut console = Console::<Syscalls>::writer();
writeln!( writeln!(
console, console,
"\nLatency for key_increment={} word_length={}.", "\nLatency for key_increment={} word_length={}.",
@@ -155,20 +163,22 @@ fn compute_latency(
} }
fn main() { fn main() {
let mut with_callback = timer::with_callback(|_, _| {}); let mut with_callback = timer::with_callback::<Syscalls, DefaultConfig, _>(|_| {});
let timer = with_callback.init().ok().unwrap();
let storage = take_storage().unwrap(); let timer = with_callback.init().flex_unwrap();
let storage = take_storage::<Syscalls, DefaultConfig>().unwrap();
let config = storage_config(&storage); let config = storage_config(&storage);
let mut stats = Vec::new(); let mut stats = Vec::new();
let mut console = Console::<Syscalls>::writer();
writeln!(Console::new(), "\nRunning 2 tests...").unwrap(); writeln!(console, "\nRunning 2 tests...").unwrap();
// Simulate a store full of credentials (of 50 words). // Simulate a store full of credentials (of 50 words).
let (storage, stat) = compute_latency(storage, &timer, config.num_pages, 1, 50); let (storage, stat) = compute_latency(storage, &timer, config.num_pages, 1, 50);
stats.push(stat); stats.push(stat);
// Simulate a store full of increments of a single counter. // Simulate a store full of increments of a single counter.
let (_storage, stat) = compute_latency(storage, &timer, config.num_pages, 0, 1); let (_storage, stat) = compute_latency(storage, &timer, config.num_pages, 0, 1);
stats.push(stat); stats.push(stat);
writeln!(Console::new(), "\nDone.\n").unwrap(); writeln!(console, "\nDone.\n").unwrap();
const HEADERS: &[&str] = &[ const HEADERS: &[&str] = &[
"Overwrite", "Overwrite",
@@ -189,8 +199,8 @@ fn main() {
format!("{:.1} ms", stat.remove_ms), format!("{:.1} ms", stat.remove_ms),
]); ]);
} }
writeln!(Console::new(), "Copy to examples/store_latency.rs:\n").unwrap(); writeln!(console, "Copy to examples/store_latency.rs:\n").unwrap();
writeln!(Console::new(), "{:?}", config).unwrap(); writeln!(console, "{:?}", config).unwrap();
write_matrix(matrix); write_matrix(matrix);
// Results for nrf52840dk_opensk: // Results for nrf52840dk_opensk:
@@ -201,10 +211,11 @@ fn main() {
} }
fn align(x: &str, n: usize) { fn align(x: &str, n: usize) {
let mut console = Console::<Syscalls>::writer();
for _ in 0..n.saturating_sub(x.len()) { for _ in 0..n.saturating_sub(x.len()) {
write!(Console::new(), " ").unwrap(); write!(console, " ").unwrap();
} }
write!(Console::new(), "{}", x).unwrap(); write!(console, "{}", x).unwrap();
} }
fn write_matrix(mut m: Vec<Vec<String>>) { fn write_matrix(mut m: Vec<Vec<String>>) {
@@ -223,6 +234,6 @@ fn write_matrix(mut m: Vec<Vec<String>>) {
for col in 0..num_cols { for col in 0..num_cols {
align(&row[col], col_len[col] + 2 * (col > 0) as usize); align(&row[col], col_len[col] + 2 * (col > 0) as usize);
} }
writeln!(Console::new()).unwrap(); writeln!(Console::<Syscalls>::writer()).unwrap();
} }
} }

794
fuzz/Cargo.lock generated
View File

@@ -1,794 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "0.7.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e"
dependencies = [
"memchr",
]
[[package]]
name = "arbitrary"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db55d72333851e17d572bec876e390cd3b11eb1ef53ae821dd9f3b653d2b4569"
dependencies = [
"derive_arbitrary",
]
[[package]]
name = "arrayref"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
[[package]]
name = "autocfg"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0dde43e75fd43e8a1bf86103336bc699aa8d17ad1be60c76c0bdfd4828e19b78"
dependencies = [
"autocfg 1.1.0",
]
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bumpalo"
version = "3.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c"
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cc"
version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cloudabi"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
dependencies = [
"bitflags",
]
[[package]]
name = "crypto"
version = "0.1.0"
dependencies = [
"arrayref",
"byteorder",
"hex",
"regex",
"ring",
"rng256",
"serde",
"serde_json",
"subtle",
"untrusted",
]
[[package]]
name = "ctap2"
version = "1.0.0"
dependencies = [
"arbitrary",
"arrayref",
"byteorder",
"crypto",
"embedded-time",
"lang_items",
"libtock_core",
"libtock_drivers",
"openssl",
"persistent_store",
"rand 0.8.5",
"rng256",
"sk-cbor",
"subtle",
"uuid",
]
[[package]]
name = "ctap2-fuzz"
version = "0.0.0"
dependencies = [
"fuzz_helper",
"libfuzzer-sys",
]
[[package]]
name = "derive_arbitrary"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1a012b5e473dc912f0db0546a1c9c6a194ce8494feb66fa0237160926f9e0e6"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "embedded-time"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7a4b4d10ac48d08bfe3db7688c402baadb244721f30a77ce360bd24c3dffe58"
dependencies = [
"num",
]
[[package]]
name = "foreign-types"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
dependencies = [
"foreign-types-shared",
]
[[package]]
name = "foreign-types-shared"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
[[package]]
name = "fuzz_helper"
version = "0.1.0"
dependencies = [
"arbitrary",
"arrayref",
"crypto",
"ctap2",
"embedded-time",
"lang_items",
"libtock_drivers",
"rng256",
"sk-cbor",
]
[[package]]
name = "getrandom"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "hex"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77"
[[package]]
name = "itoa"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
[[package]]
name = "js-sys"
version = "0.3.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47"
dependencies = [
"wasm-bindgen",
]
[[package]]
name = "lang_items"
version = "0.1.0"
dependencies = [
"libtock_core",
"libtock_drivers",
"linked_list_allocator",
]
[[package]]
name = "libc"
version = "0.2.133"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0f80d65747a3e43d1596c7c5492d95d5edddaabd45a7fcdb02b95f644164966"
[[package]]
name = "libfuzzer-sys"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcf184a4b6b274f82a5df6b357da6055d3e82272327bba281c28bbba6f1664ef"
dependencies = [
"arbitrary",
"cc",
]
[[package]]
name = "libtock_codegen"
version = "0.1.0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "libtock_core"
version = "0.1.0"
dependencies = [
"libtock_codegen",
]
[[package]]
name = "libtock_drivers"
version = "0.1.0"
dependencies = [
"libtock_core",
]
[[package]]
name = "linked_list_allocator"
version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "822add9edb1860698b79522510da17bef885171f75aa395cff099d770c609c24"
[[package]]
name = "log"
version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [
"cfg-if",
]
[[package]]
name = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "num"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b7a8e9be5e039e2ff869df49155f1c06bd01ade2117ec783e56ab0932b67a8f"
dependencies = [
"num-complex",
"num-integer",
"num-iter",
"num-rational",
"num-traits",
]
[[package]]
name = "num-complex"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "747d632c0c558b87dbabbe6a82f3b4ae03720d0646ac5b7b4dae89394be5f2c5"
dependencies = [
"num-traits",
]
[[package]]
name = "num-integer"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
dependencies = [
"autocfg 1.1.0",
"num-traits",
]
[[package]]
name = "num-iter"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
dependencies = [
"autocfg 1.1.0",
"num-integer",
"num-traits",
]
[[package]]
name = "num-rational"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07"
dependencies = [
"autocfg 1.1.0",
"num-integer",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
dependencies = [
"autocfg 1.1.0",
]
[[package]]
name = "once_cell"
version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0"
[[package]]
name = "openssl"
version = "0.10.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "618febf65336490dfcf20b73f885f5651a0c89c64c2d4a8c3662585a70bf5bd0"
dependencies = [
"bitflags",
"cfg-if",
"foreign-types",
"libc",
"once_cell",
"openssl-macros",
"openssl-sys",
]
[[package]]
name = "openssl-macros"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "openssl-sys"
version = "0.9.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5f9bd0c2710541a3cda73d6f9ac4f1b240de4ae261065d309dbe73d9dceb42f"
dependencies = [
"autocfg 1.1.0",
"cc",
"libc",
"pkg-config",
"vcpkg",
]
[[package]]
name = "persistent_store"
version = "0.1.0"
[[package]]
name = "pkg-config"
version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"
[[package]]
name = "ppv-lite86"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
[[package]]
name = "proc-macro2"
version = "1.0.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
dependencies = [
"autocfg 0.1.8",
"libc",
"rand_chacha 0.1.1",
"rand_core 0.4.2",
"rand_hc",
"rand_isaac",
"rand_jitter",
"rand_os",
"rand_pcg",
"rand_xorshift",
"winapi",
]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha 0.3.1",
"rand_core 0.6.4",
]
[[package]]
name = "rand_chacha"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
dependencies = [
"autocfg 0.1.8",
"rand_core 0.3.1",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core 0.6.4",
]
[[package]]
name = "rand_core"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
dependencies = [
"rand_core 0.4.2",
]
[[package]]
name = "rand_core"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "rand_hc"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "rand_isaac"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "rand_jitter"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b"
dependencies = [
"libc",
"rand_core 0.4.2",
"winapi",
]
[[package]]
name = "rand_os"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
dependencies = [
"cloudabi",
"fuchsia-cprng",
"libc",
"rand_core 0.4.2",
"rdrand",
"winapi",
]
[[package]]
name = "rand_pcg"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
dependencies = [
"autocfg 0.1.8",
"rand_core 0.4.2",
]
[[package]]
name = "rand_xorshift"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "rdrand"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "regex"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
[[package]]
name = "ring"
version = "0.16.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc"
dependencies = [
"cc",
"libc",
"once_cell",
"spin",
"untrusted",
"web-sys",
"winapi",
]
[[package]]
name = "rng256"
version = "0.1.0"
dependencies = [
"arrayref",
"libtock_drivers",
"rand 0.6.5",
]
[[package]]
name = "ryu"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
[[package]]
name = "serde"
version = "1.0.144"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.144"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e466864e431129c7e0d3476b92f20458e5879919a0596c6472738d9fa2d342f8"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "sk-cbor"
version = "0.1.2"
[[package]]
name = "spin"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]]
name = "subtle"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
[[package]]
name = "syn"
version = "1.0.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52205623b1b0f064a4e71182c3b18ae902267282930c6d5462c91b859668426e"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd"
[[package]]
name = "untrusted"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]]
name = "uuid"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
dependencies = [
"getrandom",
]
[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142"
dependencies = [
"bumpalo",
"log",
"once_cell",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c"
dependencies = [
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f"
[[package]]
name = "web-sys"
version = "0.3.60"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

View File

@@ -1,17 +0,0 @@
[package]
name = "fuzz_helper"
version = "0.1.0"
authors = ["Mingxiao Guo <mingxguo@google.com>"]
license = "Apache-2.0"
edition = "2018"
[dependencies]
arrayref = "0.3.6"
embedded-time = "0.12.1"
libtock_drivers = { path = "../../third_party/libtock-drivers" }
crypto = { path = "../../libraries/crypto", features = ['std'] }
rng256 = { path = "../../libraries/rng256", features = ['std'] }
sk-cbor = { path = "../../libraries/cbor" }
ctap2 = { path = "../..", features = ["fuzz"] }
lang_items = { path = "../../third_party/lang-items", features = ['std'] }
arbitrary = { version = "0.4.7", features = ["derive"] }

View File

@@ -1,52 +0,0 @@
diff --git a/deploy.py b/deploy.py
index 7f91a2b..f7b1e9a 100755
--- a/deploy.py
+++ b/deploy.py
@@ -156,7 +156,7 @@ SUPPORTED_BOARDS = {
),
}
-APP_HEAP_SIZE = 32768
+APP_HEAP_SIZE = 16384
def get_supported_boards() -> Tuple[str]:
diff --git a/examples/measure_stack.rs b/examples/measure_stack.rs
index 88f9ebc..d285a80 100644
--- a/examples/measure_stack.rs
+++ b/examples/measure_stack.rs
@@ -26,7 +26,7 @@ use crypto::{ecdsa, hybrid, sha256};
use crypto::sha256::Sha256;
use libtock_drivers::console::Console;
-libtock_core::stack_size! {0x11800}
+libtock_core::stack_size! {0x1A000}
#[inline(never)]
fn read_stack_pointer() -> u32 {
diff --git a/nrf52840_layout.ld b/nrf52840_layout.ld
index 538a2a8..c7dd5e7 100644
--- a/nrf52840_layout.ld
+++ b/nrf52840_layout.ld
@@ -14,7 +14,7 @@ MEMORY {
* Any change to STACK_SIZE should be accompanied by a corresponding change to
* `elf2tab`'s `--stack` option
*/
-STACK_SIZE = 71680;
+STACK_SIZE = 106496;
MPU_MIN_ALIGN = 8K;
diff --git a/patches/tock/07-app-break-fix.patch b/patches/tock/07-app-break-fix.patch
index fcf46fd..4048b59 100644
--- a/patches/tock/07-app-break-fix.patch
+++ b/patches/tock/07-app-break-fix.patch
@@ -7,7 +7,7 @@ index c78b1c9fb..2769d0138 100644
// The 1.x Tock kernel allocates at least 3 kB to processes, and we need
// to ensure that happens as userspace may expect it.
- 3 * 1024
-+ 70 * 1024
++ 104 * 1024
// TOCK 2.0
//

158
layout.ld
View File

@@ -1,158 +0,0 @@
/* Userland Generic Layout
*
* Currently, due to incomplete ROPI-RWPI support in rustc (see
* https://github.com/tock/libtock-rs/issues/28), this layout implements static
* linking. An application init script must define the FLASH and SRAM address
* ranges as well as MPU_MIN_ALIGN before including this layout file.
*
* Here is a an example application linker script to get started:
* MEMORY {
* /* FLASH memory region must start immediately *after* the Tock
* * Binary Format headers, which means you need to offset the
* * beginning of FLASH memory region relative to where the
* * application is loaded.
* FLASH (rx) : ORIGIN = 0x10030, LENGTH = 0x0FFD0
* SRAM (RWX) : ORIGIN = 0x20000, LENGTH = 0x10000
* }
* MPU_MIN_ALIGN = 8K;
* INCLUDE ../libtock-rs/layout.ld
*/
ENTRY(_start)
SECTIONS {
/* Section for just the app crt0 header.
* This must be first so that the app can find it.
*/
/* Runtime setup logic. The crt0_header symbol is used by the entry point
* assembly. We have to include start here rather than .text because
* otherwise elf2tab fails to recognize that the process binary's flash
* region should start at the beginning of .start.
*/
.start :
{
_beginning = .; /* Start of the app in flash. */
crt0_header = .;
/**
* Populate the header expected by `crt0`:
*
* struct hdr {
* uint32_t got_sym_start;
* uint32_t got_start;
* uint32_t got_size;
* uint32_t data_sym_start;
* uint32_t data_start;
* uint32_t data_size;
* uint32_t bss_start;
* uint32_t bss_size;
* uint32_t reldata_start;
* uint32_t stack_size;
* };
*/
/* Offset of GOT symbols in flash */
LONG(LOADADDR(.got) - _beginning);
/* Offset of GOT section in memory */
LONG(_got);
/* Size of GOT section */
LONG(SIZEOF(.got));
/* Offset of data symbols in flash */
LONG(LOADADDR(.data) - _beginning);
/* Offset of data section in memory */
LONG(_data);
/* Size of data section */
LONG(SIZEOF(.data));
/* Offset of BSS section in memory */
LONG(_bss);
/* Size of BSS section */
LONG(SIZEOF(.bss));
/* First address offset after program flash, where elf2tab places
* .rel.data section */
LONG(LOADADDR(.endflash) - _beginning);
/* The size of the stack requested by this application */
LONG(_stack_top_aligned - _sstack);
/* Pad the header out to a multiple of 32 bytes so there is not a gap
* between the header and subsequent .data section. It's unclear why,
* but LLD is aligning sections to a multiple of 32 bytes. */
. = ALIGN(32);
*(.start)
} > FLASH =0xFFFFFFFF
/* Text section, Code! */
.text :
{
. = ALIGN(4);
_text = .;
*(.text*)
*(.rodata*)
KEEP (*(.syscalls))
*(.ARM.extab*)
. = ALIGN(4); /* Make sure we're word-aligned here */
_etext = .;
} > FLASH =0xFFFFFFFF
/* Application stack */
.stack (NOLOAD) :
{
/* elf2tab requires that the `_sram_origin` symbol be present to
* mark the first address in the SRAM memory. Since ELF files do
* not really need to specify this address as they only care about
* loading into flash, we need to manually mark this address for
* elf2tab. elf2tab will use it to add a fixed address header in the
* TBF header if needed.
*/
_sram_origin = .;
_sstack = .;
KEEP(*(.stack_buffer))
_stack_top_unaligned = .;
. = ALIGN(8);
_stack_top_aligned = .;
} > SRAM
/* Data section, static initialized variables
* Note: This is placed in Flash after the text section, but needs to be
* moved to SRAM at runtime
*/
.data : AT (_etext)
{
. = ALIGN(4); /* Make sure we're word-aligned here */
_data = .;
KEEP(*(.data*))
*(.sdata*) /* RISC-V small-pointer data section */
. = ALIGN(4); /* Make sure we're word-aligned at the end of flash */
} > SRAM
/* Global Offset Table */
.got :
{
. = ALIGN(4); /* Make sure we're word-aligned here */
_got = .;
*(.got*)
*(.got.plt*)
. = ALIGN(4);
} > SRAM
/* BSS section, static uninitialized variables */
.bss :
{
. = ALIGN(4); /* Make sure we're word-aligned here */
_bss = .;
KEEP(*(.bss* .sbss*))
*(COMMON)
. = ALIGN(4);
} > SRAM
/* End of flash. */
.endflash :
{
} > FLASH
/* Sections we do not need. */
/DISCARD/ :
{
*(.ARM.exidx .eh_frame)
}
}
ASSERT((_stack_top_aligned - _stack_top_unaligned) == 0, "
STACK_SIZE must be 8 byte multiple")

View File

@@ -1,7 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "sk-cbor"
version = "0.1.2"

View File

@@ -13,41 +13,26 @@ This crate implements Concise Binary Object Representation (CBOR) from [RFC
```rust ```rust
fn main() { fn main() {
// Build a CBOR object with various different types included. Note that this // Build a CBOR object with the crate's convenience macros. Note that this
// object is not built in canonical order. // object is not built in canonical order.
let manual_object = Value::Map(vec![ let map_object = cbor_map! {
(
Value::Unsigned(1),
Value::Array(vec![Value::Unsigned(2), Value::Unsigned(3)]),
),
(
Value::TextString("tstr".to_owned()),
Value::ByteString(vec![1, 2, 3]),
),
(Value::Negative(-2), Value::Simple(SimpleValue::NullValue)),
(Value::Unsigned(3), Value::Simple(SimpleValue::TrueValue)),
]);
// Build the same object using the crate's convenience macros.
let macro_object = cbor_map! {
1 => cbor_array![2, 3], 1 => cbor_array![2, 3],
"tstr" => cbor_bytes!(vec![1, 2, 3]), "tstr" => cbor_bytes!(vec![1, 2, 3]),
-2 => cbor_null!(), -2 => cbor_null!(),
3 => cbor_true!(), 3 => cbor_true!(),
}; };
assert_eq!(manual_object, macro_object); println!("Object {:?}", map_object);
println!("Object {:?}", manual_object);
// Serialize to bytes. // Serialize to bytes.
let mut manual_data = vec![]; let mut map_data = vec![];
sk_cbor::writer::write(manual_object, &mut manual_data); sk_cbor::writer::write(map_object, &mut map_data).unwrap();
let hex_manual_data = hexify(&manual_data); let hex_map_data = hex::encode(&map_data);
// Serialized version is in canonical order. // Serialized version is in canonical order.
println!("Serializes to {}", hex_manual_data); println!("Serializes to {}", hex_map_data);
assert_eq!( assert_eq!(
hex_manual_data, hex_map_data,
concat!( concat!(
"a4", // 4-map "a4", // 4-map
"01", // int(1) => "01", // int(1) =>
@@ -63,7 +48,7 @@ fn main() {
// Convert back to an object. This is different than the original object, // Convert back to an object. This is different than the original object,
// because the map is now in canonical order. // because the map is now in canonical order.
let recovered_object = sk_cbor::reader::read(&manual_data).unwrap(); let recovered_object = sk_cbor::reader::read(&map_data).unwrap();
println!("Deserializes to {:?}", recovered_object); println!("Deserializes to {:?}", recovered_object);
} }
``` ```

View File

@@ -18,7 +18,7 @@
extern crate alloc; extern crate alloc;
use sk_cbor::values::{SimpleValue, Value}; use sk_cbor::values::Value;
use sk_cbor::{cbor_array, cbor_bytes, cbor_map, cbor_null, cbor_true}; use sk_cbor::{cbor_array, cbor_bytes, cbor_map, cbor_null, cbor_true};
fn hexify(data: &[u8]) -> String { fn hexify(data: &[u8]) -> String {
@@ -32,17 +32,14 @@ fn hexify(data: &[u8]) -> String {
fn main() { fn main() {
// Build a CBOR object with various different types included. Note that this // Build a CBOR object with various different types included. Note that this
// object is not built in canonical order. // object is not built in canonical order.
let manual_object = Value::Map(vec![ let manual_object = Value::map(vec![
( (
Value::Unsigned(1), Value::from(1),
Value::Array(vec![Value::Unsigned(2), Value::Unsigned(3)]), Value::array(vec![Value::from(2), Value::from(3)]),
), ),
( (Value::from("tstr".to_owned()), Value::from(vec![1, 2, 3])),
Value::TextString("tstr".to_owned()), (Value::from(-2), Value::null_value()),
Value::ByteString(vec![1, 2, 3]), (Value::from(3), Value::bool_value(true)),
),
(Value::Negative(-2), Value::Simple(SimpleValue::NullValue)),
(Value::Unsigned(3), Value::Simple(SimpleValue::TrueValue)),
]); ]);
// Build the same object using the crate's convenience macros. // Build the same object using the crate's convenience macros.

3
libraries/cbor/fuzz/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
/artifacts/
/corpus/
/target/

View File

@@ -1,37 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "arbitrary"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db55d72333851e17d572bec876e390cd3b11eb1ef53ae821dd9f3b653d2b4569"
[[package]]
name = "cc"
version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
[[package]]
name = "libfuzzer-sys"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcf184a4b6b274f82a5df6b357da6055d3e82272327bba281c28bbba6f1664ef"
dependencies = [
"arbitrary",
"cc",
]
[[package]]
name = "sk-cbor"
version = "0.1.2"
[[package]]
name = "sk-cbor-fuzz"
version = "0.0.0"
dependencies = [
"libfuzzer-sys",
"sk-cbor",
]

View File

@@ -22,5 +22,5 @@ pub mod values;
pub mod writer; pub mod writer;
pub use self::reader::read; pub use self::reader::read;
pub use self::values::{SimpleValue, Value}; pub use self::values::Value;
pub use self::writer::write; pub use self::writer::write;

View File

@@ -139,9 +139,12 @@ macro_rules! assert_sorted_keys {
/// ///
/// Keys and values are expressions and converted into CBOR Keys and Values. /// Keys and values are expressions and converted into CBOR Keys and Values.
/// The syntax for these pairs is `key_expression => value_expression,`. /// The syntax for these pairs is `key_expression => value_expression,`.
/// Duplicate keys will lead to invalid CBOR, i.e. writing these values fails.
/// Keys do not have to be sorted. /// Keys do not have to be sorted.
/// ///
/// # Panics
///
/// You may not call this function with identical keys in its argument.
///
/// Example usage: /// Example usage:
/// ///
/// ```rust /// ```rust
@@ -168,7 +171,7 @@ macro_rules! cbor_map {
$( $(
_map.push(($key.into_cbor_value(), $value.into_cbor_value())); _map.push(($key.into_cbor_value(), $value.into_cbor_value()));
)* )*
$crate::values::Value::Map(_map) $crate::values::Value::map(_map)
} }
}; };
} }
@@ -214,7 +217,7 @@ macro_rules! cbor_map_options {
} }
} }
)* )*
$crate::values::Value::Map(_map) $crate::values::Value::map(_map)
} }
}; };
} }
@@ -223,7 +226,7 @@ macro_rules! cbor_map_options {
#[macro_export] #[macro_export]
macro_rules! cbor_map_collection { macro_rules! cbor_map_collection {
( $tree:expr ) => {{ ( $tree:expr ) => {{
$crate::values::Value::from($tree) $crate::values::Value::map($tree)
}}; }};
} }
@@ -250,7 +253,7 @@ macro_rules! cbor_array {
// The import is unused if the list is empty. // The import is unused if the list is empty.
#[allow(unused_imports)] #[allow(unused_imports)]
use $crate::values::IntoCborValue; use $crate::values::IntoCborValue;
$crate::values::Value::Array(vec![ $( $value.into_cbor_value(), )* ]) $crate::values::Value::array(vec![ $( $value.into_cbor_value(), )* ])
} }
}; };
} }
@@ -260,7 +263,7 @@ macro_rules! cbor_array {
macro_rules! cbor_array_vec { macro_rules! cbor_array_vec {
( $vec:expr ) => {{ ( $vec:expr ) => {{
use $crate::values::IntoCborValue; use $crate::values::IntoCborValue;
$crate::values::Value::Array($vec.into_iter().map(|x| x.into_cbor_value()).collect()) $crate::values::Value::array($vec.into_iter().map(|x| x.into_cbor_value()).collect())
}}; }};
} }
@@ -268,7 +271,7 @@ macro_rules! cbor_array_vec {
#[macro_export] #[macro_export]
macro_rules! cbor_true { macro_rules! cbor_true {
( ) => { ( ) => {
$crate::values::Value::Simple($crate::values::SimpleValue::TrueValue) $crate::values::Value::bool_value(true)
}; };
} }
@@ -276,7 +279,7 @@ macro_rules! cbor_true {
#[macro_export] #[macro_export]
macro_rules! cbor_false { macro_rules! cbor_false {
( ) => { ( ) => {
$crate::values::Value::Simple($crate::values::SimpleValue::FalseValue) $crate::values::Value::bool_value(false)
}; };
} }
@@ -284,7 +287,7 @@ macro_rules! cbor_false {
#[macro_export] #[macro_export]
macro_rules! cbor_null { macro_rules! cbor_null {
( ) => { ( ) => {
$crate::values::Value::Simple($crate::values::SimpleValue::NullValue) $crate::values::Value::null_value()
}; };
} }
@@ -292,7 +295,7 @@ macro_rules! cbor_null {
#[macro_export] #[macro_export]
macro_rules! cbor_undefined { macro_rules! cbor_undefined {
( ) => { ( ) => {
$crate::values::Value::Simple($crate::values::SimpleValue::Undefined) $crate::values::Value::undefined()
}; };
} }
@@ -308,7 +311,7 @@ macro_rules! cbor_bool {
#[macro_export] #[macro_export]
macro_rules! cbor_unsigned { macro_rules! cbor_unsigned {
( $x:expr ) => { ( $x:expr ) => {
$crate::values::Value::Unsigned($x) $crate::values::Value::unsigned($x as u64)
}; };
} }
@@ -316,7 +319,7 @@ macro_rules! cbor_unsigned {
#[macro_export] #[macro_export]
macro_rules! cbor_int { macro_rules! cbor_int {
( $x:expr ) => { ( $x:expr ) => {
$crate::values::Value::integer($x) $crate::values::Value::integer($x as i64)
}; };
} }
@@ -324,7 +327,7 @@ macro_rules! cbor_int {
#[macro_export] #[macro_export]
macro_rules! cbor_text { macro_rules! cbor_text {
( $x:expr ) => { ( $x:expr ) => {
$crate::values::Value::TextString($x.into()) $crate::values::Value::text_string($x.into())
}; };
} }
@@ -332,7 +335,7 @@ macro_rules! cbor_text {
#[macro_export] #[macro_export]
macro_rules! cbor_bytes { macro_rules! cbor_bytes {
( $x:expr ) => { ( $x:expr ) => {
$crate::values::Value::ByteString($x) $crate::values::Value::byte_string($x)
}; };
} }
@@ -340,7 +343,7 @@ macro_rules! cbor_bytes {
#[macro_export] #[macro_export]
macro_rules! cbor_tagged { macro_rules! cbor_tagged {
( $t:expr, $x: expr ) => { ( $t:expr, $x: expr ) => {
$crate::values::Value::Tag($t, ::alloc::boxed::Box::new($x)) $crate::values::Value::tag($t, $x)
}; };
} }
@@ -362,41 +365,41 @@ macro_rules! cbor_bytes_lit {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::super::values::{SimpleValue, Value}; use super::super::values::Value;
use alloc::string::String; use alloc::string::String;
use alloc::vec; use alloc::vec;
use alloc::vec::Vec; use alloc::vec::Vec;
#[test] #[test]
fn test_cbor_simple_values() { fn test_cbor_simple_values() {
assert_eq!(cbor_true!(), Value::Simple(SimpleValue::TrueValue)); assert_eq!(cbor_true!(), Value::bool_value(true));
assert_eq!(cbor_false!(), Value::Simple(SimpleValue::FalseValue)); assert_eq!(cbor_false!(), Value::bool_value(false));
assert_eq!(cbor_null!(), Value::Simple(SimpleValue::NullValue)); assert_eq!(cbor_null!(), Value::null_value());
assert_eq!(cbor_undefined!(), Value::Simple(SimpleValue::Undefined)); assert_eq!(cbor_undefined!(), Value::undefined());
} }
#[test] #[test]
fn test_cbor_bool() { fn test_cbor_bool() {
assert_eq!(cbor_bool!(true), Value::Simple(SimpleValue::TrueValue)); assert_eq!(cbor_bool!(true), Value::bool_value(true));
assert_eq!(cbor_bool!(false), Value::Simple(SimpleValue::FalseValue)); assert_eq!(cbor_bool!(false), Value::bool_value(false));
} }
#[test] #[test]
fn test_cbor_int_unsigned() { fn test_cbor_int_unsigned() {
assert_eq!(cbor_int!(0), Value::Unsigned(0)); assert_eq!(cbor_int!(0), Value::from(0));
assert_eq!(cbor_int!(1), Value::Unsigned(1)); assert_eq!(cbor_int!(1), Value::from(1));
assert_eq!(cbor_int!(123456), Value::Unsigned(123456)); assert_eq!(cbor_int!(123456), Value::from(123456));
assert_eq!( assert_eq!(
cbor_int!(core::i64::MAX), cbor_int!(core::i64::MAX),
Value::Unsigned(core::i64::MAX as u64) Value::from(core::i64::MAX as u64)
); );
} }
#[test] #[test]
fn test_cbor_int_negative() { fn test_cbor_int_negative() {
assert_eq!(cbor_int!(-1), Value::Negative(-1)); assert_eq!(cbor_int!(-1), Value::from(-1));
assert_eq!(cbor_int!(-123456), Value::Negative(-123456)); assert_eq!(cbor_int!(-123456), Value::from(-123456));
assert_eq!(cbor_int!(core::i64::MIN), Value::Negative(core::i64::MIN)); assert_eq!(cbor_int!(core::i64::MIN), Value::from(core::i64::MIN));
} }
#[test] #[test]
@@ -413,17 +416,17 @@ mod test {
core::i64::MAX, core::i64::MAX,
core::u64::MAX, core::u64::MAX,
]; ];
let b = Value::Array(vec![ let b = Value::array(vec![
Value::Negative(core::i64::MIN), Value::from(core::i64::MIN),
Value::Negative(core::i32::MIN as i64), Value::from(core::i32::MIN as i64),
Value::Negative(-123456), Value::from(-123456),
Value::Negative(-1), Value::from(-1),
Value::Unsigned(0), Value::from(0),
Value::Unsigned(1), Value::from(1),
Value::Unsigned(123456), Value::from(123456),
Value::Unsigned(core::i32::MAX as u64), Value::from(core::i32::MAX as u64),
Value::Unsigned(core::i64::MAX as u64), Value::from(core::i64::MAX as u64),
Value::Unsigned(core::u64::MAX), Value::from(core::u64::MAX),
]); ]);
assert_eq!(a, b); assert_eq!(a, b);
} }
@@ -442,22 +445,17 @@ mod test {
cbor_map! {}, cbor_map! {},
cbor_map! {2 => 3}, cbor_map! {2 => 3},
]; ];
let b = Value::Array(vec![ let b = Value::array(vec![
Value::Negative(-123), Value::from(-123),
Value::Unsigned(456), Value::from(456),
Value::Simple(SimpleValue::TrueValue), Value::bool_value(true),
Value::Simple(SimpleValue::NullValue), Value::null_value(),
Value::TextString(String::from("foo")), Value::from(String::from("foo")),
Value::ByteString(b"bar".to_vec()), Value::from(b"bar".to_vec()),
Value::Array(Vec::new()), Value::array(Vec::new()),
Value::Array(vec![Value::Unsigned(0), Value::Unsigned(1)]), Value::array(vec![Value::from(0), Value::from(1)]),
Value::Map(Vec::new()), Value::map(Vec::new()),
Value::Map( Value::map([(Value::from(2), Value::from(3))].iter().cloned().collect()),
[(Value::Unsigned(2), Value::Unsigned(3))]
.iter()
.cloned()
.collect(),
),
]); ]);
assert_eq!(a, b); assert_eq!(a, b);
} }
@@ -465,18 +463,18 @@ mod test {
#[test] #[test]
fn test_cbor_array_vec_empty() { fn test_cbor_array_vec_empty() {
let a = cbor_array_vec!(Vec::<bool>::new()); let a = cbor_array_vec!(Vec::<bool>::new());
let b = Value::Array(Vec::new()); let b = Value::array(Vec::new());
assert_eq!(a, b); assert_eq!(a, b);
} }
#[test] #[test]
fn test_cbor_array_vec_int() { fn test_cbor_array_vec_int() {
let a = cbor_array_vec!(vec![1, 2, 3, 4]); let a = cbor_array_vec!(vec![1, 2, 3, 4]);
let b = Value::Array(vec![ let b = Value::array(vec![
Value::Unsigned(1), Value::from(1),
Value::Unsigned(2), Value::from(2),
Value::Unsigned(3), Value::from(3),
Value::Unsigned(4), Value::from(4),
]); ]);
assert_eq!(a, b); assert_eq!(a, b);
} }
@@ -484,10 +482,10 @@ mod test {
#[test] #[test]
fn test_cbor_array_vec_text() { fn test_cbor_array_vec_text() {
let a = cbor_array_vec!(vec!["a", "b", "c"]); let a = cbor_array_vec!(vec!["a", "b", "c"]);
let b = Value::Array(vec![ let b = Value::array(vec![
Value::TextString(String::from("a")), Value::from(String::from("a")),
Value::TextString(String::from("b")), Value::from(String::from("b")),
Value::TextString(String::from("c")), Value::from(String::from("c")),
]); ]);
assert_eq!(a, b); assert_eq!(a, b);
} }
@@ -495,10 +493,10 @@ mod test {
#[test] #[test]
fn test_cbor_array_vec_bytes() { fn test_cbor_array_vec_bytes() {
let a = cbor_array_vec!(vec![b"a", b"b", b"c"]); let a = cbor_array_vec!(vec![b"a", b"b", b"c"]);
let b = Value::Array(vec![ let b = Value::array(vec![
Value::ByteString(b"a".to_vec()), Value::from(b"a".to_vec()),
Value::ByteString(b"b".to_vec()), Value::from(b"b".to_vec()),
Value::ByteString(b"c".to_vec()), Value::from(b"c".to_vec()),
]); ]);
assert_eq!(a, b); assert_eq!(a, b);
} }
@@ -506,46 +504,35 @@ mod test {
#[test] #[test]
fn test_cbor_map() { fn test_cbor_map() {
let a = cbor_map! { let a = cbor_map! {
-1 => -23,
4 => 56, 4 => 56,
"foo" => true,
b"bar" => cbor_null!(),
5 => "foo", 5 => "foo",
6 => b"bar", 6 => b"bar",
7 => cbor_array![], 7 => cbor_array![],
8 => cbor_array![0, 1], 8 => cbor_array![0, 1],
9 => cbor_map!{}, 9 => cbor_map!{},
10 => cbor_map!{2 => 3}, 10 => cbor_map!{2 => 3},
-1 => -23,
b"bar" => cbor_null!(),
"foo" => true,
}; };
let b = Value::Map( let b = Value::map(
[ [
(Value::Negative(-1), Value::Negative(-23)), (Value::from(4), Value::from(56)),
(Value::Unsigned(4), Value::Unsigned(56)), (Value::from(5), Value::from(String::from("foo"))),
(Value::from(6), Value::from(b"bar".to_vec())),
(Value::from(7), Value::array(Vec::new())),
( (
Value::TextString(String::from("foo")), Value::from(8),
Value::Simple(SimpleValue::TrueValue), Value::array(vec![Value::from(0), Value::from(1)]),
), ),
(Value::from(9), Value::map(Vec::new())),
( (
Value::ByteString(b"bar".to_vec()), Value::from(10),
Value::Simple(SimpleValue::NullValue), Value::map([(Value::from(2), Value::from(3))].iter().cloned().collect()),
),
(Value::Unsigned(5), Value::TextString(String::from("foo"))),
(Value::Unsigned(6), Value::ByteString(b"bar".to_vec())),
(Value::Unsigned(7), Value::Array(Vec::new())),
(
Value::Unsigned(8),
Value::Array(vec![Value::Unsigned(0), Value::Unsigned(1)]),
),
(Value::Unsigned(9), Value::Map(Vec::new())),
(
Value::Unsigned(10),
Value::Map(
[(Value::Unsigned(2), Value::Unsigned(3))]
.iter()
.cloned()
.collect(),
),
), ),
(Value::from(-1), Value::from(-23)),
(Value::from(b"bar".to_vec()), Value::null_value()),
(Value::from(String::from("foo")), Value::bool_value(true)),
] ]
.iter() .iter()
.cloned() .cloned()
@@ -557,54 +544,43 @@ mod test {
#[test] #[test]
fn test_cbor_map_options() { fn test_cbor_map_options() {
let a = cbor_map_options! { let a = cbor_map_options! {
-1 => -23,
4 => Some(56), 4 => Some(56),
11 => None::<String>,
"foo" => true,
12 => None::<&str>,
b"bar" => Some(cbor_null!()),
13 => None::<Vec<u8>>,
5 => "foo", 5 => "foo",
14 => None::<&[u8]>,
6 => Some(b"bar" as &[u8]), 6 => Some(b"bar" as &[u8]),
15 => None::<bool>,
7 => cbor_array![], 7 => cbor_array![],
16 => None::<i32>,
8 => Some(cbor_array![0, 1]), 8 => Some(cbor_array![0, 1]),
17 => None::<i64>,
9 => cbor_map!{}, 9 => cbor_map!{},
18 => None::<u64>,
10 => Some(cbor_map!{2 => 3}), 10 => Some(cbor_map!{2 => 3}),
11 => None::<String>,
12 => None::<&str>,
13 => None::<Vec<u8>>,
14 => None::<&[u8]>,
15 => None::<bool>,
16 => None::<i32>,
17 => None::<i64>,
18 => None::<u64>,
-1 => -23,
b"bar" => Some(cbor_null!()),
"foo" => true,
}; };
let b = Value::Map( let b = Value::map(
[ [
(Value::Negative(-1), Value::Negative(-23)), (Value::from(4), Value::from(56)),
(Value::Unsigned(4), Value::Unsigned(56)), (Value::from(5), Value::from(String::from("foo"))),
(Value::from(6), Value::from(b"bar".to_vec())),
(Value::from(7), Value::array(Vec::new())),
( (
Value::TextString(String::from("foo")), Value::from(8),
Value::Simple(SimpleValue::TrueValue), Value::array(vec![Value::from(0), Value::from(1)]),
), ),
(Value::from(9), Value::map(Vec::new())),
( (
Value::ByteString(b"bar".to_vec()), Value::from(10),
Value::Simple(SimpleValue::NullValue), Value::map([(Value::from(2), Value::from(3))].iter().cloned().collect()),
),
(Value::Unsigned(5), Value::TextString(String::from("foo"))),
(Value::Unsigned(6), Value::ByteString(b"bar".to_vec())),
(Value::Unsigned(7), Value::Array(Vec::new())),
(
Value::Unsigned(8),
Value::Array(vec![Value::Unsigned(0), Value::Unsigned(1)]),
),
(Value::Unsigned(9), Value::Map(Vec::new())),
(
Value::Unsigned(10),
Value::Map(
[(Value::Unsigned(2), Value::Unsigned(3))]
.iter()
.cloned()
.collect(),
),
), ),
(Value::from(-1), Value::from(-23)),
(Value::from(b"bar".to_vec()), Value::null_value()),
(Value::from(String::from("foo")), Value::bool_value(true)),
] ]
.iter() .iter()
.cloned() .cloned()
@@ -616,22 +592,19 @@ mod test {
#[test] #[test]
fn test_cbor_map_collection_empty() { fn test_cbor_map_collection_empty() {
let a = cbor_map_collection!(Vec::<(_, _)>::new()); let a = cbor_map_collection!(Vec::<(_, _)>::new());
let b = Value::Map(Vec::new()); let b = Value::map(Vec::new());
assert_eq!(a, b); assert_eq!(a, b);
} }
#[test] #[test]
fn test_cbor_map_collection_foo() { fn test_cbor_map_collection_foo() {
let a = cbor_map_collection!(vec![(Value::Unsigned(2), Value::Unsigned(3))]); let a = cbor_map_collection!(vec![(Value::from(2), Value::from(3))]);
let b = Value::Map(vec![(Value::Unsigned(2), Value::Unsigned(3))]); let b = Value::map(vec![(Value::from(2), Value::from(3))]);
assert_eq!(a, b); assert_eq!(a, b);
} }
fn extract_map(cbor_value: Value) -> Vec<(Value, Value)> { fn extract_map(cbor_value: Value) -> Vec<(Value, Value)> {
match cbor_value { cbor_value.extract_map().unwrap()
Value::Map(map) => map,
_ => panic!("Expected CBOR map."),
}
} }
#[test] #[test]
@@ -721,4 +694,22 @@ mod test {
assert_eq!(x4, Some(cbor_unsigned!(40))); assert_eq!(x4, Some(cbor_unsigned!(40)));
assert_eq!(x5, None); assert_eq!(x5, None);
} }
#[test]
fn test_destructure_unsorted_cbor_map() {
let map = cbor_map! {
2 => 20,
1 => 10,
};
destructure_cbor_map! {
let {
1 => x1,
2 => x2,
} = extract_map(map);
}
assert_eq!(x1, Some(cbor_unsigned!(10)));
assert_eq!(x2, Some(cbor_unsigned!(20)));
}
} }

View File

@@ -14,7 +14,7 @@
//! Functionality for deserializing CBOR data into values. //! Functionality for deserializing CBOR data into values.
use super::values::{Constants, SimpleValue, Value}; use super::values::{Constants, SimpleValue, Value, ValueImpl};
use crate::{ use crate::{
cbor_array_vec, cbor_bytes_lit, cbor_map_collection, cbor_tagged, cbor_text, cbor_unsigned, cbor_array_vec, cbor_bytes_lit, cbor_map_collection, cbor_tagged, cbor_text, cbor_unsigned,
}; };
@@ -144,7 +144,7 @@ impl<'a> Reader<'a> {
if signed_size < 0 { if signed_size < 0 {
Err(DecoderError::OutOfRangeIntegerValue) Err(DecoderError::OutOfRangeIntegerValue)
} else { } else {
Ok(Value::Negative(-(size_value as i64) - 1)) Ok(Value(ValueImpl::Negative(-(size_value as i64) - 1)))
} }
} }
@@ -221,7 +221,7 @@ impl<'a> Reader<'a> {
return Err(DecoderError::UnsupportedFloatingPointValue); return Err(DecoderError::UnsupportedFloatingPointValue);
} }
match SimpleValue::from_integer(size_value) { match SimpleValue::from_integer(size_value) {
Some(simple_value) => Ok(Value::Simple(simple_value)), Some(simple_value) => Ok(Value(ValueImpl::Simple(simple_value))),
None => Err(DecoderError::UnsupportedSimpleValue), None => Err(DecoderError::UnsupportedSimpleValue),
} }
} }

View File

@@ -19,9 +19,13 @@ use alloc::string::{String, ToString};
use alloc::vec::Vec; use alloc::vec::Vec;
use core::cmp::Ordering; use core::cmp::Ordering;
/// The CBOR data structure.
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Value(pub(crate) ValueImpl);
/// Possible CBOR values. /// Possible CBOR values.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum Value { pub(crate) enum ValueImpl {
/// Unsigned integer value (uint). /// Unsigned integer value (uint).
Unsigned(u64), Unsigned(u64),
/// Signed integer value (nint). Only 63 bits of information are used here. /// Signed integer value (nint). Only 63 bits of information are used here.
@@ -42,7 +46,7 @@ pub enum Value {
/// Specific simple CBOR values. /// Specific simple CBOR values.
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum SimpleValue { pub(crate) enum SimpleValue {
FalseValue = 20, FalseValue = 20,
TrueValue = 21, TrueValue = 21,
NullValue = 22, NullValue = 22,
@@ -71,45 +75,177 @@ impl Constants {
} }
impl Value { impl Value {
/// Creates a CBOR unsigned value.
pub fn unsigned(int: u64) -> Value {
Value(ValueImpl::Unsigned(int))
}
/// Create an appropriate CBOR integer value (uint/nint). /// Create an appropriate CBOR integer value (uint/nint).
/// For simplicity, this only takes i64. Construct directly for the last bit. /// For simplicity, this only takes i64. Construct directly for the last bit.
pub fn integer(int: i64) -> Value { pub fn integer(int: i64) -> Value {
if int >= 0 { if int >= 0 {
Value::Unsigned(int as u64) Value(ValueImpl::Unsigned(int as u64))
} else { } else {
Value::Negative(int) Value(ValueImpl::Negative(int))
} }
} }
/// Creates a CBOR byte string value.
pub fn byte_string(bytes: Vec<u8>) -> Value {
Value(ValueImpl::ByteString(bytes))
}
/// Creates a CBOR text string value.
pub fn text_string(text: String) -> Value {
Value(ValueImpl::TextString(text))
}
/// Create a CBOR array value.
pub fn array(a: Vec<Value>) -> Value {
Value(ValueImpl::Array(a))
}
/// Create a CBOR map value.
///
/// Keys do not have to be sorted.
///
/// # Panics
///
/// You may not call this function with identical keys in its argument.
pub fn map(mut m: Vec<(Value, Value)>) -> Value {
m.sort_by(|a, b| a.0.cmp(&b.0));
let map_len = m.len();
m.dedup_by(|a, b| a.0.eq(&b.0));
if map_len != m.len() {
panic!();
}
Value(ValueImpl::Map(m))
}
/// Create a CBOR tagged value.
pub fn tag(int: u64, value: Value) -> Value {
Value(ValueImpl::Tag(int, Box::new(value)))
}
/// Create a CBOR boolean simple value. /// Create a CBOR boolean simple value.
pub fn bool_value(b: bool) -> Value { pub fn bool_value(b: bool) -> Value {
if b { if b {
Value::Simple(SimpleValue::TrueValue) Value(ValueImpl::Simple(SimpleValue::TrueValue))
} else { } else {
Value::Simple(SimpleValue::FalseValue) Value(ValueImpl::Simple(SimpleValue::FalseValue))
} }
} }
/// Return the major type for the [`Value`]. /// Creates a null value.
pub fn type_label(&self) -> u8 { pub fn null_value() -> Value {
// TODO use enum discriminant instead when stable Value(ValueImpl::Simple(SimpleValue::NullValue))
// https://github.com/rust-lang/rust/issues/60553 }
/// Creates an undefined value.
pub fn undefined() -> Value {
Value(ValueImpl::Simple(SimpleValue::Undefined))
}
pub fn extract_unsigned(self) -> Option<u64> {
match self { match self {
Value::Unsigned(_) => 0, Value(ValueImpl::Unsigned(unsigned)) => Some(unsigned),
Value::Negative(_) => 1, _ => None,
Value::ByteString(_) => 2, }
Value::TextString(_) => 3, }
Value::Array(_) => 4,
Value::Map(_) => 5, pub fn extract_integer(self) -> Option<i64> {
Value::Tag(_, _) => 6, match self {
Value::Simple(_) => 7, Value(ValueImpl::Unsigned(unsigned)) => {
if unsigned <= core::i64::MAX as u64 {
Some(unsigned as i64)
} else {
None
}
}
Value(ValueImpl::Negative(signed)) => Some(signed),
_ => None,
}
}
pub fn extract_byte_string(self) -> Option<Vec<u8>> {
match self {
Value(ValueImpl::ByteString(byte_string)) => Some(byte_string),
_ => None,
}
}
pub fn extract_text_string(self) -> Option<String> {
match self {
Value(ValueImpl::TextString(text_string)) => Some(text_string),
_ => None,
}
}
pub fn extract_array(self) -> Option<Vec<Value>> {
match self {
Value(ValueImpl::Array(array)) => Some(array),
_ => None,
}
}
pub fn extract_map(self) -> Option<Vec<(Value, Value)>> {
match self {
Value(ValueImpl::Map(map)) => Some(map),
_ => None,
}
}
pub fn extract_tag(self) -> Option<(u64, Value)> {
match self {
Value(ValueImpl::Tag(tag, value)) => Some((tag, *value)),
_ => None,
}
}
pub fn extract_bool(self) -> Option<bool> {
match self {
Value(ValueImpl::Simple(SimpleValue::FalseValue)) => Some(false),
Value(ValueImpl::Simple(SimpleValue::TrueValue)) => Some(true),
_ => None,
}
}
pub fn extract_null(self) -> Option<()> {
match self {
Value(ValueImpl::Simple(SimpleValue::NullValue)) => Some(()),
_ => None,
}
}
pub fn extract_undefined(self) -> Option<()> {
match self {
Value(ValueImpl::Simple(SimpleValue::Undefined)) => Some(()),
_ => None,
} }
} }
} }
impl Ord for Value { impl ValueImpl {
fn cmp(&self, other: &Value) -> Ordering { /// Return the major type for the [`ValueImpl`].
use super::values::Value::{ pub fn type_label(&self) -> u8 {
// TODO use enum discriminant instead when stable
// https://github.com/rust-lang/rust/issues/60553
match self {
ValueImpl::Unsigned(_) => 0,
ValueImpl::Negative(_) => 1,
ValueImpl::ByteString(_) => 2,
ValueImpl::TextString(_) => 3,
ValueImpl::Array(_) => 4,
ValueImpl::Map(_) => 5,
ValueImpl::Tag(_, _) => 6,
ValueImpl::Simple(_) => 7,
}
}
}
impl Ord for ValueImpl {
fn cmp(&self, other: &ValueImpl) -> Ordering {
use super::values::ValueImpl::{
Array, ByteString, Map, Negative, Simple, Tag, TextString, Unsigned, Array, ByteString, Map, Negative, Simple, Tag, TextString, Unsigned,
}; };
let self_type_value = self.type_label(); let self_type_value = self.type_label();
@@ -156,16 +292,16 @@ impl Ord for Value {
} }
} }
impl PartialOrd for Value { impl PartialOrd for ValueImpl {
fn partial_cmp(&self, other: &Value) -> Option<Ordering> { fn partial_cmp(&self, other: &ValueImpl) -> Option<Ordering> {
Some(self.cmp(other)) Some(self.cmp(other))
} }
} }
impl Eq for Value {} impl Eq for ValueImpl {}
impl PartialEq for Value { impl PartialEq for ValueImpl {
fn eq(&self, other: &Value) -> bool { fn eq(&self, other: &ValueImpl) -> bool {
self.cmp(other) == Ordering::Equal self.cmp(other) == Ordering::Equal
} }
} }
@@ -184,8 +320,26 @@ impl SimpleValue {
} }
impl From<u64> for Value { impl From<u64> for Value {
fn from(unsigned: u64) -> Self { fn from(u: u64) -> Self {
Value::Unsigned(unsigned) Value::unsigned(u)
}
}
impl From<u32> for Value {
fn from(u: u32) -> Self {
Value::unsigned(u as u64)
}
}
impl From<u16> for Value {
fn from(u: u16) -> Self {
Value::unsigned(u as u64)
}
}
impl From<u8> for Value {
fn from(u: u8) -> Self {
Value::unsigned(u as u64)
} }
} }
@@ -201,39 +355,57 @@ impl From<i32> for Value {
} }
} }
impl From<i16> for Value {
fn from(i: i16) -> Self {
Value::integer(i as i64)
}
}
impl From<i8> for Value {
fn from(i: i8) -> Self {
Value::integer(i as i64)
}
}
impl From<Vec<u8>> for Value { impl From<Vec<u8>> for Value {
fn from(bytes: Vec<u8>) -> Self { fn from(bytes: Vec<u8>) -> Self {
Value::ByteString(bytes) Value(ValueImpl::ByteString(bytes))
} }
} }
impl From<&[u8]> for Value { impl From<&[u8]> for Value {
fn from(bytes: &[u8]) -> Self { fn from(bytes: &[u8]) -> Self {
Value::ByteString(bytes.to_vec()) Value(ValueImpl::ByteString(bytes.to_vec()))
}
}
impl From<&[u8; 0]> for Value {
fn from(bytes: &[u8; 0]) -> Self {
Value(ValueImpl::ByteString(bytes.to_vec()))
} }
} }
impl From<String> for Value { impl From<String> for Value {
fn from(text: String) -> Self { fn from(text: String) -> Self {
Value::TextString(text) Value(ValueImpl::TextString(text))
} }
} }
impl From<&str> for Value { impl From<&str> for Value {
fn from(text: &str) -> Self { fn from(text: &str) -> Self {
Value::TextString(text.to_string()) Value(ValueImpl::TextString(text.to_string()))
} }
} }
impl From<Vec<Value>> for Value { impl From<Vec<Value>> for Value {
fn from(array: Vec<Value>) -> Self { fn from(array: Vec<Value>) -> Self {
Value::Array(array) Value(ValueImpl::Array(array))
} }
} }
impl From<Vec<(Value, Value)>> for Value { impl From<Vec<(Value, Value)>> for Value {
fn from(map: Vec<(Value, Value)>) -> Self { fn from(map: Vec<(Value, Value)>) -> Self {
Value::Map(map) Value::map(map)
} }
} }
@@ -285,9 +457,209 @@ where
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
use crate::{cbor_array, cbor_bool, cbor_bytes, cbor_int, cbor_map, cbor_tagged, cbor_text}; use crate::{
cbor_array, cbor_bool, cbor_bytes, cbor_bytes_lit, cbor_int, cbor_map, cbor_null,
cbor_tagged, cbor_text, cbor_undefined, cbor_unsigned,
};
use alloc::vec; use alloc::vec;
#[test]
#[should_panic]
fn test_duplicate_map_key() {
let _map = cbor_map! {
0 => "a",
-1 => "c",
b"a" => "e",
"c" => "g",
0 => "b",
};
}
#[test]
fn test_extract_unsigned() {
assert_eq!(cbor_int!(1).extract_unsigned(), Some(1));
assert_eq!(cbor_int!(-1).extract_unsigned(), None);
assert_eq!(cbor_bytes!(vec![]).extract_unsigned(), None);
assert_eq!(cbor_text!("").extract_unsigned(), None);
assert_eq!(cbor_array![].extract_unsigned(), None);
assert_eq!(cbor_map! {}.extract_unsigned(), None);
assert_eq!(cbor_tagged!(1, cbor_text!("s")).extract_unsigned(), None);
assert_eq!(cbor_bool!(false).extract_unsigned(), None);
}
#[test]
fn test_extract_unsigned_limits() {
assert_eq!(
cbor_unsigned!(core::u64::MAX).extract_unsigned(),
Some(core::u64::MAX)
);
assert_eq!(
cbor_unsigned!((core::i64::MAX as u64) + 1).extract_unsigned(),
Some((core::i64::MAX as u64) + 1)
);
assert_eq!(
cbor_int!(core::i64::MAX).extract_unsigned(),
Some(core::i64::MAX as u64)
);
assert_eq!(cbor_int!(123).extract_unsigned(), Some(123));
assert_eq!(cbor_int!(0).extract_unsigned(), Some(0));
assert_eq!(cbor_int!(-123).extract_unsigned(), None);
assert_eq!(cbor_int!(core::i64::MIN).extract_unsigned(), None);
}
#[test]
fn test_extract_integer() {
assert_eq!(cbor_int!(1).extract_integer(), Some(1));
assert_eq!(cbor_int!(-1).extract_integer(), Some(-1));
assert_eq!(cbor_bytes!(vec![]).extract_integer(), None);
assert_eq!(cbor_text!("").extract_integer(), None);
assert_eq!(cbor_array![].extract_integer(), None);
assert_eq!(cbor_map! {}.extract_integer(), None);
assert_eq!(cbor_tagged!(1, cbor_text!("s")).extract_integer(), None);
assert_eq!(cbor_bool!(false).extract_integer(), None);
}
#[test]
fn test_extract_integer_limits() {
assert_eq!(cbor_unsigned!(core::u64::MAX).extract_integer(), None);
assert_eq!(
cbor_unsigned!((core::i64::MAX as u64) + 1).extract_integer(),
None
);
assert_eq!(
cbor_int!(core::i64::MAX).extract_integer(),
Some(core::i64::MAX)
);
assert_eq!(cbor_int!(123).extract_integer(), Some(123));
assert_eq!(cbor_int!(0).extract_integer(), Some(0));
assert_eq!(cbor_int!(-123).extract_integer(), Some(-123));
assert_eq!(
cbor_int!(core::i64::MIN).extract_integer(),
Some(core::i64::MIN)
);
}
#[test]
fn test_extract_byte_string() {
assert_eq!(cbor_int!(1).extract_byte_string(), None);
assert_eq!(cbor_int!(-1).extract_byte_string(), None);
assert_eq!(cbor_bytes!(vec![]).extract_byte_string(), Some(Vec::new()));
assert_eq!(
cbor_bytes_lit!(b"bar").extract_byte_string(),
Some(b"bar".to_vec())
);
assert_eq!(cbor_text!("").extract_byte_string(), None);
assert_eq!(cbor_array![].extract_byte_string(), None);
assert_eq!(cbor_map! {}.extract_byte_string(), None);
assert_eq!(cbor_tagged!(1, cbor_text!("s")).extract_byte_string(), None);
assert_eq!(cbor_bool!(false).extract_byte_string(), None);
}
#[test]
fn test_extract_text_string() {
assert_eq!(cbor_int!(1).extract_text_string(), None);
assert_eq!(cbor_int!(-1).extract_text_string(), None);
assert_eq!(cbor_bytes!(vec![]).extract_text_string(), None);
assert_eq!(cbor_text!("").extract_text_string(), Some(String::new()));
assert_eq!(cbor_text!("s").extract_text_string(), Some("s".to_string()));
assert_eq!(cbor_array![].extract_text_string(), None);
assert_eq!(cbor_map! {}.extract_text_string(), None);
assert_eq!(cbor_tagged!(1, cbor_text!("s")).extract_text_string(), None);
assert_eq!(cbor_bool!(false).extract_text_string(), None);
}
#[test]
fn test_extract_array() {
assert_eq!(cbor_int!(1).extract_array(), None);
assert_eq!(cbor_int!(-1).extract_array(), None);
assert_eq!(cbor_bytes!(vec![]).extract_array(), None);
assert_eq!(cbor_text!("").extract_array(), None);
assert_eq!(cbor_array![].extract_array(), Some(Vec::new()));
assert_eq!(
cbor_array![cbor_int!(1)].extract_array(),
Some(vec![cbor_int!(1)])
);
assert_eq!(cbor_map! {}.extract_array(), None);
assert_eq!(cbor_tagged!(1, cbor_text!("s")).extract_array(), None);
assert_eq!(cbor_bool!(false).extract_array(), None);
}
#[test]
fn test_extract_map() {
assert_eq!(cbor_int!(1).extract_map(), None);
assert_eq!(cbor_int!(-1).extract_map(), None);
assert_eq!(cbor_bytes!(vec![]).extract_map(), None);
assert_eq!(cbor_text!("").extract_map(), None);
assert_eq!(cbor_array![].extract_map(), None);
assert_eq!(cbor_map! {}.extract_map(), Some(Vec::new()));
assert_eq!(
cbor_map! {0 => 1}.extract_map(),
Some(vec![(cbor_int!(0), cbor_int!(1))])
);
assert_eq!(cbor_tagged!(1, cbor_text!("s")).extract_map(), None);
assert_eq!(cbor_bool!(false).extract_map(), None);
}
#[test]
fn test_extract_tag() {
assert_eq!(cbor_int!(1).extract_tag(), None);
assert_eq!(cbor_int!(-1).extract_tag(), None);
assert_eq!(cbor_bytes!(vec![]).extract_tag(), None);
assert_eq!(cbor_text!("").extract_tag(), None);
assert_eq!(cbor_array![].extract_tag(), None);
assert_eq!(cbor_map! {}.extract_tag(), None);
assert_eq!(
cbor_tagged!(1, cbor_text!("s")).extract_tag(),
Some((1, cbor_text!("s")))
);
assert_eq!(cbor_bool!(false).extract_tag(), None);
}
#[test]
fn test_extract_bool() {
assert_eq!(cbor_int!(1).extract_bool(), None);
assert_eq!(cbor_int!(-1).extract_bool(), None);
assert_eq!(cbor_bytes!(vec![]).extract_bool(), None);
assert_eq!(cbor_text!("").extract_bool(), None);
assert_eq!(cbor_array![].extract_bool(), None);
assert_eq!(cbor_map! {}.extract_bool(), None);
assert_eq!(cbor_tagged!(1, cbor_text!("s")).extract_bool(), None);
assert_eq!(cbor_bool!(false).extract_bool(), Some(false));
assert_eq!(cbor_bool!(true).extract_bool(), Some(true));
assert_eq!(cbor_null!().extract_bool(), None);
assert_eq!(cbor_undefined!().extract_bool(), None);
}
#[test]
fn test_extract_null() {
assert_eq!(cbor_int!(1).extract_null(), None);
assert_eq!(cbor_int!(-1).extract_null(), None);
assert_eq!(cbor_bytes!(vec![]).extract_null(), None);
assert_eq!(cbor_text!("").extract_null(), None);
assert_eq!(cbor_array![].extract_null(), None);
assert_eq!(cbor_map! {}.extract_null(), None);
assert_eq!(cbor_tagged!(1, cbor_text!("s")).extract_null(), None);
assert_eq!(cbor_bool!(false).extract_null(), None);
assert_eq!(cbor_bool!(true).extract_null(), None);
assert_eq!(cbor_null!().extract_null(), Some(()));
assert_eq!(cbor_undefined!().extract_null(), None);
}
#[test]
fn test_extract_undefined() {
assert_eq!(cbor_int!(1).extract_undefined(), None);
assert_eq!(cbor_int!(-1).extract_undefined(), None);
assert_eq!(cbor_bytes!(vec![]).extract_undefined(), None);
assert_eq!(cbor_text!("").extract_undefined(), None);
assert_eq!(cbor_array![].extract_undefined(), None);
assert_eq!(cbor_map! {}.extract_undefined(), None);
assert_eq!(cbor_tagged!(1, cbor_text!("s")).extract_undefined(), None);
assert_eq!(cbor_bool!(false).extract_undefined(), None);
assert_eq!(cbor_bool!(true).extract_undefined(), None);
assert_eq!(cbor_null!().extract_undefined(), None);
assert_eq!(cbor_undefined!().extract_undefined(), Some(()));
}
#[test] #[test]
fn test_value_ordering() { fn test_value_ordering() {
assert!(cbor_int!(0) < cbor_int!(23)); assert!(cbor_int!(0) < cbor_int!(23));
@@ -329,12 +701,12 @@ mod test {
assert!(cbor_map! {"" => 0} < cbor_map! {cbor_array![] => 0}); assert!(cbor_map! {"" => 0} < cbor_map! {cbor_array![] => 0});
assert!(cbor_map! {cbor_array![] => 0} < cbor_map! {cbor_map!{} => 0}); assert!(cbor_map! {cbor_array![] => 0} < cbor_map! {cbor_map!{} => 0});
assert!(cbor_map! {cbor_map!{} => 0} < cbor_map! {false => 0}); assert!(cbor_map! {cbor_map!{} => 0} < cbor_map! {false => 0});
assert!(cbor_map! {false => 0} < cbor_map! {0 => 0, 0 => 0}); assert!(cbor_map! {false => 0} < cbor_map! {0 => 0, 1 => 0});
assert!(cbor_map! {0 => 0} < cbor_tagged!(2, cbor_int!(0))); assert!(cbor_map! {0 => 0} < cbor_tagged!(2, cbor_int!(0)));
assert!(cbor_map! {0 => 0, 0 => 0} < cbor_bool!(false)); assert!(cbor_map! {0 => 0, 1 => 0} < cbor_bool!(false));
assert!(cbor_bool!(false) < cbor_bool!(true)); assert!(cbor_bool!(false) < cbor_bool!(true));
assert!(cbor_bool!(true) < Value::Simple(SimpleValue::NullValue)); assert!(cbor_bool!(true) < cbor_null!());
assert!(Value::Simple(SimpleValue::NullValue) < Value::Simple(SimpleValue::Undefined)); assert!(cbor_null!() < cbor_undefined!());
assert!(cbor_tagged!(1, cbor_text!("s")) < cbor_tagged!(2, cbor_int!(0))); assert!(cbor_tagged!(1, cbor_text!("s")) < cbor_tagged!(2, cbor_int!(0)));
assert!(cbor_int!(1) < cbor_int!(-1)); assert!(cbor_int!(1) < cbor_int!(-1));
assert!(cbor_int!(1) < cbor_bytes!(vec![0x00])); assert!(cbor_int!(1) < cbor_bytes!(vec![0x00]));

View File

@@ -14,7 +14,7 @@
//! Functionality for serializing CBOR values into bytes. //! Functionality for serializing CBOR values into bytes.
use super::values::{Constants, Value}; use super::values::{Constants, Value, ValueImpl};
use alloc::vec::Vec; use alloc::vec::Vec;
/// Possible errors from a serialization operation. /// Possible errors from a serialization operation.
@@ -60,42 +60,36 @@ impl<'a> Writer<'a> {
if remaining_depth.map_or(false, |d| d < 0) { if remaining_depth.map_or(false, |d| d < 0) {
return Err(EncoderError::TooMuchNesting); return Err(EncoderError::TooMuchNesting);
} }
let type_label = value.type_label(); let type_label = value.0.type_label();
match value { match value.0 {
Value::Unsigned(unsigned) => self.start_item(type_label, unsigned), ValueImpl::Unsigned(unsigned) => self.start_item(type_label, unsigned),
Value::Negative(negative) => self.start_item(type_label, -(negative + 1) as u64), ValueImpl::Negative(negative) => self.start_item(type_label, -(negative + 1) as u64),
Value::ByteString(byte_string) => { ValueImpl::ByteString(byte_string) => {
self.start_item(type_label, byte_string.len() as u64); self.start_item(type_label, byte_string.len() as u64);
self.encoded_cbor.extend(byte_string); self.encoded_cbor.extend(byte_string);
} }
Value::TextString(text_string) => { ValueImpl::TextString(text_string) => {
self.start_item(type_label, text_string.len() as u64); self.start_item(type_label, text_string.len() as u64);
self.encoded_cbor.extend(text_string.into_bytes()); self.encoded_cbor.extend(text_string.into_bytes());
} }
Value::Array(array) => { ValueImpl::Array(array) => {
self.start_item(type_label, array.len() as u64); self.start_item(type_label, array.len() as u64);
for el in array { for el in array {
self.encode_cbor(el, remaining_depth.map(|d| d - 1))?; self.encode_cbor(el, remaining_depth.map(|d| d - 1))?;
} }
} }
Value::Map(mut map) => { ValueImpl::Map(map) => {
map.sort_by(|a, b| a.0.cmp(&b.0)); self.start_item(type_label, map.len() as u64);
let map_len = map.len();
map.dedup_by(|a, b| a.0.eq(&b.0));
if map_len != map.len() {
return Err(EncoderError::DuplicateMapKey);
}
self.start_item(type_label, map_len as u64);
for (k, v) in map { for (k, v) in map {
self.encode_cbor(k, remaining_depth.map(|d| d - 1))?; self.encode_cbor(k, remaining_depth.map(|d| d - 1))?;
self.encode_cbor(v, remaining_depth.map(|d| d - 1))?; self.encode_cbor(v, remaining_depth.map(|d| d - 1))?;
} }
} }
Value::Tag(tag, inner_value) => { ValueImpl::Tag(tag, inner_value) => {
self.start_item(type_label, tag); self.start_item(type_label, tag);
self.encode_cbor(*inner_value, remaining_depth.map(|d| d - 1))?; self.encode_cbor(*inner_value, remaining_depth.map(|d| d - 1))?;
} }
Value::Simple(simple_value) => self.start_item(type_label, simple_value as u64), ValueImpl::Simple(simple_value) => self.start_item(type_label, simple_value as u64),
} }
Ok(()) Ok(())
} }
@@ -342,42 +336,6 @@ mod test {
assert_eq!(write_return(sorted_map), write_return(unsorted_map)); assert_eq!(write_return(sorted_map), write_return(unsorted_map));
} }
#[test]
fn test_write_map_duplicates() {
let duplicate0 = cbor_map! {
0 => "a",
-1 => "c",
b"a" => "e",
"c" => "g",
0 => "b",
};
assert_eq!(write_return(duplicate0), None);
let duplicate1 = cbor_map! {
0 => "a",
-1 => "c",
b"a" => "e",
"c" => "g",
-1 => "d",
};
assert_eq!(write_return(duplicate1), None);
let duplicate2 = cbor_map! {
0 => "a",
-1 => "c",
b"a" => "e",
"c" => "g",
b"a" => "f",
};
assert_eq!(write_return(duplicate2), None);
let duplicate3 = cbor_map! {
0 => "a",
-1 => "c",
b"a" => "e",
"c" => "g",
"c" => "h",
};
assert_eq!(write_return(duplicate3), None);
}
#[test] #[test]
fn test_write_map_with_array() { fn test_write_map_with_array() {
let value_map = cbor_map! { let value_map = cbor_map! {

View File

@@ -1,503 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "0.7.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e"
dependencies = [
"memchr",
]
[[package]]
name = "arrayref"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
[[package]]
name = "autocfg"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0dde43e75fd43e8a1bf86103336bc699aa8d17ad1be60c76c0bdfd4828e19b78"
dependencies = [
"autocfg 1.1.0",
]
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bumpalo"
version = "3.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c"
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cc"
version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cloudabi"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
dependencies = [
"bitflags",
]
[[package]]
name = "crypto"
version = "0.1.0"
dependencies = [
"arrayref",
"byteorder",
"hex",
"regex",
"ring",
"rng256",
"serde",
"serde_json",
"subtle",
"untrusted",
]
[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
[[package]]
name = "hex"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77"
[[package]]
name = "itoa"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
[[package]]
name = "js-sys"
version = "0.3.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397"
dependencies = [
"wasm-bindgen",
]
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.133"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0f80d65747a3e43d1596c7c5492d95d5edddaabd45a7fcdb02b95f644164966"
[[package]]
name = "libtock_codegen"
version = "0.1.0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "libtock_core"
version = "0.1.0"
dependencies = [
"libtock_codegen",
]
[[package]]
name = "libtock_drivers"
version = "0.1.0"
dependencies = [
"libtock_core",
]
[[package]]
name = "log"
version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [
"cfg-if",
]
[[package]]
name = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "once_cell"
version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0"
[[package]]
name = "proc-macro2"
version = "1.0.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
dependencies = [
"autocfg 0.1.8",
"libc",
"rand_chacha",
"rand_core 0.4.2",
"rand_hc",
"rand_isaac",
"rand_jitter",
"rand_os",
"rand_pcg",
"rand_xorshift",
"winapi",
]
[[package]]
name = "rand_chacha"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
dependencies = [
"autocfg 0.1.8",
"rand_core 0.3.1",
]
[[package]]
name = "rand_core"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
dependencies = [
"rand_core 0.4.2",
]
[[package]]
name = "rand_core"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
[[package]]
name = "rand_hc"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "rand_isaac"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "rand_jitter"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b"
dependencies = [
"libc",
"rand_core 0.4.2",
"winapi",
]
[[package]]
name = "rand_os"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
dependencies = [
"cloudabi",
"fuchsia-cprng",
"libc",
"rand_core 0.4.2",
"rdrand",
"winapi",
]
[[package]]
name = "rand_pcg"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
dependencies = [
"autocfg 0.1.8",
"rand_core 0.4.2",
]
[[package]]
name = "rand_xorshift"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "rdrand"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "regex"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
[[package]]
name = "ring"
version = "0.16.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc"
dependencies = [
"cc",
"libc",
"once_cell",
"spin",
"untrusted",
"web-sys",
"winapi",
]
[[package]]
name = "rng256"
version = "0.1.0"
dependencies = [
"arrayref",
"libtock_drivers",
"rand",
]
[[package]]
name = "ryu"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
[[package]]
name = "serde"
version = "1.0.144"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.144"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e466864e431129c7e0d3476b92f20458e5879919a0596c6472738d9fa2d342f8"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "spin"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]]
name = "subtle"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
[[package]]
name = "syn"
version = "1.0.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52205623b1b0f064a4e71182c3b18ae902267282930c6d5462c91b859668426e"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd"
[[package]]
name = "untrusted"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]]
name = "wasm-bindgen"
version = "0.2.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4"
dependencies = [
"bumpalo",
"lazy_static",
"log",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b"
dependencies = [
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744"
[[package]]
name = "web-sys"
version = "0.3.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b17e741662c70c8bd24ac5c5b18de314a2c26c32bf8346ee1e6f53de919c283"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

View File

@@ -10,10 +10,8 @@ license = "Apache-2.0"
edition = "2018" edition = "2018"
[dependencies] [dependencies]
rng256 = { path = "../rng256" }
arrayref = "0.3.6" arrayref = "0.3.6"
subtle = { version = "2.2.3", default-features = false, features = ["nightly"] } subtle = { version = "2.2.3", default-features = false, features = ["nightly"] }
dilithium = { path = "../../third_party/dilithium" }
byteorder = { version = "1", default-features = false } byteorder = { version = "1", default-features = false }
hex = { version = "0.3.2", default-features = false, optional = true } hex = { version = "0.3.2", default-features = false, optional = true }
ring = { version = "0.16.11", optional = true } ring = { version = "0.16.11", optional = true }
@@ -21,7 +19,8 @@ untrusted = { version = "0.7.0", optional = true }
serde = { version = "1.0", optional = true, features = ["derive"] } serde = { version = "1.0", optional = true, features = ["derive"] }
serde_json = { version = "=1.0.69", optional = true } serde_json = { version = "=1.0.69", optional = true }
regex = { version = "1", optional = true } regex = { version = "1", optional = true }
rand_core = "0.6.4"
zeroize = { version = "1.5.7", features = ["derive"] }
[features] [features]
std = ["hex", "ring", "rng256/std", "untrusted", "serde", "serde_json", "regex"] std = ["hex", "ring", "untrusted", "serde", "serde_json", "regex", "rand_core/getrandom"]
with_ctap1 = []

View File

@@ -12,18 +12,29 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//! A portable and naive textbook implementation of AES-256
use super::util::{xor_block_16, Block16}; use super::util::{xor_block_16, Block16};
use arrayref::{array_mut_ref, array_ref}; use arrayref::{array_mut_ref, array_ref};
use zeroize::Zeroize;
/** A portable and naive textbook implementation of AES-256 **/
type Word = [u8; 4]; type Word = [u8; 4];
/** This structure caches the round keys, to avoid re-computing the key schedule for each block. **/ /// Encryption key for AES256.
///
/// Never call zeroize explicitly, to not invalidate any invariants.
#[derive(Zeroize)]
pub struct EncryptionKey { pub struct EncryptionKey {
// This structure caches the round keys, to avoid re-computing the key schedule for each block.
enc_round_keys: [Block16; 15], enc_round_keys: [Block16; 15],
} }
/// Decryption key for AES256.
///
/// Never call zeroize explicitly, to not invalidate any invariants.
#[derive(Zeroize)]
pub struct DecryptionKey { pub struct DecryptionKey {
// This structure caches the round keys, to avoid re-computing the key schedule for each block.
dec_round_keys: [Block16; 15], dec_round_keys: [Block16; 15],
} }

View File

@@ -14,11 +14,14 @@
use super::int256::{Digit, Int256}; use super::int256::{Digit, Int256};
use core::ops::Mul; use core::ops::Mul;
use rng256::Rng256; use rand_core::RngCore;
use subtle::{self, Choice, ConditionallySelectable, CtOption}; use subtle::{self, Choice, ConditionallySelectable, CtOption};
use zeroize::Zeroize;
// An exponent on the elliptic curve, that is an element modulo the curve order N. /// An exponent on the elliptic curve, that is an element modulo the curve order N.
#[derive(Clone, Copy, Debug, PartialEq, Eq)] ///
/// Never call zeroize explicitly, to not invalidate any invariants.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Zeroize)]
// TODO: remove this Default once https://github.com/dalek-cryptography/subtle/issues/63 is // TODO: remove this Default once https://github.com/dalek-cryptography/subtle/issues/63 is
// resolved. // resolved.
#[derive(Default)] #[derive(Default)]
@@ -90,8 +93,10 @@ impl Mul for &ExponentP256 {
} }
} }
// A non-zero exponent on the elliptic curve. /// A non-zero exponent on the elliptic curve.
#[derive(Clone, Copy, Debug, PartialEq, Eq)] ///
/// Never call zeroize explicitly, to not invalidate any invariants.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Zeroize)]
// TODO: remove this Default once https://github.com/dalek-cryptography/subtle/issues/63 is // TODO: remove this Default once https://github.com/dalek-cryptography/subtle/issues/63 is
// resolved. // resolved.
#[derive(Default)] #[derive(Default)]
@@ -112,7 +117,7 @@ impl NonZeroExponentP256 {
// Generates a uniformly distributed element 0 < k < N // Generates a uniformly distributed element 0 < k < N
pub fn gen_uniform<R>(r: &mut R) -> NonZeroExponentP256 pub fn gen_uniform<R>(r: &mut R) -> NonZeroExponentP256
where where
R: Rng256, R: RngCore,
{ {
loop { loop {
let x = Int256::gen_uniform_256(r); let x = Int256::gen_uniform_256(r);
@@ -293,57 +298,4 @@ pub mod test {
assert_eq!(ONE.inv(), ONE); assert_eq!(ONE.inv(), ONE);
assert_eq!(N_MIN_1.inv(), N_MIN_1); assert_eq!(N_MIN_1.inv(), N_MIN_1);
} }
/** RNG **/
// Mock rng that samples through a list of values, then panics.
struct StressTestingRng {
values: Vec<Int256>,
index: usize,
}
impl StressTestingRng {
pub fn new(values: Vec<Int256>) -> StressTestingRng {
StressTestingRng { values, index: 0 }
}
}
impl Rng256 for StressTestingRng {
// This function is unused, as we redefine gen_uniform_u32x8.
fn fill_bytes(&mut self, _buf: &mut [u8]) {
unreachable!()
}
// This function is unused, as we redefine gen_uniform_u32x8.
fn gen_uniform_u8x32(&mut self) -> [u8; 32] {
unreachable!()
}
fn gen_uniform_u32x8(&mut self) -> [u32; 8] {
let result = self.values[self.index].digits();
self.index += 1;
result
}
}
#[test]
fn test_uniform_non_zero_is_below_n() {
let mut rng = StressTestingRng::new(vec![
Int256::new([
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
0xffffffff,
]),
Int256::N,
N_MIN_1.to_int(),
Int256::N_MIN_2,
]);
assert_eq!(NonZeroExponentP256::gen_uniform(&mut rng), N_MIN_1);
}
#[test]
fn test_uniform_n_is_above_zero() {
let mut rng = StressTestingRng::new(vec![Int256::ZERO]);
assert_eq!(NonZeroExponentP256::gen_uniform(&mut rng), ONE);
}
} }

View File

@@ -15,12 +15,16 @@
use super::int256::{Digit, Int256}; use super::int256::{Digit, Int256};
use core::ops::Mul; use core::ops::Mul;
use subtle::Choice; use subtle::Choice;
use zeroize::Zeroize;
// A field element on the elliptic curve, that is an element modulo the prime P. /// A field element on the elliptic curve, that is an element modulo the prime P.
// This is the format used to serialize coordinates of points on the curve. ///
// This implements enough methods to validate points and to convert them to/from the Montgomery /// This is the format used to serialize coordinates of points on the curve.
// form, which is more convenient to operate on. /// This implements enough methods to validate points and to convert them to/from the Montgomery
#[derive(Clone, Copy, PartialEq, Eq)] /// form, which is more convenient to operate on.
///
/// Never call zeroize explicitly, to not invalidate any invariants.
#[derive(Clone, Copy, PartialEq, Eq, Zeroize)]
pub struct GFP256 { pub struct GFP256 {
int: Int256, int: Int256,
} }

View File

@@ -17,8 +17,9 @@ use alloc::vec::Vec;
use arrayref::{array_mut_ref, array_ref}; use arrayref::{array_mut_ref, array_ref};
use byteorder::{BigEndian, ByteOrder}; use byteorder::{BigEndian, ByteOrder};
use core::ops::{Add, AddAssign, Sub, SubAssign}; use core::ops::{Add, AddAssign, Sub, SubAssign};
use rng256::Rng256; use rand_core::RngCore;
use subtle::{self, Choice, ConditionallySelectable, ConstantTimeEq}; use subtle::{self, Choice, ConditionallySelectable, ConstantTimeEq};
use zeroize::Zeroize;
const BITS_PER_DIGIT: usize = 32; const BITS_PER_DIGIT: usize = 32;
const BYTES_PER_DIGIT: usize = BITS_PER_DIGIT >> 3; const BYTES_PER_DIGIT: usize = BITS_PER_DIGIT >> 3;
@@ -29,7 +30,10 @@ pub type Digit = u32;
type DoubleDigit = u64; type DoubleDigit = u64;
type SignedDoubleDigit = i64; type SignedDoubleDigit = i64;
#[derive(Clone, Copy, PartialEq, Eq)] /// Big integer implementation with 256 bits.
///
/// Never call zeroize explicitly, to not invalidate any invariants.
#[derive(Clone, Copy, PartialEq, Eq, Zeroize)]
// TODO: remove this Default once https://github.com/dalek-cryptography/subtle/issues/63 is // TODO: remove this Default once https://github.com/dalek-cryptography/subtle/issues/63 is
// resolved. // resolved.
#[derive(Default)] #[derive(Default)]
@@ -119,11 +123,13 @@ impl Int256 {
// Generates a uniformly distributed integer 0 <= x < 2^256 // Generates a uniformly distributed integer 0 <= x < 2^256
pub fn gen_uniform_256<R>(r: &mut R) -> Int256 pub fn gen_uniform_256<R>(r: &mut R) -> Int256
where where
R: Rng256, R: RngCore,
{ {
Int256 { let mut digits = [0; NDIGITS];
digits: r.gen_uniform_u32x8(), for i in 0..NDIGITS {
digits[i] = r.next_u32();
} }
Int256 { digits }
} }
/** Serialization **/ /** Serialization **/

View File

@@ -17,13 +17,16 @@ use super::int256::Int256;
use super::precomputed; use super::precomputed;
use core::ops::{Add, Mul, Sub}; use core::ops::{Add, Mul, Sub};
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq}; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
use zeroize::Zeroize;
pub const NLIMBS: usize = 9; pub const NLIMBS: usize = 9;
pub const BOTTOM_28_BITS: u32 = 0x0fff_ffff; pub const BOTTOM_28_BITS: u32 = 0x0fff_ffff;
pub const BOTTOM_29_BITS: u32 = 0x1fff_ffff; pub const BOTTOM_29_BITS: u32 = 0x1fff_ffff;
/** Field element on the secp256r1 curve, represented in Montgomery form **/ /// Field element on the secp256r1 curve, represented in Montgomery form.
#[derive(Clone, Copy)] ///
/// Never call zeroize explicitly, to not invalidate any invariants.
#[derive(Clone, Copy, Zeroize)]
pub struct Montgomery { pub struct Montgomery {
// The 9 limbs use 28 or 29 bits, alternatively: even limbs use 29 bits, odd limbs use 28 bits. // The 9 limbs use 28 or 29 bits, alternatively: even limbs use 29 bits, odd limbs use 28 bits.
// The Montgomery form stores a field element x as (x * 2^257) mod P. // The Montgomery form stores a field element x as (x * 2^257) mod P.

View File

@@ -21,11 +21,15 @@ use arrayref::array_mut_ref;
use arrayref::array_ref; use arrayref::array_ref;
use core::ops::Add; use core::ops::Add;
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq}; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
use zeroize::Zeroize;
// A point on the elliptic curve is represented by two field elements. /// A point on the elliptic curve, represented by two field elements.
// The "direct" representation with GFP256 (integer modulo p) is used for serialization of public ///
// keys. /// The "direct" representation with GFP256 (integer modulo p) is used for serialization of public
#[derive(Clone, Copy, PartialEq, Eq)] /// keys.
///
/// Never call zeroize explicitly, to not invalidate any invariants.
#[derive(Clone, Copy, Zeroize)]
pub struct PointP256 { pub struct PointP256 {
x: GFP256, x: GFP256,
y: GFP256, y: GFP256,
@@ -128,12 +132,15 @@ impl PointP256 {
} }
} }
// A point on the elliptic curve in projective form. /// A point on the elliptic curve in projective form.
// This uses Montgomery representation for field elements. ///
// This is in projective coordinates, i.e. it represents the point { x: x / z, y: y / z }. /// This uses Montgomery representation for field elements.
// This representation is more convenient to implement complete formulas for elliptic curve /// This is in projective coordinates, i.e. it represents the point { x: x / z, y: y / z }.
// arithmetic. /// This representation is more convenient to implement complete formulas for elliptic curve
#[derive(Clone, Copy)] /// arithmetic.
///
/// Never call zeroize explicitly, to not invalidate any invariants.
#[derive(Clone, Copy, Zeroize)]
pub struct PointProjective { pub struct PointProjective {
x: Montgomery, x: Montgomery,
y: Montgomery, y: Montgomery,
@@ -150,8 +157,10 @@ impl ConditionallySelectable for PointProjective {
} }
} }
// Equivalent to PointProjective { x, y, z: 1 } /// Equivalent to PointProjective { x, y, z: 1 }
#[derive(Clone, Copy)] ///
/// Never call zeroize explicitly, to not invalidate any invariants.
#[derive(Clone, Copy, Zeroize)]
pub struct PointAffine { pub struct PointAffine {
x: Montgomery, x: Montgomery,
y: Montgomery, y: Montgomery,
@@ -548,6 +557,12 @@ impl core::fmt::Debug for PointP256 {
} }
} }
impl PartialEq for PointP256 {
fn eq(&self, other: &PointP256) -> bool {
self.x == other.x && self.y == other.y
}
}
#[cfg(test)] #[cfg(test)]
pub mod test { pub mod test {
use super::*; use super::*;

View File

@@ -16,15 +16,23 @@ use super::ec::exponent256::NonZeroExponentP256;
use super::ec::int256; use super::ec::int256;
use super::ec::int256::Int256; use super::ec::int256::Int256;
use super::ec::point::PointP256; use super::ec::point::PointP256;
use rng256::Rng256; use rand_core::RngCore;
use zeroize::Zeroize;
pub const NBYTES: usize = int256::NBYTES; pub const NBYTES: usize = int256::NBYTES;
/// A private key for ECDH.
///
/// Never call zeroize explicitly, to not invalidate any invariants.
#[derive(Zeroize)]
pub struct SecKey { pub struct SecKey {
a: NonZeroExponentP256, a: NonZeroExponentP256,
} }
#[derive(Clone, Debug, PartialEq)] /// A public key for ECDH.
///
/// Never call zeroize explicitly, to not invalidate any invariants.
#[derive(Clone, Debug, PartialEq, Zeroize)]
pub struct PubKey { pub struct PubKey {
p: PointP256, p: PointP256,
} }
@@ -32,7 +40,7 @@ pub struct PubKey {
impl SecKey { impl SecKey {
pub fn gensk<R>(rng: &mut R) -> SecKey pub fn gensk<R>(rng: &mut R) -> SecKey
where where
R: Rng256, R: RngCore,
{ {
SecKey { SecKey {
a: NonZeroExponentP256::gen_uniform(rng), a: NonZeroExponentP256::gen_uniform(rng),
@@ -70,6 +78,17 @@ impl SecKey {
p.getx().to_int().to_bin(&mut x); p.getx().to_int().to_bin(&mut x);
x x
} }
/// Creates a private key from the exponent's bytes, or None if checks fail.
pub fn from_bytes(bytes: &[u8; 32]) -> Option<SecKey> {
let a = NonZeroExponentP256::from_int_checked(Int256::from_bin(bytes));
// The branching here is fine because all this reveals is whether the key was invalid.
if bool::from(a.is_none()) {
return None;
}
let a = a.unwrap();
Some(SecKey { a })
}
} }
impl PubKey { impl PubKey {
@@ -99,7 +118,7 @@ impl PubKey {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
use rng256::ThreadRng256; use rand_core::OsRng;
// Run more test iterations in release mode, as the code should be faster. // Run more test iterations in release mode, as the code should be faster.
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
@@ -110,7 +129,7 @@ mod test {
/** Test that key generation creates valid keys **/ /** Test that key generation creates valid keys **/
#[test] #[test]
fn test_gen_pub_is_valid_random() { fn test_gen_pub_is_valid_random() {
let mut rng = ThreadRng256 {}; let mut rng = OsRng::default();
for _ in 0..ITERATIONS { for _ in 0..ITERATIONS {
let sk = SecKey::gensk(&mut rng); let sk = SecKey::gensk(&mut rng);
@@ -122,7 +141,7 @@ mod test {
/** Test that the exchanged key is the same on both sides **/ /** Test that the exchanged key is the same on both sides **/
#[test] #[test]
fn test_exchange_x_is_symmetric() { fn test_exchange_x_is_symmetric() {
let mut rng = ThreadRng256 {}; let mut rng = OsRng::default();
for _ in 0..ITERATIONS { for _ in 0..ITERATIONS {
let sk_a = SecKey::gensk(&mut rng); let sk_a = SecKey::gensk(&mut rng);
@@ -135,7 +154,7 @@ mod test {
#[test] #[test]
fn test_exchange_x_bytes_is_symmetric() { fn test_exchange_x_bytes_is_symmetric() {
let mut rng = ThreadRng256 {}; let mut rng = OsRng::default();
for _ in 0..ITERATIONS { for _ in 0..ITERATIONS {
let sk_a = SecKey::gensk(&mut rng); let sk_a = SecKey::gensk(&mut rng);

View File

@@ -16,30 +16,37 @@ use super::ec::exponent256::{ExponentP256, NonZeroExponentP256};
use super::ec::int256; use super::ec::int256;
use super::ec::int256::Int256; use super::ec::int256::Int256;
use super::ec::point::PointP256; use super::ec::point::PointP256;
use super::hmac::hmac_256;
use super::Hash256; use super::Hash256;
use alloc::vec; use alloc::vec;
use alloc::vec::Vec; use alloc::vec::Vec;
#[cfg(feature = "std")] use arrayref::{array_mut_ref, array_ref, mut_array_refs};
use arrayref::array_mut_ref;
use arrayref::{array_ref, mut_array_refs};
use core::marker::PhantomData; use core::marker::PhantomData;
use rng256::Rng256; use rand_core::RngCore;
use zeroize::Zeroize;
pub const NBYTES: usize = int256::NBYTES; pub const NBYTES: usize = int256::NBYTES;
#[derive(Clone, Debug, PartialEq, Eq)] /// A private key for ECDSA.
///
/// Never call zeroize explicitly, to not invalidate any invariants.
#[derive(Clone, Debug, PartialEq, Eq, Zeroize)]
pub struct SecKey { pub struct SecKey {
k: NonZeroExponentP256, k: NonZeroExponentP256,
} }
#[derive(Clone, Debug, PartialEq, Eq)] /// An ECDSA signature.
///
/// Never call zeroize explicitly, to not invalidate any invariants.
#[derive(Zeroize)]
pub struct Signature { pub struct Signature {
r: NonZeroExponentP256, r: NonZeroExponentP256,
s: NonZeroExponentP256, s: NonZeroExponentP256,
} }
#[derive(Clone, Debug, PartialEq, Eq)] /// A public key for ECDSA.
///
/// Never call zeroize explicitly, to not invalidate any invariants.
#[derive(Clone, Zeroize)]
pub struct PubKey { pub struct PubKey {
p: PointP256, p: PointP256,
} }
@@ -47,7 +54,7 @@ pub struct PubKey {
impl SecKey { impl SecKey {
pub fn gensk<R>(rng: &mut R) -> SecKey pub fn gensk<R>(rng: &mut R) -> SecKey
where where
R: Rng256, R: RngCore,
{ {
SecKey { SecKey {
k: NonZeroExponentP256::gen_uniform(rng), k: NonZeroExponentP256::gen_uniform(rng),
@@ -68,7 +75,7 @@ impl SecKey {
pub fn sign_rng<H, R>(&self, msg: &[u8], rng: &mut R) -> Signature pub fn sign_rng<H, R>(&self, msg: &[u8], rng: &mut R) -> Signature
where where
H: Hash256, H: Hash256,
R: Rng256, R: RngCore,
{ {
let m = ExponentP256::modn(Int256::from_bin(&H::hash(msg))); let m = ExponentP256::modn(Int256::from_bin(&H::hash(msg)));
@@ -211,7 +218,6 @@ impl Signature {
Some(Signature { r, s }) Some(Signature { r, s })
} }
#[cfg(feature = "std")]
pub fn to_bytes(&self, bytes: &mut [u8; Signature::BYTES_LENGTH]) { pub fn to_bytes(&self, bytes: &mut [u8; Signature::BYTES_LENGTH]) {
self.r self.r
.to_int() .to_int()
@@ -223,9 +229,6 @@ impl Signature {
} }
impl PubKey { impl PubKey {
#[cfg(feature = "with_ctap1")]
const UNCOMPRESSED_LENGTH: usize = 1 + 2 * int256::NBYTES;
/// Creates a new PubKey from its coordinates on the elliptic curve. /// Creates a new PubKey from its coordinates on the elliptic curve.
pub fn from_coordinates(x: &[u8; NBYTES], y: &[u8; NBYTES]) -> Option<PubKey> { pub fn from_coordinates(x: &[u8; NBYTES], y: &[u8; NBYTES]) -> Option<PubKey> {
PointP256::new_checked_vartime(Int256::from_bin(x), Int256::from_bin(y)) PointP256::new_checked_vartime(Int256::from_bin(x), Int256::from_bin(y))
@@ -241,20 +244,6 @@ impl PubKey {
self.p.to_bytes_uncompressed(bytes); self.p.to_bytes_uncompressed(bytes);
} }
#[cfg(feature = "with_ctap1")]
pub fn to_uncompressed(&self) -> [u8; PubKey::UNCOMPRESSED_LENGTH] {
// Formatting according to:
// https://tools.ietf.org/id/draft-jivsov-ecc-compact-05.html#overview
const B0_BYTE_MARKER: u8 = 0x04;
let mut representation = [0; PubKey::UNCOMPRESSED_LENGTH];
let (marker, x, y) =
mut_array_refs![&mut representation, 1, int256::NBYTES, int256::NBYTES];
marker[0] = B0_BYTE_MARKER;
self.p.getx().to_int().to_bin(x);
self.p.gety().to_int().to_bin(y);
representation
}
/// Writes the coordinates into the passed in arrays. /// Writes the coordinates into the passed in arrays.
pub fn to_coordinates(&self, x: &mut [u8; NBYTES], y: &mut [u8; NBYTES]) { pub fn to_coordinates(&self, x: &mut [u8; NBYTES], y: &mut [u8; NBYTES]) {
self.p.getx().to_int().to_bin(x); self.p.getx().to_int().to_bin(x);
@@ -277,7 +266,6 @@ impl PubKey {
ExponentP256::modn(u.to_int()) == *sign.r.as_exponent() ExponentP256::modn(u.to_int()) == *sign.r.as_exponent()
} }
#[cfg(feature = "std")]
pub fn verify_vartime<H>(&self, msg: &[u8], sign: &Signature) -> bool pub fn verify_vartime<H>(&self, msg: &[u8], sign: &Signature) -> bool
where where
H: Hash256, H: Hash256,
@@ -312,15 +300,15 @@ where
Int256::to_bin(&sk.k.to_int(), contents_k); Int256::to_bin(&sk.k.to_int(), contents_k);
Int256::to_bin(&Int256::from_bin(&h1).modd(&Int256::N), contents_h1); Int256::to_bin(&Int256::from_bin(&h1).modd(&Int256::N), contents_h1);
let k = hmac_256::<H>(&k, &contents); let k = H::hmac(&k, &contents);
let v = hmac_256::<H>(&k, &v); let v = H::hmac(&k, &v);
let (contents_v, marker, _) = mut_array_refs![&mut contents, 32, 1, 64]; let (contents_v, marker, _) = mut_array_refs![&mut contents, 32, 1, 64];
contents_v.copy_from_slice(&v); contents_v.copy_from_slice(&v);
marker[0] = 0x01; marker[0] = 0x01;
let k = hmac_256::<H>(&k, &contents); let k = H::hmac(&k, &contents);
let v = hmac_256::<H>(&k, &v); let v = H::hmac(&k, &v);
Rfc6979 { Rfc6979 {
k, k,
@@ -332,14 +320,14 @@ where
fn next(&mut self) -> Int256 { fn next(&mut self) -> Int256 {
// Note: at this step, the logic from RFC 6979 is simplified, because the HMAC produces 256 // Note: at this step, the logic from RFC 6979 is simplified, because the HMAC produces 256
// bits and we need 256 bits. // bits and we need 256 bits.
let t = hmac_256::<H>(&self.k, &self.v); let t = H::hmac(&self.k, &self.v);
let result = Int256::from_bin(&t); let result = Int256::from_bin(&t);
let mut v1 = [0; 33]; let mut v1 = [0; 33];
v1[..32].copy_from_slice(&self.v); v1[..32].copy_from_slice(&self.v);
v1[32] = 0x00; v1[32] = 0x00;
self.k = hmac_256::<H>(&self.k, &v1); self.k = H::hmac(&self.k, &v1);
self.v = hmac_256::<H>(&self.k, &self.v); self.v = H::hmac(&self.k, &self.v);
result result
} }
@@ -349,7 +337,7 @@ where
mod test { mod test {
use super::super::sha256::Sha256; use super::super::sha256::Sha256;
use super::*; use super::*;
use rng256::ThreadRng256; use rand_core::OsRng;
// Run more test iterations in release mode, as the code should be faster. // Run more test iterations in release mode, as the code should be faster.
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
@@ -357,10 +345,16 @@ mod test {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
const ITERATIONS: u32 = 500; const ITERATIONS: u32 = 500;
fn gen_random_message(rng: &mut impl RngCore) -> [u8; 32] {
let mut bytes = [0; 32];
rng.fill_bytes(&mut bytes);
bytes
}
/** Test that key generation creates valid keys **/ /** Test that key generation creates valid keys **/
#[test] #[test]
fn test_genpk_is_valid_random() { fn test_genpk_is_valid_random() {
let mut rng = ThreadRng256 {}; let mut rng = OsRng::default();
for _ in 0..ITERATIONS { for _ in 0..ITERATIONS {
let sk = SecKey::gensk(&mut rng); let sk = SecKey::gensk(&mut rng);
@@ -372,7 +366,7 @@ mod test {
/** Serialization **/ /** Serialization **/
#[test] #[test]
fn test_seckey_to_bytes_from_bytes() { fn test_seckey_to_bytes_from_bytes() {
let mut rng = ThreadRng256 {}; let mut rng = OsRng::default();
for _ in 0..ITERATIONS { for _ in 0..ITERATIONS {
let sk = SecKey::gensk(&mut rng); let sk = SecKey::gensk(&mut rng);
@@ -463,10 +457,10 @@ mod test {
// Test that signed message hashes are correctly verified. // Test that signed message hashes are correctly verified.
#[test] #[test]
fn test_sign_rfc6979_verify_hash_random() { fn test_sign_rfc6979_verify_hash_random() {
let mut rng = ThreadRng256 {}; let mut rng = OsRng::default();
for _ in 0..ITERATIONS { for _ in 0..ITERATIONS {
let msg = rng.gen_uniform_u8x32(); let msg = gen_random_message(&mut rng);
let sk = SecKey::gensk(&mut rng); let sk = SecKey::gensk(&mut rng);
let pk = sk.genpk(); let pk = sk.genpk();
let sign = sk.sign_rfc6979::<Sha256>(&msg); let sign = sk.sign_rfc6979::<Sha256>(&msg);
@@ -478,10 +472,10 @@ mod test {
// Test that signed messages are correctly verified. // Test that signed messages are correctly verified.
#[test] #[test]
fn test_sign_rfc6979_verify_random() { fn test_sign_rfc6979_verify_random() {
let mut rng = ThreadRng256 {}; let mut rng = OsRng::default();
for _ in 0..ITERATIONS { for _ in 0..ITERATIONS {
let msg = rng.gen_uniform_u8x32(); let msg = gen_random_message(&mut rng);
let sk = SecKey::gensk(&mut rng); let sk = SecKey::gensk(&mut rng);
let pk = sk.genpk(); let pk = sk.genpk();
let sign = sk.sign_rfc6979::<Sha256>(&msg); let sign = sk.sign_rfc6979::<Sha256>(&msg);
@@ -492,10 +486,10 @@ mod test {
// Test that signed messages are correctly verified. // Test that signed messages are correctly verified.
#[test] #[test]
fn test_sign_verify_random() { fn test_sign_verify_random() {
let mut rng = ThreadRng256 {}; let mut rng = OsRng::default();
for _ in 0..ITERATIONS { for _ in 0..ITERATIONS {
let msg = rng.gen_uniform_u8x32(); let msg = gen_random_message(&mut rng);
let sk = SecKey::gensk(&mut rng); let sk = SecKey::gensk(&mut rng);
let pk = sk.genpk(); let pk = sk.genpk();
let sign = sk.sign_rng::<Sha256, _>(&msg, &mut rng); let sign = sk.sign_rng::<Sha256, _>(&msg, &mut rng);
@@ -580,10 +574,10 @@ mod test {
fn test_self_sign_ring_verify() { fn test_self_sign_ring_verify() {
use ring::signature::VerificationAlgorithm; use ring::signature::VerificationAlgorithm;
let mut rng = ThreadRng256 {}; let mut rng = OsRng::default();
for _ in 0..ITERATIONS { for _ in 0..ITERATIONS {
let msg_bytes = rng.gen_uniform_u8x32(); let msg_bytes = gen_random_message(&mut rng);
let sk = SecKey::gensk(&mut rng); let sk = SecKey::gensk(&mut rng);
let pk = sk.genpk(); let pk = sk.genpk();
let sign = sk.sign_rng::<Sha256, _>(&msg_bytes, &mut rng); let sign = sk.sign_rng::<Sha256, _>(&msg_bytes, &mut rng);

View File

@@ -17,6 +17,27 @@ use super::Hash256;
const HASH_SIZE: usize = 32; const HASH_SIZE: usize = 32;
/// Computes the HKDF with the given salt and 256 bit (one block) output.
///
/// # Arguments
///
/// * `ikm` - Input keying material
/// * `salt` - Byte string that acts as a key
/// * `info` - Optional context and application specific information
///
/// This implementation is equivalent to a standard HKD, with `salt` fixed at a length of
/// 32 byte and the output length l as 32.
pub fn hkdf_256<H>(ikm: &[u8], salt: &[u8; HASH_SIZE], info: &[u8], okm: &mut [u8; HASH_SIZE])
where
H: Hash256,
{
let prk = H::hmac(salt, ikm);
// l is implicitly the block size, so we iterate exactly once.
let mut t = info.to_vec();
t.push(1);
hmac_256::<H>(&prk, t.as_slice(), okm);
}
/// Computes the HKDF with empty salt and 256 bit (one block) output. /// Computes the HKDF with empty salt and 256 bit (one block) output.
/// ///
/// # Arguments /// # Arguments
@@ -26,16 +47,12 @@ const HASH_SIZE: usize = 32;
/// ///
/// This implementation is equivalent to the below hkdf, with `salt` set to the /// This implementation is equivalent to the below hkdf, with `salt` set to the
/// default block of zeros and the output length l as 32. /// default block of zeros and the output length l as 32.
pub fn hkdf_empty_salt_256<H>(ikm: &[u8], info: &[u8]) -> [u8; HASH_SIZE] pub fn hkdf_empty_salt_256<H>(ikm: &[u8], info: &[u8], okm: &mut [u8; HASH_SIZE])
where where
H: Hash256, H: Hash256,
{ {
// Salt is a zero block here. // Salt is a zero block here.
let prk = hmac_256::<H>(&[0; HASH_SIZE], ikm); hkdf_256::<H>(ikm, &[0; HASH_SIZE], info, okm);
// l is implicitly the block size, so we iterate exactly once.
let mut t = info.to_vec();
t.push(1);
hmac_256::<H>(&prk, t.as_slice())
} }
#[cfg(test)] #[cfg(test)]
@@ -49,32 +66,51 @@ mod test {
// Test vectors generated by pycryptodome using: // Test vectors generated by pycryptodome using:
// HKDF(b'0', 32, b'', SHA256, context=b'\x00').hex() // HKDF(b'0', 32, b'', SHA256, context=b'\x00').hex()
let test_okms = [ let test_okms = [
hex::decode("f9be72116cb97f41828210289caafeabde1f3dfb9723bf43538ab18f3666783a") "f9be72116cb97f41828210289caafeabde1f3dfb9723bf43538ab18f3666783a",
.unwrap(), "f50f964f5b94d62fd1da9356ab8662b0a0f5b8e36e277178b69b6ffecf50cf44",
hex::decode("f50f964f5b94d62fd1da9356ab8662b0a0f5b8e36e277178b69b6ffecf50cf44") "fc8772ceb5592d67442dcb4353cdd28519e82d6e55b4cf664b5685252c2d2998",
.unwrap(), "62831b924839a180f53be5461eeea1b89dc21779f50142b5a54df0f0cc86d61a",
hex::decode("fc8772ceb5592d67442dcb4353cdd28519e82d6e55b4cf664b5685252c2d2998") "6991f00a12946a4e3b8315cdcf0132c2ca508fd17b769f08d1454d92d33733e0",
.unwrap(), "0f9bb7dddd1ec61f91d8c4f5369b5870f9d44c4ceabccca1b83f06fec115e4e3",
hex::decode("62831b924839a180f53be5461eeea1b89dc21779f50142b5a54df0f0cc86d61a") "235367e2ab6cca2aba1a666825458dba6b272a215a2537c05feebe4b80dab709",
.unwrap(), "96e8edad661da48d1a133b38c255d33e05555bc9aa442579dea1cd8d8b8d2aef",
hex::decode("6991f00a12946a4e3b8315cdcf0132c2ca508fd17b769f08d1454d92d33733e0")
.unwrap(),
hex::decode("0f9bb7dddd1ec61f91d8c4f5369b5870f9d44c4ceabccca1b83f06fec115e4e3")
.unwrap(),
hex::decode("235367e2ab6cca2aba1a666825458dba6b272a215a2537c05feebe4b80dab709")
.unwrap(),
hex::decode("96e8edad661da48d1a133b38c255d33e05555bc9aa442579dea1cd8d8b8d2aef")
.unwrap(),
]; ];
for (i, okm) in test_okms.iter().enumerate() { for (i, okm) in test_okms.iter().enumerate() {
// String of number i. // String of number i.
let ikm = i.to_string(); let ikm = i.to_string();
// Byte i. // Byte i.
let info = [i as u8]; let info = [i as u8];
assert_eq!( let okm = hex::decode(okm).unwrap();
&hkdf_empty_salt_256::<Sha256>(&ikm.as_bytes(), &info[..]), let mut output = [0; HASH_SIZE];
array_ref!(okm, 0, 32) hkdf_empty_salt_256::<Sha256>(&ikm.as_bytes(), &info[..], &mut output);
); assert_eq!(&output, array_ref!(okm, 0, HASH_SIZE));
}
}
#[test]
fn test_hkdf_256_sha256_vectors() {
// Test vectors generated as above, but with salt:
let test_okms = [
"f9be72116cb97f41828210289caafeabde1f3dfb9723bf43538ab18f3666783a",
"a2480a09c7349d76e459f98a8259da40544bfbd2930d357a0f3250ade0acf941",
"3904f7bf3615df9512fc6b1af651ed69b43f7fad424f9c718aaab63f377a36b9",
"a0027dcffb27d356317199c6e65f153a9286ba114aee2d3cf45bdba83cb7c065",
"786d1f89f54668bac443cc6a8887c95d6fbde07702cb4c16d76c452e87c50f79",
"8e9a5bdf362c5aec2c31a742dfebd0b7b56e16ab8408d9d0609a4fad06446875",
"4a35d3d7c80ff4fab65f7e30d6b305fc7bb39ffe905aabedd6593354f86177b6",
"b1121deabd8b4308f3805cda8af991ee976bd8e413bcb6a8dd3fc26ebe2312d2",
];
for (i, okm) in test_okms.iter().enumerate() {
// String of number i.
let ikm = i.to_string();
// Bytestring of byte i.
let salt = [i as u8; 32];
// Byte i.
let info = [i as u8];
let okm = hex::decode(okm).unwrap();
let mut output = [0; HASH_SIZE];
hkdf_256::<Sha256>(&ikm.as_bytes(), &salt, &info[..], &mut output);
assert_eq!(&output, array_ref!(okm, 0, HASH_SIZE));
} }
} }
} }

View File

@@ -24,7 +24,8 @@ pub fn verify_hmac_256<H>(key: &[u8; KEY_SIZE], contents: &[u8], mac: &[u8; HASH
where where
H: Hash256, H: Hash256,
{ {
let expected_mac = hmac_256::<H>(key, contents); let mut expected_mac = [0; HASH_SIZE];
hmac_256::<H>(key, contents, &mut expected_mac);
bool::from(expected_mac.ct_eq(mac)) bool::from(expected_mac.ct_eq(mac))
} }
@@ -38,19 +39,23 @@ pub fn verify_hmac_256_first_128bits<H>(
where where
H: Hash256, H: Hash256,
{ {
let expected_mac = hmac_256::<H>(key, contents); let mut expected_mac = [0; HASH_SIZE];
hmac_256::<H>(key, contents, &mut expected_mac);
bool::from(array_ref![expected_mac, 0, 16].ct_eq(pin)) bool::from(array_ref![expected_mac, 0, 16].ct_eq(pin))
} }
pub fn hmac_256<H>(key: &[u8; KEY_SIZE], contents: &[u8]) -> [u8; HASH_SIZE] pub fn hmac_256<H>(key: &[u8; KEY_SIZE], contents: &[u8], output: &mut [u8; HASH_SIZE])
where where
H: Hash256, H: Hash256,
{ {
H::hmac(key, contents) H::hmac_mut(key, contents, output)
} }
pub(crate) fn software_hmac_256<H>(key: &[u8; KEY_SIZE], contents: &[u8]) -> [u8; HASH_SIZE] pub(crate) fn software_hmac_256<H>(
where key: &[u8; KEY_SIZE],
contents: &[u8],
output: &mut [u8; HASH_SIZE],
) where
H: Hash256, H: Hash256,
{ {
let mut ipad: [u8; BLOCK_SIZE] = [0x36; BLOCK_SIZE]; let mut ipad: [u8; BLOCK_SIZE] = [0x36; BLOCK_SIZE];
@@ -64,13 +69,13 @@ where
let mut ihasher = H::new(); let mut ihasher = H::new();
ihasher.update(&ipad); ihasher.update(&ipad);
ihasher.update(contents); ihasher.update(contents);
let ihash = ihasher.finalize(); let mut ihash = [0; HASH_SIZE];
ihasher.finalize(&mut ihash);
let mut ohasher = H::new(); let mut ohasher = H::new();
ohasher.update(&opad); ohasher.update(&opad);
ohasher.update(&ihash); ohasher.update(&ihash);
ohasher.finalize(output);
ohasher.finalize()
} }
fn xor_pads(ipad: &mut [u8; BLOCK_SIZE], opad: &mut [u8; BLOCK_SIZE], key: &[u8; KEY_SIZE]) { fn xor_pads(ipad: &mut [u8; BLOCK_SIZE], opad: &mut [u8; BLOCK_SIZE], key: &[u8; KEY_SIZE]) {
@@ -91,7 +96,8 @@ mod test {
for len in 0..128 { for len in 0..128 {
let key = [0; KEY_SIZE]; let key = [0; KEY_SIZE];
let contents = vec![0; len]; let contents = vec![0; len];
let mac = hmac_256::<Sha256>(&key, &contents); let mut mac = [0; HASH_SIZE];
hmac_256::<Sha256>(&key, &contents, &mut mac);
assert!(verify_hmac_256::<Sha256>(&key, &contents, &mac)); assert!(verify_hmac_256::<Sha256>(&key, &contents, &mac));
} }
} }
@@ -102,7 +108,8 @@ mod test {
for len in 0..128 { for len in 0..128 {
let key = [0; KEY_SIZE]; let key = [0; KEY_SIZE];
let contents = vec![0; len]; let contents = vec![0; len];
let mac = hmac_256::<Sha256>(&key, &contents); let mut mac = [0; HASH_SIZE];
hmac_256::<Sha256>(&key, &contents, &mut mac);
// Check that invalid MACs don't verify, by changing any byte of the valid MAC. // Check that invalid MACs don't verify, by changing any byte of the valid MAC.
for i in 0..HASH_SIZE { for i in 0..HASH_SIZE {
@@ -116,14 +123,21 @@ mod test {
#[test] #[test]
fn test_hmac_sha256_examples() { fn test_hmac_sha256_examples() {
let key = [0; KEY_SIZE]; let key = [0; KEY_SIZE];
let mut mac = [0; HASH_SIZE];
hmac_256::<Sha256>(&key, &[], &mut mac);
assert_eq!( assert_eq!(
hmac_256::<Sha256>(&key, &[]), mac,
hex::decode("b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad") hex::decode("b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad")
.unwrap() .unwrap()
.as_slice() .as_slice()
); );
hmac_256::<Sha256>(
&key,
b"The quick brown fox jumps over the lazy dog",
&mut mac,
);
assert_eq!( assert_eq!(
hmac_256::<Sha256>(&key, b"The quick brown fox jumps over the lazy dog"), mac,
hex::decode("fb011e6154a19b9a4c767373c305275a5a69e8b68b0b4c9200c383dced19a416") hex::decode("fb011e6154a19b9a4c767373c305275a5a69e8b68b0b4c9200c383dced19a416")
.unwrap() .unwrap()
.as_slice() .as_slice()
@@ -274,11 +288,10 @@ mod test {
let mut input = Vec::new(); let mut input = Vec::new();
let key = [b'A'; KEY_SIZE]; let key = [b'A'; KEY_SIZE];
let mut mac = [0; HASH_SIZE];
for i in 0..128 { for i in 0..128 {
assert_eq!( hmac_256::<Sha256>(&key, &input, &mut mac);
hmac_256::<Sha256>(&key, &input), assert_eq!(mac, hex::decode(hashes[i] as &[u8]).unwrap().as_slice());
hex::decode(hashes[i] as &[u8]).unwrap().as_slice()
);
input.push(b'A'); input.push(b'A');
} }
} }

View File

@@ -1,246 +0,0 @@
// Copyright 2021-2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use super::ecdsa;
use alloc::vec::Vec;
// A label generated uniformly at random from the output space of SHA256.
const LABEL: [u8; 32] = [
43, 253, 32, 250, 19, 51, 24, 237, 138, 49, 47, 182, 4, 194, 133, 183, 177, 218, 115, 58, 92,
117, 45, 172, 156, 5, 214, 176, 248, 103, 55, 216,
];
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SecKey {
dilithium_seed: [u8; dilithium::params::SEEDBYTES],
ecdsa_sk: ecdsa::SecKey,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PubKey {
pub dilithium_pk: dilithium::sign::PubKey,
pub ecdsa_pk: ecdsa::PubKey,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Signature {
pub dilithium_sign: Vec<u8>,
pub ecdsa_sign: ecdsa::Signature,
}
fn ecdsa_input(msg: &[u8]) -> Vec<u8> {
let mut input = LABEL.to_vec();
input.extend(msg);
return input;
}
fn dilithium_input(msg: &[u8], ecdsa_sign: &ecdsa::Signature) -> Vec<u8> {
let mut input = LABEL.to_vec();
input.extend(msg);
input.extend(ecdsa_sign.to_asn1_der());
return input;
}
impl SecKey {
pub const BYTES_LENGTH: usize = 32 + dilithium::params::SEEDBYTES;
pub fn gensk<R>(rng: &mut R) -> SecKey
where
R: rng256::Rng256,
{
let mut seed = [0u8; dilithium::params::SEEDBYTES];
rng.fill_bytes(&mut seed);
SecKey {
dilithium_seed: seed,
ecdsa_sk: ecdsa::SecKey::gensk(rng),
}
}
pub fn gensk_with_pk<R>(rng: &mut R) -> (SecKey, PubKey)
where
R: rng256::Rng256,
{
let mut seed = [0u8; dilithium::params::SEEDBYTES];
rng.fill_bytes(&mut seed);
let (_, dilithium_pk) = dilithium::sign::SecKey::gensk_with_pk_from_seed(&seed);
let ecdsa_sk = ecdsa::SecKey::gensk(rng);
let ecdsa_pk = ecdsa_sk.genpk();
let sk = SecKey {
dilithium_seed: seed,
ecdsa_sk,
};
let pk = PubKey {
dilithium_pk,
ecdsa_pk,
};
(sk, pk)
}
pub fn genpk(&self) -> PubKey {
let (_, dilithium_pk) =
dilithium::sign::SecKey::gensk_with_pk_from_seed(&self.dilithium_seed);
PubKey {
dilithium_pk,
ecdsa_pk: self.ecdsa_sk.genpk(),
}
}
pub fn sign_rfc6979<H>(&self, msg: &[u8]) -> Signature
where
H: super::Hash256 + super::HashBlockSize64Bytes,
{
let ecdsa_sign = self.ecdsa_sk.sign_rfc6979::<H>(&ecdsa_input(&msg));
let dilithium_sk = dilithium::sign::SecKey::gensk_from_seed(&self.dilithium_seed);
// This wastes some stack, we could revert the Dilithium API to take a &mut [u8].
let dilithium_sign = dilithium_sk
.sign(&dilithium_input(&msg, &ecdsa_sign))
.to_vec();
return Signature {
ecdsa_sign,
dilithium_sign,
};
}
pub fn from_bytes(bytes: &[u8; SecKey::BYTES_LENGTH]) -> Option<SecKey> {
let ecdsa_bytes = array_ref!(bytes, 0, 32);
let ecdsa_sk = ecdsa::SecKey::from_bytes(&ecdsa_bytes)?;
let dilithium_seed = array_ref!(bytes, 32, dilithium::params::SEEDBYTES).clone();
return Some(SecKey {
ecdsa_sk,
dilithium_seed,
});
}
pub fn to_bytes(&self, bytes: &mut [u8; SecKey::BYTES_LENGTH]) {
let mut ecdsa_bytes = array_mut_ref!(bytes, 0, 32);
self.ecdsa_sk.to_bytes(&mut ecdsa_bytes);
let dilithium_bytes = array_mut_ref!(bytes, 32, dilithium::params::SEEDBYTES);
dilithium_bytes.copy_from_slice(&self.dilithium_seed);
}
}
impl PubKey {
pub const BYTES_LENGTH: usize = 2 * ecdsa::NBYTES + dilithium::params::PK_SIZE_PACKED;
pub fn from_bytes(bytes: &[u8; PubKey::BYTES_LENGTH]) -> Option<PubKey> {
let ecdsa_x_bytes = array_ref!(bytes, 0, ecdsa::NBYTES);
let ecdsa_y_bytes = array_ref!(bytes, ecdsa::NBYTES, ecdsa::NBYTES);
let ecdsa_pk = ecdsa::PubKey::from_coordinates(&ecdsa_x_bytes, &ecdsa_y_bytes)?;
let dilithium_bytes = array_ref!(
bytes,
ecdsa::NBYTES + ecdsa::NBYTES,
dilithium::params::PK_SIZE_PACKED
)
.clone();
let dilithium_pk = dilithium::sign::PubKey::from_bytes(&dilithium_bytes);
Some(PubKey {
ecdsa_pk,
dilithium_pk,
})
}
pub fn to_bytes(&self, bytes: &mut [u8; PubKey::BYTES_LENGTH]) {
let mut ecdsa_x_bytes = [0; ecdsa::NBYTES];
let mut ecdsa_y_bytes = [0; ecdsa::NBYTES];
self.ecdsa_pk
.to_coordinates(&mut ecdsa_x_bytes, &mut ecdsa_y_bytes);
array_mut_ref!(bytes, 0, ecdsa::NBYTES).clone_from(&ecdsa_x_bytes);
array_mut_ref!(bytes, ecdsa::NBYTES, ecdsa::NBYTES).clone_from(&ecdsa_y_bytes);
let mut dilithium_bytes = array_mut_ref!(
bytes,
ecdsa::NBYTES + ecdsa::NBYTES,
dilithium::params::PK_SIZE_PACKED
);
self.dilithium_pk.to_bytes(&mut dilithium_bytes);
}
pub fn verify_vartime<H>(&self, msg: &[u8], sign: &Signature) -> bool
where
H: super::Hash256,
{
return self
.ecdsa_pk
.verify_hash_vartime(&H::hash(&ecdsa_input(&msg)), &sign.ecdsa_sign)
&& self.dilithium_pk.verify(
&dilithium_input(&msg, &sign.ecdsa_sign),
array_ref!(sign.dilithium_sign, 0, dilithium::params::SIG_SIZE_PACKED),
);
}
}
impl Signature {
pub const BYTES_LENGTH: usize = 64 + dilithium::params::SIG_SIZE_PACKED;
/// Converts a signature into the CBOR required byte array representation.
///
/// This operation consumes the signature to efficiently use memory.
pub fn to_asn1_der(self) -> Vec<u8> {
let mut bytes = self.ecdsa_sign.to_asn1_der();
bytes.reserve_exact(dilithium::params::SIG_SIZE_PACKED);
bytes.extend(self.dilithium_sign.into_iter());
bytes
}
}
#[cfg(test)]
mod test {
extern crate rng256;
use super::super::sha256::Sha256;
use super::*;
use rng256::Rng256;
pub const ITERATIONS: u32 = 500;
#[test]
fn test_hybrid_seckey_to_bytes_from_bytes() {
let mut rng = rng256::ThreadRng256 {};
for _ in 0..ITERATIONS {
let sk = SecKey::gensk(&mut rng);
let mut bytes = [0; SecKey::BYTES_LENGTH];
sk.to_bytes(&mut bytes);
let decoded_sk = SecKey::from_bytes(&bytes);
assert_eq!(decoded_sk, Some(sk));
}
}
#[test]
fn test_hybrid_pubkey_to_bytes_from_bytes() {
let mut rng = rng256::ThreadRng256 {};
for _ in 0..ITERATIONS {
let sk = SecKey::gensk(&mut rng);
let pk = sk.genpk();
let mut bytes = [0; PubKey::BYTES_LENGTH];
pk.to_bytes(&mut bytes);
let decoded_pk = PubKey::from_bytes(&bytes);
assert_eq!(decoded_pk, Some(pk));
}
}
#[test]
fn test_hybrid_sign_rfc6979_verify_vartime() {
let mut rng = rng256::ThreadRng256 {};
for _ in 0..ITERATIONS {
let msg = rng.gen_uniform_u8x32();
let sk = SecKey::gensk(&mut rng);
let pk = sk.genpk();
let sign = sk.sign_rfc6979::<Sha256>(&msg);
assert!(pk.verify_vartime::<Sha256>(&msg, &sign));
}
}
}

View File

@@ -1,4 +1,4 @@
// Copyright 2019-2022 Google LLC // Copyright 2019 Google LLC
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@@ -16,8 +16,6 @@
#![feature(wrapping_int_impl)] #![feature(wrapping_int_impl)]
extern crate alloc; extern crate alloc;
#[macro_use]
extern crate arrayref;
pub mod aes256; pub mod aes256;
pub mod cbc; pub mod cbc;
@@ -26,30 +24,42 @@ pub mod ecdh;
pub mod ecdsa; pub mod ecdsa;
pub mod hkdf; pub mod hkdf;
pub mod hmac; pub mod hmac;
pub mod hybrid;
pub mod sha256; pub mod sha256;
pub mod util; pub mod util;
// Trait for hash functions that returns a 256-bit hash. /// Trait for hash functions that returns a 256-bit hash.
// The type must be Sized (size known at compile time) so that we can instanciate one on the stack ///
// in the hash() method. /// When you implement this trait, make sure to implement `hash_mut` and `hmac_mut` first, because
/// the default implementations of `hash` and `hmac` rely on it.
pub trait Hash256: Sized { pub trait Hash256: Sized {
fn new() -> Self; fn new() -> Self;
fn update(&mut self, contents: &[u8]); fn update(&mut self, contents: &[u8]);
fn finalize(self) -> [u8; 32]; fn finalize(self, output: &mut [u8; 32]);
fn hash(contents: &[u8]) -> [u8; 32] { fn hash(contents: &[u8]) -> [u8; 32] {
let mut output = [0; 32];
Self::hash_mut(contents, &mut output);
output
}
fn hash_mut(contents: &[u8], output: &mut [u8; 32]) {
let mut h = Self::new(); let mut h = Self::new();
h.update(contents); h.update(contents);
h.finalize() h.finalize(output)
} }
fn hmac(key: &[u8; 32], contents: &[u8]) -> [u8; 32] { fn hmac(key: &[u8; 32], contents: &[u8]) -> [u8; 32] {
hmac::software_hmac_256::<Self>(key, contents) let mut output = [0; 32];
Self::hmac_mut(key, contents, &mut output);
output
}
fn hmac_mut(key: &[u8; 32], contents: &[u8], output: &mut [u8; 32]) {
hmac::software_hmac_256::<Self>(key, contents, output);
} }
} }
// Trait for hash functions that operate on 64-byte input blocks. /// Trait for hash functions that operate on 64-byte input blocks.
pub trait HashBlockSize64Bytes { pub trait HashBlockSize64Bytes {
type State; type State;

View File

@@ -17,6 +17,7 @@ use arrayref::{array_mut_ref, array_ref};
use byteorder::{BigEndian, ByteOrder}; use byteorder::{BigEndian, ByteOrder};
use core::cell::Cell; use core::cell::Cell;
use core::num::Wrapping; use core::num::Wrapping;
use zeroize::Zeroize;
const BLOCK_SIZE: usize = 64; const BLOCK_SIZE: usize = 64;
@@ -32,6 +33,17 @@ pub struct Sha256 {
total_len: usize, total_len: usize,
} }
impl Drop for Sha256 {
// TODO derive Zeroize instead when we upgrade the toolchain
fn drop(&mut self) {
for s in self.state.iter_mut() {
s.0.zeroize();
}
self.block.zeroize();
self.total_len.zeroize();
}
}
impl Hash256 for Sha256 { impl Hash256 for Sha256 {
fn new() -> Self { fn new() -> Self {
assert!(!BUSY.replace(true)); assert!(!BUSY.replace(true));
@@ -72,7 +84,7 @@ impl Hash256 for Sha256 {
} }
} }
fn finalize(mut self) -> [u8; 32] { fn finalize(mut self, output: &mut [u8; 32]) {
// Last block and padding. // Last block and padding.
let cursor_in_block = self.total_len % BLOCK_SIZE; let cursor_in_block = self.total_len % BLOCK_SIZE;
self.block[cursor_in_block] = 0x80; self.block[cursor_in_block] = 0x80;
@@ -97,12 +109,10 @@ impl Hash256 for Sha256 {
Sha256::hash_block(&mut self.state, &self.block); Sha256::hash_block(&mut self.state, &self.block);
// Encode the state's 32-bit words into bytes, using big-endian. // Encode the state's 32-bit words into bytes, using big-endian.
let mut result: [u8; 32] = [0; 32];
for i in 0..8 { for i in 0..8 {
BigEndian::write_u32(array_mut_ref![result, 4 * i, 4], self.state[i].0); BigEndian::write_u32(array_mut_ref![output, 4 * i, 4], self.state[i].0);
} }
BUSY.set(false); BUSY.set(false);
result
} }
} }
@@ -272,7 +282,9 @@ mod test {
h.update(&input[..i]); h.update(&input[..i]);
h.update(&input[i..j]); h.update(&input[i..j]);
h.update(&input[j..]); h.update(&input[j..]);
assert_eq!(h.finalize(), hash.as_slice()); let mut digest = [0; 32];
h.finalize(&mut digest);
assert_eq!(digest, hash.as_slice());
} }
} }
} }

View File

@@ -0,0 +1,55 @@
[package]
name = "opensk"
version = "1.0.0"
authors = [
"Fabian Kaczmarczyck <kaczmarczyck@google.com>",
"Guillaume Endignoux <guillaumee@google.com>",
"Jean-Michel Picod <jmichel@google.com>",
"Julien Cretin <cretin@google.com>",
]
license = "Apache-2.0"
edition = "2018"
rust-version = "1.47"
[dependencies]
sk-cbor = { path = "../cbor" }
crypto = { path = "../crypto" }
persistent_store = { path = "../persistent_store" }
byteorder = { version = "1", default-features = false }
arrayref = "0.3.6"
subtle = { version = "2.2", default-features = false, features = ["nightly"] }
arbitrary = { version = "0.4.7", features = ["derive"], optional = true }
ed25519-compact = { version = "1", default-features = false, optional = true }
rand_core = "0.6.4"
rand = { version = "0.8.5", default-features = false, optional = true }
sha2 = { version = "0.10.6", default-features = false, optional = true }
hmac = { version = "0.12.1", default-features = false, optional = true }
hkdf = { version = "0.12.3", default-features = false, optional = true }
aes = { version = "0.8.2", default-features = false, optional = true }
cbc = { version = "0.1.2", default-features = false, optional = true }
zeroize = { version = "1.5.7", features = ["derive"] }
[dependencies.p256]
version = "0.13.0"
default-features = false
features = ["alloc", "ecdh", "ecdsa"]
optional = true
[features]
default = ["config_command", "with_ctap1"]
config_command = []
debug_ctap = []
std = ["crypto/std", "persistent_store/std", "rand/std_rng", "config_command"]
with_ctap1 = []
vendor_hid = []
fuzz = ["arbitrary", "std"]
ed25519 = ["ed25519-compact"]
rust_crypto = ["p256", "sha2", "hmac", "hkdf", "aes", "cbc"]
[dev-dependencies]
enum-iterator = "0.6.0"
[build-dependencies]
sk-cbor = { path = "../cbor" }
uuid = { version = "0.8", features = ["v4"] }
openssl = "0.10.36"

3
libraries/opensk/fuzz/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
/artifacts/
/corpus/
/target/

View File

@@ -1,5 +1,5 @@
[package] [package]
name = "ctap2-fuzz" name = "opensk-fuzz"
version = "0.0.0" version = "0.0.0"
authors = ["Automatically generated"] authors = ["Automatically generated"]
publish = false publish = false

View File

@@ -0,0 +1,13 @@
[package]
name = "fuzz_helper"
version = "0.1.0"
authors = ["Mingxiao Guo <mingxguo@google.com>"]
license = "Apache-2.0"
edition = "2018"
[dependencies]
arrayref = "0.3.6"
opensk = { path = "../..", features = ["fuzz"] }
crypto = { path = "../../../crypto", features = ['std'] }
sk-cbor = { path = "../../../cbor" }
arbitrary = { version = "0.4.7", features = ["derive"] }

View File

@@ -12,27 +12,22 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
// This explicit "extern crate" is needed to make the linker aware of the
// `libtock_alloc_init` symbol.
extern crate lang_items;
use arbitrary::{Arbitrary, Unstructured}; use arbitrary::{Arbitrary, Unstructured};
use arrayref::array_ref; use arrayref::array_ref;
use core::convert::TryFrom; use core::convert::TryFrom;
use ctap2::api::customization::is_valid; use opensk::api::customization::is_valid;
use ctap2::clock::CtapInstant; use opensk::ctap::command::{
use ctap2::ctap::command::{
AuthenticatorClientPinParameters, AuthenticatorGetAssertionParameters, AuthenticatorClientPinParameters, AuthenticatorGetAssertionParameters,
AuthenticatorMakeCredentialParameters, Command, AuthenticatorMakeCredentialParameters, Command,
}; };
use ctap2::ctap::data_formats::EnterpriseAttestationMode; use opensk::ctap::data_formats::EnterpriseAttestationMode;
use ctap2::ctap::hid::{ use opensk::ctap::hid::{
ChannelID, CtapHidCommand, HidPacket, HidPacketIterator, Message, MessageAssembler, ChannelID, CtapHidCommand, HidPacket, HidPacketIterator, Message, MessageAssembler,
}; };
use ctap2::ctap::{cbor_read, Channel, CtapState}; use opensk::ctap::{cbor_read, Channel, CtapState};
use ctap2::env::test::customization::TestCustomization; use opensk::env::test::customization::TestCustomization;
use ctap2::env::test::TestEnv; use opensk::env::test::TestEnv;
use ctap2::{test_helpers, Ctap, Transport}; use opensk::{test_helpers, Ctap, Transport};
const CHANNEL_BROADCAST: ChannelID = [0xFF, 0xFF, 0xFF, 0xFF]; const CHANNEL_BROADCAST: ChannelID = [0xFF, 0xFF, 0xFF, 0xFF];
@@ -86,15 +81,11 @@ fn initialize(ctap: &mut Ctap<TestEnv>) -> ChannelID {
cmd: CtapHidCommand::Init, cmd: CtapHidCommand::Init,
payload: nonce, payload: nonce,
}; };
let mut assembler_reply = MessageAssembler::new(); let mut assembler_reply = MessageAssembler::default();
let mut result_cid: ChannelID = Default::default(); let mut result_cid: ChannelID = Default::default();
for pkt_request in HidPacketIterator::new(message).unwrap() { for pkt_request in HidPacketIterator::new(message).unwrap() {
for pkt_reply in for pkt_reply in ctap.process_hid_packet(&pkt_request, Transport::MainHid) {
ctap.process_hid_packet(&pkt_request, Transport::MainHid, CtapInstant::new(0)) if let Ok(Some(result)) = assembler_reply.parse_packet(ctap.env(), &pkt_reply, None) {
{
if let Ok(Some(result)) =
assembler_reply.parse_packet(ctap.env(), &pkt_reply, CtapInstant::new(0))
{
result_cid.copy_from_slice(&result.payload[8..12]); result_cid.copy_from_slice(&result.payload[8..12]);
} }
} }
@@ -129,13 +120,11 @@ fn is_type(data: &[u8], input_type: InputType) -> bool {
fn process_message(data: &[u8], ctap: &mut Ctap<TestEnv>) { fn process_message(data: &[u8], ctap: &mut Ctap<TestEnv>) {
let message = raw_to_message(data); let message = raw_to_message(data);
if let Some(hid_packet_iterator) = HidPacketIterator::new(message) { if let Some(hid_packet_iterator) = HidPacketIterator::new(message) {
let mut assembler_reply = MessageAssembler::new(); let mut assembler_reply = MessageAssembler::default();
for pkt_request in hid_packet_iterator { for pkt_request in hid_packet_iterator {
for pkt_reply in for pkt_reply in ctap.process_hid_packet(&pkt_request, Transport::MainHid) {
ctap.process_hid_packet(&pkt_request, Transport::MainHid, CtapInstant::new(0))
{
// Only checks for assembling crashes, not for semantics. // Only checks for assembling crashes, not for semantics.
let _ = assembler_reply.parse_packet(ctap.env(), &pkt_reply, CtapInstant::new(0)); let _ = assembler_reply.parse_packet(ctap.env(), &pkt_reply, None);
} }
} }
} }
@@ -147,12 +136,12 @@ fn process_message(data: &[u8], ctap: &mut Ctap<TestEnv>) {
pub fn process_ctap_any_type(data: &[u8]) -> arbitrary::Result<()> { pub fn process_ctap_any_type(data: &[u8]) -> arbitrary::Result<()> {
let mut unstructured = Unstructured::new(data); let mut unstructured = Unstructured::new(data);
let mut env = TestEnv::new(); let mut env = TestEnv::default();
env.rng().seed_from_u64(u64::arbitrary(&mut unstructured)?); env.seed_rng_from_u64(u64::arbitrary(&mut unstructured)?);
let data = unstructured.take_rest(); let data = unstructured.take_rest();
// Initialize ctap state and hid and get the allocated cid. // Initialize ctap state and hid and get the allocated cid.
let mut ctap = Ctap::new(env, CtapInstant::new(0)); let mut ctap = Ctap::new(env);
let cid = initialize(&mut ctap); let cid = initialize(&mut ctap);
// Wrap input as message with the allocated cid. // Wrap input as message with the allocated cid.
let mut command = cid.to_vec(); let mut command = cid.to_vec();
@@ -179,7 +168,7 @@ fn setup_customization(
fn setup_state( fn setup_state(
unstructured: &mut Unstructured, unstructured: &mut Unstructured,
state: &mut CtapState, state: &mut CtapState<TestEnv>,
env: &mut TestEnv, env: &mut TestEnv,
) -> FuzzResult<()> { ) -> FuzzResult<()> {
if bool::arbitrary(unstructured)? { if bool::arbitrary(unstructured)? {
@@ -194,15 +183,15 @@ fn setup_state(
pub fn process_ctap_specific_type(data: &[u8], input_type: InputType) -> arbitrary::Result<()> { pub fn process_ctap_specific_type(data: &[u8], input_type: InputType) -> arbitrary::Result<()> {
let mut unstructured = Unstructured::new(data); let mut unstructured = Unstructured::new(data);
let mut env = TestEnv::new(); let mut env = TestEnv::default();
env.rng().seed_from_u64(u64::arbitrary(&mut unstructured)?); env.seed_rng_from_u64(u64::arbitrary(&mut unstructured)?);
let data = unstructured.take_rest(); let data = unstructured.take_rest();
if !is_type(data, input_type) { if !is_type(data, input_type) {
return Ok(()); return Ok(());
} }
// Initialize ctap state and hid and get the allocated cid. // Initialize ctap state and hid and get the allocated cid.
let mut ctap = Ctap::new(env, CtapInstant::new(0)); let mut ctap = Ctap::new(env);
let cid = initialize(&mut ctap); let cid = initialize(&mut ctap);
// Wrap input as message with allocated cid and command type. // Wrap input as message with allocated cid and command type.
let mut command = cid.to_vec(); let mut command = cid.to_vec();
@@ -228,11 +217,11 @@ pub fn process_ctap_specific_type(data: &[u8], input_type: InputType) -> arbitra
pub fn process_ctap_structured(data: &[u8], input_type: InputType) -> FuzzResult<()> { pub fn process_ctap_structured(data: &[u8], input_type: InputType) -> FuzzResult<()> {
let unstructured = &mut Unstructured::new(data); let unstructured = &mut Unstructured::new(data);
let mut env = TestEnv::new(); let mut env = TestEnv::default();
env.rng().seed_from_u64(u64::arbitrary(unstructured)?); env.seed_rng_from_u64(u64::arbitrary(unstructured)?);
setup_customization(unstructured, env.customization_mut())?; setup_customization(unstructured, env.customization_mut())?;
let mut state = CtapState::new(&mut env, CtapInstant::new(0)); let mut state = CtapState::new(&mut env);
setup_state(unstructured, &mut state, &mut env)?; setup_state(unstructured, &mut state, &mut env)?;
let command = match input_type { let command = match input_type {
@@ -255,7 +244,6 @@ pub fn process_ctap_structured(data: &[u8], input_type: InputType) -> FuzzResult
&mut env, &mut env,
command, command,
Channel::MainHid(ChannelID::arbitrary(unstructured)?), Channel::MainHid(ChannelID::arbitrary(unstructured)?),
CtapInstant::new(0),
) )
.ok(); .ok();
@@ -266,23 +254,20 @@ pub fn process_ctap_structured(data: &[u8], input_type: InputType) -> FuzzResult
pub fn split_assemble_hid_packets(data: &[u8]) -> arbitrary::Result<()> { pub fn split_assemble_hid_packets(data: &[u8]) -> arbitrary::Result<()> {
let mut unstructured = Unstructured::new(data); let mut unstructured = Unstructured::new(data);
let mut env = TestEnv::new(); let mut env = TestEnv::default();
env.rng().seed_from_u64(u64::arbitrary(&mut unstructured)?); env.seed_rng_from_u64(u64::arbitrary(&mut unstructured)?);
let data = unstructured.take_rest(); let data = unstructured.take_rest();
let message = raw_to_message(data); let message = raw_to_message(data);
if let Some(hid_packet_iterator) = HidPacketIterator::new(message.clone()) { if let Some(hid_packet_iterator) = HidPacketIterator::new(message.clone()) {
let mut assembler = MessageAssembler::new(); let mut assembler = MessageAssembler::default();
let packets: Vec<HidPacket> = hid_packet_iterator.collect(); let packets: Vec<HidPacket> = hid_packet_iterator.collect();
if let Some((last_packet, first_packets)) = packets.split_last() { if let Some((last_packet, first_packets)) = packets.split_last() {
for packet in first_packets { for packet in first_packets {
assert_eq!( assert_eq!(assembler.parse_packet(&mut env, packet, None), Ok(None));
assembler.parse_packet(&mut env, packet, CtapInstant::new(0)),
Ok(None)
);
} }
assert_eq!( assert_eq!(
assembler.parse_packet(&mut env, last_packet, CtapInstant::new(0)), assembler.parse_packet(&mut env, last_packet, None),
Ok(Some(message)) Ok(Some(message))
); );
} }

View File

@@ -1,8 +1,23 @@
// Copyright 2022-2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::api::crypto::EC_FIELD_SIZE;
use crate::ctap::secret::Secret;
use crate::env::Env;
use alloc::vec::Vec; use alloc::vec::Vec;
use persistent_store::{StoreError, StoreUpdate}; use persistent_store::{StoreError, StoreUpdate};
use crate::env::Env;
/// Identifies an attestation. /// Identifies an attestation.
#[derive(Clone, PartialEq, Eq)] #[derive(Clone, PartialEq, Eq)]
pub enum Id { pub enum Id {
@@ -13,7 +28,7 @@ pub enum Id {
#[cfg_attr(feature = "std", derive(Debug, PartialEq, Eq))] #[cfg_attr(feature = "std", derive(Debug, PartialEq, Eq))]
pub struct Attestation { pub struct Attestation {
/// ECDSA private key (big-endian). /// ECDSA private key (big-endian).
pub private_key: [u8; 32], pub private_key: Secret<[u8; EC_FIELD_SIZE]>,
pub certificate: Vec<u8>, pub certificate: Vec<u8>,
} }
@@ -51,11 +66,11 @@ pub fn helper_get(env: &mut impl Env) -> Result<Option<Attestation>, Error> {
(None, None) => return Ok(None), (None, None) => return Ok(None),
_ => return Err(Error::Internal), _ => return Err(Error::Internal),
}; };
if private_key.len() != 32 { if private_key.len() != EC_FIELD_SIZE {
return Err(Error::Internal); return Err(Error::Internal);
} }
Ok(Some(Attestation { Ok(Some(Attestation {
private_key: *array_ref![private_key, 0, 32], private_key: Secret::from_exposed_secret(*array_ref![private_key, 0, EC_FIELD_SIZE]),
certificate, certificate,
})) }))
} }

View File

@@ -0,0 +1,39 @@
// Copyright 2022-2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
pub trait Clock {
/// Stores data for the clock to recognize if this timer is elapsed or not.
///
/// The Clock does not keep track of the timers it creates. Therefore, they should not wrap
/// unexpectedly. A timer that is elapsed may never return to a non-elapsed state.
///
/// A default Timer should return `true` when checked with `is_elapsed`.
type Timer: Default;
/// Creates a new timer that expires after the given time in ms.
fn make_timer(&mut self, milliseconds: usize) -> Self::Timer;
/// Checks whether a given timer is expired.
///
/// Until a timer expires, this function consistently returns false. Once it expires, this
/// function consistently returns true. In particular, it is valid to continue calling this
/// function after the first time it returns true.
fn is_elapsed(&mut self, timer: &Self::Timer) -> bool;
/// Timestamp in microseconds.
///
/// Normal operation only needs relative time, absolute timestamps are useful for debugging.
#[cfg(feature = "debug_ctap")]
fn timestamp_us(&mut self) -> usize;
}

View File

@@ -1,4 +1,4 @@
// Copyright 2022 Google LLC // Copyright 2022-2023 Google LLC
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@@ -12,9 +12,27 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use crate::clock::ClockInt; use core::convert::TryFrom;
use embedded_time::duration::Milliseconds;
use libtock_drivers::usb_ctap_hid::UsbEndpoint; #[derive(Clone, Copy, PartialEq, Eq)]
pub enum UsbEndpoint {
MainHid = 1,
#[cfg(feature = "vendor_hid")]
VendorHid = 2,
}
impl TryFrom<usize> for UsbEndpoint {
type Error = SendOrRecvError;
fn try_from(endpoint_num: usize) -> Result<Self, SendOrRecvError> {
match endpoint_num {
1 => Ok(UsbEndpoint::MainHid),
#[cfg(feature = "vendor_hid")]
2 => Ok(UsbEndpoint::VendorHid),
_ => Err(SendOrRecvError),
}
}
}
pub enum SendOrRecvStatus { pub enum SendOrRecvStatus {
Timeout, Timeout,
@@ -27,9 +45,5 @@ pub struct SendOrRecvError;
pub type SendOrRecvResult = Result<SendOrRecvStatus, SendOrRecvError>; pub type SendOrRecvResult = Result<SendOrRecvStatus, SendOrRecvError>;
pub trait HidConnection { pub trait HidConnection {
fn send_and_maybe_recv( fn send_and_maybe_recv(&mut self, buf: &mut [u8; 64], timeout_ms: usize) -> SendOrRecvResult;
&mut self,
buf: &mut [u8; 64],
timeout: Milliseconds<ClockInt>,
) -> SendOrRecvResult;
} }

Some files were not shown because too many files have changed in this diff Show More