├── .cargo └── audit.toml ├── .circleci └── config.yml ├── .dockerignore ├── .github ├── CODEOWNERS ├── actions │ ├── build_export_docker │ │ └── action.yml │ ├── ci_script │ │ └── action.yml │ └── load_docker │ │ └── action.yml └── workflows │ ├── ci.yml │ ├── nightly-next.yml │ └── nightly.yml ├── .gitignore ├── .gitmodules ├── .travis.yml.disabled ├── CHANGELOG.md ├── CODE-OF-CONDUCT.md ├── CONTRIBUTORS.md ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── MAINTAINERS.toml ├── PARTNERS.md ├── README.md ├── SECURITY.md ├── build.rs ├── ci.sh ├── config.toml ├── deny.toml ├── doc └── images │ ├── parsec │ ├── ARM1007_PARSEC Logo_ST2_RGB_Stacked_Colour.png │ └── ParsecConceptDiagram.png │ └── partners │ ├── arm │ └── Arm_logo_blue_150LG.png │ ├── docker │ └── vertical-logo-monochromatic.png │ ├── linaro │ └── Logo_linaro.png │ ├── mirantis │ └── mirantis-logo-2color-rgb-transparent.png │ ├── nxp │ └── NXP_logo_RGB_web.jpg │ ├── rancher │ └── rancher-logo-stacked-color.png │ └── redhat │ └── Logo-RedHat-D-Color-RGB.png ├── e2e_tests ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── docker_image │ ├── _exec_wrapper │ ├── cross-compile-tss.sh │ ├── generate-keys.sh │ ├── import-old-e2e-tests.sh │ ├── parsec-service-test-all.Dockerfile │ └── parsec-service-test-cross-compile.Dockerfile ├── fake_mappings │ └── cGFyc2VjLXRvb2w= │ │ ├── 1 │ │ └── dG90bw== │ │ └── 2 │ │ └── dG90bw== ├── provider_cfg │ ├── all │ │ ├── config.toml │ │ └── on-disk-kim-all-providers.toml │ ├── cryptoauthlib │ │ ├── cal_access_keys.toml │ │ ├── config-sqlite.toml │ │ ├── config.toml │ │ ├── config_508a.toml │ │ └── config_608a.toml │ ├── mbed-crypto │ │ ├── config-sqlite.toml │ │ └── config.toml │ ├── pkcs11 │ │ ├── config-sqlite.toml │ │ └── config.toml │ ├── tpm │ │ ├── config-sqlite.toml │ │ └── config.toml │ └── trusted-service │ │ ├── config-sqlite.toml │ │ └── config.toml ├── src │ ├── lib.rs │ ├── raw_request.rs │ └── stress.rs └── tests │ ├── all_providers │ ├── config │ │ ├── mod.rs │ │ └── tomls │ │ │ ├── allow_deprecated.toml │ │ │ ├── allow_export.toml │ │ │ ├── list_providers_1.toml │ │ │ ├── list_providers_2.toml │ │ │ ├── no_endorsement_auth.toml │ │ │ ├── no_serial_or_slot_number.toml │ │ │ ├── no_tpm_support.toml │ │ │ ├── no_user_pin.toml │ │ │ ├── pkcs11_pin_hex_fmt.toml │ │ │ ├── pkcs11_pin_str_fmt_with_hex_word.toml │ │ │ ├── pkcs11_software.toml │ │ │ ├── reject_deprecated.toml │ │ │ ├── serial_number_only.toml │ │ │ ├── serial_number_padding.toml │ │ │ ├── slot_number_only.toml │ │ │ ├── slot_numbers_mismatch.toml │ │ │ ├── ts_pkcs11_cross.toml │ │ │ └── various_field_check.toml │ ├── cross.rs │ ├── logging.rs │ ├── mod.rs │ ├── multitenancy.rs │ └── normal.rs │ ├── mod.rs │ └── per_provider │ ├── key_mappings.rs │ ├── mod.rs │ ├── normal_tests │ ├── aead.rs │ ├── asym_encryption.rs │ ├── asym_sign_verify.rs │ ├── auth.rs │ ├── basic.rs │ ├── capability_discovery.rs │ ├── cipher.rs │ ├── create_destroy_key.rs │ ├── export_key.rs │ ├── export_public_key.rs │ ├── generate_random.rs │ ├── hash.rs │ ├── import_key.rs │ ├── key_agreement.rs │ ├── key_attestation.rs │ ├── key_attributes.rs │ ├── mod.rs │ └── ping.rs │ ├── stress_test.rs │ └── tpm_reset.rs ├── fuzz.sh ├── fuzz ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── build.rs ├── cleanup.sh ├── config.toml ├── fuzz_targets │ └── fuzz_service.rs └── run_fuzz.sh ├── quickstart ├── config.toml ├── construct-build-details.sh ├── docker_README.md ├── package.sh ├── quickstart.Dockerfile └── tarball_README.md ├── src ├── authenticators │ ├── direct_authenticator │ │ └── mod.rs │ ├── jwt_svid_authenticator │ │ └── mod.rs │ ├── mod.rs │ └── unix_peer_credentials_authenticator │ │ └── mod.rs ├── back │ ├── backend_handler.rs │ ├── dispatcher.rs │ └── mod.rs ├── bin │ └── main.rs ├── front │ ├── domain_socket.rs │ ├── front_end.rs │ ├── listener.rs │ └── mod.rs ├── key_info_managers │ ├── mod.rs │ ├── on_disk_manager │ │ └── mod.rs │ └── sqlite_manager │ │ └── mod.rs ├── lib.rs ├── providers │ ├── core │ │ └── mod.rs │ ├── crypto_capability.rs │ ├── cryptoauthlib │ │ ├── access_keys.rs │ │ ├── aead.rs │ │ ├── asym_sign.rs │ │ ├── cipher.rs │ │ ├── generate_random.rs │ │ ├── hash.rs │ │ ├── key_agreement.rs │ │ ├── key_management.rs │ │ ├── key_slot.rs │ │ ├── key_slot_storage.rs │ │ └── mod.rs │ ├── mbed_crypto │ │ ├── aead.rs │ │ ├── asym_encryption.rs │ │ ├── asym_sign.rs │ │ ├── capability_discovery.rs │ │ ├── generate_random.rs │ │ ├── hash.rs │ │ ├── key_agreement.rs │ │ ├── key_management.rs │ │ └── mod.rs │ ├── mod.rs │ ├── pkcs11 │ │ ├── asym_encryption.rs │ │ ├── asym_sign.rs │ │ ├── capability_discovery.rs │ │ ├── generate_random.rs │ │ ├── key_management.rs │ │ ├── key_metadata.rs │ │ ├── mod.rs │ │ └── utils.rs │ ├── tpm │ │ ├── asym_encryption.rs │ │ ├── asym_sign.rs │ │ ├── capability_discovery.rs │ │ ├── generate_random.rs │ │ ├── key_attestation.rs │ │ ├── key_management.rs │ │ ├── mod.rs │ │ └── utils.rs │ └── trusted_service │ │ ├── asym_encryption.rs │ │ ├── asym_sign.rs │ │ ├── capability_discovery.rs │ │ ├── context │ │ ├── asym_encryption.rs │ │ ├── asym_sign.rs │ │ ├── error.rs │ │ ├── generate_random.rs │ │ ├── key_management.rs │ │ ├── mod.rs │ │ └── ts_protobuf.rs │ │ ├── error.rs │ │ ├── generate_random.rs │ │ ├── key_management.rs │ │ └── mod.rs └── utils │ ├── cli.rs │ ├── config.rs │ ├── global_config.rs │ ├── mod.rs │ ├── service_builder.rs │ └── tests │ ├── config │ ├── providers_different_type.toml │ ├── providers_different_type_same_name.toml │ ├── providers_same_type_default_name.toml │ ├── providers_same_type_different_name.toml │ └── providers_same_type_same_name.toml │ └── mod.rs ├── systemd-daemon └── parsec.service ├── test ├── cross-compile.sh └── pkg-config └── utils ├── dependency_cross_matcher.py └── release_tracking.py /.cargo/audit.toml: -------------------------------------------------------------------------------- 1 | [advisories] 2 | informational_warnings = ["unmaintained"] # warn for categories of informational advisories 3 | severity_threshold = "low" # CVSS severity ("none", "low", "medium", "high", "critical") 4 | 5 | # Advisory Database Configuration 6 | [database] 7 | path = "/tmp/advisory-db" # Path where advisory git repo will be cloned 8 | url = "https://github.com/RustSec/advisory-db.git" # URL to git repo 9 | fetch = true # Perform a `git fetch` before auditing 10 | stale = false # Allow stale advisory DB (i.e. no commits for 90 days) 11 | 12 | # Output Configuration 13 | [output] 14 | deny = ["unmaintained"] # exit on error if unmaintained dependencies are found 15 | format = "terminal" # "terminal" (human readable report) or "json" 16 | quiet = false # Only print information on error 17 | show_tree = true # Show inverse dependency trees along with advisories 18 | 19 | # Target Configuration 20 | [target] 21 | os = "linux" # Ignore advisories for operating systems other than this one 22 | 23 | [yanked] 24 | enabled = true # Warn for yanked crates in Cargo.lock 25 | update_index = true # Auto-update the crates.io index 26 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | jobs: 3 | build: 4 | working_directory: ~/repo 5 | docker: 6 | - image: ghcr.io/parallaxsecond/parsec-service-test-all 7 | resource_class: arm.medium 8 | steps: 9 | - checkout 10 | - run: | 11 | git submodule update --init --recursive 12 | cargo build --features=all-providers,all-authenticators 13 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | quickstart/quickstart.Dockerfile 2 | quickstart/package.sh 3 | quickstart/*.tar.gz 4 | .idea/ 5 | 6 | # Copied from .gitignore 7 | /target 8 | *.psa_its 9 | *.swp 10 | tags 11 | *DS_Store 12 | *vscode 13 | *.patch 14 | mappings/ 15 | kim-mappings/ 16 | NVChip 17 | .devcontainer 18 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # The content of the config.rs file should not change in a breaking way. 2 | # See https://github.com/parallaxsecond/parsec/issues/393 for details. 3 | src/utils/config.rs @parallaxsecond/admin 4 | # The content of the cli.rs file should not change in a breaking way. 5 | # See https://github.com/parallaxsecond/parsec/issues/392 for details. 6 | src/utils/cli.rs @parallaxsecond/admin 7 | # The Docker container is also used to check that there are no breaking 8 | # changes in buildtime dependencies. 9 | # See https://github.com/parallaxsecond/parsec/issues/397 10 | # See https://github.com/parallaxsecond/parsec/issues/408 11 | e2e_tests/docker_image/ @parallaxsecond/admin 12 | # The way tests are executed should be only modified carefully to not remove 13 | # regression or breaking changes detection. 14 | ci.sh @parallaxsecond/admin 15 | # The main function file contains interactions with the operating system which must 16 | # stay stable. 17 | src/bin/main.rs @parallaxsecond/admin 18 | -------------------------------------------------------------------------------- /.github/actions/build_export_docker/action.yml: -------------------------------------------------------------------------------- 1 | name: "Build and export docker image" 2 | description: "Builds and exports the docker images required by Parsec CI" 3 | inputs: 4 | image-name: 5 | required: true 6 | description: "Docker image name" 7 | 8 | runs: 9 | using: "composite" 10 | steps: 11 | - name: Build the docker container 12 | run: pushd e2e_tests/docker_image && docker build -t ${{ inputs.image-name }} -f ${{ inputs.image-name }}.Dockerfile . && popd 13 | shell: bash 14 | - name: Export the docker container 15 | run: docker save ${{ inputs.image-name }} > /tmp/${{ inputs.image-name }}.tar 16 | shell: bash 17 | - name: Upload artifact 18 | uses: actions/upload-artifact@v3 19 | with: 20 | name: ${{ inputs.image-name }} 21 | path: /tmp/${{ inputs.image-name }}.tar 22 | -------------------------------------------------------------------------------- /.github/actions/ci_script/action.yml: -------------------------------------------------------------------------------- 1 | name: "Run CI Tests" 2 | description: "Run the ci.sh script with the specified flags" 3 | inputs: 4 | ci-flags: 5 | required: true 6 | description: "Flags with which to run the ci.sh tests" 7 | rs-version: 8 | required: true 9 | default: "stable" 10 | description: "Rust version with which to run the tests" 11 | 12 | runs: 13 | using: "composite" 14 | steps: 15 | - name: Load Docker 16 | uses: ./.github/actions/load_docker 17 | if: ${{ env.TEST_ALL_DOCKER_IMAGE == 'parsec-service-test-all' }} 18 | with: 19 | image-name: "${{ env.TEST_ALL_DOCKER_IMAGE }}" 20 | image-path: "/tmp" 21 | - name: Run the container to execute the test script 22 | run: docker run -v $(pwd):/tmp/parsec -w /tmp/parsec --env RUST_TOOLCHAIN_VERSION=${{ inputs.rs-version }} -t ${{ env.TEST_ALL_DOCKER_IMAGE }} /tmp/parsec/ci.sh ${{ inputs.ci-flags }} 23 | shell: bash 24 | -------------------------------------------------------------------------------- /.github/actions/load_docker/action.yml: -------------------------------------------------------------------------------- 1 | name: "Load docker image" 2 | description: "Load docker image" 3 | inputs: 4 | image-name: 5 | required: true 6 | description: "Docker image name" 7 | image-path: 8 | required: true 9 | description: "Path to save the docker image" 10 | 11 | runs: 12 | using: "composite" 13 | steps: 14 | - uses: actions/checkout@v3 15 | - name: Download artifact 16 | uses: actions/download-artifact@v3 17 | with: 18 | name: ${{ inputs.image-name }} 19 | path: ${{ inputs.image-path }} 20 | - name: Load image 21 | run: docker load --input ${{ inputs.image-path }}/${{ inputs.image-name }}.tar 22 | shell: bash 23 | -------------------------------------------------------------------------------- /.github/workflows/nightly-next.yml: -------------------------------------------------------------------------------- 1 | name: Nightly Next Branch Checks 2 | 3 | on: 4 | schedule: 5 | # Every night at midnight 6 | - cron: "0 0 * * *" 7 | workflow_dispatch: 8 | inputs: 9 | rev: 10 | description: "Revision hash to run against" 11 | required: false 12 | default: "" 13 | 14 | 15 | env: 16 | TEST_ALL_DOCKER_IMAGE: 'ghcr.io/parallaxsecond/parsec-service-test-all' 17 | 18 | jobs: 19 | all-providers: 20 | name: Various tests targeting a Parsec image with all providers included 21 | runs-on: ubuntu-latest 22 | steps: 23 | - uses: actions/checkout@v3 24 | with: 25 | ref: "${{ github.event.inputs.rev }}" 26 | - name: Run the container to execute the test script 27 | uses: ./.github/actions/ci_script 28 | with: 29 | ci-flags: "all --test-next-branch-tracking" 30 | 31 | build-all-providers: 32 | name: Cargo check all-providers (current Rust stable & old compiler) 33 | runs-on: ubuntu-latest 34 | steps: 35 | - uses: actions/checkout@v3 36 | with: 37 | ref: "${{ github.event.inputs.rev }}" 38 | - name: Run the container to execute the test script 39 | uses: ./.github/actions/ci_script 40 | with: 41 | ci-flags: "cargo-check --test-next-branch-tracking" 42 | 43 | mbed-crypto-provider: 44 | name: Integration tests using Mbed Crypto provider 45 | runs-on: ubuntu-latest 46 | steps: 47 | - uses: actions/checkout@v3 48 | with: 49 | ref: "${{ github.event.inputs.rev }}" 50 | - name: Run the container to execute the test script 51 | uses: ./.github/actions/ci_script 52 | with: 53 | ci-flags: "mbed-crypto --test-next-branch-tracking" 54 | 55 | pkcs11-provider: 56 | name: Integration tests using PKCS 11 provider 57 | runs-on: ubuntu-latest 58 | steps: 59 | - uses: actions/checkout@v3 60 | with: 61 | ref: "${{ github.event.inputs.rev }}" 62 | - name: Run the container to execute the test script 63 | uses: ./.github/actions/ci_script 64 | with: 65 | ci-flags: "pkcs11 --no-stress-test --test-next-branch-tracking" 66 | 67 | tpm-provider: 68 | name: Integration tests using TPM provider 69 | runs-on: ubuntu-latest 70 | steps: 71 | - uses: actions/checkout@v3 72 | with: 73 | ref: "${{ github.event.inputs.rev }}" 74 | - name: Run the container to execute the test script 75 | uses: ./.github/actions/ci_script 76 | with: 77 | ci-flags: "tpm --test-next-branch-tracking" 78 | 79 | trusted-service-provider: 80 | name: Integration tests using Crypto Trusted Service provider 81 | runs-on: ubuntu-latest 82 | steps: 83 | - uses: actions/checkout@v3 84 | with: 85 | ref: "${{ github.event.inputs.rev }}" 86 | - name: Run the container to execute the test script 87 | uses: ./.github/actions/ci_script 88 | with: 89 | ci-flags: "trusted-service --test-next-branch-tracking" 90 | -------------------------------------------------------------------------------- /.github/workflows/nightly.yml: -------------------------------------------------------------------------------- 1 | name: Nightly Checks 2 | 3 | on: 4 | schedule: 5 | # Every night at midnight 6 | - cron: "0 0 * * *" 7 | workflow_dispatch: 8 | inputs: 9 | rev: 10 | description: "Revision hash to run against" 11 | required: false 12 | default: "" 13 | 14 | jobs: 15 | dependencies: 16 | name: Check for unused dependencies 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v2 20 | with: 21 | ref: "${{ github.event.inputs.rev }}" 22 | - name: Install latest Rust 23 | uses: actions-rs/toolchain@v1 24 | with: 25 | toolchain: nightly 26 | - name: Install cargo udeps 27 | run: cargo install cargo-udeps --locked 28 | - name: Execute cargo udeps 29 | run: cargo +nightly udeps 30 | 31 | audit: 32 | name: Check for crates with security vulnerabilities 33 | runs-on: ubuntu-latest 34 | steps: 35 | - uses: actions/checkout@v2 36 | with: 37 | ref: "${{ github.event.inputs.rev }}" 38 | - name: Install latest Rust 39 | uses: actions-rs/toolchain@v1 40 | with: 41 | toolchain: nightly 42 | - name: Install cargo audit 43 | run: cargo install cargo-audit 44 | - name: Execute cargo audit 45 | # shlex is currently only being brought by bindgen, which does not use the concerning APIs 46 | # except for testing. 47 | # TODO: remove when shlex gets updated to >=1.3.0 (here and in deny.toml) 48 | run: cargo audit --ignore RUSTSEC-2024-0006 49 | 50 | coverage: 51 | name: Gather coverage data and upload to Codecov 52 | runs-on: ubuntu-latest 53 | steps: 54 | - uses: actions/checkout@v2 55 | with: 56 | ref: "${{ github.event.inputs.rev }}" 57 | - name: Run the container to execute the coverage script 58 | run: docker run -v $(pwd):/tmp/parsec -w /tmp/parsec --security-opt seccomp=unconfined --env RUST_TOOLCHAIN_VERSION=1.67.0 ghcr.io/parallaxsecond/parsec-service-test-all /tmp/parsec/ci.sh coverage 59 | - name: Collect coverage results 60 | run: bash <(curl -s https://codecov.io/bash) 61 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Cargo build directory 2 | /target 3 | 4 | # Mbed Crypto key files 5 | *.psa_its 6 | 7 | # Editor swap files 8 | *.swp 9 | 10 | 11 | tags 12 | 13 | # MacOS folder attributes file 14 | *DS_Store 15 | 16 | # VS Code config folder 17 | *vscode 18 | 19 | # Git patch files 20 | *.patch 21 | 22 | # Parsec key info mappings directories 23 | mappings/ 24 | kim-mappings/ 25 | 26 | # TPM simulator state file 27 | NVChip 28 | .devcontainer 29 | 30 | # Quickstart tarball 31 | quickstart/*.tar.gz 32 | 33 | # IDE settings files 34 | .idea 35 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "trusted-services-vendor"] 2 | path = trusted-services-vendor 3 | url = https://git.trustedfirmware.org/TS/trusted-services.git 4 | branch = integration 5 | -------------------------------------------------------------------------------- /.travis.yml.disabled: -------------------------------------------------------------------------------- 1 | # Executing our tests on Arm64 with Travis CI 2 | # The TPM provider Dockerfile does not build on Arm so the all-providers and tpm-provider tests 3 | # are not executed on Aarch64. 4 | if: type = cron 5 | arch: arm64 6 | services: 7 | - docker 8 | jobs: 9 | include: 10 | - name: "Integration tests using Mbed Crypto provider" 11 | env: DOCKER_IMAGE_NAME=mbed-crypto-provider DOCKER_IMAGE_PATH=e2e_tests/provider_cfg/mbed-crypto SCRIPT="ci.sh mbed-crypto" 12 | - name: "Integration tests using PKCS 11 provider" 13 | env: DOCKER_IMAGE_NAME=pkcs11-provider DOCKER_IMAGE_PATH=e2e_tests/provider_cfg/pkcs11 SCRIPT="ci.sh pkcs11" 14 | # Re-enabling these for now, we'll need to fix the issues, otherwise the build is just useless 15 | # PKCS11 tests are failing because of unidentified issues. 16 | # See https://github.com/parallaxsecond/parsec/issues/116 17 | # allow_failures: 18 | # - env: DOCKER_IMAGE_NAME=mbed-crypto-provider DOCKER_IMAGE_PATH=e2e_tests/provider_cfg/mbed-crypto SCRIPT="ci.sh mbed-crypto" 19 | # - env: DOCKER_IMAGE_NAME=pkcs11-provider DOCKER_IMAGE_PATH=e2e_tests/provider_cfg/pkcs11 SCRIPT="ci.sh pkcs11" 20 | script: 21 | - docker build -t $DOCKER_IMAGE_NAME $DOCKER_IMAGE_PATH 22 | - docker run -v $(pwd):/tmp/parsec -w /tmp/parsec $DOCKER_IMAGE_NAME /tmp/parsec/$SCRIPT 23 | -------------------------------------------------------------------------------- /CODE-OF-CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Parsec Code of Conduct 2 | 3 | Parsec follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md). 4 | -------------------------------------------------------------------------------- /CONTRIBUTORS.md: -------------------------------------------------------------------------------- 1 | # Contributors to the Parsec project 2 | This file aims to acknowledge the specific contributors referred to in the "Contributors to the Parsec project" copyright notice. 3 | 4 | ## Organizations 5 | * Arm Ltd. 6 | * Docker Inc. 7 | * Mirantis Inc. 8 | 9 | ## Individuals 10 | * Anton Antonov (@anta5010) 11 | * Paul Howard (@paulhowardarm) 12 | * Ionut Mihalcea (@ionut-arm) 13 | * Hugues de Valon (@hug-dev) 14 | * Jesper Brynolf (@Superhepper) 15 | * Samuel Bailey (@sbailey-arm) 16 | * Patrick Uiterwijk (@puiterwijk) 17 | * Nicolas Stalder (@nickray) 18 | * Edmund Grimley Evans (@egrimley-arm) 19 | * Matt Davis (@MattDavis00) 20 | * Mohamed Omar Asaker (@mohamedasaker-arm) 21 | * Gowtham Suresh Kumar (@gowthamsk-arm) 22 | * William Brown (@firstyear) 23 | * Tomas Agustin Gonzalez Orlando (@tgonzalezorlandoarm) 24 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "parsec-service" 3 | version = "1.4.1" 4 | authors = ["Parsec Project Contributors"] 5 | description = "A language-agnostic API to secure services in a platform-agnostic way" 6 | license = "Apache-2.0" 7 | repository = "https://github.com/parallaxsecond/parsec" 8 | readme = "README.md" 9 | keywords = ["security", "service"] 10 | categories = ["cryptography", "hardware-support"] 11 | edition = "2018" 12 | rust-version = "1.67.0" 13 | 14 | [[bin]] 15 | name = "parsec" 16 | path = "src/bin/main.rs" 17 | 18 | [dependencies] 19 | parsec-interface = "0.29.1" 20 | rand = { version = "0.8.3", features = ["small_rng"], optional = true } 21 | base64 = "0.21.0" 22 | threadpool = "1.8.1" 23 | signal-hook = "0.3.4" 24 | sd-notify = "0.4.1" 25 | toml = "0.8.0" 26 | serde = { version = "1.0.123", features = ["derive"] } 27 | env_logger = "0.10.0" 28 | log = { version = "0.4.14", features = ["serde"] } 29 | cryptoki = { version = "0.6.0", optional = true, default-features = false } 30 | picky-asn1-der = { version = "0.4.0", optional = true } 31 | picky-asn1 = { version = "0.8.0", optional = true } 32 | tss-esapi = { version = "7.5.0", optional = true } 33 | bincode = "1.3.1" 34 | # TODO: Fixed until the MSRV is bumped! 35 | clap = { version = "=4.3.24", features = ["derive", "std"] } 36 | derivative = "2.2.0" 37 | hex = { version = "0.4.2", optional = true } 38 | psa-crypto = { version = "0.12.0", default-features = false, features = ["operations","std"], optional = true } 39 | zeroize = { version = "1.2.0", features = ["zeroize_derive"] } 40 | picky-asn1-x509 = { version = "0.12.0", optional = true } 41 | libc = "0.2.86" 42 | anyhow = "1.0.38" 43 | rust-cryptoauthlib = { version = "0.4.5", optional = true } 44 | spiffe = { version = "0.2.1", optional = true } 45 | prost = { version = "0.9.0", optional = true } 46 | rusqlite = { version = "0.29.0", features = ["bundled"] } 47 | num-traits = "0.2.14" 48 | 49 | [dev-dependencies] 50 | rand = { version = "0.8.3", features = ["small_rng"] } 51 | rust-cryptoauthlib = { version = "0.4.4", features=["software-backend"]} 52 | 53 | 54 | [build-dependencies] 55 | bindgen = { version = "0.66.1", optional = true } 56 | prost-build = { version = "0.9.0", optional = true } 57 | 58 | [package.metadata.docs.rs] 59 | features = ["pkcs11-provider", "tpm-provider", "mbed-crypto-provider", "cryptoauthlib-provider", "direct-authenticator"] 60 | 61 | # The features should not be modified in a breaking way. 62 | # See https://github.com/parallaxsecond/parsec/issues/408 for details. 63 | [features] 64 | default = ["unix-peer-credentials-authenticator"] 65 | 66 | # Providers 67 | mbed-crypto-provider = ["psa-crypto"] 68 | pkcs11-provider = ["cryptoki", "picky-asn1-der", "picky-asn1", "picky-asn1-x509", "psa-crypto", "rand", "hex"] 69 | tpm-provider = ["tss-esapi", "picky-asn1-der", "picky-asn1", "picky-asn1-x509", "hex"] 70 | cryptoauthlib-provider = ["rust-cryptoauthlib"] 71 | trusted-service-provider = ["psa-crypto", "bindgen", "prost-build", "prost"] 72 | all-providers = ["tpm-provider", "pkcs11-provider", "mbed-crypto-provider", "trusted-service-provider"] 73 | 74 | # Authenticators 75 | direct-authenticator = [] 76 | unix-peer-credentials-authenticator = [] 77 | jwt-svid-authenticator = ["spiffe"] 78 | all-authenticators = ["direct-authenticator", "unix-peer-credentials-authenticator", "jwt-svid-authenticator"] 79 | -------------------------------------------------------------------------------- /MAINTAINERS.toml: -------------------------------------------------------------------------------- 1 | # Parsec maintainers file 2 | # 3 | # This file lists the maintainers of the parallaxsecond/parsec project. 4 | # 5 | # Its structure is inspired from the maintainers files in the Docker Github 6 | # repositories. Please see the MAINTAINERS file in docker/opensource for more 7 | # information. 8 | 9 | [maintainers] 10 | 11 | # Core maintainers of the project. 12 | 13 | [maintainers.core] 14 | people = [ 15 | "adamparco", 16 | "heavypackets", 17 | "hug-dev", 18 | "ionut-arm", 19 | "justincormack", 20 | "paulhowardarm", 21 | "anta5010", 22 | "gowthamsk-arm", 23 | "mohamedasaker-arm", 24 | "tgonzalezorlandoarm", 25 | ] 26 | 27 | [people] 28 | 29 | # A reference list of all people associated with the project. 30 | 31 | [people.adamparco] 32 | Name = "Adam Parco" 33 | Email = "aparco@mirantis.com" 34 | GitHub = "adamparco" 35 | 36 | [people.heavypackets] 37 | Name = "Sabree Blackmon" 38 | Email = "sabree.blackmon@docker.com" 39 | GitHub = "heavypackets" 40 | 41 | [people.hug-dev] 42 | Name = "Hugues de Valon" 43 | Email = "hugues.de-valon@einride.tech" 44 | GitHub = "hug-dev" 45 | 46 | [people.ionut-arm] 47 | Name = "Ionut Mihalcea" 48 | Email = "ionut.mihalcea@arm.com" 49 | GitHub = "ionut-arm" 50 | 51 | [people.justincormack] 52 | Name = "Justin Cormack" 53 | Email = "justin.cormack@docker.com" 54 | GitHub = "justincormack" 55 | 56 | [people.paulhowardarm] 57 | Name = "Paul Howard" 58 | Email = "paul.howard@arm.com" 59 | GitHub = "paulhowardarm" 60 | 61 | [people.anta5010] 62 | Name = "Anton Antonov" 63 | Email = "anton.antonov@arm.com" 64 | GitHub = "anta5010" 65 | 66 | [people.gowthamsk-arm] 67 | Name = "Gowtham Suresh Kumar" 68 | Email = "gowtham.sureshkumar@arm.com" 69 | GitHub = "gowthamsk-arm" 70 | 71 | [people.mohamedasaker-arm] 72 | Name = "Mohamed Omar Asaker" 73 | Email = "mohamed.omarasaker@arm.com" 74 | GitHub = "mohamedasaker-arm" 75 | 76 | [people.tgonzalezorlandoarm] 77 | Name = "Tomás Agustín González Orlando" 78 | Email = "tomasagustin.gonzalezorlando@arm.com" 79 | GitHub = "tgonzalezorlandoarm" 80 | -------------------------------------------------------------------------------- /PARTNERS.md: -------------------------------------------------------------------------------- 1 | 5 | 6 | # **Contributing Organizations** 7 | 8 |

9 | arm.com                10 | docker.com               11 | mirantis.com               12 | linaro.org               13 |

14 | 15 | 16 | **Note**: Arm is contributing to Parsec as part of [Project Cassini](https://www.arm.com/-/media/global/solutions/artificial-intelligence/Project_Cassini.pdf). 17 | 18 | # **Adopters and Industry Partners** 19 | 20 |

21 | rancher.com                22 | redhat.com                23 | nxp.com                24 |

25 | 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 5 | 6 |

7 | Parsec logo 8 |

9 | Crates.io 10 | Code documentation 11 | 12 | 13 |

14 | 15 | # Welcome To PARSEC 16 | 17 | **PARSEC** is the **P**latform **A**bst**R**action for **SEC**urity, an open-source initiative 18 | to provide a common API to hardware security and cryptographic services in a platform-agnostic way. This abstraction layer keeps workloads decoupled from physical platform details, enabling cloud-native delivery flows within the data center and at the edge. 19 | 20 |

21 | Parsec Concept Diagram 22 |

23 | 24 | Read the Parsec documentation [**online**](https://parallaxsecond.github.io/parsec-book/). 25 | 26 | Read the whitepaper [**Security for the Infrastructure Edge**](https://www.arm.com/-/media/global/people/Security-For-The-Infrastructure-Edge-White-paper-NDA). 27 | 28 | 29 | # Why PARSEC? 30 | 31 | Use Parsec when you need: 32 | 33 | - A **portable interface to your platform's Root of Trust** in order to manage keys and perform cryptographic operations without knowledge of the hardware. 34 | - A simple and portable way to access the **best available security** of your platform in your **preferred programming language**. 35 | 36 | # What PARSEC Provides 37 | 38 | The value proposition of Parsec is that it provides the following: 39 | 40 | - **Abstraction** – a common API that is truly agnostic and based on modern cryptographic principles 41 | - **Mediation** – security as a microservice, brokering access to the hardware and providing isolated key stores in a multi-tenant environment 42 | - **Ergonomics** – a client library ecosystem that brings the API to the fingertips of developers in any programming language: “easy to consume, hard to get wrong” 43 | - **Openness** – an open-source project inviting contributions to enhance the ecosystem both within the service and among its client libraries 44 | 45 | # Maintainers 46 | 47 | PARSEC is a collaborative project. The current list of the individuals and organizations who maintain this project can be found [**here**](./MAINTAINERS.toml). 48 | 49 | # Partner Organizations 50 | 51 | See who is [**using and contributing to PARSEC**](./PARTNERS.md). 52 | 53 | # Getting Started 54 | 55 | If you are running on x86 Linux, check out [this guide](https://parallaxsecond.github.io/parsec-book/getting_started/linux_x86.html) to get started with Parsec quickly! 56 | 57 | For examples of how to access PARSEC as a client application, check [this Rust client documentation](https://docs.rs/parsec-client/*/parsec_client/core/basic_client/struct.BasicClient.html). 58 | 59 | Check the [**user**](https://parallaxsecond.github.io/parsec-book/parsec_users.html), [**client developer**](https://parallaxsecond.github.io/parsec-book/parsec_client/index.html) and [**service developer**](https://parallaxsecond.github.io/parsec-book/parsec_service/index.html) guides for more information on building, installing, testing and using Parsec! 60 | 61 | # Community 62 | 63 | Come and ask questions or talk with the Parsec Community in our Slack channel or biweekly meetings. 64 | See the [Community](https://github.com/parallaxsecond/community) repository for more information on how to join. 65 | 66 | # Contributing 67 | 68 | We would be happy for you to contribute to Parsec! 69 | Please check the [**Contribution Guidelines**](https://parallaxsecond.github.io/parsec-book/contributing/index.html) 70 | to know more about the contribution process. 71 | Check the [**open issues**](https://github.com/orgs/parallaxsecond/projects/1) on the board if you 72 | need any ideas 🙂! 73 | 74 | # Security Vulnerability Reporting 75 | 76 | Check [**PARSEC's security policy**](./SECURITY.md). 77 | 78 | # License 79 | 80 | The software is provided under Apache-2.0. Contributions to this project are accepted under the same license. 81 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security policy 2 | 3 | Security is of paramount importance to the Parsec project. We do all we can to identify and fix 4 | issues, however some problems might slip through the cracks. Any efforts towards responsible 5 | disclosure of security problems are greatly appreciated and your contributions will be acknowledged. 6 | 7 | ## Supported versions 8 | 9 | Currently only the most recent version of the Parsec service is eligible for patching. This could 10 | change in the future. 11 | 12 | | Version | Supported | 13 | |------------------|-----------| 14 | | 0.7.0 and higher | ✅ | 15 | | 0.6.0 and lower | ❌ | 16 | 17 | ## Our disclosure policy 18 | 19 | All security vulnerabilities affecting the Parsec service - including those reported using the steps 20 | highlighted below, those discovered during routine testing, and those found in our dependency tree 21 | either through `cargo-audit` or otherwise - will receive [security 22 | advisories](https://github.com/parallaxsecond/parsec/security/advisories) in a timely manner. The 23 | advisories should include sufficient information about the cause, effect, and possible mitigations 24 | for the vulnerability. If any information is missing, or you would like to raise a question about 25 | the advisories, please open an issue in [our repo](https://github.com/parallaxsecond/parsec). 26 | 27 | Efforts to mitigate for the reported vulnerabilities will be tracked using Github issues linked to 28 | the corresponding advisories. 29 | 30 | ## Reporting a vulnerability 31 | 32 | To report a vulnerability, please send an email to 33 | [cncf-parsec-maintainers@lists.cncf.io](mailto:cncf-parsec-maintainers@lists.cncf.io). We will reply 34 | to acknowledge your report and we'll strive to keep you in the loop as we try to reach a resolution. 35 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::multiple_crate_versions, unused)] 2 | use std::env; 3 | use std::fs::read_dir; 4 | use std::io::{Error, ErrorKind, Result}; 5 | use std::path::{Path, PathBuf}; 6 | 7 | #[cfg(feature = "trusted-service-provider")] 8 | fn generate_ts_bindings(ts_include_dir: String) -> Result<()> { 9 | let header = ts_include_dir.clone() + "/components/service/locator/interface/service_locator.h"; 10 | let encoding_header = ts_include_dir.clone() + "/protocols/rpc/common/packed-c/encoding.h"; 11 | 12 | if !Path::new(&header).exists() { 13 | return Err(Error::new( 14 | ErrorKind::Other, 15 | "Trusted Services Locator header is missing. Have you run 'git submodule update --init'?", 16 | )); 17 | } 18 | 19 | println!("cargo:rerun-if-changed={}", header); 20 | 21 | let bindings = bindgen::Builder::default() 22 | .clang_arg(format!("-I{}", ts_include_dir)) 23 | .clang_arg(format!( 24 | "-I{}", 25 | ts_include_dir + "/components/rpc/common/interface" 26 | )) 27 | .header(header) 28 | .header(encoding_header) 29 | .generate_comments(false) 30 | .size_t_is_usize(true) 31 | .derive_default(true) 32 | .generate() 33 | .map_err(|_| { 34 | Error::new( 35 | ErrorKind::Other, 36 | "Unable to generate bindings to trusted services locator", 37 | ) 38 | })?; 39 | let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); 40 | bindings.write_to_file(out_path.join("ts_bindings.rs"))?; 41 | 42 | println!("cargo:rustc-link-lib=dylib=ts"); 43 | Ok(()) 44 | } 45 | 46 | #[cfg(feature = "trusted-service-provider")] 47 | fn generate_proto_sources(contract_dir: String) -> Result<()> { 48 | let crypto_pb_dir = contract_dir.clone() + "/service/crypto/protobuf"; 49 | let dir_entries = read_dir(Path::new(&crypto_pb_dir))?; 50 | let files: Result> = dir_entries 51 | .map(|protos_file| { 52 | protos_file? 53 | .path() 54 | .into_os_string() 55 | .into_string() 56 | .map_err(|_| { 57 | Error::new( 58 | ErrorKind::InvalidData, 59 | "conversion from OsString to String failed", 60 | ) 61 | }) 62 | }) 63 | // Fail the entire operation if there was an error. 64 | .collect(); 65 | let proto_files: Vec = files? 66 | .into_iter() 67 | .filter(|string| string.ends_with(".proto")) 68 | .collect(); 69 | let files_slices: Vec<&str> = proto_files.iter().map(|file| &file[..]).collect(); 70 | 71 | prost_build::compile_protos(&files_slices, &[&contract_dir]) 72 | } 73 | 74 | #[cfg(feature = "trusted-service-provider")] 75 | fn main() -> Result<()> { 76 | { 77 | generate_ts_bindings(String::from("trusted-services-vendor"))?; 78 | generate_proto_sources(String::from("trusted-services-vendor/protocols"))?; 79 | } 80 | 81 | Ok(()) 82 | } 83 | 84 | #[cfg(not(feature = "trusted-service-provider"))] 85 | fn main() {} 86 | -------------------------------------------------------------------------------- /doc/images/parsec/ARM1007_PARSEC Logo_ST2_RGB_Stacked_Colour.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallaxsecond/parsec/5b2c4904d96808a5fb98a599f5304acef8b26dda/doc/images/parsec/ARM1007_PARSEC Logo_ST2_RGB_Stacked_Colour.png -------------------------------------------------------------------------------- /doc/images/parsec/ParsecConceptDiagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallaxsecond/parsec/5b2c4904d96808a5fb98a599f5304acef8b26dda/doc/images/parsec/ParsecConceptDiagram.png -------------------------------------------------------------------------------- /doc/images/partners/arm/Arm_logo_blue_150LG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallaxsecond/parsec/5b2c4904d96808a5fb98a599f5304acef8b26dda/doc/images/partners/arm/Arm_logo_blue_150LG.png -------------------------------------------------------------------------------- /doc/images/partners/docker/vertical-logo-monochromatic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallaxsecond/parsec/5b2c4904d96808a5fb98a599f5304acef8b26dda/doc/images/partners/docker/vertical-logo-monochromatic.png -------------------------------------------------------------------------------- /doc/images/partners/linaro/Logo_linaro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallaxsecond/parsec/5b2c4904d96808a5fb98a599f5304acef8b26dda/doc/images/partners/linaro/Logo_linaro.png -------------------------------------------------------------------------------- /doc/images/partners/mirantis/mirantis-logo-2color-rgb-transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallaxsecond/parsec/5b2c4904d96808a5fb98a599f5304acef8b26dda/doc/images/partners/mirantis/mirantis-logo-2color-rgb-transparent.png -------------------------------------------------------------------------------- /doc/images/partners/nxp/NXP_logo_RGB_web.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallaxsecond/parsec/5b2c4904d96808a5fb98a599f5304acef8b26dda/doc/images/partners/nxp/NXP_logo_RGB_web.jpg -------------------------------------------------------------------------------- /doc/images/partners/rancher/rancher-logo-stacked-color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallaxsecond/parsec/5b2c4904d96808a5fb98a599f5304acef8b26dda/doc/images/partners/rancher/rancher-logo-stacked-color.png -------------------------------------------------------------------------------- /doc/images/partners/redhat/Logo-RedHat-D-Color-RGB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallaxsecond/parsec/5b2c4904d96808a5fb98a599f5304acef8b26dda/doc/images/partners/redhat/Logo-RedHat-D-Color-RGB.png -------------------------------------------------------------------------------- /e2e_tests/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | provider_cfg/tmp_config.toml 3 | -------------------------------------------------------------------------------- /e2e_tests/Cargo.toml: -------------------------------------------------------------------------------- 1 | # This crate should NOT be upstreamed to crates.io; it is only intended for 2 | # PARSEC testing purposes (both locally and on CI) 3 | [package] 4 | name = "e2e_tests" 5 | version = "0.1.0" 6 | authors = ["Parsec Project Contributors"] 7 | description = "End to end testing framework for PARSEC" 8 | license = "Apache-2.0" 9 | edition = "2018" 10 | publish = false 11 | 12 | [dependencies] 13 | serde = { version = "1.0.123", features = ["derive"] } 14 | parsec-client = { version = "0.16.0", features = ["testing", "spiffe-auth"] } 15 | log = "0.4.14" 16 | # Compatible version with crate rsa 17 | rand = "0.7.3" 18 | env_logger = "0.10.0" 19 | stdext = "0.3.1" 20 | tss-esapi = { version = "7.5.0", optional = true } 21 | 22 | [dev-dependencies] 23 | ring = "0.16.20" 24 | rsa = "0.3.0" 25 | picky-asn1-x509 = "0.12.0" 26 | base64 = "0.21.0" 27 | num_cpus = "1.13.0" 28 | picky-asn1-der = "0.4.0" 29 | picky-asn1 = "0.8.0" 30 | sha2 = "0.9.3" 31 | serial_test = "0.5.1" 32 | regex = "1.6.0" 33 | cryptoki = { version = "0.6.0", default-features = false } 34 | snailquote = "0.3.1" 35 | 36 | [features] 37 | mbed-crypto-provider = [] 38 | tpm-provider = ["tss-esapi"] 39 | pkcs11-provider = [] 40 | cryptoauthlib-provider = [] 41 | trusted-service-provider = [] 42 | all-providers = ["pkcs11-provider","tpm-provider","mbed-crypto-provider","cryptoauthlib-provider","trusted-service-provider"] 43 | -------------------------------------------------------------------------------- /e2e_tests/docker_image/_exec_wrapper: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | RUSTUP_HOME=/opt/rust exec /opt/rust/bin/${0##*/} "$@" -------------------------------------------------------------------------------- /e2e_tests/docker_image/cross-compile-tss.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2021 Contributors to the Parsec project. 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | # Cross compile the tpm2-tss library (and its dependencies) for a given target 7 | # In order to cross-compile the TSS library we need to also cross-compile OpenSSL 8 | 9 | set -xeuf -o pipefail 10 | 11 | # Prepare directory for cross-compiled OpenSSL files 12 | mkdir -p /tmp/$1 13 | export INSTALL_DIR=/tmp/$1 14 | 15 | pushd /tmp/openssl 16 | # Compile and copy files over 17 | ./Configure $2 shared --prefix=$INSTALL_DIR --openssldir=$INSTALL_DIR/openssl --cross-compile-prefix=$1- 18 | make clean 19 | make depend 20 | make -j$(nproc) 21 | make install 22 | popd 23 | 24 | unset INSTALL_DIR 25 | 26 | # Prepare directory for cross-compiled TSS lib 27 | # `DESTDIR` is used in `make install` below to set the root of the installation paths. 28 | # The `./configure` script accepts a `--prefix` input variable which sets the same root, 29 | # but also adds it to the paths in `.pc` files used by `pkg-config`. This prevents the 30 | # use of `PKG_CONFIG_SYSROOT_DIR`. 31 | export DESTDIR=/tmp/$1 32 | 33 | pushd /tmp/tpm2-tss 34 | # Compile and copy files over 35 | ./bootstrap 36 | ./configure --build=x86_64-pc-linux-gnu --host=$1 CC=$1-gcc \ 37 | LIBCRYPTO_CFLAGS="-I/tmp/$1/include" LIBCRYPTO_LIBS="-L/tmp/$1/lib -lcrypto" 38 | make clean 39 | make -j$(nproc) 40 | make install 41 | popd 42 | 43 | unset DESTDIR -------------------------------------------------------------------------------- /e2e_tests/docker_image/import-old-e2e-tests.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2021 Contributors to the Parsec project. 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | # These commands are made to import the oldest version of the end-to-end tests to check that they 7 | # still work with the current version of the Parsec service. 8 | 9 | set -xeuf -o pipefail 10 | 11 | git clone https://github.com/parallaxsecond/parsec.git 12 | cd parsec 13 | # This commit is the oldest one which still works with current Parsec version. 14 | # It works with the Rust client version 0.6.0 15 | git checkout 2fee72fc64871472edf141906bf7f55bd59a2f8d 16 | mv e2e_tests /tmp/old_e2e_tests 17 | cd .. 18 | rm -rf parsec 19 | # Compiling the tests so that it's faster on the CI 20 | RUST_BACKTRACE=1 cargo test --no-run --manifest-path /tmp/old_e2e_tests/Cargo.toml 21 | -------------------------------------------------------------------------------- /e2e_tests/docker_image/parsec-service-test-cross-compile.Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Contributors to the Parsec project. 2 | # SPDX-License-Identifier: Apache-2.0 3 | FROM ghcr.io/parallaxsecond/parsec-service-test-all 4 | 5 | # Install aarch64-none-linux-gnu cross compilation toolchain 6 | RUN wget https://developer.arm.com/-/media/Files/downloads/gnu-a/9.2-2019.12/binrel/gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu.tar.xz?revision=61c3be5d-5175-4db6-9030-b565aae9f766 -O aarch64-gcc.tar.xz 7 | RUN tar --strip-components=1 -C /usr/ -xvf aarch64-gcc.tar.xz 8 | RUN rm aarch64-gcc.tar.xz 9 | 10 | # Install Trusted Services lib compiled for aarch64 11 | # Setup git config for patching dependencies 12 | RUN git config --global user.email "some@email.com" 13 | RUN git config --global user.name "Parsec Team" 14 | RUN git clone https://git.trustedfirmware.org/TS/trusted-services.git --branch main \ 15 | && cd trusted-services \ 16 | && git reset --hard b27d4163e01065d1203bd71ffa6562a651f77a13 17 | # Install correct python dependencies 18 | RUN pip3 install -r trusted-services/requirements.txt 19 | RUN cd trusted-services/deployments/libts/arm-linux/ \ 20 | && cmake . \ 21 | && make \ 22 | && cp libts.so* /usr/local/lib/ 23 | RUN rm -rf trusted-services 24 | 25 | # Install cross-compilers 26 | RUN apt install -y gcc-multilib 27 | RUN apt install -y gcc-arm-linux-gnueabihf 28 | RUN apt install -y gcc-aarch64-linux-gnu 29 | RUN apt install -y gcc-i686-linux-gnu libc6-dev-i386 30 | 31 | WORKDIR /tmp 32 | 33 | # Get OpenSSL source code 34 | ENV OPENSSL_VERSION="OpenSSL_1_1_1j" 35 | RUN git clone https://github.com/openssl/openssl.git --branch $OPENSSL_VERSION 36 | 37 | # Get TPM2 TSS source code 38 | ENV TPM2_TSS_VERSION="2.3.3" 39 | RUN git clone https://github.com/tpm2-software/tpm2-tss --branch $TPM2_TSS_VERSION 40 | 41 | # Copy TSS cross-compilation script 42 | COPY cross-compile-tss.sh /tmp/ 43 | # Cross-compile TPM2 TSS and OpenSSL for Linux on aarch64 44 | RUN ./cross-compile-tss.sh aarch64-linux-gnu linux-generic64 45 | # Cross-compile TPM2 TSS and OpenSSL for Linux on armv7 46 | RUN ./cross-compile-tss.sh arm-linux-gnueabihf linux-generic32 47 | # Cross-compile TPM2 TSS and OpenSSL for Linux on i686 48 | RUN ./cross-compile-tss.sh i686-linux-gnu linux-generic32 49 | 50 | RUN rustup target add armv7-unknown-linux-gnueabihf 51 | RUN rustup target add aarch64-unknown-linux-gnu 52 | RUN rustup target add i686-unknown-linux-gnu 53 | -------------------------------------------------------------------------------- /e2e_tests/fake_mappings/cGFyc2VjLXRvb2w=/1/dG90bw==: -------------------------------------------------------------------------------- 1 |   -------------------------------------------------------------------------------- /e2e_tests/fake_mappings/cGFyc2VjLXRvb2w=/2/dG90bw==: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/parallaxsecond/parsec/5b2c4904d96808a5fb98a599f5304acef8b26dda/e2e_tests/fake_mappings/cGFyc2VjLXRvb2w=/2/dG90bw== -------------------------------------------------------------------------------- /e2e_tests/provider_cfg/all/config.toml: -------------------------------------------------------------------------------- 1 | [core_settings] 2 | # The CI already timestamps the logs 3 | log_timestamp = false 4 | log_error_details = true 5 | 6 | # The container runs the Parsec service as root, so make sure we disable root 7 | # checks. 8 | allow_root = true 9 | 10 | [listener] 11 | listener_type = "DomainSocket" 12 | timeout = 200 # in milliseconds 13 | socket_path = "/tmp/parsec.sock" 14 | 15 | [authenticator] 16 | auth_type = "Direct" 17 | admins = [ { name = "list_clients test" }, { name = "1000" }, { name = "client1" }, { name = "spiffe://example.org/parsec-client-1" } ] 18 | #workload_endpoint="unix:///tmp/agent.sock" 19 | 20 | [[key_manager]] 21 | name = "sqlite-manager" 22 | manager_type = "SQLite" 23 | sqlite_db_path = "./kim-mappings/sqlite/sqlite-key-info-manager.sqlite3" 24 | 25 | [[provider]] 26 | provider_type = "MbedCrypto" 27 | key_info_manager = "sqlite-manager" 28 | 29 | [[provider]] 30 | provider_type = "Tpm" 31 | key_info_manager = "sqlite-manager" 32 | tcti = "mssim" 33 | owner_hierarchy_auth = "tpm_pass" 34 | 35 | [[provider]] 36 | provider_type = "Pkcs11" 37 | key_info_manager = "sqlite-manager" 38 | library_path = "/usr/local/lib/softhsm/libsofthsm2.so" 39 | user_pin = "123456" 40 | # The slot_number mandatory field is going to replace the following line with a valid number 41 | # slot_number 42 | 43 | 44 | # CAL provider and hardware abstraction crate are unmaintained; See #585 45 | # [[provider]] 46 | # provider_type = "CryptoAuthLib" 47 | # key_info_manager = "sqlite-manager" 48 | # device_type = "always-success" 49 | # iface_type = "test-interface" 50 | # wake_delay = 1500 51 | # rx_retries = 20 52 | # # i2c parameters for i2c-pseudo proxy 53 | # slave_address = 0xc0 54 | # bus = 1 55 | # baud = 400000 56 | -------------------------------------------------------------------------------- /e2e_tests/provider_cfg/all/on-disk-kim-all-providers.toml: -------------------------------------------------------------------------------- 1 | [core_settings] 2 | # The CI already timestamps the logs 3 | log_timestamp = false 4 | log_error_details = true 5 | 6 | # The container runs the Parsec service as root, so make sure we disable root 7 | # checks. 8 | allow_root = true 9 | 10 | [listener] 11 | listener_type = "DomainSocket" 12 | timeout = 200 # in milliseconds 13 | socket_path = "/tmp/parsec.sock" 14 | 15 | [authenticator] 16 | auth_type = "Direct" 17 | admins = [ { name = "list_clients test" }, { name = "1000" }, { name = "client1" }, { name = "spiffe://example.org/parsec-client-1" } ] 18 | #workload_endpoint="unix:///tmp/agent.sock" 19 | 20 | [[key_manager]] 21 | name = "on-disk-manager" 22 | manager_type = "OnDisk" 23 | store_path = "./mappings" 24 | 25 | [[provider]] 26 | provider_type = "MbedCrypto" 27 | key_info_manager = "on-disk-manager" 28 | 29 | [[provider]] 30 | provider_type = "Tpm" 31 | key_info_manager = "on-disk-manager" 32 | tcti = "mssim" 33 | owner_hierarchy_auth = "tpm_pass" 34 | 35 | [[provider]] 36 | provider_type = "Pkcs11" 37 | key_info_manager = "on-disk-manager" 38 | library_path = "/usr/local/lib/softhsm/libsofthsm2.so" 39 | user_pin = "123456" 40 | # The slot_number mandatory field is going to replace the following line with a valid number 41 | # slot_number 42 | 43 | # CAL provider and hardware abstraction crate are unmaintained; See #585 44 | # [[provider]] 45 | # provider_type = "CryptoAuthLib" 46 | # key_info_manager = "on-disk-manager" 47 | # device_type = "always-success" 48 | # iface_type = "test-interface" 49 | # wake_delay = 1500 50 | # rx_retries = 20 51 | # # i2c parameters for i2c-pseudo proxy 52 | # slave_address = 0xc0 53 | # bus = 1 54 | # baud = 400000 55 | -------------------------------------------------------------------------------- /e2e_tests/provider_cfg/cryptoauthlib/cal_access_keys.toml: -------------------------------------------------------------------------------- 1 | ######################################################################### 2 | # The example configuration file with access keys. 3 | # 4 | # Note! The contents of this file may be considered sensitive from 5 | # a security point of view. Therefore this file should be stored in 6 | # a secure folder, where only 'parsec' user may read its contents. 7 | # The keys MUST be exactly the same as the ones stored in given slots. 8 | # This means there may be a need to generate file per cryptochip. 9 | # 10 | # Safe to be used in github CI. 11 | ######################################################################### 12 | [[access_keys]] 13 | # Cryptochip slot index, 0..15 14 | slot = 6 15 | # Access key - 32 bytes long octet string 16 | key = [ 0x4D, 0x50, 0x72, 0x6F, 0x20, 0x49, 0x4F, 0x20, 0x4B, 0x65, 0x79, 0x20, 0x9E, 0x31, 17 | 0xBD, 0x05, 0x82, 0x58, 0x76, 0xCE, 0x37, 0x90, 0xEA, 0x77, 0x42, 0x32, 0xBB, 0x51, 18 | 0x81, 0x49, 0x66, 0x45] 19 | 20 | [[access_keys]] 21 | # Yes, slot number below does not make much sense. But it is not a big issue. 22 | slot = 22 23 | key = [ 0x4E, 0x51, 0x73, 0x70, 0x21, 0x4A, 0x50, 0x21, 0x4C, 0x66, 0x7A, 0x21, 0x9F, 0x32, 24 | 0xBE, 0x06, 0x83, 0x59, 0x77, 0xCF, 0x38, 0x91, 0xEB, 0x78, 0x43, 0x33, 0xBC, 0x52, 25 | 0x82, 0x50, 0x67, 0x46] 26 | -------------------------------------------------------------------------------- /e2e_tests/provider_cfg/cryptoauthlib/config-sqlite.toml: -------------------------------------------------------------------------------- 1 | [core_settings] 2 | # The CI already timestamps the logs 3 | log_timestamp = false 4 | log_error_details = true 5 | 6 | # The container runs the Parsec service as root, so make sure we disable root 7 | # checks. 8 | allow_root = true 9 | 10 | [listener] 11 | listener_type = "DomainSocket" 12 | timeout = 200 # in milliseconds 13 | socket_path = "/tmp/parsec.sock" 14 | 15 | [authenticator] 16 | auth_type = "Direct" 17 | 18 | [[key_manager]] 19 | name = "sqlite-manager" 20 | manager_type = "SQLite" 21 | sqlite_db_path = "./kim-mappings/sqlite/sqlite-key-info-manager.sqlite3" 22 | 23 | [[provider]] 24 | provider_type = "CryptoAuthLib" 25 | key_info_manager = "sqlite-manager" 26 | device_type = "unimplemented-fail" 27 | iface_type = "test-interface" 28 | -------------------------------------------------------------------------------- /e2e_tests/provider_cfg/cryptoauthlib/config.toml: -------------------------------------------------------------------------------- 1 | [core_settings] 2 | # The CI already timestamps the logs 3 | log_timestamp = false 4 | log_error_details = true 5 | 6 | # The container runs the Parsec service as root, so make sure we disable root 7 | # checks. 8 | allow_root = true 9 | # Allow deprecated for testing 10 | allow_deprecated = true 11 | 12 | [listener] 13 | listener_type = "DomainSocket" 14 | timeout = 200 # in milliseconds 15 | socket_path = "/tmp/parsec.sock" 16 | 17 | [authenticator] 18 | auth_type = "Direct" 19 | 20 | [[key_manager]] 21 | name = "on-disk-manager" 22 | manager_type = "OnDisk" 23 | store_path = "./mappings" 24 | 25 | [[provider]] 26 | provider_type = "CryptoAuthLib" 27 | key_info_manager = "on-disk-manager" 28 | device_type = "unimplemented-fail" 29 | iface_type = "test-interface" 30 | -------------------------------------------------------------------------------- /e2e_tests/provider_cfg/cryptoauthlib/config_508a.toml: -------------------------------------------------------------------------------- 1 | ######################################################################### 2 | # The example config file for atecc508a cryptochip. 3 | # There must be an I2C bus with a cryptochip soldered, otherwise provider 4 | # instantiation fails. 5 | # Not to be used by github CI. 6 | ######################################################################### 7 | [core_settings] 8 | # The CI already timestamps the logs 9 | log_timestamp = false 10 | log_error_details = true 11 | 12 | # The container runs the Parsec service as root, so make sure we disable root 13 | # checks. 14 | allow_root = true 15 | 16 | [listener] 17 | listener_type = "DomainSocket" 18 | timeout = 200 # in milliseconds 19 | socket_path = "/tmp/parsec.sock" 20 | 21 | [authenticator] 22 | auth_type = "Direct" 23 | 24 | [[key_manager]] 25 | name = "on-disk-manager" 26 | manager_type = "OnDisk" 27 | store_path = "./mappings" 28 | 29 | [[provider]] 30 | provider_type = "CryptoAuthLib" 31 | key_info_manager = "on-disk-manager" 32 | device_type = "atecc508a" 33 | iface_type = "i2c" 34 | wake_delay = 1500 35 | rx_retries = 20 36 | # i2c parameters for i2c-pseudo proxy 37 | slave_address = 0xc0 38 | bus = 1 39 | baud = 400000 40 | -------------------------------------------------------------------------------- /e2e_tests/provider_cfg/cryptoauthlib/config_608a.toml: -------------------------------------------------------------------------------- 1 | ######################################################################### 2 | # The example config file for atecc608a cryptochip. 3 | # There must be an I2C bus with a cryptochip soldered, otherwise provider 4 | # instantiation fails. 5 | # Not to be used by github CI. 6 | ######################################################################### 7 | [core_settings] 8 | # The CI already timestamps the logs 9 | log_timestamp = false 10 | log_error_details = true 11 | 12 | # The container runs the Parsec service as root, so make sure we disable root 13 | # checks. 14 | allow_root = true 15 | 16 | [listener] 17 | listener_type = "DomainSocket" 18 | timeout = 200 # in milliseconds 19 | socket_path = "/tmp/parsec.sock" 20 | 21 | [authenticator] 22 | auth_type = "Direct" 23 | 24 | [[key_manager]] 25 | name = "on-disk-manager" 26 | manager_type = "OnDisk" 27 | store_path = "./mappings" 28 | 29 | [[provider]] 30 | provider_type = "CryptoAuthLib" 31 | key_info_manager = "on-disk-manager" 32 | device_type = "atecc608a" 33 | iface_type = "i2c" 34 | wake_delay = 1600 35 | rx_retries = 20 36 | # i2c parameters for i2c-pseudo proxy 37 | slave_address = 0xc0 38 | bus = 1 39 | baud = 400000 40 | access_key_file_name = "e2e_tests/provider_cfg/cryptoauthlib/cal_access_keys.toml" 41 | -------------------------------------------------------------------------------- /e2e_tests/provider_cfg/mbed-crypto/config-sqlite.toml: -------------------------------------------------------------------------------- 1 | [core_settings] 2 | # The CI already timestamps the logs 3 | log_timestamp = false 4 | log_error_details = true 5 | 6 | # The container runs the Parsec service as root, so make sure we disable root 7 | # checks. 8 | allow_root = true 9 | 10 | [listener] 11 | listener_type = "DomainSocket" 12 | # The timeout needs to be smaller than the test client timeout (five seconds) as it is testing 13 | # that the service does not hang for very big values of body or authentication length. 14 | timeout = 3000 # in milliseconds 15 | socket_path = "/tmp/parsec.sock" 16 | 17 | [authenticator] 18 | auth_type = "Direct" 19 | 20 | [[key_manager]] 21 | name = "sqlite-manager" 22 | manager_type = "SQLite" 23 | sqlite_db_path = "./kim-mappings/sqlite/sqlite-key-info-manager.sqlite3" 24 | 25 | [[provider]] 26 | provider_type = "MbedCrypto" 27 | key_info_manager = "sqlite-manager" 28 | -------------------------------------------------------------------------------- /e2e_tests/provider_cfg/mbed-crypto/config.toml: -------------------------------------------------------------------------------- 1 | [core_settings] 2 | # The CI already timestamps the logs 3 | log_timestamp = false 4 | log_error_details = true 5 | 6 | # The container runs the Parsec service as root, so make sure we disable root 7 | # checks. 8 | allow_root = true 9 | # Allow deprecated for testing 10 | allow_deprecated = true 11 | 12 | [listener] 13 | listener_type = "DomainSocket" 14 | # The timeout needs to be smaller than the test client timeout (five seconds) as it is testing 15 | # that the service does not hang for very big values of body or authentication length. 16 | timeout = 3000 # in milliseconds 17 | socket_path = "/tmp/parsec.sock" 18 | 19 | [authenticator] 20 | auth_type = "Direct" 21 | 22 | [[key_manager]] 23 | name = "on-disk-manager" 24 | manager_type = "OnDisk" 25 | store_path = "./mappings" 26 | 27 | [[provider]] 28 | provider_type = "MbedCrypto" 29 | key_info_manager = "on-disk-manager" 30 | -------------------------------------------------------------------------------- /e2e_tests/provider_cfg/pkcs11/config-sqlite.toml: -------------------------------------------------------------------------------- 1 | [core_settings] 2 | # The CI already timestamps the logs 3 | log_timestamp = false 4 | log_error_details = true 5 | 6 | # The container runs the Parsec service as root, so make sure we disable root 7 | # checks. 8 | allow_root = true 9 | 10 | [listener] 11 | listener_type = "DomainSocket" 12 | # The timeout needs to be smaller than the test client timeout (five seconds) as it is testing 13 | # that the service does not hang for very big values of body or authentication length. 14 | timeout = 3000 # in milliseconds 15 | socket_path = "/tmp/parsec.sock" 16 | 17 | [authenticator] 18 | auth_type = "Direct" 19 | 20 | [[key_manager]] 21 | name = "sqlite-manager" 22 | manager_type = "SQLite" 23 | sqlite_db_path = "./kim-mappings/sqlite/sqlite-key-info-manager.sqlite3" 24 | 25 | [[provider]] 26 | provider_type = "Pkcs11" 27 | key_info_manager = "sqlite-manager" 28 | library_path = "/usr/local/lib/softhsm/libsofthsm2.so" 29 | user_pin = "123456" 30 | software_public_operations = false 31 | # The slot_number optional field is going to replace the following line with a valid number 32 | # slot_number 33 | # The token serial_number optional field is going to replace the following line with a valid number 34 | # serial_number 35 | -------------------------------------------------------------------------------- /e2e_tests/provider_cfg/pkcs11/config.toml: -------------------------------------------------------------------------------- 1 | [core_settings] 2 | # The CI already timestamps the logs 3 | log_timestamp = false 4 | log_error_details = true 5 | 6 | # The container runs the Parsec service as root, so make sure we disable root 7 | # checks. 8 | allow_root = true 9 | # Allow deprecated for testing 10 | allow_deprecated = true 11 | 12 | [listener] 13 | listener_type = "DomainSocket" 14 | # The timeout needs to be smaller than the test client timeout (five seconds) as it is testing 15 | # that the service does not hang for very big values of body or authentication length. 16 | timeout = 3000 # in milliseconds 17 | socket_path = "/tmp/parsec.sock" 18 | 19 | [authenticator] 20 | auth_type = "Direct" 21 | 22 | [[key_manager]] 23 | name = "on-disk-manager" 24 | manager_type = "OnDisk" 25 | store_path = "./mappings" 26 | 27 | [[provider]] 28 | provider_type = "Pkcs11" 29 | key_info_manager = "on-disk-manager" 30 | library_path = "/usr/local/lib/softhsm/libsofthsm2.so" 31 | user_pin = "123456" 32 | software_public_operations = false 33 | # The slot_number optional field is going to replace the following line with a valid number 34 | # slot_number 35 | # The token serial_number optional field is going to replace the following line with a valid number 36 | # serial_number 37 | -------------------------------------------------------------------------------- /e2e_tests/provider_cfg/tpm/config-sqlite.toml: -------------------------------------------------------------------------------- 1 | [core_settings] 2 | # The CI already timestamps the logs 3 | log_timestamp = false 4 | log_error_details = true 5 | 6 | # The container runs the Parsec service as root, so make sure we disable root 7 | # checks. 8 | allow_root = true 9 | 10 | [listener] 11 | listener_type = "DomainSocket" 12 | # The timeout needs to be smaller than the test client timeout (five seconds) as it is testing 13 | # that the service does not hang for very big values of body or authentication length. 14 | timeout = 3000 # in milliseconds 15 | socket_path = "/tmp/parsec.sock" 16 | 17 | [authenticator] 18 | auth_type = "Direct" 19 | 20 | [[key_manager]] 21 | name = "sqlite-manager" 22 | manager_type = "SQLite" 23 | sqlite_db_path = "./kim-mappings/sqlite/sqlite-key-info-manager.sqlite3" 24 | 25 | [[provider]] 26 | provider_type = "Tpm" 27 | key_info_manager = "sqlite-manager" 28 | tcti = "mssim:host=127.0.0.1,port=2321" 29 | owner_hierarchy_auth = "hex:74706d5f70617373" # "tpm_pass" in hex 30 | endorsement_hierarchy_auth = "str:endorsement_pass" 31 | -------------------------------------------------------------------------------- /e2e_tests/provider_cfg/tpm/config.toml: -------------------------------------------------------------------------------- 1 | [core_settings] 2 | # The CI already timestamps the logs 3 | log_timestamp = false 4 | log_error_details = true 5 | 6 | # The container runs the Parsec service as root, so make sure we disable root 7 | # checks. 8 | allow_root = true 9 | # Allow deprecated for testing 10 | allow_deprecated = true 11 | 12 | [listener] 13 | listener_type = "DomainSocket" 14 | # The timeout needs to be smaller than the test client timeout (five seconds) as it is testing 15 | # that the service does not hang for very big values of body or authentication length. 16 | timeout = 3000 # in milliseconds 17 | socket_path = "/tmp/parsec.sock" 18 | 19 | [authenticator] 20 | auth_type = "Direct" 21 | 22 | [[key_manager]] 23 | name = "on-disk-manager" 24 | manager_type = "OnDisk" 25 | store_path = "./mappings" 26 | 27 | [[provider]] 28 | provider_type = "Tpm" 29 | key_info_manager = "on-disk-manager" 30 | tcti = "mssim:host=127.0.0.1,port=2321" 31 | owner_hierarchy_auth = "hex:74706d5f70617373" # "tpm_pass" in hex 32 | endorsement_hierarchy_auth = "str:endorsement_pass" 33 | -------------------------------------------------------------------------------- /e2e_tests/provider_cfg/trusted-service/config-sqlite.toml: -------------------------------------------------------------------------------- 1 | [core_settings] 2 | # The CI already timestamps the logs 3 | log_timestamp = false 4 | log_error_details = true 5 | 6 | # The container runs the Parsec service as root, so make sure we disable root 7 | # checks. 8 | allow_root = true 9 | 10 | [listener] 11 | listener_type = "DomainSocket" 12 | # The timeout needs to be smaller than the test client timeout (five seconds) as it is testing 13 | # that the service does not hang for very big values of body or authentication length. 14 | timeout = 3000 # in milliseconds 15 | socket_path = "/tmp/parsec.sock" 16 | 17 | [authenticator] 18 | auth_type = "Direct" 19 | 20 | [[key_manager]] 21 | name = "sqlite-manager" 22 | manager_type = "SQLite" 23 | sqlite_db_path = "./kim-mappings/sqlite/sqlite-key-info-manager.sqlite3" 24 | 25 | [[provider]] 26 | provider_type = "TrustedService" 27 | key_info_manager = "sqlite-manager" 28 | -------------------------------------------------------------------------------- /e2e_tests/provider_cfg/trusted-service/config.toml: -------------------------------------------------------------------------------- 1 | [core_settings] 2 | # The CI already timestamps the logs 3 | log_timestamp = false 4 | log_error_details = true 5 | 6 | # The container runs the Parsec service as root, so make sure we disable root 7 | # checks. 8 | allow_root = true 9 | # Allow deprecated for testing 10 | allow_deprecated = true 11 | 12 | [listener] 13 | listener_type = "DomainSocket" 14 | # The timeout needs to be smaller than the test client timeout (five seconds) as it is testing 15 | # that the service does not hang for very big values of body or authentication length. 16 | timeout = 3000 # in milliseconds 17 | socket_path = "/tmp/parsec.sock" 18 | 19 | [authenticator] 20 | auth_type = "Direct" 21 | 22 | [[key_manager]] 23 | name = "on-disk-manager" 24 | manager_type = "OnDisk" 25 | store_path = "./mappings" 26 | 27 | [[provider]] 28 | provider_type = "TrustedService" 29 | key_info_manager = "on-disk-manager" 30 | -------------------------------------------------------------------------------- /e2e_tests/src/raw_request.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | use parsec_client::core::interface::requests::request::RawHeader; 4 | use parsec_client::core::interface::requests::{Response, Result}; 5 | use std::env; 6 | use std::io::Write; 7 | use std::os::unix::net::UnixStream; 8 | use std::thread; 9 | use std::time::Duration; 10 | 11 | const MAX_BODY_SIZE: usize = 1 << 31; 12 | 13 | /// Low level client structure to send a `Request` and get a `Response`. 14 | #[derive(Copy, Clone, Debug)] 15 | pub struct RawRequestClient; 16 | 17 | const TIMEOUT: Duration = Duration::from_secs(60); 18 | 19 | #[allow(clippy::new_without_default)] 20 | impl RawRequestClient { 21 | /// Send a raw request. 22 | /// 23 | /// Send a raw request header and a collection of bytes. 24 | pub fn send_raw_request(&mut self, request_hdr: RawHeader, bytes: Vec) -> Result { 25 | //Check the envrionment variable before using the default test path 26 | let socket_path = env::var("PARSEC_SERVICE_ENDPOINT") 27 | .unwrap_or_else(|_| "/tmp/parsec.sock".into()) 28 | .replace("unix:", ""); 29 | 30 | // Try to connect once, wait for a timeout until trying again. 31 | let mut stream = UnixStream::connect(&socket_path); 32 | if stream.is_err() { 33 | thread::sleep(TIMEOUT); 34 | stream = UnixStream::connect(&socket_path); 35 | } 36 | let mut stream = stream.expect("Failed to connect to Unix socket"); 37 | 38 | stream 39 | .set_read_timeout(Some(TIMEOUT)) 40 | .expect("Failed to set read timeout for stream"); 41 | stream 42 | .set_write_timeout(Some(TIMEOUT)) 43 | .expect("Failed to set write timeout for stream"); 44 | 45 | request_hdr 46 | .write_to_stream(&mut stream) 47 | .expect("Failed to write raw header to socket"); 48 | stream 49 | .write_all(&bytes) 50 | .expect("Failed to write bytes to stream"); 51 | 52 | Response::read_from_stream(&mut stream, MAX_BODY_SIZE) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /e2e_tests/tests/all_providers/config/tomls/allow_deprecated.toml: -------------------------------------------------------------------------------- 1 | [core_settings] 2 | # The CI already timestamps the logs 3 | log_timestamp = false 4 | log_error_details = true 5 | allow_deprecated = true 6 | 7 | [listener] 8 | listener_type = "DomainSocket" 9 | timeout = 200 # in milliseconds 10 | socket_path = "/tmp/parsec.sock" 11 | 12 | [authenticator] 13 | auth_type = "Direct" 14 | 15 | [[key_manager]] 16 | name = "sqlite-manager" 17 | manager_type = "SQLite" 18 | database_path = "./kim-mappings/sqlite/sqlite-key-info-manager.sqlite3" 19 | 20 | [[provider]] 21 | provider_type = "MbedCrypto" 22 | key_info_manager = "sqlite-manager" 23 | -------------------------------------------------------------------------------- /e2e_tests/tests/all_providers/config/tomls/allow_export.toml: -------------------------------------------------------------------------------- 1 | [core_settings] 2 | # The CI already timestamps the logs 3 | log_timestamp = false 4 | log_error_details = true 5 | 6 | [listener] 7 | listener_type = "DomainSocket" 8 | timeout = 200 # in milliseconds 9 | socket_path = "/tmp/parsec.sock" 10 | 11 | [authenticator] 12 | auth_type = "Direct" 13 | 14 | [[key_manager]] 15 | name = "sqlite-manager" 16 | manager_type = "SQLite" 17 | sqlite_db_path = "./kim-mappings/sqlite/sqlite-key-info-manager.sqlite3" 18 | 19 | [[provider]] 20 | provider_type = "Pkcs11" 21 | key_info_manager = "sqlite-manager" 22 | library_path = "/usr/local/lib/softhsm/libsofthsm2.so" 23 | user_pin = "123456" 24 | # The slot_number mandatory field is going to replace the following line with a valid number 25 | # slot_number 26 | allow_export = false 27 | -------------------------------------------------------------------------------- /e2e_tests/tests/all_providers/config/tomls/list_providers_1.toml: -------------------------------------------------------------------------------- 1 | [core_settings] 2 | # The CI already timestamps the logs 3 | log_timestamp = false 4 | log_error_details = true 5 | 6 | [listener] 7 | listener_type = "DomainSocket" 8 | timeout = 200 # in milliseconds 9 | socket_path = "/tmp/parsec.sock" 10 | 11 | [authenticator] 12 | auth_type = "Direct" 13 | 14 | [[key_manager]] 15 | name = "sqlite-manager" 16 | manager_type = "SQLite" 17 | sqlite_db_path = "./kim-mappings/sqlite/sqlite-key-info-manager.sqlite3" 18 | 19 | [[provider]] 20 | provider_type = "MbedCrypto" 21 | key_info_manager = "sqlite-manager" 22 | 23 | [[provider]] 24 | provider_type = "Tpm" 25 | key_info_manager = "sqlite-manager" 26 | tcti = "mssim" 27 | owner_hierarchy_auth = "tpm_pass" 28 | 29 | [[provider]] 30 | provider_type = "Pkcs11" 31 | key_info_manager = "sqlite-manager" 32 | library_path = "/usr/local/lib/softhsm/libsofthsm2.so" 33 | user_pin = "123456" 34 | # The slot_number mandatory field is going to replace the following line with a valid number 35 | # slot_number 36 | 37 | # CAL provider and hardware abstraction crate are unmaintained; See #585 38 | # [[provider]] 39 | # provider_type = "CryptoAuthLib" 40 | # key_info_manager = "sqlite-manager" 41 | # device_type = "always-success" 42 | # iface_type = "test-interface" 43 | # wake_delay = 1500 44 | # rx_retries = 20 45 | # # i2c parameters for i2c-pseudo proxy 46 | # slave_address = 0xc0 47 | # bus = 1 48 | # baud = 400000 49 | -------------------------------------------------------------------------------- /e2e_tests/tests/all_providers/config/tomls/list_providers_2.toml: -------------------------------------------------------------------------------- 1 | [core_settings] 2 | # The CI already timestamps the logs 3 | log_timestamp = false 4 | log_error_details = true 5 | 6 | [listener] 7 | listener_type = "DomainSocket" 8 | timeout = 200 # in milliseconds 9 | socket_path = "/tmp/parsec.sock" 10 | 11 | [authenticator] 12 | auth_type = "Direct" 13 | 14 | [[key_manager]] 15 | name = "sqlite-manager" 16 | manager_type = "SQLite" 17 | sqlite_db_path = "./kim-mappings/sqlite/sqlite-key-info-manager.sqlite3" 18 | 19 | [[provider]] 20 | provider_type = "Pkcs11" 21 | key_info_manager = "sqlite-manager" 22 | library_path = "/usr/local/lib/softhsm/libsofthsm2.so" 23 | user_pin = "123456" 24 | # The slot_number mandatory field is going to replace the following line with a valid number 25 | # slot_number 26 | 27 | [[provider]] 28 | provider_type = "MbedCrypto" 29 | key_info_manager = "sqlite-manager" 30 | 31 | [[provider]] 32 | provider_type = "Tpm" 33 | key_info_manager = "sqlite-manager" 34 | tcti = "mssim" 35 | owner_hierarchy_auth = "tpm_pass" 36 | 37 | # CAL provider and hardware abstraction crate are unmaintained; See #585 38 | # [[provider]] 39 | # provider_type = "CryptoAuthLib" 40 | # key_info_manager = "sqlite-manager" 41 | # device_type = "always-success" 42 | # iface_type = "test-interface" 43 | # wake_delay = 1500 44 | # rx_retries = 20 45 | # # i2c parameters for i2c-pseudo proxy 46 | # slave_address = 0xc0 47 | # bus = 1 48 | # baud = 400000 49 | -------------------------------------------------------------------------------- /e2e_tests/tests/all_providers/config/tomls/no_endorsement_auth.toml: -------------------------------------------------------------------------------- 1 | [core_settings] 2 | # The CI already timestamps the logs 3 | log_timestamp = false 4 | log_error_details = true 5 | 6 | # The container runs the Parsec service as root, so make sure we disable root 7 | # checks. 8 | allow_root = true 9 | 10 | [listener] 11 | listener_type = "DomainSocket" 12 | # The timeout needs to be smaller than the test client timeout (five seconds) as it is testing 13 | # that the service does not hang for very big values of body or authentication length. 14 | timeout = 3000 # in milliseconds 15 | socket_path = "/tmp/parsec.sock" 16 | 17 | [authenticator] 18 | auth_type = "Direct" 19 | 20 | [[key_manager]] 21 | name = "sqlite-manager" 22 | manager_type = "SQLite" 23 | sqlite_db_path = "./kim-mappings/sqlite/sqlite-key-info-manager.sqlite3" 24 | 25 | [[provider]] 26 | provider_type = "Tpm" 27 | key_info_manager = "sqlite-manager" 28 | tcti = "mssim:host=127.0.0.1,port=2321" 29 | owner_hierarchy_auth = "hex:74706d5f70617373" # "tpm_pass" in hex 30 | -------------------------------------------------------------------------------- /e2e_tests/tests/all_providers/config/tomls/no_serial_or_slot_number.toml: -------------------------------------------------------------------------------- 1 | [core_settings] 2 | # The CI already timestamps the logs 3 | log_timestamp = false 4 | log_error_details = true 5 | 6 | # The container runs the Parsec service as root, so make sure we disable root 7 | # checks. 8 | allow_root = true 9 | 10 | [listener] 11 | listener_type = "DomainSocket" 12 | # The timeout needs to be smaller than the test client timeout (five seconds) as it is testing 13 | # that the service does not hang for very big values of body or authentication length. 14 | timeout = 3000 # in milliseconds 15 | socket_path = "/tmp/parsec.sock" 16 | 17 | [authenticator] 18 | auth_type = "Direct" 19 | 20 | [[key_manager]] 21 | name = "sqlite-manager" 22 | manager_type = "SQLite" 23 | sqlite_db_path = "./kim-mappings/sqlite/sqlite-key-info-manager.sqlite3" 24 | 25 | [[provider]] 26 | provider_type = "Pkcs11" 27 | key_info_manager = "sqlite-manager" 28 | library_path = "/usr/local/lib/softhsm/libsofthsm2.so" 29 | user_pin = "123456" 30 | # Slot number not entered, it should be automatically chosen by the service. 31 | -------------------------------------------------------------------------------- /e2e_tests/tests/all_providers/config/tomls/no_tpm_support.toml: -------------------------------------------------------------------------------- 1 | [core_settings] 2 | # The CI already timestamps the logs 3 | log_timestamp = false 4 | log_error_details = true 5 | 6 | [listener] 7 | listener_type = "DomainSocket" 8 | timeout = 200 # in milliseconds 9 | socket_path = "/tmp/parsec.sock" 10 | 11 | [authenticator] 12 | auth_type = "Direct" 13 | 14 | [[key_manager]] 15 | name = "sqlite-manager" 16 | manager_type = "SQLite" 17 | sqlite_db_path = "./kim-mappings/sqlite/sqlite-key-info-manager.sqlite3" 18 | 19 | [[provider]] 20 | provider_type = "MbedCrypto" 21 | key_info_manager = "sqlite-manager" 22 | 23 | [[provider]] 24 | provider_type = "Tpm" 25 | key_info_manager = "sqlite-manager" 26 | # There shoudn't be a real TPM available on the CI 27 | tcti = "device" 28 | owner_hierarchy_auth = "" 29 | skip_if_no_tpm = true 30 | 31 | [[provider]] 32 | provider_type = "Pkcs11" 33 | key_info_manager = "sqlite-manager" 34 | library_path = "/usr/local/lib/softhsm/libsofthsm2.so" 35 | user_pin = "123456" 36 | # The slot_number mandatory field is going to replace the following line with a valid number 37 | # slot_number 38 | -------------------------------------------------------------------------------- /e2e_tests/tests/all_providers/config/tomls/no_user_pin.toml: -------------------------------------------------------------------------------- 1 | [core_settings] 2 | # The CI already timestamps the logs 3 | log_timestamp = false 4 | log_error_details = true 5 | 6 | # The container runs the Parsec service as root, so make sure we disable root 7 | # checks. 8 | allow_root = true 9 | 10 | [listener] 11 | listener_type = "DomainSocket" 12 | # The timeout needs to be smaller than the test client timeout (five seconds) as it is testing 13 | # that the service does not hang for very big values of body or authentication length. 14 | timeout = 3000 # in milliseconds 15 | socket_path = "/tmp/parsec.sock" 16 | 17 | [authenticator] 18 | auth_type = "Direct" 19 | 20 | [[key_manager]] 21 | name = "sqlite-manager" 22 | manager_type = "SQLite" 23 | sqlite_db_path = "./kim-mappings/sqlite/sqlite-key-info-manager.sqlite3" 24 | 25 | [[provider]] 26 | provider_type = "Pkcs11" 27 | key_info_manager = "sqlite-manager" 28 | library_path = "/usr/local/lib/softhsm/libsofthsm2.so" 29 | # The service should start without the user pin 30 | #user_pin = "123456" 31 | # The slot_number mandatory field is going to replace the following line with a valid number 32 | # slot_number 33 | -------------------------------------------------------------------------------- /e2e_tests/tests/all_providers/config/tomls/pkcs11_pin_hex_fmt.toml: -------------------------------------------------------------------------------- 1 | [core_settings] 2 | # The CI already timestamps the logs 3 | log_timestamp = false 4 | log_error_details = true 5 | 6 | # The container runs the Parsec service as root, so make sure we disable root 7 | # checks. 8 | allow_root = true 9 | 10 | [listener] 11 | listener_type = "DomainSocket" 12 | # The timeout needs to be smaller than the test client timeout (five seconds) as it is testing 13 | # that the service does not hang for very big values of body or authentication length. 14 | timeout = 3000 # in milliseconds 15 | socket_path = "/tmp/parsec.sock" 16 | 17 | [authenticator] 18 | auth_type = "Direct" 19 | 20 | [[key_manager]] 21 | name = "sqlite-manager" 22 | manager_type = "SQLite" 23 | database_path = "./kim-mappings/sqlite/sqlite-key-info-manager.sqlite3" 24 | 25 | [[provider]] 26 | provider_type = "Pkcs11" 27 | key_info_manager = "sqlite-manager" 28 | library_path = "/usr/local/lib/softhsm/libsofthsm2.so" 29 | user_pin = "hex:1100220033" 30 | -------------------------------------------------------------------------------- /e2e_tests/tests/all_providers/config/tomls/pkcs11_pin_str_fmt_with_hex_word.toml: -------------------------------------------------------------------------------- 1 | [core_settings] 2 | # The CI already timestamps the logs 3 | log_timestamp = false 4 | log_error_details = true 5 | 6 | # The container runs the Parsec service as root, so make sure we disable root 7 | # checks. 8 | allow_root = true 9 | 10 | [listener] 11 | listener_type = "DomainSocket" 12 | # The timeout needs to be smaller than the test client timeout (five seconds) as it is testing 13 | # that the service does not hang for very big values of body or authentication length. 14 | timeout = 3000 # in milliseconds 15 | socket_path = "/tmp/parsec.sock" 16 | 17 | [authenticator] 18 | auth_type = "Direct" 19 | 20 | [[key_manager]] 21 | name = "sqlite-manager" 22 | manager_type = "SQLite" 23 | database_path = "./kim-mappings/sqlite/sqlite-key-info-manager.sqlite3" 24 | 25 | [[provider]] 26 | provider_type = "Pkcs11" 27 | key_info_manager = "sqlite-manager" 28 | library_path = "/usr/local/lib/softhsm/libsofthsm2.so" 29 | user_pin = "str:hex:1100220033" 30 | -------------------------------------------------------------------------------- /e2e_tests/tests/all_providers/config/tomls/pkcs11_software.toml: -------------------------------------------------------------------------------- 1 | [core_settings] 2 | # The CI already timestamps the logs 3 | log_timestamp = false 4 | log_error_details = true 5 | 6 | # The container runs the Parsec service as root, so make sure we disable root 7 | # checks. 8 | allow_root = true 9 | allow_deprecated = true 10 | 11 | [listener] 12 | listener_type = "DomainSocket" 13 | # The timeout needs to be smaller than the test client timeout (five seconds) as it is testing 14 | # that the service does not hang for very big values of body or authentication length. 15 | timeout = 3000 # in milliseconds 16 | socket_path = "/tmp/parsec.sock" 17 | 18 | [authenticator] 19 | auth_type = "Direct" 20 | 21 | [[key_manager]] 22 | name = "sqlite-manager" 23 | manager_type = "SQLite" 24 | sqlite_db_path = "./kim-mappings/sqlite/sqlite-key-info-manager.sqlite3" 25 | 26 | [[provider]] 27 | provider_type = "Pkcs11" 28 | key_info_manager = "sqlite-manager" 29 | library_path = "/usr/local/lib/softhsm/libsofthsm2.so" 30 | user_pin = "123456" 31 | software_public_operations = true 32 | # The slot_number mandatory field is going to replace the following line with a valid number 33 | # slot_number 34 | -------------------------------------------------------------------------------- /e2e_tests/tests/all_providers/config/tomls/reject_deprecated.toml: -------------------------------------------------------------------------------- 1 | [core_settings] 2 | # The CI already timestamps the logs 3 | log_timestamp = false 4 | log_error_details = true 5 | allow_deprecated = false 6 | 7 | [listener] 8 | listener_type = "DomainSocket" 9 | timeout = 200 # in milliseconds 10 | socket_path = "/tmp/parsec.sock" 11 | 12 | [authenticator] 13 | auth_type = "Direct" 14 | 15 | [[key_manager]] 16 | name = "sqlite-manager" 17 | manager_type = "SQLite" 18 | database_path = "./kim-mappings/sqlite/sqlite-key-info-manager.sqlite3" 19 | 20 | [[provider]] 21 | provider_type = "MbedCrypto" 22 | key_info_manager = "sqlite-manager" 23 | -------------------------------------------------------------------------------- /e2e_tests/tests/all_providers/config/tomls/serial_number_only.toml: -------------------------------------------------------------------------------- 1 | [core_settings] 2 | # The CI already timestamps the logs 3 | log_timestamp = false 4 | log_error_details = true 5 | 6 | # The container runs the Parsec service as root, so make sure we disable root 7 | # checks. 8 | allow_root = true 9 | 10 | [listener] 11 | listener_type = "DomainSocket" 12 | # The timeout needs to be smaller than the test client timeout (five seconds) as it is testing 13 | # that the service does not hang for very big values of body or authentication length. 14 | timeout = 3000 # in milliseconds 15 | socket_path = "/tmp/parsec.sock" 16 | 17 | [authenticator] 18 | auth_type = "Direct" 19 | 20 | [[key_manager]] 21 | name = "sqlite-manager" 22 | manager_type = "SQLite" 23 | sqlite_db_path = "./kim-mappings/sqlite/sqlite-key-info-manager.sqlite3" 24 | 25 | [[provider]] 26 | provider_type = "Pkcs11" 27 | key_info_manager = "sqlite-manager" 28 | library_path = "/usr/local/lib/softhsm/libsofthsm2.so" 29 | user_pin = "123456" 30 | # The serial number optional field is going to replace the following line with a valid number 31 | # serial_number 32 | -------------------------------------------------------------------------------- /e2e_tests/tests/all_providers/config/tomls/serial_number_padding.toml: -------------------------------------------------------------------------------- 1 | [core_settings] 2 | # The CI already timestamps the logs 3 | log_timestamp = false 4 | log_error_details = true 5 | 6 | # The container runs the Parsec service as root, so make sure we disable root 7 | # checks. 8 | allow_root = true 9 | 10 | [listener] 11 | listener_type = "DomainSocket" 12 | # The timeout needs to be smaller than the test client timeout (five seconds) as it is testing 13 | # that the service does not hang for very big values of body or authentication length. 14 | timeout = 3000 # in milliseconds 15 | socket_path = "/tmp/parsec.sock" 16 | 17 | [authenticator] 18 | auth_type = "Direct" 19 | 20 | [[key_manager]] 21 | name = "sqlite-manager" 22 | manager_type = "SQLite" 23 | sqlite_db_path = "./kim-mappings/sqlite/sqlite-key-info-manager.sqlite3" 24 | 25 | [[provider]] 26 | provider_type = "Pkcs11" 27 | key_info_manager = "sqlite-manager" 28 | library_path = "/usr/local/lib/softhsm/libsofthsm2.so" 29 | user_pin = "123456" 30 | # The serial number optional field is going to replace the following line with a valid number 31 | # serial_number 32 | -------------------------------------------------------------------------------- /e2e_tests/tests/all_providers/config/tomls/slot_number_only.toml: -------------------------------------------------------------------------------- 1 | [core_settings] 2 | # The CI already timestamps the logs 3 | log_timestamp = false 4 | log_error_details = true 5 | 6 | # The container runs the Parsec service as root, so make sure we disable root 7 | # checks. 8 | allow_root = true 9 | 10 | [listener] 11 | listener_type = "DomainSocket" 12 | # The timeout needs to be smaller than the test client timeout (five seconds) as it is testing 13 | # that the service does not hang for very big values of body or authentication length. 14 | timeout = 3000 # in milliseconds 15 | socket_path = "/tmp/parsec.sock" 16 | 17 | [authenticator] 18 | auth_type = "Direct" 19 | 20 | [[key_manager]] 21 | name = "sqlite-manager" 22 | manager_type = "SQLite" 23 | sqlite_db_path = "./kim-mappings/sqlite/sqlite-key-info-manager.sqlite3" 24 | 25 | [[provider]] 26 | provider_type = "Pkcs11" 27 | key_info_manager = "sqlite-manager" 28 | library_path = "/usr/local/lib/softhsm/libsofthsm2.so" 29 | user_pin = "123456" 30 | # The slot_number optional field is going to replace the following line with a valid number 31 | # slot_number 32 | -------------------------------------------------------------------------------- /e2e_tests/tests/all_providers/config/tomls/slot_numbers_mismatch.toml: -------------------------------------------------------------------------------- 1 | [core_settings] 2 | # The CI already timestamps the logs 3 | log_timestamp = false 4 | log_error_details = true 5 | 6 | # The container runs the Parsec service as root, so make sure we disable root 7 | # checks. 8 | allow_root = true 9 | 10 | [listener] 11 | listener_type = "DomainSocket" 12 | # The timeout needs to be smaller than the test client timeout (five seconds) as it is testing 13 | # that the service does not hang for very big values of body or authentication length. 14 | timeout = 3000 # in milliseconds 15 | socket_path = "/tmp/parsec.sock" 16 | 17 | [authenticator] 18 | auth_type = "Direct" 19 | 20 | [[key_manager]] 21 | name = "sqlite-manager" 22 | manager_type = "SQLite" 23 | sqlite_db_path = "./kim-mappings/sqlite/sqlite-key-info-manager.sqlite3" 24 | 25 | [[provider]] 26 | provider_type = "Pkcs11" 27 | key_info_manager = "sqlite-manager" 28 | library_path = "/usr/local/lib/softhsm/libsofthsm2.so" 29 | user_pin = "123456" 30 | # A dummy slot_number 31 | slot_number=12345678 32 | # The serial number optional field is going to replace the following line with a valid number 33 | # serial_number 34 | -------------------------------------------------------------------------------- /e2e_tests/tests/all_providers/config/tomls/ts_pkcs11_cross.toml: -------------------------------------------------------------------------------- 1 | [core_settings] 2 | # The CI already timestamps the logs 3 | log_timestamp = false 4 | log_error_details = true 5 | 6 | # The container runs the Parsec service as root, so make sure we disable root 7 | # checks. 8 | allow_root = true 9 | 10 | [listener] 11 | listener_type = "DomainSocket" 12 | # The timeout needs to be smaller than the test client timeout (five seconds) as it is testing 13 | # that the service does not hang for very big values of body or authentication length. 14 | timeout = 3000 # in milliseconds 15 | socket_path = "/tmp/parsec.sock" 16 | 17 | [authenticator] 18 | auth_type = "Direct" 19 | 20 | [[key_manager]] 21 | name = "sqlite-manager" 22 | manager_type = "SQLite" 23 | sqlite_db_path = "./kim-mappings/sqlite/sqlite-key-info-manager.sqlite3" 24 | 25 | [[provider]] 26 | provider_type = "TrustedService" 27 | key_info_manager = "sqlite-manager" 28 | 29 | [[provider]] 30 | provider_type = "Pkcs11" 31 | key_info_manager = "sqlite-manager" 32 | library_path = "/usr/local/lib/softhsm/libsofthsm2.so" 33 | user_pin = "123456" 34 | software_public_operations = true 35 | # The slot_number mandatory field is going to replace the following line with a valid number 36 | # slot_number 37 | -------------------------------------------------------------------------------- /e2e_tests/tests/all_providers/config/tomls/various_field_check.toml: -------------------------------------------------------------------------------- 1 | [core_settings] 2 | allow_root = true 3 | thread_pool_size = 2 4 | idle_listener_sleep_duration = 12 5 | log_level = "trace" 6 | log_timestamp = true 7 | # 1 KiB max for requests 8 | body_len_limit = 1024 9 | log_error_details = true 10 | # 1 KiB max for responses 11 | buffer_size_limit = 1024 12 | 13 | [listener] 14 | listener_type = "DomainSocket" 15 | timeout = 202 16 | socket_path = "/tmp/toto.sock" 17 | 18 | [authenticator] 19 | auth_type = "Direct" 20 | 21 | [[key_manager]] 22 | name = "I-want-to-speak-to-the-manager" 23 | manager_type = "SQLite" 24 | sqlite_db_path = "./kim-mappings/sqlite/sqlite-key-info-manager.sqlite3" 25 | 26 | [[provider]] 27 | provider_type = "MbedCrypto" 28 | key_info_manager = "I-want-to-speak-to-the-manager" 29 | -------------------------------------------------------------------------------- /e2e_tests/tests/all_providers/logging.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use e2e_tests::TestClient; 5 | use parsec_client::core::interface::requests::ProviderId; 6 | use std::fs; 7 | 8 | // Ignore this test case for manual test runs. This is executed on the CI after the parsec service logs are 9 | // redirected to a log file (parsec_logging.txt) for testing purpose. 10 | #[ignore] 11 | #[test] 12 | fn check_log_source() { 13 | let mut client = TestClient::new(); 14 | 15 | // Perform key generation and encryption to generate expected logs 16 | client.set_provider(ProviderId::MbedCrypto); 17 | client.set_default_auth(Some("logging".to_string())); 18 | client 19 | .generate_rsa_sign_key(String::from("test_key")) 20 | .unwrap(); 21 | let _ = client 22 | .asymmetric_encrypt_message_with_rsapkcs1v15(String::from("test_key"), vec![0xa5; 16]) 23 | .unwrap_err(); 24 | 25 | // Read parsec log file contents 26 | let logs: String = 27 | fs::read_to_string("/tmp/parsec/parsec_logging.txt").expect("Failure in reading the file"); 28 | 29 | // Ensure logs contains INFO, WARN and ERROR message arising from different modules and crates 30 | assert!(logs.contains( 31 | "[INFO parsec_service::front::front_end] New request received without authentication" 32 | )); 33 | assert!(logs 34 | .contains("[WARN parsec_service::key_info_managers::on_disk_manager] Saving Key Triple")); 35 | assert!(logs.contains( 36 | "[ERROR psa_crypto::types::key] Key attributes do not permit encrypting messages." 37 | )); 38 | } 39 | -------------------------------------------------------------------------------- /e2e_tests/tests/all_providers/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | mod config; 5 | mod cross; 6 | mod logging; 7 | mod multitenancy; 8 | mod normal; 9 | -------------------------------------------------------------------------------- /e2e_tests/tests/all_providers/multitenancy.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | use e2e_tests::TestClient; 4 | use parsec_client::core::interface::requests::{ProviderId, ResponseStatus}; 5 | 6 | // These tests are executed by different users in the following order: 7 | // 1. client1_before is executed as parsec-client-1 8 | // 2. client2 is executed as parsec-client-2 9 | // 3. client1_after is executed as parsec-client-1 10 | // 11 | // They are executed against all possible authenticators in Parsec. 12 | // 13 | // client1 will be configured as an admin. 14 | 15 | fn get_key_name(provider: &ProviderId) -> String { 16 | format!("{}-multitenant", provider) 17 | } 18 | 19 | #[test] 20 | fn client1_before() { 21 | // Create one key on each provider 22 | let mut client = TestClient::new(); 23 | client.do_not_destroy_keys(); 24 | client.set_default_auth(Some("client1".to_string())); 25 | 26 | for provider in [ProviderId::MbedCrypto, ProviderId::Pkcs11, ProviderId::Tpm].iter() { 27 | client.set_provider(*provider); 28 | client 29 | .generate_rsa_sign_key(get_key_name(provider)) 30 | .unwrap(); 31 | } 32 | 33 | let clients = client.list_clients().unwrap(); 34 | assert_eq!(clients.len(), 1); 35 | } 36 | 37 | #[test] 38 | fn client2() { 39 | let mut client = TestClient::new(); 40 | client.do_not_destroy_keys(); 41 | client.set_default_auth(Some("client2".to_string())); 42 | 43 | // Try to list those keys 44 | let keys = client.list_keys().unwrap(); 45 | assert!(keys.is_empty()); 46 | 47 | for provider in [ProviderId::MbedCrypto, ProviderId::Pkcs11, ProviderId::Tpm].iter() { 48 | client.set_provider(*provider); 49 | assert_eq!( 50 | client 51 | .export_public_key(get_key_name(provider)) 52 | .unwrap_err(), 53 | ResponseStatus::PsaErrorDoesNotExist 54 | ); 55 | assert_eq!( 56 | client.destroy_key(get_key_name(provider)).unwrap_err(), 57 | ResponseStatus::PsaErrorDoesNotExist 58 | ); 59 | client 60 | .generate_rsa_sign_key(get_key_name(provider)) 61 | .unwrap(); 62 | client.destroy_key(get_key_name(provider)).unwrap(); 63 | } 64 | 65 | assert_eq!( 66 | client.list_clients().unwrap_err(), 67 | ResponseStatus::AdminOperation 68 | ); 69 | assert_eq!( 70 | client.delete_client("toto".to_string()).unwrap_err(), 71 | ResponseStatus::AdminOperation 72 | ); 73 | client 74 | .generate_rsa_sign_key("client2-key".to_string()) 75 | .unwrap(); 76 | } 77 | 78 | #[test] 79 | fn client1_after() { 80 | let mut client = TestClient::new(); 81 | client.do_not_destroy_keys(); 82 | client.set_default_auth(Some("client1".to_string())); 83 | 84 | // Verify all keys are still there and can be used 85 | let keys = client.list_keys().unwrap(); 86 | assert_eq!(keys.len(), 3); 87 | 88 | // Destroy the keys 89 | for provider in [ProviderId::MbedCrypto, ProviderId::Pkcs11, ProviderId::Tpm].iter() { 90 | client.set_provider(*provider); 91 | client.destroy_key(get_key_name(provider)).unwrap(); 92 | } 93 | 94 | client 95 | .generate_rsa_sign_key("client1-key".to_string()) 96 | .unwrap(); 97 | let mut clients = client.list_clients().unwrap(); 98 | assert_eq!(clients.len(), 2); 99 | client.delete_client(clients.remove(0)).unwrap(); 100 | let keys = client.list_keys().unwrap(); 101 | assert_eq!(keys.len(), 0); 102 | 103 | let mut clients = client.list_clients().unwrap(); 104 | assert_eq!(clients.len(), 1); 105 | client.delete_client(clients.remove(0)).unwrap(); 106 | let keys = client.list_keys().unwrap(); 107 | assert_eq!(keys.len(), 0); 108 | } 109 | -------------------------------------------------------------------------------- /e2e_tests/tests/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | #![deny( 5 | nonstandard_style, 6 | dead_code, 7 | improper_ctypes, 8 | non_shorthand_field_patterns, 9 | no_mangle_generic_items, 10 | overflowing_literals, 11 | path_statements, 12 | patterns_in_fns_without_body, 13 | unconditional_recursion, 14 | unused, 15 | unused_allocation, 16 | unused_comparisons, 17 | unused_parens, 18 | while_true, 19 | missing_debug_implementations, 20 | trivial_casts, 21 | trivial_numeric_casts, 22 | unused_extern_crates, 23 | unused_import_braces, 24 | unused_qualifications, 25 | unused_results, 26 | missing_copy_implementations 27 | )] 28 | // This one is hard to avoid. 29 | #![allow(clippy::multiple_crate_versions)] 30 | 31 | #[cfg(feature = "all-providers")] 32 | mod all_providers; 33 | #[cfg(not(feature = "all-providers"))] 34 | mod per_provider; 35 | -------------------------------------------------------------------------------- /e2e_tests/tests/per_provider/key_mappings.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use e2e_tests::TestClient; 5 | use parsec_client::core::interface::requests::Result; 6 | use parsec_client::core::interface::requests::{Opcode, ResponseStatus}; 7 | 8 | const HASH: [u8; 32] = [ 9 | 0x69, 0x3E, 0xDB, 0x1B, 0x22, 0x79, 0x03, 0xF4, 0xC0, 0xBF, 0xD6, 0x91, 0x76, 0x37, 0x84, 0xA2, 10 | 0x94, 0x8E, 0x92, 0x50, 0x35, 0xC2, 0x8C, 0x5C, 0x3C, 0xCA, 0xFE, 0x18, 0xE8, 0x81, 0x37, 0x78, 11 | ]; 12 | 13 | const PLAINTEXT_MESSAGE: [u8; 32] = [ 14 | 0x69, 0x3E, 0xDB, 0x1B, 0x22, 0x79, 0x03, 0xF4, 0xC0, 0xBF, 0xD6, 0x91, 0x76, 0x37, 0x84, 0xA2, 15 | 0x94, 0x8E, 0x92, 0x50, 0x35, 0xC2, 0x8C, 0x5C, 0x3C, 0xCA, 0xFE, 0x18, 0xE8, 0x81, 0x37, 0x78, 16 | ]; 17 | 18 | // This test tries to use the keys created in the Docker image via the generate-keys.sh script. 19 | // Each provider has a "ecc" and "rsa" key created by the Parsec Tool. 20 | // The ci.sh script also adds fake mappings (mappings which do not link to an existing key) in all 21 | // providers except the TPM one (as for this provider the mapping IS the key). 22 | 23 | #[test] 24 | fn use_and_check() -> Result<()> { 25 | let mut client = TestClient::new(); 26 | 27 | client.set_default_auth(Some(String::from("parsec-tool"))); 28 | 29 | let keys = client.list_keys()?; 30 | assert!(!keys.is_empty()); 31 | 32 | for key in keys { 33 | if key.name.contains("rsa") { 34 | let ciphertext = client 35 | .asymmetric_encrypt_message_with_rsapkcs1v15( 36 | key.name.clone(), 37 | PLAINTEXT_MESSAGE.to_vec(), 38 | ) 39 | .unwrap(); 40 | let plaintext = client 41 | .asymmetric_decrypt_message_with_rsapkcs1v15(key.name.clone(), ciphertext) 42 | .unwrap(); 43 | assert_eq!(PLAINTEXT_MESSAGE.to_vec(), plaintext); 44 | } else if key.name.contains("ecc") { 45 | let signature = client.sign_with_ecdsa_sha256(key.name.clone(), HASH.to_vec())?; 46 | client.verify_with_ecdsa_sha256(key.name.clone(), HASH.to_vec(), signature)?; 47 | } else { 48 | // If another key than "ecc" or "rsa" is read, it means that the fake mapping was not 49 | // deleted by the provider and this is an error. 50 | panic!( 51 | "The key {} should have been deleted as a fake mapping was created for it.", 52 | key.name 53 | ); 54 | } 55 | 56 | if client.is_operation_supported(Opcode::PsaExportKey) { 57 | assert_eq!( 58 | client.export_key(key.name.clone()).unwrap_err(), 59 | ResponseStatus::PsaErrorNotPermitted 60 | ); 61 | } 62 | } 63 | 64 | Ok(()) 65 | } 66 | -------------------------------------------------------------------------------- /e2e_tests/tests/per_provider/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | mod key_mappings; 4 | mod normal_tests; 5 | mod stress_test; 6 | #[cfg(feature = "tpm-provider")] 7 | mod tpm_reset; 8 | -------------------------------------------------------------------------------- /e2e_tests/tests/per_provider/normal_tests/auth.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | use e2e_tests::auto_test_keyname; 4 | use e2e_tests::TestClient; 5 | use parsec_client::core::interface::requests::{Opcode, ResponseStatus, Result}; 6 | 7 | #[test] 8 | fn two_auths_same_key_name() -> Result<()> { 9 | let key_name = auto_test_keyname!(); 10 | let mut client = TestClient::new(); 11 | let auth1 = String::from("first_client"); 12 | let auth2 = String::from("second_client"); 13 | 14 | if !client.is_operation_supported(Opcode::PsaGenerateKey) { 15 | return Ok(()); 16 | } 17 | 18 | client.set_default_auth(Some(auth1)); 19 | #[cfg(not(feature = "cryptoauthlib-provider"))] 20 | client.generate_rsa_sign_key(key_name.clone())?; 21 | #[cfg(feature = "cryptoauthlib-provider")] 22 | client.generate_ecc_key_pair_secpr1_ecdsa_sha256(key_name.clone())?; 23 | 24 | client.set_default_auth(Some(auth2)); 25 | #[cfg(not(feature = "cryptoauthlib-provider"))] 26 | let result = client.generate_rsa_sign_key(key_name); 27 | #[cfg(feature = "cryptoauthlib-provider")] 28 | let result = client.generate_ecc_key_pair_secpr1_ecdsa_sha256(key_name); 29 | 30 | result 31 | } 32 | 33 | #[test] 34 | fn delete_wrong_key() -> Result<()> { 35 | let key_name = auto_test_keyname!(); 36 | let mut client = TestClient::new(); 37 | let auth1 = String::from("first_client"); 38 | let auth2 = String::from("second_client"); 39 | 40 | if !client.is_operation_supported(Opcode::PsaGenerateKey) { 41 | return Ok(()); 42 | } 43 | 44 | client.set_default_auth(Some(auth1)); 45 | #[cfg(not(feature = "cryptoauthlib-provider"))] 46 | client.generate_rsa_sign_key(key_name.clone())?; 47 | #[cfg(feature = "cryptoauthlib-provider")] 48 | client.generate_ecc_key_pair_secpr1_ecdsa_sha256(key_name.clone())?; 49 | 50 | client.set_default_auth(Some(auth2)); 51 | let status = client 52 | .destroy_key(key_name) 53 | .expect_err("Destroying key should have failed"); 54 | assert_eq!(status, ResponseStatus::PsaErrorDoesNotExist); 55 | 56 | Ok(()) 57 | } 58 | -------------------------------------------------------------------------------- /e2e_tests/tests/per_provider/normal_tests/generate_random.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | use e2e_tests::TestClient; 4 | use parsec_client::core::interface::requests::{Opcode, ResponseStatus}; 5 | 6 | #[test] 7 | fn generate_random_not_supported() { 8 | let mut client = TestClient::new(); 9 | if !client.is_operation_supported(Opcode::PsaGenerateRandom) { 10 | assert_eq!( 11 | client.generate_bytes(15,).unwrap_err(), 12 | ResponseStatus::PsaErrorNotSupported 13 | ); 14 | } 15 | } 16 | 17 | #[test] 18 | fn simple_generate_random() { 19 | let mut client = TestClient::new(); 20 | 21 | if !client.is_operation_supported(Opcode::PsaGenerateRandom) { 22 | return; 23 | } 24 | 25 | // Less than one in ~35 billion chance of collision. Should be good enough for our testing. 26 | const NBYTES: usize = 35; 27 | let random_bytes_a = client.generate_bytes(NBYTES).unwrap(); 28 | let random_bytes_b = client.generate_bytes(NBYTES).unwrap(); 29 | 30 | assert_eq!(random_bytes_a.len(), NBYTES); 31 | assert_eq!(random_bytes_b.len(), NBYTES); 32 | 33 | for (a, b) in random_bytes_a.iter().zip(random_bytes_b.iter()) { 34 | if *a != *b { 35 | return; 36 | } 37 | } 38 | 39 | panic!( 40 | "Two vectors of {} randomly generated bytes were equal!", 41 | NBYTES 42 | ); 43 | } 44 | 45 | #[test] 46 | fn generate_zero_bytes() { 47 | let mut client = TestClient::new(); 48 | 49 | if !client.is_operation_supported(Opcode::PsaGenerateRandom) { 50 | return; 51 | } 52 | 53 | const NBYTES: usize = 0; 54 | let random_bytes = client.generate_bytes(NBYTES).unwrap(); 55 | 56 | assert_eq!(random_bytes, Vec::::new()); 57 | } 58 | -------------------------------------------------------------------------------- /e2e_tests/tests/per_provider/normal_tests/hash.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | use e2e_tests::TestClient; 4 | use parsec_client::core::interface::operations::psa_algorithm::Hash; 5 | use parsec_client::core::interface::requests::{Opcode, ResponseStatus, Result}; 6 | 7 | const MESSAGE: [u8; 14] = [ 8 | 0x49, 0x20, 0x61, 0x6d, 0x20, 0x61, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 9 | ]; 10 | const SHA_256: [u8; 32] = [ 11 | 0x0d, 0xc4, 0xbc, 0x13, 0xfd, 0x91, 0x74, 0x52, 0x92, 0x24, 0xc3, 0x8e, 0x0e, 0xe0, 0x75, 0xfa, 12 | 0x9e, 0xd8, 0x0b, 0x78, 0x47, 0xe6, 0xae, 0xa7, 0x6a, 0xe9, 0x8c, 0xf9, 0xdd, 0xd9, 0x26, 0x69, 13 | ]; 14 | #[cfg(not(feature = "cryptoauthlib-provider"))] 15 | const RIPE_MD160: [u8; 20] = [ 16 | 0xa6, 0xf1, 0xa8, 0xf5, 0x26, 0x04, 0x69, 0xb3, 0x67, 0xa3, 0xae, 0xc6, 0x9f, 0x73, 0x47, 0x9b, 17 | 0xb7, 0xbd, 0x02, 0xb8, 18 | ]; 19 | #[cfg(not(feature = "cryptoauthlib-provider"))] 20 | const SHA_512: [u8; 64] = [ 21 | 0x54, 0x1f, 0x9e, 0x85, 0xd4, 0xe6, 0xc2, 0x36, 0xf9, 0xb5, 0xef, 0x2e, 0x6d, 0x27, 0xd4, 0x97, 22 | 0x56, 0xda, 0x00, 0xb2, 0x6e, 0xe2, 0x6f, 0xc8, 0x6a, 0x30, 0x47, 0xd3, 0x7f, 0x09, 0xbd, 0xe9, 23 | 0x0a, 0x99, 0x14, 0xf7, 0x3d, 0xf6, 0xe7, 0x01, 0x1c, 0x97, 0x0b, 0x74, 0x84, 0x26, 0xfa, 0x0c, 24 | 0x84, 0x4c, 0xc3, 0xa1, 0x8f, 0x9d, 0x5b, 0x74, 0x01, 0xa4, 0x66, 0x8f, 0x75, 0x73, 0x65, 0xc5, 25 | ]; 26 | 27 | #[test] 28 | fn hash_not_supported() { 29 | let mut client = TestClient::new(); 30 | if !client.is_operation_supported(Opcode::PsaHashCompute) { 31 | assert_eq!( 32 | client.hash_compute(Hash::Sha256, &[],).unwrap_err(), 33 | ResponseStatus::PsaErrorNotSupported 34 | ); 35 | } 36 | 37 | if !client.is_operation_supported(Opcode::PsaHashCompare) { 38 | assert_eq!( 39 | client.hash_compare(Hash::Sha256, &[], &[]).unwrap_err(), 40 | ResponseStatus::PsaErrorNotSupported 41 | ); 42 | } 43 | } 44 | 45 | #[test] 46 | fn hash_compute_sha256() { 47 | let mut client = TestClient::new(); 48 | if !client.is_operation_supported(Opcode::PsaHashCompute) { 49 | return; 50 | } 51 | 52 | let hash = client.hash_compute(Hash::Sha256, &MESSAGE).unwrap(); 53 | assert_eq!(&SHA_256[..], hash.as_slice()) 54 | } 55 | 56 | #[cfg(not(feature = "cryptoauthlib-provider"))] 57 | #[test] 58 | fn hash_compute_ripe_md160() { 59 | let mut client = TestClient::new(); 60 | if !client.is_operation_supported(Opcode::PsaHashCompute) { 61 | return; 62 | } 63 | 64 | let hash = client.hash_compute(Hash::Ripemd160, &MESSAGE).unwrap(); 65 | assert_eq!(&RIPE_MD160[..], hash.as_slice()); 66 | } 67 | 68 | #[cfg(not(feature = "cryptoauthlib-provider"))] 69 | #[test] 70 | fn hash_compute_sha512() { 71 | let mut client = TestClient::new(); 72 | if !client.is_operation_supported(Opcode::PsaHashCompute) { 73 | return; 74 | } 75 | 76 | let hash = client.hash_compute(Hash::Sha512, &MESSAGE).unwrap(); 77 | assert_eq!(&SHA_512[..], hash.as_slice()); 78 | } 79 | 80 | #[test] 81 | fn hash_compare_sha256() -> Result<()> { 82 | let mut client = TestClient::new(); 83 | if !client.is_operation_supported(Opcode::PsaHashCompare) { 84 | return Ok(()); 85 | } 86 | 87 | client.hash_compare(Hash::Sha256, &MESSAGE, &SHA_256) 88 | } 89 | 90 | #[cfg(not(feature = "cryptoauthlib-provider"))] 91 | #[test] 92 | fn hash_compare_ripe_md160() -> Result<()> { 93 | let mut client = TestClient::new(); 94 | if !client.is_operation_supported(Opcode::PsaHashCompare) { 95 | return Ok(()); 96 | } 97 | 98 | client.hash_compare(Hash::Ripemd160, &MESSAGE, &RIPE_MD160) 99 | } 100 | 101 | #[cfg(not(feature = "cryptoauthlib-provider"))] 102 | #[test] 103 | fn hash_compare_sha512() -> Result<()> { 104 | let mut client = TestClient::new(); 105 | if !client.is_operation_supported(Opcode::PsaHashCompare) { 106 | return Ok(()); 107 | } 108 | 109 | client.hash_compare(Hash::Sha512, &MESSAGE, &SHA_512) 110 | } 111 | 112 | #[test] 113 | fn hash_compare_false() { 114 | let mut client = TestClient::new(); 115 | if !client.is_operation_supported(Opcode::PsaHashCompare) { 116 | return; 117 | } 118 | 119 | let _ = client 120 | .hash_compare(Hash::Sha512, &MESSAGE, &SHA_256) 121 | .unwrap_err(); 122 | } 123 | -------------------------------------------------------------------------------- /e2e_tests/tests/per_provider/normal_tests/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | mod aead; 4 | mod asym_encryption; 5 | mod asym_sign_verify; 6 | mod auth; 7 | mod basic; 8 | mod capability_discovery; 9 | mod cipher; 10 | mod create_destroy_key; 11 | mod export_key; 12 | mod export_public_key; 13 | mod generate_random; 14 | mod hash; 15 | mod import_key; 16 | mod key_agreement; 17 | mod key_attestation; 18 | mod key_attributes; 19 | mod ping; 20 | -------------------------------------------------------------------------------- /e2e_tests/tests/per_provider/normal_tests/ping.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | use e2e_tests::RequestClient; 4 | use e2e_tests::TestClient; 5 | use parsec_client::core::interface::requests::request::{Request, RequestAuth, RequestBody}; 6 | use parsec_client::core::interface::requests::Opcode; 7 | use parsec_client::core::interface::requests::ProviderId; 8 | use parsec_client::core::interface::requests::ResponseStatus; 9 | use parsec_client::core::interface::requests::Result; 10 | use parsec_client::core::ipc_handler::unix_socket; 11 | use std::env; 12 | use std::time::Duration; 13 | 14 | #[test] 15 | fn test_ping() -> Result<()> { 16 | let mut client = TestClient::new(); 17 | let version = client.ping()?; 18 | assert_eq!(version.0, 1); 19 | assert_eq!(version.1, 0); 20 | 21 | Ok(()) 22 | } 23 | 24 | #[test] 25 | fn mangled_ping() { 26 | let socket_path = env::var("PARSEC_SERVICE_ENDPOINT") 27 | .unwrap_or_else(|_| "/tmp/parsec.sock".into()) 28 | .replace("unix:", ""); 29 | let client = RequestClient { 30 | ipc_handler: Box::from( 31 | unix_socket::Handler::new(socket_path.into(), Some(Duration::from_secs(1))).unwrap(), 32 | ), 33 | ..Default::default() 34 | }; 35 | let mut req = Request::new(); 36 | req.header.provider = ProviderId::Core; 37 | req.header.opcode = Opcode::Ping; 38 | req.auth = RequestAuth::new(Vec::from("root")); 39 | 40 | req.body = RequestBody::_from_bytes(vec![0x11, 0x22, 0x33, 0x44, 0x55]); 41 | 42 | let resp = client 43 | .process_request(req) 44 | .expect("Failed to read Response"); 45 | assert_eq!(resp.header.status, ResponseStatus::DeserializingBodyFailed); 46 | } 47 | -------------------------------------------------------------------------------- /e2e_tests/tests/per_provider/stress_test.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | use e2e_tests::stress::{StressClient, StressTestConfig}; 4 | use std::time::Duration; 5 | 6 | #[test] 7 | fn stress_test() { 8 | let config = StressTestConfig { 9 | no_threads: num_cpus::get(), 10 | req_per_thread: 250, 11 | req_interval: Some(Duration::from_millis(10)), 12 | req_interval_deviation_millis: Some(4), 13 | check_interval: Some(Duration::from_millis(500)), 14 | }; 15 | 16 | StressClient::execute(config); 17 | } 18 | -------------------------------------------------------------------------------- /e2e_tests/tests/per_provider/tpm_reset.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | // These tests track a potential regression where the TPM provider 5 | // was unable to handle stored keys after a TPM reset. 6 | // 7 | // `before_tpm_reset` creates keys that should be usable post-TPM-reset, 8 | // in `after_tpm_reset`. 9 | // 10 | // See: https://github.com/parallaxsecond/parsec/issues/504 11 | use e2e_tests::TestClient; 12 | 13 | const RSA_KEY_NAME: &str = "tpm-reset-rsa"; 14 | const ECC_KEY_NAME: &str = "tpm-reset-ecc"; 15 | 16 | #[test] 17 | fn before_tpm_reset() { 18 | let mut client = TestClient::new(); 19 | client.do_not_destroy_keys(); 20 | 21 | let rsa_key_name = String::from(RSA_KEY_NAME); 22 | let ecc_key_name = String::from(ECC_KEY_NAME); 23 | 24 | client.generate_rsa_sign_key(rsa_key_name).unwrap(); 25 | client 26 | .generate_ecc_key_pair_secpr1_ecdsa_sha256(ecc_key_name) 27 | .unwrap(); 28 | } 29 | 30 | #[test] 31 | fn after_tpm_reset() { 32 | let mut client = TestClient::new(); 33 | 34 | let rsa_key_name = String::from(RSA_KEY_NAME); 35 | let ecc_key_name = String::from(ECC_KEY_NAME); 36 | 37 | let _ = client 38 | .sign_with_rsa_sha256(rsa_key_name, vec![0xff; 32]) 39 | .unwrap(); 40 | let _ = client 41 | .sign_with_ecdsa_sha256(ecc_key_name, vec![0xff; 32]) 42 | .unwrap(); 43 | } 44 | -------------------------------------------------------------------------------- /fuzz.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2020 Contributors to the Parsec project. 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | FUZZ_CONTAINER_NAME=parsec_fuzzer 7 | CLEANUP_CONTAINER_NAME=parsec_fuzzer_cleanup 8 | 9 | set -e 10 | 11 | if [[ "$1" == "run" ]] 12 | then 13 | # Set up fuzz folder 14 | docker run --rm -v $(pwd):/parsec -w /parsec/fuzz --name $CLEANUP_CONTAINER_NAME ghcr.io/parallaxsecond/parsec-service-test-all ./cleanup.sh 15 | # A copy of the config file is used because the file is modified during the run 16 | cp fuzz/config.toml fuzz/run_config.toml 17 | 18 | # Stop previous container and run fuzzer 19 | docker kill $FUZZ_CONTAINER_NAME || true 20 | sleep 5s 21 | docker run -d --rm -v $(pwd):/parsec -w /parsec/fuzz --name $FUZZ_CONTAINER_NAME ghcr.io/parallaxsecond/parsec-service-test-all ./run_fuzz.sh 22 | elif [[ "$1" == "stop" ]] 23 | then 24 | docker kill $FUZZ_CONTAINER_NAME 25 | elif [[ "$1" == "follow" ]] 26 | then 27 | docker logs -f --tail 100 $FUZZ_CONTAINER_NAME 28 | elif [[ "$1" == "clean" ]] 29 | then 30 | # Cleanup is done via Docker because on some systems ACL settings prevent the user who 31 | # created a container from removing the files created by said container. Another one 32 | # is needed to do the cleanup. 33 | docker run -d --rm -v $(pwd):/parsec -w /parsec/fuzz --name $CLEANUP_CONTAINER_NAME ghcr.io/parallaxsecond/parsec-service-test-all ./cleanup.sh 34 | elif [[ "$1" == "erase" ]] 35 | then 36 | docker run -d --rm -v $(pwd):/parsec -w /parsec/fuzz -e "ERASE=true" --name $CLEANUP_CONTAINER_NAME ghcr.io/parallaxsecond/parsec-service-test-all ./cleanup.sh 37 | elif [[ "$1" == "test" ]] 38 | then 39 | if [[ -z "$CONTAINER_TAG" ]] 40 | then 41 | CONTAINER_TAG=ghcr.io/parallaxsecond/parsec-service-test-all 42 | fi 43 | # A copy of the config file is used because the file is modified during the run 44 | cp fuzz/config.toml fuzz/run_config.toml 45 | # Run the fuzzer in test mode 46 | docker run --rm -v $(pwd):/parsec -w /parsec/fuzz --name $FUZZ_CONTAINER_NAME $CONTAINER_TAG ./run_fuzz.sh test 47 | else 48 | echo "usage: ./fuzz.sh [COMMAND] 49 | 50 | Commands: 51 | 'run' - builds the fuzzing container and runs the fuzzer 52 | 'stop' - stops the fuzzing container 53 | 'follow' - prints and follows the log output of the fuzzing container 54 | 'clean' - clean up the fuzzing environment (does not remove artifacts or the fuzz corpus) 55 | 'erase' - fully clean the fuzzing environment - WARNING: this will remove all the results of previous runs" 56 | fi 57 | -------------------------------------------------------------------------------- /fuzz/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | target 3 | corpus 4 | artifacts 5 | *.log 6 | run_config.toml 7 | NVChip 8 | init_corpus 9 | -------------------------------------------------------------------------------- /fuzz/Cargo.toml: -------------------------------------------------------------------------------- 1 | 2 | [package] 3 | name = "parsec-fuzz" 4 | version = "0.0.0" 5 | authors = ["Ionut Mihalcea ", 6 | "Hugues de Valon "] 7 | publish = false 8 | edition = "2018" 9 | 10 | [package.metadata] 11 | cargo-fuzz = true 12 | 13 | [dependencies] 14 | parsec-service = { path = "..", features = ["mbed-crypto-provider", "pkcs11-provider", "tpm-provider", "direct-authenticator"] } 15 | libfuzzer-sys = "0.3.0" 16 | flexi_logger = "0.14.5" 17 | log = "0.4.8" 18 | toml = "0.8.0" 19 | lazy_static = "1.4.0" 20 | arbitrary = { version = "0.4.0", features = ["derive"] } 21 | 22 | [build-dependencies] 23 | parsec-client = { version = "0.16.0", features = ["testing", "spiffe-auth"] } 24 | 25 | # Prevent this from interfering with workspaces 26 | [workspace] 27 | members = ["."] 28 | 29 | [[bin]] 30 | name = "fuzz_service" 31 | path = "fuzz_targets/fuzz_service.rs" 32 | 33 | [features] 34 | mbed-crypto-provider = [] 35 | tpm-provider = [] 36 | pkcs11-provider = [] 37 | -------------------------------------------------------------------------------- /fuzz/cleanup.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2020 Contributors to the Parsec project. 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | rm -f NVChip *log run_config.toml *psa_its 7 | rm -rf mappings 8 | if [[ "$ERASE" == "true" ]] 9 | then 10 | rm -rf artifacts corpus 11 | fi 12 | -------------------------------------------------------------------------------- /fuzz/config.toml: -------------------------------------------------------------------------------- 1 | [core_settings] 2 | 3 | [listener] 4 | listener_type = "DomainSocket" 5 | timeout = 200 # in milliseconds 6 | socket_path = "/tmp/parsec.sock" 7 | 8 | [authenticator] 9 | auth_type = "Direct" 10 | 11 | [[key_manager]] 12 | name = "on-disk-manager" 13 | manager_type = "OnDisk" 14 | store_path = "./mappings" 15 | 16 | # [[provider]] 17 | # provider_type = "MbedCryptoProvider" 18 | # key_info_manager = "on-disk-manager" 19 | 20 | [[provider]] 21 | provider_type = "Tpm" 22 | key_info_manager = "on-disk-manager" 23 | tcti = "mssim" 24 | owner_hierarchy_auth = "" 25 | 26 | # [[provider]] 27 | # provider_type = "Pkcs11Provider" 28 | # key_info_manager = "on-disk-manager" 29 | # library_path = "/usr/local/lib/softhsm/libsofthsm2.so" 30 | # user_pin = "123456" 31 | # The slot_number mandatory field is going to be added by the find_slot_number.sh script 32 | # to the last line of this file in the form: 33 | # slot_number = 123456 34 | -------------------------------------------------------------------------------- /fuzz/fuzz_targets/fuzz_service.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #![no_main] 4 | 5 | use arbitrary::Arbitrary; 6 | use lazy_static::lazy_static; 7 | use libfuzzer_sys::fuzz_target; 8 | use parsec_service::front::{front_end::FrontEndHandler, listener::Connection}; 9 | use parsec_service::utils::{config::ServiceConfig, ServiceBuilder}; 10 | use std::cmp; 11 | use std::io::{Read, Result, Write}; 12 | 13 | lazy_static! { 14 | static ref FRONT_END_HANDLER: FrontEndHandler = { 15 | log_setup(); 16 | let config_file = String::from("./run_config.toml"); 17 | let config_file = 18 | std::fs::read_to_string(config_file).expect("Failed to read configuration file"); 19 | let config: ServiceConfig = 20 | toml::from_str(&config_file).expect("Failed to parse service configuration"); 21 | ServiceBuilder::build_service(&config).expect("Failed to initialize service") 22 | }; 23 | } 24 | 25 | #[derive(Arbitrary, Debug)] 26 | struct MockStream(Vec); 27 | 28 | impl Read for MockStream { 29 | fn read(&mut self, buf: &mut [u8]) -> Result { 30 | if self.0.is_empty() { 31 | return Ok(0); 32 | } 33 | let n = cmp::min(buf.len(), self.0.len()); 34 | for (idx, val) in self.0.drain(0..n).enumerate() { 35 | buf[idx] = val; 36 | } 37 | 38 | Ok(n) 39 | } 40 | } 41 | 42 | impl Write for MockStream { 43 | fn write(&mut self, buf: &[u8]) -> Result { 44 | Ok(buf.len()) 45 | } 46 | 47 | fn flush(&mut self) -> Result<()> { 48 | Ok(()) 49 | } 50 | } 51 | 52 | fuzz_target!(|stream: MockStream| { 53 | FRONT_END_HANDLER.handle_request(Connection { 54 | stream: Box::from(stream), 55 | metadata: None, 56 | }); 57 | }); 58 | 59 | fn log_setup() { 60 | use flexi_logger::writers::FileLogWriter; 61 | use flexi_logger::{LevelFilter, LogSpecBuilder, LogTarget, Logger}; 62 | 63 | let flw = FileLogWriter::builder() 64 | .suppress_timestamp() 65 | .directory("./") 66 | .try_build() 67 | .expect("Failed to build FileLogWriter"); 68 | 69 | let log_spec = LogSpecBuilder::new().default(LevelFilter::Warn).build(); 70 | 71 | Logger::with(log_spec) 72 | .log_target(LogTarget::Writer(Box::from(flw))) 73 | .start() 74 | .unwrap(); 75 | } 76 | -------------------------------------------------------------------------------- /fuzz/run_fuzz.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2020 Contributors to the Parsec project. 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | set -ex 7 | 8 | # Use the newest version of the Rust toolchain 9 | rustup update 10 | 11 | # The clean up procedure is called when the script finished or is interrupted 12 | cleanup () { 13 | # Stop tpm_server if running 14 | if [ -n "$TPM_SRV_PID" ]; then kill $TPM_SRV_PID || true; fi 15 | # Remove fake mapping and temp files 16 | rm -rf "mappings" 17 | rm -f "NVChip" 18 | rm -rf *psa_its 19 | } 20 | 21 | trap cleanup EXIT 22 | 23 | setup_tpm() { 24 | # Start TPM server 25 | tpm_server & 26 | TPM_SRV_PID=$! 27 | sleep 5 28 | tpm2_startup -c -T mssim 29 | } 30 | 31 | # Install fuzzer 32 | cargo install cargo-fuzz 33 | # Fuzzer needs nightly toolchain to run 34 | rustup toolchain install nightly 35 | 36 | setup_tpm 37 | 38 | # Find PKCS 11 slot number 39 | CONFIG_PATH="run_config.toml" 40 | # This command suppose that the slot created by the container will be the first one that appears 41 | # when printing all the available slots. 42 | SLOT_NUMBER=`softhsm2-util --show-slots | head -n2 | tail -n1 | cut -d " " -f 2` 43 | # Find all TOML files in the directory (except Cargo.toml) and replace the commented slot number with the valid one 44 | sed -i "s/^# slot_number.*$/slot_number = $SLOT_NUMBER/" $CONFIG_PATH 45 | 46 | # Create corpus if it doesn't exist 47 | cargo build --features="mbed-crypto-provider,tpm-provider,pkcs11-provider" 48 | mkdir -p corpus/fuzz_service 49 | cp init_corpus/* corpus/fuzz_service 50 | 51 | 52 | if [[ "$1" == "test" ]] 53 | then 54 | # Create an artifact from one of the initial corpus entries 55 | mkdir -p artifacts/fuzz_service 56 | cp init_corpus/example-create-ecdsa-key-MbedCrypto artifacts/fuzz_service/ 57 | # Run the fuzzer with the artifact just created; if it fails, the whole build should fail 58 | cargo +nightly fuzz run --features="mbed-crypto-provider,tpm-provider,pkcs11-provider" fuzz_service artifacts/fuzz_service/example-create-ecdsa-key-MbedCrypto 59 | exit 0 60 | fi 61 | 62 | set +e 63 | 64 | while [ true ] 65 | do 66 | # Run fuzzer 67 | cargo +nightly fuzz run --features="mbed-crypto-provider,tpm-provider,pkcs11-provider" fuzz_service 68 | 69 | cleanup 70 | setup_tpm 71 | 72 | # Notify about crash 73 | echo "Here we'd ping the webhook to notify" 74 | done 75 | -------------------------------------------------------------------------------- /quickstart/config.toml: -------------------------------------------------------------------------------- 1 | # See https://parallaxsecond.github.io/parsec-book/parsec_service/configuration.html for a full 2 | # example. 3 | 4 | [core_settings] 5 | log_level = "info" 6 | allow_root = true 7 | 8 | [listener] 9 | listener_type = "DomainSocket" 10 | timeout = 200 # in milliseconds 11 | socket_path = "./parsec.sock" 12 | 13 | [authenticator] 14 | auth_type = "UnixPeerCredentials" 15 | 16 | [[key_manager]] 17 | name = "sqlite-manager" 18 | manager_type = "SQLite" 19 | sqlite_db_path = "./sqlite-key-info-manager.sqlite3" 20 | 21 | [[provider]] 22 | provider_type = "MbedCrypto" 23 | key_info_manager = "sqlite-manager" 24 | -------------------------------------------------------------------------------- /quickstart/construct-build-details.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2023 Contributors to the Parsec project. 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | cat << EOF 7 | ---------------------------------------- 8 | -- Parsec Quickstart Build Details 9 | ---------------------------------------- 10 | OS: $(cat /build-env/os) 11 | Architecture: $(cat /build-env/arch) 12 | Rust: $(cat /build-env/rustc-version) 13 | Cargo: $(cat /build-env/cargo-version) 14 | 15 | ---------------------------------------- 16 | -- Parsec Service 17 | ---------------------------------------- 18 | Version: $(cat /build-env/parsec-version) 19 | Commit Hash: $(cat /build-env/parsec-commit) 20 | Dependencies: 21 | $(cat /build-env/parsec-dependencies) 22 | 23 | ---------------------------------------- 24 | -- Parsec Tool 25 | ---------------------------------------- 26 | Version: $(cat /build-env/parsec-tool-version) 27 | Commit Hash: $(cat /build-env/parsec-tool-commit) 28 | Dependencies: 29 | $(cat /build-env/parsec-tool-dependencies) 30 | 31 | EOF 32 | -------------------------------------------------------------------------------- /quickstart/package.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2022 Contributors to the Parsec project. 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | # Create a quickstart package 7 | 8 | # Avoid silent failures 9 | set -euf -o pipefail 10 | 11 | PACKAGE_PATH=$(pwd) 12 | ASSETS_DIR=$(cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd) 13 | PARSEC_DIR=$(dirname $ASSETS_DIR) 14 | 15 | # Usage 16 | USAGE_STR=\ 17 | "Usage:\n"\ 18 | "package.sh [Options]\n"\ 19 | "Options:\n"\ 20 | " -o {path}: Output absolute path, the default path is the current directory i.e. $(pwd)\n"\ 21 | " -h : Display this help menu\n" 22 | 23 | # Flags 24 | while getopts v:o:j:h flag 25 | do 26 | case "${flag}" in 27 | o) PACKAGE_PATH=${OPTARG};; 28 | h) echo -e $USAGE_STR; exit 0;; 29 | esac 30 | done 31 | 32 | check_release_tag() { 33 | CURRENT_TAG=$(git name-rev --tags HEAD | cut -d "/" -f 2) 34 | LATTEST_TAG=$(git tag --sort=committerdate | tail -1) 35 | if [ -z "$LATTEST_TAG" ];then 36 | echo "Warning:No tags" 37 | fi 38 | if [ "$LATTEST_TAG" == "$CURRENT_TAG" ]; then 39 | echo "Packaging release tag: $LATTEST_TAG" 40 | else 41 | echo "Warning: The current HEAD doesn't match the latest tagged" 42 | echo "Warning: Please checkout the latest tag : $LATTEST_TAG" 43 | read -n 1 -p "Do you want to continue anyway [y/n]?" choice 44 | if [ "$choice" != "y" ]; then 45 | exit 1 46 | fi 47 | fi 48 | } 49 | 50 | build_runnable_image() { 51 | docker build --target runnable_image --tag parallaxsecond/parsec-quickstart -f quickstart.Dockerfile ${PARSEC_DIR} 52 | } 53 | 54 | build_extract_tarball() { 55 | docker build --target tarball_builder --tag parallaxsecond/parsec-quickstart-tarball -f quickstart.Dockerfile ${PARSEC_DIR} 56 | 57 | # Extract the tarball out of the image used to construct it and place it in ${PACKAGE_PATH} 58 | docker run -v ${PACKAGE_PATH}:/opt/mount --rm parallaxsecond/parsec-quickstart-tarball bash -c 'cp /parsec-tar/*.tar.gz /opt/mount/' 59 | } 60 | 61 | echo "Packaging started..." 62 | 63 | trap EXIT 64 | 65 | check_release_tag 66 | build_runnable_image 67 | build_extract_tarball 68 | 69 | echo "Finalizing packages" 70 | -------------------------------------------------------------------------------- /quickstart/quickstart.Dockerfile: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Contributors to the Parsec project. 2 | # SPDX-License-Identifier: Apache-2.0 3 | 4 | # --------------------------------------------- 5 | # Docker Stage: Base builder used for both parsec service and tools 6 | FROM rust:latest AS base_builder 7 | 8 | RUN apt update -y && \ 9 | apt install -y llvm-dev libclang-dev clang cmake jq 10 | 11 | ## Track various build environment things we may want to use throughout 12 | WORKDIR /build-env 13 | RUN echo "$(uname | awk '{print tolower($0)}')" > /build-env/os 14 | RUN echo "$(arch)" > /build-env/arch 15 | RUN echo "$(rustc --version)" > /build-env/rustc-version 16 | RUN echo "$(cargo --version)" > /build-env/cargo-version 17 | 18 | # --------------------------------------------- 19 | # Docker Stage: Temporary stage to help dependency caching 20 | FROM base_builder AS parsec_service_scratch 21 | 22 | ## Copy everything in 23 | COPY . /parsec-service 24 | WORKDIR /parsec-service 25 | 26 | # This just adds cargo dependencies to the scratch stage so that we don't need to 27 | # download them each time the builder runs. 28 | RUN cargo fetch 29 | 30 | # --------------------------------------------- 31 | # Docker Stage: Executes the build of the Parsec Service 32 | FROM parsec_service_scratch AS parsec_service_builder 33 | 34 | ## Run the actual build 35 | RUN cargo build --release --features mbed-crypto-provider 36 | 37 | # Save the current parsec version and dependencies as defined by cargo and the current git commit hash 38 | RUN echo "$(cargo metadata --format-version=1 --no-deps --offline | jq -r '.packages[0].version')" > /build-env/parsec-version 39 | RUN echo "$(cargo tree)" > /build-env/parsec-dependencies 40 | RUN echo "$(git rev-parse HEAD)" > /build-env/parsec-commit 41 | 42 | # --------------------------------------------- 43 | # Docker Stage: Executes the build of the Parsec Tool 44 | FROM base_builder AS parsec_tool_builder 45 | 46 | RUN git clone https://github.com/parallaxsecond/parsec-tool /parsec-tool 47 | WORKDIR /parsec-tool 48 | RUN git checkout $(git tag --sort=committerdate | tail -1) 49 | RUN cargo build --release 50 | 51 | # Save the current parsec-tool version and dependencies as defined by cargo and the current git commit hash 52 | RUN echo "$(cargo metadata --format-version=1 --no-deps --offline | jq -r '.packages[0].version')" > /build-env/parsec-tool-version 53 | RUN echo "$(cargo tree)" > /build-env/parsec-tool-dependencies 54 | RUN echo "$(git rev-parse HEAD)" > /build-env/parsec-tool-commit 55 | 56 | # --------------------------------------------- 57 | # Docker Stage: Extracts build results from previous stages and adds in quickstart configs 58 | FROM base_builder AS layout 59 | 60 | ## Add the built binaries into the image 61 | COPY --from=parsec_service_builder /parsec-service/target/release/parsec /parsec/bin/parsec 62 | COPY --from=parsec_tool_builder /parsec-tool/target/release/parsec-tool /parsec/bin/parsec-tool 63 | 64 | ## Create and configure a starting directory for quickstart operations 65 | WORKDIR /parsec/quickstart 66 | COPY quickstart/config.toml /parsec/quickstart/config.toml 67 | COPY --from=parsec_tool_builder /parsec-tool/tests/parsec-cli-tests.sh /parsec/quickstart/parsec-cli-tests.sh 68 | 69 | ## Grab all the build-env values 70 | COPY --from=parsec_service_builder /build-env/* /build-env/ 71 | COPY --from=parsec_tool_builder /build-env/* /build-env/ 72 | 73 | ## Generate the build details file 74 | COPY quickstart/construct-build-details.sh /build-env/ 75 | RUN chmod +x /build-env/construct-build-details.sh && /build-env/construct-build-details.sh > /parsec/quickstart/build.txt 76 | 77 | # --------------------------------------------- 78 | # Docker Stage: Constructs an appropriate tarball containing all binaries and files 79 | FROM ubuntu:latest AS tarball_builder 80 | 81 | COPY --from=layout /parsec /parsec 82 | COPY quickstart/tarball_README.md /parsec/quickstart/README.md 83 | COPY --from=parsec_service_builder /build-env /build-env 84 | 85 | ## Generate a tarball containing all quickstart items and named using the version, os, and arch 86 | RUN NAME="quickstart-$(cat /build-env/parsec-version)-$(cat /build-env/os)-$(cat /build-env/arch)" \ 87 | && mv /parsec ${NAME} \ 88 | && mkdir /parsec-tar \ 89 | && tar -zcvf /parsec-tar/${NAME}.tar.gz /${NAME} 90 | 91 | # --------------------------------------------- 92 | # Docker Stage: Constructs a valid Docker image with Parsec Quickstart 93 | FROM ubuntu:latest AS runnable_image 94 | 95 | COPY --from=layout /parsec /parsec 96 | COPY quickstart/docker_README.md /parsec/quickstart/README.md 97 | 98 | ENV PATH=$PATH:/parsec/bin 99 | ENV PARSEC_SERVICE_ENDPOINT=unix:/parsec/quickstart/parsec.sock 100 | 101 | RUN apt update && apt install -y openssl 102 | 103 | RUN useradd -ms /bin/bash qs 104 | RUN chown -R qs:qs /parsec/quickstart 105 | USER qs 106 | 107 | WORKDIR /parsec/quickstart 108 | -------------------------------------------------------------------------------- /src/authenticators/jwt_svid_authenticator/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | //! JWT SVID authenticator 4 | 5 | use super::{Admin, AdminList, Application, ApplicationIdentity, Authenticate}; 6 | use crate::front::listener::ConnectionMetadata; 7 | use log::error; 8 | use parsec_interface::operations::list_authenticators; 9 | use parsec_interface::requests::request::RequestAuth; 10 | use parsec_interface::requests::Result; 11 | use parsec_interface::requests::{AuthType, ResponseStatus}; 12 | use parsec_interface::secrecy::ExposeSecret; 13 | use spiffe::workload_api::client::WorkloadApiClient; 14 | use std::str; 15 | 16 | /// JWT SVID authenticator 17 | #[allow(missing_debug_implementations)] 18 | pub struct JwtSvidAuthenticator { 19 | client: WorkloadApiClient, 20 | admins: AdminList, 21 | } 22 | 23 | impl JwtSvidAuthenticator { 24 | /// Create a new JWT-SVID authenticator with a specific path to the Workload API socket. 25 | pub fn new(workload_endpoint: String, admins: Vec) -> Option { 26 | let client = match WorkloadApiClient::new(&workload_endpoint) { 27 | Ok(client) => client, 28 | Err(e) => { 29 | error!("Can't start the SPIFFE Workload API client ({}).", e); 30 | return None; 31 | } 32 | }; 33 | Some(JwtSvidAuthenticator { 34 | client, 35 | admins: admins.into(), 36 | }) 37 | } 38 | } 39 | 40 | impl Authenticate for JwtSvidAuthenticator { 41 | fn describe(&self) -> Result { 42 | Ok(list_authenticators::AuthenticatorInfo { 43 | description: String::from( 44 | "Authenticator validating a JWT SPIFFE Verifiable Identity Document", 45 | ), 46 | version_maj: 0, 47 | version_min: 1, 48 | version_rev: 0, 49 | id: AuthType::JwtSvid, 50 | }) 51 | } 52 | 53 | fn authenticate( 54 | &self, 55 | auth: &RequestAuth, 56 | _: Option, 57 | ) -> Result { 58 | let svid = str::from_utf8(auth.buffer.expose_secret()).map_err(|e| { 59 | error!( 60 | "The authentication buffer can not be parsed into a UTF-8 string ({}).", 61 | e 62 | ); 63 | ResponseStatus::InvalidEncoding 64 | })?; 65 | 66 | let jwt_token = self 67 | .client 68 | .validate_jwt_token("parsec", svid) 69 | .map_err(|e| { 70 | error!("The validation of the JWT-SVID failed ({}).", e); 71 | ResponseStatus::AuthenticationError 72 | })?; 73 | let app_name = jwt_token.spiffe_id().to_string(); 74 | let is_admin = self.admins.is_admin(&app_name); 75 | Ok(Application { 76 | identity: ApplicationIdentity { 77 | name: app_name, 78 | auth: AuthType::JwtSvid.into(), 79 | }, 80 | is_admin, 81 | }) 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/back/dispatcher.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | //! Dispatch requests to the correct backend 4 | //! 5 | //! The dispatcher's role is to direct requests to the provider they specify, if 6 | //! said provider is available on the system, thus acting as a multiplexer. 7 | use super::backend_handler::BackEndHandler; 8 | use crate::authenticators::Application; 9 | use log::trace; 10 | use parsec_interface::requests::request::Request; 11 | use parsec_interface::requests::ProviderId; 12 | use parsec_interface::requests::{Response, ResponseStatus}; 13 | use std::collections::HashMap; 14 | use std::io::{Error, ErrorKind, Result}; 15 | 16 | /// Dispatcher to backend 17 | /// 18 | /// Component tasked with identifying the backend handler that can 19 | /// service a request. 20 | /// 21 | /// As such, it owns all the backend handlers and attempts to match 22 | /// the fields in the request header to the properties of the handlers. 23 | #[derive(Debug)] 24 | pub struct Dispatcher { 25 | backends: HashMap, 26 | } 27 | 28 | impl Dispatcher { 29 | /// Parses the `provider` field of the request header and attempts to find 30 | /// the backend handler to which the request must be dispatched. 31 | /// 32 | /// Returns either the response coming from the backend handler, or a response 33 | /// containing a status code consistent with the error encountered during 34 | /// processing. 35 | pub fn dispatch_request(&self, request: Request, app: Option) -> Response { 36 | trace!("dispatch_request ingress"); 37 | if let Some(backend) = self.backends.get(&request.header.provider) { 38 | if let Err(status) = backend.is_capable(&request) { 39 | Response::from_request_header(request.header, status) 40 | } else { 41 | { 42 | let response = backend.execute_request(request, app); 43 | trace!("execute_request egress"); 44 | response 45 | } 46 | } 47 | } else { 48 | Response::from_request_header(request.header, ResponseStatus::ProviderNotRegistered) 49 | } 50 | } 51 | } 52 | 53 | /// `Dispatcher` builder 54 | #[derive(Debug, Default)] 55 | pub struct DispatcherBuilder { 56 | backends: Option>, 57 | } 58 | 59 | impl DispatcherBuilder { 60 | /// Create a new Dispatcher builder 61 | pub fn new() -> Self { 62 | DispatcherBuilder { backends: None } 63 | } 64 | 65 | /// Add a BackEndHandler with a specific Provider ID to the dispatcher 66 | pub fn with_backend( 67 | mut self, 68 | provider_id: ProviderId, 69 | backend_handler: BackEndHandler, 70 | ) -> Self { 71 | let mut backends = self.backends.unwrap_or_default(); 72 | let _ = backends.insert(provider_id, backend_handler); 73 | self.backends = Some(backends); 74 | 75 | self 76 | } 77 | 78 | /// Add multiple BackEndHandler to the dispatcher in one call 79 | pub fn with_backends(mut self, new_backends: HashMap) -> Self { 80 | let mut backends = self.backends.unwrap_or_default(); 81 | backends.extend(new_backends); 82 | self.backends = Some(backends); 83 | 84 | self 85 | } 86 | 87 | /// Build the builder into a dispatcher 88 | pub fn build(self) -> Result { 89 | Ok(Dispatcher { 90 | backends: self 91 | .backends 92 | .ok_or_else(|| Error::new(ErrorKind::InvalidData, "backends is missing"))?, 93 | }) 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/back/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | //! Routing and parsing requests for processing by providers 4 | pub mod backend_handler; 5 | pub mod dispatcher; 6 | -------------------------------------------------------------------------------- /src/front/listener.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | //! Interface for service IPC front 4 | //! 5 | //! The [`Listen`](https://parallaxsecond.github.io/parsec-book/parsec_service/listeners.html) 6 | //! trait acts as an interface for the operations that must be supported by any implementation 7 | //! of the IPC mechanism used as a Parsec front. 8 | use derivative::Derivative; 9 | use std::time::Duration; 10 | 11 | /// This trait is created to allow the iterator returned by incoming to iterate over a trait object 12 | /// that implements both Read and Write. 13 | pub trait ReadWrite: std::io::Read + std::io::Write {} 14 | // Automatically implements ReadWrite for all types that implement Read and Write. 15 | impl ReadWrite for T {} 16 | 17 | /// Specifies metadata associated with a connection, if any. 18 | #[derive(Copy, Clone, Debug)] 19 | pub enum ConnectionMetadata { 20 | /// Unix peer credentials metadata for Unix domain sockets. 21 | UnixPeerCredentials { 22 | /// The effective UID of the connecting process. 23 | uid: u32, 24 | /// The effective GID of the connecting process. 25 | gid: u32, 26 | /// The optional PID of the connecting process. This is an Option because not all 27 | /// platforms support retrieving PID via a domain socket. 28 | pid: Option, 29 | }, 30 | // NOTE: there is currently only _one_ variant of the ConnectionMetadata enum. When a second 31 | // variant is added, you will need to update some tests! 32 | // You should grep the tests for `TODO(new_metadata_variant)` and update them accordingly. 33 | } 34 | 35 | /// Represents a connection to a single client 36 | #[derive(Derivative)] 37 | #[derivative(Debug)] 38 | pub struct Connection { 39 | /// Stream used for communication with the client 40 | #[derivative(Debug = "ignore")] 41 | pub stream: Box, 42 | /// Metadata associated with the connection that might be useful elsewhere (i.e. authentication, etc) 43 | pub metadata: Option, 44 | } 45 | 46 | /// IPC front manager interface 47 | /// 48 | /// Interface defining the functionality that any IPC front manager has to expose to Parsec for normal 49 | /// operation. 50 | pub trait Listen { 51 | /// Set the timeout on read and write calls on any stream returned by this listener. 52 | fn set_timeout(&mut self, duration: Duration); 53 | 54 | /// Non-blocking call that gets the next client connection and returns a stream 55 | /// (a Read and Write trait object). Requests are read from the stream and responses are written 56 | /// to it. Streams returned by this method should have a timeout period as set by the 57 | /// `set_timeout` method. 58 | /// If no connections are present, return `None`. 59 | /// If there are any errors in establishing the connection other than the missing 60 | /// initialization, the implementation should log them and return `None`. 61 | /// `Send` is needed because the stream is moved to a thread. 62 | /// 63 | /// # Panics 64 | /// 65 | /// If the listener has not been initialised before, with the `init` method. 66 | fn accept(&self) -> Option; 67 | } 68 | -------------------------------------------------------------------------------- /src/front/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | //! IPC front handlers 4 | pub mod domain_socket; 5 | pub mod front_end; 6 | pub mod listener; 7 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | //! Parsec service documentation 4 | //! 5 | //! This is the source code documentation for Parsec (Platform AbstRaction for 6 | //! SECurity) service. For a more in-depth guide of the system architecture, 7 | //! supported operations and other Parsec-related topics, see our 8 | //! [Parsec Book](https://parallaxsecond.github.io/parsec-book/index.html). 9 | #![deny( 10 | nonstandard_style, 11 | dead_code, 12 | improper_ctypes, 13 | non_shorthand_field_patterns, 14 | no_mangle_generic_items, 15 | overflowing_literals, 16 | path_statements, 17 | patterns_in_fns_without_body, 18 | unconditional_recursion, 19 | unused, 20 | unused_allocation, 21 | unused_comparisons, 22 | unused_parens, 23 | while_true, 24 | missing_debug_implementations, 25 | missing_docs, 26 | trivial_casts, 27 | trivial_numeric_casts, 28 | unused_extern_crates, 29 | unused_import_braces, 30 | unused_qualifications, 31 | unused_results, 32 | missing_copy_implementations 33 | )] 34 | // This one is hard to avoid. 35 | #![allow(clippy::multiple_crate_versions)] 36 | 37 | #[allow(unused)] 38 | macro_rules! format_error { 39 | ($message:expr, $error:expr) => { 40 | if crate::utils::GlobalConfig::log_error_details() { 41 | log::error!("{}; Error: {}", $message, $error) 42 | } else { 43 | log::error!("{};", $message) 44 | } 45 | }; 46 | } 47 | 48 | #[allow(unused)] 49 | macro_rules! deprecation_check { 50 | ($operation:ident, $warning:expr, $return_flag:expr) => { 51 | if let Err(ResponseStatus::DeprecatedPrimitive) = $operation.check_deprecated() { 52 | log::warn!("{}", $warning); 53 | if $return_flag && !crate::utils::GlobalConfig::allow_deprecated() { 54 | return Err(ResponseStatus::DeprecatedPrimitive); 55 | } 56 | } 57 | }; 58 | } 59 | 60 | #[allow(unused)] 61 | macro_rules! warn_on_deprecated { 62 | ($operation:ident, $warning:expr) => { 63 | deprecation_check!($operation, $warning, false); 64 | }; 65 | } 66 | 67 | #[allow(unused)] 68 | macro_rules! return_on_deprecated { 69 | ($operation:ident, $warning:expr) => { 70 | deprecation_check!($operation, $warning, true); 71 | }; 72 | } 73 | 74 | pub mod authenticators; 75 | pub mod back; 76 | pub mod front; 77 | pub mod key_info_managers; 78 | pub mod providers; 79 | pub mod utils; 80 | -------------------------------------------------------------------------------- /src/providers/cryptoauthlib/access_keys.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | use super::Provider; 4 | use log::{error, warn}; 5 | use serde::Deserialize; 6 | use std::fs::read_to_string; 7 | use std::path::Path; 8 | 9 | #[derive(Debug, Deserialize)] 10 | struct AccessKeyContainer { 11 | access_keys: Vec, 12 | } 13 | 14 | #[derive(Debug, Deserialize)] 15 | struct AccessKey { 16 | slot: u8, 17 | key: [u8; 32], 18 | } 19 | 20 | impl Provider { 21 | /// Read access keys from a configuration file and setup the CALib to use them. 22 | pub fn set_access_keys( 23 | &self, 24 | access_keys_file_name: Option, 25 | ) -> Option { 26 | let access_keys_string = match access_keys_file_name.clone() { 27 | None => { 28 | warn!("Missing 'access_key_file_name' entry in configuration toml file"); 29 | return None; 30 | } 31 | Some(file_name) => match read_to_string(Path::new(&file_name)) { 32 | Err(err) => { 33 | warn!("Cannot read from {} file because: {}.", file_name, err); 34 | return None; 35 | } 36 | Ok(config_string) => config_string, 37 | }, 38 | }; 39 | let access_keys_container: AccessKeyContainer = match toml::from_str(&access_keys_string) { 40 | Ok(keys) => keys, 41 | Err(err) => { 42 | error!( 43 | "Error parsing access key config file {}. {}", 44 | access_keys_file_name.unwrap(), 45 | err 46 | ); 47 | return None; 48 | } 49 | }; 50 | for access_key in access_keys_container.access_keys.iter() { 51 | if rust_cryptoauthlib::ATCA_ATECC_SLOTS_COUNT > access_key.slot { 52 | let err = self.device.add_access_key(access_key.slot, &access_key.key); 53 | match err { 54 | rust_cryptoauthlib::AtcaStatus::AtcaSuccess => (), 55 | _ => error!( 56 | "add_access_key() for slot {} failed, because {}", 57 | access_key.slot, err 58 | ), 59 | } 60 | } else { 61 | error!( 62 | "add_access_key() for slot {} failed, because it exceeded total slots count {}", 63 | access_key.slot, 64 | rust_cryptoauthlib::ATCA_ATECC_SLOTS_COUNT 65 | ) 66 | } 67 | } 68 | 69 | Some(rust_cryptoauthlib::AtcaStatus::AtcaSuccess) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/providers/cryptoauthlib/generate_random.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | use super::Provider; 4 | use parsec_interface::operations::psa_generate_random; 5 | use parsec_interface::requests::{ResponseStatus, Result}; 6 | 7 | impl Provider { 8 | pub(super) fn psa_generate_random_internal( 9 | &self, 10 | op: psa_generate_random::Operation, 11 | ) -> Result { 12 | let mut random_bytes = vec![0u8; 0]; 13 | let zero_vector = vec![0u8, op.size as u8]; 14 | let mut loop_count = 0u8; 15 | // external loop to retry generation if vector is not secure 16 | loop { 17 | // calculate internal loop count 18 | let call_count = (op.size + rust_cryptoauthlib::ATCA_RANDOM_BUFFER_SIZE - 1) 19 | / rust_cryptoauthlib::ATCA_RANDOM_BUFFER_SIZE; 20 | // internal loop for vector size greater than buffer size 21 | for _i in 0..call_count { 22 | let mut buffer = Vec::with_capacity(rust_cryptoauthlib::ATCA_RANDOM_BUFFER_SIZE); 23 | let err = self.device.random(&mut buffer); 24 | match err { 25 | rust_cryptoauthlib::AtcaStatus::AtcaSuccess => { 26 | // append buffer vector to result vector 27 | random_bytes.append(&mut buffer); 28 | } 29 | _ => { 30 | let error = ResponseStatus::PsaErrorGenericError; 31 | format_error!("Bytes generation failed ", err); 32 | return Err(error); 33 | } 34 | } 35 | } // end internal loop 36 | random_bytes.truncate(op.size); // cut vector to desired size 37 | match random_bytes != zero_vector { 38 | true => { 39 | break Ok(psa_generate_random::Result { 40 | random_bytes: random_bytes.into(), 41 | }) 42 | } 43 | false => { 44 | loop_count += 1; 45 | if loop_count < 3 { 46 | continue; 47 | } else { 48 | let err = ResponseStatus::PsaErrorInsufficientEntropy; 49 | format_error!("Bytes generation failed ", err); 50 | return Err(err); 51 | } 52 | } 53 | } 54 | } // end external loop 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/providers/cryptoauthlib/hash.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | use super::Provider; 4 | use log::error; 5 | use parsec_interface::operations::psa_algorithm::Hash; 6 | use parsec_interface::operations::psa_hash_compare; 7 | use parsec_interface::operations::psa_hash_compute; 8 | use parsec_interface::requests::{ResponseStatus, Result}; 9 | 10 | impl Provider { 11 | /// Calculate SHA2-256 digest for a given message using CALib. 12 | /// Ensure proper return value type. 13 | pub fn sha256(&self, msg: &[u8]) -> Result { 14 | let mut hash = vec![0u8; rust_cryptoauthlib::ATCA_SHA2_256_DIGEST_SIZE]; 15 | let result = self.device.sha(msg.to_vec(), &mut hash); 16 | match result { 17 | rust_cryptoauthlib::AtcaStatus::AtcaSuccess => { 18 | Ok(psa_hash_compute::Result { hash: hash.into() }) 19 | } 20 | _ => { 21 | error!("Hash compute failed, hardware reported: {}.", result); 22 | Err(ResponseStatus::PsaErrorHardwareFailure) 23 | } 24 | } 25 | } 26 | 27 | pub(super) fn psa_hash_compute_internal( 28 | &self, 29 | op: psa_hash_compute::Operation, 30 | ) -> Result { 31 | match op.alg { 32 | Hash::Sha256 => self.sha256(&op.input), 33 | _ => Err(ResponseStatus::PsaErrorNotSupported), 34 | } 35 | } 36 | 37 | pub(super) fn psa_hash_compare_internal( 38 | &self, 39 | op: psa_hash_compare::Operation, 40 | ) -> Result { 41 | // check hash length 42 | if op.hash.len() != Hash::Sha256.hash_length() { 43 | error!("Invalid input hash length."); 44 | return Err(ResponseStatus::PsaErrorInvalidArgument); 45 | } 46 | match op.alg { 47 | Hash::Sha256 => { 48 | // compute hash 49 | let hash = self.sha256(&op.input)?.hash; 50 | // compare input vs. computed hash 51 | if op.hash != hash { 52 | error!("Hash comparison failed."); 53 | Err(ResponseStatus::PsaErrorInvalidSignature) 54 | } else { 55 | Ok(psa_hash_compare::Result) 56 | } 57 | } 58 | _ => Err(ResponseStatus::PsaErrorNotSupported), 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/providers/cryptoauthlib/key_agreement.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | use super::Provider; 4 | use crate::authenticators::ApplicationIdentity; 5 | use crate::key_info_managers::KeyIdentity; 6 | use parsec_interface::operations::psa_algorithm::RawKeyAgreement; 7 | use parsec_interface::operations::psa_raw_key_agreement; 8 | use parsec_interface::requests::{ResponseStatus, Result}; 9 | use parsec_interface::secrecy::Secret; 10 | 11 | impl Provider { 12 | pub(super) fn psa_raw_key_agreement_internal( 13 | &self, 14 | application_identity: &ApplicationIdentity, 15 | op: psa_raw_key_agreement::Operation, 16 | ) -> Result { 17 | let key_identity = KeyIdentity::new( 18 | application_identity.clone(), 19 | self.provider_identity.clone(), 20 | op.private_key_name.clone(), 21 | ); 22 | let key_id = self.key_info_store.get_key_id::(&key_identity)?; 23 | let key_attributes = self.key_info_store.get_key_attributes(&key_identity)?; 24 | op.validate(key_attributes)?; 25 | 26 | match op.alg { 27 | RawKeyAgreement::Ecdh => { 28 | let parameters = rust_cryptoauthlib::EcdhParams { 29 | out_target: rust_cryptoauthlib::EcdhTarget::Output, 30 | slot_id: Some(key_id), 31 | ..Default::default() 32 | }; 33 | let mut key_data = op.peer_key.to_vec(); 34 | if key_data.len() == 65 { 35 | key_data = op.peer_key[1..].to_vec(); 36 | } 37 | match self.device.ecdh(parameters, &key_data) { 38 | Ok(result) => { 39 | let shared_secret = result.pms.unwrap().to_vec(); 40 | Ok(psa_raw_key_agreement::Result { 41 | shared_secret: Secret::new(shared_secret), 42 | }) 43 | } 44 | Err(status) => { 45 | format_error!("Raw key agreement status: ", status); 46 | Err(ResponseStatus::PsaErrorGenericError) 47 | } 48 | } 49 | } 50 | _ => Err(ResponseStatus::PsaErrorNotSupported), 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/providers/mbed_crypto/aead.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | use super::Provider; 4 | use crate::authenticators::ApplicationIdentity; 5 | use crate::key_info_managers::KeyIdentity; 6 | use parsec_interface::operations::{psa_aead_decrypt, psa_aead_encrypt}; 7 | use parsec_interface::requests::{ResponseStatus, Result}; 8 | use psa_crypto::operations::aead; 9 | use psa_crypto::types::key; 10 | 11 | impl Provider { 12 | pub(super) fn psa_aead_encrypt_internal( 13 | &self, 14 | application_identity: &ApplicationIdentity, 15 | op: psa_aead_encrypt::Operation, 16 | ) -> Result { 17 | let key_name = op.key_name.clone(); 18 | 19 | let key_identity = KeyIdentity::new( 20 | application_identity.clone(), 21 | self.provider_identity.clone(), 22 | key_name, 23 | ); 24 | let key_id = self.key_info_store.get_key_id(&key_identity)?; 25 | let _guard = self 26 | .key_handle_mutex 27 | .lock() 28 | .expect("Grabbing key handle mutex failed"); 29 | let id = key::Id::from_persistent_key_id(key_id)?; 30 | let key_attributes = key::Attributes::from_key_id(id)?; 31 | 32 | op.validate(key_attributes)?; 33 | let alg = op.alg; 34 | let buffer_size = key_attributes.aead_encrypt_output_size(alg, op.plaintext.len())?; 35 | let mut ciphertext = vec![0u8; buffer_size]; 36 | 37 | match aead::encrypt( 38 | id, 39 | alg, 40 | &op.nonce, 41 | &op.additional_data, 42 | &op.plaintext, 43 | &mut ciphertext, 44 | ) { 45 | Ok(output_size) => { 46 | ciphertext.resize(output_size, 0); 47 | Ok(psa_aead_encrypt::Result { 48 | ciphertext: ciphertext.into(), 49 | }) 50 | } 51 | Err(error) => { 52 | let error = ResponseStatus::from(error); 53 | format_error!("Encrypt status: ", error); 54 | Err(error) 55 | } 56 | } 57 | } 58 | 59 | pub(super) fn psa_aead_decrypt_internal( 60 | &self, 61 | application_identity: &ApplicationIdentity, 62 | op: psa_aead_decrypt::Operation, 63 | ) -> Result { 64 | let key_identity = KeyIdentity::new( 65 | application_identity.clone(), 66 | self.provider_identity.clone(), 67 | op.key_name.clone(), 68 | ); 69 | let key_id = self.key_info_store.get_key_id(&key_identity)?; 70 | 71 | let _guard = self 72 | .key_handle_mutex 73 | .lock() 74 | .expect("Grabbing key handle mutex failed"); 75 | 76 | let id = key::Id::from_persistent_key_id(key_id)?; 77 | let key_attributes = key::Attributes::from_key_id(id)?; 78 | op.validate(key_attributes)?; 79 | let buffer_size = key_attributes.aead_decrypt_output_size(op.alg, op.ciphertext.len())?; 80 | let mut plaintext = vec![0u8; buffer_size]; 81 | 82 | match aead::decrypt( 83 | id, 84 | op.alg, 85 | &op.nonce, 86 | &op.additional_data, 87 | &op.ciphertext, 88 | &mut plaintext, 89 | ) { 90 | Ok(output_size) => { 91 | plaintext.resize(output_size, 0); 92 | Ok(psa_aead_decrypt::Result { 93 | plaintext: plaintext.into(), 94 | }) 95 | } 96 | Err(error) => { 97 | let error = ResponseStatus::from(error); 98 | format_error!("Decrypt status: ", error); 99 | Err(error) 100 | } 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/providers/mbed_crypto/asym_encryption.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | use super::Provider; 4 | use crate::authenticators::ApplicationIdentity; 5 | use crate::key_info_managers::KeyIdentity; 6 | use parsec_interface::operations::{psa_asymmetric_decrypt, psa_asymmetric_encrypt}; 7 | use parsec_interface::requests::{ResponseStatus, Result}; 8 | use psa_crypto::operations::asym_encryption; 9 | use psa_crypto::types::key; 10 | 11 | impl Provider { 12 | pub(super) fn psa_asymmetric_encrypt_internal( 13 | &self, 14 | application_identity: &ApplicationIdentity, 15 | op: psa_asymmetric_encrypt::Operation, 16 | ) -> Result { 17 | let key_name = op.key_name.clone(); 18 | 19 | let key_identity = KeyIdentity::new( 20 | application_identity.clone(), 21 | self.provider_identity.clone(), 22 | key_name, 23 | ); 24 | let key_id = self.key_info_store.get_key_id(&key_identity)?; 25 | let _guard = self 26 | .key_handle_mutex 27 | .lock() 28 | .expect("Grabbing key handle mutex failed"); 29 | let id = key::Id::from_persistent_key_id(key_id)?; 30 | let key_attributes = key::Attributes::from_key_id(id)?; 31 | 32 | op.validate(key_attributes)?; 33 | let salt_buff = op.salt.as_ref().map(|salt| salt.as_slice()); 34 | let alg = op.alg; 35 | let buffer_size = key_attributes.asymmetric_encrypt_output_size(alg)?; 36 | let mut ciphertext = vec![0u8; buffer_size]; 37 | 38 | match asym_encryption::encrypt(id, alg, &op.plaintext, salt_buff, &mut ciphertext) { 39 | Ok(output_size) => { 40 | ciphertext.resize(output_size, 0); 41 | Ok(psa_asymmetric_encrypt::Result { 42 | ciphertext: ciphertext.into(), 43 | }) 44 | } 45 | Err(error) => { 46 | let error = ResponseStatus::from(error); 47 | format_error!("Encrypt status: ", error); 48 | Err(error) 49 | } 50 | } 51 | } 52 | 53 | pub(super) fn psa_asymmetric_decrypt_internal( 54 | &self, 55 | application_identity: &ApplicationIdentity, 56 | op: psa_asymmetric_decrypt::Operation, 57 | ) -> Result { 58 | let key_identity = KeyIdentity::new( 59 | application_identity.clone(), 60 | self.provider_identity.clone(), 61 | op.key_name.clone(), 62 | ); 63 | let key_id = self.key_info_store.get_key_id(&key_identity)?; 64 | 65 | let _guard = self 66 | .key_handle_mutex 67 | .lock() 68 | .expect("Grabbing key handle mutex failed"); 69 | 70 | let id = key::Id::from_persistent_key_id(key_id)?; 71 | let key_attributes = key::Attributes::from_key_id(id)?; 72 | op.validate(key_attributes)?; 73 | let salt_buff = op.salt.as_ref().map(|salt| salt.as_slice()); 74 | let buffer_size = key_attributes.asymmetric_decrypt_output_size(op.alg)?; 75 | let mut plaintext = vec![0u8; buffer_size]; 76 | 77 | match asym_encryption::decrypt(id, op.alg, &op.ciphertext, salt_buff, &mut plaintext) { 78 | Ok(output_size) => { 79 | plaintext.resize(output_size, 0); 80 | Ok(psa_asymmetric_decrypt::Result { 81 | plaintext: plaintext.into(), 82 | }) 83 | } 84 | Err(error) => { 85 | let error = ResponseStatus::from(error); 86 | format_error!("Decrypt status: ", error); 87 | Err(error) 88 | } 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/providers/mbed_crypto/asym_sign.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | use super::Provider; 4 | use crate::authenticators::ApplicationIdentity; 5 | use crate::key_info_managers::KeyIdentity; 6 | use parsec_interface::operations::{psa_sign_hash, psa_verify_hash}; 7 | use parsec_interface::requests::{ResponseStatus, Result}; 8 | use psa_crypto::operations::asym_signature; 9 | use psa_crypto::types::key; 10 | 11 | impl Provider { 12 | pub(super) fn psa_sign_hash_internal( 13 | &self, 14 | application_identity: &ApplicationIdentity, 15 | op: psa_sign_hash::Operation, 16 | ) -> Result { 17 | let key_name = op.key_name.clone(); 18 | let alg = op.alg; 19 | let key_identity = KeyIdentity::new( 20 | application_identity.clone(), 21 | self.provider_identity.clone(), 22 | key_name, 23 | ); 24 | let key_id = self.key_info_store.get_key_id(&key_identity)?; 25 | 26 | let _guard = self 27 | .key_handle_mutex 28 | .lock() 29 | .expect("Grabbing key handle mutex failed"); 30 | 31 | let id = key::Id::from_persistent_key_id(key_id)?; 32 | let key_attributes = key::Attributes::from_key_id(id)?; 33 | let buffer_size = key_attributes.sign_output_size(alg)?; 34 | let mut signature = vec![0u8; buffer_size]; 35 | 36 | op.validate(key_attributes)?; 37 | 38 | match asym_signature::sign_hash(id, alg, &(op.hash), &mut signature) { 39 | Ok(size) => { 40 | signature.resize(size, 0); 41 | Ok(psa_sign_hash::Result { 42 | signature: signature.into(), 43 | }) 44 | } 45 | Err(error) => { 46 | let error = ResponseStatus::from(error); 47 | format_error!("Sign status: ", error); 48 | Err(error) 49 | } 50 | } 51 | } 52 | 53 | pub(super) fn psa_verify_hash_internal( 54 | &self, 55 | application_identity: &ApplicationIdentity, 56 | op: psa_verify_hash::Operation, 57 | ) -> Result { 58 | let key_name = op.key_name.clone(); 59 | let alg = op.alg; 60 | let key_identity = KeyIdentity::new( 61 | application_identity.clone(), 62 | self.provider_identity.clone(), 63 | key_name, 64 | ); 65 | let key_id = self.key_info_store.get_key_id(&key_identity)?; 66 | 67 | let _guard = self 68 | .key_handle_mutex 69 | .lock() 70 | .expect("Grabbing key handle mutex failed"); 71 | 72 | let id = key::Id::from_persistent_key_id(key_id)?; 73 | let key_attributes = key::Attributes::from_key_id(id)?; 74 | op.validate(key_attributes)?; 75 | 76 | let id = key::Id::from_persistent_key_id(key_id)?; 77 | match asym_signature::verify_hash(id, alg, &(op.hash), &(op.signature)) { 78 | Ok(()) => Ok(psa_verify_hash::Result {}), 79 | Err(error) => { 80 | let error = ResponseStatus::from(error); 81 | format_error!("Verify status: ", error); 82 | Err(error) 83 | } 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/providers/mbed_crypto/capability_discovery.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use super::Provider; 5 | use crate::authenticators::ApplicationIdentity; 6 | use crate::providers::crypto_capability::CanDoCrypto; 7 | use log::{info, trace}; 8 | use parsec_interface::operations::can_do_crypto; 9 | use parsec_interface::operations::psa_key_attributes::{Attributes, Type}; 10 | use parsec_interface::requests::ResponseStatus::PsaErrorNotSupported; 11 | use parsec_interface::requests::Result; 12 | 13 | impl CanDoCrypto for Provider { 14 | fn can_do_crypto_internal( 15 | &self, 16 | _app_identity: &ApplicationIdentity, 17 | op: can_do_crypto::Operation, 18 | ) -> Result { 19 | trace!("can_do_crypto_internal"); 20 | 21 | // Check if psa-crypto can convert the attributes into PSA structure 22 | // The conversion includes some validity checks. 23 | op.attributes.can_convert_into_psa().map_err(|_| { 24 | info!("Unsupported key attributes {:?}", op.attributes); 25 | PsaErrorNotSupported 26 | })?; 27 | 28 | Ok(can_do_crypto::Result) 29 | } 30 | 31 | fn use_check_internal(&self, attributes: Attributes) -> Result { 32 | trace!("use_check_internal"); 33 | 34 | let _ = Provider::check_key_size(attributes, false).map_err(|_| { 35 | info!("Unsupported key size {}", attributes.bits); 36 | PsaErrorNotSupported 37 | })?; 38 | 39 | Ok(can_do_crypto::Result) 40 | } 41 | 42 | fn generate_check_internal(&self, attributes: Attributes) -> Result { 43 | trace!("generate_check_internal"); 44 | 45 | let _ = Provider::check_key_size(attributes, false).map_err(|_| { 46 | info!("Unsupported key size {}", attributes.bits); 47 | PsaErrorNotSupported 48 | })?; 49 | 50 | match attributes.key_type { 51 | Type::RsaKeyPair 52 | | Type::EccKeyPair { .. } 53 | | Type::DhKeyPair { .. } 54 | | Type::RawData 55 | | Type::Aes 56 | | Type::Camellia 57 | | Type::Chacha20 => Ok(can_do_crypto::Result), 58 | _ => { 59 | info!("Unsupported key type {:?}", attributes.key_type); 60 | Err(PsaErrorNotSupported) 61 | } 62 | } 63 | } 64 | 65 | fn import_check_internal(&self, attributes: Attributes) -> Result { 66 | trace!("import_check_internal"); 67 | 68 | let _ = Provider::check_key_size(attributes, true).map_err(|_| { 69 | info!("Unsupported key size {}", attributes.bits); 70 | PsaErrorNotSupported 71 | })?; 72 | 73 | // We can import public keys and all the types we can generate. 74 | match attributes.key_type { 75 | Type::RsaPublicKey | Type::EccPublicKey { .. } | Type::DhPublicKey { .. } => { 76 | Ok(can_do_crypto::Result) 77 | } 78 | Type::RsaKeyPair 79 | | Type::EccKeyPair { .. } 80 | | Type::DhKeyPair { .. } 81 | | Type::RawData 82 | | Type::Aes 83 | | Type::Camellia 84 | | Type::Chacha20 => Ok(can_do_crypto::Result), 85 | _ => { 86 | info!("Unsupported key type {:?}", attributes.key_type); 87 | Err(PsaErrorNotSupported) 88 | } 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/providers/mbed_crypto/generate_random.rs: -------------------------------------------------------------------------------- 1 | use super::Provider; 2 | use parsec_interface::operations::psa_generate_random; 3 | use parsec_interface::requests::{ResponseStatus, Result}; 4 | use psa_crypto::operations::other::generate_random; 5 | 6 | impl Provider { 7 | pub(super) fn psa_generate_random_internal( 8 | &self, 9 | op: psa_generate_random::Operation, 10 | ) -> Result { 11 | let buffer_size = op.size; 12 | if buffer_size > crate::utils::GlobalConfig::buffer_size_limit() { 13 | let error = ResponseStatus::ResponseTooLarge; 14 | format_error!("Generate random status", error); 15 | return Err(error); 16 | } 17 | 18 | let mut buffer = vec![0u8; buffer_size]; 19 | match generate_random(&mut buffer) { 20 | Ok(_) => Ok(psa_generate_random::Result { 21 | random_bytes: buffer.into(), 22 | }), 23 | Err(error) => { 24 | let error = ResponseStatus::from(error); 25 | format_error!("Generate random status", error); 26 | Err(error) 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/providers/mbed_crypto/hash.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | use super::Provider; 4 | use parsec_interface::operations::{psa_hash_compare, psa_hash_compute}; 5 | use parsec_interface::requests::{ResponseStatus, Result}; 6 | use psa_crypto::operations::hash; 7 | 8 | impl Provider { 9 | pub(super) fn psa_hash_compute_internal( 10 | &self, 11 | op: psa_hash_compute::Operation, 12 | ) -> Result { 13 | let mut hash = vec![0u8; op.alg.hash_length()]; 14 | 15 | match hash::hash_compute(op.alg, &op.input, &mut hash) { 16 | Ok(hash_size) => { 17 | hash.resize(hash_size, 0); 18 | Ok(psa_hash_compute::Result { hash: hash.into() }) 19 | } 20 | Err(error) => { 21 | let error = ResponseStatus::from(error); 22 | format_error!("Has compute status: ", error); 23 | Err(error) 24 | } 25 | } 26 | } 27 | 28 | pub(super) fn psa_hash_compare_internal( 29 | &self, 30 | op: psa_hash_compare::Operation, 31 | ) -> Result { 32 | match hash::hash_compare(op.alg, &op.input, &op.hash) { 33 | Ok(()) => Ok(psa_hash_compare::Result), 34 | Err(error) => { 35 | let error = ResponseStatus::from(error); 36 | format_error!("Hash compare status: ", error); 37 | Err(error) 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/providers/mbed_crypto/key_agreement.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | use super::Provider; 4 | use crate::authenticators::ApplicationIdentity; 5 | use crate::key_info_managers::KeyIdentity; 6 | use parsec_interface::operations::psa_raw_key_agreement; 7 | use parsec_interface::requests::{ResponseStatus, Result}; 8 | use parsec_interface::secrecy::Secret; 9 | use psa_crypto::operations::key_agreement; 10 | use psa_crypto::types::key; 11 | 12 | impl Provider { 13 | pub(super) fn psa_raw_key_agreement( 14 | &self, 15 | application_identity: &ApplicationIdentity, 16 | op: psa_raw_key_agreement::Operation, 17 | ) -> Result { 18 | let key_name = op.private_key_name.clone(); 19 | 20 | let key_identity = KeyIdentity::new( 21 | application_identity.clone(), 22 | self.provider_identity.clone(), 23 | key_name, 24 | ); 25 | let key_id = self.key_info_store.get_key_id(&key_identity)?; 26 | let _guard = self 27 | .key_handle_mutex 28 | .lock() 29 | .expect("Grabbing key handle mutex failed"); 30 | let id = key::Id::from_persistent_key_id(key_id)?; 31 | let key_attributes = key::Attributes::from_key_id(id)?; 32 | 33 | op.validate(key_attributes)?; 34 | let buffer_size = key_attributes.raw_key_agreement_output_size(op.alg)?; 35 | let mut shared_secret = vec![0u8; buffer_size]; 36 | 37 | match key_agreement::raw_key_agreement(op.alg, id, &op.peer_key, &mut shared_secret) { 38 | Ok(output_size) => { 39 | shared_secret.resize(output_size, 0); 40 | Ok(psa_raw_key_agreement::Result { 41 | shared_secret: Secret::new(shared_secret), 42 | }) 43 | } 44 | Err(error) => { 45 | let error = ResponseStatus::from(error); 46 | format_error!("Raw key agreement status: ", error); 47 | Err(error) 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/providers/pkcs11/generate_random.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | use super::utils::to_response_status; 4 | use super::Provider; 5 | use log::error; 6 | use parsec_interface::operations::psa_generate_random; 7 | use parsec_interface::requests::{ResponseStatus, Result}; 8 | use std::convert::TryFrom; 9 | 10 | impl Provider { 11 | pub(super) fn psa_generate_random_internal( 12 | &self, 13 | op: psa_generate_random::Operation, 14 | ) -> Result { 15 | let length = u32::try_from(op.size).or_else(|_| { 16 | let error = ResponseStatus::PsaErrorGenericError; 17 | error!("Requested size is too large"); 18 | Err(error) 19 | })?; 20 | 21 | let session = self.new_session()?; 22 | 23 | Ok(psa_generate_random::Result { 24 | random_bytes: session 25 | .generate_random_vec(length) 26 | .map_err(to_response_status)? 27 | .into(), 28 | }) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/providers/pkcs11/key_metadata.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | use super::Provider; 4 | 5 | impl Provider { 6 | pub(super) fn create_key_id(&self) -> u32 { 7 | let mut local_ids_handle = self.local_ids.write().expect("Local ID lock poisoned"); 8 | let mut key_id = rand::random::(); 9 | while local_ids_handle.contains(&key_id) { 10 | key_id = rand::random::(); 11 | } 12 | let _ = local_ids_handle.insert(key_id); 13 | key_id 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/providers/tpm/asym_sign.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | use super::{utils, Provider}; 4 | use crate::authenticators::ApplicationIdentity; 5 | use crate::key_info_managers::KeyIdentity; 6 | use log::error; 7 | use parsec_interface::operations::psa_algorithm::*; 8 | use parsec_interface::operations::{psa_sign_hash, psa_verify_hash}; 9 | use parsec_interface::requests::{ResponseStatus, Result}; 10 | use std::convert::TryFrom; 11 | use tss_esapi::structures::{Auth, Digest}; 12 | 13 | impl Provider { 14 | pub(super) fn psa_sign_hash_internal( 15 | &self, 16 | application_identity: &ApplicationIdentity, 17 | op: psa_sign_hash::Operation, 18 | ) -> Result { 19 | let key_identity = KeyIdentity::new( 20 | application_identity.clone(), 21 | self.provider_identity.clone(), 22 | op.key_name.clone(), 23 | ); 24 | 25 | let password_context = self.get_key_ctx(&key_identity)?; 26 | let key_attributes = self.key_info_store.get_key_attributes(&key_identity)?; 27 | 28 | let mut esapi_context = self 29 | .esapi_context 30 | .lock() 31 | .expect("ESAPI Context lock poisoned"); 32 | 33 | match op.alg { 34 | AsymmetricSignature::RsaPkcs1v15Sign { .. } => (), 35 | AsymmetricSignature::Ecdsa { .. } => (), 36 | _ => { 37 | if crate::utils::GlobalConfig::log_error_details() { 38 | error!( 39 | "Requested algorithm is not supported by the TPM provider: {:?}", 40 | op.alg 41 | ); 42 | } else { 43 | error!("Requested algorithm is not supported by the TPM provider"); 44 | } 45 | return Err(ResponseStatus::PsaErrorNotSupported); 46 | } 47 | } 48 | 49 | op.validate(key_attributes)?; 50 | 51 | let signature = esapi_context 52 | .sign( 53 | password_context.key_material().clone(), 54 | utils::parsec_to_tpm_params(key_attributes)?, 55 | Some( 56 | Auth::try_from(password_context.auth_value().to_vec()) 57 | .map_err(utils::to_response_status)?, 58 | ), 59 | Digest::try_from((*op.hash).clone()).map_err(utils::to_response_status)?, 60 | ) 61 | .map_err(|e| { 62 | if crate::utils::GlobalConfig::log_error_details() { 63 | error!("Error signing: {}.", e); 64 | } 65 | utils::to_response_status(e) 66 | })?; 67 | 68 | Ok(psa_sign_hash::Result { 69 | signature: utils::signature_data_to_bytes(signature, key_attributes)?.into(), 70 | }) 71 | } 72 | 73 | pub(super) fn psa_verify_hash_internal( 74 | &self, 75 | application_identity: &ApplicationIdentity, 76 | op: psa_verify_hash::Operation, 77 | ) -> Result { 78 | let key_identity = KeyIdentity::new( 79 | application_identity.clone(), 80 | self.provider_identity.clone(), 81 | op.key_name.clone(), 82 | ); 83 | 84 | let password_context = self.get_key_ctx(&key_identity)?; 85 | let key_attributes = self.key_info_store.get_key_attributes(&key_identity)?; 86 | 87 | let mut esapi_context = self 88 | .esapi_context 89 | .lock() 90 | .expect("ESAPI Context lock poisoned"); 91 | 92 | match op.alg { 93 | AsymmetricSignature::RsaPkcs1v15Sign { .. } => (), 94 | AsymmetricSignature::Ecdsa { .. } => (), 95 | _ => { 96 | if crate::utils::GlobalConfig::log_error_details() { 97 | error!( 98 | "Requested algorithm is not supported by the TPM provider: {:?}", 99 | op.alg 100 | ); 101 | } else { 102 | error!("Requested algorithm is not supported by the TPM provider"); 103 | } 104 | return Err(ResponseStatus::PsaErrorNotSupported); 105 | } 106 | } 107 | 108 | op.validate(key_attributes)?; 109 | 110 | let signature = utils::parsec_to_tpm_signature(op.signature, key_attributes, op.alg)?; 111 | 112 | let _ = esapi_context 113 | .verify_signature( 114 | password_context.key_material().clone(), 115 | utils::parsec_to_tpm_params(key_attributes)?, 116 | Digest::try_from((*op.hash).clone()).map_err(utils::to_response_status)?, 117 | signature, 118 | ) 119 | .map_err(utils::to_response_status)?; 120 | 121 | Ok(psa_verify_hash::Result {}) 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/providers/tpm/capability_discovery.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use super::{utils, Provider}; 5 | use crate::authenticators::ApplicationIdentity; 6 | use crate::providers::crypto_capability::CanDoCrypto; 7 | use log::{info, trace}; 8 | use parsec_interface::operations::can_do_crypto; 9 | use parsec_interface::operations::psa_key_attributes::{Attributes, Type}; 10 | use parsec_interface::requests::ResponseStatus::PsaErrorNotSupported; 11 | use parsec_interface::requests::Result; 12 | 13 | impl CanDoCrypto for Provider { 14 | fn can_do_crypto_internal( 15 | &self, 16 | _application_identity: &ApplicationIdentity, 17 | op: can_do_crypto::Operation, 18 | ) -> Result { 19 | trace!("can_do_crypto_internal"); 20 | 21 | // Check attributes compatibility with the provider 22 | match op.attributes.key_type { 23 | Type::RsaKeyPair | Type::RsaPublicKey => { 24 | let _ = 25 | utils::rsa_key_bits(op.attributes.bits).map_err(|_| PsaErrorNotSupported)?; 26 | Ok(can_do_crypto::Result) 27 | } 28 | Type::EccKeyPair { .. } | Type::EccPublicKey { .. } => { 29 | let _ = utils::convert_curve_to_tpm(op.attributes)?; 30 | Ok(can_do_crypto::Result) 31 | } 32 | _ => { 33 | info!("Unsupported key type {:?}", op.attributes.key_type); 34 | Err(PsaErrorNotSupported) 35 | } 36 | } 37 | } 38 | 39 | fn use_check_internal(&self, attributes: Attributes) -> Result { 40 | trace!("use_check_internal"); 41 | 42 | let _ = utils::parsec_to_tpm_params(attributes).map_err(|_| PsaErrorNotSupported)?; 43 | 44 | // TO-DO we also need to check capabilities of used TMP module. 45 | // TPM_GetCapability support in the tss-esapi crate is required. 46 | Ok(can_do_crypto::Result) 47 | } 48 | 49 | fn generate_check_internal(&self, attributes: Attributes) -> Result { 50 | trace!("generate_check_internal"); 51 | match attributes.key_type { 52 | Type::RsaKeyPair | Type::EccKeyPair { .. } => Ok(can_do_crypto::Result), 53 | _ => { 54 | info!("Unsupported key type {:?}", attributes.key_type); 55 | Err(PsaErrorNotSupported) 56 | } 57 | } 58 | } 59 | 60 | fn import_check_internal(&self, attributes: Attributes) -> Result { 61 | trace!("import_check_internal"); 62 | match attributes.key_type { 63 | Type::RsaPublicKey | Type::EccPublicKey { .. } => Ok(can_do_crypto::Result), 64 | _ => { 65 | info!("Unsupported key type {:?}", attributes.key_type); 66 | Err(PsaErrorNotSupported) 67 | } 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/providers/tpm/generate_random.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | use super::utils; 4 | use super::Provider; 5 | use parsec_interface::operations::psa_generate_random; 6 | use parsec_interface::requests::Result; 7 | 8 | impl Provider { 9 | pub(super) fn psa_generate_random_internal( 10 | &self, 11 | op: psa_generate_random::Operation, 12 | ) -> Result { 13 | let size = op.size; 14 | 15 | let mut esapi_context = self 16 | .esapi_context 17 | .lock() 18 | .expect("ESAPI Context lock poisoned"); 19 | 20 | let random_bytes = esapi_context 21 | .as_mut() 22 | .execute_without_session(|esapi_context| esapi_context.get_random(size)) 23 | .map_err(|e| { 24 | format_error!("Failed to get random bytes", e); 25 | utils::to_response_status(e) 26 | })?; 27 | Ok(psa_generate_random::Result { 28 | random_bytes: random_bytes.value().to_vec().into(), 29 | }) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/providers/trusted_service/asym_encryption.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | use super::Provider; 4 | use crate::authenticators::ApplicationIdentity; 5 | use crate::key_info_managers::KeyIdentity; 6 | use log::error; 7 | use parsec_interface::operations::{psa_asymmetric_decrypt, psa_asymmetric_encrypt}; 8 | use parsec_interface::requests::Result; 9 | 10 | impl Provider { 11 | pub(super) fn psa_asymmetric_encrypt_internal( 12 | &self, 13 | application_identity: &ApplicationIdentity, 14 | op: psa_asymmetric_encrypt::Operation, 15 | ) -> Result { 16 | let key_identity = KeyIdentity::new( 17 | application_identity.clone(), 18 | self.provider_identity.clone(), 19 | op.key_name.clone(), 20 | ); 21 | let key_id = self.key_info_store.get_key_id(&key_identity)?; 22 | let salt_buff = match &op.salt { 23 | Some(salt) => salt.to_vec(), 24 | None => Vec::new(), 25 | }; 26 | 27 | match self 28 | .context 29 | .asym_encrypt(key_id, op.alg, op.plaintext.to_vec(), salt_buff) 30 | { 31 | Ok(ciphertext) => Ok(psa_asymmetric_encrypt::Result { 32 | ciphertext: ciphertext.into(), 33 | }), 34 | Err(error) => { 35 | error!("Encrypt failed with status: {}", error); 36 | Err(error) 37 | } 38 | } 39 | } 40 | 41 | pub(super) fn psa_asymmetric_decrypt_internal( 42 | &self, 43 | application_identity: &ApplicationIdentity, 44 | op: psa_asymmetric_decrypt::Operation, 45 | ) -> Result { 46 | let key_identity = KeyIdentity::new( 47 | application_identity.clone(), 48 | self.provider_identity.clone(), 49 | op.key_name.clone(), 50 | ); 51 | let key_id = self.key_info_store.get_key_id(&key_identity)?; 52 | let salt_buff = match &op.salt { 53 | Some(salt) => salt.to_vec(), 54 | None => Vec::new(), 55 | }; 56 | 57 | match self 58 | .context 59 | .asym_decrypt(key_id, op.alg, op.ciphertext.to_vec(), salt_buff) 60 | { 61 | Ok(plaintext) => Ok(psa_asymmetric_decrypt::Result { 62 | plaintext: plaintext.into(), 63 | }), 64 | Err(error) => { 65 | error!("Decrypt failed with status: {}", error); 66 | Err(error) 67 | } 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/providers/trusted_service/asym_sign.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | use super::Provider; 4 | use crate::authenticators::ApplicationIdentity; 5 | use crate::key_info_managers::KeyIdentity; 6 | use parsec_interface::operations::{psa_sign_hash, psa_verify_hash}; 7 | use parsec_interface::requests::Result; 8 | 9 | impl Provider { 10 | pub(super) fn psa_sign_hash_internal( 11 | &self, 12 | application_identity: &ApplicationIdentity, 13 | op: psa_sign_hash::Operation, 14 | ) -> Result { 15 | let key_identity = KeyIdentity::new( 16 | application_identity.clone(), 17 | self.provider_identity.clone(), 18 | op.key_name.clone(), 19 | ); 20 | let key_id = self.key_info_store.get_key_id(&key_identity)?; 21 | let key_attributes = self.key_info_store.get_key_attributes(&key_identity)?; 22 | op.validate(key_attributes)?; 23 | 24 | Ok(psa_sign_hash::Result { 25 | signature: self 26 | .context 27 | .sign_hash(key_id, op.hash.to_vec(), op.alg)? 28 | .into(), 29 | }) 30 | } 31 | 32 | pub(super) fn psa_verify_hash_internal( 33 | &self, 34 | application_identity: &ApplicationIdentity, 35 | op: psa_verify_hash::Operation, 36 | ) -> Result { 37 | let key_identity = KeyIdentity::new( 38 | application_identity.clone(), 39 | self.provider_identity.clone(), 40 | op.key_name.clone(), 41 | ); 42 | let key_id = self.key_info_store.get_key_id(&key_identity)?; 43 | let key_attributes = self.key_info_store.get_key_attributes(&key_identity)?; 44 | op.validate(key_attributes)?; 45 | 46 | self.context 47 | .verify_hash(key_id, op.hash.to_vec(), op.signature.to_vec(), op.alg)?; 48 | 49 | Ok(psa_verify_hash::Result {}) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/providers/trusted_service/capability_discovery.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | 4 | use super::Provider; 5 | use crate::authenticators::ApplicationIdentity; 6 | use crate::providers::crypto_capability::CanDoCrypto; 7 | use log::{info, trace}; 8 | use parsec_interface::operations::can_do_crypto; 9 | use parsec_interface::operations::psa_key_attributes::{Attributes, Type}; 10 | use parsec_interface::requests::ResponseStatus::PsaErrorNotSupported; 11 | use parsec_interface::requests::Result; 12 | 13 | impl CanDoCrypto for Provider { 14 | fn can_do_crypto_internal( 15 | &self, 16 | _app_identity: &ApplicationIdentity, 17 | op: can_do_crypto::Operation, 18 | ) -> Result { 19 | trace!("can_do_crypto_internal"); 20 | 21 | // Check if psa-crypto can convert the attributes into PSA structure 22 | // The conversion includes some validity checks. 23 | op.attributes.can_convert_into_psa().map_err(|_| { 24 | info!("Unsupported key attributes {:?}", op.attributes); 25 | PsaErrorNotSupported 26 | })?; 27 | 28 | Ok(can_do_crypto::Result) 29 | } 30 | 31 | fn use_check_internal(&self, attributes: Attributes) -> Result { 32 | trace!("use_check_internal"); 33 | 34 | let _ = Provider::check_key_size(attributes, false).map_err(|_| { 35 | info!("Unsupported key size {}", attributes.bits); 36 | PsaErrorNotSupported 37 | })?; 38 | 39 | Ok(can_do_crypto::Result) 40 | } 41 | 42 | fn generate_check_internal(&self, attributes: Attributes) -> Result { 43 | trace!("generate_check_internal"); 44 | 45 | let _ = Provider::check_key_size(attributes, false).map_err(|_| { 46 | info!("Unsupported key size {}", attributes.bits); 47 | PsaErrorNotSupported 48 | })?; 49 | 50 | match attributes.key_type { 51 | Type::RsaKeyPair 52 | | Type::EccKeyPair { .. } 53 | | Type::DhKeyPair { .. } 54 | | Type::RawData 55 | | Type::Aes 56 | | Type::Camellia 57 | | Type::Chacha20 => Ok(can_do_crypto::Result), 58 | _ => { 59 | info!("Unsupported key type {:?}", attributes.key_type); 60 | Err(PsaErrorNotSupported) 61 | } 62 | } 63 | } 64 | 65 | fn import_check_internal(&self, attributes: Attributes) -> Result { 66 | trace!("import_check_internal"); 67 | 68 | let _ = Provider::check_key_size(attributes, true).map_err(|_| { 69 | info!("Unsupported key size {}", attributes.bits); 70 | PsaErrorNotSupported 71 | })?; 72 | 73 | // We can import public keys and all the types we can generate. 74 | match attributes.key_type { 75 | Type::RsaPublicKey | Type::EccPublicKey { .. } | Type::DhPublicKey { .. } => { 76 | Ok(can_do_crypto::Result) 77 | } 78 | Type::RsaKeyPair 79 | | Type::EccKeyPair { .. } 80 | | Type::DhKeyPair { .. } 81 | | Type::RawData 82 | | Type::Aes 83 | | Type::Camellia 84 | | Type::Chacha20 => Ok(can_do_crypto::Result), 85 | _ => { 86 | info!("Unsupported key type {:?}", attributes.key_type); 87 | Err(PsaErrorNotSupported) 88 | } 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/providers/trusted_service/context/asym_encryption.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | use super::ts_protobuf::{ 4 | AsymmetricDecryptIn, AsymmetricDecryptOut, AsymmetricEncryptIn, AsymmetricEncryptOut, 5 | }; 6 | use super::Context; 7 | use parsec_interface::operations::psa_algorithm::AsymmetricEncryption; 8 | use parsec_interface::requests::ResponseStatus; 9 | 10 | impl Context { 11 | pub fn asym_encrypt( 12 | &self, 13 | key_id: u32, 14 | alg: AsymmetricEncryption, 15 | plaintext: Vec, 16 | salt: Vec, 17 | ) -> Result, ResponseStatus> { 18 | let alg = alg.into(); 19 | let req = AsymmetricEncryptIn { 20 | id: key_id, 21 | alg, 22 | plaintext, 23 | salt, 24 | }; 25 | let AsymmetricEncryptOut { ciphertext } = self.send_request(&req)?; 26 | 27 | Ok(ciphertext) 28 | } 29 | 30 | pub fn asym_decrypt( 31 | &self, 32 | key_id: u32, 33 | alg: AsymmetricEncryption, 34 | ciphertext: Vec, 35 | salt: Vec, 36 | ) -> Result, ResponseStatus> { 37 | let alg = alg.into(); 38 | let req = AsymmetricDecryptIn { 39 | id: key_id, 40 | alg, 41 | ciphertext, 42 | salt, 43 | }; 44 | let AsymmetricDecryptOut { plaintext } = self.send_request(&req)?; 45 | 46 | Ok(plaintext) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/providers/trusted_service/context/asym_sign.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | use super::error::Error; 4 | use super::ts_protobuf::{SignHashIn, SignHashOut, VerifyHashIn}; 5 | use super::Context; 6 | use log::info; 7 | use psa_crypto::types::algorithm::AsymmetricSignature; 8 | 9 | impl Context { 10 | /// Sign a hash with an asymmetric key given its ID and the signing algorithm. 11 | pub fn sign_hash( 12 | &self, 13 | key_id: u32, 14 | hash: Vec, 15 | algorithm: AsymmetricSignature, 16 | ) -> Result, Error> { 17 | info!("Handling SignHash request"); 18 | let proto_req = SignHashIn { 19 | id: key_id, 20 | hash, 21 | alg: algorithm.into(), 22 | }; 23 | let SignHashOut { signature } = self.send_request(&proto_req)?; 24 | 25 | Ok(signature) 26 | } 27 | 28 | /// Verify a signature on a hash with an asymmetric key given its ID and the signing algorithm. 29 | pub fn verify_hash( 30 | &self, 31 | key_id: u32, 32 | hash: Vec, 33 | signature: Vec, 34 | algorithm: AsymmetricSignature, 35 | ) -> Result<(), Error> { 36 | info!("Handling VerifyHash request"); 37 | let proto_req = VerifyHashIn { 38 | id: key_id, 39 | hash, 40 | signature, 41 | alg: algorithm.into(), 42 | }; 43 | self.send_request(&proto_req)?; 44 | 45 | Ok(()) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/providers/trusted_service/context/generate_random.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | use super::error::Error; 4 | use super::ts_protobuf::{GenerateRandomIn, GenerateRandomOut}; 5 | use super::Context; 6 | use log::info; 7 | use std::convert::TryInto; 8 | 9 | impl Context { 10 | pub fn generate_random(&self, size: usize) -> Result, Error> { 11 | info!("Handling GenerateRandom request"); 12 | let open_req: GenerateRandomIn = GenerateRandomIn { 13 | size: size.try_into()?, 14 | }; 15 | let result: GenerateRandomOut = self.send_request(&open_req)?; 16 | Ok(result.random_bytes) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/providers/trusted_service/context/key_management.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | use super::error::Error; 4 | use super::ts_protobuf::{ 5 | DestroyKeyIn, DestroyKeyOut, ExportKeyIn, ExportPublicKeyIn, GenerateKeyIn, ImportKeyIn, 6 | KeyAttributes, KeyLifetime, KeyPolicy, 7 | }; 8 | use super::Context; 9 | use log::info; 10 | use psa_crypto::types::key::Attributes; 11 | use std::convert::{TryFrom, TryInto}; 12 | use zeroize::Zeroize; 13 | 14 | impl Context { 15 | /// Generate a key given its attributes and ID 16 | /// 17 | /// Lifetime flexibility is not supported: the `lifetime` parameter in the key 18 | /// attributes is essentially ignored and replaced with `KeyLifetime::Persistent`. 19 | pub fn generate_key(&self, key_attrs: Attributes, id: u32) -> Result<(), Error> { 20 | info!("Handling GenerateKey request"); 21 | let generate_req = GenerateKeyIn { 22 | attributes: Some(KeyAttributes { 23 | r#type: u16::try_from(key_attrs.key_type)? as u32, 24 | key_bits: key_attrs.bits.try_into()?, 25 | lifetime: KeyLifetime::Persistent as u32, 26 | id, 27 | policy: Some(KeyPolicy { 28 | usage: key_attrs.policy.usage_flags.into(), 29 | alg: key_attrs.policy.permitted_algorithms.try_into()?, 30 | }), 31 | }), 32 | }; 33 | self.send_request(&generate_req)?; 34 | 35 | Ok(()) 36 | } 37 | 38 | /// Import a key given its attributes, ID, and key data. 39 | /// 40 | /// Lifetime flexibility is not supported: the `lifetime` parameter in the key 41 | /// attributes is essentially ignored and replaced with `KeyLifetime::Persistent`. 42 | /// 43 | /// Key data must be in the format described by the PSA Crypto format. 44 | pub fn import_key(&self, key_attrs: Attributes, id: u32, key_data: &[u8]) -> Result<(), Error> { 45 | info!("Handling ImportKey request"); 46 | let mut data = key_data.to_vec(); 47 | let import_req = ImportKeyIn { 48 | attributes: Some(KeyAttributes { 49 | r#type: u16::try_from(key_attrs.key_type).map_err(|e| { 50 | data.zeroize(); 51 | e 52 | })? as u32, 53 | key_bits: key_attrs.bits.try_into().map_err(|e| { 54 | data.zeroize(); 55 | e 56 | })?, 57 | lifetime: KeyLifetime::Persistent as u32, 58 | id, 59 | policy: Some(KeyPolicy { 60 | usage: key_attrs.policy.usage_flags.into(), 61 | alg: key_attrs 62 | .policy 63 | .permitted_algorithms 64 | .try_into() 65 | .map_err(|e| { 66 | data.zeroize(); 67 | e 68 | })?, 69 | }), 70 | }), 71 | data, 72 | }; 73 | self.send_request(&import_req)?; 74 | 75 | Ok(()) 76 | } 77 | 78 | /// Export the public part of a key given its ID. 79 | /// 80 | /// The public key data is returned in the format specified by the PSA Crypto 81 | /// format. 82 | pub fn export_public_key(&self, id: u32) -> Result, Error> { 83 | info!("Handling ExportPublicKey request"); 84 | let req = ExportPublicKeyIn { id }; 85 | self.send_request(&req) 86 | } 87 | 88 | /// Export the key given its ID. 89 | pub fn export_key(&self, id: u32) -> Result, Error> { 90 | info!("Handling ExportKey request"); 91 | let req = ExportKeyIn { id }; 92 | self.send_request(&req) 93 | } 94 | 95 | /// Destroy a key given its ID. 96 | pub fn destroy_key(&self, key_id: u32) -> Result<(), Error> { 97 | info!("Handling DestroyKey request"); 98 | 99 | let destroy_req = DestroyKeyIn { id: key_id }; 100 | let _proto_resp: DestroyKeyOut = self.send_request(&destroy_req)?; 101 | Ok(()) 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/providers/trusted_service/context/ts_protobuf.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | #![allow( 4 | non_snake_case, 5 | non_camel_case_types, 6 | non_upper_case_globals, 7 | clippy::unseparated_literal_suffix, 8 | // There is an issue where long double become u128 in extern blocks. Check this issue: 9 | // https://github.com/rust-lang/rust-bindgen/issues/1549 10 | improper_ctypes, 11 | missing_debug_implementations, 12 | trivial_casts, 13 | clippy::all, 14 | unused, 15 | unused_qualifications 16 | )] 17 | use zeroize::Zeroize; 18 | 19 | include!(concat!(env!("OUT_DIR"), "/ts_crypto.rs")); 20 | 21 | /// Trait for associating an Opcode with each operation type 22 | /// and obtaining it in a generic way. 23 | pub trait GetOpcode { 24 | fn opcode(&self) -> Opcode; 25 | } 26 | 27 | macro_rules! opcode_impl { 28 | ($type:ty, $opcode:ident) => { 29 | impl GetOpcode for $type { 30 | fn opcode(&self) -> Opcode { 31 | Opcode::$opcode 32 | } 33 | } 34 | }; 35 | 36 | ($type_in:ty, $type_out:ty, $opcode:ident) => { 37 | impl GetOpcode for $type_in { 38 | fn opcode(&self) -> Opcode { 39 | Opcode::$opcode 40 | } 41 | } 42 | 43 | impl GetOpcode for $type_out { 44 | fn opcode(&self) -> Opcode { 45 | Opcode::$opcode 46 | } 47 | } 48 | }; 49 | } 50 | 51 | opcode_impl!(GenerateKeyIn, GenerateKeyOut, GenerateKey); 52 | opcode_impl!(DestroyKeyIn, DestroyKeyOut, DestroyKey); 53 | opcode_impl!(SignHashIn, SignHashOut, SignHash); 54 | opcode_impl!(VerifyHashIn, VerifyHashOut, VerifyHash); 55 | opcode_impl!(ImportKeyIn, ImportKeyOut, ImportKey); 56 | opcode_impl!(ExportPublicKeyIn, ExportPublicKeyOut, ExportPublicKey); 57 | opcode_impl!(ExportKeyIn, ExportKeyOut, ExportKey); 58 | opcode_impl!(GenerateRandomIn, GenerateRandomOut, GenerateRandom); 59 | opcode_impl!(AsymmetricDecryptIn, AsymmetricDecryptOut, AsymmetricDecrypt); 60 | opcode_impl!(AsymmetricEncryptIn, AsymmetricEncryptOut, AsymmetricEncrypt); 61 | 62 | impl Drop for ImportKeyIn { 63 | fn drop(&mut self) { 64 | self.data.zeroize(); 65 | } 66 | } 67 | 68 | impl Drop for ExportKeyOut { 69 | fn drop(&mut self) { 70 | self.data.zeroize(); 71 | } 72 | } 73 | 74 | impl Drop for SignHashIn { 75 | fn drop(&mut self) { 76 | self.hash.zeroize(); 77 | } 78 | } 79 | 80 | impl Drop for VerifyHashIn { 81 | fn drop(&mut self) { 82 | self.hash.zeroize(); 83 | self.signature.zeroize(); 84 | } 85 | } 86 | 87 | impl Drop for AsymmetricEncryptIn { 88 | fn drop(&mut self) { 89 | self.plaintext.zeroize(); 90 | self.salt.zeroize(); 91 | } 92 | } 93 | 94 | impl Drop for AsymmetricDecryptIn { 95 | fn drop(&mut self) { 96 | self.ciphertext.zeroize(); 97 | self.salt.zeroize(); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/providers/trusted_service/error.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | use super::context::error::{Error, RpcCallerError, WrapperError}; 4 | use parsec_interface::requests::ResponseStatus; 5 | 6 | impl From for ResponseStatus { 7 | fn from(error: RpcCallerError) -> Self { 8 | match error { 9 | RpcCallerError::EndpointDoesNotExist 10 | | RpcCallerError::InvalidOpcode 11 | | RpcCallerError::SerializationNotSupported 12 | | RpcCallerError::ResourceFailure 13 | | RpcCallerError::NotReady 14 | | RpcCallerError::InvalidTransaction 15 | | RpcCallerError::Internal 16 | | RpcCallerError::InvalidResponseBody 17 | | RpcCallerError::InvalidParameter => ResponseStatus::PsaErrorCommunicationFailure, 18 | RpcCallerError::InvalidRequestBody => ResponseStatus::PsaErrorInvalidArgument, 19 | } 20 | } 21 | } 22 | 23 | impl From for ResponseStatus { 24 | fn from(error: WrapperError) -> Self { 25 | match error { 26 | WrapperError::CallBufferNull 27 | | WrapperError::CallHandleNull 28 | | WrapperError::FailedPbConversion 29 | | WrapperError::InvalidParam 30 | | WrapperError::InvalidOpStatus => ResponseStatus::PsaErrorCommunicationFailure, 31 | } 32 | } 33 | } 34 | 35 | impl From for ResponseStatus { 36 | fn from(error: Error) -> Self { 37 | match error { 38 | Error::PsaCrypto(e) => e.into(), 39 | Error::RpcCaller(e) => e.into(), 40 | Error::Wrapper(e) => e.into(), 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/providers/trusted_service/generate_random.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | use super::Provider; 4 | use parsec_interface::operations::psa_generate_random; 5 | use parsec_interface::requests::Result; 6 | 7 | impl Provider { 8 | pub(super) fn psa_generate_random_internal( 9 | &self, 10 | op: psa_generate_random::Operation, 11 | ) -> Result { 12 | let size = op.size; 13 | 14 | match self.context.generate_random(size) { 15 | Ok(random_bytes) => Ok(psa_generate_random::Result { 16 | random_bytes: random_bytes.into(), 17 | }), 18 | Err(error) => { 19 | format_error!("Generate random status: ", error); 20 | Err(error.into()) 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/utils/cli.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | //! Command Line Interface configuration 4 | 5 | // WARNING: This file should be only updated in a non-breaking way. CLI flags should not be 6 | // removed, new flags should be tested. 7 | // See https://github.com/parallaxsecond/parsec/issues/392 for details. 8 | #![allow(unused_qualifications)] 9 | 10 | use clap::Parser; 11 | 12 | /// Parsec is the Platform AbstRaction for SECurity, a new open-source initiative to provide a 13 | /// common API to secure services in a platform-agnostic way. 14 | /// 15 | /// Parsec documentation is available at: 16 | /// https://parallaxsecond.github.io/parsec-book/index.html 17 | /// 18 | /// Most of Parsec configuration comes from its configuration file. 19 | /// Please check the documentation to find more about configuration: 20 | /// https://parallaxsecond.github.io/parsec-book/user_guides/configuration.html 21 | #[derive(Parser, Debug)] 22 | pub struct Opts { 23 | /// Sets the configuration file path 24 | #[structopt(short, long, default_value = "config.toml")] 25 | pub config: String, 26 | } 27 | -------------------------------------------------------------------------------- /src/utils/global_config.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | use crate::utils::service_builder::DEFAULT_BUFFER_SIZE_LIMIT; 4 | use std::sync::atomic::Ordering; 5 | use std::sync::atomic::{AtomicBool, AtomicUsize}; 6 | 7 | /// Configuration values that affect most or all the 8 | /// components of the service. 9 | #[derive(Default, Debug)] 10 | pub struct GlobalConfig { 11 | log_error_details: AtomicBool, 12 | buffer_size_limit: AtomicUsize, 13 | allow_deprecated: AtomicBool, 14 | } 15 | 16 | impl GlobalConfig { 17 | const fn new() -> Self { 18 | GlobalConfig { 19 | log_error_details: AtomicBool::new(false), 20 | buffer_size_limit: AtomicUsize::new(DEFAULT_BUFFER_SIZE_LIMIT), // 1 MB 21 | allow_deprecated: AtomicBool::new(false), 22 | } 23 | } 24 | 25 | /// Determine whether error logs should include detailed 26 | /// information about the error 27 | pub fn log_error_details() -> bool { 28 | GLOBAL_CONFIG.log_error_details.load(Ordering::Relaxed) 29 | } 30 | 31 | /// Fetch the size limit for buffers within responses (in bytes). 32 | /// information about the error 33 | pub fn buffer_size_limit() -> usize { 34 | GLOBAL_CONFIG.buffer_size_limit.load(Ordering::Relaxed) 35 | } 36 | 37 | /// Determine whether deprecated algorithms and key types are allowed 38 | /// during key generation 39 | pub fn allow_deprecated() -> bool { 40 | GLOBAL_CONFIG.allow_deprecated.load(Ordering::Relaxed) 41 | } 42 | } 43 | 44 | static GLOBAL_CONFIG: GlobalConfig = GlobalConfig::new(); 45 | 46 | pub(super) struct GlobalConfigBuilder { 47 | log_error_details: bool, 48 | buffer_size_limit: Option, 49 | allow_deprecated: bool, 50 | } 51 | 52 | impl GlobalConfigBuilder { 53 | pub fn new() -> Self { 54 | GlobalConfigBuilder { 55 | log_error_details: false, 56 | buffer_size_limit: None, 57 | allow_deprecated: false, 58 | } 59 | } 60 | 61 | pub fn with_log_error_details(mut self, log_error_details: bool) -> Self { 62 | self.log_error_details = log_error_details; 63 | 64 | self 65 | } 66 | 67 | pub fn with_buffer_size_limit(mut self, buffer_size_limit: usize) -> Self { 68 | self.buffer_size_limit = Some(buffer_size_limit); 69 | 70 | self 71 | } 72 | 73 | pub fn with_allow_deprecated(mut self, allow_deprecated: bool) -> Self { 74 | self.allow_deprecated = allow_deprecated; 75 | 76 | self 77 | } 78 | 79 | pub fn build(self) { 80 | GLOBAL_CONFIG 81 | .log_error_details 82 | .store(self.log_error_details, Ordering::Relaxed); 83 | GLOBAL_CONFIG.buffer_size_limit.store( 84 | self.buffer_size_limit.unwrap_or(DEFAULT_BUFFER_SIZE_LIMIT), 85 | Ordering::Relaxed, 86 | ); 87 | GLOBAL_CONFIG 88 | .allow_deprecated 89 | .store(self.allow_deprecated, Ordering::Relaxed); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/utils/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | //! Service utilities 4 | pub mod cli; 5 | pub mod config; 6 | mod global_config; 7 | mod service_builder; 8 | #[cfg(all( 9 | feature = "mbed-crypto-provider", 10 | feature = "pkcs11-provider", 11 | feature = "tpm-provider", 12 | feature = "cryptoauthlib-provider", 13 | feature = "trusted-service-provider", 14 | feature = "direct-authenticator" 15 | ))] 16 | #[cfg(test)] 17 | mod tests; 18 | 19 | pub use global_config::GlobalConfig; 20 | pub use service_builder::ServiceBuilder; 21 | -------------------------------------------------------------------------------- /src/utils/tests/config/providers_different_type.toml: -------------------------------------------------------------------------------- 1 | [core_settings] 2 | # The CI already timestamps the logs 3 | log_timestamp = false 4 | log_error_details = true 5 | 6 | [listener] 7 | listener_type = "DomainSocket" 8 | timeout = 200 # in milliseconds 9 | socket_path = "/tmp/parsec.sock" 10 | 11 | [authenticator] 12 | auth_type = "Direct" 13 | 14 | [[key_manager]] 15 | name = "on-disk-manager" 16 | manager_type = "OnDisk" 17 | store_path = "./mappings" 18 | 19 | [[provider]] 20 | provider_type = "MbedCrypto" 21 | key_info_manager = "on-disk-manager" 22 | 23 | [[provider]] 24 | provider_type = "TrustedService" 25 | key_info_manager = "on-disk-manager" 26 | -------------------------------------------------------------------------------- /src/utils/tests/config/providers_different_type_same_name.toml: -------------------------------------------------------------------------------- 1 | [core_settings] 2 | # The CI already timestamps the logs 3 | log_timestamp = false 4 | log_error_details = true 5 | 6 | [listener] 7 | listener_type = "DomainSocket" 8 | timeout = 200 # in milliseconds 9 | socket_path = "/tmp/parsec.sock" 10 | 11 | [authenticator] 12 | auth_type = "Direct" 13 | 14 | [[key_manager]] 15 | name = "on-disk-manager" 16 | manager_type = "OnDisk" 17 | store_path = "./mappings" 18 | 19 | [[provider]] 20 | name="a-name" 21 | provider_type = "MbedCrypto" 22 | key_info_manager = "on-disk-manager" 23 | 24 | [[provider]] 25 | name="a-name" 26 | provider_type = "TrustedService" 27 | key_info_manager = "on-disk-manager" 28 | -------------------------------------------------------------------------------- /src/utils/tests/config/providers_same_type_default_name.toml: -------------------------------------------------------------------------------- 1 | [core_settings] 2 | # The CI already timestamps the logs 3 | log_timestamp = false 4 | log_error_details = true 5 | 6 | [listener] 7 | listener_type = "DomainSocket" 8 | timeout = 200 # in milliseconds 9 | socket_path = "/tmp/parsec.sock" 10 | 11 | [authenticator] 12 | auth_type = "Direct" 13 | 14 | [[key_manager]] 15 | name = "on-disk-manager" 16 | manager_type = "OnDisk" 17 | store_path = "./mappings" 18 | 19 | [[provider]] 20 | provider_type = "TrustedService" 21 | key_info_manager = "on-disk-manager" 22 | 23 | [[provider]] 24 | provider_type = "TrustedService" 25 | key_info_manager = "on-disk-manager" 26 | -------------------------------------------------------------------------------- /src/utils/tests/config/providers_same_type_different_name.toml: -------------------------------------------------------------------------------- 1 | [core_settings] 2 | # The CI already timestamps the logs 3 | log_timestamp = false 4 | log_error_details = true 5 | 6 | [listener] 7 | listener_type = "DomainSocket" 8 | timeout = 200 # in milliseconds 9 | socket_path = "/tmp/parsec.sock" 10 | 11 | [authenticator] 12 | auth_type = "Direct" 13 | 14 | [[key_manager]] 15 | name = "on-disk-manager" 16 | manager_type = "OnDisk" 17 | store_path = "./mappings" 18 | 19 | [[provider]] 20 | name="trusted-service-provider-0" 21 | provider_type = "TrustedService" 22 | key_info_manager = "on-disk-manager" 23 | 24 | [[provider]] 25 | name="trusted-service-provider-1" 26 | provider_type = "TrustedService" 27 | key_info_manager = "on-disk-manager" 28 | -------------------------------------------------------------------------------- /src/utils/tests/config/providers_same_type_same_name.toml: -------------------------------------------------------------------------------- 1 | [core_settings] 2 | # The CI already timestamps the logs 3 | log_timestamp = false 4 | log_error_details = true 5 | 6 | [listener] 7 | listener_type = "DomainSocket" 8 | timeout = 200 # in milliseconds 9 | socket_path = "/tmp/parsec.sock" 10 | 11 | [authenticator] 12 | auth_type = "Direct" 13 | 14 | [[key_manager]] 15 | name = "on-disk-manager" 16 | manager_type = "OnDisk" 17 | store_path = "./mappings" 18 | 19 | [[provider]] 20 | name="a-name" 21 | provider_type = "TrustedService" 22 | key_info_manager = "on-disk-manager" 23 | 24 | [[provider]] 25 | name="a-name" 26 | provider_type = "TrustedService" 27 | key_info_manager = "on-disk-manager" 28 | -------------------------------------------------------------------------------- /src/utils/tests/mod.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Contributors to the Parsec project. 2 | // SPDX-License-Identifier: Apache-2.0 3 | //! Static config tests to see if the service starts with different configurations. 4 | 5 | use crate::utils::config::ServiceConfig; 6 | use crate::utils::ServiceBuilder; 7 | use anyhow::anyhow; 8 | use log::error; 9 | use std::env; 10 | use std::io::Error; 11 | use std::io::ErrorKind; 12 | 13 | const CONFIG_TOMLS_FOLDER: &str = "src/utils/tests/config"; 14 | 15 | fn config_to_toml(file_name: String) -> ServiceConfig { 16 | let mut new_config_path = env::current_dir() // this is the root of the crate for tests 17 | .unwrap(); 18 | new_config_path.push(CONFIG_TOMLS_FOLDER); 19 | new_config_path.push(file_name.clone()); 20 | if !new_config_path.exists() { 21 | error!("Configuration file {} does not exist", file_name); 22 | panic!(); 23 | } 24 | 25 | let config_file = std::fs::read_to_string(new_config_path.clone()) 26 | .map_err(|e| { 27 | error!( 28 | "Failed to read config file from path: {:#?}\nError: {:#?}", 29 | new_config_path, e 30 | ); 31 | panic!(); 32 | }) 33 | .unwrap(); 34 | toml::from_str(&config_file) 35 | .map_err(|e| { 36 | error!("Failed to parse service configuration ({})", e); 37 | panic!(); 38 | }) 39 | .unwrap() 40 | } 41 | 42 | /// Check that the service throws an error when two providers of the same type are started, 43 | /// without setting a name (therefore they have the same default name). 44 | #[test] 45 | fn providers_same_type_default_name() { 46 | let config_path: String = "providers_same_type_default_name.toml".to_string(); 47 | let config = config_to_toml(config_path); 48 | 49 | let expected_error = anyhow!(Error::new( 50 | ErrorKind::InvalidData, 51 | "duplicate provider names found" 52 | )); 53 | 54 | let err = ServiceBuilder::build_service(&config).unwrap_err(); 55 | assert_eq!(format!("{:#?}", err), format!("{:#?}", expected_error)); 56 | } 57 | 58 | /// Check that the service starts when two providers of the same type have different names. 59 | #[test] 60 | fn providers_same_type_different_name() { 61 | let config_path: String = "providers_same_type_different_name.toml".to_string(); 62 | let config = config_to_toml(config_path); 63 | 64 | let _ = ServiceBuilder::build_service(&config).unwrap(); 65 | } 66 | 67 | /// Check that the service throws an error when two providers of the same type explicitly 68 | /// set the same name. 69 | #[test] 70 | fn providers_same_type_same_name() { 71 | let config_path: String = "providers_same_type_same_name.toml".to_string(); 72 | let config = config_to_toml(config_path); 73 | 74 | let expected_error = anyhow!(Error::new( 75 | ErrorKind::InvalidData, 76 | "duplicate provider names found" 77 | )); 78 | 79 | let err = ServiceBuilder::build_service(&config).unwrap_err(); 80 | assert_eq!(format!("{:#?}", err), format!("{:#?}", expected_error)); 81 | } 82 | 83 | /// Check that the service throws an error when two providers of different types explicitly 84 | /// set the same name. 85 | #[test] 86 | fn providers_different_type_same_name() { 87 | let config_path: String = "providers_different_type_same_name.toml".to_string(); 88 | let config = config_to_toml(config_path); 89 | 90 | let expected_error = anyhow!(Error::new( 91 | ErrorKind::InvalidData, 92 | "duplicate provider names found" 93 | )); 94 | 95 | let err = ServiceBuilder::build_service(&config).unwrap_err(); 96 | assert_eq!(format!("{:#?}", err), format!("{:#?}", expected_error)); 97 | } 98 | 99 | /// Check that the service starts when two providers of different types are declared. 100 | /// (Different default provider names) 101 | #[test] 102 | fn providers_different_type() { 103 | let config_path: String = "providers_different_type.toml".to_string(); 104 | let config = config_to_toml(config_path); 105 | 106 | let _ = ServiceBuilder::build_service(&config).unwrap(); 107 | } 108 | -------------------------------------------------------------------------------- /systemd-daemon/parsec.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Parsec Service 3 | Documentation=https://parallaxsecond.github.io/parsec-book/parsec_service/install_parsec_linux.html 4 | 5 | [Service] 6 | WorkingDirectory=/home/parsec/ 7 | ExecStart=/usr/libexec/parsec/parsec --config /etc/parsec/config.toml 8 | # Systemd hardening 9 | ProtectSystem=full 10 | ProtectHome=true 11 | ProtectHostname=true 12 | ProtectKernelTunables=true 13 | ProtectKernelModules=true 14 | ProtectKernelLogs=true 15 | ProtectControlGroups=true 16 | RestrictRealtime=true 17 | 18 | [Install] 19 | WantedBy=default.target 20 | -------------------------------------------------------------------------------- /test/cross-compile.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2021 Contributors to the Parsec project. 4 | # SPDX-License-Identifier: Apache-2.0 5 | 6 | set -xeuf -o pipefail 7 | 8 | # The "jwt-svid-authenticator" feature is not included yet because of a cross compilation 9 | # problem of BoringSSL. See https://github.com/tikv/grpc-rs/issues/536. Once resolved, 10 | # "all-authenticators" will be used again. 11 | 12 | # Allow the `pkg-config` crate to cross-compile 13 | export PKG_CONFIG_ALLOW_CROSS=1 14 | # Make the `pkg-config` crate use our wrapper 15 | export PKG_CONFIG=$(pwd)/test/pkg-config 16 | 17 | # Set the SYSROOT used by pkg-config 18 | export SYSROOT=/tmp/arm-linux-gnueabihf 19 | # Add the correct libcrypto to the linking process 20 | export RUSTFLAGS="-lcrypto -L/tmp/arm-linux-gnueabihf/lib" 21 | cargo build --features "pkcs11-provider, mbed-crypto-provider, tpm-provider, unix-peer-credentials-authenticator, direct-authenticator" \ 22 | --target armv7-unknown-linux-gnueabihf \ 23 | --config 'target.armv7-unknown-linux-gnueabihf.linker="arm-linux-gnueabihf-gcc"' 24 | 25 | export SYSROOT=/tmp/aarch64-linux-gnu 26 | export RUSTFLAGS="-lcrypto -L/tmp/aarch64-linux-gnu/lib" 27 | # Pull in the TS code 28 | git submodule update --init 29 | cargo build --features "pkcs11-provider, mbed-crypto-provider, tpm-provider, trusted-service-provider, unix-peer-credentials-authenticator, direct-authenticator" \ 30 | --target aarch64-unknown-linux-gnu \ 31 | --config 'target.aarch64-unknown-linux-gnu.linker="aarch64-linux-gnu-gcc"' 32 | 33 | # This is needed because for some reason the i686/i386 libs aren't picked up if we don't toss them around just before... 34 | apt install -y libc6-dev-i386-amd64-cross 35 | export SYSROOT=/tmp/i686-linux-gnu 36 | export RUSTFLAGS="-lcrypto -L/tmp/i686-linux-gnu/lib" 37 | cargo build --features "pkcs11-provider, mbed-crypto-provider, tpm-provider, unix-peer-credentials-authenticator, direct-authenticator, tss-esapi/generate-bindings" --target i686-unknown-linux-gnu 38 | -------------------------------------------------------------------------------- /test/pkg-config: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export PKG_CONFIG_PATH= 4 | export PKG_CONFIG_LIBDIR=$(SYSROOT)/lib/pkgconfig:${SYSROOT}/usr/lib/pkgconfig:${SYSROOT}/usr/share/pkgconfig:$(SYSROOT)/usr/local/lib/pkgconfig 5 | export PKG_CONFIG_SYSROOT_DIR=${SYSROOT} 6 | 7 | exec pkg-config "$@" 8 | -------------------------------------------------------------------------------- /utils/release_tracking.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import re 3 | import os 4 | import subprocess 5 | import sys 6 | 7 | 8 | def run_cargo_build(path): 9 | print(f"cargo build, path: {path}") 10 | command = f'cargo build' 11 | return subprocess.check_output(command, shell=True, cwd=path) 12 | 13 | 14 | def run_cargo_update(path, dep): 15 | print(f"cargo update, dep: {dep}") 16 | command = f'cargo update --package {dep}' 17 | return subprocess.check_output(command, shell=True, cwd=path) 18 | 19 | 20 | def git_toml_deps(toml_path, deps_repo_links, deps_branches): 21 | lines = None 22 | with open(toml_path, 'r') as f: 23 | lines = f.readlines() 24 | 25 | to_update = [] 26 | output_lines = lines + ['[patch.crates-io]\n'] 27 | for line in lines: 28 | for dep in deps_repo_links.keys(): 29 | starter = dep + " =" 30 | if line.startswith(starter): 31 | to_update.append(dep) 32 | new_line = f'git = "{deps_repo_links[dep]}", branch = "{deps_branches[dep]}"' 33 | new_line = starter + ' { ' + new_line + ' }\n' 34 | output_lines.append(new_line) 35 | 36 | for updatable in to_update: 37 | run_cargo_update(os.path.dirname(toml_path), updatable) 38 | 39 | with open(toml_path, 'w') as f: 40 | f.writelines(output_lines) 41 | git_cmd = 'git diff' 42 | print(subprocess.check_output(git_cmd, 43 | shell=True, 44 | cwd=os.path.dirname(toml_path)).decode('utf-8')) 45 | 46 | 47 | def main(argv=[], prog_name=''): 48 | parser = argparse.ArgumentParser(prog='ReleaseTracker', 49 | description='Modifies the parsec Cargo.toml files to use the ' 50 | 'main branches of parallaxsecond dependencies in ' 51 | 'preparation for their publishing and release') 52 | parser.add_argument('paths', nargs='+', help='Absolute paths to the Cargo.toml files') 53 | args = parser.parse_args() 54 | 55 | # The order is important! 56 | parallaxsecond_deps = { 57 | 'psa-crypto-sys': 'rust-psa-crypto', 58 | 'psa-crypto': 'rust-psa-crypto', 59 | 'tss-esapi-sys': 'rust-tss-esapi', 60 | 'tss-esapi': 'rust-tss-esapi', 61 | 'cryptoki-sys': 'rust-cryptoki', 62 | 'cryptoki': 'rust-cryptoki', 63 | 'parsec-interface': 'parsec-interface-rs', 64 | 'parsec-client': 'parsec-client-rust', 65 | } 66 | 67 | repo_links = { repo_name: f"https://github.com/parallaxsecond/{repo_folder}.git" \ 68 | for repo_name, repo_folder in parallaxsecond_deps.items() } 69 | 70 | repo_branches = { repo_name: 'main' for repo_name in parallaxsecond_deps.keys() } 71 | repo_branches['tss-esapi-sys'] = '7.x.y' 72 | repo_branches['tss-esapi'] = '7.x.y' 73 | 74 | for path in args.paths: 75 | git_toml_deps(path, repo_links, repo_branches) 76 | run_cargo_build(os.path.dirname(path)) 77 | 78 | return 0 79 | 80 | 81 | if __name__ == '__main__': 82 | sys.exit(main(sys.argv[1:], sys.argv[0])) 83 | --------------------------------------------------------------------------------