Skip to content

transport: storage: add support for SPDM over the storage binding (DSP0286) #2827

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

twilfredo
Copy link
Contributor

This series adds libspdm transport support for SPDM over Storage Binding Specification [1]. This allows for example NVMe or SCSI devices that conform to [1] to communicate with a host requester using the storage transport medium as defined in [1].

[1] https://www.dmtf.org/sites/default/files/standards/documents/DSP0286_1.0.0WIP90.pdf

@twilfredo
Copy link
Contributor Author

@alistair23

@twilfredo twilfredo force-pushed the wilfred/add-trans-storage-05.9 branch 7 times, most recently from 8ab52c6 to 7a14888 Compare September 5, 2024 04:21
@steven-bellock
Copy link
Contributor

A couple of high level comments.

  1. This pull request will not be able to be merged until DSP0286 has been published, but that looks to be soonish.
  2. The WDC-authored files have a WDC copyright. I believe (not 100 % sure) that per the "DMTF Members’ Software Submission Policy" it should have the DMTF copyright. If you want to keep the WDC copyright we can talk to the DMTF open source folks to clarify things.

@twilfredo twilfredo force-pushed the wilfred/add-trans-storage-05.9 branch from 7a14888 to c63269b Compare September 6, 2024 04:50
@twilfredo
Copy link
Contributor Author

twilfredo commented Sep 6, 2024

A couple of high level comments.

1. This pull request will not be able to be merged until DSP0286 has been published, but that looks to be soonish.

Yeah that sounds good, just wanted to get comments early on

2. The WDC-authored files have a WDC copyright. I believe (not 100 % sure) that per the "DMTF Members’ Software Submission Policy" it should have the DMTF copyright. If you want to keep the WDC copyright we can talk to the DMTF open source folks to clarify things.

I've updated the license header with an author tag, is that sufficient? Diff: https://github.com/DMTF/libspdm/compare/7a14888587717c8a16e7390388fd39629e7a7076..c63269b162af091a35ef282052980087a378c68f

@steven-bellock
Copy link
Contributor

Presumably authorship is recorded in the commit log, but if you want to put it in the file itself:

/**
 *  Copyright Notice:
 *  Copyright 2024 DMTF. All rights reserved.
 *  License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md
 **/
 
 /**
  *  Author: Wilfred Mallawa <[email protected]>
  *          Alistair Francis <[email protected]>
  **/

@twilfredo twilfredo force-pushed the wilfred/add-trans-storage-05.9 branch 3 times, most recently from e50ff9f to 8fc10b2 Compare September 9, 2024 01:34
@jyao1
Copy link
Member

jyao1 commented Sep 11, 2024

Usually, the implementation for WIP should NOT be posted to main, but a WIP specific branch
For example, StorageBinding_WIP, in this case.

The WIP branch can be merged into main, after the WIP spec becomes official standard.

@twilfredo
Copy link
Contributor Author

twilfredo commented Sep 11, 2024

Usually, the implementation for WIP should NOT be posted to main, but a WIP specific branch For example, StorageBinding_WIP, in this case.

The WIP branch can be merged into main, after the WIP spec becomes official standard.

Okay noted, are you happy to keep this up for now? since review is in progress.

@jyao1
Copy link
Member

jyao1 commented Sep 11, 2024

Okay noted, are you happy to keep this up for now? since review is in progress.

That is fine. We can keep reviewing and address all feedback in this PR.

Whenever you think it is done and ready for merge, you can switch to branch merge request.

@twilfredo twilfredo force-pushed the wilfred/add-trans-storage-05.9 branch 5 times, most recently from 7d5dfea to 5569c6c Compare October 2, 2024 02:35
@jyao1
Copy link
Member

jyao1 commented Nov 1, 2024

@twilfredo , do you want to keep it in PR? or do you want to push to a branch, and keep updating the branch?

I am OK either way. But I just feel a branch might be more helpful.

@twilfredo
Copy link
Contributor Author

@twilfredo , do you want to keep it in PR? or do you want to push to a branch, and keep updating the branch?

I am OK either way. But I just feel a branch might be more helpful.

I'll stick to the PR is that's okay with everyone. I'm just waiting for the spec to be ratified so I can address all the changes in one go.

Add support for bswap16 and 32. Also rename the existing
`libspdm_le_to_be_64` to `libspdm_byte_swap_64` for consistency.

Signed-off-by: Wilfred Mallawa <[email protected]>
@twilfredo twilfredo force-pushed the wilfred/add-trans-storage-05.9 branch from 5569c6c to 9ca12b3 Compare November 27, 2024 06:23
@twilfredo
Copy link
Contributor Author

