This is a workaround. This works around the current configuration of the AST1060 I2C. The device has a 32-byte SRAM buffer per I2C channel, and this is too small for NEGOTIATE_ALGORITHMS. There is support for DMA, and we are pursuing it. This commit should not be merged to main as it its for DEMO purposes only. It should be discarded from the DEMO if DMA is working before needed.
diff --git a/services/spdm/transport-mctp/src/lib.rs b/services/spdm/transport-mctp/src/lib.rs index 61d6c1a..3071dd8 100644 --- a/services/spdm/transport-mctp/src/lib.rs +++ b/services/spdm/transport-mctp/src/lib.rs
@@ -29,6 +29,55 @@ /// MCTP transport layer header size (none for SPDM over MCTP) const MCTP_HEADER_SIZE: usize = 0; +/// SPDM RequestResponseCode for NEGOTIATE_ALGORITHMS request +const SPDM_NEGOTIATE_ALGORITHMS: u8 = 0xE3; + +/// SPDM RequestResponseCode for ALGORITHMS response +const SPDM_ALGORITHMS: u8 = 0x63; + +/// Canned NEGOTIATE_ALGORITHMS request body (everything after the 4-byte header) +/// This represents a minimal valid NEGOTIATE_ALGORITHMS request per Table 15. +/// Format per DSP0274 v1.3.0 Table 15: +/// Length(2) + MeasurementSpecification(1) + OtherParamsSupport(1) + +/// BaseAsymAlgo(4) + BaseHashAlgo(4) + Reserved(12) + +/// ExtAsymCount(1) + ExtHashCount(1) + Reserved(1) + MELspecification(1) +const NEGOTIATE_ALGORITHMS_BODY: &[u8] = &[ + 0x20, 0x00, // Bytes 4-5: Length = 32 bytes (0x0020) + 0x01, // Byte 6: MeasurementSpecification = DMTF (bit 0 set) + 0x00, // Byte 7: OtherParamsSupport = 0 + 0x01, 0x00, 0x00, 0x00, // Bytes 8-11: BaseAsymAlgo = TPM_ALG_RSASSA_2048 (0x00000001) + 0x01, 0x00, 0x00, 0x00, // Bytes 12-15: BaseHashAlgo = TPM_ALG_SHA_256 (0x00000001) + 0x00, 0x00, 0x00, 0x00, // Bytes 16-19: Reserved + 0x00, 0x00, 0x00, 0x00, // Bytes 20-23: Reserved + 0x00, 0x00, 0x00, 0x00, // Bytes 24-27: Reserved + 0x00, // Byte 28: ExtAsymCount = 0 + 0x00, // Byte 29: ExtHashCount = 0 + 0x00, // Byte 30: Reserved + 0x00, // Byte 31: MELspecification = 0 +]; + +/// Canned ALGORITHMS response body (everything after the 4-byte header) +/// This represents a minimal valid ALGORITHMS response per Table 16. +/// Format per DSP0274 v1.3.0 Table 16: +/// Length(2) + MeasurementSpecificationSel(1) + OtherParamsSelection(1) + +/// MeasurementHashAlgo(4) + BaseAsymSel(4) + BaseHashSel(4) + Reserved(11) + +/// MELspecificationSel(1) + ExtAsymSelCount(1) + ExtHashSelCount(1) + Reserved(2) +const ALGORITHMS_BODY: &[u8] = &[ + 0x24, 0x00, // Bytes 4-5: Length = 36 bytes (0x0024) + 0x01, // Byte 6: MeasurementSpecificationSel = DMTF (bit 0 set) + 0x00, // Byte 7: OtherParamsSelection = 0 + 0x01, 0x00, 0x00, 0x00, // Bytes 8-11: MeasurementHashAlgo = TPM_ALG_SHA_256 (0x00000001) + 0x01, 0x00, 0x00, 0x00, // Bytes 12-15: BaseAsymSel = TPM_ALG_RSASSA_2048 (0x00000001) + 0x01, 0x00, 0x00, 0x00, // Bytes 16-19: BaseHashSel = TPM_ALG_SHA_256 (0x00000001) + 0x00, 0x00, 0x00, 0x00, // Bytes 20-23: Reserved (11 bytes total) + 0x00, 0x00, 0x00, 0x00, // Bytes 24-27: Reserved + 0x00, 0x00, 0x00, // Bytes 28-30: Reserved + 0x00, // Byte 31: MELspecificationSel = 0 + 0x00, // Byte 32: ExtAsymSelCount = 0 + 0x00, // Byte 33: ExtHashSelCount = 0 + 0x00, 0x00, // Bytes 34-35: Reserved +]; + /// SPDM transport implementation using MCTP as the underlying transport. /// /// This transport can operate in two modes: @@ -142,6 +191,14 @@ msg_data.get(1).copied().unwrap_or(0) as u32, ); + // WORKAROUND: Truncate NEGOTIATE_ALGORITHMS to just the 4-byte header + let send_data = if msg_data.len() >= 4 && msg_data[1] == SPDM_NEGOTIATE_ALGORITHMS { + pw_log::info!("send_request: truncating NEGOTIATE_ALGORITHMS from {} to 4 bytes", msg_data.len() as u32); + &msg_data[..4] + } else { + msg_data + }; + // Send via MCTP self.client .send( @@ -150,7 +207,7 @@ Some(dest_eid), None, // Let MCTP allocate tag false, // No integrity check for SPDM - msg_data, + send_data, ) .map_err(|_| TransportError::SendError)?; @@ -174,18 +231,30 @@ return Err(TransportError::UnexpectedMessageType); } - // Copy payload into MessageBuf - let payload = &recv_buf[..meta.payload_size]; pw_log::debug!("receive_response: len={} [0]={:#04x} [1]={:#04x}", meta.payload_size as u32, - payload.first().copied().unwrap_or(0) as u32, - payload.get(1).copied().unwrap_or(0) as u32, + recv_buf.first().copied().unwrap_or(0) as u32, + recv_buf.get(1).copied().unwrap_or(0) as u32, ); - rsp.reserve(MCTP_HEADER_SIZE).map_err(|_| TransportError::BufferTooSmall)?; - rsp.put_data(meta.payload_size).map_err(|_| TransportError::BufferTooSmall)?; - let rsp_buf = rsp.data_mut(meta.payload_size).map_err(|_| TransportError::BufferTooSmall)?; - rsp_buf.copy_from_slice(payload); + // WORKAROUND: Reassemble ALGORITHMS from 4-byte header + canned body + let final_size = if meta.payload_size == 4 && recv_buf[1] == SPDM_ALGORITHMS { + pw_log::info!("receive_response: reassembling ALGORITHMS from 4 bytes to {}", + (4 + ALGORITHMS_BODY.len()) as u32); + + // Header is already in recv_buf[0..4], just append canned body + recv_buf[4..4 + ALGORITHMS_BODY.len()].copy_from_slice(ALGORITHMS_BODY); + 4 + ALGORITHMS_BODY.len() + } else { + meta.payload_size + }; + + // Copy payload into MessageBuf + rsp.reserve(MCTP_HEADER_SIZE).map_err(|_| TransportError::BufferTooSmall)?; + rsp.put_data(final_size).map_err(|_| TransportError::BufferTooSmall)?; + + let rsp_buf = rsp.data_mut(final_size).map_err(|_| TransportError::BufferTooSmall)?; + rsp_buf.copy_from_slice(&recv_buf[..final_size]); Ok(()) } @@ -210,18 +279,30 @@ // Store metadata for response correlation self.last_request_meta = Some(meta); - // Copy payload into MessageBuf - let payload = &recv_buf[..meta.payload_size]; pw_log::debug!("receive_request: len={} [0]={:#04x} [1]={:#04x}", meta.payload_size as u32, - payload.first().copied().unwrap_or(0) as u32, - payload.get(1).copied().unwrap_or(0) as u32, + recv_buf.first().copied().unwrap_or(0) as u32, + recv_buf.get(1).copied().unwrap_or(0) as u32, ); - req.reserve(MCTP_HEADER_SIZE).map_err(|_| TransportError::BufferTooSmall)?; - req.put_data(meta.payload_size).map_err(|_| TransportError::BufferTooSmall)?; - let req_buf = req.data_mut(meta.payload_size).map_err(|_| TransportError::BufferTooSmall)?; - req_buf.copy_from_slice(payload); + // WORKAROUND: Reassemble NEGOTIATE_ALGORITHMS from 4-byte header + canned body + let final_size = if meta.payload_size == 4 && recv_buf[1] == SPDM_NEGOTIATE_ALGORITHMS { + pw_log::info!("receive_request: reassembling NEGOTIATE_ALGORITHMS from 4 bytes to {}", + (4 + NEGOTIATE_ALGORITHMS_BODY.len()) as u32); + + // Header is already in recv_buf[0..4], just append canned body + recv_buf[4..4 + NEGOTIATE_ALGORITHMS_BODY.len()].copy_from_slice(NEGOTIATE_ALGORITHMS_BODY); + 4 + NEGOTIATE_ALGORITHMS_BODY.len() + } else { + meta.payload_size + }; + + // Copy payload into MessageBuf + req.reserve(MCTP_HEADER_SIZE).map_err(|_| TransportError::BufferTooSmall)?; + req.put_data(final_size).map_err(|_| TransportError::BufferTooSmall)?; + + let req_buf = req.data_mut(final_size).map_err(|_| TransportError::BufferTooSmall)?; + req_buf.copy_from_slice(&recv_buf[..final_size]); Ok(()) } @@ -238,6 +319,14 @@ msg_data.get(1).copied().unwrap_or(0) as u32, ); + // WORKAROUND: Truncate ALGORITHMS to just the 4-byte header + let send_data = if msg_data.len() >= 4 && msg_data[1] == SPDM_ALGORITHMS { + pw_log::info!("send_response: truncating ALGORITHMS from {} to 4 bytes", msg_data.len() as u32); + &msg_data[..4] + } else { + msg_data + }; + // Send response back to requester self.client .send( @@ -246,7 +335,7 @@ Some(meta.remote_eid), // Back to requester Some(meta.msg_tag), // Use same tag for correlation meta.msg_ic, // Match integrity check - msg_data, + send_data, ) .map_err(|_| TransportError::SendError)?;