18 Commits

Author SHA1 Message Date
Fabian Kaczmarczyck
93357524d9 dilithium, hybrid, ctap implementation, experiments 2022-10-20 23:19:15 +02:00
kaczmarczyck
44cafb9566 introduces customization for PIN protcol v1 (#559) 2022-10-13 16:13:07 +02:00
kaczmarczyck
3c28ff49ee Simplifies Env upgrade API (#551)
* removes read_partition and partition_length from upgrade API

* renames partition to bundle, also data type change from slice to Vec

* removes hash from Env API

* fixes comment
2022-10-03 16:33:34 +02:00
kaczmarczyck
6610a29a67 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
2022-09-27 10:12:45 +02:00
kaczmarczyck
f2fac83124 Fix once_cell dependency (#548)
* fixed version of once_cell

* fixes comments

* removes unnecessary fuzz dependency
2022-09-21 19:32:09 +02:00
kaczmarczyck
d6994e3bc3 New Upgrade Interface (#543)
* includes metadata inside partition, introduces the partition helper

* style improvements
2022-09-13 10:06:58 +02:00
kaczmarczyck
8288bb0860 Firmware version for upgrades (#542)
* shows and checks the firmware version

* merges metadata ranges in boards

* simplifies locations loop
2022-09-01 18:28:03 +02:00
kaczmarczyck
771ce7635b moves metadata parsing to Env (#541) 2022-08-31 16:58:49 +02:00
kaczmarczyck
1b360662ee Public Key plain byte encoding (#540)
* public key is encoded in bytes

* ECDSA pubkey in uncompressed format
2022-08-31 15:51:40 +02:00
kaczmarczyck
598c21071e New metadata format (#539)
* new metadata format is used

* Update bootloader/src/main.rs

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

* splits the metadata signed and unsigned parts evenly

* fixes pylint

Co-authored-by: ztoked <zhalvorsen@google.com>
2022-08-31 14:35:45 +02:00
kaczmarczyck
932924ea85 removes metadata storage type (#538) 2022-08-29 12:05:58 +02:00
kaczmarczyck
01cc8333e5 Tool fixes (#537)
* private key type is str, some fixes

* catches file exceptions for private key

* adds exception type

* adds exception message
2022-08-29 11:00:31 +02:00
Julien Cretin
2dc44984ed Merge pull request #534 from ia0/bumpalo
Fix bumpalo issue
2022-08-23 11:11:34 +02:00
Julien Cretin
a44d961e7e Fix bumpalo issue 2022-08-23 10:43:44 +02:00
Julien Cretin
5509e3f072 Merge pull request #531 from ia0/concat
Add support for concatenated values
2022-08-22 17:09:08 +02:00
kaczmarczyck
d2037a4bbe Merge branch 'develop' into concat 2022-08-22 15:55:29 +02:00
kaczmarczyck
6bb12252f8 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
2022-08-22 15:53:50 +02:00
Julien Cretin
e52adf04c7 Add support for concatenated values 2022-08-19 12:47:29 +02:00
88 changed files with 12962 additions and 949 deletions

View File

@@ -94,9 +94,3 @@ jobs:
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

1
.gitignore vendored
View File

@@ -2,7 +2,6 @@ fuzz/artifacts
fuzz/corpus
fuzz/coverage
target/
Cargo.lock
# Local installation of elf2tab.
/elf2tab/

789
Cargo.lock generated Normal file
View File

@@ -0,0 +1,789 @@
# 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",
"ed25519-compact",
"embedded-time",
"enum-iterator",
"lang_items",
"libtock_core",
"libtock_drivers",
"openssl",
"persistent_store",
"rand 0.8.5",
"rng256",
"sk-cbor",
"subtle",
"uuid",
]
[[package]]
name = "derive_arbitrary"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1a012b5e473dc912f0db0546a1c9c6a194ce8494feb66fa0237160926f9e0e6"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "ed25519-compact"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bee9df587982575886a8682edcee11877894349a805f25629c27f63abe3e9ae8"
[[package]]
name = "embedded-time"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7a4b4d10ac48d08bfe3db7688c402baadb244721f30a77ce360bd24c3dffe58"
dependencies = [
"num",
]
[[package]]
name = "enum-iterator"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c79a6321a1197d7730510c7e3f6cb80432dfefecb32426de8cea0aa19b4bb8d7"
dependencies = [
"enum-iterator-derive",
]
[[package]]
name = "enum-iterator-derive"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e94aa31f7c0dc764f57896dc615ddd76fc13b0d5dca7eb6cc5e018a5a09ec06"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[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 = "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 = "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.145"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.145"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c"
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

@@ -20,18 +20,17 @@ persistent_store = { path = "libraries/persistent_store" }
byteorder = { version = "1", default-features = false }
arrayref = "0.3.6"
subtle = { version = "2.2", default-features = false, features = ["nightly"] }
# This import explicitly locks the version.
serde_json = { version = "=1.0.69", default-features = false, features = ["alloc"] }
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 }
dilithium = { path = "third_party/dilithium" }
[features]
debug_allocations = ["lang_items/debug_allocations"]
debug_ctap = ["libtock_drivers/debug_ctap"]
panic_console = ["lang_items/panic_console"]
std = ["crypto/std", "lang_items/std", "persistent_store/std", "rng256/std", "rand"]
std = ["crypto/std", "dilithium/std", "lang_items/std", "persistent_store/std", "rng256/std", "rand"]
verbose = ["debug_ctap", "libtock_drivers/verbose_usb"]
with_ctap1 = ["crypto/with_ctap1"]
with_nfc = ["libtock_drivers/with_nfc"]

162
README.md
View File

@@ -1,84 +1,114 @@
# <img alt="OpenSK logo" src="docs/img/OpenSK.svg" width="200px">
![markdownlint](https://github.com/google/OpenSK/workflows/markdownlint/badge.svg?branch=develop)
![pylint](https://github.com/google/OpenSK/workflows/pylint/badge.svg?branch=develop)
![Cargo check](https://github.com/google/OpenSK/workflows/Cargo%20check/badge.svg?branch=develop)
![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)
## OpenSK
This repository contains a Rust implementation of a
[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)!
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
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. 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. 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.
This is an OpenSK fork that allows signing with a PQC Hybrid scheme. If you are looking for the original documentation, please check the
[develop branch of its GitHub page](https://github.com/google/OpenSK/tree/develop).
## Hardware
You will need one the following supported boards:
* [Nordic nRF52840-DK](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52840-DK)
development kit. This board is more convenient for development and debug
scenarios as the JTAG probe is already on the board.
* [Nordic nRF52840 Dongle](https://www.nordicsemi.com/Software-and-tools/Development-Kits/nRF52840-Dongle)
to have a more practical form factor.
* [Makerdiary nRF52840-MDK USB dongle](https://wiki.makerdiary.com/nrf52840-mdk/).
* [Feitian OpenSK dongle](https://feitiantech.github.io/OpenSK_USB/).
You will need a
[Nordic nRF52840-DK](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52840-DK)
development kit.
## Installation
To install OpenSK,
1. follow the [general setup steps](docs/install.md),
1. then continue with the instructions for your specific hardware:
* [Nordic nRF52840-DK](docs/boards/nrf52840dk.md)
* [Nordic nRF52840 Dongle](docs/boards/nrf52840_dongle.md)
* [Makerdiary nRF52840-MDK USB dongle](docs/boards/nrf52840_mdk.md)
* [Feitian OpenSK dongle](docs/boards/nrf52840_feitian.md)
[Nordic nRF52840-DK](docs/boards/nrf52840dk.md)
To test whether the installation was successful, visit a
[demo website](https://webauthn.io/) and try to register and login.
Please check our [Troubleshooting and Debugging](docs/debugging.md) section if you
have problems with the installation process or during development. To find out what
else you can do with your OpenSK, see [Customization](docs/customization.md).
## PQC Experiments
## Contributing
### Modes
See [Contributing.md](docs/contributing.md).
The Dilithium mode is set at compile time. If you want to perform experiments for different modes,
you will need to recompile. The mode is a feature, defined in
`third_party/dilithium/Cargo.toml`. By default, it is set to
`default = [ "dilithium5", "optimize_stack" ]`. You can change the default mode by either changing
the number 5 to 2 or 3. Or you remove the feature for stack optimizations, e.g.
`default = [ "dilithium2" ]`.
## Reporting a Vulnerability
Note that some benchmarks will not run in all modes without stack optimizations. You can try to
play with the stack size in these cases. As an example, stack painting for speed mode Dilithium2
works if you apply the following changes:
* `APP_HEAP_SIZE = 16384` in `deploy.py`
* `libtock_core::stack_size! {0x1A000}` in `examples/measure_stack.rs`
* `STACK_SIZE = 106496;` in `nrf52840_layout.ld`
* Change the app break from `70 * 1024` to `104 * 1024` in `patches/tock/07-app-break-fix.patch`.
For your convenience, you can also simply try:
```
git apply increase_stack.patch
```
### Compiler flags
To trade binary size for speed, you can play with `[profile.release]` in `Cargo.toml`.
For example, try a different compiler optimization level:
```
opt-level = 3
```
### Debug output
Only the CTAP commands tests are measured end to end on the host. All other experiments are
measured on the embedded device itself and output over RTT. You can either use a client to print
results by running the following commands in different terminals:
```
JLinkExe -device nrf52 -if swd -speed 1000 -autoconnect 1
JLinkRTTClient
```
Or you directly output all messages to a file:
```
JLinkRTTLogger -device NRF52840_XXAA -if swd -speed 1000 -RTTchannel 0
```
### Perform Experiments
The paper contains the following experiments:
#### Crypto benchmarks
Deploy the `crypto_bench` example and read the debug output with one of the methods above:
```
./deploy.py --board=nrf52840dk_opensk --crypto_bench
```
#### CTAP benchmarks
To measure the speed of FIDO commands, run:
```
python benchmarks.py --runs=2000
```
Aggregate results will be printed, and the raw data is written to `make_durations.txt` and
`get_durations.txt`.
#### Stack painting
Deploy the `measure_stack` example and read the debug output with one of the methods above:
```
./deploy.py --board=nrf52840dk_opensk --measure_stack
```
#### x86 benchmarks
You don't need your embedded hardware for those, run:
```
cd third_party/dilithium/
cargo bench --features std
```
See [SECURITY.md](SECURITY.md).

167
benchmarks.py Normal file
View File

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

View File

@@ -69,12 +69,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

@@ -63,12 +63,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

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

@@ -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,
},
kernel::StorageLocation {
address: 0x5000,
size: 0x1000,
storage_type: kernel::StorageType::METADATA,
storage_type: kernel::StorageType::Partition,
},
];
"

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,
},
kernel::StorageLocation {
address: 0x4000,
size: 0x1000,
storage_type: kernel::StorageType::METADATA,
storage_type: kernel::StorageType::Partition,
},
];
"

282
bootloader/Cargo.lock generated Normal file
View File

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

View File

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

View File

@@ -15,7 +15,6 @@
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;
@@ -52,25 +51,7 @@ fn main() {
.public_key()
.to_bytes(&group, conversion_form, &mut ctx)
.unwrap();
const POINT_LEN: usize = 32;
assert_eq!(raw_bytes.len(), 1 + 2 * POINT_LEN);
assert_eq!(raw_bytes[0], 0x04);
let x_bytes = &raw_bytes[1..][..POINT_LEN];
let y_bytes = &raw_bytes[1 + POINT_LEN..][..POINT_LEN];
const EC2_KEY_TYPE: i64 = 2;
const P_256_CURVE: i64 = 1;
const ES256_ALGORITHM: i64 = -7;
let pub_key_cbor = sk_cbor::cbor_map! {
1 => EC2_KEY_TYPE,
3 => ES256_ALGORITHM,
-1 => P_256_CURVE,
-2 => x_bytes,
-3 => y_bytes,
};
let mut cbor_bytes = vec![];
sk_cbor::writer::write(pub_key_cbor, &mut cbor_bytes).unwrap();
let upgrade_pubkey_path = Path::new(&out_dir).join("opensk_upgrade_pubkey_cbor.bin");
let 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(&cbor_bytes).unwrap();
upgrade_pub_bin_file.write_all(&raw_bytes).unwrap();
}

View File

@@ -38,7 +38,7 @@ from tockloader import tockloader as loader
from tockloader.exceptions import TockLoaderException
import tools.configure
from tools.deploy_partition import create_metadata, pad_to
from tools.deploy_partition import create_metadata, load_priv_key, pad_to
PROGRAMMERS = frozenset(("jlink", "openocd", "pyocd", "nordicdfu", "none"))
@@ -156,9 +156,7 @@ SUPPORTED_BOARDS = {
),
}
# The following value must match the one used in the file
# `src/entry_point.rs`
APP_HEAP_SIZE = 90000
APP_HEAP_SIZE = 32768
def get_supported_boards() -> Tuple[str]:
@@ -622,7 +620,9 @@ class OpenSKInstaller:
# The kernel is already padded when read.
firmware_image = kernel + pad_to(app, app_size)
metadata = create_metadata(firmware_image, board_props.kernel_address)
priv_key = load_priv_key(self.args.upgrade_priv_key)
metadata = create_metadata(firmware_image, board_props.kernel_address,
self.args.version, priv_key)
if self.args.verbose_build:
info(f"Metadata bytes: {metadata}")
@@ -1131,6 +1131,22 @@ 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"])
# Start parsing to know if we're going to list things or not.
@@ -1159,6 +1175,12 @@ if __name__ == "__main__":
const="crypto_bench",
help=("Compiles and installs the crypto_bench example that benchmarks "
"the performance of the cryptographic algorithms on the board."))
apps_group.add_argument(
"--measure_stack",
dest="application",
action="store_const",
const="measure_stack",
help=("Measures stack usage of Dilithium."))
apps_group.add_argument(
"--store_latency",
dest="application",

View File

@@ -55,15 +55,15 @@ There are variants of the board that introduce A/B partitions for upgrading the
firmware. You can bootstrap an upgradable board using one of the two commands:
```shell
./deploy.py --board=nrf52840dk_opensk_a --opensk
./deploy.py --board=nrf52840dk_opensk_b --opensk
./deploy.py --board=nrf52840dk_opensk_a --opensk --version=0
./deploy.py --board=nrf52840dk_opensk_b --opensk --version=0
```
Afterwards, you can upgrade the other partition with
```shell
./tools/perform_upgrade.sh nrf52840dk_opensk_b
./tools/perform_upgrade.sh nrf52840dk_opensk_a
./tools/perform_upgrade.sh nrf52840dk_opensk_b --version=1
./tools/perform_upgrade.sh nrf52840dk_opensk_a --version=1
```
respectively. You can only upgrade the partition that is not currently running,
@@ -75,6 +75,6 @@ If you deploy with `--vendor-hid`, also add this flag to `perform_upgrade.sh`,
for example:
```shell
./deploy.py --board=nrf52840dk_opensk_a --opensk --vendor-hid
./tools/perform_upgrade.sh nrf52840dk_opensk_b --vendor-hid
./deploy.py --board=nrf52840dk_opensk_a --opensk --version=0 --vendor-hid
./tools/perform_upgrade.sh nrf52840dk_opensk_b --version=1 --vendor-hid
```

View File

@@ -17,27 +17,42 @@
extern crate alloc;
extern crate lang_items;
use alloc::format;
use alloc::vec::Vec;
use core::fmt::Write;
use crypto::{aes256, cbc, ecdsa, sha256, Hash256};
use crypto::sha256::Sha256;
use crypto::{ecdsa, hybrid};
use libtock_drivers::console::Console;
use libtock_drivers::result::FlexUnwrap;
use libtock_drivers::timer;
use libtock_drivers::timer::{Timer, Timestamp};
use rng256::TockRng256;
use rng256::Rng256;
// use ctap2::env::tock::{take_storage, TockStorage};
// use persistent_store::Store;
libtock_core::stack_size! {0x800}
libtock_core::stack_size! {0x11800}
/*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 {
storage.erase_page(page).unwrap();
}
}
Store::new(storage).ok().unwrap()
}*/
fn main() {
// Fix to be faster.
//let storage = take_storage().unwrap();
//let mut _store = boot_store(storage, true);
let mut console = Console::new();
let mut rng = rng256::TockRng256 {};
// Setup the timer with a dummy callback (we only care about reading the current time, but the
// API forces us to set an alarm callback too).
let mut with_callback = timer::with_callback(|_, _| {});
let timer = with_callback.init().flex_unwrap();
let mut rng = TockRng256 {};
writeln!(console, "****************************************").unwrap();
writeln!(
console,
@@ -46,136 +61,133 @@ fn main() {
)
.unwrap();
// AES
bench(&mut console, &timer, "aes256::EncryptionKey::new", || {
aes256::EncryptionKey::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(
custom_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..8 {
blocks.resize(1 << (i + 4), 0);
bench(
&mut console,
&timer,
&format!("cbc::cbc_encrypt({} bytes)", blocks.len()),
|| {
cbc::cbc_encrypt(&ek, [0; 16], &mut blocks);
},
);
}
drop(blocks);
let mut blocks = Vec::new();
for i in 0..8 {
blocks.resize(1 << (i + 4), 0);
bench(
&mut console,
&timer,
&format!("cbc::cbc_decrypt({} bytes)", blocks.len()),
|| {
cbc::cbc_decrypt(&dk, [0; 16], &mut blocks);
},
);
}
drop(blocks);
// SHA-256
let mut contents = Vec::new();
for i in 0..8 {
contents.resize(16 << i, 0);
bench(
&mut console,
&timer,
&format!("sha256::Sha256::update({} bytes)", contents.len()),
|| {
let mut sha = sha256::Sha256::new();
sha.update(&contents);
sha.finalize();
},
);
}
drop(contents);
// ECDSA
bench(&mut console, &timer, "ecdsa::SecKey::gensk", || {
ecdsa::SecKey::gensk(&mut rng);
});
"ECDSA keygen",
1000,
|| {},
|()| {
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();
custom_bench(
&mut console,
&timer,
"ECDSA sign",
1000,
|| {
let k = ecdsa::SecKey::gensk(&mut rng);
let mut m = [0; 64];
rng.fill_bytes(&mut m);
(k, m)
},
|(k, m)| {
k.sign_rfc6979::<Sha256>(&m);
},
);
custom_bench(
&mut console,
&timer,
"dilithium::SecKey::gensk_with_pk",
1000,
|| {},
|()| {
dilithium::sign::SecKey::gensk_with_pk(&mut rng);
},
);
custom_bench(
&mut console,
&timer,
"dilithium::SecKey::sign",
1000,
|| {
let sk = dilithium::sign::SecKey::gensk(&mut rng);
let mut m = [0; 64];
rng.fill_bytes(&mut m);
(sk, m)
},
|(sk, m)| {
sk.sign(&m);
},
);
custom_bench(
&mut console,
&timer,
"hybrid::SecKey::gensk_with_pk",
1000,
|| {},
|()| {
hybrid::SecKey::gensk_with_pk(&mut rng);
},
);
custom_bench(
&mut console,
&timer,
"hybrid::SecKey::sign",
1000,
|| {
let sk = hybrid::SecKey::gensk(&mut rng);
let mut m = [0; 64];
rng.fill_bytes(&mut m);
(sk, m)
},
|(sk, m)| {
sk.sign_rfc6979::<Sha256>(&m).to_asn1_der();
},
);
}
fn bench<F>(console: &mut Console, timer: &Timer, title: &str, mut f: F)
where
F: FnMut(),
fn custom_bench<I, O, F, S>(
console: &mut Console,
timer: &Timer,
title: &str,
iter_count: usize,
mut setup: S,
mut f: F,
) where
S: FnMut() -> I,
F: FnMut(I) -> O,
{
writeln!(console, "****************************************").unwrap();
writeln!(console, "Benchmarking: {}", title).unwrap();
writeln!(console, "----------------------------------------").unwrap();
let mut count = 1;
for _ in 0..30 {
let mut elapsed = 0.0;
for _ in 1..(iter_count + 1) {
let inputs = setup();
let start = Timestamp::<f64>::from_clock_value(timer.get_current_clock().flex_unwrap());
for _ in 0..count {
f();
}
f(inputs);
let end = Timestamp::<f64>::from_clock_value(timer.get_current_clock().flex_unwrap());
let elapsed = (end - start).ms();
let mut run_duration = (end - start).ms();
// After 512 seconds, we get a negative difference between the start
// time and the end time.
if run_duration < 0.0 {
run_duration += 512.0 * 1000.0;
}
elapsed += run_duration;
writeln!(console, "{},", run_duration).unwrap();
console.flush();
}
writeln!(
console,
"{} ms elapsed for {} iterations ({} ms/iter)",
"Total: {} ms elapsed for {} iterations ({} ms/iter)",
elapsed,
count,
elapsed / (count as f64)
iter_count,
elapsed / (iter_count as f64)
)
.unwrap();
console.flush();
if elapsed > 1000.0 {
break;
}
count <<= 1;
}
}

184
examples/measure_stack.rs Normal file
View File

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

View File

@@ -132,49 +132,49 @@ mod example {
match buf[0] {
0xe0 /* RATS */=> {
let mut answer_to_select = [0x05, 0x78, 0x80, 0xB1, 0x00];
return_code = bench_transmit(&mut console, &timer, "TX: ATS", &mut answer_to_select);
return_code = bench_transmit(&mut console, timer, "TX: ATS", &mut answer_to_select);
}
0xc2 /* DESELECT */ => {
// Ignore the request
let mut command_error = [0x6A, 0x81];
return_code = bench_transmit(&mut 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(&mut 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(&mut 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(&mut 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(&mut 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(&mut 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(&mut 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(&mut 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(&mut console, &timer, "TX: 0x9000", &mut reply);
return_code = bench_transmit(&mut console, timer, "TX: 0x9000", &mut reply);
}
}
0x26 | 0x52 | 0x50 /* REQA | WUPA | Halt */ => {

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

@@ -11,8 +11,6 @@ cargo-fuzz = true
[dependencies]
libfuzzer-sys = { version = "0.3" }
fuzz_helper = { path = "fuzz_helper" }
# This import explicitly locks the version.
serde_json = { version = "=1.0.69" }
# Prevent this from interfering with workspaces
[workspace]

52
increase_stack.patch Normal file
View File

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

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"

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",
]

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

@@ -13,6 +13,7 @@ edition = "2018"
rng256 = { path = "../rng256" }
arrayref = "0.3.6"
subtle = { version = "2.2.3", default-features = false, features = ["nightly"] }
dilithium = { path = "../../third_party/dilithium" }
byteorder = { version = "1", default-features = false }
hex = { version = "0.3.2", default-features = false, optional = true }
ring = { version = "0.16.11", optional = true }

View File

@@ -308,6 +308,11 @@ pub mod test {
}
impl Rng256 for StressTestingRng {
// This function is unused, as we redefine gen_uniform_u32x8.
fn fill_bytes(&mut self, _buf: &mut [u8]) {
unreachable!()
}
// This function is unused, as we redefine gen_uniform_u32x8.
fn gen_uniform_u8x32(&mut self) -> [u8; 32] {
unreachable!()

View File

@@ -16,9 +16,8 @@ use super::exponent256::ExponentP256;
use super::gfp256::GFP256;
use super::int256::Int256;
use super::montgomery::Montgomery;
#[cfg(test)]
use arrayref::array_mut_ref;
#[cfg(feature = "std")]
use arrayref::array_mut_ref;
use arrayref::array_ref;
use core::ops::Add;
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
@@ -26,7 +25,7 @@ use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
// 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)]
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct PointP256 {
x: GFP256,
y: GFP256,
@@ -45,7 +44,6 @@ 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
@@ -57,7 +55,7 @@ impl PointP256 {
}
}
#[cfg(test)]
#[cfg(feature = "std")]
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]);
@@ -550,12 +548,6 @@ impl core::fmt::Debug for PointP256 {
}
}
impl PartialEq for PointP256 {
fn eq(&self, other: &PointP256) -> bool {
self.x == other.x && self.y == other.y
}
}
#[cfg(test)]
pub mod test {
use super::*;

View File

@@ -33,12 +33,13 @@ pub struct SecKey {
k: NonZeroExponentP256,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Signature {
r: NonZeroExponentP256,
s: NonZeroExponentP256,
}
#[derive(Clone)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PubKey {
p: PointP256,
}
@@ -231,13 +232,12 @@ impl PubKey {
.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(test)]
fn to_bytes_uncompressed(&self, bytes: &mut [u8; 65]) {
#[cfg(feature = "std")]
pub fn to_bytes_uncompressed(&self, bytes: &mut [u8; 65]) {
self.p.to_bytes_uncompressed(bytes);
}

View File

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

View File

@@ -1,4 +1,4 @@
// Copyright 2019 Google LLC
// Copyright 2019-2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -16,6 +16,8 @@
#![feature(wrapping_int_impl)]
extern crate alloc;
#[macro_use]
extern crate arrayref;
pub mod aes256;
pub mod cbc;
@@ -24,6 +26,7 @@ pub mod ecdh;
pub mod ecdsa;
pub mod hkdf;
pub mod hmac;
pub mod hybrid;
pub mod sha256;
pub mod util;

100
libraries/persistent_store/Cargo.lock generated Normal file
View File

@@ -0,0 +1,100 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "fastrand"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf"
dependencies = [
"instant",
]
[[package]]
name = "instant"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
dependencies = [
"cfg-if",
]
[[package]]
name = "libc"
version = "0.2.133"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0f80d65747a3e43d1596c7c5492d95d5edddaabd45a7fcdb02b95f644164966"
[[package]]
name = "persistent_store"
version = "0.1.0"
dependencies = [
"tempfile",
]
[[package]]
name = "redox_syscall"
version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42"
dependencies = [
"bitflags",
]
[[package]]
name = "remove_dir_all"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
dependencies = [
"winapi",
]
[[package]]
name = "tempfile"
version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
dependencies = [
"cfg-if",
"fastrand",
"libc",
"redox_syscall",
"remove_dir_all",
"winapi",
]
[[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,4 +1,3 @@
/Cargo.lock
/artifacts/
/corpus/
/target/

126
libraries/persistent_store/fuzz/Cargo.lock generated Normal file
View File

@@ -0,0 +1,126 @@
# 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 = "fuzz-store"
version = "0.0.0"
dependencies = [
"libfuzzer-sys",
"persistent_store",
"rand_core",
"rand_pcg",
"strum",
]
[[package]]
name = "heck"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
dependencies = [
"unicode-segmentation",
]
[[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 = "persistent_store"
version = "0.1.0"
[[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_core"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
[[package]]
name = "rand_pcg"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429"
dependencies = [
"rand_core",
]
[[package]]
name = "strum"
version = "0.19.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b89a286a7e3b5720b9a477b23253bc50debac207c8d21505f8e70b36792f11b5"
dependencies = [
"strum_macros",
]
[[package]]
name = "strum_macros"
version = "0.19.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e61bb0be289045cb80bfce000512e32d09f8337e54c186725da381377ad1f8d5"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn",
]
[[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 = "unicode-segmentation"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a"

View File

@@ -0,0 +1,242 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Support for concatenated entries.
//!
//! This module permits to store multiple indexed values under the same key by concatenation. Such
//! values must be at most 255 bytes and there can't be more than 255 such values under the same
//! key (they are indexed with a `u8`).
//!
//! The rationale for using those particular constraints is that we want the number of bits to store
//! the index and the number of bits to store the length to fit in an integer number of bytes
//! (because the values are an integer number of bytes). Using only one byte is too restrictive
//! (e.g. 8 values of at most 31 bytes or 16 values of at most 15 bytes). Using 2 bytes is plenty of
//! space, so using one byte for each field makes parsing simpler and faster.
//!
//! The format is thus `(index:u8 length:u8 payload:[u8; length])*`. The concatenation is not
//! particularly sorted.
use crate::{Storage, Store, StoreError, StoreResult};
use alloc::vec::Vec;
use core::cmp::Ordering;
use core::ops::Range;
/// Reads a value from a concatenated entry.
pub fn read(store: &Store<impl Storage>, key: usize, index: u8) -> StoreResult<Option<Vec<u8>>> {
let values = match store.find(key)? {
None => return Ok(None),
Some(x) => x,
};
Ok(find(&values, index)?.map(|range| values[range].to_vec()))
}
/// Writes a value to a concatenated entry.
pub fn write(
store: &mut Store<impl Storage>,
key: usize,
index: u8,
value: &[u8],
) -> StoreResult<()> {
if value.len() > 255 {
return Err(StoreError::InvalidArgument);
}
let mut values = store.find(key)?.unwrap_or(vec![]);
match find(&values, index)? {
None => {
values.push(index);
values.push(value.len() as u8);
values.extend_from_slice(value);
}
Some(mut range) => {
values[range.start - 1] = value.len() as u8;
match range.len().cmp(&value.len()) {
Ordering::Less => {
let diff = value.len() - range.len();
values.resize(values.len() + diff, 0);
values[range.end..].rotate_right(diff);
range.end += diff;
}
Ordering::Equal => (),
Ordering::Greater => {
let diff = range.len() - value.len();
range.end -= diff;
values[range.end..].rotate_left(diff);
values.truncate(values.len() - diff);
}
}
values[range].copy_from_slice(value);
}
}
store.insert(key, &values)
}
/// Deletes the value from a concatenated entry.
pub fn delete(store: &mut Store<impl Storage>, key: usize, index: u8) -> StoreResult<()> {
let mut values = match store.find(key)? {
None => return Ok(()),
Some(x) => x,
};
let mut range = match find(&values, index)? {
None => return Ok(()),
Some(x) => x,
};
range.start -= 2;
values[range.start..].rotate_left(range.len());
values.truncate(values.len() - range.len());
store.insert(key, &values)
}
fn find(values: &[u8], index: u8) -> StoreResult<Option<Range<usize>>> {
let mut pos = 0;
while pos < values.len() {
if pos == values.len() - 1 {
return Err(StoreError::InvalidStorage);
}
let len = values[pos + 1] as usize;
if len > values.len() - 2 || pos > values.len() - 2 - len {
return Err(StoreError::InvalidStorage);
}
if index == values[pos] {
return Ok(Some(pos + 2..pos + 2 + len));
}
pos += 2 + len;
}
Ok(None)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test::MINIMAL;
#[test]
fn read_empty_entry() {
let store = MINIMAL.new_store();
assert_eq!(read(&store, 0, 0), Ok(None));
assert_eq!(read(&store, 0, 1), Ok(None));
}
#[test]
fn read_missing_value() {
let mut store = MINIMAL.new_store();
let value = b"\x00\x03foo\x02\x05hello".to_vec();
store.insert(0, &value).unwrap();
assert_eq!(read(&store, 0, 1), Ok(None));
}
#[test]
fn read_existing_value() {
let mut store = MINIMAL.new_store();
let value = b"\x00\x03foo\x02\x05hello".to_vec();
store.insert(0, &value).unwrap();
assert_eq!(read(&store, 0, 0), Ok(Some(b"foo".to_vec())));
assert_eq!(read(&store, 0, 2), Ok(Some(b"hello".to_vec())));
}
#[test]
fn read_invalid_entry_too_long() {
let mut store = MINIMAL.new_store();
let value = b"\x00\x03foo\x02\x08hello".to_vec();
store.insert(0, &value).unwrap();
assert_eq!(read(&store, 0, 1), Err(StoreError::InvalidStorage));
}
#[test]
fn read_invalid_entry_too_short() {
let mut store = MINIMAL.new_store();
let value = b"\x00\x03foo\x02".to_vec();
store.insert(0, &value).unwrap();
assert_eq!(read(&store, 0, 1), Err(StoreError::InvalidStorage));
}
#[test]
fn write_empty_entry() {
let mut store = MINIMAL.new_store();
assert_eq!(write(&mut store, 0, 0, b"foo"), Ok(()));
assert_eq!(store.find(0), Ok(Some(b"\x00\x03foo".to_vec())));
}
#[test]
fn write_missing_value() {
let mut store = MINIMAL.new_store();
let value = b"\x00\x03foo".to_vec();
store.insert(0, &value).unwrap();
assert_eq!(write(&mut store, 0, 1, b"bar"), Ok(()));
assert_eq!(store.find(0), Ok(Some(b"\x00\x03foo\x01\x03bar".to_vec())));
}
#[test]
fn write_existing_value_same_size() {
let mut store = MINIMAL.new_store();
let value = b"\x00\x03foo\x02\x05hello".to_vec();
store.insert(0, &value).unwrap();
assert_eq!(write(&mut store, 0, 0, b"bar"), Ok(()));
assert_eq!(
store.find(0),
Ok(Some(b"\x00\x03bar\x02\x05hello".to_vec()))
);
}
#[test]
fn write_existing_value_longer() {
let mut store = MINIMAL.new_store();
let value = b"\x00\x03foo\x02\x05hello".to_vec();
store.insert(0, &value).unwrap();
assert_eq!(write(&mut store, 0, 0, b"barrage"), Ok(()));
assert_eq!(
store.find(0),
Ok(Some(b"\x00\x07barrage\x02\x05hello".to_vec()))
);
}
#[test]
fn write_existing_value_shorter() {
let mut store = MINIMAL.new_store();
let value = b"\x00\x08football\x02\x05hello".to_vec();
store.insert(0, &value).unwrap();
assert_eq!(write(&mut store, 0, 0, b"bar"), Ok(()));
assert_eq!(
store.find(0),
Ok(Some(b"\x00\x03bar\x02\x05hello".to_vec()))
);
}
#[test]
fn delete_empty_entry() {
let mut store = MINIMAL.new_store();
assert_eq!(delete(&mut store, 0, 0), Ok(()));
assert_eq!(delete(&mut store, 0, 1), Ok(()));
}
#[test]
fn delete_missing_value() {
let mut store = MINIMAL.new_store();
let value = b"\x00\x03foo\x02\x05hello".to_vec();
store.insert(0, &value).unwrap();
assert_eq!(delete(&mut store, 0, 1), Ok(()));
assert_eq!(
store.find(0),
Ok(Some(b"\x00\x03foo\x02\x05hello".to_vec()))
);
}
#[test]
fn delete_existing_value() {
let mut store = MINIMAL.new_store();
let value = b"\x00\x03foo\x02\x05hello".to_vec();
store.insert(0, &value).unwrap();
assert_eq!(delete(&mut store, 0, 0), Ok(()));
assert_eq!(store.find(0), Ok(Some(b"\x02\x05hello".to_vec())));
}
}

View File

@@ -363,6 +363,7 @@ extern crate alloc;
#[cfg(feature = "std")]
mod buffer;
pub mod concat;
#[cfg(feature = "std")]
mod driver;
#[cfg(feature = "std")]

255
libraries/rng256/Cargo.lock generated Normal file
View File

@@ -0,0 +1,255 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[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 = "cloudabi"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
dependencies = [
"bitflags",
]
[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
[[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 = "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 = "rng256"
version = "0.1.0"
dependencies = [
"arrayref",
"libtock_drivers",
"rand",
]
[[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 = "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

@@ -21,6 +21,8 @@ use rand::Rng;
// Lightweight RNG trait to generate uniformly distributed 256 bits.
pub trait Rng256 {
fn fill_bytes(&mut self, buf: &mut [u8]);
fn gen_uniform_u8x32(&mut self) -> [u8; 32];
fn gen_uniform_u32x8(&mut self) -> [u32; 8] {
@@ -45,6 +47,10 @@ fn bytes_to_u32(bytes: [u8; 32]) -> [u32; 8] {
pub struct TockRng256 {}
impl Rng256 for TockRng256 {
fn fill_bytes(&mut self, buf: &mut [u8]) {
libtock_drivers::rng::fill_buffer(buf);
}
fn gen_uniform_u8x32(&mut self) -> [u8; 32] {
let mut buf: [u8; 32] = [Default::default(); 32];
rng::fill_buffer(&mut buf);
@@ -58,6 +64,11 @@ pub struct ThreadRng256 {}
#[cfg(feature = "std")]
impl Rng256 for ThreadRng256 {
fn fill_bytes(&mut self, buf: &mut [u8]) {
let mut rng = rand::thread_rng();
rng.fill(buf);
}
fn gen_uniform_u8x32(&mut self) -> [u8; 32] {
let mut rng = rand::thread_rng();
let mut result = [Default::default(); 32];

View File

@@ -14,7 +14,7 @@ MEMORY {
* Any change to STACK_SIZE should be accompanied by a corresponding change to
* `elf2tab`'s `--stack` option
*/
STACK_SIZE = 16384;
STACK_SIZE = 71680;
MPU_MIN_ALIGN = 8K;

View File

@@ -0,0 +1,13 @@
diff --git a/rust-toolchain b/rust-toolchain
index 1674405..2ba073e 100644
--- a/rust-toolchain
+++ b/rust-toolchain
@@ -1,7 +1,7 @@
[toolchain]
# See https://rust-lang.github.io/rustup-components-history/ for a list of
# recently nightlies and what components are available for them.
-channel = "nightly-2021-03-25"
+channel = "nightly-2021-06-25"
components = ["clippy", "miri", "rustfmt"]
targets = ["thumbv7em-none-eabi",
"riscv32imac-unknown-none-elf",

View File

@@ -31,19 +31,18 @@ index 5465c95f4..e596648f7 100644
}
}
diff --git a/kernel/src/sched.rs b/kernel/src/sched.rs
index 8844bc6c3..692bad2d3 100644
index 8844bc6c3..00c13a7c6 100644
--- a/kernel/src/sched.rs
+++ b/kernel/src/sched.rs
@@ -118,10 +118,19 @@ pub enum SchedulingDecision {
@@ -118,10 +118,18 @@ pub enum SchedulingDecision {
TrySleep,
}
+/// Represents the type of a storage slice.
+#[derive(Copy, Clone)]
+pub enum StorageType {
+ STORE = 1,
+ PARTITION = 2,
+ METADATA = 3,
+ Store = 1,
+ Partition = 2,
+}
+
/// Represents a storage location in flash.

View File

@@ -7,7 +7,7 @@ index c78b1c9fb..2769d0138 100644
// The 1.x Tock kernel allocates at least 3 kB to processes, and we need
// to ensure that happens as userspace may expect it.
- 3 * 1024
+ 16 * 1024
+ 70 * 1024
// TOCK 2.0
//

View File

@@ -156,7 +156,7 @@ index f7899d8c5..6956523c6 100644
hil::usb::CtrlSetupResult::ErrGeneric
}
diff --git a/capsules/src/usb/usbc_ctap_hid.rs b/capsules/src/usb/usbc_ctap_hid.rs
index 642039120..adb7fde14 100644
index 642039120..abf224f97 100644
--- a/capsules/src/usb/usbc_ctap_hid.rs
+++ b/capsules/src/usb/usbc_ctap_hid.rs
@@ -44,21 +44,59 @@ static CTAP_REPORT_DESCRIPTOR: &'static [u8] = &[

View File

@@ -262,7 +262,7 @@ index da3d16d85..e8f1a87a4 100644
if !app.waiting {
// The call to receive_packet() collected a pending packet.
diff --git a/capsules/src/usb/usbc_ctap_hid.rs b/capsules/src/usb/usbc_ctap_hid.rs
index adb7fde14..f6762b4b9 100644
index abf224f97..d47e5f644 100644
--- a/capsules/src/usb/usbc_ctap_hid.rs
+++ b/capsules/src/usb/usbc_ctap_hid.rs
@@ -11,6 +11,7 @@ use super::descriptors::HIDSubordinateDescriptor;

View File

@@ -0,0 +1,13 @@
diff --git a/boards/nordic/nrf52840dk_opensk/src/main.rs b/boards/nordic/nrf52840dk_opensk/src/main.rs
index 83fd0bbab..53d623b46 100644
--- a/boards/nordic/nrf52840dk_opensk/src/main.rs
+++ b/boards/nordic/nrf52840dk_opensk/src/main.rs
@@ -147,7 +147,7 @@ static mut CHIP: Option<&'static nrf52840::chip::NRF52<Nrf52840DefaultPeripheral
/// Dummy buffer that causes the linker to reserve enough space for the stack.
#[no_mangle]
#[link_section = ".stack_buffer"]
-pub static mut STACK_MEMORY: [u8; 0x1000] = [0; 0x1000];
+pub static mut STACK_MEMORY: [u8; 0x2000] = [0; 0x2000];
/// Supported drivers by the platform
pub struct Platform {

View File

@@ -108,7 +108,7 @@ index e8f1a87a4..2c91c0968 100644
} else {
// Cannot cancel now because the transaction is already in process.
diff --git a/capsules/src/usb/usbc_ctap_hid.rs b/capsules/src/usb/usbc_ctap_hid.rs
index f6762b4b9..16b80cb10 100644
index d47e5f644..76f6af73b 100644
--- a/capsules/src/usb/usbc_ctap_hid.rs
+++ b/capsules/src/usb/usbc_ctap_hid.rs
@@ -18,13 +18,27 @@ use core::cell::Cell;

68
plot_data.py Normal file
View File

@@ -0,0 +1,68 @@
#!/usr/bin/env python3
# Copyright 2022 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Lint as: python3
"""Hacky script to read RTT output from crypto_bench and plot it."""
import matplotlib.pyplot as plt
import numpy as np
def read_file(filename):
with open(filename, "r", encoding="utf-8") as f:
lines = f.readlines()
return [float(l[:-2]) for l in lines]
def below_threshold(data, threshold=10.):
a = np.array(data)
return np.mean(a / 1000. < threshold)
def percentiles(data):
s = sorted(data)
l = len(s)
for i in range(10):
print(f"{i * 10}th percentile: {s[(i * l) // 10]}")
def show_plot(data, title):
threshold_ratio = below_threshold(data)
if threshold_ratio < 0.9999:
max_range = min(max(data), 2 * 10. * 1000)
hist_range = (0, max_range)
else:
hist_range = None
plt.hist(data, bins=50, range=hist_range, label="Timing distribution")
mean = np.mean(data)
plt.axvline(x=mean, color="g", label="Mean")
if threshold_ratio < 0.9999:
plt.axvline(x=10. * 1000, color="r", label="CTAP threshold")
plt.title(title)
plt.legend()
plt.savefig(title.replace(" ", "") + "_plot.png")
plt.show()
def run(filename, title):
data = read_file(filename)
print(title, "below 10s:", below_threshold(data))
print("Mean:", np.mean(data))
percentiles(data)
show_plot(data, title)
run("make_durations.txt", "MakeCredential")
run("get_durations.txt", "GetAssertion")

View File

@@ -26,6 +26,12 @@ pub trait Customization {
// Constants for adjusting privacy and protection levels.
// ###########################################################################
/// Removes support for PIN protocol v1.
///
/// We support PIN protocol v2, "intended to aid FIPS certification".
/// To certify, you might want to remove support for v1 using this customization.
fn allows_pin_protocol_v1(&self) -> bool;
/// Changes the default level for the credProtect extension.
///
/// You can change this value to one of the following for more privacy:
@@ -245,6 +251,7 @@ pub trait Customization {
#[derive(Clone)]
pub struct CustomizationImpl {
pub allows_pin_protocol_v1: bool,
pub default_cred_protect: Option<CredentialProtectionPolicy>,
pub default_min_pin_length: u8,
pub default_min_pin_length_rp_ids: &'static [&'static str],
@@ -263,6 +270,7 @@ pub struct CustomizationImpl {
}
pub const DEFAULT_CUSTOMIZATION: CustomizationImpl = CustomizationImpl {
allows_pin_protocol_v1: true,
default_cred_protect: None,
default_min_pin_length: 4,
default_min_pin_length_rp_ids: &[],
@@ -281,6 +289,10 @@ pub const DEFAULT_CUSTOMIZATION: CustomizationImpl = CustomizationImpl {
};
impl Customization for CustomizationImpl {
fn allows_pin_protocol_v1(&self) -> bool {
self.allows_pin_protocol_v1
}
fn default_cred_protect(&self) -> Option<CredentialProtectionPolicy> {
self.default_cred_protect
}

View File

@@ -15,6 +15,7 @@
// For compiling with std outside of tests.
#![cfg_attr(feature = "std", allow(dead_code))]
use alloc::vec::Vec;
use core::iter::Iterator;
use persistent_store::{StorageError, StorageResult};
@@ -55,6 +56,7 @@ pub fn is_aligned(block_size: usize, address: usize) -> bool {
///
/// The range is treated as the interval `[start, start + length)`.
/// All objects with length of 0, regardless of the start value, are considered empty.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ModRange {
start: usize,
length: usize,
@@ -86,25 +88,45 @@ impl ModRange {
self.length == 0
}
/// Returns the disjoint union with the other range, if is consecutive.
/// Returns the disjoint union with the other range, if consecutive.
///
/// Appending empty ranges is not possible.
/// Appending to the empty range returns the other range.
pub fn append(&self, other: ModRange) -> Option<ModRange> {
///
/// Returns true if successful.
pub fn append(&mut self, other: &ModRange) -> bool {
if self.is_empty() {
return Some(other);
self.start = other.start;
self.length = other.length;
return true;
}
if other.is_empty() {
return None;
return false;
}
if self.start >= other.start {
return None;
return false;
}
if self.length != other.start - self.start {
return None;
return false;
}
let new_length = self.length.checked_add(other.length);
new_length.map(|l| ModRange::new(self.start, l))
if let Some(new_length) = self.length.checked_add(other.length) {
self.length = new_length;
true
} else {
false
}
}
/// Helper function to check whether a range starts within another.
fn starts_inside(&self, range: &ModRange) -> bool {
!range.is_empty() && self.start >= range.start && self.start - range.start < range.length
}
/// Returns whether the given range has intersects.
///
/// Mathematically, we calculate whether: `self ∩ range ≠ ∅`.
pub fn intersects_range(&self, range: &ModRange) -> bool {
self.starts_inside(range) || range.starts_inside(self)
}
/// Returns whether the given range is fully contained.
@@ -128,6 +150,73 @@ impl ModRange {
}
}
pub struct Partition {
ranges: Vec<ModRange>,
}
impl Partition {
pub fn new() -> Partition {
Partition { ranges: Vec::new() }
}
/// Total length of all ranges.
pub fn length(&self) -> usize {
self.ranges.iter().map(|r| r.length()).sum()
}
/// Appends the given range.
///
/// Ranges should be appending with ascending start addresses.
pub fn append(&mut self, range: ModRange) -> bool {
if let Some(last_range) = self.ranges.last_mut() {
if range.start() <= last_range.start()
|| range.start() - last_range.start() < last_range.length()
{
return false;
}
if !last_range.append(&range) {
self.ranges.push(range);
}
} else {
self.ranges.push(range);
}
true
}
/// Returns the start address that corresponds to the given offset.
///
/// If the offset bigger than the accumulated length or the requested slice doesn't fit a
/// connected component, return `None`.
pub fn find_address(&self, mut offset: usize, length: usize) -> Option<usize> {
for range in &self.ranges {
if offset < range.length() {
return if range.length() - offset >= length {
Some(range.start() + offset)
} else {
None
};
}
offset -= range.length()
}
None
}
pub fn ranges_from(&self, start_address: usize) -> Vec<ModRange> {
let mut result = Vec::new();
for range in &self.ranges {
match start_address.checked_sub(range.start()) {
None | Some(0) => result.push(range.clone()),
Some(offset) => {
if range.length() > offset {
result.push(ModRange::new(start_address, range.length() - offset));
}
}
}
}
result
}
}
#[cfg(test)]
mod tests {
use super::*;
@@ -186,18 +275,17 @@ mod tests {
#[test]
fn mod_range_append() {
let range = ModRange::new(200, 100);
let new_range = range.append(ModRange::new(300, 400)).unwrap();
assert!(new_range.start() == 200);
assert!(new_range.length() == 500);
assert!(range.append(ModRange::new(299, 400)).is_none());
assert!(range.append(ModRange::new(301, 400)).is_none());
assert!(range.append(ModRange::new(200, 400)).is_none());
let empty_append = ModRange::new_empty()
.append(ModRange::new(200, 100))
.unwrap();
assert!(empty_append.start() == 200);
assert!(empty_append.length() == 100);
let mut range = ModRange::new(200, 100);
assert!(range.append(&ModRange::new(300, 400)));
assert!(range.start() == 200);
assert!(range.length() == 500);
assert!(!range.append(&ModRange::new(499, 400)));
assert!(!range.append(&ModRange::new(501, 400)));
assert!(!range.append(&ModRange::new(300, 400)));
let mut range = ModRange::new_empty();
assert!(range.append(&ModRange::new(200, 100)));
assert!(range.start() == 200);
assert!(range.length() == 100);
}
#[test]
@@ -216,6 +304,20 @@ mod tests {
assert!(ModRange::new(usize::MAX, 2).contains_range(&ModRange::new(usize::MAX, 2)));
}
#[test]
fn mod_range_intersects_range() {
let range = ModRange::new(200, 100);
assert!(range.intersects_range(&ModRange::new(200, 1)));
assert!(range.intersects_range(&ModRange::new(299, 1)));
assert!(!range.intersects_range(&ModRange::new(199, 1)));
assert!(!range.intersects_range(&ModRange::new(300, 1)));
assert!(!ModRange::new_empty().intersects_range(&ModRange::new_empty()));
assert!(!ModRange::new_empty().intersects_range(&ModRange::new(200, 100)));
assert!(!ModRange::new(200, 100).intersects_range(&ModRange::new_empty()));
assert!(ModRange::new(usize::MAX, 1).intersects_range(&ModRange::new(usize::MAX, 1)));
assert!(ModRange::new(usize::MAX, 2).intersects_range(&ModRange::new(usize::MAX, 2)));
}
#[test]
fn mod_range_aligned_iter() {
let mut iter = ModRange::new(200, 100).aligned_iter(100);
@@ -234,4 +336,49 @@ mod tests {
assert_eq!(iter.next(), Some(0xffff_ffff_ffff_fff0));
assert_eq!(iter.next(), None);
}
#[test]
fn partition_append() {
let mut partition = Partition::new();
partition.append(ModRange::new(0x4000, 0x1000));
partition.append(ModRange::new(0x20000, 0x20000));
partition.append(ModRange::new(0x40000, 0x20000));
assert_eq!(partition.find_address(0, 1), Some(0x4000));
assert_eq!(partition.length(), 0x41000);
}
#[test]
fn partition_find_address() {
let mut partition = Partition::new();
partition.append(ModRange::new(0x4000, 0x1000));
partition.append(ModRange::new(0x20000, 0x20000));
partition.append(ModRange::new(0x40000, 0x20000));
assert_eq!(partition.find_address(0, 0x1000), Some(0x4000));
assert_eq!(partition.find_address(0x1000, 0x1000), Some(0x20000));
assert_eq!(partition.find_address(0x20000, 0x1000), Some(0x3F000));
assert_eq!(partition.find_address(0x21000, 0x1000), Some(0x40000));
assert_eq!(partition.find_address(0x40000, 0x1000), Some(0x5F000));
assert_eq!(partition.find_address(0x41000, 0x1000), None);
assert_eq!(partition.find_address(0x40000, 0x2000), None);
}
#[test]
fn partition_ranges_from() {
let mut partition = Partition::new();
partition.append(ModRange::new(0x4000, 0x1000));
partition.append(ModRange::new(0x20000, 0x20000));
partition.append(ModRange::new(0x40000, 0x20000));
let all_ranges = partition.ranges_from(0);
let from_start_ranges = partition.ranges_from(0x4000);
assert_eq!(&all_ranges, &from_start_ranges);
assert_eq!(all_ranges.len(), 2);
assert_eq!(all_ranges[0], ModRange::new(0x4000, 0x1000));
assert_eq!(all_ranges[1], ModRange::new(0x20000, 0x40000));
let second_range = partition.ranges_from(0x20000);
let same_second_range = partition.ranges_from(0x1F000);
assert_eq!(&second_range, &same_second_range);
assert_eq!(&second_range, &all_ranges[1..]);
let partial_range = partition.ranges_from(0x30000);
assert_eq!(partial_range[0], ModRange::new(0x30000, 0x30000));
}
}

View File

@@ -1,4 +1,4 @@
// Copyright 2021 Google LLC
// Copyright 2021-2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -12,45 +12,28 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use alloc::vec::Vec;
use persistent_store::StorageResult;
pub(crate) mod helper;
/// Accessors to storage locations used for upgrading from a CTAP command.
pub trait UpgradeStorage {
/// Reads a slice of the partition, if within bounds.
/// Processes the given data as part of an upgrade.
///
/// The offset is relative to the start of the partition.
/// The offset indicates the data location inside the bundle.
///
/// # Errors
///
/// Returns [`StorageError::OutOfBounds`] if the requested slice is not inside the partition.
fn read_partition(&self, offset: usize, length: usize) -> StorageResult<&[u8]>;
/// - Returns [`StorageError::OutOfBounds`] if the data does not fit.
/// - Returns [`StorageError::CustomError`] if any Metadata or other check fails.
fn write_bundle(&mut self, offset: usize, data: Vec<u8>) -> StorageResult<()>;
/// Writes the given data to the given offset address, if within bounds of the partition.
/// Returns an identifier for the requested bundle.
///
/// The offset is relative to the start of the partition.
///
/// # Errors
///
/// Returns [`StorageError::OutOfBounds`] if the data does not fit the partition.
fn write_partition(&mut self, offset: usize, data: &[u8]) -> StorageResult<()>;
/// Use this to determine whether you are writing to A or B.
fn bundle_identifier(&self) -> u32;
/// Returns the address of the partition.
fn partition_address(&self) -> usize;
/// Returns the length of the partition.
fn partition_length(&self) -> usize;
/// Reads the metadata location.
fn read_metadata(&self) -> StorageResult<&[u8]>;
/// Writes the given data into the metadata location.
///
/// The passed in data is appended with 0xFF bytes if shorter than the metadata storage.
///
/// # Errors
///
/// Returns [`StorageError::OutOfBounds`] if the data is too long to fit the metadata storage.
fn write_metadata(&mut self, data: &[u8]) -> StorageResult<()>;
/// Returns the currently running firmware version.
fn running_firmware_version(&self) -> u64;
}

View File

@@ -21,6 +21,7 @@ use super::pin_protocol::{verify_pin_uv_auth_token, PinProtocol, SharedSecret};
use super::response::{AuthenticatorClientPinResponse, ResponseData};
use super::status_code::Ctap2StatusCode;
use super::token_state::PinUvAuthTokenState;
use crate::api::customization::Customization;
use crate::ctap::storage;
use crate::env::Env;
use alloc::boxed::Box;
@@ -390,6 +391,11 @@ impl ClientPin {
client_pin_params: AuthenticatorClientPinParameters,
now: CtapInstant,
) -> Result<ResponseData, Ctap2StatusCode> {
if !env.customization().allows_pin_protocol_v1()
&& client_pin_params.pin_uv_auth_protocol == PinUvAuthProtocol::V1
{
return Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER);
}
let response = match client_pin_params.sub_command {
ClientPinSubCommand::GetPinRetries => Some(self.process_get_pin_retries(env)?),
ClientPinSubCommand::GetKeyAgreement => {
@@ -872,6 +878,20 @@ mod test {
test_helper_process_get_key_agreement(PinUvAuthProtocol::V2);
}
#[test]
fn test_process_get_key_agreement_v1_not_allowed() {
let (mut client_pin, params) = create_client_pin_and_parameters(
PinUvAuthProtocol::V1,
ClientPinSubCommand::GetKeyAgreement,
);
let mut env = TestEnv::new();
env.customization_mut().set_allows_pin_protocol_v1(false);
assert_eq!(
client_pin.process_command(&mut env, params, CtapInstant::new(0)),
Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER)
);
}
fn test_helper_process_set_pin(pin_uv_auth_protocol: PinUvAuthProtocol) {
let (mut client_pin, params) =
create_client_pin_and_parameters(pin_uv_auth_protocol, ClientPinSubCommand::SetPin);

View File

@@ -15,11 +15,10 @@
use super::data_formats::{
extract_array, extract_bool, extract_byte_string, extract_map, extract_text_string,
extract_unsigned, ok_or_missing, ClientPinSubCommand, ConfigSubCommand, ConfigSubCommandParams,
CoseKey, CoseSignature, CredentialManagementSubCommand,
CredentialManagementSubCommandParameters, GetAssertionExtensions, GetAssertionOptions,
MakeCredentialExtensions, MakeCredentialOptions, PinUvAuthProtocol,
PublicKeyCredentialDescriptor, PublicKeyCredentialParameter, PublicKeyCredentialRpEntity,
PublicKeyCredentialUserEntity, SetMinPinLengthParams,
CoseKey, CredentialManagementSubCommand, CredentialManagementSubCommandParameters,
GetAssertionExtensions, GetAssertionOptions, MakeCredentialExtensions, MakeCredentialOptions,
PinUvAuthProtocol, PublicKeyCredentialDescriptor, PublicKeyCredentialParameter,
PublicKeyCredentialRpEntity, PublicKeyCredentialUserEntity, SetMinPinLengthParams,
};
use super::status_code::Ctap2StatusCode;
use super::{cbor_read, key_material};
@@ -593,10 +592,9 @@ impl TryFrom<cbor::Value> for AuthenticatorVendorConfigureParameters {
#[derive(Debug, PartialEq, Eq)]
pub struct AuthenticatorVendorUpgradeParameters {
pub address: Option<usize>,
pub offset: usize,
pub data: Vec<u8>,
pub hash: Vec<u8>,
pub signature: Option<CoseSignature>,
pub hash: [u8; 32],
}
impl TryFrom<cbor::Value> for AuthenticatorVendorUpgradeParameters {
@@ -605,25 +603,16 @@ impl TryFrom<cbor::Value> for AuthenticatorVendorUpgradeParameters {
fn try_from(cbor_value: cbor::Value) -> Result<Self, Ctap2StatusCode> {
destructure_cbor_map! {
let {
0x01 => address,
0x01 => offset,
0x02 => data,
0x03 => hash,
0x04 => signature,
} = extract_map(cbor_value)?;
}
let address = address
.map(extract_unsigned)
.transpose()?
.map(|u| u as usize);
let offset = extract_unsigned(ok_or_missing(offset)?)? as usize;
let data = extract_byte_string(ok_or_missing(data)?)?;
let hash = extract_byte_string(ok_or_missing(hash)?)?;
let signature = signature.map(CoseSignature::try_from).transpose()?;
Ok(AuthenticatorVendorUpgradeParameters {
address,
data,
hash,
signature,
})
let hash = <[u8; 32]>::try_from(extract_byte_string(ok_or_missing(hash)?)?)
.map_err(|_| Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER)?;
Ok(AuthenticatorVendorUpgradeParameters { offset, data, hash })
}
}
@@ -631,7 +620,7 @@ impl TryFrom<cbor::Value> for AuthenticatorVendorUpgradeParameters {
mod test {
use super::super::data_formats::{
AuthenticatorTransport, PublicKeyCredentialRpEntity, PublicKeyCredentialType,
PublicKeyCredentialUserEntity, SignatureAlgorithm,
PublicKeyCredentialUserEntity,
};
use super::super::ES256_CRED_PARAM;
use super::*;
@@ -1072,6 +1061,16 @@ mod test {
let command = Command::deserialize(&cbor_bytes);
assert_eq!(command, Err(Ctap2StatusCode::CTAP2_ERR_INVALID_CBOR));
// Missing offset
let cbor_value = cbor_map! {
0x02 => [0xFF; 0x100],
0x03 => [0x44; 32],
};
assert_eq!(
AuthenticatorVendorUpgradeParameters::try_from(cbor_value),
Err(Ctap2StatusCode::CTAP2_ERR_MISSING_PARAMETER)
);
// Missing data
let cbor_value = cbor_map! {
0x01 => 0x1000,
@@ -1082,6 +1081,17 @@ mod test {
Err(Ctap2StatusCode::CTAP2_ERR_MISSING_PARAMETER)
);
// Invalid hash size
let cbor_value = cbor_map! {
0x01 => 0x1000,
0x02 => [0xFF; 0x100],
0x03 => [0x44; 33],
};
assert_eq!(
AuthenticatorVendorUpgradeParameters::try_from(cbor_value),
Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER)
);
// Missing hash
let cbor_value = cbor_map! {
0x01 => 0x1000,
@@ -1092,29 +1102,7 @@ mod test {
Err(Ctap2StatusCode::CTAP2_ERR_MISSING_PARAMETER)
);
// Valid without address
let cbor_value = cbor_map! {
0x02 => [0xFF; 0x100],
0x03 => [0x44; 32],
0x04 => cbor_map! {
"alg" => -7,
"signature" => [0x55; 64],
},
};
assert_eq!(
AuthenticatorVendorUpgradeParameters::try_from(cbor_value),
Ok(AuthenticatorVendorUpgradeParameters {
address: None,
data: vec![0xFF; 0x100],
hash: vec![0x44; 32],
signature: Some(CoseSignature {
algorithm: SignatureAlgorithm::Es256,
bytes: [0x55; 64],
}),
})
);
// Valid without signature
// Valid
let cbor_value = cbor_map! {
0x01 => 0x1000,
0x02 => [0xFF; 0x100],
@@ -1123,10 +1111,9 @@ mod test {
assert_eq!(
AuthenticatorVendorUpgradeParameters::try_from(cbor_value),
Ok(AuthenticatorVendorUpgradeParameters {
address: Some(0x1000),
offset: 0x1000,
data: vec![0xFF; 0x100],
hash: vec![0x44; 32],
signature: None,
hash: [0x44; 32],
})
);
}

View File

@@ -20,8 +20,8 @@ use alloc::vec;
use alloc::vec::Vec;
use core::convert::TryFrom;
use crypto::cbc::{cbc_decrypt, cbc_encrypt};
use crypto::ecdsa;
use crypto::sha256::Sha256;
use crypto::{ecdsa, hybrid};
use rng256::Rng256;
use sk_cbor as cbor;
use sk_cbor::{cbor_array, cbor_bytes, cbor_int};
@@ -82,6 +82,7 @@ pub enum PrivateKey {
Ecdsa([u8; 32]),
#[cfg(feature = "ed25519")]
Ed25519(ed25519_compact::SecretKey),
Hybrid(hybrid::SecKey),
}
impl PrivateKey {
@@ -100,6 +101,34 @@ impl PrivateKey {
let bytes = env.rng().gen_uniform_u8x32();
Self::new_ed25519_from_bytes(&bytes).unwrap()
}
SignatureAlgorithm::Hybrid => PrivateKey::Hybrid(hybrid::SecKey::gensk(env.rng())),
SignatureAlgorithm::Unknown => unreachable!(),
}
}
/// Creates a new private / public key pair for the given algorithm.
///
/// # Panics
///
/// Panics if the algorithm is [`SignatureAlgorithm::Unknown`].
pub fn new_with_pub_key(env: &mut impl Env, alg: SignatureAlgorithm) -> (Self, CoseKey) {
match alg {
SignatureAlgorithm::Es256 => {
let private_key = PrivateKey::Ecdsa(env.key_store().generate_ecdsa_seed().unwrap());
let pub_key = private_key.get_pub_key(env).unwrap();
(private_key, pub_key)
}
#[cfg(feature = "ed25519")]
SignatureAlgorithm::Eddsa => {
let bytes = env.rng().gen_uniform_u8x32();
let private_key = Self::new_ed25519_from_bytes(&bytes).unwrap();
let pub_key = private_key.get_pub_key(env).unwrap();
(private_key, pub_key)
}
SignatureAlgorithm::Hybrid => {
let (hybrid_key, pub_key) = hybrid::SecKey::gensk_with_pk(env.rng());
(PrivateKey::Hybrid(hybrid_key), CoseKey::from(pub_key))
}
SignatureAlgorithm::Unknown => unreachable!(),
}
}
@@ -137,6 +166,15 @@ impl PrivateKey {
}
}
/// Helper function that creates a private key of type Hybrid.
fn new_hybrid_from_bytes(bytes: &[u8]) -> Option<Self> {
if bytes.len() != hybrid::SecKey::BYTES_LENGTH {
return None;
}
hybrid::SecKey::from_bytes(array_ref!(bytes, 0, hybrid::SecKey::BYTES_LENGTH))
.map(PrivateKey::from)
}
/// Returns the corresponding public key.
pub fn get_pub_key(&self, env: &mut impl Env) -> Result<CoseKey, Ctap2StatusCode> {
Ok(match self {
@@ -145,6 +183,7 @@ impl PrivateKey {
}
#[cfg(feature = "ed25519")]
PrivateKey::Ed25519(ed25519_key) => CoseKey::from(ed25519_key.public_key()),
PrivateKey::Hybrid(hybrid_key) => CoseKey::from(hybrid_key.genpk()),
})
}
@@ -160,6 +199,9 @@ impl PrivateKey {
.to_asn1_der(),
#[cfg(feature = "ed25519")]
PrivateKey::Ed25519(ed25519_key) => ed25519_key.sign(message, None).to_vec(),
PrivateKey::Hybrid(hybrid_key) => {
hybrid_key.sign_rfc6979::<Sha256>(message).to_asn1_der()
}
})
}
@@ -169,6 +211,7 @@ impl PrivateKey {
PrivateKey::Ecdsa(_) => SignatureAlgorithm::Es256,
#[cfg(feature = "ed25519")]
PrivateKey::Ed25519(_) => SignatureAlgorithm::Eddsa,
PrivateKey::Hybrid(_) => SignatureAlgorithm::Hybrid,
}
}
@@ -178,6 +221,11 @@ impl PrivateKey {
PrivateKey::Ecdsa(ecdsa_seed) => ecdsa_seed.to_vec(),
#[cfg(feature = "ed25519")]
PrivateKey::Ed25519(ed25519_key) => ed25519_key.seed().to_vec(),
PrivateKey::Hybrid(hybrid_key) => {
let mut key_bytes = vec![0u8; hybrid::SecKey::BYTES_LENGTH];
hybrid_key.to_bytes(array_mut_ref!(key_bytes, 0, hybrid::SecKey::BYTES_LENGTH));
key_bytes
}
}
}
}
@@ -214,11 +262,19 @@ impl TryFrom<cbor::Value> for PrivateKey {
#[cfg(feature = "ed25519")]
SignatureAlgorithm::Eddsa => PrivateKey::new_ed25519_from_bytes(&key_bytes)
.ok_or(Ctap2StatusCode::CTAP2_ERR_INVALID_CBOR),
SignatureAlgorithm::Hybrid => PrivateKey::new_hybrid_from_bytes(&key_bytes)
.ok_or(Ctap2StatusCode::CTAP2_ERR_INVALID_CBOR),
_ => Err(Ctap2StatusCode::CTAP2_ERR_INVALID_CBOR),
}
}
}
impl From<hybrid::SecKey> for PrivateKey {
fn from(hybrid_key: hybrid::SecKey) -> Self {
PrivateKey::Hybrid(hybrid_key)
}
}
#[cfg(test)]
mod test {
use super::*;

View File

@@ -15,21 +15,26 @@
use super::crypto_wrapper::PrivateKey;
use super::status_code::Ctap2StatusCode;
use alloc::string::String;
use alloc::vec;
use alloc::vec::Vec;
#[cfg(feature = "fuzz")]
use arbitrary::Arbitrary;
use arrayref::array_ref;
use core::convert::TryFrom;
use crypto::{ecdh, ecdsa};
use crypto::{ecdh, ecdsa, hybrid};
#[cfg(test)]
use enum_iterator::IntoEnumIterator;
use sk_cbor as cbor;
use sk_cbor::{cbor_array_vec, cbor_map, cbor_map_options, destructure_cbor_map};
use sk_cbor::{cbor_array_vec, cbor_bytes, cbor_map_options, destructure_cbor_map};
use {dilithium, sk_cbor as cbor};
// Used as the identifier for ECDSA in assertion signatures and COSE.
pub const ES256_ALGORITHM: i64 = -7;
#[cfg(feature = "ed25519")]
pub const EDDSA_ALGORITHM: i64 = -8;
// Used as the identifier for Hybrid in assertion signatures.
// (numbers less than -65536 are reserved for private use)
// TODO: Update this number later.
pub const HYBRID_ALGORITHM: i64 = -65537;
// https://www.w3.org/TR/webauthn/#dictdef-publickeycredentialrpentity
#[derive(Clone, Debug, PartialEq, Eq)]
@@ -510,6 +515,7 @@ pub enum SignatureAlgorithm {
Es256 = ES256_ALGORITHM as isize,
#[cfg(feature = "ed25519")]
Eddsa = EDDSA_ALGORITHM as isize,
Hybrid = HYBRID_ALGORITHM as isize,
// This is the default for all numbers not covered above.
// Unknown types should be ignored, instead of returning errors.
Unknown = 0,
@@ -527,6 +533,7 @@ impl From<i64> for SignatureAlgorithm {
ES256_ALGORITHM => SignatureAlgorithm::Es256,
#[cfg(feature = "ed25519")]
EDDSA_ALGORITHM => SignatureAlgorithm::Eddsa,
HYBRID_ALGORITHM => SignatureAlgorithm::Hybrid,
_ => SignatureAlgorithm::Unknown,
}
}
@@ -733,6 +740,7 @@ pub struct CoseKey {
algorithm: i64,
key_type: i64,
curve: i64,
dilithium_bytes: Option<Vec<u8>>,
}
impl CoseKey {
@@ -744,6 +752,8 @@ impl CoseKey {
const EC2_KEY_TYPE: i64 = 2;
#[cfg(feature = "ed25519")]
const OKP_KEY_TYPE: i64 = 1;
// The key type changes for hybrid. The value is made up.
const HYBRID_KEY_TYPE: i64 = -65537;
// The parameter behind map key -1.
const P_256_CURVE: i64 = 1;
#[cfg(feature = "ed25519")]
@@ -763,6 +773,7 @@ impl TryFrom<cbor::Value> for CoseKey {
-1 => curve,
-2 => x_bytes,
-3 => y_bytes,
-4 => dilithium_bytes,
} = extract_map(cbor_value)?;
}
@@ -785,16 +796,30 @@ impl TryFrom<cbor::Value> for CoseKey {
return Err(Ctap2StatusCode::CTAP2_ERR_UNSUPPORTED_ALGORITHM);
}
let key_type = extract_integer(ok_or_missing(key_type)?)?;
if key_type != CoseKey::EC2_KEY_TYPE {
if key_type != CoseKey::EC2_KEY_TYPE && key_type != CoseKey::HYBRID_KEY_TYPE {
return Err(Ctap2StatusCode::CTAP2_ERR_UNSUPPORTED_ALGORITHM);
}
let parsed_dilithium_bytes = if key_type == CoseKey::EC2_KEY_TYPE {
if dilithium_bytes.is_some() {
return Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER);
}
None
} else {
let dilithium_bytes = extract_byte_string(ok_or_missing(dilithium_bytes)?)?;
if dilithium_bytes.len() != dilithium::params::PK_SIZE_PACKED {
return Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER);
}
Some(dilithium_bytes)
};
Ok(CoseKey {
x_bytes: *array_ref![x_bytes.as_slice(), 0, ecdh::NBYTES],
y_bytes: *array_ref![y_bytes.as_slice(), 0, ecdh::NBYTES],
algorithm,
key_type,
curve,
dilithium_bytes: parsed_dilithium_bytes,
})
}
}
@@ -807,14 +832,16 @@ impl From<CoseKey> for cbor::Value {
algorithm,
key_type,
curve,
dilithium_bytes,
} = cose_key;
cbor_map! {
1 => key_type,
3 => algorithm,
-1 => curve,
-2 => x_bytes,
-3 => y_bytes,
cbor_map_options! {
1 => Some(key_type),
3 => Some(algorithm),
-1 => Some(curve),
-2 => Some(cbor_bytes!(x_bytes.to_vec())),
-3 => Some(cbor_bytes!(y_bytes.to_vec())),
-4 => dilithium_bytes.map(|b| cbor_bytes!(b)),
}
}
}
@@ -830,14 +857,15 @@ impl From<ecdh::PubKey> for CoseKey {
algorithm: CoseKey::ECDH_ALGORITHM,
key_type: CoseKey::EC2_KEY_TYPE,
curve: CoseKey::P_256_CURVE,
dilithium_bytes: None,
}
}
}
impl From<ecdsa::PubKey> for CoseKey {
fn from(pk: ecdsa::PubKey) -> Self {
let mut x_bytes = [0; ecdh::NBYTES];
let mut y_bytes = [0; ecdh::NBYTES];
let mut x_bytes = [0; ecdsa::NBYTES];
let mut y_bytes = [0; ecdsa::NBYTES];
pk.to_coordinates(&mut x_bytes, &mut y_bytes);
CoseKey {
x_bytes,
@@ -845,6 +873,7 @@ impl From<ecdsa::PubKey> for CoseKey {
algorithm: ES256_ALGORITHM,
key_type: CoseKey::EC2_KEY_TYPE,
curve: CoseKey::P_256_CURVE,
dilithium_bytes: None,
}
}
}
@@ -858,6 +887,27 @@ impl From<ed25519_compact::PublicKey> for CoseKey {
key_type: CoseKey::OKP_KEY_TYPE,
curve: CoseKey::ED25519_CURVE,
algorithm: EDDSA_ALGORITHM,
dilithium_bytes: None,
}
}
}
impl From<hybrid::PubKey> for CoseKey {
fn from(pk: hybrid::PubKey) -> Self {
let mut ecdsa_x_bytes = [0; ecdsa::NBYTES];
let mut ecdsa_y_bytes = [0; ecdsa::NBYTES];
pk.ecdsa_pk
.to_coordinates(&mut ecdsa_x_bytes, &mut ecdsa_y_bytes);
let mut dilithium_bytes = vec![0; dilithium::params::PK_SIZE_PACKED];
let bytes_ref = array_mut_ref!(dilithium_bytes, 0, dilithium::params::PK_SIZE_PACKED);
pk.dilithium_pk.to_bytes(bytes_ref);
CoseKey {
x_bytes: ecdsa_x_bytes,
y_bytes: ecdsa_y_bytes,
key_type: CoseKey::EC2_KEY_TYPE,
curve: CoseKey::P_256_CURVE,
algorithm: ES256_ALGORITHM,
dilithium_bytes: Some(dilithium_bytes),
}
}
}
@@ -872,6 +922,7 @@ impl TryFrom<CoseKey> for ecdh::PubKey {
algorithm,
key_type,
curve,
dilithium_bytes,
} = cose_key;
// Since algorithm can be used for different COSE key types, we check
@@ -884,6 +935,9 @@ impl TryFrom<CoseKey> for ecdh::PubKey {
if key_type != CoseKey::EC2_KEY_TYPE || curve != CoseKey::P_256_CURVE {
return Err(Ctap2StatusCode::CTAP2_ERR_UNSUPPORTED_ALGORITHM);
}
if dilithium_bytes.is_some() {
return Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER);
}
ecdh::PubKey::from_coordinates(&x_bytes, &y_bytes)
.ok_or(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER)
}
@@ -899,6 +953,7 @@ impl TryFrom<CoseKey> for ecdsa::PubKey {
algorithm,
key_type,
curve,
dilithium_bytes,
} = cose_key;
if algorithm != ES256_ALGORITHM
@@ -907,55 +962,11 @@ impl TryFrom<CoseKey> for ecdsa::PubKey {
{
return Err(Ctap2StatusCode::CTAP2_ERR_UNSUPPORTED_ALGORITHM);
}
ecdsa::PubKey::from_coordinates(&x_bytes, &y_bytes)
.ok_or(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER)
}
}
/// Data structure for receiving a signature.
///
/// See https://datatracker.ietf.org/doc/html/rfc8152#appendix-C.1.1 for reference.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CoseSignature {
pub algorithm: SignatureAlgorithm,
pub bytes: [u8; ecdsa::Signature::BYTES_LENGTH],
}
impl TryFrom<cbor::Value> for CoseSignature {
type Error = Ctap2StatusCode;
fn try_from(cbor_value: cbor::Value) -> Result<Self, Ctap2StatusCode> {
destructure_cbor_map! {
let {
"alg" => algorithm,
"signature" => bytes,
} = extract_map(cbor_value)?;
}
let algorithm = SignatureAlgorithm::try_from(ok_or_missing(algorithm)?)?;
let bytes = extract_byte_string(ok_or_missing(bytes)?)?;
if bytes.len() != ecdsa::Signature::BYTES_LENGTH {
if dilithium_bytes.is_some() {
return Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER);
}
Ok(CoseSignature {
algorithm,
bytes: *array_ref![bytes.as_slice(), 0, ecdsa::Signature::BYTES_LENGTH],
})
}
}
impl TryFrom<CoseSignature> for ecdsa::Signature {
type Error = Ctap2StatusCode;
fn try_from(cose_signature: CoseSignature) -> Result<Self, Ctap2StatusCode> {
match cose_signature.algorithm {
SignatureAlgorithm::Es256 => ecdsa::Signature::from_bytes(&cose_signature.bytes)
.ok_or(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER),
#[cfg(feature = "ed25519")]
SignatureAlgorithm::Eddsa => Err(Ctap2StatusCode::CTAP2_ERR_UNSUPPORTED_ALGORITHM),
SignatureAlgorithm::Unknown => Err(Ctap2StatusCode::CTAP2_ERR_UNSUPPORTED_ALGORITHM),
}
ecdsa::PubKey::from_coordinates(&x_bytes, &y_bytes)
.ok_or(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER)
}
}
@@ -1289,10 +1300,9 @@ mod test {
use super::*;
use crate::env::test::TestEnv;
use cbor::{
cbor_array, cbor_bool, cbor_bytes, cbor_bytes_lit, cbor_false, cbor_int, cbor_null,
cbor_array, cbor_bool, cbor_bytes_lit, cbor_false, cbor_int, cbor_map, cbor_null,
cbor_text, cbor_unsigned,
};
use crypto::sha256::Sha256;
use rng256::Rng256;
#[test]
@@ -2003,64 +2013,6 @@ mod test {
assert_eq!(cose_key.algorithm, ES256_ALGORITHM);
}
#[test]
fn test_from_into_cose_signature() {
let mut env = TestEnv::new();
let sk = crypto::ecdsa::SecKey::gensk(env.rng());
let dummy_signature = sk.sign_rfc6979::<Sha256>(&[]);
let mut bytes = [0; ecdsa::Signature::BYTES_LENGTH];
dummy_signature.to_bytes(&mut bytes);
let cbor_value = cbor_map! {
"alg" => ES256_ALGORITHM,
"signature" => bytes,
};
let cose_signature = CoseSignature::try_from(cbor_value).unwrap();
let created_signature = crypto::ecdsa::Signature::try_from(cose_signature).unwrap();
let mut created_bytes = [0; ecdsa::Signature::BYTES_LENGTH];
created_signature.to_bytes(&mut created_bytes);
assert_eq!(bytes[..], created_bytes[..]);
}
#[test]
fn test_cose_signature_wrong_algorithm() {
let mut env = TestEnv::new();
let sk = crypto::ecdsa::SecKey::gensk(env.rng());
let dummy_signature = sk.sign_rfc6979::<Sha256>(&[]);
let mut bytes = [0; ecdsa::Signature::BYTES_LENGTH];
dummy_signature.to_bytes(&mut bytes);
let cbor_value = cbor_map! {
"alg" => -1, // unused algorithm
"signature" => bytes,
};
let cose_signature = CoseSignature::try_from(cbor_value).unwrap();
let created_signature = crypto::ecdsa::Signature::try_from(cose_signature);
// Can not compare directly, since ecdsa::Signature does not implement Debug.
assert_eq!(
created_signature.err(),
Some(Ctap2StatusCode::CTAP2_ERR_UNSUPPORTED_ALGORITHM)
);
}
#[test]
fn test_cose_signature_wrong_signature_length() {
let cbor_value = cbor_map! {
"alg" => ES256_ALGORITHM,
"signature" => [0; ecdsa::Signature::BYTES_LENGTH - 1],
};
assert_eq!(
CoseSignature::try_from(cbor_value),
Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER)
);
let cbor_value = cbor_map! {
"alg" => ES256_ALGORITHM,
"signature" => [0; ecdsa::Signature::BYTES_LENGTH + 1],
};
assert_eq!(
CoseSignature::try_from(cbor_value),
Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER)
);
}
#[test]
fn test_from_pin_uv_auth_protocol() {
let cbor_protocol: cbor::Value = cbor_int!(0x01);

View File

@@ -14,9 +14,6 @@
pub const ATTESTATION_PRIVATE_KEY_LENGTH: usize = 32;
pub const AAGUID_LENGTH: usize = 16;
pub const UPGRADE_PUBLIC_KEY_LENGTH: usize = 77;
pub const AAGUID: &[u8; AAGUID_LENGTH] =
include_bytes!(concat!(env!("OUT_DIR"), "/opensk_aaguid.bin"));
pub const UPGRADE_PUBLIC_KEY: &[u8; UPGRADE_PUBLIC_KEY_LENGTH] =
include_bytes!(concat!(env!("OUT_DIR"), "/opensk_upgrade_pubkey_cbor.bin"));

View File

@@ -47,11 +47,10 @@ use self::credential_id::{
use self::credential_management::process_credential_management;
use self::crypto_wrapper::PrivateKey;
use self::data_formats::{
AuthenticatorTransport, CoseKey, CoseSignature, CredentialProtectionPolicy,
EnterpriseAttestationMode, GetAssertionExtensions, PackedAttestationStatement,
PinUvAuthProtocol, PublicKeyCredentialDescriptor, PublicKeyCredentialParameter,
PublicKeyCredentialSource, PublicKeyCredentialType, PublicKeyCredentialUserEntity,
SignatureAlgorithm,
AuthenticatorTransport, CredentialProtectionPolicy, EnterpriseAttestationMode,
GetAssertionExtensions, PackedAttestationStatement, PinUvAuthProtocol,
PublicKeyCredentialDescriptor, PublicKeyCredentialParameter, PublicKeyCredentialSource,
PublicKeyCredentialType, PublicKeyCredentialUserEntity, SignatureAlgorithm,
};
use self::hid::{ChannelID, CtapHid, CtapHidCommand, KeepaliveStatus, ProcessedPacket};
use self::large_blobs::LargeBlobs;
@@ -76,7 +75,6 @@ use alloc::boxed::Box;
use alloc::string::{String, ToString};
use alloc::vec;
use alloc::vec::Vec;
use arrayref::array_ref;
use byteorder::{BigEndian, ByteOrder};
use core::convert::TryFrom;
use crypto::hmac::hmac_256;
@@ -116,8 +114,6 @@ pub const U2F_VERSION_STRING: &str = "U2F_V2";
// TODO(#106) change to final string when ready
pub const FIDO2_1_VERSION_STRING: &str = "FIDO_2_1_PRE";
// We currently only support one algorithm for signatures: ES256.
// This algorithm is requested in MakeCredential and advertized in GetInfo.
pub const ES256_CRED_PARAM: PublicKeyCredentialParameter = PublicKeyCredentialParameter {
cred_type: PublicKeyCredentialType::PublicKey,
alg: SignatureAlgorithm::Es256,
@@ -129,10 +125,16 @@ pub const EDDSA_CRED_PARAM: PublicKeyCredentialParameter = PublicKeyCredentialPa
alg: SignatureAlgorithm::Eddsa,
};
pub const HYBRID_CRED_PARAM: PublicKeyCredentialParameter = PublicKeyCredentialParameter {
cred_type: PublicKeyCredentialType::PublicKey,
alg: SignatureAlgorithm::Hybrid,
};
const SUPPORTED_CRED_PARAMS: &[PublicKeyCredentialParameter] = &[
ES256_CRED_PARAM,
#[cfg(feature = "ed25519")]
EDDSA_CRED_PARAM,
HYBRID_CRED_PARAM,
];
fn get_preferred_cred_param(
@@ -210,56 +212,6 @@ fn truncate_to_char_boundary(s: &str, mut max: usize) -> &str {
}
}
/// Parses the metadata of an upgrade, and checks its correctness.
///
/// Returns the hash over the upgrade, including partition and some metadata.
/// The metadata consists of:
/// - 32B upgrade hash (SHA256)
/// - 4B timestamp (little endian encoding)
/// - 4B partition address (little endian encoding)
/// The upgrade hash is computed over the firmware image and all metadata,
/// except the hash itself.
fn parse_metadata(
upgrade_locations: &impl UpgradeStorage,
metadata: &[u8],
) -> Result<[u8; 32], Ctap2StatusCode> {
const METADATA_LEN: usize = 40;
if metadata.len() != METADATA_LEN {
return Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER);
}
// The hash implementation handles this in chunks, so no memory issues.
let partition_slice = upgrade_locations
.read_partition(0, upgrade_locations.partition_length())
.map_err(|_| Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR)?;
let mut hasher = Sha256::new();
hasher.update(partition_slice);
hasher.update(&metadata[32..METADATA_LEN]);
let computed_hash = hasher.finalize();
if &computed_hash != array_ref!(metadata, 0, 32) {
return Err(Ctap2StatusCode::CTAP2_ERR_INTEGRITY_FAILURE);
}
Ok(computed_hash)
}
/// Verifies the signature over the given hash.
///
/// The public key is COSE encoded, and the hash is a SHA256.
fn verify_signature(
signature: Option<CoseSignature>,
public_key_bytes: &[u8],
signed_hash: &[u8; 32],
) -> Result<(), Ctap2StatusCode> {
let signature =
ecdsa::Signature::try_from(signature.ok_or(Ctap2StatusCode::CTAP2_ERR_MISSING_PARAMETER)?)?;
let cbor_public_key = cbor_read(public_key_bytes)?;
let cose_key = CoseKey::try_from(cbor_public_key)?;
let public_key = ecdsa::PubKey::try_from(cose_key)?;
if !public_key.verify_hash_vartime(signed_hash, &signature) {
return Err(Ctap2StatusCode::CTAP2_ERR_INTEGRITY_FAILURE);
}
Ok(())
}
// Sends keepalive packet during user presence checking. If user agent replies with CANCEL response,
// returns Err(UserPresenceError::Canceled).
fn send_keepalive_up_needed(
@@ -313,6 +265,8 @@ fn send_keepalive_up_needed(
}
match processed_packet {
ProcessedPacket::InitPacket { cmd, .. } => {
// Clippy doesn't understand the macro.
#[allow(clippy::branches_sharing_code)]
if cmd == CtapHidCommand::Cancel as u8 {
// We ignore the payload, we can't answer with an error code anyway.
debug_ctap!(env, "User presence check cancelled");
@@ -900,7 +854,7 @@ impl CtapState {
// We decide on the algorithm early, but delay key creation since it takes time.
// We rather do that later so all intermediate checks may return faster.
let private_key = PrivateKey::new(env, algorithm);
let (private_key, public_cose_key) = PrivateKey::new_with_pub_key(env, algorithm);
let credential_id = if options.rk {
let random_id = env.rng().gen_uniform_u8x32().to_vec();
let credential_source = PublicKeyCredentialSource {
@@ -939,13 +893,11 @@ impl CtapState {
let mut auth_data = self.generate_auth_data(env, &rp_id_hash, flags)?;
auth_data.extend(&storage::aaguid(env)?);
// The length is fixed to 0x20 or 0x80 and fits one byte.
if credential_id.len() > 0xFF {
return Err(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR);
}
auth_data.extend(vec![0x00, credential_id.len() as u8]);
auth_data.extend(vec![
(credential_id.len() >> 8) as u8,
credential_id.len() as u8,
]);
auth_data.extend(&credential_id);
let public_cose_key = private_key.get_pub_key(env)?;
cbor_write(cbor::Value::from(public_cose_key), &mut auth_data)?;
if has_extension_output {
let hmac_secret_output = if extensions.hmac_secret {
@@ -987,7 +939,7 @@ impl CtapState {
.attestation_store()
.get(&id)?
.ok_or(Ctap2StatusCode::CTAP2_ERR_VENDOR_INTERNAL_ERROR)?;
let attestation_key = crypto::ecdsa::SecKey::from_bytes(&private_key).unwrap();
let attestation_key = ecdsa::SecKey::from_bytes(&private_key).unwrap();
(
attestation_key
.sign_rfc6979::<Sha256>(&signature_data)
@@ -995,7 +947,20 @@ impl CtapState {
Some(vec![certificate]),
)
}
None => (private_key.sign_and_encode(env, &signature_data)?, None),
None => {
if matches!(algorithm, SignatureAlgorithm::Hybrid) {
// We can't attest with Dilithium due to message size limits.
let new_ecdsa_key = ecdsa::SecKey::gensk(env.rng());
(
new_ecdsa_key
.sign_rfc6979::<Sha256>(&signature_data)
.to_asn1_der(),
None,
)
} else {
(private_key.sign_and_encode(env, &signature_data)?, None)
}
}
};
let attestation_statement = PackedAttestationStatement {
alg: SignatureAlgorithm::Es256 as i64,
@@ -1316,6 +1281,10 @@ impl CtapState {
(String::from("setMinPINLength"), true),
(String::from("makeCredUvNotRqd"), !has_always_uv),
]);
let mut pin_protocols = vec![PinUvAuthProtocol::V2 as u64];
if env.customization().allows_pin_protocol_v1() {
pin_protocols.push(PinUvAuthProtocol::V1 as u64);
}
Ok(ResponseData::AuthenticatorGetInfo(
AuthenticatorGetInfoResponse {
@@ -1331,10 +1300,7 @@ impl CtapState {
options: Some(options),
max_msg_size: Some(env.customization().max_msg_size() as u64),
// The order implies preference. We favor the new V2.
pin_protocols: Some(vec![
PinUvAuthProtocol::V2 as u64,
PinUvAuthProtocol::V1 as u64,
]),
pin_protocols: Some(pin_protocols),
max_credential_count_in_list: env
.customization()
.max_credential_count_in_list()
@@ -1347,7 +1313,7 @@ impl CtapState {
),
force_pin_change: Some(storage::has_force_pin_change(env)?),
min_pin_length: storage::min_pin_length(env)?,
firmware_version: None,
firmware_version: env.upgrade_storage().map(|u| u.running_firmware_version()),
max_cred_blob_length: Some(env.customization().max_cred_blob_length() as u64),
max_rp_ids_for_set_min_pin_length: Some(
env.customization().max_rp_ids_length() as u64
@@ -1450,39 +1416,15 @@ impl CtapState {
env: &mut impl Env,
params: AuthenticatorVendorUpgradeParameters,
) -> Result<ResponseData, Ctap2StatusCode> {
let AuthenticatorVendorUpgradeParameters {
address,
data,
hash,
signature,
} = params;
let upgrade_locations = env
.upgrade_storage()
.ok_or(Ctap2StatusCode::CTAP1_ERR_INVALID_COMMAND)?;
let written_slice = if let Some(address) = address {
upgrade_locations
.write_partition(address, &data)
.map_err(|_| Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER)?;
upgrade_locations
.read_partition(address, data.len())
.map_err(|_| Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER)?
} else {
// Compares the hash inside the metadata to the actual hash.
let upgrade_hash = parse_metadata(upgrade_locations, &data)?;
// Only signed firmware images may be fully written.
verify_signature(signature, key_material::UPGRADE_PUBLIC_KEY, &upgrade_hash)?;
// Write the metadata page after verifying that its hash is signed.
upgrade_locations
.write_metadata(&data)
.map_err(|_| Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER)?;
&upgrade_locations
.read_metadata()
.map_err(|_| Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER)?[..data.len()]
};
let written_hash = Sha256::hash(written_slice);
if hash != written_hash {
let AuthenticatorVendorUpgradeParameters { offset, data, hash } = params;
let calculated_hash = Sha256::hash(&data);
if hash != calculated_hash {
return Err(Ctap2StatusCode::CTAP2_ERR_INTEGRITY_FAILURE);
}
env.upgrade_storage()
.ok_or(Ctap2StatusCode::CTAP1_ERR_INVALID_COMMAND)?
.write_bundle(offset, data)
.map_err(|_| Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER)?;
Ok(ResponseData::AuthenticatorVendorUpgrade)
}
@@ -1495,7 +1437,7 @@ impl CtapState {
.ok_or(Ctap2StatusCode::CTAP1_ERR_INVALID_COMMAND)?;
Ok(ResponseData::AuthenticatorVendorUpgradeInfo(
AuthenticatorVendorUpgradeInfoResponse {
info: upgrade_locations.partition_address() as u32,
info: upgrade_locations.bundle_identifier(),
},
))
}
@@ -1646,6 +1588,7 @@ mod test {
0x0B => env.customization().max_large_blob_array_size() as u64,
0x0C => false,
0x0D => storage::min_pin_length(&mut env).unwrap() as u64,
0x0E => 0,
0x0F => env.customization().max_cred_blob_length() as u64,
0x10 => env.customization().max_rp_ids_length() as u64,
0x14 => storage::remaining_credentials(&mut env).unwrap() as u64,
@@ -1656,6 +1599,23 @@ mod test {
assert_eq!(info_reponse, response_cbor);
}
#[test]
fn test_get_info_no_pin_protocol_v1() {
let mut env = TestEnv::new();
env.customization_mut().set_allows_pin_protocol_v1(false);
let ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
let info_response = ctap_state.process_get_info(&mut env).unwrap();
match info_response {
ResponseData::AuthenticatorGetInfo(response) => {
assert_eq!(
response.pin_protocols,
Some(vec![PinUvAuthProtocol::V2 as u64])
);
}
_ => panic!("Invalid response type"),
}
}
fn create_minimal_make_credential_parameters() -> AuthenticatorMakeCredentialParameters {
let client_data_hash = vec![0xCD];
let rp = PublicKeyCredentialRpEntity {
@@ -3453,177 +3413,71 @@ mod test {
);
}
#[test]
fn test_parse_metadata() {
let mut env = TestEnv::new();
// The test buffer starts fully erased with 0xFF bytes.
// The compiler issues an incorrect warning.
#[allow(unused_mut)]
let mut upgrade_locations = env.upgrade_storage().unwrap();
// Partition of 0x40000 bytes and 8 bytes metadata are hashed.
let hashed_data = vec![0xFF; 0x40000 + 8];
let expected_hash = Sha256::hash(&hashed_data);
let mut metadata = vec![0xFF; 40];
metadata[..32].copy_from_slice(&expected_hash);
assert_eq!(
parse_metadata(upgrade_locations, &metadata),
Ok(expected_hash)
);
// Any manipulation of data fails.
metadata[32] = 0x88;
assert_eq!(
parse_metadata(upgrade_locations, &metadata),
Err(Ctap2StatusCode::CTAP2_ERR_INTEGRITY_FAILURE)
);
metadata[32] = 0xFF;
metadata[0] ^= 0x01;
assert_eq!(
parse_metadata(upgrade_locations, &metadata),
Err(Ctap2StatusCode::CTAP2_ERR_INTEGRITY_FAILURE)
);
metadata[0] ^= 0x01;
upgrade_locations.write_partition(0, &[0x88; 1]).unwrap();
assert_eq!(
parse_metadata(upgrade_locations, &metadata),
Err(Ctap2StatusCode::CTAP2_ERR_INTEGRITY_FAILURE)
);
}
#[test]
fn test_verify_signature() {
let mut env = TestEnv::new();
let private_key = crypto::ecdsa::SecKey::gensk(env.rng());
let message = [0x44; 64];
let signed_hash = Sha256::hash(&message);
let signature = private_key.sign_rfc6979::<Sha256>(&message);
let mut signature_bytes = [0; ecdsa::Signature::BYTES_LENGTH];
signature.to_bytes(&mut signature_bytes);
let cose_signature = CoseSignature {
algorithm: SignatureAlgorithm::Es256,
bytes: signature_bytes,
};
let public_key = private_key.genpk();
let mut public_key_bytes = vec![];
cbor_write(
cbor::Value::from(CoseKey::from(public_key)),
&mut public_key_bytes,
)
.unwrap();
assert_eq!(
verify_signature(
Some(cose_signature.clone()),
&public_key_bytes,
&signed_hash
),
Ok(())
);
assert_eq!(
verify_signature(Some(cose_signature.clone()), &public_key_bytes, &[0x55; 32]),
Err(Ctap2StatusCode::CTAP2_ERR_INTEGRITY_FAILURE)
);
public_key_bytes[0] ^= 0x01;
assert_eq!(
verify_signature(Some(cose_signature), &public_key_bytes, &signed_hash),
Err(Ctap2StatusCode::CTAP2_ERR_INVALID_CBOR)
);
public_key_bytes[0] ^= 0x01;
assert_eq!(
verify_signature(None, &public_key_bytes, &signed_hash),
Err(Ctap2StatusCode::CTAP2_ERR_MISSING_PARAMETER)
);
signature_bytes[0] ^= 0x01;
let cose_signature = CoseSignature {
algorithm: SignatureAlgorithm::Es256,
bytes: signature_bytes,
};
assert_eq!(
verify_signature(Some(cose_signature), &public_key_bytes, &signed_hash),
Err(Ctap2StatusCode::CTAP2_ERR_INTEGRITY_FAILURE)
);
}
#[test]
fn test_vendor_upgrade() {
// The test partition storage has size 0x40000.
// The test metadata storage has size 0x1000.
// The test identifier matches partition B.
let mut env = TestEnv::new();
let private_key = crypto::ecdsa::SecKey::gensk(env.rng());
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
const METADATA_LEN: usize = 40;
const METADATA_LEN: usize = 0x1000;
let metadata = vec![0xFF; METADATA_LEN];
let metadata_hash = Sha256::hash(&metadata);
let data = vec![0xFF; 0x1000];
let hash = Sha256::hash(&data).to_vec();
let upgrade_locations = env.upgrade_storage().unwrap();
let partition_length = upgrade_locations.partition_length();
let mut signed_over_data = upgrade_locations
.read_partition(0, partition_length)
.unwrap()
.to_vec();
signed_over_data.extend(&[0xFF; METADATA_LEN - 32]);
let signed_hash = Sha256::hash(&signed_over_data);
let mut metadata = vec![0xFF; METADATA_LEN];
metadata[..32].copy_from_slice(&signed_hash);
let metadata_hash = Sha256::hash(&metadata).to_vec();
let hash = Sha256::hash(&data);
let signature = private_key.sign_rfc6979::<Sha256>(&signed_over_data);
let mut signature_bytes = [0; ecdsa::Signature::BYTES_LENGTH];
signature.to_bytes(&mut signature_bytes);
let cose_signature = CoseSignature {
algorithm: SignatureAlgorithm::Es256,
bytes: signature_bytes,
};
// Write to partition and metadata.
// Write to partition.
let response = ctap_state.process_vendor_upgrade(
&mut env,
AuthenticatorVendorUpgradeParameters {
address: Some(0x20000),
offset: 0x20000,
data: data.clone(),
hash: hash.clone(),
signature: None,
hash,
},
);
assert_eq!(response, Ok(ResponseData::AuthenticatorVendorUpgrade));
// We can't inject a public key for our known private key, so the last upgrade step fails.
// verify_signature is separately tested for that reason.
// TestEnv doesn't check the metadata, test its parser in your Env.
let response = ctap_state.process_vendor_upgrade(
&mut env,
AuthenticatorVendorUpgradeParameters {
address: None,
offset: 0,
data: metadata.clone(),
hash: metadata_hash.clone(),
signature: Some(cose_signature.clone()),
hash: metadata_hash,
},
);
assert_eq!(response, Err(Ctap2StatusCode::CTAP2_ERR_INTEGRITY_FAILURE));
assert_eq!(response, Ok(ResponseData::AuthenticatorVendorUpgrade));
// TestEnv doesn't check the metadata, test its parser in your Env.
let response = ctap_state.process_vendor_upgrade(
&mut env,
AuthenticatorVendorUpgradeParameters {
offset: METADATA_LEN,
data: data.clone(),
hash,
},
);
assert_eq!(response, Ok(ResponseData::AuthenticatorVendorUpgrade));
// Write metadata of a wrong size.
let response = ctap_state.process_vendor_upgrade(
&mut env,
AuthenticatorVendorUpgradeParameters {
address: None,
offset: 0,
data: metadata[..METADATA_LEN - 1].to_vec(),
hash: metadata_hash,
signature: Some(cose_signature),
},
);
assert_eq!(response, Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER));
assert_eq!(response, Err(Ctap2StatusCode::CTAP2_ERR_INTEGRITY_FAILURE));
// Write outside of the partition.
let response = ctap_state.process_vendor_upgrade(
&mut env,
AuthenticatorVendorUpgradeParameters {
address: Some(0x40000),
offset: 0x41000,
data: data.clone(),
hash,
signature: None,
},
);
assert_eq!(response, Err(Ctap2StatusCode::CTAP1_ERR_INVALID_PARAMETER));
@@ -3632,10 +3486,9 @@ mod test {
let response = ctap_state.process_vendor_upgrade(
&mut env,
AuthenticatorVendorUpgradeParameters {
address: Some(0x20000),
offset: 0x20000,
data,
hash: [0xEE; 32].to_vec(),
signature: None,
hash: [0xEE; 32],
},
);
assert_eq!(response, Err(Ctap2StatusCode::CTAP2_ERR_INTEGRITY_FAILURE));
@@ -3648,14 +3501,13 @@ mod test {
let mut ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
let data = vec![0xFF; 0x1000];
let hash = Sha256::hash(&data).to_vec();
let hash = Sha256::hash(&data);
let response = ctap_state.process_vendor_upgrade(
&mut env,
AuthenticatorVendorUpgradeParameters {
address: Some(0),
offset: 0,
data,
hash,
signature: None,
},
);
assert_eq!(response, Err(Ctap2StatusCode::CTAP1_ERR_INVALID_COMMAND));
@@ -3665,14 +3517,14 @@ mod test {
fn test_vendor_upgrade_info() {
let mut env = TestEnv::new();
let ctap_state = CtapState::new(&mut env, CtapInstant::new(0));
let partition_address = env.upgrade_storage().unwrap().partition_address();
let bundle_identifier = env.upgrade_storage().unwrap().bundle_identifier();
let upgrade_info_reponse = ctap_state.process_vendor_upgrade_info(&mut env);
assert_eq!(
upgrade_info_reponse,
Ok(ResponseData::AuthenticatorVendorUpgradeInfo(
AuthenticatorVendorUpgradeInfoResponse {
info: partition_address as u32,
info: bundle_identifier,
}
))
);

View File

@@ -18,6 +18,7 @@ use alloc::string::String;
use alloc::vec::Vec;
pub struct TestCustomization {
allows_pin_protocol_v1: bool,
default_cred_protect: Option<CredentialProtectionPolicy>,
default_min_pin_length: u8,
default_min_pin_length_rp_ids: Vec<String>,
@@ -36,6 +37,10 @@ pub struct TestCustomization {
}
impl TestCustomization {
pub fn set_allows_pin_protocol_v1(&mut self, is_allowed: bool) {
self.allows_pin_protocol_v1 = is_allowed;
}
pub fn setup_enterprise_attestation(
&mut self,
mode: Option<EnterpriseAttestationMode>,
@@ -49,6 +54,10 @@ impl TestCustomization {
}
impl Customization for TestCustomization {
fn allows_pin_protocol_v1(&self) -> bool {
self.allows_pin_protocol_v1
}
fn default_cred_protect(&self) -> Option<CredentialProtectionPolicy> {
self.default_cred_protect
}
@@ -117,6 +126,7 @@ impl Customization for TestCustomization {
impl From<CustomizationImpl> for TestCustomization {
fn from(c: CustomizationImpl) -> Self {
let CustomizationImpl {
allows_pin_protocol_v1,
default_cred_protect,
default_min_pin_length,
default_min_pin_length_rp_ids,
@@ -145,6 +155,7 @@ impl From<CustomizationImpl> for TestCustomization {
.collect::<Vec<_>>();
Self {
allows_pin_protocol_v1,
default_cred_protect,
default_min_pin_length,
default_min_pin_length_rp_ids,

4
src/env/test/mod.rs vendored
View File

@@ -50,6 +50,10 @@ impl TestRng256 {
}
impl Rng256 for TestRng256 {
fn fill_bytes(&mut self, buf: &mut [u8]) {
self.rng.fill(buf)
}
fn gen_uniform_u8x32(&mut self) -> [u8; 32] {
let mut result = [Default::default(); 32];
self.rng.fill(&mut result);

View File

@@ -17,27 +17,22 @@ use crate::api::upgrade_storage::UpgradeStorage;
use alloc::boxed::Box;
use persistent_store::{StorageError, StorageResult};
const PARTITION_LENGTH: usize = 0x40000;
const PARTITION_LENGTH: usize = 0x41000;
const METADATA_LENGTH: usize = 0x1000;
pub struct BufferUpgradeStorage {
/// Content of the partition storage.
partition: Box<[u8]>,
/// Content of the metadata storage.
metadata: Box<[u8]>,
}
impl BufferUpgradeStorage {
pub fn new() -> StorageResult<BufferUpgradeStorage> {
Ok(BufferUpgradeStorage {
partition: vec![0xff; PARTITION_LENGTH].into_boxed_slice(),
metadata: vec![0xff; METADATA_LENGTH].into_boxed_slice(),
})
}
}
impl UpgradeStorage for BufferUpgradeStorage {
#[cfg(test)]
fn read_partition(&self, offset: usize, length: usize) -> StorageResult<&[u8]> {
if length == 0 {
return Err(StorageError::OutOfBounds);
@@ -49,40 +44,31 @@ impl UpgradeStorage for BufferUpgradeStorage {
Err(StorageError::OutOfBounds)
}
}
}
fn write_partition(&mut self, offset: usize, data: &[u8]) -> StorageResult<()> {
impl UpgradeStorage for BufferUpgradeStorage {
fn write_bundle(&mut self, offset: usize, data: Vec<u8>) -> StorageResult<()> {
if offset == 0 && data.len() != METADATA_LENGTH {
return Err(StorageError::OutOfBounds);
}
if data.is_empty() {
return Err(StorageError::OutOfBounds);
}
let partition_range = ModRange::new(0, self.partition.len());
if partition_range.contains_range(&ModRange::new(offset, data.len())) {
self.partition[offset..][..data.len()].copy_from_slice(data);
self.partition[offset..][..data.len()].copy_from_slice(&data);
Ok(())
} else {
Err(StorageError::OutOfBounds)
}
}
fn partition_address(&self) -> usize {
fn bundle_identifier(&self) -> u32 {
0x60000
}
fn partition_length(&self) -> usize {
PARTITION_LENGTH
}
fn read_metadata(&self) -> StorageResult<&[u8]> {
Ok(&self.metadata[..])
}
fn write_metadata(&mut self, data: &[u8]) -> StorageResult<()> {
if data.len() <= METADATA_LENGTH {
self.metadata.copy_from_slice(&[0xff; METADATA_LENGTH]);
self.metadata[..data.len()].copy_from_slice(data);
Ok(())
} else {
Err(StorageError::OutOfBounds)
}
fn running_firmware_version(&self) -> u64 {
0
}
}
@@ -91,13 +77,13 @@ mod tests {
use super::*;
#[test]
fn read_write_partition() {
fn read_write_bundle() {
let mut storage = BufferUpgradeStorage::new().unwrap();
assert_eq!(storage.read_partition(0, 2).unwrap(), &[0xFF, 0xFF]);
assert!(storage.write_partition(1, &[0x88, 0x88]).is_ok());
assert!(storage.write_bundle(1, vec![0x88, 0x88]).is_ok());
assert_eq!(storage.read_partition(0, 2).unwrap(), &[0xFF, 0x88]);
assert_eq!(
storage.write_partition(PARTITION_LENGTH - 1, &[0x88, 0x88]),
storage.write_bundle(PARTITION_LENGTH - 1, vec![0x88, 0x88],),
Err(StorageError::OutOfBounds)
);
assert_eq!(
@@ -109,11 +95,11 @@ mod tests {
Err(StorageError::OutOfBounds)
);
assert_eq!(
storage.write_partition(4, &[]),
storage.write_bundle(4, vec![]),
Err(StorageError::OutOfBounds)
);
assert_eq!(
storage.write_partition(PARTITION_LENGTH + 4, &[]),
storage.write_bundle(PARTITION_LENGTH + 4, vec![]),
Err(StorageError::OutOfBounds)
);
assert_eq!(storage.read_partition(4, 0), Err(StorageError::OutOfBounds));
@@ -126,23 +112,6 @@ mod tests {
#[test]
fn partition_slice() {
let storage = BufferUpgradeStorage::new().unwrap();
assert_eq!(storage.partition_address(), 0x60000);
assert_eq!(storage.partition_length(), PARTITION_LENGTH);
}
#[test]
fn read_write_metadata() {
let mut storage = BufferUpgradeStorage::new().unwrap();
assert_eq!(storage.read_metadata().unwrap(), &[0xFF; METADATA_LENGTH]);
assert!(storage.write_metadata(&[0x88, 0x88]).is_ok());
assert_eq!(
storage.write_metadata(&[0x88; METADATA_LENGTH + 1]),
Err(StorageError::OutOfBounds)
);
let new_metadata = storage.read_metadata().unwrap();
assert_eq!(&new_metadata[0..2], &[0x88, 0x88]);
assert_eq!(&new_metadata[2..], &[0xFF; METADATA_LENGTH - 2]);
assert!(storage.write_metadata(&[]).is_ok());
assert_eq!(storage.read_metadata().unwrap(), &[0xFF; METADATA_LENGTH]);
assert_eq!(storage.bundle_identifier(), 0x60000);
}
}

2
src/env/tock/mod.rs vendored
View File

@@ -117,7 +117,7 @@ impl UserPresence for TockEnv {
}
fn wait_with_timeout(&mut self, timeout: Milliseconds<ClockInt>) -> UserPresenceResult {
if timeout.integer() == 0 {
return Err(UserPresenceError::Timeout);
return Ok(());
}
blink_leds(self.blink_pattern);
self.blink_pattern += 1;

View File

@@ -12,15 +12,23 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::api::upgrade_storage::helper::{find_slice, is_aligned, ModRange};
use crate::api::upgrade_storage::helper::{find_slice, is_aligned, ModRange, Partition};
use crate::api::upgrade_storage::UpgradeStorage;
use alloc::borrow::Cow;
use alloc::vec::Vec;
use arrayref::array_ref;
use byteorder::{ByteOrder, LittleEndian};
use core::cell::Cell;
use crypto::sha256::Sha256;
use crypto::{ecdsa, Hash256};
use libtock_core::{callback, syscalls};
use persistent_store::{Storage, StorageError, StorageIndex, StorageResult};
const DRIVER_NUMBER: usize = 0x50003;
const METADATA_SIGN_OFFSET: usize = 0x800;
const UPGRADE_PUBLIC_KEY: &[u8; 65] =
include_bytes!(concat!(env!("OUT_DIR"), "/opensk_upgrade_pubkey.bin"));
mod subscribe_nr {
pub const DONE: usize = 0;
@@ -52,7 +60,6 @@ mod memop_nr {
mod storage_type {
pub const STORE: usize = 1;
pub const PARTITION: usize = 2;
pub const METADATA: usize = 3;
}
fn get_info(nr: usize, arg: usize) -> StorageResult<usize> {
@@ -94,6 +101,10 @@ fn block_command(driver: usize, cmd: usize, arg1: usize, arg2: usize) -> Storage
}
}
unsafe fn read_slice(address: usize, length: usize) -> &'static [u8] {
core::slice::from_raw_parts(address as *const u8, length)
}
fn write_slice(ptr: usize, value: &[u8]) -> StorageResult<()> {
let code = unsafe {
syscalls::raw::allow(
@@ -220,11 +231,19 @@ impl Storage for TockStorage {
pub struct TockUpgradeStorage {
page_size: usize,
partition: ModRange,
partition: Partition,
metadata: ModRange,
running_metadata: ModRange,
identifier: u32,
}
impl TockUpgradeStorage {
// Ideally, the kernel should tell us metadata and partitions directly.
// This code only works for one layout, refactor this into the storage driver to support more.
const METADATA_ADDRESS: usize = 0x4000;
const PARTITION_ADDRESS_A: usize = 0x20000;
const PARTITION_ADDRESS_B: usize = 0x60000;
/// Provides access to the other upgrade partition and metadata if available.
///
/// The implementation assumes that storage locations returned by the kernel through
@@ -235,24 +254,26 @@ impl TockUpgradeStorage {
/// Returns `CustomError` if any of the following conditions do not hold:
/// - The page size is a power of two.
/// - The storage slices are page-aligned.
/// - There are not partition or metadata slices.
/// - There are no partition or no metadata slices.
/// Returns a `NotAligned` error if partitions or metadata ranges are
/// - not exclusive or,
/// - not consecutive.
pub fn new() -> StorageResult<TockUpgradeStorage> {
let mut locations = TockUpgradeStorage {
page_size: get_info(command_nr::get_info_nr::PAGE_SIZE, 0)?,
partition: ModRange::new_empty(),
partition: Partition::new(),
metadata: ModRange::new_empty(),
running_metadata: ModRange::new_empty(),
identifier: Self::PARTITION_ADDRESS_A as u32,
};
if !locations.page_size.is_power_of_two() {
return Err(StorageError::CustomError);
}
let mut firmware_range = ModRange::new_empty();
for i in 0..memop(memop_nr::STORAGE_CNT, 0)? {
let storage_type = memop(memop_nr::STORAGE_TYPE, i)?;
match storage_type {
storage_type::PARTITION | storage_type::METADATA => (),
_ => continue,
if !matches!(storage_type, storage_type::PARTITION) {
continue;
};
let storage_ptr = memop(memop_nr::STORAGE_PTR, i)?;
let storage_len = memop(memop_nr::STORAGE_LEN, i)?;
@@ -260,91 +281,292 @@ impl TockUpgradeStorage {
return Err(StorageError::CustomError);
}
let range = ModRange::new(storage_ptr, storage_len);
match storage_type {
storage_type::PARTITION => {
locations.partition = locations
.partition
.append(range)
.ok_or(StorageError::NotAligned)?
match range.start() {
Self::METADATA_ADDRESS => {
// Will be swapped if we are on B.
locations.metadata = ModRange::new(range.start(), locations.page_size);
locations.running_metadata =
ModRange::new(range.start() + locations.page_size, locations.page_size);
}
storage_type::METADATA => {
locations.metadata = locations
.metadata
.append(range)
.ok_or(StorageError::NotAligned)?
_ => {
if !firmware_range.append(&range) {
return Err(StorageError::NotAligned);
}
_ => (),
};
}
if locations.partition.is_empty() || locations.metadata.is_empty() {
Err(StorageError::CustomError)
} else {
}
}
if firmware_range.is_empty()
|| locations.metadata.is_empty()
|| locations.running_metadata.is_empty()
{
return Err(StorageError::CustomError);
}
if firmware_range.start() == Self::PARTITION_ADDRESS_B {
core::mem::swap(&mut locations.metadata, &mut locations.running_metadata);
locations.identifier = Self::PARTITION_ADDRESS_B as u32;
}
if !locations.partition.append(locations.metadata.clone()) {
return Err(StorageError::NotAligned);
}
if !locations.partition.append(firmware_range) {
return Err(StorageError::NotAligned);
}
Ok(locations)
}
}
fn is_page_aligned(&self, x: usize) -> bool {
is_aligned(self.page_size, x)
}
/// Returns whether the metadata is contained in this range or not.
///
/// Assumes that metadata is written in one call per range. If the metadata is only partially
/// contained, returns an error.
fn contains_metadata(&self, checked_range: &ModRange) -> StorageResult<bool> {
if checked_range.intersects_range(&self.metadata) {
if checked_range.contains_range(&self.metadata) {
Ok(true)
} else {
Err(StorageError::NotAligned)
}
} else {
Ok(false)
}
}
/// Checks if the metadata's hash matches the partition's content.
fn check_partition_hash(&self, metadata: &[u8]) -> StorageResult<()> {
let start_address = self.metadata.start() + METADATA_SIGN_OFFSET;
let mut hasher = Sha256::new();
for range in self.partition.ranges_from(start_address) {
let partition_slice = unsafe { read_slice(range.start(), range.length()) };
// The hash implementation handles this in chunks, so no memory issues.
hasher.update(partition_slice);
}
let computed_hash = hasher.finalize();
if &computed_hash != parse_metadata_hash(metadata) {
return Err(StorageError::CustomError);
}
Ok(())
}
}
impl UpgradeStorage for TockUpgradeStorage {
fn read_partition(&self, offset: usize, length: usize) -> StorageResult<&[u8]> {
if length == 0 {
return Err(StorageError::OutOfBounds);
}
let address = self.partition.start() + offset;
if self
.partition
.contains_range(&ModRange::new(address, length))
{
Ok(unsafe { core::slice::from_raw_parts(address as *const u8, length) })
} else {
Err(StorageError::OutOfBounds)
}
}
fn write_partition(&mut self, offset: usize, data: &[u8]) -> StorageResult<()> {
fn write_bundle(&mut self, offset: usize, data: Vec<u8>) -> StorageResult<()> {
if data.is_empty() {
return Err(StorageError::OutOfBounds);
}
let address = self.partition.start() + offset;
let address = self
.partition
.find_address(offset, data.len())
.ok_or(StorageError::OutOfBounds)?;
let write_range = ModRange::new(address, data.len());
if self.partition.contains_range(&write_range) {
if self.contains_metadata(&write_range)? {
let new_metadata = &data[self.metadata.start() - address..][..self.metadata.length()];
check_metadata(self, UPGRADE_PUBLIC_KEY, new_metadata)?;
}
// Erases all pages that have their first byte in the write range.
// Since we expect calls in order, we don't want to erase half-written pages.
for address in write_range.aligned_iter(self.page_size) {
erase_page(address, self.page_size)?;
}
write_slice(address, data)
} else {
Err(StorageError::OutOfBounds)
write_slice(address, &data)?;
let written_slice = unsafe { read_slice(address, data.len()) };
if written_slice != data {
return Err(StorageError::CustomError);
}
// Case: Last slice is written.
if data.len() == self.partition.length() - offset {
let metadata = unsafe { read_slice(self.metadata.start(), self.metadata.length()) };
self.check_partition_hash(metadata)?;
}
Ok(())
}
fn bundle_identifier(&self) -> u32 {
self.identifier
}
fn running_firmware_version(&self) -> u64 {
let running_metadata = unsafe {
read_slice(
self.running_metadata.start(),
self.running_metadata.length(),
)
};
parse_metadata_version(running_metadata)
}
}
fn partition_address(&self) -> usize {
self.partition.start()
/// Parses the metadata of an upgrade, and checks its correctness.
///
/// The metadata is a page starting with:
/// - 32 B upgrade hash (SHA256)
/// - 64 B signature,
/// that are not signed over. The second part is included in the signature with
/// - 8 B version and
/// - 4 B partition address in little endian encoding
/// written at METADATA_SIGN_OFFSET.
///
/// Checks signature correctness against the hash, and whether the partition offset matches.
/// Whether the hash matches the partition content is not tested here!
fn check_metadata(
upgrade_locations: &impl UpgradeStorage,
public_key_bytes: &[u8],
metadata: &[u8],
) -> StorageResult<()> {
const METADATA_LEN: usize = 0x1000;
if metadata.len() != METADATA_LEN {
return Err(StorageError::CustomError);
}
fn partition_length(&self) -> usize {
self.partition.length()
let version = parse_metadata_version(metadata);
if version < upgrade_locations.running_firmware_version() {
return Err(StorageError::CustomError);
}
fn read_metadata(&self) -> StorageResult<&[u8]> {
Ok(unsafe {
core::slice::from_raw_parts(self.metadata.start() as *const u8, self.metadata.length())
})
let metadata_address = LittleEndian::read_u32(&metadata[METADATA_SIGN_OFFSET + 8..][..4]);
if metadata_address != upgrade_locations.bundle_identifier() {
return Err(StorageError::CustomError);
}
fn write_metadata(&mut self, data: &[u8]) -> StorageResult<()> {
// If less data is passed in than is reserved, assume the rest is 0xFF.
if data.len() <= self.metadata.length() {
for address in self.metadata.aligned_iter(self.page_size) {
erase_page(address, self.page_size)?;
}
write_slice(self.metadata.start(), data)
} else {
Err(StorageError::OutOfBounds)
verify_signature(
array_ref!(metadata, 32, 64),
public_key_bytes,
parse_metadata_hash(metadata),
)?;
Ok(())
}
/// Parses the metadata, returns the hash.
fn parse_metadata_hash(data: &[u8]) -> &[u8; 32] {
array_ref!(data, 0, 32)
}
/// Parses the metadata, returns the firmware version.
fn parse_metadata_version(data: &[u8]) -> u64 {
LittleEndian::read_u64(&data[METADATA_SIGN_OFFSET..][..8])
}
/// Verifies the signature over the given hash.
///
/// The public key is COSE encoded, and the hash is a SHA256.
fn verify_signature(
signature_bytes: &[u8; 64],
public_key_bytes: &[u8],
signed_hash: &[u8; 32],
) -> StorageResult<()> {
let signature =
ecdsa::Signature::from_bytes(signature_bytes).ok_or(StorageError::CustomError)?;
let public_key = ecdsa::PubKey::from_bytes_uncompressed(public_key_bytes)
.ok_or(StorageError::CustomError)?;
if !public_key.verify_hash_vartime(signed_hash, &signature) {
return Err(StorageError::CustomError);
}
Ok(())
}
#[cfg(test)]
mod test {
use super::*;
use crate::env::test::TestEnv;
use crate::env::Env;
#[test]
fn test_check_metadata() {
let mut env = TestEnv::new();
let private_key = crypto::ecdsa::SecKey::gensk(env.rng());
let upgrade_locations = env.upgrade_storage().unwrap();
const METADATA_LEN: usize = 0x1000;
const METADATA_SIGN_OFFSET: usize = 0x800;
let mut metadata = vec![0xFF; METADATA_LEN];
LittleEndian::write_u32(&mut metadata[METADATA_SIGN_OFFSET + 8..][..4], 0x60000);
let mut signed_over_data = metadata[METADATA_SIGN_OFFSET..].to_vec();
signed_over_data.extend(&[0xFF; 0x20000]);
let signed_hash = Sha256::hash(&signed_over_data);
metadata[..32].copy_from_slice(&signed_hash);
let signature = private_key.sign_rfc6979::<Sha256>(&signed_over_data);
let mut signature_bytes = [0; ecdsa::Signature::BYTES_LENGTH];
signature.to_bytes(&mut signature_bytes);
metadata[32..96].copy_from_slice(&signature_bytes);
let public_key = private_key.genpk();
let mut public_key_bytes = [0; 65];
public_key.to_bytes_uncompressed(&mut public_key_bytes);
assert_eq!(
check_metadata(upgrade_locations, &public_key_bytes, &metadata),
Ok(())
);
// Manipulating the partition address fails.
metadata[METADATA_SIGN_OFFSET + 8] = 0x88;
assert_eq!(
check_metadata(upgrade_locations, &public_key_bytes, &metadata),
Err(StorageError::CustomError)
);
metadata[METADATA_SIGN_OFFSET + 8] = 0x00;
// Wrong metadata length fails.
assert_eq!(
check_metadata(
upgrade_locations,
&public_key_bytes,
&metadata[..METADATA_LEN - 1]
),
Err(StorageError::CustomError)
);
// Manipulating the hash fails.
metadata[0] ^= 0x01;
assert_eq!(
check_metadata(upgrade_locations, &public_key_bytes, &metadata),
Err(StorageError::CustomError)
);
metadata[0] ^= 0x01;
// Manipulating the signature fails.
metadata[32] ^= 0x01;
assert_eq!(
check_metadata(upgrade_locations, &public_key_bytes, &metadata),
Err(StorageError::CustomError)
);
}
#[test]
fn test_verify_signature() {
let mut env = TestEnv::new();
let private_key = crypto::ecdsa::SecKey::gensk(env.rng());
let message = [0x44; 64];
let signed_hash = Sha256::hash(&message);
let signature = private_key.sign_rfc6979::<Sha256>(&message);
let mut signature_bytes = [0; ecdsa::Signature::BYTES_LENGTH];
signature.to_bytes(&mut signature_bytes);
let public_key = private_key.genpk();
let mut public_key_bytes = [0; 65];
public_key.to_bytes_uncompressed(&mut public_key_bytes);
assert_eq!(
verify_signature(&signature_bytes, &public_key_bytes, &signed_hash),
Ok(())
);
assert_eq!(
verify_signature(&signature_bytes, &public_key_bytes, &[0x55; 32]),
Err(StorageError::CustomError)
);
public_key_bytes[0] ^= 0x01;
assert_eq!(
verify_signature(&signature_bytes, &public_key_bytes, &signed_hash),
Err(StorageError::CustomError)
);
public_key_bytes[0] ^= 0x01;
signature_bytes[0] ^= 0x01;
assert_eq!(
verify_signature(&signature_bytes, &public_key_bytes, &signed_hash),
Err(StorageError::CustomError)
);
}
}

View File

@@ -49,7 +49,7 @@ use libtock_drivers::timer::Duration;
use libtock_drivers::usb_ctap_hid;
use usb_ctap_hid::UsbEndpoint;
libtock_core::stack_size! {0x4000}
libtock_core::stack_size! {0x11800}
const SEND_TIMEOUT: Milliseconds<ClockInt> = Milliseconds(1000);
const KEEPALIVE_DELAY_TOCK: Duration<isize> = Duration::from_ms(KEEPALIVE_DELAY_MS as isize);

957
third_party/dilithium/Cargo.lock generated vendored Normal file
View File

@@ -0,0 +1,957 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "ansi_term"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
dependencies = [
"winapi",
]
[[package]]
name = "arrayref"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[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 = "block-buffer"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab"
dependencies = [
"arrayref",
"byte-tools",
]
[[package]]
name = "bstr"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
dependencies = [
"lazy_static",
"memchr",
"regex-automata",
"serde",
]
[[package]]
name = "bumpalo"
version = "3.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c"
[[package]]
name = "byte-tools"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40"
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "cast"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "2.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
dependencies = [
"ansi_term",
"atty",
"bitflags",
"strsim",
"textwrap",
"unicode-width",
"vec_map",
]
[[package]]
name = "cloudabi"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
dependencies = [
"bitflags",
]
[[package]]
name = "criterion"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f"
dependencies = [
"atty",
"cast",
"clap",
"criterion-plot",
"csv",
"itertools 0.10.5",
"lazy_static",
"num-traits",
"oorandom",
"plotters",
"rayon",
"regex",
"serde",
"serde_cbor",
"serde_derive",
"serde_json",
"tinytemplate",
"walkdir",
]
[[package]]
name = "criterion-plot"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876"
dependencies = [
"cast",
"itertools 0.10.5",
]
[[package]]
name = "crossbeam-channel"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521"
dependencies = [
"cfg-if",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-deque"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc"
dependencies = [
"cfg-if",
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f916dfc5d356b0ed9dae65f1db9fc9770aa2851d2662b988ccf4fe3516e86348"
dependencies = [
"autocfg 1.1.0",
"cfg-if",
"crossbeam-utils",
"memoffset",
"scopeguard",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edbafec5fa1f196ca66527c1b12c2ec4745ca14b50f1ad8f9f6f720b55d11fac"
dependencies = [
"cfg-if",
]
[[package]]
name = "csv"
version = "1.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1"
dependencies = [
"bstr",
"csv-core",
"itoa 0.4.8",
"ryu",
"serde",
]
[[package]]
name = "csv-core"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90"
dependencies = [
"memchr",
]
[[package]]
name = "digest"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90"
dependencies = [
"generic-array",
]
[[package]]
name = "dilithium"
version = "0.2.0-alpha.3"
dependencies = [
"arrayref",
"byteorder",
"criterion",
"digest",
"hex",
"itertools 0.7.11",
"once_cell",
"rand_core 0.6.4",
"rng256",
"sha3",
"structopt",
]
[[package]]
name = "either"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
[[package]]
name = "generic-array"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d00328cedcac5e81c683e5620ca6a30756fc23027ebf9bff405c0e8da1fbb7e"
dependencies = [
"typenum",
]
[[package]]
name = "half"
version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
[[package]]
name = "heck"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
dependencies = [
"unicode-segmentation",
]
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]]
name = "hex"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77"
[[package]]
name = "itertools"
version = "0.7.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d47946d458e94a1b7bcabbf6521ea7c037062c81f534615abcad76e84d4970d"
dependencies = [
"either",
]
[[package]]
name = "itertools"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4"
[[package]]
name = "itoa"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc"
[[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 = "keccak"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9b7d56ba4a8344d6be9729995e6b06f928af29998cdf79fe390cbf6b1fee838"
[[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.135"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c"
[[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 = "memoffset"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
dependencies = [
"autocfg 1.1.0",
]
[[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 = "num_cpus"
version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
dependencies = [
"hermit-abi",
"libc",
]
[[package]]
name = "once_cell"
version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f7254b99e31cad77da24b08ebf628882739a608578bb1bcdfc1f9c21260d7c0"
[[package]]
name = "oorandom"
version = "11.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
[[package]]
name = "plotters"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2538b639e642295546c50fcd545198c9d64ee2a38620a628724a3b266d5fbf97"
dependencies = [
"num-traits",
"plotters-backend",
"plotters-svg",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "plotters-backend"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142"
[[package]]
name = "plotters-svg"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9a81d2759aae1dae668f783c308bc5c8ebd191ff4184aaa1b37f65a6ae5a56f"
dependencies = [
"plotters-backend",
]
[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
"proc-macro-error-attr",
"proc-macro2",
"quote",
"syn",
"version_check",
]
[[package]]
name = "proc-macro-error-attr"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
"proc-macro2",
"quote",
"version_check",
]
[[package]]
name = "proc-macro2"
version = "1.0.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94e2ef8dbfc347b10c094890f778ee2e36ca9bb4262e86dc99cd217e35f3470b"
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_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
[[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 = "rayon"
version = "1.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d"
dependencies = [
"autocfg 1.1.0",
"crossbeam-deque",
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f"
dependencies = [
"crossbeam-channel",
"crossbeam-deque",
"crossbeam-utils",
"num_cpus",
]
[[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 = [
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
[[package]]
name = "regex-syntax"
version = "0.6.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
[[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 = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]]
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "serde"
version = "1.0.145"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b"
[[package]]
name = "serde_cbor"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5"
dependencies = [
"half",
"serde",
]
[[package]]
name = "serde_derive"
version = "1.0.145"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41feea4228a6f1cd09ec7a3593a682276702cd67b5273544757dae23c096f074"
dependencies = [
"itoa 1.0.4",
"ryu",
"serde",
]
[[package]]
name = "sha3"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b64dcef59ed4290b9fb562b53df07f564690d6539e8ecdd4728cf392477530bc"
dependencies = [
"block-buffer",
"byte-tools",
"digest",
"keccak",
]
[[package]]
name = "strsim"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]]
name = "structopt"
version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10"
dependencies = [
"clap",
"lazy_static",
"structopt-derive",
]
[[package]]
name = "structopt-derive"
version = "0.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0"
dependencies = [
"heck",
"proc-macro-error",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "syn"
version = "1.0.102"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fcd952facd492f9be3ef0d0b7032a6e442ee9b361d4acc2b1d0c4aaa5f613a1"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "textwrap"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
dependencies = [
"unicode-width",
]
[[package]]
name = "tinytemplate"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc"
dependencies = [
"serde",
"serde_json",
]
[[package]]
name = "typenum"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
[[package]]
name = "unicode-ident"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
[[package]]
name = "unicode-segmentation"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fdbf052a0783de01e944a6ce7a8cb939e295b1e7be835a1112c3b9a7f047a5a"
[[package]]
name = "unicode-width"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
[[package]]
name = "vec_map"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "walkdir"
version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
dependencies = [
"same-file",
"winapi",
"winapi-util",
]
[[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-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

34
third_party/dilithium/Cargo.toml vendored Normal file
View File

@@ -0,0 +1,34 @@
[package]
name = "dilithium"
version = "0.2.0-alpha.3"
authors = ["quininer <quininer@live.com>"]
description = "Digital Signatures from Module Lattices"
repository = "https://github.com/quininer/dilithium"
license = "MIT"
[dependencies]
rng256 = { path = "../../libraries/rng256" }
rand_core = { version = "0.6", default-features = false }
arrayref = {version = "0.3", default-features = false}
itertools = { version = "0.7", default-features = false }
byteorder = { version = "1", default-features = false }
sha3 = { version = "0.7.3", default-features = false }
digest = { version = "0.7", default-features = false }
[dev-dependencies]
hex = "0.3"
structopt = "0.3.25"
criterion = "0.3"
[features]
std = [ "rng256/std" ]
default = [ "dilithium5", "optimize_stack" ]
dilithium2 = []
dilithium3 = []
dilithium5 = []
optimize_stack = []
derive_debug = []
[[bench]]
name = "sign_bench"
harness = false

8
third_party/dilithium/LICENSE vendored Normal file
View File

@@ -0,0 +1,8 @@
MIT License
Copyright (c) 2017 quininer@live.com
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

7
third_party/dilithium/README.md vendored Normal file
View File

@@ -0,0 +1,7 @@
Dilithium
---------
Digital Signatures from Module Lattices
* [CRYSTALS Dilithium: Digital Signatures from Module Lattices](https://eprint.iacr.org/2017/633.pdf)
* [ref dilithium implemention](https://github.com/pq-crystals/dilithium)

View File

@@ -0,0 +1,70 @@
// Benchmarks for key generation and signing with Dilithium.
// cargo criterion --features std
extern crate core;
extern crate criterion;
extern crate dilithium;
extern crate rng256;
use core::time::Duration;
use criterion::*;
use dilithium::sign::SecKey;
use rng256::Rng256;
const SAMPLE_SIZE: usize = 1000;
const MEASUREMENT_TIME: Duration = Duration::from_secs(10);
fn bench_sk(c: &mut Criterion) {
let mut rng = rng256::ThreadRng256 {};
c.bench_function("gensk", |b| {
b.iter_batched(
|| {},
|_| {
SecKey::gensk(&mut rng);
},
BatchSize::SmallInput,
)
});
}
fn bench_pk(c: &mut Criterion) {
let mut rng = rng256::ThreadRng256 {};
c.bench_function("genpk", |b| {
b.iter_batched(
|| SecKey::gensk(&mut rng),
|sk| {
sk.genpk();
},
BatchSize::SmallInput,
)
});
}
fn bench_sign(c: &mut Criterion) {
const MESSAGE_LENGTH: usize = 64;
let mut rng = rng256::ThreadRng256 {};
c.bench_function("sign", |b| {
b.iter_batched(
|| {
let sk = SecKey::gensk(&mut rng);
let mut message = [0; MESSAGE_LENGTH];
rng.fill_bytes(&mut message);
(sk, message)
},
|(sk, message)| {
sk.sign(&message);
},
BatchSize::SmallInput,
)
});
}
criterion_group! {
name = benches;
config = Criterion::default().sample_size(SAMPLE_SIZE).measurement_time(MEASUREMENT_TIME);
targets = bench_sk, bench_pk, bench_sign
}
criterion_main!(benches);

41
third_party/dilithium/examples/sign.rs vendored Normal file
View File

@@ -0,0 +1,41 @@
// Command for changing the stack size:
// cargo run --example sign --features std -- --stack-size-kb (new value in KB)
extern crate dilithium;
extern crate rng256;
extern crate structopt;
use dilithium::sign::SecKey;
use rng256::Rng256;
use std::thread;
use structopt::StructOpt;
const DEFAULT_STACK_SIZE_KB: &str = "81";
#[derive(Debug, StructOpt)]
struct Opts {
#[structopt(long, default_value=DEFAULT_STACK_SIZE_KB)]
stack_size_kb: usize,
}
fn run() {
let mut rng = rng256::ThreadRng256 {};
let sk = SecKey::gensk(&mut rng);
let mut message = [0; 59];
rng.fill_bytes(&mut message);
sk.sign(&message);
}
fn main() {
let stack_size_kb = Opts::from_args().stack_size_kb;
// We bound the stack size for generating keys and signing in Dilithium.
let child = thread::Builder::new()
.stack_size(stack_size_kb * 1024)
.spawn(run)
.unwrap();
// Wait for thread to join
child.join().unwrap();
}

25
third_party/dilithium/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,25 @@
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(feature = "std")]
extern crate core;
#[macro_use]
extern crate arrayref;
extern crate byteorder;
extern crate digest;
extern crate itertools;
extern crate sha3;
#[macro_use]
mod utils;
mod ntt;
mod packing;
pub mod params;
mod poly;
mod polyvec;
mod reduce;
mod rounding;
pub mod sign;
#[cfg(test)]
mod test_mul;

94
third_party/dilithium/src/ntt.rs vendored Normal file
View File

@@ -0,0 +1,94 @@
use itertools::Itertools;
use params::N;
use reduce::montgomery_reduce;
const ZETAS: [i32; N] = [
0, 25847, -2608894, -518909, 237124, -777960, -876248, 466468, 1826347, 2353451, -359251,
-2091905, 3119733, -2884855, 3111497, 2680103, 2725464, 1024112, -1079900, 3585928, -549488,
-1119584, 2619752, -2108549, -2118186, -3859737, -1399561, -3277672, 1757237, -19422, 4010497,
280005, 2706023, 95776, 3077325, 3530437, -1661693, -3592148, -2537516, 3915439, -3861115,
-3043716, 3574422, -2867647, 3539968, -300467, 2348700, -539299, -1699267, -1643818, 3505694,
-3821735, 3507263, -2140649, -1600420, 3699596, 811944, 531354, 954230, 3881043, 3900724,
-2556880, 2071892, -2797779, -3930395, -1528703, -3677745, -3041255, -1452451, 3475950,
2176455, -1585221, -1257611, 1939314, -4083598, -1000202, -3190144, -3157330, -3632928, 126922,
3412210, -983419, 2147896, 2715295, -2967645, -3693493, -411027, -2477047, -671102, -1228525,
-22981, -1308169, -381987, 1349076, 1852771, -1430430, -3343383, 264944, 508951, 3097992,
44288, -1100098, 904516, 3958618, -3724342, -8578, 1653064, -3249728, 2389356, -210977, 759969,
-1316856, 189548, -3553272, 3159746, -1851402, -2409325, -177440, 1315589, 1341330, 1285669,
-1584928, -812732, -1439742, -3019102, -3881060, -3628969, 3839961, 2091667, 3407706, 2316500,
3817976, -3342478, 2244091, -2446433, -3562462, 266997, 2434439, -1235728, 3513181, -3520352,
-3759364, -1197226, -3193378, 900702, 1859098, 909542, 819034, 495491, -1613174, -43260,
-522500, -655327, -3122442, 2031748, 3207046, -3556995, -525098, -768622, -3595838, 342297,
286988, -2437823, 4108315, 3437287, -3342277, 1735879, 203044, 2842341, 2691481, -2590150,
1265009, 4055324, 1247620, 2486353, 1595974, -3767016, 1250494, 2635921, -3548272, -2994039,
1869119, 1903435, -1050970, -1333058, 1237275, -3318210, -1430225, -451100, 1312455, 3306115,
-1962642, -1279661, 1917081, -2546312, -1374803, 1500165, 777191, 2235880, 3406031, -542412,
-2831860, -1671176, -1846953, -2584293, -3724270, 594136, -3776993, -2013608, 2432395, 2454455,
-164721, 1957272, 3369112, 185531, -1207385, -3183426, 162844, 1616392, 3014001, 810149,
1652634, -3694233, -1799107, -3038916, 3523897, 3866901, 269760, 2213111, -975884, 1717735,
472078, -426683, 1723600, -1803090, 1910376, -1667432, -1104333, -260646, -3833893, -2939036,
-2235985, -420899, -2286327, 183443, -976891, 1612842, -3545687, -554416, 3919660, -48306,
-1362209, 3937738, 1400424, -846154, 1976782,
];
/// Implements forward NTT, in-place.
///
/// No modular reduction is performed after additions or substractions.
/// The output vector is in bitreversed order.
///
/// # Arguments
///
/// * `p` - a polynomial in standard representation.
pub fn ntt(p: &mut [i32; N]) {
let mut k = 1;
let mut len = 128;
while len > 0 {
for start in Itertools::step(0..N, 2 * len) {
let zeta = i64::from(ZETAS[k]);
k += 1;
for j in start..(start + len) {
let t = montgomery_reduce(zeta * i64::from(p[j + len]));
p[j + len] = p[j] - t;
p[j] += t;
}
}
len >>= 1;
}
}
/// Implements inverse NTT and multiplication by Montgomery factor 2^32.
///
/// The implementation is in-place.
/// No modular reduction is performed after additions or substractions.
/// Input coefficients must be smaller than Q in absolute value.
/// The output coefficients are smaller than Q in absolute value.
///
/// # Arguments
///
/// * `p` - a polynomial in NTT representation.
pub fn invntt_frominvmont(p: &mut [i32; N]) {
let mut k = 255;
let mut len = 1;
while len < N {
for start in Itertools::step(0..N, 2 * len) {
let zeta = (-1) * i64::from(ZETAS[k]);
k -= 1;
for j in start..(start + len) {
let t = p[j];
p[j] += p[j + len];
p[j + len] = t - p[j + len];
p[j + len] = montgomery_reduce(zeta * i64::from(p[j + len]));
}
}
len <<= 1;
}
// F = MONT^2 / 256 mod Q, where MONT = 2^32 mod Q.
const F: i64 = 41978;
for j in 0..N {
p[j] = montgomery_reduce(F * i64::from(p[j]));
}
}

164
third_party/dilithium/src/packing.rs vendored Normal file
View File

@@ -0,0 +1,164 @@
use params::{
K, L, N, OMEGA, PK_SIZE_PACKED, POLT1_SIZE_PACKED, POLZ_SIZE_PACKED, SEEDBYTES, SIG_SIZE_PACKED,
};
use poly::{self, Poly};
use polyvec::{PolyVecK, PolyVecL};
pub mod pk {
use super::*;
/// Decodes a public key with the shape: `pk || rho || encodings of t1`.
///
/// # Arguments
///
/// * `pk` - the encoded public key
/// * `rho` - output array for the randomness seed `rho`
/// * `t1` - output PolyVecK for the vector of polynomials `t1`
pub fn unpack(pk: &[u8; PK_SIZE_PACKED], rho: &mut [u8; SEEDBYTES], t1: &mut PolyVecK) {
let (rho_bytes, t1s_bytes) = array_refs!(pk, SEEDBYTES, POLT1_SIZE_PACKED * K);
rho.clone_from(rho_bytes);
for i in 0..K {
let t1_bytes = array_ref!(t1s_bytes, i * POLT1_SIZE_PACKED, POLT1_SIZE_PACKED);
poly::t1_unpack(&mut t1[i], t1_bytes);
}
}
}
// Encodes and Decodes a signature with the shape:
// c_seed || encodings of z || encodings of h
pub mod sign {
use super::*;
/// Encodes an array used to obtain the challenge `c`.
///
/// # Arguments
///
/// * `sig` - the output array representing the encoded signature
/// * `c_seed` - array to be encoded
pub fn pack_c(sign: &mut [u8; SIG_SIZE_PACKED], c_seed: &[u8; SEEDBYTES]) {
let c_bytes = array_mut_ref!(sign, 0, SEEDBYTES);
for i in 0..SEEDBYTES {
c_bytes[i] = c_seed[i];
}
}
/// Encodes `z[i]`, where z is a vector of `L` polynomials.
///
/// # Arguments
///
/// * `sig` - output array representing the encoded signature
/// * `z_component` - polynomial representing `z[i]`
/// * `i` - the index of the component to be encoded
pub fn pack_z_component(sign: &mut [u8; SIG_SIZE_PACKED], z_component: &Poly, i: usize) {
let z_bytes = array_mut_ref!(sign, SEEDBYTES + i * POLZ_SIZE_PACKED, POLZ_SIZE_PACKED);
poly::z_pack(z_bytes, &z_component);
}
/// Encodes `z`, where `z` is a vector of `L` polynomials.
///
/// # Arguments
///
/// * `sig` - output array representing the encoded signature
/// * `z` - vector of `L` polynomials`
#[cfg(not(feature = "optimize_stack"))]
pub fn pack_z(sign: &mut [u8; SIG_SIZE_PACKED], z: &PolyVecL) {
for i in 0..L {
pack_z_component(sign, &z[i], i);
}
}
/// Encodes `h[i]`, where `h` is a vector of `K` polynomials.
///
/// # Arguments
///
/// * `sig` - output array representing the encoded signature
/// * `h_component` - polynomial representing `h[i]`
/// * `i` - the index of the component to be encoded
/// * `non_zero_coeff_index` - the index returned when encoding
/// `h[i - 1]` (0 if `i` = 0)
pub fn pack_h_component(
sign: &mut [u8; SIG_SIZE_PACKED],
h_component: &Poly,
i: usize,
non_zero_coeff_index: &mut usize,
) {
let h_bytes = array_mut_ref!(sign, SEEDBYTES + POLZ_SIZE_PACKED * L, OMEGA + K);
for j in 0..N {
if h_component[j] != 0 {
h_bytes[*non_zero_coeff_index] = j as u8;
*non_zero_coeff_index += 1;
}
}
h_bytes[OMEGA + i] = *non_zero_coeff_index as u8;
}
/// Encodes `h`, where `h` is a vector of `K` polynomials.
///
/// # Arguments
///
/// * `sig` - output array representing the encoded signature
/// * `h` - vector of `K` polynomials.
#[cfg(not(feature = "optimize_stack"))]
pub fn pack_h(sign: &mut [u8; SIG_SIZE_PACKED], h: &PolyVecK) {
let mut non_zero_coeff_index = 0;
for i in 0..K {
pack_h_component(sign, &h[i], i, &mut non_zero_coeff_index);
}
}
/// Decodes the components of the signature.
///
/// The values are written into the output arguments `c_seed`,
/// `z`, and `h` from `sig`.
///
/// # Arguments
///
/// * `sig` - the encoded signature
/// * `c_seed` - output array for the seed used to compute the challenge
/// * `z` - output PolyVecL for the vector of polynomials `z`
/// * `h` - output PolyVecK for the vector of polynomials `h`
pub fn unpack(
sign: &[u8; SIG_SIZE_PACKED],
c_seed: &mut [u8; SEEDBYTES],
z: &mut PolyVecL,
h: &mut PolyVecK,
) -> bool {
let (c_bytes, z_bytes, h_bytes) =
array_refs!(sign, SEEDBYTES, POLZ_SIZE_PACKED * L, OMEGA + K);
for i in 0..SEEDBYTES {
c_seed[i] = c_bytes[i];
}
for i in 0..L {
let z_bytes = array_ref!(z_bytes, i * POLZ_SIZE_PACKED, POLZ_SIZE_PACKED);
poly::z_unpack(&mut z[i], z_bytes);
}
// Decode h
let mut k = 0;
for i in 0..K {
if (h_bytes[OMEGA + i] as usize) < k || (h_bytes[OMEGA + i] as usize) > OMEGA {
return false;
}
for j in k..(h_bytes[OMEGA + i] as usize) {
// Coefficients are ordered for strong unforgeability
if j > k && h_bytes[j] <= h_bytes[j - 1] {
return false;
}
h[i][h_bytes[j] as usize] = 1;
}
k = h_bytes[OMEGA + i] as usize;
}
// Extra indices are zero for strong unforgeability
if h_bytes[k..OMEGA].iter().any(|&v| v != 0) {
return false;
}
true
}
}

78
third_party/dilithium/src/params.rs vendored Normal file
View File

@@ -0,0 +1,78 @@
#![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))]
pub const SEEDBYTES: usize = 32;
pub const CRHBYTES: usize = 64;
pub const N: usize = 256;
pub const Q: i32 = 8380417;
pub const D: usize = 13;
pub const ROOT_OF_UNITY: usize = 1753;
#[cfg(feature = "dilithium2")]
mod mode {
use super::Q;
pub const K: usize = 4;
pub const L: usize = 4;
pub const ETA: i32 = 2;
pub const TAU: usize = 39;
pub const BETA: i32 = 78;
pub const GAMMA1: i32 = 1 << 17;
pub const GAMMA2: i32 = (Q - 1) / 88;
pub const OMEGA: usize = 80;
pub const POLZ_SIZE_PACKED: usize = 576;
pub const POLW1_SIZE_PACKED: usize = 192;
pub const POLETA_SIZE_PACKED: usize = 96;
}
#[cfg(feature = "dilithium3")]
mod mode {
use super::Q;
pub const K: usize = 6;
pub const L: usize = 5;
pub const ETA: i32 = 4;
pub const TAU: usize = 49;
pub const BETA: i32 = 196;
pub const GAMMA1: i32 = 1 << 19;
pub const GAMMA2: i32 = (Q - 1) / 32;
pub const OMEGA: usize = 55;
pub const POLZ_SIZE_PACKED: usize = 640;
pub const POLW1_SIZE_PACKED: usize = 128;
pub const POLETA_SIZE_PACKED: usize = 128;
}
#[cfg(feature = "dilithium5")]
mod mode {
use super::Q;
pub const K: usize = 8;
pub const L: usize = 7;
pub const ETA: i32 = 2;
pub const TAU: usize = 60;
pub const BETA: i32 = 120;
pub const GAMMA1: i32 = 1 << 19;
pub const GAMMA2: i32 = (Q - 1) / 32;
pub const OMEGA: usize = 75;
pub const POLZ_SIZE_PACKED: usize = 640;
pub const POLW1_SIZE_PACKED: usize = 128;
pub const POLETA_SIZE_PACKED: usize = 96;
}
pub use self::mode::*;
pub const POLT1_SIZE_PACKED: usize = 320;
pub const POLT0_SIZE_PACKED: usize = 416;
pub const PK_SIZE_PACKED: usize = SEEDBYTES + K * POLT1_SIZE_PACKED;
pub const SK_SIZE_PACKED: usize = 3 * SEEDBYTES + (L + K) * POLETA_SIZE_PACKED;
pub const SK_SIZE_PACKED_ORIGINAL: usize =
3 * SEEDBYTES + (L + K) * POLETA_SIZE_PACKED + K * POLT0_SIZE_PACKED;
pub const SIG_SIZE_PACKED: usize = L * POLZ_SIZE_PACKED + (OMEGA + K) + SEEDBYTES;
pub const PUBLICKEYBYTES: usize = PK_SIZE_PACKED;
pub const SECRETKEYBYTES: usize = SK_SIZE_PACKED;
pub const BYTES: usize = SIG_SIZE_PACKED;
/// `MONT = 2^32 mod Q`
pub const MONT: i64 = -4186625;
pub const QINV: isize = 58728449;

775
third_party/dilithium/src/poly.rs vendored Normal file
View File

@@ -0,0 +1,775 @@
use byteorder::{ByteOrder, LittleEndian};
pub use ntt::{invntt_frominvmont as invntt_montgomery, ntt};
use params::{
CRHBYTES, D, ETA, GAMMA1, GAMMA2, N, POLETA_SIZE_PACKED, POLT1_SIZE_PACKED, POLW1_SIZE_PACKED,
POLZ_SIZE_PACKED, Q, SEEDBYTES, TAU,
};
use reduce::{caddq as xcaddq, freeze as xfreeze, montgomery_reduce, reduce32};
use rounding;
pub type Poly = [i32; N];
/// Reduces the coefficients of the polynomial `a` to [-6283009,6283007].
///
/// # Arguments
///
/// * `a` - a polynomial
pub fn reduce(a: &mut Poly) {
for i in 0..N {
a[i] = reduce32(a[i]);
}
}
/// Adds `Q` to every negative coefficient in `a`.
///
/// # Arguments
///
/// * `a` - a polynomial
pub fn caddq(a: &mut Poly) {
for i in 0..N {
a[i] = xcaddq(a[i]);
}
}
/// For every coefficient `x` in `a`, computes `x mod Q`.
///
/// # Arguments
///
/// * `a` - a polynomial
pub fn freeze(a: &mut Poly) {
for i in 0..N {
a[i] = xfreeze(a[i]);
}
}
/// Computes `c = a + b`, where `c`, `a`, and `b` are polynomials.
///
/// # Arguments
///
/// * `a` - a polynomial
pub fn add(c: &mut Poly, a: &Poly, b: &Poly) {
for i in 0..N {
c[i] = a[i] + b[i];
}
}
/// Computes `c = c + a`, where `c`, and `a` are polynomials.
///
/// # Arguments
///
/// * `a` - a polynomial
pub fn add_assign(c: &mut Poly, a: &Poly) {
for i in 0..N {
c[i] += a[i];
}
}
/// Computes `c = a - b`, where `c`, `a` and `b` are polynomials.
///
/// # Arguments
///
/// * `a` - a polynomial
pub fn sub(c: &mut Poly, a: &Poly, b: &Poly) {
for i in 0..N {
c[i] = a[i] - b[i];
}
}
/// Multiplies the polynomial `a` by `2^D` without modular reduction.
///
/// # Arguments
///
/// * `a` - a polynomial with coefficients smaller than than 2^{31-D}
/// in absolute value
pub fn shift_left(a: &mut Poly) {
for i in 0..N {
a[i] <<= D;
}
}
/// Computes `c = a * b` in NTT domain representation.
///
/// # Arguments
///
/// * `c` - the output polynomial, in NTT domain representation
/// * `a` - a polynomial in NTT domain representation
/// * `b` - a polynomial in NTT domain representation
pub fn pointwise_invmontgomery(c: &mut Poly, a: &Poly, b: &Poly) {
for i in 0..N {
c[i] = montgomery_reduce((a[i] as i64) * (b[i] as i64));
}
}
/// Returns `c = a * b` in standard representation.
///
/// # Arguments
///
/// * `a` - a polynomial in NTT domain representation
/// * `b` - a polynomial in NTT domain representation
pub fn multiply(a: &Poly, b: &Poly) -> Poly {
let mut c = [0; N];
pointwise_invmontgomery(&mut c, a, b);
invntt_montgomery(&mut c);
reduce(&mut c);
c
}
/// Decomposes a into the quotient and remainder of its division with `2^{D-1}`.
///
/// For every coefficient `c` of the polynomial `a`, computes `c0`, `c1`
/// such that `c mod Q = c1 * 2^D + c0`, with `-2^{D-1} < c0 <= 2^{D-1}`.
///
/// # Arguments
///
/// * `a` - a polynomial in standard representation (not NTT)
/// * `a0` - output polynomial representing the remainder (coefficients `c0`)
/// * `a1` - output polynomial representing the quotient (coefficients `c1`)
pub fn power2round(a: &Poly, a0: &mut Poly, a1: &mut Poly) {
for i in 0..N {
let (x, y) = rounding::power2round(a[i]);
a0[i] = x;
a1[i] = y;
}
}
/// Obtains the remainder of dividing `a` with `2^{D-1}`.
///
/// For every coefficient `c` of the polynomial a, computes `c0`, `c1`
/// such that `c mod Q = c1 * 2^D + c0`, with `-2^{D-1} < c0 <= 2^{D-1}`.
///
/// # Arguments
///
/// * `a` - a polynomial in standard representation (not NTT)
/// * `a0` - output polynomial representing the remainder (coefficients `c0`)
pub fn power2round_remainder(a: &Poly) -> Poly {
let mut remainder = [0; N];
for i in 0..N {
let (x, _) = rounding::power2round(a[i]);
remainder[i] = x;
}
remainder
}
/// Obtains the quotient of dividing `a` with `2^{D-1}`.
///
/// For every coefficient `c` of the polynomial `a`, computes `c0, c1`
/// such that `c mod Q = c1 * 2^D + c0`, with `-2^{D-1} < c0 <= 2^{D-1}`.
///
/// # Arguments
///
/// * `a` - a polynomial in standard representation (not NTT)
/// * `a1` - output polynomial representing the quotient (coefficients `c1`)
pub fn power2round_quotient(a: &Poly) -> Poly {
let mut quotient = [0; N];
for i in 0..N {
let (_, y) = rounding::power2round(a[i]);
quotient[i] = y;
}
quotient
}
/// Obtains the high bits and the low bits of `a`.
///
/// For every coefficient `c` of the input polynomial `a`, computes its
/// high bits `c1` and low bits `c0` such that `c mod Q = c1*ALPHA + c0`,
/// where -ALPHA/2 < c0 <= ALPHA/2.
/// Exception: if `c1 = (Q-1)/ALPHA`, `c1` is set to 0 and `c0 = c mod Q - Q`.
///
/// # Arguments
///
/// * `a` - a polynomial in standard representation (not NTT)
/// * `a0` - output polynomial representing `a`'s low bits (coefficients `c0`)
/// * `a1` - output polynomial representing `a`'s high bits (coefficients `c1`)
pub fn decompose(a: &Poly, a0: &mut Poly, a1: &mut Poly) {
for i in 0..N {
let (x, y) = rounding::decompose(a[i]);
a0[i] = x; // low bits
a1[i] = y; // high bits
}
}
/// Returns a polynomial whose coefficients are the high bits of `a`.
///
/// For every coefficient `c` of the input polynomial a, computes its
/// high bits `c1` and low bits `c0` such that `c mod Q = c1*ALPHA + c0`,
/// where `-ALPHA/2 < c0 <= ALPHA/2`.
/// Exception: if `c1 = (Q-1)/ALPHA`, `c1` is set to 0 and `c0 = c mod Q - Q`.
///
/// # Arguments
///
/// * `a` - a polynomial in standard representation (not NTT)
#[cfg(feature = "optimize_stack")]
pub fn high_bits(a: &Poly) -> Poly {
let mut high_bits: Poly = [0; N];
for i in 0..N {
let (_x, y) = rounding::decompose(a[i]);
high_bits[i] = y;
}
return high_bits;
}
/// Returns a polynomial whose coefficients are the low bits of `a`.
///
/// For every coefficient `c` of the input polynomial `a`, computes its
/// high bits `c1` and low bits `c0` such that `c mod Q = c1*ALPHA + c0`,
/// where `-ALPHA/2 < c0 <= ALPHA/2`.
/// Exception: if `c1 = (Q-1)/ALPHA`, `c1` is set to 0 and `c0 = c mod Q - Q`.
///
/// # Arguments
///
/// * `a` - a polynomial in standard representation (not NTT)
#[cfg(feature = "optimize_stack")]
pub fn low_bits(a: &Poly) -> Poly {
let mut low_bits: Poly = [0; N];
for i in 0..N {
let (x, _y) = rounding::decompose(a[i]);
low_bits[i] = x;
}
return low_bits;
}
/// Makes the hint used to obtain `a` from an approximate result `b`.
///
/// Given a polynomial of low bits `a`, and a polynomial of high bits `b`,
/// computes the hint polynomial `h`. The coefficient of `h` indicate
/// whether the low bits of the corresponding coefficient of the input
/// polynomial `a` overflow into the high bits (`b`).
///
/// # Arguments
///
/// * `a` - a polynomial
/// * `b` - a polynomial
/// * `h` - the output polynomial
pub fn make_hint(a: &Poly, b: &Poly, h: &mut Poly) -> usize {
let mut s = 0;
for i in 0..N {
h[i] = rounding::make_hint(a[i], b[i]) as i32;
s += h[i] as usize;
}
s
}
/// Uses a hint polynomial `h` to correct the high bits of a polynomial `b`.
///
/// # Arguments
///
/// * `a` - the output corrected polynomial
/// * `b` - a polynomial
/// * `h` - the hint polynomial: containing values 0 or 1
pub fn use_hint(a: &mut Poly, b: &Poly, h: &Poly) {
for i in 0..N {
a[i] = rounding::use_hint(b[i], h[i] as u32);
}
}
/// Checks if the infinity norm of a polynomial `a` against a given bound `b`.
///
/// The input coefficients must be reduced by `reduce32()`.
///
/// # Arguments
///
/// * `a` - a polynomial
/// * `b` - the bound.
pub fn chknorm(a: &Poly, b: i32) -> bool {
if b > (Q - 1) / 8 {
return true;
}
// It is ok to leak which coefficient violates the bound since
// the probability for each coefficient is independent of secret
// data but we must not leak the sign of the centralized representative.
for i in 0..N {
let mut t: i32 = a[i] >> 31;
t = a[i] - (t & 2 * a[i]);
if t >= b {
return true;
}
}
return false;
}
/// Samples a polynomial with random coefficients in `[0, Q - 1]`.
///
/// The sampling is done by performing rejection sampling on the output stream
/// of `SHAKE256(seed|nonce)`.
///
/// # Arguments
///
/// * `a` - the output polynomial
/// * `seed` - an array of random bytes
/// * `nonce` - a number.
pub fn uniform(a: &mut Poly, seed: &[u8; SEEDBYTES], nonce: u16) {
use digest::{ExtendableOutput, Input, XofReader};
use sha3::Shake128;
fn rej_uniform(a: &mut [i32], i_start: usize, buf: &[u8], buf_len: usize) -> usize {
let mut ctr = 0usize;
let mut pos = 0usize;
let mut t: u32;
let len = a.len() - i_start;
while ctr < len && pos + 3 <= buf_len {
t = buf[pos] as u32;
pos += 1;
t |= (buf[pos] as u32) << 8;
pos += 1;
t |= (buf[pos] as u32) << 16;
pos += 1;
t &= 0x7FFFFF;
if t < (Q as u32) {
a[i_start + ctr] = t as i32;
ctr += 1;
}
}
ctr
}
let mut hasher = Shake128::default();
hasher.process(seed);
let nonce0 = (nonce & ((1 << 8) - 1)) as u8;
let nonce1 = (nonce >> 8) as u8;
hasher.process(&[nonce0, nonce1]);
const STREAM128_BLOCKBYTES: usize = 168;
const POLY_UNIFORM_NBLOCKS: usize = (768 + STREAM128_BLOCKBYTES - 1) / STREAM128_BLOCKBYTES;
let mut buf_len = POLY_UNIFORM_NBLOCKS * STREAM128_BLOCKBYTES;
let mut buf = [0u8; POLY_UNIFORM_NBLOCKS * STREAM128_BLOCKBYTES + 2];
let mut xof = hasher.xof_result();
xof.read(&mut buf[..buf_len]);
let mut ctr = rej_uniform(a, 0, &buf, buf_len);
while ctr < N {
let off = buf_len % 3;
for i in 0..off {
buf[i] = buf[buf_len - off + i];
}
for i in 0..STREAM128_BLOCKBYTES {
buf[off + i] = 0;
}
xof.read(&mut buf[off..off + STREAM128_BLOCKBYTES]);
buf_len = STREAM128_BLOCKBYTES + off;
ctr += rej_uniform(a, ctr, &buf, buf_len);
}
}
/// Samples a polynomial with random coefficients in `[-ETA, ETA]`.
///
/// The sampling is done by performing rejection sampling on the output stream
/// of `SHAKE256(seed|nonce)`.
///
/// # Arguments
///
/// * `a` - the output polynomial
/// * `seed` - an array of random bytes
/// * `nonce` - a number.
pub fn uniform_eta(a: &mut Poly, seed: &[u8; CRHBYTES], nonce: u16) {
use digest::{ExtendableOutput, Input, XofReader};
use sha3::Shake256;
const STREAM256_BLOCKBYTES: usize = 136;
const POLY_UNIFORM_ETA_NBLOCKS: usize = match ETA {
2 => (136 + STREAM256_BLOCKBYTES - 1) / STREAM256_BLOCKBYTES,
_ => (227 + STREAM256_BLOCKBYTES - 1) / STREAM256_BLOCKBYTES,
};
fn rej_eta(a: &mut [i32], a_start: usize, buf: &[u8], buf_len: usize) -> usize {
let mut ctr = 0;
let mut pos = 0;
while a_start + ctr < a.len() && pos < buf_len {
let mut t0 = (buf[pos] as u32) & 0x0F;
let mut t1 = (buf[pos] as u32) >> 4;
pos += 1;
if ETA == 2 {
if t0 < 15 {
t0 = t0 - (205 * t0 >> 10) * 5;
a[a_start + ctr] = 2 - (t0 as i32);
ctr += 1;
}
if t1 < 15 && a_start + ctr < a.len() {
t1 = t1 - (205 * t1 >> 10) * 5;
a[a_start + ctr] = 2 - (t1 as i32);
ctr += 1;
}
} else if ETA == 4 {
if t0 < 9 {
a[a_start + ctr] = 4 - (t0 as i32);
ctr += 1;
}
if t1 < 9 && a_start + ctr < a.len() {
a[a_start + ctr] = 4 - (t1 as i32);
ctr += 1;
}
}
}
ctr
}
let buf_len = POLY_UNIFORM_ETA_NBLOCKS * STREAM256_BLOCKBYTES;
let mut buf = [0u8; POLY_UNIFORM_ETA_NBLOCKS * STREAM256_BLOCKBYTES];
let mut hasher = Shake256::default();
hasher.process(seed);
let nonce0 = (nonce & ((1 << 8) - 1)) as u8;
let nonce1 = (nonce >> 8) as u8;
hasher.process(&[nonce0, nonce1]);
let mut xof = hasher.xof_result();
xof.read(&mut buf[..buf_len]);
let mut ctr = rej_eta(a, 0, &buf, buf_len);
while ctr < N {
xof.read(&mut buf[..STREAM256_BLOCKBYTES]);
ctr += rej_eta(a, ctr, &buf, STREAM256_BLOCKBYTES);
}
}
/// Samples a polynomial with random coefficients in `[-(GAMMA1 - 1), GAMMA1]`.
///
/// The sampling is done by unpacking the first `POLZ_SIZE_PACKED` bytes in the
/// output stream of `SHAKE256(seed|nonce)`.
///
/// # Arguments
///
/// * `a` - the output polynomial
/// * `seed` - an array of random bytes
/// * `nonce` - a number.
pub fn uniform_gamma1m1(a: &mut Poly, seed: &[u8; CRHBYTES], nonce: u16) {
use digest::{ExtendableOutput, Input, XofReader};
use sha3::Shake256;
const SHAKE256_RATE: usize = 136;
let mut outbuf = [0; 5 * SHAKE256_RATE];
let mut nonce_bytes = [0; 2];
LittleEndian::write_u16(&mut nonce_bytes, nonce);
let mut hasher = Shake256::default();
hasher.process(seed);
hasher.process(&nonce_bytes);
let mut xof = hasher.xof_result();
xof.read(&mut outbuf);
z_unpack(a, array_ref!(&outbuf, 0, POLZ_SIZE_PACKED));
}
/// Returns a polynomial with coefficients in {0, -1, 1}.
///
/// Returns a polynomial sampled with `TAU` nonzero coefficients in
/// {-1, 1} and `N - TAU` zero coefficients using the output stream
/// of `SHAKE256(seed)`.
/// More details can be found in the paper, in section 2.3.
/// <https://eprint.iacr.org/2017/633.pdf>
///
/// # Arguments
///
/// * `seed` - an array of bytes
pub fn build_challenge_from_seed(seed: &[u8; SEEDBYTES]) -> Poly {
use digest::{ExtendableOutput, Input, XofReader};
use sha3::Shake256;
const SHAKE256_RATE: usize = 136;
let mut outbuf = [0u8; SHAKE256_RATE];
let mut hasher = Shake256::default();
hasher.process(seed);
let mut xof = hasher.xof_result();
xof.read(&mut outbuf);
let mut signs: u64 = 0;
for i in 0..8 {
signs |= (outbuf[i] as u64) << 8 * i;
}
let mut pos = 8;
let mut c = [0i32; N];
for i in (N - TAU)..N {
let b = loop {
if pos >= SHAKE256_RATE {
xof.read(&mut outbuf);
pos = 0;
}
let b = outbuf[pos] as usize;
pos += 1;
if b <= i {
break b;
}
};
c[i] = c[b];
c[b] = 1i32 - (2 * (signs & 1) as i32);
signs >>= 1;
}
c
}
/// Bit-packs a polynomial with coefficients in `[-ETA, ETA]`.
///
/// # Arguments
///
/// * `r` - the output array, which will contain the polynomial's encoding
/// * `a` - the polynomial to encode
#[inline]
pub fn eta_pack(r: &mut [u8; POLETA_SIZE_PACKED], a: &Poly) {
if ETA == 2 {
let mut t = [0u8; 8];
for i in 0..(N / 8) {
for j in 0..8 {
t[j] = (ETA - a[8 * i + j]) as u8;
}
r[3 * i + 0] = (t[0] >> 0) | (t[1] << 3) | (t[2] << 6);
r[3 * i + 1] = (t[2] >> 2) | (t[3] << 1) | (t[4] << 4) | (t[5] << 7);
r[3 * i + 2] = (t[5] >> 1) | (t[6] << 2) | (t[7] << 5);
}
} else {
let mut t = [0u8; 2];
for i in 0..(N / 2) {
t[0] = (ETA - a[2 * i + 0]) as u8;
t[1] = (ETA - a[2 * i + 1]) as u8;
r[i] = t[0] | (t[1] << 4);
}
}
}
/// Unpacks a polynomial with coefficients in `[-ETA, ETA]`.
///
/// # Arguments
///
/// * `r` - the output decoded polynomial
/// * `a` - the polynomial's encoding
#[inline]
pub fn eta_unpack(r: &mut Poly, a: &[u8; POLETA_SIZE_PACKED]) {
if ETA == 2 {
for i in 0..(N / 8) {
r[8 * i + 0] = ((a[3 * i + 0] as i32) >> 0) & 7;
r[8 * i + 1] = ((a[3 * i + 0] as i32) >> 3) & 7;
r[8 * i + 2] = (((a[3 * i + 0] as i32) >> 6) | ((a[3 * i + 1] as i32) << 2)) & 7;
r[8 * i + 3] = ((a[3 * i + 1] as i32) >> 1) & 7;
r[8 * i + 4] = ((a[3 * i + 1] as i32) >> 4) & 7;
r[8 * i + 5] = (((a[3 * i + 1] as i32) >> 7) | ((a[3 * i + 2] as i32) << 1)) & 7;
r[8 * i + 6] = ((a[3 * i + 2] as i32) >> 2) & 7;
r[8 * i + 7] = ((a[3 * i + 2] as i32) >> 5) & 7;
for j in 0..8 {
r[8 * i + j] = ETA - r[8 * i + j];
}
}
} else {
for i in 0..(N / 2) {
r[2 * i + 0] = (a[i] as i32) & 0x0F;
r[2 * i + 1] = (a[i] as i32) >> 4;
r[2 * i + 0] = ETA - r[2 * i + 0];
r[2 * i + 1] = ETA - r[2 * i + 1];
}
}
}
/// Bit-packs a polynomial with coefficients fitting in 10 bits.
///
/// # Arguments
///
/// * `r` - the output array, which will contain the polynomial's encoding
/// * `a` - the polynomial to encode
#[inline]
pub fn t1_pack(r: &mut [u8; POLT1_SIZE_PACKED], a: &Poly) {
for i in 0..(N / 4) {
r[5 * i + 0] = (a[4 * i + 0] >> 0) as u8;
r[5 * i + 1] = ((a[4 * i + 0] >> 8) | (a[4 * i + 1] << 2)) as u8;
r[5 * i + 2] = ((a[4 * i + 1] >> 6) | (a[4 * i + 2] << 4)) as u8;
r[5 * i + 3] = ((a[4 * i + 2] >> 4) | (a[4 * i + 3] << 6)) as u8;
r[5 * i + 4] = (a[4 * i + 3] >> 2) as u8;
}
}
/// Unpacks a polynomial with coefficients fitting in 10 bits.
///
/// # Arguments
///
/// * `r` - the output decoded polynomial
/// * `a` - the polynomial's encoding
#[inline]
pub fn t1_unpack(r: &mut Poly, a: &[u8; POLT1_SIZE_PACKED]) {
for i in 0..(N / 4) {
r[4 * i + 0] =
((((a[5 * i + 0] >> 0) as u32) | ((a[5 * i + 1] as u32) << 8)) & 0x3FF) as i32;
r[4 * i + 1] =
((((a[5 * i + 1] >> 2) as u32) | ((a[5 * i + 2] as u32) << 6)) & 0x3FF) as i32;
r[4 * i + 2] =
((((a[5 * i + 2] >> 4) as u32) | ((a[5 * i + 3] as u32) << 4)) & 0x3FF) as i32;
r[4 * i + 3] =
((((a[5 * i + 3] >> 6) as u32) | ((a[5 * i + 4] as u32) << 2)) & 0x3FF) as i32;
}
}
/// Packs a polynomial with coefficients in `[-(GAMMA1 - 1), GAMMA1]`.
///
/// # Arguments
///
/// * `r` - the output array, which will contain the polynomial's encoding
/// * `a` - the polynomial to encode
#[inline]
pub fn z_pack(r: &mut [u8; POLZ_SIZE_PACKED], a: &Poly) {
let mut t = [0u32; 4];
if GAMMA1 == (1 << 17) {
for i in 0..(N / 4) {
for j in 0..4 {
t[j] = (GAMMA1 - a[4 * i + j]) as u32;
}
r[9 * i + 0] = t[0] as u8;
r[9 * i + 1] = (t[0] >> 8) as u8;
r[9 * i + 2] = (t[0] >> 16) as u8;
r[9 * i + 2] |= (t[1] << 2) as u8;
r[9 * i + 3] = (t[1] >> 6) as u8;
r[9 * i + 4] = (t[1] >> 14) as u8;
r[9 * i + 4] |= (t[2] << 4) as u8;
r[9 * i + 5] = (t[2] >> 4) as u8;
r[9 * i + 6] = (t[2] >> 12) as u8;
r[9 * i + 6] |= (t[3] << 6) as u8;
r[9 * i + 7] = (t[3] >> 2) as u8;
r[9 * i + 8] = (t[3] >> 10) as u8;
}
} else if GAMMA1 == (1 << 19) {
for i in 0..(N / 2) {
t[0] = (GAMMA1 - a[2 * i + 0]) as u32;
t[1] = (GAMMA1 - a[2 * i + 1]) as u32;
r[5 * i + 0] = t[0] as u8;
r[5 * i + 1] = (t[0] >> 8) as u8;
r[5 * i + 2] = (t[0] >> 16) as u8;
r[5 * i + 2] |= (t[1] << 4) as u8;
r[5 * i + 3] = (t[1] >> 4) as u8;
r[5 * i + 4] = (t[1] >> 12) as u8;
}
}
}
/// Unpacks a polynomial with coefficients in `[-(GAMMA1 - 1), GAMMA1]`.
///
/// # Arguments
///
/// * `r` - the output decoded polynomial
/// * `a` - the polynomial's encoding
#[inline]
pub fn z_unpack(r: &mut Poly, a: &[u8; POLZ_SIZE_PACKED]) {
if GAMMA1 == (1 << 17) {
for i in 0..(N / 4) {
r[4 * i + 0] = a[9 * i + 0] as i32;
r[4 * i + 0] |= (a[9 * i + 1] as i32) << 8;
r[4 * i + 0] |= (a[9 * i + 2] as i32) << 16;
r[4 * i + 0] &= 0x3FFFF;
r[4 * i + 1] = (a[9 * i + 2] >> 2) as i32;
r[4 * i + 1] |= (a[9 * i + 3] as i32) << 6;
r[4 * i + 1] |= (a[9 * i + 4] as i32) << 14;
r[4 * i + 1] &= 0x3FFFF;
r[4 * i + 2] = (a[9 * i + 4] >> 4) as i32;
r[4 * i + 2] |= (a[9 * i + 5] as i32) << 4;
r[4 * i + 2] |= (a[9 * i + 6] as i32) << 12;
r[4 * i + 2] &= 0x3FFFF;
r[4 * i + 3] = (a[9 * i + 6] >> 6) as i32;
r[4 * i + 3] |= (a[9 * i + 7] as i32) << 2;
r[4 * i + 3] |= (a[9 * i + 8] as i32) << 10;
r[4 * i + 3] &= 0x3FFFF;
for j in 0..4 {
r[4 * i + j] = GAMMA1 - r[4 * i + j];
}
}
} else if GAMMA1 == (1 << 19) {
for i in 0..(N / 2) {
r[2 * i + 0] = a[5 * i + 0] as i32;
r[2 * i + 0] |= (a[5 * i + 1] as i32) << 8;
r[2 * i + 0] |= (a[5 * i + 2] as i32) << 16;
r[2 * i + 0] &= 0xFFFFF;
r[2 * i + 1] = (a[5 * i + 2] >> 4) as i32;
r[2 * i + 1] |= (a[5 * i + 3] as i32) << 4;
r[2 * i + 1] |= (a[5 * i + 4] as i32) << 12;
r[2 * i + 0] &= 0xFFFFF;
r[2 * i + 0] = GAMMA1 - r[2 * i + 0];
r[2 * i + 1] = GAMMA1 - r[2 * i + 1];
}
}
}
/// Bit-packs a polynomial with coefficients in `[0,15]` or `[0,43]`.
///
/// # Arguments
///
/// * `r` - the output array, which will contain the polynomial's encoding
/// * `a` - the polynomial to encode
#[inline]
pub fn w1_pack(r: &mut [u8; POLW1_SIZE_PACKED], a: &Poly) {
if GAMMA2 == (Q - 1) / 88 {
for i in 0..(N / 4) {
r[3 * i + 0] = a[4 * i + 0] as u8;
r[3 * i + 0] |= (a[4 * i + 1] << 6) as u8;
r[3 * i + 1] = (a[4 * i + 1] >> 2) as u8;
r[3 * i + 1] |= (a[4 * i + 2] << 4) as u8;
r[3 * i + 2] = (a[4 * i + 2] >> 4) as u8;
r[3 * i + 2] |= (a[4 * i + 3] << 2) as u8;
}
} else if GAMMA2 == (Q - 1) / 32 {
for i in 0..(N / 2) {
r[i] = (a[2 * i + 0] | (a[2 * i + 1] << 4)) as u8;
}
}
}
/// Bit-packs a polynomial `t0` with coefficients in `[-2^{D-1}, 2^{D-1}]`.
///
/// # Arguments
///
/// * `r` - the output array, which will contain the polynomial's encoding
/// * `a` - the polynomial to encode
#[inline]
pub fn t0_pack(r: &mut [u8], a: &Poly) {
let mut t = [0u32; 8];
for i in 0..(N / 8) {
for j in 0..8 {
t[j] = ((1 << (D - 1) as u32) - a[8 * i + j]) as u32;
}
r[13 * i + 0] = (t[0]) as u8;
r[13 * i + 1] = (t[0] >> 8) as u8;
r[13 * i + 1] |= (t[1] << 5) as u8;
r[13 * i + 2] = (t[1] >> 3) as u8;
r[13 * i + 3] = (t[1] >> 11) as u8;
r[13 * i + 3] |= (t[2] << 2) as u8;
r[13 * i + 4] = (t[2] >> 6) as u8;
r[13 * i + 4] |= (t[3] << 7) as u8;
r[13 * i + 5] = (t[3] >> 1) as u8;
r[13 * i + 6] = (t[3] >> 9) as u8;
r[13 * i + 6] |= (t[4] << 4) as u8;
r[13 * i + 7] = (t[4] >> 4) as u8;
r[13 * i + 8] = (t[4] >> 12) as u8;
r[13 * i + 8] |= (t[5] << 1) as u8;
r[13 * i + 9] = (t[5] >> 7) as u8;
r[13 * i + 9] |= (t[6] << 6) as u8;
r[13 * i + 10] = (t[6] >> 2) as u8;
r[13 * i + 11] = (t[6] >> 10) as u8;
r[13 * i + 11] |= (t[7] << 3) as u8;
r[13 * i + 12] = (t[7] >> 5) as u8;
}
}

167
third_party/dilithium/src/polyvec.rs vendored Normal file
View File

@@ -0,0 +1,167 @@
#![allow(dead_code)]
use params::{K, L, N};
use poly::{self, Poly};
macro_rules! polyvec {
( $polyvec:ident, $len:expr ) => {
#[derive(Copy, Clone)]
pub struct $polyvec(pub [Poly; $len]);
impl $polyvec {
pub fn reduce(&mut self) {
self.0.iter_mut().for_each(poly::reduce)
}
pub fn caddq(&mut self) {
self.0.iter_mut().for_each(poly::caddq)
}
pub fn freeze(&mut self) {
self.0.iter_mut().for_each(poly::freeze)
}
pub fn with_add(&mut self, u: &Self, v: &Self) {
for i in 0..$len {
poly::add(&mut self[i], &u[i], &v[i]);
}
}
pub fn add_assign(&mut self, u: &Self) {
for i in 0..$len {
poly::add_assign(&mut self[i], &u[i]);
}
}
pub fn with_sub(&mut self, u: &Self, v: &Self) {
for i in 0..$len {
poly::sub(&mut self[i], &u[i], &v[i]);
}
}
pub fn shift_left(&mut self) {
self.0.iter_mut().for_each(|p| poly::shift_left(p));
}
pub fn ntt(&mut self) {
self.0.iter_mut().for_each(poly::ntt);
}
pub fn invntt_montgomery(&mut self) {
self.0.iter_mut().for_each(poly::invntt_montgomery)
}
pub fn chknorm(&self, bound: i32) -> bool {
self.0
.iter()
.map(|p| poly::chknorm(p, bound))
.fold(false, |x, y| x | y)
}
}
impl ::core::ops::Index<usize> for $polyvec {
type Output = Poly;
#[inline(always)]
fn index(&self, i: usize) -> &Self::Output {
self.0.index(i)
}
}
impl ::core::ops::IndexMut<usize> for $polyvec {
#[inline(always)]
fn index_mut(&mut self, i: usize) -> &mut Self::Output {
self.0.index_mut(i)
}
}
impl ::core::cmp::PartialEq for $polyvec {
fn eq(&self, other: &Self) -> bool {
self.0
.iter()
.zip(&other.0)
.flat_map(|(x, y)| x.iter().zip(y.iter()))
.all(|(x, y)| x == y)
}
}
impl Eq for $polyvec {}
impl Default for $polyvec {
fn default() -> Self {
$polyvec([[0; N]; $len])
}
}
};
}
polyvec!(PolyVecL, L);
polyvec!(PolyVecK, K);
pub fn pointwise_acc_invmontgomery(w: &mut Poly, u: &PolyVecL, v: &PolyVecL) {
let mut t = [0; N];
poly::pointwise_invmontgomery(w, &u[0], &v[0]);
for i in 1..L {
poly::pointwise_invmontgomery(&mut t, &u[i], &v[i]);
poly::add_assign(w, &t);
}
}
/// Computes a partial result of the dot product `w = u * v`.
///
/// # Arguments
/// * `w` - the output polynomial, which will contain the partial result
/// * `u_component` - the polynomial `u[i]`
/// * `v_component` - the polynomial `v[i]`
/// * `i` - the index
pub fn pointwise_acc_invmontgomery_componentwise(
w: &mut Poly,
u_component: &Poly,
v_component: &Poly,
i: usize,
) {
if i == 0 {
poly::pointwise_invmontgomery(w, &u_component, &v_component);
return;
}
let mut t = [0; N];
poly::pointwise_invmontgomery(&mut t, &u_component, &v_component);
poly::add_assign(w, &t);
}
impl PolyVecK {
pub fn power2round(&self, v0: &mut Self, v1: &mut Self) {
for i in 0..K {
poly::power2round(&self[i], &mut v0[i], &mut v1[i]);
}
}
pub fn power2round_remainder(&self, v0: &mut Self) {
for i in 0..K {
v0[i] = poly::power2round_remainder(&self[i]);
}
}
pub fn decompose(&self, v0: &mut Self, v1: &mut Self) {
for i in 0..K {
poly::decompose(&self[i], &mut v0[i], &mut v1[i]);
}
}
}
pub fn make_hint(u: &PolyVecK, v: &PolyVecK, h: &mut PolyVecK) -> usize {
let mut s = 0;
for i in 0..K {
s += poly::make_hint(&u[i], &v[i], &mut h[i]);
}
s
}
pub fn use_hint(w: &mut PolyVecK, u: &PolyVecK, h: &PolyVecK) {
for i in 0..K {
poly::use_hint(&mut w[i], &u[i], &h[i]);
}
}

52
third_party/dilithium/src/reduce.rs vendored Normal file
View File

@@ -0,0 +1,52 @@
use params::{Q, QINV};
/// Returns a value between `-Q` and `Q` that is equivalent to `a`.
///
/// For a finite field element `a` with `-2^{31}*Q <= a <= Q*2^31`,
/// computes `r` equivalent to `a*2^{-32} (mod Q)` such that `-Q < r < Q`.
///
/// # Arguments
///
/// * `a` - a number between `2^{31}*Q` and `Q*2^31`.
pub fn montgomery_reduce(a: i64) -> i32 {
let mut t: i32 = (((a as i32) as i64) * (QINV as i64)) as i32;
t = ((a - (t as i64) * (Q as i64)) >> 32) as i32;
t
}
/// Returns a value between `-6283009` and `6283007` that is equivalent to `a`.
///
/// For a finite field element `a` with `a <= 2^{31} - 2^{22} - 1`,
/// computes `r` equivalent to `a (mod Q)` such that
/// `-6283009 <= r <= 6283007`.
///
/// # Arguments
///
/// * `a` - a number between `2^{31}*Q` and `Q*2^31`.
pub fn reduce32(a: i32) -> i32 {
let mut t: i32 = (a + (1 << 22)) >> 23;
t = a - t * Q;
t
}
/// Adds `Q` if the input finite field element is negative.
///
/// # Arguments
///
/// * `a` - a number.
pub fn caddq(a: i32) -> i32 {
let mut t = a;
t += (a >> 31) & Q;
t
}
/// Computes the standard representative `r = a mod Q`.
///
/// # Arguments
///
/// * `a` - a number.
pub fn freeze(a: i32) -> i32 {
let a = reduce32(a);
let a = caddq(a);
a
}

93
third_party/dilithium/src/rounding.rs vendored Normal file
View File

@@ -0,0 +1,93 @@
use params::{D, GAMMA2, Q};
/// Returns the remainder and the quotient of `a` divided by `2^{D-1}`.
///
/// For a finite field element `a`, computes `a0` and `a1` such that
/// `a mod Q = a1*2^D + a0` with `-2^{D-1} < a0 <= 2^{D-1}`.
///
/// # Arguments
///
/// * `a` - a number assumed to be a standard representative modulo `Q`.
pub fn power2round(a: i32) -> (i32, i32) {
let a1: i32 = (a + (1 << (D - 1)) - 1) >> D;
let a0: i32 = a - (a1 << D);
(a0, a1)
}
/// Computes the high bits and low bits of `a`.
///
/// For a finite field element `a`, computes the high and the low bits `a1`
/// and respectively `a0`, such that `a mod Q = a1*ALPHA + a0`
/// with `-ALPHA/2 < a0 <= ALPHA/2`.
/// Exception: If `a1 = (Q-1)/ALPHA`, `a0` is set to 0.
///
/// # Arguments
///
/// * `a` - a number assumed to be a standard representative modulo `Q`.
pub fn decompose(a: i32) -> (i32, i32) {
let mut a1: i32 = (a + 127) >> 7;
if GAMMA2 == (Q - 1) / 32 {
a1 = (a1 * 1025 + (1 << 21)) >> 22;
a1 &= 15;
} else if GAMMA2 == (Q - 1) / 88 {
a1 = (a1 * 11275 + (1 << 23)) >> 24;
a1 ^= ((43 - a1) >> 31) & a1;
}
let mut a0: i32 = a - a1 * 2 * GAMMA2;
a0 -= (((Q - 1) / 2 - a0) >> 31) & Q;
(a0, a1)
}
/// Computes the hint bit.
///
/// The hint bit indicates whether the low bits `a0` overflow into the
/// the high bits `a1`.
///
/// # Arguments
///
/// * `a0` - a number representing the low bits of some element `a`
/// * `a1` - a number representing the high bits of the same element `a`
pub fn make_hint(a0: i32, a1: i32) -> u32 {
if a0 > GAMMA2 || a0 < -GAMMA2 || (a0 == -GAMMA2 && a1 != 0) {
1
} else {
0
}
}
/// Uses the given hint to correct the high bits of a.
///
/// # Arguments
///
/// * `a` - the number to be corrected
/// * `hint` - a value 0 or 1
pub fn use_hint(a: i32, hint: u32) -> i32 {
let (a0, a1) = decompose(a);
if hint == 0 {
a1
} else if GAMMA2 == (Q - 1) / 32 {
if a0 > 0 {
(a1 + 1) & 15
} else {
(a1 - 1) & 15
}
} else {
if a0 > 0 {
if a1 == 43 {
0
} else {
a1 + 1
}
} else {
if a1 == 0 {
43
} else {
a1 - 1
}
}
}
}

1220
third_party/dilithium/src/sign.rs vendored Normal file

File diff suppressed because it is too large Load Diff

64
third_party/dilithium/src/test_mul.rs vendored Normal file
View File

@@ -0,0 +1,64 @@
extern crate rng256;
use super::*;
use params::{N, Q};
use poly::Poly;
const NTESTS: usize = 10000;
fn poly_naivemul(c: &mut Poly, a: &Poly, b: &Poly) {
let mut r = [0; 2 * N];
for i in 0..N {
for j in 0..N {
r[i + j] += (((a[i] as i64) * (b[j] as i64)) % (Q as i64)) as i32;
}
}
for i in N..(2 * N) {
r[i - N] = (r[i - N] - r[i]) % Q;
}
c.copy_from_slice(&r[..N]);
}
#[test]
fn test_mul() {
use self::rng256::Rng256;
let mut rndbuf = [0; 32];
let mut c = [0; N];
let (mut c1, mut c2) = ([0; N], [0; N]);
let (mut a, mut b) = ([0; N], [0; N]);
let mut rng = rng256::ThreadRng256 {};
for _ in 0..NTESTS {
rng.fill_bytes(&mut rndbuf);
poly::uniform(&mut a, &rndbuf, 0);
rng.fill_bytes(&mut rndbuf);
poly::uniform(&mut b, &rndbuf, 0);
c.copy_from_slice(&a[..N]);
poly::ntt(&mut c);
for j in 0..N {
c[j] = ((c[j] as i64) * -114592 % (Q as i64)) as i32;
}
poly::invntt_montgomery(&mut c);
for j in 0..N {
assert_eq!((c[j] - a[j]) % Q, 0);
}
poly_naivemul(&mut c1, &a, &b);
poly::ntt(&mut a);
poly::ntt(&mut b);
poly::pointwise_invmontgomery(&mut c2, &a, &b);
poly::invntt_montgomery(&mut c2);
for j in 0..N {
assert_eq!((c1[j] - c2[j]) % Q, 0);
}
}
}

10
third_party/dilithium/src/utils.rs vendored Normal file
View File

@@ -0,0 +1,10 @@
macro_rules! shake256 {
( $output:expr ; $( $input:expr ),* ) => {
let mut hasher = ::sha3::Shake256::default();
$(
::digest::Input::process(&mut hasher, $input);
)*
let mut reader = ::digest::ExtendableOutput::xof_result(hasher);
::digest::XofReader::read(&mut reader, $output);
}
}

3548
third_party/dilithium/tests/dilithium_c.rs vendored Normal file

File diff suppressed because it is too large Load Diff

65
third_party/dilithium/tests/sign.rs vendored Normal file
View File

@@ -0,0 +1,65 @@
extern crate dilithium;
extern crate rng256;
use dilithium::sign::{PubKey, SecKey};
use rng256::Rng256;
const ITERATIONS: u32 = 500;
#[test]
fn test_sk_with_pk() {
let mut rng = rng256::ThreadRng256 {};
for _ in 0..ITERATIONS {
let (sk, pk) = SecKey::gensk_with_pk(&mut rng);
let pk_from_sk = sk.genpk();
assert_eq!(pk, pk_from_sk);
}
}
#[test]
fn test_sign() {
let mut rng = rng256::ThreadRng256 {};
for _ in 0..ITERATIONS {
let sk = SecKey::gensk(&mut rng);
let mut message = [0; 59];
rng.fill_bytes(&mut message);
let sig = sk.sign(&message);
let pk = sk.genpk();
let mut bytes = [0; dilithium::params::PK_SIZE_PACKED];
pk.to_bytes(&mut bytes);
assert!(pk.verify(&message, &sig));
message[2] ^= 42;
assert!(!pk.verify(&message, &sig));
}
}
#[test]
fn test_seckey_to_bytes_from_bytes() {
let mut rng = rng256::ThreadRng256 {};
for _ in 0..ITERATIONS {
let sk = SecKey::gensk(&mut rng);
let mut bytes = [0; dilithium::params::SK_SIZE_PACKED];
sk.to_bytes(&mut bytes);
let decoded_sk = SecKey::from_bytes(&bytes);
assert_eq!(decoded_sk, sk);
}
}
#[test]
fn test_pubkey_to_bytes_from_bytes() {
let mut rng = rng256::ThreadRng256 {};
for _ in 0..ITERATIONS {
let sk = SecKey::gensk(&mut rng);
let pk = sk.genpk();
let mut bytes = [0; dilithium::params::PK_SIZE_PACKED];
pk.to_bytes(&mut bytes);
let decoded_pk = PubKey::from_bytes(&bytes);
assert_eq!(decoded_pk, pk);
}
}

File diff suppressed because one or more lines are too long

76
third_party/lang-items/Cargo.lock generated vendored Normal file
View File

@@ -0,0 +1,76 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "lang_items"
version = "0.1.0"
dependencies = [
"libtock_core",
"libtock_drivers",
"linked_list_allocator",
]
[[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 = "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 = "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"

61
third_party/libtock-drivers/Cargo.lock generated vendored Normal file
View File

@@ -0,0 +1,61 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[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 = "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 = "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"

View File

@@ -169,7 +169,7 @@ def main(args):
("Failed to configure OpenSK (device is partially programmed but "
"the given cert/key don't match the ones currently programmed)."))
else:
error(f"Failed to configure OpenSK (unknown error: {ex}")
error(f"Failed to configure OpenSK (unknown error: {ex})")
return responses

View File

@@ -20,7 +20,6 @@ from __future__ import division
from __future__ import print_function
import argparse
import datetime
import hashlib
import os
import struct
@@ -44,6 +43,7 @@ OPENSK_VID_PID = (0x1915, 0x521F)
OPENSK_VENDOR_UPGRADE = 0x42
OPENSK_VENDOR_UPGRADE_INFO = 0x43
PAGE_SIZE = 0x1000
METADATA_SIGN_OFFSET = 0x800
KERNEL_SIZE = 0x20000
APP_SIZE = 0x20000
PARTITION_ADDRESS = {
@@ -54,7 +54,15 @@ ES256_ALGORITHM = -7
ARCH = "thumbv7em-none-eabi"
def create_metadata(firmware_image: bytes, partition_address: int) -> bytes:
def hash_message(message: bytes) -> bytes:
"""Uses SHA256 to hash a message."""
sha256_hash = hashlib.sha256()
sha256_hash.update(message)
return sha256_hash.digest()
def create_metadata(firmware_image: bytes, partition_address: int, version: int,
priv_key: Any) -> bytes:
"""Creates the matching metadata for the given firmware.
The metadata consists of a timestamp, the expected address and a hash of
@@ -65,25 +73,26 @@ def create_metadata(firmware_image: bytes, partition_address: int) -> bytes:
partition_address: The address to be written as a metadata property.
Returns:
A byte array consisting of 32B hash, 4B timestamp and 4B partition address
in little endian encoding.
A byte array of page size, consisting of
- 32 B hash,
- 64 B signature,
at the beginning and
- 8 B version and
- 4 B partition address in little endian encoding
after METADATA_SIGN_OFFSET. All other bytes are 0xFF.
"""
t = datetime.datetime.utcnow().timestamp()
timestamp = struct.pack("<I", int(t))
if version < 0 or version >= 2**63:
fatal("The version must fit into an unsigned integer with 63 bit.\n"
"Please pass it using --version")
version_bytes = struct.pack("<Q", version)
partition_start = struct.pack("<I", partition_address)
sha256_hash = hashlib.sha256()
sha256_hash.update(firmware_image)
sha256_hash.update(timestamp)
sha256_hash.update(partition_start)
checksum = sha256_hash.digest()
return checksum + timestamp + partition_start
def hash_message(message: bytes) -> bytes:
"""Uses SHA256 to hash a message."""
sha256_hash = hashlib.sha256()
sha256_hash.update(message)
return sha256_hash.digest()
# Prefix sizes that are a multiple of 64 suit our bootloader's SHA.
signed_metadata = pad_to(version_bytes + partition_start,
PAGE_SIZE - METADATA_SIGN_OFFSET)
signed_data = signed_metadata + firmware_image
checksum = hash_message(signed_data)
signature = sign_firmware(signed_data, priv_key)
return pad_to(checksum + signature, METADATA_SIGN_OFFSET) + signed_metadata
def check_info(partition_address: int, authenticator: Any):
@@ -95,9 +104,10 @@ def check_info(partition_address: int, authenticator: Any):
data={},
)
if result[0x01] != partition_address:
fatal("Identifiers do not match.")
fatal(f"Identifiers do not match, received 0x{result[0x01]:0x}, "
f"expected 0x{partition_address:0x}.")
except ctap.CtapError as ex:
error(f"Failed to read OpenSK upgrade info (error: {ex}")
fatal(f"Failed to read OpenSK upgrade info (error: {ex})")
def get_kernel(board: str) -> bytes:
@@ -137,8 +147,10 @@ def generate_firmware_image(board: str) -> bytes:
return pad_to(kernel, KERNEL_SIZE) + pad_to(app, APP_SIZE)
def load_priv_key(priv_key_file: argparse.FileType) -> Any:
def load_priv_key(priv_key_filename: str) -> Any:
"""Loads the ECDSA private key from the specified file."""
try:
with open(priv_key_filename, "rb") as priv_key_file:
priv_key = get_private_key(priv_key_file.read())
if not isinstance(priv_key, ec.EllipticCurvePrivateKey):
fatal("Private key must be an Elliptic Curve one.")
@@ -148,6 +160,8 @@ def load_priv_key(priv_key_file: argparse.FileType) -> Any:
fatal("Private key must be 256 bits long.")
info("Private key is valid.")
return priv_key
except IOError as e:
fatal(f"Unable to open file: {priv_key_filename}\n{e}")
def sign_firmware(data: bytes, priv_key: Any) -> bytes:
@@ -159,19 +173,15 @@ def sign_firmware(data: bytes, priv_key: Any) -> bytes:
def main(args):
colorama.init()
if not args.priv_key:
fatal("Please pass in a private key file using --private-key.")
firmware_image = generate_firmware_image(args.board)
partition_address = PARTITION_ADDRESS[args.board]
metadata = create_metadata(firmware_image, partition_address)
if not args.priv_key:
fatal("Please pass in a private key file using --private-key.")
priv_key = load_priv_key(args.priv_key)
signed_data = firmware_image + metadata[32:40]
signature = {
"alg": ES256_ALGORITHM,
"signature": sign_firmware(signed_data, priv_key)
}
metadata = create_metadata(firmware_image, partition_address, args.version,
priv_key)
partition = metadata + firmware_image
if args.use_vendor_hid:
patcher = patch.object(hid.base, "FIDO_USAGE_PAGE", 0xFF00)
@@ -189,11 +199,18 @@ def main(args):
aaguid = uuid.UUID(bytes=authenticator.get_info().aaguid)
info(f"Upgrading OpenSK device AAGUID {aaguid} ({authenticator.device}).")
running_version = authenticator.get_info().firmware_version
if args.version < running_version:
fatal(f"Can not write version {args.version} when version "
f"{running_version} is running.")
else:
info(f"Running version: {running_version}")
try:
check_info(partition_address, authenticator)
offset = 0
for offset in range(0, len(firmware_image), PAGE_SIZE):
page = firmware_image[offset:][:PAGE_SIZE]
for offset in range(0, len(partition), PAGE_SIZE):
page = partition[offset:][:PAGE_SIZE]
info(f"Writing at offset 0x{offset:08X}...")
cbor_data = {1: offset, 2: page, 3: hash_message(page)}
authenticator.send_cbor(
@@ -201,26 +218,20 @@ def main(args):
data=cbor_data,
)
info("Writing metadata...")
cbor_data = {2: metadata, 3: hash_message(metadata), 4: signature}
authenticator.send_cbor(
OPENSK_VENDOR_UPGRADE,
data=cbor_data,
)
except ctap.CtapError as ex:
message = "Failed to upgrade OpenSK"
if ex.code.value == ctap.CtapError.ERR.INVALID_COMMAND:
error(f"{message} (unsupported command).")
elif ex.code.value == ctap.CtapError.ERR.INVALID_PARAMETER:
error(f"{message} (invalid parameter, maybe a wrong byte array size?).")
elif ex.code.value == ctap.CtapError.ERR_INTEGRITY_FAILURE:
error(f"{message} (hashes or signature don't match).")
error(f"{message} (invalid parameter).")
elif ex.code.value == ctap.CtapError.ERR.INTEGRITY_FAILURE:
error(f"{message} (data hash does not match slice).")
elif ex.code.value == 0xF2: # VENDOR_INTERNAL_ERROR
error(f"{message} (internal conditions not met).")
elif ex.code.value == 0xF3: # VENDOR_HARDWARE_FAILURE
error(f"{message} (internal hardware error).")
else:
error(f"{message} (unexpected error: {ex}")
error(f"{message} (unexpected error: {ex})")
if __name__ == "__main__":
@@ -247,7 +258,7 @@ if __name__ == "__main__":
)
parser.add_argument(
"--private-key",
type=argparse.FileType("rb"),
type=str,
default="crypto_data/opensk_upgrade.key",
dest="priv_key",
help=("PEM file for signing the firmware."),
@@ -259,4 +270,10 @@ if __name__ == "__main__":
dest="use_vendor_hid",
help=("Whether to upgrade the device using the Vendor HID interface."),
)
parser.add_argument(
"--version",
type=int,
dest="version",
help=("Firmware version that is built."),
)
main(parser.parse_args())

179
tools/heapviz/Cargo.lock generated Normal file
View File

@@ -0,0 +1,179 @@
# 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 = "ansi_term"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
dependencies = [
"winapi",
]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi",
"libc",
"winapi",
]
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "cc"
version = "1.0.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
[[package]]
name = "clap"
version = "2.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
dependencies = [
"ansi_term",
"atty",
"bitflags",
"strsim",
"textwrap",
"unicode-width",
"vec_map",
]
[[package]]
name = "heapviz"
version = "0.1.0"
dependencies = [
"clap",
"lazy_static",
"ncurses",
"regex",
]
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[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 = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "ncurses"
version = "5.101.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e2c5d34d72657dc4b638a1c25d40aae81e4f1c699062f72f467237920752032"
dependencies = [
"cc",
"libc",
"pkg-config",
]
[[package]]
name = "pkg-config"
version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae"
[[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 = "strsim"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]]
name = "textwrap"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
dependencies = [
"unicode-width",
]
[[package]]
name = "unicode-width"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
[[package]]
name = "vec_map"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[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"