What is the correct way to generate a seed for the fuzzing tests to go here unit_test/fuzzing/seeds mapping to the respective tests.

As requested by @jyao1 I have added some unit tests to test the storage transport api, but I'm unsure about how the seeds are generated (hence why some of the the CI is failing also).

@twilfredo twilfredo force-pushed the wilfred/add-trans-storage-05.9 branch 3 times, most recently from 1e2c501 to a2c713e Compare November 29, 2024 02:36
alistair23 and others added 4 commits November 29, 2024 13:21
As defined by DSP0826, add support for SPDM storage transport. The
transport layer uses a virtual storage header that encapsulates SPDM
requests to allow the caller to generate the required parameters
for a storage SPDM request. SPDM responses are not transport encoded,
with this header, instead just the message is returned.

Signed-off-by: Wilfred Mallawa <[email protected]>
Signed-off-by: Alistair Francis <[email protected]>
This allows transports such as Storage (DSP0286) to determine if the
next response is protected via secured messages. Unlike other transport
layers, storage does not encode the message type in a response header.
As such, the requester must track the expected type.

The issue [1] discusses this implementation requirement in further
detail with regards to DSP0286.

[1] DMTF/SPDM-WG#3520

Signed-off-by: Wilfred Mallawa <[email protected]>
Signed-off-by: Alistair Francis <[email protected]>
Signed-off-by: Wilfred Mallawa <[email protected]>
@twilfredo twilfredo force-pushed the wilfred/add-trans-storage-05.9 branch from a2c713e to 10033fd Compare November 29, 2024 03:22
@twilfredo
Copy link
Contributor Author

ping!

@jyao1
Copy link
Member

jyao1 commented May 29, 2025

@twilfredo , would you please:

  1. fix CI failure.
  2. Check if it aligns to latest published DSP0286

@twilfredo
Copy link
Contributor Author

@twilfredo , would you please:

1. fix CI failure.

2. Check if it aligns to latest published [DSP0286](https://www.dmtf.org/sites/default/files/standards/documents/DSP0286_1.0.0.pdf)

Good to see the spec being released! and yeah I will work on getting this upto date. Thanks!

uint16_t security_protocol_specific;
bool inc_512;
uint32_t length;
} storage_spdm_transport_header;
Copy link
Member

@jyao1 jyao1 May 29, 2025

Choose a reason for hiding this comment

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

Which spec section the storage_spdm_transport_header is following?

If I look at DSP0286, Figure 5 — SCSI SECURITY PROTOCOL OUT CDB, then there is reserved between inc_512 and length.
Also, there is SECURITY PROTOCOL OUT before security_protocol
There are Reserved and CONTROL after length.

I guess you are following Table 17 — SECURITY PROTOCOL OUT field definitions. But Table 17 just defines the meaning, not the real structure layout.

Also Table 17 is also for SCSI, what about NVME (table 13) and ATA (table 22)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was defined to allow upper level applications that use libspdm to extract the needed information to make storage API calls. That is these fields are required when using the NVMe/SCSI/ATA api to interact with devices. It is not part of the SPDM message.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The doc is perhaps misleading, in that by "SPDM Storage transport binding header for request encoding as defined by DSP0286" I was referring to the fields.

Copy link
Member

@jyao1 jyao1 May 29, 2025

Choose a reason for hiding this comment

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

Current storage_spdm_transport_header is only align to SCSI (table 17). What about NVME (table 13) and ATA (table 22)?

Also, if it is NOT align to structure layout, then there is no need to put pack(1) around it. That is big misleading to me.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For NVME and ATA, this header still contains the relevant information. For example:
For NVMe, SPS1/0 will be in security_protocol_specific and inc 512 shall be ignored.
For ATA, SP SPECIFIC is again in security_protocol_specific. Allocation length will at minimum length but that is upto a higher layer decide. inc 512 shall be ignored.

This way we have a common header, and an upper layer can extract the necessary information for NVMe/SCSI and ATA as required.

Copy link
Member

Choose a reason for hiding this comment

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

I studied the code.

In the real device driver, the POC removes the storage_spdm_transport_header and adds a real device specific header, such as SCSI or NVMe, then send it out.

For receive, I noticed that the POC code uses encode() in receive() function. For example:
NVMe: https://github.com/twilfredo/spdm-utils/blob/5be6539fe483f489c720965eb805f227fd1784f0/src/nvme.rs#L484. It uses libspdm_transport_storage_encode_message for nvme_security_receive_args receive function.
SCSI: https://github.com/twilfredo/spdm-utils/blob/5be6539fe483f489c720965eb805f227fd1784f0/src/scsi.rs#L422. It uses libspdm_storage_encode_message for gen_libspdm_response receive function.

