Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions doc/tpm_usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,31 @@ This document describes how to use TPM-backed helper APIs with libspdm for secur

---

## CMake Configuration

Configure TPM key handles and certificate chain NV indices at build time:

```bash
cmake -B build \
-D LIBSPDM_TPM_REQUESTER_HANDLES="0x81000011;0x81000012" \
-D LIBSPDM_TPM_REQUESTER_CERTCHAINS="0x1500011;0x1500012" \
-D LIBSPDM_TPM_RESPONDER_HANDLES="0x81000021;0x81000022" \
-D LIBSPDM_TPM_RESPONDER_CERTCHAINS="0x1500021;0x1500022"
```

### Configuration Parameters

| Parameter | Description | Format |
|-----------|-------------|--------|
| `LIBSPDM_TPM_REQUESTER_HANDLES` | TPM persistent key handles for requester | Semicolon-separated hex values |
| `LIBSPDM_TPM_REQUESTER_CERTCHAINS` | NV indices for requester certificate chains | Semicolon-separated hex values |
| `LIBSPDM_TPM_RESPONDER_HANDLES` | TPM persistent key handles for responder | Semicolon-separated hex values |
| `LIBSPDM_TPM_RESPONDER_CERTCHAINS` | NV indices for responder certificate chains | Semicolon-separated hex values |

**Note:** Multiple handles/indices support multi-key scenarios. First handle maps to slot 0, second to slot 1, etc.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems this design does not support empty slot.
Current libspdm device sample support slot 0, slot 1, and slot 4.

Please make slot 4 work or add comment to indicate the limitation.


---

## Overview

The TPM integration layer provides:
Expand Down
2 changes: 1 addition & 1 deletion os_stub/cryptlib_openssl/tpm/tpm.c
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ bool libspdm_tpm_read_nv(uint32_t index, void **buffer, size_t *size)
if (nv_name)
Esys_Free(nv_name);
if (nv_tr != ESYS_TR_NONE)
Esys_FlushContext(esys, nv_tr);
Esys_TR_Close(esys, &nv_tr);
if (esys)
Esys_Finalize(&esys);
if (tcti)
Expand Down
62 changes: 62 additions & 0 deletions os_stub/spdm_device_secret_lib_tpm/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,70 @@
cmake_minimum_required(VERSION 3.5)

# Default values for backward compatibility (2 slots)
set(LIBSPDM_TPM_REQUESTER_HANDLES "0x81000011;0x81000011" CACHE STRING "Semicolon-separated list of TPM Requester Handle Strings")
set(LIBSPDM_TPM_REQUESTER_CERTCHAINS "0x1500011;0x1500011" CACHE STRING "Semicolon-separated list of TPM Requester Certificate Chain NV Indices")
set(LIBSPDM_TPM_RESPONDER_HANDLES "0x81000021;0x81000021" CACHE STRING "Semicolon-separated list of TPM Responder Handle Strings")
set(LIBSPDM_TPM_RESPONDER_CERTCHAINS "0x1500021;0x1500021" CACHE STRING "Semicolon-separated list of TPM Responder Certificate Chain NV Indices")
Comment thread
itsManjeet marked this conversation as resolved.

# Count the number of slots (variables are already CMake lists)
list(LENGTH LIBSPDM_TPM_REQUESTER_HANDLES REQUESTER_SLOT_COUNT)
list(LENGTH LIBSPDM_TPM_REQUESTER_CERTCHAINS REQUESTER_CERTCHAIN_COUNT)
list(LENGTH LIBSPDM_TPM_RESPONDER_HANDLES RESPONDER_SLOT_COUNT)
list(LENGTH LIBSPDM_TPM_RESPONDER_CERTCHAINS RESPONDER_CERTCHAIN_COUNT)

# Validate that handles and certchains have matching counts
if(NOT REQUESTER_SLOT_COUNT EQUAL REQUESTER_CERTCHAIN_COUNT)
message(FATAL_ERROR "LIBSPDM_TPM_REQUESTER_HANDLES and LIBSPDM_TPM_REQUESTER_CERTCHAINS must have the same number of entries")
endif()

