Coverage Report

Created: 2025-10-12 06:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/spdm-rs/spdmlib/src/common/key_schedule.rs
Line
Count
Source
1
// Copyright (c) 2020 Intel Corporation
2
//
3
// SPDX-License-Identifier: Apache-2.0 or MIT
4
5
use crate::crypto;
6
use crate::protocol::*;
7
use codec::{Codec, Reader, Writer};
8
extern crate alloc;
9
use crate::secret;
10
use alloc::boxed::Box;
11
12
const MAX_BIN_CONCAT_BUF_SIZE: usize = 2 + 8 + 12 + SPDM_MAX_HASH_SIZE;
13
const SALT_0: [u8; SPDM_MAX_HASH_SIZE] = [0u8; SPDM_MAX_HASH_SIZE];
14
const BIN_STR0_LABEL: &[u8] = b"derived";
15
const BIN_STR1_LABEL: &[u8] = b"req hs data";
16
const BIN_STR2_LABEL: &[u8] = b"rsp hs data";
17
const BIN_STR3_LABEL: &[u8] = b"req app data";
18
const BIN_STR4_LABEL: &[u8] = b"rsp app data";
19
const BIN_STR5_LABEL: &[u8] = b"key";
20
const BIN_STR6_LABEL: &[u8] = b"iv";
21
const BIN_STR7_LABEL: &[u8] = b"finished";
22
const BIN_STR8_LABEL: &[u8] = b"exp master";
23
const BIN_STR9_LABEL: &[u8] = b"traffic upd";
24
const SPDM_VERSION_VALUE: &[u8; 8] = b"spdm .  ";
25
const SPDM_VERSION_VALUE_MAJOR_INDEX: usize = 4;
26
const SPDM_VERSION_VALUE_MINOR_INDEX: usize = 6;
27
28
#[derive(Clone, Debug, Eq, PartialEq)]
29
pub struct SpdmKeySchedule;
30
31
impl Default for SpdmKeySchedule {
32
0
    fn default() -> Self {
33
0
        Self::new()
34
0
    }
35
}
36
37
impl Codec for SpdmKeySchedule {
38
0
    fn encode(&self, _writer: &mut Writer) -> Result<usize, codec::EncodeErr> {
39
        // SpdmKeySchedule is a unit struct with no data to encode
40
0
        Ok(0)
41
0
    }
42
43
0
    fn read(_reader: &mut Reader) -> Option<Self> {
44
        // SpdmKeySchedule is a unit struct with no data to read
45
0
        Some(SpdmKeySchedule)
46
0
    }
47
}
48
49
impl SpdmKeySchedule {
50
0
    pub fn new() -> Self {
51
0
        SpdmKeySchedule {}
52
0
    }
53
54
0
    pub fn derive_handshake_secret(
55
0
        &self,
56
0
        _spdm_version: SpdmVersion,
57
0
        hash_algo: SpdmBaseHashAlgo,
58
0
        key: &SpdmSharedSecretFinalKeyStruct,
59
0
    ) -> Option<SpdmHandshakeSecretStruct> {
60
0
        let prk = crypto::hkdf::hkdf_extract(
61
0
            hash_algo,
62
0
            &SALT_0[0..hash_algo.get_size() as usize],
63
0
            &SpdmHkdfInputKeyingMaterial::SpdmSharedSecretFinalKey(key),
64
0
        )?;
65
0
        SpdmHandshakeSecretStruct::from_spdm_hkdf_prk(prk)
66
0
    }
67
68
0
    pub fn derive_master_secret(
69
0
        &self,
70
0
        spdm_version: SpdmVersion,
71
0
        hash_algo: SpdmBaseHashAlgo,
72
0
        key: &SpdmHandshakeSecretStruct,
73
0
    ) -> Option<SpdmMasterSecretStruct> {
74
0
        let buffer = &mut [0; MAX_BIN_CONCAT_BUF_SIZE];
75
0
        let bin_str0 = self.binconcat(
76
0
            hash_algo.get_size(),
77
0
            spdm_version,
78
0
            BIN_STR0_LABEL,
79
0
            None,
80
0
            buffer,
81
0
        )?;
82
0
        let salt_1 = crypto::hkdf::hkdf_expand(
83
0
            hash_algo,
84
0
            &SpdmHkdfPseudoRandomKey::from_input_keying_material(
85
0
                &SpdmHkdfInputKeyingMaterial::SpdmHandshakeSecret(key),
86
0
            )?,
87
0
            bin_str0,
88
0
            hash_algo.get_size(),
89
0
        )?;
90
0
        debug!("salt_1 - {:02x?}", salt_1.as_ref());
91
92
0
        let prk = crypto::hkdf::hkdf_extract(
93
0
            hash_algo,
94
0
            salt_1.as_ref(),
95
0
            &SpdmHkdfInputKeyingMaterial::SpdmZeroFilled(&SpdmZeroFilledStruct {
96
0
                data_size: hash_algo.get_size(),
97
0
                data: Box::new([0u8; SPDM_MAX_HASH_SIZE]),
98
0
            }),
99
0
        )?;
100
101
0
        SpdmMasterSecretStruct::from_spdm_hkdf_prk(prk)
102
0
    }
103
104
0
    pub fn derive_request_handshake_secret(
105
0
        &self,
106
0
        use_psk: bool,
107
0
        spdm_version: SpdmVersion,
108
0
        hash_algo: SpdmBaseHashAlgo,
109
0
        key: Option<&SpdmHandshakeSecretStruct>,
110
0
        psk_hint: Option<&SpdmPskHintStruct>,
111
0
        th1: &[u8],
112
0
    ) -> Option<SpdmDirectionHandshakeSecretStruct> {
113
0
        let buffer = &mut [0; MAX_BIN_CONCAT_BUF_SIZE];
114
0
        let bin_str1 = self.binconcat(
115
0
            hash_algo.get_size(),
116
0
            spdm_version,
117
0
            BIN_STR1_LABEL,
118
0
            Some(th1),
119
0
            buffer,
120
0
        )?;
121
0
        let okm = if !use_psk {
122
0
            if let Some(k) = key {
123
0
                crypto::hkdf::hkdf_expand(
124
0
                    hash_algo,
125
0
                    &SpdmHkdfPseudoRandomKey::from_input_keying_material(
126
0
                        &SpdmHkdfInputKeyingMaterial::SpdmHandshakeSecret(k),
127
0
                    )?,
128
0
                    bin_str1,
129
0
                    hash_algo.get_size(),
130
0
                )?
131
            } else {
132
0
                return None;
133
            }
134
        } else {
135
0
            let empty_pskhint = SpdmPskHintStruct::default();
136
0
            secret::psk::handshake_secret_hkdf_expand(
137
0
                spdm_version,
138
0
                hash_algo,
139
0
                if let Some(hint) = psk_hint {
140
0
                    hint
141
                } else {
142
0
                    &empty_pskhint
143
                },
144
0
                bin_str1,
145
0
            )?
146
        };
147
148
0
        SpdmDirectionHandshakeSecretStruct::from_spdm_hkdf_okm(okm)
149
0
    }
150
151
0
    pub fn derive_response_handshake_secret(
152
0
        &self,
153
0
        use_psk: bool,
154
0
        spdm_version: SpdmVersion,
155
0
        hash_algo: SpdmBaseHashAlgo,
156
0
        key: Option<&SpdmHandshakeSecretStruct>,
157
0
        psk_hint: Option<&SpdmPskHintStruct>,
158
0
        th1: &[u8],
159
0
    ) -> Option<SpdmDirectionHandshakeSecretStruct> {
160
0
        let buffer = &mut [0; MAX_BIN_CONCAT_BUF_SIZE];
161
0
        let bin_str2 = self.binconcat(
162
0
            hash_algo.get_size(),
163
0
            spdm_version,
164
0
            BIN_STR2_LABEL,
165
0
            Some(th1),
166
0
            buffer,
167
0
        )?;
168
0
        let okm = if !use_psk {
169
0
            if let Some(k) = key {
170
0
                crypto::hkdf::hkdf_expand(
171
0
                    hash_algo,
172
0
                    &SpdmHkdfPseudoRandomKey::from_input_keying_material(
173
0
                        &SpdmHkdfInputKeyingMaterial::SpdmHandshakeSecret(k),
174
0
                    )?,
175
0
                    bin_str2,
176
0
                    hash_algo.get_size(),
177
0
                )?
178
            } else {
179
0
                return None;
180
            }
181
        } else {
182
0
            let empty_pskhint = SpdmPskHintStruct::default();
183
0
            secret::psk::handshake_secret_hkdf_expand(
184
0
                spdm_version,
185
0
                hash_algo,
186
0
                if let Some(hint) = psk_hint {
187
0
                    hint
188
                } else {
189
0
                    &empty_pskhint
190
                },
191
0
                bin_str2,
192
0
            )?
193
        };
194
195
0
        SpdmDirectionHandshakeSecretStruct::from_spdm_hkdf_okm(okm)
196
0
    }
197
198
0
    pub fn derive_finished_key(
199
0
        &self,
200
0
        spdm_version: SpdmVersion,
201
0
        hash_algo: SpdmBaseHashAlgo,
202
0
        key: &SpdmDirectionHandshakeSecretStruct,
203
0
    ) -> Option<SpdmFinishedKeyStruct> {
204
0
        let buffer = &mut [0; MAX_BIN_CONCAT_BUF_SIZE];
205
0
        let bin_str7 = self.binconcat(
206
0
            hash_algo.get_size(),
207
0
            spdm_version,
208
0
            BIN_STR7_LABEL,
209
0
            None,
210
0
            buffer,
211
0
        )?;
212
0
        let okm = crypto::hkdf::hkdf_expand(
213
0
            hash_algo,
214
0
            &SpdmHkdfPseudoRandomKey::from_input_keying_material(
215
0
                &SpdmHkdfInputKeyingMaterial::SpdmDirectionHandshakeSecret(key),
216
0
            )?,
217
0
            bin_str7,
218
0
            hash_algo.get_size(),
219
0
        )?;
220
221
0
        SpdmFinishedKeyStruct::from_spdm_hkdf_okm(okm)
222
0
    }
223
224
0
    pub fn derive_aead_key_iv(
225
0
        &self,
226
0
        spdm_version: SpdmVersion,
227
0
        hash_algo: SpdmBaseHashAlgo,
228
0
        aead_algo: SpdmAeadAlgo,
229
0
        key: &SpdmMajorSecret,
230
0
    ) -> Option<(SpdmAeadKeyStruct, SpdmAeadIvStruct)> {
231
0
        let buffer = &mut [0; MAX_BIN_CONCAT_BUF_SIZE];
232
0
        let bin_str5 = self.binconcat(
233
0
            aead_algo.get_key_size(),
234
0
            spdm_version,
235
0
            BIN_STR5_LABEL,
236
0
            None,
237
0
            buffer,
238
0
        )?;
239
0
        let okm = match key {
240
0
            SpdmMajorSecret::SpdmDirectionHandshakeSecret(k) => crypto::hkdf::hkdf_expand(
241
0
                hash_algo,
242
0
                &SpdmHkdfPseudoRandomKey::from_input_keying_material(
243
0
                    &SpdmHkdfInputKeyingMaterial::SpdmDirectionHandshakeSecret(k),
244
0
                )?,
245
0
                bin_str5,
246
0
                SPDM_MAX_AEAD_KEY_SIZE as u16,
247
0
            )?,
248
0
            SpdmMajorSecret::SpdmDirectionDataSecret(k) => crypto::hkdf::hkdf_expand(
249
0
                hash_algo,
250
0
                &SpdmHkdfPseudoRandomKey::from_input_keying_material(
251
0
                    &SpdmHkdfInputKeyingMaterial::SpdmDirectionDataSecret(k),
252
0
                )?,
253
0
                bin_str5,
254
0
                SPDM_MAX_AEAD_KEY_SIZE as u16,
255
0
            )?,
256
        };
257
0
        let encrypt_key = SpdmAeadKeyStruct::from_spdm_hkdf_okm(okm)?;
258
259
0
        let bin_str6 = self.binconcat(
260
0
            aead_algo.get_iv_size(),
261
0
            spdm_version,
262
0
            BIN_STR6_LABEL,
263
0
            None,
264
0
            buffer,
265
0
        )?;
266
0
        let okm = match key {
267
0
            SpdmMajorSecret::SpdmDirectionHandshakeSecret(k) => crypto::hkdf::hkdf_expand(
268
0
                hash_algo,
269
0
                &SpdmHkdfPseudoRandomKey::from_input_keying_material(
270
0
                    &SpdmHkdfInputKeyingMaterial::SpdmDirectionHandshakeSecret(k),
271
0
                )?,
272
0
                bin_str6,
273
0
                SPDM_MAX_AEAD_IV_SIZE as u16,
274
0
            )?,
275
0
            SpdmMajorSecret::SpdmDirectionDataSecret(k) => crypto::hkdf::hkdf_expand(
276
0
                hash_algo,
277
0
                &SpdmHkdfPseudoRandomKey::from_input_keying_material(
278
0
                    &SpdmHkdfInputKeyingMaterial::SpdmDirectionDataSecret(k),
279
0
                )?,
280
0
                bin_str6,
281
0
                SPDM_MAX_AEAD_IV_SIZE as u16,
282
0
            )?,
283
        };
284
0
        let iv = SpdmAeadIvStruct::from_spdm_hkdf_okm(okm)?;
285
286
0
        Some((encrypt_key, iv))
287
0
    }
288
289
0
    pub fn derive_request_data_secret(
290
0
        &self,
291
0
        use_psk: bool,
292
0
        spdm_version: SpdmVersion,
293
0
        hash_algo: SpdmBaseHashAlgo,
294
0
        key: Option<&SpdmMasterSecretStruct>,
295
0
        psk_hint: Option<&SpdmPskHintStruct>,
296
0
        th2: &[u8],
297
0
    ) -> Option<SpdmDirectionDataSecretStruct> {
298
0
        let buffer = &mut [0; MAX_BIN_CONCAT_BUF_SIZE];
299
0
        let bin_str3 = self.binconcat(
300
0
            hash_algo.get_size(),
301
0
            spdm_version,
302
0
            BIN_STR3_LABEL,
303
0
            Some(th2),
304
0
            buffer,
305
0
        )?;
306
0
        let okm = if !use_psk {
307
0
            if let Some(k) = key {
308
0
                crypto::hkdf::hkdf_expand(
309
0
                    hash_algo,
310
0
                    &SpdmHkdfPseudoRandomKey::from_input_keying_material(
311
0
                        &SpdmHkdfInputKeyingMaterial::SpdmMasterSecret(k),
312
0
                    )?,
313
0
                    bin_str3,
314
0
                    hash_algo.get_size(),
315
0
                )?
316
            } else {
317
0
                return None;
318
            }
319
        } else {
320
0
            let empty_pskhint = SpdmPskHintStruct::default();
321
0
            secret::psk::master_secret_hkdf_expand(
322
0
                spdm_version,
323
0
                hash_algo,
324
0
                if let Some(hint) = psk_hint {
325
0
                    hint
326
                } else {
327
0
                    &empty_pskhint
328
                },
329
0
                bin_str3,
330
0
            )?
331
        };
332
333
0
        SpdmDirectionDataSecretStruct::from_spdm_hkdf_okm(okm)
334
0
    }
335
336
0
    pub fn derive_response_data_secret(
337
0
        &self,
338
0
        use_psk: bool,
339
0
        spdm_version: SpdmVersion,
340
0
        hash_algo: SpdmBaseHashAlgo,
341
0
        key: Option<&SpdmMasterSecretStruct>,
342
0
        psk_hint: Option<&SpdmPskHintStruct>,
343
0
        th2: &[u8],
344
0
    ) -> Option<SpdmDirectionDataSecretStruct> {
345
0
        let buffer = &mut [0; MAX_BIN_CONCAT_BUF_SIZE];
346
0
        let bin_str4 = self.binconcat(
347
0
            hash_algo.get_size(),
348
0
            spdm_version,
349
0
            BIN_STR4_LABEL,
350
0
            Some(th2),
351
0
            buffer,
352
0
        )?;
353
0
        let okm = if !use_psk {
354
0
            if let Some(k) = key {
355
0
                crypto::hkdf::hkdf_expand(
356
0
                    hash_algo,
357
0
                    &SpdmHkdfPseudoRandomKey::from_input_keying_material(
358
0
                        &SpdmHkdfInputKeyingMaterial::SpdmMasterSecret(k),
359
0
                    )?,
360
0
                    bin_str4,
361
0
                    hash_algo.get_size(),
362
0
                )?
363
            } else {
364
0
                return None;
365
            }
366
        } else {
367
0
            let empty_pskhint = SpdmPskHintStruct::default();
368
0
            secret::psk::master_secret_hkdf_expand(
369
0
                spdm_version,
370
0
                hash_algo,
371
0
                if let Some(hint) = psk_hint {
372
0
                    hint
373
                } else {
374
0
                    &empty_pskhint
375
                },
376
0
                bin_str4,
377
0
            )?
378
        };
379
380
0
        SpdmDirectionDataSecretStruct::from_spdm_hkdf_okm(okm)
381
0
    }
382
383
0
    pub fn derive_export_master_secret(
384
0
        &self,
385
0
        use_psk: bool,
386
0
        spdm_version: SpdmVersion,
387
0
        hash_algo: SpdmBaseHashAlgo,
388
0
        key: Option<&SpdmMasterSecretStruct>,
389
0
        psk_hint: Option<&SpdmPskHintStruct>,
390
0
    ) -> Option<SpdmExportMasterSecretStruct> {
391
0
        let buffer = &mut [0; MAX_BIN_CONCAT_BUF_SIZE];
392
0
        let bin_str8 = self.binconcat(
393
0
            hash_algo.get_size(),
394
0
            spdm_version,
395
0
            BIN_STR8_LABEL,
396
0
            None,
397
0
            buffer,
398
0
        )?;
399
0
        let okm = if !use_psk {
400
0
            if let Some(k) = key {
401
0
                crypto::hkdf::hkdf_expand(
402
0
                    hash_algo,
403
0
                    &SpdmHkdfPseudoRandomKey::from_input_keying_material(
404
0
                        &SpdmHkdfInputKeyingMaterial::SpdmMasterSecret(k),
405
0
                    )?,
406
0
                    bin_str8,
407
0
                    hash_algo.get_size(),
408
0
                )?
409
            } else {
410
0
                return None;
411
            }
412
        } else {
413
0
            let empty_pskhint = SpdmPskHintStruct::default();
414
0
            secret::psk::master_secret_hkdf_expand(
415
0
                spdm_version,
416
0
                hash_algo,
417
0
                if let Some(hint) = psk_hint {
418
0
                    hint
419
                } else {
420
0
                    &empty_pskhint
421
                },
422
0
                bin_str8,
423
0
            )?
424
        };
425
426
0
        SpdmExportMasterSecretStruct::from_spdm_hkdf_okm(okm)
427
0
    }
428
429
0
    pub fn derive_update_secret(
430
0
        &self,
431
0
        spdm_version: SpdmVersion,
432
0
        hash_algo: SpdmBaseHashAlgo,
433
0
        key: &SpdmDirectionDataSecretStruct,
434
0
    ) -> Option<SpdmDirectionDataSecretStruct> {
435
0
        let buffer = &mut [0; MAX_BIN_CONCAT_BUF_SIZE];
436
0
        let bin_str9 = self.binconcat(
437
0
            hash_algo.get_size(),
438
0
            spdm_version,
439
0
            BIN_STR9_LABEL,
440
0
            None,
441
0
            buffer,
442
0
        )?;
443
0
        let okm = crypto::hkdf::hkdf_expand(
444
0
            hash_algo,
445
0
            &SpdmHkdfPseudoRandomKey::from_input_keying_material(
446
0
                &SpdmHkdfInputKeyingMaterial::SpdmDirectionDataSecret(key),
447
0
            )?,
448
0
            bin_str9,
449
0
            hash_algo.get_size(),
450
0
        )?;
451
452
0
        SpdmDirectionDataSecretStruct::from_spdm_hkdf_okm(okm)
453
0
    }
454
455
0
    pub fn binconcat<'a>(
456
0
        &self,
457
0
        length: u16,
458
0
        spdm_version: SpdmVersion,
459
0
        label: &[u8],
460
0
        context: Option<&[u8]>,
461
0
        buffer: &'a mut [u8],
462
0
    ) -> Option<&'a [u8]> {
463
0
        let mut len = label.len();
464
0
        if let Some(context) = context {
465
0
            len += context.len();
466
0
        }
467
0
        if len > buffer.len() - 2 - 8 {
468
0
            return None;
469
0
        }
470
471
0
        let mut version = [0u8; 8];
472
0
        version.copy_from_slice(SPDM_VERSION_VALUE);
473
0
        version[SPDM_VERSION_VALUE_MAJOR_INDEX] = (u8::from(spdm_version) >> 4) + b'0';
474
0
        version[SPDM_VERSION_VALUE_MINOR_INDEX] = (u8::from(spdm_version) & 0x0F) + b'0';
475
476
0
        let mut writer = Writer::init(buffer);
477
0
        length.encode(&mut writer).ok()?;
478
0
        writer.extend_from_slice(&version[..]);
479
0
        writer.extend_from_slice(label);
480
0
        if let Some(context) = context {
481
0
            writer.extend_from_slice(context);
482
0
        }
483
484
0
        let len = writer.used();
485
0
        Some(&buffer[0..len])
486
0
    }
487
}