1use heapless::Vec;
29
30use crate::limits::{
31 GETDATA_RAW_MAX, MAX_KEYSETS, MAX_KEYS_PER_SET, MAX_MODULES_PER_ELF, MAX_PRIVILEGE_BYTES,
32 MAX_REGISTRY_ENTRIES, MAX_SCP_VARIANTS,
33};
34use crate::model::{CardCapabilities, KeyInfo, KeyTemplateFormat, KeyType, Keyset, ScpVariant};
35use crate::report::CardLifeCycle;
36use crate::tlv::{self, Tlv, TlvError};
37
38const TAG_CRD: u32 = 0x66;
42const TAG_CRD_BODY: u32 = 0x73;
44const TAG_SCP_ENTRY: u32 = 0x64;
47const TAG_OID: u32 = 0x06;
49
50const TAG_KEY_TEMPLATE: u32 = 0xE0;
52const TAG_KEY_ENTRY: u32 = 0xC0;
54const KEY_EXTENDED_MARKER: u8 = 0xB9;
56
57const TAG_CCI: u32 = 0x67;
59const TAG_CCI_CHANNELS: u32 = 0xA0;
61const TAG_CCI_PRIVILEGES: u32 = 0xA3;
63
64const TAG_GP_REGISTRY: u32 = 0xE3;
66const TAG_LIFE_CYCLE: u32 = 0x9F70;
68const TAG_AID: u32 = 0x4F;
70const TAG_PRIVILEGES: u32 = 0xC5;
73const TAG_ASSOC_SD_AID: u32 = 0xCC;
76const TAG_ELF_AID: u32 = 0xC4;
79const TAG_MODULE_AID: u32 = 0x84;
82
83const KEY_TYPE_DES: u8 = 0x80;
86const KEY_TYPE_AES: u8 = 0x88;
87const KEY_TYPE_RSA_PUBLIC: u8 = 0xA1;
88const KEY_TYPE_RSA_PRIVATE_CRT: u8 = 0xA2;
89const KEY_TYPE_RSA_PRIVATE_EXP: u8 = 0xA3;
90const KEY_TYPE_ECC_PUBLIC: u8 = 0xB0;
91const KEY_TYPE_ECC_PRIVATE: u8 = 0xB1;
92const KEY_TYPE_ECC_PARAMS_REF: u8 = 0xB2;
93
94#[derive(Debug, Clone, Default, PartialEq, Eq)]
100pub struct CardRecognition {
101 pub scp: Vec<ScpVariant, MAX_SCP_VARIANTS>,
105}
106
107pub fn parse_card_recognition(data: &[u8]) -> Result<CardRecognition, TlvError> {
118 let mut out = CardRecognition::default();
119 if data.is_empty() {
120 return Ok(out);
121 }
122 let top = tlv::parse(data)?;
123 let body = if let Some(v66) = find(&top, TAG_CRD) {
125 let wrapped = tlv::parse(v66)?;
126 find(&wrapped, TAG_CRD_BODY)
127 } else {
128 find(&top, TAG_CRD_BODY)
129 };
130 let Some(body) = body else {
131 return Ok(out); };
133 let entries = tlv::parse(body)?;
134 for entry in entries.iter().filter(|t| t.tag == TAG_SCP_ENTRY) {
135 let oid_tlvs = tlv::parse(entry.value)?;
136 let Some(oid) = find(&oid_tlvs, TAG_OID) else {
137 continue;
138 };
139 if let [.., scp_id, i] = oid {
141 if let Some(variant) = scp_variant(*scp_id, *i) {
142 out.scp.push(variant).map_err(|_| TlvError::TooMany)?;
143 }
144 }
145 }
146 Ok(out)
147}
148
149fn scp_variant(scp_id: u8, i_param: u8) -> Option<ScpVariant> {
153 match scp_id {
154 0x02 => Some(ScpVariant::Scp02 { i_param }),
155 0x03 => Some(ScpVariant::Scp03 { i_param }),
156 _ => None,
157 }
158}
159
160pub struct KeyInformation {
166 pub format: KeyTemplateFormat,
167 pub keysets: Vec<Keyset, MAX_KEYSETS>,
168}
169
170pub fn parse_key_information(data: &[u8]) -> Result<KeyInformation, TlvError> {
182 let mut format = KeyTemplateFormat::Basic;
183 let mut keysets: Vec<Keyset, MAX_KEYSETS> = Vec::new();
184 if data.is_empty() {
185 return Ok(KeyInformation { format, keysets });
186 }
187 let top = tlv::parse(data)?;
188 let body = find(&top, TAG_KEY_TEMPLATE).unwrap_or(data);
189 let entries = tlv::parse(body)?;
190 for entry in entries.iter().filter(|t| t.tag == TAG_KEY_ENTRY) {
191 let value = entry.value;
192 let (Some(&kid), Some(&kvn)) = (value.first(), value.get(1)) else {
198 continue;
199 };
200 let rest = &value[2..];
201 if rest.first() == Some(&KEY_EXTENDED_MARKER) {
202 format = KeyTemplateFormat::Extended;
206 push_key(
207 &mut keysets,
208 kvn,
209 KeyInfo {
210 kid,
211 key_type: KeyType::Other(KEY_EXTENDED_MARKER),
212 key_length: 0,
213 },
214 )?;
215 } else {
216 for pair in rest.chunks_exact(2) {
218 push_key(
219 &mut keysets,
220 kvn,
221 KeyInfo {
222 kid,
223 key_type: decode_key_type(pair[0]),
224 key_length: pair[1],
225 },
226 )?;
227 }
228 }
229 }
230 Ok(KeyInformation { format, keysets })
231}
232
233fn push_key(keysets: &mut Vec<Keyset, MAX_KEYSETS>, kvn: u8, key: KeyInfo) -> Result<(), TlvError> {
235 if let Some(set) = keysets.iter_mut().find(|s| s.kvn == kvn) {
236 return set.keys.push(key).map_err(|_| TlvError::TooMany);
237 }
238 let mut keys: Vec<KeyInfo, MAX_KEYS_PER_SET> = Vec::new();
239 keys.push(key).map_err(|_| TlvError::TooMany)?;
241 keysets
242 .push(Keyset { kvn, keys })
243 .map_err(|_| TlvError::TooMany)
244}
245
246fn decode_key_type(byte: u8) -> KeyType {
248 match byte {
249 KEY_TYPE_DES => KeyType::Des,
250 KEY_TYPE_AES => KeyType::Aes,
251 KEY_TYPE_RSA_PUBLIC => KeyType::RsaPublic,
252 KEY_TYPE_RSA_PRIVATE_CRT => KeyType::RsaPrivateCrt,
253 KEY_TYPE_RSA_PRIVATE_EXP => KeyType::RsaPrivateExponent,
254 KEY_TYPE_ECC_PUBLIC => KeyType::EccPublic,
255 KEY_TYPE_ECC_PRIVATE => KeyType::EccPrivate,
256 KEY_TYPE_ECC_PARAMS_REF => KeyType::EccParametersRef,
257 other => KeyType::Other(other),
258 }
259}
260
261pub fn parse_card_capabilities(data: &[u8]) -> Result<CardCapabilities, TlvError> {
276 let mut caps = CardCapabilities {
277 max_logical_channels: 1, ciphers_supported: Vec::new(),
279 privileges_supported: Vec::new(),
280 memory_total_bytes: None,
281 memory_free_bytes: None,
282 cci_raw: Vec::new(),
283 };
284 let raw_len = data.len().min(GETDATA_RAW_MAX);
285 let _ = caps.cci_raw.extend_from_slice(&data[..raw_len]);
287 if data.is_empty() {
288 return Ok(caps);
289 }
290 let top = tlv::parse(data)?;
291 let body = find(&top, TAG_CCI).unwrap_or(data);
292 let subs = tlv::parse(body)?;
293 if let Some(channels) = find(&subs, TAG_CCI_CHANNELS) {
294 if let Some(&n) = channels.first() {
295 caps.max_logical_channels = n;
296 }
297 }
298 if let Some(privileges) = find(&subs, TAG_CCI_PRIVILEGES) {
299 let n = privileges.len().min(MAX_PRIVILEGE_BYTES);
300 let _ = caps
302 .privileges_supported
303 .extend_from_slice(&privileges[..n]);
304 }
305 Ok(caps)
306}
307
308pub fn parse_status_e3(data: &[u8]) -> Result<Option<CardLifeCycle>, TlvError> {
322 if data.is_empty() {
323 return Ok(None);
324 }
325 let top = tlv::parse(data)?;
326 let Some(registry) = find(&top, TAG_GP_REGISTRY) else {
327 return Ok(None);
328 };
329 let fields = tlv::parse(registry)?;
330 let Some(life_cycle) = find(&fields, TAG_LIFE_CYCLE) else {
331 return Ok(None);
332 };
333 Ok(life_cycle.first().map(|&b| decode_life_cycle(b)))
334}
335
336fn decode_life_cycle(byte: u8) -> CardLifeCycle {
338 match byte {
339 0x01 => CardLifeCycle::OpReady,
340 0x07 => CardLifeCycle::Initialized,
341 0x0F => CardLifeCycle::Secured,
342 0x7F => CardLifeCycle::CardLocked,
343 0xFF => CardLifeCycle::Terminated,
344 other => CardLifeCycle::Unknown(other),
345 }
346}
347
348#[derive(Debug, Clone, PartialEq, Eq)]
361pub struct RegistryEntry<'a> {
362 pub aid: &'a [u8],
365 pub life_cycle: u8,
367 pub privileges: [u8; 3],
370 pub associated_sd_aid: Option<&'a [u8]>,
372 pub elf_aid: Option<&'a [u8]>,
374 pub modules: Vec<&'a [u8], MAX_MODULES_PER_ELF>,
377}
378
379pub fn parse_status_registry(
398 data: &[u8],
399) -> Result<Vec<RegistryEntry<'_>, MAX_REGISTRY_ENTRIES>, TlvError> {
400 let mut out: Vec<RegistryEntry, MAX_REGISTRY_ENTRIES> = Vec::new();
401 if data.is_empty() {
402 return Ok(out);
403 }
404 let top = tlv::parse(data)?;
405 for e3 in top.iter().filter(|t| t.tag == TAG_GP_REGISTRY) {
406 let fields = tlv::parse(e3.value)?;
407 let aid = find(&fields, TAG_AID).unwrap_or(&[]);
408 let life_cycle = find(&fields, TAG_LIFE_CYCLE)
409 .and_then(|v| v.first().copied())
410 .unwrap_or(0);
411 let privileges = privileges_to_3(find(&fields, TAG_PRIVILEGES));
412 let associated_sd_aid = find(&fields, TAG_ASSOC_SD_AID);
413 let elf_aid = find(&fields, TAG_ELF_AID);
414 let mut modules: Vec<&[u8], MAX_MODULES_PER_ELF> = Vec::new();
415 for m in fields.iter().filter(|t| t.tag == TAG_MODULE_AID) {
416 if modules.push(m.value).is_err() {
417 break; }
419 }
420 let entry = RegistryEntry {
421 aid,
422 life_cycle,
423 privileges,
424 associated_sd_aid,
425 elf_aid,
426 modules,
427 };
428 if out.push(entry).is_err() {
429 break; }
431 }
432 Ok(out)
433}
434
435fn privileges_to_3(value: Option<&[u8]>) -> [u8; 3] {
440 let mut p = [0u8; 3];
441 if let Some(b) = value {
442 let n = b.len().min(3);
443 p[..n].copy_from_slice(&b[..n]);
444 }
445 p
446}
447
448fn find<'a>(tlvs: &[Tlv<'a>], tag: u32) -> Option<&'a [u8]> {
453 tlvs.iter().find(|t| t.tag == tag).map(|t| t.value)
454}
455
456#[cfg(test)]
457mod tests {
458 use super::*;
459
460 const CRD_SCP02_55: &[u8] = &[
464 0x66, 0x4C, 0x73, 0x4A, 0x06, 0x07, 0x2A, 0x86, 0x48, 0x86, 0xFC, 0x6B, 0x01, 0x60, 0x0C,
465 0x06, 0x0A, 0x2A, 0x86, 0x48, 0x86, 0xFC, 0x6B, 0x02, 0x02, 0x01, 0x01, 0x63, 0x09, 0x06,
466 0x07, 0x2A, 0x86, 0x48, 0x86, 0xFC, 0x6B, 0x03, 0x64, 0x0B, 0x06, 0x09, 0x2A, 0x86, 0x48,
467 0x86, 0xFC, 0x6B, 0x04, 0x02, 0x55, 0x65, 0x0B, 0x06, 0x09, 0x2B, 0x85, 0x10, 0x86, 0x48,
468 0x64, 0x02, 0x01, 0x03, 0x66, 0x0C, 0x06, 0x0A, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x2A, 0x02,
469 0x6E, 0x01, 0x02,
470 ];
471
472 #[test]
473 fn crd_decodes_scp02_i55() {
474 let crd = parse_card_recognition(CRD_SCP02_55).unwrap();
475 assert_eq!(crd.scp.len(), 1);
476 assert_eq!(crd.scp[0], ScpVariant::Scp02 { i_param: 0x55 });
477 }
478
479 #[test]
480 fn crd_decodes_scp03_i70() {
481 let crd = [
483 0x66, 0x0E, 0x73, 0x0C, 0x64, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xFC, 0x6B,
484 0x03, 0x70,
485 ];
486 let r = parse_card_recognition(&crd).unwrap();
487 assert_eq!(r.scp[0], ScpVariant::Scp03 { i_param: 0x70 });
488 }
489
490 #[test]
491 fn crd_multiple_variants_preserve_order() {
492 let crd = [
494 0x73, 0x10, 0x64, 0x06, 0x06, 0x04, 0x00, 0x00, 0x02, 0x55, 0x64, 0x06, 0x06, 0x04,
495 0x00, 0x00, 0x03, 0x70,
496 ];
497 let r = parse_card_recognition(&crd).unwrap();
498 assert_eq!(r.scp.len(), 2);
499 assert_eq!(r.scp[0], ScpVariant::Scp02 { i_param: 0x55 });
500 assert_eq!(r.scp[1], ScpVariant::Scp03 { i_param: 0x70 });
501 }
502
503 #[test]
504 fn crd_drops_scp01() {
505 let crd = [0x73, 0x08, 0x64, 0x06, 0x06, 0x04, 0x00, 0x00, 0x01, 0x05];
507 assert!(parse_card_recognition(&crd).unwrap().scp.is_empty());
508 }
509
510 #[test]
511 fn crd_empty_input_is_empty_not_error() {
512 assert!(parse_card_recognition(&[]).unwrap().scp.is_empty());
513 }
514
515 #[test]
516 fn crd_no_template_is_empty_not_error() {
517 assert!(parse_card_recognition(&[0x5C, 0x01, 0x9F])
519 .unwrap()
520 .scp
521 .is_empty());
522 }
523
524 #[test]
525 fn crd_entry_without_oid_is_skipped() {
526 let crd = [0x73, 0x06, 0x64, 0x04, 0x80, 0x02, 0x00, 0x00];
528 assert!(parse_card_recognition(&crd).unwrap().scp.is_empty());
529 }
530
531 #[test]
532 fn crd_oid_shorter_than_two_octets_is_skipped() {
533 let crd = [0x73, 0x05, 0x64, 0x03, 0x06, 0x01, 0x2A];
534 assert!(parse_card_recognition(&crd).unwrap().scp.is_empty());
535 }
536
537 #[test]
538 fn crd_malformed_tlv_is_rejected() {
539 assert_eq!(
541 parse_card_recognition(&[0x66, 0x05, 0x00]),
542 Err(TlvError::Truncated)
543 );
544 }
545
546 #[test]
549 fn key_info_basic_single_keyset_three_kids() {
550 let data = [
554 0xE0, 0x12, 0xC0, 0x04, 0x01, 0x01, 0x88, 0x10, 0xC0, 0x04, 0x02, 0x01, 0x88, 0x10,
555 0xC0, 0x04, 0x03, 0x01, 0x88, 0x10,
556 ];
557 let info = parse_key_information(&data).unwrap();
558 assert!(matches!(info.format, KeyTemplateFormat::Basic));
559 assert_eq!(info.keysets.len(), 1);
560 assert_eq!(info.keysets[0].kvn, 1);
561 assert_eq!(info.keysets[0].keys.len(), 3);
562 assert_eq!(info.keysets[0].keys[0].kid, 1);
563 assert!(matches!(info.keysets[0].keys[0].key_type, KeyType::Aes));
564 assert_eq!(info.keysets[0].keys[2].key_length, 0x10);
565 }
566
567 #[test]
568 fn key_info_groups_by_kvn() {
569 let data = [
570 0xE0, 0x0E, 0xC0, 0x04, 0x01, 0x01, 0x80, 0x10, 0xC0, 0x04, 0x01, 0x02, 0x88, 0x10,
571 0xC0, 0x00, ];
573 let info = parse_key_information(&data).unwrap();
574 assert_eq!(info.keysets.len(), 2);
575 assert!(matches!(info.keysets[0].keys[0].key_type, KeyType::Des));
576 assert!(matches!(info.keysets[1].keys[0].key_type, KeyType::Aes));
577 }
578
579 #[test]
580 fn key_info_multi_component_pairs() {
581 let data = [0xE0, 0x08, 0xC0, 0x06, 0x10, 0x01, 0xA1, 0x80, 0xA2, 0x80];
583 let info = parse_key_information(&data).unwrap();
584 assert_eq!(info.keysets[0].keys.len(), 2);
585 assert!(matches!(
586 info.keysets[0].keys[0].key_type,
587 KeyType::RsaPublic
588 ));
589 assert!(matches!(
590 info.keysets[0].keys[1].key_type,
591 KeyType::RsaPrivateCrt
592 ));
593 }
594
595 #[test]
596 fn key_info_extended_format_sets_flag() {
597 let data = [0xE0, 0x06, 0xC0, 0x04, 0x01, 0x01, 0xB9, 0x00];
599 let info = parse_key_information(&data).unwrap();
600 assert!(matches!(info.format, KeyTemplateFormat::Extended));
601 assert_eq!(info.keysets[0].keys[0].kid, 1);
602 assert!(matches!(
603 info.keysets[0].keys[0].key_type,
604 KeyType::Other(0xB9)
605 ));
606 }
607
608 #[test]
609 fn key_info_unknown_type_is_other() {
610 let data = [0xE0, 0x06, 0xC0, 0x04, 0x05, 0x09, 0x42, 0x08];
612 let info = parse_key_information(&data).unwrap();
613 assert!(matches!(
614 info.keysets[0].keys[0].key_type,
615 KeyType::Other(0x42)
616 ));
617 }
618
619 #[test]
620 fn key_info_bare_c0_without_e0_wrapper() {
621 let data = [0xC0, 0x04, 0x01, 0x01, 0x88, 0x10];
622 let info = parse_key_information(&data).unwrap();
623 assert_eq!(info.keysets[0].keys[0].kid, 1);
624 }
625
626 #[test]
627 fn key_info_empty_is_empty_not_error() {
628 let info = parse_key_information(&[]).unwrap();
629 assert!(info.keysets.is_empty());
630 }
631
632 #[test]
633 fn key_info_malformed_tlv_is_rejected() {
634 assert!(matches!(
635 parse_key_information(&[0xE0, 0x05, 0xC0]),
636 Err(TlvError::Truncated)
637 ));
638 }
639
640 #[test]
643 fn cci_decodes_channels_and_privileges_and_keeps_raw() {
644 let data = [0x67, 0x08, 0xA0, 0x01, 0x04, 0xA3, 0x03, 0x80, 0x00, 0x00];
646 let caps = parse_card_capabilities(&data).unwrap();
647 assert_eq!(caps.max_logical_channels, 4);
648 assert_eq!(caps.privileges_supported.len(), 3);
649 assert_eq!(caps.privileges_supported[0], 0x80);
650 assert_eq!(caps.cci_raw.len(), data.len());
651 assert!(caps.ciphers_supported.is_empty());
653 assert!(caps.memory_total_bytes.is_none());
654 }
655
656 #[test]
657 fn cci_defaults_to_one_channel_when_a0_absent() {
658 let data = [0x67, 0x05, 0xA3, 0x03, 0x80, 0x00, 0x00];
659 let caps = parse_card_capabilities(&data).unwrap();
660 assert_eq!(caps.max_logical_channels, 1);
661 }
662
663 #[test]
664 fn cci_empty_a0_keeps_default_channel() {
665 let data = [0x67, 0x02, 0xA0, 0x00];
666 let caps = parse_card_capabilities(&data).unwrap();
667 assert_eq!(caps.max_logical_channels, 1);
668 }
669
670 #[test]
671 fn cci_bare_subtags_without_67_wrapper() {
672 let data = [0xA0, 0x01, 0x02];
673 let caps = parse_card_capabilities(&data).unwrap();
674 assert_eq!(caps.max_logical_channels, 2);
675 }
676
677 #[test]
678 fn cci_empty_is_defaults_not_error() {
679 let caps = parse_card_capabilities(&[]).unwrap();
680 assert_eq!(caps.max_logical_channels, 1);
681 assert!(caps.cci_raw.is_empty());
682 }
683
684 #[test]
685 fn cci_malformed_tlv_is_rejected() {
686 assert!(matches!(
687 parse_card_capabilities(&[0x67, 0x05, 0xA0]),
688 Err(TlvError::Truncated)
689 ));
690 }
691
692 #[test]
695 fn e3_decodes_each_known_lifecycle_byte() {
696 for (raw, expect) in [
697 (0x01u8, CardLifeCycle::OpReady),
698 (0x07, CardLifeCycle::Initialized),
699 (0x0F, CardLifeCycle::Secured),
700 (0x7F, CardLifeCycle::CardLocked),
701 (0xFF, CardLifeCycle::Terminated),
702 ] {
703 let data = [
705 0xE3, 0x0D, 0x4F, 0x07, 0xA0, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x9F, 0x70, 0x01,
706 raw,
707 ];
708 assert_eq!(parse_status_e3(&data).unwrap(), Some(expect));
709 }
710 }
711
712 #[test]
713 fn e3_unknown_byte_maps_to_unknown() {
714 let data = [0xE3, 0x04, 0x9F, 0x70, 0x01, 0x42];
715 assert_eq!(
716 parse_status_e3(&data).unwrap(),
717 Some(CardLifeCycle::Unknown(0x42))
718 );
719 }
720
721 #[test]
722 fn e3_absent_template_is_none() {
723 assert_eq!(parse_status_e3(&[0x4F, 0x00]).unwrap(), None);
725 }
726
727 #[test]
728 fn e3_without_9f70_is_none() {
729 let data = [0xE3, 0x02, 0x4F, 0x00];
730 assert_eq!(parse_status_e3(&data).unwrap(), None);
731 }
732
733 #[test]
734 fn e3_empty_9f70_is_none() {
735 let data = [0xE3, 0x03, 0x9F, 0x70, 0x00];
736 assert_eq!(parse_status_e3(&data).unwrap(), None);
737 }
738
739 #[test]
740 fn e3_empty_input_is_none() {
741 assert_eq!(parse_status_e3(&[]).unwrap(), None);
742 }
743
744 #[test]
745 fn e3_malformed_tlv_is_rejected() {
746 assert_eq!(
747 parse_status_e3(&[0xE3, 0x05, 0x9F]),
748 Err(TlvError::Truncated)
749 );
750 }
751
752 fn e3_app(aid: &[u8], lc: u8, privs: &[u8]) -> std::vec::Vec<u8> {
756 let mut inner = std::vec::Vec::new();
757 inner.push(0x4F);
758 inner.push(u8::try_from(aid.len()).unwrap());
759 inner.extend_from_slice(aid);
760 inner.extend_from_slice(&[0x9F, 0x70, 0x01, lc]);
761 inner.push(0xC5);
762 inner.push(u8::try_from(privs.len()).unwrap());
763 inner.extend_from_slice(privs);
764 let mut v = std::vec::Vec::new();
765 v.push(0xE3);
766 v.push(u8::try_from(inner.len()).unwrap());
767 v.extend_from_slice(&inner);
768 v
769 }
770
771 #[test]
772 fn registry_decodes_isd_with_full_3byte_privileges() {
773 let aid = [0xA0, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00];
775 let e = e3_app(&aid, 0x01, &[0x9E, 0xFE, 0x80]);
776 let r = parse_status_registry(&e).unwrap();
777 assert_eq!(r.len(), 1);
778 assert_eq!(r[0].aid, &aid);
779 assert_eq!(r[0].life_cycle, 0x01);
780 assert_eq!(r[0].privileges, [0x9E, 0xFE, 0x80]);
781 assert!(r[0].modules.is_empty());
782 }
783
784 #[test]
785 fn registry_pads_one_byte_privileges_into_byte_zero() {
786 let e = e3_app(&[0xA0, 0x00, 0x00, 0x00, 0x18], 0x07, &[0x80]);
788 let r = parse_status_registry(&e).unwrap();
789 assert_eq!(r[0].privileges, [0x80, 0x00, 0x00]);
790 }
791
792 #[test]
793 fn registry_decodes_two_entries_in_one_page() {
794 let a = e3_app(&[0xA0, 0x00, 0x00, 0x00, 0x11], 0x07, &[0x00, 0x00, 0x00]);
795 let b = e3_app(&[0xA0, 0x00, 0x00, 0x00, 0x22], 0x0F, &[0x80, 0x00, 0x00]);
796 let mut page = a;
797 page.extend_from_slice(&b);
798 let r = parse_status_registry(&page).unwrap();
799 assert_eq!(r.len(), 2);
800 assert_eq!(r[0].life_cycle, 0x07);
801 assert_eq!(r[1].privileges, [0x80, 0x00, 0x00]);
802 }
803
804 #[test]
805 fn registry_decodes_elf_with_associated_sd_and_modules() {
806 let elf = [0xA0, 0x00, 0x00, 0x00, 0x62, 0x01];
808 let sd = [0xA0, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00];
809 let m1 = [0xA0, 0x00, 0x00, 0x00, 0x62, 0x01, 0x01];
810 let m2 = [0xA0, 0x00, 0x00, 0x00, 0x62, 0x01, 0x02];
811 let mut inner = std::vec::Vec::new();
812 inner.push(0x4F);
813 inner.push(u8::try_from(elf.len()).unwrap());
814 inner.extend_from_slice(&elf);
815 inner.extend_from_slice(&[0x9F, 0x70, 0x01, 0x01]);
816 inner.push(0xCC);
817 inner.push(u8::try_from(sd.len()).unwrap());
818 inner.extend_from_slice(&sd);
819 for m in [&m1[..], &m2[..]] {
820 inner.push(0x84);
821 inner.push(u8::try_from(m.len()).unwrap());
822 inner.extend_from_slice(m);
823 }
824 let mut e = std::vec::Vec::new();
825 e.push(0xE3);
826 e.push(u8::try_from(inner.len()).unwrap());
827 e.extend_from_slice(&inner);
828
829 let r = parse_status_registry(&e).unwrap();
830 assert_eq!(r[0].aid, &elf);
831 assert_eq!(r[0].associated_sd_aid, Some(&sd[..]));
832 assert_eq!(r[0].modules.len(), 2);
833 assert_eq!(r[0].modules[0], &m1);
834 assert_eq!(r[0].modules[1], &m2);
835 }
836
837 #[test]
838 fn registry_decodes_application_elf_aid_tag_c4() {
839 let inst = [0xA0, 0x00, 0x00, 0x00, 0x62, 0x03, 0x01, 0x0C];
841 let elf = [0xA0, 0x00, 0x00, 0x00, 0x62, 0x03];
842 let mut inner = std::vec::Vec::new();
843 inner.push(0x4F);
844 inner.push(u8::try_from(inst.len()).unwrap());
845 inner.extend_from_slice(&inst);
846 inner.extend_from_slice(&[0x9F, 0x70, 0x01, 0x07]);
847 inner.extend_from_slice(&[0xC5, 0x01, 0x00]);
848 inner.push(0xC4);
849 inner.push(u8::try_from(elf.len()).unwrap());
850 inner.extend_from_slice(&elf);
851 let mut e = std::vec::Vec::new();
852 e.push(0xE3);
853 e.push(u8::try_from(inner.len()).unwrap());
854 e.extend_from_slice(&inner);
855
856 let r = parse_status_registry(&e).unwrap();
857 assert_eq!(r[0].elf_aid, Some(&elf[..]));
858 assert_eq!(r[0].associated_sd_aid, None);
859 }
860
861 #[test]
862 fn registry_missing_4f_yields_empty_aid_not_error() {
863 let e = [0xE3, 0x04, 0x9F, 0x70, 0x01, 0x0F];
865 let r = parse_status_registry(&e).unwrap();
866 assert_eq!(r.len(), 1);
867 assert!(r[0].aid.is_empty());
868 assert_eq!(r[0].life_cycle, 0x0F);
869 }
870
871 #[test]
872 fn registry_empty_page_is_empty_not_error() {
873 assert!(parse_status_registry(&[]).unwrap().is_empty());
874 }
875
876 #[test]
877 fn registry_no_e3_is_empty_not_error() {
878 assert!(parse_status_registry(&[0x4F, 0x00]).unwrap().is_empty());
880 }
881
882 #[test]
883 fn registry_malformed_tlv_is_rejected() {
884 assert_eq!(
885 parse_status_registry(&[0xE3, 0x05, 0x4F]),
886 Err(TlvError::Truncated)
887 );
888 }
889
890 #[test]
891 fn registry_truncates_excess_modules_without_panic() {
892 use crate::limits::MAX_MODULES_PER_ELF;
894 let elf = [0xA0, 0x00, 0x00, 0x00, 0x62, 0x09];
895 let mut inner = std::vec::Vec::new();
896 inner.push(0x4F);
897 inner.push(u8::try_from(elf.len()).unwrap());
898 inner.extend_from_slice(&elf);
899 inner.extend_from_slice(&[0x9F, 0x70, 0x01, 0x01]);
900 for i in 0..(MAX_MODULES_PER_ELF + 4) {
901 inner.extend_from_slice(&[
903 0x84,
904 0x05,
905 0xA0,
906 0x00,
907 0x00,
908 0x01,
909 u8::try_from(i).unwrap(),
910 ]);
911 }
912 let mut e = std::vec::Vec::new();
913 e.push(0xE3);
914 if inner.len() < 0x80 {
916 e.push(u8::try_from(inner.len()).unwrap());
917 } else {
918 e.push(0x81);
919 e.push(u8::try_from(inner.len()).unwrap());
920 }
921 e.extend_from_slice(&inner);
922 let r = parse_status_registry(&e).unwrap();
923 assert_eq!(r[0].modules.len(), MAX_MODULES_PER_ELF);
924 }
925}