├── .cargo └── config.toml ├── .github ├── cross-docker │ └── Dockerfile-cross-debian-11 └── workflows │ └── ci.yml ├── .gitignore ├── CONTRIBUTING.md ├── Cargo.lock ├── Cargo.toml ├── Cross.toml ├── LICENSE ├── Makefile.toml ├── README.md ├── release.toml └── src ├── cmd ├── bench.rs ├── config.rs ├── generate.rs ├── info.rs ├── key.rs ├── mod.rs ├── provision.rs └── test.rs ├── device ├── ecc.rs ├── file.rs ├── mod.rs ├── nova_tz.rs └── tpm.rs ├── lib.rs ├── main.rs └── result.rs /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [target.mipsel-unknown-linux-musl] 2 | rustflags = [ 3 | "-C", "target-feature=+crt-static", 4 | "-C", "link-args=-static", 5 | ] 6 | -------------------------------------------------------------------------------- /.github/cross-docker/Dockerfile-cross-debian-11: -------------------------------------------------------------------------------- 1 | FROM debian:11-slim 2 | ARG DEBIAN_FRONTEND=noninteractive 3 | 4 | RUN apt-get update && apt-get install --assume-yes --no-install-recommends \ 5 | g++-x86-64-linux-gnu \ 6 | libc6-dev-amd64-cross \ 7 | libtss2-dev \ 8 | llvm-dev \ 9 | libclang-dev \ 10 | clang 11 | 12 | ENV CROSS_TOOLCHAIN_PREFIX=x86_64-linux-gnu- 13 | ENV CROSS_SYSROOT=/usr/x86_64-linux-gnu 14 | ENV CROSS_TARGET_RUNNER="/linux-runner x86_64" 15 | ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER="$CROSS_TOOLCHAIN_PREFIX"gcc \ 16 | CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER="$CROSS_TARGET_RUNNER" \ 17 | AR_x86_64_unknown_linux_gnu="$CROSS_TOOLCHAIN_PREFIX"ar \ 18 | CC_x86_64_unknown_linux_gnu="$CROSS_TOOLCHAIN_PREFIX"gcc \ 19 | CXX_x86_64_unknown_linux_gnu="$CROSS_TOOLCHAIN_PREFIX"g++ \ 20 | BINDGEN_EXTRA_CLANG_ARGS_x86_64_unknown_linux_gnu="--sysroot=$CROSS_SYSROOT" \ 21 | RUST_TEST_THREADS=1 \ 22 | PKG_CONFIG_PATH="/usr/lib/x86_64-linux-gnu/pkgconfig/:${PKG_CONFIG_PATH}" 23 | ENV CPATH="/usr/include/" -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | on: 2 | pull_request: 3 | branches: [main] 4 | push: 5 | branches: [main] 6 | tags: ["v*"] 7 | 8 | name: ci 9 | 10 | jobs: 11 | build: 12 | name: hygiene 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v3 16 | - uses: dtolnay/rust-toolchain@stable 17 | with: 18 | components: clippy, rustfmt 19 | 20 | - name: Install dependencies 21 | run: sudo apt-get install -y libtss2-dev 22 | 23 | - name: Cancel previous runs 24 | uses: styfle/cancel-workflow-action@0.11.0 25 | with: 26 | access_token: ${{ github.token }} 27 | 28 | - name: Check formatting 29 | run: cargo fmt -- --check 30 | 31 | - name: Clippy 32 | run: cargo clippy --all-features -- -Dclippy::all -D warnings 33 | 34 | package: 35 | name: package 36 | runs-on: ubuntu-latest 37 | strategy: 38 | matrix: 39 | target: 40 | - aarch64-unknown-linux-gnu 41 | - arm-unknown-linux-gnueabihf 42 | - armv5te-unknown-linux-musleabi 43 | - armv7-unknown-linux-gnueabihf 44 | - armv7-unknown-linux-musleabihf 45 | - mips-unknown-linux-musl 46 | - mipsel-unknown-linux-musl 47 | - x86_64-unknown-debian-gnu 48 | - x86_64-tpm-debian-gnu 49 | 50 | steps: 51 | - uses: actions/checkout@v3 52 | - uses: davidB/rust-cargo-make@v1 53 | - uses: dtolnay/rust-toolchain@stable 54 | 55 | - name: install cross 56 | uses: jaxxstorm/action-install-gh-release@v1.9.0 57 | env: 58 | ## Allow cross install into PATH 59 | ACTIONS_ALLOW_UNSECURE_COMMANDS: true 60 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 61 | with: 62 | repo: rust-embedded/cross 63 | 64 | - name: build target 65 | run: cargo make --profile ${{ matrix.target }} build 66 | 67 | - name: package release 68 | if: startsWith(github.ref, 'refs/tags') 69 | run: cargo make --profile ${{ matrix.target }} pkg 70 | 71 | - name: push release 72 | uses: softprops/action-gh-release@v1 73 | if: startsWith(github.ref, 'refs/tags/') 74 | env: 75 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 76 | with: 77 | fail_on_unmatched_files: true 78 | files: | 79 | gateway-mfr-*.tar.gz 80 | gateway-mfr-*.checksum 81 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | .envrc 3 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to Contribute to this repository # 2 | 3 | We value contributions from the community and will do everything we 4 | can go get them reviewed in a timely fashion. If you have code to send 5 | our way or a bug to report: 6 | 7 | * **Contributing Code**: If you have new code or a bug fix, fork this 8 | repo, create a logically-named branch, and [submit a PR against this 9 | repo](https://github.com/helium/ecc608-linux-rs/issues). Include a 10 | write up of the PR with details on what it does. 11 | 12 | * **Reporting Bugs**: Open an issue [against this 13 | repo](https://github.com/helium/ecc608-linux-rs/issues) with as much 14 | detail as you can. At the very least you'll include steps to 15 | reproduce the problem. 16 | 17 | This project is intended to be a safe, welcoming space for 18 | collaboration, and contributors are expected to adhere to the 19 | [Contributor Covenant Code of 20 | Conduct](http://contributor-covenant.org/). 21 | 22 | Above all, thank you for taking the time to be a part of the Helium community. 23 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "CoreFoundation-sys" 7 | version = "0.1.4" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "d0e9889e6db118d49d88d84728d0e964d973a5680befb5f85f55141beea5c20b" 10 | dependencies = [ 11 | "libc", 12 | "mach", 13 | ] 14 | 15 | [[package]] 16 | name = "IOKit-sys" 17 | version = "0.1.5" 18 | source = "registry+https://github.com/rust-lang/crates.io-index" 19 | checksum = "99696c398cbaf669d2368076bdb3d627fb0ce51a26899d7c61228c5c0af3bf4a" 20 | dependencies = [ 21 | "CoreFoundation-sys", 22 | "libc", 23 | "mach", 24 | ] 25 | 26 | [[package]] 27 | name = "aho-corasick" 28 | version = "1.0.4" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "6748e8def348ed4d14996fa801f4122cd763fff530258cdc03f64b25f89d3a5a" 31 | dependencies = [ 32 | "memchr", 33 | ] 34 | 35 | [[package]] 36 | name = "android-tzdata" 37 | version = "0.1.1" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" 40 | 41 | [[package]] 42 | name = "angry-purple-tiger" 43 | version = "0.1.0" 44 | source = "registry+https://github.com/rust-lang/crates.io-index" 45 | checksum = "49c749eb8b90a5c85a879ac35bba5374ba18ff41d609878d7d37dd2ac0122a3c" 46 | dependencies = [ 47 | "md5", 48 | ] 49 | 50 | [[package]] 51 | name = "anstream" 52 | version = "0.3.2" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" 55 | dependencies = [ 56 | "anstyle", 57 | "anstyle-parse", 58 | "anstyle-query", 59 | "anstyle-wincon", 60 | "colorchoice", 61 | "is-terminal", 62 | "utf8parse", 63 | ] 64 | 65 | [[package]] 66 | name = "anstyle" 67 | version = "1.0.1" 68 | source = "registry+https://github.com/rust-lang/crates.io-index" 69 | checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" 70 | 71 | [[package]] 72 | name = "anstyle-parse" 73 | version = "0.2.1" 74 | source = "registry+https://github.com/rust-lang/crates.io-index" 75 | checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" 76 | dependencies = [ 77 | "utf8parse", 78 | ] 79 | 80 | [[package]] 81 | name = "anstyle-query" 82 | version = "1.0.0" 83 | source = "registry+https://github.com/rust-lang/crates.io-index" 84 | checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" 85 | dependencies = [ 86 | "windows-sys", 87 | ] 88 | 89 | [[package]] 90 | name = "anstyle-wincon" 91 | version = "1.0.2" 92 | source = "registry+https://github.com/rust-lang/crates.io-index" 93 | checksum = "c677ab05e09154296dd37acecd46420c17b9713e8366facafa8fc0885167cf4c" 94 | dependencies = [ 95 | "anstyle", 96 | "windows-sys", 97 | ] 98 | 99 | [[package]] 100 | name = "anyhow" 101 | version = "1.0.72" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" 104 | 105 | [[package]] 106 | name = "autocfg" 107 | version = "1.1.0" 108 | source = "registry+https://github.com/rust-lang/crates.io-index" 109 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 110 | 111 | [[package]] 112 | name = "base16ct" 113 | version = "0.1.1" 114 | source = "registry+https://github.com/rust-lang/crates.io-index" 115 | checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" 116 | 117 | [[package]] 118 | name = "base64" 119 | version = "0.21.2" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" 122 | 123 | [[package]] 124 | name = "bindgen" 125 | version = "0.65.1" 126 | source = "registry+https://github.com/rust-lang/crates.io-index" 127 | checksum = "cfdf7b466f9a4903edc73f95d6d2bcd5baf8ae620638762244d3f60143643cc5" 128 | dependencies = [ 129 | "bitflags 1.3.2", 130 | "cexpr", 131 | "clang-sys", 132 | "lazy_static", 133 | "lazycell", 134 | "log", 135 | "peeking_take_while", 136 | "prettyplease", 137 | "proc-macro2", 138 | "quote", 139 | "regex", 140 | "rustc-hash", 141 | "shlex", 142 | "syn", 143 | "which", 144 | ] 145 | 146 | [[package]] 147 | name = "bitfield" 148 | version = "0.14.0" 149 | source = "registry+https://github.com/rust-lang/crates.io-index" 150 | checksum = "2d7e60934ceec538daadb9d8432424ed043a904d8e0243f3c6446bce549a46ac" 151 | 152 | [[package]] 153 | name = "bitflags" 154 | version = "1.3.2" 155 | source = "registry+https://github.com/rust-lang/crates.io-index" 156 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 157 | 158 | [[package]] 159 | name = "bitflags" 160 | version = "2.0.2" 161 | source = "registry+https://github.com/rust-lang/crates.io-index" 162 | checksum = "487f1e0fcbe47deb8b0574e646def1c903389d95241dd1bbcc6ce4a715dfc0c1" 163 | 164 | [[package]] 165 | name = "block-buffer" 166 | version = "0.9.0" 167 | source = "registry+https://github.com/rust-lang/crates.io-index" 168 | checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" 169 | dependencies = [ 170 | "generic-array", 171 | ] 172 | 173 | [[package]] 174 | name = "block-buffer" 175 | version = "0.10.4" 176 | source = "registry+https://github.com/rust-lang/crates.io-index" 177 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 178 | dependencies = [ 179 | "generic-array", 180 | ] 181 | 182 | [[package]] 183 | name = "bs58" 184 | version = "0.5.0" 185 | source = "registry+https://github.com/rust-lang/crates.io-index" 186 | checksum = "f5353f36341f7451062466f0b755b96ac3a9547e4d7f6b70d603fc721a7d7896" 187 | dependencies = [ 188 | "sha2 0.10.7", 189 | "tinyvec", 190 | ] 191 | 192 | [[package]] 193 | name = "byteorder" 194 | version = "1.4.3" 195 | source = "registry+https://github.com/rust-lang/crates.io-index" 196 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 197 | 198 | [[package]] 199 | name = "bytes" 200 | version = "1.4.0" 201 | source = "registry+https://github.com/rust-lang/crates.io-index" 202 | checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" 203 | 204 | [[package]] 205 | name = "cc" 206 | version = "1.0.82" 207 | source = "registry+https://github.com/rust-lang/crates.io-index" 208 | checksum = "305fe645edc1442a0fa8b6726ba61d422798d37a52e12eaecf4b022ebbb88f01" 209 | dependencies = [ 210 | "libc", 211 | ] 212 | 213 | [[package]] 214 | name = "cexpr" 215 | version = "0.6.0" 216 | source = "registry+https://github.com/rust-lang/crates.io-index" 217 | checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" 218 | dependencies = [ 219 | "nom", 220 | ] 221 | 222 | [[package]] 223 | name = "cfg-if" 224 | version = "1.0.0" 225 | source = "registry+https://github.com/rust-lang/crates.io-index" 226 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 227 | 228 | [[package]] 229 | name = "chrono" 230 | version = "0.4.26" 231 | source = "registry+https://github.com/rust-lang/crates.io-index" 232 | checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" 233 | dependencies = [ 234 | "android-tzdata", 235 | "num-traits", 236 | ] 237 | 238 | [[package]] 239 | name = "clang-sys" 240 | version = "1.6.1" 241 | source = "registry+https://github.com/rust-lang/crates.io-index" 242 | checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" 243 | dependencies = [ 244 | "glob", 245 | "libc", 246 | "libloading", 247 | ] 248 | 249 | [[package]] 250 | name = "clap" 251 | version = "4.3.21" 252 | source = "registry+https://github.com/rust-lang/crates.io-index" 253 | checksum = "c27cdf28c0f604ba3f512b0c9a409f8de8513e4816705deb0498b627e7c3a3fd" 254 | dependencies = [ 255 | "clap_builder", 256 | "clap_derive", 257 | "once_cell", 258 | ] 259 | 260 | [[package]] 261 | name = "clap_builder" 262 | version = "4.3.21" 263 | source = "registry+https://github.com/rust-lang/crates.io-index" 264 | checksum = "08a9f1ab5e9f01a9b81f202e8562eb9a10de70abf9eaeac1be465c28b75aa4aa" 265 | dependencies = [ 266 | "anstream", 267 | "anstyle", 268 | "clap_lex", 269 | "strsim", 270 | ] 271 | 272 | [[package]] 273 | name = "clap_derive" 274 | version = "4.3.12" 275 | source = "registry+https://github.com/rust-lang/crates.io-index" 276 | checksum = "54a9bb5758fc5dfe728d1019941681eccaf0cf8a4189b692a0ee2f2ecf90a050" 277 | dependencies = [ 278 | "heck", 279 | "proc-macro2", 280 | "quote", 281 | "syn", 282 | ] 283 | 284 | [[package]] 285 | name = "clap_lex" 286 | version = "0.5.0" 287 | source = "registry+https://github.com/rust-lang/crates.io-index" 288 | checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" 289 | 290 | [[package]] 291 | name = "colorchoice" 292 | version = "1.0.0" 293 | source = "registry+https://github.com/rust-lang/crates.io-index" 294 | checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" 295 | 296 | [[package]] 297 | name = "const-oid" 298 | version = "0.7.1" 299 | source = "registry+https://github.com/rust-lang/crates.io-index" 300 | checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" 301 | 302 | [[package]] 303 | name = "const-oid" 304 | version = "0.9.5" 305 | source = "registry+https://github.com/rust-lang/crates.io-index" 306 | checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" 307 | 308 | [[package]] 309 | name = "cpufeatures" 310 | version = "0.2.9" 311 | source = "registry+https://github.com/rust-lang/crates.io-index" 312 | checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" 313 | dependencies = [ 314 | "libc", 315 | ] 316 | 317 | [[package]] 318 | name = "crypto-bigint" 319 | version = "0.3.2" 320 | source = "registry+https://github.com/rust-lang/crates.io-index" 321 | checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21" 322 | dependencies = [ 323 | "generic-array", 324 | "rand_core", 325 | "subtle", 326 | "zeroize", 327 | ] 328 | 329 | [[package]] 330 | name = "crypto-common" 331 | version = "0.1.6" 332 | source = "registry+https://github.com/rust-lang/crates.io-index" 333 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 334 | dependencies = [ 335 | "generic-array", 336 | "typenum", 337 | ] 338 | 339 | [[package]] 340 | name = "crypto-mac" 341 | version = "0.11.1" 342 | source = "registry+https://github.com/rust-lang/crates.io-index" 343 | checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" 344 | dependencies = [ 345 | "generic-array", 346 | "subtle", 347 | ] 348 | 349 | [[package]] 350 | name = "ct-codecs" 351 | version = "1.1.1" 352 | source = "registry+https://github.com/rust-lang/crates.io-index" 353 | checksum = "f3b7eb4404b8195a9abb6356f4ac07d8ba267045c8d6d220ac4dc992e6cc75df" 354 | 355 | [[package]] 356 | name = "der" 357 | version = "0.5.1" 358 | source = "registry+https://github.com/rust-lang/crates.io-index" 359 | checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c" 360 | dependencies = [ 361 | "const-oid 0.7.1", 362 | ] 363 | 364 | [[package]] 365 | name = "digest" 366 | version = "0.9.0" 367 | source = "registry+https://github.com/rust-lang/crates.io-index" 368 | checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" 369 | dependencies = [ 370 | "generic-array", 371 | ] 372 | 373 | [[package]] 374 | name = "digest" 375 | version = "0.10.7" 376 | source = "registry+https://github.com/rust-lang/crates.io-index" 377 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 378 | dependencies = [ 379 | "block-buffer 0.10.4", 380 | "const-oid 0.9.5", 381 | "crypto-common", 382 | ] 383 | 384 | [[package]] 385 | name = "drop_guard" 386 | version = "0.3.0" 387 | source = "registry+https://github.com/rust-lang/crates.io-index" 388 | checksum = "2c4a817d8b683f6e649aed359aab0c47a875377516bb5791d0f7e46d9066d209" 389 | 390 | [[package]] 391 | name = "ecc608-linux" 392 | version = "0.2.2" 393 | source = "registry+https://github.com/rust-lang/crates.io-index" 394 | checksum = "8b4113eb6c60325223528978de0c0744327ea7c741ff5a6ddf1282740c8c7c54" 395 | dependencies = [ 396 | "bitfield", 397 | "bytes", 398 | "i2c-linux", 399 | "serde", 400 | "serde_derive", 401 | "serialport", 402 | "sha2 0.10.7", 403 | "thiserror", 404 | ] 405 | 406 | [[package]] 407 | name = "ecdsa" 408 | version = "0.13.4" 409 | source = "registry+https://github.com/rust-lang/crates.io-index" 410 | checksum = "d0d69ae62e0ce582d56380743515fefaf1a8c70cec685d9677636d7e30ae9dc9" 411 | dependencies = [ 412 | "der", 413 | "elliptic-curve", 414 | "rfc6979", 415 | "signature", 416 | ] 417 | 418 | [[package]] 419 | name = "ed25519" 420 | version = "1.5.3" 421 | source = "registry+https://github.com/rust-lang/crates.io-index" 422 | checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" 423 | dependencies = [ 424 | "signature", 425 | ] 426 | 427 | [[package]] 428 | name = "ed25519-compact" 429 | version = "2.0.4" 430 | source = "registry+https://github.com/rust-lang/crates.io-index" 431 | checksum = "6a3d382e8464107391c8706b4c14b087808ecb909f6c15c34114bc42e53a9e4c" 432 | dependencies = [ 433 | "ct-codecs", 434 | "ed25519", 435 | "getrandom", 436 | ] 437 | 438 | [[package]] 439 | name = "either" 440 | version = "1.9.0" 441 | source = "registry+https://github.com/rust-lang/crates.io-index" 442 | checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" 443 | 444 | [[package]] 445 | name = "elliptic-curve" 446 | version = "0.11.12" 447 | source = "registry+https://github.com/rust-lang/crates.io-index" 448 | checksum = "25b477563c2bfed38a3b7a60964c49e058b2510ad3f12ba3483fd8f62c2306d6" 449 | dependencies = [ 450 | "base16ct", 451 | "crypto-bigint", 452 | "der", 453 | "ff", 454 | "generic-array", 455 | "group", 456 | "rand_core", 457 | "sec1", 458 | "subtle", 459 | "zeroize", 460 | ] 461 | 462 | [[package]] 463 | name = "equivalent" 464 | version = "1.0.1" 465 | source = "registry+https://github.com/rust-lang/crates.io-index" 466 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 467 | 468 | [[package]] 469 | name = "errno" 470 | version = "0.3.2" 471 | source = "registry+https://github.com/rust-lang/crates.io-index" 472 | checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f" 473 | dependencies = [ 474 | "errno-dragonfly", 475 | "libc", 476 | "windows-sys", 477 | ] 478 | 479 | [[package]] 480 | name = "errno-dragonfly" 481 | version = "0.1.2" 482 | source = "registry+https://github.com/rust-lang/crates.io-index" 483 | checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" 484 | dependencies = [ 485 | "cc", 486 | "libc", 487 | ] 488 | 489 | [[package]] 490 | name = "ff" 491 | version = "0.11.1" 492 | source = "registry+https://github.com/rust-lang/crates.io-index" 493 | checksum = "131655483be284720a17d74ff97592b8e76576dc25563148601df2d7c9080924" 494 | dependencies = [ 495 | "rand_core", 496 | "subtle", 497 | ] 498 | 499 | [[package]] 500 | name = "fnv" 501 | version = "1.0.7" 502 | source = "registry+https://github.com/rust-lang/crates.io-index" 503 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 504 | 505 | [[package]] 506 | name = "form_urlencoded" 507 | version = "1.2.0" 508 | source = "registry+https://github.com/rust-lang/crates.io-index" 509 | checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" 510 | dependencies = [ 511 | "percent-encoding", 512 | ] 513 | 514 | [[package]] 515 | name = "gateway-mfr" 516 | version = "0.5.4" 517 | dependencies = [ 518 | "angry-purple-tiger", 519 | "anyhow", 520 | "bytes", 521 | "clap", 522 | "helium-crypto", 523 | "http", 524 | "rand", 525 | "semver", 526 | "serde", 527 | "serde_json", 528 | "serde_urlencoded", 529 | "toml", 530 | ] 531 | 532 | [[package]] 533 | name = "generic-array" 534 | version = "0.14.7" 535 | source = "registry+https://github.com/rust-lang/crates.io-index" 536 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 537 | dependencies = [ 538 | "typenum", 539 | "version_check", 540 | ] 541 | 542 | [[package]] 543 | name = "getrandom" 544 | version = "0.2.10" 545 | source = "registry+https://github.com/rust-lang/crates.io-index" 546 | checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" 547 | dependencies = [ 548 | "cfg-if", 549 | "libc", 550 | "wasi", 551 | ] 552 | 553 | [[package]] 554 | name = "glob" 555 | version = "0.3.1" 556 | source = "registry+https://github.com/rust-lang/crates.io-index" 557 | checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" 558 | 559 | [[package]] 560 | name = "group" 561 | version = "0.11.0" 562 | source = "registry+https://github.com/rust-lang/crates.io-index" 563 | checksum = "bc5ac374b108929de78460075f3dc439fa66df9d8fc77e8f12caa5165fcf0c89" 564 | dependencies = [ 565 | "ff", 566 | "rand_core", 567 | "subtle", 568 | ] 569 | 570 | [[package]] 571 | name = "hashbrown" 572 | version = "0.14.0" 573 | source = "registry+https://github.com/rust-lang/crates.io-index" 574 | checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" 575 | 576 | [[package]] 577 | name = "heck" 578 | version = "0.4.1" 579 | source = "registry+https://github.com/rust-lang/crates.io-index" 580 | checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" 581 | 582 | [[package]] 583 | name = "helium-crypto" 584 | version = "0.8.0" 585 | source = "registry+https://github.com/rust-lang/crates.io-index" 586 | checksum = "f5847434afa99d189f926f2337172a2072785edc1762adb36313e74038c86008" 587 | dependencies = [ 588 | "base64", 589 | "bs58", 590 | "byteorder", 591 | "drop_guard", 592 | "ecc608-linux", 593 | "ed25519-compact", 594 | "getrandom", 595 | "k256", 596 | "lazy_static", 597 | "libc", 598 | "p256", 599 | "rand_core", 600 | "rsa", 601 | "serde", 602 | "sha2 0.10.7", 603 | "signature", 604 | "thiserror", 605 | "tss2", 606 | "uuid", 607 | ] 608 | 609 | [[package]] 610 | name = "hermit-abi" 611 | version = "0.3.2" 612 | source = "registry+https://github.com/rust-lang/crates.io-index" 613 | checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" 614 | 615 | [[package]] 616 | name = "hmac" 617 | version = "0.11.0" 618 | source = "registry+https://github.com/rust-lang/crates.io-index" 619 | checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" 620 | dependencies = [ 621 | "crypto-mac", 622 | "digest 0.9.0", 623 | ] 624 | 625 | [[package]] 626 | name = "http" 627 | version = "0.2.9" 628 | source = "registry+https://github.com/rust-lang/crates.io-index" 629 | checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" 630 | dependencies = [ 631 | "bytes", 632 | "fnv", 633 | "itoa", 634 | ] 635 | 636 | [[package]] 637 | name = "i2c-linux" 638 | version = "0.1.2" 639 | source = "registry+https://github.com/rust-lang/crates.io-index" 640 | checksum = "c0268a871aaa071221d6c2875ebedcf64710e59b0d87c68c8faf5e98b87dd2a4" 641 | dependencies = [ 642 | "bitflags 1.3.2", 643 | "i2c-linux-sys", 644 | "resize-slice", 645 | ] 646 | 647 | [[package]] 648 | name = "i2c-linux-sys" 649 | version = "0.2.1" 650 | source = "registry+https://github.com/rust-lang/crates.io-index" 651 | checksum = "55cd060ed0016621d3da4ed3a23b0158084de90d1f3a8e59f3d391aacd3bbcf8" 652 | dependencies = [ 653 | "bitflags 1.3.2", 654 | "byteorder", 655 | "libc", 656 | ] 657 | 658 | [[package]] 659 | name = "indexmap" 660 | version = "2.0.0" 661 | source = "registry+https://github.com/rust-lang/crates.io-index" 662 | checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" 663 | dependencies = [ 664 | "equivalent", 665 | "hashbrown", 666 | ] 667 | 668 | [[package]] 669 | name = "io-lifetimes" 670 | version = "1.0.11" 671 | source = "registry+https://github.com/rust-lang/crates.io-index" 672 | checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" 673 | dependencies = [ 674 | "hermit-abi", 675 | "libc", 676 | "windows-sys", 677 | ] 678 | 679 | [[package]] 680 | name = "is-terminal" 681 | version = "0.4.7" 682 | source = "registry+https://github.com/rust-lang/crates.io-index" 683 | checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" 684 | dependencies = [ 685 | "hermit-abi", 686 | "io-lifetimes", 687 | "rustix", 688 | "windows-sys", 689 | ] 690 | 691 | [[package]] 692 | name = "itoa" 693 | version = "1.0.9" 694 | source = "registry+https://github.com/rust-lang/crates.io-index" 695 | checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" 696 | 697 | [[package]] 698 | name = "k256" 699 | version = "0.10.4" 700 | source = "registry+https://github.com/rust-lang/crates.io-index" 701 | checksum = "19c3a5e0a0b8450278feda242592512e09f61c72e018b8cd5c859482802daf2d" 702 | dependencies = [ 703 | "cfg-if", 704 | "ecdsa", 705 | "elliptic-curve", 706 | "sec1", 707 | "sha2 0.9.9", 708 | ] 709 | 710 | [[package]] 711 | name = "lazy_static" 712 | version = "1.4.0" 713 | source = "registry+https://github.com/rust-lang/crates.io-index" 714 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 715 | dependencies = [ 716 | "spin", 717 | ] 718 | 719 | [[package]] 720 | name = "lazycell" 721 | version = "1.3.0" 722 | source = "registry+https://github.com/rust-lang/crates.io-index" 723 | checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" 724 | 725 | [[package]] 726 | name = "libc" 727 | version = "0.2.147" 728 | source = "registry+https://github.com/rust-lang/crates.io-index" 729 | checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" 730 | 731 | [[package]] 732 | name = "libloading" 733 | version = "0.7.4" 734 | source = "registry+https://github.com/rust-lang/crates.io-index" 735 | checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" 736 | dependencies = [ 737 | "cfg-if", 738 | "winapi", 739 | ] 740 | 741 | [[package]] 742 | name = "libm" 743 | version = "0.2.7" 744 | source = "registry+https://github.com/rust-lang/crates.io-index" 745 | checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" 746 | 747 | [[package]] 748 | name = "linux-raw-sys" 749 | version = "0.3.8" 750 | source = "registry+https://github.com/rust-lang/crates.io-index" 751 | checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" 752 | 753 | [[package]] 754 | name = "log" 755 | version = "0.4.20" 756 | source = "registry+https://github.com/rust-lang/crates.io-index" 757 | checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" 758 | 759 | [[package]] 760 | name = "mach" 761 | version = "0.1.2" 762 | source = "registry+https://github.com/rust-lang/crates.io-index" 763 | checksum = "2fd13ee2dd61cc82833ba05ade5a30bb3d63f7ced605ef827063c63078302de9" 764 | dependencies = [ 765 | "libc", 766 | ] 767 | 768 | [[package]] 769 | name = "mach2" 770 | version = "0.4.1" 771 | source = "registry+https://github.com/rust-lang/crates.io-index" 772 | checksum = "6d0d1830bcd151a6fc4aea1369af235b36c1528fe976b8ff678683c9995eade8" 773 | dependencies = [ 774 | "libc", 775 | ] 776 | 777 | [[package]] 778 | name = "md5" 779 | version = "0.7.0" 780 | source = "registry+https://github.com/rust-lang/crates.io-index" 781 | checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" 782 | 783 | [[package]] 784 | name = "memchr" 785 | version = "2.5.0" 786 | source = "registry+https://github.com/rust-lang/crates.io-index" 787 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" 788 | 789 | [[package]] 790 | name = "minimal-lexical" 791 | version = "0.2.1" 792 | source = "registry+https://github.com/rust-lang/crates.io-index" 793 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 794 | 795 | [[package]] 796 | name = "nix" 797 | version = "0.26.2" 798 | source = "registry+https://github.com/rust-lang/crates.io-index" 799 | checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" 800 | dependencies = [ 801 | "bitflags 1.3.2", 802 | "cfg-if", 803 | "libc", 804 | "static_assertions", 805 | ] 806 | 807 | [[package]] 808 | name = "nom" 809 | version = "7.1.3" 810 | source = "registry+https://github.com/rust-lang/crates.io-index" 811 | checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" 812 | dependencies = [ 813 | "memchr", 814 | "minimal-lexical", 815 | ] 816 | 817 | [[package]] 818 | name = "num-bigint" 819 | version = "0.4.3" 820 | source = "registry+https://github.com/rust-lang/crates.io-index" 821 | checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" 822 | dependencies = [ 823 | "autocfg", 824 | "num-integer", 825 | "num-traits", 826 | ] 827 | 828 | [[package]] 829 | name = "num-bigint-dig" 830 | version = "0.7.1" 831 | source = "registry+https://github.com/rust-lang/crates.io-index" 832 | checksum = "f9bc3e36fd683e004fd59c64a425e0e991616f5a8b617c3b9a933a93c168facc" 833 | dependencies = [ 834 | "byteorder", 835 | "lazy_static", 836 | "libm", 837 | "num-integer", 838 | "num-iter", 839 | "num-traits", 840 | "rand", 841 | "smallvec", 842 | "zeroize", 843 | ] 844 | 845 | [[package]] 846 | name = "num-integer" 847 | version = "0.1.45" 848 | source = "registry+https://github.com/rust-lang/crates.io-index" 849 | checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" 850 | dependencies = [ 851 | "autocfg", 852 | "num-traits", 853 | ] 854 | 855 | [[package]] 856 | name = "num-iter" 857 | version = "0.1.43" 858 | source = "registry+https://github.com/rust-lang/crates.io-index" 859 | checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" 860 | dependencies = [ 861 | "autocfg", 862 | "num-integer", 863 | "num-traits", 864 | ] 865 | 866 | [[package]] 867 | name = "num-traits" 868 | version = "0.2.16" 869 | source = "registry+https://github.com/rust-lang/crates.io-index" 870 | checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" 871 | dependencies = [ 872 | "autocfg", 873 | "libm", 874 | ] 875 | 876 | [[package]] 877 | name = "once_cell" 878 | version = "1.18.0" 879 | source = "registry+https://github.com/rust-lang/crates.io-index" 880 | checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" 881 | 882 | [[package]] 883 | name = "opaque-debug" 884 | version = "0.3.0" 885 | source = "registry+https://github.com/rust-lang/crates.io-index" 886 | checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" 887 | 888 | [[package]] 889 | name = "p256" 890 | version = "0.10.1" 891 | source = "registry+https://github.com/rust-lang/crates.io-index" 892 | checksum = "19736d80675fbe9fe33426268150b951a3fb8f5cfca2a23a17c85ef3adb24e3b" 893 | dependencies = [ 894 | "ecdsa", 895 | "elliptic-curve", 896 | "sec1", 897 | "sha2 0.9.9", 898 | ] 899 | 900 | [[package]] 901 | name = "peeking_take_while" 902 | version = "0.1.2" 903 | source = "registry+https://github.com/rust-lang/crates.io-index" 904 | checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" 905 | 906 | [[package]] 907 | name = "percent-encoding" 908 | version = "2.3.0" 909 | source = "registry+https://github.com/rust-lang/crates.io-index" 910 | checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" 911 | 912 | [[package]] 913 | name = "pest" 914 | version = "2.7.2" 915 | source = "registry+https://github.com/rust-lang/crates.io-index" 916 | checksum = "1acb4a4365a13f749a93f1a094a7805e5cfa0955373a9de860d962eaa3a5fe5a" 917 | dependencies = [ 918 | "thiserror", 919 | "ucd-trie", 920 | ] 921 | 922 | [[package]] 923 | name = "ppv-lite86" 924 | version = "0.2.17" 925 | source = "registry+https://github.com/rust-lang/crates.io-index" 926 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 927 | 928 | [[package]] 929 | name = "prettyplease" 930 | version = "0.2.12" 931 | source = "registry+https://github.com/rust-lang/crates.io-index" 932 | checksum = "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62" 933 | dependencies = [ 934 | "proc-macro2", 935 | "syn", 936 | ] 937 | 938 | [[package]] 939 | name = "proc-macro2" 940 | version = "1.0.66" 941 | source = "registry+https://github.com/rust-lang/crates.io-index" 942 | checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" 943 | dependencies = [ 944 | "unicode-ident", 945 | ] 946 | 947 | [[package]] 948 | name = "quote" 949 | version = "1.0.32" 950 | source = "registry+https://github.com/rust-lang/crates.io-index" 951 | checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" 952 | dependencies = [ 953 | "proc-macro2", 954 | ] 955 | 956 | [[package]] 957 | name = "rand" 958 | version = "0.8.5" 959 | source = "registry+https://github.com/rust-lang/crates.io-index" 960 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 961 | dependencies = [ 962 | "libc", 963 | "rand_chacha", 964 | "rand_core", 965 | ] 966 | 967 | [[package]] 968 | name = "rand_chacha" 969 | version = "0.3.1" 970 | source = "registry+https://github.com/rust-lang/crates.io-index" 971 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 972 | dependencies = [ 973 | "ppv-lite86", 974 | "rand_core", 975 | ] 976 | 977 | [[package]] 978 | name = "rand_core" 979 | version = "0.6.4" 980 | source = "registry+https://github.com/rust-lang/crates.io-index" 981 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 982 | dependencies = [ 983 | "getrandom", 984 | ] 985 | 986 | [[package]] 987 | name = "regex" 988 | version = "1.9.3" 989 | source = "registry+https://github.com/rust-lang/crates.io-index" 990 | checksum = "81bc1d4caf89fac26a70747fe603c130093b53c773888797a6329091246d651a" 991 | dependencies = [ 992 | "aho-corasick", 993 | "memchr", 994 | "regex-automata", 995 | "regex-syntax", 996 | ] 997 | 998 | [[package]] 999 | name = "regex-automata" 1000 | version = "0.3.6" 1001 | source = "registry+https://github.com/rust-lang/crates.io-index" 1002 | checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69" 1003 | dependencies = [ 1004 | "aho-corasick", 1005 | "memchr", 1006 | "regex-syntax", 1007 | ] 1008 | 1009 | [[package]] 1010 | name = "regex-syntax" 1011 | version = "0.7.4" 1012 | source = "registry+https://github.com/rust-lang/crates.io-index" 1013 | checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" 1014 | 1015 | [[package]] 1016 | name = "resize-slice" 1017 | version = "0.1.3" 1018 | source = "registry+https://github.com/rust-lang/crates.io-index" 1019 | checksum = "8a3cb2f74a9891e76958b9e0ccd269a25b466c3ae3bb3efd71db157248308c4a" 1020 | dependencies = [ 1021 | "uninitialized", 1022 | ] 1023 | 1024 | [[package]] 1025 | name = "rfc6979" 1026 | version = "0.1.0" 1027 | source = "registry+https://github.com/rust-lang/crates.io-index" 1028 | checksum = "96ef608575f6392792f9ecf7890c00086591d29a83910939d430753f7c050525" 1029 | dependencies = [ 1030 | "crypto-bigint", 1031 | "hmac", 1032 | "zeroize", 1033 | ] 1034 | 1035 | [[package]] 1036 | name = "rsa" 1037 | version = "0.4.1" 1038 | source = "registry+https://github.com/rust-lang/crates.io-index" 1039 | checksum = "7b0aeddcca1082112a6eeb43bf25fd7820b066aaf6eaef776e19d0a1febe38fe" 1040 | dependencies = [ 1041 | "byteorder", 1042 | "digest 0.9.0", 1043 | "lazy_static", 1044 | "num-bigint-dig", 1045 | "num-integer", 1046 | "num-iter", 1047 | "num-traits", 1048 | "rand", 1049 | "simple_asn1", 1050 | "subtle", 1051 | "zeroize", 1052 | ] 1053 | 1054 | [[package]] 1055 | name = "rustc-hash" 1056 | version = "1.1.0" 1057 | source = "registry+https://github.com/rust-lang/crates.io-index" 1058 | checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" 1059 | 1060 | [[package]] 1061 | name = "rustix" 1062 | version = "0.37.23" 1063 | source = "registry+https://github.com/rust-lang/crates.io-index" 1064 | checksum = "4d69718bf81c6127a49dc64e44a742e8bb9213c0ff8869a22c308f84c1d4ab06" 1065 | dependencies = [ 1066 | "bitflags 1.3.2", 1067 | "errno", 1068 | "io-lifetimes", 1069 | "libc", 1070 | "linux-raw-sys", 1071 | "windows-sys", 1072 | ] 1073 | 1074 | [[package]] 1075 | name = "ryu" 1076 | version = "1.0.15" 1077 | source = "registry+https://github.com/rust-lang/crates.io-index" 1078 | checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" 1079 | 1080 | [[package]] 1081 | name = "scopeguard" 1082 | version = "1.2.0" 1083 | source = "registry+https://github.com/rust-lang/crates.io-index" 1084 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 1085 | 1086 | [[package]] 1087 | name = "sec1" 1088 | version = "0.2.1" 1089 | source = "registry+https://github.com/rust-lang/crates.io-index" 1090 | checksum = "08da66b8b0965a5555b6bd6639e68ccba85e1e2506f5fbb089e93f8a04e1a2d1" 1091 | dependencies = [ 1092 | "der", 1093 | "generic-array", 1094 | "subtle", 1095 | "zeroize", 1096 | ] 1097 | 1098 | [[package]] 1099 | name = "semver" 1100 | version = "0.11.0" 1101 | source = "registry+https://github.com/rust-lang/crates.io-index" 1102 | checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" 1103 | dependencies = [ 1104 | "semver-parser", 1105 | ] 1106 | 1107 | [[package]] 1108 | name = "semver-parser" 1109 | version = "0.10.2" 1110 | source = "registry+https://github.com/rust-lang/crates.io-index" 1111 | checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" 1112 | dependencies = [ 1113 | "pest", 1114 | ] 1115 | 1116 | [[package]] 1117 | name = "serde" 1118 | version = "1.0.183" 1119 | source = "registry+https://github.com/rust-lang/crates.io-index" 1120 | checksum = "32ac8da02677876d532745a130fc9d8e6edfa81a269b107c5b00829b91d8eb3c" 1121 | dependencies = [ 1122 | "serde_derive", 1123 | ] 1124 | 1125 | [[package]] 1126 | name = "serde_derive" 1127 | version = "1.0.183" 1128 | source = "registry+https://github.com/rust-lang/crates.io-index" 1129 | checksum = "aafe972d60b0b9bee71a91b92fee2d4fb3c9d7e8f6b179aa99f27203d99a4816" 1130 | dependencies = [ 1131 | "proc-macro2", 1132 | "quote", 1133 | "syn", 1134 | ] 1135 | 1136 | [[package]] 1137 | name = "serde_json" 1138 | version = "1.0.104" 1139 | source = "registry+https://github.com/rust-lang/crates.io-index" 1140 | checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" 1141 | dependencies = [ 1142 | "itoa", 1143 | "ryu", 1144 | "serde", 1145 | ] 1146 | 1147 | [[package]] 1148 | name = "serde_spanned" 1149 | version = "0.6.3" 1150 | source = "registry+https://github.com/rust-lang/crates.io-index" 1151 | checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" 1152 | dependencies = [ 1153 | "serde", 1154 | ] 1155 | 1156 | [[package]] 1157 | name = "serde_urlencoded" 1158 | version = "0.7.1" 1159 | source = "registry+https://github.com/rust-lang/crates.io-index" 1160 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 1161 | dependencies = [ 1162 | "form_urlencoded", 1163 | "itoa", 1164 | "ryu", 1165 | "serde", 1166 | ] 1167 | 1168 | [[package]] 1169 | name = "serialport" 1170 | version = "4.2.2" 1171 | source = "registry+https://github.com/rust-lang/crates.io-index" 1172 | checksum = "c32634e2bd4311420caa504404a55fad2131292c485c97014cbed89a5899885f" 1173 | dependencies = [ 1174 | "CoreFoundation-sys", 1175 | "IOKit-sys", 1176 | "bitflags 2.0.2", 1177 | "cfg-if", 1178 | "mach2", 1179 | "nix", 1180 | "regex", 1181 | "scopeguard", 1182 | "winapi", 1183 | ] 1184 | 1185 | [[package]] 1186 | name = "sha2" 1187 | version = "0.9.9" 1188 | source = "registry+https://github.com/rust-lang/crates.io-index" 1189 | checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" 1190 | dependencies = [ 1191 | "block-buffer 0.9.0", 1192 | "cfg-if", 1193 | "cpufeatures", 1194 | "digest 0.9.0", 1195 | "opaque-debug", 1196 | ] 1197 | 1198 | [[package]] 1199 | name = "sha2" 1200 | version = "0.10.7" 1201 | source = "registry+https://github.com/rust-lang/crates.io-index" 1202 | checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" 1203 | dependencies = [ 1204 | "cfg-if", 1205 | "cpufeatures", 1206 | "digest 0.10.7", 1207 | ] 1208 | 1209 | [[package]] 1210 | name = "shlex" 1211 | version = "1.1.0" 1212 | source = "registry+https://github.com/rust-lang/crates.io-index" 1213 | checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" 1214 | 1215 | [[package]] 1216 | name = "signature" 1217 | version = "1.4.0" 1218 | source = "registry+https://github.com/rust-lang/crates.io-index" 1219 | checksum = "02658e48d89f2bec991f9a78e69cfa4c316f8d6a6c4ec12fae1aeb263d486788" 1220 | dependencies = [ 1221 | "digest 0.9.0", 1222 | "rand_core", 1223 | ] 1224 | 1225 | [[package]] 1226 | name = "simple_asn1" 1227 | version = "0.5.4" 1228 | source = "registry+https://github.com/rust-lang/crates.io-index" 1229 | checksum = "8eb4ea60fb301dc81dfc113df680571045d375ab7345d171c5dc7d7e13107a80" 1230 | dependencies = [ 1231 | "chrono", 1232 | "num-bigint", 1233 | "num-traits", 1234 | "thiserror", 1235 | ] 1236 | 1237 | [[package]] 1238 | name = "smallvec" 1239 | version = "1.11.0" 1240 | source = "registry+https://github.com/rust-lang/crates.io-index" 1241 | checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" 1242 | 1243 | [[package]] 1244 | name = "spin" 1245 | version = "0.5.2" 1246 | source = "registry+https://github.com/rust-lang/crates.io-index" 1247 | checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" 1248 | 1249 | [[package]] 1250 | name = "static_assertions" 1251 | version = "1.1.0" 1252 | source = "registry+https://github.com/rust-lang/crates.io-index" 1253 | checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" 1254 | 1255 | [[package]] 1256 | name = "strsim" 1257 | version = "0.10.0" 1258 | source = "registry+https://github.com/rust-lang/crates.io-index" 1259 | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 1260 | 1261 | [[package]] 1262 | name = "subtle" 1263 | version = "2.4.1" 1264 | source = "registry+https://github.com/rust-lang/crates.io-index" 1265 | checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" 1266 | 1267 | [[package]] 1268 | name = "syn" 1269 | version = "2.0.28" 1270 | source = "registry+https://github.com/rust-lang/crates.io-index" 1271 | checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" 1272 | dependencies = [ 1273 | "proc-macro2", 1274 | "quote", 1275 | "unicode-ident", 1276 | ] 1277 | 1278 | [[package]] 1279 | name = "thiserror" 1280 | version = "1.0.44" 1281 | source = "registry+https://github.com/rust-lang/crates.io-index" 1282 | checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" 1283 | dependencies = [ 1284 | "thiserror-impl", 1285 | ] 1286 | 1287 | [[package]] 1288 | name = "thiserror-impl" 1289 | version = "1.0.44" 1290 | source = "registry+https://github.com/rust-lang/crates.io-index" 1291 | checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" 1292 | dependencies = [ 1293 | "proc-macro2", 1294 | "quote", 1295 | "syn", 1296 | ] 1297 | 1298 | [[package]] 1299 | name = "tinyvec" 1300 | version = "1.6.0" 1301 | source = "registry+https://github.com/rust-lang/crates.io-index" 1302 | checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" 1303 | dependencies = [ 1304 | "tinyvec_macros", 1305 | ] 1306 | 1307 | [[package]] 1308 | name = "tinyvec_macros" 1309 | version = "0.1.1" 1310 | source = "registry+https://github.com/rust-lang/crates.io-index" 1311 | checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" 1312 | 1313 | [[package]] 1314 | name = "toml" 1315 | version = "0.7.6" 1316 | source = "registry+https://github.com/rust-lang/crates.io-index" 1317 | checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542" 1318 | dependencies = [ 1319 | "serde", 1320 | "serde_spanned", 1321 | "toml_datetime", 1322 | "toml_edit", 1323 | ] 1324 | 1325 | [[package]] 1326 | name = "toml_datetime" 1327 | version = "0.6.3" 1328 | source = "registry+https://github.com/rust-lang/crates.io-index" 1329 | checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" 1330 | dependencies = [ 1331 | "serde", 1332 | ] 1333 | 1334 | [[package]] 1335 | name = "toml_edit" 1336 | version = "0.19.14" 1337 | source = "registry+https://github.com/rust-lang/crates.io-index" 1338 | checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" 1339 | dependencies = [ 1340 | "indexmap", 1341 | "serde", 1342 | "serde_spanned", 1343 | "toml_datetime", 1344 | "winnow", 1345 | ] 1346 | 1347 | [[package]] 1348 | name = "tss2" 1349 | version = "0.1.3" 1350 | source = "registry+https://github.com/rust-lang/crates.io-index" 1351 | checksum = "168c56265eb9153cbc97235aec648bdae6128ca18cd68e1344f114cdb8de5e69" 1352 | dependencies = [ 1353 | "bindgen", 1354 | ] 1355 | 1356 | [[package]] 1357 | name = "typenum" 1358 | version = "1.16.0" 1359 | source = "registry+https://github.com/rust-lang/crates.io-index" 1360 | checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" 1361 | 1362 | [[package]] 1363 | name = "ucd-trie" 1364 | version = "0.1.6" 1365 | source = "registry+https://github.com/rust-lang/crates.io-index" 1366 | checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" 1367 | 1368 | [[package]] 1369 | name = "unicode-ident" 1370 | version = "1.0.11" 1371 | source = "registry+https://github.com/rust-lang/crates.io-index" 1372 | checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" 1373 | 1374 | [[package]] 1375 | name = "uninitialized" 1376 | version = "0.0.2" 1377 | source = "registry+https://github.com/rust-lang/crates.io-index" 1378 | checksum = "74c1aa4511c38276c548406f0b1f5f8b793f000cfb51e18f278a102abd057e81" 1379 | 1380 | [[package]] 1381 | name = "utf8parse" 1382 | version = "0.2.1" 1383 | source = "registry+https://github.com/rust-lang/crates.io-index" 1384 | checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" 1385 | 1386 | [[package]] 1387 | name = "uuid" 1388 | version = "1.4.1" 1389 | source = "registry+https://github.com/rust-lang/crates.io-index" 1390 | checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" 1391 | dependencies = [ 1392 | "getrandom", 1393 | "rand", 1394 | ] 1395 | 1396 | [[package]] 1397 | name = "version_check" 1398 | version = "0.9.4" 1399 | source = "registry+https://github.com/rust-lang/crates.io-index" 1400 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 1401 | 1402 | [[package]] 1403 | name = "wasi" 1404 | version = "0.11.0+wasi-snapshot-preview1" 1405 | source = "registry+https://github.com/rust-lang/crates.io-index" 1406 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1407 | 1408 | [[package]] 1409 | name = "which" 1410 | version = "4.4.0" 1411 | source = "registry+https://github.com/rust-lang/crates.io-index" 1412 | checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" 1413 | dependencies = [ 1414 | "either", 1415 | "libc", 1416 | "once_cell", 1417 | ] 1418 | 1419 | [[package]] 1420 | name = "winapi" 1421 | version = "0.3.9" 1422 | source = "registry+https://github.com/rust-lang/crates.io-index" 1423 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1424 | dependencies = [ 1425 | "winapi-i686-pc-windows-gnu", 1426 | "winapi-x86_64-pc-windows-gnu", 1427 | ] 1428 | 1429 | [[package]] 1430 | name = "winapi-i686-pc-windows-gnu" 1431 | version = "0.4.0" 1432 | source = "registry+https://github.com/rust-lang/crates.io-index" 1433 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1434 | 1435 | [[package]] 1436 | name = "winapi-x86_64-pc-windows-gnu" 1437 | version = "0.4.0" 1438 | source = "registry+https://github.com/rust-lang/crates.io-index" 1439 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1440 | 1441 | [[package]] 1442 | name = "windows-sys" 1443 | version = "0.48.0" 1444 | source = "registry+https://github.com/rust-lang/crates.io-index" 1445 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 1446 | dependencies = [ 1447 | "windows-targets", 1448 | ] 1449 | 1450 | [[package]] 1451 | name = "windows-targets" 1452 | version = "0.48.2" 1453 | source = "registry+https://github.com/rust-lang/crates.io-index" 1454 | checksum = "d1eeca1c172a285ee6c2c84c341ccea837e7c01b12fbb2d0fe3c9e550ce49ec8" 1455 | dependencies = [ 1456 | "windows_aarch64_gnullvm", 1457 | "windows_aarch64_msvc", 1458 | "windows_i686_gnu", 1459 | "windows_i686_msvc", 1460 | "windows_x86_64_gnu", 1461 | "windows_x86_64_gnullvm", 1462 | "windows_x86_64_msvc", 1463 | ] 1464 | 1465 | [[package]] 1466 | name = "windows_aarch64_gnullvm" 1467 | version = "0.48.2" 1468 | source = "registry+https://github.com/rust-lang/crates.io-index" 1469 | checksum = "b10d0c968ba7f6166195e13d593af609ec2e3d24f916f081690695cf5eaffb2f" 1470 | 1471 | [[package]] 1472 | name = "windows_aarch64_msvc" 1473 | version = "0.48.2" 1474 | source = "registry+https://github.com/rust-lang/crates.io-index" 1475 | checksum = "571d8d4e62f26d4932099a9efe89660e8bd5087775a2ab5cdd8b747b811f1058" 1476 | 1477 | [[package]] 1478 | name = "windows_i686_gnu" 1479 | version = "0.48.2" 1480 | source = "registry+https://github.com/rust-lang/crates.io-index" 1481 | checksum = "2229ad223e178db5fbbc8bd8d3835e51e566b8474bfca58d2e6150c48bb723cd" 1482 | 1483 | [[package]] 1484 | name = "windows_i686_msvc" 1485 | version = "0.48.2" 1486 | source = "registry+https://github.com/rust-lang/crates.io-index" 1487 | checksum = "600956e2d840c194eedfc5d18f8242bc2e17c7775b6684488af3a9fff6fe3287" 1488 | 1489 | [[package]] 1490 | name = "windows_x86_64_gnu" 1491 | version = "0.48.2" 1492 | source = "registry+https://github.com/rust-lang/crates.io-index" 1493 | checksum = "ea99ff3f8b49fb7a8e0d305e5aec485bd068c2ba691b6e277d29eaeac945868a" 1494 | 1495 | [[package]] 1496 | name = "windows_x86_64_gnullvm" 1497 | version = "0.48.2" 1498 | source = "registry+https://github.com/rust-lang/crates.io-index" 1499 | checksum = "8f1a05a1ece9a7a0d5a7ccf30ba2c33e3a61a30e042ffd247567d1de1d94120d" 1500 | 1501 | [[package]] 1502 | name = "windows_x86_64_msvc" 1503 | version = "0.48.2" 1504 | source = "registry+https://github.com/rust-lang/crates.io-index" 1505 | checksum = "d419259aba16b663966e29e6d7c6ecfa0bb8425818bb96f6f1f3c3eb71a6e7b9" 1506 | 1507 | [[package]] 1508 | name = "winnow" 1509 | version = "0.5.10" 1510 | source = "registry+https://github.com/rust-lang/crates.io-index" 1511 | checksum = "5504cc7644f4b593cbc05c4a55bf9bd4e94b867c3c0bd440934174d50482427d" 1512 | dependencies = [ 1513 | "memchr", 1514 | ] 1515 | 1516 | [[package]] 1517 | name = "zeroize" 1518 | version = "1.3.0" 1519 | source = "registry+https://github.com/rust-lang/crates.io-index" 1520 | checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" 1521 | dependencies = [ 1522 | "zeroize_derive", 1523 | ] 1524 | 1525 | [[package]] 1526 | name = "zeroize_derive" 1527 | version = "1.4.2" 1528 | source = "registry+https://github.com/rust-lang/crates.io-index" 1529 | checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" 1530 | dependencies = [ 1531 | "proc-macro2", 1532 | "quote", 1533 | "syn", 1534 | ] 1535 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "gateway-mfr" 3 | version = "0.5.4" 4 | authors = ["Marc Nijdam "] 5 | edition = "2021" 6 | license = "Apache-2.0" 7 | 8 | [[bin]] 9 | name = "gateway_mfr" 10 | path = "src/main.rs" 11 | doc = false 12 | 13 | [dependencies] 14 | clap = { version = "4", features = ["derive"] } 15 | anyhow = "1" 16 | semver = "0" 17 | serde = { version = "1", features = ["derive"] } 18 | toml = { version = "0" } 19 | rand = "0.8" 20 | serde_json = "1" 21 | serde_urlencoded = "*" 22 | http = "0" 23 | bytes = "*" 24 | angry-purple-tiger = "0" 25 | helium-crypto = { version = ">=0.8" } 26 | 27 | [features] 28 | default = ["ecc608"] 29 | tpm = ["helium-crypto/tpm"] 30 | ecc608 = ["helium-crypto/ecc608"] 31 | nova-tz = ["helium-crypto/nova-tz"] 32 | -------------------------------------------------------------------------------- /Cross.toml: -------------------------------------------------------------------------------- 1 | [target.armv7-unknown-linux-gnueabihf.env] 2 | volumes = [ 3 | "BUILD_DIR", 4 | ] 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | Copyright 2018, Helium Systems Inc. 179 | 180 | Licensed under the Apache License, Version 2.0 (the "License"); 181 | you may not use this file except in compliance with the License. 182 | You may obtain a copy of the License at 183 | 184 | http://www.apache.org/licenses/LICENSE-2.0 185 | 186 | Unless required by applicable law or agreed to in writing, software 187 | distributed under the License is distributed on an "AS IS" BASIS, 188 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 189 | See the License for the specific language governing permissions and 190 | limitations under the License. 191 | 192 | -------------------------------------------------------------------------------- /Makefile.toml: -------------------------------------------------------------------------------- 1 | [env] 2 | CROSS_TARGET = "${CARGO_MAKE_PROFILE}" 3 | FEATURES = "ecc608" 4 | BUILD_COMMAND = "cross" 5 | TAR = { source = "${CARGO_MAKE_RUST_TARGET_OS}", default_value = "linux", mapping = {"macos" = "gtar", "linux" = "tar" } } 6 | 7 | [env.x86_64-unknown-debian-gnu] 8 | CROSS_TARGET = "x86_64-unknown-linux-gnu" 9 | CROSS_BUILD_DOCKERFILE = "./.github/cross-docker/Dockerfile-cross-debian-11" 10 | 11 | [env.x86_64-tpm-debian-gnu] 12 | CROSS_TARGET = "x86_64-unknown-linux-gnu" 13 | CROSS_BUILD_DOCKERFILE = "./.github/cross-docker/Dockerfile-cross-debian-11" 14 | FEATURES = "tpm" 15 | 16 | [tasks.build] 17 | description = "Runs the cross/cargo rust compiler." 18 | condition = { env_set = ["CROSS_TARGET", "BUILD_COMMAND", "FEATURES"] } 19 | command = "${BUILD_COMMAND}" 20 | args = [ 21 | "build", 22 | "--target", 23 | "${CROSS_TARGET}", 24 | "--features", 25 | "${FEATURES}", 26 | "--release" 27 | ] 28 | 29 | [tasks.pkg] 30 | description = "Package application" 31 | workspace = false 32 | condition = { env_set = ["CARGO_MAKE_PROFILE", "CROSS_TARGET"]} 33 | env = { PKG_NAME = "gateway-mfr-v${CARGO_MAKE_CRATE_VERSION}-${CARGO_MAKE_PROFILE}" } 34 | script = ''' 35 | ${TAR} -zcv -C target/${CROSS_TARGET}/release -f ${PKG_NAME}.tar.gz gateway_mfr 36 | sha256sum --tag ${PKG_NAME}.tar.gz > ${PKG_NAME}.checksum 37 | ''' 38 | 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status][actions-badge]][actions-url] 2 | [![Discord chat][discord-badge]][discord-url] 3 | 4 | [actions-badge]: https://github.com/helium/gateway-mfr-rs/actions/workflows/ci.yml/badge.svg 5 | [actions-url]: https://github.com/helium/gateway-mfr-rs/actions/workflows/ci.yml 6 | [discord-badge]: https://img.shields.io/discord/500028886025895936.svg?logo=discord&style=flat-square 7 | [discord-url]: https://discord.gg/helium 8 | 9 | ## gateway-mfr-rs 10 | 11 | The gateway_mfr application provisions an security part (like the ECC508/ECC608) 12 | for use as part of a Helium hotspot, and provides utilities for testing and 13 | benchmarking the addressed part. 14 | 15 | In the ECC case, it does provisioning by configuring and locking the ECC 16 | configuration fields and then generating the miner key in the slot identified in 17 | the device URL (default slot 0). 18 | 19 | Other security parts may be provisioned in different ways or may have been 20 | locked down before hotspot integration. 21 | 22 | The public part of the miner key needs to be captured from the output of this 23 | application and supplied as part of the data required to get into the Helium 24 | Onboarding Server if gateway add and assert location transactions are to be paid 25 | for on behalf of the user. 26 | 27 | This applications should be used as part of a manufacturing image that does NOT 28 | include the Helium miner software and is solely used for testing and 29 | provisioning the built hotspot before setting up the production miner image. 30 | 31 | ## Addressing 32 | 33 | The security device to provision or test is addressed using a `--device` option. 34 | In the ECC case, for exmaple this URL could be `ecc://i2c-1:96?slot=0` to 35 | address the `/dev/i2c-1` linux device, using the bus address`96` and slot `0` on 36 | the ECC device. This is also the default URL for the application, and must be 37 | provided for ECC parts with a different bus address or slot. 38 | 39 | If you are passing an additional command such as those decribed in the [usage section](#usage) below those commands need to come after the device address. For example: 40 | 41 | ``` 42 | gateway_mfr --device ecc://i2c-1:96?slot=0 key 43 | ``` 44 | 45 | Each security part will have it's own URL scheme and host/path arguments to 46 | address the specific system and entry used for key material and provisioning. 47 | 48 | ## Usage 49 | 50 | 1. Using the application can be done in two ways; 51 | 52 | - Download a pre-built binary from the 53 | [releases](https://github.com/helium/gateway-mfr-rs/releases/latest) page. 54 | Note that the `unknown` target systems are all `ecc608` based targets. To 55 | find the right target binary for a given platform, look at the [supported 56 | targets](https://github.com/helium/gateway-rs#supported-targets) for the 57 | maker name and associated target. 58 | 59 | - Build the application. This will involve [installing 60 | rust](https://www.rust-lang.org/learn/get-started) on the host system and 61 | cross compiling for running the application on the target hardware. 62 | [Install cross](https://github.com/rust-embedded/cross) make cross 63 | compiling to targets easier. Also install 64 | [cargo-make](https://github.com/sagiegurari/cargo-make) to set up for 65 | packaging and specific profile support. 66 | 67 | For example to compile for Raspbery-Pi's aarch64 architecture: 68 | 69 | ```shell 70 | cargo make --profile aarch64-unknown-linux-musl --release 71 | ``` 72 | 73 | The resulting cross compiled binary will be located in `./target/ aarch64-unknown-linux-musl/release/gateway_mfr` 74 | 75 | **NOTE**: For some profiles the resulting target will not be in the profile 76 | name but under the target system triplet that was used to build the target. 77 | For example, the `x86_64-tpm-debian-gnu` uses the `x86_64-unkown-linux-gnu` 78 | target but a custom Docker file to build using Debian since that is where 79 | `tpm` is supported. 80 | 81 | 2. As part of the provisioning/QA steps start and provision the security part: 82 | 83 | ```shell 84 | gateway_mfr provision 85 | ``` 86 | 87 | This will configure the security part, generate the miner key and output it 88 | to stdout. Capture this output and collect it and other required information 89 | for use by the Onboarding Server. 90 | 91 | If you need the extract the onboarding/miner key at a later stage you can 92 | run: 93 | 94 | ```shell 95 | gateway_mfr key 96 | ``` 97 | 98 | **NOTE**: Do **not** include this application in the final image as it is not 99 | used as part of normal hotspot operations. 100 | 101 | 3. To verify that the security part is configured correctly you can run a final 102 | test cycle as part of the QA steps: 103 | 104 | ```shell 105 | gateway_mfr test 106 | ``` 107 | 108 | This will output a json table with all executed tests for the security part 109 | and their results. This includes a top level `result` key with `pass` or 110 | `fail` as the value. 111 | 112 | Tests are specific for each security part and are intended to test that the 113 | security part is locked, and that signing and ecdh opterations function 114 | 115 | 4. To benchmark a security part as part of integration: 116 | 117 | ```shell 118 | gateway_mfr bench 119 | ``` 120 | 121 | This will run a number of signing iterations (default 100) and report the 122 | average signing time and the number of signing operations per second. 123 | 124 | Helium Hotspots using a full miner will need 6-7 or better signing operations 125 | per second while light/dataonly hotspots should be able to operate with 126 | around 3-5 operations per second (this number needs to be confirmed). 127 | 128 | The security part is now configured for production use. The production image, 129 | including the Helium miner can be installed and started. If configured correctly 130 | the miner software will use the configured key in slot 0 as the miner key and 131 | use the security part for secured transaction signing. 132 | 133 | The full suite of options can be found by running the help command: 134 | 135 | ```shell 136 | gateway_mfr help 137 | ``` 138 | 139 | This will give you an output like the following where you can find all of the options listed: 140 | 141 | ``` 142 | gateway_mfr 0.3.2 143 | Gateway Manufacturing 144 | 145 | USAGE: 146 | gateway_mfr [OPTIONS] 147 | 148 | FLAGS: 149 | -h, --help Prints help information 150 | -V, --version Prints version information 151 | 152 | OPTIONS: 153 | --device The security device to use [default: ecc://i2c-1] 154 | 155 | SUBCOMMANDS: 156 | bench Run a benchmark test 157 | config Gets the zone, slot or key config for a given ecc slot 158 | help Prints this message or the help of the given subcommand(s) 159 | info Get ecc chip information 160 | key Prints public key information for a given slot 161 | provision Configures the ECC for gateway/miner use. This includes configuring slot and key configs for †he 162 | given slot, locking the data and config zone and generating an ecc compact key in the configured 163 | slot 164 | test Read the slot configuration for a given slot 165 | ``` 166 | -------------------------------------------------------------------------------- /release.toml: -------------------------------------------------------------------------------- 1 | sign-commit = true 2 | sign-tag = true 3 | publish = false 4 | -------------------------------------------------------------------------------- /src/cmd/bench.rs: -------------------------------------------------------------------------------- 1 | use crate::{cmd::print_json, Device, Result}; 2 | use helium_crypto::{Keypair, Sign}; 3 | use rand::{rngs::OsRng, RngCore}; 4 | use serde_json::json; 5 | use std::time::{Duration, Instant}; 6 | 7 | /// Run a benchmark test. 8 | /// 9 | /// This reports number of signing operations per second a security part can 10 | /// handle 11 | #[derive(Debug, clap::Args)] 12 | pub struct Cmd { 13 | /// Number of iterations to use for test 14 | #[arg(long, short, default_value_t = 100)] 15 | pub iterations: u32, 16 | } 17 | 18 | impl Cmd { 19 | pub fn run(&self, device: &Device) -> Result { 20 | device.init()?; 21 | let keypair = device.get_keypair(false)?; 22 | let duration = bench_sign(&keypair, self.iterations)?; 23 | let rate = self.iterations as f64 / duration.as_secs_f64(); 24 | let avg_ms = duration.as_millis() as f64 / self.iterations as f64; 25 | let json = json!({ 26 | "iterations": self.iterations, 27 | "avg_ms": round2(avg_ms), 28 | "rate": round2(rate), 29 | }); 30 | print_json(&json) 31 | } 32 | } 33 | 34 | fn round2(v: f64) -> f64 { 35 | (v * 100.0).round() / 100.0 36 | } 37 | 38 | fn bench_sign(keypair: &Keypair, iterations: u32) -> Result { 39 | let mut total_duration = Duration::new(0, 0); 40 | for _ in 0..iterations { 41 | let mut data = [0u8; 32]; 42 | OsRng.try_fill_bytes(&mut data)?; 43 | 44 | let start = Instant::now(); 45 | let _signature = keypair.sign(&data)?; 46 | total_duration += start.elapsed(); 47 | } 48 | Ok(total_duration) 49 | } 50 | -------------------------------------------------------------------------------- /src/cmd/config.rs: -------------------------------------------------------------------------------- 1 | use crate::{cmd::print_json, Device, Result}; 2 | 3 | /// Gets the security device configuration 4 | #[derive(Debug, clap::Args)] 5 | pub struct Cmd {} 6 | 7 | impl Cmd { 8 | pub fn run(&self, device: &Device) -> Result { 9 | device.init()?; 10 | let config = device.get_config()?; 11 | print_json(&config) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/cmd/generate.rs: -------------------------------------------------------------------------------- 1 | use crate::{Device, Result}; 2 | 3 | /// Generate default configuration files for the given security device. 4 | #[derive(Debug, clap::Args)] 5 | pub struct Cmd {} 6 | 7 | impl Cmd { 8 | pub fn run(&self, device: &Device) -> Result { 9 | let config = device.generate_config()?; 10 | let toml = toml::to_string_pretty(&config)?; 11 | println!("{}", toml); 12 | Ok(()) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/cmd/info.rs: -------------------------------------------------------------------------------- 1 | use crate::{cmd::print_json, device::Device, Result}; 2 | 3 | /// Get ecc chip information 4 | #[derive(Debug, clap::Args)] 5 | pub struct Cmd {} 6 | 7 | impl Cmd { 8 | pub fn run(&self, device: &Device) -> Result { 9 | device.init()?; 10 | let info = device.get_info()?; 11 | print_json(&info) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/cmd/key.rs: -------------------------------------------------------------------------------- 1 | use crate::{cmd::print_json, Device, Result}; 2 | use angry_purple_tiger::AnimalName; 3 | use helium_crypto::Keypair; 4 | use serde_json::json; 5 | 6 | /// Prints public key information from the security device 7 | #[derive(Debug, clap::Args)] 8 | pub struct Cmd { 9 | /// Generate a new private key in the slot. WARNING: This will overwrite the 10 | /// existing private key on the security device. 11 | #[arg(long)] 12 | pub generate: bool, 13 | } 14 | 15 | impl Cmd { 16 | pub fn run(&self, device: &Device) -> Result { 17 | device.init()?; 18 | let keypair = device.get_keypair(self.generate)?; 19 | print_keypair(&keypair) 20 | } 21 | } 22 | 23 | pub(crate) fn print_keypair(keypair: &Keypair) -> Result { 24 | let public_key_str = keypair.public_key().to_string(); 25 | let json = json!({ 26 | "key": public_key_str, 27 | "name": public_key_str.parse::()?.to_string(), 28 | }); 29 | print_json(&json) 30 | } 31 | -------------------------------------------------------------------------------- /src/cmd/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod bench; 2 | pub mod config; 3 | pub mod generate; 4 | pub mod info; 5 | pub mod key; 6 | pub mod provision; 7 | pub mod test; 8 | 9 | pub fn print_json(value: &T) -> crate::Result { 10 | println!("{}", serde_json::to_string_pretty(value)?); 11 | Ok(()) 12 | } 13 | -------------------------------------------------------------------------------- /src/cmd/provision.rs: -------------------------------------------------------------------------------- 1 | use crate::{cmd::key::print_keypair, Device, Result}; 2 | 3 | /// Configures the security device for gateway/miner use. 4 | #[derive(Debug, clap::Args)] 5 | pub struct Cmd {} 6 | 7 | impl Cmd { 8 | pub fn run(&self, device: &Device) -> Result { 9 | device.init()?; 10 | let keypair = device.provision()?; 11 | print_keypair(&keypair) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/cmd/test.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | cmd::print_json, 3 | device::{ 4 | test::{self, TestOutcome, TestResult}, 5 | Device, 6 | }, 7 | Result, 8 | }; 9 | use serde_json::json; 10 | use std::collections::HashMap; 11 | 12 | /// Read the slot configuration for a given slot 13 | #[derive(Debug, clap::Args)] 14 | pub struct Cmd {} 15 | 16 | impl Cmd { 17 | pub fn run(&self, device: &Device) -> Result { 18 | device.init()?; 19 | let tests = device.get_tests(); 20 | let results: Vec<(String, TestResult)> = tests 21 | .iter() 22 | .map(|test| (test.to_string(), test.run())) 23 | .collect(); 24 | let passed = test_results_to_pass_fail(&results); 25 | let json_results: Vec<(String, serde_json::Value)> = results 26 | .into_iter() 27 | .map(|(test, result)| { 28 | let (out_name, out_json) = test_result_to_json(&result); 29 | ( 30 | test, 31 | json!({ 32 | "result": test_result_to_pass_fail(&result), 33 | out_name: out_json, 34 | }), 35 | ) 36 | }) 37 | .collect(); 38 | let result_map: HashMap = HashMap::from_iter(json_results); 39 | let json = json!({ 40 | "result": passed, 41 | "tests": result_map, 42 | }); 43 | 44 | print_json(&json) 45 | } 46 | } 47 | 48 | fn test_result_to_pass_fail(result: &TestResult) -> String { 49 | result 50 | .as_ref() 51 | .map(|outcome| outcome.to_string()) 52 | .unwrap_or_else(|_| "fail".to_string()) 53 | } 54 | 55 | fn test_results_to_pass_fail(results: &[(String, TestResult)]) -> &'static str { 56 | if results 57 | .iter() 58 | .all(|(_, result)| result.as_ref().map_or(false, |outcome| outcome.passed())) 59 | { 60 | "pass" 61 | } else { 62 | "fail" 63 | } 64 | } 65 | 66 | fn test_result_to_json(result: &TestResult) -> (&'static str, TestOutcome) { 67 | result 68 | .as_ref() 69 | .map(|outcome| ("checks", outcome.clone())) 70 | .unwrap_or_else(|err| ("error", test::fail(format!("{err:?}")))) 71 | } 72 | -------------------------------------------------------------------------------- /src/device/ecc.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | anyhow, 3 | device::{ 4 | test::{self, TestResult}, 5 | DeviceArgs, 6 | }, 7 | Result, 8 | }; 9 | use bytes::Bytes; 10 | use helium_crypto::{ 11 | ecc608::{self, key_config::KeyConfigType, with_ecc, Ecc, EccConfig}, 12 | KeyTag, KeyType, Keypair, Network, Sign, Verify, 13 | }; 14 | use http::Uri; 15 | use serde::{Serialize, Serializer}; 16 | use std::{ 17 | fmt, fs, 18 | path::{Path, PathBuf}, 19 | }; 20 | 21 | pub use ecc608::EccConfig as FileConfig; 22 | 23 | #[derive(Debug, Clone)] 24 | pub struct Device { 25 | /// The i2c/swi device path 26 | pub path: PathBuf, 27 | /// The bus address 28 | pub address: u16, 29 | /// The ecc slot to use 30 | pub slot: u8, 31 | /// The config parameters 32 | pub config: Option, 33 | } 34 | 35 | impl Device { 36 | /// Parses an ecc device url of the form `ecc:[:address][?slot=]`, 37 | /// where is the device file name (usually begins with i2c or tty), 38 | ///
is the bus address (default 96, ignored for swi), and 39 | /// is the slot to use for key lookup/manipulation (default: 0) 40 | pub fn from_url(url: &Uri) -> Result { 41 | let args = DeviceArgs::from_uri(url)?; 42 | let address = url.port_u16().unwrap_or(96); 43 | let slot = args.get("slot", 0)?; 44 | let path = url 45 | .host() 46 | .map(|dev| Path::new("/dev").join(dev)) 47 | .ok_or_else(|| anyhow!("missing ecc device path"))?; 48 | 49 | let config = if let Some(config_file) = args.get_string("config") { 50 | let contents = fs::read_to_string(config_file)?; 51 | let config: EccConfig = toml::from_str(&contents)?; 52 | Some(config) 53 | } else { 54 | None 55 | }; 56 | 57 | Ok(Self { 58 | path, 59 | address, 60 | slot, 61 | config, 62 | }) 63 | } 64 | 65 | pub fn init(&self) -> Result { 66 | // Initialize the global instance if not already initialized 67 | Ok(ecc608::init( 68 | &self.path.to_string_lossy(), 69 | self.address, 70 | self.config, 71 | )?) 72 | } 73 | 74 | pub fn get_info(&self) -> Result { 75 | let info = with_ecc(|ecc: &mut Ecc| { 76 | ecc.get_info() 77 | .and_then(|info| ecc.get_serial().map(|serial| Info { info, serial })) 78 | })?; 79 | Ok(info) 80 | } 81 | 82 | pub fn get_keypair(&self, create: bool) -> Result { 83 | let keypair: Keypair = with_ecc(|ecc| { 84 | if create { 85 | generate_compact_key_in_slot(ecc, self.slot) 86 | } else { 87 | compact_key_in_slot(ecc, self.slot) 88 | } 89 | })?; 90 | Ok(keypair) 91 | } 92 | 93 | pub fn provision(&self) -> Result { 94 | let slot_config = ecc608::SlotConfig::default(); 95 | let key_config = ecc608::KeyConfig::default(); 96 | for slot in 0..=ecc608::MAX_SLOT { 97 | with_ecc(|ecc| ecc.set_slot_config(slot, &slot_config))?; 98 | with_ecc(|ecc| ecc.set_key_config(slot, &key_config))?; 99 | } 100 | with_ecc(|ecc| ecc.set_locked(ecc608::Zone::Config))?; 101 | with_ecc(|ecc| ecc.set_locked(ecc608::Zone::Data))?; 102 | 103 | self.get_keypair(true) 104 | } 105 | 106 | pub fn get_config(&self) -> Result { 107 | let slot_config = with_ecc(|ecc| ecc.get_slot_config(self.slot))?; 108 | let key_config = with_ecc(|ecc| ecc.get_key_config(self.slot))?; 109 | let zones = [ecc608::Zone::Config, ecc608::Zone::Data] 110 | .into_iter() 111 | .map(get_zone_config) 112 | .collect::>>()?; 113 | Ok(Config { 114 | slot_config, 115 | key_config, 116 | zones, 117 | }) 118 | } 119 | 120 | pub fn generate_config(&self) -> Result { 121 | let config = ecc608::EccConfig::from_path(&self.path.to_string_lossy())?; 122 | Ok(config) 123 | } 124 | 125 | pub fn get_tests(&self) -> Vec { 126 | vec![ 127 | Test::zone_locked(ecc608::Zone::Data), 128 | Test::zone_locked(ecc608::Zone::Config), 129 | Test::slot_config(self.slot, ecc608::SlotConfig::default()), 130 | Test::key_config(self.slot, ecc608::KeyConfig::default()), 131 | Test::MinerKey(self.slot), 132 | Test::Sign(self.slot), 133 | Test::Ecdh(self.slot), 134 | ] 135 | } 136 | } 137 | 138 | fn compact_key_in_slot(ecc: &mut Ecc, slot: u8) -> Result { 139 | let keypair = ecc608::Keypair::from_ecc_slot(ecc, Network::MainNet, slot)?; 140 | Ok(keypair.into()) 141 | } 142 | 143 | fn generate_compact_key_in_slot(ecc: &mut Ecc, slot: u8) -> Result { 144 | let mut try_count = 5; 145 | loop { 146 | ecc.genkey(ecc608::KeyType::Private, slot)?; 147 | 148 | match compact_key_in_slot(ecc, slot) { 149 | Ok(keypair) => return Ok(keypair), 150 | Err(err) if try_count == 0 => return Err(err), 151 | Err(_) => try_count -= 1, 152 | } 153 | } 154 | } 155 | 156 | fn get_zone_config(zone: ecc608::Zone) -> Result { 157 | let config = with_ecc(|ecc| ecc.get_locked(&zone)).map(|locked| ZoneConfig { zone, locked })?; 158 | Ok(config) 159 | } 160 | 161 | #[derive(Debug, Serialize)] 162 | pub struct Info { 163 | #[serde(serialize_with = "serialize_bytes")] 164 | info: Bytes, 165 | #[serde(serialize_with = "serialize_bytes")] 166 | serial: Bytes, 167 | } 168 | 169 | #[derive(Debug, Serialize)] 170 | pub struct Config { 171 | key_config: ecc608::KeyConfig, 172 | slot_config: ecc608::SlotConfig, 173 | zones: Vec, 174 | } 175 | 176 | #[derive(Debug, Serialize)] 177 | pub struct ZoneConfig { 178 | #[serde(serialize_with = "serialize_zone")] 179 | zone: ecc608::Zone, 180 | locked: bool, 181 | } 182 | 183 | pub fn serialize_bytes(bytes: &Bytes, s: S) -> std::result::Result 184 | where 185 | S: Serializer, 186 | { 187 | s.serialize_str(&format!("{bytes:#02x}")) 188 | } 189 | 190 | pub fn serialize_zone(zone: &ecc608::Zone, s: S) -> std::result::Result 191 | where 192 | S: Serializer, 193 | { 194 | s.serialize_str(&zone.to_string()) 195 | } 196 | 197 | #[derive(Debug)] 198 | pub enum Test { 199 | ZoneLocked(ecc608::Zone), 200 | SlotConfig { 201 | slot: u8, 202 | config: ecc608::SlotConfig, 203 | }, 204 | KeyConfig { 205 | slot: u8, 206 | config: ecc608::KeyConfig, 207 | }, 208 | MinerKey(u8), 209 | Sign(u8), 210 | Ecdh(u8), 211 | } 212 | 213 | impl fmt::Display for Test { 214 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 215 | match self { 216 | Self::ZoneLocked(zone) => { 217 | let zone_str = match zone { 218 | ecc608::Zone::Config => "config", 219 | ecc608::Zone::Data => "data", 220 | }; 221 | f.write_fmt(format_args!("zone_locked({zone_str})")) 222 | } 223 | Self::SlotConfig { slot, .. } => f.write_fmt(format_args!("slot_config({slot})")), 224 | Self::KeyConfig { slot, .. } => f.write_fmt(format_args!("key_config({slot})")), 225 | Self::MinerKey(slot) => f.write_fmt(format_args!("miner_key({slot})")), 226 | Self::Sign(slot) => f.write_fmt(format_args!("sign({slot})")), 227 | Self::Ecdh(slot) => f.write_fmt(format_args!("ecdh({slot})")), 228 | } 229 | } 230 | } 231 | 232 | impl Test { 233 | pub fn zone_locked(zone: ecc608::Zone) -> Self { 234 | Self::ZoneLocked(zone) 235 | } 236 | 237 | pub fn slot_config(slot: u8, config: ecc608::SlotConfig) -> Self { 238 | Self::SlotConfig { slot, config } 239 | } 240 | 241 | pub fn key_config(slot: u8, config: ecc608::KeyConfig) -> Self { 242 | Self::KeyConfig { slot, config } 243 | } 244 | 245 | pub fn run(&self) -> TestResult { 246 | match self { 247 | Self::ZoneLocked(zone) => check_zone_locked(zone), 248 | Self::SlotConfig { slot, .. } => check_slot_config(*slot), 249 | Self::KeyConfig { slot, .. } => check_key_config(*slot), 250 | Self::MinerKey(slot) => check_miner_key(*slot), 251 | Self::Sign(slot) => check_sign(*slot), 252 | Self::Ecdh(slot) => check_ecdh(*slot), 253 | } 254 | } 255 | } 256 | 257 | fn check_zone_locked(zone: &ecc608::Zone) -> TestResult { 258 | match with_ecc(|ecc| ecc.get_locked(zone))? { 259 | true => test::pass("ok").into(), 260 | _ => test::expected("locked", "unlocked").into(), 261 | } 262 | } 263 | 264 | fn check(name: &'static str, found: T, expected: T) -> (&'static str, test::TestOutcome) 265 | where 266 | T: fmt::Display + PartialEq, 267 | { 268 | let outcome = if found == expected { 269 | test::pass(expected) 270 | } else { 271 | test::expected(expected, found) 272 | }; 273 | (name, outcome) 274 | } 275 | 276 | fn check_any(name: &'static str, found: T) -> (&'static str, test::TestOutcome) 277 | where 278 | T: fmt::Display + PartialEq, 279 | { 280 | (name, test::pass(found)) 281 | } 282 | 283 | fn check_slot_config(slot: u8) -> TestResult { 284 | let config = with_ecc(|ecc| ecc.get_slot_config(slot))?; 285 | let outcomes = [ 286 | check("secret", config.secret(), true), 287 | check("encrypt_read", config.encrypt_read(), false), 288 | check("limited_use", config.limited_use(), false), 289 | check( 290 | "external_signatures", 291 | config.read_key().external_signatures(), 292 | true, 293 | ), 294 | check_any( 295 | "internal_signatures", 296 | config.read_key().internal_signatures(), 297 | ), 298 | check("ecdh_operation", config.read_key().ecdh_operation(), true), 299 | ] 300 | .into_iter() 301 | .collect::>(); 302 | test::checks(outcomes).into() 303 | } 304 | 305 | fn check_key_config_type(key_type: KeyConfigType) -> (&'static str, test::TestOutcome) { 306 | let outcome = if key_type == KeyConfigType::Ecc { 307 | test::pass("ecc") 308 | } else { 309 | test::expected("ecc", "not_ecc") 310 | }; 311 | ("key_type", outcome) 312 | } 313 | 314 | fn check_key_config(slot: u8) -> TestResult { 315 | let config = with_ecc(|ecc| ecc.get_key_config(slot))?; 316 | let outcomes = [ 317 | check("auth_key", config.auth_key(), 0), 318 | check("intrusion_disable", config.intrusion_disable(), false), 319 | check("x509_index", config.x509_index(), 0), 320 | check("private", config.private(), true), 321 | check("pub_info", config.pub_info(), true), 322 | check_any("req_random", config.req_random()), 323 | check("req_auth", config.req_auth(), false), 324 | check("lockable", config.lockable(), true), 325 | check_key_config_type(config.key_type()), 326 | ] 327 | .into_iter() 328 | .collect::>(); 329 | test::checks(outcomes).into() 330 | } 331 | 332 | fn check_miner_key(slot: u8) -> TestResult { 333 | let keypair = with_ecc(|ecc| compact_key_in_slot(ecc, slot))?; 334 | test::pass(keypair.public_key()).into() 335 | } 336 | 337 | fn check_sign(slot: u8) -> TestResult { 338 | const DATA: &[u8] = b"hello world"; 339 | let keypair = with_ecc(|ecc| compact_key_in_slot(ecc, slot))?; 340 | let signature = keypair.sign(DATA)?; 341 | keypair.public_key().verify(DATA, &signature)?; 342 | test::pass("ok").into() 343 | } 344 | 345 | fn check_ecdh(slot: u8) -> TestResult { 346 | use rand::rngs::OsRng; 347 | let keypair = with_ecc(|ecc| compact_key_in_slot(ecc, slot))?; 348 | let other_keypair = Keypair::generate( 349 | KeyTag { 350 | network: Network::MainNet, 351 | key_type: KeyType::EccCompact, 352 | }, 353 | &mut OsRng, 354 | ); 355 | let ecc_shared_secret = keypair.ecdh(other_keypair.public_key())?; 356 | let other_shared_secret = other_keypair.ecdh(keypair.public_key())?; 357 | 358 | if ecc_shared_secret.as_bytes() != other_shared_secret.as_bytes() { 359 | return test::expected( 360 | format!("{:#02x}", ecc_shared_secret.as_bytes()), 361 | format!("{:#02x}", other_shared_secret.as_bytes()), 362 | ) 363 | .into(); 364 | } 365 | test::pass("ok").into() 366 | } 367 | -------------------------------------------------------------------------------- /src/device/file.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | device::test::{self, TestResult}, 3 | Result, 4 | }; 5 | use helium_crypto::{KeyTag, KeyType, Keypair, Sign, Verify}; 6 | use http::Uri; 7 | use rand::rngs::OsRng; 8 | use serde::Serialize; 9 | use std::{ 10 | fmt, fs, 11 | path::{Path, PathBuf}, 12 | }; 13 | 14 | #[derive(Debug, Clone)] 15 | pub struct Device { 16 | /// The file device path 17 | pub path: PathBuf, 18 | } 19 | 20 | impl Device { 21 | /// Parses an ecc device url of the form `ecc:[:address][?slot=]`, 22 | /// where is the device file name (usually begins with i2c or tty), 23 | ///
is the bus address (default 96, ignored for swi), and 24 | /// is the slot to use for key lookup/manipulation (default: 0) 25 | pub fn from_url(url: &Uri) -> Result { 26 | Ok(Self { 27 | path: url.path().into(), 28 | }) 29 | } 30 | 31 | pub fn get_info(&self) -> Result { 32 | let keypair = self.get_keypair(false)?; 33 | let key_type = keypair.key_tag().key_type.to_string(); 34 | let info = Info { 35 | r#type: key_type, 36 | path: self.path.clone(), 37 | }; 38 | Ok(info) 39 | } 40 | 41 | pub fn get_keypair(&self, create: bool) -> Result { 42 | if !self.path.exists() || create { 43 | let keypair = Keypair::generate(KeyTag::default(), &mut OsRng); 44 | fs::write(&self.path, keypair.to_vec())?; 45 | } 46 | load_keypair(&self.path) 47 | } 48 | 49 | pub fn provision(&self) -> Result { 50 | self.get_keypair(true) 51 | } 52 | 53 | pub fn get_config(&self) -> Result { 54 | Ok(Config { 55 | path: self.path.clone(), 56 | }) 57 | } 58 | 59 | pub fn get_tests(&self) -> Vec { 60 | vec![ 61 | Test::MinerKey(self.path.clone()), 62 | Test::Sign(self.path.clone()), 63 | Test::Ecdh(self.path.clone()), 64 | ] 65 | } 66 | } 67 | 68 | fn load_keypair>(path: &P) -> Result { 69 | let data = fs::read(path)?; 70 | let keypair = Keypair::try_from(&data[..])?; 71 | Ok(keypair) 72 | } 73 | 74 | #[derive(Debug, Serialize)] 75 | pub struct Info { 76 | r#type: String, 77 | path: PathBuf, 78 | } 79 | 80 | #[derive(Debug, Serialize)] 81 | pub struct Config { 82 | path: PathBuf, 83 | } 84 | 85 | #[derive(Debug)] 86 | pub enum Test { 87 | MinerKey(PathBuf), 88 | Sign(PathBuf), 89 | Ecdh(PathBuf), 90 | } 91 | 92 | impl fmt::Display for Test { 93 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 94 | match self { 95 | Self::MinerKey(path) => { 96 | f.write_fmt(format_args!("miner_key({}", path.to_string_lossy())) 97 | } 98 | Self::Sign(path) => f.write_fmt(format_args!("sign({})", path.to_string_lossy())), 99 | Self::Ecdh(path) => f.write_fmt(format_args!("ecdh({})", path.to_string_lossy())), 100 | } 101 | } 102 | } 103 | 104 | impl Test { 105 | pub fn run(&self) -> TestResult { 106 | match self { 107 | Self::MinerKey(path) => check_miner_key(path), 108 | Self::Sign(path) => check_sign(path), 109 | Self::Ecdh(path) => check_ecdh(path), 110 | } 111 | } 112 | } 113 | 114 | fn check_miner_key(path: &PathBuf) -> TestResult { 115 | let keypair = load_keypair(path)?; 116 | test::pass(keypair.public_key()).into() 117 | } 118 | 119 | fn check_sign(path: &PathBuf) -> TestResult { 120 | const DATA: &[u8] = b"hello world"; 121 | let keypair = load_keypair(path)?; 122 | let signature = keypair.sign(DATA)?; 123 | keypair.public_key().verify(DATA, &signature)?; 124 | test::pass("ok").into() 125 | } 126 | 127 | fn check_ecdh(path: &PathBuf) -> TestResult { 128 | let keypair = load_keypair(path)?; 129 | let other_keypair = Keypair::generate( 130 | KeyTag { 131 | network: keypair.key_tag().network, 132 | key_type: KeyType::EccCompact, 133 | }, 134 | &mut OsRng, 135 | ); 136 | let ecc_shared_secret = keypair.ecdh(other_keypair.public_key())?; 137 | let other_shared_secret = other_keypair.ecdh(keypair.public_key())?; 138 | 139 | if ecc_shared_secret.as_bytes() != other_shared_secret.as_bytes() { 140 | return test::expected( 141 | format!("{:#02x}", ecc_shared_secret.as_bytes()), 142 | format!("{:#02x}", other_shared_secret.as_bytes()), 143 | ) 144 | .into(); 145 | } 146 | test::pass("ok").into() 147 | } 148 | -------------------------------------------------------------------------------- /src/device/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::{anyhow, Result}; 2 | use helium_crypto::Keypair; 3 | use http::Uri; 4 | use serde::Serialize; 5 | use std::{collections::HashMap, str::FromStr}; 6 | 7 | #[cfg(feature = "ecc608")] 8 | mod ecc; 9 | mod file; 10 | #[cfg(feature = "nova-tz")] 11 | mod nova_tz; 12 | #[cfg(feature = "tpm")] 13 | mod tpm; 14 | 15 | /// A security device to work with. Security devices come in all forms. This 16 | /// abstracts them into one with a well defined interface for doing what this 17 | /// tool needs to do with them. 18 | #[derive(Debug, Clone)] 19 | pub enum Device { 20 | #[cfg(feature = "ecc608")] 21 | Ecc(ecc::Device), 22 | #[cfg(feature = "tpm")] 23 | Tpm(tpm::Device), 24 | #[cfg(feature = "nova-tz")] 25 | TrustZone(nova_tz::Device), 26 | File(file::Device), 27 | } 28 | 29 | pub struct DeviceArgs(HashMap); 30 | 31 | /// Represents the configuration state for the given security device. This 32 | /// information should include enough detail to convey that the security device 33 | /// is "locked" so key material can be written to it. 34 | #[derive(Debug, Serialize)] 35 | #[serde(untagged)] 36 | pub enum Config { 37 | #[cfg(feature = "ecc608")] 38 | Ecc(ecc::Config), 39 | #[cfg(feature = "tpm")] 40 | Tpm(tpm::Config), 41 | #[cfg(feature = "nova-tz")] 42 | TrustZone(nova_tz::Config), 43 | File(file::Config), 44 | } 45 | 46 | #[derive(Debug, Serialize)] 47 | #[serde(untagged)] 48 | pub enum FileConfig { 49 | #[cfg(feature = "ecc608")] 50 | Ecc(ecc::FileConfig), 51 | } 52 | 53 | pub mod test { 54 | use crate::Result; 55 | 56 | #[cfg(feature = "ecc608")] 57 | use crate::device::ecc; 58 | use crate::device::file; 59 | #[cfg(feature = "nova-tz")] 60 | use crate::device::nova_tz; 61 | #[cfg(feature = "tpm")] 62 | use crate::device::tpm; 63 | 64 | use serde::Serialize; 65 | use std::{collections::HashMap, fmt}; 66 | 67 | /// Represents a single test for a given device 68 | pub enum Test { 69 | #[cfg(feature = "ecc608")] 70 | Ecc(ecc::Test), 71 | #[cfg(feature = "tpm")] 72 | Tpm(tpm::Test), 73 | #[cfg(feature = "nova-tz")] 74 | TrustZone(nova_tz::Test), 75 | File(file::Test), 76 | } 77 | 78 | #[derive(Debug, Serialize, Clone)] 79 | #[serde(untagged)] 80 | pub enum TestOutcome { 81 | Pass(String), 82 | Fail(String), 83 | Expect { found: String, expected: String }, 84 | Checks(HashMap<&'static str, TestOutcome>), 85 | } 86 | 87 | pub type TestResult = Result; 88 | 89 | impl From for TestResult { 90 | fn from(v: TestOutcome) -> Self { 91 | Ok(v) 92 | } 93 | } 94 | 95 | pub fn pass(msg: T) -> TestOutcome { 96 | TestOutcome::Pass(msg.to_string()) 97 | } 98 | 99 | pub fn fail(msg: T) -> TestOutcome { 100 | TestOutcome::Fail(msg.to_string()) 101 | } 102 | 103 | pub fn expected(expected: T, found: T) -> TestOutcome { 104 | TestOutcome::Expect { 105 | expected: expected.to_string(), 106 | found: found.to_string(), 107 | } 108 | } 109 | 110 | pub fn checks>(checks: T) -> TestOutcome { 111 | TestOutcome::Checks(HashMap::from_iter(checks)) 112 | } 113 | 114 | impl Test { 115 | pub fn run(&self) -> TestResult { 116 | match self { 117 | #[cfg(feature = "ecc608")] 118 | Self::Ecc(test) => test.run(), 119 | #[cfg(feature = "tpm")] 120 | Self::Tpm(test) => test.run(), 121 | #[cfg(feature = "nova-tz")] 122 | Self::TrustZone(test) => test.run(), 123 | Self::File(test) => test.run(), 124 | } 125 | } 126 | } 127 | 128 | impl fmt::Display for Test { 129 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 130 | match self { 131 | #[cfg(feature = "ecc608")] 132 | Self::Ecc(test) => test.fmt(f), 133 | #[cfg(feature = "tpm")] 134 | Self::Tpm(test) => test.fmt(f), 135 | #[cfg(feature = "nova-tz")] 136 | Self::TrustZone(test) => test.fmt(f), 137 | Self::File(test) => test.fmt(f), 138 | } 139 | } 140 | } 141 | 142 | impl TestOutcome { 143 | pub fn passed(&self) -> bool { 144 | match self { 145 | Self::Pass(_) => true, 146 | Self::Expect { .. } => false, 147 | Self::Fail(_) => false, 148 | Self::Checks(tests) => tests.iter().all(|(_, outcome)| outcome.passed()), 149 | } 150 | } 151 | } 152 | 153 | impl fmt::Display for TestOutcome { 154 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 155 | if self.passed() { 156 | f.write_str("pass") 157 | } else { 158 | f.write_str("fail") 159 | } 160 | } 161 | } 162 | } 163 | 164 | impl FromStr for Device { 165 | type Err = crate::Error; 166 | 167 | fn from_str(s: &str) -> Result { 168 | let url: Uri = s 169 | .parse() 170 | .map_err(|err| anyhow!("invalid device url \"{s}\": {err:?}"))?; 171 | match url.scheme_str() { 172 | #[cfg(feature = "ecc608")] 173 | Some("ecc") => Ok(Self::Ecc(ecc::Device::from_url(&url)?)), 174 | #[cfg(feature = "tpm")] 175 | Some("tpm") => Ok(Self::Tpm(tpm::Device::from_url(&url)?)), 176 | #[cfg(feature = "nova-tz")] 177 | Some("nova-tz") => Ok(Self::TrustZone(nova_tz::Device::from_url(&url)?)), 178 | Some("file") | None => Ok(Self::File(file::Device::from_url(&url)?)), 179 | _ => Err(anyhow!("invalid device url \"{s}\"")), 180 | } 181 | } 182 | } 183 | 184 | impl DeviceArgs { 185 | #[cfg(feature = "ecc608")] 186 | pub(crate) fn from_uri(url: &Uri) -> Result { 187 | let args = url 188 | .query() 189 | .map_or_else( 190 | || Ok(HashMap::new()), 191 | serde_urlencoded::from_str::>, 192 | ) 193 | .map_err(|err| anyhow!("invalid device url \"{url}\": {err:?}"))?; 194 | Ok(Self(args)) 195 | } 196 | 197 | pub fn get_string(&self, name: &str) -> Option { 198 | self.0.get(name).cloned() 199 | } 200 | 201 | pub fn get(&self, name: &str, default: T) -> Result 202 | where 203 | T: std::str::FromStr, 204 | ::Err: std::fmt::Debug, 205 | { 206 | self.0 207 | .get(name) 208 | .map(|s| s.parse::()) 209 | .unwrap_or(Ok(default)) 210 | .map_err(|err| anyhow!("invalid uri argument for {name}: {err:?}")) 211 | } 212 | } 213 | 214 | impl Device { 215 | pub fn init(&self) -> Result { 216 | match self { 217 | #[cfg(feature = "ecc608")] 218 | Self::Ecc(device) => device.init(), 219 | _ => Ok(()), 220 | } 221 | } 222 | 223 | pub fn get_info(&self) -> Result { 224 | let info = match self { 225 | #[cfg(feature = "ecc608")] 226 | Self::Ecc(device) => Info::Ecc(device.get_info()?), 227 | #[cfg(feature = "tpm")] 228 | Self::Tpm(device) => Info::Tpm(device.get_info()?), 229 | #[cfg(feature = "nova-tz")] 230 | Self::TrustZone(device) => Info::TrustZone(device.get_info()?), 231 | Self::File(device) => Info::File(device.get_info()?), 232 | }; 233 | Ok(info) 234 | } 235 | 236 | pub fn get_config(&self) -> Result { 237 | let config = match self { 238 | #[cfg(feature = "ecc608")] 239 | Self::Ecc(device) => Config::Ecc(device.get_config()?), 240 | #[cfg(feature = "tpm")] 241 | Self::Tpm(device) => Config::Tpm(device.get_config()?), 242 | #[cfg(feature = "nova-tz")] 243 | Self::TrustZone(device) => Config::TrustZone(device.get_config()?), 244 | Self::File(device) => Config::File(device.get_config()?), 245 | }; 246 | Ok(config) 247 | } 248 | 249 | pub fn get_keypair(&self, create: bool) -> Result { 250 | let keypair = match self { 251 | #[cfg(feature = "ecc608")] 252 | Self::Ecc(device) => device.get_keypair(create)?, 253 | #[cfg(feature = "tpm")] 254 | Self::Tpm(device) => device.get_keypair(create)?, 255 | #[cfg(feature = "nova-tz")] 256 | Self::TrustZone(device) => device.get_keypair(create)?, 257 | Self::File(device) => device.get_keypair(create)?, 258 | }; 259 | Ok(keypair) 260 | } 261 | 262 | pub fn provision(&self) -> Result { 263 | let keypair = match self { 264 | #[cfg(feature = "ecc608")] 265 | Self::Ecc(device) => device.provision()?, 266 | #[cfg(feature = "tpm")] 267 | Self::Tpm(device) => device.provision()?, 268 | #[cfg(feature = "nova-tz")] 269 | Self::TrustZone(device) => device.provision()?, 270 | Self::File(device) => device.provision()?, 271 | }; 272 | Ok(keypair) 273 | } 274 | 275 | pub fn get_tests(&self) -> Vec { 276 | match self { 277 | #[cfg(feature = "ecc608")] 278 | Self::Ecc(device) => device 279 | .get_tests() 280 | .into_iter() 281 | .map(test::Test::Ecc) 282 | .collect(), 283 | #[cfg(feature = "tpm")] 284 | Self::Tpm(device) => device 285 | .get_tests() 286 | .into_iter() 287 | .map(test::Test::Tpm) 288 | .collect(), 289 | #[cfg(feature = "nova-tz")] 290 | Self::TrustZone(device) => device 291 | .get_tests() 292 | .into_iter() 293 | .map(test::Test::TrustZone) 294 | .collect(), 295 | Self::File(device) => device 296 | .get_tests() 297 | .into_iter() 298 | .map(test::Test::File) 299 | .collect(), 300 | } 301 | } 302 | 303 | pub fn generate_config(&self) -> Result { 304 | let config = match self { 305 | #[cfg(feature = "ecc608")] 306 | Self::Ecc(device) => FileConfig::Ecc(device.generate_config()?), 307 | _ => return Err(anyhow!("device does not support config generation")), 308 | }; 309 | Ok(config) 310 | } 311 | } 312 | 313 | /// Represents useful device information like model and serial number. 314 | #[derive(Debug, Serialize)] 315 | #[serde(untagged)] 316 | pub enum Info { 317 | #[cfg(feature = "ecc608")] 318 | Ecc(ecc::Info), 319 | #[cfg(feature = "tpm")] 320 | Tpm(tpm::Info), 321 | #[cfg(feature = "nova-tz")] 322 | TrustZone(nova_tz::Info), 323 | File(file::Info), 324 | } 325 | -------------------------------------------------------------------------------- /src/device/nova_tz.rs: -------------------------------------------------------------------------------- 1 | use http::Uri; 2 | use std::fmt; 3 | use std::path::{Path, PathBuf}; 4 | 5 | use serde::Serialize; 6 | 7 | use helium_crypto::{nova_tz, Keypair, Network, Sign, Verify}; 8 | 9 | use crate::{ 10 | device::test::{self, TestResult}, 11 | Result, 12 | }; 13 | 14 | #[derive(Debug, Clone)] 15 | pub struct Device { 16 | /// TrustZone keyblob path 17 | pub path: PathBuf, 18 | } 19 | 20 | impl Device { 21 | /// Parses a trustzone device url of the form `nova-tz://rsa/`, 22 | /// where is the path to TrustZone keyblob 23 | pub fn from_url(url: &Uri) -> Result { 24 | let path = url.path(); 25 | 26 | Ok(Self { path: path.into() }) 27 | } 28 | 29 | pub fn get_info(&self) -> Result { 30 | Ok(Info { 31 | path: self.path.clone(), 32 | }) 33 | } 34 | 35 | pub fn get_keypair(&self, create: bool) -> Result { 36 | if create { 37 | panic!("not supported") 38 | } 39 | 40 | let keypair = nova_tz::Keypair::from_key_path(Network::MainNet, &self.path) 41 | .map(helium_crypto::Keypair::from)?; 42 | Ok(keypair) 43 | } 44 | 45 | pub fn provision(&self) -> Result { 46 | panic!("not supported") 47 | } 48 | 49 | pub fn get_config(&self) -> Result { 50 | Ok(Config { 51 | path: self.path.clone(), 52 | }) 53 | } 54 | 55 | pub fn get_tests(&self) -> Vec { 56 | vec![ 57 | Test::MinerKey(self.path.clone()), 58 | Test::Sign(self.path.clone()), 59 | ] 60 | } 61 | } 62 | 63 | #[derive(Debug, Serialize)] 64 | pub struct Info { 65 | path: PathBuf, 66 | } 67 | 68 | #[derive(Debug, Serialize)] 69 | pub struct Config { 70 | path: PathBuf, 71 | } 72 | 73 | #[derive(Debug)] 74 | pub enum Test { 75 | MinerKey(PathBuf), 76 | Sign(PathBuf), 77 | } 78 | 79 | impl fmt::Display for Test { 80 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 81 | match self { 82 | Self::MinerKey(key_path) => { 83 | f.write_fmt(format_args!("miner_key({})", key_path.to_string_lossy())) 84 | } 85 | Self::Sign(key_path) => { 86 | f.write_fmt(format_args!("sign({})", key_path.to_string_lossy())) 87 | } 88 | } 89 | } 90 | } 91 | 92 | impl Test { 93 | pub fn run(&self) -> TestResult { 94 | match self { 95 | Self::MinerKey(key_path) => check_miner_key(key_path), 96 | Self::Sign(key_path) => check_sign(key_path), 97 | } 98 | } 99 | } 100 | 101 | fn check_miner_key(key_path: &Path) -> TestResult { 102 | let keypair = nova_tz::Keypair::from_key_path(Network::MainNet, key_path) 103 | .map(helium_crypto::Keypair::from)?; 104 | test::pass(keypair.public_key()).into() 105 | } 106 | 107 | fn check_sign(key_path: &Path) -> TestResult { 108 | const DATA: &[u8] = b"hello world"; 109 | let keypair = nova_tz::Keypair::from_key_path(Network::MainNet, key_path) 110 | .map(helium_crypto::Keypair::from)?; 111 | let signature = keypair.sign(DATA)?; 112 | keypair.public_key().verify(DATA, &signature)?; 113 | test::pass("ok").into() 114 | } 115 | -------------------------------------------------------------------------------- /src/device/tpm.rs: -------------------------------------------------------------------------------- 1 | use http::Uri; 2 | use std::fmt; 3 | 4 | use serde::Serialize; 5 | 6 | use helium_crypto::{tpm, KeyTag, KeyType, Keypair, Network, Sign, Verify}; 7 | 8 | use crate::{ 9 | device::test::{self, TestResult}, 10 | Result, 11 | }; 12 | 13 | #[derive(Debug, Clone)] 14 | pub struct Device { 15 | /// TPM key path 16 | pub path: String, 17 | } 18 | 19 | impl Device { 20 | /// Parses a tpm device url of the form `tpm://tpm/`, 21 | /// where is the path to TPM KEY 22 | pub fn from_url(url: &Uri) -> Result { 23 | let path = url.path(); 24 | 25 | Ok(Self { 26 | path: path.to_string(), 27 | }) 28 | } 29 | 30 | pub fn get_info(&self) -> Result { 31 | Ok(Info { 32 | path: self.path.clone(), 33 | }) 34 | } 35 | 36 | pub fn get_keypair(&self, create: bool) -> Result { 37 | if create { 38 | panic!("not supported") 39 | } 40 | 41 | let keypair = tpm::Keypair::from_key_path(Network::MainNet, self.path.as_str()) 42 | .map(helium_crypto::Keypair::from)?; 43 | Ok(keypair) 44 | } 45 | 46 | pub fn provision(&self) -> Result { 47 | panic!("not supported") 48 | } 49 | 50 | pub fn get_config(&self) -> Result { 51 | Ok(Config { 52 | path: self.path.clone(), 53 | }) 54 | } 55 | 56 | pub fn get_tests(&self) -> Vec { 57 | vec![ 58 | Test::MinerKey(self.path.clone()), 59 | Test::Sign(self.path.clone()), 60 | Test::Ecdh(self.path.clone()), 61 | ] 62 | } 63 | } 64 | 65 | #[derive(Debug, Serialize)] 66 | pub struct Info { 67 | path: String, 68 | } 69 | 70 | #[derive(Debug, Serialize)] 71 | pub struct Config { 72 | path: String, 73 | } 74 | 75 | #[derive(Debug)] 76 | pub enum Test { 77 | MinerKey(String), 78 | Sign(String), 79 | Ecdh(String), 80 | } 81 | 82 | impl fmt::Display for Test { 83 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 84 | match self { 85 | Self::MinerKey(key_path) => f.write_fmt(format_args!("miner_key({key_path})")), 86 | Self::Sign(key_path) => f.write_fmt(format_args!("sign({key_path})")), 87 | Self::Ecdh(key_path) => f.write_fmt(format_args!("ecdh({key_path})")), 88 | } 89 | } 90 | } 91 | 92 | impl Test { 93 | pub fn run(&self) -> TestResult { 94 | match self { 95 | Self::MinerKey(key_path) => check_miner_key(key_path), 96 | Self::Sign(key_path) => check_sign(key_path), 97 | Self::Ecdh(key_path) => check_ecdh(key_path), 98 | } 99 | } 100 | } 101 | 102 | fn check_miner_key(key_path: &str) -> TestResult { 103 | let keypair = tpm::Keypair::from_key_path(Network::MainNet, key_path) 104 | .map(helium_crypto::Keypair::from)?; 105 | test::pass(keypair.public_key()).into() 106 | } 107 | 108 | fn check_sign(key_path: &str) -> TestResult { 109 | const DATA: &[u8] = b"hello world"; 110 | let keypair = tpm::Keypair::from_key_path(Network::MainNet, key_path) 111 | .map(helium_crypto::Keypair::from)?; 112 | let signature = keypair.sign(DATA)?; 113 | keypair.public_key().verify(DATA, &signature)?; 114 | test::pass("ok").into() 115 | } 116 | 117 | fn check_ecdh(key_path: &str) -> TestResult { 118 | use rand::rngs::OsRng; 119 | let keypair = tpm::Keypair::from_key_path(Network::MainNet, key_path) 120 | .map(helium_crypto::Keypair::from)?; 121 | let other_keypair = Keypair::generate( 122 | KeyTag { 123 | network: Network::MainNet, 124 | key_type: KeyType::EccCompact, 125 | }, 126 | &mut OsRng, 127 | ); 128 | let ecc_shared_secret = keypair.ecdh(other_keypair.public_key())?; 129 | let other_shared_secret = other_keypair.ecdh(keypair.public_key())?; 130 | 131 | if ecc_shared_secret.as_bytes() != other_shared_secret.as_bytes() { 132 | return test::expected( 133 | format!("{:#02x}", ecc_shared_secret.as_bytes()), 134 | format!("{:#02x}", other_shared_secret.as_bytes()), 135 | ) 136 | .into(); 137 | } 138 | test::pass("ok").into() 139 | } 140 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod cmd; 2 | pub mod device; 3 | pub mod result; 4 | 5 | pub use device::Device; 6 | pub use result::{anyhow, bail, Error, Result}; 7 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use clap::Parser; 2 | use gateway_mfr::{cmd, Device, Result}; 3 | 4 | #[derive(Debug, Parser)] 5 | #[command(version = env!("CARGO_PKG_VERSION"))] 6 | #[command(name = env!("CARGO_BIN_NAME"))] 7 | pub struct Cli { 8 | /// The security device to use. 9 | /// 10 | /// The URL for the security device is dependent on the device type being 11 | /// used. 12 | /// 13 | /// Examples: 14 | /// 15 | /// ecc608 - "ecc://i2c-1", "ecc://i2c-1:96?slot=0" 16 | /// file - "file:///etc/keypair.bin"\n 17 | /// tpm - "tpm://tpm/" 18 | #[arg(long, verbatim_doc_comment)] 19 | device: Device, 20 | 21 | #[command(subcommand)] 22 | cmd: Cmd, 23 | } 24 | 25 | #[derive(Debug, clap::Subcommand)] 26 | pub enum Cmd { 27 | Info(cmd::info::Cmd), 28 | Key(cmd::key::Cmd), 29 | Provision(cmd::provision::Cmd), 30 | Config(cmd::config::Cmd), 31 | Test(cmd::test::Cmd), 32 | Bench(cmd::bench::Cmd), 33 | Generate(cmd::generate::Cmd), 34 | } 35 | 36 | pub fn main() -> Result { 37 | let cli = Cli::parse(); 38 | cli.cmd.run(&cli.device) 39 | } 40 | 41 | impl Cmd { 42 | fn run(&self, device: &Device) -> Result { 43 | match self { 44 | Self::Info(cmd) => cmd.run(device), 45 | Self::Key(cmd) => cmd.run(device), 46 | Self::Provision(cmd) => cmd.run(device), 47 | Self::Config(cmd) => cmd.run(device), 48 | Self::Test(cmd) => cmd.run(device), 49 | Self::Bench(cmd) => cmd.run(device), 50 | Self::Generate(cmd) => cmd.run(device), 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/result.rs: -------------------------------------------------------------------------------- 1 | pub type Result = anyhow::Result; 2 | pub type Error = anyhow::Error; 3 | pub use anyhow::{anyhow, bail}; 4 | --------------------------------------------------------------------------------