26 Commits

Author SHA1 Message Date
kaczmarczyck
7ab1b568fb Updated README to reflect maintenance status (#660)
* Updated README to reflect maintenance status

This PR is to be merged after the branches are reworked.

* FIDO -> CTAP

* Wording change to default branch
2023-11-09 14:28:39 +01:00
kaczmarczyck
c85a01579f Updates the metadata to MDS 3 (#654) 2023-11-08 11:05:32 +01:00
kaczmarczyck
bc0b30bc9e Removes broken workflows (#656)
We have problems compiling, and therefore workflows are deleted.
2023-11-08 10:05:46 +01:00
kaczmarczyck
5b67f3f9a8 Adds Bibtex for our paper to the README (#646)
* Adds Bibtex for our paper to the README

* Reference to proceedings instead of eprint

* Add date to News section
2023-08-24 12:51:56 +02:00
kaczmarczyck
244a199316 Links PQC work on stable README (#638) 2023-07-14 15:50:07 +02:00
Jean-Michel Picod
1b70583243 Fix nRF52 boards with bootloader (#560)
Backporting patch from develop branch which saves and restores
the bootloader parameters in case we need to erase UICR at startup.
2022-10-18 17:31:10 +02:00
kaczmarczyck
3b9274e93e updates libfido to version 1 (#558) 2022-10-11 01:36:02 +02:00
kaczmarczyck
a969faaaa0 Submit Cargo.lock (#555)
* submits Cargo.lock files

* removes the unused test runner from libtock-rs for less depepdencies
2022-10-10 15:34:05 +02:00
kaczmarczyck
a79abc209a uses latest in workflows (#528) 2022-08-24 15:16:46 +02:00
kaczmarczyck
b396fc0f36 Set bumpalo version for crypto library (#533) 2022-08-24 15:16:46 +02:00
kaczmarczyck
f2496a8e6d Ported documentation (#413)
* ported documentation from develop

* adapted instructions

* fix broken English
2021-11-19 17:55:12 +01:00
kaczmarczyck
e4d82087a8 Fix desktop tests for bugfix and stable (#395)
* fix build and lint problems

* fix coveralls workflow by setting a working toolchain
2021-11-19 17:55:12 +01:00
Fabian Kaczmarczyck
c847e7060a use f-strings and test with 3.9 2021-11-19 17:55:12 +01:00
Minjun
52343ed86f Added one python package required by one of the tockloader dependencies; (#376)
Signed-off-by: minjun <xi.minjun@gmail.com>
2021-11-19 17:55:12 +01:00
kaczmarczyck
57ffafaa24 Update bugfix with changes from stable (#377)
* Add Feitian OpenSK USB Dongle (#257) (#258)

Co-authored-by: superskybird <skybird.le@gmail.com>

Co-authored-by: Geoffrey <geoffrey@ftsafe.com>
Co-authored-by: superskybird <skybird.le@gmail.com>

* Bugfix (#304)

* Add Feitian OpenSK USB Dongle (#257)

Co-authored-by: superskybird <skybird.le@gmail.com>

* Fix `config.py` tool according to the new API of fido2 python package (#284)

* Fix fido2 API update.

Since fido2 0.8.1 the device descriptor moved to NamedTuple, breaking
our configuration tool.
Code is now updated accordingly and the setup script ensure we're
using the correct version for fido2 package.

* Make Yapf happy

* Fix missing update for fido2 0.9.1

Also split the comment into 2 lines so that the touch is not hidden
at the end of the screen.

* adds README changes, logo and certificate (#285)

Co-authored-by: Geoffrey <geoffrey@ftsafe.com>
Co-authored-by: superskybird <skybird.le@gmail.com>
Co-authored-by: kaczmarczyck <43844792+kaczmarczyck@users.noreply.github.com>

* Compare all timestamps in UTC timezone. (#309)

* Merge bugfix into stable (#324)

* Add Feitian OpenSK USB Dongle (#257)

Co-authored-by: superskybird <skybird.le@gmail.com>

* Fix `config.py` tool according to the new API of fido2 python package (#284)

* Fix fido2 API update.

Since fido2 0.8.1 the device descriptor moved to NamedTuple, breaking
our configuration tool.
Code is now updated accordingly and the setup script ensure we're
using the correct version for fido2 package.

* Make Yapf happy

* Fix missing update for fido2 0.9.1

Also split the comment into 2 lines so that the touch is not hidden
at the end of the screen.

* adds README changes, logo and certificate (#285)

* Fix broken parsing. (#317)

* Fix broken parsing.

By setting the default value before pre-parsing we ensure that the item
can't be None. As an extra safety the custom action also checks for
None.

Co-authored-by: Geoffrey <geoffrey@ftsafe.com>
Co-authored-by: superskybird <skybird.le@gmail.com>
Co-authored-by: kaczmarczyck <43844792+kaczmarczyck@users.noreply.github.com>

* Coveralls workflow applied also to stable (#342)

* Coveralls (#339)

* Add code coverage report as part of the workflows

* Remove -Clink-dead-code which seems to be problematic

* Manually set features to avoid debug_* failing unit tests.

* Update badges

* Add libraries directory to trigger code coverage reporting.

* Fix coveralls badge not pointing to the branch

* Badges to stable branch

* adds and links new security policy

* Add erase_storage application example (#352)

* Fix coveralls workflow (#356)

* Return error instead of debug assert (#363)

With dirty storage we hit the assert. Returning an error permits to continue to
catch if the invariant is broken for normal operation while being able to
continue fuzzing with dirty storage.

* Remove elf2tab dev-dependency (#366)

We don't use it anymore. Not sure when we used to use it.

Fixes #364

Co-authored-by: kaczmarczyck <43844792+kaczmarczyck@users.noreply.github.com>

* Install Rust tools with stable compiler

We only need the frozen nightly for Tock (and maybe the app).

* fix python lint with encoding, see commit 7418196

* more encoding

Co-authored-by: Jean-Michel Picod <jmichel@google.com>
Co-authored-by: Geoffrey <geoffrey@ftsafe.com>
Co-authored-by: superskybird <skybird.le@gmail.com>
Co-authored-by: Julien Cretin <cretin@google.com>
2021-11-19 17:55:12 +01:00
Julien Cretin
420f062a21 Install Rust tools with stable compiler
We only need the frozen nightly for Tock (and maybe the app).
2021-09-09 07:04:24 +02:00
Julien Cretin
e02eaa2cac Remove elf2tab dev-dependency (#366)
We don't use it anymore. Not sure when we used to use it.

Fixes #364

Co-authored-by: kaczmarczyck <43844792+kaczmarczyck@users.noreply.github.com>
2021-08-10 13:20:33 +02:00
Julien Cretin
5c7df89198 Return error instead of debug assert (#363)
With dirty storage we hit the assert. Returning an error permits to continue to
catch if the invariant is broken for normal operation while being able to
continue fuzzing with dirty storage.
2021-08-10 13:09:22 +02:00
Jean-Michel Picod
42050f96af Fix coveralls workflow (#356) 2021-08-02 18:05:07 +02:00
Julien Cretin
40d6040d41 Add erase_storage application example (#352) 2021-08-02 09:51:57 +02:00
Fabian Kaczmarczyck
eb65c4f07f adds and links new security policy 2021-07-09 13:05:18 +02:00
Jean-Michel Picod
2de660ae4d Coveralls workflow applied also to stable (#342)
* Coveralls (#339)

* Add code coverage report as part of the workflows

* Remove -Clink-dead-code which seems to be problematic

* Manually set features to avoid debug_* failing unit tests.

* Update badges

* Add libraries directory to trigger code coverage reporting.

* Fix coveralls badge not pointing to the branch

* Badges to stable branch
2021-07-06 11:22:05 +02:00
Jean-Michel Picod
7e5e2a665f Merge bugfix into stable (#324)
* Add Feitian OpenSK USB Dongle (#257)

Co-authored-by: superskybird <skybird.le@gmail.com>

* Fix `config.py` tool according to the new API of fido2 python package (#284)

* Fix fido2 API update.

Since fido2 0.8.1 the device descriptor moved to NamedTuple, breaking
our configuration tool.
Code is now updated accordingly and the setup script ensure we're
using the correct version for fido2 package.

* Make Yapf happy

* Fix missing update for fido2 0.9.1

Also split the comment into 2 lines so that the touch is not hidden
at the end of the screen.

* adds README changes, logo and certificate (#285)

* Fix broken parsing. (#317)

* Fix broken parsing.

By setting the default value before pre-parsing we ensure that the item
can't be None. As an extra safety the custom action also checks for
None.

Co-authored-by: Geoffrey <geoffrey@ftsafe.com>
Co-authored-by: superskybird <skybird.le@gmail.com>
Co-authored-by: kaczmarczyck <43844792+kaczmarczyck@users.noreply.github.com>
2021-06-09 16:50:00 +02:00
Jean-Michel Picod
5e682d9e17 Compare all timestamps in UTC timezone. (#309) 2021-04-15 17:22:54 +02:00
Jean-Michel Picod
748b7e7fb8 Bugfix (#304)
* Add Feitian OpenSK USB Dongle (#257)

Co-authored-by: superskybird <skybird.le@gmail.com>

* Fix `config.py` tool according to the new API of fido2 python package (#284)

* Fix fido2 API update.

Since fido2 0.8.1 the device descriptor moved to NamedTuple, breaking
our configuration tool.
Code is now updated accordingly and the setup script ensure we're
using the correct version for fido2 package.

* Make Yapf happy

* Fix missing update for fido2 0.9.1

Also split the comment into 2 lines so that the touch is not hidden
at the end of the screen.

* adds README changes, logo and certificate (#285)

Co-authored-by: Geoffrey <geoffrey@ftsafe.com>
Co-authored-by: superskybird <skybird.le@gmail.com>
Co-authored-by: kaczmarczyck <43844792+kaczmarczyck@users.noreply.github.com>
2021-04-13 14:59:47 +02:00
Jean-Michel Picod
b0c1b73897 Add Feitian OpenSK USB Dongle (#257) (#258)
Co-authored-by: superskybird <skybird.le@gmail.com>

Co-authored-by: Geoffrey <geoffrey@ftsafe.com>
Co-authored-by: superskybird <skybird.le@gmail.com>
2021-01-14 12:32:28 +01:00
237 changed files with 8264 additions and 29311 deletions

View File

@@ -2,10 +2,5 @@ Fixes #<issue_number_goes_here>
> It's a good idea to open an issue first for discussion. > It's a good idea to open an issue first for discussion.
- [ ] Local tests pass (running `run_desktop_tests.sh`) - [ ] Tests pass
- [ ] Tested against boards
- [ ] Nordic nRF52840 DK
- [ ] Nordic nRF52840 Dongle (JTAG programmed)
- [ ] Nordic nRF52840 Dongle (DFU programmed)
- [ ] Makerdiary nRF52840 MDK USB Dongle
- [ ] Appropriate changes to README are included in PR - [ ] Appropriate changes to README are included in PR

9
.github/actions-rs/grcov.yml vendored Normal file
View File

@@ -0,0 +1,9 @@
branch: true
ignore-not-existing: true
llvm: true
filter: covered
output-type: lcov
output-path: ./lcov.info
ignore:
- "third_party/*"
- "/*"

View File

@@ -1,46 +0,0 @@
#!/bin/bash
# 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.
cd "$(dirname "$0")"
# New output file is $1
# Old output file is $2
TMP=comment.md
WARNING="Note: numbers above are a result of guesswork. They are not 100% correct and never will be."
NEW_SIZE=$(cat "$1" | sed -nr 's/.*100.0% (.*)KiB .text.*/\1/p')
OLD_SIZE=$(cat "$2" | sed -nr 's/.*100.0% (.*)KiB .text.*/\1/p')
echo "
OLD $OLD_SIZE kiB
NEW $NEW_SIZE kiB" > "$TMP"
echo "
Output of cargo bloat
======================
" >> "$TMP"
echo "Including PR" >> "$TMP"
cat "$1" >> "$TMP"
echo "Base branch" >> "$TMP"
cat "$2" >> "$TMP"
COMMENT="$(cat $TMP | sed "s/$WARNING//g" | sed 's/%/%25/g' | sed -z 's/\n/%0A/g')"
# No output for equality is intentional.
if (( $(echo "$NEW_SIZE > $OLD_SIZE" | bc -l) )); then
echo "::warning file=.github/workflows/cargo_bloat.yml,title=Binary size::$COMMENT"
fi
if (( $(echo "$NEW_SIZE < $OLD_SIZE" | bc -l) )); then
echo "::notice file=.github/workflows/cargo_bloat.yml,title=Binary size::$COMMENT"
fi

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

@@ -1,25 +0,0 @@
name: Security audit
on:
schedule:
- cron: '0 0 * * *'
jobs:
audit:
runs-on: ubuntu-latest
if: github.repository == 'google/OpenSK'
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/audit-check@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,47 +0,0 @@
name: Binary size report
on: pull_request
jobs:
cargo_bloat:
runs-on: ubuntu-latest
steps:
# Setup
- uses: actions/setup-python@v1
with:
python-version: 3.7
- name: Install Python dependencies
run: python -m pip install --upgrade pip setuptools wheel
- uses: actions-rs/cargo@v1
with:
command: install
args: cargo-bloat
# First run: PR
- uses: actions/checkout@v2
with:
submodules: true
- name: Install Rust toolchain
run: rustup show
- name: Set up OpenSK
run: ./setup.sh
- 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
# Second run: PR
- uses: actions/checkout@v2
with:
submodules: true
ref: ${{ github.base_ref }}
path: OpenSK_base
- name: Install old Rust toolchain
working-directory: ./OpenSK_base
run: rustup show
- name: Set up OpenSK
working-directory: ./OpenSK_base
run: ./setup.sh
- name: Run bloat on 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"
- 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

View File

@@ -1,102 +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
- name: Check bootloader
uses: actions-rs/cargo@v1
with:
command: check
args: --manifest-path bootloader/Cargo.toml --target thumbv7em-none-eabi --release

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

View File

@@ -1,28 +0,0 @@
name: CIFuzz
on:
pull_request:
branches:
- develop
jobs:
Fuzzing:
runs-on: ubuntu-latest
steps:
- name: Build Fuzzers
id: build
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
with:
oss-fuzz-project-name: 'opensk'
dry-run: false
language: rust
- name: Run Fuzzers
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
with:
oss-fuzz-project-name: 'opensk'
fuzz-seconds: 600
dry-run: false
- name: Upload Crash
uses: actions/upload-artifact@v1
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts
path: ./out/artifacts

View File

@@ -1,48 +0,0 @@
---
name: OpenSK code coverage report
on:
push:
paths:
- 'src/**/*.rs'
- 'libraries/**/*.rs'
pull_request:
types: [opened, synchronize, reopened]
jobs:
coveralls:
name: OpenSK code coverage
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: Install llvm tools
run: rustup component add llvm-tools-preview
- name: Install grcov
run: if [[ ! -e ~/.cargo/bin/grcov ]]; then cargo +stable install grcov; fi
- uses: actions-rs/cargo@v1
with:
command: test
args: --features "with_ctap1,vendor_hid,ed25519,with_nfc,std" --no-fail-fast
env:
RUSTFLAGS: "-Zinstrument-coverage"
LLVM_PROFILE_FILE: "opensk-%p-%m.profraw"
- 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/*"
- uses: coverallsapp/github-action@1.1.3
name: upload report to coveralls
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
path-to-lcov: "./lcov.info"

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

@@ -1,45 +0,0 @@
---
name: Check that binaries are reproducible
on:
push:
pull_request:
types: [opened, synchronize, reopened]
jobs:
check_hashes:
strategy:
matrix:
os: [ubuntu-latest, macos-10.15]
fail-fast: false
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: Use sample cryptographic material
run: rm -R crypto_data/ && cp -r reproducible/sample_crypto_data crypto_data
- name: Computing cryptographic hashes
run: ./maintainers/reproduce_hashes.sh
- name: Upload reproduced binaries
uses: actions/upload-artifact@v1
with:
name: reproduced-${{ matrix.os }}
path: reproducible/reproduced.tar
- name: Comparing binary sizes
if: always()
run: git diff --no-index reproducible/reference_elf2tab_${{ matrix.os }}.txt reproducible/elf2tab.txt || true
- name: Comparing cryptographic hashes
if: always()
run: git diff --no-index reproducible/reference_binaries_${{ matrix.os }}.sha256sum reproducible/binaries.sha256sum || true

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

3
.gitignore vendored
View File

@@ -1,6 +1,3 @@
fuzz/artifacts
fuzz/corpus
fuzz/coverage
target/ target/
# Local installation of elf2tab. # Local installation of elf2tab.

543
.pylintrc
View File

@@ -1,318 +1,135 @@
# This Pylint rcfile contains a best-effort configuration to uphold the # File taken from Tensor2Tensor project
# best-practices and style described in the Google Python style guide: # https://github.com/tensorflow/tensor2tensor/blob/master/pylintrc
# https://google.github.io/styleguide/pyguide.html
#
# Its canonical open-source location is:
# https://google.github.io/styleguide/pylintrc
[MAIN] [MASTER]
# Files or directories to be skipped. They should be base names, not paths.
ignore=third_party
# Files or directories matching the regex patterns are skipped. The regex
# matches against base names, not paths.
ignore-patterns=
# Pickle collected data for later comparisons. # Pickle collected data for later comparisons.
persistent=no persistent=no
# List of plugins (as comma separated values of python modules names) to load, # Set the cache size for astng objects.
# usually to register additional checkers. cache-size=500
# Ignore Py3 files
ignore=get_references_web.py,get_references_web_single_group.py
load-plugins= load-plugins=
pylint.extensions.bad_builtin,
# Use multiple processes to speed up Pylint. pylint.extensions.docparams,
jobs=4 pylint.extensions.docstyle,
pylint.extensions.redefined_variable_type,
# Allow loading of arbitrary C extensions. Extensions are imported into the pylint.extensions.overlapping_exceptions,
# active Python interpreter and may run arbitrary code.
unsafe-load-any-extension=no
[MESSAGES CONTROL]
# Only show warnings with the listed confidence levels. Leave empty to show
# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED
confidence=
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
# multiple time (only on the command line, not in the configuration file where
# it should appear only once). See also the "--disable" option for examples.
#enable=
# Disable the message, report, category or checker with the given id(s). You
# can either give multiple identifiers separated by comma (,) or put this
# option multiple times (only on the command line, not in the configuration
# file where it should appear only once).You can also use "--disable=all" to
# disable everything first and then reenable specific checks. For example, if
# you want to run only the similarities checker, you can use "--disable=all
# --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use"--disable=all --enable=classes
# --disable=W"
disable=abstract-method,
apply-builtin,
arguments-differ,
attribute-defined-outside-init,
backtick,
bad-option-value,
basestring-builtin,
buffer-builtin,
c-extension-no-member,
consider-using-enumerate,
cmp-builtin,
cmp-method,
coerce-builtin,
coerce-method,
delslice-method,
div-method,
duplicate-code,
eq-without-hash,
execfile-builtin,
file-builtin,
filter-builtin-not-iterating,
fixme,
getslice-method,
global-statement,
hex-method,
idiv-method,
implicit-str-concat-in-sequence,
import-error,
import-self,
import-star-module-level,
inconsistent-return-statements,
input-builtin,
intern-builtin,
invalid-str-codec,
locally-disabled,
long-builtin,
long-suffix,
map-builtin-not-iterating,
misplaced-comparison-constant,
missing-function-docstring,
metaclass-assignment,
next-method-called,
next-method-defined,
no-absolute-import,
no-else-break,
no-else-continue,
no-else-raise,
no-else-return,
no-init, # added
no-member,
no-name-in-module,
no-self-use,
nonzero-method,
oct-method,
old-division,
old-ne-operator,
old-octal-literal,
old-raise-syntax,
parameter-unpacking,
print-statement,
raising-string,
range-builtin-not-iterating,
raw_input-builtin,
rdiv-method,
reduce-builtin,
relative-import,
reload-builtin,
round-builtin,
setslice-method,
signature-differs,
standarderror-builtin,
suppressed-message,
sys-max-int,
too-few-public-methods,
too-many-ancestors,
too-many-arguments,
too-many-boolean-expressions,
too-many-branches,
too-many-instance-attributes,
too-many-locals,
too-many-nested-blocks,
too-many-public-methods,
too-many-return-statements,
too-many-statements,
trailing-newlines,
unichr-builtin,
unicode-builtin,
unnecessary-pass,
unpacking-in-except,
unrecognized-option,
useless-else-on-loop,
useless-object-inheritance,
useless-suppression,
using-cmp-argument,
wrong-import-order,
xrange-builtin,
zip-builtin-not-iterating,
[REPORTS] [REPORTS]
# Set the output format. Available formats are text, parseable, colorized, msvs # Set the output format.
# (visual studio) and html. You can also give a reporter class, eg # output-format=sorted-text
# mypackage.mymodule.MyReporterClass.
output-format=text
# Put messages in a separate file for each module / package specified on the # Put messages in a separate file for each module / package specified on the
# command line instead of printing them on stdout. Reports (if any) will be # command line instead of printing them on stdout. Reports (if any) will be
# written in a file name "pylint_global.[txt|html]". This option is deprecated # written in a file name "pylint_global.[txt|html]".
# and it will be removed in Pylint 2.0.
files-output=no files-output=no
# Tells whether to display a full report or only the messages # Tells whether to display a full report or only the messages.
reports=no reports=no
# Python expression which should return a note less than 10 (10 is the highest # Disable the report(s) with the given id(s).
# note). You have access to the variables errors warning, statement which disable-report=R0001,R0002,R0003,R0004,R0101,R0102,R0201,R0202,R0220,R0401,R0402,R0701,R0801,R0901,R0902,R0903,R0904,R0911,R0912,R0913,R0914,R0915,R0921,R0922,R0923
# respectively contain the number of errors / warnings messages and the total
# number of statements analyzed. This is used by the global evaluation report
# (RP0004).
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
# Template used to display messages. This is a python new-style format string # Error message template (continued on second line)
# used to format the message information. See doc for all details msg-template={msg_id}:{line:3} {obj}: {msg} [{symbol}]
#msg-template=
# We don't need evaluation score
score=no
[MESSAGES CONTROL]
# List of checkers and warnings to enable.
enable=indexing-exception,old-raise-syntax
# List of checkers and warnings to disable.
disable=design,similarities,no-self-use,attribute-defined-outside-init,locally-disabled,star-args,pointless-except,bad-option-value,global-statement,fixme,suppressed-message,useless-suppression,locally-enabled,file-ignored,multiple-imports,c-extension-no-member,trailing-newlines,unsubscriptable-object,misplaced-comparison-constant,no-member,abstract-method,no-else-return,missing-docstring,wrong-import-order,protected-access,inconsistent-return-statements,invalid-unary-operand-type,import-error,no-name-in-module,arguments-differ,not-context-manager,unused-argument
[BASIC] [BASIC]
# Required attributes for module, separated by a comma
required-attributes=
# Regular expression which should only match the name
# of functions or classes which do not require a docstring.
no-docstring-rgx=(__.*__|main)
# Min length in lines of a function that requires a docstring.
docstring-min-length=10
# Regular expression which should only match correct module names. The
# leading underscore is sanctioned for private modules by Google's style
# guide.
#
# There are exceptions to the basic rule (_?[a-z][a-z0-9_]*) to cover
# requirements of Python's module system.
module-rgx=^(_?[a-z][a-z0-9_]*)|__init__$
# Regular expression which should only match correct module level names
const-rgx=^(_?[A-Z][A-Z0-9_]*|__[a-z0-9_]+__|_?[a-z][a-z0-9_]*)$
# Regular expression which should only match correct class attribute
class-attribute-rgx=^(_?[A-Z][A-Z0-9_]*|__[a-z0-9_]+__|_?[a-z][a-z0-9_]*)$
# Regular expression which should only match correct class names
class-rgx=^_?[A-Z][a-zA-Z0-9]*$
# Regular expression which should only match correct function names.
# 'camel_case' and 'snake_case' group names are used for consistency of naming
# styles across functions and methods.
function-rgx=^(?:(?P<exempt>setUp|tearDown|setUpModule|tearDownModule)|(?P<camel_case>_?[A-Z][a-zA-Z0-9]*)|(?P<snake_case>_?[a-z][a-z0-9_]*))$
# Regular expression which should only match correct method names.
# 'camel_case' and 'snake_case' group names are used for consistency of naming
# styles across functions and methods. 'exempt' indicates a name which is
# consistent with all naming styles.
method-rgx=(?x)
^(?:(?P<exempt>_[a-z0-9_]+__|runTest|setUp|tearDown|setUpTestCase
|tearDownTestCase|setupSelf|tearDownClass|setUpClass
|(test|assert)_*[A-Z0-9][a-zA-Z0-9_]*|next)
|(?P<camel_case>_{0,2}[A-Z][a-zA-Z0-9_]*)
|(?P<snake_case>_{0,2}[a-z][a-z0-9_]*))$
# Regular expression which should only match correct instance attribute names
attr-rgx=^_{0,2}[a-z][a-z0-9_]*$
# Regular expression which should only match correct argument names
argument-rgx=^[a-z][a-z0-9_]*$
# Regular expression which should only match correct variable names
variable-rgx=^[a-z][a-z0-9_]*$
# Regular expression which should only match correct list comprehension /
# generator expression variable names
inlinevar-rgx=^[a-z][a-z0-9_]*$
# Good variable names which should always be accepted, separated by a comma # Good variable names which should always be accepted, separated by a comma
good-names=main,_ good-names=main,_
# Bad variable names which should always be refused, separated by a comma # Bad variable names which should always be refused, separated by a comma
bad-names= bad-names=
# Colon-delimited sets of names that determine each other's naming style when # List of builtins function names that should not be used, separated by a comma
# the name regexes allow several styles. bad-functions=input,apply,reduce
name-group=
# Include a hint for the correct naming format with invalid-name # List of decorators that define properties, such as abc.abstractproperty.
include-naming-hint=no property-classes=abc.abstractproperty
# List of decorators that produce properties, such as abc.abstractproperty. Add
# to this list to register other decorators that produce valid properties.
property-classes=abc.abstractproperty,cached_property.cached_property,cached_property.threaded_cached_property,cached_property.cached_property_with_ttl,cached_property.threaded_cached_property_with_ttl
# Regular expression matching correct function names
function-rgx=^(?:(?P<exempt>setUp|tearDown|setUpModule|tearDownModule)|(?P<camel_case>_?[A-Z][a-zA-Z0-9]*)|(?P<snake_case>_?[a-z][a-z0-9_]*))$
# Regular expression matching correct variable names
variable-rgx=^[a-z][a-z0-9_]*$
# Regular expression matching correct constant names
const-rgx=^(_?[A-Z][A-Z0-9_]*|__[a-z0-9_]+__|_?[a-z][a-z0-9_]*)$
# Regular expression matching correct attribute names
attr-rgx=^_{0,2}[a-z][a-z0-9_]*$
# Regular expression matching correct argument names
argument-rgx=^[a-z][a-z0-9_]*$
# Regular expression matching correct class attribute names
class-attribute-rgx=^(_?[A-Z][A-Z0-9_]*|__[a-z0-9_]+__|_?[a-z][a-z0-9_]*)$
# Regular expression matching correct inline iteration names
inlinevar-rgx=^[a-z][a-z0-9_]*$
# Regular expression matching correct class names
class-rgx=^_?[A-Z][a-zA-Z0-9]*$
# Regular expression matching correct module names
module-rgx=^(_?[a-z][a-z0-9_]*|__init__)$
# Regular expression matching correct method names
method-rgx=(?x)^(?:(?P<exempt>_[a-z0-9_]+__|runTest|setUp|tearDown|setUpTestCase|tearDownTestCase|setupSelf|tearDownClass|setUpClass|(test|assert)_*[A-Z0-9][a-zA-Z0-9_]*|next)|(?P<camel_case>_{0,2}[A-Z][a-zA-Z0-9_]*)|(?P<snake_case>_{0,2}[a-z][a-z0-9_]*))$
# Regular expression which should only match function or class names that do
# not require a docstring.
no-docstring-rgx=(__.*__|main|test.*|.*test|.*Test)$
# Minimum line length for functions/classes that require docstrings, shorter
# ones are exempt.
docstring-min-length=10
[TYPECHECK] [TYPECHECK]
# List of decorators that produce context managers, such as
# contextlib.contextmanager. Add to this list to register other decorators that
# produce valid context managers.
contextmanager-decorators=contextlib.contextmanager,contextlib2.contextmanager
# Tells whether missing members accessed in mixin class should be ignored. A # Tells whether missing members accessed in mixin class should be ignored. A
# mixin class is detected if its name ends with "mixin" (case insensitive). # mixin class is detected if its name ends with "mixin" (case insensitive).
ignore-mixin-members=yes ignore-mixin-members=yes
# List of module names for which member attributes should not be checked # List of decorators that create context managers from functions, such as
# (useful for modules/projects where namespaces are manipulated during runtime # contextlib.contextmanager.
# and thus existing member attributes cannot be deduced by static analysis. It contextmanager-decorators=contextlib.contextmanager,contextlib2.contextmanager
# supports qualified module names, as well as Unix pattern matching.
ignored-modules=
# List of class names for which member attributes should not be checked (useful
# for classes with dynamically set attributes). This supports the use of
# qualified names.
ignored-classes=optparse.Values,thread._local,_thread._local
# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E1101 when accessed. Python regular
# expressions are accepted.
generated-members=
[FORMAT]
# Maximum number of characters on a single line.
max-line-length=80
# TODO(https://github.com/PyCQA/pylint/issues/3352): Direct pylint to exempt
# lines made too long by directives to pytype.
# Regexp for a line that is allowed to be longer than the limit.
ignore-long-lines=(?x)(
^\s*(\#\ )?<?https?://\S+>?$|
^\s*(from\s+\S+\s+)?import\s+.+$)
# Allow the body of an if to be on the same line as the test if there is no
# else.
single-line-if-stmt=yes
# List of optional constructs for which whitespace checking is disabled. `dict-
# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
# `trailing-comma` allows a space between comma and closing bracket: (a, ).
# `empty-line` allows space-only lines.
no-space-check=
# Maximum number of lines in a module
max-module-lines=99999
# String used as indentation unit. The internal Google style guide mandates 2
# spaces. Google's externaly-published style guide says 4, consistent with
# PEP 8. Here, we use 2 spaces, for conformity with many open-sourced Google
# projects (like TensorFlow).
indent-string=' '
# Number of spaces of indent required inside a hanging or continued line.
indent-after-paren=4
# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
expected-line-ending-format=
[MISCELLANEOUS]
# List of note tags to take in consideration, separated by a comma.
notes=TODO
[STRING]
# This flag controls whether inconsistent-quotes generates a warning when the
# character used as a quote delimiter is used inconsistently within a module.
check-quote-consistency=yes
[VARIABLES] [VARIABLES]
@@ -320,123 +137,99 @@ check-quote-consistency=yes
# Tells whether we should check for unused import in __init__ files. # Tells whether we should check for unused import in __init__ files.
init-import=no init-import=no
# A regular expression matching the name of dummy variables (i.e. expectedly # A regular expression matching names used for dummy variables (i.e. not used).
# not used).
dummy-variables-rgx=^\*{0,2}(_$|unused_|dummy_) dummy-variables-rgx=^\*{0,2}(_$|unused_|dummy_)
# List of additional names supposed to be defined in builtins. Remember that # List of additional names supposed to be defined in builtins. Remember that
# you should avoid to define new builtins when possible. # you should avoid to define new builtins when possible.
additional-builtins= additional-builtins=
# List of strings which can identify a callback function by name. A callback
# name must start or end with one of those strings.
callbacks=cb_,_cb
# List of qualified module names which can have objects that can redefine [CLASSES]
# builtins.
redefining-builtins-modules=six,six.moves,past.builtins,future.builtins,functools # List of method names used to declare (i.e. assign) instance attributes.
defining-attr-methods=__init__,__new__,setUp
# "class_" is also a valid for the first argument to a class method.
valid-classmethod-first-arg=cls,class_
[LOGGING] [EXCEPTIONS]
# Logging modules to check that the string format arguments are in logging overgeneral-exceptions=StandardError,Exception,BaseException
# function parameter format
logging-modules=logging,absl.logging,tensorflow.io.logging
[SIMILARITIES]
# Minimum lines number of a similarity.
min-similarity-lines=4
# Ignore comments when computing similarities.
ignore-comments=yes
# Ignore docstrings when computing similarities.
ignore-docstrings=yes
# Ignore imports when computing similarities.
ignore-imports=no
[SPELLING]
# Spelling dictionary name. Available dictionaries: none. To make it working
# install python-enchant package.
spelling-dict=
# List of comma separated words that should not be checked.
spelling-ignore-words=
# A path to a file that contains private dictionary; one word per line.
spelling-private-dict-file=
# Tells whether to store unknown words to indicated private dictionary in
# --spelling-private-dict-file option instead of raising a message.
spelling-store-unknown-words=no
[IMPORTS] [IMPORTS]
# Deprecated modules which should not be used, separated by a comma # Deprecated modules which should not be used, separated by a comma
deprecated-modules=regsub, deprecated-modules=regsub,TERMIOS,Bastion,rexec,sets
TERMIOS,
Bastion,
rexec,
sets
# Create a graph of every (i.e. internal and external) dependencies in the
# given file (report RP0402 must not be disabled)
import-graph=
# Create a graph of external dependencies in the given file (report RP0402 must
# not be disabled)
ext-import-graph=
# Create a graph of internal dependencies in the given file (report RP0402 must
# not be disabled)
int-import-graph=
# Force import order to recognize a module as part of the standard
# compatibility libraries.
known-standard-library=
# Force import order to recognize a module as part of a third party library.
known-third-party=enchant, absl
# Analyse import fallback blocks. This can be used to support both Python 2 and
# 3 compatible code, which means that the block might have code that exists
# only in one or another interpreter, leading to false positives when analysed.
analyse-fallback-blocks=no
[CLASSES] [FORMAT]
# List of method names used to declare (i.e. assign) instance attributes. # Maximum number of characters on a single line.
defining-attr-methods=__init__, max-line-length=80
__new__,
setUp
# List of member names, which should be excluded from the protected access # Regexp for a line that is allowed to be longer than the limit.
# warning. # This "ignore" regex is today composed of several independent parts:
exclude-protected=_asdict, # (1) Long import lines
_fields, # (2) URLs in comments or pydocs. Detecting URLs by regex is a hard problem and
_replace, # no amount of tweaking will make a perfect regex AFAICT. This one is a good
_source, # compromise.
_make # (3) Constant string literals at the start of files don't need to be broken
# across lines. Allowing long paths and urls to be on a single
# line. Also requires that the string not be a triplequoted string.
ignore-long-lines=(?x)
(^\s*(import|from)\s
|^\s*(\#\ )?<?(https?|ftp):\/\/[^\s\/$.?#].[^\s]*>?$
|^[a-zA-Z_][a-zA-Z0-9_]*\s*=\s*("[^"]\S+"|'[^']\S+')
)
# List of valid names for the first argument in a class method. # Maximum number of lines in a module
valid-classmethod-first-arg=cls, max-module-lines=99999
class_
# List of valid names for the first argument in a metaclass class method. # String used as indentation unit. We differ from PEP8's normal 4 spaces.
valid-metaclass-classmethod-first-arg=mcs indent-string=' '
# Do not warn about multiple statements on a single line for constructs like
# if test: stmt
single-line-if-stmt=y
# Make sure : in dicts and trailing commas are checked for whitespace.
no-space-check=
[EXCEPTIONS] [LOGGING]
# Exceptions that will emit a warning when being caught. Defaults to # Add logging modules.
# "Exception" logging-modules=logging,absl.logging
overgeneral-exceptions=StandardError,
Exception,
BaseException [MISCELLANEOUS]
# List of note tags to take in consideration, separated by a comma.
notes=
# Maximum line length for lambdas
short-func-length=1
# List of module members that should be marked as deprecated.
# All of the string functions are listed in 4.1.4 Deprecated string functions
# in the Python 2.4 docs.
deprecated-members=string.atof,string.atoi,string.atol,string.capitalize,string.expandtabs,string.find,string.rfind,string.index,string.rindex,string.count,string.lower,string.split,string.rsplit,string.splitfields,string.join,string.joinfields,string.lstrip,string.rstrip,string.strip,string.swapcase,string.translate,string.upper,string.ljust,string.rjust,string.center,string.zfill,string.replace,sys.exitfunc,sys.maxint
# List of exceptions that do not need to be mentioned in the Raises section of
# a docstring.
ignore-exceptions=AssertionError,NotImplementedError,StopIteration,TypeError
# Number of spaces of indent required when the last token on the preceding line
# is an open (, [, or {.
indent-after-paren=4
# Set the linting for string quotes
string-quote=double
triple-quote=double
docstring-quote=double

253
Cargo.lock generated
View File

@@ -1,7 +1,5 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3
[[package]] [[package]]
name = "aho-corasick" name = "aho-corasick"
version = "0.7.19" version = "0.7.19"
@@ -11,15 +9,6 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "arbitrary"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db55d72333851e17d572bec876e390cd3b11eb1ef53ae821dd9f3b653d2b4569"
dependencies = [
"derive_arbitrary",
]
[[package]] [[package]]
name = "arrayref" name = "arrayref"
version = "0.3.6" version = "0.3.6"
@@ -59,6 +48,10 @@ version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cbor"
version = "0.1.0"
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.73" version = "1.0.73"
@@ -86,10 +79,12 @@ version = "0.1.0"
dependencies = [ dependencies = [
"arrayref", "arrayref",
"byteorder", "byteorder",
"cbor",
"hex", "hex",
"libtock_drivers",
"rand",
"regex", "regex",
"ring", "ring",
"rng256",
"serde", "serde",
"serde_json", "serde_json",
"subtle", "subtle",
@@ -100,51 +95,19 @@ dependencies = [
name = "ctap2" name = "ctap2"
version = "1.0.0" version = "1.0.0"
dependencies = [ dependencies = [
"arbitrary",
"arrayref", "arrayref",
"byteorder", "byteorder",
"cbor",
"crypto", "crypto",
"ed25519-compact",
"embedded-time",
"enum-iterator", "enum-iterator",
"lang_items", "lang_items",
"libtock_core", "libtock_core",
"libtock_drivers", "libtock_drivers",
"openssl",
"persistent_store", "persistent_store",
"rand 0.8.5",
"rng256",
"sk-cbor",
"subtle", "subtle",
"uuid", "uuid",
] ]
[[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 = "ed25519-compact"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bee9df587982575886a8682edcee11877894349a805f25629c27f63abe3e9ae8"
[[package]]
name = "embedded-time"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7a4b4d10ac48d08bfe3db7688c402baadb244721f30a77ce360bd24c3dffe58"
dependencies = [
"num",
]
[[package]] [[package]]
name = "enum-iterator" name = "enum-iterator"
version = "0.6.0" version = "0.6.0"
@@ -165,21 +128,6 @@ dependencies = [
"syn", "syn",
] ]
[[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]] [[package]]
name = "fuchsia-cprng" name = "fuchsia-cprng"
version = "0.1.1" version = "0.1.1"
@@ -205,9 +153,9 @@ checksum = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77"
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "0.4.8" version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc"
[[package]] [[package]]
name = "js-sys" name = "js-sys"
@@ -229,9 +177,9 @@ dependencies = [
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.133" version = "0.2.134"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0f80d65747a3e43d1596c7c5492d95d5edddaabd45a7fcdb02b95f644164966" checksum = "329c933548736bc49fd575ee68c89e8be4d260064184389a5b77517cddd99ffb"
[[package]] [[package]]
name = "libtock_codegen" name = "libtock_codegen"
@@ -277,130 +225,16 @@ version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" 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]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.14.0" version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0" 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]] [[package]]
name = "persistent_store" name = "persistent_store"
version = "0.1.0" 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]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.43" version = "1.0.43"
@@ -427,7 +261,7 @@ checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
dependencies = [ dependencies = [
"autocfg 0.1.8", "autocfg 0.1.8",
"libc", "libc",
"rand_chacha 0.1.1", "rand_chacha",
"rand_core 0.4.2", "rand_core 0.4.2",
"rand_hc", "rand_hc",
"rand_isaac", "rand_isaac",
@@ -438,17 +272,6 @@ dependencies = [
"winapi", "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]] [[package]]
name = "rand_chacha" name = "rand_chacha"
version = "0.1.1" version = "0.1.1"
@@ -459,16 +282,6 @@ dependencies = [
"rand_core 0.3.1", "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]] [[package]]
name = "rand_core" name = "rand_core"
version = "0.3.1" version = "0.3.1"
@@ -484,15 +297,6 @@ version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" 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]] [[package]]
name = "rand_hc" name = "rand_hc"
version = "0.1.0" version = "0.1.0"
@@ -596,15 +400,6 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "rng256"
version = "0.1.0"
dependencies = [
"arrayref",
"libtock_drivers",
"rand 0.6.5",
]
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.11" version = "1.0.11"
@@ -633,19 +428,15 @@ dependencies = [
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.69" version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e466864e431129c7e0d3476b92f20458e5879919a0596c6472738d9fa2d342f8" checksum = "41feea4228a6f1cd09ec7a3593a682276702cd67b5273544757dae23c096f074"
dependencies = [ dependencies = [
"itoa", "itoa",
"ryu", "ryu",
"serde", "serde",
] ]
[[package]]
name = "sk-cbor"
version = "0.1.2"
[[package]] [[package]]
name = "spin" name = "spin"
version = "0.5.2" version = "0.5.2"
@@ -660,9 +451,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.100" version = "1.0.101"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52205623b1b0f064a4e71182c3b18ae902267282930c6d5462c91b859668426e" checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -671,9 +462,9 @@ dependencies = [
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.4" version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd" checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
[[package]] [[package]]
name = "untrusted" name = "untrusted"
@@ -690,12 +481,6 @@ dependencies = [
"getrandom", "getrandom",
] ]
[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]] [[package]]
name = "wasi" name = "wasi"
version = "0.11.0+wasi-snapshot-preview1" version = "0.11.0+wasi-snapshot-preview1"

View File

@@ -13,37 +13,28 @@ edition = "2018"
libtock_core = { path = "third_party/libtock-rs/core" } libtock_core = { path = "third_party/libtock-rs/core" }
libtock_drivers = { path = "third_party/libtock-drivers" } libtock_drivers = { path = "third_party/libtock-drivers" }
lang_items = { path = "third_party/lang-items" } lang_items = { path = "third_party/lang-items" }
sk-cbor = { path = "libraries/cbor" } 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" }
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"] } subtle = { version = "2.2", default-features = false, features = ["nightly"] }
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 }
[features] [features]
debug_allocations = ["lang_items/debug_allocations"] debug_allocations = ["lang_items/debug_allocations"]
debug_ctap = ["libtock_drivers/debug_ctap"] debug_ctap = ["crypto/derive_debug", "libtock_drivers/debug_ctap"]
panic_console = ["lang_items/panic_console"] panic_console = ["lang_items/panic_console"]
std = ["crypto/std", "lang_items/std", "persistent_store/std", "rng256/std", "rand"] std = ["cbor/std", "crypto/std", "crypto/derive_debug", "lang_items/std", "persistent_store/std"]
verbose = ["debug_ctap", "libtock_drivers/verbose_usb"] verbose = ["debug_ctap", "libtock_drivers/verbose_usb"]
with_ctap1 = ["crypto/with_ctap1"] with_ctap1 = ["crypto/with_ctap1"]
with_ctap2_1 = []
with_nfc = ["libtock_drivers/with_nfc"] with_nfc = ["libtock_drivers/with_nfc"]
vendor_hid = ["libtock_drivers/vendor_hid"]
fuzz = ["arbitrary", "std"]
ed25519 = ["ed25519-compact"]
[dev-dependencies] [dev-dependencies]
enum-iterator = "0.6.0" enum-iterator = "0.6.0"
[build-dependencies] [build-dependencies]
sk-cbor = { path = "libraries/cbor" }
uuid = { version = "0.8", features = ["v4"] } uuid = { version = "0.8", features = ["v4"] }
openssl = "0.10.36"
[profile.dev] [profile.dev]
panic = "abort" panic = "abort"
@@ -52,5 +43,3 @@ lto = true # Link Time Optimization usually reduces size of binaries and static
[profile.release] [profile.release]
panic = "abort" 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"
codegen-units = 1

View File

@@ -1,10 +1,9 @@
# <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=develop) This branch is unmaintained. It implements the CTAP 2.0 version of OpenSK.
![pylint](https://github.com/google/OpenSK/workflows/pylint/badge.svg?branch=develop) Please check out the default branch for maintained code.
![Cargo check](https://github.com/google/OpenSK/workflows/Cargo%20check/badge.svg?branch=develop) If you are a developer, go to the
![Cargo format](https://github.com/google/OpenSK/workflows/Cargo%20format/badge.svg?branch=develop) [develop branch](https://github.com/google/OpenSK/tree/develop).
[![Coverage Status](https://coveralls.io/repos/github/google/OpenSK/badge.svg?branch=develop)](https://coveralls.io/github/google/OpenSK?branch=develop)
## OpenSK ## OpenSK
@@ -18,26 +17,18 @@ enclosure!
You can see OpenSK in action in this You can see OpenSK in action in this
[video on YouTube](https://www.youtube.com/watch?v=klEozvpw0xg)! [video on YouTube](https://www.youtube.com/watch?v=klEozvpw0xg)!
You are viewing the branch for developers. New features are developed here
before they are stabilized. If you instead want to use the FIDO certified
firmware, please go back to the
[stable branch](https://github.com/google/OpenSK).
### FIDO2 ### FIDO2
The develop branch implements the This branch implements the
[CTAP2.1 specification](https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-20210615.html). [CTAP2.0 specification](https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html)
This branch is not FIDO certified. The implementation is backwards compatible and is FIDO certified. OpenSK supports U2F, and non-discoverable credentials
to CTAP2.0. Additionally, OpenSK supports U2F, and non-discoverable credentials
created with either protocol are compatible with the other. created with either protocol are compatible with the other.
### :warning: Disclaimer ### :warning: Disclaimer
This project is **proof-of-concept and a research platform**. It is **NOT** This project is **proof-of-concept and a research platform**. It is **NOT**
meant for a daily usage. It comes with a few limitations: meant for a daily usage. The cryptography implementations are not resistent
against side-channel attacks.
* This branch is under development, and therefore less rigorously tested than the stable branch.
* The cryptography implementations are not resistent against side-channel attacks.
We're still in the process of integrating the We're still in the process of integrating the
[ARM&reg; CryptoCell-310](https://developer.arm.com/ip-products/security-ip/cryptocell-300-family) [ARM&reg; CryptoCell-310](https://developer.arm.com/ip-products/security-ip/cryptocell-300-family)

View File

@@ -6,7 +6,7 @@ build = "build.rs"
edition = "2018" edition = "2018"
[[bin]] [[bin]]
path = "../nrf52840_dongle_opensk/src/main.rs" path = "../nrf52840_dongle/src/main.rs"
name = "nrf52840_dongle_dfu" name = "nrf52840_dongle_dfu"
[dependencies] [dependencies]
@@ -16,6 +16,3 @@ capsules = { path = "../../../capsules" }
kernel = { path = "../../../kernel" } kernel = { path = "../../../kernel" }
nrf52840 = { path = "../../../chips/nrf52840" } nrf52840 = { path = "../../../chips/nrf52840" }
nrf52_components = { path = "../nrf52_components" } nrf52_components = { path = "../nrf52_components" }
[features]
vendor_hid = ["capsules/vendor_hid"]

View File

@@ -1,17 +0,0 @@
[package]
name = "nrf52840_dongle_opensk"
version = "0.1.0"
authors = ["Tock Project Developers <tock-dev@googlegroups.com>"]
build = "build.rs"
edition = "2018"
[dependencies]
components = { path = "../../components" }
cortexm4 = { path = "../../../arch/cortex-m4" }
capsules = { path = "../../../capsules" }
kernel = { path = "../../../kernel" }
nrf52840 = { path = "../../../chips/nrf52840" }
nrf52_components = { path = "../nrf52_components" }
[features]
vendor_hid = ["capsules/vendor_hid"]

View File

@@ -1,28 +0,0 @@
# Makefile for building the tock kernel for the nRF development kit
TARGET=thumbv7em-none-eabi
PLATFORM=nrf52840_dongle_opensk
include ../../Makefile.common
TOCKLOADER=tockloader
# Where in the nrf52 flash to load the kernel with `tockloader`
KERNEL_ADDRESS=0x00000
# Upload programs over uart with tockloader
ifdef PORT
TOCKLOADER_GENERAL_FLAGS += --port $(PORT)
endif
TOCKLOADER_JTAG_FLAGS = --jlink --board nrf52dk
# Upload the kernel over JTAG
.PHONY: flash
flash: $(TOCK_ROOT_DIRECTORY)target/$(TARGET)/release/$(PLATFORM).bin
$(TOCKLOADER) $(TOCKLOADER_GENERAL_FLAGS) flash --address $(KERNEL_ADDRESS) $(TOCKLOADER_JTAG_FLAGS) $<
# Upload the kernel over serial/bootloader
.PHONY: program
program: $(TOCK_ROOT_DIRECTORY)target/$(TARGET)/release/$(PLATFORM).hex
$(error Cannot program nRF52840-Dongle over USB. Use \`make flash\` and JTAG)

View File

@@ -1,41 +0,0 @@
Platform-Specific Instructions: nRF52840-Dongle
===================================
This is an adapted nrf52840\_dongle made to work with OpenSK.
The [nRF52840 Dongle](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52840-Dongle)
is a platform based around the nRF52840, an SoC with an ARM Cortex-M4 and a BLE radio.
The kit is uses a USB key form factor and includes 1 button, 1 red LED and 1 RGB LED.
## Getting Started
To program the nRF52840 Dongle with Tock, you will need a JLink JTAG device and the
appropriate cables. An example setup is:
- [JLink JTAG Device](https://www.digikey.com/product-detail/en/segger-microcontroller-systems/8.08.90-J-LINK-EDU/899-1008-ND/2263130)
- [ARM to TagConnect Adapter](https://www.digikey.com/product-detail/en/tag-connect-llc/TC2050-ARM2010/TC2050-ARM2010-ND/3528170)
- [10pin TagConnect Cable](https://www.digikey.com/product-detail/en/tag-connect-llc/TC2050-IDC-NL/TC2050-IDC-NL-ND/2605367)
Then, follow the [Tock Getting Started guide](../../../doc/Getting_Started.md)
JTAG is the preferred method to program. The development kit has the JTAG pins exposed either
through the half-moons pads or, below the PCB, on a Tag-Connect TC2050 connector footprint.
You need to [install JTAG software](../../../doc/Getting_Started.md#optional-requirements).
## Programming the kernel
Once you have all software installed, you should be able to simply run
make flash in this directory to install a fresh kernel.
## Programming user-level applications
You can program an application via JTAG using `tockloader`:
```shell
$ cd libtock-c/examples/<app>
$ make
$ tockloader install --jlink --board nrf52dk
```
## Debugging
See the [nrf52dk README](../nrf52dk/README.md) for information about debugging
the nRF52840 Dongle.

View File

@@ -1,4 +0,0 @@
fn main() {
println!("cargo:rerun-if-changed=layout.ld");
println!("cargo:rerun-if-changed=../../kernel_layout.ld");
}

View File

@@ -1,25 +0,0 @@
#
#
#
# J-LINK GDB SERVER initialization
#
# This connects to a GDB Server listening
# for commands on localhost at tcp port 2331
target remote localhost:2331
monitor speed 30
file ../../../../target/thumbv7em-none-eabi/release/nrf52840_dongle
monitor reset
#
# CPU core initialization (to be done by user)
#
# Set the processor mode
# monitor reg cpsr = 0xd3
# Set auto JTAG speed
monitor speed auto
# Setup GDB FOR FASTER DOWNLOADS
set remote memory-write-packet-size 1024
set remote memory-write-packet-size fixed
# tui enable
# layout split
# layout service_pending_interrupts
b reset_handler

View File

@@ -1 +0,0 @@
JLinkGDBServer -device nRF52840_xxAA -speed 1200 -if swd -AutoConnect 1 -port 2331

View File

@@ -1,2 +0,0 @@
INCLUDE ../nrf52840_chip_layout.ld
INCLUDE ../../kernel_layout.ld

View File

@@ -1,68 +0,0 @@
use core::fmt::Write;
use core::panic::PanicInfo;
use cortexm4;
use kernel::debug;
use kernel::debug::IoWrite;
use kernel::hil::led;
use kernel::hil::uart::{self, Configure};
use nrf52840::gpio::Pin;
use crate::CHIP;
use crate::PROCESSES;
struct Writer {
initialized: bool,
}
static mut WRITER: Writer = Writer { initialized: false };
impl Write for Writer {
fn write_str(&mut self, s: &str) -> ::core::fmt::Result {
self.write(s.as_bytes());
Ok(())
}
}
impl IoWrite for Writer {
fn write(&mut self, buf: &[u8]) {
// Here, we create a second instance of the Uarte struct.
// This is okay because we only call this during a panic, and
// we will never actually process the interrupts
let uart = nrf52840::uart::Uarte::new();
if !self.initialized {
self.initialized = true;
uart.configure(uart::Parameters {
baud_rate: 115200,
stop_bits: uart::StopBits::One,
parity: uart::Parity::None,
hw_flow_control: false,
width: uart::Width::Eight,
});
}
for &c in buf {
unsafe {
uart.send_byte(c);
}
while !uart.tx_ready() {}
}
}
}
#[cfg(not(test))]
#[no_mangle]
#[panic_handler]
/// Panic handler
pub unsafe extern "C" fn panic_fmt(pi: &PanicInfo) -> ! {
// The nRF52840 Dongle LEDs (see back of board)
let led_kernel_pin = &nrf52840::gpio::GPIOPin::new(Pin::P0_06);
let led = &mut led::LedLow::new(led_kernel_pin);
let writer = &mut WRITER;
debug::panic(
&mut [led],
writer,
pi,
&cortexm4::support::nop,
&PROCESSES,
&CHIP,
)
}

View File

@@ -1,420 +0,0 @@
//! Tock kernel for the Nordic Semiconductor nRF52840 dongle.
//!
//! It is based on nRF52840 SoC (Cortex M4 core with a BLE transceiver) with
//! many exported I/O and peripherals.
#![no_std]
// Disable this attribute when documenting, as a workaround for
// https://github.com/rust-lang/rust/issues/62184.
#![cfg_attr(not(doc), no_main)]
#![feature(const_in_array_repeat_expressions)]
#![deny(missing_docs)]
use kernel::common::dynamic_deferred_call::{DynamicDeferredCall, DynamicDeferredCallClientState};
use kernel::component::Component;
use kernel::hil::led::LedLow;
use kernel::hil::time::Counter;
#[allow(unused_imports)]
use kernel::{capabilities, create_capability, debug, debug_gpio, debug_verbose, static_init};
use nrf52840::gpio::Pin;
use nrf52840::interrupt_service::Nrf52840DefaultPeripherals;
use nrf52_components::{self, UartChannel, UartPins};
// The nRF52840 Dongle LEDs
const LED1_PIN: Pin = Pin::P0_06;
const LED2_R_PIN: Pin = Pin::P0_08;
const LED2_G_PIN: Pin = Pin::P1_09;
const LED2_B_PIN: Pin = Pin::P0_12;
// The nRF52840 Dongle button
const BUTTON_PIN: Pin = Pin::P1_06;
const BUTTON_RST_PIN: Pin = Pin::P0_18;
const UART_RTS: Option<Pin> = Some(Pin::P0_13);
const UART_TXD: Pin = Pin::P0_15;
const UART_CTS: Option<Pin> = Some(Pin::P0_17);
const UART_RXD: Pin = Pin::P0_20;
// SPI pins not currently in use, but left here for convenience
const _SPI_MOSI: Pin = Pin::P1_01;
const _SPI_MISO: Pin = Pin::P1_02;
const _SPI_CLK: Pin = Pin::P1_04;
/// UART Writer
pub mod io;
const VENDOR_ID: u16 = 0x1915; // Nordic Semiconductor
const PRODUCT_ID: u16 = 0x521f; // nRF52840 Dongle (PCA10059)
static STRINGS: &'static [&'static str] = &[
// Manufacturer
"Nordic Semiconductor ASA",
// Product
"OpenSK",
// Serial number
"v1.0",
];
// State for loading and holding applications.
// How should the kernel respond when a process faults.
const FAULT_RESPONSE: kernel::procs::FaultResponse = kernel::procs::FaultResponse::Panic;
// Number of concurrent processes this platform supports.
const NUM_PROCS: usize = 8;
static mut PROCESSES: [Option<&'static dyn kernel::procs::ProcessType>; NUM_PROCS] =
[None; NUM_PROCS];
static mut STORAGE_LOCATIONS: [kernel::StorageLocation; 2] = [
// We implement NUM_PAGES = 20 as 16 + 4 to satisfy the MPU.
kernel::StorageLocation {
address: 0xC0000,
size: 0x10000, // 16 pages
storage_type: kernel::StorageType::STORE,
},
kernel::StorageLocation {
address: 0xD0000,
size: 0x4000, // 4 pages
storage_type: kernel::StorageType::STORE,
},
];
// Static reference to chip for panic dumps
static mut CHIP: Option<&'static nrf52840::chip::NRF52<Nrf52840DefaultPeripherals>> = None;
/// Dummy buffer that causes the linker to reserve enough space for the stack.
#[no_mangle]
#[link_section = ".stack_buffer"]
pub static mut STACK_MEMORY: [u8; 0x1000] = [0; 0x1000];
/// Supported drivers by the platform
pub struct Platform {
button: &'static capsules::button::Button<'static, nrf52840::gpio::GPIOPin<'static>>,
pconsole: &'static capsules::process_console::ProcessConsole<
'static,
components::process_console::Capability,
>,
console: &'static capsules::console::Console<'static>,
gpio: &'static capsules::gpio::GPIO<'static, nrf52840::gpio::GPIOPin<'static>>,
led: &'static capsules::led::LedDriver<
'static,
LedLow<'static, nrf52840::gpio::GPIOPin<'static>>,
>,
rng: &'static capsules::rng::RngDriver<'static>,
ipc: kernel::ipc::IPC<NUM_PROCS>,
analog_comparator: &'static capsules::analog_comparator::AnalogComparator<
'static,
nrf52840::acomp::Comparator<'static>,
>,
alarm: &'static capsules::alarm::AlarmDriver<
'static,
capsules::virtual_alarm::VirtualMuxAlarm<'static, nrf52840::rtc::Rtc<'static>>,
>,
nvmc: &'static nrf52840::nvmc::SyscallDriver,
usb: &'static capsules::usb::usb_ctap::CtapUsbSyscallDriver<
'static,
'static,
nrf52840::usbd::Usbd<'static>,
>,
crp: &'static capsules::firmware_protection::FirmwareProtection<nrf52840::uicr::Uicr>,
}
impl kernel::Platform for Platform {
fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
where
F: FnOnce(Option<&dyn kernel::Driver>) -> R,
{
match driver_num {
capsules::console::DRIVER_NUM => f(Some(self.console)),
capsules::gpio::DRIVER_NUM => f(Some(self.gpio)),
capsules::alarm::DRIVER_NUM => f(Some(self.alarm)),
capsules::led::DRIVER_NUM => f(Some(self.led)),
capsules::button::DRIVER_NUM => f(Some(self.button)),
capsules::rng::DRIVER_NUM => f(Some(self.rng)),
capsules::analog_comparator::DRIVER_NUM => f(Some(self.analog_comparator)),
nrf52840::nvmc::DRIVER_NUM => f(Some(self.nvmc)),
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)),
_ => f(None),
}
}
fn filter_syscall(
&self,
process: &dyn kernel::procs::ProcessType,
syscall: &kernel::syscall::Syscall,
) -> Result<(), kernel::ReturnCode> {
use kernel::syscall::Syscall;
match *syscall {
Syscall::COMMAND {
driver_number: nrf52840::nvmc::DRIVER_NUM,
subdriver_number: cmd,
arg0: ptr,
arg1: len,
} if (cmd == 2 || cmd == 3) && !process.fits_in_storage_location(ptr, len) => {
Err(kernel::ReturnCode::EINVAL)
}
_ => Ok(()),
}
}
}
/// Entry point in the vector table called on hard reset.
#[no_mangle]
pub unsafe fn reset_handler() {
// Loads relocations and clears BSS
nrf52840::init();
let ppi = static_init!(nrf52840::ppi::Ppi, nrf52840::ppi::Ppi::new());
// Initialize chip peripheral drivers
let nrf52840_peripherals = static_init!(
Nrf52840DefaultPeripherals,
Nrf52840DefaultPeripherals::new(ppi)
);
// set up circular peripheral dependencies
nrf52840_peripherals.init();
let base_peripherals = &nrf52840_peripherals.nrf52;
let board_kernel = static_init!(
kernel::Kernel,
kernel::Kernel::new_with_storage(&PROCESSES, &STORAGE_LOCATIONS)
);
// GPIOs
let gpio = components::gpio::GpioComponent::new(
board_kernel,
components::gpio_component_helper!(
nrf52840::gpio::GPIOPin,
// left side of the USB plug
0 => &nrf52840_peripherals.gpio_port[Pin::P0_13],
1 => &nrf52840_peripherals.gpio_port[Pin::P0_15],
2 => &nrf52840_peripherals.gpio_port[Pin::P0_17],
3 => &nrf52840_peripherals.gpio_port[Pin::P0_20],
4 => &nrf52840_peripherals.gpio_port[Pin::P0_22],
5 => &nrf52840_peripherals.gpio_port[Pin::P0_24],
6 => &nrf52840_peripherals.gpio_port[Pin::P1_00],
7 => &nrf52840_peripherals.gpio_port[Pin::P0_09],
8 => &nrf52840_peripherals.gpio_port[Pin::P0_10],
// right side of the USB plug
9 => &nrf52840_peripherals.gpio_port[Pin::P0_31],
10 => &nrf52840_peripherals.gpio_port[Pin::P0_29],
11 => &nrf52840_peripherals.gpio_port[Pin::P0_02],
12 => &nrf52840_peripherals.gpio_port[Pin::P1_15],
13 => &nrf52840_peripherals.gpio_port[Pin::P1_13],
14 => &nrf52840_peripherals.gpio_port[Pin::P1_10],
// Below the PCB
15 => &nrf52840_peripherals.gpio_port[Pin::P0_26],
16 => &nrf52840_peripherals.gpio_port[Pin::P0_04],
17 => &nrf52840_peripherals.gpio_port[Pin::P0_11],
18 => &nrf52840_peripherals.gpio_port[Pin::P0_14],
19 => &nrf52840_peripherals.gpio_port[Pin::P1_11],
20 => &nrf52840_peripherals.gpio_port[Pin::P1_07],
21 => &nrf52840_peripherals.gpio_port[Pin::P1_01],
22 => &nrf52840_peripherals.gpio_port[Pin::P1_04],
23 => &nrf52840_peripherals.gpio_port[Pin::P1_02]
),
)
.finalize(components::gpio_component_buf!(nrf52840::gpio::GPIOPin));
let button = components::button::ButtonComponent::new(
board_kernel,
components::button_component_helper!(
nrf52840::gpio::GPIOPin,
(
&nrf52840_peripherals.gpio_port[BUTTON_PIN],
kernel::hil::gpio::ActivationMode::ActiveLow,
kernel::hil::gpio::FloatingState::PullUp
)
),
)
.finalize(components::button_component_buf!(nrf52840::gpio::GPIOPin));
let led = components::led::LedsComponent::new(components::led_component_helper!(
LedLow<'static, nrf52840::gpio::GPIOPin>,
LedLow::new(&nrf52840_peripherals.gpio_port[LED1_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_B_PIN]),
))
.finalize(components::led_component_buf!(
LedLow<'static, nrf52840::gpio::GPIOPin>
));
let chip = static_init!(
nrf52840::chip::NRF52<Nrf52840DefaultPeripherals>,
nrf52840::chip::NRF52::new(nrf52840_peripherals)
);
CHIP = Some(chip);
nrf52_components::startup::NrfStartupComponent::new(
false,
BUTTON_RST_PIN,
nrf52840::uicr::Regulator0Output::V3_0,
&base_peripherals.nvmc,
)
.finalize(());
// Create capabilities that the board needs to call certain protected kernel
// functions.
let process_management_capability =
create_capability!(capabilities::ProcessManagementCapability);
let main_loop_capability = create_capability!(capabilities::MainLoopCapability);
let memory_allocation_capability = create_capability!(capabilities::MemoryAllocationCapability);
let gpio_port = &nrf52840_peripherals.gpio_port;
// Configure kernel debug gpios as early as possible
kernel::debug::assign_gpios(
Some(&gpio_port[LED2_R_PIN]),
Some(&gpio_port[LED2_G_PIN]),
Some(&gpio_port[LED2_B_PIN]),
);
let rtc = &base_peripherals.rtc;
rtc.start();
let mux_alarm = components::alarm::AlarmMuxComponent::new(rtc)
.finalize(components::alarm_mux_component_helper!(nrf52840::rtc::Rtc));
let alarm = components::alarm::AlarmDriverComponent::new(board_kernel, mux_alarm)
.finalize(components::alarm_component_helper!(nrf52840::rtc::Rtc));
let uart_channel = UartChannel::Pins(UartPins::new(UART_RTS, UART_TXD, UART_CTS, UART_RXD));
let channel = nrf52_components::UartChannelComponent::new(
uart_channel,
mux_alarm,
&base_peripherals.uarte0,
)
.finalize(());
let dynamic_deferred_call_clients =
static_init!([DynamicDeferredCallClientState; 3], Default::default());
let dynamic_deferred_caller = static_init!(
DynamicDeferredCall,
DynamicDeferredCall::new(dynamic_deferred_call_clients)
);
DynamicDeferredCall::set_global_instance(dynamic_deferred_caller);
// Create a shared UART channel for the console and for kernel debug.
let uart_mux =
components::console::UartMuxComponent::new(channel, 115200, dynamic_deferred_caller)
.finalize(());
let pconsole =
components::process_console::ProcessConsoleComponent::new(board_kernel, uart_mux)
.finalize(());
// Setup the console.
let console = components::console::ConsoleComponent::new(board_kernel, uart_mux).finalize(());
// Create the debugger object that handles calls to `debug!()`.
components::debug_writer::DebugWriterComponent::new(uart_mux).finalize(());
let rng = components::rng::RngComponent::new(board_kernel, &base_peripherals.trng).finalize(());
// Initialize AC using AIN5 (P0.29) as VIN+ and VIN- as AIN0 (P0.02)
// These are hardcoded pin assignments specified in the driver
let analog_comparator = components::analog_comparator::AcComponent::new(
&base_peripherals.acomp,
components::acomp_component_helper!(
nrf52840::acomp::Channel,
&nrf52840::acomp::CHANNEL_AC0
),
)
.finalize(components::acomp_component_buf!(
nrf52840::acomp::Comparator
));
let nvmc = static_init!(
nrf52840::nvmc::SyscallDriver,
nrf52840::nvmc::SyscallDriver::new(
&base_peripherals.nvmc,
board_kernel.create_grant(&memory_allocation_capability),
dynamic_deferred_caller,
)
);
nvmc.set_deferred_handle(
dynamic_deferred_caller
.register(nvmc)
.expect("no deferred call slot available for nvmc"),
);
// Configure USB controller
let usb = components::usb_ctap::UsbCtapComponent::new(
board_kernel,
&nrf52840_peripherals.usbd,
capsules::usb::usbc_client::MAX_CTRL_PACKET_SIZE_NRF52840,
VENDOR_ID,
PRODUCT_ID,
STRINGS,
)
.finalize(components::usb_ctap_component_buf!(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(());
let platform = Platform {
button,
pconsole,
console,
led,
gpio,
rng,
alarm,
analog_comparator,
nvmc,
usb,
crp,
ipc: kernel::ipc::IPC::new(board_kernel, &memory_allocation_capability),
};
platform.pconsole.start();
debug!("Initialization complete. Entering main loop\r");
debug!("{}", &nrf52840::ficr::FICR_INSTANCE);
/// These symbols are defined in the linker script.
extern "C" {
/// Beginning of the ROM region containing app images.
static _sapps: u8;
/// End of the ROM region containing app images.
static _eapps: u8;
/// Beginning of the RAM region for app memory.
static mut _sappmem: u8;
/// End of the RAM region for app memory.
static _eappmem: u8;
}
kernel::procs::load_processes(
board_kernel,
chip,
core::slice::from_raw_parts(
&_sapps as *const u8,
&_eapps as *const u8 as usize - &_sapps as *const u8 as usize,
),
core::slice::from_raw_parts_mut(
&mut _sappmem as *mut u8,
&_eappmem as *const u8 as usize - &_sappmem as *const u8 as usize,
),
&mut PROCESSES,
FAULT_RESPONSE,
&process_management_capability,
)
.unwrap_or_else(|err| {
debug!("Error loading processes!");
debug!("{:?}", err);
});
let scheduler = components::sched::round_robin::RoundRobinComponent::new(&PROCESSES)
.finalize(components::rr_component_helper!(NUM_PROCS));
board_kernel.kernel_loop(
&platform,
chip,
Some(&platform.ipc),
scheduler,
&main_loop_capability,
);
}

View File

@@ -12,6 +12,3 @@ capsules = { path = "../../../capsules" }
kernel = { path = "../../../kernel" } kernel = { path = "../../../kernel" }
nrf52840 = { path = "../../../chips/nrf52840" } nrf52840 = { path = "../../../chips/nrf52840" }
nrf52_components = { path = "../nrf52_components" } nrf52_components = { path = "../nrf52_components" }
[features]
vendor_hid = ["capsules/vendor_hid"]

View File

@@ -25,10 +25,7 @@ impl Write for Writer {
impl IoWrite for Writer { impl IoWrite for Writer {
fn write(&mut self, buf: &[u8]) { fn write(&mut self, buf: &[u8]) {
// Here, we create a second instance of the Uarte struct. let uart = unsafe { &mut nrf52840::uart::UARTE0 };
// This is okay because we only call this during a panic, and
// we will never actually process the interrupts
let uart = nrf52840::uart::Uarte::new();
if !self.initialized { if !self.initialized {
self.initialized = true; self.initialized = true;
uart.configure(uart::Parameters { uart.configure(uart::Parameters {
@@ -54,8 +51,8 @@ impl IoWrite for Writer {
/// Panic handler /// Panic handler
pub unsafe extern "C" fn panic_fmt(pi: &PanicInfo) -> ! { pub unsafe extern "C" fn panic_fmt(pi: &PanicInfo) -> ! {
// The nRF52840 Dongle LEDs (see back of board) // The nRF52840 Dongle LEDs (see back of board)
let led_kernel_pin = &nrf52840::gpio::GPIOPin::new(Pin::P0_23); const LED1_PIN: Pin = Pin::P0_23;
let led = &mut led::LedLow::new(led_kernel_pin); let led = &mut led::LedLow::new(&mut nrf52840::gpio::PORT[LED1_PIN]);
let writer = &mut WRITER; let writer = &mut WRITER;
debug::panic( debug::panic(
&mut [led], &mut [led],

View File

@@ -10,14 +10,13 @@
#![feature(const_in_array_repeat_expressions)] #![feature(const_in_array_repeat_expressions)]
#![deny(missing_docs)] #![deny(missing_docs)]
use capsules::virtual_alarm::VirtualMuxAlarm;
use kernel::common::dynamic_deferred_call::{DynamicDeferredCall, DynamicDeferredCallClientState}; use kernel::common::dynamic_deferred_call::{DynamicDeferredCall, DynamicDeferredCallClientState};
use kernel::component::Component; use kernel::component::Component;
use kernel::hil::led::LedLow;
use kernel::hil::time::Counter;
#[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::hil::usb::UsbController;
use nrf52840::gpio::Pin; use nrf52840::gpio::Pin;
use nrf52840::interrupt_service::Nrf52840DefaultPeripherals;
use nrf52_components::{self, UartChannel, UartPins}; use nrf52_components::{self, UartChannel, UartPins};
// The nRF52840 MDK USB Dongle LEDs // The nRF52840 MDK USB Dongle LEDs
@@ -27,13 +26,17 @@ const LED1_B_PIN: Pin = Pin::P0_24;
// The nRF52840 Dongle button // The nRF52840 Dongle button
const BUTTON_PIN: Pin = Pin::P0_18; const BUTTON_PIN: Pin = Pin::P0_18;
const _BUTTON_RST_PIN: Pin = Pin::P0_02; const BUTTON_RST_PIN: Pin = Pin::P0_02;
const UART_RTS: Option<Pin> = Some(Pin::P0_21); const UART_RTS: Option<Pin> = Some(Pin::P0_21);
const UART_TXD: Pin = Pin::P0_20; const UART_TXD: Pin = Pin::P0_20;
const UART_CTS: Option<Pin> = Some(Pin::P0_03); const UART_CTS: Option<Pin> = Some(Pin::P0_03);
const UART_RXD: Pin = Pin::P0_19; const UART_RXD: Pin = Pin::P0_19;
// Constants related to the configuration of the 15.4 network stack
const SRC_MAC: u16 = 0xf00f;
const PAN_ID: u16 = 0xABCD;
/// UART Writer /// UART Writer
pub mod io; pub mod io;
@@ -58,22 +61,13 @@ const NUM_PROCS: usize = 8;
static mut PROCESSES: [Option<&'static dyn kernel::procs::ProcessType>; NUM_PROCS] = static mut PROCESSES: [Option<&'static dyn kernel::procs::ProcessType>; NUM_PROCS] =
[None; NUM_PROCS]; [None; NUM_PROCS];
static mut STORAGE_LOCATIONS: [kernel::StorageLocation; 2] = [ static mut STORAGE_LOCATIONS: [kernel::StorageLocation; 1] = [kernel::StorageLocation {
// We implement NUM_PAGES = 20 as 16 + 4 to satisfy the MPU.
kernel::StorageLocation {
address: 0xC0000, address: 0xC0000,
size: 0x10000, // 16 pages size: 0x40000,
storage_type: kernel::StorageType::STORE, }];
},
kernel::StorageLocation {
address: 0xD0000,
size: 0x4000, // 4 pages
storage_type: kernel::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::Chip> = None;
/// 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]
@@ -82,6 +76,12 @@ pub static mut STACK_MEMORY: [u8; 0x1000] = [0; 0x1000];
/// Supported drivers by the platform /// Supported drivers by the platform
pub struct Platform { pub struct Platform {
ble_radio: &'static capsules::ble_advertising_driver::BLE<
'static,
nrf52840::ble_radio::Radio<'static>,
VirtualMuxAlarm<'static, nrf52840::rtc::Rtc<'static>>,
>,
ieee802154_radio: &'static capsules::ieee802154::RadioDriver<'static>,
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,
@@ -89,12 +89,10 @@ pub struct Platform {
>, >,
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::LED<'static, nrf52840::gpio::GPIOPin<'static>>,
'static,
LedLow<'static, nrf52840::gpio::GPIOPin<'static>>,
>,
rng: &'static capsules::rng::RngDriver<'static>, rng: &'static capsules::rng::RngDriver<'static>,
ipc: kernel::ipc::IPC<NUM_PROCS>, temp: &'static capsules::temperature::TemperatureSensor<'static>,
ipc: kernel::ipc::IPC,
analog_comparator: &'static capsules::analog_comparator::AnalogComparator< analog_comparator: &'static capsules::analog_comparator::AnalogComparator<
'static, 'static,
nrf52840::acomp::Comparator<'static>, nrf52840::acomp::Comparator<'static>,
@@ -123,6 +121,9 @@ impl kernel::Platform for Platform {
capsules::led::DRIVER_NUM => f(Some(self.led)), capsules::led::DRIVER_NUM => f(Some(self.led)),
capsules::button::DRIVER_NUM => f(Some(self.button)), capsules::button::DRIVER_NUM => f(Some(self.button)),
capsules::rng::DRIVER_NUM => f(Some(self.rng)), capsules::rng::DRIVER_NUM => f(Some(self.rng)),
capsules::ble_advertising_driver::DRIVER_NUM => f(Some(self.ble_radio)),
capsules::ieee802154::DRIVER_NUM => f(Some(self.ieee802154_radio)),
capsules::temperature::DRIVER_NUM => f(Some(self.temp)),
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)),
@@ -157,17 +158,6 @@ pub unsafe fn reset_handler() {
// Loads relocations and clears BSS // Loads relocations and clears BSS
nrf52840::init(); nrf52840::init();
let ppi = static_init!(nrf52840::ppi::Ppi, nrf52840::ppi::Ppi::new());
// Initialize chip peripheral drivers
let nrf52840_peripherals = static_init!(
Nrf52840DefaultPeripherals,
Nrf52840DefaultPeripherals::new(ppi)
);
// set up circular peripheral dependencies
nrf52840_peripherals.init();
let base_peripherals = &nrf52840_peripherals.nrf52;
let board_kernel = static_init!( let board_kernel = static_init!(
kernel::Kernel, kernel::Kernel,
kernel::Kernel::new_with_storage(&PROCESSES, &STORAGE_LOCATIONS) kernel::Kernel::new_with_storage(&PROCESSES, &STORAGE_LOCATIONS)
@@ -178,21 +168,20 @@ pub unsafe fn reset_handler() {
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
0 => &nrf52840_peripherals.gpio_port[Pin::P0_04], 0 => &nrf52840::gpio::PORT[Pin::P0_04],
1 => &nrf52840_peripherals.gpio_port[Pin::P0_05], 1 => &nrf52840::gpio::PORT[Pin::P0_05],
2 => &nrf52840_peripherals.gpio_port[Pin::P0_06], 2 => &nrf52840::gpio::PORT[Pin::P0_06],
3 => &nrf52840_peripherals.gpio_port[Pin::P0_07], 3 => &nrf52840::gpio::PORT[Pin::P0_07],
4 => &nrf52840_peripherals.gpio_port[Pin::P0_08] 4 => &nrf52840::gpio::PORT[Pin::P0_08]
), ),
) ).finalize(components::gpio_component_buf!(nrf52840::gpio::GPIOPin));
.finalize(components::gpio_component_buf!(nrf52840::gpio::GPIOPin));
let button = components::button::ButtonComponent::new( let button = components::button::ButtonComponent::new(
board_kernel, board_kernel,
components::button_component_helper!( components::button_component_helper!(
nrf52840::gpio::GPIOPin, nrf52840::gpio::GPIOPin,
( (
&nrf52840_peripherals.gpio_port[BUTTON_PIN], &nrf52840::gpio::PORT[BUTTON_PIN],
kernel::hil::gpio::ActivationMode::ActiveLow, kernel::hil::gpio::ActivationMode::ActiveLow,
kernel::hil::gpio::FloatingState::PullUp kernel::hil::gpio::FloatingState::PullUp
) )
@@ -201,21 +190,32 @@ 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(components::led_component_helper!(
LedLow<'static, nrf52840::gpio::GPIOPin>, nrf52840::gpio::GPIOPin,
LedLow::new(&nrf52840_peripherals.gpio_port[LED1_R_PIN]), (
LedLow::new(&nrf52840_peripherals.gpio_port[LED1_G_PIN]), &nrf52840::gpio::PORT[LED1_R_PIN],
LedLow::new(&nrf52840_peripherals.gpio_port[LED1_B_PIN]), kernel::hil::gpio::ActivationMode::ActiveLow
),
(
&nrf52840::gpio::PORT[LED1_G_PIN],
kernel::hil::gpio::ActivationMode::ActiveLow
),
(
&nrf52840::gpio::PORT[LED1_B_PIN],
kernel::hil::gpio::ActivationMode::ActiveLow
)
)) ))
.finalize(components::led_component_buf!( .finalize(components::led_component_buf!(nrf52840::gpio::GPIOPin));
LedLow<'static, nrf52840::gpio::GPIOPin>
));
let chip = static_init!( let chip = static_init!(nrf52840::chip::Chip, nrf52840::chip::new());
nrf52840::chip::NRF52<Nrf52840DefaultPeripherals>,
nrf52840::chip::NRF52::new(nrf52840_peripherals)
);
CHIP = Some(chip); CHIP = Some(chip);
nrf52_components::startup::NrfStartupComponent::new(
false,
BUTTON_RST_PIN,
nrf52840::uicr::Regulator0Output::V3_0,
)
.finalize(());
// Create capabilities that the board needs to call certain protected kernel // Create capabilities that the board needs to call certain protected kernel
// functions. // functions.
let process_management_capability = let process_management_capability =
@@ -223,7 +223,7 @@ pub unsafe fn reset_handler() {
let main_loop_capability = create_capability!(capabilities::MainLoopCapability); let main_loop_capability = create_capability!(capabilities::MainLoopCapability);
let memory_allocation_capability = create_capability!(capabilities::MemoryAllocationCapability); let memory_allocation_capability = create_capability!(capabilities::MemoryAllocationCapability);
let gpio_port = &nrf52840_peripherals.gpio_port; let gpio_port = &nrf52840::gpio::PORT;
// Configure kernel debug gpios as early as possible // Configure kernel debug gpios as early as possible
kernel::debug::assign_gpios( kernel::debug::assign_gpios(
@@ -232,19 +232,14 @@ pub unsafe fn reset_handler() {
Some(&gpio_port[LED1_B_PIN]), Some(&gpio_port[LED1_B_PIN]),
); );
let rtc = &base_peripherals.rtc; let rtc = &nrf52840::rtc::RTC;
rtc.start(); 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, 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(uart_channel, mux_alarm).finalize(());
uart_channel,
mux_alarm,
&base_peripherals.uarte0,
)
.finalize(());
let dynamic_deferred_call_clients = let dynamic_deferred_call_clients =
static_init!([DynamicDeferredCallClientState; 2], Default::default()); static_init!([DynamicDeferredCallClientState; 2], Default::default());
@@ -268,12 +263,34 @@ pub unsafe fn reset_handler() {
// 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 ble_radio =
nrf52_components::BLEComponent::new(board_kernel, &nrf52840::ble_radio::RADIO, mux_alarm)
.finalize(());
let (ieee802154_radio, _mux_mac) = components::ieee802154::Ieee802154Component::new(
board_kernel,
&nrf52840::ieee802154_radio::RADIO,
&nrf52840::aes::AESECB,
PAN_ID,
SRC_MAC,
)
.finalize(components::ieee802154_component_helper!(
nrf52840::ieee802154_radio::Radio,
nrf52840::aes::AesECB<'static>
));
let temp = components::temperature::TemperatureComponent::new(
board_kernel,
&nrf52840::temperature::TEMP,
)
.finalize(());
let rng = components::rng::RngComponent::new(board_kernel, &nrf52840::trng::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
let analog_comparator = components::analog_comparator::AcComponent::new( let analog_comparator = components::analog_comparator::AcComponent::new(
&base_peripherals.acomp, &nrf52840::acomp::ACOMP,
components::acomp_component_helper!( components::acomp_component_helper!(
nrf52840::acomp::Channel, nrf52840::acomp::Channel,
&nrf52840::acomp::CHANNEL_AC0 &nrf52840::acomp::CHANNEL_AC0
@@ -286,37 +303,66 @@ pub unsafe fn reset_handler() {
let nvmc = static_init!( let nvmc = static_init!(
nrf52840::nvmc::SyscallDriver, nrf52840::nvmc::SyscallDriver,
nrf52840::nvmc::SyscallDriver::new( nrf52840::nvmc::SyscallDriver::new(
&base_peripherals.nvmc, &nrf52840::nvmc::NVMC,
board_kernel.create_grant(&memory_allocation_capability), board_kernel.create_grant(&memory_allocation_capability),
dynamic_deferred_caller,
) )
); );
nvmc.set_deferred_handle(
dynamic_deferred_caller
.register(nvmc)
.expect("no deferred call slot available for nvmc"),
);
// Configure USB controller // Configure USB controller
let usb = components::usb_ctap::UsbCtapComponent::new( let usb:
board_kernel, &'static capsules::usb::usb_ctap::CtapUsbSyscallDriver<
&nrf52840_peripherals.usbd, 'static,
'static,
nrf52840::usbd::Usbd<'static>,
> = {
let usb_ctap = static_init!(
capsules::usb::usbc_ctap_hid::ClientCtapHID<
'static,
'static,
nrf52840::usbd::Usbd<'static>,
>,
capsules::usb::usbc_ctap_hid::ClientCtapHID::new(
&nrf52840::usbd::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)); );
nrf52840::usbd::USBD.set_client(usb_ctap);
nrf52_components::NrfClockComponent::new(&base_peripherals.clock).finalize(()); // Enable power events to be sent to USB controller
nrf52840::power::POWER.set_usb_client(&nrf52840::usbd::USBD);
nrf52840::power::POWER.enable_interrupts();
// Configure the USB userspace driver
let usb_driver = static_init!(
capsules::usb::usb_ctap::CtapUsbSyscallDriver<
'static,
'static,
nrf52840::usbd::Usbd<'static>,
>,
capsules::usb::usb_ctap::CtapUsbSyscallDriver::new(
usb_ctap,
board_kernel.create_grant(&memory_allocation_capability)
)
);
usb_ctap.set_client(usb_driver);
usb_driver as &'static _
};
nrf52_components::NrfClockComponent::new().finalize(());
let platform = Platform { let platform = Platform {
button, button,
ble_radio,
ieee802154_radio,
pconsole, pconsole,
console, console,
led, led,
gpio, gpio,
rng, rng,
temp,
alarm, alarm,
analog_comparator, analog_comparator,
nvmc, nvmc,

View File

@@ -1,17 +0,0 @@
[package]
name = "nrf52840dk_opensk"
version = "0.1.0"
authors = ["Tock Project Developers <tock-dev@googlegroups.com>"]
build = "build.rs"
edition = "2018"
[dependencies]
components = { path = "../../components" }
cortexm4 = { path = "../../../arch/cortex-m4" }
capsules = { path = "../../../capsules" }
kernel = { path = "../../../kernel" }
nrf52840 = { path = "../../../chips/nrf52840" }
nrf52_components = { path = "../nrf52_components" }
[features]
vendor_hid = ["capsules/vendor_hid"]

View File

@@ -1,31 +0,0 @@
# Makefile for building the tock kernel for the nRF development kit
TARGET=thumbv7em-none-eabi
PLATFORM=nrf52840dk_opensk
include ../../Makefile.common
TOCKLOADER=tockloader
# Where in the SAM4L flash to load the kernel with `tockloader`
KERNEL_ADDRESS=0x00000
# Upload programs over uart with tockloader
ifdef PORT
TOCKLOADER_GENERAL_FLAGS += --port $(PORT)
endif
# Upload the kernel over JTAG
.PHONY: flash
flash: $(TOCK_ROOT_DIRECTORY)target/$(TARGET)/release/$(PLATFORM).bin
$(TOCKLOADER) $(TOCKLOADER_GENERAL_FLAGS) flash --address $(KERNEL_ADDRESS) --board nrf52dk --jlink $<
# Upload the kernel over JTAG using OpenOCD
.PHONY: flash-openocd
flash-openocd: $(TOCK_ROOT_DIRECTORY)target/$(TARGET)/release/$(PLATFORM).bin
$(TOCKLOADER) $(TOCKLOADER_GENERAL_FLAGS) flash --address $(KERNEL_ADDRESS) --board nrf52dk --openocd $<
# Upload the kernel over serial/bootloader
.PHONY: program
program: $(TOCK_ROOT_DIRECTORY)target/$(TARGET)/release/$(PLATFORM).hex
$(error Cannot program nRF52840DK over USB. Use \`make flash\` and JTAG)

View File

@@ -1,65 +0,0 @@
Platform-Specific Instructions: nRF52840-DK
===================================
This is an adapted nrf52840dk made to work with OpenSK.
The [nRF52840 Development
Kit](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52840-DK) is a platform
based around the nRF52840, an SoC with an ARM Cortex-M4 and a BLE
radio. The kit is Arduino shield compatible and includes several
buttons.
## Getting Started
First, follow the [Tock Getting Started guide](../../../doc/Getting_Started.md)
JTAG is the preferred method to program. The development kit has an
integrated JTAG debugger, you simply need to [install JTAG
software](../../../doc/Getting_Started.md#loading-the-kernel-onto-a-board).
## Programming the kernel
Once you have all software installed, you should be able to simply run
make flash in this directory to install a fresh kernel.
## Programming user-level applications
You can program an application over USB using the integrated JTAG and `tockloader`:
```bash
$ cd libtock-c/examples/<app>
$ make
$ tockloader install --jlink --board nrf52dk
```
The same options (`--jlink --board nrf52dk`) must be passed for other tockloader commands
such as `erase-apps` or `list`.
Viewing console output on the nrf52840dk is slightly different from other boards. You must use
```bash
$ tockloader listen
```
**followed by a press of the reset button** in order to view console output starting from the boot
sequence. Notably, you should not
pass the `--jlink` option to `tockloader listen`.
## Console output
This board supports two methods for writing messages to a console interface
(console driver for applications as well as debug statements in the kernel).
By default, messages are written to a UART interface over the GPIO pins `P0.05`
to `P0.08` (see the [main.rs](src/main.rs) file).
If you don't have any UART cables or want to use a different interface, there is
also a console over the Segger RTT protocol. This only requires a micro-USB
cable on the USB debugging port (the same used to flash Tock on the board), and
is enabled by setting the `USB_DEBUGGING` constant to `true` in the
[main.rs](src/main.rs) file.
This disables the UART interface.
For instructions about how to receive RTT messages on the host, see the
[corresponding capsule](../../../capsules/src/segger_rtt.rs).
## Debugging
See the [nrf52dk README](../nrf52dk/README.md) for information about debugging
the nRF52840dk.

View File

@@ -1,29 +0,0 @@
use std::env;
use std::fs;
use std::path::Path;
fn main() {
println!("cargo:rerun-if-changed=layout.ld");
println!("cargo:rerun-if-changed=../../kernel_layout.ld");
let out_dir = env::var_os("OUT_DIR").unwrap();
let dest_path = Path::new(&out_dir).join("locations.rs");
fs::write(
&dest_path,
"
static mut STORAGE_LOCATIONS: [kernel::StorageLocation; 2] = [
// We implement NUM_PAGES = 20 as 16 + 4 to satisfy the MPU.
kernel::StorageLocation {
address: 0xC0000,
size: 0x10000, // 16 pages
storage_type: kernel::StorageType::STORE,
},
kernel::StorageLocation {
address: 0xD0000,
size: 0x4000, // 4 pages
storage_type: kernel::StorageType::STORE,
},
];
"
).unwrap();
}

View File

@@ -1,25 +0,0 @@
#
#
#
# J-LINK GDB SERVER initialization
#
# This connects to a GDB Server listening
# for commands on localhost at tcp port 2331
target remote localhost:2331
monitor speed 30
file ../../../../target/thumbv7em-none-eabi/release/nrf52dk
monitor reset
#
# CPU core initialization (to be done by user)
#
# Set the processor mode
# monitor reg cpsr = 0xd3
# Set auto JTAG speed
monitor speed auto
# Setup GDB FOR FASTER DOWNLOADS
set remote memory-write-packet-size 1024
set remote memory-write-packet-size fixed
# tui enable
# layout split
# layout service_pending_interrupts
b reset_handler

View File

@@ -1 +0,0 @@
JLinkGDBServer -device nrf52 -speed 1200 -if swd -AutoConnect 1 -port 2331

View File

@@ -1,2 +0,0 @@
INCLUDE ../nrf52840_chip_layout.ld
INCLUDE ../../kernel_layout.ld

View File

@@ -1,106 +0,0 @@
use core::fmt::Write;
use core::panic::PanicInfo;
use cortexm4;
use kernel::debug;
use kernel::debug::IoWrite;
use kernel::hil::led;
use kernel::hil::uart;
use kernel::hil::uart::Configure;
use nrf52840::gpio::Pin;
use crate::CHIP;
use crate::PROCESSES;
enum Writer {
WriterUart(/* initialized */ bool),
WriterRtt(&'static capsules::segger_rtt::SeggerRttMemory<'static>),
}
static mut WRITER: Writer = Writer::WriterUart(false);
fn wait() {
for _ in 0..100 {
cortexm4::support::nop();
}
}
/// Set the RTT memory buffer used to output panic messages.
pub unsafe fn set_rtt_memory(
rtt_memory: &'static mut capsules::segger_rtt::SeggerRttMemory<'static>,
) {
WRITER = Writer::WriterRtt(rtt_memory);
}
impl Write for Writer {
fn write_str(&mut self, s: &str) -> ::core::fmt::Result {
self.write(s.as_bytes());
Ok(())
}
}
impl IoWrite for Writer {
fn write(&mut self, buf: &[u8]) {
match self {
Writer::WriterUart(ref mut initialized) => {
// Here, we create a second instance of the Uarte struct.
// This is okay because we only call this during a panic, and
// we will never actually process the interrupts
let uart = nrf52840::uart::Uarte::new();
if !*initialized {
*initialized = true;
uart.configure(uart::Parameters {
baud_rate: 115200,
stop_bits: uart::StopBits::One,
parity: uart::Parity::None,
hw_flow_control: false,
width: uart::Width::Eight,
});
}
for &c in buf {
unsafe {
uart.send_byte(c);
}
while !uart.tx_ready() {}
}
}
Writer::WriterRtt(rtt_memory) => {
let up_buffer = unsafe { &*rtt_memory.get_up_buffer_ptr() };
let buffer_len = up_buffer.length.get();
let buffer = unsafe {
core::slice::from_raw_parts_mut(
up_buffer.buffer.get() as *mut u8,
buffer_len as usize,
)
};
let mut write_position = up_buffer.write_position.get();
for &c in buf {
buffer[write_position as usize] = c;
write_position = (write_position + 1) % buffer_len;
up_buffer.write_position.set(write_position);
wait();
}
}
};
}
}
#[cfg(not(test))]
#[no_mangle]
#[panic_handler]
/// Panic handler
pub unsafe extern "C" fn panic_fmt(pi: &PanicInfo) -> ! {
// The nRF52840DK LEDs (see back of board)
let led_kernel_pin = &nrf52840::gpio::GPIOPin::new(Pin::P0_13);
let led = &mut led::LedLow::new(led_kernel_pin);
let writer = &mut WRITER;
debug::panic(
&mut [led],
writer,
pi,
&cortexm4::support::nop,
&PROCESSES,
&CHIP,
)
}

View File

@@ -1,493 +0,0 @@
//! Tock kernel for the Nordic Semiconductor nRF52840 development kit (DK).
//!
//! It is based on nRF52840 SoC (Cortex M4 core with a BLE transceiver) with
//! many exported I/O and peripherals.
//!
//! Pin Configuration
//! -------------------
//!
//! ### `GPIO`
//!
//! | # | Pin | Ix | Header | Arduino |
//! |----|-------|----|--------|---------|
//! | 0 | P1.01 | 33 | P3 1 | D0 |
//! | 1 | P1.02 | 34 | P3 2 | D1 |
//! | 2 | P1.03 | 35 | P3 3 | D2 |
//! | 3 | P1.04 | 36 | P3 4 | D3 |
//! | 4 | P1.05 | 37 | P3 5 | D4 |
//! | 5 | P1.06 | 38 | P3 6 | D5 |
//! | 6 | P1.07 | 39 | P3 7 | D6 |
//! | 7 | P1.08 | 40 | P3 8 | D7 |
//! | 8 | P1.10 | 42 | P4 1 | D8 |
//! | 9 | P1.11 | 43 | P4 2 | D9 |
//! | 10 | P1.12 | 44 | P4 3 | D10 |
//! | 11 | P1.13 | 45 | P4 4 | D11 |
//! | 12 | P1.14 | 46 | P4 5 | D12 |
//! | 13 | P1.15 | 47 | P4 6 | D13 |
//! | 14 | P0.26 | 26 | P4 9 | D14 |
//! | 15 | P0.27 | 27 | P4 10 | D15 |
//!
//! ### `GPIO` / Analog Inputs
//!
//! | # | Pin | Header | Arduino |
//! |----|------------|--------|---------|
//! | 16 | P0.03 AIN1 | P2 1 | A0 |
//! | 17 | P0.04 AIN2 | P2 2 | A1 |
//! | 18 | P0.28 AIN4 | P2 3 | A2 |
//! | 19 | P0.29 AIN5 | P2 4 | A3 |
//! | 20 | P0.30 AIN6 | P2 5 | A4 |
//! | 21 | P0.31 AIN7 | P2 6 | A5 |
//! | 22 | P0.02 AIN0 | P4 8 | AVDD |
//!
//! ### Onboard Functions
//!
//! | Pin | Header | Function |
//! |-------|--------|----------|
//! | P0.05 | P6 3 | UART RTS |
//! | P0.06 | P6 4 | UART TXD |
//! | P0.07 | P6 5 | UART CTS |
//! | P0.08 | P6 6 | UART RXT |
//! | P0.11 | P24 1 | Button 1 |
//! | P0.12 | P24 2 | Button 2 |
//! | P0.13 | P24 3 | LED 1 |
//! | P0.14 | P24 4 | LED 2 |
//! | P0.15 | P24 5 | LED 3 |
//! | P0.16 | P24 6 | LED 4 |
//! | P0.18 | P24 8 | Reset |
//! | P0.19 | P24 9 | SPI CLK |
//! | P0.20 | P24 10 | SPI MOSI |
//! | P0.21 | P24 11 | SPI MISO |
//! | P0.24 | P24 14 | Button 3 |
//! | P0.25 | P24 15 | Button 4 |
#![no_std]
// Disable this attribute when documenting, as a workaround for
// https://github.com/rust-lang/rust/issues/62184.
#![cfg_attr(not(doc), no_main)]
#![feature(const_in_array_repeat_expressions)]
#![deny(missing_docs)]
use core::env;
use kernel::common::dynamic_deferred_call::{DynamicDeferredCall, DynamicDeferredCallClientState};
use kernel::component::Component;
use kernel::hil::led::LedLow;
use kernel::hil::time::Counter;
#[allow(unused_imports)]
use kernel::{capabilities, create_capability, debug, debug_gpio, debug_verbose, static_init};
use nrf52840::gpio::Pin;
use nrf52840::interrupt_service::Nrf52840DefaultPeripherals;
use nrf52_components::{self, UartChannel, UartPins};
// The nRF52840DK LEDs (see back of board)
const LED1_PIN: Pin = Pin::P0_13;
const LED2_PIN: Pin = Pin::P0_14;
const LED3_PIN: Pin = Pin::P0_15;
const LED4_PIN: Pin = Pin::P0_16;
// The nRF52840DK buttons (see back of board)
const BUTTON1_PIN: Pin = Pin::P0_11;
const BUTTON2_PIN: Pin = Pin::P0_12;
const BUTTON3_PIN: Pin = Pin::P0_24;
const BUTTON4_PIN: Pin = Pin::P0_25;
const BUTTON_RST_PIN: Pin = Pin::P0_18;
const UART_RTS: Option<Pin> = Some(Pin::P0_05);
const UART_TXD: Pin = Pin::P0_06;
const UART_CTS: Option<Pin> = Some(Pin::P0_07);
const UART_RXD: Pin = Pin::P0_08;
const SPI_MOSI: Pin = Pin::P0_20;
const SPI_MISO: Pin = Pin::P0_21;
const SPI_CLK: Pin = Pin::P0_19;
/// Debug Writer
pub mod io;
// Whether to use UART debugging or Segger RTT (USB) debugging.
// - Set to false to use UART.
// - Set to true to use Segger RTT over USB.
const USB_DEBUGGING: bool = true;
const VENDOR_ID: u16 = 0x1915; // Nordic Semiconductor
const PRODUCT_ID: u16 = 0x521f; // nRF52840 Dongle (PCA10059)
static STRINGS: &'static [&'static str] = &[
// Manufacturer
"Nordic Semiconductor ASA",
// Product
"OpenSK",
// Serial number
"v1.0",
];
// State for loading and holding applications.
// How should the kernel respond when a process faults.
const FAULT_RESPONSE: kernel::procs::FaultResponse = kernel::procs::FaultResponse::Panic;
// Number of concurrent processes this platform supports.
const NUM_PROCS: usize = 8;
static mut PROCESSES: [Option<&'static dyn kernel::procs::ProcessType>; NUM_PROCS] =
[None; NUM_PROCS];
include!(concat!(env!("OUT_DIR"), "/locations.rs"));
static mut CHIP: Option<&'static nrf52840::chip::NRF52<Nrf52840DefaultPeripherals>> = None;
/// Dummy buffer that causes the linker to reserve enough space for the stack.
#[no_mangle]
#[link_section = ".stack_buffer"]
pub static mut STACK_MEMORY: [u8; 0x1000] = [0; 0x1000];
/// Supported drivers by the platform
pub struct Platform {
button: &'static capsules::button::Button<'static, nrf52840::gpio::GPIOPin<'static>>,
pconsole: &'static capsules::process_console::ProcessConsole<
'static,
components::process_console::Capability,
>,
console: &'static capsules::console::Console<'static>,
gpio: &'static capsules::gpio::GPIO<'static, nrf52840::gpio::GPIOPin<'static>>,
led: &'static capsules::led::LedDriver<
'static,
kernel::hil::led::LedLow<'static, nrf52840::gpio::GPIOPin<'static>>,
>,
rng: &'static capsules::rng::RngDriver<'static>,
ipc: kernel::ipc::IPC<NUM_PROCS>,
analog_comparator: &'static capsules::analog_comparator::AnalogComparator<
'static,
nrf52840::acomp::Comparator<'static>,
>,
alarm: &'static capsules::alarm::AlarmDriver<
'static,
capsules::virtual_alarm::VirtualMuxAlarm<'static, nrf52840::rtc::Rtc<'static>>,
>,
nvmc: &'static nrf52840::nvmc::SyscallDriver,
usb: &'static capsules::usb::usb_ctap::CtapUsbSyscallDriver<
'static,
'static,
nrf52840::usbd::Usbd<'static>,
>,
crp: &'static capsules::firmware_protection::FirmwareProtection<nrf52840::uicr::Uicr>,
}
impl kernel::Platform for Platform {
fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
where
F: FnOnce(Option<&dyn kernel::Driver>) -> R,
{
match driver_num {
capsules::console::DRIVER_NUM => f(Some(self.console)),
capsules::gpio::DRIVER_NUM => f(Some(self.gpio)),
capsules::alarm::DRIVER_NUM => f(Some(self.alarm)),
capsules::led::DRIVER_NUM => f(Some(self.led)),
capsules::button::DRIVER_NUM => f(Some(self.button)),
capsules::rng::DRIVER_NUM => f(Some(self.rng)),
capsules::analog_comparator::DRIVER_NUM => f(Some(self.analog_comparator)),
nrf52840::nvmc::DRIVER_NUM => f(Some(self.nvmc)),
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)),
_ => f(None),
}
}
fn filter_syscall(
&self,
process: &dyn kernel::procs::ProcessType,
syscall: &kernel::syscall::Syscall,
) -> Result<(), kernel::ReturnCode> {
use kernel::syscall::Syscall;
match *syscall {
Syscall::COMMAND {
driver_number: nrf52840::nvmc::DRIVER_NUM,
subdriver_number: cmd,
arg0: ptr,
arg1: len,
} if (cmd == 2 || cmd == 3) && !process.fits_in_storage_location(ptr, len) => {
Err(kernel::ReturnCode::EINVAL)
}
_ => Ok(()),
}
}
}
/// Entry point in the vector table called on hard reset.
#[no_mangle]
pub unsafe fn reset_handler() {
// Loads relocations and clears BSS
nrf52840::init();
let ppi = static_init!(nrf52840::ppi::Ppi, nrf52840::ppi::Ppi::new());
// Initialize chip peripheral drivers
let nrf52840_peripherals = static_init!(
Nrf52840DefaultPeripherals,
Nrf52840DefaultPeripherals::new(ppi)
);
// set up circular peripheral dependencies
nrf52840_peripherals.init();
let base_peripherals = &nrf52840_peripherals.nrf52;
let uart_channel = if USB_DEBUGGING {
// Initialize early so any panic beyond this point can use the RTT memory object.
let mut rtt_memory_refs =
components::segger_rtt::SeggerRttMemoryComponent::new().finalize(());
// XXX: This is inherently unsafe as it aliases the mutable reference to rtt_memory. This
// aliases reference is only used inside a panic handler, which should be OK, but maybe we
// should use a const reference to rtt_memory and leverage interior mutability instead.
self::io::set_rtt_memory(&mut *rtt_memory_refs.get_rtt_memory_ptr());
UartChannel::Rtt(rtt_memory_refs)
} else {
UartChannel::Pins(UartPins::new(UART_RTS, UART_TXD, UART_CTS, UART_RXD))
};
let board_kernel = static_init!(
kernel::Kernel,
kernel::Kernel::new_with_storage(&PROCESSES, &STORAGE_LOCATIONS)
);
let gpio = components::gpio::GpioComponent::new(
board_kernel,
components::gpio_component_helper!(
nrf52840::gpio::GPIOPin,
0 => &nrf52840_peripherals.gpio_port[Pin::P1_01],
1 => &nrf52840_peripherals.gpio_port[Pin::P1_02],
2 => &nrf52840_peripherals.gpio_port[Pin::P1_03],
3 => &nrf52840_peripherals.gpio_port[Pin::P1_04],
4 => &nrf52840_peripherals.gpio_port[Pin::P1_05],
5 => &nrf52840_peripherals.gpio_port[Pin::P1_06],
6 => &nrf52840_peripherals.gpio_port[Pin::P1_07],
7 => &nrf52840_peripherals.gpio_port[Pin::P1_08],
8 => &nrf52840_peripherals.gpio_port[Pin::P1_10],
9 => &nrf52840_peripherals.gpio_port[Pin::P1_11],
10 => &nrf52840_peripherals.gpio_port[Pin::P1_12],
11 => &nrf52840_peripherals.gpio_port[Pin::P1_13],
12 => &nrf52840_peripherals.gpio_port[Pin::P1_14],
13 => &nrf52840_peripherals.gpio_port[Pin::P1_15],
14 => &nrf52840_peripherals.gpio_port[Pin::P0_26],
15 => &nrf52840_peripherals.gpio_port[Pin::P0_27]
),
)
.finalize(components::gpio_component_buf!(nrf52840::gpio::GPIOPin));
let button = components::button::ButtonComponent::new(
board_kernel,
components::button_component_helper!(
nrf52840::gpio::GPIOPin,
(
&nrf52840_peripherals.gpio_port[BUTTON1_PIN],
kernel::hil::gpio::ActivationMode::ActiveLow,
kernel::hil::gpio::FloatingState::PullUp
), //13
(
&nrf52840_peripherals.gpio_port[BUTTON2_PIN],
kernel::hil::gpio::ActivationMode::ActiveLow,
kernel::hil::gpio::FloatingState::PullUp
), //14
(
&nrf52840_peripherals.gpio_port[BUTTON3_PIN],
kernel::hil::gpio::ActivationMode::ActiveLow,
kernel::hil::gpio::FloatingState::PullUp
), //15
(
&nrf52840_peripherals.gpio_port[BUTTON4_PIN],
kernel::hil::gpio::ActivationMode::ActiveLow,
kernel::hil::gpio::FloatingState::PullUp
) //16
),
)
.finalize(components::button_component_buf!(nrf52840::gpio::GPIOPin));
let led = components::led::LedsComponent::new(components::led_component_helper!(
LedLow<'static, nrf52840::gpio::GPIOPin>,
LedLow::new(&nrf52840_peripherals.gpio_port[LED1_PIN]),
LedLow::new(&nrf52840_peripherals.gpio_port[LED2_PIN]),
LedLow::new(&nrf52840_peripherals.gpio_port[LED3_PIN]),
LedLow::new(&nrf52840_peripherals.gpio_port[LED4_PIN]),
))
.finalize(components::led_component_buf!(
LedLow<'static, nrf52840::gpio::GPIOPin>
));
let chip = static_init!(
nrf52840::chip::NRF52<Nrf52840DefaultPeripherals>,
nrf52840::chip::NRF52::new(nrf52840_peripherals)
);
CHIP = Some(chip);
nrf52_components::startup::NrfStartupComponent::new(
false,
BUTTON_RST_PIN,
nrf52840::uicr::Regulator0Output::DEFAULT,
&base_peripherals.nvmc,
)
.finalize(());
// Create capabilities that the board needs to call certain protected kernel
// functions.
let process_management_capability =
create_capability!(capabilities::ProcessManagementCapability);
let main_loop_capability = create_capability!(capabilities::MainLoopCapability);
let memory_allocation_capability = create_capability!(capabilities::MemoryAllocationCapability);
let gpio_port = &nrf52840_peripherals.gpio_port;
// Configure kernel debug gpios as early as possible
kernel::debug::assign_gpios(
Some(&gpio_port[LED1_PIN]),
Some(&gpio_port[LED2_PIN]),
Some(&gpio_port[LED3_PIN]),
);
let rtc = &base_peripherals.rtc;
rtc.start();
let mux_alarm = components::alarm::AlarmMuxComponent::new(rtc)
.finalize(components::alarm_mux_component_helper!(nrf52840::rtc::Rtc));
let alarm = components::alarm::AlarmDriverComponent::new(board_kernel, mux_alarm)
.finalize(components::alarm_component_helper!(nrf52840::rtc::Rtc));
let channel = nrf52_components::UartChannelComponent::new(
uart_channel,
mux_alarm,
&base_peripherals.uarte0,
)
.finalize(());
let dynamic_deferred_call_clients =
static_init!([DynamicDeferredCallClientState; 3], Default::default());
let dynamic_deferred_caller = static_init!(
DynamicDeferredCall,
DynamicDeferredCall::new(dynamic_deferred_call_clients)
);
DynamicDeferredCall::set_global_instance(dynamic_deferred_caller);
// Create a shared UART channel for the console and for kernel debug.
let uart_mux =
components::console::UartMuxComponent::new(channel, 115200, dynamic_deferred_caller)
.finalize(());
let pconsole =
components::process_console::ProcessConsoleComponent::new(board_kernel, uart_mux)
.finalize(());
// Setup the console.
let console = components::console::ConsoleComponent::new(board_kernel, uart_mux).finalize(());
// Create the debugger object that handles calls to `debug!()`.
components::debug_writer::DebugWriterComponent::new(uart_mux).finalize(());
let rng = components::rng::RngComponent::new(board_kernel, &base_peripherals.trng).finalize(());
base_peripherals.spim0.configure(
nrf52840::pinmux::Pinmux::new(SPI_MOSI as u32),
nrf52840::pinmux::Pinmux::new(SPI_MISO as u32),
nrf52840::pinmux::Pinmux::new(SPI_CLK as u32),
);
// Initialize AC using AIN5 (P0.29) as VIN+ and VIN- as AIN0 (P0.02)
// These are hardcoded pin assignments specified in the driver
let analog_comparator = components::analog_comparator::AcComponent::new(
&base_peripherals.acomp,
components::acomp_component_helper!(
nrf52840::acomp::Channel,
&nrf52840::acomp::CHANNEL_AC0
),
)
.finalize(components::acomp_component_buf!(
nrf52840::acomp::Comparator
));
let nvmc = static_init!(
nrf52840::nvmc::SyscallDriver,
nrf52840::nvmc::SyscallDriver::new(
&base_peripherals.nvmc,
board_kernel.create_grant(&memory_allocation_capability),
dynamic_deferred_caller,
)
);
nvmc.set_deferred_handle(
dynamic_deferred_caller
.register(nvmc)
.expect("no deferred call slot available for nvmc"),
);
// Configure USB controller
let usb = components::usb_ctap::UsbCtapComponent::new(
board_kernel,
&nrf52840_peripherals.usbd,
capsules::usb::usbc_client::MAX_CTRL_PACKET_SIZE_NRF52840,
VENDOR_ID,
PRODUCT_ID,
STRINGS,
)
.finalize(components::usb_ctap_component_buf!(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(());
let platform = Platform {
button,
pconsole,
console,
led,
gpio,
rng,
alarm,
analog_comparator,
nvmc,
usb,
crp,
ipc: kernel::ipc::IPC::new(board_kernel, &memory_allocation_capability),
};
platform.pconsole.start();
debug!("Initialization complete. Entering main loop\r");
debug!("{}", &nrf52840::ficr::FICR_INSTANCE);
/// These symbols are defined in the linker script.
extern "C" {
/// Beginning of the ROM region containing app images.
static _sapps: u8;
/// End of the ROM region containing app images.
static _eapps: u8;
/// Beginning of the RAM region for app memory.
static mut _sappmem: u8;
/// End of the RAM region for app memory.
static _eappmem: u8;
}
kernel::procs::load_processes(
board_kernel,
chip,
core::slice::from_raw_parts(
&_sapps as *const u8,
&_eapps as *const u8 as usize - &_sapps as *const u8 as usize,
),
core::slice::from_raw_parts_mut(
&mut _sappmem as *mut u8,
&_eappmem as *const u8 as usize - &_sappmem as *const u8 as usize,
),
&mut PROCESSES,
FAULT_RESPONSE,
&process_management_capability,
)
.unwrap_or_else(|err| {
debug!("Error loading processes!");
debug!("{:?}", err);
});
let scheduler = components::sched::round_robin::RoundRobinComponent::new(&PROCESSES)
.finalize(components::rr_component_helper!(NUM_PROCS));
board_kernel.kernel_loop(
&platform,
chip,
Some(&platform.ipc),
scheduler,
&main_loop_capability,
);
}

View File

@@ -1,21 +0,0 @@
[package]
name = "nrf52840dk_opensk_a"
version = "0.1.0"
authors = ["Tock Project Developers <tock-dev@googlegroups.com>"]
build = "build.rs"
edition = "2018"
[[bin]]
path = "../nrf52840dk_opensk/src/main.rs"
name = "nrf52840dk_opensk_a"
[dependencies]
components = { path = "../../components" }
cortexm4 = { path = "../../../arch/cortex-m4" }
capsules = { path = "../../../capsules" }
kernel = { path = "../../../kernel" }
nrf52840 = { path = "../../../chips/nrf52840" }
nrf52_components = { path = "../nrf52_components" }
[features]
vendor_hid = ["capsules/vendor_hid"]

View File

@@ -1,31 +0,0 @@
# Makefile for building the tock kernel for the nRF development kit
TARGET=thumbv7em-none-eabi
PLATFORM=nrf52840dk_opensk_a
include ../../Makefile.common
TOCKLOADER=tockloader
# Where in the SAM4L flash to load the kernel with `tockloader`
KERNEL_ADDRESS=0x20000
# Upload programs over uart with tockloader
ifdef PORT
TOCKLOADER_GENERAL_FLAGS += --port $(PORT)
endif
# Upload the kernel over JTAG
.PHONY: flash
flash: $(TOCK_ROOT_DIRECTORY)target/$(TARGET)/release/$(PLATFORM).bin
$(TOCKLOADER) $(TOCKLOADER_GENERAL_FLAGS) flash --address $(KERNEL_ADDRESS) --board nrf52dk --jlink $<
# Upload the kernel over JTAG using OpenOCD
.PHONY: flash-openocd
flash-openocd: $(TOCK_ROOT_DIRECTORY)target/$(TARGET)/release/$(PLATFORM).bin
$(TOCKLOADER) $(TOCKLOADER_GENERAL_FLAGS) flash --address $(KERNEL_ADDRESS) --board nrf52dk --openocd $<
# Upload the kernel over serial/bootloader
.PHONY: program
program: $(TOCK_ROOT_DIRECTORY)target/$(TARGET)/release/$(PLATFORM).hex
$(error Cannot program nRF52840DK over USB. Use \`make flash\` and JTAG)

View File

@@ -1,11 +0,0 @@
Platform-Specific Instructions: nRF52840-DK, partition A
===================================
This is an upgrade partition for the adapted nrf52840dk in `../nrf52840dk_opensk`.
Compared to our regular board definition for the nrf52840dk, changes are:
- a `layout.ld` with 128 kB for kernel and app
- the matching kernel address in the `Makefile`
- different `StorageLocation`s in `build.rs`
For everything else, please check the README in `../nrf52840dk_opensk`.

View File

@@ -1,45 +0,0 @@
use std::env;
use std::fs;
use std::path::Path;
fn main() {
println!("cargo:rerun-if-changed=layout.ld");
println!("cargo:rerun-if-changed=../../kernel_layout.ld");
let out_dir = env::var_os("OUT_DIR").unwrap();
let dest_path = Path::new(&out_dir).join("locations.rs");
fs::write(
&dest_path,
"
static mut STORAGE_LOCATIONS: [kernel::StorageLocation; 5] = [
// We implement NUM_PAGES = 20 as 16 + 4 to satisfy the MPU.
kernel::StorageLocation {
address: 0xC0000,
size: 0x10000, // 16 pages
storage_type: kernel::StorageType::STORE,
},
kernel::StorageLocation {
address: 0xD0000,
size: 0x4000, // 4 pages
storage_type: kernel::StorageType::STORE,
},
// Partitions can also be split to maximize MPU happiness.
kernel::StorageLocation {
address: 0x60000,
size: 0x20000,
storage_type: kernel::StorageType::PARTITION,
},
kernel::StorageLocation {
address: 0x80000,
size: 0x20000,
storage_type: kernel::StorageType::PARTITION,
},
kernel::StorageLocation {
address: 0x5000,
size: 0x1000,
storage_type: kernel::StorageType::METADATA,
},
];
"
).unwrap();
}

View File

@@ -1,13 +0,0 @@
/* Memory Space Definitions, 1M flash, 256K ram */
MEMORY
{
rom (rx) : ORIGIN = 0x00020000, LENGTH = 128K
prog (rx) : ORIGIN = 0x00040000, LENGTH = 128K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 256K
}
MPU_MIN_ALIGN = 8K;
PAGE_SIZE = 4K;
INCLUDE ../../kernel_layout.ld

View File

@@ -1,21 +0,0 @@
[package]
name = "nrf52840dk_opensk_b"
version = "0.1.0"
authors = ["Tock Project Developers <tock-dev@googlegroups.com>"]
build = "build.rs"
edition = "2018"
[[bin]]
path = "../nrf52840dk_opensk/src/main.rs"
name = "nrf52840dk_opensk_b"
[dependencies]
components = { path = "../../components" }
cortexm4 = { path = "../../../arch/cortex-m4" }
capsules = { path = "../../../capsules" }
kernel = { path = "../../../kernel" }
nrf52840 = { path = "../../../chips/nrf52840" }
nrf52_components = { path = "../nrf52_components" }
[features]
vendor_hid = ["capsules/vendor_hid"]

View File

@@ -1,31 +0,0 @@
# Makefile for building the tock kernel for the nRF development kit
TARGET=thumbv7em-none-eabi
PLATFORM=nrf52840dk_opensk_b
include ../../Makefile.common
TOCKLOADER=tockloader
# Where in the SAM4L flash to load the kernel with `tockloader`
KERNEL_ADDRESS=0x60000
# Upload programs over uart with tockloader
ifdef PORT
TOCKLOADER_GENERAL_FLAGS += --port $(PORT)
endif
# Upload the kernel over JTAG
.PHONY: flash
flash: $(TOCK_ROOT_DIRECTORY)target/$(TARGET)/release/$(PLATFORM).bin
$(TOCKLOADER) $(TOCKLOADER_GENERAL_FLAGS) flash --address $(KERNEL_ADDRESS) --board nrf52dk --jlink $<
# Upload the kernel over JTAG using OpenOCD
.PHONY: flash-openocd
flash-openocd: $(TOCK_ROOT_DIRECTORY)target/$(TARGET)/release/$(PLATFORM).bin
$(TOCKLOADER) $(TOCKLOADER_GENERAL_FLAGS) flash --address $(KERNEL_ADDRESS) --board nrf52dk --openocd $<
# Upload the kernel over serial/bootloader
.PHONY: program
program: $(TOCK_ROOT_DIRECTORY)target/$(TARGET)/release/$(PLATFORM).hex
$(error Cannot program nRF52840DK over USB. Use \`make flash\` and JTAG)

View File

@@ -1,11 +0,0 @@
Platform-Specific Instructions: nRF52840-DK, partition B
===================================
This is an upgrade partition for the adapted nrf52840dk in `../nrf52840dk_opensk`.
Compared to our regular board definition for the nrf52840dk, changes are:
- a `layout.ld` with 128 kB for kernel and app
- the matching kernel address in the `Makefile`
- different `StorageLocation`s in `build.rs`
For everything else, please check the README in `../nrf52840dk_opensk`.

View File

@@ -1,45 +0,0 @@
use std::env;
use std::fs;
use std::path::Path;
fn main() {
println!("cargo:rerun-if-changed=layout.ld");
println!("cargo:rerun-if-changed=../../kernel_layout.ld");
let out_dir = env::var_os("OUT_DIR").unwrap();
let dest_path = Path::new(&out_dir).join("locations.rs");
fs::write(
&dest_path,
"
static mut STORAGE_LOCATIONS: [kernel::StorageLocation; 5] = [
// We implement NUM_PAGES = 20 as 16 + 4 to satisfy the MPU.
kernel::StorageLocation {
address: 0xC0000,
size: 0x10000, // 16 pages
storage_type: kernel::StorageType::STORE,
},
kernel::StorageLocation {
address: 0xD0000,
size: 0x4000, // 4 pages
storage_type: kernel::StorageType::STORE,
},
// Partitions can also be split to maximize MPU happiness.
kernel::StorageLocation {
address: 0x20000,
size: 0x20000,
storage_type: kernel::StorageType::PARTITION,
},
kernel::StorageLocation {
address: 0x40000,
size: 0x20000,
storage_type: kernel::StorageType::PARTITION,
},
kernel::StorageLocation {
address: 0x4000,
size: 0x1000,
storage_type: kernel::StorageType::METADATA,
},
];
"
).unwrap();
}

View File

@@ -1,13 +0,0 @@
/* Memory Space Definitions, 1M flash, 256K ram */
MEMORY
{
rom (rx) : ORIGIN = 0x00060000, LENGTH = 128K
prog (rx) : ORIGIN = 0x00080000, LENGTH = 128K
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 256K
}
MPU_MIN_ALIGN = 8K;
PAGE_SIZE = 4K;
INCLUDE ../../kernel_layout.ld

View File

@@ -1,2 +0,0 @@
[target.thumbv7em-none-eabi]
linker = "arm-none-eabi-gcc"

282
bootloader/Cargo.lock generated
View File

@@ -1,282 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "aligned"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a785a543aea40f5e4e2e93bb2655d31bc21bb391fff65697150973e383f16bb"
dependencies = [
"as-slice",
]
[[package]]
name = "as-slice"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45403b49e3954a4b8428a0ac21a4b7afadccf92bfd96273f1a58cd4812496ae0"
dependencies = [
"generic-array 0.12.4",
"generic-array 0.13.3",
"generic-array 0.14.6",
"stable_deref_trait",
]
[[package]]
name = "bare-metal"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3"
dependencies = [
"rustc_version",
]
[[package]]
name = "bitfield"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719"
[[package]]
name = "bootloader"
version = "0.1.0"
dependencies = [
"byteorder",
"cortex-m 0.6.7",
"cortex-m-rt",
"cortex-m-rt-macros",
"panic-abort",
"rtt-target",
"tock-registers",
]
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cortex-m"
version = "0.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9075300b07c6a56263b9b582c214d0ff037b00d45ec9fde1cc711490c56f1bb9"
dependencies = [
"aligned",
"bare-metal",
"bitfield",
"cortex-m 0.7.6",
"volatile-register",
]
[[package]]
name = "cortex-m"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70858629a458fdfd39f9675c4dc309411f2a3f83bede76988d81bf1a0ecee9e0"
dependencies = [
"bare-metal",
"bitfield",
"embedded-hal",
"volatile-register",
]
[[package]]
name = "cortex-m-rt"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c433da385b720d5bb9f52362fa2782420798e68d40d67bfe4b0d992aba5dfe7"
dependencies = [
"cortex-m-rt-macros",
]
[[package]]
name = "cortex-m-rt-macros"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0f6f3e36f203cfedbc78b357fb28730aa2c6dc1ab060ee5c2405e843988d3c7"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "embedded-hal"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff"
dependencies = [
"nb 0.1.3",
"void",
]
[[package]]
name = "generic-array"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd"
dependencies = [
"typenum",
]
[[package]]
name = "generic-array"
version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f797e67af32588215eaaab8327027ee8e71b9dd0b2b26996aedf20c030fce309"
dependencies = [
"typenum",
]
[[package]]
name = "generic-array"
version = "0.14.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "nb"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f"
dependencies = [
"nb 1.0.0",
]
[[package]]
name = "nb"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae"
[[package]]
name = "panic-abort"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e20e6499bbbc412f280b04a42346b356c6fa0753d5fd22b7bd752ff34c778ee"
[[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 = "rtt-target"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "065d6058bb1204f51a562a67209e1817cf714759d5cf845aa45c75fa7b0b9d9b"
dependencies = [
"cortex-m 0.7.6",
"ufmt-write",
]
[[package]]
name = "rustc_version"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
dependencies = [
"semver",
]
[[package]]
name = "semver"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
dependencies = [
"semver-parser",
]
[[package]]
name = "semver-parser"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]]
name = "stable_deref_trait"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[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 = "tock-registers"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f521a79accce68c417c9c77ce22108056b626126da1932f7e2e9b5bbffee0cea"
[[package]]
name = "typenum"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
[[package]]
name = "ufmt-write"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e87a2ed6b42ec5e28cc3b94c09982969e9227600b2e3dcbc1db927a84c06bd69"
[[package]]
name = "unicode-ident"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd"
[[package]]
name = "vcell"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "void"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
[[package]]
name = "volatile-register"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ee8f19f9d74293faf70901bc20ad067dc1ad390d2cbf1e3f75f721ffee908b6"
dependencies = [
"vcell",
]

View File

@@ -1,29 +0,0 @@
[package]
name = "bootloader"
version = "0.1.0"
authors = [
"Fabian Kaczmarczyck <kaczmarczyck@google.com>",
]
build = "build.rs"
license = "Apache-2.0"
edition = "2018"
[dependencies]
byteorder = { version = "1", default-features = false }
cortex-m = "^0.6.0"
cortex-m-rt = "*"
cortex-m-rt-macros = "*"
panic-abort = "0.3.2"
rtt-target = { version = "*", features = ["cortex-m"] }
tock-registers = { version = "0.6.0", features = ["no_std_unit_tests"] }
[profile.dev]
panic = "abort"
lto = true
opt-level = 3
[profile.release]
panic = "abort"
lto = true
# Level "z" may decrease the binary size more of necessary.
opt-level = 3

View File

@@ -1,36 +0,0 @@
# OpenSK Bootloader
This bootloader supports upgradability for OpenSK. Its functionality is to
- check images on A/B partitions,
- boot the most recent valid partition.
## How to use
The bootloader is built and deployed by OpenSK's `deploy.py`. If your board
defines a metadata address, it is detected as an upgradable board and this
bootloader is flashed to memory address 0.
## How to debug
The bootloader prints debug message over RTT when compiled in debug mode. Using
`nrfjprog` for flashing and inspecting memory is recommended for debugging.
```shell
RUSTFLAGS="-C link-arg=-Wl,-Tlink.x -C link-arg=-nostartfiles" \
cargo build --target thumbv7em-none-eabi
llvm-objcopy -O ihex target/thumbv7em-none-eabi/debug/bootloader \
target/thumbv7em-none-eabi/debug/bootloader.hex
nrfjprog --program target/thumbv7em-none-eabi/debug/bootloader.hex \
--sectorerase -f nrf52 --reset
```
To read the debug messages, open two terminals for:
```shell
JLinkRTTLogger -device NRF52840_XXAA -if swd -speed 1000 -RTTchannel 0
JLinkRTTClient
```
The first command also logs the output to a file. The second shows all output in
real time.

View File

@@ -1,17 +0,0 @@
// Copyright 2021 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.
fn main() {
println!("cargo:rerun-if-changed=memory.x");
}

View File

@@ -1,21 +0,0 @@
/* Copyright 2021 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.
*/
MEMORY
{
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 16K
RAM (rwx) : ORIGIN = 0x20020000, LENGTH = 128K
}

View File

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

View File

@@ -1,118 +0,0 @@
// Copyright 2020-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 tock_registers::register_bitfields;
register_bitfields! [u32,
// Generic or shared bitfields
pub Task [
ENABLE OFFSET(0) NUMBITS(1)
],
pub Byte [
VALUE OFFSET(0) NUMBITS(8)
],
pub Busy [
/// Asserted when AES_BUSY or DES_BUSY or HASH_BUSY are asserted or when the DIN FIFO is not empty
BUSY OFFSET(0) NUMBITS(1) [
Ready = 0,
Busy = 1
]
],
// CC_CTL register bitfields
pub CryptoMode [
/// Determines the active cryptographic engine
MODE OFFSET(0) NUMBITS(5) [
Bypass = 0,
Aes = 1,
AesToHash = 2,
AesAndHash = 3,
Des = 4,
DesToHash = 5,
DesAndHash = 6,
Hash = 7,
AesMacAndBypass = 9,
AesToHashAndDout = 10
]
],
// HOST_RGF register bitfields
pub Interrupts [
/// This interrupt is asserted when all data was delivered to DIN buffer from SRAM
SRAM_TO_DIN OFFSET(4) NUMBITS(1),
/// This interrupt is asserted when all data was delivered to SRAM buffer from DOUT
DOUT_TO_SRAM OFFSET(5) NUMBITS(1),
/// This interrupt is asserted when all data was delivered to DIN buffer from memory
MEM_TO_DIN OFFSET(6) NUMBITS(1),
/// This interrupt is asserted when all data was delivered to memory buffer from DOUT
DOUT_TO_MEM OFFSET(7) NUMBITS(1),
AXI_ERROR OFFSET(8) NUMBITS(1),
/// The PKA end of operation interrupt status
PKA_EXP OFFSET(9) NUMBITS(1),
/// The RNG interrupt status
RNG OFFSET(10) NUMBITS(1),
/// The GPR interrupt status
SYM_DMA_COMPLETED OFFSET(11) NUMBITS(1)
],
pub RgfEndianness [
/// DOUT write endianness
DOUT_WR_BG OFFSET(3) NUMBITS(1) [
LittleEndian = 0,
BigEndian = 1
],
/// DIN write endianness
DIN_RD_BG OFFSET(7) NUMBITS(1) [
LittleEndian = 0,
BigEndian = 1
],
/// DOUT write word endianness
DOUT_WR_WBG OFFSET(11) NUMBITS(1) [
LittleEndian = 0,
BigEndian = 1
],
/// DIN write word endianness
DIN_RD_WBG OFFSET(15) NUMBITS(1) [
LittleEndian = 0,
BigEndian = 1
]
],
// DIN and DOUT register bitfields
pub LliWord1 [
/// Total number of bytes to read using DMA in this entry
BYTES_NUM OFFSET(0) NUMBITS(30),
/// Indicates the first LLI entry
FIRST OFFSET(30) NUMBITS(1),
/// Indicates the last LLI entry
LAST OFFSET(31) NUMBITS(1)
],
pub HashControl [
// bit 2 is reserved but to simplify the logic we include it in the bitfield.
MODE OFFSET(0) NUMBITS(4) [
MD5 = 0,
SHA1 = 1,
SHA256 = 2,
SHA224 = 10
]
],
pub PaddingConfig [
/// Enable Padding generation. must be reset upon completion of padding.
DO_PAD OFFSET(2) NUMBITS(1)
]
];

View File

@@ -1,283 +0,0 @@
// Copyright 2019-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.
//! CryptoCell 310
//!
//! Author
//! -------------------
//!
//! * Author: Jean-Michel Picod <jmichel@google.com>
//! * Date: October 1 2019
use super::bitfields;
use super::registers::{CryptoCellRegisters, NordicCC310Registers};
use super::static_ref::StaticRef;
use core::cell::Cell;
#[cfg(debug_assertions)]
use rtt_target::rprintln;
const SHA256_INIT_VALUE: [u32; 8] = [
0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19,
];
#[derive(Copy, Clone)]
enum DigestAlgorithm {
Sha256 = 2,
}
#[derive(Copy, Clone)]
enum OperationMode {
Idle,
Hash,
}
pub struct CryptoCell310 {
registers: StaticRef<CryptoCellRegisters>,
power: StaticRef<NordicCC310Registers>,
current_op: Cell<OperationMode>,
hash_ctx: Cell<[u32; 8]>,
hash_total_size: Cell<u64>,
}
const CC310_BASE: StaticRef<CryptoCellRegisters> =
unsafe { StaticRef::new(0x5002B000 as *const CryptoCellRegisters) };
const CC310_POWER: StaticRef<NordicCC310Registers> =
unsafe { StaticRef::new(0x5002A500 as *const NordicCC310Registers) };
// Identification "signature" for CryptoCell. According to the documentation, the value
// held by this register is a fixed value, used by Host driver to verify CryptoCell presence
// at this address.
// This value was read from a CryptoCell-310 on a nRF52840-dongle kit.
const CC310_SIGNATURE: u32 = 0x20E00000;
impl CryptoCell310 {
/// Creates a new instance of cryptocell state.
pub const fn new() -> Self {
CryptoCell310 {
registers: CC310_BASE,
power: CC310_POWER,
current_op: Cell::new(OperationMode::Idle),
hash_ctx: Cell::new(SHA256_INIT_VALUE),
hash_total_size: Cell::new(0),
}
}
fn enable(&self) {
self.power.enable.write(bitfields::Task::ENABLE::SET);
for _i in 1..10 {
let read_signature = self.registers.host_rgf.signature.get();
if read_signature != CC310_SIGNATURE {
#[cfg(debug_assertions)]
rprintln!(
"[loop {}] Invalid CC310 signature. Expected {}, got {}\n",
_i,
CC310_SIGNATURE,
read_signature
);
} else {
break;
}
}
if self.registers.host_rgf.signature.get() != CC310_SIGNATURE {
panic!("Failed to initialize CC310");
}
// Make sure everything is set to little endian
self.registers.host_rgf.endian.write(
bitfields::RgfEndianness::DOUT_WR_BG::LittleEndian
+ bitfields::RgfEndianness::DIN_RD_BG::LittleEndian
+ bitfields::RgfEndianness::DOUT_WR_WBG::LittleEndian
+ bitfields::RgfEndianness::DIN_RD_WBG::LittleEndian,
);
// Always start the clock for DMA engine. It's too hard to keep
// track of which submodule needs DMA otherwise.
self.registers
.misc
.dma_clk_enable
.write(bitfields::Task::ENABLE::SET);
self.registers.host_rgf.interrupt_mask.write(
bitfields::Interrupts::SRAM_TO_DIN::CLEAR
+ bitfields::Interrupts::DOUT_TO_SRAM::CLEAR
+ bitfields::Interrupts::MEM_TO_DIN::CLEAR
+ bitfields::Interrupts::DOUT_TO_MEM::CLEAR
+ bitfields::Interrupts::AXI_ERROR::SET
+ bitfields::Interrupts::PKA_EXP::SET
+ bitfields::Interrupts::RNG::SET
+ bitfields::Interrupts::SYM_DMA_COMPLETED::CLEAR,
);
}
fn disable(&self) {
self.registers.host_rgf.interrupt_mask.set(0);
self.power.enable.write(bitfields::Task::ENABLE::CLEAR);
self.registers
.misc
.dma_clk_enable
.write(bitfields::Task::ENABLE::CLEAR);
}
fn clear_data(&self) {
let mut ctx = self.hash_ctx.get();
ctx.iter_mut().for_each(|b| *b = 0);
self.hash_ctx.set(ctx);
self.hash_total_size.set(0);
}
/// Adds data to the current hash computation.
///
/// You have to know in advance if is this is going to be the last block, and indicate that
/// correctly. Sizes of chunks before the last need to be multiples of 64.
pub fn update(&self, data: &[u8], is_last_block: bool) {
// Start CryptoCell
self.enable();
while self.registers.ctrl.hash_busy.is_set(bitfields::Busy::BUSY) {}
while self
.registers
.ctrl
.crypto_busy
.is_set(bitfields::Busy::BUSY)
{}
while self
.registers
.din
.mem_dma_busy
.is_set(bitfields::Busy::BUSY)
{}
// Start HASH module and configure it
self.current_op.set(OperationMode::Hash);
self.registers
.misc
.hash_clk_enable
.write(bitfields::Task::ENABLE::SET);
self.registers
.ctrl
.crypto_ctl
.write(bitfields::CryptoMode::MODE::Hash);
self.registers
.hash
.padding
.write(bitfields::Task::ENABLE::SET);
let size = self.hash_total_size.get();
self.registers.hash.hash_len_lsb.set(size as u32);
self.registers
.hash
.hash_len_msb
.set(size.wrapping_shr(32) as u32);
self.registers
.hash
.control
.set(DigestAlgorithm::Sha256 as u32);
// Digest must be set backwards because writing to HASH[0]
// starts computation
let mut digest = self.hash_ctx.get();
for i in (0..digest.len()).rev() {
self.registers.hash.hash[i].set(digest[i]);
}
while self.registers.ctrl.hash_busy.is_set(bitfields::Busy::BUSY) {}
// Process data
if !data.is_empty() {
if is_last_block {
self.registers
.hash
.auto_hw_padding
.write(bitfields::Task::ENABLE::SET);
}
self.registers.din.src_lli_word0.set(data.as_ptr() as u32);
self.registers
.din
.src_lli_word1
.write(bitfields::LliWord1::BYTES_NUM.val(data.len() as u32));
while !self
.registers
.host_rgf
.interrupts
.is_set(bitfields::Interrupts::MEM_TO_DIN)
{}
self.registers
.host_rgf
.interrupt_clear
.write(bitfields::Interrupts::MEM_TO_DIN::SET);
} else {
// use DO_PAD to complete padding of previous operation
self.registers
.hash
.pad_config
.write(bitfields::PaddingConfig::DO_PAD::SET);
}
while self
.registers
.ctrl
.crypto_busy
.is_set(bitfields::Busy::BUSY)
{}
while self
.registers
.din
.mem_dma_busy
.is_set(bitfields::Busy::BUSY)
{}
// Update context and total size
for i in (0..digest.len()).rev() {
digest[i] = self.registers.hash.hash[i].get();
}
self.hash_ctx.set(digest);
let new_size: u64 = ((self.registers.hash.hash_len_msb.get() as u64) << 32)
+ (self.registers.hash.hash_len_lsb.get() as u64);
self.hash_total_size.set(new_size);
// Disable HASH module
self.registers
.hash
.padding
.write(bitfields::Task::ENABLE::SET);
self.registers
.hash
.auto_hw_padding
.write(bitfields::Task::ENABLE::CLEAR);
self.registers
.hash
.pad_config
.write(bitfields::PaddingConfig::DO_PAD::CLEAR);
while self
.registers
.ctrl
.crypto_busy
.is_set(bitfields::Busy::BUSY)
{}
self.registers
.misc
.hash_clk_enable
.write(bitfields::Task::ENABLE::CLEAR);
self.disable();
}
/// Clears the data for potential reuse, and returns the result.
pub fn finalize_and_clear(&self) -> [u8; 32] {
use byteorder::{BigEndian, ByteOrder};
let words = self.hash_ctx.get();
let mut bytes = [0u8; 32];
for (i, word) in words.iter().enumerate() {
BigEndian::write_u32(&mut bytes[4 * i..4 * i + 4], *word);
}
self.clear_data();
bytes
}
}

View File

@@ -1,176 +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.
#![no_main]
#![no_std]
mod bitfields;
mod crypto_cell;
mod registers;
mod static_ref;
extern crate cortex_m;
extern crate cortex_m_rt as rt;
use byteorder::{ByteOrder, LittleEndian};
use core::convert::TryInto;
use core::ptr;
use cortex_m::asm;
use panic_abort as _;
use rt::entry;
#[cfg(debug_assertions)]
use rtt_target::{rprintln, rtt_init_print};
/// Size of a flash page in bytes.
const PAGE_SIZE: usize = 0x1000;
/// A flash page.
type Page = [u8; PAGE_SIZE];
/// Reads a page of memory.
unsafe fn read_page(address: usize) -> Page {
debug_assert!(address % PAGE_SIZE == 0);
let address_pointer = address as *const Page;
ptr::read(address_pointer)
}
/// Parsed metadata for a firmware partition.
struct Metadata {
checksum: [u8; 32],
timestamp: u32,
address: u32,
}
impl Metadata {
pub const DATA_LEN: usize = 40;
}
/// Reads the metadata from a flash page.
impl From<Page> for Metadata {
fn from(page: Page) -> Self {
Metadata {
checksum: page[0..32].try_into().unwrap(),
timestamp: LittleEndian::read_u32(&page[32..36]),
address: LittleEndian::read_u32(&page[36..Metadata::DATA_LEN]),
}
}
}
/// Location of a firmware partition's data.
struct BootPartition {
firmware_address: usize,
metadata_address: usize,
}
impl BootPartition {
const FIRMWARE_LENGTH: usize = 0x00040000;
/// Reads the metadata, returns the timestamp if all checks pass.
pub fn read_timestamp(&self) -> Result<u32, ()> {
let metadata_page = unsafe { read_page(self.metadata_address) };
let hash_value = self.compute_upgrade_hash(&metadata_page);
let metadata = Metadata::from(metadata_page);
if self.firmware_address != metadata.address as usize {
#[cfg(debug_assertions)]
rprintln!(
"Firmware address mismatch: expected 0x{:08X}, metadata 0x{:08X}",
self.firmware_address,
metadata.address as usize
);
return Err(());
}
if hash_value != metadata.checksum {
#[cfg(debug_assertions)]
rprintln!("Hash mismatch");
return Err(());
}
Ok(metadata.timestamp)
}
/// Computes the SHA256 of metadata information and partition data.
///
/// Assumes that firmware address and length are divisible by the page size.
/// This is the hardware implementation on the cryptocell.
#[allow(clippy::assertions_on_constants)]
fn compute_upgrade_hash(&self, metadata_page: &[u8]) -> [u8; 32] {
debug_assert!(self.firmware_address % PAGE_SIZE == 0);
debug_assert!(BootPartition::FIRMWARE_LENGTH % PAGE_SIZE == 0);
let cc310 = crypto_cell::CryptoCell310::new();
for page_offset in (0..BootPartition::FIRMWARE_LENGTH).step_by(PAGE_SIZE) {
let page = unsafe { read_page(self.firmware_address + page_offset) };
cc310.update(&page, false);
}
cc310.update(&metadata_page[32..Metadata::DATA_LEN], true);
cc310.finalize_and_clear()
}
/// Jump to the firmware.
pub fn boot(&self) -> ! {
let address = self.firmware_address;
// Clear any pending Cryptocell interrupt in NVIC
let peripherals = cortex_m::Peripherals::take().unwrap();
unsafe {
// We could only clear cryptocell interrupts, but let's clean up before booting.
// Example code to clear more specifically:
// const CC310_IRQ: u16 = 42;
// peripherals.NVIC.icpr[usize::from(CC310_IRQ / 32)].write(1 << (CC310_IRQ % 32));
peripherals.NVIC.icer[0].write(0xffff_ffff);
peripherals.NVIC.icpr[0].write(0xffff_ffff);
peripherals.NVIC.icer[1].write(0xffff_ffff);
peripherals.NVIC.icpr[1].write(0xffff_ffff);
}
#[cfg(debug_assertions)]
rprintln!("Boot jump to {:08X}", address);
let address_pointer = address as *const u32;
// https://docs.rs/cortex-m/0.7.2/cortex_m/asm/fn.bootload.html
unsafe { asm::bootload(address_pointer) };
}
}
#[entry]
fn main() -> ! {
#[cfg(debug_assertions)]
rtt_init_print!();
#[cfg(debug_assertions)]
rprintln!("Starting bootloader");
let partition_a = BootPartition {
firmware_address: 0x20000,
metadata_address: 0x4000,
};
let partition_b = BootPartition {
firmware_address: 0x60000,
metadata_address: 0x5000,
};
#[cfg(debug_assertions)]
rprintln!("Reading partition A");
let timestamp_a = partition_a.read_timestamp();
#[cfg(debug_assertions)]
rprintln!("Reading partition B");
let timestamp_b = partition_b.read_timestamp();
match (timestamp_a, timestamp_b) {
(Ok(t1), Ok(t2)) => {
if t1 >= t2 {
partition_a.boot()
} else {
partition_b.boot()
}
}
(Ok(_), Err(_)) => partition_a.boot(),
(Err(_), Ok(_)) => partition_b.boot(),
(Err(_), Err(_)) => panic!(),
}
}

View File

@@ -1,137 +0,0 @@
// Copyright 2020-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::bitfields::{
Busy, CryptoMode, HashControl, Interrupts, LliWord1, PaddingConfig, RgfEndianness, Task,
};
use tock_registers::register_structs;
use tock_registers::registers::{ReadOnly, ReadWrite, WriteOnly};
register_structs! {
pub CryptoCellControlRegisters {
/// Defines the cryptographic flow
(0x0000 => pub crypto_ctl: WriteOnly<u32, CryptoMode::Register>),
(0x0004 => _reserved0),
/// This register is set whent the cryptographic core is busy
(0x0010 => pub crypto_busy: ReadOnly<u32, Busy::Register>),
(0x0014 => _reserved1),
/// This register is set when the Hash engine is busy
(0x001C => pub hash_busy: ReadOnly<u32, Busy::Register>),
(0x0020 => @END),
}
}
register_structs! {
pub CryptoCellDinRegisters {
(0x0000 => _reserved0),
/// Indicates whether memoty (AXI) source DMA (DIN) is busy
(0x0020 => pub mem_dma_busy: ReadOnly<u32, Busy::Register>),
(0x0024 => _reserved1),
/// This register is used in direct LLI mode - holds the location of the data source
/// in the memory (AXI)
(0x0028 => pub src_lli_word0: WriteOnly<u32>),
/// This register is used in direct LLI mode - holds the number of bytes to be read
/// from the memory (AXI).
/// Writing to this register triggers the DMA.
(0x002C => pub src_lli_word1: WriteOnly<u32, LliWord1::Register>),
(0x0030 => @END),
}
}
register_structs! {
pub CryptoCellHashRegisters {
/// Write initial hash value or read final hash value
(0x0000 => pub hash: [ReadWrite<u32>; 9]),
(0x0024 => _reserved0),
/// HW padding automatically activated by engine.
/// For the special case of ZERO bytes data vector this register should not be used! instead use HASH_PAD_CFG
(0x0044 => pub auto_hw_padding: WriteOnly<u32, Task::Register>),
(0x0048 => _reserved1),
/// Selects which HASH mode to run
(0x0180 => pub control: ReadWrite<u32, HashControl::Register>),
/// This register enables the hash hw padding.
(0x0184 => pub padding: ReadWrite<u32, Task::Register>),
/// HASH_PAD_CFG Register.
(0x0188 => pub pad_config: ReadWrite<u32, PaddingConfig::Register>),
/// This register hold the length of current hash operation
(0x018C => pub hash_len_lsb: ReadWrite<u32>),
/// This register hold the length of current hash operation
(0x0190 => pub hash_len_msb: ReadWrite<u32>),
(0x0194 => @END),
}
}
register_structs! {
pub CryptoCellHostRgfRegisters {
/// The Interrupt Request register.
/// Each bit of this register holds the interrupt status of a single interrupt source.
(0x0000 => pub interrupts: ReadOnly<u32, Interrupts::Register>),
/// The Interrupt Mask register. Each bit of this register holds the mask of a single
/// interrupt source.
(0x0004 => pub interrupt_mask: ReadWrite<u32, Interrupts::Register>),
/// Interrupt Clear Register
(0x0008 => pub interrupt_clear: WriteOnly<u32, Interrupts::Register>),
/// This register defines the endianness of the Host-accessible registers.
(0x000C => pub endian: ReadWrite<u32, RgfEndianness::Register>),
(0x0010 => _reserved0),
/// This register holds the CryptoCell product signature.
(0x0024 => pub signature: ReadOnly<u32>),
(0x0028 => @END),
}
}
register_structs! {
pub CryptoCellMiscRegisters {
(0x0000 => _reserved0),
/// The HASH clock enable register
(0x0018 => pub hash_clk_enable: ReadWrite<u32, Task::Register>),
/// The PKA clock enable register
(0x001C => _reserved1),
/// The DMA clock enable register
(0x0020 => pub dma_clk_enable: ReadWrite<u32, Task::Register>),
/// the CryptoCell clocks' status register
(0x0024 => @END),
}
}
register_structs! {
pub NordicCC310Registers {
(0x0000 => pub enable: ReadWrite<u32, Task::Register>),
(0x0004 => @END),
},
pub CryptoCellRegisters {
(0x0000 => _reserved0),
/// HASH registers
/// - Base address: 0x0640
(0x0640 => pub hash: CryptoCellHashRegisters),
(0x07D4 => _reserved1),
/// Misc registers
/// - Base address: 0x0800
(0x0800 => pub misc: CryptoCellMiscRegisters),
(0x0824 => _reserved2),
/// CryptoCell control registers
/// - Base address: 0x0900
(0x0900 => pub ctrl: CryptoCellControlRegisters),
(0x0920 => _reserved3),
/// HOST_RGF registers
/// - Base address: 0x0A00
(0x0A00 => pub host_rgf: CryptoCellHostRgfRegisters),
(0x0A28 => _reserved4),
/// DIN registers
/// - Base address: 0x0C00
(0x0C00 => pub din: CryptoCellDinRegisters),
(0x0C30 => @END),
}
}

View File

@@ -1,46 +0,0 @@
//! Wrapper type for safe pointers to static memory.
//!
//! Imported from:
//! https://github.com/tock/tock/blob/master/kernel/src/utilities/static_ref.rs
use core::ops::Deref;
/// A pointer to statically allocated mutable data such as memory mapped I/O
/// registers.
///
/// This is a simple wrapper around a raw pointer that encapsulates an unsafe
/// dereference in a safe manner. It serve the role of creating a `&'static T`
/// given a raw address and acts similarly to `extern` definitions, except
/// `StaticRef` is subject to module and crate boundaries, while `extern`
/// definitions can be imported anywhere.
#[derive(Debug)]
pub struct StaticRef<T> {
ptr: *const T,
}
impl<T> StaticRef<T> {
/// Create a new `StaticRef` from a raw pointer
///
/// ## Safety
///
/// Callers must pass in a reference to statically allocated memory which
/// does not overlap with other values.
pub const unsafe fn new(ptr: *const T) -> StaticRef<T> {
StaticRef { ptr }
}
}
impl<T> Clone for StaticRef<T> {
fn clone(&self) -> Self {
StaticRef { ptr: self.ptr }
}
}
impl<T> Copy for StaticRef<T> {}
impl<T> Deref for StaticRef<T> {
type Target = T;
fn deref(&self) -> &'static T {
unsafe { &*self.ptr }
}
}

View File

@@ -1,4 +1,4 @@
// Copyright 2019-2021 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.
@@ -12,24 +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.
extern crate alloc; use std::env;
use openssl::{bn, ec, nid};
use sk_cbor::cbor_map;
use std::fs::File; use std::fs::File;
use std::io::{Read, Write}; use std::io::Read;
use std::io::Write;
use std::path::Path; use std::path::Path;
use std::{env, fs};
use uuid::Uuid; use uuid::Uuid;
fn main() { fn main() {
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=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_b.ld");
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");
@@ -41,36 +32,4 @@ fn main() {
content.truncate(36); content.truncate(36);
let aaguid = Uuid::parse_str(&content).unwrap(); let aaguid = Uuid::parse_str(&content).unwrap();
aaguid_bin_file.write_all(aaguid.as_bytes()).unwrap(); aaguid_bin_file.write_all(aaguid.as_bytes()).unwrap();
// COSE encoding the public key, then write it out.
let pem_bytes = fs::read(UPGRADE_FILE).unwrap();
let ec_key = ec::EcKey::public_key_from_pem(&pem_bytes).ok().unwrap();
let group = ec::EcGroup::from_curve_name(nid::Nid::X9_62_PRIME256V1).unwrap();
let conversion_form = ec::PointConversionForm::UNCOMPRESSED;
let mut ctx = bn::BigNumContext::new().unwrap();
let raw_bytes = ec_key
.public_key()
.to_bytes(&group, conversion_form, &mut ctx)
.unwrap();
const POINT_LEN: usize = 32;
assert_eq!(raw_bytes.len(), 1 + 2 * POINT_LEN);
assert_eq!(raw_bytes[0], 0x04);
let x_bytes = &raw_bytes[1..][..POINT_LEN];
let y_bytes = &raw_bytes[1 + POINT_LEN..][..POINT_LEN];
const EC2_KEY_TYPE: i64 = 2;
const P_256_CURVE: i64 = 1;
const ES256_ALGORITHM: i64 = -7;
let pub_key_cbor = sk_cbor::cbor_map! {
1 => EC2_KEY_TYPE,
3 => ES256_ALGORITHM,
-1 => P_256_CURVE,
-2 => x_bytes,
-3 => y_bytes,
};
let mut cbor_bytes = vec![];
sk_cbor::writer::write(pub_key_cbor, &mut cbor_bytes).unwrap();
let upgrade_pubkey_path = Path::new(&out_dir).join("opensk_upgrade_pubkey_cbor.bin");
let mut upgrade_pub_bin_file = File::create(&upgrade_pubkey_path).unwrap();
upgrade_pub_bin_file.write_all(&cbor_bytes).unwrap();
} }

514
deploy.py
View File

@@ -26,8 +26,6 @@ import os
import shutil import shutil
import subprocess import subprocess
import sys import sys
import time
from typing import Dict, List, Tuple
import colorama import colorama
from six.moves import input from six.moves import input
@@ -37,9 +35,6 @@ from tockloader import tbfh
from tockloader import tockloader as loader from tockloader import tockloader as loader
from tockloader.exceptions import TockLoaderException from tockloader.exceptions import TockLoaderException
import tools.configure
from tools.deploy_partition import create_metadata, pad_to
PROGRAMMERS = frozenset(("jlink", "openocd", "pyocd", "nordicdfu", "none")) PROGRAMMERS = frozenset(("jlink", "openocd", "pyocd", "nordicdfu", "none"))
# This structure allows us to support out-of-tree boards as well as (in the # This structure allows us to support out-of-tree boards as well as (in the
@@ -55,19 +50,12 @@ OpenSKBoard = collections.namedtuple(
"page_size", "page_size",
# Flash address at which the kernel will be written # Flash address at which the kernel will be written
"kernel_address", "kernel_address",
# Set to None if padding is not required for the board. # Set to None is padding is not required for the board.
# This creates a fake Tock OS application that starts at the # This creates a fake Tock OS application that starts at the
# address specified by this parameter (must match the `prog` value # address specified by this parameter (must match the `prog` value
# specified on the board's `layout.ld` file) and will end at # specified on the board's `layout.ld` file) and will end at
# `app_address`. # `app_address`.
"padding_address", "padding_address",
# If present, enforce that the firmware image equals this value,
# padding it with 0xFF bytes.
"firmware_size",
# Set to None if metadata is not required for the board.
# Writes the metadata that is checked by the custom bootloader for
# upgradable board.
"metadata_address",
# Linker script to produce a working app for this board # Linker script to produce a working app for this board
"app_ldscript", "app_ldscript",
# Flash address at which the app should be written # Flash address at which the app should be written
@@ -95,18 +83,18 @@ OpenSKBoard = collections.namedtuple(
"nordic_dfu", "nordic_dfu",
]) ])
nrf52840dk_opensk_board = OpenSKBoard( SUPPORTED_BOARDS = {
path="third_party/tock/boards/nordic/nrf52840dk_opensk", "nrf52840dk":
OpenSKBoard(
path="third_party/tock/boards/nordic/nrf52840dk",
arch="thumbv7em-none-eabi", arch="thumbv7em-none-eabi",
page_size=4096, page_size=4096,
kernel_address=0, kernel_address=0,
padding_address=0x30000, padding_address=0x30000,
firmware_size=None,
metadata_address=None,
app_ldscript="nrf52840_layout.ld", app_ldscript="nrf52840_layout.ld",
app_address=0x40000, app_address=0x40000,
storage_address=0xC0000, storage_address=0xC0000,
storage_size=0x14000, storage_size=0x40000,
pyocd_target="nrf52840", pyocd_target="nrf52840",
openocd_board="nordic_nrf52840_dongle.cfg", openocd_board="nordic_nrf52840_dongle.cfg",
openocd_options=[], openocd_options=[],
@@ -114,55 +102,77 @@ nrf52840dk_opensk_board = OpenSKBoard(
jlink_if="swd", jlink_if="swd",
jlink_device="nrf52840_xxaa", jlink_device="nrf52840_xxaa",
nordic_dfu=False, nordic_dfu=False,
) ),
"nrf52840_dongle":
SUPPORTED_BOARDS = { OpenSKBoard(
"nrf52840dk_opensk": path="third_party/tock/boards/nordic/nrf52840_dongle",
nrf52840dk_opensk_board, arch="thumbv7em-none-eabi",
"nrf52840dk_opensk_a": page_size=4096,
nrf52840dk_opensk_board._replace( kernel_address=0,
path=nrf52840dk_opensk_board.path + "_a", padding_address=0x30000,
kernel_address=0x20000, app_ldscript="nrf52840_layout.ld",
padding_address=None,
firmware_size=0x40000,
metadata_address=0x4000,
app_ldscript="nrf52840_layout_a.ld",
app_address=0x40000, app_address=0x40000,
storage_address=0xC0000,
storage_size=0x40000,
pyocd_target="nrf52840",
openocd_board="nordic_nrf52840_dongle.cfg",
openocd_options=[],
openocd_commands={},
jlink_if="swd",
jlink_device="nrf52840_xxaa",
nordic_dfu=False,
), ),
"nrf52840dk_opensk_b":
nrf52840dk_opensk_board._replace(
path=nrf52840dk_opensk_board.path + "_b",
kernel_address=0x60000,
padding_address=None,
firmware_size=0x40000,
metadata_address=0x5000,
app_ldscript="nrf52840_layout_b.ld",
app_address=0x80000,
),
"nrf52840_dongle_opensk":
nrf52840dk_opensk_board._replace(
path="third_party/tock/boards/nordic/nrf52840_dongle_opensk",),
"nrf52840_dongle_dfu": "nrf52840_dongle_dfu":
nrf52840dk_opensk_board._replace( OpenSKBoard(
path="third_party/tock/boards/nordic/nrf52840_dongle_dfu", path="third_party/tock/boards/nordic/nrf52840_dongle_dfu",
arch="thumbv7em-none-eabi",
page_size=4096,
kernel_address=0x1000, kernel_address=0x1000,
padding_address=0x30000,
app_ldscript="nrf52840_layout.ld",
app_address=0x40000,
storage_address=0xC0000,
storage_size=0x40000,
pyocd_target="nrf52840",
openocd_board="nordic_nrf52840_dongle.cfg",
openocd_options=[],
openocd_commands={},
jlink_if="swd",
jlink_device="nrf52840_xxaa",
nordic_dfu=True, nordic_dfu=True,
), ),
"nrf52840_mdk_dfu": "nrf52840_mdk_dfu":
nrf52840dk_opensk_board._replace( OpenSKBoard(
path="third_party/tock/boards/nordic/nrf52840_mdk_dfu", path="third_party/tock/boards/nordic/nrf52840_mdk_dfu",
arch="thumbv7em-none-eabi",
page_size=4096,
kernel_address=0x1000, kernel_address=0x1000,
padding_address=0x30000,
app_ldscript="nrf52840_layout.ld",
app_address=0x40000,
storage_address=0xC0000,
storage_size=0x40000,
pyocd_target="nrf52840",
openocd_board="nordic_nrf52840_dongle.cfg",
openocd_options=[],
openocd_commands={},
jlink_if="swd",
jlink_device="nrf52840_xxaa",
nordic_dfu=True, nordic_dfu=True,
), ),
} }
# The STACK_SIZE value below must match the one used in the linker script
# used by the board.
# e.g. for Nordic nRF52840 boards the file is `nrf52840_layout.ld`.
STACK_SIZE = 0x4000
# The following value must match the one used in the file # The following value must match the one used in the file
# `src/entry_point.rs` # `src/entry_point.rs`
APP_HEAP_SIZE = 90000 APP_HEAP_SIZE = 90000
def get_supported_boards() -> Tuple[str]: def get_supported_boards():
"""Returns a tuple all valid supported boards."""
boards = [] boards = []
for name, props in SUPPORTED_BOARDS.items(): for name, props in SUPPORTED_BOARDS.items():
if all((os.path.exists(os.path.join(props.path, "Cargo.toml")), if all((os.path.exists(os.path.join(props.path, "Cargo.toml")),
@@ -171,28 +181,28 @@ def get_supported_boards() -> Tuple[str]:
return tuple(set(boards)) return tuple(set(boards))
def fatal(msg: str): def fatal(msg):
print(f"{colorama.Fore.RED + colorama.Style.BRIGHT}fatal:" print(f"{colorama.Fore.RED + colorama.Style.BRIGHT}fatal:"
f"{colorama.Style.RESET_ALL} {msg}") f"{colorama.Style.RESET_ALL} {msg}")
sys.exit(1) sys.exit(1)
def error(msg: str): def error(msg):
print(f"{colorama.Fore.RED}error:{colorama.Style.RESET_ALL} {msg}") print(f"{colorama.Fore.RED}error:{colorama.Style.RESET_ALL} {msg}")
def info(msg: str): def info(msg):
print(f"{colorama.Fore.GREEN + colorama.Style.BRIGHT}info:" print(f"{colorama.Fore.GREEN + colorama.Style.BRIGHT}info:"
f"{colorama.Style.RESET_ALL} {msg}") f"{colorama.Style.RESET_ALL} {msg}")
def assert_mandatory_binary(binary_name: str): def assert_mandatory_binary(binary):
if not shutil.which(binary_name): if not shutil.which(binary):
fatal((f"Couldn't find {binary_name} binary. Make sure it is installed and " fatal((f"Couldn't find {binary} binary. Make sure it is installed and "
"that your PATH is set correctly.")) "that your PATH is set correctly."))
def assert_python_library(module: str): def assert_python_library(module):
try: try:
__import__(module) __import__(module)
except ModuleNotFoundError: except ModuleNotFoundError:
@@ -238,18 +248,6 @@ class RemoveConstAction(argparse.Action):
class OpenSKInstaller: class OpenSKInstaller:
"""Checks, builds and installs various parts of OpenSK.
This module can perform the following tasks:
- build and install Tock OS
- check, build and install the main ctap2 application
- build and install example applications
- write padding
- erase apps and persistent storage
- write metadata entries for upgradable boards
OpenSKInstaller(args).run()
"""
def __init__(self, args): def __init__(self, args):
self.args = args self.args = args
@@ -257,7 +255,6 @@ class OpenSKInstaller:
self.tab_folder = os.path.join("target", "tab") self.tab_folder = os.path.join("target", "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,
arch=board.arch, arch=board.arch,
board=self.args.board, board=self.args.board,
bundle_apps=False, bundle_apps=False,
@@ -270,7 +267,7 @@ class OpenSKInstaller:
jlink_speed=1200, jlink_speed=1200,
openocd=self.args.programmer == "openocd", openocd=self.args.programmer == "openocd",
openocd_board=board.openocd_board, openocd_board=board.openocd_board,
openocd_cmd=self.args.openocd_cmd, openocd_cmd="openocd",
openocd_commands=copy.copy(board.openocd_commands), openocd_commands=copy.copy(board.openocd_commands),
openocd_options=copy.copy(board.openocd_options), openocd_options=copy.copy(board.openocd_options),
jtag=False, jtag=False,
@@ -279,21 +276,7 @@ class OpenSKInstaller:
port=None, port=None,
) )
def checked_command(self, def checked_command(self, cmd, env=None, cwd=None):
cmd: List[str],
env: Dict[str, str] = None,
cwd: str = None):
"""Executes the given command.
Outside of debug mode, the command's output is muted. Exits if the called
process returns an error.
Args:
cmd: A list of strings. The first string is the command, the other list
elements are parameters to that command."
env: The dictionary of environment variables.
cwd: The directory to execute from.
"""
stdout = None if self.args.verbose_build else subprocess.DEVNULL stdout = None if self.args.verbose_build else subprocess.DEVNULL
try: try:
subprocess.run( subprocess.run(
@@ -301,11 +284,7 @@ class OpenSKInstaller:
except subprocess.CalledProcessError as e: except subprocess.CalledProcessError as e:
fatal(f"Failed to execute {cmd[0]}: {str(e)}") fatal(f"Failed to execute {cmd[0]}: {str(e)}")
def checked_command_output(self, def checked_command_output(self, cmd, env=None, cwd=None):
cmd: List[str],
env: Dict[str, str] = None,
cwd: str = None) -> str:
"""Executes cmd like checked_command, but returns the output."""
cmd_output = "" cmd_output = ""
try: try:
cmd_output = subprocess.run( cmd_output = subprocess.run(
@@ -321,7 +300,6 @@ class OpenSKInstaller:
return cmd_output.decode() return cmd_output.decode()
def update_rustc_if_needed(self): def update_rustc_if_needed(self):
"""Updates the Rust and installs the necessary target toolchain."""
target_toolchain_fullstring = "stable" target_toolchain_fullstring = "stable"
with open("rust-toolchain", "r", encoding="utf-8") as f: with open("rust-toolchain", "r", encoding="utf-8") as f:
content = f.readlines() content = f.readlines()
@@ -361,7 +339,6 @@ class OpenSKInstaller:
info("Rust toolchain up-to-date") info("Rust toolchain up-to-date")
def build_tockos(self): def build_tockos(self):
"""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}")
props = SUPPORTED_BOARDS[self.args.board] props = SUPPORTED_BOARDS[self.args.board]
out_directory = os.path.join("third_party", "tock", "target", props.arch, out_directory = os.path.join("third_party", "tock", "target", props.arch,
@@ -371,66 +348,17 @@ class OpenSKInstaller:
env = os.environ.copy() env = os.environ.copy()
if self.args.verbose_build: if self.args.verbose_build:
env["V"] = "1" env["V"] = "1"
if "vendor_hid" in self.args.features:
env["CARGO_FLAGS"] = "--features=vendor_hid"
self.checked_command(["make"], cwd=props.path, env=env) self.checked_command(["make"], cwd=props.path, env=env)
def build_example(self): def build_example(self):
"""Builds an example with the name from args."""
info(f"Building example {self.args.application}") info(f"Building example {self.args.application}")
self._build_app_or_example(is_example=True) self._build_app_or_example(is_example=True)
def build_opensk(self): def build_opensk(self):
"""Runs essential tests in OpenSK, then builds it if successful."""
info("Building OpenSK application") info("Building OpenSK application")
self._check_invariants()
self._build_app_or_example(is_example=False) self._build_app_or_example(is_example=False)
def build_bootloader(self): def _build_app_or_example(self, is_example):
"""Builds the upgrade bootloader."""
props = SUPPORTED_BOARDS[self.args.board]
info("Building bootloader")
rust_flags = [
f"--remap-path-prefix={os.getcwd()}=",
"-C",
"link-arg=-Wl,-Tlink.x",
"-C",
"link-arg=-nostartfiles",
]
env = os.environ.copy()
env["RUSTFLAGS"] = " ".join(rust_flags)
cargo_command = ["cargo", "build", "--release", f"--target={props.arch}"]
self.checked_command(cargo_command, cwd="bootloader", env=env)
binary_path = os.path.join("target", props.arch, "release", "bootloader")
objcopy_command = [
"llvm-objcopy", "-O", "binary", binary_path, f"{binary_path}.bin"
]
self.checked_command(objcopy_command, cwd="bootloader")
def flash_bootloader(self):
"""Flashes the upgrade bootloader."""
props = SUPPORTED_BOARDS[self.args.board]
info("Flashing bootloader")
bin_file = os.path.join("bootloader", "target", props.arch, "release",
"bootloader.bin")
if not os.path.exists(bin_file):
fatal(f"File not found: {bin_file}")
with open(bin_file, "rb") as bootloader_bin:
bootloader = bootloader_bin.read()
self.write_binary(bootloader, 0)
def _build_app_or_example(self, is_example: bool):
"""Builds the application specified through args.
This function specifies the used compile time flags, specifying the linker
script and reducing the binary size. It compiles the application and calls
elf2tab to create a TAB file out of the produced binary.
The settings in self.args have to match is_example.
Args:
is_example: Whether args.application is an example or the main ctap2 app.
"""
assert self.args.application assert self.args.application
# Ideally we would build a TAB file for all boards at once but depending on # Ideally we would build a TAB file for all boards at once but depending on
# the chip on the board, the link script could be totally different. # the chip on the board, the link script could be totally different.
@@ -445,10 +373,6 @@ class OpenSKInstaller:
"-D", "-D",
"warnings", "warnings",
f"--remap-path-prefix={os.getcwd()}=", f"--remap-path-prefix={os.getcwd()}=",
"-C",
"link-arg=-icf=all",
"-C",
"force-frame-pointers=no",
] ]
env = os.environ.copy() env = os.environ.copy()
env["RUSTFLAGS"] = " ".join(rust_flags) env["RUSTFLAGS"] = " ".join(rust_flags)
@@ -470,18 +394,7 @@ class OpenSKInstaller:
# Create a TAB file # Create a TAB file
self.create_tab_file({props.arch: app_path}) self.create_tab_file({props.arch: app_path})
def _check_invariants(self): def generate_crypto_materials(self, force_regenerate):
"""Runs selected unit tests to check preconditions in the code."""
print("Testing invariants in customization.rs...")
features = ["std"]
features.extend(self.args.features)
self.checked_command_output([
"cargo", "test", f"--features={','.join(features)}", "--lib",
"customization"
])
def generate_crypto_materials(self, force_regenerate: bool):
"""Calls a shell script that generates cryptographic material."""
has_error = subprocess.call([ has_error = subprocess.call([
os.path.join("tools", "gen_key_materials.sh"), os.path.join("tools", "gen_key_materials.sh"),
"Y" if force_regenerate else "N", "Y" if force_regenerate else "N",
@@ -490,18 +403,17 @@ class OpenSKInstaller:
error(("Something went wrong while trying to generate ECC " error(("Something went wrong while trying to generate ECC "
"key and/or certificate for OpenSK")) "key and/or certificate for OpenSK"))
def create_tab_file(self, binary_names: Dict[str, str]): def create_tab_file(self, binaries):
"""Checks and uses elf2tab to generated an TAB file out of the binaries.""" assert binaries
assert binary_names
assert self.args.application assert self.args.application
info("Generating Tock TAB file for application/example " info("Generating Tock TAB file for application/example "
f"{self.args.application}") f"{self.args.application}")
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.6.0":
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.6.0 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")
elf2tab_args = [ elf2tab_args = [
@@ -510,23 +422,13 @@ class OpenSKInstaller:
] ]
if self.args.verbose_build: if self.args.verbose_build:
elf2tab_args.append("--verbose") elf2tab_args.append("--verbose")
stack_sizes = set() for arch, app_file in binaries.items():
for arch, app_file in binary_names.items():
dest_file = os.path.join(self.tab_folder, f"{arch}.elf") dest_file = os.path.join(self.tab_folder, f"{arch}.elf")
shutil.copyfile(app_file, dest_file) shutil.copyfile(app_file, dest_file)
elf2tab_args.append(dest_file) elf2tab_args.append(dest_file)
# extract required stack size directly from binary
nm = self.checked_command_output(
["nm", "--print-size", "--radix=x", app_file])
for line in nm.splitlines():
if "STACK_MEMORY" in line:
required_stack_size = int(line.split(" ", maxsplit=2)[1], 16)
stack_sizes.add(required_stack_size)
if len(stack_sizes) != 1:
error("Detected different stack sizes across tab files.")
elf2tab_args.extend([ elf2tab_args.extend([
f"--stack={stack_sizes.pop()}", f"--app-heap={APP_HEAP_SIZE}", f"--stack={STACK_SIZE}", f"--app-heap={APP_HEAP_SIZE}",
"--kernel-heap=1024", "--protected-region-size=64" "--kernel-heap=1024", "--protected-region-size=64"
]) ])
if self.args.elf2tab_output: if self.args.elf2tab_output:
@@ -535,11 +437,12 @@ class OpenSKInstaller:
else: else:
self.checked_command(elf2tab_args) self.checked_command(elf2tab_args)
def install_tab_file(self, tab_filename: str): def install_tab_file(self, tab_filename):
"""Calls Tockloader to install a TAB file."""
assert self.args.application assert self.args.application
info(f"Installing Tock application {self.args.application}") info(f"Installing Tock application {self.args.application}")
board_props = SUPPORTED_BOARDS[self.args.board]
args = copy.copy(self.tockloader_default_args) args = copy.copy(self.tockloader_default_args)
setattr(args, "app_address", board_props.app_address)
setattr(args, "erase", self.args.clear_apps) setattr(args, "erase", self.args.clear_apps)
setattr(args, "make", False) setattr(args, "make", False)
setattr(args, "no_replace", False) setattr(args, "no_replace", False)
@@ -552,86 +455,46 @@ class OpenSKInstaller:
fatal("Couldn't install Tock application " fatal("Couldn't install Tock application "
f"{self.args.application}: {str(e)}") f"{self.args.application}: {str(e)}")
def get_padding(self) -> bytes: def get_padding(self):
"""Creates a padding application binary."""
padding = tbfh.TBFHeaderPadding( padding = tbfh.TBFHeaderPadding(
SUPPORTED_BOARDS[self.args.board].app_address - SUPPORTED_BOARDS[self.args.board].app_address -
SUPPORTED_BOARDS[self.args.board].padding_address) SUPPORTED_BOARDS[self.args.board].padding_address)
return padding.get_binary() return padding.get_binary()
def write_binary(self, binary: bytes, address: int): def install_tock_os(self):
"""Writes a binary to the device's flash at the given address."""
tock = loader.TockLoader(self.tockloader_default_args)
tock.open()
try:
tock.flash_binary(binary, address)
except TockLoaderException as e:
fatal(f"Couldn't write binary: {str(e)}")
def read_kernel(self) -> bytes:
"""Reads the kernel file from disk and returns it as a byte array."""
board_props = SUPPORTED_BOARDS[self.args.board] board_props = SUPPORTED_BOARDS[self.args.board]
kernel_file = os.path.join("third_party", "tock", "target", kernel_file = os.path.join("third_party", "tock", "target",
board_props.arch, "release", board_props.arch, "release",
f"{self.args.board}.bin") f"{self.args.board}.bin")
if not os.path.exists(kernel_file): info(f"Flashing file {kernel_file}.")
fatal(f"File not found: {kernel_file}") with open(kernel_file, "rb") as f:
with open(kernel_file, "rb") as firmware: kernel = f.read()
kernel = firmware.read() args = copy.copy(self.tockloader_default_args)
setattr(args, "address", board_props.app_address)
# Pads the kernel to the expected length. tock = loader.TockLoader(args)
if board_props.padding_address is None: tock.open()
end_address = board_props.app_address try:
else: tock.flash_binary(kernel, board_props.kernel_address)
end_address = board_props.padding_address except TockLoaderException as e:
kernel_size = end_address - board_props.kernel_address fatal(f"Couldn't install Tock OS: {str(e)}")
return pad_to(kernel, kernel_size)
def install_tock_os(self):
"""Reads the kernel from disk and writes it to the device's flash."""
kernel = self.read_kernel()
board_props = SUPPORTED_BOARDS[self.args.board]
self.write_binary(kernel, board_props.kernel_address)
def install_padding(self): def install_padding(self):
"""Generates a padding application and writes it to the address in args.""" padding = self.get_padding()
board_props = SUPPORTED_BOARDS[self.args.board] board_props = SUPPORTED_BOARDS[self.args.board]
if board_props.padding_address is None:
return
info("Flashing padding application") info("Flashing padding application")
self.write_binary(self.get_padding(), board_props.padding_address) args = copy.copy(self.tockloader_default_args)
setattr(args, "address", board_props.padding_address)
def install_metadata(self): tock = loader.TockLoader(args)
"""Generates and writes firmware metadata at the metadata address.""" tock.open()
board_props = SUPPORTED_BOARDS[self.args.board] try:
if board_props.metadata_address is None: tock.flash_binary(padding, args.address)
return except TockLoaderException as e:
fatal(f"Couldn't install padding: {str(e)}")
kernel = self.read_kernel()
app_tab_path = "target/tab/ctap2.tab"
if not os.path.exists(app_tab_path):
fatal(f"File not found: {app_tab_path}")
app_tab = tab.TAB(app_tab_path)
arch = board_props.arch
if arch not in app_tab.get_supported_architectures():
fatal(f"Architecture not found: {arch}")
app = app_tab.extract_app(arch).get_binary(board_props.app_address)
kernel_size = board_props.app_address - board_props.kernel_address
app_size = board_props.firmware_size - kernel_size
# The kernel is already padded when read.
firmware_image = kernel + pad_to(app, app_size)
metadata = create_metadata(firmware_image, board_props.kernel_address)
if self.args.verbose_build:
info(f"Metadata bytes: {metadata}")
info("Flashing metadata application")
self.write_binary(metadata, board_props.metadata_address)
def clear_apps(self): def clear_apps(self):
"""Uses Tockloader to erase all applications on the device."""
args = copy.copy(self.tockloader_default_args) args = copy.copy(self.tockloader_default_args)
board_props = SUPPORTED_BOARDS[self.args.board]
setattr(args, "app_address", board_props.app_address)
# Ensure we don't force erase all apps but only the apps starting # Ensure we don't force erase all apps but only the apps starting
# at `board.app_address`. This makes sure we don't erase the padding. # at `board.app_address`. This makes sure we don't erase the padding.
setattr(args, "force", False) setattr(args, "force", False)
@@ -645,7 +508,6 @@ class OpenSKInstaller:
info(f"A non-critical error occurred while erasing apps: {str(e)}") info(f"A non-critical error occurred while erasing apps: {str(e)}")
def clear_storage(self): def clear_storage(self):
"""Overwrites the storage's flash with 0xFF bytes."""
if self.args.programmer == "none": if self.args.programmer == "none":
return 0 return 0
info("Erasing the persistent storage") info("Erasing the persistent storage")
@@ -653,7 +515,12 @@ class OpenSKInstaller:
# Use tockloader if possible # Use tockloader if possible
if self.args.programmer in ("jlink", "openocd"): if self.args.programmer in ("jlink", "openocd"):
storage = bytes([0xFF] * board_props.storage_size) storage = bytes([0xFF] * board_props.storage_size)
self.write_binary(storage, board_props.storage_address) tock = loader.TockLoader(self.tockloader_default_args)
tock.open()
try:
tock.flash_binary(storage, board_props.storage_address)
except TockLoaderException as e:
fatal(f"Couldn't erase the persistent storage: {str(e)}")
return 0 return 0
if self.args.programmer == "pyocd": if self.args.programmer == "pyocd":
self.checked_command([ self.checked_command([
@@ -664,11 +531,11 @@ class OpenSKInstaller:
fatal(f"Programmer {self.args.programmer} is not supported.") fatal(f"Programmer {self.args.programmer} is not supported.")
# pylint: disable=protected-access # pylint: disable=protected-access
def verify_flashed_app(self, expected_app: str) -> bool: def verify_flashed_app(self, expected_app):
"""Uses Tockloader to check if an app of the expected name was written."""
if self.args.programmer not in ("jlink", "openocd"): if self.args.programmer not in ("jlink", "openocd"):
return False return False
tock = loader.TockLoader(self.tockloader_default_args) args = copy.copy(self.tockloader_default_args)
tock = loader.TockLoader(args)
tock.open() tock.open()
app_found = False app_found = False
with tock._start_communication_with_board(): with tock._start_communication_with_board():
@@ -676,8 +543,7 @@ class OpenSKInstaller:
app_found = expected_app in apps app_found = expected_app in apps
return app_found return app_found
def create_hex_file(self, dest_file: str): def create_hex_file(self, dest_file):
"""Creates an intelhex file from the kernel and app binaries on disk."""
# We produce an intelhex file with everything in it # We produce an intelhex file with everything in it
# https://en.wikipedia.org/wiki/Intel_HEX # https://en.wikipedia.org/wiki/Intel_HEX
# pylint: disable=g-import-not-at-top,import-outside-toplevel # pylint: disable=g-import-not-at-top,import-outside-toplevel
@@ -687,8 +553,12 @@ class OpenSKInstaller:
if self.args.tockos: if self.args.tockos:
# Process kernel # Process kernel
kernel_path = os.path.join("third_party", "tock", "target",
board_props.arch, "release",
f"{self.args.board}.bin")
with open(kernel_path, "rb") as kernel:
kern_hex = intelhex.IntelHex() kern_hex = intelhex.IntelHex()
kern_hex.frombytes(self.read_kernel(), offset=board_props.kernel_address) kern_hex.frombytes(kernel.read(), offset=board_props.kernel_address)
final_hex.merge(kern_hex, overlap="error") final_hex.merge(kern_hex, overlap="error")
if self.args.application: if self.args.application:
@@ -716,7 +586,6 @@ class OpenSKInstaller:
final_hex.tofile(dest_file, format="hex") final_hex.tofile(dest_file, format="hex")
def check_prerequisites(self): def check_prerequisites(self):
"""Checks versions of the used tools, exits on version mismatch."""
if not tockloader.__version__.startswith("1.5."): if not tockloader.__version__.startswith("1.5."):
fatal(("Your version of tockloader seems incompatible: found " fatal(("Your version of tockloader seems incompatible: found "
f"{tockloader.__version__}, expected 1.5.x.")) f"{tockloader.__version__}, expected 1.5.x."))
@@ -747,41 +616,19 @@ class OpenSKInstaller:
if self.args.programmer == "none": if self.args.programmer == "none":
assert_python_library("intelhex") assert_python_library("intelhex")
def configure_device(self): def run(self):
"""Checks the device configuration, and sets it according to args."""
configure_response = tools.configure.main(
argparse.Namespace(
batch=False,
certificate=self.args.config_cert,
priv_key=self.args.config_pkey,
lock=self.args.lock_device,
use_vendor_hid="vendor_hid" in self.args.features,
))
if not configure_response:
return None
return configure_response[0]
def run(self) -> int:
"""Reads args to decide and run all required tasks."""
self.check_prerequisites() self.check_prerequisites()
self.update_rustc_if_needed() 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):
info("Nothing to do.") info("Nothing to do.")
return 0 return 0
if self.args.check_patches:
subprocess.run(["./maintainers/patches", "check"], check=False)
# Compile what needs to be compiled # Compile what needs to be compiled
board_props = SUPPORTED_BOARDS[self.args.board]
if self.args.tockos: if self.args.tockos:
self.build_tockos() self.build_tockos()
if board_props.metadata_address is not None:
self.build_bootloader()
if self.args.application == "ctap2": if self.args.application == "ctap2":
self.generate_crypto_materials(self.args.regenerate_keys) self.generate_crypto_materials(self.args.regenerate_keys)
self.build_opensk() self.build_opensk()
@@ -795,6 +642,7 @@ class OpenSKInstaller:
self.clear_storage() self.clear_storage()
# Flashing # Flashing
board_props = SUPPORTED_BOARDS[self.args.board]
if self.args.programmer in ("jlink", "openocd"): if self.args.programmer in ("jlink", "openocd"):
# We rely on Tockloader to do the job # We rely on Tockloader to do the job
if self.args.clear_apps: if self.args.clear_apps:
@@ -802,21 +650,21 @@ class OpenSKInstaller:
if self.args.tockos: if self.args.tockos:
# Install Tock OS # Install Tock OS
self.install_tock_os() self.install_tock_os()
if board_props.metadata_address is not None:
# Install the bootloader
self.flash_bootloader()
# 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"target/tab/{self.args.application}.tab")
self.install_metadata() if self.verify_flashed_app(self.args.application):
if not self.verify_flashed_app(self.args.application): info("You're all set!")
error(("It seems that something went wrong. App/example not found " return 0
"on your board. Ensure the connections between the programmer " error(
"and the board are correct.")) ("It seems that something went wrong. App/example not found "
"on your board. Ensure the connections between the programmer and "
"the board are correct."))
return 1 return 1
return 0
elif self.args.programmer in ("pyocd", "nordicdfu", "none"): if self.args.programmer in ("pyocd", "nordicdfu", "none"):
dest_file = f"target/{self.args.board}_merged.hex" dest_file = f"target/{self.args.board}_merged.hex"
os.makedirs("target", exist_ok=True) os.makedirs("target", exist_ok=True)
self.create_hex_file(dest_file) self.create_hex_file(dest_file)
@@ -853,7 +701,7 @@ class OpenSKInstaller:
fatal("Multiple DFU devices are detected. Please only connect one.") fatal("Multiple DFU devices are detected. Please only connect one.")
# Run the command without capturing stdout so that we show progress # Run the command without capturing stdout so that we show progress
info("Flashing device using DFU...") info("Flashing device using DFU...")
dfu_return_code = subprocess.run( return subprocess.run(
[ [
"nrfutil", "dfu", "usb-serial", f"--package={dfu_pkg_file}", "nrfutil", "dfu", "usb-serial", f"--package={dfu_pkg_file}",
f"--serial-number={serial_number[0]}" f"--serial-number={serial_number[0]}"
@@ -861,57 +709,26 @@ class OpenSKInstaller:
check=False, check=False,
timeout=None, timeout=None,
).returncode ).returncode
if dfu_return_code != 0:
return dfu_return_code
# Configure OpenSK through vendor specific command if needed # Configure OpenSK through vendor specific command if needed
if self.args.programmer == "none":
if any([ if any([
self.args.lock_device, self.args.lock_device,
self.args.config_cert, self.args.config_cert,
self.args.config_pkey, self.args.config_pkey,
]): ]):
fatal("Unexpected arguments to configure your device. Since you " # pylint: disable=g-import-not-at-top,import-outside-toplevel
"selected the programmer \"none\", the device is not ready to be " import tools.configure
"configured yet.") tools.configure.main(
return 0 argparse.Namespace(
batch=False,
# Perform checks if OpenSK was flashed. certificate=self.args.config_cert,
if self.args.application == "ctap2" or self.args.configure: priv_key=self.args.config_pkey,
self.configure() lock=self.args.lock_device,
return 0 ))
def configure(self):
info("Configuring device.")
# Trying to check or configure the device. Booting might take some time.
for i in range(5):
# Increasing wait time, total of 10 seconds.
time.sleep(i)
devices = tools.configure.get_opensk_devices(False)
if devices:
break
if not devices:
fatal("No device to configure found.")
status = self.configure_device()
if not status:
fatal("Could not read device configuration.")
if status["cert"] and status["pkey"]:
info("You're all set!")
else:
info("Your device is not yet configured, and lacks some functionality. "
"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
def main(args): def main(args):
"""Verifies some args, then runs a new OpenSKInstaller."""
colorama.init() colorama.init()
# Make sure the current working directory is the right one before running # Make sure the current working directory is the right one before running
@@ -1004,14 +821,6 @@ if __name__ == "__main__":
help=("Sets the method to be used to flash Tock OS or the application " help=("Sets the method to be used to flash Tock OS or the application "
"on the target board."), "on the target board."),
) )
main_parser.add_argument(
"--openocd_cmd",
dest="openocd_cmd",
metavar="CMD",
default="openocd",
help=("Specifies a custom command to use when calling openocd. Can be "
"used to pass arguments i.e. 'openocd -s /tmp/openocd_scripts'."),
)
main_parser.add_argument( main_parser.add_argument(
"--no-tockos", "--no-tockos",
@@ -1071,6 +880,14 @@ 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(
"--ctap2.1",
action="append_const",
const="with_ctap2_1",
dest="features",
help=("Compiles the OpenSK application with backward compatible "
"support for CTAP2.1 protocol."),
)
main_parser.add_argument( main_parser.add_argument(
"--nfc", "--nfc",
action="append_const", action="append_const",
@@ -1078,20 +895,6 @@ if __name__ == "__main__":
dest="features", dest="features",
help=("Compiles the OpenSK application with support for nfc."), help=("Compiles the OpenSK application with support for nfc."),
) )
main_parser.add_argument(
"--configure",
action="store_true",
default=True,
dest="configure",
help="Configure.",
)
main_parser.add_argument(
"--vendor-hid",
action="append_const",
const="vendor_hid",
dest="features",
help=("Compiles the OpenSK application to support two HID usage pages."),
)
main_parser.add_argument( main_parser.add_argument(
"--regen-keys", "--regen-keys",
action="store_true", action="store_true",
@@ -1112,25 +915,6 @@ if __name__ == "__main__":
help=("When set, the output of elf2tab is appended to this file."), help=("When set, the output of elf2tab is appended to this file."),
) )
main_parser.add_argument(
"--ed25519",
action="append_const",
const="ed25519",
dest="features",
help=("Adds support for credentials that use EdDSA algorithm over "
"curve Ed25519. "
"Current implementation is not side-channel resilient due to use "
"of variable-time arithmetic for computations over secret key."),
)
main_parser.add_argument(
"--disable-check-patches",
action="store_false",
default=True,
dest="check_patches",
help=("Don't check that patches are in sync with their submodules."),
)
main_parser.set_defaults(features=["with_ctap1"]) main_parser.set_defaults(features=["with_ctap1"])
# 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.
@@ -1164,7 +948,7 @@ if __name__ == "__main__":
dest="application", dest="application",
action="store_const", action="store_const",
const="store_latency", const="store_latency",
help=("Compiles and installs the store_latency example which prints " help=("Compiles and installs the store_latency example which print "
"latency statistics of the persistent store library.")) "latency statistics of the persistent store library."))
apps_group.add_argument( apps_group.add_argument(
"--erase_storage", "--erase_storage",

View File

@@ -59,48 +59,14 @@ Follow these steps:
![Nordic dongle retainer clip](../img/dongle_clip.jpg) ![Nordic dongle retainer clip](../img/dongle_clip.jpg)
#### JLink 1. Depending on the programmer you're using, you may have to adapt the next
command line. Run our script for compiling/flashing Tock OS on your device:
Run our script for compiling/flashing Tock OS on your device:
```shell ```shell
$ ./deploy.py --board=nrf52840_dongle --programmer=jlink $ ./deploy.py --board=nrf52840_dongle --programmer=jlink
``` ```
#### OpenOCD 1. Remove the programming cable and the USB-A extension cable.
1. Create your openocd config, named `nordic_nrf52840_dongle.cfg` in the
appropriate location:
```shell
mkdir -p ${HOME}/.openocd/board
touch ${HOME}/.openocd/board/nordic_nrf52840_dongle.cfg
```
Paste the following st-link example and edit the specific setup to your needs:
```
# Specific setup
source [find interface/stlink-dap.cfg]
transport select dapdirect_swd
# The rest should be kept the same
set CHIPNAME nrf52840
source [find target/nrf52.cfg]
```
1. Test your config:
```shell
openocd -f board/nordic_nrf52840_dongle.cfg
```
1. Run the deploy script with the appropriate options, i.e.:
```shell
./deploy.py --board=nrf52840_dongle --opensk --programmer=openocd
```
Finally, remove the programming cable and the USB-A extension cable.
### Buttons and LEDs ### Buttons and LEDs

View File

@@ -14,7 +14,7 @@ is the easiest and most convenient. You can flash OpenSK with these steps:
1. Run our script for compiling/flashing Tock OS and OpenSK on your device: 1. Run our script for compiling/flashing Tock OS and OpenSK on your device:
```shell ```shell
./deploy.py --board=nrf52840dk_opensk --opensk ./deploy.py --board=nrf52840dk --opensk
``` ```
1. Connect a micro USB cable to the device USB port. 1. Connect a micro USB cable to the device USB port.
@@ -48,33 +48,3 @@ There are 3 switches that need to be in the correct position:
* Power (bottom left): On * Power (bottom left): On
* nRF power source (center left): VDD * nRF power source (center left): VDD
* SW6 (top right): DEFAULT * SW6 (top right): DEFAULT
### Upgradability
There are variants of the board that introduce A/B partitions for upgrading the
firmware. You can bootstrap an upgradable board using one of the two commands:
```shell
./deploy.py --board=nrf52840dk_opensk_a --opensk
./deploy.py --board=nrf52840dk_opensk_b --opensk
```
Afterwards, you can upgrade the other partition with
```shell
./tools/perform_upgrade.sh nrf52840dk_opensk_b
./tools/perform_upgrade.sh nrf52840dk_opensk_a
```
respectively. You can only upgrade the partition that is not currently running,
so always alternate your calls to `perform_upgrade.sh`. Otherwise, this script
works like `deploy.py`. You can call it even after you locked down your device,
to deploy changes to your development board.
If you deploy with `--vendor-hid`, also add this flag to `perform_upgrade.sh`,
for example:
```shell
./deploy.py --board=nrf52840dk_opensk_a --opensk --vendor-hid
./tools/perform_upgrade.sh nrf52840dk_opensk_b --vendor-hid
```

View File

@@ -17,8 +17,6 @@ File | Purpose
`opensk_cert.csr` | Certificate sign request for the attestation certificate `opensk_cert.csr` | Certificate sign request for the attestation certificate
`opensk_cert.pem` | PEM encoded certificate used for the authenticator `opensk_cert.pem` | PEM encoded certificate used for the authenticator
`opensk.key` | ECC secp256r1 private key used for the autenticator `opensk.key` | ECC secp256r1 private key used for the autenticator
`opensk_upgrade.key` | Private key for signing upgrades through CTAP
`opensk_upgrade_pub.pem` | Public key added to the firmware for verifying upgrades
If you want to use your own attestation certificate and private key, If you want to use your own attestation certificate and private key,
replace the `opensk_cert.pem` and `opensk.key` files. The script at replace the `opensk_cert.pem` and `opensk.key` files. The script at
@@ -51,45 +49,30 @@ If you build your own security key, depending on the hardware you use, there are
a few things you can personalize: a few things you can personalize:
1. If you have multiple buttons, choose the buttons responsible for user 1. If you have multiple buttons, choose the buttons responsible for user
presence in `src/main.rs`. presence in `main.rs`.
1. If you have colored LEDs, like different blinking patterns and want to play 2. Decide whether you want to use batch attestation. There is a boolean flag in
around with the code in `src/main.rs` more, take a look at e.g. `wink_leds`. `ctap/mod.rs`. It is mandatory for U2F, and you can create your own
1. You find more options and documentation in `src/ctap/customization.rs`, self-signed certificate. The flag is used for FIDO2 and has some privacy
including: implications. Please check
* The default level for the credProtect extension. [WebAuthn](https://www.w3.org/TR/webauthn/#attestation) for more
* The default minimum PIN length, and what relying parties can set it. information.
* Whether you want to enforce alwaysUv. 3. Decide whether you want to use signature counters. Currently, only global
* Settings for enterprise attestation. signature counters are implemented, as they are the default option for U2F.
* The maximum PIN retries. The flag in `ctap/mod.rs` only turns them off for FIDO2. The most privacy
* Whether you want to use batch attestation. preserving solution is individual or no signature counters. Again, please
* Whether you want to use signature counters. check [WebAuthn](https://www.w3.org/TR/webauthn/#signature-counter) for
* Various constants to adapt to different hardware. documentation.
4. Depending on your available flash storage, choose an appropriate maximum
### Testing and Fuzzing number of supported resident keys and number of pages in
`ctap/storage.rs`.
You might want to test your changes before deploying them. To run unit tests, 5. Change the default level for the credProtect extension in `ctap/mod.rs`.
make sure that at least the `std` feature is included, e.g.: When changing the default, resident credentials become undiscoverable without
user verification. This helps privacy, but can make usage less comfortable
```shell for credentials that need less protection.
cargo test --features=std,with_ctap1 6. Increase the default minimum length for PINs in `ctap/storage.rs`.
``` The current minimum is 4. Values from 4 to 63 are allowed. Requiring longer
PINs can help establish trust between users and relying parties. It makes
Alternatively, you can simply call our test script to also test all libraries, user verification harder to break, but less convenient.
run clippy, check formatting and more: NIST recommends at least 6-digit PINs in section 5.1.9.1 of their
[Digital Identity Guidelines](https://pages.nist.gov/800-63-3/sp800-63b.html).
```shell You can add relying parties to the list of readers of the minimum PIN length.
./run_desktop_tests.sh
```
OpenSK is fuzzed with the [OSS-Fuzz](https://github.com/google/oss-fuzz)
project. You can also run fuzzing locally. First install:
```shell
cargo +stable install cargo-fuzz --version 0.10.2
```
Then choose a fuzz target from `fuzz/fuzz_targets/`, e.g.:
```shell
cargo fuzz run fuzz_target_process_ctap1
```

View File

@@ -83,7 +83,7 @@ driver, before faulting the app, you can use the `--panic-console` flag of the
```shell ```shell
# Example on Nordic nRF52840-DK board # Example on Nordic nRF52840-DK board
./deploy.py --board=nrf52840dk_opensk --opensk --panic-console ./deploy.py --board=nrf52840dk --opensk --panic-console
``` ```
### Memory allocations ### Memory allocations

View File

@@ -28,7 +28,6 @@ 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.
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
@@ -39,48 +38,16 @@ haven't tested them on Windows and other platforms.
### Compiling the firmware ### Compiling the firmware
If this is your first time installing OpenSK, please skip directly to If you are switching branches or used an old version of OpenSK before, we have
[Initial setup](#Initial-setup). Else, see tools to help you migrate to our develop branch. You find more information on
[Updating your setup](#Updating-your-setup) below. how to update your setup or reset your storage in its
[install instructions](https://github.com/google/OpenSK/blob/develop/docs/install.md).
#### Updating your setup To clone and setup the repository for the stable branch, run the following
Depending on the difference to your last state, you may need some of the
following steps:
* If you are not just testing minor changes, reset and redo the setup. This
will delete all uncommited changes.
```shell
./reset.sh
./setup.sh
```
* Flash your board according to the
[flashing instructions below](#Flashing-a-firmware]. If you come from an
OpenSK version before the 2.0 certified one, your credential storage is not
backwards compatible and you have to reset it. :warning: You will lose
logins to all websites that you registered with OpenSK. To erase your
persistent storage, run the deploy script twice: Once with the application
parameter `--erase_storage`, and once with `--opensk` as usual.
This reset also clears the certificate. For a privacy discussion, see the
[certificate section in Customization](customization.md#Certificate-considerations).
If you want to reinstall it, you also need to rerun:
```shell
./tools/configure.py \
--certificate=crypto_data/opensk_cert.pem \
--private-key=crypto_data/opensk.key
```
#### Initial setup
To clone and setup the repository for the develop branch, run the following
commands: commands:
```shell ```shell
git clone -b develop https://github.com/google/OpenSK.git git clone https://github.com/google/OpenSK.git
cd OpenSK cd OpenSK
./setup.sh ./setup.sh
``` ```
@@ -137,36 +104,14 @@ We recommend that you flash your development board with JTAG and dongles with
DFU, as described in the [board documentation](#Flashing-a-firmware) linked DFU, as described in the [board documentation](#Flashing-a-firmware) linked
above. However, we support other programmers: above. However, we support other programmers:
* OpenOCD: `./deploy.py --board=nrf52840_dongle_opensk --opensk * OpenOCD: `./deploy.py --board=nrf52840_dongle --opensk --programmer=openocd`
--programmer=openocd` * pyOCD: `./deploy.py --board=nrf52840_dongle --opensk --programmer=pyocd`
* pyOCD: `./deploy.py --board=nrf52840_dongle_opensk --opensk * Custom: `./deploy.py --board=nrf52840_dongle --opensk --programmer=none`.
--programmer=pyocd` In this case, an IntelHex file will be created and how to program a board is
* Custom: `./deploy.py --board=nrf52840_dongle_opensk --opensk left to the user.
--programmer=none`. In this case, an IntelHex file will be created and how
to program a board is left to the user.
If your board is already flashed with Tock OS, you may skip installing it: If your board is already flashed with Tock OS, you may skip installing it:
`./deploy.py --board=nrf52840dk_opensk --opensk --no-tockos` `./deploy.py --board=nrf52840dk --opensk --no-tockos`
For more options, we invite you to read the help of our `deploy.py` script by For more options, we invite you to read the help of our `deploy.py` script by
running `./deploy.py --help`. running `./deploy.py --help`.
### Upgradability
We experiment with a new CTAP command to allow upgrading your device without
access to its debugging port. For that purpose, the flash storage is split into
4 parts:
* the bootloader to decide with partition to boot
* firmware partition A
* firmware partition B
* the persistent storage for credentials
The storage is backward compatible to non-upgradable boards. Deploying an
upgradable board automatically installs the bootloader. Please keep in mind that
you have to safely store your private signing key for upgrades if you want to
use this feature. For more information on the cryptographic material, see
[Customization](customization.md).
So far, upgradability is only supported for the development board. See the
instructions on the [board specific page](boards/nrf52840dk.md).

View File

@@ -18,8 +18,6 @@ extern crate lang_items;
use libtock_drivers::console::{Console, BUFFER_SIZE}; use libtock_drivers::console::{Console, BUFFER_SIZE};
libtock_core::stack_size! {0x800}
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; BUFFER_SIZE];

View File

@@ -20,14 +20,14 @@ extern crate lang_items;
use alloc::format; use alloc::format;
use alloc::vec::Vec; use alloc::vec::Vec;
use core::fmt::Write; use core::fmt::Write;
use crypto::{aes256, cbc, ecdsa, sha256, Hash256}; use crypto::{
aes256, cbc, ecdsa, rng256, sha256, Decrypt16BytesBlock, Encrypt16BytesBlock, Hash256,
};
use libtock_drivers::console::Console; use libtock_drivers::console::Console;
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;
use rng256::TockRng256; use libtock_drivers::timer::Timestamp;
libtock_core::stack_size! {0x800}
fn main() { fn main() {
let mut console = Console::new(); let mut console = Console::new();
@@ -36,7 +36,7 @@ fn main() {
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 = TockRng256 {}; let mut rng = rng256::TockRng256 {};
writeln!(console, "****************************************").unwrap(); writeln!(console, "****************************************").unwrap();
writeln!( writeln!(
@@ -76,11 +76,11 @@ fn main() {
// CBC // CBC
let mut blocks = Vec::new(); let mut blocks = Vec::new();
for i in 0..8 { for i in 0..8 {
blocks.resize(1 << (i + 4), 0); blocks.resize(1 << i, [0; 16]);
bench( bench(
&mut console, &mut console,
&timer, &timer,
&format!("cbc::cbc_encrypt({} bytes)", blocks.len()), &format!("cbc::cbc_encrypt({} bytes)", blocks.len() * 16),
|| { || {
cbc::cbc_encrypt(&ek, [0; 16], &mut blocks); cbc::cbc_encrypt(&ek, [0; 16], &mut blocks);
}, },
@@ -90,11 +90,11 @@ fn main() {
let mut blocks = Vec::new(); let mut blocks = Vec::new();
for i in 0..8 { for i in 0..8 {
blocks.resize(1 << (i + 4), 0); blocks.resize(1 << i, [0; 16]);
bench( bench(
&mut console, &mut console,
&timer, &timer,
&format!("cbc::cbc_decrypt({} bytes)", blocks.len()), &format!("cbc::cbc_decrypt({} bytes)", blocks.len() * 16),
|| { || {
cbc::cbc_decrypt(&dk, [0; 16], &mut blocks); cbc::cbc_decrypt(&dk, [0; 16], &mut blocks);
}, },

View File

@@ -17,14 +17,12 @@
extern crate lang_items; extern crate lang_items;
use core::fmt::Write; use core::fmt::Write;
use ctap2::env::tock::take_storage; use ctap2::embedded_flash::new_storage;
use libtock_drivers::console::Console; use libtock_drivers::console::Console;
use libtock_drivers::led; use libtock_drivers::led;
use libtock_drivers::result::FlexUnwrap; use libtock_drivers::result::FlexUnwrap;
use persistent_store::{Storage, StorageIndex}; use persistent_store::{Storage, StorageIndex};
libtock_core::stack_size! {0x800}
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 };
let length = storage.page_size(); let length = storage.page_size();
@@ -37,10 +35,10 @@ 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 led::get(1).flex_unwrap().on().flex_unwrap(); // red on dongle
let mut storage = take_storage().unwrap(); const NUM_PAGES: usize = 20; // should be at least ctap::storage::NUM_PAGES
let num_pages = storage.num_pages(); let mut storage = new_storage(NUM_PAGES);
writeln!(Console::new(), "Erase {} pages of storage:", num_pages).unwrap(); writeln!(Console::new(), "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::new(), "- 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::new(), "skipped (was already erased).").unwrap();

View File

@@ -7,11 +7,10 @@ extern crate libtock_drivers;
use core::fmt::Write; use core::fmt::Write;
use libtock_drivers::console::Console; use libtock_drivers::console::Console;
libtock_core::stack_size! {0x4000}
#[cfg(not(feature = "with_nfc"))] #[cfg(not(feature = "with_nfc"))]
mod example { mod example {
use super::{Console, Write}; use super::Console;
use super::Write;
pub fn nfc(console: &mut Console) { pub fn nfc(console: &mut Console) {
writeln!(console, "NFC feature flag is missing!").unwrap(); writeln!(console, "NFC feature flag is missing!").unwrap();
@@ -20,15 +19,20 @@ mod example {
#[cfg(feature = "with_nfc")] #[cfg(feature = "with_nfc")]
mod example { mod example {
use super::{Console, Write}; use super::Console;
use super::Write;
use libtock_core::result::CommandError; use libtock_core::result::CommandError;
use libtock_drivers::nfc::{NfcTag, RecvOp}; use libtock_drivers::nfc::NfcTag;
use libtock_drivers::result::{FlexUnwrap, TockError}; use libtock_drivers::nfc::RecvOp;
use libtock_drivers::result::FlexUnwrap;
use libtock_drivers::result::TockError;
use libtock_drivers::timer; use libtock_drivers::timer;
use libtock_drivers::timer::{Timer, Timestamp}; use libtock_drivers::timer::Timer;
use libtock_drivers::timer::Timestamp;
#[derive(Copy, Clone, Debug, PartialEq)] #[derive(Copy, Clone, Debug, PartialEq)]
#[allow(clippy::upper_case_acronyms)] // The actual lint upper_case_acronyms is not supported in all toolchains.
#[allow(clippy::all)]
enum ReturnCode { enum ReturnCode {
/// Operation completed successfully /// Operation completed successfully
SUCCESS, SUCCESS,

View File

@@ -17,8 +17,6 @@
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_drivers::console::Console;

View File

@@ -16,8 +16,6 @@
extern crate lang_items; extern crate lang_items;
libtock_core::stack_size! {0x800}
fn main() { fn main() {
panic!("Bye world!") panic!("Bye world!")
} }

View File

@@ -17,17 +17,13 @@
extern crate alloc; extern crate alloc;
extern crate lang_items; extern crate lang_items;
use alloc::string::{String, ToString}; use alloc::vec;
use alloc::vec::Vec;
use alloc::{format, vec};
use core::fmt::Write; use core::fmt::Write;
use ctap2::env::tock::{take_storage, TockStorage}; use ctap2::embedded_flash::{new_storage, Storage};
use libtock_drivers::console::Console; use libtock_drivers::console::Console;
use libtock_drivers::timer::{self, Duration, Timer, Timestamp}; use libtock_drivers::timer::{self, Duration, Timer, Timestamp};
use persistent_store::Store; use persistent_store::Store;
libtock_core::stack_size! {0x2000}
fn timestamp(timer: &Timer) -> Timestamp<f64> { fn timestamp(timer: &Timer) -> Timestamp<f64> {
Timestamp::<f64>::from_clock_value(timer.get_current_clock().ok().unwrap()) Timestamp::<f64>::from_clock_value(timer.get_current_clock().ok().unwrap())
} }
@@ -39,61 +35,28 @@ fn measure<T>(timer: &Timer, operation: impl FnOnce() -> T) -> (T, Duration<f64>
(result, after - before) (result, after - before)
} }
fn boot_store(mut storage: TockStorage, erase: bool) -> Store<TockStorage> { // Only use one store at a time.
use persistent_store::Storage; unsafe fn boot_store(num_pages: usize, erase: bool) -> Store<Storage> {
let num_pages = storage.num_pages(); let mut storage = new_storage(num_pages);
if erase { if erase {
for page in 0..num_pages { for page in 0..num_pages {
use persistent_store::Storage;
storage.erase_page(page).unwrap(); storage.erase_page(page).unwrap();
} }
} }
Store::new(storage).ok().unwrap() Store::new(storage).ok().unwrap()
} }
#[derive(Debug)] fn compute_latency(timer: &Timer, num_pages: usize, key_increment: usize, word_length: usize) {
struct StorageConfig {
num_pages: usize,
}
fn storage_config(storage: &TockStorage) -> StorageConfig {
use persistent_store::Storage;
StorageConfig {
num_pages: storage.num_pages(),
}
}
#[derive(Default)]
struct Stat {
key_increment: usize,
entry_length: usize, // words
boot_ms: f64,
compaction_ms: f64,
insert_ms: f64,
remove_ms: f64,
}
fn compute_latency(
storage: TockStorage,
timer: &Timer,
num_pages: usize,
key_increment: usize,
word_length: usize,
) -> (TockStorage, Stat) {
let mut stat = Stat {
key_increment,
entry_length: word_length,
..Default::default()
};
let mut console = Console::new(); let mut console = Console::new();
writeln!( writeln!(
console, console,
"\nLatency for key_increment={} word_length={}.", "\nLatency for num_pages={} key_increment={} word_length={}.",
key_increment, word_length num_pages, key_increment, word_length
) )
.unwrap(); .unwrap();
let mut store = boot_store(storage, true); let mut store = unsafe { boot_store(num_pages, true) };
let total_capacity = store.capacity().unwrap().total(); let total_capacity = store.capacity().unwrap().total();
assert_eq!(store.capacity().unwrap().used(), 0); assert_eq!(store.capacity().unwrap().used(), 0);
assert_eq!(store.lifetime().unwrap().used(), 0); assert_eq!(store.lifetime().unwrap().used(), 0);
@@ -109,33 +72,33 @@ fn compute_latency(
let ((), time) = measure(timer, || { let ((), time) = measure(timer, || {
for i in 0..count { for i in 0..count {
let key = 1 + key_increment * i; let key = 1 + key_increment * i;
store.insert(key, &vec![0; 4 * word_length]).unwrap(); // For some reason the kernel sometimes fails.
while store.insert(key, &vec![0; 4 * word_length]).is_err() {
// We never enter this loop in practice, but we still need it for the kernel.
writeln!(console, "Retry insert.").unwrap();
}
} }
}); });
writeln!(console, "Setup: {:.1}ms for {} entries.", time.ms(), count).unwrap(); writeln!(console, "Setup: {:.1}ms for {} entries.", time.ms(), count).unwrap();
// Measure latency of insert. // Measure latency of insert.
let key = 1 + key_increment * count; let key = 1 + key_increment * count;
let ((), time) = measure(timer, || { let ((), time) = measure(&timer, || {
store.insert(key, &vec![0; 4 * word_length]).unwrap() store.insert(key, &vec![0; 4 * word_length]).unwrap()
}); });
writeln!(console, "Insert: {:.1}ms.", time.ms()).unwrap(); writeln!(console, "Insert: {:.1}ms.", time.ms()).unwrap();
stat.insert_ms = time.ms();
assert_eq!( assert_eq!(
store.lifetime().unwrap().used(), store.lifetime().unwrap().used(),
num_pages + (1 + count) * (1 + word_length) num_pages + (1 + count) * (1 + word_length)
); );
// Measure latency of boot. // Measure latency of boot.
let storage = store.extract_storage(); let (mut store, time) = measure(&timer, || unsafe { boot_store(num_pages, false) });
let (mut store, time) = measure(timer, || boot_store(storage, false));
writeln!(console, "Boot: {:.1}ms.", time.ms()).unwrap(); writeln!(console, "Boot: {:.1}ms.", time.ms()).unwrap();
stat.boot_ms = time.ms();
// Measure latency of remove. // Measure latency of remove.
let ((), time) = measure(timer, || store.remove(key).unwrap()); let ((), time) = measure(&timer, || store.remove(key).unwrap());
writeln!(console, "Remove: {:.1}ms.", time.ms()).unwrap(); writeln!(console, "Remove: {:.1}ms.", time.ms()).unwrap();
stat.remove_ms = time.ms();
// Measure latency of compaction. // Measure latency of compaction.
let length = total_capacity + num_pages - store.lifetime().unwrap().used(); let length = total_capacity + num_pages - store.lifetime().unwrap().used();
@@ -148,81 +111,28 @@ fn compute_latency(
assert_eq!(store.lifetime().unwrap().used(), num_pages + total_capacity); assert_eq!(store.lifetime().unwrap().used(), num_pages + total_capacity);
let ((), time) = measure(timer, || store.prepare(1).unwrap()); let ((), time) = measure(timer, || store.prepare(1).unwrap());
writeln!(console, "Compaction: {:.1}ms.", time.ms()).unwrap(); writeln!(console, "Compaction: {:.1}ms.", time.ms()).unwrap();
stat.compaction_ms = time.ms();
assert!(store.lifetime().unwrap().used() > total_capacity + num_pages); assert!(store.lifetime().unwrap().used() > total_capacity + num_pages);
(store.extract_storage(), stat)
} }
fn main() { fn main() {
let mut with_callback = timer::with_callback(|_, _| {}); let mut with_callback = timer::with_callback(|_, _| {});
let timer = with_callback.init().ok().unwrap(); let timer = with_callback.init().ok().unwrap();
let storage = take_storage().unwrap();
let config = storage_config(&storage);
let mut stats = Vec::new();
writeln!(Console::new(), "\nRunning 2 tests...").unwrap(); writeln!(Console::new(), "\nRunning 4 tests...").unwrap();
// Simulate a store full of credentials (of 50 words). // Those non-overwritten 50 words entries simulate credentials.
let (storage, stat) = compute_latency(storage, &timer, config.num_pages, 1, 50); compute_latency(&timer, 3, 1, 50);
stats.push(stat); compute_latency(&timer, 20, 1, 50);
// Simulate a store full of increments of a single counter. // Those overwritten 1 word entries simulate counters.
let (_storage, stat) = compute_latency(storage, &timer, config.num_pages, 0, 1); compute_latency(&timer, 3, 0, 1);
stats.push(stat); compute_latency(&timer, 6, 0, 1);
writeln!(Console::new(), "\nDone.\n").unwrap(); writeln!(Console::new(), "\nDone.").unwrap();
const HEADERS: &[&str] = &[ // Results on nrf52840dk:
"Overwrite", //
"Length", // | Pages | Overwrite | Length | Boot | Compaction | Insert | Remove |
"Boot", // | ----- | --------- | --------- | ------- | ---------- | ------ | ------- |
"Compaction", // | 3 | no | 50 words | 2.0 ms | 132.5 ms | 4.8 ms | 1.2 ms |
"Insert", // | 20 | no | 50 words | 7.4 ms | 135.5 ms | 10.2 ms | 3.9 ms |
"Remove", // | 3 | yes | 1 word | 21.9 ms | 94.5 ms | 12.4 ms | 5.9 ms |
]; // | 6 | yes | 1 word | 55.2 ms | 100.8 ms | 24.8 ms | 12.1 ms |
let mut matrix = vec![HEADERS.iter().map(|x| x.to_string()).collect()];
for stat in stats {
matrix.push(vec![
if stat.key_increment == 0 { "yes" } else { "no" }.to_string(),
format!("{} words", stat.entry_length),
format!("{:.1} ms", stat.boot_ms),
format!("{:.1} ms", stat.compaction_ms),
format!("{:.1} ms", stat.insert_ms),
format!("{:.1} ms", stat.remove_ms),
]);
}
writeln!(Console::new(), "Copy to examples/store_latency.rs:\n").unwrap();
writeln!(Console::new(), "{:?}", config).unwrap();
write_matrix(matrix);
// Results for nrf52840dk_opensk:
// StorageConfig { num_pages: 20 }
// Overwrite Length Boot Compaction Insert Remove
// no 50 words 18.6 ms 145.8 ms 21.0 ms 9.8 ms
// yes 1 words 335.8 ms 100.6 ms 11.7 ms 5.7 ms
}
fn align(x: &str, n: usize) {
for _ in 0..n.saturating_sub(x.len()) {
write!(Console::new(), " ").unwrap();
}
write!(Console::new(), "{}", x).unwrap();
}
fn write_matrix(mut m: Vec<Vec<String>>) {
if m.is_empty() {
return;
}
let num_cols = m.iter().map(|r| r.len()).max().unwrap();
let mut col_len = vec![0; num_cols];
for row in &mut m {
row.resize(num_cols, String::new());
for col in 0..num_cols {
col_len[col] = core::cmp::max(col_len[col], row[col].len());
}
}
for row in m {
for col in 0..num_cols {
align(&row[col], col_len[col] + 2 * (col > 0) as usize);
}
writeln!(Console::new()).unwrap();
}
} }

253
fuzz/Cargo.lock generated
View File

@@ -1,7 +1,5 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3
[[package]] [[package]]
name = "aho-corasick" name = "aho-corasick"
version = "0.7.19" version = "0.7.19"
@@ -16,9 +14,6 @@ name = "arbitrary"
version = "0.4.7" version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db55d72333851e17d572bec876e390cd3b11eb1ef53ae821dd9f3b653d2b4569" checksum = "db55d72333851e17d572bec876e390cd3b11eb1ef53ae821dd9f3b653d2b4569"
dependencies = [
"derive_arbitrary",
]
[[package]] [[package]]
name = "arrayref" name = "arrayref"
@@ -59,6 +54,10 @@ version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cbor"
version = "0.1.0"
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.73" version = "1.0.73"
@@ -86,10 +85,12 @@ version = "0.1.0"
dependencies = [ dependencies = [
"arrayref", "arrayref",
"byteorder", "byteorder",
"cbor",
"hex", "hex",
"libtock_drivers",
"rand",
"regex", "regex",
"ring", "ring",
"rng256",
"serde", "serde",
"serde_json", "serde_json",
"subtle", "subtle",
@@ -100,19 +101,14 @@ dependencies = [
name = "ctap2" name = "ctap2"
version = "1.0.0" version = "1.0.0"
dependencies = [ dependencies = [
"arbitrary",
"arrayref", "arrayref",
"byteorder", "byteorder",
"cbor",
"crypto", "crypto",
"embedded-time",
"lang_items", "lang_items",
"libtock_core", "libtock_core",
"libtock_drivers", "libtock_drivers",
"openssl",
"persistent_store", "persistent_store",
"rand 0.8.5",
"rng256",
"sk-cbor",
"subtle", "subtle",
"uuid", "uuid",
] ]
@@ -125,41 +121,6 @@ dependencies = [
"libfuzzer-sys", "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]] [[package]]
name = "fuchsia-cprng" name = "fuchsia-cprng"
version = "0.1.1" version = "0.1.1"
@@ -170,15 +131,12 @@ checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
name = "fuzz_helper" name = "fuzz_helper"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"arbitrary",
"arrayref", "arrayref",
"cbor",
"crypto", "crypto",
"ctap2", "ctap2",
"embedded-time",
"lang_items", "lang_items",
"libtock_drivers", "libtock_drivers",
"rng256",
"sk-cbor",
] ]
[[package]] [[package]]
@@ -200,9 +158,9 @@ checksum = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77"
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "0.4.8" version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc"
[[package]] [[package]]
name = "js-sys" name = "js-sys"
@@ -224,9 +182,9 @@ dependencies = [
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.133" version = "0.2.135"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0f80d65747a3e43d1596c7c5492d95d5edddaabd45a7fcdb02b95f644164966" checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c"
[[package]] [[package]]
name = "libfuzzer-sys" name = "libfuzzer-sys"
@@ -282,130 +240,16 @@ version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" 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]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.14.0" version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0" 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]] [[package]]
name = "persistent_store" name = "persistent_store"
version = "0.1.0" 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]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.43" version = "1.0.43"
@@ -432,7 +276,7 @@ checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
dependencies = [ dependencies = [
"autocfg 0.1.8", "autocfg 0.1.8",
"libc", "libc",
"rand_chacha 0.1.1", "rand_chacha",
"rand_core 0.4.2", "rand_core 0.4.2",
"rand_hc", "rand_hc",
"rand_isaac", "rand_isaac",
@@ -443,17 +287,6 @@ dependencies = [
"winapi", "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]] [[package]]
name = "rand_chacha" name = "rand_chacha"
version = "0.1.1" version = "0.1.1"
@@ -464,16 +297,6 @@ dependencies = [
"rand_core 0.3.1", "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]] [[package]]
name = "rand_core" name = "rand_core"
version = "0.3.1" version = "0.3.1"
@@ -489,15 +312,6 @@ version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" 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]] [[package]]
name = "rand_hc" name = "rand_hc"
version = "0.1.0" version = "0.1.0"
@@ -601,15 +415,6 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "rng256"
version = "0.1.0"
dependencies = [
"arrayref",
"libtock_drivers",
"rand 0.6.5",
]
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.11" version = "1.0.11"
@@ -618,18 +423,18 @@ checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.144" version = "1.0.145"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f747710de3dcd43b88c9168773254e809d8ddbdf9653b84e2554ab219f17860" checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.144" version = "1.0.145"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94ed3a816fb1d101812f83e789f888322c34e291f894f19590dc310963e87a00" checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -638,19 +443,15 @@ dependencies = [
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.69" version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e466864e431129c7e0d3476b92f20458e5879919a0596c6472738d9fa2d342f8" checksum = "41feea4228a6f1cd09ec7a3593a682276702cd67b5273544757dae23c096f074"
dependencies = [ dependencies = [
"itoa", "itoa",
"ryu", "ryu",
"serde", "serde",
] ]
[[package]]
name = "sk-cbor"
version = "0.1.2"
[[package]] [[package]]
name = "spin" name = "spin"
version = "0.5.2" version = "0.5.2"
@@ -665,9 +466,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.100" version = "1.0.101"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52205623b1b0f064a4e71182c3b18ae902267282930c6d5462c91b859668426e" checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -676,9 +477,9 @@ dependencies = [
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.4" version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcc811dc4066ac62f84f11307873c4850cb653bfa9b1719cee2bd2204a4bc5dd" checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
[[package]] [[package]]
name = "untrusted" name = "untrusted"
@@ -695,12 +496,6 @@ dependencies = [
"getrandom", "getrandom",
] ]
[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]] [[package]]
name = "wasi" name = "wasi"
version = "0.11.0+wasi-snapshot-preview1" version = "0.11.0+wasi-snapshot-preview1"

View File

@@ -34,36 +34,18 @@ path = "fuzz_targets/fuzz_target_process_ctap2_client_pin.rs"
test = false test = false
doc = false doc = false
[[bin]]
name = "fuzz_target_process_ctap2_client_pin_structured"
path = "fuzz_targets/fuzz_target_process_ctap2_client_pin_structured.rs"
test = false
doc = false
[[bin]] [[bin]]
name = "fuzz_target_process_ctap2_get_assertion" name = "fuzz_target_process_ctap2_get_assertion"
path = "fuzz_targets/fuzz_target_process_ctap2_get_assertion.rs" path = "fuzz_targets/fuzz_target_process_ctap2_get_assertion.rs"
test = false test = false
doc = false doc = false
[[bin]]
name = "fuzz_target_process_ctap2_get_assertion_structured"
path = "fuzz_targets/fuzz_target_process_ctap2_get_assertion_structured.rs"
test = false
doc = false
[[bin]] [[bin]]
name = "fuzz_target_process_ctap2_make_credential" name = "fuzz_target_process_ctap2_make_credential"
path = "fuzz_targets/fuzz_target_process_ctap2_make_credential.rs" path = "fuzz_targets/fuzz_target_process_ctap2_make_credential.rs"
test = false test = false
doc = false doc = false
[[bin]]
name = "fuzz_target_process_ctap2_make_credential_structured"
path = "fuzz_targets/fuzz_target_process_ctap2_make_credential_structured.rs"
test = false
doc = false
[[bin]] [[bin]]
name = "fuzz_target_split_assemble" name = "fuzz_target_split_assemble"
path = "fuzz_targets/fuzz_target_split_assemble.rs" path = "fuzz_targets/fuzz_target_split_assemble.rs"

View File

@@ -7,11 +7,8 @@ edition = "2018"
[dependencies] [dependencies]
arrayref = "0.3.6" arrayref = "0.3.6"
embedded-time = "0.12.1"
libtock_drivers = { path = "../../third_party/libtock-drivers" } libtock_drivers = { path = "../../third_party/libtock-drivers" }
crypto = { path = "../../libraries/crypto", features = ['std'] } crypto = { path = "../../libraries/crypto", features = ['std'] }
rng256 = { path = "../../libraries/rng256", features = ['std'] } cbor = { path = "../../libraries/cbor", features = ['std'] }
sk-cbor = { path = "../../libraries/cbor" } ctap2 = { path = "../..", features = ['std'] }
ctap2 = { path = "../..", features = ["fuzz"] }
lang_items = { path = "../../third_party/lang-items", features = ['std'] } lang_items = { path = "../../third_party/lang-items", features = ['std'] }
arbitrary = { version = "0.4.7", features = ["derive"] }

View File

@@ -16,25 +16,27 @@
// `libtock_alloc_init` symbol. // `libtock_alloc_init` symbol.
extern crate lang_items; extern crate lang_items;
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 crypto::rng256::ThreadRng256;
use ctap2::clock::CtapInstant;
use ctap2::ctap::command::{ use ctap2::ctap::command::{
AuthenticatorClientPinParameters, AuthenticatorGetAssertionParameters, AuthenticatorClientPinParameters, AuthenticatorGetAssertionParameters,
AuthenticatorMakeCredentialParameters, Command, AuthenticatorMakeCredentialParameters,
}; };
use ctap2::ctap::data_formats::EnterpriseAttestationMode; use ctap2::ctap::hid::receive::MessageAssembler;
use ctap2::ctap::hid::{ use ctap2::ctap::hid::send::HidPacketIterator;
ChannelID, CtapHidCommand, HidPacket, HidPacketIterator, Message, MessageAssembler, use ctap2::ctap::hid::{ChannelID, CtapHid, HidPacket, Message};
}; use ctap2::ctap::status_code::Ctap2StatusCode;
use ctap2::ctap::{cbor_read, Channel, CtapState}; use ctap2::ctap::CtapState;
use ctap2::env::test::customization::TestCustomization; use libtock_drivers::timer::{ClockValue, Timestamp};
use ctap2::env::test::TestEnv;
use ctap2::{test_helpers, Ctap, Transport};
const COMMAND_INIT: u8 = 0x06;
const CHANNEL_BROADCAST: ChannelID = [0xFF, 0xFF, 0xFF, 0xFF]; const CHANNEL_BROADCAST: ChannelID = [0xFF, 0xFF, 0xFF, 0xFF];
const PACKET_TYPE_MASK: u8 = 0x80;
const CLOCK_FREQUENCY_HZ: usize = 32768;
const DUMMY_TIMESTAMP: Timestamp<isize> = Timestamp::from_ms(0);
const DUMMY_CLOCK_VALUE: ClockValue = ClockValue::new(0, CLOCK_FREQUENCY_HZ);
#[derive(Clone, Copy, PartialEq)] #[derive(Clone, Copy, PartialEq)]
pub enum InputType { pub enum InputType {
@@ -44,17 +46,8 @@ pub enum InputType {
Ctap1, Ctap1,
} }
pub enum FuzzError { fn user_immediately_present(_: ChannelID) -> Result<(), Ctap2StatusCode> {
ArbitraryError(arbitrary::Error), Ok(())
InvalidCustomization,
}
pub type FuzzResult<T> = Result<T, FuzzError>;
impl From<arbitrary::Error> for FuzzError {
fn from(err: arbitrary::Error) -> Self {
Self::ArbitraryError(err)
}
} }
// Converts a byte slice into Message // Converts a byte slice into Message
@@ -64,14 +57,13 @@ fn raw_to_message(data: &[u8]) -> Message {
cid[..data.len()].copy_from_slice(data); cid[..data.len()].copy_from_slice(data);
Message { Message {
cid, cid,
// Arbitrary command. cmd: 0,
cmd: CtapHidCommand::Cbor,
payload: vec![], payload: vec![],
} }
} else { } else {
Message { Message {
cid: array_ref!(data, 0, 4).clone(), cid: array_ref!(data, 0, 4).clone(),
cmd: CtapHidCommand::from(data[4]), cmd: data[4],
payload: data[5..].to_vec(), payload: data[5..].to_vec(),
} }
} }
@@ -79,22 +71,24 @@ fn raw_to_message(data: &[u8]) -> Message {
// Returns an initialized ctap state, hid and the allocated cid // Returns an initialized ctap state, hid and the allocated cid
// after processing the init command. // after processing the init command.
fn initialize(ctap: &mut Ctap<TestEnv>) -> ChannelID { fn initialize<CheckUserPresence>(
ctap_state: &mut CtapState<ThreadRng256, CheckUserPresence>,
ctap_hid: &mut CtapHid,
) -> ChannelID
where
CheckUserPresence: Fn(ChannelID) -> Result<(), Ctap2StatusCode>,
{
let nonce = vec![0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0]; let nonce = vec![0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0];
let message = Message { let message = Message {
cid: CHANNEL_BROADCAST, cid: CHANNEL_BROADCAST,
cmd: CtapHidCommand::Init, cmd: COMMAND_INIT,
payload: nonce, payload: nonce,
}; };
let mut assembler_reply = MessageAssembler::new(); let mut assembler_reply = MessageAssembler::new();
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_hid.process_hid_packet(&pkt_request, DUMMY_CLOCK_VALUE, ctap_state) {
ctap.process_hid_packet(&pkt_request, Transport::MainHid, CtapInstant::new(0)) if let Ok(Some(result)) = assembler_reply.parse_packet(&pkt_reply, DUMMY_TIMESTAMP) {
{
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]);
} }
} }
@@ -107,7 +101,7 @@ fn is_type(data: &[u8], input_type: InputType) -> bool {
if input_type == InputType::Ctap1 { if input_type == InputType::Ctap1 {
return true; return true;
} }
match cbor_read(data) { match cbor::read(data) {
Err(_) => false, Err(_) => false,
Ok(decoded_cbor) => match input_type { Ok(decoded_cbor) => match input_type {
InputType::CborMakeCredentialParameter => { InputType::CborMakeCredentialParameter => {
@@ -126,16 +120,22 @@ fn is_type(data: &[u8], input_type: InputType) -> bool {
// Interprets the raw data as a complete message (with channel id, command type and payload) and // Interprets the raw data as a complete message (with channel id, command type and payload) and
// invokes message splitting, packet processing at CTAP HID level and response assembling. // invokes message splitting, packet processing at CTAP HID level and response assembling.
fn process_message(data: &[u8], ctap: &mut Ctap<TestEnv>) { fn process_message<CheckUserPresence>(
data: &[u8],
ctap_state: &mut CtapState<ThreadRng256, CheckUserPresence>,
ctap_hid: &mut CtapHid,
) where
CheckUserPresence: Fn(ChannelID) -> Result<(), Ctap2StatusCode>,
{
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::new();
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, CtapInstant::new(0)) ctap_hid.process_hid_packet(&pkt_request, DUMMY_CLOCK_VALUE, ctap_state)
{ {
// 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(&pkt_reply, DUMMY_TIMESTAMP);
} }
} }
} }
@@ -144,66 +144,30 @@ fn process_message(data: &[u8], ctap: &mut Ctap<TestEnv>) {
// Interprets the raw data as any ctap command (including the command byte) and // Interprets the raw data as any ctap command (including the command byte) and
// invokes message splitting, packet processing at CTAP HID level and response assembling // invokes message splitting, packet processing at CTAP HID level and response assembling
// using an initialized and allocated channel. // using an initialized and allocated channel.
pub fn process_ctap_any_type(data: &[u8]) -> arbitrary::Result<()> { pub fn process_ctap_any_type(data: &[u8]) {
let mut unstructured = Unstructured::new(data);
let mut env = TestEnv::new();
env.rng().seed_from_u64(u64::arbitrary(&mut unstructured)?);
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 rng = ThreadRng256 {};
let cid = initialize(&mut ctap); let mut ctap_state = CtapState::new(&mut rng, user_immediately_present, DUMMY_CLOCK_VALUE);
let mut ctap_hid = CtapHid::new();
let cid = initialize(&mut ctap_state, &mut ctap_hid);
// 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();
command.extend(data); command.extend(data);
process_message(&command, &mut ctap); process_message(&command, &mut ctap_state, &mut ctap_hid);
Ok(())
}
fn setup_customization(
unstructured: &mut Unstructured,
customization: &mut TestCustomization,
) -> FuzzResult<()> {
customization.setup_enterprise_attestation(
Option::<EnterpriseAttestationMode>::arbitrary(unstructured)?,
// TODO: Generate arbitrary rp_id_list (but with some dummies because content doesn't
// matter), and use the rp ids in commands.
None,
);
if !is_valid(customization) {
return Err(FuzzError::InvalidCustomization);
}
Ok(())
}
fn setup_state(
unstructured: &mut Unstructured,
state: &mut CtapState,
env: &mut TestEnv,
) -> FuzzResult<()> {
if bool::arbitrary(unstructured)? {
test_helpers::enable_enterprise_attestation(state, env).ok();
}
Ok(())
} }
// Interprets the raw data as of the given input type and // Interprets the raw data as of the given input type and
// invokes message splitting, packet processing at CTAP HID level and response assembling // invokes message splitting, packet processing at CTAP HID level and response assembling
// using an initialized and allocated channel. // using an initialized and allocated channel.
pub fn process_ctap_specific_type(data: &[u8], input_type: InputType) -> arbitrary::Result<()> { pub fn process_ctap_specific_type(data: &[u8], input_type: InputType) {
let mut unstructured = Unstructured::new(data);
let mut env = TestEnv::new();
env.rng().seed_from_u64(u64::arbitrary(&mut unstructured)?);
let data = unstructured.take_rest();
if !is_type(data, input_type) { if !is_type(data, input_type) {
return Ok(()); return;
} }
// 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 rng = ThreadRng256 {};
let cid = initialize(&mut ctap); let mut ctap_state = CtapState::new(&mut rng, user_immediately_present, DUMMY_CLOCK_VALUE);
let mut ctap_hid = CtapHid::new();
let cid = initialize(&mut ctap_state, &mut ctap_hid);
// 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();
match input_type { match input_type {
@@ -221,71 +185,24 @@ pub fn process_ctap_specific_type(data: &[u8], input_type: InputType) -> arbitra
} }
} }
command.extend(data); command.extend(data);
process_message(&command, &mut ctap); process_message(&command, &mut ctap_state, &mut ctap_hid);
Ok(())
}
pub fn process_ctap_structured(data: &[u8], input_type: InputType) -> FuzzResult<()> {
let unstructured = &mut Unstructured::new(data);
let mut env = TestEnv::new();
env.rng().seed_from_u64(u64::arbitrary(unstructured)?);
setup_customization(unstructured, env.customization_mut())?;
let mut state = CtapState::new(&mut env, CtapInstant::new(0));
setup_state(unstructured, &mut state, &mut env)?;
let command = match input_type {
InputType::CborMakeCredentialParameter => Command::AuthenticatorMakeCredential(
AuthenticatorMakeCredentialParameters::arbitrary(unstructured)?,
),
InputType::CborGetAssertionParameter => Command::AuthenticatorGetAssertion(
AuthenticatorGetAssertionParameters::arbitrary(unstructured)?,
),
InputType::CborClientPinParameter => Command::AuthenticatorClientPin(
AuthenticatorClientPinParameters::arbitrary(unstructured)?,
),
InputType::Ctap1 => {
unimplemented!()
}
};
state
.process_parsed_command(
&mut env,
command,
Channel::MainHid(ChannelID::arbitrary(unstructured)?),
CtapInstant::new(0),
)
.ok();
Ok(())
} }
// Splits the given data as HID packets and reassembles it, verifying that the original input message is reconstructed. // Splits the given data as HID packets and reassembles it, verifying that the original input message is reconstructed.
pub fn split_assemble_hid_packets(data: &[u8]) -> arbitrary::Result<()> { pub fn split_assemble_hid_packets(data: &[u8]) {
let mut unstructured = Unstructured::new(data); let mut message = raw_to_message(data);
let mut env = TestEnv::new();
env.rng().seed_from_u64(u64::arbitrary(&mut unstructured)?);
let data = unstructured.take_rest();
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::new();
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(packet, DUMMY_TIMESTAMP), Ok(None));
assembler.parse_packet(&mut env, packet, CtapInstant::new(0)),
Ok(None)
);
} }
message.cmd &= !PACKET_TYPE_MASK;
assert_eq!( assert_eq!(
assembler.parse_packet(&mut env, last_packet, CtapInstant::new(0)), assembler.parse_packet(last_packet, DUMMY_TIMESTAMP),
Ok(Some(message)) Ok(Some(message))
); );
} }
} }
Ok(())
} }

View File

@@ -7,5 +7,5 @@ use libfuzzer_sys::fuzz_target;
// For a more generic fuzz target including all CTAP commands, you can use // For a more generic fuzz target including all CTAP commands, you can use
// fuzz_target_process_ctap_command. // fuzz_target_process_ctap_command.
fuzz_target!(|data: &[u8]| { fuzz_target!(|data: &[u8]| {
process_ctap_specific_type(data, InputType::Ctap1).ok(); process_ctap_specific_type(data, InputType::Ctap1);
}); });

View File

@@ -7,5 +7,5 @@ use libfuzzer_sys::fuzz_target;
// For a more generic fuzz target including all CTAP commands, you can use // For a more generic fuzz target including all CTAP commands, you can use
// fuzz_target_process_ctap_command. // fuzz_target_process_ctap_command.
fuzz_target!(|data: &[u8]| { fuzz_target!(|data: &[u8]| {
process_ctap_specific_type(data, InputType::CborClientPinParameter).ok(); process_ctap_specific_type(data, InputType::CborClientPinParameter);
}); });

View File

@@ -1,10 +0,0 @@
#![no_main]
use fuzz_helper::{process_ctap_structured, InputType};
use libfuzzer_sys::fuzz_target;
// Fuzz inputs as CTAP2 client pin command parameters.
// The inputs will used to construct arbitrary client pin parameters.
fuzz_target!(|data: &[u8]| {
process_ctap_structured(data, InputType::CborClientPinParameter).ok();
});

View File

@@ -7,5 +7,5 @@ use libfuzzer_sys::fuzz_target;
// For a more generic fuzz target including all CTAP commands, you can use // For a more generic fuzz target including all CTAP commands, you can use
// fuzz_target_process_ctap_command. // fuzz_target_process_ctap_command.
fuzz_target!(|data: &[u8]| { fuzz_target!(|data: &[u8]| {
process_ctap_specific_type(data, InputType::CborGetAssertionParameter).ok(); process_ctap_specific_type(data, InputType::CborGetAssertionParameter);
}); });

View File

@@ -1,10 +0,0 @@
#![no_main]
use fuzz_helper::{process_ctap_structured, InputType};
use libfuzzer_sys::fuzz_target;
// Fuzz inputs as CTAP2 get assertion command parameters.
// The inputs will used to construct arbitrary get assertion parameters.
fuzz_target!(|data: &[u8]| {
process_ctap_structured(data, InputType::CborGetAssertionParameter).ok();
});

View File

@@ -7,5 +7,5 @@ use libfuzzer_sys::fuzz_target;
// For a more generic fuzz target including all CTAP commands, you can use // For a more generic fuzz target including all CTAP commands, you can use
// fuzz_target_process_ctap_command. // fuzz_target_process_ctap_command.
fuzz_target!(|data: &[u8]| { fuzz_target!(|data: &[u8]| {
process_ctap_specific_type(data, InputType::CborMakeCredentialParameter).ok(); process_ctap_specific_type(data, InputType::CborMakeCredentialParameter);
}); });

View File

@@ -1,10 +0,0 @@
#![no_main]
use fuzz_helper::{process_ctap_structured, InputType};
use libfuzzer_sys::fuzz_target;
// Fuzz inputs as CTAP2 make credential command parameters.
// The inputs will used to construct arbitrary make credential parameters.
fuzz_target!(|data: &[u8]| {
process_ctap_structured(data, InputType::CborMakeCredentialParameter).ok();
});

View File

@@ -5,5 +5,5 @@ use libfuzzer_sys::fuzz_target;
// Generically fuzz inputs as CTAP commands. // Generically fuzz inputs as CTAP commands.
fuzz_target!(|data: &[u8]| { fuzz_target!(|data: &[u8]| {
process_ctap_any_type(data).ok(); process_ctap_any_type(data);
}); });

View File

@@ -5,5 +5,5 @@ use libfuzzer_sys::fuzz_target;
// Fuzzing HID packets splitting and assembling functions. // Fuzzing HID packets splitting and assembling functions.
fuzz_target!(|data: &[u8]| { fuzz_target!(|data: &[u8]| {
split_assemble_hid_packets(data).ok(); split_assemble_hid_packets(data);
}); });

View File

@@ -1,24 +1,24 @@
"""Creates a directory containing seed inputs from a json file having
the following structure:
[
{
"hex": "a901a1182a182a02a3626964781a6d616b655f6261645f7...",
"cbor": "{1: h'42', 2: {\"id\": \"make.example.com\", ...",
"description": "make credential parameters"
},
...
]
Usage:
- pass the resulting corpus directory path as the first argument
- pass the json file path to make the corpus from as the second argument
Example:
python make_corpus.py ./corpus ./corpus_file.json
"""
import argparse import argparse
import json import json
import os.path import os.path
# Creates a directory containing seed inputs from a json file having
# the following structure:
# [
# {
# "hex": "a901a1182a182a02a3626964781a6d616b655f6261645f7...",
# "cbor": "{1: h'42', 2: {\"id\": \"make.example.com\", ...",
# "description": "make credential parameters"
# },
# ...
# ]
#
# Usage:
# - pass the resulting corpus directory path as the first argument
# - pass the json file path to make the corpus from as the second argument
# Example:
# python make_corpus.py ./corpus ./corpus_file.json
# Creates a corpus directory to the given path from the given json file. # Creates a corpus directory to the given path from the given json file.
def make_corpus(corpus_dir, corpus_json): def make_corpus(corpus_dir, corpus_json):

View File

@@ -14,6 +14,7 @@
* FLASH (rx) : ORIGIN = 0x10030, LENGTH = 0x0FFD0 * FLASH (rx) : ORIGIN = 0x10030, LENGTH = 0x0FFD0
* SRAM (RWX) : ORIGIN = 0x20000, LENGTH = 0x10000 * SRAM (RWX) : ORIGIN = 0x20000, LENGTH = 0x10000
* } * }
* STACK_SIZE = 2048;
* MPU_MIN_ALIGN = 8K; * MPU_MIN_ALIGN = 8K;
* INCLUDE ../libtock-rs/layout.ld * INCLUDE ../libtock-rs/layout.ld
*/ */
@@ -24,15 +25,9 @@ SECTIONS {
/* Section for just the app crt0 header. /* Section for just the app crt0 header.
* This must be first so that the app can find it. * This must be first so that the app can find it.
*/ */
/* Runtime setup logic. The crt0_header symbol is used by the entry point .crt0_header :
* 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. */ _beginning = .; /* Start of the app in flash. */
crt0_header = .;
/** /**
* Populate the header expected by `crt0`: * Populate the header expected by `crt0`:
* *
@@ -69,41 +64,32 @@ SECTIONS {
* .rel.data section */ * .rel.data section */
LONG(LOADADDR(.endflash) - _beginning); LONG(LOADADDR(.endflash) - _beginning);
/* The size of the stack requested by this application */ /* The size of the stack requested by this application */
LONG(_stack_top_aligned - _sstack); LONG(STACK_SIZE);
/* Pad the header out to a multiple of 32 bytes so there is not a gap /* 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, * between the header and subsequent .data section. It's unclear why,
* but LLD is aligning sections to a multiple of 32 bytes. */ * but LLD is aligning sections to a multiple of 32 bytes. */
. = ALIGN(32); . = ALIGN(32);
} > FLASH =0xFF
*(.start)
} > FLASH =0xFFFFFFFF
/* Text section, Code! */ /* Text section, Code! */
.text : .text :
{ {
. = ALIGN(4); . = ALIGN(4);
_text = .; _text = .;
KEEP (*(.start))
*(.text*) *(.text*)
*(.rodata*) *(.rodata*)
KEEP (*(.syscalls)) KEEP (*(.syscalls))
*(.ARM.extab*) *(.ARM.extab*)
. = ALIGN(4); /* Make sure we're word-aligned here */ . = ALIGN(4); /* Make sure we're word-aligned here */
_etext = .; _etext = .;
} > FLASH =0xFFFFFFFF } > FLASH =0xFF
/* Application stack */ /* Application stack */
.stack (NOLOAD) : .stack :
{ {
/* elf2tab requires that the `_sram_origin` symbol be present to . = . + STACK_SIZE;
* 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 = .; _stack_top_unaligned = .;
. = ALIGN(8); . = ALIGN(8);
_stack_top_aligned = .; _stack_top_aligned = .;
@@ -118,7 +104,6 @@ SECTIONS {
. = ALIGN(4); /* Make sure we're word-aligned here */ . = ALIGN(4); /* Make sure we're word-aligned here */
_data = .; _data = .;
KEEP(*(.data*)) KEEP(*(.data*))
*(.sdata*) /* RISC-V small-pointer data section */
. = ALIGN(4); /* Make sure we're word-aligned at the end of flash */ . = ALIGN(4); /* Make sure we're word-aligned at the end of flash */
} > SRAM } > SRAM
@@ -137,7 +122,7 @@ SECTIONS {
{ {
. = ALIGN(4); /* Make sure we're word-aligned here */ . = ALIGN(4); /* Make sure we're word-aligned here */
_bss = .; _bss = .;
KEEP(*(.bss* .sbss*)) KEEP(*(.bss*))
*(COMMON) *(COMMON)
. = ALIGN(4); . = ALIGN(4);
} > SRAM } > SRAM
@@ -147,11 +132,26 @@ SECTIONS {
{ {
} > FLASH } > FLASH
/* Sections we do not need. */ /* ARM Exception support
/DISCARD/ : *
* This contains compiler-generated support for unwinding the stack,
* consisting of key-value pairs of function addresses and information on
* how to unwind stack frames.
* https://wiki.linaro.org/KenWerner/Sandbox/libunwind?action=AttachFile&do=get&target=libunwind-LDS.pdf
*
* .ARM.exidx is sorted, so has to go in its own output section.
*
* __NOTE__: It's at the end because we currently don't actually serialize
* it to the binary in elf2tbf. If it was before the RAM sections, it would
* through off our calculations of the header.
*/
PROVIDE_HIDDEN (__exidx_start = .);
.ARM.exidx :
{ {
*(.ARM.exidx .eh_frame) /* (C++) Index entries for section unwinding */
} *(.ARM.exidx* .gnu.linkonce.armexidx.*)
} > FLASH
PROVIDE_HIDDEN (__exidx_end = .);
} }
ASSERT((_stack_top_aligned - _stack_top_unaligned) == 0, " ASSERT((_stack_top_aligned - _stack_top_unaligned) == 0, "

View File

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

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