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
4 changes: 3 additions & 1 deletion .github/workflows/build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ jobs:
env:
# Standalone builds carry none of the TPM side, pure TCG builds none of
# the standard requester
TPM_SYMS: 'wolfSPDM_(TCG_.*|Nuvoton_.*|Nations_.*|Resp[A-Z].*|.*Psk.*|SetPSK|ConnectTCG|.*TcgClear.*|.*VendorDefined|SetRequesterKey.*|SignHash|GetConnectionHandle|GetFipsIndicator)'
TPM_SYMS: 'wolfSPDM_(TCG_.*|Nuvoton_.*|Nations_.*|Infineon_.*|Resp[A-Z].*|.*Psk.*|SetPSK|ConnectTCG|.*TcgClear.*|.*VendorDefined|SetRequesterKey.*|SignHash|GetConnectionHandle|GetFipsIndicator)'
STD_SYMS: 'wolfSPDM_(GetCapabilities|BuildGetCapabilities|ParseCapabilities|NegotiateAlgorithms|BuildNegotiateAlgorithms|ParseAlgorithms|GetDigests|ParseDigests|GetCertificate|ParseCertificate|ValidateCertChain|SetTrustedCAs|AllowUntrustedCerts|ConnectStandard|.*Measurement.*|.*Challenge.*|M1Start|M1Add|AttestFree|ChunkExchange|ClearExchange|SendData|ReceiveData|EncryptMessage|DecryptMessage|.*MlDsa.*|.*MlKem.*|SetKeyExchangePref)'
strategy:
fail-fast: false
Expand All @@ -96,6 +96,8 @@ jobs:
configure: '--enable-nuvoton'
- variant: nations
configure: '--enable-nations'
- variant: infineon
configure: '--enable-infineon'
- variant: tcg-responder
configure: '--enable-tcg --enable-responder'
- variant: tcg-pure
Expand Down
4 changes: 4 additions & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ endif
if BUILD_NATIONS
libwolfspdm_la_SOURCES += src/vendor/spdm_nations.c
endif
if BUILD_INFINEON
Comment thread
dgarske marked this conversation as resolved.
libwolfspdm_la_SOURCES += src/vendor/spdm_infineon.c
endif
if BUILD_RESPONDER
libwolfspdm_la_SOURCES += src/spdm_responder.c
endif
Expand Down Expand Up @@ -54,6 +57,7 @@ nobase_include_HEADERS = \
wolfspdm/spdm_psk.h \
wolfspdm/spdm_nuvoton.h \
wolfspdm/spdm_nations.h \
wolfspdm/spdm_infineon.h \
wolfspdm/spdm_responder.h \
wolfspdm/options.h

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ make
make
```

Add `--disable-mctp` for a TPM-only build that drops the standard DMTF requester entirely, and `--enable-nuvoton` / `--enable-nations` for vendor TPM commands. Each piece is independent, so you can compose exactly what you want: `--enable-tcg` alone gives just the TCG binding (PSK and the responder stay off until you enable them).
Add `--disable-mctp` for a TPM-only build that drops the standard DMTF requester entirely, and `--enable-nuvoton` / `--enable-nations` / `--enable-infineon` for vendor TPM commands. Each piece is independent, so you can compose exactly what you want: `--enable-tcg` alone gives just the TCG binding (PSK and the responder stay off until you enable them).

## Main Features

Expand Down Expand Up @@ -89,7 +89,7 @@ make check
| `--disable-meas` / `--disable-challenge` | Compile out GET_MEASUREMENTS / CHALLENGE (default: enabled) |
| `--disable-heartbeat` / `--disable-key-update` | Compile out HEARTBEAT / KEY_UPDATE (default: enabled) |
| `--disable-app-data` | Compile out `SendData`/`ReceiveData` MCTP application messages and `Encrypt`/`DecryptMessage` (default: enabled) |
| `--enable-tcg` / `--enable-nuvoton` / `--enable-nations` / `--enable-psk` / `--enable-responder` | TPM side: TCG SPDM binding, vendor commands, PSK and the responder (default: all disabled, so a standalone build carries none of it) |
| `--enable-tcg` / `--enable-nuvoton` / `--enable-nations` / `--enable-infineon` / `--enable-psk` / `--enable-responder` | TPM side: TCG SPDM binding, vendor commands, PSK and the responder (default: all disabled, so a standalone build carries none of it) |
| `--disable-mctp` | Pure TCG build: drops MCTP secured messages and the whole standard requester (needs `--enable-tcg` or a vendor) |
| `--with-wolfssl=PATH` | wolfSSL installation path |
| `CFLAGS=-DWOLFSPDM_DATA_TRANSFER_SIZE=N` | Largest single SPDM message, 42 to 4096 (default 4096). Smaller values shrink the per-message transport buffers; larger messages then travel in CHUNK_SEND/CHUNK_GET pieces when the responder supports chunking |
Expand Down
3 changes: 3 additions & 0 deletions config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@
/* Enable dynamic memory allocation */
#undef WOLFSPDM_DYNAMIC_MEMORY

/* Enable Infineon SPDM vendor commands */
#undef WOLFSPDM_INFINEON

/* Enable Nations SPDM vendor commands */
#undef WOLFSPDM_NATIONS

Expand Down
13 changes: 12 additions & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -258,12 +258,18 @@ AC_ARG_ENABLE([nations],
[enable_nations=$enableval],
[enable_nations=no])

AC_ARG_ENABLE([infineon],
[AS_HELP_STRING([--enable-infineon], [Enable Infineon OPTIGA SLB9678 SPDM vendor commands (default: disabled)])],
[enable_infineon=$enableval],
[enable_infineon=no])
Comment thread
dgarske marked this conversation as resolved.

AC_ARG_ENABLE([responder],
[AS_HELP_STRING([--enable-responder], [Enable the SPDM responder (default: disabled)])],
[enable_responder=$enableval],
[enable_responder=no])

if test "x$enable_nuvoton" = "xyes" || test "x$enable_nations" = "xyes"; then
if test "x$enable_nuvoton" = "xyes" || test "x$enable_nations" = "xyes" \
|| test "x$enable_infineon" = "xyes"; then
enable_tcg=yes
fi
if test "x$enable_nations" = "xyes"; then
Expand Down Expand Up @@ -294,6 +300,9 @@ fi
if test "x$enable_nations" = "xyes"; then
AC_DEFINE([WOLFSPDM_NATIONS], [1], [Enable Nations SPDM vendor commands])
fi
if test "x$enable_infineon" = "xyes"; then
AC_DEFINE([WOLFSPDM_INFINEON], [1], [Enable Infineon SPDM vendor commands])
fi
if test "x$enable_responder" = "xyes"; then
AC_DEFINE([WOLFSPDM_RESPONDER], [1], [Enable the SPDM responder])
fi
Expand All @@ -302,6 +311,7 @@ AM_CONDITIONAL([BUILD_TCG], [test "x$enable_tcg" = "xyes"])
AM_CONDITIONAL([BUILD_PSK], [test "x$enable_psk" = "xyes"])
AM_CONDITIONAL([BUILD_NUVOTON], [test "x$enable_nuvoton" = "xyes"])
AM_CONDITIONAL([BUILD_NATIONS], [test "x$enable_nations" = "xyes"])
AM_CONDITIONAL([BUILD_INFINEON], [test "x$enable_infineon" = "xyes"])
AM_CONDITIONAL([BUILD_RESPONDER], [test "x$enable_responder" = "xyes"])

# Output files
Expand Down Expand Up @@ -334,6 +344,7 @@ echo " TCG: $enable_tcg"
echo " PSK: $enable_psk"
echo " Nuvoton: $enable_nuvoton"
echo " Nations: $enable_nations"
echo " Infineon: $enable_infineon"
echo " Responder: $enable_responder"
echo " wolfSSL: ${WOLFSSL_DIR:-system}"
echo ""
15 changes: 11 additions & 4 deletions docs/API-Reference.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# API Reference

Public APIs are declared in `wolfspdm/spdm.h`, plus `wolfspdm/spdm_tcg.h`,
`spdm_nuvoton.h`, `spdm_nations.h`, `spdm_psk.h`, and `spdm_responder.h` for
the TPM/TCG side.
`spdm_nuvoton.h`, `spdm_nations.h`, `spdm_infineon.h`, `spdm_psk.h`, and
`spdm_responder.h` for the TPM/TCG side.

All APIs return `WOLFSPDM_SUCCESS` (`0`) on success unless documented
otherwise; failures are negative error codes from `wolfspdm/spdm_error.h`.
Expand All @@ -17,8 +17,8 @@ otherwise; failures are negative error codes from `wolfspdm/spdm_error.h`.

## Configuration

- `wolfSPDM_SetIO`
- `wolfSPDM_SetMode` / `wolfSPDM_GetMode` *(`WOLFSPDM_MODE_AUTO` / `_NUVOTON` / `_NATIONS` / `_NATIONS_PSK`)*
- `wolfSPDM_SetIO` / `wolfSPDM_HasIO`
- `wolfSPDM_SetMode` / `wolfSPDM_GetMode` *(`WOLFSPDM_MODE_AUTO` / `_NUVOTON` / `_NATIONS` / `_NATIONS_PSK`, alias `_PSK` / `_TCG`)*. `_TCG` is the TCG binding with no vendor commands; `_AUTO` picks it when no vendor adapter is compiled in.
- `wolfSPDM_SetResponderPubKey`: pin the responder key (96-byte P-384 X‖Y) for cert-less operation
- `wolfSPDM_SetRequesterKeyPair` *(`WOLFSPDM_MUTUAL_AUTH` builds, TCG or TPM profile)*
- `wolfSPDM_SetMaxVersion`: cap the negotiated version (0x12-0x14)
Expand Down Expand Up @@ -88,6 +88,13 @@ otherwise; failures are negative error codes from `wolfspdm/spdm_error.h`.
- `wolfSPDM_Nations_SetOnlyMode`
- `wolfSPDM_Nations_PskSet` / `wolfSPDM_Nations_PskClear` / `wolfSPDM_Nations_PskClearWithVCA`

## Infineon (`wolfspdm/spdm_infineon.h`, `WOLFSPDM_INFINEON`)
Comment thread
dgarske marked this conversation as resolved.

- `wolfSPDM_Infineon_GetStatus`
- `wolfSPDM_Infineon_SetOnlyMode`

The SLB9678 identity flow itself is plain TCG, so it needs no adapter: set `WOLFSPDM_MODE_TCG` and connect. The calls above are the vendor commands on top of it.

## PSK (`wolfspdm/spdm_psk.h`, `WOLFSPDM_PSK`)

- `wolfSPDM_SetPSK`
Expand Down
3 changes: 2 additions & 1 deletion docs/Configuration-and-Macros.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ From `configure.ac`:
| `--enable-tcg` | off | `WOLFSPDM_TCG` | TCG SPDM binding (TPM transport) |
| `--enable-nuvoton` | off | `WOLFSPDM_NUVOTON` | Nuvoton NPCT75x vendor commands (implies `--enable-tcg`) |
| `--enable-nations` | off | `WOLFSPDM_NATIONS` | Nations NS350 vendor commands (implies `--enable-tcg` and `--enable-psk`) |
| `--enable-infineon` | off | `WOLFSPDM_INFINEON` | Infineon OPTIGA SLB9678 vendor commands (implies `--enable-tcg`; PSK stays opt-in) |
| `--enable-psk` | off | `WOLFSPDM_PSK` | SPDM PSK_EXCHANGE/PSK_FINISH (requires `--enable-tcg`) |
| `--enable-responder` | off | `WOLFSPDM_RESPONDER` | SPDM responder (requires `--enable-tcg`) |

Expand Down Expand Up @@ -52,7 +53,7 @@ matching `WOLFSPDM_*` macro. `WOLFSPDM_PROFILE_TPM` implies:
above) and `WOLFSPDM_NO_APP_DATA`.
- `WOLFSPDM_PROFILE_TPM` implies `WOLFSPDM_NO_CERT`, `WOLFSPDM_NO_HEARTBEAT`,
`WOLFSPDM_NO_KEY_UPDATE`, `WOLFSPDM_NO_APP_DATA`.
- `WOLFSPDM_NUVOTON` or `WOLFSPDM_NATIONS` implies `WOLFSPDM_TCG`.
- `WOLFSPDM_NUVOTON`, `WOLFSPDM_NATIONS` or `WOLFSPDM_INFINEON` implies `WOLFSPDM_TCG`.
- `WOLFSPDM_NATIONS` implies `WOLFSPDM_PSK`.
- `WOLFSPDM_TCG` or `WOLFSPDM_PROFILE_TPM` implies `WOLFSPDM_MUTUAL_AUTH`
(requester identity-key API for TCG GIVE_PUB).
Expand Down
2 changes: 1 addition & 1 deletion docs/Getting-Started.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ make check
| `--disable-meas` / `--disable-challenge` | Disables GET_MEASUREMENTS / CHALLENGE |
| `--disable-heartbeat` / `--disable-key-update` | Disables HEARTBEAT / KEY_UPDATE |
| `--disable-mldsa` / `--disable-mlkem` | Forces ML-DSA / ML-KEM off (default auto-follows wolfSSL) |
| `--enable-tcg` / `--enable-nuvoton` / `--enable-nations` / `--enable-psk` / `--enable-responder` | TPM side: TCG SPDM binding, vendor commands, PSK, responder (default: all off) |
| `--enable-tcg` / `--enable-nuvoton` / `--enable-nations` / `--enable-infineon` / `--enable-psk` / `--enable-responder` | TPM side: TCG SPDM binding, vendor commands, PSK, responder (default: all off) |

See [[Configuration and Macros]] for the full option-to-macro mapping and
their implications.
Expand Down
24 changes: 22 additions & 2 deletions src/spdm_context.c
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,14 @@ int wolfSPDM_SetIO(WOLFSPDM_CTX* ctx, WOLFSPDM_IO_CB ioCb, void* userCtx)
return WOLFSPDM_SUCCESS;
}

/* Whether a transport is already installed. A caller that wants to supply a
* default transport needs to know, so it can leave an I/O callback the
* application set alone rather than replacing it. */
int wolfSPDM_HasIO(WOLFSPDM_CTX* ctx)
{
return ctx != NULL && ctx->ioCb != NULL;
}

int wolfSPDM_SetResponderPubKey(WOLFSPDM_CTX* ctx,
const byte* pubKey, word32 pubKeySz)
{
Expand Down Expand Up @@ -260,10 +268,21 @@ int wolfSPDM_SetMode(WOLFSPDM_CTX* ctx, WOLFSPDM_MODE mode)
}

#if !defined(WOLFSPDM_NUVOTON) && !defined(WOLFSPDM_NATIONS) && \
!defined(WOLFSPDM_PSK)
!defined(WOLFSPDM_PSK) && !defined(WOLFSPDM_TCG)
(void)mode;
#endif

#ifdef WOLFSPDM_TCG
/* The TCG binding with no vendor commands, for a part that uses only the
* identity flow of "TPM Communication over SPDM". */
if (mode == WOLFSPDM_MODE_TCG) {
ctx->mode = WOLFSPDM_MODE_TCG;
ctx->connectionHandle = 0;
ctx->fipsIndicator = WOLFSPDM_FIPS_NON_FIPS;
return WOLFSPDM_SUCCESS;
}
#endif

#ifdef WOLFSPDM_NUVOTON
if (mode == WOLFSPDM_MODE_NUVOTON) {
ctx->mode = WOLFSPDM_MODE_NUVOTON;
Expand Down Expand Up @@ -381,7 +400,8 @@ int wolfSPDM_Connect(WOLFSPDM_CTX* ctx)
wolfSPDM_ResetSession(ctx);

#ifdef WOLFSPDM_TCG
if (ctx->mode == WOLFSPDM_MODE_NUVOTON ||
if (ctx->mode == WOLFSPDM_MODE_TCG ||
ctx->mode == WOLFSPDM_MODE_NUVOTON ||
ctx->mode == WOLFSPDM_MODE_NATIONS) {
return wolfSPDM_ConnectTCG(ctx);
}
Expand Down
3 changes: 2 additions & 1 deletion src/spdm_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,8 @@ static WC_INLINE int wolfSPDM_ConstCompare(const byte* a, const byte* b,
static WC_INLINE int wolfSPDM_IsTcgMode(const WOLFSPDM_CTX* ctx)
{
#ifdef WOLFSPDM_TCG
return ctx->mode == WOLFSPDM_MODE_NUVOTON ||
return ctx->mode == WOLFSPDM_MODE_TCG ||
ctx->mode == WOLFSPDM_MODE_NUVOTON ||
ctx->mode == WOLFSPDM_MODE_NATIONS ||
ctx->mode == WOLFSPDM_MODE_NATIONS_PSK;
#else
Expand Down
22 changes: 21 additions & 1 deletion src/spdm_msg.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,19 @@ static const byte kexOpaqueNuvoton[] = {
/* Nations only accepts OpaqueLength=0 */
static const byte kexOpaqueNations[] = { 0x00, 0x00 };
#endif
#ifdef WOLFSPDM_TCG
/* TCG binding version 1.0 in DSP0274 opaque format 1. A part that follows
* the TCG binding and offers no secured message version list of its own
* rejects the standard list above with InvalidRequest. */
static const byte kexOpaqueTcg[] = {
0x10, 0x00, /* OpaqueLength */
0x01, 0x00, 0x00, 0x00, /* one element */
0x00, 0x00, 0x05, 0x00, /* DMTF, no vendor ID */
0x01, 0x01, 0x01, /* SMDataVersion, ID, count */
0x00, 0x10, /* version 1.0 */
0x00, 0x00, 0x00 /* alignment */
};
#endif

static void wolfSPDM_KeyExOpaque(const WOLFSPDM_CTX* ctx,
const byte** opaque, word32* opaqueSz)
Expand All @@ -85,6 +98,12 @@ static void wolfSPDM_KeyExOpaque(const WOLFSPDM_CTX* ctx,
*opaque = NULL;
*opaqueSz = 0;
#endif
#ifdef WOLFSPDM_TCG
if (ctx->mode == WOLFSPDM_MODE_TCG) {
*opaque = kexOpaqueTcg;
*opaqueSz = (word32)sizeof(kexOpaqueTcg);
}
Comment thread
dgarske marked this conversation as resolved.
#endif
#ifdef WOLFSPDM_NUVOTON
if (ctx->mode == WOLFSPDM_MODE_NUVOTON) {
*opaque = kexOpaqueNuvoton;
Expand All @@ -97,7 +116,8 @@ static void wolfSPDM_KeyExOpaque(const WOLFSPDM_CTX* ctx,
*opaqueSz = (word32)sizeof(kexOpaqueNations);
}
#endif
#if !defined(WOLFSPDM_NUVOTON) && !defined(WOLFSPDM_NATIONS)
#if !defined(WOLFSPDM_NUVOTON) && !defined(WOLFSPDM_NATIONS) && \
!defined(WOLFSPDM_TCG)
(void)ctx;
#endif
}
Expand Down
112 changes: 112 additions & 0 deletions src/vendor/spdm_infineon.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/* spdm_infineon.c
*
* Copyright (C) 2006-2026 wolfSSL Inc.
*
* This file is part of wolfSPDM.
*
* wolfSPDM is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfSPDM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

/* Infineon OPTIGA SLB9678 SPDM Functions
*
* Infineon PSK provisioning and configuration commands. Both asymmetric
* and PSK handshakes use the shared protocol code, subject to firmware
* capabilities. Framing uses the shared TCG code in spdm_tcg.c.
*/

#include "spdm_internal.h"

#ifdef WOLFSPDM_INFINEON

#include <wolfspdm/spdm_infineon.h>

/* ----- Infineon PSK-Mode Vendor Commands ----- */

int wolfSPDM_Infineon_GetStatus(WOLFSPDM_CTX* ctx,
WOLFSPDM_INFINEON_STATUS* status)
{
WOLFSPDM_VENDOR_RSP rsp;
int rc;

if (ctx == NULL || status == NULL) {
return WOLFSPDM_E_INVALID_ARG;
}

XMEMSET(status, 0, sizeof(*status));

wolfSPDM_DebugPrint(ctx, "Infineon: GET_STS_\n");

/* SLB9678 accepts GET_STATUS with no payload (Type field omitted) */
rc = wolfSPDM_TCG_VendorCmdClear(ctx, WOLFSPDM_VDCODE_GET_STS,
NULL, 0, &rsp);
if (rc != WOLFSPDM_SUCCESS) {
return rc;
}

wolfSPDM_DebugHex(ctx, "GET_STS_ payload", rsp.payload, rsp.payloadSz);

/* Per TCG spec Table 15 - GET_STATUS_RSP payload:
* [0] SpecMajorVersion, [1] SpecMinorVersion,
* [2] PSKSet (00=NO, 01=YES),
* [3] SPDMOnly (00=DISABLED, 01=ENABLED, 81=PENDING_DISABLE) */
if (rsp.payloadSz < 4) {
return WOLFSPDM_E_FRAMING;
}
status->spdmEnabled = 1;
status->pskProvisioned = (rsp.payload[2] != 0);
status->spdmOnlyLocked = (rsp.payload[3] != 0);
status->spdmOnlyPending = (rsp.payload[3] == 0x81);
wolfSPDM_DebugPrint(ctx, "GET_STS_: v%u.%u PSK=%s SPDMOnly=0x%02x\n",
rsp.payload[0], rsp.payload[1],
status->pskProvisioned ? "YES" : "NO",
rsp.payload[3]);

return WOLFSPDM_SUCCESS;
}

int wolfSPDM_Infineon_SetOnlyMode(WOLFSPDM_CTX* ctx, int lock)
{
byte param[1];
int rc;

if (ctx == NULL) {
return WOLFSPDM_E_INVALID_ARG;
}

if (ctx->state != WOLFSPDM_STATE_CONNECTED) {
return WOLFSPDM_E_NOT_CONNECTED;
}

param[0] = lock ? WOLFSPDM_SPDMONLY_LOCK : WOLFSPDM_SPDMONLY_UNLOCK;

wolfSPDM_DebugPrint(ctx, "Infineon: SPDMONLY %s\n",
lock ? "LOCK" : "UNLOCK");

rc = wolfSPDM_TCG_VendorCmdSecured(ctx, WOLFSPDM_VDCODE_SPDMONLY,
param, sizeof(param));
if (rc != WOLFSPDM_SUCCESS) {
return rc;
}

wolfSPDM_DebugPrint(ctx, "SPDMONLY: Success (Lock=%u)\n", param[0]);
return WOLFSPDM_SUCCESS;
}

#endif /* WOLFSPDM_INFINEON */

Loading
Loading