From 80a591b7440233d39b05c0cbf72a3defc04221ef Mon Sep 17 00:00:00 2001 From: Fabrizio Damato Date: Tue, 30 Sep 2025 17:07:16 -0700 Subject: [PATCH 1/5] Device Identity Provisioning: Expanding the Spec with Provisioning Flow Signed-off-by: Fabrizio Damato --- .../device-identity-provisioning/spec.ocp | 343 +++++++++++++++++- 1 file changed, 341 insertions(+), 2 deletions(-) diff --git a/specifications/device-identity-provisioning/spec.ocp b/specifications/device-identity-provisioning/spec.ocp index d38455d..b00b4d2 100644 --- a/specifications/device-identity-provisioning/spec.ocp +++ b/specifications/device-identity-provisioning/spec.ocp @@ -330,11 +330,350 @@ The following OIDs are defined for key derivation attributes: These OIDs indicate which inputs contribute to the derivation of the identity key for which the CSR is being requested. -Subsequent versions of this specification may be expanded with additional key derivation attribute OIDs. +**Key Provisioning Entity OID Branch**: `ocp-security-dip-kpe OBJECT IDENTIFIER ::= {ocp-security 4}` + +The following OIDs are defined for key provisioning entities: + +- **Vendor Provisioning Entity**: `ocp-security-dip-kpe-vendor ::= {ocp-security-dip-kpe 1}` + - Used to identify vendor-provisioned endorsements (typically pre-installed in slot 0) + +- **Platform Owner Provisioning Entity**: `ocp-security-dip-kpe-owner ::= {ocp-security-dip-kpe 2}` + - Used to identify platform owner-provisioned endorsements + +- **Tenant Provisioning Entity**: `ocp-security-dip-kpe-tenant ::= {ocp-security-dip-kpe 3}` + - Used to identify tenant-provisioned endorsements in bare metal scenarios + +These OIDs are returned by the `OCP_GET_SLOT_ID_MAPPING` command to indicate which entity's endorsement is associated with each slot. + +Subsequent versions of this specification may be expanded with additional key derivation attribute OIDs and provisioning entity OIDs. ## Issuing and provisioning an identity certificate {#sec:issuing-and-provisioning-identity-cert} -This will be accomplished via the `SET_CERTIFICATE` SPDM command. +After establishing trust in a device's identity keypair through the envelope-signed CSR mechanism, a PKI owner can issue and provision an identity certificate to the device. This specification defines a standardized approach using OCP-specific extensions transported via SPDM's VENDOR_DEFINED_REQUEST mechanism. + +### Certificate provisioning overview + +Identity certificates are provisioned to devices using the OCP-specific `OCP_SET_ENDORSEMENT` command. The PKI owner provisions their endorsement chain (excluding the LEAF certificate) to a specific slot on the device. + +**Important**: This specification mandates that LEAF certificates (the identity certificates themselves) are NOT included in the provisioned certificate chains. The separation between endorsement chains and LEAF certificates ensures: + +- Multiple use cases (attestation, secure sessions) can use different LEAF certificates while sharing the same endorsement point +- The endorsement chain remains stable even as LEAF certificates may change based on key derivation inputs + +### Slot allocation and management + +Devices implementing this specification SHALL support certificate slot allocation with the following requirements: + +- **Minimum requirement**: Devices MUST reserve at least 2 slots for OCP provisioning (one for platform owner, one for tenant) +- **Vendor flexibility**: The specific slot numbers are determined by the device vendor and discovered via `OCP_GET_SLOT_ID_MAPPING` +- **Total slots**: SPDM supports up to 8 slots (0-7), with the allocation between vendor and OCP use defined by the vendor + +Example allocation (vendor-specific): +- Slot 0: Vendor endorsement (pre-provisioned) +- Slot 2: Platform owner endorsement +- Slot 4: Tenant endorsement +- Other slots: Available for additional use cases or vendor-specific purposes + +**Important**: The actual slot mapping is vendor-defined and discovered at runtime. The device SHALL return an error if attempts are made to provision more slots than physically supported + +### OCP extensions for certificate management + +To address the needs of heterogeneous environments where devices may support both SPDM and non-SPDM attestation paths, this specification defines OCP-specific commands transported via SPDM's VENDOR_DEFINED_REQUEST mechanism. + +#### OCP_GET_SLOT_ID_MAPPING command + +GET_SLOT_ID_MAPPING request and SLOT_ID_MAPPING response messages are transported as follows: + +- The Requester must use the SPDM VENDOR_DEFINED_REQUEST format +- The Responder must use the SPDM VENDOR_DEFINED_RESPONSE format +- The StandardID field of VENDOR_DEFINED_REQUEST and VENDOR_DEFINED_RESPONSE message must contain 4 (the value assigned in SPDM to identify IANA). +- The VendorID field of VENDOR_DEFINED_REQUEST and VENDOR_DEFINED_RESPONSE message must contain 42623 (the value assigned in IANA to identify Open Compute Project). +- The first byte of the VendorDefinedReqPayload/VendorDefinedRespPayload is the Command Code, and must contain the value 03h to indicate GET_SLOT_ID_MAPPING / SLOT_ID_MAPPING. +- The GET_SLOT_ID_MAPPING request and SLOT_ID_MAPPING response forms the payload in the VendorDefinedReqPayload and VendorDefinedRespPayload respectively, defined in Tables [-@tbl:slot-mapping-req] and [-@tbl:slot-mapping-resp]. + +Table: GET_SLOT_ID_MAPPING VendorDefinedReqPayload {#tbl:slot-mapping-req} + ++---------------------+---------------------+---------------------+----------------------------------------------+ +| Byte offset | Field | Size (bytes) | Description | ++=====================+=====================+=====================+==============================================+ +| 0 | CommandVersion | 1 | The version of this request structure. | +| | | | Shall be zero. | ++---------------------+---------------------+---------------------+----------------------------------------------+ +| 1 | CommandCode | 1 | Shall be 03h to indicate | +| | | | GET_SLOT_ID_MAPPING. | ++---------------------+---------------------+---------------------+----------------------------------------------+ +| 2 | Reserved | 4 | Reserved. | ++---------------------+---------------------+---------------------+----------------------------------------------+ + +Table: SLOT_ID_MAPPING VendorDefinedRespPayload {#tbl:slot-mapping-resp} + ++--------+-------------------------+-------------------------+------------------------------------------+ +| Byte | Field | Size (bytes) | Description | +| offset | | | | ++========+=========================+=========================+==========================================+ +| 0 | CommandVersion | 1 | The version of this response structure. | +| | | | Shall be zero. | ++--------+-------------------------+-------------------------+------------------------------------------+ +| 1 | CommandCode | 1 | Shall be 03h to indicate | +| | | | SLOT_ID_MAPPING. | ++--------+-------------------------+-------------------------+------------------------------------------+ +| 2 | Reserved | 4 | Reserved. | ++--------+-------------------------+-------------------------+------------------------------------------+ +| 6 | MappingCount | 1 | Number of slot mappings returned. | +| | | | Shall not exceed 8. | ++--------+-------------------------+-------------------------+------------------------------------------+ +| 7 | Reserved | 1 | Reserved. | ++--------+-------------------------+-------------------------+------------------------------------------+ +| 8 | MappingTable | MappingCount * 16 | Array of slot mappings. Each entry | +| | | | consists of: | +| | | | - SlotID (1 byte) | +| | | | - Reserved (3 bytes) | +| | | | - OID Length (2 bytes) | +| | | | - Reserved (2 bytes) | +| | | | - OID (8 bytes, zero-padded) | ++--------+-------------------------+-------------------------+------------------------------------------+ + +#### OCP_SET_ENDORSEMENT command + +SET_ENDORSEMENT request and SET_ENDORSEMENT response messages are transported as follows: + +- The Requester must use the SPDM VENDOR_DEFINED_REQUEST format +- The Responder must use the SPDM VENDOR_DEFINED_RESPONSE format +- The StandardID field of VENDOR_DEFINED_REQUEST and VENDOR_DEFINED_RESPONSE message must contain 4 (the value assigned in SPDM to identify IANA). +- The VendorID field of VENDOR_DEFINED_REQUEST and VENDOR_DEFINED_RESPONSE message must contain 42623 (the value assigned in IANA to identify Open Compute Project). +- The first byte of the VendorDefinedReqPayload/VendorDefinedRespPayload is the Command Code, and must contain the value 04h to indicate SET_ENDORSEMENT. +- The SET_ENDORSEMENT request and SET_ENDORSEMENT response forms the payload in the VendorDefinedReqPayload and VendorDefinedRespPayload respectively, defined in Tables [-@tbl:set-endorsement-req] and [-@tbl:set-endorsement-resp]. + +Table: SET_ENDORSEMENT VendorDefinedReqPayload {#tbl:set-endorsement-req} + ++---------------------+---------------------+---------------------+----------------------------------------------+ +| Byte offset | Field | Size (bytes) | Description | ++=====================+=====================+=====================+==============================================+ +| 0 | CommandVersion | 1 | The version of this request structure. | +| | | | Shall be zero. | ++---------------------+---------------------+---------------------+----------------------------------------------+ +| 1 | CommandCode | 1 | Shall be 04h to indicate | +| | | | SET_ENDORSEMENT. | ++---------------------+---------------------+---------------------+----------------------------------------------+ +| 2 | Reserved | 4 | Reserved. | ++---------------------+---------------------+---------------------+----------------------------------------------+ +| 6 | SlotID | 1 | Target slot for the endorsement chain. | +| | | | Shall be a valid slot as indicated by | +| | | | GET_SLOT_ID_MAPPING. | ++---------------------+---------------------+---------------------+----------------------------------------------+ +| 7 | Flags | 1 | - Bit [7:1]: Reserved. | +| | | | - Bit [0]: FORCE flag. | +| | | | If set to 1, allows overwriting an | +| | | | existing endorsement in the slot. | +| | | | If set to 0, returns error if slot | +| | | | is already occupied. | ++---------------------+---------------------+---------------------+----------------------------------------------+ +| 8 | KeyID | 1 | Key identifier for certificate selection. | +| | | | Usage is vendor-specific. | ++---------------------+---------------------+---------------------+----------------------------------------------+ +| 9 | Reserved | 1 | Reserved. | ++---------------------+---------------------+---------------------+----------------------------------------------+ +| 10 | CertChainLength | 2 | Length of the certificate chain in bytes. | +| | | | Shall not exceed device capabilities. | ++---------------------+---------------------+---------------------+----------------------------------------------+ +| 12 | CertChain | CertChainLength | DER-encoded certificate chain. | +| | | | Shall NOT include LEAF certificate. | ++---------------------+---------------------+---------------------+----------------------------------------------+ + +Table: SET_ENDORSEMENT VendorDefinedRespPayload {#tbl:set-endorsement-resp} + ++--------+-------------------------+-------------------------+------------------------------------------+ +| Byte | Field | Size (bytes) | Description | +| offset | | | | ++========+=========================+=========================+==========================================+ +| 0 | CommandVersion | 1 | The version of this response structure. | +| | | | Shall be zero. | ++--------+-------------------------+-------------------------+------------------------------------------+ +| 1 | CommandCode | 1 | Shall be 04h to indicate | +| | | | SET_ENDORSEMENT. | ++--------+-------------------------+-------------------------+------------------------------------------+ +| 2 | Reserved | 4 | Reserved. | ++--------+-------------------------+-------------------------+------------------------------------------+ +| 6 | Status | 1 | Status code: | +| | | | - 00h: Success | +| | | | - 01h: Slot occupied | +| | | | - 02h: Invalid slot | +| | | | - 03h: Invalid chain | +| | | | - 04h: Chain too long | +| | | | - 05h: Insufficient resources | +| | | | - FFh: General failure | ++--------+-------------------------+-------------------------+------------------------------------------+ +| 7 | Reserved | 1 | Reserved. | ++--------+-------------------------+-------------------------+------------------------------------------+ + + +#### OCP_GET_ENDORSEMENT command + +GET_ENDORSEMENT request and GET_ENDORSEMENT response messages are transported as follows: + +- The Requester must use the SPDM VENDOR_DEFINED_REQUEST format +- The Responder must use the SPDM VENDOR_DEFINED_RESPONSE format +- The StandardID field of VENDOR_DEFINED_REQUEST and VENDOR_DEFINED_RESPONSE message must contain 4 (the value assigned in SPDM to identify IANA). +- The VendorID field of VENDOR_DEFINED_REQUEST and VENDOR_DEFINED_RESPONSE message must contain 42623 (the value assigned in IANA to identify Open Compute Project). +- The first byte of the VendorDefinedReqPayload/VendorDefinedRespPayload is the Command Code, and must contain the value 04h to indicate GET_ENDORSEMENT. +- The GET_ENDORSEMENT request and GET_ENDORSEMENT response forms the payload in the VendorDefinedReqPayload and VendorDefinedRespPayload respectively, defined in Tables [-@tbl:get-endorsement-req] and [-@tbl:get-endorsement-resp]. + +Table: GET_ENDORSEMENT VendorDefinedReqPayload {#tbl:get-endorsement-req} + ++---------------------+---------------------+---------------------+----------------------------------------------+ +| Byte offset | Field | Size (bytes) | Description | ++=====================+=====================+=====================+==============================================+ +| 0 | CommandVersion | 1 | The version of this request structure. | +| | | | Shall be zero. | ++---------------------+---------------------+---------------------+----------------------------------------------+ +| 1 | CommandCode | 1 | Shall be 04h to indicate | +| | | | GET_ENDORSEMENT. | ++---------------------+---------------------+---------------------+----------------------------------------------+ +| 2 | Reserved | 4 | Reserved. | ++---------------------+---------------------+---------------------+----------------------------------------------+ +| 6 | SlotID | 1 | Slot from which to retrieve the | +| | | | endorsement chain. | ++---------------------+---------------------+---------------------+----------------------------------------------+ +| 7 | Reserved | 1 | Reserved. | ++---------------------+---------------------+---------------------+----------------------------------------------+ + +Table: GET_ENDORSEMENT VendorDefinedRespPayload {#tbl:get-endorsement-resp} + ++--------+-------------------------+-------------------------+------------------------------------------+ +| Byte | Field | Size (bytes) | Description | +| offset | | | | ++========+=========================+=========================+==========================================+ +| 0 | CommandVersion | 1 | The version of this response structure. | +| | | | Shall be zero. | ++--------+-------------------------+-------------------------+------------------------------------------+ +| 1 | CommandCode | 1 | Shall be 04h to indicate | +| | | | GET_ENDORSEMENT. | ++--------+-------------------------+-------------------------+------------------------------------------+ +| 2 | Reserved | 4 | Reserved. | ++--------+-------------------------+-------------------------+------------------------------------------+ +| 6 | Status | 1 | Status code: | +| | | | - 00h: Success | +| | | | - 02h: Invalid slot | +| | | | - 06h: Slot not provisioned | +| | | | - FFh: General failure | ++--------+-------------------------+-------------------------+------------------------------------------+ +| 7 | Reserved | 1 | Reserved. | ++--------+-------------------------+-------------------------+------------------------------------------+ +| 8 | CertChainLength | 2 | Length of the certificate chain. | +| | | | Zero if status is not success. | ++--------+-------------------------+-------------------------+------------------------------------------+ +| 10 | CertChain | CertChainLength | DER-encoded certificate chain. | +| | | | Does NOT include LEAF certificate. | +| | | | Present only if status is success. | ++--------+-------------------------+-------------------------+------------------------------------------+ + +### Provisioning workflow + +A typical provisioning workflow follows these steps: + +1. **Discovery**: The PKI owner queries `OCP_GET_SLOT_ID_MAPPING` to understand the device's slot allocation +2. **CSR Generation**: The PKI owner requests an envelope-signed CSR for their chosen identity key using `GET_ENVELOPE_SIGNED_CSR` +3. **Certificate Issuance**: The PKI owner validates the CSR and issues an identity certificate +4. **Chain Provisioning**: The PKI owner provisions their endorsement chain (excluding the newly issued LEAF certificate) using `OCP_SET_ENDORSEMENT` +5. **Verification**: The PKI owner can verify successful provisioning by retrieving the chain using `OCP_GET_ENDORSEMENT` + +### Compatibility considerations + +For devices that support both SPDM and OCP attestation paths: + +- The same SlotID namespace is shared between SPDM and OCP commands +- `OCP_SET_ENDORSEMENT` provisions to the same underlying storage accessed by SPDM +- `GET_CERTIFICATE` (SPDM) returns the endorsement chain plus any associated LEAF certificate +- `OCP_GET_ENDORSEMENT` returns only the endorsement chain + +This unified approach ensures consistent certificate management regardless of the attestation path used. + +### Certificate chain validation + +When provisioning certificate chains, devices SHALL validate: + +- The certificate chain is properly formed and each certificate correctly signs the next +- The chain terminates at a self-signed root or a certificate that can be verified against pre-existing trust anchors +- All certificates in the chain are within their validity periods +- The certificate chain length does not exceed device storage capabilities + +### Error handling + +The following error conditions SHALL be reported: + +- **SLOT_OCCUPIED**: Attempting to provision a slot that already contains a certificate chain when FORCE flag is not set +- **INVALID_SLOT**: Specified slot ID is outside the valid range +- **CHAIN_TOO_LONG**: Certificate chain exceeds device storage capacity +- **INVALID_CHAIN**: Certificate chain validation failed +- **INSUFFICIENT_RESOURCES**: Device lacks resources to complete the operation + +### Security considerations + +#### Protection of provisioning operations + +Certificate provisioning operations SHOULD be performed over authenticated and encrypted channels: + +- For SPDM paths: Use SPDM secured messages when available +- For out-of-band provisioning: Use platform-specific secure channels + +#### Slot update policy + +To prevent unauthorized certificate replacement: + +- Devices MAY implement policies restricting certificate updates based on: + - Physical presence assertions + - Platform ownership state + - Secure boot state +- Once provisioned, slots SHALL NOT be overwritable without the FORCE flag being explicitly set +- When FORCE flag is used to overwrite an existing endorsement, devices SHOULD log this as a security-relevant event + +#### Certificate lifecycle management + +PKI owners are responsible for: + +- Tracking certificate expiration dates +- Implementing certificate renewal procedures before expiration +- Maintaining certificate revocation lists (CRLs) for compromised certificates +- Ensuring time synchronization for certificate validity checking + +### Implementation notes + +#### Storage optimization + +Given the limited storage available on many devices: + +- Redundant certificates (e.g., those appearing in multiple chains) MAY be stored once and referenced multiple times + +#### Backwards compatibility + +For devices that only support SPDM without OCP extensions: + +- Standard SPDM `SET_CERTIFICATE` commands remain fully functional + +### Example provisioning sequence + +Here's a complete example of a platform owner provisioning their endorsement chain: + +1. **BMC → Device**: `OCP_GET_SLOT_ID_MAPPING()` + + **Device → BMC**: `{0: OID_VENDOR, 2: OID_OWNER, 4: OID_TENANT}` + +2. **BMC → Device**: `GET_ENVELOPE_SIGNED_CSR(KeyPairID=LDevID, SlotID=0, Nonce)` + + **Device → BMC**: `EAT{CSR for LDevID}` + +3. **BMC validates CSR and issues certificate for LDevID** + +4. **BMC → Device**: `OCP_SET_ENDORSEMENT(SlotID=2, KeyID, OwnerEndorsementChain)` + + **Device → BMC**: `SUCCESS` + +5. **TENANT → Device**: `OCP_GET_ENDORSEMENT(SlotID=2)` + + **Device → TENANT**: `OwnerEndorsementChain` (confirming successful provisioning) + +After this sequence, attestations from the device can reference the owner's endorsement chain. + TODO: fill in additional details. From 7c139398b1744fcb44fdc3945824f6acbd4f676c Mon Sep 17 00:00:00 2001 From: Fabrizio Damato Date: Tue, 30 Sep 2025 19:43:51 -0700 Subject: [PATCH 2/5] Device Identity Provisioning: Replace OIDs for Key Provisioning Entity to Enum type Signed-off-by: Fabrizio Damato --- .../device-identity-provisioning/spec.ocp | 164 ++++++++++-------- 1 file changed, 93 insertions(+), 71 deletions(-) diff --git a/specifications/device-identity-provisioning/spec.ocp b/specifications/device-identity-provisioning/spec.ocp index b00b4d2..bdea19f 100644 --- a/specifications/device-identity-provisioning/spec.ocp +++ b/specifications/device-identity-provisioning/spec.ocp @@ -330,22 +330,7 @@ The following OIDs are defined for key derivation attributes: These OIDs indicate which inputs contribute to the derivation of the identity key for which the CSR is being requested. -**Key Provisioning Entity OID Branch**: `ocp-security-dip-kpe OBJECT IDENTIFIER ::= {ocp-security 4}` - -The following OIDs are defined for key provisioning entities: - -- **Vendor Provisioning Entity**: `ocp-security-dip-kpe-vendor ::= {ocp-security-dip-kpe 1}` - - Used to identify vendor-provisioned endorsements (typically pre-installed in slot 0) - -- **Platform Owner Provisioning Entity**: `ocp-security-dip-kpe-owner ::= {ocp-security-dip-kpe 2}` - - Used to identify platform owner-provisioned endorsements - -- **Tenant Provisioning Entity**: `ocp-security-dip-kpe-tenant ::= {ocp-security-dip-kpe 3}` - - Used to identify tenant-provisioned endorsements in bare metal scenarios - -These OIDs are returned by the `OCP_GET_SLOT_ID_MAPPING` command to indicate which entity's endorsement is associated with each slot. - -Subsequent versions of this specification may be expanded with additional key derivation attribute OIDs and provisioning entity OIDs. +Subsequent versions of this specification may be expanded with additional key derivation attribute OIDs. ## Issuing and provisioning an identity certificate {#sec:issuing-and-provisioning-identity-cert} @@ -380,7 +365,20 @@ Example allocation (vendor-specific): To address the needs of heterogeneous environments where devices may support both SPDM and non-SPDM attestation paths, this specification defines OCP-specific commands transported via SPDM's VENDOR_DEFINED_REQUEST mechanism. -#### OCP_GET_SLOT_ID_MAPPING command +**Transport flexibility**: While this specification defines these commands as SPDM vendor-defined messages, devices that do not support SPDM MAY implement these same commands over alternative transport mechanisms. The definition of transport bindings for non-SPDM attesters is outside the scope of this specification. Regardless of transport, the command and response payload formats defined in this specification SHALL be preserved. + +#### Key Provisioning Entity Enumeration + +The following Key Provisioning Entity values are defined: + +- **VENDOR** (0x00): Vendor-provisioned endorsements (typically pre-installed) +- **OWNER** (0x01): Platform owner-provisioned endorsements +- **TENANT** (0x02): Tenant-provisioned endorsements in bare metal scenarios +Future versions of this specification may define additional entity values. + +#### OCP_GET_SLOT_ID_MAPPING command (Informational) + +This command is provided for informational purposes, primarily for devices that also support SPDM. It allows callers to understand which SPDM slot corresponds to each Key Provisioning Entity. GET_SLOT_ID_MAPPING request and SLOT_ID_MAPPING response messages are transported as follows: @@ -419,20 +417,19 @@ Table: SLOT_ID_MAPPING VendorDefinedRespPayload {#tbl:slot-mapping-resp} +--------+-------------------------+-------------------------+------------------------------------------+ | 2 | Reserved | 4 | Reserved. | +--------+-------------------------+-------------------------+------------------------------------------+ -| 6 | MappingCount | 1 | Number of slot mappings returned. | +| 6 | MappingCount | 1 | Number of mappings returned. | | | | | Shall not exceed 8. | +--------+-------------------------+-------------------------+------------------------------------------+ | 7 | Reserved | 1 | Reserved. | +--------+-------------------------+-------------------------+------------------------------------------+ -| 8 | MappingTable | MappingCount * 16 | Array of slot mappings. Each entry | +| 8 | MappingTable | MappingCount * 2 | Array of mappings. Each entry | | | | | consists of: | +| | | | - KeyProvisioningEntity (1 byte) | | | | | - SlotID (1 byte) | -| | | | - Reserved (3 bytes) | -| | | | - OID Length (2 bytes) | -| | | | - Reserved (2 bytes) | -| | | | - OID (8 bytes, zero-padded) | +--------+-------------------------+-------------------------+------------------------------------------+ +**Note**: The `OCP_GET_SLOT_ID_MAPPING` command is informational only. Devices that support both OCP and SPDM commands use this to report which SPDM slot corresponds to each Key Provisioning Entity. This allows SPDM requesters to understand the side effects of `OCP_SET_ENDORSEMENT` operations. + #### OCP_SET_ENDORSEMENT command SET_ENDORSEMENT request and SET_ENDORSEMENT response messages are transported as follows: @@ -457,16 +454,18 @@ Table: SET_ENDORSEMENT VendorDefinedReqPayload {#tbl:set-endorsement-req} +---------------------+---------------------+---------------------+----------------------------------------------+ | 2 | Reserved | 4 | Reserved. | +---------------------+---------------------+---------------------+----------------------------------------------+ -| 6 | SlotID | 1 | Target slot for the endorsement chain. | -| | | | Shall be a valid slot as indicated by | -| | | | GET_SLOT_ID_MAPPING. | +| 6 | KeyProvisioningEntity| 1 | Entity for which to set endorsement: | +| | | | - 00h: VENDOR | +| | | | - 01h: OWNER | +| | | | - 02h: TENANT | +| | | | Other values reserved. | +---------------------+---------------------+---------------------+----------------------------------------------+ | 7 | Flags | 1 | - Bit [7:1]: Reserved. | | | | | - Bit [0]: FORCE flag. | | | | | If set to 1, allows overwriting an | -| | | | existing endorsement in the slot. | -| | | | If set to 0, returns error if slot | -| | | | is already occupied. | +| | | | existing endorsement. | +| | | | If set to 0, returns error if | +| | | | already provisioned. | +---------------------+---------------------+---------------------+----------------------------------------------+ | 8 | KeyID | 1 | Key identifier for certificate selection. | | | | | Usage is vendor-specific. | @@ -496,8 +495,8 @@ Table: SET_ENDORSEMENT VendorDefinedRespPayload {#tbl:set-endorsement-resp} +--------+-------------------------+-------------------------+------------------------------------------+ | 6 | Status | 1 | Status code: | | | | | - 00h: Success | -| | | | - 01h: Slot occupied | -| | | | - 02h: Invalid slot | +| | | | - 01h: Invalid entity | +| | | | - 02h: Entity already provisioned | | | | | - 03h: Invalid chain | | | | | - 04h: Chain too long | | | | | - 05h: Insufficient resources | @@ -506,7 +505,6 @@ Table: SET_ENDORSEMENT VendorDefinedRespPayload {#tbl:set-endorsement-resp} | 7 | Reserved | 1 | Reserved. | +--------+-------------------------+-------------------------+------------------------------------------+ - #### OCP_GET_ENDORSEMENT command GET_ENDORSEMENT request and GET_ENDORSEMENT response messages are transported as follows: @@ -515,7 +513,7 @@ GET_ENDORSEMENT request and GET_ENDORSEMENT response messages are transported as - The Responder must use the SPDM VENDOR_DEFINED_RESPONSE format - The StandardID field of VENDOR_DEFINED_REQUEST and VENDOR_DEFINED_RESPONSE message must contain 4 (the value assigned in SPDM to identify IANA). - The VendorID field of VENDOR_DEFINED_REQUEST and VENDOR_DEFINED_RESPONSE message must contain 42623 (the value assigned in IANA to identify Open Compute Project). -- The first byte of the VendorDefinedReqPayload/VendorDefinedRespPayload is the Command Code, and must contain the value 04h to indicate GET_ENDORSEMENT. +- The first byte of the VendorDefinedReqPayload/VendorDefinedRespPayload is the Command Code, and must contain the value 05h to indicate GET_ENDORSEMENT. - The GET_ENDORSEMENT request and GET_ENDORSEMENT response forms the payload in the VendorDefinedReqPayload and VendorDefinedRespPayload respectively, defined in Tables [-@tbl:get-endorsement-req] and [-@tbl:get-endorsement-resp]. Table: GET_ENDORSEMENT VendorDefinedReqPayload {#tbl:get-endorsement-req} @@ -526,15 +524,18 @@ Table: GET_ENDORSEMENT VendorDefinedReqPayload {#tbl:get-endorsement-req} | 0 | CommandVersion | 1 | The version of this request structure. | | | | | Shall be zero. | +---------------------+---------------------+---------------------+----------------------------------------------+ -| 1 | CommandCode | 1 | Shall be 04h to indicate | +| 1 | CommandCode | 1 | Shall be 05h to indicate | | | | | GET_ENDORSEMENT. | +---------------------+---------------------+---------------------+----------------------------------------------+ | 2 | Reserved | 4 | Reserved. | +---------------------+---------------------+---------------------+----------------------------------------------+ -| 6 | SlotID | 1 | Slot from which to retrieve the | -| | | | endorsement chain. | +| 6 | KeyProvisioningEntity| 1 | Entity from which to get endorsement: | +| | | | - 00h: VENDOR | +| | | | - 01h: OWNER | +| | | | - 02h: TENANT | +| | | | Other values reserved. | +---------------------+---------------------+---------------------+----------------------------------------------+ -| 7 | Reserved | 1 | Reserved. | +| 7 | Reserved | 1 | Reserved. | +---------------------+---------------------+---------------------+----------------------------------------------+ Table: GET_ENDORSEMENT VendorDefinedRespPayload {#tbl:get-endorsement-resp} @@ -546,15 +547,15 @@ Table: GET_ENDORSEMENT VendorDefinedRespPayload {#tbl:get-endorsement-resp} | 0 | CommandVersion | 1 | The version of this response structure. | | | | | Shall be zero. | +--------+-------------------------+-------------------------+------------------------------------------+ -| 1 | CommandCode | 1 | Shall be 04h to indicate | +| 1 | CommandCode | 1 | Shall be 05h to indicate | | | | | GET_ENDORSEMENT. | +--------+-------------------------+-------------------------+------------------------------------------+ | 2 | Reserved | 4 | Reserved. | +--------+-------------------------+-------------------------+------------------------------------------+ | 6 | Status | 1 | Status code: | | | | | - 00h: Success | -| | | | - 02h: Invalid slot | -| | | | - 06h: Slot not provisioned | +| | | | - 01h: Invalid entity | +| | | | - 02h: Entity not provisioned | | | | | - FFh: General failure | +--------+-------------------------+-------------------------+------------------------------------------+ | 7 | Reserved | 1 | Reserved. | @@ -571,22 +572,25 @@ Table: GET_ENDORSEMENT VendorDefinedRespPayload {#tbl:get-endorsement-resp} A typical provisioning workflow follows these steps: -1. **Discovery**: The PKI owner queries `OCP_GET_SLOT_ID_MAPPING` to understand the device's slot allocation -2. **CSR Generation**: The PKI owner requests an envelope-signed CSR for their chosen identity key using `GET_ENVELOPE_SIGNED_CSR` -3. **Certificate Issuance**: The PKI owner validates the CSR and issues an identity certificate -4. **Chain Provisioning**: The PKI owner provisions their endorsement chain (excluding the newly issued LEAF certificate) using `OCP_SET_ENDORSEMENT` -5. **Verification**: The PKI owner can verify successful provisioning by retrieving the chain using `OCP_GET_ENDORSEMENT` +1. **CSR Generation**: The PKI owner requests an envelope-signed CSR for their chosen identity key using `GET_ENVELOPE_SIGNED_CSR` +2. **Certificate Issuance**: The PKI owner validates the CSR and issues an identity certificate +3. **Chain Provisioning**: The PKI owner provisions their endorsement chain (excluding the newly issued LEAF certificate) using `OCP_SET_ENDORSEMENT` with the appropriate KeyProvisioningEntity value +4. **Verification**: The PKI owner can verify successful provisioning by retrieving the chain using `OCP_GET_ENDORSEMENT` + +For SPDM-aware implementations: + +5. **Optional Mapping Discovery**: Query `OCP_GET_SLOT_ID_MAPPING` to understand which SPDM slots are affected by OCP operations ### Compatibility considerations For devices that support both SPDM and OCP attestation paths: -- The same SlotID namespace is shared between SPDM and OCP commands -- `OCP_SET_ENDORSEMENT` provisions to the same underlying storage accessed by SPDM -- `GET_CERTIFICATE` (SPDM) returns the endorsement chain plus any associated LEAF certificate -- `OCP_GET_ENDORSEMENT` returns only the endorsement chain +- `OCP_SET_ENDORSEMENT` internally manages slot allocation based on the KeyProvisioningEntity +- `OCP_GET_ENDORSEMENT` retrieves endorsements by entity rather than slot number +- `GET_CERTIFICATE` (SPDM) can still be used with the slot numbers reported by `OCP_GET_SLOT_ID_MAPPING` +- The device ensures consistency between OCP entity-based and SPDM slot-based access -This unified approach ensures consistent certificate management regardless of the attestation path used. +This approach simplifies the interface by abstracting slot management while maintaining full compatibility with SPDM. ### Certificate chain validation @@ -597,15 +601,21 @@ When provisioning certificate chains, devices SHALL validate: - All certificates in the chain are within their validity periods - The certificate chain length does not exceed device storage capabilities +Devices MAY additionally validate: + +- Certificate revocation status if CRL or OCSP information is available +- Certificate policy OIDs match expected values for the entity being provisioned + ### Error handling The following error conditions SHALL be reported: -- **SLOT_OCCUPIED**: Attempting to provision a slot that already contains a certificate chain when FORCE flag is not set -- **INVALID_SLOT**: Specified slot ID is outside the valid range +- **ENTITY_ALREADY_PROVISIONED**: Attempting to provision an entity that already has an endorsement when FORCE flag is not set +- **INVALID_ENTITY**: Specified KeyProvisioningEntity value is not supported - **CHAIN_TOO_LONG**: Certificate chain exceeds device storage capacity - **INVALID_CHAIN**: Certificate chain validation failed - **INSUFFICIENT_RESOURCES**: Device lacks resources to complete the operation +- **ENTITY_NOT_PROVISIONED**: Attempting to retrieve endorsement for an entity that has not been provisioned ### Security considerations @@ -616,7 +626,7 @@ Certificate provisioning operations SHOULD be performed over authenticated and e - For SPDM paths: Use SPDM secured messages when available - For out-of-band provisioning: Use platform-specific secure channels -#### Slot update policy +#### Entity update policy To prevent unauthorized certificate replacement: @@ -624,7 +634,7 @@ To prevent unauthorized certificate replacement: - Physical presence assertions - Platform ownership state - Secure boot state -- Once provisioned, slots SHALL NOT be overwritable without the FORCE flag being explicitly set +- Once provisioned, entities SHALL NOT be overwritable without the FORCE flag being explicitly set - When FORCE flag is used to overwrite an existing endorsement, devices SHOULD log this as a security-relevant event #### Certificate lifecycle management @@ -638,41 +648,53 @@ PKI owners are responsible for: ### Implementation notes +#### Internal slot management + +Devices implementing these OCP commands: + +- SHALL internally manage the mapping between KeyProvisioningEntity values and storage slots +- MAY use any slot allocation strategy as long as it supports the minimum required entities +- SHOULD use consistent slot assignments across device resets for predictability + #### Storage optimization Given the limited storage available on many devices: - Redundant certificates (e.g., those appearing in multiple chains) MAY be stored once and referenced multiple times -#### Backwards compatibility +#### Minimal implementation -For devices that only support SPDM without OCP extensions: +Devices that only support OCP commands (not SPDM): -- Standard SPDM `SET_CERTIFICATE` commands remain fully functional +- MAY omit implementation of `OCP_GET_SLOT_ID_MAPPING` +- SHALL still support all KeyProvisioningEntity values defined in this specification +- Focus on entity-based access without exposing slot details ### Example provisioning sequence Here's a complete example of a platform owner provisioning their endorsement chain: -1. **BMC → Device**: `OCP_GET_SLOT_ID_MAPPING()` - - **Device → BMC**: `{0: OID_VENDOR, 2: OID_OWNER, 4: OID_TENANT}` - -2. **BMC → Device**: `GET_ENVELOPE_SIGNED_CSR(KeyPairID=LDevID, SlotID=0, Nonce)` - - **Device → BMC**: `EAT{CSR for LDevID}` - -3. **BMC validates CSR and issues certificate for LDevID** +1. **BMC → Device**: `GET_ENVELOPE_SIGNED_CSR(KeyPairID=LDevID, SlotID=0, Nonce)` + + **Device → BMC**: `EAT{CSR for LDevID, signed by IDevID}` -4. **BMC → Device**: `OCP_SET_ENDORSEMENT(SlotID=2, KeyID, OwnerEndorsementChain)` +2. **BMC validates CSR and issues certificate for LDevID** - **Device → BMC**: `SUCCESS` +3. **BMC → Device**: `OCP_SET_ENDORSEMENT(KeyProvisioningEntity=OWNER, Flags=0, KeyID, OwnerEndorsementChain)` + + **Device → BMC**: `Status=SUCCESS` -5. **TENANT → Device**: `OCP_GET_ENDORSEMENT(SlotID=2)` +4. **BMC → Device**: `OCP_GET_ENDORSEMENT(KeyProvisioningEntity=OWNER)` + + **Device → BMC**: `Status=SUCCESS, OwnerEndorsementChain` (confirming successful provisioning) - **Device → TENANT**: `OwnerEndorsementChain` (confirming successful provisioning) +5. **Optional - BMC → Device**: `OCP_GET_SLOT_ID_MAPPING()` + + **Device → BMC**: `[{VENDOR: 0}, {OWNER: 2}, {TENANT: 4}]` + + (BMC now knows that the OWNER endorsement was stored in SPDM slot 2) -After this sequence, attestations from the device can reference the owner's endorsement chain. +After this sequence, attestations from the device can reference the owner's endorsement chain TODO: fill in additional details. From 7ff9f8c54f77ff7318abd0edbd29dfd6483749cf Mon Sep 17 00:00:00 2001 From: Fabrizio Damato Date: Wed, 1 Oct 2025 20:25:26 -0700 Subject: [PATCH 3/5] Device Identity Provisioning: Set Certificate, address reviews and consistency cleanup Signed-off-by: Fabrizio Damato --- .../bibliography.yaml | 7 + .../cddl/envelope-signed-csr-eat.cddl | 3 - .../diag/envelope-signed-csr-eat-example.diag | 3 +- .../device-identity-provisioning/spec.ocp | 356 ++++++++++-------- 4 files changed, 199 insertions(+), 170 deletions(-) diff --git a/specifications/device-identity-provisioning/bibliography.yaml b/specifications/device-identity-provisioning/bibliography.yaml index b771a7a..39731d0 100644 --- a/specifications/device-identity-provisioning/bibliography.yaml +++ b/specifications/device-identity-provisioning/bibliography.yaml @@ -45,3 +45,10 @@ references: year: 2000 month: 11 url: "https://datatracker.ietf.org/doc/html/rfc2986" + - id: "ocp-command-registry" + title: "OCP Command Registry" + publisher: "Open Compute Project" + issued: + year: 2025 + month: 9 + url: "https://github.com/opencomputeproject/ocp-registry/blob/main/command-registry.md" \ No newline at end of file diff --git a/specifications/device-identity-provisioning/cddl/envelope-signed-csr-eat.cddl b/specifications/device-identity-provisioning/cddl/envelope-signed-csr-eat.cddl index c833319..c47acb9 100644 --- a/specifications/device-identity-provisioning/cddl/envelope-signed-csr-eat.cddl +++ b/specifications/device-identity-provisioning/cddl/envelope-signed-csr-eat.cddl @@ -1,7 +1,4 @@ cwt-envelope-signed-csr-eat = { - ; The EAT Profile for Envelope-Signed CSR OCP will register - &(eat-profile : 265 ) => ~oid ; "1.3.6.1.4.1.42623.1" - note: `~` strips CBOR tag #6.111(oid) from `oid` - ; Issuer claim is StringOrURI (tstr) &(iss : 1) => tstr diff --git a/specifications/device-identity-provisioning/diag/envelope-signed-csr-eat-example.diag b/specifications/device-identity-provisioning/diag/envelope-signed-csr-eat-example.diag index 8a1b1b3..c8b3613 100644 --- a/specifications/device-identity-provisioning/diag/envelope-signed-csr-eat-example.diag +++ b/specifications/device-identity-provisioning/diag/envelope-signed-csr-eat-example.diag @@ -2,11 +2,10 @@ signed-cwt / 18([ / protected / <<{ / alg-id / 1 : 7, / content-type / 3 : "application/eat+cbor", - / kid / 4 : 'Example OCP Envelope-Signed CSR CWT' + / kid / 4 : 'RT Alias Key' }>>, / unprotected / {/ x5-chain / 33 : h'59025630820252308201d9a003020102021431a4ef62e5244e4d952ea485976098090d5f242f300a06082a8648ce3d040303307b310b30090603550406130255533113301106035504080c0a43616c69666f726e69613116301406035504070c0d53616e204672616e636973636f311d301b060355040a0c144578616d706c65204f7267616e697a6174696f6e3120301e06035504030c174578616d706c652043575420456e646f7273656d656e74301e170d3235303231333139303230345a170d3236303231343139303230345a307b310b30090603550406130255533113301106035504080c0a43616c69666f726e69613116301406035504070c0d53616e204672616e636973636f311d301b060355040a0c144578616d706c65204f7267616e697a6174696f6e3120301e06035504030c174578616d706c652043575420456e646f7273656d656e743076301006072a8648ce3d020106052b8104002203620004fcd3fad48575addceee9638583aa7054f71a402f35993901923cc0ee9763b85b1e729c740331f4e91079559bce17d5c3b706748333faeb192120e32d815f88f7310ae05df55060f96fbdb2d0acb19e710d25ec27cfa8945fe5dda73332813feda31e301c301a0603551d1104133011820f7777772e6578616d706c652e636f6d300a06082a8648ce3d040303036700306402306e1166a8a3132d4a20e0200a26d1eba0937fec54fdb7547eb7c5ccca0370170853294cdd6b3a1eb0fe649f12446d8b17023071219daf2b7c1aa6f7727d053e1027309594fd8cab9f820fa89d8f88fc7e551c0d30781b12aea48b53fde200e6cf082b' }, / payload / <<{ - / eat-profile / 265 : h'88378952', / iss / 1 : "RT Alias Key", / nonce / 10: h'AAAABBBBAAAABBBBAAAABBBB', / csr / -70001 : h'59025630820252308201d9a003020102021431a4e0', diff --git a/specifications/device-identity-provisioning/spec.ocp b/specifications/device-identity-provisioning/spec.ocp index bdea19f..ebbb069 100644 --- a/specifications/device-identity-provisioning/spec.ocp +++ b/specifications/device-identity-provisioning/spec.ocp @@ -193,16 +193,11 @@ Some devices may not support the generation of self-signed CSRs for certain keys ![Envelope-signed Non-self-signed CSR](./diagrams/envelope_signed_csr_non_self_signed.drawio.svg){#fig:envelope-signed-csr-non-self-signed} -This specification provides a definition for a vendor-defined SPDM command, utilizing VENDOR_DEFINED_REQUEST from SPDM 1.3, which can be used to surface these envelope-signed CSRs. +**Transport**: These commands follow the transport bindings defined in [@{ocp-command-registry}]. -GET_ENVELOPE_SIGNED_CSR request and ENVELOPE_SIGNED_CSR response messages are transported as follows: +### GET_ENVELOPE_SIGNED_CSR command -- The Requester must use the SPDM VENDOR_DEFINED_REQUEST format -- The Responder must use the SPDM VENDOR_DEFINED_RESPONSE format -- The StandardID field of VENDOR_DEFINED_REQUEST and VENDOR_DEFINED_RESPONSE message must contain 4 (the value assigned in SPDM to identify IANA). -- The VendorID field of VENDOR_DEFINED_REQUEST and VENDOR_DEFINED_RESPONSE message must contain 42623 (the value assigned in IANA to identify Open Compute Project). -- The first byte of the VendorDefinedReqPayload/VendorDefinedRespPayload is the Command Code, and must contain the value 01h to indicate GET_ENVELOPE_SIGNED_CSR / ENVELOPE_SIGNED_CSR. -- The GET_ENVELOPE_SIGNED_CSR request and ENVELOPE_SIGNED_CSR response forms the payload in the VendorDefinedReqPayload and VendorDefinedRespPayload respectively, defined in Tables [-@tbl:ecsr-req] and [-@tbl:ecsr-resp]. +This command returns an envelope-signed Certificate Signing Request (CSR) that conveys the key derivation properties of the requested identity key, enabling PKI owners to make informed decisions when issuing certificates based on how the key was derived. Table: GET_ENVELOPE_SIGNED_CSR VendorDefinedReqPayload {#tbl:ecsr-req} @@ -245,6 +240,8 @@ Table: GET_ENVELOPE_SIGNED_CSR VendorDefinedReqPayload {#tbl:ecsr-req} | | | | CSR envelope. If the Responder’s public key | | | | | was provisioned to the Requester previously, | | | | | this field shall be 0xF. | +| | | | For non-SPDM implementations, bits [3:0] | +| | | | are DNC. | +---------------------+---------------------+---------------------+----------------------------------------------+ | 13 | Nonce | 32 | The Requester should choose a random | | | | | value. | @@ -281,22 +278,25 @@ Table: ENVELOPE_SIGNED_CSR VendorDefinedRespPayload {#tbl:ecsr-resp} | Byte | Field | Size (bytes) | Description | | offset | | | | +========+=========================+=========================+==========================================+ -| 0 | CommandVersion | 1 | The version of this request structure. | +| 0 | CommandVersion | 1 | The version of this response structure. | | | | | Shall be zero. | +--------+-------------------------+-------------------------+------------------------------------------+ | 1 | CommandCode | 1 | Shall be 01h to indicate | | | | | ENVELOPE_SIGNED_CSR. | +--------+-------------------------+-------------------------+------------------------------------------+ -| 2 | Reserved | 4 | Reserved. | +| 2 | Reserved | 2 | Reserved. | +--------+-------------------------+-------------------------+------------------------------------------+ -| 6 | EnvelopeSignedCSRLength | 2 | Shall be the length of the | +| 4 | EnvelopeSignedCSRLength | 2 | Shall be the length of the | | | | | EnvelopeSignedCSRdata in bytes. | +| | | | Zero if status is not success. | +--------+-------------------------+-------------------------+------------------------------------------+ -| 8 | EnvelopeSignedCSRdata | EnvelopeSignedCSRLength | Shall be the requested contents of the | +| 6 | EnvelopeSignedCSRdata | EnvelopeSignedCSRLength | Shall be the requested contents of the | | | | | envelope-signed CSR. This field shall be | -| | | | CBOR-encoded. | +| | | | CBOR-encoded. Present only if status | +| | | | is success. | +--------+-------------------------+-------------------------+------------------------------------------+ + The EnvelopeSignedCSRdata shall adhere to the following requirements: - The payload SHALL be an EAT encoded as a CBOR Web Token (CWT) [@{ietf-cwt}]. @@ -334,22 +334,58 @@ Subsequent versions of this specification may be expanded with additional key de ## Issuing and provisioning an identity certificate {#sec:issuing-and-provisioning-identity-cert} -After establishing trust in a device's identity keypair through the envelope-signed CSR mechanism, a PKI owner can issue and provision an identity certificate to the device. This specification defines a standardized approach using OCP-specific extensions transported via SPDM's VENDOR_DEFINED_REQUEST mechanism. +After establishing trust in a device's identity keypair through the envelope-signed CSR mechanism, a PKI owner can issue and provision an identity certificate to the device. This specification defines OCP-specific commands for certificate provisioning. ### Certificate provisioning overview -Identity certificates are provisioned to devices using the OCP-specific `OCP_SET_ENDORSEMENT` command. The PKI owner provisions their endorsement chain (excluding the LEAF certificate) to a specific slot on the device. +When a PKI owner issues an identity certificate for a device key (such as IDevID or LDevID), they provision a certificate chain to the device that includes the PKI-issued identity certificate for the device key. + +**Certificate chain requirements**: When provisioning certificate chains via `OCP_SET_ENDORSEMENT`: + +1. **The chain SHALL terminate with a certificate for an advertised identity keypair** - The end-entity certificate in the chain MUST correspond to one of the keypairs for which the device can generate CSRs (e.g., IDevID, LDevID, or other device-specific identity keys). + +2. **Chain validation** - The device SHALL validate that: + - The public key in the terminal certificate matches a keypair that the device advertises via CSR capabilities + - The certificate chain is well-formed (proper DER encoding, valid signatures where verifiable) + - Note: When only a single certificate is provisioned (the identity certificate itself), the device cannot validate the complete chain to a root. This is expected and valid. + +3. **CSR advertisement policy** - Devices SHALL NOT advertise CSRs for ephemeral or leaf keys (e.g., TLS server keys, attestation signing keys that are generated per-session). + +This approach ensures that only identity certificates can be provisioned, as those are the only keys for which CSRs are available. -**Important**: This specification mandates that LEAF certificates (the identity certificates themselves) are NOT included in the provisioned certificate chains. The separation between endorsement chains and LEAF certificates ensures: +**Certificate chain composition**: When provisioning via `OCP_SET_ENDORSEMENT`, the certificate chain MAY include: +- The PKI-issued identity certificate for the device key (required - this is the terminal certificate) +- Optionally, any intermediate CA certificates +- Optionally, the root CA certificate -- Multiple use cases (attestation, secure sessions) can use different LEAF certificates while sharing the same endorsement point -- The endorsement chain remains stable even as LEAF certificates may change based on key derivation inputs + +**Important**: While devices may expose CSRs for various keys in their hierarchy, endorsement chains provisioned via `OCP_SET_ENDORSEMENT` SHALL NOT include LEAF certificates. This ensures that endorsements work across different use cases (e.g., attestation, secure sessions) since each use case may have different LEAF certificates while sharing the same endorsement chain. + +**Certificate chain composition**: When provisioning via `OCP_SET_ENDORSEMENT`, the certificate chain SHALL include: +- The PKI-issued identity certificate for the device key (e.g., the LDevID certificate issued by the owner's PKI) +- Optionally, any intermediate CA certificates +- Optionally, the root CA certificate + +### Understanding slots + +In this specification, a "slot" refers to a storage location within the device that holds a certificate chain. This concept directly maps to SPDM's certificate slot mechanism: + +- **SPDM context**: SPDM defines 8 possible slots (0-7) where certificate chains can be stored. When an SPDM requester invokes `GET_CERTIFICATE`, they specify which slot's certificate chain they want to retrieve. + +- **Attestation context**: During attestation, the device uses these certificate chains to establish trust. For example, when generating an EAT, the device may include a LEAF certificate that chains to one of the certificates stored in these slots. The verifier can then retrieve the appropriate certificate chain to validate the complete trust path. + +- **OCP abstraction**: While SPDM uses numeric slot IDs (0-7), the OCP commands abstract this using Key Provisioning Entity identifiers (VENDOR, OWNER, TENANT). The device internally maps these entities to specific slot numbers, which can be discovered via `OCP_GET_SLOT_ID_MAPPING`. + +This abstraction allows: +- Consistent semantics across different device implementations +- Devices to optimize their internal slot allocation +- Compatibility with both SPDM and non-SPDM attestation flows ### Slot allocation and management Devices implementing this specification SHALL support certificate slot allocation with the following requirements: -- **Minimum requirement**: Devices MUST reserve at least 2 slots for OCP provisioning (one for platform owner, one for tenant) +- **Minimum requirement**: Devices MUST present at least three slots for attestation (vendor, owner, tenant), and MUST support in-field provisioning of certificates for the latter two (owner, tenant). - **Vendor flexibility**: The specific slot numbers are determined by the device vendor and discovered via `OCP_GET_SLOT_ID_MAPPING` - **Total slots**: SPDM supports up to 8 slots (0-7), with the allocation between vendor and OCP use defined by the vendor @@ -361,33 +397,32 @@ Example allocation (vendor-specific): **Important**: The actual slot mapping is vendor-defined and discovered at runtime. The device SHALL return an error if attempts are made to provision more slots than physically supported -### OCP extensions for certificate management - -To address the needs of heterogeneous environments where devices may support both SPDM and non-SPDM attestation paths, this specification defines OCP-specific commands transported via SPDM's VENDOR_DEFINED_REQUEST mechanism. +#### Key Provisioning Entity Registry -**Transport flexibility**: While this specification defines these commands as SPDM vendor-defined messages, devices that do not support SPDM MAY implement these same commands over alternative transport mechanisms. The definition of transport bindings for non-SPDM attesters is outside the scope of this specification. Regardless of transport, the command and response payload formats defined in this specification SHALL be preserved. +The following Key Provisioning Entity values are defined and SHALL be used consistently across all OCP certificate management commands: -#### Key Provisioning Entity Enumeration +Table: Key Provisioning Entity Values {#tbl:key-provisioning-entity} -The following Key Provisioning Entity values are defined: ++--------+----------+--------------------------------------------------+ +| Value | Name | Description | ++========+==========+==================================================+ +| 0x00 | VENDOR | Vendor-provisioned endorsements | +| | | (typically pre-installed) | ++--------+----------+--------------------------------------------------+ +| 0x01 | OWNER | Platform owner-provisioned endorsements | ++--------+----------+--------------------------------------------------+ +| 0x02 | TENANT | Tenant-provisioned endorsements | +| | | in bare metal scenarios | ++--------+----------+--------------------------------------------------+ +| 0x03- | Reserved | Reserved for future use | +| 0xFF | | | ++--------+----------+--------------------------------------------------+ -- **VENDOR** (0x00): Vendor-provisioned endorsements (typically pre-installed) -- **OWNER** (0x01): Platform owner-provisioned endorsements -- **TENANT** (0x02): Tenant-provisioned endorsements in bare metal scenarios Future versions of this specification may define additional entity values. -#### OCP_GET_SLOT_ID_MAPPING command (Informational) +#### OCP_GET_SLOT_ID_MAPPING command -This command is provided for informational purposes, primarily for devices that also support SPDM. It allows callers to understand which SPDM slot corresponds to each Key Provisioning Entity. - -GET_SLOT_ID_MAPPING request and SLOT_ID_MAPPING response messages are transported as follows: - -- The Requester must use the SPDM VENDOR_DEFINED_REQUEST format -- The Responder must use the SPDM VENDOR_DEFINED_RESPONSE format -- The StandardID field of VENDOR_DEFINED_REQUEST and VENDOR_DEFINED_RESPONSE message must contain 4 (the value assigned in SPDM to identify IANA). -- The VendorID field of VENDOR_DEFINED_REQUEST and VENDOR_DEFINED_RESPONSE message must contain 42623 (the value assigned in IANA to identify Open Compute Project). -- The first byte of the VendorDefinedReqPayload/VendorDefinedRespPayload is the Command Code, and must contain the value 03h to indicate GET_SLOT_ID_MAPPING / SLOT_ID_MAPPING. -- The GET_SLOT_ID_MAPPING request and SLOT_ID_MAPPING response forms the payload in the VendorDefinedReqPayload and VendorDefinedRespPayload respectively, defined in Tables [-@tbl:slot-mapping-req] and [-@tbl:slot-mapping-resp]. +This is an informational command that returns the mapping between Key Provisioning Entities (VENDOR, OWNER, TENANT) and SPDM slot numbers. It enables interoperability between OCP entity-based commands and SPDM slot-based commands on devices that support both SPDM and non-SPDM attesters. Table: GET_SLOT_ID_MAPPING VendorDefinedReqPayload {#tbl:slot-mapping-req} @@ -422,62 +457,51 @@ Table: SLOT_ID_MAPPING VendorDefinedRespPayload {#tbl:slot-mapping-resp} +--------+-------------------------+-------------------------+------------------------------------------+ | 7 | Reserved | 1 | Reserved. | +--------+-------------------------+-------------------------+------------------------------------------+ -| 8 | MappingTable | MappingCount * 2 | Array of mappings. Each entry | +| 8 | MappingTable | MappingCount * 2 | Array of mappings. Each entry | | | | | consists of: | | | | | - KeyProvisioningEntity (1 byte) | | | | | - SlotID (1 byte) | +--------+-------------------------+-------------------------+------------------------------------------+ -**Note**: The `OCP_GET_SLOT_ID_MAPPING` command is informational only. Devices that support both OCP and SPDM commands use this to report which SPDM slot corresponds to each Key Provisioning Entity. This allows SPDM requesters to understand the side effects of `OCP_SET_ENDORSEMENT` operations. - #### OCP_SET_ENDORSEMENT command -SET_ENDORSEMENT request and SET_ENDORSEMENT response messages are transported as follows: - -- The Requester must use the SPDM VENDOR_DEFINED_REQUEST format -- The Responder must use the SPDM VENDOR_DEFINED_RESPONSE format -- The StandardID field of VENDOR_DEFINED_REQUEST and VENDOR_DEFINED_RESPONSE message must contain 4 (the value assigned in SPDM to identify IANA). -- The VendorID field of VENDOR_DEFINED_REQUEST and VENDOR_DEFINED_RESPONSE message must contain 42623 (the value assigned in IANA to identify Open Compute Project). -- The first byte of the VendorDefinedReqPayload/VendorDefinedRespPayload is the Command Code, and must contain the value 04h to indicate SET_ENDORSEMENT. -- The SET_ENDORSEMENT request and SET_ENDORSEMENT response forms the payload in the VendorDefinedReqPayload and VendorDefinedRespPayload respectively, defined in Tables [-@tbl:set-endorsement-req] and [-@tbl:set-endorsement-resp]. - Table: SET_ENDORSEMENT VendorDefinedReqPayload {#tbl:set-endorsement-req} -+---------------------+---------------------+---------------------+----------------------------------------------+ -| Byte offset | Field | Size (bytes) | Description | -+=====================+=====================+=====================+==============================================+ -| 0 | CommandVersion | 1 | The version of this request structure. | -| | | | Shall be zero. | -+---------------------+---------------------+---------------------+----------------------------------------------+ -| 1 | CommandCode | 1 | Shall be 04h to indicate | -| | | | SET_ENDORSEMENT. | -+---------------------+---------------------+---------------------+----------------------------------------------+ -| 2 | Reserved | 4 | Reserved. | -+---------------------+---------------------+---------------------+----------------------------------------------+ -| 6 | KeyProvisioningEntity| 1 | Entity for which to set endorsement: | -| | | | - 00h: VENDOR | -| | | | - 01h: OWNER | -| | | | - 02h: TENANT | -| | | | Other values reserved. | -+---------------------+---------------------+---------------------+----------------------------------------------+ -| 7 | Flags | 1 | - Bit [7:1]: Reserved. | -| | | | - Bit [0]: FORCE flag. | -| | | | If set to 1, allows overwriting an | -| | | | existing endorsement. | -| | | | If set to 0, returns error if | -| | | | already provisioned. | -+---------------------+---------------------+---------------------+----------------------------------------------+ -| 8 | KeyID | 1 | Key identifier for certificate selection. | -| | | | Usage is vendor-specific. | -+---------------------+---------------------+---------------------+----------------------------------------------+ -| 9 | Reserved | 1 | Reserved. | -+---------------------+---------------------+---------------------+----------------------------------------------+ -| 10 | CertChainLength | 2 | Length of the certificate chain in bytes. | -| | | | Shall not exceed device capabilities. | -+---------------------+---------------------+---------------------+----------------------------------------------+ -| 12 | CertChain | CertChainLength | DER-encoded certificate chain. | -| | | | Shall NOT include LEAF certificate. | -+---------------------+---------------------+---------------------+----------------------------------------------+ ++---------------------+----------------------+---------------------+----------------------------------------------+ +| Byte offset | Field | Size (bytes) | Description | ++=====================+======================+=====================+==============================================+ +| 0 | CommandVersion | 1 | The version of this request structure. | +| | | | Shall be zero. | ++---------------------+----------------------+---------------------+----------------------------------------------+ +| 1 | CommandCode | 1 | Shall be 04h to indicate | +| | | | SET_ENDORSEMENT. | ++---------------------+----------------------+---------------------+----------------------------------------------+ +| 2 | Reserved | 4 | Reserved. | ++---------------------+----------------------+---------------------+----------------------------------------------+ +| 6 | KeyProvisioningEntity| 1 | Entity for which to set the endorsement. | +| | | | See @tbl:key-provisioning-entity. | ++---------------------+----------------------+---------------------+----------------------------------------------+ +| 7 | Flags | 1 | - Bit [7:1]: Reserved. | +| | | | - Bit [0]: FORCE flag. | +| | | | If set to 1, allows overwriting an | +| | | | existing endorsement. | +| | | | If set to 0, returns error if | +| | | | already provisioned. | ++---------------------+----------------------+---------------------+----------------------------------------------+ +| 8 | KeyPairID | 1 | Key identifier for certificate selection. | +| | | | Usage is vendor-specific. | ++---------------------+----------------------+---------------------+----------------------------------------------+ +| 9 | Reserved | 1 | Reserved. | ++---------------------+----------------------+---------------------+----------------------------------------------+ +| 10 | CertChainLength | 2 | Length of the certificate chain in bytes. | +| | | | Shall not exceed device capabilities. | ++---------------------+----------------------+---------------------+----------------------------------------------+ +| 12 | CertChain | CertChainLength | DER-encoded certificate chain. | +| | | | Terminal certificate MUST match an | +| | | | advertised identity keypair. | +| | | | Device SHALL return INVALID_PARAMETER | +| | | | if no match is found | ++---------------------+----------------------+---------------------+----------------------------------------------+ Table: SET_ENDORSEMENT VendorDefinedRespPayload {#tbl:set-endorsement-resp} @@ -491,52 +515,30 @@ Table: SET_ENDORSEMENT VendorDefinedRespPayload {#tbl:set-endorsement-resp} | 1 | CommandCode | 1 | Shall be 04h to indicate | | | | | SET_ENDORSEMENT. | +--------+-------------------------+-------------------------+------------------------------------------+ -| 2 | Reserved | 4 | Reserved. | +| 2 | Reserved | 2 | Reserved. | +--------+-------------------------+-------------------------+------------------------------------------+ -| 6 | Status | 1 | Status code: | -| | | | - 00h: Success | -| | | | - 01h: Invalid entity | -| | | | - 02h: Entity already provisioned | -| | | | - 03h: Invalid chain | -| | | | - 04h: Chain too long | -| | | | - 05h: Insufficient resources | -| | | | - FFh: General failure | -+--------+-------------------------+-------------------------+------------------------------------------+ -| 7 | Reserved | 1 | Reserved. | -+--------+-------------------------+-------------------------+------------------------------------------+ - -#### OCP_GET_ENDORSEMENT command -GET_ENDORSEMENT request and GET_ENDORSEMENT response messages are transported as follows: -- The Requester must use the SPDM VENDOR_DEFINED_REQUEST format -- The Responder must use the SPDM VENDOR_DEFINED_RESPONSE format -- The StandardID field of VENDOR_DEFINED_REQUEST and VENDOR_DEFINED_RESPONSE message must contain 4 (the value assigned in SPDM to identify IANA). -- The VendorID field of VENDOR_DEFINED_REQUEST and VENDOR_DEFINED_RESPONSE message must contain 42623 (the value assigned in IANA to identify Open Compute Project). -- The first byte of the VendorDefinedReqPayload/VendorDefinedRespPayload is the Command Code, and must contain the value 05h to indicate GET_ENDORSEMENT. -- The GET_ENDORSEMENT request and GET_ENDORSEMENT response forms the payload in the VendorDefinedReqPayload and VendorDefinedRespPayload respectively, defined in Tables [-@tbl:get-endorsement-req] and [-@tbl:get-endorsement-resp]. +#### OCP_GET_ENDORSEMENT command Table: GET_ENDORSEMENT VendorDefinedReqPayload {#tbl:get-endorsement-req} -+---------------------+---------------------+---------------------+----------------------------------------------+ -| Byte offset | Field | Size (bytes) | Description | -+=====================+=====================+=====================+==============================================+ -| 0 | CommandVersion | 1 | The version of this request structure. | -| | | | Shall be zero. | -+---------------------+---------------------+---------------------+----------------------------------------------+ -| 1 | CommandCode | 1 | Shall be 05h to indicate | -| | | | GET_ENDORSEMENT. | -+---------------------+---------------------+---------------------+----------------------------------------------+ -| 2 | Reserved | 4 | Reserved. | -+---------------------+---------------------+---------------------+----------------------------------------------+ -| 6 | KeyProvisioningEntity| 1 | Entity from which to get endorsement: | -| | | | - 00h: VENDOR | -| | | | - 01h: OWNER | -| | | | - 02h: TENANT | -| | | | Other values reserved. | -+---------------------+---------------------+---------------------+----------------------------------------------+ -| 7 | Reserved | 1 | Reserved. | -+---------------------+---------------------+---------------------+----------------------------------------------+ ++---------------------+----------------------+---------------------+----------------------------------------------+ +| Byte offset | Field | Size (bytes) | Description | ++=====================+======================+=====================+==============================================+ +| 0 | CommandVersion | 1 | The version of this request structure. | +| | | | Shall be zero. | ++---------------------+----------------------+---------------------+----------------------------------------------+ +| 1 | CommandCode | 1 | Shall be 05h to indicate | +| | | | GET_ENDORSEMENT. | ++---------------------+----------------------+---------------------+----------------------------------------------+ +| 2 | Reserved | 4 | Reserved. | ++---------------------+----------------------+---------------------+----------------------------------------------+ +| 6 | KeyProvisioningEntity| 1 | Entity from which to get endorsement. | +| | | | See @tbl:key-provisioning-entity. | ++---------------------+----------------------+---------------------+----------------------------------------------+ +| 7 | Reserved | 1 | Reserved. | ++---------------------+----------------------+---------------------+----------------------------------------------+ Table: GET_ENDORSEMENT VendorDefinedRespPayload {#tbl:get-endorsement-resp} @@ -552,18 +554,12 @@ Table: GET_ENDORSEMENT VendorDefinedRespPayload {#tbl:get-endorsement-resp} +--------+-------------------------+-------------------------+------------------------------------------+ | 2 | Reserved | 4 | Reserved. | +--------+-------------------------+-------------------------+------------------------------------------+ -| 6 | Status | 1 | Status code: | -| | | | - 00h: Success | -| | | | - 01h: Invalid entity | -| | | | - 02h: Entity not provisioned | -| | | | - FFh: General failure | +| 6 | Reserved | 1 | Reserved. | +--------+-------------------------+-------------------------+------------------------------------------+ -| 7 | Reserved | 1 | Reserved. | -+--------+-------------------------+-------------------------+------------------------------------------+ -| 8 | CertChainLength | 2 | Length of the certificate chain. | +| 7 | CertChainLength | 2 | Length of the certificate chain. | | | | | Zero if status is not success. | +--------+-------------------------+-------------------------+------------------------------------------+ -| 10 | CertChain | CertChainLength | DER-encoded certificate chain. | +| 9 | CertChain | CertChainLength | DER-encoded certificate chain. | | | | | Does NOT include LEAF certificate. | | | | | Present only if status is success. | +--------+-------------------------+-------------------------+------------------------------------------+ @@ -574,7 +570,7 @@ A typical provisioning workflow follows these steps: 1. **CSR Generation**: The PKI owner requests an envelope-signed CSR for their chosen identity key using `GET_ENVELOPE_SIGNED_CSR` 2. **Certificate Issuance**: The PKI owner validates the CSR and issues an identity certificate -3. **Chain Provisioning**: The PKI owner provisions their endorsement chain (excluding the newly issued LEAF certificate) using `OCP_SET_ENDORSEMENT` with the appropriate KeyProvisioningEntity value +3. **Chain Provisioning**: The PKI owner provisions their endorsement chain using `OCP_SET_ENDORSEMENT` with the appropriate KeyProvisioningEntity value 4. **Verification**: The PKI owner can verify successful provisioning by retrieving the chain using `OCP_GET_ENDORSEMENT` For SPDM-aware implementations: @@ -596,46 +592,75 @@ This approach simplifies the interface by abstracting slot management while main When provisioning certificate chains, devices SHALL validate: -- The certificate chain is properly formed and each certificate correctly signs the next -- The chain terminates at a self-signed root or a certificate that can be verified against pre-existing trust anchors -- All certificates in the chain are within their validity periods -- The certificate chain length does not exceed device storage capabilities +- The terminal certificate's public key matches an advertised identity keypair +- All certificates in the chain are properly DER-encoded +- When multiple certificates are present, each certificate correctly signs the next +- Basic certificate field validation (e.g., version, serial number presence) + +Devices SHALL NOT require: +- A complete chain to a trust anchor (the PKI owner may provision only the identity certificate) +- The presence of a self-signed root certificate +- Certificate validity period checking (as devices may not have reliable time sources) + +Upon receiving a SET_ENDORSEMENT command, the device SHALL: + +1. Parse the certificate chain starting from the last certificate (terminal certificate) +2. Extract the public key from the terminal certificate +3. Verify that this public key matches one of the device's identity keypairs for which it can generate CSRs +4. If no match is found, return INVALID_PARAMETER error +5. Perform basic certificate validation: + - Verify proper DER encoding for all certificates + - If multiple certificates are present, verify that each certificate properly signs the next Devices MAY additionally validate: +- Certificate validity periods if a reliable time source is available -- Certificate revocation status if CRL or OCSP information is available -- Certificate policy OIDs match expected values for the entity being provisioned ### Error handling -The following error conditions SHALL be reported: +This specification uses error codes defined in the [@{ocp-command-registry}]. The following error conditions are specifically relevant to certificate provisioning operations: + +#### GET_ENVELOPE_SIGNED_CSR errors + +- **INVALID_PARAMETER (0x02)**: Invalid KeyPairID format, malformed SignerSlotIDParam, or invalid Request Attributes +- **INVALID_LENGTH (0x03)**: RequesterInfoLength or OpaqueDataLength exceeds limits +- **INVALID_IDENTIFIER (0x04)**: Requested KeyPairID not found, or SignerSlotIDParam references a non-existent or unprovisioned slot +- **DEVICE_NOT_READY (0x08)**: Device cannot generate CSR in current state + +#### Certificate provisioning errors (SET_ENDORSEMENT) + +- **INVALID_PARAMETER (0x02)**: Invalid KeyProvisioningEntity value +- **INVALID_LENGTH (0x03)**: Certificate chain exceeds device storage capacity +- **INSUFFICIENT_RESOURCES (0x06)**: Device lacks resources to complete the operation +- **POLICY_VIOLATION (0x0E)**: + - Attempting to provision an entity that already has an endorsement when FORCE flag is not set +- **INVALID_STATE (0x0F)**: Certificate chain validation failed + +#### Certificate retrieval errors (GET_ENDORSEMENT) + +- **INVALID_PARAMETER (0x02)**: Invalid KeyProvisioningEntity value +- **RESOURCE_UNAVAILABLE (0x0D)**: Attempting to retrieve endorsement for an entity that has not been provisioned + +Implementations SHALL use these standardized error codes to ensure consistent error reporting across different devices. -- **ENTITY_ALREADY_PROVISIONED**: Attempting to provision an entity that already has an endorsement when FORCE flag is not set -- **INVALID_ENTITY**: Specified KeyProvisioningEntity value is not supported -- **CHAIN_TOO_LONG**: Certificate chain exceeds device storage capacity -- **INVALID_CHAIN**: Certificate chain validation failed -- **INSUFFICIENT_RESOURCES**: Device lacks resources to complete the operation -- **ENTITY_NOT_PROVISIONED**: Attempting to retrieve endorsement for an entity that has not been provisioned ### Security considerations #### Protection of provisioning operations -Certificate provisioning operations SHOULD be performed over authenticated and encrypted channels: - -- For SPDM paths: Use SPDM secured messages when available -- For out-of-band provisioning: Use platform-specific secure channels +Certificate provisioning SHALL be performed over an authorized channel. The details of authorization are vendor-defined and deployment-specific. #### Entity update policy -To prevent unauthorized certificate replacement: - -- Devices MAY implement policies restricting certificate updates based on: - - Physical presence assertions - - Platform ownership state - - Secure boot state +**Update protection:** - Once provisioned, entities SHALL NOT be overwritable without the FORCE flag being explicitly set -- When FORCE flag is used to overwrite an existing endorsement, devices SHOULD log this as a security-relevant event +- Devices MAY implement additional restrictions even when FORCE flag is set, based on their authorization policy + +**Channel considerations:** +- The transport channel SHOULD provide integrity protection to prevent tampering with certificates during provisioning +- Confidentiality MAY be required depending on whether the certificates contain sensitive information + +Implementations SHALL document their authorization requirements. #### Certificate lifecycle management @@ -668,19 +693,20 @@ Devices that only support OCP commands (not SPDM): - MAY omit implementation of `OCP_GET_SLOT_ID_MAPPING` - SHALL still support all KeyProvisioningEntity values defined in this specification -- Focus on entity-based access without exposing slot details +- Focus solely on entity-based access (VENDOR, OWNER, TENANT) without any slot abstraction +- For `GET_ENVELOPE_SIGNED_CSR`, the SignerSlotIDParam bits [3:0] are DNC ### Example provisioning sequence Here's a complete example of a platform owner provisioning their endorsement chain: -1. **BMC → Device**: `GET_ENVELOPE_SIGNED_CSR(KeyPairID=LDevID, SlotID=0, Nonce)` +1. **BMC → Device**: `GET_ENVELOPE_SIGNED_CSR(KeyPairID=LDevID, SignerSlotIDParam=0, Nonce)` - **Device → BMC**: `EAT{CSR for LDevID, signed by IDevID}` + **Device → BMC**: `EAT{CSR for LDevID, LDEVID Key Derivation Attributes(OIDs), Nonce}` 2. **BMC validates CSR and issues certificate for LDevID** -3. **BMC → Device**: `OCP_SET_ENDORSEMENT(KeyProvisioningEntity=OWNER, Flags=0, KeyID, OwnerEndorsementChain)` +3. **BMC → Device**: `OCP_SET_ENDORSEMENT(KeyProvisioningEntity=OWNER, Flags=0, KeyPairID=LDevID, OwnerEndorsementChain)` **Device → BMC**: `Status=SUCCESS` @@ -701,7 +727,7 @@ TODO: fill in additional details. ## Requesting an identity certificate during attestation {#sec:requesting-identity-cert-during-attestation} -This will be accomplished by selecting the correct `SlotIDParam` when invoking SPDM commands. +This will be accomplished by selecting the correct `SignerSlotIDParam` when invoking SPDM commands. TODO: fill in additional details. From 7ec11f40f9a64c9592982c909132b6d4b12e73c3 Mon Sep 17 00:00:00 2001 From: Fabrizio Damato Date: Tue, 2 Dec 2025 20:22:23 -0800 Subject: [PATCH 4/5] Device Identity Provisioning: Update Details on EAT response to GET_ENVELOPE_SIGNED_CSR Signed-off-by: Fabrizio Damato --- .../cddl/envelope-signed-csr-eat.cddl | 3 - .../diag/envelope-signed-csr-eat-example.diag | 6 +- .../device-identity-provisioning/spec.ocp | 55 +++++++++++++------ 3 files changed, 41 insertions(+), 23 deletions(-) diff --git a/specifications/device-identity-provisioning/cddl/envelope-signed-csr-eat.cddl b/specifications/device-identity-provisioning/cddl/envelope-signed-csr-eat.cddl index c47acb9..5c7cd07 100644 --- a/specifications/device-identity-provisioning/cddl/envelope-signed-csr-eat.cddl +++ b/specifications/device-identity-provisioning/cddl/envelope-signed-csr-eat.cddl @@ -1,7 +1,4 @@ cwt-envelope-signed-csr-eat = { - ; Issuer claim is StringOrURI (tstr) - &(iss : 1) => tstr - ; Nonce claim is nonce-type = bstr .size (8..64) ? &(nonce : 10) => bstr diff --git a/specifications/device-identity-provisioning/diag/envelope-signed-csr-eat-example.diag b/specifications/device-identity-provisioning/diag/envelope-signed-csr-eat-example.diag index c8b3613..3fbb2eb 100644 --- a/specifications/device-identity-provisioning/diag/envelope-signed-csr-eat-example.diag +++ b/specifications/device-identity-provisioning/diag/envelope-signed-csr-eat-example.diag @@ -1,12 +1,10 @@ signed-cwt / 18([ / protected / <<{ / alg-id / 1 : 7, - / content-type / 3 : "application/eat+cbor", - / kid / 4 : 'RT Alias Key' + / content-type / 3 : "application/eat+cwt", + / issuer-key-id / 4 : 'RT Alias Key' }>>, -/ unprotected / {/ x5-chain / 33 : h'59025630820252308201d9a003020102021431a4ef62e5244e4d952ea485976098090d5f242f300a06082a8648ce3d040303307b310b30090603550406130255533113301106035504080c0a43616c69666f726e69613116301406035504070c0d53616e204672616e636973636f311d301b060355040a0c144578616d706c65204f7267616e697a6174696f6e3120301e06035504030c174578616d706c652043575420456e646f7273656d656e74301e170d3235303231333139303230345a170d3236303231343139303230345a307b310b30090603550406130255533113301106035504080c0a43616c69666f726e69613116301406035504070c0d53616e204672616e636973636f311d301b060355040a0c144578616d706c65204f7267616e697a6174696f6e3120301e06035504030c174578616d706c652043575420456e646f7273656d656e743076301006072a8648ce3d020106052b8104002203620004fcd3fad48575addceee9638583aa7054f71a402f35993901923cc0ee9763b85b1e729c740331f4e91079559bce17d5c3b706748333faeb192120e32d815f88f7310ae05df55060f96fbdb2d0acb19e710d25ec27cfa8945fe5dda73332813feda31e301c301a0603551d1104133011820f7777772e6578616d706c652e636f6d300a06082a8648ce3d040303036700306402306e1166a8a3132d4a20e0200a26d1eba0937fec54fdb7547eb7c5ccca0370170853294cdd6b3a1eb0fe649f12446d8b17023071219daf2b7c1aa6f7727d053e1027309594fd8cab9f820fa89d8f88fc7e551c0d30781b12aea48b53fde200e6cf082b' }, / payload / <<{ - / iss / 1 : "RT Alias Key", / nonce / 10: h'AAAABBBBAAAABBBBAAAABBBB', / csr / -70001 : h'59025630820252308201d9a003020102021431a4e0', / attrib / -70002: [ diff --git a/specifications/device-identity-provisioning/spec.ocp b/specifications/device-identity-provisioning/spec.ocp index ebbb069..c7a385f 100644 --- a/specifications/device-identity-provisioning/spec.ocp +++ b/specifications/device-identity-provisioning/spec.ocp @@ -230,14 +230,11 @@ Table: GET_ENVELOPE_SIGNED_CSR VendorDefinedReqPayload {#tbl:ecsr-req} | | | | bytes. Shall be 0 if no OpaqueData is | | | | | provided. | +---------------------+---------------------+---------------------+----------------------------------------------+ -| 12 | SignerSlotIDParam | 1 | - Bit [7:5]. Reserved. | -| | | | - Bit [4:4]. If this value is `1`, the CSR | -| | | | envelope is signed; otherwise the envelope | -| | | | is unsigned, and bits [3:0] are ignored. | +| 12 | SignerSlotIDParam | 1 | - Bit [7:4]. Reserved. | | | | | - Bit [3:0]. Shall be the SlotID. Slot | | | | | number of the Responder certificate chain | | | | | that shall be used for authenticating the | -| | | | CSR envelope. If the Responder’s public key | +| | | | CSR envelope. If the Responder's public key | | | | | was provisioned to the Requester previously, | | | | | this field shall be 0xF. | | | | | For non-SPDM implementations, bits [3:0] | @@ -317,8 +314,6 @@ The EnvelopeSignedCSRdata shall adhere to the following requirements: **OCP Security Branch**: `ocp-security OBJECT IDENTIFIER ::= {1 3 6 1 4 1 42623 1}` -**Envelope-signed EAT profile OID**: `ocp-security-dip-eat-profile OBJECT IDENTIFIER ::= {ocp-security 1}` - **Key Derivation Attribute OID Branch**: `ocp-security-dip-kda OBJECT IDENTIFIER ::= {ocp-security 2}` The following OIDs are defined for key derivation attributes: @@ -332,6 +327,42 @@ These OIDs indicate which inputs contribute to the derivation of the identity ke Subsequent versions of this specification may be expanded with additional key derivation attribute OIDs. +#### Envelope-Signed CSR EAT Profile + +This specification defines a partial EAT profile for use in the GET_ENVELOPE_SIGNED_CSR response. This is not a complete EAT profile as defined in RFC 9711 because: + +1. It does not prescribe specific cryptographic algorithms +2. It is only used as a response to the GET_ENVELOPE_SIGNED_CSR command +3. It does not define all aspects required for a full profile + +Therefore, no EAT Profile OID is assigned for this usage. + +**Required EAT Claims:** + +The EAT contained in EnvelopeSignedCSRdata SHALL include the following claims: + +1. **Nonce claim (nonce: 10)** - A binary string between 8 and 64 bytes that MUST match the Nonce value provided in the GET_ENVELOPE_SIGNED_CSR request. This provides freshness and prevents replay attacks. + +2. **CSR claim (csr: -70001)** - A binary string containing the DER-encoded Certificate Signing Request. This may be either: + - A self-signed CSR where the signature is generated by the subject key + - A non-self-signed CSR where the signature field contains all zeroes + +3. **Key derivation attributes claim (attrib: -70002)** - An array of OIDs indicating which inputs contributed to the derivation of the identity key for which the CSR is being requested. Each OID is encoded according to CBOR OID encoding rules. + +**Signature Requirements:** + +The EAT SHALL be encoded as a signed CWT using COSE_Sign1. The signature provides authenticity and integrity for the CSR and its associated metadata. + +**Key Identification:** + +The COSE_Sign1 protected header SHALL include: +- **Algorithm identifier (alg: 1)** - Integer identifying the signature algorithm used +- **Content type (content-type: 3)** - Text string or integer indicating the content type (for EAT, this is typically "application/eat+cwt") +- **Key ID (issuer-key-id: 4)** - Binary string that MUST match the subject name of the certificate containing the public key that can verify the EAT signature + +For example, if the EAT is signed by the RT_Alias key, the kid should match the subject field of the RT_Alias certificate. + + ## Issuing and provisioning an identity certificate {#sec:issuing-and-provisioning-identity-cert} After establishing trust in a device's identity keypair through the envelope-signed CSR mechanism, a PKI owner can issue and provision an identity certificate to the device. This specification defines OCP-specific commands for certificate provisioning. @@ -349,18 +380,10 @@ When a PKI owner issues an identity certificate for a device key (such as IDevID - The certificate chain is well-formed (proper DER encoding, valid signatures where verifiable) - Note: When only a single certificate is provisioned (the identity certificate itself), the device cannot validate the complete chain to a root. This is expected and valid. -3. **CSR advertisement policy** - Devices SHALL NOT advertise CSRs for ephemeral or leaf keys (e.g., TLS server keys, attestation signing keys that are generated per-session). +3. **CSR advertisement policy** - Devices SHALL NOT advertise CSRs for ephemeral keys (e.g., TLS server keys, attestation signing keys that are generated per-session). This approach ensures that only identity certificates can be provisioned, as those are the only keys for which CSRs are available. -**Certificate chain composition**: When provisioning via `OCP_SET_ENDORSEMENT`, the certificate chain MAY include: -- The PKI-issued identity certificate for the device key (required - this is the terminal certificate) -- Optionally, any intermediate CA certificates -- Optionally, the root CA certificate - - -**Important**: While devices may expose CSRs for various keys in their hierarchy, endorsement chains provisioned via `OCP_SET_ENDORSEMENT` SHALL NOT include LEAF certificates. This ensures that endorsements work across different use cases (e.g., attestation, secure sessions) since each use case may have different LEAF certificates while sharing the same endorsement chain. - **Certificate chain composition**: When provisioning via `OCP_SET_ENDORSEMENT`, the certificate chain SHALL include: - The PKI-issued identity certificate for the device key (e.g., the LDevID certificate issued by the owner's PKI) - Optionally, any intermediate CA certificates From 6b9f6ba17a3d87a5d089919a81b2252caf741696 Mon Sep 17 00:00:00 2001 From: Fabrizio Damato Date: Tue, 2 Dec 2025 21:13:59 -0800 Subject: [PATCH 5/5] Small fix in the GetEnvelopeSignedCSR Signed-off-by: Fabrizio Damato --- specifications/device-identity-provisioning/spec.ocp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/specifications/device-identity-provisioning/spec.ocp b/specifications/device-identity-provisioning/spec.ocp index c7a385f..8d13947 100644 --- a/specifications/device-identity-provisioning/spec.ocp +++ b/specifications/device-identity-provisioning/spec.ocp @@ -266,7 +266,7 @@ The following fields should be treated identically as in GET_CSR from SPDM 1.3: The following fields present in this command are not present in GET_CSR: -- **SignerSlotIDParam** - defines which key signs the CSR envelope. +- **SignerSlotIDParam** - defines which key signs the CSR envelope (for SPDM Implementation). - **Nonce** - provides freshness. Table: ENVELOPE_SIGNED_CSR VendorDefinedRespPayload {#tbl:ecsr-resp} @@ -304,9 +304,7 @@ The EnvelopeSignedCSRdata shall adhere to the following requirements: - An array of OIDs representing the key's derivation attributes (see @sec:defined-oids for defined OIDs) - The CSR included in the EAT SHALL be DER-encoded and may be either self-signed or non-self-signed depending on device capabilities. For non-self-signed CSRs, the signature field SHALL contain all zeroes and be the same size as would be required for a valid signature using the subject key's algorithm. - The nonce claim SHALL match the nonce value provided in the GET_ENVELOPE_SIGNED_CSR request to ensure freshness. -- If SignerSlotIDParam indicates a signed envelope, the CWT SHALL be signed by an Attestation Key endorsed by the certificate chain corresponding to the specified SlotID. In addition, the unprotected header of the CWT SHALL contain the Attestation Key's certificate chain, including at least all certificates from the Attestation Key up to the identity certificate issued by the slot's PKI owner. - - E.g., Slot 0's certificate chain would extend at least to the vendor-endorsed certificate over IDevID. A separate slot's certificate chain would extend at least to the certificate issued by the slot's configured PKI owner. - - A device may report intermediate certificates for the slot's PKI owner if it is configured to do so. +- The CWT SHALL be signed by an Attestation Key. The EAT's protected header contains a key identifier (kid) that indicates which key signed the EAT, allowing verifiers to locate the appropriate certificate for verification. [^private-claims]: RFC 8392 [@{ietf-cwt}] defines a private claim as one whose key value has an integer value < -65536. @@ -356,6 +354,7 @@ The EAT SHALL be encoded as a signed CWT using COSE_Sign1. The signature provide **Key Identification:** The COSE_Sign1 protected header SHALL include: + - **Algorithm identifier (alg: 1)** - Integer identifying the signature algorithm used - **Content type (content-type: 3)** - Text string or integer indicating the content type (for EAT, this is typically "application/eat+cwt") - **Key ID (issuer-key-id: 4)** - Binary string that MUST match the subject name of the certificate containing the public key that can verify the EAT signature