1use crate::igvm_attest::Error as CommonError;
7use crate::igvm_attest::parse_response_header;
8use der::Decode;
9use der::Reader;
10use der::SliceReader;
11use der::Tag;
12use der::TagNumber;
13use der::Tagged;
14use der::asn1::AnyRef;
15use der::asn1::BitStringRef;
16use der::asn1::BmpString;
17use der::asn1::GeneralizedTime;
18use der::asn1::IntRef;
19use der::asn1::ObjectIdentifier;
20use der::asn1::OctetStringRef;
21use der::asn1::PrintableStringRef;
22use der::asn1::TeletexStringRef;
23use der::asn1::UtcTime;
24use der::asn1::Utf8StringRef;
25use openhcl_attestation_protocol::igvm_attest::get::runtime_claims::AkCertMetadata;
26use thiserror::Error;
27use zerocopy::FromBytes;
28
29#[derive(Debug, PartialEq, Eq)]
31pub enum AkCertResponse {
32 Certificate(Vec<u8>),
34 NoRenewal,
36}
37
38#[derive(Debug, Error)]
40pub enum AkCertMetadataError {
41 #[error("invalid AK certificate metadata")]
42 Decode(#[from] der::Error),
43 #[error("AK certificate has no {0} common name")]
44 MissingCommonName(&'static str),
45}
46
47pub fn parse_metadata(data: &[u8]) -> Result<AkCertMetadata, AkCertMetadataError> {
56 SliceReader::new(data)?.sequence(|certificate| {
59 let metadata = certificate.sequence(|tbs| {
60 let version = match optional_field(tbs, TagNumber(0).context_specific(true))? {
61 Some(field) => {
62 let version = u8::from_der(field.value())?;
63 if !(1..=2).contains(&version) {
65 return Err(der::Error::from(Tag::Integer.value_error()).into());
66 }
67 version
68 }
69 None => 0,
70 };
71 check_serial(tbs.decode()?)?;
72 skip_algorithm(tbs)?;
73 let issuer = common_name(tbs, "issuer")?;
74 let (not_before, not_after) = tbs.sequence(|validity| {
75 Ok::<_, der::Error>((
76 time_content(validity.decode()?)?,
77 time_content(validity.decode()?)?,
78 ))
79 })?;
80 let subject = common_name(tbs, "subject")?;
81 tbs.sequence(|spki| {
83 skip_algorithm(spki)?;
84 spki.decode::<AnyRef<'_>>()?
85 .decode_as::<BitStringRef<'_>>()?;
86 Ok::<_, der::Error>(())
87 })?;
88 for number in [1, 2] {
89 if let Some(uid) = optional_field(tbs, TagNumber(number).context_specific(false))? {
90 if version == 0 {
91 return Err(der::Error::from(uid.tag().value_error()).into());
92 }
93 AnyRef::new(Tag::BitString, uid.value())?.decode_as::<BitStringRef<'_>>()?;
94 }
95 }
96 let authority = match optional_field(tbs, TagNumber(3).context_specific(true))? {
97 Some(field) => {
98 if version != 2 {
99 return Err(der::Error::from(field.tag().value_error()).into());
100 }
101 authority_key_identifier(field.value())?
102 }
103 None => None,
104 };
105 Ok::<_, AkCertMetadataError>(AkCertMetadata {
106 issuer,
107 subject,
108 not_before,
109 not_after,
110 authority: authority.map(hex::encode_upper).unwrap_or_default(),
111 })
112 })?;
113 skip_algorithm(certificate)?;
114 certificate
115 .decode::<AnyRef<'_>>()?
116 .decode_as::<BitStringRef<'_>>()?;
117 Ok(metadata)
118 })
119}
120
121fn optional_field<'a>(reader: &mut SliceReader<'a>, tag: Tag) -> der::Result<Option<AnyRef<'a>>> {
125 if !reader.is_finished() && Tag::peek(reader)? == tag {
126 reader.decode().map(Some)
127 } else {
128 Ok(None)
129 }
130}
131
132fn check_serial(serial: AnyRef<'_>) -> der::Result<()> {
133 if serial.decode_as::<IntRef<'_>>()?.as_bytes().len() > 21 {
135 return Err(Tag::Integer.value_error().into());
136 }
137 Ok(())
138}
139
140fn skip_algorithm(reader: &mut SliceReader<'_>) -> der::Result<()> {
141 reader.sequence(|algorithm| {
142 algorithm.decode::<ObjectIdentifier>()?;
143 if !algorithm.is_finished() {
144 algorithm.decode::<AnyRef<'_>>()?;
145 }
146 Ok(())
147 })
148}
149
150fn common_name(
151 reader: &mut SliceReader<'_>,
152 name: &'static str,
153) -> Result<String, AkCertMetadataError> {
154 const COMMON_NAME: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.5.4.3");
155 let mut cn = None;
156 reader.sequence(|rdns| {
157 while !rdns.is_finished() {
158 let set = rdns.decode::<AnyRef<'_>>()?;
159 set.tag().assert_eq(Tag::Set)?;
160 let mut attributes = SliceReader::new(set.value())?;
161 if attributes.is_finished() {
162 return Err(Tag::Set.value_error().into());
163 }
164 let mut previous = None;
165 while !attributes.is_finished() {
166 let encoded = attributes.tlv_bytes()?;
167 if previous.is_some_and(|previous| previous > encoded) {
168 return Err(Tag::Set.non_canonical_error().into());
169 }
170 previous = Some(encoded);
171 AnyRef::from_der(encoded)?.sequence(|attribute| {
172 let oid = attribute.decode::<ObjectIdentifier>()?;
173 let value = attribute.decode::<AnyRef<'_>>()?;
174 if oid == COMMON_NAME && cn.is_none() {
177 cn = Some(value);
178 }
179 Ok::<_, der::Error>(())
180 })?;
181 }
182 attributes.finish()?;
183 }
184 Ok::<_, der::Error>(())
185 })?;
186 Ok(directory_string(
187 cn.ok_or(AkCertMetadataError::MissingCommonName(name))?,
188 )?)
189}
190
191fn directory_string(value: AnyRef<'_>) -> der::Result<String> {
192 match value.tag() {
195 Tag::Utf8String => Ok(value.decode_as::<Utf8StringRef<'_>>()?.as_str().to_owned()),
196 Tag::PrintableString => Ok(value
197 .decode_as::<PrintableStringRef<'_>>()?
198 .as_str()
199 .to_owned()),
200 Tag::TeletexString => Ok(value
201 .decode_as::<TeletexStringRef<'_>>()?
202 .as_str()
203 .to_owned()),
204 Tag::BmpString => Ok(value.decode_as::<BmpString>()?.to_string()),
205 tag => Err(tag.value_error().into()),
206 }
207}
208
209fn authority_key_identifier(extensions: &[u8]) -> der::Result<Option<&[u8]>> {
210 const AUTHORITY_KEY_IDENTIFIER: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.5.29.35");
211 let mut seen = false;
212 let mut key = None;
213 AnyRef::from_der(extensions)?.sequence(|extensions| {
214 if extensions.is_finished() {
215 return Err(Tag::Sequence.value_error().into());
216 }
217 while !extensions.is_finished() {
218 extensions.sequence(|extension| {
219 let oid = extension.decode::<ObjectIdentifier>()?;
220 if let Some(critical) = optional_field(extension, Tag::Boolean)? {
221 if !critical.decode_as::<bool>()? {
223 return Err(Tag::Boolean.non_canonical_error().into());
224 }
225 }
226 let value = extension.decode::<&OctetStringRef>()?;
227 if oid == AUTHORITY_KEY_IDENTIFIER {
228 if seen {
229 return Err(Tag::Sequence.value_error().into());
230 }
231 seen = true;
232 key = decode_authority_key_identifier(value.as_bytes())?;
233 }
234 Ok::<_, der::Error>(())
235 })?;
236 }
237 Ok(key)
238 })
239}
240
241fn decode_authority_key_identifier(data: &[u8]) -> der::Result<Option<&[u8]>> {
242 AnyRef::from_der(data)?.sequence(|aki| {
243 let key = optional_field(aki, TagNumber(0).context_specific(false))?;
244 if let Some(issuer) = optional_field(aki, TagNumber(1).context_specific(true))? {
245 let mut names = SliceReader::new(issuer.value())?;
248 if names.is_finished() {
249 return Err(issuer.tag().value_error().into());
250 }
251 while !names.is_finished() {
252 let name = names.decode::<AnyRef<'_>>()?;
253 match name.tag() {
254 Tag::ContextSpecific {
255 number: TagNumber(0 | 3 | 4 | 5),
256 constructed: true,
257 }
258 | Tag::ContextSpecific {
259 number: TagNumber(1 | 2 | 6 | 7 | 8),
260 constructed: false,
261 } => {}
262 tag => return Err(tag.value_error().into()),
263 }
264 }
265 names.finish()?;
266 }
267 if let Some(serial) = optional_field(aki, TagNumber(2).context_specific(false))? {
268 check_serial(AnyRef::new(Tag::Integer, serial.value())?)?;
269 }
270 Ok(key.map(|key| key.value()))
271 })
272}
273
274fn time_content(time: AnyRef<'_>) -> der::Result<String> {
275 match time.tag() {
276 Tag::UtcTime => {
277 time.decode_as::<UtcTime>()?;
278 }
279 Tag::GeneralizedTime => {
280 time.decode_as::<GeneralizedTime>()?;
281 }
282 tag => return Err(tag.value_error().into()),
283 }
284 Ok(core::str::from_utf8(time.value())
287 .map_err(|_| time.tag().value_error())?
288 .to_owned())
289}
290
291#[derive(Debug, Error)]
293pub enum AkCertError {
294 #[error(
295 "AK cert response is too small to parse. Found {size} bytes but expected at least {minimum_size}"
296 )]
297 SizeTooSmall { size: usize, minimum_size: usize },
298 #[error(
299 "AK cert response size {specified_size} specified in the header is larger then the actual size {size}"
300 )]
301 SizeMismatch { size: usize, specified_size: usize },
302 #[error(
303 "AK cert response header version {version} does match the expected version {expected_version}"
304 )]
305 HeaderVersionMismatch { version: u32, expected_version: u32 },
306 #[error("error in parsing response header")]
307 ParseHeader(#[source] CommonError),
308 #[error("invalid response header version: {0}")]
309 InvalidResponseVersion(u32),
310}
311
312pub fn parse_response(response: &[u8]) -> Result<AkCertResponse, AkCertError> {
314 use openhcl_attestation_protocol::igvm_attest::get::IgvmAttestAkCertResponseHeader;
315 use openhcl_attestation_protocol::igvm_attest::get::IgvmAttestCommonResponseHeader;
316 use openhcl_attestation_protocol::igvm_attest::get::IgvmAttestResponseVersion;
317
318 let header = parse_response_header(response).map_err(AkCertError::ParseHeader)?;
319
320 let header_size = match header.version {
322 IgvmAttestResponseVersion::VERSION_1 => size_of::<IgvmAttestCommonResponseHeader>(),
323 IgvmAttestResponseVersion::VERSION_2 => size_of::<IgvmAttestAkCertResponseHeader>(),
324 invalid_version => return Err(AkCertError::InvalidResponseVersion(invalid_version.0)),
325 };
326 let data_size = header.data_size as usize;
327
328 if data_size < header_size {
329 return Err(AkCertError::SizeTooSmall {
330 size: data_size,
331 minimum_size: header_size,
332 });
333 }
334
335 if header.version == IgvmAttestResponseVersion::VERSION_2 {
336 let (header, _) = IgvmAttestAkCertResponseHeader::read_from_prefix(&response[..data_size])
337 .map_err(|_| AkCertError::SizeTooSmall {
338 size: data_size,
339 minimum_size: header_size,
340 })?;
341 if header.error_info.igvm_signal.no_renew_cert() {
342 return Ok(AkCertResponse::NoRenewal);
343 }
344 }
345
346 Ok(AkCertResponse::Certificate(
347 response[header_size..data_size].to_vec(),
348 ))
349}
350
351#[cfg(test)]
352mod tests {
353 use super::*;
354 use der::Encode;
355 use openhcl_attestation_protocol::igvm_attest::get::IgvmAttestAkCertResponseHeader;
356 use openhcl_attestation_protocol::igvm_attest::get::IgvmAttestCommonResponseHeader;
357 use openhcl_attestation_protocol::igvm_attest::get::IgvmAttestResponseVersion;
358 use openhcl_attestation_protocol::igvm_attest::get::IgvmSignal;
359 use test_igvm_agent_lib::ak_cert::certificate;
360 use test_with_tracing::test;
361 use zerocopy::IntoBytes;
362
363 #[test]
364 fn test_certificate_metadata() {
365 let cert = certificate();
366 let metadata = parse_metadata(&cert).unwrap();
367 assert_eq!(metadata.issuer, "Test \"AK\" issuer");
368 assert_eq!(metadata.subject, "Test \"AK\" issuer");
369 assert_eq!(metadata.not_before, "261009180232Z");
370 assert_eq!(metadata.not_after, "20561120180232Z");
371 assert_eq!(
372 metadata.authority,
373 "9FF3935C2C83D84F1DB5242A0E7D3C9B1D191D3B"
374 );
375
376 let mut padded = cert.clone();
377 padded.resize(4096, 0);
378 assert_eq!(parse_metadata(&padded).unwrap(), metadata);
379 padded[cert.len()..].fill(0xa5);
380 assert_eq!(parse_metadata(&padded).unwrap(), metadata);
381 }
382
383 #[test]
384 fn test_certificate_without_authority_key_identifier() {
385 let cert = with_aki(&[der_value(TagNumber(0).context_specific(false), &[1])]);
387 assert_eq!(parse_metadata(&cert).unwrap().authority, "01");
388 let cert = edit_children(&cert, &[0, 7, 0, 0], |extension| {
389 extension[0] = ObjectIdentifier::new_unwrap("2.5.29.36").to_der().unwrap();
390 });
391 assert_eq!(parse_metadata(&cert).unwrap().authority, "");
392 }
393
394 #[test]
395 fn test_certificate_missing_common_name() {
396 for name_index in [3, 5] {
397 let cert = edit_children(&certificate(), &[0, name_index, 0, 0], |attribute| {
398 attribute[0] = ObjectIdentifier::new_unwrap("2.5.4.10").to_der().unwrap();
399 });
400 assert!(matches!(
401 parse_metadata(&cert),
402 Err(AkCertMetadataError::MissingCommonName(_))
403 ));
404 }
405 }
406
407 #[test]
408 fn test_invalid_certificate_metadata() {
409 let cert = certificate();
410 for size in 0..cert.len() {
411 assert!(parse_metadata(&cert[..size]).is_err());
412 }
413 assert!(parse_metadata(&[0; 4096]).is_err());
414 let cert = with_aki(&[vec![0x80, 2, 1]]);
416 assert!(parse_metadata(&cert).is_err());
417 }
418
419 fn der_value(tag: Tag, value: &[u8]) -> Vec<u8> {
420 AnyRef::new(tag, value).unwrap().to_der().unwrap()
421 }
422
423 fn der_children(data: &[u8]) -> Vec<Vec<u8>> {
424 let value = AnyRef::from_der(data).unwrap();
425 let mut reader = SliceReader::new(value.value()).unwrap();
426 let mut children = Vec::new();
427 while !reader.is_finished() {
428 children.push(reader.tlv_bytes().unwrap().to_vec());
429 }
430 reader.finish().unwrap();
431 children
432 }
433
434 fn edit_children(data: &[u8], path: &[usize], edit: impl FnOnce(&mut Vec<Vec<u8>>)) -> Vec<u8> {
437 let mut children = der_children(data);
438 if let Some((&index, rest)) = path.split_first() {
439 children[index] = edit_children(&children[index], rest, edit);
440 } else {
441 edit(&mut children);
442 }
443 der_value(AnyRef::from_der(data).unwrap().tag(), &children.concat())
444 }
445
446 fn with_aki(fields: &[Vec<u8>]) -> Vec<u8> {
447 let extension = der_value(
448 Tag::Sequence,
449 &[
450 ObjectIdentifier::new_unwrap("2.5.29.35").to_der().unwrap(),
451 der_value(
452 Tag::OctetString,
453 &der_value(Tag::Sequence, &fields.concat()),
454 ),
455 ]
456 .concat(),
457 );
458 edit_children(&certificate(), &[0], |tbs| {
459 tbs.truncate(7);
460 tbs.push(der_value(
461 TagNumber(3).context_specific(true),
462 &der_value(Tag::Sequence, &extension),
463 ));
464 })
465 }
466
467 #[test]
468 fn test_metadata_without_optional_fields() {
469 let fixture = certificate();
470 let expected = AkCertMetadata {
471 authority: String::new(),
472 ..parse_metadata(&fixture).unwrap()
473 };
474 for omit_version in [false, true] {
476 let cert = edit_children(&fixture, &[0], |tbs| {
477 tbs.truncate(7);
478 if omit_version {
479 tbs.remove(0);
480 }
481 });
482 assert_eq!(parse_metadata(&cert).unwrap(), expected);
483 }
484 assert_eq!(parse_metadata(&with_aki(&[])).unwrap(), expected);
485
486 let issuer = der_value(
487 TagNumber(1).context_specific(true),
488 &der_value(TagNumber(2).context_specific(false), b"issuer.example"),
489 );
490 let serial = der_value(TagNumber(2).context_specific(false), &[1]);
491 assert_eq!(
493 parse_metadata(&with_aki(&[issuer.clone(), serial.clone()])).unwrap(),
494 expected
495 );
496 let key = der_value(TagNumber(0).context_specific(false), &[0xab, 0xcd]);
497 assert_eq!(
498 parse_metadata(&with_aki(&[key, issuer, serial]))
499 .unwrap()
500 .authority,
501 "ABCD"
502 );
503 }
504
505 #[test]
506 fn test_metadata_duplicate_aki_extension() {
507 for fields in [
509 vec![],
510 vec![der_value(TagNumber(0).context_specific(false), &[1])],
511 ] {
512 let cert = edit_children(&with_aki(&fields), &[0, 7, 0], |extensions| {
513 extensions.push(extensions[0].clone());
514 });
515 assert!(parse_metadata(&cert).is_err());
516 }
517 }
518
519 #[test]
520 fn test_metadata_invalid_aki_fields() {
521 let key = der_value(TagNumber(0).context_specific(false), &[1]);
522 let serial = der_value(TagNumber(2).context_specific(false), &[1]);
523 let malformed_fields = [
524 vec![key.clone(), key.clone()],
525 vec![serial.clone(), key],
526 vec![serial.clone(), serial],
527 vec![der_value(TagNumber(0).context_specific(true), &[1])],
528 vec![der_value(TagNumber(1).context_specific(false), &[])],
529 vec![der_value(TagNumber(1).context_specific(true), &[])],
530 vec![der_value(
532 TagNumber(1).context_specific(true),
533 &[0x82, 2, b'a'],
534 )],
535 vec![der_value(
536 TagNumber(1).context_specific(true),
537 &der_value(Tag::Null, &[]),
538 )],
539 vec![der_value(TagNumber(2).context_specific(true), &[1])],
540 vec![der_value(TagNumber(2).context_specific(false), &[])],
541 vec![der_value(TagNumber(2).context_specific(false), &[0, 1])],
542 vec![der_value(TagNumber(2).context_specific(false), &[1; 22])],
543 vec![der_value(TagNumber(3).context_specific(false), &[])],
544 ];
545 for fields in malformed_fields {
546 assert!(parse_metadata(&with_aki(&fields)).is_err(), "{fields:?}");
547 }
548 for payload in [
550 der_value(Tag::Null, &[]),
551 vec![0x30, 1],
552 vec![0x30, 0, 0x05, 0],
553 ] {
554 let cert = edit_children(&with_aki(&[]), &[0, 7, 0, 0], |extension| {
555 extension[1] = der_value(Tag::OctetString, &payload);
556 });
557 assert!(parse_metadata(&cert).is_err());
558 }
559 }
560
561 #[test]
562 fn test_metadata_optional_field_order_and_tags() {
563 let fixture = certificate();
564 let issuer_uid = der_value(TagNumber(1).context_specific(false), &[0, 0x80]);
565 let subject_uid = der_value(TagNumber(2).context_specific(false), &[0, 0x40]);
566 for uids in [
567 vec![issuer_uid.clone()],
568 vec![subject_uid.clone()],
569 vec![issuer_uid.clone(), subject_uid.clone()],
570 ] {
571 let cert = edit_children(&fixture, &[0], |tbs| {
572 tbs.splice(7..7, uids);
573 });
574 assert_eq!(
575 parse_metadata(&cert).unwrap(),
576 parse_metadata(&fixture).unwrap()
577 );
578 }
579 for uids in [
580 vec![issuer_uid.clone(), issuer_uid.clone()],
581 vec![subject_uid.clone(), issuer_uid],
582 vec![subject_uid.clone(), subject_uid],
583 vec![der_value(TagNumber(1).context_specific(true), &[0])],
584 vec![der_value(TagNumber(2).context_specific(false), &[8, 0])],
585 vec![der_value(TagNumber(4).context_specific(false), &[])],
586 ] {
587 let cert = edit_children(&fixture, &[0], |tbs| {
588 tbs.splice(7..7, uids);
589 });
590 assert!(parse_metadata(&cert).is_err());
591 }
592 for index in [0, 7] {
593 let cert = edit_children(&fixture, &[0], |tbs| {
594 tbs.insert(index, tbs[index].clone());
595 });
596 assert!(parse_metadata(&cert).is_err());
597 }
598 for version in [0u8, 1, 3, 255] {
599 let cert = edit_children(&fixture, &[0, 0], |fields| {
600 fields[0] = version.to_der().unwrap();
601 });
602 assert!(parse_metadata(&cert).is_err());
603 }
604 let cert = edit_children(&fixture, &[0], |tbs| {
605 tbs.push(der_value(TagNumber(1).context_specific(false), &[0]));
606 });
607 assert!(parse_metadata(&cert).is_err());
608 }
609
610 #[test]
611 fn test_metadata_nested_sequences_are_fully_consumed() {
612 let fixture = certificate();
613 for path in [
616 vec![],
617 vec![0],
618 vec![0, 0],
619 vec![0, 2],
620 vec![1],
621 vec![0, 3, 0, 0],
622 vec![0, 4],
623 vec![0, 5, 0, 0],
624 vec![0, 6],
625 vec![0, 6, 0],
626 vec![0, 7],
627 vec![0, 7, 0, 0],
628 ] {
629 let cert = edit_children(&fixture, &path, |fields| {
630 fields.push(der_value(Tag::Null, &[]));
632 fields.push(der_value(Tag::Null, &[]));
633 });
634 assert!(parse_metadata(&cert).is_err(), "extra field at {path:?}");
635 let mut missing_optional = path == [0];
636 let cert = edit_children(&fixture, &path, |fields| {
637 fields.pop().unwrap();
638 if [vec![0, 2], vec![1], vec![0, 6, 0]].contains(&path) {
640 missing_optional = fields.len() == 1;
641 }
642 });
643 if missing_optional {
644 assert!(parse_metadata(&cert).is_ok(), "optional field at {path:?}");
645 } else {
646 assert!(parse_metadata(&cert).is_err(), "missing field at {path:?}");
647 }
648 }
649 for index in 0..3 {
650 let cert = edit_children(&fixture, &[], |fields| {
651 fields[index] = der_value(Tag::Null, &[]);
652 });
653 assert!(parse_metadata(&cert).is_err());
654 }
655 for index in 0..8 {
656 let cert = edit_children(&fixture, &[0], |fields| {
657 fields[index] = der_value(Tag::Null, &[]);
658 });
659 assert!(parse_metadata(&cert).is_err());
660 }
661 let cert = edit_children(&fixture, &[0, 3], |rdns| {
662 rdns[0] = der_value(Tag::Set, &[]);
663 });
664 assert!(parse_metadata(&cert).is_err());
665 let cert = edit_children(&fixture, &[0, 3, 0], |attributes| {
666 attributes.push(vec![0x30, 2, 0x06]);
667 });
668 assert!(parse_metadata(&cert).is_err());
669 }
670
671 #[test]
672 fn test_metadata_directory_strings() {
673 let fixture = certificate();
674 for name in [3, 5] {
675 for (tag, content, expected) in [
676 (Tag::Utf8String, "AK é 水 😀".as_bytes(), "AK é 水 😀"),
677 (
678 Tag::PrintableString,
679 b"AZaz09 '()+,-./:=?".as_slice(),
680 "AZaz09 '()+,-./:=?",
681 ),
682 (Tag::BmpString, b"\x00A\x00K\x00 \x00\xe9\x6c\x34", "AK é水"),
683 (
684 Tag::TeletexString,
685 b"Test \"AK\" @issuer\x7f",
686 "Test \"AK\" @issuer\x7f",
687 ),
688 (Tag::Utf8String, b"", ""),
690 (Tag::PrintableString, b"", ""),
691 (Tag::BmpString, b"", ""),
692 (Tag::TeletexString, b"", ""),
693 ] {
694 let cert = edit_children(&fixture, &[0, name, 0, 0], |attribute| {
695 attribute[1] = der_value(tag, content);
696 });
697 let metadata = parse_metadata(&cert).unwrap();
698 assert_eq!(
699 if name == 3 {
700 metadata.issuer
701 } else {
702 metadata.subject
703 },
704 expected,
705 "{tag:?} at name {name}"
706 );
707 }
708 for value in [
709 der_value(Tag::Utf8String, &[0xff]),
710 der_value(Tag::Utf8String, &[0xc0, 0xaf]),
711 der_value(Tag::Utf8String, &[0xe2, 0x82]),
712 der_value(Tag::PrintableString, b"invalid@CN"),
713 der_value(Tag::PrintableString, "é".as_bytes()),
714 der_value(Tag::PrintableString, b"invalid\0CN"),
715 der_value(Tag::BmpString, &[0]),
716 der_value(Tag::BmpString, &[0xd8, 0x00]),
717 der_value(Tag::BmpString, &[0xdc, 0x00]),
718 der_value(Tag::BmpString, &[0xd8, 0x3d, 0xde, 0x00]),
720 der_value(Tag::BmpString, &[0xff, 0xff]),
721 der_value(Tag::TeletexString, &[0x80]),
723 der_value(Tag::TeletexString, &[0xe9]),
724 der_value(Tag::TeletexString, "é".as_bytes()),
725 der_value(Tag::OctetString, b"not a DirectoryString"),
726 der_value(Tag::Ia5String, b"not a DirectoryString"),
727 der_value(Tag::Integer, &[1]),
728 der_value(Tag::Null, &[]),
729 der_value(Tag::Sequence, &[]),
730 der_value(TagNumber(0).context_specific(false), b"CN"),
731 vec![0x1c, 4, 0, 0, 0, b'A'],
733 ] {
734 let cert = edit_children(&fixture, &[0, name, 0, 0], |attribute| {
735 attribute[1] = value.clone();
736 });
737 assert!(parse_metadata(&cert).is_err(), "{value:?} at name {name}");
738 }
739 }
740 }
741
742 #[test]
743 fn test_metadata_times() {
744 let fixture = certificate();
745 for index in [0, 1] {
746 for (tag, content) in [
750 (Tag::UtcTime, "700101000000Z"),
751 (Tag::UtcTime, "991231235959Z"),
752 (Tag::UtcTime, "000229000000Z"),
753 (Tag::UtcTime, "261009180232Z"),
754 (Tag::UtcTime, "491231235959Z"),
755 (Tag::GeneralizedTime, "19700101000000Z"),
756 (Tag::GeneralizedTime, "20000229000000Z"),
757 (Tag::GeneralizedTime, "20561120180232Z"),
758 (Tag::GeneralizedTime, "99991231235959Z"),
759 ] {
760 let cert = edit_children(&fixture, &[0, 4], |validity| {
761 validity[index] = der_value(tag, content.as_bytes());
762 });
763 let metadata = parse_metadata(&cert).unwrap();
764 assert_eq!(
765 if index == 0 {
766 metadata.not_before
767 } else {
768 metadata.not_after
769 },
770 content
771 );
772 }
773 for (tag, content) in [
774 (Tag::UtcTime, b"261309180232Z".as_slice()),
775 (Tag::UtcTime, b"260009180232Z"),
776 (Tag::UtcTime, b"260229180232Z"),
777 (Tag::UtcTime, b"261009240232Z"),
778 (Tag::UtcTime, b"261009186032Z"),
779 (Tag::UtcTime, b"261009180260Z"),
780 (Tag::UtcTime, b"261009180232"),
781 (Tag::UtcTime, b"2610091802Z"),
782 (Tag::UtcTime, b"261009180232+0000"),
783 (Tag::UtcTime, b"261009180232z"),
784 (Tag::UtcTime, b"261009180232.0Z"),
785 (Tag::UtcTime, b"26100918023\xffZ"),
786 (Tag::UtcTime, b"691231235959Z"),
788 (Tag::GeneralizedTime, b"19691231235959Z"),
789 (Tag::GeneralizedTime, b"20561132180232Z"),
790 (Tag::GeneralizedTime, b"20561320180232Z"),
791 (Tag::GeneralizedTime, b"21000229180232Z"),
792 (Tag::GeneralizedTime, b"20561120240232Z"),
793 (Tag::GeneralizedTime, b"20561120186032Z"),
794 (Tag::GeneralizedTime, b"20561120180260Z"),
795 (Tag::GeneralizedTime, b"20561120180232"),
796 (Tag::GeneralizedTime, b"205611201802Z"),
797 (Tag::GeneralizedTime, b"20561120180232+0000"),
798 (Tag::GeneralizedTime, b"20561120180232z"),
799 (Tag::GeneralizedTime, b"20561120180232.0Z"),
800 (Tag::GeneralizedTime, b"2056112018023\xffZ"),
801 (Tag::UtcTime, b"20561120180232Z"),
802 (Tag::GeneralizedTime, b"261009180232Z"),
803 (Tag::Utf8String, b"261009180232Z"),
804 (Tag::OctetString, b"20561120180232Z"),
805 (Tag::Null, b""),
806 (Tag::Sequence, b""),
807 ] {
808 let cert = edit_children(&fixture, &[0, 4], |validity| {
809 validity[index] = der_value(tag, content);
810 });
811 assert!(
812 parse_metadata(&cert).is_err(),
813 "{tag:?} {content:?} at {index}"
814 );
815 }
816 }
817 }
818
819 fn v2_response(signal: IgvmSignal, payload: &[u8]) -> Vec<u8> {
820 let header = IgvmAttestAkCertResponseHeader {
821 data_size: (size_of::<IgvmAttestAkCertResponseHeader>() + payload.len()) as u32,
822 version: IgvmAttestResponseVersion::VERSION_2,
823 error_info: openhcl_attestation_protocol::igvm_attest::get::IgvmErrorInfo {
824 igvm_signal: signal,
825 ..Default::default()
826 },
827 };
828 let mut response = header.as_bytes().to_vec();
829 response.extend_from_slice(payload);
830 response
831 }
832
833 #[test]
834 fn test_v2_certificate_and_no_renewal() {
835 for payload in [b"".as_slice(), b"certificate"] {
836 assert_eq!(
837 parse_response(&v2_response(IgvmSignal::new(), payload)).unwrap(),
838 AkCertResponse::Certificate(payload.to_vec())
839 );
840 let signal = IgvmSignal::new().with_no_renew_cert(true);
842 assert_eq!(signal.as_bytes(), &32u32.to_le_bytes());
843 assert_eq!(
844 parse_response(&v2_response(signal, payload)).unwrap(),
845 AkCertResponse::NoRenewal
846 );
847 }
848 for bit in [0, 1, 2, 3, 4, 6, 31] {
849 let signal = IgvmSignal::from(1u32 << bit);
850 assert_eq!(
851 parse_response(&v2_response(signal, b"cert")).unwrap(),
852 AkCertResponse::Certificate(b"cert".to_vec())
853 );
854 }
855 }
856
857 #[test]
858 fn test_no_renewal_does_not_override_errors_or_bad_sizes() {
859 let response = v2_response(IgvmSignal::new().with_no_renew_cert(true), &[]);
860 for size in 0..response.len() {
861 assert!(parse_response(&response[..size]).is_err());
862 let mut invalid = response.clone();
864 invalid[..4].copy_from_slice(&(size as u32).to_le_bytes());
865 assert!(parse_response(&invalid).is_err());
866 }
867 let mut invalid = response.clone();
868 invalid[..4].copy_from_slice(&((response.len() + 1) as u32).to_le_bytes());
869 assert!(parse_response(&invalid).is_err());
870
871 let mut error = response.clone();
872 error[8..12].copy_from_slice(&1u32.to_le_bytes());
873 assert!(matches!(
874 parse_response(&error),
875 Err(AkCertError::ParseHeader(CommonError::Attestation { .. }))
876 ));
877 for version in [0u32, 3, u32::MAX] {
878 let mut invalid = response.clone();
879 invalid[4..8].copy_from_slice(&version.to_le_bytes());
880 assert!(parse_response(&invalid).is_err());
881 }
882 }
883
884 #[test]
885 fn test_undersized_response() {
886 const HEADER_SIZE: usize = size_of::<IgvmAttestAkCertResponseHeader>();
887 let properly_sized_response: [u8; HEADER_SIZE] = [1; HEADER_SIZE];
888 let undersized_response = &properly_sized_response[..HEADER_SIZE - 1];
889
890 let result = parse_response(&[]);
892 assert!(result.is_err());
893 assert_eq!(
894 result.unwrap_err().to_string(),
895 AkCertError::ParseHeader(CommonError::ResponseSizeTooSmall { response_size: 0 })
896 .to_string()
897 );
898
899 let undersized_parse_ = parse_response(undersized_response);
901 assert!(undersized_parse_.is_err());
902 assert_eq!(
903 undersized_parse_.unwrap_err().to_string(),
904 AkCertError::ParseHeader(CommonError::ResponseSizeTooSmall {
905 response_size: HEADER_SIZE - 1
906 })
907 .to_string()
908 );
909
910 let properly_sized_parse = parse_response(&properly_sized_response);
913 assert!(
914 !properly_sized_parse
915 .unwrap_err()
916 .to_string()
917 .starts_with("AK cert response is too small to parse"),
918 );
919 }
920
921 fn v1_response(payload: &[u8]) -> Vec<u8> {
922 let data_size = (size_of::<IgvmAttestCommonResponseHeader>() + payload.len()) as u32;
923 let mut response = data_size.to_le_bytes().to_vec();
924 response.extend_from_slice(&IgvmAttestResponseVersion::VERSION_1.0.to_le_bytes());
925 response.extend_from_slice(payload);
926 response
927 }
928
929 #[test]
930 fn test_valid_response_size_match() {
931 let cert = certificate();
932 assert_eq!(
933 parse_response(&v1_response(&cert)).unwrap(),
934 AkCertResponse::Certificate(cert)
935 );
936 }
937
938 #[test]
939 fn test_parse_response_small_size() {
940 let mut response = [0u8; 8];
941 response[0..4].copy_from_slice(&4u32.to_le_bytes());
943 response[4..8].copy_from_slice(&1u32.to_le_bytes());
945
946 assert!(parse_response(&response).is_err());
947 }
948
949 #[test]
950 fn test_valid_response_size_smaller_than_specified() {
951 let cert = certificate();
952 let mut response = v1_response(&cert);
953 response.extend_from_slice(b"trailing bytes");
955 assert_eq!(
956 parse_response(&response).unwrap(),
957 AkCertResponse::Certificate(cert)
958 );
959 }
960}