/src/spdm-rs/spdmlib/src/responder/key_exchange_rsp.rs
Line | Count | Source |
1 | | // Copyright (c) 2020 Intel Corporation |
2 | | // |
3 | | // SPDX-License-Identifier: Apache-2.0 or MIT |
4 | | |
5 | | use crate::common::session::SpdmSession; |
6 | | #[cfg(feature = "hashed-transcript-data")] |
7 | | use crate::common::ManagedBuffer12Sign; |
8 | | use crate::common::SMVersionSelOpaque; |
9 | | use crate::common::SecuredMessageVersion; |
10 | | use crate::common::SpdmCodec; |
11 | | use crate::common::SpdmConnectionState; |
12 | | use crate::common::SpdmTransportEncap; |
13 | | use crate::crypto; |
14 | | use crate::error::{ |
15 | | SpdmResult, SPDM_STATUS_BUFFER_FULL, SPDM_STATUS_CRYPTO_ERROR, SPDM_STATUS_INVALID_MSG_FIELD, |
16 | | SPDM_STATUS_INVALID_STATE_LOCAL, SPDM_STATUS_INVALID_STATE_PEER, |
17 | | }; |
18 | | use crate::message::*; |
19 | | use crate::protocol::*; |
20 | | use crate::responder::*; |
21 | | extern crate alloc; |
22 | | use crate::common::opaque::SpdmOpaqueStruct; |
23 | | use crate::secret; |
24 | | use alloc::boxed::Box; |
25 | | use core::convert::TryFrom; |
26 | | use core::ops::DerefMut; |
27 | | |
28 | | impl ResponderContext { |
29 | 0 | pub fn handle_spdm_key_exchange<'a>( |
30 | 0 | &mut self, |
31 | 0 | bytes: &[u8], |
32 | 0 | writer: &'a mut Writer, |
33 | 0 | ) -> (SpdmResult, Option<&'a [u8]>) { |
34 | 0 | let mut target_session_id = None; |
35 | 0 | let (result, rsp_slice) = |
36 | 0 | self.write_spdm_key_exchange_response(bytes, writer, &mut target_session_id); |
37 | 0 | if result.is_err() { |
38 | 0 | if let Some(session_id) = target_session_id { |
39 | 0 | if let Some(session) = self.common.get_session_via_id(session_id) { |
40 | 0 | session.teardown(); |
41 | 0 | } |
42 | 0 | } |
43 | 0 | } |
44 | | |
45 | 0 | (result, rsp_slice) |
46 | 0 | } |
47 | | |
48 | 0 | pub fn write_spdm_key_exchange_response<'a>( |
49 | 0 | &mut self, |
50 | 0 | bytes: &[u8], |
51 | 0 | writer: &'a mut Writer, |
52 | 0 | target_session_id: &mut Option<u32>, |
53 | 0 | ) -> (SpdmResult, Option<&'a [u8]>) { |
54 | 0 | if self.common.runtime_info.get_connection_state().get_u8() |
55 | 0 | < SpdmConnectionState::SpdmConnectionNegotiated.get_u8() |
56 | | { |
57 | 0 | self.write_spdm_error(SpdmErrorCode::SpdmErrorUnexpectedRequest, 0, writer); |
58 | 0 | return ( |
59 | 0 | Err(SPDM_STATUS_INVALID_STATE_PEER), |
60 | 0 | Some(writer.used_slice()), |
61 | 0 | ); |
62 | 0 | } |
63 | 0 | let mut reader = Reader::init(bytes); |
64 | 0 | let message_header = SpdmMessageHeader::read(&mut reader); |
65 | 0 | if let Some(message_header) = message_header { |
66 | 0 | if message_header.version != self.common.negotiate_info.spdm_version_sel { |
67 | 0 | self.write_spdm_error(SpdmErrorCode::SpdmErrorVersionMismatch, 0, writer); |
68 | 0 | return ( |
69 | 0 | Err(SPDM_STATUS_INVALID_MSG_FIELD), |
70 | 0 | Some(writer.used_slice()), |
71 | 0 | ); |
72 | 0 | } |
73 | 0 | if message_header.version < SpdmVersion::SpdmVersion11 { |
74 | 0 | self.write_spdm_error(SpdmErrorCode::SpdmErrorUnsupportedRequest, 0, writer); |
75 | 0 | return ( |
76 | 0 | Err(SPDM_STATUS_INVALID_MSG_FIELD), |
77 | 0 | Some(writer.used_slice()), |
78 | 0 | ); |
79 | 0 | } |
80 | | } else { |
81 | 0 | self.write_spdm_error(SpdmErrorCode::SpdmErrorInvalidRequest, 0, writer); |
82 | 0 | return ( |
83 | 0 | Err(SPDM_STATUS_INVALID_MSG_FIELD), |
84 | 0 | Some(writer.used_slice()), |
85 | 0 | ); |
86 | | } |
87 | | |
88 | 0 | self.common |
89 | 0 | .reset_buffer_via_request_code(SpdmRequestResponseCode::SpdmRequestKeyExchange, None); |
90 | | |
91 | 0 | let key_exchange_req = |
92 | 0 | SpdmKeyExchangeRequestPayload::spdm_read(&mut self.common, &mut reader); |
93 | | |
94 | 0 | let mut return_opaque = SpdmOpaqueStruct::default(); |
95 | | |
96 | | let measurement_summary_hash; |
97 | 0 | if let Some(key_exchange_req) = &key_exchange_req { |
98 | 0 | debug!("!!! key_exchange req : {:02x?}\n", key_exchange_req); |
99 | | |
100 | 0 | if (key_exchange_req.measurement_summary_hash_type |
101 | 0 | == SpdmMeasurementSummaryHashType::SpdmMeasurementSummaryHashTypeTcb) |
102 | 0 | || (key_exchange_req.measurement_summary_hash_type |
103 | 0 | == SpdmMeasurementSummaryHashType::SpdmMeasurementSummaryHashTypeAll) |
104 | | { |
105 | 0 | self.common.runtime_info.need_measurement_summary_hash = true; |
106 | 0 | let measurement_summary_hash_res = |
107 | 0 | secret::measurement::generate_measurement_summary_hash( |
108 | 0 | self.common.negotiate_info.spdm_version_sel, |
109 | 0 | self.common.negotiate_info.base_hash_sel, |
110 | 0 | self.common.negotiate_info.measurement_specification_sel, |
111 | 0 | self.common.negotiate_info.measurement_hash_sel, |
112 | 0 | key_exchange_req.measurement_summary_hash_type, |
113 | | ); |
114 | 0 | if measurement_summary_hash_res.is_none() { |
115 | 0 | self.write_spdm_error(SpdmErrorCode::SpdmErrorUnspecified, 0, writer); |
116 | 0 | return ( |
117 | 0 | Err(SPDM_STATUS_INVALID_MSG_FIELD), |
118 | 0 | Some(writer.used_slice()), |
119 | 0 | ); |
120 | 0 | } |
121 | 0 | measurement_summary_hash = measurement_summary_hash_res.unwrap(); |
122 | 0 | if measurement_summary_hash.data_size == 0 { |
123 | 0 | self.write_spdm_error(SpdmErrorCode::SpdmErrorUnspecified, 0, writer); |
124 | 0 | return ( |
125 | 0 | Err(SPDM_STATUS_INVALID_MSG_FIELD), |
126 | 0 | Some(writer.used_slice()), |
127 | 0 | ); |
128 | 0 | } |
129 | 0 | } else { |
130 | 0 | self.common.runtime_info.need_measurement_summary_hash = false; |
131 | 0 | measurement_summary_hash = SpdmDigestStruct::default(); |
132 | 0 | } |
133 | | |
134 | 0 | self.common.negotiate_info.termination_policy_set = key_exchange_req.session_policy |
135 | 0 | & KEY_EXCHANGE_REQUESTER_SESSION_POLICY_TERMINATION_POLICY_MASK |
136 | 0 | == KEY_EXCHANGE_REQUESTER_SESSION_POLICY_TERMINATION_POLICY_VALUE; |
137 | | |
138 | 0 | if (key_exchange_req.session_policy |
139 | 0 | & KEY_EXCHANGE_REQUESTER_SESSION_POLICY_EVENT_ALL_POLICY_MASK |
140 | 0 | == KEY_EXCHANGE_REQUESTER_SESSION_POLICY_EVENT_ALL_POLICY_VALUE) |
141 | 0 | && self |
142 | 0 | .common |
143 | 0 | .negotiate_info |
144 | 0 | .rsp_capabilities_sel |
145 | 0 | .contains(SpdmResponseCapabilityFlags::EVENT_CAP) |
146 | | { |
147 | 0 | return ( |
148 | 0 | Err(SPDM_STATUS_INVALID_MSG_FIELD), |
149 | 0 | Some(writer.used_slice()), |
150 | 0 | ); |
151 | 0 | } |
152 | | |
153 | 0 | if let Some(secured_message_version_list) = key_exchange_req |
154 | 0 | .opaque |
155 | 0 | .rsp_get_dmtf_supported_secure_spdm_version_list(&mut self.common) |
156 | | { |
157 | 0 | if secured_message_version_list.version_count |
158 | 0 | > crate::common::opaque::MAX_SECURE_SPDM_VERSION_COUNT as u8 |
159 | | { |
160 | 0 | self.write_spdm_error(SpdmErrorCode::SpdmErrorInvalidRequest, 0, writer); |
161 | 0 | return ( |
162 | 0 | Err(SPDM_STATUS_INVALID_MSG_FIELD), |
163 | 0 | Some(writer.used_slice()), |
164 | 0 | ); |
165 | 0 | } |
166 | 0 | let mut selected_version: Option<SecuredMessageVersion> = None; |
167 | 0 | for index in 0..secured_message_version_list.version_count as usize { |
168 | 0 | for local_version in |
169 | 0 | self.common.config_info.secure_spdm_version.iter().flatten() |
170 | | { |
171 | 0 | if secured_message_version_list.versions_list[index] == *local_version { |
172 | 0 | selected_version = Some(*local_version); |
173 | 0 | } |
174 | | } |
175 | | } |
176 | | |
177 | 0 | if let Some(selected_version) = selected_version { |
178 | 0 | if let Ok(opaque) = SpdmOpaqueStruct::from_sm_version_sel_opaque( |
179 | 0 | &mut self.common, |
180 | 0 | &SMVersionSelOpaque { |
181 | 0 | secured_message_version: selected_version, |
182 | 0 | }, |
183 | 0 | ) { |
184 | 0 | return_opaque = opaque; |
185 | 0 | } else { |
186 | 0 | self.write_spdm_error( |
187 | 0 | SpdmErrorCode::SpdmErrorUnsupportedRequest, |
188 | | 0, |
189 | 0 | writer, |
190 | | ); |
191 | 0 | return ( |
192 | 0 | Err(SPDM_STATUS_INVALID_MSG_FIELD), |
193 | 0 | Some(writer.used_slice()), |
194 | 0 | ); |
195 | | } |
196 | | } else { |
197 | 0 | error!("secure message version not selected!"); |
198 | 0 | self.write_spdm_error(SpdmErrorCode::SpdmErrorInvalidRequest, 0, writer); |
199 | 0 | return ( |
200 | 0 | Err(SPDM_STATUS_INVALID_MSG_FIELD), |
201 | 0 | Some(writer.used_slice()), |
202 | 0 | ); |
203 | | } |
204 | 0 | } |
205 | | } else { |
206 | 0 | error!("!!! key_exchange req : fail !!!\n"); |
207 | 0 | self.write_spdm_error(SpdmErrorCode::SpdmErrorInvalidRequest, 0, writer); |
208 | 0 | return ( |
209 | 0 | Err(SPDM_STATUS_INVALID_MSG_FIELD), |
210 | 0 | Some(writer.used_slice()), |
211 | 0 | ); |
212 | | } |
213 | | |
214 | 0 | let key_exchange_req = key_exchange_req.unwrap(); |
215 | | |
216 | 0 | let slot_id = key_exchange_req.slot_id as usize; |
217 | 0 | if slot_id >= SPDM_MAX_SLOT_NUMBER && slot_id != SPDM_PUB_KEY_SLOT_ID_KEY_EXCHANGE as usize |
218 | | { |
219 | 0 | self.write_spdm_error(SpdmErrorCode::SpdmErrorInvalidRequest, 0, writer); |
220 | 0 | return ( |
221 | 0 | Err(SPDM_STATUS_INVALID_MSG_FIELD), |
222 | 0 | Some(writer.used_slice()), |
223 | 0 | ); |
224 | 0 | }; |
225 | 0 | if slot_id < SPDM_MAX_SLOT_NUMBER |
226 | 0 | && self.common.provision_info.my_cert_chain[slot_id].is_none() |
227 | | { |
228 | 0 | self.write_spdm_error(SpdmErrorCode::SpdmErrorInvalidRequest, 0, writer); |
229 | 0 | return ( |
230 | 0 | Err(SPDM_STATUS_INVALID_MSG_FIELD), |
231 | 0 | Some(writer.used_slice()), |
232 | 0 | ); |
233 | 0 | } |
234 | | |
235 | 0 | self.common |
236 | 0 | .runtime_info |
237 | 0 | .set_local_used_cert_chain_slot_id(slot_id as u8); |
238 | | |
239 | 0 | debug!( |
240 | 0 | "!!! exchange data (peer) : {:02x?}\n", |
241 | 0 | &key_exchange_req.exchange |
242 | | ); |
243 | | |
244 | 0 | let (final_key, exchange) = if self.common.negotiate_info.kem_sel != SpdmKemAlgo::empty() { |
245 | 0 | let peer_kem_encap_key = key_exchange_req.exchange.to_kem(); |
246 | 0 | let kem_key_exchange_context = |
247 | 0 | crypto::kem_encap::new_key(self.common.negotiate_info.kem_sel, &peer_kem_encap_key); |
248 | 0 | if kem_key_exchange_context.is_none() { |
249 | 0 | self.write_spdm_error(SpdmErrorCode::SpdmErrorUnspecified, 0, writer); |
250 | 0 | return (Err(SPDM_STATUS_CRYPTO_ERROR), Some(writer.used_slice())); |
251 | 0 | } |
252 | 0 | let kem_key_exchange_context = kem_key_exchange_context.unwrap(); |
253 | | |
254 | 0 | let (my_kem_cipher_text, my_final_key) = |
255 | 0 | if let Some(kp) = kem_key_exchange_context.encap_key() { |
256 | 0 | kp |
257 | | } else { |
258 | 0 | self.write_spdm_error(SpdmErrorCode::SpdmErrorUnspecified, 0, writer); |
259 | 0 | return (Err(SPDM_STATUS_CRYPTO_ERROR), Some(writer.used_slice())); |
260 | | }; |
261 | 0 | ( |
262 | 0 | Some(my_final_key), |
263 | 0 | SpdmRspExchangeStruct::from_kem(my_kem_cipher_text), |
264 | 0 | ) |
265 | | } else { |
266 | 0 | let (my_dhe_exchange, dhe_key_exchange_context) = if let Some(kp) = |
267 | 0 | crypto::dhe::generate_key_pair(self.common.negotiate_info.dhe_sel) |
268 | | { |
269 | 0 | kp |
270 | | } else { |
271 | 0 | self.write_spdm_error(SpdmErrorCode::SpdmErrorUnspecified, 0, writer); |
272 | 0 | return (Err(SPDM_STATUS_CRYPTO_ERROR), Some(writer.used_slice())); |
273 | | }; |
274 | 0 | let peer_dhe_exchange = key_exchange_req.exchange.to_dhe(); |
275 | 0 | ( |
276 | 0 | dhe_key_exchange_context.compute_final_key(&peer_dhe_exchange), |
277 | 0 | SpdmRspExchangeStruct::from_dhe(my_dhe_exchange), |
278 | 0 | ) |
279 | | }; |
280 | | |
281 | 0 | debug!("!!! exchange data : {:02x?}\n", exchange); |
282 | | |
283 | 0 | if final_key.is_none() { |
284 | 0 | self.write_spdm_error(SpdmErrorCode::SpdmErrorUnspecified, 0, writer); |
285 | 0 | return (Err(SPDM_STATUS_CRYPTO_ERROR), Some(writer.used_slice())); |
286 | 0 | } |
287 | 0 | let final_key = final_key.unwrap(); |
288 | 0 | debug!("!!! final_key : {:02x?}\n", final_key.as_ref()); |
289 | | |
290 | 0 | let rsp_session_id = self.common.get_next_half_session_id(false); |
291 | 0 | if rsp_session_id.is_err() { |
292 | 0 | self.write_spdm_error(SpdmErrorCode::SpdmErrorSessionLimitExceeded, 0, writer); |
293 | 0 | return ( |
294 | 0 | Err(SPDM_STATUS_INVALID_STATE_LOCAL), |
295 | 0 | Some(writer.used_slice()), |
296 | 0 | ); |
297 | 0 | } |
298 | 0 | let rsp_session_id = rsp_session_id.unwrap(); |
299 | | |
300 | | // create session structure |
301 | 0 | let hash_algo = self.common.negotiate_info.base_hash_sel; |
302 | 0 | let dhe_algo = self.common.negotiate_info.dhe_sel; |
303 | 0 | let kem_algo = self.common.negotiate_info.kem_sel; |
304 | 0 | let aead_algo = self.common.negotiate_info.aead_sel; |
305 | 0 | let key_schedule_algo = self.common.negotiate_info.key_schedule_sel; |
306 | 0 | let sequence_number_count = { |
307 | 0 | let mut transport_encap = self.common.transport_encap.lock(); |
308 | 0 | let transport_encap: &mut (dyn SpdmTransportEncap + Send + Sync) = |
309 | 0 | transport_encap.deref_mut(); |
310 | 0 | transport_encap.get_sequence_number_count() |
311 | | }; |
312 | 0 | let max_random_count = { |
313 | 0 | let mut transport_encap = self.common.transport_encap.lock(); |
314 | 0 | let transport_encap: &mut (dyn SpdmTransportEncap + Send + Sync) = |
315 | 0 | transport_encap.deref_mut(); |
316 | 0 | transport_encap.get_max_random_count() |
317 | | }; |
318 | | |
319 | 0 | let spdm_version_sel = self.common.negotiate_info.spdm_version_sel; |
320 | 0 | let message_a = self.common.runtime_info.message_a.clone(); |
321 | | |
322 | | #[cfg(feature = "mut-auth")] |
323 | 0 | let mut_auth_req = match self.common.encap_context.mut_auth_requested { |
324 | | SpdmKeyExchangeMutAuthAttributes::MUT_AUTH_REQ => { |
325 | 0 | SpdmKeyExchangeMutAuthAttributes::MUT_AUTH_REQ |
326 | | } |
327 | 0 | _ => SpdmKeyExchangeMutAuthAttributes::MUT_AUTH_REQ_WITH_GET_DIGESTS, |
328 | | }; |
329 | | #[cfg(feature = "mut-auth")] |
330 | 0 | let req_slot_id = if mut_auth_req == SpdmKeyExchangeMutAuthAttributes::MUT_AUTH_REQ { |
331 | 0 | if self.common.encap_context.req_slot_id >= SPDM_MAX_SLOT_NUMBER as u8 |
332 | 0 | && self.common.encap_context.req_slot_id != SPDM_PUB_KEY_SLOT_ID_KEY_EXCHANGE_RSP |
333 | | { |
334 | 0 | self.write_spdm_error(SpdmErrorCode::SpdmErrorUnspecified, 0, writer); |
335 | 0 | return ( |
336 | 0 | Err(SPDM_STATUS_INVALID_MSG_FIELD), |
337 | 0 | Some(writer.used_slice()), |
338 | 0 | ); |
339 | 0 | } |
340 | 0 | self.common.encap_context.req_slot_id |
341 | | } else { |
342 | 0 | 0 |
343 | | }; |
344 | | #[cfg(feature = "mut-auth")] |
345 | 0 | if mut_auth_req == SpdmKeyExchangeMutAuthAttributes::MUT_AUTH_REQ { |
346 | 0 | self.common |
347 | 0 | .runtime_info |
348 | 0 | .set_peer_used_cert_chain_slot_id(self.common.encap_context.req_slot_id); |
349 | 0 | } |
350 | | #[cfg(not(feature = "mut-auth"))] |
351 | | let mut_auth_req = SpdmKeyExchangeMutAuthAttributes::empty(); |
352 | | #[cfg(not(feature = "mut-auth"))] |
353 | | let req_slot_id = 0; |
354 | | |
355 | 0 | let cert_chain_hash = if slot_id == SPDM_PUB_KEY_SLOT_ID_KEY_EXCHANGE as usize { |
356 | 0 | if let Some(my_pub_key) = &self.common.provision_info.my_pub_key { |
357 | 0 | crypto::hash::hash_all( |
358 | 0 | self.common.negotiate_info.base_hash_sel, |
359 | 0 | my_pub_key.data[..my_pub_key.data_size as usize].as_ref(), |
360 | | ) |
361 | | } else { |
362 | 0 | error!("responder public key not provisioned!\n"); |
363 | 0 | None |
364 | | } |
365 | 0 | } else if slot_id < SPDM_MAX_SLOT_NUMBER { |
366 | 0 | self.common.get_certchain_hash_local(false, slot_id) |
367 | | } else { |
368 | 0 | error!("invalid requested slot!\n"); |
369 | 0 | None |
370 | | }; |
371 | 0 | if cert_chain_hash.is_none() { |
372 | 0 | self.write_spdm_error(SpdmErrorCode::SpdmErrorInvalidRequest, 0, writer); |
373 | 0 | return ( |
374 | 0 | Err(SPDM_STATUS_INVALID_MSG_FIELD), |
375 | 0 | Some(writer.used_slice()), |
376 | 0 | ); |
377 | 0 | } |
378 | | |
379 | 0 | let session = self.common.get_next_avaiable_session(); |
380 | 0 | if session.is_none() { |
381 | 0 | error!("!!! too many sessions : fail !!!\n"); |
382 | 0 | self.write_spdm_error(SpdmErrorCode::SpdmErrorSessionLimitExceeded, 0, writer); |
383 | 0 | return ( |
384 | 0 | Err(SPDM_STATUS_INVALID_STATE_LOCAL), |
385 | 0 | Some(writer.used_slice()), |
386 | 0 | ); |
387 | 0 | } |
388 | | |
389 | 0 | let session = session.unwrap(); |
390 | 0 | let session_id = ((rsp_session_id as u32) << 16) + key_exchange_req.req_session_id as u32; |
391 | 0 | *target_session_id = Some(session_id); |
392 | 0 | session.setup(session_id).unwrap(); |
393 | 0 | session.set_use_psk(false); |
394 | 0 | session.set_crypto_param(hash_algo, dhe_algo, kem_algo, aead_algo, key_schedule_algo); |
395 | 0 | session.set_mut_auth_requested(mut_auth_req); |
396 | 0 | session.set_transport_param(sequence_number_count, max_random_count); |
397 | 0 | if session |
398 | 0 | .set_shared_secret(spdm_version_sel, final_key) |
399 | 0 | .is_err() |
400 | | { |
401 | 0 | session.teardown(); |
402 | 0 | self.write_spdm_error(SpdmErrorCode::SpdmErrorUnspecified, 0, writer); |
403 | 0 | return (Err(SPDM_STATUS_CRYPTO_ERROR), Some(writer.used_slice())); |
404 | 0 | } |
405 | 0 | session.runtime_info.message_a = message_a; |
406 | 0 | session.runtime_info.rsp_cert_hash = cert_chain_hash; |
407 | 0 | session.runtime_info.req_cert_hash = None; |
408 | | |
409 | 0 | let mut random = [0u8; SPDM_RANDOM_SIZE]; |
410 | 0 | let res = crypto::rand::get_random(&mut random); |
411 | 0 | if res.is_err() { |
412 | 0 | self.write_spdm_error(SpdmErrorCode::SpdmErrorUnspecified, 0, writer); |
413 | 0 | return (Err(SPDM_STATUS_CRYPTO_ERROR), Some(writer.used_slice())); |
414 | 0 | } |
415 | | |
416 | 0 | let in_clear_text = self |
417 | 0 | .common |
418 | 0 | .negotiate_info |
419 | 0 | .req_capabilities_sel |
420 | 0 | .contains(SpdmRequestCapabilityFlags::HANDSHAKE_IN_THE_CLEAR_CAP) |
421 | 0 | && self |
422 | 0 | .common |
423 | 0 | .negotiate_info |
424 | 0 | .rsp_capabilities_sel |
425 | 0 | .contains(SpdmResponseCapabilityFlags::HANDSHAKE_IN_THE_CLEAR_CAP); |
426 | 0 | info!("in_clear_text {:?}\n", in_clear_text); |
427 | | |
428 | 0 | info!("send spdm key_exchange rsp\n"); |
429 | | |
430 | | // prepare response |
431 | 0 | let response = SpdmMessage { |
432 | 0 | header: SpdmMessageHeader { |
433 | 0 | version: self.common.negotiate_info.spdm_version_sel, |
434 | 0 | request_response_code: SpdmRequestResponseCode::SpdmResponseKeyExchangeRsp, |
435 | 0 | }, |
436 | 0 | payload: SpdmMessagePayload::SpdmKeyExchangeResponse(SpdmKeyExchangeResponsePayload { |
437 | 0 | heartbeat_period: self.common.config_info.heartbeat_period, |
438 | 0 | rsp_session_id, |
439 | 0 | mut_auth_req, |
440 | 0 | req_slot_id, |
441 | 0 | random: SpdmRandomStruct { data: random }, |
442 | 0 | exchange, |
443 | 0 | measurement_summary_hash, |
444 | 0 | opaque: return_opaque, |
445 | 0 | signature: SpdmSignatureStruct { |
446 | 0 | data_size: self.common.get_asym_sig_size(), |
447 | 0 | data: [0xbb; SPDM_MAX_ASYM_SIG_SIZE], |
448 | 0 | }, |
449 | 0 | verify_data: SpdmDigestStruct { |
450 | 0 | data_size: self.common.get_hash_size(), |
451 | 0 | data: Box::new([0xcc; SPDM_MAX_HASH_SIZE]), |
452 | 0 | }, |
453 | 0 | }), |
454 | 0 | }; |
455 | | |
456 | 0 | let res = response.spdm_encode(&mut self.common, writer); |
457 | 0 | if res.is_err() { |
458 | 0 | self.write_spdm_error(SpdmErrorCode::SpdmErrorUnspecified, 0, writer); |
459 | 0 | return ( |
460 | 0 | Err(SPDM_STATUS_INVALID_STATE_LOCAL), |
461 | 0 | Some(writer.used_slice()), |
462 | 0 | ); |
463 | 0 | } |
464 | | |
465 | | // generate signature |
466 | 0 | let signature_size = self.common.get_asym_sig_size() as usize; |
467 | 0 | let base_hash_size = self.common.get_hash_size() as usize; |
468 | 0 | let mut temp_used = if in_clear_text { |
469 | 0 | writer.used() - signature_size |
470 | | } else { |
471 | 0 | writer.used() - signature_size - base_hash_size |
472 | | }; |
473 | | |
474 | 0 | if self |
475 | 0 | .common |
476 | 0 | .append_message_k(session_id, &bytes[..reader.used()]) |
477 | 0 | .is_err() |
478 | | { |
479 | 0 | self.write_spdm_error(SpdmErrorCode::SpdmErrorUnspecified, 0, writer); |
480 | 0 | return (Err(SPDM_STATUS_CRYPTO_ERROR), Some(writer.used_slice())); |
481 | 0 | } |
482 | 0 | if self |
483 | 0 | .common |
484 | 0 | .append_message_k(session_id, &writer.used_slice()[..temp_used]) |
485 | 0 | .is_err() |
486 | | { |
487 | 0 | self.write_spdm_error(SpdmErrorCode::SpdmErrorUnspecified, 0, writer); |
488 | 0 | return ( |
489 | 0 | Err(SPDM_STATUS_INVALID_STATE_LOCAL), |
490 | 0 | Some(writer.used_slice()), |
491 | 0 | ); |
492 | 0 | } |
493 | | |
494 | 0 | let session = if let Some(session) = self.common.get_immutable_session_via_id(session_id) { |
495 | 0 | session |
496 | | } else { |
497 | 0 | self.write_spdm_error(SpdmErrorCode::SpdmErrorUnspecified, 0, writer); |
498 | 0 | return ( |
499 | 0 | Err(SPDM_STATUS_INVALID_STATE_LOCAL), |
500 | 0 | Some(writer.used_slice()), |
501 | 0 | ); |
502 | | }; |
503 | | |
504 | 0 | let signature = self.generate_key_exchange_rsp_signature(slot_id as u8, session); |
505 | 0 | if signature.is_err() { |
506 | 0 | self.write_spdm_error(SpdmErrorCode::SpdmErrorUnspecified, 0, writer); |
507 | 0 | return (Err(SPDM_STATUS_CRYPTO_ERROR), Some(writer.used_slice())); |
508 | 0 | } |
509 | 0 | let signature = signature.unwrap(); |
510 | | |
511 | 0 | if self |
512 | 0 | .common |
513 | 0 | .append_message_k(session_id, signature.as_ref()) |
514 | 0 | .is_err() |
515 | | { |
516 | 0 | self.write_spdm_error(SpdmErrorCode::SpdmErrorUnspecified, 0, writer); |
517 | 0 | return ( |
518 | 0 | Err(SPDM_STATUS_INVALID_STATE_LOCAL), |
519 | 0 | Some(writer.used_slice()), |
520 | 0 | ); |
521 | 0 | } |
522 | | |
523 | | // patch the signature before send |
524 | 0 | writer.mut_used_slice()[temp_used..(temp_used + signature_size)] |
525 | 0 | .copy_from_slice(signature.as_ref()); |
526 | 0 | temp_used += signature_size; |
527 | | |
528 | 0 | let session = if let Some(session) = self.common.get_immutable_session_via_id(session_id) { |
529 | 0 | session |
530 | | } else { |
531 | 0 | self.write_spdm_error(SpdmErrorCode::SpdmErrorUnspecified, 0, writer); |
532 | 0 | return ( |
533 | 0 | Err(SPDM_STATUS_INVALID_STATE_LOCAL), |
534 | 0 | Some(writer.used_slice()), |
535 | 0 | ); |
536 | | }; |
537 | | |
538 | | // generate the handshake secret (including finished_key) before generate HMAC |
539 | 0 | let th1 = self.common.calc_rsp_transcript_hash(false, false, session); |
540 | 0 | if th1.is_err() { |
541 | 0 | self.write_spdm_error(SpdmErrorCode::SpdmErrorUnspecified, 0, writer); |
542 | 0 | return (Err(SPDM_STATUS_CRYPTO_ERROR), Some(writer.used_slice())); |
543 | 0 | } |
544 | 0 | let th1 = th1.unwrap(); |
545 | 0 | debug!("!!! th1 : {:02x?}\n", th1.as_ref()); |
546 | | |
547 | 0 | let session = if let Some(session) = self.common.get_session_via_id(session_id) { |
548 | 0 | session |
549 | | } else { |
550 | 0 | self.write_spdm_error(SpdmErrorCode::SpdmErrorUnspecified, 0, writer); |
551 | 0 | return ( |
552 | 0 | Err(SPDM_STATUS_INVALID_STATE_LOCAL), |
553 | 0 | Some(writer.used_slice()), |
554 | 0 | ); |
555 | | }; |
556 | 0 | session.set_th1(th1.clone()); |
557 | 0 | if let Err(e) = session.generate_handshake_secret(spdm_version_sel, &th1) { |
558 | 0 | self.write_spdm_error(SpdmErrorCode::SpdmErrorUnspecified, 0, writer); |
559 | 0 | return (Err(e), Some(writer.used_slice())); |
560 | 0 | } |
561 | | |
562 | 0 | if !in_clear_text { |
563 | 0 | let session = |
564 | 0 | if let Some(session) = self.common.get_immutable_session_via_id(session_id) { |
565 | 0 | session |
566 | | } else { |
567 | 0 | self.write_spdm_error(SpdmErrorCode::SpdmErrorUnspecified, 0, writer); |
568 | 0 | return ( |
569 | 0 | Err(SPDM_STATUS_INVALID_STATE_LOCAL), |
570 | 0 | Some(writer.used_slice()), |
571 | 0 | ); |
572 | | }; |
573 | | |
574 | | // generate HMAC with finished_key |
575 | 0 | let transcript_hash = self.common.calc_rsp_transcript_hash(false, false, session); |
576 | 0 | if transcript_hash.is_err() { |
577 | 0 | self.write_spdm_error(SpdmErrorCode::SpdmErrorUnspecified, 0, writer); |
578 | 0 | return (Err(SPDM_STATUS_CRYPTO_ERROR), Some(writer.used_slice())); |
579 | 0 | } |
580 | 0 | let transcript_hash = transcript_hash.unwrap(); |
581 | | |
582 | 0 | let session = if let Some(session) = self.common.get_session_via_id(session_id) { |
583 | 0 | session |
584 | | } else { |
585 | 0 | self.write_spdm_error(SpdmErrorCode::SpdmErrorUnspecified, 0, writer); |
586 | 0 | return ( |
587 | 0 | Err(SPDM_STATUS_INVALID_STATE_LOCAL), |
588 | 0 | Some(writer.used_slice()), |
589 | 0 | ); |
590 | | }; |
591 | | |
592 | 0 | let hmac = session.generate_hmac_with_response_finished_key(transcript_hash.as_ref()); |
593 | 0 | if hmac.is_err() { |
594 | 0 | session.teardown(); |
595 | 0 | self.write_spdm_error(SpdmErrorCode::SpdmErrorUnspecified, 0, writer); |
596 | 0 | return (Err(SPDM_STATUS_CRYPTO_ERROR), Some(writer.used_slice())); |
597 | 0 | } |
598 | 0 | let hmac = hmac.unwrap(); |
599 | | |
600 | | // append verify_data after TH1 |
601 | 0 | if self |
602 | 0 | .common |
603 | 0 | .append_message_k(session_id, hmac.as_ref()) |
604 | 0 | .is_err() |
605 | | { |
606 | 0 | let session = if let Some(session) = self.common.get_session_via_id(session_id) { |
607 | 0 | session |
608 | | } else { |
609 | 0 | self.write_spdm_error(SpdmErrorCode::SpdmErrorUnspecified, 0, writer); |
610 | 0 | return ( |
611 | 0 | Err(SPDM_STATUS_INVALID_STATE_LOCAL), |
612 | 0 | Some(writer.used_slice()), |
613 | 0 | ); |
614 | | }; |
615 | 0 | session.teardown(); |
616 | 0 | self.write_spdm_error(SpdmErrorCode::SpdmErrorUnspecified, 0, writer); |
617 | 0 | return ( |
618 | 0 | Err(SPDM_STATUS_INVALID_STATE_LOCAL), |
619 | 0 | Some(writer.used_slice()), |
620 | 0 | ); |
621 | 0 | } |
622 | | |
623 | | // patch the hmac before send |
624 | 0 | writer.mut_used_slice()[temp_used..(temp_used + base_hash_size)] |
625 | 0 | .copy_from_slice(hmac.as_ref()); |
626 | 0 | } |
627 | | |
628 | 0 | let heartbeat_period = self.common.config_info.heartbeat_period; |
629 | 0 | let session = if let Some(session) = self.common.get_session_via_id(session_id) { |
630 | 0 | session |
631 | | } else { |
632 | 0 | self.write_spdm_error(SpdmErrorCode::SpdmErrorUnspecified, 0, writer); |
633 | 0 | return ( |
634 | 0 | Err(SPDM_STATUS_INVALID_STATE_LOCAL), |
635 | 0 | Some(writer.used_slice()), |
636 | 0 | ); |
637 | | }; |
638 | | |
639 | 0 | session.heartbeat_period = heartbeat_period; |
640 | 0 | if return_opaque.data_size != 0 { |
641 | 0 | session.secure_spdm_version_sel = if let Ok(svs) = SecuredMessageVersion::try_from( |
642 | 0 | return_opaque.data[return_opaque.data_size as usize - 1], |
643 | 0 | ) { |
644 | 0 | svs |
645 | | } else { |
646 | 0 | self.write_spdm_error(SpdmErrorCode::SpdmErrorInvalidRequest, 0, writer); |
647 | 0 | return ( |
648 | 0 | Err(SPDM_STATUS_INVALID_MSG_FIELD), |
649 | 0 | Some(writer.used_slice()), |
650 | 0 | ); |
651 | | }; |
652 | 0 | } |
653 | | |
654 | 0 | session.set_session_state(crate::common::session::SpdmSessionState::SpdmSessionHandshaking); |
655 | | |
656 | 0 | if in_clear_text { |
657 | 0 | self.common |
658 | 0 | .runtime_info |
659 | 0 | .set_last_session_id(Some(session_id)); |
660 | 0 | } |
661 | | |
662 | 0 | (Ok(()), Some(writer.used_slice())) |
663 | 0 | } |
664 | | |
665 | | #[cfg(feature = "hashed-transcript-data")] |
666 | 0 | pub fn generate_key_exchange_rsp_signature( |
667 | 0 | &self, |
668 | 0 | _slot_id: u8, |
669 | 0 | session: &SpdmSession, |
670 | 0 | ) -> SpdmResult<SpdmSignatureStruct> { |
671 | 0 | let transcript_hash = self |
672 | 0 | .common |
673 | 0 | .calc_rsp_transcript_hash(false, false, session)?; |
674 | | |
675 | 0 | debug!("message_hash - {:02x?}", transcript_hash.as_ref()); |
676 | | |
677 | 0 | let mut message_sign = ManagedBuffer12Sign::default(); |
678 | 0 | if self.common.negotiate_info.spdm_version_sel >= SpdmVersion::SpdmVersion12 { |
679 | 0 | message_sign.reset_message(); |
680 | 0 | message_sign |
681 | 0 | .append_message(&self.common.get_signing_prefix_context()) |
682 | 0 | .ok_or(SPDM_STATUS_BUFFER_FULL)?; |
683 | 0 | message_sign |
684 | 0 | .append_message(&SPDM_VERSION_SIGNING_CONTEXT_ZEROPAD_2) |
685 | 0 | .ok_or(SPDM_STATUS_BUFFER_FULL)?; |
686 | 0 | message_sign |
687 | 0 | .append_message(&SPDM_KEY_EXCHANGE_RESPONSE_SIGN_CONTEXT) |
688 | 0 | .ok_or(SPDM_STATUS_BUFFER_FULL)?; |
689 | 0 | message_sign |
690 | 0 | .append_message(transcript_hash.as_ref()) |
691 | 0 | .ok_or(SPDM_STATUS_BUFFER_FULL)?; |
692 | | } else { |
693 | 0 | error!("hashed-transcript-data is unsupported in SPDM 1.0/1.1 signing!\n"); |
694 | 0 | return Err(SPDM_STATUS_INVALID_STATE_LOCAL); |
695 | | } |
696 | | |
697 | 0 | crate::secret::spdm_asym_sign( |
698 | 0 | &self.common, |
699 | 0 | self.common.negotiate_info.base_hash_sel, |
700 | 0 | self.common.negotiate_info.base_asym_sel, |
701 | 0 | self.common.negotiate_info.pqc_asym_sel, |
702 | 0 | message_sign.as_ref(), |
703 | | ) |
704 | 0 | .ok_or(SPDM_STATUS_CRYPTO_ERROR) |
705 | 0 | } |
706 | | |
707 | | #[cfg(not(feature = "hashed-transcript-data"))] |
708 | | pub fn generate_key_exchange_rsp_signature( |
709 | | &self, |
710 | | _slot_id: u8, |
711 | | session: &SpdmSession, |
712 | | ) -> SpdmResult<SpdmSignatureStruct> { |
713 | | let message_hash = self |
714 | | .common |
715 | | .calc_rsp_transcript_hash(false, false, session)?; |
716 | | // we dont need create message hash for verify |
717 | | // we just print message hash for debug purpose |
718 | | debug!("message_hash - {:02x?}", message_hash.as_ref()); |
719 | | |
720 | | let mut message = self.common.calc_rsp_transcript_data( |
721 | | false, |
722 | | false, |
723 | | &session.runtime_info.message_k, |
724 | | None, |
725 | | None, |
726 | | )?; |
727 | | if self.common.negotiate_info.spdm_version_sel >= SpdmVersion::SpdmVersion12 { |
728 | | message.reset_message(); |
729 | | message |
730 | | .append_message(&self.common.get_signing_prefix_context()) |
731 | | .ok_or(SPDM_STATUS_BUFFER_FULL)?; |
732 | | message |
733 | | .append_message(&SPDM_VERSION_SIGNING_CONTEXT_ZEROPAD_2) |
734 | | .ok_or(SPDM_STATUS_BUFFER_FULL)?; |
735 | | message |
736 | | .append_message(&SPDM_KEY_EXCHANGE_RESPONSE_SIGN_CONTEXT) |
737 | | .ok_or(SPDM_STATUS_BUFFER_FULL)?; |
738 | | message |
739 | | .append_message(message_hash.as_ref()) |
740 | | .ok_or(SPDM_STATUS_BUFFER_FULL)?; |
741 | | } |
742 | | |
743 | | crate::secret::spdm_asym_sign( |
744 | | &self.common, |
745 | | self.common.negotiate_info.base_hash_sel, |
746 | | self.common.negotiate_info.base_asym_sel, |
747 | | self.common.negotiate_info.pqc_asym_sel, |
748 | | message.as_ref(), |
749 | | ) |
750 | | .ok_or(SPDM_STATUS_CRYPTO_ERROR) |
751 | | } |
752 | | } |