if(NOT RESPONDER_SLOT_COUNT EQUAL RESPONDER_CERTCHAIN_COUNT)
message(FATAL_ERROR "LIBSPDM_TPM_RESPONDER_HANDLES and LIBSPDM_TPM_RESPONDER_CERTCHAINS must have the same number of entries")
endif()

message(STATUS "TPM Configuration:")
message(STATUS " Requester slots: ${REQUESTER_SLOT_COUNT}")
message(STATUS " Responder slots: ${RESPONDER_SLOT_COUNT}")

# Generate keys.h content dynamically
set(KEYS_H_CONTENT "/**\n")
set(KEYS_H_CONTENT "${KEYS_H_CONTENT} * Copyright Notice:\n")
set(KEYS_H_CONTENT "${KEYS_H_CONTENT} * Copyright 2024-2025 DMTF. All rights reserved.\n")
set(KEYS_H_CONTENT "${KEYS_H_CONTENT} * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md\n")
set(KEYS_H_CONTENT "${KEYS_H_CONTENT} **/\n\n")
set(KEYS_H_CONTENT "${KEYS_H_CONTENT}#pragma once\n\n")
set(KEYS_H_CONTENT "${KEYS_H_CONTENT}/* Auto-generated TPM handle configuration */\n\n")

# Add slot count macros
set(KEYS_H_CONTENT "${KEYS_H_CONTENT}#define LIBSPDM_TPM_REQUESTER_SLOT_COUNT ${REQUESTER_SLOT_COUNT}\n")
set(KEYS_H_CONTENT "${KEYS_H_CONTENT}#define LIBSPDM_TPM_RESPONDER_SLOT_COUNT ${RESPONDER_SLOT_COUNT}\n\n")

# Generate requester handle definitions
set(KEYS_H_CONTENT "${KEYS_H_CONTENT}/* TPM Requester Handles */\n")
math(EXPR REQUESTER_MAX_INDEX "${REQUESTER_SLOT_COUNT} - 1")
foreach(INDEX RANGE ${REQUESTER_MAX_INDEX})
list(GET LIBSPDM_TPM_REQUESTER_HANDLES ${INDEX} HANDLE)
list(GET LIBSPDM_TPM_REQUESTER_CERTCHAINS ${INDEX} CERTCHAIN)
set(KEYS_H_CONTENT "${KEYS_H_CONTENT}#define LIBSPDM_TPM_HANDLE_REQUESTER_HANDLE_SLOT_${INDEX} \"handle:${HANDLE}\"\n")
set(KEYS_H_CONTENT "${KEYS_H_CONTENT}#define LIBSPDM_TPM_HANDLE_REQUESTER_CERTCHAIN_SLOT_${INDEX} ${CERTCHAIN}\n")
endforeach()

set(KEYS_H_CONTENT "${KEYS_H_CONTENT}\n/* TPM Responder Handles */\n")
math(EXPR RESPONDER_MAX_INDEX "${RESPONDER_SLOT_COUNT} - 1")
foreach(INDEX RANGE ${RESPONDER_MAX_INDEX})
list(GET LIBSPDM_TPM_RESPONDER_HANDLES ${INDEX} HANDLE)
list(GET LIBSPDM_TPM_RESPONDER_CERTCHAINS ${INDEX} CERTCHAIN)
set(KEYS_H_CONTENT "${KEYS_H_CONTENT}#define LIBSPDM_TPM_HANDLE_RESPONDER_HANDLE_SLOT_${INDEX} \"handle:${HANDLE}\"\n")
set(KEYS_H_CONTENT "${KEYS_H_CONTENT}#define LIBSPDM_TPM_HANDLE_RESPONDER_CERTCHAIN_SLOT_${INDEX} ${CERTCHAIN}\n")
endforeach()

# Write the generated keys.h file
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/keys.h "${KEYS_H_CONTENT}")

add_library(spdm_device_secret_lib_tpm STATIC "")

