Skip to content

Commit ee61275

Browse files
committed
Implement GET_MEASUREMENTS request generation
1 parent e4031ef commit ee61275

4 files changed

Lines changed: 168 additions & 3 deletions

File tree

examples/spdm_requester.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use spdm_lib::commands::certificate::request::generate_get_certificate;
1414
use spdm_lib::commands::challenge::{
1515
request::generate_challenge_request, MeasurementSummaryHashType,
1616
};
17+
use spdm_lib::commands::measurements::request::generate_get_measurements;
1718
use spdm_lib::context::SpdmContext;
1819
use spdm_lib::error::SpdmError;
1920
use spdm_lib::protocol::algorithms::{
@@ -472,6 +473,26 @@ fn full_flow(stream: TcpStream, config: &RequesterConfig) -> IoResult<()> {
472473
println!("CHALLENGE_AUTH signature verification successfull");
473474
}
474475

476+
// GET_MEASUREMENTS
477+
message_buffer.reset();
478+
generate_get_measurements(
479+
&mut spdm_context,
480+
&mut message_buffer,
481+
false,
482+
false,
483+
0x01,
484+
Some(0),
485+
None,
486+
)
487+
.unwrap();
488+
spdm_context
489+
.requester_send_request(&mut message_buffer, EID)
490+
.unwrap();
491+
492+
if config.verbose {
493+
println!("GET_MEASUREMENTS: {:?}", &message_buffer.message_data());
494+
}
495+
475496
Ok(())
476497
}
477498

