@@ -4,11 +4,13 @@ use crate::{
44 codec:: { Codec , MessageBuf } ,
55 commands:: measurements:: {
66 GetMeasurementsReqAttr , GetMeasurementsReqCommon , GetMeasurementsReqSignature ,
7+ MeasurementBlockHeader , MeasurementOperation , MeasurementsRspFixed ,
78 } ,
89 context:: SpdmContext ,
910 error:: { CommandError , CommandResult , PlatformError } ,
1011 protocol:: { ReqRespCode , SpdmMsgHdr , SpdmVersion , NONCE_LEN } ,
1112 state:: ConnectionState ,
13+ transcript:: TranscriptContext ,
1214} ;
1315
1416/// Generate a GET_MEASUREMENTS request
@@ -19,10 +21,12 @@ use crate::{
1921/// * `raw_bitstream_requested`: Request a raw bit stream (if supported) (SPDM v1.2+)
2022/// * `new_measurement_requested`: Request new measurement if the responder has pending updates to blocks (SPDM v1.3+)
2123/// * `meas_op`: Measurement operation
22- /// (0x00: query total number of available blocks, 0x01-0xFE: query block, 0xFF: query all blocks)
2324/// * `slot_id`: Request a signed measurement if provided, signed with certificate slot identifier (0-7)
2425/// * `context`: Append optional 8 byte context (SPDM v1.3+)
2526///
27+ /// ## Note
28+ /// For SPDM version 1.0 this implementation does **not** supporte signed measurements.
29+ ///
2630/// # Returns
2731/// - () on success
2832/// - [CommandError] on failure
@@ -37,7 +41,7 @@ pub fn generate_get_measurements<'a>(
3741 req_buf : & mut MessageBuf < ' a > ,
3842 raw_bitstream_requested : bool ,
3943 new_measurement_requested : bool ,
40- meas_op : u8 ,
44+ meas_op : MeasurementOperation ,
4145 slot_id : Option < u8 > ,
4246 context : Option < & [ u8 ; 8 ] > ,
4347) -> CommandResult < ( ) > {
@@ -60,7 +64,11 @@ pub fn generate_get_measurements<'a>(
6064 let mut req_attr = GetMeasurementsReqAttr ( 0 ) ;
6165
6266 // signature requested is available in all versions
67+ // (v1.0 doesn't support slot-ids)
6368 if slot_id. is_some ( ) {
69+ if connection_version == SpdmVersion :: V10 {
70+ return Err ( ( true , CommandError :: UnsupportedRequest ) ) ;
71+ }
6472 // Error if the responder doesn't support this
6573 if !responder_supports_signed_measurements ( ctx) {
6674 return Err ( ( true , CommandError :: UnsupportedRequest ) ) ;
@@ -84,7 +92,10 @@ pub fn generate_get_measurements<'a>(
8492 }
8593
8694 // Encode request attributes and `Measurement` operation
87- let get_meas_common = GetMeasurementsReqCommon { req_attr, meas_op } ;
95+ let get_meas_common = GetMeasurementsReqCommon {
96+ req_attr,
97+ meas_op : meas_op. try_into ( ) . map_err ( |e| ( true , e) ) ?,
98+ } ;
8899 payload_len += get_meas_common
89100 . encode ( req_buf)
90101 . map_err ( |e| ( false , CommandError :: Codec ( e) ) ) ?;
@@ -125,7 +136,7 @@ pub fn generate_get_measurements<'a>(
125136 . push_data ( payload_len)
126137 . map_err ( |_| ( false , CommandError :: BufferTooSmall ) ) ?;
127138
128- ctx. append_message_to_transcript ( req_buf, crate :: transcript :: TranscriptContext :: L1 )
139+ ctx. append_message_to_transcript ( req_buf, TranscriptContext :: L1 )
129140}
130141
131142/// Check if the responder supports signing its measurements
@@ -153,5 +164,56 @@ pub(crate) fn handle_measurements_response<'a>(
153164 resp_header : SpdmMsgHdr ,
154165 resp : & mut MessageBuf < ' a > ,
155166) -> CommandResult < ( ) > {
156- todo ! ( )
167+ // Validate connection state - algorithms must be negotiated
168+ if ctx. state . connection_info . state ( ) < ConnectionState :: AlgorithmsNegotiated {
169+ return Err ( ( true , CommandError :: UnsupportedResponse ) ) ;
170+ }
171+
172+ // Validate version matches connection version
173+ let connection_version = ctx. state . connection_info . version_number ( ) ;
174+ if resp_header. version ( ) . ok ( ) != Some ( connection_version) {
175+ return Err ( ( true , CommandError :: InvalidResponse ) ) ;
176+ }
177+
178+ // Include the already parsed header again to parse `MeasurementsRspFixed`
179+ resp. push_data ( size_of :: < SpdmMsgHdr > ( ) )
180+ . map_err ( |e| ( false , e. into ( ) ) ) ?;
181+
182+ let fixed_fields = MeasurementsRspFixed :: decode ( resp) . map_err ( |e| ( true , e. into ( ) ) ) ?;
183+
184+ // Convert 3-byte measurement record length to u32
185+ let _meas_record_length = u32:: from_le_bytes ( [
186+ fixed_fields. measurement_record_len_byte0 ( ) ,
187+ fixed_fields. measurement_record_len_byte1 ( ) ,
188+ fixed_fields. measurement_record_len_byte2 ( ) ,
189+ 0 ,
190+ ] ) ;
191+
192+ // Decode all measurement blocks
193+ for _ in 0 ..fixed_fields. num_blocks ( ) {
194+ let block_header = MeasurementBlockHeader :: decode ( resp) . map_err ( |e| ( true , e. into ( ) ) ) ?;
195+ resp. pull_data ( block_header. measurement_size . get ( ) as usize )
196+ . map_err ( |e| ( true , e. into ( ) ) ) ?;
197+ }
198+
199+ // Decode Nonce
200+ let _nonce = resp. data ( 32 ) . map_err ( |e| ( true , e. into ( ) ) ) ?;
201+ resp. pull_data ( 32 ) . map_err ( |e| ( true , e. into ( ) ) ) ?;
202+
203+ // Decode opaque data
204+ let mut len_bytes = [ 0 ; 2 ] ;
205+ len_bytes. copy_from_slice ( resp. data ( 2 ) . map_err ( |e| ( true , e. into ( ) ) ) ?) ;
206+ let opaque_data_len = u16:: from_le_bytes ( len_bytes) ;
207+ resp. pull_data ( 2 ) . map_err ( |e| ( true , e. into ( ) ) ) ?;
208+ resp. pull_data ( opaque_data_len as usize )
209+ . map_err ( |e| ( true , e. into ( ) ) ) ?;
210+
211+ // Decode requester context
212+ let _requester_ctx = resp. data ( 8 ) . map_err ( |e| ( true , e. into ( ) ) ) ?;
213+ resp. pull_data ( 8 ) . map_err ( |e| ( true , e. into ( ) ) ) ?;
214+
215+ // Remaining is the signature, if requested by the GET_MEASUREMENTS request
216+
217+ // Append response to transcript (L1 context for measurements)
218+ ctx. append_message_to_transcript ( resp, TranscriptContext :: L1 )
157219}
0 commit comments