target_include_directories(spdm_device_secret_lib_tpm
PRIVATE
${CMAKE_CURRENT_BINARY_DIR}
${LIBSPDM_DIR}/os_stub/spdm_device_secret_lib_tpm
${LIBSPDM_DIR}/include
${LIBSPDM_DIR}/include/hal
Expand All @@ -26,6 +87,7 @@ target_sources(spdm_device_secret_lib_tpm
../spdm_device_secret_lib_sample/read_special_cert.c
../spdm_device_secret_lib_sample/set_cert.c
sign.c
${CMAKE_CURRENT_BINARY_DIR}/keys.h
)

if ((ARCH STREQUAL "arm") OR (ARCH STREQUAL "aarch64"))
Expand Down
45 changes: 39 additions & 6 deletions os_stub/spdm_device_secret_lib_tpm/csr.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "library/memlib.h"
#include "internal/libspdm_device_secret_lib.h"
#include "internal/libspdm_common_lib.h"
#include "library/spdm_crypt_lib.h"
#include "library/spdm_crypt_ext_lib.h"
#include "keys.h"

Expand Down Expand Up @@ -116,19 +117,37 @@ bool libspdm_gen_csr_without_reset(uint32_t base_hash_algo, uint32_t base_asym_a
csr_buffer_size = *csr_len;

void *cert;
const uint8_t *x509_ca_cert_der;
void *x509_ca_cert;
size_t x509_ca_cert_len;
size_t cert_size;

if (!libspdm_tpm_get_pvt_key_handle(TPM_RESP_HANDLE, &context)) {
return false;
context = NULL;
cert = NULL;
x509_ca_cert_der = NULL;
x509_ca_cert = NULL;
result = false;

if (!libspdm_tpm_get_pvt_key_handle(LIBSPDM_TPM_HANDLE_RESPONDER_HANDLE_SLOT_0, &context)) {
LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR, "failed to load TPM responder key handle for CSR\n"));
goto cleanup;
}

if (!libspdm_tpm_read_nv(LIBSPDM_TPM_HANDLE_RESPONDER_CERTCHAIN_SLOT_0, &cert, &cert_size)) {
LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR, "failed to read TPM responder cert chain for CSR\n"));
goto cleanup;
}

if (!libspdm_tpm_read_nv(TPM_RESP_CERT, &cert, &cert_size)) {
return false;
if (!libspdm_x509_get_cert_from_cert_chain(cert, cert_size, -1, &x509_ca_cert_der,
&x509_ca_cert_len)) {
LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR, "failed to parse TPM responder cert chain for CSR\n"));
goto cleanup;
}

if (!libspdm_x509_construct_certificate(cert, cert_size, (uint8_t**)&x509_ca_cert)) {
return false;
if (!libspdm_x509_construct_certificate(x509_ca_cert_der, x509_ca_cert_len,
(uint8_t **)&x509_ca_cert)) {
LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR, "failed to construct X509 responder leaf cert for CSR\n"));
goto cleanup;
}

hash_nid = libspdm_get_hash_nid(base_hash_algo);
Expand All @@ -140,12 +159,26 @@ bool libspdm_gen_csr_without_reset(uint32_t base_hash_algo, uint32_t base_asym_a
result = libspdm_gen_x509_csr(hash_nid, asym_nid, pqc_asym_nid,
requester_info, requester_info_length, !is_device_cert_model,
context, subject_name, csr_len, csr_pointer, x509_ca_cert);
if (!result) {
LIBSPDM_DEBUG((LIBSPDM_DEBUG_ERROR, "failed to generate TPM-backed X509 CSR\n"));
}

if (csr_buffer_size < *csr_len) {
LIBSPDM_DEBUG((LIBSPDM_DEBUG_INFO,"csr buffer is too small to store generated csr! \n"));
result = false;
}

cleanup:
if (context != NULL) {
libspdm_asym_free(base_asym_algo, context);
}
if (cert != NULL) {
free(cert);
}
if (x509_ca_cert != NULL) {
libspdm_x509_free(x509_ca_cert);
}

return result;
}

Expand Down
25 changes: 0 additions & 25 deletions os_stub/spdm_device_secret_lib_tpm/keys.h

This file was deleted.

Loading
Loading