src/commands/measurements/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ bitfield! {
3838
struct GetMeasurementsReqAttr(u8);
3939
impl Debug;
4040
u8;
41-
pub signature_requested, _: 0, 0;
42-
pub raw_bitstream_requested, _: 1, 1;
43-
pub new_measurement_requested, _: 2, 2;
41+
pub signature_requested, set_signature_requested: 0, 0;
42+
pub raw_bitstream_requested, set_raw_bitstream_requested: 1, 1;
43+
pub new_measurement_requested, set_new_measurement_requested: 2, 2;
4444
reserved, _: 7, 3;
4545
}
4646

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,127 @@
11
// Licensed under the Apache-2.0 license
2+
3+
use crate::{
4+
codec::{Codec, MessageBuf},
5+
commands::measurements::{
6+
GetMeasurementsReqAttr, GetMeasurementsReqCommon, GetMeasurementsReqSignature,
7+
},
8+
context::SpdmContext,
9+
error::{CommandError, CommandResult, PlatformError},
10+
protocol::{ReqRespCode, SpdmMsgHdr, SpdmVersion, NONCE_LEN},
11+
state::ConnectionState,
12+
};
13+
14+
pub fn generate_get_measurements<'a>(
15+
ctx: &mut SpdmContext<'a>,
16+
req_buf: &mut MessageBuf<'a>,
17+
raw_bitstream_requested: bool,
18+
new_measurement_requested: bool,
19+
meas_op: u8,
20+
slot_id: Option<u8>,
21+
context: Option<&[u8; 8]>,
22+
) -> CommandResult<()> {
23+
// Validate connection state - algorithms must be negotiated first
24+
if ctx.state.connection_info.state() < ConnectionState::AlgorithmsNegotiated {
25+
return Err((true, CommandError::UnsupportedRequest));
26+
}
27+
28+
// TODO: maybe add a check if measuements are supported by the responder
29+
30+
// Get connection version
31+
let connection_version = ctx.state.connection_info.version_number();
32+
33+
// Create and encode SPDM message header
34+
let spdm_hdr = SpdmMsgHdr::new(connection_version, ReqRespCode::GetMeasurements);
35+
let mut payload_len = spdm_hdr
36+
.encode(req_buf)
37+
.map_err(|e| (false, CommandError::Codec(e)))?;
38+
39+
let mut req_attr = GetMeasurementsReqAttr(0);
40+
41+
// signature requested is available in all versions
42+
if slot_id.is_some() {
43+
// Error if the responder doesn't support this
44+
if !responder_supports_signed_measurements(ctx) {
45+
return Err((true, CommandError::UnsupportedRequest));
46+
}
47+
req_attr.set_signature_requested(1);
48+
}
49+
50+
if raw_bitstream_requested {
51+
if connection_version < SpdmVersion::V12 {
52+
return Err((true, CommandError::UnsupportedRequest));
53+
}
54+
// TODO Check measuement block spec
55+
req_attr.set_raw_bitstream_requested(1);
56+
}
57+
58+
if new_measurement_requested {
59+
if connection_version < SpdmVersion::V13 {
60+
return Err((true, CommandError::UnsupportedRequest));
61+
}
62+
req_attr.set_new_measurement_requested(1);
63+
}
64+
65+
// Encode request attributes and `Measurement` operation
66+
let get_meas_common = GetMeasurementsReqCommon { req_attr, meas_op };
67+
payload_len += get_meas_common
68+
.encode(req_buf)
69+
.map_err(|e| (false, CommandError::Codec(e)))?;
70+
71+
// Generate Nonce if signature was requested
72+
if let Some(id) = slot_id {
73+
let mut nonce = [0; NONCE_LEN];
74+
ctx.rng
75+
.get_random_bytes(&mut nonce)
76+
.map_err(|e| (true, PlatformError::from(e).into()))?;
77+
78+
if connection_version < SpdmVersion::V11 {
79+
todo!("Implement encoding of nonce only for v1.0");
80+
} else {
81+
let get_meas_sig = GetMeasurementsReqSignature {
82+
requester_nonce: nonce,
83+
slot_id: id,
84+
};
85+
payload_len += get_meas_sig
86+
.encode(req_buf)
87+
.map_err(|e| (false, CommandError::Codec(e)))?;
88+
}
89+
}
90+
91+
// encode context data if spdm version is >= v1.3
92+
if connection_version >= SpdmVersion::V13 {
93+
if let Some(context) = context {
94+
payload_len +=
95+
crate::codec::encode_u8_slice(context, req_buf).map_err(|e| (true, e.into()))?;
96+
} else {
97+
payload_len +=
98+
crate::codec::encode_u8_slice(&[0; 8], req_buf).map_err(|e| (true, e.into()))?;
99+
}
100+
}
101+
102+
// Finalize message by pushing total payload length
103+
req_buf
104+
.push_data(payload_len)
105+
.map_err(|_| (false, CommandError::BufferTooSmall))?;
106+
107+
ctx.append_message_to_transcript(req_buf, crate::transcript::TranscriptContext::L1)
108+
}
109+
110+
/// Check if the responder supports signing its measurements
111+
///
112+
/// Currently only the `MEAS_CAP` is checked.
113+
/// Checking `BaseAsymSel` and `ExtAsymSelCount` might need to checked,
114+
/// to determine if a signed measurement can be requested.
115+
/// (The Spec is a bit fuzzy about that.)
116+
fn responder_supports_signed_measurements(ctx: &SpdmContext<'_>) -> bool {
117+
let flags = &ctx.state.connection_info.peer_capabilities().flags;
118+
// 0b00 no measurements support
119+
// 0b01 measurements support without signing
120+
// 0b10 measurements with signing supported
121+
// 0b11 reserved
122+
if flags.meas_cap() == 0b10 {
123+
return true;
124+
} else {
125+
return false;
126+
}
127+
}

src/error.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ pub enum PlatformError {
3737
EvidenceError(SpdmEvidenceError),
3838
}
3939

40+
impl From<SpdmRngError> for PlatformError {
41+
fn from(value: SpdmRngError) -> Self {
42+
PlatformError::RngError(value)
43+
}
44+
}
45+
4046
#[non_exhaustive]
4147
#[derive(Debug, PartialEq)]
4248
pub enum CommandError {
@@ -62,3 +68,15 @@ pub enum CommandError {
6268
/// in a dependency, or a uncaught platform misbehavior.
6369
InternalError,
6470
}
71+
72+
impl From<PlatformError> for CommandError {
73+
fn from(value: PlatformError) -> Self {
74+
CommandError::Platform(value)
75+
}
76+
}
77+
78+
impl From<CodecError> for CommandError {
79+
fn from(value: CodecError) -> Self {
80+
CommandError::Codec(value)
81+
}
82+
}

0 commit comments

Comments
 (0)