Skip to content

Commit 6190822

Browse files
Add initial support for the TCG protocols
The TCG protocols are for interacting with TPMs, or Trusted Platform Modules. There are two versions in common use: TPM 1.2 and TPM 2.0. The TCG protocol is for TPM 1.x, and the TCG2 protocol can theoretically be used for any TPM but in practice is usually implemented just for TPM 2.0. To avoid dumping too much into one PR, this commit is an MVP that only includes getting information from the TPM (`status_check` for v1, `get_capability` for v2). I've exposed the new protocols with the same name but in different module paths: ``` uefi::proto::tcg::v1::Tcg uefi::proto::tcg::v2::Tcg ``` There is a lot of overlap between the two protocols, and the TPM v2 protocol relies in some places on v1 (although those parts are not included in this MVP). Also, it is common to need to support both versions at the same time, so I expect a common usage pattern will be to import `uefi::proto::tcg::{v1, v2}` and refer to TCG types with `v1::...` and `v2::...`.
1 parent 45047a6 commit 6190822

File tree

9 files changed

+762
-1
lines changed

9 files changed

+762
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
feature. (requires the **unstable** and **alloc** features)
1414
- Added an `core::error::Error` implementation for `Error` to ease
1515
integration with error-handling crates. (requires the **unstable** feature)
16+
- Added partial support for the TCG protocols for TPM devices under `uefi::proto::tcg`.
1617

1718
### Changed
1819

uefi-test-runner/src/proto/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ pub fn test(image: Handle, st: &mut SystemTable<Boot>) {
2828
target_arch = "aarch64"
2929
))]
3030
shim::test(bt);
31+
tcg::test(bt);
3132
}
3233

3334
fn find_protocol(bt: &BootServices) {
@@ -73,3 +74,4 @@ mod rng;
7374
))]
7475
mod shim;
7576
mod string;
77+
mod tcg;

uefi-test-runner/src/proto/tcg.rs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
use uefi::proto::tcg::{v1, v2};
2+
use uefi::table::boot::BootServices;
3+
4+
// Environmental note:
5+
//
6+
// QEMU does not support attaching multiple TPM devices at once, so we
7+
// can't test TPM v1 and v2 at the same time. To ensure that the CI
8+
// tests both v1 and v2, we arbitrarily choose x86_64 to test TPM v1 and
9+
// x86 32-bit to test TPM v2.
10+
//
11+
// This is enforced in the tests here; if the `ci` feature is enabled
12+
// but the TPM device of the appropriate type isn't available, the test
13+
// panics. If the `ci` feature is not enabled then you can freely enable
14+
// v1, v2, or no TPM.
15+
16+
pub fn test_tcg_v1(bt: &BootServices) {
17+
info!("Running TCG v1 test");
18+
19+
let handle = if let Ok(handle) = bt.get_handle_for_protocol::<v1::Tcg>() {
20+
handle
21+
} else if cfg!(all(feature = "ci", target_arch = "x86_64")) {
22+
panic!("TPM v1 is required on x86_64 CI");
23+
} else {
24+
info!("No TCG handle found");
25+
return;
26+
};
27+
28+
let mut tcg = bt
29+
.open_protocol_exclusive::<v1::Tcg>(handle)
30+
.expect("failed to open TCG protocol");
31+
32+
let status = tcg.status_check().expect("failed to call status_check");
33+
info!(
34+
"tcg status: {:?} {}",
35+
status.protocol_capability, status.feature_flags
36+
);
37+
for event in status.event_log.iter() {
38+
info!("PCR {}: {:?}", event.pcr_index().0, event.event_type());
39+
}
40+
}
41+
42+
pub fn test_tcg_v2(bt: &BootServices) {
43+
info!("Running TCG v2 test");
44+
45+
let handle = if let Ok(handle) = bt.get_handle_for_protocol::<v2::Tcg>() {
46+
handle
47+
} else if cfg!(all(feature = "ci", target_arch = "x86")) {
48+
panic!("TPM v2 is required on x86 (32-bit) CI");
49+
} else {
50+
info!("No TCG handle found");
51+
return;
52+
};
53+
54+
let mut tcg = bt
55+
.open_protocol_exclusive::<v2::Tcg>(handle)
56+
.expect("failed to open TCG protocol");
57+
58+
let capability = tcg.get_capability().expect("failed to call get_capability");
59+
info!("capability: {:?}", capability);
60+
}
61+
62+
pub fn test(bt: &BootServices) {
63+
test_tcg_v1(bt);
64+
test_tcg_v2(bt);
65+
}

uefi/src/proto/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,4 @@ pub mod rng;
7575
pub mod security;
7676
pub mod shim;
7777
pub mod string;
78+
pub mod tcg;

