[RFC] SPDM attestation E2E findings from Renode testing

Gary Beihl garybeihl at microsoft.com
Thu Apr 2 08:35:21 AEDT 2026


Hello everyone,

Following up on my earlier ComponentIntegrity route email - I've completed end-to-end SPDM attestation testing using Renode (emulated AST2600 running a full OpenBMC image with spdmd + bmcweb). The Renode SpdmResponderDevice functions as an SPDM 1.1/1.2 responder over MCTP-serial and the tests cover the full flow:

MCTP discovery → VCA → GET_DIGESTS → GET_CERTIFICATE → CHALLENGE  → D-Bus property updates → Redfish ComponentIntegrity

I cherry-picked the MCTP transport series (80355, 80358, 80311, 80267, through 80359) and built against libspdm. The tests cover 14 scenarios including successful attestation, wrong-key rejection, unreachable devices, multi-endpoint, SPDM 1.1-only devices, version mismatch, and mid-flow disconnects.

To get these E2E tests passing, the following changes were needed on top of the current patchsets:

(a) Missing CHALLENGE step (affects 80359: spdmd.cpp) [Security]

The VCA flow does GET_VERSION → GET_CAPABILITIES →  NEGOTIATE_ALGORITHMS → GET_DIGESTS → GET_CERTIFICATE, but stops before
CHALLENGE. Without CHALLENGE, the responder never proves  possession of its private key - a compromised certificate would pass attestation. Adding libspdm_challenge() after  GET_CERTIFICATE completes the proof-of-possession verification.

(b) D-Bus path and version extraction (affects spdm_dbus_responder.cpp, spdmd.cpp)

ComponentIntegrity D-Bus path uses CamelCase: /xyz/openbmc_project/ComponentIntegrity/ but phosphor-dbus-interfaces and bmcweb expect snake_case: /xyz/openbmc_project/component_integrity/

Also, version extraction from connection_info.version needs  SPDM_VERSION_NUMBER_SHIFT_BIT before extracting major/minor  nibbles.

(c) Shared AF_MCTP socket (affects 80311: mctp_helper.hpp)

Only one socket can bind to (MCTP_ADDR_ANY, MCTP_TYPE_SPDM).  When spdmd attests multiple endpoints sequentially, the second   MctpIoClass::createSocket() fails with EADDRINUSE. The fix is a process-lifetime shared socket (singleton pattern), draining stale responses between endpoint attestations with recv(MSG_DONTWAIT).

Also needed: SO_RCVTIMEO on the socket so recvfrom() doesn't block forever when a device is unreachable or disconnects mid-flow.

(d) Certificate verification callback (affects 80359: libspdm_mctp_transport.cpp)

libspdm_get_certificate() fails without a registered cert chain verification callback, and the current code doesn't register one. For initial bring-up, a trust-on-first-use callback that accepts any valid chain works; production should verify against a provisioned trust anchor.

Also needed in configureContext():
  - Register all supported SPDM versions (1.0/1.1/1.2) to enable negotiation (current code sets only one version)
  - Set requester capability flags (CERT_CAP | CHAL_CAP)
  - Register measurement hash algorithm

I'm happy to submit these as follow-up Gerrit changes on top of the series, or if preferred, I can provide the diffs to fold into the existing patchsets. The Renode E2E test suite (14 scenarios) is also available if it would be useful for CI validation.

The bmcweb ComponentIntegrity routes are up for review at [1] and consume these D-Bus interfaces.

[1] https://gerrit.openbmc.org/c/openbmc/bmcweb/+/88828

Best regards,
Gary Beihl
Firmware Engineering
Microsoft Corporation

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.ozlabs.org/pipermail/openbmc/attachments/20260401/6dd59d89/attachment.htm>


More information about the openbmc mailing list