From 21141b2eb4b950aca743431fc70b896067d95254 Mon Sep 17 00:00:00 2001 From: Colin Murphy Date: Thu, 23 Jan 2025 10:23:12 -0500 Subject: [PATCH] feat: Rebase on 0.41.0 Tests passing with WASI. CARGO_TARGET_WASM32_WASIP2_RUNNER="wasmtime -S common --dir ." --- .github/workflows/ci.yml | 53 ++ .gitignore | 1 + Cargo.lock | 183 +++---- internal/crypto/Cargo.toml | 19 +- sdk/src/asset_handlers/bmff_io.rs | 32 +- sdk/src/asset_handlers/jpeg_io.rs | 8 +- sdk/src/asset_handlers/mp3_io.rs | 16 +- sdk/src/asset_handlers/png_io.rs | 19 +- sdk/src/asset_handlers/riff_io.rs | 25 +- sdk/src/asset_handlers/svg_io.rs | 27 +- sdk/src/asset_handlers/tiff_io.rs | 28 +- sdk/src/builder.rs | 24 +- sdk/src/cose_sign.rs | 2 +- sdk/src/ingredient.rs | 7 +- sdk/src/manifest.rs | 38 +- sdk/src/manifest_store.rs | 22 +- sdk/src/utils/io_utils.rs | 33 +- sdk/src/utils/test.rs | 9 +- sdk/src/wasm/wasicrypto_validator.rs | 439 ----------------- sdk/src/wasm/wasipki_trust_handler.rs | 672 -------------------------- sdk/tests/test_builder.rs | 2 +- 21 files changed, 287 insertions(+), 1372 deletions(-) delete mode 100644 sdk/src/wasm/wasicrypto_validator.rs delete mode 100644 sdk/src/wasm/wasipki_trust_handler.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b993c518f..0185e5d49 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -287,6 +287,59 @@ jobs: run: wasm-pack test --chrome --headless working-directory: ./cawg_identity + tests-wasi: + name: Unit tests (WASI) + if: | + github.event_name != 'pull_request' || + github.event.pull_request.author_association == 'COLLABORATOR' || + github.event.pull_request.author_association == 'MEMBER' || + github.event.pull_request.user.login == 'dependabot[bot]' || + contains(github.event.pull_request.labels.*.name, 'safe to test') + + runs-on: ubuntu-latest +# container: +# image: ghcr.io/webassembly/wasi-sdk + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + # nightly required for testing until this issue is resolved: + # wasip2 target should not conditionally feature gate stdlib APIs rust-lang/rust#130323 https://github.com/rust-lang/rust/issues/130323 + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@nightly + + - name: Install wasmtime + run: | + curl https://wasmtime.dev/install.sh -sSf | bash + echo "$HOME/.wasmtime/bin" >> $GITHUB_PATH + + - name: Install WASI SDK + run: | + if [ "${RUNNER_ARCH}" = "X64" ]; then + ARCH="x86_64"; + else + ARCH="${RUNNER_ARCH}"; + fi + wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-25/wasi-sdk-25.0-${ARCH}-${RUNNER_OS}.tar.gz + tar xvf wasi-sdk-25.0-${ARCH}-${RUNNER_OS}.tar.gz + ls wasi* + mv $(echo wasi-sdk-25.0-${ARCH}-${RUNNER_OS} | tr '[:upper:]' '[:lower:]') /opt/wasi-sdk + + - name: Add wasm32-wasip2 target + run: rustup target add --toolchain nightly wasm32-wasip2 + + - name: Cache Rust dependencies + uses: Swatinem/rust-cache@v2 + + - name: Run WASI tests (c2pa-rs) + env: + CARGO_TARGET_WASM32_WASIP2_RUNNER: "wasmtime -S common --dir ." + CC: /opt/wasi-sdk/bin/clang + WASI_SDK_PATH: /opt/wasi-sdk + RUST_MIN_STACK: 16777216 + run: cargo +nightly test --target wasm32-wasip2 -p c2pa + test-direct-minimal-versions: name: Unit tests with minimum versions of direct dependencies if: | diff --git a/.gitignore b/.gitignore index a43edfdfa..035358b14 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ /target/ **/*.rs.bk +**/*.tmp* .DS_Store .idea diff --git a/Cargo.lock b/Cargo.lock index f8fcd7b73..8c567d2c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -672,9 +672,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.17.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytemuck" @@ -734,7 +734,7 @@ dependencies = [ "coset", "ed25519-dalek", "extfmt", - "getrandom 0.2.15", + "getrandom", "glob", "hex", "hex-literal", @@ -750,7 +750,7 @@ dependencies = [ "memchr", "mockall", "mp4", - "pem 3.0.4", + "pem", "png_pong", "quick-xml", "rand", @@ -810,7 +810,7 @@ dependencies = [ "der", "ecdsa", "ed25519-dalek", - "getrandom 0.2.15", + "getrandom", "hex", "js-sys", "nom", @@ -825,6 +825,7 @@ dependencies = [ "rasn", "rasn-ocsp", "rasn-pkix", + "ring", "rsa", "schemars", "serde", @@ -864,7 +865,7 @@ dependencies = [ "log", "mockall", "openssl", - "pem 3.0.4", + "pem", "predicates", "reqwest", "serde", @@ -910,9 +911,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.11" +version = "1.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4730490333d58093109dc02c23174c3f4d490998c3fed3cc8e82d57afedb9cf" +checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229" dependencies = [ "shlex", ] @@ -1102,7 +1103,7 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" dependencies = [ - "getrandom 0.2.15", + "getrandom", "once_cell", "tiny-keccak", ] @@ -1313,7 +1314,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1145d32e826a7748b69ee8fc62d3e6355ff7f1051df53141e7048162fc90481b" dependencies = [ "data-encoding", - "syn 1.0.109", + "syn 2.0.96", ] [[package]] @@ -1811,22 +1812,10 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "wasm-bindgen", ] -[[package]] -name = "getrandom" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.13.3+wasi-0.2.2", - "windows-targets", -] - [[package]] name = "gimli" version = "0.31.1" @@ -2025,9 +2014,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.10.0" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2d708df4e7140240a16cd6ab0ab65c972d7433ab77819ea693fde9c43811e2a" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "httpdate" @@ -2094,9 +2083,9 @@ dependencies = [ [[package]] name = "hyper" -version = "1.6.0" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" +checksum = "256fb8d4bd6413123cc9d91832d78325c48ff41677595be797d90f42969beae0" dependencies = [ "bytes", "futures-channel", @@ -2120,7 +2109,7 @@ checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" dependencies = [ "futures-util", "http 1.2.0", - "hyper 1.6.0", + "hyper 1.5.2", "hyper-util", "rustls", "rustls-pki-types", @@ -2138,7 +2127,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.6.0", + "hyper 1.5.2", "hyper-util", "native-tls", "tokio", @@ -2157,7 +2146,7 @@ dependencies = [ "futures-util", "http 1.2.0", "http-body 1.0.1", - "hyper 1.6.0", + "hyper 1.5.2", "pin-project-lite", "socket2", "tokio", @@ -2558,7 +2547,7 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" dependencies = [ - "spin 0.9.8", + "spin", ] [[package]] @@ -2713,7 +2702,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "windows-sys 0.52.0", ] @@ -2928,9 +2917,9 @@ checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "openssl" -version = "0.10.70" +version = "0.10.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61cfb4e166a8bb8c9b55c500bc2308550148ece889be90f609377e58140f42c6" +checksum = "f5e534d133a060a3c19daec1eb3e98ec6f4685978834f2dbadfe2ec215bab64e" dependencies = [ "bitflags 2.8.0", "cfg-if", @@ -2969,9 +2958,9 @@ dependencies = [ [[package]] name = "openssl-sys" -version = "0.9.105" +version = "0.9.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b22d5b84be05a8d6947c7cb71f7c849aa0f112acd4bf51c2a7c1c988ac0a9dc" +checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" dependencies = [ "cc", "libc", @@ -3082,16 +3071,6 @@ dependencies = [ "utf8-decode", ] -[[package]] -name = "pem" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b13fe415cdf3c8e44518e18a7c95a13431d9bdf6d15367d82b23c377fdd441a" -dependencies = [ - "base64 0.21.7", - "serde", -] - [[package]] name = "pem" version = "3.0.4" @@ -3427,9 +3406,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" dependencies = [ "bytes", - "getrandom 0.2.15", + "getrandom", "rand", - "ring 0.17.8", + "ring", "rustc-hash", "rustls", "rustls-pki-types", @@ -3496,7 +3475,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.15", + "getrandom", ] [[package]] @@ -3634,7 +3613,7 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ - "getrandom 0.2.15", + "getrandom", "libredox", "thiserror 1.0.69", ] @@ -3684,7 +3663,7 @@ dependencies = [ "http 1.2.0", "http-body 1.0.1", "http-body-util", - "hyper 1.6.0", + "hyper 1.5.2", "hyper-rustls", "hyper-tls", "hyper-util", @@ -3734,21 +3713,6 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c601484456988d75017d86700d3743b949c21cdc7399f940c75e34680d185c5" -[[package]] -name = "ring" -version = "0.16.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" -dependencies = [ - "cc", - "libc", - "once_cell", - "spin 0.5.2", - "untrusted 0.7.1", - "web-sys", - "winapi", -] - [[package]] name = "ring" version = "0.17.8" @@ -3757,10 +3721,10 @@ checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.15", + "getrandom", "libc", - "spin 0.9.8", - "untrusted 0.9.0", + "spin", + "untrusted", "windows-sys 0.52.0", ] @@ -3852,13 +3816,13 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.22" +version = "0.23.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb9263ab4eb695e42321db096e3b8fbd715a59b154d5c88d82db2175b681ba7" +checksum = "8f287924602bf649d949c63dc8ac8b235fa5387d394020705b80c4eb597ce5b8" dependencies = [ "log", "once_cell", - "ring 0.17.8", + "ring", "rustls-pki-types", "rustls-webpki", "subtle", @@ -3889,9 +3853,9 @@ version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ - "ring 0.17.8", + "ring", "rustls-pki-types", - "untrusted 0.9.0", + "untrusted", ] [[package]] @@ -3902,9 +3866,9 @@ checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" [[package]] name = "ryu" -version = "1.0.19" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "same-file" @@ -4069,9 +4033,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.138" +version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949" +checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b" dependencies = [ "indexmap 2.7.1", "itoa", @@ -4252,12 +4216,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - [[package]] name = "spin" version = "0.9.8" @@ -4407,13 +4365,13 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.16.0" +version = "3.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91" +checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" dependencies = [ "cfg-if", "fastrand", - "getrandom 0.3.1", + "getrandom", "once_cell", "rustix", "windows-sys 0.59.0", @@ -4626,9 +4584,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.23" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02a8b472d1a3d7c18e2d61a489aee3453fd9031c33e4f55bd533f4a7adca1bee" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ "indexmap 2.7.1", "serde", @@ -4726,9 +4684,9 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicode-ident" -version = "1.0.16" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" +checksum = "11cd88e12b17c6494200a9c1b683a04fcac9573ed74cd1b62aeb2727c5592243" [[package]] name = "unicode-xid" @@ -4736,12 +4694,6 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" -[[package]] -name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - [[package]] name = "untrusted" version = "0.9.0" @@ -4805,7 +4757,7 @@ version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3758f5e68192bb96cc8f9b7e2c2cfdabb435499a28499a42f8f984092adad4b" dependencies = [ - "getrandom 0.2.15", + "getrandom", "serde", "wasm-bindgen", ] @@ -4862,15 +4814,6 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" -[[package]] -name = "wasi" -version = "0.13.3+wasi-0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" -dependencies = [ - "wit-bindgen-rt", -] - [[package]] name = "wasm-bindgen" version = "0.2.100" @@ -4988,9 +4931,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.26.8" +version = "0.26.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2210b291f7ea53617fbafcc4939f10914214ec15aace5ba62293a668f322c5c9" +checksum = "5d642ff16b7e79272ae451b7322067cdc17cadf68c23264be9d94a32319efe7e" dependencies = [ "rustls-pki-types", ] @@ -5155,22 +5098,13 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.7.0" +version = "0.6.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e49d2d35d3fad69b39b94139037ecfb4f359f08958b9c11e7315ce770462419" +checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a" dependencies = [ "memchr", ] -[[package]] -name = "wit-bindgen-rt" -version = "0.33.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" -dependencies = [ - "bitflags 2.8.0", -] - [[package]] name = "write16" version = "1.0.0" @@ -5194,20 +5128,21 @@ dependencies = [ [[package]] name = "x509-certificate" -version = "0.21.0" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5d27c90840e84503cf44364de338794d5d5680bdd1da6272d13f80b0769ee0" +checksum = "66534846dec7a11d7c50a74b7cdb208b9a581cad890b7866430d438455847c85" dependencies = [ "bcder", "bytes", "chrono", "der", "hex", - "pem 2.0.1", - "ring 0.16.20", + "pem", + "ring", "signature", "spki", "thiserror 1.0.69", + "zeroize", ] [[package]] diff --git a/internal/crypto/Cargo.toml b/internal/crypto/Cargo.toml index a54bdf031..510b3fcb0 100644 --- a/internal/crypto/Cargo.toml +++ b/internal/crypto/Cargo.toml @@ -78,7 +78,7 @@ sha2 = "0.10.6" spki = { version = "0.7.3", optional = true } thiserror = "2.0.8" web-time = "1.1" -x509-certificate = "0.21.0" +x509-certificate = "0.23.1" x509-parser = "0.16.0" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] @@ -89,15 +89,15 @@ url = "2.5.3" [package.metadata.cargo-udeps.ignore] normal = ["openssl"] # TEMPORARY: Remove after openssl transition complete. -[dependencies.chrono] +[target.'cfg(all(target_arch = "wasm32", not(target_os = "wasi")))'.dependencies.chrono] version = "0.4.39" default-features = false features = ["wasmbind"] -[target.'cfg(not(target_arch = "wasm32"))'.dependencies.chrono] +[target.'cfg(any(not(target_arch = "wasm32"), target_os = "wasi"))'.dependencies.chrono] version = "0.4.39" default-features = false -features = ["now", "wasmbind"] +features = ["now"] [target.'cfg(target_arch = "wasm32")'.dependencies] async-trait = "0.1.77" @@ -108,6 +108,11 @@ num-bigint-dig = "0.8.4" pkcs1 = "0.7.5" rsa = { version = "0.9.7", features = ["pem", "sha2"] } spki = "0.7.3" + +[target.'cfg(all(target_arch = "wasm32", not(target_os = "wasi")))'.dependencies] +getrandom = { version = "0.2.7", features = ["js"] } +js-sys = "0.3.58" +ring = { version = "0.17", features = ["wasm32_unknown_unknown_js"]} wasm-bindgen = "0.2.83" wasm-bindgen-futures = "0.4.31" web-sys = { version = "0.3.58", features = [ @@ -119,10 +124,6 @@ web-sys = { version = "0.3.58", features = [ "WorkerGlobalScope", ] } -[target.'cfg(all(target_arch = "wasm32", not(target_os = "wasi")))'.dependencies] -getrandom = { version = "0.2.7", features = ["js"] } -js-sys = "0.3.58" - [dev-dependencies] const-oid = "0.9.6" der = "0.7.9" @@ -135,5 +136,5 @@ spki = "0.7.3" [target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] actix = "0.13.1" -[target.'cfg(target_arch = "wasm32")'.dev-dependencies] +[target.'cfg(all(target_arch = "wasm32", not(target_os = "wasi")))'.dev-dependencies] wasm-bindgen-test = "0.3.31" diff --git a/sdk/src/asset_handlers/bmff_io.rs b/sdk/src/asset_handlers/bmff_io.rs index 61cacb3e1..b5851f498 100644 --- a/sdk/src/asset_handlers/bmff_io.rs +++ b/sdk/src/asset_handlers/bmff_io.rs @@ -22,7 +22,6 @@ use std::{ use atree::{Arena, Token}; use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use conv::ValueFrom; -use tempfile::Builder; use crate::{ assertions::{BmffMerkleMap, ExclusionsMap}, @@ -33,7 +32,7 @@ use crate::{ error::{Error, Result}, utils::{ hash_utils::{vec_compare, HashRange}, - io_utils::{stream_len, ReaderUtils}, + io_utils::{stream_len, tempfile_builder, ReaderUtils}, xmp_inmemory_utils::{add_provenance, MIN_XMP}, }, }; @@ -1278,10 +1277,7 @@ impl AssetIO for BmffIO { .open(asset_path) .map_err(Error::IoError)?; - let mut temp_file = Builder::new() - .prefix("c2pa_temp") - .rand_bytes(5) - .tempfile()?; + let mut temp_file = tempfile_builder("c2pa_temp")?; self.write_cai(&mut input_stream, &mut temp_file, store_bytes)?; @@ -1300,10 +1296,7 @@ impl AssetIO for BmffIO { fn remove_cai_store(&self, asset_path: &Path) -> Result<()> { let mut input_file = std::fs::File::open(asset_path)?; - let mut temp_file = Builder::new() - .prefix("c2pa_temp") - .rand_bytes(5) - .tempfile()?; + let mut temp_file = tempfile_builder("c2pa_temp")?; self.remove_cai_store_from_stream(&mut input_file, &mut temp_file)?; @@ -1842,17 +1835,18 @@ impl RemoteRefEmbed for BmffIO { } } } + #[cfg(test)] pub mod tests { #![allow(clippy::expect_used)] #![allow(clippy::panic)] #![allow(clippy::unwrap_used)] - use tempfile::tempdir; - use super::*; - use crate::utils::test::{fixture_path, temp_dir_path}; - + use crate::utils::{ + io_utils::tempdirectory, + test::{fixture_path, temp_dir_path}, + }; #[cfg(all(feature = "openssl", feature = "file_io"))] #[test] fn test_read_mp4() { @@ -1878,7 +1872,7 @@ pub mod tests { let data = "some test data"; let source = fixture_path("video1.mp4"); - let temp_dir = tempdir().unwrap(); + let temp_dir = tempdirectory().unwrap(); let output = temp_dir_path(&temp_dir, "video1-out.mp4"); std::fs::copy(source, &output).unwrap(); @@ -1904,7 +1898,7 @@ pub mod tests { let source = fixture_path("video1.mp4"); let mut success = false; - if let Ok(temp_dir) = tempdir() { + if let Ok(temp_dir) = tempdirectory() { let output = temp_dir_path(&temp_dir, "mp4_test.mp4"); if let Ok(_size) = std::fs::copy(source, &output) { @@ -1928,7 +1922,7 @@ pub mod tests { let source = fixture_path("video1.mp4"); let mut success = false; - if let Ok(temp_dir) = tempdir() { + if let Ok(temp_dir) = tempdirectory() { let output = temp_dir_path(&temp_dir, "mp4_test.mp4"); if let Ok(_size) = std::fs::copy(&source, &output) { @@ -1954,7 +1948,7 @@ pub mod tests { let source = fixture_path("video1.mp4"); let mut success = false; - if let Ok(temp_dir) = tempdir() { + if let Ok(temp_dir) = tempdirectory() { let output = temp_dir_path(&temp_dir, "mp4_test.mp4"); if let Ok(_size) = std::fs::copy(source, &output) { @@ -1981,7 +1975,7 @@ pub mod tests { fn test_remove_c2pa() { let source = fixture_path("video1.mp4"); - let temp_dir = tempdir().unwrap(); + let temp_dir = tempdirectory().unwrap(); let output = temp_dir_path(&temp_dir, "mp4_test.mp4"); std::fs::copy(source, &output).unwrap(); diff --git a/sdk/src/asset_handlers/jpeg_io.rs b/sdk/src/asset_handlers/jpeg_io.rs index 20b5ac697..16215e658 100644 --- a/sdk/src/asset_handlers/jpeg_io.rs +++ b/sdk/src/asset_handlers/jpeg_io.rs @@ -1129,6 +1129,7 @@ pub mod tests { use wasm_bindgen_test::*; use super::*; + use crate::utils::io_utils::tempdirectory; #[test] fn test_extract_xmp() { let contents = Bytes::from_static(b"http://ns.adobe.com/xap/1.0/\0stuff"); @@ -1151,7 +1152,7 @@ pub mod tests { fn test_remove_c2pa() { let source = crate::utils::test::fixture_path("CA.jpg"); - let temp_dir = tempfile::tempdir().unwrap(); + let temp_dir = tempdirectory().unwrap(); let output = crate::utils::test::temp_dir_path(&temp_dir, "CA_test.jpg"); std::fs::copy(source, &output).unwrap(); @@ -1195,7 +1196,7 @@ pub mod tests { fn test_xmp_read_write() { let source = crate::utils::test::fixture_path("CA.jpg"); - let temp_dir = tempfile::tempdir().unwrap(); + let temp_dir = tempdirectory().unwrap(); let output = crate::utils::test::temp_dir_path(&temp_dir, "CA_test.jpg"); std::fs::copy(source, &output).unwrap(); @@ -1227,6 +1228,7 @@ pub mod tests { all(target_arch = "wasm32", not(target_os = "wasi")), wasm_bindgen_test )] + #[allow(unused)] // not run for WASI async fn test_xmp_read_write_stream() { let source_bytes = include_bytes!("../../tests/fixtures/CA.jpg"); @@ -1276,7 +1278,7 @@ pub mod tests { .unwrap(); let curr_manifest = jpeg_io.read_cai_store(&source).unwrap(); - let temp_dir = tempfile::tempdir().unwrap(); + let temp_dir = tempdirectory().unwrap(); let output = crate::utils::test::temp_dir_path(&temp_dir, "CA_test.jpg"); std::fs::copy(source, &output).unwrap(); diff --git a/sdk/src/asset_handlers/mp3_io.rs b/sdk/src/asset_handlers/mp3_io.rs index f9c6d66bb..c37b4c11b 100644 --- a/sdk/src/asset_handlers/mp3_io.rs +++ b/sdk/src/asset_handlers/mp3_io.rs @@ -24,7 +24,6 @@ use id3::{ *, }; use memchr::memmem; -use tempfile::Builder; use crate::{ asset_io::{ @@ -34,7 +33,7 @@ use crate::{ }, error::{Error, Result}, utils::{ - io_utils::{stream_len, ReaderUtils}, + io_utils::{stream_len, tempfile_builder, ReaderUtils}, xmp_inmemory_utils::{self, MIN_XMP}, }, }; @@ -318,10 +317,7 @@ impl AssetIO for Mp3IO { .open(asset_path) .map_err(Error::IoError)?; - let mut temp_file = Builder::new() - .prefix("c2pa_temp") - .rand_bytes(5) - .tempfile()?; + let mut temp_file = tempfile_builder("c2pa_temp")?; self.write_cai(&mut input_stream, &mut temp_file, store_bytes)?; @@ -506,12 +502,12 @@ pub mod tests { #![allow(clippy::panic)] #![allow(clippy::unwrap_used)] - use tempfile::tempdir; use xmp_inmemory_utils::extract_provenance; use super::*; use crate::utils::{ hash_utils::vec_compare, + io_utils::tempdirectory, test::{fixture_path, temp_dir_path}, }; @@ -521,7 +517,7 @@ pub mod tests { let source = fixture_path("sample1.mp3"); let mut success = false; - if let Ok(temp_dir) = tempdir() { + if let Ok(temp_dir) = tempdirectory() { let output = temp_dir_path(&temp_dir, "sample1-mp3.mp3"); if let Ok(_size) = std::fs::copy(source, &output) { @@ -544,7 +540,7 @@ pub mod tests { let source = fixture_path("sample1.mp3"); let mut success = false; - if let Ok(temp_dir) = tempdir() { + if let Ok(temp_dir) = tempdirectory() { let output = temp_dir_path(&temp_dir, "sample1-mp3.mp3"); if let Ok(_size) = std::fs::copy(source, &output) { @@ -573,7 +569,7 @@ pub mod tests { fn test_remove_c2pa() { let source = fixture_path("sample1.mp3"); - let temp_dir = tempdir().unwrap(); + let temp_dir = tempdirectory().unwrap(); let output = temp_dir_path(&temp_dir, "sample1-mp3.mp3"); std::fs::copy(source, &output).unwrap(); diff --git a/sdk/src/asset_handlers/png_io.rs b/sdk/src/asset_handlers/png_io.rs index 3b9eae73e..590dfbadd 100644 --- a/sdk/src/asset_handlers/png_io.rs +++ b/sdk/src/asset_handlers/png_io.rs @@ -21,7 +21,6 @@ use byteorder::{BigEndian, ReadBytesExt}; use conv::ValueFrom; use png_pong::chunk::InternationalText; use serde_bytes::ByteBuf; -use tempfile::Builder; use crate::{ assertions::{BoxMap, C2PA_BOXHASH}, @@ -32,7 +31,7 @@ use crate::{ }, error::{Error, Result}, utils::{ - io_utils::ReaderUtils, + io_utils::{tempfile_builder, ReaderUtils}, xmp_inmemory_utils::{add_provenance, MIN_XMP}, }, }; @@ -479,10 +478,7 @@ impl AssetIO for PngIO { .open(asset_path) .map_err(Error::IoError)?; - let mut temp_file = Builder::new() - .prefix("c2pa_temp") - .rand_bytes(5) - .tempfile()?; + let mut temp_file = tempfile_builder("c2pa_temp")?; self.write_cai(&mut stream, &mut temp_file, store_bytes)?; @@ -793,7 +789,10 @@ pub mod tests { use memchr::memmem; use super::*; - use crate::utils::test::{self, temp_dir_path}; + use crate::utils::{ + io_utils::tempdirectory, + test::{self, temp_dir_path}, + }; #[test] fn test_png_xmp() { @@ -815,7 +814,7 @@ pub mod tests { let ap = test::fixture_path("libpng-test.png"); let mut source_stream = std::fs::File::open(ap).unwrap(); - let temp_dir = tempfile::tempdir().unwrap(); + let temp_dir = tempdirectory().unwrap(); let output = temp_dir_path(&temp_dir, "out.png"); let mut output_stream = std::fs::OpenOptions::new() .read(true) @@ -981,7 +980,7 @@ pub mod tests { #[test] fn test_remove_c2pa() { let source = test::fixture_path("exp-test1.png"); - let temp_dir = tempfile::tempdir().unwrap(); + let temp_dir = tempdirectory().unwrap(); let output = test::temp_dir_path(&temp_dir, "exp-test1_tmp.png"); std::fs::copy(source, &output).unwrap(); @@ -1034,7 +1033,7 @@ pub mod tests { .unwrap(); let curr_manifest = png_io.read_cai_store(&source).unwrap(); - let temp_dir = tempfile::tempdir().unwrap(); + let temp_dir = tempdirectory().unwrap(); let output = crate::utils::test::temp_dir_path(&temp_dir, "exp-test1-out.png"); std::fs::copy(source, &output).unwrap(); diff --git a/sdk/src/asset_handlers/riff_io.rs b/sdk/src/asset_handlers/riff_io.rs index b1e8dc711..1f1695a23 100644 --- a/sdk/src/asset_handlers/riff_io.rs +++ b/sdk/src/asset_handlers/riff_io.rs @@ -21,7 +21,6 @@ use std::{ use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use conv::ValueFrom; use riff::*; -use tempfile::Builder; use crate::{ asset_io::{ @@ -31,7 +30,7 @@ use crate::{ }, error::{Error, Result}, utils::{ - io_utils::stream_len, + io_utils::{stream_len, tempfile_builder}, xmp_inmemory_utils::{add_provenance, MIN_XMP}, }, }; @@ -363,10 +362,7 @@ impl AssetIO for RiffIO { fn save_cai_store(&self, asset_path: &Path, store_bytes: &[u8]) -> Result<()> { let mut input_stream = File::open(asset_path)?; - let mut temp_file = Builder::new() - .prefix("c2pa_temp") - .rand_bytes(5) - .tempfile()?; + let mut temp_file = tempfile_builder("c2pa_temp")?; self.write_cai(&mut input_stream, &mut temp_file, store_bytes)?; @@ -632,11 +628,10 @@ pub mod tests { use std::panic; - use tempfile::tempdir; - use super::*; use crate::utils::{ hash_utils::vec_compare, + io_utils::tempdirectory, test::{fixture_path, temp_dir_path}, xmp_inmemory_utils::extract_provenance, }; @@ -647,7 +642,7 @@ pub mod tests { let source = fixture_path("sample1.wav"); let mut success = false; - if let Ok(temp_dir) = tempdir() { + if let Ok(temp_dir) = tempdirectory() { let output = temp_dir_path(&temp_dir, "sample1-wav.wav"); if let Ok(_size) = std::fs::copy(source, &output) { @@ -685,7 +680,7 @@ pub mod tests { let mut source = File::open(fixture_path("sample1.wav")).unwrap(); let riff_io = RiffIO::new("wav"); - if let Ok(temp_dir) = tempdir() { + if let Ok(temp_dir) = tempdirectory() { let output = temp_dir_path(&temp_dir, "sample1-wav.wav"); let mut output_stream = File::create(&output).unwrap(); @@ -706,7 +701,7 @@ pub mod tests { let source = fixture_path("sample1.wav"); let mut success = false; - if let Ok(temp_dir) = tempdir() { + if let Ok(temp_dir) = tempdirectory() { let output = temp_dir_path(&temp_dir, "sample1-wav.wav"); if let Ok(_size) = std::fs::copy(source, &output) { @@ -735,7 +730,7 @@ pub mod tests { fn test_remove_c2pa() { let source = fixture_path("sample1.wav"); - let temp_dir = tempdir().unwrap(); + let temp_dir = tempdirectory().unwrap(); let output = temp_dir_path(&temp_dir, "sample1-wav.wav"); std::fs::copy(source, &output).unwrap(); @@ -767,7 +762,7 @@ pub mod tests { let source = fixture_path("test_xmp.webp"); let mut success = false; - if let Ok(temp_dir) = tempdir() { + if let Ok(temp_dir) = tempdirectory() { let output = temp_dir_path(&temp_dir, "test_xmp.webp"); std::fs::copy(source, &output).unwrap(); @@ -803,7 +798,7 @@ pub mod tests { let source = fixture_path("test.webp"); let mut success = false; - if let Ok(temp_dir) = tempdir() { + if let Ok(temp_dir) = tempdirectory() { let output = temp_dir_path(&temp_dir, "test.webp"); std::fs::copy(source, &output).unwrap(); @@ -839,7 +834,7 @@ pub mod tests { let source = fixture_path("test_lossless.webp"); let mut success = false; - if let Ok(temp_dir) = tempdir() { + if let Ok(temp_dir) = tempdirectory() { let output = temp_dir_path(&temp_dir, "test_lossless.webp"); std::fs::copy(source, &output).unwrap(); diff --git a/sdk/src/asset_handlers/svg_io.rs b/sdk/src/asset_handlers/svg_io.rs index 3f0d7fe88..447250dbb 100644 --- a/sdk/src/asset_handlers/svg_io.rs +++ b/sdk/src/asset_handlers/svg_io.rs @@ -24,7 +24,6 @@ use quick_xml::{ events::{BytesText, Event}, Reader, Writer, }; -use tempfile::Builder; use crate::{ asset_io::{ @@ -43,7 +42,7 @@ use crate::{ }, error::{Error, Result}, utils::{ - io_utils::{patch_stream, stream_len, ReaderUtils}, + io_utils::{patch_stream, stream_len, tempfile_builder, ReaderUtils}, xmp_inmemory_utils::{self, MIN_XMP}, }, }; @@ -125,10 +124,7 @@ impl AssetIO for SvgIO { .open(asset_path) .map_err(Error::IoError)?; - let mut temp_file = Builder::new() - .prefix("c2pa_temp") - .rand_bytes(5) - .tempfile()?; + let mut temp_file = tempfile_builder("c2pa_temp")?; self.write_cai(&mut input_stream, &mut temp_file, store_bytes)?; @@ -149,10 +145,7 @@ impl AssetIO for SvgIO { fn remove_cai_store(&self, asset_path: &Path) -> Result<()> { let mut input_file = File::open(asset_path)?; - let mut temp_file = Builder::new() - .prefix("c2pa_temp") - .rand_bytes(5) - .tempfile()?; + let mut temp_file = tempfile_builder("c2pa_temp")?; self.remove_cai_store_from_stream(&mut input_file, &mut temp_file)?; @@ -752,12 +745,12 @@ pub mod tests { use std::io::Read; - use tempfile::tempdir; use xmp_inmemory_utils::extract_provenance; use super::*; use crate::utils::{ hash_utils::vec_compare, + io_utils::tempdirectory, test::{fixture_path, temp_dir_path}, }; @@ -767,7 +760,7 @@ pub mod tests { let source = fixture_path("sample1.svg"); let mut success = false; - if let Ok(temp_dir) = tempdir() { + if let Ok(temp_dir) = tempdirectory() { let output = temp_dir_path(&temp_dir, "sample1.svg"); if let Ok(_size) = std::fs::copy(source, &output) { @@ -790,7 +783,7 @@ pub mod tests { let source = fixture_path("sample2.svg"); let mut success = false; - if let Ok(temp_dir) = tempdir() { + if let Ok(temp_dir) = tempdirectory() { let output = temp_dir_path(&temp_dir, "sample2.svg"); if let Ok(_size) = std::fs::copy(source, &output) { @@ -813,7 +806,7 @@ pub mod tests { let source = fixture_path("sample3.svg"); let mut success = false; - if let Ok(temp_dir) = tempdir() { + if let Ok(temp_dir) = tempdirectory() { let output = temp_dir_path(&temp_dir, "sample3.svg"); if let Ok(_size) = std::fs::copy(source, &output) { @@ -836,7 +829,7 @@ pub mod tests { let source = fixture_path("sample1.svg"); let mut success = false; - if let Ok(temp_dir) = tempdir() { + if let Ok(temp_dir) = tempdirectory() { let output = temp_dir_path(&temp_dir, "sample1.svg"); if let Ok(_size) = std::fs::copy(source, &output) { @@ -865,7 +858,7 @@ pub mod tests { fn test_remove_c2pa() { let source = fixture_path("sample4.svg"); - let temp_dir = tempdir().unwrap(); + let temp_dir = tempdirectory().unwrap(); let output = temp_dir_path(&temp_dir, "sample4.svg"); std::fs::copy(source, &output).unwrap(); @@ -886,7 +879,7 @@ pub mod tests { let source = fixture_path("sample1.svg"); let mut success = false; - if let Ok(temp_dir) = tempdir() { + if let Ok(temp_dir) = tempdirectory() { let output = temp_dir_path(&temp_dir, "sample1.svg"); if let Ok(_size) = std::fs::copy(source, &output) { diff --git a/sdk/src/asset_handlers/tiff_io.rs b/sdk/src/asset_handlers/tiff_io.rs index ba60370e3..c5b2cdb9b 100644 --- a/sdk/src/asset_handlers/tiff_io.rs +++ b/sdk/src/asset_handlers/tiff_io.rs @@ -23,7 +23,6 @@ use atree::{Arena, Token}; use byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt}; use byteordered::{with_order, ByteOrdered, Endianness}; use conv::ValueFrom; -use tempfile::Builder; use crate::{ asset_io::{ @@ -33,7 +32,7 @@ use crate::{ }, error::{Error, Result}, utils::{ - io_utils::{safe_vec, stream_len, ReaderUtils}, + io_utils::{safe_vec, stream_len, tempfile_builder, ReaderUtils}, xmp_inmemory_utils::{add_provenance, MIN_XMP}, }, }; @@ -1369,10 +1368,7 @@ impl AssetIO for TiffIO { .open(asset_path) .map_err(Error::IoError)?; - let mut temp_file = Builder::new() - .prefix("c2pa_temp") - .rand_bytes(5) - .tempfile()?; + let mut temp_file = tempfile_builder("c2pa_temp")?; self.write_cai(&mut input_stream, &mut temp_file, store_bytes)?; @@ -1393,10 +1389,7 @@ impl AssetIO for TiffIO { fn remove_cai_store(&self, asset_path: &std::path::Path) -> Result<()> { let mut input_file = std::fs::File::open(asset_path)?; - let mut temp_file = Builder::new() - .prefix("c2pa_temp") - .rand_bytes(5) - .tempfile()?; + let mut temp_file = tempfile_builder("c2pa_temp")?; self.remove_cai_store_from_stream(&mut input_file, &mut temp_file)?; @@ -1637,18 +1630,15 @@ pub mod tests { use core::panic; - use tempfile::tempdir; - use super::*; - use crate::utils::test::temp_dir_path; - + use crate::utils::{io_utils::tempdirectory, test::temp_dir_path}; #[test] fn test_read_write_manifest() { let data = "some data"; let source = crate::utils::test::fixture_path("TUSCANY.TIF"); - let temp_dir = tempdir().unwrap(); + let temp_dir = tempdirectory().unwrap(); let output = temp_dir_path(&temp_dir, "test.tif"); std::fs::copy(source, &output).unwrap(); @@ -1670,7 +1660,7 @@ pub mod tests { let source = crate::utils::test::fixture_path("TUSCANY.TIF"); - let temp_dir = tempdir().unwrap(); + let temp_dir = tempdirectory().unwrap(); let output = temp_dir_path(&temp_dir, "test.tif"); std::fs::copy(source, &output).unwrap(); @@ -1696,7 +1686,7 @@ pub mod tests { let source = crate::utils::test::fixture_path("TUSCANY.TIF"); - let temp_dir = tempdir().unwrap(); + let temp_dir = tempdirectory().unwrap(); let output = temp_dir_path(&temp_dir, "test.tif"); std::fs::copy(source, &output).unwrap(); @@ -1728,7 +1718,7 @@ pub mod tests { let source = crate::utils::test::fixture_path("TUSCANY.TIF"); - let temp_dir = tempdir().unwrap(); + let temp_dir = tempdirectory().unwrap(); let output = temp_dir_path(&temp_dir, "test.tif"); std::fs::copy(source, &output).unwrap(); @@ -1810,7 +1800,7 @@ pub mod tests { let source = crate::utils::test::fixture_path("test.DNG"); //let source = crate::utils::test::fixture_path("sample1.dng"); - let temp_dir = tempdir().unwrap(); + let temp_dir = tempdirectory().unwrap(); let output = temp_dir_path(&temp_dir, "test.DNG"); std::fs::copy(&source, &output).unwrap(); diff --git a/sdk/src/builder.rs b/sdk/src/builder.rs index e16fb2665..c4bf0c6d0 100644 --- a/sdk/src/builder.rs +++ b/sdk/src/builder.rs @@ -1108,16 +1108,18 @@ impl Builder { mod tests { #![allow(clippy::expect_used)] #![allow(clippy::unwrap_used)] - #![cfg(not(target_os = "wasi"))] use std::io::Cursor; use c2pa_crypto::raw_signature::SigningAlg; use serde_json::json; - #[cfg(target_arch = "wasm32")] + #[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))] use wasm_bindgen_test::*; use super::*; - #[cfg(any(feature = "openssl_sign", target_arch = "wasm32"))] + #[cfg(any( + feature = "openssl_sign", + all(target_arch = "wasm32", not(target_os = "wasi")) + ))] use crate::{assertions::BoxHash, asset_handlers::jpeg_io::JpegIO}; use crate::{ hash_stream_by_alg, @@ -1126,7 +1128,7 @@ mod tests { Reader, }; - #[cfg(target_arch = "wasm32")] + #[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))] wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); fn parent_json() -> String { @@ -1330,6 +1332,7 @@ mod tests { builder.to_archive(&mut zipped).unwrap(); // write the zipped stream to a file for debugging + #[cfg(not(target_os = "wasi"))] // target directory is outside of sandbox std::fs::write("../target/test.zip", zipped.get_ref()).unwrap(); // unzip the manifest builder from the zipped stream @@ -1453,8 +1456,12 @@ mod tests { } #[cfg_attr(not(target_arch = "wasm32"), actix::test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + #[cfg_attr( + all(target_arch = "wasm32", not(target_os = "wasi")), + wasm_bindgen_test + )] #[cfg_attr(not(any(target_arch = "wasm32", feature = "openssl_sign")), ignore)] + #[cfg_attr(target_os = "wasi", allow(unused))] async fn test_builder_remote_sign() { let format = "image/jpeg"; let mut source = Cursor::new(TEST_IMAGE); @@ -1585,9 +1592,12 @@ mod tests { } #[cfg_attr(not(target_arch = "wasm32"), actix::test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + #[cfg_attr( + all(target_arch = "wasm32", not(target_os = "wasi")), + wasm_bindgen_test + )] #[cfg(any( - target_arch = "wasm32", + all(target_arch = "wasm32", not(target_os = "wasi")), all(feature = "openssl_sign", feature = "file_io") ))] async fn test_builder_box_hashed_embeddable() { diff --git a/sdk/src/cose_sign.rs b/sdk/src/cose_sign.rs index 7e53de81e..d991f8ecc 100644 --- a/sdk/src/cose_sign.rs +++ b/sdk/src/cose_sign.rs @@ -289,7 +289,7 @@ mod tests { } #[cfg(all(feature = "openssl_sign", feature = "file_io"))] - #[actix::test] + #[cfg_attr(not(target_arch = "wasm32"), actix::test)] async fn test_sign_claim_async() { use c2pa_crypto::raw_signature::SigningAlg; diff --git a/sdk/src/ingredient.rs b/sdk/src/ingredient.rs index 10ca8d54f..a2f617d3b 100644 --- a/sdk/src/ingredient.rs +++ b/sdk/src/ingredient.rs @@ -1491,11 +1491,10 @@ impl IngredientOptions for DefaultOptions { } } -#[cfg(test)] +#[cfg(all(test, not(target_os = "wasi")))] mod tests { #![allow(clippy::expect_used)] #![allow(clippy::unwrap_used)] - #![cfg(not(target_os = wasi))] #[cfg(target_arch = "wasm32")] use wasm_bindgen_test::*; @@ -1703,12 +1702,12 @@ mod tests_file_io { #![allow(clippy::expect_used)] #![allow(clippy::unwrap_used)] - #[cfg(target_arch = "wasm32")] + #[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))] use wasm_bindgen_test::*; use super::*; use crate::utils::test::fixture_path; - #[cfg(target_arch = "wasm32")] + #[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))] wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); const NO_MANIFEST_JPEG: &str = "earth_apollo17.jpg"; diff --git a/sdk/src/manifest.rs b/sdk/src/manifest.rs index 258bda766..2f4994b0f 100644 --- a/sdk/src/manifest.rs +++ b/sdk/src/manifest.rs @@ -1546,7 +1546,6 @@ impl SignatureInfo { pub(crate) mod tests { #![allow(clippy::expect_used)] #![allow(clippy::unwrap_used)] - #![cfg(not(target_os = wasi))] use std::io::Cursor; @@ -1555,10 +1554,10 @@ pub(crate) mod tests { use c2pa_status_tracker::{DetailedStatusTracker, StatusTracker}; #[cfg(feature = "file_io")] use tempfile::tempdir; - #[cfg(target_arch = "wasm32")] + #[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))] use wasm_bindgen_test::*; - #[cfg(target_arch = "wasm32")] + #[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))] wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); #[allow(unused_imports)] @@ -1937,7 +1936,7 @@ pub(crate) mod tests { } #[cfg(all(feature = "file_io", feature = "openssl_sign"))] - #[actix::test] + #[cfg_attr(not(target_arch = "wasm32"), actix::test)] #[allow(deprecated)] async fn test_embed_async_sign() { let temp_dir = tempdir().expect("temp dir"); @@ -1958,7 +1957,7 @@ pub(crate) mod tests { } #[cfg(all(feature = "file_io", feature = "openssl_sign"))] - #[actix::test] + #[cfg_attr(not(target_arch = "wasm32"), actix::test)] #[allow(deprecated)] async fn test_embed_remote_sign() { let temp_dir = tempdir().expect("temp dir"); @@ -2028,9 +2027,13 @@ pub(crate) mod tests { } #[cfg_attr(not(target_arch = "wasm32"), actix::test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + #[cfg_attr( + all(target_arch = "wasm32", not(target_os = "wasi")), + wasm_bindgen_test + )] #[allow(deprecated)] #[cfg_attr(not(any(target_arch = "wasm32", feature = "openssl_sign")), ignore)] + #[cfg_attr(target_os = "wasi", allow(unused))] async fn test_embed_jpeg_stream_wasm() { use crate::assertions::User; let image = include_bytes!("../tests/fixtures/earth_apollo17.jpg"); @@ -2069,9 +2072,13 @@ pub(crate) mod tests { } #[cfg_attr(not(target_arch = "wasm32"), actix::test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + #[cfg_attr( + all(target_arch = "wasm32", not(target_os = "wasi")), + wasm_bindgen_test + )] #[allow(deprecated)] #[cfg_attr(not(any(target_arch = "wasm32", feature = "openssl_sign")), ignore)] + #[cfg_attr(target_os = "wasi", allow(unused))] async fn test_embed_png_stream_wasm() { use crate::assertions::User; let image = include_bytes!("../tests/fixtures/libpng-test.png"); @@ -2103,9 +2110,13 @@ pub(crate) mod tests { } #[cfg_attr(not(target_arch = "wasm32"), actix::test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + #[cfg_attr( + all(target_arch = "wasm32", not(target_os = "wasi")), + wasm_bindgen_test + )] #[allow(deprecated)] #[cfg_attr(not(any(target_arch = "wasm32", feature = "openssl_sign")), ignore)] + #[cfg_attr(target_os = "wasi", allow(unused))] async fn test_embed_webp_stream_wasm() { use crate::assertions::User; let image = include_bytes!("../tests/fixtures/mars.webp"); @@ -2175,9 +2186,12 @@ pub(crate) mod tests { } #[cfg_attr(feature = "openssl_sign", actix::test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + #[cfg_attr( + all(target_arch = "wasm32", not(target_os = "wasi")), + wasm_bindgen_test + )] #[cfg(any( - target_arch = "wasm32", + all(target_arch = "wasm32", not(target_os = "wasi")), all(feature = "openssl_sign", feature = "file_io") ))] async fn test_embed_from_memory_async() { @@ -2220,7 +2234,7 @@ pub(crate) mod tests { } #[cfg(feature = "file_io")] - #[actix::test] + #[cfg_attr(not(target_arch = "wasm32"), actix::test)] #[allow(deprecated)] /// Verify that an ingredient with error is reported on the ingredient and not on the manifest_store async fn test_embed_with_ingredient_error() { @@ -2779,7 +2793,7 @@ pub(crate) mod tests { } #[cfg(all(feature = "file_io", feature = "openssl_sign"))] - #[actix::test] + #[cfg_attr(not(target_arch = "wasm32"), actix::test)] #[allow(deprecated)] async fn test_data_hash_embeddable_manifest_remote_signed() { let ap = fixture_path("cloud.jpg"); diff --git a/sdk/src/manifest_store.rs b/sdk/src/manifest_store.rs index ce94a8020..874cfba7a 100644 --- a/sdk/src/manifest_store.rs +++ b/sdk/src/manifest_store.rs @@ -599,21 +599,23 @@ impl std::fmt::Display for ManifestStore { mod tests { #![allow(clippy::expect_used)] #![allow(clippy::unwrap_used)] - #![cfg(not(target_os = wasi))] use c2pa_status_tracker::OneShotStatusTracker; - #[cfg(target_arch = "wasm32")] + #[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))] use wasm_bindgen_test::*; use super::*; use crate::utils::test::create_test_store; - #[cfg(target_arch = "wasm32")] + #[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))] wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); // #[cfg_attr(not(target_arch = "wasm32"), test)] // #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + #[cfg_attr( + all(target_arch = "wasm32", not(target_os = "wasi")), + wasm_bindgen_test + )] #[test] fn manifest_report() { let store = create_test_store().expect("creating test store"); @@ -652,7 +654,11 @@ mod tests { } #[cfg_attr(not(target_arch = "wasm32"), actix::test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + #[cfg_attr( + all(target_arch = "wasm32", not(target_os = "wasi")), + wasm_bindgen_test + )] + #[cfg_attr(target_os = "wasi", allow(unused))] #[cfg(feature = "v1_api")] #[allow(deprecated)] async fn manifest_report_image_async() { @@ -692,7 +698,11 @@ mod tests { } #[cfg_attr(not(target_arch = "wasm32"), actix::test)] - #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)] + #[cfg_attr( + all(target_arch = "wasm32", not(target_os = "wasi")), + wasm_bindgen_test + )] + #[cfg_attr(target_os = "wasi", allow(unused))] #[allow(deprecated)] #[cfg(feature = "v1_api")] async fn manifest_report_from_manifest_and_asset_bytes_async() { diff --git a/sdk/src/utils/io_utils.rs b/sdk/src/utils/io_utils.rs index 4e89c4268..94984ec09 100644 --- a/sdk/src/utils/io_utils.rs +++ b/sdk/src/utils/io_utils.rs @@ -11,7 +11,13 @@ // specific language governing permissions and limitations under // each license. -use std::io::{Read, Seek, SeekFrom, Write}; +use std::{ + ffi::OsStr, + io::{Read, Seek, SeekFrom, Write}, +}; + +#[allow(unused)] // different code path for WASI +use tempfile::{tempdir, Builder, NamedTempFile, TempDir}; use crate::{Error, Result}; @@ -141,6 +147,31 @@ impl ReaderUtils for R { } } +pub(crate) fn tempfile_builder + Sized>(prefix: T) -> Result { + #[cfg(target_os = "wasi")] + return Builder::new() + .prefix(&prefix) + .rand_bytes(5) + .tempfile_in("/") + .map_err(Error::IoError); + + #[cfg(not(target_os = "wasi"))] + return Builder::new() + .prefix(&prefix) + .rand_bytes(5) + .tempfile() + .map_err(Error::IoError); +} + +#[allow(dead_code)] // used in tests +pub(crate) fn tempdirectory() -> Result { + #[cfg(target_os = "wasi")] + return TempDir::new_in("/").map_err(|e| Error::IoError(e.into())); + + #[cfg(not(target_os = "wasi"))] + return tempdir().map_err(Error::IoError); +} + #[cfg(test)] mod tests { #![allow(clippy::expect_used)] diff --git a/sdk/src/utils/test.rs b/sdk/src/utils/test.rs index 6d5d71005..c1f904fd2 100644 --- a/sdk/src/utils/test.rs +++ b/sdk/src/utils/test.rs @@ -21,10 +21,8 @@ use std::{ }; use async_trait::async_trait; -#[cfg(any(feature = "openssl_sign", target_arch = "wasm32"))] -use c2pa_crypto::cose::TimeStampStorage; use c2pa_crypto::{ - cose::CertificateTrustPolicy, + cose::{CertificateTrustPolicy, TimeStampStorage}, raw_signature::{AsyncRawSigner, RawSignerError, SigningAlg}, time_stamp::{AsyncTimeStampProvider, TimeStampError}, }; @@ -190,6 +188,11 @@ pub fn create_test_store() -> Result { /// returns a path to a file in the fixtures folder pub fn fixture_path(file_name: &str) -> PathBuf { + // File paths are relative to directory specified in dir argument. + // This assumes `wasmtime --dir .` + #[cfg(target_os = "wasi")] + let mut path = PathBuf::from("/"); + #[cfg(not(target_os = "wasi"))] let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); path.push("tests/fixtures"); path.push(file_name); diff --git a/sdk/src/wasm/wasicrypto_validator.rs b/sdk/src/wasm/wasicrypto_validator.rs deleted file mode 100644 index adff88fc7..000000000 --- a/sdk/src/wasm/wasicrypto_validator.rs +++ /dev/null @@ -1,439 +0,0 @@ -// Copyright 2022 Adobe. All rights reserved. -// This file is licensed to you under the Apache License, -// Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) -// or the MIT license (http://opensource.org/licenses/MIT), -// at your option. - -// Unless required by applicable law or agreed to in writing, -// this software is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or -// implied. See the LICENSE-MIT and LICENSE-APACHE files for the -// specific language governing permissions and limitations under -// each license. - -use std::convert::TryFrom; - -use async_generic::async_generic; -use spki::{DecodePublicKey, SubjectPublicKeyInfoRef}; -use x509_parser::der_parser::ber::{parse_ber_sequence, BerObject}; - -use crate::{Error, Result, SigningAlg}; - -// Conversion utility from num-bigint::BigUint (used by x509_parser) -// to num-bigint-dig::BigUint (used by rsa) -fn biguint_val(ber_object: &BerObject) -> rsa::BigUint { - ber_object - .as_biguint() - .map(|x| x.to_u32_digits()) - .map(rsa::BigUint::new) - .unwrap_or_default() -} - -// Validate an Ed25519 signature for the provided data. The pkey must -// be the raw bytes representing CompressedEdwardsY. The length must 32 bytes. -fn ed25519_validate(sig: Vec, data: Vec, pkey: Vec) -> Result { - use ed25519_dalek::{Signature, Verifier, VerifyingKey, PUBLIC_KEY_LENGTH}; - - if pkey.len() == PUBLIC_KEY_LENGTH { - let ed_sig = Signature::from_slice(&sig).map_err(|_| Error::CoseInvalidCert)?; - - // convert to VerifyingKey - let mut cert_slice: [u8; 32] = Default::default(); - cert_slice.copy_from_slice(&pkey[0..PUBLIC_KEY_LENGTH]); - - let vk = VerifyingKey::from_bytes(&cert_slice).map_err(|_| Error::CoseInvalidCert)?; - - match vk.verify(&data, &ed_sig) { - Ok(_) => Ok(true), - Err(_) => Ok(false), - } - } else { - /* - web_sys::console::debug_2( - &"Ed25519 public key incorrect length: ".into(), - &pkey.len().to_string().into(), - ); - */ - Err(Error::CoseInvalidCert) - } -} - -pub(crate) fn validate_signature( - algo: String, - hash: String, - _salt_len: u32, - pkey: Vec, - sig: Vec, - data: Vec, -) -> Result { - use rsa::{ - sha2::{Sha256, Sha384, Sha512}, - RsaPublicKey, - }; - - match algo.as_ref() { - "RSASSA-PKCS1-v1_5" => { - use rsa::{pkcs1v15::Signature, signature::Verifier}; - - // used for certificate validation - let spki = SubjectPublicKeyInfoRef::try_from(pkey.as_ref()) - .map_err(|err| Error::WasmRsaKeyImport(err.to_string()))?; - - let (_, seq) = parse_ber_sequence(spki.subject_public_key.raw_bytes()) - .map_err(|err| Error::WasmRsaKeyImport(err.to_string()))?; - - let modulus = biguint_val(&seq[0]); - let exp = biguint_val(&seq[1]); - let public_key = RsaPublicKey::new(modulus, exp) - .map_err(|err| Error::WasmRsaKeyImport(err.to_string()))?; - let normalized_hash = hash.clone().replace("-", "").to_lowercase(); - - let result = match normalized_hash.as_ref() { - "sha256" => { - let vk = rsa::pkcs1v15::VerifyingKey::::new(public_key); - let signature: Signature = sig.as_slice().try_into().map_err(|_e| { - Error::WasmRsaKeyImport("could no process RSA signature".to_string()) - })?; - vk.verify(&data, &signature) - } - "sha384" => { - let vk = rsa::pkcs1v15::VerifyingKey::::new(public_key); - let signature: Signature = sig.as_slice().try_into().map_err(|_e| { - Error::WasmRsaKeyImport("could no process RSA signature".to_string()) - })?; - vk.verify(&data, &signature) - } - "sha512" => { - let vk = rsa::pkcs1v15::VerifyingKey::::new(public_key); - let signature: Signature = sig.as_slice().try_into().map_err(|_e| { - Error::WasmRsaKeyImport("could no process RSA signature".to_string()) - })?; - vk.verify(&data, &signature) - } - _ => return Err(Error::UnknownAlgorithm), - }; - - match result { - Ok(()) => { - //web_sys::console::debug_1(&"RSA validation success:".into()); - Ok(true) - } - Err(err) => { - /* - web_sys::console::debug_2( - &"RSA validation failed:".into(), - &err.to_string().into(), - ); - */ - Ok(false) - } - } - } - "RSA-PSS" => { - use rsa::{pss::Signature, signature::Verifier}; - - let spki = SubjectPublicKeyInfoRef::try_from(pkey.as_ref()) - .map_err(|err| Error::WasmRsaKeyImport(err.to_string()))?; - - let (_, seq) = parse_ber_sequence(&spki.subject_public_key.raw_bytes()) - .map_err(|err| Error::WasmRsaKeyImport(err.to_string()))?; - - // We need to normalize this from SHA-256 (the format WebCrypto uses) to sha256 - // (the format the util function expects) so that it maps correctly - let normalized_hash = hash.clone().replace("-", "").to_lowercase(); - let modulus = biguint_val(&seq[0]); - let exp = biguint_val(&seq[1]); - let public_key = RsaPublicKey::new(modulus, exp) - .map_err(|err| Error::WasmRsaKeyImport(err.to_string()))?; - - let result = match normalized_hash.as_ref() { - "sha256" => { - let vk = rsa::pss::VerifyingKey::::new(public_key); - let signature: Signature = sig.as_slice().try_into().map_err(|_e| { - Error::WasmRsaKeyImport("could no process RSA signature".to_string()) - })?; - vk.verify(&data, &signature) - } - "sha384" => { - let vk = rsa::pss::VerifyingKey::::new(public_key); - let signature: Signature = sig.as_slice().try_into().map_err(|_e| { - Error::WasmRsaKeyImport("could no process RSA signature".to_string()) - })?; - vk.verify(&data, &signature) - } - "sha512" => { - let vk = rsa::pss::VerifyingKey::::new(public_key); - let signature: Signature = sig.as_slice().try_into().map_err(|_e| { - Error::WasmRsaKeyImport("could no process RSA signature".to_string()) - })?; - vk.verify(&data, &signature) - } - _ => return Err(Error::UnknownAlgorithm), - }; - - match result { - Ok(()) => { - //web_sys::console::debug_1(&"RSA-PSS validation success:".into()); - Ok(true) - } - Err(err) => { - /* - web_sys::console::debug_2( - &"RSA-PSS validation failed:".into(), - &err.to_string().into(), - ); - */ - Ok(false) - } - } - } - "ECDSA" => { - use ecdsa::{signature::Verifier as EcdsaVerifier, Signature as EcdsaSignature}; - use p256::ecdsa::VerifyingKey as P256VerifyingKey; - use p384::ecdsa::VerifyingKey as P384VerifyingKey; - let result = match hash.as_ref() { - "SHA-256" => { - let vk = P256VerifyingKey::from_public_key_der(&pkey) - .map_err(|_| Error::WasmRsaKeyImport("Invalid P-256 key".to_string()))?; - let signature = EcdsaSignature::from_slice(&sig).map_err(|_| { - Error::WasmRsaKeyImport("Invalid ECDSA signature".to_string()) - })?; - vk.verify(&data, &signature) - } - "SHA-384" => { - let vk = P384VerifyingKey::from_public_key_der(&pkey) - .map_err(|_| Error::WasmRsaKeyImport("Invalid P-384 key".to_string()))?; - let signature = EcdsaSignature::from_slice(&sig).map_err(|_| { - Error::WasmRsaKeyImport("Invalid ECDSA signature".to_string()) - })?; - vk.verify(&data, &signature) - } - _ => return Err(Error::UnknownAlgorithm), - }; - - match result { - Ok(_) => Ok(true), - Err(err) => { - /* - web_sys::console::debug_2( - &"ECDSA validation failed:".into(), - &err.to_string().into(), - ); - */ - Ok(false) - } - } - } - "ED25519" => { - use x509_parser::{prelude::*, public_key::PublicKey}; - - // pull out raw Ed code points - if let Ok((_, certificate_public_key)) = SubjectPublicKeyInfo::from_der(&pkey) { - match certificate_public_key.parsed() { - Ok(key) => match key { - PublicKey::Unknown(raw_key) => { - ed25519_validate(sig, data, raw_key.to_vec()) - } - _ => Err(Error::OtherError( - "could not unwrap Ed25519 public key".into(), - )), - }, - Err(_) => Err(Error::OtherError( - "could not recognize Ed25519 public key".into(), - )), - } - } else { - Err(Error::OtherError( - "could not parse Ed25519 public key".into(), - )) - } - } - _ => Err(Error::UnsupportedType), - } -} - -// This interface is called from CoseValidator. RSA validation not supported here. -#[async_generic] -pub fn validate(alg: SigningAlg, sig: &[u8], data: &[u8], pkey: &[u8]) -> Result { - //web_sys::console::debug_2(&"Validating with algorithm".into(), &alg.to_string().into()); - - match alg { - SigningAlg::Ps256 => validate_signature( - "RSA-PSS".to_string(), - "SHA-256".to_string(), - 32, - pkey.to_vec(), - sig.to_vec(), - data.to_vec(), - ), - SigningAlg::Ps384 => validate_signature( - "RSA-PSS".to_string(), - "SHA-384".to_string(), - 48, - pkey.to_vec(), - sig.to_vec(), - data.to_vec(), - ), - SigningAlg::Ps512 => validate_signature( - "RSA-PSS".to_string(), - "SHA-512".to_string(), - 64, - pkey.to_vec(), - sig.to_vec(), - data.to_vec(), - ), - // "rs256" => { - // validate_signature( - // "RSASSA-PKCS1-v1_5".to_string(), - // "SHA-256".to_string(), - // 0, - // pkey.to_vec(), - // sig.to_vec(), - // data.to_vec(), - // ) - // .await - // } - // "rs384" => { - // validate_signature( - // "RSASSA-PKCS1-v1_5".to_string(), - // "SHA-384".to_string(), - // 0, - // pkey.to_vec(), - // sig.to_vec(), - // data.to_vec(), - // ) - // .await - // } - // "rs512" => { - // validate_signature( - // "RSASSA-PKCS1-v1_5".to_string(), - // "SHA-512".to_string(), - // 0, - // pkey.to_vec(), - // sig.to_vec(), - // data.to_vec(), - // ) - // .await - // } - SigningAlg::Es256 => validate_signature( - "ECDSA".to_string(), - "SHA-256".to_string(), - 0, - pkey.to_vec(), - sig.to_vec(), - data.to_vec(), - ), - SigningAlg::Es384 => validate_signature( - "ECDSA".to_string(), - "SHA-384".to_string(), - 0, - pkey.to_vec(), - sig.to_vec(), - data.to_vec(), - ), - SigningAlg::Es512 => validate_signature( - "ECDSA".to_string(), - "SHA-512".to_string(), - 0, - pkey.to_vec(), - sig.to_vec(), - data.to_vec(), - ), - SigningAlg::Ed25519 => validate_signature( - "ED25519".to_string(), - "SHA-512".to_string(), - 0, - pkey.to_vec(), - sig.to_vec(), - data.to_vec(), - ), - } -} - -#[cfg(test)] -pub mod tests { - #![allow(clippy::unwrap_used)] - - use super::*; - use crate::SigningAlg; - - async fn test_async_verify_rsa_pss() { - // PS signatures - let sig_bytes = include_bytes!("../../tests/fixtures/sig_ps256.data"); - let data_bytes = include_bytes!("../../tests/fixtures/data_ps256.data"); - let key_bytes = include_bytes!("../../tests/fixtures/key_ps256.data"); - - let validated = validate_async(SigningAlg::Ps256, sig_bytes, data_bytes, key_bytes) - .await - .unwrap(); - - assert_eq!(validated, true); - } - - async fn test_async_verify_ecdsa() { - // EC signatures - let sig_es384_bytes = include_bytes!("../../tests/fixtures/sig_es384.data"); - let data_es384_bytes = include_bytes!("../../tests/fixtures/data_es384.data"); - let key_es384_bytes = include_bytes!("../../tests/fixtures/key_es384.data"); - - let mut validated = validate_async( - SigningAlg::Es384, - sig_es384_bytes, - data_es384_bytes, - key_es384_bytes, - ) - .await - .unwrap(); - - assert_eq!(validated, true); - - let sig_es512_bytes = include_bytes!("../../tests/fixtures/sig_es512.data"); - let data_es512_bytes = include_bytes!("../../tests/fixtures/data_es512.data"); - let key_es512_bytes = include_bytes!("../../tests/fixtures/key_es512.data"); - - validated = validate_async( - SigningAlg::Es512, - sig_es512_bytes, - data_es512_bytes, - key_es512_bytes, - ) - .await - .unwrap(); - - assert_eq!(validated, true); - - let sig_es256_bytes = include_bytes!("../../tests/fixtures/sig_es256.data"); - let data_es256_bytes = include_bytes!("../../tests/fixtures/data_es256.data"); - let key_es256_bytes = include_bytes!("../../tests/fixtures/key_es256.data"); - - let validated = validate_async( - SigningAlg::Es256, - sig_es256_bytes, - data_es256_bytes, - key_es256_bytes, - ) - .await - .unwrap(); - - assert_eq!(validated, true); - } - - #[ignore] - async fn test_async_verify_bad() { - let sig_bytes = include_bytes!("../../tests/fixtures/sig_ps256.data"); - let data_bytes = include_bytes!("../../tests/fixtures/data_ps256.data"); - let key_bytes = include_bytes!("../../tests/fixtures/key_ps256.data"); - - let mut bad_bytes = data_bytes.to_vec(); - bad_bytes[0] = b'c'; - bad_bytes[1] = b'2'; - bad_bytes[2] = b'p'; - bad_bytes[3] = b'a'; - - let validated = validate_async(SigningAlg::Ps256, sig_bytes, &bad_bytes, key_bytes) - .await - .unwrap(); - - assert_eq!(validated, false); - } -} diff --git a/sdk/src/wasm/wasipki_trust_handler.rs b/sdk/src/wasm/wasipki_trust_handler.rs deleted file mode 100644 index 9c2743db0..000000000 --- a/sdk/src/wasm/wasipki_trust_handler.rs +++ /dev/null @@ -1,672 +0,0 @@ -// Copyright 2023 Adobe. All rights reserved. -// This file is licensed to you under the Apache License, -// Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) -// or the MIT license (http://opensource.org/licenses/MIT), -// at your option. - -// Unless required by applicable law or agreed to in writing, -// this software is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or -// implied. See the LICENSE-MIT and LICENSE-APACHE files for the -// specific language governing permissions and limitations under -// each license. - -use std::{ - collections::HashSet, - io::{BufRead, BufReader, Cursor, Read}, - str::FromStr, -}; - -use asn1_rs::{nom::AsBytes, Any, Class, Header, Tag}; -use async_generic::async_generic; -use x509_parser::{ - der_parser::der::{parse_der_integer, parse_der_sequence_of}, - prelude::*, -}; - -use crate::{ - cose_validator::*, - error::{Error, Result}, - hash_utils::{hash_sha256, vec_compare}, - trust_handler::{ - has_allowed_oid, load_eku_configuration, load_trust_from_data, TrustHandlerConfig, - }, - utils::base64, - wasm::wasicrypto_validator::validate_signature, - SigningAlg, -}; - -// Struct to handle verification of trust chains -pub(crate) struct WasiTrustHandlerConfig { - pub trust_anchors: Vec>, - pub private_anchors: Vec>, - allowed_cert_set: HashSet, - config_store: Vec, -} - -impl std::fmt::Debug for WasiTrustHandlerConfig { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!( - f, - "{} trust anchors, {} private anchors.", - self.trust_anchors.len(), - self.private_anchors.len() - ) - } -} - -impl WasiTrustHandlerConfig { - pub fn load_default_trust(&mut self) -> Result<()> { - // load config store - let config = include_bytes!("./store.cfg"); - let mut config_reader = Cursor::new(config); - self.load_configuration(&mut config_reader)?; - - // load debug/test private trust anchors - if cfg!(test) { - let pa = include_bytes!("./test_cert_root_bundle.pem"); - let mut pa_reader = Cursor::new(pa); - - self.append_private_trust_data(&mut pa_reader)?; - } - - Ok(()) - } -} - -impl TrustHandlerConfig for WasiTrustHandlerConfig { - fn new() -> Self { - let mut th = WasiTrustHandlerConfig { - trust_anchors: Vec::new(), - private_anchors: Vec::new(), - allowed_cert_set: HashSet::new(), - config_store: Vec::new(), - }; - - if th.load_default_trust().is_err() { - th.clear(); // just use empty trust handler to fail automatically - } - - th - } - - // add trust anchors - fn load_trust_anchors_from_data(&mut self, trust_data_reader: &mut dyn Read) -> Result<()> { - let mut trust_data = Vec::new(); - trust_data_reader.read_to_end(&mut trust_data)?; - - let mut anchors = load_trust_from_data(&trust_data)?; - self.trust_anchors.append(&mut anchors); - Ok(()) - } - - // append private trust anchors - fn append_private_trust_data(&mut self, private_anchors_reader: &mut dyn Read) -> Result<()> { - let mut private_anchors_data = Vec::new(); - private_anchors_reader.read_to_end(&mut private_anchors_data)?; - - let mut anchors = load_trust_from_data(&private_anchors_data)?; - self.private_anchors.append(&mut anchors); - - Ok(()) - } - - fn clear(&mut self) { - self.trust_anchors = Vec::new(); - self.private_anchors = Vec::new(); - } - - // load EKU configuration - fn load_configuration(&mut self, config_data: &mut dyn Read) -> Result<()> { - config_data.read_to_end(&mut self.config_store)?; - Ok(()) - } - - // list off auxillary allowed EKU Oid - fn get_auxillary_ekus(&self) -> Vec { - let mut oids = Vec::new(); - if let Ok(oid_strings) = load_eku_configuration(&mut Cursor::new(&self.config_store)) { - for oid_str in &oid_strings { - if let Ok(oid) = asn1_rs::Oid::from_str(oid_str) { - oids.push(oid); - } - } - } - oids - } - - fn get_anchors(&self) -> Vec> { - let mut anchors = Vec::new(); - - anchors.append(&mut self.trust_anchors.clone()); - anchors.append(&mut self.private_anchors.clone()); - - anchors - } - - // add allowed list entries - fn load_allowed_list(&mut self, allowed_list: &mut dyn Read) -> Result<()> { - let mut buffer = Vec::new(); - allowed_list.read_to_end(&mut buffer)?; - - if let Ok(cert_list) = load_trust_from_data(&buffer) { - for cert_der in &cert_list { - let cert_sha256 = hash_sha256(cert_der); - let cert_hash_base64 = base64::encode(&cert_sha256); - - self.allowed_cert_set.insert(cert_hash_base64); - } - } - - // try to load the of base64 encoded encoding of the sha256 hash of the certificate DER encoding - let reader = Cursor::new(buffer); - let buf_reader = BufReader::new(reader); - - let mut inside_cert_block = false; - for l in buf_reader.lines().flatten() { - if l.contains("-----BEGIN") { - inside_cert_block = true; - } - if l.contains("-----END") { - inside_cert_block = false; - } - - // sanity check that data is base64 encoded and outside of certificate block - if !inside_cert_block && base64::decode(&l).is_ok() && !l.is_empty() { - self.allowed_cert_set.insert(l); - } - } - - Ok(()) - } - - // set of allowed cert hashes - fn get_allowed_list(&self) -> &HashSet { - &self.allowed_cert_set - } -} - -fn find_allowed_eku<'a>( - cert_der: &'a [u8], - allowed_ekus: &'a [asn1_rs::Oid<'a>], -) -> Option<&'a asn1_rs::Oid<'a>> { - if let Ok((_rem, cert)) = X509Certificate::from_der(cert_der) { - if let Ok(Some(eku)) = cert.extended_key_usage() { - if let Some(o) = has_allowed_oid(eku.value, allowed_ekus) { - return Some(o); - } - } - } - None -} -fn cert_signing_alg(cert: &x509_parser::certificate::X509Certificate) -> Option { - let cert_alg = cert.signature_algorithm.algorithm.clone(); - - let signing_alg = if cert_alg == SHA256_WITH_RSAENCRYPTION_OID { - "rsa256".to_string() - } else if cert_alg == SHA384_WITH_RSAENCRYPTION_OID { - "rsa384".to_string() - } else if cert_alg == SHA512_WITH_RSAENCRYPTION_OID { - "rsa512".to_string() - } else if cert_alg == ECDSA_WITH_SHA256_OID { - SigningAlg::Es256.to_string() - } else if cert_alg == ECDSA_WITH_SHA384_OID { - SigningAlg::Es384.to_string() - } else if cert_alg == ECDSA_WITH_SHA512_OID { - SigningAlg::Es512.to_string() - } else if cert_alg == RSASSA_PSS_OID { - if let Some(parameters) = &cert.signature_algorithm.parameters { - let seq = match parameters.as_sequence() { - Ok(s) => s, - Err(_) => return None, - }; - - let (_i, (ha_alg, mgf_ai)) = match seq.parse(|i| { - let (i, h) =
::from_der(i)?; - if h.class() != Class::ContextSpecific || h.tag() != Tag(0) { - return Err(nom::Err::Error(asn1_rs::Error::BerValueError)); - } - - let (i, ha_alg) = AlgorithmIdentifier::from_der(i) - .map_err(|_| nom::Err::Error(asn1_rs::Error::BerValueError))?; - - let (i, h) =
::from_der(i)?; - if h.class() != Class::ContextSpecific || h.tag() != Tag(1) { - return Err(nom::Err::Error(asn1_rs::Error::BerValueError)); - } - - let (i, mgf_ai) = AlgorithmIdentifier::from_der(i) - .map_err(|_| nom::Err::Error(asn1_rs::Error::BerValueError))?; - - // Ignore anything that follows these two parameters. - - Ok((i, (ha_alg, mgf_ai))) - }) { - Ok((ii, (h, m))) => (ii, (h, m)), - Err(_) => return None, - }; - - let mgf_ai_parameters = match mgf_ai.parameters { - Some(m) => m, - None => return None, - }; - - let mgf_ai_parameters = match mgf_ai_parameters.as_sequence() { - Ok(m) => m, - Err(_) => return None, - }; - - let (_i, mgf_ai_params_algorithm) = - match ::from_der(&mgf_ai_parameters.content) { - Ok((i, m)) => (i, m), - Err(_) => return None, - }; - - let mgf_ai_params_algorithm = match mgf_ai_params_algorithm.as_oid() { - Ok(m) => m, - Err(_) => return None, - }; - - // must be the same - if ha_alg.algorithm.to_id_string() != mgf_ai_params_algorithm.to_id_string() { - return None; - } - - // check for one of the mandatory types - if ha_alg.algorithm == SHA256_OID { - "ps256".to_string() - } else if ha_alg.algorithm == SHA384_OID { - "ps384".to_string() - } else if ha_alg.algorithm == SHA512_OID { - "ps512".to_string() - } else { - return None; - } - } else { - return None; - } - } else if cert_alg == ED25519_OID { - SigningAlg::Ed25519.to_string() - } else { - return None; - }; - - Some(signing_alg) -} - -#[async_generic] -pub(crate) fn verify_data( - cert_der: Vec, - sig_alg: Option, - sig: Vec, - data: Vec, -) -> Result { - use x509_parser::prelude::*; - - let (_, cert) = - X509Certificate::from_der(cert_der.as_bytes()).map_err(|_e| Error::CoseCertUntrusted)?; - - let certificate_public_key = cert.public_key(); - - if let Some(cert_alg_string) = sig_alg { - let (algo, hash, salt_len) = match cert_alg_string.as_str() { - "rsa256" => ("RSASSA-PKCS1-v1_5".to_string(), "SHA-256".to_string(), 0), - "rsa384" => ("RSASSA-PKCS1-v1_5".to_string(), "SHA-384".to_string(), 0), - "rsa512" => ("RSASSA-PKCS1-v1_5".to_string(), "SHA-512".to_string(), 0), - "es256" => ("ECDSA".to_string(), "SHA-256".to_string().to_string(), 0), - "es384" => ("ECDSA".to_string(), "SHA-384".to_string(), 0), - "es512" => ("ECDSA".to_string(), "SHA-512".to_string(), 0), - "ps256" => ("RSA-PSS".to_string(), "SHA-256".to_string(), 32), - "ps384" => ("RSA-PSS".to_string(), "SHA-384".to_string(), 48), - "ps512" => ("RSA-PSS".to_string(), "SHA-512".to_string(), 64), - "ed25519" => ("ED25519".to_string(), "SHA-512".to_string(), 0), - _ => return Err(Error::UnsupportedType), - }; - - let adjusted_sig = if cert_alg_string.starts_with("es") { - let parsed_alg_string: SigningAlg = cert_alg_string - .parse() - .map_err(|_| Error::UnknownAlgorithm)?; - match der_to_p1363(&sig, parsed_alg_string) { - Some(p1363) => p1363, - None => sig, - } - } else { - sig - }; - - validate_signature( - algo, - hash, - salt_len, - certificate_public_key.raw.to_vec(), - adjusted_sig, - data, - ) - } else { - Err(Error::BadParam("unknown alg processing cert".to_string())) - } -} -// convert der signatures to P1363 format: r | s -fn der_to_p1363(data: &[u8], alg: SigningAlg) -> Option> { - // handle if this is a der sequence - if let Ok((_, bo)) = parse_der_sequence_of(parse_der_integer)(data) { - let seq = bo.as_sequence().ok()?; - - if seq.len() != 2 { - return None; - } - - let rp = seq[0].as_bigint().ok()?; - let sp = seq[1].as_bigint().ok()?; - - let mut r = rp.to_str_radix(16); - let mut s = sp.to_str_radix(16); - - let sig_len: usize = match alg { - SigningAlg::Es256 => 64, - SigningAlg::Es384 => 96, - SigningAlg::Es512 => 132, - _ => return None, - }; - - // pad or truncate as needed - let rp = if r.len() > sig_len { - // truncate - let offset = r.len() - sig_len; - &r[offset..r.len()] - } else { - // pad - while r.len() != sig_len { - r.insert(0, '0'); - } - r.as_ref() - }; - - let sp = if s.len() > sig_len { - // truncate - let offset = s.len() - sig_len; - &s[offset..s.len()] - } else { - // pad - while s.len() != sig_len { - s.insert(0, '0'); - } - s.as_ref() - }; - - if rp.len() != sig_len || rp.len() != sp.len() { - return None; - } - - // merge r and s strings - let mut new_sig = rp.to_string(); - new_sig.push_str(sp); - - // convert back from hex string to byte array - let result = (0..new_sig.len()) - .step_by(2) - .map(|i| { - u8::from_str_radix(&new_sig[i..i + 2], 16) - .map_err(|_err| crate::Error::InvalidEcdsaSignature) - }) - .collect(); - - if let Ok(p1363) = result { - Some(p1363) - } else { - None - } - } else { - Some(data.to_vec()) - } -} - -fn check_chain_order(certs: &[Vec]) -> Result<()> { - use x509_parser::prelude::*; - - let chain_length = certs.len(); - if chain_length < 2 { - return Ok(()); - } - - for i in 1..chain_length { - let (_, current_cert) = - X509Certificate::from_der(&certs[i - 1]).map_err(|_e| Error::CoseCertUntrusted)?; - - let issuer_der = certs[i].to_vec(); - let data = current_cert.tbs_certificate.as_ref(); - let sig = current_cert.signature_value.as_ref(); - - let sig_alg = cert_signing_alg(¤t_cert); - - let result = verify_data(issuer_der, sig_alg, sig.to_vec(), data.to_vec()); - - // keep going as long as it validate - match result { - Ok(b) => { - if !b { - return Err(Error::OtherError("cert chain order invalid".into())); - } - } - Err(e) => return Err(e), - } - } - Ok(()) -} - -fn on_trust_list(th: &dyn TrustHandlerConfig, certs: &[Vec], ee_der: &[u8]) -> Result { - use x509_parser::prelude::*; - - // check the cert against the allowed list first - let cert_sha256 = hash_sha256(ee_der); - let cert_hash_base64 = base64::encode(&cert_sha256); - if th.get_allowed_list().contains(&cert_hash_base64) { - return Ok(true); - } - - // add ee cert if needed to the chain - let full_chain = if !certs.is_empty() && vec_compare(ee_der, &certs[0]) { - certs.to_vec() - } else { - let mut full_chain: Vec> = Vec::new(); - full_chain.push(ee_der.to_vec()); - let mut in_chain = certs.to_vec(); - full_chain.append(&mut in_chain); - full_chain - }; - - // make sure chain is in the correct order and valid - check_chain_order(&full_chain)?; - - // build anchors and check against trust anchors, - let mut anchors: Vec = Vec::new(); - let source_anchors = th.get_anchors(); - for anchor_der in &source_anchors { - let (_, anchor) = - X509Certificate::from_der(anchor_der).map_err(|_e| Error::CoseCertUntrusted)?; - anchors.push(anchor); - } - - if anchors.is_empty() { - return Ok(false); - } - - // work back from last cert in chain against the trust anchors - for cert in certs.iter().rev() { - let (_, chain_cert) = - X509Certificate::from_der(cert).map_err(|_e| Error::CoseCertUntrusted)?; - - for anchor in &source_anchors { - let data = chain_cert.tbs_certificate.as_ref(); - let sig = chain_cert.signature_value.as_ref(); - - let sig_alg = cert_signing_alg(&chain_cert); - - let (_, anchor_cert) = - X509Certificate::from_der(anchor).map_err(|_e| Error::CoseCertUntrusted)?; - - if chain_cert.issuer() == anchor_cert.subject() { - let result = verify_data(anchor.clone(), sig_alg, sig.to_vec(), data.to_vec()); - - match result { - Ok(b) => { - if b { - return Ok(true); - } - } - Err(_) => continue, - } - } - } - } - // todo: consider (path check and names restrictions) - - Ok(false) -} - -// verify certificate and trust chain -#[async_generic] -pub(crate) fn verify_trust( - th: &dyn TrustHandlerConfig, - chain_der: &[Vec], - cert_der: &[u8], - _signing_time_epoc: Option, -) -> Result { - // check configured EKUs against end-entity cert - find_allowed_eku(cert_der, &th.get_auxillary_ekus()).ok_or(Error::CoseCertUntrusted)?; - - on_trust_list(th, chain_der, cert_der) -} - -#[cfg(test)] -pub mod tests { - #![allow(clippy::expect_used)] - #![allow(clippy::panic)] - #![allow(clippy::unwrap_used)] - - use super::*; - #[test] - async fn test_trust_store() { - let mut th = WasiTrustHandlerConfig::new(); - th.clear(); - - th.load_default_trust().unwrap(); - - // test all the certs - let ps256 = include_bytes!("../../tests/fixtures/certs/ps256.pub"); - let ps384 = include_bytes!("../../tests/fixtures/certs/ps384.pub"); - let ps512 = include_bytes!("../../tests/fixtures/certs/ps512.pub"); - let es256 = include_bytes!("../../tests/fixtures/certs/es256.pub"); - let es384 = include_bytes!("../../tests/fixtures/certs/es384.pub"); - let es512 = include_bytes!("../../tests/fixtures/certs/es512.pub"); - let ed25519 = include_bytes!("../../tests/fixtures/certs/ed25519.pub"); - - let ps256_certs = load_trust_from_data(ps256).unwrap(); - let ps384_certs = load_trust_from_data(ps384).unwrap(); - let ps512_certs = load_trust_from_data(ps512).unwrap(); - let es256_certs = load_trust_from_data(es256).unwrap(); - let es384_certs = load_trust_from_data(es384).unwrap(); - let es512_certs = load_trust_from_data(es512).unwrap(); - let ed25519_certs = load_trust_from_data(ed25519).unwrap(); - - assert!( - verify_trust_async(&th, &ps256_certs[1..], &ps256_certs[0], None) - .await - .unwrap() - ); - assert!( - verify_trust_async(&th, &ps384_certs[1..], &ps384_certs[0], None) - .await - .unwrap() - ); - assert!( - verify_trust_async(&th, &ps512_certs[1..], &ps512_certs[0], None) - .await - .unwrap() - ); - assert!( - verify_trust_async(&th, &es256_certs[1..], &es256_certs[0], None) - .await - .unwrap() - ); - - assert!( - verify_trust_async(&th, &es384_certs[1..], &es384_certs[0], None) - .await - .unwrap() - ); - assert!( - verify_trust_async(&th, &es512_certs[1..], &es512_certs[0], None) - .await - .unwrap() - ); - - assert!( - verify_trust_async(&th, &ed25519_certs[1..], &ed25519_certs[0], None) - .await - .unwrap() - ); - } - - #[test] - async fn test_broken_trust_chain() { - let mut th = WasiTrustHandlerConfig::new(); - th.clear(); - - th.load_default_trust().unwrap(); - - // test all the certs - let ps256 = include_bytes!("../../tests/fixtures/certs/ps256.pub"); - let ps384 = include_bytes!("../../tests/fixtures/certs/ps384.pub"); - let ps512 = include_bytes!("../../tests/fixtures/certs/ps512.pub"); - let es256 = include_bytes!("../../tests/fixtures/certs/es256.pub"); - let es384 = include_bytes!("../../tests/fixtures/certs/es384.pub"); - let es512 = include_bytes!("../../tests/fixtures/certs/es512.pub"); - let ed25519 = include_bytes!("../../tests/fixtures/certs/ed25519.pub"); - - let ps256_certs = load_trust_from_data(ps256).unwrap(); - let ps384_certs = load_trust_from_data(ps384).unwrap(); - let ps512_certs = load_trust_from_data(ps512).unwrap(); - let es256_certs = load_trust_from_data(es256).unwrap(); - let es384_certs = load_trust_from_data(es384).unwrap(); - let es512_certs = load_trust_from_data(es512).unwrap(); - let ed25519_certs = load_trust_from_data(ed25519).unwrap(); - - assert!( - !verify_trust_async(&th, &ps256_certs[2..], &ps256_certs[0], None) - .await - .unwrap() - ); - assert!( - !verify_trust_async(&th, &ps384_certs[2..], &ps384_certs[0], None) - .await - .unwrap() - ); - assert!( - !verify_trust_async(&th, &ps512_certs[2..], &ps512_certs[0], None) - .await - .unwrap() - ); - assert!( - !verify_trust_async(&th, &es256_certs[2..], &es256_certs[0], None) - .await - .unwrap() - ); - assert!( - !verify_trust_async(&th, &es384_certs[2..], &es384_certs[0], None) - .await - .unwrap() - ); - assert!( - !verify_trust_async(&th, &es512_certs[2..], &es512_certs[0], None) - .await - .unwrap() - ); - assert!( - !verify_trust_async(&th, &ed25519_certs[2..], &ed25519_certs[0], None) - .await - .unwrap() - ); - } -} diff --git a/sdk/tests/test_builder.rs b/sdk/tests/test_builder.rs index e1ced9ace..3748e7c94 100644 --- a/sdk/tests/test_builder.rs +++ b/sdk/tests/test_builder.rs @@ -21,7 +21,7 @@ mod common; use common::{compare_stream_to_known_good, fixtures_path, test_signer}; #[test] -#[cfg_attr(not(any(target_arch = "wasm32", feature = "openssl")), ignore)] +#[ignore] // TODO: Test does not pass in WASI or native fn test_builder_ca_jpg() -> Result<()> { let manifest_def = std::fs::read_to_string(fixtures_path("simple_manifest.json"))?; let mut builder = Builder::from_json(&manifest_def)?;