AxlTpm — TPM 2.0 presence + capability
TPM 2.0 access via EFI_TCG2_PROTOCOL: presence + capability readout, the
Endorsement Key public part, and PCR-bound seal/unseal.
Header: <axl/axl-tpm.h>. The TCG2 protocol is a singleton, so there is
nothing to enumerate. The read-only surface is a presence check plus one
typed capability struct; beyond that the module drives raw TPM2 commands
over SubmitCommand for the Endorsement Key and for sealing a secret to
the platform’s measured-boot state (see below). Measurement (PCR extend)
and the event log remain out of scope — sealing reads PCRs into a
policy, it does not extend them.
The protocol is located lazily and cached (like the CPU-arch /
MP-services helpers). axl_tpm_present() reports whether the TCG2
protocol is published; axl_tpm_get_capability() calls GetCapability
and projects EFI_TCG2_BOOT_SERVICE_CAPABILITY into AxlTpmCapability.
if (axl_tpm_present()) {
AxlTpmCapability cap;
if (axl_tpm_get_capability(&cap) == AXL_OK && cap.present) {
axl_printf("TPM mfr=0x%08x banks=%u active=0x%x\n",
cap.manufacturer_id, cap.number_of_pcr_banks,
cap.active_pcr_banks);
}
}
Two presence concepts: axl_tpm_present() is “the TCG2 protocol is
published” (a stack is available to query); AxlTpmCapability.present
is the firmware’s TPMPresentFlag (“a chip is installed and
responding”). When the protocol is absent axl_tpm_get_capability
returns AXL_ERR and the consumer reports the TPM as not present (the
QEMU-default golden, {"tpm":{"present":false}}).
active_pcr_banks is a hash-algorithm bitmask (EFI_TCG2_BOOT_HASH_ALG_*,
consumer decodes names); number_of_pcr_banks is a count. Both are
valid only when the capability structure version is >= 1.1.
Endorsement Key + PCR-bound seal/unseal
Beyond the read-only capability surface, the module also drives raw TPM2
commands over EFI_TCG2_PROTOCOL.SubmitCommand:
axl_tpm_read_ek_pubderives the Endorsement Key public part (a stable per-device identity) viaTPM2_CreatePrimaryin the endorsement hierarchy.axl_tpm_seal/axl_tpm_unsealseal a small secret (e.g. a TLS private key) to the chosen SHA-256 PCRs and recover it only when the live PCRs reproduce the seal-time measured state. The chain isCreatePrimary(a deterministic ECC SRK) ->PCR_Read(the PolicyPCR digest is computed in software) ->Create(a keyedhash sealed object whose authPolicy is that digest); unseal runsLoad->StartAuthSession->PolicyPCR->Unseal. The blobaxl_tpm_sealreturns is opaque ciphertext the caller persists;axl_tpm_unsealreturnsAXL_DENIEDif the measured state changed. Uses empty owner/parent authorization (the common firmware default); cross-boot unseal also needs a stable owner primary seed (noTPM2_Clearbetween).
The raw-command paths are validated against swtpm in QEMU
(test/integration/test-tpm-qemu.sh, test-tpm-seal-qemu.sh); the
absent path is covered on both arches by the unit suite.
API Reference
TPM 2.0 presence and capability readout.
Reads the platform’s TPM 2.0 capability via the firmware’s TCG2 protocol (EFI_TCG2_PROTOCOL.GetCapability). Unlike the other platform readers there is nothing to enumerate — the TCG2 protocol is a singleton — so this is a presence check plus one typed capability struct.
if (axl_tpm_present()) {
AxlTpmCapability cap;
if (axl_tpm_get_capability(&cap) == AXL_OK) {
// ... report manufacturer, banks, sizes ...
}
}
Scope is the boot-service capability fields a diagnostic/inventory view reports. Measurement, the event log, and PCR extension are out of scope.
Defines
-
AXL_TPM_SEAL_MAX_SECRET
Largest secret axl_tpm_seal accepts (TPM sealed-data limit).
Enums
Functions
-
bool axl_tpm_present(void)
Report whether the firmware publishes the TCG2 protocol.
A cheap presence gate: true means a TPM 2.0 software stack is available to query (call
axl_tpm_get_capabilityfor the details). It does not by itself guarantee a physical TPM is responding — that isAxlTpmCapability.present(TPMPresentFlag). Result is cached after the first call.- Returns:
true if the TCG2 protocol is published, false otherwise.
-
int axl_tpm_get_capability(AxlTpmCapability *out)
Read the TPM 2.0 boot-service capability.
- Parameters:
out – [out] populated on success
- Returns:
AXL_OK on success, AXL_ERR if the TCG2 protocol is not published, the GetCapability call fails, or
outis NULL. A present-but-wedged TPM (protocol published, GetCapability fails) reports the same AXL_ERR as an absent protocol — the consumer reports the TPM as not present in both cases (theaxl_tpm_present() == falsecase).
-
bool axl_tpm_ek_available(void)
Whether a TPM 2.0 with a readable Endorsement Key is present.
A consumer can branch on this to fall back to a weaker machine id (e.g. the SMBIOS UUID) when no TPM is available. Returns false immediately when the TCG2 protocol is absent; otherwise it confirms the EK can actually be derived. The result is cached after the first call.
- Returns:
true if axl_tpm_read_ek_pub() will succeed.
-
int axl_tpm_read_ek_pub(uint8_t *buf, size_t buf_size, size_t *out_len, AxlTpmEkAlg *out_alg)
Read the TPM 2.0 Endorsement Key public part.
Derives the EK with TPM2_CreatePrimary in the endorsement hierarchy using the standard TCG EK template — ECC P-256 first, falling back to RSA-2048 — and returns the public key’s canonical bytes: for ECC the uncompressed point X||Y (64 bytes for P-256); for RSA the modulus (256 bytes for RSA-2048). Bytes are in their natural big-endian order, so they are deterministic for a given TPM across boots — hash them for a stable machine id. Derivation is transient (the primary handle is flushed); nothing is persisted in the TPM.
Output-buffer protocol: call with
buf== NULL to query the required size (written to*out_len). Otherwisebuf_sizeis the capacity; on success*out_lenis the byte count and*out_algthe key type. Ifbuf_sizeis too small, returns AXL_ERR with*out_lenset to the required size andbufuntouched.- Parameters:
buf – [out] EK public bytes, or NULL to size-query
buf_size – capacity of
bufin bytesout_len – [out] bytes written / required size
out_alg – [out] EK algorithm (may be NULL)
- Returns:
AXL_OK on success; AXL_ERR if no TPM / no TCG2 protocol, the EK could not be derived, the buffer is too small, or
out_lenis NULL.
-
int axl_tpm_seal(const uint8_t *secret, size_t secret_len, const uint32_t *pcrs, size_t pcr_count, uint8_t **out_blob, size_t *out_blob_len)
Seal a secret under a PCR policy.
Binds
secretto the current values of the PCRs listed inpcrs(SHA-256 bank, indices 0..23) and returns an opaque sealed blob inout_blobthat the caller persists and later passes toaxl_tpm_unseal. The blob carries everything unseal needs (the sealed object and the PCR selection); the secret is never in it in the clear.out_blobis allocated with axl_malloc — free it withaxl_free.- Parameters:
secret – secret bytes to seal
secret_len – secret length (1..AXL_TPM_SEAL_MAX_SECRET)
pcrs – PCR indices to bind to (each 0..23)
pcr_count – number of PCRs in
pcrsout_blob – [out] sealed blob (free with axl_free)
out_blob_len – [out] sealed blob length
- Returns:
AXL_OK on success; AXL_INVALID if
secret/out_blob/out_blob_lenis NULL,secret_lenis 0 or exceeds AXL_TPM_SEAL_MAX_SECRET, orpcr_countis 0 or names a PCR > 23; AXL_ERR if no TPM (!axl_tpm_present()) or a TPM command fails.
-
int axl_tpm_unseal(const uint8_t *blob, size_t blob_len, uint8_t **out_secret, size_t *out_secret_len)
Unseal a blob produced by axl_tpm_seal.
Recovers the secret only if the current PCR values satisfy the policy baked into the blob at seal time. The recovered secret is returned in
out_secret, allocated with axl_malloc — free it withaxl_free.- Parameters:
blob – sealed blob from axl_tpm_seal
blob_len – blob length
out_secret – [out] recovered secret (free with axl_free)
out_secret_len – [out] recovered secret length
- Returns:
AXL_OK on success; AXL_INVALID if an argument is NULL or the blob is malformed; AXL_DENIED if the current PCRs do not satisfy the seal-time policy (the firmware/measured state changed); AXL_ERR if no TPM or a TPM command fails.
-
struct AxlTpmCapability
- #include <axl-tpm.h>
TPM 2.0 boot-service capability.
Typed projection of the firmware’s
EFI_TCG2_BOOT_SERVICE_CAPABILITY.presentis the firmware’s own TPMPresentFlag — a TPM chip is installed and responding — which is distinct fromaxl_tpm_present()reporting that the TCG2 protocol is published.Note the two PCR fields are different kinds of value:
number_of_pcr_banksis a count,active_pcr_banksis a hash-algorithm bitmask (not a count). Both are meaningful only when the structure version is >= 1.1; on older firmware they read 0 — and since a present TPM always has at least one bank,number_of_pcr_banks == 0on a present TPM means the firmware predates struct ver 1.1, not a bankless TPM.The event-log format flags (SupportedEventLogs) are omitted — the event log is measurement-domain (out of scope). The two hash-algorithm bitmasks below are the supported/active pair an inventory view reports.
Public Members
-
bool present
TPMPresentFlag: a TPM is installed and responding.
-
uint8_t structure_version_major
capability structure version major
-
uint8_t structure_version_minor
capability structure version minor
-
uint8_t protocol_version_major
TCG2 protocol version major.
-
uint8_t protocol_version_minor
TCG2 protocol version minor.
-
uint32_t manufacturer_id
TPM manufacturer ID (TCG vendor ID, 4 packed ASCII bytes)
-
uint32_t max_command_size
max supported command buffer size in bytes
-
uint32_t max_response_size
max supported response buffer size in bytes
-
uint32_t number_of_pcr_banks
COUNT of PCR banks the TPM supports (struct ver >= 1.1)
-
uint32_t supported_hash_algorithms
hash algorithms the TCG2 stack supports, EFI_TCG2_BOOT_HASH_ALG_* BITMASK (HashAlgorithmBitmap; superset of active_pcr_banks; consumer decodes names)
-
uint32_t active_pcr_banks
active PCR-bank hash-algorithm BITMASK, EFI_TCG2_BOOT_HASH_ALG_* (struct ver >= 1.1; consumer decodes names)
-
bool present