/src/spdm-rs/spdmlib/src/crypto/x509v3.rs
Line | Count | Source |
1 | | // Copyright (c) 2023 Intel Corporation |
2 | | // |
3 | | // SPDX-License-Identifier: Apache-2.0 or MIT |
4 | | |
5 | | use crate::error::{SpdmResult, SPDM_STATUS_VERIF_FAIL}; |
6 | | use crate::protocol::SpdmBaseAsymAlgo; |
7 | | |
8 | | // Key Usage: Digital Signature Bit; |
9 | | const RFC_5280_KEY_USAGE_DIGITAL_SIGNATURE_BIT: u8 = 0x80; |
10 | | // reference: https://www.itu.int/rec/T-REC-X.690/en |
11 | | // TAG |
12 | | const ASN1_TAG_CLASS_UNIVERSAL_MASK: u8 = 0x0; |
13 | | const ASN1_TAG_CLASS_CONTEXT_SPECIFIC_MASK: u8 = 0x80; |
14 | | |
15 | | const ASN1_FORM_CONSTRUCTED_MASK: u8 = 0x20; |
16 | | |
17 | | const ASN1_TAG_BOOLEAN: u8 = 0x1; |
18 | | const ASN1_TAG_NUMBER_INTEGER: u8 = 0x2; |
19 | | const ASN1_TAG_BIT_STRING: u8 = 0x3; |
20 | | const ASN1_TAG_OCTET_STRING: u8 = 0x4; |
21 | | const ASN1_TAG_NUMBER_OBJECT_IDENTIFIER: u8 = 0x6; |
22 | | const ASN1_TAG_NUMBER_SEQUENCE: u8 = 0x10; |
23 | | |
24 | | const ASN1_TAG_SEQUENCE: u8 = |
25 | | ASN1_TAG_CLASS_UNIVERSAL_MASK | ASN1_FORM_CONSTRUCTED_MASK | ASN1_TAG_NUMBER_SEQUENCE; |
26 | | const ASN1_TAG_EXPLICIT_EXTENSION: u8 = 0xA3; |
27 | | const ASN1_TAG_EXTN_VALUE: u8 = 0x04; |
28 | | const ASN1_LENGTH_MULTI_OCTET_MASK: u8 = 0x80; |
29 | | const ASN1_LENGTH_ONE_OCTET: u8 = 0x81; |
30 | | const ASN1_LENGTH_TWO_OCTET: u8 = 0x82; |
31 | | |
32 | | const X509V3_VERSION: u8 = 2; |
33 | | const OID_RSA_SHA256RSA: &[u8] = &[0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0bu8]; |
34 | | const OID_RSA_SHA384RSA: &[u8] = &[0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0cu8]; |
35 | | const OID_RSA_SHA512RSA: &[u8] = &[0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0du8]; |
36 | | const OID_ECDSA_SHA256: &[u8] = &[0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02u8]; |
37 | | const OID_ECDSA_SHA384: &[u8] = &[0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03u8]; |
38 | | const OID_DMTF_SPDM_DEVICE_INFO: &[u8] = |
39 | | &[0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1C, 0x82, 0x12, 0x01]; |
40 | | const OID_DMTF_SPDM_HARDWARE_IDENTITY: &[u8] = |
41 | | &[0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1C, 0x82, 0x12, 0x02]; |
42 | | const OID_DMTF_SPDM_EKU_RESPONDER_AUTH: &[u8] = |
43 | | &[0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1C, 0x82, 0x12, 0x03]; |
44 | | const OID_DMTF_SPDM_EKU_REQUESTER_AUTH: &[u8] = |
45 | | &[0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1C, 0x82, 0x12, 0x04]; |
46 | | const OID_DMTF_MUTABLE_CERTIFICATE: &[u8] = |
47 | | &[0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1C, 0x82, 0x12, 0x05]; |
48 | | const OID_DMTF_SPDM_EXTENSION: &[u8] = |
49 | | &[0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1C, 0x82, 0x12, 0x06]; |
50 | | const OID_KEY_USAGE: &[u8] = &[0x55, 0x1D, 0x0F]; |
51 | | const OID_SUBJECT_ALTERNATIVE_NAME: &[u8] = &[0x55, 0x1D, 0x11]; |
52 | | const OID_EXT_KEY_USAGE: &[u8] = &[0x55, 0x1D, 0x25]; |
53 | | |
54 | | // reference: https://www.rfc-editor.org/rfc/rfc5280.txt |
55 | | // IN DER encoded certificate chain slice |
56 | | // OUT Ok certificate count |
57 | | // OUT Error Mulformed certificate found |
58 | | // checked: |
59 | | // 1. version should be x509v3. |
60 | | // 2. the algorithm is match for leaf certificate |
61 | | // 3. no more or less bytes found |
62 | 0 | pub fn check_cert_chain_format( |
63 | 0 | cert_chain: &[u8], |
64 | 0 | base_asym_algo: SpdmBaseAsymAlgo, |
65 | 0 | ) -> SpdmResult<usize> { |
66 | 0 | let mut cc_walker = 0usize; |
67 | 0 | let mut cert_count = 0usize; |
68 | 0 | let cert_chain_size = cert_chain.len(); |
69 | | |
70 | 0 | while cc_walker < cert_chain_size { |
71 | 0 | cc_walker = cc_walker + check_cert_format(&cert_chain[cc_walker..], base_asym_algo)?; |
72 | 0 | cert_count += 1; |
73 | | } |
74 | | |
75 | 0 | if cc_walker == cert_chain_size { |
76 | 0 | Ok(cert_count) |
77 | | } else { |
78 | 0 | Err(SPDM_STATUS_VERIF_FAIL) |
79 | | } |
80 | 0 | } |
81 | | |
82 | | // IN DER encoded certificate slice |
83 | | // OUT Ok cert size |
84 | | // OUT Error Mulformed certificate found |
85 | 0 | fn check_cert_format(cert: &[u8], base_asym_algo: SpdmBaseAsymAlgo) -> SpdmResult<usize> { |
86 | 0 | let mut c_walker = 0usize; |
87 | 0 | let len = cert.len(); |
88 | | |
89 | 0 | check_tag_is_sequence(cert)?; |
90 | 0 | c_walker += 1; |
91 | | |
92 | 0 | let (body_size, bytes_consumed) = check_length(&cert[c_walker..])?; |
93 | 0 | c_walker += bytes_consumed; |
94 | | |
95 | 0 | if len == c_walker + body_size { |
96 | 0 | c_walker += check_tbs_certificate(&cert[c_walker..], base_asym_algo, true)?; |
97 | 0 | c_walker += check_signature_algorithm(&cert[c_walker..], base_asym_algo, true)?; |
98 | | } else { |
99 | 0 | c_walker += check_tbs_certificate(&cert[c_walker..], base_asym_algo, false)?; |
100 | 0 | c_walker += check_signature_algorithm(&cert[c_walker..], base_asym_algo, false)?; |
101 | | } |
102 | | |
103 | 0 | c_walker += check_signature_value(&cert[c_walker..], base_asym_algo)?; |
104 | | |
105 | 0 | if c_walker == 1 + bytes_consumed + body_size { |
106 | 0 | Ok(c_walker) |
107 | | } else { |
108 | 0 | Err(SPDM_STATUS_VERIF_FAIL) |
109 | | } |
110 | 0 | } |
111 | | |
112 | 0 | fn check_tbs_certificate( |
113 | 0 | data: &[u8], |
114 | 0 | base_asym_algo: SpdmBaseAsymAlgo, |
115 | 0 | is_leaf_cert: bool, |
116 | 0 | ) -> SpdmResult<usize> { |
117 | 0 | let mut t_walker = 0usize; |
118 | 0 | let len = data.len(); |
119 | | |
120 | 0 | check_tag_is_sequence(data)?; |
121 | 0 | t_walker += 1; |
122 | | |
123 | 0 | let (tbs_length, bytes_consumed) = check_length(&data[t_walker..])?; |
124 | 0 | t_walker += bytes_consumed; |
125 | | |
126 | 0 | let length_before_tbs = t_walker; |
127 | | |
128 | 0 | if len < t_walker + tbs_length { |
129 | 0 | return Err(SPDM_STATUS_VERIF_FAIL); |
130 | 0 | } |
131 | | |
132 | | // version [0] EXPLICIT Version DEFAULT v1, |
133 | 0 | let bytes_consumed = check_version(&data[t_walker..])?; |
134 | 0 | t_walker += bytes_consumed; |
135 | | |
136 | | // serialNumber CertificateSerialNumber, |
137 | 0 | let bytes_consumed = check_and_skip_common_tag(&data[t_walker..])?; |
138 | 0 | t_walker += bytes_consumed; |
139 | | |
140 | | // signature AlgorithmIdentifier, |
141 | 0 | check_tag_is_sequence(&data[t_walker..])?; |
142 | 0 | t_walker += 1; |
143 | 0 | let (signature_id_length, bytes_consumed) = check_length(&data[t_walker..])?; |
144 | 0 | t_walker += bytes_consumed; |
145 | | |
146 | 0 | if is_leaf_cert { |
147 | 0 | check_object_identifier(&data[t_walker..], get_oid_by_base_asym_algo(base_asym_algo))?; |
148 | | } else { |
149 | 0 | check_object_identifier(&data[t_walker..], None)?; |
150 | | } |
151 | 0 | t_walker += signature_id_length; |
152 | | // issuer Name, |
153 | 0 | let bytes_consumed = check_name(&data[t_walker..])?; |
154 | 0 | t_walker += bytes_consumed; |
155 | | |
156 | | // validity Validity, |
157 | 0 | let bytes_consumed = check_validity(&data[t_walker..])?; |
158 | 0 | t_walker += bytes_consumed; |
159 | | |
160 | | // subject Name, |
161 | 0 | let bytes_consumed = check_name(&data[t_walker..])?; |
162 | 0 | t_walker += bytes_consumed; |
163 | | |
164 | | // subjectPublicKeyInfo SubjectPublicKeyInfo, |
165 | 0 | let bytes_consumed = check_public_key_info(&data[t_walker..])?; |
166 | 0 | t_walker += bytes_consumed; |
167 | | |
168 | | // issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, |
169 | | // subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, |
170 | | // extensions [3] EXPLICIT Extensions OPTIONAL |
171 | | |
172 | | // key_usage EXTENSIONS, |
173 | 0 | let (bytes_consumed, extension_data) = check_and_get_extensions(&data[t_walker..])?; |
174 | 0 | let (find_key_usage, key_usage_value) = get_key_usage_value(extension_data)?; |
175 | | // The digitalSignature bit SHOULD asserted when subject public key is used for verifying digital signatures |
176 | | // in an entity authentication service, a data origin authentication service, and/or an integrity service. |
177 | 0 | let check_extensions_success = !(find_key_usage |
178 | 0 | && (RFC_5280_KEY_USAGE_DIGITAL_SIGNATURE_BIT & key_usage_value |
179 | 0 | != RFC_5280_KEY_USAGE_DIGITAL_SIGNATURE_BIT)); |
180 | | // when key usage digitalSignature bit unset, it SHOULD return false. |
181 | | |
182 | | //extensions EXTENSIONS, |
183 | 0 | let check_extn_spdm_success = check_extensions_spdm_oid(extension_data, is_leaf_cert)?; |
184 | 0 | t_walker += bytes_consumed; |
185 | | |
186 | 0 | if (t_walker == length_before_tbs + tbs_length) |
187 | 0 | && check_extensions_success |
188 | 0 | && check_extn_spdm_success |
189 | | { |
190 | 0 | Ok(length_before_tbs + tbs_length) |
191 | | } else { |
192 | 0 | Err(SPDM_STATUS_VERIF_FAIL) |
193 | | } |
194 | 0 | } |
195 | | |
196 | 0 | fn check_signature_algorithm( |
197 | 0 | data: &[u8], |
198 | 0 | base_asym_algo: SpdmBaseAsymAlgo, |
199 | 0 | is_leaf_cert: bool, |
200 | 0 | ) -> SpdmResult<usize> { |
201 | 0 | let mut s_walker = 0usize; |
202 | | // signature AlgorithmIdentifier, |
203 | 0 | check_tag_is_sequence(&data[s_walker..])?; |
204 | 0 | s_walker += 1; |
205 | 0 | let (signature_id_length, bytes_consumed) = check_length(&data[s_walker..])?; |
206 | 0 | s_walker += bytes_consumed; |
207 | | |
208 | 0 | if is_leaf_cert { |
209 | 0 | check_object_identifier(&data[s_walker..], get_oid_by_base_asym_algo(base_asym_algo))?; |
210 | | } else { |
211 | 0 | check_object_identifier(&data[s_walker..], None)?; |
212 | | } |
213 | | |
214 | 0 | Ok(s_walker + signature_id_length) |
215 | 0 | } |
216 | | |
217 | 0 | fn check_signature_value(data: &[u8], _base_asym_algo: SpdmBaseAsymAlgo) -> SpdmResult<usize> { |
218 | 0 | check_and_skip_common_tag(data) |
219 | 0 | } |
220 | | |
221 | 0 | fn check_tag_is_sequence(data: &[u8]) -> SpdmResult { |
222 | 0 | if data.is_empty() { |
223 | 0 | Err(SPDM_STATUS_VERIF_FAIL) |
224 | 0 | } else if data[0] == ASN1_TAG_SEQUENCE { |
225 | 0 | Ok(()) |
226 | | } else { |
227 | 0 | Err(SPDM_STATUS_VERIF_FAIL) |
228 | | } |
229 | 0 | } |
230 | | |
231 | 0 | fn check_tag_is_num_oid(data: &[u8]) -> SpdmResult { |
232 | 0 | if data.is_empty() { |
233 | 0 | Err(SPDM_STATUS_VERIF_FAIL) |
234 | 0 | } else if data[0] == ASN1_TAG_NUMBER_OBJECT_IDENTIFIER { |
235 | 0 | Ok(()) |
236 | | } else { |
237 | 0 | Err(SPDM_STATUS_VERIF_FAIL) |
238 | | } |
239 | 0 | } |
240 | | |
241 | 0 | fn check_tag_is_bool(data: &[u8]) -> SpdmResult { |
242 | 0 | if data.is_empty() { |
243 | 0 | Err(SPDM_STATUS_VERIF_FAIL) |
244 | 0 | } else if data[0] == ASN1_TAG_BOOLEAN { |
245 | 0 | Ok(()) |
246 | | } else { |
247 | 0 | Err(SPDM_STATUS_VERIF_FAIL) |
248 | | } |
249 | 0 | } |
250 | | |
251 | 0 | fn check_tag_is_octet_string(data: &[u8]) -> SpdmResult { |
252 | 0 | if data.is_empty() { |
253 | 0 | Err(SPDM_STATUS_VERIF_FAIL) |
254 | 0 | } else if data[0] == ASN1_TAG_OCTET_STRING { |
255 | 0 | Ok(()) |
256 | | } else { |
257 | 0 | Err(SPDM_STATUS_VERIF_FAIL) |
258 | | } |
259 | 0 | } |
260 | | |
261 | | // IN bytes slice |
262 | | // OUT Ok (length, bytes consumed) |
263 | | // OUT Error Mulformed certificate found |
264 | 0 | fn check_length(data: &[u8]) -> SpdmResult<(usize, usize)> { |
265 | 0 | let len = data.len(); |
266 | 0 | if len < 1 { |
267 | 0 | Err(SPDM_STATUS_VERIF_FAIL) |
268 | | } else { |
269 | 0 | let length_byte0 = data[0]; |
270 | 0 | let (length, byte_comsumed) = match length_byte0 { |
271 | 0 | n if (n & ASN1_LENGTH_MULTI_OCTET_MASK) == 0 => (n as usize, 1), |
272 | | ASN1_LENGTH_ONE_OCTET => { |
273 | 0 | if len < 2 { |
274 | 0 | return Err(SPDM_STATUS_VERIF_FAIL); |
275 | | } else { |
276 | 0 | let second_byte = data[1] as usize; |
277 | 0 | if second_byte < 0x80 { |
278 | 0 | return Err(SPDM_STATUS_VERIF_FAIL); // Not the canonical encoding. |
279 | | } else { |
280 | 0 | (second_byte, 2) |
281 | | } |
282 | | } |
283 | | } |
284 | | ASN1_LENGTH_TWO_OCTET => { |
285 | 0 | if len < 3 { |
286 | 0 | return Err(SPDM_STATUS_VERIF_FAIL); |
287 | | } else { |
288 | 0 | let second_byte = data[1] as usize; |
289 | 0 | let third_byte = data[2] as usize; |
290 | | |
291 | 0 | let combined = (second_byte << 8) | third_byte; |
292 | 0 | if combined < 0x100 { |
293 | 0 | return Err(SPDM_STATUS_VERIF_FAIL); // Not the canonical encoding. |
294 | | } else { |
295 | 0 | (combined, 3) |
296 | | } |
297 | | } |
298 | | } |
299 | | _ => { |
300 | 0 | return Err(SPDM_STATUS_VERIF_FAIL); // spdm-rs don't support longer lengths. |
301 | | } |
302 | | }; |
303 | | |
304 | 0 | if len < byte_comsumed + length { |
305 | 0 | Err(SPDM_STATUS_VERIF_FAIL) |
306 | | } else { |
307 | 0 | Ok((length, byte_comsumed)) |
308 | | } |
309 | | } |
310 | 0 | } |
311 | | |
312 | 0 | fn check_version(data: &[u8]) -> SpdmResult<usize> { |
313 | 0 | let len = data.len(); |
314 | 0 | if len < 5 |
315 | 0 | || data[0] != (ASN1_TAG_CLASS_CONTEXT_SPECIFIC_MASK | ASN1_FORM_CONSTRUCTED_MASK) |
316 | 0 | || data[1] != 3 |
317 | 0 | || data[2] != ASN1_TAG_NUMBER_INTEGER |
318 | 0 | || data[3] != 1 |
319 | | { |
320 | 0 | Err(SPDM_STATUS_VERIF_FAIL) |
321 | | } else { |
322 | 0 | let version = data[4]; |
323 | 0 | if version == X509V3_VERSION { |
324 | 0 | Ok(5) |
325 | | } else { |
326 | 0 | Err(SPDM_STATUS_VERIF_FAIL) |
327 | | } |
328 | | } |
329 | 0 | } |
330 | | |
331 | 0 | fn check_object_identifier(data: &[u8], oid: Option<&'static [u8]>) -> SpdmResult<usize> { |
332 | 0 | let len = data.len(); |
333 | 0 | if len < 2 || data[0] != ASN1_TAG_NUMBER_OBJECT_IDENTIFIER { |
334 | 0 | Err(SPDM_STATUS_VERIF_FAIL) |
335 | | } else { |
336 | 0 | let oid_length = data[1]; |
337 | 0 | if len < oid_length as usize + 2 || oid_length >= 0x80 { |
338 | 0 | Err(SPDM_STATUS_VERIF_FAIL) |
339 | 0 | } else if let Some(oid) = oid { |
340 | 0 | if object_identifiers_are_same(&data[2..2 + oid_length as usize], oid) { |
341 | 0 | Ok(oid_length as usize + 2) |
342 | | } else { |
343 | 0 | Err(SPDM_STATUS_VERIF_FAIL) |
344 | | } |
345 | | } else { |
346 | 0 | Ok(oid_length as usize + 2) |
347 | | } |
348 | | } |
349 | 0 | } |
350 | | |
351 | 0 | fn check_name(data: &[u8]) -> SpdmResult<usize> { |
352 | 0 | check_and_skip_common_sequence(data) |
353 | 0 | } |
354 | | |
355 | 0 | fn check_validity(data: &[u8]) -> SpdmResult<usize> { |
356 | 0 | check_and_skip_common_sequence(data) |
357 | 0 | } |
358 | | |
359 | 0 | fn check_public_key_info(data: &[u8]) -> SpdmResult<usize> { |
360 | 0 | check_and_skip_common_sequence(data) |
361 | 0 | } |
362 | | |
363 | 0 | fn check_and_get_extensions(data: &[u8]) -> SpdmResult<(usize, &[u8])> { |
364 | 0 | let len = data.len(); |
365 | 0 | if len < 1 || data[0] != ASN1_TAG_EXPLICIT_EXTENSION { |
366 | 0 | Ok((len, &data[0..])) |
367 | | } else { |
368 | 0 | let (payload_length, bytes_consumed) = check_length(&data[1..])?; |
369 | 0 | if len < 1 + bytes_consumed + payload_length { |
370 | 0 | Err(SPDM_STATUS_VERIF_FAIL) |
371 | | } else { |
372 | 0 | Ok(( |
373 | 0 | 1 + bytes_consumed + payload_length, |
374 | 0 | &data[1 + bytes_consumed..1 + bytes_consumed + payload_length], |
375 | 0 | )) |
376 | | } |
377 | | } |
378 | 0 | } |
379 | | |
380 | 0 | fn get_key_usage_value(data: &[u8]) -> SpdmResult<(bool, u8)> { |
381 | 0 | let mut find_key_usage = false; |
382 | 0 | let len = data.len(); |
383 | 0 | let key_usage_oid_len = OID_KEY_USAGE.len(); |
384 | 0 | if len < 1 || data[0] != ASN1_TAG_SEQUENCE { |
385 | 0 | return Err(SPDM_STATUS_VERIF_FAIL); |
386 | 0 | } |
387 | 0 | let (data_length, bytes_consumed) = check_length(&data[1..])?; |
388 | 0 | if len < 1 + data_length + bytes_consumed { |
389 | 0 | Err(SPDM_STATUS_VERIF_FAIL) |
390 | | } else { |
391 | 0 | let mut index = 1 + bytes_consumed; |
392 | | // search KEY_Usage OID in Extensions Sequence |
393 | 0 | while index < len { |
394 | 0 | if index + 1 >= len { |
395 | 0 | return Err(SPDM_STATUS_VERIF_FAIL); |
396 | 0 | } |
397 | 0 | let (payload_length, bytes_consumed) = check_length(&data[index + 1..])?; |
398 | 0 | if bytes_consumed + payload_length > len - (index + 1) { |
399 | 0 | return Err(SPDM_STATUS_VERIF_FAIL); |
400 | 0 | } |
401 | | // search in sequence, skip bytes consumed |
402 | 0 | if data[index] == ASN1_TAG_SEQUENCE { |
403 | 0 | index += 1 + bytes_consumed; |
404 | 0 | continue; |
405 | 0 | } else if data[index] == ASN1_TAG_NUMBER_OBJECT_IDENTIFIER |
406 | 0 | && payload_length == key_usage_oid_len |
407 | 0 | && object_identifiers_are_same( |
408 | 0 | &data[index + 1 + bytes_consumed..index + 1 + bytes_consumed + payload_length], |
409 | 0 | OID_KEY_USAGE, |
410 | | ) |
411 | | { |
412 | 0 | index += 1 + bytes_consumed + payload_length; |
413 | 0 | if index >= len { |
414 | 0 | return Err(SPDM_STATUS_VERIF_FAIL); |
415 | 0 | } |
416 | | |
417 | 0 | if data[index] == ASN1_TAG_EXTN_VALUE { |
418 | 0 | if index + 1 >= len { |
419 | 0 | return Err(SPDM_STATUS_VERIF_FAIL); |
420 | 0 | } |
421 | 0 | let (_, extnvalue_consumed) = check_length(&data[index + 1..])?; |
422 | 0 | index += 1 + extnvalue_consumed; |
423 | | |
424 | 0 | if index >= len { |
425 | 0 | return Err(SPDM_STATUS_VERIF_FAIL); |
426 | 0 | } |
427 | | |
428 | 0 | if data[index] == ASN1_TAG_BIT_STRING { |
429 | 0 | if index + 1 >= len { |
430 | 0 | return Err(SPDM_STATUS_VERIF_FAIL); |
431 | 0 | } |
432 | 0 | let (string_length, string_consumed) = check_length(&data[index + 1..])?; |
433 | 0 | index += string_consumed + string_length; |
434 | | |
435 | 0 | if index >= len { |
436 | 0 | return Err(SPDM_STATUS_VERIF_FAIL); |
437 | 0 | } |
438 | 0 | find_key_usage = true; |
439 | 0 | } else { |
440 | 0 | find_key_usage = false; |
441 | 0 | } |
442 | 0 | break; |
443 | | } else { |
444 | 0 | return Err(SPDM_STATUS_VERIF_FAIL); |
445 | | } |
446 | | } else { |
447 | | // if not Sequence or OID tag, skip |
448 | 0 | index += 1 + bytes_consumed + payload_length; |
449 | 0 | continue; |
450 | | } |
451 | | } |
452 | 0 | if find_key_usage { |
453 | 0 | Ok((true, data[index])) |
454 | | } else { |
455 | 0 | Ok((false, 0x00)) |
456 | | } |
457 | | } |
458 | 0 | } |
459 | | |
460 | 0 | fn check_extensions_spdm_oid(extensions: &[u8], is_leaf_cert: bool) -> SpdmResult<bool> { |
461 | 0 | let mut responder_auth_oid_find_success = false; |
462 | 0 | let mut requester_auth_oid_find_success = false; |
463 | 0 | let len = extensions.len(); |
464 | 0 | if len < 1 || extensions[0] != ASN1_TAG_SEQUENCE { |
465 | 0 | Err(SPDM_STATUS_VERIF_FAIL) |
466 | | } else { |
467 | 0 | let (payload_length, sequences_bytes_consumed) = check_length(&extensions[1..])?; |
468 | 0 | let extn_sequences = &extensions[1 + sequences_bytes_consumed..]; |
469 | 0 | let sequences_len = extn_sequences.len(); |
470 | 0 | if sequences_len < payload_length { |
471 | 0 | Err(SPDM_STATUS_VERIF_FAIL) |
472 | | } else { |
473 | 0 | let mut index = 0; |
474 | 0 | while index < payload_length { |
475 | 0 | let (extnid, extn_sequence_len) = check_and_get_extn_id(&extn_sequences[index..])?; |
476 | 0 | if extn_sequence_len > payload_length - index { |
477 | 0 | return Err(SPDM_STATUS_VERIF_FAIL); |
478 | 0 | } |
479 | | // find the first level extension identifiy from extensions sequence |
480 | 0 | if object_identifiers_are_same(extnid, OID_SUBJECT_ALTERNATIVE_NAME) { |
481 | 0 | if find_target_object_identifier_in_single_extension( |
482 | 0 | &extn_sequences[index..index + extn_sequence_len], |
483 | 0 | OID_DMTF_SPDM_DEVICE_INFO, |
484 | 0 | )? { |
485 | 0 | info!("find id-DMTF-device-info OID\n"); |
486 | 0 | } |
487 | 0 | index += extn_sequence_len; |
488 | 0 | continue; |
489 | 0 | } else if object_identifiers_are_same(extnid, OID_EXT_KEY_USAGE) { |
490 | 0 | if find_target_object_identifier_in_single_extension( |
491 | 0 | &extn_sequences[index..index + extn_sequence_len], |
492 | 0 | OID_DMTF_SPDM_EKU_RESPONDER_AUTH, |
493 | 0 | )? { |
494 | 0 | responder_auth_oid_find_success = true; |
495 | 0 | info!("find id-DMTF-eku-responder-auth OID\n"); |
496 | 0 | } else if find_target_object_identifier_in_single_extension( |
497 | 0 | &extn_sequences[index..index + extn_sequence_len], |
498 | 0 | OID_DMTF_SPDM_EKU_REQUESTER_AUTH, |
499 | 0 | )? { |
500 | 0 | requester_auth_oid_find_success = true; |
501 | 0 | info!("find id-DMTF-eku-requester-auth OID\n"); |
502 | 0 | } |
503 | 0 | index += extn_sequence_len; |
504 | 0 | continue; |
505 | 0 | } else if object_identifiers_are_same(extnid, OID_DMTF_SPDM_EXTENSION) { |
506 | 0 | if find_target_object_identifier_in_single_extension( |
507 | 0 | &extn_sequences[index..index + extn_sequence_len], |
508 | 0 | OID_DMTF_MUTABLE_CERTIFICATE, |
509 | 0 | )? { |
510 | 0 | info!("find id-DMTF-mutable-certificate OID\n"); |
511 | 0 | } else if find_target_object_identifier_in_single_extension( |
512 | 0 | &extn_sequences[index..index + extn_sequence_len], |
513 | 0 | OID_DMTF_SPDM_HARDWARE_IDENTITY, |
514 | 0 | )? { |
515 | 0 | info!("find id-DMTF-hardware-identity OID\n"); |
516 | 0 | } |
517 | 0 | index += extn_sequence_len; |
518 | 0 | continue; |
519 | | } else { |
520 | 0 | index += extn_sequence_len; |
521 | 0 | continue; |
522 | | } |
523 | | } |
524 | | // if not the leaf certificate, reuester/responder auth OIDs SHOULD not be presented. |
525 | 0 | Ok(!(!is_leaf_cert |
526 | 0 | && (responder_auth_oid_find_success || requester_auth_oid_find_success))) |
527 | | } |
528 | | } |
529 | 0 | } |
530 | | |
531 | | // IN (sequences slice, target oid) |
532 | | // OUT true when find target oid |
533 | | // OUT false when not find target oid |
534 | 0 | fn find_target_object_identifier_in_single_extension( |
535 | 0 | data: &[u8], |
536 | 0 | target_oid: &[u8], |
537 | 0 | ) -> SpdmResult<bool> { |
538 | 0 | let mut target_oid_find_success = false; |
539 | 0 | let len = data.len(); |
540 | 0 | let target_oid_len = target_oid.len(); |
541 | 0 | if len < 1 { |
542 | 0 | Err(SPDM_STATUS_VERIF_FAIL) |
543 | 0 | } else if len < target_oid_len { |
544 | 0 | target_oid_find_success = false; |
545 | 0 | Ok(target_oid_find_success) |
546 | | } else { |
547 | 0 | let mut index = 0; |
548 | 0 | while index < len - target_oid_len { |
549 | 0 | if index + 1 >= len { |
550 | 0 | return Err(SPDM_STATUS_VERIF_FAIL); |
551 | 0 | } |
552 | 0 | let (payload_length, bytes_consumed) = check_length(&data[index + 1..])?; |
553 | 0 | if bytes_consumed + payload_length > len - (index + 1) { |
554 | 0 | return Err(SPDM_STATUS_VERIF_FAIL); |
555 | 0 | } |
556 | 0 | if data[index] == ASN1_TAG_NUMBER_OBJECT_IDENTIFIER { |
557 | 0 | if object_identifiers_are_same( |
558 | 0 | &data[index + 1 + bytes_consumed..index + 1 + bytes_consumed + payload_length], |
559 | 0 | target_oid, |
560 | 0 | ) && payload_length == target_oid_len |
561 | | { |
562 | 0 | target_oid_find_success = true; |
563 | 0 | break; |
564 | | } else { |
565 | 0 | index += 1 + bytes_consumed + payload_length; |
566 | 0 | continue; |
567 | | } |
568 | 0 | } else if data[index] == ASN1_TAG_SEQUENCE || data[index] == ASN1_TAG_EXTN_VALUE { |
569 | 0 | index += 1 + bytes_consumed; |
570 | 0 | continue; |
571 | | } else { |
572 | 0 | index += 1 + bytes_consumed + payload_length; |
573 | 0 | continue; |
574 | | } |
575 | | } |
576 | 0 | Ok(target_oid_find_success) |
577 | | } |
578 | 0 | } |
579 | | |
580 | | // IN extension sequences slice |
581 | | // OUT true when find hardware oid |
582 | | // OUT false when not find hardware oid |
583 | 0 | fn find_target_object_identifier_in_extensions(data: &[u8], target_oid: &[u8]) -> SpdmResult<bool> { |
584 | 0 | let len = data.len(); |
585 | 0 | let mut walker = 0usize; |
586 | 0 | if walker >= len { |
587 | 0 | return Err(SPDM_STATUS_VERIF_FAIL); |
588 | 0 | } |
589 | | |
590 | 0 | check_tag_is_sequence(&data[walker..])?; |
591 | 0 | walker += 1; |
592 | 0 | if walker >= len { |
593 | 0 | return Err(SPDM_STATUS_VERIF_FAIL); |
594 | 0 | } |
595 | | |
596 | 0 | let (payload_length, bytes_consumed) = check_length(&data[walker..])?; |
597 | 0 | walker += bytes_consumed; |
598 | 0 | if payload_length > len - walker { |
599 | 0 | return Err(SPDM_STATUS_VERIF_FAIL); |
600 | 0 | } |
601 | | |
602 | 0 | let data = &data[walker..walker + payload_length]; |
603 | 0 | let len = payload_length; |
604 | 0 | walker = 0; |
605 | 0 | while walker < len { |
606 | 0 | check_tag_is_sequence(&data[walker..])?; |
607 | 0 | walker += 1; |
608 | 0 | if walker >= len { |
609 | 0 | return Err(SPDM_STATUS_VERIF_FAIL); |
610 | 0 | } |
611 | | |
612 | 0 | let (extension_length, bytes_consumed) = check_length(&data[walker..])?; |
613 | 0 | walker += bytes_consumed; |
614 | 0 | if walker >= len { |
615 | 0 | return Err(SPDM_STATUS_VERIF_FAIL); |
616 | 0 | } |
617 | | |
618 | 0 | let next_ext_walker = walker + extension_length; |
619 | | |
620 | 0 | check_tag_is_num_oid(&data[walker..])?; |
621 | 0 | walker += 1; |
622 | 0 | if walker >= len { |
623 | 0 | return Err(SPDM_STATUS_VERIF_FAIL); |
624 | 0 | } |
625 | | |
626 | 0 | let (payload_length, bytes_consumed) = check_length(&data[walker..])?; |
627 | 0 | walker += bytes_consumed; |
628 | 0 | if walker >= len { |
629 | 0 | return Err(SPDM_STATUS_VERIF_FAIL); |
630 | 0 | } |
631 | | |
632 | 0 | if walker + payload_length < len |
633 | 0 | && object_identifiers_are_same( |
634 | 0 | &data[walker..walker + payload_length], |
635 | 0 | OID_DMTF_SPDM_EXTENSION, |
636 | | ) |
637 | | { |
638 | 0 | walker += payload_length; |
639 | 0 | if walker >= len { |
640 | 0 | return Err(SPDM_STATUS_VERIF_FAIL); |
641 | 0 | } |
642 | | |
643 | | // check critical, it is optional |
644 | 0 | if check_tag_is_bool(&data[walker..]).is_ok() { |
645 | 0 | walker += 3; // tag, length, value |
646 | 0 | if walker >= len { |
647 | 0 | return Err(SPDM_STATUS_VERIF_FAIL); |
648 | 0 | } |
649 | 0 | } |
650 | | |
651 | | // next find hardware oid |
652 | 0 | check_tag_is_octet_string(&data[walker..])?; |
653 | 0 | walker += 1; |
654 | 0 | if walker >= len { |
655 | 0 | return Err(SPDM_STATUS_VERIF_FAIL); |
656 | 0 | } |
657 | | |
658 | 0 | let (_, bytes_consumed) = check_length(&data[walker..])?; |
659 | 0 | walker += bytes_consumed; |
660 | 0 | if walker >= len { |
661 | 0 | return Err(SPDM_STATUS_VERIF_FAIL); |
662 | 0 | } |
663 | | |
664 | | // sequence |
665 | 0 | check_tag_is_sequence(&data[walker..])?; |
666 | 0 | walker += 1; |
667 | 0 | if walker >= len { |
668 | 0 | return Err(SPDM_STATUS_VERIF_FAIL); |
669 | 0 | } |
670 | | |
671 | 0 | let (_, bytes_consumed) = check_length(&data[walker..])?; |
672 | 0 | walker += bytes_consumed; |
673 | 0 | if walker >= len { |
674 | 0 | return Err(SPDM_STATUS_VERIF_FAIL); |
675 | 0 | } |
676 | | |
677 | | // sequence |
678 | 0 | check_tag_is_sequence(&data[walker..])?; |
679 | 0 | walker += 1; |
680 | 0 | if walker >= len { |
681 | 0 | return Err(SPDM_STATUS_VERIF_FAIL); |
682 | 0 | } |
683 | | |
684 | 0 | let (_, bytes_consumed) = check_length(&data[walker..])?; |
685 | 0 | walker += bytes_consumed; |
686 | 0 | if walker >= len { |
687 | 0 | return Err(SPDM_STATUS_VERIF_FAIL); |
688 | 0 | } |
689 | | |
690 | 0 | check_tag_is_num_oid(&data[walker..])?; |
691 | 0 | walker += 1; |
692 | 0 | if walker >= len { |
693 | 0 | return Err(SPDM_STATUS_VERIF_FAIL); |
694 | 0 | } |
695 | | |
696 | 0 | let (target_oid_length, bytes_consumed) = check_length(&data[walker..])?; |
697 | 0 | walker += bytes_consumed; |
698 | 0 | if walker >= len { |
699 | 0 | return Err(SPDM_STATUS_VERIF_FAIL); |
700 | 0 | } |
701 | | |
702 | 0 | if target_oid_length != target_oid.len() { |
703 | 0 | return Err(SPDM_STATUS_VERIF_FAIL); |
704 | 0 | } |
705 | | |
706 | 0 | if walker + target_oid_length <= len |
707 | 0 | && object_identifiers_are_same( |
708 | 0 | &data[walker..walker + target_oid_length], |
709 | 0 | target_oid, |
710 | | ) |
711 | | { |
712 | 0 | return Ok(true); |
713 | 0 | } |
714 | 0 | } |
715 | | |
716 | 0 | walker = next_ext_walker; |
717 | | } |
718 | | |
719 | 0 | Ok(false) |
720 | 0 | } |
721 | | |
722 | | // IN extension sequence slice |
723 | | // OUT Ok (extnID, extn sequence length) |
724 | | // OUT Error not found extnID, verify fail |
725 | 0 | fn check_and_get_extn_id(extn_sequences: &[u8]) -> SpdmResult<(&[u8], usize)> { |
726 | 0 | let len = extn_sequences.len(); |
727 | 0 | if len < 1 || extn_sequences[0] != ASN1_TAG_SEQUENCE { |
728 | 0 | Err(SPDM_STATUS_VERIF_FAIL) |
729 | | } else { |
730 | 0 | let (extn_payload_length, extn_bytes_consumed) = check_length(&extn_sequences[1..])?; |
731 | 0 | if len < 1 + extn_bytes_consumed + extn_payload_length { |
732 | 0 | Err(SPDM_STATUS_VERIF_FAIL) |
733 | | } else { |
734 | | // extnID is the first item in the extension sequence and the tag is Object identifier |
735 | 0 | let extn_id = &extn_sequences[1 + extn_bytes_consumed..]; |
736 | 0 | if extn_id.is_empty() || extn_id[0] != ASN1_TAG_NUMBER_OBJECT_IDENTIFIER { |
737 | 0 | Err(SPDM_STATUS_VERIF_FAIL) |
738 | | } else { |
739 | 0 | let (extn_id_length, extn_id_bytes_consumed) = check_length(&extn_id[1..])?; |
740 | 0 | Ok(( |
741 | 0 | &extn_id |
742 | 0 | [1 + extn_id_bytes_consumed..1 + extn_id_bytes_consumed + extn_id_length], |
743 | 0 | 1 + extn_bytes_consumed + extn_payload_length, |
744 | 0 | )) |
745 | | } |
746 | | } |
747 | | } |
748 | 0 | } |
749 | | |
750 | 0 | fn check_and_skip_common_sequence(data: &[u8]) -> SpdmResult<usize> { |
751 | 0 | let len = data.len(); |
752 | 0 | if len < 1 || data[0] != ASN1_TAG_SEQUENCE { |
753 | 0 | Err(SPDM_STATUS_VERIF_FAIL) |
754 | | } else { |
755 | 0 | let (payload_length, bytes_consumed) = check_length(&data[1..])?; |
756 | 0 | if len < 1 + bytes_consumed + payload_length { |
757 | 0 | Err(SPDM_STATUS_VERIF_FAIL) |
758 | | } else { |
759 | 0 | Ok(1 + bytes_consumed + payload_length) |
760 | | } |
761 | | } |
762 | 0 | } |
763 | | |
764 | 0 | fn check_and_skip_common_tag(data: &[u8]) -> SpdmResult<usize> { |
765 | 0 | let len = data.len(); |
766 | 0 | if len < 1 { |
767 | 0 | Err(SPDM_STATUS_VERIF_FAIL) |
768 | | } else { |
769 | 0 | let (payload_length, bytes_consumed) = check_length(&data[1..])?; |
770 | 0 | if len < 1 + bytes_consumed + payload_length { |
771 | 0 | Err(SPDM_STATUS_VERIF_FAIL) |
772 | | } else { |
773 | 0 | Ok(1 + bytes_consumed + payload_length) |
774 | | } |
775 | | } |
776 | 0 | } |
777 | | |
778 | 0 | fn check_and_get_common_tag(data: &[u8]) -> SpdmResult<(usize, &[u8])> { |
779 | 0 | let len = data.len(); |
780 | 0 | if len < 1 { |
781 | 0 | Err(SPDM_STATUS_VERIF_FAIL) |
782 | | } else { |
783 | 0 | let (payload_length, bytes_consumed) = check_length(&data[1..])?; |
784 | 0 | if len < 1 + bytes_consumed + payload_length { |
785 | 0 | Err(SPDM_STATUS_VERIF_FAIL) |
786 | | } else { |
787 | 0 | Ok(( |
788 | 0 | 1 + bytes_consumed + payload_length, |
789 | 0 | &data[1 + bytes_consumed..1 + bytes_consumed + payload_length], |
790 | 0 | )) |
791 | | } |
792 | | } |
793 | 0 | } |
794 | | |
795 | 0 | fn get_oid_by_base_asym_algo(base_asym_algo: SpdmBaseAsymAlgo) -> Option<&'static [u8]> { |
796 | 0 | match base_asym_algo { |
797 | 0 | SpdmBaseAsymAlgo::TPM_ALG_RSASSA_2048 => Some(OID_RSA_SHA256RSA), |
798 | 0 | SpdmBaseAsymAlgo::TPM_ALG_RSAPSS_2048 => Some(OID_RSA_SHA256RSA), |
799 | 0 | SpdmBaseAsymAlgo::TPM_ALG_RSASSA_3072 => Some(OID_RSA_SHA384RSA), |
800 | 0 | SpdmBaseAsymAlgo::TPM_ALG_RSAPSS_3072 => Some(OID_RSA_SHA384RSA), |
801 | 0 | SpdmBaseAsymAlgo::TPM_ALG_ECDSA_ECC_NIST_P256 => Some(OID_ECDSA_SHA256), |
802 | 0 | SpdmBaseAsymAlgo::TPM_ALG_RSASSA_4096 => Some(OID_RSA_SHA512RSA), |
803 | 0 | SpdmBaseAsymAlgo::TPM_ALG_RSAPSS_4096 => Some(OID_RSA_SHA512RSA), |
804 | 0 | SpdmBaseAsymAlgo::TPM_ALG_ECDSA_ECC_NIST_P384 => Some(OID_ECDSA_SHA384), |
805 | 0 | _ => None, |
806 | | } |
807 | 0 | } |
808 | | |
809 | 0 | fn object_identifiers_are_same(a: &[u8], b: &[u8]) -> bool { |
810 | 0 | if a.len() != b.len() { |
811 | 0 | false |
812 | | } else { |
813 | 0 | for (ai, bi) in a.iter().zip(b.iter()) { |
814 | 0 | match ai.cmp(bi) { |
815 | 0 | core::cmp::Ordering::Equal => continue, |
816 | 0 | _ => return false, |
817 | | } |
818 | | } |
819 | 0 | true |
820 | | } |
821 | 0 | } |
822 | | |
823 | | // test root cert by checking issuer name == subject name |
824 | 0 | pub fn is_root_certificate(cert: &[u8]) -> SpdmResult { |
825 | 0 | let mut c_walker = 0usize; |
826 | | |
827 | 0 | check_tag_is_sequence(cert)?; |
828 | 0 | c_walker += 1; |
829 | | |
830 | 0 | let (_, bytes_consumed) = check_length(&cert[c_walker..])?; |
831 | 0 | c_walker += bytes_consumed; |
832 | | |
833 | | // tbs |
834 | 0 | let data = &cert[c_walker..]; |
835 | 0 | let mut t_walker = 0usize; |
836 | 0 | let len = data.len(); |
837 | | |
838 | 0 | check_tag_is_sequence(data)?; |
839 | 0 | t_walker += 1; |
840 | | |
841 | 0 | let (tbs_length, bytes_consumed) = check_length(&data[t_walker..])?; |
842 | 0 | t_walker += bytes_consumed; |
843 | | |
844 | 0 | if len < t_walker + tbs_length { |
845 | 0 | return Err(SPDM_STATUS_VERIF_FAIL); |
846 | 0 | } |
847 | | |
848 | | // version [0] EXPLICIT Version DEFAULT v1, |
849 | 0 | let bytes_consumed = check_version(&data[t_walker..])?; |
850 | 0 | t_walker += bytes_consumed; |
851 | | |
852 | | // serialNumber CertificateSerialNumber, |
853 | 0 | let bytes_consumed = check_and_skip_common_tag(&data[t_walker..])?; |
854 | 0 | t_walker += bytes_consumed; |
855 | | |
856 | | // signature AlgorithmIdentifier, |
857 | 0 | check_tag_is_sequence(&data[t_walker..])?; |
858 | 0 | t_walker += 1; |
859 | 0 | let (signature_id_length, bytes_consumed) = check_length(&data[t_walker..])?; |
860 | 0 | t_walker += bytes_consumed; |
861 | | |
862 | 0 | check_object_identifier(&data[t_walker..], None)?; |
863 | | |
864 | 0 | t_walker += signature_id_length; |
865 | | // issuer Name, |
866 | 0 | let (bytes_consumed, issuer) = check_and_get_common_tag(&data[t_walker..])?; |
867 | 0 | t_walker += bytes_consumed; |
868 | | |
869 | | // validity Validity, |
870 | 0 | let bytes_consumed = check_validity(&data[t_walker..])?; |
871 | 0 | t_walker += bytes_consumed; |
872 | | |
873 | | // subject Name, |
874 | 0 | let (_, subject) = check_and_get_common_tag(&data[t_walker..])?; |
875 | | |
876 | 0 | if subject == issuer { |
877 | 0 | Ok(()) |
878 | | } else { |
879 | 0 | Err(SPDM_STATUS_VERIF_FAIL) |
880 | | } |
881 | 0 | } |
882 | | |
883 | | // verify alias and device model by searching hardware oid in leaf cert |
884 | 0 | pub fn check_leaf_certificate(cert: &[u8], is_alias_cert_model: bool) -> SpdmResult { |
885 | 0 | let mut c_walker = 0usize; |
886 | | |
887 | 0 | check_tag_is_sequence(cert)?; |
888 | 0 | c_walker += 1; |
889 | | |
890 | 0 | let (_, bytes_consumed) = check_length(&cert[c_walker..])?; |
891 | 0 | c_walker += bytes_consumed; |
892 | | |
893 | | // tbs |
894 | 0 | let data = &cert[c_walker..]; |
895 | 0 | let mut t_walker = 0usize; |
896 | 0 | let len = data.len(); |
897 | | |
898 | 0 | check_tag_is_sequence(data)?; |
899 | 0 | t_walker += 1; |
900 | | |
901 | 0 | let (tbs_length, bytes_consumed) = check_length(&data[t_walker..])?; |
902 | 0 | t_walker += bytes_consumed; |
903 | | |
904 | 0 | if len < t_walker + tbs_length { |
905 | 0 | return Err(SPDM_STATUS_VERIF_FAIL); |
906 | 0 | } |
907 | | |
908 | | // version [0] EXPLICIT Version DEFAULT v1, |
909 | 0 | let bytes_consumed = check_version(&data[t_walker..])?; |
910 | 0 | t_walker += bytes_consumed; |
911 | | |
912 | | // serialNumber CertificateSerialNumber, |
913 | 0 | let bytes_consumed = check_and_skip_common_tag(&data[t_walker..])?; |
914 | 0 | t_walker += bytes_consumed; |
915 | | |
916 | | // signature AlgorithmIdentifier, |
917 | 0 | check_tag_is_sequence(&data[t_walker..])?; |
918 | 0 | t_walker += 1; |
919 | 0 | let (signature_id_length, bytes_consumed) = check_length(&data[t_walker..])?; |
920 | 0 | t_walker += bytes_consumed; |
921 | | |
922 | 0 | check_object_identifier(&data[t_walker..], None)?; |
923 | 0 | t_walker += signature_id_length; |
924 | | |
925 | | // issuer Name, |
926 | 0 | let bytes_consumed = check_name(&data[t_walker..])?; |
927 | 0 | t_walker += bytes_consumed; |
928 | | |
929 | | // validity Validity, |
930 | 0 | let bytes_consumed = check_validity(&data[t_walker..])?; |
931 | 0 | t_walker += bytes_consumed; |
932 | | |
933 | | // subject Name, |
934 | 0 | let bytes_consumed = check_name(&data[t_walker..])?; |
935 | 0 | t_walker += bytes_consumed; |
936 | | |
937 | | // subjectPublicKeyInfo SubjectPublicKeyInfo, |
938 | 0 | let bytes_consumed = check_public_key_info(&data[t_walker..])?; |
939 | 0 | t_walker += bytes_consumed; |
940 | | |
941 | | //extensions EXTENSIONS, |
942 | 0 | let (_, extension_data) = check_and_get_extensions(&data[t_walker..])?; |
943 | | |
944 | 0 | if is_alias_cert_model |
945 | 0 | && find_target_object_identifier_in_extensions( |
946 | 0 | extension_data, |
947 | 0 | OID_DMTF_SPDM_HARDWARE_IDENTITY, |
948 | 0 | )? |
949 | | { |
950 | 0 | info!("Hardware identity OID shall not be present in alias cert!\n"); |
951 | 0 | Err(SPDM_STATUS_VERIF_FAIL) |
952 | 0 | } else if !is_alias_cert_model |
953 | 0 | && !find_target_object_identifier_in_extensions( |
954 | 0 | extension_data, |
955 | 0 | OID_DMTF_SPDM_HARDWARE_IDENTITY, |
956 | 0 | )? |
957 | | { |
958 | 0 | info!("Hardware identity OID should be present in device cert!\n"); |
959 | 0 | Ok(()) |
960 | | } else { |
961 | 0 | Ok(()) |
962 | | } |
963 | 0 | } |
964 | | |
965 | | #[cfg(test)] |
966 | | mod tests { |
967 | | extern crate std; |
968 | | use super::*; |
969 | | |
970 | | #[test] |
971 | | fn test_case0_object_identifiers_are_same() { |
972 | | let lt = [0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0bu8]; |
973 | | let lt_wrong1 = [0x2b, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0bu8]; |
974 | | let lt_wrong2 = [0x2b, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0xb0u8]; |
975 | | let lt_empty: [u8; 0] = []; |
976 | | assert!(object_identifiers_are_same(<, OID_RSA_SHA256RSA)); |
977 | | assert!(!object_identifiers_are_same(<, OID_RSA_SHA384RSA)); |
978 | | assert!(!object_identifiers_are_same(<_wrong1, OID_RSA_SHA256RSA)); |
979 | | assert!(!object_identifiers_are_same(<_wrong2, OID_RSA_SHA256RSA)); |
980 | | assert!(!object_identifiers_are_same(<_empty, OID_RSA_SHA384RSA)); |
981 | | } |
982 | | |
983 | | #[test] |
984 | | fn test_case0_get_oid_by_base_asym_algo() { |
985 | | assert_eq!( |
986 | | get_oid_by_base_asym_algo(SpdmBaseAsymAlgo::TPM_ALG_RSASSA_2048), |
987 | | Some(OID_RSA_SHA256RSA) |
988 | | ); |
989 | | assert_eq!( |
990 | | get_oid_by_base_asym_algo(SpdmBaseAsymAlgo::TPM_ALG_ECDSA_ECC_NIST_P256), |
991 | | Some(OID_ECDSA_SHA256) |
992 | | ); |
993 | | } |
994 | | |
995 | | #[test] |
996 | | fn test_case0_check_and_skip_common_tag() { |
997 | | let sq1 = [ |
998 | | 0x03, 0x68, 0x00, 0x30, 0x65, 0x02, 0x31, 0x00, 0xD7, 0x9C, 0x7F, 0x26, 0x91, 0x34, |
999 | | 0xA5, 0x2B, 0x79, 0xEA, 0x66, 0x15, 0x00, 0x88, 0x0A, 0x4D, 0xE7, 0xAD, 0x71, 0xC6, |
1000 | | 0x2E, 0xE4, 0x7E, 0x37, 0xE1, 0x86, 0xEB, 0xE8, 0x55, 0xB0, 0x2F, 0xC5, 0xF3, 0xA9, |
1001 | | 0xE0, 0x90, 0xF9, 0x0B, 0x82, 0xC5, 0xDF, 0x4A, 0x35, 0x9A, 0x0D, 0x35, 0x38, 0x4B, |
1002 | | 0x02, 0x30, 0x40, 0xA7, 0xFE, 0x70, 0x39, 0x7B, 0x4B, 0xD7, 0xC2, 0x28, 0x72, 0x93, |
1003 | | 0x93, 0x0C, 0x62, 0x12, 0x14, 0xF0, 0x70, 0x74, 0x0F, 0xFC, 0xB1, 0x21, 0x60, 0x40, |
1004 | | 0x6D, 0x13, 0xA3, 0x59, 0x0E, 0x27, 0x06, 0xC1, 0x73, 0x4E, 0xCA, 0x40, 0x4C, 0x2D, |
1005 | | 0xF5, 0x96, 0x48, 0x66, 0x05, 0xB1, 0xA6, 0x08, |
1006 | | ]; |
1007 | | let sq2 = [0xA0, 0x03, 0x02, 0x01, 0x02]; |
1008 | | let sq3 = [0x01, 0x01, 0xFF]; |
1009 | | let sq4 = [0x01, 0x01, 0xFF, 0xAA]; |
1010 | | let sq1_wrong = [0x01, 0x02, 0xFF]; |
1011 | | assert_eq!(check_and_skip_common_tag(&sq1), Ok(106)); |
1012 | | assert_eq!(check_and_skip_common_tag(&sq2), Ok(5)); |
1013 | | assert_eq!(check_and_skip_common_tag(&sq3), Ok(3)); |
1014 | | assert_eq!(check_and_skip_common_tag(&sq4), Ok(3)); |
1015 | | assert_eq!( |
1016 | | check_and_skip_common_tag(&sq1_wrong), |
1017 | | Err(SPDM_STATUS_VERIF_FAIL) |
1018 | | ); |
1019 | | } |
1020 | | |
1021 | | #[test] |
1022 | | fn test_case0_check_object_identifier() { |
1023 | | let oid1 = [0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x03]; |
1024 | | let oid2 = [0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02]; |
1025 | | let oid3 = [ |
1026 | | 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, |
1027 | | ]; |
1028 | | let oid1_wrong = [ |
1029 | | 0x30, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x03, |
1030 | | ]; |
1031 | | let oid2_wrong = [0x06, 0x08, 0x2A, 0x86]; |
1032 | | let oid3_wrong: [u8; 0] = []; |
1033 | | assert_eq!( |
1034 | | check_object_identifier(&oid1, Some(OID_ECDSA_SHA384)), |
1035 | | Ok(10) |
1036 | | ); |
1037 | | assert_eq!( |
1038 | | check_object_identifier(&oid2, Some(OID_ECDSA_SHA256)), |
1039 | | Ok(10) |
1040 | | ); |
1041 | | assert_eq!( |
1042 | | check_object_identifier(&oid3, Some(OID_RSA_SHA256RSA)), |
1043 | | Ok(11) |
1044 | | ); |
1045 | | assert_eq!( |
1046 | | check_object_identifier(&oid1_wrong, Some(OID_ECDSA_SHA384)), |
1047 | | Err(SPDM_STATUS_VERIF_FAIL) |
1048 | | ); |
1049 | | assert_eq!( |
1050 | | check_object_identifier(&oid2_wrong, Some(OID_ECDSA_SHA384)), |
1051 | | Err(SPDM_STATUS_VERIF_FAIL) |
1052 | | ); |
1053 | | assert_eq!( |
1054 | | check_object_identifier(&oid3_wrong, Some(OID_ECDSA_SHA384)), |
1055 | | Err(SPDM_STATUS_VERIF_FAIL) |
1056 | | ); |
1057 | | } |
1058 | | |
1059 | | #[test] |
1060 | | fn test_case0_check_version() { |
1061 | | let v1 = [0xA0, 0x03, 0x02, 0x01, 0x02]; |
1062 | | let v1_wrong = [0xA0, 0x03, 0x02, 0x01, 0x01]; |
1063 | | let v2_wrong = [0x30, 0x03, 0x02, 0x01, 0x02]; |
1064 | | let v3_wrong = [0xA0, 0x03, 0x02, 0x01]; |
1065 | | assert_eq!(check_version(&v1), Ok(5)); |
1066 | | assert_eq!(check_version(&v1_wrong), Err(SPDM_STATUS_VERIF_FAIL)); |
1067 | | assert_eq!(check_version(&v2_wrong), Err(SPDM_STATUS_VERIF_FAIL)); |
1068 | | assert_eq!(check_version(&v3_wrong), Err(SPDM_STATUS_VERIF_FAIL)); |
1069 | | } |
1070 | | |
1071 | | #[test] |
1072 | | fn test_case0_check_length() { |
1073 | | let l1 = [0x03, 0x1, 0x2, 0x3]; |
1074 | | let l2 = [ |
1075 | | 0x81, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1076 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1077 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1078 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1079 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1080 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1081 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1082 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1083 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1084 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1085 | | ]; |
1086 | | let l3 = [ |
1087 | | 0x82, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1088 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1089 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1090 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1091 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1092 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1093 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1094 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1095 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1096 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1097 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1098 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1099 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1100 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1101 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1102 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1103 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1104 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1105 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1106 | | ]; |
1107 | | let l1_wrong = [0x80]; |
1108 | | let l2_wrong = [0x81]; |
1109 | | let l3_wrong = [0x82, 0x01]; |
1110 | | let mut l4_wrong = [0u8; 1 + 3 + 0x10000]; |
1111 | | l4_wrong[0] = 0x83; |
1112 | | l4_wrong[1] = 0x01; |
1113 | | l4_wrong[1] = 0x00; |
1114 | | l4_wrong[1] = 0x00; |
1115 | | assert_eq!(check_length(&l1), Ok((3, 1))); |
1116 | | assert_eq!(check_length(&l2), Ok((0x82, 2))); |
1117 | | assert_eq!(check_length(&l3), Ok((0x101, 3))); |
1118 | | assert_eq!(check_length(&l1_wrong), Err(SPDM_STATUS_VERIF_FAIL)); |
1119 | | assert_eq!(check_length(&l2_wrong), Err(SPDM_STATUS_VERIF_FAIL)); |
1120 | | assert_eq!(check_length(&l3_wrong), Err(SPDM_STATUS_VERIF_FAIL)); |
1121 | | assert_eq!(check_length(&l4_wrong), Err(SPDM_STATUS_VERIF_FAIL)); |
1122 | | } |
1123 | | |
1124 | | #[test] |
1125 | | fn test_case0_check_tag_is_sequence() { |
1126 | | let l1 = [0x30]; |
1127 | | let l1_wrong = [0x80]; |
1128 | | let l2_wrong = [0x81]; |
1129 | | let l3_wrong = [0x82, 0x01]; |
1130 | | assert_eq!(check_tag_is_sequence(&l1), Ok(())); |
1131 | | assert_eq!( |
1132 | | check_tag_is_sequence(&l1_wrong), |
1133 | | Err(SPDM_STATUS_VERIF_FAIL) |
1134 | | ); |
1135 | | assert_eq!( |
1136 | | check_tag_is_sequence(&l2_wrong), |
1137 | | Err(SPDM_STATUS_VERIF_FAIL) |
1138 | | ); |
1139 | | assert_eq!( |
1140 | | check_tag_is_sequence(&l3_wrong), |
1141 | | Err(SPDM_STATUS_VERIF_FAIL) |
1142 | | ); |
1143 | | } |
1144 | | |
1145 | | #[test] |
1146 | | fn test_case0_check_signature_algorithm() { |
1147 | | let s1 = [ |
1148 | | 0x30, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x03, |
1149 | | ]; |
1150 | | let s1_wrong = [ |
1151 | | 0x30, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, |
1152 | | ]; |
1153 | | let s2_wrong = [0x06, 0x08, 0x2A, 0x86]; |
1154 | | let s3_wrong: [u8; 0] = []; |
1155 | | assert_eq!( |
1156 | | check_signature_algorithm(&s1, SpdmBaseAsymAlgo::TPM_ALG_ECDSA_ECC_NIST_P384, true), |
1157 | | Ok(12) |
1158 | | ); |
1159 | | assert_eq!( |
1160 | | check_signature_algorithm(&s1, SpdmBaseAsymAlgo::TPM_ALG_ECDSA_ECC_NIST_P384, false), |
1161 | | Ok(12) |
1162 | | ); |
1163 | | assert_eq!( |
1164 | | check_signature_algorithm(&s1, SpdmBaseAsymAlgo::TPM_ALG_ECDSA_ECC_NIST_P256, false), |
1165 | | Ok(12) |
1166 | | ); |
1167 | | assert_eq!( |
1168 | | check_signature_algorithm(&s1, SpdmBaseAsymAlgo::TPM_ALG_ECDSA_ECC_NIST_P256, true), |
1169 | | Err(SPDM_STATUS_VERIF_FAIL) |
1170 | | ); |
1171 | | assert_eq!( |
1172 | | check_signature_algorithm( |
1173 | | &s1_wrong, |
1174 | | SpdmBaseAsymAlgo::TPM_ALG_ECDSA_ECC_NIST_P384, |
1175 | | false |
1176 | | ), |
1177 | | Err(SPDM_STATUS_VERIF_FAIL) |
1178 | | ); |
1179 | | assert_eq!( |
1180 | | check_signature_algorithm( |
1181 | | &s2_wrong, |
1182 | | SpdmBaseAsymAlgo::TPM_ALG_ECDSA_ECC_NIST_P384, |
1183 | | false |
1184 | | ), |
1185 | | Err(SPDM_STATUS_VERIF_FAIL) |
1186 | | ); |
1187 | | assert_eq!( |
1188 | | check_signature_algorithm( |
1189 | | &s3_wrong, |
1190 | | SpdmBaseAsymAlgo::TPM_ALG_ECDSA_ECC_NIST_P384, |
1191 | | false |
1192 | | ), |
1193 | | Err(SPDM_STATUS_VERIF_FAIL) |
1194 | | ); |
1195 | | } |
1196 | | |
1197 | | #[test] |
1198 | | fn test_case0_check_tbs_certificate() { |
1199 | | let t1 = std::fs::read("../test_key/ecp384/ca.cert.der").expect("unable to read ca cert!"); |
1200 | | let t2 = |
1201 | | std::fs::read("../test_key/ecp384/inter.cert.der").expect("unable to read inter cert!"); |
1202 | | let t3 = std::fs::read("../test_key/ecp384/end_responder.cert.der") |
1203 | | .expect("unable to read leaf cert!"); |
1204 | | |
1205 | | let t1_wrong = [0x30, 0x82, 0x01, 0xA8, 0xA0]; |
1206 | | |
1207 | | assert_eq!( |
1208 | | check_tbs_certificate( |
1209 | | &t1[4..], |
1210 | | SpdmBaseAsymAlgo::TPM_ALG_ECDSA_ECC_NIST_P384, |
1211 | | false |
1212 | | ), |
1213 | | Ok(350) |
1214 | | ); |
1215 | | assert_eq!( |
1216 | | check_tbs_certificate( |
1217 | | &t2[4..], |
1218 | | SpdmBaseAsymAlgo::TPM_ALG_ECDSA_ECC_NIST_P384, |
1219 | | false |
1220 | | ), |
1221 | | Ok(357) |
1222 | | ); |
1223 | | assert_eq!( |
1224 | | check_tbs_certificate( |
1225 | | &t3[4..], |
1226 | | SpdmBaseAsymAlgo::TPM_ALG_ECDSA_ECC_NIST_P384, |
1227 | | false |
1228 | | ), |
1229 | | Ok(464) |
1230 | | ); |
1231 | | assert_eq!( |
1232 | | check_tbs_certificate( |
1233 | | &t3[4..], |
1234 | | SpdmBaseAsymAlgo::TPM_ALG_ECDSA_ECC_NIST_P256, |
1235 | | false |
1236 | | ), |
1237 | | Ok(464) |
1238 | | ); |
1239 | | assert_eq!( |
1240 | | check_tbs_certificate( |
1241 | | &t3[4..], |
1242 | | SpdmBaseAsymAlgo::TPM_ALG_ECDSA_ECC_NIST_P384, |
1243 | | true |
1244 | | ), |
1245 | | Ok(464) |
1246 | | ); |
1247 | | assert_eq!( |
1248 | | check_tbs_certificate( |
1249 | | &t3[4..], |
1250 | | SpdmBaseAsymAlgo::TPM_ALG_ECDSA_ECC_NIST_P256, |
1251 | | true |
1252 | | ), |
1253 | | Err(SPDM_STATUS_VERIF_FAIL) |
1254 | | ); |
1255 | | assert_eq!( |
1256 | | check_tbs_certificate( |
1257 | | &t1_wrong, |
1258 | | SpdmBaseAsymAlgo::TPM_ALG_ECDSA_ECC_NIST_P384, |
1259 | | false |
1260 | | ), |
1261 | | Err(SPDM_STATUS_VERIF_FAIL) |
1262 | | ); |
1263 | | assert_eq!( |
1264 | | check_tbs_certificate( |
1265 | | &t1_wrong, |
1266 | | SpdmBaseAsymAlgo::TPM_ALG_ECDSA_ECC_NIST_P384, |
1267 | | true |
1268 | | ), |
1269 | | Err(SPDM_STATUS_VERIF_FAIL) |
1270 | | ); |
1271 | | } |
1272 | | |
1273 | | #[test] |
1274 | | fn test_case1_check_tbs_certificate() { |
1275 | | let t1 = std::fs::read("../test_key/rsa2048/end_requester_with_spdm_rsp_eku.cert.der") |
1276 | | .expect("unable to read leaf cert!"); |
1277 | | let t2 = std::fs::read("../test_key/rsa2048/end_responder_with_spdm_req_eku.cert.der") |
1278 | | .expect("unable to read leaf cert!"); |
1279 | | |
1280 | | assert_eq!( |
1281 | | check_tbs_certificate(&t1[4..], SpdmBaseAsymAlgo::TPM_ALG_RSASSA_2048, true), |
1282 | | Ok(562) |
1283 | | ); |
1284 | | assert_eq!( |
1285 | | check_tbs_certificate(&t1[4..], SpdmBaseAsymAlgo::TPM_ALG_RSASSA_2048, false), |
1286 | | Err(SPDM_STATUS_VERIF_FAIL) |
1287 | | ); |
1288 | | assert_eq!( |
1289 | | check_tbs_certificate(&t2[4..], SpdmBaseAsymAlgo::TPM_ALG_RSASSA_2048, true), |
1290 | | Ok(562) |
1291 | | ); |
1292 | | assert_eq!( |
1293 | | check_tbs_certificate(&t2[4..], SpdmBaseAsymAlgo::TPM_ALG_RSASSA_2048, false), |
1294 | | Err(SPDM_STATUS_VERIF_FAIL) |
1295 | | ); |
1296 | | } |
1297 | | |
1298 | | #[test] |
1299 | | fn test_case0_check_cert_format() { |
1300 | | let c1 = std::fs::read("../test_key/ecp384/ca.cert.der").expect("unable to read ca cert!"); |
1301 | | let c2 = |
1302 | | std::fs::read("../test_key/ecp384/inter.cert.der").expect("unable to read inter cert!"); |
1303 | | let c3 = std::fs::read("../test_key/ecp384/end_responder.cert.der") |
1304 | | .expect("unable to read leaf cert!"); |
1305 | | |
1306 | | let c1_wrong = [0x30u8, 0x82, 0x01, 0xA8, 0xA0]; |
1307 | | |
1308 | | assert_eq!( |
1309 | | check_cert_format(&c1, SpdmBaseAsymAlgo::TPM_ALG_ECDSA_ECC_NIST_P384), |
1310 | | Ok(472) |
1311 | | ); |
1312 | | assert_eq!( |
1313 | | check_cert_format(&c2, SpdmBaseAsymAlgo::TPM_ALG_ECDSA_ECC_NIST_P384), |
1314 | | Ok(480) |
1315 | | ); |
1316 | | assert_eq!( |
1317 | | check_cert_format(&c3, SpdmBaseAsymAlgo::TPM_ALG_ECDSA_ECC_NIST_P384), |
1318 | | Ok(587) |
1319 | | ); |
1320 | | assert_eq!( |
1321 | | check_cert_format(&c3, SpdmBaseAsymAlgo::TPM_ALG_ECDSA_ECC_NIST_P256), |
1322 | | Err(SPDM_STATUS_VERIF_FAIL) |
1323 | | ); |
1324 | | assert_eq!( |
1325 | | check_cert_format(&c1_wrong, SpdmBaseAsymAlgo::TPM_ALG_ECDSA_ECC_NIST_P384), |
1326 | | Err(SPDM_STATUS_VERIF_FAIL) |
1327 | | ); |
1328 | | } |
1329 | | |
1330 | | #[test] |
1331 | | fn test_case0_check_cert_chain_format() { |
1332 | | let ct1 = std::fs::read("../test_key/ecp256/bundle_responder.certchain.der") |
1333 | | .expect("unable to read ca cert!"); |
1334 | | let ct2 = std::fs::read("../test_key/ecp384/bundle_responder.certchain.der") |
1335 | | .expect("unable to read ca cert!"); |
1336 | | let ct3 = std::fs::read("../test_key/rsa2048/bundle_responder.certchain.der") |
1337 | | .expect("unable to read ca cert!"); |
1338 | | let ct4 = std::fs::read("../test_key/rsa3072/bundle_responder.certchain.der") |
1339 | | .expect("unable to read ca cert!"); |
1340 | | let ct5 = std::fs::read("../test_key/rsa4096/bundle_responder.certchain.der") |
1341 | | .expect("unable to read ca cert!"); |
1342 | | |
1343 | | let ct1_wrong = [0x30, 0x82, 0x01, 0xA8, 0xA0]; |
1344 | | |
1345 | | assert_eq!( |
1346 | | check_cert_chain_format(&ct1, SpdmBaseAsymAlgo::TPM_ALG_ECDSA_ECC_NIST_P256), |
1347 | | Ok(3) |
1348 | | ); |
1349 | | assert_eq!( |
1350 | | check_cert_chain_format(&ct2, SpdmBaseAsymAlgo::TPM_ALG_ECDSA_ECC_NIST_P384), |
1351 | | Ok(3) |
1352 | | ); |
1353 | | assert_eq!( |
1354 | | check_cert_chain_format(&ct3, SpdmBaseAsymAlgo::TPM_ALG_RSASSA_2048), |
1355 | | Ok(3) |
1356 | | ); |
1357 | | assert_eq!( |
1358 | | check_cert_chain_format(&ct4, SpdmBaseAsymAlgo::TPM_ALG_RSASSA_3072), |
1359 | | Ok(3) |
1360 | | ); |
1361 | | assert_eq!( |
1362 | | check_cert_chain_format(&ct5, SpdmBaseAsymAlgo::TPM_ALG_RSASSA_4096), |
1363 | | Ok(3) |
1364 | | ); |
1365 | | assert_eq!( |
1366 | | check_cert_chain_format(&ct3, SpdmBaseAsymAlgo::TPM_ALG_ECDSA_ECC_NIST_P256), |
1367 | | Err(SPDM_STATUS_VERIF_FAIL) |
1368 | | ); |
1369 | | assert_eq!( |
1370 | | check_cert_chain_format(&ct1_wrong, SpdmBaseAsymAlgo::TPM_ALG_ECDSA_ECC_NIST_P384), |
1371 | | Err(SPDM_STATUS_VERIF_FAIL) |
1372 | | ); |
1373 | | } |
1374 | | |
1375 | | #[test] |
1376 | | fn test_case0_is_root_certificate() { |
1377 | | let ca1 = std::fs::read("../test_key/ecp256/ca.cert.der").expect("unable to read ca cert!"); |
1378 | | let ca2 = |
1379 | | std::fs::read("../test_key/ecp256/ca1.cert.der").expect("unable to read ca1 cert!"); |
1380 | | let inter1 = |
1381 | | std::fs::read("../test_key/ecp256/inter.cert.der").expect("unable to read inter cert!"); |
1382 | | let end1 = std::fs::read("../test_key/ecp256/end_requester1.cert.der") |
1383 | | .expect("unable to read end cert!"); |
1384 | | let end2 = std::fs::read("../test_key/ecp256/end_responder1.cert.der") |
1385 | | .expect("unable to read end cert!"); |
1386 | | |
1387 | | let ct1_wrong = [0x30, 0x82, 0x01, 0xA8, 0xA0]; |
1388 | | |
1389 | | assert!(is_root_certificate(&ca1).is_ok()); |
1390 | | assert!(is_root_certificate(&ca2).is_ok()); |
1391 | | |
1392 | | assert!(is_root_certificate(&inter1).is_err()); |
1393 | | assert!(is_root_certificate(&end1).is_err()); |
1394 | | assert!(is_root_certificate(&end2).is_err()); |
1395 | | assert!(is_root_certificate(&ct1_wrong).is_err()); |
1396 | | } |
1397 | | |
1398 | | #[test] |
1399 | | fn test_case0_get_key_usage_value() { |
1400 | | let key_usage1 = &[ |
1401 | | 0x30, 0x0B, 0x06, 0x03, 0x55, 0x1D, 0x0F, 0x04, 0x04, 0x03, 0x02, 0x05, 0xE0, |
1402 | | ]; |
1403 | | let key_usage2_wrong = &[ |
1404 | | 0x30, 0x0B, 0x06, 0x03, 0x55, 0x1D, 0x0E, 0x04, 0x04, 0x03, 0x02, 0x05, 0xE0, |
1405 | | ]; |
1406 | | let key_usage3_wrong = &[0x30, 0x0B]; |
1407 | | let key_usage4_wrong = &[ |
1408 | | 0x30, 0x0B, 0x06, 0x03, 0x55, 0x1D, 0x0F, 0x04, 0x04, 0x03, 0x02, 0x05, |
1409 | | ]; |
1410 | | assert_eq!(get_key_usage_value(key_usage1), Ok((true, 0xE0))); |
1411 | | assert_eq!(get_key_usage_value(key_usage2_wrong), Ok((false, 0x00))); |
1412 | | assert_eq!( |
1413 | | get_key_usage_value(key_usage3_wrong), |
1414 | | Err(SPDM_STATUS_VERIF_FAIL) |
1415 | | ); |
1416 | | assert_eq!( |
1417 | | get_key_usage_value(key_usage4_wrong), |
1418 | | Err(SPDM_STATUS_VERIF_FAIL) |
1419 | | ); |
1420 | | } |
1421 | | |
1422 | | #[test] |
1423 | | fn test_case1_get_key_usage_value() { |
1424 | | let key_usage1 = std::fs::read("../test_key/ecp384/end_responder.cert.der") |
1425 | | .expect("unable to read leaf cert!"); |
1426 | | let key_usage2 = |
1427 | | std::fs::read("../test_key/rsa2048/end_requester_with_spdm_rsp_eku.cert.der") |
1428 | | .expect("unable to read leaf cert!"); |
1429 | | let key_usage3 = |
1430 | | std::fs::read("../test_key/rsa2048/end_responder_with_spdm_req_eku.cert.der") |
1431 | | .expect("unable to read leaf cert!"); |
1432 | | |
1433 | | let key_usage1_wrong = &[ |
1434 | | 0x30, 0x0, 0x30, 0x0, 0xa0, 0x3, 0x2, 0x1, 0x2, 0x8, 0x0, 0x30, 0x6, 0x6, 0x6, 0x6, |
1435 | | 0x20, 0x6, 0x0, 0x30, 0x0, 0x30, 0x0, 0x30, 0x6, 0x6, 0x20, 0x26, 0x0, 0x30, 0x0, 0x30, |
1436 | | 0x20, 0x30, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x20, |
1437 | | 0x30, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, |
1438 | | 0x16, 0x16, 0x16, 0x16, 0x4, 0x30, 0x32, 0x10, 0x2, 0x8, 0x0, 0x30, 0x6, 0x6, 0x6, 0x6, |
1439 | | 0x20, 0x6, 0x0, 0x30, 0x0, 0x30, 0x0, 0x30, 0x6, 0x6, 0x20, 0x26, 0x0, 0x30, 0x0, 0x30, |
1440 | | 0x21, 0x30, 0x4, 0x30, 0xa0, 0x1, 0x2, 0x8, 0x0, 0xbb, 0x0, 0x30, 0x2, 0x8, 0x0, 0x0, |
1441 | | 0x0, 0x0, 0x0, 0xbb, 0x6, 0x6, 0x6, 0x6, 0x20, 0x26, 0x0, 0x6, 0x3, 0x55, 0x1d, 0xf, |
1442 | | ]; |
1443 | | let key_usage2_wrong = &[ |
1444 | | 0x30, 0x0, 0x30, 0x0, 0xa0, 0x3, 0x2, 0x1, 0x2, 0x8, 0x0, 0x30, 0x6, 0x6, 0x6, 0x6, |
1445 | | 0x20, 0x6, 0x0, 0x30, 0x0, 0x30, 0x0, 0x30, 0x6, 0x6, 0x20, 0x26, 0x0, 0x30, 0x0, 0x30, |
1446 | | 0x20, 0x30, 0x4, 0x30, 0x32, 0x10, 0x2, 0x8, 0x0, 0x30, 0x6, 0x6, 0x6, 0x6, 0x20, 0x6, |
1447 | | 0x0, 0x30, 0x66, 0x30, 0x0, 0x30, 0x6, 0x6, 0x20, 0x26, 0x0, 0x30, 0x0, 0x30, 0x20, |
1448 | | 0x30, 0x4, 0x30, 0x32, 0x10, 0x30, 0x31, 0x31, 0x31, 0x31, 0x6, 0x20, 0x26, 0x0, 0x30, |
1449 | | 0x0, 0x30, 0x31, 0x31, 0x31, 0xff, 0xff, 0xff, 0xff, 0x0, 0x8, 0x6, 0x27, 0x3, 0x55, |
1450 | | 0x1d, 0xf, 0x4, 0x0, 0x30, 0x0, 0x30, 0x0, 0xa0, 0x3, 0x2, 0x1, 0x26, 0x0, 0x0, 0x0, |
1451 | | 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x6, 0x3, 0x55, 0x1d, 0xf, |
1452 | | ]; |
1453 | | |
1454 | | assert_eq!( |
1455 | | get_key_usage_value(&key_usage1[280..]), |
1456 | | Ok((true, key_usage1[309])) |
1457 | | ); |
1458 | | assert_eq!( |
1459 | | get_key_usage_value(&key_usage2[450..]), |
1460 | | Ok((true, key_usage2[478])) |
1461 | | ); |
1462 | | assert_eq!( |
1463 | | get_key_usage_value(&key_usage3[450..]), |
1464 | | Ok((true, key_usage3[478])) |
1465 | | ); |
1466 | | assert_eq!( |
1467 | | get_key_usage_value(key_usage1_wrong), |
1468 | | Err(SPDM_STATUS_VERIF_FAIL) |
1469 | | ); |
1470 | | assert_eq!( |
1471 | | get_key_usage_value(key_usage2_wrong), |
1472 | | Err(SPDM_STATUS_VERIF_FAIL) |
1473 | | ); |
1474 | | } |
1475 | | |
1476 | | #[test] |
1477 | | fn test_case0_check_extensions_spdm_oid() { |
1478 | | let e1 = std::fs::read("../test_key/ecp384/end_responder.cert.der") |
1479 | | .expect("unable to read leaf cert!"); |
1480 | | let e2 = std::fs::read("../test_key/rsa2048/end_requester_with_spdm_rsp_eku.cert.der") |
1481 | | .expect("unable to read leaf cert!"); |
1482 | | let e3 = std::fs::read("../test_key/rsa2048/end_responder_with_spdm_req_eku.cert.der") |
1483 | | .expect("unable to read leaf cert!"); |
1484 | | assert_eq!(check_extensions_spdm_oid(&e1[280..], false), Ok(true)); |
1485 | | assert_eq!(check_extensions_spdm_oid(&e1[280..], true), Ok(true)); |
1486 | | assert_eq!(check_extensions_spdm_oid(&e2[450..], true), Ok(true)); |
1487 | | assert_eq!(check_extensions_spdm_oid(&e2[450..], false), Ok(false)); |
1488 | | assert_eq!(check_extensions_spdm_oid(&e3[450..], true), Ok(true)); |
1489 | | assert_eq!(check_extensions_spdm_oid(&e3[450..], false), Ok(false)); |
1490 | | } |
1491 | | |
1492 | | #[test] |
1493 | | fn test_case0_check_and_get_extn_id() { |
1494 | | let extension_s1 = &[ |
1495 | | 0x30, 0x0C, 0x06, 0x03, 0x55, 0x1D, 0x13, 0x01, 0x01, 0xFF, 0x04, 0x02, 0x30, 0x00, |
1496 | | ]; |
1497 | | let extension_s2 = &[ |
1498 | | 0x30, 0x2A, 0x06, 0x03, 0x55, 0x1D, 0x25, 0x01, 0x01, 0xFF, 0x04, 0x20, 0x30, 0x1E, |
1499 | | 0x06, 0x08, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2B, 0x06, |
1500 | | 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x06, 0x08, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, |
1501 | | 0x03, 0x09, |
1502 | | ]; |
1503 | | let extension_s3_wrong = &[ |
1504 | | 0x30, 0x0D, 0x06, 0x03, 0x55, 0x1D, 0x13, 0x01, 0x01, 0xFF, 0x04, 0x02, 0x30, 0x00, |
1505 | | ]; |
1506 | | let extension_sa4_wrong = &[ |
1507 | | 0x30, 0x0C, 0x05, 0x03, 0x55, 0x1D, 0x13, 0x01, 0x01, 0xFF, 0x04, 0x02, 0x30, 0x00, |
1508 | | ]; |
1509 | | let oid1: &[u8] = &[0x55, 0x1D, 0x13]; |
1510 | | let oid2: &[u8] = &[0x55, 0x1D, 0x25]; |
1511 | | assert_eq!(check_and_get_extn_id(extension_s1), Ok((oid1, 14))); |
1512 | | assert_eq!(check_and_get_extn_id(extension_s2), Ok((oid2, 44))); |
1513 | | assert_eq!( |
1514 | | check_and_get_extn_id(extension_s3_wrong), |
1515 | | Err(SPDM_STATUS_VERIF_FAIL) |
1516 | | ); |
1517 | | assert_eq!( |
1518 | | check_and_get_extn_id(extension_sa4_wrong), |
1519 | | Err(SPDM_STATUS_VERIF_FAIL) |
1520 | | ); |
1521 | | } |
1522 | | |
1523 | | #[test] |
1524 | | fn test_case0_find_target_object_identifiers() { |
1525 | | let extension_s1 = &[ |
1526 | | 0x30, 0x0C, 0x06, 0x03, 0x55, 0x1D, 0x13, 0x01, 0x01, 0xFF, 0x04, 0x02, 0x30, 0x00, |
1527 | | ]; |
1528 | | let extension_s2 = &[ |
1529 | | 0x04, 0x2C, 0x30, 0x2A, 0x06, 0x08, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, |
1530 | | 0x06, 0x08, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x06, 0x08, 0x2B, 0x06, |
1531 | | 0x01, 0x05, 0x05, 0x07, 0x03, 0x09, 0x06, 0x0A, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, |
1532 | | 0x1C, 0x82, 0x12, 0x04, |
1533 | | ]; |
1534 | | let extension_s3_wrong = &[ |
1535 | | 0x30, 0x0D, 0x06, 0x03, 0x55, 0x1D, 0x13, 0x01, 0x01, 0xFF, 0x04, 0x03, 0x30, 0x00, |
1536 | | 0x00, |
1537 | | ]; |
1538 | | let extension_sa4_wrong = &[ |
1539 | | 0x30, 0x0C, 0x05, 0x03, 0x55, 0x1D, 0x13, 0x01, 0x01, 0xFF, 0x04, 0x02, 0x30, 0x00, |
1540 | | ]; |
1541 | | assert_eq!( |
1542 | | find_target_object_identifier_in_single_extension(extension_s1, &[0x55, 0x1D, 0x13]), |
1543 | | Ok(true) |
1544 | | ); |
1545 | | assert_eq!( |
1546 | | find_target_object_identifier_in_single_extension( |
1547 | | extension_s2, |
1548 | | &[0x2B, 0x06, 0x01, 0x04, 0x01, 0x83, 0x1C, 0x82, 0x12, 0x04] |
1549 | | ), |
1550 | | Ok(true) |
1551 | | ); |
1552 | | assert_eq!( |
1553 | | find_target_object_identifier_in_single_extension( |
1554 | | extension_s3_wrong, |
1555 | | &[0x55, 0x1D, 0x14] |
1556 | | ), |
1557 | | Ok(false) |
1558 | | ); |
1559 | | assert_eq!( |
1560 | | find_target_object_identifier_in_single_extension( |
1561 | | extension_sa4_wrong, |
1562 | | &[0x55, 0x1D, 0x13] |
1563 | | ), |
1564 | | Ok(false) |
1565 | | ); |
1566 | | } |
1567 | | |
1568 | | #[test] |
1569 | | fn test_case0_check_leaf_certificate() { |
1570 | | let end1 = std::fs::read("../test_key/rsa2048/end_responder_with_spdm_rsp_eku.cert.der") |
1571 | | .expect("unable to read end cert!"); |
1572 | | let end2 = std::fs::read("../test_key/ecp384/end_responder.cert.der") |
1573 | | .expect("unable to read end cert!"); |
1574 | | |
1575 | | let ct1_wrong = [0x30, 0x82, 0x01, 0xA8, 0xA0]; |
1576 | | |
1577 | | assert!(check_leaf_certificate(&end1, true).is_ok()); |
1578 | | assert!(check_leaf_certificate(&end1, false).is_ok()); |
1579 | | assert!(check_leaf_certificate(&end2, false).is_ok()); |
1580 | | assert!(check_leaf_certificate(&end2, true).is_err()); |
1581 | | assert!(check_leaf_certificate(&ct1_wrong, true).is_err()); |
1582 | | assert!(check_leaf_certificate(&ct1_wrong, false).is_err()); |
1583 | | } |
1584 | | |
1585 | | #[test] |
1586 | | fn test_check_length_short_form() { |
1587 | | let data = [0x03, 0x01, 0x02, 0x03]; |
1588 | | assert_eq!(check_length(&data), Ok((3, 1))); |
1589 | | } |
1590 | | |
1591 | | #[test] |
1592 | | fn test_check_length_short_form_large_than_128() { |
1593 | | let data = [0x80]; |
1594 | | assert_eq!(check_length(&data), Err(SPDM_STATUS_VERIF_FAIL)); |
1595 | | } |
1596 | | |
1597 | | #[test] |
1598 | | fn test_check_length_long_form() { |
1599 | | let data = [ |
1600 | | 0x81, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1601 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1602 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1603 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1604 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1605 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1606 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1607 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1608 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1609 | | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
1610 | | ]; |
1611 | | assert_eq!(check_length(&data), Ok((0x80, 2))); |
1612 | | } |
1613 | | |
1614 | | #[test] |
1615 | | fn test_check_length_long_form_smaller_than_128() { |
1616 | | let data: [u8; 2] = [0x81, 0x7F]; |
1617 | | assert_eq!(check_length(&data), Err(SPDM_STATUS_VERIF_FAIL)); |
1618 | | } |
1619 | | |
1620 | | #[test] |
1621 | | fn test_check_length_overflow_the_length_of_k_octets_bytes_is_less_than_k() { |
1622 | | // First Octet + k + l octets |
1623 | | // bit0..=6 k Length l |
1624 | | // k = 5 |
1625 | | // length(k(octets)) < 5 |
1626 | | let data = [0x85, 0xFF, 0xFF, 0xFF, 0xFF]; |
1627 | | assert_eq!(check_length(&data), Err(SPDM_STATUS_VERIF_FAIL)); |
1628 | | } |
1629 | | |
1630 | | #[test] |
1631 | | fn test_check_cert_format_large_length() { |
1632 | | let cert = std::fs::read("../test_key/ecp384/bundle_requester.certchain.der") |
1633 | | .expect("unable to read ca cert!"); |
1634 | | let mut malformed_cert = cert.clone(); |
1635 | | malformed_cert[1] = 0x88; |
1636 | | for i in 2..10 { |
1637 | | malformed_cert[i] = 0xff; |
1638 | | } |
1639 | | assert_eq!( |
1640 | | check_cert_format( |
1641 | | &malformed_cert, |
1642 | | SpdmBaseAsymAlgo::TPM_ALG_ECDSA_ECC_NIST_P384 |
1643 | | ), |
1644 | | Err(SPDM_STATUS_VERIF_FAIL) |
1645 | | ); |
1646 | | } |
1647 | | } |