1use std::fmt;
8
9use crate::error::{Error, Result};
10use crate::pin::Pin;
11use crate::tlv::ber;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
24pub struct ApIdentification {
25 pub specification_version: u8,
27 pub extended_lc_le_support: u8,
29 pub vendor_id: u8,
31 pub vendor_specific: u8,
33}
34
35impl ApIdentification {
36 pub const LEN: usize = 4;
38
39 pub fn parse(bytes: &[u8]) -> Result<Self> {
45 let [
46 specification_version,
47 extended_lc_le_support,
48 vendor_id,
49 vendor_specific,
50 ] = <[u8; Self::LEN]>::try_from(bytes).map_err(|_| {
51 malformed(&format!(
52 "AP identification must be 4 bytes, got {}",
53 bytes.len()
54 ))
55 })?;
56 Ok(Self {
57 specification_version,
58 extended_lc_le_support,
59 vendor_id,
60 vendor_specific,
61 })
62 }
63
64 pub const fn to_bytes(self) -> [u8; Self::LEN] {
66 [
67 self.specification_version,
68 self.extended_lc_le_support,
69 self.vendor_id,
70 self.vendor_specific,
71 ]
72 }
73}
74
75#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
77pub struct Date {
78 pub year: u16,
80 pub month: u8,
82 pub day: u8,
84}
85
86impl Date {
87 pub fn parse(bytes: &[u8]) -> Result<Self> {
89 let text = std::str::from_utf8(bytes)
90 .ok()
91 .filter(|s| s.len() == 8 && s.bytes().all(|b| b.is_ascii_digit()))
92 .ok_or_else(|| malformed(&format!("expected 8 digits, got {}", hex(bytes))))?;
93 let date = Date {
94 year: text[0..4].parse().unwrap(),
95 month: text[4..6].parse().unwrap(),
96 day: text[6..8].parse().unwrap(),
97 };
98 if !(1..=12).contains(&date.month) || !(1..=31).contains(&date.day) {
99 return Err(malformed(&format!("not a calendar date: {date}")));
100 }
101 Ok(date)
102 }
103
104 pub fn from_unix_seconds(seconds: i64) -> Self {
109 let days = seconds.div_euclid(86_400) + 719_468;
112 let era = days.div_euclid(146_097);
113 let doe = days.rem_euclid(146_097);
114 let yoe = (doe - doe / 1460 + doe / 36_524 - doe / 146_096) / 365;
115 let doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
116 let mp = (5 * doy + 2) / 153;
117 let day = (doy - (153 * mp + 2) / 5 + 1) as u8;
118 let month = if mp < 10 { mp + 3 } else { mp - 9 } as u8;
119 let year = (yoe + era * 400 + i64::from(month <= 2)) as u16;
120 Date { year, month, day }
121 }
122
123 pub fn to_era(self) -> Option<(Era, u16)> {
127 let key = (self.year, self.month, self.day);
128 let era = match key {
129 k if k >= (2019, 5, 1) => Era::Reiwa,
130 k if k >= (1989, 1, 8) => Era::Heisei,
131 k if k >= (1926, 12, 25) => Era::Showa,
132 k if k >= (1912, 7, 30) => Era::Taisho,
133 k if k >= (1868, 1, 25) => Era::Meiji,
134 _ => return None,
135 };
136 Some((era, self.year - era.first_gregorian_year() + 1))
137 }
138}
139
140impl fmt::Display for Date {
141 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
142 write!(f, "{:04}-{:02}-{:02}", self.year, self.month, self.day)
143 }
144}
145
146#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
148#[allow(missing_docs)]
149pub enum Era {
150 Meiji,
151 Taisho,
152 Showa,
153 Heisei,
154 Reiwa,
155}
156
157impl Era {
158 pub const fn first_gregorian_year(self) -> u16 {
160 match self {
161 Era::Meiji => 1868,
162 Era::Taisho => 1912,
163 Era::Showa => 1926,
164 Era::Heisei => 1989,
165 Era::Reiwa => 2019,
166 }
167 }
168
169 pub const fn name(self) -> &'static str {
171 match self {
172 Era::Meiji => "明治",
173 Era::Taisho => "大正",
174 Era::Showa => "昭和",
175 Era::Heisei => "平成",
176 Era::Reiwa => "令和",
177 }
178 }
179}
180
181#[derive(Debug, Clone, Copy, PartialEq, Eq)]
186pub enum Sex {
187 Male,
189 Female,
191 Unknown,
193 NotApplicable,
195 Other(u8),
197}
198
199impl Sex {
200 pub const fn from_byte(b: u8) -> Self {
202 match b {
203 b'0' => Sex::Unknown,
204 b'1' => Sex::Male,
205 b'2' => Sex::Female,
206 b'9' => Sex::NotApplicable,
207 other => Sex::Other(other),
208 }
209 }
210}
211
212#[derive(Clone, PartialEq, Eq)]
216pub struct MyNumber([u8; 12]);
217
218impl MyNumber {
219 pub fn parse(bytes: &[u8]) -> Result<Self> {
221 let digits: [u8; 12] = bytes
222 .try_into()
223 .ok()
224 .filter(|d: &[u8; 12]| d.iter().all(u8::is_ascii_digit))
225 .ok_or_else(|| malformed(&format!("個人番号 must be 12 digits, got {}", hex(bytes))))?;
226 Ok(MyNumber(digits))
227 }
228
229 pub fn as_bytes(&self) -> &[u8; 12] {
231 &self.0
232 }
233
234 pub fn as_str(&self) -> &str {
236 std::str::from_utf8(&self.0).expect("digits are ASCII")
238 }
239
240 pub fn as_verification_code_a(&self) -> Result<Pin> {
245 Pin::numeric(self.0)
246 }
247}
248
249impl fmt::Debug for MyNumber {
251 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
252 write!(f, "MyNumber(<12 digits redacted>)")
253 }
254}
255
256pub fn verification_code_b(
279 birth_date: Date,
280 expiry_year: u16,
281 security_code: &[u8],
282) -> Result<Pin> {
283 let (_, era_year) = birth_date
284 .to_era()
285 .ok_or_else(|| malformed(&format!("{birth_date} predates the Meiji era")))?;
286 if era_year > 99 {
287 return Err(malformed(&format!(
288 "era year {era_year} does not fit in two digits"
289 )));
290 }
291 if security_code.len() != 4 || !security_code.iter().all(u8::is_ascii_digit) {
292 return Err(Error::InvalidPin("security code must be 4 digits"));
293 }
294 let text = format!(
295 "{:02}{:02}{:02}{:04}{}",
296 era_year,
297 birth_date.month,
298 birth_date.day,
299 expiry_year,
300 std::str::from_utf8(security_code).expect("digits are ASCII"),
301 );
302 Pin::numeric(text)
303}
304
305#[derive(Debug, Clone, PartialEq, Eq)]
307pub struct RsaPublicKey {
308 pub exponent: Vec<u8>,
310 pub modulus: Vec<u8>,
312}
313
314impl RsaPublicKey {
315 pub const TAG_EXPONENT: u32 = 0x90;
317 pub const TAG_MODULUS: u32 = 0x91;
319
320 pub fn parse(data: &[u8]) -> Result<Self> {
322 let mut exponent = None;
323 let mut modulus = None;
324 for tlv in ber::iter(data) {
325 let tlv = tlv?;
326 match tlv.tag {
327 Self::TAG_EXPONENT => exponent = Some(tlv.value.to_vec()),
328 Self::TAG_MODULUS => modulus = Some(tlv.value.to_vec()),
329 _ => {}
330 }
331 }
332 Ok(RsaPublicKey {
333 exponent: exponent.ok_or_else(|| malformed("no public exponent (tag 90)"))?,
334 modulus: modulus.ok_or_else(|| malformed("no modulus (tag 91)"))?,
335 })
336 }
337
338 pub fn bits(&self) -> usize {
340 match self.modulus.iter().position(|&b| b != 0) {
341 Some(first) => {
342 (self.modulus.len() - first) * 8 - self.modulus[first].leading_zeros() as usize
343 }
344 None => 0,
345 }
346 }
347}
348
349#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
364pub struct KeyId([u8; Self::LEN]);
365
366impl KeyId {
367 pub const LEN: usize = 16;
369
370 pub fn parse(bytes: &[u8]) -> Result<Self> {
377 let bytes: [u8; Self::LEN] = bytes.try_into().map_err(|_| {
378 malformed(&format!(
379 "key identifier must be 16 bytes, got {}",
380 bytes.len()
381 ))
382 })?;
383 if !bytes[..7].iter().all(u8::is_ascii_digit)
384 || !bytes[9..12].iter().all(u8::is_ascii_digit)
385 {
386 return Err(malformed("key identifier is not digits where it should be"));
387 }
388 Ok(KeyId(bytes))
389 }
390
391 pub fn number(&self) -> &str {
393 std::str::from_utf8(&self.0[..7]).unwrap_or("???????")
394 }
395
396 pub fn group(&self) -> &str {
398 std::str::from_utf8(&self.0[9..12]).unwrap_or("???")
399 }
400
401 pub fn as_bytes(&self) -> &[u8; Self::LEN] {
403 &self.0
404 }
405}
406
407impl fmt::Display for KeyId {
408 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
410 write!(f, "{}/{}", self.number(), self.group())
411 }
412}
413
414impl fmt::Debug for KeyId {
415 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
418 write!(f, "KeyId({self}")?;
419 for byte in &self.0[12..] {
420 write!(f, " {byte:02X}")?;
421 }
422 write!(f, ")")
423 }
424}
425
426#[derive(Debug, Clone, PartialEq, Eq)]
446pub struct CardVerifiableCertificate {
447 pub issuer_key_id: KeyId,
449 pub subject_key_id: KeyId,
451 pub public_key: RsaPublicKey,
453 pub signature: Vec<u8>,
455 pub signed_data: Vec<u8>,
457}
458
459impl CardVerifiableCertificate {
460 pub const TAG: u32 = 0x7F21;
462 pub const TAG_BODY: u32 = 0x5F4E;
464 pub const TAG_SIGNATURE: u32 = 0x5F37;
466 pub const KEY_ID_LEN: usize = 16;
468 pub const BODY_LEN: usize = 297;
470
471 pub fn parse(data: &[u8]) -> Result<Self> {
476 let contents = if data.starts_with(&[0x7F, 0x21]) {
477 let outer = ber::parse(data)?;
478 if outer.tag != Self::TAG {
479 return Err(malformed(&format!(
480 "expected tag 7F21, got {:04X}",
481 outer.tag
482 )));
483 }
484 outer.value
485 } else {
486 data
487 };
488 let mut body = None;
489 let mut signature = None;
490 for tlv in ber::iter(contents) {
491 let tlv = tlv?;
492 match tlv.tag {
493 Self::TAG_BODY => body = Some(tlv.value),
494 Self::TAG_SIGNATURE => signature = Some(tlv.value.to_vec()),
495 _ => {}
496 }
497 }
498 let body = body.ok_or_else(|| malformed("certificate has no body (tag 5F4E)"))?;
499 if body.len() != Self::BODY_LEN {
502 return Err(malformed(&format!(
503 "certificate body must be {} bytes, got {}",
504 Self::BODY_LEN,
505 body.len()
506 )));
507 }
508 let ids = 2 * Self::KEY_ID_LEN;
509 Ok(CardVerifiableCertificate {
510 issuer_key_id: KeyId::parse(&body[..Self::KEY_ID_LEN])?,
511 subject_key_id: KeyId::parse(&body[Self::KEY_ID_LEN..ids])?,
512 public_key: RsaPublicKey::parse(&body[ids..])?,
513 signature: signature
514 .ok_or_else(|| malformed("certificate has no signature (tag 5F37)"))?,
515 signed_data: body.to_vec(),
516 })
517 }
518}
519
520#[derive(Debug, Clone, Copy, PartialEq, Eq)]
525pub enum ImageFormat {
526 Png,
528 Jpeg2000,
530 Unknown,
532}
533
534impl ImageFormat {
535 pub fn detect(data: &[u8]) -> Self {
537 if data.starts_with(b"\x89PNG\r\n\x1a\n") {
538 ImageFormat::Png
539 } else if data.len() >= 8 && &data[4..8] == b"jP " {
540 ImageFormat::Jpeg2000
541 } else {
542 ImageFormat::Unknown
543 }
544 }
545
546 pub const fn extension(self) -> &'static str {
548 match self {
549 ImageFormat::Png => "png",
550 ImageFormat::Jpeg2000 => "jp2",
551 ImageFormat::Unknown => "bin",
552 }
553 }
554}
555
556#[derive(Debug, Clone, PartialEq, Eq)]
558pub struct Image {
559 pub data: Vec<u8>,
561 pub format: ImageFormat,
563}
564
565impl Image {
566 pub fn new(data: Vec<u8>) -> Self {
568 let format = ImageFormat::detect(&data);
569 Image { data, format }
570 }
571}
572
573pub(crate) fn check_offsets(file: &[u8], table: &[u8], starts: &[usize]) -> Result<()> {
579 if table.len() != starts.len() * 2 {
580 return Err(malformed(&format!(
581 "offset table is {} bytes for {} objects",
582 table.len(),
583 starts.len()
584 )));
585 }
586 for (i, (chunk, &start)) in table.chunks_exact(2).zip(starts).enumerate() {
587 let declared = usize::from(u16::from_be_bytes([chunk[0], chunk[1]]));
588 if declared != start {
589 return Err(malformed(&format!(
590 "offset {i} says {declared:#06X} but the object starts at {start:#06X}"
591 )));
592 }
593 }
594 let _ = file;
595 Ok(())
596}
597
598pub(crate) struct TlvFields<'a> {
605 items: Vec<(u32, &'a [u8], &'a [u8])>,
607}
608
609impl<'a> TlvFields<'a> {
610 pub(crate) fn parse(
611 raw: &'a [u8],
612 expected_tag: u32,
613 offset_table: Option<u32>,
614 ) -> Result<Self> {
615 let outer = ber::parse(raw)?;
616 if outer.tag != expected_tag {
617 return Err(malformed(&format!(
618 "expected tag {expected_tag:04X}, got {:04X}",
619 outer.tag
620 )));
621 }
622 let mut pos = ber::parse_header(raw)?.header_len;
626 let mut rest = outer.value;
627 let mut offsets = None;
628 let mut items = Vec::new();
629 let mut starts = Vec::new();
630 while let Some(&first) = rest.first() {
631 if first == 0x00 || first == 0xFF {
632 break;
633 }
634 let header = ber::parse_header(rest)?;
635 let end = header.total_len();
636 let value = rest
637 .get(header.header_len..end)
638 .ok_or_else(|| malformed("a field runs past the end of the file"))?;
639 if Some(header.tag) == offset_table {
640 offsets = Some(value);
641 } else {
642 items.push((header.tag, value, &rest[..end]));
643 starts.push(pos);
644 }
645 pos += end;
646 rest = &rest[end..];
647 }
648 if let Some(table) = offsets {
649 check_offsets(raw, table, &starts)?;
650 }
651 Ok(TlvFields { items })
652 }
653
654 pub(crate) fn get(&self, tag: u32) -> Result<&'a [u8]> {
655 self.items
656 .iter()
657 .find(|(t, _, _)| *t == tag)
658 .map(|(_, v, _)| *v)
659 .ok_or_else(|| malformed(&format!("no field with tag {tag:04X}")))
660 }
661
662 pub(crate) fn bytes_before(&self, tag: u32) -> Result<Vec<u8>> {
664 let end = self
665 .items
666 .iter()
667 .position(|(t, _, _)| *t == tag)
668 .ok_or_else(|| malformed(&format!("no field with tag {tag:04X}")))?;
669 Ok(self.items[..end]
670 .iter()
671 .flat_map(|(_, _, raw)| *raw)
672 .copied()
673 .collect())
674 }
675
676 pub(crate) fn bytes_of(&self, tags: &[u32]) -> Result<Vec<u8>> {
678 let mut out = Vec::new();
679 for tag in tags {
680 let raw = self
681 .items
682 .iter()
683 .find(|(t, _, _)| t == tag)
684 .map(|(_, _, raw)| *raw)
685 .ok_or_else(|| malformed(&format!("no field with tag {tag:04X}")))?;
686 out.extend_from_slice(raw);
687 }
688 Ok(out)
689 }
690}
691
692pub(crate) fn malformed(what: &str) -> Error {
693 Error::Malformed(what.to_owned())
694}
695
696fn hex(bytes: &[u8]) -> String {
697 bytes
698 .iter()
699 .map(|b| format!("{b:02X}"))
700 .collect::<Vec<_>>()
701 .join(" ")
702}
703
704pub fn sha256_digest_info(digest: &[u8]) -> Vec<u8> {
714 const ALGORITHM: [u8; 15] = [
715 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00,
716 ];
717 let inner = ALGORITHM.len() + 2 + digest.len();
718 let mut out = vec![0x30];
719 if inner < 0x80 {
720 out.push(inner as u8);
721 } else {
722 out.push(0x81);
723 out.push(inner as u8);
724 }
725 out.extend_from_slice(&ALGORITHM);
726 out.push(0x04);
727 out.push(digest.len() as u8);
728 out.extend_from_slice(digest);
729 out
730}
731
732#[cfg(feature = "verify")]
733impl RsaPublicKey {
734 fn to_rsa(&self) -> Result<rsa::RsaPublicKey> {
735 rsa::RsaPublicKey::new(
736 rsa::BigUint::from_bytes_be(&self.modulus),
737 rsa::BigUint::from_bytes_be(&self.exponent),
738 )
739 .map_err(|_| Error::SignatureInvalid("the public key is not usable"))
740 }
741
742 pub fn verify_pkcs1(&self, digest_info: &[u8], signature: &[u8]) -> Result<()> {
747 self.to_rsa()?
748 .verify(rsa::Pkcs1v15Sign::new_unprefixed(), digest_info, signature)
749 .map_err(|_| Error::SignatureInvalid("PKCS #1 v1.5 signature does not verify"))
750 }
751
752 pub fn verify_pkcs1_sha256(&self, message: &[u8], signature: &[u8]) -> Result<()> {
754 use rsa::sha2::Digest as _;
755 let digest = rsa::sha2::Sha256::digest(message);
756 self.verify_pkcs1(&sha256_digest_info(&digest), signature)
757 }
758
759 pub fn verify_pss_sha256(&self, message: &[u8], signature: &[u8]) -> Result<()> {
761 use rsa::sha2::Digest as _;
762 self.verify_pss_prehashed(&rsa::sha2::Sha256::digest(message), signature)
763 }
764
765 #[cfg(feature = "sm")]
772 pub fn encrypt_oaep_sha256(&self, message: &[u8]) -> Result<Vec<u8>> {
773 use rsa::rand_core::OsRng;
774 self.to_rsa()?
775 .encrypt(&mut OsRng, rsa::Oaep::new::<rsa::sha2::Sha256>(), message)
776 .map_err(|_| Error::SignatureInvalid("OAEP encryption failed"))
777 }
778
779 pub fn verify_pss_prehashed(&self, digest: &[u8], signature: &[u8]) -> Result<()> {
781 self.to_rsa()?
782 .verify(rsa::Pss::new::<rsa::sha2::Sha256>(), digest, signature)
783 .map_err(|_| Error::SignatureInvalid("PSS signature does not verify"))
784 }
785}
786
787#[cfg(feature = "verify")]
789pub fn sha256(data: &[u8]) -> [u8; 32] {
790 use rsa::sha2::Digest as _;
791 rsa::sha2::Sha256::digest(data).into()
792}
793
794#[cfg(all(test, feature = "verify"))]
795mod verify_tests {
796 use super::*;
797
798 #[test]
799 fn builds_digest_infos_of_both_lengths() {
800 let one = sha256_digest_info(&[0xAA; 32]);
802 assert_eq!(&one[..2], &[0x30, 0x31]);
803 assert_eq!(&one[17..19], &[0x04, 0x20]);
804 assert_eq!(one.len(), 51);
805
806 let three = sha256_digest_info(&[0xAA; 96]);
808 assert_eq!(&three[..2], &[0x30, 0x71]);
809 assert_eq!(&three[17..19], &[0x04, 0x60]);
810 assert_eq!(three.len(), 115);
811 }
812}
813
814#[cfg(feature = "verify")]
815impl CardVerifiableCertificate {
816 pub fn verify(&self) -> Result<()> {
827 let ca = crate::ca::find(&self.issuer_key_id)
828 .ok_or(Error::UnknownCertificateAuthority(self.issuer_key_id))?;
829 self.verify_with(&ca.to_public_key())
830 }
831
832 pub fn verify_chain(chain: &[Self]) -> Result<()> {
845 let (first, rest) = chain
846 .split_first()
847 .ok_or_else(|| malformed("an empty chain verifies nothing"))?;
848 first.verify()?;
849 let mut issuer = first;
850 for cert in rest {
851 if cert.issuer_key_id != issuer.subject_key_id {
852 return Err(malformed(
853 "chain is broken: a certificate names an issuer the one above does not certify",
854 ));
855 }
856 cert.verify_with(&issuer.public_key)?;
857 issuer = cert;
858 }
859 Ok(())
860 }
861
862 pub fn verify_with(&self, ca_key: &RsaPublicKey) -> Result<()> {
871 ca_key.verify_pkcs1_sha256(&self.signed_data, &self.signature)
872 }
873}
874
875#[cfg(test)]
876mod tests {
877 use super::*;
878
879 #[test]
880 fn parses_an_ap_identification_field() {
881 let identification = ApIdentification::parse(&[0x06, 0x03, 0x0E, 0x01]).unwrap();
882 assert_eq!(identification.specification_version, 0x06);
883 assert_eq!(identification.extended_lc_le_support, 0x03);
884 assert_eq!(identification.vendor_id, 0x0E);
885 assert_eq!(identification.vendor_specific, 0x01);
886 assert_eq!(identification.to_bytes(), [0x06, 0x03, 0x0E, 0x01]);
887 assert!(ApIdentification::parse(&[0x06, 0x03, 0x0E]).is_err());
888 assert!(ApIdentification::parse(&[0x06, 0x03, 0x0E, 0x01, 0x00]).is_err());
889 }
890
891 #[test]
892 fn parses_a_date() {
893 assert_eq!(
894 Date::parse(b"19800217").unwrap(),
895 Date {
896 year: 1980,
897 month: 2,
898 day: 17
899 }
900 );
901 assert_eq!(Date::parse(b"19800217").unwrap().to_string(), "1980-02-17");
902 assert!(Date::parse(b"1980021").is_err());
903 assert!(Date::parse(b"19801317").is_err());
904 assert!(Date::parse(b"1980-2-17").is_err());
905 }
906
907 #[test]
908 fn converts_to_japanese_eras() {
909 assert_eq!(
911 Date::parse(b"19800217").unwrap().to_era(),
912 Some((Era::Showa, 55))
913 );
914 assert_eq!(
916 Date::parse(b"19890107").unwrap().to_era(),
917 Some((Era::Showa, 64))
918 );
919 assert_eq!(
920 Date::parse(b"19890108").unwrap().to_era(),
921 Some((Era::Heisei, 1))
922 );
923 assert_eq!(
924 Date::parse(b"20190430").unwrap().to_era(),
925 Some((Era::Heisei, 31))
926 );
927 assert_eq!(
928 Date::parse(b"20190501").unwrap().to_era(),
929 Some((Era::Reiwa, 1))
930 );
931 assert_eq!(Date::parse(b"18670101").unwrap().to_era(), None);
932 assert_eq!(Era::Showa.name(), "昭和");
933 }
934
935 #[test]
936 fn builds_verification_code_b() {
937 let dob = Date::parse(b"19800217").unwrap();
939 let code = verification_code_b(dob, 2035, b"2285").unwrap();
940 assert_eq!(code.as_bytes(), b"55021720352285");
941 assert_eq!(code.len(), 14);
942 }
943
944 #[test]
945 fn rejects_a_code_b_it_cannot_build() {
946 let dob = Date::parse(b"19800217").unwrap();
947 assert!(verification_code_b(dob, 2035, b"228").is_err());
948 assert!(verification_code_b(dob, 2035, b"22X5").is_err());
949 assert!(verification_code_b(Date::parse(b"18000101").unwrap(), 2035, b"2285").is_err());
950 }
951
952 #[test]
953 fn my_number_is_also_verification_code_a() {
954 let n = MyNumber::parse(b"537686677188").unwrap();
955 assert_eq!(n.as_str(), "537686677188");
956 assert_eq!(
957 n.as_verification_code_a().unwrap().as_bytes(),
958 b"537686677188"
959 );
960 assert!(!format!("{n:?}").contains("5376"));
961 assert!(MyNumber::parse(b"53768667718").is_err());
962 assert!(MyNumber::parse(b"53768667718X").is_err());
963 }
964
965 #[test]
966 fn parses_a_public_key() {
967 let mut data = vec![0x90, 0x03, 0x01, 0x00, 0x01, 0x91, 0x82, 0x01, 0x00];
968 data.push(0xC9);
969 data.extend(std::iter::repeat_n(0xAA, 255));
970 let key = RsaPublicKey::parse(&data).unwrap();
971 assert_eq!(key.exponent, [0x01, 0x00, 0x01]);
972 assert_eq!(key.modulus.len(), 256);
973 assert_eq!(key.bits(), 2048);
974 }
975
976 #[test]
977 fn detects_image_formats() {
978 assert_eq!(
979 ImageFormat::detect(b"\x89PNG\r\n\x1a\n\x00"),
980 ImageFormat::Png
981 );
982 assert_eq!(
983 ImageFormat::detect(b"\x00\x00\x00\x0CjP \r\n"),
984 ImageFormat::Jpeg2000
985 );
986 assert_eq!(ImageFormat::detect(b"nope"), ImageFormat::Unknown);
987 assert_eq!(ImageFormat::Png.extension(), "png");
988 }
989
990 fn cv_certificate() -> Vec<u8> {
992 let mut body = b"9200073\x08\x050010000".to_vec();
993 body.extend_from_slice(b"9299774\x08\x050010000");
994 body.extend_from_slice(&[0x90, 0x03, 0x01, 0x00, 0x01, 0x91, 0x82, 0x01, 0x00]);
995 body.push(0xC9);
996 body.extend(std::iter::repeat_n(0xAA, 255));
997 assert_eq!(body.len(), CardVerifiableCertificate::BODY_LEN);
998
999 let mut inner = vec![0x5F, 0x4E, 0x82];
1000 inner.extend_from_slice(&(body.len() as u16).to_be_bytes());
1001 inner.extend_from_slice(&body);
1002 inner.extend_from_slice(&[0x5F, 0x37, 0x82, 0x01, 0x00]);
1003 inner.extend(std::iter::repeat_n(0xBC, 256));
1004
1005 let mut cert = vec![0x7F, 0x21, 0x82];
1006 cert.extend_from_slice(&(inner.len() as u16).to_be_bytes());
1007 cert.extend_from_slice(&inner);
1008 cert
1009 }
1010
1011 #[test]
1012 fn parses_a_card_verifiable_certificate() {
1013 let parsed = CardVerifiableCertificate::parse(&cv_certificate()).unwrap();
1014 assert_eq!(parsed.issuer_key_id.to_string(), "9200073/001");
1015 assert_eq!(parsed.subject_key_id.to_string(), "9299774/001");
1016 assert_eq!(parsed.public_key.bits(), 2048);
1017 assert_eq!(parsed.signature.len(), 256);
1018 assert_eq!(
1020 parsed.signed_data.len(),
1021 CardVerifiableCertificate::BODY_LEN
1022 );
1023 assert!(parsed.signed_data.starts_with(b"9200073"));
1024 }
1025
1026 #[test]
1027 fn rejects_a_body_of_the_wrong_size() {
1028 let mut cert = cv_certificate();
1029 let body_len = CardVerifiableCertificate::BODY_LEN - 1;
1031 cert[8] = (body_len >> 8) as u8;
1032 cert[9] = body_len as u8;
1033 cert.remove(10 + body_len);
1034 cert[3] = ((cert.len() - 5) >> 8) as u8;
1035 cert[4] = (cert.len() - 5) as u8;
1036 let err = CardVerifiableCertificate::parse(&cert).unwrap_err();
1037 assert!(format!("{err}").contains("297"), "{err}");
1038 }
1039
1040 #[test]
1041 fn offset_table_mismatch_is_an_error() {
1042 assert!(check_offsets(&[], &[0x00, 0x0E, 0x00, 0x20], &[14, 32]).is_ok());
1043 assert!(check_offsets(&[], &[0x00, 0x0E, 0x00, 0x20], &[14, 33]).is_err());
1044 assert!(check_offsets(&[], &[0x00, 0x0E], &[14, 32]).is_err());
1045 }
1046}