4 Commits
2.1 ... ctap2.0

Author SHA1 Message Date
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
279 changed files with 15425 additions and 36352 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

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

39
.github/workflows/boards_build.yml vendored Normal file
View File

@@ -0,0 +1,39 @@
---
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-18.04, macos-10.15]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
with:
submodules: "true"
- uses: actions-rs/toolchain@v1
with:
target: thumbv7em-none-eabi
- 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
run: ./deploy.py --board=nrf52840dk --no-app --programmer=none
- name: Building board nrf52840_dongle
run: ./deploy.py --board=nrf52840_dongle --no-app --programmer=none
- name: Building board nrf52840_dongle_dfu
run: ./deploy.py --board=nrf52840_dongle_dfu --no-app --programmer=none
- name: Building board nrf52840_mdk_dfu
run: ./deploy.py --board=nrf52840_mdk_dfu --no-app --programmer=none

View File

@@ -5,15 +5,20 @@ on:
jobs: jobs:
audit: audit:
runs-on: ubuntu-latest runs-on: ubuntu-18.04
if: github.repository == 'google/OpenSK' if: github.repository == 'google/OpenSK'
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with: with:
submodules: "true" submodules: "true"
- uses: actions-rs/toolchain@v1
with:
target: thumbv7em-none-eabi
- uses: actions/setup-python@v1 - uses: actions/setup-python@v1
with: with:
python-version: "3.10" python-version: 3.7
- name: Install Python dependencies
run: python -m pip install --upgrade pip setuptools wheel
- name: Set up OpenSK - name: Set up OpenSK
run: ./setup.sh run: ./setup.sh
- uses: actions-rs/audit-check@v1 - uses: actions-rs/audit-check@v1

View File

@@ -1,40 +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.10"
- uses: actions-rs/cargo@v1
with:
command: install
args: cargo-bloat
# First run: PR
- uses: actions/checkout@v2
with:
submodules: true
- 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 -C link-arg=-Tnrf52840_layout.ld" cargo bloat --release --target=thumbv7em-none-eabi --features=config_command,with_ctap1 --crates >> .github/workflows/bloat_output_new.txt
# Second run: PR
- uses: actions/checkout@v2
with:
submodules: true
ref: ${{ github.base_ref }}
path: OpenSK_base
- 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 -C link-arg=-Tnrf52840_layout.ld" cargo bloat --release --target=thumbv7em-none-eabi --features=config_command,with_ctap1 --crates >> "$GITHUB_WORKSPACE/.github/workflows/bloat_output_old.txt"
- name: Run output formatter to echo workflow command
run: ./.github/workflows/bloat_formatter.sh bloat_output_new.txt bloat_output_old.txt bloat_comment.md

97
.github/workflows/cargo_check.yml vendored Normal file
View File

@@ -0,0 +1,97 @@
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-18.04
steps:
- uses: actions/checkout@v2
with:
submodules: "true"
- uses: actions-rs/toolchain@v1
with:
target: thumbv7em-none-eabi
- 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 with_ctap2_1
uses: actions-rs/cargo@v1
with:
command: check
args: --target thumbv7em-none-eabi --release --features with_ctap2_1
- 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_ctap2_1
uses: actions-rs/cargo@v1
with:
command: check
args: --target thumbv7em-none-eabi --release --features debug_ctap,with_ctap2_1
- name: Check OpenSK debug_ctap,with_ctap1,with_ctap2_1,panic_console,debug_allocations,verbose
uses: actions-rs/cargo@v1
with:
command: check
args: --target thumbv7em-none-eabi --release --features debug_ctap,with_ctap1,with_ctap2_1,panic_console,debug_allocations,verbose
- name: Check examples
uses: actions-rs/cargo@v1
with:
command: check
args: --target thumbv7em-none-eabi --release --examples

32
.github/workflows/cargo_clippy.yml vendored Normal file
View File

@@ -0,0 +1,32 @@
---
name: Cargo Clippy
on:
push:
pull_request:
types: [opened, synchronize, reopened]
jobs:
cargo_clippy:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
with:
submodules: "true"
- uses: actions-rs/toolchain@v1
with:
target: thumbv7em-none-eabi
components: clippy
- 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
run: cargo clippy --all-targets --features std -- -A clippy::new_without_default -D warnings

75
.github/workflows/cargo_fmt.yml vendored Normal file
View File

@@ -0,0 +1,75 @@
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-18.04
steps:
- uses: actions/checkout@v2
with:
submodules: "true"
- uses: actions-rs/toolchain@v1
with:
target: thumbv7em-none-eabi
components: rustfmt
- 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

33
.github/workflows/cargo_fuzz.yml vendored Normal file
View File

@@ -0,0 +1,33 @@
---
name: Cargo fuzz build
on:
push:
pull_request:
types: [opened, synchronize, reopened]
jobs:
build_fuzzing:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
with:
submodules: "true"
- uses: actions-rs/toolchain@v1
with:
target: thumbv7em-none-eabi
- 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 ../..

38
.github/workflows/cbor_test.yml vendored Normal file
View File

@@ -0,0 +1,38 @@
---
name: CBOR tests
on:
push:
paths:
- 'libraries/cbor/**'
pull_request:
types: [opened, synchronize, reopened]
jobs:
cbor_test:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
with:
submodules: "true"
- uses: actions-rs/toolchain@v1
with:
target: thumbv7em-none-eabi
- 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 --features std
- name: Unit testing of CBOR library (debug mode)
uses: actions-rs/cargo@v1
with:
command: test
args: --manifest-path libraries/cbor/Cargo.toml --features std

View File

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

View File

@@ -1,28 +0,0 @@
name: CIFuzz
on:
push:
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,47 +0,0 @@
---
name: OpenSK code coverage report
on:
push:
paths:
- '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.10"
- name: Set up OpenSK
run: ./setup.sh
- name: Install llvm tools
run: rustup +nightly 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:
toolchain: nightly
command: test
args: --manifest-path libraries/opensk/Cargo.toml --features "std,with_ctap1,vendor_hid,ed25519" --no-fail-fast
env:
RUSTFLAGS: "-Cinstrument-coverage"
LLVM_PROFILE_FILE: "opensk-%p-%m.profraw"
- name: Run grcov
run: RUSTUP_TOOLCHAIN=nightly grcov . --binary-path ./libraries/opensk/target/debug/ --source-dir libraries/opensk/ --output-type lcov --ignore-not-existing --output-path ./lcov.info --ignore "/*" --ignore "examples/*" --ignore "third_party/*"
- uses: coverallsapp/github-action@1.1.3
name: upload report to coveralls
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
path-to-lcov: "./lcov.info"
base-path: "libraries/opensk"

42
.github/workflows/crypto_test.yml vendored Normal file
View File

@@ -0,0 +1,42 @@
---
name: Crypto library tests
on:
push:
paths:
- 'libraries/crypto/**'
pull_request:
types: [opened, synchronize, reopened]
paths:
- 'libraries/crypto/**'
jobs:
crypto_test:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
with:
submodules: "true"
- uses: actions-rs/toolchain@v1
with:
target: thumbv7em-none-eabi
- 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,derive_debug
- 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,derive_debug

34
.github/workflows/heapviz_test.yml vendored Normal file
View File

@@ -0,0 +1,34 @@
---
name: Heapviz tool tests
on:
push:
paths:
- 'tools/heapviz/**'
pull_request:
types: [opened, synchronize, reopened]
jobs:
heapviz_test:
runs-on: ubuntu-18.04
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

@@ -10,7 +10,7 @@ on:
jobs: jobs:
mdlint: mdlint:
runs-on: ubuntu-latest runs-on: ubuntu-18.04
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: markdownlint-cli - name: markdownlint-cli

41
.github/workflows/opensk_build.yml vendored Normal file
View File

@@ -0,0 +1,41 @@
---
name: OpenSK build
on:
push:
pull_request:
types: [opened, synchronize, reopened]
jobs:
build_ctap2:
strategy:
matrix:
os: [ubuntu-18.04, macos-10.15]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
with:
submodules: "true"
- uses: actions-rs/toolchain@v1
with:
target: thumbv7em-none-eabi
- 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
- name: Compute SHA-256 sum
run: ./third_party/tock/tools/sha256sum/target/debug/sha256sum target/thumbv7em-none-eabi/release/ctap2

77
.github/workflows/opensk_test.yml vendored Normal file
View File

@@ -0,0 +1,77 @@
---
name: OpenSK tests
on:
push:
paths:
- 'src/**/*.rs'
pull_request:
types: [opened, synchronize, reopened]
jobs:
ctap2_test:
name: CTAP2 unit tests
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
with:
submodules: "true"
- uses: actions-rs/toolchain@v1
with:
target: thumbv7em-none-eabi
- 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
- name: Unit testing of CTAP2 (release mode + CTAP2.1)
uses: actions-rs/cargo@v1
with:
command: test
args: --release --features std,with_ctap2_1
- name: Unit testing of CTAP2 (debug mode + CTAP2.1)
uses: actions-rs/cargo@v1
with:
command: test
args: --features std,with_ctap2_1
- name: Unit testing of CTAP2 (release mode + CTAP1 + CTAP2.1)
uses: actions-rs/cargo@v1
with:
command: test
args: --release --features std,with_ctap1,with_ctap2_1
- name: Unit testing of CTAP2 (debug mode + CTAP1 + CTAP2.1)
uses: actions-rs/cargo@v1
with:
command: test
args: --features std,with_ctap1,with_ctap2_1

View File

@@ -0,0 +1,26 @@
---
name: Persistent store tests
on:
push:
paths:
- 'libraries/peristent_store/**'
pull_request:
types: [opened, synchronize, reopened]
jobs:
persistent_store_test:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
- 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

46
.github/workflows/python.yml vendored Normal file
View File

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

View File

@@ -9,25 +9,28 @@ jobs:
check_hashes: check_hashes:
strategy: strategy:
matrix: matrix:
os: [ubuntu-latest, macos-latest] os: [ubuntu-18.04, macos-10.15]
fail-fast: false fail-fast: false
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with: with:
submodules: "true" submodules: "true"
- name: Install Rust toolchain - uses: actions-rs/toolchain@v1
run: rustup show with:
target: thumbv7em-none-eabi
- uses: actions/setup-python@v1 - uses: actions/setup-python@v1
with: with:
python-version: "3.10" python-version: 3.7
- name: Install Python dependencies
run: python -m pip install --upgrade pip setuptools wheel
- name: Set up OpenSK - name: Set up OpenSK
run: ./setup.sh run: ./setup.sh
- name: Use sample cryptographic material - name: Use sample cryptographic material
run: rm -R crypto_data/ && cp -r reproducible/sample_crypto_data crypto_data run: rm -R crypto_data/ && cp -r reproducible/sample_crypto_data crypto_data
- name: Computing cryptographic hashes - name: Computing cryptographic hashes
run: ./maintainers/reproduce_hashes.sh run: ./reproduce_hashes.sh
- name: Upload reproduced binaries - name: Upload reproduced binaries
uses: actions/upload-artifact@v1 uses: actions/upload-artifact@v1

4
.gitignore vendored
View File

@@ -1,7 +1,5 @@
libraries/**/Cargo.lock
target/ target/
/build/ Cargo.lock
/py_virtual_env/
# Local installation of elf2tab. # Local installation of elf2tab.
/elf2tab/ /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=builtins.StandardError,
builtins.Exception,
builtins.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

View File

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

978
Cargo.lock generated
View File

