Skip to content

Commit 5678749

Browse files
committed
feat(tdx-isa): add ioctl-based backend for TDX attestation and enhance error handling
1 parent 9c268d5 commit 5678749

File tree

5 files changed

+238
-95
lines changed

5 files changed

+238
-95
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

intel-tdx/tdx-isa/Cargo.toml

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@ edition = "2024"
55
readme = "README.md"
66

77
[dependencies]
8-
tdx_module = { git = "https://github.com/intel/confidential-computing.tee.dcap.git", tag = "DCAP_1.24", package = "tdx-attest-rs" }
8+
tdx_module = { git = "https://github.com/intel/confidential-computing.tee.dcap.git", tag = "DCAP_1.24", package = "tdx-attest-rs", optional = true }
99
thiserror = "2"
10-
memory-layout = { version = "0.1", path = "../../memory-layout" }
10+
memory-layout = { version = "0.1", path = "../../memory-layout" }
11+
nix = { version = "0.30",features = ["ioctl"], optional = true }
12+
13+
[features]
14+
default = ["ioctl"]
15+
large_array_derive = ["memory-layout/large_array_derive"]
16+
serde = ["memory-layout/serde"]
17+
ioctl = ["dep:nix"]
18+
tdx-module = ["dep:tdx_module"]

intel-tdx/tdx-isa/src/lib.rs

Lines changed: 118 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,49 @@ extern crate memory_layout;
99

1010
use memory_layout::impl_default_clone_eq;
1111
use std::slice;
12-
use tdx_module::tdx_rtmr_event_t;
12+
use thiserror::Error;
1313

14+
#[cfg(feature = "tdx-module")]
1415
pub mod tdx_attest;
16+
#[cfg(feature = "ioctl")]
17+
pub mod tdx_ioctl;
1518

16-
use tdx_attest::{TdxAttestError, tdx_report_data_t, tdx_report_t};
19+
#[cfg(feature = "tdx-module")]
20+
use tdx_attest::tdx_report_t;
21+
22+
#[derive(Error, Debug, PartialEq, Eq)]
23+
pub enum TdxAttestError {
24+
/// Lower bound for error translations.
25+
#[error("Indicate min error to allow better translation, should be unexpected in production")]
26+
Min,
27+
#[error("The parameter is incorrect")]
28+
InvalidParameter,
29+
#[error("Not enough memory is available to complete this operation")]
30+
OutOfMemory,
31+
#[error("vsock related failure")]
32+
VsockFailure,
33+
#[error("Failed to get the TD Report")]
34+
ReportFailure,
35+
#[error("Failed to extend rtmr")]
36+
ExtendFailure,
37+
#[error("Request feature is not supported")]
38+
NotSupported,
39+
#[error("Failed to get the TD Quote")]
40+
QuoteFailure,
41+
#[error("The device driver return busy")]
42+
Busy,
43+
#[error("Failed to acess tdx attest device")]
44+
DeviceFailure,
45+
#[error("Only supported RTMR index is 2 and 3")]
46+
InvalidRtmrIndex,
47+
#[error(
48+
"The platform Quoting infrastructure does not support any of the keys described in att_key_id_list"
49+
)]
50+
UnsupportedAttKeyId,
51+
/// Upper bound for error translations.
52+
#[error("Indicate max error to allow better translation, should be unexpected in production")]
53+
Max,
54+
}
1755

1856
/// SHA384
1957
pub const TEE_HASH_384_SIZE: usize = 48;
@@ -34,8 +72,11 @@ pub const TEE_REPORT2_VERSION: usize = 0x0;
3472
/// VERSION for Report Type2 which mr_servicetd is used
3573
pub const TEE_REPORT2_VERSION_SERVICETD: usize = 0x1;
3674

37-
// Ref: https://github.com/intel/confidential-computing.sgx/blob/main/common/inc/sgx_report2.h
3875
struct_def! {
76+
/// Rust definition of `REPORTTYPE` from `REPORTMACSTRUCT`.
77+
///
78+
/// Ref: Intel TDX Module ABI Specification, section 4.7.4.
79+
/// Link to latest version (Sep 2025): https://cdrdv2.intel.com/v1/dl/getContent/733579
3980
#[repr(C, align(4))]
4081
#[derive(Clone, Debug, Default, Eq, PartialEq)]
4182
pub struct TeeReportType {
@@ -58,17 +99,19 @@ impl TeeReportType {
5899
pub const UNPADDED_SIZE: usize = 4;
59100
}
60101

61-
62102
pub const TDX_REPORT_MAC_STRUCT_SIZE: usize = 256;
63103
pub const TDX_REPORT_MAC_STRUCT_RESERVED1_BYTES: usize = 12;
64104
pub const TDX_REPORT_MAC_STRUCT_RESERVED2_BYTES: usize = 32;
65105

66-
// Ref: https://github.com/intel/confidential-computing.sgx/blob/main/common/inc/sgx_report2.h
67106
struct_def! {
107+
/// Rust definition of `REPORTMACSTRUCT` from `TDREPORT_STRUCT`.
108+
///
109+
/// Ref: Intel TDX Module ABI Specification, section 4.7.3.
110+
/// Link to latest version (Sep 2025): https://cdrdv2.intel.com/v1/dl/getContent/733579
68111
#[repr(C, align(256))]
69112
#[cfg_attr(
70113
feature = "large_array_derive",
71-
derive(Clone, Debug, Default, Eq, PartialEq)
114+
derive(Clone, Debug, Eq, PartialEq)
72115
)]
73116
pub struct TdxReportMac {
74117
/// ( 0) TEE Report type
@@ -78,7 +121,7 @@ struct_def! {
78121
/// ( 16) Security Version of the CPU
79122
pub cpu_svn: [u8; TEE_CPU_SVN_SIZE],
80123
/// ( 32) SHA384 of TEE_TCB_INFO for TEEs
81-
pub tee_tcb_info_hash:[u8; TEE_HASH_384_SIZE],
124+
pub tee_tcb_info_hash: [u8; TEE_HASH_384_SIZE],
82125
/// ( 80) SHA384 of TEE_INFO
83126
pub tee_info_hash: [u8; TEE_HASH_384_SIZE],
84127
/// (128) Data provided by the user
@@ -100,12 +143,16 @@ pub const TEE_TCB_INFO_SIZE: usize = 239;
100143
pub const TDX_REPORT_RESERVED_SIZE: usize = 17;
101144
pub const TEE_INFO_SIZE: usize = 512;
102145

103-
// Ref: https://github.com/intel/confidential-computing.sgx/blob/main/common/inc/sgx_report2.h
104146
struct_def! {
147+
/// Rust definition of `TDREPORT_STRUCT` from the output of the `TDG.MR.REPORT` function.
148+
/// `TDG.MR.REPORT` is one variant of syscall `TDCALL`.
149+
///
150+
/// Ref: Intel TDX Module ABI Specification, section 4.7.2.
151+
/// Link to latest version (Sep 2025): https://cdrdv2.intel.com/v1/dl/getContent/733579
105152
#[repr(C, align(1024))]
106153
#[cfg_attr(
107154
feature = "large_array_derive",
108-
derive(Clone, Debug, Default, Eq, PartialEq)
155+
derive(Clone, Debug, Eq, PartialEq)
109156
)]
110157
pub struct TdxReport {
111158
/// ( 0) Report mac struct for SGX report type 2
@@ -119,12 +166,14 @@ struct_def! {
119166
}
120167
}
121168

169+
#[cfg(feature = "tdx-module")]
122170
impl From<tdx_report_t> for TdxReport {
123171
fn from(report: tdx_report_t) -> Self {
124172
Self::try_copy_from(&report.d).expect("validated size")
125173
}
126174
}
127175

176+
#[cfg(feature = "tdx-module")]
128177
impl From<TdxReport> for tdx_report_t {
129178
fn from(report: TdxReport) -> Self {
130179
let mut d = [0u8; TDX_REPORT_SIZE];
@@ -148,35 +197,28 @@ impl TdxReport {
148197
/// # Errors
149198
/// Propagates the underlying TDX attestation error code.
150199
pub fn get_report(report_data: [u8; TDX_REPORT_DATA_SIZE]) -> Result<Self, TdxAttestError> {
151-
let mut tdx_report = tdx_report_t {
152-
d: [0; TDX_REPORT_SIZE],
153-
};
154-
let report_data = tdx_report_data_t { d: report_data };
155-
tdx_attest::parse_tdx_attest_error(tdx_attest::tdx_att_get_report(
156-
Some(&report_data),
157-
&mut tdx_report,
158-
))?;
159-
Ok(tdx_report.into())
200+
#[cfg(feature = "ioctl")]
201+
{
202+
return tdx_ioctl::get_report(report_data);
203+
}
204+
#[cfg(all(not(feature = "ioctl"), feature = "tdx-module"))]
205+
{
206+
return tdx_attest::get_report(report_data);
207+
}
208+
#[cfg(not(any(feature = "ioctl", feature = "tdx-module")))]
209+
{
210+
Err(TdxAttestError::NotSupported)
211+
}
160212
}
161213
}
162214

163215
pub const TDX_RTMR_EVENT_HEADER_SIZE: usize = 68;
164216
/// Size of the RTMR extend data field in bytes.
165217
pub const TDX_RTMR_EXTEND_DATA_SIZE: usize = 48;
166218

167-
#[repr(u8)]
168-
pub enum TdxStatus {
169-
Success = 0,
170-
InvalidParameter = 1,
171-
AccessDenied = 2,
172-
InternalError = 255,
173-
}
174-
175-
pub const REMR_EXTEND_DATA_SIZE: usize = 48;
176-
177219
/// Extend one of the TDX runtime measurement registers (RTMRs).
178220
///
179-
/// RTMR[rtmr_index] = SHA384(RTMR[rtmr_index] || extend_data)
221+
/// `RTMR[rtmr_index] = SHA384(RTMR[rtmr_index] || extend_data)`
180222
/// - `rtmr_index`: only supported RTMR index is 2 and 3.
181223
/// - `event_data`: field is currently expected to be empty by the platform
182224
/// quoting infrastructure.
@@ -193,48 +235,66 @@ pub const REMR_EXTEND_DATA_SIZE: usize = 48;
193235
/// not supported.
194236
pub fn extend_rtmr(
195237
rtmr_index: u64,
196-
extend_data: [u8; REMR_EXTEND_DATA_SIZE],
238+
extend_data: [u8; TDX_RTMR_EXTEND_DATA_SIZE],
197239
) -> Result<(), TdxAttestError> {
198-
match rtmr_index {
199-
2..=3 => (),
200-
_ => return Err(TdxAttestError::InvalidRtmrIndex),
201-
};
202-
// From: `tdx_attest_sys` crate generated binding code
203-
// ```C
204-
// typedef struct _tdx_rtmr_event_t {
205-
// uint32_t version;
206-
// uint64_t rtmr_index;
207-
// uint8_t extend_data[48];
208-
// uint32_t event_type;
209-
// uint32_t event_data_size;
210-
// uint8_t event_data[];
211-
// } tdx_rtmr_event_t;
212-
// ```
213-
let mut rtmr_event = [0u8; std::mem::size_of::<tdx_rtmr_event_t>()];
214-
rtmr_event[0..0 + 4].copy_from_slice(&1u32.to_ne_bytes());
215-
rtmr_event[4..4 + 8].copy_from_slice(&rtmr_index.to_ne_bytes());
216-
rtmr_event[12..12 + REMR_EXTEND_DATA_SIZE].copy_from_slice(&extend_data);
217-
218-
tdx_attest::parse_tdx_attest_error(tdx_attest::tdx_att_extend(&rtmr_event))
240+
#[cfg(feature = "ioctl")]
241+
{
242+
return tdx_ioctl::extend_rtmr(rtmr_index, extend_data);
243+
}
244+
#[cfg(all(not(feature = "ioctl"), feature = "tdx-module"))]
245+
{
246+
return tdx_attest::extend_rtmr(rtmr_index, extend_data);
247+
}
248+
#[cfg(not(any(feature = "ioctl", feature = "tdx-module")))]
249+
{
250+
Err(TdxAttestError::NotSupported)
251+
}
219252
}
220253

221254
#[cfg(test)]
222255
mod tests {
223256
use super::*;
224257

225258
#[test]
226-
fn test_tdx_att_get_report() {
259+
fn test_tdx_att_get_report_invalid_device() {
260+
let expected_err = if cfg!(any(feature = "ioctl", feature = "tdx-module")) {
261+
TdxAttestError::DeviceFailure
262+
} else {
263+
TdxAttestError::NotSupported
264+
};
227265
let result = TdxReport::get_report([0; TDX_REPORT_DATA_SIZE]);
228-
assert!(matches!(result, Err(TdxAttestError::DeviceFailure)));
266+
match result {
267+
Ok(_) => panic!("expecting error"),
268+
Err(err) => assert_eq!(err, expected_err),
269+
}
270+
}
271+
272+
#[test]
273+
fn test_tdx_att_extend_invalid_device() {
274+
let expected_err = if cfg!(any(feature = "ioctl", feature = "tdx-module")) {
275+
TdxAttestError::DeviceFailure
276+
} else {
277+
TdxAttestError::NotSupported
278+
};
279+
280+
let mut extend_data = [0u8; TDX_RTMR_EXTEND_DATA_SIZE];
281+
extend_data[0] = 123;
282+
let err = extend_rtmr(2, extend_data).expect_err("expecting err");
283+
assert_eq!(err, expected_err);
229284
}
230285

231286
#[test]
232-
fn test_tdx_att_extend() {
287+
fn test_tdx_att_extend_invalid_index() {
288+
let expected_err = if cfg!(any(feature = "ioctl", feature = "tdx-module")) {
289+
TdxAttestError::InvalidRtmrIndex
290+
} else {
291+
TdxAttestError::NotSupported
292+
};
293+
233294
let mut extend_data = [0u8; TDX_RTMR_EXTEND_DATA_SIZE];
234295
extend_data[0] = 123;
235-
let result = extend_rtmr(2, extend_data);
236-
assert!(matches!(result, Err(TdxAttestError::DeviceFailure)));
237-
let result = extend_rtmr(77, extend_data);
238-
assert!(matches!(result, Err(TdxAttestError::InvalidRtmrIndex)));
296+
297+
let err = extend_rtmr(77, extend_data).expect_err("expecting err");
298+
assert_eq!(err, expected_err);
239299
}
240300
}

intel-tdx/tdx-isa/src/tdx_attest.rs

Lines changed: 39 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,52 @@
11
//! Low-level TDX attestation bindings and error translation.
22
//!
3-
//! This module re-exports the raw attestation FFI functions and provides a
4-
//! Rust-friendly error enum mirroring the upstream TDX attestation errors.
3+
//! This module re-exports the raw attestation FFI functions and provides
4+
//! backend helpers for the `tdx-attest-rs` approach.
55
6-
use thiserror::Error;
6+
use crate::{TdxAttestError, TdxReport, TDX_REPORT_DATA_SIZE, TDX_REPORT_SIZE, TDX_RTMR_EXTEND_DATA_SIZE};
77

88
pub use tdx_module::tdx_att_extend;
99
pub use tdx_module::tdx_att_get_quote;
1010
pub use tdx_module::tdx_att_get_report;
1111
pub use tdx_module::tdx_att_get_supported_att_key_ids;
1212
pub use tdx_module::{tdx_attest_error_t, tdx_report_data_t, tdx_report_t, tdx_rtmr_event_t};
1313

14-
#[derive(Error, Debug)]
15-
pub enum TdxAttestError {
16-
/// Lower bound for error translations.
17-
#[error("Indicate min error to allow better translation, should be unexpected in production")]
18-
Min,
19-
#[error("The parameter is incorrect")]
20-
InvalidParameter,
21-
#[error("Not enough memory is available to complete this operation")]
22-
OutOfMemory,
23-
#[error("vsock related failure")]
24-
VsockFailure,
25-
#[error("Failed to get the TD Report")]
26-
ReportFailure,
27-
#[error("Failed to extend rtmr")]
28-
ExtendFailure,
29-
#[error("Request feature is not supported")]
30-
NotSupported,
31-
#[error("Failed to get the TD Quote")]
32-
QuoteFailure,
33-
#[error("The device driver return busy")]
34-
Busy,
35-
#[error("Failed to acess tdx attest device")]
36-
DeviceFailure,
37-
#[error("Only supported RTMR index is 2 and 3")]
38-
InvalidRtmrIndex,
39-
#[error(
40-
"The platform Quoting infrastructure does not support any of the keys described in att_key_id_list"
41-
)]
42-
UnsupportedAttKeyId,
43-
/// Upper bound for error translations.
44-
#[error("Indicate max error to allow better translation, should be unexpected in production")]
45-
Max,
14+
/// Request a TDX Report of the calling TD using `tdx-attest-rs`.
15+
pub fn get_report(report_data: [u8; TDX_REPORT_DATA_SIZE]) -> Result<TdxReport, TdxAttestError> {
16+
let mut tdx_report = tdx_report_t {
17+
d: [0; TDX_REPORT_SIZE],
18+
};
19+
let report_data = tdx_report_data_t { d: report_data };
20+
parse_tdx_attest_error(tdx_att_get_report(Some(&report_data), &mut tdx_report))?;
21+
Ok(tdx_report.into())
22+
}
23+
24+
/// Extend one of the TDX runtime measurement registers (RTMRs) using `tdx-attest-rs`.
25+
pub fn extend_rtmr(
26+
rtmr_index: u64,
27+
extend_data: [u8; TDX_RTMR_EXTEND_DATA_SIZE],
28+
) -> Result<(), TdxAttestError> {
29+
match rtmr_index {
30+
2..=3 => (),
31+
_ => return Err(TdxAttestError::InvalidRtmrIndex),
32+
};
33+
// From: `tdx_attest_sys` crate generated binding code
34+
// ```C
35+
// typedef struct _tdx_rtmr_event_t {
36+
// uint32_t version;
37+
// uint64_t rtmr_index;
38+
// uint8_t extend_data[48];
39+
// uint32_t event_type;
40+
// uint32_t event_data_size;
41+
// uint8_t event_data[];
42+
// } tdx_rtmr_event_t;
43+
// ```
44+
let mut rtmr_event = [0u8; std::mem::size_of::<tdx_rtmr_event_t>()];
45+
rtmr_event[0..0 + 4].copy_from_slice(&1u32.to_ne_bytes());
46+
rtmr_event[4..4 + 8].copy_from_slice(&rtmr_index.to_ne_bytes());
47+
rtmr_event[12..12 + TDX_RTMR_EXTEND_DATA_SIZE].copy_from_slice(&extend_data);
48+
49+
parse_tdx_attest_error(tdx_att_extend(&rtmr_event))
4650
}
4751

4852
#[rustfmt::skip]

0 commit comments

Comments
 (0)