SPDM(Security Protocol for Data Mobility)是一种安全协议,用于保护数据在移动存储设备之间的安全性和完整性。它是由 Trusted Computing Group (TCG) 的 Storage Work Group 开发的一个规范,旨在为存储设备提供一个安全的数据传输和存储环境。SPDM 协议的目标是确保数据在设备之间移动时不会被未授权访问、篡改或泄露。
SPDM 协议的主要特点和功能包括:
设备认证:SPDM 允许设备相互验证对方的身份,确保数据传输是在可信的设备之间进行。这可以通过证书、密钥交换和挑战-响应机制来实现。
数据加密:为了保护数据在传输过程中的安全,SPDM 支持对数据进行加密。这可以防止数据在传输过程中被窃听或篡改。
数据完整性:SPDM 使用哈希函数和数字签名来确保数据的完整性。接收方可以验证数据在传输过程中是否被篡改。
安全启动:SPDM 可以确保设备在启动时只加载未被篡改的软件和固件,从而防止恶意软件的运行。
访问控制:SPDM 支持基于角色的访问控制,确保只有具有适当权限的用户和设备能够访问数据。
审计和日志记录:SPDM 支持审计功能,可以记录安全事件和操作,以便于事后分析和调查。
兼容性和互操作性:SPDM 被设计为与现有的存储和网络技术兼容,以确保不同厂商的设备能够互操作。
SPDM消息传递协议在两个endpoints之间定义了一个request-response消息传递模型,以执行SPDM消息交换中概述的SPDM message exchanges。
Requester应在发出任何其他请求消息之前发出GET_VERSION、GET_CAPABILITIES和NEGOTIATE_ALGORITHMS请求消息。 这三个请求消息在Responster应答以后,Requester可以保存起来,以便在重置后Requester可以跳过这些请求。
1.SPDM connection model
在SPDM中,当一个端点向另一个SPDM端点发送GET_VERSION请求时,一对SPDM端点之间的通信就开始了。启动通信的SPDM端点称为Requester。接收GET_VERSION并提供VERSION响应的端点称为Responder。一对请求者和响应者之间的通信称为connection。请求者和响应者之间可以存在一个或多个连接。不同的连接可能存在于相同的传输或不同的传输上。当同一传输上有多个连接时,传输负责为SPDM端点提供机制,以区分一个或多个连接。当传输不提供这种机制时,在请求者和响应者之间应该通过该连接建立一个连接上。
SPDM端点既可以是请求者,也可以是响应者。作为请求者,SPDM端点可以与一个或多个响应者通信。同样作为响应者,SPDM端点可以响应多个请求者。SPDM连接模型认为这些通信中的每一个都是单独的连接。例如,一对SPDM端点可以互为请求者和响应者。因此,SPDM连接模型认为这是两个独立的连接。
在一个连接中,请求者可以建立一个或多个secure sessions。这些安全会话被认为是同一连接的一部分。安全会话可以在任何时候终止,并且可以建立额外的会话。GET_VERSION可以重置连接和与该连接相关的所有上下文,包括但不限于会话密钥和会话id等信息。但是,这并不被认为是连接的终止。连接可能由于外部事件而终止,例如设备Reset或在SPDM端点上实现的错误处理策略,但是这些场景不在本规范的范围之内。可以使用本规范范围之外的机制终止连接。
2.SPDM bits-to-bytes mapping
所有的SPDM字段,无论大小或者端序如何,都可以将最高bit位映射到最高byte赋值域。并按顺序递减。
3.Generic SPDM message format
Byte offset | Bit offset | Size(bits) | Field | Description |
0 | [7:4] | 4 | SPDM Major Version | SPDM规范主要版本 |
0 | [3:0] | 4 | SPDM Minor Version | SPDM规范小版本 |
1 | [7:0] | 8 | Request Response Code | 0x00到0x7F表示响应码,0x80到0xFF表示请求代码。在请求消息中,该字段被认为是请求代码。在响应消息中,该字段被认为是响应代码. |
2 | [7:0] | 8 | Param1 | 特定于Request Response Code的参数1 |
3 | [7:0] | 8 | Param2 | 特定于Request Response Code的参数2 |
4 | See the description | Variable | SPDM message payload | 应该是零个或多个特定于请求响应的字节代码。 |
4.SPDM request codes
所有与SPDM兼容的实现都应使用SPDM请求代码。
注意:如果发送了一个不支持的request codes,ERROR response 的ErrorCode应该设置为UnsupportedRequest。
5.SPDM response codes
SPDM操作成功完成后,将返回指定的响应消息。在SPDM操作未成功完成时,应该返回ERROR响应消息。
6. Requirements for Requesters
请求方不得在一个连接中对同一响应方有多个未完成的请求,但以下情况除外:
- 正如GET_VERSION请求和VERSION响应消息子句所描述的,请求者可以发出一个GET_VERSION到一个响应器,以便随时重置连接,即使请求者对同一响应器有现有的未完成请求。
- 在大型SPDM消息传输机制中,单个大型SPDM请求消息和单个CHUNK_SEND请求可以同时处理。
未完成的请求的定义:请求消息已经开始传输,相应的响应还没有被完全接收,并且请求不是Timing Requirements中描述的重试。
如果请求方向响应方发送了一个请求,并希望向同一响应方发送后续请求,请求方需要等待完成以下操作任一操作后,才能发送后续的子请求:
- 接收响应者对未完成请求的响应。
- 等待响应超时。
- 从传输层接收请求消息传输失败的指示。
- 请求程序遇到内部错误或重置。
- 请求者发送GET_VERSION来重新初始化会话
7. Requirements for Responders
响应器不需要同时处理多个请求消息,即使是跨连接,但有以下例外情况:
- 正如GET_VERSION请求和VERSION响应消息子句所描述的,请求者可以发出一个GET_VERSION到响应者,以便随时重置连接,即使请求者对同一响应者有现有的未完成请求。
- 在大型SPDM消息传输机制中,单个大型SPDM请求消息和单个CHUNK_SEND请求可以同时处理。
- Retries可以多次发送到相同Responder,作为Timing requirements定义。
如果Responder没有准备好接受新的请求消息或同时处理来自同一请求者的多个未完成请求,则应响应ErrorCode=Busy的ERROR消息或默默地丢弃请求消息。
如果响应者正在处理来自请求者的请求消息,响应者可以用ErrorCode=Busy的ERROR消息进行响应。
如果一个响应者支持与多个请求者同时通信,那么响应者应该通过使用本规范范围之外的机制来区分请求者。
8. SPDM messages
SPDM消息可以分为以下几类,它们支持请求者和响应者之间安全交换的不同方面:
- Capability discovery and negotiation(能力发现和协商)
- Responder identify authentication(响应者身份验证)
- Measurement(测量)
- Key agreement for secure-channel establishment(建立安全通道的秘钥协议)
9. Capability discovery and negotiation
所有的Requesters和Responders应该支持GET_VERSION,GET_CAPABILITIES,NEGOTIATE_ALGORITHMS.
下图展示该流程图:
VCA(Version-Capabilities-Algorithms)应该是请求者和响应者最后一次交换协商确认下的结果。
如果两个端点不支持使用PSK(Pre-Shared Key, 预共享密钥)选项建立会话密钥,或者如果两个端点支持PSK,但协商的功能和算法没有与PSK一起提供给两个端点,则请求者应发出GET_VERSION、GET_CAPABILITIES和NEGOTIATE_ALGORITHMS来构建VCA。
如果响应者支持缓存协商状态(CACHE_CAP=1),则请求者可能不会发出请求
GET_VERSION, GET_CAPABILITIES和NEGOTIATE_ALGORITHMS。在这种情况下,请求方和响应方应将最新的VCA存储为协商状态的一部分。
如果两个端点支持使用PSK建立会话密钥,并且协商的功能和算法(VCA的C和A)与PSK一起提供给两个端点,则请求方不应该发出GET_CAPABILITIES和NEGOTIATE_ALGORITHMS。
10. GET_VERSION request and VERSION response messages
该请求消息将检索端点SPDM的版本信息。在所有未来的SPDM版本中,GET_VERSION和VERSION响应消息将向后兼容所有早期版本。
请求方应该通过发送一个GET_VERSION请求消息,将SPDM Version字段的值设置为0x10来开始discovery过程。所有响应者应始终支持主版本为0x1的GET_VERSION请求消息,并提供包含所有支持版本的version响应。
请求方应查阅VERSION响应以选择一个受支持的通用版本,该版本应是受支持的最新通用版本。请求方应在后续所有其他请求的通信中使用选定的版本。在收到成功的VERSION响应并确定双方支持的通用版本之前,请求方不得发出其他请求。
Responder不能用ErrorCode=ResponseNotReady的错误消息来响应GET_VERSION请求消息。所选版本应为紧接在GET_version请求之后的请求SPDMVersion字段中的版本(GET_VERSITION除外)。如果请求者在请求中使用的版本与选择的版本不同,响应者应该返回ErrorCode=VersionMismatch的ERROR消息,或者默默地放弃请求。
请求者可以在任何时候向响应者发出GET_VERSION请求消息,这可以作为请求者的需求允许由于内部错误或重置,而要求请求者重新启动协议的场景。
在接收到有效的GET_VERSION请求后,Responder将使与来自同一请求者的所有先前请求相关的状态和数据无效。请求者和响应者之间的所有活动会话都将终止,这些会话的信息(如会话密钥和会话id)不应再使用。此外,此消息应清除先前在请求方及其相应响应方中的协商状态(如果有的话)。无效的GET_VERSION请求会导致响应者返回一个错误给请求者,这不会影响会话状态。无效GET_VERSION请求导致的错误消息,应该将SPDMVersion字段的值设置为0x10。
在为GET_VERSION请求发送版本响应后,如果Responder完成了硬件或固件测量的运行时代码或更改配置,并且更改已经生效,则响应器将静默地丢弃会话外接收的任何请求,或者对会话外接收的任何请求响应ErrorCode=RequestResynch错误消息,直到接收到GET_VERSION请求。
Byte offset | Field | Size(bytes) | Description |
---|---|---|---|
0 | SPDMVersion | 1 | Shall be 0x10 (V1.0) |
1 | RequestResponseCode | 1 | Shall be 0x84 = GET_VERSION. |
2 | Param1 | 1 | Reserved. |
3 | Param2 | 1 | Reserved. |
Byte offset | Field | Size(bytes) | Description |
---|---|---|---|
0 | SPDMVersion | 1 | Shall be 0x10(V1.0) |
1 | RequestResponseCode | 1 | Shall be 0x04 = VERSION |
2 | Param1 | 1 | Reserved. |
3 | Param2 | 1 | Reserved. |
4 | Reserved | 1 | Reserved. |
5 | VersionNumberEntryCount | 1 | 支持的版本数量(=n) |
6 | VersionNumberEntry1:n | 2*n | 16-bit version entry. Each entry should be unique. |
Version Number Entry 定义如下:
11.GET_CAPABILITIES request and CAPABILITIES response messages
此请求消息将检索端点的SPDM功能,Responder 不能用错误消息响应GET_CAPABILITIES请求消息ErrorCode = ResponseNotReady.
为了正确地支持SPDM消息的传输,请求方和响应方应指明两种缓冲区大小:
1. 一个用于接收单个SPDM传输,称为DataTransferSize;
2.一个用于指示它们处理单个组装收到的SPDM消息的最大内部缓冲区大小,称为MaxSPDMmsgSize;
此外,请求者和响应者可以有一个传输缓冲区。发送缓冲区大小不会传递给其他SPDM端点,但可以小于接收SPDM端点的DataTransferSize。
请求者和响应者都应支持发送和接收缓冲区的最小大小,以成功传输SPDM消息。最小大小称为MinDataTransferSize。对于这个版本的规范,MinDataTransferSize应该是42。该值是该列表中最大的SPDM消息的大小(以字节为单位)。
只有当请求者和响应者都支持大型SPDM消息传输机制(CHUNK_CAP=1)时,才允许具有扩展功能的GET_CAPABILITIES请求(Param1的第0位设置为1)。如果GET_CAPABILITIES请求将Param1的Bit 0设置为1,则响应者将使用来自请求的DataTransferSize和MaxSPDMmsgSize的值来传输CAPABILITIES响应。响应者可以通过发送ErrorCode= largerresponse的ERROR消息来报告它需要以较小的传输传输响应。如果GET_CAPABILITIES请求将Param1的0位设置为1,并且响应者不支持大SPDM消息传输机制(CHUNK_CAP=0),则响应者应发送ErrorCode=InvalidRequest的错误消息。
Byte offset | Field | Size(bytes) | Description |
---|---|---|---|
0 | SPDMVersion | 1 | Shall be the SPDMVersion,使用GET_VERSION中协商的版本。 |
1 | RequestResponseCode | 1 | Shall be 0xE1 = GET_CAPABILITIES. |
2 | Param1 | 1 | Bit 0 : 如果设置为1,Responder应该返回支持的Algorithms block。 如果请求方不支持大SPDM消息传输机制(CHUNK_CAP=0),则该位应为0。 Bit 1:7 Reserved. |
3 | Param2 | 1 | Reserved. |
4 | Reserved | 1 | Reserved. |
5 | CTExponent | 1 | 为以2为底的指数,用于计算CT,单位为us。 |
6 | Reserved | 2 | Reserved. |
8 | Flags | 4 | See Table13 |
12 | DataTransferSize | 4 | 该字段以字节为单位指示请求方接收一条小于或等于该字段值的完整SPDM消息的最大缓冲区大小。该字段的值应等于或大于 MinDataTransferSize。DataTransferSize应该不包括传输头、加密头和MAC。该字段帮助SPDM消息的发送方知道是否需要使用 大型SPDM消息传输机制。 |
16 | MaxSPDMmsgSize | 4 | 如果请求方支持大型SPDM消息传输机制,则该字段应以字节为单位指示用于重新组装单个完整的大型SPDM消息的请求方内部缓冲区的最大大小。该字段必须大于或等于DataTransferSize。当在多个块中传输大型SPDM消息时,此缓冲区大小是最有用的,因为它告诉发送方是否有足够的内存容纳完全重新组装的SPDM消息。如果请求方不支持大SPDM报文传输机制,则该字段等于请求方的DataTransferSize |
Byte offset | Field | Size(bytes) | Description |
---|---|---|---|
0 | SPDMVersion | 1 | Shall be the SPDMVersion |
1 | RequestResponseCode | 1 | Shall be 0x61 = CAPABILITIES. |
2 | Param1 | 1 | Bit 0 : 如果设置为1,Responder应该返回支持的Algorithms block。 如果请求方不支持大SPDM消息传输机制(CHUNK_CAP=0),则该位应为0。 Bit 1:7 Reserved. |
3 | Param2 | 1 | Reserved. |
4 | Reserved | 1 | Reserved. |
5 | CTExponent | 1 | 为以2为底的指数,用于计算CT,单位为us。 |
6 | Reserved | 2 | Reserved. |
8 | Flags | 4 | See Table 14 |
12 | DataTransferSize | 4 | 该字段以字节为单位指示请求方接收一条小于或等于该字段值的完整SPDM消息的最大缓冲区大小。该字段的值应等于或大于 MinDataTransferSize。DataTransferSize应该不包括传输头、加密头和MAC。该字段帮助SPDM消息的发送方知道是否需要使用 大型SPDM消息传输机制。 |
16 | MaxSPDMmsgSize | 4 | 如果请求方支持大型SPDM消息传输机制,则该字段应以字节为单位指示用于重新组装单个完整的大型SPDM消息的请求方内部缓冲区的最大大小。该字段必须大于或等于DataTransferSize。当在多个块中传输大型SPDM消息时,此缓冲区大小是最有用的,因为它告诉发送方是否有足够的内存容纳完全重新组装的SPDM消息。如果请求方不支持大SPDM报文传输机制,则该字段等于请求方的DataTransferSize |
20 | SupportedAlgorithms | AlgSize or 0 | 如果存在,该字段的大小为AlgSize,格式如Supported algorithms块中所述。如果Param1的0位不表示该响应包含支持算法扩展能力,则该字段不存在。 |
如本规范的其他部分所述,对于某些SPDM消息和流,请求者或响应者可以反转角色,或者同时扮演这两种角色。因此,SPDM端点不能发送超过接收SPDM端点的MaxSPDMmsgSize的大型SPDM消息。具体来说,请求SPDM端点发送的请求不能超过响应SPDM端点的MaxSPDMmsgSize。同样,响应的SPDM端点发送的响应不能超过请求SPDM端点的MaxSPDMmsgSize。如果响应消息的大小超过了请求SPDM端点的MaxSPDMmsgSize的大小,则响应SPDM端点将返回ErrorCode=ResponseTooLarge的ERROR消息。如果请求消息的大小超过了响应SPDM端点的MaxSPDMmsgSize的大小,则响应SPDM端点将返回ErrorCode=RequestTooLarge的ERROR消息或静默丢弃该请求。此外,如果SPDM端点收到超过其MaxSPDMmsgSize的SPDM消息,则应该提供优雅的错误处理(例如,缓冲区溢出/下溢保护).
除非另有说明,如果Requester表示支持与SPDM请求或响应消息相关联的功能,则意味着Requester可以接收相应的请求并生成成功的响应。换句话说,请求者充当与该功能相关联的SPDM请求的响应者。例如,如果请求者将CERT_CAP位设置为1,则请求者可以接收GET_CERTIFICATE请求并发回成功的CERTIFICATE响应消息。
12.NEGOTIATE_ALGORITHMS request and ALGORITHMS response messages
此请求消息将协商加密算法。在SPDM中,请求者发送NEGOTIATE_ALGORITHMS
用于指示它为每种类型的加密操作支持哪种加密算法,并且响应者使用算法响应消息从每种类型中选择一种算法。所选算法应用于连接期间的所有相关加密操作。当两个端点都支持多个算法时,响应者用来确定选择哪个算法的标准不在本规范的范围之内。
下图说明两个端点如何协商hashing算法。端点A发出一个NEGOTIATE_ALGORITHMS请求消息,端点B在算法响应中返回一个选定的相互支持的ALGORITHMS。
如果请求方和响应方不支持某一特定类型的通用算法,则响应方应发送一个ALGORITHMS响应消息,所有适当的选择字段值设置为零,以表明没有进行选择。响应程序应该用错误消息响应该请求程序的所有后续请求ErrorCode = RequestResynch。对于不需要协商加密算法的操作,响应者可以继续使用有限的功能进行操作。
在收到成功的CAPABILITIES响应消息之前,请求方不应发出NEGOTIATE_ALGORITHMS请求消息。
在请求方发出一个NEGOTIATE_ALGORITHMS请求之后,在它收到一个成功的ALGORITHMS响应消息之前,它不应该发出任何其他SPDM请求(GET_VERSION除外)。
响应者不能响应带有错误消息的NEGOTIATE_ALGORITHMS请求消息
ErrorCode = ResponseNotReady。
对于每种算法类型,响应者不能同时选择SPDM枚举算法和扩展算法。
SPDM协议考虑到两个端点相互独立地发出NEGOTIATE_ALGORITHMS请求消息的可能性。在这种情况下,端点A Requester和端点B Responder通信对可能会选择与端点B Requester和端点A Responder通信对选择的算法不同的算法。
Byte offset | Field | Size (bytes) | Description |
---|---|---|---|
0 | SPDMVersion | 1 | Shall be the SPDMVersion |
1 | RequestResponseCode | 1 | Shall be 0xE3 = NEGOTIATE_ALGORITHMS |
2 | Param1 | 1 | 应该是这个请求中使用ReqAlgStruct的算法结构表的数量。 |
3 | Param2 | 1 | Reserved. |
4 | Length | 2 | 应该是整个请求消息的长度,以字节为单位。长度应小于或等于128字节。 |
6 | MeasurementSpecification | 1 | Bit mask, See Measurement specification field format table |
7 | OtherParamsSupport | 1 | Shall be the selection bit mask. |
8 | BaseAsymAlgo | 4 | 应该是请求者支持的Bit mask列表,用于签名验证的spdm枚举的非对称密钥key signature算法。如果请求方不支持任何需要签名验证的请求/响应对,则此值应设置为零。如果请求程序不发送任何需要签名的请求,则该值应设置为零。设SigLen为签名的大小,以字节为单位。 |
12 | BaseHashAlgo | 4 | 应该是请求者支持的bit mask列表,用于签名验证的spdm枚举的hashing算法。如果请求方不支持任何需要签名验证的请求/响应对,则此值应设置为零。如果请求程序不发送任何需要签名的请求,则该值应设置为零。设SigLen为签名的大小,以字节为单位。 |
16 | Reserved | 12 | Reserved. |
28 | ExtAsymCount | 1 | 应是请求方支持的用于签名验证的扩展非对称密钥签名算法的个数(=A)。A + e + ExtAlgCount2 + ExtAlgCount3 + ExtAlgCount4 + ExtAlgCount5小于等于20。如果请求方不支持任何需要签名验证的请求/响应对,则此值应设置为零。 |
29 | ExtHashCount | 1 | 为请求方支持的扩展散列算法的个数(=E)。A + e + ExtAlgCount2 + ExtAlgCount3 + ExtAlgCount4 + ExtAlgCount5小于等于20。如果请求方不支持任何需要哈希操作的请求/响应对,则此值应设置为零。 |
30 | Reserved | 1 | Reserved |
31 | MELspecification | 1 | Shall be the bit mask,Requester通设置每一个bit位来表示支持的MEL。 |
32 | ExtAsym | 4 * A | 应是请求方支持的用于签名验证的扩展非对称密钥签名算法列表 |
32 + 4 * A | ExtHash | 4 * E | 应该是请求程序支持的扩展散列算法的列表。 |
32 + 4 * A + 4 * E | ReqAlgStruct | AlgStructSize | See the AlgStrucuture request field. |