uefi/src/proto/tcg/enums.rs

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// Providing docstrings for each constant would be a lot of work, so
2+
// allow missing docs. Each type-level doc links to the relevant spec to
3+
// provide more info.
4+
//
5+
// Setting this at the module level so that we don't have to write it
6+
// above each constant. That's also why these enums are in a separate
7+
// module instead of `super`, since we don't want to allow missing docs
8+
// too broadly.
9+
#![allow(missing_docs)]
10+
11+
newtype_enum! {
12+
/// Algorithm identifiers.
13+
///
14+
/// These values are defined in the [TCG Algorithm Registry].
15+
///
16+
/// [TCG Algorithm Registry]: https://trustedcomputinggroup.org/resource/tcg-algorithm-registry/
17+
pub enum AlgorithmId: u16 => {
18+
ERROR = 0x0000,
19+
RSA = 0x0001,
20+
TDES = 0x0003,
21+
SHA1 = 0x0004,
22+
HMAC = 0x0005,
23+
AES = 0x0006,
24+
MGF1 = 0x0007,
25+
KEYED_HASH = 0x0008,
26+
XOR = 0x000a,
27+
SHA256 = 0x000b,
28+
SHA384 = 0x000c,
29+
SHA512 = 0x000d,
30+
NULL = 0x0010,
31+
SM3_256 = 0x0012,
32+
SM4 = 0x0013,
33+
// TODO: there are a bunch more, but the above list is probably
34+
// more than sufficient for real devices.
35+
}
36+
}
37+
38+
newtype_enum! {
39+
/// Event types stored in the TPM event log. The event type defines
40+
/// which structure type is stored in the event data.
41+
///
42+
/// For details of each variant, see the [TCG PC Client Platform
43+
/// Firmware Protocol Specification][spec], in particular the Events
44+
/// table in the Event Logging chapter.
45+
///
46+
/// [spec]: https://trustedcomputinggroup.org/resource/pc-client-specific-platform-firmware-profile-specification/
47+
pub enum EventType: u32 => {
48+
PREBOOT_CERT = 0x0000_0000,
49+
POST_CODE = 0x0000_0001,
50+
UNUSED = 0x0000_0002,
51+
NO_ACTION = 0x0000_0003,
52+
SEPARATOR = 0x0000_0004,
53+
ACTION = 0x0000_0005,
54+
EVENT_TAG = 0x0000_0006,
55+
CRTM_CONTENTS = 0x0000_0007,
56+
CRTM_VERSION = 0x0000_0008,
57+
CPU_MICROCODE = 0x0000_0009,
58+
PLATFORM_CONFIG_FLAGS = 0x0000_000a,
59+
TABLE_OF_DEVICES = 0x0000_000b,
60+
COMPACT_HASH = 0x0000_000c,
61+
IPL = 0x0000_000d,
62+
IPL_PARTITION_DATA = 0x0000_000e,
63+
NONHOST_CODE = 0x0000_000f,
64+
NONHOST_CONFIG = 0x0000_0010,
65+
NONHOST_INFO = 0x0000_0011,
66+
OMIT_BOOT_DEVICE_EVENTS = 0x0000_0012,
67+
EFI_EVENT_BASE = 0x8000_0000,
68+
EFI_VARIABLE_DRIVER_CONFIG = 0x8000_0001,
69+
EFI_VARIABLE_BOOT = 0x8000_0002,
70+
EFI_BOOT_SERVICES_APPLICATION = 0x8000_0003,
71+
EFI_BOOT_SERVICES_DRIVER = 0x8000_0004,
72+
EFI_RUNTIME_SERVICES_DRIVER = 0x8000_0005,
73+
EFI_GPT_EVENT = 0x8000_0006,
74+
EFI_ACTION = 0x8000_0007,
75+
EFI_PLATFORM_FIRMWARE_BLOB = 0x8000_0008,
76+
EFI_HANDOFF_TABLES = 0x8000_0009,
77+
EFI_PLATFORM_FIRMWARE_BLOB2 = 0x8000_000a,
78+
EFI_HANDOFF_TABLES2 = 0x8000_000b,
79+
EFI_VARIABLE_BOOT2 = 0x8000_000c,
80+
EFI_HCRTM_EVENT = 0x8000_0010,
81+
EFI_VARIABLE_AUTHORITY = 0x8000_00e0,
82+
EFI_SPDM_FIRMWARE_BLOB = 0x8000_00e1,
83+
EFI_SPDM_FIRMWARE_CONFIG = 0x8000_00e2,
84+
}
85+
}

uefi/src/proto/tcg/mod.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//! [TCG] (Trusted Computing Group) protocols.
2+
//!
3+
//! These protocols provide access to the [TPM][tpm] (Trusted Platform Module).
4+
//!
5+
//! There are two versions of the protocol. The original protocol is in
6+
//! the [`v1`] module. It is used with TPM 1.1 and 1.2 devices. The
7+
//! newer protocol in the [`v2`] module is generally provided for TPM
8+
//! 2.0 devices, although the spec indicates it can be used for older
9+
//! TPM versions as well.
10+
//!
11+
//! [TCG]: https://trustedcomputinggroup.org/
12+
//! [TPM]: https://en.wikipedia.org/wiki/Trusted_Platform_Module
13+
14+
pub mod v1;
15+
pub mod v2;
16+
17+
mod enums;
18+
pub use enums::*;
19+
20+
use bitflags::bitflags;
21+
22+
/// Platform Configuration Register (PCR) index.
23+
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
24+
pub struct PcrIndex(pub u32);
25+
26+
bitflags! {
27+
/// Hash algorithms the protocol can provide.
28+
///
29+
/// The [`v1`] protocol only supports SHA1.
30+
#[derive(Default)]
31+
#[repr(transparent)]
32+
pub struct HashAlgorithm: u32 {
33+
/// SHA-1 hash.
34+
const SHA1 = 0x0000_0001;
35+
36+
/// SHA-256 hash.
37+
const SHA256 = 0x0000_0002;
38+
39+
/// SHA-384 hash.
40+
const SHA384 = 0x0000_0004;
41+
42+
/// SHA-512 hash.
43+
const SHA512 = 0x0000_0008;
44+
45+
/// SM3-256 hash.
46+
const SM3_256 = 0x0000_0010;
47+
}
48+
}
49+
50+
/// Convenience function for converting from a `u32` to a `usize`
51+
/// without using `as` or unwrapping everywhere. This particular
52+
/// conversion comes up a lot in the TPM API, and it should be
53+
/// infallable on supported targets.
54+
fn usize_from_u32(val: u32) -> usize {
55+
val.try_into().expect("`u32` does not fit in `usize`")
56+
}

0 commit comments

Comments
 (0)