diff --git a/CLAUDE.md b/CLAUDE.md index 2a2f5043..c85c936a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -210,8 +210,7 @@ RPC definitions use `prpc` framework with Protocol Buffers: ### Working with TDX Quotes -- Low-level bindings: `tdx-attest-sys/` (FFI to libtdx-attest) -- High-level API: `tdx-attest/` +- Pure Rust API: `tdx-attest/` - Verification: `verifier/` using `dcap-qvl` - Event log parsing: `cc-eventlog/` diff --git a/Cargo.lock b/Cargo.lock index 46ffc994..c363f2b9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -984,26 +984,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bindgen" -version = "0.71.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" -dependencies = [ - "bitflags 2.10.0", - "cexpr", - "clang-sys", - "itertools 0.13.0", - "log", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn 2.0.111", -] - [[package]] name = "bit-set" version = "0.8.0" @@ -1354,15 +1334,6 @@ dependencies = [ "tracing-subscriber", ] -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - [[package]] name = "cfg-if" version = "1.0.4" @@ -1409,17 +1380,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "clang-sys" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" -dependencies = [ - "glob", - "libc", - "libloading", -] - [[package]] name = "clap" version = "4.5.53" @@ -4207,16 +4167,6 @@ version = "0.2.178" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" -[[package]] -name = "libloading" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" -dependencies = [ - "cfg-if", - "windows-link 0.2.1", -] - [[package]] name = "libm" version = "0.2.15" @@ -4754,28 +4704,6 @@ dependencies = [ "libc", ] -[[package]] -name = "num_enum" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" -dependencies = [ - "num_enum_derive", - "rustversion", -] - -[[package]] -name = "num_enum_derive" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 2.0.111", -] - [[package]] name = "nybbles" version = "0.4.6" @@ -7373,25 +7301,19 @@ version = "0.5.6" dependencies = [ "anyhow", "cc-eventlog", + "dcap-qvl", "fs-err", "hex", "insta", - "num_enum", + "libc", "parity-scale-codec", "serde", "serde-human-bytes", "serde_json", "sha2 0.10.9", - "tdx-attest-sys", "thiserror 2.0.17", -] - -[[package]] -name = "tdx-attest-sys" -version = "0.5.6" -dependencies = [ - "bindgen", - "cc", + "tokio", + "vsock", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 0eec1d1c..3a75109b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,6 @@ members = [ "kms/rpc", "ra-rpc", "ra-tls", - "tdx-attest-sys", "tdx-attest", "dstack-attest", "dstack-util", @@ -69,7 +68,6 @@ cc-eventlog = { path = "cc-eventlog" } supervisor = { path = "supervisor" } supervisor-client = { path = "supervisor/client" } tdx-attest = { path = "tdx-attest" } -tdx-attest-sys = { path = "tdx-attest-sys" } dstack-attest = { path = "dstack-attest" } certbot = { path = "certbot" } rocket-vsock-listener = { path = "rocket-vsock-listener" } diff --git a/LICENSES/BSD-3-Clause.txt b/LICENSES/BSD-3-Clause.txt deleted file mode 100644 index ea890afb..00000000 --- a/LICENSES/BSD-3-Clause.txt +++ /dev/null @@ -1,11 +0,0 @@ -Copyright (c) . - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/REUSE.toml b/REUSE.toml index 18aced85..44b27da0 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -115,11 +115,6 @@ SPDX-FileCopyrightText = "NONE" SPDX-License-Identifier = "Apache-2.0" precedence = "override" -[[annotations]] -path = "tdx-attest-sys/csrc/*" -SPDX-FileCopyrightText = "Copyright (C) 2011-2021 Intel Corporation. All rights reserved." -SPDX-License-Identifier = "BSD-3-Clause" - [[annotations]] path = "mod-tdx-guest/Kconfig" SPDX-FileCopyrightText = "© 2022 Intel Corporation" diff --git a/tdx-attest-sys/Cargo.lock b/tdx-attest-sys/Cargo.lock deleted file mode 100644 index 52d7f54c..00000000 --- a/tdx-attest-sys/Cargo.lock +++ /dev/null @@ -1,286 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "bindgen" -version = "0.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" -dependencies = [ - "bitflags", - "cexpr", - "clang-sys", - "itertools", - "log", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn", -] - -[[package]] -name = "bitflags" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" - -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "clang-sys" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" -dependencies = [ - "glob", - "libc", - "libloading", -] - -[[package]] -name = "either" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" - -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - -[[package]] -name = "itertools" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" -dependencies = [ - "either", -] - -[[package]] -name = "libc" -version = "0.2.158" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" - -[[package]] -name = "libloading" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" -dependencies = [ - "cfg-if", - "windows-targets", -] - -[[package]] -name = "log" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "prettyplease" -version = "0.2.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" -dependencies = [ - "proc-macro2", - "syn", -] - -[[package]] -name = "proc-macro2" -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "regex" -version = "1.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "syn" -version = "2.0.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578e081a14e0cefc3279b0472138c513f37b41a08d5a3cca9b6e4e8ceb6cd525" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tdx-attest-sys" -version = "0.1.0" -dependencies = [ - "bindgen", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/tdx-attest-sys/Cargo.toml b/tdx-attest-sys/Cargo.toml deleted file mode 100644 index 01cdd7a4..00000000 --- a/tdx-attest-sys/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -# SPDX-FileCopyrightText: © 2024 Phala Network -# -# SPDX-License-Identifier: Apache-2.0 - -[package] -name = "tdx-attest-sys" -version.workspace = true -authors.workspace = true -edition.workspace = true -license.workspace = true - -[dependencies] - -[build-dependencies] -bindgen.workspace = true -cc.workspace = true diff --git a/tdx-attest-sys/bindings.h b/tdx-attest-sys/bindings.h deleted file mode 100644 index afd97d06..00000000 --- a/tdx-attest-sys/bindings.h +++ /dev/null @@ -1,7 +0,0 @@ -/* - * SPDX-FileCopyrightText: © 2024 Phala Network - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "csrc/tdx_attest.h" diff --git a/tdx-attest-sys/build.rs b/tdx-attest-sys/build.rs deleted file mode 100644 index 9e30e05f..00000000 --- a/tdx-attest-sys/build.rs +++ /dev/null @@ -1,25 +0,0 @@ -// SPDX-FileCopyrightText: © 2024 Phala Network -// -// SPDX-License-Identifier: Apache-2.0 - -#![allow(clippy::expect_used)] - -use std::env; -use std::path::PathBuf; - -fn main() { - println!("cargo:rerun-if-changed=csrc/tdx_attest.c"); - println!("cargo:rerun-if-changed=csrc/qgs_msg_lib.cpp"); - let output_path = PathBuf::from(env::var("OUT_DIR").expect("OUT_DIR not set")); - bindgen::Builder::default() - .header("bindings.h") - .default_enum_style(bindgen::EnumVariation::ModuleConsts) - .generate() - .expect("Unable to generate bindings") - .write_to_file(output_path.join("bindings.rs")) - .expect("Couldn't write bindings!"); - cc::Build::new() - .file("csrc/tdx_attest.c") - .file("csrc/qgs_msg_lib.cpp") - .compile("tdx_attest"); -} diff --git a/tdx-attest-sys/csrc/README.txt b/tdx-attest-sys/csrc/README.txt deleted file mode 100644 index 16af54a4..00000000 --- a/tdx-attest-sys/csrc/README.txt +++ /dev/null @@ -1,2 +0,0 @@ -The C source code is forked from: https://github.com/intel/SGXDataCenterAttestationPrimitives/tree/DCAP_1.21/QuoteGeneration/quote_wrapper/tdx_attest -without functionality modification. diff --git a/tdx-attest-sys/csrc/qgs_msg_lib.cpp b/tdx-attest-sys/csrc/qgs_msg_lib.cpp deleted file mode 100644 index 254f673f..00000000 --- a/tdx-attest-sys/csrc/qgs_msg_lib.cpp +++ /dev/null @@ -1,1073 +0,0 @@ -/* - * Copyright (C) 2011-2021 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "qgs_msg_lib.h" - -#include -#include - -const uint32_t QGS_MSG_LIB_MAJOR_VER = 1; -const uint32_t QGS_MSG_LIB_MINOR_VER = 1; - -void qgs_msg_free(void *p_buf) { - free(p_buf); -} - -/** - * @brief Generate serialized get_quote request - * - * @param p_report Cannot be NULL - * @param report_size Cannot be 0 - * @param p_id_list Can be NULL - * @param id_list_size Can be 0 - * @param pp_req returned serialized buffer, valid only if the return code is QGS_MSG_SUCCESS - * @param p_req_size return size of the serialized buffer, valid only if the return code is QGS_MSG_SUCCESS - * @return qgs_msg_error_t - */ -qgs_msg_error_t qgs_msg_gen_get_quote_req( - const uint8_t *p_report, uint32_t report_size, - const uint8_t *p_id_list, uint32_t id_list_size, - uint8_t **pp_req, uint32_t *p_req_size) { - qgs_msg_error_t ret = QGS_MSG_SUCCESS; - qgs_msg_get_quote_req_t *p_req = NULL; - uint32_t buf_size = 0; - uint64_t temp = 0; - - if (!p_report || !report_size) { - ret = QGS_MSG_ERROR_INVALID_PARAMETER; - goto ret_point; - } - - if ((!p_id_list && id_list_size) || (p_id_list && !id_list_size)) { - ret = QGS_MSG_ERROR_INVALID_PARAMETER; - goto ret_point; - } - - if (!pp_req || !p_req_size) { - ret = QGS_MSG_ERROR_INVALID_PARAMETER; - goto ret_point; - } - - temp = sizeof(*p_req); - temp += report_size; - temp += id_list_size; - if (temp < UINT32_MAX) { - buf_size = temp & UINT32_MAX; - } else { - ret = QGS_MSG_ERROR_UNEXPECTED; - goto ret_point; - } - p_req = (qgs_msg_get_quote_req_t *)calloc(buf_size, sizeof(uint8_t)); - if (!p_req) { - ret = QGS_MSG_ERROR_OUT_OF_MEMORY; - goto ret_point; - } - - p_req->header.major_version = QGS_MSG_LIB_MAJOR_VER; - p_req->header.minor_version = QGS_MSG_LIB_MINOR_VER; - p_req->header.type = GET_QUOTE_REQ; - p_req->header.size = buf_size; - p_req->header.error_code = 0; - - p_req->report_size = report_size; - p_req->id_list_size = id_list_size; - memcpy(p_req->report_id_list, p_report, report_size); - if (id_list_size) { - memcpy(p_req->report_id_list + report_size, p_id_list, id_list_size); - } - *pp_req = (uint8_t *)p_req; - *p_req_size = buf_size; - ret = QGS_MSG_SUCCESS; - -ret_point : - return ret; -} - -/** - * @brief Generate serialized get_collateral request - * - * @param p_fsmpc Cannot be NULL - * @param fsmpc_size Cannot be 0 - * @param p_pckca Cannot be NULL - * @param pckca_size Cannot be 0 - * @param pp_req returned serialized buffer, valid only if the return code is QGS_MSG_SUCCESS - * @param p_req_size return size of the serialized buffer, valid only if the return code is QGS_MSG_SUCCESS - * @return qgs_msg_error_t - */ -qgs_msg_error_t qgs_msg_gen_get_collateral_req( - const uint8_t *p_fsmpc, uint32_t fsmpc_size, - const uint8_t *p_pckca, uint32_t pckca_size, - uint8_t **pp_req, uint32_t *p_req_size) { - qgs_msg_error_t ret = QGS_MSG_SUCCESS; - qgs_msg_get_collateral_req_t *p_req = NULL; - uint32_t buf_size = 0; - uint64_t temp = 0; - - if (!p_fsmpc || !fsmpc_size) { - ret = QGS_MSG_ERROR_INVALID_PARAMETER; - goto ret_point; - } - - if (!p_pckca || !pckca_size) { - ret = QGS_MSG_ERROR_INVALID_PARAMETER; - goto ret_point; - } - - if (!pp_req || !p_req_size) { - ret = QGS_MSG_ERROR_INVALID_PARAMETER; - goto ret_point; - } - - temp = sizeof(*p_req); - temp += fsmpc_size; - temp += pckca_size; - if (temp < UINT32_MAX) { - buf_size = temp & UINT32_MAX; - } else { - ret = QGS_MSG_ERROR_UNEXPECTED; - goto ret_point; - } - p_req = (qgs_msg_get_collateral_req_t *)calloc(buf_size, sizeof(uint8_t)); - if (!p_req) { - ret = QGS_MSG_ERROR_OUT_OF_MEMORY; - goto ret_point; - } - - p_req->header.major_version = QGS_MSG_LIB_MAJOR_VER; - p_req->header.minor_version = QGS_MSG_LIB_MINOR_VER; - p_req->header.type = GET_COLLATERAL_REQ; - p_req->header.size = buf_size; - p_req->header.error_code = 0; - - p_req->fsmpc_size = fsmpc_size; - p_req->pckca_size = pckca_size; - memcpy(p_req->fsmpc_pckca, p_fsmpc, fsmpc_size); - memcpy(p_req->fsmpc_pckca + fsmpc_size, p_pckca, pckca_size); - - *pp_req = (uint8_t *)p_req; - *p_req_size = buf_size; - ret = QGS_MSG_SUCCESS; - -ret_point: - return ret; -} - -qgs_msg_error_t qgs_msg_inflate_get_quote_req( - const uint8_t *p_serialized_req, uint32_t size, - const uint8_t **pp_report, uint32_t *p_report_size, - const uint8_t **pp_id_list, uint32_t *p_id_list_size) { - qgs_msg_error_t ret = QGS_MSG_SUCCESS; - qgs_msg_get_quote_req_t *p_req = NULL; - uint64_t temp = 0; - - if (!p_serialized_req || !size) { - ret = QGS_MSG_ERROR_INVALID_PARAMETER; - goto ret_point; - } - - if (!pp_report || !p_report_size) { - ret = QGS_MSG_ERROR_INVALID_PARAMETER; - goto ret_point; - } - - if (!pp_id_list || !p_id_list_size) { - ret = QGS_MSG_ERROR_INVALID_PARAMETER; - goto ret_point; - } - - // sanity check, the size shouldn't smaller than qgs_msg_get_quote_req_t - if (size < sizeof(qgs_msg_get_quote_req_t)) { - ret = QGS_MSG_ERROR_INVALID_PARAMETER; - goto ret_point; - } - - p_req = (qgs_msg_get_quote_req_t *)p_serialized_req; - // Only major version is checked, minor change is deemed as compatible. - if (p_req->header.major_version != QGS_MSG_LIB_MAJOR_VER) { - ret = QGS_MSG_ERROR_INVALID_VERSION; - goto ret_point; - } - - if (p_req->header.type != GET_QUOTE_REQ) { - ret = QGS_MSG_ERROR_INVALID_TYPE; - goto ret_point; - } - - if (p_req->header.size != size) { - ret = QGS_MSG_ERROR_INVALID_SIZE; - goto ret_point; - } - - if (p_req->header.error_code != 0) { - ret = QGS_MSG_ERROR_INVALID_CODE; - goto ret_point; - } - - if (!p_req->report_size) { - ret = QGS_MSG_ERROR_INVALID_CODE; - goto ret_point; - } - - temp = sizeof(qgs_msg_get_quote_req_t); - temp += p_req->report_size; - temp += p_req->id_list_size; - if (temp >= UINT32_MAX) { - ret = QGS_MSG_ERROR_UNEXPECTED; - goto ret_point; - } - if (p_req->header.size != temp) { - ret = QGS_MSG_ERROR_INVALID_SIZE; - goto ret_point; - } - - *pp_report = p_req->report_id_list; - if (p_req->id_list_size) { - *pp_id_list = p_req->report_id_list + p_req->report_size; - } else { - *pp_id_list = NULL; - } - - *p_report_size = p_req->report_size; - *p_id_list_size = p_req->id_list_size; - -ret_point: - return ret; -} - -qgs_msg_error_t qgs_msg_inflate_get_collateral_req( - const uint8_t *p_serialized_req, uint32_t size, - const uint8_t **pp_fsmpc, uint32_t *p_fsmpc_size, - const uint8_t **pp_pckca, uint32_t *p_pckca_size) { - qgs_msg_error_t ret = QGS_MSG_SUCCESS; - qgs_msg_get_collateral_req_t *p_req = NULL; - uint64_t temp = 0; - - if (!p_serialized_req || !size) { - ret = QGS_MSG_ERROR_INVALID_PARAMETER; - goto ret_point; - } - - if (!pp_fsmpc || !p_fsmpc_size) { - ret = QGS_MSG_ERROR_INVALID_PARAMETER; - goto ret_point; - } - - if (!pp_pckca || !p_pckca_size) { - ret = QGS_MSG_ERROR_INVALID_PARAMETER; - goto ret_point; - } - - // sanity check, the size shouldn't smaller than qgs_msg_get_quote_req_t - if (size < sizeof(qgs_msg_get_collateral_req_t)) { - ret = QGS_MSG_ERROR_INVALID_PARAMETER; - goto ret_point; - } - - p_req = (qgs_msg_get_collateral_req_t *)p_serialized_req; - // Only major version is checked, minor change is deemed as compatible. - if (p_req->header.major_version != QGS_MSG_LIB_MAJOR_VER) { - ret = QGS_MSG_ERROR_INVALID_VERSION; - goto ret_point; - } - - if (p_req->header.type != GET_COLLATERAL_REQ) { - ret = QGS_MSG_ERROR_INVALID_TYPE; - goto ret_point; - } - - if (p_req->header.size != size) { - ret = QGS_MSG_ERROR_INVALID_SIZE; - goto ret_point; - } - - if (p_req->header.error_code != 0) { - ret = QGS_MSG_ERROR_INVALID_CODE; - goto ret_point; - } - - if (!p_req->fsmpc_size || !p_req->pckca_size) { - ret = QGS_MSG_ERROR_INVALID_SIZE; - goto ret_point; - } - - temp = sizeof(qgs_msg_get_collateral_req_t); - temp += p_req->fsmpc_size; - temp += p_req->pckca_size; - if (temp >= UINT32_MAX) { - ret = QGS_MSG_ERROR_UNEXPECTED; - goto ret_point; - } - if (p_req->header.size != temp) { - ret = QGS_MSG_ERROR_INVALID_SIZE; - goto ret_point; - } - - *pp_fsmpc = p_req->fsmpc_pckca; - *pp_pckca = p_req->fsmpc_pckca + p_req->fsmpc_size; - - *p_fsmpc_size = p_req->fsmpc_size; - *p_pckca_size = p_req->pckca_size; - -ret_point: - return ret; -} - -qgs_msg_error_t qgs_msg_gen_error_resp( - uint32_t error_code, uint32_t type, - uint8_t **pp_resp, uint32_t *p_resp_size) { - qgs_msg_error_t ret = QGS_MSG_SUCCESS; - uint32_t buf_size = 0; - qgs_msg_header_t *p_resp = NULL; - if (error_code == QGS_MSG_SUCCESS) { - ret = QGS_MSG_ERROR_INVALID_PARAMETER; - goto ret_point; - } - - if (!pp_resp || !p_resp_size) { - ret = QGS_MSG_ERROR_INVALID_PARAMETER; - goto ret_point; - } - - switch (type) { - case GET_QUOTE_RESP: - buf_size = sizeof(qgs_msg_get_quote_resp_t); - break; - case GET_COLLATERAL_RESP: - buf_size = sizeof(qgs_msg_get_collateral_resp_t); - break; - case GET_PLATFORM_INFO_RESP: - buf_size = sizeof(qgs_msg_get_platform_info_resp_t); - break; - default: - ret = QGS_MSG_ERROR_INVALID_TYPE; - goto ret_point; - } - p_resp = (qgs_msg_header_t *)calloc(buf_size, sizeof(uint8_t)); - if (!p_resp) { - ret = QGS_MSG_ERROR_OUT_OF_MEMORY; - goto ret_point; - } - - p_resp->major_version = QGS_MSG_LIB_MAJOR_VER; - p_resp->minor_version = QGS_MSG_LIB_MINOR_VER; - p_resp->type = type; - p_resp->size = buf_size; - p_resp->error_code = error_code; - - *pp_resp = (uint8_t *)p_resp; - *p_resp_size = buf_size; - ret = QGS_MSG_SUCCESS; - -ret_point: - return ret; -} - -qgs_msg_error_t qgs_msg_gen_get_quote_resp( - const uint8_t *p_selected_id, uint32_t id_size, - const uint8_t *p_quote, uint32_t quote_size, - uint8_t **pp_resp, uint32_t *p_resp_size) { - qgs_msg_error_t ret = QGS_MSG_SUCCESS; - qgs_msg_get_quote_resp_t *p_resp = NULL; - uint32_t buf_size = 0; - uint64_t temp = 0; - - if (!pp_resp || !p_resp_size) { - ret = QGS_MSG_ERROR_INVALID_PARAMETER; - goto ret_point; - } - - if ((!p_selected_id && id_size) || (p_selected_id && !id_size)) { - ret = QGS_MSG_ERROR_INVALID_PARAMETER; - goto ret_point; - } - - if (!p_quote || !quote_size) { - ret = QGS_MSG_ERROR_INVALID_PARAMETER; - goto ret_point; - } - - temp = sizeof(*p_resp); - temp += id_size; - temp += quote_size; - if (temp < UINT32_MAX) { - buf_size = temp & UINT32_MAX; - } else { - ret = QGS_MSG_ERROR_UNEXPECTED; - goto ret_point; - } - p_resp = (qgs_msg_get_quote_resp_t *)calloc(buf_size, sizeof(uint8_t)); - if (!p_resp) { - ret = QGS_MSG_ERROR_OUT_OF_MEMORY; - goto ret_point; - } - - p_resp->header.major_version = QGS_MSG_LIB_MAJOR_VER; - p_resp->header.minor_version = QGS_MSG_LIB_MINOR_VER; - p_resp->header.type = GET_QUOTE_RESP; - p_resp->header.size = buf_size; - p_resp->header.error_code = QGS_MSG_SUCCESS; - - p_resp->selected_id_size = id_size; - p_resp->quote_size = quote_size; - if (id_size) { - memcpy(p_resp->id_quote, p_selected_id, id_size); - } - memcpy(p_resp->id_quote + id_size, p_quote, quote_size); - - *pp_resp = (uint8_t *)p_resp; - *p_resp_size = buf_size; - ret = QGS_MSG_SUCCESS; - -ret_point : - return ret; -} - -qgs_msg_error_t qgs_msg_gen_get_collateral_resp( - uint16_t major_version, uint16_t minor_version, - const uint8_t *p_pck_crl_issuer_chain, uint32_t pck_crl_issuer_chain_size, - const uint8_t *p_root_ca_crl, uint32_t root_ca_crl_size, - const uint8_t *p_pck_crl, uint32_t pck_crl_size, - const uint8_t *p_tcb_info_issuer_chain, uint32_t tcb_info_issuer_chain_size, - const uint8_t *p_tcb_info, uint32_t tcb_info_size, - const uint8_t *p_qe_identity_issuer_chain, uint32_t qe_identity_issuer_chain_size, - const uint8_t *p_qe_identity, uint32_t qe_identity_size, - uint8_t **pp_resp, uint32_t *p_resp_size, - const qgs_msg_header_t *p_req_header) { - qgs_msg_error_t ret = QGS_MSG_SUCCESS; - qgs_msg_get_collateral_resp_t *p_resp = NULL; - uint8_t *p_ptr = NULL; - uint32_t buf_size = 0; - uint64_t temp = 0; - - if (!pp_resp || !p_resp_size) { - ret = QGS_MSG_ERROR_INVALID_PARAMETER; - goto ret_point; - } - - //TODO major_version and minor_version are ignored here, is 0.0 a valid version? - if (!p_pck_crl_issuer_chain || !pck_crl_issuer_chain_size - || !p_root_ca_crl || !root_ca_crl_size - || !p_pck_crl || !pck_crl_size - || !p_tcb_info_issuer_chain || !tcb_info_issuer_chain_size - || !p_tcb_info || !tcb_info_size - || !p_qe_identity_issuer_chain || !qe_identity_issuer_chain_size - || !p_qe_identity || !qe_identity_size) { - ret = QGS_MSG_ERROR_INVALID_PARAMETER; - goto ret_point; - } - - if (p_req_header->major_version != QGS_MSG_LIB_MAJOR_VER) { - ret = QGS_MSG_ERROR_INVALID_VERSION; - goto ret_point; - } - if (p_req_header->minor_version == 0) { - temp = sizeof(major_version) + sizeof(minor_version) + sizeof(*p_resp); - } else { - temp = sizeof(*p_resp); - } - temp += pck_crl_issuer_chain_size; - temp += root_ca_crl_size; - temp += pck_crl_size; - temp += tcb_info_issuer_chain_size; - temp += tcb_info_size; - temp += qe_identity_issuer_chain_size; - temp += qe_identity_size; - - if (temp < UINT32_MAX) { - buf_size = temp & UINT32_MAX; - } else { - ret = QGS_MSG_ERROR_UNEXPECTED; - goto ret_point; - } - p_resp = (qgs_msg_get_collateral_resp_t *)calloc(buf_size, sizeof(uint8_t)); - if (!p_resp) { - ret = QGS_MSG_ERROR_OUT_OF_MEMORY; - goto ret_point; - } - - p_resp->header.major_version = QGS_MSG_LIB_MAJOR_VER; - p_resp->header.minor_version = QGS_MSG_LIB_MINOR_VER; - p_resp->header.type = GET_COLLATERAL_RESP; - p_resp->header.size = buf_size; - p_resp->header.error_code = QGS_MSG_SUCCESS; - - p_resp->major_version = major_version; - p_resp->minor_version = minor_version; - p_ptr = p_resp->collaterals; - if (pck_crl_issuer_chain_size) { - p_resp->pck_crl_issuer_chain_size = pck_crl_issuer_chain_size; - memcpy(p_ptr, p_pck_crl_issuer_chain, pck_crl_issuer_chain_size); - p_ptr += pck_crl_issuer_chain_size; - } - - if (root_ca_crl_size) { - p_resp->root_ca_crl_size = root_ca_crl_size; - memcpy(p_ptr, p_root_ca_crl, root_ca_crl_size); - p_ptr += root_ca_crl_size; - } - - if (pck_crl_size) { - p_resp->pck_crl_size = pck_crl_size; - memcpy(p_ptr, p_pck_crl, pck_crl_size); - p_ptr += pck_crl_size; - } - - if (tcb_info_issuer_chain_size) { - p_resp->tcb_info_issuer_chain_size = tcb_info_issuer_chain_size; - memcpy(p_ptr, p_tcb_info_issuer_chain, tcb_info_issuer_chain_size); - p_ptr += tcb_info_issuer_chain_size; - } - - if (tcb_info_size) { - p_resp->tcb_info_size = tcb_info_size; - memcpy(p_ptr, p_tcb_info, tcb_info_size); - p_ptr += tcb_info_size; - } - - if (qe_identity_issuer_chain_size) { - p_resp->qe_identity_issuer_chain_size = qe_identity_issuer_chain_size; - memcpy(p_ptr, p_qe_identity_issuer_chain, qe_identity_issuer_chain_size); - p_ptr += qe_identity_issuer_chain_size; - } - - if (root_ca_crl_size) { - p_resp->qe_identity_size = qe_identity_size; - memcpy(p_ptr, p_qe_identity, qe_identity_size); - } - - *pp_resp = (uint8_t *)p_resp; - *p_resp_size = buf_size; - ret = QGS_MSG_SUCCESS; - -ret_point: - return ret; -} - -qgs_msg_error_t qgs_msg_inflate_get_quote_resp( - const uint8_t *p_serialized_resp, uint32_t size, - const uint8_t **pp_selected_id, uint32_t *p_id_size, - const uint8_t **pp_quote, uint32_t *p_quote_size) { - qgs_msg_error_t ret = QGS_MSG_SUCCESS; - qgs_msg_get_quote_resp_t *p_resp = NULL; - uint64_t temp = 0; - - if (!p_serialized_resp || !size) { - ret = QGS_MSG_ERROR_INVALID_PARAMETER; - goto ret_point; - } - - if (!pp_selected_id || !p_id_size) { - ret = QGS_MSG_ERROR_INVALID_PARAMETER; - goto ret_point; - } - - if (!pp_quote || !p_quote_size) { - ret = QGS_MSG_ERROR_INVALID_PARAMETER; - goto ret_point; - } - - // sanity check, the size shouldn't smaller than qgs_msg_get_quote_req_t - if (size < sizeof(qgs_msg_get_quote_resp_t)) { - ret = QGS_MSG_ERROR_INVALID_PARAMETER; - goto ret_point; - } - - p_resp = (qgs_msg_get_quote_resp_t *)p_serialized_resp; - // Only major version is checked, minor change is deemed as compatible. - if (p_resp->header.major_version != QGS_MSG_LIB_MAJOR_VER) { - ret = QGS_MSG_ERROR_INVALID_VERSION; - goto ret_point; - } - - if (p_resp->header.type != GET_QUOTE_RESP) { - ret = QGS_MSG_ERROR_INVALID_TYPE; - goto ret_point; - } - - if (p_resp->header.size != size) { - ret = QGS_MSG_ERROR_INVALID_SIZE; - goto ret_point; - } - - temp = sizeof(qgs_msg_get_quote_resp_t); - temp += p_resp->selected_id_size; - temp += p_resp->quote_size; - if (temp >= UINT32_MAX) { - ret = QGS_MSG_ERROR_UNEXPECTED; - goto ret_point; - } - if (p_resp->header.size != temp) { - ret = QGS_MSG_ERROR_INVALID_SIZE; - goto ret_point; - } - - if (p_resp->header.error_code == QGS_MSG_SUCCESS) { - if (!p_resp->quote_size) { - // It makes no sense to return success and an empty quote - ret = QGS_MSG_ERROR_INVALID_SIZE; - goto ret_point; - } - if (p_resp->selected_id_size) { - *pp_selected_id = p_resp->id_quote; - *p_id_size = p_resp->selected_id_size; - } else { - *pp_selected_id = NULL; - *p_id_size = 0; - } - *pp_quote = p_resp->id_quote + p_resp->selected_id_size; - *p_quote_size = p_resp->quote_size; - } else if (p_resp->header.error_code < QGS_MSG_ERROR_MAX) { - if (p_resp->selected_id_size || p_resp->quote_size) { - ret = QGS_MSG_ERROR_INVALID_SIZE; - goto ret_point; - } - *pp_selected_id = NULL; - *p_id_size = 0; - *pp_quote = NULL; - *p_quote_size = 0; - } else { - ret = QGS_MSG_ERROR_INVALID_CODE; - goto ret_point; - } - - ret = QGS_MSG_SUCCESS; -ret_point: - return ret; -} - -qgs_msg_error_t qgs_msg_inflate_get_collateral_resp( - const uint8_t *p_serialized_resp, uint32_t size, - uint16_t *p_major_version, uint16_t *p_minor_version, - const uint8_t **pp_pck_crl_issuer_chain, uint32_t *p_pck_crl_issuer_chain_size, - const uint8_t **pp_root_ca_crl, uint32_t *p_root_ca_crl_size, - const uint8_t **pp_pck_crl, uint32_t *p_pck_crl_size, - const uint8_t **pp_tcb_info_issuer_chain, uint32_t *p_tcb_info_issuer_chain_size, - const uint8_t **pp_tcb_info, uint32_t *p_tcb_info_size, - const uint8_t **pp_qe_identity_issuer_chain, uint32_t *p_qe_identity_issuer_chain_size, - const uint8_t **pp_qe_identity, uint32_t *p_qe_identity_size) { - qgs_msg_error_t ret = QGS_MSG_SUCCESS; - qgs_msg_get_collateral_resp_t *p_resp = NULL; - uint64_t temp = 0; - - if (!p_serialized_resp || !size) { - ret = QGS_MSG_ERROR_INVALID_PARAMETER; - goto ret_point; - } - - if (!p_major_version || !p_minor_version - || !pp_pck_crl_issuer_chain || !p_pck_crl_issuer_chain_size - || !pp_root_ca_crl || !p_root_ca_crl_size - || !pp_pck_crl || !p_pck_crl_size - || !pp_tcb_info_issuer_chain || !p_tcb_info_issuer_chain_size - || !pp_tcb_info || !p_tcb_info_size - || !pp_qe_identity_issuer_chain || !p_qe_identity_issuer_chain_size - || !pp_qe_identity || !p_qe_identity_size) { - ret = QGS_MSG_ERROR_INVALID_PARAMETER; - goto ret_point; - } - - // sanity check, the size shouldn't smaller than qgs_msg_get_quote_req_t - if (size < sizeof(qgs_msg_get_collateral_resp_t)) { - ret = QGS_MSG_ERROR_INVALID_PARAMETER; - goto ret_point; - } - - p_resp = (qgs_msg_get_collateral_resp_t *)p_serialized_resp; - // Only major version is checked, minor change is deemed as compatible. - if (p_resp->header.major_version != QGS_MSG_LIB_MAJOR_VER) { - ret = QGS_MSG_ERROR_INVALID_VERSION; - goto ret_point; - } - - if (p_resp->header.type != GET_COLLATERAL_RESP) { - ret = QGS_MSG_ERROR_INVALID_TYPE; - goto ret_point; - } - - if (p_resp->header.size != size) { - ret = QGS_MSG_ERROR_INVALID_SIZE; - goto ret_point; - } - - if (p_resp->header.minor_version == 0) { - temp = sizeof(*p_resp) + sizeof(p_resp->major_version) + sizeof(p_resp->minor_version); - } else { - temp = sizeof(*p_resp); - } - temp += p_resp->pck_crl_issuer_chain_size; - temp += p_resp->root_ca_crl_size; - temp += p_resp->pck_crl_size; - temp += p_resp->tcb_info_issuer_chain_size; - temp += p_resp->tcb_info_size; - temp += p_resp->qe_identity_issuer_chain_size; - temp += p_resp->qe_identity_size; - - if (temp >= UINT32_MAX) { - ret = QGS_MSG_ERROR_UNEXPECTED; - goto ret_point; - } - if (p_resp->header.size != temp) { - ret = QGS_MSG_ERROR_INVALID_SIZE; - goto ret_point; - } - - if (p_resp->header.error_code == QGS_MSG_SUCCESS) { - // It makes no sense to return success and empty collaterals - if (!p_resp->pck_crl_issuer_chain_size - || !p_resp->root_ca_crl_size - || !p_resp->pck_crl_size - || !p_resp->tcb_info_issuer_chain_size - || !p_resp->tcb_info_size - || !p_resp->qe_identity_issuer_chain_size - || !p_resp->qe_identity_size) { - ret = QGS_MSG_ERROR_INVALID_SIZE; - goto ret_point; - } - *p_major_version = p_resp->major_version; - *p_minor_version = p_resp->minor_version; - - *pp_pck_crl_issuer_chain = p_resp->collaterals; - *p_pck_crl_issuer_chain_size = p_resp->pck_crl_issuer_chain_size; - - *pp_root_ca_crl = *pp_pck_crl_issuer_chain + p_resp->pck_crl_issuer_chain_size; - *p_root_ca_crl_size = p_resp->root_ca_crl_size; - - *pp_pck_crl = *pp_root_ca_crl + p_resp->root_ca_crl_size; - *p_pck_crl_size = p_resp->pck_crl_size; - - *pp_tcb_info_issuer_chain = *pp_pck_crl + p_resp->pck_crl_size; - *p_tcb_info_issuer_chain_size = p_resp->tcb_info_issuer_chain_size; - - *pp_tcb_info = *pp_tcb_info_issuer_chain + p_resp->tcb_info_issuer_chain_size; - *p_tcb_info_size = p_resp->tcb_info_size; - - *pp_qe_identity_issuer_chain = *pp_tcb_info + p_resp->tcb_info_size; - *p_qe_identity_issuer_chain_size = p_resp->qe_identity_issuer_chain_size; - - *pp_qe_identity = *pp_qe_identity_issuer_chain + p_resp->qe_identity_issuer_chain_size; - *p_qe_identity_size = p_resp->qe_identity_size; - - } else if (p_resp->header.error_code < QGS_MSG_ERROR_MAX) { - if (p_resp->pck_crl_issuer_chain_size - || p_resp->root_ca_crl_size - || p_resp->pck_crl_size - || p_resp->tcb_info_issuer_chain_size - || p_resp->tcb_info_size - || p_resp->qe_identity_issuer_chain_size - || p_resp->qe_identity_size) { - ret = QGS_MSG_ERROR_INVALID_SIZE; - goto ret_point; - } - *p_major_version = 0; - *p_minor_version = 0; - - *pp_pck_crl_issuer_chain = NULL; - *p_pck_crl_issuer_chain_size = 0; - *pp_root_ca_crl = NULL; - *p_root_ca_crl_size = 0; - *pp_pck_crl = NULL; - *p_pck_crl_size = 0; - *pp_tcb_info_issuer_chain = NULL; - *p_tcb_info_issuer_chain_size = 0; - *pp_tcb_info = NULL; - *p_tcb_info_size = 0; - *pp_qe_identity_issuer_chain = NULL; - *p_qe_identity_issuer_chain_size = 0; - *pp_qe_identity = NULL; - *p_qe_identity_size = 0; - } else { - ret = QGS_MSG_ERROR_INVALID_CODE; - goto ret_point; - } - - ret = QGS_MSG_SUCCESS; -ret_point: - return ret; -} - -uint32_t qgs_msg_get_type(const uint8_t *p_serialized_msg, uint32_t size, uint32_t *p_type) { - qgs_msg_error_t ret = QGS_MSG_SUCCESS; - const qgs_msg_header_t *p_header = (const qgs_msg_header_t *)p_serialized_msg; - - if (size < sizeof(qgs_msg_header_t)) { - ret = QGS_MSG_ERROR_INVALID_PARAMETER; - goto ret_point; - } - - if (p_header->major_version != QGS_MSG_LIB_MAJOR_VER) { - ret = QGS_MSG_ERROR_INVALID_VERSION; - goto ret_point; - } - if (p_header->type >= QGS_MSG_TYPE_MAX) { - ret = QGS_MSG_ERROR_INVALID_VERSION; - goto ret_point; - } - *p_type = p_header->type; - ret = QGS_MSG_SUCCESS; -ret_point: - return ret; -} - -qgs_msg_error_t qgs_msg_gen_get_platform_info_req( - uint8_t **pp_req, uint32_t *p_req_size) -{ - qgs_msg_error_t ret = QGS_MSG_SUCCESS; - qgs_msg_get_platform_info_req_t *p_req = NULL; - - if (!pp_req || !p_req_size) { - ret = QGS_MSG_ERROR_INVALID_PARAMETER; - goto ret_point; - } - - p_req = (qgs_msg_get_platform_info_req_t *)calloc(sizeof(*p_req), sizeof(uint8_t)); - if (!p_req) { - ret = QGS_MSG_ERROR_OUT_OF_MEMORY; - goto ret_point; - } - - p_req->header.major_version = QGS_MSG_LIB_MAJOR_VER; - p_req->header.minor_version = QGS_MSG_LIB_MINOR_VER; - p_req->header.type = GET_PLATFORM_INFO_REQ; - p_req->header.size = sizeof(*p_req); - p_req->header.error_code = 0; - - *pp_req = (uint8_t *)p_req; - *p_req_size = sizeof(*p_req); - ret = QGS_MSG_SUCCESS; - -ret_point: - return ret; -} - -qgs_msg_error_t qgs_msg_inflate_get_platform_info_req( - const uint8_t *p_serialized_req, uint32_t size) -{ - qgs_msg_error_t ret = QGS_MSG_SUCCESS; - qgs_msg_get_platform_info_req_t *p_req = NULL; - - if (!p_serialized_req || !size) { - ret = QGS_MSG_ERROR_INVALID_PARAMETER; - goto ret_point; - } - - // sanity check, the size shouldn't smaller than qgs_msg_get_platform_info_req_t - if (size < sizeof(qgs_msg_get_platform_info_req_t)) { - ret = QGS_MSG_ERROR_INVALID_PARAMETER; - goto ret_point; - } - - p_req = (qgs_msg_get_platform_info_req_t *)p_serialized_req; - // Only major version is checked, minor change is deemed as compatible. - if (p_req->header.major_version != QGS_MSG_LIB_MAJOR_VER) { - ret = QGS_MSG_ERROR_INVALID_VERSION; - goto ret_point; - } - - if (p_req->header.type != GET_PLATFORM_INFO_REQ) { - ret = QGS_MSG_ERROR_INVALID_TYPE; - goto ret_point; - } - - if (p_req->header.size != size) { - ret = QGS_MSG_ERROR_INVALID_SIZE; - goto ret_point; - } - - if (p_req->header.error_code != 0) { - ret = QGS_MSG_ERROR_INVALID_CODE; - goto ret_point; - } - -ret_point: - return ret; -} - -qgs_msg_error_t qgs_msg_gen_get_platform_info_resp( - uint16_t tdqe_isvsvn, uint16_t pce_isvsvn, - const uint8_t *p_platform_id, uint32_t platform_id_size, - const uint8_t *p_cpusvn, uint32_t cpusvn_size, - uint8_t **pp_resp, uint32_t *p_resp_size) -{ - qgs_msg_error_t ret = QGS_MSG_SUCCESS; - qgs_msg_get_platform_info_resp_t *p_resp = NULL; - uint32_t buf_size = 0; - uint64_t temp = 0; - uint8_t *p_ptr = NULL; - - if (!pp_resp || !p_resp_size) { - ret = QGS_MSG_ERROR_INVALID_PARAMETER; - goto ret_point; - } - - if ((!p_platform_id || !platform_id_size)) { - ret = QGS_MSG_ERROR_INVALID_PARAMETER; - goto ret_point; - } - - if (!p_cpusvn || !cpusvn_size) { - ret = QGS_MSG_ERROR_INVALID_PARAMETER; - goto ret_point; - } - - temp = sizeof(tdqe_isvsvn) + sizeof(pce_isvsvn) + sizeof(*p_resp); - temp += platform_id_size + cpusvn_size; - if (temp < UINT32_MAX) { - buf_size = temp & UINT32_MAX; - } else { - ret = QGS_MSG_ERROR_UNEXPECTED; - goto ret_point; - } - p_resp = (qgs_msg_get_platform_info_resp_t *)calloc(buf_size, sizeof(uint8_t)); - if (!p_resp) { - ret = QGS_MSG_ERROR_OUT_OF_MEMORY; - goto ret_point; - } - - p_resp->header.major_version = QGS_MSG_LIB_MAJOR_VER; - p_resp->header.minor_version = QGS_MSG_LIB_MINOR_VER; - p_resp->header.type = GET_PLATFORM_INFO_RESP; - p_resp->header.size = buf_size; - p_resp->header.error_code = QGS_MSG_SUCCESS; - - p_resp->platform_id_size = platform_id_size; - p_resp->cpusvn_size = cpusvn_size; - - p_resp->tdqe_isvsvn = tdqe_isvsvn; - p_resp->pce_isvsvn = pce_isvsvn; - - p_ptr = p_resp->platform_id_cpusvn; - memcpy(p_ptr, p_platform_id, platform_id_size); - p_ptr += platform_id_size; - - memcpy(p_ptr, p_cpusvn, cpusvn_size); - - *pp_resp = (uint8_t *)p_resp; - *p_resp_size = buf_size; - ret = QGS_MSG_SUCCESS; - -ret_point: - return ret; -} - -qgs_msg_error_t qgs_msg_inflate_get_platform_info_resp( - const uint8_t *p_serialized_resp, uint32_t size, - uint16_t *p_tdqe_isvsvn, uint16_t *p_pce_isvsvn, - const uint8_t **pp_platform_id, uint32_t *p_platform_id_size, - const uint8_t **pp_cpusvn, uint32_t *p_cpusvn_size) -{ - qgs_msg_error_t ret = QGS_MSG_SUCCESS; - qgs_msg_get_platform_info_resp_t *p_resp = NULL; - uint64_t temp = 0; - - if (!p_serialized_resp || !size) { - ret = QGS_MSG_ERROR_INVALID_PARAMETER; - goto ret_point; - } - - if (!pp_platform_id || !p_platform_id_size - || !pp_cpusvn || !p_cpusvn_size - || !p_tdqe_isvsvn || !p_pce_isvsvn) { - ret = QGS_MSG_ERROR_INVALID_PARAMETER; - goto ret_point; - } - - // sanity check, the size shouldn't smaller than qgs_msg_get_quote_req_t - if (size < sizeof(qgs_msg_get_platform_info_resp_t)) { - ret = QGS_MSG_ERROR_INVALID_PARAMETER; - goto ret_point; - } - - p_resp = (qgs_msg_get_platform_info_resp_t *)p_serialized_resp; - // Only major version is checked, minor change is deemed as compatible. - if (p_resp->header.major_version != QGS_MSG_LIB_MAJOR_VER) { - ret = QGS_MSG_ERROR_INVALID_VERSION; - goto ret_point; - } - - if (p_resp->header.type != GET_PLATFORM_INFO_RESP) { - ret = QGS_MSG_ERROR_INVALID_TYPE; - goto ret_point; - } - - if (p_resp->header.size != size) { - ret = QGS_MSG_ERROR_INVALID_SIZE; - goto ret_point; - } - - temp = sizeof(p_resp->tdqe_isvsvn) + sizeof(p_resp->pce_isvsvn) + sizeof(*p_resp); - temp += p_resp->platform_id_size; - temp += p_resp->cpusvn_size; - if (temp >= UINT32_MAX) { - ret = QGS_MSG_ERROR_UNEXPECTED; - goto ret_point; - } - if (p_resp->header.size != temp) { - ret = QGS_MSG_ERROR_INVALID_SIZE; - goto ret_point; - } - - if (p_resp->header.error_code == QGS_MSG_SUCCESS) { - // It makes no sense to return success and empty platform info - if (!p_resp->platform_id_size || !p_resp->cpusvn_size) { - ret = QGS_MSG_ERROR_INVALID_SIZE; - goto ret_point; - } - *p_tdqe_isvsvn = p_resp->tdqe_isvsvn; - *p_pce_isvsvn = p_resp->pce_isvsvn; - - *pp_platform_id = p_resp->platform_id_cpusvn; - *p_platform_id_size = p_resp->platform_id_size; - - *pp_cpusvn = *pp_platform_id + p_resp->platform_id_size; - *p_cpusvn_size = p_resp->cpusvn_size; - - } else if (p_resp->header.error_code < QGS_MSG_ERROR_MAX) { - if (p_resp->platform_id_size || p_resp->cpusvn_size) { - ret = QGS_MSG_ERROR_INVALID_SIZE; - goto ret_point; - } - *p_tdqe_isvsvn = 0; - *p_pce_isvsvn = 0; - - *pp_platform_id = NULL; - *p_platform_id_size = 0; - - *pp_cpusvn = NULL; - *p_cpusvn_size = 0; - } else { - ret = QGS_MSG_ERROR_INVALID_CODE; - goto ret_point; - } - - ret = QGS_MSG_SUCCESS; -ret_point: - return ret; -} \ No newline at end of file diff --git a/tdx-attest-sys/csrc/qgs_msg_lib.h b/tdx-attest-sys/csrc/qgs_msg_lib.h deleted file mode 100644 index c235806c..00000000 --- a/tdx-attest-sys/csrc/qgs_msg_lib.h +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright (C) 2011-2021 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - - -/** - * File: qgs_msg_lib.h - * - * Description: Message and API definitions for TDX QGS messages - * - */ -#ifndef _QGS_MSG_DEF_H_ -#define _QGS_MSG_DEF_H_ -#include - -#ifndef QGS_MSG_MK_ERROR -#define QGS_MSG_MK_ERROR(x) (0x00012000 | (x)) -#endif - -#pragma pack(push, 1) - -/** Possible errors generated by the qgs message library. */ -typedef enum _qgs_msg_error_t { - QGS_MSG_SUCCESS = 0x0000, ///< Success - QGS_MSG_ERROR_UNEXPECTED = QGS_MSG_MK_ERROR(0x0001), ///< Unexpected error - QGS_MSG_ERROR_OUT_OF_MEMORY = QGS_MSG_MK_ERROR(0x0002), ///< Not enough memory is available to complete this operation - QGS_MSG_ERROR_INVALID_PARAMETER = QGS_MSG_MK_ERROR(0x0003), ///< The parameter is incorrect - QGS_MSG_ERROR_INVALID_VERSION = QGS_MSG_MK_ERROR(0x0004), ///< Unrecognized version of serialized data - QGS_MSG_ERROR_INVALID_TYPE = QGS_MSG_MK_ERROR(0x0005), ///< Invalid message type found - QGS_MSG_ERROR_INVALID_SIZE = QGS_MSG_MK_ERROR(0x0006), ///< Invalid message size found - QGS_MSG_ERROR_INVALID_CODE = QGS_MSG_MK_ERROR(0x0007), ///< Invalid error code - - QGS_MSG_ERROR_MAX, ///< Indicate max error to allow better translation. -} qgs_msg_error_t; - -typedef enum _qgs_msg_type_t { - GET_QUOTE_REQ = 0, - GET_QUOTE_RESP = 1, - GET_COLLATERAL_REQ = 2, - GET_COLLATERAL_RESP = 3, - GET_PLATFORM_INFO_REQ = 4, - GET_PLATFORM_INFO_RESP = 5, - QGS_MSG_TYPE_MAX -} qgs_msg_type_t; - -typedef struct _qgs_msg_header_t { - uint16_t major_version; - uint16_t minor_version; - uint32_t type; - uint32_t size; // size of the whole message, include this header, in byte - uint32_t error_code; // used in response only -} qgs_msg_header_t; - -typedef struct _qgs_msg_get_quote_req_t { - qgs_msg_header_t header; // header.type = GET_QUOTE_REQ - uint32_t report_size; // cannot be 0 - uint32_t id_list_size; // length of id_list, in byte, can be 0 - uint8_t report_id_list[]; // report followed by id list -} qgs_msg_get_quote_req_t; - -typedef struct _qgs_msg_get_quote_resp_s { - qgs_msg_header_t header; // header.type = GET_QUOTE_RESP - uint32_t selected_id_size; // can be 0 in case only one id is sent in request - uint32_t quote_size; // length of quote_data, in byte - uint8_t id_quote[]; // selected id followed by quote -} qgs_msg_get_quote_resp_t; - -typedef struct _qgs_msg_get_collateral_req_t { - qgs_msg_header_t header; // header.type = GET_COLLATERAL_REQ - uint32_t fsmpc_size; // length of fsmpc, in byte - uint32_t pckca_size; // length of pckca, in byte - uint8_t fsmpc_pckca[]; // fsmpc followed by pckca -} qgs_msg_get_collateral_req_t; - -typedef struct _qgs_msg_get_collateral_resp_s { - qgs_msg_header_t header; // header.type = GET_COLLATERAL_RESP - uint16_t major_version; - uint16_t minor_version; - uint32_t pck_crl_issuer_chain_size; - uint32_t root_ca_crl_size; - uint32_t pck_crl_size; - uint32_t tcb_info_issuer_chain_size; - uint32_t tcb_info_size; - uint32_t qe_identity_issuer_chain_size; - uint32_t qe_identity_size; - uint8_t collaterals[]; // payload filled in same order as upper sizes parameters -} qgs_msg_get_collateral_resp_t; - -typedef struct _qgs_msg_get_platform_info_req_t { - qgs_msg_header_t header; // header.type = GET_PLATFORM_INFO_REQ -} qgs_msg_get_platform_info_req_t; - -typedef struct _qgs_msg_get_platform_info_resp_s { - qgs_msg_header_t header; // header.type = GET_PLATFORM_INFO_RESP - uint16_t tdqe_isvsvn; - uint16_t pce_isvsvn; - uint32_t platform_id_size; - uint32_t cpusvn_size; - uint8_t platform_id_cpusvn[]; -} qgs_msg_get_platform_info_resp_t; - -#pragma pack(pop) - -#if defined(__cplusplus) -extern "C" { -#endif -void qgs_msg_free(void *buf); - -qgs_msg_error_t qgs_msg_gen_get_quote_req( - const uint8_t *p_report, uint32_t report_size, - const uint8_t *p_id_list, uint32_t id_list_size, - uint8_t **pp_req, uint32_t *p_req_size); -qgs_msg_error_t qgs_msg_gen_get_collateral_req( - const uint8_t *p_fsmpc, uint32_t fsmpc_size, - const uint8_t *p_pckca, uint32_t pckca_size, - uint8_t **pp_req, uint32_t *p_req_size); - -qgs_msg_error_t qgs_msg_inflate_get_quote_req( - const uint8_t *p_serialized_req, uint32_t size, - const uint8_t **pp_report, uint32_t *p_report_size, - const uint8_t **pp_id_list, uint32_t *p_id_list_size); -qgs_msg_error_t qgs_msg_inflate_get_collateral_req( - const uint8_t *p_serialized_req, uint32_t size, - const uint8_t **pp_fsmpc, uint32_t *p_fsmpc_size, - const uint8_t **pp_pckca, uint32_t *p_pckca_size); - -qgs_msg_error_t qgs_msg_gen_error_resp( - uint32_t error_code, uint32_t type, - uint8_t **pp_resp, uint32_t *p_resp_size); - -qgs_msg_error_t qgs_msg_gen_get_quote_resp( - const uint8_t *p_selected_id, uint32_t id_size, - const uint8_t *p_quote, uint32_t quote_size, - uint8_t **pp_resp, uint32_t *p_resp_size); -qgs_msg_error_t qgs_msg_gen_get_collateral_resp( - uint16_t major_version, uint16_t minor_version, - const uint8_t *p_pck_crl_issuer_chain, uint32_t pck_crl_issuer_chain_size, - const uint8_t *p_root_ca_crl, uint32_t root_ca_crl_size, - const uint8_t *p_pck_crl, uint32_t pck_crl_size, - const uint8_t *p_tcb_info_issuer_chain, uint32_t tcb_info_issuer_chain_size, - const uint8_t *p_tcb_info, uint32_t tcb_info_size, - const uint8_t *p_qe_identity_issuer_chain, uint32_t qe_identity_issuer_chain_size, - const uint8_t *p_qe_identity, uint32_t qe_identity_size, - uint8_t **pp_resp, uint32_t *p_resp_size, - const qgs_msg_header_t *p_req_header); - -qgs_msg_error_t qgs_msg_inflate_get_quote_resp( - const uint8_t *p_serialized_resp, uint32_t size, - const uint8_t **pp_selected_id, uint32_t *p_id_size, - const uint8_t **pp_quote, uint32_t *p_quote_size); -qgs_msg_error_t qgs_msg_inflate_get_collateral_resp( - const uint8_t *p_serialized_resp, uint32_t size, - uint16_t *p_major_version, uint16_t *p_minor_version, - const uint8_t **pp_pck_crl_issuer_chain, uint32_t *p_pck_crl_issuer_chain_size, - const uint8_t **pp_root_ca_crl, uint32_t *p_root_ca_crl_size, - const uint8_t **pp_pck_crl, uint32_t *p_pck_crl_size, - const uint8_t **pp_tcb_info_issuer_chain, uint32_t *p_tcb_info_issuer_chain_size, - const uint8_t **pp_tcb_info, uint32_t *p_tcb_info_size, - const uint8_t **pp_qe_identity_issuer_chain, uint32_t *p_qe_identity_issuer_chain_size, - const uint8_t **pp_qe_identity, uint32_t *p_qe_identity_size); -uint32_t qgs_msg_get_type(const uint8_t *p_serialized_msg, uint32_t size, uint32_t *p_type); - -qgs_msg_error_t qgs_msg_gen_get_platform_info_req( - uint8_t **pp_req, uint32_t *p_req_size); -qgs_msg_error_t qgs_msg_inflate_get_platform_info_req( - const uint8_t *p_serialized_req, uint32_t size); -qgs_msg_error_t qgs_msg_gen_get_platform_info_resp( - uint16_t tdqe_isvsvn, uint16_t pce_isvsvn, - const uint8_t *p_platform_id, uint32_t platform_id_size, - const uint8_t *p_cpusvn, uint32_t cpusvn_size, - uint8_t **pp_resp, uint32_t *p_resp_size); -qgs_msg_error_t qgs_msg_inflate_get_platform_info_resp( - const uint8_t *p_serialized_resp, uint32_t size, - uint16_t *p_tdqe_isvsvn, uint16_t *p_pce_isvsvn, - const uint8_t **pp_platform_id, uint32_t *p_platform_id_size, - const uint8_t **pp_cpusvn, uint32_t *p_cpusvn_size); - -#if defined(__cplusplus) -} -#endif - -#endif \ No newline at end of file diff --git a/tdx-attest-sys/csrc/tdx_attest.c b/tdx-attest-sys/csrc/tdx_attest.c deleted file mode 100644 index 5b6a9399..00000000 --- a/tdx-attest-sys/csrc/tdx_attest.c +++ /dev/null @@ -1,1045 +0,0 @@ -/* - * Copyright (C) 2011-2021 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef SERVTD_ATTEST - -#define _GNU_SOURCE -#include -#include -#include "qgs_msg_lib.h" -#include "tdx_attest.h" - -#include -#include -#include -#include -#include // For strtoul -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define TDX_ATTEST_DEV_PATH "/dev/tdx_guest" -#define CFG_FILE_PATH "/etc/tdx-attest.conf" -#define DCAP_TDX_QUOTE_CONFIGFS_PATH_ENV "DCAP_TDX_QUOTE_CONFIGFS_PATH" -#define QUOTE_CONFIGFS_PATH "/sys/kernel/config/tsm/report" -#define DEFAULT_DCAP_TDX_QUOTE_CONFIGFS_PATH QUOTE_CONFIGFS_PATH"/com.intel.dcap" - -// TODO: Should include kernel header, but the header file are included by -// different package in differnt distro, and installed in different locations. -// So add these defines here. Need to remove them later when kernel header -// became stable. - -#define TDX_CMD_GET_REPORT0 _IOWR('T', 1, struct tdx_report_req) -#ifdef V3_DRIVER -#define TDX_CMD_VERIFY_REPORT _IOWR('T', 2, struct tdx_verify_report_req) -#define TDX_CMD_EXTEND_RTMR _IOW('T', 3, struct tdx_extend_rtmr_req) -#define TDX_CMD_GET_QUOTE _IOWR('T', 4, struct tdx_quote_req) -#else -#define TDX_CMD_VERIFY_REPORT _IOR('T', 2, struct tdx_verify_report_req) -#define TDX_CMD_EXTEND_RTMR _IOR('T', 3, struct tdx_extend_rtmr_req) -#define TDX_CMD_GET_QUOTE _IOR('T', 4, struct tdx_quote_req) -#endif - - -/* TD Quote status codes */ -#define GET_QUOTE_SUCCESS 0 -#define GET_QUOTE_IN_FLIGHT 0xffffffffffffffff -#define GET_QUOTE_ERROR 0x8000000000000000 -#define GET_QUOTE_SERVICE_UNAVAILABLE 0x8000000000000001 - -#define TDX_EXTEND_RTMR_DATA_LEN 48 - -#ifdef DEBUG -#define TDX_TRACE \ - do { \ - fprintf(stderr, "\n[%s:%d] ", __FILE__, __LINE__); \ - perror(NULL); \ - }while(0) -#else -#define TDX_TRACE -#endif - -struct tdx_report_req { - __u8 reportdata[TDX_REPORT_DATA_SIZE]; - __u8 tdreport[TDX_REPORT_SIZE]; -}; - -struct tdx_extend_rtmr_req { - __u8 data[TDX_EXTEND_RTMR_DATA_LEN]; - __u8 index; -}; - -struct tdx_quote_hdr { - /* Quote version, filled by TD */ - __u64 version; - /* Status code of Quote request, filled by VMM */ - __u64 status; - /* Length of TDREPORT, filled by TD */ - __u32 in_len; - /* Length of Quote, filled by VMM */ - __u32 out_len; - /* Actual Quote data or TDREPORT on input */ - __u64 data[0]; -}; - -struct tdx_quote_req { - __u64 buf; - __u64 len; -}; - -static const unsigned HEADER_SIZE = 4; -static const size_t REQ_BUF_SIZE = 4 * 4 * 1024; // 4 pages -static const size_t QUOTE_BUF_SIZE = 8 * 1024; //8K -static const size_t QUOTE_MIN_SIZE = 1020; - -static const tdx_uuid_t g_intel_tdqe_uuid = {TDX_SGX_ECDSA_ATTESTATION_ID}; - -static unsigned int get_vsock_port(void) -{ - FILE *p_config_fd = NULL; - char *p_line = NULL; - char *p = NULL; - size_t line_len = 0; - long long_num = 0; - unsigned int port = 0; - - p_config_fd = fopen(CFG_FILE_PATH, "r"); - if (NULL == p_config_fd) { - TDX_TRACE; - return 0; - } - while(-1 != getline(&p_line, &line_len, p_config_fd)) { - char temp[11] = {0}; - int number = 0; - int ret = sscanf(p_line, " %10[#]", temp); - if (ret == 1) { - continue; - } - /* leading or trailing white space are ignored, white space around '=' - are also ignored. The number should no longer than 10 characters. - Trailing non-whitespace are not allowed. */ - ret = sscanf(p_line, " port = %10[0-9] %n", temp, &number); - /* Make sure number is positive then make the cast. It's not likely to - have a negtive value, just a defense-in-depth. The cast is used to - suppress the -Wsign-compare warning. */ - if (ret == 1 && number > 0 && ((size_t)number < line_len) - && !p_line[number]) { - errno = 0; - long_num = strtol(temp, &p, 10); - if (p == temp) { - TDX_TRACE; - port = 0; - break; - } - - // make sure that no range error occurred - if (errno == ERANGE || long_num > UINT_MAX) { - TDX_TRACE; - port = 0; - break; - } - - // range is ok, so we can convert to int - port = (unsigned int)long_num & 0xFFFFFFFF; -#ifdef DEBUG - fprintf(stdout, "\nGet the vsock port number [%u]\n", port); -#endif - break; - } - } - - /* p_line is allocated by sscanf */ - free(p_line); - fclose(p_config_fd); - - return port; -} - -static tdx_attest_error_t get_tdx_report( - int devfd, - const tdx_report_data_t *p_tdx_report_data, - tdx_report_t *p_tdx_report) -{ - if (-1 == devfd) { - return TDX_ATTEST_ERROR_UNEXPECTED; - } - if (!p_tdx_report) { - fprintf(stderr, "\nNeed to input TDX report."); - return TDX_ATTEST_ERROR_INVALID_PARAMETER; - } - if (!p_tdx_report_data) { - fprintf(stderr, "\nNeed to input TDX report data."); - return TDX_ATTEST_ERROR_INVALID_PARAMETER; - } - struct tdx_report_req req = {0}; - memcpy(req.reportdata, p_tdx_report_data->d, sizeof(req.reportdata)); - - if (-1 == ioctl(devfd, TDX_CMD_GET_REPORT0, &req)) { - TDX_TRACE; - return TDX_ATTEST_ERROR_REPORT_FAILURE; - } - memcpy(p_tdx_report->d, req.tdreport, sizeof(p_tdx_report->d)); - return TDX_ATTEST_SUCCESS; -} - -#define MAX_PATH 260 - -static int b_mkdir = 1; -pthread_mutex_t mkdir_mutex; - -void __attribute__((constructor)) init_mutex(void) { pthread_mutex_init(&mkdir_mutex, NULL); } -void __attribute__((destructor)) destroy_mutex(void) { pthread_mutex_destroy(&mkdir_mutex); } - -static tdx_attest_error_t prepare_configfs(char **p_configfs_path) { - int ret = TDX_ATTEST_ERROR_NOT_SUPPORTED; - char *configfs_path = NULL; - do { - // Retrive DCAP TDX quote configFS path from environment - configfs_path = secure_getenv(DCAP_TDX_QUOTE_CONFIGFS_PATH_ENV); - if (configfs_path == NULL) { - syslog(LOG_INFO, "libtdx_attest: env '%s' is not provided - try default path.", - DCAP_TDX_QUOTE_CONFIGFS_PATH_ENV); - break; - } - if (strnlen(configfs_path, MAX_PATH) >= MAX_PATH - 20) { - syslog(LOG_ERR, "libtdx_attest: env '%s' is too long.", DCAP_TDX_QUOTE_CONFIGFS_PATH_ENV); - return ret; - } - - // Check whether the configFS directory exists - DIR *dir = opendir(configfs_path); - if (dir == NULL) { - syslog(LOG_ERR, "libtdx_attest: env '%s' is not valid directory.", - DCAP_TDX_QUOTE_CONFIGFS_PATH_ENV); - return ret; - } - closedir(dir); - ret = TDX_ATTEST_SUCCESS; - } while (0); - - while (ret != TDX_ATTEST_SUCCESS) { - // Default DCAP TDX quote configFS path - ret = TDX_ATTEST_ERROR_NOT_SUPPORTED; - configfs_path = DEFAULT_DCAP_TDX_QUOTE_CONFIGFS_PATH; - pthread_mutex_lock(&mkdir_mutex); - DIR *dir = opendir(configfs_path); - if (dir != NULL) { - pthread_mutex_unlock(&mkdir_mutex); - ret = TDX_ATTEST_SUCCESS; - closedir(dir); - break; - } - if (errno != ENOENT) { - pthread_mutex_unlock(&mkdir_mutex); - syslog(LOG_INFO, "libtdx_attest: default DCAP configFS not supported - fallback to vsock mode."); - break; - } - - // Create default DCAP TDX quote configFS path only once - if (!b_mkdir) { - pthread_mutex_unlock(&mkdir_mutex); - syslog(LOG_INFO, "libtdx_attest: default DCAP configFS not supported - fallback to vsock mode."); - break; - } - b_mkdir = 0; - - dir = opendir(QUOTE_CONFIGFS_PATH); - if (dir == NULL) { - pthread_mutex_unlock(&mkdir_mutex); - syslog(LOG_INFO, "libtdx_attest: configFS not supported - fallback to vsock mode."); - break; - } - closedir(dir); - - if (mkdir(configfs_path, S_IRWXU | S_IRWXG)) { - pthread_mutex_unlock(&mkdir_mutex); - if (errno == EEXIST && (dir = opendir(configfs_path)) != NULL) { - // Another process has just created configfs_path - ret = TDX_ATTEST_SUCCESS; - closedir(dir); - break; - } - syslog(LOG_INFO, "libtdx_attest: cannot create default configFS - fallback to vsock mode."); - break; - } - char provider_path[MAX_PATH]; - snprintf(provider_path, sizeof(provider_path), "%s/provider", configfs_path); - for (size_t retry = 0; retry < 5; retry++) { - // Linux kernel will create provider, generation, inblob, outblob in configfs_path - // after configfs_path direcotry created. - if (access(provider_path, F_OK) == 0) { - pthread_mutex_unlock(&mkdir_mutex); - ret = TDX_ATTEST_SUCCESS; - break; - } - usleep((useconds_t)retry); - } - pthread_mutex_unlock(&mkdir_mutex); - syslog(LOG_INFO, "libtdx_attest: unavailable default configFS - fallback to vsock mode."); - break; - } - - if (ret != TDX_ATTEST_SUCCESS) { - //Both configfs path are unavailable - return ret; - } - - // For Intel TDX, provider is "tdx_guest" - char provider_path[MAX_PATH]; - snprintf(provider_path, sizeof(provider_path), "%s/provider", configfs_path); - int fd = open(provider_path, O_RDONLY); - if (-1 == fd) { - TDX_TRACE; - syslog(LOG_ERR, "libtdx_attest: cannot open configFS `%s`.", provider_path); - return TDX_ATTEST_ERROR_UNEXPECTED; - } - - // Read the entire file in one shot - char provider[16] = {0}; - ssize_t byte_size = read(fd, provider, 15); - close(fd); - - if (byte_size == -1 || byte_size == 0 || - strncmp(provider, "tdx_guest", sizeof("tdx_guest") - 1)) { - syslog(LOG_ERR, "libtdx_attest: configFS unsupported provider."); - return TDX_ATTEST_ERROR_NOT_SUPPORTED; - } - *p_configfs_path = configfs_path; - return TDX_ATTEST_SUCCESS; -} - -static tdx_attest_error_t read_configfs_generation(char *generation_path, long* p_generation) -{ - int fd = open(generation_path, O_RDONLY); - if (-1 == fd) { - TDX_TRACE; - syslog(LOG_ERR, "libtdx_attest: failed to open configFS generation."); - return TDX_ATTEST_ERROR_UNEXPECTED; - } -#ifdef DEBUG - fprintf(stdout, "\nstart to read generation\n"); -#endif - #define GENERATION_MAX_LENGTH 20 - char str_generation[GENERATION_MAX_LENGTH] = {0}; - ssize_t byte_size = read(fd, str_generation, GENERATION_MAX_LENGTH); - if (byte_size == -1) { - TDX_TRACE; - close(fd); - syslog(LOG_ERR, "libtdx_attest: failed to read configFS generation."); - return TDX_ATTEST_ERROR_UNEXPECTED; - } - close(fd); - if (byte_size == 0) { - syslog(LOG_ERR, "libtdx_attest: no content of configFS generation."); - return TDX_ATTEST_ERROR_UNEXPECTED; - } - if (byte_size >= GENERATION_MAX_LENGTH) { - syslog(LOG_ERR, "libtdx_attest: too large configFS generation."); - return TDX_ATTEST_ERROR_UNEXPECTED; - } - - errno = 0; - long generation = strtol(str_generation, NULL, 10); - if (errno != 0) { - TDX_TRACE; - syslog(LOG_ERR, "libtdx_attest: cannot parse configFS generation."); - return TDX_ATTEST_ERROR_UNEXPECTED; - } - *p_generation = generation; - -#ifdef DEBUG - fprintf(stdout, "\ngeneration: %ld\n", generation); -#endif - return TDX_ATTEST_SUCCESS; -} - -#define RETRY_WAIT_TIME_USEC 10000000 - -tdx_attest_error_t tdx_att_get_quote( - const tdx_report_data_t *p_tdx_report_data, - const tdx_uuid_t *p_att_key_id_list, - uint32_t list_size, - tdx_uuid_t *p_att_key_id, - uint8_t **pp_quote, - uint32_t *p_quote_size, - uint32_t flags) -{ - int s = -1; - int devfd = -1; - - const uint8_t *p_quote = NULL; - uint32_t quote_size = 0; - tdx_attest_error_t ret = TDX_ATTEST_ERROR_UNEXPECTED; - uint8_t *p_blob_payload = NULL; - - if ((!p_att_key_id_list && list_size) || - (p_att_key_id_list && !list_size)) { - return TDX_ATTEST_ERROR_INVALID_PARAMETER; - } - if (!pp_quote) { - return TDX_ATTEST_ERROR_INVALID_PARAMETER; - } - if (flags) { - //TODO: I think we need to have a runtime version to make this flag usable. - return TDX_ATTEST_ERROR_INVALID_PARAMETER; - } - - // Currently only intel TDQE are supported - if (1 < list_size) { - return TDX_ATTEST_ERROR_INVALID_PARAMETER; - } - if (p_att_key_id_list && memcmp(p_att_key_id_list, &g_intel_tdqe_uuid, - sizeof(g_intel_tdqe_uuid))) { - return TDX_ATTEST_ERROR_UNSUPPORTED_ATT_KEY_ID; - } - - *pp_quote = NULL; - - do { - char *configfs_path = NULL; - if (prepare_configfs(&configfs_path) != TDX_ATTEST_SUCCESS) - break; - - char inblob_path[MAX_PATH]; - snprintf(inblob_path, sizeof(inblob_path), "%s/inblob", configfs_path); - - // Lock `inblob` to avoid other processes accessing it using libtdx_attest - // Will unlock it via close() - int fd_lock = open(inblob_path, O_WRONLY | O_CLOEXEC); - if (-1 == fd_lock) { - TDX_TRACE; - syslog(LOG_ERR, "libtdx_attest: failed to open configFS inblob."); - return TDX_ATTEST_ERROR_UNEXPECTED; - } - if (flock(fd_lock, LOCK_EX)) { - TDX_TRACE; - close(fd_lock); - syslog(LOG_ERR, "libtdx_attest: failed to lock configFS inblob."); - return TDX_ATTEST_ERROR_UNEXPECTED; - } - - /* Read and check generation value before writing inblob, after writing inblob and after - reading outblob to make sure that outblob matches inblob */ - char generation_path[MAX_PATH]; - snprintf(generation_path, sizeof(generation_path), "%s/generation", configfs_path); - long generation1; - ret = read_configfs_generation(generation_path, &generation1); - if (ret) { - close(fd_lock); - return ret; - } - - // Write TDX report data to inblob - int fd_inblob = open(inblob_path, O_WRONLY); - if (-1 == fd_inblob) { - TDX_TRACE; - close(fd_lock); - syslog(LOG_ERR, "libtdx_attest: failed to open configFS inblob."); - return TDX_ATTEST_ERROR_UNEXPECTED; - } - - ssize_t byte_size = 0; - // Wait and retry when EBUSY; other TDX Quotes are being generating - for (int retry = 0; retry < 3; retry++) { - errno = 0; - byte_size = write(fd_inblob, p_tdx_report_data, sizeof(*p_tdx_report_data)); - if (errno != EBUSY) - break; - usleep(RETRY_WAIT_TIME_USEC); - } - if (byte_size != sizeof(*p_tdx_report_data)) { - if (errno == EBUSY) { - TDX_TRACE; - ret = TDX_ATTEST_ERROR_BUSY; - } else { - TDX_TRACE; - ret = TDX_ATTEST_ERROR_UNEXPECTED; - } - close(fd_lock); - close(fd_inblob); - syslog(LOG_ERR, "libtdx_attest: failed to write configFS inblob."); - return ret; - } - close(fd_inblob); - - long generation2; - do { - ret = read_configfs_generation(generation_path, &generation2); - if (ret) { - close(fd_lock); - return ret; - } - // In rare cases, generation is not updated - } while (generation2 == generation1 && !usleep(0)); - if (generation2 != generation1 + 1) { - // Another TDX quote generation has been triggered - close(fd_lock); - return TDX_ATTEST_ERROR_BUSY; - } - - // Read TDX quote from outblob - char outblob_path[MAX_PATH]; - snprintf(outblob_path, sizeof(outblob_path), "%s/outblob", configfs_path); - int fd = open(outblob_path, O_RDONLY); - if (-1 == fd) { - TDX_TRACE; - syslog(LOG_ERR, "libtdx_attest: failed to open configFS outblob."); - close(fd_lock); - return TDX_ATTEST_ERROR_UNEXPECTED; - } - - // Allocate memory for the entire file content - p_blob_payload = malloc(QUOTE_BUF_SIZE); - if (p_blob_payload == NULL) { - close(fd_lock); - close(fd); - return TDX_ATTEST_ERROR_OUT_OF_MEMORY; - } -#ifdef DEBUG - fprintf(stdout, "\nstart to read outblob\n"); -#endif - // Read the entire file in one shot - for (int retry = 0; retry < 3; retry++) { - errno = 0; - byte_size = read(fd, p_blob_payload, QUOTE_BUF_SIZE); - if (errno == EBUSY) { - usleep(RETRY_WAIT_TIME_USEC); - } else if (errno != EINTR && errno != ETIMEDOUT) - break; - } - if (byte_size == -1 || byte_size == 0) { - if (errno == EBUSY || errno == EINTR || errno == ETIMEDOUT) { - TDX_TRACE; - ret = TDX_ATTEST_ERROR_BUSY; - } else - ret = TDX_ATTEST_ERROR_QUOTE_FAILURE; - close(fd_lock); - close(fd); - free(p_blob_payload); - syslog(LOG_ERR, "libtdx_attest: failed to read outblob."); - return ret; - } - close(fd); - - quote_size = (uint32_t)byte_size; -#ifdef DEBUG - fprintf(stdout, "\nquote size: %d\n", quote_size); -#endif - if (quote_size <= QUOTE_MIN_SIZE || quote_size == QUOTE_BUF_SIZE) { - close(fd_lock); - free(p_blob_payload); - return TDX_ATTEST_ERROR_QUOTE_FAILURE; - } - - long generation3; - ret = read_configfs_generation(generation_path, &generation3); - close(fd_lock); - if (ret) { - free(p_blob_payload); - return ret; - } - // Another TDX quote generation is triggered - if (generation3 != generation2) { - free(p_blob_payload); - return TDX_ATTEST_ERROR_BUSY; - } - - void* tmp_p = realloc(p_blob_payload, quote_size); - if (tmp_p == NULL) { - free(p_blob_payload); - return TDX_ATTEST_ERROR_OUT_OF_MEMORY; - } - *pp_quote = tmp_p; - - if (p_quote_size) { - *p_quote_size = quote_size; - } - if (p_att_key_id) { - *p_att_key_id = g_intel_tdqe_uuid; - } - return TDX_ATTEST_SUCCESS; - } while (0); - -#ifdef DEBUG - fprintf(stdout, "\ngoto legacy logic\n"); -#endif - - uint32_t recieved_bytes = 0; - uint32_t in_msg_size = 0; - unsigned int vsock_port = 0; - uint32_t msg_size = 0; - qgs_msg_error_t qgs_msg_ret = QGS_MSG_SUCCESS; - qgs_msg_header_t *p_header = NULL; - uint8_t *p_req = NULL; - const uint8_t *p_selected_id = NULL; - uint32_t id_size = 0; - - tdx_report_t tdx_report; - memset(&tdx_report, 0, sizeof(tdx_report)); - - struct tdx_quote_hdr *p_get_quote_blob = malloc(REQ_BUF_SIZE); - if (!p_get_quote_blob) { - ret = TDX_ATTEST_ERROR_OUT_OF_MEMORY; - goto ret_point; - } - - devfd = open(TDX_ATTEST_DEV_PATH, O_RDWR | O_SYNC); - if (-1 == devfd) { - TDX_TRACE; - ret = TDX_ATTEST_ERROR_DEVICE_FAILURE; - goto ret_point; - } - - ret = get_tdx_report(devfd, p_tdx_report_data, &tdx_report); - if (TDX_ATTEST_SUCCESS != ret) { - goto ret_point; - } - - qgs_msg_ret = qgs_msg_gen_get_quote_req(tdx_report.d, sizeof(tdx_report.d), - NULL, 0, &p_req, &msg_size); - if (QGS_MSG_SUCCESS != qgs_msg_ret) { -#ifdef DEBUG - fprintf(stdout, "\nqgs_msg_gen_get_quote_req return 0x%x\n", qgs_msg_ret); -#endif - ret = TDX_ATTEST_ERROR_UNEXPECTED; - goto ret_point; - } - - if (msg_size > REQ_BUF_SIZE - sizeof(struct tdx_quote_hdr) - HEADER_SIZE) { -#ifdef DEBUG - fprintf(stdout, "\nqmsg_size[%d] is too big\n", msg_size); - #endif - ret = TDX_ATTEST_ERROR_NOT_SUPPORTED; - goto ret_point; - } - - p_blob_payload = (uint8_t *)&p_get_quote_blob->data; - p_blob_payload[0] = (uint8_t)((msg_size >> 24) & 0xFF); - p_blob_payload[1] = (uint8_t)((msg_size >> 16) & 0xFF); - p_blob_payload[2] = (uint8_t)((msg_size >> 8) & 0xFF); - p_blob_payload[3] = (uint8_t)(msg_size & 0xFF); - - memcpy(p_blob_payload + HEADER_SIZE, p_req, msg_size); - - do { - vsock_port = get_vsock_port(); - if (!vsock_port) { - syslog(LOG_INFO, "libtdx_attest: cannot parse sock port - fallback to tdvmcall mode."); - break; - } - s = socket(AF_VSOCK, SOCK_STREAM, 0); - if (-1 == s) { - syslog(LOG_INFO, "libtdx_attest: cannot create socket - fallback to tdvmcall mode."); - break; - } - struct sockaddr_vm vm_addr; - memset(&vm_addr, 0, sizeof(vm_addr)); - vm_addr.svm_family = AF_VSOCK; - vm_addr.svm_reserved1 = 0; - vm_addr.svm_port = vsock_port; - vm_addr.svm_cid = VMADDR_CID_HOST; - if (connect(s, (struct sockaddr *)&vm_addr, sizeof(vm_addr))) { - syslog(LOG_INFO, "libtdx_attest: cannot connect - fallback to tdvmcall mode."); - break; - } - - // Write to socket - if (HEADER_SIZE + msg_size != send(s, p_blob_payload, - HEADER_SIZE + msg_size, 0)) { - TDX_TRACE; - ret = TDX_ATTEST_ERROR_VSOCK_FAILURE; - goto ret_point; - } - - // Read the response size header - if (HEADER_SIZE != recv(s, p_blob_payload, - HEADER_SIZE, 0)) { - TDX_TRACE; - ret = TDX_ATTEST_ERROR_VSOCK_FAILURE; - goto ret_point; - } - - // decode the size - for (unsigned i = 0; i < HEADER_SIZE; ++i) { - in_msg_size = in_msg_size * 256 + ((p_blob_payload[i]) & 0xFF); - } - - // prepare the buffer and read the reply body - #ifdef DEBUG - fprintf(stdout, "\nReply message body is %u bytes", in_msg_size); - #endif - - if (REQ_BUF_SIZE - sizeof(struct tdx_quote_hdr) - HEADER_SIZE < in_msg_size) { - #ifdef DEBUG - fprintf(stdout, "\nReply message body is too big"); - #endif - ret = TDX_ATTEST_ERROR_UNEXPECTED; - goto ret_point; - } - while( recieved_bytes < in_msg_size) { - int recv_ret = (int)recv(s, p_blob_payload + HEADER_SIZE + recieved_bytes, - in_msg_size - recieved_bytes, 0); - if (recv_ret < 0) { - ret = TDX_ATTEST_ERROR_VSOCK_FAILURE; - goto ret_point; - } - recieved_bytes += (uint32_t)recv_ret; - } - #ifdef DEBUG - fprintf(stdout, "\nGet %u bytes response from vsock", recieved_bytes); - #endif - - goto done; - } while (0); - - int ioctl_ret; - struct tdx_quote_req arg; - p_get_quote_blob->version = 1; - p_get_quote_blob->status = 0; - p_get_quote_blob->in_len = HEADER_SIZE + msg_size; - p_get_quote_blob->out_len = 0; - arg.buf = (__u64)p_get_quote_blob; - arg.len = REQ_BUF_SIZE; - - ioctl_ret = ioctl(devfd, TDX_CMD_GET_QUOTE, &arg); - if (EBUSY == ioctl_ret) { - TDX_TRACE; - ret = TDX_ATTEST_ERROR_BUSY; - goto ret_point; - } else if (ioctl_ret) { - TDX_TRACE; - ret = TDX_ATTEST_ERROR_QUOTE_FAILURE; - goto ret_point; - } - if (p_get_quote_blob->status - || p_get_quote_blob->out_len <= HEADER_SIZE) { - TDX_TRACE; - if (GET_QUOTE_IN_FLIGHT == p_get_quote_blob->status) { - ret = TDX_ATTEST_ERROR_BUSY; - } else if (GET_QUOTE_SERVICE_UNAVAILABLE == p_get_quote_blob->status) { - ret = TDX_ATTEST_ERROR_NOT_SUPPORTED; - } else { - ret = TDX_ATTEST_ERROR_UNEXPECTED; - } - goto ret_point; - } - - //in_msg_size is the size of serialized response - for (unsigned i = 0; i < HEADER_SIZE; ++i) { - in_msg_size = in_msg_size * 256 + ((p_blob_payload[i]) & 0xFF); - } - if (in_msg_size != p_get_quote_blob->out_len - HEADER_SIZE) { - TDX_TRACE; - ret = TDX_ATTEST_ERROR_UNEXPECTED; - goto ret_point; - } - #ifdef DEBUG - fprintf(stdout, "\nGet %u bytes response from tdvmcall", in_msg_size); - #endif - -done: - qgs_msg_ret = qgs_msg_inflate_get_quote_resp( - p_blob_payload + HEADER_SIZE, in_msg_size, - &p_selected_id, &id_size, - &p_quote, "e_size); - if (QGS_MSG_SUCCESS != qgs_msg_ret) { - #ifdef DEBUG - fprintf(stdout, "\nqgs_msg_inflate_get_quote_resp return 0x%x", qgs_msg_ret); - #endif - ret = TDX_ATTEST_ERROR_UNEXPECTED; - goto ret_point; - } - - // We've called qgs_msg_inflate_get_quote_resp, the message type should be GET_QUOTE_RESP - p_header = (qgs_msg_header_t *)(p_blob_payload + HEADER_SIZE); - if (p_header->error_code != 0) { - #ifdef DEBUG - fprintf(stdout, "\nerror code in resp msg is 0x%x", p_header->error_code); - #endif - ret = TDX_ATTEST_ERROR_UNEXPECTED; - goto ret_point; - } - *pp_quote = malloc(quote_size); - if (!*pp_quote) { - ret = TDX_ATTEST_ERROR_OUT_OF_MEMORY; - goto ret_point; - } - memcpy(*pp_quote, p_quote, quote_size); - if (p_quote_size) { - *p_quote_size = quote_size; - } - if (p_att_key_id) { - *p_att_key_id = g_intel_tdqe_uuid; - } - ret = TDX_ATTEST_SUCCESS; - -ret_point: - if (s >= 0) { - close(s); - } - if (-1 != devfd) { - close(devfd); - } - qgs_msg_free(p_req); - free(p_get_quote_blob); - - return ret; -} - -tdx_attest_error_t tdx_att_free_quote( - uint8_t *p_quote) -{ - free(p_quote); - return TDX_ATTEST_SUCCESS; -} - -tdx_attest_error_t tdx_att_get_report( - const tdx_report_data_t *p_tdx_report_data, - tdx_report_t *p_tdx_report) -{ - int devfd; - tdx_attest_error_t ret = TDX_ATTEST_SUCCESS; - - devfd = open(TDX_ATTEST_DEV_PATH, O_RDWR | O_SYNC); - if (-1 == devfd) { - TDX_TRACE; - return TDX_ATTEST_ERROR_DEVICE_FAILURE; - } - - ret = get_tdx_report(devfd, p_tdx_report_data, p_tdx_report); - - close(devfd); - return ret; -} - -tdx_attest_error_t tdx_att_get_supported_att_key_ids( - tdx_uuid_t *p_att_key_id_list, - uint32_t *p_list_size) -{ - if (!p_list_size) { - return TDX_ATTEST_ERROR_INVALID_PARAMETER; - } - if (p_att_key_id_list && !*p_list_size) { - return TDX_ATTEST_ERROR_INVALID_PARAMETER; - } - if (!p_att_key_id_list && *p_list_size) { - return TDX_ATTEST_ERROR_INVALID_PARAMETER; - } - if (p_att_key_id_list) { - p_att_key_id_list[0] = g_intel_tdqe_uuid; - } - *p_list_size = 1; - return TDX_ATTEST_SUCCESS; -} - -tdx_attest_error_t tdx_att_extend( - const tdx_rtmr_event_t *p_rtmr_event) -{ -#ifdef TDX_CMD_EXTEND_RTMR - int devfd = -1; - struct tdx_extend_rtmr_req req; - if (!p_rtmr_event || p_rtmr_event->version != 1) { - return TDX_ATTEST_ERROR_INVALID_PARAMETER; - } - if (p_rtmr_event->event_data_size) { - return TDX_ATTEST_ERROR_NOT_SUPPORTED; - } - if (p_rtmr_event->rtmr_index > 3) { - return TDX_ATTEST_ERROR_INVALID_PARAMETER; - } - - devfd = open(TDX_ATTEST_DEV_PATH, O_RDWR | O_SYNC); - if (-1 == devfd) { - TDX_TRACE; - return TDX_ATTEST_ERROR_DEVICE_FAILURE; - } - - static_assert(TDX_EXTEND_RTMR_DATA_LEN == sizeof(p_rtmr_event->extend_data), - "rtmr extend size mismatch!"); - req.index = (uint8_t)p_rtmr_event->rtmr_index; - memcpy(req.data, p_rtmr_event->extend_data, TDX_EXTEND_RTMR_DATA_LEN); - if (-1 == ioctl(devfd, TDX_CMD_EXTEND_RTMR, &req)) { - TDX_TRACE; - close(devfd); - if (EINVAL == errno) { - return TDX_ATTEST_ERROR_INVALID_RTMR_INDEX; - } - return TDX_ATTEST_ERROR_EXTEND_FAILURE; - } - close(devfd); - return TDX_ATTEST_SUCCESS; -#else - (void)p_rtmr_event; - return TDX_ATTEST_ERROR_NOT_SUPPORTED; -#endif -} - -#else - -#include "tdx_attest.h" -#include "servtd_com.h" -#include "servtd_external.h" -#include "qgs_msg_lib.h" - -#include -#include -#include -#include - -__attribute__ ((visibility("default"))) tdx_attest_error_t tdx_att_get_quote_by_report ( - const void *p_tdx_report, - uint32_t tdx_report_size, - void *p_quote, - uint32_t *p_quote_size) -{ - uint32_t quote_size = 0; - uint32_t in_msg_size = 0; - tdx_attest_error_t ret = TDX_ATTEST_ERROR_UNEXPECTED; - struct servtd_tdx_quote_hdr *p_get_quote_blob = NULL; - uint8_t *p_blob_payload = NULL; - uint32_t msg_size = 0; - int servtd_get_quote_ret = 0; - const uint8_t *tmp_p_quote = NULL; - const uint8_t *p_selected_id = NULL; - uint32_t id_size = 0; - qgs_msg_error_t qgs_msg_ret = QGS_MSG_SUCCESS; - qgs_msg_header_t *p_header = NULL; - uint8_t *p_req = NULL; - - if (NULL == p_tdx_report || TDX_REPORT_SIZE != tdx_report_size) { - ret = TDX_ATTEST_ERROR_INVALID_PARAMETER; - goto ret_point; - } - - if (NULL == p_quote || NULL == p_quote_size || 0 == *p_quote_size) { - ret = TDX_ATTEST_ERROR_INVALID_PARAMETER; - goto ret_point; - } - - p_get_quote_blob = (struct servtd_tdx_quote_hdr *)malloc(SERVTD_REQ_BUF_SIZE); - if (!p_get_quote_blob) { - ret = TDX_ATTEST_ERROR_OUT_OF_MEMORY; - goto ret_point; - } - - qgs_msg_ret = qgs_msg_gen_get_quote_req(p_tdx_report, tdx_report_size, - NULL, 0, &p_req, &msg_size); - if (QGS_MSG_SUCCESS != qgs_msg_ret) { - ret = TDX_ATTEST_ERROR_UNEXPECTED; - goto ret_point; - } - - if (msg_size > SERVTD_REQ_BUF_SIZE - sizeof(struct servtd_tdx_quote_hdr) - SERVTD_HEADER_SIZE) { - ret = TDX_ATTEST_ERROR_NOT_SUPPORTED; - goto ret_point; - } - - p_blob_payload = (uint8_t *)&p_get_quote_blob->data; - p_blob_payload[0] = (uint8_t)((msg_size >> 24) & 0xFF); - p_blob_payload[1] = (uint8_t)((msg_size >> 16) & 0xFF); - p_blob_payload[2] = (uint8_t)((msg_size >> 8) & 0xFF); - p_blob_payload[3] = (uint8_t)(msg_size & 0xFF); - - // Serialization - memcpy(p_blob_payload + SERVTD_HEADER_SIZE, p_req, msg_size); - - p_get_quote_blob->version = 1; - p_get_quote_blob->status = 0; - p_get_quote_blob->in_len = SERVTD_HEADER_SIZE + msg_size; - p_get_quote_blob->out_len = 0; - - servtd_get_quote_ret = servtd_get_quote(p_get_quote_blob, SERVTD_REQ_BUF_SIZE); - if (servtd_get_quote_ret) { - ret = TDX_ATTEST_ERROR_QUOTE_FAILURE; - goto ret_point; - } - - if (p_get_quote_blob->status - || p_get_quote_blob->out_len <= SERVTD_HEADER_SIZE) { - if (GET_QUOTE_IN_FLIGHT == p_get_quote_blob->status) { - ret = TDX_ATTEST_ERROR_BUSY; - } else if (GET_QUOTE_SERVICE_UNAVAILABLE == p_get_quote_blob->status) { - ret = TDX_ATTEST_ERROR_NOT_SUPPORTED; - } else { - ret = TDX_ATTEST_ERROR_UNEXPECTED; - } - goto ret_point; - } - - //in_msg_size is the size of serialized response, remove 4bytes header - for (unsigned i = 0; i < SERVTD_HEADER_SIZE; ++i) { - in_msg_size = in_msg_size * 256 + ((p_blob_payload[i]) & 0xFF); - } - if (in_msg_size != p_get_quote_blob->out_len - SERVTD_HEADER_SIZE) { - ret = TDX_ATTEST_ERROR_UNEXPECTED; - goto ret_point; - } - - qgs_msg_ret = qgs_msg_inflate_get_quote_resp( - p_blob_payload + SERVTD_HEADER_SIZE, in_msg_size, - &p_selected_id, &id_size, - (const uint8_t **)&tmp_p_quote, "e_size); - if (QGS_MSG_SUCCESS != qgs_msg_ret) { - ret = TDX_ATTEST_ERROR_UNEXPECTED; - goto ret_point; - } - - // We've called qgs_msg_inflate_get_quote_resp, the message type should be GET_QUOTE_RESP - p_header = (qgs_msg_header_t *)(p_blob_payload + SERVTD_HEADER_SIZE); - if (p_header->error_code != 0) { - ret = TDX_ATTEST_ERROR_UNEXPECTED; - goto ret_point; - } - - if (quote_size > *p_quote_size) { - ret = TDX_ATTEST_ERROR_OUT_OF_MEMORY; - goto ret_point; - } - memcpy(p_quote, tmp_p_quote, quote_size); - - *p_quote_size = quote_size; - ret = TDX_ATTEST_SUCCESS; - -ret_point: - qgs_msg_free(p_req); - SAFE_FREE(p_get_quote_blob); - return ret; -} - -#endif diff --git a/tdx-attest-sys/csrc/tdx_attest.h b/tdx-attest-sys/csrc/tdx_attest.h deleted file mode 100644 index 258617bf..00000000 --- a/tdx-attest-sys/csrc/tdx_attest.h +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright (C) 2011-2021 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - - -/** - * File: tdx_attest.h - * - * Description: API definitions for TDX Attestation library - * - */ -#ifndef _TDX_ATTEST_H_ -#define _TDX_ATTEST_H_ -#include - -typedef enum _tdx_attest_error_t { - TDX_ATTEST_SUCCESS = 0x0000, ///< Success - TDX_ATTEST_ERROR_MIN = 0x0001, ///< Indicate min error to allow better translation. - TDX_ATTEST_ERROR_UNEXPECTED = 0x0001, ///< Unexpected error - TDX_ATTEST_ERROR_INVALID_PARAMETER = 0x0002, ///< The parameter is incorrect - TDX_ATTEST_ERROR_OUT_OF_MEMORY = 0x0003, ///< Not enough memory is available to complete this operation - TDX_ATTEST_ERROR_VSOCK_FAILURE = 0x0004, ///< vsock related failure - TDX_ATTEST_ERROR_REPORT_FAILURE = 0x0005, ///< Failed to get the TD Report - TDX_ATTEST_ERROR_EXTEND_FAILURE = 0x0006, ///< Failed to extend rtmr - TDX_ATTEST_ERROR_NOT_SUPPORTED = 0x0007, ///< Request feature is not supported - TDX_ATTEST_ERROR_QUOTE_FAILURE = 0x0008, ///< Failed to get the TD Quote - TDX_ATTEST_ERROR_BUSY = 0x0009, ///< The device driver return busy - TDX_ATTEST_ERROR_DEVICE_FAILURE = 0x000a, ///< Failed to acess tdx attest device - TDX_ATTEST_ERROR_INVALID_RTMR_INDEX = 0x000b, ///< Only supported RTMR index is 2 and 3 - TDX_ATTEST_ERROR_UNSUPPORTED_ATT_KEY_ID = 0x000c, ///< The platform Quoting infrastructure does not support any of the keys described in att_key_id_list - TDX_ATTEST_ERROR_MAX -} tdx_attest_error_t; - -#define TDX_UUID_SIZE 16 - -#pragma pack(push, 1) - -#define TDX_UUID_SIZE 16 -typedef struct _tdx_uuid_t -{ - uint8_t d[TDX_UUID_SIZE]; -} tdx_uuid_t; - -#define TDX_SGX_ECDSA_ATTESTATION_ID \ -{ \ - 0xe8, 0x6c, 0x04, 0x6e, 0x8c, 0xc4, 0x4d, 0x95, \ - 0x81, 0x73, 0xfc, 0x43, 0xc1, 0xfa, 0x4f, 0x3f \ -} - -#define TDX_REPORT_DATA_SIZE 64 -typedef struct _tdx_report_data_t -{ - uint8_t d[TDX_REPORT_DATA_SIZE]; -} tdx_report_data_t; - -#define TDX_REPORT_SIZE 1024 -typedef struct _tdx_report_t -{ - uint8_t d[TDX_REPORT_SIZE]; -} tdx_report_t; - -typedef struct _tdx_rtmr_event_t { - uint32_t version; - uint64_t rtmr_index; - uint8_t extend_data[48]; - uint32_t event_type; - uint32_t event_data_size; - uint8_t event_data[]; -} tdx_rtmr_event_t; - -#pragma pack(pop) - -#if defined(__cplusplus) -extern "C" { -#endif - -#ifndef SERVTD_ATTEST -/** - * @brief Request a Quote of the calling TD. - * - * The caller provides data intended to be cryptographically bound to the - * resulting Quote. (This data should not require confidentiality protection.) - * The caller also provides information about the type of Quote signing that - * should be used. - * - * In general, a given platform can create Quotes using - * different cryptographic algorithms or using different vendors’ code/enclaves. - * The att_key_id_list parameter is related to this. It is a list of key IDs - * supported by the eventual verifier of the Quote. How the caller of this - * function obtains this list is outside the scope of the R3AAL. - * - * A default key ID is supported and will be used when att_key_id_list == NULL. - * In this case, the default key ID is returned via the p_att_key_id parameter. - * - * When the function returns successfully, p_quote will point to a buffer - * containing the Quote. This buffer is allocated by the function. Use - * tdx_att_free_quote to free this buffer. - * - * @param p_tdx_report_data [in] Pointer to data that the caller/TD wants to - * cryptographically bind to the Quote, - * typically a hash. Cannot be NULL. - * @param att_key_id_list [in] List (array) of the attestation key IDs supported - * by the Quote verifier. The function compares the - * key IDs in att_key_id_list to the key IDs that - * the platform supports and uses the first match. - * May be NULL. If NULL, the API will use the - * platform’s default key ID. The uuid_t - * corresponding to the key ID that’s used is - * pointed to by p_att_key_id when the function - * returns unless p_att_key_id == NULL. - * @param list_size [in] Size of att_key_id_list in entries. - * @param p_att_key_id [out] The selected attestation key ID when the function - * returns. May be NULL indicating the platform’s - * default key ID - * @param pp_quote [out] Pointer to a pointer that the function will set equal - * to the address of the buffer containing the Quote. The - * function also allocates this buffer. Use - * tdx_att_free_quote to free this buffe - * @param p_quote_size [out] This function will place the size of the Quote, in - * bytes, in the uint32_t pointed to by the - * p_quote_size parameter. May be NULL. - * @param flags [in] Reserved, must be zero. - * @return TDX_ATTEST_SUCCESS: Successfully generated the Quote. - * @return TDX_ATTEST_ERROR_UNEXPECTED: An unexpected internal error occurred. - * @return TDX_ATTEST_ERROR_INVALID_PARAMETER: The parameter is incorrect - * @return TDX_ATTEST_ERROR_DEVICE_FAILURE: Failed to acess tdx attest device. - * @return TDX_ATTEST_ERROR_REPORT_FAILURE: Failed to get TD report. - * @return TDX_ATTEST_ERROR_VSOCK_FAILURE: Failed read/write in vsock mode - * @return TDX_ATTEST_ERROR_QUOTE_FAILURE: Failed to get quote from QGS - * @return TDX_ATTEST_UNSUPPORTED_ATT_KEY_ID: The platform Quoting - * infrastructure does not support any of the keys described in - * att_key_id_list. - * @return TDX_ATTEST_OUT_OF_MEMORY: Heap memory allocation error in library or - * enclave. - */ -tdx_attest_error_t tdx_att_get_quote( - const tdx_report_data_t *p_tdx_report_data, - const tdx_uuid_t att_key_id_list[], - uint32_t list_size, - tdx_uuid_t *p_att_key_id, - uint8_t **pp_quote, - uint32_t *p_quote_size, - uint32_t flags); - - -/** - * @brief Free the Quote buffer allocated by tdx_att_get_quote. - * - * @param p_quote [in] The value of *p_quote returned by tdx_att_get_quote. - * @return TDX_ATTEST_SUCCESS: Successfully freed the p_quote. - */ -tdx_attest_error_t tdx_att_free_quote( - uint8_t *p_quote); - -/** - * @brief Request a TDX Report of the calling TD. - * - * The caller provides data intended to be cryptographically bound to the - * resulting Report. - * - * @param p_tdx_report_data [in] Pointer to data that the caller/TD wants to - * cryptographically bind to the Quote, typically - * a hash. Cannot be NULL. - * @param p_tdx_report [out] Pointer to the buffer that will contain the - * generated TDX Report. Must not be NULL. - * @return TDX_ATTEST_SUCCESS: Successfully generated the Report. - * @return TDX_ATTEST_ERROR_INVALID_PARAMETER: p_tdx_report == NULL - * @return TDX_ATTEST_ERROR_DEVICE_FAILURE: Failed to acess tdx attest device. - * @return TDX_ATTEST_ERROR_REPORT_FAILURE: Failed to get TD report. - */ -tdx_attest_error_t tdx_att_get_report( - const tdx_report_data_t *p_tdx_report_data, - tdx_report_t* p_tdx_report); - - -/** - * @brief Extend one of the TDX runtime measurement registers (RTMRs). - * - * RTMR[rtmr_index] = SHA384(RTMR[rtmr_index] || extend_data) - * rtmr_index and extend_data are fields in the structure that is an input of - * this API. - * This API does not return either the new or old value of the specified RTMR. - * The tdx_att_get_report API may be used for this. - * The input to this API includes a description of the “extend data”. This is - * intended to facilitate reconstruction of the RTMR value. This, in turn, - * suggests maintenance of an event log by the callee. Currently, event_data is - * not supported. - * - * @param p_rtmr_event [in] Pointer to structure that contains the index of the - * RTMR to extend, the data with which to extend it and - * a description of the data. - * @return TDX_ATTEST_SUCCESS: Successfully extended the RTMR. - * @return TDX_ATTEST_ERROR_INVALID_PARAMETER: p_rtmr_event == NULL - * @return TDX_ATTEST_ERROR_UNEXPECTED: An unexpected internal error occurred. - * @return TDX_ATTEST_ERROR_DEVICE_FAILURE: Failed to acess tdx attest device. - * @return TDX_ATTEST_ERROR_EXTEND_FAILURE: Failed to extend data. - * @return TDX_ATTEST_ERROR_NOT_SUPPORTED: p_rtmr_event->event_data_size != 0 - */ -tdx_attest_error_t tdx_att_extend( - const tdx_rtmr_event_t *p_rtmr_event); - - -/** - * @brief Retrieve the list of attestation key IDs supported by the platform. - * - * Specify p_att_key_id_list = NULL to learn the number of entries in the list. - * - * @param p_att_key_id_list [out] List of the attestation key IDs that the - * platform supports. May be NULL. If NULL, the - * API will return the number of entries in the - * list in the uint32_t pointed to by p_list_size - * @param p_list_size [in/out] As input, pointer to a uint32_t specifying the - * size of p_att_key_id_list in entries. As output, - * this function will place the required size, in - * entries, in the uint32_t pointed to by the - * p_list_size parameter. If this value changes, the - * new value will be the required size - * @return TDX_ATTEST_SUCCESS: att_key_id_list populated and p_list_size points - * to a uint32_t that indicates the number of - * entries. - * @return TDX_ATTEST_ERROR_INVALID_PARAMETER: The parameter is incorrect - */ -tdx_attest_error_t tdx_att_get_supported_att_key_ids( - tdx_uuid_t *p_att_key_id_list, - uint32_t *p_list_size); - -#else -__attribute__ ((visibility("default"))) tdx_attest_error_t tdx_att_get_quote_by_report ( - const void *p_tdx_report, - uint32_t tdx_report_size, - void *p_quote, - uint32_t *p_quote_size); -#endif - -#if defined(__cplusplus) -} -#endif - - -#endif - diff --git a/tdx-attest-sys/src/lib.rs b/tdx-attest-sys/src/lib.rs deleted file mode 100644 index abe54931..00000000 --- a/tdx-attest-sys/src/lib.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![allow(non_camel_case_types)] -#![allow(non_snake_case)] -#![allow(non_upper_case_globals)] -#![allow(clippy::missing_safety_doc)] - -// SPDX-FileCopyrightText: © 2024 Phala Network -// -// SPDX-License-Identifier: Apache-2.0 - -include!(concat!(env!("OUT_DIR"), "/bindings.rs")); diff --git a/tdx-attest/Cargo.lock b/tdx-attest/Cargo.lock deleted file mode 100644 index 84c027d7..00000000 --- a/tdx-attest/Cargo.lock +++ /dev/null @@ -1,372 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "bindgen" -version = "0.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" -dependencies = [ - "bitflags", - "cexpr", - "clang-sys", - "itertools", - "log", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn", -] - -[[package]] -name = "bitflags" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" - -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "clang-sys" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" -dependencies = [ - "glob", - "libc", - "libloading", -] - -[[package]] -name = "either" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" - -[[package]] -name = "indexmap" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" -dependencies = [ - "equivalent", - "hashbrown", -] - -[[package]] -name = "itertools" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" -dependencies = [ - "either", -] - -[[package]] -name = "libc" -version = "0.2.158" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" - -[[package]] -name = "libloading" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" -dependencies = [ - "cfg-if", - "windows-targets", -] - -[[package]] -name = "log" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "num_enum" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" -dependencies = [ - "num_enum_derive", -] - -[[package]] -name = "num_enum_derive" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" -dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "prettyplease" -version = "0.2.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" -dependencies = [ - "proc-macro2", - "syn", -] - -[[package]] -name = "proc-macro-crate" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" -dependencies = [ - "toml_edit", -] - -[[package]] -name = "proc-macro2" -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "regex" -version = "1.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "syn" -version = "2.0.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578e081a14e0cefc3279b0472138c513f37b41a08d5a3cca9b6e4e8ceb6cd525" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tdx-attest" -version = "0.1.0" -dependencies = [ - "num_enum", - "tdx-attest-sys", -] - -[[package]] -name = "tdx-attest-sys" -version = "0.1.0" -dependencies = [ - "bindgen", -] - -[[package]] -name = "toml_datetime" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" - -[[package]] -name = "toml_edit" -version = "0.22.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" -dependencies = [ - "indexmap", - "toml_datetime", - "winnow", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "winnow" -version = "0.6.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" -dependencies = [ - "memchr", -] diff --git a/tdx-attest/Cargo.toml b/tdx-attest/Cargo.toml index 1a193024..661b2f5f 100644 --- a/tdx-attest/Cargo.toml +++ b/tdx-attest/Cargo.toml @@ -13,7 +13,6 @@ license.workspace = true [dependencies] anyhow.workspace = true hex.workspace = true -num_enum.workspace = true scale.workspace = true serde.workspace = true serde-human-bytes.workspace = true @@ -23,9 +22,13 @@ fs-err.workspace = true serde_json = { workspace = true, features = ["alloc"] } sha2.workspace = true -[target.'cfg(all(target_os = "linux", target_arch = "x86_64", target_env = "gnu"))'.dependencies] -tdx-attest-sys.workspace = true +# Linux x86_64 - pure Rust implementation using libc for syscalls +[target.'cfg(all(target_os = "linux", target_arch = "x86_64"))'.dependencies] +libc.workspace = true +vsock = "0.5" [dev-dependencies] insta.workspace = true serde_json.workspace = true +dcap-qvl.workspace = true +tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } diff --git a/tdx-attest/examples/test_tdx.rs b/tdx-attest/examples/test_tdx.rs new file mode 100644 index 00000000..173fc15d --- /dev/null +++ b/tdx-attest/examples/test_tdx.rs @@ -0,0 +1,98 @@ +// SPDX-FileCopyrightText: © 2025 Phala Network +// +// SPDX-License-Identifier: Apache-2.0 + +//! Test TDX attestation functions on real TDX hardware. + +use dcap_qvl::collateral::get_collateral_and_verify; +use dcap_qvl::quote::Quote; + +#[tokio::main] +async fn main() { + println!("=== TDX Attestation Test ===\n"); + + // Test get_report + println!("1. Testing get_report..."); + let report_data = [0u8; 64]; + match tdx_attest::get_report(&report_data) { + Ok(report) => { + println!(" ✓ get_report succeeded"); + println!(" Report size: {} bytes", report.0.len()); + println!(" Report hash: {:02x?}", &report.0[..32]); + } + Err(e) => { + println!(" ✗ get_report failed: {}", e); + } + } + + // Test get_quote + println!("\n2. Testing get_quote..."); + let report_data = [0x42u8; 64]; + let quote = match tdx_attest::get_quote(&report_data) { + Ok(quote) => { + println!(" ✓ get_quote succeeded"); + println!(" Quote size: {} bytes", quote.len()); + println!(" Quote header: {:02x?}", "e[..32.min(quote.len())]); + Some(quote) + } + Err(e) => { + println!(" ✗ get_quote failed: {}", e); + None + } + }; + + // Parse and verify quote with dcap-qvl + if let Some(ref quote) = quote { + println!("\n3. Parsing quote..."); + match Quote::parse(quote) { + Ok(q) => { + println!(" ✓ Quote parsed"); + println!(" Version: {}", q.header.version); + if let Some(report) = q.report.as_td10() { + println!(" MRTD: {}...", hex::encode(&report.mr_td[..16])); + println!(" RTMR3: {}...", hex::encode(&report.rt_mr3[..16])); + } + } + Err(e) => { + println!(" ✗ Quote parse failed: {:?}", e); + } + } + + println!("\n4. Verifying quote with PCCS..."); + let pccs_url = std::env::var("PCCS_URL").ok(); + println!( + " PCCS URL: {}", + pccs_url.as_deref().unwrap_or("(default)") + ); + match get_collateral_and_verify(quote, pccs_url.as_deref()).await { + Ok(verified) => { + println!(" ✓ Quote verified!"); + println!(" QE status: {:?}", verified.qe_status); + if let Some(report) = verified.report.as_td10() { + if report.report_data[..] == report_data[..] { + println!(" ✓ Report data matches"); + } else { + println!(" ✗ Report data mismatch!"); + } + } + } + Err(e) => { + println!(" ✗ Verification failed: {:?}", e); + } + } + } + + // Test extend_rtmr (RTMR 3 is user-extensible) + println!("\n5. Testing extend_rtmr (RTMR 3)..."); + let digest = [0xABu8; 48]; + match tdx_attest::extend_rtmr(3, 0, digest) { + Ok(()) => { + println!(" ✓ extend_rtmr succeeded"); + } + Err(e) => { + println!(" ✗ extend_rtmr failed: {:?}", e); + } + } + + println!("\n=== Test Complete ==="); +} diff --git a/tdx-attest/src/dummy.rs b/tdx-attest/src/dummy.rs index 1f116812..c6002f6f 100644 --- a/tdx-attest/src/dummy.rs +++ b/tdx-attest/src/dummy.rs @@ -2,17 +2,17 @@ // // SPDX-License-Identifier: Apache-2.0 -use num_enum::FromPrimitive; -use thiserror::Error; +//! Dummy implementation for non-Linux/non-x86_64 platforms. +//! +//! All functions return `NotSupported` error. -use crate::{TdxReport, TdxReportData, TdxUuid}; +use thiserror::Error; -type Result = std::result::Result; +use crate::{Result, TdxReport, TdxReportData}; -#[repr(u32)] -#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, Error)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Error)] pub enum TdxAttestError { - #[error("unexpected")] + #[error("unexpected error")] Unexpected, #[error("invalid parameter")] InvalidParameter, @@ -28,28 +28,24 @@ pub enum TdxAttestError { NotSupported, #[error("quote failure")] QuoteFailure, - #[error("busy")] + #[error("device busy")] Busy, #[error("device failure")] DeviceFailure, - #[error("invalid rtmr index")] + #[error("invalid RTMR index")] InvalidRtmrIndex, - #[error("unsupported att key id")] + #[error("unsupported attestation key ID")] UnsupportedAttKeyId, - #[num_enum(catch_all)] - #[error("unknown error ({0})")] - UnknownError(u32), } -pub fn extend_rtmr(_index: u32, _event_type: u32, _digest: [u8; 48]) -> Result<()> { +pub fn get_quote(_report_data: &TdxReportData) -> Result> { Err(TdxAttestError::NotSupported) } + pub fn get_report(_report_data: &TdxReportData) -> Result { Err(TdxAttestError::NotSupported) } -pub fn get_quote(_report_data: &TdxReportData) -> Result> { - Err(TdxAttestError::NotSupported) -} -pub fn get_supported_att_key_ids() -> Result> { + +pub fn extend_rtmr(_index: u32, _event_type: u32, _digest: [u8; 48]) -> Result<()> { Err(TdxAttestError::NotSupported) } diff --git a/tdx-attest/src/lib.rs b/tdx-attest/src/lib.rs index 453843ce..4c73fb02 100644 --- a/tdx-attest/src/lib.rs +++ b/tdx-attest/src/lib.rs @@ -2,24 +2,22 @@ // // SPDX-License-Identifier: Apache-2.0 -#[cfg(all(target_os = "linux", target_arch = "x86_64", target_env = "gnu"))] +// Linux x86_64 with glibc or musl +#[cfg(all(target_os = "linux", target_arch = "x86_64"))] pub use linux::*; -#[cfg(all(target_os = "linux", target_arch = "x86_64", target_env = "gnu"))] +#[cfg(all(target_os = "linux", target_arch = "x86_64"))] mod linux; -#[cfg(not(all(target_os = "linux", target_arch = "x86_64", target_env = "gnu")))] +// Fallback for non-Linux/non-x86_64 platforms (dummy implementation) +#[cfg(not(all(target_os = "linux", target_arch = "x86_64")))] pub use dummy::*; - -#[cfg(not(all(target_os = "linux", target_arch = "x86_64", target_env = "gnu")))] +#[cfg(not(all(target_os = "linux", target_arch = "x86_64")))] mod dummy; pub use cc_eventlog as eventlog; pub type Result = std::result::Result; -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct TdxUuid(pub [u8; 16]); - pub type TdxReportData = [u8; 64]; #[derive(Debug, Clone, Copy, PartialEq, Eq)] diff --git a/tdx-attest/src/linux.rs b/tdx-attest/src/linux.rs index f81e45eb..89e2e06b 100644 --- a/tdx-attest/src/linux.rs +++ b/tdx-attest/src/linux.rs @@ -2,143 +2,637 @@ // // SPDX-License-Identifier: Apache-2.0 -use tdx_attest_sys as sys; +//! Pure Rust implementation of TDX attestation operations. +//! +//! This module provides TDX quote generation, report retrieval, and RTMR extension +//! without depending on the C tdx-attest library. It supports three methods for +//! quote generation (in priority order): +//! +//! 1. ConfigFS - via `/sys/kernel/config/tsm/report/` (Linux 6.7+) +//! 2. VSock - via QGS (Quote Generation Service) over vsock +//! 3. TDVMCALL - via `/dev/tdx_guest` ioctl (legacy) -use std::ptr; -use std::slice; +use std::fs::{self, File, OpenOptions}; +use std::io::{Read, Write}; +use std::os::unix::io::AsRawFd; +use std::path::Path; use std::sync::Mutex; +use std::thread; +use std::time::Duration; -use sys::*; +use thiserror::Error; -/// Global lock for TDX attestation operations. The TDX driver does not support concurrent access. -static TDX_LOCK: Mutex<()> = Mutex::new(()); +use crate::{Result, TdxReport, TdxReportData}; -use num_enum::FromPrimitive; -use thiserror::Error; +// ============================================================================ +// Constants +// ============================================================================ + +const TDX_GUEST_DEVICE: &str = "/dev/tdx_guest"; +const CONFIGFS_BASE: &str = "/sys/kernel/config/tsm/report"; +const CONFIGFS_DEFAULT: &str = "/sys/kernel/config/tsm/report/com.intel.dcap"; +const CONFIGFS_PATH_ENV: &str = "DCAP_TDX_QUOTE_CONFIGFS_PATH"; +const RTMR_SYSFS_BASE: &str = "/sys/devices/virtual/misc/tdx_guest/measurements"; +const TDX_ATTEST_CONFIG_PATH: &str = "/etc/tdx-attest.conf"; + +const TDX_REPORT_DATA_SIZE: usize = 64; +const TDX_REPORT_SIZE: usize = 1024; +const RTMR_EXTEND_DATA_SIZE: usize = 48; +const QUOTE_BUF_SIZE: usize = 8 * 1024; +const QUOTE_MIN_SIZE: usize = 1020; + +// QGS message constants +const QGS_MSG_LEN_PREFIX_SIZE: usize = 4; // 4-byte length prefix +const QGS_REQ_BUF_SIZE: usize = 16 * 1024; // 16KB buffer for request/response + +// QGS message types +const QGS_MSG_GET_QUOTE_REQ: u32 = 0; +const QGS_MSG_GET_QUOTE_RESP: u32 = 1; + +// QGS message version +const QGS_MSG_VERSION_MAJOR: u16 = 1; +const QGS_MSG_VERSION_MINOR: u16 = 0; + +// ============================================================================ +// ioctl definitions for /dev/tdx_guest +// ============================================================================ -use crate::TdxReport; -use crate::TdxReportData; -use crate::{Result, TdxUuid}; +// ioctl request type varies between glibc and musl +#[cfg(target_env = "musl")] +type IoctlRequest = libc::c_int; +#[cfg(not(target_env = "musl"))] +type IoctlRequest = libc::c_ulong; + +// ioctl command encoding +const fn ioc(dir: u32, ty: u8, nr: u8, size: usize) -> IoctlRequest { + (((dir as IoctlRequest) << 30) + | ((ty as IoctlRequest) << 8) + | (nr as IoctlRequest) + | ((size as IoctlRequest) << 16)) as IoctlRequest +} + +const IOC_WRITE: u32 = 1; +const IOC_READ: u32 = 2; + +fn iowr(ty: u8, nr: u8) -> IoctlRequest { + ioc(IOC_READ | IOC_WRITE, ty, nr, std::mem::size_of::()) +} + +fn ior(ty: u8, nr: u8) -> IoctlRequest { + ioc(IOC_READ, ty, nr, std::mem::size_of::()) +} + +// TDX ioctl commands +fn tdx_cmd_get_report0() -> IoctlRequest { + iowr::(b'T', 1) +} -#[repr(u32)] -#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, Error)] +// Note: Kernel driver uses _IOR (not _IOW) for extend RTMR +fn tdx_cmd_extend_rtmr() -> IoctlRequest { + ior::(b'T', 3) +} + +// ============================================================================ +// Kernel interface structures +// ============================================================================ + +#[repr(C)] +struct TdxReportReq { + reportdata: [u8; TDX_REPORT_DATA_SIZE], + tdreport: [u8; TDX_REPORT_SIZE], +} + +#[repr(C)] +struct TdxExtendRtmrReq { + data: [u8; RTMR_EXTEND_DATA_SIZE], + index: u8, +} + +// ============================================================================ +// Error types +// ============================================================================ + +#[derive(Debug, Error)] pub enum TdxAttestError { - #[error("TDX_ATTEST_ERROR_UNEXPECTED")] - Unexpected = _tdx_attest_error_t::TDX_ATTEST_ERROR_UNEXPECTED, - #[error("TDX_ATTEST_ERROR_INVALID_PARAMETER")] - InvalidParameter = _tdx_attest_error_t::TDX_ATTEST_ERROR_INVALID_PARAMETER, - #[error("TDX_ATTEST_ERROR_OUT_OF_MEMORY")] - OutOfMemory = _tdx_attest_error_t::TDX_ATTEST_ERROR_OUT_OF_MEMORY, - #[error("TDX_ATTEST_ERROR_VSOCK_FAILURE")] - VsockFailure = _tdx_attest_error_t::TDX_ATTEST_ERROR_VSOCK_FAILURE, - #[error("TDX_ATTEST_ERROR_REPORT_FAILURE")] - ReportFailure = _tdx_attest_error_t::TDX_ATTEST_ERROR_REPORT_FAILURE, - #[error("TDX_ATTEST_ERROR_EXTEND_FAILURE")] - ExtendFailure = _tdx_attest_error_t::TDX_ATTEST_ERROR_EXTEND_FAILURE, - #[error("TDX_ATTEST_ERROR_NOT_SUPPORTED")] - NotSupported = _tdx_attest_error_t::TDX_ATTEST_ERROR_NOT_SUPPORTED, - #[error("TDX_ATTEST_ERROR_QUOTE_FAILURE")] - QuoteFailure = _tdx_attest_error_t::TDX_ATTEST_ERROR_QUOTE_FAILURE, - #[error("TDX_ATTEST_ERROR_BUSY")] - Busy = _tdx_attest_error_t::TDX_ATTEST_ERROR_BUSY, - #[error("TDX_ATTEST_ERROR_DEVICE_FAILURE")] - DeviceFailure = _tdx_attest_error_t::TDX_ATTEST_ERROR_DEVICE_FAILURE, - #[error("TDX_ATTEST_ERROR_INVALID_RTMR_INDEX")] - InvalidRtmrIndex = _tdx_attest_error_t::TDX_ATTEST_ERROR_INVALID_RTMR_INDEX, - #[error("TDX_ATTEST_ERROR_UNSUPPORTED_ATT_KEY_ID")] - UnsupportedAttKeyId = _tdx_attest_error_t::TDX_ATTEST_ERROR_UNSUPPORTED_ATT_KEY_ID, - #[num_enum(catch_all)] - #[error("unknown tdx attest error ({0})")] - UnknownError(u32), + #[error("unexpected error: {0}")] + Unexpected(String), + #[error("invalid parameter")] + InvalidParameter, + #[error("out of memory")] + OutOfMemory, + #[error("vsock failure: {0}")] + VsockFailure(#[from] std::io::Error), + #[error("report failure: {0}")] + ReportFailure(String), + #[error("extend failure: {0}")] + ExtendFailure(String), + #[error("not supported: {0}")] + NotSupported(String), + #[error("quote failure: {0}")] + QuoteFailure(String), + #[error("device busy")] + Busy, + #[error("device failure: {0}")] + DeviceFailure(String), + #[error("invalid RTMR index: {0}")] + InvalidRtmrIndex(u32), + #[error("unsupported attestation key ID")] + UnsupportedAttKeyId, } +// ============================================================================ +// Global state +// ============================================================================ + +/// Global lock for TDX operations - the driver doesn't support concurrent access +static TDX_LOCK: Mutex<()> = Mutex::new(()); + +/// Track if we've already tried to create the configfs directory +static CONFIGFS_MKDIR_TRIED: Mutex = Mutex::new(false); + +// ============================================================================ +// Public API +// ============================================================================ + +/// Get a TDX quote for the given report data. +/// +/// Tries multiple methods in order: +/// 1. ConfigFS (Linux 6.7+) +/// 2. VSock to QGS service pub fn get_quote(report_data: &TdxReportData) -> Result> { - // Lock to prevent concurrent access - TDX driver doesn't support it let _guard = TDX_LOCK.lock().map_err(|_| TdxAttestError::Busy)?; - let mut att_key_id = TdxUuid([0; TDX_UUID_SIZE as usize]); - let mut quote_ptr = ptr::null_mut(); - let mut quote_size = 0; - - let error = unsafe { - let key_id_list_ptr = ptr::null(); - tdx_att_get_quote( - report_data as *const TdxReportData as *const tdx_report_data_t, - key_id_list_ptr, - 0, - &mut att_key_id as *mut TdxUuid as *mut tdx_uuid_t, - &mut quote_ptr, - &mut quote_size, - 0, - ) - }; + if is_configfs_available() { + return get_quote_via_configfs(report_data); + } - if error != _tdx_attest_error_t::TDX_ATTEST_SUCCESS { - return Err(error.into()); + if is_vsock_available() { + return get_quote_via_vsock(report_data); } - let quote = unsafe { slice::from_raw_parts(quote_ptr, quote_size as usize).to_vec() }; + Err(TdxAttestError::NotSupported( + "no quote method available (configfs not mounted, no vsock port configured)".to_string(), + )) +} - unsafe { - tdx_att_free_quote(quote_ptr); - } +fn is_configfs_available() -> bool { + Path::new(CONFIGFS_DEFAULT).is_dir() || Path::new(CONFIGFS_BASE).is_dir() +} - Ok(quote) +fn is_vsock_available() -> bool { + read_vsock_port().map(|p| p > 0).unwrap_or(false) } +/// Get a TDX report for the given report data. pub fn get_report(report_data: &TdxReportData) -> Result { - let mut report = TdxReport([0; TDX_REPORT_SIZE as usize]); + let file = OpenOptions::new() + .read(true) + .write(true) + .open(TDX_GUEST_DEVICE) + .map_err(|e| TdxAttestError::DeviceFailure(format!("open {TDX_GUEST_DEVICE}: {e}")))?; - let error = unsafe { - tdx_att_get_report( - report_data as *const TdxReportData as *const tdx_report_data_t, - &mut report as *mut TdxReport as *mut tdx_report_t, - ) + let mut req = TdxReportReq { + reportdata: *report_data, + tdreport: [0u8; TDX_REPORT_SIZE], }; - if error != _tdx_attest_error_t::TDX_ATTEST_SUCCESS { - return Err(error.into()); + let ret = unsafe { libc::ioctl(file.as_raw_fd(), tdx_cmd_get_report0(), &mut req) }; + if ret != 0 { + let err = std::io::Error::last_os_error(); + return Err(TdxAttestError::ReportFailure(format!("ioctl: {err}"))); } - Ok(report) + Ok(TdxReport(req.tdreport)) } -pub fn extend_rtmr(index: u32, event_type: u32, digest: [u8; 48]) -> Result<()> { - let event = tdx_rtmr_event_t { - version: 1, - rtmr_index: index as u64, - extend_data: digest, - event_type, - event_data_size: 0, - event_data: Default::default(), +/// Extend a TDX RTMR (Runtime Measurement Register). +/// +/// RTMR[index] = SHA384(RTMR[index] || digest) +/// +/// Only RTMR indices 2 and 3 are user-extensible. +/// +/// Tries two methods: +/// 1. sysfs interface at `/sys/devices/virtual/misc/tdx_guest/measurements/rtmrN:sha384` +/// 2. ioctl on `/dev/tdx_guest` (legacy) +pub fn extend_rtmr(index: u32, _event_type: u32, digest: [u8; 48]) -> Result<()> { + if index > 3 { + return Err(TdxAttestError::InvalidRtmrIndex(index)); + } + + if is_rtmr_sysfs_available() { + return extend_rtmr_via_sysfs(index, &digest); + } + + if Path::new(TDX_GUEST_DEVICE).exists() { + return extend_rtmr_via_ioctl(index, digest); + } + + Err(TdxAttestError::NotSupported( + "no extend_rtmr method available (no sysfs measurements, no /dev/tdx_guest)".to_string(), + )) +} + +fn is_rtmr_sysfs_available() -> bool { + Path::new(RTMR_SYSFS_BASE).is_dir() +} + +fn extend_rtmr_via_sysfs(index: u32, digest: &[u8; 48]) -> Result<()> { + let path = format!("{}/rtmr{}:sha384", RTMR_SYSFS_BASE, index); + + let mut file = OpenOptions::new() + .write(true) + .open(&path) + .map_err(|e| TdxAttestError::ExtendFailure(format!("open {path}: {e}")))?; + + file.write_all(digest).map_err(|e| match e.raw_os_error() { + Some(libc::EINVAL) => TdxAttestError::InvalidRtmrIndex(index), + Some(libc::EPERM) | Some(libc::EACCES) => { + TdxAttestError::ExtendFailure(format!("permission denied for RTMR {index}")) + } + _ => TdxAttestError::ExtendFailure(format!("write {path}: {e}")), + }) +} + +fn extend_rtmr_via_ioctl(index: u32, digest: [u8; 48]) -> Result<()> { + let file = OpenOptions::new() + .read(true) + .write(true) + .open(TDX_GUEST_DEVICE) + .map_err(|e| TdxAttestError::ExtendFailure(format!("open {TDX_GUEST_DEVICE}: {e}")))?; + + let req = TdxExtendRtmrReq { + data: digest, + index: index as u8, }; - let error = unsafe { tdx_att_extend(&event) }; - if error != _tdx_attest_error_t::TDX_ATTEST_SUCCESS { - return Err(error.into()); + + let ret = unsafe { libc::ioctl(file.as_raw_fd(), tdx_cmd_extend_rtmr(), &req) }; + if ret != 0 { + let err = std::io::Error::last_os_error(); + let errno = err.raw_os_error().unwrap_or(0); + if errno == libc::EINVAL { + return Err(TdxAttestError::InvalidRtmrIndex(index)); + } + return Err(TdxAttestError::ExtendFailure(format!("ioctl: {err}"))); } + Ok(()) } -pub fn get_supported_att_key_ids() -> Result> { - let mut list_size = 0; - let error = unsafe { tdx_att_get_supported_att_key_ids(ptr::null_mut(), &mut list_size) }; +// ============================================================================ +// ConfigFS Quote Generation +// ============================================================================ + +/// Get quote using Linux ConfigFS TSM interface (Linux 6.7+) +fn get_quote_via_configfs(report_data: &TdxReportData) -> Result> { + let configfs_path = prepare_configfs()?; + + let inblob_path = format!("{}/inblob", configfs_path); + let outblob_path = format!("{}/outblob", configfs_path); + let generation_path = format!("{}/generation", configfs_path); + + let lock_file = OpenOptions::new() + .write(true) + .open(&inblob_path) + .map_err(|e| TdxAttestError::Unexpected(format!("open {inblob_path}: {e}")))?; - if error != _tdx_attest_error_t::TDX_ATTEST_SUCCESS { - return Err(error.into()); + let ret = unsafe { libc::flock(lock_file.as_raw_fd(), libc::LOCK_EX) }; + if ret != 0 { + let err = std::io::Error::last_os_error(); + return Err(TdxAttestError::Unexpected(format!( + "flock {inblob_path}: {err}" + ))); } - let mut att_key_id_list = vec![TdxUuid([0; TDX_UUID_SIZE as usize]); list_size as usize]; + let gen1 = read_generation(&generation_path)?; + write_inblob_with_retry(&inblob_path, report_data)?; + + let gen2 = wait_for_generation_change(&generation_path, gen1)?; + if gen2 != gen1 + 1 { + return Err(TdxAttestError::Busy); + } + + let quote = read_outblob_with_retry(&outblob_path)?; + + let gen3 = read_generation(&generation_path)?; + if gen3 != gen2 { + return Err(TdxAttestError::Busy); + } + + if quote.len() <= QUOTE_MIN_SIZE || quote.len() >= QUOTE_BUF_SIZE { + return Err(TdxAttestError::QuoteFailure(format!( + "invalid quote size: {}", + quote.len() + ))); + } + + Ok(quote) +} + +fn prepare_configfs() -> Result { + if let Ok(path) = std::env::var(CONFIGFS_PATH_ENV) { + if path.len() < 240 && Path::new(&path).is_dir() && verify_configfs_provider(&path)? { + return Ok(path); + } + return Err(TdxAttestError::NotSupported(format!( + "invalid configfs path from env: {path}" + ))); + } - let error = unsafe { - tdx_att_get_supported_att_key_ids( - att_key_id_list.as_mut_ptr() as *mut tdx_uuid_t, - &mut list_size, - ) + let default_path = CONFIGFS_DEFAULT; + if Path::new(default_path).is_dir() && verify_configfs_provider(default_path)? { + return Ok(default_path.to_string()); + } + + { + let mut tried = CONFIGFS_MKDIR_TRIED + .lock() + .map_err(|_| TdxAttestError::Busy)?; + if *tried { + return Err(TdxAttestError::NotSupported( + "configfs already tried".to_string(), + )); + } + *tried = true; + } + + if !Path::new(CONFIGFS_BASE).is_dir() { + return Err(TdxAttestError::NotSupported(format!( + "configfs base not found: {CONFIGFS_BASE}" + ))); + } + + if fs::create_dir(default_path).is_ok() || Path::new(default_path).is_dir() { + let provider_path = format!("{}/provider", default_path); + for i in 0..5 { + if Path::new(&provider_path).exists() { + if verify_configfs_provider(default_path)? { + return Ok(default_path.to_string()); + } + break; + } + thread::sleep(Duration::from_micros(i as u64)); + } + } + + Err(TdxAttestError::NotSupported(format!( + "failed to prepare configfs: {default_path}" + ))) +} + +fn verify_configfs_provider(path: &str) -> Result { + let provider_path = format!("{}/provider", path); + let provider = fs::read_to_string(&provider_path) + .map_err(|e| TdxAttestError::Unexpected(format!("read {provider_path}: {e}")))?; + + Ok(provider.trim().starts_with("tdx_guest")) +} + +fn read_generation(path: &str) -> Result { + let content = fs::read_to_string(path) + .map_err(|e| TdxAttestError::Unexpected(format!("read {path}: {e}")))?; + content + .trim() + .parse() + .map_err(|e| TdxAttestError::Unexpected(format!("parse generation: {e}"))) +} + +fn write_inblob_with_retry(path: &str, data: &TdxReportData) -> Result<()> { + const RETRY_WAIT_MS: u64 = 10000; // 10 seconds + const MAX_RETRIES: usize = 3; + + let mut last_err = None; + for _ in 0..MAX_RETRIES { + let mut file = match OpenOptions::new().write(true).open(path) { + Ok(f) => f, + Err(e) => { + last_err = Some(e); + continue; + } + }; + + match file.write_all(data) { + Ok(()) => return Ok(()), + Err(e) => { + if e.raw_os_error() == Some(libc::EBUSY) { + thread::sleep(Duration::from_millis(RETRY_WAIT_MS)); + last_err = Some(e); + continue; + } + return Err(TdxAttestError::Unexpected(format!("write {path}: {e}"))); + } + } + } + + match last_err { + Some(e) if e.raw_os_error() == Some(libc::EBUSY) => Err(TdxAttestError::Busy), + Some(e) => Err(TdxAttestError::Unexpected(format!("write {path}: {e}"))), + None => Err(TdxAttestError::Unexpected("unknown error".to_string())), + } +} + +fn wait_for_generation_change(path: &str, current: i64) -> Result { + loop { + let gen = read_generation(path)?; + if gen != current { + return Ok(gen); + } + thread::sleep(Duration::from_micros(1)); + } +} + +fn read_outblob_with_retry(path: &str) -> Result> { + const RETRY_WAIT_MS: u64 = 10000; + const MAX_RETRIES: usize = 3; + + let mut last_err = None; + for _ in 0..MAX_RETRIES { + let mut file = match File::open(path) { + Ok(f) => f, + Err(e) => { + last_err = Some(e); + continue; + } + }; + + let mut buf = vec![0u8; QUOTE_BUF_SIZE]; + match file.read(&mut buf) { + Ok(n) if n > 0 => { + buf.truncate(n); + return Ok(buf); + } + Ok(_) => { + return Err(TdxAttestError::QuoteFailure("empty outblob".to_string())); + } + Err(e) => { + let errno = e.raw_os_error().unwrap_or(0); + if errno == libc::EBUSY || errno == libc::EINTR || errno == libc::ETIMEDOUT { + thread::sleep(Duration::from_millis(RETRY_WAIT_MS)); + last_err = Some(e); + continue; + } + return Err(TdxAttestError::QuoteFailure(format!("read {path}: {e}"))); + } + } + } + + match last_err { + Some(e) if e.raw_os_error() == Some(libc::EBUSY) => Err(TdxAttestError::Busy), + Some(e) => Err(TdxAttestError::QuoteFailure(format!("read {path}: {e}"))), + None => Err(TdxAttestError::Unexpected("unknown error".to_string())), + } +} + +// ============================================================================ +// VSock Quote Generation (QGS Protocol) +// ============================================================================ + +fn get_quote_via_vsock(report_data: &TdxReportData) -> Result> { + use std::io::{Read as _, Write as _}; + + let vsock_port = read_vsock_port()?; + if vsock_port == 0 { + return Err(TdxAttestError::NotSupported(format!( + "no vsock port configured in {TDX_ATTEST_CONFIG_PATH}" + ))); + } + + let report = get_report(report_data)?; + let request = build_qgs_get_quote_request(&report.0); + + let mut stream = vsock::VsockStream::connect_with_cid_port(vsock::VMADDR_CID_HOST, vsock_port)?; + + let len_header = (request.len() as u32).to_be_bytes(); + stream.write_all(&len_header)?; + stream.write_all(&request)?; + + let mut len_buf = [0u8; QGS_MSG_LEN_PREFIX_SIZE]; + stream.read_exact(&mut len_buf)?; + let msg_len = u32::from_be_bytes(len_buf) as usize; + + if msg_len > QGS_REQ_BUF_SIZE { + return Err(TdxAttestError::QuoteFailure(format!( + "response too large: {msg_len}" + ))); + } + + let mut response = vec![0u8; msg_len]; + stream.read_exact(&mut response)?; + + parse_qgs_get_quote_response(&response) +} + +fn read_vsock_port() -> Result { + let content = match fs::read_to_string(TDX_ATTEST_CONFIG_PATH) { + Ok(c) => c, + Err(_) => return Ok(0), }; - if error != _tdx_attest_error_t::TDX_ATTEST_SUCCESS { - return Err(error.into()); + for line in content.lines() { + let line = line.trim(); + if line.starts_with('#') { + continue; + } + if let Some(rest) = line.strip_prefix("port") { + let rest = rest.trim_start(); + if let Some(rest) = rest.strip_prefix('=') { + let port_str = rest.trim(); + if let Ok(port) = port_str.parse::() { + return Ok(port); + } + } + } + } + + Ok(0) +} + +/// Build QGS get_quote request message +/// +/// Message format: +/// - qgs_msg_header_t (16 bytes) +/// - report_size (4 bytes) +/// - id_list_size (4 bytes) +/// - report data (1024 bytes) +fn build_qgs_get_quote_request(report: &[u8; TDX_REPORT_SIZE]) -> Vec { + let report_size = TDX_REPORT_SIZE as u32; + let id_list_size: u32 = 0; + + // Calculate total message size (header + fields + report) + let msg_size: u32 = 16 + 4 + 4 + report_size; + + let mut msg = Vec::with_capacity(msg_size as usize); + + // QGS message header (16 bytes) + msg.extend_from_slice(&QGS_MSG_VERSION_MAJOR.to_le_bytes()); // major_version + msg.extend_from_slice(&QGS_MSG_VERSION_MINOR.to_le_bytes()); // minor_version + msg.extend_from_slice(&QGS_MSG_GET_QUOTE_REQ.to_le_bytes()); // type + msg.extend_from_slice(&msg_size.to_le_bytes()); // size + msg.extend_from_slice(&0u32.to_le_bytes()); // error_code (unused in request) + + // Request body + msg.extend_from_slice(&report_size.to_le_bytes()); // report_size + msg.extend_from_slice(&id_list_size.to_le_bytes()); // id_list_size + msg.extend_from_slice(report); // report data + + msg +} + +/// Parse QGS get_quote response and extract the quote +/// +/// Response format: +/// - qgs_msg_header_t (16 bytes) +/// - selected_id_size (4 bytes) +/// - quote_size (4 bytes) +/// - selected_id data (variable) +/// - quote data (variable) +fn parse_qgs_get_quote_response(data: &[u8]) -> Result> { + // Minimum size: header (16) + selected_id_size (4) + quote_size (4) = 24 bytes + if data.len() < 24 { + return Err(TdxAttestError::QuoteFailure(format!( + "response too short: {} bytes", + data.len() + ))); } - Ok(att_key_id_list) + // Parse header + let msg_type = u32::from_le_bytes([data[4], data[5], data[6], data[7]]); + let error_code = u32::from_le_bytes([data[12], data[13], data[14], data[15]]); + + if msg_type != QGS_MSG_GET_QUOTE_RESP { + return Err(TdxAttestError::QuoteFailure(format!( + "unexpected message type: {msg_type}" + ))); + } + + if error_code != 0 { + return Err(TdxAttestError::QuoteFailure(format!( + "QGS error code: 0x{error_code:x}" + ))); + } + + // Parse response body + let selected_id_size = u32::from_le_bytes([data[16], data[17], data[18], data[19]]) as usize; + let quote_size = u32::from_le_bytes([data[20], data[21], data[22], data[23]]) as usize; + + // Validate sizes + let expected_len = 24 + selected_id_size + quote_size; + if data.len() < expected_len { + return Err(TdxAttestError::QuoteFailure(format!( + "response truncated: got {} bytes, expected {expected_len}", + data.len() + ))); + } + + // Extract quote (skip selected_id) + let quote_offset = 24 + selected_id_size; + let quote = data[quote_offset..quote_offset + quote_size].to_vec(); + + if quote.len() < QUOTE_MIN_SIZE { + return Err(TdxAttestError::QuoteFailure(format!( + "quote too short: {} bytes", + quote.len() + ))); + } + + Ok(quote) }