@@ -1,978 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "aes"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2"
dependencies = [
"cfg-if",
"cipher",
"cpufeatures",
]
[[package]]
name = "aho-corasick"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
dependencies = [
"memchr",
]
[[package]]
name = "arrayref"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545"
[[package]]
name = "base16ct"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf"
[[package]]
name = "base64ct"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
[[package]]
name = "bitflags"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
[[package]]
name = "block-buffer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [
"generic-array",
]
[[package]]
name = "bumpalo"
version = "3.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "cbc"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6"
dependencies = [
"cipher",
]
[[package]]
name = "cc"
version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
dependencies = [
"libc",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cipher"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
dependencies = [
"crypto-common",
"inout",
]
[[package]]
name = "const-oid"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f"
[[package]]
name = "cpufeatures"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0"
dependencies = [
"libc",
]
[[package]]
name = "crypto"
version = "0.1.0"
dependencies = [
"arrayref",
"byteorder",
"hex",
"rand_core",
"regex",
"ring",
"serde",
"serde_json",
"subtle",
"untrusted",
"zeroize",
]
[[package]]
name = "crypto-bigint"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "740fe28e594155f10cfc383984cbefd529d7396050557148f79cb0f621204124"
dependencies = [
"generic-array",
"rand_core",
"subtle",
"zeroize",
]
[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"typenum",
]
[[package]]
name = "ctap2"
version = "1.0.0"
dependencies = [
"arrayref",
"byteorder",
"crypto",
"ed25519-compact",
"enum-iterator",
"lang_items",
"libtock_alarm",
"libtock_buttons",
"libtock_console",
"libtock_drivers",
"libtock_leds",
"libtock_platform",
"libtock_runtime",
"libtock_unittest",
"opensk",
"openssl",
"persistent_store",
"rand_core",
"sk-cbor",
"uuid",
]
[[package]]
name = "der"
version = "0.7.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c"
dependencies = [
"const-oid",
"zeroize",
]
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"const-oid",
"crypto-common",
"subtle",
]
[[package]]
name = "ecdsa"
version = "0.16.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4b1e0c257a9e9f25f90ff76d7a68360ed497ee519c8e428d1825ef0000799d4"
dependencies = [
"der",
"digest",
"elliptic-curve",
"rfc6979",
"signature",
"spki",
]
[[package]]
name = "ed25519-compact"
version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e18997d4604542d0736fae2c5ad6de987f0a50530cbcc14a7ce5a685328a252d"
[[package]]
name = "elliptic-curve"
version = "0.13.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d97ca172ae9dc9f9b779a6e3a65d308f2af74e5b8c921299075bdb4a0370e914"
dependencies = [
"base16ct",
"crypto-bigint",
"digest",
"ff",
"generic-array",
"group",
"hkdf",
"pkcs8",
"rand_core",
"sec1",
"subtle",
"zeroize",
]
[[package]]
name = "enum-iterator"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c79a6321a1197d7730510c7e3f6cb80432dfefecb32426de8cea0aa19b4bb8d7"
dependencies = [
"enum-iterator-derive",
]
[[package]]
name = "enum-iterator-derive"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e94aa31f7c0dc764f57896dc615ddd76fc13b0d5dca7eb6cc5e018a5a09ec06"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "ff"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449"
dependencies = [
"rand_core",
"subtle",
]
[[package]]
name = "foreign-types"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
dependencies = [
"foreign-types-shared",
]
[[package]]
name = "foreign-types-shared"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
name = "generic-array"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
"zeroize",
]
[[package]]
name = "getrandom"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "group"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63"
dependencies = [
"ff",
"rand_core",
"subtle",
]
[[package]]
name = "hex"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77"
[[package]]
name = "hkdf"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437"
dependencies = [
"hmac",
]
[[package]]
name = "hmac"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
dependencies = [
"digest",
]
[[package]]
name = "inout"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
dependencies = [
"generic-array",
]
[[package]]
name = "itoa"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
[[package]]
name = "js-sys"
version = "0.3.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8"
dependencies = [
"wasm-bindgen",
]
[[package]]
name = "lang_items"
version = "0.1.0"
dependencies = [
"libtock_alarm",
"libtock_console",
"libtock_drivers",
"libtock_leds",
"libtock_low_level_debug",
"libtock_platform",
"libtock_runtime",
"linked_list_allocator",
]
[[package]]
name = "libc"
version = "0.2.150"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
[[package]]
name = "libtock_alarm"
version = "0.1.0"
dependencies = [
"libtock_platform",
]
[[package]]
name = "libtock_buttons"
version = "0.1.0"
dependencies = [
"libtock_platform",
]
[[package]]
name = "libtock_console"
version = "0.1.0"
dependencies = [
"libtock_platform",
]
[[package]]
name = "libtock_drivers"
version = "0.1.0"
dependencies = [
"libtock_alarm",
"libtock_console",
"libtock_platform",
]
[[package]]
name = "libtock_leds"
version = "0.1.0"
dependencies = [
"libtock_platform",
]
[[package]]
name = "libtock_low_level_debug"
version = "0.1.0"
dependencies = [
"libtock_platform",
]
[[package]]
name = "libtock_platform"
version = "0.1.0"
[[package]]
name = "libtock_runtime"
version = "0.1.0"
dependencies = [
"libtock_platform",
]
[[package]]
name = "libtock_unittest"
version = "0.1.0"
dependencies = [
"libtock_platform",
"thiserror",
]
[[package]]
name = "linked_list_allocator"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286"
[[package]]
name = "log"
version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]]
name = "memchr"
version = "2.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
[[package]]
name = "once_cell"
version = "1.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
[[package]]
name = "opensk"
version = "1.0.0"
dependencies = [
"aes",
"arrayref",
"byteorder",
"cbc",
"crypto",
"ed25519-compact",
"hkdf",
"hmac",
"openssl",
"p256",
"persistent_store",
"rand",
"rand_core",
"sha2",
"sk-cbor",
"subtle",
"uuid",
"zeroize",
]
[[package]]
name = "openssl"
version = "0.10.59"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a257ad03cd8fb16ad4172fedf8094451e1af1c4b70097636ef2eac9a5f0cc33"
dependencies = [
"bitflags",
"cfg-if",
"foreign-types",
"libc",
"once_cell",
"openssl-macros",
"openssl-sys",
]
[[package]]
name = "openssl-macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
]
[[package]]
name = "openssl-sys"
version = "0.9.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40a4130519a360279579c2053038317e40eff64d13fd3f004f9e1b72b8a6aaf9"
dependencies = [
"cc",
"libc",
"pkg-config",
"vcpkg",
]
[[package]]
name = "p256"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b"
dependencies = [
"ecdsa",
"elliptic-curve",
"primeorder",
"sha2",
]
[[package]]
name = "persistent_store"
version = "0.1.0"
[[package]]
name = "pkcs8"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7"
dependencies = [
"der",
"spki",
]
[[package]]
name = "pkg-config"
version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
[[package]]
name = "ppv-lite86"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "primeorder"
version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7dbe9ed3b56368bd99483eb32fe9c17fdd3730aebadc906918ce78d54c7eeb4"
dependencies = [
"elliptic-curve",
]
[[package]]
name = "proc-macro2"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"rand_chacha",
"rand_core",
]
[[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",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "regex"
version = "1.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
[[package]]
name = "rfc6979"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2"
dependencies = [
"hmac",
"subtle",
]
[[package]]
name = "ring"
version = "0.16.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc"
dependencies = [
"cc",
"libc",
"once_cell",
"spin",
"untrusted",
"web-sys",
"winapi",
]
[[package]]
name = "ryu"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
[[package]]
name = "sec1"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc"
dependencies = [
"base16ct",
"der",
"generic-array",
"pkcs8",
"subtle",
"zeroize",
]
[[package]]
name = "serde"
version = "1.0.192"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.192"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
]
[[package]]
name = "serde_json"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e466864e431129c7e0d3476b92f20458e5879919a0596c6472738d9fa2d342f8"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "sha2"
version = "0.10.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "signature"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500"
dependencies = [
"digest",
"rand_core",
]
[[package]]
name = "sk-cbor"
version = "0.1.2"
[[package]]
name = "spin"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]]
name = "spki"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a"
dependencies = [
"base64ct",
"der",
]
[[package]]
name = "subtle"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.39"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "thiserror"
version = "1.0.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
]
[[package]]
name = "typenum"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "untrusted"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]]
name = "uuid"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
dependencies = [
"getrandom",
]
[[package]]
name = "vcpkg"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
version = "0.2.88"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.88"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217"
dependencies = [
"bumpalo",
"log",
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.39",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.88"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.88"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.88"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b"
[[package]]
name = "web-sys"
version = "0.3.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "zeroize"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9"
dependencies = [
"zeroize_derive",
]
[[package]]
name = "zeroize_derive"
version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.39",
]

View File

@@ -5,54 +5,37 @@ authors = [
"Fabian Kaczmarczyck <kaczmarczyck@google.com>", "Fabian Kaczmarczyck <kaczmarczyck@google.com>",
"Guillaume Endignoux <guillaumee@google.com>", "Guillaume Endignoux <guillaumee@google.com>",
"Jean-Michel Picod <jmichel@google.com>", "Jean-Michel Picod <jmichel@google.com>",
"Julien Cretin <cretin@google.com>",
] ]
license = "Apache-2.0" license = "Apache-2.0"
edition = "2018" edition = "2018"
[target.'cfg(any(target_arch = "arm", target_arch = "riscv32"))'.dependencies.libtock_runtime]
path = "third_party/libtock-rs/runtime"
default-features = false
features = ["no_auto_layout", "no_debug_memop"]
[dependencies] [dependencies]
libtock_buttons = { path = "third_party/libtock-rs/apis/buttons" } libtock_core = { path = "third_party/libtock-rs/core" }
libtock_platform = { path = "third_party/libtock-rs/platform" }
libtock_drivers = { path = "third_party/libtock-drivers" } libtock_drivers = { path = "third_party/libtock-drivers" }
libtock_alarm = { path = "third_party/libtock-rs/apis/alarm" }
libtock_console = { path = "third_party/libtock-rs/apis/console" }
libtock_leds = { path = "third_party/libtock-rs/apis/leds" }
lang_items = { path = "third_party/lang-items" } lang_items = { path = "third_party/lang-items" }
opensk = { path = "libraries/opensk", default-features = false } cbor = { path = "libraries/cbor" }
sk-cbor = { path = "libraries/cbor" }
crypto = { path = "libraries/crypto" } crypto = { path = "libraries/crypto" }
persistent_store = { path = "libraries/persistent_store" } persistent_store = { path = "libraries/persistent_store" }
libtock_unittest = { path = "third_party/libtock-rs/unittest", optional = true }
byteorder = { version = "1", default-features = false } byteorder = { version = "1", default-features = false }
arrayref = "0.3.6" arrayref = "0.3.6"
rand_core = "0.6.4" subtle = { version = "2.2", default-features = false, features = ["nightly"] }
ed25519-compact = { version = "1", default-features = false, optional = true }
[features] [features]
config_command = ["opensk/config_command"]
debug_allocations = ["lang_items/debug_allocations"] debug_allocations = ["lang_items/debug_allocations"]
debug_ctap = ["libtock_drivers/debug_ctap", "opensk/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", "opensk/std", "libtock_unittest"] 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 = ["opensk/with_ctap1"] with_ctap1 = ["crypto/with_ctap1"]
with_ctap2_1 = []
with_nfc = ["libtock_drivers/with_nfc"] with_nfc = ["libtock_drivers/with_nfc"]
vendor_hid = ["opensk/vendor_hid"]
ed25519 = ["ed25519-compact", "opensk/ed25519"]
rust_crypto = ["opensk/rust_crypto"]
[dev-dependencies] [dev-dependencies]
elf2tab = "0.6.0"
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.55"
[profile.dev] [profile.dev]
panic = "abort" panic = "abort"
@@ -61,10 +44,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
[profile.release.package]
aes = { opt-level = 3 }
sha2 = { opt-level = 3 }
p256 = { opt-level = 3 }

251
README.md
View File

