diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..0c99bdc --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +**/Dockerfile* +target/ diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..8e255fd --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,4 @@ +# Each line is a file pattern followed by one or more owners. +# Owners will be automatically notified about new PRs and +# an owner's approval is required to merge to protected branches. +* @matter-labs/tee diff --git a/.github/renovate.json b/.github/renovate.json new file mode 100644 index 0000000..39a2b6e --- /dev/null +++ b/.github/renovate.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "config:base" + ] +} diff --git a/.github/workflows/container.yml b/.github/workflows/container.yml new file mode 100644 index 0000000..9917bcc --- /dev/null +++ b/.github/workflows/container.yml @@ -0,0 +1,52 @@ +name: Container +on: + push: + branches: [ "main" ] + pull_request: + +jobs: + push_to_registry: + permissions: + packages: write + contents: read + name: Build and push containers image to GitHub Packages + runs-on: ubuntu-latest + concurrency: + group: ${{ github.workflow }}-${{ github.ref }}-${{ matrix.config.dockerfile }} + cancel-in-progress: true + strategy: + fail-fast: false + matrix: + config: + - { dockerfile: 'vault/Dockerfile', tag: 'vault:latest', repository: 'teepot-vault' } + - { dockerfile: 'bin/tee-vault-unseal/Dockerfile-azure', tag: 'tvu:latest', repository: 'teepot-tvu' } + - { dockerfile: 'bin/tee-vault-admin/Dockerfile-azure', tag: 'tva:latest', repository: 'teepot-tva' } + steps: + - name: Check out the repo + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Log in to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USER }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Set up env + run: echo "repository_owner=${GITHUB_REPOSITORY_OWNER,,}" >>${GITHUB_ENV} + - name: Build and Push Container + uses: docker/build-push-action@v5 + with: + file: ${{ matrix.config.dockerfile }} + tags: | + ghcr.io/${{env.repository_owner}}/${{ github.event.repository.name }}-${{ matrix.config.tag }} + matterlabsrobot/${{ matrix.config.repository }}:latest + cache-from: type=gha + cache-to: type=gha,mode=max,ignore-error=true + push: ${{ github.event_name == 'push' || github.event_name == 'schedule' }} + diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..3d13537 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,47 @@ +name: lint + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + fmt: + name: cargo fmt + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 + - name: Setup Rust toolchain + run: rustup show + - run: cargo fmt --all -- --check + + deny: + name: cargo deny + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 + - uses: EmbarkStudios/cargo-deny-action@v1 + with: + arguments: --workspace + + check-spdx-headers: + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 + - uses: enarx/spdx@master + with: + licenses: Apache-2.0 BSD-3-Clause MIT + + taplo: + name: taplo + runs-on: ubuntu-latest + container: tamasfe/taplo:latest + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 + - run: taplo fmt --check diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml new file mode 100644 index 0000000..97df33c --- /dev/null +++ b/.github/workflows/nix.yml @@ -0,0 +1,66 @@ +name: nix + +on: + pull_request: + branches: [ "main" ] + push: + branches: [ "main" ] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 + - uses: cachix/install-nix-action@6004951b182f8860210c8d6f0d808ec5b1a33d28 # v25 + with: + extra_nix_config: | + access-tokens = github.com=${{ github.token }} + - run: nix flake check -L --show-trace --keep-going + + fmt: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 + - uses: cachix/install-nix-action@6004951b182f8860210c8d6f0d808ec5b1a33d28 # v25 + with: + extra_nix_config: | + access-tokens = github.com=${{ github.token }} + - run: nix fmt + + clippy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 + - uses: cachix/install-nix-action@6004951b182f8860210c8d6f0d808ec5b1a33d28 # v25 + with: + extra_nix_config: | + access-tokens = github.com=${{ github.token }} + - uses: cachix/cachix-action@v14 + continue-on-error: true + with: + name: teepot + authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' + extraPullNames: nixsgx + - name: cargo clippy + run: nix develop -L --ignore-environment -c cargo clippy --all --locked + + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 + - uses: cachix/install-nix-action@6004951b182f8860210c8d6f0d808ec5b1a33d28 # v25 + with: + extra_nix_config: | + access-tokens = github.com=${{ github.token }} + - uses: cachix/cachix-action@v14 + continue-on-error: true + with: + name: teepot + authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' + extraPullNames: nixsgx + - name: nix build + run: nix run nixpkgs#nixci diff --git a/.github/workflows/secrets_scanner.yaml b/.github/workflows/secrets_scanner.yaml new file mode 100644 index 0000000..c326ae8 --- /dev/null +++ b/.github/workflows/secrets_scanner.yaml @@ -0,0 +1,18 @@ +name: Leaked Secrets Scan +on: [pull_request] +jobs: + TruffleHog: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4 + with: + fetch-depth: 0 + - name: TruffleHog OSS + uses: trufflesecurity/trufflehog@4db20e29f8568502b8d69ca2be6ce47a533925d3 # v3.63.3 + with: + path: ./ + base: ${{ github.event.repository.default_branch }} + head: HEAD + extra_args: --debug --only-verified + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..29db1db --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb + +# Intellij +/.idea +/.fleet + +/.envrc +/.direnv +/result diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..b4cff94 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,3292 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "actix-codec" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617a8268e3537fe1d8c9ead925fca49ef6400927ee7bc26750e90ecee14ce4b8" +dependencies = [ + "bitflags 1.3.2", + "bytes", + "futures-core", + "futures-sink", + "memchr", + "pin-project-lite", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "actix-http" +version = "3.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d223b13fd481fc0d1f83bb12659ae774d9e3601814c68a0bc539731698cca743" +dependencies = [ + "actix-codec", + "actix-rt", + "actix-service", + "actix-tls", + "actix-utils", + "ahash", + "base64", + "bitflags 2.4.2", + "brotli", + "bytes", + "bytestring", + "derive_more", + "encoding_rs", + "flate2", + "futures-core", + "h2", + "http 0.2.11", + "httparse", + "httpdate", + "itoa", + "language-tags", + "local-channel", + "mime", + "percent-encoding", + "pin-project-lite", + "rand", + "sha1", + "smallvec", + "tokio", + "tokio-util", + "tracing", + "zstd", +] + +[[package]] +name = "actix-macros" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" +dependencies = [ + "quote", + "syn 2.0.48", +] + +[[package]] +name = "actix-router" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d22475596539443685426b6bdadb926ad0ecaefdfc5fb05e5e3441f15463c511" +dependencies = [ + "bytestring", + "http 0.2.11", + "regex", + "serde", + "tracing", +] + +[[package]] +name = "actix-rt" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28f32d40287d3f402ae0028a9d54bef51af15c8769492826a69d28f81893151d" +dependencies = [ + "futures-core", + "tokio", +] + +[[package]] +name = "actix-server" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eb13e7eef0423ea6eab0e59f6c72e7cb46d33691ad56a726b3cd07ddec2c2d4" +dependencies = [ + "actix-rt", + "actix-service", + "actix-utils", + "futures-core", + "futures-util", + "mio", + "socket2", + "tokio", + "tracing", +] + +[[package]] +name = "actix-service" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b894941f818cfdc7ccc4b9e60fa7e53b5042a2e8567270f9147d5591893373a" +dependencies = [ + "futures-core", + "paste", + "pin-project-lite", +] + +[[package]] +name = "actix-tls" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4cce60a2f2b477bc72e5cde0af1812a6e82d8fd85b5570a5dcf2a5bf2c5be5f" +dependencies = [ + "actix-rt", + "actix-service", + "actix-utils", + "futures-core", + "http 0.2.11", + "http 1.0.0", + "impl-more", + "pin-project-lite", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tokio-util", + "tracing", + "webpki-roots", +] + +[[package]] +name = "actix-utils" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a1dcdff1466e3c2488e1cb5c36a71822750ad43839937f85d2f4d9f8b705d8" +dependencies = [ + "local-waker", + "pin-project-lite", +] + +[[package]] +name = "actix-web" +version = "4.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a6556ddebb638c2358714d853257ed226ece6023ef9364f23f0c70737ea984" +dependencies = [ + "actix-codec", + "actix-http", + "actix-macros", + "actix-router", + "actix-rt", + "actix-server", + "actix-service", + "actix-tls", + "actix-utils", + "actix-web-codegen", + "ahash", + "bytes", + "bytestring", + "cfg-if", + "cookie", + "derive_more", + "encoding_rs", + "futures-core", + "futures-util", + "itoa", + "language-tags", + "log", + "mime", + "once_cell", + "pin-project-lite", + "regex", + "serde", + "serde_json", + "serde_urlencoded", + "smallvec", + "socket2", + "time", + "url", +] + +[[package]] +name = "actix-web-codegen" +version = "4.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb1f50ebbb30eca122b188319a4398b3f7bb4a8cdf50ecfb73bfc6a3c3ce54f5" +dependencies = [ + "actix-router", + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aes" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "ahash" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anstyle" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" + +[[package]] +name = "anyhow" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "awc" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68c09cc97310b926f01621faee652f3d1b0962545a3cec6c9ac07def9ea36c2c" +dependencies = [ + "actix-codec", + "actix-http", + "actix-rt", + "actix-service", + "actix-tls", + "actix-utils", + "base64", + "bytes", + "cfg-if", + "cookie", + "derive_more", + "futures-core", + "futures-util", + "h2", + "http 0.2.11", + "itoa", + "log", + "mime", + "percent-encoding", + "pin-project-lite", + "rand", + "rustls", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", +] + +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bindgen" +version = "0.69.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" +dependencies = [ + "bitflags 2.4.2", + "cexpr", + "clang-sys", + "itertools", + "lazy_static", + "lazycell", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.48", + "which", +] + +[[package]] +name = "bitfield" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d7e60934ceec538daadb9d8432424ed043a904d8e0243f3c6446bce549a46ac" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-padding" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" +dependencies = [ + "generic-array", +] + +[[package]] +name = "blowfish" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e412e2cd0f2b2d93e02543ceae7917b3c70331573df19ee046bcbc35e45e87d7" +dependencies = [ + "byteorder", + "cipher", +] + +[[package]] +name = "brotli" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "516074a47ef4bce09577a3b379392300159ce5b1ba2e501ff1c819950066100f" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "2.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e2e4afe60d7dd600fdd3de8d0f08c2b7ec039712e3b6137ff98b7004e82de4f" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bstr" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c48f0051a4b4c5e0b6d365cd04af53aeaa209e3cc15ec2cdb69e73cc87fbd0dc" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "buffer-redux" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2886ea01509598caac116942abd33ab5a88fa32acdf7e4abfa0fc489ca520c9" +dependencies = [ + "memchr", + "safemem", +] + +[[package]] +name = "bumpalo" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + +[[package]] +name = "bytemuck" +version = "1.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea31d69bda4949c1c1562c1e6f042a1caefac98cdc8a298260a2ff41c1e2d42b" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "965ab7eb5f8f97d2a083c799f3a1b994fc397b2fe2da5d1da1626ce15a39f2b1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + +[[package]] +name = "bytestring" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d80203ea6b29df88012294f62733de21cfeab47f17b41af3a38bc30a03ee72" +dependencies = [ + "bytes", +] + +[[package]] +name = "camellia" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3264e2574e9ef2b53ce6f536dea83a69ac0bc600b762d1523ff83fe07230ce30" +dependencies = [ + "byteorder", + "cipher", +] + +[[package]] +name = "cast5" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b07d673db1ccf000e90f54b819db9e75a8348d6eb056e9b8ab53231b7a9911" +dependencies = [ + "cipher", +] + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "jobserver", + "libc", +] + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfb-mode" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "738b8d467867f80a71351933f70461f5b56f24d5c93e0cf216e59229c968d330" +dependencies = [ + "cipher", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41daef31d7a747c5c847246f36de49ced6f7403b4cdabc807a97b5cc184cda7a" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "serde", + "windows-targets 0.52.0", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "clang-sys" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "clap" +version = "4.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" +dependencies = [ + "anstyle", + "clap_lex", + "terminal_size", +] + +[[package]] +name = "clap_derive" +version = "4.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "clap_lex" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "cookie" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" +dependencies = [ + "percent-encoding", + "time", + "version_check", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crc24" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd121741cf3eb82c08dd3023eb55bf2665e5f60ec20f89760cf836ae4562e6a0" + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89b8c6a2e4b1f45971ad09761aafb85514a84744b67a95e32c3cc1352d1f65c" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest", + "fiat-crypto", + "platforms", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core 0.14.4", + "darling_macro 0.14.4", +] + +[[package]] +name = "darling" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" +dependencies = [ + "darling_core 0.20.3", + "darling_macro 0.20.3", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 1.0.109", +] + +[[package]] +name = "darling_core" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.48", +] + +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core 0.14.4", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" +dependencies = [ + "darling_core 0.20.3", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "der" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +dependencies = [ + "const-oid", + "der_derive", + "flagset", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "der_derive" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fe87ce4529967e0ba1dcf8450bab64d97dfd5010a6256187ffe2e43e6f0e049" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", + "serde", +] + +[[package]] +name = "derive_builder" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f" +dependencies = [ + "darling 0.14.4", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_builder_macro" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e" +dependencies = [ + "derive_builder_core", + "syn 1.0.109", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 1.0.109", +] + +[[package]] +name = "des" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdd80ce8ce993de27e9f063a444a4d53ce8e8db4c1f00cc03af5ad5a9867a1e" +dependencies = [ + "cipher", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f628eaec48bfd21b865dc2950cfa014450c01d2fa2b69a86c2fd5844ec523c0" +dependencies = [ + "curve25519-dalek", + "ed25519", + "serde", + "sha2", + "subtle", + "zeroize", +] + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "hkdf", + "pem-rfc7468", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "encoding_rs" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "enumset" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "226c0da7462c13fb57e5cc9e0dc8f0635e7d27f276a3a7fd30054647f669007d" +dependencies = [ + "enumset_derive", + "serde", +] + +[[package]] +name = "enumset_derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08b6c6ab82d70f08844964ba10c7babb716de2ecaeab9be5717918a5177d3af" +dependencies = [ + "darling 0.20.3", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27573eac26f4dd11e2b1916c3fe1baa56407c83c71a773a8ba17ec0bca03b6b7" + +[[package]] +name = "flagset" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a7e408202050813e6f1d9addadcaafef3dca7530c7ddfb005d4081cce6779" + +[[package]] +name = "flate2" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-core", + "futures-sink", + "futures-task", + "pin-project-lite", + "pin-utils", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "h2" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.11", + "indexmap 2.1.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "http" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "iana-time-zone" +version = "0.1.59" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "idea" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "075557004419d7f2031b8bb7f44bb43e55a83ca7b63076a8fb8fe75753836477" +dependencies = [ + "cipher", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "impl-more" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "206ca75c9c03ba3d4ace2460e57b189f39f43de612c2f85836e65c929701bb2d" + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +dependencies = [ + "equivalent", + "hashbrown 0.14.3", + "serde", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + +[[package]] +name = "intel-tee-quote-verification-rs" +version = "0.2.1" +dependencies = [ + "intel-tee-quote-verification-sys", + "serde", +] + +[[package]] +name = "intel-tee-quote-verification-sys" +version = "0.2.0" +dependencies = [ + "bindgen", +] + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" + +[[package]] +name = "jobserver" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "k256" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2", + "signature", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "language-tags" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin 0.5.2", +] + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "libc" +version = "0.2.152" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" + +[[package]] +name = "libloading" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "linux-raw-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" + +[[package]] +name = "local-channel" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6cbc85e69b8df4b8bb8b89ec634e7189099cea8927a276b7384ce5488e53ec8" +dependencies = [ + "futures-core", + "futures-sink", + "local-waker", +] + +[[package]] +name = "local-waker" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d873d7c67ce09b42110d801813efbc9364414e356be9935700d368351657487" + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + +[[package]] +name = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "mutually_exclusive_features" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d02c0b00610773bb7fc61d85e13d86c7858cbdf00e1a120bfc41bc055dbaa0e" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num-bigint-dig" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand", + "serde", + "smallvec", + "zeroize", +] + +[[package]] +name = "num-derive" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfb77679af88f8b125209d354a202862602672222e7f2313fdd6dc349bad4712" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "p384" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70786f51bcc69f6a4c0360e063a4cac5419ef7c5cd5b3c99ad70f3be5ba79209" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.48.5", +] + +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pgp" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27e1f8e085bfa9b85763fe3ddaacbe90a09cd847b3833129153a6cb063bbe132" +dependencies = [ + "aes", + "base64", + "bitfield", + "block-padding", + "blowfish", + "bstr", + "buffer-redux", + "byteorder", + "camellia", + "cast5", + "cfb-mode", + "chrono", + "cipher", + "crc24", + "curve25519-dalek", + "derive_builder", + "des", + "digest", + "ed25519-dalek", + "elliptic-curve", + "flate2", + "generic-array", + "hex", + "idea", + "log", + "md-5", + "nom", + "num-bigint-dig", + "num-derive", + "num-traits", + "p256", + "p384", + "rand", + "ripemd", + "rsa", + "sha1", + "sha2", + "sha3", + "signature", + "smallvec", + "thiserror", + "twofish", + "x25519-dalek", + "zeroize", +] + +[[package]] +name = "pin-project" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" + +[[package]] +name = "platforms" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "626dec3cac7cc0e1577a2ec3fc496277ec2baa084bebad95bb6fdbfae235f84c" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "prettyplease" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5" +dependencies = [ + "proc-macro2", + "syn 2.0.48", +] + +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "regex" +version = "1.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.4", + "regex-syntax 0.8.2", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b7fa1134405e2ec9353fd416b17f8dacd46c473d7d3fd1cf202706a14eb792a" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.2", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "ring" +version = "0.17.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +dependencies = [ + "cc", + "getrandom", + "libc", + "spin 0.9.8", + "untrusted", + "windows-sys 0.48.0", +] + +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest", +] + +[[package]] +name = "rsa" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core", + "sha2", + "signature", + "spki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.38.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca" +dependencies = [ + "bitflags 2.4.2", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.22.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e87c9956bd9807afa1f77e0f7594af32566e830e088a5576d27c5b6f30f49d41" +dependencies = [ + "log", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64", +] + +[[package]] +name = "rustls-pki-types" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a716eb65e3158e90e17cd93d855216e27bde02745ab842f2cab4a39dba1bacf" + +[[package]] +name = "rustls-webpki" +version = "0.102.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faaa0a62740bedb9b2ef5afa303da42764c012f743917351dc9a237ea1663610" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "ryu" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" + +[[package]] +name = "safemem" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "semver" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" + +[[package]] +name = "serde" +version = "1.0.195" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.195" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "serde_json" +version = "1.0.111" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "3.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b0ed1662c5a68664f45b76d18deb0e234aff37207086803165c961eb695e981" +dependencies = [ + "base64", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.1.0", + "serde", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "568577ff0ef47b879f736cd66740e022f3672788cdf002a05a4e609ea5a6fb15" +dependencies = [ + "darling 0.20.3", + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest", + "keccak", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" + +[[package]] +name = "socket2" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +dependencies = [ + "libc", + "windows-sys 0.48.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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tee-key-preexec" +version = "0.1.0" +dependencies = [ + "anyhow", + "hex", + "k256", + "rand", + "sha2", + "teepot", + "tracing", + "tracing-log", + "tracing-subscriber", +] + +[[package]] +name = "tee-self-attestation-test" +version = "0.1.0" +dependencies = [ + "actix-web", + "anyhow", + "teepot", + "tracing", + "tracing-log", + "tracing-subscriber", +] + +[[package]] +name = "tee-stress-client" +version = "0.1.0" +dependencies = [ + "actix-web", + "anyhow", + "awc", + "base64", + "bytemuck", + "clap", + "hex", + "mio", + "rustls", + "serde", + "serde_json", + "sha2", + "teepot", + "tracing", + "tracing-actix-web", + "tracing-log", + "tracing-subscriber", +] + +[[package]] +name = "tee-vault-admin" +version = "0.1.0" +dependencies = [ + "actix-web", + "anyhow", + "awc", + "base64", + "bytemuck", + "clap", + "hex", + "mio", + "rustls", + "serde", + "serde_json", + "sha2", + "teepot", + "tracing", + "tracing-actix-web", + "tracing-log", + "tracing-subscriber", +] + +[[package]] +name = "tee-vault-unseal" +version = "0.1.0" +dependencies = [ + "actix-tls", + "actix-web", + "anyhow", + "awc", + "clap", + "hex", + "mio", + "rustls", + "rustls-pemfile", + "serde", + "serde_json", + "sha2", + "teepot", + "thiserror", + "tokio", + "tracing", + "tracing-log", + "tracing-subscriber", + "x509-cert", +] + +[[package]] +name = "teepot" +version = "0.1.0" +dependencies = [ + "actix-http", + "actix-web", + "anyhow", + "awc", + "base64", + "bitflags 2.4.2", + "bytemuck", + "bytes", + "clap", + "const-oid", + "enumset", + "futures-core", + "getrandom", + "hex", + "intel-tee-quote-verification-rs", + "num-integer", + "num-traits", + "pgp", + "pkcs8", + "rand", + "ring", + "rsa", + "rustls", + "sec1", + "serde", + "serde_json", + "serde_with", + "sha2", + "testaso", + "thiserror", + "tracing", + "x509-cert", + "zeroize", +] + +[[package]] +name = "teepot-read" +version = "0.1.0" +dependencies = [ + "actix-web", + "anyhow", + "awc", + "clap", + "serde", + "serde_json", + "teepot", + "tracing", + "tracing-actix-web", + "tracing-log", + "tracing-subscriber", +] + +[[package]] +name = "teepot-write" +version = "0.1.0" +dependencies = [ + "actix-web", + "anyhow", + "awc", + "clap", + "serde", + "serde_json", + "teepot", + "tracing", + "tracing-actix-web", + "tracing-log", + "tracing-subscriber", +] + +[[package]] +name = "terminal_size" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" +dependencies = [ + "rustix", + "windows-sys 0.48.0", +] + +[[package]] +name = "testaso" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b4d2149a2f578665ca39f8115084635847e9dd6921b5442dcafc7f87bb8e99" + +[[package]] +name = "thiserror" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "thread_local" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "time" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e" +dependencies = [ + "deranged", + "itoa", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26197e33420244aeb70c3e8c78376ca46571bc4e701e4791c2cd9f57dcb3a43f" +dependencies = [ + "time-core", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tls_codec" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38a1d5fcfa859f0ec2b5e111dc903890bd7dac7f34713232bf9aa4fd7cad7b2" +dependencies = [ + "tls_codec_derive", + "zeroize", +] + +[[package]] +name = "tls_codec_derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8e00e3e7a54e0f1c8834ce72ed49c8487fbd3f801d8cfe1a0ad0640382f8e15" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "tokio" +version = "1.35.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-macros" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "tokio-rustls" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" +dependencies = [ + "rustls", + "rustls-pki-types", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.1.0", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-actix-web" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fe0d5feac3f4ca21ba33496bcb1ccab58cca6412b1405ae80f0581541e0ca78" +dependencies = [ + "actix-web", + "mutually_exclusive_features", + "pin-project", + "tracing", + "uuid", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "twofish" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a78e83a30223c757c3947cd144a31014ff04298d8719ae10d03c31c0448c8013" +dependencies = [ + "cipher", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "uuid" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" +dependencies = [ + "getrandom", +] + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "vault-admin" +version = "0.1.0" +dependencies = [ + "actix-web", + "anyhow", + "awc", + "bytemuck", + "clap", + "hex", + "pgp", + "serde", + "serde_json", + "sha2", + "teepot", + "tracing", + "tracing-log", + "tracing-subscriber", +] + +[[package]] +name = "vault-unseal" +version = "0.1.0" +dependencies = [ + "actix-web", + "anyhow", + "awc", + "base64", + "clap", + "hex", + "serde", + "serde_json", + "sha2", + "teepot", + "tracing", + "tracing-log", + "tracing-subscriber", +] + +[[package]] +name = "verify-attestation" +version = "0.1.0" +dependencies = [ + "anyhow", + "hex", + "intel-tee-quote-verification-rs", + "teepot", +] + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.48", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" + +[[package]] +name = "webpki-roots" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de2cfda980f21be5a7ed2eadb3e6fe074d56022bea2cdeb1a62eb220fc04188" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + +[[package]] +name = "winnow" +version = "0.5.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7cf47b659b318dccbd69cc4797a39ae128f533dce7902a1096044d1967b9c16" +dependencies = [ + "memchr", +] + +[[package]] +name = "x25519-dalek" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb66477291e7e8d2b0ff1bcb900bf29489a9692816d79874bea351e7a8b6de96" +dependencies = [ + "curve25519-dalek", + "rand_core", + "serde", + "zeroize", +] + +[[package]] +name = "x509-cert" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1301e935010a701ae5f8655edc0ad17c44bad3ac5ce8c39185f75453b720ae94" +dependencies = [ + "const-oid", + "der", + "spki", + "tls_codec", +] + +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +dependencies = [ + "serde", + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "zstd" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bffb3309596d527cfcba7dfc6ed6052f1d39dfbd7c867aa2e865e4a449c10110" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43747c7422e2924c11144d5229878b98180ef8b06cca4ab5af37afc8a8d8ea3e" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.9+zstd.1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..4ce84db --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,111 @@ +[package] +name = "teepot" +description = "TEE secret manager" +# no MIT license, because of copied code from: +# * https://github.com/enarx/enarx +# * https://github.com/enarx/sgx +license = "Apache-2.0" +version.workspace = true +edition.workspace = true +authors.workspace = true +repository.workspace = true + +[dependencies] +actix-http.workspace = true +actix-web.workspace = true +anyhow.workspace = true +awc.workspace = true +bitflags.workspace = true +bytemuck.workspace = true +bytes.workspace = true +clap.workspace = true +const-oid.workspace = true +enumset.workspace = true +futures-core.workspace = true +getrandom.workspace = true +hex.workspace = true +intel-tee-quote-verification-rs.workspace = true +num-integer.workspace = true +num-traits.workspace = true +pgp.workspace = true +pkcs8.workspace = true +rand.workspace = true +ring.workspace = true +rsa.workspace = true +rustls.workspace = true +sec1.workspace = true +serde.workspace = true +serde_json.workspace = true +serde_with.workspace = true +sha2.workspace = true +thiserror.workspace = true +tracing.workspace = true +x509-cert.workspace = true +zeroize.workspace = true + +[dev-dependencies] +anyhow.workspace = true +base64.workspace = true +hex.workspace = true +testaso.workspace = true + +[workspace] +members = ["crates/*", "bin/*"] + +[workspace.package] +version = "0.1.0" +edition = "2021" +authors = ["Harald Hoyer "] +# rest of the workspace, if not specified in the package section +# has the standard Apache-2.0 OR MIT license +license = "Apache-2.0 OR MIT" +repository = "https://github.com/matter-labs/teepot" + +[workspace.dependencies] +actix-http = "3" +actix-tls = "3" +actix-web = { version = "4.5", features = ["rustls-0_22"] } +anyhow = "1.0.79" +awc = { version = "3.4", features = ["rustls-0_22-webpki-roots"] } +base64 = "0.21.7" +bindgen = "0.69.4" +bitflags = "2.4" +bytemuck = { version = "1.14.2", features = ["derive", "min_const_generics", "extern_crate_std"] } +bytes = "1" +clap = { version = "4.4", features = ["std", "derive", "env", "error-context", "help", "usage", "wrap_help"], default-features = false } +const-oid = { version = "0.9", default-features = false } +der = "0.7.8" +enumset = { version = "1.1", features = ["serde", "std"] } +futures-core = { version = "0.3.30", features = ["alloc"], default-features = false } +getrandom = "0.2.12" +hex = { version = "0.4.3", features = ["std"], default-features = false } +intel-tee-quote-verification-rs = { path = "crates/intel-tee-quote-verification-rs", version = "0.2.1" } +intel-tee-quote-verification-sys = { path = "crates/intel-tee-quote-verification-sys", version = "0.2.0" } +k256 = "0.13" +log = "0.4" +mio = "0.8.10" +num-integer = "0.1.46" +num-traits = "0.2.18" +pgp = "0.10" +pkcs8 = { version = "0.10" } +rand = "0.8" +ring = { version = "0.17.7", features = ["std"], default-features = false } +rsa = { version = "0.9.6", features = ["sha2"] } +rustls = { version = "0.22" } +rustls-pemfile = "1" +sec1 = { version = "0.7.3", features = ["der"], default-features = false } +serde = { version = "1", features = ["derive", "rc"] } +serde_json = "1" +serde_with = { version = "3.6", features = ["base64", "hex"] } +sha2 = "0.10.8" +teepot = { path = "." } +testaso = "0.1.0" +thiserror = "1.0.56" +tokio = { version = "1", features = ["sync", "macros", "rt-multi-thread", "fs", "time"] } +tracing = "0.1" +tracing-actix-web = "0.7" +tracing-log = "0.2" +tracing-subscriber = { version = "0.3", features = ["env-filter"] } +x509 = { version = "0.2", package = "x509-cert", default-features = false } +x509-cert = "0.2.5" +zeroize = { version = "1.7.0", features = ["serde"] } diff --git a/LICENSE-APACHE b/LICENSE-APACHE new file mode 100644 index 0000000..d9a10c0 --- /dev/null +++ b/LICENSE-APACHE @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 0000000..2739ea6 --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Matter Labs + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index e8f6922..69688cc 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,19 @@ # teepot Key Value store in a TEE with Remote Attestation for Authentication + +## Introduction + +This project is a key-value store that runs in a Trusted Execution Environment (TEE) and uses Remote Attestation for Authentication. +The key-value store is implemented using Hashicorp Vault running in an Intel SGX enclave via the Gramine runtime. + +## Parts of this project + +- `teepot`: The main rust crate that abstracts TEEs and key-value stores. +- `tee-vault-unseal`: An enclave that uses the Vault API to unseal a vault as a proxy. +- `vault-unseal`: A client utility, that talks to `tee-vault-unseal` to unseal a vault. +- `tee-vault-admin`: An enclave that uses the Vault API to administer a vault as a proxy. +- `vault-admin`: A client utility, that talks to `tee-vault-admin` to administer a vault. +- `teepot-read` : A pre-exec utility that reads from the key-value store and passes the key-value pairs as environment variables to the enclave. +- `teepot-write` : A pre-exec utility that reads key-values from the environment variables and writes them to the key-value store. +- `verify-attestation`: A client utility that verifies the attestation of an enclave. +- `tee-key-preexec`: A pre-exec utility that generates a p256 secret key and passes it as an environment variable to the enclave along with the attestation quote containing the hash of the public key. diff --git a/assets/Azure-DCAP-Client.patch b/assets/Azure-DCAP-Client.patch new file mode 100644 index 0000000..8763455 --- /dev/null +++ b/assets/Azure-DCAP-Client.patch @@ -0,0 +1,38 @@ +diff --git a/src/dcap_provider.cpp b/src/dcap_provider.cpp +index d23c250..34c4d9d 100644 +--- a/src/dcap_provider.cpp ++++ b/src/dcap_provider.cpp +@@ -1333,7 +1333,7 @@ static std::string build_tcb_info_url( + tcb_info_url << base_url; + } + else +- tcb_info_url << get_base_url(); ++ tcb_info_url << "https://api.trustedservices.intel.com/sgx/certification"; + + if (!version.empty()) + { +@@ -1426,7 +1426,7 @@ static std::string build_enclave_id_url( + qe_id_url << base_url; + } + else +- qe_id_url << get_base_url(); ++ qe_id_url << "https://api.trustedservices.intel.com/sgx/certification/"; + + // Select the correct issuer header name + if (!version.empty()) +@@ -1521,6 +1521,7 @@ static quote3_error_t get_collateral( + "Successfully fetched %s from URL: '%s'.", + friendly_name.c_str(), + url.c_str()); ++/* + std::string cache_control; + auto get_cache_header_operation = get_unescape_header(*curl_operation, headers::CACHE_CONTROL, &cache_control); + retval = convert_to_intel_error(get_cache_header_operation); +@@ -1534,6 +1535,7 @@ static quote3_error_t get_collateral( + local_cache_add(issuer_chain_cache_name, expiry, issuer_chain.size(), issuer_chain.c_str()); + } + } ++*/ + } + + return retval; diff --git a/assets/extract-sig.sh b/assets/extract-sig.sh new file mode 100644 index 0000000..b66e354 --- /dev/null +++ b/assets/extract-sig.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: Apache-2.0 +# +# This script is used to extract the signature of a gramine docker image. +# +# Usage: ./extract-sig.sh +# Example: ./extract-sig.sh tva tee-vault-admin + +id=$(docker create $1) +trap 'docker rm -v $id' EXIT +docker cp "$id:/app/$2.sig" "$3" diff --git a/assets/replace-sig.sh b/assets/replace-sig.sh new file mode 100644 index 0000000..8ef54bf --- /dev/null +++ b/assets/replace-sig.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: Apache-2.0 +# +# This script is used to replace the signature of a gramine docker image with a new one. +# +# Usage: ./replace-sig.sh +# Example: ./replace-sig.sh tva tee-vault-admin.sig /app/tee-vault-admin.sig + +DOCKERFILE="Dockerfile-tmp-$$" + +trap 'rm -f $DOCKERFILE' EXIT + +cat > "$DOCKERFILE" < Result<()> { + LogTracer::init().context("Failed to set logger")?; + + let subscriber = Registry::default() + .with(EnvFilter::from_default_env()) + .with(fmt::layer().with_writer(std::io::stderr)); + tracing::subscriber::set_global_default(subscriber).context("Failed to set logger")?; + + let args = env::args_os().collect::>(); + + if args.len() < 2 { + return Err(anyhow::anyhow!( + "Usage: {} [args...]", + args[0].to_string_lossy() + )); + } + + let mut rng = rand::thread_rng(); + let signing_key = SigningKey::random(&mut rng); + let verifying_key_bytes = signing_key.verifying_key().to_sec1_bytes(); + let hash_verifying_key = Sha256::digest(verifying_key_bytes); + let signing_key_string = signing_key.to_bytes().encode_hex::(); + let tee_type = match get_quote(&hash_verifying_key) { + Ok(quote) => { + // save quote to file + std::fs::write(TEE_QUOTE_FILE, quote)?; + "sgx" + } + Err(e) => { + error!("Failed to get quote: {}", e); + std::fs::write(TEE_QUOTE_FILE, [])?; + "none" + } + }; + + let err = Command::new(&args[1]) + .args(&args[2..]) + .env("TEE_SIGNING_KEY", signing_key_string) + .env("TEE_QUOTE_FILE", TEE_QUOTE_FILE) + .env("TEE_TYPE", tee_type) + .exec(); + + Err(err).with_context(|| format!("exec of `{cmd}` failed", cmd = args[1].to_string_lossy())) +} + +fn main() -> Result<()> { + let ret = main_with_error(); + if let Err(e) = &ret { + error!("Error: {}", e); + } + ret +} diff --git a/bin/tee-self-attestation-test/Cargo.toml b/bin/tee-self-attestation-test/Cargo.toml new file mode 100644 index 0000000..ef6fef9 --- /dev/null +++ b/bin/tee-self-attestation-test/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "tee-self-attestation-test" +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true +repository.workspace = true + +[dependencies] +actix-web.workspace = true +anyhow.workspace = true +teepot.workspace = true +tracing-log.workspace = true +tracing-subscriber.workspace = true +tracing.workspace = true diff --git a/bin/tee-self-attestation-test/Dockerfile-azure b/bin/tee-self-attestation-test/Dockerfile-azure new file mode 100644 index 0000000..73526cb --- /dev/null +++ b/bin/tee-self-attestation-test/Dockerfile-azure @@ -0,0 +1,85 @@ +FROM docker.io/ubuntu:20.04 AS azuredcap +WORKDIR /build +ADD https://github.com/microsoft/Azure-DCAP-Client/archive/refs/tags/1.12.0.tar.gz ./Azure-DCAP-Client.tar.gz +RUN tar -xvf Azure-DCAP-Client.tar.gz +COPY assets/Azure-DCAP-Client.patch ./Azure-DCAP-Client.patch +RUN set -eux; \ + apt-get update; \ + apt-get install -y software-properties-common; \ + add-apt-repository ppa:team-xbmc/ppa -y; \ + apt-get update; \ + apt-get install -y \ + build-essential \ + cmake \ + libssl-dev \ + libcurl4-openssl-dev \ + pkg-config \ + nlohmann-json3-dev \ + wget \ + dos2unix \ + ; + +WORKDIR /build/Azure-DCAP-Client-1.12.0 +RUN dos2unix src/dcap_provider.cpp && patch -p1 < ../Azure-DCAP-Client.patch +WORKDIR /build/Azure-DCAP-Client-1.12.0/src/Linux +RUN ./configure && make && make install + +FROM docker.io/rust:1-bullseye AS buildtee +RUN curl -fsSLo /usr/share/keyrings/intel.asc https://download.01.org/intel-sgx/sgx_repo/ubuntu/intel-sgx-deb.key \ + && echo "deb [arch=amd64 signed-by=/usr/share/keyrings/intel.asc] https://download.01.org/intel-sgx/sgx_repo/ubuntu focal main" > /etc/apt/sources.list.d/intel-sgx.list \ + && apt-get update \ + && apt-get install -y --no-install-recommends \ + build-essential \ + cmake \ + rsync \ + pkg-config \ + libssl-dev \ + libcurl4-openssl-dev \ + libprotobuf-dev \ + protobuf-compiler \ + clang \ + libsgx-headers \ + libsgx-dcap-quote-verify-dev + +WORKDIR /opt/vault/plugins + +WORKDIR /build +RUN --mount=type=bind,target=/data rsync --exclude='/.git' --filter="dir-merge,- .gitignore" --exclude "Dockerfile-*" --exclude 'tee-self-attestation-test.manifest.template.toml' -av /data/ ./ +RUN --mount=type=cache,target=/usr/local/cargo/registry --mount=type=cache,target=target \ + RUSTFLAGS="-C target-cpu=icelake-server --cfg mio_unsupported_force_waker_pipe" \ + cargo build --locked --target x86_64-unknown-linux-gnu --release -p tee-self-attestation-test --bin tee-self-attestation-test \ + && mv ./target/x86_64-unknown-linux-gnu/release/tee-self-attestation-test ./ + +FROM docker.io/gramineproject/gramine:v1.5 + +RUN curl -fsSLo /usr/share/keyrings/microsoft.asc https://packages.microsoft.com/keys/microsoft.asc \ + && echo "deb [arch=amd64 signed-by=/usr/share/keyrings/microsoft.asc] https://packages.microsoft.com/ubuntu/20.04/prod focal main" > /etc/apt/sources.list.d/msprod.list \ + && apt-get update \ + && apt purge -y libsgx-dcap-default-qpl \ + && apt-get install -y az-dcap-client + +RUN apt purge -y libsgx-ae-qve +# libsgx-urts + +RUN rm -rf /var/lib/apt/lists/* + +# So we only have to use one gramine template +RUN touch /etc/sgx_default_qcnl.conf + +WORKDIR /app + +COPY --from=buildtee /build/tee-self-attestation-test . +COPY ./bin/tee-self-attestation-test/tee-self-attestation-test.manifest.template.toml . +COPY vault/enclave-key.pem . + +# The original Azure library is still delivering expired collateral, so we have to use a patched version +COPY --from=azuredcap /usr/local/lib/libdcap_quoteprov.so /usr/lib/ + +RUN gramine-manifest -Darch_libdir=/lib/x86_64-linux-gnu -Dexecdir=/usr/bin -Dlog_level=warning tee-self-attestation-test.manifest.template.toml tee-self-attestation-test.manifest \ + && gramine-sgx-sign --manifest tee-self-attestation-test.manifest --output tee-self-attestation-test.manifest.sgx --key enclave-key.pem \ + && rm enclave-key.pem + +EXPOSE 8443 + +ENTRYPOINT ["/bin/sh", "-c"] +CMD [ "/restart_aesm.sh ; exec gramine-sgx tee-self-attestation-test" ] diff --git a/bin/tee-self-attestation-test/Dockerfile-intel b/bin/tee-self-attestation-test/Dockerfile-intel new file mode 100644 index 0000000..c30f99f --- /dev/null +++ b/bin/tee-self-attestation-test/Dockerfile-intel @@ -0,0 +1,58 @@ +FROM docker.io/rust:1-bullseye AS buildtee +RUN curl -fsSLo /usr/share/keyrings/intel.asc https://download.01.org/intel-sgx/sgx_repo/ubuntu/intel-sgx-deb.key \ + && echo "deb [arch=amd64 signed-by=/usr/share/keyrings/intel.asc] https://download.01.org/intel-sgx/sgx_repo/ubuntu focal main" > /etc/apt/sources.list.d/intel-sgx.list \ + && apt-get update \ + && apt-get install -y --no-install-recommends \ + build-essential \ + cmake \ + rsync \ + pkg-config \ + libssl-dev \ + libcurl4-openssl-dev \ + libprotobuf-dev \ + protobuf-compiler \ + clang \ + libsgx-headers \ + libsgx-dcap-quote-verify-dev + +WORKDIR /opt/vault/plugins + +WORKDIR /build +RUN --mount=type=bind,target=/data rsync --exclude='/.git' --filter="dir-merge,- .gitignore" --exclude "Dockerfile-*" --exclude 'tee-vault-admin.manifest.template' -av /data/ ./ +RUN --mount=type=cache,target=/usr/local/cargo/registry --mount=type=cache,target=target \ + RUSTFLAGS="-C target-cpu=icelake-server --cfg mio_unsupported_force_waker_pipe" \ + cargo build --locked --target x86_64-unknown-linux-gnu --release -p tee-self-attestation-test --bin tee-self-attestation-test \ + && mv ./target/x86_64-unknown-linux-gnu/release/tee-self-attestation-test ./ + +FROM docker.io/gramineproject/gramine:v1.5 + +RUN curl -fsSLo /usr/share/keyrings/intel.asc https://download.01.org/intel-sgx/sgx_repo/ubuntu/intel-sgx-deb.key \ + && echo "deb [arch=amd64 signed-by=/usr/share/keyrings/intel.asc] https://download.01.org/intel-sgx/sgx_repo/ubuntu focal main" > /etc/apt/sources.list.d/intel-sgx.list \ + && apt-get update \ + && apt-get install -y --no-install-recommends \ + libsgx-dcap-default-qpl \ + libsgx-urts \ + libsgx-enclave-common \ + libsgx-dcap-quote-verify +RUN apt purge -y libsgx-ae-qve +RUN rm -rf /var/lib/apt/lists/* + +# So we only have to use one gramine template +RUN touch /lib/libdcap_quoteprov.so + +WORKDIR /app + +COPY --from=buildtee /build/tee-self-attestation-test . +COPY ./bin/tee-self-attestation-test/tee-self-attestation-test.template.toml . +COPY vault/enclave-key.pem . + +COPY assets/sgx_default_qcnl.conf.json /etc/sgx_default_qcnl.conf + +RUN gramine-manifest -Darch_libdir=/lib/x86_64-linux-gnu -Dexecdir=/usr/bin -Dlog_level=warning tee-self-attestation-test.template.toml tee-self-attestation-test.manifest \ + && gramine-sgx-sign --manifest tee-self-attestation-test.manifest --output tee-self-attestation-test.manifest.sgx --key enclave-key.pem \ + && rm enclave-key.pem + +EXPOSE 8443 + +ENTRYPOINT ["/bin/sh", "-c"] +CMD [ "exec gramine-sgx tee-self-attestation-test" ] diff --git a/bin/tee-self-attestation-test/src/main.rs b/bin/tee-self-attestation-test/src/main.rs new file mode 100644 index 0000000..0d71c82 --- /dev/null +++ b/bin/tee-self-attestation-test/src/main.rs @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023 Matter Labs + +//! Simple TEE self-attestation test + +#![deny(missing_docs)] +#![deny(clippy::all)] + +use anyhow::{Context, Result}; +use teepot::server::attestation::get_quote_and_collateral; +use tracing::error; +use tracing_log::LogTracer; +use tracing_subscriber::{fmt, prelude::*, EnvFilter, Registry}; + +#[actix_web::main] +async fn main() -> Result<()> { + LogTracer::init().context("Failed to set logger")?; + + let subscriber = Registry::default() + .with(EnvFilter::from_default_env()) + .with(fmt::layer().with_writer(std::io::stderr)); + tracing::subscriber::set_global_default(subscriber).unwrap(); + + let report_data = [0u8; 64]; + if let Err(e) = get_quote_and_collateral(None, &report_data) { + error!("failed to get quote and collateral: {e:?}"); + return Err(e); + } + Ok(()) +} diff --git a/bin/tee-self-attestation-test/tee-self-attestation-test.template.toml b/bin/tee-self-attestation-test/tee-self-attestation-test.template.toml new file mode 100644 index 0000000..18590aa --- /dev/null +++ b/bin/tee-self-attestation-test/tee-self-attestation-test.template.toml @@ -0,0 +1,57 @@ +libos.entrypoint = "/app/tee-self-attestation-test" + +[loader] +argv = ["/app/tee-self-attestation-test"] +entrypoint = "file:{{ gramine.libos }}" +env.LD_LIBRARY_PATH = "/lib:{{ arch_libdir }}:/usr{{ arch_libdir }}:/lib" +env.HOME = "/app" +env.MALLOC_ARENA_MAX = "1" +env.AZDCAP_DEBUG_LOG_LEVEL = "ignore" +env.AZDCAP_COLLATERAL_VERSION = "v4" + +### DEBUG ### +env.RUST_BACKTRACE = "1" +env.RUST_LOG = "info" + +[fs] +root.uri = "file:/" +start_dir = "/app" +mounts = [ + { path = "{{ execdir }}", uri = "file:{{ execdir }}" }, + { path = "/lib", uri = "file:{{ gramine.runtimedir() }}" }, + { path = "{{ arch_libdir }}", uri = "file:{{ arch_libdir }}" }, + { path = "/etc", uri = "file:/etc" }, + { type = "tmpfs", path = "/var/tmp" }, + { type = "tmpfs", path = "/tmp" }, + { type = "tmpfs", path = "/app/.dcap-qcnl" }, + { type = "tmpfs", path = "/app/.az-dcap-client" }, + { path = "/lib/libdcap_quoteprov.so", uri = "file:/lib/libdcap_quoteprov.so" }, +] + +[sgx] +trusted_files = [ + "file:/etc/ld.so.cache", + "file:/app/", + "file:{{ execdir }}/", + "file:{{ arch_libdir }}/", + "file:/usr/{{ arch_libdir }}/", + "file:{{ gramine.libos }}", + "file:{{ gramine.runtimedir() }}/", + "file:/usr/lib/ssl/openssl.cnf", + "file:/etc/ssl/", + "file:/etc/sgx_default_qcnl.conf", + "file:/lib/libdcap_quoteprov.so", +] +remote_attestation = "dcap" +max_threads = 64 +edmm_enable = false +## max enclave size +enclave_size = "1G" + +[sys] +enable_extra_runtime_domain_names_conf = true +enable_sigterm_injection = true + +# possible tweak option, if problems with mio +# currently mio is compiled with `mio_unsupported_force_waker_pipe` +# insecure__allow_eventfd = true diff --git a/bin/tee-stress-client/Cargo.toml b/bin/tee-stress-client/Cargo.toml new file mode 100644 index 0000000..289ee92 --- /dev/null +++ b/bin/tee-stress-client/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "tee-stress-client" +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true +repository.workspace = true + +[dependencies] +actix-web.workspace = true +anyhow.workspace = true +awc.workspace = true +base64.workspace = true +bytemuck.workspace = true +clap.workspace = true +hex.workspace = true +mio.workspace = true +rustls.workspace = true +serde.workspace = true +serde_json.workspace = true +sha2.workspace = true +teepot.workspace = true +tracing-actix-web.workspace = true +tracing-log.workspace = true +tracing-subscriber.workspace = true +tracing.workspace = true diff --git a/bin/tee-stress-client/Dockerfile-azure b/bin/tee-stress-client/Dockerfile-azure new file mode 100644 index 0000000..56ac72e --- /dev/null +++ b/bin/tee-stress-client/Dockerfile-azure @@ -0,0 +1,85 @@ +FROM docker.io/ubuntu:20.04 AS azuredcap +WORKDIR /build +ADD https://github.com/microsoft/Azure-DCAP-Client/archive/refs/tags/1.12.0.tar.gz ./Azure-DCAP-Client.tar.gz +RUN tar -xvf Azure-DCAP-Client.tar.gz +COPY assets/Azure-DCAP-Client.patch ./Azure-DCAP-Client.patch +RUN set -eux; \ + apt-get update; \ + apt-get install -y software-properties-common; \ + add-apt-repository ppa:team-xbmc/ppa -y; \ + apt-get update; \ + apt-get install -y \ + build-essential \ + cmake \ + libssl-dev \ + libcurl4-openssl-dev \ + pkg-config \ + nlohmann-json3-dev \ + wget \ + dos2unix \ + ; + +WORKDIR /build/Azure-DCAP-Client-1.12.0 +RUN dos2unix src/dcap_provider.cpp && patch -p1 < ../Azure-DCAP-Client.patch +WORKDIR /build/Azure-DCAP-Client-1.12.0/src/Linux +RUN ./configure && make && make install + +FROM docker.io/rust:1-bullseye AS buildtee +RUN curl -fsSLo /usr/share/keyrings/intel.asc https://download.01.org/intel-sgx/sgx_repo/ubuntu/intel-sgx-deb.key \ + && echo "deb [arch=amd64 signed-by=/usr/share/keyrings/intel.asc] https://download.01.org/intel-sgx/sgx_repo/ubuntu focal main" > /etc/apt/sources.list.d/intel-sgx.list \ + && apt-get update \ + && apt-get install -y --no-install-recommends \ + build-essential \ + cmake \ + rsync \ + pkg-config \ + libssl-dev \ + libcurl4-openssl-dev \ + libprotobuf-dev \ + protobuf-compiler \ + clang \ + libsgx-headers \ + libsgx-dcap-quote-verify-dev + +WORKDIR /opt/vault/plugins + +WORKDIR /build +RUN --mount=type=bind,target=/data rsync --exclude='/.git' --filter="dir-merge,- .gitignore" --exclude "Dockerfile-*" --exclude 'tee-stress-client.manifest.template' -av /data/ ./ +RUN --mount=type=cache,target=/usr/local/cargo/registry --mount=type=cache,target=target \ + RUSTFLAGS="-C target-cpu=icelake-server --cfg mio_unsupported_force_waker_pipe" \ + cargo build --locked --target x86_64-unknown-linux-gnu --release -p tee-stress-client --bin tee-stress-client \ + && mv ./target/x86_64-unknown-linux-gnu/release/tee-stress-client ./ + +FROM docker.io/gramineproject/gramine:v1.5 + +RUN curl -fsSLo /usr/share/keyrings/microsoft.asc https://packages.microsoft.com/keys/microsoft.asc \ + && echo "deb [arch=amd64 signed-by=/usr/share/keyrings/microsoft.asc] https://packages.microsoft.com/ubuntu/20.04/prod focal main" > /etc/apt/sources.list.d/msprod.list \ + && apt-get update \ + && apt purge -y libsgx-dcap-default-qpl \ + && apt-get install -y az-dcap-client + +RUN apt purge -y libsgx-ae-qve +# libsgx-urts + +RUN rm -rf /var/lib/apt/lists/* + +# So we only have to use one gramine template +RUN touch /etc/sgx_default_qcnl.conf + +WORKDIR /app + +COPY --from=buildtee /build/tee-stress-client . +COPY ./bin/tee-stress-client/tee-stress-client.manifest.template . +COPY vault/enclave-key.pem . + +# The original Azure library is still delivering expired collateral, so we have to use a patched version +COPY --from=azuredcap /usr/local/lib/libdcap_quoteprov.so /usr/lib/ + +RUN gramine-manifest -Darch_libdir=/lib/x86_64-linux-gnu -Dexecdir=/usr/bin -Dlog_level=warning tee-stress-client.manifest.template tee-stress-client.manifest \ + && gramine-sgx-sign --manifest tee-stress-client.manifest --output tee-stress-client.manifest.sgx --key enclave-key.pem \ + && rm enclave-key.pem + +EXPOSE 8443 + +ENTRYPOINT ["/bin/sh", "-c"] +CMD [ "/restart_aesm.sh ; exec gramine-sgx tee-stress-client" ] diff --git a/bin/tee-stress-client/Dockerfile-intel b/bin/tee-stress-client/Dockerfile-intel new file mode 100644 index 0000000..4f84bc3 --- /dev/null +++ b/bin/tee-stress-client/Dockerfile-intel @@ -0,0 +1,58 @@ +FROM docker.io/rust:1-bullseye AS buildtee +RUN curl -fsSLo /usr/share/keyrings/intel.asc https://download.01.org/intel-sgx/sgx_repo/ubuntu/intel-sgx-deb.key \ + && echo "deb [arch=amd64 signed-by=/usr/share/keyrings/intel.asc] https://download.01.org/intel-sgx/sgx_repo/ubuntu focal main" > /etc/apt/sources.list.d/intel-sgx.list \ + && apt-get update \ + && apt-get install -y --no-install-recommends \ + build-essential \ + cmake \ + rsync \ + pkg-config \ + libssl-dev \ + libcurl4-openssl-dev \ + libprotobuf-dev \ + protobuf-compiler \ + clang \ + libsgx-headers \ + libsgx-dcap-quote-verify-dev + +WORKDIR /opt/vault/plugins + +WORKDIR /build +RUN --mount=type=bind,target=/data rsync --exclude='/.git' --filter="dir-merge,- .gitignore" --exclude "Dockerfile-*" --exclude 'tee-stress-client.manifest.template' -av /data/ ./ +RUN --mount=type=cache,target=/usr/local/cargo/registry --mount=type=cache,target=target \ + RUSTFLAGS="-C target-cpu=icelake-server --cfg mio_unsupported_force_waker_pipe" \ + cargo build --locked --target x86_64-unknown-linux-gnu --release -p tee-stress-client --bin tee-stress-client \ + && mv ./target/x86_64-unknown-linux-gnu/release/tee-stress-client ./ + +FROM docker.io/gramineproject/gramine:v1.5 + +RUN curl -fsSLo /usr/share/keyrings/intel.asc https://download.01.org/intel-sgx/sgx_repo/ubuntu/intel-sgx-deb.key \ + && echo "deb [arch=amd64 signed-by=/usr/share/keyrings/intel.asc] https://download.01.org/intel-sgx/sgx_repo/ubuntu focal main" > /etc/apt/sources.list.d/intel-sgx.list \ + && apt-get update \ + && apt-get install -y --no-install-recommends \ + libsgx-dcap-default-qpl \ + libsgx-urts \ + libsgx-enclave-common \ + libsgx-dcap-quote-verify +RUN apt purge -y libsgx-ae-qve +RUN rm -rf /var/lib/apt/lists/* + +# So we only have to use one gramine template +RUN touch /lib/libdcap_quoteprov.so + +WORKDIR /app + +COPY --from=buildtee /build/tee-stress-client . +COPY ./bin/tee-stress-client/tee-stress-client.manifest.template . +COPY vault/enclave-key.pem . + +COPY assets/sgx_default_qcnl.conf.json /etc/sgx_default_qcnl.conf + +RUN gramine-manifest -Darch_libdir=/lib/x86_64-linux-gnu -Dexecdir=/usr/bin -Dlog_level=warning tee-stress-client.manifest.template tee-stress-client.manifest \ + && gramine-sgx-sign --manifest tee-stress-client.manifest --output tee-stress-client.manifest.sgx --key enclave-key.pem \ + && rm enclave-key.pem + +EXPOSE 8443 + +ENTRYPOINT ["/bin/sh", "-c"] +CMD [ "/restart_aesm.sh ; exec gramine-sgx tee-stress-client" ] diff --git a/bin/tee-stress-client/src/main.rs b/bin/tee-stress-client/src/main.rs new file mode 100644 index 0000000..e4a4e10 --- /dev/null +++ b/bin/tee-stress-client/src/main.rs @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: Apache-2.0 + +//! Server to handle requests to the Vault TEE + +#![deny(missing_docs)] +#![deny(clippy::all)] + +use actix_web::rt::time::sleep; +use anyhow::{Context, Result}; +use clap::Parser; +use serde::{Deserialize, Serialize}; +use std::time::Duration; +use teepot::client::vault::VaultConnection; +use teepot::server::attestation::{get_quote_and_collateral, VaultAttestationArgs}; +use teepot::server::pki::make_self_signed_cert; +use teepot::sgx::{parse_tcb_levels, EnumSet, TcbLevel}; +use tracing::{error, trace}; +use tracing_log::LogTracer; +use tracing_subscriber::Registry; +use tracing_subscriber::{fmt, prelude::*, EnvFilter}; + +#[derive(Parser, Debug)] +#[command(author, version, about, long_about = None)] +struct Arguments { + /// allowed TCB levels, comma separated + #[arg(long, value_parser = parse_tcb_levels, env = "ALLOWED_TCB_LEVELS", default_value = "Ok")] + my_sgx_allowed_tcb_levels: EnumSet, + #[clap(flatten)] + pub attestation: VaultAttestationArgs, +} + +#[derive(Debug, Serialize, Deserialize)] +struct MySecret { + val: usize, +} + +#[actix_web::main] +async fn main() -> Result<()> { + LogTracer::init().context("Failed to set logger")?; + + let subscriber = Registry::default() + .with(EnvFilter::from_default_env()) + .with(fmt::layer().with_writer(std::io::stderr)); + tracing::subscriber::set_global_default(subscriber).unwrap(); + + let args = Arguments::parse(); + + let (report_data, _cert_chain, _priv_key) = make_self_signed_cert()?; + if let Err(e) = get_quote_and_collateral(Some(args.my_sgx_allowed_tcb_levels), &report_data) { + error!("failed to get quote and collateral: {e:?}"); + // don't return for now, we can still serve requests but we won't be able to attest + } + + let mut vault_1 = args.attestation.clone(); + let mut vault_2 = args.attestation.clone(); + let mut vault_3 = args.attestation.clone(); + + vault_1.vault_addr = "https://vault-1:8210".to_string(); + vault_2.vault_addr = "https://vault-2:8210".to_string(); + vault_3.vault_addr = "https://vault-3:8210".to_string(); + + let servers = vec![vault_1.clone(), vault_2.clone(), vault_3.clone()]; + + let mut val: usize = 1; + + loop { + let mut conns = Vec::new(); + for server in &servers { + match VaultConnection::new(&server.into(), "stress".to_string()).await { + Ok(conn) => conns.push(conn), + Err(e) => { + error!("connecting to {}: {}", server.vault_addr, e); + continue; + } + } + } + + if conns.is_empty() { + error!("no connections"); + sleep(Duration::from_secs(1)).await; + continue; + } + + let i = val % conns.len(); + trace!("storing secret"); + conns[i] + .store_secret(MySecret { val }, "val") + .await + .context("storing secret")?; + for conn in conns { + let got: MySecret = conn + .load_secret("val") + .await + .context("loading secret")? + .context("loading secret")?; + assert_eq!(got.val, val,); + } + val += 1; + sleep(Duration::from_secs(1)).await; + } +} diff --git a/bin/tee-stress-client/tee-stress-client.manifest.template b/bin/tee-stress-client/tee-stress-client.manifest.template new file mode 100644 index 0000000..a293e00 --- /dev/null +++ b/bin/tee-stress-client/tee-stress-client.manifest.template @@ -0,0 +1,66 @@ +libos.entrypoint = "/app/tee-stress-client" + +[loader] +argv = [ "/app/tee-stress-client" ] +entrypoint = "file:{{ gramine.libos }}" +env.LD_LIBRARY_PATH = "/lib:{{ arch_libdir }}:/usr{{ arch_libdir }}:/lib" +env.HOME = "/app" +env.MALLOC_ARENA_MAX = "1" +env.AZDCAP_DEBUG_LOG_LEVEL = "ignore" +env.AZDCAP_COLLATERAL_VERSION = "v4" + +### Admin Config ### +env.PORT = { passthrough = true } + +### VAULT attestation ### +env.VAULT_ADDR = { passthrough = true } +env.VAULT_SGX_MRENCLAVE = { passthrough = true } +env.VAULT_SGX_MRSIGNER = { passthrough = true } +env.VAULT_SGX_ALLOWED_TCB_LEVELS = { passthrough = true } + +### DEBUG ### +env.RUST_BACKTRACE = "1" +env.RUST_LOG="info" + +[fs] +root.uri = "file:/" +start_dir = "/app" +mounts = [ + { path = "{{ execdir }}", uri = "file:{{ execdir }}" }, + { path = "/lib", uri = "file:{{ gramine.runtimedir() }}" }, + { path = "{{ arch_libdir }}", uri = "file:{{ arch_libdir }}" }, + { path = "/etc", uri = "file:/etc" }, + { type = "tmpfs", path = "/var/tmp" }, + { type = "tmpfs", path = "/tmp" }, + { type = "tmpfs", path = "/app/.dcap-qcnl" }, + { type = "tmpfs", path = "/app/.az-dcap-client" }, + { path = "/lib/libdcap_quoteprov.so", uri = "file:/lib/libdcap_quoteprov.so" }, +] + +[sgx] +trusted_files = [ + "file:/etc/ld.so.cache", + "file:/app/", + "file:{{ execdir }}/", + "file:{{ arch_libdir }}/", + "file:/usr/{{ arch_libdir }}/", + "file:{{ gramine.libos }}", + "file:{{ gramine.runtimedir() }}/", + "file:/usr/lib/ssl/openssl.cnf", + "file:/etc/ssl/", + "file:/etc/sgx_default_qcnl.conf", + "file:/lib/libdcap_quoteprov.so", +] +remote_attestation = "dcap" +max_threads = 64 +edmm_enable = false +## max enclave size +enclave_size = "8G" + +[sys] +enable_extra_runtime_domain_names_conf = true +enable_sigterm_injection = true + +# possible tweak option, if problems with mio +# currently mio is compiled with `mio_unsupported_force_waker_pipe` +# insecure__allow_eventfd = true diff --git a/bin/tee-vault-admin/Cargo.toml b/bin/tee-vault-admin/Cargo.toml new file mode 100644 index 0000000..4f1223b --- /dev/null +++ b/bin/tee-vault-admin/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "tee-vault-admin" +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true +repository.workspace = true + +[dependencies] +actix-web.workspace = true +anyhow.workspace = true +awc.workspace = true +base64.workspace = true +bytemuck.workspace = true +clap.workspace = true +hex.workspace = true +mio.workspace = true +rustls.workspace = true +serde.workspace = true +serde_json.workspace = true +sha2.workspace = true +teepot.workspace = true +tracing-actix-web.workspace = true +tracing-log.workspace = true +tracing-subscriber.workspace = true +tracing.workspace = true diff --git a/bin/tee-vault-admin/Dockerfile-azure b/bin/tee-vault-admin/Dockerfile-azure new file mode 100644 index 0000000..ca3fce7 --- /dev/null +++ b/bin/tee-vault-admin/Dockerfile-azure @@ -0,0 +1,85 @@ +FROM docker.io/ubuntu:20.04 AS azuredcap +WORKDIR /build +ADD https://github.com/microsoft/Azure-DCAP-Client/archive/refs/tags/1.12.0.tar.gz ./Azure-DCAP-Client.tar.gz +RUN tar -xvf Azure-DCAP-Client.tar.gz +COPY assets/Azure-DCAP-Client.patch ./Azure-DCAP-Client.patch +RUN set -eux; \ + apt-get update; \ + apt-get install -y software-properties-common; \ + add-apt-repository ppa:team-xbmc/ppa -y; \ + apt-get update; \ + apt-get install -y \ + build-essential \ + cmake \ + libssl-dev \ + libcurl4-openssl-dev \ + pkg-config \ + nlohmann-json3-dev \ + wget \ + dos2unix \ + ; + +WORKDIR /build/Azure-DCAP-Client-1.12.0 +RUN dos2unix src/dcap_provider.cpp && patch -p1 < ../Azure-DCAP-Client.patch +WORKDIR /build/Azure-DCAP-Client-1.12.0/src/Linux +RUN ./configure && make && make install + +FROM docker.io/rust:1-bullseye AS buildtee +RUN curl -fsSLo /usr/share/keyrings/intel.asc https://download.01.org/intel-sgx/sgx_repo/ubuntu/intel-sgx-deb.key \ + && echo "deb [arch=amd64 signed-by=/usr/share/keyrings/intel.asc] https://download.01.org/intel-sgx/sgx_repo/ubuntu focal main" > /etc/apt/sources.list.d/intel-sgx.list \ + && apt-get update \ + && apt-get install -y --no-install-recommends \ + build-essential \ + cmake \ + rsync \ + pkg-config \ + libssl-dev \ + libcurl4-openssl-dev \ + libprotobuf-dev \ + protobuf-compiler \ + clang \ + libsgx-headers \ + libsgx-dcap-quote-verify-dev + +WORKDIR /opt/vault/plugins + +WORKDIR /build +RUN --mount=type=bind,target=/data rsync --exclude='/.git' --filter="dir-merge,- .gitignore" --exclude "Dockerfile-*" --exclude 'tee-vault-admin.manifest.template' -av /data/ ./ +RUN --mount=type=cache,target=/usr/local/cargo/registry --mount=type=cache,target=target \ + RUSTFLAGS="-C target-cpu=icelake-server --cfg mio_unsupported_force_waker_pipe" \ + cargo build --locked --target x86_64-unknown-linux-gnu --release -p tee-vault-admin --bin tee-vault-admin \ + && mv ./target/x86_64-unknown-linux-gnu/release/tee-vault-admin ./ + +FROM docker.io/gramineproject/gramine:v1.5 + +RUN curl -fsSLo /usr/share/keyrings/microsoft.asc https://packages.microsoft.com/keys/microsoft.asc \ + && echo "deb [arch=amd64 signed-by=/usr/share/keyrings/microsoft.asc] https://packages.microsoft.com/ubuntu/20.04/prod focal main" > /etc/apt/sources.list.d/msprod.list \ + && apt-get update \ + && apt purge -y libsgx-dcap-default-qpl \ + && apt-get install -y az-dcap-client + +RUN apt purge -y libsgx-ae-qve +# libsgx-urts + +RUN rm -rf /var/lib/apt/lists/* + +# So we only have to use one gramine template +RUN touch /etc/sgx_default_qcnl.conf + +WORKDIR /app + +COPY --from=buildtee /build/tee-vault-admin . +COPY ./bin/tee-vault-admin/tee-vault-admin.manifest.template . +COPY vault/enclave-key.pem . + +# The original Azure library is still delivering expired collateral, so we have to use a patched version +COPY --from=azuredcap /usr/local/lib/libdcap_quoteprov.so /usr/lib/ + +RUN gramine-manifest -Darch_libdir=/lib/x86_64-linux-gnu -Dexecdir=/usr/bin -Dlog_level=warning tee-vault-admin.manifest.template tee-vault-admin.manifest \ + && gramine-sgx-sign --manifest tee-vault-admin.manifest --output tee-vault-admin.manifest.sgx --key enclave-key.pem \ + && rm enclave-key.pem + +EXPOSE 8443 + +ENTRYPOINT ["/bin/sh", "-c"] +CMD [ "/restart_aesm.sh ; exec gramine-sgx tee-vault-admin" ] diff --git a/bin/tee-vault-admin/Dockerfile-intel b/bin/tee-vault-admin/Dockerfile-intel new file mode 100644 index 0000000..6e8d21e --- /dev/null +++ b/bin/tee-vault-admin/Dockerfile-intel @@ -0,0 +1,58 @@ +FROM docker.io/rust:1-bullseye AS buildtee +RUN curl -fsSLo /usr/share/keyrings/intel.asc https://download.01.org/intel-sgx/sgx_repo/ubuntu/intel-sgx-deb.key \ + && echo "deb [arch=amd64 signed-by=/usr/share/keyrings/intel.asc] https://download.01.org/intel-sgx/sgx_repo/ubuntu focal main" > /etc/apt/sources.list.d/intel-sgx.list \ + && apt-get update \ + && apt-get install -y --no-install-recommends \ + build-essential \ + cmake \ + rsync \ + pkg-config \ + libssl-dev \ + libcurl4-openssl-dev \ + libprotobuf-dev \ + protobuf-compiler \ + clang \ + libsgx-headers \ + libsgx-dcap-quote-verify-dev + +WORKDIR /opt/vault/plugins + +WORKDIR /build +RUN --mount=type=bind,target=/data rsync --exclude='/.git' --filter="dir-merge,- .gitignore" --exclude "Dockerfile-*" --exclude 'tee-vault-admin.manifest.template' -av /data/ ./ +RUN --mount=type=cache,target=/usr/local/cargo/registry --mount=type=cache,target=target \ + RUSTFLAGS="-C target-cpu=icelake-server --cfg mio_unsupported_force_waker_pipe" \ + cargo build --locked --target x86_64-unknown-linux-gnu --release -p tee-vault-admin --bin tee-vault-admin \ + && mv ./target/x86_64-unknown-linux-gnu/release/tee-vault-admin ./ + +FROM docker.io/gramineproject/gramine:v1.5 + +RUN curl -fsSLo /usr/share/keyrings/intel.asc https://download.01.org/intel-sgx/sgx_repo/ubuntu/intel-sgx-deb.key \ + && echo "deb [arch=amd64 signed-by=/usr/share/keyrings/intel.asc] https://download.01.org/intel-sgx/sgx_repo/ubuntu focal main" > /etc/apt/sources.list.d/intel-sgx.list \ + && apt-get update \ + && apt-get install -y --no-install-recommends \ + libsgx-dcap-default-qpl \ + libsgx-urts \ + libsgx-enclave-common \ + libsgx-dcap-quote-verify +RUN apt purge -y libsgx-ae-qve +RUN rm -rf /var/lib/apt/lists/* + +# So we only have to use one gramine template +RUN touch /lib/libdcap_quoteprov.so + +WORKDIR /app + +COPY --from=buildtee /build/tee-vault-admin . +COPY ./bin/tee-vault-admin/tee-vault-admin.manifest.template . +COPY vault/enclave-key.pem . + +COPY assets/sgx_default_qcnl.conf.json /etc/sgx_default_qcnl.conf + +RUN gramine-manifest -Darch_libdir=/lib/x86_64-linux-gnu -Dexecdir=/usr/bin -Dlog_level=warning tee-vault-admin.manifest.template tee-vault-admin.manifest \ + && gramine-sgx-sign --manifest tee-vault-admin.manifest --output tee-vault-admin.manifest.sgx --key enclave-key.pem \ + && rm enclave-key.pem + +EXPOSE 8443 + +ENTRYPOINT ["/bin/sh", "-c"] +CMD [ "/restart_aesm.sh ; exec gramine-sgx tee-vault-admin" ] diff --git a/bin/tee-vault-admin/src/attestation.rs b/bin/tee-vault-admin/src/attestation.rs new file mode 100644 index 0000000..66f410a --- /dev/null +++ b/bin/tee-vault-admin/src/attestation.rs @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023 Matter Labs + +//! attestation + +use crate::ServerState; +use actix_web::http::StatusCode; +use actix_web::web::{Data, Json}; +use anyhow::{Context, Result}; +use std::sync::Arc; +use teepot::json::http::AttestationResponse; +use teepot::server::attestation::get_quote_and_collateral; +use teepot::server::{HttpResponseError, Status}; +use tracing::instrument; + +/// Get attestation +#[instrument(level = "info", name = "/v1/sys/attestation", skip_all)] +pub async fn get_attestation( + worker: Data>, +) -> Result, HttpResponseError> { + get_quote_and_collateral(None, &worker.report_data) + .context("Error getting attestation") + .map(Json) + .status(StatusCode::INTERNAL_SERVER_ERROR) +} diff --git a/bin/tee-vault-admin/src/command.rs b/bin/tee-vault-admin/src/command.rs new file mode 100644 index 0000000..b39c05a --- /dev/null +++ b/bin/tee-vault-admin/src/command.rs @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023 Matter Labs + +//! post commands + +use crate::ServerState; +use actix_web::web; +use anyhow::{anyhow, Context, Result}; +use awc::http::StatusCode; +use sha2::{Digest, Sha256}; +use std::sync::Arc; +use teepot::client::vault::VaultConnection; +use teepot::json::http::{ + VaultCommandRequest, VaultCommandResponse, VaultCommands, VaultCommandsResponse, +}; +use teepot::json::secrets::{AdminConfig, AdminState}; +use teepot::server::{signatures::VerifySig, HttpResponseError, Status}; +use tracing::instrument; + +/// Post command +#[instrument(level = "info", name = "/v1/command", skip_all)] +pub async fn post_command( + state: web::Data>, + item: web::Json, +) -> Result, HttpResponseError> { + let conn = VaultConnection::new(&state.vault_attestation.clone().into(), "admin".to_string()) + .await + .context("connecting to vault") + .status(StatusCode::BAD_GATEWAY)?; + + let mut admin_state: AdminState = conn + .load_secret("state") + .await? + .context("empty admin state") + .status(StatusCode::BAD_GATEWAY)?; + + let commands: VaultCommands = serde_json::from_str(&item.commands) + .context("parsing commands") + .status(StatusCode::BAD_REQUEST)?; + + if admin_state.last_digest.to_ascii_lowercase() != commands.last_digest { + return Err(anyhow!( + "last digest does not match {} != {}", + admin_state.last_digest.to_ascii_lowercase(), + commands.last_digest + )) + .status(StatusCode::BAD_REQUEST); + } + + let admin_config: AdminConfig = conn + .load_secret("config") + .await? + .context("empty admin config") + .status(StatusCode::BAD_GATEWAY)?; + admin_config.check_sigs(&item.signatures, item.commands.as_bytes())?; + + let mut hasher = Sha256::new(); + hasher.update(item.commands.as_bytes()); + let hash = hasher.finalize(); + let digest = hex::encode(hash); + admin_state.last_digest = digest.clone(); + conn.store_secret(admin_state, "state").await?; + + let mut responds = VaultCommandsResponse { + digest, + results: vec![], + }; + + for (pos, command) in commands.commands.iter().enumerate() { + let resp = conn + .vault_put( + &format!("Executing command {pos}"), + &command.url, + &command.data, + ) + .await?; + + let vcr = VaultCommandResponse { + status_code: resp.0.as_u16(), + value: resp.1, + }; + + responds.results.push(vcr); + } + + let _ = conn.revoke_token().await; + + Ok(web::Json(responds)) +} diff --git a/bin/tee-vault-admin/src/digest.rs b/bin/tee-vault-admin/src/digest.rs new file mode 100644 index 0000000..bd87b02 --- /dev/null +++ b/bin/tee-vault-admin/src/digest.rs @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023 Matter Labs + +//! digest + +use crate::ServerState; +use actix_web::{web, HttpResponse}; +use anyhow::{Context, Result}; +use awc::http::StatusCode; +use serde_json::json; +use std::sync::Arc; +use teepot::client::vault::VaultConnection; +use teepot::json::secrets::AdminState; +use teepot::server::{HttpResponseError, Status}; +use tracing::instrument; + +/// Get last digest +#[instrument(level = "info", name = "/v1/digest", skip_all)] +pub async fn get_digest( + state: web::Data>, +) -> Result { + let conn = VaultConnection::new(&state.vault_attestation.clone().into(), "admin".to_string()) + .await + .context("connecting to vault") + .status(StatusCode::BAD_GATEWAY)?; + + let admin_state: AdminState = conn + .load_secret("state") + .await? + .context("empty admin state") + .status(StatusCode::BAD_GATEWAY)?; + + Ok(HttpResponse::Ok().json(json!({"last_digest": admin_state.last_digest }))) +} diff --git a/bin/tee-vault-admin/src/main.rs b/bin/tee-vault-admin/src/main.rs new file mode 100644 index 0000000..7a1e35f --- /dev/null +++ b/bin/tee-vault-admin/src/main.rs @@ -0,0 +1,148 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023 Matter Labs + +//! Server to handle requests to the Vault TEE + +#![deny(missing_docs)] +#![deny(clippy::all)] + +mod attestation; +mod command; +mod digest; +mod sign; + +use actix_web::web::Data; +use actix_web::{web, App, HttpServer}; +use anyhow::{Context, Result}; +use attestation::get_attestation; +use clap::Parser; +use command::post_command; +use digest::get_digest; +use rustls::ServerConfig; +use sign::post_sign; +use std::net::Ipv6Addr; +use std::sync::Arc; +use teepot::json::http::{SignRequest, VaultCommandRequest, ATTESTATION_URL, DIGEST_URL}; +use teepot::server::attestation::{get_quote_and_collateral, VaultAttestationArgs}; +use teepot::server::new_json_cfg; +use teepot::server::pki::make_self_signed_cert; +use teepot::sgx::{parse_tcb_levels, EnumSet, TcbLevel}; +use tracing::{error, info}; +use tracing_actix_web::TracingLogger; +use tracing_log::LogTracer; +use tracing_subscriber::Registry; +use tracing_subscriber::{fmt, prelude::*, EnvFilter}; + +/// Server state +pub struct ServerState { + /// Server TLS public key hash + pub report_data: [u8; 64], + /// Vault attestation args + pub vault_attestation: VaultAttestationArgs, +} + +#[derive(Parser, Debug)] +#[command(author, version, about, long_about = None)] +struct Arguments { + /// allowed TCB levels, comma separated + #[arg(long, value_parser = parse_tcb_levels, env = "ALLOWED_TCB_LEVELS", default_value = "Ok")] + server_sgx_allowed_tcb_levels: EnumSet, + /// port to listen on + #[arg(long, env = "PORT", default_value = "8444")] + port: u16, + #[clap(flatten)] + pub attestation: VaultAttestationArgs, +} + +#[actix_web::main] +async fn main() -> Result<()> { + LogTracer::init().context("Failed to set logger")?; + + let subscriber = Registry::default() + .with(EnvFilter::from_default_env()) + .with(fmt::layer().with_writer(std::io::stderr)); + tracing::subscriber::set_global_default(subscriber).unwrap(); + + let args = Arguments::parse(); + + let (report_data, cert_chain, priv_key) = make_self_signed_cert()?; + + if let Err(e) = get_quote_and_collateral(Some(args.server_sgx_allowed_tcb_levels), &report_data) + { + error!("failed to get quote and collateral: {e:?}"); + // don't return for now, we can still serve requests but we won't be able to attest + } + + // init server config builder with safe defaults + let config = ServerConfig::builder() + .with_no_client_auth() + .with_single_cert([cert_chain].into(), priv_key) + .context("Failed to load TLS key/cert files")?; + + info!("Starting HTTPS server at port {}", args.port); + + info!("Quote verified! Connection secure!"); + + let server_state = Arc::new(ServerState { + report_data, + vault_attestation: args.attestation, + }); + + let server = match HttpServer::new(move || { + App::new() + // enable logger + .wrap(TracingLogger::default()) + .app_data(new_json_cfg()) + .app_data(Data::new(server_state.clone())) + .service(web::resource(ATTESTATION_URL).route(web::get().to(get_attestation))) + .service(web::resource(VaultCommandRequest::URL).route(web::post().to(post_command))) + .service(web::resource(SignRequest::URL).route(web::post().to(post_sign))) + .service(web::resource(DIGEST_URL).route(web::get().to(get_digest))) + }) + .bind_rustls_0_22((Ipv6Addr::UNSPECIFIED, args.port), config) + { + Ok(c) => c, + Err(e) => { + error!("Failed to bind to port {}: {e:?}", args.port); + return Err(e).context(format!("Failed to bind to port {}", args.port)); + } + }; + + if let Err(e) = server.worker_max_blocking_threads(2).workers(8).run().await { + error!("failed to start HTTPS server: {e:?}"); + return Err(e).context("Failed to start HTTPS server"); + } + + Ok(()) +} + +#[cfg(test)] +mod tests { + use serde_json::json; + use teepot::json::http::{VaultCommand, VaultCommands}; + + const TEST_DATA: &str = include_str!("../../../tests/data/test.json"); + + #[test] + fn test_vault_commands() { + let cmd = VaultCommand { + url: "/v1/auth/tee/tees/test".to_string(), + data: json!({ + "lease": "1000", + "name": "test", + "types": "sgx", + "sgx_allowed_tcb_levels": "Ok,SwHardeningNeeded", + "sgx_mrsigner": "c5591a72b8b86e0d8814d6e8750e3efe66aea2d102b8ba2405365559b858697d", + "token_policies": "test" + }), + }; + let cmds = VaultCommands { + commands: vec![cmd], + last_digest: "".into(), + }; + + let test_data_cmds: VaultCommands = serde_json::from_str(TEST_DATA).unwrap(); + + assert_eq!(cmds, test_data_cmds); + } +} diff --git a/bin/tee-vault-admin/src/sign.rs b/bin/tee-vault-admin/src/sign.rs new file mode 100644 index 0000000..eece999 --- /dev/null +++ b/bin/tee-vault-admin/src/sign.rs @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023 Matter Labs + +//! post signing request + +use crate::ServerState; +use actix_web::http::StatusCode; +use actix_web::web; +use anyhow::{anyhow, Context, Result}; +use sha2::{Digest, Sha256}; +use std::sync::Arc; +use teepot::client::vault::VaultConnection; +use teepot::json::http::{SignRequest, SignRequestData, SignResponse}; +use teepot::json::secrets::{AdminConfig, AdminState, SGXSigningKey}; +use teepot::server::signatures::VerifySig as _; +use teepot::server::{HttpResponseError, Status}; +use teepot::sgx::sign::PrivateKey as _; +use teepot::sgx::sign::{Author, Signature}; +use teepot::sgx::sign::{Body, RS256PrivateKey}; +use tracing::instrument; + +/// Sign command +#[instrument(level = "info", name = "/v1/sign", skip_all)] +pub async fn post_sign( + state: web::Data>, + item: web::Json, +) -> Result, HttpResponseError> { + let conn = VaultConnection::new(&state.vault_attestation.clone().into(), "admin".to_string()) + .await + .context("connecting to vault") + .status(StatusCode::BAD_GATEWAY)?; + + let mut admin_state: AdminState = conn + .load_secret("state") + .await? + .context("empty admin state") + .status(StatusCode::BAD_GATEWAY)?; + + let sign_request: SignRequestData = serde_json::from_str(&item.sign_request_data) + .context("parsing sign request data") + .status(StatusCode::BAD_REQUEST)?; + + // Sanity checks + if sign_request.tee_type != "sgx" { + return Err(anyhow!("tee_type not supported")).status(StatusCode::BAD_REQUEST); + } + + let tee_name = sign_request.tee_name; + + if !tee_name.is_ascii() { + return Err(anyhow!("tee_name is not ascii")).status(StatusCode::BAD_REQUEST); + } + + // check if tee_name is alphanumeric + if !tee_name.chars().all(|c| c.is_alphanumeric()) { + return Err(anyhow!("tee_name is not alphanumeric")).status(StatusCode::BAD_REQUEST); + } + + // check if tee_name starts with an alphabetic char + if !tee_name.chars().next().unwrap().is_alphabetic() { + return Err(anyhow!("tee_name does not start with an alphabetic char")) + .status(StatusCode::BAD_REQUEST); + } + + if admin_state.last_digest != sign_request.last_digest { + return Err(anyhow!( + "last digest does not match {} != {}", + admin_state.last_digest.to_ascii_lowercase(), + sign_request.last_digest + )) + .status(StatusCode::BAD_REQUEST); + } + + let admin_config: AdminConfig = conn + .load_secret("config") + .await? + .context("empty admin config") + .status(StatusCode::BAD_GATEWAY)?; + admin_config.check_sigs(&item.signatures, item.sign_request_data.as_bytes())?; + + let mut hasher = Sha256::new(); + hasher.update(item.sign_request_data.as_bytes()); + let hash = hasher.finalize(); + let digest = hex::encode(hash); + admin_state.last_digest = digest.clone(); + conn.store_secret(admin_state, "state").await?; + + // Sign SGX enclave + let key_path = format!("signing_keys/{}", tee_name); + + let sgx_key = match conn + .load_secret::(&key_path) + .await + .context("Error loading signing key") + .status(StatusCode::INTERNAL_SERVER_ERROR)? + { + Some(key) => RS256PrivateKey::from_pem(&key.pem_pk) + .context("Failed to parse private key") + .status(StatusCode::INTERNAL_SERVER_ERROR)?, + None => { + let private_key = RS256PrivateKey::generate(3) + .context("Failed to generate private key") + .status(StatusCode::INTERNAL_SERVER_ERROR)?; + + let pem_pk = private_key + .to_pem() + .context("Failed to convert private key to pem") + .status(StatusCode::INTERNAL_SERVER_ERROR)?; + + let key = SGXSigningKey { pem_pk }; + + conn.store_secret(key.clone(), &key_path) + .await + .context("Error storing generated private key") + .status(StatusCode::INTERNAL_SERVER_ERROR)?; + + private_key + } + }; + + let signed_data = sign_sgx(&sign_request.data, &sgx_key)?; + let respond = SignResponse { + digest, + signed_data, + }; + + let _ = conn.revoke_token().await; + + Ok(web::Json(respond)) +} + +fn sign_sgx(body_bytes: &[u8], sgx_key: &RS256PrivateKey) -> Result, HttpResponseError> { + let body: Body = bytemuck::try_pod_read_unaligned(body_bytes) + .context("Invalid SGX input data") + .status(StatusCode::INTERNAL_SERVER_ERROR)?; + + if body.can_set_debug() { + return Err(anyhow!("Not signing SGX enclave with debug flag")) + .status(StatusCode::BAD_REQUEST); + } + + // FIXME: do we need the date and sw defined value? + let author = Author::new(0, 0); + let sig = Signature::new(sgx_key, author, body) + .context("Failed to create RSA signature") + .status(StatusCode::INTERNAL_SERVER_ERROR)?; + + Ok(bytemuck::bytes_of(&sig).to_vec()) +} diff --git a/bin/tee-vault-admin/tee-vault-admin.manifest.template b/bin/tee-vault-admin/tee-vault-admin.manifest.template new file mode 100644 index 0000000..97c6ab5 --- /dev/null +++ b/bin/tee-vault-admin/tee-vault-admin.manifest.template @@ -0,0 +1,66 @@ +libos.entrypoint = "/app/tee-vault-admin" + +[loader] +argv = [ "/app/tee-vault-admin" ] +entrypoint = "file:{{ gramine.libos }}" +env.LD_LIBRARY_PATH = "/lib:{{ arch_libdir }}:/usr{{ arch_libdir }}:/lib" +env.HOME = "/app" +env.MALLOC_ARENA_MAX = "1" +env.AZDCAP_DEBUG_LOG_LEVEL = "ignore" +env.AZDCAP_COLLATERAL_VERSION = "v4" + +### Admin Config ### +env.PORT = { passthrough = true } + +### VAULT attestation ### +env.VAULT_ADDR = { passthrough = true } +env.VAULT_SGX_MRENCLAVE = { passthrough = true } +env.VAULT_SGX_MRSIGNER = { passthrough = true } +env.VAULT_SGX_ALLOWED_TCB_LEVELS = { passthrough = true } + +### DEBUG ### +env.RUST_BACKTRACE = "1" +env.RUST_LOG="info,tee_vault_admin=trace,teepot=trace,vault_tee_client=trace,tee_client=trace,awc=debug" + +[fs] +root.uri = "file:/" +start_dir = "/app" +mounts = [ + { path = "{{ execdir }}", uri = "file:{{ execdir }}" }, + { path = "/lib", uri = "file:{{ gramine.runtimedir() }}" }, + { path = "{{ arch_libdir }}", uri = "file:{{ arch_libdir }}" }, + { path = "/etc", uri = "file:/etc" }, + { type = "tmpfs", path = "/var/tmp" }, + { type = "tmpfs", path = "/tmp" }, + { type = "tmpfs", path = "/app/.dcap-qcnl" }, + { type = "tmpfs", path = "/app/.az-dcap-client" }, + { path = "/lib/libdcap_quoteprov.so", uri = "file:/lib/libdcap_quoteprov.so" }, +] + +[sgx] +trusted_files = [ + "file:/etc/ld.so.cache", + "file:/app/", + "file:{{ execdir }}/", + "file:{{ arch_libdir }}/", + "file:/usr/{{ arch_libdir }}/", + "file:{{ gramine.libos }}", + "file:{{ gramine.runtimedir() }}/", + "file:/usr/lib/ssl/openssl.cnf", + "file:/etc/ssl/", + "file:/etc/sgx_default_qcnl.conf", + "file:/lib/libdcap_quoteprov.so", +] +remote_attestation = "dcap" +max_threads = 64 +edmm_enable = false +## max enclave size +enclave_size = "8G" + +[sys] +enable_extra_runtime_domain_names_conf = true +enable_sigterm_injection = true + +# possible tweak option, if problems with mio +# currently mio is compiled with `mio_unsupported_force_waker_pipe` +# insecure__allow_eventfd = true diff --git a/bin/tee-vault-unseal/Cargo.toml b/bin/tee-vault-unseal/Cargo.toml new file mode 100644 index 0000000..256b5bb --- /dev/null +++ b/bin/tee-vault-unseal/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "tee-vault-unseal" +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true +repository.workspace = true + +[dependencies] +actix-tls.workspace = true +actix-web.workspace = true +anyhow.workspace = true +awc.workspace = true +clap.workspace = true +hex.workspace = true +mio.workspace = true +rustls-pemfile.workspace = true +rustls.workspace = true +serde.workspace = true +serde_json.workspace = true +sha2.workspace = true +teepot.workspace = true +thiserror.workspace = true +tokio.workspace = true +tracing-log.workspace = true +tracing-subscriber.workspace = true +tracing.workspace = true +x509-cert.workspace = true diff --git a/bin/tee-vault-unseal/Dockerfile-azure b/bin/tee-vault-unseal/Dockerfile-azure new file mode 100644 index 0000000..cd7c28d --- /dev/null +++ b/bin/tee-vault-unseal/Dockerfile-azure @@ -0,0 +1,92 @@ +FROM ghcr.io/matter-labs/vault-auth-tee:latest AS vault-auth-tee + +FROM docker.io/ubuntu:20.04 AS azuredcap +WORKDIR /build +ADD https://github.com/microsoft/Azure-DCAP-Client/archive/refs/tags/1.12.0.tar.gz ./Azure-DCAP-Client.tar.gz +RUN tar -xvf Azure-DCAP-Client.tar.gz +COPY assets/Azure-DCAP-Client.patch ./Azure-DCAP-Client.patch +RUN set -eux; \ + apt-get update; \ + apt-get install -y software-properties-common; \ + add-apt-repository ppa:team-xbmc/ppa -y; \ + apt-get update; \ + apt-get install -y \ + build-essential \ + cmake \ + libssl-dev \ + libcurl4-openssl-dev \ + pkg-config \ + nlohmann-json3-dev \ + wget \ + dos2unix \ + ; + +WORKDIR /build/Azure-DCAP-Client-1.12.0 +RUN dos2unix src/dcap_provider.cpp && patch -p1 < ../Azure-DCAP-Client.patch +WORKDIR /build/Azure-DCAP-Client-1.12.0/src/Linux +RUN ./configure && make && make install + +FROM docker.io/rust:1-bullseye AS buildtee +RUN curl -fsSLo /usr/share/keyrings/intel.asc https://download.01.org/intel-sgx/sgx_repo/ubuntu/intel-sgx-deb.key \ + && echo "deb [arch=amd64 signed-by=/usr/share/keyrings/intel.asc] https://download.01.org/intel-sgx/sgx_repo/ubuntu focal main" > /etc/apt/sources.list.d/intel-sgx.list \ + && apt-get update \ + && apt-get install -y --no-install-recommends \ + build-essential \ + cmake \ + rsync \ + pkg-config \ + libssl-dev \ + libcurl4-openssl-dev \ + libprotobuf-dev \ + protobuf-compiler \ + clang \ + libsgx-headers \ + libsgx-dcap-quote-verify-dev + +WORKDIR /opt/vault/plugins +COPY --from=vault-auth-tee /opt/vault/plugins/vault-auth-tee ./ + +WORKDIR /build +RUN --mount=type=bind,target=/data rsync --exclude='/.git' --filter="dir-merge,- .gitignore" --exclude "Dockerfile-*" --exclude 'tee-vault-unseal.manifest.template' -av /data/ ./ +RUN sha256sum /opt/vault/plugins/vault-auth-tee | ( read a _ ; echo -n $a ) | tee assets/vault-auth-tee.sha256 +RUN --mount=type=cache,target=/usr/local/cargo/registry --mount=type=cache,target=target \ + RUSTFLAGS="-C target-cpu=icelake-server --cfg mio_unsupported_force_waker_pipe" \ + cargo build --locked --target x86_64-unknown-linux-gnu --release -p tee-vault-unseal --bin tee-vault-unseal \ + && mv ./target/x86_64-unknown-linux-gnu/release/tee-vault-unseal ./ + +FROM docker.io/gramineproject/gramine:v1.5 + +RUN curl -fsSLo /usr/share/keyrings/microsoft.asc https://packages.microsoft.com/keys/microsoft.asc \ + && echo "deb [arch=amd64 signed-by=/usr/share/keyrings/microsoft.asc] https://packages.microsoft.com/ubuntu/20.04/prod focal main" > /etc/apt/sources.list.d/msprod.list \ + && apt-get update \ + && apt purge -y libsgx-dcap-default-qpl \ + && apt-get install -y az-dcap-client + +RUN apt purge -y libsgx-ae-qve +# libsgx-urts + +RUN rm -rf /var/lib/apt/lists/* + +# So we only have to use one gramine template +RUN touch /etc/sgx_default_qcnl.conf + +WORKDIR /app + +COPY --from=buildtee /build/tee-vault-unseal . +COPY ./bin/tee-vault-unseal/tee-vault-unseal.manifest.template . +COPY vault/enclave-key.pem . +RUN mkdir -p /opt/vault/tls && rm -rf /opt/vault/tls/* + +# The original Azure library is still delivering expired collateral, so we have to use a patched version +COPY --from=azuredcap /usr/local/lib/libdcap_quoteprov.so /usr/lib/ + +RUN gramine-manifest -Darch_libdir=/lib/x86_64-linux-gnu -Dexecdir=/usr/bin -Dlog_level=warning tee-vault-unseal.manifest.template tee-vault-unseal.manifest \ + && gramine-sgx-sign --manifest tee-vault-unseal.manifest --output tee-vault-unseal.manifest.sgx --key enclave-key.pem \ + && rm enclave-key.pem + +VOLUME /opt/vault/tls + +EXPOSE 8443 + +ENTRYPOINT ["/bin/sh", "-c"] +CMD [ "/restart_aesm.sh ; exec gramine-sgx tee-vault-unseal" ] diff --git a/bin/tee-vault-unseal/Dockerfile-intel b/bin/tee-vault-unseal/Dockerfile-intel new file mode 100644 index 0000000..870b3ab --- /dev/null +++ b/bin/tee-vault-unseal/Dockerfile-intel @@ -0,0 +1,65 @@ +FROM ghcr.io/matter-labs/vault-auth-tee:latest AS vault-auth-tee + +FROM docker.io/rust:1-bullseye AS buildtee +RUN curl -fsSLo /usr/share/keyrings/intel.asc https://download.01.org/intel-sgx/sgx_repo/ubuntu/intel-sgx-deb.key \ + && echo "deb [arch=amd64 signed-by=/usr/share/keyrings/intel.asc] https://download.01.org/intel-sgx/sgx_repo/ubuntu focal main" > /etc/apt/sources.list.d/intel-sgx.list \ + && apt-get update \ + && apt-get install -y --no-install-recommends \ + build-essential \ + cmake \ + rsync \ + pkg-config \ + libssl-dev \ + libcurl4-openssl-dev \ + libprotobuf-dev \ + protobuf-compiler \ + clang \ + libsgx-headers \ + libsgx-dcap-quote-verify-dev + +WORKDIR /opt/vault/plugins +COPY --from=vault-auth-tee /opt/vault/plugins/vault-auth-tee ./ + +WORKDIR /build +RUN --mount=type=bind,target=/data rsync --exclude='/.git' --filter="dir-merge,- .gitignore" --exclude "Dockerfile-*" --exclude 'tee-vault-unseal.manifest.template' -av /data/ ./ +RUN sha256sum /opt/vault/plugins/vault-auth-tee | ( read a _ ; echo -n $a ) | tee assets/vault-auth-tee.sha256 +RUN --mount=type=cache,target=/usr/local/cargo/registry --mount=type=cache,target=target \ + RUSTFLAGS="-C target-cpu=icelake-server --cfg mio_unsupported_force_waker_pipe" \ + cargo build --locked --target x86_64-unknown-linux-gnu --release -p tee-vault-unseal --bin tee-vault-unseal \ + && mv ./target/x86_64-unknown-linux-gnu/release/tee-vault-unseal ./ + +FROM docker.io/gramineproject/gramine:v1.5 + +RUN curl -fsSLo /usr/share/keyrings/intel.asc https://download.01.org/intel-sgx/sgx_repo/ubuntu/intel-sgx-deb.key \ + && echo "deb [arch=amd64 signed-by=/usr/share/keyrings/intel.asc] https://download.01.org/intel-sgx/sgx_repo/ubuntu focal main" > /etc/apt/sources.list.d/intel-sgx.list \ + && apt-get update \ + && apt-get install -y --no-install-recommends \ + libsgx-dcap-default-qpl \ + libsgx-urts \ + libsgx-enclave-common \ + libsgx-dcap-quote-verify +RUN apt purge -y libsgx-ae-qve +RUN rm -rf /var/lib/apt/lists/* + +# So we only have to use one gramine template +RUN touch /lib/libdcap_quoteprov.so + +WORKDIR /app + +COPY --from=buildtee /build/tee-vault-unseal . +COPY ./bin/tee-vault-unseal/tee-vault-unseal.manifest.template . +COPY vault/enclave-key.pem . +RUN mkdir -p /opt/vault/tls && rm -rf /opt/vault/tls/* + +COPY assets/sgx_default_qcnl.conf.json /etc/sgx_default_qcnl.conf + +RUN gramine-manifest -Darch_libdir=/lib/x86_64-linux-gnu -Dexecdir=/usr/bin -Dlog_level=warning tee-vault-unseal.manifest.template tee-vault-unseal.manifest \ + && gramine-sgx-sign --manifest tee-vault-unseal.manifest --output tee-vault-unseal.manifest.sgx --key enclave-key.pem \ + && rm enclave-key.pem + +VOLUME /opt/vault/tls + +EXPOSE 8443 + +ENTRYPOINT ["/bin/sh", "-c"] +CMD [ "/restart_aesm.sh ; exec gramine-sgx tee-vault-unseal" ] diff --git a/bin/tee-vault-unseal/src/admin-policy.hcl b/bin/tee-vault-unseal/src/admin-policy.hcl new file mode 100644 index 0000000..e79bb6b --- /dev/null +++ b/bin/tee-vault-unseal/src/admin-policy.hcl @@ -0,0 +1,80 @@ +# Read system health check +path "sys/health" +{ + capabilities = ["read", "sudo"] +} + +# Create and manage ACL policies broadly across Vault + +# List existing policies +path "sys/policies/acl" +{ + capabilities = ["list"] +} + +# Create and manage ACL policies +path "sys/policies/acl/*" +{ + capabilities = ["create", "read", "update", "delete", "list", "sudo"] +} + +# Enable and manage authentication methods broadly across Vault + +# Manage auth methods broadly across Vault +path "auth/*" +{ + capabilities = ["create", "read", "update", "delete", "list", "sudo"] +} + +# Create, update, and delete auth methods +path "sys/auth/*" +{ + capabilities = ["create", "update", "delete", "sudo"] +} + +# List auth methods +path "sys/auth" +{ + capabilities = ["read"] +} + +# Enable and manage the key/value secrets engine at `secret/` path + +# List, create, update, and delete key/value secrets +path "secret/*" +{ + capabilities = ["create", "read", "update", "delete", "list", "sudo"] +} + +# Manage secrets engines +path "sys/mounts/*" +{ + capabilities = ["create", "read", "update", "delete", "list", "sudo"] +} + +# List existing secrets engines. +path "sys/mounts" +{ + capabilities = ["read"] +} + +# Manage plugins +# https://developer.hashicorp.com/vault/api-docs/system/plugins-catalog +path "sys/plugins/catalog/*" +{ + capabilities = ["create", "read", "update", "delete", "list", "sudo"] +} + +# List existing plugins +# https://developer.hashicorp.com/vault/api-docs/system/plugins-catalog +path "sys/plugins/catalog" +{ + capabilities = ["list"] +} + +# Reload plugins +# https://developer.hashicorp.com/vault/api-docs/system/plugins-reload-backend +path "sys/plugins/reload/backend" +{ + capabilities = ["create", "update", "sudo"] +} diff --git a/bin/tee-vault-unseal/src/attestation.rs b/bin/tee-vault-unseal/src/attestation.rs new file mode 100644 index 0000000..bf556fc --- /dev/null +++ b/bin/tee-vault-unseal/src/attestation.rs @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023 Matter Labs + +use crate::Worker; +use actix_web::http::StatusCode; +use actix_web::web::{Data, Json}; +use anyhow::{Context, Result}; +use teepot::json::http::AttestationResponse; +use teepot::server::attestation::get_quote_and_collateral; +use teepot::server::{HttpResponseError, Status}; +use tracing::instrument; + +#[instrument(level = "info", name = "/v1/sys/attestation", skip_all)] +pub async fn get_attestation( + worker: Data, +) -> Result, HttpResponseError> { + let report_data: [u8; 64] = worker + .config + .report_data + .clone() + .try_into() + .map_err(|_| "Error getting attestation")?; + get_quote_and_collateral(None, &report_data) + .context("Error getting attestation") + .map(Json) + .status(StatusCode::INTERNAL_SERVER_ERROR) +} diff --git a/bin/tee-vault-unseal/src/init.rs b/bin/tee-vault-unseal/src/init.rs new file mode 100644 index 0000000..df7ad47 --- /dev/null +++ b/bin/tee-vault-unseal/src/init.rs @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023 Matter Labs + +use crate::{create_https_client, get_vault_status, UnsealServerState, Worker}; +use actix_web::error::ErrorBadRequest; +use actix_web::{web, HttpResponse}; +use anyhow::{anyhow, Context, Result}; +use awc::http::StatusCode; +use serde_json::json; +use teepot::json::http::{Init, InitResponse, VaultInitRequest}; +use teepot::json::secrets::AdminConfig; +use teepot::server::{HttpResponseError, Status}; +use tracing::{debug, error, info, instrument, trace}; + +#[instrument(level = "info", name = "/v1/sys/init", skip_all)] +pub async fn post_init( + worker: web::Data, + init: web::Json, +) -> Result { + let Init { + pgp_keys, + secret_shares, + secret_threshold, + admin_pgp_keys, + admin_threshold, + admin_tee_mrenclave, + } = init.into_inner(); + let client = create_https_client(worker.client_tls_config.clone()); + let vault_url = &worker.config.vault_url; + + let vault_init = VaultInitRequest { + pgp_keys, + secret_shares, + secret_threshold, + }; + + if admin_threshold < 1 { + return Ok(HttpResponse::from_error(ErrorBadRequest( + json!({"error": "admin_threshold must be at least 1"}), + ))); + } + + if admin_threshold > admin_pgp_keys.len() { + return Ok(HttpResponse::from_error(ErrorBadRequest( + json!({"error": "admin_threshold must be less than or equal to the number of admin_pgp_keys"}), + ))); + } + + loop { + let current_state = worker.state.read().unwrap().clone(); + match current_state { + UnsealServerState::VaultUninitialized => { + break; + } + UnsealServerState::VaultUnsealed => { + return Err(anyhow!("Vault already unsealed")).status(StatusCode::BAD_REQUEST); + } + UnsealServerState::VaultInitialized { .. } => { + return Err(anyhow!("Vault already initialized")).status(StatusCode::BAD_REQUEST); + } + UnsealServerState::VaultInitializedAndConfigured => { + return Err(anyhow!("Vault already initialized")).status(StatusCode::BAD_REQUEST); + } + UnsealServerState::Undefined => { + let state = get_vault_status(vault_url, client.clone()).await; + *worker.state.write().unwrap() = state; + continue; + } + } + } + + trace!( + "Sending init request to Vault {}", + serde_json::to_string(&vault_init).unwrap() + ); + let mut response = client + .post(format!("{}/v1/sys/init", vault_url)) + .send_json(&vault_init) + .await?; + + let status_code = response.status(); + if !status_code.is_success() { + error!("Vault returned server error: {}", status_code); + return Err(HttpResponseError::from_proxy(response).await); + } + + let response = response + .json::() + .await + .context("Failed to convert to json") + .status(StatusCode::INTERNAL_SERVER_ERROR)?; + + info!("Vault initialized"); + trace!("response {}", response); + + let root_token = response["root_token"] + .as_str() + .ok_or(anyhow!("No `root_token` field")) + .status(StatusCode::BAD_GATEWAY)? + .to_string(); + + debug!("Root token: {root_token}"); + + let unseal_keys = response["keys_base64"] + .as_array() + .ok_or(anyhow!("No `keys_base64` field")) + .status(StatusCode::BAD_GATEWAY)? + .iter() + .map(|v| v.as_str().unwrap().to_string()) + .collect::>(); + + debug!("Unseal keys: {}", unseal_keys.join(", ")); + + /* + FIXME: use unseal keys to create new token + let mut output = File::create("/opt/vault/data/root_token") + .context("Failed to create `/opt/vault/data/root_token`")?; + output + .write_all(root_token.as_bytes()) + .context("Failed to write root_token")?; + */ + + *worker.state.write().unwrap() = UnsealServerState::VaultInitialized { + admin_config: AdminConfig { + admin_pgp_keys, + admin_threshold, + }, + admin_tee_mrenclave, + root_token, + }; + + let response = InitResponse { unseal_keys }; + + Ok(HttpResponse::Ok().json(response)) // <- send response +} diff --git a/bin/tee-vault-unseal/src/main.rs b/bin/tee-vault-unseal/src/main.rs new file mode 100644 index 0000000..74b2f96 --- /dev/null +++ b/bin/tee-vault-unseal/src/main.rs @@ -0,0 +1,366 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023 Matter Labs + +//! Server to initialize and unseal the Vault TEE. + +#![deny(missing_docs)] +#![deny(clippy::all)] + +mod attestation; +mod init; +mod unseal; + +use actix_web::http::header; +use actix_web::rt::time::sleep; +use actix_web::web::Data; +use actix_web::{web, App, HttpServer}; +use anyhow::{Context, Result}; +use attestation::get_attestation; +use awc::{Client, Connector}; +use clap::Parser; +use init::post_init; +use rustls::client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier}; +use rustls::client::WebPkiServerVerifier; +use rustls::pki_types::{CertificateDer, ServerName, UnixTime}; +use rustls::{ClientConfig, DigitallySignedStruct, Error, ServerConfig, SignatureScheme}; +use rustls_pemfile::{certs, read_one}; +use sha2::{Digest, Sha256}; +use std::fmt::Debug; +use std::net::Ipv6Addr; +use std::sync::{Arc, RwLock}; +use std::time::Duration; +use std::{fs::File, io::BufReader}; +use teepot::json::http::{Init, Unseal, ATTESTATION_URL}; +use teepot::json::secrets::AdminConfig; +use teepot::server::attestation::get_quote_and_collateral; +use teepot::server::new_json_cfg; +use teepot::sgx::{parse_tcb_levels, EnumSet, TcbLevel}; +use tracing::{error, info, trace}; +use tracing_log::LogTracer; +use tracing_subscriber::{fmt, prelude::*, EnvFilter, Registry}; +use unseal::post_unseal; +use x509_cert::der::Decode as _; +use x509_cert::der::Encode as _; +use x509_cert::Certificate; + +const VAULT_AUTH_TEE_SHA256: &str = include_str!("../../../assets/vault-auth-tee.sha256"); +const VAULT_TOKEN_HEADER: &str = "X-Vault-Token"; + +/// Worker thread state and data +pub struct Worker { + /// TLS config for the HTTPS client + pub client_tls_config: Arc, + /// Server config + pub config: Arc, + /// Server state + pub state: Arc>, +} + +/// Global Server config +#[derive(Debug, Default)] +pub struct UnsealServerConfig { + /// Vault URL + pub vault_url: String, + /// The expected report_data for the Vault TEE + pub report_data: Vec, + /// allowed TCB levels + pub allowed_tcb_levels: Option>, +} + +/// Server state +#[derive(Debug, Clone)] +pub enum UnsealServerState { + /// Undefined + Undefined, + /// Vault is not yet initialized + VaultUninitialized, + /// Vault is initialized but not unsealed + VaultInitialized { + /// config for the admin TEE + admin_config: AdminConfig, + /// initial admin TEE mrenclave + admin_tee_mrenclave: String, + /// Vault root token + root_token: String, + }, + /// Vault is already initialized but not unsealed + /// and should already be configured + VaultInitializedAndConfigured, + /// Vault is unsealed + VaultUnsealed, +} + +impl UnsealServerConfig { + /// Create a new ServerState + pub fn new( + vault_url: String, + report_data: [u8; 64], + allowed_tcb_levels: Option>, + ) -> Self { + Self { + report_data: report_data.to_vec(), + vault_url, + allowed_tcb_levels, + } + } +} + +#[derive(Parser, Debug)] +#[command(author, version, about, long_about = None)] +struct Args { + /// allowed TCB levels, comma separated + #[arg(long, value_parser = parse_tcb_levels, env = "ALLOWED_TCB_LEVELS", default_value = "Ok")] + allowed_tcb_levels: EnumSet, + /// port to listen on + #[arg(long, env = "PORT", default_value = "8443")] + port: u16, + /// vault url + #[arg(long, env = "VAULT_ADDR", default_value = "https://vault:8210")] + vault_url: String, +} + +#[actix_web::main] +async fn main() -> Result<()> { + LogTracer::init().context("Failed to set logger")?; + + let subscriber = Registry::default() + .with(EnvFilter::from_default_env()) + .with( + fmt::layer() + .with_span_events(fmt::format::FmtSpan::NEW) + .with_writer(std::io::stderr), + ); + tracing::subscriber::set_global_default(subscriber).unwrap(); + + let args = Args::parse(); + + let tls_ok = std::path::Path::new("/opt/vault/tls/tls.ok"); + loop { + info!("Waiting for TLS key/cert files to be generated"); + + // Wait for the file `data/tls.key` to exist + if tls_ok.exists() { + break; + } + sleep(Duration::from_secs(1)).await; + } + + info!("Starting up"); + + let (config, client_tls_config, report_data) = load_rustls_config().or_else(|e| { + error!("failed to load rustls config: {e:?}"); + Err(e).context("Failed to load rustls config") + })?; + + if let Err(e) = get_quote_and_collateral(Some(args.allowed_tcb_levels), &report_data) { + error!("failed to get quote and collateral: {e:?}"); + // don't return for now, we can still serve requests but we won't be able to attest + } + + let client = create_https_client(client_tls_config.clone()); + + let server_state = get_vault_status(&args.vault_url, client).await; + + info!("Starting HTTPS server at port {}", args.port); + let server_config = Arc::new(UnsealServerConfig::new( + args.vault_url, + report_data, + Some(args.allowed_tcb_levels), + )); + + let server_state = Arc::new(RwLock::new(server_state)); + + let server = match HttpServer::new(move || { + let worker = Worker { + client_tls_config: client_tls_config.clone(), + config: server_config.clone(), + state: server_state.clone(), + }; + + App::new() + // enable logger + //.wrap(TracingLogger::default()) + .app_data(new_json_cfg()) + .app_data(Data::new(worker)) + .service(web::resource(ATTESTATION_URL).route(web::get().to(get_attestation))) + .service(web::resource(Init::URL).route(web::post().to(post_init))) + .service(web::resource(Unseal::URL).route(web::post().to(post_unseal))) + }) + .bind_rustls_0_22((Ipv6Addr::UNSPECIFIED, args.port), config) + { + Ok(c) => c, + Err(e) => { + error!("Failed to bind to port {}: {e:?}", args.port); + return Err(e).context(format!("Failed to bind to port {}", args.port)); + } + }; + + if let Err(e) = server.worker_max_blocking_threads(2).workers(8).run().await { + error!("failed to start HTTPS server: {e:?}"); + return Err(e).context("Failed to start HTTPS server"); + } + + Ok(()) +} + +async fn get_vault_status(vault_url: &str, client: Client) -> UnsealServerState { + loop { + let r = client + .get(format!("{}/v1/sys/health", vault_url)) + .send() + .await; + + if let Ok(r) = r { + // https://developer.hashicorp.com/vault/api-docs/system/health + match r.status().as_u16() { + 200 | 429 | 472 | 473 => { + info!("Vault is initialized and unsealed"); + break UnsealServerState::VaultUnsealed; + } + 501 => { + info!("Vault is not initialized"); + break UnsealServerState::VaultUninitialized; + } + 503 => { + info!("Vault is initialized but not unsealed"); + break UnsealServerState::VaultInitializedAndConfigured; + } + s => { + error!("Vault is not ready: status code {s}"); + } + } + } + info!("Waiting for vault to be ready"); + sleep(Duration::from_secs(1)).await; + } +} + +// Save the hash of the public server key to `REPORT_DATA` to check +// the attestations against it and it does not change on reconnect. +fn make_verifier(server_cert: Box<[u8]>) -> impl ServerCertVerifier { + #[derive(Debug)] + struct V { + server_cert: Box<[u8]>, + server_verifier: Arc, + } + impl ServerCertVerifier for V { + fn verify_server_cert( + &self, + end_entity: &CertificateDer, + _intermediates: &[CertificateDer], + _server_name: &ServerName, + _ocsp_response: &[u8], + _now: UnixTime, + ) -> std::result::Result { + let data = &self.server_cert; + + if data.as_ref() == end_entity.as_ref() { + info!("Server certificate matches expected certificate"); + Ok(ServerCertVerified::assertion()) + } else { + error!("Server certificate does not match expected certificate"); + Err(rustls::Error::General( + "Server certificate does not match expected certificate".to_string(), + )) + } + } + fn verify_tls12_signature( + &self, + message: &[u8], + cert: &CertificateDer<'_>, + dss: &DigitallySignedStruct, + ) -> std::result::Result { + self.server_verifier + .verify_tls12_signature(message, cert, dss) + } + + fn verify_tls13_signature( + &self, + message: &[u8], + cert: &CertificateDer<'_>, + dss: &DigitallySignedStruct, + ) -> std::result::Result { + self.server_verifier + .verify_tls13_signature(message, cert, dss) + } + + fn supported_verify_schemes(&self) -> Vec { + self.server_verifier.supported_verify_schemes() + } + } + let root_store = Arc::new(rustls::RootCertStore::empty()); + let server_verifier = WebPkiServerVerifier::builder(root_store).build().unwrap(); + V { + server_cert, + server_verifier, + } +} + +/// Load TLS key/cert files +pub fn load_rustls_config() -> Result<(ServerConfig, Arc, [u8; 64])> { + // init server config builder with safe defaults + let config = ServerConfig::builder().with_no_client_auth(); + + // load TLS key/cert files + let cert_file = &mut BufReader::new( + File::open("/opt/vault/tls/tls.crt").context("Failed to open TLS cert file")?, + ); + let key_file = &mut BufReader::new( + File::open("/opt/vault/tls/tls.key").context("Failed to open TLS key file")?, + ); + + // convert files to key/cert objects + let cert_chain: Vec<_> = certs(cert_file) + .unwrap() + .into_iter() + .map(rustls::pki_types::CertificateDer::from) + .collect(); + let priv_key: rustls::pki_types::PrivateKeyDer = match read_one(key_file).unwrap() { + Some(rustls_pemfile::Item::RSAKey(key)) => { + rustls::pki_types::PrivatePkcs1KeyDer::from(key).into() + } + Some(rustls_pemfile::Item::PKCS8Key(key)) => { + rustls::pki_types::PrivatePkcs8KeyDer::from(key).into() + } + _ => panic!("no keys found"), + }; + + let tls_config = Arc::new( + rustls::ClientConfig::builder() + .dangerous() + .with_custom_certificate_verifier(Arc::new(make_verifier( + cert_chain[0].as_ref().into(), + ))) + .with_no_client_auth(), + ); + + let cert = Certificate::from_der(cert_chain[0].as_ref()).unwrap(); + let pub_key = cert + .tbs_certificate + .subject_public_key_info + .to_der() + .unwrap(); + + let hash = Sha256::digest(pub_key); + let mut report_data = [0u8; 64]; + report_data[..32].copy_from_slice(&hash[..32]); + + let report_data_hex = hex::encode(report_data); + trace!(report_data_hex); + + let config = config + .with_single_cert(cert_chain, priv_key) + .context("Failed to load TLS key/cert files")?; + + Ok((config, tls_config, report_data)) +} + +/// Create an HTTPS client with the default headers and config +pub fn create_https_client(client_tls_config: Arc) -> Client { + Client::builder() + .add_default_header((header::USER_AGENT, "teepot/1.0")) + // a "connector" wraps the stream into an encrypted connection + .connector(Connector::new().rustls_0_22(client_tls_config)) + .timeout(Duration::from_secs(12000)) + .finish() +} diff --git a/bin/tee-vault-unseal/src/unseal.rs b/bin/tee-vault-unseal/src/unseal.rs new file mode 100644 index 0000000..e999608 --- /dev/null +++ b/bin/tee-vault-unseal/src/unseal.rs @@ -0,0 +1,412 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023 Matter Labs + +use crate::{ + create_https_client, get_vault_status, UnsealServerConfig, UnsealServerState, Worker, + VAULT_AUTH_TEE_SHA256, VAULT_TOKEN_HEADER, +}; +use actix_web::http::StatusCode; +use actix_web::rt::time::sleep; +use actix_web::{web, HttpResponse}; +use anyhow::{anyhow, Context, Result}; +use awc::{Client, ClientRequest, SendClientRequest}; +use serde_json::{json, Value}; +use std::fs::File; +use std::future::Future; +use std::io::Read; +use std::time::Duration; +use teepot::client::vault::VaultConnection; +use teepot::json::http::Unseal; +use teepot::json::secrets::{AdminConfig, AdminState}; +use teepot::server::{HttpResponseError, Status}; +use tracing::{debug, error, info, instrument, trace}; + +#[instrument(level = "info", name = "/v1/sys/unseal", skip_all)] +pub async fn post_unseal( + worker: web::Data, + item: web::Json, +) -> Result { + let client = create_https_client(worker.client_tls_config.clone()); + let app = &worker.config; + let vault_url = &app.vault_url; + + loop { + let current_state = worker.state.read().unwrap().clone(); + match current_state { + UnsealServerState::VaultUninitialized => { + return Err(anyhow!("Vault not yet initialized")).status(StatusCode::BAD_REQUEST); + } + UnsealServerState::VaultUnsealed => { + return Err(anyhow!("Vault already unsealed")).status(StatusCode::BAD_REQUEST); + } + UnsealServerState::VaultInitialized { .. } => { + break; + } + UnsealServerState::VaultInitializedAndConfigured => { + break; + } + UnsealServerState::Undefined => { + let state = get_vault_status(vault_url, client.clone()).await; + *worker.state.write().unwrap() = state; + continue; + } + } + } + + let mut response = client + .post(format!("{}/v1/sys/unseal", vault_url)) + .send_json(&item.0) + .await?; + + let status_code = response.status(); + if !status_code.is_success() { + error!("Vault returned server error: {}", status_code); + let mut client_resp = HttpResponse::build(status_code); + for (header_name, header_value) in response.headers().iter() { + client_resp.insert_header((header_name.clone(), header_value.clone())); + } + return Ok(client_resp.streaming(response)); + } + + let response: Value = response + .json() + .await + .context("parsing unseal response") + .status(StatusCode::INTERNAL_SERVER_ERROR)?; + + debug!("unseal: {:?}", response); + + if response.get("errors").is_some() { + return Ok(HttpResponse::Ok().json(response)); + } + + let sealed = response + .get("sealed") + .map(|v| v.as_bool().unwrap_or(true)) + .unwrap_or(true); + + debug!(sealed); + + // if unsealed + if !sealed { + let mut state = UnsealServerState::VaultUnsealed; + std::mem::swap(&mut *worker.state.write().unwrap(), &mut state); + + match state { + UnsealServerState::VaultUninitialized => { + return Err(anyhow!("Invalid internal state")).status(StatusCode::BAD_REQUEST); + } + UnsealServerState::VaultUnsealed => { + return Err(anyhow!("Invalid internal state")).status(StatusCode::BAD_REQUEST); + } + UnsealServerState::VaultInitialized { + admin_config, + admin_tee_mrenclave, + root_token, + } => { + debug!(root_token); + info!("Vault is unsealed"); + let app = &worker.config; + let client = create_https_client(worker.client_tls_config.clone()); + + vault_configure_unsealed( + app, + &admin_config, + &root_token, + &admin_tee_mrenclave, + &client, + ) + .await + .context("Failed to configure unsealed vault") + .status(StatusCode::BAD_GATEWAY)?; + + // destroy root token + let _response = client + .post(format!("{}/v1/auth/token/revoke-self", app.vault_url)) + .insert_header((VAULT_TOKEN_HEADER, root_token.to_string())) + .send() + .await; + + info!("Vault unsealed and configured!"); + } + UnsealServerState::VaultInitializedAndConfigured => { + info!("Vault is unsealed and hopefully configured!"); + info!("Initiating raft join"); + // load TLS cert chain + let mut cert_file = File::open("/opt/vault/tls/cacert.pem") + .context("Failed to open TLS cert chain") + .status(StatusCode::INTERNAL_SERVER_ERROR)?; + + let mut cert_buf = Vec::new(); + cert_file + .read_to_end(&mut cert_buf) + .context("Failed to read TLS cert chain") + .status(StatusCode::INTERNAL_SERVER_ERROR)?; + + let cert_chain = std::str::from_utf8(&cert_buf) + .context("Failed to parse TLS cert chain as UTF-8") + .status(StatusCode::INTERNAL_SERVER_ERROR)? + .to_string(); + + let payload = json!({"leader_ca_cert": cert_chain, "retry": true }); + + let mut response = client + .post(format!("{}/v1/sys/storage/raft/join", vault_url)) + .send_json(&payload) + .await?; + + let status_code = response.status(); + if !status_code.is_success() { + error!("Vault returned server error: {}", status_code); + let mut client_resp = HttpResponse::build(status_code); + for (header_name, header_value) in response.headers().iter() { + client_resp.insert_header((header_name.clone(), header_value.clone())); + } + return Ok(client_resp.streaming(response)); + } + + let response: Value = response + .json() + .await + .context("parsing raft join response") + .status(StatusCode::INTERNAL_SERVER_ERROR)?; + + debug!("raft join: {:?}", response); + + if response.get("errors").is_some() { + return Ok(HttpResponse::Ok().json(response)); + } + } + UnsealServerState::Undefined => { + unreachable!("Invalid internal state"); + } + } + } + + Ok(HttpResponse::Accepted().json(response)) // <- send response +} + +pub async fn vault_configure_unsealed( + app: &UnsealServerConfig, + admin_config: &AdminConfig, + root_token: &str, + admin_tee_mrenclave: &str, + c: &Client, +) -> Result<(), HttpResponseError> { + wait_for_plugins_catalog(app, root_token, c).await; + + if !plugin_is_already_running(app, root_token, c).await? { + let r = vault( + "Installing vault-auth-tee plugin", + c.put(format!( + "{}/v1/sys/plugins/catalog/auth/vault-auth-tee", + app.vault_url + )), + root_token, + json!({ + "sha256": VAULT_AUTH_TEE_SHA256, + "command": "vault-auth-tee", + "version": "0.1.0+dev" + }), + ) + .await + .map_err(|e| anyhow!("{:?}", e)) + .status(StatusCode::BAD_GATEWAY)?; + if !r.status().is_success() { + let err = HttpResponseError::from_proxy(r).await; + return Err(err); + } + } else { + info!("vault-auth-tee plugin already installed"); + } + + if !plugin_is_already_running(app, root_token, c).await? { + let r = vault( + "Activating vault-auth-tee plugin", + c.post(format!("{}/v1/sys/auth/tee", app.vault_url)), + root_token, + json!({"type": "vault-auth-tee"}), + ) + .await + .map_err(|e| anyhow!("{:?}", e)) + .status(StatusCode::BAD_GATEWAY)?; + if !r.status().is_success() { + let err = HttpResponseError::from_proxy(r).await; + return Err(err); + } + } else { + info!("vault-auth-tee plugin already activated"); + } + + if let Ok(mut r) = c + .get(format!("{}/v1/auth/tee/tees?list=true", app.vault_url)) + .insert_header((VAULT_TOKEN_HEADER, root_token)) + .send() + .await + { + let r: Value = r + .json() + .await + .map_err(|e| anyhow!("{:?}", e)) + .status(StatusCode::BAD_GATEWAY)?; + trace!("{:?}", r); + if let Some(tees) = r.get("data").and_then(|v| v.get("keys")) { + if let Some(tees) = tees.as_array() { + if tees.contains(&json!("root")) { + info!("root TEE already installed"); + return Ok(()); + } + } + } + } + + vault( + "Installing root TEE", + c.put(format!("{}/v1/auth/tee/tees/admin", app.vault_url)), + root_token, + json!({ + "lease": "1000", + "name": "admin", + "types": "sgx", + "sgx_allowed_tcb_levels": "Ok,SwHardeningNeeded", + "sgx_mrenclave": &admin_tee_mrenclave, + "token_policies": "admin" + }), + ) + .await + .map_err(|e| anyhow!("{:?}", e)) + .status(StatusCode::BAD_GATEWAY)?; + + // Install admin policies + let admin_policy = include_str!("admin-policy.hcl"); + vault( + "Installing admin policy", + c.put(format!("{}/v1/sys/policies/acl/admin", app.vault_url)), + root_token, + json!({ "policy": admin_policy }), + ) + .await + .map_err(|e| anyhow!("{:?}", e)) + .status(StatusCode::BAD_GATEWAY)?; + + vault( + "Enable the key/value secrets engine v1 at secret/.", + c.put(format!("{}/v1/sys/mounts/secret", app.vault_url)), + root_token, + json!({ "type": "kv", "description": "K/V v1" } ), + ) + .await + .map_err(|e| anyhow!("{:?}", e)) + .status(StatusCode::BAD_GATEWAY)?; + + // Create a `VaultConnection` for the `admin` tee to initialize the secrets for it. + // Safety: the connection was already attested + let admin_vcon = unsafe { + VaultConnection::new_from_client_without_attestation( + app.vault_url.clone(), + c.clone(), + "admin".into(), + root_token.to_string(), + ) + }; + + // initialize the admin config + admin_vcon.store_secret(admin_config, "config").await?; + admin_vcon + .store_secret(AdminState::default(), "state") + .await?; + + Ok(()) +} + +async fn wait_for_plugins_catalog(app: &UnsealServerConfig, root_token: &str, c: &Client) { + info!("Waiting for plugins to be loaded"); + loop { + let r = c + .get(format!("{}/v1/sys/plugins/catalog", app.vault_url)) + .insert_header((VAULT_TOKEN_HEADER, root_token)) + .send() + .await; + + match r { + Ok(r) => { + if r.status().is_success() { + break; + } else { + debug!("/v1/sys/plugins/catalog status: {:#?}", r) + } + } + Err(e) => { + debug!("/v1/sys/plugins/catalog error: {}", e) + } + } + + info!("Waiting for plugins to be loaded"); + sleep(Duration::from_secs(1)).await; + } +} + +async fn plugin_is_already_running( + app: &UnsealServerConfig, + root_token: &str, + c: &Client, +) -> std::result::Result { + if let Ok(mut r) = c + .get(format!("{}/v1/sys/auth", app.vault_url)) + .insert_header((VAULT_TOKEN_HEADER, root_token)) + .send() + .await + { + if !r.status().is_success() { + return Ok(false); + } + let r: Value = r + .json() + .await + .map_err(|e| anyhow!("{:?}", e)) + .status(StatusCode::BAD_GATEWAY)?; + trace!("{}", r.to_string()); + + let is_running = r + .get("data") + .and_then(|v| v.get("tee/")) + .and_then(|v| v.get("running_sha256")) + .and_then(|v| v.as_str()) + .and_then(|v| if v.is_empty() { None } else { Some(v) }) + .and_then(|v| { + if v == VAULT_AUTH_TEE_SHA256 { + Some(v) + } else { + None + } + }) + .is_some(); + Ok(is_running) + } else { + Ok(false) + } +} + +async fn vault( + action: &str, + req: ClientRequest, + token: &str, + json: Value, +) -> ::Output { + info!("{}", action); + debug!("json: {:?}", json); + match req + .insert_header((VAULT_TOKEN_HEADER, token)) + .send_json(&json) + .await + { + Ok(r) => { + debug!("response {:?}", r); + Ok(r) + } + Err(e) => { + error!("{}: {}", action, e); + Err(e) + } + } +} diff --git a/bin/tee-vault-unseal/tee-vault-unseal.manifest.template b/bin/tee-vault-unseal/tee-vault-unseal.manifest.template new file mode 100644 index 0000000..b30bf2a --- /dev/null +++ b/bin/tee-vault-unseal/tee-vault-unseal.manifest.template @@ -0,0 +1,62 @@ +libos.entrypoint = "/app/tee-vault-unseal" + +[loader] +argv = [ "/app/tee-vault-unseal" ] +entrypoint = "file:{{ gramine.libos }}" +env.LD_LIBRARY_PATH = "/lib:{{ arch_libdir }}:/usr{{ arch_libdir }}:/lib" +env.HOME = "/app" +env.MALLOC_ARENA_MAX = "1" +env.AZDCAP_DEBUG_LOG_LEVEL = "ignore" +env.AZDCAP_COLLATERAL_VERSION = "v4" + +### Required configuration ### +env.ALLOWED_TCB_LEVELS = { passthrough = true } +env.VAULT_ADDR = { passthrough = true } + +### DEBUG ### +env.RUST_BACKTRACE = "1" +env.RUST_LOG="info,tee_vault_unseal=trace,teepot=trace,awc=debug" + +[fs] +root.uri = "file:/" +start_dir = "/app" +mounts = [ + { path = "{{ execdir }}", uri = "file:{{ execdir }}" }, + { path = "/lib", uri = "file:{{ gramine.runtimedir() }}" }, + { path = "{{ arch_libdir }}", uri = "file:{{ arch_libdir }}" }, + { path = "/etc", uri = "file:/etc" }, + { type = "tmpfs", path = "/var/tmp" }, + { type = "tmpfs", path = "/tmp" }, + { type = "tmpfs", path = "/app/.dcap-qcnl" }, + { type = "tmpfs", path = "/app/.az-dcap-client" }, + { type = "encrypted", path = "/opt/vault/tls", uri = "file:/opt/vault/tls", key_name = "_sgx_mrsigner" }, + { path = "/lib/libdcap_quoteprov.so", uri = "file:/lib/libdcap_quoteprov.so" }, +] + +[sgx] +trusted_files = [ + "file:/etc/ld.so.cache", + "file:/app/", + "file:{{ execdir }}/", + "file:{{ arch_libdir }}/", + "file:/usr/{{ arch_libdir }}/", + "file:{{ gramine.libos }}", + "file:{{ gramine.runtimedir() }}/", + "file:/usr/lib/ssl/openssl.cnf", + "file:/etc/ssl/", + "file:/etc/sgx_default_qcnl.conf", + "file:/lib/libdcap_quoteprov.so", +] +remote_attestation = "dcap" +max_threads = 64 +edmm_enable = false +## max enclave size +enclave_size = "2G" + +[sys] +enable_extra_runtime_domain_names_conf = true +enable_sigterm_injection = true + +# possible tweak option, if problems with mio +# currently mio is compiled with `mio_unsupported_force_waker_pipe` +# insecure__allow_eventfd = true diff --git a/bin/teepot-read/Cargo.toml b/bin/teepot-read/Cargo.toml new file mode 100644 index 0000000..3fcaf80 --- /dev/null +++ b/bin/teepot-read/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "teepot-read" +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true +repository.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +actix-web.workspace = true +anyhow.workspace = true +awc.workspace = true +clap.workspace = true +serde.workspace = true +serde_json.workspace = true +teepot.workspace = true +tracing-actix-web.workspace = true +tracing-log.workspace = true +tracing-subscriber.workspace = true +tracing.workspace = true diff --git a/bin/teepot-read/src/main.rs b/bin/teepot-read/src/main.rs new file mode 100644 index 0000000..1b1afe2 --- /dev/null +++ b/bin/teepot-read/src/main.rs @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023 Matter Labs + +//! Get the secrets from a Vault TEE and pass them as environment variables to a command + +#![deny(missing_docs)] +#![deny(clippy::all)] + +use anyhow::{Context, Result}; +use clap::Parser; +use serde_json::Value; +use std::collections::HashMap; +use std::os::unix::process::CommandExt; +use std::process::Command; +use teepot::client::vault::VaultConnection; +use teepot::server::attestation::VaultAttestationArgs; +use tracing::{debug, info, warn}; +use tracing_log::LogTracer; +use tracing_subscriber::{fmt, prelude::*, EnvFilter, Registry}; + +#[derive(Parser, Debug)] +#[command(author, version, about, long_about = None)] +struct Arguments { + /// turn on test mode + #[arg(long, hide = true)] + pub test: bool, + /// vault token + #[arg(long, env = "VAULT_TOKEN", hide = true)] + pub vault_token: String, + #[clap(flatten)] + pub attestation: VaultAttestationArgs, + /// name of this TEE to login to vault + #[arg(long, required = true)] + pub name: String, + /// secrets to get from vault and pass as environment variables + #[arg(long, required = true)] + pub secrets: Vec, + /// command to run + pub command: Vec, +} + +#[actix_web::main] +async fn main() -> Result<()> { + LogTracer::init().context("Failed to set logger")?; + + let subscriber = Registry::default() + .with(EnvFilter::from_default_env()) + .with(fmt::layer().with_writer(std::io::stderr)); + tracing::subscriber::set_global_default(subscriber).unwrap(); + + let args = Arguments::parse(); + + // Split every string with a ',' into a vector of strings, flatten them and collect them. + let secrets = args + .secrets + .iter() + .flat_map(|s| s.split(',')) + .collect::>(); + + info!("args: {:?}", args); + + let conn = if args.test { + warn!("TEST MODE"); + let client = awc::Client::builder() + .add_default_header((actix_web::http::header::USER_AGENT, "teepot/1.0")) + .finish(); + // SAFETY: TEST MODE + unsafe { + VaultConnection::new_from_client_without_attestation( + args.attestation.vault_addr.clone(), + client, + args.name.clone(), + args.vault_token.clone(), + ) + } + } else { + VaultConnection::new(&args.attestation.clone().into(), args.name.clone()) + .await + .expect("connecting to vault") + }; + + let mut env: HashMap = HashMap::new(); + + for secret_name in secrets { + debug!("getting secret {secret_name}"); + let secret_val: serde_json::Value = match conn.load_secret(secret_name).await? { + Some(val) => val, + None => { + debug!("secret {secret_name} not found"); + continue; + } + }; + + debug!("got secret {secret_name}: {secret_val}"); + + // Plain strings can be converted to strings. + let env_val = match secret_val { + Value::String(s) => s, + _ => secret_val.to_string(), + }; + + env.insert(secret_name.to_string(), env_val); + } + + let err = Command::new(&args.command[0]) + .args(&args.command[1..]) + .envs(env) + .exec(); + + Err(err).context("exec failed") +} diff --git a/bin/teepot-write/Cargo.toml b/bin/teepot-write/Cargo.toml new file mode 100644 index 0000000..f94f63a --- /dev/null +++ b/bin/teepot-write/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "teepot-write" +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true +repository.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +actix-web.workspace = true +anyhow.workspace = true +awc.workspace = true +clap.workspace = true +serde.workspace = true +serde_json.workspace = true +teepot.workspace = true +tracing-actix-web.workspace = true +tracing-log.workspace = true +tracing-subscriber.workspace = true +tracing.workspace = true diff --git a/bin/teepot-write/src/main.rs b/bin/teepot-write/src/main.rs new file mode 100644 index 0000000..04fea08 --- /dev/null +++ b/bin/teepot-write/src/main.rs @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023 Matter Labs + +//! Write secrets to a Vault TEE from environment variables + +#![deny(missing_docs)] +#![deny(clippy::all)] + +use anyhow::{Context, Result}; +use clap::Parser; +use serde_json::Value; +use std::collections::HashMap; +use std::env; +use teepot::client::vault::VaultConnection; +use teepot::server::attestation::VaultAttestationArgs; +use tracing::{debug, info, warn}; +use tracing_log::LogTracer; +use tracing_subscriber::{fmt, prelude::*, EnvFilter, Registry}; + +#[derive(Parser, Debug)] +#[command(author, version, about, long_about = None)] +struct Arguments { + /// turn on test mode + #[arg(long, hide = true)] + pub test: bool, + /// vault token + #[arg(long, env = "VAULT_TOKEN", hide = true)] + pub vault_token: String, + #[clap(flatten)] + pub attestation: VaultAttestationArgs, + /// name of this TEE to login to vault + #[arg(long, required = true)] + pub name: String, + /// name of this TEE to login to vault + #[arg(long)] + pub store_name: Option, + /// secrets to write to vault with the value of the environment variables + #[arg(long, required = true)] + pub secrets: Vec, +} + +#[actix_web::main] +async fn main() -> Result<()> { + LogTracer::init().context("Failed to set logger")?; + + let subscriber = Registry::default() + .with(EnvFilter::from_default_env()) + .with(fmt::layer().with_writer(std::io::stderr)); + tracing::subscriber::set_global_default(subscriber).unwrap(); + + let args = Arguments::parse(); + + // Split every string with a ',' into a vector of strings, flatten them and collect them. + let secrets = args + .secrets + .iter() + .flat_map(|s| s.split(',')) + .collect::>(); + + info!("args: {:?}", args); + + let conn = if args.test { + warn!("TEST MODE"); + let client = awc::Client::builder() + .add_default_header((actix_web::http::header::USER_AGENT, "teepot/1.0")) + .finish(); + // SAFETY: TEST MODE + unsafe { + VaultConnection::new_from_client_without_attestation( + args.attestation.vault_addr.clone(), + client, + args.name.clone(), + args.vault_token.clone(), + ) + } + } else { + VaultConnection::new(&args.attestation.clone().into(), args.name.clone()) + .await + .expect("connecting to vault") + }; + + let tee_name = args.store_name.unwrap_or(args.name.clone()); + + let env = env::vars() + .filter(|(k, _)| secrets.contains(&k.as_str())) + .collect::>(); + + for (secret_name, secret_val) in env { + debug!("storing secret {secret_name}: {secret_val}"); + let secret_val = Value::String(secret_val); + conn.store_secret_for_tee(&tee_name, &secret_val, &secret_name) + .await + .expect("storing secret"); + info!("stored secret {secret_name}"); + } + + Ok(()) +} diff --git a/bin/vault-admin/Cargo.toml b/bin/vault-admin/Cargo.toml new file mode 100644 index 0000000..b93b52e --- /dev/null +++ b/bin/vault-admin/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "vault-admin" +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true +repository.workspace = true + +[dependencies] +actix-web.workspace = true +anyhow.workspace = true +awc.workspace = true +bytemuck.workspace = true +clap.workspace = true +hex.workspace = true +pgp.workspace = true +serde.workspace = true +serde_json.workspace = true +sha2.workspace = true +teepot.workspace = true +tracing-log.workspace = true +tracing-subscriber.workspace = true +tracing.workspace = true diff --git a/bin/vault-admin/README.md b/bin/vault-admin/README.md new file mode 100644 index 0000000..7685279 --- /dev/null +++ b/bin/vault-admin/README.md @@ -0,0 +1,46 @@ +```bash +❯ idents=( tests/data/pub*.asc ) +❯ cargo run --bin vault-admin -p vault-admin -- \ + verify \ + ${idents[@]/#/-i } \ + tests/data/test.json \ + tests/data/test.json.asc + +Verified signature for `81A312C59D679D930FA9E8B06D728F29A2DBABF8` + +❯ RUST_LOG=info cargo run -p vault-admin -- \ + send \ + --sgx-mrsigner c5591a72b8b86e0d8814d6e8750e3efe66aea2d102b8ba2405365559b858697d \ + --sgx-allowed-tcb-levels SwHardeningNeeded \ + --server https://127.0.0.1:8444 \ + bin/tee-vault-admin/tests/data/test.json \ + bin/tee-vault-admin/tests/data/test.json.asc + +2023-08-04T10:51:14.919941Z INFO vault_admin: Quote verified! Connection secure! +2023-08-04T10:51:14.920430Z INFO tee_client: Getting attestation report +2023-08-04T10:51:15.020459Z INFO tee_client: Checked or set server certificate public key hash `f6dc06b9f2a14fa16a94c076a85eab8513f99ec0091801cc62c8761e42908fc1` +2023-08-04T10:51:15.024310Z INFO tee_client: Verifying attestation report +2023-08-04T10:51:15.052712Z INFO tee_client: TcbLevel is allowed: SwHardeningNeeded: Software hardening is needed +2023-08-04T10:51:15.054508Z WARN tee_client: Info: Advisory ID: INTEL-SA-00615 +2023-08-04T10:51:15.054572Z INFO tee_client: Report data matches `f6dc06b9f2a14fa16a94c076a85eab8513f99ec0091801cc62c8761e42908fc1` +2023-08-04T10:51:15.054602Z INFO tee_client: mrsigner `c5591a72b8b86e0d8814d6e8750e3efe66aea2d102b8ba2405365559b858697d` matches +[ + { + "request": { + "data": { + "lease": "1000", + "name": "test", + "sgx_allowed_tcb_levels": "Ok,SwHardeningNeeded", + "sgx_mrsigner": "c5591a72b8b86e0d8814d6e8750e3efe66aea2d102b8ba2405365559b858697d", + "token_policies": "test", + "types": "sgx" + }, + "url": "/v1/auth/tee/tees/test" + }, + "response": { + "status_code": 204, + "value": null + } + } +] +``` diff --git a/bin/vault-admin/src/main.rs b/bin/vault-admin/src/main.rs new file mode 100644 index 0000000..b6d93df --- /dev/null +++ b/bin/vault-admin/src/main.rs @@ -0,0 +1,366 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023 Matter Labs + +use anyhow::{anyhow, bail, Context, Result}; +use clap::{Args, Parser, Subcommand}; +use pgp::types::KeyTrait; +use pgp::{Deserializable, SignedPublicKey}; +use serde_json::Value; +use std::default::Default; +use std::fs::{File, OpenOptions}; +use std::io::{Read, Write}; +use std::path::{Path, PathBuf}; +use teepot::client::{AttestationArgs, TeeConnection}; +use teepot::json::http::{ + SignRequest, SignRequestData, SignResponse, VaultCommandRequest, VaultCommands, + VaultCommandsResponse, ATTESTATION_URL, DIGEST_URL, +}; +use teepot::server::signatures::verify_sig; +use teepot::sgx::sign::Signature; +use tracing::{error, info}; +use tracing_log::LogTracer; +use tracing_subscriber::Registry; +use tracing_subscriber::{fmt, prelude::*, EnvFilter}; + +#[derive(Args, Debug)] +struct SendArgs { + #[clap(flatten)] + pub attestation: AttestationArgs, + /// Vault command file + #[arg(required = true)] + pub command_file: PathBuf, + /// GPG signature files + #[arg(required = true)] + pub sigs: Vec, +} + +#[derive(Args, Debug)] +struct SignTeeArgs { + #[clap(flatten)] + pub attestation: AttestationArgs, + /// output file + #[arg(short, long, required = true)] + pub out: PathBuf, + /// signature request file + #[arg(required = true)] + pub sig_request_file: PathBuf, + /// GPG signature files + #[arg(required = true)] + pub sigs: Vec, +} + +#[derive(Args, Debug)] +struct DigestArgs { + #[clap(flatten)] + pub attestation: AttestationArgs, +} + +#[derive(Args, Debug)] +struct VerifyArgs { + /// GPG identity files + #[arg(short, long, required = true)] + pub idents: Vec, + /// Vault command file + #[arg(required = true)] + pub command_file: PathBuf, + /// GPG signature files + #[arg(required = true)] + pub sigs: Vec, +} + +#[derive(Args, Debug)] +struct CreateSignRequestArgs { + /// Last digest + #[arg(long)] + pub last_digest: Option, + /// TEE name + #[arg(long)] + pub tee_name: Option, + /// Vault command file + #[arg(required = true)] + pub sig_file: PathBuf, +} + +#[derive(Subcommand, Debug)] +enum SubCommands { + /// Send the signed commands to execute to the vault + Command(SendArgs), + /// Verify the signature(s) for the commands to send + Verify(VerifyArgs), + /// Get the digest of the last executed commands + Digest(DigestArgs), + /// Send the signed commands to execute to the vault + SignTee(SignTeeArgs), + /// Create a sign request + CreateSignRequest(CreateSignRequestArgs), +} + +/// Admin tool for the vault +#[derive(Parser, Debug)] +#[command(author, version, about, long_about = None)] +struct Arguments { + #[clap(subcommand)] + cmd: SubCommands, +} + +#[actix_web::main] +async fn main() -> Result<()> { + LogTracer::init().context("Failed to set logger")?; + + let subscriber = Registry::default() + .with(EnvFilter::from_default_env()) + .with(fmt::layer().with_writer(std::io::stderr)); + tracing::subscriber::set_global_default(subscriber).unwrap(); + + let args = Arguments::parse(); + info!("Quote verified! Connection secure!"); + + match args.cmd { + SubCommands::Command(args) => send_commands(args).await?, + SubCommands::SignTee(args) => send_sig_request(args).await?, + SubCommands::Verify(args) => { + verify(args.command_file, args.idents.iter(), args.sigs.iter())? + } + SubCommands::Digest(args) => digest(args).await?, + SubCommands::CreateSignRequest(args) => create_sign_request(args)?, + } + + Ok(()) +} + +fn create_sign_request(args: CreateSignRequestArgs) -> Result<()> { + let mut sigstruct_file = File::open(&args.sig_file)?; + let mut sigstruct_bytes = Vec::new(); + sigstruct_file.read_to_end(&mut sigstruct_bytes)?; + + let sigstruct = bytemuck::try_from_bytes::(&sigstruct_bytes) + .context(format!("parsing signature file {:?}", &args.sig_file))?; + + let body = sigstruct.body(); + let data = bytemuck::bytes_of(&body).to_vec(); + + let sign_request_data = SignRequestData { + data, + last_digest: args.last_digest.unwrap_or_default(), + tee_name: args.tee_name.unwrap_or_default(), + tee_type: "sgx".to_string(), + ..Default::default() + }; + + println!("{}", serde_json::to_string_pretty(&sign_request_data)?); + Ok(()) +} + +fn verify( + msg: impl AsRef, + idents_file_paths: impl Iterator>, + sig_paths: impl Iterator>, +) -> Result<()> { + let mut cmd_file = File::open(msg.as_ref())?; + let mut cmd_buf = Vec::new(); + cmd_file + .read_to_end(&mut cmd_buf) + .context(format!("reading command file {:?}", &cmd_file))?; + + let mut idents = Vec::new(); + for ident_file_path in idents_file_paths { + let ident_file = File::open(ident_file_path.as_ref()).context(format!( + "reading identity file {:?}", + ident_file_path.as_ref() + ))?; + idents.push( + SignedPublicKey::from_armor_single(ident_file) + .context(format!( + "reading identity file {:?}", + ident_file_path.as_ref() + ))? + .0, + ); + } + + for sig_path in sig_paths { + let mut sig_file = File::open(&sig_path) + .context(format!("reading signature file {:?}", sig_path.as_ref()))?; + let mut sig = String::new(); + sig_file + .read_to_string(&mut sig) + .context(format!("reading signature file {:?}", sig_path.as_ref()))?; + let ident_pos = verify_sig(&sig, &cmd_buf, &idents)?; + println!( + "Verified signature for `{}`", + hex::encode_upper(idents.get(ident_pos).unwrap().fingerprint()) + ); + // Remove the identity from the list of identities to verify + idents.remove(ident_pos); + } + + Ok(()) +} + +async fn send_commands(args: SendArgs) -> Result<()> { + // Read the command file into a string + let mut cmd_file = File::open(&args.command_file)?; + let mut commands = String::new(); + cmd_file.read_to_string(&mut commands)?; + + // Check that the command file is valid JSON + let vault_commands: VaultCommands = serde_json::from_str(&commands) + .context(format!("parsing command file {:?}", &args.command_file))?; + + let mut signatures = Vec::new(); + + for sig in args.sigs { + let mut sig_file = File::open(sig)?; + let mut sig = String::new(); + sig_file.read_to_string(&mut sig)?; + signatures.push(sig); + } + + let send_req = VaultCommandRequest { + commands, + signatures, + }; + + let conn = TeeConnection::new(&args.attestation, ATTESTATION_URL).await?; + + let mut response = conn + .client() + .post(&format!( + "{server}{url}", + server = conn.server(), + url = VaultCommandRequest::URL + )) + .send_json(&send_req) + .await + .map_err(|e| anyhow!("sending command request: {}", e))?; + + let status_code = response.status(); + if !status_code.is_success() { + error!("sending command request: {}", status_code); + if let Ok(r) = response.json::().await { + eprintln!( + "Error sending command request: {}", + serde_json::to_string(&r).unwrap_or_default() + ); + } + bail!("sending command request: {}", status_code); + } + + let cmd_responses: VaultCommandsResponse = response + .json() + .await + .context("failed parsing command response")?; + + println!("digest: {}", &cmd_responses.digest); + + let pairs = cmd_responses + .results + .iter() + .zip(vault_commands.commands.iter()) + .map(|(resp, cmd)| { + let mut pair = serde_json::Map::new(); + pair.insert("request".to_string(), serde_json::to_value(cmd).unwrap()); + pair.insert("response".to_string(), serde_json::to_value(resp).unwrap()); + pair + }) + .collect::>(); + + println!("{}", serde_json::to_string_pretty(&pairs)?); + Ok(()) +} + +async fn send_sig_request(args: SignTeeArgs) -> Result<()> { + // Read the command file into a string + let mut cmd_file = File::open(&args.sig_request_file)?; + let mut sign_request_data_str = String::new(); + cmd_file.read_to_string(&mut sign_request_data_str)?; + + // Check that the command file is valid JSON + let _sign_request_data: SignRequestData = serde_json::from_str(&sign_request_data_str) + .context(format!("parsing command file {:?}", &args.sig_request_file))?; + + let mut signatures = Vec::new(); + + for sig in args.sigs { + let mut sig_file = File::open(sig)?; + let mut sig = String::new(); + sig_file.read_to_string(&mut sig)?; + signatures.push(sig); + } + + // open out_file early to fail fast if it is not writable + let mut out_file = OpenOptions::new() + .create(true) + .write(true) + .open(&args.out)?; + + let send_req = SignRequest { + sign_request_data: sign_request_data_str, + signatures, + }; + + let conn = TeeConnection::new(&args.attestation, ATTESTATION_URL).await?; + + let mut response = conn + .client() + .post(&format!( + "{server}{url}", + server = conn.server(), + url = SignRequest::URL + )) + .send_json(&send_req) + .await + .map_err(|e| anyhow!("sending sign request: {}", e))?; + + let status_code = response.status(); + if !status_code.is_success() { + error!("sending sign request: {}", status_code); + if let Ok(r) = response.json::().await { + eprintln!( + "Error sending sign request: {}", + serde_json::to_string(&r).unwrap_or_default() + ); + } + bail!("sending sign request: {}", status_code); + } + + let sign_response: SignResponse = response + .json() + .await + .context("failed parsing sign response")?; + + println!("digest: {}", &sign_response.digest); + + out_file.write_all(&sign_response.signed_data)?; + + println!("{{ \"digest\": \"{}\" }}", sign_response.digest); + Ok(()) +} + +async fn digest(args: DigestArgs) -> Result<()> { + let conn = TeeConnection::new(&args.attestation, ATTESTATION_URL).await?; + + let mut response = conn + .client() + .get(&format!("{server}{DIGEST_URL}", server = conn.server())) + .send() + .await + .map_err(|e| anyhow!("sending digest request: {}", e))?; + + let status_code = response.status(); + if !status_code.is_success() { + error!("sending digest request: {}", status_code); + if let Ok(r) = response.json::().await { + eprintln!("Error sending digest request: {}", r); + } + bail!("sending digest request: {}", status_code); + } + + let digest_response: Value = response + .json() + .await + .context("failed parsing digest response")?; + + println!("{}", serde_json::to_string_pretty(&digest_response)?); + Ok(()) +} diff --git a/bin/vault-unseal/Cargo.toml b/bin/vault-unseal/Cargo.toml new file mode 100644 index 0000000..b9b9473 --- /dev/null +++ b/bin/vault-unseal/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "vault-unseal" +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true +repository.workspace = true + +[dependencies] +actix-web.workspace = true +anyhow.workspace = true +awc.workspace = true +base64.workspace = true +clap.workspace = true +hex.workspace = true +serde.workspace = true +serde_json.workspace = true +sha2.workspace = true +teepot.workspace = true +tracing-log.workspace = true +tracing-subscriber.workspace = true +tracing.workspace = true diff --git a/bin/vault-unseal/src/main.rs b/bin/vault-unseal/src/main.rs new file mode 100644 index 0000000..0e3142f --- /dev/null +++ b/bin/vault-unseal/src/main.rs @@ -0,0 +1,220 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023 Matter Labs + +use anyhow::{anyhow, bail, Context, Result}; +use base64::{engine::general_purpose, Engine as _}; +use clap::{Args, Parser, Subcommand}; +use serde_json::Value; +use std::fs::File; +use std::io::Read; +use teepot::client::{AttestationArgs, TeeConnection}; +use teepot::json::http::{Init, InitResponse, Unseal, ATTESTATION_URL}; +use tracing::{error, info, trace, warn}; +use tracing_log::LogTracer; +use tracing_subscriber::Registry; +use tracing_subscriber::{fmt, prelude::*, EnvFilter}; + +#[derive(Args, Debug)] +pub struct InitArgs { + /// admin threshold + #[arg(long)] + admin_threshold: usize, + /// PGP keys to sign commands for the admin tee + #[arg(short, long)] + admin_pgp_key_file: Vec, + /// admin TEE mrenclave + #[arg(long)] + admin_tee_mrenclave: String, + /// secret threshold + #[arg(long)] + unseal_threshold: usize, + /// PGP keys to encrypt the unseal keys with + #[arg(short, long)] + unseal_pgp_key_file: Vec, +} + +/// subcommands and their options/arguments. +#[derive(Subcommand, Debug)] +enum SubCommands { + Init(InitArgs), + Unseal, +} + +#[derive(Parser, Debug)] +#[command(author, version, about, long_about = None)] +struct Arguments { + #[clap(flatten)] + pub attestation: AttestationArgs, + /// Subcommands (with their own options) + #[clap(subcommand)] + cmd: SubCommands, +} + +#[actix_web::main] +async fn main() -> Result<()> { + LogTracer::init().context("Failed to set logger")?; + + let subscriber = Registry::default() + .with(EnvFilter::from_default_env()) + .with(fmt::layer().with_writer(std::io::stderr)); + tracing::subscriber::set_global_default(subscriber).unwrap(); + + let args = Arguments::parse(); + + match args.cmd { + SubCommands::Init(_) => init(args).await?, + SubCommands::Unseal => unseal(args).await?, + } + + Ok(()) +} + +async fn init(args: Arguments) -> Result<()> { + let conn = TeeConnection::new(&args.attestation, ATTESTATION_URL).await?; + + info!("Quote verified! Connection secure!"); + + let SubCommands::Init(init_args) = args.cmd else { + unreachable!() + }; + + if init_args.admin_threshold == 0 { + bail!("admin threshold must be greater than 0"); + } + + if init_args.unseal_threshold == 0 { + bail!("unseal threshold must be greater than 0"); + } + + if init_args.admin_threshold > init_args.admin_pgp_key_file.len() { + bail!("admin threshold must be less than or equal to the number of admin pgp keys"); + } + + if init_args.unseal_threshold > init_args.unseal_pgp_key_file.len() { + bail!("unseal threshold must be less than or equal to the number of unseal pgp keys"); + } + + let mut pgp_keys = Vec::new(); + + for filename in init_args.unseal_pgp_key_file { + let mut file = + File::open(&filename).context(format!("Failed to open pgp key file {}", &filename))?; + let mut buf = Vec::new(); + file.read_to_end(&mut buf)?; + let key = std::str::from_utf8(&buf)?.trim().to_string(); + pgp_keys.push(key); + } + + let mut admin_pgp_keys = Vec::new(); + + for filename in init_args.admin_pgp_key_file { + let mut file = + File::open(&filename).context(format!("Failed to open pgp key file {}", &filename))?; + // read all lines from file and concatenate them + let mut key = String::new(); + file.read_to_string(&mut key) + .context(format!("Failed to read pgp key file {}", &filename))?; + key.retain(|c| !c.is_ascii_whitespace()); + + let bytes = general_purpose::STANDARD.decode(key).context(format!( + "Failed to base64 decode pgp key file {}", + &filename + ))?; + admin_pgp_keys.push(bytes.into_boxed_slice()); + } + + let init = Init { + secret_shares: pgp_keys.len() as _, + secret_threshold: init_args.unseal_threshold, + admin_threshold: init_args.admin_threshold, + admin_tee_mrenclave: init_args.admin_tee_mrenclave, + admin_pgp_keys: admin_pgp_keys.into_boxed_slice(), + pgp_keys, + }; + + info!("Inititalizing vault"); + + let mut response = conn + .client() + .post(&format!( + "{server}{url}", + server = conn.server(), + url = Init::URL + )) + .send_json(&init) + .await + .map_err(|e| anyhow!("Error sending init request: {}", e))?; + + let status_code = response.status(); + if !status_code.is_success() { + error!("Failed to init vault: {}", status_code); + if let Ok(r) = response.json::().await { + eprintln!("Failed to init vault: {}", r); + } + bail!("failed to init vault: {}", status_code); + } + + let init_response: Value = response.json().await.context("failed to init vault")?; + + info!("Got Response: {}", init_response.to_string()); + + let resp: InitResponse = + serde_json::from_value(init_response).context("Failed to parse init response")?; + println!("{}", serde_json::to_string(&resp).unwrap()); + Ok(()) +} + +async fn unseal(args: Arguments) -> Result<()> { + info!("Reading unencrypted key from stdin"); + + // read all bytes from stdin + let mut stdin = std::io::stdin(); + let mut buf = Vec::new(); + stdin.read_to_end(&mut buf)?; + let key = std::str::from_utf8(&buf)?.trim().to_string(); + + if key.is_empty() { + bail!("Error reading key from stdin"); + } + + let conn = TeeConnection::new(&args.attestation, ATTESTATION_URL).await?; + + info!("Quote verified! Connection secure!"); + + info!("Unsealing vault"); + + let unseal_data = Unseal { key }; + + let mut response = conn + .client() + .post(&format!( + "{server}{url}", + server = conn.server(), + url = Unseal::URL + )) + .send_json(&unseal_data) + .await + .map_err(|e| anyhow!("Error sending unseal request: {}", e))?; + + let status_code = response.status(); + if !status_code.is_success() { + error!("Failed to unseal vault: {}", status_code); + if let Ok(r) = response.json::().await { + eprintln!("Failed to unseal vault: {}", r); + } + bail!("failed to unseal vault: {}", status_code); + } + + let unseal_response: Value = response.json().await.context("failed to unseal vault")?; + + trace!("Got Response: {}", unseal_response.to_string()); + + if matches!(unseal_response["sealed"].as_bool(), Some(true)) { + warn!("Vault is still sealed!"); + println!("Vault is still sealed!"); + } else { + info!("Vault is unsealed!"); + println!("Vault is unsealed!"); + } + Ok(()) +} diff --git a/bin/verify-attestation/Cargo.toml b/bin/verify-attestation/Cargo.toml new file mode 100644 index 0000000..4179836 --- /dev/null +++ b/bin/verify-attestation/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "verify-attestation" +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true +repository.workspace = true + +[dependencies] +anyhow.workspace = true +hex.workspace = true +intel-tee-quote-verification-rs.workspace = true +teepot.workspace = true diff --git a/bin/verify-attestation/Dockerfile b/bin/verify-attestation/Dockerfile new file mode 100644 index 0000000..627902a --- /dev/null +++ b/bin/verify-attestation/Dockerfile @@ -0,0 +1,46 @@ +FROM docker.io/rust:1-bullseye AS buildtee +RUN curl -fsSLo /usr/share/keyrings/intel.asc https://download.01.org/intel-sgx/sgx_repo/ubuntu/intel-sgx-deb.key \ + && echo "deb [arch=amd64 signed-by=/usr/share/keyrings/intel.asc] https://download.01.org/intel-sgx/sgx_repo/ubuntu focal main" > /etc/apt/sources.list.d/intel-sgx.list \ + && apt-get update \ + && apt-get install -y --no-install-recommends \ + build-essential \ + cmake \ + rsync \ + pkg-config \ + libssl-dev \ + libcurl4-openssl-dev \ + libprotobuf-dev \ + protobuf-compiler \ + clang \ + libsgx-headers \ + libsgx-dcap-quote-verify-dev + +WORKDIR /opt/vault/plugins + +WORKDIR /build +RUN --mount=type=bind,target=/data rsync --exclude='/.git' --filter="dir-merge,- .gitignore" --exclude "Dockerfile-*" --exclude 'tee-vault-admin.manifest.template' -av /data/ ./ +RUN --mount=type=cache,target=/usr/local/cargo/registry --mount=type=cache,target=target \ + RUSTFLAGS="-C target-cpu=icelake-server --cfg mio_unsupported_force_waker_pipe" \ + cargo build --locked --target x86_64-unknown-linux-gnu --release -p verify-attestation --bin verify-attestation \ + && mv ./target/x86_64-unknown-linux-gnu/release/verify-attestation ./ + +FROM docker.io/ubuntu:20.04 + +RUN apt-get update \ + && apt-get install -y curl + +RUN curl -fsSLo /usr/share/keyrings/intel.asc https://download.01.org/intel-sgx/sgx_repo/ubuntu/intel-sgx-deb.key \ + && echo "deb [arch=amd64 signed-by=/usr/share/keyrings/intel.asc] https://download.01.org/intel-sgx/sgx_repo/ubuntu focal main" > /etc/apt/sources.list.d/intel-sgx.list \ + && apt-get update \ + && apt-get install -y --no-install-recommends \ + libsgx-dcap-default-qpl \ + libsgx-urts \ + libsgx-enclave-common \ + libsgx-dcap-quote-verify +RUN apt purge -y libsgx-ae-qve +RUN rm -rf /var/lib/apt/lists/* + +COPY --from=buildtee /build/verify-attestation /bin/verify-attestation + +ENTRYPOINT ["/bin/sh", "-c"] +CMD [ "verify-attestation" ] diff --git a/bin/verify-attestation/src/main.rs b/bin/verify-attestation/src/main.rs new file mode 100644 index 0000000..14242a0 --- /dev/null +++ b/bin/verify-attestation/src/main.rs @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023 Matter Labs + +//! Simple TEE attestation verification test + +#![deny(missing_docs)] +#![deny(clippy::all)] + +use anyhow::{bail, Context, Result}; +use std::io::Read; +use std::time::UNIX_EPOCH; +use teepot::client::TcbLevel; +use teepot::sgx::{tee_qv_get_collateral, verify_quote_with_collateral, QuoteVerificationResult}; + +fn main() -> Result<()> { + // read myquote from stdin + let mut myquote = Vec::new(); + std::io::stdin() + .read_to_end(&mut myquote) + .context("Failed to read quote from stdin")?; + + let collateral = tee_qv_get_collateral(&myquote).context("Failed to get collateral")?; + + let unix_time: i64 = std::time::SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs() as _; + + let QuoteVerificationResult { + collateral_expired, + result, + + quote, + advisories, + .. + } = verify_quote_with_collateral(&myquote, Some(&collateral), unix_time.saturating_add(60)) + .context("Failed to verify quote with collateral")?; + + if collateral_expired { + bail!("Freshly fetched collateral expired"); + } + + let tcblevel = TcbLevel::from(result); + if tcblevel != TcbLevel::Ok { + println!("Quote verification result: {}", tcblevel); + } + + for advisory in advisories { + println!("\tInfo: Advisory ID: {advisory}"); + } + + println!("Quote verified successfully: {}", tcblevel); + println!("mrsigner: {}", hex::encode(quote.report_body.mrsigner)); + println!("mrenclave: {}", hex::encode(quote.report_body.mrenclave)); + println!("reportdata: {}", hex::encode(quote.report_body.reportdata)); + + Ok(()) +} diff --git a/crates/intel-tee-quote-verification-rs/Cargo.toml b/crates/intel-tee-quote-verification-rs/Cargo.toml new file mode 100644 index 0000000..2177dd3 --- /dev/null +++ b/crates/intel-tee-quote-verification-rs/Cargo.toml @@ -0,0 +1,11 @@ +# Fork of the original crate: https://github.com/intel/SGXDataCenterAttestationPrimitives + +[package] +name = "intel-tee-quote-verification-rs" +version = "0.2.1" +edition = "2021" +license = "BSD-3-Clause" + +[dependencies] +intel-tee-quote-verification-sys.workspace = true +serde.workspace = true diff --git a/crates/intel-tee-quote-verification-rs/License.txt b/crates/intel-tee-quote-verification-rs/License.txt new file mode 100644 index 0000000..c49d62f --- /dev/null +++ b/crates/intel-tee-quote-verification-rs/License.txt @@ -0,0 +1,38 @@ +BSD License + +Copyright (C) 2011-2021 Intel Corporation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +============================================================== + +pce.signed.dll, qve.signed.dll,id_enclave.signed.dll and qe3.signed.dll, +libsgx_pce.signed.so, libsgx_qve.signed.so, libsgx_id_enclave.signed.so, +libsgx_qe3.signed.so and libsgx_tdqe.signed.so are licensed under +3-Clause BSD License. + diff --git a/crates/intel-tee-quote-verification-rs/src/lib.rs b/crates/intel-tee-quote-verification-rs/src/lib.rs new file mode 100644 index 0000000..5f0714c --- /dev/null +++ b/crates/intel-tee-quote-verification-rs/src/lib.rs @@ -0,0 +1,553 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (C) 2011-2021 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +//! Intel(R) Software Guard Extensions Data Center Attestation Primitives (Intel(R) SGX DCAP) +//! Rust wrapper for Quote Verification Library +//! ================================================ +//! +//! This is a safe wrapper for **sgx-dcap-quoteverify-sys**. + +use serde::{Deserialize, Serialize}; +use std::marker::PhantomData; +use std::mem; +use std::ops::Deref; +use std::slice; + +use intel_tee_quote_verification_sys as qvl_sys; + +pub use qvl_sys::quote3_error_t; +pub use qvl_sys::sgx_ql_qe_report_info_t; +pub use qvl_sys::sgx_ql_qv_result_t; +pub use qvl_sys::sgx_ql_qv_supplemental_t; +pub use qvl_sys::sgx_ql_qve_collateral_t; +pub use qvl_sys::sgx_ql_request_policy_t; +pub use qvl_sys::sgx_qv_path_type_t; +pub use qvl_sys::tdx_ql_qve_collateral_t; +pub use qvl_sys::tee_supp_data_descriptor_t; + +/// When the Quoting Verification Library is linked to a process, it needs to know the proper enclave loading policy. +/// The library may be linked with a long lived process, such as a service, where it can load the enclaves and leave +/// them loaded (persistent). This better ensures that the enclaves will be available upon quote requests and not subject +/// to EPC limitations if loaded on demand. However, if the Quoting library is linked with an application process, there +/// may be many applications with the Quoting library and a better utilization of EPC is to load and unloaded the quoting +/// enclaves on demand (ephemeral). The library will be shipped with a default policy of loading enclaves and leaving +/// them loaded until the library is unloaded (PERSISTENT). If the policy is set to EPHEMERAL, then the QE and PCE will +/// be loaded and unloaded on-demand. If either enclave is already loaded when the policy is change to EPHEMERAL, the +/// enclaves will be unloaded before returning. +/// +/// # Param +/// - **policy**\ +/// Set the requested enclave loading policy to either *SGX_QL_PERSISTENT*, *SGX_QL_EPHEMERAL* or *SGX_QL_DEFAULT*. +/// +/// # Return +/// - ***SGX_QL_SUCCESS***\ +/// Successfully set the enclave loading policy for the quoting library's enclaves.\ +/// - ***SGX_QL_UNSUPPORTED_LOADING_POLICY***\ +/// The selected policy is not support by the quoting library.\ +/// - ***SGX_QL_ERROR_UNEXPECTED***\ +/// Unexpected internal error. +/// +/// # Examples +/// ``` +/// use intel_tee_quote_verification_rs::*; +/// +/// let policy = sgx_ql_request_policy_t::SGX_QL_DEFAULT; +/// let ret = sgx_qv_set_enclave_load_policy(policy); +/// +/// assert_eq!(ret, quote3_error_t::SGX_QL_SUCCESS); +/// ``` +pub fn sgx_qv_set_enclave_load_policy(policy: sgx_ql_request_policy_t) -> quote3_error_t { + unsafe { qvl_sys::sgx_qv_set_enclave_load_policy(policy) } +} + +/// Get SGX supplemental data required size. +/// +/// # Return +/// Size of the supplemental data in bytes. +/// +/// Status code of the operation, one of: +/// - *SGX_QL_ERROR_INVALID_PARAMETER* +/// - *SGX_QL_ERROR_QVL_QVE_MISMATCH* +/// - *SGX_QL_ENCLAVE_LOAD_ERROR* +/// +/// # Examples +/// ``` +/// use intel_tee_quote_verification_rs::*; +/// +/// let data_size = sgx_qv_get_quote_supplemental_data_size().unwrap(); +/// +/// assert_eq!(data_size, std::mem::size_of::() as u32); +/// ``` +pub fn sgx_qv_get_quote_supplemental_data_size() -> Result { + let mut data_size = 0u32; + unsafe { + match qvl_sys::sgx_qv_get_quote_supplemental_data_size(&mut data_size) { + quote3_error_t::SGX_QL_SUCCESS => Ok(data_size), + error_code => Err(error_code), + } + } +} + +/// Perform SGX ECDSA quote verification. +/// +/// # Param +/// - **quote**\ +/// SGX Quote, presented as u8 vector. +/// - **quote_collateral**\ +/// Quote Certification Collateral provided by the caller. +/// - **expiration_check_date**\ +/// This is the date that the QvE will use to determine if any of the inputted collateral have expired. +/// - **qve_report_info**\ +/// This parameter can be used in 2 ways.\ +/// - If qve_report_info is NOT None, the API will use Intel QvE to perform quote verification, and QvE will generate a report using the target_info in sgx_ql_qe_report_info_t structure.\ +/// - if qve_report_info is None, the API will use QVL library to perform quote verification, note that the results can not be cryptographically authenticated in this mode. +/// - **supplemental_data_size**\ +/// Size of the supplemental data (in bytes). +/// - **supplemental_data**\ +/// The parameter is optional. If it is None, supplemental_data_size must be 0. +/// +/// # Return +/// Result type of (collateral_expiration_status, verification_result). +/// +/// Status code of the operation, one of: +/// - *SGX_QL_ERROR_INVALID_PARAMETER* +/// - *SGX_QL_QUOTE_FORMAT_UNSUPPORTED* +/// - *SGX_QL_QUOTE_CERTIFICATION_DATA_UNSUPPORTED* +/// - *SGX_QL_UNABLE_TO_GENERATE_REPORT* +/// - *SGX_QL_CRL_UNSUPPORTED_FORMAT* +/// - *SGX_QL_ERROR_UNEXPECTED* +/// +pub fn sgx_qv_verify_quote( + quote: &[u8], + quote_collateral: Option<&Collateral>, + expiration_check_date: i64, + qve_report_info: Option<&mut sgx_ql_qe_report_info_t>, + supplemental_data_size: u32, + supplemental_data: Option<&mut sgx_ql_qv_supplemental_t>, +) -> Result<(u32, sgx_ql_qv_result_t), quote3_error_t> { + let mut collateral_expiration_status = 1u32; + let mut quote_verification_result = sgx_ql_qv_result_t::SGX_QL_QV_RESULT_UNSPECIFIED; + + let quote_collateral = quote_collateral.map(SgxQlQveCollateralT::from); + let p_quote_collateral = quote_collateral.as_deref().map_or(std::ptr::null(), |p| p); + + let p_qve_report_info = match qve_report_info { + Some(p) => p, + None => std::ptr::null_mut(), + }; + let p_supplemental_data = match supplemental_data { + Some(p) => p as *mut sgx_ql_qv_supplemental_t as *mut u8, + None => std::ptr::null_mut(), + }; + + unsafe { + match qvl_sys::sgx_qv_verify_quote( + quote.as_ptr(), + quote.len() as u32, + p_quote_collateral, + expiration_check_date, + &mut collateral_expiration_status, + &mut quote_verification_result, + p_qve_report_info, + supplemental_data_size, + p_supplemental_data, + ) { + quote3_error_t::SGX_QL_SUCCESS => { + Ok((collateral_expiration_status, quote_verification_result)) + } + error_code => Err(error_code), + } + } +} + +/// Get TDX supplemental data required size. +/// +/// # Return +/// Size of the supplemental data in bytes. +/// +/// Status code of the operation, one of: +/// - *SGX_QL_ERROR_INVALID_PARAMETER* +/// - *SGX_QL_ERROR_QVL_QVE_MISMATCH* +/// - *SGX_QL_ENCLAVE_LOAD_ERROR* +/// +/// # Examples +/// ``` +/// use intel_tee_quote_verification_rs::*; +/// +/// let data_size = tdx_qv_get_quote_supplemental_data_size().unwrap(); +/// +/// assert_eq!(data_size, std::mem::size_of::() as u32); +/// ``` +pub fn tdx_qv_get_quote_supplemental_data_size() -> Result { + let mut data_size = 0u32; + unsafe { + match qvl_sys::tdx_qv_get_quote_supplemental_data_size(&mut data_size) { + quote3_error_t::SGX_QL_SUCCESS => Ok(data_size), + error_code => Err(error_code), + } + } +} + +/// Perform TDX ECDSA quote verification. +/// +/// # Param +/// - **quote**\ +/// TDX Quote, presented as u8 vector. +/// - **quote_collateral**\ +/// Quote Certification Collateral provided by the caller. +/// - **expiration_check_date**\ +/// This is the date that the QvE will use to determine if any of the inputted collateral have expired. +/// - **qve_report_info**\ +/// This parameter can be used in 2 ways.\ +/// - If qve_report_info is NOT None, the API will use Intel QvE to perform quote verification, and QvE will generate a report using the target_info in sgx_ql_qe_report_info_t structure.\ +/// - if qve_report_info is None, the API will use QVL library to perform quote verification, note that the results can not be cryptographically authenticated in this mode. +/// - **supplemental_data_size**\ +/// Size of the supplemental data (in bytes). +/// - **supplemental_data**\ +/// The parameter is optional. If it is None, supplemental_data_size must be 0. +/// +/// # Return +/// Result type of (collateral_expiration_status, verification_result). +/// +/// Status code of the operation, one of: +/// - *SGX_QL_ERROR_INVALID_PARAMETER* +/// - *SGX_QL_QUOTE_FORMAT_UNSUPPORTED* +/// - *SGX_QL_QUOTE_CERTIFICATION_DATA_UNSUPPORTED* +/// - *SGX_QL_UNABLE_TO_GENERATE_REPORT* +/// - *SGX_QL_CRL_UNSUPPORTED_FORMAT* +/// - *SGX_QL_ERROR_UNEXPECTED* +/// +pub fn tdx_qv_verify_quote( + quote: &[u8], + quote_collateral: Option<&Collateral>, + expiration_check_date: i64, + qve_report_info: Option<&mut sgx_ql_qe_report_info_t>, + supplemental_data_size: u32, + supplemental_data: Option<&mut sgx_ql_qv_supplemental_t>, +) -> Result<(u32, sgx_ql_qv_result_t), quote3_error_t> { + let mut collateral_expiration_status = 1u32; + let mut quote_verification_result = sgx_ql_qv_result_t::SGX_QL_QV_RESULT_UNSPECIFIED; + + let quote_collateral = quote_collateral.map(SgxQlQveCollateralT::from); + let p_quote_collateral = quote_collateral.as_deref().map_or(std::ptr::null(), |p| p); + + let p_qve_report_info = match qve_report_info { + Some(p) => p, + None => std::ptr::null_mut(), + }; + let p_supplemental_data = match supplemental_data { + Some(p) => p as *mut sgx_ql_qv_supplemental_t as *mut u8, + None => std::ptr::null_mut(), + }; + + unsafe { + match qvl_sys::tdx_qv_verify_quote( + quote.as_ptr(), + quote.len() as u32, + p_quote_collateral, + expiration_check_date, + &mut collateral_expiration_status, + &mut quote_verification_result, + p_qve_report_info, + supplemental_data_size, + p_supplemental_data, + ) { + quote3_error_t::SGX_QL_SUCCESS => { + Ok((collateral_expiration_status, quote_verification_result)) + } + error_code => Err(error_code), + } + } +} + +/// Set the full path of QVE and QPL library.\ +/// The function takes the enum and the corresponding full path. +/// +/// # Param +/// - **path_type**\ +/// The type of binary being passed in. +/// - **path**\ +/// It should be a valid full path. +/// +/// # Return +/// - ***SGX_QL_SUCCESS***\ +/// Successfully set the full path. +/// - ***SGX_QL_ERROR_INVALID_PARAMETER***\ +/// Path is not a valid full path or the path is too long. +/// +#[cfg(target_os = "linux")] +pub fn sgx_qv_set_path(path_type: sgx_qv_path_type_t, path: &str) -> quote3_error_t { + match std::ffi::CString::new(path) { + Ok(path) => unsafe { qvl_sys::sgx_qv_set_path(path_type, path.as_ptr()) }, + _ => quote3_error_t::SGX_QL_ERROR_INVALID_PARAMETER, + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Collateral { + pub major_version: u16, + pub minor_version: u16, + pub tee_type: u32, + pub pck_crl_issuer_chain: Box<[u8]>, + pub root_ca_crl: Box<[u8]>, + pub pck_crl: Box<[u8]>, + pub tcb_info_issuer_chain: Box<[u8]>, + pub tcb_info: Box<[u8]>, + pub qe_identity_issuer_chain: Box<[u8]>, + pub qe_identity: Box<[u8]>, +} + +impl TryFrom<&sgx_ql_qve_collateral_t> for Collateral { + type Error = (); + + fn try_from(value: &sgx_ql_qve_collateral_t) -> Result { + fn to_boxed_slice(p: *mut ::std::os::raw::c_char, size: u32) -> Result, ()> { + if p.is_null() { + return Err(()); + } + Ok(Box::from(unsafe { + slice::from_raw_parts(p as _, size as _) + })) + } + + Ok(Collateral { + major_version: unsafe { value.__bindgen_anon_1.__bindgen_anon_1.major_version }, + minor_version: unsafe { value.__bindgen_anon_1.__bindgen_anon_1.minor_version }, + tee_type: value.tee_type, + pck_crl_issuer_chain: to_boxed_slice( + value.pck_crl_issuer_chain, + value.pck_crl_issuer_chain_size, + )?, + root_ca_crl: to_boxed_slice(value.root_ca_crl, value.root_ca_crl_size)?, + pck_crl: to_boxed_slice(value.pck_crl, value.pck_crl_size)?, + tcb_info_issuer_chain: to_boxed_slice( + value.tcb_info_issuer_chain, + value.tcb_info_issuer_chain_size, + )?, + tcb_info: to_boxed_slice(value.tcb_info, value.tcb_info_size)?, + qe_identity_issuer_chain: to_boxed_slice( + value.qe_identity_issuer_chain, + value.qe_identity_issuer_chain_size, + )?, + qe_identity: to_boxed_slice(value.qe_identity, value.qe_identity_size)?, + }) + } +} + +// referential struct +struct SgxQlQveCollateralT<'a> { + inner: sgx_ql_qve_collateral_t, + _phantom: PhantomData<&'a ()>, +} + +// create the referential struct +impl<'a> From<&'a Collateral> for SgxQlQveCollateralT<'a> { + fn from(data: &'a Collateral) -> Self { + let mut this = SgxQlQveCollateralT { + inner: sgx_ql_qve_collateral_t { + __bindgen_anon_1: Default::default(), + tee_type: data.tee_type, + pck_crl_issuer_chain: data.pck_crl_issuer_chain.as_ptr() as _, + pck_crl_issuer_chain_size: data.pck_crl_issuer_chain.len() as _, + root_ca_crl: data.root_ca_crl.as_ptr() as _, + root_ca_crl_size: data.root_ca_crl.len() as _, + pck_crl: data.pck_crl.as_ptr() as _, + pck_crl_size: data.pck_crl.len() as _, + tcb_info_issuer_chain: data.tcb_info_issuer_chain.as_ptr() as _, + tcb_info_issuer_chain_size: data.tcb_info_issuer_chain.len() as _, + tcb_info: data.tcb_info.as_ptr() as _, + tcb_info_size: data.tcb_info.len() as _, + qe_identity_issuer_chain: data.qe_identity_issuer_chain.as_ptr() as _, + qe_identity_issuer_chain_size: data.qe_identity_issuer_chain.len() as _, + qe_identity: data.qe_identity.as_ptr() as _, + qe_identity_size: data.qe_identity.len() as _, + }, + _phantom: PhantomData, + }; + this.inner.__bindgen_anon_1.__bindgen_anon_1.major_version = data.major_version; + this.inner.__bindgen_anon_1.__bindgen_anon_1.minor_version = data.minor_version; + this + } +} + +impl<'a> Deref for SgxQlQveCollateralT<'a> { + type Target = sgx_ql_qve_collateral_t; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +/// Get quote verification collateral. +/// +/// # Param +/// - **quote**\ +/// SGX/TDX Quote, presented as u8 vector. +/// +/// # Return +/// Result type of quote_collecteral. +/// +/// - **quote_collateral**\ +/// This is the Quote Certification Collateral retrieved based on Quote. +/// +/// Status code of the operation, one of: +/// - *SGX_QL_ERROR_INVALID_PARAMETER* +/// - *SGX_QL_PLATFORM_LIB_UNAVAILABLE* +/// - *SGX_QL_PCK_CERT_CHAIN_ERROR* +/// - *SGX_QL_PCK_CERT_UNSUPPORTED_FORMAT* +/// - *SGX_QL_QUOTE_FORMAT_UNSUPPORTED* +/// - *SGX_QL_OUT_OF_MEMORY* +/// - *SGX_QL_NO_QUOTE_COLLATERAL_DATA* +/// - *SGX_QL_ERROR_UNEXPECTED* +/// +pub fn tee_qv_get_collateral(quote: &[u8]) -> Result { + let mut buf = std::ptr::null_mut(); + let mut buf_len = 0u32; + + match unsafe { + qvl_sys::tee_qv_get_collateral(quote.as_ptr(), quote.len() as u32, &mut buf, &mut buf_len) + } { + quote3_error_t::SGX_QL_SUCCESS => { + assert!(!buf.is_null()); + assert!(buf_len > 0); + assert_eq!( + (buf as usize) % mem::align_of::(), + 0 + ); + // SAFETY: buf is not null, buf_len is not zero, and buf is aligned. + let orig_collateral = &unsafe { *(buf as *const sgx_ql_qve_collateral_t) }; + Collateral::try_from(orig_collateral).map_err(|_| quote3_error_t::SGX_QL_ERROR_MAX) + } + error_code => Err(error_code), + } +} + +/// Get supplemental data latest version and required size, support both SGX and TDX. +/// +/// # Param +/// - **quote**\ +/// SGX/TDX Quote, presented as u8 vector. +/// +/// # Return +/// Result type of (version, data_size) tuple. +/// +/// - **version**\ +/// Latest version of the supplemental data. +/// - **data_size**\ +/// The size of the buffer in bytes required to contain all of the supplemental data. +/// +pub fn tee_get_supplemental_data_version_and_size( + quote: &[u8], +) -> Result<(u32, u32), quote3_error_t> { + let mut version = 0u32; + let mut data_size = 0u32; + + unsafe { + match qvl_sys::tee_get_supplemental_data_version_and_size( + quote.as_ptr(), + quote.len() as u32, + &mut version, + &mut data_size, + ) { + quote3_error_t::SGX_QL_SUCCESS => Ok((version, data_size)), + error_code => Err(error_code), + } + } +} + +/// Perform quote verification for SGX and TDX.\ +/// This API works the same as the old one, but takes a new parameter to describe the supplemental data (supp_data_descriptor). +/// +/// # Param +/// - **quote**\ +/// SGX/TDX Quote, presented as u8 vector. +/// - **quote_collateral**\ +/// Quote Certification Collateral provided by the caller. +/// - **expiration_check_date**\ +/// This is the date that the QvE will use to determine if any of the inputted collateral have expired. +/// - **qve_report_info**\ +/// This parameter can be used in 2 ways.\ +/// - If qve_report_info is NOT None, the API will use Intel QvE to perform quote verification, and QvE will generate a report using the target_info in sgx_ql_qe_report_info_t structure.\ +/// - if qve_report_info is None, the API will use QVL library to perform quote verification, note that the results can not be cryptographically authenticated in this mode. +/// - **supp_datal_descriptor**\ +/// *tee_supp_data_descriptor_t* structure.\ +/// You can specify the major version of supplemental data by setting supp_datal_descriptor.major_version.\ +/// If supp_datal_descriptor is None, no supplemental data is returned.\ +/// If supp_datal_descriptor.major_version == 0, then return the latest version of the *sgx_ql_qv_supplemental_t* structure.\ +/// If supp_datal_descriptor.major_version <= latest supported version, return the latest minor version associated with that major version.\ +/// If supp_datal_descriptor.major_version > latest supported version, return an error *SGX_QL_SUPPLEMENTAL_DATA_VERSION_NOT_SUPPORTED*. +/// +/// # Return +/// Result type of (collateral_expiration_status, verification_result). +/// +/// Status code of the operation, one of: +/// - *SGX_QL_ERROR_INVALID_PARAMETER* +/// - *SGX_QL_QUOTE_FORMAT_UNSUPPORTED* +/// - *SGX_QL_QUOTE_CERTIFICATION_DATA_UNSUPPORTED* +/// - *SGX_QL_UNABLE_TO_GENERATE_REPORT* +/// - *SGX_QL_CRL_UNSUPPORTED_FORMAT* +/// - *SGX_QL_ERROR_UNEXPECTED* +/// +pub fn tee_verify_quote( + quote: &[u8], + quote_collateral: Option<&Collateral>, + expiration_check_date: i64, + qve_report_info: Option<&mut sgx_ql_qe_report_info_t>, + supp_data_descriptor: Option<&mut tee_supp_data_descriptor_t>, +) -> Result<(u32, sgx_ql_qv_result_t), quote3_error_t> { + let mut collateral_expiration_status = 1u32; + let mut quote_verification_result = sgx_ql_qv_result_t::SGX_QL_QV_RESULT_UNSPECIFIED; + + let quote_collateral = quote_collateral.map(SgxQlQveCollateralT::from); + let p_quote_collateral = quote_collateral.as_deref().map_or(std::ptr::null(), |p| p); + + let p_qve_report_info = qve_report_info.map_or(std::ptr::null_mut(), |p| p); + + let p_supp_data_descriptor = supp_data_descriptor.map_or(std::ptr::null_mut(), |p| p); + + unsafe { + match qvl_sys::tee_verify_quote( + quote.as_ptr(), + quote.len() as u32, + p_quote_collateral as _, + expiration_check_date, + &mut collateral_expiration_status, + &mut quote_verification_result, + p_qve_report_info, + p_supp_data_descriptor, + ) { + quote3_error_t::SGX_QL_SUCCESS => { + Ok((collateral_expiration_status, quote_verification_result)) + } + error_code => Err(error_code), + } + } +} diff --git a/crates/intel-tee-quote-verification-sys/Cargo.toml b/crates/intel-tee-quote-verification-sys/Cargo.toml new file mode 100644 index 0000000..a2597ef --- /dev/null +++ b/crates/intel-tee-quote-verification-sys/Cargo.toml @@ -0,0 +1,10 @@ +# Fork of the original crate: https://github.com/intel/SGXDataCenterAttestationPrimitives + +[package] +name = "intel-tee-quote-verification-sys" +version = "0.2.0" +edition = "2021" +license = "BSD-3-Clause" + +[build-dependencies] +bindgen.workspace = true diff --git a/crates/intel-tee-quote-verification-sys/License.txt b/crates/intel-tee-quote-verification-sys/License.txt new file mode 100644 index 0000000..c49d62f --- /dev/null +++ b/crates/intel-tee-quote-verification-sys/License.txt @@ -0,0 +1,38 @@ +BSD License + +Copyright (C) 2011-2021 Intel Corporation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of Intel Corporation nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +============================================================== + +pce.signed.dll, qve.signed.dll,id_enclave.signed.dll and qe3.signed.dll, +libsgx_pce.signed.so, libsgx_qve.signed.so, libsgx_id_enclave.signed.so, +libsgx_qe3.signed.so and libsgx_tdqe.signed.so are licensed under +3-Clause BSD License. + diff --git a/crates/intel-tee-quote-verification-sys/bindings.h b/crates/intel-tee-quote-verification-sys/bindings.h new file mode 100644 index 0000000..4735c32 --- /dev/null +++ b/crates/intel-tee-quote-verification-sys/bindings.h @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (C) 2011-2021 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "sgx_dcap_quoteverify.h" diff --git a/crates/intel-tee-quote-verification-sys/build.rs b/crates/intel-tee-quote-verification-sys/build.rs new file mode 100644 index 0000000..9f05778 --- /dev/null +++ b/crates/intel-tee-quote-verification-sys/build.rs @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (C) 2011-2021 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +use std::env; +use std::path::PathBuf; + +fn main() { + // Tell cargo to tell rustc to link the system + // sgx-dcap-quoteverify shared library. + println!("cargo:rustc-link-lib=sgx_dcap_quoteverify"); + + // Tell cargo to invalidate the built crate whenever the wrapper changes + println!("cargo:rerun-if-changed=bindings.h"); + + // Set sdk to search path if SGX_SDK is in environment variable + let mut sdk_inc = String::from(""); + if let Ok(val) = env::var("SGX_SDK") { + sdk_inc.push_str("-I"); + sdk_inc.push_str(&val); + sdk_inc.push_str("/include/"); + } + + // The bindgen::Builder is the main entry point + // to bindgen, and lets you build up options for + // the resulting bindings. + let bindings = bindgen::Builder::default() + // The input header we would like to generate + // bindings for. + .header("bindings.h") + // Include search path + .clang_arg(sdk_inc) + // Convert C enum to Rust enum + .rustified_enum("_quote3_error_t") + .rustified_enum("_sgx_ql_request_policy") + .rustified_enum("_sgx_ql_qv_result_t") + .rustified_enum("sgx_qv_path_type_t") + // Disable Debug trait for packed C structures + .no_debug("_quote_t") + .no_debug("_sgx_ql_auth_data_t") + .no_debug("_sgx_ql_certification_data_t") + .no_debug("_sgx_ql_ecdsa_sig_data_t") + .no_debug("_sgx_quote3_t") + .no_debug("_sgx_ql_att_key_id_param_t") + // Enable Default trait + .derive_default(true) + // Tell cargo to invalidate the built crate whenever any of the + // included header files changed. + .parse_callbacks(Box::new(bindgen::CargoCallbacks::new())) + // Finish the builder and generate the bindings. + .generate() + // Unwrap the Result and panic on failure. + .expect("Unable to generate bindings"); + + // Write the bindings to the $OUT_DIR/bindings.rs file. + let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + bindings + .write_to_file(out_path.join("bindings.rs")) + .expect("Couldn't write bindings!"); +} diff --git a/crates/intel-tee-quote-verification-sys/src/lib.rs b/crates/intel-tee-quote-verification-sys/src/lib.rs new file mode 100644 index 0000000..a06fa7e --- /dev/null +++ b/crates/intel-tee-quote-verification-sys/src/lib.rs @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: BSD-3-Clause +/* + * Copyright (C) 2011-2021 Intel Corporation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +//! Intel(R) Software Guard Extensions Data Center Attestation Primitives (Intel(R) SGX DCAP) +//! Rust raw FFI bindings for Quote Verification Library +//! ================================================ +//! +//! Please install the following prerequisite: +//! * Intel(R) SGX DCAP Driver +//! * Intel(R) SGX SDK +//! * Intel(R) SGX DCAP Packages +//! * Intel(R) SGX DCAP PCCS (Provisioning Certificate Caching Service) +//! +//! *Please refer to [SGX DCAP Linux installation guide]( +//! https://download.01.org/intel-sgx/latest/linux-latest/docs/Intel_SGX_SW_Installation_Guide_for_Linux.pdf) +//! to install above dependencies.* +//! +//! *Note that you need to install **libsgx-dcap-quote-verify-dev** and **clang** for this package.* + +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(clippy::missing_safety_doc)] +include!(concat!(env!("OUT_DIR"), "/bindings.rs")); diff --git a/deny.toml b/deny.toml new file mode 100644 index 0000000..afe1cbc --- /dev/null +++ b/deny.toml @@ -0,0 +1,76 @@ +targets = [] +all-features = false +no-default-features = false +feature-depth = 1 + +[advisories] +db-path = "~/.cargo/advisory-db" +db-urls = ["https://github.com/rustsec/advisory-db"] +vulnerability = "deny" +unmaintained = "warn" +yanked = "warn" +notice = "warn" +ignore = [ + # Sidechannel attack to get the private key https://rustsec.org/advisories/RUSTSEC-2023-0071 + # currently no rsa private key is used in the codebase, + # except for signing SGX enclaves, which is only triggered with enough admin signatures + "RUSTSEC-2023-0071", + # ed25519-dalek 2.0.0-rc.3 already contains the fix for RUSTSEC-2022-0093 + "RUSTSEC-2022-0093", +] + +[licenses] +unlicensed = "deny" +copyleft = "deny" +allow = [ + "MIT", + "Apache-2.0", + "ISC", + "Unlicense", + "MPL-2.0", + "Unicode-DFS-2016", + "CC0-1.0", + "BSD-2-Clause", + "BSD-3-Clause", + "OpenSSL", +] +deny = [] +allow-osi-fsf-free = "neither" +default = "deny" +confidence-threshold = 0.8 +exceptions = [] + +[[licenses.clarify]] +name = "ring" +version = "*" +expression = "MIT AND ISC AND OpenSSL" +license-files = [{ path = "LICENSE", hash = 0xbd0eed23 }] + +[licenses.private] +ignore = false +registries = [] + +[bans] +multiple-versions = "warn" +wildcards = "allow" +highlight = "all" +workspace-default-features = "allow" +external-default-features = "allow" +allow = [] +deny = [] +skip = [] +skip-tree = [] + +[sources] +unknown-registry = "warn" +unknown-git = "warn" +allow-registry = ["https://github.com/rust-lang/crates.io-index"] +allow-git = [ + # we need the mio override to disable eventfd for SGX + "https://github.com/tokio-rs/mio?rev=ec0776f5af29548e4e1f48f86f5fa123a46caa07#ec0776f5af29548e4e1f48f86f5fa123a46caa07", +] + +[sources.allow-org] +github = [""] +gitlab = [""] +bitbucket = [""] diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..ab7275e --- /dev/null +++ b/examples/README.md @@ -0,0 +1,241 @@ +# Scratch Notes for running the teepot vault setup + +## Build and Run on SGX server + +```bash +$ docker compose build +$ docker compose up +``` + +## Build and Run on client machine +```bash +$ cd teepot +$ gpg --export username@example.com | base64 > gpgkey.pub +❯ RUST_LOG=info cargo run -p vault-unseal -- --sgx-mrsigner c5591a72b8b86e0d8814d6e8750e3efe66aea2d102b8ba2405365559b858697d --sgx-allowed-tcb-levels SwHardeningNeeded --server https://20.172.154.218:8443 init --unseal-threshold 1 -u bin/tee-vault-admin/tests/data/gpgkey.pub --admin-threshold 1 -a bin/tee-vault-admin/tests/data/gpgkey.pub --admin-tee-mrenclave 21c8c1a4dbcce04798f5119eb47203084bc74e564a3c954d1a21172c656cb801 + Finished dev [unoptimized + debuginfo] target(s) in 0.09s + Running `target/debug/vault-unseal --sgx-mrsigner c5591a72b8b86e0d8814d6e8750e3efe66aea2d102b8ba2405365559b858697d --sgx-allowed-tcb-levels SwHardeningNeeded --server 'https://20.172.154.218:8443' init --unseal-threshold 1 -u bin/tee-vault-admin/tests/data/gpgkey.pub --admin-threshold 1 -a bin/tee-vault-admin/tests/data/gpgkey.pub --admin-tee-mrenclave 21c8c1a4dbcce04798f5119eb47203084bc74e564a3c954d1a21172c656cb801` +2023-08-23T14:47:56.902422Z INFO tee_client: Getting attestation report +2023-08-23T14:47:57.340877Z INFO tee_client: Checked or set server certificate public key hash `b4bf52fdb37431c8531fb310be389c2d17ad9bd41d662e10308c9147c007d0d0` +2023-08-23T14:47:57.741599Z INFO tee_client: Verifying attestation report +2023-08-23T14:47:57.763320Z INFO tee_client: TcbLevel is allowed: SwHardeningNeeded: Software hardening is needed +2023-08-23T14:47:57.763356Z WARN tee_client: Info: Advisory ID: INTEL-SA-00615 +2023-08-23T14:47:57.763371Z INFO tee_client: Report data matches `b4bf52fdb37431c8531fb310be389c2d17ad9bd41d662e10308c9147c007d0d0` +2023-08-23T14:47:57.763391Z INFO tee_client: mrsigner `c5591a72b8b86e0d8814d6e8750e3efe66aea2d102b8ba2405365559b858697d` matches +2023-08-23T14:47:57.763412Z INFO vault_unseal: Quote verified! Connection secure! +2023-08-23T14:47:57.763418Z INFO vault_unseal: Inititalizing vault +2023-08-23T14:48:07.278090Z INFO vault_unseal: Got Response: {"unseal_keys":["wcDMA9FaOxXbOhL7AQv7BoGfG5K+78RHV6LGqT5k/M1e8GP3pvBHTeY1lReCo2bkLmm4k4KBxdqNLSE8lV4urN5iWTAt74jCoC+uuAeA2OSL7AidX+HcftzcAXhJp2INtkyqsL8xGaPgpZxXj77fJ/Z7HW1mUlAxJowdZudvA5DmJls6u8VK6YtY3deLGbMRVygXFG+NGabNrRQ0nnFMMMCPXZ39ETitJyfFX6x4BizVQixagN9IqkozXLiupoHD4N0LOESDIm2MuqPnGAk0X6YgyZhFZc8uCrN9W/zNkXQ7eJxIamsLysVnPGaNQ92VQlz4aFAJLKrMCvGrtrxQJk9N+P47EArGCl9bP2hXfg783arXF6Bp/YgGgpvJRFZ04nMNDlIcIFuV5QBfiJX1hNIXg0MVlqmzVeGDVHlys+2mOvOO8seIBG1p4FGRQr6YWI4KxaN6sVA5DNclvITWiH/6H50SUJqXQ5M6rfEoBajYenpzZwYXb0oGzVHrUg5AnfPSuYRT0p8dAPz3/9vE0nEBzNeNVedEwwbgHP1aSPK8J3pPgoRVMyiq7gXzJEXoG5PLJEq4poQ1QwevAVTNv5Pu/TvTacDkJfVcBL5fukB9fj/WJktxEXmznEK3GMBBmvIAVLkgCEl+dH17CxvKq2ik6AfAHVdmEPcNw0ViNCZj1Q=="]} +{"unseal_keys":["wcDMA9FaOxXbOhL7AQv7BoGfG5K+78RHV6LGqT5k/M1e8GP3pvBHTeY1lReCo2bkLmm4k4KBxdqNLSE8lV4urN5iWTAt74jCoC+uuAeA2OSL7AidX+HcftzcAXhJp2INtkyqsL8xGaPgpZxXj77fJ/Z7HW1mUlAxJowdZudvA5DmJls6u8VK6YtY3deLGbMRVygXFG+NGabNrRQ0nnFMMMCPXZ39ETitJyfFX6x4BizVQixagN9IqkozXLiupoHD4N0LOESDIm2MuqPnGAk0X6YgyZhFZc8uCrN9W/zNkXQ7eJxIamsLysVnPGaNQ92VQlz4aFAJLKrMCvGrtrxQJk9N+P47EArGCl9bP2hXfg783arXF6Bp/YgGgpvJRFZ04nMNDlIcIFuV5QBfiJX1hNIXg0MVlqmzVeGDVHlys+2mOvOO8seIBG1p4FGRQr6YWI4KxaN6sVA5DNclvITWiH/6H50SUJqXQ5M6rfEoBajYenpzZwYXb0oGzVHrUg5AnfPSuYRT0p8dAPz3/9vE0nEBzNeNVedEwwbgHP1aSPK8J3pPgoRVMyiq7gXzJEXoG5PLJEq4poQ1QwevAVTNv5Pu/TvTacDkJfVcBL5fukB9fj/WJktxEXmznEK3GMBBmvIAVLkgCEl+dH17CxvKq2ik6AfAHVdmEPcNw0ViNCZj1Q=="]} + +❯ echo wcDMA9FaOxXbOhL7AQv7BoGfG5K+78RHV6LGqT5k/M1e8GP3pvBHTeY1lReCo2bkLmm4k4KBxdqNLSE8lV4urN5iWTAt74jCoC+uuAeA2OSL7AidX+HcftzcAXhJp2INtkyqsL8xGaPgpZxXj77fJ/Z7HW1mUlAxJowdZudvA5DmJls6u8VK6YtY3deLGbMRVygXFG+NGabNrRQ0nnFMMMCPXZ39ETitJyfFX6x4BizVQixagN9IqkozXLiupoHD4N0LOESDIm2MuqPnGAk0X6YgyZhFZc8uCrN9W/zNkXQ7eJxIamsLysVnPGaNQ92VQlz4aFAJLKrMCvGrtrxQJk9N+P47EArGCl9bP2hXfg783arXF6Bp/YgGgpvJRFZ04nMNDlIcIFuV5QBfiJX1hNIXg0MVlqmzVeGDVHlys+2mOvOO8seIBG1p4FGRQr6YWI4KxaN6sVA5DNclvITWiH/6H50SUJqXQ5M6rfEoBajYenpzZwYXb0oGzVHrUg5AnfPSuYRT0p8dAPz3/9vE0nEBzNeNVedEwwbgHP1aSPK8J3pPgoRVMyiq7gXzJEXoG5PLJEq4poQ1QwevAVTNv5Pu/TvTacDkJfVcBL5fukB9fj/WJktxEXmznEK3GMBBmvIAVLkgCEl+dH17CxvKq2ik6AfAHVdmEPcNw0ViNCZj1Q== | base64 --decode | gpg -dq | RUST_LOG=info cargo run -p vault-unseal -- --sgx-mrsigner c5591a72b8b86e0d8814d6e8750e3efe66aea2d102b8ba2405365559b858697d --sgx-allowed-tcb-levels SwHardeningNeeded --server https://20.172.154.218:8443 unseal + Finished dev [unoptimized + debuginfo] target(s) in 0.09s + Running `target/debug/vault-unseal --sgx-mrsigner c5591a72b8b86e0d8814d6e8750e3efe66aea2d102b8ba2405365559b858697d --sgx-allowed-tcb-levels SwHardeningNeeded --server 'https://20.172.154.218:8443' unseal` +2023-08-23T14:48:20.735605Z INFO tee_client: Getting attestation report +2023-08-23T14:48:21.349424Z INFO tee_client: Checked or set server certificate public key hash `b4bf52fdb37431c8531fb310be389c2d17ad9bd41d662e10308c9147c007d0d0` +2023-08-23T14:48:21.742086Z INFO tee_client: Verifying attestation report +2023-08-23T14:48:21.757960Z INFO tee_client: TcbLevel is allowed: SwHardeningNeeded: Software hardening is needed +2023-08-23T14:48:21.757996Z WARN tee_client: Info: Advisory ID: INTEL-SA-00615 +2023-08-23T14:48:21.758014Z INFO tee_client: Report data matches `b4bf52fdb37431c8531fb310be389c2d17ad9bd41d662e10308c9147c007d0d0` +2023-08-23T14:48:21.758039Z INFO tee_client: mrsigner `c5591a72b8b86e0d8814d6e8750e3efe66aea2d102b8ba2405365559b858697d` matches +2023-08-23T14:48:21.758060Z INFO vault_unseal: Quote verified! Connection secure! +2023-08-23T14:48:21.758065Z INFO vault_unseal: Unsealing vault +2023-08-23T14:49:28.144877Z INFO vault_unseal: Vault is unsealed! +Vault is unsealed! + +``` + +```bash +❯ (id=$(docker create tva); docker cp $id:/app/tee-vault-admin.sig ~/tee-vault-admin.sig; docker rm -v $id) +❯ cargo run -p vault-admin -- create-sign-request ~/tee-vault-admin.sig > ~/sign_admin_tee.json +❯ vim sign_admin_tee.json +❯ gpg --local-user test@example.com --detach-sign --armor ~/sign_admin_tee.json +❯ RUST_LOG=info cargo run -p vault-admin -- \ + sign-tee \ + --sgx-mrenclave 080c3210d5b6bcf47887101a554c117c21d80e75240bb70846c3e158a713ec65 \ + --sgx-allowed-tcb-levels SwHardeningNeeded \ + --server https://127.0.0.1:8444 \ + --out new_admin.sig \ + ~/sign_admin_tee.json ~/sign_admin_tee.json.asc + +❯ gramine-sgx-sigstruct-view new_admin.sig +Attributes: + mr_signer: 8392a970ea57f1f37fb8985d9394b26611b18a5d5591b7d9d58d23998a116298 + mr_enclave: 080c3210d5b6bcf47887101a554c117c21d80e75240bb70846c3e158a713ec65 + isv_prod_id: 0 + isv_svn: 0 + debug_enclave: False + +❯ RUST_LOG=info cargo run -p vault-admin -- digest --sgx-mrsigner 8392a970ea57f1f37fb8985d9394b26611b18a5d5591b7d9d58d23998a116298 --sgx-allowed-tcb-levels SwHardeningNeeded --server https://127.0.0.1:8444 + Finished dev [unoptimized + debuginfo] target(s) in 0.12s + Running `target/debug/vault-admin digest --sgx-mrsigner 8392a970ea57f1f37fb8985d9394b26611b18a5d5591b7d9d58d23998a116298 --sgx-allowed-tcb-levels SwHardeningNeeded --server 'https://127.0.0.1:8444'` +2023-09-01T09:13:40.502841Z INFO vault_admin: Quote verified! Connection secure! +2023-09-01T09:13:40.503374Z INFO tee_client: Getting attestation report +2023-09-01T09:13:40.810238Z INFO tee_client: Checked or set server certificate public key hash `6296a59283e8b70b5501cf391457bd618159df4c206a4c5b206afc5b324cdd91` +2023-09-01T09:13:41.110855Z INFO tee_client: Verifying attestation report +2023-09-01T09:13:41.131057Z INFO tee_client: TcbLevel is allowed: SwHardeningNeeded: Software hardening is needed +2023-09-01T09:13:41.131099Z WARN tee_client: Info: Advisory ID: INTEL-SA-00615 +2023-09-01T09:13:41.131121Z INFO tee_client: Report data matches `6296a59283e8b70b5501cf391457bd618159df4c206a4c5b206afc5b324cdd91` +2023-09-01T09:13:41.131143Z INFO tee_client: mrsigner `8392a970ea57f1f37fb8985d9394b26611b18a5d5591b7d9d58d23998a116298` matches +{ + "last_digest": "c9929fef9c87b5c7bb7c47b563c83c4609741245847f173de0bedb2b3a00daa8" +} + +``` + +```bash +❯ docker compose build && (docker compose rm; docker volume rm teepot_vault-storage teepot_ha-raft-1 teepot_shared-1 teepot_ha-raft-2 teepot_shared-2 teepot_ha-raft-3 teepot_shared-3; docke +r compose up --remove-orphans vault-1 tvu-1) +❯ (id=$(docker create teepot-admin); docker cp $id:/app/tee-vault-admin.sig ~/tee-vault-admin.sig; docker rm -v $id) +❯ gramine-sgx-sigstruct-view ~/tee-vault-admin.sig +Attributes: + mr_signer: c5591a72b8b86e0d8814d6e8750e3efe66aea2d102b8ba2405365559b858697d + mr_enclave: 265ca491bf13e2486fd67d12038fcce02f133c5d91277e42f58c0ab464d5b46b + isv_prod_id: 0 + isv_svn: 0 + debug_enclave: False +❯ RUST_LOG=info cargo run -p vault-unseal -- --sgx-mrsigner c5591a72b8b86e0d8814d6e8750e3efe66aea2d102b8ba2405365559b858697d --sgx-allowed-tcb-levels SwHardeningNeeded --server https://127.0.0.1:8413 init --unseal-threshold 1 -u tests/data/gpgkey.pub --admin-threshold 1 -a tests/data/gpgkey.pub --admin-tee-mrenclave 265ca491bf13e2486fd67d12038fcce02f133c5d91277e42f58c0ab464d5b46b +❯ export GPG_TTY=$(tty) +❯ gpg-connect-agent updatestartuptty /bye >/dev/null +❯ gpg-connect-agent reloadagent /bye +OK +❯ echo wcDMA9FaOxXbOhL7AQwAgMxP/gTv/3RY/lMGPyEAfmIgIRdvfkWf8Sl07blUXmMKfIYyTkksMZLNc0Kiqx1oUR1qbT85WjWDhwhWADEbIhNFnTGdZ/CI24Bl4Nc8Dv7EnvJ0hmJw5AydE5YHACktSYTVgqXR9W8j5BO5K/+LyudJaMvcZFJH44MwYL8hMDKZbIdvIVFFEg2O/cBQgZc+UHljZEX+ptmR1q4BJM0dK6Ol5+v+zQ8FiByf6wgXJ2SQCERkhkiAaKkcIpyW1q8zgqVy29e46B6hfalYe0wD7U9L4QPiAr7Ik8rHEXB5iQucyDuWj65CVJXPVZ2Y+Q1Fk+OPrtYe7yDqZwJs3SlgzI7GNL4x7UqWALhroYzbiWETNwlhF4UZLOQRP5gkCQlAP3LkJJAFtUAbeJy8IgMRCz4F4f8nUCVLf6MDelr9ZXukmuc9U0tkmidNO8R2QAQUMLCCLUCkNnNa/hZz+81EUcNrI24kGqTlZfJxBpc+nr3MJxqSQ+btvqt8eJWlP9UJ0nEBdm74wj7nsekgwwttyq77Z8lciHgTLsjtSwk4tMse6uedWcPEGXxDKGzLd3dyaQD96NCUYt/GbGXVYTkH5mZci59+fkbGFEsJZYGffFmt7pcL69aoctgEKwBUxVR+BESo+UV1qUKAfO92QTYeXCA4/A== | base64 --decode | gpg -dq | RUST_LOG=info cargo run -p vault-unseal -- --sgx-mrsigner c5591a72b8b86e0d8814d6e8750e3efe66aea2d102b8ba2405365559b858697d --sgx-allowed-tcb-levels SwHardeningNeeded --server https://127.0.0.1:8413 unseal Please enter the passphrase to unlock the OpenPGP secret key: +"test " +3072-bit RSA key, ID D15A3B15DB3A12FB, +created 2023-08-08 (main key ID 6D728F29A2DBABF8). + +Passphrase: +❯ (id=$(docker create teepot-stress); docker cp $id:/app/tee-stress-client.sig ~/tee-stress-client.sig; docker rm -v $id) + + +``` + +## Kubernetes + +Find out the `mr_enclave` value of the tee-vault-admin enclave and extract the sigstruct file: + +```bash +❯ docker run -v .:/mnt --pull always -it matterlabsrobot/teepot-tva:latest 'gramine-sgx-sigstruct-view tee-vault-admin.sig; cp tee-vault-admin.sig /mnt' +[...] +Attributes: + mr_signer: c5591a72b8b86e0d8814d6e8750e3efe66aea2d102b8ba2405365559b858697d + mr_enclave: 98a540dd7056584e2009c7cf7374f932fbb8e30a4c66cc815c9809620653f751 + isv_prod_id: 0 + isv_svn: 0 + debug_enclave: False +❯ ls -l ~/tee-vault-admin.sig +-rw-r--r--. 1 harald harald 1808 2. Nov 10:46 tee-vault-admin.sig +``` + +Start the vault service and pod and forward the port + +```bash +❯ kubectl apply \ + -f examples/k8s/data-1-persistentvolumeclaim.yaml \ + -f examples/k8s/shared-1-persistentvolumeclaim.yaml \ + -f examples/k8s/vault-1-pod.yaml \ + -f examples/k8s/vault-1-service.yaml +❯ kubectl port-forward pods/vault-1 8443 +``` + +Initialize the instance. +This can take up to 6 minutes, depending on the `performance_multiplier` setting in vault. +Adjust the `--admin-tee-mrenclave` parameter to match the `mr_enclave` value of the tee-vault-admin container. + +```bash +❯ RUST_LOG=info cargo run -p vault-unseal -- \ + --sgx-mrsigner c5591a72b8b86e0d8814d6e8750e3efe66aea2d102b8ba2405365559b858697d \ + --sgx-allowed-tcb-levels SwHardeningNeeded \ + --server https://127.0.0.1:8443 \ + init \ + --unseal-threshold 1 \ + --unseal-pgp-key-file ./tests/data/gpgkey.pub \ + --admin-threshold 1 \ + --admin-pgp-key-file ./tests/data/gpgkey.pub \ + --admin-tee-mrenclave 98a540dd7056584e2009c7cf7374f932fbb8e30a4c66cc815c9809620653f751 +``` + +Unseal the instance + +```bash +❯ echo \ + | base64 --decode \ + | gpg -dq \ + | RUST_LOG=info cargo run -p vault-unseal -- \ + --sgx-mrsigner c5591a72b8b86e0d8814d6e8750e3efe66aea2d102b8ba2405365559b858697d \ + --sgx-allowed-tcb-levels SwHardeningNeeded \ + --server https://127.0.0.1:8443 \ + unseal +``` + +End the port forwarding of vault-1 and start the rest of the nodes: + +```bash +❯ kubectl apply -f examples/k8s +``` + +Unseal the other vault instances: + +Every unseal secret holder has to do it, until the threshold is reached. + +```bash +❯ kubectl port-forward pods/vault-$NUM 8443 +❯ echo \ + | base64 --decode \ + | gpg -dq \ + | RUST_LOG=info cargo run -p vault-unseal -- \ + --sgx-mrsigner c5591a72b8b86e0d8814d6e8750e3efe66aea2d102b8ba2405365559b858697d \ + --sgx-allowed-tcb-levels SwHardeningNeeded \ + --server https://127.0.0.1:8443 \ + unseal +❯ kubectl port-forward pods/vault-3 8443 +❯ echo \ + | base64 --decode \ + | gpg -dq \ + | RUST_LOG=info cargo run -p vault-unseal -- \ + --sgx-mrsigner c5591a72b8b86e0d8814d6e8750e3efe66aea2d102b8ba2405365559b858697d \ + --sgx-allowed-tcb-levels SwHardeningNeeded \ + --server https://127.0.0.1:8443 \ + unseal +``` + +The vault cluster should now settle to be completely unsealed and synced. + +Start the vault-admin pod and forward the port: + +```bash +❯ kubectl port-forward pods/tee-vault-admin 8444 +``` + +Next is to sign the admin tee with the vault-admin tool: + +```bash +❯ cargo run -p vault-admin -- create-sign-request --tee-name admin ~/tee-vault-admin.sig > ~/tee-vault-admin.json +❯ gpg --local-user test@example.com --detach-sign --armor ~/tee-vault-admin.json +❯ cargo run -p vault-admin -- command \ + --server https://127.0.0.1:8444 \ + --sgx-allowed-tcb-levels SwHardeningNeeded \ + --out ~/tee-vault-admin-new.sig \ + ~/tee-vault-admin.json ~/tee-vault-admin.json.asc +``` + +Then replace `tee-vault-admin.sig` with `tee-vault-admin-new.sig` in the container image `matterlabsrobot/teepot-tva:latest` with this Dockerfile: + +```Dockerfile +FROM matterlabsrobot/teepot-tva:latest +COPY tee-vault-admin-new.sig /app/tee-vault-admin.sig +``` + +Build and push the new image: + +```bash +❯ docker build -t matterlabsrobot/teepot-tva-signed:latest . +❯ docker push matterlabsrobot/teepot-tva-signed:latest +``` + +Delete the old vault-admin pod and start the new one: + +```bash +❯ kubectl delete pod/tee-vault-admin +❯ kubectl apply -f examples/k8s/vault-admin-signed-pod.yaml +``` + +The new signed admin tee can now be used. diff --git a/examples/docker-compose.yml b/examples/docker-compose.yml new file mode 100644 index 0000000..132ef93 --- /dev/null +++ b/examples/docker-compose.yml @@ -0,0 +1,146 @@ +# From the main directory run: +# ❯ docker compose -f examples/docker-compose.yml --project-directory $PWD up +services: + tvu-1: + build: + context: . + dockerfile: bin/tee-vault-unseal/Dockerfile-azure + image: tee-vault-unseal + restart: "no" + ports: + - 8413:8443 + environment: + VAULT_ADDR: "https://vault-1:8210" + ALLOWED_TCB_LEVELS: "SwHardeningNeeded" + privileged: true + init: true + volumes: + - /run/aesmd:/run/aesmd + - /dev/sgx_enclave:/dev/sgx_enclave + - shared-1:/opt/vault/tls + vault-1: + build: + context: . + dockerfile: vault/Dockerfile + image: vault + restart: "no" + ports: + - 8210:8210 +# - 8211:8211 + environment: + VAULT_API_ADDR: "https://vault-1:8210" + VAULT_CLUSTER_ADDR: "https://vault-1:8211" + VAULT_RAFT_NODE_ID: "vault-1" + privileged: true + init: true + volumes: + - /run/aesmd:/run/aesmd + - /dev/sgx_enclave:/dev/sgx_enclave + - shared-1:/opt/vault/tls + - data-1:/opt/vault/data + + tvu-2: + image: tee-vault-unseal + restart: "no" + ports: + - 8423:8443 + environment: + VAULT_ADDR: "https://vault-2:8210" + ALLOWED_TCB_LEVELS: "SwHardeningNeeded" + privileged: true + init: true + volumes: + - /run/aesmd:/run/aesmd + - /dev/sgx_enclave:/dev/sgx_enclave + - shared-2:/opt/vault/tls + vault-2: + image: vault + restart: "no" + ports: + - 8220:8210 +# - 8221:8211 + environment: + VAULT_API_ADDR: "https://vault-2:8210" + VAULT_CLUSTER_ADDR: "https://vault-2:8211" + VAULT_RAFT_NODE_ID: "vault-2" + privileged: true + init: true + volumes: + - /run/aesmd:/run/aesmd + - /dev/sgx_enclave:/dev/sgx_enclave + - shared-2:/opt/vault/tls + - data-2:/opt/vault/data + + tvu-3: + image: tee-vault-unseal + restart: "no" + ports: + - 8433:8443 + environment: + VAULT_ADDR: "https://vault-3:8210" + ALLOWED_TCB_LEVELS: "SwHardeningNeeded" + privileged: true + init: true + volumes: + - /run/aesmd:/run/aesmd + - /dev/sgx_enclave:/dev/sgx_enclave + - shared-3:/opt/vault/tls + vault-3: + image: vault + restart: "no" + ports: + - 8230:8210 +# - 8231:8211 + environment: + VAULT_API_ADDR: "https://vault-3:8210" + VAULT_CLUSTER_ADDR: "https://vault-3:8211" + VAULT_RAFT_NODE_ID: "vault-3" + privileged: true + init: true + volumes: + - /run/aesmd:/run/aesmd + - /dev/sgx_enclave:/dev/sgx_enclave + - shared-3:/opt/vault/tls + - data-3:/opt/vault/data + + admin: + build: + context: . + dockerfile: bin/tee-vault-admin/Dockerfile-azure + restart: "no" + ports: + - 8444:8444 + environment: + VAULT_ADDR: "https://vault-1:8210" + VAULT_SGX_MRSIGNER: "c5591a72b8b86e0d8814d6e8750e3efe66aea2d102b8ba2405365559b858697d" + VAULT_SGX_ALLOWED_TCB_LEVELS: "SwHardeningNeeded" + ALLOWED_TCB_LEVELS: "SwHardeningNeeded" + privileged: true + init: true + volumes: + - /run/aesmd:/run/aesmd + - /dev/sgx_enclave:/dev/sgx_enclave + + stress: + build: + context: . + dockerfile: bin/tee-stress-client/Dockerfile-azure + restart: "no" + environment: + VAULT_ADDR: "https://vault-1:8210" + VAULT_SGX_MRSIGNER: "c5591a72b8b86e0d8814d6e8750e3efe66aea2d102b8ba2405365559b858697d" + VAULT_SGX_ALLOWED_TCB_LEVELS: "SwHardeningNeeded" + ALLOWED_TCB_LEVELS: "SwHardeningNeeded" + privileged: true + init: true + volumes: + - /run/aesmd:/run/aesmd + - /dev/sgx_enclave:/dev/sgx_enclave + +volumes: + shared-1: + data-1: + shared-2: + data-2: + shared-3: + data-3: diff --git a/examples/k8s/data-1-persistentvolumeclaim.yaml b/examples/k8s/data-1-persistentvolumeclaim.yaml new file mode 100644 index 0000000..b90e11a --- /dev/null +++ b/examples/k8s/data-1-persistentvolumeclaim.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + labels: + io.kompose.service: data-1 + name: data-1 + namespace: default +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 100Mi +status: {} diff --git a/examples/k8s/data-2-persistentvolumeclaim.yaml b/examples/k8s/data-2-persistentvolumeclaim.yaml new file mode 100644 index 0000000..520afd8 --- /dev/null +++ b/examples/k8s/data-2-persistentvolumeclaim.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + labels: + io.kompose.service: data-2 + name: data-2 + namespace: default +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 100Mi +status: {} diff --git a/examples/k8s/data-3-persistentvolumeclaim.yaml b/examples/k8s/data-3-persistentvolumeclaim.yaml new file mode 100644 index 0000000..321acfa --- /dev/null +++ b/examples/k8s/data-3-persistentvolumeclaim.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + labels: + io.kompose.service: data-3 + name: data-3 + namespace: default +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 100Mi +status: {} diff --git a/examples/k8s/shared-1-persistentvolumeclaim.yaml b/examples/k8s/shared-1-persistentvolumeclaim.yaml new file mode 100644 index 0000000..f9eefa5 --- /dev/null +++ b/examples/k8s/shared-1-persistentvolumeclaim.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + labels: + io.kompose.service: shared-1 + name: shared-1 + namespace: default +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 100Mi +status: {} diff --git a/examples/k8s/shared-2-persistentvolumeclaim.yaml b/examples/k8s/shared-2-persistentvolumeclaim.yaml new file mode 100644 index 0000000..48b34b4 --- /dev/null +++ b/examples/k8s/shared-2-persistentvolumeclaim.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + labels: + io.kompose.service: shared-2 + name: shared-2 + namespace: default +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 100Mi +status: {} diff --git a/examples/k8s/shared-3-persistentvolumeclaim.yaml b/examples/k8s/shared-3-persistentvolumeclaim.yaml new file mode 100644 index 0000000..ff76a83 --- /dev/null +++ b/examples/k8s/shared-3-persistentvolumeclaim.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + labels: + io.kompose.service: shared-3 + name: shared-3 + namespace: default +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 100Mi +status: {} diff --git a/examples/k8s/vault-1-pod.yaml b/examples/k8s/vault-1-pod.yaml new file mode 100644 index 0000000..dbc13e5 --- /dev/null +++ b/examples/k8s/vault-1-pod.yaml @@ -0,0 +1,97 @@ +apiVersion: v1 +kind: Pod +metadata: + annotations: + kompose.cmd: kompose convert + labels: + io.kompose.network/teepot-default: "true" + io.kompose.service: vault-1 + app: vault + name: vault-1 + namespace: default +spec: + tolerations: + - key: sgx.intel.com/provision + operator: Exists + effect: NoSchedule + affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - topologyKey: kubernetes.io/hostname + labelSelector: + matchExpressions: + - key: app + operator: In + values: + - vault + imagePullSecrets: + - name: docker-regcred + containers: + - image: matterlabsrobot/teepot-vault:latest + name: vault + imagePullPolicy: Always + env: + - name: VAULT_API_ADDR + value: "https://vault-1:8210" + - name: VAULT_CLUSTER_ADDR + value: "https://vault-1:8211" + - name: VAULT_RAFT_NODE_ID + value: "vault-1" + readinessProbe: + exec: + command: + - curl + - -k + - https://localhost:8210/v1/sys/health + initialDelaySeconds: 5 + periodSeconds: 5 + ports: + - containerPort: 8210 + hostPort: 8210 + protocol: TCP + - containerPort: 8211 + hostPort: 8211 + protocol: TCP + resources: + limits: + sgx.intel.com/epc: "10Mi" + requests: + sgx.intel.com/epc: "10Mi" + securityContext: + privileged: true + volumeMounts: + - mountPath: /opt/vault/tls + name: shared-1 + - mountPath: /opt/vault/data + name: data-1 + - image: matterlabsrobot/teepot-tvu:latest + name: vault-unseal + imagePullPolicy: Always + env: + - name: VAULT_ADDR + value: "https://vault-1:8210" + - name: ALLOWED_TCB_LEVELS + value: "SwHardeningNeeded" + ports: + - containerPort: 8443 + hostPort: 8443 + protocol: TCP + resources: + limits: + sgx.intel.com/epc: "10Mi" + requests: + sgx.intel.com/epc: "10Mi" + securityContext: + privileged: true + volumeMounts: + - mountPath: /opt/vault/tls + name: shared-1 + restartPolicy: Never + volumes: + - name: shared-1 + persistentVolumeClaim: + claimName: shared-1 + - name: data-1 + persistentVolumeClaim: + claimName: data-1 +status: {} diff --git a/examples/k8s/vault-1-service.yaml b/examples/k8s/vault-1-service.yaml new file mode 100644 index 0000000..a942ee6 --- /dev/null +++ b/examples/k8s/vault-1-service.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: Service +metadata: + annotations: + kompose.cmd: kompose convert + + labels: + io.kompose.service: vault-1 + name: vault-1 + namespace: default +spec: + ports: + - name: "8210" + port: 8210 + targetPort: 8210 + - name: "8211" + port: 8211 + targetPort: 8211 + selector: + io.kompose.service: vault-1 diff --git a/examples/k8s/vault-2-pod.yaml b/examples/k8s/vault-2-pod.yaml new file mode 100644 index 0000000..c8e739c --- /dev/null +++ b/examples/k8s/vault-2-pod.yaml @@ -0,0 +1,97 @@ +apiVersion: v1 +kind: Pod +metadata: + annotations: + kompose.cmd: kompose convert + labels: + io.kompose.network/teepot-default: "true" + io.kompose.service: vault-2 + app: vault + name: vault-2 + namespace: default +spec: + tolerations: + - key: sgx.intel.com/provision + operator: Exists + effect: NoSchedule + affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - topologyKey: kubernetes.io/hostname + labelSelector: + matchExpressions: + - key: app + operator: In + values: + - vault + imagePullSecrets: + - name: docker-regcred + containers: + - image: matterlabsrobot/teepot-vault:latest + name: vault + imagePullPolicy: Always + env: + - name: VAULT_API_ADDR + value: "https://vault-2:8210" + - name: VAULT_CLUSTER_ADDR + value: "https://vault-2:8211" + - name: VAULT_RAFT_NODE_ID + value: "vault-2" + readinessProbe: + exec: + command: + - curl + - -k + - https://localhost:8210/v1/sys/health + initialDelaySeconds: 5 + periodSeconds: 5 + ports: + - containerPort: 8210 + hostPort: 8210 + protocol: TCP + - containerPort: 8211 + hostPort: 8211 + protocol: TCP + resources: + limits: + sgx.intel.com/epc: "10Mi" + requests: + sgx.intel.com/epc: "10Mi" + securityContext: + privileged: true + volumeMounts: + - mountPath: /opt/vault/tls + name: shared-2 + - mountPath: /opt/vault/data + name: data-2 + - image: matterlabsrobot/teepot-tvu:latest + name: vault-unseal + imagePullPolicy: Always + env: + - name: VAULT_ADDR + value: "https://vault-2:8210" + - name: ALLOWED_TCB_LEVELS + value: "SwHardeningNeeded" + ports: + - containerPort: 8443 + hostPort: 8443 + protocol: TCP + resources: + limits: + sgx.intel.com/epc: "10Mi" + requests: + sgx.intel.com/epc: "10Mi" + securityContext: + privileged: true + volumeMounts: + - mountPath: /opt/vault/tls + name: shared-2 + restartPolicy: Never + volumes: + - name: shared-2 + persistentVolumeClaim: + claimName: shared-2 + - name: data-2 + persistentVolumeClaim: + claimName: data-2 +status: {} diff --git a/examples/k8s/vault-2-service.yaml b/examples/k8s/vault-2-service.yaml new file mode 100644 index 0000000..29f2ea1 --- /dev/null +++ b/examples/k8s/vault-2-service.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: Service +metadata: + annotations: + kompose.cmd: kompose convert + + labels: + io.kompose.service: vault-2 + name: vault-2 + namespace: default +spec: + ports: + - name: "8210" + port: 8210 + targetPort: 8210 + - name: "8211" + port: 8211 + targetPort: 8211 + selector: + io.kompose.service: vault-2 diff --git a/examples/k8s/vault-3-pod.yaml b/examples/k8s/vault-3-pod.yaml new file mode 100644 index 0000000..2d5b975 --- /dev/null +++ b/examples/k8s/vault-3-pod.yaml @@ -0,0 +1,97 @@ +apiVersion: v1 +kind: Pod +metadata: + annotations: + kompose.cmd: kompose convert + labels: + io.kompose.network/teepot-default: "true" + io.kompose.service: vault-3 + app: vault + name: vault-3 + namespace: default +spec: + tolerations: + - key: sgx.intel.com/provision + operator: Exists + effect: NoSchedule + affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - topologyKey: kubernetes.io/hostname + labelSelector: + matchExpressions: + - key: app + operator: In + values: + - vault + imagePullSecrets: + - name: docker-regcred + containers: + - image: matterlabsrobot/teepot-vault:latest + name: vault + imagePullPolicy: Always + env: + - name: VAULT_API_ADDR + value: "https://vault-3:8210" + - name: VAULT_CLUSTER_ADDR + value: "https://vault-3:8211" + - name: VAULT_RAFT_NODE_ID + value: "vault-3" + readinessProbe: + exec: + command: + - curl + - -k + - https://localhost:8210/v1/sys/health + initialDelaySeconds: 5 + periodSeconds: 5 + ports: + - containerPort: 8210 + hostPort: 8210 + protocol: TCP + - containerPort: 8211 + hostPort: 8211 + protocol: TCP + resources: + limits: + sgx.intel.com/epc: "10Mi" + requests: + sgx.intel.com/epc: "10Mi" + securityContext: + privileged: true + volumeMounts: + - mountPath: /opt/vault/tls + name: shared-3 + - mountPath: /opt/vault/data + name: data-3 + - image: matterlabsrobot/teepot-tvu:latest + name: vault-unseal + imagePullPolicy: Always + env: + - name: VAULT_ADDR + value: "https://vault-3:8210" + - name: ALLOWED_TCB_LEVELS + value: "SwHardeningNeeded" + ports: + - containerPort: 8443 + hostPort: 8443 + protocol: TCP + resources: + limits: + sgx.intel.com/epc: "10Mi" + requests: + sgx.intel.com/epc: "10Mi" + securityContext: + privileged: true + volumeMounts: + - mountPath: /opt/vault/tls + name: shared-3 + restartPolicy: Never + volumes: + - name: shared-3 + persistentVolumeClaim: + claimName: shared-3 + - name: data-3 + persistentVolumeClaim: + claimName: data-3 +status: {} diff --git a/examples/k8s/vault-3-service.yaml b/examples/k8s/vault-3-service.yaml new file mode 100644 index 0000000..41e7aa7 --- /dev/null +++ b/examples/k8s/vault-3-service.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: Service +metadata: + annotations: + kompose.cmd: kompose convert + + labels: + io.kompose.service: vault-3 + name: vault-3 + namespace: default +spec: + ports: + - name: "8210" + port: 8210 + targetPort: 8210 + - name: "8211" + port: 8211 + targetPort: 8211 + selector: + io.kompose.service: vault-3 diff --git a/examples/k8s/vault-ha-serice.yaml b/examples/k8s/vault-ha-serice.yaml new file mode 100644 index 0000000..cffeec9 --- /dev/null +++ b/examples/k8s/vault-ha-serice.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + annotations: + kompose.cmd: kompose convert + labels: + io.kompose.service: vault-ha + name: vault-ha + namespace: default +spec: + ports: + - name: "8210" + port: 8210 + targetPort: 8210 + - name: "8211" + port: 8211 + targetPort: 8211 + selector: + app: vault diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..88a9946 --- /dev/null +++ b/flake.lock @@ -0,0 +1,258 @@ +{ + "nodes": { + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1650374568, + "narHash": "sha256-Z+s0J8/r907g149rllvwhb4pKi8Wam5ij0st8PwAh+E=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "b4a34015c698c7793d592d66adbab377907a2be8", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1705309234, + "narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils-plus": { + "inputs": { + "flake-utils": "flake-utils_2" + }, + "locked": { + "lastModified": 1696331477, + "narHash": "sha256-YkbRa/1wQWdWkVJ01JvV+75KIdM37UErqKgTf0L54Fk=", + "owner": "gytis-ivaskevicius", + "repo": "flake-utils-plus", + "rev": "bfc53579db89de750b25b0c5e7af299e0c06d7d3", + "type": "github" + }, + "original": { + "owner": "gytis-ivaskevicius", + "repo": "flake-utils-plus", + "type": "github" + } + }, + "flake-utils_2": { + "inputs": { + "systems": "systems_2" + }, + "locked": { + "lastModified": 1694529238, + "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "ff7b65b44d01cf9ba6a71320833626af21126384", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_3": { + "inputs": { + "systems": "systems_3" + }, + "locked": { + "lastModified": 1705309234, + "narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nix-filter": { + "locked": { + "lastModified": 1705332318, + "narHash": "sha256-kcw1yFeJe9N4PjQji9ZeX47jg0p9A0DuU4djKvg1a7I=", + "owner": "numtide", + "repo": "nix-filter", + "rev": "3449dc925982ad46246cfc36469baf66e1b64f17", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "nix-filter", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1706515015, + "narHash": "sha256-eFfY5A7wlYy3jD/75lx6IJRueg4noE+jowl0a8lIlVo=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "f4a8d6d5324c327dcc2d863eb7f3cc06ad630df4", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-23.11", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1706487304, + "narHash": "sha256-LE8lVX28MV2jWJsidW13D2qrHU/RUUONendL2Q/WlJg=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "90f456026d284c22b3e3497be980b2e47d0b28ac", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixsgx-flake": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ], + "snowfall-lib": "snowfall-lib" + }, + "locked": { + "lastModified": 1706717028, + "narHash": "sha256-paQ5fBXWRpYdQMXphi8/gahl3/ptej4kncqxsMFguH4=", + "owner": "haraldh", + "repo": "nixsgx", + "rev": "ff39bbbbbf7e88a28eeace784784839f1bf7e3b0", + "type": "github" + }, + "original": { + "owner": "haraldh", + "repo": "nixsgx", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nix-filter": "nix-filter", + "nixpkgs": "nixpkgs", + "nixsgx-flake": "nixsgx-flake", + "rust-overlay": "rust-overlay" + } + }, + "rust-overlay": { + "inputs": { + "flake-utils": "flake-utils_3", + "nixpkgs": "nixpkgs_2" + }, + "locked": { + "lastModified": 1706753617, + "narHash": "sha256-ZKqTFzhFwSWFEpQTJ0uXnfJBs5Y/po9/8TK4bzssdbs=", + "owner": "oxalica", + "repo": "rust-overlay", + "rev": "58be43ae223034217ea1bd58c73210644031b687", + "type": "github" + }, + "original": { + "owner": "oxalica", + "repo": "rust-overlay", + "type": "github" + } + }, + "snowfall-lib": { + "inputs": { + "flake-compat": "flake-compat", + "flake-utils-plus": "flake-utils-plus", + "nixpkgs": [ + "nixsgx-flake", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1696432959, + "narHash": "sha256-oJQZv2MYyJaVyVJY5IeevzqpGvMGKu5pZcCCJvb+xjc=", + "owner": "snowfallorg", + "repo": "lib", + "rev": "92803a029b5314d4436a8d9311d8707b71d9f0b6", + "type": "github" + }, + "original": { + "owner": "snowfallorg", + "repo": "lib", + "type": "github" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_3": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..f43378a --- /dev/null +++ b/flake.nix @@ -0,0 +1,115 @@ +{ + description = "teepot"; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs/nixos-23.11"; + + nix-filter.url = "github:numtide/nix-filter"; + flake-utils.url = "github:numtide/flake-utils"; + + nixsgx-flake = { + url = "github:matter-labs/nixsgx"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + rust-overlay.url = "github:oxalica/rust-overlay"; + }; + + outputs = { self, nixpkgs, flake-utils, nix-filter, nixsgx-flake, rust-overlay }: + flake-utils.lib.eachDefaultSystem (system: + let + pkgs = import nixpkgs { inherit system; overlays = [ (import rust-overlay) nixsgx-flake.overlays.default ]; }; + rustVersion = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml; + makeRustPlatform = pkgs.makeRustPlatform.override { + stdenv = pkgs.stdenvAdapters.useMoldLinker pkgs.gccStdenv; + }; + rustPlatform = makeRustPlatform { + cargo = rustVersion; + rustc = rustVersion; + }; + + filter = nix-filter.lib; + + bin = rustPlatform.buildRustPackage { + pname = "teepot"; + version = "0.1.0"; + + nativeBuildInputs = with pkgs; [ + pkg-config + rustPlatform.bindgenHook + ]; + + buildInputs = with pkgs; [ + nixsgx.sgx-sdk + nixsgx.sgx-dcap + nixsgx.sgx-dcap.quote_verify + ]; + + src = filter { + root = ./.; + exclude = [ + ".github" + ".gitignore" + "flake.lock" + "flake.nix" + "LICENSE-APACHE" + "LICENSE-MIT" + "README.md" + "renovate.json" + "deny.toml" + (filter.inDirectory "examples") + (filter.inDirectory "vault") + ]; + }; + RUSTFLAGS = "--cfg mio_unsupported_force_waker_pipe"; + cargoBuildFlags = "--all"; + checkType = "debug"; + cargoLock = { + lockFile = ./Cargo.lock; + }; + + outputs = [ + "out" + "tee_key_preexec" + "tee_self_attestation_test" + "tee_stress_client" + "tee_vault_admin" + "tee_vault_unseal" + "teepot_read" + "teepot_write" + "vault_admin" + "vault_unseal" + "verify_attestation" + ]; + + postInstall = '' + mkdir -p $out/nix-support + for i in $outputs; do + [[ $i == "out" ]] && continue + mkdir -p "''${!i}/bin" + echo "''${!i}" >> $out/nix-support/propagated-user-env-packages + binname=''${i//_/-} + mv "$out/bin/$binname" "''${!i}/bin/" + done + ''; + }; + in + { + formatter = pkgs.nixpkgs-fmt; + + packages = rec { + teepot = bin; + default = teepot; + }; + + devShells = { + default = pkgs.mkShell { + inputsFrom = [ bin ]; + nativeBuildInputs = with pkgs; [ + rustup + rustVersion + ]; + }; + }; + }); +} diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..33bc70a --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,3 @@ +[toolchain] +channel = "1.75" +components = ["rustfmt", "clippy", "rust-src"] diff --git a/src/client/mod.rs b/src/client/mod.rs new file mode 100644 index 0000000..96496ee --- /dev/null +++ b/src/client/mod.rs @@ -0,0 +1,305 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023-2024 Matter Labs + +//! Helper functions for CLI clients to verify Intel SGX enclaves and other TEEs. + +#![deny(missing_docs)] +#![deny(clippy::all)] + +pub mod vault; + +use crate::json::http::AttestationResponse; +use crate::sgx::Collateral; +pub use crate::sgx::{ + parse_tcb_levels, sgx_ql_qv_result_t, verify_quote_with_collateral, EnumSet, + QuoteVerificationResult, TcbLevel, +}; +use actix_web::http::header; +use anyhow::{anyhow, bail, Context, Result}; +use awc::{Client, Connector}; +use clap::Args; +use rustls::client::danger::{HandshakeSignatureValid, ServerCertVerifier}; +use rustls::client::WebPkiServerVerifier; +use rustls::pki_types::{CertificateDer, ServerName, UnixTime}; +use rustls::{ClientConfig, DigitallySignedStruct, Error, SignatureScheme}; +use serde_json::Value; +use sha2::{Digest, Sha256}; +use std::sync::{Arc, OnceLock}; +use std::time; +use std::time::Duration; +use tracing::{error, info, warn}; +use x509_cert::der::{Decode as _, Encode as _}; +use x509_cert::Certificate; + +/// Options and arguments needed to attest a TEE +#[derive(Args, Debug, Clone)] +pub struct AttestationArgs { + /// hex encoded SGX mrsigner of the enclave to attest + #[arg(long)] + pub sgx_mrsigner: Option, + /// hex encoded SGX mrenclave of the enclave to attest + #[arg(long)] + pub sgx_mrenclave: Option, + /// URL of the server + #[arg(long, required = true)] + pub server: String, + /// allowed TCB levels, comma separated: + /// Ok, ConfigNeeded, ConfigAndSwHardeningNeeded, SwHardeningNeeded, OutOfDate, OutOfDateConfigNeeded + #[arg(long, value_parser = parse_tcb_levels)] + pub sgx_allowed_tcb_levels: Option>, +} + +/// A connection to a TEE, which implements the `teepot` attestation API +pub struct TeeConnection { + /// Options and arguments needed to attest a TEE + server: String, + client: Client, +} + +impl TeeConnection { + /// Create a new connection to a TEE + /// + /// This will verify the attestation report and check that the enclave + /// is running the expected code. + pub async fn new(args: &AttestationArgs, attestation_url: &str) -> Result { + let pk_hash = Arc::new(OnceLock::new()); + + let tls_config = Arc::new( + ClientConfig::builder() + .dangerous() + .with_custom_certificate_verifier(Arc::new(Self::make_verifier(pk_hash.clone()))) + .with_no_client_auth(), + ); + + let agent = Client::builder() + .add_default_header((header::USER_AGENT, "teepot/1.0")) + // a "connector" wraps the stream into an encrypted connection + .connector(Connector::new().rustls_0_22(tls_config)) + .timeout(Duration::from_secs(12000)) + .finish(); + + let this = Self { + server: args.server.clone(), + client: agent, + }; + + this.check_attestation(args, attestation_url, pk_hash) + .await?; + + Ok(this) + } + + /// Create a new connection to a TEE + /// + /// # Safety + /// This function is unsafe, because it does not verify the attestation report. + pub unsafe fn new_from_client_without_attestation(server: String, client: Client) -> Self { + Self { server, client } + } + + /// Get a reference to the agent, which can be used to make requests to the TEE + /// + /// Note, that it will refuse to connect to any other TLS server than the one + /// specified in the `AttestationArgs` of the `Self::new` function. + pub fn client(&self) -> &Client { + &self.client + } + + /// Get a reference to the server URL + pub fn server(&self) -> &str { + &self.server + } + + async fn check_attestation( + &self, + args: &AttestationArgs, + attestation_url: &str, + pk_hash: Arc>, + ) -> Result<()> { + info!("Getting attestation report"); + + let mut response = self + .client + .get(&format!("{}{attestation_url}", args.server)) + .send() + .await + .map_err(|e| anyhow!("Error sending attestation request: {}", e))?; + + let status_code = response.status(); + if !status_code.is_success() { + error!("Failed to get attestation: {}", status_code); + if let Ok(r) = response.json::().await { + eprintln!("Failed to get attestation: {}", r); + } + bail!("failed to get attestation: {}", status_code); + } + + let attestation: AttestationResponse = + response.json().await.context("failed to get attestation")?; + + let current_time: i64 = time::SystemTime::now() + .duration_since(time::UNIX_EPOCH) + .unwrap() + .as_secs() as _; + + info!("Verifying attestation report"); + + let quote: &[u8] = &attestation.quote; + let collateral: Option<&Collateral> = Some(&attestation.collateral); + let pk_hash = pk_hash.get().unwrap(); + + Self::check_attestation_args(args, current_time, quote, collateral, pk_hash)?; + + Ok(()) + } + + /// Check the attestation report against `AttestationArgs` + pub fn check_attestation_args( + args: &AttestationArgs, + current_time: i64, + quote: &[u8], + collateral: Option<&Collateral>, + pk_hash: &[u8; 32], + ) -> Result<()> { + let QuoteVerificationResult { + collateral_expired, + result, + quote, + advisories, + .. + } = verify_quote_with_collateral(quote, collateral, current_time).unwrap(); + + if collateral_expired || !matches!(result, sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OK) { + if collateral_expired { + error!("Collateral is out of date!"); + bail!("Collateral is out of date!"); + } + + let tcblevel = TcbLevel::from(result); + if args + .sgx_allowed_tcb_levels + .map_or(true, |levels| !levels.contains(tcblevel)) + { + error!("Quote verification result: {}", tcblevel); + bail!("Quote verification result: {}", tcblevel); + } + + info!("TcbLevel is allowed: {}", tcblevel); + } + + for advisory in advisories { + warn!("Info: Advisory ID: {advisory}"); + } + + if "e.report_body.reportdata[..32] != pk_hash { + error!("Report data mismatch"); + bail!("Report data mismatch"); + } else { + info!( + "Report data matches `{}`", + hex::encode("e.report_body.reportdata[..32]) + ); + } + + if let Some(mrsigner) = &args.sgx_mrsigner { + let mrsigner_bytes = hex::decode(mrsigner).context("Failed to decode mrsigner")?; + if quote.report_body.mrsigner[..] != mrsigner_bytes { + bail!( + "mrsigner mismatch: got {}, expected {}", + hex::encode(quote.report_body.mrsigner), + &mrsigner + ); + } else { + info!("mrsigner `{mrsigner}` matches"); + } + } + + if let Some(mrenclave) = &args.sgx_mrenclave { + let mrenclave_bytes = hex::decode(mrenclave).context("Failed to decode mrenclave")?; + if quote.report_body.mrenclave[..] != mrenclave_bytes { + bail!( + "mrenclave mismatch: got {}, expected {}", + hex::encode(quote.report_body.mrenclave), + &mrenclave + ); + } else { + info!("mrenclave `{mrenclave}` matches"); + } + } + Ok(()) + } + + /// Save the hash of the public server key to `REPORT_DATA` to check + /// the attestations against it and it does not change on reconnect. + pub fn make_verifier(pk_hash: Arc>) -> impl ServerCertVerifier { + #[derive(Debug)] + struct V { + pk_hash: Arc>, + server_verifier: Arc, + } + impl ServerCertVerifier for V { + fn verify_server_cert( + &self, + end_entity: &CertificateDer, + _intermediates: &[CertificateDer], + _server_name: &ServerName, + _ocsp_response: &[u8], + _now: UnixTime, + ) -> Result { + let cert = Certificate::from_der(end_entity.as_ref()) + .map_err(|e| Error::General(format!("Failed get certificate {e:?}")))?; + let pub_key = cert + .tbs_certificate + .subject_public_key_info + .to_der() + .unwrap(); + + let hash = Sha256::digest(pub_key); + let data = self.pk_hash.get_or_init(|| hash[..32].try_into().unwrap()); + + if data == &hash[..32] { + info!( + "Checked or set server certificate public key hash `{}`", + hex::encode(&hash[..32]) + ); + Ok(rustls::client::danger::ServerCertVerified::assertion()) + } else { + error!("Server certificate does not match expected certificate"); + Err(rustls::Error::General( + "Server certificate does not match expected certificate".to_string(), + )) + } + } + + fn verify_tls12_signature( + &self, + message: &[u8], + cert: &CertificateDer<'_>, + dss: &DigitallySignedStruct, + ) -> std::result::Result { + self.server_verifier + .verify_tls12_signature(message, cert, dss) + } + + fn verify_tls13_signature( + &self, + message: &[u8], + cert: &CertificateDer<'_>, + dss: &DigitallySignedStruct, + ) -> std::result::Result { + self.server_verifier + .verify_tls13_signature(message, cert, dss) + } + + fn supported_verify_schemes(&self) -> Vec { + self.server_verifier.supported_verify_schemes() + } + } + let root_store = Arc::new(rustls::RootCertStore::empty()); + let server_verifier = WebPkiServerVerifier::builder(root_store).build().unwrap(); + V { + pk_hash, + server_verifier, + } + } +} diff --git a/src/client/vault.rs b/src/client/vault.rs new file mode 100644 index 0000000..6f8a5c6 --- /dev/null +++ b/src/client/vault.rs @@ -0,0 +1,393 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023 Matter Labs + +//! Helper functions for CLI clients to verify Intel SGX enclaves and other TEEs. + +#![deny(missing_docs)] +#![deny(clippy::all)] + +use super::{AttestationArgs, TeeConnection}; +use crate::json::http::{AuthRequest, AuthResponse}; +use crate::server::pki::make_self_signed_cert; +use crate::server::{AnyHowResponseError, HttpResponseError, Status}; +pub use crate::sgx::{ + parse_tcb_levels, sgx_gramine_get_quote, sgx_ql_qv_result_t, tee_qv_get_collateral, + verify_quote_with_collateral, Collateral, EnumSet, QuoteVerificationResult, TcbLevel, +}; +use actix_http::error::PayloadError; +use actix_web::http::header; +use actix_web::ResponseError; +use anyhow::{anyhow, bail, Context, Result}; +use awc::error::{SendRequestError, StatusCode}; +use awc::{Client, ClientResponse, Connector}; +use bytes::Bytes; +use futures_core::Stream; +use getrandom::getrandom; +use rustls::ClientConfig; +use serde_json::{json, Value}; +use std::fmt::{Display, Formatter}; +use std::sync::{Arc, OnceLock}; +use std::time; +use tracing::{debug, error, info, trace}; + +const VAULT_TOKEN_HEADER: &str = "X-Vault-Token"; + +/// Error returned when sending a request to Vault +#[derive(Debug, thiserror::Error)] +pub enum VaultSendError { + /// Error sending the request + SendRequest(String), + /// Error returned by the Vault API + #[error(transparent)] + Vault(#[from] HttpResponseError), +} + +impl Display for VaultSendError { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + VaultSendError::SendRequest(e) => write!(f, "VaultSendError: {}", e), + VaultSendError::Vault(e) => write!(f, "VaultSendError: {}", e), + } + } +} + +const _: () = { + fn assert_send() {} + let _ = assert_send::; +}; + +impl From for HttpResponseError { + fn from(value: VaultSendError) -> Self { + match value { + VaultSendError::SendRequest(e) => HttpResponseError::Anyhow(AnyHowResponseError { + status_code: StatusCode::BAD_GATEWAY, + error: anyhow!(e), + }), + VaultSendError::Vault(e) => e, + } + } +} + +/// A connection to a Vault TEE, which implements the `teepot` attestation API +/// called by a TEE itself. This authenticates the TEE to Vault and gets a token, +/// which can be used to access the Vault API. +pub struct VaultConnection { + /// Options and arguments needed to attest Vault + pub conn: TeeConnection, + key_hash: [u8; 64], + client_token: String, + name: String, +} + +impl VaultConnection { + /// Create a new connection to Vault + /// + /// This will verify the attestation report and check that the enclave + /// is running the expected code. + pub async fn new(args: &AttestationArgs, name: String) -> Result { + let pk_hash = Arc::new(OnceLock::new()); + + let (key_hash, rustls_certificate, rustls_pk) = make_self_signed_cert()?; + + let tls_config = Arc::new( + ClientConfig::builder() + .dangerous() + .with_custom_certificate_verifier(Arc::new(TeeConnection::make_verifier( + pk_hash.clone(), + ))) + .with_client_auth_cert(vec![rustls_certificate], rustls_pk)?, + ); + + let client = Client::builder() + .add_default_header((header::USER_AGENT, "teepot/1.0")) + // a "connector" wraps the stream into an encrypted connection + .connector(Connector::new().rustls_0_22(tls_config)) + .timeout(time::Duration::from_secs(12000)) + .finish(); + + let mut this = Self { + name, + key_hash, + conn: unsafe { + TeeConnection::new_from_client_without_attestation(args.server.clone(), client) + }, + client_token: Default::default(), + }; + + this.client_token = this.auth(args).await?.auth.client_token; + + trace!("Got Token: {:#?}", &this.client_token); + + Ok(this) + } + + /// create a new [`VaultConnection`] to Vault from an existing connection + /// + /// # Safety + /// This function is unsafe, because it does not verify the attestation report. + pub unsafe fn new_from_client_without_attestation( + server: String, + client: Client, + name: String, + client_token: String, + ) -> Self { + Self { + name, + client_token, + conn: unsafe { TeeConnection::new_from_client_without_attestation(server, client) }, + key_hash: [0u8; 64], + } + } + + /// Get a reference to the agent, which can be used to make requests to the TEE + /// + /// Note, that it will refuse to connect to any other TLS server than the one + /// specified in the `AttestationArgs` of the `Self::new` function. + pub fn agent(&self) -> &Client { + self.conn.client() + } + + async fn auth(&self, args: &AttestationArgs) -> Result { + info!("Getting attestation report"); + let attestation_url = AuthRequest::URL; + let quote = sgx_gramine_get_quote(&self.key_hash).context("Failed to get own quote")?; + let collateral = tee_qv_get_collateral("e).context("Failed to get own collateral")?; + + let mut challenge_bytes = [0u8; 32]; + getrandom(&mut challenge_bytes)?; + let challenge = hex::encode(challenge_bytes); + info!("Challenging Vault with: {}", challenge); + let challenge = Some(challenge_bytes); + + let auth_req = AuthRequest { + name: self.name.clone(), + tee_type: "sgx".to_string(), + quote, + collateral: serde_json::to_string(&collateral)?, + challenge, + }; + + let mut response = self + .agent() + .post(&format!( + "{server}{attestation_url}", + server = self.conn.server, + )) + .send_json(&auth_req) + .await + .map_err(|e| anyhow!("Error sending attestation request: {}", e))?; + + let status_code = response.status(); + if !status_code.is_success() { + error!("Failed to login to vault: {}", status_code); + if let Ok(r) = response.json::().await { + eprintln!("Failed to login to vault: {}", r); + } + bail!("failed to login to vault: {}", status_code); + } + + let auth_response: Value = response.json().await.context("failed to login to vault")?; + trace!( + "Got AuthResponse: {:?}", + serde_json::to_string(&auth_response) + ); + + let auth_response: AuthResponse = + serde_json::from_value(auth_response).context("Failed to parse AuthResponse")?; + + trace!("Got AuthResponse: {:#?}", &auth_response); + + let current_time: i64 = time::SystemTime::now() + .duration_since(time::UNIX_EPOCH) + .unwrap() + .as_secs() as _; + + info!("Verifying attestation report"); + + let collateral: Option = + serde_json::from_str(&auth_response.data.collateral).ok(); + let collateral = collateral.as_ref(); + + TeeConnection::check_attestation_args( + args, + current_time, + &auth_response.data.quote, + collateral, + &challenge_bytes, + ) + .context("Failed to verify Vault attestation report")?; + + Ok(auth_response) + } + + /// Send a put request to the vault + pub async fn vault_put( + &self, + action: &str, + url: &str, + json: &Value, + ) -> std::result::Result<(StatusCode, Option), VaultSendError> { + let full_url = format!("{}{url}", self.conn.server); + info!("{action} via put {full_url}"); + debug!( + "sending json: {:?}", + serde_json::to_string(json).unwrap_or_default() + ); + let res = self + .agent() + .put(full_url) + .insert_header((VAULT_TOKEN_HEADER, self.client_token.clone())) + .send_json(json) + .await; + Self::handle_client_response(action, res).await + } + + /// Send a get request to the vault + pub async fn vault_get( + &self, + action: &str, + url: &str, + ) -> std::result::Result<(StatusCode, Option), VaultSendError> { + let full_url = format!("{}{url}", self.conn.server); + info!("{action} via get {full_url}"); + let res = self + .agent() + .get(full_url) + .insert_header((VAULT_TOKEN_HEADER, self.client_token.clone())) + .send() + .await; + Self::handle_client_response(action, res).await + } + + async fn handle_client_response( + action: &str, + res: std::result::Result, SendRequestError>, + ) -> std::result::Result<(StatusCode, Option), VaultSendError> + where + S: Stream>, + { + match res { + Ok(mut r) => { + let status_code = r.status(); + if status_code.is_success() { + let msg = r.json().await.ok(); + debug!( + "{action}: status code: {status_code} {:?}", + serde_json::to_string(&msg) + ); + Ok((status_code, msg)) + } else { + let err = HttpResponseError::from_proxy(r).await; + error!("{action}: {err:?}"); + Err(err.into()) + } + } + Err(e) => { + error!("{}: {}", action, e); + Err(VaultSendError::SendRequest(e.to_string())) + } + } + } + + /// Revoke the token + pub async fn revoke_token(&self) -> std::result::Result<(), VaultSendError> { + self.vault_put( + "Revoke the token", + "/v1/auth/token/revoke-self", + &Value::default(), + ) + .await?; + Ok(()) + } + + fn check_rel_path(rel_path: &str) -> Result<(), HttpResponseError> { + if !rel_path.is_ascii() { + return Err(anyhow!("path is not ascii")).status(StatusCode::BAD_REQUEST); + } + + // check if rel_path is alphanumeric + if !rel_path.chars().all(|c| c.is_alphanumeric() || c == '_') { + return Err(anyhow!("path is not alphanumeric")).status(StatusCode::BAD_REQUEST); + } + + Ok(()) + } + + /// set a secret in the vault + pub async fn store_secret<'de, T: serde::Serialize>( + &self, + val: T, + rel_path: &str, + ) -> Result<(), HttpResponseError> { + self.store_secret_for_tee(&self.name, val, rel_path).await + } + + /// set a secret in the vault for a different TEE + pub async fn store_secret_for_tee<'de, T: serde::Serialize>( + &self, + tee_name: &str, + val: T, + rel_path: &str, + ) -> Result<(), HttpResponseError> { + Self::check_rel_path(rel_path)?; + + let value = serde_json::to_value(val) + .context("converting value to json") + .status(StatusCode::INTERNAL_SERVER_ERROR)?; + + let value = json!({ "data" : { "_" : value } }); + + self.vault_put( + "Setting secret", + &format!("/v1/secret/data/tee/{}/{}", tee_name, rel_path), + &value, + ) + .await?; + Ok(()) + } + + /// get a secret from the vault + pub async fn load_secret<'de, T: serde::de::DeserializeOwned>( + &self, + rel_path: &str, + ) -> Result, HttpResponseError> { + self.load_secret_for_tee(&self.name, rel_path).await + } + + /// get a secret from the vault for a specific TEE + pub async fn load_secret_for_tee<'de, T: serde::de::DeserializeOwned>( + &self, + tee_name: &str, + rel_path: &str, + ) -> Result, HttpResponseError> { + Self::check_rel_path(rel_path)?; + let v = self + .vault_get( + "Getting secret", + &format!("/v1/secret/data/tee/{}/{}", tee_name, rel_path), + ) + .await + .or_else(|e| match e { + VaultSendError::Vault(ref se) => { + if se.status_code() == StatusCode::NOT_FOUND { + debug!("Secret not found: {}", rel_path); + Ok((StatusCode::OK, None)) + } else { + Err(e) + } + } + VaultSendError::SendRequest(_) => Err(e), + })? + .1 + .as_ref() + .and_then(|v| v.get("data")) + .and_then(|v| v.get("data")) + .and_then(|v| v.get("_")) + .and_then(|v| serde_json::from_value(v.clone()).transpose()) + .transpose() + .context("Error getting value from vault") + .status(StatusCode::INTERNAL_SERVER_ERROR)? + .flatten(); + Ok(v) + } +} diff --git a/src/json/http.rs b/src/json/http.rs new file mode 100644 index 0000000..ea3456d --- /dev/null +++ b/src/json/http.rs @@ -0,0 +1,280 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023 Matter Labs + +//! Common types for the teepot http JSON API + +use crate::sgx::Collateral; +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use serde_with::base64::Base64; +use serde_with::serde_as; +use std::fmt::Display; +use std::sync::Arc; + +/// The unseal request data +#[derive(Debug, Serialize, Deserialize)] +pub struct Unseal { + /// The unseal key + pub key: String, +} + +impl Unseal { + /// The unseal URL + pub const URL: &'static str = "/v1/sys/unseal"; +} + +/// The attestation URL +pub const ATTESTATION_URL: &str = "/v1/sys/attestation"; + +/// The attestation response +#[derive(Debug, Serialize, Deserialize)] +pub struct AttestationResponse { + /// The quote + pub quote: Arc<[u8]>, + /// The collateral + pub collateral: Arc, +} + +/// The init request data +#[serde_as] +#[derive(Debug, Serialize, Deserialize)] +pub struct Init { + /// PGP keys to encrypt the unseal keys with + pub pgp_keys: Vec, + /// number of secret shares + pub secret_shares: usize, + /// secret threshold + pub secret_threshold: usize, + /// PGP keys to sign commands for the admin tee + #[serde_as(as = "Box<[Base64]>")] + pub admin_pgp_keys: Box<[Box<[u8]>]>, + /// admin threshold + pub admin_threshold: usize, + /// admin TEE mrenclave + pub admin_tee_mrenclave: String, +} + +impl Init { + /// The init URL + pub const URL: &'static str = "/v1/sys/init"; +} + +/// The init request data +#[derive(Debug, Serialize, Deserialize)] +pub struct VaultInitRequest { + /// PGP keys to encrypt the unseal keys with + pub pgp_keys: Vec, + /// number of secret shares + pub secret_shares: usize, + /// secret threshold + pub secret_threshold: usize, +} + +/// The init response data +#[derive(Debug, Serialize, Deserialize)] +pub struct InitResponse { + /// The unseal keys (gpg encrypted) + pub unseal_keys: Vec, +} + +/// The Vault TEE auth request data +#[serde_as] +#[derive(Debug, Serialize, Deserialize)] +pub struct AuthRequest { + /// The name of the TEE + pub name: String, + /// The type of the TEE + #[serde(rename = "type")] + pub tee_type: String, + /// The attestation report data base64 encoded + #[serde_as(as = "Base64")] + pub quote: Box<[u8]>, + /// The attestation collateral json encoded + pub collateral: String, + /// The vault attestation challenge (hex encoded) + #[serde_as(as = "Option")] + #[serde(skip_serializing_if = "Option::is_none", default = "Option::default")] + pub challenge: Option<[u8; 32]>, +} + +impl AuthRequest { + /// The auth URL + pub const URL: &'static str = "/v1/auth/tee/login"; +} + +/// Vault auth metadata +#[derive(Debug, Default, Serialize, Deserialize)] +pub struct AuthMetadataField { + collateral_expiration_date: String, + tee_name: String, +} + +/// Vault auth data +#[serde_as] +#[derive(Debug, Default, Serialize, Deserialize)] +pub struct AuthDataField { + /// The attestation report data base64 encoded + #[serde_as(as = "Base64")] + #[serde(default)] + pub quote: Box<[u8]>, + /// The attestation collateral json encoded + #[serde(default)] + pub collateral: String, +} + +/// Vault auth +#[derive(Debug, Default, Serialize, Deserialize)] +pub struct AuthField { + /// TODO + pub renewable: bool, + /// TODO + pub lease_duration: isize, + /// TODO + pub policies: Vec, + /// TODO + pub accessor: String, + /// TODO + pub client_token: String, + /// TODO + pub metadata: AuthMetadataField, +} + +/// The Vault TEE auth response data +#[derive(Debug, Default, Serialize, Deserialize)] +pub struct AuthResponse { + /// vault auth + pub auth: AuthField, + /// + pub data: AuthDataField, +} + +/// One command datum +#[derive(Debug, Serialize, Deserialize, PartialEq)] +pub struct VaultCommand { + /// The command to execute + pub url: String, + /// The command to execute + pub data: Value, +} + +impl Display for VaultCommand { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if f.alternate() { + f.write_str( + serde_json::to_string_pretty(self) + .unwrap_or("{}".into()) + .as_str(), + ) + } else { + f.write_str(serde_json::to_string(self).unwrap_or("{}".into()).as_str()) + } + } +} + +/// Multiple command data +#[derive(Debug, Serialize, Deserialize, PartialEq)] +pub struct VaultCommands { + /// The sha-256 hash of the last command hex encoded + pub last_digest: String, + /// The actual commands + pub commands: Vec, +} + +/// The command request data +#[derive(Debug, Serialize, Deserialize)] +pub struct VaultCommandRequest { + /// The commands to execute + /// + /// The commands are json serialized `VaultCommands`, + /// because they are signed with multiple signatures. + /// + /// The commands are executed in order. + pub commands: String, + /// The signatures of the commands + pub signatures: Vec, +} + +impl VaultCommandRequest { + /// The command request URL + pub const URL: &'static str = "/v1/command"; +} + +/// The command response +#[derive(Debug, Serialize, Deserialize)] +pub struct VaultCommandResponse { + /// The status code + pub status_code: u16, + /// The response body + pub value: Option, +} + +/// The command response +#[derive(Debug, Serialize, Deserialize)] +pub struct VaultCommandsResponse { + /// The stored digest for the execution + pub digest: String, + /// The results of the individual commands + pub results: Vec, +} + +impl Display for VaultCommandResponse { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if f.alternate() { + f.write_str( + serde_json::to_string_pretty(self) + .unwrap_or("{}".into()) + .as_str(), + ) + } else { + f.write_str(serde_json::to_string(self).unwrap_or("{}".into()).as_str()) + } + } +} + +/// The command request URL +pub const DIGEST_URL: &str = "/v1/digest"; + +/// The signing request +#[derive(Debug, Serialize, Deserialize)] +pub struct SignRequest { + /// json serialized `SignRequestData`, because it is signed with multiple signatures. + pub sign_request_data: String, + /// The signatures of the SignRequestData + pub signatures: Vec, +} + +impl SignRequest { + /// The sign request URL + pub const URL: &'static str = "/v1/sign"; +} + +/// The signing request data +#[serde_as] +#[derive(Debug, Default, Serialize, Deserialize)] +pub struct SignRequestData { + /// The sha-256 hash of the last command hex encoded + pub last_digest: String, + /// The name of the TEE + pub tee_name: String, + /// The type of the TEE + #[serde(rename = "type")] + pub tee_type: String, + /// The TEE security version number + pub tee_svn: u16, + /// The data to be signed. + /// + /// In case of `tee_type == "sgx"`, it's the SGX Sigstruct Body + #[serde_as(as = "Base64")] + pub data: Vec, +} + +/// The signing request +#[derive(Debug, Serialize, Deserialize)] +pub struct SignResponse { + /// The stored digest for the execution + pub digest: String, + /// The signed data for the tee. + /// + /// In case of `tee_type == "sgx"`, it's the SGX Sigstruct + pub signed_data: Vec, +} diff --git a/src/json/mod.rs b/src/json/mod.rs new file mode 100644 index 0000000..956b434 --- /dev/null +++ b/src/json/mod.rs @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023 Matter Labs + +//! Common types for the teepot JSON API + +#![deny(missing_docs)] +#![deny(clippy::all)] + +pub mod http; +pub mod secrets; diff --git a/src/json/secrets.rs b/src/json/secrets.rs new file mode 100644 index 0000000..dd1fae5 --- /dev/null +++ b/src/json/secrets.rs @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023 Matter Labs + +//! Common types for the teepot secrets JSON API + +use crate::sgx::sign::Zeroizing; +use serde::{Deserialize, Serialize}; +use serde_with::base64::Base64; +use serde_with::serde_as; + +/// Configuration for the admin tee +#[serde_as] +#[derive(Debug, Clone, Default, Serialize, Deserialize)] +pub struct AdminConfig { + /// PGP keys to sign commands for the admin tee + #[serde_as(as = "Box<[Base64]>")] + pub admin_pgp_keys: Box<[Box<[u8]>]>, + /// admin threshold + pub admin_threshold: usize, +} + +/// Configuration for the admin tee +#[derive(Debug, Default, Clone, Serialize, Deserialize)] +pub struct AdminState { + /// last digest of executed commands + pub last_digest: String, +} + +/// Configuration for the admin tee +#[derive(Debug, Default, Clone, Serialize, Deserialize)] +pub struct SGXSigningKey { + /// private key in PEM format + pub pem_pk: Zeroizing, +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..4259f4c --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023 Matter Labs + +//! Helper functions to verify Intel SGX enclaves and other TEEs. + +#![deny(missing_docs)] +#![deny(clippy::all)] + +pub mod client; +pub mod json; +pub mod server; +pub mod sgx; + +pub mod quote; diff --git a/src/quote/mod.rs b/src/quote/mod.rs new file mode 100644 index 0000000..4d8ae51 --- /dev/null +++ b/src/quote/mod.rs @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023-2024 Matter Labs + +//! Get a quote from a TEE + +use crate::sgx::sgx_gramine_get_quote; +use std::io; + +#[derive(Debug, thiserror::Error)] +#[allow(missing_docs)] +#[error("{msg}")] +pub struct GetQuoteError { + pub(crate) msg: Box, + #[source] // optional if field name is `source` + pub(crate) source: io::Error, +} + +/// Get the attestation quote from a TEE +pub fn get_quote(report_data: &[u8]) -> Result, GetQuoteError> { + // check, if we are running in a TEE + if std::fs::metadata("/dev/attestation").is_ok() { + if report_data.len() > 64 { + return Err(GetQuoteError { + msg: "Report data too long".into(), + source: io::Error::new(io::ErrorKind::Other, "Report data too long"), + }); + } + + let mut report_data_fixed = [0u8; 64]; + report_data_fixed[..report_data.len()].copy_from_slice(report_data); + + sgx_gramine_get_quote(&report_data_fixed) + } else { + // if not, return an error + Err(GetQuoteError { + msg: "Not running in a TEE".into(), + source: io::Error::new(io::ErrorKind::Other, "Not running in a TEE"), + }) + } +} diff --git a/src/server/attestation.rs b/src/server/attestation.rs new file mode 100644 index 0000000..f24f2a3 --- /dev/null +++ b/src/server/attestation.rs @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023 Matter Labs + +//! Common attestation API for all TEEs + +use crate::client::AttestationArgs; +use crate::json::http::AttestationResponse; +use crate::sgx::{ + parse_tcb_levels, sgx_gramine_get_quote, tee_qv_get_collateral, verify_quote_with_collateral, + Collateral, EnumSet, QuoteVerificationResult, TcbLevel, +}; +use anyhow::{bail, Context, Result}; +use clap::Args; +use serde::{Deserialize, Serialize}; +use std::sync::{Arc, RwLock}; +use std::time::{Duration, UNIX_EPOCH}; +use tracing::{debug, error, info, trace, warn}; + +struct Attestation { + quote: Arc<[u8]>, + collateral: Arc, + report_data: [u8; 64], + earliest_expiration_date: i64, +} + +/// Returns the quote and collateral for the current TEE. +/// +/// if `allowed_tcb_levels` is `None`, then any TCB level is accepted. +/// Otherwise, the quote must be verified and the collateral must be +/// within the allowed TCB levels. +pub fn get_quote_and_collateral( + allowed_tcb_levels: Option>, + report_data: &[u8; 64], +) -> Result { + static ATTESTATION: RwLock> = RwLock::new(None); + + let unix_time: i64 = std::time::SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs() as _; + + if let Some(attestation) = ATTESTATION.read().unwrap().as_ref() { + trace!(attestation.earliest_expiration_date); + + if attestation.earliest_expiration_date > unix_time.saturating_add(60) + && report_data.eq(&attestation.report_data) + { + debug!("return cache attestation quote and collateral"); + return Ok(AttestationResponse { + quote: attestation.quote.clone(), + collateral: attestation.collateral.clone(), + }); + } + } + + let myquote = sgx_gramine_get_quote(report_data).context("Failed to get own quote")?; + let collateral = tee_qv_get_collateral(&myquote).context("Failed to get own collateral")?; + + let QuoteVerificationResult { + collateral_expired, + result, + earliest_expiration_date, + tcb_level_date_tag, + quote, + advisories, + } = verify_quote_with_collateral(&myquote, Some(&collateral), unix_time.saturating_add(60)) + .context("Failed to verify own quote with collateral")?; + + debug!(tcb_level_date_tag); + + if collateral_expired { + bail!("Freshly fetched collateral expired"); + } + + let tcblevel = TcbLevel::from(result); + if tcblevel != TcbLevel::Ok + && allowed_tcb_levels.map_or(false, |levels| !levels.contains(tcblevel)) + { + error!("Quote verification result: {}", tcblevel); + bail!("Quote verification result: {}", tcblevel); + } + + for advisory in advisories { + warn!("\tInfo: Advisory ID: {advisory}"); + } + + info!("Own quote verified successfully: {}", tcblevel); + info!( + "Earliest expiration in {:?}", + Duration::from_secs((earliest_expiration_date - unix_time) as _) + ); + info!("mrsigner: {}", hex::encode(quote.report_body.mrsigner)); + info!("mrenclave: {}", hex::encode(quote.report_body.mrenclave)); + + let quote: Arc<[u8]> = Arc::from(myquote); + let collateral = Arc::from(collateral); + + let mut attestation = ATTESTATION.write().unwrap(); + *attestation = Some(Attestation { + quote: quote.clone(), + collateral: collateral.clone(), + report_data: *report_data, + earliest_expiration_date, + }); + + Ok(AttestationResponse { quote, collateral }) +} + +/// Options and arguments needed to attest a TEE +#[derive(Args, Debug, Clone, Serialize, Deserialize, Default)] +pub struct VaultAttestationArgs { + /// hex encoded SGX mrsigner of the enclave to attest + #[arg(long, env = "VAULT_SGX_MRSIGNER")] + pub vault_sgx_mrsigner: Option, + /// hex encoded SGX mrenclave of the enclave to attest + #[arg(long, env = "VAULT_SGX_MRENCLAVE")] + pub vault_sgx_mrenclave: Option, + /// URL of the server + #[arg(long, required = true, env = "VAULT_ADDR")] + pub vault_addr: String, + /// allowed TCB levels, comma separated: + /// Ok, ConfigNeeded, ConfigAndSwHardeningNeeded, SwHardeningNeeded, OutOfDate, OutOfDateConfigNeeded + #[arg(long, value_parser = parse_tcb_levels, env = "VAULT_SGX_ALLOWED_TCB_LEVELS")] + pub vault_sgx_allowed_tcb_levels: Option>, +} + +impl From for AttestationArgs { + fn from(value: VaultAttestationArgs) -> Self { + AttestationArgs { + sgx_mrsigner: value.vault_sgx_mrsigner, + sgx_mrenclave: value.vault_sgx_mrenclave, + server: value.vault_addr, + sgx_allowed_tcb_levels: value.vault_sgx_allowed_tcb_levels, + } + } +} + +impl From<&VaultAttestationArgs> for AttestationArgs { + fn from(value: &VaultAttestationArgs) -> Self { + AttestationArgs { + sgx_mrsigner: value.vault_sgx_mrsigner.clone(), + sgx_mrenclave: value.vault_sgx_mrenclave.clone(), + server: value.vault_addr.clone(), + sgx_allowed_tcb_levels: value.vault_sgx_allowed_tcb_levels, + } + } +} diff --git a/src/server/mod.rs b/src/server/mod.rs new file mode 100644 index 0000000..e21e999 --- /dev/null +++ b/src/server/mod.rs @@ -0,0 +1,181 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023 Matter Labs + +//! # tee-server + +#![deny(missing_docs)] +#![deny(clippy::all)] + +pub mod attestation; +pub mod pki; +pub mod signatures; + +use actix_web::http::StatusCode; +use actix_web::web::Bytes; +use actix_web::{error, HttpRequest, HttpResponse}; +use actix_web::{HttpMessage, ResponseError}; +use anyhow::anyhow; +use awc::error::{PayloadError, SendRequestError}; +use awc::ClientResponse; +use futures_core::Stream; +use std::fmt::{Debug, Display, Formatter}; +use tracing::error; + +/// Anyhow error with an HTTP status code +pub struct AnyHowResponseError { + /// error message + pub error: anyhow::Error, + /// HTTP status code + pub status_code: StatusCode, +} + +/// Proxy response error +pub struct ProxyResponseError { + /// HTTP status code + pub status_code: StatusCode, + /// HTTP body + pub body: Option, + /// HTTP content type + pub content_type: String, +} + +/// custom HTTP response error +pub enum HttpResponseError { + /// Anyhow error + Anyhow(AnyHowResponseError), + /// Proxy error + Proxy(ProxyResponseError), +} + +impl std::error::Error for HttpResponseError {} + +/// Attach an HTTP status code to an anyhow error turning it into an HttpResponseError +pub trait Status { + /// The Ok type + type Ok; + /// Attach an HTTP status code to an anyhow error turning it into an HttpResponseError + fn status(self, status: StatusCode) -> Result; +} + +impl Status for Result { + type Ok = T; + fn status(self, status: StatusCode) -> Result { + match self { + Ok(value) => Ok(value), + Err(error) => Err(HttpResponseError::new(error, status)), + } + } +} + +impl HttpResponseError { + fn new(error: anyhow::Error, status_code: StatusCode) -> Self { + Self::Anyhow(AnyHowResponseError { error, status_code }) + } + + /// Create a new HTTP response error from a proxy response + pub async fn from_proxy(mut response: ClientResponse) -> Self + where + S: Stream>, + { + let status_code = response.status(); + error!("Vault returned server error: {}", status_code); + let body = response.body().await.ok(); + let content_type = response.content_type().to_string(); + Self::Proxy(ProxyResponseError { + status_code, + body, + content_type, + }) + } +} + +impl From<&str> for HttpResponseError { + fn from(value: &str) -> Self { + error!("{}", value); + HttpResponseError::new( + anyhow!(value.to_string()), + StatusCode::INTERNAL_SERVER_ERROR, + ) + } +} + +impl From for HttpResponseError { + fn from(error: SendRequestError) -> Self { + error!("Error sending request: {:?}", error); + HttpResponseError::new( + anyhow!(error.to_string()), + StatusCode::INTERNAL_SERVER_ERROR, + ) + } +} + +impl Debug for HttpResponseError { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + if let Self::Anyhow(e) = self { + if f.alternate() { + write!(f, "{:#?}", e.error) + } else { + write!(f, "{:?}", e.error) + } + } else { + write!(f, "HttpResponseError") + } + } +} + +impl Display for HttpResponseError { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + if let Self::Anyhow(e) = self { + if f.alternate() { + write!(f, "{:#}", e.error) + } else { + write!(f, "{}", e.error) + } + } else { + write!(f, "HttpResponseError") + } + } +} + +impl ResponseError for HttpResponseError { + fn status_code(&self) -> StatusCode { + match self { + HttpResponseError::Anyhow(e) => e.status_code, + HttpResponseError::Proxy(e) => e.status_code, + } + } + + fn error_response(&self) -> HttpResponse { + match self { + HttpResponseError::Anyhow(e) => HttpResponse::build(self.status_code()) + .content_type("application/json") + .body(format!(r#"{{"error":"{}"}}"#, e.error)), + HttpResponseError::Proxy(e) => { + if let Some(ref body) = e.body { + HttpResponse::build(self.status_code()) + .content_type(e.content_type.clone()) + .body(body.clone()) + } else { + HttpResponse::new(self.status_code()) + } + } + } + } +} + +/// Create a new json config +pub fn new_json_cfg() -> actix_web::web::JsonConfig { + actix_web::web::JsonConfig::default() + .limit(1024 * 1024) + .error_handler(json_error_handler) +} + +fn json_error_handler(err: error::JsonPayloadError, _: &HttpRequest) -> actix_web::Error { + error::InternalError::from_response( + "", + HttpResponse::BadRequest() + .content_type("application/json") + .body(format!(r#"{{"error":"json error: {}"}}"#, err)), + ) + .into() +} diff --git a/src/server/pki.rs b/src/server/pki.rs new file mode 100644 index 0000000..332922f --- /dev/null +++ b/src/server/pki.rs @@ -0,0 +1,215 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023-2024 Matter Labs + +//! Some cryptographic utilities + +pub use crate::sgx::{ + parse_tcb_levels, sgx_ql_qv_result_t, verify_quote_with_collateral, EnumSet, + QuoteVerificationResult, TcbLevel, +}; +use anyhow::{anyhow, Context, Result}; +use const_oid::db::rfc5280::{ + ID_CE_BASIC_CONSTRAINTS, ID_CE_EXT_KEY_USAGE, ID_CE_KEY_USAGE, ID_KP_CLIENT_AUTH, + ID_KP_SERVER_AUTH, +}; +use const_oid::db::rfc5912::SECP_256_R_1; +use getrandom::getrandom; +use pkcs8::der::asn1::OctetString; +use pkcs8::der::referenced::OwnedToRef; +use pkcs8::der::referenced::RefToOwned; +use pkcs8::{ + AlgorithmIdentifierRef, ObjectIdentifier, PrivateKeyInfo, SubjectPublicKeyInfo, + SubjectPublicKeyInfoRef, +}; +use rustls::pki_types::PrivatePkcs8KeyDer; +use sec1::EcPrivateKey; +use sha2::{Digest, Sha256}; +use std::str::FromStr; +use std::time::Duration; +use x509_cert::der::asn1::BitString; +use x509_cert::der::{Decode as _, Encode as _}; +use x509_cert::ext::pkix::{BasicConstraints, ExtendedKeyUsage, KeyUsage, KeyUsages}; +use x509_cert::name::RdnSequence; +use x509_cert::serial_number::SerialNumber; +use x509_cert::time::Validity; +use x509_cert::{Certificate, TbsCertificate}; +use zeroize::Zeroizing; + +use const_oid::db::rfc5912::{ + ECDSA_WITH_SHA_256, ECDSA_WITH_SHA_384, ID_EC_PUBLIC_KEY as ECPK, SECP_256_R_1 as P256, + SECP_384_R_1 as P384, +}; +use pkcs8::der::asn1::BitStringRef; + +const ES256: AlgorithmIdentifierRef<'static> = AlgorithmIdentifierRef { + oid: ECDSA_WITH_SHA_256, + parameters: None, +}; + +const ES384: AlgorithmIdentifierRef<'static> = AlgorithmIdentifierRef { + oid: ECDSA_WITH_SHA_384, + parameters: None, +}; + +/// Utility trait for signing with a private key +pub trait PrivateKeyInfoExt { + /// Generates a keypair + /// + /// Returns the DER encoding of the `PrivateKeyInfo` type. + fn generate(oid: ObjectIdentifier) -> Result>>; + + /// Get the public key + /// + /// This function creates a `SubjectPublicKeyInfo` which corresponds with + /// this private key. Note that this function does not do any cryptographic + /// calculations. It expects that the `PrivateKeyInfo` already contains the + /// public key. + fn public_key(&self) -> Result>; + + /// Get the default signing algorithm for this `SubjectPublicKeyInfo` + fn signs_with(&self) -> Result>; + + /// Signs the body with the specified algorithm + /// + /// Note that the signature is returned in its encoded form as it will + /// appear in an X.509 certificate or PKCS#10 certification request. + fn sign(&self, body: &[u8], algo: AlgorithmIdentifierRef<'_>) -> Result>; +} + +impl<'a> PrivateKeyInfoExt for PrivateKeyInfo<'a> { + fn generate(oid: ObjectIdentifier) -> Result>> { + let rand = ring::rand::SystemRandom::new(); + + let doc = match oid { + P256 => { + use ring::signature::{EcdsaKeyPair, ECDSA_P256_SHA256_ASN1_SIGNING as ALG}; + EcdsaKeyPair::generate_pkcs8(&ALG, &rand)? + } + + P384 => { + use ring::signature::{EcdsaKeyPair, ECDSA_P384_SHA384_ASN1_SIGNING as ALG}; + EcdsaKeyPair::generate_pkcs8(&ALG, &rand)? + } + + _ => return Err(anyhow!("unsupported")), + }; + + Ok(doc.as_ref().to_vec().into()) + } + + fn public_key(&self) -> Result> { + match self.algorithm.oids()? { + (ECPK, ..) => { + let ec = EcPrivateKey::from_der(self.private_key)?; + let pk = ec.public_key.ok_or_else(|| anyhow!("missing public key"))?; + Ok(SubjectPublicKeyInfo { + algorithm: self.algorithm, + subject_public_key: BitStringRef::new(0, pk)?, + }) + } + _ => Err(anyhow!("unsupported")), + } + } + + fn signs_with(&self) -> Result> { + match self.algorithm.oids()? { + (ECPK, Some(P256)) => Ok(ES256), + (ECPK, Some(P384)) => Ok(ES384), + _ => Err(anyhow!("unsupported")), + } + } + + fn sign(&self, body: &[u8], algo: AlgorithmIdentifierRef<'_>) -> Result> { + let rng = ring::rand::SystemRandom::new(); + match (self.algorithm.oids()?, algo) { + ((ECPK, Some(P256)), ES256) => { + use ring::signature::{EcdsaKeyPair, ECDSA_P256_SHA256_ASN1_SIGNING as ALG}; + let kp = EcdsaKeyPair::from_pkcs8(&ALG, &self.to_der()?, &rng)?; + Ok(kp.sign(&rng, body)?.as_ref().to_vec()) + } + + ((ECPK, Some(P384)), ES384) => { + use ring::signature::{EcdsaKeyPair, ECDSA_P384_SHA384_ASN1_SIGNING as ALG}; + let kp = EcdsaKeyPair::from_pkcs8(&ALG, &self.to_der()?, &rng)?; + Ok(kp.sign(&rng, body)?.as_ref().to_vec()) + } + + _ => Err(anyhow!("unsupported")), + } + } +} + +/// Create a private key and a self-signed certificate +pub fn make_self_signed_cert() -> Result<( + [u8; 64], + rustls::pki_types::CertificateDer<'static>, + rustls::pki_types::PrivateKeyDer<'static>, +)> { + // Generate a keypair. + let raw = PrivateKeyInfo::generate(SECP_256_R_1).context("failed to generate a private key")?; + let pki = PrivateKeyInfo::from_der(raw.as_ref()) + .context("failed to parse DER-encoded private key")?; + let der = pki.public_key().unwrap().to_der().unwrap(); + + let mut key_hash = [0u8; 64]; + let hash = Sha256::digest(der); + key_hash[..32].copy_from_slice(&hash); + + // Create a relative distinguished name. + let rdns = RdnSequence::from_str("CN=localhost")?; + + // Create the extensions. + let ku = KeyUsage(KeyUsages::DigitalSignature | KeyUsages::KeyEncipherment).to_der()?; + let eu = ExtendedKeyUsage(vec![ID_KP_SERVER_AUTH, ID_KP_CLIENT_AUTH]).to_der()?; + let bc = BasicConstraints { + ca: false, + path_len_constraint: None, + } + .to_der()?; + + let mut serial = [0u8; 16]; + getrandom(&mut serial)?; + + // Create the certificate body. + let tbs = TbsCertificate { + version: x509_cert::Version::V3, + serial_number: SerialNumber::new(&serial)?, + signature: pki.signs_with()?.ref_to_owned(), + issuer: rdns.clone(), + validity: Validity::from_now(Duration::from_secs(60 * 60 * 24 * 365))?, + subject: rdns, + subject_public_key_info: pki.public_key()?.ref_to_owned(), + issuer_unique_id: None, + subject_unique_id: None, + extensions: Some(vec![ + x509_cert::ext::Extension { + extn_id: ID_CE_KEY_USAGE, + critical: true, + extn_value: OctetString::new(ku)?, + }, + x509_cert::ext::Extension { + extn_id: ID_CE_BASIC_CONSTRAINTS, + critical: true, + extn_value: OctetString::new(bc)?, + }, + x509_cert::ext::Extension { + extn_id: ID_CE_EXT_KEY_USAGE, + critical: false, + extn_value: OctetString::new(eu)?, + }, + ]), + }; + + // Self-sign the certificate. + let alg = tbs.signature.clone(); + let sig = pki.sign(&tbs.to_der()?, alg.owned_to_ref())?; + let crt = Certificate { + tbs_certificate: tbs, + signature_algorithm: alg, + signature: BitString::from_bytes(&sig)?, + }; + + let rustls_certificate = rustls::pki_types::CertificateDer::from(crt.to_der()?); + let rustls_pk = rustls::pki_types::PrivateKeyDer::from(PrivatePkcs8KeyDer::from(pki.to_der()?)); + Ok((key_hash, rustls_certificate, rustls_pk)) +} diff --git a/src/server/signatures.rs b/src/server/signatures.rs new file mode 100644 index 0000000..e91aa93 --- /dev/null +++ b/src/server/signatures.rs @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023 Matter Labs + +//! Signature checking utilities + +use crate::json::secrets::AdminConfig; +use crate::server::{HttpResponseError, Status as _}; +use actix_web::http::StatusCode; +use anyhow::{anyhow, bail, Context, Result}; +use pgp::types::KeyTrait; +use pgp::{Deserializable, SignedPublicKey, StandaloneSignature}; +use tracing::debug; + +/// Verify a pgp signature for some message given some public keys +pub fn verify_sig(sig: &str, msg: &[u8], keys: &[SignedPublicKey]) -> anyhow::Result { + let (signatures, _) = + StandaloneSignature::from_string_many(sig).context(format!("reading signature {}", sig))?; + + for signature in signatures { + let signature = match signature { + Ok(s) => s, + Err(e) => { + debug!("Failed to parse signature: {}", e); + continue; + } + }; + + for (pos, key) in keys.iter().enumerate() { + let actual_key = &key.primary_key; + if actual_key.is_signing_key() && signature.verify(&actual_key, msg).is_ok() { + return Ok(pos); + } + for sub_key in &key.public_subkeys { + if sub_key.is_signing_key() && signature.verify(sub_key, msg).is_ok() { + return Ok(pos); + } + } + } + } + eprintln!("Failed to verify signature for `{sig}`"); + bail!("Failed to verify signature for `{sig}`"); +} + +/// Verify pgp signatures for a message with some threshold +pub fn check_sigs( + pgp_keys: &[Box<[u8]>], + threshold: usize, + signatures: &[String], + msg: &[u8], +) -> Result<(), HttpResponseError> { + let mut keys = Vec::new(); + + for bytes in pgp_keys { + let key = SignedPublicKey::from_bytes(bytes.as_ref()) + .context("parsing public key") + .status(StatusCode::INTERNAL_SERVER_ERROR)?; + keys.push(key); + } + + let mut verified: usize = 0; + + for sig in signatures { + if let Ok(pos) = verify_sig(sig, msg, &keys) { + keys.remove(pos); + verified += 1; + } + if verified >= threshold { + break; + } + } + + if verified < threshold { + return Err(anyhow!("not enough valid signatures")).status(StatusCode::BAD_REQUEST); + } + Ok(()) +} + +/// Verify pgp signatures for a message +pub trait VerifySig { + /// Verify pgp signatures for a message + fn check_sigs(&self, signatures: &[String], msg: &[u8]) -> Result<(), HttpResponseError>; +} + +impl VerifySig for AdminConfig { + fn check_sigs(&self, signatures: &[String], msg: &[u8]) -> Result<(), HttpResponseError> { + check_sigs(&self.admin_pgp_keys, self.admin_threshold, signatures, msg) + } +} + +#[cfg(test)] +mod tests { + use super::verify_sig; + use base64::{engine::general_purpose, Engine as _}; + use pgp::{Deserializable, SignedPublicKey}; + + const TEST_DATA: &str = include_str!("../../tests/data/test.json"); + + // gpg --armor --local-user test@example.com --detach-sign bin/tee-vault-admin/tests/data/test.json + const TEST_SIG: &str = include_str!("../../tests/data/test.json.asc"); + + // gpg --armor --export 81A312C59D679D930FA9E8B06D728F29A2DBABF8 > bin/tee-vault-admin/tests/data/pub-81A312C59D679D930FA9E8B06D728F29A2DBABF8.asc + const TEST_KEY: &str = + include_str!("../../tests/data/pub-81A312C59D679D930FA9E8B06D728F29A2DBABF8.asc"); + + const TEST_KEY_BASE64: &str = + include_str!("../../tests/data/pub-81A312C59D679D930FA9E8B06D728F29A2DBABF8.b64"); + + #[test] + fn test_sig() { + let test_key = SignedPublicKey::from_string(TEST_KEY).unwrap().0; + verify_sig(TEST_SIG, TEST_DATA.as_bytes(), &[test_key]).unwrap(); + } + + #[test] + fn test_key_import() { + let str = TEST_KEY_BASE64.lines().collect::(); + let bytes = general_purpose::STANDARD.decode(str).unwrap(); + let _ = SignedPublicKey::from_bytes(bytes.as_slice()).unwrap(); + } +} diff --git a/src/sgx/error.rs b/src/sgx/error.rs new file mode 100644 index 0000000..492a42a --- /dev/null +++ b/src/sgx/error.rs @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023 Matter Labs + +//! Intel SGX Enclave error wrapper + +use bytemuck::PodCastError; +use intel_tee_quote_verification_rs::quote3_error_t; +use std::fmt::Formatter; + +/// Wrapper for the quote verification Error +#[derive(Copy, Clone)] +pub struct Quote3Error { + /// error message + pub msg: &'static str, + /// raw error code + pub inner: quote3_error_t, +} + +impl std::fmt::Display for Quote3Error { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}: {:?}", self.msg, self.inner) + } +} + +impl std::fmt::Debug for Quote3Error { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}: {:?}", self.msg, self.inner) + } +} + +impl std::error::Error for Quote3Error {} + +impl From for Quote3Error { + fn from(inner: quote3_error_t) -> Self { + Self { + msg: "Generic", + inner, + } + } +} + +#[derive(Debug, thiserror::Error)] +#[allow(missing_docs)] +pub enum QuoteFromError { + #[error(transparent)] + PodCastError(#[from] PodCastError), + + #[error("Quote version is invalid")] + InvalidVersion, +} diff --git a/src/sgx/mod.rs b/src/sgx/mod.rs new file mode 100644 index 0000000..a841f61 --- /dev/null +++ b/src/sgx/mod.rs @@ -0,0 +1,249 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023 Matter Labs + +// Copyright (c) The Enarx Project Developers https://github.com/enarx/sgx + +//! Intel SGX Enclave report structures. + +pub mod error; +pub mod sign; +pub mod tcblevel; + +use bytemuck::{cast_slice, try_from_bytes, AnyBitPattern, PodCastError}; +use intel_tee_quote_verification_rs::{ + quote3_error_t, sgx_ql_qv_supplemental_t, tee_get_supplemental_data_version_and_size, + tee_supp_data_descriptor_t, tee_verify_quote, +}; +use std::ffi::CStr; +use std::fs::OpenOptions; +use std::io::{Read, Write}; +use std::mem; +use tracing::{trace, warn}; + +use crate::quote::GetQuoteError; +pub use error::{Quote3Error, QuoteFromError}; +pub use intel_tee_quote_verification_rs::{sgx_ql_qv_result_t, Collateral}; +pub use tcblevel::{parse_tcb_levels, EnumSet, TcbLevel}; + +/// Structure of a quote +#[derive(Copy, Clone, Debug, AnyBitPattern)] +#[repr(C)] +pub struct Quote { + version: [u8; 2], + key_type: [u8; 2], + reserved: [u8; 4], + qe_svn: [u8; 2], + pce_svn: [u8; 2], + qe_vendor_id: [u8; 16], + /// The user data that was passed, when creating the enclave + pub user_data: [u8; 20], + /// The report body + pub report_body: ReportBody, +} + +impl Quote { + /// Creates a quote from a byte slice + pub fn try_from_bytes(bytes: &[u8]) -> Result<&Self, QuoteFromError> { + if bytes.len() < mem::size_of::() { + return Err(PodCastError::SizeMismatch.into()); + } + let this: &Self = try_from_bytes(&bytes[..mem::size_of::()])?; + if this.version() != 3 { + return Err(QuoteFromError::InvalidVersion); + } + Ok(this) + } + + /// Version of the `Quote` structure + pub fn version(&self) -> u16 { + u16::from_le_bytes(self.version) + } +} + +/// The enclave report body. +/// +/// For more information see the following documents: +/// +/// [Intel® Software Guard Extensions (Intel® SGX) Data Center Attestation Primitives: ECDSA Quote Library API](https://download.01.org/intel-sgx/dcap-1.0/docs/SGX_ECDSA_QuoteGenReference_DCAP_API_Linux_1.0.pdf) +/// +/// Table 5, A.4. Quote Format +/// +/// [Intel® 64 and IA-32 Architectures Software Developer's Manual Volume 3 (3A, 3B, 3C & 3D): System Programming Guide](https://www.intel.com/content/www/us/en/architecture-and-technology/64-ia-32-architectures-software-developer-vol-3d-part-4-manual.html) +/// +/// Table 38-21. Layout of REPORT +#[derive(Copy, Clone, Debug, AnyBitPattern)] +#[repr(C)] +pub struct ReportBody { + /// The security version number of the enclave. + pub cpusvn: [u8; 16], + /// The Misc section of the StateSaveArea of the enclave + pub miscselect: [u8; 4], + reserved1: [u8; 28], + /// The allowed Features of the enclave. + pub features: [u8; 8], + /// The allowed XCr0Flags of the enclave. + pub xfrm: [u8; 8], + /// The measurement of the enclave + pub mrenclave: [u8; 32], + reserved2: [u8; 32], + /// The hash of the public key, that signed the enclave + pub mrsigner: [u8; 32], + reserved3: [u8; 96], + /// ISV assigned Product ID of the enclave. + pub isv_prodid: [u8; 2], + /// ISV assigned SVN (security version number) of the enclave. + pub isv_svn: [u8; 2], + reserved4: [u8; 60], + /// The enclave report data, injected when requesting the quote, that is used for attestation. + pub reportdata: [u8; 64], +} + +/// The result of the quote verification +pub struct QuoteVerificationResult<'a> { + /// the raw result + pub result: sgx_ql_qv_result_t, + /// indicates if the collateral is expired + pub collateral_expired: bool, + /// the earliest expiration date of the collateral + pub earliest_expiration_date: i64, + /// Date of the TCB level + pub tcb_level_date_tag: i64, + /// the advisory string + pub advisories: Vec, + /// the quote + pub quote: &'a Quote, +} + +/// Verifies a quote with collateral material +pub fn verify_quote_with_collateral<'a>( + quote: &'a [u8], + collateral: Option<&Collateral>, + current_time: i64, +) -> Result, Quote3Error> { + let mut supp_data: mem::MaybeUninit = mem::MaybeUninit::zeroed(); + let mut supp_data_desc = tee_supp_data_descriptor_t { + major_version: 0, + data_size: 0, + p_data: supp_data.as_mut_ptr() as *mut u8, + }; + trace!("tee_get_supplemental_data_version_and_size"); + let (_, supp_size) = + tee_get_supplemental_data_version_and_size(quote).map_err(|e| Quote3Error { + msg: "tee_get_supplemental_data_version_and_size", + inner: e, + })?; + + trace!( + "tee_get_supplemental_data_version_and_size supp_size: {}", + supp_size + ); + + if supp_size == mem::size_of::() as u32 { + supp_data_desc.data_size = supp_size; + } else { + supp_data_desc.data_size = 0; + trace!( + "tee_get_supplemental_data_version_and_size supp_size: {}", + supp_size + ); + trace!( + "mem::size_of::(): {}", + mem::size_of::() + ); + warn!("Quote supplemental data size is different between DCAP QVL and QvE, please make sure you installed DCAP QVL and QvE from same release.") + } + + let p_supplemental_data = match supp_data_desc.data_size { + 0 => None, + _ => Some(&mut supp_data_desc), + }; + + let has_sup = p_supplemental_data.is_some(); + + trace!("tee_verify_quote"); + + let (collateral_expiration_status, result) = + tee_verify_quote(quote, collateral, current_time, None, p_supplemental_data).map_err( + |e| Quote3Error { + msg: "tee_verify_quote", + inner: e, + }, + )?; + + // check supplemental data if necessary + let (advisories, earliest_expiration_date, tcb_level_date_tag) = if has_sup { + unsafe { + let supp_data = supp_data.assume_init(); + // convert to valid UTF-8 string + let ads = CStr::from_bytes_until_nul(cast_slice(&supp_data.sa_list[..])) + .ok() + .and_then(|s| CStr::to_str(s).ok()) + .into_iter() + .flat_map(|s| s.split(',').map(str::trim).map(String::from)) + .filter(|s| !s.is_empty()) + .collect(); + ( + ads, + supp_data.earliest_expiration_date, + supp_data.tcb_level_date_tag, + ) + } + } else { + (vec![], 0, 0) + }; + + let quote = Quote::try_from_bytes(quote).map_err(|_| Quote3Error { + msg: "Quote::try_from_bytes", + inner: quote3_error_t::SGX_QL_QUOTE_FORMAT_UNSUPPORTED, + })?; + + let res = QuoteVerificationResult { + collateral_expired: collateral_expiration_status != 0, + earliest_expiration_date, + tcb_level_date_tag, + result, + quote, + advisories, + }; + + Ok(res) +} + +/// Get the attestation report in a Gramine enclave +pub fn sgx_gramine_get_quote(report_data: &[u8; 64]) -> Result, GetQuoteError> { + let mut file = OpenOptions::new() + .write(true) + .open("/dev/attestation/user_report_data") + .map_err(|e| GetQuoteError { + msg: "Failed to open `/dev/attestation/user_report_data`".into(), + source: e, + })?; + + file.write(report_data).map_err(|e| GetQuoteError { + msg: "Failed to write `/dev/attestation/user_report_data`".into(), + source: e, + })?; + + drop(file); + + let mut file = OpenOptions::new() + .read(true) + .open("/dev/attestation/quote") + .map_err(|e| GetQuoteError { + msg: "Failed to open `/dev/attestation/quote`".into(), + source: e, + })?; + + let mut quote = Vec::new(); + file.read_to_end(&mut quote).map_err(|e| GetQuoteError { + msg: "Failed to read `/dev/attestation/quote`".into(), + source: e, + })?; + Ok(quote.into_boxed_slice()) +} + +/// Wrapper func for error +/// TODO: move to intel_tee_quote_verification_rs +pub fn tee_qv_get_collateral(quote: &[u8]) -> Result { + intel_tee_quote_verification_rs::tee_qv_get_collateral(quote).map_err(Into::into) +} diff --git a/src/sgx/sign.rs b/src/sgx/sign.rs new file mode 100644 index 0000000..6b9e0d0 --- /dev/null +++ b/src/sgx/sign.rs @@ -0,0 +1,383 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023 Matter Labs + +// Copyright (c) The Enarx Project Developers https://github.com/enarx/sgx + +//! SGX signature structures +//! +//! Mostly copied from the [`sgx`](https://crates.io/crates/sgx) crate, +//! but with some modifications to make it easier to use in a standalone context. +//! + +use bytemuck::{bytes_of, Pod, Zeroable}; +use num_integer::Integer; +use num_traits::ToPrimitive; +use rand::thread_rng; +use rsa::{ + pkcs1::{DecodeRsaPrivateKey, EncodeRsaPrivateKey, LineEnding}, + traits::PublicKeyParts, + BigUint, Pkcs1v15Sign, RsaPrivateKey, +}; +use sha2::Digest as _; +use sha2::Sha256; +pub use zeroize::Zeroizing; + +/// Enclave CPU attributes +/// +/// This type represents the CPU features turned on in an enclave. +#[repr(C, packed(4))] +#[derive(Copy, Clone, Debug, Pod, Zeroable)] +pub struct Attributes { + features: u64, + xfrm: u64, +} + +/// The `Author` of an enclave +/// +/// This structure encompasses the first block of fields from `SIGSTRUCT` +/// that is included in the signature. It is split out from `Signature` +/// in order to make it easy to hash the fields for the signature. +#[repr(C)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Pod)] +pub struct Author { + header1: [u8; 16], + vendor: u32, + date: u32, + header2: [u8; 16], + swdefined: u32, + reserved: [u32; 21], +} + +unsafe impl Zeroable for Author {} + +impl Author { + const HEADER1: [u8; 16] = 0x06000000E10000000000010000000000u128.to_be_bytes(); + const HEADER2: [u8; 16] = 0x01010000600000006000000001000000u128.to_be_bytes(); + + #[allow(clippy::unreadable_literal)] + /// Creates a new Author from a date and software defined value. + /// + /// Note that the `date` input is defined in binary-coded decimal. For + /// example, the unix epoch is: `0x1970_01_01`. + pub const fn new(date: u32, swdefined: u32) -> Self { + Self { + header1: Self::HEADER1, + vendor: 0, + date, + header2: Self::HEADER2, + swdefined, + reserved: [0; 21], + } + } + + /// get the date + #[inline] + pub fn date(&self) -> u32 { + self.date + } + + /// get the swdefined + #[inline] + pub fn swdefined(&self) -> u32 { + self.swdefined + } +} + +/// The enclave signature body +/// +/// This structure encompasses the second block of fields from `SIGSTRUCT` +/// that is included in the signature. It is split out from `Signature` +/// in order to make it easy to hash the fields for the signature. +#[repr(C)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Pod, Zeroable)] +pub struct Body { + misc_select: u32, + misc_mask: u32, + cet_attr_select: u8, + cet_attr_mask: u8, + reserved0: [u8; 2], + ext_fid: [u8; 16], + attr_select: [u8; 16], + attr_mask: [u8; 16], + mrenclave: [u8; 32], + reserved1: [u8; 16], + ext_pid: [u8; 16], + pid: u16, + svn: u16, +} + +impl Body { + /// Check if the debug flag can be set + #[inline] + pub fn can_set_debug(&self) -> bool { + /// Enables enclave debug mode + /// + /// This gives permission to use EDBGRD and EDBGWR to read and write + /// enclave memory as plaintext, respectively. You most likely want + /// to validate that this option is disabled during attestion. + const DEBUG: u64 = 1 << 1; + let attr_select: &Attributes = bytemuck::try_from_bytes(&self.attr_select).unwrap(); + let attr_mask: &Attributes = bytemuck::try_from_bytes(&self.attr_mask).unwrap(); + + (attr_select.features & DEBUG) == 0 && (attr_mask.features & DEBUG) == 0 + } +} + +/// A signature on an enclave +/// +/// This structure encompasses the `SIGSTRUCT` structure from the SGX +/// documentation, renamed for ergonomics. The two portions of the +/// data that are included in the signature are further divided into +/// subordinate structures (`Author` and `Body`) for ease during +/// signature generation and validation. +#[repr(C)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Pod, Zeroable)] +pub struct Signature { + author: Author, + modulus: [u8; 384], + exponent: u32, + signature: [u8; 384], + body: Body, + reserved: [u8; 12], + q1: [u8; 384], + q2: [u8; 384], +} + +impl Signature { + /// Signs the supplied `author` and `body` with the specified `key`. + pub fn new(key: &T, author: Author, body: Body) -> Result { + let a = bytes_of(&author); + let b = bytes_of(&body); + let sd = key.sign(a, b)?; + + Ok(Self { + author, + modulus: sd.modulus, + exponent: sd.exponent, + signature: sd.signature, + body, + reserved: [0; 12], + q1: sd.q1, + q2: sd.q2, + }) + } + + /// Returns the author of the enclave. + pub fn author(&self) -> Author { + self.author + } + + /// Returns the body of the enclave. + pub fn body(&self) -> Body { + self.body + } +} + +/// A detached enclave signature +pub struct SigData { + /// The signature + pub signature: [u8; 384], + /// The public modulus + pub modulus: [u8; 384], + /// The public exponent + pub exponent: u32, + /// The first prime factor + pub q1: [u8; 384], + /// The second prime factor + pub q2: [u8; 384], +} + +/// A fixed-size hash +pub trait Digest: Sized { + /// The output size of the hash + type Output: AsRef<[u8]>; + + /// Construct a new hasher + fn new() -> Self; + /// Update the hasher with more data + fn update(&mut self, bytes: &[u8]); + /// Finalize the hasher and return the digest + fn finish(self) -> Self::Output; + + /// Update the hasher with more data and return the hasher + #[inline] + fn chain(mut self, bytes: &[u8]) -> Self { + self.update(bytes); + self + } +} + +/// A private key used for signing an enclave +pub trait PrivateKey: Sized { + /// The error type for this key + type Error: core::fmt::Debug; + + /// Generate a new private key + fn generate(exponent: u8) -> Result; + + /// Stringify the private key as a PEM-encoded string + fn to_pem(&self) -> Result, Self::Error>; + + /// Load a private key from a PEM-encoded string + fn from_pem(pem: &str) -> Result; + /// Load a private key from a DER-encoded buffer + fn from_der(der: &[u8]) -> Result; + /// Sign the specified `author` and `body` + fn sign(&self, author: &[u8], body: &[u8]) -> Result; +} + +fn arr_from_big(value: &BigUint) -> [u8; 384] { + let mut arr = [0u8; 384]; + let buf = value.to_bytes_le(); + arr[..buf.len()].copy_from_slice(&buf); + arr +} + +/// SHA2-256 +pub struct S256Digest(Sha256); + +impl Digest for S256Digest { + type Output = [u8; 32]; + + #[inline] + fn new() -> Self { + Self(Sha256::new()) + } + + #[inline] + fn update(&mut self, bytes: &[u8]) { + self.0.update(bytes) + } + + #[inline] + fn finish(self) -> Self::Output { + *self.0.finalize().as_ref() + } +} + +/// RSA w/ SHA2-256 +pub struct RS256PrivateKey(RsaPrivateKey); + +impl RS256PrivateKey { + /// Create a new RSA private key. + pub fn new(key: RsaPrivateKey) -> Self { + assert!(key.n().bits() <= 384 * 8); + Self(key) + } +} + +impl PrivateKey for RS256PrivateKey { + type Error = rsa::errors::Error; + + fn generate(exponent: u8) -> Result { + let mut rng = thread_rng(); + let exp = BigUint::from(exponent); + let key = RsaPrivateKey::new_with_exp(&mut rng, 384 * 8, &exp)?; + Ok(Self::new(key)) + } + + fn to_pem(&self) -> Result, Self::Error> { + let pem = RsaPrivateKey::to_pkcs1_pem(&self.0, LineEnding::default())?; + Ok(pem) + } + + fn from_pem(pem: &str) -> Result { + let key = RsaPrivateKey::from_pkcs1_pem(pem)?; + Ok(Self::new(key)) + } + + fn from_der(der: &[u8]) -> Result { + let key = RsaPrivateKey::from_pkcs1_der(der)?; + Ok(Self::new(key)) + } + + fn sign(&self, author: &[u8], body: &[u8]) -> Result { + use sha2::digest::Update; + + let hash = Sha256::new().chain(author).chain(body).finalize(); + + let padding = Pkcs1v15Sign::new::(); + let sig = self.0.sign(padding, &hash)?; + + // Calculate q1 and q2. + let s = BigUint::from_bytes_be(&sig); + let m = self.0.n(); + let (q1, qr) = (&s * &s).div_rem(m); + let q2 = (&s * qr) / m; + + Ok(SigData { + signature: arr_from_big(&s), + modulus: arr_from_big(m), + exponent: self.0.e().to_u32().unwrap(), + q1: arr_from_big(&q1), + q2: arr_from_big(&q2), + }) + } +} + +#[cfg(test)] +mod test { + use super::{Author, Body, Signature}; + use testaso::testaso; + + testaso! { + struct Author: 4, 128 => { + header1: 0, + vendor: 16, + date: 20, + header2: 24, + swdefined: 40, + reserved: 44 + } + struct Body: 4, 128 => { + misc_select: 0, + misc_mask: 4, + cet_attr_select: 8, + cet_attr_mask: 9, + reserved0: 10, + ext_fid: 12, + attr_select: 28, + attr_mask: 44, + mrenclave: 60, + reserved1: 92, + ext_pid: 108, + pid: 124, + svn: 126 + } + struct Signature: 4, 1808 => { + author: 0, + modulus: 128, + exponent: 512, + signature: 516, + body: 900, + reserved: 1028, + q1: 1040, + q2: 1424 + } + } + + #[test] + fn author_instantiation() { + let author = Author::new(0x2000_03_30, 0u32); + assert_eq!(author.header1, Author::HEADER1); + assert_eq!(author.vendor, 0u32); + assert_eq!(author.date, 0x2000_03_30); + assert_eq!(author.header2, Author::HEADER2); + assert_eq!(author.swdefined, 0u32); + assert_eq!(author.reserved, [0; 21]); + } + + #[test] + fn test_signature() { + let test_sig = include_bytes!("../../tests/data/gramine-test.sig"); + let sig: Signature = bytemuck::try_pod_read_unaligned(test_sig).unwrap(); + let body = sig.body(); + assert_eq!( + body.mrenclave.to_vec(), + hex::decode("f78170fe28e2e8671d83f5056975d25a27eb2c333dc520c2ccaf4de6b3f9c81b") + .unwrap() + ); + assert!(!body.can_set_debug()); + assert_eq!(body.misc_select, 0); + } +} diff --git a/src/sgx/tcblevel.rs b/src/sgx/tcblevel.rs new file mode 100644 index 0000000..e98fa5a --- /dev/null +++ b/src/sgx/tcblevel.rs @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (c) 2023 Matter Labs + +//! Intel SGX Enclave TCB level wrapper + +use enumset::EnumSetType; +use intel_tee_quote_verification_rs::sgx_ql_qv_result_t; +use std::fmt::{Display, Formatter}; +use std::str::FromStr; + +pub use enumset::EnumSet; + +/// TCB level +#[derive(EnumSetType, Debug)] +pub enum TcbLevel { + /// TCB is up to date + Ok, + /// TCB is up to date, but the configuration is not + ConfigNeeded, + /// TCB is up to date, but the configuration and software hardening is not + ConfigAndSwHardeningNeeded, + /// TCB is up to date, but the software hardening is not + SwHardeningNeeded, + /// TCB is out of date + OutOfDate, + /// TCB is out of date and the configuration is also out of date + OutOfDateConfigNeeded, + /// TCB level is invalid + Invalid, +} + +impl From for TcbLevel { + fn from(value: sgx_ql_qv_result_t) -> Self { + match value { + sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OK => TcbLevel::Ok, + sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OUT_OF_DATE => TcbLevel::OutOfDate, + sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OUT_OF_DATE_CONFIG_NEEDED => { + TcbLevel::OutOfDateConfigNeeded + } + sgx_ql_qv_result_t::SGX_QL_QV_RESULT_SW_HARDENING_NEEDED => TcbLevel::SwHardeningNeeded, + sgx_ql_qv_result_t::SGX_QL_QV_RESULT_CONFIG_AND_SW_HARDENING_NEEDED => { + TcbLevel::ConfigAndSwHardeningNeeded + } + sgx_ql_qv_result_t::SGX_QL_QV_RESULT_CONFIG_NEEDED => TcbLevel::ConfigNeeded, + _ => TcbLevel::Invalid, + } + } +} + +impl FromStr for TcbLevel { + type Err = (); + + fn from_str(s: &str) -> Result { + match s { + "Ok" => Ok(TcbLevel::Ok), + "ConfigNeeded" => Ok(TcbLevel::ConfigNeeded), + "ConfigAndSwHardeningNeeded" => Ok(TcbLevel::ConfigAndSwHardeningNeeded), + "SwHardeningNeeded" => Ok(TcbLevel::SwHardeningNeeded), + "OutOfDate" => Ok(TcbLevel::OutOfDate), + "OutOfDateConfigNeeded" => Ok(TcbLevel::OutOfDateConfigNeeded), + "Invalid" => Ok(TcbLevel::Invalid), + _ => Err(()), + } + } +} + +impl Display for TcbLevel { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + TcbLevel::Ok => write!(f, "Ok"), + TcbLevel::ConfigNeeded => write!(f, "ConfigNeeded: Firmware needs to be updated"), + TcbLevel::ConfigAndSwHardeningNeeded => write!(f, "ConfigAndSwHardeningNeeded: Firmware configuration needs to be updated and software hardening is needed"), + TcbLevel::SwHardeningNeeded => write!(f, "SwHardeningNeeded: Software hardening is needed"), + TcbLevel::OutOfDate => write!(f, "OutOfDate: Firmware needs to be updated"), + TcbLevel::OutOfDateConfigNeeded => write!(f, "OutOfDateConfigNeeded: Firmware needs to be updated and configuration needs to be updated."), + TcbLevel::Invalid => write!(f, "Invalid TCB level"), + } + } +} + +/// Parse a comma-separated list of TCB levels +pub fn parse_tcb_levels( + s: &str, +) -> Result, Box> { + let mut set = EnumSet::new(); + for level_str in s.split(',') { + let level_str = level_str.trim(); + let level = TcbLevel::from_str(level_str) + .map_err(|_| format!("Invalid TCB level: {}", level_str))?; + set.insert(level); + } + Ok(set) +} diff --git a/taplo.toml b/taplo.toml new file mode 100644 index 0000000..696fb7b --- /dev/null +++ b/taplo.toml @@ -0,0 +1,11 @@ +[formatting] +reorder_keys = false +inline_table_expand = false +compact_arrays = true + +[[rule]] +include = ["**/Cargo.toml"] +keys = ["dependencies", "dev-dependencies", "build-dependencies"] + +[rule.formatting] +reorder_keys = true diff --git a/tests/data/gpgkey.asc b/tests/data/gpgkey.asc new file mode 100644 index 0000000..2e22186 --- /dev/null +++ b/tests/data/gpgkey.asc @@ -0,0 +1,83 @@ +-----BEGIN PGP PRIVATE KEY BLOCK----- + +lQWGBGTBKKQBDACo28S5h7rvfcj89OIv66evSsOExJJ363oYWBfs0GPkgPG/bS2p +gIFe5+yqvW5q2tnDYHz0WJkYQcwTqQQpt/Ma+UV+uaHc2pJfKvsmpI9o3xf+eV3C +9HrU+6lwr8efkBkjLrfzkroQf0II/eX9omePt4qXNMX07UKI1ZrmXWmn5BlXiwkQ +l0M9XWwS3PZ2aiM2MMUjfmDAdi5pc10UgZddlbInjK8guXj9/HQt23l3W1df83QN +lxC+sDmlekwugeg0HckcgTjGICvML+gwsX/GVDMJe/O8D7Sy7KKrO23xwus7p8At +4C5+0WCqARBKQbTE0IZTyUZUgt6xnn1BhFHBCblpI2KPkRXSUWBkb/Npr40Y2uMi +BZNk2Iwdyuim8+Zs5pHCISvR09COswFgM+K7ikv7EMMr1YsEcFGH4sE3GQXVw4qO +NdITNBAz/5+cPWAOUOske6BeUjLaC4XaG4wY2Rg7RVoDCqhKav+VYE2B/X0pNVSf +PyZKirkMllHVwA8AEQEAAf4HAwKZjSDmS/MZ3/8NRbzHTpijZMM4chf0Rum51Llu +NVqfoMU7/dibd7CFn6ZnuYPND/9lurj3Z1/idB2hOJ6LQsgCEPD7FQ+qKURWheq5 +wo9nN7K8Y6jSQd+7NtgeeOTbfvGslb1KTRspXZyB2d0Z5lJj7IE5BbMachyySKrC +IPadBPfqxLnLRd33gobw00lQYXahV5corurLBf8mqbk9Yy14Ts3uKEaYmMkiS9Hj +IcWlGm+3hzn+OA0A/5r9ix0pKRqSHPwIQPbAk4ZF9DUdQX0iZ0Te87wtSY/H88Qa +goTpfmI2Xtq13CFl1/uLzX3ZovgCkDELYg9wle/nGxmZ5AkHXM9PcXk+Gr8t/n1a +TZfSzj52PhMcmqf7zTuOCFGH/7HvrNnPcKYVOa0+YWKLe+tGHvVvqHyCoJtDJ6xp +zeNbxMCU6rVkLtoGWyS7j8gXQyaDmdAllCxLe3Wx1WXxN7faBBSwGB8kAflbo//x +xkYbjZxfYfhmarwqxUlfAHYyAUNYEb1bXvdDL7xwoHhBwRJl/303oGAwGEeOP6Xd +2cWhgBrbA+uTCjr0UZKyrbLABKHPyqF5MYi6xZDH4tEvJLj7lP28xw4NZUbA0PzZ +7kglkezgK2d4w/oGe9Kv2O8UztHDK9cPJgl45Ii/bqhhS0mm/2E2btylIPGvPQQf +Dtha5nGRWD9ho/TgM8gG0IEDiuZubV51YZu7gIvRdOI5OjckaLd0N+l3MmdaNWWj +OqSZkyxEuP1ZoDS84afJ/Rog7Xr64yXNSn8a/3LoOMfD84nrE348xl12jAQgMAb8 +GDnfPRpqCbopaxdKA0E40dJ01e7NiHDMiZ8MgrIUrzHo8logoYeOPmGEwWkBUoKx +T0i+tYmHL0ygsCtF0GvDM0QidDGlQtN99XPG9ZBJ1WNml7VtmnKJkCRjZIZJXYhc +5L3QsU09xrlQydrcVeNS6stFEOWsVR5QrOEa5sX0qfeIldHUg5+Q8Kz9Om8gxPWu +ELqcb1i5VK3ltOUf84xqYsBQBy8R5Xzz0RetLr36QtP/BxggyG2ekg8Xxf+lmxbo +SJo0Uy0PPMEJhyficMMepBmEUaov5B+Q4KL7ASeOleu6NouVhI5+t2RJQz7FcLSi +K7FELZuHDhfxCuPHReu6uJDKgrEH8F5xPaNNqXkAj7IX5n4H0snRxPn9yUPkHoLR +Z5DbdRb21e4VryQpBANLuYDdHxhJWtI45c6pRhE147aoxbJhHpuy7DC37nppINTq +I/pFdxsmhg2HtIRpuOTqA1OVHjnq9+3nZx8ZBTjonAsDlI7lbsXKj55H0p7p33Yl +aYp77ZagVxJchnRei4nVpan5FuRU7MqAxbQXdGVzdCA8dGVzdEBleGFtcGxlLmNv +bT6JAdEEEwEIADsWIQSBoxLFnWedkw+p6LBtco8potur+AUCZMEopAIbAwULCQgH +AgIiAgYVCgkICwIEFgIDAQIeBwIXgAAKCRBtco8potur+Cb2C/9sc2VYpi8eYnPr +clU/28SoecG9cyPAZ5D+AQfAnVPLDdeBgLLr4FrMkRLvFNEoNwSFWAHNde77ChKF +VPjqs1ubR+P6RJ8YjeuF5l5objn/xXd+fe79gjBfWRVUR36+q9TvJwr51bL/cFNv +0eGpvxV4OhiXImF99Ik3HtXX2w5b8rkH2DcW39HlQvxqOY3OTskmVn0nv5l6Q9CH +rIXsaug11Bp/EQPyMG/E0Qa1SWCIyDwphEQzIUFIBg0zlAUC2Tlh9PYrgZJ5GjNY +18a0ZglwTp48IpwOUXwT9IzOKyrM1jA9lg8P5ih/MLZKIMvroKrry+IZXQAujnvH +0HwMehDuepR+liOx1byI2VitOkl7GpAZ03t+ae/KrsjJ+Dx/oFFkDVQAF2dDJHiF +zZD8DHucIngY4b8Wq7N+8hzyk8AgKFK9rq3HqPH5L+NsJEzS1xOQeaGlI1H1knnA +gRuIBZdZewrR/UosYei3mZtEclHU+YqeeBAsVoKKSVi2ryu8RCmdBYYEZNIoLAEM +ANOH0uCrzNirekQ5YKtPP8/NS4SJBm15QoYN8TomIeiGStRTQB0X1RJQNxhkvswU +0i3ThjzWYCUBDMf5TB75QmAT4l8emjeE0oK/OycaVCgjavq9I+ycBub1QZ5Bcf3D +HNim1uvHxoWjniGkyhjTbfvX7rlnoXjL47hQmkZ0SuiDycm8ArZVKaGa0aSLP2wo +K+ze4nhQT3aKXz7rv6VwYVtHRJdtVLVxzDf7Z+XSKr5k7SqUS0UwrZDaNZbHUtrM +9hImdhkHDeMf/LxDVkou/WFujMORmL4esSQ90zhcMUqFvZbKY2H1MXRjZ9SjLnXa +5L1WuRYkC7cz3E7LaI0ptwPGhUbFc65xxJBvAsA+fXiokHExvHnA2xRY7RBZxpRq +1bXmMZxcIYFi142/7SMyqXmPRnBvuDztxuHtg6rGu+xBa+AhpY8x/iGekN7TobDe +Spjlf6WaarOb2J9Pw30sMvE+I9xaKB6eUNSorjXGdQC8KLh6fgRIiMVwEihtmyu5 ++QARAQAB/gcDAjZJ7hpI6Pgc//Vwz3rQfVyTr+J12X9saT4zdGT7WZw1qeYlIZJw +5IrBb2rkZktfl+1XG8UVVFq61LfCcGlpmP79Sgo+THSEDkoCPlU5rQQ4uV0zjWPA +aV5177kR2HQDWdzsfBQrXbrrxvvSh3oXuGSMtQZz3NxYA9YD7guLa/xljAczCVb/ +5U7HDGRc1mgUkhsT57EES5/PD7+lTPqJ53nGbXnpisw7mj6CFYd+4XbY0JF6Uu1C +rIiX9Zp5z5smL3ufOMsIthMFqLWu1P3snfb3OQJ/fnBk3I2tOVGJXMDHqJ8dFwdF +w98KDXI4SCVJeZ4XRvjHAvN8WMEUp6X3GgnxJBiiu87mpH0tPb8X25hfb8mnoFdG +qhtsJbJ0NAOuTGSu+ULSqOn96cu4jWmNgHxn1eoAtqA/hdQMA+CuHrwDm05xC7Er +XdObNmVndUoXxWzL2yA0j1mlaoxMCfJQJVHGIKrZh3CQyQxZKtDkBSpCb2GAK5w7 +kPsoQXJtsdgnulSd4R7lcVTXQbL9mT+G6Me/zDGLSmT/fSS4zVlEKtsCIWrwt54b +VTVHm75AIebGyCKTFgPuxqSPNWOD7pWpSOhaWWrb8wdhsB0+xi0QqWyUACi+nq43 +7zQpGvQwxujEfUskrlbSdxl2Fkgbc7Ss5av4qRPyjctbBRAq0u/pLqbH+r7k8Afz +9MmgIXE5vgQgOzlhLno8Att9wCoGCvWFWswhSu/mXmGBgsva9W/jQ6R6LdsfkXfs +Hy19Zd4U8SNTAZm+CZ294GBpADhCnr2iwW9PE0WTQ8yYJ28+IvnhxffYAHmG+jdN +aq7x0VyZIM7gSFJWOp4Yfrt5mzepZRYCMjobQRzR7OUF53K+iEb1030u6FuCLMy6 +2O2S/i1n2zTWIks1bS7kJiz41x+6WPzR9ataTYV/UBXVq85FtJzsNIY8pkVo52It +a9l179GeY6wwffBW2TmDEQl9Dbd9t2QfNIKOaVKdRuM9maf9l3D/b4aUVIEE64D/ +uuAo+Nb8i6pUAllM6PG6MbgkPE4qvbRCdO4egqXd2wg9KHxjiGrrotqaNwtl83zg +aETossRimW9Ja8wcd1NpJ+G/F2wg3/q5Y+cKPv/3jDNUSmeV9mkRAR2MoEP1wFe3 +6Q3skQdtimFlqYObVqFvFFlMb4D/PK4brazIiahMRIQqSCeZQdTuqDxNNn4bAdH6 +dc1H1VdbmaUf0zf4B1+7Uq/dvT3oU5R8sZRXVMFDHg6/XxEa35qEm4RjIMWLqYdT +ZRR19csnBDwC8uA7t4c+jij/eif4mwnyyt2AkF+ATAzXlctbuodiwBoG0PcVQLbP +pTX4HH82Zz5J73mnItdLiQG2BBgBCAAgFiEEgaMSxZ1nnZMPqeiwbXKPKaLbq/gF +AmTSKCwCGwwACgkQbXKPKaLbq/jheQwAnuyDaBHVapp+j4hVZs6wksNM4xYpmsjs +XaSufhPugMTg/XF4phsi63VGgJEQpWndeAPBLQZb6CHDBvfL0YEmWr6hMjxpuTMz +M1RJA3wzI0j7vWc7m3dQzoaju9LeLskQpBUpSucrqEBBfDba+CYEaNDkn2aJcL0O +AJjnH3MhYtF9gLfFDzMCwOVah/jPBnFG+2QfyZuWO/Qdzgk7o4VZHySfZTA3zgUZ +hhkFC9Vm0d8QtpxHVHyy7kCs/jAtyyVKl+LJWWO4NizrsHojROS0NmnQFSHfc4ua +xUmfybvvu0OKk5YTud/l3Fjoma1M/BDn4No0zZpsEPGXgERDvWg9SLqnV74J80kR +3sjQyhaP6agbpHtEwXcpjVJP1XNZ9zBm7XVjVsVknNzde510JdbY3KtElfp0JYT6 +EsVtISx4JlhyaCLAK0t+QbfsnL8rpzI+Qnirxvo7x7QT3k7dRu2AB0S+t0bsFu7b +NcPkByuqaJvurs3VRpU4rOyFaxaTKXfr +=Bpm9 +-----END PGP PRIVATE KEY BLOCK----- diff --git a/tests/data/gpgkey.pub b/tests/data/gpgkey.pub new file mode 100644 index 0000000..702905a --- /dev/null +++ b/tests/data/gpgkey.pub @@ -0,0 +1,31 @@ +mQGNBGTBKKQBDACo28S5h7rvfcj89OIv66evSsOExJJ363oYWBfs0GPkgPG/bS2pgIFe5+yqvW5q +2tnDYHz0WJkYQcwTqQQpt/Ma+UV+uaHc2pJfKvsmpI9o3xf+eV3C9HrU+6lwr8efkBkjLrfzkroQ +f0II/eX9omePt4qXNMX07UKI1ZrmXWmn5BlXiwkQl0M9XWwS3PZ2aiM2MMUjfmDAdi5pc10UgZdd +lbInjK8guXj9/HQt23l3W1df83QNlxC+sDmlekwugeg0HckcgTjGICvML+gwsX/GVDMJe/O8D7Sy +7KKrO23xwus7p8At4C5+0WCqARBKQbTE0IZTyUZUgt6xnn1BhFHBCblpI2KPkRXSUWBkb/Npr40Y +2uMiBZNk2Iwdyuim8+Zs5pHCISvR09COswFgM+K7ikv7EMMr1YsEcFGH4sE3GQXVw4qONdITNBAz +/5+cPWAOUOske6BeUjLaC4XaG4wY2Rg7RVoDCqhKav+VYE2B/X0pNVSfPyZKirkMllHVwA8AEQEA +AbQXdGVzdCA8dGVzdEBleGFtcGxlLmNvbT6JAdEEEwEIADsWIQSBoxLFnWedkw+p6LBtco8potur ++AUCZMEopAIbAwULCQgHAgIiAgYVCgkICwIEFgIDAQIeBwIXgAAKCRBtco8potur+Cb2C/9sc2VY +pi8eYnPrclU/28SoecG9cyPAZ5D+AQfAnVPLDdeBgLLr4FrMkRLvFNEoNwSFWAHNde77ChKFVPjq +s1ubR+P6RJ8YjeuF5l5objn/xXd+fe79gjBfWRVUR36+q9TvJwr51bL/cFNv0eGpvxV4OhiXImF9 +9Ik3HtXX2w5b8rkH2DcW39HlQvxqOY3OTskmVn0nv5l6Q9CHrIXsaug11Bp/EQPyMG/E0Qa1SWCI +yDwphEQzIUFIBg0zlAUC2Tlh9PYrgZJ5GjNY18a0ZglwTp48IpwOUXwT9IzOKyrM1jA9lg8P5ih/ +MLZKIMvroKrry+IZXQAujnvH0HwMehDuepR+liOx1byI2VitOkl7GpAZ03t+ae/KrsjJ+Dx/oFFk +DVQAF2dDJHiFzZD8DHucIngY4b8Wq7N+8hzyk8AgKFK9rq3HqPH5L+NsJEzS1xOQeaGlI1H1knnA +gRuIBZdZewrR/UosYei3mZtEclHU+YqeeBAsVoKKSVi2ryu8RCm5AY0EZNIoLAEMANOH0uCrzNir +ekQ5YKtPP8/NS4SJBm15QoYN8TomIeiGStRTQB0X1RJQNxhkvswU0i3ThjzWYCUBDMf5TB75QmAT +4l8emjeE0oK/OycaVCgjavq9I+ycBub1QZ5Bcf3DHNim1uvHxoWjniGkyhjTbfvX7rlnoXjL47hQ +mkZ0SuiDycm8ArZVKaGa0aSLP2woK+ze4nhQT3aKXz7rv6VwYVtHRJdtVLVxzDf7Z+XSKr5k7SqU +S0UwrZDaNZbHUtrM9hImdhkHDeMf/LxDVkou/WFujMORmL4esSQ90zhcMUqFvZbKY2H1MXRjZ9Sj +LnXa5L1WuRYkC7cz3E7LaI0ptwPGhUbFc65xxJBvAsA+fXiokHExvHnA2xRY7RBZxpRq1bXmMZxc +IYFi142/7SMyqXmPRnBvuDztxuHtg6rGu+xBa+AhpY8x/iGekN7TobDeSpjlf6WaarOb2J9Pw30s +MvE+I9xaKB6eUNSorjXGdQC8KLh6fgRIiMVwEihtmyu5+QARAQABiQG2BBgBCAAgFiEEgaMSxZ1n +nZMPqeiwbXKPKaLbq/gFAmTSKCwCGwwACgkQbXKPKaLbq/jheQwAnuyDaBHVapp+j4hVZs6wksNM +4xYpmsjsXaSufhPugMTg/XF4phsi63VGgJEQpWndeAPBLQZb6CHDBvfL0YEmWr6hMjxpuTMzM1RJ +A3wzI0j7vWc7m3dQzoaju9LeLskQpBUpSucrqEBBfDba+CYEaNDkn2aJcL0OAJjnH3MhYtF9gLfF +DzMCwOVah/jPBnFG+2QfyZuWO/Qdzgk7o4VZHySfZTA3zgUZhhkFC9Vm0d8QtpxHVHyy7kCs/jAt +yyVKl+LJWWO4NizrsHojROS0NmnQFSHfc4uaxUmfybvvu0OKk5YTud/l3Fjoma1M/BDn4No0zZps +EPGXgERDvWg9SLqnV74J80kR3sjQyhaP6agbpHtEwXcpjVJP1XNZ9zBm7XVjVsVknNzde510JdbY +3KtElfp0JYT6EsVtISx4JlhyaCLAK0t+QbfsnL8rpzI+Qnirxvo7x7QT3k7dRu2AB0S+t0bsFu7b +NcPkByuqaJvurs3VRpU4rOyFaxaTKXfr diff --git a/tests/data/gramine-test.sig b/tests/data/gramine-test.sig new file mode 100644 index 0000000..22e982e Binary files /dev/null and b/tests/data/gramine-test.sig differ diff --git a/tests/data/pub-81A312C59D679D930FA9E8B06D728F29A2DBABF8.asc b/tests/data/pub-81A312C59D679D930FA9E8B06D728F29A2DBABF8.asc new file mode 100644 index 0000000..9a3a6c4 --- /dev/null +++ b/tests/data/pub-81A312C59D679D930FA9E8B06D728F29A2DBABF8.asc @@ -0,0 +1,23 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQGNBGTBKKQBDACo28S5h7rvfcj89OIv66evSsOExJJ363oYWBfs0GPkgPG/bS2p +gIFe5+yqvW5q2tnDYHz0WJkYQcwTqQQpt/Ma+UV+uaHc2pJfKvsmpI9o3xf+eV3C +9HrU+6lwr8efkBkjLrfzkroQf0II/eX9omePt4qXNMX07UKI1ZrmXWmn5BlXiwkQ +l0M9XWwS3PZ2aiM2MMUjfmDAdi5pc10UgZddlbInjK8guXj9/HQt23l3W1df83QN +lxC+sDmlekwugeg0HckcgTjGICvML+gwsX/GVDMJe/O8D7Sy7KKrO23xwus7p8At +4C5+0WCqARBKQbTE0IZTyUZUgt6xnn1BhFHBCblpI2KPkRXSUWBkb/Npr40Y2uMi +BZNk2Iwdyuim8+Zs5pHCISvR09COswFgM+K7ikv7EMMr1YsEcFGH4sE3GQXVw4qO +NdITNBAz/5+cPWAOUOske6BeUjLaC4XaG4wY2Rg7RVoDCqhKav+VYE2B/X0pNVSf +PyZKirkMllHVwA8AEQEAAbQXdGVzdCA8dGVzdEBleGFtcGxlLmNvbT6JAdEEEwEI +ADsWIQSBoxLFnWedkw+p6LBtco8potur+AUCZMEopAIbAwULCQgHAgIiAgYVCgkI +CwIEFgIDAQIeBwIXgAAKCRBtco8potur+Cb2C/9sc2VYpi8eYnPrclU/28SoecG9 +cyPAZ5D+AQfAnVPLDdeBgLLr4FrMkRLvFNEoNwSFWAHNde77ChKFVPjqs1ubR+P6 +RJ8YjeuF5l5objn/xXd+fe79gjBfWRVUR36+q9TvJwr51bL/cFNv0eGpvxV4OhiX +ImF99Ik3HtXX2w5b8rkH2DcW39HlQvxqOY3OTskmVn0nv5l6Q9CHrIXsaug11Bp/ +EQPyMG/E0Qa1SWCIyDwphEQzIUFIBg0zlAUC2Tlh9PYrgZJ5GjNY18a0ZglwTp48 +IpwOUXwT9IzOKyrM1jA9lg8P5ih/MLZKIMvroKrry+IZXQAujnvH0HwMehDuepR+ +liOx1byI2VitOkl7GpAZ03t+ae/KrsjJ+Dx/oFFkDVQAF2dDJHiFzZD8DHucIngY +4b8Wq7N+8hzyk8AgKFK9rq3HqPH5L+NsJEzS1xOQeaGlI1H1knnAgRuIBZdZewrR +/UosYei3mZtEclHU+YqeeBAsVoKKSVi2ryu8RCk= +=LKzc +-----END PGP PUBLIC KEY BLOCK----- diff --git a/tests/data/pub-81A312C59D679D930FA9E8B06D728F29A2DBABF8.b64 b/tests/data/pub-81A312C59D679D930FA9E8B06D728F29A2DBABF8.b64 new file mode 100644 index 0000000..befdcaf --- /dev/null +++ b/tests/data/pub-81A312C59D679D930FA9E8B06D728F29A2DBABF8.b64 @@ -0,0 +1,16 @@ +mQGNBGTBKKQBDACo28S5h7rvfcj89OIv66evSsOExJJ363oYWBfs0GPkgPG/bS2pgIFe5+yqvW5q +2tnDYHz0WJkYQcwTqQQpt/Ma+UV+uaHc2pJfKvsmpI9o3xf+eV3C9HrU+6lwr8efkBkjLrfzkroQ +f0II/eX9omePt4qXNMX07UKI1ZrmXWmn5BlXiwkQl0M9XWwS3PZ2aiM2MMUjfmDAdi5pc10UgZdd +lbInjK8guXj9/HQt23l3W1df83QNlxC+sDmlekwugeg0HckcgTjGICvML+gwsX/GVDMJe/O8D7Sy +7KKrO23xwus7p8At4C5+0WCqARBKQbTE0IZTyUZUgt6xnn1BhFHBCblpI2KPkRXSUWBkb/Npr40Y +2uMiBZNk2Iwdyuim8+Zs5pHCISvR09COswFgM+K7ikv7EMMr1YsEcFGH4sE3GQXVw4qONdITNBAz +/5+cPWAOUOske6BeUjLaC4XaG4wY2Rg7RVoDCqhKav+VYE2B/X0pNVSfPyZKirkMllHVwA8AEQEA +AbQXdGVzdCA8dGVzdEBleGFtcGxlLmNvbT6JAdEEEwEIADsWIQSBoxLFnWedkw+p6LBtco8potur ++AUCZMEopAIbAwULCQgHAgIiAgYVCgkICwIEFgIDAQIeBwIXgAAKCRBtco8potur+Cb2C/9sc2VY +pi8eYnPrclU/28SoecG9cyPAZ5D+AQfAnVPLDdeBgLLr4FrMkRLvFNEoNwSFWAHNde77ChKFVPjq +s1ubR+P6RJ8YjeuF5l5objn/xXd+fe79gjBfWRVUR36+q9TvJwr51bL/cFNv0eGpvxV4OhiXImF9 +9Ik3HtXX2w5b8rkH2DcW39HlQvxqOY3OTskmVn0nv5l6Q9CHrIXsaug11Bp/EQPyMG/E0Qa1SWCI +yDwphEQzIUFIBg0zlAUC2Tlh9PYrgZJ5GjNY18a0ZglwTp48IpwOUXwT9IzOKyrM1jA9lg8P5ih/ +MLZKIMvroKrry+IZXQAujnvH0HwMehDuepR+liOx1byI2VitOkl7GpAZ03t+ae/KrsjJ+Dx/oFFk +DVQAF2dDJHiFzZD8DHucIngY4b8Wq7N+8hzyk8AgKFK9rq3HqPH5L+NsJEzS1xOQeaGlI1H1knnA +gRuIBZdZewrR/UosYei3mZtEclHU+YqeeBAsVoKKSVi2ryu8RCk= diff --git a/tests/data/stress.json b/tests/data/stress.json new file mode 100644 index 0000000..82b676d --- /dev/null +++ b/tests/data/stress.json @@ -0,0 +1,22 @@ +{ + "last_digest": "", + "commands": [ + { + "url": "/v1/sys/policies/acl/tee-stress", + "data": { + "policy": "path \"secret/data/tee/stress/*\" { capabilities = [\"create\", \"read\", \"update\", \"delete\", \"list\" ] }\n" + } + }, + { + "url": "/v1/auth/tee/tees/stress", + "data": { + "lease": "1000", + "name": "stress", + "sgx_allowed_tcb_levels": "Ok,SwHardeningNeeded", + "sgx_mrsigner": "c5591a72b8b86e0d8814d6e8750e3efe66aea2d102b8ba2405365559b858697d", + "token_policies": "tee-stress", + "types": "sgx" + } + } + ] +} diff --git a/tests/data/stress.json.asc b/tests/data/stress.json.asc new file mode 100644 index 0000000..468ec78 --- /dev/null +++ b/tests/data/stress.json.asc @@ -0,0 +1,26 @@ +-----BEGIN PGP SIGNATURE----- + +iQIzBAABCAAdFiEEC0Pk344t4+guABNk9RmhFDs/vjIFAmUn5WkACgkQ9RmhFDs/ +vjK5kw/8Dl1XuMOfJ+mxshaRH4JexPmB/+c4x5JnaYS6GGJaJ/eOp+hSFchxnwfI +OXRV3S+/kgaytfu5zVEepqyypX43LbV+eZ5s450xa3qI0fR/rd+LnJeJNqFoJVrZ +M+xTGpkBPvPB3340ebyti5k49I+uhgO8c5Cd1FpM00dWN0qUUJMsFuOKNueFURlC +Sk9HLDk63G2/ZDyBzT83vMpFUZbtJ46yJmS2++W1UfEt2GZvL6sc2wr7pwlb5EtF +wEgLtaIAy749h1Lzilw6RTWVC3ShQvaddIFIh+XagnrKmk2D0gha2XprbvBSkpYf +a/9tZKH/4U8wfONR3sJ83wlODwks6zdIibspk7868vY5Bm9Yr2N1cIIPGtnnypHE +xPZI9QXY/zUSnTXgs5JyEZkea8j29v135zhuGINFPVWOa+frGYTIN/zZ3sjdhZMt ++4rRL8SZbFbkCDc/zGdlJOcTygUbEJBiseNJ8GXgbWrXzY/WDZpxL1xdxjkPK4PA +xtKyaPlBP1B1RyHkZGYDq86t9DzX2H/gkqBHJpuSavcx/7/Q/b6KGYdf/QFxo7kY +S0jdVXRVem0ClxWtEVZU9Wu9QykcYQbj3AM7hk+9Khmq32w7b3bwOndYNAojwzP+ +9UEVOAXv2K8LSBbq6RXott5KMKDwowOu4hQCNsDuvmBYkr1Sy5OJAcUEAAEIAC8W +IQSBoxLFnWedkw+p6LBtco8potur+AUCZSflbREcdGVzdEBleGFtcGxlLmNvbQAK +CRBtco8potur+LwPC/wOjT27sE4D/4Cadg58lXlRE2qoFdtc8vfs+ioxS7UxQX4m +ggY4P6lHq8u2TkY4jDe9FpA5S7LNGQJoQx2zrr3lGwonBwGkj4nRM60/uNSar+wd +Wknke8IUiv8E8MzITy+gKdFHwu95ZZh9IXefiQ4Fq8UQurELAfVA/sNk+1ovGzsO +/S4srkR4uejsAuk84PCA7dgNLYobcU/7SMH/ffgorqE6BOXwzfIy13c9TV5ZztWo +eK6R+wc92hza0ZvXVmB4i5NBe+aO7gSLe0QcJqHdaTpkcVhhhE+v8HdpF1JIgOH8 +/336W/ZOp1q1K0hL2rNU2YX40MOaZZLoxjfXNmC/dAZPel5HJMwTLzM6Aqqk49sB +LHEPgHjefUWiHe2C31PGM0THM3fuA6i5OwypnZRI14WYVDlVa5KRmj/titcCt6aQ ++fbzK5lYIg4AhLl8rIns8+/yJnwTIw3Zy94H8Xwjq8tplk6nSUWm0GKjYqFquwUf +6PyKGVnqs2Cp0hFmD9o= +=AsWI +-----END PGP SIGNATURE----- diff --git a/tests/data/test.json b/tests/data/test.json new file mode 100644 index 0000000..95244cb --- /dev/null +++ b/tests/data/test.json @@ -0,0 +1,16 @@ +{ + "last_digest": "", + "commands": [ + { + "url": "/v1/auth/tee/tees/test", + "data": { + "lease": "1000", + "name": "test", + "sgx_allowed_tcb_levels": "Ok,SwHardeningNeeded", + "sgx_mrsigner": "c5591a72b8b86e0d8814d6e8750e3efe66aea2d102b8ba2405365559b858697d", + "token_policies": "test", + "types": "sgx" + } + } + ] +} diff --git a/tests/data/test.json.asc b/tests/data/test.json.asc new file mode 100644 index 0000000..de8708e --- /dev/null +++ b/tests/data/test.json.asc @@ -0,0 +1,26 @@ +-----BEGIN PGP SIGNATURE----- + +iQIzBAABCAAdFiEEC0Pk344t4+guABNk9RmhFDs/vjIFAmT5sBwACgkQ9RmhFDs/ +vjIJ2g/9E8kRdvz8hhxOyJRPpNZ9bcGJ+FvMjG7geEdixqu1Bwpfyj+UhGRY7Dgq +4T46w/Hmr8YBZTI3xpafUSldyEvZnFXRuIQoBR+JQYNu8s9Jm9yDIyLLA86quiY8 +nU+x6x89sSOOvmTpRUBi6htTC4h0zZHHfAcmu0YS2pMmxXYJX7Rw3T7AJE0Uc4O/ ++0Ho1PMFB4BRmnNGlqBFc2u/yXEy38AWrmcheoPNtbdWmI/3leKikW5l2cXfPRuT +tazc92NiIK6qu209jlusMBpADdu8FSAI9ax4dKL1uE8KQyUIKQVQq3sBqQsPTgiW +XT6XznFdWawtW1y2jzt0DbdCt2osSwV7rPYbn6yxEpzQWuPL75JiDmJMktgBV38t +FKBpQl1ZDF9wARwsxBvNRaL0XPSurTtf/x4olue91D3I2fNeymS6P1DNXvLGXPD5 +46C2TvS1305wPjCpFAEgS58WpiiJppCYDsU0A7DEHbaIgk5mQ/iEdBOBvrn0xton +Rni5mXt0Vi0WfE8GriR25YajtAOI2/rxTSZjiSJI51WmdnV/lkJiY1YF0ws+KUXG +r2E+Bea0kwcnCMYFzraxwLwiS4mgamdQmp8DNALYZe8m/k+dNKI6tDEdWFMTiwda +PJMDc3+lUOcZCN6+umLUOVvNWQZ2QtZ4RSTzbJyDww4ysgTpFHOJAcUEAAEIAC8W +IQSBoxLFnWedkw+p6LBtco8potur+AUCZPmwIREcdGVzdEBleGFtcGxlLmNvbQAK +CRBtco8potur+CMVDACm+OMPck8lmOnNGphP7kKtMcyMyIvsI2Ik/fB3A2z+iXnX +TQljubYTqN4Hzv5MECoUhm3GiWJOYjGoXnpec1zAk4VAewin1814Dldq/9CQ+YlN +W7HKjCiCBSdk2tPEBUK6gfV+OU9N2mNp/+biuwNTVHpPokIiwBE3MKjtUc0W0xLU +N+S/mb1l0MsA91PPRlZqovEFs6214zo8e31pXcWbLbfhbVY32pqDk4eG1JAFjjGM +oBASk7z1TH8Ealfj3xr8/HCbfyoaMcSmQzYdEr4E7XOp955IjRU91RrHxYjcxQ9f +0VUwak08k6hNBD502jstv5ePJBWoFXYXKuBlaH224Xvhe+9GnaUXsU8rI+OMHJes +g4/98+bparaQ8pjhLeh5BoIhojg0y4qNaFmbJraZxG3uhyH0nDVfepOsUj4QOadS +VbuULwAy97q+UFwUWuVn/XVzrb3B35TpIJWpvJLF6w5f3pyy58XsVOfVmNyyGuyU +jMWUGxIGAsXZusCmsNs= +=qVV5 +-----END PGP SIGNATURE----- diff --git a/tests/data/test2.json b/tests/data/test2.json new file mode 100644 index 0000000..8d795a1 --- /dev/null +++ b/tests/data/test2.json @@ -0,0 +1,16 @@ +{ + "last_digest": "564623a3afcedc19737f7002885bb62529bd8125f4dd6b0d6efd57ab768fb773", + "commands": [ + { + "url": "/v1/auth/tee/tees/test", + "data": { + "lease": "1000", + "name": "test", + "sgx_allowed_tcb_levels": "Ok,SwHardeningNeeded", + "sgx_mrsigner": "c5591a72b8b86e0d8814d6e8750e3efe66aea2d102b8ba2405365559b858697d", + "token_policies": "test", + "types": "sgx" + } + } + ] +} diff --git a/tests/data/test2.json.asc b/tests/data/test2.json.asc new file mode 100644 index 0000000..4497af1 --- /dev/null +++ b/tests/data/test2.json.asc @@ -0,0 +1,14 @@ +-----BEGIN PGP SIGNATURE----- + +iQHFBAABCAAvFiEEgaMSxZ1nnZMPqeiwbXKPKaLbq/gFAmTSQ7sRHHRlc3RAZXhh +bXBsZS5jb20ACgkQbXKPKaLbq/jd0Av/Zruw1+nsVFwVIF98IhK4rWoW4vV3Xims +wMpAxoV2wTlk55xHbGkWa0BHnjvJr3XlwyJtEI4fT4rL53AgsSd/kp0/2Ml6ExgN +LGgziTf+Ct6oHPSM8YDtBXWtFv8YwieSxTYNA1hlCkwpN1d1k8JLZj4i1+U1AhPL +nYtM2PLOxxkdFCx7ecp2GCKqsZa1qR+dc+igAHJ4mKKKR9bhhtTxf1tH3nf1BAWu +G3Kw+CZISX4IvuUFVC/AA/+g2ySBoLhmk01lzjYvlJHQyJiOlSpHo1nGBvQHZ9cO +32I0dn+GOlnzCnsYX4JBsiGrNXG1PfEqL0MbNdrVf8grRC96zwQ9ITio25DaRe1r +rO+i68aAS3f9XGGJ1YHUKCAAmCnwPz+x34gH6r6r8LOI+ZRnFKbUDd7Fbuy47EXb +oKe3/oGfnY6avn+/2dR1qeHwnN+CSW64UDChWFXyxCD17go7crGq1MhpNvlmmuxW +HRI4+gMa4DpiCrzDgCS4ZVaZyzIwIvWw +=X/H8 +-----END PGP SIGNATURE----- diff --git a/tests/sgx_quote_verification.rs b/tests/sgx_quote_verification.rs new file mode 100644 index 0000000..f095e63 --- /dev/null +++ b/tests/sgx_quote_verification.rs @@ -0,0 +1,3679 @@ +// SPDX-License-Identifier: Apache-2.0 + +mod sgx { + use anyhow::Result; + use intel_tee_quote_verification_rs::{sgx_ql_qv_result_t, Collateral}; + use std::time::{Duration, UNIX_EPOCH}; + use teepot::sgx::{verify_quote_with_collateral, QuoteVerificationResult}; + + fn check_quote( + quote: &[u8], + collateral: &Collateral, + current_time: i64, + expected_mrsigner: &[u8], + expected_reportdata: &[u8], + expected_result: sgx_ql_qv_result_t, + ) -> Result<()> { + let QuoteVerificationResult { + collateral_expired, + result, + earliest_expiration_date, + quote, + advisories, + tcb_level_date_tag, + } = verify_quote_with_collateral(quote, Some(collateral), current_time).unwrap(); + + if collateral_expired || !matches!(result, sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OK) { + print!("Attestation failed: "); + + if collateral_expired { + println!("\t Collateral is out of date!"); + let earliest_expiration_date = + UNIX_EPOCH + Duration::from_secs(earliest_expiration_date as u64); + println!( + "\tCollateral expiration date: {:?}", + earliest_expiration_date + ); + } + + match result { + sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OK => (), + sgx_ql_qv_result_t::SGX_QL_QV_RESULT_CONFIG_NEEDED => println!("Config needed"), + sgx_ql_qv_result_t::SGX_QL_QV_RESULT_CONFIG_AND_SW_HARDENING_NEEDED => { + println!("Config and Software hardening needed") + } + sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OUT_OF_DATE => println!("Out of date"), + sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OUT_OF_DATE_CONFIG_NEEDED => { + println!("Out of Date and Config needed") + } + sgx_ql_qv_result_t::SGX_QL_QV_RESULT_SW_HARDENING_NEEDED => { + println!("Software hardening needed") + } + sgx_ql_qv_result_t::SGX_QL_QV_RESULT_INVALID_SIGNATURE => { + println!("Invalid signature") + } + sgx_ql_qv_result_t::SGX_QL_QV_RESULT_REVOKED => println!("Revoked"), + sgx_ql_qv_result_t::SGX_QL_QV_RESULT_UNSPECIFIED => println!("Unspecified"), + + _ => println!("Unknown state!"), + } + } + + for advisory in advisories { + println!("\tInfo: Advisory ID: {advisory}"); + } + + println!("tcb_level_date_tag: {:?}", tcb_level_date_tag); + + assert_eq!(expected_result, result); + let expected_reportdata = hex::encode(expected_reportdata); + let expected_mrsigner = hex::encode(expected_mrsigner); + let actual_reportdata = hex::encode("e.report_body.reportdata[..]); + let actual_mrsigner = hex::encode("e.report_body.mrsigner[..]); + assert_eq!(expected_mrsigner, actual_mrsigner); + assert_eq!(expected_reportdata, actual_reportdata); + Ok(()) + } + + #[test] + fn sw_hardening() { + let quote = [ + 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x0e, 0x00, 0x93, 0x9a, + 0x72, 0x33, 0xf7, 0x9c, 0x4c, 0xa9, 0x94, 0x0a, 0x0d, 0xb3, 0x95, 0x7f, 0x06, 0x07, + 0xe2, 0x5d, 0x0f, 0x4e, 0x64, 0x9c, 0xd7, 0xd8, 0xc7, 0x88, 0xbf, 0xc2, 0x7b, 0xca, + 0x4f, 0x78, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x0b, 0x0f, 0x0e, 0xff, 0xff, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x4c, 0xfb, 0xda, 0x9c, 0x05, 0x62, 0xfb, 0xab, 0x7d, 0x5c, 0x11, 0xeb, 0xcb, 0xd2, + 0x93, 0x32, 0x63, 0x97, 0xb4, 0x3e, 0x18, 0x20, 0x55, 0x0a, 0x0b, 0xb0, 0x92, 0x93, + 0x08, 0x8c, 0x8d, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x80, 0x37, 0xd8, 0x87, 0x82, + 0xe0, 0x22, 0xe0, 0x19, 0xb3, 0x02, 0x07, 0x45, 0xb7, 0x8a, 0xa4, 0x0e, 0xd9, 0x5c, + 0x77, 0xda, 0x4b, 0xf7, 0xf3, 0x25, 0x3d, 0x3a, 0x44, 0xc4, 0xfd, 0x7e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, + 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0xca, 0x10, + 0x00, 0x00, 0x83, 0x90, 0x4f, 0x15, 0x14, 0x92, 0xe7, 0xfb, 0xcf, 0xa9, 0xf6, 0x11, + 0xf9, 0xce, 0x13, 0xc1, 0xb9, 0x80, 0xbc, 0x39, 0x38, 0x15, 0x18, 0x1f, 0x4a, 0x75, + 0x18, 0x70, 0x69, 0xb9, 0x1c, 0x1c, 0x8c, 0x7a, 0x38, 0x9d, 0x93, 0x77, 0x32, 0x14, + 0x05, 0xd3, 0x97, 0x22, 0x4f, 0x7d, 0xa8, 0x83, 0x40, 0xcc, 0x4f, 0x7a, 0x20, 0x9d, + 0xfe, 0x9b, 0xfe, 0x9c, 0xf0, 0x29, 0xa9, 0xd9, 0x03, 0xb7, 0xcd, 0xd2, 0x06, 0xa2, + 0xec, 0x48, 0x1b, 0xd8, 0x66, 0x0b, 0xbb, 0xa3, 0xed, 0xcc, 0xa7, 0x75, 0x2c, 0x12, + 0x30, 0xd9, 0x23, 0xfd, 0x37, 0x7f, 0x38, 0x45, 0xa5, 0x87, 0x03, 0xbe, 0x5d, 0x02, + 0x03, 0xbe, 0x4a, 0x16, 0xd3, 0x8c, 0x88, 0xc5, 0xd4, 0x75, 0x51, 0x20, 0x5e, 0xbd, + 0xc5, 0xfc, 0x41, 0x36, 0xc8, 0xe4, 0x80, 0x60, 0x3e, 0x0f, 0xbb, 0x36, 0x76, 0x07, + 0x34, 0x3e, 0xac, 0x85, 0x0b, 0x0b, 0x0f, 0x0e, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x2a, + 0xa5, 0x0c, 0xe1, 0xc0, 0xce, 0xf0, 0x3c, 0xcf, 0x89, 0xe7, 0xb5, 0xb1, 0x6b, 0x0d, + 0x79, 0x78, 0xf5, 0xc2, 0xb1, 0xed, 0xcf, 0x77, 0x4d, 0x87, 0x70, 0x2e, 0x81, 0x54, + 0xd8, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x4f, 0x57, 0x75, 0xd7, 0x96, 0x50, 0x3e, + 0x96, 0x13, 0x7f, 0x77, 0xc6, 0x8a, 0x82, 0x9a, 0x00, 0x56, 0xac, 0x8d, 0xed, 0x70, + 0x14, 0x0b, 0x08, 0x1b, 0x09, 0x44, 0x90, 0xc5, 0x7b, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7a, 0xce, 0x06, 0x57, 0x43, 0xb2, 0x7d, 0x7e, 0xf9, 0x2d, 0x74, 0xf6, + 0x68, 0x1e, 0x6b, 0x61, 0x34, 0x08, 0xfc, 0xe1, 0x9b, 0xcf, 0x73, 0xda, 0x46, 0xab, + 0xaa, 0xe8, 0xb3, 0x99, 0xd9, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x6a, 0x09, 0x0d, + 0xd1, 0x55, 0xb5, 0x8c, 0x29, 0xd8, 0x73, 0x2d, 0x82, 0xf2, 0x76, 0x0b, 0xad, 0x26, + 0x5e, 0xa5, 0x4b, 0x95, 0x18, 0x4a, 0xf5, 0x6d, 0xa5, 0xd4, 0xe1, 0x34, 0x78, 0x11, + 0xcc, 0x78, 0x7c, 0x40, 0xe2, 0xa0, 0xb1, 0x5a, 0x79, 0x88, 0x1b, 0x4f, 0xa1, 0xf4, + 0x32, 0x5c, 0x74, 0x16, 0xf6, 0x9c, 0xfe, 0x56, 0xd5, 0x47, 0x58, 0x93, 0x7a, 0x70, + 0x49, 0xf5, 0xa6, 0x9b, 0x20, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x05, 0x00, 0x62, 0x0e, + 0x00, 0x00, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, + 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x45, 0x38, 0x6a, 0x43, 0x43, 0x42, 0x4a, 0x69, 0x67, + 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x55, 0x4a, 0x66, 0x43, 0x6a, 0x2b, 0x35, + 0x73, 0x48, 0x74, 0x48, 0x47, 0x68, 0x55, 0x78, 0x45, 0x36, 0x45, 0x4d, 0x71, 0x79, + 0x6e, 0x34, 0x73, 0x43, 0x6c, 0x4a, 0x77, 0x77, 0x43, 0x67, 0x59, 0x49, 0x4b, 0x6f, + 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x45, 0x41, 0x77, 0x49, 0x77, 0x0a, 0x63, 0x44, 0x45, + 0x69, 0x4d, 0x43, 0x41, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, 0x77, 0x5a, 0x53, + 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, 0x67, 0x55, 0x30, 0x64, 0x59, 0x49, 0x46, 0x42, + 0x44, 0x53, 0x79, 0x42, 0x51, 0x62, 0x47, 0x46, 0x30, 0x5a, 0x6d, 0x39, 0x79, 0x62, + 0x53, 0x42, 0x44, 0x51, 0x54, 0x45, 0x61, 0x4d, 0x42, 0x67, 0x47, 0x41, 0x31, 0x55, + 0x45, 0x43, 0x67, 0x77, 0x52, 0x0a, 0x53, 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, 0x67, + 0x51, 0x32, 0x39, 0x79, 0x63, 0x47, 0x39, 0x79, 0x59, 0x58, 0x52, 0x70, 0x62, 0x32, + 0x34, 0x78, 0x46, 0x44, 0x41, 0x53, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x63, 0x4d, + 0x43, 0x31, 0x4e, 0x68, 0x62, 0x6e, 0x52, 0x68, 0x49, 0x45, 0x4e, 0x73, 0x59, 0x58, + 0x4a, 0x68, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x49, + 0x0a, 0x44, 0x41, 0x4a, 0x44, 0x51, 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x77, 0x48, 0x68, 0x63, + 0x4e, 0x4d, 0x6a, 0x4d, 0x77, 0x4e, 0x44, 0x45, 0x7a, 0x4d, 0x54, 0x63, 0x7a, 0x4e, + 0x7a, 0x41, 0x33, 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x7a, 0x41, 0x77, 0x4e, 0x44, 0x45, + 0x7a, 0x4d, 0x54, 0x63, 0x7a, 0x4e, 0x7a, 0x41, 0x33, 0x0a, 0x57, 0x6a, 0x42, 0x77, + 0x4d, 0x53, 0x49, 0x77, 0x49, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x44, 0x42, + 0x6c, 0x4a, 0x62, 0x6e, 0x52, 0x6c, 0x62, 0x43, 0x42, 0x54, 0x52, 0x31, 0x67, 0x67, + 0x55, 0x45, 0x4e, 0x4c, 0x49, 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, + 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x6c, 0x4d, 0x52, 0x6f, 0x77, 0x47, 0x41, 0x59, 0x44, + 0x56, 0x51, 0x51, 0x4b, 0x0a, 0x44, 0x42, 0x46, 0x4a, 0x62, 0x6e, 0x52, 0x6c, 0x62, + 0x43, 0x42, 0x44, 0x62, 0x33, 0x4a, 0x77, 0x62, 0x33, 0x4a, 0x68, 0x64, 0x47, 0x6c, + 0x76, 0x62, 0x6a, 0x45, 0x55, 0x4d, 0x42, 0x49, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, + 0x77, 0x77, 0x4c, 0x55, 0x32, 0x46, 0x75, 0x64, 0x47, 0x45, 0x67, 0x51, 0x32, 0x78, + 0x68, 0x63, 0x6d, 0x45, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x0a, + 0x42, 0x41, 0x67, 0x4d, 0x41, 0x6b, 0x4e, 0x42, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, + 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x42, 0x5a, + 0x4d, 0x42, 0x4d, 0x47, 0x42, 0x79, 0x71, 0x47, 0x53, 0x4d, 0x34, 0x39, 0x41, 0x67, + 0x45, 0x47, 0x43, 0x43, 0x71, 0x47, 0x53, 0x4d, 0x34, 0x39, 0x41, 0x77, 0x45, 0x48, + 0x41, 0x30, 0x49, 0x41, 0x42, 0x47, 0x5a, 0x4c, 0x0a, 0x48, 0x38, 0x70, 0x47, 0x4f, + 0x5a, 0x69, 0x7a, 0x38, 0x6a, 0x4e, 0x34, 0x37, 0x4e, 0x2b, 0x50, 0x59, 0x6b, 0x58, + 0x65, 0x42, 0x31, 0x57, 0x79, 0x6e, 0x53, 0x4a, 0x34, 0x48, 0x2f, 0x53, 0x49, 0x61, + 0x30, 0x30, 0x47, 0x6a, 0x57, 0x5a, 0x78, 0x4b, 0x55, 0x62, 0x44, 0x67, 0x32, 0x58, + 0x4d, 0x78, 0x47, 0x45, 0x64, 0x4d, 0x74, 0x4c, 0x47, 0x7a, 0x79, 0x79, 0x4c, 0x50, + 0x35, 0x63, 0x70, 0x0a, 0x7a, 0x30, 0x62, 0x4d, 0x32, 0x6f, 0x58, 0x32, 0x57, 0x2b, + 0x6a, 0x4d, 0x51, 0x39, 0x5a, 0x2f, 0x4a, 0x36, 0x79, 0x6a, 0x67, 0x67, 0x4d, 0x4f, + 0x4d, 0x49, 0x49, 0x44, 0x43, 0x6a, 0x41, 0x66, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x53, + 0x4d, 0x45, 0x47, 0x44, 0x41, 0x57, 0x67, 0x42, 0x53, 0x56, 0x62, 0x31, 0x33, 0x4e, + 0x76, 0x52, 0x76, 0x68, 0x36, 0x55, 0x42, 0x4a, 0x79, 0x64, 0x54, 0x30, 0x0a, 0x4d, + 0x38, 0x34, 0x42, 0x56, 0x77, 0x76, 0x65, 0x56, 0x44, 0x42, 0x72, 0x42, 0x67, 0x4e, + 0x56, 0x48, 0x52, 0x38, 0x45, 0x5a, 0x44, 0x42, 0x69, 0x4d, 0x47, 0x43, 0x67, 0x58, + 0x71, 0x42, 0x63, 0x68, 0x6c, 0x70, 0x6f, 0x64, 0x48, 0x52, 0x77, 0x63, 0x7a, 0x6f, + 0x76, 0x4c, 0x32, 0x46, 0x77, 0x61, 0x53, 0x35, 0x30, 0x63, 0x6e, 0x56, 0x7a, 0x64, + 0x47, 0x56, 0x6b, 0x63, 0x32, 0x56, 0x79, 0x0a, 0x64, 0x6d, 0x6c, 0x6a, 0x5a, 0x58, + 0x4d, 0x75, 0x61, 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, 0x75, 0x59, 0x32, 0x39, 0x74, + 0x4c, 0x33, 0x4e, 0x6e, 0x65, 0x43, 0x39, 0x6a, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57, + 0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x4c, 0x33, 0x59, 0x7a, + 0x4c, 0x33, 0x42, 0x6a, 0x61, 0x32, 0x4e, 0x79, 0x62, 0x44, 0x39, 0x6a, 0x59, 0x54, + 0x31, 0x77, 0x0a, 0x62, 0x47, 0x46, 0x30, 0x5a, 0x6d, 0x39, 0x79, 0x62, 0x53, 0x5a, + 0x6c, 0x62, 0x6d, 0x4e, 0x76, 0x5a, 0x47, 0x6c, 0x75, 0x5a, 0x7a, 0x31, 0x6b, 0x5a, + 0x58, 0x49, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, + 0x45, 0x46, 0x4b, 0x47, 0x44, 0x38, 0x50, 0x75, 0x50, 0x42, 0x63, 0x63, 0x54, 0x43, + 0x64, 0x76, 0x6e, 0x41, 0x75, 0x58, 0x46, 0x49, 0x56, 0x66, 0x36, 0x0a, 0x76, 0x49, + 0x6b, 0x48, 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77, 0x45, 0x42, + 0x2f, 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, 0x47, 0x77, 0x44, 0x41, 0x4d, 0x42, 0x67, + 0x4e, 0x56, 0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x45, 0x41, 0x6a, 0x41, 0x41, + 0x4d, 0x49, 0x49, 0x43, 0x4f, 0x77, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, + 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x0a, 0x42, 0x49, 0x49, 0x43, 0x4c, 0x44, 0x43, + 0x43, 0x41, 0x69, 0x67, 0x77, 0x48, 0x67, 0x59, 0x4b, 0x4b, 0x6f, 0x5a, 0x49, 0x68, + 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x51, 0x51, 0x51, 0x55, 0x59, 0x50, + 0x38, 0x65, 0x34, 0x73, 0x4c, 0x7a, 0x66, 0x73, 0x45, 0x34, 0x54, 0x64, 0x62, 0x6f, + 0x53, 0x79, 0x44, 0x52, 0x54, 0x43, 0x43, 0x41, 0x57, 0x55, 0x47, 0x43, 0x69, 0x71, + 0x47, 0x0a, 0x53, 0x49, 0x62, 0x34, 0x54, 0x51, 0x45, 0x4e, 0x41, 0x51, 0x49, 0x77, + 0x67, 0x67, 0x46, 0x56, 0x4d, 0x42, 0x41, 0x47, 0x43, 0x79, 0x71, 0x47, 0x53, 0x49, + 0x62, 0x34, 0x54, 0x51, 0x45, 0x4e, 0x41, 0x51, 0x49, 0x42, 0x41, 0x67, 0x45, 0x4c, + 0x4d, 0x42, 0x41, 0x47, 0x43, 0x79, 0x71, 0x47, 0x53, 0x49, 0x62, 0x34, 0x54, 0x51, + 0x45, 0x4e, 0x41, 0x51, 0x49, 0x43, 0x41, 0x67, 0x45, 0x4c, 0x0a, 0x4d, 0x42, 0x41, + 0x47, 0x43, 0x79, 0x71, 0x47, 0x53, 0x49, 0x62, 0x34, 0x54, 0x51, 0x45, 0x4e, 0x41, + 0x51, 0x49, 0x44, 0x41, 0x67, 0x45, 0x44, 0x4d, 0x42, 0x41, 0x47, 0x43, 0x79, 0x71, + 0x47, 0x53, 0x49, 0x62, 0x34, 0x54, 0x51, 0x45, 0x4e, 0x41, 0x51, 0x49, 0x45, 0x41, + 0x67, 0x45, 0x44, 0x4d, 0x42, 0x45, 0x47, 0x43, 0x79, 0x71, 0x47, 0x53, 0x49, 0x62, + 0x34, 0x54, 0x51, 0x45, 0x4e, 0x0a, 0x41, 0x51, 0x49, 0x46, 0x41, 0x67, 0x49, 0x41, + 0x2f, 0x7a, 0x41, 0x52, 0x42, 0x67, 0x73, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x2b, 0x45, + 0x30, 0x42, 0x44, 0x51, 0x45, 0x43, 0x42, 0x67, 0x49, 0x43, 0x41, 0x50, 0x38, 0x77, + 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, + 0x30, 0x42, 0x41, 0x67, 0x63, 0x43, 0x41, 0x51, 0x45, 0x77, 0x45, 0x41, 0x59, 0x4c, + 0x0a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, + 0x67, 0x67, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, + 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, 0x6b, 0x43, 0x41, + 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, + 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, 0x6f, 0x43, 0x0a, 0x41, 0x51, 0x41, 0x77, + 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, + 0x30, 0x42, 0x41, 0x67, 0x73, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, + 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, + 0x77, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, + 0x68, 0x76, 0x68, 0x4e, 0x0a, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, 0x30, 0x43, 0x41, + 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, + 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, 0x34, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, + 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, + 0x42, 0x41, 0x67, 0x38, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x0a, + 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x68, + 0x41, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, + 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x68, 0x45, 0x43, 0x41, 0x51, + 0x30, 0x77, 0x48, 0x77, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, + 0x41, 0x51, 0x30, 0x42, 0x41, 0x68, 0x49, 0x45, 0x0a, 0x45, 0x41, 0x73, 0x4c, 0x41, + 0x77, 0x50, 0x2f, 0x2f, 0x77, 0x45, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4b, 0x4b, 0x6f, 0x5a, 0x49, 0x68, + 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x77, 0x51, 0x43, 0x41, 0x41, 0x41, + 0x77, 0x46, 0x41, 0x59, 0x4b, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, + 0x51, 0x30, 0x42, 0x0a, 0x42, 0x41, 0x51, 0x47, 0x41, 0x47, 0x42, 0x71, 0x41, 0x41, + 0x41, 0x41, 0x4d, 0x41, 0x38, 0x47, 0x43, 0x69, 0x71, 0x47, 0x53, 0x49, 0x62, 0x34, + 0x54, 0x51, 0x45, 0x4e, 0x41, 0x51, 0x55, 0x4b, 0x41, 0x51, 0x45, 0x77, 0x48, 0x67, + 0x59, 0x4b, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, + 0x42, 0x67, 0x51, 0x51, 0x55, 0x48, 0x50, 0x72, 0x61, 0x78, 0x7a, 0x61, 0x0a, 0x57, + 0x6e, 0x42, 0x4d, 0x69, 0x67, 0x2f, 0x42, 0x49, 0x75, 0x44, 0x66, 0x75, 0x6a, 0x42, + 0x45, 0x42, 0x67, 0x6f, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x2b, 0x45, 0x30, 0x42, 0x44, + 0x51, 0x45, 0x48, 0x4d, 0x44, 0x59, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, + 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x42, 0x77, 0x45, 0x42, 0x41, + 0x66, 0x38, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x0a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, + 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x42, 0x77, 0x49, 0x42, 0x41, 0x66, 0x38, 0x77, + 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, + 0x30, 0x42, 0x42, 0x77, 0x4d, 0x42, 0x41, 0x51, 0x41, 0x77, 0x43, 0x67, 0x59, 0x49, + 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x45, 0x41, 0x77, 0x49, 0x44, 0x53, 0x41, + 0x41, 0x77, 0x0a, 0x52, 0x51, 0x49, 0x67, 0x52, 0x35, 0x4e, 0x4e, 0x76, 0x6d, 0x77, + 0x73, 0x50, 0x61, 0x77, 0x78, 0x48, 0x4b, 0x61, 0x76, 0x5a, 0x74, 0x33, 0x59, 0x79, + 0x6a, 0x69, 0x58, 0x4e, 0x76, 0x55, 0x7a, 0x79, 0x30, 0x58, 0x31, 0x4a, 0x70, 0x6d, + 0x45, 0x66, 0x77, 0x2b, 0x4c, 0x4a, 0x58, 0x30, 0x43, 0x49, 0x51, 0x44, 0x43, 0x67, + 0x74, 0x76, 0x2f, 0x74, 0x78, 0x42, 0x67, 0x74, 0x6c, 0x54, 0x6b, 0x0a, 0x70, 0x6e, + 0x45, 0x47, 0x73, 0x6c, 0x51, 0x6a, 0x51, 0x6c, 0x39, 0x51, 0x30, 0x46, 0x62, 0x35, + 0x79, 0x73, 0x2f, 0x73, 0x42, 0x51, 0x4e, 0x42, 0x31, 0x75, 0x65, 0x68, 0x75, 0x67, + 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, + 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, + 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x6c, 0x6a, 0x43, 0x43, 0x41, 0x6a, 0x32, 0x67, 0x41, + 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x56, 0x41, 0x4a, 0x56, 0x76, 0x58, 0x63, 0x32, + 0x39, 0x47, 0x2b, 0x48, 0x70, 0x51, 0x45, 0x6e, 0x4a, 0x31, 0x50, 0x51, 0x7a, 0x7a, + 0x67, 0x46, 0x58, 0x43, 0x39, 0x35, 0x55, 0x4d, 0x41, 0x6f, 0x47, 0x43, 0x43, 0x71, + 0x47, 0x53, 0x4d, 0x34, 0x39, 0x42, 0x41, 0x4d, 0x43, 0x0a, 0x4d, 0x47, 0x67, 0x78, + 0x47, 0x6a, 0x41, 0x59, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x4d, 0x45, 0x55, + 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, 0x49, 0x46, 0x4e, 0x48, 0x57, 0x43, 0x42, 0x53, + 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, 0x4e, 0x42, 0x4d, 0x52, 0x6f, 0x77, 0x47, 0x41, + 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x44, 0x42, 0x46, 0x4a, 0x62, 0x6e, 0x52, 0x6c, + 0x62, 0x43, 0x42, 0x44, 0x0a, 0x62, 0x33, 0x4a, 0x77, 0x62, 0x33, 0x4a, 0x68, 0x64, + 0x47, 0x6c, 0x76, 0x62, 0x6a, 0x45, 0x55, 0x4d, 0x42, 0x49, 0x47, 0x41, 0x31, 0x55, + 0x45, 0x42, 0x77, 0x77, 0x4c, 0x55, 0x32, 0x46, 0x75, 0x64, 0x47, 0x45, 0x67, 0x51, + 0x32, 0x78, 0x68, 0x63, 0x6d, 0x45, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x67, 0x4d, 0x41, 0x6b, 0x4e, 0x42, 0x4d, 0x51, 0x73, 0x77, 0x0a, + 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, + 0x41, 0x65, 0x46, 0x77, 0x30, 0x78, 0x4f, 0x44, 0x41, 0x31, 0x4d, 0x6a, 0x45, 0x78, + 0x4d, 0x44, 0x55, 0x77, 0x4d, 0x54, 0x42, 0x61, 0x46, 0x77, 0x30, 0x7a, 0x4d, 0x7a, + 0x41, 0x31, 0x4d, 0x6a, 0x45, 0x78, 0x4d, 0x44, 0x55, 0x77, 0x4d, 0x54, 0x42, 0x61, + 0x4d, 0x48, 0x41, 0x78, 0x49, 0x6a, 0x41, 0x67, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x42, + 0x41, 0x4d, 0x4d, 0x47, 0x55, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, 0x49, 0x46, 0x4e, + 0x48, 0x57, 0x43, 0x42, 0x51, 0x51, 0x30, 0x73, 0x67, 0x55, 0x47, 0x78, 0x68, 0x64, + 0x47, 0x5a, 0x76, 0x63, 0x6d, 0x30, 0x67, 0x51, 0x30, 0x45, 0x78, 0x47, 0x6a, 0x41, + 0x59, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x45, 0x55, 0x6c, 0x75, 0x64, + 0x47, 0x56, 0x73, 0x0a, 0x49, 0x45, 0x4e, 0x76, 0x63, 0x6e, 0x42, 0x76, 0x63, 0x6d, + 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x4d, 0x52, 0x51, 0x77, 0x45, 0x67, 0x59, 0x44, + 0x56, 0x51, 0x51, 0x48, 0x44, 0x41, 0x74, 0x54, 0x59, 0x57, 0x35, 0x30, 0x59, 0x53, + 0x42, 0x44, 0x62, 0x47, 0x46, 0x79, 0x59, 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, + 0x41, 0x31, 0x55, 0x45, 0x43, 0x41, 0x77, 0x43, 0x51, 0x30, 0x45, 0x78, 0x0a, 0x43, + 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6c, 0x56, + 0x54, 0x4d, 0x46, 0x6b, 0x77, 0x45, 0x77, 0x59, 0x48, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, + 0x6a, 0x30, 0x43, 0x41, 0x51, 0x59, 0x49, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, + 0x44, 0x41, 0x51, 0x63, 0x44, 0x51, 0x67, 0x41, 0x45, 0x4e, 0x53, 0x42, 0x2f, 0x37, + 0x74, 0x32, 0x31, 0x6c, 0x58, 0x53, 0x4f, 0x0a, 0x32, 0x43, 0x75, 0x7a, 0x70, 0x78, + 0x77, 0x37, 0x34, 0x65, 0x4a, 0x42, 0x37, 0x32, 0x45, 0x79, 0x44, 0x47, 0x67, 0x57, + 0x35, 0x72, 0x58, 0x43, 0x74, 0x78, 0x32, 0x74, 0x56, 0x54, 0x4c, 0x71, 0x36, 0x68, + 0x4b, 0x6b, 0x36, 0x7a, 0x2b, 0x55, 0x69, 0x52, 0x5a, 0x43, 0x6e, 0x71, 0x52, 0x37, + 0x70, 0x73, 0x4f, 0x76, 0x67, 0x71, 0x46, 0x65, 0x53, 0x78, 0x6c, 0x6d, 0x54, 0x6c, + 0x4a, 0x6c, 0x0a, 0x65, 0x54, 0x6d, 0x69, 0x32, 0x57, 0x59, 0x7a, 0x33, 0x71, 0x4f, + 0x42, 0x75, 0x7a, 0x43, 0x42, 0x75, 0x44, 0x41, 0x66, 0x42, 0x67, 0x4e, 0x56, 0x48, + 0x53, 0x4d, 0x45, 0x47, 0x44, 0x41, 0x57, 0x67, 0x42, 0x51, 0x69, 0x5a, 0x51, 0x7a, + 0x57, 0x57, 0x70, 0x30, 0x30, 0x69, 0x66, 0x4f, 0x44, 0x74, 0x4a, 0x56, 0x53, 0x76, + 0x31, 0x41, 0x62, 0x4f, 0x53, 0x63, 0x47, 0x72, 0x44, 0x42, 0x53, 0x0a, 0x42, 0x67, + 0x4e, 0x56, 0x48, 0x52, 0x38, 0x45, 0x53, 0x7a, 0x42, 0x4a, 0x4d, 0x45, 0x65, 0x67, + 0x52, 0x61, 0x42, 0x44, 0x68, 0x6b, 0x46, 0x6f, 0x64, 0x48, 0x52, 0x77, 0x63, 0x7a, + 0x6f, 0x76, 0x4c, 0x32, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, + 0x59, 0x58, 0x52, 0x6c, 0x63, 0x79, 0x35, 0x30, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x47, + 0x56, 0x6b, 0x63, 0x32, 0x56, 0x79, 0x0a, 0x64, 0x6d, 0x6c, 0x6a, 0x5a, 0x58, 0x4d, + 0x75, 0x61, 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, 0x75, 0x59, 0x32, 0x39, 0x74, 0x4c, + 0x30, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, 0x55, 0x30, 0x64, 0x59, 0x55, 0x6d, 0x39, + 0x76, 0x64, 0x45, 0x4e, 0x42, 0x4c, 0x6d, 0x52, 0x6c, 0x63, 0x6a, 0x41, 0x64, 0x42, + 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, 0x51, 0x55, 0x6c, 0x57, 0x39, + 0x64, 0x0a, 0x7a, 0x62, 0x30, 0x62, 0x34, 0x65, 0x6c, 0x41, 0x53, 0x63, 0x6e, 0x55, + 0x39, 0x44, 0x50, 0x4f, 0x41, 0x56, 0x63, 0x4c, 0x33, 0x6c, 0x51, 0x77, 0x44, 0x67, + 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x51, 0x44, + 0x41, 0x67, 0x45, 0x47, 0x4d, 0x42, 0x49, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, + 0x45, 0x42, 0x2f, 0x77, 0x51, 0x49, 0x4d, 0x41, 0x59, 0x42, 0x0a, 0x41, 0x66, 0x38, + 0x43, 0x41, 0x51, 0x41, 0x77, 0x43, 0x67, 0x59, 0x49, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, + 0x6a, 0x30, 0x45, 0x41, 0x77, 0x49, 0x44, 0x52, 0x77, 0x41, 0x77, 0x52, 0x41, 0x49, + 0x67, 0x58, 0x73, 0x56, 0x6b, 0x69, 0x30, 0x77, 0x2b, 0x69, 0x36, 0x56, 0x59, 0x47, + 0x57, 0x33, 0x55, 0x46, 0x2f, 0x32, 0x32, 0x75, 0x61, 0x58, 0x65, 0x30, 0x59, 0x4a, + 0x44, 0x6a, 0x31, 0x55, 0x65, 0x0a, 0x6e, 0x41, 0x2b, 0x54, 0x6a, 0x44, 0x31, 0x61, + 0x69, 0x35, 0x63, 0x43, 0x49, 0x43, 0x59, 0x62, 0x31, 0x53, 0x41, 0x6d, 0x44, 0x35, + 0x78, 0x6b, 0x66, 0x54, 0x56, 0x70, 0x76, 0x6f, 0x34, 0x55, 0x6f, 0x79, 0x69, 0x53, + 0x59, 0x78, 0x72, 0x44, 0x57, 0x4c, 0x6d, 0x55, 0x52, 0x34, 0x43, 0x49, 0x39, 0x4e, + 0x4b, 0x79, 0x66, 0x50, 0x4e, 0x2b, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, + 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, + 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x6a, 0x7a, 0x43, 0x43, 0x41, + 0x6a, 0x53, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x55, 0x49, 0x6d, 0x55, + 0x4d, 0x31, 0x6c, 0x71, 0x64, 0x4e, 0x49, 0x6e, 0x7a, 0x67, 0x37, 0x53, 0x56, 0x55, + 0x72, 0x39, 0x51, 0x47, 0x7a, 0x6b, 0x6e, 0x42, 0x71, 0x77, 0x77, 0x43, 0x67, 0x59, + 0x49, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x45, 0x41, 0x77, 0x49, 0x77, 0x0a, + 0x61, 0x44, 0x45, 0x61, 0x4d, 0x42, 0x67, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, + 0x77, 0x52, 0x53, 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, 0x67, 0x55, 0x30, 0x64, 0x59, + 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, 0x51, 0x30, 0x45, 0x78, 0x47, 0x6a, + 0x41, 0x59, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x45, 0x55, 0x6c, 0x75, + 0x64, 0x47, 0x56, 0x73, 0x49, 0x45, 0x4e, 0x76, 0x0a, 0x63, 0x6e, 0x42, 0x76, 0x63, + 0x6d, 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x4d, 0x52, 0x51, 0x77, 0x45, 0x67, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x48, 0x44, 0x41, 0x74, 0x54, 0x59, 0x57, 0x35, 0x30, 0x59, + 0x53, 0x42, 0x44, 0x62, 0x47, 0x46, 0x79, 0x59, 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x41, 0x77, 0x43, 0x51, 0x30, 0x45, 0x78, 0x43, + 0x7a, 0x41, 0x4a, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6c, + 0x56, 0x54, 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, 0x45, 0x34, 0x4d, 0x44, 0x55, 0x79, + 0x4d, 0x54, 0x45, 0x77, 0x4e, 0x44, 0x55, 0x78, 0x4d, 0x46, 0x6f, 0x58, 0x44, 0x54, + 0x51, 0x35, 0x4d, 0x54, 0x49, 0x7a, 0x4d, 0x54, 0x49, 0x7a, 0x4e, 0x54, 0x6b, 0x31, + 0x4f, 0x56, 0x6f, 0x77, 0x61, 0x44, 0x45, 0x61, 0x4d, 0x42, 0x67, 0x47, 0x0a, 0x41, + 0x31, 0x55, 0x45, 0x41, 0x77, 0x77, 0x52, 0x53, 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, + 0x67, 0x55, 0x30, 0x64, 0x59, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, 0x51, + 0x30, 0x45, 0x78, 0x47, 0x6a, 0x41, 0x59, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, + 0x4d, 0x45, 0x55, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, 0x49, 0x45, 0x4e, 0x76, 0x63, + 0x6e, 0x42, 0x76, 0x63, 0x6d, 0x46, 0x30, 0x0a, 0x61, 0x57, 0x39, 0x75, 0x4d, 0x52, + 0x51, 0x77, 0x45, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x48, 0x44, 0x41, 0x74, 0x54, + 0x59, 0x57, 0x35, 0x30, 0x59, 0x53, 0x42, 0x44, 0x62, 0x47, 0x46, 0x79, 0x59, 0x54, + 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x41, 0x77, 0x43, + 0x51, 0x30, 0x45, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, + 0x59, 0x54, 0x0a, 0x41, 0x6c, 0x56, 0x54, 0x4d, 0x46, 0x6b, 0x77, 0x45, 0x77, 0x59, + 0x48, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x43, 0x41, 0x51, 0x59, 0x49, 0x4b, + 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x44, 0x41, 0x51, 0x63, 0x44, 0x51, 0x67, 0x41, + 0x45, 0x43, 0x36, 0x6e, 0x45, 0x77, 0x4d, 0x44, 0x49, 0x59, 0x5a, 0x4f, 0x6a, 0x2f, + 0x69, 0x50, 0x57, 0x73, 0x43, 0x7a, 0x61, 0x45, 0x4b, 0x69, 0x37, 0x0a, 0x31, 0x4f, + 0x69, 0x4f, 0x53, 0x4c, 0x52, 0x46, 0x68, 0x57, 0x47, 0x6a, 0x62, 0x6e, 0x42, 0x56, + 0x4a, 0x66, 0x56, 0x6e, 0x6b, 0x59, 0x34, 0x75, 0x33, 0x49, 0x6a, 0x6b, 0x44, 0x59, + 0x59, 0x4c, 0x30, 0x4d, 0x78, 0x4f, 0x34, 0x6d, 0x71, 0x73, 0x79, 0x59, 0x6a, 0x6c, + 0x42, 0x61, 0x6c, 0x54, 0x56, 0x59, 0x78, 0x46, 0x50, 0x32, 0x73, 0x4a, 0x42, 0x4b, + 0x35, 0x7a, 0x6c, 0x4b, 0x4f, 0x42, 0x0a, 0x75, 0x7a, 0x43, 0x42, 0x75, 0x44, 0x41, + 0x66, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x53, 0x4d, 0x45, 0x47, 0x44, 0x41, 0x57, 0x67, + 0x42, 0x51, 0x69, 0x5a, 0x51, 0x7a, 0x57, 0x57, 0x70, 0x30, 0x30, 0x69, 0x66, 0x4f, + 0x44, 0x74, 0x4a, 0x56, 0x53, 0x76, 0x31, 0x41, 0x62, 0x4f, 0x53, 0x63, 0x47, 0x72, + 0x44, 0x42, 0x53, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x38, 0x45, 0x53, 0x7a, 0x42, + 0x4a, 0x0a, 0x4d, 0x45, 0x65, 0x67, 0x52, 0x61, 0x42, 0x44, 0x68, 0x6b, 0x46, 0x6f, + 0x64, 0x48, 0x52, 0x77, 0x63, 0x7a, 0x6f, 0x76, 0x4c, 0x32, 0x4e, 0x6c, 0x63, 0x6e, + 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x6c, 0x63, 0x79, 0x35, 0x30, + 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x47, 0x56, 0x6b, 0x63, 0x32, 0x56, 0x79, 0x64, 0x6d, + 0x6c, 0x6a, 0x5a, 0x58, 0x4d, 0x75, 0x61, 0x57, 0x35, 0x30, 0x0a, 0x5a, 0x57, 0x77, + 0x75, 0x59, 0x32, 0x39, 0x74, 0x4c, 0x30, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, 0x55, + 0x30, 0x64, 0x59, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x45, 0x4e, 0x42, 0x4c, 0x6d, 0x52, + 0x6c, 0x63, 0x6a, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, + 0x67, 0x51, 0x55, 0x49, 0x6d, 0x55, 0x4d, 0x31, 0x6c, 0x71, 0x64, 0x4e, 0x49, 0x6e, + 0x7a, 0x67, 0x37, 0x53, 0x56, 0x0a, 0x55, 0x72, 0x39, 0x51, 0x47, 0x7a, 0x6b, 0x6e, + 0x42, 0x71, 0x77, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, + 0x48, 0x2f, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x45, 0x47, 0x4d, 0x42, 0x49, 0x47, + 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x49, 0x4d, 0x41, + 0x59, 0x42, 0x41, 0x66, 0x38, 0x43, 0x41, 0x51, 0x45, 0x77, 0x43, 0x67, 0x59, 0x49, + 0x0a, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x45, 0x41, 0x77, 0x49, 0x44, 0x53, + 0x51, 0x41, 0x77, 0x52, 0x67, 0x49, 0x68, 0x41, 0x4f, 0x57, 0x2f, 0x35, 0x51, 0x6b, + 0x52, 0x2b, 0x53, 0x39, 0x43, 0x69, 0x53, 0x44, 0x63, 0x4e, 0x6f, 0x6f, 0x77, 0x4c, + 0x75, 0x50, 0x52, 0x4c, 0x73, 0x57, 0x47, 0x66, 0x2f, 0x59, 0x69, 0x37, 0x47, 0x53, + 0x58, 0x39, 0x34, 0x42, 0x67, 0x77, 0x54, 0x77, 0x67, 0x0a, 0x41, 0x69, 0x45, 0x41, + 0x34, 0x4a, 0x30, 0x6c, 0x72, 0x48, 0x6f, 0x4d, 0x73, 0x2b, 0x58, 0x6f, 0x35, 0x6f, + 0x2f, 0x73, 0x58, 0x36, 0x4f, 0x39, 0x51, 0x57, 0x78, 0x48, 0x52, 0x41, 0x76, 0x5a, + 0x55, 0x47, 0x4f, 0x64, 0x52, 0x51, 0x37, 0x63, 0x76, 0x71, 0x52, 0x58, 0x61, 0x71, + 0x49, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, + 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x0a, 0x00, + ]; + + let collateral = Collateral { + major_version: 3, + minor_version: 1, + tee_type: 0, + pck_crl_issuer_chain: [ + 45, 45, 45, 45, 45, 66, 69, 71, 73, 78, 32, 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, + 69, 45, 45, 45, 45, 45, 10, 77, 73, 73, 67, 108, 106, 67, 67, 65, 106, 50, 103, 65, + 119, 73, 66, 65, 103, 73, 86, 65, 74, 86, 118, 88, 99, 50, 57, 71, 43, 72, 112, 81, + 69, 110, 74, 49, 80, 81, 122, 122, 103, 70, 88, 67, 57, 53, 85, 77, 65, 111, 71, + 67, 67, 113, 71, 83, 77, 52, 57, 66, 65, 77, 67, 10, 77, 71, 103, 120, 71, 106, 65, + 89, 66, 103, 78, 86, 66, 65, 77, 77, 69, 85, 108, 117, 100, 71, 86, 115, 73, 70, + 78, 72, 87, 67, 66, 83, 98, 50, 57, 48, 73, 69, 78, 66, 77, 82, 111, 119, 71, 65, + 89, 68, 86, 81, 81, 75, 68, 66, 70, 74, 98, 110, 82, 108, 98, 67, 66, 68, 10, 98, + 51, 74, 119, 98, 51, 74, 104, 100, 71, 108, 118, 98, 106, 69, 85, 77, 66, 73, 71, + 65, 49, 85, 69, 66, 119, 119, 76, 85, 50, 70, 117, 100, 71, 69, 103, 81, 50, 120, + 104, 99, 109, 69, 120, 67, 122, 65, 74, 66, 103, 78, 86, 66, 65, 103, 77, 65, 107, + 78, 66, 77, 81, 115, 119, 10, 67, 81, 89, 68, 86, 81, 81, 71, 69, 119, 74, 86, 85, + 122, 65, 101, 70, 119, 48, 120, 79, 68, 65, 49, 77, 106, 69, 120, 77, 68, 85, 119, + 77, 84, 66, 97, 70, 119, 48, 122, 77, 122, 65, 49, 77, 106, 69, 120, 77, 68, 85, + 119, 77, 84, 66, 97, 77, 72, 65, 120, 73, 106, 65, 103, 10, 66, 103, 78, 86, 66, + 65, 77, 77, 71, 85, 108, 117, 100, 71, 86, 115, 73, 70, 78, 72, 87, 67, 66, 81, 81, + 48, 115, 103, 85, 71, 120, 104, 100, 71, 90, 118, 99, 109, 48, 103, 81, 48, 69, + 120, 71, 106, 65, 89, 66, 103, 78, 86, 66, 65, 111, 77, 69, 85, 108, 117, 100, 71, + 86, 115, 10, 73, 69, 78, 118, 99, 110, 66, 118, 99, 109, 70, 48, 97, 87, 57, 117, + 77, 82, 81, 119, 69, 103, 89, 68, 86, 81, 81, 72, 68, 65, 116, 84, 89, 87, 53, 48, + 89, 83, 66, 68, 98, 71, 70, 121, 89, 84, 69, 76, 77, 65, 107, 71, 65, 49, 85, 69, + 67, 65, 119, 67, 81, 48, 69, 120, 10, 67, 122, 65, 74, 66, 103, 78, 86, 66, 65, 89, + 84, 65, 108, 86, 84, 77, 70, 107, 119, 69, 119, 89, 72, 75, 111, 90, 73, 122, 106, + 48, 67, 65, 81, 89, 73, 75, 111, 90, 73, 122, 106, 48, 68, 65, 81, 99, 68, 81, 103, + 65, 69, 78, 83, 66, 47, 55, 116, 50, 49, 108, 88, 83, 79, 10, 50, 67, 117, 122, + 112, 120, 119, 55, 52, 101, 74, 66, 55, 50, 69, 121, 68, 71, 103, 87, 53, 114, 88, + 67, 116, 120, 50, 116, 86, 84, 76, 113, 54, 104, 75, 107, 54, 122, 43, 85, 105, 82, + 90, 67, 110, 113, 82, 55, 112, 115, 79, 118, 103, 113, 70, 101, 83, 120, 108, 109, + 84, 108, 74, 108, 10, 101, 84, 109, 105, 50, 87, 89, 122, 51, 113, 79, 66, 117, + 122, 67, 66, 117, 68, 65, 102, 66, 103, 78, 86, 72, 83, 77, 69, 71, 68, 65, 87, + 103, 66, 81, 105, 90, 81, 122, 87, 87, 112, 48, 48, 105, 102, 79, 68, 116, 74, 86, + 83, 118, 49, 65, 98, 79, 83, 99, 71, 114, 68, 66, 83, 10, 66, 103, 78, 86, 72, 82, + 56, 69, 83, 122, 66, 74, 77, 69, 101, 103, 82, 97, 66, 68, 104, 107, 70, 111, 100, + 72, 82, 119, 99, 122, 111, 118, 76, 50, 78, 108, 99, 110, 82, 112, 90, 109, 108, + 106, 89, 88, 82, 108, 99, 121, 53, 48, 99, 110, 86, 122, 100, 71, 86, 107, 99, 50, + 86, 121, 10, 100, 109, 108, 106, 90, 88, 77, 117, 97, 87, 53, 48, 90, 87, 119, 117, + 89, 50, 57, 116, 76, 48, 108, 117, 100, 71, 86, 115, 85, 48, 100, 89, 85, 109, 57, + 118, 100, 69, 78, 66, 76, 109, 82, 108, 99, 106, 65, 100, 66, 103, 78, 86, 72, 81, + 52, 69, 70, 103, 81, 85, 108, 87, 57, 100, 10, 122, 98, 48, 98, 52, 101, 108, 65, + 83, 99, 110, 85, 57, 68, 80, 79, 65, 86, 99, 76, 51, 108, 81, 119, 68, 103, 89, 68, + 86, 82, 48, 80, 65, 81, 72, 47, 66, 65, 81, 68, 65, 103, 69, 71, 77, 66, 73, 71, + 65, 49, 85, 100, 69, 119, 69, 66, 47, 119, 81, 73, 77, 65, 89, 66, 10, 65, 102, 56, + 67, 65, 81, 65, 119, 67, 103, 89, 73, 75, 111, 90, 73, 122, 106, 48, 69, 65, 119, + 73, 68, 82, 119, 65, 119, 82, 65, 73, 103, 88, 115, 86, 107, 105, 48, 119, 43, 105, + 54, 86, 89, 71, 87, 51, 85, 70, 47, 50, 50, 117, 97, 88, 101, 48, 89, 74, 68, 106, + 49, 85, 101, 10, 110, 65, 43, 84, 106, 68, 49, 97, 105, 53, 99, 67, 73, 67, 89, 98, + 49, 83, 65, 109, 68, 53, 120, 107, 102, 84, 86, 112, 118, 111, 52, 85, 111, 121, + 105, 83, 89, 120, 114, 68, 87, 76, 109, 85, 82, 52, 67, 73, 57, 78, 75, 121, 102, + 80, 78, 43, 10, 45, 45, 45, 45, 45, 69, 78, 68, 32, 67, 69, 82, 84, 73, 70, 73, 67, + 65, 84, 69, 45, 45, 45, 45, 45, 10, 45, 45, 45, 45, 45, 66, 69, 71, 73, 78, 32, 67, + 69, 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, 10, 77, 73, 73, 67, + 106, 122, 67, 67, 65, 106, 83, 103, 65, 119, 73, 66, 65, 103, 73, 85, 73, 109, 85, + 77, 49, 108, 113, 100, 78, 73, 110, 122, 103, 55, 83, 86, 85, 114, 57, 81, 71, 122, + 107, 110, 66, 113, 119, 119, 67, 103, 89, 73, 75, 111, 90, 73, 122, 106, 48, 69, + 65, 119, 73, 119, 10, 97, 68, 69, 97, 77, 66, 103, 71, 65, 49, 85, 69, 65, 119, + 119, 82, 83, 87, 53, 48, 90, 87, 119, 103, 85, 48, 100, 89, 73, 70, 74, 118, 98, + 51, 81, 103, 81, 48, 69, 120, 71, 106, 65, 89, 66, 103, 78, 86, 66, 65, 111, 77, + 69, 85, 108, 117, 100, 71, 86, 115, 73, 69, 78, 118, 10, 99, 110, 66, 118, 99, 109, + 70, 48, 97, 87, 57, 117, 77, 82, 81, 119, 69, 103, 89, 68, 86, 81, 81, 72, 68, 65, + 116, 84, 89, 87, 53, 48, 89, 83, 66, 68, 98, 71, 70, 121, 89, 84, 69, 76, 77, 65, + 107, 71, 65, 49, 85, 69, 67, 65, 119, 67, 81, 48, 69, 120, 67, 122, 65, 74, 10, 66, + 103, 78, 86, 66, 65, 89, 84, 65, 108, 86, 84, 77, 66, 52, 88, 68, 84, 69, 52, 77, + 68, 85, 121, 77, 84, 69, 119, 78, 68, 85, 120, 77, 70, 111, 88, 68, 84, 81, 53, 77, + 84, 73, 122, 77, 84, 73, 122, 78, 84, 107, 49, 79, 86, 111, 119, 97, 68, 69, 97, + 77, 66, 103, 71, 10, 65, 49, 85, 69, 65, 119, 119, 82, 83, 87, 53, 48, 90, 87, 119, + 103, 85, 48, 100, 89, 73, 70, 74, 118, 98, 51, 81, 103, 81, 48, 69, 120, 71, 106, + 65, 89, 66, 103, 78, 86, 66, 65, 111, 77, 69, 85, 108, 117, 100, 71, 86, 115, 73, + 69, 78, 118, 99, 110, 66, 118, 99, 109, 70, 48, 10, 97, 87, 57, 117, 77, 82, 81, + 119, 69, 103, 89, 68, 86, 81, 81, 72, 68, 65, 116, 84, 89, 87, 53, 48, 89, 83, 66, + 68, 98, 71, 70, 121, 89, 84, 69, 76, 77, 65, 107, 71, 65, 49, 85, 69, 67, 65, 119, + 67, 81, 48, 69, 120, 67, 122, 65, 74, 66, 103, 78, 86, 66, 65, 89, 84, 10, 65, 108, + 86, 84, 77, 70, 107, 119, 69, 119, 89, 72, 75, 111, 90, 73, 122, 106, 48, 67, 65, + 81, 89, 73, 75, 111, 90, 73, 122, 106, 48, 68, 65, 81, 99, 68, 81, 103, 65, 69, 67, + 54, 110, 69, 119, 77, 68, 73, 89, 90, 79, 106, 47, 105, 80, 87, 115, 67, 122, 97, + 69, 75, 105, 55, 10, 49, 79, 105, 79, 83, 76, 82, 70, 104, 87, 71, 106, 98, 110, + 66, 86, 74, 102, 86, 110, 107, 89, 52, 117, 51, 73, 106, 107, 68, 89, 89, 76, 48, + 77, 120, 79, 52, 109, 113, 115, 121, 89, 106, 108, 66, 97, 108, 84, 86, 89, 120, + 70, 80, 50, 115, 74, 66, 75, 53, 122, 108, 75, 79, 66, 10, 117, 122, 67, 66, 117, + 68, 65, 102, 66, 103, 78, 86, 72, 83, 77, 69, 71, 68, 65, 87, 103, 66, 81, 105, 90, + 81, 122, 87, 87, 112, 48, 48, 105, 102, 79, 68, 116, 74, 86, 83, 118, 49, 65, 98, + 79, 83, 99, 71, 114, 68, 66, 83, 66, 103, 78, 86, 72, 82, 56, 69, 83, 122, 66, 74, + 10, 77, 69, 101, 103, 82, 97, 66, 68, 104, 107, 70, 111, 100, 72, 82, 119, 99, 122, + 111, 118, 76, 50, 78, 108, 99, 110, 82, 112, 90, 109, 108, 106, 89, 88, 82, 108, + 99, 121, 53, 48, 99, 110, 86, 122, 100, 71, 86, 107, 99, 50, 86, 121, 100, 109, + 108, 106, 90, 88, 77, 117, 97, 87, 53, 48, 10, 90, 87, 119, 117, 89, 50, 57, 116, + 76, 48, 108, 117, 100, 71, 86, 115, 85, 48, 100, 89, 85, 109, 57, 118, 100, 69, 78, + 66, 76, 109, 82, 108, 99, 106, 65, 100, 66, 103, 78, 86, 72, 81, 52, 69, 70, 103, + 81, 85, 73, 109, 85, 77, 49, 108, 113, 100, 78, 73, 110, 122, 103, 55, 83, 86, 10, + 85, 114, 57, 81, 71, 122, 107, 110, 66, 113, 119, 119, 68, 103, 89, 68, 86, 82, 48, + 80, 65, 81, 72, 47, 66, 65, 81, 68, 65, 103, 69, 71, 77, 66, 73, 71, 65, 49, 85, + 100, 69, 119, 69, 66, 47, 119, 81, 73, 77, 65, 89, 66, 65, 102, 56, 67, 65, 81, 69, + 119, 67, 103, 89, 73, 10, 75, 111, 90, 73, 122, 106, 48, 69, 65, 119, 73, 68, 83, + 81, 65, 119, 82, 103, 73, 104, 65, 79, 87, 47, 53, 81, 107, 82, 43, 83, 57, 67, + 105, 83, 68, 99, 78, 111, 111, 119, 76, 117, 80, 82, 76, 115, 87, 71, 102, 47, 89, + 105, 55, 71, 83, 88, 57, 52, 66, 103, 119, 84, 119, 103, 10, 65, 105, 69, 65, 52, + 74, 48, 108, 114, 72, 111, 77, 115, 43, 88, 111, 53, 111, 47, 115, 88, 54, 79, 57, + 81, 87, 120, 72, 82, 65, 118, 90, 85, 71, 79, 100, 82, 81, 55, 99, 118, 113, 82, + 88, 97, 113, 73, 61, 10, 45, 45, 45, 45, 45, 69, 78, 68, 32, 67, 69, 82, 84, 73, + 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, 10, 0, + ] + .into(), + root_ca_crl: [ + 48, 130, 1, 33, 48, 129, 200, 2, 1, 1, 48, 10, 6, 8, 42, 134, 72, 206, 61, 4, 3, 2, + 48, 104, 49, 26, 48, 24, 6, 3, 85, 4, 3, 12, 17, 73, 110, 116, 101, 108, 32, 83, + 71, 88, 32, 82, 111, 111, 116, 32, 67, 65, 49, 26, 48, 24, 6, 3, 85, 4, 10, 12, 17, + 73, 110, 116, 101, 108, 32, 67, 111, 114, 112, 111, 114, 97, 116, 105, 111, 110, + 49, 20, 48, 18, 6, 3, 85, 4, 7, 12, 11, 83, 97, 110, 116, 97, 32, 67, 108, 97, 114, + 97, 49, 11, 48, 9, 6, 3, 85, 4, 8, 12, 2, 67, 65, 49, 11, 48, 9, 6, 3, 85, 4, 6, + 19, 2, 85, 83, 23, 13, 50, 51, 48, 52, 48, 51, 49, 48, 50, 50, 53, 49, 90, 23, 13, + 50, 52, 48, 52, 48, 50, 49, 48, 50, 50, 53, 49, 90, 160, 47, 48, 45, 48, 10, 6, 3, + 85, 29, 20, 4, 3, 2, 1, 1, 48, 31, 6, 3, 85, 29, 35, 4, 24, 48, 22, 128, 20, 34, + 101, 12, 214, 90, 157, 52, 137, 243, 131, 180, 149, 82, 191, 80, 27, 57, 39, 6, + 172, 48, 10, 6, 8, 42, 134, 72, 206, 61, 4, 3, 2, 3, 72, 0, 48, 69, 2, 32, 81, 87, + 125, 71, 217, 251, 161, 87, 182, 95, 30, 181, 244, 101, 123, 188, 94, 86, 204, 175, + 115, 90, 3, 241, 185, 99, 215, 4, 128, 90, 177, 24, 2, 33, 0, 147, 144, 21, 236, + 22, 54, 231, 234, 250, 95, 66, 108, 30, 64, 38, 71, 198, 115, 19, 43, 104, 80, 202, + 189, 104, 206, 246, 186, 215, 104, 42, 3, 0, + ] + .into(), + pck_crl: [ + 48, 130, 10, 97, 48, 130, 10, 8, 2, 1, 1, 48, 10, 6, 8, 42, 134, 72, 206, 61, 4, 3, + 2, 48, 112, 49, 34, 48, 32, 6, 3, 85, 4, 3, 12, 25, 73, 110, 116, 101, 108, 32, 83, + 71, 88, 32, 80, 67, 75, 32, 80, 108, 97, 116, 102, 111, 114, 109, 32, 67, 65, 49, + 26, 48, 24, 6, 3, 85, 4, 10, 12, 17, 73, 110, 116, 101, 108, 32, 67, 111, 114, 112, + 111, 114, 97, 116, 105, 111, 110, 49, 20, 48, 18, 6, 3, 85, 4, 7, 12, 11, 83, 97, + 110, 116, 97, 32, 67, 108, 97, 114, 97, 49, 11, 48, 9, 6, 3, 85, 4, 8, 12, 2, 67, + 65, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 85, 83, 23, 13, 50, 51, 48, 53, 48, 57, + 49, 51, 52, 57, 53, 53, 90, 23, 13, 50, 51, 48, 54, 48, 56, 49, 51, 52, 57, 53, 53, + 90, 48, 130, 9, 52, 48, 51, 2, 20, 111, 195, 78, 80, 35, 231, 40, 146, 52, 53, 214, + 26, 164, 184, 60, 97, 129, 102, 173, 53, 23, 13, 50, 51, 48, 53, 48, 57, 49, 51, + 52, 57, 53, 53, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 52, 2, + 21, 0, 239, 174, 110, 151, 21, 252, 161, 59, 135, 227, 51, 232, 38, 30, 214, 217, + 144, 169, 38, 173, 23, 13, 50, 51, 48, 53, 48, 57, 49, 51, 52, 57, 53, 53, 90, 48, + 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 52, 2, 21, 0, 253, 96, 134, 72, + 98, 156, 186, 115, 7, 139, 77, 73, 47, 75, 62, 167, 65, 173, 8, 205, 23, 13, 50, + 51, 48, 53, 48, 57, 49, 51, 52, 57, 53, 53, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, + 4, 3, 10, 1, 1, 48, 52, 2, 21, 0, 138, 249, 36, 24, 78, 29, 90, 253, 221, 115, 195, + 214, 58, 18, 245, 232, 181, 115, 126, 86, 23, 13, 50, 51, 48, 53, 48, 57, 49, 51, + 52, 57, 53, 53, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 52, 2, + 21, 0, 177, 37, 121, 120, 207, 169, 204, 221, 7, 89, 171, 248, 197, 202, 114, 250, + 227, 167, 138, 155, 23, 13, 50, 51, 48, 53, 48, 57, 49, 51, 52, 57, 53, 53, 90, 48, + 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 51, 2, 20, 116, 254, 166, 20, + 169, 114, 190, 14, 40, 67, 242, 5, 152, 53, 129, 30, 216, 114, 249, 179, 23, 13, + 50, 51, 48, 53, 48, 57, 49, 51, 52, 57, 53, 53, 90, 48, 12, 48, 10, 6, 3, 85, 29, + 21, 4, 3, 10, 1, 1, 48, 52, 2, 21, 0, 249, 196, 239, 86, 179, 171, 72, 213, 119, + 225, 8, 186, 237, 244, 191, 136, 1, 66, 20, 185, 23, 13, 50, 51, 48, 53, 48, 57, + 49, 51, 52, 57, 53, 53, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, + 51, 2, 20, 7, 29, 224, 119, 143, 158, 95, 196, 242, 135, 143, 48, 214, 176, 124, + 154, 48, 230, 179, 11, 23, 13, 50, 51, 48, 53, 48, 57, 49, 51, 52, 57, 53, 53, 90, + 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 52, 2, 21, 0, 205, 226, 66, + 79, 151, 44, 234, 148, 255, 35, 153, 55, 244, 216, 12, 37, 2, 157, 214, 11, 23, 13, + 50, 51, 48, 53, 48, 57, 49, 51, 52, 57, 53, 53, 90, 48, 12, 48, 10, 6, 3, 85, 29, + 21, 4, 3, 10, 1, 1, 48, 51, 2, 20, 108, 51, 25, 229, 16, 155, 100, 80, 125, 60, + 241, 19, 44, 224, 3, 73, 239, 82, 115, 25, 23, 13, 50, 51, 48, 53, 48, 57, 49, 51, + 52, 57, 53, 53, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 52, 2, + 21, 0, 223, 8, 215, 86, 182, 106, 116, 151, 244, 59, 91, 181, 138, 218, 4, 211, + 244, 247, 169, 55, 23, 13, 50, 51, 48, 53, 48, 57, 49, 51, 52, 57, 53, 53, 90, 48, + 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 51, 2, 20, 40, 175, 72, 91, 108, + 246, 126, 64, 154, 57, 213, 203, 90, 238, 69, 152, 247, 168, 250, 123, 23, 13, 50, + 51, 48, 53, 48, 57, 49, 51, 52, 57, 53, 53, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, + 4, 3, 10, 1, 1, 48, 52, 2, 21, 0, 251, 139, 45, 174, 192, 146, 202, 218, 138, 169, + 188, 79, 242, 241, 194, 13, 3, 70, 102, 140, 23, 13, 50, 51, 48, 53, 48, 57, 49, + 51, 52, 57, 53, 53, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 52, + 2, 21, 0, 205, 72, 80, 172, 82, 189, 204, 105, 166, 166, 240, 88, 200, 188, 87, + 187, 208, 181, 248, 100, 23, 13, 50, 51, 48, 53, 48, 57, 49, 51, 52, 57, 53, 53, + 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 52, 2, 21, 0, 153, 77, + 211, 102, 111, 82, 117, 251, 128, 95, 149, 221, 2, 189, 80, 203, 38, 121, 216, 173, + 23, 13, 50, 51, 48, 53, 48, 57, 49, 51, 52, 57, 53, 53, 90, 48, 12, 48, 10, 6, 3, + 85, 29, 21, 4, 3, 10, 1, 1, 48, 51, 2, 20, 7, 2, 19, 105, 0, 37, 34, 116, 217, 3, + 94, 237, 245, 69, 116, 98, 250, 208, 239, 76, 23, 13, 50, 51, 48, 53, 48, 57, 49, + 51, 52, 57, 53, 53, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 51, + 2, 20, 97, 242, 191, 115, 227, 155, 78, 4, 170, 39, 216, 1, 189, 115, 210, 67, 25, + 181, 191, 128, 23, 13, 50, 51, 48, 53, 48, 57, 49, 51, 52, 57, 53, 53, 90, 48, 12, + 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 51, 2, 20, 57, 146, 190, 133, 27, + 150, 144, 46, 255, 56, 149, 158, 108, 46, 255, 27, 6, 81, 164, 181, 23, 13, 50, 51, + 48, 53, 48, 57, 49, 51, 52, 57, 53, 53, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, + 10, 1, 1, 48, 51, 2, 20, 99, 159, 19, 154, 80, 64, 253, 207, 241, 145, 232, 164, + 251, 27, 240, 134, 237, 96, 57, 113, 23, 13, 50, 51, 48, 53, 48, 57, 49, 51, 52, + 57, 53, 53, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 52, 2, 21, 0, + 149, 157, 83, 63, 146, 73, 220, 30, 81, 53, 68, 205, 200, 48, 191, 25, 183, 241, + 243, 1, 23, 13, 50, 51, 48, 53, 48, 57, 49, 51, 52, 57, 53, 53, 90, 48, 12, 48, 10, + 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 51, 2, 20, 15, 218, 67, 160, 11, 104, 234, + 121, 183, 194, 222, 174, 172, 11, 73, 139, 223, 178, 175, 144, 23, 13, 50, 51, 48, + 53, 48, 57, 49, 51, 52, 57, 53, 53, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, + 1, 1, 48, 52, 2, 21, 0, 157, 103, 117, 59, 129, 228, 112, 144, 174, 167, 99, 251, + 236, 76, 69, 73, 188, 219, 153, 51, 23, 13, 50, 51, 48, 53, 48, 57, 49, 51, 52, 57, + 53, 53, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 51, 2, 20, 52, + 191, 187, 122, 29, 156, 86, 129, 71, 225, 24, 182, 20, 247, 183, 110, 211, 239, + 104, 223, 23, 13, 50, 51, 48, 53, 48, 57, 49, 51, 52, 57, 53, 53, 90, 48, 12, 48, + 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 52, 2, 21, 0, 133, 211, 201, 56, 27, 119, + 167, 224, 77, 17, 156, 158, 90, 214, 116, 159, 243, 255, 171, 135, 23, 13, 50, 51, + 48, 53, 48, 57, 49, 51, 52, 57, 53, 53, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, + 10, 1, 1, 48, 52, 2, 21, 0, 147, 136, 124, 164, 65, 30, 122, 146, 59, 209, 254, + 210, 129, 155, 41, 73, 242, 1, 181, 180, 23, 13, 50, 51, 48, 53, 48, 57, 49, 51, + 52, 57, 53, 53, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 51, 2, + 20, 36, 152, 220, 98, 131, 147, 9, 150, 253, 139, 242, 58, 55, 172, 190, 38, 163, + 190, 212, 87, 23, 13, 50, 51, 48, 53, 48, 57, 49, 51, 52, 57, 53, 53, 90, 48, 12, + 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 52, 2, 21, 0, 138, 102, 241, 167, 73, + 72, 134, 103, 104, 156, 195, 144, 58, 197, 76, 102, 43, 113, 46, 115, 23, 13, 50, + 51, 48, 53, 48, 57, 49, 51, 52, 57, 53, 53, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, + 4, 3, 10, 1, 1, 48, 52, 2, 21, 0, 175, 193, 54, 16, 189, 211, 108, 183, 152, 93, + 16, 100, 129, 168, 128, 211, 160, 31, 218, 7, 23, 13, 50, 51, 48, 53, 48, 57, 49, + 51, 52, 57, 53, 53, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 52, + 2, 21, 0, 239, 224, 75, 44, 51, 208, 54, 170, 201, 108, 166, 115, 191, 30, 154, 71, + 182, 77, 92, 187, 23, 13, 50, 51, 48, 53, 48, 57, 49, 51, 52, 57, 53, 53, 90, 48, + 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 52, 2, 21, 0, 131, 217, 172, 141, + 139, 181, 9, 209, 198, 200, 9, 173, 113, 46, 132, 48, 85, 158, 215, 243, 23, 13, + 50, 51, 48, 53, 48, 57, 49, 51, 52, 57, 53, 53, 90, 48, 12, 48, 10, 6, 3, 85, 29, + 21, 4, 3, 10, 1, 1, 48, 51, 2, 20, 121, 49, 253, 80, 181, 7, 28, 27, 191, 197, 183, + 182, 222, 216, 180, 91, 157, 139, 133, 41, 23, 13, 50, 51, 48, 53, 48, 57, 49, 51, + 52, 57, 53, 53, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 51, 2, + 20, 31, 162, 14, 41, 112, 189, 229, 213, 127, 123, 141, 223, 131, 57, 72, 78, 31, + 29, 8, 35, 23, 13, 50, 51, 48, 53, 48, 57, 49, 51, 52, 57, 53, 53, 90, 48, 12, 48, + 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 51, 2, 20, 30, 135, 178, 195, 179, 45, + 141, 35, 228, 17, 206, 243, 65, 151, 185, 90, 240, 200, 173, 245, 23, 13, 50, 51, + 48, 53, 48, 57, 49, 51, 52, 57, 53, 53, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, + 10, 1, 1, 48, 52, 2, 21, 0, 154, 253, 46, 233, 10, 71, 53, 80, 161, 103, 217, 150, + 145, 20, 55, 199, 80, 45, 31, 9, 23, 13, 50, 51, 48, 53, 48, 57, 49, 51, 52, 57, + 53, 53, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 51, 2, 20, 68, + 129, 176, 241, 23, 40, 161, 59, 105, 109, 62, 169, 199, 112, 160, 177, 94, 197, + 141, 218, 23, 13, 50, 51, 48, 53, 48, 57, 49, 51, 52, 57, 53, 53, 90, 48, 12, 48, + 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 52, 2, 21, 0, 167, 133, 159, 87, 152, 46, + 240, 230, 125, 55, 188, 142, 242, 239, 90, 200, 53, 255, 26, 169, 23, 13, 50, 51, + 48, 53, 48, 57, 49, 51, 52, 57, 53, 53, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, + 10, 1, 1, 48, 51, 2, 20, 122, 227, 119, 72, 169, 249, 18, 244, 198, 59, 167, 171, + 7, 197, 147, 206, 29, 29, 17, 129, 23, 13, 50, 51, 48, 53, 48, 57, 49, 51, 52, 57, + 53, 53, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 51, 2, 20, 19, + 136, 75, 51, 38, 153, 56, 193, 149, 170, 23, 15, 202, 117, 218, 23, 117, 56, 223, + 11, 23, 13, 50, 51, 48, 53, 48, 57, 49, 51, 52, 57, 53, 53, 90, 48, 12, 48, 10, 6, + 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 51, 2, 20, 44, 60, 198, 254, 146, 121, 219, 21, + 22, 213, 206, 57, 242, 168, 152, 205, 165, 161, 117, 225, 23, 13, 50, 51, 48, 53, + 48, 57, 49, 51, 52, 57, 53, 53, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, + 1, 48, 51, 2, 20, 113, 121, 72, 104, 117, 9, 35, 75, 233, 121, 228, 183, 220, 230, + 243, 27, 239, 100, 182, 140, 23, 13, 50, 51, 48, 53, 48, 57, 49, 51, 52, 57, 53, + 53, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 52, 2, 21, 0, 157, + 118, 239, 44, 57, 193, 54, 232, 101, 139, 110, 115, 150, 177, 215, 68, 90, 39, 99, + 31, 23, 13, 50, 51, 48, 53, 48, 57, 49, 51, 52, 57, 53, 53, 90, 48, 12, 48, 10, 6, + 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 52, 2, 21, 0, 195, 224, 37, 252, 169, 149, 243, + 111, 89, 180, 132, 103, 147, 158, 62, 52, 230, 54, 26, 111, 23, 13, 50, 51, 48, 53, + 48, 57, 49, 51, 52, 57, 53, 53, 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, + 1, 48, 52, 2, 21, 0, 140, 95, 107, 50, 87, 218, 5, 177, 116, 41, 226, 230, 27, 169, + 101, 214, 115, 48, 96, 106, 23, 13, 50, 51, 48, 53, 48, 57, 49, 51, 52, 57, 53, 53, + 90, 48, 12, 48, 10, 6, 3, 85, 29, 21, 4, 3, 10, 1, 1, 48, 52, 2, 21, 0, 161, 124, + 81, 114, 46, 193, 224, 195, 39, 143, 232, 189, 240, 82, 5, 156, 190, 196, 230, 72, + 23, 13, 50, 51, 48, 53, 48, 57, 49, 51, 52, 57, 53, 53, 90, 48, 12, 48, 10, 6, 3, + 85, 29, 21, 4, 3, 10, 1, 1, 160, 47, 48, 45, 48, 10, 6, 3, 85, 29, 20, 4, 3, 2, 1, + 1, 48, 31, 6, 3, 85, 29, 35, 4, 24, 48, 22, 128, 20, 149, 111, 93, 205, 189, 27, + 225, 233, 64, 73, 201, 212, 244, 51, 206, 1, 87, 11, 222, 84, 48, 10, 6, 8, 42, + 134, 72, 206, 61, 4, 3, 2, 3, 71, 0, 48, 68, 2, 32, 76, 254, 31, 25, 241, 225, 67, + 36, 9, 135, 23, 86, 174, 140, 83, 12, 200, 38, 212, 185, 162, 94, 123, 4, 87, 24, + 205, 179, 22, 6, 27, 29, 2, 32, 39, 131, 160, 174, 166, 27, 207, 3, 33, 18, 215, + 239, 11, 221, 30, 101, 82, 231, 224, 39, 167, 218, 149, 171, 98, 252, 45, 145, 104, + 133, 133, 45, 0, + ] + .into(), + tcb_info_issuer_chain: [ + 45, 45, 45, 45, 45, 66, 69, 71, 73, 78, 32, 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, + 69, 45, 45, 45, 45, 45, 10, 77, 73, 73, 67, 105, 122, 67, 67, 65, 106, 75, 103, 65, + 119, 73, 66, 65, 103, 73, 85, 102, 106, 105, 67, 49, 102, 116, 86, 75, 85, 112, 65, + 83, 89, 53, 70, 104, 65, 80, 112, 70, 74, 71, 57, 57, 70, 85, 119, 67, 103, 89, 73, + 75, 111, 90, 73, 122, 106, 48, 69, 65, 119, 73, 119, 10, 97, 68, 69, 97, 77, 66, + 103, 71, 65, 49, 85, 69, 65, 119, 119, 82, 83, 87, 53, 48, 90, 87, 119, 103, 85, + 48, 100, 89, 73, 70, 74, 118, 98, 51, 81, 103, 81, 48, 69, 120, 71, 106, 65, 89, + 66, 103, 78, 86, 66, 65, 111, 77, 69, 85, 108, 117, 100, 71, 86, 115, 73, 69, 78, + 118, 10, 99, 110, 66, 118, 99, 109, 70, 48, 97, 87, 57, 117, 77, 82, 81, 119, 69, + 103, 89, 68, 86, 81, 81, 72, 68, 65, 116, 84, 89, 87, 53, 48, 89, 83, 66, 68, 98, + 71, 70, 121, 89, 84, 69, 76, 77, 65, 107, 71, 65, 49, 85, 69, 67, 65, 119, 67, 81, + 48, 69, 120, 67, 122, 65, 74, 10, 66, 103, 78, 86, 66, 65, 89, 84, 65, 108, 86, 84, + 77, 66, 52, 88, 68, 84, 69, 52, 77, 68, 85, 121, 77, 84, 69, 119, 78, 84, 65, 120, + 77, 70, 111, 88, 68, 84, 73, 49, 77, 68, 85, 121, 77, 84, 69, 119, 78, 84, 65, 120, + 77, 70, 111, 119, 98, 68, 69, 101, 77, 66, 119, 71, 10, 65, 49, 85, 69, 65, 119, + 119, 86, 83, 87, 53, 48, 90, 87, 119, 103, 85, 48, 100, 89, 73, 70, 82, 68, 81, + 105, 66, 84, 97, 87, 100, 117, 97, 87, 53, 110, 77, 82, 111, 119, 71, 65, 89, 68, + 86, 81, 81, 75, 68, 66, 70, 74, 98, 110, 82, 108, 98, 67, 66, 68, 98, 51, 74, 119, + 10, 98, 51, 74, 104, 100, 71, 108, 118, 98, 106, 69, 85, 77, 66, 73, 71, 65, 49, + 85, 69, 66, 119, 119, 76, 85, 50, 70, 117, 100, 71, 69, 103, 81, 50, 120, 104, 99, + 109, 69, 120, 67, 122, 65, 74, 66, 103, 78, 86, 66, 65, 103, 77, 65, 107, 78, 66, + 77, 81, 115, 119, 67, 81, 89, 68, 10, 86, 81, 81, 71, 69, 119, 74, 86, 85, 122, 66, + 90, 77, 66, 77, 71, 66, 121, 113, 71, 83, 77, 52, 57, 65, 103, 69, 71, 67, 67, 113, + 71, 83, 77, 52, 57, 65, 119, 69, 72, 65, 48, 73, 65, 66, 69, 78, 70, 71, 56, 120, + 122, 121, 100, 87, 82, 102, 75, 57, 50, 98, 109, 71, 118, 10, 80, 43, 109, 65, 104, + 57, 49, 80, 69, 121, 86, 55, 74, 104, 54, 70, 71, 74, 100, 53, 110, 100, 69, 57, + 97, 66, 72, 55, 82, 51, 69, 52, 65, 55, 117, 98, 114, 108, 104, 47, 122, 78, 51, + 67, 52, 120, 118, 112, 111, 111, 117, 71, 108, 105, 114, 77, 98, 97, 43, 87, 50, + 108, 106, 117, 10, 121, 112, 97, 106, 103, 98, 85, 119, 103, 98, 73, 119, 72, 119, + 89, 68, 86, 82, 48, 106, 66, 66, 103, 119, 70, 111, 65, 85, 73, 109, 85, 77, 49, + 108, 113, 100, 78, 73, 110, 122, 103, 55, 83, 86, 85, 114, 57, 81, 71, 122, 107, + 110, 66, 113, 119, 119, 85, 103, 89, 68, 86, 82, 48, 102, 10, 66, 69, 115, 119, 83, + 84, 66, 72, 111, 69, 87, 103, 81, 52, 90, 66, 97, 72, 82, 48, 99, 72, 77, 54, 76, + 121, 57, 106, 90, 88, 74, 48, 97, 87, 90, 112, 89, 50, 70, 48, 90, 88, 77, 117, + 100, 72, 74, 49, 99, 51, 82, 108, 90, 72, 78, 108, 99, 110, 90, 112, 89, 50, 86, + 122, 10, 76, 109, 108, 117, 100, 71, 86, 115, 76, 109, 78, 118, 98, 83, 57, 74, 98, + 110, 82, 108, 98, 70, 78, 72, 87, 70, 74, 118, 98, 51, 82, 68, 81, 83, 53, 107, 90, + 88, 73, 119, 72, 81, 89, 68, 86, 82, 48, 79, 66, 66, 89, 69, 70, 72, 52, 52, 103, + 116, 88, 55, 86, 83, 108, 75, 10, 81, 69, 109, 79, 82, 89, 81, 68, 54, 82, 83, 82, + 118, 102, 82, 86, 77, 65, 52, 71, 65, 49, 85, 100, 68, 119, 69, 66, 47, 119, 81, + 69, 65, 119, 73, 71, 119, 68, 65, 77, 66, 103, 78, 86, 72, 82, 77, 66, 65, 102, 56, + 69, 65, 106, 65, 65, 77, 65, 111, 71, 67, 67, 113, 71, 10, 83, 77, 52, 57, 66, 65, + 77, 67, 65, 48, 99, 65, 77, 69, 81, 67, 73, 66, 57, 67, 56, 119, 79, 65, 78, 47, + 73, 109, 120, 68, 116, 71, 65, 67, 86, 50, 52, 54, 75, 99, 113, 106, 97, 103, 90, + 79, 82, 48, 107, 121, 99, 116, 121, 66, 114, 115, 71, 71, 74, 86, 65, 105, 65, 106, + 10, 102, 116, 98, 114, 78, 71, 115, 71, 85, 56, 89, 72, 50, 49, 49, 100, 82, 105, + 89, 78, 111, 80, 80, 117, 49, 57, 90, 112, 47, 122, 101, 56, 74, 109, 104, 117, + 106, 66, 48, 111, 66, 119, 61, 61, 10, 45, 45, 45, 45, 45, 69, 78, 68, 32, 67, 69, + 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, 10, 45, 45, 45, 45, 45, 66, + 69, 71, 73, 78, 32, 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, + 10, 77, 73, 73, 67, 106, 122, 67, 67, 65, 106, 83, 103, 65, 119, 73, 66, 65, 103, + 73, 85, 73, 109, 85, 77, 49, 108, 113, 100, 78, 73, 110, 122, 103, 55, 83, 86, 85, + 114, 57, 81, 71, 122, 107, 110, 66, 113, 119, 119, 67, 103, 89, 73, 75, 111, 90, + 73, 122, 106, 48, 69, 65, 119, 73, 119, 10, 97, 68, 69, 97, 77, 66, 103, 71, 65, + 49, 85, 69, 65, 119, 119, 82, 83, 87, 53, 48, 90, 87, 119, 103, 85, 48, 100, 89, + 73, 70, 74, 118, 98, 51, 81, 103, 81, 48, 69, 120, 71, 106, 65, 89, 66, 103, 78, + 86, 66, 65, 111, 77, 69, 85, 108, 117, 100, 71, 86, 115, 73, 69, 78, 118, 10, 99, + 110, 66, 118, 99, 109, 70, 48, 97, 87, 57, 117, 77, 82, 81, 119, 69, 103, 89, 68, + 86, 81, 81, 72, 68, 65, 116, 84, 89, 87, 53, 48, 89, 83, 66, 68, 98, 71, 70, 121, + 89, 84, 69, 76, 77, 65, 107, 71, 65, 49, 85, 69, 67, 65, 119, 67, 81, 48, 69, 120, + 67, 122, 65, 74, 10, 66, 103, 78, 86, 66, 65, 89, 84, 65, 108, 86, 84, 77, 66, 52, + 88, 68, 84, 69, 52, 77, 68, 85, 121, 77, 84, 69, 119, 78, 68, 85, 120, 77, 70, 111, + 88, 68, 84, 81, 53, 77, 84, 73, 122, 77, 84, 73, 122, 78, 84, 107, 49, 79, 86, 111, + 119, 97, 68, 69, 97, 77, 66, 103, 71, 10, 65, 49, 85, 69, 65, 119, 119, 82, 83, 87, + 53, 48, 90, 87, 119, 103, 85, 48, 100, 89, 73, 70, 74, 118, 98, 51, 81, 103, 81, + 48, 69, 120, 71, 106, 65, 89, 66, 103, 78, 86, 66, 65, 111, 77, 69, 85, 108, 117, + 100, 71, 86, 115, 73, 69, 78, 118, 99, 110, 66, 118, 99, 109, 70, 48, 10, 97, 87, + 57, 117, 77, 82, 81, 119, 69, 103, 89, 68, 86, 81, 81, 72, 68, 65, 116, 84, 89, 87, + 53, 48, 89, 83, 66, 68, 98, 71, 70, 121, 89, 84, 69, 76, 77, 65, 107, 71, 65, 49, + 85, 69, 67, 65, 119, 67, 81, 48, 69, 120, 67, 122, 65, 74, 66, 103, 78, 86, 66, 65, + 89, 84, 10, 65, 108, 86, 84, 77, 70, 107, 119, 69, 119, 89, 72, 75, 111, 90, 73, + 122, 106, 48, 67, 65, 81, 89, 73, 75, 111, 90, 73, 122, 106, 48, 68, 65, 81, 99, + 68, 81, 103, 65, 69, 67, 54, 110, 69, 119, 77, 68, 73, 89, 90, 79, 106, 47, 105, + 80, 87, 115, 67, 122, 97, 69, 75, 105, 55, 10, 49, 79, 105, 79, 83, 76, 82, 70, + 104, 87, 71, 106, 98, 110, 66, 86, 74, 102, 86, 110, 107, 89, 52, 117, 51, 73, 106, + 107, 68, 89, 89, 76, 48, 77, 120, 79, 52, 109, 113, 115, 121, 89, 106, 108, 66, 97, + 108, 84, 86, 89, 120, 70, 80, 50, 115, 74, 66, 75, 53, 122, 108, 75, 79, 66, 10, + 117, 122, 67, 66, 117, 68, 65, 102, 66, 103, 78, 86, 72, 83, 77, 69, 71, 68, 65, + 87, 103, 66, 81, 105, 90, 81, 122, 87, 87, 112, 48, 48, 105, 102, 79, 68, 116, 74, + 86, 83, 118, 49, 65, 98, 79, 83, 99, 71, 114, 68, 66, 83, 66, 103, 78, 86, 72, 82, + 56, 69, 83, 122, 66, 74, 10, 77, 69, 101, 103, 82, 97, 66, 68, 104, 107, 70, 111, + 100, 72, 82, 119, 99, 122, 111, 118, 76, 50, 78, 108, 99, 110, 82, 112, 90, 109, + 108, 106, 89, 88, 82, 108, 99, 121, 53, 48, 99, 110, 86, 122, 100, 71, 86, 107, 99, + 50, 86, 121, 100, 109, 108, 106, 90, 88, 77, 117, 97, 87, 53, 48, 10, 90, 87, 119, + 117, 89, 50, 57, 116, 76, 48, 108, 117, 100, 71, 86, 115, 85, 48, 100, 89, 85, 109, + 57, 118, 100, 69, 78, 66, 76, 109, 82, 108, 99, 106, 65, 100, 66, 103, 78, 86, 72, + 81, 52, 69, 70, 103, 81, 85, 73, 109, 85, 77, 49, 108, 113, 100, 78, 73, 110, 122, + 103, 55, 83, 86, 10, 85, 114, 57, 81, 71, 122, 107, 110, 66, 113, 119, 119, 68, + 103, 89, 68, 86, 82, 48, 80, 65, 81, 72, 47, 66, 65, 81, 68, 65, 103, 69, 71, 77, + 66, 73, 71, 65, 49, 85, 100, 69, 119, 69, 66, 47, 119, 81, 73, 77, 65, 89, 66, 65, + 102, 56, 67, 65, 81, 69, 119, 67, 103, 89, 73, 10, 75, 111, 90, 73, 122, 106, 48, + 69, 65, 119, 73, 68, 83, 81, 65, 119, 82, 103, 73, 104, 65, 79, 87, 47, 53, 81, + 107, 82, 43, 83, 57, 67, 105, 83, 68, 99, 78, 111, 111, 119, 76, 117, 80, 82, 76, + 115, 87, 71, 102, 47, 89, 105, 55, 71, 83, 88, 57, 52, 66, 103, 119, 84, 119, 103, + 10, 65, 105, 69, 65, 52, 74, 48, 108, 114, 72, 111, 77, 115, 43, 88, 111, 53, 111, + 47, 115, 88, 54, 79, 57, 81, 87, 120, 72, 82, 65, 118, 90, 85, 71, 79, 100, 82, 81, + 55, 99, 118, 113, 82, 88, 97, 113, 73, 61, 10, 45, 45, 45, 45, 45, 69, 78, 68, 32, + 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, 10, 0, + ] + .into(), + tcb_info: [ + 123, 34, 116, 99, 98, 73, 110, 102, 111, 34, 58, 123, 34, 118, 101, 114, 115, 105, + 111, 110, 34, 58, 50, 44, 34, 105, 115, 115, 117, 101, 68, 97, 116, 101, 34, 58, + 34, 50, 48, 50, 51, 45, 48, 53, 45, 48, 57, 84, 49, 51, 58, 52, 57, 58, 53, 53, 90, + 34, 44, 34, 110, 101, 120, 116, 85, 112, 100, 97, 116, 101, 34, 58, 34, 50, 48, 50, + 51, 45, 48, 54, 45, 48, 56, 84, 49, 51, 58, 52, 57, 58, 53, 53, 90, 34, 44, 34, + 102, 109, 115, 112, 99, 34, 58, 34, 48, 48, 54, 48, 54, 65, 48, 48, 48, 48, 48, 48, + 34, 44, 34, 112, 99, 101, 73, 100, 34, 58, 34, 48, 48, 48, 48, 34, 44, 34, 116, 99, + 98, 84, 121, 112, 101, 34, 58, 48, 44, 34, 116, 99, 98, 69, 118, 97, 108, 117, 97, + 116, 105, 111, 110, 68, 97, 116, 97, 78, 117, 109, 98, 101, 114, 34, 58, 49, 53, + 44, 34, 116, 99, 98, 76, 101, 118, 101, 108, 115, 34, 58, 91, 123, 34, 116, 99, 98, + 34, 58, 123, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 49, 115, 118, + 110, 34, 58, 49, 49, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 50, + 115, 118, 110, 34, 58, 49, 49, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, + 112, 48, 51, 115, 118, 110, 34, 58, 51, 44, 34, 115, 103, 120, 116, 99, 98, 99, + 111, 109, 112, 48, 52, 115, 118, 110, 34, 58, 51, 44, 34, 115, 103, 120, 116, 99, + 98, 99, 111, 109, 112, 48, 53, 115, 118, 110, 34, 58, 50, 53, 53, 44, 34, 115, 103, + 120, 116, 99, 98, 99, 111, 109, 112, 48, 54, 115, 118, 110, 34, 58, 50, 53, 53, 44, + 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 55, 115, 118, 110, 34, 58, + 49, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 56, 115, 118, 110, + 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 57, 115, + 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, + 48, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, + 112, 49, 49, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, + 111, 109, 112, 49, 50, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, + 98, 99, 111, 109, 112, 49, 51, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, + 116, 99, 98, 99, 111, 109, 112, 49, 52, 115, 118, 110, 34, 58, 48, 44, 34, 115, + 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 53, 115, 118, 110, 34, 58, 48, 44, + 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 54, 115, 118, 110, 34, 58, + 48, 44, 34, 112, 99, 101, 115, 118, 110, 34, 58, 49, 51, 125, 44, 34, 116, 99, 98, + 68, 97, 116, 101, 34, 58, 34, 50, 48, 50, 51, 45, 48, 50, 45, 49, 53, 84, 48, 48, + 58, 48, 48, 58, 48, 48, 90, 34, 44, 34, 116, 99, 98, 83, 116, 97, 116, 117, 115, + 34, 58, 34, 83, 87, 72, 97, 114, 100, 101, 110, 105, 110, 103, 78, 101, 101, 100, + 101, 100, 34, 125, 44, 123, 34, 116, 99, 98, 34, 58, 123, 34, 115, 103, 120, 116, + 99, 98, 99, 111, 109, 112, 48, 49, 115, 118, 110, 34, 58, 49, 49, 44, 34, 115, 103, + 120, 116, 99, 98, 99, 111, 109, 112, 48, 50, 115, 118, 110, 34, 58, 49, 49, 44, 34, + 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 51, 115, 118, 110, 34, 58, 51, + 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 52, 115, 118, 110, 34, + 58, 51, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 53, 115, 118, + 110, 34, 58, 50, 53, 53, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, + 54, 115, 118, 110, 34, 58, 50, 53, 53, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, + 109, 112, 48, 55, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, + 99, 111, 109, 112, 48, 56, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, + 99, 98, 99, 111, 109, 112, 48, 57, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, + 120, 116, 99, 98, 99, 111, 109, 112, 49, 48, 115, 118, 110, 34, 58, 48, 44, 34, + 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 49, 115, 118, 110, 34, 58, 48, + 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 50, 115, 118, 110, 34, + 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 51, 115, 118, + 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 52, + 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, + 49, 53, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, + 109, 112, 49, 54, 115, 118, 110, 34, 58, 48, 44, 34, 112, 99, 101, 115, 118, 110, + 34, 58, 49, 51, 125, 44, 34, 116, 99, 98, 68, 97, 116, 101, 34, 58, 34, 50, 48, 50, + 51, 45, 48, 50, 45, 49, 53, 84, 48, 48, 58, 48, 48, 58, 48, 48, 90, 34, 44, 34, + 116, 99, 98, 83, 116, 97, 116, 117, 115, 34, 58, 34, 67, 111, 110, 102, 105, 103, + 117, 114, 97, 116, 105, 111, 110, 65, 110, 100, 83, 87, 72, 97, 114, 100, 101, 110, + 105, 110, 103, 78, 101, 101, 100, 101, 100, 34, 125, 44, 123, 34, 116, 99, 98, 34, + 58, 123, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 49, 115, 118, 110, + 34, 58, 55, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 50, 115, + 118, 110, 34, 58, 57, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, + 51, 115, 118, 110, 34, 58, 51, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, + 112, 48, 52, 115, 118, 110, 34, 58, 51, 44, 34, 115, 103, 120, 116, 99, 98, 99, + 111, 109, 112, 48, 53, 115, 118, 110, 34, 58, 50, 53, 53, 44, 34, 115, 103, 120, + 116, 99, 98, 99, 111, 109, 112, 48, 54, 115, 118, 110, 34, 58, 50, 53, 53, 44, 34, + 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 55, 115, 118, 110, 34, 58, 49, + 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 56, 115, 118, 110, 34, + 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 57, 115, 118, + 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 48, + 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, + 49, 49, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, + 109, 112, 49, 50, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, + 99, 111, 109, 112, 49, 51, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, + 99, 98, 99, 111, 109, 112, 49, 52, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, + 120, 116, 99, 98, 99, 111, 109, 112, 49, 53, 115, 118, 110, 34, 58, 48, 44, 34, + 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 54, 115, 118, 110, 34, 58, 48, + 44, 34, 112, 99, 101, 115, 118, 110, 34, 58, 49, 51, 125, 44, 34, 116, 99, 98, 68, + 97, 116, 101, 34, 58, 34, 50, 48, 50, 50, 45, 48, 56, 45, 49, 48, 84, 48, 48, 58, + 48, 48, 58, 48, 48, 90, 34, 44, 34, 116, 99, 98, 83, 116, 97, 116, 117, 115, 34, + 58, 34, 79, 117, 116, 79, 102, 68, 97, 116, 101, 34, 125, 44, 123, 34, 116, 99, 98, + 34, 58, 123, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 49, 115, 118, + 110, 34, 58, 55, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 50, + 115, 118, 110, 34, 58, 57, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, + 48, 51, 115, 118, 110, 34, 58, 51, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, + 109, 112, 48, 52, 115, 118, 110, 34, 58, 51, 44, 34, 115, 103, 120, 116, 99, 98, + 99, 111, 109, 112, 48, 53, 115, 118, 110, 34, 58, 50, 53, 53, 44, 34, 115, 103, + 120, 116, 99, 98, 99, 111, 109, 112, 48, 54, 115, 118, 110, 34, 58, 50, 53, 53, 44, + 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 55, 115, 118, 110, 34, 58, + 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 56, 115, 118, 110, + 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 57, 115, + 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, + 48, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, + 112, 49, 49, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, + 111, 109, 112, 49, 50, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, + 98, 99, 111, 109, 112, 49, 51, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, + 116, 99, 98, 99, 111, 109, 112, 49, 52, 115, 118, 110, 34, 58, 48, 44, 34, 115, + 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 53, 115, 118, 110, 34, 58, 48, 44, + 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 54, 115, 118, 110, 34, 58, + 48, 44, 34, 112, 99, 101, 115, 118, 110, 34, 58, 49, 51, 125, 44, 34, 116, 99, 98, + 68, 97, 116, 101, 34, 58, 34, 50, 48, 50, 50, 45, 48, 56, 45, 49, 48, 84, 48, 48, + 58, 48, 48, 58, 48, 48, 90, 34, 44, 34, 116, 99, 98, 83, 116, 97, 116, 117, 115, + 34, 58, 34, 79, 117, 116, 79, 102, 68, 97, 116, 101, 67, 111, 110, 102, 105, 103, + 117, 114, 97, 116, 105, 111, 110, 78, 101, 101, 100, 101, 100, 34, 125, 44, 123, + 34, 116, 99, 98, 34, 58, 123, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, + 48, 49, 115, 118, 110, 34, 58, 52, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, + 109, 112, 48, 50, 115, 118, 110, 34, 58, 52, 44, 34, 115, 103, 120, 116, 99, 98, + 99, 111, 109, 112, 48, 51, 115, 118, 110, 34, 58, 51, 44, 34, 115, 103, 120, 116, + 99, 98, 99, 111, 109, 112, 48, 52, 115, 118, 110, 34, 58, 51, 44, 34, 115, 103, + 120, 116, 99, 98, 99, 111, 109, 112, 48, 53, 115, 118, 110, 34, 58, 50, 53, 53, 44, + 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 54, 115, 118, 110, 34, 58, + 50, 53, 53, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 55, 115, + 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, + 56, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, + 112, 48, 57, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, + 111, 109, 112, 49, 48, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, + 98, 99, 111, 109, 112, 49, 49, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, + 116, 99, 98, 99, 111, 109, 112, 49, 50, 115, 118, 110, 34, 58, 48, 44, 34, 115, + 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 51, 115, 118, 110, 34, 58, 48, 44, + 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 52, 115, 118, 110, 34, 58, + 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 53, 115, 118, 110, + 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 54, 115, + 118, 110, 34, 58, 48, 44, 34, 112, 99, 101, 115, 118, 110, 34, 58, 49, 49, 125, 44, + 34, 116, 99, 98, 68, 97, 116, 101, 34, 58, 34, 50, 48, 50, 49, 45, 49, 49, 45, 49, + 48, 84, 48, 48, 58, 48, 48, 58, 48, 48, 90, 34, 44, 34, 116, 99, 98, 83, 116, 97, + 116, 117, 115, 34, 58, 34, 79, 117, 116, 79, 102, 68, 97, 116, 101, 34, 125, 44, + 123, 34, 116, 99, 98, 34, 58, 123, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, + 112, 48, 49, 115, 118, 110, 34, 58, 52, 44, 34, 115, 103, 120, 116, 99, 98, 99, + 111, 109, 112, 48, 50, 115, 118, 110, 34, 58, 52, 44, 34, 115, 103, 120, 116, 99, + 98, 99, 111, 109, 112, 48, 51, 115, 118, 110, 34, 58, 51, 44, 34, 115, 103, 120, + 116, 99, 98, 99, 111, 109, 112, 48, 52, 115, 118, 110, 34, 58, 51, 44, 34, 115, + 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 53, 115, 118, 110, 34, 58, 50, 53, + 53, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 54, 115, 118, 110, + 34, 58, 50, 53, 53, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 55, + 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, + 48, 56, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, + 109, 112, 48, 57, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, + 99, 111, 109, 112, 49, 48, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, + 99, 98, 99, 111, 109, 112, 49, 49, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, + 120, 116, 99, 98, 99, 111, 109, 112, 49, 50, 115, 118, 110, 34, 58, 48, 44, 34, + 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 51, 115, 118, 110, 34, 58, 48, + 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 52, 115, 118, 110, 34, + 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 53, 115, 118, + 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 54, + 115, 118, 110, 34, 58, 48, 44, 34, 112, 99, 101, 115, 118, 110, 34, 58, 49, 48, + 125, 44, 34, 116, 99, 98, 68, 97, 116, 101, 34, 58, 34, 50, 48, 50, 48, 45, 49, 49, + 45, 49, 49, 84, 48, 48, 58, 48, 48, 58, 48, 48, 90, 34, 44, 34, 116, 99, 98, 83, + 116, 97, 116, 117, 115, 34, 58, 34, 79, 117, 116, 79, 102, 68, 97, 116, 101, 34, + 125, 44, 123, 34, 116, 99, 98, 34, 58, 123, 34, 115, 103, 120, 116, 99, 98, 99, + 111, 109, 112, 48, 49, 115, 118, 110, 34, 58, 52, 44, 34, 115, 103, 120, 116, 99, + 98, 99, 111, 109, 112, 48, 50, 115, 118, 110, 34, 58, 52, 44, 34, 115, 103, 120, + 116, 99, 98, 99, 111, 109, 112, 48, 51, 115, 118, 110, 34, 58, 51, 44, 34, 115, + 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 52, 115, 118, 110, 34, 58, 51, 44, + 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 53, 115, 118, 110, 34, 58, + 50, 53, 53, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 54, 115, + 118, 110, 34, 58, 50, 53, 53, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, + 112, 48, 55, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, + 111, 109, 112, 48, 56, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, + 98, 99, 111, 109, 112, 48, 57, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, + 116, 99, 98, 99, 111, 109, 112, 49, 48, 115, 118, 110, 34, 58, 48, 44, 34, 115, + 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 49, 115, 118, 110, 34, 58, 48, 44, + 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 50, 115, 118, 110, 34, 58, + 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 51, 115, 118, 110, + 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 52, 115, + 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, + 53, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, + 112, 49, 54, 115, 118, 110, 34, 58, 48, 44, 34, 112, 99, 101, 115, 118, 110, 34, + 58, 53, 125, 44, 34, 116, 99, 98, 68, 97, 116, 101, 34, 58, 34, 50, 48, 49, 56, 45, + 48, 49, 45, 48, 52, 84, 48, 48, 58, 48, 48, 58, 48, 48, 90, 34, 44, 34, 116, 99, + 98, 83, 116, 97, 116, 117, 115, 34, 58, 34, 79, 117, 116, 79, 102, 68, 97, 116, + 101, 34, 125, 93, 125, 44, 34, 115, 105, 103, 110, 97, 116, 117, 114, 101, 34, 58, + 34, 56, 98, 100, 101, 55, 101, 50, 55, 49, 99, 55, 100, 52, 102, 49, 100, 53, 51, + 49, 98, 51, 50, 102, 98, 102, 48, 56, 49, 97, 98, 57, 100, 100, 49, 101, 55, 48, + 97, 99, 100, 54, 57, 97, 99, 48, 51, 52, 49, 51, 98, 48, 99, 56, 101, 102, 52, 53, + 102, 48, 51, 50, 99, 101, 53, 97, 98, 100, 52, 56, 53, 53, 49, 98, 99, 54, 102, 55, + 52, 100, 101, 53, 100, 101, 97, 100, 54, 98, 56, 102, 99, 55, 57, 50, 49, 49, 102, + 53, 101, 57, 97, 51, 53, 98, 102, 54, 55, 51, 55, 102, 52, 56, 101, 52, 100, 100, + 102, 102, 49, 48, 101, 55, 100, 56, 102, 54, 98, 57, 57, 34, 125, 0, + ] + .into(), + qe_identity_issuer_chain: [ + 45, 45, 45, 45, 45, 66, 69, 71, 73, 78, 32, 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, + 69, 45, 45, 45, 45, 45, 10, 77, 73, 73, 67, 105, 122, 67, 67, 65, 106, 75, 103, 65, + 119, 73, 66, 65, 103, 73, 85, 102, 106, 105, 67, 49, 102, 116, 86, 75, 85, 112, 65, + 83, 89, 53, 70, 104, 65, 80, 112, 70, 74, 71, 57, 57, 70, 85, 119, 67, 103, 89, 73, + 75, 111, 90, 73, 122, 106, 48, 69, 65, 119, 73, 119, 10, 97, 68, 69, 97, 77, 66, + 103, 71, 65, 49, 85, 69, 65, 119, 119, 82, 83, 87, 53, 48, 90, 87, 119, 103, 85, + 48, 100, 89, 73, 70, 74, 118, 98, 51, 81, 103, 81, 48, 69, 120, 71, 106, 65, 89, + 66, 103, 78, 86, 66, 65, 111, 77, 69, 85, 108, 117, 100, 71, 86, 115, 73, 69, 78, + 118, 10, 99, 110, 66, 118, 99, 109, 70, 48, 97, 87, 57, 117, 77, 82, 81, 119, 69, + 103, 89, 68, 86, 81, 81, 72, 68, 65, 116, 84, 89, 87, 53, 48, 89, 83, 66, 68, 98, + 71, 70, 121, 89, 84, 69, 76, 77, 65, 107, 71, 65, 49, 85, 69, 67, 65, 119, 67, 81, + 48, 69, 120, 67, 122, 65, 74, 10, 66, 103, 78, 86, 66, 65, 89, 84, 65, 108, 86, 84, + 77, 66, 52, 88, 68, 84, 69, 52, 77, 68, 85, 121, 77, 84, 69, 119, 78, 84, 65, 120, + 77, 70, 111, 88, 68, 84, 73, 49, 77, 68, 85, 121, 77, 84, 69, 119, 78, 84, 65, 120, + 77, 70, 111, 119, 98, 68, 69, 101, 77, 66, 119, 71, 10, 65, 49, 85, 69, 65, 119, + 119, 86, 83, 87, 53, 48, 90, 87, 119, 103, 85, 48, 100, 89, 73, 70, 82, 68, 81, + 105, 66, 84, 97, 87, 100, 117, 97, 87, 53, 110, 77, 82, 111, 119, 71, 65, 89, 68, + 86, 81, 81, 75, 68, 66, 70, 74, 98, 110, 82, 108, 98, 67, 66, 68, 98, 51, 74, 119, + 10, 98, 51, 74, 104, 100, 71, 108, 118, 98, 106, 69, 85, 77, 66, 73, 71, 65, 49, + 85, 69, 66, 119, 119, 76, 85, 50, 70, 117, 100, 71, 69, 103, 81, 50, 120, 104, 99, + 109, 69, 120, 67, 122, 65, 74, 66, 103, 78, 86, 66, 65, 103, 77, 65, 107, 78, 66, + 77, 81, 115, 119, 67, 81, 89, 68, 10, 86, 81, 81, 71, 69, 119, 74, 86, 85, 122, 66, + 90, 77, 66, 77, 71, 66, 121, 113, 71, 83, 77, 52, 57, 65, 103, 69, 71, 67, 67, 113, + 71, 83, 77, 52, 57, 65, 119, 69, 72, 65, 48, 73, 65, 66, 69, 78, 70, 71, 56, 120, + 122, 121, 100, 87, 82, 102, 75, 57, 50, 98, 109, 71, 118, 10, 80, 43, 109, 65, 104, + 57, 49, 80, 69, 121, 86, 55, 74, 104, 54, 70, 71, 74, 100, 53, 110, 100, 69, 57, + 97, 66, 72, 55, 82, 51, 69, 52, 65, 55, 117, 98, 114, 108, 104, 47, 122, 78, 51, + 67, 52, 120, 118, 112, 111, 111, 117, 71, 108, 105, 114, 77, 98, 97, 43, 87, 50, + 108, 106, 117, 10, 121, 112, 97, 106, 103, 98, 85, 119, 103, 98, 73, 119, 72, 119, + 89, 68, 86, 82, 48, 106, 66, 66, 103, 119, 70, 111, 65, 85, 73, 109, 85, 77, 49, + 108, 113, 100, 78, 73, 110, 122, 103, 55, 83, 86, 85, 114, 57, 81, 71, 122, 107, + 110, 66, 113, 119, 119, 85, 103, 89, 68, 86, 82, 48, 102, 10, 66, 69, 115, 119, 83, + 84, 66, 72, 111, 69, 87, 103, 81, 52, 90, 66, 97, 72, 82, 48, 99, 72, 77, 54, 76, + 121, 57, 106, 90, 88, 74, 48, 97, 87, 90, 112, 89, 50, 70, 48, 90, 88, 77, 117, + 100, 72, 74, 49, 99, 51, 82, 108, 90, 72, 78, 108, 99, 110, 90, 112, 89, 50, 86, + 122, 10, 76, 109, 108, 117, 100, 71, 86, 115, 76, 109, 78, 118, 98, 83, 57, 74, 98, + 110, 82, 108, 98, 70, 78, 72, 87, 70, 74, 118, 98, 51, 82, 68, 81, 83, 53, 107, 90, + 88, 73, 119, 72, 81, 89, 68, 86, 82, 48, 79, 66, 66, 89, 69, 70, 72, 52, 52, 103, + 116, 88, 55, 86, 83, 108, 75, 10, 81, 69, 109, 79, 82, 89, 81, 68, 54, 82, 83, 82, + 118, 102, 82, 86, 77, 65, 52, 71, 65, 49, 85, 100, 68, 119, 69, 66, 47, 119, 81, + 69, 65, 119, 73, 71, 119, 68, 65, 77, 66, 103, 78, 86, 72, 82, 77, 66, 65, 102, 56, + 69, 65, 106, 65, 65, 77, 65, 111, 71, 67, 67, 113, 71, 10, 83, 77, 52, 57, 66, 65, + 77, 67, 65, 48, 99, 65, 77, 69, 81, 67, 73, 66, 57, 67, 56, 119, 79, 65, 78, 47, + 73, 109, 120, 68, 116, 71, 65, 67, 86, 50, 52, 54, 75, 99, 113, 106, 97, 103, 90, + 79, 82, 48, 107, 121, 99, 116, 121, 66, 114, 115, 71, 71, 74, 86, 65, 105, 65, 106, + 10, 102, 116, 98, 114, 78, 71, 115, 71, 85, 56, 89, 72, 50, 49, 49, 100, 82, 105, + 89, 78, 111, 80, 80, 117, 49, 57, 90, 112, 47, 122, 101, 56, 74, 109, 104, 117, + 106, 66, 48, 111, 66, 119, 61, 61, 10, 45, 45, 45, 45, 45, 69, 78, 68, 32, 67, 69, + 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, 10, 45, 45, 45, 45, 45, 66, + 69, 71, 73, 78, 32, 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, + 10, 77, 73, 73, 67, 106, 122, 67, 67, 65, 106, 83, 103, 65, 119, 73, 66, 65, 103, + 73, 85, 73, 109, 85, 77, 49, 108, 113, 100, 78, 73, 110, 122, 103, 55, 83, 86, 85, + 114, 57, 81, 71, 122, 107, 110, 66, 113, 119, 119, 67, 103, 89, 73, 75, 111, 90, + 73, 122, 106, 48, 69, 65, 119, 73, 119, 10, 97, 68, 69, 97, 77, 66, 103, 71, 65, + 49, 85, 69, 65, 119, 119, 82, 83, 87, 53, 48, 90, 87, 119, 103, 85, 48, 100, 89, + 73, 70, 74, 118, 98, 51, 81, 103, 81, 48, 69, 120, 71, 106, 65, 89, 66, 103, 78, + 86, 66, 65, 111, 77, 69, 85, 108, 117, 100, 71, 86, 115, 73, 69, 78, 118, 10, 99, + 110, 66, 118, 99, 109, 70, 48, 97, 87, 57, 117, 77, 82, 81, 119, 69, 103, 89, 68, + 86, 81, 81, 72, 68, 65, 116, 84, 89, 87, 53, 48, 89, 83, 66, 68, 98, 71, 70, 121, + 89, 84, 69, 76, 77, 65, 107, 71, 65, 49, 85, 69, 67, 65, 119, 67, 81, 48, 69, 120, + 67, 122, 65, 74, 10, 66, 103, 78, 86, 66, 65, 89, 84, 65, 108, 86, 84, 77, 66, 52, + 88, 68, 84, 69, 52, 77, 68, 85, 121, 77, 84, 69, 119, 78, 68, 85, 120, 77, 70, 111, + 88, 68, 84, 81, 53, 77, 84, 73, 122, 77, 84, 73, 122, 78, 84, 107, 49, 79, 86, 111, + 119, 97, 68, 69, 97, 77, 66, 103, 71, 10, 65, 49, 85, 69, 65, 119, 119, 82, 83, 87, + 53, 48, 90, 87, 119, 103, 85, 48, 100, 89, 73, 70, 74, 118, 98, 51, 81, 103, 81, + 48, 69, 120, 71, 106, 65, 89, 66, 103, 78, 86, 66, 65, 111, 77, 69, 85, 108, 117, + 100, 71, 86, 115, 73, 69, 78, 118, 99, 110, 66, 118, 99, 109, 70, 48, 10, 97, 87, + 57, 117, 77, 82, 81, 119, 69, 103, 89, 68, 86, 81, 81, 72, 68, 65, 116, 84, 89, 87, + 53, 48, 89, 83, 66, 68, 98, 71, 70, 121, 89, 84, 69, 76, 77, 65, 107, 71, 65, 49, + 85, 69, 67, 65, 119, 67, 81, 48, 69, 120, 67, 122, 65, 74, 66, 103, 78, 86, 66, 65, + 89, 84, 10, 65, 108, 86, 84, 77, 70, 107, 119, 69, 119, 89, 72, 75, 111, 90, 73, + 122, 106, 48, 67, 65, 81, 89, 73, 75, 111, 90, 73, 122, 106, 48, 68, 65, 81, 99, + 68, 81, 103, 65, 69, 67, 54, 110, 69, 119, 77, 68, 73, 89, 90, 79, 106, 47, 105, + 80, 87, 115, 67, 122, 97, 69, 75, 105, 55, 10, 49, 79, 105, 79, 83, 76, 82, 70, + 104, 87, 71, 106, 98, 110, 66, 86, 74, 102, 86, 110, 107, 89, 52, 117, 51, 73, 106, + 107, 68, 89, 89, 76, 48, 77, 120, 79, 52, 109, 113, 115, 121, 89, 106, 108, 66, 97, + 108, 84, 86, 89, 120, 70, 80, 50, 115, 74, 66, 75, 53, 122, 108, 75, 79, 66, 10, + 117, 122, 67, 66, 117, 68, 65, 102, 66, 103, 78, 86, 72, 83, 77, 69, 71, 68, 65, + 87, 103, 66, 81, 105, 90, 81, 122, 87, 87, 112, 48, 48, 105, 102, 79, 68, 116, 74, + 86, 83, 118, 49, 65, 98, 79, 83, 99, 71, 114, 68, 66, 83, 66, 103, 78, 86, 72, 82, + 56, 69, 83, 122, 66, 74, 10, 77, 69, 101, 103, 82, 97, 66, 68, 104, 107, 70, 111, + 100, 72, 82, 119, 99, 122, 111, 118, 76, 50, 78, 108, 99, 110, 82, 112, 90, 109, + 108, 106, 89, 88, 82, 108, 99, 121, 53, 48, 99, 110, 86, 122, 100, 71, 86, 107, 99, + 50, 86, 121, 100, 109, 108, 106, 90, 88, 77, 117, 97, 87, 53, 48, 10, 90, 87, 119, + 117, 89, 50, 57, 116, 76, 48, 108, 117, 100, 71, 86, 115, 85, 48, 100, 89, 85, 109, + 57, 118, 100, 69, 78, 66, 76, 109, 82, 108, 99, 106, 65, 100, 66, 103, 78, 86, 72, + 81, 52, 69, 70, 103, 81, 85, 73, 109, 85, 77, 49, 108, 113, 100, 78, 73, 110, 122, + 103, 55, 83, 86, 10, 85, 114, 57, 81, 71, 122, 107, 110, 66, 113, 119, 119, 68, + 103, 89, 68, 86, 82, 48, 80, 65, 81, 72, 47, 66, 65, 81, 68, 65, 103, 69, 71, 77, + 66, 73, 71, 65, 49, 85, 100, 69, 119, 69, 66, 47, 119, 81, 73, 77, 65, 89, 66, 65, + 102, 56, 67, 65, 81, 69, 119, 67, 103, 89, 73, 10, 75, 111, 90, 73, 122, 106, 48, + 69, 65, 119, 73, 68, 83, 81, 65, 119, 82, 103, 73, 104, 65, 79, 87, 47, 53, 81, + 107, 82, 43, 83, 57, 67, 105, 83, 68, 99, 78, 111, 111, 119, 76, 117, 80, 82, 76, + 115, 87, 71, 102, 47, 89, 105, 55, 71, 83, 88, 57, 52, 66, 103, 119, 84, 119, 103, + 10, 65, 105, 69, 65, 52, 74, 48, 108, 114, 72, 111, 77, 115, 43, 88, 111, 53, 111, + 47, 115, 88, 54, 79, 57, 81, 87, 120, 72, 82, 65, 118, 90, 85, 71, 79, 100, 82, 81, + 55, 99, 118, 113, 82, 88, 97, 113, 73, 61, 10, 45, 45, 45, 45, 45, 69, 78, 68, 32, + 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, 10, 0, + ] + .into(), + qe_identity: [ + 123, 34, 101, 110, 99, 108, 97, 118, 101, 73, 100, 101, 110, 116, 105, 116, 121, + 34, 58, 123, 34, 105, 100, 34, 58, 34, 81, 69, 34, 44, 34, 118, 101, 114, 115, 105, + 111, 110, 34, 58, 50, 44, 34, 105, 115, 115, 117, 101, 68, 97, 116, 101, 34, 58, + 34, 50, 48, 50, 51, 45, 48, 53, 45, 48, 57, 84, 49, 49, 58, 52, 55, 58, 48, 56, 90, + 34, 44, 34, 110, 101, 120, 116, 85, 112, 100, 97, 116, 101, 34, 58, 34, 50, 48, 50, + 51, 45, 48, 54, 45, 48, 56, 84, 49, 49, 58, 52, 55, 58, 48, 56, 90, 34, 44, 34, + 116, 99, 98, 69, 118, 97, 108, 117, 97, 116, 105, 111, 110, 68, 97, 116, 97, 78, + 117, 109, 98, 101, 114, 34, 58, 49, 53, 44, 34, 109, 105, 115, 99, 115, 101, 108, + 101, 99, 116, 34, 58, 34, 48, 48, 48, 48, 48, 48, 48, 48, 34, 44, 34, 109, 105, + 115, 99, 115, 101, 108, 101, 99, 116, 77, 97, 115, 107, 34, 58, 34, 70, 70, 70, 70, + 70, 70, 70, 70, 34, 44, 34, 97, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 58, + 34, 49, 49, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 34, 44, 34, 97, 116, 116, 114, 105, + 98, 117, 116, 101, 115, 77, 97, 115, 107, 34, 58, 34, 70, 66, 70, 70, 70, 70, 70, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 34, 44, 34, 109, 114, 115, 105, 103, 110, 101, 114, 34, 58, 34, 56, + 67, 52, 70, 53, 55, 55, 53, 68, 55, 57, 54, 53, 48, 51, 69, 57, 54, 49, 51, 55, 70, + 55, 55, 67, 54, 56, 65, 56, 50, 57, 65, 48, 48, 53, 54, 65, 67, 56, 68, 69, 68, 55, + 48, 49, 52, 48, 66, 48, 56, 49, 66, 48, 57, 52, 52, 57, 48, 67, 53, 55, 66, 70, 70, + 34, 44, 34, 105, 115, 118, 112, 114, 111, 100, 105, 100, 34, 58, 49, 44, 34, 116, + 99, 98, 76, 101, 118, 101, 108, 115, 34, 58, 91, 123, 34, 116, 99, 98, 34, 58, 123, + 34, 105, 115, 118, 115, 118, 110, 34, 58, 56, 125, 44, 34, 116, 99, 98, 68, 97, + 116, 101, 34, 58, 34, 50, 48, 50, 51, 45, 48, 50, 45, 49, 53, 84, 48, 48, 58, 48, + 48, 58, 48, 48, 90, 34, 44, 34, 116, 99, 98, 83, 116, 97, 116, 117, 115, 34, 58, + 34, 85, 112, 84, 111, 68, 97, 116, 101, 34, 125, 44, 123, 34, 116, 99, 98, 34, 58, + 123, 34, 105, 115, 118, 115, 118, 110, 34, 58, 54, 125, 44, 34, 116, 99, 98, 68, + 97, 116, 101, 34, 58, 34, 50, 48, 50, 49, 45, 49, 49, 45, 49, 48, 84, 48, 48, 58, + 48, 48, 58, 48, 48, 90, 34, 44, 34, 116, 99, 98, 83, 116, 97, 116, 117, 115, 34, + 58, 34, 79, 117, 116, 79, 102, 68, 97, 116, 101, 34, 125, 44, 123, 34, 116, 99, 98, + 34, 58, 123, 34, 105, 115, 118, 115, 118, 110, 34, 58, 53, 125, 44, 34, 116, 99, + 98, 68, 97, 116, 101, 34, 58, 34, 50, 48, 50, 48, 45, 49, 49, 45, 49, 49, 84, 48, + 48, 58, 48, 48, 58, 48, 48, 90, 34, 44, 34, 116, 99, 98, 83, 116, 97, 116, 117, + 115, 34, 58, 34, 79, 117, 116, 79, 102, 68, 97, 116, 101, 34, 125, 44, 123, 34, + 116, 99, 98, 34, 58, 123, 34, 105, 115, 118, 115, 118, 110, 34, 58, 52, 125, 44, + 34, 116, 99, 98, 68, 97, 116, 101, 34, 58, 34, 50, 48, 49, 57, 45, 49, 49, 45, 49, + 51, 84, 48, 48, 58, 48, 48, 58, 48, 48, 90, 34, 44, 34, 116, 99, 98, 83, 116, 97, + 116, 117, 115, 34, 58, 34, 79, 117, 116, 79, 102, 68, 97, 116, 101, 34, 125, 44, + 123, 34, 116, 99, 98, 34, 58, 123, 34, 105, 115, 118, 115, 118, 110, 34, 58, 50, + 125, 44, 34, 116, 99, 98, 68, 97, 116, 101, 34, 58, 34, 50, 48, 49, 57, 45, 48, 53, + 45, 49, 53, 84, 48, 48, 58, 48, 48, 58, 48, 48, 90, 34, 44, 34, 116, 99, 98, 83, + 116, 97, 116, 117, 115, 34, 58, 34, 79, 117, 116, 79, 102, 68, 97, 116, 101, 34, + 125, 44, 123, 34, 116, 99, 98, 34, 58, 123, 34, 105, 115, 118, 115, 118, 110, 34, + 58, 49, 125, 44, 34, 116, 99, 98, 68, 97, 116, 101, 34, 58, 34, 50, 48, 49, 56, 45, + 48, 56, 45, 49, 53, 84, 48, 48, 58, 48, 48, 58, 48, 48, 90, 34, 44, 34, 116, 99, + 98, 83, 116, 97, 116, 117, 115, 34, 58, 34, 79, 117, 116, 79, 102, 68, 97, 116, + 101, 34, 125, 93, 125, 44, 34, 115, 105, 103, 110, 97, 116, 117, 114, 101, 34, 58, + 34, 51, 53, 98, 102, 56, 48, 100, 49, 53, 57, 53, 97, 53, 54, 56, 99, 102, 51, 101, + 102, 51, 101, 102, 56, 100, 97, 55, 100, 49, 50, 97, 51, 53, 100, 49, 97, 101, 101, + 102, 102, 98, 55, 102, 50, 52, 57, 48, 55, 98, 55, 54, 53, 50, 57, 48, 97, 99, 52, + 55, 100, 100, 57, 97, 53, 56, 102, 54, 55, 53, 51, 52, 98, 56, 50, 101, 56, 100, + 102, 102, 99, 52, 98, 99, 48, 100, 100, 99, 51, 54, 53, 50, 99, 51, 49, 102, 50, + 102, 100, 54, 57, 97, 99, 52, 52, 55, 102, 56, 52, 49, 52, 97, 49, 99, 48, 50, 99, + 54, 99, 49, 101, 53, 50, 102, 56, 53, 57, 48, 51, 34, 125, 0, + ] + .into(), + }; + + let current_time = 1684165303; + + let report_data = [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + ]; + + let mrsigner = + hex::decode("298037d88782e022e019b3020745b78aa40ed95c77da4bf7f3253d3a44c4fd7e") + .unwrap(); + + check_quote( + "e, + &collateral, + current_time, + &mrsigner, + &report_data, + sgx_ql_qv_result_t::SGX_QL_QV_RESULT_SW_HARDENING_NEEDED, + ) + .unwrap(); + } + + #[test] + fn out_of_date() { + let quote = [ + 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x0e, 0x00, 0x93, 0x9a, + 0x72, 0x33, 0xf7, 0x9c, 0x4c, 0xa9, 0x94, 0x0a, 0x0d, 0xb3, 0x95, 0x7f, 0x06, 0x07, + 0x46, 0x72, 0x07, 0x77, 0x7b, 0x2a, 0x56, 0xdf, 0xa2, 0xb1, 0x0e, 0xdd, 0x20, 0x16, + 0x0d, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x0c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xb1, 0xab, 0x35, 0x6e, 0xa0, 0x6e, 0x53, 0x25, 0xae, 0x16, 0x7d, 0x29, 0x0b, 0x3a, + 0x66, 0xb6, 0x1b, 0x89, 0x79, 0xd1, 0x2e, 0x6b, 0xbd, 0x5a, 0x97, 0xf3, 0x85, 0x72, + 0xc0, 0x32, 0x38, 0xa2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x80, 0x37, 0xd8, 0x87, 0x82, + 0xe0, 0x22, 0xe0, 0x19, 0xb3, 0x02, 0x07, 0x45, 0xb7, 0x8a, 0xa4, 0x0e, 0xd9, 0x5c, + 0x77, 0xda, 0x4b, 0xf7, 0xf3, 0x25, 0x3d, 0x3a, 0x44, 0xc4, 0xfd, 0x7e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, + 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x44, 0x10, + 0x00, 0x00, 0xb6, 0xdc, 0x93, 0xed, 0xc9, 0x25, 0x9d, 0x21, 0x6b, 0x17, 0xe4, 0xfa, + 0x00, 0x68, 0x21, 0x80, 0x5a, 0x8e, 0xbd, 0x81, 0x9a, 0x39, 0xc5, 0xb0, 0xb1, 0xbd, + 0x0b, 0xfc, 0x4b, 0x4b, 0xe3, 0x5c, 0x7a, 0x44, 0x46, 0xe1, 0x5a, 0xc6, 0xb1, 0x2e, + 0x8c, 0xee, 0x58, 0xce, 0x09, 0x3c, 0xed, 0xe6, 0xe5, 0xdc, 0x2c, 0xbe, 0xef, 0xbe, + 0xee, 0x21, 0x96, 0xd6, 0xa3, 0x6e, 0x4f, 0x7c, 0xc8, 0x21, 0xdc, 0x8c, 0x78, 0xda, + 0x8c, 0x50, 0xe0, 0xb3, 0x86, 0xa1, 0x4d, 0x55, 0x96, 0x93, 0xb2, 0xc7, 0xf7, 0x97, + 0xe9, 0x75, 0x5f, 0xc7, 0x22, 0xdd, 0x23, 0xe7, 0xab, 0x8c, 0x97, 0xe9, 0xe9, 0x1d, + 0xa5, 0x1a, 0x02, 0xe8, 0x23, 0xf7, 0xbe, 0x88, 0xa0, 0x8b, 0x1a, 0x6b, 0xdc, 0x58, + 0x44, 0xa0, 0xaf, 0x68, 0xdc, 0x16, 0xb0, 0x8c, 0xe5, 0x3a, 0x53, 0xb2, 0xba, 0xf1, + 0x36, 0xd1, 0x4f, 0x7d, 0x0b, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x2a, + 0xa5, 0x0c, 0xe1, 0xc0, 0xce, 0xf0, 0x3c, 0xcf, 0x89, 0xe7, 0xb5, 0xb1, 0x6b, 0x0d, + 0x79, 0x78, 0xf5, 0xc2, 0xb1, 0xed, 0xcf, 0x77, 0x4d, 0x87, 0x70, 0x2e, 0x81, 0x54, + 0xd8, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x4f, 0x57, 0x75, 0xd7, 0x96, 0x50, 0x3e, + 0x96, 0x13, 0x7f, 0x77, 0xc6, 0x8a, 0x82, 0x9a, 0x00, 0x56, 0xac, 0x8d, 0xed, 0x70, + 0x14, 0x0b, 0x08, 0x1b, 0x09, 0x44, 0x90, 0xc5, 0x7b, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x4b, 0xba, 0x65, 0x76, 0x56, 0xb9, 0xb1, 0x19, 0x79, 0xbd, 0x5c, 0x8e, + 0xf7, 0x68, 0x82, 0xf7, 0x54, 0x82, 0x12, 0xf6, 0x85, 0xa2, 0x37, 0x65, 0x04, 0x3f, + 0x46, 0x54, 0x3e, 0x64, 0x18, 0xa7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0xd6, 0xbf, 0x3d, + 0x17, 0x99, 0x41, 0xbb, 0xf2, 0xd1, 0x94, 0xd7, 0xce, 0x30, 0xa0, 0xaa, 0xf9, 0x4e, + 0x8f, 0xe3, 0x46, 0xb6, 0xd8, 0x07, 0x7e, 0x6a, 0x06, 0xcb, 0x80, 0x15, 0x3f, 0xd1, + 0x00, 0xcc, 0x6c, 0x46, 0xd2, 0xd0, 0x2c, 0x02, 0x8d, 0xd9, 0x2c, 0x7d, 0x95, 0xff, + 0x13, 0x10, 0xed, 0xf8, 0x69, 0x00, 0xc8, 0x9c, 0x67, 0x68, 0x59, 0xbe, 0xc6, 0xfa, + 0x1e, 0x79, 0x74, 0x50, 0x20, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x05, 0x00, 0xdc, 0x0d, + 0x00, 0x00, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, + 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x45, 0x6a, 0x44, 0x43, 0x43, 0x42, 0x44, 0x4b, 0x67, + 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x55, 0x57, 0x74, 0x46, 0x4d, 0x63, 0x4b, + 0x63, 0x64, 0x75, 0x30, 0x43, 0x37, 0x62, 0x39, 0x30, 0x65, 0x38, 0x32, 0x67, 0x46, + 0x2f, 0x4d, 0x36, 0x63, 0x56, 0x2b, 0x45, 0x77, 0x43, 0x67, 0x59, 0x49, 0x4b, 0x6f, + 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x45, 0x41, 0x77, 0x49, 0x77, 0x0a, 0x63, 0x54, 0x45, + 0x6a, 0x4d, 0x43, 0x45, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, 0x77, 0x61, 0x53, + 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, 0x67, 0x55, 0x30, 0x64, 0x59, 0x49, 0x46, 0x42, + 0x44, 0x53, 0x79, 0x42, 0x51, 0x63, 0x6d, 0x39, 0x6a, 0x5a, 0x58, 0x4e, 0x7a, 0x62, + 0x33, 0x49, 0x67, 0x51, 0x30, 0x45, 0x78, 0x47, 0x6a, 0x41, 0x59, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x0a, 0x45, 0x55, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, + 0x49, 0x45, 0x4e, 0x76, 0x63, 0x6e, 0x42, 0x76, 0x63, 0x6d, 0x46, 0x30, 0x61, 0x57, + 0x39, 0x75, 0x4d, 0x52, 0x51, 0x77, 0x45, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x48, + 0x44, 0x41, 0x74, 0x54, 0x59, 0x57, 0x35, 0x30, 0x59, 0x53, 0x42, 0x44, 0x62, 0x47, + 0x46, 0x79, 0x59, 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, + 0x0a, 0x43, 0x41, 0x77, 0x43, 0x51, 0x30, 0x45, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, + 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6c, 0x56, 0x54, 0x4d, 0x42, 0x34, + 0x58, 0x44, 0x54, 0x49, 0x7a, 0x4d, 0x44, 0x55, 0x77, 0x4f, 0x54, 0x45, 0x79, 0x4e, + 0x44, 0x59, 0x78, 0x4e, 0x6c, 0x6f, 0x58, 0x44, 0x54, 0x4d, 0x77, 0x4d, 0x44, 0x55, + 0x77, 0x4f, 0x54, 0x45, 0x79, 0x4e, 0x44, 0x59, 0x78, 0x0a, 0x4e, 0x6c, 0x6f, 0x77, + 0x63, 0x44, 0x45, 0x69, 0x4d, 0x43, 0x41, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, + 0x77, 0x5a, 0x53, 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, 0x67, 0x55, 0x30, 0x64, 0x59, + 0x49, 0x46, 0x42, 0x44, 0x53, 0x79, 0x42, 0x44, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57, + 0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, 0x5a, 0x54, 0x45, 0x61, 0x4d, 0x42, 0x67, 0x47, + 0x41, 0x31, 0x55, 0x45, 0x0a, 0x43, 0x67, 0x77, 0x52, 0x53, 0x57, 0x35, 0x30, 0x5a, + 0x57, 0x77, 0x67, 0x51, 0x32, 0x39, 0x79, 0x63, 0x47, 0x39, 0x79, 0x59, 0x58, 0x52, + 0x70, 0x62, 0x32, 0x34, 0x78, 0x46, 0x44, 0x41, 0x53, 0x42, 0x67, 0x4e, 0x56, 0x42, + 0x41, 0x63, 0x4d, 0x43, 0x31, 0x4e, 0x68, 0x62, 0x6e, 0x52, 0x68, 0x49, 0x45, 0x4e, + 0x73, 0x59, 0x58, 0x4a, 0x68, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x0a, + 0x56, 0x51, 0x51, 0x49, 0x44, 0x41, 0x4a, 0x44, 0x51, 0x54, 0x45, 0x4c, 0x4d, 0x41, + 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x77, + 0x57, 0x54, 0x41, 0x54, 0x42, 0x67, 0x63, 0x71, 0x68, 0x6b, 0x6a, 0x4f, 0x50, 0x51, + 0x49, 0x42, 0x42, 0x67, 0x67, 0x71, 0x68, 0x6b, 0x6a, 0x4f, 0x50, 0x51, 0x4d, 0x42, + 0x42, 0x77, 0x4e, 0x43, 0x41, 0x41, 0x51, 0x57, 0x0a, 0x49, 0x41, 0x6e, 0x45, 0x63, + 0x72, 0x51, 0x43, 0x78, 0x51, 0x48, 0x41, 0x77, 0x6d, 0x66, 0x43, 0x2f, 0x6d, 0x53, + 0x5a, 0x37, 0x33, 0x59, 0x4d, 0x31, 0x39, 0x45, 0x76, 0x43, 0x30, 0x2b, 0x62, 0x75, + 0x51, 0x6c, 0x35, 0x6e, 0x65, 0x6a, 0x65, 0x64, 0x77, 0x36, 0x6c, 0x6d, 0x62, 0x5a, + 0x55, 0x31, 0x4e, 0x45, 0x39, 0x5a, 0x55, 0x52, 0x48, 0x4d, 0x31, 0x57, 0x44, 0x44, + 0x4b, 0x72, 0x4e, 0x0a, 0x6d, 0x62, 0x35, 0x53, 0x7a, 0x6c, 0x79, 0x33, 0x46, 0x66, + 0x57, 0x79, 0x4f, 0x4a, 0x59, 0x67, 0x4f, 0x6b, 0x4e, 0x49, 0x6f, 0x34, 0x49, 0x43, + 0x70, 0x7a, 0x43, 0x43, 0x41, 0x71, 0x4d, 0x77, 0x48, 0x77, 0x59, 0x44, 0x56, 0x52, + 0x30, 0x6a, 0x42, 0x42, 0x67, 0x77, 0x46, 0x6f, 0x41, 0x55, 0x30, 0x4f, 0x69, 0x71, + 0x32, 0x6e, 0x58, 0x58, 0x2b, 0x53, 0x35, 0x4a, 0x46, 0x35, 0x67, 0x38, 0x0a, 0x65, + 0x78, 0x52, 0x6c, 0x30, 0x4e, 0x58, 0x79, 0x57, 0x55, 0x30, 0x77, 0x62, 0x41, 0x59, + 0x44, 0x56, 0x52, 0x30, 0x66, 0x42, 0x47, 0x55, 0x77, 0x59, 0x7a, 0x42, 0x68, 0x6f, + 0x46, 0x2b, 0x67, 0x58, 0x59, 0x5a, 0x62, 0x61, 0x48, 0x52, 0x30, 0x63, 0x48, 0x4d, + 0x36, 0x4c, 0x79, 0x39, 0x68, 0x63, 0x47, 0x6b, 0x75, 0x64, 0x48, 0x4a, 0x31, 0x63, + 0x33, 0x52, 0x6c, 0x5a, 0x48, 0x4e, 0x6c, 0x0a, 0x63, 0x6e, 0x5a, 0x70, 0x59, 0x32, + 0x56, 0x7a, 0x4c, 0x6d, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, 0x4c, 0x6d, 0x4e, 0x76, + 0x62, 0x53, 0x39, 0x7a, 0x5a, 0x33, 0x67, 0x76, 0x59, 0x32, 0x56, 0x79, 0x64, 0x47, + 0x6c, 0x6d, 0x61, 0x57, 0x4e, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x69, 0x39, 0x32, + 0x4d, 0x79, 0x39, 0x77, 0x59, 0x32, 0x74, 0x6a, 0x63, 0x6d, 0x77, 0x2f, 0x59, 0x32, + 0x45, 0x39, 0x0a, 0x63, 0x48, 0x4a, 0x76, 0x59, 0x32, 0x56, 0x7a, 0x63, 0x32, 0x39, + 0x79, 0x4a, 0x6d, 0x56, 0x75, 0x59, 0x32, 0x39, 0x6b, 0x61, 0x57, 0x35, 0x6e, 0x50, + 0x57, 0x52, 0x6c, 0x63, 0x6a, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, + 0x45, 0x46, 0x67, 0x51, 0x55, 0x77, 0x48, 0x49, 0x6e, 0x51, 0x41, 0x52, 0x6c, 0x67, + 0x30, 0x44, 0x4a, 0x51, 0x6c, 0x45, 0x46, 0x4b, 0x4d, 0x4e, 0x5a, 0x0a, 0x56, 0x53, + 0x4b, 0x62, 0x59, 0x42, 0x51, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, + 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x62, 0x41, 0x4d, 0x41, + 0x77, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x43, + 0x4d, 0x41, 0x41, 0x77, 0x67, 0x67, 0x48, 0x54, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, + 0x69, 0x47, 0x2b, 0x45, 0x30, 0x42, 0x0a, 0x44, 0x51, 0x45, 0x45, 0x67, 0x67, 0x48, + 0x45, 0x4d, 0x49, 0x49, 0x42, 0x77, 0x44, 0x41, 0x65, 0x42, 0x67, 0x6f, 0x71, 0x68, + 0x6b, 0x69, 0x47, 0x2b, 0x45, 0x30, 0x42, 0x44, 0x51, 0x45, 0x42, 0x42, 0x42, 0x42, + 0x5a, 0x4c, 0x56, 0x4a, 0x69, 0x69, 0x5a, 0x4b, 0x39, 0x78, 0x4a, 0x33, 0x30, 0x41, + 0x33, 0x37, 0x6b, 0x72, 0x6b, 0x4a, 0x6b, 0x4d, 0x49, 0x49, 0x42, 0x59, 0x77, 0x59, + 0x4b, 0x0a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, + 0x41, 0x6a, 0x43, 0x43, 0x41, 0x56, 0x4d, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, + 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, 0x45, 0x43, + 0x41, 0x51, 0x6f, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, + 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, 0x49, 0x43, 0x0a, 0x41, 0x51, 0x6f, + 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, + 0x51, 0x30, 0x42, 0x41, 0x67, 0x4d, 0x43, 0x41, 0x51, 0x49, 0x77, 0x45, 0x41, 0x59, + 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, + 0x67, 0x51, 0x43, 0x41, 0x51, 0x49, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, + 0x49, 0x68, 0x76, 0x68, 0x4e, 0x0a, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, 0x55, 0x43, + 0x41, 0x51, 0x49, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, + 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, 0x59, 0x43, 0x41, 0x51, 0x45, 0x77, + 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, + 0x30, 0x42, 0x41, 0x67, 0x63, 0x43, 0x41, 0x51, 0x51, 0x77, 0x45, 0x41, 0x59, 0x4c, + 0x0a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, + 0x67, 0x67, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, + 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, 0x6b, 0x43, 0x41, + 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, + 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, 0x6f, 0x43, 0x0a, 0x41, 0x51, 0x41, 0x77, + 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, + 0x30, 0x42, 0x41, 0x67, 0x73, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, + 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, + 0x77, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, + 0x68, 0x76, 0x68, 0x4e, 0x0a, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, 0x30, 0x43, 0x41, + 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, + 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, 0x34, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, + 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, + 0x42, 0x41, 0x67, 0x38, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x0a, + 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x68, + 0x41, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, + 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x68, 0x45, 0x43, 0x41, 0x51, + 0x73, 0x77, 0x48, 0x77, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, + 0x41, 0x51, 0x30, 0x42, 0x41, 0x68, 0x49, 0x45, 0x0a, 0x45, 0x41, 0x6f, 0x4b, 0x41, + 0x67, 0x49, 0x43, 0x41, 0x51, 0x51, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4b, 0x4b, 0x6f, 0x5a, 0x49, 0x68, + 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x77, 0x51, 0x43, 0x41, 0x41, 0x41, + 0x77, 0x46, 0x41, 0x59, 0x4b, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, + 0x51, 0x30, 0x42, 0x0a, 0x42, 0x41, 0x51, 0x47, 0x41, 0x48, 0x42, 0x75, 0x52, 0x77, + 0x41, 0x41, 0x4d, 0x41, 0x38, 0x47, 0x43, 0x69, 0x71, 0x47, 0x53, 0x49, 0x62, 0x34, + 0x54, 0x51, 0x45, 0x4e, 0x41, 0x51, 0x55, 0x4b, 0x41, 0x51, 0x41, 0x77, 0x43, 0x67, + 0x59, 0x49, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x45, 0x41, 0x77, 0x49, 0x44, + 0x53, 0x41, 0x41, 0x77, 0x52, 0x51, 0x49, 0x67, 0x4b, 0x64, 0x36, 0x2b, 0x0a, 0x58, + 0x62, 0x4e, 0x42, 0x64, 0x66, 0x49, 0x73, 0x4f, 0x30, 0x4c, 0x56, 0x48, 0x45, 0x49, + 0x50, 0x75, 0x39, 0x49, 0x66, 0x4a, 0x52, 0x7a, 0x39, 0x70, 0x4f, 0x58, 0x73, 0x4f, + 0x74, 0x68, 0x78, 0x56, 0x4d, 0x59, 0x72, 0x58, 0x48, 0x49, 0x43, 0x49, 0x51, 0x44, + 0x5a, 0x71, 0x79, 0x6c, 0x61, 0x6f, 0x52, 0x36, 0x77, 0x5a, 0x76, 0x54, 0x48, 0x49, + 0x33, 0x51, 0x55, 0x59, 0x55, 0x7a, 0x6a, 0x0a, 0x77, 0x67, 0x62, 0x6b, 0x65, 0x35, + 0x77, 0x52, 0x48, 0x4c, 0x74, 0x6c, 0x31, 0x39, 0x34, 0x79, 0x53, 0x5a, 0x75, 0x4a, + 0x55, 0x41, 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, + 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, + 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x6d, 0x44, 0x43, 0x43, 0x41, 0x6a, 0x36, + 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x56, 0x41, 0x4e, 0x44, 0x6f, 0x71, + 0x74, 0x70, 0x31, 0x31, 0x2f, 0x6b, 0x75, 0x53, 0x52, 0x65, 0x59, 0x50, 0x48, 0x73, + 0x55, 0x5a, 0x64, 0x44, 0x56, 0x38, 0x6c, 0x6c, 0x4e, 0x4d, 0x41, 0x6f, 0x47, 0x43, + 0x43, 0x71, 0x47, 0x53, 0x4d, 0x34, 0x39, 0x42, 0x41, 0x4d, 0x43, 0x0a, 0x4d, 0x47, + 0x67, 0x78, 0x47, 0x6a, 0x41, 0x59, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x4d, + 0x45, 0x55, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, 0x49, 0x46, 0x4e, 0x48, 0x57, 0x43, + 0x42, 0x53, 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, 0x4e, 0x42, 0x4d, 0x52, 0x6f, 0x77, + 0x47, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x44, 0x42, 0x46, 0x4a, 0x62, 0x6e, + 0x52, 0x6c, 0x62, 0x43, 0x42, 0x44, 0x0a, 0x62, 0x33, 0x4a, 0x77, 0x62, 0x33, 0x4a, + 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x6a, 0x45, 0x55, 0x4d, 0x42, 0x49, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x42, 0x77, 0x77, 0x4c, 0x55, 0x32, 0x46, 0x75, 0x64, 0x47, 0x45, + 0x67, 0x51, 0x32, 0x78, 0x68, 0x63, 0x6d, 0x45, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, + 0x67, 0x4e, 0x56, 0x42, 0x41, 0x67, 0x4d, 0x41, 0x6b, 0x4e, 0x42, 0x4d, 0x51, 0x73, + 0x77, 0x0a, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, + 0x55, 0x7a, 0x41, 0x65, 0x46, 0x77, 0x30, 0x78, 0x4f, 0x44, 0x41, 0x31, 0x4d, 0x6a, + 0x45, 0x78, 0x4d, 0x44, 0x55, 0x77, 0x4d, 0x54, 0x42, 0x61, 0x46, 0x77, 0x30, 0x7a, + 0x4d, 0x7a, 0x41, 0x31, 0x4d, 0x6a, 0x45, 0x78, 0x4d, 0x44, 0x55, 0x77, 0x4d, 0x54, + 0x42, 0x61, 0x4d, 0x48, 0x45, 0x78, 0x49, 0x7a, 0x41, 0x68, 0x0a, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x4d, 0x4d, 0x47, 0x6b, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, 0x49, + 0x46, 0x4e, 0x48, 0x57, 0x43, 0x42, 0x51, 0x51, 0x30, 0x73, 0x67, 0x55, 0x48, 0x4a, + 0x76, 0x59, 0x32, 0x56, 0x7a, 0x63, 0x32, 0x39, 0x79, 0x49, 0x45, 0x4e, 0x42, 0x4d, + 0x52, 0x6f, 0x77, 0x47, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x44, 0x42, 0x46, + 0x4a, 0x62, 0x6e, 0x52, 0x6c, 0x0a, 0x62, 0x43, 0x42, 0x44, 0x62, 0x33, 0x4a, 0x77, + 0x62, 0x33, 0x4a, 0x68, 0x64, 0x47, 0x6c, 0x76, 0x62, 0x6a, 0x45, 0x55, 0x4d, 0x42, + 0x49, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, 0x77, 0x77, 0x4c, 0x55, 0x32, 0x46, 0x75, + 0x64, 0x47, 0x45, 0x67, 0x51, 0x32, 0x78, 0x68, 0x63, 0x6d, 0x45, 0x78, 0x43, 0x7a, + 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x67, 0x4d, 0x41, 0x6b, 0x4e, 0x42, + 0x0a, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, + 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x42, 0x5a, 0x4d, 0x42, 0x4d, 0x47, 0x42, 0x79, 0x71, + 0x47, 0x53, 0x4d, 0x34, 0x39, 0x41, 0x67, 0x45, 0x47, 0x43, 0x43, 0x71, 0x47, 0x53, + 0x4d, 0x34, 0x39, 0x41, 0x77, 0x45, 0x48, 0x41, 0x30, 0x49, 0x41, 0x42, 0x4c, 0x39, + 0x71, 0x2b, 0x4e, 0x4d, 0x70, 0x32, 0x49, 0x4f, 0x67, 0x0a, 0x74, 0x64, 0x6c, 0x31, + 0x62, 0x6b, 0x2f, 0x75, 0x57, 0x5a, 0x35, 0x2b, 0x54, 0x47, 0x51, 0x6d, 0x38, 0x61, + 0x43, 0x69, 0x38, 0x7a, 0x37, 0x38, 0x66, 0x73, 0x2b, 0x66, 0x4b, 0x43, 0x51, 0x33, + 0x64, 0x2b, 0x75, 0x44, 0x7a, 0x58, 0x6e, 0x56, 0x54, 0x41, 0x54, 0x32, 0x5a, 0x68, + 0x44, 0x43, 0x69, 0x66, 0x79, 0x49, 0x75, 0x4a, 0x77, 0x76, 0x4e, 0x33, 0x77, 0x4e, + 0x42, 0x70, 0x39, 0x69, 0x0a, 0x48, 0x42, 0x53, 0x53, 0x4d, 0x4a, 0x4d, 0x4a, 0x72, + 0x42, 0x4f, 0x6a, 0x67, 0x62, 0x73, 0x77, 0x67, 0x62, 0x67, 0x77, 0x48, 0x77, 0x59, + 0x44, 0x56, 0x52, 0x30, 0x6a, 0x42, 0x42, 0x67, 0x77, 0x46, 0x6f, 0x41, 0x55, 0x49, + 0x6d, 0x55, 0x4d, 0x31, 0x6c, 0x71, 0x64, 0x4e, 0x49, 0x6e, 0x7a, 0x67, 0x37, 0x53, + 0x56, 0x55, 0x72, 0x39, 0x51, 0x47, 0x7a, 0x6b, 0x6e, 0x42, 0x71, 0x77, 0x77, 0x0a, + 0x55, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x66, 0x42, 0x45, 0x73, 0x77, 0x53, 0x54, + 0x42, 0x48, 0x6f, 0x45, 0x57, 0x67, 0x51, 0x34, 0x5a, 0x42, 0x61, 0x48, 0x52, 0x30, + 0x63, 0x48, 0x4d, 0x36, 0x4c, 0x79, 0x39, 0x6a, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57, + 0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, 0x5a, 0x58, 0x4d, 0x75, 0x64, 0x48, 0x4a, 0x31, + 0x63, 0x33, 0x52, 0x6c, 0x5a, 0x48, 0x4e, 0x6c, 0x0a, 0x63, 0x6e, 0x5a, 0x70, 0x59, + 0x32, 0x56, 0x7a, 0x4c, 0x6d, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, 0x4c, 0x6d, 0x4e, + 0x76, 0x62, 0x53, 0x39, 0x4a, 0x62, 0x6e, 0x52, 0x6c, 0x62, 0x46, 0x4e, 0x48, 0x57, + 0x46, 0x4a, 0x76, 0x62, 0x33, 0x52, 0x44, 0x51, 0x53, 0x35, 0x6b, 0x5a, 0x58, 0x49, + 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, 0x45, 0x46, + 0x4e, 0x44, 0x6f, 0x0a, 0x71, 0x74, 0x70, 0x31, 0x31, 0x2f, 0x6b, 0x75, 0x53, 0x52, + 0x65, 0x59, 0x50, 0x48, 0x73, 0x55, 0x5a, 0x64, 0x44, 0x56, 0x38, 0x6c, 0x6c, 0x4e, + 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77, 0x45, 0x42, 0x2f, 0x77, + 0x51, 0x45, 0x41, 0x77, 0x49, 0x42, 0x42, 0x6a, 0x41, 0x53, 0x42, 0x67, 0x4e, 0x56, + 0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x45, 0x43, 0x44, 0x41, 0x47, 0x0a, 0x41, + 0x51, 0x48, 0x2f, 0x41, 0x67, 0x45, 0x41, 0x4d, 0x41, 0x6f, 0x47, 0x43, 0x43, 0x71, + 0x47, 0x53, 0x4d, 0x34, 0x39, 0x42, 0x41, 0x4d, 0x43, 0x41, 0x30, 0x67, 0x41, 0x4d, + 0x45, 0x55, 0x43, 0x49, 0x51, 0x43, 0x4a, 0x67, 0x54, 0x62, 0x74, 0x56, 0x71, 0x4f, + 0x79, 0x5a, 0x31, 0x6d, 0x33, 0x6a, 0x71, 0x69, 0x41, 0x58, 0x4d, 0x36, 0x51, 0x59, + 0x61, 0x36, 0x72, 0x35, 0x73, 0x57, 0x53, 0x0a, 0x34, 0x79, 0x2f, 0x47, 0x37, 0x79, + 0x38, 0x75, 0x49, 0x4a, 0x47, 0x78, 0x64, 0x77, 0x49, 0x67, 0x52, 0x71, 0x50, 0x76, + 0x42, 0x53, 0x4b, 0x7a, 0x7a, 0x51, 0x61, 0x67, 0x42, 0x4c, 0x51, 0x71, 0x35, 0x73, + 0x35, 0x41, 0x37, 0x30, 0x70, 0x64, 0x6f, 0x69, 0x61, 0x52, 0x4a, 0x38, 0x7a, 0x2f, + 0x30, 0x75, 0x44, 0x7a, 0x34, 0x4e, 0x67, 0x56, 0x39, 0x31, 0x6b, 0x3d, 0x0a, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, + 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, + 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, + 0x43, 0x6a, 0x7a, 0x43, 0x43, 0x41, 0x6a, 0x53, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, + 0x67, 0x49, 0x55, 0x49, 0x6d, 0x55, 0x4d, 0x31, 0x6c, 0x71, 0x64, 0x4e, 0x49, 0x6e, + 0x7a, 0x67, 0x37, 0x53, 0x56, 0x55, 0x72, 0x39, 0x51, 0x47, 0x7a, 0x6b, 0x6e, 0x42, + 0x71, 0x77, 0x77, 0x43, 0x67, 0x59, 0x49, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, + 0x45, 0x41, 0x77, 0x49, 0x77, 0x0a, 0x61, 0x44, 0x45, 0x61, 0x4d, 0x42, 0x67, 0x47, + 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, 0x77, 0x52, 0x53, 0x57, 0x35, 0x30, 0x5a, 0x57, + 0x77, 0x67, 0x55, 0x30, 0x64, 0x59, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, + 0x51, 0x30, 0x45, 0x78, 0x47, 0x6a, 0x41, 0x59, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, + 0x6f, 0x4d, 0x45, 0x55, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, 0x49, 0x45, 0x4e, 0x76, + 0x0a, 0x63, 0x6e, 0x42, 0x76, 0x63, 0x6d, 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x4d, + 0x52, 0x51, 0x77, 0x45, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x48, 0x44, 0x41, 0x74, + 0x54, 0x59, 0x57, 0x35, 0x30, 0x59, 0x53, 0x42, 0x44, 0x62, 0x47, 0x46, 0x79, 0x59, + 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x41, 0x77, + 0x43, 0x51, 0x30, 0x45, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x0a, 0x42, 0x67, 0x4e, 0x56, + 0x42, 0x41, 0x59, 0x54, 0x41, 0x6c, 0x56, 0x54, 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, + 0x45, 0x34, 0x4d, 0x44, 0x55, 0x79, 0x4d, 0x54, 0x45, 0x77, 0x4e, 0x44, 0x55, 0x78, + 0x4d, 0x46, 0x6f, 0x58, 0x44, 0x54, 0x51, 0x35, 0x4d, 0x54, 0x49, 0x7a, 0x4d, 0x54, + 0x49, 0x7a, 0x4e, 0x54, 0x6b, 0x31, 0x4f, 0x56, 0x6f, 0x77, 0x61, 0x44, 0x45, 0x61, + 0x4d, 0x42, 0x67, 0x47, 0x0a, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, 0x77, 0x52, 0x53, + 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, 0x67, 0x55, 0x30, 0x64, 0x59, 0x49, 0x46, 0x4a, + 0x76, 0x62, 0x33, 0x51, 0x67, 0x51, 0x30, 0x45, 0x78, 0x47, 0x6a, 0x41, 0x59, 0x42, + 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x45, 0x55, 0x6c, 0x75, 0x64, 0x47, 0x56, + 0x73, 0x49, 0x45, 0x4e, 0x76, 0x63, 0x6e, 0x42, 0x76, 0x63, 0x6d, 0x46, 0x30, 0x0a, + 0x61, 0x57, 0x39, 0x75, 0x4d, 0x52, 0x51, 0x77, 0x45, 0x67, 0x59, 0x44, 0x56, 0x51, + 0x51, 0x48, 0x44, 0x41, 0x74, 0x54, 0x59, 0x57, 0x35, 0x30, 0x59, 0x53, 0x42, 0x44, + 0x62, 0x47, 0x46, 0x79, 0x59, 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, + 0x55, 0x45, 0x43, 0x41, 0x77, 0x43, 0x51, 0x30, 0x45, 0x78, 0x43, 0x7a, 0x41, 0x4a, + 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x0a, 0x41, 0x6c, 0x56, 0x54, 0x4d, + 0x46, 0x6b, 0x77, 0x45, 0x77, 0x59, 0x48, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, + 0x43, 0x41, 0x51, 0x59, 0x49, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x44, 0x41, + 0x51, 0x63, 0x44, 0x51, 0x67, 0x41, 0x45, 0x43, 0x36, 0x6e, 0x45, 0x77, 0x4d, 0x44, + 0x49, 0x59, 0x5a, 0x4f, 0x6a, 0x2f, 0x69, 0x50, 0x57, 0x73, 0x43, 0x7a, 0x61, 0x45, + 0x4b, 0x69, 0x37, 0x0a, 0x31, 0x4f, 0x69, 0x4f, 0x53, 0x4c, 0x52, 0x46, 0x68, 0x57, + 0x47, 0x6a, 0x62, 0x6e, 0x42, 0x56, 0x4a, 0x66, 0x56, 0x6e, 0x6b, 0x59, 0x34, 0x75, + 0x33, 0x49, 0x6a, 0x6b, 0x44, 0x59, 0x59, 0x4c, 0x30, 0x4d, 0x78, 0x4f, 0x34, 0x6d, + 0x71, 0x73, 0x79, 0x59, 0x6a, 0x6c, 0x42, 0x61, 0x6c, 0x54, 0x56, 0x59, 0x78, 0x46, + 0x50, 0x32, 0x73, 0x4a, 0x42, 0x4b, 0x35, 0x7a, 0x6c, 0x4b, 0x4f, 0x42, 0x0a, 0x75, + 0x7a, 0x43, 0x42, 0x75, 0x44, 0x41, 0x66, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x53, 0x4d, + 0x45, 0x47, 0x44, 0x41, 0x57, 0x67, 0x42, 0x51, 0x69, 0x5a, 0x51, 0x7a, 0x57, 0x57, + 0x70, 0x30, 0x30, 0x69, 0x66, 0x4f, 0x44, 0x74, 0x4a, 0x56, 0x53, 0x76, 0x31, 0x41, + 0x62, 0x4f, 0x53, 0x63, 0x47, 0x72, 0x44, 0x42, 0x53, 0x42, 0x67, 0x4e, 0x56, 0x48, + 0x52, 0x38, 0x45, 0x53, 0x7a, 0x42, 0x4a, 0x0a, 0x4d, 0x45, 0x65, 0x67, 0x52, 0x61, + 0x42, 0x44, 0x68, 0x6b, 0x46, 0x6f, 0x64, 0x48, 0x52, 0x77, 0x63, 0x7a, 0x6f, 0x76, + 0x4c, 0x32, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, + 0x52, 0x6c, 0x63, 0x79, 0x35, 0x30, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x47, 0x56, 0x6b, + 0x63, 0x32, 0x56, 0x79, 0x64, 0x6d, 0x6c, 0x6a, 0x5a, 0x58, 0x4d, 0x75, 0x61, 0x57, + 0x35, 0x30, 0x0a, 0x5a, 0x57, 0x77, 0x75, 0x59, 0x32, 0x39, 0x74, 0x4c, 0x30, 0x6c, + 0x75, 0x64, 0x47, 0x56, 0x73, 0x55, 0x30, 0x64, 0x59, 0x55, 0x6d, 0x39, 0x76, 0x64, + 0x45, 0x4e, 0x42, 0x4c, 0x6d, 0x52, 0x6c, 0x63, 0x6a, 0x41, 0x64, 0x42, 0x67, 0x4e, + 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, 0x51, 0x55, 0x49, 0x6d, 0x55, 0x4d, 0x31, + 0x6c, 0x71, 0x64, 0x4e, 0x49, 0x6e, 0x7a, 0x67, 0x37, 0x53, 0x56, 0x0a, 0x55, 0x72, + 0x39, 0x51, 0x47, 0x7a, 0x6b, 0x6e, 0x42, 0x71, 0x77, 0x77, 0x44, 0x67, 0x59, 0x44, + 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, + 0x45, 0x47, 0x4d, 0x42, 0x49, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, + 0x2f, 0x77, 0x51, 0x49, 0x4d, 0x41, 0x59, 0x42, 0x41, 0x66, 0x38, 0x43, 0x41, 0x51, + 0x45, 0x77, 0x43, 0x67, 0x59, 0x49, 0x0a, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, + 0x45, 0x41, 0x77, 0x49, 0x44, 0x53, 0x51, 0x41, 0x77, 0x52, 0x67, 0x49, 0x68, 0x41, + 0x4f, 0x57, 0x2f, 0x35, 0x51, 0x6b, 0x52, 0x2b, 0x53, 0x39, 0x43, 0x69, 0x53, 0x44, + 0x63, 0x4e, 0x6f, 0x6f, 0x77, 0x4c, 0x75, 0x50, 0x52, 0x4c, 0x73, 0x57, 0x47, 0x66, + 0x2f, 0x59, 0x69, 0x37, 0x47, 0x53, 0x58, 0x39, 0x34, 0x42, 0x67, 0x77, 0x54, 0x77, + 0x67, 0x0a, 0x41, 0x69, 0x45, 0x41, 0x34, 0x4a, 0x30, 0x6c, 0x72, 0x48, 0x6f, 0x4d, + 0x73, 0x2b, 0x58, 0x6f, 0x35, 0x6f, 0x2f, 0x73, 0x58, 0x36, 0x4f, 0x39, 0x51, 0x57, + 0x78, 0x48, 0x52, 0x41, 0x76, 0x5a, 0x55, 0x47, 0x4f, 0x64, 0x52, 0x51, 0x37, 0x63, + 0x76, 0x71, 0x52, 0x58, 0x61, 0x71, 0x49, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, + 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x00, + ]; + + let collateral = Collateral { + major_version: 3, + minor_version: 1, + tee_type: 0, + pck_crl_issuer_chain: [ + 45, 45, 45, 45, 45, 66, 69, 71, 73, 78, 32, 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, + 69, 45, 45, 45, 45, 45, 10, 77, 73, 73, 67, 109, 68, 67, 67, 65, 106, 54, 103, 65, + 119, 73, 66, 65, 103, 73, 86, 65, 78, 68, 111, 113, 116, 112, 49, 49, 47, 107, 117, + 83, 82, 101, 89, 80, 72, 115, 85, 90, 100, 68, 86, 56, 108, 108, 78, 77, 65, 111, + 71, 67, 67, 113, 71, 83, 77, 52, 57, 66, 65, 77, 67, 10, 77, 71, 103, 120, 71, 106, + 65, 89, 66, 103, 78, 86, 66, 65, 77, 77, 69, 85, 108, 117, 100, 71, 86, 115, 73, + 70, 78, 72, 87, 67, 66, 83, 98, 50, 57, 48, 73, 69, 78, 66, 77, 82, 111, 119, 71, + 65, 89, 68, 86, 81, 81, 75, 68, 66, 70, 74, 98, 110, 82, 108, 98, 67, 66, 68, 10, + 98, 51, 74, 119, 98, 51, 74, 104, 100, 71, 108, 118, 98, 106, 69, 85, 77, 66, 73, + 71, 65, 49, 85, 69, 66, 119, 119, 76, 85, 50, 70, 117, 100, 71, 69, 103, 81, 50, + 120, 104, 99, 109, 69, 120, 67, 122, 65, 74, 66, 103, 78, 86, 66, 65, 103, 77, 65, + 107, 78, 66, 77, 81, 115, 119, 10, 67, 81, 89, 68, 86, 81, 81, 71, 69, 119, 74, 86, + 85, 122, 65, 101, 70, 119, 48, 120, 79, 68, 65, 49, 77, 106, 69, 120, 77, 68, 85, + 119, 77, 84, 66, 97, 70, 119, 48, 122, 77, 122, 65, 49, 77, 106, 69, 120, 77, 68, + 85, 119, 77, 84, 66, 97, 77, 72, 69, 120, 73, 122, 65, 104, 10, 66, 103, 78, 86, + 66, 65, 77, 77, 71, 107, 108, 117, 100, 71, 86, 115, 73, 70, 78, 72, 87, 67, 66, + 81, 81, 48, 115, 103, 85, 72, 74, 118, 89, 50, 86, 122, 99, 50, 57, 121, 73, 69, + 78, 66, 77, 82, 111, 119, 71, 65, 89, 68, 86, 81, 81, 75, 68, 66, 70, 74, 98, 110, + 82, 108, 10, 98, 67, 66, 68, 98, 51, 74, 119, 98, 51, 74, 104, 100, 71, 108, 118, + 98, 106, 69, 85, 77, 66, 73, 71, 65, 49, 85, 69, 66, 119, 119, 76, 85, 50, 70, 117, + 100, 71, 69, 103, 81, 50, 120, 104, 99, 109, 69, 120, 67, 122, 65, 74, 66, 103, 78, + 86, 66, 65, 103, 77, 65, 107, 78, 66, 10, 77, 81, 115, 119, 67, 81, 89, 68, 86, 81, + 81, 71, 69, 119, 74, 86, 85, 122, 66, 90, 77, 66, 77, 71, 66, 121, 113, 71, 83, 77, + 52, 57, 65, 103, 69, 71, 67, 67, 113, 71, 83, 77, 52, 57, 65, 119, 69, 72, 65, 48, + 73, 65, 66, 76, 57, 113, 43, 78, 77, 112, 50, 73, 79, 103, 10, 116, 100, 108, 49, + 98, 107, 47, 117, 87, 90, 53, 43, 84, 71, 81, 109, 56, 97, 67, 105, 56, 122, 55, + 56, 102, 115, 43, 102, 75, 67, 81, 51, 100, 43, 117, 68, 122, 88, 110, 86, 84, 65, + 84, 50, 90, 104, 68, 67, 105, 102, 121, 73, 117, 74, 119, 118, 78, 51, 119, 78, 66, + 112, 57, 105, 10, 72, 66, 83, 83, 77, 74, 77, 74, 114, 66, 79, 106, 103, 98, 115, + 119, 103, 98, 103, 119, 72, 119, 89, 68, 86, 82, 48, 106, 66, 66, 103, 119, 70, + 111, 65, 85, 73, 109, 85, 77, 49, 108, 113, 100, 78, 73, 110, 122, 103, 55, 83, 86, + 85, 114, 57, 81, 71, 122, 107, 110, 66, 113, 119, 119, 10, 85, 103, 89, 68, 86, 82, + 48, 102, 66, 69, 115, 119, 83, 84, 66, 72, 111, 69, 87, 103, 81, 52, 90, 66, 97, + 72, 82, 48, 99, 72, 77, 54, 76, 121, 57, 106, 90, 88, 74, 48, 97, 87, 90, 112, 89, + 50, 70, 48, 90, 88, 77, 117, 100, 72, 74, 49, 99, 51, 82, 108, 90, 72, 78, 108, 10, + 99, 110, 90, 112, 89, 50, 86, 122, 76, 109, 108, 117, 100, 71, 86, 115, 76, 109, + 78, 118, 98, 83, 57, 74, 98, 110, 82, 108, 98, 70, 78, 72, 87, 70, 74, 118, 98, 51, + 82, 68, 81, 83, 53, 107, 90, 88, 73, 119, 72, 81, 89, 68, 86, 82, 48, 79, 66, 66, + 89, 69, 70, 78, 68, 111, 10, 113, 116, 112, 49, 49, 47, 107, 117, 83, 82, 101, 89, + 80, 72, 115, 85, 90, 100, 68, 86, 56, 108, 108, 78, 77, 65, 52, 71, 65, 49, 85, + 100, 68, 119, 69, 66, 47, 119, 81, 69, 65, 119, 73, 66, 66, 106, 65, 83, 66, 103, + 78, 86, 72, 82, 77, 66, 65, 102, 56, 69, 67, 68, 65, 71, 10, 65, 81, 72, 47, 65, + 103, 69, 65, 77, 65, 111, 71, 67, 67, 113, 71, 83, 77, 52, 57, 66, 65, 77, 67, 65, + 48, 103, 65, 77, 69, 85, 67, 73, 81, 67, 74, 103, 84, 98, 116, 86, 113, 79, 121, + 90, 49, 109, 51, 106, 113, 105, 65, 88, 77, 54, 81, 89, 97, 54, 114, 53, 115, 87, + 83, 10, 52, 121, 47, 71, 55, 121, 56, 117, 73, 74, 71, 120, 100, 119, 73, 103, 82, + 113, 80, 118, 66, 83, 75, 122, 122, 81, 97, 103, 66, 76, 81, 113, 53, 115, 53, 65, + 55, 48, 112, 100, 111, 105, 97, 82, 74, 56, 122, 47, 48, 117, 68, 122, 52, 78, 103, + 86, 57, 49, 107, 61, 10, 45, 45, 45, 45, 45, 69, 78, 68, 32, 67, 69, 82, 84, 73, + 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, 10, 45, 45, 45, 45, 45, 66, 69, 71, 73, + 78, 32, 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, 10, 77, 73, + 73, 67, 106, 122, 67, 67, 65, 106, 83, 103, 65, 119, 73, 66, 65, 103, 73, 85, 73, + 109, 85, 77, 49, 108, 113, 100, 78, 73, 110, 122, 103, 55, 83, 86, 85, 114, 57, 81, + 71, 122, 107, 110, 66, 113, 119, 119, 67, 103, 89, 73, 75, 111, 90, 73, 122, 106, + 48, 69, 65, 119, 73, 119, 10, 97, 68, 69, 97, 77, 66, 103, 71, 65, 49, 85, 69, 65, + 119, 119, 82, 83, 87, 53, 48, 90, 87, 119, 103, 85, 48, 100, 89, 73, 70, 74, 118, + 98, 51, 81, 103, 81, 48, 69, 120, 71, 106, 65, 89, 66, 103, 78, 86, 66, 65, 111, + 77, 69, 85, 108, 117, 100, 71, 86, 115, 73, 69, 78, 118, 10, 99, 110, 66, 118, 99, + 109, 70, 48, 97, 87, 57, 117, 77, 82, 81, 119, 69, 103, 89, 68, 86, 81, 81, 72, 68, + 65, 116, 84, 89, 87, 53, 48, 89, 83, 66, 68, 98, 71, 70, 121, 89, 84, 69, 76, 77, + 65, 107, 71, 65, 49, 85, 69, 67, 65, 119, 67, 81, 48, 69, 120, 67, 122, 65, 74, 10, + 66, 103, 78, 86, 66, 65, 89, 84, 65, 108, 86, 84, 77, 66, 52, 88, 68, 84, 69, 52, + 77, 68, 85, 121, 77, 84, 69, 119, 78, 68, 85, 120, 77, 70, 111, 88, 68, 84, 81, 53, + 77, 84, 73, 122, 77, 84, 73, 122, 78, 84, 107, 49, 79, 86, 111, 119, 97, 68, 69, + 97, 77, 66, 103, 71, 10, 65, 49, 85, 69, 65, 119, 119, 82, 83, 87, 53, 48, 90, 87, + 119, 103, 85, 48, 100, 89, 73, 70, 74, 118, 98, 51, 81, 103, 81, 48, 69, 120, 71, + 106, 65, 89, 66, 103, 78, 86, 66, 65, 111, 77, 69, 85, 108, 117, 100, 71, 86, 115, + 73, 69, 78, 118, 99, 110, 66, 118, 99, 109, 70, 48, 10, 97, 87, 57, 117, 77, 82, + 81, 119, 69, 103, 89, 68, 86, 81, 81, 72, 68, 65, 116, 84, 89, 87, 53, 48, 89, 83, + 66, 68, 98, 71, 70, 121, 89, 84, 69, 76, 77, 65, 107, 71, 65, 49, 85, 69, 67, 65, + 119, 67, 81, 48, 69, 120, 67, 122, 65, 74, 66, 103, 78, 86, 66, 65, 89, 84, 10, 65, + 108, 86, 84, 77, 70, 107, 119, 69, 119, 89, 72, 75, 111, 90, 73, 122, 106, 48, 67, + 65, 81, 89, 73, 75, 111, 90, 73, 122, 106, 48, 68, 65, 81, 99, 68, 81, 103, 65, 69, + 67, 54, 110, 69, 119, 77, 68, 73, 89, 90, 79, 106, 47, 105, 80, 87, 115, 67, 122, + 97, 69, 75, 105, 55, 10, 49, 79, 105, 79, 83, 76, 82, 70, 104, 87, 71, 106, 98, + 110, 66, 86, 74, 102, 86, 110, 107, 89, 52, 117, 51, 73, 106, 107, 68, 89, 89, 76, + 48, 77, 120, 79, 52, 109, 113, 115, 121, 89, 106, 108, 66, 97, 108, 84, 86, 89, + 120, 70, 80, 50, 115, 74, 66, 75, 53, 122, 108, 75, 79, 66, 10, 117, 122, 67, 66, + 117, 68, 65, 102, 66, 103, 78, 86, 72, 83, 77, 69, 71, 68, 65, 87, 103, 66, 81, + 105, 90, 81, 122, 87, 87, 112, 48, 48, 105, 102, 79, 68, 116, 74, 86, 83, 118, 49, + 65, 98, 79, 83, 99, 71, 114, 68, 66, 83, 66, 103, 78, 86, 72, 82, 56, 69, 83, 122, + 66, 74, 10, 77, 69, 101, 103, 82, 97, 66, 68, 104, 107, 70, 111, 100, 72, 82, 119, + 99, 122, 111, 118, 76, 50, 78, 108, 99, 110, 82, 112, 90, 109, 108, 106, 89, 88, + 82, 108, 99, 121, 53, 48, 99, 110, 86, 122, 100, 71, 86, 107, 99, 50, 86, 121, 100, + 109, 108, 106, 90, 88, 77, 117, 97, 87, 53, 48, 10, 90, 87, 119, 117, 89, 50, 57, + 116, 76, 48, 108, 117, 100, 71, 86, 115, 85, 48, 100, 89, 85, 109, 57, 118, 100, + 69, 78, 66, 76, 109, 82, 108, 99, 106, 65, 100, 66, 103, 78, 86, 72, 81, 52, 69, + 70, 103, 81, 85, 73, 109, 85, 77, 49, 108, 113, 100, 78, 73, 110, 122, 103, 55, 83, + 86, 10, 85, 114, 57, 81, 71, 122, 107, 110, 66, 113, 119, 119, 68, 103, 89, 68, 86, + 82, 48, 80, 65, 81, 72, 47, 66, 65, 81, 68, 65, 103, 69, 71, 77, 66, 73, 71, 65, + 49, 85, 100, 69, 119, 69, 66, 47, 119, 81, 73, 77, 65, 89, 66, 65, 102, 56, 67, 65, + 81, 69, 119, 67, 103, 89, 73, 10, 75, 111, 90, 73, 122, 106, 48, 69, 65, 119, 73, + 68, 83, 81, 65, 119, 82, 103, 73, 104, 65, 79, 87, 47, 53, 81, 107, 82, 43, 83, 57, + 67, 105, 83, 68, 99, 78, 111, 111, 119, 76, 117, 80, 82, 76, 115, 87, 71, 102, 47, + 89, 105, 55, 71, 83, 88, 57, 52, 66, 103, 119, 84, 119, 103, 10, 65, 105, 69, 65, + 52, 74, 48, 108, 114, 72, 111, 77, 115, 43, 88, 111, 53, 111, 47, 115, 88, 54, 79, + 57, 81, 87, 120, 72, 82, 65, 118, 90, 85, 71, 79, 100, 82, 81, 55, 99, 118, 113, + 82, 88, 97, 113, 73, 61, 10, 45, 45, 45, 45, 45, 69, 78, 68, 32, 67, 69, 82, 84, + 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, 10, 0, + ] + .into(), + root_ca_crl: [ + 48, 130, 1, 33, 48, 129, 200, 2, 1, 1, 48, 10, 6, 8, 42, 134, 72, 206, 61, 4, 3, 2, + 48, 104, 49, 26, 48, 24, 6, 3, 85, 4, 3, 12, 17, 73, 110, 116, 101, 108, 32, 83, + 71, 88, 32, 82, 111, 111, 116, 32, 67, 65, 49, 26, 48, 24, 6, 3, 85, 4, 10, 12, 17, + 73, 110, 116, 101, 108, 32, 67, 111, 114, 112, 111, 114, 97, 116, 105, 111, 110, + 49, 20, 48, 18, 6, 3, 85, 4, 7, 12, 11, 83, 97, 110, 116, 97, 32, 67, 108, 97, 114, + 97, 49, 11, 48, 9, 6, 3, 85, 4, 8, 12, 2, 67, 65, 49, 11, 48, 9, 6, 3, 85, 4, 6, + 19, 2, 85, 83, 23, 13, 50, 51, 48, 52, 48, 51, 49, 48, 50, 50, 53, 49, 90, 23, 13, + 50, 52, 48, 52, 48, 50, 49, 48, 50, 50, 53, 49, 90, 160, 47, 48, 45, 48, 10, 6, 3, + 85, 29, 20, 4, 3, 2, 1, 1, 48, 31, 6, 3, 85, 29, 35, 4, 24, 48, 22, 128, 20, 34, + 101, 12, 214, 90, 157, 52, 137, 243, 131, 180, 149, 82, 191, 80, 27, 57, 39, 6, + 172, 48, 10, 6, 8, 42, 134, 72, 206, 61, 4, 3, 2, 3, 72, 0, 48, 69, 2, 32, 81, 87, + 125, 71, 217, 251, 161, 87, 182, 95, 30, 181, 244, 101, 123, 188, 94, 86, 204, 175, + 115, 90, 3, 241, 185, 99, 215, 4, 128, 90, 177, 24, 2, 33, 0, 147, 144, 21, 236, + 22, 54, 231, 234, 250, 95, 66, 108, 30, 64, 38, 71, 198, 115, 19, 43, 104, 80, 202, + 189, 104, 206, 246, 186, 215, 104, 42, 3, 0, + ] + .into(), + pck_crl: [ + 48, 130, 1, 41, 48, 129, 209, 2, 1, 1, 48, 10, 6, 8, 42, 134, 72, 206, 61, 4, 3, 2, + 48, 113, 49, 35, 48, 33, 6, 3, 85, 4, 3, 12, 26, 73, 110, 116, 101, 108, 32, 83, + 71, 88, 32, 80, 67, 75, 32, 80, 114, 111, 99, 101, 115, 115, 111, 114, 32, 67, 65, + 49, 26, 48, 24, 6, 3, 85, 4, 10, 12, 17, 73, 110, 116, 101, 108, 32, 67, 111, 114, + 112, 111, 114, 97, 116, 105, 111, 110, 49, 20, 48, 18, 6, 3, 85, 4, 7, 12, 11, 83, + 97, 110, 116, 97, 32, 67, 108, 97, 114, 97, 49, 11, 48, 9, 6, 3, 85, 4, 8, 12, 2, + 67, 65, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 85, 83, 23, 13, 50, 51, 48, 53, 48, + 57, 49, 50, 52, 54, 50, 52, 90, 23, 13, 50, 51, 48, 54, 48, 56, 49, 50, 52, 54, 50, + 52, 90, 160, 47, 48, 45, 48, 10, 6, 3, 85, 29, 20, 4, 3, 2, 1, 1, 48, 31, 6, 3, 85, + 29, 35, 4, 24, 48, 22, 128, 20, 208, 232, 170, 218, 117, 215, 249, 46, 73, 23, 152, + 60, 123, 20, 101, 208, 213, 242, 89, 77, 48, 10, 6, 8, 42, 134, 72, 206, 61, 4, 3, + 2, 3, 71, 0, 48, 68, 2, 32, 27, 223, 5, 23, 228, 147, 24, 110, 238, 12, 48, 228, + 112, 248, 245, 217, 211, 202, 42, 56, 61, 216, 106, 201, 130, 9, 2, 250, 236, 7, + 139, 186, 2, 32, 86, 206, 118, 134, 129, 237, 244, 14, 117, 201, 156, 112, 225, 33, + 231, 72, 85, 193, 91, 236, 63, 45, 20, 17, 170, 171, 225, 57, 84, 126, 10, 8, 0, + ] + .into(), + tcb_info_issuer_chain: [ + 45, 45, 45, 45, 45, 66, 69, 71, 73, 78, 32, 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, + 69, 45, 45, 45, 45, 45, 10, 77, 73, 73, 67, 105, 122, 67, 67, 65, 106, 75, 103, 65, + 119, 73, 66, 65, 103, 73, 85, 102, 106, 105, 67, 49, 102, 116, 86, 75, 85, 112, 65, + 83, 89, 53, 70, 104, 65, 80, 112, 70, 74, 71, 57, 57, 70, 85, 119, 67, 103, 89, 73, + 75, 111, 90, 73, 122, 106, 48, 69, 65, 119, 73, 119, 10, 97, 68, 69, 97, 77, 66, + 103, 71, 65, 49, 85, 69, 65, 119, 119, 82, 83, 87, 53, 48, 90, 87, 119, 103, 85, + 48, 100, 89, 73, 70, 74, 118, 98, 51, 81, 103, 81, 48, 69, 120, 71, 106, 65, 89, + 66, 103, 78, 86, 66, 65, 111, 77, 69, 85, 108, 117, 100, 71, 86, 115, 73, 69, 78, + 118, 10, 99, 110, 66, 118, 99, 109, 70, 48, 97, 87, 57, 117, 77, 82, 81, 119, 69, + 103, 89, 68, 86, 81, 81, 72, 68, 65, 116, 84, 89, 87, 53, 48, 89, 83, 66, 68, 98, + 71, 70, 121, 89, 84, 69, 76, 77, 65, 107, 71, 65, 49, 85, 69, 67, 65, 119, 67, 81, + 48, 69, 120, 67, 122, 65, 74, 10, 66, 103, 78, 86, 66, 65, 89, 84, 65, 108, 86, 84, + 77, 66, 52, 88, 68, 84, 69, 52, 77, 68, 85, 121, 77, 84, 69, 119, 78, 84, 65, 120, + 77, 70, 111, 88, 68, 84, 73, 49, 77, 68, 85, 121, 77, 84, 69, 119, 78, 84, 65, 120, + 77, 70, 111, 119, 98, 68, 69, 101, 77, 66, 119, 71, 10, 65, 49, 85, 69, 65, 119, + 119, 86, 83, 87, 53, 48, 90, 87, 119, 103, 85, 48, 100, 89, 73, 70, 82, 68, 81, + 105, 66, 84, 97, 87, 100, 117, 97, 87, 53, 110, 77, 82, 111, 119, 71, 65, 89, 68, + 86, 81, 81, 75, 68, 66, 70, 74, 98, 110, 82, 108, 98, 67, 66, 68, 98, 51, 74, 119, + 10, 98, 51, 74, 104, 100, 71, 108, 118, 98, 106, 69, 85, 77, 66, 73, 71, 65, 49, + 85, 69, 66, 119, 119, 76, 85, 50, 70, 117, 100, 71, 69, 103, 81, 50, 120, 104, 99, + 109, 69, 120, 67, 122, 65, 74, 66, 103, 78, 86, 66, 65, 103, 77, 65, 107, 78, 66, + 77, 81, 115, 119, 67, 81, 89, 68, 10, 86, 81, 81, 71, 69, 119, 74, 86, 85, 122, 66, + 90, 77, 66, 77, 71, 66, 121, 113, 71, 83, 77, 52, 57, 65, 103, 69, 71, 67, 67, 113, + 71, 83, 77, 52, 57, 65, 119, 69, 72, 65, 48, 73, 65, 66, 69, 78, 70, 71, 56, 120, + 122, 121, 100, 87, 82, 102, 75, 57, 50, 98, 109, 71, 118, 10, 80, 43, 109, 65, 104, + 57, 49, 80, 69, 121, 86, 55, 74, 104, 54, 70, 71, 74, 100, 53, 110, 100, 69, 57, + 97, 66, 72, 55, 82, 51, 69, 52, 65, 55, 117, 98, 114, 108, 104, 47, 122, 78, 51, + 67, 52, 120, 118, 112, 111, 111, 117, 71, 108, 105, 114, 77, 98, 97, 43, 87, 50, + 108, 106, 117, 10, 121, 112, 97, 106, 103, 98, 85, 119, 103, 98, 73, 119, 72, 119, + 89, 68, 86, 82, 48, 106, 66, 66, 103, 119, 70, 111, 65, 85, 73, 109, 85, 77, 49, + 108, 113, 100, 78, 73, 110, 122, 103, 55, 83, 86, 85, 114, 57, 81, 71, 122, 107, + 110, 66, 113, 119, 119, 85, 103, 89, 68, 86, 82, 48, 102, 10, 66, 69, 115, 119, 83, + 84, 66, 72, 111, 69, 87, 103, 81, 52, 90, 66, 97, 72, 82, 48, 99, 72, 77, 54, 76, + 121, 57, 106, 90, 88, 74, 48, 97, 87, 90, 112, 89, 50, 70, 48, 90, 88, 77, 117, + 100, 72, 74, 49, 99, 51, 82, 108, 90, 72, 78, 108, 99, 110, 90, 112, 89, 50, 86, + 122, 10, 76, 109, 108, 117, 100, 71, 86, 115, 76, 109, 78, 118, 98, 83, 57, 74, 98, + 110, 82, 108, 98, 70, 78, 72, 87, 70, 74, 118, 98, 51, 82, 68, 81, 83, 53, 107, 90, + 88, 73, 119, 72, 81, 89, 68, 86, 82, 48, 79, 66, 66, 89, 69, 70, 72, 52, 52, 103, + 116, 88, 55, 86, 83, 108, 75, 10, 81, 69, 109, 79, 82, 89, 81, 68, 54, 82, 83, 82, + 118, 102, 82, 86, 77, 65, 52, 71, 65, 49, 85, 100, 68, 119, 69, 66, 47, 119, 81, + 69, 65, 119, 73, 71, 119, 68, 65, 77, 66, 103, 78, 86, 72, 82, 77, 66, 65, 102, 56, + 69, 65, 106, 65, 65, 77, 65, 111, 71, 67, 67, 113, 71, 10, 83, 77, 52, 57, 66, 65, + 77, 67, 65, 48, 99, 65, 77, 69, 81, 67, 73, 66, 57, 67, 56, 119, 79, 65, 78, 47, + 73, 109, 120, 68, 116, 71, 65, 67, 86, 50, 52, 54, 75, 99, 113, 106, 97, 103, 90, + 79, 82, 48, 107, 121, 99, 116, 121, 66, 114, 115, 71, 71, 74, 86, 65, 105, 65, 106, + 10, 102, 116, 98, 114, 78, 71, 115, 71, 85, 56, 89, 72, 50, 49, 49, 100, 82, 105, + 89, 78, 111, 80, 80, 117, 49, 57, 90, 112, 47, 122, 101, 56, 74, 109, 104, 117, + 106, 66, 48, 111, 66, 119, 61, 61, 10, 45, 45, 45, 45, 45, 69, 78, 68, 32, 67, 69, + 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, 10, 45, 45, 45, 45, 45, 66, + 69, 71, 73, 78, 32, 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, + 10, 77, 73, 73, 67, 106, 122, 67, 67, 65, 106, 83, 103, 65, 119, 73, 66, 65, 103, + 73, 85, 73, 109, 85, 77, 49, 108, 113, 100, 78, 73, 110, 122, 103, 55, 83, 86, 85, + 114, 57, 81, 71, 122, 107, 110, 66, 113, 119, 119, 67, 103, 89, 73, 75, 111, 90, + 73, 122, 106, 48, 69, 65, 119, 73, 119, 10, 97, 68, 69, 97, 77, 66, 103, 71, 65, + 49, 85, 69, 65, 119, 119, 82, 83, 87, 53, 48, 90, 87, 119, 103, 85, 48, 100, 89, + 73, 70, 74, 118, 98, 51, 81, 103, 81, 48, 69, 120, 71, 106, 65, 89, 66, 103, 78, + 86, 66, 65, 111, 77, 69, 85, 108, 117, 100, 71, 86, 115, 73, 69, 78, 118, 10, 99, + 110, 66, 118, 99, 109, 70, 48, 97, 87, 57, 117, 77, 82, 81, 119, 69, 103, 89, 68, + 86, 81, 81, 72, 68, 65, 116, 84, 89, 87, 53, 48, 89, 83, 66, 68, 98, 71, 70, 121, + 89, 84, 69, 76, 77, 65, 107, 71, 65, 49, 85, 69, 67, 65, 119, 67, 81, 48, 69, 120, + 67, 122, 65, 74, 10, 66, 103, 78, 86, 66, 65, 89, 84, 65, 108, 86, 84, 77, 66, 52, + 88, 68, 84, 69, 52, 77, 68, 85, 121, 77, 84, 69, 119, 78, 68, 85, 120, 77, 70, 111, + 88, 68, 84, 81, 53, 77, 84, 73, 122, 77, 84, 73, 122, 78, 84, 107, 49, 79, 86, 111, + 119, 97, 68, 69, 97, 77, 66, 103, 71, 10, 65, 49, 85, 69, 65, 119, 119, 82, 83, 87, + 53, 48, 90, 87, 119, 103, 85, 48, 100, 89, 73, 70, 74, 118, 98, 51, 81, 103, 81, + 48, 69, 120, 71, 106, 65, 89, 66, 103, 78, 86, 66, 65, 111, 77, 69, 85, 108, 117, + 100, 71, 86, 115, 73, 69, 78, 118, 99, 110, 66, 118, 99, 109, 70, 48, 10, 97, 87, + 57, 117, 77, 82, 81, 119, 69, 103, 89, 68, 86, 81, 81, 72, 68, 65, 116, 84, 89, 87, + 53, 48, 89, 83, 66, 68, 98, 71, 70, 121, 89, 84, 69, 76, 77, 65, 107, 71, 65, 49, + 85, 69, 67, 65, 119, 67, 81, 48, 69, 120, 67, 122, 65, 74, 66, 103, 78, 86, 66, 65, + 89, 84, 10, 65, 108, 86, 84, 77, 70, 107, 119, 69, 119, 89, 72, 75, 111, 90, 73, + 122, 106, 48, 67, 65, 81, 89, 73, 75, 111, 90, 73, 122, 106, 48, 68, 65, 81, 99, + 68, 81, 103, 65, 69, 67, 54, 110, 69, 119, 77, 68, 73, 89, 90, 79, 106, 47, 105, + 80, 87, 115, 67, 122, 97, 69, 75, 105, 55, 10, 49, 79, 105, 79, 83, 76, 82, 70, + 104, 87, 71, 106, 98, 110, 66, 86, 74, 102, 86, 110, 107, 89, 52, 117, 51, 73, 106, + 107, 68, 89, 89, 76, 48, 77, 120, 79, 52, 109, 113, 115, 121, 89, 106, 108, 66, 97, + 108, 84, 86, 89, 120, 70, 80, 50, 115, 74, 66, 75, 53, 122, 108, 75, 79, 66, 10, + 117, 122, 67, 66, 117, 68, 65, 102, 66, 103, 78, 86, 72, 83, 77, 69, 71, 68, 65, + 87, 103, 66, 81, 105, 90, 81, 122, 87, 87, 112, 48, 48, 105, 102, 79, 68, 116, 74, + 86, 83, 118, 49, 65, 98, 79, 83, 99, 71, 114, 68, 66, 83, 66, 103, 78, 86, 72, 82, + 56, 69, 83, 122, 66, 74, 10, 77, 69, 101, 103, 82, 97, 66, 68, 104, 107, 70, 111, + 100, 72, 82, 119, 99, 122, 111, 118, 76, 50, 78, 108, 99, 110, 82, 112, 90, 109, + 108, 106, 89, 88, 82, 108, 99, 121, 53, 48, 99, 110, 86, 122, 100, 71, 86, 107, 99, + 50, 86, 121, 100, 109, 108, 106, 90, 88, 77, 117, 97, 87, 53, 48, 10, 90, 87, 119, + 117, 89, 50, 57, 116, 76, 48, 108, 117, 100, 71, 86, 115, 85, 48, 100, 89, 85, 109, + 57, 118, 100, 69, 78, 66, 76, 109, 82, 108, 99, 106, 65, 100, 66, 103, 78, 86, 72, + 81, 52, 69, 70, 103, 81, 85, 73, 109, 85, 77, 49, 108, 113, 100, 78, 73, 110, 122, + 103, 55, 83, 86, 10, 85, 114, 57, 81, 71, 122, 107, 110, 66, 113, 119, 119, 68, + 103, 89, 68, 86, 82, 48, 80, 65, 81, 72, 47, 66, 65, 81, 68, 65, 103, 69, 71, 77, + 66, 73, 71, 65, 49, 85, 100, 69, 119, 69, 66, 47, 119, 81, 73, 77, 65, 89, 66, 65, + 102, 56, 67, 65, 81, 69, 119, 67, 103, 89, 73, 10, 75, 111, 90, 73, 122, 106, 48, + 69, 65, 119, 73, 68, 83, 81, 65, 119, 82, 103, 73, 104, 65, 79, 87, 47, 53, 81, + 107, 82, 43, 83, 57, 67, 105, 83, 68, 99, 78, 111, 111, 119, 76, 117, 80, 82, 76, + 115, 87, 71, 102, 47, 89, 105, 55, 71, 83, 88, 57, 52, 66, 103, 119, 84, 119, 103, + 10, 65, 105, 69, 65, 52, 74, 48, 108, 114, 72, 111, 77, 115, 43, 88, 111, 53, 111, + 47, 115, 88, 54, 79, 57, 81, 87, 120, 72, 82, 65, 118, 90, 85, 71, 79, 100, 82, 81, + 55, 99, 118, 113, 82, 88, 97, 113, 73, 61, 10, 45, 45, 45, 45, 45, 69, 78, 68, 32, + 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, 10, 0, + ] + .into(), + tcb_info: [ + 123, 34, 116, 99, 98, 73, 110, 102, 111, 34, 58, 123, 34, 118, 101, 114, 115, 105, + 111, 110, 34, 58, 50, 44, 34, 105, 115, 115, 117, 101, 68, 97, 116, 101, 34, 58, + 34, 50, 48, 50, 51, 45, 48, 53, 45, 48, 57, 84, 49, 50, 58, 52, 54, 58, 49, 55, 90, + 34, 44, 34, 110, 101, 120, 116, 85, 112, 100, 97, 116, 101, 34, 58, 34, 50, 48, 50, + 51, 45, 48, 54, 45, 48, 56, 84, 49, 50, 58, 52, 54, 58, 49, 55, 90, 34, 44, 34, + 102, 109, 115, 112, 99, 34, 58, 34, 48, 48, 55, 48, 54, 69, 52, 55, 48, 48, 48, 48, + 34, 44, 34, 112, 99, 101, 73, 100, 34, 58, 34, 48, 48, 48, 48, 34, 44, 34, 116, 99, + 98, 84, 121, 112, 101, 34, 58, 48, 44, 34, 116, 99, 98, 69, 118, 97, 108, 117, 97, + 116, 105, 111, 110, 68, 97, 116, 97, 78, 117, 109, 98, 101, 114, 34, 58, 49, 53, + 44, 34, 116, 99, 98, 76, 101, 118, 101, 108, 115, 34, 58, 91, 123, 34, 116, 99, 98, + 34, 58, 123, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 49, 115, 118, + 110, 34, 58, 49, 54, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 50, + 115, 118, 110, 34, 58, 49, 54, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, + 112, 48, 51, 115, 118, 110, 34, 58, 50, 44, 34, 115, 103, 120, 116, 99, 98, 99, + 111, 109, 112, 48, 52, 115, 118, 110, 34, 58, 50, 44, 34, 115, 103, 120, 116, 99, + 98, 99, 111, 109, 112, 48, 53, 115, 118, 110, 34, 58, 50, 44, 34, 115, 103, 120, + 116, 99, 98, 99, 111, 109, 112, 48, 54, 115, 118, 110, 34, 58, 49, 44, 34, 115, + 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 55, 115, 118, 110, 34, 58, 49, 50, + 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 56, 115, 118, 110, 34, + 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 57, 115, 118, + 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 48, + 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, + 49, 49, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, + 109, 112, 49, 50, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, + 99, 111, 109, 112, 49, 51, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, + 99, 98, 99, 111, 109, 112, 49, 52, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, + 120, 116, 99, 98, 99, 111, 109, 112, 49, 53, 115, 118, 110, 34, 58, 48, 44, 34, + 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 54, 115, 118, 110, 34, 58, 48, + 44, 34, 112, 99, 101, 115, 118, 110, 34, 58, 49, 51, 125, 44, 34, 116, 99, 98, 68, + 97, 116, 101, 34, 58, 34, 50, 48, 50, 51, 45, 48, 50, 45, 49, 53, 84, 48, 48, 58, + 48, 48, 58, 48, 48, 90, 34, 44, 34, 116, 99, 98, 83, 116, 97, 116, 117, 115, 34, + 58, 34, 83, 87, 72, 97, 114, 100, 101, 110, 105, 110, 103, 78, 101, 101, 100, 101, + 100, 34, 125, 44, 123, 34, 116, 99, 98, 34, 58, 123, 34, 115, 103, 120, 116, 99, + 98, 99, 111, 109, 112, 48, 49, 115, 118, 110, 34, 58, 49, 54, 44, 34, 115, 103, + 120, 116, 99, 98, 99, 111, 109, 112, 48, 50, 115, 118, 110, 34, 58, 49, 54, 44, 34, + 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 51, 115, 118, 110, 34, 58, 50, + 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 52, 115, 118, 110, 34, + 58, 50, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 53, 115, 118, + 110, 34, 58, 50, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 54, + 115, 118, 110, 34, 58, 49, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, + 48, 55, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, + 109, 112, 48, 56, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, + 99, 111, 109, 112, 48, 57, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, + 99, 98, 99, 111, 109, 112, 49, 48, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, + 120, 116, 99, 98, 99, 111, 109, 112, 49, 49, 115, 118, 110, 34, 58, 48, 44, 34, + 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 50, 115, 118, 110, 34, 58, 48, + 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 51, 115, 118, 110, 34, + 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 52, 115, 118, + 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 53, + 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, + 49, 54, 115, 118, 110, 34, 58, 48, 44, 34, 112, 99, 101, 115, 118, 110, 34, 58, 49, + 51, 125, 44, 34, 116, 99, 98, 68, 97, 116, 101, 34, 58, 34, 50, 48, 50, 51, 45, 48, + 50, 45, 49, 53, 84, 48, 48, 58, 48, 48, 58, 48, 48, 90, 34, 44, 34, 116, 99, 98, + 83, 116, 97, 116, 117, 115, 34, 58, 34, 67, 111, 110, 102, 105, 103, 117, 114, 97, + 116, 105, 111, 110, 65, 110, 100, 83, 87, 72, 97, 114, 100, 101, 110, 105, 110, + 103, 78, 101, 101, 100, 101, 100, 34, 125, 44, 123, 34, 116, 99, 98, 34, 58, 123, + 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 49, 115, 118, 110, 34, 58, + 49, 53, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 50, 115, 118, + 110, 34, 58, 49, 53, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 51, + 115, 118, 110, 34, 58, 50, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, + 48, 52, 115, 118, 110, 34, 58, 50, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, + 109, 112, 48, 53, 115, 118, 110, 34, 58, 50, 44, 34, 115, 103, 120, 116, 99, 98, + 99, 111, 109, 112, 48, 54, 115, 118, 110, 34, 58, 49, 44, 34, 115, 103, 120, 116, + 99, 98, 99, 111, 109, 112, 48, 55, 115, 118, 110, 34, 58, 49, 50, 44, 34, 115, 103, + 120, 116, 99, 98, 99, 111, 109, 112, 48, 56, 115, 118, 110, 34, 58, 48, 44, 34, + 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 57, 115, 118, 110, 34, 58, 48, + 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 48, 115, 118, 110, 34, + 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 49, 115, 118, + 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 50, + 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, + 49, 51, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, + 109, 112, 49, 52, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, + 99, 111, 109, 112, 49, 53, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, + 99, 98, 99, 111, 109, 112, 49, 54, 115, 118, 110, 34, 58, 48, 44, 34, 112, 99, 101, + 115, 118, 110, 34, 58, 49, 51, 125, 44, 34, 116, 99, 98, 68, 97, 116, 101, 34, 58, + 34, 50, 48, 50, 50, 45, 49, 49, 45, 48, 57, 84, 48, 48, 58, 48, 48, 58, 48, 48, 90, + 34, 44, 34, 116, 99, 98, 83, 116, 97, 116, 117, 115, 34, 58, 34, 79, 117, 116, 79, + 102, 68, 97, 116, 101, 34, 125, 44, 123, 34, 116, 99, 98, 34, 58, 123, 34, 115, + 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 49, 115, 118, 110, 34, 58, 49, 53, + 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 50, 115, 118, 110, 34, + 58, 49, 53, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 51, 115, + 118, 110, 34, 58, 50, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, + 52, 115, 118, 110, 34, 58, 50, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, + 112, 48, 53, 115, 118, 110, 34, 58, 50, 44, 34, 115, 103, 120, 116, 99, 98, 99, + 111, 109, 112, 48, 54, 115, 118, 110, 34, 58, 49, 44, 34, 115, 103, 120, 116, 99, + 98, 99, 111, 109, 112, 48, 55, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, + 116, 99, 98, 99, 111, 109, 112, 48, 56, 115, 118, 110, 34, 58, 48, 44, 34, 115, + 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 57, 115, 118, 110, 34, 58, 48, 44, + 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 48, 115, 118, 110, 34, 58, + 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 49, 115, 118, 110, + 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 50, 115, + 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, + 51, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, + 112, 49, 52, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, + 111, 109, 112, 49, 53, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, + 98, 99, 111, 109, 112, 49, 54, 115, 118, 110, 34, 58, 48, 44, 34, 112, 99, 101, + 115, 118, 110, 34, 58, 49, 51, 125, 44, 34, 116, 99, 98, 68, 97, 116, 101, 34, 58, + 34, 50, 48, 50, 50, 45, 49, 49, 45, 48, 57, 84, 48, 48, 58, 48, 48, 58, 48, 48, 90, + 34, 44, 34, 116, 99, 98, 83, 116, 97, 116, 117, 115, 34, 58, 34, 79, 117, 116, 79, + 102, 68, 97, 116, 101, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, + 110, 78, 101, 101, 100, 101, 100, 34, 125, 44, 123, 34, 116, 99, 98, 34, 58, 123, + 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 49, 115, 118, 110, 34, 58, + 49, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 50, 115, 118, + 110, 34, 58, 49, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 51, + 115, 118, 110, 34, 58, 50, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, + 48, 52, 115, 118, 110, 34, 58, 50, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, + 109, 112, 48, 53, 115, 118, 110, 34, 58, 50, 44, 34, 115, 103, 120, 116, 99, 98, + 99, 111, 109, 112, 48, 54, 115, 118, 110, 34, 58, 49, 44, 34, 115, 103, 120, 116, + 99, 98, 99, 111, 109, 112, 48, 55, 115, 118, 110, 34, 58, 52, 44, 34, 115, 103, + 120, 116, 99, 98, 99, 111, 109, 112, 48, 56, 115, 118, 110, 34, 58, 48, 44, 34, + 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 57, 115, 118, 110, 34, 58, 48, + 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 48, 115, 118, 110, 34, + 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 49, 115, 118, + 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 50, + 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, + 49, 51, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, + 109, 112, 49, 52, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, + 99, 111, 109, 112, 49, 53, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, + 99, 98, 99, 111, 109, 112, 49, 54, 115, 118, 110, 34, 58, 48, 44, 34, 112, 99, 101, + 115, 118, 110, 34, 58, 49, 49, 125, 44, 34, 116, 99, 98, 68, 97, 116, 101, 34, 58, + 34, 50, 48, 50, 49, 45, 49, 49, 45, 49, 48, 84, 48, 48, 58, 48, 48, 58, 48, 48, 90, + 34, 44, 34, 116, 99, 98, 83, 116, 97, 116, 117, 115, 34, 58, 34, 79, 117, 116, 79, + 102, 68, 97, 116, 101, 34, 125, 44, 123, 34, 116, 99, 98, 34, 58, 123, 34, 115, + 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 49, 115, 118, 110, 34, 58, 49, 48, + 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 50, 115, 118, 110, 34, + 58, 49, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 51, 115, + 118, 110, 34, 58, 50, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, + 52, 115, 118, 110, 34, 58, 50, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, + 112, 48, 53, 115, 118, 110, 34, 58, 50, 44, 34, 115, 103, 120, 116, 99, 98, 99, + 111, 109, 112, 48, 54, 115, 118, 110, 34, 58, 49, 44, 34, 115, 103, 120, 116, 99, + 98, 99, 111, 109, 112, 48, 55, 115, 118, 110, 34, 58, 52, 44, 34, 115, 103, 120, + 116, 99, 98, 99, 111, 109, 112, 48, 56, 115, 118, 110, 34, 58, 48, 44, 34, 115, + 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 57, 115, 118, 110, 34, 58, 48, 44, + 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 48, 115, 118, 110, 34, 58, + 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 49, 115, 118, 110, + 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 50, 115, + 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, + 51, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, + 112, 49, 52, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, + 111, 109, 112, 49, 53, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, + 98, 99, 111, 109, 112, 49, 54, 115, 118, 110, 34, 58, 48, 44, 34, 112, 99, 101, + 115, 118, 110, 34, 58, 49, 48, 125, 44, 34, 116, 99, 98, 68, 97, 116, 101, 34, 58, + 34, 50, 48, 50, 48, 45, 49, 49, 45, 49, 49, 84, 48, 48, 58, 48, 48, 58, 48, 48, 90, + 34, 44, 34, 116, 99, 98, 83, 116, 97, 116, 117, 115, 34, 58, 34, 79, 117, 116, 79, + 102, 68, 97, 116, 101, 34, 125, 44, 123, 34, 116, 99, 98, 34, 58, 123, 34, 115, + 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 49, 115, 118, 110, 34, 58, 49, 48, + 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 50, 115, 118, 110, 34, + 58, 49, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 51, 115, + 118, 110, 34, 58, 50, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, + 52, 115, 118, 110, 34, 58, 50, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, + 112, 48, 53, 115, 118, 110, 34, 58, 50, 44, 34, 115, 103, 120, 116, 99, 98, 99, + 111, 109, 112, 48, 54, 115, 118, 110, 34, 58, 49, 44, 34, 115, 103, 120, 116, 99, + 98, 99, 111, 109, 112, 48, 55, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, + 116, 99, 98, 99, 111, 109, 112, 48, 56, 115, 118, 110, 34, 58, 48, 44, 34, 115, + 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 57, 115, 118, 110, 34, 58, 48, 44, + 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 48, 115, 118, 110, 34, 58, + 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 49, 115, 118, 110, + 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 50, 115, + 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, + 51, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, + 112, 49, 52, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, + 111, 109, 112, 49, 53, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, + 98, 99, 111, 109, 112, 49, 54, 115, 118, 110, 34, 58, 48, 44, 34, 112, 99, 101, + 115, 118, 110, 34, 58, 49, 49, 125, 44, 34, 116, 99, 98, 68, 97, 116, 101, 34, 58, + 34, 50, 48, 50, 49, 45, 49, 49, 45, 49, 48, 84, 48, 48, 58, 48, 48, 58, 48, 48, 90, + 34, 44, 34, 116, 99, 98, 83, 116, 97, 116, 117, 115, 34, 58, 34, 79, 117, 116, 79, + 102, 68, 97, 116, 101, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, + 110, 78, 101, 101, 100, 101, 100, 34, 125, 44, 123, 34, 116, 99, 98, 34, 58, 123, + 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 49, 115, 118, 110, 34, 58, + 49, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 50, 115, 118, + 110, 34, 58, 49, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 51, + 115, 118, 110, 34, 58, 50, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, + 48, 52, 115, 118, 110, 34, 58, 50, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, + 109, 112, 48, 53, 115, 118, 110, 34, 58, 50, 44, 34, 115, 103, 120, 116, 99, 98, + 99, 111, 109, 112, 48, 54, 115, 118, 110, 34, 58, 49, 44, 34, 115, 103, 120, 116, + 99, 98, 99, 111, 109, 112, 48, 55, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, + 120, 116, 99, 98, 99, 111, 109, 112, 48, 56, 115, 118, 110, 34, 58, 48, 44, 34, + 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 57, 115, 118, 110, 34, 58, 48, + 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 48, 115, 118, 110, 34, + 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 49, 115, 118, + 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 50, + 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, + 49, 51, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, + 109, 112, 49, 52, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, + 99, 111, 109, 112, 49, 53, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, + 99, 98, 99, 111, 109, 112, 49, 54, 115, 118, 110, 34, 58, 48, 44, 34, 112, 99, 101, + 115, 118, 110, 34, 58, 49, 48, 125, 44, 34, 116, 99, 98, 68, 97, 116, 101, 34, 58, + 34, 50, 48, 50, 48, 45, 49, 49, 45, 49, 49, 84, 48, 48, 58, 48, 48, 58, 48, 48, 90, + 34, 44, 34, 116, 99, 98, 83, 116, 97, 116, 117, 115, 34, 58, 34, 79, 117, 116, 79, + 102, 68, 97, 116, 101, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, + 110, 78, 101, 101, 100, 101, 100, 34, 125, 44, 123, 34, 116, 99, 98, 34, 58, 123, + 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 49, 115, 118, 110, 34, 58, + 54, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 50, 115, 118, 110, + 34, 58, 54, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 51, 115, + 118, 110, 34, 58, 50, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, + 52, 115, 118, 110, 34, 58, 50, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, + 112, 48, 53, 115, 118, 110, 34, 58, 50, 44, 34, 115, 103, 120, 116, 99, 98, 99, + 111, 109, 112, 48, 54, 115, 118, 110, 34, 58, 49, 44, 34, 115, 103, 120, 116, 99, + 98, 99, 111, 109, 112, 48, 55, 115, 118, 110, 34, 58, 52, 44, 34, 115, 103, 120, + 116, 99, 98, 99, 111, 109, 112, 48, 56, 115, 118, 110, 34, 58, 48, 44, 34, 115, + 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 57, 115, 118, 110, 34, 58, 48, 44, + 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 48, 115, 118, 110, 34, 58, + 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 49, 115, 118, 110, + 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 50, 115, + 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, + 51, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, + 112, 49, 52, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, + 111, 109, 112, 49, 53, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, + 98, 99, 111, 109, 112, 49, 54, 115, 118, 110, 34, 58, 48, 44, 34, 112, 99, 101, + 115, 118, 110, 34, 58, 49, 48, 125, 44, 34, 116, 99, 98, 68, 97, 116, 101, 34, 58, + 34, 50, 48, 50, 48, 45, 48, 54, 45, 49, 48, 84, 48, 48, 58, 48, 48, 58, 48, 48, 90, + 34, 44, 34, 116, 99, 98, 83, 116, 97, 116, 117, 115, 34, 58, 34, 79, 117, 116, 79, + 102, 68, 97, 116, 101, 34, 125, 44, 123, 34, 116, 99, 98, 34, 58, 123, 34, 115, + 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 49, 115, 118, 110, 34, 58, 54, 44, + 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 50, 115, 118, 110, 34, 58, + 54, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 51, 115, 118, 110, + 34, 58, 50, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 52, 115, + 118, 110, 34, 58, 50, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, + 53, 115, 118, 110, 34, 58, 50, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, + 112, 48, 54, 115, 118, 110, 34, 58, 49, 44, 34, 115, 103, 120, 116, 99, 98, 99, + 111, 109, 112, 48, 55, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, + 98, 99, 111, 109, 112, 48, 56, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, + 116, 99, 98, 99, 111, 109, 112, 48, 57, 115, 118, 110, 34, 58, 48, 44, 34, 115, + 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 48, 115, 118, 110, 34, 58, 48, 44, + 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 49, 115, 118, 110, 34, 58, + 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 50, 115, 118, 110, + 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 51, 115, + 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, + 52, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, + 112, 49, 53, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, + 111, 109, 112, 49, 54, 115, 118, 110, 34, 58, 48, 44, 34, 112, 99, 101, 115, 118, + 110, 34, 58, 49, 48, 125, 44, 34, 116, 99, 98, 68, 97, 116, 101, 34, 58, 34, 50, + 48, 50, 48, 45, 48, 54, 45, 49, 48, 84, 48, 48, 58, 48, 48, 58, 48, 48, 90, 34, 44, + 34, 116, 99, 98, 83, 116, 97, 116, 117, 115, 34, 58, 34, 79, 117, 116, 79, 102, 68, + 97, 116, 101, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 78, + 101, 101, 100, 101, 100, 34, 125, 44, 123, 34, 116, 99, 98, 34, 58, 123, 34, 115, + 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 49, 115, 118, 110, 34, 58, 52, 44, + 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 50, 115, 118, 110, 34, 58, + 52, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 51, 115, 118, 110, + 34, 58, 50, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 52, 115, + 118, 110, 34, 58, 50, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, + 53, 115, 118, 110, 34, 58, 50, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, + 112, 48, 54, 115, 118, 110, 34, 58, 49, 44, 34, 115, 103, 120, 116, 99, 98, 99, + 111, 109, 112, 48, 55, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, + 98, 99, 111, 109, 112, 48, 56, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, + 116, 99, 98, 99, 111, 109, 112, 48, 57, 115, 118, 110, 34, 58, 48, 44, 34, 115, + 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 48, 115, 118, 110, 34, 58, 48, 44, + 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 49, 115, 118, 110, 34, 58, + 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 50, 115, 118, 110, + 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 51, 115, + 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, + 52, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, + 112, 49, 53, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, + 111, 109, 112, 49, 54, 115, 118, 110, 34, 58, 48, 44, 34, 112, 99, 101, 115, 118, + 110, 34, 58, 57, 125, 44, 34, 116, 99, 98, 68, 97, 116, 101, 34, 58, 34, 50, 48, + 49, 57, 45, 49, 49, 45, 49, 51, 84, 48, 48, 58, 48, 48, 58, 48, 48, 90, 34, 44, 34, + 116, 99, 98, 83, 116, 97, 116, 117, 115, 34, 58, 34, 79, 117, 116, 79, 102, 68, 97, + 116, 101, 34, 125, 44, 123, 34, 116, 99, 98, 34, 58, 123, 34, 115, 103, 120, 116, + 99, 98, 99, 111, 109, 112, 48, 49, 115, 118, 110, 34, 58, 49, 44, 34, 115, 103, + 120, 116, 99, 98, 99, 111, 109, 112, 48, 50, 115, 118, 110, 34, 58, 49, 44, 34, + 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 51, 115, 118, 110, 34, 58, 50, + 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 52, 115, 118, 110, 34, + 58, 50, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 53, 115, 118, + 110, 34, 58, 50, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 54, + 115, 118, 110, 34, 58, 49, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, + 48, 55, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, + 109, 112, 48, 56, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, + 99, 111, 109, 112, 48, 57, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, + 99, 98, 99, 111, 109, 112, 49, 48, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, + 120, 116, 99, 98, 99, 111, 109, 112, 49, 49, 115, 118, 110, 34, 58, 48, 44, 34, + 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 50, 115, 118, 110, 34, 58, 48, + 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 51, 115, 118, 110, 34, + 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 52, 115, 118, + 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 53, + 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, + 49, 54, 115, 118, 110, 34, 58, 48, 44, 34, 112, 99, 101, 115, 118, 110, 34, 58, 55, + 125, 44, 34, 116, 99, 98, 68, 97, 116, 101, 34, 58, 34, 50, 48, 49, 57, 45, 48, 53, + 45, 49, 53, 84, 48, 48, 58, 48, 48, 58, 48, 48, 90, 34, 44, 34, 116, 99, 98, 83, + 116, 97, 116, 117, 115, 34, 58, 34, 79, 117, 116, 79, 102, 68, 97, 116, 101, 34, + 125, 44, 123, 34, 116, 99, 98, 34, 58, 123, 34, 115, 103, 120, 116, 99, 98, 99, + 111, 109, 112, 48, 49, 115, 118, 110, 34, 58, 49, 44, 34, 115, 103, 120, 116, 99, + 98, 99, 111, 109, 112, 48, 50, 115, 118, 110, 34, 58, 49, 44, 34, 115, 103, 120, + 116, 99, 98, 99, 111, 109, 112, 48, 51, 115, 118, 110, 34, 58, 50, 44, 34, 115, + 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 52, 115, 118, 110, 34, 58, 50, 44, + 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 53, 115, 118, 110, 34, 58, + 50, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 54, 115, 118, 110, + 34, 58, 49, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, 55, 115, + 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 48, + 56, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, + 112, 48, 57, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, + 111, 109, 112, 49, 48, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, + 98, 99, 111, 109, 112, 49, 49, 115, 118, 110, 34, 58, 48, 44, 34, 115, 103, 120, + 116, 99, 98, 99, 111, 109, 112, 49, 50, 115, 118, 110, 34, 58, 48, 44, 34, 115, + 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 51, 115, 118, 110, 34, 58, 48, 44, + 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 52, 115, 118, 110, 34, 58, + 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 53, 115, 118, 110, + 34, 58, 48, 44, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 49, 54, 115, + 118, 110, 34, 58, 48, 44, 34, 112, 99, 101, 115, 118, 110, 34, 58, 54, 125, 44, 34, + 116, 99, 98, 68, 97, 116, 101, 34, 58, 34, 50, 48, 49, 56, 45, 48, 56, 45, 49, 53, + 84, 48, 48, 58, 48, 48, 58, 48, 48, 90, 34, 44, 34, 116, 99, 98, 83, 116, 97, 116, + 117, 115, 34, 58, 34, 79, 117, 116, 79, 102, 68, 97, 116, 101, 34, 125, 93, 125, + 44, 34, 115, 105, 103, 110, 97, 116, 117, 114, 101, 34, 58, 34, 99, 98, 99, 55, 50, + 51, 100, 55, 50, 102, 102, 49, 100, 54, 53, 48, 49, 101, 102, 97, 97, 52, 54, 48, + 49, 98, 98, 100, 52, 56, 100, 50, 50, 50, 98, 55, 56, 50, 52, 53, 97, 50, 100, 51, + 98, 101, 101, 55, 51, 102, 54, 54, 53, 100, 97, 97, 48, 49, 54, 56, 99, 53, 102, + 99, 56, 99, 57, 102, 54, 53, 98, 53, 99, 57, 100, 100, 101, 57, 102, 101, 56, 48, + 48, 49, 102, 100, 57, 56, 48, 55, 57, 56, 98, 101, 99, 52, 102, 97, 97, 97, 51, 53, + 54, 99, 48, 55, 53, 49, 53, 55, 55, 49, 49, 97, 98, 57, 99, 101, 100, 101, 101, 52, + 99, 51, 57, 48, 56, 101, 34, 125, 0, + ] + .into(), + qe_identity_issuer_chain: [ + 45, 45, 45, 45, 45, 66, 69, 71, 73, 78, 32, 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, + 69, 45, 45, 45, 45, 45, 10, 77, 73, 73, 67, 105, 122, 67, 67, 65, 106, 75, 103, 65, + 119, 73, 66, 65, 103, 73, 85, 102, 106, 105, 67, 49, 102, 116, 86, 75, 85, 112, 65, + 83, 89, 53, 70, 104, 65, 80, 112, 70, 74, 71, 57, 57, 70, 85, 119, 67, 103, 89, 73, + 75, 111, 90, 73, 122, 106, 48, 69, 65, 119, 73, 119, 10, 97, 68, 69, 97, 77, 66, + 103, 71, 65, 49, 85, 69, 65, 119, 119, 82, 83, 87, 53, 48, 90, 87, 119, 103, 85, + 48, 100, 89, 73, 70, 74, 118, 98, 51, 81, 103, 81, 48, 69, 120, 71, 106, 65, 89, + 66, 103, 78, 86, 66, 65, 111, 77, 69, 85, 108, 117, 100, 71, 86, 115, 73, 69, 78, + 118, 10, 99, 110, 66, 118, 99, 109, 70, 48, 97, 87, 57, 117, 77, 82, 81, 119, 69, + 103, 89, 68, 86, 81, 81, 72, 68, 65, 116, 84, 89, 87, 53, 48, 89, 83, 66, 68, 98, + 71, 70, 121, 89, 84, 69, 76, 77, 65, 107, 71, 65, 49, 85, 69, 67, 65, 119, 67, 81, + 48, 69, 120, 67, 122, 65, 74, 10, 66, 103, 78, 86, 66, 65, 89, 84, 65, 108, 86, 84, + 77, 66, 52, 88, 68, 84, 69, 52, 77, 68, 85, 121, 77, 84, 69, 119, 78, 84, 65, 120, + 77, 70, 111, 88, 68, 84, 73, 49, 77, 68, 85, 121, 77, 84, 69, 119, 78, 84, 65, 120, + 77, 70, 111, 119, 98, 68, 69, 101, 77, 66, 119, 71, 10, 65, 49, 85, 69, 65, 119, + 119, 86, 83, 87, 53, 48, 90, 87, 119, 103, 85, 48, 100, 89, 73, 70, 82, 68, 81, + 105, 66, 84, 97, 87, 100, 117, 97, 87, 53, 110, 77, 82, 111, 119, 71, 65, 89, 68, + 86, 81, 81, 75, 68, 66, 70, 74, 98, 110, 82, 108, 98, 67, 66, 68, 98, 51, 74, 119, + 10, 98, 51, 74, 104, 100, 71, 108, 118, 98, 106, 69, 85, 77, 66, 73, 71, 65, 49, + 85, 69, 66, 119, 119, 76, 85, 50, 70, 117, 100, 71, 69, 103, 81, 50, 120, 104, 99, + 109, 69, 120, 67, 122, 65, 74, 66, 103, 78, 86, 66, 65, 103, 77, 65, 107, 78, 66, + 77, 81, 115, 119, 67, 81, 89, 68, 10, 86, 81, 81, 71, 69, 119, 74, 86, 85, 122, 66, + 90, 77, 66, 77, 71, 66, 121, 113, 71, 83, 77, 52, 57, 65, 103, 69, 71, 67, 67, 113, + 71, 83, 77, 52, 57, 65, 119, 69, 72, 65, 48, 73, 65, 66, 69, 78, 70, 71, 56, 120, + 122, 121, 100, 87, 82, 102, 75, 57, 50, 98, 109, 71, 118, 10, 80, 43, 109, 65, 104, + 57, 49, 80, 69, 121, 86, 55, 74, 104, 54, 70, 71, 74, 100, 53, 110, 100, 69, 57, + 97, 66, 72, 55, 82, 51, 69, 52, 65, 55, 117, 98, 114, 108, 104, 47, 122, 78, 51, + 67, 52, 120, 118, 112, 111, 111, 117, 71, 108, 105, 114, 77, 98, 97, 43, 87, 50, + 108, 106, 117, 10, 121, 112, 97, 106, 103, 98, 85, 119, 103, 98, 73, 119, 72, 119, + 89, 68, 86, 82, 48, 106, 66, 66, 103, 119, 70, 111, 65, 85, 73, 109, 85, 77, 49, + 108, 113, 100, 78, 73, 110, 122, 103, 55, 83, 86, 85, 114, 57, 81, 71, 122, 107, + 110, 66, 113, 119, 119, 85, 103, 89, 68, 86, 82, 48, 102, 10, 66, 69, 115, 119, 83, + 84, 66, 72, 111, 69, 87, 103, 81, 52, 90, 66, 97, 72, 82, 48, 99, 72, 77, 54, 76, + 121, 57, 106, 90, 88, 74, 48, 97, 87, 90, 112, 89, 50, 70, 48, 90, 88, 77, 117, + 100, 72, 74, 49, 99, 51, 82, 108, 90, 72, 78, 108, 99, 110, 90, 112, 89, 50, 86, + 122, 10, 76, 109, 108, 117, 100, 71, 86, 115, 76, 109, 78, 118, 98, 83, 57, 74, 98, + 110, 82, 108, 98, 70, 78, 72, 87, 70, 74, 118, 98, 51, 82, 68, 81, 83, 53, 107, 90, + 88, 73, 119, 72, 81, 89, 68, 86, 82, 48, 79, 66, 66, 89, 69, 70, 72, 52, 52, 103, + 116, 88, 55, 86, 83, 108, 75, 10, 81, 69, 109, 79, 82, 89, 81, 68, 54, 82, 83, 82, + 118, 102, 82, 86, 77, 65, 52, 71, 65, 49, 85, 100, 68, 119, 69, 66, 47, 119, 81, + 69, 65, 119, 73, 71, 119, 68, 65, 77, 66, 103, 78, 86, 72, 82, 77, 66, 65, 102, 56, + 69, 65, 106, 65, 65, 77, 65, 111, 71, 67, 67, 113, 71, 10, 83, 77, 52, 57, 66, 65, + 77, 67, 65, 48, 99, 65, 77, 69, 81, 67, 73, 66, 57, 67, 56, 119, 79, 65, 78, 47, + 73, 109, 120, 68, 116, 71, 65, 67, 86, 50, 52, 54, 75, 99, 113, 106, 97, 103, 90, + 79, 82, 48, 107, 121, 99, 116, 121, 66, 114, 115, 71, 71, 74, 86, 65, 105, 65, 106, + 10, 102, 116, 98, 114, 78, 71, 115, 71, 85, 56, 89, 72, 50, 49, 49, 100, 82, 105, + 89, 78, 111, 80, 80, 117, 49, 57, 90, 112, 47, 122, 101, 56, 74, 109, 104, 117, + 106, 66, 48, 111, 66, 119, 61, 61, 10, 45, 45, 45, 45, 45, 69, 78, 68, 32, 67, 69, + 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, 10, 45, 45, 45, 45, 45, 66, + 69, 71, 73, 78, 32, 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, + 10, 77, 73, 73, 67, 106, 122, 67, 67, 65, 106, 83, 103, 65, 119, 73, 66, 65, 103, + 73, 85, 73, 109, 85, 77, 49, 108, 113, 100, 78, 73, 110, 122, 103, 55, 83, 86, 85, + 114, 57, 81, 71, 122, 107, 110, 66, 113, 119, 119, 67, 103, 89, 73, 75, 111, 90, + 73, 122, 106, 48, 69, 65, 119, 73, 119, 10, 97, 68, 69, 97, 77, 66, 103, 71, 65, + 49, 85, 69, 65, 119, 119, 82, 83, 87, 53, 48, 90, 87, 119, 103, 85, 48, 100, 89, + 73, 70, 74, 118, 98, 51, 81, 103, 81, 48, 69, 120, 71, 106, 65, 89, 66, 103, 78, + 86, 66, 65, 111, 77, 69, 85, 108, 117, 100, 71, 86, 115, 73, 69, 78, 118, 10, 99, + 110, 66, 118, 99, 109, 70, 48, 97, 87, 57, 117, 77, 82, 81, 119, 69, 103, 89, 68, + 86, 81, 81, 72, 68, 65, 116, 84, 89, 87, 53, 48, 89, 83, 66, 68, 98, 71, 70, 121, + 89, 84, 69, 76, 77, 65, 107, 71, 65, 49, 85, 69, 67, 65, 119, 67, 81, 48, 69, 120, + 67, 122, 65, 74, 10, 66, 103, 78, 86, 66, 65, 89, 84, 65, 108, 86, 84, 77, 66, 52, + 88, 68, 84, 69, 52, 77, 68, 85, 121, 77, 84, 69, 119, 78, 68, 85, 120, 77, 70, 111, + 88, 68, 84, 81, 53, 77, 84, 73, 122, 77, 84, 73, 122, 78, 84, 107, 49, 79, 86, 111, + 119, 97, 68, 69, 97, 77, 66, 103, 71, 10, 65, 49, 85, 69, 65, 119, 119, 82, 83, 87, + 53, 48, 90, 87, 119, 103, 85, 48, 100, 89, 73, 70, 74, 118, 98, 51, 81, 103, 81, + 48, 69, 120, 71, 106, 65, 89, 66, 103, 78, 86, 66, 65, 111, 77, 69, 85, 108, 117, + 100, 71, 86, 115, 73, 69, 78, 118, 99, 110, 66, 118, 99, 109, 70, 48, 10, 97, 87, + 57, 117, 77, 82, 81, 119, 69, 103, 89, 68, 86, 81, 81, 72, 68, 65, 116, 84, 89, 87, + 53, 48, 89, 83, 66, 68, 98, 71, 70, 121, 89, 84, 69, 76, 77, 65, 107, 71, 65, 49, + 85, 69, 67, 65, 119, 67, 81, 48, 69, 120, 67, 122, 65, 74, 66, 103, 78, 86, 66, 65, + 89, 84, 10, 65, 108, 86, 84, 77, 70, 107, 119, 69, 119, 89, 72, 75, 111, 90, 73, + 122, 106, 48, 67, 65, 81, 89, 73, 75, 111, 90, 73, 122, 106, 48, 68, 65, 81, 99, + 68, 81, 103, 65, 69, 67, 54, 110, 69, 119, 77, 68, 73, 89, 90, 79, 106, 47, 105, + 80, 87, 115, 67, 122, 97, 69, 75, 105, 55, 10, 49, 79, 105, 79, 83, 76, 82, 70, + 104, 87, 71, 106, 98, 110, 66, 86, 74, 102, 86, 110, 107, 89, 52, 117, 51, 73, 106, + 107, 68, 89, 89, 76, 48, 77, 120, 79, 52, 109, 113, 115, 121, 89, 106, 108, 66, 97, + 108, 84, 86, 89, 120, 70, 80, 50, 115, 74, 66, 75, 53, 122, 108, 75, 79, 66, 10, + 117, 122, 67, 66, 117, 68, 65, 102, 66, 103, 78, 86, 72, 83, 77, 69, 71, 68, 65, + 87, 103, 66, 81, 105, 90, 81, 122, 87, 87, 112, 48, 48, 105, 102, 79, 68, 116, 74, + 86, 83, 118, 49, 65, 98, 79, 83, 99, 71, 114, 68, 66, 83, 66, 103, 78, 86, 72, 82, + 56, 69, 83, 122, 66, 74, 10, 77, 69, 101, 103, 82, 97, 66, 68, 104, 107, 70, 111, + 100, 72, 82, 119, 99, 122, 111, 118, 76, 50, 78, 108, 99, 110, 82, 112, 90, 109, + 108, 106, 89, 88, 82, 108, 99, 121, 53, 48, 99, 110, 86, 122, 100, 71, 86, 107, 99, + 50, 86, 121, 100, 109, 108, 106, 90, 88, 77, 117, 97, 87, 53, 48, 10, 90, 87, 119, + 117, 89, 50, 57, 116, 76, 48, 108, 117, 100, 71, 86, 115, 85, 48, 100, 89, 85, 109, + 57, 118, 100, 69, 78, 66, 76, 109, 82, 108, 99, 106, 65, 100, 66, 103, 78, 86, 72, + 81, 52, 69, 70, 103, 81, 85, 73, 109, 85, 77, 49, 108, 113, 100, 78, 73, 110, 122, + 103, 55, 83, 86, 10, 85, 114, 57, 81, 71, 122, 107, 110, 66, 113, 119, 119, 68, + 103, 89, 68, 86, 82, 48, 80, 65, 81, 72, 47, 66, 65, 81, 68, 65, 103, 69, 71, 77, + 66, 73, 71, 65, 49, 85, 100, 69, 119, 69, 66, 47, 119, 81, 73, 77, 65, 89, 66, 65, + 102, 56, 67, 65, 81, 69, 119, 67, 103, 89, 73, 10, 75, 111, 90, 73, 122, 106, 48, + 69, 65, 119, 73, 68, 83, 81, 65, 119, 82, 103, 73, 104, 65, 79, 87, 47, 53, 81, + 107, 82, 43, 83, 57, 67, 105, 83, 68, 99, 78, 111, 111, 119, 76, 117, 80, 82, 76, + 115, 87, 71, 102, 47, 89, 105, 55, 71, 83, 88, 57, 52, 66, 103, 119, 84, 119, 103, + 10, 65, 105, 69, 65, 52, 74, 48, 108, 114, 72, 111, 77, 115, 43, 88, 111, 53, 111, + 47, 115, 88, 54, 79, 57, 81, 87, 120, 72, 82, 65, 118, 90, 85, 71, 79, 100, 82, 81, + 55, 99, 118, 113, 82, 88, 97, 113, 73, 61, 10, 45, 45, 45, 45, 45, 69, 78, 68, 32, + 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, 10, 0, + ] + .into(), + qe_identity: [ + 123, 34, 101, 110, 99, 108, 97, 118, 101, 73, 100, 101, 110, 116, 105, 116, 121, + 34, 58, 123, 34, 105, 100, 34, 58, 34, 81, 69, 34, 44, 34, 118, 101, 114, 115, 105, + 111, 110, 34, 58, 50, 44, 34, 105, 115, 115, 117, 101, 68, 97, 116, 101, 34, 58, + 34, 50, 48, 50, 51, 45, 48, 53, 45, 48, 57, 84, 49, 49, 58, 52, 55, 58, 48, 56, 90, + 34, 44, 34, 110, 101, 120, 116, 85, 112, 100, 97, 116, 101, 34, 58, 34, 50, 48, 50, + 51, 45, 48, 54, 45, 48, 56, 84, 49, 49, 58, 52, 55, 58, 48, 56, 90, 34, 44, 34, + 116, 99, 98, 69, 118, 97, 108, 117, 97, 116, 105, 111, 110, 68, 97, 116, 97, 78, + 117, 109, 98, 101, 114, 34, 58, 49, 53, 44, 34, 109, 105, 115, 99, 115, 101, 108, + 101, 99, 116, 34, 58, 34, 48, 48, 48, 48, 48, 48, 48, 48, 34, 44, 34, 109, 105, + 115, 99, 115, 101, 108, 101, 99, 116, 77, 97, 115, 107, 34, 58, 34, 70, 70, 70, 70, + 70, 70, 70, 70, 34, 44, 34, 97, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 58, + 34, 49, 49, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 34, 44, 34, 97, 116, 116, 114, 105, + 98, 117, 116, 101, 115, 77, 97, 115, 107, 34, 58, 34, 70, 66, 70, 70, 70, 70, 70, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 34, 44, 34, 109, 114, 115, 105, 103, 110, 101, 114, 34, 58, 34, 56, + 67, 52, 70, 53, 55, 55, 53, 68, 55, 57, 54, 53, 48, 51, 69, 57, 54, 49, 51, 55, 70, + 55, 55, 67, 54, 56, 65, 56, 50, 57, 65, 48, 48, 53, 54, 65, 67, 56, 68, 69, 68, 55, + 48, 49, 52, 48, 66, 48, 56, 49, 66, 48, 57, 52, 52, 57, 48, 67, 53, 55, 66, 70, 70, + 34, 44, 34, 105, 115, 118, 112, 114, 111, 100, 105, 100, 34, 58, 49, 44, 34, 116, + 99, 98, 76, 101, 118, 101, 108, 115, 34, 58, 91, 123, 34, 116, 99, 98, 34, 58, 123, + 34, 105, 115, 118, 115, 118, 110, 34, 58, 56, 125, 44, 34, 116, 99, 98, 68, 97, + 116, 101, 34, 58, 34, 50, 48, 50, 51, 45, 48, 50, 45, 49, 53, 84, 48, 48, 58, 48, + 48, 58, 48, 48, 90, 34, 44, 34, 116, 99, 98, 83, 116, 97, 116, 117, 115, 34, 58, + 34, 85, 112, 84, 111, 68, 97, 116, 101, 34, 125, 44, 123, 34, 116, 99, 98, 34, 58, + 123, 34, 105, 115, 118, 115, 118, 110, 34, 58, 54, 125, 44, 34, 116, 99, 98, 68, + 97, 116, 101, 34, 58, 34, 50, 48, 50, 49, 45, 49, 49, 45, 49, 48, 84, 48, 48, 58, + 48, 48, 58, 48, 48, 90, 34, 44, 34, 116, 99, 98, 83, 116, 97, 116, 117, 115, 34, + 58, 34, 79, 117, 116, 79, 102, 68, 97, 116, 101, 34, 125, 44, 123, 34, 116, 99, 98, + 34, 58, 123, 34, 105, 115, 118, 115, 118, 110, 34, 58, 53, 125, 44, 34, 116, 99, + 98, 68, 97, 116, 101, 34, 58, 34, 50, 48, 50, 48, 45, 49, 49, 45, 49, 49, 84, 48, + 48, 58, 48, 48, 58, 48, 48, 90, 34, 44, 34, 116, 99, 98, 83, 116, 97, 116, 117, + 115, 34, 58, 34, 79, 117, 116, 79, 102, 68, 97, 116, 101, 34, 125, 44, 123, 34, + 116, 99, 98, 34, 58, 123, 34, 105, 115, 118, 115, 118, 110, 34, 58, 52, 125, 44, + 34, 116, 99, 98, 68, 97, 116, 101, 34, 58, 34, 50, 48, 49, 57, 45, 49, 49, 45, 49, + 51, 84, 48, 48, 58, 48, 48, 58, 48, 48, 90, 34, 44, 34, 116, 99, 98, 83, 116, 97, + 116, 117, 115, 34, 58, 34, 79, 117, 116, 79, 102, 68, 97, 116, 101, 34, 125, 44, + 123, 34, 116, 99, 98, 34, 58, 123, 34, 105, 115, 118, 115, 118, 110, 34, 58, 50, + 125, 44, 34, 116, 99, 98, 68, 97, 116, 101, 34, 58, 34, 50, 48, 49, 57, 45, 48, 53, + 45, 49, 53, 84, 48, 48, 58, 48, 48, 58, 48, 48, 90, 34, 44, 34, 116, 99, 98, 83, + 116, 97, 116, 117, 115, 34, 58, 34, 79, 117, 116, 79, 102, 68, 97, 116, 101, 34, + 125, 44, 123, 34, 116, 99, 98, 34, 58, 123, 34, 105, 115, 118, 115, 118, 110, 34, + 58, 49, 125, 44, 34, 116, 99, 98, 68, 97, 116, 101, 34, 58, 34, 50, 48, 49, 56, 45, + 48, 56, 45, 49, 53, 84, 48, 48, 58, 48, 48, 58, 48, 48, 90, 34, 44, 34, 116, 99, + 98, 83, 116, 97, 116, 117, 115, 34, 58, 34, 79, 117, 116, 79, 102, 68, 97, 116, + 101, 34, 125, 93, 125, 44, 34, 115, 105, 103, 110, 97, 116, 117, 114, 101, 34, 58, + 34, 51, 53, 98, 102, 56, 48, 100, 49, 53, 57, 53, 97, 53, 54, 56, 99, 102, 51, 101, + 102, 51, 101, 102, 56, 100, 97, 55, 100, 49, 50, 97, 51, 53, 100, 49, 97, 101, 101, + 102, 102, 98, 55, 102, 50, 52, 57, 48, 55, 98, 55, 54, 53, 50, 57, 48, 97, 99, 52, + 55, 100, 100, 57, 97, 53, 56, 102, 54, 55, 53, 51, 52, 98, 56, 50, 101, 56, 100, + 102, 102, 99, 52, 98, 99, 48, 100, 100, 99, 51, 54, 53, 50, 99, 51, 49, 102, 50, + 102, 100, 54, 57, 97, 99, 52, 52, 55, 102, 56, 52, 49, 52, 97, 49, 99, 48, 50, 99, + 54, 99, 49, 101, 53, 50, 102, 56, 53, 57, 48, 51, 34, 125, 0, + ] + .into(), + }; + + let current_time = 1684165303; + + let report_data = [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + ]; + + let mrsigner = + hex::decode("298037d88782e022e019b3020745b78aa40ed95c77da4bf7f3253d3a44c4fd7e") + .unwrap(); + + check_quote( + "e, + &collateral, + current_time, + &mrsigner, + &report_data, + sgx_ql_qv_result_t::SGX_QL_QV_RESULT_OUT_OF_DATE, + ) + .unwrap(); + } + + #[test] + fn azure() { + std::env::set_var("AZDCAP_DEBUG_LOG_LEVEL", "ignore"); + std::env::set_var("AZDCAP_COLLATERAL_VERSION", "v4"); + + let quote = [ + 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x00, 0x0e, 0x00, 0x93, 0x9a, + 0x72, 0x33, 0xf7, 0x9c, 0x4c, 0xa9, 0x94, 0x0a, 0x0d, 0xb3, 0x95, 0x7f, 0x06, 0x07, + 0x1a, 0x24, 0xf2, 0x9c, 0x17, 0x78, 0x4f, 0x6a, 0x1b, 0xac, 0xff, 0x9b, 0x40, 0xc2, + 0x5f, 0x58, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x0b, 0x10, 0x0f, 0xff, 0xff, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x64, 0xd0, 0xe3, 0xeb, 0xfb, 0xb9, 0x8f, 0xd0, 0x61, 0xac, 0x2e, 0x9d, 0x21, 0x97, + 0x78, 0x0f, 0x81, 0x9c, 0x91, 0x72, 0xce, 0xef, 0xf4, 0xb3, 0x13, 0x0d, 0x72, 0x47, + 0xa6, 0x42, 0x1a, 0xd2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x80, 0x37, 0xd8, 0x87, 0x82, + 0xe0, 0x22, 0xe0, 0x19, 0xb3, 0x02, 0x07, 0x45, 0xb7, 0x8a, 0xa4, 0x0e, 0xd9, 0x5c, + 0x77, 0xda, 0x4b, 0xf7, 0xf3, 0x25, 0x3d, 0x3a, 0x44, 0xc4, 0xfd, 0x7e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, + 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0xca, 0x10, + 0x00, 0x00, 0x4d, 0xce, 0x39, 0x7e, 0x12, 0x4f, 0xd5, 0x09, 0xb6, 0x2b, 0x47, 0x97, + 0x79, 0xa8, 0x78, 0xae, 0xfe, 0x3a, 0x45, 0x42, 0x98, 0x74, 0x36, 0x06, 0xd6, 0x9e, + 0xf4, 0xce, 0x7c, 0x17, 0x67, 0xeb, 0x5a, 0xdf, 0x43, 0x3b, 0x11, 0x13, 0x40, 0x8a, + 0xa6, 0xaf, 0xb2, 0xa5, 0xd1, 0xa4, 0xd9, 0xaa, 0xa3, 0xd2, 0x40, 0x88, 0xc5, 0x50, + 0xa1, 0x4b, 0x04, 0xfc, 0x52, 0x05, 0x10, 0x2c, 0x97, 0xe7, 0x36, 0x40, 0xd7, 0x3d, + 0x6b, 0x83, 0xf0, 0xc4, 0xe1, 0x34, 0x2b, 0x4b, 0x36, 0x24, 0xba, 0x11, 0xf3, 0x51, + 0x92, 0x24, 0x59, 0x50, 0x5e, 0x54, 0xc0, 0x51, 0x59, 0xc9, 0x5d, 0x3a, 0xae, 0x00, + 0xa2, 0x3e, 0x46, 0xe0, 0x34, 0xfd, 0xee, 0x89, 0xb3, 0x85, 0xb7, 0x9f, 0xe2, 0x12, + 0xa5, 0x74, 0xea, 0x00, 0xbd, 0x8f, 0xae, 0xe2, 0xbb, 0x0c, 0x73, 0x22, 0x71, 0xc7, + 0x15, 0xad, 0x82, 0xea, 0x0b, 0x0b, 0x10, 0x0f, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x2a, + 0xa5, 0x0c, 0xe1, 0xc0, 0xce, 0xf0, 0x3c, 0xcf, 0x89, 0xe7, 0xb5, 0xb1, 0x6b, 0x0d, + 0x79, 0x78, 0xf5, 0xc2, 0xb1, 0xed, 0xcf, 0x77, 0x4d, 0x87, 0x70, 0x2e, 0x81, 0x54, + 0xd8, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x4f, 0x57, 0x75, 0xd7, 0x96, 0x50, 0x3e, + 0x96, 0x13, 0x7f, 0x77, 0xc6, 0x8a, 0x82, 0x9a, 0x00, 0x56, 0xac, 0x8d, 0xed, 0x70, + 0x14, 0x0b, 0x08, 0x1b, 0x09, 0x44, 0x90, 0xc5, 0x7b, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x09, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x71, 0x4e, 0x58, 0xe9, 0x48, 0x14, 0x59, 0x70, 0x69, 0x71, 0x4b, 0x5e, + 0x68, 0x78, 0xfb, 0x3a, 0xcf, 0x58, 0x32, 0xaa, 0xf9, 0x6d, 0x30, 0xa0, 0x45, 0x5d, + 0x78, 0xa4, 0xd9, 0xae, 0xd2, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe4, 0x63, 0x7f, 0x0b, + 0x53, 0xdd, 0x15, 0xdd, 0x0d, 0xfd, 0x3e, 0x70, 0x16, 0x0a, 0x70, 0x62, 0x67, 0x25, + 0xd0, 0x3c, 0x9e, 0x1c, 0x4a, 0x63, 0x6e, 0x8d, 0xb4, 0xfd, 0x52, 0xe1, 0x41, 0xb9, + 0x74, 0xf7, 0x9b, 0x34, 0x65, 0xb4, 0x5f, 0xfd, 0x51, 0xbd, 0x4f, 0x92, 0xdf, 0x66, + 0xd3, 0x05, 0xf3, 0x88, 0x9f, 0xb5, 0x50, 0xb0, 0x97, 0x1e, 0xc8, 0xb9, 0x0e, 0x0c, + 0x08, 0x1d, 0x65, 0xa1, 0x20, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x05, 0x00, 0x62, 0x0e, + 0x00, 0x00, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, + 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x45, 0x38, 0x6a, 0x43, 0x43, 0x42, 0x4a, 0x69, 0x67, + 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x55, 0x57, 0x30, 0x71, 0x70, 0x4d, 0x78, + 0x45, 0x37, 0x52, 0x37, 0x69, 0x75, 0x30, 0x4b, 0x39, 0x38, 0x62, 0x55, 0x6a, 0x37, + 0x66, 0x4b, 0x73, 0x66, 0x75, 0x71, 0x63, 0x77, 0x43, 0x67, 0x59, 0x49, 0x4b, 0x6f, + 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x45, 0x41, 0x77, 0x49, 0x77, 0x0a, 0x63, 0x44, 0x45, + 0x69, 0x4d, 0x43, 0x41, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, 0x77, 0x5a, 0x53, + 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, 0x67, 0x55, 0x30, 0x64, 0x59, 0x49, 0x46, 0x42, + 0x44, 0x53, 0x79, 0x42, 0x51, 0x62, 0x47, 0x46, 0x30, 0x5a, 0x6d, 0x39, 0x79, 0x62, + 0x53, 0x42, 0x44, 0x51, 0x54, 0x45, 0x61, 0x4d, 0x42, 0x67, 0x47, 0x41, 0x31, 0x55, + 0x45, 0x43, 0x67, 0x77, 0x52, 0x0a, 0x53, 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, 0x67, + 0x51, 0x32, 0x39, 0x79, 0x63, 0x47, 0x39, 0x79, 0x59, 0x58, 0x52, 0x70, 0x62, 0x32, + 0x34, 0x78, 0x46, 0x44, 0x41, 0x53, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x63, 0x4d, + 0x43, 0x31, 0x4e, 0x68, 0x62, 0x6e, 0x52, 0x68, 0x49, 0x45, 0x4e, 0x73, 0x59, 0x58, + 0x4a, 0x68, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x49, + 0x0a, 0x44, 0x41, 0x4a, 0x44, 0x51, 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, + 0x31, 0x55, 0x45, 0x42, 0x68, 0x4d, 0x43, 0x56, 0x56, 0x4d, 0x77, 0x48, 0x68, 0x63, + 0x4e, 0x4d, 0x6a, 0x4d, 0x77, 0x4e, 0x44, 0x41, 0x79, 0x4d, 0x54, 0x63, 0x79, 0x4d, + 0x54, 0x45, 0x35, 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x7a, 0x41, 0x77, 0x4e, 0x44, 0x41, + 0x79, 0x4d, 0x54, 0x63, 0x79, 0x4d, 0x54, 0x45, 0x35, 0x0a, 0x57, 0x6a, 0x42, 0x77, + 0x4d, 0x53, 0x49, 0x77, 0x49, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x44, 0x42, + 0x6c, 0x4a, 0x62, 0x6e, 0x52, 0x6c, 0x62, 0x43, 0x42, 0x54, 0x52, 0x31, 0x67, 0x67, + 0x55, 0x45, 0x4e, 0x4c, 0x49, 0x45, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, + 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x6c, 0x4d, 0x52, 0x6f, 0x77, 0x47, 0x41, 0x59, 0x44, + 0x56, 0x51, 0x51, 0x4b, 0x0a, 0x44, 0x42, 0x46, 0x4a, 0x62, 0x6e, 0x52, 0x6c, 0x62, + 0x43, 0x42, 0x44, 0x62, 0x33, 0x4a, 0x77, 0x62, 0x33, 0x4a, 0x68, 0x64, 0x47, 0x6c, + 0x76, 0x62, 0x6a, 0x45, 0x55, 0x4d, 0x42, 0x49, 0x47, 0x41, 0x31, 0x55, 0x45, 0x42, + 0x77, 0x77, 0x4c, 0x55, 0x32, 0x46, 0x75, 0x64, 0x47, 0x45, 0x67, 0x51, 0x32, 0x78, + 0x68, 0x63, 0x6d, 0x45, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x0a, + 0x42, 0x41, 0x67, 0x4d, 0x41, 0x6b, 0x4e, 0x42, 0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, + 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, 0x42, 0x5a, + 0x4d, 0x42, 0x4d, 0x47, 0x42, 0x79, 0x71, 0x47, 0x53, 0x4d, 0x34, 0x39, 0x41, 0x67, + 0x45, 0x47, 0x43, 0x43, 0x71, 0x47, 0x53, 0x4d, 0x34, 0x39, 0x41, 0x77, 0x45, 0x48, + 0x41, 0x30, 0x49, 0x41, 0x42, 0x45, 0x37, 0x45, 0x0a, 0x46, 0x50, 0x4d, 0x68, 0x61, + 0x55, 0x47, 0x45, 0x57, 0x6b, 0x68, 0x6b, 0x4f, 0x43, 0x78, 0x36, 0x51, 0x4c, 0x63, + 0x75, 0x71, 0x72, 0x56, 0x45, 0x32, 0x55, 0x6b, 0x62, 0x36, 0x31, 0x2f, 0x6d, 0x62, + 0x6d, 0x54, 0x66, 0x47, 0x33, 0x64, 0x69, 0x43, 0x62, 0x68, 0x56, 0x77, 0x4c, 0x38, + 0x49, 0x79, 0x4b, 0x73, 0x31, 0x33, 0x46, 0x75, 0x6b, 0x50, 0x52, 0x59, 0x58, 0x2b, + 0x64, 0x70, 0x79, 0x0a, 0x7a, 0x38, 0x6a, 0x7a, 0x76, 0x36, 0x58, 0x4a, 0x6e, 0x67, + 0x76, 0x47, 0x4c, 0x51, 0x41, 0x70, 0x37, 0x59, 0x65, 0x6a, 0x67, 0x67, 0x4d, 0x4f, + 0x4d, 0x49, 0x49, 0x44, 0x43, 0x6a, 0x41, 0x66, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x53, + 0x4d, 0x45, 0x47, 0x44, 0x41, 0x57, 0x67, 0x42, 0x53, 0x56, 0x62, 0x31, 0x33, 0x4e, + 0x76, 0x52, 0x76, 0x68, 0x36, 0x55, 0x42, 0x4a, 0x79, 0x64, 0x54, 0x30, 0x0a, 0x4d, + 0x38, 0x34, 0x42, 0x56, 0x77, 0x76, 0x65, 0x56, 0x44, 0x42, 0x72, 0x42, 0x67, 0x4e, + 0x56, 0x48, 0x52, 0x38, 0x45, 0x5a, 0x44, 0x42, 0x69, 0x4d, 0x47, 0x43, 0x67, 0x58, + 0x71, 0x42, 0x63, 0x68, 0x6c, 0x70, 0x6f, 0x64, 0x48, 0x52, 0x77, 0x63, 0x7a, 0x6f, + 0x76, 0x4c, 0x32, 0x46, 0x77, 0x61, 0x53, 0x35, 0x30, 0x63, 0x6e, 0x56, 0x7a, 0x64, + 0x47, 0x56, 0x6b, 0x63, 0x32, 0x56, 0x79, 0x0a, 0x64, 0x6d, 0x6c, 0x6a, 0x5a, 0x58, + 0x4d, 0x75, 0x61, 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, 0x75, 0x59, 0x32, 0x39, 0x74, + 0x4c, 0x33, 0x4e, 0x6e, 0x65, 0x43, 0x39, 0x6a, 0x5a, 0x58, 0x4a, 0x30, 0x61, 0x57, + 0x5a, 0x70, 0x59, 0x32, 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x4c, 0x33, 0x59, 0x7a, + 0x4c, 0x33, 0x42, 0x6a, 0x61, 0x32, 0x4e, 0x79, 0x62, 0x44, 0x39, 0x6a, 0x59, 0x54, + 0x31, 0x77, 0x0a, 0x62, 0x47, 0x46, 0x30, 0x5a, 0x6d, 0x39, 0x79, 0x62, 0x53, 0x5a, + 0x6c, 0x62, 0x6d, 0x4e, 0x76, 0x5a, 0x47, 0x6c, 0x75, 0x5a, 0x7a, 0x31, 0x6b, 0x5a, + 0x58, 0x49, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, 0x30, 0x4f, 0x42, 0x42, 0x59, + 0x45, 0x46, 0x41, 0x48, 0x70, 0x48, 0x38, 0x49, 0x61, 0x72, 0x51, 0x76, 0x79, 0x51, + 0x39, 0x67, 0x6d, 0x53, 0x70, 0x59, 0x35, 0x4d, 0x30, 0x49, 0x59, 0x0a, 0x4c, 0x53, + 0x34, 0x71, 0x4d, 0x41, 0x34, 0x47, 0x41, 0x31, 0x55, 0x64, 0x44, 0x77, 0x45, 0x42, + 0x2f, 0x77, 0x51, 0x45, 0x41, 0x77, 0x49, 0x47, 0x77, 0x44, 0x41, 0x4d, 0x42, 0x67, + 0x4e, 0x56, 0x48, 0x52, 0x4d, 0x42, 0x41, 0x66, 0x38, 0x45, 0x41, 0x6a, 0x41, 0x41, + 0x4d, 0x49, 0x49, 0x43, 0x4f, 0x77, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, + 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x0a, 0x42, 0x49, 0x49, 0x43, 0x4c, 0x44, 0x43, + 0x43, 0x41, 0x69, 0x67, 0x77, 0x48, 0x67, 0x59, 0x4b, 0x4b, 0x6f, 0x5a, 0x49, 0x68, + 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x51, 0x51, 0x51, 0x57, 0x6f, 0x72, + 0x76, 0x4e, 0x78, 0x69, 0x57, 0x62, 0x65, 0x49, 0x32, 0x70, 0x6e, 0x62, 0x53, 0x77, + 0x61, 0x6e, 0x6f, 0x78, 0x44, 0x43, 0x43, 0x41, 0x57, 0x55, 0x47, 0x43, 0x69, 0x71, + 0x47, 0x0a, 0x53, 0x49, 0x62, 0x34, 0x54, 0x51, 0x45, 0x4e, 0x41, 0x51, 0x49, 0x77, + 0x67, 0x67, 0x46, 0x56, 0x4d, 0x42, 0x41, 0x47, 0x43, 0x79, 0x71, 0x47, 0x53, 0x49, + 0x62, 0x34, 0x54, 0x51, 0x45, 0x4e, 0x41, 0x51, 0x49, 0x42, 0x41, 0x67, 0x45, 0x4c, + 0x4d, 0x42, 0x41, 0x47, 0x43, 0x79, 0x71, 0x47, 0x53, 0x49, 0x62, 0x34, 0x54, 0x51, + 0x45, 0x4e, 0x41, 0x51, 0x49, 0x43, 0x41, 0x67, 0x45, 0x4c, 0x0a, 0x4d, 0x42, 0x41, + 0x47, 0x43, 0x79, 0x71, 0x47, 0x53, 0x49, 0x62, 0x34, 0x54, 0x51, 0x45, 0x4e, 0x41, + 0x51, 0x49, 0x44, 0x41, 0x67, 0x45, 0x44, 0x4d, 0x42, 0x41, 0x47, 0x43, 0x79, 0x71, + 0x47, 0x53, 0x49, 0x62, 0x34, 0x54, 0x51, 0x45, 0x4e, 0x41, 0x51, 0x49, 0x45, 0x41, + 0x67, 0x45, 0x44, 0x4d, 0x42, 0x45, 0x47, 0x43, 0x79, 0x71, 0x47, 0x53, 0x49, 0x62, + 0x34, 0x54, 0x51, 0x45, 0x4e, 0x0a, 0x41, 0x51, 0x49, 0x46, 0x41, 0x67, 0x49, 0x41, + 0x2f, 0x7a, 0x41, 0x52, 0x42, 0x67, 0x73, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x2b, 0x45, + 0x30, 0x42, 0x44, 0x51, 0x45, 0x43, 0x42, 0x67, 0x49, 0x43, 0x41, 0x50, 0x38, 0x77, + 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, + 0x30, 0x42, 0x41, 0x67, 0x63, 0x43, 0x41, 0x51, 0x45, 0x77, 0x45, 0x41, 0x59, 0x4c, + 0x0a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, + 0x67, 0x67, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, + 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, 0x6b, 0x43, 0x41, + 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, + 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, 0x6f, 0x43, 0x0a, 0x41, 0x51, 0x41, 0x77, + 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, + 0x30, 0x42, 0x41, 0x67, 0x73, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, + 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, + 0x77, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, + 0x68, 0x76, 0x68, 0x4e, 0x0a, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, 0x30, 0x43, 0x41, + 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, + 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x67, 0x34, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, + 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, + 0x42, 0x41, 0x67, 0x38, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x0a, + 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x68, + 0x41, 0x43, 0x41, 0x51, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, + 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x68, 0x45, 0x43, 0x41, 0x51, + 0x30, 0x77, 0x48, 0x77, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, + 0x41, 0x51, 0x30, 0x42, 0x41, 0x68, 0x49, 0x45, 0x0a, 0x45, 0x41, 0x73, 0x4c, 0x41, + 0x77, 0x50, 0x2f, 0x2f, 0x77, 0x45, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x77, 0x45, 0x41, 0x59, 0x4b, 0x4b, 0x6f, 0x5a, 0x49, 0x68, + 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x41, 0x77, 0x51, 0x43, 0x41, 0x41, 0x41, + 0x77, 0x46, 0x41, 0x59, 0x4b, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, + 0x51, 0x30, 0x42, 0x0a, 0x42, 0x41, 0x51, 0x47, 0x41, 0x47, 0x42, 0x71, 0x41, 0x41, + 0x41, 0x41, 0x4d, 0x41, 0x38, 0x47, 0x43, 0x69, 0x71, 0x47, 0x53, 0x49, 0x62, 0x34, + 0x54, 0x51, 0x45, 0x4e, 0x41, 0x51, 0x55, 0x4b, 0x41, 0x51, 0x45, 0x77, 0x48, 0x67, + 0x59, 0x4b, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, + 0x42, 0x67, 0x51, 0x51, 0x70, 0x4a, 0x75, 0x73, 0x2f, 0x64, 0x35, 0x79, 0x0a, 0x7a, + 0x76, 0x39, 0x38, 0x45, 0x56, 0x63, 0x79, 0x75, 0x47, 0x47, 0x58, 0x2b, 0x54, 0x42, + 0x45, 0x42, 0x67, 0x6f, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x2b, 0x45, 0x30, 0x42, 0x44, + 0x51, 0x45, 0x48, 0x4d, 0x44, 0x59, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, + 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x42, 0x77, 0x45, 0x42, 0x41, + 0x66, 0x38, 0x77, 0x45, 0x41, 0x59, 0x4c, 0x0a, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, + 0x68, 0x4e, 0x41, 0x51, 0x30, 0x42, 0x42, 0x77, 0x49, 0x42, 0x41, 0x51, 0x41, 0x77, + 0x45, 0x41, 0x59, 0x4c, 0x4b, 0x6f, 0x5a, 0x49, 0x68, 0x76, 0x68, 0x4e, 0x41, 0x51, + 0x30, 0x42, 0x42, 0x77, 0x4d, 0x42, 0x41, 0x51, 0x41, 0x77, 0x43, 0x67, 0x59, 0x49, + 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x45, 0x41, 0x77, 0x49, 0x44, 0x53, 0x41, + 0x41, 0x77, 0x0a, 0x52, 0x51, 0x49, 0x68, 0x41, 0x50, 0x48, 0x62, 0x5a, 0x76, 0x49, + 0x6d, 0x50, 0x68, 0x74, 0x7a, 0x53, 0x59, 0x4f, 0x53, 0x4c, 0x47, 0x45, 0x47, 0x55, + 0x46, 0x51, 0x32, 0x68, 0x30, 0x58, 0x36, 0x70, 0x67, 0x65, 0x48, 0x77, 0x6f, 0x51, + 0x33, 0x6e, 0x6a, 0x4a, 0x37, 0x76, 0x48, 0x74, 0x57, 0x41, 0x69, 0x42, 0x43, 0x37, + 0x78, 0x75, 0x57, 0x65, 0x6e, 0x79, 0x4f, 0x46, 0x68, 0x6e, 0x6d, 0x0a, 0x71, 0x58, + 0x38, 0x6d, 0x63, 0x57, 0x76, 0x71, 0x34, 0x58, 0x32, 0x72, 0x6d, 0x64, 0x63, 0x4f, + 0x56, 0x63, 0x64, 0x53, 0x4c, 0x50, 0x5a, 0x4c, 0x4f, 0x4e, 0x4b, 0x41, 0x54, 0x77, + 0x3d, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, + 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, 0x45, + 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x6c, 0x6a, 0x43, 0x43, 0x41, 0x6a, 0x32, 0x67, 0x41, + 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x56, 0x41, 0x4a, 0x56, 0x76, 0x58, 0x63, 0x32, + 0x39, 0x47, 0x2b, 0x48, 0x70, 0x51, 0x45, 0x6e, 0x4a, 0x31, 0x50, 0x51, 0x7a, 0x7a, + 0x67, 0x46, 0x58, 0x43, 0x39, 0x35, 0x55, 0x4d, 0x41, 0x6f, 0x47, 0x43, 0x43, 0x71, + 0x47, 0x53, 0x4d, 0x34, 0x39, 0x42, 0x41, 0x4d, 0x43, 0x0a, 0x4d, 0x47, 0x67, 0x78, + 0x47, 0x6a, 0x41, 0x59, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, 0x4d, 0x45, 0x55, + 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, 0x49, 0x46, 0x4e, 0x48, 0x57, 0x43, 0x42, 0x53, + 0x62, 0x32, 0x39, 0x30, 0x49, 0x45, 0x4e, 0x42, 0x4d, 0x52, 0x6f, 0x77, 0x47, 0x41, + 0x59, 0x44, 0x56, 0x51, 0x51, 0x4b, 0x44, 0x42, 0x46, 0x4a, 0x62, 0x6e, 0x52, 0x6c, + 0x62, 0x43, 0x42, 0x44, 0x0a, 0x62, 0x33, 0x4a, 0x77, 0x62, 0x33, 0x4a, 0x68, 0x64, + 0x47, 0x6c, 0x76, 0x62, 0x6a, 0x45, 0x55, 0x4d, 0x42, 0x49, 0x47, 0x41, 0x31, 0x55, + 0x45, 0x42, 0x77, 0x77, 0x4c, 0x55, 0x32, 0x46, 0x75, 0x64, 0x47, 0x45, 0x67, 0x51, + 0x32, 0x78, 0x68, 0x63, 0x6d, 0x45, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, + 0x56, 0x42, 0x41, 0x67, 0x4d, 0x41, 0x6b, 0x4e, 0x42, 0x4d, 0x51, 0x73, 0x77, 0x0a, + 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55, 0x7a, + 0x41, 0x65, 0x46, 0x77, 0x30, 0x78, 0x4f, 0x44, 0x41, 0x31, 0x4d, 0x6a, 0x45, 0x78, + 0x4d, 0x44, 0x55, 0x77, 0x4d, 0x54, 0x42, 0x61, 0x46, 0x77, 0x30, 0x7a, 0x4d, 0x7a, + 0x41, 0x31, 0x4d, 0x6a, 0x45, 0x78, 0x4d, 0x44, 0x55, 0x77, 0x4d, 0x54, 0x42, 0x61, + 0x4d, 0x48, 0x41, 0x78, 0x49, 0x6a, 0x41, 0x67, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x42, + 0x41, 0x4d, 0x4d, 0x47, 0x55, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, 0x49, 0x46, 0x4e, + 0x48, 0x57, 0x43, 0x42, 0x51, 0x51, 0x30, 0x73, 0x67, 0x55, 0x47, 0x78, 0x68, 0x64, + 0x47, 0x5a, 0x76, 0x63, 0x6d, 0x30, 0x67, 0x51, 0x30, 0x45, 0x78, 0x47, 0x6a, 0x41, + 0x59, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x45, 0x55, 0x6c, 0x75, 0x64, + 0x47, 0x56, 0x73, 0x0a, 0x49, 0x45, 0x4e, 0x76, 0x63, 0x6e, 0x42, 0x76, 0x63, 0x6d, + 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x4d, 0x52, 0x51, 0x77, 0x45, 0x67, 0x59, 0x44, + 0x56, 0x51, 0x51, 0x48, 0x44, 0x41, 0x74, 0x54, 0x59, 0x57, 0x35, 0x30, 0x59, 0x53, + 0x42, 0x44, 0x62, 0x47, 0x46, 0x79, 0x59, 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, + 0x41, 0x31, 0x55, 0x45, 0x43, 0x41, 0x77, 0x43, 0x51, 0x30, 0x45, 0x78, 0x0a, 0x43, + 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6c, 0x56, + 0x54, 0x4d, 0x46, 0x6b, 0x77, 0x45, 0x77, 0x59, 0x48, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, + 0x6a, 0x30, 0x43, 0x41, 0x51, 0x59, 0x49, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, + 0x44, 0x41, 0x51, 0x63, 0x44, 0x51, 0x67, 0x41, 0x45, 0x4e, 0x53, 0x42, 0x2f, 0x37, + 0x74, 0x32, 0x31, 0x6c, 0x58, 0x53, 0x4f, 0x0a, 0x32, 0x43, 0x75, 0x7a, 0x70, 0x78, + 0x77, 0x37, 0x34, 0x65, 0x4a, 0x42, 0x37, 0x32, 0x45, 0x79, 0x44, 0x47, 0x67, 0x57, + 0x35, 0x72, 0x58, 0x43, 0x74, 0x78, 0x32, 0x74, 0x56, 0x54, 0x4c, 0x71, 0x36, 0x68, + 0x4b, 0x6b, 0x36, 0x7a, 0x2b, 0x55, 0x69, 0x52, 0x5a, 0x43, 0x6e, 0x71, 0x52, 0x37, + 0x70, 0x73, 0x4f, 0x76, 0x67, 0x71, 0x46, 0x65, 0x53, 0x78, 0x6c, 0x6d, 0x54, 0x6c, + 0x4a, 0x6c, 0x0a, 0x65, 0x54, 0x6d, 0x69, 0x32, 0x57, 0x59, 0x7a, 0x33, 0x71, 0x4f, + 0x42, 0x75, 0x7a, 0x43, 0x42, 0x75, 0x44, 0x41, 0x66, 0x42, 0x67, 0x4e, 0x56, 0x48, + 0x53, 0x4d, 0x45, 0x47, 0x44, 0x41, 0x57, 0x67, 0x42, 0x51, 0x69, 0x5a, 0x51, 0x7a, + 0x57, 0x57, 0x70, 0x30, 0x30, 0x69, 0x66, 0x4f, 0x44, 0x74, 0x4a, 0x56, 0x53, 0x76, + 0x31, 0x41, 0x62, 0x4f, 0x53, 0x63, 0x47, 0x72, 0x44, 0x42, 0x53, 0x0a, 0x42, 0x67, + 0x4e, 0x56, 0x48, 0x52, 0x38, 0x45, 0x53, 0x7a, 0x42, 0x4a, 0x4d, 0x45, 0x65, 0x67, + 0x52, 0x61, 0x42, 0x44, 0x68, 0x6b, 0x46, 0x6f, 0x64, 0x48, 0x52, 0x77, 0x63, 0x7a, + 0x6f, 0x76, 0x4c, 0x32, 0x4e, 0x6c, 0x63, 0x6e, 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, + 0x59, 0x58, 0x52, 0x6c, 0x63, 0x79, 0x35, 0x30, 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x47, + 0x56, 0x6b, 0x63, 0x32, 0x56, 0x79, 0x0a, 0x64, 0x6d, 0x6c, 0x6a, 0x5a, 0x58, 0x4d, + 0x75, 0x61, 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, 0x75, 0x59, 0x32, 0x39, 0x74, 0x4c, + 0x30, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, 0x55, 0x30, 0x64, 0x59, 0x55, 0x6d, 0x39, + 0x76, 0x64, 0x45, 0x4e, 0x42, 0x4c, 0x6d, 0x52, 0x6c, 0x63, 0x6a, 0x41, 0x64, 0x42, + 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, 0x67, 0x51, 0x55, 0x6c, 0x57, 0x39, + 0x64, 0x0a, 0x7a, 0x62, 0x30, 0x62, 0x34, 0x65, 0x6c, 0x41, 0x53, 0x63, 0x6e, 0x55, + 0x39, 0x44, 0x50, 0x4f, 0x41, 0x56, 0x63, 0x4c, 0x33, 0x6c, 0x51, 0x77, 0x44, 0x67, + 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, 0x48, 0x2f, 0x42, 0x41, 0x51, 0x44, + 0x41, 0x67, 0x45, 0x47, 0x4d, 0x42, 0x49, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, + 0x45, 0x42, 0x2f, 0x77, 0x51, 0x49, 0x4d, 0x41, 0x59, 0x42, 0x0a, 0x41, 0x66, 0x38, + 0x43, 0x41, 0x51, 0x41, 0x77, 0x43, 0x67, 0x59, 0x49, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, + 0x6a, 0x30, 0x45, 0x41, 0x77, 0x49, 0x44, 0x52, 0x77, 0x41, 0x77, 0x52, 0x41, 0x49, + 0x67, 0x58, 0x73, 0x56, 0x6b, 0x69, 0x30, 0x77, 0x2b, 0x69, 0x36, 0x56, 0x59, 0x47, + 0x57, 0x33, 0x55, 0x46, 0x2f, 0x32, 0x32, 0x75, 0x61, 0x58, 0x65, 0x30, 0x59, 0x4a, + 0x44, 0x6a, 0x31, 0x55, 0x65, 0x0a, 0x6e, 0x41, 0x2b, 0x54, 0x6a, 0x44, 0x31, 0x61, + 0x69, 0x35, 0x63, 0x43, 0x49, 0x43, 0x59, 0x62, 0x31, 0x53, 0x41, 0x6d, 0x44, 0x35, + 0x78, 0x6b, 0x66, 0x54, 0x56, 0x70, 0x76, 0x6f, 0x34, 0x55, 0x6f, 0x79, 0x69, 0x53, + 0x59, 0x78, 0x72, 0x44, 0x57, 0x4c, 0x6d, 0x55, 0x52, 0x34, 0x43, 0x49, 0x39, 0x4e, + 0x4b, 0x79, 0x66, 0x50, 0x4e, 0x2b, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, + 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, + 0x4e, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x6a, 0x7a, 0x43, 0x43, 0x41, + 0x6a, 0x53, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x55, 0x49, 0x6d, 0x55, + 0x4d, 0x31, 0x6c, 0x71, 0x64, 0x4e, 0x49, 0x6e, 0x7a, 0x67, 0x37, 0x53, 0x56, 0x55, + 0x72, 0x39, 0x51, 0x47, 0x7a, 0x6b, 0x6e, 0x42, 0x71, 0x77, 0x77, 0x43, 0x67, 0x59, + 0x49, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x45, 0x41, 0x77, 0x49, 0x77, 0x0a, + 0x61, 0x44, 0x45, 0x61, 0x4d, 0x42, 0x67, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x77, + 0x77, 0x52, 0x53, 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, 0x67, 0x55, 0x30, 0x64, 0x59, + 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, 0x51, 0x30, 0x45, 0x78, 0x47, 0x6a, + 0x41, 0x59, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, 0x4d, 0x45, 0x55, 0x6c, 0x75, + 0x64, 0x47, 0x56, 0x73, 0x49, 0x45, 0x4e, 0x76, 0x0a, 0x63, 0x6e, 0x42, 0x76, 0x63, + 0x6d, 0x46, 0x30, 0x61, 0x57, 0x39, 0x75, 0x4d, 0x52, 0x51, 0x77, 0x45, 0x67, 0x59, + 0x44, 0x56, 0x51, 0x51, 0x48, 0x44, 0x41, 0x74, 0x54, 0x59, 0x57, 0x35, 0x30, 0x59, + 0x53, 0x42, 0x44, 0x62, 0x47, 0x46, 0x79, 0x59, 0x54, 0x45, 0x4c, 0x4d, 0x41, 0x6b, + 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x41, 0x77, 0x43, 0x51, 0x30, 0x45, 0x78, 0x43, + 0x7a, 0x41, 0x4a, 0x0a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x59, 0x54, 0x41, 0x6c, + 0x56, 0x54, 0x4d, 0x42, 0x34, 0x58, 0x44, 0x54, 0x45, 0x34, 0x4d, 0x44, 0x55, 0x79, + 0x4d, 0x54, 0x45, 0x77, 0x4e, 0x44, 0x55, 0x78, 0x4d, 0x46, 0x6f, 0x58, 0x44, 0x54, + 0x51, 0x35, 0x4d, 0x54, 0x49, 0x7a, 0x4d, 0x54, 0x49, 0x7a, 0x4e, 0x54, 0x6b, 0x31, + 0x4f, 0x56, 0x6f, 0x77, 0x61, 0x44, 0x45, 0x61, 0x4d, 0x42, 0x67, 0x47, 0x0a, 0x41, + 0x31, 0x55, 0x45, 0x41, 0x77, 0x77, 0x52, 0x53, 0x57, 0x35, 0x30, 0x5a, 0x57, 0x77, + 0x67, 0x55, 0x30, 0x64, 0x59, 0x49, 0x46, 0x4a, 0x76, 0x62, 0x33, 0x51, 0x67, 0x51, + 0x30, 0x45, 0x78, 0x47, 0x6a, 0x41, 0x59, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x6f, + 0x4d, 0x45, 0x55, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, 0x49, 0x45, 0x4e, 0x76, 0x63, + 0x6e, 0x42, 0x76, 0x63, 0x6d, 0x46, 0x30, 0x0a, 0x61, 0x57, 0x39, 0x75, 0x4d, 0x52, + 0x51, 0x77, 0x45, 0x67, 0x59, 0x44, 0x56, 0x51, 0x51, 0x48, 0x44, 0x41, 0x74, 0x54, + 0x59, 0x57, 0x35, 0x30, 0x59, 0x53, 0x42, 0x44, 0x62, 0x47, 0x46, 0x79, 0x59, 0x54, + 0x45, 0x4c, 0x4d, 0x41, 0x6b, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x41, 0x77, 0x43, + 0x51, 0x30, 0x45, 0x78, 0x43, 0x7a, 0x41, 0x4a, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, + 0x59, 0x54, 0x0a, 0x41, 0x6c, 0x56, 0x54, 0x4d, 0x46, 0x6b, 0x77, 0x45, 0x77, 0x59, + 0x48, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x43, 0x41, 0x51, 0x59, 0x49, 0x4b, + 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x44, 0x41, 0x51, 0x63, 0x44, 0x51, 0x67, 0x41, + 0x45, 0x43, 0x36, 0x6e, 0x45, 0x77, 0x4d, 0x44, 0x49, 0x59, 0x5a, 0x4f, 0x6a, 0x2f, + 0x69, 0x50, 0x57, 0x73, 0x43, 0x7a, 0x61, 0x45, 0x4b, 0x69, 0x37, 0x0a, 0x31, 0x4f, + 0x69, 0x4f, 0x53, 0x4c, 0x52, 0x46, 0x68, 0x57, 0x47, 0x6a, 0x62, 0x6e, 0x42, 0x56, + 0x4a, 0x66, 0x56, 0x6e, 0x6b, 0x59, 0x34, 0x75, 0x33, 0x49, 0x6a, 0x6b, 0x44, 0x59, + 0x59, 0x4c, 0x30, 0x4d, 0x78, 0x4f, 0x34, 0x6d, 0x71, 0x73, 0x79, 0x59, 0x6a, 0x6c, + 0x42, 0x61, 0x6c, 0x54, 0x56, 0x59, 0x78, 0x46, 0x50, 0x32, 0x73, 0x4a, 0x42, 0x4b, + 0x35, 0x7a, 0x6c, 0x4b, 0x4f, 0x42, 0x0a, 0x75, 0x7a, 0x43, 0x42, 0x75, 0x44, 0x41, + 0x66, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x53, 0x4d, 0x45, 0x47, 0x44, 0x41, 0x57, 0x67, + 0x42, 0x51, 0x69, 0x5a, 0x51, 0x7a, 0x57, 0x57, 0x70, 0x30, 0x30, 0x69, 0x66, 0x4f, + 0x44, 0x74, 0x4a, 0x56, 0x53, 0x76, 0x31, 0x41, 0x62, 0x4f, 0x53, 0x63, 0x47, 0x72, + 0x44, 0x42, 0x53, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x52, 0x38, 0x45, 0x53, 0x7a, 0x42, + 0x4a, 0x0a, 0x4d, 0x45, 0x65, 0x67, 0x52, 0x61, 0x42, 0x44, 0x68, 0x6b, 0x46, 0x6f, + 0x64, 0x48, 0x52, 0x77, 0x63, 0x7a, 0x6f, 0x76, 0x4c, 0x32, 0x4e, 0x6c, 0x63, 0x6e, + 0x52, 0x70, 0x5a, 0x6d, 0x6c, 0x6a, 0x59, 0x58, 0x52, 0x6c, 0x63, 0x79, 0x35, 0x30, + 0x63, 0x6e, 0x56, 0x7a, 0x64, 0x47, 0x56, 0x6b, 0x63, 0x32, 0x56, 0x79, 0x64, 0x6d, + 0x6c, 0x6a, 0x5a, 0x58, 0x4d, 0x75, 0x61, 0x57, 0x35, 0x30, 0x0a, 0x5a, 0x57, 0x77, + 0x75, 0x59, 0x32, 0x39, 0x74, 0x4c, 0x30, 0x6c, 0x75, 0x64, 0x47, 0x56, 0x73, 0x55, + 0x30, 0x64, 0x59, 0x55, 0x6d, 0x39, 0x76, 0x64, 0x45, 0x4e, 0x42, 0x4c, 0x6d, 0x52, + 0x6c, 0x63, 0x6a, 0x41, 0x64, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x34, 0x45, 0x46, + 0x67, 0x51, 0x55, 0x49, 0x6d, 0x55, 0x4d, 0x31, 0x6c, 0x71, 0x64, 0x4e, 0x49, 0x6e, + 0x7a, 0x67, 0x37, 0x53, 0x56, 0x0a, 0x55, 0x72, 0x39, 0x51, 0x47, 0x7a, 0x6b, 0x6e, + 0x42, 0x71, 0x77, 0x77, 0x44, 0x67, 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x41, 0x51, + 0x48, 0x2f, 0x42, 0x41, 0x51, 0x44, 0x41, 0x67, 0x45, 0x47, 0x4d, 0x42, 0x49, 0x47, + 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, 0x42, 0x2f, 0x77, 0x51, 0x49, 0x4d, 0x41, + 0x59, 0x42, 0x41, 0x66, 0x38, 0x43, 0x41, 0x51, 0x45, 0x77, 0x43, 0x67, 0x59, 0x49, + 0x0a, 0x4b, 0x6f, 0x5a, 0x49, 0x7a, 0x6a, 0x30, 0x45, 0x41, 0x77, 0x49, 0x44, 0x53, + 0x51, 0x41, 0x77, 0x52, 0x67, 0x49, 0x68, 0x41, 0x4f, 0x57, 0x2f, 0x35, 0x51, 0x6b, + 0x52, 0x2b, 0x53, 0x39, 0x43, 0x69, 0x53, 0x44, 0x63, 0x4e, 0x6f, 0x6f, 0x77, 0x4c, + 0x75, 0x50, 0x52, 0x4c, 0x73, 0x57, 0x47, 0x66, 0x2f, 0x59, 0x69, 0x37, 0x47, 0x53, + 0x58, 0x39, 0x34, 0x42, 0x67, 0x77, 0x54, 0x77, 0x67, 0x0a, 0x41, 0x69, 0x45, 0x41, + 0x34, 0x4a, 0x30, 0x6c, 0x72, 0x48, 0x6f, 0x4d, 0x73, 0x2b, 0x58, 0x6f, 0x35, 0x6f, + 0x2f, 0x73, 0x58, 0x36, 0x4f, 0x39, 0x51, 0x57, 0x78, 0x48, 0x52, 0x41, 0x76, 0x5a, + 0x55, 0x47, 0x4f, 0x64, 0x52, 0x51, 0x37, 0x63, 0x76, 0x71, 0x52, 0x58, 0x61, 0x71, + 0x49, 0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43, 0x45, + 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x0a, 0x00, + ]; + + let collateral = Collateral { + major_version: 1, + minor_version: 0, + tee_type: 0, + pck_crl_issuer_chain: "-----BEGIN CERTIFICATE-----\nMIICljCCAj2gAwIBAgIVAJVvXc29G+HpQEnJ1PQzzgFXC95UMAoGCCqGSM49BAMC\nMGgxGjAYBgNVBAMMEUludGVsIFNHWCBSb290IENBMRowGAYDVQQKDBFJbnRlbCBD\nb3Jwb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQsw\nCQYDVQQGEwJVUzAeFw0xODA1MjExMDUwMTBaFw0zMzA1MjExMDUwMTBaMHAxIjAg\nBgNVBAMMGUludGVsIFNHWCBQQ0sgUGxhdGZvcm0gQ0ExGjAYBgNVBAoMEUludGVs\nIENvcnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0Ex\nCzAJBgNVBAYTAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENSB/7t21lXSO\n2Cuzpxw74eJB72EyDGgW5rXCtx2tVTLq6hKk6z+UiRZCnqR7psOvgqFeSxlmTlJl\neTmi2WYz3qOBuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBS\nBgNVHR8ESzBJMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2Vy\ndmljZXMuaW50ZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUlW9d\nzb0b4elAScnU9DPOAVcL3lQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYB\nAf8CAQAwCgYIKoZIzj0EAwIDRwAwRAIgXsVki0w+i6VYGW3UF/22uaXe0YJDj1Ue\nnA+TjD1ai5cCICYb1SAmD5xkfTVpvo4UoyiSYxrDWLmUR4CI9NKyfPN+\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n\0".as_bytes().into(), + root_ca_crl: "-----BEGIN X509 CRL-----\nMIIBITCByAIBATAKBggqhkjOPQQDAjBoMRowGAYDVQQDDBFJbnRlbCBTR1ggUm9v\ndCBDQTEaMBgGA1UECgwRSW50ZWwgQ29ycG9yYXRpb24xFDASBgNVBAcMC1NhbnRh\nIENsYXJhMQswCQYDVQQIDAJDQTELMAkGA1UEBhMCVVMXDTIzMDQwMzEwMjI1MVoX\nDTI0MDQwMjEwMjI1MVqgLzAtMAoGA1UdFAQDAgEBMB8GA1UdIwQYMBaAFCJlDNZa\nnTSJ84O0lVK/UBs5JwasMAoGCCqGSM49BAMCA0gAMEUCIFFXfUfZ+6FXtl8etfRl\ne7xeVsyvc1oD8blj1wSAWrEYAiEAk5AV7BY25+r6X0JsHkAmR8ZzEytoUMq9aM72\nutdoKgM=\n-----END X509 CRL-----\n\0".as_bytes().into(), + pck_crl: "-----BEGIN X509 CRL-----\nMIIKYTCCCggCAQEwCgYIKoZIzj0EAwIwcDEiMCAGA1UEAwwZSW50ZWwgU0dYIFBD\nSyBQbGF0Zm9ybSBDQTEaMBgGA1UECgwRSW50ZWwgQ29ycG9yYXRpb24xFDASBgNV\nBAcMC1NhbnRhIENsYXJhMQswCQYDVQQIDAJDQTELMAkGA1UEBhMCVVMXDTIzMDUx\nMzIxMDAwM1oXDTIzMDYxMjIxMDAwM1owggk0MDMCFG/DTlAj5yiSNDXWGqS4PGGB\nZq01Fw0yMzA1MTMyMTAwMDNaMAwwCgYDVR0VBAMKAQEwNAIVAO+ubpcV/KE7h+Mz\n6CYe1tmQqSatFw0yMzA1MTMyMTAwMDNaMAwwCgYDVR0VBAMKAQEwNAIVAP1ghkhi\nnLpzB4tNSS9LPqdBrQjNFw0yMzA1MTMyMTAwMDNaMAwwCgYDVR0VBAMKAQEwNAIV\nAIr5JBhOHVr93XPD1joS9ei1c35WFw0yMzA1MTMyMTAwMDNaMAwwCgYDVR0VBAMK\nAQEwNAIVALEleXjPqczdB1mr+MXKcvrjp4qbFw0yMzA1MTMyMTAwMDNaMAwwCgYD\nVR0VBAMKAQEwMwIUdP6mFKlyvg4oQ/IFmDWBHthy+bMXDTIzMDUxMzIxMDAwM1ow\nDDAKBgNVHRUEAwoBATA0AhUA+cTvVrOrSNV34Qi67fS/iAFCFLkXDTIzMDUxMzIx\nMDAwM1owDDAKBgNVHRUEAwoBATAzAhQHHeB3j55fxPKHjzDWsHyaMOazCxcNMjMw\nNTEzMjEwMDAzWjAMMAoGA1UdFQQDCgEBMDQCFQDN4kJPlyzqlP8jmTf02AwlAp3W\nCxcNMjMwNTEzMjEwMDAzWjAMMAoGA1UdFQQDCgEBMDMCFGwzGeUQm2RQfTzxEyzg\nA0nvUnMZFw0yMzA1MTMyMTAwMDNaMAwwCgYDVR0VBAMKAQEwNAIVAN8I11a2anSX\n9DtbtYraBNP096k3Fw0yMzA1MTMyMTAwMDNaMAwwCgYDVR0VBAMKAQEwMwIUKK9I\nW2z2fkCaOdXLWu5FmPeo+nsXDTIzMDUxMzIxMDAwM1owDDAKBgNVHRUEAwoBATA0\nAhUA+4strsCSytqKqbxP8vHCDQNGZowXDTIzMDUxMzIxMDAwM1owDDAKBgNVHRUE\nAwoBATA0AhUAzUhQrFK9zGmmpvBYyLxXu9C1+GQXDTIzMDUxMzIxMDAwM1owDDAK\nBgNVHRUEAwoBATA0AhUAmU3TZm9SdfuAX5XdAr1QyyZ52K0XDTIzMDUxMzIxMDAw\nM1owDDAKBgNVHRUEAwoBATAzAhQHAhNpACUidNkDXu31RXRi+tDvTBcNMjMwNTEz\nMjEwMDAzWjAMMAoGA1UdFQQDCgEBMDMCFGHyv3Pjm04EqifYAb1z0kMZtb+AFw0y\nMzA1MTMyMTAwMDNaMAwwCgYDVR0VBAMKAQEwMwIUOZK+hRuWkC7/OJWebC7/GwZR\npLUXDTIzMDUxMzIxMDAwM1owDDAKBgNVHRUEAwoBATAzAhRjnxOaUED9z/GR6KT7\nG/CG7WA5cRcNMjMwNTEzMjEwMDAzWjAMMAoGA1UdFQQDCgEBMDQCFQCVnVM/kknc\nHlE1RM3IML8Zt/HzARcNMjMwNTEzMjEwMDAzWjAMMAoGA1UdFQQDCgEBMDMCFA/a\nQ6ALaOp5t8LerqwLSYvfsq+QFw0yMzA1MTMyMTAwMDNaMAwwCgYDVR0VBAMKAQEw\nNAIVAJ1ndTuB5HCQrqdj++xMRUm825kzFw0yMzA1MTMyMTAwMDNaMAwwCgYDVR0V\nBAMKAQEwMwIUNL+7eh2cVoFH4Ri2FPe3btPvaN8XDTIzMDUxMzIxMDAwM1owDDAK\nBgNVHRUEAwoBATA0AhUAhdPJOBt3p+BNEZyeWtZ0n/P/q4cXDTIzMDUxMzIxMDAw\nM1owDDAKBgNVHRUEAwoBATA0AhUAk4h8pEEeepI70f7SgZspSfIBtbQXDTIzMDUx\nMzIxMDAwM1owDDAKBgNVHRUEAwoBATAzAhQkmNxig5MJlv2L8jo3rL4mo77UVxcN\nMjMwNTEzMjEwMDAzWjAMMAoGA1UdFQQDCgEBMDQCFQCKZvGnSUiGZ2icw5A6xUxm\nK3EucxcNMjMwNTEzMjEwMDAzWjAMMAoGA1UdFQQDCgEBMDQCFQCvwTYQvdNst5hd\nEGSBqIDToB/aBxcNMjMwNTEzMjEwMDAzWjAMMAoGA1UdFQQDCgEBMDQCFQDv4Ess\nM9A2qslspnO/HppHtk1cuxcNMjMwNTEzMjEwMDAzWjAMMAoGA1UdFQQDCgEBMDQC\nFQCD2ayNi7UJ0cbICa1xLoQwVZ7X8xcNMjMwNTEzMjEwMDAzWjAMMAoGA1UdFQQD\nCgEBMDMCFHkx/VC1Bxwbv8W3tt7YtFudi4UpFw0yMzA1MTMyMTAwMDNaMAwwCgYD\nVR0VBAMKAQEwMwIUH6IOKXC95dV/e43fgzlITh8dCCMXDTIzMDUxMzIxMDAwM1ow\nDDAKBgNVHRUEAwoBATAzAhQeh7LDsy2NI+QRzvNBl7la8Mit9RcNMjMwNTEzMjEw\nMDAzWjAMMAoGA1UdFQQDCgEBMDQCFQCa/S7pCkc1UKFn2ZaRFDfHUC0fCRcNMjMw\nNTEzMjEwMDAzWjAMMAoGA1UdFQQDCgEBMDMCFESBsPEXKKE7aW0+qcdwoLFexY3a\nFw0yMzA1MTMyMTAwMDNaMAwwCgYDVR0VBAMKAQEwNAIVAKeFn1eYLvDmfTe8jvLv\nWsg1/xqpFw0yMzA1MTMyMTAwMDNaMAwwCgYDVR0VBAMKAQEwMwIUeuN3SKn5EvTG\nO6erB8WTzh0dEYEXDTIzMDUxMzIxMDAwM1owDDAKBgNVHRUEAwoBATAzAhQTiEsz\nJpk4wZWqFw/KddoXdTjfCxcNMjMwNTEzMjEwMDAzWjAMMAoGA1UdFQQDCgEBMDMC\nFCw8xv6SedsVFtXOOfKomM2loXXhFw0yMzA1MTMyMTAwMDNaMAwwCgYDVR0VBAMK\nAQEwMwIUcXlIaHUJI0vpeeS33ObzG+9ktowXDTIzMDUxMzIxMDAwM1owDDAKBgNV\nHRUEAwoBATA0AhUAnXbvLDnBNuhli25zlrHXRFonYx8XDTIzMDUxMzIxMDAwM1ow\nDDAKBgNVHRUEAwoBATA0AhUAw+Al/KmV829ZtIRnk54+NOY2Gm8XDTIzMDUxMzIx\nMDAwM1owDDAKBgNVHRUEAwoBATA0AhUAjF9rMlfaBbF0KeLmG6ll1nMwYGoXDTIz\nMDUxMzIxMDAwM1owDDAKBgNVHRUEAwoBATA0AhUAoXxRci7B4MMnj+i98FIFnL7E\n5kgXDTIzMDUxMzIxMDAwM1owDDAKBgNVHRUEAwoBAaAvMC0wCgYDVR0UBAMCAQEw\nHwYDVR0jBBgwFoAUlW9dzb0b4elAScnU9DPOAVcL3lQwCgYIKoZIzj0EAwIDRwAw\nRAIgFCcExhc9muZCJybEgaDtgH1ZF5s739IHTjXl/JZTDR4CIG5WeLcFCg2nZozP\n5NqC0+MecmYxPN0eubPbpzhsF28z\n-----END X509 CRL-----\n\0".as_bytes().into(), + tcb_info_issuer_chain: "-----BEGIN CERTIFICATE-----\nMIICizCCAjKgAwIBAgIUfjiC1ftVKUpASY5FhAPpFJG99FUwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNTAxMFoXDTI1MDUyMTEwNTAxMFowbDEeMBwG\nA1UEAwwVSW50ZWwgU0dYIFRDQiBTaWduaW5nMRowGAYDVQQKDBFJbnRlbCBDb3Jw\nb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQswCQYD\nVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABENFG8xzydWRfK92bmGv\nP+mAh91PEyV7Jh6FGJd5ndE9aBH7R3E4A7ubrlh/zN3C4xvpoouGlirMba+W2lju\nypajgbUwgbIwHwYDVR0jBBgwFoAUImUM1lqdNInzg7SVUr9QGzknBqwwUgYDVR0f\nBEswSTBHoEWgQ4ZBaHR0cHM6Ly9jZXJ0aWZpY2F0ZXMudHJ1c3RlZHNlcnZpY2Vz\nLmludGVsLmNvbS9JbnRlbFNHWFJvb3RDQS5kZXIwHQYDVR0OBBYEFH44gtX7VSlK\nQEmORYQD6RSRvfRVMA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMAoGCCqG\nSM49BAMCA0cAMEQCIB9C8wOAN/ImxDtGACV246KcqjagZOR0kyctyBrsGGJVAiAj\nftbrNGsGU8YH211dRiYNoPPu19Zp/ze8JmhujB0oBw==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n\0".as_bytes().into(), + tcb_info: "{\"tcbInfo\":{\"id\":\"SGX\",\"version\":3,\"issueDate\":\"2023-05-15T14:08:11Z\",\"nextUpdate\":\"2023-06-14T14:08:11Z\",\"fmspc\":\"00606a000000\",\"pceId\":\"0000\",\"tcbType\":0,\"tcbEvaluationDataNumber\":15,\"tcbLevels\":[{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":11,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":11,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":255},{\"svn\":255},{\"svn\":1},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":13},\"tcbDate\":\"2023-02-15T00:00:00Z\",\"tcbStatus\":\"SWHardeningNeeded\",\"advisoryIDs\":[\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":11,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":11,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":255},{\"svn\":255},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":13},\"tcbDate\":\"2023-02-15T00:00:00Z\",\"tcbStatus\":\"ConfigurationAndSWHardeningNeeded\",\"advisoryIDs\":[\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":7,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":9,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":255},{\"svn\":255},{\"svn\":1},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":13},\"tcbDate\":\"2022-08-10T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00657\",\"INTEL-SA-00730\",\"INTEL-SA-00738\",\"INTEL-SA-00767\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":7,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":9,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":255},{\"svn\":255},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":13},\"tcbDate\":\"2022-08-10T00:00:00Z\",\"tcbStatus\":\"OutOfDateConfigurationNeeded\",\"advisoryIDs\":[\"INTEL-SA-00657\",\"INTEL-SA-00730\",\"INTEL-SA-00738\",\"INTEL-SA-00767\",\"INTEL-SA-00615\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":4,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":4,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":255},{\"svn\":255},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":11},\"tcbDate\":\"2021-11-10T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00586\",\"INTEL-SA-00614\",\"INTEL-SA-00615\",\"INTEL-SA-00657\",\"INTEL-SA-00730\",\"INTEL-SA-00738\",\"INTEL-SA-00767\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":4,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":4,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":255},{\"svn\":255},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":10},\"tcbDate\":\"2020-11-11T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00477\",\"INTEL-SA-00586\",\"INTEL-SA-00614\",\"INTEL-SA-00615\",\"INTEL-SA-00657\",\"INTEL-SA-00730\",\"INTEL-SA-00738\",\"INTEL-SA-00767\"]},{\"tcb\":{\"sgxtcbcomponents\":[{\"svn\":4,\"category\":\"BIOS\",\"type\":\"Early Microcode Update\"},{\"svn\":4,\"category\":\"OS/VMM\",\"type\":\"SGX Late Microcode Update\"},{\"svn\":3,\"category\":\"OS/VMM\",\"type\":\"TXT SINIT\"},{\"svn\":3,\"category\":\"BIOS\"},{\"svn\":255},{\"svn\":255},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0},{\"svn\":0}],\"pcesvn\":5},\"tcbDate\":\"2018-01-04T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00106\",\"INTEL-SA-00115\",\"INTEL-SA-00135\",\"INTEL-SA-00203\",\"INTEL-SA-00220\",\"INTEL-SA-00233\",\"INTEL-SA-00270\",\"INTEL-SA-00293\",\"INTEL-SA-00320\",\"INTEL-SA-00329\",\"INTEL-SA-00381\",\"INTEL-SA-00389\",\"INTEL-SA-00477\",\"INTEL-SA-00586\",\"INTEL-SA-00614\",\"INTEL-SA-00615\",\"INTEL-SA-00657\",\"INTEL-SA-00730\",\"INTEL-SA-00738\",\"INTEL-SA-00767\"]}]},\"signature\":\"5fee75684718bcb9191312cd3bf47096a4068f450d2ec9e05b8cd5a3a7cb61b292612a708c4c5a304836c82c3a7191447e3ba691e59287cc9c8943e821734d41\"}\0".as_bytes().into(), + qe_identity_issuer_chain: "-----BEGIN CERTIFICATE-----\nMIICizCCAjKgAwIBAgIUfjiC1ftVKUpASY5FhAPpFJG99FUwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNTAxMFoXDTI1MDUyMTEwNTAxMFowbDEeMBwG\nA1UEAwwVSW50ZWwgU0dYIFRDQiBTaWduaW5nMRowGAYDVQQKDBFJbnRlbCBDb3Jw\nb3JhdGlvbjEUMBIGA1UEBwwLU2FudGEgQ2xhcmExCzAJBgNVBAgMAkNBMQswCQYD\nVQQGEwJVUzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABENFG8xzydWRfK92bmGv\nP+mAh91PEyV7Jh6FGJd5ndE9aBH7R3E4A7ubrlh/zN3C4xvpoouGlirMba+W2lju\nypajgbUwgbIwHwYDVR0jBBgwFoAUImUM1lqdNInzg7SVUr9QGzknBqwwUgYDVR0f\nBEswSTBHoEWgQ4ZBaHR0cHM6Ly9jZXJ0aWZpY2F0ZXMudHJ1c3RlZHNlcnZpY2Vz\nLmludGVsLmNvbS9JbnRlbFNHWFJvb3RDQS5kZXIwHQYDVR0OBBYEFH44gtX7VSlK\nQEmORYQD6RSRvfRVMA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMAoGCCqG\nSM49BAMCA0cAMEQCIB9C8wOAN/ImxDtGACV246KcqjagZOR0kyctyBrsGGJVAiAj\nftbrNGsGU8YH211dRiYNoPPu19Zp/ze8JmhujB0oBw==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICjzCCAjSgAwIBAgIUImUM1lqdNInzg7SVUr9QGzknBqwwCgYIKoZIzj0EAwIw\naDEaMBgGA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENv\ncnBvcmF0aW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJ\nBgNVBAYTAlVTMB4XDTE4MDUyMTEwNDUxMFoXDTQ5MTIzMTIzNTk1OVowaDEaMBgG\nA1UEAwwRSW50ZWwgU0dYIFJvb3QgQ0ExGjAYBgNVBAoMEUludGVsIENvcnBvcmF0\naW9uMRQwEgYDVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExCzAJBgNVBAYT\nAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC6nEwMDIYZOj/iPWsCzaEKi7\n1OiOSLRFhWGjbnBVJfVnkY4u3IjkDYYL0MxO4mqsyYjlBalTVYxFP2sJBK5zlKOB\nuzCBuDAfBgNVHSMEGDAWgBQiZQzWWp00ifODtJVSv1AbOScGrDBSBgNVHR8ESzBJ\nMEegRaBDhkFodHRwczovL2NlcnRpZmljYXRlcy50cnVzdGVkc2VydmljZXMuaW50\nZWwuY29tL0ludGVsU0dYUm9vdENBLmRlcjAdBgNVHQ4EFgQUImUM1lqdNInzg7SV\nUr9QGzknBqwwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEwCgYI\nKoZIzj0EAwIDSQAwRgIhAOW/5QkR+S9CiSDcNoowLuPRLsWGf/Yi7GSX94BgwTwg\nAiEA4J0lrHoMs+Xo5o/sX6O9QWxHRAvZUGOdRQ7cvqRXaqI=\n-----END CERTIFICATE-----\n\0".as_bytes().into(), + qe_identity: "{\"enclaveIdentity\":{\"id\":\"QE\",\"version\":2,\"issueDate\":\"2023-05-15T14:48:40Z\",\"nextUpdate\":\"2023-06-14T14:48:40Z\",\"tcbEvaluationDataNumber\":15,\"miscselect\":\"00000000\",\"miscselectMask\":\"FFFFFFFF\",\"attributes\":\"11000000000000000000000000000000\",\"attributesMask\":\"FBFFFFFFFFFFFFFF0000000000000000\",\"mrsigner\":\"8C4F5775D796503E96137F77C68A829A0056AC8DED70140B081B094490C57BFF\",\"isvprodid\":1,\"tcbLevels\":[{\"tcb\":{\"isvsvn\":8},\"tcbDate\":\"2023-02-15T00:00:00Z\",\"tcbStatus\":\"UpToDate\"},{\"tcb\":{\"isvsvn\":6},\"tcbDate\":\"2021-11-10T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00615\"]},{\"tcb\":{\"isvsvn\":5},\"tcbDate\":\"2020-11-11T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00477\",\"INTEL-SA-00615\"]},{\"tcb\":{\"isvsvn\":4},\"tcbDate\":\"2019-11-13T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00334\",\"INTEL-SA-00477\",\"INTEL-SA-00615\"]},{\"tcb\":{\"isvsvn\":2},\"tcbDate\":\"2019-05-15T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00219\",\"INTEL-SA-00293\",\"INTEL-SA-00334\",\"INTEL-SA-00477\",\"INTEL-SA-00615\"]},{\"tcb\":{\"isvsvn\":1},\"tcbDate\":\"2018-08-15T00:00:00Z\",\"tcbStatus\":\"OutOfDate\",\"advisoryIDs\":[\"INTEL-SA-00202\",\"INTEL-SA-00219\",\"INTEL-SA-00293\",\"INTEL-SA-00334\",\"INTEL-SA-00477\",\"INTEL-SA-00615\"]}]},\"signature\":\"97ff8957975b40aa51a17765d734363b8cb7557e6657b04f63b67c05f2886be1b7cc14b9c1b889e03b85866e277a102eb9fb85029b7008b41754cdba014a5a8c\"}\0".as_bytes().into(), + }; + + let current_time = 1684165303; + + let report_data = [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + ]; + + let mrsigner = + hex::decode("298037d88782e022e019b3020745b78aa40ed95c77da4bf7f3253d3a44c4fd7e") + .unwrap(); + + check_quote( + "e, + &collateral, + current_time, + &mrsigner, + &report_data, + sgx_ql_qv_result_t::SGX_QL_QV_RESULT_SW_HARDENING_NEEDED, + ) + .unwrap(); + } + + #[test] + fn vault_proxy() { + let quote = [ + 3, 0, 2, 0, 0, 0, 0, 0, 9, 0, 14, 0, 147, 154, 114, 51, 247, 156, 76, 169, 148, 10, 13, + 179, 149, 127, 6, 7, 96, 61, 1, 77, 110, 199, 12, 105, 18, 177, 33, 134, 118, 220, 150, + 214, 0, 0, 0, 0, 11, 11, 16, 15, 255, 255, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, + 0, 0, 0, 0, 0, 0, 231, 0, 0, 0, 0, 0, 0, 0, 99, 123, 107, 103, 81, 7, 65, 134, 7, 2, + 227, 71, 236, 110, 52, 243, 213, 111, 129, 4, 184, 2, 245, 81, 120, 45, 104, 34, 192, + 43, 91, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 59, 144, 155, 179, 101, 143, 244, 42, 30, 135, 123, 136, 6, 253, + 171, 133, 127, 112, 223, 201, 2, 68, 39, 12, 18, 236, 36, 89, 201, 141, 25, 26, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 123, 250, 226, 215, 249, 8, 157, 23, 107, + 24, 181, 206, 242, 216, 29, 236, 31, 209, 220, 51, 46, 155, 35, 197, 83, 196, 224, 47, + 227, 228, 171, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 198, 16, 0, 0, 52, 52, 211, 66, 109, 190, 155, 41, 19, 214, 24, + 139, 55, 152, 225, 202, 15, 107, 171, 105, 32, 74, 200, 205, 98, 104, 82, 160, 37, 88, + 107, 62, 30, 54, 98, 54, 127, 167, 43, 179, 172, 36, 146, 255, 128, 50, 47, 116, 186, + 139, 167, 212, 0, 84, 167, 1, 128, 229, 124, 90, 177, 148, 212, 11, 191, 166, 217, 50, + 160, 111, 125, 97, 248, 240, 119, 55, 108, 81, 22, 80, 189, 0, 162, 116, 16, 221, 134, + 187, 117, 145, 202, 254, 236, 124, 19, 21, 199, 245, 133, 184, 159, 7, 93, 228, 148, + 214, 186, 54, 155, 38, 230, 199, 59, 72, 200, 21, 94, 181, 76, 247, 207, 179, 10, 61, + 62, 141, 57, 94, 11, 11, 16, 15, 255, 255, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 0, + 0, 0, 0, 0, 0, 0, 231, 0, 0, 0, 0, 0, 0, 0, 25, 42, 165, 12, 225, 192, 206, 240, 60, + 207, 137, 231, 181, 177, 107, 13, 121, 120, 245, 194, 177, 237, 207, 119, 77, 135, 112, + 46, 129, 84, 216, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 140, 79, 87, 117, 215, 150, 80, 62, 150, 19, 127, 119, + 198, 138, 130, 154, 0, 86, 172, 141, 237, 112, 20, 11, 8, 27, 9, 68, 144, 197, 123, + 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 203, 102, 177, 250, 244, 129, 135, + 71, 143, 199, 216, 48, 169, 146, 182, 79, 151, 137, 73, 239, 37, 153, 190, 144, 17, + 177, 224, 176, 80, 159, 240, 155, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 180, 85, 182, 231, 60, 230, 215, 202, 181, + 22, 253, 249, 82, 23, 141, 83, 75, 119, 221, 139, 84, 15, 50, 202, 123, 164, 58, 61, + 243, 249, 188, 90, 163, 138, 165, 76, 35, 75, 250, 163, 234, 250, 0, 177, 190, 34, 169, + 113, 71, 114, 163, 202, 191, 190, 144, 23, 169, 224, 68, 240, 130, 7, 188, 118, 32, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 5, 0, 94, 14, 0, 0, 45, 45, 45, 45, 45, 66, 69, 71, 73, + 78, 32, 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, 10, 77, 73, 73, + 69, 56, 84, 67, 67, 66, 74, 105, 103, 65, 119, 73, 66, 65, 103, 73, 85, 68, 50, 67, 80, + 67, 52, 101, 120, 51, 80, 114, 112, 122, 80, 79, 88, 69, 112, 110, 85, 50, 43, 52, 51, + 51, 98, 111, 119, 67, 103, 89, 73, 75, 111, 90, 73, 122, 106, 48, 69, 65, 119, 73, 119, + 10, 99, 68, 69, 105, 77, 67, 65, 71, 65, 49, 85, 69, 65, 119, 119, 90, 83, 87, 53, 48, + 90, 87, 119, 103, 85, 48, 100, 89, 73, 70, 66, 68, 83, 121, 66, 81, 98, 71, 70, 48, 90, + 109, 57, 121, 98, 83, 66, 68, 81, 84, 69, 97, 77, 66, 103, 71, 65, 49, 85, 69, 67, 103, + 119, 82, 10, 83, 87, 53, 48, 90, 87, 119, 103, 81, 50, 57, 121, 99, 71, 57, 121, 89, + 88, 82, 112, 98, 50, 52, 120, 70, 68, 65, 83, 66, 103, 78, 86, 66, 65, 99, 77, 67, 49, + 78, 104, 98, 110, 82, 104, 73, 69, 78, 115, 89, 88, 74, 104, 77, 81, 115, 119, 67, 81, + 89, 68, 86, 81, 81, 73, 10, 68, 65, 74, 68, 81, 84, 69, 76, 77, 65, 107, 71, 65, 49, + 85, 69, 66, 104, 77, 67, 86, 86, 77, 119, 72, 104, 99, 78, 77, 106, 77, 119, 78, 84, + 69, 119, 77, 106, 65, 121, 78, 68, 85, 50, 87, 104, 99, 78, 77, 122, 65, 119, 78, 84, + 69, 119, 77, 106, 65, 121, 78, 68, 85, 50, 10, 87, 106, 66, 119, 77, 83, 73, 119, 73, + 65, 89, 68, 86, 81, 81, 68, 68, 66, 108, 74, 98, 110, 82, 108, 98, 67, 66, 84, 82, 49, + 103, 103, 85, 69, 78, 76, 73, 69, 78, 108, 99, 110, 82, 112, 90, 109, 108, 106, 89, 88, + 82, 108, 77, 82, 111, 119, 71, 65, 89, 68, 86, 81, 81, 75, 10, 68, 66, 70, 74, 98, 110, + 82, 108, 98, 67, 66, 68, 98, 51, 74, 119, 98, 51, 74, 104, 100, 71, 108, 118, 98, 106, + 69, 85, 77, 66, 73, 71, 65, 49, 85, 69, 66, 119, 119, 76, 85, 50, 70, 117, 100, 71, 69, + 103, 81, 50, 120, 104, 99, 109, 69, 120, 67, 122, 65, 74, 66, 103, 78, 86, 10, 66, 65, + 103, 77, 65, 107, 78, 66, 77, 81, 115, 119, 67, 81, 89, 68, 86, 81, 81, 71, 69, 119, + 74, 86, 85, 122, 66, 90, 77, 66, 77, 71, 66, 121, 113, 71, 83, 77, 52, 57, 65, 103, 69, + 71, 67, 67, 113, 71, 83, 77, 52, 57, 65, 119, 69, 72, 65, 48, 73, 65, 66, 68, 117, 101, + 10, 67, 56, 89, 118, 47, 82, 103, 103, 101, 121, 114, 117, 121, 113, 106, 102, 82, 88, + 114, 118, 77, 89, 70, 48, 104, 82, 120, 81, 119, 87, 110, 121, 111, 104, 85, 116, 47, + 119, 101, 99, 121, 76, 101, 47, 102, 50, 68, 71, 89, 72, 105, 53, 70, 83, 70, 47, 54, + 103, 82, 105, 83, 56, 47, 86, 10, 54, 98, 98, 87, 122, 109, 113, 50, 113, 48, 108, 102, + 111, 76, 122, 47, 97, 48, 71, 106, 103, 103, 77, 79, 77, 73, 73, 68, 67, 106, 65, 102, + 66, 103, 78, 86, 72, 83, 77, 69, 71, 68, 65, 87, 103, 66, 83, 86, 98, 49, 51, 78, 118, + 82, 118, 104, 54, 85, 66, 74, 121, 100, 84, 48, 10, 77, 56, 52, 66, 86, 119, 118, 101, + 86, 68, 66, 114, 66, 103, 78, 86, 72, 82, 56, 69, 90, 68, 66, 105, 77, 71, 67, 103, 88, + 113, 66, 99, 104, 108, 112, 111, 100, 72, 82, 119, 99, 122, 111, 118, 76, 50, 70, 119, + 97, 83, 53, 48, 99, 110, 86, 122, 100, 71, 86, 107, 99, 50, 86, 121, 10, 100, 109, 108, + 106, 90, 88, 77, 117, 97, 87, 53, 48, 90, 87, 119, 117, 89, 50, 57, 116, 76, 51, 78, + 110, 101, 67, 57, 106, 90, 88, 74, 48, 97, 87, 90, 112, 89, 50, 70, 48, 97, 87, 57, + 117, 76, 51, 89, 122, 76, 51, 66, 106, 97, 50, 78, 121, 98, 68, 57, 106, 89, 84, 49, + 119, 10, 98, 71, 70, 48, 90, 109, 57, 121, 98, 83, 90, 108, 98, 109, 78, 118, 90, 71, + 108, 117, 90, 122, 49, 107, 90, 88, 73, 119, 72, 81, 89, 68, 86, 82, 48, 79, 66, 66, + 89, 69, 70, 74, 47, 121, 118, 104, 113, 87, 73, 65, 119, 74, 107, 57, 50, 72, 109, 122, + 99, 73, 107, 107, 121, 103, 10, 49, 65, 67, 65, 77, 65, 52, 71, 65, 49, 85, 100, 68, + 119, 69, 66, 47, 119, 81, 69, 65, 119, 73, 71, 119, 68, 65, 77, 66, 103, 78, 86, 72, + 82, 77, 66, 65, 102, 56, 69, 65, 106, 65, 65, 77, 73, 73, 67, 79, 119, 89, 74, 75, 111, + 90, 73, 104, 118, 104, 78, 65, 81, 48, 66, 10, 66, 73, 73, 67, 76, 68, 67, 67, 65, 105, + 103, 119, 72, 103, 89, 75, 75, 111, 90, 73, 104, 118, 104, 78, 65, 81, 48, 66, 65, 81, + 81, 81, 113, 102, 55, 48, 73, 56, 100, 103, 98, 75, 48, 120, 101, 109, 104, 70, 52, 76, + 76, 72, 51, 122, 67, 67, 65, 87, 85, 71, 67, 105, 113, 71, 10, 83, 73, 98, 52, 84, 81, + 69, 78, 65, 81, 73, 119, 103, 103, 70, 86, 77, 66, 65, 71, 67, 121, 113, 71, 83, 73, + 98, 52, 84, 81, 69, 78, 65, 81, 73, 66, 65, 103, 69, 76, 77, 66, 65, 71, 67, 121, 113, + 71, 83, 73, 98, 52, 84, 81, 69, 78, 65, 81, 73, 67, 65, 103, 69, 76, 10, 77, 66, 65, + 71, 67, 121, 113, 71, 83, 73, 98, 52, 84, 81, 69, 78, 65, 81, 73, 68, 65, 103, 69, 68, + 77, 66, 65, 71, 67, 121, 113, 71, 83, 73, 98, 52, 84, 81, 69, 78, 65, 81, 73, 69, 65, + 103, 69, 68, 77, 66, 69, 71, 67, 121, 113, 71, 83, 73, 98, 52, 84, 81, 69, 78, 10, 65, + 81, 73, 70, 65, 103, 73, 65, 47, 122, 65, 82, 66, 103, 115, 113, 104, 107, 105, 71, 43, + 69, 48, 66, 68, 81, 69, 67, 66, 103, 73, 67, 65, 80, 56, 119, 69, 65, 89, 76, 75, 111, + 90, 73, 104, 118, 104, 78, 65, 81, 48, 66, 65, 103, 99, 67, 65, 81, 69, 119, 69, 65, + 89, 76, 10, 75, 111, 90, 73, 104, 118, 104, 78, 65, 81, 48, 66, 65, 103, 103, 67, 65, + 81, 65, 119, 69, 65, 89, 76, 75, 111, 90, 73, 104, 118, 104, 78, 65, 81, 48, 66, 65, + 103, 107, 67, 65, 81, 65, 119, 69, 65, 89, 76, 75, 111, 90, 73, 104, 118, 104, 78, 65, + 81, 48, 66, 65, 103, 111, 67, 10, 65, 81, 65, 119, 69, 65, 89, 76, 75, 111, 90, 73, + 104, 118, 104, 78, 65, 81, 48, 66, 65, 103, 115, 67, 65, 81, 65, 119, 69, 65, 89, 76, + 75, 111, 90, 73, 104, 118, 104, 78, 65, 81, 48, 66, 65, 103, 119, 67, 65, 81, 65, 119, + 69, 65, 89, 76, 75, 111, 90, 73, 104, 118, 104, 78, 10, 65, 81, 48, 66, 65, 103, 48, + 67, 65, 81, 65, 119, 69, 65, 89, 76, 75, 111, 90, 73, 104, 118, 104, 78, 65, 81, 48, + 66, 65, 103, 52, 67, 65, 81, 65, 119, 69, 65, 89, 76, 75, 111, 90, 73, 104, 118, 104, + 78, 65, 81, 48, 66, 65, 103, 56, 67, 65, 81, 65, 119, 69, 65, 89, 76, 10, 75, 111, 90, + 73, 104, 118, 104, 78, 65, 81, 48, 66, 65, 104, 65, 67, 65, 81, 65, 119, 69, 65, 89, + 76, 75, 111, 90, 73, 104, 118, 104, 78, 65, 81, 48, 66, 65, 104, 69, 67, 65, 81, 48, + 119, 72, 119, 89, 76, 75, 111, 90, 73, 104, 118, 104, 78, 65, 81, 48, 66, 65, 104, 73, + 69, 10, 69, 65, 115, 76, 65, 119, 80, 47, 47, 119, 69, 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 119, 69, 65, 89, 75, 75, 111, 90, 73, 104, 118, 104, 78, 65, 81, 48, + 66, 65, 119, 81, 67, 65, 65, 65, 119, 70, 65, 89, 75, 75, 111, 90, 73, 104, 118, 104, + 78, 65, 81, 48, 66, 10, 66, 65, 81, 71, 65, 71, 66, 113, 65, 65, 65, 65, 77, 65, 56, + 71, 67, 105, 113, 71, 83, 73, 98, 52, 84, 81, 69, 78, 65, 81, 85, 75, 65, 81, 69, 119, + 72, 103, 89, 75, 75, 111, 90, 73, 104, 118, 104, 78, 65, 81, 48, 66, 66, 103, 81, 81, + 75, 68, 111, 43, 122, 117, 103, 104, 10, 56, 90, 99, 76, 65, 48, 79, 97, 51, 112, 82, + 107, 100, 68, 66, 69, 66, 103, 111, 113, 104, 107, 105, 71, 43, 69, 48, 66, 68, 81, 69, + 72, 77, 68, 89, 119, 69, 65, 89, 76, 75, 111, 90, 73, 104, 118, 104, 78, 65, 81, 48, + 66, 66, 119, 69, 66, 65, 102, 56, 119, 69, 65, 89, 76, 10, 75, 111, 90, 73, 104, 118, + 104, 78, 65, 81, 48, 66, 66, 119, 73, 66, 65, 81, 65, 119, 69, 65, 89, 76, 75, 111, 90, + 73, 104, 118, 104, 78, 65, 81, 48, 66, 66, 119, 77, 66, 65, 81, 65, 119, 67, 103, 89, + 73, 75, 111, 90, 73, 122, 106, 48, 69, 65, 119, 73, 68, 82, 119, 65, 119, 10, 82, 65, + 73, 103, 68, 112, 102, 100, 90, 109, 84, 78, 72, 98, 117, 81, 104, 81, 52, 115, 70, 76, + 74, 118, 121, 115, 50, 51, 99, 102, 113, 117, 100, 117, 56, 48, 89, 113, 73, 68, 86, + 110, 110, 119, 99, 79, 69, 67, 73, 70, 104, 84, 48, 81, 118, 71, 108, 106, 75, 81, 82, + 51, 99, 111, 10, 80, 106, 56, 104, 104, 72, 84, 57, 106, 117, 86, 97, 113, 100, 51, 84, + 114, 116, 77, 88, 68, 49, 80, 100, 72, 89, 88, 118, 10, 45, 45, 45, 45, 45, 69, 78, 68, + 32, 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, 10, 45, 45, 45, 45, + 45, 66, 69, 71, 73, 78, 32, 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, + 45, 10, 77, 73, 73, 67, 108, 106, 67, 67, 65, 106, 50, 103, 65, 119, 73, 66, 65, 103, + 73, 86, 65, 74, 86, 118, 88, 99, 50, 57, 71, 43, 72, 112, 81, 69, 110, 74, 49, 80, 81, + 122, 122, 103, 70, 88, 67, 57, 53, 85, 77, 65, 111, 71, 67, 67, 113, 71, 83, 77, 52, + 57, 66, 65, 77, 67, 10, 77, 71, 103, 120, 71, 106, 65, 89, 66, 103, 78, 86, 66, 65, 77, + 77, 69, 85, 108, 117, 100, 71, 86, 115, 73, 70, 78, 72, 87, 67, 66, 83, 98, 50, 57, 48, + 73, 69, 78, 66, 77, 82, 111, 119, 71, 65, 89, 68, 86, 81, 81, 75, 68, 66, 70, 74, 98, + 110, 82, 108, 98, 67, 66, 68, 10, 98, 51, 74, 119, 98, 51, 74, 104, 100, 71, 108, 118, + 98, 106, 69, 85, 77, 66, 73, 71, 65, 49, 85, 69, 66, 119, 119, 76, 85, 50, 70, 117, + 100, 71, 69, 103, 81, 50, 120, 104, 99, 109, 69, 120, 67, 122, 65, 74, 66, 103, 78, 86, + 66, 65, 103, 77, 65, 107, 78, 66, 77, 81, 115, 119, 10, 67, 81, 89, 68, 86, 81, 81, 71, + 69, 119, 74, 86, 85, 122, 65, 101, 70, 119, 48, 120, 79, 68, 65, 49, 77, 106, 69, 120, + 77, 68, 85, 119, 77, 84, 66, 97, 70, 119, 48, 122, 77, 122, 65, 49, 77, 106, 69, 120, + 77, 68, 85, 119, 77, 84, 66, 97, 77, 72, 65, 120, 73, 106, 65, 103, 10, 66, 103, 78, + 86, 66, 65, 77, 77, 71, 85, 108, 117, 100, 71, 86, 115, 73, 70, 78, 72, 87, 67, 66, 81, + 81, 48, 115, 103, 85, 71, 120, 104, 100, 71, 90, 118, 99, 109, 48, 103, 81, 48, 69, + 120, 71, 106, 65, 89, 66, 103, 78, 86, 66, 65, 111, 77, 69, 85, 108, 117, 100, 71, 86, + 115, 10, 73, 69, 78, 118, 99, 110, 66, 118, 99, 109, 70, 48, 97, 87, 57, 117, 77, 82, + 81, 119, 69, 103, 89, 68, 86, 81, 81, 72, 68, 65, 116, 84, 89, 87, 53, 48, 89, 83, 66, + 68, 98, 71, 70, 121, 89, 84, 69, 76, 77, 65, 107, 71, 65, 49, 85, 69, 67, 65, 119, 67, + 81, 48, 69, 120, 10, 67, 122, 65, 74, 66, 103, 78, 86, 66, 65, 89, 84, 65, 108, 86, 84, + 77, 70, 107, 119, 69, 119, 89, 72, 75, 111, 90, 73, 122, 106, 48, 67, 65, 81, 89, 73, + 75, 111, 90, 73, 122, 106, 48, 68, 65, 81, 99, 68, 81, 103, 65, 69, 78, 83, 66, 47, 55, + 116, 50, 49, 108, 88, 83, 79, 10, 50, 67, 117, 122, 112, 120, 119, 55, 52, 101, 74, 66, + 55, 50, 69, 121, 68, 71, 103, 87, 53, 114, 88, 67, 116, 120, 50, 116, 86, 84, 76, 113, + 54, 104, 75, 107, 54, 122, 43, 85, 105, 82, 90, 67, 110, 113, 82, 55, 112, 115, 79, + 118, 103, 113, 70, 101, 83, 120, 108, 109, 84, 108, 74, 108, 10, 101, 84, 109, 105, 50, + 87, 89, 122, 51, 113, 79, 66, 117, 122, 67, 66, 117, 68, 65, 102, 66, 103, 78, 86, 72, + 83, 77, 69, 71, 68, 65, 87, 103, 66, 81, 105, 90, 81, 122, 87, 87, 112, 48, 48, 105, + 102, 79, 68, 116, 74, 86, 83, 118, 49, 65, 98, 79, 83, 99, 71, 114, 68, 66, 83, 10, 66, + 103, 78, 86, 72, 82, 56, 69, 83, 122, 66, 74, 77, 69, 101, 103, 82, 97, 66, 68, 104, + 107, 70, 111, 100, 72, 82, 119, 99, 122, 111, 118, 76, 50, 78, 108, 99, 110, 82, 112, + 90, 109, 108, 106, 89, 88, 82, 108, 99, 121, 53, 48, 99, 110, 86, 122, 100, 71, 86, + 107, 99, 50, 86, 121, 10, 100, 109, 108, 106, 90, 88, 77, 117, 97, 87, 53, 48, 90, 87, + 119, 117, 89, 50, 57, 116, 76, 48, 108, 117, 100, 71, 86, 115, 85, 48, 100, 89, 85, + 109, 57, 118, 100, 69, 78, 66, 76, 109, 82, 108, 99, 106, 65, 100, 66, 103, 78, 86, 72, + 81, 52, 69, 70, 103, 81, 85, 108, 87, 57, 100, 10, 122, 98, 48, 98, 52, 101, 108, 65, + 83, 99, 110, 85, 57, 68, 80, 79, 65, 86, 99, 76, 51, 108, 81, 119, 68, 103, 89, 68, 86, + 82, 48, 80, 65, 81, 72, 47, 66, 65, 81, 68, 65, 103, 69, 71, 77, 66, 73, 71, 65, 49, + 85, 100, 69, 119, 69, 66, 47, 119, 81, 73, 77, 65, 89, 66, 10, 65, 102, 56, 67, 65, 81, + 65, 119, 67, 103, 89, 73, 75, 111, 90, 73, 122, 106, 48, 69, 65, 119, 73, 68, 82, 119, + 65, 119, 82, 65, 73, 103, 88, 115, 86, 107, 105, 48, 119, 43, 105, 54, 86, 89, 71, 87, + 51, 85, 70, 47, 50, 50, 117, 97, 88, 101, 48, 89, 74, 68, 106, 49, 85, 101, 10, 110, + 65, 43, 84, 106, 68, 49, 97, 105, 53, 99, 67, 73, 67, 89, 98, 49, 83, 65, 109, 68, 53, + 120, 107, 102, 84, 86, 112, 118, 111, 52, 85, 111, 121, 105, 83, 89, 120, 114, 68, 87, + 76, 109, 85, 82, 52, 67, 73, 57, 78, 75, 121, 102, 80, 78, 43, 10, 45, 45, 45, 45, 45, + 69, 78, 68, 32, 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, 10, 45, + 45, 45, 45, 45, 66, 69, 71, 73, 78, 32, 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, + 45, 45, 45, 45, 10, 77, 73, 73, 67, 106, 122, 67, 67, 65, 106, 83, 103, 65, 119, 73, + 66, 65, 103, 73, 85, 73, 109, 85, 77, 49, 108, 113, 100, 78, 73, 110, 122, 103, 55, 83, + 86, 85, 114, 57, 81, 71, 122, 107, 110, 66, 113, 119, 119, 67, 103, 89, 73, 75, 111, + 90, 73, 122, 106, 48, 69, 65, 119, 73, 119, 10, 97, 68, 69, 97, 77, 66, 103, 71, 65, + 49, 85, 69, 65, 119, 119, 82, 83, 87, 53, 48, 90, 87, 119, 103, 85, 48, 100, 89, 73, + 70, 74, 118, 98, 51, 81, 103, 81, 48, 69, 120, 71, 106, 65, 89, 66, 103, 78, 86, 66, + 65, 111, 77, 69, 85, 108, 117, 100, 71, 86, 115, 73, 69, 78, 118, 10, 99, 110, 66, 118, + 99, 109, 70, 48, 97, 87, 57, 117, 77, 82, 81, 119, 69, 103, 89, 68, 86, 81, 81, 72, 68, + 65, 116, 84, 89, 87, 53, 48, 89, 83, 66, 68, 98, 71, 70, 121, 89, 84, 69, 76, 77, 65, + 107, 71, 65, 49, 85, 69, 67, 65, 119, 67, 81, 48, 69, 120, 67, 122, 65, 74, 10, 66, + 103, 78, 86, 66, 65, 89, 84, 65, 108, 86, 84, 77, 66, 52, 88, 68, 84, 69, 52, 77, 68, + 85, 121, 77, 84, 69, 119, 78, 68, 85, 120, 77, 70, 111, 88, 68, 84, 81, 53, 77, 84, 73, + 122, 77, 84, 73, 122, 78, 84, 107, 49, 79, 86, 111, 119, 97, 68, 69, 97, 77, 66, 103, + 71, 10, 65, 49, 85, 69, 65, 119, 119, 82, 83, 87, 53, 48, 90, 87, 119, 103, 85, 48, + 100, 89, 73, 70, 74, 118, 98, 51, 81, 103, 81, 48, 69, 120, 71, 106, 65, 89, 66, 103, + 78, 86, 66, 65, 111, 77, 69, 85, 108, 117, 100, 71, 86, 115, 73, 69, 78, 118, 99, 110, + 66, 118, 99, 109, 70, 48, 10, 97, 87, 57, 117, 77, 82, 81, 119, 69, 103, 89, 68, 86, + 81, 81, 72, 68, 65, 116, 84, 89, 87, 53, 48, 89, 83, 66, 68, 98, 71, 70, 121, 89, 84, + 69, 76, 77, 65, 107, 71, 65, 49, 85, 69, 67, 65, 119, 67, 81, 48, 69, 120, 67, 122, 65, + 74, 66, 103, 78, 86, 66, 65, 89, 84, 10, 65, 108, 86, 84, 77, 70, 107, 119, 69, 119, + 89, 72, 75, 111, 90, 73, 122, 106, 48, 67, 65, 81, 89, 73, 75, 111, 90, 73, 122, 106, + 48, 68, 65, 81, 99, 68, 81, 103, 65, 69, 67, 54, 110, 69, 119, 77, 68, 73, 89, 90, 79, + 106, 47, 105, 80, 87, 115, 67, 122, 97, 69, 75, 105, 55, 10, 49, 79, 105, 79, 83, 76, + 82, 70, 104, 87, 71, 106, 98, 110, 66, 86, 74, 102, 86, 110, 107, 89, 52, 117, 51, 73, + 106, 107, 68, 89, 89, 76, 48, 77, 120, 79, 52, 109, 113, 115, 121, 89, 106, 108, 66, + 97, 108, 84, 86, 89, 120, 70, 80, 50, 115, 74, 66, 75, 53, 122, 108, 75, 79, 66, 10, + 117, 122, 67, 66, 117, 68, 65, 102, 66, 103, 78, 86, 72, 83, 77, 69, 71, 68, 65, 87, + 103, 66, 81, 105, 90, 81, 122, 87, 87, 112, 48, 48, 105, 102, 79, 68, 116, 74, 86, 83, + 118, 49, 65, 98, 79, 83, 99, 71, 114, 68, 66, 83, 66, 103, 78, 86, 72, 82, 56, 69, 83, + 122, 66, 74, 10, 77, 69, 101, 103, 82, 97, 66, 68, 104, 107, 70, 111, 100, 72, 82, 119, + 99, 122, 111, 118, 76, 50, 78, 108, 99, 110, 82, 112, 90, 109, 108, 106, 89, 88, 82, + 108, 99, 121, 53, 48, 99, 110, 86, 122, 100, 71, 86, 107, 99, 50, 86, 121, 100, 109, + 108, 106, 90, 88, 77, 117, 97, 87, 53, 48, 10, 90, 87, 119, 117, 89, 50, 57, 116, 76, + 48, 108, 117, 100, 71, 86, 115, 85, 48, 100, 89, 85, 109, 57, 118, 100, 69, 78, 66, 76, + 109, 82, 108, 99, 106, 65, 100, 66, 103, 78, 86, 72, 81, 52, 69, 70, 103, 81, 85, 73, + 109, 85, 77, 49, 108, 113, 100, 78, 73, 110, 122, 103, 55, 83, 86, 10, 85, 114, 57, 81, + 71, 122, 107, 110, 66, 113, 119, 119, 68, 103, 89, 68, 86, 82, 48, 80, 65, 81, 72, 47, + 66, 65, 81, 68, 65, 103, 69, 71, 77, 66, 73, 71, 65, 49, 85, 100, 69, 119, 69, 66, 47, + 119, 81, 73, 77, 65, 89, 66, 65, 102, 56, 67, 65, 81, 69, 119, 67, 103, 89, 73, 10, 75, + 111, 90, 73, 122, 106, 48, 69, 65, 119, 73, 68, 83, 81, 65, 119, 82, 103, 73, 104, 65, + 79, 87, 47, 53, 81, 107, 82, 43, 83, 57, 67, 105, 83, 68, 99, 78, 111, 111, 119, 76, + 117, 80, 82, 76, 115, 87, 71, 102, 47, 89, 105, 55, 71, 83, 88, 57, 52, 66, 103, 119, + 84, 119, 103, 10, 65, 105, 69, 65, 52, 74, 48, 108, 114, 72, 111, 77, 115, 43, 88, 111, + 53, 111, 47, 115, 88, 54, 79, 57, 81, 87, 120, 72, 82, 65, 118, 90, 85, 71, 79, 100, + 82, 81, 55, 99, 118, 113, 82, 88, 97, 113, 73, 61, 10, 45, 45, 45, 45, 45, 69, 78, 68, + 32, 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, 10, 0, + ]; + + let collateral = Collateral { + major_version: 1, + minor_version: 0, + tee_type: 0, + pck_crl_issuer_chain: [ + 45, 45, 45, 45, 45, 66, 69, 71, 73, 78, 32, 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, + 69, 45, 45, 45, 45, 45, 10, 77, 73, 73, 67, 108, 106, 67, 67, 65, 106, 50, 103, 65, + 119, 73, 66, 65, 103, 73, 86, 65, 74, 86, 118, 88, 99, 50, 57, 71, 43, 72, 112, 81, + 69, 110, 74, 49, 80, 81, 122, 122, 103, 70, 88, 67, 57, 53, 85, 77, 65, 111, 71, + 67, 67, 113, 71, 83, 77, 52, 57, 66, 65, 77, 67, 10, 77, 71, 103, 120, 71, 106, 65, + 89, 66, 103, 78, 86, 66, 65, 77, 77, 69, 85, 108, 117, 100, 71, 86, 115, 73, 70, + 78, 72, 87, 67, 66, 83, 98, 50, 57, 48, 73, 69, 78, 66, 77, 82, 111, 119, 71, 65, + 89, 68, 86, 81, 81, 75, 68, 66, 70, 74, 98, 110, 82, 108, 98, 67, 66, 68, 10, 98, + 51, 74, 119, 98, 51, 74, 104, 100, 71, 108, 118, 98, 106, 69, 85, 77, 66, 73, 71, + 65, 49, 85, 69, 66, 119, 119, 76, 85, 50, 70, 117, 100, 71, 69, 103, 81, 50, 120, + 104, 99, 109, 69, 120, 67, 122, 65, 74, 66, 103, 78, 86, 66, 65, 103, 77, 65, 107, + 78, 66, 77, 81, 115, 119, 10, 67, 81, 89, 68, 86, 81, 81, 71, 69, 119, 74, 86, 85, + 122, 65, 101, 70, 119, 48, 120, 79, 68, 65, 49, 77, 106, 69, 120, 77, 68, 85, 119, + 77, 84, 66, 97, 70, 119, 48, 122, 77, 122, 65, 49, 77, 106, 69, 120, 77, 68, 85, + 119, 77, 84, 66, 97, 77, 72, 65, 120, 73, 106, 65, 103, 10, 66, 103, 78, 86, 66, + 65, 77, 77, 71, 85, 108, 117, 100, 71, 86, 115, 73, 70, 78, 72, 87, 67, 66, 81, 81, + 48, 115, 103, 85, 71, 120, 104, 100, 71, 90, 118, 99, 109, 48, 103, 81, 48, 69, + 120, 71, 106, 65, 89, 66, 103, 78, 86, 66, 65, 111, 77, 69, 85, 108, 117, 100, 71, + 86, 115, 10, 73, 69, 78, 118, 99, 110, 66, 118, 99, 109, 70, 48, 97, 87, 57, 117, + 77, 82, 81, 119, 69, 103, 89, 68, 86, 81, 81, 72, 68, 65, 116, 84, 89, 87, 53, 48, + 89, 83, 66, 68, 98, 71, 70, 121, 89, 84, 69, 76, 77, 65, 107, 71, 65, 49, 85, 69, + 67, 65, 119, 67, 81, 48, 69, 120, 10, 67, 122, 65, 74, 66, 103, 78, 86, 66, 65, 89, + 84, 65, 108, 86, 84, 77, 70, 107, 119, 69, 119, 89, 72, 75, 111, 90, 73, 122, 106, + 48, 67, 65, 81, 89, 73, 75, 111, 90, 73, 122, 106, 48, 68, 65, 81, 99, 68, 81, 103, + 65, 69, 78, 83, 66, 47, 55, 116, 50, 49, 108, 88, 83, 79, 10, 50, 67, 117, 122, + 112, 120, 119, 55, 52, 101, 74, 66, 55, 50, 69, 121, 68, 71, 103, 87, 53, 114, 88, + 67, 116, 120, 50, 116, 86, 84, 76, 113, 54, 104, 75, 107, 54, 122, 43, 85, 105, 82, + 90, 67, 110, 113, 82, 55, 112, 115, 79, 118, 103, 113, 70, 101, 83, 120, 108, 109, + 84, 108, 74, 108, 10, 101, 84, 109, 105, 50, 87, 89, 122, 51, 113, 79, 66, 117, + 122, 67, 66, 117, 68, 65, 102, 66, 103, 78, 86, 72, 83, 77, 69, 71, 68, 65, 87, + 103, 66, 81, 105, 90, 81, 122, 87, 87, 112, 48, 48, 105, 102, 79, 68, 116, 74, 86, + 83, 118, 49, 65, 98, 79, 83, 99, 71, 114, 68, 66, 83, 10, 66, 103, 78, 86, 72, 82, + 56, 69, 83, 122, 66, 74, 77, 69, 101, 103, 82, 97, 66, 68, 104, 107, 70, 111, 100, + 72, 82, 119, 99, 122, 111, 118, 76, 50, 78, 108, 99, 110, 82, 112, 90, 109, 108, + 106, 89, 88, 82, 108, 99, 121, 53, 48, 99, 110, 86, 122, 100, 71, 86, 107, 99, 50, + 86, 121, 10, 100, 109, 108, 106, 90, 88, 77, 117, 97, 87, 53, 48, 90, 87, 119, 117, + 89, 50, 57, 116, 76, 48, 108, 117, 100, 71, 86, 115, 85, 48, 100, 89, 85, 109, 57, + 118, 100, 69, 78, 66, 76, 109, 82, 108, 99, 106, 65, 100, 66, 103, 78, 86, 72, 81, + 52, 69, 70, 103, 81, 85, 108, 87, 57, 100, 10, 122, 98, 48, 98, 52, 101, 108, 65, + 83, 99, 110, 85, 57, 68, 80, 79, 65, 86, 99, 76, 51, 108, 81, 119, 68, 103, 89, 68, + 86, 82, 48, 80, 65, 81, 72, 47, 66, 65, 81, 68, 65, 103, 69, 71, 77, 66, 73, 71, + 65, 49, 85, 100, 69, 119, 69, 66, 47, 119, 81, 73, 77, 65, 89, 66, 10, 65, 102, 56, + 67, 65, 81, 65, 119, 67, 103, 89, 73, 75, 111, 90, 73, 122, 106, 48, 69, 65, 119, + 73, 68, 82, 119, 65, 119, 82, 65, 73, 103, 88, 115, 86, 107, 105, 48, 119, 43, 105, + 54, 86, 89, 71, 87, 51, 85, 70, 47, 50, 50, 117, 97, 88, 101, 48, 89, 74, 68, 106, + 49, 85, 101, 10, 110, 65, 43, 84, 106, 68, 49, 97, 105, 53, 99, 67, 73, 67, 89, 98, + 49, 83, 65, 109, 68, 53, 120, 107, 102, 84, 86, 112, 118, 111, 52, 85, 111, 121, + 105, 83, 89, 120, 114, 68, 87, 76, 109, 85, 82, 52, 67, 73, 57, 78, 75, 121, 102, + 80, 78, 43, 10, 45, 45, 45, 45, 45, 69, 78, 68, 32, 67, 69, 82, 84, 73, 70, 73, 67, + 65, 84, 69, 45, 45, 45, 45, 45, 10, 45, 45, 45, 45, 45, 66, 69, 71, 73, 78, 32, 67, + 69, 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, 10, 77, 73, 73, 67, + 106, 122, 67, 67, 65, 106, 83, 103, 65, 119, 73, 66, 65, 103, 73, 85, 73, 109, 85, + 77, 49, 108, 113, 100, 78, 73, 110, 122, 103, 55, 83, 86, 85, 114, 57, 81, 71, 122, + 107, 110, 66, 113, 119, 119, 67, 103, 89, 73, 75, 111, 90, 73, 122, 106, 48, 69, + 65, 119, 73, 119, 10, 97, 68, 69, 97, 77, 66, 103, 71, 65, 49, 85, 69, 65, 119, + 119, 82, 83, 87, 53, 48, 90, 87, 119, 103, 85, 48, 100, 89, 73, 70, 74, 118, 98, + 51, 81, 103, 81, 48, 69, 120, 71, 106, 65, 89, 66, 103, 78, 86, 66, 65, 111, 77, + 69, 85, 108, 117, 100, 71, 86, 115, 73, 69, 78, 118, 10, 99, 110, 66, 118, 99, 109, + 70, 48, 97, 87, 57, 117, 77, 82, 81, 119, 69, 103, 89, 68, 86, 81, 81, 72, 68, 65, + 116, 84, 89, 87, 53, 48, 89, 83, 66, 68, 98, 71, 70, 121, 89, 84, 69, 76, 77, 65, + 107, 71, 65, 49, 85, 69, 67, 65, 119, 67, 81, 48, 69, 120, 67, 122, 65, 74, 10, 66, + 103, 78, 86, 66, 65, 89, 84, 65, 108, 86, 84, 77, 66, 52, 88, 68, 84, 69, 52, 77, + 68, 85, 121, 77, 84, 69, 119, 78, 68, 85, 120, 77, 70, 111, 88, 68, 84, 81, 53, 77, + 84, 73, 122, 77, 84, 73, 122, 78, 84, 107, 49, 79, 86, 111, 119, 97, 68, 69, 97, + 77, 66, 103, 71, 10, 65, 49, 85, 69, 65, 119, 119, 82, 83, 87, 53, 48, 90, 87, 119, + 103, 85, 48, 100, 89, 73, 70, 74, 118, 98, 51, 81, 103, 81, 48, 69, 120, 71, 106, + 65, 89, 66, 103, 78, 86, 66, 65, 111, 77, 69, 85, 108, 117, 100, 71, 86, 115, 73, + 69, 78, 118, 99, 110, 66, 118, 99, 109, 70, 48, 10, 97, 87, 57, 117, 77, 82, 81, + 119, 69, 103, 89, 68, 86, 81, 81, 72, 68, 65, 116, 84, 89, 87, 53, 48, 89, 83, 66, + 68, 98, 71, 70, 121, 89, 84, 69, 76, 77, 65, 107, 71, 65, 49, 85, 69, 67, 65, 119, + 67, 81, 48, 69, 120, 67, 122, 65, 74, 66, 103, 78, 86, 66, 65, 89, 84, 10, 65, 108, + 86, 84, 77, 70, 107, 119, 69, 119, 89, 72, 75, 111, 90, 73, 122, 106, 48, 67, 65, + 81, 89, 73, 75, 111, 90, 73, 122, 106, 48, 68, 65, 81, 99, 68, 81, 103, 65, 69, 67, + 54, 110, 69, 119, 77, 68, 73, 89, 90, 79, 106, 47, 105, 80, 87, 115, 67, 122, 97, + 69, 75, 105, 55, 10, 49, 79, 105, 79, 83, 76, 82, 70, 104, 87, 71, 106, 98, 110, + 66, 86, 74, 102, 86, 110, 107, 89, 52, 117, 51, 73, 106, 107, 68, 89, 89, 76, 48, + 77, 120, 79, 52, 109, 113, 115, 121, 89, 106, 108, 66, 97, 108, 84, 86, 89, 120, + 70, 80, 50, 115, 74, 66, 75, 53, 122, 108, 75, 79, 66, 10, 117, 122, 67, 66, 117, + 68, 65, 102, 66, 103, 78, 86, 72, 83, 77, 69, 71, 68, 65, 87, 103, 66, 81, 105, 90, + 81, 122, 87, 87, 112, 48, 48, 105, 102, 79, 68, 116, 74, 86, 83, 118, 49, 65, 98, + 79, 83, 99, 71, 114, 68, 66, 83, 66, 103, 78, 86, 72, 82, 56, 69, 83, 122, 66, 74, + 10, 77, 69, 101, 103, 82, 97, 66, 68, 104, 107, 70, 111, 100, 72, 82, 119, 99, 122, + 111, 118, 76, 50, 78, 108, 99, 110, 82, 112, 90, 109, 108, 106, 89, 88, 82, 108, + 99, 121, 53, 48, 99, 110, 86, 122, 100, 71, 86, 107, 99, 50, 86, 121, 100, 109, + 108, 106, 90, 88, 77, 117, 97, 87, 53, 48, 10, 90, 87, 119, 117, 89, 50, 57, 116, + 76, 48, 108, 117, 100, 71, 86, 115, 85, 48, 100, 89, 85, 109, 57, 118, 100, 69, 78, + 66, 76, 109, 82, 108, 99, 106, 65, 100, 66, 103, 78, 86, 72, 81, 52, 69, 70, 103, + 81, 85, 73, 109, 85, 77, 49, 108, 113, 100, 78, 73, 110, 122, 103, 55, 83, 86, 10, + 85, 114, 57, 81, 71, 122, 107, 110, 66, 113, 119, 119, 68, 103, 89, 68, 86, 82, 48, + 80, 65, 81, 72, 47, 66, 65, 81, 68, 65, 103, 69, 71, 77, 66, 73, 71, 65, 49, 85, + 100, 69, 119, 69, 66, 47, 119, 81, 73, 77, 65, 89, 66, 65, 102, 56, 67, 65, 81, 69, + 119, 67, 103, 89, 73, 10, 75, 111, 90, 73, 122, 106, 48, 69, 65, 119, 73, 68, 83, + 81, 65, 119, 82, 103, 73, 104, 65, 79, 87, 47, 53, 81, 107, 82, 43, 83, 57, 67, + 105, 83, 68, 99, 78, 111, 111, 119, 76, 117, 80, 82, 76, 115, 87, 71, 102, 47, 89, + 105, 55, 71, 83, 88, 57, 52, 66, 103, 119, 84, 119, 103, 10, 65, 105, 69, 65, 52, + 74, 48, 108, 114, 72, 111, 77, 115, 43, 88, 111, 53, 111, 47, 115, 88, 54, 79, 57, + 81, 87, 120, 72, 82, 65, 118, 90, 85, 71, 79, 100, 82, 81, 55, 99, 118, 113, 82, + 88, 97, 113, 73, 61, 10, 45, 45, 45, 45, 45, 69, 78, 68, 32, 67, 69, 82, 84, 73, + 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, 10, 0, + ] + .into(), + root_ca_crl: [ + 45, 45, 45, 45, 45, 66, 69, 71, 73, 78, 32, 88, 53, 48, 57, 32, 67, 82, 76, 45, 45, + 45, 45, 45, 10, 77, 73, 73, 66, 73, 84, 67, 66, 121, 65, 73, 66, 65, 84, 65, 75, + 66, 103, 103, 113, 104, 107, 106, 79, 80, 81, 81, 68, 65, 106, 66, 111, 77, 82, + 111, 119, 71, 65, 89, 68, 86, 81, 81, 68, 68, 66, 70, 74, 98, 110, 82, 108, 98, 67, + 66, 84, 82, 49, 103, 103, 85, 109, 57, 118, 10, 100, 67, 66, 68, 81, 84, 69, 97, + 77, 66, 103, 71, 65, 49, 85, 69, 67, 103, 119, 82, 83, 87, 53, 48, 90, 87, 119, + 103, 81, 50, 57, 121, 99, 71, 57, 121, 89, 88, 82, 112, 98, 50, 52, 120, 70, 68, + 65, 83, 66, 103, 78, 86, 66, 65, 99, 77, 67, 49, 78, 104, 98, 110, 82, 104, 10, 73, + 69, 78, 115, 89, 88, 74, 104, 77, 81, 115, 119, 67, 81, 89, 68, 86, 81, 81, 73, 68, + 65, 74, 68, 81, 84, 69, 76, 77, 65, 107, 71, 65, 49, 85, 69, 66, 104, 77, 67, 86, + 86, 77, 88, 68, 84, 73, 122, 77, 68, 81, 119, 77, 122, 69, 119, 77, 106, 73, 49, + 77, 86, 111, 88, 10, 68, 84, 73, 48, 77, 68, 81, 119, 77, 106, 69, 119, 77, 106, + 73, 49, 77, 86, 113, 103, 76, 122, 65, 116, 77, 65, 111, 71, 65, 49, 85, 100, 70, + 65, 81, 68, 65, 103, 69, 66, 77, 66, 56, 71, 65, 49, 85, 100, 73, 119, 81, 89, 77, + 66, 97, 65, 70, 67, 74, 108, 68, 78, 90, 97, 10, 110, 84, 83, 74, 56, 52, 79, 48, + 108, 86, 75, 47, 85, 66, 115, 53, 74, 119, 97, 115, 77, 65, 111, 71, 67, 67, 113, + 71, 83, 77, 52, 57, 66, 65, 77, 67, 65, 48, 103, 65, 77, 69, 85, 67, 73, 70, 70, + 88, 102, 85, 102, 90, 43, 54, 70, 88, 116, 108, 56, 101, 116, 102, 82, 108, 10, + 101, 55, 120, 101, 86, 115, 121, 118, 99, 49, 111, 68, 56, 98, 108, 106, 49, 119, + 83, 65, 87, 114, 69, 89, 65, 105, 69, 65, 107, 53, 65, 86, 55, 66, 89, 50, 53, 43, + 114, 54, 88, 48, 74, 115, 72, 107, 65, 109, 82, 56, 90, 122, 69, 121, 116, 111, 85, + 77, 113, 57, 97, 77, 55, 50, 10, 117, 116, 100, 111, 75, 103, 77, 61, 10, 45, 45, + 45, 45, 45, 69, 78, 68, 32, 88, 53, 48, 57, 32, 67, 82, 76, 45, 45, 45, 45, 45, 10, + 0, + ] + .into(), + pck_crl: [ + 45, 45, 45, 45, 45, 66, 69, 71, 73, 78, 32, 88, 53, 48, 57, 32, 67, 82, 76, 45, 45, + 45, 45, 45, 10, 77, 73, 73, 75, 89, 84, 67, 67, 67, 103, 103, 67, 65, 81, 69, 119, + 67, 103, 89, 73, 75, 111, 90, 73, 122, 106, 48, 69, 65, 119, 73, 119, 99, 68, 69, + 105, 77, 67, 65, 71, 65, 49, 85, 69, 65, 119, 119, 90, 83, 87, 53, 48, 90, 87, 119, + 103, 85, 48, 100, 89, 73, 70, 66, 68, 10, 83, 121, 66, 81, 98, 71, 70, 48, 90, 109, + 57, 121, 98, 83, 66, 68, 81, 84, 69, 97, 77, 66, 103, 71, 65, 49, 85, 69, 67, 103, + 119, 82, 83, 87, 53, 48, 90, 87, 119, 103, 81, 50, 57, 121, 99, 71, 57, 121, 89, + 88, 82, 112, 98, 50, 52, 120, 70, 68, 65, 83, 66, 103, 78, 86, 10, 66, 65, 99, 77, + 67, 49, 78, 104, 98, 110, 82, 104, 73, 69, 78, 115, 89, 88, 74, 104, 77, 81, 115, + 119, 67, 81, 89, 68, 86, 81, 81, 73, 68, 65, 74, 68, 81, 84, 69, 76, 77, 65, 107, + 71, 65, 49, 85, 69, 66, 104, 77, 67, 86, 86, 77, 88, 68, 84, 73, 122, 77, 68, 89, + 120, 10, 77, 106, 73, 120, 77, 68, 69, 119, 77, 49, 111, 88, 68, 84, 73, 122, 77, + 68, 99, 120, 77, 106, 73, 120, 77, 68, 69, 119, 77, 49, 111, 119, 103, 103, 107, + 48, 77, 68, 77, 67, 70, 71, 47, 68, 84, 108, 65, 106, 53, 121, 105, 83, 78, 68, 88, + 87, 71, 113, 83, 52, 80, 71, 71, 66, 10, 90, 113, 48, 49, 70, 119, 48, 121, 77, + 122, 65, 50, 77, 84, 73, 121, 77, 84, 65, 120, 77, 68, 78, 97, 77, 65, 119, 119, + 67, 103, 89, 68, 86, 82, 48, 86, 66, 65, 77, 75, 65, 81, 69, 119, 78, 65, 73, 86, + 65, 79, 43, 117, 98, 112, 99, 86, 47, 75, 69, 55, 104, 43, 77, 122, 10, 54, 67, 89, + 101, 49, 116, 109, 81, 113, 83, 97, 116, 70, 119, 48, 121, 77, 122, 65, 50, 77, 84, + 73, 121, 77, 84, 65, 120, 77, 68, 78, 97, 77, 65, 119, 119, 67, 103, 89, 68, 86, + 82, 48, 86, 66, 65, 77, 75, 65, 81, 69, 119, 78, 65, 73, 86, 65, 80, 49, 103, 104, + 107, 104, 105, 10, 110, 76, 112, 122, 66, 52, 116, 78, 83, 83, 57, 76, 80, 113, + 100, 66, 114, 81, 106, 78, 70, 119, 48, 121, 77, 122, 65, 50, 77, 84, 73, 121, 77, + 84, 65, 120, 77, 68, 78, 97, 77, 65, 119, 119, 67, 103, 89, 68, 86, 82, 48, 86, 66, + 65, 77, 75, 65, 81, 69, 119, 78, 65, 73, 86, 10, 65, 73, 114, 53, 74, 66, 104, 79, + 72, 86, 114, 57, 51, 88, 80, 68, 49, 106, 111, 83, 57, 101, 105, 49, 99, 51, 53, + 87, 70, 119, 48, 121, 77, 122, 65, 50, 77, 84, 73, 121, 77, 84, 65, 120, 77, 68, + 78, 97, 77, 65, 119, 119, 67, 103, 89, 68, 86, 82, 48, 86, 66, 65, 77, 75, 10, 65, + 81, 69, 119, 78, 65, 73, 86, 65, 76, 69, 108, 101, 88, 106, 80, 113, 99, 122, 100, + 66, 49, 109, 114, 43, 77, 88, 75, 99, 118, 114, 106, 112, 52, 113, 98, 70, 119, 48, + 121, 77, 122, 65, 50, 77, 84, 73, 121, 77, 84, 65, 120, 77, 68, 78, 97, 77, 65, + 119, 119, 67, 103, 89, 68, 10, 86, 82, 48, 86, 66, 65, 77, 75, 65, 81, 69, 119, 77, + 119, 73, 85, 100, 80, 54, 109, 70, 75, 108, 121, 118, 103, 52, 111, 81, 47, 73, 70, + 109, 68, 87, 66, 72, 116, 104, 121, 43, 98, 77, 88, 68, 84, 73, 122, 77, 68, 89, + 120, 77, 106, 73, 120, 77, 68, 69, 119, 77, 49, 111, 119, 10, 68, 68, 65, 75, 66, + 103, 78, 86, 72, 82, 85, 69, 65, 119, 111, 66, 65, 84, 65, 48, 65, 104, 85, 65, 43, + 99, 84, 118, 86, 114, 79, 114, 83, 78, 86, 51, 52, 81, 105, 54, 55, 102, 83, 47, + 105, 65, 70, 67, 70, 76, 107, 88, 68, 84, 73, 122, 77, 68, 89, 120, 77, 106, 73, + 120, 10, 77, 68, 69, 119, 77, 49, 111, 119, 68, 68, 65, 75, 66, 103, 78, 86, 72, + 82, 85, 69, 65, 119, 111, 66, 65, 84, 65, 122, 65, 104, 81, 72, 72, 101, 66, 51, + 106, 53, 53, 102, 120, 80, 75, 72, 106, 122, 68, 87, 115, 72, 121, 97, 77, 79, 97, + 122, 67, 120, 99, 78, 77, 106, 77, 119, 10, 78, 106, 69, 121, 77, 106, 69, 119, 77, + 84, 65, 122, 87, 106, 65, 77, 77, 65, 111, 71, 65, 49, 85, 100, 70, 81, 81, 68, 67, + 103, 69, 66, 77, 68, 81, 67, 70, 81, 68, 78, 52, 107, 74, 80, 108, 121, 122, 113, + 108, 80, 56, 106, 109, 84, 102, 48, 50, 65, 119, 108, 65, 112, 51, 87, 10, 67, 120, + 99, 78, 77, 106, 77, 119, 78, 106, 69, 121, 77, 106, 69, 119, 77, 84, 65, 122, 87, + 106, 65, 77, 77, 65, 111, 71, 65, 49, 85, 100, 70, 81, 81, 68, 67, 103, 69, 66, 77, + 68, 77, 67, 70, 71, 119, 122, 71, 101, 85, 81, 109, 50, 82, 81, 102, 84, 122, 120, + 69, 121, 122, 103, 10, 65, 48, 110, 118, 85, 110, 77, 90, 70, 119, 48, 121, 77, + 122, 65, 50, 77, 84, 73, 121, 77, 84, 65, 120, 77, 68, 78, 97, 77, 65, 119, 119, + 67, 103, 89, 68, 86, 82, 48, 86, 66, 65, 77, 75, 65, 81, 69, 119, 78, 65, 73, 86, + 65, 78, 56, 73, 49, 49, 97, 50, 97, 110, 83, 88, 10, 57, 68, 116, 98, 116, 89, 114, + 97, 66, 78, 80, 48, 57, 54, 107, 51, 70, 119, 48, 121, 77, 122, 65, 50, 77, 84, 73, + 121, 77, 84, 65, 120, 77, 68, 78, 97, 77, 65, 119, 119, 67, 103, 89, 68, 86, 82, + 48, 86, 66, 65, 77, 75, 65, 81, 69, 119, 77, 119, 73, 85, 75, 75, 57, 73, 10, 87, + 50, 122, 50, 102, 107, 67, 97, 79, 100, 88, 76, 87, 117, 53, 70, 109, 80, 101, 111, + 43, 110, 115, 88, 68, 84, 73, 122, 77, 68, 89, 120, 77, 106, 73, 120, 77, 68, 69, + 119, 77, 49, 111, 119, 68, 68, 65, 75, 66, 103, 78, 86, 72, 82, 85, 69, 65, 119, + 111, 66, 65, 84, 65, 48, 10, 65, 104, 85, 65, 43, 52, 115, 116, 114, 115, 67, 83, + 121, 116, 113, 75, 113, 98, 120, 80, 56, 118, 72, 67, 68, 81, 78, 71, 90, 111, 119, + 88, 68, 84, 73, 122, 77, 68, 89, 120, 77, 106, 73, 120, 77, 68, 69, 119, 77, 49, + 111, 119, 68, 68, 65, 75, 66, 103, 78, 86, 72, 82, 85, 69, 10, 65, 119, 111, 66, + 65, 84, 65, 48, 65, 104, 85, 65, 122, 85, 104, 81, 114, 70, 75, 57, 122, 71, 109, + 109, 112, 118, 66, 89, 121, 76, 120, 88, 117, 57, 67, 49, 43, 71, 81, 88, 68, 84, + 73, 122, 77, 68, 89, 120, 77, 106, 73, 120, 77, 68, 69, 119, 77, 49, 111, 119, 68, + 68, 65, 75, 10, 66, 103, 78, 86, 72, 82, 85, 69, 65, 119, 111, 66, 65, 84, 65, 48, + 65, 104, 85, 65, 109, 85, 51, 84, 90, 109, 57, 83, 100, 102, 117, 65, 88, 53, 88, + 100, 65, 114, 49, 81, 121, 121, 90, 53, 50, 75, 48, 88, 68, 84, 73, 122, 77, 68, + 89, 120, 77, 106, 73, 120, 77, 68, 69, 119, 10, 77, 49, 111, 119, 68, 68, 65, 75, + 66, 103, 78, 86, 72, 82, 85, 69, 65, 119, 111, 66, 65, 84, 65, 122, 65, 104, 81, + 72, 65, 104, 78, 112, 65, 67, 85, 105, 100, 78, 107, 68, 88, 117, 51, 49, 82, 88, + 82, 105, 43, 116, 68, 118, 84, 66, 99, 78, 77, 106, 77, 119, 78, 106, 69, 121, 10, + 77, 106, 69, 119, 77, 84, 65, 122, 87, 106, 65, 77, 77, 65, 111, 71, 65, 49, 85, + 100, 70, 81, 81, 68, 67, 103, 69, 66, 77, 68, 77, 67, 70, 71, 72, 121, 118, 51, 80, + 106, 109, 48, 52, 69, 113, 105, 102, 89, 65, 98, 49, 122, 48, 107, 77, 90, 116, 98, + 43, 65, 70, 119, 48, 121, 10, 77, 122, 65, 50, 77, 84, 73, 121, 77, 84, 65, 120, + 77, 68, 78, 97, 77, 65, 119, 119, 67, 103, 89, 68, 86, 82, 48, 86, 66, 65, 77, 75, + 65, 81, 69, 119, 77, 119, 73, 85, 79, 90, 75, 43, 104, 82, 117, 87, 107, 67, 55, + 47, 79, 74, 87, 101, 98, 67, 55, 47, 71, 119, 90, 82, 10, 112, 76, 85, 88, 68, 84, + 73, 122, 77, 68, 89, 120, 77, 106, 73, 120, 77, 68, 69, 119, 77, 49, 111, 119, 68, + 68, 65, 75, 66, 103, 78, 86, 72, 82, 85, 69, 65, 119, 111, 66, 65, 84, 65, 122, 65, + 104, 82, 106, 110, 120, 79, 97, 85, 69, 68, 57, 122, 47, 71, 82, 54, 75, 84, 55, + 10, 71, 47, 67, 71, 55, 87, 65, 53, 99, 82, 99, 78, 77, 106, 77, 119, 78, 106, 69, + 121, 77, 106, 69, 119, 77, 84, 65, 122, 87, 106, 65, 77, 77, 65, 111, 71, 65, 49, + 85, 100, 70, 81, 81, 68, 67, 103, 69, 66, 77, 68, 81, 67, 70, 81, 67, 86, 110, 86, + 77, 47, 107, 107, 110, 99, 10, 72, 108, 69, 49, 82, 77, 51, 73, 77, 76, 56, 90, + 116, 47, 72, 122, 65, 82, 99, 78, 77, 106, 77, 119, 78, 106, 69, 121, 77, 106, 69, + 119, 77, 84, 65, 122, 87, 106, 65, 77, 77, 65, 111, 71, 65, 49, 85, 100, 70, 81, + 81, 68, 67, 103, 69, 66, 77, 68, 77, 67, 70, 65, 47, 97, 10, 81, 54, 65, 76, 97, + 79, 112, 53, 116, 56, 76, 101, 114, 113, 119, 76, 83, 89, 118, 102, 115, 113, 43, + 81, 70, 119, 48, 121, 77, 122, 65, 50, 77, 84, 73, 121, 77, 84, 65, 120, 77, 68, + 78, 97, 77, 65, 119, 119, 67, 103, 89, 68, 86, 82, 48, 86, 66, 65, 77, 75, 65, 81, + 69, 119, 10, 78, 65, 73, 86, 65, 74, 49, 110, 100, 84, 117, 66, 53, 72, 67, 81, + 114, 113, 100, 106, 43, 43, 120, 77, 82, 85, 109, 56, 50, 53, 107, 122, 70, 119, + 48, 121, 77, 122, 65, 50, 77, 84, 73, 121, 77, 84, 65, 120, 77, 68, 78, 97, 77, 65, + 119, 119, 67, 103, 89, 68, 86, 82, 48, 86, 10, 66, 65, 77, 75, 65, 81, 69, 119, 77, + 119, 73, 85, 78, 76, 43, 55, 101, 104, 50, 99, 86, 111, 70, 72, 52, 82, 105, 50, + 70, 80, 101, 51, 98, 116, 80, 118, 97, 78, 56, 88, 68, 84, 73, 122, 77, 68, 89, + 120, 77, 106, 73, 120, 77, 68, 69, 119, 77, 49, 111, 119, 68, 68, 65, 75, 10, 66, + 103, 78, 86, 72, 82, 85, 69, 65, 119, 111, 66, 65, 84, 65, 48, 65, 104, 85, 65, + 104, 100, 80, 74, 79, 66, 116, 51, 112, 43, 66, 78, 69, 90, 121, 101, 87, 116, 90, + 48, 110, 47, 80, 47, 113, 52, 99, 88, 68, 84, 73, 122, 77, 68, 89, 120, 77, 106, + 73, 120, 77, 68, 69, 119, 10, 77, 49, 111, 119, 68, 68, 65, 75, 66, 103, 78, 86, + 72, 82, 85, 69, 65, 119, 111, 66, 65, 84, 65, 48, 65, 104, 85, 65, 107, 52, 104, + 56, 112, 69, 69, 101, 101, 112, 73, 55, 48, 102, 55, 83, 103, 90, 115, 112, 83, + 102, 73, 66, 116, 98, 81, 88, 68, 84, 73, 122, 77, 68, 89, 120, 10, 77, 106, 73, + 120, 77, 68, 69, 119, 77, 49, 111, 119, 68, 68, 65, 75, 66, 103, 78, 86, 72, 82, + 85, 69, 65, 119, 111, 66, 65, 84, 65, 122, 65, 104, 81, 107, 109, 78, 120, 105, + 103, 53, 77, 74, 108, 118, 50, 76, 56, 106, 111, 51, 114, 76, 52, 109, 111, 55, 55, + 85, 86, 120, 99, 78, 10, 77, 106, 77, 119, 78, 106, 69, 121, 77, 106, 69, 119, 77, + 84, 65, 122, 87, 106, 65, 77, 77, 65, 111, 71, 65, 49, 85, 100, 70, 81, 81, 68, 67, + 103, 69, 66, 77, 68, 81, 67, 70, 81, 67, 75, 90, 118, 71, 110, 83, 85, 105, 71, 90, + 50, 105, 99, 119, 53, 65, 54, 120, 85, 120, 109, 10, 75, 51, 69, 117, 99, 120, 99, + 78, 77, 106, 77, 119, 78, 106, 69, 121, 77, 106, 69, 119, 77, 84, 65, 122, 87, 106, + 65, 77, 77, 65, 111, 71, 65, 49, 85, 100, 70, 81, 81, 68, 67, 103, 69, 66, 77, 68, + 81, 67, 70, 81, 67, 118, 119, 84, 89, 81, 118, 100, 78, 115, 116, 53, 104, 100, 10, + 69, 71, 83, 66, 113, 73, 68, 84, 111, 66, 47, 97, 66, 120, 99, 78, 77, 106, 77, + 119, 78, 106, 69, 121, 77, 106, 69, 119, 77, 84, 65, 122, 87, 106, 65, 77, 77, 65, + 111, 71, 65, 49, 85, 100, 70, 81, 81, 68, 67, 103, 69, 66, 77, 68, 81, 67, 70, 81, + 68, 118, 52, 69, 115, 115, 10, 77, 57, 65, 50, 113, 115, 108, 115, 112, 110, 79, + 47, 72, 112, 112, 72, 116, 107, 49, 99, 117, 120, 99, 78, 77, 106, 77, 119, 78, + 106, 69, 121, 77, 106, 69, 119, 77, 84, 65, 122, 87, 106, 65, 77, 77, 65, 111, 71, + 65, 49, 85, 100, 70, 81, 81, 68, 67, 103, 69, 66, 77, 68, 81, 67, 10, 70, 81, 67, + 68, 50, 97, 121, 78, 105, 55, 85, 74, 48, 99, 98, 73, 67, 97, 49, 120, 76, 111, 81, + 119, 86, 90, 55, 88, 56, 120, 99, 78, 77, 106, 77, 119, 78, 106, 69, 121, 77, 106, + 69, 119, 77, 84, 65, 122, 87, 106, 65, 77, 77, 65, 111, 71, 65, 49, 85, 100, 70, + 81, 81, 68, 10, 67, 103, 69, 66, 77, 68, 77, 67, 70, 72, 107, 120, 47, 86, 67, 49, + 66, 120, 119, 98, 118, 56, 87, 51, 116, 116, 55, 89, 116, 70, 117, 100, 105, 52, + 85, 112, 70, 119, 48, 121, 77, 122, 65, 50, 77, 84, 73, 121, 77, 84, 65, 120, 77, + 68, 78, 97, 77, 65, 119, 119, 67, 103, 89, 68, 10, 86, 82, 48, 86, 66, 65, 77, 75, + 65, 81, 69, 119, 77, 119, 73, 85, 72, 54, 73, 79, 75, 88, 67, 57, 53, 100, 86, 47, + 101, 52, 51, 102, 103, 122, 108, 73, 84, 104, 56, 100, 67, 67, 77, 88, 68, 84, 73, + 122, 77, 68, 89, 120, 77, 106, 73, 120, 77, 68, 69, 119, 77, 49, 111, 119, 10, 68, + 68, 65, 75, 66, 103, 78, 86, 72, 82, 85, 69, 65, 119, 111, 66, 65, 84, 65, 122, 65, + 104, 81, 101, 104, 55, 76, 68, 115, 121, 50, 78, 73, 43, 81, 82, 122, 118, 78, 66, + 108, 55, 108, 97, 56, 77, 105, 116, 57, 82, 99, 78, 77, 106, 77, 119, 78, 106, 69, + 121, 77, 106, 69, 119, 10, 77, 84, 65, 122, 87, 106, 65, 77, 77, 65, 111, 71, 65, + 49, 85, 100, 70, 81, 81, 68, 67, 103, 69, 66, 77, 68, 81, 67, 70, 81, 67, 97, 47, + 83, 55, 112, 67, 107, 99, 49, 85, 75, 70, 110, 50, 90, 97, 82, 70, 68, 102, 72, 85, + 67, 48, 102, 67, 82, 99, 78, 77, 106, 77, 119, 10, 78, 106, 69, 121, 77, 106, 69, + 119, 77, 84, 65, 122, 87, 106, 65, 77, 77, 65, 111, 71, 65, 49, 85, 100, 70, 81, + 81, 68, 67, 103, 69, 66, 77, 68, 77, 67, 70, 69, 83, 66, 115, 80, 69, 88, 75, 75, + 69, 55, 97, 87, 48, 43, 113, 99, 100, 119, 111, 76, 70, 101, 120, 89, 51, 97, 10, + 70, 119, 48, 121, 77, 122, 65, 50, 77, 84, 73, 121, 77, 84, 65, 120, 77, 68, 78, + 97, 77, 65, 119, 119, 67, 103, 89, 68, 86, 82, 48, 86, 66, 65, 77, 75, 65, 81, 69, + 119, 78, 65, 73, 86, 65, 75, 101, 70, 110, 49, 101, 89, 76, 118, 68, 109, 102, 84, + 101, 56, 106, 118, 76, 118, 10, 87, 115, 103, 49, 47, 120, 113, 112, 70, 119, 48, + 121, 77, 122, 65, 50, 77, 84, 73, 121, 77, 84, 65, 120, 77, 68, 78, 97, 77, 65, + 119, 119, 67, 103, 89, 68, 86, 82, 48, 86, 66, 65, 77, 75, 65, 81, 69, 119, 77, + 119, 73, 85, 101, 117, 78, 51, 83, 75, 110, 53, 69, 118, 84, 71, 10, 79, 54, 101, + 114, 66, 56, 87, 84, 122, 104, 48, 100, 69, 89, 69, 88, 68, 84, 73, 122, 77, 68, + 89, 120, 77, 106, 73, 120, 77, 68, 69, 119, 77, 49, 111, 119, 68, 68, 65, 75, 66, + 103, 78, 86, 72, 82, 85, 69, 65, 119, 111, 66, 65, 84, 65, 122, 65, 104, 81, 84, + 105, 69, 115, 122, 10, 74, 112, 107, 52, 119, 90, 87, 113, 70, 119, 47, 75, 100, + 100, 111, 88, 100, 84, 106, 102, 67, 120, 99, 78, 77, 106, 77, 119, 78, 106, 69, + 121, 77, 106, 69, 119, 77, 84, 65, 122, 87, 106, 65, 77, 77, 65, 111, 71, 65, 49, + 85, 100, 70, 81, 81, 68, 67, 103, 69, 66, 77, 68, 77, 67, 10, 70, 67, 119, 56, 120, + 118, 54, 83, 101, 100, 115, 86, 70, 116, 88, 79, 79, 102, 75, 111, 109, 77, 50, + 108, 111, 88, 88, 104, 70, 119, 48, 121, 77, 122, 65, 50, 77, 84, 73, 121, 77, 84, + 65, 120, 77, 68, 78, 97, 77, 65, 119, 119, 67, 103, 89, 68, 86, 82, 48, 86, 66, 65, + 77, 75, 10, 65, 81, 69, 119, 77, 119, 73, 85, 99, 88, 108, 73, 97, 72, 85, 74, 73, + 48, 118, 112, 101, 101, 83, 51, 51, 79, 98, 122, 71, 43, 57, 107, 116, 111, 119, + 88, 68, 84, 73, 122, 77, 68, 89, 120, 77, 106, 73, 120, 77, 68, 69, 119, 77, 49, + 111, 119, 68, 68, 65, 75, 66, 103, 78, 86, 10, 72, 82, 85, 69, 65, 119, 111, 66, + 65, 84, 65, 48, 65, 104, 85, 65, 110, 88, 98, 118, 76, 68, 110, 66, 78, 117, 104, + 108, 105, 50, 53, 122, 108, 114, 72, 88, 82, 70, 111, 110, 89, 120, 56, 88, 68, 84, + 73, 122, 77, 68, 89, 120, 77, 106, 73, 120, 77, 68, 69, 119, 77, 49, 111, 119, 10, + 68, 68, 65, 75, 66, 103, 78, 86, 72, 82, 85, 69, 65, 119, 111, 66, 65, 84, 65, 48, + 65, 104, 85, 65, 119, 43, 65, 108, 47, 75, 109, 86, 56, 50, 57, 90, 116, 73, 82, + 110, 107, 53, 52, 43, 78, 79, 89, 50, 71, 109, 56, 88, 68, 84, 73, 122, 77, 68, 89, + 120, 77, 106, 73, 120, 10, 77, 68, 69, 119, 77, 49, 111, 119, 68, 68, 65, 75, 66, + 103, 78, 86, 72, 82, 85, 69, 65, 119, 111, 66, 65, 84, 65, 48, 65, 104, 85, 65, + 106, 70, 57, 114, 77, 108, 102, 97, 66, 98, 70, 48, 75, 101, 76, 109, 71, 54, 108, + 108, 49, 110, 77, 119, 89, 71, 111, 88, 68, 84, 73, 122, 10, 77, 68, 89, 120, 77, + 106, 73, 120, 77, 68, 69, 119, 77, 49, 111, 119, 68, 68, 65, 75, 66, 103, 78, 86, + 72, 82, 85, 69, 65, 119, 111, 66, 65, 84, 65, 48, 65, 104, 85, 65, 111, 88, 120, + 82, 99, 105, 55, 66, 52, 77, 77, 110, 106, 43, 105, 57, 56, 70, 73, 70, 110, 76, + 55, 69, 10, 53, 107, 103, 88, 68, 84, 73, 122, 77, 68, 89, 120, 77, 106, 73, 120, + 77, 68, 69, 119, 77, 49, 111, 119, 68, 68, 65, 75, 66, 103, 78, 86, 72, 82, 85, 69, + 65, 119, 111, 66, 65, 97, 65, 118, 77, 67, 48, 119, 67, 103, 89, 68, 86, 82, 48, + 85, 66, 65, 77, 67, 65, 81, 69, 119, 10, 72, 119, 89, 68, 86, 82, 48, 106, 66, 66, + 103, 119, 70, 111, 65, 85, 108, 87, 57, 100, 122, 98, 48, 98, 52, 101, 108, 65, 83, + 99, 110, 85, 57, 68, 80, 79, 65, 86, 99, 76, 51, 108, 81, 119, 67, 103, 89, 73, 75, + 111, 90, 73, 122, 106, 48, 69, 65, 119, 73, 68, 82, 119, 65, 119, 10, 82, 65, 73, + 103, 87, 87, 97, 121, 79, 100, 87, 65, 102, 108, 53, 115, 78, 108, 68, 101, 49, 87, + 71, 85, 52, 110, 83, 80, 88, 52, 86, 72, 107, 87, 55, 97, 104, 104, 86, 101, 74, + 48, 119, 115, 75, 53, 69, 67, 73, 72, 117, 117, 53, 54, 87, 77, 77, 78, 78, 56, 48, + 89, 70, 80, 10, 66, 47, 110, 56, 122, 48, 121, 104, 106, 66, 84, 69, 114, 79, 102, + 97, 108, 73, 54, 111, 52, 118, 75, 101, 100, 109, 78, 68, 10, 45, 45, 45, 45, 45, + 69, 78, 68, 32, 88, 53, 48, 57, 32, 67, 82, 76, 45, 45, 45, 45, 45, 10, 0, + ] + .into(), + tcb_info_issuer_chain: [ + 45, 45, 45, 45, 45, 66, 69, 71, 73, 78, 32, 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, + 69, 45, 45, 45, 45, 45, 10, 77, 73, 73, 67, 105, 122, 67, 67, 65, 106, 75, 103, 65, + 119, 73, 66, 65, 103, 73, 85, 102, 106, 105, 67, 49, 102, 116, 86, 75, 85, 112, 65, + 83, 89, 53, 70, 104, 65, 80, 112, 70, 74, 71, 57, 57, 70, 85, 119, 67, 103, 89, 73, + 75, 111, 90, 73, 122, 106, 48, 69, 65, 119, 73, 119, 10, 97, 68, 69, 97, 77, 66, + 103, 71, 65, 49, 85, 69, 65, 119, 119, 82, 83, 87, 53, 48, 90, 87, 119, 103, 85, + 48, 100, 89, 73, 70, 74, 118, 98, 51, 81, 103, 81, 48, 69, 120, 71, 106, 65, 89, + 66, 103, 78, 86, 66, 65, 111, 77, 69, 85, 108, 117, 100, 71, 86, 115, 73, 69, 78, + 118, 10, 99, 110, 66, 118, 99, 109, 70, 48, 97, 87, 57, 117, 77, 82, 81, 119, 69, + 103, 89, 68, 86, 81, 81, 72, 68, 65, 116, 84, 89, 87, 53, 48, 89, 83, 66, 68, 98, + 71, 70, 121, 89, 84, 69, 76, 77, 65, 107, 71, 65, 49, 85, 69, 67, 65, 119, 67, 81, + 48, 69, 120, 67, 122, 65, 74, 10, 66, 103, 78, 86, 66, 65, 89, 84, 65, 108, 86, 84, + 77, 66, 52, 88, 68, 84, 69, 52, 77, 68, 85, 121, 77, 84, 69, 119, 78, 84, 65, 120, + 77, 70, 111, 88, 68, 84, 73, 49, 77, 68, 85, 121, 77, 84, 69, 119, 78, 84, 65, 120, + 77, 70, 111, 119, 98, 68, 69, 101, 77, 66, 119, 71, 10, 65, 49, 85, 69, 65, 119, + 119, 86, 83, 87, 53, 48, 90, 87, 119, 103, 85, 48, 100, 89, 73, 70, 82, 68, 81, + 105, 66, 84, 97, 87, 100, 117, 97, 87, 53, 110, 77, 82, 111, 119, 71, 65, 89, 68, + 86, 81, 81, 75, 68, 66, 70, 74, 98, 110, 82, 108, 98, 67, 66, 68, 98, 51, 74, 119, + 10, 98, 51, 74, 104, 100, 71, 108, 118, 98, 106, 69, 85, 77, 66, 73, 71, 65, 49, + 85, 69, 66, 119, 119, 76, 85, 50, 70, 117, 100, 71, 69, 103, 81, 50, 120, 104, 99, + 109, 69, 120, 67, 122, 65, 74, 66, 103, 78, 86, 66, 65, 103, 77, 65, 107, 78, 66, + 77, 81, 115, 119, 67, 81, 89, 68, 10, 86, 81, 81, 71, 69, 119, 74, 86, 85, 122, 66, + 90, 77, 66, 77, 71, 66, 121, 113, 71, 83, 77, 52, 57, 65, 103, 69, 71, 67, 67, 113, + 71, 83, 77, 52, 57, 65, 119, 69, 72, 65, 48, 73, 65, 66, 69, 78, 70, 71, 56, 120, + 122, 121, 100, 87, 82, 102, 75, 57, 50, 98, 109, 71, 118, 10, 80, 43, 109, 65, 104, + 57, 49, 80, 69, 121, 86, 55, 74, 104, 54, 70, 71, 74, 100, 53, 110, 100, 69, 57, + 97, 66, 72, 55, 82, 51, 69, 52, 65, 55, 117, 98, 114, 108, 104, 47, 122, 78, 51, + 67, 52, 120, 118, 112, 111, 111, 117, 71, 108, 105, 114, 77, 98, 97, 43, 87, 50, + 108, 106, 117, 10, 121, 112, 97, 106, 103, 98, 85, 119, 103, 98, 73, 119, 72, 119, + 89, 68, 86, 82, 48, 106, 66, 66, 103, 119, 70, 111, 65, 85, 73, 109, 85, 77, 49, + 108, 113, 100, 78, 73, 110, 122, 103, 55, 83, 86, 85, 114, 57, 81, 71, 122, 107, + 110, 66, 113, 119, 119, 85, 103, 89, 68, 86, 82, 48, 102, 10, 66, 69, 115, 119, 83, + 84, 66, 72, 111, 69, 87, 103, 81, 52, 90, 66, 97, 72, 82, 48, 99, 72, 77, 54, 76, + 121, 57, 106, 90, 88, 74, 48, 97, 87, 90, 112, 89, 50, 70, 48, 90, 88, 77, 117, + 100, 72, 74, 49, 99, 51, 82, 108, 90, 72, 78, 108, 99, 110, 90, 112, 89, 50, 86, + 122, 10, 76, 109, 108, 117, 100, 71, 86, 115, 76, 109, 78, 118, 98, 83, 57, 74, 98, + 110, 82, 108, 98, 70, 78, 72, 87, 70, 74, 118, 98, 51, 82, 68, 81, 83, 53, 107, 90, + 88, 73, 119, 72, 81, 89, 68, 86, 82, 48, 79, 66, 66, 89, 69, 70, 72, 52, 52, 103, + 116, 88, 55, 86, 83, 108, 75, 10, 81, 69, 109, 79, 82, 89, 81, 68, 54, 82, 83, 82, + 118, 102, 82, 86, 77, 65, 52, 71, 65, 49, 85, 100, 68, 119, 69, 66, 47, 119, 81, + 69, 65, 119, 73, 71, 119, 68, 65, 77, 66, 103, 78, 86, 72, 82, 77, 66, 65, 102, 56, + 69, 65, 106, 65, 65, 77, 65, 111, 71, 67, 67, 113, 71, 10, 83, 77, 52, 57, 66, 65, + 77, 67, 65, 48, 99, 65, 77, 69, 81, 67, 73, 66, 57, 67, 56, 119, 79, 65, 78, 47, + 73, 109, 120, 68, 116, 71, 65, 67, 86, 50, 52, 54, 75, 99, 113, 106, 97, 103, 90, + 79, 82, 48, 107, 121, 99, 116, 121, 66, 114, 115, 71, 71, 74, 86, 65, 105, 65, 106, + 10, 102, 116, 98, 114, 78, 71, 115, 71, 85, 56, 89, 72, 50, 49, 49, 100, 82, 105, + 89, 78, 111, 80, 80, 117, 49, 57, 90, 112, 47, 122, 101, 56, 74, 109, 104, 117, + 106, 66, 48, 111, 66, 119, 61, 61, 10, 45, 45, 45, 45, 45, 69, 78, 68, 32, 67, 69, + 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, 10, 45, 45, 45, 45, 45, 66, + 69, 71, 73, 78, 32, 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, + 10, 77, 73, 73, 67, 106, 122, 67, 67, 65, 106, 83, 103, 65, 119, 73, 66, 65, 103, + 73, 85, 73, 109, 85, 77, 49, 108, 113, 100, 78, 73, 110, 122, 103, 55, 83, 86, 85, + 114, 57, 81, 71, 122, 107, 110, 66, 113, 119, 119, 67, 103, 89, 73, 75, 111, 90, + 73, 122, 106, 48, 69, 65, 119, 73, 119, 10, 97, 68, 69, 97, 77, 66, 103, 71, 65, + 49, 85, 69, 65, 119, 119, 82, 83, 87, 53, 48, 90, 87, 119, 103, 85, 48, 100, 89, + 73, 70, 74, 118, 98, 51, 81, 103, 81, 48, 69, 120, 71, 106, 65, 89, 66, 103, 78, + 86, 66, 65, 111, 77, 69, 85, 108, 117, 100, 71, 86, 115, 73, 69, 78, 118, 10, 99, + 110, 66, 118, 99, 109, 70, 48, 97, 87, 57, 117, 77, 82, 81, 119, 69, 103, 89, 68, + 86, 81, 81, 72, 68, 65, 116, 84, 89, 87, 53, 48, 89, 83, 66, 68, 98, 71, 70, 121, + 89, 84, 69, 76, 77, 65, 107, 71, 65, 49, 85, 69, 67, 65, 119, 67, 81, 48, 69, 120, + 67, 122, 65, 74, 10, 66, 103, 78, 86, 66, 65, 89, 84, 65, 108, 86, 84, 77, 66, 52, + 88, 68, 84, 69, 52, 77, 68, 85, 121, 77, 84, 69, 119, 78, 68, 85, 120, 77, 70, 111, + 88, 68, 84, 81, 53, 77, 84, 73, 122, 77, 84, 73, 122, 78, 84, 107, 49, 79, 86, 111, + 119, 97, 68, 69, 97, 77, 66, 103, 71, 10, 65, 49, 85, 69, 65, 119, 119, 82, 83, 87, + 53, 48, 90, 87, 119, 103, 85, 48, 100, 89, 73, 70, 74, 118, 98, 51, 81, 103, 81, + 48, 69, 120, 71, 106, 65, 89, 66, 103, 78, 86, 66, 65, 111, 77, 69, 85, 108, 117, + 100, 71, 86, 115, 73, 69, 78, 118, 99, 110, 66, 118, 99, 109, 70, 48, 10, 97, 87, + 57, 117, 77, 82, 81, 119, 69, 103, 89, 68, 86, 81, 81, 72, 68, 65, 116, 84, 89, 87, + 53, 48, 89, 83, 66, 68, 98, 71, 70, 121, 89, 84, 69, 76, 77, 65, 107, 71, 65, 49, + 85, 69, 67, 65, 119, 67, 81, 48, 69, 120, 67, 122, 65, 74, 66, 103, 78, 86, 66, 65, + 89, 84, 10, 65, 108, 86, 84, 77, 70, 107, 119, 69, 119, 89, 72, 75, 111, 90, 73, + 122, 106, 48, 67, 65, 81, 89, 73, 75, 111, 90, 73, 122, 106, 48, 68, 65, 81, 99, + 68, 81, 103, 65, 69, 67, 54, 110, 69, 119, 77, 68, 73, 89, 90, 79, 106, 47, 105, + 80, 87, 115, 67, 122, 97, 69, 75, 105, 55, 10, 49, 79, 105, 79, 83, 76, 82, 70, + 104, 87, 71, 106, 98, 110, 66, 86, 74, 102, 86, 110, 107, 89, 52, 117, 51, 73, 106, + 107, 68, 89, 89, 76, 48, 77, 120, 79, 52, 109, 113, 115, 121, 89, 106, 108, 66, 97, + 108, 84, 86, 89, 120, 70, 80, 50, 115, 74, 66, 75, 53, 122, 108, 75, 79, 66, 10, + 117, 122, 67, 66, 117, 68, 65, 102, 66, 103, 78, 86, 72, 83, 77, 69, 71, 68, 65, + 87, 103, 66, 81, 105, 90, 81, 122, 87, 87, 112, 48, 48, 105, 102, 79, 68, 116, 74, + 86, 83, 118, 49, 65, 98, 79, 83, 99, 71, 114, 68, 66, 83, 66, 103, 78, 86, 72, 82, + 56, 69, 83, 122, 66, 74, 10, 77, 69, 101, 103, 82, 97, 66, 68, 104, 107, 70, 111, + 100, 72, 82, 119, 99, 122, 111, 118, 76, 50, 78, 108, 99, 110, 82, 112, 90, 109, + 108, 106, 89, 88, 82, 108, 99, 121, 53, 48, 99, 110, 86, 122, 100, 71, 86, 107, 99, + 50, 86, 121, 100, 109, 108, 106, 90, 88, 77, 117, 97, 87, 53, 48, 10, 90, 87, 119, + 117, 89, 50, 57, 116, 76, 48, 108, 117, 100, 71, 86, 115, 85, 48, 100, 89, 85, 109, + 57, 118, 100, 69, 78, 66, 76, 109, 82, 108, 99, 106, 65, 100, 66, 103, 78, 86, 72, + 81, 52, 69, 70, 103, 81, 85, 73, 109, 85, 77, 49, 108, 113, 100, 78, 73, 110, 122, + 103, 55, 83, 86, 10, 85, 114, 57, 81, 71, 122, 107, 110, 66, 113, 119, 119, 68, + 103, 89, 68, 86, 82, 48, 80, 65, 81, 72, 47, 66, 65, 81, 68, 65, 103, 69, 71, 77, + 66, 73, 71, 65, 49, 85, 100, 69, 119, 69, 66, 47, 119, 81, 73, 77, 65, 89, 66, 65, + 102, 56, 67, 65, 81, 69, 119, 67, 103, 89, 73, 10, 75, 111, 90, 73, 122, 106, 48, + 69, 65, 119, 73, 68, 83, 81, 65, 119, 82, 103, 73, 104, 65, 79, 87, 47, 53, 81, + 107, 82, 43, 83, 57, 67, 105, 83, 68, 99, 78, 111, 111, 119, 76, 117, 80, 82, 76, + 115, 87, 71, 102, 47, 89, 105, 55, 71, 83, 88, 57, 52, 66, 103, 119, 84, 119, 103, + 10, 65, 105, 69, 65, 52, 74, 48, 108, 114, 72, 111, 77, 115, 43, 88, 111, 53, 111, + 47, 115, 88, 54, 79, 57, 81, 87, 120, 72, 82, 65, 118, 90, 85, 71, 79, 100, 82, 81, + 55, 99, 118, 113, 82, 88, 97, 113, 73, 61, 10, 45, 45, 45, 45, 45, 69, 78, 68, 32, + 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, 10, 0, + ] + .into(), + tcb_info: [ + 123, 34, 116, 99, 98, 73, 110, 102, 111, 34, 58, 123, 34, 105, 100, 34, 58, 34, 83, + 71, 88, 34, 44, 34, 118, 101, 114, 115, 105, 111, 110, 34, 58, 51, 44, 34, 105, + 115, 115, 117, 101, 68, 97, 116, 101, 34, 58, 34, 50, 48, 50, 51, 45, 48, 54, 45, + 50, 49, 84, 49, 48, 58, 49, 53, 58, 51, 52, 90, 34, 44, 34, 110, 101, 120, 116, 85, + 112, 100, 97, 116, 101, 34, 58, 34, 50, 48, 50, 51, 45, 48, 55, 45, 50, 49, 84, 49, + 48, 58, 49, 53, 58, 51, 52, 90, 34, 44, 34, 102, 109, 115, 112, 99, 34, 58, 34, 48, + 48, 54, 48, 54, 97, 48, 48, 48, 48, 48, 48, 34, 44, 34, 112, 99, 101, 73, 100, 34, + 58, 34, 48, 48, 48, 48, 34, 44, 34, 116, 99, 98, 84, 121, 112, 101, 34, 58, 48, 44, + 34, 116, 99, 98, 69, 118, 97, 108, 117, 97, 116, 105, 111, 110, 68, 97, 116, 97, + 78, 117, 109, 98, 101, 114, 34, 58, 49, 53, 44, 34, 116, 99, 98, 76, 101, 118, 101, + 108, 115, 34, 58, 91, 123, 34, 116, 99, 98, 34, 58, 123, 34, 115, 103, 120, 116, + 99, 98, 99, 111, 109, 112, 111, 110, 101, 110, 116, 115, 34, 58, 91, 123, 34, 115, + 118, 110, 34, 58, 49, 49, 44, 34, 99, 97, 116, 101, 103, 111, 114, 121, 34, 58, 34, + 66, 73, 79, 83, 34, 44, 34, 116, 121, 112, 101, 34, 58, 34, 69, 97, 114, 108, 121, + 32, 77, 105, 99, 114, 111, 99, 111, 100, 101, 32, 85, 112, 100, 97, 116, 101, 34, + 125, 44, 123, 34, 115, 118, 110, 34, 58, 49, 49, 44, 34, 99, 97, 116, 101, 103, + 111, 114, 121, 34, 58, 34, 79, 83, 47, 86, 77, 77, 34, 44, 34, 116, 121, 112, 101, + 34, 58, 34, 83, 71, 88, 32, 76, 97, 116, 101, 32, 77, 105, 99, 114, 111, 99, 111, + 100, 101, 32, 85, 112, 100, 97, 116, 101, 34, 125, 44, 123, 34, 115, 118, 110, 34, + 58, 51, 44, 34, 99, 97, 116, 101, 103, 111, 114, 121, 34, 58, 34, 79, 83, 47, 86, + 77, 77, 34, 44, 34, 116, 121, 112, 101, 34, 58, 34, 84, 88, 84, 32, 83, 73, 78, 73, + 84, 34, 125, 44, 123, 34, 115, 118, 110, 34, 58, 51, 44, 34, 99, 97, 116, 101, 103, + 111, 114, 121, 34, 58, 34, 66, 73, 79, 83, 34, 125, 44, 123, 34, 115, 118, 110, 34, + 58, 50, 53, 53, 125, 44, 123, 34, 115, 118, 110, 34, 58, 50, 53, 53, 125, 44, 123, + 34, 115, 118, 110, 34, 58, 49, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, + 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, + 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, + 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, + 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, + 34, 115, 118, 110, 34, 58, 48, 125, 93, 44, 34, 112, 99, 101, 115, 118, 110, 34, + 58, 49, 51, 125, 44, 34, 116, 99, 98, 68, 97, 116, 101, 34, 58, 34, 50, 48, 50, 51, + 45, 48, 50, 45, 49, 53, 84, 48, 48, 58, 48, 48, 58, 48, 48, 90, 34, 44, 34, 116, + 99, 98, 83, 116, 97, 116, 117, 115, 34, 58, 34, 83, 87, 72, 97, 114, 100, 101, 110, + 105, 110, 103, 78, 101, 101, 100, 101, 100, 34, 44, 34, 97, 100, 118, 105, 115, + 111, 114, 121, 73, 68, 115, 34, 58, 91, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, + 48, 54, 49, 53, 34, 93, 125, 44, 123, 34, 116, 99, 98, 34, 58, 123, 34, 115, 103, + 120, 116, 99, 98, 99, 111, 109, 112, 111, 110, 101, 110, 116, 115, 34, 58, 91, 123, + 34, 115, 118, 110, 34, 58, 49, 49, 44, 34, 99, 97, 116, 101, 103, 111, 114, 121, + 34, 58, 34, 66, 73, 79, 83, 34, 44, 34, 116, 121, 112, 101, 34, 58, 34, 69, 97, + 114, 108, 121, 32, 77, 105, 99, 114, 111, 99, 111, 100, 101, 32, 85, 112, 100, 97, + 116, 101, 34, 125, 44, 123, 34, 115, 118, 110, 34, 58, 49, 49, 44, 34, 99, 97, 116, + 101, 103, 111, 114, 121, 34, 58, 34, 79, 83, 47, 86, 77, 77, 34, 44, 34, 116, 121, + 112, 101, 34, 58, 34, 83, 71, 88, 32, 76, 97, 116, 101, 32, 77, 105, 99, 114, 111, + 99, 111, 100, 101, 32, 85, 112, 100, 97, 116, 101, 34, 125, 44, 123, 34, 115, 118, + 110, 34, 58, 51, 44, 34, 99, 97, 116, 101, 103, 111, 114, 121, 34, 58, 34, 79, 83, + 47, 86, 77, 77, 34, 44, 34, 116, 121, 112, 101, 34, 58, 34, 84, 88, 84, 32, 83, 73, + 78, 73, 84, 34, 125, 44, 123, 34, 115, 118, 110, 34, 58, 51, 44, 34, 99, 97, 116, + 101, 103, 111, 114, 121, 34, 58, 34, 66, 73, 79, 83, 34, 125, 44, 123, 34, 115, + 118, 110, 34, 58, 50, 53, 53, 125, 44, 123, 34, 115, 118, 110, 34, 58, 50, 53, 53, + 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, + 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, + 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, + 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, + 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, + 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 93, 44, 34, 112, 99, 101, 115, + 118, 110, 34, 58, 49, 51, 125, 44, 34, 116, 99, 98, 68, 97, 116, 101, 34, 58, 34, + 50, 48, 50, 51, 45, 48, 50, 45, 49, 53, 84, 48, 48, 58, 48, 48, 58, 48, 48, 90, 34, + 44, 34, 116, 99, 98, 83, 116, 97, 116, 117, 115, 34, 58, 34, 67, 111, 110, 102, + 105, 103, 117, 114, 97, 116, 105, 111, 110, 65, 110, 100, 83, 87, 72, 97, 114, 100, + 101, 110, 105, 110, 103, 78, 101, 101, 100, 101, 100, 34, 44, 34, 97, 100, 118, + 105, 115, 111, 114, 121, 73, 68, 115, 34, 58, 91, 34, 73, 78, 84, 69, 76, 45, 83, + 65, 45, 48, 48, 54, 49, 53, 34, 93, 125, 44, 123, 34, 116, 99, 98, 34, 58, 123, 34, + 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 111, 110, 101, 110, 116, 115, 34, + 58, 91, 123, 34, 115, 118, 110, 34, 58, 55, 44, 34, 99, 97, 116, 101, 103, 111, + 114, 121, 34, 58, 34, 66, 73, 79, 83, 34, 44, 34, 116, 121, 112, 101, 34, 58, 34, + 69, 97, 114, 108, 121, 32, 77, 105, 99, 114, 111, 99, 111, 100, 101, 32, 85, 112, + 100, 97, 116, 101, 34, 125, 44, 123, 34, 115, 118, 110, 34, 58, 57, 44, 34, 99, 97, + 116, 101, 103, 111, 114, 121, 34, 58, 34, 79, 83, 47, 86, 77, 77, 34, 44, 34, 116, + 121, 112, 101, 34, 58, 34, 83, 71, 88, 32, 76, 97, 116, 101, 32, 77, 105, 99, 114, + 111, 99, 111, 100, 101, 32, 85, 112, 100, 97, 116, 101, 34, 125, 44, 123, 34, 115, + 118, 110, 34, 58, 51, 44, 34, 99, 97, 116, 101, 103, 111, 114, 121, 34, 58, 34, 79, + 83, 47, 86, 77, 77, 34, 44, 34, 116, 121, 112, 101, 34, 58, 34, 84, 88, 84, 32, 83, + 73, 78, 73, 84, 34, 125, 44, 123, 34, 115, 118, 110, 34, 58, 51, 44, 34, 99, 97, + 116, 101, 103, 111, 114, 121, 34, 58, 34, 66, 73, 79, 83, 34, 125, 44, 123, 34, + 115, 118, 110, 34, 58, 50, 53, 53, 125, 44, 123, 34, 115, 118, 110, 34, 58, 50, 53, + 53, 125, 44, 123, 34, 115, 118, 110, 34, 58, 49, 125, 44, 123, 34, 115, 118, 110, + 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, + 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, + 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, + 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, + 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 93, 44, 34, 112, 99, 101, + 115, 118, 110, 34, 58, 49, 51, 125, 44, 34, 116, 99, 98, 68, 97, 116, 101, 34, 58, + 34, 50, 48, 50, 50, 45, 48, 56, 45, 49, 48, 84, 48, 48, 58, 48, 48, 58, 48, 48, 90, + 34, 44, 34, 116, 99, 98, 83, 116, 97, 116, 117, 115, 34, 58, 34, 79, 117, 116, 79, + 102, 68, 97, 116, 101, 34, 44, 34, 97, 100, 118, 105, 115, 111, 114, 121, 73, 68, + 115, 34, 58, 91, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 54, 53, 55, 34, + 44, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 55, 51, 48, 34, 44, 34, 73, 78, + 84, 69, 76, 45, 83, 65, 45, 48, 48, 55, 51, 56, 34, 44, 34, 73, 78, 84, 69, 76, 45, + 83, 65, 45, 48, 48, 55, 54, 55, 34, 44, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, + 48, 54, 49, 53, 34, 93, 125, 44, 123, 34, 116, 99, 98, 34, 58, 123, 34, 115, 103, + 120, 116, 99, 98, 99, 111, 109, 112, 111, 110, 101, 110, 116, 115, 34, 58, 91, 123, + 34, 115, 118, 110, 34, 58, 55, 44, 34, 99, 97, 116, 101, 103, 111, 114, 121, 34, + 58, 34, 66, 73, 79, 83, 34, 44, 34, 116, 121, 112, 101, 34, 58, 34, 69, 97, 114, + 108, 121, 32, 77, 105, 99, 114, 111, 99, 111, 100, 101, 32, 85, 112, 100, 97, 116, + 101, 34, 125, 44, 123, 34, 115, 118, 110, 34, 58, 57, 44, 34, 99, 97, 116, 101, + 103, 111, 114, 121, 34, 58, 34, 79, 83, 47, 86, 77, 77, 34, 44, 34, 116, 121, 112, + 101, 34, 58, 34, 83, 71, 88, 32, 76, 97, 116, 101, 32, 77, 105, 99, 114, 111, 99, + 111, 100, 101, 32, 85, 112, 100, 97, 116, 101, 34, 125, 44, 123, 34, 115, 118, 110, + 34, 58, 51, 44, 34, 99, 97, 116, 101, 103, 111, 114, 121, 34, 58, 34, 79, 83, 47, + 86, 77, 77, 34, 44, 34, 116, 121, 112, 101, 34, 58, 34, 84, 88, 84, 32, 83, 73, 78, + 73, 84, 34, 125, 44, 123, 34, 115, 118, 110, 34, 58, 51, 44, 34, 99, 97, 116, 101, + 103, 111, 114, 121, 34, 58, 34, 66, 73, 79, 83, 34, 125, 44, 123, 34, 115, 118, + 110, 34, 58, 50, 53, 53, 125, 44, 123, 34, 115, 118, 110, 34, 58, 50, 53, 53, 125, + 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, + 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, + 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, + 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, + 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, + 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 93, 44, 34, 112, 99, 101, 115, 118, + 110, 34, 58, 49, 51, 125, 44, 34, 116, 99, 98, 68, 97, 116, 101, 34, 58, 34, 50, + 48, 50, 50, 45, 48, 56, 45, 49, 48, 84, 48, 48, 58, 48, 48, 58, 48, 48, 90, 34, 44, + 34, 116, 99, 98, 83, 116, 97, 116, 117, 115, 34, 58, 34, 79, 117, 116, 79, 102, 68, + 97, 116, 101, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 78, + 101, 101, 100, 101, 100, 34, 44, 34, 97, 100, 118, 105, 115, 111, 114, 121, 73, 68, + 115, 34, 58, 91, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 54, 53, 55, 34, + 44, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 55, 51, 48, 34, 44, 34, 73, 78, + 84, 69, 76, 45, 83, 65, 45, 48, 48, 55, 51, 56, 34, 44, 34, 73, 78, 84, 69, 76, 45, + 83, 65, 45, 48, 48, 55, 54, 55, 34, 44, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, + 48, 54, 49, 53, 34, 93, 125, 44, 123, 34, 116, 99, 98, 34, 58, 123, 34, 115, 103, + 120, 116, 99, 98, 99, 111, 109, 112, 111, 110, 101, 110, 116, 115, 34, 58, 91, 123, + 34, 115, 118, 110, 34, 58, 52, 44, 34, 99, 97, 116, 101, 103, 111, 114, 121, 34, + 58, 34, 66, 73, 79, 83, 34, 44, 34, 116, 121, 112, 101, 34, 58, 34, 69, 97, 114, + 108, 121, 32, 77, 105, 99, 114, 111, 99, 111, 100, 101, 32, 85, 112, 100, 97, 116, + 101, 34, 125, 44, 123, 34, 115, 118, 110, 34, 58, 52, 44, 34, 99, 97, 116, 101, + 103, 111, 114, 121, 34, 58, 34, 79, 83, 47, 86, 77, 77, 34, 44, 34, 116, 121, 112, + 101, 34, 58, 34, 83, 71, 88, 32, 76, 97, 116, 101, 32, 77, 105, 99, 114, 111, 99, + 111, 100, 101, 32, 85, 112, 100, 97, 116, 101, 34, 125, 44, 123, 34, 115, 118, 110, + 34, 58, 51, 44, 34, 99, 97, 116, 101, 103, 111, 114, 121, 34, 58, 34, 79, 83, 47, + 86, 77, 77, 34, 44, 34, 116, 121, 112, 101, 34, 58, 34, 84, 88, 84, 32, 83, 73, 78, + 73, 84, 34, 125, 44, 123, 34, 115, 118, 110, 34, 58, 51, 44, 34, 99, 97, 116, 101, + 103, 111, 114, 121, 34, 58, 34, 66, 73, 79, 83, 34, 125, 44, 123, 34, 115, 118, + 110, 34, 58, 50, 53, 53, 125, 44, 123, 34, 115, 118, 110, 34, 58, 50, 53, 53, 125, + 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, + 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, + 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, + 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, + 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, + 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 93, 44, 34, 112, 99, 101, 115, 118, + 110, 34, 58, 49, 49, 125, 44, 34, 116, 99, 98, 68, 97, 116, 101, 34, 58, 34, 50, + 48, 50, 49, 45, 49, 49, 45, 49, 48, 84, 48, 48, 58, 48, 48, 58, 48, 48, 90, 34, 44, + 34, 116, 99, 98, 83, 116, 97, 116, 117, 115, 34, 58, 34, 79, 117, 116, 79, 102, 68, + 97, 116, 101, 34, 44, 34, 97, 100, 118, 105, 115, 111, 114, 121, 73, 68, 115, 34, + 58, 91, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 53, 56, 54, 34, 44, 34, 73, + 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 54, 49, 52, 34, 44, 34, 73, 78, 84, 69, 76, + 45, 83, 65, 45, 48, 48, 54, 49, 53, 34, 44, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, + 48, 48, 54, 53, 55, 34, 44, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 55, 51, + 48, 34, 44, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 55, 51, 56, 34, 44, 34, + 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 55, 54, 55, 34, 93, 125, 44, 123, 34, + 116, 99, 98, 34, 58, 123, 34, 115, 103, 120, 116, 99, 98, 99, 111, 109, 112, 111, + 110, 101, 110, 116, 115, 34, 58, 91, 123, 34, 115, 118, 110, 34, 58, 52, 44, 34, + 99, 97, 116, 101, 103, 111, 114, 121, 34, 58, 34, 66, 73, 79, 83, 34, 44, 34, 116, + 121, 112, 101, 34, 58, 34, 69, 97, 114, 108, 121, 32, 77, 105, 99, 114, 111, 99, + 111, 100, 101, 32, 85, 112, 100, 97, 116, 101, 34, 125, 44, 123, 34, 115, 118, 110, + 34, 58, 52, 44, 34, 99, 97, 116, 101, 103, 111, 114, 121, 34, 58, 34, 79, 83, 47, + 86, 77, 77, 34, 44, 34, 116, 121, 112, 101, 34, 58, 34, 83, 71, 88, 32, 76, 97, + 116, 101, 32, 77, 105, 99, 114, 111, 99, 111, 100, 101, 32, 85, 112, 100, 97, 116, + 101, 34, 125, 44, 123, 34, 115, 118, 110, 34, 58, 51, 44, 34, 99, 97, 116, 101, + 103, 111, 114, 121, 34, 58, 34, 79, 83, 47, 86, 77, 77, 34, 44, 34, 116, 121, 112, + 101, 34, 58, 34, 84, 88, 84, 32, 83, 73, 78, 73, 84, 34, 125, 44, 123, 34, 115, + 118, 110, 34, 58, 51, 44, 34, 99, 97, 116, 101, 103, 111, 114, 121, 34, 58, 34, 66, + 73, 79, 83, 34, 125, 44, 123, 34, 115, 118, 110, 34, 58, 50, 53, 53, 125, 44, 123, + 34, 115, 118, 110, 34, 58, 50, 53, 53, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, + 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, + 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, + 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, + 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, + 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, + 125, 93, 44, 34, 112, 99, 101, 115, 118, 110, 34, 58, 49, 48, 125, 44, 34, 116, 99, + 98, 68, 97, 116, 101, 34, 58, 34, 50, 48, 50, 48, 45, 49, 49, 45, 49, 49, 84, 48, + 48, 58, 48, 48, 58, 48, 48, 90, 34, 44, 34, 116, 99, 98, 83, 116, 97, 116, 117, + 115, 34, 58, 34, 79, 117, 116, 79, 102, 68, 97, 116, 101, 34, 44, 34, 97, 100, 118, + 105, 115, 111, 114, 121, 73, 68, 115, 34, 58, 91, 34, 73, 78, 84, 69, 76, 45, 83, + 65, 45, 48, 48, 52, 55, 55, 34, 44, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, + 53, 56, 54, 34, 44, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 54, 49, 52, 34, + 44, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 54, 49, 53, 34, 44, 34, 73, 78, + 84, 69, 76, 45, 83, 65, 45, 48, 48, 54, 53, 55, 34, 44, 34, 73, 78, 84, 69, 76, 45, + 83, 65, 45, 48, 48, 55, 51, 48, 34, 44, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, + 48, 55, 51, 56, 34, 44, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 55, 54, 55, + 34, 93, 125, 44, 123, 34, 116, 99, 98, 34, 58, 123, 34, 115, 103, 120, 116, 99, 98, + 99, 111, 109, 112, 111, 110, 101, 110, 116, 115, 34, 58, 91, 123, 34, 115, 118, + 110, 34, 58, 52, 44, 34, 99, 97, 116, 101, 103, 111, 114, 121, 34, 58, 34, 66, 73, + 79, 83, 34, 44, 34, 116, 121, 112, 101, 34, 58, 34, 69, 97, 114, 108, 121, 32, 77, + 105, 99, 114, 111, 99, 111, 100, 101, 32, 85, 112, 100, 97, 116, 101, 34, 125, 44, + 123, 34, 115, 118, 110, 34, 58, 52, 44, 34, 99, 97, 116, 101, 103, 111, 114, 121, + 34, 58, 34, 79, 83, 47, 86, 77, 77, 34, 44, 34, 116, 121, 112, 101, 34, 58, 34, 83, + 71, 88, 32, 76, 97, 116, 101, 32, 77, 105, 99, 114, 111, 99, 111, 100, 101, 32, 85, + 112, 100, 97, 116, 101, 34, 125, 44, 123, 34, 115, 118, 110, 34, 58, 51, 44, 34, + 99, 97, 116, 101, 103, 111, 114, 121, 34, 58, 34, 79, 83, 47, 86, 77, 77, 34, 44, + 34, 116, 121, 112, 101, 34, 58, 34, 84, 88, 84, 32, 83, 73, 78, 73, 84, 34, 125, + 44, 123, 34, 115, 118, 110, 34, 58, 51, 44, 34, 99, 97, 116, 101, 103, 111, 114, + 121, 34, 58, 34, 66, 73, 79, 83, 34, 125, 44, 123, 34, 115, 118, 110, 34, 58, 50, + 53, 53, 125, 44, 123, 34, 115, 118, 110, 34, 58, 50, 53, 53, 125, 44, 123, 34, 115, + 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, + 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, + 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, + 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, + 34, 58, 48, 125, 44, 123, 34, 115, 118, 110, 34, 58, 48, 125, 44, 123, 34, 115, + 118, 110, 34, 58, 48, 125, 93, 44, 34, 112, 99, 101, 115, 118, 110, 34, 58, 53, + 125, 44, 34, 116, 99, 98, 68, 97, 116, 101, 34, 58, 34, 50, 48, 49, 56, 45, 48, 49, + 45, 48, 52, 84, 48, 48, 58, 48, 48, 58, 48, 48, 90, 34, 44, 34, 116, 99, 98, 83, + 116, 97, 116, 117, 115, 34, 58, 34, 79, 117, 116, 79, 102, 68, 97, 116, 101, 34, + 44, 34, 97, 100, 118, 105, 115, 111, 114, 121, 73, 68, 115, 34, 58, 91, 34, 73, 78, + 84, 69, 76, 45, 83, 65, 45, 48, 48, 49, 48, 54, 34, 44, 34, 73, 78, 84, 69, 76, 45, + 83, 65, 45, 48, 48, 49, 49, 53, 34, 44, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, + 48, 49, 51, 53, 34, 44, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 50, 48, 51, + 34, 44, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 50, 50, 48, 34, 44, 34, 73, + 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 50, 51, 51, 34, 44, 34, 73, 78, 84, 69, 76, + 45, 83, 65, 45, 48, 48, 50, 55, 48, 34, 44, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, + 48, 48, 50, 57, 51, 34, 44, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 51, 50, + 48, 34, 44, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 51, 50, 57, 34, 44, 34, + 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 51, 56, 49, 34, 44, 34, 73, 78, 84, 69, + 76, 45, 83, 65, 45, 48, 48, 51, 56, 57, 34, 44, 34, 73, 78, 84, 69, 76, 45, 83, 65, + 45, 48, 48, 52, 55, 55, 34, 44, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 53, + 56, 54, 34, 44, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 54, 49, 52, 34, 44, + 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 54, 49, 53, 34, 44, 34, 73, 78, 84, + 69, 76, 45, 83, 65, 45, 48, 48, 54, 53, 55, 34, 44, 34, 73, 78, 84, 69, 76, 45, 83, + 65, 45, 48, 48, 55, 51, 48, 34, 44, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, + 55, 51, 56, 34, 44, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 55, 54, 55, 34, + 93, 125, 93, 125, 44, 34, 115, 105, 103, 110, 97, 116, 117, 114, 101, 34, 58, 34, + 100, 52, 98, 49, 57, 56, 100, 51, 52, 55, 97, 56, 98, 49, 100, 55, 99, 97, 98, 49, + 102, 99, 99, 99, 51, 51, 98, 102, 98, 52, 51, 102, 52, 48, 97, 100, 98, 101, 50, + 48, 51, 102, 49, 50, 98, 57, 54, 50, 53, 49, 48, 53, 55, 55, 100, 53, 53, 54, 99, + 100, 102, 98, 49, 49, 56, 102, 48, 98, 101, 55, 49, 101, 49, 49, 97, 51, 97, 98, + 50, 99, 98, 53, 56, 102, 48, 54, 55, 56, 51, 53, 52, 98, 51, 57, 55, 52, 98, 54, + 97, 55, 97, 99, 53, 51, 49, 48, 51, 101, 54, 100, 101, 102, 54, 97, 98, 54, 48, 54, + 102, 57, 52, 50, 55, 52, 99, 55, 53, 97, 34, 125, 0, + ] + .into(), + qe_identity_issuer_chain: [ + 45, 45, 45, 45, 45, 66, 69, 71, 73, 78, 32, 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, + 69, 45, 45, 45, 45, 45, 10, 77, 73, 73, 67, 105, 122, 67, 67, 65, 106, 75, 103, 65, + 119, 73, 66, 65, 103, 73, 85, 102, 106, 105, 67, 49, 102, 116, 86, 75, 85, 112, 65, + 83, 89, 53, 70, 104, 65, 80, 112, 70, 74, 71, 57, 57, 70, 85, 119, 67, 103, 89, 73, + 75, 111, 90, 73, 122, 106, 48, 69, 65, 119, 73, 119, 10, 97, 68, 69, 97, 77, 66, + 103, 71, 65, 49, 85, 69, 65, 119, 119, 82, 83, 87, 53, 48, 90, 87, 119, 103, 85, + 48, 100, 89, 73, 70, 74, 118, 98, 51, 81, 103, 81, 48, 69, 120, 71, 106, 65, 89, + 66, 103, 78, 86, 66, 65, 111, 77, 69, 85, 108, 117, 100, 71, 86, 115, 73, 69, 78, + 118, 10, 99, 110, 66, 118, 99, 109, 70, 48, 97, 87, 57, 117, 77, 82, 81, 119, 69, + 103, 89, 68, 86, 81, 81, 72, 68, 65, 116, 84, 89, 87, 53, 48, 89, 83, 66, 68, 98, + 71, 70, 121, 89, 84, 69, 76, 77, 65, 107, 71, 65, 49, 85, 69, 67, 65, 119, 67, 81, + 48, 69, 120, 67, 122, 65, 74, 10, 66, 103, 78, 86, 66, 65, 89, 84, 65, 108, 86, 84, + 77, 66, 52, 88, 68, 84, 69, 52, 77, 68, 85, 121, 77, 84, 69, 119, 78, 84, 65, 120, + 77, 70, 111, 88, 68, 84, 73, 49, 77, 68, 85, 121, 77, 84, 69, 119, 78, 84, 65, 120, + 77, 70, 111, 119, 98, 68, 69, 101, 77, 66, 119, 71, 10, 65, 49, 85, 69, 65, 119, + 119, 86, 83, 87, 53, 48, 90, 87, 119, 103, 85, 48, 100, 89, 73, 70, 82, 68, 81, + 105, 66, 84, 97, 87, 100, 117, 97, 87, 53, 110, 77, 82, 111, 119, 71, 65, 89, 68, + 86, 81, 81, 75, 68, 66, 70, 74, 98, 110, 82, 108, 98, 67, 66, 68, 98, 51, 74, 119, + 10, 98, 51, 74, 104, 100, 71, 108, 118, 98, 106, 69, 85, 77, 66, 73, 71, 65, 49, + 85, 69, 66, 119, 119, 76, 85, 50, 70, 117, 100, 71, 69, 103, 81, 50, 120, 104, 99, + 109, 69, 120, 67, 122, 65, 74, 66, 103, 78, 86, 66, 65, 103, 77, 65, 107, 78, 66, + 77, 81, 115, 119, 67, 81, 89, 68, 10, 86, 81, 81, 71, 69, 119, 74, 86, 85, 122, 66, + 90, 77, 66, 77, 71, 66, 121, 113, 71, 83, 77, 52, 57, 65, 103, 69, 71, 67, 67, 113, + 71, 83, 77, 52, 57, 65, 119, 69, 72, 65, 48, 73, 65, 66, 69, 78, 70, 71, 56, 120, + 122, 121, 100, 87, 82, 102, 75, 57, 50, 98, 109, 71, 118, 10, 80, 43, 109, 65, 104, + 57, 49, 80, 69, 121, 86, 55, 74, 104, 54, 70, 71, 74, 100, 53, 110, 100, 69, 57, + 97, 66, 72, 55, 82, 51, 69, 52, 65, 55, 117, 98, 114, 108, 104, 47, 122, 78, 51, + 67, 52, 120, 118, 112, 111, 111, 117, 71, 108, 105, 114, 77, 98, 97, 43, 87, 50, + 108, 106, 117, 10, 121, 112, 97, 106, 103, 98, 85, 119, 103, 98, 73, 119, 72, 119, + 89, 68, 86, 82, 48, 106, 66, 66, 103, 119, 70, 111, 65, 85, 73, 109, 85, 77, 49, + 108, 113, 100, 78, 73, 110, 122, 103, 55, 83, 86, 85, 114, 57, 81, 71, 122, 107, + 110, 66, 113, 119, 119, 85, 103, 89, 68, 86, 82, 48, 102, 10, 66, 69, 115, 119, 83, + 84, 66, 72, 111, 69, 87, 103, 81, 52, 90, 66, 97, 72, 82, 48, 99, 72, 77, 54, 76, + 121, 57, 106, 90, 88, 74, 48, 97, 87, 90, 112, 89, 50, 70, 48, 90, 88, 77, 117, + 100, 72, 74, 49, 99, 51, 82, 108, 90, 72, 78, 108, 99, 110, 90, 112, 89, 50, 86, + 122, 10, 76, 109, 108, 117, 100, 71, 86, 115, 76, 109, 78, 118, 98, 83, 57, 74, 98, + 110, 82, 108, 98, 70, 78, 72, 87, 70, 74, 118, 98, 51, 82, 68, 81, 83, 53, 107, 90, + 88, 73, 119, 72, 81, 89, 68, 86, 82, 48, 79, 66, 66, 89, 69, 70, 72, 52, 52, 103, + 116, 88, 55, 86, 83, 108, 75, 10, 81, 69, 109, 79, 82, 89, 81, 68, 54, 82, 83, 82, + 118, 102, 82, 86, 77, 65, 52, 71, 65, 49, 85, 100, 68, 119, 69, 66, 47, 119, 81, + 69, 65, 119, 73, 71, 119, 68, 65, 77, 66, 103, 78, 86, 72, 82, 77, 66, 65, 102, 56, + 69, 65, 106, 65, 65, 77, 65, 111, 71, 67, 67, 113, 71, 10, 83, 77, 52, 57, 66, 65, + 77, 67, 65, 48, 99, 65, 77, 69, 81, 67, 73, 66, 57, 67, 56, 119, 79, 65, 78, 47, + 73, 109, 120, 68, 116, 71, 65, 67, 86, 50, 52, 54, 75, 99, 113, 106, 97, 103, 90, + 79, 82, 48, 107, 121, 99, 116, 121, 66, 114, 115, 71, 71, 74, 86, 65, 105, 65, 106, + 10, 102, 116, 98, 114, 78, 71, 115, 71, 85, 56, 89, 72, 50, 49, 49, 100, 82, 105, + 89, 78, 111, 80, 80, 117, 49, 57, 90, 112, 47, 122, 101, 56, 74, 109, 104, 117, + 106, 66, 48, 111, 66, 119, 61, 61, 10, 45, 45, 45, 45, 45, 69, 78, 68, 32, 67, 69, + 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, 10, 45, 45, 45, 45, 45, 66, + 69, 71, 73, 78, 32, 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, + 10, 77, 73, 73, 67, 106, 122, 67, 67, 65, 106, 83, 103, 65, 119, 73, 66, 65, 103, + 73, 85, 73, 109, 85, 77, 49, 108, 113, 100, 78, 73, 110, 122, 103, 55, 83, 86, 85, + 114, 57, 81, 71, 122, 107, 110, 66, 113, 119, 119, 67, 103, 89, 73, 75, 111, 90, + 73, 122, 106, 48, 69, 65, 119, 73, 119, 10, 97, 68, 69, 97, 77, 66, 103, 71, 65, + 49, 85, 69, 65, 119, 119, 82, 83, 87, 53, 48, 90, 87, 119, 103, 85, 48, 100, 89, + 73, 70, 74, 118, 98, 51, 81, 103, 81, 48, 69, 120, 71, 106, 65, 89, 66, 103, 78, + 86, 66, 65, 111, 77, 69, 85, 108, 117, 100, 71, 86, 115, 73, 69, 78, 118, 10, 99, + 110, 66, 118, 99, 109, 70, 48, 97, 87, 57, 117, 77, 82, 81, 119, 69, 103, 89, 68, + 86, 81, 81, 72, 68, 65, 116, 84, 89, 87, 53, 48, 89, 83, 66, 68, 98, 71, 70, 121, + 89, 84, 69, 76, 77, 65, 107, 71, 65, 49, 85, 69, 67, 65, 119, 67, 81, 48, 69, 120, + 67, 122, 65, 74, 10, 66, 103, 78, 86, 66, 65, 89, 84, 65, 108, 86, 84, 77, 66, 52, + 88, 68, 84, 69, 52, 77, 68, 85, 121, 77, 84, 69, 119, 78, 68, 85, 120, 77, 70, 111, + 88, 68, 84, 81, 53, 77, 84, 73, 122, 77, 84, 73, 122, 78, 84, 107, 49, 79, 86, 111, + 119, 97, 68, 69, 97, 77, 66, 103, 71, 10, 65, 49, 85, 69, 65, 119, 119, 82, 83, 87, + 53, 48, 90, 87, 119, 103, 85, 48, 100, 89, 73, 70, 74, 118, 98, 51, 81, 103, 81, + 48, 69, 120, 71, 106, 65, 89, 66, 103, 78, 86, 66, 65, 111, 77, 69, 85, 108, 117, + 100, 71, 86, 115, 73, 69, 78, 118, 99, 110, 66, 118, 99, 109, 70, 48, 10, 97, 87, + 57, 117, 77, 82, 81, 119, 69, 103, 89, 68, 86, 81, 81, 72, 68, 65, 116, 84, 89, 87, + 53, 48, 89, 83, 66, 68, 98, 71, 70, 121, 89, 84, 69, 76, 77, 65, 107, 71, 65, 49, + 85, 69, 67, 65, 119, 67, 81, 48, 69, 120, 67, 122, 65, 74, 66, 103, 78, 86, 66, 65, + 89, 84, 10, 65, 108, 86, 84, 77, 70, 107, 119, 69, 119, 89, 72, 75, 111, 90, 73, + 122, 106, 48, 67, 65, 81, 89, 73, 75, 111, 90, 73, 122, 106, 48, 68, 65, 81, 99, + 68, 81, 103, 65, 69, 67, 54, 110, 69, 119, 77, 68, 73, 89, 90, 79, 106, 47, 105, + 80, 87, 115, 67, 122, 97, 69, 75, 105, 55, 10, 49, 79, 105, 79, 83, 76, 82, 70, + 104, 87, 71, 106, 98, 110, 66, 86, 74, 102, 86, 110, 107, 89, 52, 117, 51, 73, 106, + 107, 68, 89, 89, 76, 48, 77, 120, 79, 52, 109, 113, 115, 121, 89, 106, 108, 66, 97, + 108, 84, 86, 89, 120, 70, 80, 50, 115, 74, 66, 75, 53, 122, 108, 75, 79, 66, 10, + 117, 122, 67, 66, 117, 68, 65, 102, 66, 103, 78, 86, 72, 83, 77, 69, 71, 68, 65, + 87, 103, 66, 81, 105, 90, 81, 122, 87, 87, 112, 48, 48, 105, 102, 79, 68, 116, 74, + 86, 83, 118, 49, 65, 98, 79, 83, 99, 71, 114, 68, 66, 83, 66, 103, 78, 86, 72, 82, + 56, 69, 83, 122, 66, 74, 10, 77, 69, 101, 103, 82, 97, 66, 68, 104, 107, 70, 111, + 100, 72, 82, 119, 99, 122, 111, 118, 76, 50, 78, 108, 99, 110, 82, 112, 90, 109, + 108, 106, 89, 88, 82, 108, 99, 121, 53, 48, 99, 110, 86, 122, 100, 71, 86, 107, 99, + 50, 86, 121, 100, 109, 108, 106, 90, 88, 77, 117, 97, 87, 53, 48, 10, 90, 87, 119, + 117, 89, 50, 57, 116, 76, 48, 108, 117, 100, 71, 86, 115, 85, 48, 100, 89, 85, 109, + 57, 118, 100, 69, 78, 66, 76, 109, 82, 108, 99, 106, 65, 100, 66, 103, 78, 86, 72, + 81, 52, 69, 70, 103, 81, 85, 73, 109, 85, 77, 49, 108, 113, 100, 78, 73, 110, 122, + 103, 55, 83, 86, 10, 85, 114, 57, 81, 71, 122, 107, 110, 66, 113, 119, 119, 68, + 103, 89, 68, 86, 82, 48, 80, 65, 81, 72, 47, 66, 65, 81, 68, 65, 103, 69, 71, 77, + 66, 73, 71, 65, 49, 85, 100, 69, 119, 69, 66, 47, 119, 81, 73, 77, 65, 89, 66, 65, + 102, 56, 67, 65, 81, 69, 119, 67, 103, 89, 73, 10, 75, 111, 90, 73, 122, 106, 48, + 69, 65, 119, 73, 68, 83, 81, 65, 119, 82, 103, 73, 104, 65, 79, 87, 47, 53, 81, + 107, 82, 43, 83, 57, 67, 105, 83, 68, 99, 78, 111, 111, 119, 76, 117, 80, 82, 76, + 115, 87, 71, 102, 47, 89, 105, 55, 71, 83, 88, 57, 52, 66, 103, 119, 84, 119, 103, + 10, 65, 105, 69, 65, 52, 74, 48, 108, 114, 72, 111, 77, 115, 43, 88, 111, 53, 111, + 47, 115, 88, 54, 79, 57, 81, 87, 120, 72, 82, 65, 118, 90, 85, 71, 79, 100, 82, 81, + 55, 99, 118, 113, 82, 88, 97, 113, 73, 61, 10, 45, 45, 45, 45, 45, 69, 78, 68, 32, + 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, 10, 0, + ] + .into(), + qe_identity: [ + 123, 34, 101, 110, 99, 108, 97, 118, 101, 73, 100, 101, 110, 116, 105, 116, 121, + 34, 58, 123, 34, 105, 100, 34, 58, 34, 81, 69, 34, 44, 34, 118, 101, 114, 115, 105, + 111, 110, 34, 58, 50, 44, 34, 105, 115, 115, 117, 101, 68, 97, 116, 101, 34, 58, + 34, 50, 48, 50, 51, 45, 48, 54, 45, 50, 49, 84, 49, 48, 58, 53, 56, 58, 51, 51, 90, + 34, 44, 34, 110, 101, 120, 116, 85, 112, 100, 97, 116, 101, 34, 58, 34, 50, 48, 50, + 51, 45, 48, 55, 45, 50, 49, 84, 49, 48, 58, 53, 56, 58, 51, 51, 90, 34, 44, 34, + 116, 99, 98, 69, 118, 97, 108, 117, 97, 116, 105, 111, 110, 68, 97, 116, 97, 78, + 117, 109, 98, 101, 114, 34, 58, 49, 53, 44, 34, 109, 105, 115, 99, 115, 101, 108, + 101, 99, 116, 34, 58, 34, 48, 48, 48, 48, 48, 48, 48, 48, 34, 44, 34, 109, 105, + 115, 99, 115, 101, 108, 101, 99, 116, 77, 97, 115, 107, 34, 58, 34, 70, 70, 70, 70, + 70, 70, 70, 70, 34, 44, 34, 97, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 58, + 34, 49, 49, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 34, 44, 34, 97, 116, 116, 114, 105, + 98, 117, 116, 101, 115, 77, 97, 115, 107, 34, 58, 34, 70, 66, 70, 70, 70, 70, 70, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 34, 44, 34, 109, 114, 115, 105, 103, 110, 101, 114, 34, 58, 34, 56, + 67, 52, 70, 53, 55, 55, 53, 68, 55, 57, 54, 53, 48, 51, 69, 57, 54, 49, 51, 55, 70, + 55, 55, 67, 54, 56, 65, 56, 50, 57, 65, 48, 48, 53, 54, 65, 67, 56, 68, 69, 68, 55, + 48, 49, 52, 48, 66, 48, 56, 49, 66, 48, 57, 52, 52, 57, 48, 67, 53, 55, 66, 70, 70, + 34, 44, 34, 105, 115, 118, 112, 114, 111, 100, 105, 100, 34, 58, 49, 44, 34, 116, + 99, 98, 76, 101, 118, 101, 108, 115, 34, 58, 91, 123, 34, 116, 99, 98, 34, 58, 123, + 34, 105, 115, 118, 115, 118, 110, 34, 58, 56, 125, 44, 34, 116, 99, 98, 68, 97, + 116, 101, 34, 58, 34, 50, 48, 50, 51, 45, 48, 50, 45, 49, 53, 84, 48, 48, 58, 48, + 48, 58, 48, 48, 90, 34, 44, 34, 116, 99, 98, 83, 116, 97, 116, 117, 115, 34, 58, + 34, 85, 112, 84, 111, 68, 97, 116, 101, 34, 125, 44, 123, 34, 116, 99, 98, 34, 58, + 123, 34, 105, 115, 118, 115, 118, 110, 34, 58, 54, 125, 44, 34, 116, 99, 98, 68, + 97, 116, 101, 34, 58, 34, 50, 48, 50, 49, 45, 49, 49, 45, 49, 48, 84, 48, 48, 58, + 48, 48, 58, 48, 48, 90, 34, 44, 34, 116, 99, 98, 83, 116, 97, 116, 117, 115, 34, + 58, 34, 79, 117, 116, 79, 102, 68, 97, 116, 101, 34, 44, 34, 97, 100, 118, 105, + 115, 111, 114, 121, 73, 68, 115, 34, 58, 91, 34, 73, 78, 84, 69, 76, 45, 83, 65, + 45, 48, 48, 54, 49, 53, 34, 93, 125, 44, 123, 34, 116, 99, 98, 34, 58, 123, 34, + 105, 115, 118, 115, 118, 110, 34, 58, 53, 125, 44, 34, 116, 99, 98, 68, 97, 116, + 101, 34, 58, 34, 50, 48, 50, 48, 45, 49, 49, 45, 49, 49, 84, 48, 48, 58, 48, 48, + 58, 48, 48, 90, 34, 44, 34, 116, 99, 98, 83, 116, 97, 116, 117, 115, 34, 58, 34, + 79, 117, 116, 79, 102, 68, 97, 116, 101, 34, 44, 34, 97, 100, 118, 105, 115, 111, + 114, 121, 73, 68, 115, 34, 58, 91, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, + 52, 55, 55, 34, 44, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 54, 49, 53, 34, + 93, 125, 44, 123, 34, 116, 99, 98, 34, 58, 123, 34, 105, 115, 118, 115, 118, 110, + 34, 58, 52, 125, 44, 34, 116, 99, 98, 68, 97, 116, 101, 34, 58, 34, 50, 48, 49, 57, + 45, 49, 49, 45, 49, 51, 84, 48, 48, 58, 48, 48, 58, 48, 48, 90, 34, 44, 34, 116, + 99, 98, 83, 116, 97, 116, 117, 115, 34, 58, 34, 79, 117, 116, 79, 102, 68, 97, 116, + 101, 34, 44, 34, 97, 100, 118, 105, 115, 111, 114, 121, 73, 68, 115, 34, 58, 91, + 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 51, 51, 52, 34, 44, 34, 73, 78, 84, + 69, 76, 45, 83, 65, 45, 48, 48, 52, 55, 55, 34, 44, 34, 73, 78, 84, 69, 76, 45, 83, + 65, 45, 48, 48, 54, 49, 53, 34, 93, 125, 44, 123, 34, 116, 99, 98, 34, 58, 123, 34, + 105, 115, 118, 115, 118, 110, 34, 58, 50, 125, 44, 34, 116, 99, 98, 68, 97, 116, + 101, 34, 58, 34, 50, 48, 49, 57, 45, 48, 53, 45, 49, 53, 84, 48, 48, 58, 48, 48, + 58, 48, 48, 90, 34, 44, 34, 116, 99, 98, 83, 116, 97, 116, 117, 115, 34, 58, 34, + 79, 117, 116, 79, 102, 68, 97, 116, 101, 34, 44, 34, 97, 100, 118, 105, 115, 111, + 114, 121, 73, 68, 115, 34, 58, 91, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, + 50, 49, 57, 34, 44, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 50, 57, 51, 34, + 44, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 51, 51, 52, 34, 44, 34, 73, 78, + 84, 69, 76, 45, 83, 65, 45, 48, 48, 52, 55, 55, 34, 44, 34, 73, 78, 84, 69, 76, 45, + 83, 65, 45, 48, 48, 54, 49, 53, 34, 93, 125, 44, 123, 34, 116, 99, 98, 34, 58, 123, + 34, 105, 115, 118, 115, 118, 110, 34, 58, 49, 125, 44, 34, 116, 99, 98, 68, 97, + 116, 101, 34, 58, 34, 50, 48, 49, 56, 45, 48, 56, 45, 49, 53, 84, 48, 48, 58, 48, + 48, 58, 48, 48, 90, 34, 44, 34, 116, 99, 98, 83, 116, 97, 116, 117, 115, 34, 58, + 34, 79, 117, 116, 79, 102, 68, 97, 116, 101, 34, 44, 34, 97, 100, 118, 105, 115, + 111, 114, 121, 73, 68, 115, 34, 58, 91, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, + 48, 50, 48, 50, 34, 44, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 50, 49, 57, + 34, 44, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 50, 57, 51, 34, 44, 34, 73, + 78, 84, 69, 76, 45, 83, 65, 45, 48, 48, 51, 51, 52, 34, 44, 34, 73, 78, 84, 69, 76, + 45, 83, 65, 45, 48, 48, 52, 55, 55, 34, 44, 34, 73, 78, 84, 69, 76, 45, 83, 65, 45, + 48, 48, 54, 49, 53, 34, 93, 125, 93, 125, 44, 34, 115, 105, 103, 110, 97, 116, 117, + 114, 101, 34, 58, 34, 99, 53, 56, 102, 100, 100, 99, 52, 98, 57, 101, 102, 54, 53, + 48, 48, 53, 50, 50, 100, 55, 99, 55, 50, 48, 57, 54, 97, 97, 49, 54, 102, 53, 55, + 101, 98, 99, 52, 53, 56, 102, 99, 57, 56, 55, 99, 98, 49, 48, 53, 98, 49, 56, 51, + 53, 99, 56, 56, 52, 99, 52, 54, 54, 102, 99, 98, 57, 48, 52, 56, 53, 54, 56, 51, + 56, 55, 101, 98, 52, 57, 101, 102, 54, 49, 50, 99, 57, 50, 99, 51, 57, 50, 48, 102, + 51, 102, 49, 54, 99, 57, 101, 102, 100, 56, 51, 97, 57, 48, 97, 98, 99, 50, 54, 48, + 99, 53, 100, 98, 56, 55, 101, 97, 99, 100, 54, 53, 56, 49, 34, 125, 0, + ] + .into(), + }; + + let current_time = 1687346037; + + let report_data = hex::decode("997bfae2d7f9089d176b18b5cef2d81dec1fd1dc332e9b23c553c4e02fe3e4ab0000000000000000000000000000000000000000000000000000000000000000").unwrap(); + + let mrsigner = + hex::decode("3b909bb3658ff42a1e877b8806fdab857f70dfc90244270c12ec2459c98d191a") + .unwrap(); + + check_quote( + "e, + &collateral, + current_time, + &mrsigner, + &report_data, + sgx_ql_qv_result_t::SGX_QL_QV_RESULT_SW_HARDENING_NEEDED, + ) + .unwrap(); + } +} diff --git a/vault/Dockerfile b/vault/Dockerfile new file mode 100644 index 0000000..0dfd3e2 --- /dev/null +++ b/vault/Dockerfile @@ -0,0 +1,53 @@ +FROM docker.io/ubuntu:focal + +RUN set -eux; \ + apt-get update; \ + apt-get install -y curl gpg; + +RUN set -eux; \ + curl -fsSLo /usr/share/keyrings/gramine-keyring.gpg https://packages.gramineproject.io/gramine-keyring.gpg; \ + echo "deb [arch=amd64 signed-by=/usr/share/keyrings/gramine-keyring.gpg] https://packages.gramineproject.io/ focal main" > /etc/apt/sources.list.d/gramine.list + +RUN set -eux; \ + curl -fsSLo /usr/share/keyrings/intel-sgx-deb.asc https://download.01.org/intel-sgx/sgx_repo/ubuntu/intel-sgx-deb.key; \ + echo "deb [arch=amd64 signed-by=/usr/share/keyrings/intel-sgx-deb.asc] https://download.01.org/intel-sgx/sgx_repo/ubuntu focal main" > /etc/apt/sources.list.d/intel-sgx.list + +RUN set -eux; \ + curl -fsSLo /usr/share/keyrings/microsoft.asc https://packages.microsoft.com/keys/microsoft.asc; \ + echo "deb [arch=amd64 signed-by=/usr/share/keyrings/microsoft.asc] https://packages.microsoft.com/ubuntu/20.04/prod focal main" > /etc/apt/sources.list.d/msprod.list + +# Install gramine +RUN set -eux; \ + apt-get update; \ + DEBIAN_FRONTEND=noninteractive apt-get install -y gramine \ + libsgx-urts \ + libsgx-enclave-common \ + libsgx-dcap-quote-verify \ + az-dcap-client \ + psmisc \ + ; + +RUN set -eux; \ + curl -s -o - https://apt.releases.hashicorp.com/gpg | gpg --dearmor > /usr/share/keyrings/hashicorp-archive-keyring.gpg; \ + echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com focal main" > /etc/apt/sources.list.d/hashicorp.list; \ + apt-get update; \ + apt-get install -y --no-install-recommends vault libcap2-bin; + +RUN rm -rf /var/lib/apt/lists/* + +WORKDIR /opt/vault +COPY vault/vault.manifest.toml vault/config.hcl vault/vault-csr.conf vault/cakey.pem vault/cacert.pem vault/start.sh ./ +RUN mkdir -p /opt/vault/data /opt/vault/.cache /opt/vault/tls && rm -rf /opt/vault/tls/* + +COPY vault/enclave-key.pem /tmp/ +RUN set -eux; \ + find / -xdev -print0 | xargs -0 touch -r /usr/bin/vault || : ; \ + gramine-manifest -Darch_libdir=/lib/x86_64-linux-gnu -Dexecdir=/usr/bin -Dlog_level=warning vault.manifest.toml vault.manifest; \ + gramine-sgx-sign --manifest vault.manifest --output vault.manifest.sgx --key /tmp/enclave-key.pem; \ + rm /tmp/enclave-key.pem + +VOLUME /opt/vault/tls +VOLUME /opt/vault/data + +ENTRYPOINT ["/bin/sh", "-c"] +CMD [ "/restart_aesm.sh ; exec gramine-sgx vault" ] diff --git a/vault/cacert.pem b/vault/cacert.pem new file mode 100644 index 0000000..405b43f --- /dev/null +++ b/vault/cacert.pem @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFSDCCAzCgAwIBAgIUDjUfoOY4o+E38mka8ViQOPpHBhgwDQYJKoZIhvcNAQEL +BQAwLTEZMBcGA1UECgwQVGVzdCBDQSwgTGltaXRlZDEQMA4GA1UEAwwHVGVzdCBD +QTAeFw0yMzA2MDYwNzU4MTNaFw0yNDA2MDUwNzU4MTNaMC0xGTAXBgNVBAoMEFRl +c3QgQ0EsIExpbWl0ZWQxEDAOBgNVBAMMB1Rlc3QgQ0EwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQD4hjplzpqaXoWL/8bex/zBStuYmBuOGvIELS5aiHfw +XfGnOwIViIMf+ikuxASYj3AmEmPOCXXbUsARe/0cHn438rVbeFK6cJl/kXlwGMOy +SpXbKDqrmM+U2lUyrcmHRapHvwBaKU5LKumsshurP62DlpcZ6Imasmtlm9t+NJfP +esTEKAhzuRGwcEaOXkvksK7QXEwl3q4da4ST/+qjfnYq/gA6PFgHHWRo8qXPa62H +pPcYkCiCfd4oYSSqH6kEeym2upDVVjtAo6y7ytQU0DNs51vR+ePL9qd3WVWnzm9z +66V9ZUCqfU1LY4dAMEN8UH2QiXPVyFG/Y2lb7gtltI7D2D4C63vgCS657cRcOMg/ +xbiYXaVh0BQvJkznyv+IOkU8a42Uth/CX7Tv9N2n4X5accV82oUHtW3BbeYxW4Wb +dTfsMir/q50io/l3nbPlzA28GwlZ3owdi22/Tdc+yg7NxOHPpJ6ZULK6d9n1glV5 +PDkO9J8Ad1MZwkKKMh+tPdccNarUkdBj0K8tpZqBmjhMWQddwAd5MZGWS0VBKBZb +b5Z9ivqZ70oQSx8HKE3EGWSfT6ZJVhQ4XDAdMpw+wQcZQ+6twIpAQU3k6imJ4yGz +ZYIOF2izn8Z4vBE4I/vKrpFci3mBDIJl59x49uAi5KpTBeeY/lLMnFLRa5sDUtLn +kwIDAQABo2AwXjAdBgNVHQ4EFgQU4ZHyVkjYaunC0Rk9PtDsk8nALhcwHwYDVR0j +BBgwFoAU4ZHyVkjYaunC0Rk9PtDsk8nALhcwDwYDVR0TAQH/BAUwAwEB/zALBgNV +HQ8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBAIGigs3CZO1DdnaxZwUghMm95NAX +D7vKYFAmoNtbVBv1NAfpv23XOhAzccEFGg20XEa1t2z0Nfct9NDXxZ2VCgU+9vws +d96EBkufgnKrc/hLxRnVsExQxy5FKYz/d5LePeYd1OFS0bw+DRpzEnFZm34vpToj +mku845LtHbeZEzaVdzaSu9m7YcoENGgGuOlsgvp/qB6MlxI0fHG5M2M5aLnIEyIv +QAMmX42eJ09jhaLr8dl2zLImyIYO0dMO0NNl5gU01cpJ5REHJ3e3oUDUJ5ZZCL51 +/VYSd/btHYRCdH/w6FSUOGGwU38LhhbeD94103gkKS5bfIui77sY0F3jRIluVQci +PnKzRNsfl5uL8KICDJtT6uNwkhSG4ucYNAb21eo6idzyMe4qdJz1poPjmph19rnU +oAE/0+jqOyVErBZuRAL9wbQg1Prqx1WBsOIUyi5Y7qAUt+AuDt0uf4mdRnE1yDvw +o0CIz3XLD1YoHXqJ/Nu1By1fI2zA0Y7osSX4SzfbD0EUXqjUyy80KrvKmJaV8lMd +1/jGHuApNQjZFwbY+RN0OTtDk7zPAETaGz/15BEmVDpq0OAVqe0XrXpQfaYwHzzq +TsOvVYZSj2gsDbKzM8tmCkLoS+Yh5ubxaoIE2qCjvFNXZwFzqQtDgBKQhjuE54+K +lweZ5hgUkLPf5EW0 +-----END CERTIFICATE----- diff --git a/vault/cakey.pem b/vault/cakey.pem new file mode 100644 index 0000000..b457997 --- /dev/null +++ b/vault/cakey.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQD4hjplzpqaXoWL +/8bex/zBStuYmBuOGvIELS5aiHfwXfGnOwIViIMf+ikuxASYj3AmEmPOCXXbUsAR +e/0cHn438rVbeFK6cJl/kXlwGMOySpXbKDqrmM+U2lUyrcmHRapHvwBaKU5LKums +shurP62DlpcZ6Imasmtlm9t+NJfPesTEKAhzuRGwcEaOXkvksK7QXEwl3q4da4ST +/+qjfnYq/gA6PFgHHWRo8qXPa62HpPcYkCiCfd4oYSSqH6kEeym2upDVVjtAo6y7 +ytQU0DNs51vR+ePL9qd3WVWnzm9z66V9ZUCqfU1LY4dAMEN8UH2QiXPVyFG/Y2lb +7gtltI7D2D4C63vgCS657cRcOMg/xbiYXaVh0BQvJkznyv+IOkU8a42Uth/CX7Tv +9N2n4X5accV82oUHtW3BbeYxW4WbdTfsMir/q50io/l3nbPlzA28GwlZ3owdi22/ +Tdc+yg7NxOHPpJ6ZULK6d9n1glV5PDkO9J8Ad1MZwkKKMh+tPdccNarUkdBj0K8t +pZqBmjhMWQddwAd5MZGWS0VBKBZbb5Z9ivqZ70oQSx8HKE3EGWSfT6ZJVhQ4XDAd +Mpw+wQcZQ+6twIpAQU3k6imJ4yGzZYIOF2izn8Z4vBE4I/vKrpFci3mBDIJl59x4 +9uAi5KpTBeeY/lLMnFLRa5sDUtLnkwIDAQABAoICABokGFFsHXP+XELBGTyGwa3d +P2L6IO/eIrXQwM7yCtekMg56lPoJ3W0IJbvPD4Kyl8PRbGEYOqbiueQ86/9Ar9sX +sv7XlbAZtvOlrCXf3PnMgZ3HSgCRtsf7/Tky8X9Ckyovy4wwSxV6ApFRPLrTHF+6 +f9NQU+ULPmO2NKy+QHeo/Lh7U4REo7kw3iMMhSQdd43gH3xeQ2dBz3S31wjyfOCB +zilR/ppk+5JUb591PpAFiJ4zT6eGMM+DhFVGtkML53PahPCDvQDMFpe8Onmj+rzK +Syy3gcALBkt2AJ4Bh1SkpUge1eH5Ax/abLgSO48Acmy5II+MnhipDsSGMfm1N8zp +yjzitqay1B/8VHu8FJ7up4XbLvvhjG3uKLchARJ9pGjJ8JYdFNcxv+ZBD2H111J5 +b5XHHII1W/6wgpcB6SesasjoTe/jJhPPosvUT+QuT3IG46TDE4ct8+20kSP3vmm4 +FtgfyMFNqh7/GR42UMDjMcx+zCUPpQj9KTH1KUHnW/tQqqb0+lCwTw9vuMBxxysD +KjG5qxaLqY9uIQ3h+hSuTGtPOIFt3uMrZMp6R1pMmWr+imPED7NAildbOqsCxI00 +1icPp43vOVdFYIlVX3FZLGUg5c9SkTv5O628HUoHQM+TPqG6bysA+w/pL2d9ByPX +5N3LfbqPTr9PYYd6owNBAoIBAQD89s1MDFY1E6cuP8ut2avrwJzqm0u7FzCxbXC9 +PUgzUKdcVZ7ilQxEM8GRijq0HegefycPwR5oYF8OtpXsuXJ81q69jW1hYHWTSER2 +VrjWhF5TiKoaiLW1YfSX3IQRZ2zpLKRKC1IvsOzd115Yl0gjHBXlK875z3t2d61q +grCG/QjfXer+5pJsOjxROS+lob6pDohHJLIaRYheLRVstiG+o0pk6LCVo1UPqdQN +rZ6pUoBZjaX56alP1xexMguN1/2GRTgkk1BUdOJ/wfpQv6VW7EpdwwkVJxZ+c77P +6zy6FkELtSCuEYt8ETmCnYzUBJs58ZSKqar4+BFD4b4w1nRTAoIBAQD7gckhaW7G +gHZsiaGfgsnf7kVJmeBJ5WnCTAXRDUQRK+/KEz+4uyVFoeX0czIoviYOWOn6Sg4I +qHIUkYkIG/aOCo0z5HnxoXwAA5HY/3ZLzMGlM2sqoQpPCFUQE//a5eYfSyyOVFQO +LoJpJyPIWppYPPo6AMy/OTXl9R6I/kN98cya8scWfwakNfgA8jhnii0ezEr1WwR8 +nrK2SBhO9Rl2FcUSNXbOtk8BmcimW5IoDiATssLyReEqoQhrCgt8It90OtozT1GQ +qjL7ZG786s02YuBddU5t27qbqFGn4XXQk3ArCFsOUqUf8Lj5U6mZ75sNRrU1O8NB +J4Q7E+geT1fBAoIBAEmuVXPuL/n7xHlLKbd0rIfZrZsEKtXO1mcHuovUWsBfoK/b +XJEg2tbOwHX07k5iW6buYGFNXd8HGwj9E8RE690C5xjdJdv0Lar9pLtXXTVWjucD +6pAZ+9teMdE98NXk6ysrzpqmm4S6ovOm9JsXTXK0jogW742B6rNB/qgEcwiOkVQG +Vhly7XlKqSD7aC51Y0R4sCcQwDO4xxSvSwtELaYKh/PGdxDO50rNq69kP8+P8USk +ZpDZh3By9TqumgDxxa2jYcv9gKto9EREKvX0LGOaJbsTwQSBQyMH8a88FI8bRkzz +sBYjlB5KIhcybr+eq9v/ysVs0Bj+oIDGMxCklnMCggEAcT+hl1/oN43ExV673h2A +VUru/BNDwUKB+rFMtTNqAOlt0eoU+VOblt0ttILihSIJ9M/om4EZDKD8rXJS58nf +nVn29vTcTAdQ1JjG5ZUyaTNLxt1+VfWptKil1NWMkb6PfmvVJkmmh7Q9mKe9Hwxd +D3p1mgSeLUTPljpng3wqW92zKdpD90c/cFW01Ig9CbJYWtPWtOBFBvBWvGl+OJ94 +1Yk78dUNKEtDDA95IB9/knW5z+Tgj0MT/qQALGKbhUwWnjmZ4xzGN4PL7RLuPwhj +Wyfuq2aU6DbWshx6mEOXT1H0YgwjJDHmlJlKUUpwxhX0FWhPVCcS5pWqnwd5r5w+ +gQKCAQAG6FIn1Gh0kqlMZBp0g/NXXaC+ZqKu/GzDk5o0inGaZXjlE0XlgjAHZBCn +DlxQsZiA1rXTOZu9oIvaVD5Kqr9PmCiRc0a17CNVK6dfBHBI4+vscVaZev10BjAD +tIvZ+E9SqP7MRWYmNeOhSVPtty9VWCwAcKFP4zhAqfykyl9EzFvLFuoYNWy36Ggm +EpSWHzD3ju/t/31FcAWyQ3ZzN9Z6zAd909S3YvTfBRY2HLiXzKSRKT+4BzKr5UkG +y1aXeDQQlykdxehMU7EFu9pzFR+P3iTTh93qbcSgrWIDVUjBGhnLI03wxlLN2XPA +ddNNT9BMXrut8KdPM9+L+8v5a57L +-----END PRIVATE KEY----- diff --git a/vault/config.hcl b/vault/config.hcl new file mode 100644 index 0000000..2197153 --- /dev/null +++ b/vault/config.hcl @@ -0,0 +1,55 @@ +# Parameter needed because of slow plugin loading +# may be relaxed for faster machines +#http_read_header_timeout = 0 +#http_read_timeout = 300 + +disable_mlock = true +ui = false + +listener "tcp" { + address = "0.0.0.0:8210" + cluster_address = "0.0.0.0:8211" + tls_disable = false + tls_cert_file = "/opt/vault/tls/tls.crt" + tls_key_file = "/opt/vault/tls/tls.key" + tls_client_ca_file = "/opt/vault/cacert.pem" +} + +storage "raft" { + path = "/opt/vault/data/" + # override vial env var VAULT_RAFT_NODE_ID + node_id = "vault-1" + + # Parameter needed because of slow plugin loading + # may be relaxed for faster machines + performance_multiplier = 200 + #autopilot_reconcile_interval = "120s" + #autopilot_update_interval = "60s" + + retry_join { + leader_api_addr = "https://vault-1:8210" + leader_ca_cert_file = "/opt/vault/cacert.pem" + leader_client_cert_file = "/opt/vault/tls/tls.crt" + leader_client_key_file = "/opt/vault/tls/tls.key" + } + retry_join { + leader_api_addr = "https://vault-2:8210" + leader_ca_cert_file = "/opt/vault/cacert.pem" + leader_client_cert_file = "/opt/vault/tls/tls.crt" + leader_client_key_file = "/opt/vault/tls/tls.key" + } + retry_join { + leader_api_addr = "https://vault-3:8210" + leader_ca_cert_file = "/opt/vault/cacert.pem" + leader_client_cert_file = "/opt/vault/tls/tls.crt" + leader_client_key_file = "/opt/vault/tls/tls.key" + } +} + +# path of plugin binaries +plugin_directory = "/opt/vault/plugins" + +# override via env var VAULT_API_ADDR +api_addr = "https://vault:8210" +# override via env var VAULT_CLUSTER_ADDR +cluster_addr = "https://vault:8211" diff --git a/vault/enclave-key.pem b/vault/enclave-key.pem new file mode 100644 index 0000000..53b317a --- /dev/null +++ b/vault/enclave-key.pem @@ -0,0 +1,39 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIG5AIBAAKCAYEAwDrEJDyGnIGv/xWF4/MQtVEshpft/xGECSdjuHOU87nwCWon +hirmOyggPPU772tobmaqRhAMHn0NwvRyFCQcSwTIjd0e/cfwH/QtEd/fp4yaw/z7 +FZmesTm+wjaobnRfPwrNHAfM8U2EQPXp1yYyjUqPVEXb/7ivdR+u7qnb0o6oNfzA +ibRF6H+Fozj5FwepfbQ1DTauTEwdjywD+/21W+Ru5qF7SQVHYwf9OuyD4yZBm9os +0Aqnk1nO6ZUSJfrL1gd10LoblnPUjNxwQtWhxIPyeKRYwmVpoaYL45U+6iNOkBiL +PyGJDC+lq+AS8YtwzPOt3pUUpFh/XZyxSHla3Q8qPAikjcv1DvTiK+NVEVXoFrbs +/uG6Ii9BSRbZ3NQH1bOLtdkW7W6GPGCMr/KuXEvIQaOpDb27/DEtvCh3T/9vrKsO +etpTI0an6NZ1oshZ3X2TxZ9nNxh9zMvPswXBdy9O9/WybAN6a1PvIb3v66bxJW6T +Pu87/q0DKzeMM20pAgEDAoIBgQCAJy1tfa8TAR//Y66X92B44MhZup6qC61bb5fQ +TQ330Uqw8W+ux0QncBV9+NKfnPBJmcbZYAgUU16B+EwNbWgyAzBek2n+hUq/+B4L +6pUaXbyCqKdju78g0SnWzxr0TZTUsd4Sr932M62Ao/E6GXcI3F+Ng+f/0HT4v8n0 +cT03CcV5UysGeC6a/65s0KYPWnD+eCNeJHQy3WkKHVf9U849QvSZwPzbWNpCBVN8 +na1CGYESkXM1XG+3kTSbuLbD/Ia8KvGsaOeVORvhXr04kD9qW2ioaisSAcXELHY7 +qFcktM1cYnDJn1/LcCH6tUlnJdGIKWYlbBcmJvhT2FqpULg5IPldNiu9ybh5yQY9 +HB0pnzg6Ldcb/aunyjdwXgcaPgdkOOpnqRYGq6yrmWk6WsnNMK/QFmgxadbfOU0i +xjSrSYVItugHwOrH2eH842jBP2wbe1UJCOrKNytzZ3mBcb0RJbbFYjV0QzdPeVTN +Y9ermQTt29tJVrd+Emzo8CK4+gMCgcEA4sXchskGNcoChkDpAqie0W2YLm2XDyPY +CoiA+OVLc5lDd995Vqe2kCIC8VMMGIHhxG3NIqxrfxpH5LvqDczphyH6dlWl/O2M +CrS/67NjCTm6935ADeR0qndYdMm5XyfYEjl5qESoq4oNq4Pg/0/P1Q/mhN8GQiKb +qYAIHE/28dw1tsF6Kl7oqALpBXLQ/iRuFqJmrSPgQ32c5bEQUBD3F7HZq8T7V+O2 +7/jH8A1A2XddnddIe6fTqboFsghcPAHrAoHBANkBLsdTugDUKDSNa2tUo9ONPU2X +gRg+6PDa2ZEzcL961w2laLoKwsrlb8J9GL5Q1LxHx4PGhmwDwvscPzyzXQA7ubnh +vPQv1E2SmOSFxkmtWMfz6kcAw/wIlavAFdZPJK0ksnIWzTfi9Y92jdkar9Ny2gSj +BoF8XgPbMeuvMV008gjXOETaCk986+gOh4LEyZ2iLYruJsRIH7n/iSDKLsXE4yQd +ZuW68IQlJ/2a65DKDCLNgdVFVRfXWhvG++H0OwKBwQCXLpMEhgQj3AGu1fCscGng +87rJnmS0wpAHBatQmNz3u4JP6lDkb88KwVdLjLK7AUEtnojByEeqEYVDJ/FeiJuv +a/xO48P987KxzdVHzOyw0SdPqYAJQvhxpOWjMSY/b+Vhe6ZwLcXHsV5yV+tU39/j +X+8DP1mBbGfGVVq9iqShPXkkgPwcP0XFV0YDoeCpbZ65wZnIwpWCU73udgrgC09l +ITvH2KeP7SSf+y/1Xis7pOkT5Nr9Go0b0VkhWugoAUcCgcEAkKt0hOJ8AI1wIwjy +R43CjQjTiQ+rZX9F9ec7tiJLKlHks8ObJrHXMe5Kgai7KYs4fYUvrS8ESAKB/L1/ +fczoqtJ70UEoosqNiQxl7a6EMR47L/fxhKstUrBjx9Vj5DTDHhh29rneJUH5Ck8J +O2cf4kyRWGyvAP2UApIhR8og6M32sI962JFcNP3ymrRaVy3bvmweXJ7Egtq/0VUG +FdwfLoNCGBOZ7nygWBjFU7ydCzFdbIkBONjjZTo8EoSn6/gnAoHBAJ/XSbhoVzkI +CgW7gXSp+qKMhtbR2QawL3006KfQbK/sdcJ0Cyd4IfHXswrFQKV4BrL4tOxay1PT +HoQZW5+pLTbZjz3d0tDU9WpSd6FNovoxB6lUA3ymD4ay8Zysy3FflNqOSO6XkwKq +0GApQ6pIiDTst+LpnfgvQBDAnJXK3Hik2wDgXThXEofUoMDcGNsQ+NbdackR7/yL +8ep5ZLAhczGi4XE471ut48CHtxKq0eGde/lHx0Origk9PPbsNoH2XA== +-----END RSA PRIVATE KEY----- diff --git a/vault/start.sh b/vault/start.sh new file mode 100644 index 0000000..3c7d1b7 --- /dev/null +++ b/vault/start.sh @@ -0,0 +1,17 @@ +#!/bin/bash +set -e +if [ ! -f /opt/vault/tls/tls.ok ]; then + # Generate the TLS certificates + cd /opt/vault/tls + cp ../cacert.pem ../cakey.pem ../vault-csr.conf . + openssl req -new -newkey rsa:4096 -keyout tls.key -out vault.csr \ + -config vault-csr.conf -extensions v3_req + openssl x509 -req -in vault.csr -days 365 -CA cacert.pem -CAkey cakey.pem -CAcreateserial \ + -out tls_single.crt -extensions v3_req -extfile vault-csr.conf + cat tls_single.crt cacert.pem >> tls.crt + echo ok > tls.ok +fi +cd /opt/vault + +# Start the vault server +exec vault server -config=/opt/vault/config.hcl -log-level=trace diff --git a/vault/vault-csr.conf b/vault/vault-csr.conf new file mode 100644 index 0000000..5882012 --- /dev/null +++ b/vault/vault-csr.conf @@ -0,0 +1,21 @@ +[req] +default_bits = 4096 +prompt = no +encrypt_key = no +default_md = sha256 +distinguished_name = kubelet_serving +req_extensions = v3_req +x509_extensions = v3_req +[ kubelet_serving ] +O = system:nodes +CN = system:node +[ v3_req ] +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment, dataEncipherment +extendedKeyUsage = serverAuth, clientAuth +subjectAltName = @alt_names +[alt_names] +IP.1 = 127.0.0.1 +DNS.1 = vault-1 +DNS.2 = vault-2 +DNS.3 = vault-3 diff --git a/vault/vault.manifest.toml b/vault/vault.manifest.toml new file mode 100644 index 0000000..84b6280 --- /dev/null +++ b/vault/vault.manifest.toml @@ -0,0 +1,69 @@ +libos.entrypoint = "/bin/bash" + +[loader] +entrypoint = "file:{{ gramine.libos }}" +argv = ["bash", "/opt/vault/start.sh"] +# set a log level for gramine +log_level = "{{ log_level }}" + +[loader.env] +LD_LIBRARY_PATH = "/lib:{{ arch_libdir }}:/usr{{ arch_libdir }}" +PATH = "{{ execdir }}" + +VAULT_CLUSTER_ADDR.passthrough = true +VAULT_API_ADDR.passthrough = true +VAULT_RAFT_NODE_ID.passthrough = true + +# otherwise vault will lock a lot of unused EPC memory +VAULT_RAFT_INITIAL_MMAP_SIZE = "0" + +# possible tweak option, if problems with raft +# VAULT_RAFT_DISABLE_MAP_POPULATE = "true" + +[fs] +root.uri = "file:/" +start_dir = "/root" +mounts = [ + { path = "{{ execdir }}", uri = "file:{{ execdir }}" }, + { path = "/lib", uri = "file:{{ gramine.runtimedir() }}" }, + { path = "{{ arch_libdir }}", uri = "file:{{ arch_libdir }}" }, + { type = "tmpfs", path = "/var/tmp" }, + { type = "tmpfs", path = "/tmp" }, + { type = "tmpfs", path = "/app/.dcap-qcnl" }, + { type = "tmpfs", path = "/app/.az-dcap-client" }, + { path = "/lib/libdcap_quoteprov.so", uri = "file:/lib/libdcap_quoteprov.so" }, + { type = "encrypted", path = "/opt/vault/.cache", uri = "file:/opt/vault/.cache", key_name = "_sgx_mrsigner" }, + { type = "encrypted", path = "/opt/vault/tls", uri = "file:/opt/vault/tls", key_name = "_sgx_mrsigner" }, + { type = "encrypted", path = "/opt/vault/data", uri = "file:/opt/vault/data", key_name = "_sgx_mrsigner" }, +] + +[sgx] +debug = false +edmm_enable = false +enclave_size = "8G" +max_threads = 64 +nonpie_binary = true +remote_attestation = "dcap" + +trusted_files = [ + "file:/bin/bash", + "file:{{ gramine.libos }}", + "file:{{ execdir }}/", + "file:{{ gramine.runtimedir() }}/", + "file:{{ arch_libdir }}/", + "file:/usr/{{ arch_libdir }}/", + "file:/usr/lib/ssl/openssl.cnf", + "file:/etc/ssl/", + "file:/lib/libdcap_quoteprov.so", + "file:/opt/vault/", +] + +#file_check_policy = "allow_all_but_log" + +[sys] +stack.size = "1M" +enable_extra_runtime_domain_names_conf = true +enable_sigterm_injection = true + +# vault needs flock +experimental__enable_flock = true