SPDM
utils.py
SPDM conformance test case utilities.
- LARGE_RESPONSE = 15
The response is bigger than the
DataTransferSizethe requester advertised, so it has to be collected with CHUNK_GET. Carries a Handle.
- NO_PENDING_REQUESTS = frozenset({69})
Defined response when the responder has no encapsulated request outstanding.
- OUT_OF_FLOW_ERRORS = frozenset({1, 4, 5, 11})
ErrorCodes a conformant responder may return when a request that belongs to a secure session, or to a transfer already in progress, is issued on its own. The conformance suite has no way to establish a secure session, so these are a consequence of how the case is driven, not a defect in the responder.
- RESPONSE_TOO_LARGE = 13
The response is bigger than the
MaxSPDMmsgSizethe requester advertised in GET_CAPABILITIES, so it cannot be received at all.
- SPDM_ERROR = 127
RequestResponseCodeof an SPDM ERROR response.
- class TestSetup(steps=None)
Composable SPDM TestSetup step pipeline.
- get_capabilities(*, required_capabilities: dict[str, int] | None = None, **kwargs: Any) TestSetup
Run GET_CAPABILITIES. Skip test if provided capabilities are not met.
- get_version(required_spdm_version: int | None = None) TestSetup
Run GET_VERSION and select a negotiated version.
The test is skipped when no entry in
VERSION.VersionNumberEntrysatisfies the requirement.
- negotiate_algorithms(**kwargs) TestSetup
Run NEGOTIATE_ALGORITHMS using the supplied
kwargs.
- run(dut: DUT) dict[str, Any]
Execute SPDM pipeline. Returns the accumulated context.
- step(action: Callable[[DUT], None]) TestSetup
Add step to SPDM pipeline.
Steps may write into
self.contextto expose values to the main function (e.g. the result of GET_CAPABILITIES).
- UNSUPPORTED_REQUEST = frozenset({7})
Some responders reject a session-only request with UnsupportedRequest rather than SessionRequired. Accepted where the request is issued out of session.
- common_req_alg_struct(spdm_version: int, *, include_pqc: bool = False, **kwargs) list
Generate ReqAlgStruct with all requester supported algorithms set, based on the SPDM version
- common_spdm_test(setup: ~utils.TestSetup = <utils.TestSetup object>, teardown: ~collections.abc.Callable[[~sanblaze.script.dut.DUT], None] | None = None)
Run SPDM TestSetup and TestTeardown
- doe_capability_version(dut) int
Return the device’s PCIe DOE capability version, or skip if it has none.
The DOE transport needs the PCIe Data Object Exchange extended capability. Without it the doe binary exits 9 with “failed to find PCIe ‘Data Object Exchange’ capability”, which is the device not being a candidate for the case rather than a test failure. SBSUPPORT-10273.
- get_capabilities_common_params() dict
Default GET_CAPABILITIES requester flags from SPDM-Responder-Validator.
See spdm_test_case_algorithms_setup_version_capabilities() in spdm_responder_test_3_algorithms.c
- multi_key_conn_rsp(MULTI_KEY_CAP: int, ResponderMultiKeyConn: int) bool | None
Table 38 — MULTI_KEY_CONN_RSP value calculation
- negotiate_algorithms_common_params(spdm_version: int, *, include_pqc: bool | None = None) dict
Generate common NEGOTIATE_ALGORITHIMS parameters based on SPDM version
Based on: SPDM-Responder-Validator/library/spdm_responder_conformance_test_lib/spdm_responder_test_3_algorithms.c
NEGOTIATE_ALGORITHMS {SPDMVersion=NegotiatedVersion, …}
Code=E3h(NEGOTIATE_ALGORITHMS) NumAlgStruct=4 (NumAlgStruct=6 for SPDM 1.4+ with PQC) Length=48 (Length=56 for SPDM 1.4+ with PQC) MeasureSpec=1h OtherParamsSupport=2h BaseAsymAlgo=FFFh BaseHashAlgo=7Fh ExtAsymCount=0 ExtHashCount=0 ReqAlgStruct=02207F00,03200F00,0420FF0F,05200100 (+0620FF7F00,07200700 for SPDM 1.4+ with PQC)
- require_response(result: dict[str, Any], request_name: str, response_name: str = 'response') Any
Return the parsed response, failing the case when there is none.
A responder that answers nothing at all leaves
result['data']unset, so every assertion that reads the message raisesAttributeErroronNoneand the case ends in Warning with a traceback instead of a verdict. Fail it with the transport’s reason instead.Use this where the case does not already stop on a failed
check_result– typically the ERROR-expecting cases, which passfail_type='notify'because the request under test is meant to fail.- Parameters:
result (dict) – The dictionary returned by the SPDM API call.
request_name (str) – Request that was sent, e.g.
'GET_CSR'. Used in the log message.response_name (str) – What the case expected back, e.g.
'ERROR(VersionMismatch)'.
- Return type:
The parsed response message.
- resolve_large_response(dut: DUT, result: dict[str, Any], request_name: str, response_name: str, structure: str) dict[str, Any]
Return the response, collecting it with CHUNK_GET when it is too large.
A response bigger than the
DataTransferSizethe requester advertised is not returned directly. The responder answers ERROR(LargeResponse) with a Handle, and the response has to be fetched with CHUNK_GET; this helper does that and hands back the reassembled message so the case can validate it as if it had arrived in one piece.A response bigger than the advertised
MaxSPDMmsgSizecannot be received at all, and ERROR(ResponseTooLarge) is the conformant answer. There is then noresponse_nameto validate, so the case is Skipped rather than Failed. Certificate chains signed with a post-quantum algorithm are the case that reaches this in practice.Anything else is returned untouched, for the caller to check as usual.
- Parameters:
result (dict) – The dictionary returned by the SPDM API call.
request_name (str) – Request that was sent, e.g.
'SLOT_MANAGEMENT'. For log messages.response_name (str) – Response the case validates, e.g.
'SLOT_MANAGEMENT_RESP'.structure (str) – Name of the response template the reassembled bytes are parsed with.
- skip_on_expected_error(result: dict[str, Any], request_name: str, response_name: str, expected_errors, note: str | None = None) None
Skip the case when the responder answers a request with a legal ERROR.
Several SPDM messages are only meaningful inside a secure session or a transfer that is already under way. The conformance suite issues them on their own, so a conformant responder is entitled to answer ERROR instead of the response under test. There is then no
response_nameto validate and the case is Skipped; any other failure is still a failure.- Parameters:
result (dict) – The dictionary returned by the SPDM API call.
request_name (str) – Request that was sent, e.g.
'CHUNK_GET'. Used in log messages.response_name (str) – Response the case validates, e.g.
'CHUNK_RESPONSE'.expected_errors (set of int) – ErrorCodes accepted for this case, e.g.
OUT_OF_FLOW_ERRORS.note (str) – Optional extra sentence logged with the skip message.
- spdm_test_ctx(dut: DUT) dict[str, Any]
Return TestSetup context from
@common_spdm_test(...).Scripts can use this with
def main(dut)somain(dut)inif __name__ == '__main__'keeps working without actxparameter.