@@ -1,116 +1,203 @@
# <img alt="OpenSK logo" src="docs/img/OpenSK.svg" width="200px"> # <img alt="OpenSK logo" src="docs/img/OpenSK.svg" width="200px">
![markdownlint](https://github.com/google/OpenSK/workflows/markdownlint/badge.svg?branch=2.1) ![markdownlint](https://github.com/google/OpenSK/workflows/markdownlint/badge.svg?branch=master)
[![Coverage Status](https://coveralls.io/repos/github/google/OpenSK/badge.svg?branch=2.1)](https://coveralls.io/github/google/OpenSK?branch=2.1) ![pylint](https://github.com/google/OpenSK/workflows/pylint/badge.svg?branch=master)
![Cargo check](https://github.com/google/OpenSK/workflows/Cargo%20check/badge.svg?branch=master)
*News:* ![Cargo format](https://github.com/google/OpenSK/workflows/Cargo%20format/badge.svg?branch=master)
- 2023-08-24: [PQC paper reference](#Research)
## OpenSK ## OpenSK
This repository contains a Rust implementation of a This repository contains a Rust implementation of a
[FIDO2](https://fidoalliance.org/fido2/) security key. [FIDO2](https://fidoalliance.org/fido2/) authenticator.
Security keys are external devices that can be used for signing in on websites.
You can see OpenSK in action in this
[video on YouTube](https://www.youtube.com/watch?v=klEozvpw0xg)!
We intend to bring a full open source experience to security keys, from We developed this as a [Tock OS](https://tockos.org) application and it has been
application to operating system. You can even 3D print your own open source successfully tested on the following boards:
enclosure!
<img src="docs/img/enclosure.jpg" alt="OpenSK Enclosure" width="200"/> * [Nordic nRF52840-DK](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52840-DK)
* [Nordic nRF52840-dongle](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52840-Dongle)
You can run OpenSK as a [Tock OS](https://tockos.org) application, or use the ## Disclaimer
library to bring OpenSK to your own hardware.
You are viewing the CTAP 2.1 version. This branch fixes bugs, but doesn't This project is **proof-of-concept and a research platform**. It is **NOT**
implement new features. If you want to contribute, go to the meant for a daily usage. It's still under development and as such comes with a
[develop branch](https://github.com/google/OpenSK/tree/develop). few limitations:
### FIDO2 ### FIDO2
OpenSK's version that implemented CTAP 2.0 was certified by the FIDO Alliance. The stable branch implements the published
[CTAP2.0 specifications](https://fidoalliance.org/specs/fido-v2.0-ps-20190130/fido-client-to-authenticator-protocol-v2.0-ps-20190130.html)
and is FIDO certified.
This branch implements version 2.1 of the <img alt="FIDO2 certified L1" src="docs/img/FIDO2_Certified_L1.png" width="200px">
[CTAP specification](https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-errata-20220621.html).
This branch is not FIDO certified.
OpenSK supports U2F, and non-discoverable credentials created with either
protocol are compatible with the other.
### :warning: Disclaimer It already contains some preview features of 2.1, that you can try by adding the
flag `--ctap2.1` to the deploy command. The full
[CTAP2.1 specification](https://fidoalliance.org/specs/fido-v2.1-rd-20201208/fido-client-to-authenticator-protocol-v2.1-rd-20201208.html)
is work in progress in the develop branch and is tested less thoroughly.
This project is **proof-of-concept and a research platform**. It is **NOT** ### Cryptography
meant for a daily usage. This branch is under development, and therefore less
rigorously tested than the numbered branches.
We're still in the process of integrating the We're currently still in the process on making 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)
embedded in the embedded in the
[Nordic nRF52840 chip](https://infocenter.nordicsemi.com/index.jsp?topic=%2Fps_nrf52840%2Fcryptocell.html) [Nordic nRF52840 chip](https://infocenter.nordicsemi.com/index.jsp?topic=%2Fps_nrf52840%2Fcryptocell.html)
to enable hardware-accelerated cryptography. work to get hardware-accelerated cryptography. In the meantime we implemented
In the meantime, there are 2 options for cryptography implementations: the required cryptography algorithms (ECDSA, ECC secp256r1, HMAC-SHA256 and
AES256) in Rust as a placeholder. Those implementations are research-quality
* Our own placeholder implementation. The code is research quality and doesn't code and haven't been reviewed. They don't provide constant-time guarantees and
provide constant-time guarantees. are not designed to be resistant against side-channel attacks.
* The [RustCrypto](https://github.com/RustCrypto) interface. Deploy with
`--rust-crypto`. Note that our own ECC implementation is faster and has
smaller binary size, so not all boards support RustCrypto yet.
## Hardware
You will need one the following supported boards:
* [Nordic nRF52840-DK](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52840-DK)
development kit. This board is more convenient for development and debug
scenarios as the JTAG probe is already on the board.
* [Nordic nRF52840 Dongle](https://www.nordicsemi.com/Software-and-tools/Development-Kits/nRF52840-Dongle)
to have a more practical form factor.
* [Makerdiary nRF52840-MDK USB dongle](https://wiki.makerdiary.com/nrf52840-mdk/).
* [Feitian OpenSK dongle](https://feitiantech.github.io/OpenSK_USB/).
## Installation ## Installation
To install OpenSK, For a more detailed guide, please refer to our
1. follow the [general setup steps](docs/install.md), [installation guide](docs/install.md).
1. then continue with the instructions for your specific hardware:
* [Nordic nRF52840-DK](docs/boards/nrf52840dk.md)
* [Nordic nRF52840 Dongle](docs/boards/nrf52840_dongle.md)
* [Makerdiary nRF52840-MDK USB dongle](docs/boards/nrf52840_mdk.md)
* [Feitian OpenSK dongle](docs/boards/nrf52840_feitian.md)
To test whether the installation was successful, visit a 1. If you just cloned this repository, run the following script (**Note**: you
[demo website](https://webauthn.io/) and try to register and login. only need to do this once):
Please check our [Troubleshooting and Debugging](docs/debugging.md) section if you
have problems with the installation process or during development. To find out what
else you can do with your OpenSK, see [Customization](docs/customization.md).
## Research ```shell
./setup.sh
```
We implemented post-quantum cryptography on OpenSK. The code is released under 1. Next step is to install Tock OS as well as the OpenSK application on your
the [hybrid-pqc tag](https://github.com/google/OpenSK/releases/tag/hybrid-pqc). board. Run:
Our [paper](https://eprint.iacr.org/2022/1225) was published in the ACNS
Secure Cryptographic Implementation workshop 2023 and won the best paper award.
<details> ```shell
<summary>Bibtex reference</summary> # Nordic nRF52840-DK board
./deploy.py --board=nrf52840dk --opensk
# Nordic nRF52840-Dongle
./deploy.py --board=nrf52840_dongle --opensk
```
``` 1. Finally you need to inject the cryptographic material if you enabled
@InProceedings{Ghinea2023hybrid, batch attestation or CTAP1/U2F compatibility (which is the case by
author= {Diana Ghinea and Fabian Kaczmarczyck and Jennifer Pullman and Julien Cretin and Rafael Misoczki and Stefan Kölbl and Luca Invernizzi and Elie Bursztein and Jean-Michel Picod}, default):
title= {{Hybrid Post-Quantum Signatures in Hardware Security Keys}},
booktitle= {{4th ACNS Workshop on Secure Cryptographic Implementation, Kyoto, Japan}}, ```shell
month= {June}, ./tools/configure.py \
year= {2023}, --certificate=crypto_data/opensk_cert.pem \
} --private-key=crypto_data/opensk.key
```
1. On Linux, you may want to avoid the need for `root` privileges to interact
with the key. For that purpose we provide a udev rule file that can be
installed with the following command:
```shell
sudo cp rules.d/55-opensk.rules /etc/udev/rules.d/ &&
sudo udevadm control --reload
```
### Customization
If you build your own security key, depending on the hardware you use, there are
a few things you can personalize:
1. If you have multiple buttons, choose the buttons responsible for user
presence in `main.rs`.
2. Decide whether you want to use batch attestation. There is a boolean flag in
`ctap/mod.rs`. It is mandatory for U2F, and you can create your own
self-signed certificate. The flag is used for FIDO2 and has some privacy
implications. Please check
[WebAuthn](https://www.w3.org/TR/webauthn/#attestation) for more
information.
3. Decide whether you want to use signature counters. Currently, only global
signature counters are implemented, as they are the default option for U2F.
The flag in `ctap/mod.rs` only turns them off for FIDO2. The most privacy
preserving solution is individual or no signature counters. Again, please
check [WebAuthn](https://www.w3.org/TR/webauthn/#signature-counter) for
documentation.
4. Depending on your available flash storage, choose an appropriate maximum
number of supported residential keys and number of pages in
`ctap/storage.rs`.
5. Change the default level for the credProtect extension in `ctap/mod.rs`.
When changing the default, resident credentials become undiscoverable without
user verification. This helps privacy, but can make usage less comfortable
for credentials that need less protection.
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
user verification harder to break, but less convenient.
NIST recommends at least 6-digit PINs in section 5.1.9.1:
https://pages.nist.gov/800-63-3/sp800-63b.html
You can add relying parties to the list of readers of the minimum PIN length.
### 3D printed enclosure
To protect and carry your key, we partnered with a professional designer and we
are providing a custom enclosure that can be printed on both professional 3D
printers and hobbyist models.
All the required files can be downloaded from
[Thingiverse](https://www.thingiverse.com/thing:4132768) including the STEP
file, allowing you to easily make the modifications you need to further
customize it.
## Development and testing
### Printing panic messages to the console
By default, libtock-rs blinks some LEDs when the userspace application panicks.
This is not always convenient as the panic message is lost. In order to enable
a custom panic handler that first writes the panic message via Tock's console
driver, before faulting the app, you can use the `--panic-console` flag of the
`deploy.py` script.
```shell
# Example on Nordic nRF52840-DK board
./deploy.py --board=nrf52840dk --opensk --panic-console
``` ```
</details> ### Debugging memory allocations
You may want to track memory allocations to understand the heap usage of
OpenSK. This can be useful if you plan to port it to a board with fewer
available RAM for example. To do so, you can enable the `--debug-allocations`
flag of the `deploy.py` script. This enables a custom (userspace) allocator
that prints a message to the console for each allocation and deallocation
operation.
The additional output looks like the following.
```text
# Allocation of 256 byte(s), aligned on 1 byte(s). The allocated address is
# 0x2002401c. After this operation, 2 pointers have been allocated, totalling
# 384 bytes (the total heap usage may be larger, due to alignment and
# fragmentation of allocations within the heap).
alloc[256, 1] = 0x2002401c (2 ptrs, 384 bytes)
# Deallocation of 64 byte(s), aligned on 1 byte(s), from address 0x2002410c.
# After this operation, 1 pointers are allocated, totalling 512 bytes.
dealloc[64, 1] = 0x2002410c (1 ptrs, 512 bytes)
```
A tool is provided to analyze such reports, in `tools/heapviz`. This tool
parses the console output, identifies the lines corresponding to (de)allocation
operations, and first computes some statistics:
* Address range used by the heap over this run of the program,
* Peak heap usage (how many useful bytes are allocated),
* Peak heap consumption (how many bytes are used by the heap, including
unavailable bytes between allocated blocks, due to alignment constraints and
memory fragmentation),
* Fragmentation overhead (difference between heap consumption and usage).
Then, the `heapviz` tool displays an animated "movie" of the allocated bytes in
heap memory. Each frame in this "movie" shows bytes that are currently
allocated, that were allocated but are now freed, and that have never been
allocated. A new frame is generated for each (de)allocation operation. This tool
uses the `ncurses` library, that you may have to install beforehand.
You can control the tool with the following parameters:
* `--logfile` (required) to provide the file which contains the console output
to parse,
* `--fps` (optional) to customize the number of frames per second in the movie
animation.
```shell
cargo run --manifest-path tools/heapviz/Cargo.toml -- --logfile console.log --fps 50
```
## Contributing ## Contributing
See [Contributing.md](docs/contributing.md). See [Contributing.md](docs/contributing.md).
## Reporting a Vulnerability
See [SECURITY.md](SECURITY.md).

View File

@@ -1,4 +0,0 @@
To report a security issue, please use http://g.co/vulnz. We use
http://g.co/vulnz for our intake, and do coordination and disclosure here on
GitHub (including using GitHub Security Advisory). The Google Security Team will
respond within 5 working days of your report on g.co/vulnz.

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, PROCESSES, PROCESS_PRINTER};
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;
let _ = 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,
&PROCESS_PRINTER,
)
}

View File

@@ -1,497 +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)]
#![deny(missing_docs)]
use capsules::virtual_alarm::VirtualMuxAlarm;
use kernel::component::Component;
use kernel::dynamic_deferred_call::{DynamicDeferredCall, DynamicDeferredCallClientState};
use kernel::hil::led::LedLow;
use kernel::hil::time::Counter;
use kernel::platform::{KernelResources, SyscallDriverLookup, SyscallFilter};
use kernel::scheduler::round_robin::RoundRobinSched;
#[allow(unused_imports)]
use kernel::{capabilities, create_capability, debug, debug_gpio, debug_verbose, static_init};
use kernel::{StorageLocation, StorageType};
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",
// Interface description + main HID string
"FIDO2",
// vendor HID string
"Vendor HID",
];
// State for loading and holding applications.
// How should the kernel respond when a process faults.
const FAULT_RESPONSE: kernel::process::PanicFaultPolicy = kernel::process::PanicFaultPolicy {};
// Number of concurrent processes this platform supports.
const NUM_PROCS: usize = 8;
static mut PROCESSES: [Option<&'static dyn kernel::process::Process>; NUM_PROCS] =
[None; NUM_PROCS];
static mut STORAGE_LOCATIONS: [StorageLocation; 2] = [
// We implement NUM_PAGES = 20 as 16 + 4 to satisfy the MPU.
StorageLocation {
address: 0xC0000,
size: 0x10000, // 16 pages
storage_type: StorageType::Store,
},
StorageLocation {
address: 0xD0000,
size: 0x4000, // 4 pages
storage_type: StorageType::Store,
},
];
// Static reference to chip for panic dumps
static mut CHIP: Option<&'static nrf52840::chip::NRF52<Nrf52840DefaultPeripherals>> = None;
// Static reference to process printer for panic dumps
static mut PROCESS_PRINTER: Option<&'static kernel::process::ProcessPrinterText> = None;
/// Flash buffer for the custom nvmc driver
static mut APP_FLASH_BUFFER: [u8; 0x1000] = [0; 0x1000];
/// Dummy buffer that causes the linker to reserve enough space for the stack.
#[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,
VirtualMuxAlarm<'static, nrf52840::rtc::Rtc<'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>>,
4,
>,
rng: &'static capsules::rng::RngDriver<'static>,
ipc: kernel::ipc::IPC<{ NUM_PROCS as u8 }>,
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>>,
>,
scheduler: &'static RoundRobinSched<'static>,
systick: cortexm4::systick::SysTick,
nvmc: &'static nrf52840::nvmc::SyscallDriver,
usb: &'static capsules::usb::usb_ctap::CtapUsbSyscallDriver<
'static,
'static,
nrf52840::usbd::Usbd<'static>,
>,
}
impl SyscallDriverLookup for Platform {
fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
where
F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> 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)),
kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)),
_ => f(None),
}
}
}
impl SyscallFilter for Platform {
fn filter_syscall(
&self,
process: &dyn kernel::process::Process,
syscall: &kernel::syscall::Syscall,
) -> Result<(), kernel::errorcode::ErrorCode> {
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::ErrorCode::INVAL)
}
_ => Ok(()),
}
}
}
impl KernelResources<nrf52840::chip::NRF52<'static, Nrf52840DefaultPeripherals<'static>>>
for Platform
{
type SyscallDriverLookup = Self;
type SyscallFilter = Self;
type ProcessFault = ();
type Scheduler = RoundRobinSched<'static>;
type SchedulerTimer = cortexm4::systick::SysTick;
type WatchDog = ();
type ContextSwitchCallback = ();
fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
&self
}
fn syscall_filter(&self) -> &Self::SyscallFilter {
&self
}
fn process_fault(&self) -> &Self::ProcessFault {
&()
}
fn scheduler(&self) -> &Self::Scheduler {
self.scheduler
}
fn scheduler_timer(&self) -> &Self::SchedulerTimer {
&self.systick
}
fn watchdog(&self) -> &Self::WatchDog {
&()
}
fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
&()
}
}
/// This is in a separate, inline(never) function so that its stack frame is
/// removed when this function returns. Otherwise, the stack space used for
/// these static_inits is wasted.
#[inline(never)]
unsafe fn get_peripherals() -> &'static mut Nrf52840DefaultPeripherals<'static> {
// Initialize chip peripheral drivers
let nrf52840_peripherals = static_init!(
Nrf52840DefaultPeripherals,
Nrf52840DefaultPeripherals::new()
);
nrf52840_peripherals
}
/// Main function called after RAM initialized.
#[no_mangle]
pub unsafe fn main() {
nrf52840::init();
let nrf52840_peripherals = get_peripherals();
// set up circular peripheral dependencies
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,
capsules::gpio::DRIVER_NUM,
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,
capsules::button::DRIVER_NUM,
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().finalize(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]),
));
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;
let _ = 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,
capsules::alarm::DRIVER_NUM,
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);
let process_printer =
components::process_printer::ProcessPrinterTextComponent::new().finalize(());
PROCESS_PRINTER = Some(process_printer);
// Create a shared UART channel for the console and for kernel debug.
let uart_mux =
components::console::UartMuxComponent::new(channel, 115200, dynamic_deferred_caller)
.finalize(());
let pconsole = components::process_console::ProcessConsoleComponent::new(
board_kernel,
uart_mux,
mux_alarm,
process_printer,
)
.finalize(components::process_console_component_helper!(
nrf52840::rtc::Rtc<'static>
));
// Setup the console.
let console = components::console::ConsoleComponent::new(
board_kernel,
capsules::console::DRIVER_NUM,
uart_mux,
)
.finalize(components::console_component_helper!());
// Create the debugger object that handles calls to `debug!()`.
components::debug_writer::DebugWriterComponent::new(uart_mux).finalize(());
let rng = components::rng::RngComponent::new(
board_kernel,
capsules::rng::DRIVER_NUM,
&base_peripherals.trng,
)
.finalize(());
// Initialize AC using AIN5 (P0.29) as VIN+ and VIN- as AIN0 (P0.02)
// 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
),
board_kernel,
capsules::analog_comparator::DRIVER_NUM,
)
.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(nrf52840::nvmc::DRIVER_NUM, &memory_allocation_capability),
dynamic_deferred_caller,
&mut APP_FLASH_BUFFER,
)
);
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,
capsules::usb::usb_ctap::DRIVER_NUM,
&nrf52840_peripherals.usbd,
capsules::usb::usbc_client::MAX_CTRL_PACKET_SIZE_NRF52840,
VENDOR_ID,
PRODUCT_ID,
STRINGS,
)
.finalize(components::usb_ctap_component_helper!(nrf52840::usbd::Usbd));
nrf52_components::NrfClockComponent::new(&base_peripherals.clock).finalize(());
let scheduler = components::sched::round_robin::RoundRobinComponent::new(&PROCESSES)
.finalize(components::rr_component_helper!(NUM_PROCS));
let platform = Platform {
button,
pconsole,
console,
led,
gpio,
rng,
alarm,
analog_comparator,
nvmc,
usb,
ipc: kernel::ipc::IPC::new(
board_kernel,
kernel::ipc::DRIVER_NUM,
&memory_allocation_capability,
),
scheduler,
systick: cortexm4::systick::SysTick::new_with_calibration(6400_0000),
};
let _ = 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::process::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);
});
board_kernel.kernel_loop(&platform, chip, Some(&platform.ipc), &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

@@ -7,7 +7,8 @@ use kernel::hil::led;
use kernel::hil::uart::{self, Configure}; use kernel::hil::uart::{self, Configure};
use nrf52840::gpio::Pin; use nrf52840::gpio::Pin;
use crate::{CHIP, PROCESSES, PROCESS_PRINTER}; use crate::CHIP;
use crate::PROCESSES;
struct Writer { struct Writer {
initialized: bool, initialized: bool,
@@ -24,13 +25,10 @@ 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;
let _ = uart.configure(uart::Parameters { uart.configure(uart::Parameters {
baud_rate: 115200, baud_rate: 115200,
stop_bits: uart::StopBits::One, stop_bits: uart::StopBits::One,
parity: uart::Parity::None, parity: uart::Parity::None,
@@ -53,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],
@@ -63,6 +61,5 @@ pub unsafe extern "C" fn panic_fmt(pi: &PanicInfo) -> ! {
&cortexm4::support::nop, &cortexm4::support::nop,
&PROCESSES, &PROCESSES,
&CHIP, &CHIP,
&PROCESS_PRINTER,
) )
} }

View File

@@ -7,19 +7,16 @@
// Disable this attribute when documenting, as a workaround for // Disable this attribute when documenting, as a workaround for
// https://github.com/rust-lang/rust/issues/62184. // https://github.com/rust-lang/rust/issues/62184.
#![cfg_attr(not(doc), no_main)] #![cfg_attr(not(doc), no_main)]
#![feature(const_in_array_repeat_expressions)]
#![deny(missing_docs)] #![deny(missing_docs)]
use capsules::virtual_alarm::VirtualMuxAlarm; use capsules::virtual_alarm::VirtualMuxAlarm;
use kernel::common::dynamic_deferred_call::{DynamicDeferredCall, DynamicDeferredCallClientState};
use kernel::component::Component; use kernel::component::Component;
use kernel::dynamic_deferred_call::{DynamicDeferredCall, DynamicDeferredCallClientState};
use kernel::hil::led::LedLow;
use kernel::hil::time::Counter;
use kernel::platform::{KernelResources, SyscallDriverLookup, SyscallFilter};
use kernel::scheduler::round_robin::RoundRobinSched;
#[allow(unused_imports)] #[allow(unused_imports)]
use kernel::{capabilities, create_capability, debug, debug_gpio, debug_verbose, static_init}; use kernel::{capabilities, create_capability, debug, debug_gpio, debug_verbose, static_init};
use kernel::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
@@ -29,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;
@@ -48,41 +49,25 @@ static STRINGS: &'static [&'static str] = &[
"OpenSK", "OpenSK",
// Serial number // Serial number
"v1.0", "v1.0",
// Interface description + main HID string
"FIDO2",
// vendor HID string
"Vendor HID",
]; ];
// State for loading and holding applications. // State for loading and holding applications.
// How should the kernel respond when a process faults. // How should the kernel respond when a process faults.
const FAULT_RESPONSE: kernel::process::PanicFaultPolicy = kernel::process::PanicFaultPolicy {}; const FAULT_RESPONSE: kernel::procs::FaultResponse = kernel::procs::FaultResponse::Panic;
// Number of concurrent processes this platform supports. // Number of concurrent processes this platform supports.
const NUM_PROCS: usize = 8; const NUM_PROCS: usize = 8;
static mut PROCESSES: [Option<&'static dyn kernel::process::Process>; 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;
static mut PROCESS_PRINTER: Option<&'static kernel::process::ProcessPrinterText> = None;
/// Flash buffer for the custom nvmc driver
static mut APP_FLASH_BUFFER: [u8; 0x1000] = [0; 0x1000];
/// Dummy buffer that causes the linker to reserve enough space for the stack. /// Dummy buffer that causes the linker to reserve enough space for the stack.
#[no_mangle] #[no_mangle]
@@ -91,21 +76,23 @@ 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,
VirtualMuxAlarm<'static, nrf52840::rtc::Rtc<'static>>,
components::process_console::Capability, components::process_console::Capability,
>, >,
console: &'static capsules::console::Console<'static>, console: &'static capsules::console::Console<'static>,
gpio: &'static capsules::gpio::GPIO<'static, nrf52840::gpio::GPIOPin<'static>>, gpio: &'static capsules::gpio::GPIO<'static, nrf52840::gpio::GPIOPin<'static>>,
led: &'static capsules::led::LedDriver< led: &'static capsules::led::LED<'static, nrf52840::gpio::GPIOPin<'static>>,
'static,
kernel::hil::led::LedLow<'static, nrf52840::gpio::GPIOPin<'static>>,
3,
>,
rng: &'static capsules::rng::RngDriver<'static>, rng: &'static capsules::rng::RngDriver<'static>,
ipc: kernel::ipc::IPC<{ NUM_PROCS as u8 }>, 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>,
@@ -114,8 +101,6 @@ pub struct Platform {
'static, 'static,
capsules::virtual_alarm::VirtualMuxAlarm<'static, nrf52840::rtc::Rtc<'static>>, capsules::virtual_alarm::VirtualMuxAlarm<'static, nrf52840::rtc::Rtc<'static>>,
>, >,
scheduler: &'static RoundRobinSched<'static>,
systick: cortexm4::systick::SysTick,
nvmc: &'static nrf52840::nvmc::SyscallDriver, nvmc: &'static nrf52840::nvmc::SyscallDriver,
usb: &'static capsules::usb::usb_ctap::CtapUsbSyscallDriver< usb: &'static capsules::usb::usb_ctap::CtapUsbSyscallDriver<
'static, 'static,
@@ -124,10 +109,10 @@ pub struct Platform {
>, >,
} }
impl SyscallDriverLookup for Platform { impl kernel::Platform for Platform {
fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
where where
F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R, F: FnOnce(Option<&dyn kernel::Driver>) -> R,
{ {
match driver_num { match driver_num {
capsules::console::DRIVER_NUM => f(Some(self.console)), capsules::console::DRIVER_NUM => f(Some(self.console)),
@@ -136,6 +121,9 @@ impl SyscallDriverLookup 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)),
@@ -143,87 +131,33 @@ impl SyscallDriverLookup for Platform {
_ => f(None), _ => f(None),
} }
} }
}
impl SyscallFilter for Platform {
fn filter_syscall( fn filter_syscall(
&self, &self,
process: &dyn kernel::process::Process, process: &dyn kernel::procs::ProcessType,
syscall: &kernel::syscall::Syscall, syscall: &kernel::syscall::Syscall,
) -> Result<(), kernel::errorcode::ErrorCode> { ) -> Result<(), kernel::ReturnCode> {
use kernel::syscall::Syscall; use kernel::syscall::Syscall;
match *syscall { match *syscall {
Syscall::Command { Syscall::COMMAND {
driver_number: nrf52840::nvmc::DRIVER_NUM, driver_number: nrf52840::nvmc::DRIVER_NUM,
subdriver_number: cmd, subdriver_number: cmd,
arg0: ptr, arg0: ptr,
arg1: len, arg1: len,
} if (cmd == 2 || cmd == 3) && !process.fits_in_storage_location(ptr, len) => { } if (cmd == 2 || cmd == 3) && !process.fits_in_storage_location(ptr, len) => {
Err(kernel::ErrorCode::INVAL) Err(kernel::ReturnCode::EINVAL)
} }
_ => Ok(()), _ => Ok(()),
} }
} }
} }
/// This is in a separate, inline(never) function so that its stack frame is /// Entry point in the vector table called on hard reset.
/// removed when this function returns. Otherwise, the stack space used for
/// these static_inits is wasted.
#[inline(never)]
unsafe fn get_peripherals() -> &'static mut Nrf52840DefaultPeripherals<'static> {
// Initialize chip peripheral drivers
let nrf52840_peripherals = static_init!(
Nrf52840DefaultPeripherals,
Nrf52840DefaultPeripherals::new()
);
nrf52840_peripherals
}
impl KernelResources<nrf52840::chip::NRF52<'static, Nrf52840DefaultPeripherals<'static>>>
for Platform
{
type SyscallDriverLookup = Self;
type SyscallFilter = Self;
type ProcessFault = ();
type Scheduler = RoundRobinSched<'static>;
type SchedulerTimer = cortexm4::systick::SysTick;
type WatchDog = ();
type ContextSwitchCallback = ();
fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
&self
}
fn syscall_filter(&self) -> &Self::SyscallFilter {
&self
}
fn process_fault(&self) -> &Self::ProcessFault {
&()
}
fn scheduler(&self) -> &Self::Scheduler {
self.scheduler
}
fn scheduler_timer(&self) -> &Self::SchedulerTimer {
&self.systick
}
fn watchdog(&self) -> &Self::WatchDog {
&()
}
fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
&()
}
}
/// Main function called after RAM initialized.
#[no_mangle] #[no_mangle]
pub unsafe fn main() { pub unsafe fn reset_handler() {
// Loads relocations and clears BSS // Loads relocations and clears BSS
nrf52840::init(); nrf52840::init();
// Initialize chip peripheral drivers
let nrf52840_peripherals = get_peripherals();
// 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)
@@ -231,26 +165,23 @@ pub unsafe fn main() {
// GPIOs // GPIOs
let gpio = components::gpio::GpioComponent::new( let gpio = components::gpio::GpioComponent::new(
board_kernel, board_kernel,
capsules::gpio::DRIVER_NUM,
components::gpio_component_helper!( components::gpio_component_helper!(
nrf52840::gpio::GPIOPin, nrf52840::gpio::GPIOPin,
// left side of the USB plug. Right side is used for UART // left side of the USB plug. Right side is used for UART
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,
capsules::button::DRIVER_NUM,
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
) )
@@ -258,19 +189,33 @@ pub unsafe fn main() {
) )
.finalize(components::button_component_buf!(nrf52840::gpio::GPIOPin)); .finalize(components::button_component_buf!(nrf52840::gpio::GPIOPin));
let led = components::led::LedsComponent::new().finalize(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!(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 =
@@ -278,7 +223,7 @@ pub unsafe fn main() {
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(
@@ -287,23 +232,14 @@ pub unsafe fn main() {
Some(&gpio_port[LED1_B_PIN]), Some(&gpio_port[LED1_B_PIN]),
); );
let rtc = &base_peripherals.rtc; let rtc = &nrf52840::rtc::RTC;
let _ = 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( let alarm = components::alarm::AlarmDriverComponent::new(board_kernel, mux_alarm)
board_kernel,
capsules::alarm::DRIVER_NUM,
mux_alarm,
)
.finalize(components::alarm_component_helper!(nrf52840::rtc::Rtc)); .finalize(components::alarm_component_helper!(nrf52840::rtc::Rtc));
let uart_channel = UartChannel::Pins(UartPins::new(UART_RTS, UART_TXD, UART_CTS, UART_RXD)); let uart_channel = UartChannel::Pins(UartPins::new(UART_RTS, UART_TXD, UART_CTS, UART_RXD));
let channel = nrf52_components::UartChannelComponent::new( let channel = nrf52_components::UartChannelComponent::new(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());
@@ -312,51 +248,53 @@ pub unsafe fn main() {
DynamicDeferredCall::new(dynamic_deferred_call_clients) DynamicDeferredCall::new(dynamic_deferred_call_clients)
); );
DynamicDeferredCall::set_global_instance(dynamic_deferred_caller); DynamicDeferredCall::set_global_instance(dynamic_deferred_caller);
let process_printer =
components::process_printer::ProcessPrinterTextComponent::new().finalize(());
PROCESS_PRINTER = Some(process_printer);
// Create a shared UART channel for the console and for kernel debug. // Create a shared UART channel for the console and for kernel debug.
let uart_mux = let uart_mux =
components::console::UartMuxComponent::new(channel, 115200, dynamic_deferred_caller) components::console::UartMuxComponent::new(channel, 115200, dynamic_deferred_caller)
.finalize(()); .finalize(());
let pconsole = components::process_console::ProcessConsoleComponent::new( let pconsole =
board_kernel, components::process_console::ProcessConsoleComponent::new(board_kernel, uart_mux)
uart_mux, .finalize(());
mux_alarm,
process_printer,
)
.finalize(components::process_console_component_helper!(
nrf52840::rtc::Rtc<'static>
));
// Setup the console. // Setup the console.
let console = components::console::ConsoleComponent::new( let console = components::console::ConsoleComponent::new(board_kernel, uart_mux).finalize(());
board_kernel,
capsules::console::DRIVER_NUM,
uart_mux,
)
.finalize(components::console_component_helper!());
// Create the debugger object that handles calls to `debug!()`. // Create the debugger object that handles calls to `debug!()`.
components::debug_writer::DebugWriterComponent::new(uart_mux).finalize(()); components::debug_writer::DebugWriterComponent::new(uart_mux).finalize(());
let rng = components::rng::RngComponent::new(
let 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, board_kernel,
capsules::rng::DRIVER_NUM, &nrf52840::ieee802154_radio::RADIO,
&base_peripherals.trng, &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(()); .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
), ),
board_kernel,
capsules::analog_comparator::DRIVER_NUM,
) )
.finalize(components::acomp_component_buf!( .finalize(components::acomp_component_buf!(
nrf52840::acomp::Comparator nrf52840::acomp::Comparator
@@ -365,60 +303,78 @@ pub unsafe fn main() {
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(nrf52840::nvmc::DRIVER_NUM, &memory_allocation_capability), board_kernel.create_grant(&memory_allocation_capability),
dynamic_deferred_caller,
&mut APP_FLASH_BUFFER,
) )
); );
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<
capsules::usb::usb_ctap::DRIVER_NUM, 'static,
&nrf52840_peripherals.usbd, '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_helper!(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();
let scheduler = components::sched::round_robin::RoundRobinComponent::new(&PROCESSES) // Configure the USB userspace driver
.finalize(components::rr_component_helper!(NUM_PROCS)); 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,
usb, usb,
ipc: kernel::ipc::IPC::new( ipc: kernel::ipc::IPC::new(board_kernel, &memory_allocation_capability),
board_kernel,
kernel::ipc::DRIVER_NUM,
&memory_allocation_capability,
),
scheduler,
systick: cortexm4::systick::SysTick::new_with_calibration(64000000),
}; };
let _ = platform.pconsole.start(); platform.pconsole.start();
debug!("Initialization complete. Entering main loop\r"); debug!("Initialization complete. Entering main loop\r");
debug!("{}", &nrf52840::ficr::FICR_INSTANCE); debug!("{}", &nrf52840::ficr::FICR_INSTANCE);
// These symbols are defined in the linker script. /// These symbols are defined in the linker script.
extern "C" { extern "C" {
/// Beginning of the ROM region containing app images. /// Beginning of the ROM region containing app images.
static _sapps: u8; static _sapps: u8;
@@ -430,7 +386,7 @@ pub unsafe fn main() {
static _eappmem: u8; static _eappmem: u8;
} }
kernel::process::load_processes( kernel::procs::load_processes(
board_kernel, board_kernel,
chip, chip,
core::slice::from_raw_parts( core::slice::from_raw_parts(
@@ -442,7 +398,7 @@ pub unsafe fn main() {
&_eappmem as *const u8 as usize - &_sappmem as *const u8 as usize, &_eappmem as *const u8 as usize - &_sappmem as *const u8 as usize,
), ),
&mut PROCESSES, &mut PROCESSES,
&FAULT_RESPONSE, FAULT_RESPONSE,
&process_management_capability, &process_management_capability,
) )
.unwrap_or_else(|err| { .unwrap_or_else(|err| {
@@ -450,5 +406,13 @@ pub unsafe fn main() {
debug!("{:?}", err); debug!("{:?}", err);
}); });
board_kernel.kernel_loop(&platform, chip, Some(&platform.ipc), &main_loop_capability); 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,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,108 +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;
use crate::PROCESS_PRINTER;
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;
let _ = 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,
&PROCESS_PRINTER,
)
}

View File

@@ -1,569 +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)]
#![deny(missing_docs)]
use capsules::virtual_alarm::VirtualMuxAlarm;
use core::env;
use kernel::component::Component;
use kernel::dynamic_deferred_call::{DynamicDeferredCall, DynamicDeferredCallClientState};
use kernel::hil::led::LedLow;
use kernel::hil::time::Counter;
use kernel::platform::{KernelResources, SyscallDriverLookup, SyscallFilter};
use kernel::scheduler::round_robin::RoundRobinSched;
#[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",
// Interface description + main HID string
"FIDO2",
// vendor HID string
"Vendor HID",
];
// State for loading and holding applications.
// How should the kernel respond when a process faults.
const FAULT_RESPONSE: kernel::process::PanicFaultPolicy = kernel::process::PanicFaultPolicy {};
// Number of concurrent processes this platform supports.
const NUM_PROCS: usize = 8;
static mut PROCESSES: [Option<&'static dyn kernel::process::Process>; NUM_PROCS] =
[None; NUM_PROCS];
include!(concat!(env!("OUT_DIR"), "/locations.rs"));
static mut CHIP: Option<&'static nrf52840::chip::NRF52<Nrf52840DefaultPeripherals>> = None;
static mut PROCESS_PRINTER: Option<&'static kernel::process::ProcessPrinterText> = None;
/// Flash buffer for the custom nvmc driver
static mut APP_FLASH_BUFFER: [u8; 0x1000] = [0; 0x1000];
/// Dummy buffer that causes the linker to reserve enough space for the stack.
#[no_mangle]
#[link_section = ".stack_buffer"]
pub static mut STACK_MEMORY: [u8; 0x2000] = [0; 0x2000];
/// 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,
VirtualMuxAlarm<'static, nrf52840::rtc::Rtc<'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>>,
4,
>,
rng: &'static capsules::rng::RngDriver<'static>,
ipc: kernel::ipc::IPC<{ NUM_PROCS as u8 }>,
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>,
>,
scheduler: &'static RoundRobinSched<'static>,
systick: cortexm4::systick::SysTick,
}
impl SyscallDriverLookup for Platform {
fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
where
F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> 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)),
kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)),
_ => f(None),
}
}
}
impl SyscallFilter for Platform {
fn filter_syscall(
&self,
process: &dyn kernel::process::Process,
syscall: &kernel::syscall::Syscall,
) -> Result<(), kernel::errorcode::ErrorCode> {
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::ErrorCode::INVAL)
}
_ => Ok(()),
}
}
}
/// This is in a separate, inline(never) function so that its stack frame is
/// removed when this function returns. Otherwise, the stack space used for
/// these static_inits is wasted.
#[inline(never)]
unsafe fn get_peripherals() -> &'static mut Nrf52840DefaultPeripherals<'static> {
// Initialize chip peripheral drivers
let nrf52840_peripherals = static_init!(
Nrf52840DefaultPeripherals,
Nrf52840DefaultPeripherals::new()
);
nrf52840_peripherals
}
impl KernelResources<nrf52840::chip::NRF52<'static, Nrf52840DefaultPeripherals<'static>>>
for Platform
{
type SyscallDriverLookup = Self;
type SyscallFilter = Self;
type ProcessFault = ();
type Scheduler = RoundRobinSched<'static>;
type SchedulerTimer = cortexm4::systick::SysTick;
type WatchDog = ();
type ContextSwitchCallback = ();
fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
&self
}
fn syscall_filter(&self) -> &Self::SyscallFilter {
&self
}
fn process_fault(&self) -> &Self::ProcessFault {
&()
}
fn scheduler(&self) -> &Self::Scheduler {
self.scheduler
}
fn scheduler_timer(&self) -> &Self::SchedulerTimer {
&self.systick
}
fn watchdog(&self) -> &Self::WatchDog {
&()
}
fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
&()
}
}
/// Main function called after RAM initialized.
#[no_mangle]
pub unsafe fn main() {
// Loads relocations and clears BSS
nrf52840::init();
// Initialize chip peripheral drivers
let nrf52840_peripherals = get_peripherals();
// set up circular peripheral dependencies
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,
capsules::gpio::DRIVER_NUM,
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,
capsules::button::DRIVER_NUM,
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().finalize(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]),
));
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;
let _ = 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,
capsules::alarm::DRIVER_NUM,
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);
let process_printer =
components::process_printer::ProcessPrinterTextComponent::new().finalize(());
PROCESS_PRINTER = Some(process_printer);
// Create a shared UART channel for the console and for kernel debug.
let uart_mux =
components::console::UartMuxComponent::new(channel, 115200, dynamic_deferred_caller)
.finalize(());
let pconsole = components::process_console::ProcessConsoleComponent::new(
board_kernel,
uart_mux,
mux_alarm,
process_printer,
)
.finalize(components::process_console_component_helper!(
nrf52840::rtc::Rtc<'static>
));
// Setup the console.
let console = components::console::ConsoleComponent::new(
board_kernel,
capsules::console::DRIVER_NUM,
uart_mux,
)
.finalize(components::console_component_helper!());
// Create the debugger object that handles calls to `debug!()`.
components::debug_writer::DebugWriterComponent::new(uart_mux).finalize(());
let rng = components::rng::RngComponent::new(
board_kernel,
capsules::rng::DRIVER_NUM,
&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
),
board_kernel,
capsules::analog_comparator::DRIVER_NUM,
)
.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(nrf52840::nvmc::DRIVER_NUM, &memory_allocation_capability),
dynamic_deferred_caller,
&mut APP_FLASH_BUFFER,
)
);
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,
capsules::usb::usb_ctap::DRIVER_NUM,
&nrf52840_peripherals.usbd,
capsules::usb::usbc_client::MAX_CTRL_PACKET_SIZE_NRF52840,
VENDOR_ID,
PRODUCT_ID,
STRINGS,
)
.finalize(components::usb_ctap_component_helper!(nrf52840::usbd::Usbd));
let scheduler = components::sched::round_robin::RoundRobinComponent::new(&PROCESSES)
.finalize(components::rr_component_helper!(NUM_PROCS));
nrf52_components::NrfClockComponent::new(&base_peripherals.clock).finalize(());
let platform = Platform {
button,
pconsole,
console,
led,
gpio,
rng,
alarm,
analog_comparator,
nvmc,
usb,
ipc: kernel::ipc::IPC::new(
board_kernel,
kernel::ipc::DRIVER_NUM,
&memory_allocation_capability,
),
scheduler,
systick: cortexm4::systick::SysTick::new_with_calibration(64000000),
};
let _ = 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::process::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);
});
board_kernel.kernel_loop(&platform, chip, Some(&platform.ipc), &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: 0x4000,
size: 0x2000,
storage_type: kernel::StorageType::Partition,
},
kernel::StorageLocation {
address: 0x60000,
size: 0x20000,
storage_type: kernel::StorageType::Partition,
},
kernel::StorageLocation {
address: 0x80000,
size: 0x20000,
storage_type: kernel::StorageType::Partition,
},
];
"
).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: 0x4000,
size: 0x2000,
storage_type: kernel::StorageType::Partition,
},
kernel::StorageLocation {
address: 0x20000,
size: 0x20000,
storage_type: kernel::StorageType::Partition,
},
kernel::StorageLocation {
address: 0x40000,
size: 0x20000,
storage_type: kernel::StorageType::Partition,
},
];
"
).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.7",
"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.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[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.7",
"volatile-register",
]
[[package]]
name = "cortex-m"
version = "0.7.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9"
dependencies = [
"bare-metal",
"bitfield",
"embedded-hal",
"volatile-register",
]
[[package]]
name = "cortex-m-rt"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee84e813d593101b1723e13ec38b6ab6abbdbaaa4546553f5395ed274079ddb1"
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.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
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.1.0",
]
[[package]]
name = "nb"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d"
[[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.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
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.7",
"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.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "tock-registers"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ee8fba06c1f4d0b396ef61a54530bb6b28f0dc61c38bc8bc5a5a48161e6282e"
[[package]]
name = "typenum"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[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.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[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.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc"
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 = "0.7.0"
[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,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,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,284 +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;
use tock_registers::interfaces::{Readable, Writeable};
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,178 +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;
const METADATA_SIGN_OFFSET: usize = 0x800;
/// 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],
_signature: [u8; 64],
version: u64,
address: u32,
}
/// 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(),
_signature: page[32..96].try_into().unwrap(),
version: LittleEndian::read_u64(&page[METADATA_SIGN_OFFSET..][..8]),
address: LittleEndian::read_u32(&page[METADATA_SIGN_OFFSET + 8..][..4]),
}
}
}
/// 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 firmware version if all checks pass.
pub fn read_version(&self) -> Result<u64, ()> {
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!(
"Partition 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.version)
}
/// 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();
cc310.update(&metadata_page[METADATA_SIGN_OFFSET..], false);
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,
page_offset + PAGE_SIZE == BootPartition::FIRMWARE_LENGTH,
);
}
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 version_a = partition_a.read_version();
#[cfg(debug_assertions)]
rprintln!("Reading partition B");
let version_b = partition_b.read_version();
match (version_a, version_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) -> &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,46 +12,24 @@
// 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 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");
let mut aaguid_bin_file = File::create(aaguid_bin_path).unwrap(); let mut aaguid_bin_file = File::create(&aaguid_bin_path).unwrap();
let mut aaguid_txt_file = File::open("crypto_data/aaguid.txt").unwrap(); let mut aaguid_txt_file = File::open("crypto_data/aaguid.txt").unwrap();
let mut content = String::new(); let mut content = String::new();
aaguid_txt_file.read_to_string(&mut content).unwrap(); aaguid_txt_file.read_to_string(&mut content).unwrap();
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();
let upgrade_pubkey_path = Path::new(&out_dir).join("opensk_upgrade_pubkey.bin");
let mut upgrade_pub_bin_file = File::create(upgrade_pubkey_path).unwrap();
upgrade_pub_bin_file.write_all(&raw_bytes).unwrap();
} }

725
deploy.py

File diff suppressed because it is too large Load Diff

View File

@@ -1,119 +0,0 @@
# <img alt="OpenSK logo" src="../img/OpenSK.svg" width="200px">
## Nordic nRF52840 Dongle
![Nordic dongle](../img/dongle_front.jpg)
### 3D printed enclosure
To protect and carry your key, we partnered with a professional designer and we
are providing a custom enclosure that can be printed on both professional 3D
printers and hobbyist models.
![OpenSK Enclosure](../img/enclosure.jpg)
All the required files can be downloaded from
[Thingiverse](https://www.thingiverse.com/thing:4132768) including the STEP
file, allowing you to easily make the modifications you need to further
customize it.
### Flashing using DFU (preferred method)
To flash the firmware, run:
```shell
./deploy.py --board=nrf52840_dongle_dfu --opensk --programmer=nordicdfu
```
The script will ask you to switch to DFU mode. To activate that on your dongle,
keep the button pressed while inserting the device into your USB port. You may
additionally need to press the tiny, sideways facing reset button. The device
indicates DFU mode with a slowly blinking red LED.
### Flashing with an external programmer (JLink, OpenOCD, etc.)
If you want to use JTAG with the dongle, you need additional hardware.
* a [Segger J-Link](https://www.segger.com/products/debug-probes/j-link/) JTAG
probe.
* a
[TC2050 Tag-Connect programming cable](https://www.tag-connect.com/product/tc2050-idc-nl-10-pin-no-legs-cable-with-ribbon-connector).
* a [Tag-Connect TC2050 ARM2010](http://www.tag-connect.com/TC2050-ARM2010)
adaptor
* optionally a
[Tag-Connect TC2050 retainer clip](http://www.tag-connect.com/TC2050-CLIP)
to keep the spring loaded connector pressed to the PCB.
Follow these steps:
1. The JTAG probe used for programming won't provide power to the board.
Therefore you will need to use a USB-A extension cable to power the dongle
through its USB port.
1. Connect the TC2050 cable to the pads below the PCB:
![Nordic dongle pads](../img/dongle_pads.jpg)
1. You can use the retainer clip if you have one to avoid maintaining pressure
between the board and the cable:
![Nordic dongle retainer clip](../img/dongle_clip.jpg)
#### JLink
Run our script for compiling/flashing Tock OS on your device:
```shell
$ ./deploy.py --board=nrf52840_dongle --programmer=jlink
```
#### OpenOCD
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
The bigger, white button conveys user presence to the application. Some actions
like register and login will make the dongle blink, asking you to confirm the
transaction with a button press. The small, sideways pointing buttong next to it
restarts the dongle.
The 2 LEDs show the state of the app. There are different patterns:
| Pattern | Cause |
|------------------------------------|------------------------|
| all LEDs and colors | app panic |
| green and blue blinking | asking for touch |
| all LEDs and colors for 5s | wink (just saying Hi!) |
| red slow blink | DFU mode |

View File

@@ -1,23 +0,0 @@
# <img alt="OpenSK logo" src="../img/OpenSK.svg" width="200px">
## Feitian OpenSK USB Dongle
### Flashing using DFU
This board is similar in hardware to the Nordic nRF52840 Dongle. You can use DFU
to flash it, instructions to enter DFU mode depend on the version of your
hardware. See
[Feitian's instructions](https://feitiantech.github.io/OpenSK_USB/). In short:
* In V1, use a paperclip to press the Reset button through the tiny hole.
* In V2, push and hold the user button for more than 10 seconds after
connecting your device.
Afterwards, you can flash your Feitian OpenSK using DFU following the
[instructions for the Nordic nRF52840 Dongle](nrf52840_dongle.md#Flashing-using-DFU).
### Buttons and LEDs
For both hardware versions, the buttons and LEDs are described in detail in the
[hardware section](https://feitiantech.github.io/OpenSK_USB/hardware/) of
Feitian's website.

View File

@@ -1,47 +0,0 @@
# <img alt="OpenSK logo" src="../img/OpenSK.svg" width="200px">
## Nordic nRF52840 MDK
Makerdiary has instructions on their [website](https://wiki.makerdiary.com/nrf52840-mdk-usb-dongle/opensk/). They use a custom script to deploy via DFU.
After general setup, you still need these steps:
1. Create the hexfile with the firmware.
```shell
./deploy.py --board=nrf52840_mdk_dfu --opensk --programmer=none
```
1. Download the
[script](https://github.com/makerdiary/nrf52840-mdk-usb-dongle/blob/master/tools/uf2conv.py)
from Makerdiary's GitHub into the OpenSK repository.
1. Run the script:
```shell
py_virtual_env/bin/python3 uf2conv.py -c -f 0xada52840 -o target/opensk.uf2 target/nrf52840_mdk_dfu_merged.hex
```
1. Boot into DFU mode. Keep the user button pressed on your hardware while
inserting it into a USB slot. You should see a bit of red blinking, and then
a constant green light.
1. Your dongle should appear in your normal file browser like other USB sticks.
Copy the file `target/opensk.uf2` over.
1. Replug to reboot.
### Buttons and LEDs
The big, white button conveys user presence to the application. Some actions
like register and login will make the device blink, asking you to confirm the
transaction with a button press.
The LED shows the state of the app. There are different patterns:
| Pattern | Cause |
|------------------------------------|------------------------|
| red glow | busy |
| red and blue blinking | asking for touch |
| red, green, white pattern for 5s | wink (just saying Hi!) |
| constant green | DFU mode |

View File

@@ -1,85 +0,0 @@
# <img alt="OpenSK logo" src="../img/OpenSK.svg" width="200px">
## Nordic nRF52840-DK board
![Nordic development kit](../img/devkit_annotated.jpg)
### Flashing using JTAG
The development board comes with its own JTAG port, so the default programmer
is the easiest and most convenient. You can flash OpenSK with these steps:
1. Connect a micro USB cable to the JTAG USB port.
1. Run our script for compiling/flashing Tock OS and OpenSK on your device:
```shell
./deploy.py --board=nrf52840dk_opensk --opensk
```
1. Connect a micro USB cable to the device USB port.
**Note**: Due to current limitations of our implementation and Tock, you may
have to press the `BOOT/RESET` button, located next to the device USB port on
the board in order to see your OpenSK device on your system.
### Buttons and LEDs
Out of the 5 buttons, the group of 4 behaves identically. They all convey user
presence to the application. Some actions like register and login will make the
board blink, asking you to confirm the transaction with a button press. The
remaining fifth button restarts the board.
The group of 4 LEDs on the right show the state of the app. There are different
patterns:
| Pattern | Cause |
|------------------------------------|------------------------|
| LED1 slow blink | kernel panic |
| all LEDs blinking together | app panic |
| LED1+4 and LED2+3 fast alternating | asking for touch |
| fast swirling | wink (just saying Hi!) |
| circle | allocator panic |
The LEDs closer to the JTAG port indicates the power and debugging state.
There are 3 switches that need to be in the correct position:
* Power (bottom left): On
* nRF power source (center left): VDD
* 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 --version=0
./deploy.py --board=nrf52840dk_opensk_b --opensk --version=0
```
Afterwards, you can upgrade the other partition with
```shell
# Board A -> B
./deploy.py --board=nrf52840dk_opensk_b --opensk --programmer=none --version=1
py_virtual_env/bin/python3 -m tools.deploy_partition --board=nrf52840dk_opensk_b --version=1
# Board B -> A
./deploy.py --board=nrf52840dk_opensk_a --opensk --programmer=none --version=1
py_virtual_env/bin/python3 -m tools.deploy_partition --board=nrf52840dk_opensk_a --version=1
```
respectively. You can only upgrade the partition that is not currently running,
otherwise your deploy attempts will fail. You can call `deploy_partition` after
you locked down your device, to deploy changes to your development board.
Upgrades only apply after a reboot.
If you want to use Vendor HID, add the `--vendor-hid` flag to all calls,
for example:
```shell
./deploy.py --board=nrf52840dk_opensk_a --opensk --version=0 --vendor-hid
./deploy.py --board=nrf52840dk_opensk_b --opensk --programmer=none --version=1 --vendor-hid
py_virtual_env/bin/python3 -m tools.deploy_partition --board=nrf52840dk_opensk_b --version=1 --vendor-hid
```

View File

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

View File

@@ -1,95 +0,0 @@
# <img alt="OpenSK logo" src="img/OpenSK.svg" width="200px">
## Customization
### Cryptographic material
All the generated certificates and private keys are stored in the directory
`crypto_data/`. The expected content after running our `setup.sh` script is:
File | Purpose
------------------------ | --------------------------------------------------------
`aaguid.txt` | Text file containaing the AAGUID value
`opensk_ca.csr` | Certificate sign request for the Root CA
`opensk_ca.key` | ECC secp256r1 private key used for the Root CA
`opensk_ca.pem` | PEM encoded certificate of the Root CA
`opensk_ca.srl` | File generated by OpenSSL
`opensk_cert.csr` | Certificate sign request for the attestation certificate
`opensk_cert.pem` | PEM encoded certificate used for the authenticator
`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,
replace the `opensk_cert.pem` and `opensk.key` files. The script at
`tools/configure.py` customizes an OpenSK device with the correct certificate
and private key.
Our build script `build.rs` is responsible for converting the `aaguid.txt` file
into raw data that is then used by the Rust file `src/ctap/key_material.rs`.
Please make sure to safely store all private key material before calling
`reset.sh`, or the files will be lost.
#### Certificate considerations
The certificate on OpenSK is used for attestation. That means, whenever you
register OpenSK on a website, you attest the legitimacy of your hardware. For
self-generated certificates, this claim is rather trivial. Still, it is required
by some websites and to use U2F.
Usually, the attestation private key is shared between a batch of at least
100,000 security keys of the same model. If you build your own OpenSK, your
private key is unique to you. This makes you identifiable across registrations:
Two websites could collaborate to track if registrations were attested with the
same key material. If you use OpenSK beyond experimentation, please consider
carefully if you want to take this privacy risk.
### Software personalization
If you build your own security key, depending on the hardware you use, there are
a few things you can personalize:
1. If you have multiple buttons, choose the buttons responsible for user
presence in `src/main.rs`.
1. If you have colored LEDs, like different blinking patterns and want to play
around with the code in `src/main.rs` more, take a look at e.g. `wink_leds`.
1. You find more options and documentation in `src/ctap/customization.rs`,
including:
* The default level for the credProtect extension.
* The default minimum PIN length, and what relying parties can set it.
* Whether you want to enforce alwaysUv.
* Settings for enterprise attestation.
* The maximum PIN retries.
* Whether you want to use batch attestation.
* Whether you want to use signature counters.
* Various constants to adapt to different hardware.
### Testing and Fuzzing
You might want to test your changes before deploying them. To run unit tests,
make sure that at least the `std` feature is included, e.g.:
```shell
cargo test --features=std,with_ctap1
```
Alternatively, you can simply call our test script to also test all libraries,
run clippy, check formatting and more:
```shell
./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
./fuzzing_setup.sh
```
Then choose a fuzz target from `fuzz/fuzz_targets/`, e.g.:
```shell
cargo fuzz run fuzz_target_process_ctap1
```

View File

@@ -1,137 +0,0 @@
# <img alt="OpenSK logo" src="img/OpenSK.svg" width="200px">
## Troubleshooting and Debugging
### Inspecting USB
The following commands should help you identify whether your operating system
identifies OpenSK over USB.
#### Linux
When plugging in the USB key, the following line should appear in `lsusb`.
```shell
$ lsusb
...
Bus XXX Device YYY: ID 1915:521f Nordic Semiconductor ASA OpenSK
```
You should also see lines similar to the following in `dmesg`.
```shell
$ dmesg
...
[XXX] usb A-BB: new full-speed USB device number 00 using xhci_hcd
[XXX] usb A-BB: New USB device found, idVendor=1915, idProduct=521f, bcdDevice= 0.01
[XXX] usb A-BB: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[XXX] usb A-BB: Product: OpenSK
[XXX] usb A-BB: Manufacturer: Nordic Semiconductor ASA
[XXX] usb A-BB: SerialNumber: v0.1
[XXX] hid-generic 0000:0000:0000.0000: hiddev0,hidraw0: USB HID v1.10 Device [Nordic Semiconductor ASA OpenSK] on usb-0000:00:00.0-00/input0
```
#### Mac OS X
When plugging in the USB key, you should see a similar line by using the `ioreg`
tool:
```shell
$ ioreg -p IOUSB
+-o Root <class IORegistryEntry, id 0x100000100, retain 21>
...
+-o AppleUSBXHCI Root Hub Simulation@14000000 <class AppleUSBRootHubDevice, id 0x100000a00, registered, matched, active, busy 0 (0 ms), retain 9>
+-o OpenSK@14400000 <class AppleUSBDevice, id 0x100003c04, registered, matched, active, busy 0 (0 ms), retain 13>
```
### Debug console
On the dev board, you can read the debug messages using JLink. Use one terminal
for the server and one for the client:
```shell
# Terminal 1
JLinkExe -device nrf52 -if swd -speed 1000 -autoconnect 1
# Terminal 2
JLinkRTTClient
```
You can enhance the debug output by adding flags to the deploy command (see
below for details):
* `--debug`: more debug messages
* `--panic-console`: add panic messages
* `--debug-allocations`: print information about the used heap
Adding debugging to your firmware increases resource usage, including
* USB communication speed
* RAM usage
* binary size
Depending on your choice of board, you may have to increase the available stack
for kernel or app, or disable features so that the binary fits the flash. Also
expect more packet loss.
### App panic messages
By default, libtock-rs blinks some LEDs when the userspace application panics.
This is not always convenient as the panic message is lost. In order to enable
a custom panic handler that first writes the panic message via Tock's console
driver, before faulting the app, you can use the `--panic-console` flag of the
`deploy.py` script.
```shell
# Example on Nordic nRF52840-DK board
./deploy.py --board=nrf52840dk_opensk --opensk --panic-console
```
### Memory allocations
You may want to track memory allocations to understand the heap usage of
OpenSK. This can be useful if you plan to port it to a board with fewer
available RAM for example. To do so, you can enable the `--debug-allocations`
flag of the `deploy.py` script. This enables a custom (userspace) allocator
that prints a message to the console for each allocation and deallocation
operation.
The additional output looks like the following.
```text
# Allocation of 256 byte(s), aligned on 1 byte(s). The allocated address is
# 0x2002401c. After this operation, 2 pointers have been allocated, totalling
# 384 bytes (the total heap usage may be larger, due to alignment and
# fragmentation of allocations within the heap).
alloc[256, 1] = 0x2002401c (2 ptrs, 384 bytes)
# Deallocation of 64 byte(s), aligned on 1 byte(s), from address 0x2002410c.
# After this operation, 1 pointers are allocated, totalling 512 bytes.
dealloc[64, 1] = 0x2002410c (1 ptrs, 512 bytes)
```
A tool is provided to analyze such reports, in `tools/heapviz`. This tool
parses the console output, identifies the lines corresponding to (de)allocation
operations, and first computes some statistics:
* Address range used by the heap over this run of the program,
* Peak heap usage (how many useful bytes are allocated),
* Peak heap consumption (how many bytes are used by the heap, including
unavailable bytes between allocated blocks, due to alignment constraints and
memory fragmentation),
* Fragmentation overhead (difference between heap consumption and usage).
Then, the `heapviz` tool displays an animated "movie" of the allocated bytes in
heap memory. Each frame in this "movie" shows bytes that are currently
allocated, that were allocated but are now freed, and that have never been
allocated. A new frame is generated for each (de)allocation operation. This tool
uses the `ncurses` library, that you may have to install beforehand.
You can control the tool with the following parameters:
* `--logfile` (required) to provide the file which contains the console output
to parse,
* `--fps` (optional) to customize the number of frames per second in the movie
animation.
```shell
cargo run --manifest-path tools/heapviz/Cargo.toml -- --logfile console.log --fps 50
```

Binary file not shown.

Before

Width:  |  Height:  |  Size: 544 KiB

View File

@@ -1,177 +1,340 @@
# <img alt="OpenSK logo" src="img/OpenSK.svg" width="200px"> <img alt="OpenSK logo" src="img/OpenSK.svg" width="200px">
## Installation guide # Installation guide
This document lists required steps to start build your own OpenSK. This document describes in details how to turn a Nordic nRF52840 board into a
working FIDO2 security key.
### Programmers ## Pre-requisite
OpenSK supports different ways to flash your board: ### Hardware
You will need one the following supported boards:
* [Nordic nRF52840-DK](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52840-DK)
development kit. This board is more convenient for development and debug
scenarios as the JTAG probe is already on the board.
* [Nordic nRF52840 Dongle](https://www.nordicsemi.com/Software-and-tools/Development-Kits/nRF52840-Dongle)
to have a more practical form factor.
* [Makerdiary nRF52840-MDK USB dongle](https://wiki.makerdiary.com/nrf52840-mdk/).
* [Feitian OpenSK dongle](https://feitiantech.github.io/OpenSK_USB/).
In the case of the Nordic USB dongle, you may also need the following extra
hardware:
* a [Segger J-Link](https://www.segger.com/products/debug-probes/j-link/) JTAG
probe.
* a
[TC2050 Tag-Connect programming cable](https://www.tag-connect.com/product/tc2050-idc-nl-10-pin-no-legs-cable-with-ribbon-connector).
* a [Tag-Connect TC2050 ARM2010](http://www.tag-connect.com/TC2050-ARM2010)
adaptor
* optionally a
[Tag-Connect TC2050 retainer clip](http://www.tag-connect.com/TC2050-CLIP)
to keep the spring loaded connector pressed to the PCB.
Additionnaly, OpenSK supports other ways to flash your board:
* [OpenOCD](http://openocd.org/).
* [Segger J-Link](https://www.segger.com/products/debug-probes/j-link/) * [Segger J-Link](https://www.segger.com/products/debug-probes/j-link/)
(default method). (default method).
* [OpenOCD](http://openocd.org/).
* [pyOCD](https://pypi.org/project/pyocd/). * [pyOCD](https://pypi.org/project/pyocd/).
* [nrfutil](https://pypi.org/project/nrfutil/) for the USB dongle boards that * [nrfutil](https://pypi.org/project/nrfutil/) for the USB dongle boards that
support it, which allows you to directly flash a working board over USB supports it, which allows you to directly flash a working board over USB
without additional hardware. without additional hardware.
### Software requirements This guide **does not** cover how to setup the JTAG probe and their related
tools on your system.
### Software
In order to compile and flash a working OpenSK firmware, you will need the In order to compile and flash a working OpenSK firmware, you will need the
following: following:
* rustup (can be installed with [Rustup](https://rustup.rs/)) * rustup (can be installed with [Rustup](https://rustup.rs/))
* python3 and pip (can be installed with the `python3-pip` package on Debian) * python3 and pip (can be installed with the `python3-pip` package on Debian)
* the OpenSSL command line tool (can be installed and configured with the * the OpenSSL command line tool (can be installed with the `libssl-dev`
`libssl-dev` and `pkg-config` packages on Debian) package on Debian)
* `nrfutil` (can be installed using `pip3 install nrfutil`) if you want to flash
a device with DFU
* `uuid-runtime` if you are missing the `uuidgen` command.
* `llvm` and `gcc-arm-none-eabi` if you want to use the upgradability feature.
The proprietary software to use the default programmer can be found on the
[Segger website](https://www.segger.com/downloads/jlink). Please follow their
instructions to appropriate binaries for your system.
The scripts provided in this project have been tested under Linux and OS X. We The scripts provided in this project have been tested under Linux and OS X. We
haven't tested them on Windows and other platforms. haven't tested them on Windows and other platforms.
If you use Python newer than 3.10, then nrfutil for flashing over DFU is ## Compiling the firmware
currently not supported. Please use Python 3.10, or play around with [Nordic's
new tool](https://www.nordicsemi.com/Products/Development-tools/nrf-util)
instead.
### Compiling the firmware ### Initial setup
If this is your first time installing OpenSK, please skip directly to If you just cloned this repository, you need to run the following script
[Initial setup](#Initial-setup). Else, see (_output may differ_):
[Updating your setup](#Updating-your-setup) below.
#### Updating your setup
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:
```shell ```shell
git clone -b develop https://github.com/google/OpenSK.git $ ./setup.sh
cd OpenSK [-] Applying patch "01-persistent-storage.patch"... DONE.
./setup.sh [-] Applying patch "02-usb.patch"... DONE.
[-] Applying patch "03-app-memory.patch"... DONE.
[-] Applying patch "04-rtt.patch"... DONE.
[-] Applying patch "01-linked_list_allocator.patch"... DONE.
[-] Applying patch "02-panic_console.patch"... DONE.
[-] Applying patch "03-timer.patch"... DONE.
[-] Applying patch "04-public_syscalls.patch"... DONE.
[-] Applying patch "05-bigger_heap.patch"... DONE.
[-] Applying patch "06-no_spin_allocator.patch"... DONE.
Signature ok
subject=CN = Google OpenSK CA
Getting Private key
Signature ok
subject=CN = Google OpenSK Hacker Edition
Getting CA Private Key
info: syncing channel updates for 'nightly-2020-02-03-x86_64-unknown-linux-gnu'
nightly-2020-02-03-x86_64-unknown-linux-gnu unchanged - rustc 1.42.0-nightly (f43c34a13 2020-02-02)
Requirement already up-to-date: tockloader in /usr/lib/python3/dist-packages/tockloader-1.4.0.dev0-py3.7.egg (1.4.0.dev0)
Requirement already satisfied, skipping upgrade: argcomplete>=1.8.2 in /usr/lib/python3/dist-packages (from tockloader) (1.10.0)
Requirement already satisfied, skipping upgrade: colorama>=0.3.7 in /usr/lib/python3/dist-packages (from tockloader) (0.3.7)
Requirement already satisfied, skipping upgrade: crcmod>=1.7 in /usr/lib/python3/dist-packages (from tockloader) (1.7)
Requirement already satisfied, skipping upgrade: pyserial>=3.0.1 in /usr/lib/python3/dist-packages (from tockloader) (3.4)
Requirement already satisfied, skipping upgrade: pytoml>=0.1.11 in /usr/lib/python3/dist-packages (from tockloader) (0.1.21)
info: component 'rust-std' for target 'thumbv7em-none-eabi' is up to date
Updating crates.io index
Ignored package `elf2tab v0.4.0` is already installed, use --force to override
``` ```
The setup script performs the following steps: The script performs the following steps:
1. Make sure that the git submodules are checked out. 1. Make sure that the git submodules are checked out
1. Apply our patches that haven't yet been merged upstream to both 1. Apply our patches that haven't yet been merged upstream to both
[Tock](https://github.com/tock/tock) and [Tock](https://github.com/tock/tock) and
[libtock-rs](https://github.com/tock/libtock-rs). [libtock-rs](https://github.com/tock/libtock-rs)
1. Generate crypto material, see [Customization](customization.md) for details. 1. Generate a self-signed certificate authority as well as a private key and a
corresponding certificate for your OpenSK key signed by this CA. You will be
able to replace them with your own certificate and private key.
1. Install the correct Rust toolchain for ARM devices. 1. Ensure that your Rust toolchain is using the same version that we tested
OpenSK with.
1. Install [tockloader](https://github.com/tock/tockloader). 1. Install [tockloader](https://github.com/tock/tockloader).
Additionally on Linux, you need to install a `udev` rule file to allow non-root 1. Ensure that the Rust toolchain can compile code for ARM devices.
users to interact with OpenSK devices. To install it, execute:
### Replacing the certificates
All the generated certificates and private keys are stored in the directory
`crypto_data/`.
This is the expected content after running our `setup.sh` script:
File | Purpose
----------------- | --------------------------------------------------------
`aaguid.txt` | Text file containaing the AAGUID value
`opensk_ca.csr` | Certificate sign request for the Root CA
`opensk_ca.key` | ECC secp256r1 private key used for the Root CA
`opensk_ca.pem` | PEM encoded certificate of the Root CA
`opensk_ca.srl` | File generated by OpenSSL
`opensk_cert.csr` | Certificate sign request for the attestation certificate
`opensk_cert.pem` | PEM encoded certificate used for the authenticator
`opensk.key` | ECC secp256r1 private key used for the autenticator
If you want to use your own attestation certificate and private key, simply
replace `opensk_cert.pem` and `opensk.key` files.
Our build script `build.rs` is responsible for converting the `aaguid.txt` file
into raw data that is then used by the Rust file `src/ctap/key_material.rs`.
Our configuration script `tools/configure.py` is responsible for configuring
an OpenSK device with the correct certificate and private key.
### Flashing a firmware
#### Nordic nRF52840-DK board
![Nordic development kit](img/devkit_annotated.jpg)
1. Connect a micro USB cable to the JTAG USB port.
1. Run our script for compiling/flashing Tock OS and OpenSK on your device
(_output may differ_):
```shell
$ ./deploy.py --board=nrf52840dk --opensk
info: Updating rust toolchain to nightly-2020-02-03
info: syncing channel updates for 'nightly-2020-02-03-x86_64-unknown-linux-gnu'
info: checking for self-updates
info: component 'rust-std' for target 'thumbv7em-none-eabi' is up to date
info: Rust toolchain up-to-date
info: Building Tock OS for board nrf52840dk
Compiling tock-registers v0.5.0 (./third_party/tock/libraries/tock-register-interface)
Compiling tock-cells v0.1.0 (./third_party/tock/libraries/tock-cells)
Compiling enum_primitive v0.1.0 (./third_party/tock/libraries/enum_primitive)
Compiling tock_rt0 v0.1.0 (./third_party/tock/libraries/tock-rt0)
Compiling nrf52840dk v0.1.0 (./third_party/tock/boards/nordic/nrf52840dk)
Compiling kernel v0.1.0 (./third_party/tock/kernel)
Compiling cortexm v0.1.0 (./third_party/tock/arch/cortex-m)
Compiling nrf5x v0.1.0 (./third_party/tock/chips/nrf5x)
Compiling capsules v0.1.0 (./third_party/tock/capsules)
Compiling cortexm4 v0.1.0 (./third_party/tock/arch/cortex-m4)
Compiling nrf52 v0.1.0 (./third_party/tock/chips/nrf52)
Compiling nrf52840 v0.1.0 (./third_party/tock/chips/nrf52840)
Compiling components v0.1.0 (./third_party/tock/boards/components)
Compiling nrf52dk_base v0.1.0 (./third_party/tock/boards/nordic/nrf52dk_base)
Finished release [optimized + debuginfo] target(s) in 13.15s
info: Converting Tock OS file into a binary
info: Building OpenSK application
Finished release [optimized] target(s) in 0.02s
info: Generating Tock TAB file for application/example ctap2
info: Erasing all installed applications
All apps have been erased.
info: Flashing file third_party/tock/boards/nordic/nrf52840dk/target/thumbv7em-none-eabi/release/nrf52840dk.bin.
info: Flashing padding application
info: Installing Tock application ctap2
info: You're all set!
```
1. Connect a micro USB cable to the device USB port.
**Note**: Due to current limitations of our implementation and Tock, you may
have to press the `BOOT/RESET` button, located next to the device USB port on
the board in order to see your OpenSK device on your system.
#### Nordic nRF52840 Dongle
##### Using external programmer (JLink, OpenOCD, etc.)
![Nordic dongle](img/dongle_front.jpg)
1. The JTAG probe used for programming won't provide power to the board.
Therefore you will need to use a USB-A extension cable to power the dongle
through its USB port.
1. Connect the TC2050 cable to the pads below the PCB:
![Nordic dongle pads](img/dongle_pads.jpg)
1. You can use the retainer clip if you have one to avoid maintaining pressure
between the board and the cable:
![Nordic dongle retainer clip](img/dongle_clip.jpg)
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
(_output may differ_):
```shell
$ ./deploy.py os --board=nrf52840_dongle --programmer=jlink
info: Updating rust toolchain to nightly-2020-02-03
info: syncing channel updates for 'nightly-2020-02-03-x86_64-unknown-linux-gnu'
info: checking for self-updates
info: component 'rust-std' for target 'thumbv7em-none-eabi' is up to date
info: Rust toolchain up-to-date
info: Building Tock OS for board nrf52840_dongle
Compiling tock-cells v0.1.0 (./third_party/tock/libraries/tock-cells)
Compiling tock-registers v0.5.0 (./third_party/tock/libraries/tock-register-interface)
Compiling enum_primitive v0.1.0 (./third_party/tock/libraries/enum_primitive)
Compiling tock_rt0 v0.1.0 (./third_party/tock/libraries/tock-rt0)
Compiling nrf52840_dongle v0.1.0 (./third_party/tock/boards/nordic/nrf52840_dongle)
Compiling kernel v0.1.0 (./third_party/tock/kernel)
Compiling cortexm v0.1.0 (./third_party/tock/arch/cortex-m)
Compiling nrf5x v0.1.0 (./third_party/tock/chips/nrf5x)
Compiling capsules v0.1.0 (./third_party/tock/capsules)
Compiling cortexm4 v0.1.0 (./third_party/tock/arch/cortex-m4)
Compiling nrf52 v0.1.0 (./third_party/tock/chips/nrf52)
Compiling nrf52840 v0.1.0 (./third_party/tock/chips/nrf52840)
Compiling components v0.1.0 (./third_party/tock/boards/components)
Compiling nrf52dk_base v0.1.0 (./third_party/tock/boards/nordic/nrf52dk_base)
Finished release [optimized + debuginfo] target(s) in 11.72s
info: Converting Tock OS file into a binary
info: Building OpenSK application
Finished release [optimized] target(s) in 0.02s
info: Generating Tock TAB file for application/example ctap2
info: Erasing all installed applications
All apps have been erased.
info: Flashing file third_party/tock/boards/nordic/nrf52840_dongle/target/thumbv7em-none-eabi/release/nrf52840_dongle.bin.
info: Flashing padding application
info: Installing Tock application ctap2
info: You're all set!
```
1. Remove the programming cable and the USB-A extension cable.
### Advanced installation
Although flashing using a Segger JLink probe is the officially supported way,
our tool, `deploy.py` also supports other methods:
* OpenOCD: `./deploy.py --board=nrf52840_dongle --opensk --programmer=openocd`
* pyOCD: `./deploy.py --board=nrf52840_dongle --opensk --programmer=pyocd`
* Nordic DFU: `./deploy.py --board=nrf52840_dongle --opensk
--programmer=nordicdfu`
* Custom: `./deploy.py --board=nrf52840_dongle --opensk --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:
`./deploy.py --board=nrf52840dk --opensk --no-tockos`
For more options, we invite you to read the help of our `deploy.py` script by
running `./deploy.py --help`.
### Installing the udev rule (Linux only)
By default on Linux, a USB device will require root privilege in order interact
with it. As it is not recommended to run your web browser with such a high
privileged account, we made a `udev` rule file to allow regular users to
interact with OpenSK authenticators.
To install it, you need to execute the following commands:
```shell ```shell
sudo cp rules.d/55-opensk.rules /etc/udev/rules.d/ sudo cp rules.d/55-opensk.rules /etc/udev/rules.d/
sudo udevadm control --reload sudo udevadm control --reload
``` ```
Then, you need and replug the device for the rule to trigger. Then, you will need to unplug and replug the key for the rule to trigger.
Last, if you want to use U2F or attestation, configure the certificate. If your ## Troubleshooting
client does not support FIDO2 yet, this step is mandatory for your OpenSK to
work. OpenSK is incompatible with some browsers without a certificate. Please To test whether the installation was successful, visit a
read the [demo website](https://webauthn.io/) and try to register and login.
[certificate section in Customization](customization.md#Certificate-considerations)
for understand privacy tradeoffs. ### Linux
If you have issues with the demo website, the following commands should help you
understand whether OpenSK was installed properly.
When plugging in the USB key, the following line should appear in `lsusb`.
```shell ```shell
./tools/configure.py \ $ lsusb
--certificate=crypto_data/opensk_cert.pem \ ...
--private-key=crypto_data/opensk.key Bus XXX Device YYY: ID 1915:521f Nordic Semiconductor ASA OpenSK
``` ```
### Flashing a firmware You should also see lines similar to the following in `dmesg`.
From here on, please follow the instructions for your hardware: ```shell
$ dmesg
...
[XXX] usb A-BB: new full-speed USB device number 00 using xhci_hcd
[XXX] usb A-BB: New USB device found, idVendor=1915, idProduct=521f, bcdDevice= 0.01
[XXX] usb A-BB: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[XXX] usb A-BB: Product: OpenSK
[XXX] usb A-BB: Manufacturer: Nordic Semiconductor ASA
[XXX] usb A-BB: SerialNumber: v0.1
[XXX] hid-generic 0000:0000:0000.0000: hiddev0,hidraw0: USB HID v1.10 Device [Nordic Semiconductor ASA OpenSK] on usb-0000:00:00.0-00/input0
```
* [Nordic nRF52840-DK](boards/nrf52840dk.md) ### Mac OS X
* [Nordic nRF52840 Dongle](boards/nrf52840_dongle.md)
* [Makerdiary nRF52840-MDK USB dongle](boards/nrf52840_mdk.md)
* [Feitian OpenSK dongle](boards/nrf52840_feitian.md)
### Advanced installation If you have issues with the demo website, the following commands should help you
understand whether OpenSK was installed properly.
We recommend that you flash your development board with JTAG and dongles with When plugging in the USB key, you should see a similar line by using the `ioreg`
DFU, as described in the [board documentation](#Flashing-a-firmware) linked tool:
above. However, we support other programmers:
* OpenOCD: `./deploy.py --board=nrf52840_dongle_opensk --opensk ```shell
--programmer=openocd` $ ioreg -p IOUSB
* pyOCD: `./deploy.py --board=nrf52840_dongle_opensk --opensk +-o Root <class IORegistryEntry, id 0x100000100, retain 21>
--programmer=pyocd` ...
* Custom: `./deploy.py --board=nrf52840_dongle_opensk --opensk +-o AppleUSBXHCI Root Hub Simulation@14000000 <class AppleUSBRootHubDevice, id 0x100000a00, registered, matched, active, busy 0 (0 ms), retain 9>
--programmer=none`. In this case, an IntelHex file will be created and how +-o OpenSK@14400000 <class AppleUSBDevice, id 0x100003c04, registered, matched, active, busy 0 (0 ms), retain 13>
to program a board is left to the user. ```
If your board is already flashed with Tock OS, you may skip installing it:
`./deploy.py --board=nrf52840dk_opensk --opensk --no-tockos`
For more options, we invite you to read the help of our `deploy.py` script by
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

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

View File

@@ -12,7 +12,6 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#![no_main]
#![no_std] #![no_std]
extern crate alloc; extern crate alloc;
@@ -21,72 +20,83 @@ 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 core::hint::black_box; use crypto::{
use ctap2::env::tock::{TockEnv, TockRng}; aes256, cbc, ecdsa, rng256, sha256, Decrypt16BytesBlock, Encrypt16BytesBlock, Hash256,
use libtock_console::{Console, ConsoleWriter}; };
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 libtock_runtime::{set_main, stack_size, TockSyscalls}; use libtock_drivers::timer::Timestamp;
use opensk::api::crypto::aes256::Aes256;
use opensk::api::crypto::ecdsa::SecretKey as _;
use opensk::api::crypto::sha256::Sha256;
use opensk::env::{AesKey, EcdsaSk, Sha};
stack_size! {0x2000}
set_main! {main}
type Syscalls = TockSyscalls;
fn main() { fn main() {
let mut console = Console::<Syscalls>::writer(); let mut console = Console::new();
// Setup the timer with a dummy callback (we only care about reading the current time, but the // Setup the timer with a dummy callback (we only care about reading the current time, but the
// API forces us to set an alarm callback too). // API forces us to set an alarm callback too).
let mut with_callback = timer::with_callback(|_| {}); let mut with_callback = timer::with_callback(|_, _| {});
let timer = with_callback.init().flex_unwrap(); let timer = with_callback.init().flex_unwrap();
let mut rng = TockRng::<Syscalls>::default(); let mut rng = rng256::TockRng256 {};
writeln!(console, "****************************************").unwrap(); writeln!(console, "****************************************").unwrap();
writeln!(console, "Clock frequency: {:?} Hz", timer.clock_frequency()).unwrap(); writeln!(
console,
"Clock frequency: {} Hz",
timer.clock_frequency().hz()
)
.unwrap();
// AES // AES
bench(&mut console, &timer, "Aes256::new", || { bench(&mut console, &timer, "aes256::EncryptionKey::new", || {
black_box(AesKey::<TockEnv<Syscalls>>::new(&[0; 32])); aes256::EncryptionKey::new(&[0; 32]);
}); });
let aes_key = AesKey::<TockEnv<Syscalls>>::new(&[0; 32]); let ek = aes256::EncryptionKey::new(&[0; 32]);
bench(&mut console, &timer, "aes256::DecryptionKey::new", || {
aes256::DecryptionKey::new(&ek);
});
let dk = aes256::DecryptionKey::new(&ek);
bench(&mut console, &timer, "Aes256::encrypt_block", || {
aes_key.encrypt_block(&mut [0; 16]);
});
bench(&mut console, &timer, "Aes256::decrypt_block", || {
aes_key.decrypt_block(&mut [0; 16]);
});
// CBC
let mut blocks = Vec::new();
for i in 0..6 {
blocks.resize(1 << (i + 4), 0);
bench( bench(
&mut console, &mut console,
&timer, &timer,
&format!("Aes256::encrypt_cbc({} bytes)", blocks.len()), "aes256::EncryptionKey::encrypt_block",
|| { || {
aes_key.encrypt_cbc(&[0; 16], &mut blocks); ek.encrypt_block(&mut [0; 16]);
},
);
bench(
&mut console,
&timer,
"aes256::DecryptionKey::decrypt_block",
|| {
dk.decrypt_block(&mut [0; 16]);
},
);
// CBC
let mut blocks = Vec::new();
for i in 0..8 {
blocks.resize(1 << i, [0; 16]);
bench(
&mut console,
&timer,
&format!("cbc::cbc_encrypt({} bytes)", blocks.len() * 16),
|| {
cbc::cbc_encrypt(&ek, [0; 16], &mut blocks);
}, },
); );
} }
drop(blocks); drop(blocks);
let mut blocks = Vec::new(); let mut blocks = Vec::new();
for i in 0..6 { 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!("Aes256::decrypt_cbc({} bytes)", blocks.len()), &format!("cbc::cbc_decrypt({} bytes)", blocks.len() * 16),
|| { || {
aes_key.decrypt_cbc(&[0; 16], &mut blocks); cbc::cbc_decrypt(&dk, [0; 16], &mut blocks);
}, },
); );
} }
@@ -94,37 +104,52 @@ fn main() {
// SHA-256 // SHA-256
let mut contents = Vec::new(); let mut contents = Vec::new();
for i in 0..6 { for i in 0..8 {
contents.resize(16 << i, 0); contents.resize(16 << i, 0);
bench( bench(
&mut console, &mut console,
&timer, &timer,
&format!("Sha256::digest({} bytes)", contents.len()), &format!("sha256::Sha256::update({} bytes)", contents.len()),
|| { || {
Sha::<TockEnv<Syscalls>>::digest(&contents); let mut sha = sha256::Sha256::new();
sha.update(&contents);
sha.finalize();
}, },
); );
} }
drop(contents); drop(contents);
// ECDSA // ECDSA
bench(&mut console, &timer, "Ecdsa::SecretKey::random", || { bench(&mut console, &timer, "ecdsa::SecKey::gensk", || {
EcdsaSk::<TockEnv<Syscalls>>::random(&mut rng); ecdsa::SecKey::gensk(&mut rng);
}); });
let sk = EcdsaSk::<TockEnv<Syscalls>>::random(&mut rng); let k = ecdsa::SecKey::gensk(&mut rng);
bench(&mut console, &timer, "Ecdsa::SecretKey::public_key", || { bench(&mut console, &timer, "ecdsa::SecKey::genpk", || {
black_box(sk.public_key()); k.genpk();
});
bench(&mut console, &timer, "Ecdsa::SecretKey::sign", || {
sk.sign(&[]);
}); });
bench(
&mut console,
&timer,
"ecdsa::SecKey::sign_rng::<sha256::Sha256, _>",
|| {
k.sign_rng::<sha256::Sha256, _>(&[], &mut rng);
},
);
bench(
&mut console,
&timer,
"ecdsa::SecKey::sign_rfc6979::<sha256::Sha256>",
|| {
k.sign_rfc6979::<sha256::Sha256>(&[]);
},
);
writeln!(console, "****************************************").unwrap(); writeln!(console, "****************************************").unwrap();
writeln!(console, "All the benchmarks are done.\nHave a nice day!").unwrap(); writeln!(console, "All the benchmarks are done.\nHave a nice day!").unwrap();
writeln!(console, "****************************************").unwrap(); writeln!(console, "****************************************").unwrap();
} }
fn bench<F>(console: &mut ConsoleWriter<Syscalls>, timer: &Timer<Syscalls>, title: &str, mut f: F) fn bench<F>(console: &mut Console, timer: &Timer, title: &str, mut f: F)
where where
F: FnMut(), F: FnMut(),
{ {
@@ -133,13 +158,11 @@ where
writeln!(console, "----------------------------------------").unwrap(); writeln!(console, "----------------------------------------").unwrap();
let mut count = 1; let mut count = 1;
for _ in 0..30 { for _ in 0..30 {
let start = let start = Timestamp::<f64>::from_clock_value(timer.get_current_clock().flex_unwrap());
Timestamp::<f64>::from_clock_value(timer.get_current_counter_ticks().flex_unwrap());
for _ in 0..count { for _ in 0..count {
f(); f();
} }
let end = let end = Timestamp::<f64>::from_clock_value(timer.get_current_clock().flex_unwrap());
Timestamp::<f64>::from_clock_value(timer.get_current_counter_ticks().flex_unwrap());
let elapsed = (end - start).ms(); let elapsed = (end - start).ms();
writeln!( writeln!(
console, console,
@@ -149,6 +172,7 @@ where
elapsed / (count as f64) elapsed / (count as f64)
) )
.unwrap(); .unwrap();
console.flush();
if elapsed > 1000.0 { if elapsed > 1000.0 {
break; break;
} }

View File

@@ -1,63 +0,0 @@
// Copyright 2020 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]
extern crate lang_items;
use core::fmt::Write;
use ctap2::env::tock::take_storage;
use libtock_console::Console;
use libtock_drivers::result::FlexUnwrap;
use libtock_leds::Leds;
use libtock_platform as platform;
use libtock_runtime::{set_main, stack_size, TockSyscalls};
use persistent_store::{Storage, StorageIndex};
use platform::DefaultConfig;
stack_size! {0x800}
set_main! {main}
type Syscalls = TockSyscalls;
fn is_page_erased(storage: &dyn Storage, page: usize) -> bool {
let index = StorageIndex { page, byte: 0 };
let length = storage.page_size();
storage
.read_slice(index, length)
.unwrap()
.iter()
.all(|&x| x == 0xff)
}
fn main() {
Leds::<Syscalls>::on(1).map_err(|e| e.into()).flex_unwrap(); // red on dongle
let mut storage = take_storage::<Syscalls, DefaultConfig>().unwrap();
let num_pages = storage.num_pages();
let mut console = Console::<Syscalls>::writer();
writeln!(console, "Erase {} pages of storage:", num_pages).unwrap();
for page in 0..num_pages {
write!(console, "- Page {} ", page).unwrap();
if is_page_erased(&storage, page) {
writeln!(console, "skipped (was already erased).").unwrap();
} else {
storage.erase_page(page).unwrap();
writeln!(console, "erased.").unwrap();
}
}
writeln!(console, "Done.").unwrap();
Leds::<Syscalls>::on(1).map_err(|e| e.into()).flex_unwrap();
Leds::<Syscalls>::off(0).map_err(|e| e.into()).flex_unwrap(); // green on dongle
}

View File

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

View File

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

View File

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

View File

@@ -12,96 +12,51 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#![no_main]
#![no_std] #![no_std]
extern crate alloc; extern crate alloc;
extern crate lang_items; extern crate lang_items;
use alloc::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, Storage}; use ctap2::embedded_flash::{new_storage, Storage};
use libtock_console::Console; use libtock_drivers::console::Console;
use libtock_drivers::result::FlexUnwrap;
use libtock_drivers::timer::{self, Duration, Timer, Timestamp}; use libtock_drivers::timer::{self, Duration, Timer, Timestamp};
use libtock_platform::DefaultConfig; use persistent_store::Store;
use libtock_runtime::{set_main, stack_size, TockSyscalls};
use persistent_store::{Storage as _, Store};
stack_size! {0x800} fn timestamp(timer: &Timer) -> Timestamp<f64> {
set_main! {main} Timestamp::<f64>::from_clock_value(timer.get_current_clock().ok().unwrap())
type Syscalls = TockSyscalls;
fn timestamp(timer: &Timer<Syscalls>) -> Timestamp<f64> {
Timestamp::<f64>::from_clock_value(timer.get_current_counter_ticks().ok().unwrap())
} }
fn measure<T>(timer: &Timer<Syscalls>, operation: impl FnOnce() -> T) -> (T, Duration<f64>) { fn measure<T>(timer: &Timer, operation: impl FnOnce() -> T) -> (T, Duration<f64>) {
let before = timestamp(timer); let before = timestamp(timer);
let result = operation(); let result = operation();
let after = timestamp(timer); let after = timestamp(timer);
(result, after - before) (result, after - before)
} }
fn boot_store( // Only use one store at a time.
mut storage: Storage<Syscalls, DefaultConfig>, unsafe fn boot_store(num_pages: usize, erase: bool) -> Store<Storage> {
erase: bool, let mut storage = new_storage(num_pages);
) -> Store<Storage<Syscalls, DefaultConfig>> {
let num_pages = 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 { let mut console = Console::new();
num_pages: usize,
}
fn storage_config(storage: &Storage<Syscalls, DefaultConfig>) -> StorageConfig {
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: Storage<Syscalls, DefaultConfig>,
timer: &Timer<Syscalls>,
num_pages: usize,
key_increment: usize,
word_length: usize,
) -> (Storage<Syscalls, DefaultConfig>, Stat) {
let mut stat = Stat {
key_increment,
entry_length: word_length,
..Default::default()
};
let mut console = Console::<Syscalls>::writer();
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);
@@ -117,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();
@@ -156,84 +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::<Syscalls, DefaultConfig, _>(|_| {}); let mut with_callback = timer::with_callback(|_, _| {});
let timer = with_callback.init().ok().unwrap();
let timer = with_callback.init().flex_unwrap(); writeln!(Console::new(), "\nRunning 4 tests...").unwrap();
let storage = take_storage::<Syscalls, DefaultConfig>().unwrap(); // Those non-overwritten 50 words entries simulate credentials.
let config = storage_config(&storage); compute_latency(&timer, 3, 1, 50);
let mut stats = Vec::new(); compute_latency(&timer, 20, 1, 50);
let mut console = Console::<Syscalls>::writer(); // Those overwritten 1 word entries simulate counters.
compute_latency(&timer, 3, 0, 1);
compute_latency(&timer, 6, 0, 1);
writeln!(Console::new(), "\nDone.").unwrap();
writeln!(console, "\nRunning 2 tests...").unwrap(); // Results on nrf52840dk:
// Simulate a store full of credentials (of 50 words). //
let (storage, stat) = compute_latency(storage, &timer, config.num_pages, 1, 50); // | Pages | Overwrite | Length | Boot | Compaction | Insert | Remove |
stats.push(stat); // | ----- | --------- | --------- | ------- | ---------- | ------ | ------- |
// Simulate a store full of increments of a single counter. // | 3 | no | 50 words | 2.0 ms | 132.5 ms | 4.8 ms | 1.2 ms |
let (_storage, stat) = compute_latency(storage, &timer, config.num_pages, 0, 1); // | 20 | no | 50 words | 7.4 ms | 135.5 ms | 10.2 ms | 3.9 ms |
stats.push(stat); // | 3 | yes | 1 word | 21.9 ms | 94.5 ms | 12.4 ms | 5.9 ms |
writeln!(console, "\nDone.\n").unwrap(); // | 6 | yes | 1 word | 55.2 ms | 100.8 ms | 24.8 ms | 12.1 ms |
const HEADERS: &[&str] = &[
"Overwrite",
"Length",
"Boot",
"Compaction",
"Insert",
"Remove",
];
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, "Copy to examples/store_latency.rs:\n").unwrap();
writeln!(console, "{:?}", 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) {
let mut console = Console::<Syscalls>::writer();
for _ in 0..n.saturating_sub(x.len()) {
write!(console, " ").unwrap();
}
write!(console, "{}", 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::<Syscalls>::writer()).unwrap();
}
} }

View File

@@ -1,5 +1,5 @@
[package] [package]
name = "opensk-fuzz" name = "ctap2-fuzz"
version = "0.0.0" version = "0.0.0"
authors = ["Automatically generated"] authors = ["Automatically generated"]
publish = false publish = false
@@ -9,7 +9,7 @@ edition = "2018"
cargo-fuzz = true cargo-fuzz = true
[dependencies] [dependencies]
libfuzzer-sys = { version = "0.3" } libfuzzer-sys = { version = "0.3"}
fuzz_helper = { path = "fuzz_helper" } fuzz_helper = { path = "fuzz_helper" }
# Prevent this from interfering with workspaces # Prevent this from interfering with workspaces
@@ -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

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

View File

@@ -12,24 +12,31 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use arbitrary::{Arbitrary, Unstructured}; // This explicit "extern crate" is needed to make the linker aware of the
// `libtock_alloc_init` symbol.
extern crate lang_items;
use arrayref::array_ref; use arrayref::array_ref;
use core::convert::TryFrom; use core::convert::TryFrom;
use opensk::api::customization::is_valid; use crypto::rng256::ThreadRng256;
use opensk::ctap::command::{ use ctap2::ctap::command::{
AuthenticatorClientPinParameters, AuthenticatorGetAssertionParameters, AuthenticatorClientPinParameters, AuthenticatorGetAssertionParameters,
AuthenticatorMakeCredentialParameters, Command, AuthenticatorMakeCredentialParameters,
}; };
use opensk::ctap::data_formats::EnterpriseAttestationMode; use ctap2::ctap::hid::receive::MessageAssembler;
use opensk::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 opensk::ctap::{cbor_read, Channel, CtapState}; use ctap2::ctap::CtapState;
use opensk::env::test::customization::TestCustomization; use libtock_drivers::timer::{ClockValue, Timestamp};
use opensk::env::test::TestEnv;
use opensk::{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 {
@@ -39,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
@@ -59,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(),
} }
} }
@@ -74,18 +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::default(); 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 ctap.process_hid_packet(&pkt_request, Transport::MainHid) { for pkt_reply in ctap_hid.process_hid_packet(&pkt_request, DUMMY_CLOCK_VALUE, ctap_state) {
if let Ok(Some(result)) = assembler_reply.parse_packet(ctap.env(), &pkt_reply, None) { if let Ok(Some(result)) = assembler_reply.parse_packet(&pkt_reply, DUMMY_TIMESTAMP) {
result_cid.copy_from_slice(&result.payload[8..12]); result_cid.copy_from_slice(&result.payload[8..12]);
} }
} }
@@ -98,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 => {
@@ -117,14 +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::default(); let mut assembler_reply = MessageAssembler::new();
for pkt_request in hid_packet_iterator { for pkt_request in hid_packet_iterator {
for pkt_reply in ctap.process_hid_packet(&pkt_request, Transport::MainHid) { for pkt_reply in
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, None); let _ = assembler_reply.parse_packet(&pkt_reply, DUMMY_TIMESTAMP);
} }
} }
} }
@@ -133,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::default();
env.seed_rng_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); 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<TestEnv>,
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::default();
env.seed_rng_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); 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 {
@@ -210,67 +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::default();
env.seed_rng_from_u64(u64::arbitrary(unstructured)?);
setup_customization(unstructured, env.customization_mut())?;
let mut state = CtapState::new(&mut env);
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)?),
)
.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::default();
env.seed_rng_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::default(); 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!(assembler.parse_packet(&mut env, packet, None), Ok(None)); assert_eq!(assembler.parse_packet(packet, DUMMY_TIMESTAMP), Ok(None));
} }
message.cmd &= !PACKET_TYPE_MASK;
assert_eq!( assert_eq!(
assembler.parse_packet(&mut env, last_packet, None), 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

@@ -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

@@ -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

@@ -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):
@@ -29,7 +29,7 @@ def make_corpus(corpus_dir, corpus_json):
if os.path.isfile(corpus_json) and \ if os.path.isfile(corpus_json) and \
os.path.splitext(corpus_json)[-1] == ".json": os.path.splitext(corpus_json)[-1] == ".json":
with open(corpus_json, encoding="utf-8") as corpus_file: with open(corpus_json) as corpus_file:
corpus = json.load(corpus_file) corpus = json.load(corpus_file)
else: else:
raise TypeError raise TypeError

View File

@@ -20,4 +20,4 @@ done_text="$(tput bold)DONE.$(tput sgr0)"
set -e set -e
# Install cargo-fuzz library. # Install cargo-fuzz library.
cargo +stable install cargo-fuzz cargo install cargo-fuzz

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