4 Commits

Author SHA1 Message Date
hcyang
81330e5d52 Persist/parse slot_id in/from credential (#569)
* Persist/parse slot_id in/from credential

Persist slot_id into credential_id or the resident credential record
during MakeCredential, and parse it during GetAssertion. Add related
unittests.

* Fix styles

* Move enable_pin_uv back to ctap/mod.rs
2022-11-02 18:08:25 +08:00
hcyang
31774ef316 Add storage test cases for multi-PIN (#567)
* Add storage test cases for multi-PIN

* Fixed proc-macro2 version (#550)

* fixes proc-macro2 in dependencies

* adds missing locked versions, and a verbose print for cargo check

* commits Cargo.lock files

* removes unnecessary Cargo.lock entries

* adds missing Cargo.lock

Co-authored-by: kaczmarczyck <43844792+kaczmarczyck@users.noreply.github.com>
2022-10-26 11:29:56 +08:00
hcyang
1c6c7a4eae Parse slot_id in use from token state (#546)
* Parse slot_id in use from token state

Support switching to multi-PIN feature and making the default slots 8.
But the command to switch to multi-PIN isn't exposed yet because the
implementation isn't ready.

Main change of this commit is to cache the slot_id in use inside token
state, and retrieve it from token state when needed.

* Fix once_cell dependency (#548)

* fixed version of once_cell

* fixes comments

* removes unnecessary fuzz dependency

* Fix styles

Co-authored-by: kaczmarczyck <43844792+kaczmarczyck@users.noreply.github.com>
2022-09-22 14:30:52 +08:00
hcyang
078e565ac1 Add basic setup for multi-PIN (#530)
* Add basic setup for multi-PIN

- Reserve the storage keys for maximum of 8 user slots.
- Modify the storage functions to take a slot_id parameter.
- Add the slot_count() customization.
- Assume slot_id as a parameter when needed except these places:
  - Entrance functions of command processing that directly takes the
    command parameter structure. slot_id is set as 0, and will be
    parsed from the parameters when we enable the feature.
  - MakeCredential/GetAssertion/AuthenticatorConfig will take the
    slot_id from active token state when we enable the feature,
    resulting in an `Option<usize>`. Below code will act on the option
    value correctly. When the feature isn't enabled, we're always
    referring to the only PIN slot so set slot_id as Some(0).
  - GetInfo returns verdict of whether PIN is supported and enabled, and
    whether PIN needs to be forced changed. There will be new fields to
    represent those values when the feature is enabled, and the old
    fields will not be populated. So when the feature isn't enabled, we
    can treat slot_id as 0.

Not covered in this commit:
- Unittests for other slots. The existing tests all pass and I plan to
  add unittests for multi-slot case after the codebase allows enabling
  the feature.
- Persisting and checking the slot_id in credentials. This is planned to
  come in the next commit.

* Fix storage and some other style

* Add support for concatenated values

* Switch some storage entries back to multi-entry

* Set bumpalo version for fuzzing (#532)

* maximum working bumpalo version

* explicit comment to explain version locking

* removes incorrect comment

* moves serde version lock to dev dependencies

* removes serde dependencies

* reverts serde removal in crypto library

* Make PIN_PROPERTIES use concatenated storage entry

* Fix bumpalo issue

* Use concatenated storage entry for force_pin_change too

* Fix cargofmt

Co-authored-by: Julien Cretin <cretin@google.com>
Co-authored-by: kaczmarczyck <43844792+kaczmarczyck@users.noreply.github.com>
2022-08-23 23:01:13 +08:00
244 changed files with 15900 additions and 14133 deletions

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

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

View File

@@ -8,12 +8,16 @@ jobs:
runs-on: ubuntu-latest
if: github.repository == 'google/OpenSK'
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v2
with:
submodules: "true"
- uses: actions/setup-python@v5
- name: Install Rust toolchain
run: rustup show
- uses: actions/setup-python@v1
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
run: ./setup.sh
- uses: actions-rs/audit-check@v1

View File

@@ -6,35 +6,42 @@ jobs:
runs-on: ubuntu-latest
steps:
# Setup
- uses: actions/setup-python@v5
- uses: actions/setup-python@v1
with:
python-version: "3.10"
python-version: 3.7
- name: Install Python dependencies
run: python -m pip install --upgrade pip setuptools wheel
- uses: actions-rs/cargo@v1
with:
command: install
args: cargo-bloat
# First run: PR
- uses: actions/checkout@v4
- uses: actions/checkout@v2
with:
submodules: true
- name: Install Rust toolchain
run: rustup show
- name: Set up OpenSK
run: ./setup.sh
- name: Run bloat on the PR
run: RUSTFLAGS="-C link-arg=-icf=all -C force-frame-pointers=no -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
run: RUSTFLAGS="-C link-arg=-icf=all -C force-frame-pointers=no" cargo bloat --release --target=thumbv7em-none-eabi --features=with_ctap1,vendor_hid --crates >> .github/workflows/bloat_output_new.txt
# Second run: PR
- uses: actions/checkout@v4
- uses: actions/checkout@v2
with:
submodules: true
ref: ${{ github.base_ref }}
path: OpenSK_base
- name: Install old Rust toolchain
working-directory: ./OpenSK_base
run: rustup show
- name: Set up OpenSK
working-directory: ./OpenSK_base
run: ./setup.sh
- name: Run bloat on base
working-directory: ./OpenSK_base
run: RUSTFLAGS="-C link-arg=-icf=all -C force-frame-pointers=no -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"
run: RUSTFLAGS="-C link-arg=-icf=all -C force-frame-pointers=no" cargo bloat --release --target=thumbv7em-none-eabi --features=with_ctap1,vendor_hid --crates >> "$GITHUB_WORKSPACE/.github/workflows/bloat_output_old.txt"
- name: Run output formatter to echo workflow command
run: ./.github/workflows/bloat_formatter.sh bloat_output_new.txt bloat_output_old.txt bloat_comment.md

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

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

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

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

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

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

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

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

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

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

View File

@@ -1,31 +0,0 @@
name: Continuous Integration
on:
push:
branches:
- develop
pull_request:
branches:
- develop
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@v4
- uses: actions/setup-python@v5
with:
python-version: "3.10"
- run: ./setup.sh
- run: ./run_desktop_tests.sh

View File

@@ -1,6 +1,6 @@
name: CIFuzz
on:
push:
pull_request:
branches:
- develop
jobs:
@@ -21,7 +21,7 @@ jobs:
fuzz-seconds: 600
dry-run: false
- name: Upload Crash
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v1
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts

View File

@@ -3,6 +3,7 @@ name: OpenSK code coverage report
on:
push:
paths:
- 'src/**/*.rs'
- 'libraries/**/*.rs'
pull_request:
types: [opened, synchronize, reopened]
@@ -13,35 +14,35 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v2
with:
submodules: "true"
- name: Install Rust toolchain
run: rustup show
- uses: actions/setup-python@v5
- uses: actions/setup-python@v1
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
run: ./setup.sh
- name: Install llvm tools
run: rustup +nightly component add llvm-tools-preview
run: rustup component add llvm-tools-preview
- name: Install grcov
run: if [[ ! -e ~/.cargo/bin/grcov ]]; then cargo +stable install grcov; fi
- uses: actions-rs/cargo@v1
with:
toolchain: nightly
command: test
args: --manifest-path libraries/opensk/Cargo.toml --features "std,with_ctap1,vendor_hid,ed25519" --no-fail-fast
args: --features "with_ctap1,vendor_hid,ed25519,with_nfc,std" --no-fail-fast
env:
RUSTFLAGS: "-Cinstrument-coverage"
RUSTFLAGS: "-Zinstrument-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/*"
run: grcov . --binary-path ./target/debug/ --source-dir . --output-type lcov --ignore-not-existing ---output-path ./lcov.info --ignore "/*" --ignore "examples/*" --ignore "third_party/*"
- uses: coverallsapp/github-action@1.1.3
name: upload report to coveralls
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
path-to-lcov: "./lcov.info"
base-path: "libraries/opensk"

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

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

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-latest
steps:
- uses: actions/checkout@v2
- name: Install ncurses
run: sudo apt-get install libncurses-dev
- name: Check heapviz tool
uses: actions-rs/cargo@v1
with:
command: check
args: --manifest-path tools/heapviz/Cargo.toml
- name: Unit testing of heapviz tool (debug mode)
uses: actions-rs/cargo@v1
with:
command: test
args: --manifest-path tools/heapviz/Cargo.toml
- name: Unit testing of heapviz tool (release mode)
uses: actions-rs/cargo@v1
with:
command: test
args: --manifest-path tools/heapviz/Cargo.toml --release

View File

@@ -12,10 +12,10 @@ jobs:
mdlint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v2
- name: markdownlint-cli
uses: nosborn/github-action-markdown-cli@v3
uses: nosborn/github-action-markdown-cli@v1.1.1
with:
files: '**/*.md'
config_file: '.markdownlint.json'
ignore_files: 'third_party/*'
ignore_files: "third_party/*"
config_file: ".markdownlint.json"

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

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

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

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

View File

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

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-latest
strategy:
matrix:
python-version: [3.6, 3.7, 3.8, 3.9]
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip setuptools wheel
pip install 'tockloader==1.5' pylint
- name: Register matcher
run: echo ::add-matcher::./.github/python_matcher.json
- name: Test code with pylint
run: ./tools/run_pylint.sh
yapf:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python 3.7
uses: actions/setup-python@v1
with:
python-version: 3.7
- name: Install dependencies
run: |
python -m pip install --upgrade pip setuptools wheel
pip install 'yapf>=0.30.0' tockloader
- name: Test code formatting with yapf
run: |
echo ::add-matcher::./.github/python_matcher.json
yapf --style=yapf --recursive --exclude third_party --diff .

View File

@@ -9,18 +9,20 @@ jobs:
check_hashes:
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
os: [ubuntu-latest, macos-10.15]
fail-fast: false
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v2
with:
submodules: "true"
- name: Install Rust toolchain
run: rustup show
- uses: actions/setup-python@v5
- uses: actions/setup-python@v1
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
run: ./setup.sh
@@ -30,7 +32,7 @@ jobs:
run: ./maintainers/reproduce_hashes.sh
- name: Upload reproduced binaries
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v1
with:
name: reproduced-${{ matrix.os }}
path: reproducible/reproduced.tar

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

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

6
.gitignore vendored
View File

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

View File

@@ -1,22 +1,35 @@
{
"default": true,
"MD003": {
"heading-style": {
"style": "atx"
},
"MD007": {
"indent": 4
},
"MD009": {
"no-trailing-spaces": {
"br_spaces": 0,
"strict": true
},
"MD013": {
"ul-indent": {
"indent": 4
},
"line-length": {
"line_length": 80,
"code_blocks": false
},
"MD033": {
"list-marker-space": {
"ol_single": 2,
"ol_multi": 2,
"ul_single": 3,
"ul_multi": 3
},
"no-inline-html": {
"allowed_elements": [
"img"
]
},
"fenced-code-language": true,
"code-block-style": {
"style": "fenced"
},
"code-fence-style": {
"style": "backtick"
}
}

View File

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

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

837
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -5,46 +5,37 @@ authors = [
"Fabian Kaczmarczyck <kaczmarczyck@google.com>",
"Guillaume Endignoux <guillaumee@google.com>",
"Jean-Michel Picod <jmichel@google.com>",
"Julien Cretin <cretin@google.com>",
]
license = "Apache-2.0"
edition = "2018"
[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]
libtock_buttons = { path = "third_party/libtock-rs/apis/buttons" }
libtock_platform = { path = "third_party/libtock-rs/platform" }
libtock_core = { path = "third_party/libtock-rs/core" }
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" }
opensk = { path = "libraries/opensk", default-features = false }
sk-cbor = { path = "libraries/cbor" }
crypto = { path = "libraries/crypto" }
rng256 = { path = "libraries/rng256" }
persistent_store = { path = "libraries/persistent_store" }
libtock_unittest = { path = "third_party/libtock-rs/unittest", optional = true }
byteorder = { version = "1", default-features = false }
arrayref = "0.3.6"
rand_core = "0.6.4"
subtle = { version = "2.2", default-features = false, features = ["nightly"] }
embedded-time = "0.12.1"
arbitrary = { version = "0.4.7", features = ["derive"], optional = true }
rand = { version = "0.8.4", optional = true }
ed25519-compact = { version = "1", default-features = false, optional = true }
[features]
config_command = ["opensk/config_command"]
debug_allocations = ["lang_items/debug_allocations"]
debug_ctap = ["libtock_drivers/debug_ctap", "opensk/debug_ctap"]
debug_ctap = ["libtock_drivers/debug_ctap"]
panic_console = ["lang_items/panic_console"]
std = ["crypto/std", "lang_items/std", "persistent_store/std", "opensk/std", "libtock_unittest"]
std = ["crypto/std", "lang_items/std", "persistent_store/std", "rng256/std", "rand"]
verbose = ["debug_ctap", "libtock_drivers/verbose_usb"]
with_ctap1 = ["opensk/with_ctap1"]
with_ctap1 = ["crypto/with_ctap1"]
with_nfc = ["libtock_drivers/with_nfc"]
vendor_hid = ["opensk/vendor_hid"]
ed25519 = ["ed25519-compact", "opensk/ed25519"]
rust_crypto = ["opensk/rust_crypto"]
vendor_hid = ["libtock_drivers/vendor_hid"]
fuzz = ["arbitrary", "std"]
ed25519 = ["ed25519-compact"]
[dev-dependencies]
enum-iterator = "0.6.0"
@@ -52,7 +43,7 @@ enum-iterator = "0.6.0"
[build-dependencies]
sk-cbor = { path = "libraries/cbor" }
uuid = { version = "0.8", features = ["v4"] }
openssl = "0.10.55"
openssl = "0.10.36"
[profile.dev]
panic = "abort"
@@ -63,8 +54,3 @@ panic = "abort"
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 }

View File

@@ -6,58 +6,46 @@
![Cargo format](https://github.com/google/OpenSK/workflows/Cargo%20format/badge.svg?branch=develop)
[![Coverage Status](https://coveralls.io/repos/github/google/OpenSK/badge.svg?branch=develop)](https://coveralls.io/github/google/OpenSK?branch=develop)
*News:*
- 2023-08-24: [PQC paper reference](#Research)
## OpenSK
This repository contains a Rust implementation of a
[FIDO2](https://fidoalliance.org/fido2/) security key.
Security keys are external devices that can be used for signing in on websites.
You can see OpenSK in action in this
[video on YouTube](https://www.youtube.com/watch?v=klEozvpw0xg)!
[FIDO2](https://fidoalliance.org/fido2/) authenticator.
We developed OpenSK as a [Tock OS](https://tockos.org) application.
We intend to bring a full open source experience to security keys, from
application to operating system. You can even 3D print your own open source
enclosure!
You can see OpenSK in action in this
[video on YouTube](https://www.youtube.com/watch?v=klEozvpw0xg)!
<img src="docs/img/enclosure.jpg" alt="OpenSK Enclosure" width="200"/>
You can run OpenSK as a [Tock OS](https://tockos.org) application, or use the
library to bring OpenSK to your own hardware.
You are viewing the branch for developers. New features are developed here.
Go to the default branch for a more stable version of OpenSK.
You are viewing the branch for developers. New features are developed here
before they are stabilized. If you instead want to use the FIDO certified
firmware, please go back to the
[stable branch](https://github.com/google/OpenSK).
### FIDO2
OpenSK's version that implemented CTAP 2.0 was certified by the FIDO Alliance.
The develop branch tracks the latest release version of the
[CTAP specification](https://fidoalliance.org/specs/fido-v2.2-rd-20230321/fido-client-to-authenticator-protocol-v2.2-rd-20230321.html).
This branch is not FIDO certified.
OpenSK supports U2F, and non-discoverable credentials created with either
protocol are compatible with the other.
The develop branch implements the
[CTAP2.1 specification](https://fidoalliance.org/specs/fido-v2.1-ps-20210615/fido-client-to-authenticator-protocol-v2.1-ps-20210615.html).
This branch is not FIDO certified. The implementation is backwards compatible
to CTAP2.0. Additionally, OpenSK supports U2F, and non-discoverable credentials
created with either protocol are compatible with the other.
### :warning: Disclaimer
This project is **proof-of-concept and a research platform**. It is **NOT**
meant for a daily usage. This branch is under development, and therefore less
rigorously tested than the numbered branches.
meant for a daily usage. It comes with a few limitations:
* This branch is under development, and therefore less rigorously tested than the stable branch.
* The cryptography implementations are not resistent against side-channel attacks.
We're still in the process of integrating the
[ARM&reg; CryptoCell-310](https://developer.arm.com/ip-products/security-ip/cryptocell-300-family)
embedded in the
[Nordic nRF52840 chip](https://infocenter.nordicsemi.com/index.jsp?topic=%2Fps_nrf52840%2Fcryptocell.html)
to enable hardware-accelerated cryptography.
In the meantime, there are 2 options for cryptography implementations:
* Our own placeholder implementation. The code is research quality and doesn't
provide constant-time guarantees.
* The [RustCrypto](https://github.com/RustCrypto) interface. Deploy with
`--rust-crypto`. Note that our own ECC implementation is faster and has
smaller binary size, so not all boards support RustCrypto yet.
to enable hardware-accelerated cryptography. Our placeholder implementations of required
cryptography algorithms (ECDSA, ECC secp256r1, HMAC-SHA256 and AES256) in Rust are research-quality
code. They haven't been reviewed and don't provide constant-time guarantees.
## Hardware
@@ -87,28 +75,6 @@ Please check our [Troubleshooting and Debugging](docs/debugging.md) section if y
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
We implemented post-quantum cryptography on OpenSK. The code is released under
the [hybrid-pqc tag](https://github.com/google/OpenSK/releases/tag/hybrid-pqc).
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>
<summary>Bibtex reference</summary>
```
@InProceedings{Ghinea2023hybrid,
author= {Diana Ghinea and Fabian Kaczmarczyck and Jennifer Pullman and Julien Cretin and Rafael Misoczki and Stefan Kölbl and Luca Invernizzi and Elie Bursztein and Jean-Michel Picod},
title= {{Hybrid Post-Quantum Signatures in Hardware Security Keys}},
booktitle= {{4th ACNS Workshop on Secure Cryptographic Implementation, Kyoto, Japan}},
month= {June},
year= {2023},
}
```
</details>
## Contributing
See [Contributing.md](docs/contributing.md).

View File

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

View File

@@ -7,18 +7,15 @@
// Disable this attribute when documenting, as a workaround for
// https://github.com/rust-lang/rust/issues/62184.
#![cfg_attr(not(doc), no_main)]
#![feature(const_in_array_repeat_expressions)]
#![deny(missing_docs)]
use capsules::virtual_alarm::VirtualMuxAlarm;
use kernel::common::dynamic_deferred_call::{DynamicDeferredCall, DynamicDeferredCallClientState};
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};
@@ -55,43 +52,34 @@ static STRINGS: &'static [&'static str] = &[
"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 {};
const FAULT_RESPONSE: kernel::procs::FaultResponse = kernel::procs::FaultResponse::Panic;
// Number of concurrent processes this platform supports.
const NUM_PROCS: usize = 8;
static mut PROCESSES: [Option<&'static dyn kernel::process::Process>; NUM_PROCS] =
static mut PROCESSES: [Option<&'static dyn kernel::procs::ProcessType>; NUM_PROCS] =
[None; NUM_PROCS];
static mut STORAGE_LOCATIONS: [StorageLocation; 2] = [
static mut STORAGE_LOCATIONS: [kernel::StorageLocation; 2] = [
// We implement NUM_PAGES = 20 as 16 + 4 to satisfy the MPU.
StorageLocation {
kernel::StorageLocation {
address: 0xC0000,
size: 0x10000, // 16 pages
storage_type: StorageType::Store,
storage_type: kernel::StorageType::STORE,
},
StorageLocation {
kernel::StorageLocation {
address: 0xD0000,
size: 0x4000, // 4 pages
storage_type: StorageType::Store,
storage_type: kernel::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]
@@ -103,7 +91,6 @@ 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>,
@@ -111,10 +98,9 @@ pub struct Platform {
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 }>,
ipc: kernel::ipc::IPC<NUM_PROCS>,
analog_comparator: &'static capsules::analog_comparator::AnalogComparator<
'static,
nrf52840::acomp::Comparator<'static>,
@@ -123,20 +109,19 @@ pub struct Platform {
'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>,
>,
crp: &'static capsules::firmware_protection::FirmwareProtection<nrf52840::uicr::Uicr>,
}
impl SyscallDriverLookup for Platform {
impl kernel::Platform for Platform {
fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
where
F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R,
F: FnOnce(Option<&dyn kernel::Driver>) -> R,
{
match driver_num {
capsules::console::DRIVER_NUM => f(Some(self.console)),
@@ -148,88 +133,45 @@ impl SyscallDriverLookup for Platform {
capsules::analog_comparator::DRIVER_NUM => f(Some(self.analog_comparator)),
nrf52840::nvmc::DRIVER_NUM => f(Some(self.nvmc)),
capsules::usb::usb_ctap::DRIVER_NUM => f(Some(self.usb)),
capsules::firmware_protection::DRIVER_NUM => f(Some(self.crp)),
kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)),
_ => f(None),
}
}
}
impl SyscallFilter for Platform {
fn filter_syscall(
&self,
process: &dyn kernel::process::Process,
process: &dyn kernel::procs::ProcessType,
syscall: &kernel::syscall::Syscall,
) -> Result<(), kernel::errorcode::ErrorCode> {
) -> Result<(), kernel::ReturnCode> {
use kernel::syscall::Syscall;
match *syscall {
Syscall::Command {
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)
Err(kernel::ReturnCode::EINVAL)
}
_ => 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 = ();
/// Entry point in the vector table called on hard reset.
#[no_mangle]
pub unsafe fn reset_handler() {
// Loads relocations and clears BSS
nrf52840::init();
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> {
let ppi = static_init!(nrf52840::ppi::Ppi, nrf52840::ppi::Ppi::new());
// Initialize chip peripheral drivers
let nrf52840_peripherals = static_init!(
Nrf52840DefaultPeripherals,
Nrf52840DefaultPeripherals::new()
Nrf52840DefaultPeripherals::new(ppi)
);
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;
@@ -242,7 +184,6 @@ pub unsafe fn main() {
// 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
@@ -278,7 +219,6 @@ pub unsafe fn main() {
let button = components::button::ButtonComponent::new(
board_kernel,
capsules::button::DRIVER_NUM,
components::button_component_helper!(
nrf52840::gpio::GPIOPin,
(
@@ -290,12 +230,15 @@ pub unsafe fn main() {
)
.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>,
LedLow::new(&nrf52840_peripherals.gpio_port[LED1_PIN]),
LedLow::new(&nrf52840_peripherals.gpio_port[LED2_R_PIN]),
LedLow::new(&nrf52840_peripherals.gpio_port[LED2_G_PIN]),
LedLow::new(&nrf52840_peripherals.gpio_port[LED2_B_PIN]),
))
.finalize(components::led_component_buf!(
LedLow<'static, nrf52840::gpio::GPIOPin>
));
let chip = static_init!(
@@ -329,14 +272,10 @@ pub unsafe fn main() {
);
let rtc = &base_peripherals.rtc;
let _ = rtc.start();
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,
)
let alarm = components::alarm::AlarmDriverComponent::new(board_kernel, mux_alarm)
.finalize(components::alarm_component_helper!(nrf52840::rtc::Rtc));
let uart_channel = UartChannel::Pins(UartPins::new(UART_RTS, UART_TXD, UART_CTS, UART_RXD));
let channel = nrf52_components::UartChannelComponent::new(
@@ -354,41 +293,21 @@ pub unsafe fn main() {
);
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>
));
let pconsole =
components::process_console::ProcessConsoleComponent::new(board_kernel, uart_mux)
.finalize(());
// Setup the console.
let console = components::console::ConsoleComponent::new(
board_kernel,
capsules::console::DRIVER_NUM,
uart_mux,
)
.finalize(components::console_component_helper!());
let console = components::console::ConsoleComponent::new(board_kernel, uart_mux).finalize(());
// Create the debugger object that handles calls to `debug!()`.
components::debug_writer::DebugWriterComponent::new(uart_mux).finalize(());
let rng = components::rng::RngComponent::new(
board_kernel,
capsules::rng::DRIVER_NUM,
&base_peripherals.trng,
)
.finalize(());
let rng = components::rng::RngComponent::new(board_kernel, &base_peripherals.trng).finalize(());
// Initialize AC using AIN5 (P0.29) as VIN+ and VIN- as AIN0 (P0.02)
// These are hardcoded pin assignments specified in the driver
@@ -398,8 +317,6 @@ pub unsafe fn main() {
nrf52840::acomp::Channel,
&nrf52840::acomp::CHANNEL_AC0
),
board_kernel,
capsules::analog_comparator::DRIVER_NUM,
)
.finalize(components::acomp_component_buf!(
nrf52840::acomp::Comparator
@@ -409,9 +326,8 @@ pub unsafe fn main() {
nrf52840::nvmc::SyscallDriver,
nrf52840::nvmc::SyscallDriver::new(
&base_peripherals.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(
@@ -423,20 +339,24 @@ pub unsafe fn main() {
// 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));
.finalize(components::usb_ctap_component_buf!(nrf52840::usbd::Usbd));
let crp = components::firmware_protection::FirmwareProtectionComponent::new(
board_kernel,
nrf52840::uicr::Uicr::new(),
)
.finalize(components::firmware_protection_component_helper!(
nrf52840::uicr::Uicr
));
nrf52_components::NrfClockComponent::new(&base_peripherals.clock).finalize(());
let scheduler = components::sched::round_robin::RoundRobinComponent::new(&PROCESSES)
.finalize(components::rr_component_helper!(NUM_PROCS));
let platform = Platform {
button,
pconsole,
@@ -448,20 +368,15 @@ pub unsafe fn main() {
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),
crp,
ipc: kernel::ipc::IPC::new(board_kernel, &memory_allocation_capability),
};
let _ = platform.pconsole.start();
platform.pconsole.start();
debug!("Initialization complete. Entering main loop\r");
debug!("{}", &nrf52840::ficr::FICR_INSTANCE);
// These symbols are defined in the linker script.
/// These symbols are defined in the linker script.
extern "C" {
/// Beginning of the ROM region containing app images.
static _sapps: u8;
@@ -473,7 +388,7 @@ pub unsafe fn main() {
static _eappmem: u8;
}
kernel::process::load_processes(
kernel::procs::load_processes(
board_kernel,
chip,
core::slice::from_raw_parts(
@@ -485,7 +400,7 @@ pub unsafe fn main() {
&_eappmem as *const u8 as usize - &_sappmem as *const u8 as usize,
),
&mut PROCESSES,
&FAULT_RESPONSE,
FAULT_RESPONSE,
&process_management_capability,
)
.unwrap_or_else(|err| {
@@ -493,5 +408,13 @@ pub unsafe fn main() {
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

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

View File

@@ -7,15 +7,13 @@
// Disable this attribute when documenting, as a workaround for
// https://github.com/rust-lang/rust/issues/62184.
#![cfg_attr(not(doc), no_main)]
#![feature(const_in_array_repeat_expressions)]
#![deny(missing_docs)]
use capsules::virtual_alarm::VirtualMuxAlarm;
use kernel::common::dynamic_deferred_call::{DynamicDeferredCall, DynamicDeferredCallClientState};
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;
@@ -48,20 +46,16 @@ static STRINGS: &'static [&'static str] = &[
"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 {};
const FAULT_RESPONSE: kernel::procs::FaultResponse = kernel::procs::FaultResponse::Panic;
// Number of concurrent processes this platform supports.
const NUM_PROCS: usize = 8;
static mut PROCESSES: [Option<&'static dyn kernel::process::Process>; NUM_PROCS] =
static mut PROCESSES: [Option<&'static dyn kernel::procs::ProcessType>; NUM_PROCS] =
[None; NUM_PROCS];
static mut STORAGE_LOCATIONS: [kernel::StorageLocation; 2] = [
@@ -69,20 +63,17 @@ static mut STORAGE_LOCATIONS: [kernel::StorageLocation; 2] = [
kernel::StorageLocation {
address: 0xC0000,
size: 0x10000, // 16 pages
storage_type: kernel::StorageType::Store,
storage_type: kernel::StorageType::STORE,
},
kernel::StorageLocation {
address: 0xD0000,
size: 0x4000, // 4 pages
storage_type: kernel::StorageType::Store,
storage_type: kernel::StorageType::STORE,
},
];
// Static reference to chip for panic dumps
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]
@@ -94,18 +85,16 @@ 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>>,
3,
LedLow<'static, nrf52840::gpio::GPIOPin<'static>>,
>,
rng: &'static capsules::rng::RngDriver<'static>,
ipc: kernel::ipc::IPC<{ NUM_PROCS as u8 }>,
ipc: kernel::ipc::IPC<NUM_PROCS>,
analog_comparator: &'static capsules::analog_comparator::AnalogComparator<
'static,
nrf52840::acomp::Comparator<'static>,
@@ -114,8 +103,6 @@ pub struct Platform {
'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,
@@ -124,10 +111,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
where
F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R,
F: FnOnce(Option<&dyn kernel::Driver>) -> R,
{
match driver_num {
capsules::console::DRIVER_NUM => f(Some(self.console)),
@@ -143,82 +130,39 @@ impl SyscallDriverLookup for Platform {
_ => f(None),
}
}
}
impl SyscallFilter for Platform {
fn filter_syscall(
&self,
process: &dyn kernel::process::Process,
process: &dyn kernel::procs::ProcessType,
syscall: &kernel::syscall::Syscall,
) -> Result<(), kernel::errorcode::ErrorCode> {
) -> Result<(), kernel::ReturnCode> {
use kernel::syscall::Syscall;
match *syscall {
Syscall::Command {
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)
Err(kernel::ReturnCode::EINVAL)
}
_ => 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.
/// Entry point in the vector table called on hard reset.
#[no_mangle]
pub unsafe fn main() {
pub unsafe fn reset_handler() {
// Loads relocations and clears BSS
nrf52840::init();
let ppi = static_init!(nrf52840::ppi::Ppi, nrf52840::ppi::Ppi::new());
// Initialize chip peripheral drivers
let nrf52840_peripherals = get_peripherals();
let nrf52840_peripherals = static_init!(
Nrf52840DefaultPeripherals,
Nrf52840DefaultPeripherals::new(ppi)
);
// set up circular peripheral dependencies
nrf52840_peripherals.init();
@@ -231,7 +175,6 @@ pub unsafe fn main() {
// 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. Right side is used for UART
@@ -246,7 +189,6 @@ pub unsafe fn main() {
let button = components::button::ButtonComponent::new(
board_kernel,
capsules::button::DRIVER_NUM,
components::button_component_helper!(
nrf52840::gpio::GPIOPin,
(
@@ -258,11 +200,14 @@ pub unsafe fn main() {
)
.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>,
LedLow::new(&nrf52840_peripherals.gpio_port[LED1_R_PIN]),
LedLow::new(&nrf52840_peripherals.gpio_port[LED1_G_PIN]),
LedLow::new(&nrf52840_peripherals.gpio_port[LED1_B_PIN]),
))
.finalize(components::led_component_buf!(
LedLow<'static, nrf52840::gpio::GPIOPin>
));
let chip = static_init!(
@@ -288,14 +233,10 @@ pub unsafe fn main() {
);
let rtc = &base_peripherals.rtc;
let _ = rtc.start();
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,
)
let alarm = components::alarm::AlarmDriverComponent::new(board_kernel, mux_alarm)
.finalize(components::alarm_component_helper!(nrf52840::rtc::Rtc));
let uart_channel = UartChannel::Pins(UartPins::new(UART_RTS, UART_TXD, UART_CTS, UART_RXD));
let channel = nrf52_components::UartChannelComponent::new(
@@ -312,40 +253,22 @@ pub unsafe fn main() {
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>
));
let pconsole =
components::process_console::ProcessConsoleComponent::new(board_kernel, uart_mux)
.finalize(());
// Setup the console.
let console = components::console::ConsoleComponent::new(
board_kernel,
capsules::console::DRIVER_NUM,
uart_mux,
)
.finalize(components::console_component_helper!());
let console = components::console::ConsoleComponent::new(board_kernel, uart_mux).finalize(());
// Create the debugger object that handles calls to `debug!()`.
components::debug_writer::DebugWriterComponent::new(uart_mux).finalize(());
let rng = components::rng::RngComponent::new(
board_kernel,
capsules::rng::DRIVER_NUM,
&base_peripherals.trng,
)
.finalize(());
let rng = components::rng::RngComponent::new(board_kernel, &base_peripherals.trng).finalize(());
// Initialize AC using AIN5 (P0.29) as VIN+ and VIN- as AIN0 (P0.02)
// These are hardcoded pin assignments specified in the driver
@@ -355,8 +278,6 @@ pub unsafe fn main() {
nrf52840::acomp::Channel,
&nrf52840::acomp::CHANNEL_AC0
),
board_kernel,
capsules::analog_comparator::DRIVER_NUM,
)
.finalize(components::acomp_component_buf!(
nrf52840::acomp::Comparator
@@ -366,9 +287,8 @@ pub unsafe fn main() {
nrf52840::nvmc::SyscallDriver,
nrf52840::nvmc::SyscallDriver::new(
&base_peripherals.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(
@@ -380,20 +300,16 @@ pub unsafe fn main() {
// 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));
.finalize(components::usb_ctap_component_buf!(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,
@@ -405,20 +321,14 @@ pub unsafe fn main() {
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),
ipc: kernel::ipc::IPC::new(board_kernel, &memory_allocation_capability),
};
let _ = platform.pconsole.start();
platform.pconsole.start();
debug!("Initialization complete. Entering main loop\r");
debug!("{}", &nrf52840::ficr::FICR_INSTANCE);
// These symbols are defined in the linker script.
/// These symbols are defined in the linker script.
extern "C" {
/// Beginning of the ROM region containing app images.
static _sapps: u8;
@@ -430,7 +340,7 @@ pub unsafe fn main() {
static _eappmem: u8;
}
kernel::process::load_processes(
kernel::procs::load_processes(
board_kernel,
chip,
core::slice::from_raw_parts(
@@ -442,7 +352,7 @@ pub unsafe fn main() {
&_eappmem as *const u8 as usize - &_sappmem as *const u8 as usize,
),
&mut PROCESSES,
&FAULT_RESPONSE,
FAULT_RESPONSE,
&process_management_capability,
)
.unwrap_or_else(|err| {
@@ -450,5 +360,13 @@ pub unsafe fn main() {
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

@@ -16,12 +16,12 @@ static mut STORAGE_LOCATIONS: [kernel::StorageLocation; 2] = [
kernel::StorageLocation {
address: 0xC0000,
size: 0x10000, // 16 pages
storage_type: kernel::StorageType::Store,
storage_type: kernel::StorageType::STORE,
},
kernel::StorageLocation {
address: 0xD0000,
size: 0x4000, // 4 pages
storage_type: kernel::StorageType::Store,
storage_type: kernel::StorageType::STORE,
},
];
"

View File

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

View File

@@ -64,16 +64,14 @@
// Disable this attribute when documenting, as a workaround for
// https://github.com/rust-lang/rust/issues/62184.
#![cfg_attr(not(doc), no_main)]
#![feature(const_in_array_repeat_expressions)]
#![deny(missing_docs)]
use capsules::virtual_alarm::VirtualMuxAlarm;
use core::env;
use kernel::common::dynamic_deferred_call::{DynamicDeferredCall, DynamicDeferredCallClientState};
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;
@@ -119,41 +117,32 @@ static STRINGS: &'static [&'static str] = &[
"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 {};
const FAULT_RESPONSE: kernel::procs::FaultResponse = kernel::procs::FaultResponse::Panic;
// Number of concurrent processes this platform supports.
const NUM_PROCS: usize = 8;
static mut PROCESSES: [Option<&'static dyn kernel::process::Process>; NUM_PROCS] =
static mut PROCESSES: [Option<&'static dyn kernel::procs::ProcessType>; NUM_PROCS] =
[None; NUM_PROCS];
include!(concat!(env!("OUT_DIR"), "/locations.rs"));
static mut CHIP: Option<&'static nrf52840::chip::NRF52<Nrf52840DefaultPeripherals>> = None;
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];
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>,
@@ -161,10 +150,9 @@ pub struct Platform {
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 }>,
ipc: kernel::ipc::IPC<NUM_PROCS>,
analog_comparator: &'static capsules::analog_comparator::AnalogComparator<
'static,
nrf52840::acomp::Comparator<'static>,
@@ -179,14 +167,13 @@ pub struct Platform {
'static,
nrf52840::usbd::Usbd<'static>,
>,
scheduler: &'static RoundRobinSched<'static>,
systick: cortexm4::systick::SysTick,
crp: &'static capsules::firmware_protection::FirmwareProtection<nrf52840::uicr::Uicr>,
}
impl SyscallDriverLookup for Platform {
impl kernel::Platform for Platform {
fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
where
F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R,
F: FnOnce(Option<&dyn kernel::Driver>) -> R,
{
match driver_num {
capsules::console::DRIVER_NUM => f(Some(self.console)),
@@ -198,89 +185,44 @@ impl SyscallDriverLookup for Platform {
capsules::analog_comparator::DRIVER_NUM => f(Some(self.analog_comparator)),
nrf52840::nvmc::DRIVER_NUM => f(Some(self.nvmc)),
capsules::usb::usb_ctap::DRIVER_NUM => f(Some(self.usb)),
capsules::firmware_protection::DRIVER_NUM => f(Some(self.crp)),
kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)),
_ => f(None),
}
}
}
impl SyscallFilter for Platform {
fn filter_syscall(
&self,
process: &dyn kernel::process::Process,
process: &dyn kernel::procs::ProcessType,
syscall: &kernel::syscall::Syscall,
) -> Result<(), kernel::errorcode::ErrorCode> {
) -> Result<(), kernel::ReturnCode> {
use kernel::syscall::Syscall;
match *syscall {
Syscall::Command {
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)
Err(kernel::ReturnCode::EINVAL)
}
_ => 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> {
/// Entry point in the vector table called on hard reset.
#[no_mangle]
pub unsafe fn reset_handler() {
// Loads relocations and clears BSS
nrf52840::init();
let ppi = static_init!(nrf52840::ppi::Ppi, nrf52840::ppi::Ppi::new());
// Initialize chip peripheral drivers
let nrf52840_peripherals = static_init!(
Nrf52840DefaultPeripherals,
Nrf52840DefaultPeripherals::new()
Nrf52840DefaultPeripherals::new(ppi)
);
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;
@@ -307,7 +249,6 @@ pub unsafe fn main() {
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],
@@ -332,7 +273,6 @@ pub unsafe fn main() {
let button = components::button::ButtonComponent::new(
board_kernel,
capsules::button::DRIVER_NUM,
components::button_component_helper!(
nrf52840::gpio::GPIOPin,
(
@@ -359,12 +299,15 @@ pub unsafe fn main() {
)
.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>,
LedLow::new(&nrf52840_peripherals.gpio_port[LED1_PIN]),
LedLow::new(&nrf52840_peripherals.gpio_port[LED2_PIN]),
LedLow::new(&nrf52840_peripherals.gpio_port[LED3_PIN]),
LedLow::new(&nrf52840_peripherals.gpio_port[LED4_PIN]),
))
.finalize(components::led_component_buf!(
LedLow<'static, nrf52840::gpio::GPIOPin>
));
let chip = static_init!(
@@ -396,14 +339,10 @@ pub unsafe fn main() {
);
let rtc = &base_peripherals.rtc;
let _ = rtc.start();
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,
)
let alarm = components::alarm::AlarmDriverComponent::new(board_kernel, mux_alarm)
.finalize(components::alarm_component_helper!(nrf52840::rtc::Rtc));
let channel = nrf52_components::UartChannelComponent::new(
@@ -420,41 +359,22 @@ pub unsafe fn main() {
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>
));
let pconsole =
components::process_console::ProcessConsoleComponent::new(board_kernel, uart_mux)
.finalize(());
// Setup the console.
let console = components::console::ConsoleComponent::new(
board_kernel,
capsules::console::DRIVER_NUM,
uart_mux,
)
.finalize(components::console_component_helper!());
let console = components::console::ConsoleComponent::new(board_kernel, uart_mux).finalize(());
// Create the debugger object that handles calls to `debug!()`.
components::debug_writer::DebugWriterComponent::new(uart_mux).finalize(());
let rng = components::rng::RngComponent::new(
board_kernel,
capsules::rng::DRIVER_NUM,
&base_peripherals.trng,
)
.finalize(());
let rng = components::rng::RngComponent::new(board_kernel, &base_peripherals.trng).finalize(());
base_peripherals.spim0.configure(
nrf52840::pinmux::Pinmux::new(SPI_MOSI as u32),
@@ -470,8 +390,6 @@ pub unsafe fn main() {
nrf52840::acomp::Channel,
&nrf52840::acomp::CHANNEL_AC0
),
board_kernel,
capsules::analog_comparator::DRIVER_NUM,
)
.finalize(components::acomp_component_buf!(
nrf52840::acomp::Comparator
@@ -481,9 +399,8 @@ pub unsafe fn main() {
nrf52840::nvmc::SyscallDriver,
nrf52840::nvmc::SyscallDriver::new(
&base_peripherals.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(
@@ -495,17 +412,21 @@ pub unsafe fn main() {
// 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));
.finalize(components::usb_ctap_component_buf!(nrf52840::usbd::Usbd));
let scheduler = components::sched::round_robin::RoundRobinComponent::new(&PROCESSES)
.finalize(components::rr_component_helper!(NUM_PROCS));
let crp = components::firmware_protection::FirmwareProtectionComponent::new(
board_kernel,
nrf52840::uicr::Uicr::new(),
)
.finalize(components::firmware_protection_component_helper!(
nrf52840::uicr::Uicr
));
nrf52_components::NrfClockComponent::new(&base_peripherals.clock).finalize(());
@@ -520,20 +441,15 @@ pub unsafe fn main() {
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),
crp,
ipc: kernel::ipc::IPC::new(board_kernel, &memory_allocation_capability),
};
let _ = platform.pconsole.start();
platform.pconsole.start();
debug!("Initialization complete. Entering main loop\r");
debug!("{}", &nrf52840::ficr::FICR_INSTANCE);
// These symbols are defined in the linker script.
/// These symbols are defined in the linker script.
extern "C" {
/// Beginning of the ROM region containing app images.
static _sapps: u8;
@@ -545,7 +461,7 @@ pub unsafe fn main() {
static _eappmem: u8;
}
kernel::process::load_processes(
kernel::procs::load_processes(
board_kernel,
chip,
core::slice::from_raw_parts(
@@ -557,7 +473,7 @@ pub unsafe fn main() {
&_eappmem as *const u8 as usize - &_sappmem as *const u8 as usize,
),
&mut PROCESSES,
&FAULT_RESPONSE,
FAULT_RESPONSE,
&process_management_capability,
)
.unwrap_or_else(|err| {
@@ -565,5 +481,13 @@ pub unsafe fn main() {
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

@@ -16,28 +16,28 @@ static mut STORAGE_LOCATIONS: [kernel::StorageLocation; 5] = [
kernel::StorageLocation {
address: 0xC0000,
size: 0x10000, // 16 pages
storage_type: kernel::StorageType::Store,
storage_type: kernel::StorageType::STORE,
},
kernel::StorageLocation {
address: 0xD0000,
size: 0x4000, // 4 pages
storage_type: kernel::StorageType::Store,
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,
storage_type: kernel::StorageType::PARTITION,
},
kernel::StorageLocation {
address: 0x80000,
size: 0x20000,
storage_type: kernel::StorageType::Partition,
storage_type: kernel::StorageType::PARTITION,
},
kernel::StorageLocation {
address: 0x5000,
size: 0x1000,
storage_type: kernel::StorageType::METADATA,
},
];
"

View File

@@ -16,28 +16,28 @@ static mut STORAGE_LOCATIONS: [kernel::StorageLocation; 5] = [
kernel::StorageLocation {
address: 0xC0000,
size: 0x10000, // 16 pages
storage_type: kernel::StorageType::Store,
storage_type: kernel::StorageType::STORE,
},
kernel::StorageLocation {
address: 0xD0000,
size: 0x4000, // 4 pages
storage_type: kernel::StorageType::Store,
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,
storage_type: kernel::StorageType::PARTITION,
},
kernel::StorageLocation {
address: 0x40000,
size: 0x20000,
storage_type: kernel::StorageType::Partition,
storage_type: kernel::StorageType::PARTITION,
},
kernel::StorageLocation {
address: 0x4000,
size: 0x1000,
storage_type: kernel::StorageType::METADATA,
},
];
"

56
bootloader/Cargo.lock generated
View File

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

View File

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

View File

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

View File

@@ -26,7 +26,6 @@ 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,

View File

@@ -34,7 +34,6 @@ 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];
@@ -49,19 +48,21 @@ unsafe fn read_page(address: usize) -> Page {
/// Parsed metadata for a firmware partition.
struct Metadata {
checksum: [u8; 32],
_signature: [u8; 64],
version: u64,
timestamp: u32,
address: u32,
}
impl Metadata {
pub const DATA_LEN: usize = 40;
}
/// Reads the metadata from a flash page.
impl From<Page> for Metadata {
fn from(page: Page) -> Self {
Metadata {
checksum: page[0..32].try_into().unwrap(),
_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]),
timestamp: LittleEndian::read_u32(&page[32..36]),
address: LittleEndian::read_u32(&page[36..Metadata::DATA_LEN]),
}
}
}
@@ -75,15 +76,15 @@ struct BootPartition {
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, ()> {
/// Reads the metadata, returns the timestamp if all checks pass.
pub fn read_timestamp(&self) -> Result<u32, ()> {
let metadata_page = unsafe { read_page(self.metadata_address) };
let hash_value = self.compute_upgrade_hash(&metadata_page);
let metadata = Metadata::from(metadata_page);
if self.firmware_address != metadata.address as usize {
#[cfg(debug_assertions)]
rprintln!(
"Partition address mismatch: expected 0x{:08X}, metadata 0x{:08X}",
"Firmware address mismatch: expected 0x{:08X}, metadata 0x{:08X}",
self.firmware_address,
metadata.address as usize
);
@@ -94,7 +95,7 @@ impl BootPartition {
rprintln!("Hash mismatch");
return Err(());
}
Ok(metadata.version)
Ok(metadata.timestamp)
}
/// Computes the SHA256 of metadata information and partition data.
@@ -106,14 +107,11 @@ impl BootPartition {
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.update(&page, false);
}
cc310.update(&metadata_page[32..Metadata::DATA_LEN], true);
cc310.finalize_and_clear()
}
@@ -158,12 +156,12 @@ fn main() -> ! {
};
#[cfg(debug_assertions)]
rprintln!("Reading partition A");
let version_a = partition_a.read_version();
let timestamp_a = partition_a.read_timestamp();
#[cfg(debug_assertions)]
rprintln!("Reading partition B");
let version_b = partition_b.read_version();
let timestamp_b = partition_b.read_timestamp();
match (version_a, version_b) {
match (timestamp_a, timestamp_b) {
(Ok(t1), Ok(t2)) => {
if t1 >= t2 {
partition_a.boot()

View File

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

View File

@@ -15,6 +15,7 @@
extern crate alloc;
use openssl::{bn, ec, nid};
use sk_cbor::cbor_map;
use std::fs::File;
use std::io::{Read, Write};
use std::path::Path;
@@ -24,7 +25,7 @@ use uuid::Uuid;
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={UPGRADE_FILE}");
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");
@@ -33,7 +34,7 @@ fn main() {
let out_dir = env::var_os("OUT_DIR").unwrap();
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 content = String::new();
aaguid_txt_file.read_to_string(&mut content).unwrap();
@@ -51,7 +52,25 @@ fn main() {
.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();
const POINT_LEN: usize = 32;
assert_eq!(raw_bytes.len(), 1 + 2 * POINT_LEN);
assert_eq!(raw_bytes[0], 0x04);
let x_bytes = &raw_bytes[1..][..POINT_LEN];
let y_bytes = &raw_bytes[1 + POINT_LEN..][..POINT_LEN];
const EC2_KEY_TYPE: i64 = 2;
const P_256_CURVE: i64 = 1;
const ES256_ALGORITHM: i64 = -7;
let pub_key_cbor = sk_cbor::cbor_map! {
1 => EC2_KEY_TYPE,
3 => ES256_ALGORITHM,
-1 => P_256_CURVE,
-2 => x_bytes,
-3 => y_bytes,
};
let mut cbor_bytes = vec![];
sk_cbor::writer::write(pub_key_cbor, &mut cbor_bytes).unwrap();
let upgrade_pubkey_path = Path::new(&out_dir).join("opensk_upgrade_pubkey_cbor.bin");
let mut upgrade_pub_bin_file = File::create(&upgrade_pubkey_path).unwrap();
upgrade_pub_bin_file.write_all(&cbor_bytes).unwrap();
}

187
deploy.py
View File

@@ -1,5 +1,5 @@
#!py_virtual_env/bin/python3
# Copyright 2019-2023 Google LLC
#!/usr/bin/env python3
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -23,7 +23,6 @@ import argparse
import collections
import copy
import os
from serial.tools import list_ports
import shutil
import subprocess
import sys
@@ -39,7 +38,7 @@ from tockloader import tockloader as loader
from tockloader.exceptions import TockLoaderException
import tools.configure
from tools.deploy_partition import create_metadata, load_priv_key, pad_to
from tools.deploy_partition import create_metadata, pad_to
PROGRAMMERS = frozenset(("jlink", "openocd", "pyocd", "nordicdfu", "none"))
@@ -159,9 +158,7 @@ SUPPORTED_BOARDS = {
# The following value must match the one used in the file
# `src/entry_point.rs`
APP_HEAP_SIZE = 90_000
CARGO_TARGET_DIR = os.environ.get("CARGO_TARGET_DIR", "target")
APP_HEAP_SIZE = 90000
def get_supported_boards() -> Tuple[str]:
@@ -203,12 +200,6 @@ def assert_python_library(module: str):
f"Try to run: pip3 install {module}"))
def list_serials(vid: int, pid: int) -> List[str]:
ports = list_ports.comports()
ports = filter(lambda p: p.vid == vid and p.pid == pid, ports)
return list(map(lambda p: p.serial_number, ports))
class RemoveConstAction(argparse.Action):
# pylint: disable=redefined-builtin
@@ -263,7 +254,7 @@ class OpenSKInstaller:
def __init__(self, args):
self.args = args
# Where all the TAB files should go
self.tab_folder = os.path.join(CARGO_TARGET_DIR, "tab")
self.tab_folder = os.path.join("target", "tab")
board = SUPPORTED_BOARDS[self.args.board]
self.tockloader_default_args = argparse.Namespace(
app_address=board.app_address,
@@ -329,6 +320,46 @@ class OpenSKInstaller:
# Unreachable because fatal() will exit
return cmd_output.decode()
def update_rustc_if_needed(self):
"""Updates the Rust and installs the necessary target toolchain."""
target_toolchain_fullstring = "stable"
with open("rust-toolchain", "r", encoding="utf-8") as f:
content = f.readlines()
if len(content) == 1:
# Old format, only the build is stored
target_toolchain_fullstring = content[0].strip()
else:
# New format
for line in content:
if line.startswith("channel"):
channel = line.strip().split("=", maxsplit=1)[1].strip()
target_toolchain_fullstring = channel.strip('"')
target_toolchain = target_toolchain_fullstring.split("-", maxsplit=1)
if len(target_toolchain) == 1:
# If we target the stable version of rust, we won't have a date
# associated to the version and split will only return 1 item.
# To avoid failing later when accessing the date, we insert an
# empty value.
target_toolchain.append("")
current_version = self.checked_command_output(["rustc", "--version"])
if not (target_toolchain[0] in current_version and
target_toolchain[1] in current_version):
info(f"Updating rust toolchain to {'-'.join(target_toolchain)}")
# Need to update
rustup_install = ["rustup"]
if self.args.verbose_build:
rustup_install.append("--verbose")
rustup_install.extend(["install", target_toolchain_fullstring])
self.checked_command(rustup_install)
rustup_target = ["rustup"]
if self.args.verbose_build:
rustup_target.append("--verbose")
rustup_target.extend(
["target", "add", SUPPORTED_BOARDS[self.args.board].arch])
self.checked_command(rustup_target)
info("Rust toolchain up-to-date")
def build_tockos(self):
"""Buids Tock OS with the parameters specified in args."""
info(f"Building Tock OS for board {self.args.board}")
@@ -370,8 +401,7 @@ class OpenSKInstaller:
env["RUSTFLAGS"] = " ".join(rust_flags)
cargo_command = ["cargo", "build", "--release", f"--target={props.arch}"]
self.checked_command(cargo_command, cwd="bootloader", env=env)
binary_path = os.path.join(CARGO_TARGET_DIR, props.arch, "release",
"bootloader")
binary_path = os.path.join("target", props.arch, "release", "bootloader")
objcopy_command = [
"llvm-objcopy", "-O", "binary", binary_path, f"{binary_path}.bin"
]
@@ -433,7 +463,7 @@ class OpenSKInstaller:
if self.args.verbose_build:
command.append("--verbose")
self.checked_command(command, env=env)
app_path = os.path.join(CARGO_TARGET_DIR, props.arch, "release")
app_path = os.path.join("target", props.arch, "release")
if is_example:
app_path = os.path.join(app_path, "examples")
app_path = os.path.join(app_path, self.args.application)
@@ -469,16 +499,14 @@ class OpenSKInstaller:
elf2tab_ver = self.checked_command_output(
["elf2tab/bin/elf2tab", "--version"]).split(
"\n", maxsplit=1)[0]
if elf2tab_ver != "elf2tab 0.10.2":
error(("Detected unsupported elf2tab version {elf2tab_ver!a}! The "
"following commands may fail. Please use 0.10.2 instead."))
if elf2tab_ver != "elf2tab 0.7.0":
error(("Detected unsupported elf2tab version {elf2tab_ver!a}. The "
"following commands may fail. Please use 0.7.0 instead."))
os.makedirs(self.tab_folder, exist_ok=True)
tab_filename = os.path.join(self.tab_folder, f"{self.args.application}.tab")
supported_kernel = (2, 1)
elf2tab_args = [
"elf2tab/bin/elf2tab", "--deterministic", "--package-name",
self.args.application, f"--kernel-major={supported_kernel[0]}",
f"--kernel-minor={supported_kernel[1]}", "-o", tab_filename
self.args.application, "-o", tab_filename
]
if self.args.verbose_build:
elf2tab_args.append("--verbose")
@@ -496,11 +524,10 @@ class OpenSKInstaller:
stack_sizes.add(required_stack_size)
if len(stack_sizes) != 1:
error("Detected different stack sizes across tab files.")
# `protected-region-size` must match the `TBF_HEADER_SIZE`
# (currently 0x60 = 96 bytes)
elf2tab_args.extend([
f"--stack={stack_sizes.pop()}", f"--app-heap={APP_HEAP_SIZE}",
"--kernel-heap=1024", "--protected-region-size=96"
"--kernel-heap=1024", "--protected-region-size=64"
])
if self.args.elf2tab_output:
output = self.checked_command_output(elf2tab_args)
@@ -581,7 +608,7 @@ class OpenSKInstaller:
return
kernel = self.read_kernel()
app_tab_path = f"{CARGO_TARGET_DIR}/tab/ctap2.tab"
app_tab_path = "target/tab/ctap2.tab"
if not os.path.exists(app_tab_path):
fatal(f"File not found: {app_tab_path}")
app_tab = tab.TAB(app_tab_path)
@@ -595,9 +622,7 @@ class OpenSKInstaller:
# The kernel is already padded when read.
firmware_image = kernel + pad_to(app, app_size)
priv_key = load_priv_key(self.args.upgrade_priv_key)
metadata = create_metadata(firmware_image, board_props.kernel_address,
self.args.version, priv_key)
metadata = create_metadata(firmware_image, board_props.kernel_address)
if self.args.verbose_build:
info(f"Metadata bytes: {metadata}")
@@ -675,18 +700,17 @@ class OpenSKInstaller:
final_hex.merge(padding_hex, overlap="error")
# Now we can add the application from the TAB file
app_tab_path = f"{CARGO_TARGET_DIR}/tab/{self.args.application}.tab"
app_tab_path = f"target/tab/{self.args.application}.tab"
assert os.path.exists(app_tab_path)
app_tab = tab.TAB(app_tab_path)
if board_props.arch not in app_tab.get_supported_architectures():
fatal(("It seems that the TAB file was not produced for the "
"architecture {board_props.arch}"))
app_hex = intelhex.IntelHex()
tab_bytes = app_tab.extract_app(board_props.arch).get_binary(
board_props.app_address)
if tab_bytes is None:
fatal("The extracted bytes from the TAB file are none")
app_hex.frombytes(tab_bytes, offset=board_props.app_address)
app_hex.frombytes(
app_tab.extract_app(board_props.arch).get_binary(
board_props.app_address),
offset=board_props.app_address)
final_hex.merge(app_hex)
info(f"Generating all-merged HEX file: {dest_file}")
final_hex.tofile(dest_file, format="hex")
@@ -710,14 +734,13 @@ class OpenSKInstaller:
fatal("This board doesn't seem to support flashing through pyocd.")
if self.args.programmer == "nordicdfu":
assert_python_library("intelhex")
assert_mandatory_binary("nrfutil")
nrfutil_version = self.checked_command_output(["nrfutil", "version"])
nrfutil_version = nrfutil_version.removeprefix("nrfutil version ")
assert_python_library("intelhex")
assert_python_library("nordicsemi.lister")
nrfutil_version = __import__("nordicsemi.version").version.NRFUTIL_VERSION
if not nrfutil_version.startswith("6."):
fatal(("You need to install nrfutil python3 package v6.0 or above. "
f"Found: v{nrfutil_version}. If you use Python >= 3.11, please "
"try version 3.10."))
"Found: {nrfutil_version}"))
if not SUPPORTED_BOARDS[self.args.board].nordic_dfu:
fatal("This board doesn't support flashing over DFU.")
@@ -741,6 +764,7 @@ class OpenSKInstaller:
def run(self) -> int:
"""Reads args to decide and run all required tasks."""
self.check_prerequisites()
self.update_rustc_if_needed()
if not (self.args.tockos or self.args.application or
self.args.clear_storage or self.args.configure):
@@ -765,7 +789,6 @@ class OpenSKInstaller:
info("No application selected.")
else:
self.build_example()
self.args.configure = False
# Erase persistent storage
if self.args.clear_storage:
@@ -785,8 +808,7 @@ class OpenSKInstaller:
# Install padding and application if needed
if self.args.application:
self.install_padding()
self.install_tab_file(
f"{CARGO_TARGET_DIR}/tab/{self.args.application}.tab")
self.install_tab_file(f"target/tab/{self.args.application}.tab")
self.install_metadata()
if not self.verify_flashed_app(self.args.application):
error(("It seems that something went wrong. App/example not found "
@@ -795,8 +817,8 @@ class OpenSKInstaller:
return 1
elif self.args.programmer in ("pyocd", "nordicdfu", "none"):
dest_file = f"{CARGO_TARGET_DIR}/{self.args.board}_merged.hex"
os.makedirs(CARGO_TARGET_DIR, exist_ok=True)
dest_file = f"target/{self.args.board}_merged.hex"
os.makedirs("target", exist_ok=True)
self.create_hex_file(dest_file)
if self.args.programmer == "pyocd":
@@ -807,7 +829,7 @@ class OpenSKInstaller:
])
if self.args.programmer == "nordicdfu":
info("Creating DFU package")
dfu_pkg_file = f"{CARGO_TARGET_DIR}/{self.args.board}_dfu.zip"
dfu_pkg_file = f"target/{self.args.board}_dfu.zip"
self.checked_command([
"nrfutil", "pkg", "generate", "--hw-version=52", "--sd-req=0",
"--application-version=1", f"--application={dest_file}",
@@ -819,17 +841,22 @@ class OpenSKInstaller:
info("Press [ENTER] when ready.")
_ = input()
# Search for the DFU devices
serial_numbers = list_serials(0x1915, 0x521F)
if not serial_numbers:
serial_number = []
# pylint: disable=g-import-not-at-top,import-outside-toplevel
from nordicsemi.lister import device_lister
for device in device_lister.DeviceLister().enumerate():
if device.vendor_id == "1915" and device.product_id == "521F":
serial_number.append(device.serial_number)
if not serial_number:
fatal("Couldn't find any DFU device on your system.")
if len(serial_numbers) > 1:
if len(serial_number) > 1:
fatal("Multiple DFU devices are detected. Please only connect one.")
# Run the command without capturing stdout so that we show progress
info("Flashing device using DFU...")
dfu_return_code = subprocess.run(
[
"nrfutil", "dfu", "usb-serial", f"--package={dfu_pkg_file}",
f"--serial-number={serial_numbers[0]}"
f"--serial-number={serial_number[0]}"
],
check=False,
timeout=None,
@@ -854,18 +881,6 @@ class OpenSKInstaller:
self.configure()
return 0
def print_configure_help(self):
vendor_hid = " --vendor-hid" if "vendor_hid" in self.args.features else ""
info("Your device is not yet configured, and lacks some functionality. "
"You can check its configuration status with:\n\n"
f"./tools/configure.py{vendor_hid}\n\n"
"If you run into issues, this command might help:\n\n"
f"./tools/configure.py{vendor_hid} \\\n"
" --certificate=crypto_data/opensk_cert.pem \\\n"
" --private-key=crypto_data/opensk.key\n\n"
"Please read the Certificate considerations in docs/customization.md"
" to understand the privacy trade-off.")
def configure(self):
info("Configuring device.")
# Trying to check or configure the device. Booting might take some time.
@@ -877,7 +892,6 @@ class OpenSKInstaller:
break
if not devices:
self.print_configure_help()
fatal("No device to configure found.")
status = self.configure_device()
if not status:
@@ -886,7 +900,13 @@ class OpenSKInstaller:
if status["cert"] and status["pkey"]:
info("You're all set!")
else:
self.print_configure_help()
info("Your device is not yet configured, and lacks some functionality. "
"If you run into issues, this command might help:\n\n"
"./tools/configure.py \\\n"
" --certificate=crypto_data/opensk_cert.pem \\\n"
" --private-key=crypto_data/opensk.key\n\n"
"Please read the Certificate considerations in docs/customization.md"
" to understand the privacy trade-off.")
return 0
@@ -955,8 +975,7 @@ if __name__ == "__main__":
dest="lock_device",
help=("Try to disable JTAG at the end of the operations. This "
"operation may fail if the device is already locked or if "
"the certificate/private key are not programmed."
"Currently not implemented on nrf52840 and always fails."),
"the certificate/private key are not programmed."),
)
main_parser.add_argument(
"--inject-certificate",
@@ -1052,20 +1071,6 @@ if __name__ == "__main__":
help=("Compiles the OpenSK application without backward compatible "
"support for U2F/CTAP1 protocol."),
)
main_parser.add_argument(
"--no-config-command",
action=RemoveConstAction,
const="config_command",
dest="features",
help=("Removes the AuthenticatorConfig command."),
)
main_parser.add_argument(
"--rust-crypto",
action="append_const",
const="rust_crypto",
dest="features",
help=("Compiles the OpenSK application with RustCrypto implementations."),
)
main_parser.add_argument(
"--nfc",
action="append_const",
@@ -1126,30 +1131,14 @@ if __name__ == "__main__":
help=("Don't check that patches are in sync with their submodules."),
)
main_parser.add_argument(
"--private-key",
type=str,
default="crypto_data/opensk_upgrade.key",
dest="upgrade_priv_key",
help=("PEM file for signing the firmware."),
)
main_parser.add_argument(
"--version",
type=int,
default=-1,
dest="version",
help=("Firmware version that is built."),
)
main_parser.set_defaults(features=["with_ctap1", "config_command"])
main_parser.set_defaults(features=["with_ctap1"])
# Start parsing to know if we're going to list things or not.
partial_args, _ = main_parser.parse_known_args()
# We only need the apps_group if we have a board set
apps_group = main_parser.add_mutually_exclusive_group(
required=partial_args.board is not None)
required=(partial_args.board is not None))
apps_group.add_argument(
"--no-app",
dest="application",

View File

@@ -19,9 +19,6 @@ customize it.
### Flashing using DFU (preferred method)
You need `nrfutil` version 6. The [install manual](../install.md) has
setup instructions.
To flash the firmware, run:
```shell

View File

@@ -19,7 +19,7 @@ After general setup, you still need these steps:
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
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

View File

@@ -55,31 +55,26 @@ 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
./deploy.py --board=nrf52840dk_opensk_a --opensk
./deploy.py --board=nrf52840dk_opensk_b --opensk
```
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
./tools/perform_upgrade.sh nrf52840dk_opensk_b
./tools/perform_upgrade.sh nrf52840dk_opensk_a
```
respectively. You can only upgrade the partition that is not currently running,
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.
so always alternate your calls to `perform_upgrade.sh`. Otherwise, this script
works like `deploy.py`. You can call it even after you locked down your device,
to deploy changes to your development board.
If you want to use Vendor HID, add the `--vendor-hid` flag to all calls,
If you deploy with `--vendor-hid`, also add this flag to `perform_upgrade.sh`,
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
./deploy.py --board=nrf52840dk_opensk_a --opensk --vendor-hid
./tools/perform_upgrade.sh nrf52840dk_opensk_b --vendor-hid
```

View File

@@ -7,18 +7,18 @@
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` | CSR for attestation certificate |
| `opensk_cert.pem` | PEM encoded certificate for the authenticator |
| `opensk.key` | ECC secp256r1 private key for the autenticator |
| `opensk_upgrade.key` | Private key for signing upgrades through CTAP |
| `opensk_upgrade_pub.pem` | Public key for verifying upgrades |
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
@@ -85,7 +85,7 @@ OpenSK is fuzzed with the [OSS-Fuzz](https://github.com/google/oss-fuzz)
project. You can also run fuzzing locally. First install:
```shell
./fuzzing_setup.sh
cargo +stable install cargo-fuzz --version 0.10.2
```
Then choose a fuzz target from `fuzz/fuzz_targets/`, e.g.:

View File

@@ -107,3 +107,31 @@ alloc[256, 1] = 0x2002401c (2 ptrs, 384 bytes)
# 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
```

View File

@@ -25,10 +25,10 @@ following:
* 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
`libssl-dev` and `pkg-config` packages on Debian)
* `nrfutil` (pip package of the same name), if you want to flash
a device with DFU. Read the disclaimer below.
* `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.
* `llvm` 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
@@ -37,17 +37,11 @@ instructions to appropriate binaries for your system.
The scripts provided in this project have been tested under Linux and OS X. We
haven't tested them on Windows and other platforms.
You need `nrfutil` version 6, if you want to flash over DFU.
The tool doesn't support Python newer than 3.10. Therefore, we don't officially
support DFU for other versions. If you want to try regardless,
[Nordic's new tool](https://www.nordicsemi.com/Products/Development-tools/nrf-util)
might work for you.
### Compiling the firmware
If this is your first time installing OpenSK, please skip directly to
[Initial setup](#initial-setup). Else, see
[Updating your setup](#updating-your-setup) below.
[Initial setup](#Initial-setup). Else, see
[Updating your setup](#Updating-your-setup) below.
#### Updating your setup
@@ -62,11 +56,11 @@ following steps:
./setup.sh
```
* Flash your board according to the [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
* 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.
@@ -140,7 +134,7 @@ From here on, please follow the instructions for your hardware:
### Advanced installation
We recommend that you flash your development board with JTAG and dongles with
DFU, as described in the [board documentation](#flashing-a-firmware) linked
DFU, as described in the [board documentation](#Flashing-a-firmware) linked
above. However, we support other programmers:
* OpenOCD: `./deploy.py --board=nrf52840_dongle_opensk --opensk

View File

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

View File

@@ -12,7 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#![no_main]
#![no_std]
extern crate alloc;
@@ -21,72 +20,83 @@ extern crate lang_items;
use alloc::format;
use alloc::vec::Vec;
use core::fmt::Write;
use core::hint::black_box;
use ctap2::env::tock::{TockEnv, TockRng};
use libtock_console::{Console, ConsoleWriter};
use crypto::{aes256, cbc, ecdsa, sha256, Hash256};
use libtock_drivers::console::Console;
use libtock_drivers::result::FlexUnwrap;
use libtock_drivers::timer;
use libtock_drivers::timer::{Timer, Timestamp};
use libtock_runtime::{set_main, stack_size, TockSyscalls};
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};
use rng256::TockRng256;
stack_size! {0x2000}
set_main! {main}
type Syscalls = TockSyscalls;
libtock_core::stack_size! {0x800}
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
// 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 mut rng = TockRng::<Syscalls>::default();
let mut rng = TockRng256 {};
writeln!(console, "****************************************").unwrap();
writeln!(console, "Clock frequency: {:?} Hz", timer.clock_frequency()).unwrap();
writeln!(
console,
"Clock frequency: {} Hz",
timer.clock_frequency().hz()
)
.unwrap();
// AES
bench(&mut console, &timer, "Aes256::new", || {
black_box(AesKey::<TockEnv<Syscalls>>::new(&[0; 32]));
bench(&mut console, &timer, "aes256::EncryptionKey::new", || {
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]);
});
bench(
&mut console,
&timer,
"aes256::EncryptionKey::encrypt_block",
|| {
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..6 {
for i in 0..8 {
blocks.resize(1 << (i + 4), 0);
bench(
&mut console,
&timer,
&format!("Aes256::encrypt_cbc({} bytes)", blocks.len()),
&format!("cbc::cbc_encrypt({} bytes)", blocks.len()),
|| {
aes_key.encrypt_cbc(&[0; 16], &mut blocks);
cbc::cbc_encrypt(&ek, [0; 16], &mut blocks);
},
);
}
drop(blocks);
let mut blocks = Vec::new();
for i in 0..6 {
for i in 0..8 {
blocks.resize(1 << (i + 4), 0);
bench(
&mut console,
&timer,
&format!("Aes256::decrypt_cbc({} bytes)", blocks.len()),
&format!("cbc::cbc_decrypt({} bytes)", blocks.len()),
|| {
aes_key.decrypt_cbc(&[0; 16], &mut blocks);
cbc::cbc_decrypt(&dk, [0; 16], &mut blocks);
},
);
}
@@ -94,37 +104,52 @@ fn main() {
// SHA-256
let mut contents = Vec::new();
for i in 0..6 {
for i in 0..8 {
contents.resize(16 << i, 0);
bench(
&mut console,
&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);
// ECDSA
bench(&mut console, &timer, "Ecdsa::SecretKey::random", || {
EcdsaSk::<TockEnv<Syscalls>>::random(&mut rng);
bench(&mut console, &timer, "ecdsa::SecKey::gensk", || {
ecdsa::SecKey::gensk(&mut rng);
});
let sk = EcdsaSk::<TockEnv<Syscalls>>::random(&mut rng);
bench(&mut console, &timer, "Ecdsa::SecretKey::public_key", || {
black_box(sk.public_key());
});
bench(&mut console, &timer, "Ecdsa::SecretKey::sign", || {
sk.sign(&[]);
let k = ecdsa::SecKey::gensk(&mut rng);
bench(&mut console, &timer, "ecdsa::SecKey::genpk", || {
k.genpk();
});
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, "All the benchmarks are done.\nHave a nice day!").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
F: FnMut(),
{
@@ -133,13 +158,11 @@ where
writeln!(console, "----------------------------------------").unwrap();
let mut count = 1;
for _ in 0..30 {
let start =
Timestamp::<f64>::from_clock_value(timer.get_current_counter_ticks().flex_unwrap());
let start = Timestamp::<f64>::from_clock_value(timer.get_current_clock().flex_unwrap());
for _ in 0..count {
f();
}
let end =
Timestamp::<f64>::from_clock_value(timer.get_current_counter_ticks().flex_unwrap());
let end = Timestamp::<f64>::from_clock_value(timer.get_current_clock().flex_unwrap());
let elapsed = (end - start).ms();
writeln!(
console,
@@ -149,6 +172,7 @@ where
elapsed / (count as f64)
)
.unwrap();
console.flush();
if elapsed > 1000.0 {
break;
}

View File

@@ -12,25 +12,18 @@
// 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::console::Console;
use libtock_drivers::led;
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;
libtock_core::stack_size! {0x800}
fn is_page_erased(storage: &dyn Storage, page: usize) -> bool {
let index = StorageIndex { page, byte: 0 };
@@ -43,21 +36,20 @@ fn is_page_erased(storage: &dyn Storage, page: usize) -> bool {
}
fn main() {
Leds::<Syscalls>::on(1).map_err(|e| e.into()).flex_unwrap(); // red on dongle
let mut storage = take_storage::<Syscalls, DefaultConfig>().unwrap();
led::get(1).flex_unwrap().on().flex_unwrap(); // red on dongle
let mut storage = take_storage().unwrap();
let num_pages = storage.num_pages();
let mut console = Console::<Syscalls>::writer();
writeln!(console, "Erase {} pages of storage:", num_pages).unwrap();
writeln!(Console::new(), "Erase {} pages of storage:", num_pages).unwrap();
for page in 0..num_pages {
write!(console, "- Page {} ", page).unwrap();
write!(Console::new(), "- Page {} ", page).unwrap();
if is_page_erased(&storage, page) {
writeln!(console, "skipped (was already erased).").unwrap();
writeln!(Console::new(), "skipped (was already erased).").unwrap();
} else {
storage.erase_page(page).unwrap();
writeln!(console, "erased.").unwrap();
writeln!(Console::new(), "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
writeln!(Console::new(), "Done.").unwrap();
led::get(1).flex_unwrap().off().flex_unwrap();
led::get(0).flex_unwrap().on().flex_unwrap(); // green on dongle
}

View File

@@ -1,4 +1,3 @@
#![no_main]
#![no_std]
extern crate alloc;
@@ -6,32 +5,27 @@ extern crate lang_items;
extern crate libtock_drivers;
use core::fmt::Write;
use libtock_console::{Console, ConsoleWriter};
use libtock_runtime::{set_main, stack_size, TockSyscalls};
use libtock_drivers::console::Console;
stack_size! {0x4000}
set_main! {main}
type Syscalls = TockSyscalls;
libtock_core::stack_size! {0x4000}
#[cfg(not(feature = "with_nfc"))]
mod example {
use super::{ConsoleWriter, Syscalls, Write};
use super::{Console, Write};
pub fn nfc(console: &mut ConsoleWriter<Syscalls>) {
pub fn nfc(console: &mut Console) {
writeln!(console, "NFC feature flag is missing!").unwrap();
}
}
#[cfg(feature = "with_nfc")]
mod example {
use super::{Console, ConsoleWriter, Write};
use crate::Syscalls;
use super::{Console, Write};
use libtock_core::result::CommandError;
use libtock_drivers::nfc::{NfcTag, RecvOp};
use libtock_drivers::result::{FlexUnwrap, TockError};
use libtock_drivers::timer;
use libtock_drivers::timer::{Timer, Timestamp};
use libtock_platform::{DefaultConfig, ErrorCode};
#[derive(Copy, Clone, Debug, PartialEq)]
#[allow(clippy::upper_case_acronyms)]
@@ -54,15 +48,16 @@ mod example {
ENOSUPPORT,
}
impl From<ErrorCode> for ReturnCode {
fn from(original: ErrorCode) -> ReturnCode {
impl From<isize> for ReturnCode {
fn from(original: isize) -> ReturnCode {
match original {
ErrorCode::Fail => ReturnCode::FAIL,
ErrorCode::Busy => ReturnCode::EBUSY,
ErrorCode::Off => ReturnCode::EOFF,
ErrorCode::Invalid => ReturnCode::EINVAL,
ErrorCode::Cancel => ReturnCode::ECANCEL,
ErrorCode::NoMem => ReturnCode::ENOMEM,
0 => ReturnCode::SUCCESS,
-1 => ReturnCode::FAIL,
-2 => ReturnCode::EBUSY,
-4 => ReturnCode::EOFF,
-6 => ReturnCode::EINVAL,
-8 => ReturnCode::ECANCEL,
-9 => ReturnCode::ENOMEM,
_ => ReturnCode::ENOSUPPORT,
}
}
@@ -71,32 +66,34 @@ mod example {
/// Helper function to write on console the received packet.
fn print_rx_buffer(buf: &mut [u8]) {
if let Some((last, bytes)) = buf.split_last() {
let mut console = Console::<Syscalls>::writer();
let mut console = Console::new();
write!(console, "RX:").unwrap();
for byte in bytes {
write!(console, " {:02x?}", byte).unwrap();
}
writeln!(console, " {:02x?}", last).unwrap();
console.flush();
}
}
/// Function to identify the time elapsed for a transmission request.
fn bench_transmit(
console: &mut ConsoleWriter<Syscalls>,
timer: &Timer<Syscalls>,
console: &mut Console,
timer: &Timer,
title: &str,
buf: &mut [u8],
mut buf: &mut [u8],
) -> ReturnCode {
let amount = buf.len();
let start =
Timestamp::<f64>::from_clock_value(timer.get_current_counter_ticks().flex_unwrap());
match NfcTag::<Syscalls, DefaultConfig>::transmit(buf, amount as u32) {
let start = Timestamp::<f64>::from_clock_value(timer.get_current_clock().flex_unwrap());
match NfcTag::transmit(&mut buf, amount) {
Ok(_) => (),
Err(TockError::Command(ErrorCode::Cancel)) => return ReturnCode::ECANCEL,
Err(_) => writeln!(console, " -- tx error!").unwrap(),
Err(TockError::Command(CommandError {
return_code: -8, /* ECANCEL: No Field*/
..
})) => return ReturnCode::ECANCEL,
Err(_) => writeln!(Console::new(), " -- tx error!").unwrap(),
}
let end =
Timestamp::<f64>::from_clock_value(timer.get_current_counter_ticks().flex_unwrap());
let end = Timestamp::<f64>::from_clock_value(timer.get_current_clock().flex_unwrap());
let elapsed = (end - start).ms();
writeln!(
console,
@@ -107,21 +104,21 @@ mod example {
(amount as f64) / elapsed * 8.
)
.unwrap();
console.flush();
ReturnCode::SUCCESS
}
fn receive_packet(console: &mut ConsoleWriter<Syscalls>, buf: &mut [u8; 256]) -> ReturnCode {
match NfcTag::<Syscalls, DefaultConfig>::receive(buf) {
fn receive_packet(console: &mut Console, mut buf: &mut [u8; 256]) -> ReturnCode {
match NfcTag::receive(&mut buf) {
Ok(RecvOp {
recv_amount: amount,
..
}) => {
if amount <= buf.len() as u32 {
print_rx_buffer(&mut buf[..amount as usize]);
if amount <= buf.len() {
print_rx_buffer(&mut buf[..amount]);
}
}
Err(TockError::Command(code)) => return code.into(),
Err(TockError::Command(CommandError { return_code, .. })) => return return_code.into(),
Err(_) => {
writeln!(console, " -- RX Err").unwrap();
return ReturnCode::ECANCEL;
@@ -130,58 +127,54 @@ mod example {
ReturnCode::SUCCESS
}
fn transmit_reply(
console: &mut ConsoleWriter<Syscalls>,
timer: &Timer<Syscalls>,
buf: &[u8],
) -> ReturnCode {
fn transmit_reply(mut console: &mut Console, timer: &Timer, buf: &[u8]) -> ReturnCode {
let mut return_code = ReturnCode::SUCCESS;
match buf[0] {
0xe0 /* RATS */=> {
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 */ => {
// Ignore the request
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] {
// If the received packet is applet selection command (FIDO 2)
0xa4 /* SELECT */ => if buf[3] == 0x04 && buf[5] == 0x08 && buf[6] == 0xa0 {
// Vesion: "FIDO_2_0"
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)){
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 */ {
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] {
0x02 => {
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 => {
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,];
return_code = bench_transmit(console, timer, "TX: NDEF", &mut reply);
return_code = bench_transmit(&mut console, &timer, "TX: NDEF", &mut reply);
}
0x0f => {
let mut reply = [buf[0], 0x00, 0x0f, 0x20, 0x00, 0x7f, 0x00, 0x7f, 0x04, 0x06, 0xe1, 0x04,
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];
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];
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 */ => {
@@ -192,27 +185,31 @@ mod example {
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
// 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();
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;
loop {
let mut rx_buf = [0; 256];
match receive_packet(console, &mut rx_buf) {
match receive_packet(&mut console, &mut rx_buf) {
ReturnCode::EOFF => {
// Not configured
while !NfcTag::<Syscalls, DefaultConfig>::enable_emulation() {}
while !NfcTag::enable_emulation() {}
// Configure Type 4 tag
while !NfcTag::<Syscalls, DefaultConfig>::configure(4) {}
while !NfcTag::configure(4) {}
}
ReturnCode::ECANCEL /* field lost */ => {
NfcTag::<Syscalls, DefaultConfig>::disable_emulation();
NfcTag::disable_emulation();
}
ReturnCode::EBUSY /* awaiting select*/ => (),
ReturnCode::ENOMEM => {
@@ -223,9 +220,9 @@ mod example {
ReturnCode::ENOSUPPORT => (),
ReturnCode::SUCCESS => {
// 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 => {
if NfcTag::<Syscalls, DefaultConfig>::disable_emulation() {
if NfcTag::disable_emulation() {
writeln!(console, " -- TAG DISABLED").unwrap();
}
state_change_counter += 1;
@@ -242,7 +239,7 @@ mod example {
}
fn main() {
let mut console = Console::<Syscalls>::writer();
let mut console = Console::new();
writeln!(console, "****************************************").unwrap();
writeln!(console, "nfct_test application is installed").unwrap();
example::nfc(&mut console);

View File

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

View File

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

View File

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

794
fuzz/Cargo.lock generated Normal file
View File

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

View File

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

View File

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

View File

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

158
layout.ld Normal file
View File

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

7
libraries/cbor/Cargo.lock generated Normal file
View File

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

View File

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

View File

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

View File

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

37
libraries/cbor/fuzz/Cargo.lock generated Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

503
libraries/crypto/Cargo.lock generated Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -16,20 +16,17 @@ use super::exponent256::ExponentP256;
use super::gfp256::GFP256;
use super::int256::Int256;
use super::montgomery::Montgomery;
#[cfg(feature = "std")]
#[cfg(test)]
use arrayref::array_mut_ref;
#[cfg(feature = "std")]
use arrayref::array_ref;
use core::ops::Add;
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
use zeroize::Zeroize;
/// A point on the elliptic curve, represented by two field elements.
///
/// The "direct" representation with GFP256 (integer modulo p) is used for serialization of public
/// keys.
///
/// Never call zeroize explicitly, to not invalidate any invariants.
#[derive(Clone, Copy, Zeroize)]
// A point on the elliptic curve is represented by two field elements.
// The "direct" representation with GFP256 (integer modulo p) is used for serialization of public
// keys.
#[derive(Clone, Copy)]
pub struct PointP256 {
x: GFP256,
y: GFP256,
@@ -48,6 +45,7 @@ impl PointP256 {
/** Serialization **/
// This uses uncompressed point format from "SEC 1: Elliptic Curve Cryptography" ("Standards for
// Efficient Cryptography").
#[cfg(feature = "std")]
pub fn from_bytes_uncompressed_vartime(bytes: &[u8]) -> Option<PointP256> {
if bytes.len() != 65 || bytes[0] != 0x04 {
None
@@ -59,7 +57,7 @@ impl PointP256 {
}
}
#[cfg(feature = "std")]
#[cfg(test)]
pub fn to_bytes_uncompressed(&self, bytes: &mut [u8; 65]) {
bytes[0] = 0x04;
self.x.to_int().to_bin(array_mut_ref![bytes, 1, 32]);
@@ -132,15 +130,12 @@ impl PointP256 {
}
}
/// A point on the elliptic curve in projective form.
///
/// This uses Montgomery representation for field elements.
/// This is in projective coordinates, i.e. it represents the point { x: x / z, y: y / z }.
/// This representation is more convenient to implement complete formulas for elliptic curve
/// arithmetic.
///
/// Never call zeroize explicitly, to not invalidate any invariants.
#[derive(Clone, Copy, Zeroize)]
// A point on the elliptic curve in projective form.
// This uses Montgomery representation for field elements.
// This is in projective coordinates, i.e. it represents the point { x: x / z, y: y / z }.
// This representation is more convenient to implement complete formulas for elliptic curve
// arithmetic.
#[derive(Clone, Copy)]
pub struct PointProjective {
x: Montgomery,
y: Montgomery,
@@ -157,10 +152,8 @@ impl ConditionallySelectable for PointProjective {
}
}
/// Equivalent to PointProjective { x, y, z: 1 }
///
/// Never call zeroize explicitly, to not invalidate any invariants.
#[derive(Clone, Copy, Zeroize)]
// Equivalent to PointProjective { x, y, z: 1 }
#[derive(Clone, Copy)]
pub struct PointAffine {
x: Montgomery,
y: Montgomery,

View File

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

View File

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

View File

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

View File

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

View File

@@ -27,39 +27,26 @@ pub mod hmac;
pub mod sha256;
pub mod util;
/// Trait for hash functions that returns a 256-bit hash.
///
/// When you implement this trait, make sure to implement `hash_mut` and `hmac_mut` first, because
/// the default implementations of `hash` and `hmac` rely on it.
// Trait for hash functions that returns a 256-bit hash.
// The type must be Sized (size known at compile time) so that we can instanciate one on the stack
// in the hash() method.
pub trait Hash256: Sized {
fn new() -> Self;
fn update(&mut self, contents: &[u8]);
fn finalize(self, output: &mut [u8; 32]);
fn finalize(self) -> [u8; 32];
fn hash(contents: &[u8]) -> [u8; 32] {
let mut output = [0; 32];
Self::hash_mut(contents, &mut output);
output
}
fn hash_mut(contents: &[u8], output: &mut [u8; 32]) {
let mut h = Self::new();
h.update(contents);
h.finalize(output)
h.finalize()
}
fn hmac(key: &[u8; 32], contents: &[u8]) -> [u8; 32] {
let mut output = [0; 32];
Self::hmac_mut(key, contents, &mut output);
output
}
fn hmac_mut(key: &[u8; 32], contents: &[u8], output: &mut [u8; 32]) {
hmac::software_hmac_256::<Self>(key, contents, output);
hmac::software_hmac_256::<Self>(key, contents)
}
}
/// Trait for hash functions that operate on 64-byte input blocks.
// Trait for hash functions that operate on 64-byte input blocks.
pub trait HashBlockSize64Bytes {
type State;

View File

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

View File

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

View File

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

View File

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

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