It seems that the current POC code uses storage_spdm_transport_header structure be a generic fake header to pass the information between libspdm and the real device driver, when send or receive.

Please let me know if that is right?

Copy link
Contributor Author

@twilfredo twilfredo Jun 4, 2025

Choose a reason for hiding this comment

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

It seems that the current POC code uses storage_spdm_transport_header structure be a generic fake header to pass the information between libspdm and the real device driver, when send or receive

Essentially yes, we are using libspdm to publicly define this virtual header at the transport layer (as libspdm is the only current implementer of DSP0286). As you noticed, the data from this structure is then used to generate the real device storage API (SCSI/NVMe) specific headers.

Note that, it is also used to encode management commands using libspdm_transport_storage_encode_management_cmd(). Which will generate the SPDM specific datum and pass that over to the device driver above, similarly to above, then used to generate the real device storage API (SCSI/NVMe) specific headers.

Copy link
Member

@jyao1 jyao1 Jun 4, 2025

Choose a reason for hiding this comment

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

Thanks to confirm that. Here is my thought:

We have 2 directions:

  • define one common virtual header for all storage devices.
  • define multiple device specific virtual headers for NVMe, SCSI, ATA to match the NVMe, SPC-6, ATA8-ACS spec.

Since they do have common attribute {security_protocol, security_protocol_specific_data}, I would prefer one common virtual header, like what you have proposed in the code.
I think we can simply use following code:

#pragma pack(1)
typedef struct {
    uint8_t security_protocol;
    uint16_t security_protocol_specific_data;
} spdm_storage_transport_virtual_header_t;
#pragma pack()

Now, there are several opens:

  1. do we need length field?
    I think it is NOT needed, because we already have message_size in the parameter. The length of the final data can be determined by (message_size - sizeof(spdm_storage_transport_virtual_header_t)).
    Adding length here seems redundant to me.

  2. do we need inc_512 field?
    I think it is NOT needed, because inc_512 is SCSI specific way to handle message size internally. It is not common, and it should be invisible to outside.

  3. Another thing, I am not sure if we need storage specific field, e.g. NVMe Security Specific Field (NSSF), SCSI Control field, ATA Device field. If that is needed, then we can add descriptor_types and device_specific_data;

#pragma pack(1)
typedef struct {
    uint8_t device_type; // Table 9 — SPDM Storage Secured Message descriptor types (NVME=1, SCSI=2, ATA=3)
    uint8_t security_protocol;
    uint16_t security_protocol_specific_data;
    uint32_t device_specific_data_size; // device specific. Currently, it should be 0.
    uint8_t device_specific_data[]; // device specific. Currently, it should be N/A.
} spdm_storage_transport_virtual_header_t;
#pragma pack()

Please let me know your thought.

Copy link
Contributor Author

@twilfredo twilfredo Jun 4, 2025

Choose a reason for hiding this comment

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

Thanks for the suggestions. I agree with having a single virtual header, this would simplify the logic.

  1. Yeah I think we could omit this.
  2. Agreed
  3. I am not too sure, I will try to implement it come back with a better idea. My initial thought is, we can handle it in libspdm and it seems only relevant for secured messages so it likely doesn't need to be defined in this header.

So perhaps the below should suffice.

#pragma pack(1)
typedef struct {
    uint8_t security_protocol;
    uint16_t security_protocol_specific_data;
} spdm_storage_transport_virtual_header_t;
#pragma pack()

Copy link
Member

Choose a reason for hiding this comment

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

Yes, let's start from this simple version.

sec_trans_header_size = is_request_message ?
sizeof(storage_spdm_transport_header): 0;
/* DSP0286 Specifies 4 Reserved bytes at the start of a secured message */
sec_trans_header_size += sizeof(uint32_t);
Copy link
Member

Choose a reason for hiding this comment

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

Please help me understand where is the code to handle Descriptor in Table 7 — SPDM Storage Secured Message data buffer field descriptions.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That will need to be added. I have missed that.

@jyao1
Copy link
Member

jyao1 commented Jun 5, 2025

@twilfredo , the next release (Q2) will be end of June. Please let us know if this can be completed at that time windows.

@twilfredo
Copy link
Contributor Author

twilfredo commented Jun 6, 2025

@twilfredo , the next release (Q2) will be end of June. Please let us know if this can be completed at that time windows.

As an update: I have all of the changes discussed above added and tested with the respective modifications to the NVMe driver (in spdm-utils), things are working in emulation (QEMU).

Just need to support and test the SPDM Storage Secured Message Descriptors. So hopefully I will have something ready next week and we can try to get this out before the next release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants