From 431e0e87de1d8b4da6be2221b59501bb94173685 Mon Sep 17 00:00:00 2001 From: zhongjie Date: Tue, 5 Mar 2024 10:34:11 +0800 Subject: [PATCH 1/2] test: adjust workflow and case for recent change Signed-off-by: zhongjie --- .github/workflows/vmsdk-test-python.yaml | 22 ++++++++++++++++++- ...sdk-test-rust.yml => vmsdk-test-rust.yaml} | 11 +++++++++- vmsdk/python/cctrusted_vm/sdk.py | 2 +- vmsdk/python/tests/test_sdk.py | 3 ++- 4 files changed, 34 insertions(+), 4 deletions(-) rename .github/workflows/{vmsdk-test-rust.yml => vmsdk-test-rust.yaml} (70%) diff --git a/.github/workflows/vmsdk-test-python.yaml b/.github/workflows/vmsdk-test-python.yaml index 66461f01..689076d4 100644 --- a/.github/workflows/vmsdk-test-python.yaml +++ b/.github/workflows/vmsdk-test-python.yaml @@ -7,17 +7,37 @@ on: paths: - 'vmsdk/**/*.py' - 'common/**/*.py' + - 'setupenv.sh' + - '.github/workflows/vmsdk-test-python.yaml' pull_request: paths: - 'vmsdk/**/*.py' - 'common/**/*.py' + - 'setupenv.sh' + - '.github/workflows/vmsdk-test-python.yaml' workflow_dispatch: +env: + VMSDK_PYTEST_DIR: 'vmsdk_pytest' + jobs: vmsdk_pytest: runs-on: [self-hosted, tdx-guest] + defaults: + run: + working-directory: ${{env.VMSDK_PYTEST_DIR}} steps: - - uses: actions/checkout@v3 + - name: Clean up intermediate files + continue-on-error: true + run: | + # Remove the intermediate files that could be left + # by previous run with sudo. Otherwise, the checkout + # will fail with permission issue. + sudo rm -fr ./* + - name: Checkout repo + uses: actions/checkout@v4 + with: + path: ${{env.VMSDK_PYTEST_DIR}} - name: Run PyTest for VMSDK run: | set -ex diff --git a/.github/workflows/vmsdk-test-rust.yml b/.github/workflows/vmsdk-test-rust.yaml similarity index 70% rename from .github/workflows/vmsdk-test-rust.yml rename to .github/workflows/vmsdk-test-rust.yaml index eeb65b5e..a2ba2d19 100644 --- a/.github/workflows/vmsdk-test-rust.yml +++ b/.github/workflows/vmsdk-test-rust.yaml @@ -6,17 +6,23 @@ on: - main paths: - 'vmsdk/rust/**/*' + - '.github/workflows/vmsdk-test-rust.yaml' pull_request: paths: - 'vmsdk/rust/**/*' + - '.github/workflows/vmsdk-test-rust.yaml' workflow_dispatch: env: CARGO_TERM_COLOR: always + VMSDK_RUST_TEST_DIR: vmsdk_rust_test jobs: vmsdk_rust_test: runs-on: [self-hosted, tdx-guest] + defaults: + run: + working-directory: ${{env.VMSDK_RUST_TEST_DIR}} steps: - name: Clean up intermediate files continue-on-error: true @@ -26,7 +32,10 @@ jobs: # will fail with permission issue. sudo rm -f vmsdk/rust/cctrusted_vm/Cargo.lock sudo rm -fr vmsdk/rust/cctrusted_vm/target - - uses: actions/checkout@v3 + - name: Checkout repo + uses: actions/checkout@v4 + with: + path: ${{env.VMSDK_RUST_TEST_DIR}} - name: Run tests run: | cd vmsdk/rust/cctrusted_vm/ diff --git a/vmsdk/python/cctrusted_vm/sdk.py b/vmsdk/python/cctrusted_vm/sdk.py index dc224b60..1a715ff6 100644 --- a/vmsdk/python/cctrusted_vm/sdk.py +++ b/vmsdk/python/cctrusted_vm/sdk.py @@ -135,7 +135,7 @@ def get_cc_eventlog(self, start:int = None, count:int = None) -> list: self._cvm.process_eventlog() event_logs = EventLogs(self._cvm.boot_time_event_log, self._cvm.runtime_event_log, - TcgEventLog.TCG_PCCLIENT_FORMAT) + TcgEventLog.TCG_FORMAT_PCCLIENT) event_logs.select(start, count) diff --git a/vmsdk/python/tests/test_sdk.py b/vmsdk/python/tests/test_sdk.py index ee76fe7b..dec10a14 100644 --- a/vmsdk/python/tests/test_sdk.py +++ b/vmsdk/python/tests/test_sdk.py @@ -2,6 +2,7 @@ from cctrusted_base.ccreport import CcReport, CcReportData, CcReportSignature from cctrusted_base.tcg import TcgImrEvent, TcgPcClientImrEvent +from cctrusted_base.tcgcel import TcgTpmsCelEvent import pytest def test_get_default_algorithms(vm_sdk, default_alg_id): @@ -81,7 +82,7 @@ def test_get_cc_eventlog_with_valid_input(vm_sdk): event_count = 0 for e in eventlog: event_count += 1 - assert isinstance(e, (TcgImrEvent, TcgPcClientImrEvent)) + assert isinstance(e, (TcgImrEvent, TcgPcClientImrEvent, TcgTpmsCelEvent)) def test_get_cc_report_with_valid_input(vm_sdk, check_quote_valid_input): """Test get_cc_report() function with valid input.""" From b9515762d2cd30091150b53475c380eadd7fddf1 Mon Sep 17 00:00:00 2001 From: zhongjie Date: Wed, 6 Mar 2024 15:21:39 +0800 Subject: [PATCH 2/2] remove the folder "vmsdk" The latest code for vmsdk can be found here: https://github.com/cc-api/cc-trusted-vmsdk/tree/main Signed-off-by: zhongjie --- .github/workflows/pr-check-rust.yaml | 12 - .github/workflows/publish-pypi-packages.yaml | 5 - .github/workflows/pylicense.yaml | 1 - .github/workflows/pylint.yaml | 3 - .github/workflows/vmsdk-test-python.yaml | 28 +- .github/workflows/vmsdk-test-rust.yaml | 21 +- README.md | 22 +- setupenv.sh | 2 +- vmsdk/README.md | 75 --- vmsdk/python/cc_event_log_cli.py | 40 -- vmsdk/python/cc_imr_cli.py | 39 -- vmsdk/python/cc_quote_cli.py | 89 --- vmsdk/python/cctrusted_vm/__init__.py | 7 - vmsdk/python/cctrusted_vm/cvm.py | 420 ------------- vmsdk/python/cctrusted_vm/sdk.py | 142 ----- vmsdk/python/cctrusted_vm/tdx.py | 22 - vmsdk/python/pyproject.toml | 32 - vmsdk/python/requirements.txt | 2 - vmsdk/python/td_report_cli.py | 28 - vmsdk/python/tests/conftest.py | 106 ---- vmsdk/python/tests/tdx_check.py | 258 -------- vmsdk/python/tests/test_sdk.py | 116 ---- vmsdk/rust/cctrusted_vm/Cargo.toml | 20 - vmsdk/rust/cctrusted_vm/deny.toml | 35 -- vmsdk/rust/cctrusted_vm/src/cvm.rs | 140 ----- vmsdk/rust/cctrusted_vm/src/lib.rs | 3 - vmsdk/rust/cctrusted_vm/src/sdk.rs | 554 ------------------ vmsdk/rust/cctrusted_vm/src/tdvm.rs | 503 ---------------- vmsdk/rust/sample/Cargo.toml | 26 - vmsdk/rust/sample/src/cc-sample-eventlog.rs | 61 -- .../rust/sample/src/cc-sample-measurement.rs | 54 -- vmsdk/rust/sample/src/cc-sample-quote.rs | 55 -- 32 files changed, 45 insertions(+), 2876 deletions(-) delete mode 100644 vmsdk/README.md delete mode 100644 vmsdk/python/cc_event_log_cli.py delete mode 100644 vmsdk/python/cc_imr_cli.py delete mode 100644 vmsdk/python/cc_quote_cli.py delete mode 100644 vmsdk/python/cctrusted_vm/__init__.py delete mode 100644 vmsdk/python/cctrusted_vm/cvm.py delete mode 100644 vmsdk/python/cctrusted_vm/sdk.py delete mode 100644 vmsdk/python/cctrusted_vm/tdx.py delete mode 100644 vmsdk/python/pyproject.toml delete mode 100644 vmsdk/python/requirements.txt delete mode 100644 vmsdk/python/td_report_cli.py delete mode 100644 vmsdk/python/tests/conftest.py delete mode 100644 vmsdk/python/tests/tdx_check.py delete mode 100644 vmsdk/python/tests/test_sdk.py delete mode 100644 vmsdk/rust/cctrusted_vm/Cargo.toml delete mode 100644 vmsdk/rust/cctrusted_vm/deny.toml delete mode 100644 vmsdk/rust/cctrusted_vm/src/cvm.rs delete mode 100644 vmsdk/rust/cctrusted_vm/src/lib.rs delete mode 100644 vmsdk/rust/cctrusted_vm/src/sdk.rs delete mode 100644 vmsdk/rust/cctrusted_vm/src/tdvm.rs delete mode 100644 vmsdk/rust/sample/Cargo.toml delete mode 100644 vmsdk/rust/sample/src/cc-sample-eventlog.rs delete mode 100644 vmsdk/rust/sample/src/cc-sample-measurement.rs delete mode 100644 vmsdk/rust/sample/src/cc-sample-quote.rs diff --git a/.github/workflows/pr-check-rust.yaml b/.github/workflows/pr-check-rust.yaml index 76107628..dd975fd9 100644 --- a/.github/workflows/pr-check-rust.yaml +++ b/.github/workflows/pr-check-rust.yaml @@ -8,16 +8,12 @@ on: - 'common/rust/cctrusted_base/src/**.rs' - 'common/rust/cctrusted_base/src/tdx/**.rs' - 'common/rust/cctrusted_base/src/tpm/**.rs' - - 'vmsdk/rust/cctrusted_vm/src/**.rs' - - 'vmsdk/rust/sample/src/**.rs' - '.github/workflows/pr-check-rust.yaml' pull_request: paths: - 'common/rust/cctrusted_base/src/**.rs' - 'common/rust/cctrusted_base/src/tdx/**.rs' - 'common/rust/cctrusted_base/src/tpm/**.rs' - - 'vmsdk/rust/cctrusted_vm/src/**.rs' - - 'vmsdk/rust/sample/src/**.rs' - '.github/workflows/pr-check-rust.yaml' workflow_dispatch: @@ -45,11 +41,3 @@ jobs: cargo clippy cargo install --locked cargo-deny cargo deny check - - - name: Run cargo check for VM SDK - run: | - cd vmsdk/rust/cctrusted_vm/ - cargo check - cargo fmt -- --check - cargo clippy - cargo deny check \ No newline at end of file diff --git a/.github/workflows/publish-pypi-packages.yaml b/.github/workflows/publish-pypi-packages.yaml index dc5fe786..cfafb802 100644 --- a/.github/workflows/publish-pypi-packages.yaml +++ b/.github/workflows/publish-pypi-packages.yaml @@ -25,8 +25,3 @@ jobs: python3 -m build python3 -m twine upload -u $PYPI_USERNAME -p $PYPI_PASSWORD --repository pypi dist/* popd - - pushd vmsdk/python/ - python3 -m build - python3 -m twine upload -u $PYPI_USERNAME -p $PYPI_PASSWORD --repository pypi dist/* - popd diff --git a/.github/workflows/pylicense.yaml b/.github/workflows/pylicense.yaml index 09eca496..9969e5a1 100644 --- a/.github/workflows/pylicense.yaml +++ b/.github/workflows/pylicense.yaml @@ -4,7 +4,6 @@ on: pull_request: paths: - 'common/python/**' - - 'vmsdk/python/**' workflow_dispatch: jobs: diff --git a/.github/workflows/pylint.yaml b/.github/workflows/pylint.yaml index 323d9be9..4f202a75 100644 --- a/.github/workflows/pylint.yaml +++ b/.github/workflows/pylint.yaml @@ -6,11 +6,9 @@ on: - main paths: - 'common/**/*.py' - - 'vmsdk/**/*.py' pull_request: paths: - 'common/**/*.py' - - 'vmsdk/**/*.py' workflow_dispatch: jobs: @@ -26,7 +24,6 @@ jobs: python3 -m pip install --upgrade pip python3 -m pip install pylint pydocstyle python3 -m pip install -r ./common/python/requirements.txt - python3 -m pip install -r ./vmsdk/python/requirements.txt sudo apt update - name: Analyze python code diff --git a/.github/workflows/vmsdk-test-python.yaml b/.github/workflows/vmsdk-test-python.yaml index 689076d4..9c50977b 100644 --- a/.github/workflows/vmsdk-test-python.yaml +++ b/.github/workflows/vmsdk-test-python.yaml @@ -5,13 +5,11 @@ on: branches: - main paths: - - 'vmsdk/**/*.py' - 'common/**/*.py' - 'setupenv.sh' - '.github/workflows/vmsdk-test-python.yaml' pull_request: paths: - - 'vmsdk/**/*.py' - 'common/**/*.py' - 'setupenv.sh' - '.github/workflows/vmsdk-test-python.yaml' @@ -19,6 +17,7 @@ on: env: VMSDK_PYTEST_DIR: 'vmsdk_pytest' + VMSDK_DIR: 'cc-trusted-vmsdk' jobs: vmsdk_pytest: @@ -34,19 +33,24 @@ jobs: # by previous run with sudo. Otherwise, the checkout # will fail with permission issue. sudo rm -fr ./* - - name: Checkout repo + - name: Checkout cc-trusted-api repo uses: actions/checkout@v4 with: path: ${{env.VMSDK_PYTEST_DIR}} + - name: Checkout cc-trusted-vmsdk repo + uses: actions/checkout@v4 + with: + repository: cc-api/cc-trusted-vmsdk + path: ${{env.VMSDK_PYTEST_DIR}}/${{env.VMSDK_DIR}} - name: Run PyTest for VMSDK run: | set -ex - # Set the "PYTHONDONTWRITEBYTECODE" and "no:cacheprovider" to prevent - # generated some intermediate files by root. Othwerwise, these - # files will fail the action/checkout in the next round of running - # due to the permission issue. - sudo su -c "source setupenv.sh && \ - pushd vmsdk/python/tests && \ - export PYTHONDONTWRITEBYTECODE=1 && \ - python3 -m pytest -p no:cacheprovider -v test_sdk.py && \ - popd" + cd ${{env.VMSDK_DIR}} + # The trick here is that we need to use the local version + # of cctrusted_base instead of the version instaleed by + # setupenv.sh. So uninstall it and reinstall from local. + sudo su -c 'source setupenv.sh && \ + python3 -m pip uninstall -y cctrusted_base && \ + python3 -m pip install ../common/python && \ + cd src/python/tests && \ + python3 -m pytest -v test_sdk.py' diff --git a/.github/workflows/vmsdk-test-rust.yaml b/.github/workflows/vmsdk-test-rust.yaml index a2ba2d19..4d7b7364 100644 --- a/.github/workflows/vmsdk-test-rust.yaml +++ b/.github/workflows/vmsdk-test-rust.yaml @@ -5,17 +5,16 @@ on: branches: - main paths: - - 'vmsdk/rust/**/*' - '.github/workflows/vmsdk-test-rust.yaml' pull_request: paths: - - 'vmsdk/rust/**/*' - '.github/workflows/vmsdk-test-rust.yaml' workflow_dispatch: env: CARGO_TERM_COLOR: always - VMSDK_RUST_TEST_DIR: vmsdk_rust_test + VMSDK_RUST_TEST_DIR: 'vmsdk_rust_test' + VMSDK_DIR: 'cc-trusted-vmsdk' jobs: vmsdk_rust_test: @@ -30,13 +29,21 @@ jobs: # Remove the intermediate files that could be left # by previous run with sudo. Otherwise, the checkout # will fail with permission issue. - sudo rm -f vmsdk/rust/cctrusted_vm/Cargo.lock - sudo rm -fr vmsdk/rust/cctrusted_vm/target - - name: Checkout repo + sudo rm -fr ./* + - name: Checkout cc-trusted-api repo uses: actions/checkout@v4 with: path: ${{env.VMSDK_RUST_TEST_DIR}} + - name: Checkout cc-trusted-vmsdk repo + uses: actions/checkout@v4 + with: + repository: cc-api/cc-trusted-vmsdk + path: ${{env.VMSDK_RUST_TEST_DIR}}/${{env.VMSDK_DIR}} - name: Run tests run: | - cd vmsdk/rust/cctrusted_vm/ + cd ${{env.VMSDK_DIR}}/src/rust/cctrusted_vm + # The trick here is to override the dependencies with local version. + echo "" >> Cargo.toml + echo "[patch.crates-io]" >> Cargo.toml + echo 'cctrusted_base = { path = "../../../../common/rust/cctrusted_base" }' >> Cargo.toml sudo bash -c "export CARGO_TERM_COLOR=always && cargo test --verbose" diff --git a/README.md b/README.md index 267126c0..47472c44 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ Choose correct SDK according to your environment. Installation guide can be foun | SDK | Deployment Scenarios | Installation Guide | | --- | --------------- | -- | | Firmware SDK | Firmware Application | | -| [VM SDK](https://github.com/cc-api/cc-trusted-api/tree/main/vmsdk) | Confidential Virtual Machine | [Guide](vmsdk/README.md) | +| [VM SDK](https://github.com/cc-api/cc-trusted-vmsdk) | Confidential Virtual Machine | [Guide](https://github.com/cc-api/cc-trusted-vmsdk/blob/main/README.md) | | [Confidential Cloud Native Primitives (CCNP)](https://github.com/cc-api/confidential-cloud-native-primitives) | Confidential Cluster/Container | [Guide](https://github.com/cc-api/confidential-cloud-native-primitives/blob/main/deployment/README.md) | ## 5. How to use the APIs @@ -93,12 +93,14 @@ for index in range(CCTrustedVmSdk.inst().get_measurement_count()): LOG.info("HASH: %s", hash_str) ``` -Run [cc_imr_cli.py](vmsdk/python/cc_imr_cli.py) to execute the sample. +Run [cc_imr_cli.py](https://github.com/cc-api/cc-trusted-vmsdk/blob/main/src/python/cc_imr_cli.py) to execute the sample. ``` +$ git clone https://github.com/cc-api/cc-trusted-vmsdk.git +$ cd cc-trusted-vmsdk $ sudo su # source setupenv.sh -# cd vmsdk/python +# cd src/python # python3 cc_imr_cli.py ``` @@ -148,19 +150,21 @@ if quote is not None: quote.dump(is_raw=True) ``` -Run [cc_quote_cli.py](vmsdk/python/cc_quote_cli.py) to execute the sample. +Run [cc_quote_cli.py](https://github.com/cc-api/cc-trusted-vmsdk/blob/main/src/python/cc_quote_cli.py) to execute the sample. ``` +$ git clone https://github.com/cc-api/cc-trusted-vmsdk.git +$ cd cc-trusted-vmsdk $ sudo su # source setupenv.sh -# cd vmsdk/python +# cd src/python # python3 cc_quote_cli.py ``` Below is the example output for `get_cc_report` API on Intel® TDX via VM SDK: ``` -root@tdx-guest:/home/tdx/cc-trusted-api/vmsdk/python# python3 ./cc_quote_cli.py +root@tdx-guest:/home/tdx/cc-trusted-vmsdk/src/python# python3 ./cc_quote_cli.py cctrusted.cvm DEBUG Successful open device node /dev/tdx_guest cctrusted.cvm DEBUG Successful read TDREPORT from /dev/tdx_guest. cctrusted.cvm DEBUG Successful parse TDREPORT. @@ -210,12 +214,14 @@ event_logs = CCTrustedVmSdk.inst().get_cc_eventlog(start, count) event_logs.dump() ``` -Run [cc_event_log_cli.py](vmsdk/python/cc_event_log_cli.py) to execute the sample. +Run [cc_event_log_cli.py](https://github.com/cc-api/cc-trusted-vmsdk/blob/main/src/python/cc_event_log_cli.py) to execute the sample. ``` +$ git clone https://github.com/cc-api/cc-trusted-vmsdk.git +$ cd cc-trusted-vmsdk $ sudo su # source setupenv.sh -# cd vmsdk/python +# cd src/python # python3 cc_event_log_cli.py [-s ] [-c ] ``` diff --git a/setupenv.sh b/setupenv.sh index 84e9e6ba..4800ef28 100644 --- a/setupenv.sh +++ b/setupenv.sh @@ -3,4 +3,4 @@ CURR_DIR=$(pwd) # setup PYTHONPATH -export PYTHONPATH=$PYTHONPATH:$CURR_DIR/common/python/:$CURR_DIR/vmsdk/python +export PYTHONPATH=$PYTHONPATH:$CURR_DIR/common/python/ diff --git a/vmsdk/README.md b/vmsdk/README.md deleted file mode 100644 index 8e6fa09e..00000000 --- a/vmsdk/README.md +++ /dev/null @@ -1,75 +0,0 @@ - -# SDK for CC Trusted API in Confidential VM - -In confidential VM, the trusted primitives (measurement, eventlog, quote) normally -can be accessed via device node like /dev/tpm0, sysfs etc, and different vendor -may provides the different definitions. - -This VMSDK following the CC Trusted API design -shields the difference introduced by the platform and provides user with unified usage -in the confidential virtual machine environments. - -![](/docs/cc-trusted-primitives-vendor.png) - -_NOTE: `VMSDK` currently supports Python, and it will provide support on Rust and Golang later._ - -## How to use VMSDK - -VMSDK is supposed to provide trusted primitives (measurement, eventlog, quote) of CVM. -All below steps are supposed to run in a CVM, such as Intel® TD. - -### Installation - -`VMSDK` package is already available in PyPI. You can install the SDK simply by: - -``` -$ pip install cctrusted-vm -``` - -If you would like to run from source code. Try: - -``` -$ git clone https://github.com/cc-api/cc-trusted-api.git -$ cd cc-trusted-api -$ source setupenv.sh -``` - -### Run CLI tool - -It provides 3 CLI tools for quick usage of Python VMSDK. - -- [cc_event_log_cli.py](./python/cc_event_log_cli.py): Print event log of CVM. -- [cc_imr_cli.py](./python/cc_imr_cli.py): Print algorithm and hash od Integrity Measurement Registers (IMR). -- [cc_quote_cli.py](./python/cc_quote_cli.py): Print quote of CVM. - - -How to run the CLI tool: - -``` -$ git clone https://github.com/cc-api/cc-trusted-api.git -$ cd cc-trusted-api -$ sudo su -$ source setupenv.sh -$ python3 vmsdk/python/cc_imr_cli.py -``` -_NOTE: The CLI tool needs to run via root user._ - -Below is example output of `cc_imr_cli.py`. - -![](/docs/imr-cli-output.png) - - -### Run Tests - -It provides test cases for Python VMSDK. Run tests with below commands. - -``` -$ git clone https://github.com/cc-api/cc-trusted-api.git -$ cd cc-trusted-api -$ sudo su -$ source setupenv.sh -$ python3 -m pip install pytest -$ python3 -m pytest -v ./vmsdk/python/tests/test_sdk.py -``` - -_NOTE: The tests need to run via root user._ diff --git a/vmsdk/python/cc_event_log_cli.py b/vmsdk/python/cc_event_log_cli.py deleted file mode 100644 index ec9410e9..00000000 --- a/vmsdk/python/cc_event_log_cli.py +++ /dev/null @@ -1,40 +0,0 @@ -""" -Command line to dump the cc event logs -""" -import logging -import argparse -import os -from cctrusted_base.api import CCTrustedApi -from cctrusted_vm.cvm import ConfidentialVM -from cctrusted_vm.sdk import CCTrustedVmSdk - - -LOG = logging.getLogger(__name__) - -logging.basicConfig(level=logging.NOTSET, format='%(name)s %(levelname)-8s %(message)s') - -def main(): - """Example cc event log fetching utility.""" - if ConfidentialVM.detect_cc_type() == CCTrustedApi.TYPE_CC_NONE: - LOG.error("This is not a confidential VM!") - return - if os.geteuid() != 0: - LOG.error("Please run as root which is required for this example!") - return - - parser = argparse.ArgumentParser( - description="The example utility to fetch CC event logs") - parser.add_argument('-s', type=int, - help='index of first event log to fetch', dest='start') - parser.add_argument("-c", type=int, help="number of event logs to fetch", - dest="count") - args = parser.parse_args() - - event_logs = CCTrustedVmSdk.inst().get_cc_eventlog(args.start, args.count) - if event_logs is not None: - LOG.info("Total %d of event logs fetched.", len(event_logs)) - for event in event_logs: - event.dump() - -if __name__ == "__main__": - main() diff --git a/vmsdk/python/cc_imr_cli.py b/vmsdk/python/cc_imr_cli.py deleted file mode 100644 index 6309377b..00000000 --- a/vmsdk/python/cc_imr_cli.py +++ /dev/null @@ -1,39 +0,0 @@ - -""" -Command line to dump the integrated measurement register -""" -import logging -import os -from cctrusted_base.api import CCTrustedApi -from cctrusted_vm.cvm import ConfidentialVM -from cctrusted_vm.sdk import CCTrustedVmSdk - -LOG = logging.getLogger(__name__) - -logging.basicConfig(level=logging.NOTSET, format='%(name)s %(levelname)-8s %(message)s') - -def main(): - """Example to call get_cc_measurement and dump the result to stdout.""" - if ConfidentialVM.detect_cc_type() == CCTrustedApi.TYPE_CC_NONE: - LOG.error("This is not a confidential VM!") - return - if os.geteuid() != 0: - LOG.error("Please run as root which is required for this example!") - return - - count = CCTrustedVmSdk.inst().get_measurement_count() - LOG.info("Measurement Count: %d", count) - for index in range(CCTrustedVmSdk.inst().get_measurement_count()): - alg = CCTrustedVmSdk.inst().get_default_algorithms() - imr = CCTrustedVmSdk.inst().get_cc_measurement([index, alg.alg_id]) - digest_obj = imr.digest(alg.alg_id) - - hash_str = "" - for hash_item in digest_obj.hash: - hash_str += "".join([f"{hash_item:02x}", " "]) - - LOG.info("Algorithms: %s", str(alg)) - LOG.info("HASH: %s", hash_str) - -if __name__ == "__main__": - main() diff --git a/vmsdk/python/cc_quote_cli.py b/vmsdk/python/cc_quote_cli.py deleted file mode 100644 index bc5f501e..00000000 --- a/vmsdk/python/cc_quote_cli.py +++ /dev/null @@ -1,89 +0,0 @@ -""" -Command line to get quote -""" -import argparse -import base64 -import logging -import os -import random -from cctrusted_base.api import CCTrustedApi -from cctrusted_vm.cvm import ConfidentialVM -from cctrusted_vm.sdk import CCTrustedVmSdk - -LOG = logging.getLogger(__name__) - -logging.basicConfig(level=logging.NOTSET, format="%(name)s %(levelname)-8s %(message)s") - -OUT_FORMAT_RAW = "raw" -OUT_FORMAT_HUMAN = "human" - -def out_format_validator(out_format): - """Validator (callback for ArgumentParser) of output format - - Args: - out_format: User specified output format. - - Returns: - Validated value of the argument. - - Raises: - ValueError: An invalid value is given by user. - """ - if out_format not in (OUT_FORMAT_HUMAN, OUT_FORMAT_RAW): - raise ValueError - return out_format - -def make_nounce(): - """Make nonce for demo. - - Returns: - A nonce for demo that is base64 encoded bytes reprensting a 64 bits unsigned integer. - """ - # Generte a 64 bits unsigned integer randomly (range from 0 to 64 bits max). - rand_num = random.randrange(0x0, 0xFFFFFFFFFFFFFFFF, 1) - nonce = base64.b64encode(rand_num.to_bytes(8, "little")) - return nonce - -def make_userdata(): - """Make userdata for demo. - - Returns: - User data that is base64 encoded bytes for demo. - """ - userdata = base64.b64encode(bytes("demo user data", "utf-8")) - return userdata - -def main(): - """Example to call get_cc_report and dump the result to stdout.""" - if ConfidentialVM.detect_cc_type() == CCTrustedApi.TYPE_CC_NONE: - LOG.error("This is not a confidential VM!") - return - if os.geteuid() != 0: - LOG.error("Please run as root which is required for this example!") - return - - parser = argparse.ArgumentParser() - parser.add_argument( - "--out-format", - action="store", - default=OUT_FORMAT_RAW, - dest="out_format", - help="Output format: raw/human. Default raw.", - type=out_format_validator - ) - args = parser.parse_args() - - nonce = make_nounce() - LOG.info("demo random number in base64: %s", nonce.decode("utf-8")) - userdata = make_userdata() - LOG.info("demo user data in base64: %s", userdata.decode("utf-8")) - - quote = CCTrustedVmSdk.inst().get_cc_report(nonce, userdata) - if quote is not None: - quote.dump(args.out_format == OUT_FORMAT_RAW) - else: - LOG.error("Fail to get Quote!") - LOG.error("Please double check the log and your config!") - -if __name__ == "__main__": - main() diff --git a/vmsdk/python/cctrusted_vm/__init__.py b/vmsdk/python/cctrusted_vm/__init__.py deleted file mode 100644 index 93490e59..00000000 --- a/vmsdk/python/cctrusted_vm/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -Package to provide CC trusted API for confidential VM -""" - -# pylint: disable=syntax-error -from cctrusted_vm.sdk import* -from cctrusted_vm.tdx import * diff --git a/vmsdk/python/cctrusted_vm/cvm.py b/vmsdk/python/cctrusted_vm/cvm.py deleted file mode 100644 index 88d0d1cf..00000000 --- a/vmsdk/python/cctrusted_vm/cvm.py +++ /dev/null @@ -1,420 +0,0 @@ -""" -Confidential VM class manages following items: - -1. Confidential device node like /dev/tdx-guest or /dev/sev-guest -2. Event log table from memory -3. IMR (integrated measurement register) - -""" -import base64 -import hashlib -import os -import logging -import struct -import fcntl -from abc import abstractmethod -from cctrusted_base.api import CCTrustedApi -from cctrusted_base.imr import TcgIMR -from cctrusted_base.ccreport import CcReport -from cctrusted_base.tcg import TcgAlgorithmRegistry -from cctrusted_base.tdx.common import TDX_VERSION_1_0, TDX_VERSION_1_5 -from cctrusted_base.tdx.rtmr import TdxRTMR -from cctrusted_base.tdx.quote import TdxQuoteReq10, TdxQuoteReq15 -from cctrusted_base.tdx.report import TdxReportReq10, TdxReportReq15 - -LOG = logging.getLogger(__name__) - -class ConfidentialVM: - - _inst = None - - def __init__(self, cctype): - self._cc_type:int = cctype - self._is_init:bool = False - self._imrs:dict[int, TcgIMR] = {} - self._boot_time_event_log:bytes = None - self._runtime_event_log = None - - @property - def cc_type(self) -> int: - """CC type like TYPE_CC_TDX, TYPE_CC_SEV etc.""" - return self._cc_type - - @property - @abstractmethod - def default_algo_id(self): - """Default algorithms ID supported by this Confidential VM.""" - raise NotImplementedError("Should be implemented by inherited class") - - @property - @abstractmethod - def version(self): - """Version of CC VM.""" - raise NotImplementedError("Should be implemented by inherited class") - - @property - def imrs(self) -> list[TcgIMR]: - """The array of integrated measurement registers (IMR).""" - return self._imrs - - @property - def cc_type_str(self): - """the CC type string.""" - return CCTrustedApi.cc_type_str[self.cc_type] - - @property - def boot_time_event_log(self): - """boot time event log data blob.""" - return self._boot_time_event_log - - @property - def runtime_event_log(self): - """runtime event log data blob""" - return self._runtime_event_log - - def init(self) -> bool: - """Initialize the CC stub and environment. - - Returns: - Success or not - """ - if self._is_init: - return True - - if not self.process_cc_report(): - return False - - if not self.process_eventlog(): - return False - - self._is_init = True - return True - - @staticmethod - def detect_cc_type(): - """Detect the type of current confidential VM""" - # TODO: refine the justification - for devpath in TdxVM.DEVICE_NODE_PATH.values(): - if os.path.exists(devpath): - return CCTrustedApi.TYPE_CC_TDX - return CCTrustedApi.TYPE_CC_NONE - - @abstractmethod - def process_cc_report(self, report_data=None) -> bool: - """Process the confidential computing REPORT. - - Returns: - Success or not. - """ - raise NotImplementedError("Should be implemented by inherited class") - - @abstractmethod - def process_eventlog(self) -> bool: - """Process the event log. - - Returns: - Success or not. - """ - raise NotImplementedError("Should be implemented by inherited class") - - @abstractmethod - def get_cc_report(self, nonce: bytearray, data: bytearray, extraArgs) -> CcReport: - """Get the CcReport (i.e. quote) for given nonce and data. - - The CcReport is signing of attestation data (IMR values or hashes of IMR - values), made by a trusted foundation (TPM) using a key trusted by the - verifier. - - Different trusted foundation may use different quote format. - - Args: - nonce (bytearray): against replay attacks. - data (bytearray): user data - extraArgs: for TPM, it will be given list of IMR/PCRs - - Returns: - The ``CcReport`` object. - """ - raise NotImplementedError("Should be implemented by inherited class") - - def dump(self): - """Dump confidential VM information.""" - LOG.info("======================================") - LOG.info("CVM type = %s", self.cc_type_str) - LOG.info("CVM version = %s", self.version) - LOG.info("======================================") - - @staticmethod - def inst(): - """Singleton interface for the instance of CcLinuxStub""" - if ConfidentialVM._inst is None: - obj = None - cc_type = ConfidentialVM.detect_cc_type() - if cc_type is CCTrustedApi.TYPE_CC_TDX: - obj = TdxVM() - else: - LOG.error("Unsupported confidential environment.") - return None - - if obj is not None and obj.init(): - ConfidentialVM._inst = obj - else: - LOG.error("Fail to initialize the confidential VM.") - return ConfidentialVM._inst - -class TdxVM(ConfidentialVM): - - DEVICE_NODE_PATH = { - TDX_VERSION_1_0: "/dev/tdx-guest", - TDX_VERSION_1_5: "/dev/tdx_guest" - } - - IOCTL_GET_REPORT = { - TDX_VERSION_1_0: int.from_bytes(struct.pack('Hcb', 0x08c0, b'T', 1), 'big'), - TDX_VERSION_1_5: int.from_bytes(struct.pack('Hcb', 0x40c4, b'T', 1),'big') - } - """ - TDX v1.0 reference: arch/x86/include/uapi/asm/tdx.h in kernel source - TDX ioctl command layout (bits): - command dir(2) size(14) type(8) nr(8) - TDX_CMD_GET_REPORT 11 00,0000,0000,1000 (0xc008) b'T' 0000,0001 (1) - Convert the higher 16 bits from little-endian to big-endian: - 0xc008 -> 0x08c0 - - TDX v1.5 reference: include/uapi/linux/tdx-guest.h in kernel source - TDX ioctl command layout (bits): - command dir(2) size(14bit) type(8bit) nr(8bit) - TDX_CMD_GET_REPORT0 11 00,0100,0100,0000 (0xc440) b'T' 0000,0001 (1) - Convert the higher 16 bits from little-endian to big-endian: - 0xc440 -> 0x40c4 - """ - - IOCTL_GET_QUOTE = { - TDX_VERSION_1_0: int.from_bytes(struct.pack('Hcb', 0x0880, b'T', 2), 'big'), - TDX_VERSION_1_5: int.from_bytes(struct.pack('Hcb', 0x1080, b'T', 4),'big') - } - """ - TDX v1.0 reference: arch/x86/include/uapi/asm/tdx.h in kernel source - TDX ioctl command layout (bits): - command dir(2) size(14) type(8) nr(8) - TDX_CMD_GET_QUOTE 10 00,0000,0000,1000 (0x8008) b'T' 0000,0010 (2) - Convert the higher 16 bits from little-endian to big-endian: - 0x8008 -> 0x0880 - - TDX v1.5 Reference: include/uapi/linux/tdx-guest.h in kernel source - TDX ioctl command layout (bits): - command dir(2) size(14bit) type(8bit) nr(8bit) - TDX_CMD_GET_QUOTE 10 00,0000,0001,0000 (0x8010) b'T' 0000,0100 (4) - Convert the higher 16 bits from little-endian to big-endian - 0x8010 -> 0x1080 - """ - - # The length of the tdquote 4 pages - TDX_QUOTE_LEN = 4 * 4096 - - # ACPI table containing the event logs - ACPI_TABLE_FILE = "/sys/firmware/acpi/tables/CCEL" - ACPI_TABLE_DATA_FILE = "/sys/firmware/acpi/tables/data/CCEL" - IMA_DATA_FILE = "/sys/kernel/security/integrity/ima/ascii_runtime_measurements" - - def __init__(self): - ConfidentialVM.__init__(self, CCTrustedApi.TYPE_CC_TDX) - self._version:str = None - self._tdreport = None - - @property - def version(self): - if self._version is None: - for key, value in TdxVM.DEVICE_NODE_PATH.items(): - if os.path.exists(value): - self._version = key - return self._version - - @property - def default_algo_id(self): - return TcgAlgorithmRegistry.TPM_ALG_SHA384 - - @property - def tdreport(self): - """TDREPORT structure""" - return self._tdreport - - def process_cc_report(self, report_data=None) -> bool: - """Process the confidential computing REPORT.""" - dev_path = self.DEVICE_NODE_PATH[self.version] - try: - tdx_dev = os.open(dev_path, os.O_RDWR) - except (PermissionError, IOError, OSError): - LOG.error("Fail to open device node %s", dev_path) - return False - - LOG.debug("Successful open device node %s", dev_path) - - if self.version is TDX_VERSION_1_0: - tdreport_req = TdxReportReq10() - elif self.version is TDX_VERSION_1_5: - tdreport_req = TdxReportReq15() - - # pylint: disable=E1111 - reqbuf = tdreport_req.prepare_reqbuf(report_data) - try: - fcntl.ioctl(tdx_dev, self.IOCTL_GET_REPORT[self.version], reqbuf) - except OSError: - LOG.error("Fail to execute ioctl for file %s", dev_path) - os.close(tdx_dev) - return False - - LOG.debug("Successful read TDREPORT from %s.", dev_path) - os.close(tdx_dev) - - # pylint: disable=E1111 - tdreport = tdreport_req.process_output(reqbuf) - if tdreport is not None: - LOG.debug("Successful parse TDREPORT.") - - # process IMR - self._tdreport = tdreport - self._imrs[0] = TdxRTMR(0, tdreport.td_info.rtmr_0) - self._imrs[1] = TdxRTMR(1, tdreport.td_info.rtmr_1) - self._imrs[2] = TdxRTMR(2, tdreport.td_info.rtmr_2) - self._imrs[3] = TdxRTMR(3, tdreport.td_info.rtmr_3) - - return True - - def process_eventlog(self) -> bool: - """Process the event log - - Fetch boot time event logs from CCEL table and CCEL data file - Save contents into TdxVM attributes - - Args: - None - - Returns: - A boolean indicating the status of process_eventlog - True means the function runs successfully - False means error occurred in event log processing - - Raises: - PermissionError: An error occurred when accessing CCEL files - """ - - # verify if CCEL files existed - if (not os.path.exists(TdxVM.ACPI_TABLE_FILE) or - not os.path.exists(TdxVM.ACPI_TABLE_DATA_FILE)): - LOG.error("Failed to find TDX CCEL table at %s or CCEL data file at %s", - TdxVM.ACPI_TABLE_FILE, TdxVM.ACPI_TABLE_DATA_FILE) - return False - - try: - with open(TdxVM.ACPI_TABLE_FILE, "rb") as f: - ccel_data = f.read() - assert len(ccel_data) > 0 and ccel_data[0:4] == b'CCEL', \ - "Invalid CCEL table" - except (PermissionError, OSError): - LOG.error("Need root permission to open file %s", TdxVM.ACPI_TABLE_FILE) - return False - - try: - with open(TdxVM.ACPI_TABLE_DATA_FILE, "rb") as f: - self._boot_time_event_log = f.read() - assert len(self._boot_time_event_log) > 0 - except (PermissionError, OSError): - LOG.error("Need root permission to open file %s", TdxVM.ACPI_TABLE_DATA_FILE) - return False - - # Check if the identifier 'ima_hash=sha384' exists on kernel cmdline - # If yes, suppose IMA over RTMR enabled in kernel (IMA over RTMR patch included in - # https://github.com/intel/tdx-tools/blob/tdx-1.5/build/common/patches-tdx-kernel-MVP-KERNEL-6.2.16-v5.0.tar.gz) - # If not, suppose IMA over RTMR not enabled in kernel - with open("/proc/cmdline", encoding="utf-8") as cmdfile: - cmdline = cmdfile.read().splitlines() - if "ima_hash=sha384" not in cmdline[0].split(" "): - return True - - if not os.path.exists(TdxVM.IMA_DATA_FILE): - LOG.error("Failed to find IMA binary measurements at %s", TdxVM.IMA_DATA_FILE) - return True - - try: - with open(TdxVM.IMA_DATA_FILE, "rb") as f: - self._runtime_event_log = f.read() - if len(self._runtime_event_log) == 0: - LOG.info("Empty IMA measurement found at %s", TdxVM.IMA_DATA_FILE) - except (PermissionError, OSError): - LOG.error("Need root permission to open file %s", TdxVM.IMA_DATA_FILE) - - return True - - - def get_cc_report(self, nonce: bytearray, data: bytearray, extraArgs) -> CcReport: - """Get CcReport (i.e. TD Quote in the context of TDX). - - This depends on Quote Generation Service. Please reference "Whitepaper: - Linux* Stacks for Intel® Trust Domain Extensions (4.3 Attestation)" for - settings: - https://www.intel.com/content/www/us/en/content-details/790888/whitepaper-linux-stacks-for-intel-trust-domain-extensions-1-5.html - - 1. Set up the host: follow 4.3.1 ~ 4.3.4. - 2. Set up the guest: follow "Approach 2: Get quote via TDG.VP.VMCALL.GETQUOTE" - in "4.3.5.1 Launch TD with Quote Generation Support". - - Args: - nonce (bytearray): against replay attacks. - data (bytearray): user data - extraArgs: for TPM, it will be given list of IMR/PCRs - - Returns: - The ``CcReport`` object. Return None if it fails. - - Raises: - binascii.Error when the parameter "nonce" or "data" is not base64 encoded. - """ - - # Prepare user defined data which could include nonce - if nonce is not None: - nonce = base64.b64decode(nonce, validate=True) - if data is not None: - data = base64.b64decode(data, validate=True) - report_bytes = None - input_data = None - if nonce is None and data is None: - LOG.info("No report data, generating default quote") - else: - LOG.info("Calculate report data by nonce and user data") - hash_algo = hashlib.sha512() - if nonce is not None: - hash_algo.update(bytes(nonce)) - if data is not None: - hash_algo.update(bytes(data)) - input_data = hash_algo.digest() - self.process_cc_report(input_data) - report_bytes = self.tdreport.data - - # Open TDX guest device node - dev_path = self.DEVICE_NODE_PATH[self.version] - try: - tdx_dev = os.open(dev_path, os.O_RDWR) - except (PermissionError, IOError, OSError) as e: - LOG.error("Fail to open device node %s: %s", dev_path, str(e)) - return None - LOG.debug("Successful open device node %s", dev_path) - - # Run ioctl command to get TD Quote - if self.version is TDX_VERSION_1_0: - quote_req = TdxQuoteReq10() - elif self.version is TDX_VERSION_1_5: - quote_req = TdxQuoteReq15() - # pylint: disable=E1111 - req_buf = quote_req.prepare_reqbuf(report_bytes) - try: - fcntl.ioctl(tdx_dev, self.IOCTL_GET_QUOTE[self.version], req_buf) - except OSError as e: - LOG.error("Fail to execute ioctl for file %s: %s", dev_path, str(e)) - os.close(tdx_dev) - return None - LOG.debug("Successful get Quote from %s.", dev_path) - os.close(tdx_dev) - - # Get TD Quote from ioctl command output - return quote_req.process_output(req_buf) diff --git a/vmsdk/python/cctrusted_vm/sdk.py b/vmsdk/python/cctrusted_vm/sdk.py deleted file mode 100644 index 1a715ff6..00000000 --- a/vmsdk/python/cctrusted_vm/sdk.py +++ /dev/null @@ -1,142 +0,0 @@ -""" -The VMSDK implementation for ``CCTrusted`` API. -""" -import logging - -# pylint: disable=unused-import -from cctrusted_base.api import CCTrustedApi -from cctrusted_base.imr import TcgIMR -from cctrusted_base.ccreport import CcReport -from cctrusted_base.eventlog import EventLogs -from cctrusted_base.eventlog import TcgEventLog -from cctrusted_base.tcg import TcgAlgorithmRegistry -from cctrusted_vm.cvm import ConfidentialVM - - -LOG = logging.getLogger(__name__) - -class CCTrustedVmSdk(CCTrustedApi): - - """CC trusted API implementation for a general CVM.""" - - _inst = None - - @classmethod - def inst(cls): - """Singleton instance function.""" - if cls._inst is None: - cls._inst = cls() - return cls._inst - - def __init__(self): - """Contrustor of CCTrustedCVM.""" - self._cvm = ConfidentialVM.inst() - - def get_default_algorithms(self) -> TcgAlgorithmRegistry: - """Get the default Digest algorithms supported by trusted foundation. - - Different trusted foundation may support different algorithms, for example - the Intel TDX use SHA384, TPM uses SHA256. - - Beyond the default digest algorithm, some trusted foundation like TPM - may support multiple algorithms. - - Returns: - The default algorithms. - """ - return TcgAlgorithmRegistry(self._cvm.default_algo_id) - - def get_measurement_count(self) -> int: - """Get the count of measurement register. - - Different trusted foundation may provide different count of measurement - register. For example, Intel TDX TDREPORT provides the 4 measurement - register by default. TPM provides 24 measurement (0~16 for SRTM and 17~24 - for DRTM). - - Beyond the real mesurement register, some SDK may extend virtual measurement - reigster for additional trust chain like container, namespace, cluster in - cloud native paradiagm. - - Returns: - The count of measurement registers - """ - return len(self._cvm.imrs) - - def get_cc_measurement(self, imr_select:[int, int]) -> TcgIMR: - """Get measurement register according to given selected index and algorithms - - Each trusted foundation in CC environment provides the multiple measurement - registers, the count is update to ``get_measurement_count()``. And for each - measurement register, it may provides multiple digest for different algorithms. - - Args: - imr_select ([int, int]): The first is index of measurement register, - the second is the alrogithms ID - - Returns: - The object of TcgIMR - """ - imr_index = imr_select[0] - algo_id = imr_select[1] - - if imr_index not in self._cvm.imrs: - LOG.error("Invalid select index for IMR.") - return None - - if algo_id is None or algo_id is TcgAlgorithmRegistry.TPM_ALG_ERROR: - algo_id = self._cvm.default_algo_id - - # Re-do the processing to fetch the latest measurements - self._cvm.process_cc_report() - - return self._cvm.imrs[imr_index] - - def get_cc_report( - self, - nonce: bytearray = None, - data: bytearray = None, - extraArgs = None - ) -> CcReport: - """Get the CcReport (i.e. quote) for given nonce and data. - - The CcReport is signing of attestation data (IMR values or hashes of IMR - values), made by a trusted foundation (TPM) using a key trusted by the - verifier. - - Different trusted foundation may use different quote format. - - Args: - nonce (bytearray): against replay attacks. - data (bytearray): user data - extraArgs: for TPM, it will be given list of IMR/PCRs - - Returns: - The ``CcReport`` object. Return None if it fails. - """ - return self._cvm.get_cc_report(nonce, data, extraArgs) - - def get_cc_eventlog(self, start:int = None, count:int = None) -> list: - """Get eventlog for given index and count. - - TCG log in Eventlog. Verify to spoof events in the TCG log, hence defeating - remotely-attested measured-boot. - To measure the full CC runtime environment, the eventlog may include addtional - OS type and cloud native type event beyond the measured-boot. - - Args: - start(int): the first index of event log to fetch - count(int): the number of event logs to fetch - - Returns: - Parsed event logs following TCG Spec. - """ - # Re-do the processing to fetch the latest event logs - self._cvm.process_eventlog() - - event_logs = EventLogs(self._cvm.boot_time_event_log, self._cvm.runtime_event_log, - TcgEventLog.TCG_FORMAT_PCCLIENT) - - event_logs.select(start, count) - - return event_logs.event_logs diff --git a/vmsdk/python/cctrusted_vm/tdx.py b/vmsdk/python/cctrusted_vm/tdx.py deleted file mode 100644 index 5c333562..00000000 --- a/vmsdk/python/cctrusted_vm/tdx.py +++ /dev/null @@ -1,22 +0,0 @@ -""" -Provide addtional TDVM SDK inherited from general CVM SDK. -""" - -from cctrusted_base.tdx.report import TdReport -from cctrusted_vm.sdk import CCTrustedVmSdk -from cctrusted_vm.cvm import TdxVM - -class CCTrustedTdvmSdk(CCTrustedVmSdk): - - """Inherited SDK class for TDVM only.""" - - def get_tdreport(self) -> TdReport: - """Get TDX Report - - TDREPORT data structure generated by TDG.MR.REPORT instruction in Intel TDX. - - Returns: - TdReport object - """ - assert isinstance(self._cvm, TdxVM) - return self._cvm.tdreport diff --git a/vmsdk/python/pyproject.toml b/vmsdk/python/pyproject.toml deleted file mode 100644 index 64676db3..00000000 --- a/vmsdk/python/pyproject.toml +++ /dev/null @@ -1,32 +0,0 @@ -[project] -name = "cctrusted_vm" -version = "0.3.1" -authors = [ - { name="Lu, Ken", email="ken.lu@intel.com" }, - { name="Zhang, Wenhui", email="wenhui.zhang@bytedance.com" }, -] -description = "CC Trusted API VM SDK" -readme = "README.md" -license = { text="Apache Software License" } -requires-python = ">=3.6" -classifiers = [ - "Programming Language :: Python :: 3", - "License :: OSI Approved :: Apache Software License", - "Operating System :: POSIX :: Linux", -] -dependencies = [ - "cctrusted_base", - "pytest", -] - -[project.urls] -"Homepage" = "https://github.com/cc-api/cc-trusted-api" -"Bug Tracker" = "https://github.com/cc-api/cc-trusted-api/issues" - -[build-system] -requires = ["setuptools", "wheel"] -build-backend = "setuptools.build_meta" - -[tool.setuptools.packages.find] -where=["."] -include=["cctrusted_vm*"] diff --git a/vmsdk/python/requirements.txt b/vmsdk/python/requirements.txt deleted file mode 100644 index 5f95c9c3..00000000 --- a/vmsdk/python/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -cctrusted_base -pytest diff --git a/vmsdk/python/td_report_cli.py b/vmsdk/python/td_report_cli.py deleted file mode 100644 index 87e801ef..00000000 --- a/vmsdk/python/td_report_cli.py +++ /dev/null @@ -1,28 +0,0 @@ - -""" -Command line to dump the integrated measurement register -""" -import logging -import os -from cctrusted_base.api import CCTrustedApi -from cctrusted_vm.cvm import ConfidentialVM -from cctrusted_vm.tdx import CCTrustedTdvmSdk - -LOG = logging.getLogger(__name__) - -logging.basicConfig(level=logging.NOTSET, format="%(name)s %(levelname)-8s %(message)s") - -def main(): - """Example to call get_tdreport and dump the result to stdout.""" - if ConfidentialVM.detect_cc_type() != CCTrustedApi.TYPE_CC_TDX: - LOG.error("This is not a TD VM!") - return - if os.geteuid() != 0: - LOG.error("Please run as root which is required for this example!") - return - - tdreport = CCTrustedTdvmSdk.inst().get_tdreport() - tdreport.dump() - -if __name__ == "__main__": - main() diff --git a/vmsdk/python/tests/conftest.py b/vmsdk/python/tests/conftest.py deleted file mode 100644 index 006fb763..00000000 --- a/vmsdk/python/tests/conftest.py +++ /dev/null @@ -1,106 +0,0 @@ -"""Local conftest.py containing directory-specific hook implementations.""" - -import pytest -from cctrusted_base.api import CCTrustedApi -from cctrusted_base.tcg import TcgAlgorithmRegistry -from cctrusted_base.tdx.rtmr import TdxRTMR -from cctrusted_vm.cvm import ConfidentialVM -from cctrusted_vm.sdk import CCTrustedVmSdk -import tdx_check - -cnf_default_alg = { - CCTrustedApi.TYPE_CC_TDX: TcgAlgorithmRegistry.TPM_ALG_SHA384 -} -"""Configurations of default algorithm. -The configurations could be different for different confidential VMs. -e.g. TDX use sha384 as the default. -""" - -cnf_measurement_cnt = { - CCTrustedApi.TYPE_CC_TDX: TdxRTMR.RTMR_COUNT -} -"""Configurations of measurement count. -The configurations could be different for different confidential VMs. -""" - -cnf_measurement_check = { - CCTrustedApi.TYPE_CC_TDX: tdx_check.tdx_check_measurement_imrs -} -"""Configurations of measurement check functions. -The configurations could be different for different confidential VMs. -""" - -cnf_quote_check_valid_input = { - CCTrustedApi.TYPE_CC_TDX: tdx_check.tdx_check_quote_with_valid_input -} -"""Configurations of quote check functions for valid input. -The configurations could be different for different confidential VMs. -""" - -cnf_quote_check_invalid_input = { - CCTrustedApi.TYPE_CC_TDX: tdx_check.tdx_check_quote_with_invalid_input -} -"""Configurations of quote check functions for invalid input. -The configurations could be different for different confidential VMs. -""" - -cnf_replay_eventlog_check_valid_input = { - CCTrustedApi.TYPE_CC_TDX: tdx_check.tdx_check_replay_eventlog_with_valid_input -} -"""Configurations of replay_eventlog check functions for valid input. -The configurations could be different for different confidential VMs. -""" - -cnf_replay_eventlog_check_invalid_input = { - CCTrustedApi.TYPE_CC_TDX: tdx_check.tdx_check_replay_eventlog_with_invalid_input -} -"""Configurations of replay_eventlog check functions for invalid input. -The configurations could be different for different confidential VMs. -""" - -@pytest.fixture(scope="module") -def vm_sdk(): - """Get VMSDK instance.""" - return CCTrustedVmSdk.inst() - -@pytest.fixture(scope="module") -def default_alg_id(): - """Get default algorithm.""" - cc_type = ConfidentialVM.detect_cc_type() - return cnf_default_alg[cc_type] - -@pytest.fixture(scope="module") -def measurement_count(): - """Get measurement count.""" - cc_type = ConfidentialVM.detect_cc_type() - return cnf_measurement_cnt[cc_type] - -@pytest.fixture(scope="module") -def check_measurement(): - """Return checker for measurement.""" - cc_type = ConfidentialVM.detect_cc_type() - return cnf_measurement_check[cc_type] - -@pytest.fixture(scope="module") -def check_quote_valid_input(): - """Return checker for quote when input is valid.""" - cc_type = ConfidentialVM.detect_cc_type() - return cnf_quote_check_valid_input[cc_type] - -@pytest.fixture(scope="module") -def check_quote_invalid_input(): - """Return checker for quote when input is invalid.""" - cc_type = ConfidentialVM.detect_cc_type() - return cnf_quote_check_invalid_input[cc_type] - -@pytest.fixture(scope="module") -def check_replay_eventlog_valid_input(): - """Return checker for replay_eventlog when input is valid.""" - cc_type = ConfidentialVM.detect_cc_type() - return cnf_replay_eventlog_check_valid_input[cc_type] - -@pytest.fixture(scope="module") -def check_replay_eventlog_invalid_input(): - """Return checker for replay_eventlog when input is invalid.""" - cc_type = ConfidentialVM.detect_cc_type() - return cnf_replay_eventlog_check_invalid_input[cc_type] diff --git a/vmsdk/python/tests/tdx_check.py b/vmsdk/python/tests/tdx_check.py deleted file mode 100644 index 59fc8d8e..00000000 --- a/vmsdk/python/tests/tdx_check.py +++ /dev/null @@ -1,258 +0,0 @@ -"""TDX specific test.""" - -import base64 -import hashlib -import logging -import os -import random -import pytest -from cctrusted_base.api import CCTrustedApi -from cctrusted_base.eventlog import EventLogs -from cctrusted_base.tcg import TcgAlgorithmRegistry, TcgEventType -from cctrusted_base.tdx.common import TDX_REPORTDATA_LEN -from cctrusted_base.tdx.quote import TdxQuote, TdxQuoteBody -from cctrusted_base.tdx.rtmr import TdxRTMR -from cctrusted_vm.sdk import CCTrustedVmSdk - -LOG = logging.getLogger(__name__) - -def _replay_eventlog(): - """Get RTMRs from event log by replay.""" - rtmr_len = TdxRTMR.RTMR_LENGTH_BY_BYTES - rtmr_cnt = TdxRTMR.RTMR_COUNT - rtmrs = [bytearray(rtmr_len)] * rtmr_cnt - event_logs = CCTrustedVmSdk.inst().get_cc_eventlog() - assert event_logs is not None - for event in event_logs: - if event.event_type != TcgEventType.EV_NO_ACTION: - sha384_algo = hashlib.sha384() - sha384_algo.update(rtmrs[event.imr_index] + event.digests[0].hash) - rtmrs[event.imr_index] = sha384_algo.digest() - return rtmrs - -def _check_imr(imr_index: int, alg_id: int, rtmr: bytes): - """Check individual IMR. - Compare the 4 IMR hash with the hash derived by replay event log. They are - expected to be same. - Args: - imr_index: an integer specified the IMR index. - alg_id: an integer specified the hash algorithm. - rtmr: bytes of RTMR data for comparison. - """ - assert 0 <= imr_index < TdxRTMR.RTMR_COUNT - assert rtmr is not None - assert alg_id == TcgAlgorithmRegistry.TPM_ALG_SHA384 - imr = CCTrustedVmSdk.inst().get_cc_measurement([imr_index, alg_id]) - assert imr is not None - digest_obj = imr.digest(alg_id) - assert digest_obj is not None - digest_alg_id = digest_obj.alg.alg_id - assert digest_alg_id == TcgAlgorithmRegistry.TPM_ALG_SHA384 - digest_hash = digest_obj.hash - assert digest_hash is not None - assert digest_hash == rtmr, f"rtmr {rtmr.hex()} doesn't equal digest {digest_hash.hex()}" - -def tdx_check_measurement_imrs(): - """Test measurement result. - The test is done by compare the measurement register against the value - derived by replay eventlog. - """ - alg = CCTrustedVmSdk.inst().get_default_algorithms() - rtmrs = _replay_eventlog() - _check_imr(0, alg.alg_id, rtmrs[0]) - _check_imr(1, alg.alg_id, rtmrs[1]) - _check_imr(2, alg.alg_id, rtmrs[2]) - _check_imr(3, alg.alg_id, rtmrs[3]) - -def _gen_valid_nonce(): - """Generate nonce for test. - - Returns: - A nonce for test that is base64 encoded bytes reprensting a 64 bits unsigned integer. - """ - # Generte a 64 bits unsigned integer randomly (range from 0 to 64 bits max). - rand_num = random.randrange(0x0, 0xFFFFFFFFFFFFFFFF, 1) - nonce = base64.b64encode(rand_num.to_bytes(8, "little")) - LOG.info("_gen_valid_nonce: %s", nonce.hex()) - return nonce - -def _gen_valid_userdata(): - """Generate userdata for test. - - Returns: - User data that is base64 encoded bytes for test. - """ - userdata = base64.b64encode(bytes("test user data", "utf-8")) - LOG.info("_gen_valid_userdata: %s", userdata.hex()) - return userdata - -def _gen_invalid_base64_bytes(): - """Generate bytes which is not base64 encoded. - - Returns: - Bytes which is not base64 encoded. - """ - invalid_chars = bytes("~!@#$%^&*()", "utf-8") - invalid_bytes_len = random.randrange(1, len(invalid_chars), 1) - invalid_bytes = bytes(random.choices(invalid_chars, k = invalid_bytes_len)) - LOG.info("_gen_invalid_base64_bytes: %s", invalid_bytes.hex()) - return invalid_bytes - -def _gen_invalid_nonce(): - """Generate invalid nonce for test. - - Returns: - Invalid nonce. e.g. A string that violates base64 encoding rule. - """ - # Generate a string with some randomness for test. - invalid_nonce = _gen_invalid_base64_bytes() - LOG.info("_gen_invalid_nonce: %s", invalid_nonce.hex()) - return invalid_nonce - -def _gen_invalid_userdata(): - """Generate invalid userdata for test. - - Returns: - Invalid user data. e.g. A string that violates base64 encoding rule. - """ - # Generate a string with some randomness for test. - invalid_userdata = _gen_invalid_base64_bytes() - LOG.info("_gen_invalid_userdata: %s", invalid_userdata.hex()) - return invalid_userdata - -def _check_quote_rtmrs(quote): - """Check the RTMRs in quote result. - The test is done by compare the RTMRs in quote body against the value - derived by replay eventlog. - """ - assert quote is not None and isinstance(quote, TdxQuote) - body = quote.body - assert body is not None and isinstance(body, TdxQuoteBody) - rtmrs = _replay_eventlog() - assert body.rtmr0 == rtmrs[0], "RTMR0 doesn't equal the replay from event log!" - assert body.rtmr1 == rtmrs[1], "RTMR1 doesn't equal the replay from event log!" - assert body.rtmr2 == rtmrs[2], "RTMR2 doesn't equal the replay from event log!" - assert body.rtmr3 == rtmrs[3], "RTMR3 doesn't equal the replay from event log!" - -def _check_quote_reportdata(quote, nonce=None, userdata=None): - """Check the userdata in quote result.""" - assert quote is not None and isinstance(quote, TdxQuote) - assert quote.cc_type == CCTrustedApi.TYPE_CC_TDX - body = quote.body - assert body is not None and isinstance(body, TdxQuoteBody) - out_data = body.reportdata - assert out_data is not None - expectation = None - if nonce is None and userdata is None: - expectation = bytes([0]) * TDX_REPORTDATA_LEN - else: - hash_algo = hashlib.sha512() - if nonce is not None: - hash_algo.update(bytes(base64.b64decode(nonce))) - if userdata is not None: - hash_algo.update(bytes(base64.b64decode(userdata))) - expectation = hash_algo.digest() - assert expectation == out_data - -def tdx_check_quote_with_valid_input(): - """Test get quote result when nonce and userdata are valid.""" - - # Check RTMRs and REPORTDATA in the quote when "both nonce and userdata are None". - quote = CCTrustedVmSdk.inst().get_cc_report() - _check_quote_rtmrs(quote) - _check_quote_reportdata(quote) - - # Check RTMRs and REPORTDATA in the quote when "userdata is None". - nonce = _gen_valid_nonce() - quote = CCTrustedVmSdk.inst().get_cc_report(nonce) - _check_quote_rtmrs(quote) - _check_quote_reportdata(quote, nonce) - - # Check RTMRs and REPORTDATA in the quote when "nonce is None". - userdata = _gen_valid_userdata() - quote = CCTrustedVmSdk.inst().get_cc_report(None, userdata) - _check_quote_rtmrs(quote) - _check_quote_reportdata(quote, None, userdata) - - # Check RTMRs and REPORTDATA in the quote when "userdata is not None". - nonce = _gen_valid_nonce() - userdata = _gen_valid_userdata() - quote = CCTrustedVmSdk.inst().get_cc_report(nonce, userdata) - _check_quote_rtmrs(quote) - _check_quote_reportdata(quote, nonce, userdata) - -def tdx_check_quote_with_invalid_input(): - """Test get quote result when nonce and userdata are invalid.""" - - # Check exception handling when "both nonce and user data are not base64 encoded". - invalid_nonce = _gen_invalid_nonce() - invalid_userdata = _gen_invalid_userdata() - with pytest.raises(Exception) as excinfo: - CCTrustedVmSdk.inst().get_cc_report(invalid_nonce, invalid_userdata) - assert 'Non-base64 digit found' in str(excinfo.value) - - # Check exception handling when "nonce is not base64 encoded". - invalid_nonce = _gen_invalid_nonce() - userdata = _gen_valid_userdata() - with pytest.raises(Exception) as excinfo: - CCTrustedVmSdk.inst().get_cc_report(invalid_nonce, userdata) - assert 'Non-base64 digit found' in str(excinfo.value) - with pytest.raises(Exception) as excinfo: - # Also check when userdata is None. - CCTrustedVmSdk.inst().get_cc_report(invalid_nonce) - assert 'Non-base64 digit found' in str(excinfo.value) - - # Check exception handling when "userdata is not base64 encoded". - nonce = _gen_valid_nonce() - invalid_userdata = _gen_invalid_userdata() - with pytest.raises(Exception) as excinfo: - CCTrustedVmSdk.inst().get_cc_report(nonce, invalid_userdata) - assert 'Non-base64 digit found' in str(excinfo.value) - with pytest.raises(Exception) as excinfo: - # Also check when nonce is None. - CCTrustedVmSdk.inst().get_cc_report(None, invalid_userdata) - assert 'Non-base64 digit found' in str(excinfo.value) - -def _gen_valid_eventlog(): - """Generate valid eventlog for test.""" - # One valid input could be current eventlog. - eventlog = CCTrustedVmSdk.inst().get_cc_eventlog() - assert eventlog is not None - return eventlog - -def _gen_invalid_eventlog(): - """Generate invalid eventlog for test.""" - boot_time_data_len = random.randrange(0, 512, 1) - boot_time_data = os.urandom(boot_time_data_len) - LOG.info("_gen_invalid_eventlog boot_time_data: %s", boot_time_data.hex()) - run_time_data_len = random.randrange(0, 512, 1) - run_time_data = os.urandom(run_time_data_len) - LOG.info("_gen_invalid_eventlog run_time_data: %s", run_time_data.hex()) - invalid_eventlog = EventLogs(boot_time_data, run_time_data) - return invalid_eventlog - -def tdx_check_replay_eventlog_with_valid_input(): - """Test replay_eventlog with valid input.""" - eventlog = _gen_valid_eventlog() - replay_result = CCTrustedVmSdk.inst().replay_cc_eventlog(eventlog) - assert replay_result is not None and 0 < len(replay_result) <= TdxRTMR.RTMR_COUNT - alg = CCTrustedVmSdk.inst().get_default_algorithms().alg_id - for imr_idx, replayed_values in replay_result.items(): - assert 0 <= imr_idx < TdxRTMR.RTMR_COUNT - assert replayed_values is not None and isinstance(replayed_values, dict) - v = replayed_values[alg] - assert v is not None - _check_imr(imr_idx, alg, v) - -def tdx_check_replay_eventlog_with_invalid_input(): - """Test replay_eventlog with invalid input.""" - - # Check the replay result should be None when input None. - replay_result = CCTrustedVmSdk.inst().replay_cc_eventlog(None) - assert replay_result == {} - - # Check the replay result when input invalid eventlog. - invalid_eventlog = _gen_invalid_eventlog() - replay_result = CCTrustedVmSdk.inst().replay_cc_eventlog(invalid_eventlog.event_logs) - assert replay_result is not None - assert 0 == len(replay_result) diff --git a/vmsdk/python/tests/test_sdk.py b/vmsdk/python/tests/test_sdk.py deleted file mode 100644 index dec10a14..00000000 --- a/vmsdk/python/tests/test_sdk.py +++ /dev/null @@ -1,116 +0,0 @@ -"""Containing unit test cases for sdk class""" - -from cctrusted_base.ccreport import CcReport, CcReportData, CcReportSignature -from cctrusted_base.tcg import TcgImrEvent, TcgPcClientImrEvent -from cctrusted_base.tcgcel import TcgTpmsCelEvent -import pytest - -def test_get_default_algorithms(vm_sdk, default_alg_id): - """Test get_default_algorithms() function.""" - algo = vm_sdk.get_default_algorithms() - assert algo is not None - assert algo.alg_id == default_alg_id - -def test_get_measurement_count(vm_sdk, measurement_count): - """Test get_measurement_count() function.""" - count = vm_sdk.get_measurement_count() - assert count is not None - assert count == measurement_count - -def test_get_cc_measurement_with_invalid_input(vm_sdk): - """Test get_cc_measurement() function with invalid input.""" - # calling get_cc_measurement() with invalid IMR index - measurement = vm_sdk.get_cc_measurement([-1, 0xC]) - assert measurement is None - - # calling get_cc_measurement() with invalid algorithm ID - measurement = vm_sdk.get_cc_measurement([0, None]) - assert measurement is not None - -def test_get_cc_measurement_with_valid_input(vm_sdk, check_measurement): - """Test get_cc_measurement() function with valid input.""" - count = vm_sdk.get_measurement_count() - for index in range(count): - alg = vm_sdk.get_default_algorithms() - digest_obj = vm_sdk.get_cc_measurement([index, alg.alg_id]) - assert digest_obj is not None - check_measurement() - -def test_get_cc_eventlog_with_invalid_input(vm_sdk): - """Test get_cc_eventlog() function with invalid input. - - The test logic currently has an assumption that the return result of get_cc_eventlog - doesn't change if the input parameters are the same within a short period of time. - """ - event_num = len(vm_sdk.get_cc_eventlog()) - idx_min = 0 - idx_max = event_num - 1 - cnt_min = 1 - cnt_max = event_num - - # calling get_cc_eventlog with invalid "start" - with pytest.raises(ValueError): - invalid_start = idx_min - 1 - vm_sdk.get_cc_eventlog(start=invalid_start, count=1) - with pytest.raises(ValueError): - invalid_start = idx_max + 2 - vm_sdk.get_cc_eventlog(start=invalid_start, count=1) - # a special case works as current design - invalid_start = idx_max + 1 - eventlog = vm_sdk.get_cc_eventlog(start=invalid_start, count=1) - assert len(eventlog) == 0 - - # calling get_cc_eventlog with invalid "count" - with pytest.raises(ValueError): - invalid_count = cnt_min - 1 - vm_sdk.get_cc_eventlog(start=idx_min, count=invalid_count) - with pytest.raises(ValueError): - invalid_count = cnt_max + 1 - vm_sdk.get_cc_eventlog(start=idx_min, count=invalid_count) - with pytest.raises(ValueError): - vm_sdk.get_cc_eventlog(start=idx_max, count=2) - -def test_get_cc_eventlog_with_valid_input(vm_sdk): - """Test get_eventlog() funtion with valid input.""" - eventlog = vm_sdk.get_cc_eventlog() - - # Check 1: the eventlog should not be None. - assert eventlog is not None - - # Check 2: the object type should be correct. - assert isinstance(eventlog, list) - event_count = 0 - for e in eventlog: - event_count += 1 - assert isinstance(e, (TcgImrEvent, TcgPcClientImrEvent, TcgTpmsCelEvent)) - -def test_get_cc_report_with_valid_input(vm_sdk, check_quote_valid_input): - """Test get_cc_report() function with valid input.""" - quote = vm_sdk.get_cc_report(None, None, None) - - # Check 1: the quote should not be None. - assert quote is not None - - # Check 2: the object type should be correct. - assert isinstance(quote, CcReport) - quoted_data = quote.get_quoted_data() - assert quoted_data is not None - assert isinstance(quoted_data, CcReportData) - sigature_data = quote.get_sig() - assert sigature_data is not None - assert isinstance(sigature_data, CcReportSignature) - - # Check 3: platform specific check. - check_quote_valid_input() - -def test_get_cc_report_with_invalid_input(check_quote_invalid_input): - """Test get_cc_report() function with invalid input.""" - check_quote_invalid_input() - -def test_replay_cc_eventlog_with_valid_input(check_replay_eventlog_valid_input): - """Test replay_cc_eventlog() function with valid input.""" - check_replay_eventlog_valid_input() - -def test_replay_cc_eventlog_with_invalid_input(check_replay_eventlog_invalid_input): - """Test replay_cc_eventlog() function with invalid input.""" - check_replay_eventlog_invalid_input() diff --git a/vmsdk/rust/cctrusted_vm/Cargo.toml b/vmsdk/rust/cctrusted_vm/Cargo.toml deleted file mode 100644 index bf75a22b..00000000 --- a/vmsdk/rust/cctrusted_vm/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "cctrusted_vm" -version = "0.1.0" -edition = "2021" -authors = ["Chen Hairong ", "Lu Ken "] -repository = "https://github.com/cc-api/cc-trusted-api" -description = "CC Trusted API VM SDK" -license = "Apache-2.0" - -[lib] -name = "cctrusted_vm" -path = "src/lib.rs" - -[dependencies] -cctrusted_base = { path = "../../../common/rust/cctrusted_base" } -anyhow = "1.0" -log = "0.4.20" -nix = "0.26.2" -base64 = "0.13.0" -rand = "0.8.5" diff --git a/vmsdk/rust/cctrusted_vm/deny.toml b/vmsdk/rust/cctrusted_vm/deny.toml deleted file mode 100644 index 6e656f7e..00000000 --- a/vmsdk/rust/cctrusted_vm/deny.toml +++ /dev/null @@ -1,35 +0,0 @@ -[advisories] -vulnerability = "deny" -unmaintained = "warn" -yanked = "warn" -notice = "warn" - -[licenses] -unlicensed = "warn" -allow = [ - "MIT", - "Apache-2.0", - "ISC", - "BSD-3-Clause", - "Unicode-DFS-2016", -] - -copyleft = "warn" -allow-osi-fsf-free = "neither" -default = "deny" -confidence-threshold = 0.8 - -[[licenses.clarify]] -name = "ring" -expression = "MIT AND ISC AND OpenSSL" -license-files = [ - { path = "LICENSE", hash = 0xbd0eed23 } -] - -[bans] -multiple-versions = "warn" -wildcards = "allow" - -[sources] -unknown-registry = "warn" -unknown-git = "warn" \ No newline at end of file diff --git a/vmsdk/rust/cctrusted_vm/src/cvm.rs b/vmsdk/rust/cctrusted_vm/src/cvm.rs deleted file mode 100644 index 3b3a11ba..00000000 --- a/vmsdk/rust/cctrusted_vm/src/cvm.rs +++ /dev/null @@ -1,140 +0,0 @@ -use crate::tdvm::TdxVM; -use anyhow::*; -use cctrusted_base::api_data::ReplayResult; -use cctrusted_base::cc_type::*; -use cctrusted_base::tcg::EventLogEntry; -use cctrusted_base::tcg::{TcgAlgorithmRegistry, TcgDigest}; -use std::path::Path; - -// the interfaces a CVM should implement -pub trait CVM { - /*** - retrive CVM signed report - - Args: - nonce (String): against replay attacks - data (String): user data - - Returns: - the cc report byte array or error information - */ - fn process_cc_report( - &mut self, - nonce: Option, - data: Option, - ) -> Result, anyhow::Error>; - - /*** - retrive CVM max number of measurement registers - - Args: - None - - Returns: - max index of register of CVM - */ - fn get_max_index(&self) -> u8; - - /*** - retrive CVM measurement registers, e.g.: RTMRs, vTPM PCRs, etc. - - Args: - index (u8): the index of measurement register, - algo_id (u8): the alrogithms ID - - Returns: - TcgDigest struct - */ - fn process_cc_measurement(&self, index: u8, algo_id: u16) -> Result; - - /*** - retrive CVM eventlogs - - Args: - start and count of eventlogs - - Returns: - array of eventlogs - */ - fn process_cc_eventlog( - &self, - start: Option, - count: Option, - ) -> Result, anyhow::Error>; - - /*** - replay retrived CVM eventlogs - Args: - array of eventlogs - Returns: - A struct containing the replay result arranged by IMR index and hash algorithm. - Layer 1 key of the struct is the IMR index, the value is another dict which using the - hash algorithm as the key and the replayed measurement as value. - Sample value: - [ - 0: [{ 4: },{ 12: },] - 1: { 12: }, - ] - */ - fn replay_eventlog( - &self, - eventlogs: Vec, - ) -> Result, anyhow::Error>; - - /*** - retrive CVM type - - Args: - None - - Returns: - CcType of CVM - */ - fn get_cc_type(&self) -> CcType; - - //Dump confidential CVM information - fn dump(&self); -} - -// used for return of Boxed trait object in build_cvm() -// this composed trait includes functions in both trait CVM and trait TcgAlgorithmRegistry -pub trait BuildCVM: CVM + TcgAlgorithmRegistry {} - -// holds the device node info -pub struct DeviceNode { - pub device_path: String, -} - -/*** - instance a specific object containers specific CVM methods - and desired trait functions specified by "dyn BuildCVM" -*/ -pub fn build_cvm() -> Result, anyhow::Error> { - // instance a CVM according to detected TEE type - match get_cvm_type().tee_type { - TeeType::TDX => Ok(Box::new(TdxVM::new())), - TeeType::SEV => todo!(), - TeeType::CCA => todo!(), - TeeType::TPM => todo!(), - TeeType::PLAIN => Err(anyhow!("[build_cvm] Error: not in any TEE!")), - } -} - -// detect CVM type -pub fn get_cvm_type() -> CcType { - let mut tee_type = TeeType::PLAIN; - if Path::new(TEE_TPM_PATH).exists() { - tee_type = TeeType::TPM; - } else if Path::new(TEE_TDX_1_0_PATH).exists() || Path::new(TEE_TDX_1_5_PATH).exists() { - tee_type = TeeType::TDX; - } else if Path::new(TEE_SEV_PATH).exists() { - tee_type = TeeType::SEV; - } else { - // TODO add support for CCA and etc. - } - - CcType { - tee_type: tee_type.clone(), - tee_type_str: TEE_NAME_MAP.get(&tee_type).unwrap().to_owned(), - } -} diff --git a/vmsdk/rust/cctrusted_vm/src/lib.rs b/vmsdk/rust/cctrusted_vm/src/lib.rs deleted file mode 100644 index 5fcc9b0f..00000000 --- a/vmsdk/rust/cctrusted_vm/src/lib.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod cvm; -pub mod sdk; -pub mod tdvm; diff --git a/vmsdk/rust/cctrusted_vm/src/sdk.rs b/vmsdk/rust/cctrusted_vm/src/sdk.rs deleted file mode 100644 index 19692732..00000000 --- a/vmsdk/rust/cctrusted_vm/src/sdk.rs +++ /dev/null @@ -1,554 +0,0 @@ -use anyhow::*; -use core::result::Result; -use core::result::Result::Ok; - -use cctrusted_base::binary_blob::dump_data; -use cctrusted_base::tcg::{EventLogEntry, TcgDigest, ALGO_NAME_MAP}; - -use crate::cvm::build_cvm; -use cctrusted_base::api::*; -use cctrusted_base::api_data::*; - -pub struct API {} - -impl CCTrustedApi for API { - // CCTrustedApi trait function: get report of a CVM - fn get_cc_report( - nonce: Option, - data: Option, - _extra_args: ExtraArgs, - ) -> Result { - match build_cvm() { - Ok(mut cvm) => { - // call CVM trait defined methods - cvm.dump(); - Ok(CcReport { - cc_report: match cvm.process_cc_report(nonce, data) { - Ok(r) => r, - Err(e) => { - return Err(anyhow!("[get_cc_report] error get cc report: {:?}", e)); - } - }, - cc_type: cvm.get_cc_type().tee_type, - }) - } - Err(e) => Err(anyhow!("[get_cc_report] error create cvm: {:?}", e)), - } - } - - // CCTrustedApi trait function: dump report of a CVM in hex and char format - fn dump_cc_report(report: &Vec) { - dump_data(report) - } - - // CCTrustedApi trait function: get max number of CVM IMRs - fn get_measurement_count() -> Result { - match build_cvm() { - Ok(cvm) => Ok(cvm.get_max_index() + 1), - Err(e) => Err(anyhow!("[get_measurement_count] error create cvm: {:?}", e)), - } - } - - // CCTrustedApi trait function: get measurements of a CVM - fn get_cc_measurement(index: u8, algo_id: u16) -> Result { - match build_cvm() { - Ok(cvm) => cvm.process_cc_measurement(index, algo_id), - Err(e) => Err(anyhow!("[get_cc_measurement] error create cvm: {:?}", e)), - } - } - - // CCTrustedApi trait function: get eventlogs of a CVM - fn get_cc_eventlog( - start: Option, - count: Option, - ) -> Result, anyhow::Error> { - match build_cvm() { - Ok(cvm) => cvm.process_cc_eventlog(start, count), - Err(e) => Err(anyhow!("[get_cc_eventlog] error create cvm: {:?}", e)), - } - } - - // CCTrustedApi trait function: replay eventlogs of a CVM - fn replay_cc_eventlog( - eventlogs: Vec, - ) -> Result, anyhow::Error> { - match build_cvm() { - Ok(cvm) => cvm.replay_eventlog(eventlogs), - Err(e) => Err(anyhow!("[replay_cc_eventlog] error create cvm: {:?}", e)), - } - } - - // CCTrustedApi trait function: get default algorithm of a CVM - fn get_default_algorithm() -> Result { - match build_cvm() { - Ok(cvm) => { - // call CVM trait defined methods - let algo_id = cvm.get_algorithm_id(); - Ok(Algorithm { - algo_id, - algo_id_str: ALGO_NAME_MAP.get(&algo_id).unwrap().to_owned(), - }) - } - Err(e) => Err(anyhow!( - "[get_default_algorithm] error get algorithm: {:?}", - e - )), - } - } -} - -#[cfg(test)] -mod sdk_api_tests { - use super::*; - use crate::cvm::get_cvm_type; - use cctrusted_base::cc_type::TeeType; - use cctrusted_base::tcg::{TPM_ALG_SHA256, TPM_ALG_SHA384}; - use cctrusted_base::tdx::common::{ - AttestationKeyType, IntelTeeType, QeCertDataType, Tdx, QE_VENDOR_INTEL_SGX, - }; - use cctrusted_base::tdx::quote::TdxQuote; - use rand::Rng; - - // test on cc trusted API [get_cc_report] - #[test] - fn test_get_cc_report() { - let nonce = base64::encode(rand::thread_rng().gen::<[u8; 32]>()); - let data = base64::encode(rand::thread_rng().gen::<[u8; 32]>()); - - match Tdx::generate_tdx_report_data(Some(nonce.clone()), Some(data.clone())) { - Ok(r) => r, - Err(e) => { - assert_eq!(true, format!("{:?}", e).is_empty()); - return; - } - }; - - let report = match API::get_cc_report(Some(nonce.clone()), Some(data.clone()), ExtraArgs {}) - { - Ok(q) => q, - Err(e) => { - assert_eq!(true, format!("{:?}", e).is_empty()); - return; - } - }; - - assert_ne!(report.cc_report.len(), 0); - - let expected_cvm_type = get_cvm_type().tee_type; - assert_eq!(report.cc_type, expected_cvm_type); - } - - #[test] - fn test_get_cc_report_without_data() { - let nonce = base64::encode(rand::thread_rng().gen::<[u8; 32]>()); - - let expected_report_data = match Tdx::generate_tdx_report_data(Some(nonce.clone()), None) { - Ok(r) => r, - Err(e) => { - assert_eq!(true, format!("{:?}", e).is_empty()); - return; - } - }; - - let report = match API::get_cc_report(Some(nonce.clone()), None, ExtraArgs {}) { - Ok(q) => q, - Err(e) => { - assert_eq!(true, format!("{:?}", e).is_empty()); - return; - } - }; - - if report.cc_type == TeeType::TDX { - let tdx_quote: TdxQuote = match CcReport::parse_cc_report(report.cc_report) { - Ok(q) => q, - Err(e) => { - assert_eq!(true, format!("{:?}", e).is_empty()); - return; - } - }; - - assert_eq!( - base64::encode(&tdx_quote.body.report_data), - expected_report_data - ); - } - } - - #[test] - fn test_get_cc_report_without_nonce_and_data() { - let expected_report_data = match Tdx::generate_tdx_report_data(None, None) { - Ok(r) => r, - Err(e) => { - assert_eq!(true, format!("{:?}", e).is_empty()); - return; - } - }; - - let report = match API::get_cc_report(None, None, ExtraArgs {}) { - Ok(q) => q, - Err(e) => { - assert_eq!(true, format!("{:?}", e).is_empty()); - return; - } - }; - - if report.cc_type == TeeType::TDX { - let tdx_quote: TdxQuote = match CcReport::parse_cc_report(report.cc_report) { - Ok(q) => q, - Err(e) => { - assert_eq!(true, format!("{:?}", e).is_empty()); - return; - } - }; - - assert_eq!( - base64::encode(&tdx_quote.body.report_data), - expected_report_data - ); - } - } - - #[test] - fn test_get_cc_report_nonce_not_base64_encoded() { - let nonce = "XD^%*!x".to_string(); - match API::get_cc_report(Some(nonce), None, ExtraArgs {}) { - Ok(q) => q, - Err(e) => { - assert_eq!( - true, - format!("{:?}", e).contains("nonce is not base64 encoded") - ); - return; - } - }; - } - - #[test] - fn test_get_cc_report_data_not_base64_encoded() { - let data = "XD^%*!x".to_string(); - match API::get_cc_report(None, Some(data), ExtraArgs {}) { - Ok(q) => q, - Err(e) => { - assert_eq!( - true, - format!("{:?}", e).contains("data is not base64 encoded") - ); - return; - } - }; - } - - // test on cc trusted API [get_default_algorithm] - #[test] - fn test_get_default_algorithm() { - let defalt_algo = match API::get_default_algorithm() { - Ok(algorithm) => algorithm, - Err(e) => { - assert_eq!(true, format!("{:?}", e).is_empty()); - return; - } - }; - - if get_cvm_type().tee_type == TeeType::TDX { - assert_eq!(defalt_algo.algo_id, TPM_ALG_SHA384); - } - } - - // test on cc trusted API [get_measurement_count] - #[test] - fn test_get_measurement_count() { - let count = match API::get_measurement_count() { - Ok(count) => count, - Err(e) => { - assert_eq!(true, format!("{:?}", e).is_empty()); - return; - } - }; - - if get_cvm_type().tee_type == TeeType::TDX { - assert_eq!(count, 4); - } - } - - // test on cc trusted API [get_cc_measurement] - #[test] - fn test_get_cc_measurement() { - let count = match API::get_measurement_count() { - Ok(count) => count, - Err(e) => { - assert_eq!(true, format!("{:?}", e).is_empty()); - return; - } - }; - - if get_cvm_type().tee_type == TeeType::TDX { - for index in 0..count { - let tcg_digest = match API::get_cc_measurement(index, TPM_ALG_SHA384) { - Ok(tcg_digest) => tcg_digest, - Err(e) => { - assert_eq!(true, format!("{:?}", e).is_empty()); - return; - } - }; - - assert_eq!(tcg_digest.algo_id, TPM_ALG_SHA384); - assert_eq!(tcg_digest.hash.len(), 48); - } - } - } - - #[test] - fn test_get_cc_measurement_with_wrong_algo_id() { - let count = match API::get_measurement_count() { - Ok(count) => count, - Err(e) => { - assert_eq!(true, format!("{:?}", e).is_empty()); - return; - } - }; - - if get_cvm_type().tee_type == TeeType::TDX { - for index in 0..count { - match API::get_cc_measurement(index, TPM_ALG_SHA256) { - Ok(tcg_digest) => tcg_digest, - Err(e) => { - assert_eq!(true, format!("{:?}", e).contains("invalid algo id")); - return; - } - }; - } - } - } - - // test on cc trusted API [parse_cc_report] - #[test] - fn test_parse_cc_report() { - let nonce = base64::encode(rand::thread_rng().gen::<[u8; 32]>()); - let data = base64::encode(rand::thread_rng().gen::<[u8; 32]>()); - - let expected_report_data = - match Tdx::generate_tdx_report_data(Some(nonce.clone()), Some(data.clone())) { - Ok(r) => r, - Err(e) => { - assert_eq!(true, format!("{:?}", e).is_empty()); - return; - } - }; - - let report = match API::get_cc_report(Some(nonce.clone()), Some(data.clone()), ExtraArgs {}) - { - Ok(q) => q, - Err(e) => { - assert_eq!(true, format!("{:?}", e).is_empty()); - return; - } - }; - - if report.cc_type == TeeType::TDX { - let tdx_quote: TdxQuote = match CcReport::parse_cc_report(report.cc_report) { - Ok(q) => q, - Err(e) => { - assert_eq!(true, format!("{:?}", e).is_empty()); - return; - } - }; - - assert_eq!(tdx_quote.header.version, 4); - assert_eq!(tdx_quote.header.tee_type, IntelTeeType::TEE_TDX); - assert_eq!(tdx_quote.header.qe_vendor, QE_VENDOR_INTEL_SGX); - assert_eq!( - base64::encode(&tdx_quote.body.report_data), - expected_report_data - ); - - if tdx_quote.header.ak_type == AttestationKeyType::ECDSA_P256 { - match tdx_quote.tdx_quote_ecdsa256_sigature { - Some(tdx_quote_ecdsa256_sigature) => { - if tdx_quote_ecdsa256_sigature.qe_cert.cert_type - == QeCertDataType::QE_REPORT_CERT - { - match tdx_quote_ecdsa256_sigature.qe_cert.cert_data_struct { - Some(_) => (), - None => assert!(false, "cert_data_struct is None"), - } - } - } - None => assert!(false, "tdx_quote_ecdsa256_sigature is None"), - } - } else if tdx_quote.header.ak_type == AttestationKeyType::ECDSA_P384 { - match tdx_quote.tdx_quote_signature { - Some(_) => (), - None => assert!(false, "tdx_quote_signature is None"), - } - } else { - assert!(false, "unknown ak type"); - } - } - } - - // test on cc trusted API [get_cc_eventlog] - #[test] - fn test_get_cc_eventlog_start_count_normal() { - let event_logs = match API::get_cc_eventlog(Some(0), Some(10)) { - Ok(q) => q, - Err(e) => { - assert_eq!(true, format!("{:?}", e).is_empty()); - return; - } - }; - - assert_eq!(event_logs.len(), 10); - } - - #[test] - fn test_get_cc_eventlog_start_equal_count() { - let number_of_eventlogs = match API::get_cc_eventlog(None, None) { - Ok(q) => q.len(), - Err(e) => { - assert_eq!(true, format!("{:?}", e).is_empty()); - return; - } - }; - - let event_logs = - match API::get_cc_eventlog(Some(number_of_eventlogs.try_into().unwrap()), None) { - Ok(q) => q, - Err(e) => { - assert_eq!(true, format!("{:?}", e).is_empty()); - return; - } - }; - - assert_eq!(event_logs.len(), 0); - } - - #[test] - fn test_get_cc_eventlog_start_bigger_than_count() { - let number_of_eventlogs = match API::get_cc_eventlog(None, None) { - Ok(q) => q.len(), - Err(e) => { - assert_eq!(true, format!("{:?}", e).is_empty()); - return; - } - }; - - match API::get_cc_eventlog(Some((number_of_eventlogs + 1).try_into().unwrap()), None) { - Ok(q) => q, - Err(e) => { - assert_eq!(false, format!("{:?}", e).is_empty()); - return; - } - }; - } - - #[test] - fn test_get_cc_eventlog_none() { - let event_logs = match API::get_cc_eventlog(None, None) { - Ok(q) => q, - Err(e) => { - assert_eq!(true, format!("{:?}", e).is_empty()); - return; - } - }; - - assert_ne!(event_logs.len(), 0); - } - - #[test] - fn test_get_cc_eventlog_invalid_count() { - match API::get_cc_eventlog(Some(1), Some(0)) { - Ok(q) => q, - Err(e) => { - assert_eq!(false, format!("{:?}", e).is_empty()); - return; - } - }; - } - - #[test] - fn test_get_cc_eventlog_start_plus_count_bigger_than_eventlog_number() { - let number_of_eventlogs = match API::get_cc_eventlog(None, None) { - Ok(q) => q.len(), - Err(e) => { - assert_eq!(true, format!("{:?}", e).is_empty()); - return; - } - }; - - let event_logs = match API::get_cc_eventlog( - Some(0), - Some((number_of_eventlogs + 10).try_into().unwrap()), - ) { - Ok(q) => q, - Err(e) => { - assert_eq!(true, format!("{:?}", e).is_empty()); - return; - } - }; - - assert_eq!(event_logs.len(), number_of_eventlogs); - } - - #[test] - fn test_get_cc_eventlog_get_eventlogs_in_batch() { - let batch_size = 10; - let number_of_eventlogs = match API::get_cc_eventlog(None, None) { - Ok(q) => q.len(), - Err(e) => { - assert_eq!(true, format!("{:?}", e).is_empty()); - return; - } - }; - - let mut eventlogs: Vec = Vec::new(); - let mut start = 0; - loop { - let event_logs = match API::get_cc_eventlog(Some(start), Some(batch_size)) { - Ok(q) => q, - Err(e) => { - assert_eq!(true, format!("{:?}", e).is_empty()); - return; - } - }; - for event_log in &event_logs { - eventlogs.push(event_log.clone()); - } - if event_logs.len() != 0 { - start += event_logs.len() as u32; - } else { - break; - } - } - - assert_eq!(eventlogs.len(), number_of_eventlogs); - } - - #[test] - fn test_get_cc_eventlog_check_return_type() { - let event_logs = match API::get_cc_eventlog(Some(1), Some(5)) { - Ok(q) => q, - Err(e) => { - assert_eq!(true, format!("{:?}", e).is_empty()); - return; - } - }; - - for event_log in event_logs { - match event_log { - EventLogEntry::TcgImrEvent(tcg_imr_event) => { - assert_eq!( - tcg_imr_event.event_size, - tcg_imr_event.event.len().try_into().unwrap() - ); - } - EventLogEntry::TcgPcClientImrEvent(tcg_pc_client_imr_event) => { - assert_eq!( - tcg_pc_client_imr_event.event_size, - tcg_pc_client_imr_event.event.len().try_into().unwrap() - ); - } - EventLogEntry::TcgCanonicalEvent(_) => todo!(), - } - } - } -} diff --git a/vmsdk/rust/cctrusted_vm/src/tdvm.rs b/vmsdk/rust/cctrusted_vm/src/tdvm.rs deleted file mode 100644 index 3dad6b61..00000000 --- a/vmsdk/rust/cctrusted_vm/src/tdvm.rs +++ /dev/null @@ -1,503 +0,0 @@ -#![allow(non_camel_case_types)] - -use crate::cvm::*; -use anyhow::*; -use cctrusted_base::api_data::ReplayResult; -use cctrusted_base::cc_type::*; -use cctrusted_base::eventlog::EventLogs; -use cctrusted_base::tcg::EventLogEntry; -use cctrusted_base::tcg::*; -use cctrusted_base::tdx::common::*; -use cctrusted_base::tdx::quote::*; -use cctrusted_base::tdx::report::*; -use cctrusted_base::tdx::rtmr::TdxRTMR; -use core::convert::TryInto; -use core::mem; -use core::ptr; -use core::result::Result; -use core::result::Result::Ok; -use log::info; -use nix::*; -use std::fs::read_to_string; -use std::fs::File; -use std::io::BufReader; -use std::io::Read; -use std::os::fd::AsRawFd; -use std::path::Path; - -// TDX ioctl operation code to be used for get TDX quote and TD Report -pub enum TdxOperation { - TDX_GET_TD_REPORT = 1, - TDX_1_0_GET_QUOTE = 2, - TDX_1_5_GET_QUOTE = 4, -} - -/* - TdxVM is an abstraction of TDX running environment, it contains: - cc_type: should always be CcType built with TeeType::TDX - version: TdxVersion::TDX_1_0 or TdxVersion::TDX_1_5 - device_node: /dev/tdx-guest or /dev/tdx_guest - algo_id: should be TPM_ALG_SHA384 -*/ -pub struct TdxVM { - pub cc_type: CcType, - pub version: TdxVersion, - pub device_node: DeviceNode, - pub algo_id: u16, -} - -// implement the structure method and associated function -impl Default for TdxVM { - fn default() -> Self { - Self::new() - } -} - -impl TdxVM { - // TdxVM struct associated function: to build a TdxVM sturcture instance - pub fn new() -> TdxVM { - let cc_type = CcType { - tee_type: TeeType::TDX, - tee_type_str: TEE_NAME_MAP.get(&TeeType::TDX).unwrap().to_owned(), - }; - - let version = Self::get_tdx_version(); - let device_node = DeviceNode { - device_path: TDX_DEVICE_NODE_MAP.get(&version).unwrap().to_owned(), - }; - let algo_id = cctrusted_base::tcg::TPM_ALG_SHA384; - - TdxVM { - cc_type, - version, - device_node, - algo_id, - } - } - - // TdxVM struct method: get tdreport - fn get_td_report( - &self, - nonce: Option, - data: Option, - ) -> Result, anyhow::Error> { - let report_data = match Tdx::generate_tdx_report_data(nonce, data) { - Ok(r) => r, - Err(e) => { - return Err(anyhow!( - "[get_td_report] error generating TDX report data: {:?}", - e - )) - } - }; - - let device_node = match File::options() - .read(true) - .write(true) - .open(self.device_node.device_path.clone()) - { - Err(e) => { - return Err(anyhow!( - "[get_td_report] Fail to open {}: {:?}", - self.device_node.device_path, - e - )) - } - Ok(fd) => fd, - }; - - match self.version { - TdxVersion::TDX_1_0 => { - let report_data_bytes = match base64::decode(report_data) { - Ok(v) => v, - Err(e) => return Err(anyhow!("report data is not base64 encoded: {:?}", e)), - }; - - //prepare get TDX report request data - let mut report_data_array: [u8; REPORT_DATA_LEN as usize] = - [0; REPORT_DATA_LEN as usize]; - report_data_array.copy_from_slice(&report_data_bytes[0..]); - let td_report: [u8; TDX_REPORT_LEN as usize] = [0; TDX_REPORT_LEN as usize]; - - //build the request - let request = tdx_1_0_report_req { - subtype: 0_u8, - reportdata: ptr::addr_of!(report_data_array) as u64, - rpd_len: REPORT_DATA_LEN, - tdreport: ptr::addr_of!(td_report) as u64, - tdr_len: TDX_REPORT_LEN, - }; - - //build the operator code - ioctl_readwrite!( - get_report_1_0_ioctl, - b'T', - TdxOperation::TDX_GET_TD_REPORT, - u64 - ); - - //apply the ioctl command - if let Err(e) = unsafe { - get_report_1_0_ioctl( - device_node.as_raw_fd(), - ptr::addr_of!(request) as *mut u64, - ) - } { - return Err(anyhow!("[get_td_report] Fail to get TDX report: {:?}", e)); - }; - - Ok(td_report.to_vec()) - } - TdxVersion::TDX_1_5 => { - let report_data_bytes = match base64::decode(report_data) { - Ok(v) => v, - Err(e) => return Err(anyhow!("report data is not base64 encoded: {:?}", e)), - }; - - //prepare get TDX report request data - let mut request = tdx_1_5_report_req { - reportdata: [0; REPORT_DATA_LEN as usize], - tdreport: [0; TDX_REPORT_LEN as usize], - }; - request.reportdata.copy_from_slice(&report_data_bytes[0..]); - - //build the operator code - ioctl_readwrite!( - get_report_1_5_ioctl, - b'T', - TdxOperation::TDX_GET_TD_REPORT, - tdx_1_5_report_req - ); - - //apply the ioctl command - if let Err(e) = unsafe { - get_report_1_5_ioctl( - device_node.as_raw_fd(), - ptr::addr_of!(request) as *mut tdx_1_5_report_req, - ) - } { - return Err(anyhow!("[get_td_report] Fail to get TDX report: {:?}", e)); - }; - - Ok(request.tdreport.to_vec()) - } - } - } - - // TdxVM struct associated function: detect the TDX version - fn get_tdx_version() -> TdxVersion { - if Path::new(TEE_TDX_1_0_PATH).exists() { - TdxVersion::TDX_1_0 - } else if Path::new(TEE_TDX_1_5_PATH).exists() { - TdxVersion::TDX_1_5 - } else { - TdxVersion::TDX_1_0 - } - } -} - -// TdxVM implements the interfaces defined in CVM trait -impl CVM for TdxVM { - // CVM trait function: get tdx quote - fn process_cc_report( - &mut self, - nonce: Option, - data: Option, - ) -> Result, anyhow::Error> { - let tdreport = match self.get_td_report(nonce, data) { - Ok(r) => r, - Err(e) => { - return Err(anyhow!( - "[process_cc_report] error getting TD report: {:?}", - e - )) - } - }; - - let report_data_array: [u8; TDX_REPORT_LEN as usize] = match tdreport.try_into() { - Ok(r) => r, - Err(e) => return Err(anyhow!("[get_tdx_quote] Wrong TDX report format: {:?}", e)), - }; - - //build QGS request message - let qgs_msg = Tdx::generate_qgs_quote_msg(report_data_array); - - //build quote generation request header - let mut quote_header = tdx_quote_hdr { - version: 1, - status: 0, - in_len: (mem::size_of_val(&qgs_msg) + 4) as u32, - out_len: 0, - data_len_be_bytes: (1048_u32).to_be_bytes(), - data: [0; TDX_QUOTE_LEN], - }; - - let qgs_msg_bytes = unsafe { - let ptr = &qgs_msg as *const qgs_msg_get_quote_req as *const u8; - core::slice::from_raw_parts(ptr, mem::size_of::()) - }; - quote_header.data[0..(16 + 8 + TDX_REPORT_LEN) as usize] - .copy_from_slice(&qgs_msg_bytes[0..((16 + 8 + TDX_REPORT_LEN) as usize)]); - - let tdx_quote_request = tdx_quote_req { - buf: ptr::addr_of!(quote_header) as u64, - len: TDX_QUOTE_LEN as u64, - }; - - let device_node = match File::options() - .read(true) - .write(true) - .open(self.device_node.device_path.clone()) - { - Err(e) => { - return Err(anyhow!( - "[get_td_report] Fail to open {}: {:?}", - self.device_node.device_path, - e - )) - } - Ok(fd) => fd, - }; - - //build the operator code and apply the ioctl command - match self.version { - TdxVersion::TDX_1_0 => { - ioctl_read!( - get_quote_1_0_ioctl, - b'T', - TdxOperation::TDX_1_0_GET_QUOTE, - u64 - ); - match unsafe { - get_quote_1_0_ioctl( - device_node.as_raw_fd(), - ptr::addr_of!(tdx_quote_request) as *mut u64, - ) - } { - Err(e) => { - return Err(anyhow!("[get_tdx_quote] Fail to get TDX quote: {:?}", e)) - } - Ok(_r) => _r, - }; - } - TdxVersion::TDX_1_5 => { - ioctl_read!( - get_quote_1_5_ioctl, - b'T', - TdxOperation::TDX_1_5_GET_QUOTE, - tdx_quote_req - ); - match unsafe { - get_quote_1_5_ioctl( - device_node.as_raw_fd(), - ptr::addr_of!(tdx_quote_request) as *mut tdx_quote_req, - ) - } { - Err(e) => { - return Err(anyhow!("[get_tdx_quote] Fail to get TDX quote: {:?}", e)) - } - Ok(_r) => _r, - }; - } - }; - - //inspect the response and retrive quote data - let out_len = quote_header.out_len; - let qgs_msg_resp_size = - unsafe { core::mem::transmute::<[u8; 4], u32>(quote_header.data_len_be_bytes) }.to_be(); - - let qgs_msg_resp = unsafe { - let raw_ptr = ptr::addr_of!(quote_header.data) as *mut qgs_msg_get_quote_resp; - raw_ptr.as_mut().unwrap() as &mut qgs_msg_get_quote_resp - }; - - if out_len - qgs_msg_resp_size != 4 { - return Err(anyhow!( - "[get_tdx_quote] Fail to get TDX quote: wrong TDX quote size!" - )); - } - - if qgs_msg_resp.header.major_version != 1 - || qgs_msg_resp.header.minor_version != 0 - || qgs_msg_resp.header.msg_type != 1 - || qgs_msg_resp.header.error_code != 0 - { - return Err(anyhow!( - "[get_tdx_quote] Fail to get TDX quote: QGS response error!" - )); - } - - Ok(qgs_msg_resp.id_quote[0..(qgs_msg_resp.quote_size as usize)].to_vec()) - } - - // CVM trait function: get tdx rtmr max index - fn get_max_index(&self) -> u8 { - TdxRTMR::max_index() - } - - // CVM trait function: retrieve TDX RTMR - fn process_cc_measurement(&self, index: u8, algo_id: u16) -> Result { - match TdxRTMR::is_valid_index(index) { - Ok(_) => (), - Err(e) => return Err(anyhow!("[process_cc_measurement] {:?}", e)), - }; - - match TdxRTMR::is_valid_algo(algo_id) { - Ok(_) => (), - Err(e) => return Err(anyhow!("[process_cc_measurement] {:?}", e)), - }; - - let tdreport_raw = match self.get_td_report(None, None) { - Ok(r) => r, - Err(e) => { - return Err(anyhow!( - "[process_cc_measurement] error getting TD report: {:?}", - e - )) - } - }; - - let tdreport = match Tdx::parse_td_report(&tdreport_raw, self.version.clone()) { - Ok(r) => r, - Err(e) => { - return Err(anyhow!( - "[process_cc_measurement] error parsing TD report: {:?}", - e - )) - } - }; - - match TdxRTMR::new(index, algo_id, tdreport.td_info.rtmrs[index as usize]) { - Ok(rtmr) => Ok(rtmr.get_tcg_digest(algo_id)), - Err(e) => Err(anyhow!("error creating TdxRTMR {:?}", e)), - } - } - - // CVM trait function: retrieve TDX CCEL and IMA eventlog - fn process_cc_eventlog( - &self, - start: Option, - count: Option, - ) -> Result, anyhow::Error> { - let (acpi_table_file, acpi_table_data_file, ima_data_file); - - if !Path::new(ACPI_TABLE_FILE_VM).exists() { - if !Path::new(ACPI_TABLE_FILE_CONTAINER).exists() { - return Err(anyhow!( - "[process_cc_eventlog] Failed to find TDX CCEL table file at {:?} or {:?}", - ACPI_TABLE_FILE_VM, - ACPI_TABLE_FILE_CONTAINER - )); - } else { - acpi_table_file = ACPI_TABLE_FILE_CONTAINER.to_string(); - } - } else { - acpi_table_file = ACPI_TABLE_FILE_VM.to_string(); - } - - if !Path::new(ACPI_TABLE_DATA_FILE_VM).exists() { - if !Path::new(ACPI_TABLE_DATA_FILE_CONTAINER).exists() { - return Err(anyhow!( - "[process_cc_eventlog] Failed to find TDX CCEL table data at {:?} or {:?}", - ACPI_TABLE_DATA_FILE_VM, - ACPI_TABLE_DATA_FILE_CONTAINER - )); - } else { - acpi_table_data_file = ACPI_TABLE_DATA_FILE_CONTAINER.to_string(); - } - } else { - acpi_table_data_file = ACPI_TABLE_DATA_FILE_VM.to_string(); - } - - // read ACPI data - let ccel_file = File::open(acpi_table_file)?; - let mut ccel_reader = BufReader::new(ccel_file); - let mut ccel = Vec::new(); - ccel_reader.read_to_end(&mut ccel)?; - let ccel_char_vec = ['C', 'C', 'E', 'L']; - let ccel_u8_vec: Vec = ccel_char_vec.iter().map(|c| *c as u8).collect::>(); - if ccel.is_empty() || (ccel[0..4].to_vec() != ccel_u8_vec) { - return Err(anyhow!("[process_cc_eventlog] Invalid CCEL table")); - } - - let boot_time_data_file = File::open(acpi_table_data_file)?; - let mut boot_time_data_reader = BufReader::new(boot_time_data_file); - let mut boot_time_data = Vec::new(); - boot_time_data_reader.read_to_end(&mut boot_time_data)?; - - // read IMA data - /* - First check if the identifier 'ima_hash=sha384' exists on kernel cmdline - If yes, suppose IMA over RTMR enabled in kernel (IMA over RTMR patch included in - https://github.com/intel/tdx-tools/blob/tdx-1.5/build/common/patches-tdx-kernel-MVP-KERNEL-6.2.16-v5.0.tar.gz) - If not, suppose IMA over RTMR not enabled in kernel - */ - - if !Path::new(IMA_DATA_FILE_VM).exists() { - if !Path::new(IMA_DATA_FILE_CONTAINER).exists() { - return Err(anyhow!( - "[process_cc_eventlog] Failed to find TDX CCEL table data at {:?} or {:?}", - IMA_DATA_FILE_VM, - IMA_DATA_FILE_CONTAINER - )); - } else { - ima_data_file = IMA_DATA_FILE_CONTAINER.to_string(); - } - } else { - ima_data_file = IMA_DATA_FILE_VM.to_string(); - } - - let mut run_time_data = Vec::new(); - - let cmdline_file = File::open("/proc/cmdline")?; - let mut cmdline_reader = BufReader::new(cmdline_file); - let mut cmdline_string = String::new(); - let _ = cmdline_reader.read_to_string(&mut cmdline_string); - if cmdline_string.contains("ima_hash=sha384") { - run_time_data = read_to_string(ima_data_file) - .unwrap() - .lines() - .map(String::from) - .collect(); - } - - let mut eventlogs = EventLogs::new(boot_time_data, run_time_data, TCG_PCCLIENT_FORMAT); - eventlogs.select(start, count) - } - - fn replay_eventlog( - &self, - eventlogs: Vec, - ) -> Result, anyhow::Error> { - EventLogs::replay(eventlogs, TdxRTMR::max_index().into()) - } - - // CVM trait function: retrive CVM type - fn get_cc_type(&self) -> CcType { - self.cc_type.clone() - } - - // CVM trait function: dump CVM basic information - fn dump(&self) { - info!("======================================"); - info!("CVM type = {}", self.cc_type.tee_type_str); - info!( - "CVM version = {}", - TDX_VERSION_MAP.get(&self.version).unwrap().to_owned() - ); - info!("======================================"); - } -} - -impl TcgAlgorithmRegistry for TdxVM { - // TcgAlgorithmRegistry trait function: return CVM default algorithm ID - fn get_algorithm_id(&self) -> u16 { - self.algo_id - } - - fn get_algorithm_id_str(&self) -> String { - ALGO_NAME_MAP.get(&self.algo_id).unwrap().to_owned() - } -} - -impl BuildCVM for TdxVM {} diff --git a/vmsdk/rust/sample/Cargo.toml b/vmsdk/rust/sample/Cargo.toml deleted file mode 100644 index 473b72a7..00000000 --- a/vmsdk/rust/sample/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -name = "cctrusted-sample" -version = "0.1.0" -edition = "2021" -license = "Apache-2.0" - -[[bin]] -name = "cc-sample-quote" -path = "src/cc-sample-quote.rs" - -[[bin]] -name = "cc-sample-measurement" -path = "src/cc-sample-measurement.rs" - -[[bin]] -name = "cc-sample-eventlog" -path = "src/cc-sample-eventlog.rs" - -[dependencies] -cctrusted_vm = { path = "../cctrusted_vm" } -cctrusted_base = { path = "../../../common/rust/cctrusted_base" } -anyhow = "1.0" -log = "0.4.20" -env_logger = "0.10.1" -base64 = "0.13.0" -rand = "0.8.5" \ No newline at end of file diff --git a/vmsdk/rust/sample/src/cc-sample-eventlog.rs b/vmsdk/rust/sample/src/cc-sample-eventlog.rs deleted file mode 100644 index d7c8949b..00000000 --- a/vmsdk/rust/sample/src/cc-sample-eventlog.rs +++ /dev/null @@ -1,61 +0,0 @@ -use cctrusted_base::api::*; -use cctrusted_base::tcg::EventLogEntry; -use cctrusted_vm::sdk::API; -use log::*; - -fn main() { - // set log level - env_logger::init_from_env(env_logger::Env::new().default_filter_or("info")); - - // retrieve cc eventlog with API "get_cc_eventlog" - let eventlogs = match API::get_cc_eventlog(Some(0), None) { - Ok(r) => r, - Err(e) => { - error!("error getting TDX report: {:?}", e); - return; - } - }; - - info!("event log count: {}", eventlogs.len()); - // for eventlog in &eventlogs { - // eventlog.show(); - // } - - // replay cc eventlog with API "replay_cc_eventlog" - let replay_results = match API::replay_cc_eventlog(eventlogs) { - Ok(r) => r, - Err(e) => { - error!("error replay eventlog: {:?}", e); - return; - } - }; - - // show replay results - for replay_result in replay_results { - replay_result.show(); - } - - // retrieve cc eventlog in batch - let mut eventlogs1: Vec = Vec::new(); - let mut start = 0; - let batch_size = 10; - loop { - let event_logs = match API::get_cc_eventlog(Some(start), Some(batch_size)) { - Ok(q) => q, - Err(e) => { - error!("error get eventlog: {:?}", e); - return; - } - }; - for event_log in &event_logs { - eventlogs1.push(event_log.clone()); - } - if !event_logs.is_empty() { - start += event_logs.len() as u32; - } else { - break; - } - } - - info!("event log count: {}", eventlogs1.len()); -} diff --git a/vmsdk/rust/sample/src/cc-sample-measurement.rs b/vmsdk/rust/sample/src/cc-sample-measurement.rs deleted file mode 100644 index 55076838..00000000 --- a/vmsdk/rust/sample/src/cc-sample-measurement.rs +++ /dev/null @@ -1,54 +0,0 @@ -use cctrusted_base::api::*; -use cctrusted_base::tcg::TcgAlgorithmRegistry; -use cctrusted_vm::sdk::API; - -use log::*; - -fn main() { - // set log level - env_logger::init_from_env(env_logger::Env::new().default_filter_or("info")); - - // get CVM default algorithm with API "get_default_algorithm" - info!("call cc trusted API [get_default_algorithm] to get CVM supported algorithm!"); - let defalt_algo = match API::get_default_algorithm() { - Ok(algorithm) => { - info!("supported algorithm: {}", algorithm.algo_id_str); - algorithm - } - Err(e) => { - error!("error get algorithm: {:?}", e); - return; - } - }; - - // get number of measurement registers in CVM - info!("call cc trusted API [get_measurement_count] to get number of measurement registers in CVM!"); - let count = match API::get_measurement_count() { - Ok(count) => { - info!("measurement registers count: {}", count); - count - } - Err(e) => { - error!("error get measurement count: {:?}", e); - return; - } - }; - - // retrive and show measurement registers in CVM - info!("call cc trusted API [get_cc_measurement] to get measurement register content in CVM!"); - for index in 0..count { - let tcg_digest = match API::get_cc_measurement(index, defalt_algo.algo_id) { - Ok(tcg_digest) => tcg_digest, - Err(e) => { - error!("error get measurement: {:?}", e); - return; - } - }; - info!( - "show index = {}, algo = {:?}, hash = {:02X?}", - index, - tcg_digest.get_algorithm_id_str(), - tcg_digest.get_hash() - ); - } -} diff --git a/vmsdk/rust/sample/src/cc-sample-quote.rs b/vmsdk/rust/sample/src/cc-sample-quote.rs deleted file mode 100644 index 622c697d..00000000 --- a/vmsdk/rust/sample/src/cc-sample-quote.rs +++ /dev/null @@ -1,55 +0,0 @@ -use cctrusted_base::api::*; -use cctrusted_base::api_data::*; -use cctrusted_base::cc_type::TeeType; -use cctrusted_base::tdx::quote::TdxQuote; -use cctrusted_vm::sdk::API; - -use log::*; -use rand::Rng; - -fn main() { - // set log level - env_logger::init_from_env(env_logger::Env::new().default_filter_or("info")); - - /*** - * Note: in real user case, the nonce should come from attestation server - * side to prevent replay attack and the data should be generate by API caller - * according to user define spec - */ - let nonce = base64::encode(rand::thread_rng().gen::<[u8; 32]>()); - let data = base64::encode(rand::thread_rng().gen::<[u8; 32]>()); - - // retrieve cc report with API "get_cc_report" - info!("call cc trusted API [get_cc_report] to retrieve cc report!"); - let report = match API::get_cc_report(Some(nonce), Some(data), ExtraArgs {}) { - Ok(q) => q, - Err(e) => { - error!("error getting TDX report: {:?}", e); - return; - } - }; - - // dump the cc report with API "dump_cc_report" - //info!("call cc trusted API [dump_cc_report] to dump cc report!"); - API::dump_cc_report(&report.cc_report); - - // parse the cc report with API "parse_cc_report" - if report.cc_type == TeeType::TDX { - let tdx_quote: TdxQuote = match CcReport::parse_cc_report(report.cc_report) { - Ok(q) => q, - Err(e) => { - error!("error parse tdx quote: {:?}", e); - return; - } - }; - info!( - "version = {}, report_data = {}", - tdx_quote.header.version, - base64::encode(tdx_quote.body.report_data) - ); - - // show data of the struct TdxQuoteHeader - info!("call struct show function to show data of the struct TdxQuoteHeader!"); - tdx_quote.header.show(); - } -}