1extern crate alloc;
41
42use crate::asn1::oid;
43use crate::asn1::reader;
44use crate::sm2::{DEFAULT_SIGNER_ID, Sm2PublicKey, verify_with_id};
45use alloc::vec::Vec;
46
47const TAG_UTC_TIME: u8 = 0x17;
48const TAG_GENERALIZED_TIME: u8 = 0x18;
49const TAG_BOOLEAN: u8 = 0x01;
50
51#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
62pub struct X509Time {
63 pub year: u16,
65 pub month: u8,
67 pub day: u8,
69 pub hour: u8,
71 pub minute: u8,
73 pub second: u8,
75}
76
77fn two_digits(b: &[u8]) -> Option<u8> {
78 match b {
79 [a @ b'0'..=b'9', c @ b'0'..=b'9'] => Some((a - b'0') * 10 + (c - b'0')),
80 _ => None,
81 }
82}
83
84fn read_time(input: &[u8]) -> Option<(X509Time, &[u8])> {
86 let (year, body, rest) = if let Some((v, rest)) = reader::read_tlv(input, TAG_UTC_TIME) {
87 if v.len() != 13 {
88 return None;
89 }
90 let yy = u16::from(two_digits(&v[0..2])?);
91 (if yy >= 50 { 1900 + yy } else { 2000 + yy }, &v[2..], rest)
92 } else {
93 let (v, rest) = reader::read_tlv(input, TAG_GENERALIZED_TIME)?;
94 if v.len() != 15 {
95 return None;
96 }
97 (
98 u16::from(two_digits(&v[0..2])?) * 100 + u16::from(two_digits(&v[2..4])?),
99 &v[4..],
100 rest,
101 )
102 };
103 if body.len() != 11 || body[10] != b'Z' {
105 return None;
106 }
107 let (month, day) = (two_digits(&body[0..2])?, two_digits(&body[2..4])?);
108 let (hour, minute, second) = (
109 two_digits(&body[4..6])?,
110 two_digits(&body[6..8])?,
111 two_digits(&body[8..10])?,
112 );
113 if !(1..=12).contains(&month)
114 || !(1..=31).contains(&day)
115 || hour > 23
116 || minute > 59
117 || second > 59
118 {
119 return None;
120 }
121 Some((
122 X509Time {
123 year,
124 month,
125 day,
126 hour,
127 minute,
128 second,
129 },
130 rest,
131 ))
132}
133
134fn read_sm2_sig_algid(input: &[u8]) -> Option<(&[u8], &[u8])> {
139 let (body, rest) = reader::read_sequence(input)?;
140 let span = &input[..input.len() - rest.len()];
141 let (oid_bytes, after_oid) = reader::read_oid(body)?;
142 if oid_bytes != oid::SM2_SIGN_WITH_SM3 {
143 return None;
144 }
145 if after_oid.is_empty() {
146 Some((span, rest))
147 } else {
148 let after_null = reader::read_null(after_oid)?;
149 if after_null.is_empty() {
150 Some((span, rest))
151 } else {
152 None
153 }
154 }
155}
156
157struct ParsedExt<'a> {
160 oid: &'a [u8],
161 critical: bool,
162 value: &'a [u8],
163 rest: &'a [u8],
164}
165
166fn next_extension(exts: &[u8]) -> Option<ParsedExt<'_>> {
173 let (ext, rest) = reader::read_sequence(exts)?;
174 let (oid, after_oid) = reader::read_oid(ext)?;
175 let (critical, after_bool) = match reader::read_tlv(after_oid, TAG_BOOLEAN) {
176 Some((b, rb)) => {
177 if b.len() != 1 {
178 return None;
179 }
180 (b[0] != 0, rb)
181 }
182 None => (false, after_oid),
183 };
184 let (value, after_value) = reader::read_octet_string(after_bool)?;
185 if !after_value.is_empty() {
186 return None;
187 }
188 Some(ParsedExt {
189 oid,
190 critical,
191 value,
192 rest,
193 })
194}
195
196fn check_extensions_shape(content: &[u8]) -> Option<()> {
200 let (seq, rest) = reader::read_sequence(content)?;
201 if !rest.is_empty() || seq.is_empty() {
202 return None;
203 }
204 let mut exts = seq;
205 while !exts.is_empty() {
206 exts = next_extension(exts)?.rest;
207 }
208 Some(())
209}
210
211#[derive(Clone, Copy, Debug, PartialEq, Eq)]
218pub struct KeyUsage {
219 bits: u16,
220}
221
222impl KeyUsage {
223 fn parse(bit_string_tlv: &[u8]) -> Option<Self> {
226 let (unused, value, rest) = reader::read_bit_string(bit_string_tlv)?;
227 if !rest.is_empty() || unused > 7 {
228 return None;
229 }
230 let mut bits = 0u16;
231 for i in 0u16..9 {
232 let (byte, off) = ((i / 8) as usize, 7 - (i % 8));
233 if byte < value.len() && (value[byte] >> off) & 1 == 1 {
234 bits |= 1 << i;
235 }
236 }
237 Some(Self { bits })
238 }
239 const fn has(self, i: u16) -> bool {
240 self.bits & (1 << i) != 0
241 }
242 #[must_use]
244 pub const fn digital_signature(self) -> bool {
245 self.has(0)
246 }
247 #[must_use]
249 pub const fn content_commitment(self) -> bool {
250 self.has(1)
251 }
252 #[must_use]
254 pub const fn key_encipherment(self) -> bool {
255 self.has(2)
256 }
257 #[must_use]
259 pub const fn data_encipherment(self) -> bool {
260 self.has(3)
261 }
262 #[must_use]
264 pub const fn key_agreement(self) -> bool {
265 self.has(4)
266 }
267 #[must_use]
269 pub const fn key_cert_sign(self) -> bool {
270 self.has(5)
271 }
272 #[must_use]
274 pub const fn crl_sign(self) -> bool {
275 self.has(6)
276 }
277 #[must_use]
279 pub const fn encipher_only(self) -> bool {
280 self.has(7)
281 }
282 #[must_use]
284 pub const fn decipher_only(self) -> bool {
285 self.has(8)
286 }
287 #[doc(hidden)]
293 #[must_use]
294 pub const fn bits(&self) -> u16 {
295 self.bits
296 }
297}
298
299#[derive(Clone, Copy, Debug, PartialEq, Eq)]
305pub struct BasicConstraints {
306 pub is_ca: bool,
308 pub path_len: Option<u32>,
310}
311
312impl BasicConstraints {
313 fn parse(seq_tlv: &[u8]) -> Option<Self> {
317 let (content, rest) = reader::read_sequence(seq_tlv)?;
318 if !rest.is_empty() {
319 return None;
320 }
321 let (is_ca, after) = match reader::read_tlv(content, TAG_BOOLEAN) {
322 Some((b, r)) => {
323 if b.len() != 1 {
324 return None;
325 }
326 (b[0] != 0, r)
327 }
328 None => (false, content),
329 };
330 let path_len = if after.is_empty() {
331 None
332 } else {
333 let (int, r) = reader::read_integer(after)?;
334 if !r.is_empty() || int.len() > 4 {
335 return None;
336 }
337 let mut v = 0u32;
338 for &byte in int {
339 v = (v << 8) | u32::from(byte);
340 }
341 Some(v)
342 };
343 Some(Self { is_ca, path_len })
344 }
345}
346
347fn find_extension<'a>(ext_tlv: &'a [u8], extn_id: &[u8]) -> Option<&'a [u8]> {
353 let (seq, _) = reader::read_sequence(ext_tlv)?;
354 let mut exts = seq;
355 while !exts.is_empty() {
356 let ext = next_extension(exts)?;
357 if ext.oid == extn_id {
358 return Some(ext.value);
359 }
360 exts = ext.rest;
361 }
362 None
363}
364
365fn has_unknown_critical(ext_tlv: &[u8], known: &[&[u8]]) -> bool {
370 let Some((seq, _)) = reader::read_sequence(ext_tlv) else {
371 return false;
372 };
373 let mut exts = seq;
374 while !exts.is_empty() {
375 let Some(ext) = next_extension(exts) else {
376 return false;
377 };
378 if ext.critical && !known.contains(&ext.oid) {
379 return true;
380 }
381 exts = ext.rest;
382 }
383 false
384}
385
386pub struct Certificate {
393 tbs: Vec<u8>,
394 serial: Vec<u8>,
395 issuer: Vec<u8>,
396 subject: Vec<u8>,
397 extensions: Option<Vec<u8>>,
398 sig: Vec<u8>,
399 not_before: X509Time,
400 not_after: X509Time,
401 subject_key: Sm2PublicKey,
402}
403
404impl Certificate {
405 #[must_use]
413 pub fn from_der(der: &[u8]) -> Option<Self> {
414 let (cert, rest) = reader::read_sequence(der)?;
415 if !rest.is_empty() {
416 return None;
417 }
418
419 let (tbs_content, after_tbs) = reader::read_sequence(cert)?;
422 let tbs_span = &cert[..cert.len() - after_tbs.len()];
423
424 let (ver_content, cur) = reader::read_context_tagged_explicit(tbs_content, 0)?;
428 let (ver_int, ver_rest) = reader::read_integer(ver_content)?;
429 if ver_int != [2] || !ver_rest.is_empty() {
430 return None;
431 }
432
433 let (serial, cur) = reader::read_integer(cur)?;
438 if serial.is_empty() || serial.len() > 20 {
439 return None;
440 }
441
442 let (algid_inner, cur) = read_sm2_sig_algid(cur)?;
445
446 let (_, after_issuer) = reader::read_sequence(cur)?;
448 let issuer = &cur[..cur.len() - after_issuer.len()];
449 let cur = after_issuer;
450
451 let (val_content, cur) = reader::read_sequence(cur)?;
453 let (not_before, val_rest) = read_time(val_content)?;
454 let (not_after, val_rest) = read_time(val_rest)?;
455 if !val_rest.is_empty() {
456 return None;
457 }
458
459 let (_, after_subject) = reader::read_sequence(cur)?;
461 let subject = &cur[..cur.len() - after_subject.len()];
462 let cur = after_subject;
463
464 let (_, after_spki) = reader::read_sequence(cur)?;
468 let spki_span = &cur[..cur.len() - after_spki.len()];
469 let subject_key = crate::spki::decode(spki_span)?;
470 let cur = after_spki;
471
472 let cur = match reader::read_context_tagged_implicit(cur, 1) {
474 Some((_, r)) => r,
475 None => cur,
476 };
477 let cur = match reader::read_context_tagged_implicit(cur, 2) {
478 Some((_, r)) => r,
479 None => cur,
480 };
481
482 let (extensions, cur) = match reader::read_context_tagged_explicit(cur, 3) {
485 Some((ext_content, r)) => {
486 check_extensions_shape(ext_content)?;
487 (Some(ext_content), r)
488 }
489 None => (None, cur),
490 };
491 if !cur.is_empty() {
493 return None;
494 }
495
496 let (algid_outer, after_alg) = read_sm2_sig_algid(after_tbs)?;
500 if algid_outer != algid_inner {
501 return None;
502 }
503
504 let (unused, sig, after_sig) = reader::read_bit_string(after_alg)?;
509 if unused != 0 || !after_sig.is_empty() {
510 return None;
511 }
512
513 Some(Self {
514 tbs: tbs_span.to_vec(),
515 serial: serial.to_vec(),
516 issuer: issuer.to_vec(),
517 subject: subject.to_vec(),
518 extensions: extensions.map(<[u8]>::to_vec),
519 sig: sig.to_vec(),
520 not_before,
521 not_after,
522 subject_key,
523 })
524 }
525
526 #[must_use]
535 pub fn verify_signature(&self, issuer: &Sm2PublicKey) -> bool {
536 self.verify_signature_with_id(issuer, DEFAULT_SIGNER_ID)
537 }
538
539 #[must_use]
542 pub fn verify_signature_with_id(&self, issuer: &Sm2PublicKey, id: &[u8]) -> bool {
543 verify_with_id(issuer, id, &self.tbs, &self.sig)
544 }
545
546 #[must_use]
549 pub const fn subject_public_key(&self) -> Sm2PublicKey {
550 self.subject_key
551 }
552
553 #[must_use]
556 pub fn tbs_raw(&self) -> &[u8] {
557 &self.tbs
558 }
559
560 #[must_use]
564 pub fn serial_raw(&self) -> &[u8] {
565 &self.serial
566 }
567
568 #[must_use]
571 pub fn issuer_raw(&self) -> &[u8] {
572 &self.issuer
573 }
574
575 #[must_use]
577 pub fn subject_raw(&self) -> &[u8] {
578 &self.subject
579 }
580
581 #[must_use]
587 pub fn extensions_raw(&self) -> Option<&[u8]> {
588 self.extensions.as_deref()
589 }
590
591 #[must_use]
594 pub const fn not_before(&self) -> X509Time {
595 self.not_before
596 }
597
598 #[must_use]
600 pub const fn not_after(&self) -> X509Time {
601 self.not_after
602 }
603
604 #[must_use]
610 pub fn is_self_issued(&self) -> bool {
611 self.issuer == self.subject
612 }
613
614 #[must_use]
618 pub fn key_usage(&self) -> Option<KeyUsage> {
619 KeyUsage::parse(find_extension(self.extensions.as_deref()?, oid::KEY_USAGE)?)
620 }
621
622 #[must_use]
626 pub fn basic_constraints(&self) -> Option<BasicConstraints> {
627 BasicConstraints::parse(find_extension(
628 self.extensions.as_deref()?,
629 oid::BASIC_CONSTRAINTS,
630 )?)
631 }
632
633 #[cfg(feature = "tlcp")]
640 pub(crate) fn subject_is_empty(&self) -> bool {
641 reader::read_sequence(&self.subject).is_none_or(|(content, _)| content.is_empty())
642 }
643}
644
645pub const MAX_CHAIN_DEPTH: usize = 8;
651
652const KNOWN_EXTS: &[&[u8]] = &[oid::KEY_USAGE, oid::BASIC_CONSTRAINTS];
655
656fn within_window(cert: &Certificate, at: Option<X509Time>) -> bool {
657 at.is_none_or(|t| cert.not_before <= t && t <= cert.not_after)
658}
659
660fn is_ca_issuer(cert: &Certificate) -> bool {
664 cert.basic_constraints().is_some_and(|bc| bc.is_ca)
665 && cert.key_usage().is_some_and(KeyUsage::key_cert_sign)
666}
667
668#[must_use]
692pub fn verify_chain(
693 chain: &[Certificate],
694 anchors: &[Certificate],
695 at_time: Option<X509Time>,
696) -> bool {
697 let chain: alloc::vec::Vec<&Certificate> = chain.iter().collect();
698 let anchors: alloc::vec::Vec<&Certificate> = anchors.iter().collect();
699 verify_chain_refs(&chain, &anchors, at_time)
700}
701
702#[doc(hidden)]
709#[must_use]
710pub fn verify_chain_refs(
711 chain: &[&Certificate],
712 anchors: &[&Certificate],
713 at_time: Option<X509Time>,
714) -> bool {
715 if chain.is_empty() || chain.len() > MAX_CHAIN_DEPTH {
716 return false;
717 }
718 for &cert in chain {
719 if cert
720 .extensions
721 .as_deref()
722 .is_some_and(|e| has_unknown_critical(e, KNOWN_EXTS))
723 {
724 return false;
725 }
726 if !within_window(cert, at_time) {
727 return false;
728 }
729 }
730 for i in 0..chain.len() - 1 {
732 let (subj, iss) = (chain[i], chain[i + 1]);
733 if subj.issuer_raw() != iss.subject_raw() {
734 return false;
735 }
736 if !subj.verify_signature(&iss.subject_public_key()) {
737 return false;
738 }
739 if !is_ca_issuer(iss) {
740 return false;
741 }
742 }
743 let top = chain[chain.len() - 1];
747 anchors.iter().any(|a| {
748 a.subject_raw() == top.issuer_raw()
749 && within_window(a, at_time)
750 && top.verify_signature(&a.subject_public_key())
751 })
752}
753
754#[cfg(test)]
758pub(crate) mod test_support {
759 use crate::sm2::{DEFAULT_SIGNER_ID, Sm2PrivateKey, Sm2PublicKey, sign_with_id};
760 use alloc::vec::Vec;
761 use getrandom::SysRng;
762
763 #[allow(clippy::cast_possible_truncation)]
765 pub fn der(tag: u8, content: &[u8]) -> Vec<u8> {
766 let mut out = alloc::vec![tag];
767 let n = content.len();
768 if n < 128 {
769 out.push(n as u8);
770 } else {
771 let mut len_bytes = Vec::new();
772 let mut v = n;
773 while v > 0 {
774 len_bytes.push((v & 0xff) as u8);
775 v >>= 8;
776 }
777 len_bytes.reverse();
778 out.push(0x80 | len_bytes.len() as u8);
779 out.extend_from_slice(&len_bytes);
780 }
781 out.extend_from_slice(content);
782 out
783 }
784
785 pub fn name(label: &[u8]) -> Vec<u8> {
788 der(0x30, label)
789 }
790
791 pub fn key(seed: u8) -> Sm2PrivateKey {
793 let mut b = [0u8; 32];
794 b[31] = seed.max(1);
795 Option::from(Sm2PrivateKey::from_bytes_be(&b)).expect("valid test scalar")
796 }
797
798 pub fn ku_ext(bits: &[u8], critical: bool) -> Vec<u8> {
800 let mut val = [0u8; 2];
801 for &b in bits {
802 val[(b / 8) as usize] |= 1 << (7 - (b % 8));
803 }
804 let nbytes = usize::from(bits.iter().any(|&b| b >= 8)) + 1;
805 let mut bs = alloc::vec![0u8]; bs.extend_from_slice(&val[..nbytes]);
807 extension(
808 crate::asn1::oid::KEY_USAGE,
809 critical,
810 &der(0x04, &der(0x03, &bs)),
811 )
812 }
813
814 #[allow(clippy::cast_possible_truncation)]
816 pub fn bc_ext(is_ca: bool, path_len: Option<u32>, critical: bool) -> Vec<u8> {
817 let mut seq = Vec::new();
818 if is_ca {
819 seq.extend_from_slice(&[0x01, 0x01, 0xFF]);
820 }
821 if let Some(p) = path_len {
822 seq.extend_from_slice(&der(0x02, &[p as u8]));
823 }
824 extension(
825 crate::asn1::oid::BASIC_CONSTRAINTS,
826 critical,
827 &der(0x04, &der(0x30, &seq)),
828 )
829 }
830
831 pub fn raw_ext(oid_bytes: &[u8], critical: bool, value_inner: &[u8]) -> Vec<u8> {
833 extension(oid_bytes, critical, &der(0x04, value_inner))
834 }
835
836 fn extension(oid_bytes: &[u8], critical: bool, octet_string_tlv: &[u8]) -> Vec<u8> {
837 let mut body = der(0x06, oid_bytes);
838 if critical {
839 body.extend_from_slice(&[0x01, 0x01, 0xFF]);
840 }
841 body.extend_from_slice(octet_string_tlv);
842 der(0x30, &body)
843 }
844
845 pub fn mint(
849 issuer_key: &Sm2PrivateKey,
850 issuer_name: &[u8],
851 subject_name: &[u8],
852 subject_key: &Sm2PublicKey,
853 exts: &[u8],
854 not_before: &str,
855 not_after: &str,
856 ) -> Vec<u8> {
857 let algid = der(0x30, &der(0x06, crate::asn1::oid::SM2_SIGN_WITH_SM3));
858 let mut tbs_body = der(0xA0, &der(0x02, &[0x02])); tbs_body.extend_from_slice(&der(0x02, &[0x01])); tbs_body.extend_from_slice(&algid);
861 tbs_body.extend_from_slice(issuer_name);
862 let validity = der(
863 0x30,
864 &[
865 der(0x17, not_before.as_bytes()),
866 der(0x17, not_after.as_bytes()),
867 ]
868 .concat(),
869 );
870 tbs_body.extend_from_slice(&validity);
871 tbs_body.extend_from_slice(subject_name);
872 tbs_body.extend_from_slice(&crate::spki::encode(subject_key));
873 if !exts.is_empty() {
874 tbs_body.extend_from_slice(&der(0xA3, &der(0x30, exts)));
875 }
876 let tbs = der(0x30, &tbs_body);
877 let sig = sign_with_id(issuer_key, DEFAULT_SIGNER_ID, &tbs, &mut SysRng).expect("sign tbs");
878 let mut sig_bs = alloc::vec![0u8]; sig_bs.extend_from_slice(&sig);
880 let mut cert = tbs;
881 cert.extend_from_slice(&algid);
882 cert.extend_from_slice(&der(0x03, &sig_bs));
883 der(0x30, &cert)
884 }
885
886 pub fn cert(
888 issuer_key: &Sm2PrivateKey,
889 issuer_name: &[u8],
890 subject_name: &[u8],
891 subject_key: &Sm2PublicKey,
892 exts: &[u8],
893 ) -> super::Certificate {
894 let der_bytes = mint(
895 issuer_key,
896 issuer_name,
897 subject_name,
898 subject_key,
899 exts,
900 "260101000000Z",
901 "270101000000Z",
902 );
903 super::Certificate::from_der(&der_bytes).expect("minted cert parses")
904 }
905}
906
907#[cfg(test)]
908mod v1_8_tests {
909 use super::test_support::*;
910 use super::*;
911 use alloc::vec::Vec;
912
913 #[test]
916 fn keyusage_bit_order() {
917 let k = KeyUsage::parse(&[0x03, 0x02, 0x05, 0xA0]).unwrap();
919 assert!(k.digital_signature() && k.key_encipherment());
920 assert!(!k.content_commitment() && !k.key_agreement() && !k.key_cert_sign());
921 let k2 = KeyUsage::parse(&[0x03, 0x03, 0x07, 0x80, 0x80]).unwrap();
923 assert!(k2.digital_signature() && k2.decipher_only());
924 assert!(KeyUsage::parse(&[0x03, 0x02, 0x05, 0xA0, 0x00]).is_none());
926 assert!(KeyUsage::parse(&[0x03, 0x02, 0x08, 0xA0]).is_none());
927 }
928
929 #[test]
930 fn basicconstraints_reader() {
931 let ca = BasicConstraints::parse(&[0x30, 0x03, 0x01, 0x01, 0xFF]).unwrap();
932 assert!(ca.is_ca && ca.path_len.is_none());
933 let ca_pl =
934 BasicConstraints::parse(&[0x30, 0x06, 0x01, 0x01, 0xFF, 0x02, 0x01, 0x00]).unwrap();
935 assert!(ca_pl.is_ca && ca_pl.path_len == Some(0));
936 let empty = BasicConstraints::parse(&[0x30, 0x00]).unwrap();
937 assert!(!empty.is_ca && empty.path_len.is_none());
938 assert!(BasicConstraints::parse(&[0x30, 0x03, 0x01, 0x01, 0xFF, 0x00]).is_none());
940 }
941
942 #[test]
943 fn extension_helpers() {
944 let known: &[&[u8]] = &[oid::KEY_USAGE, oid::BASIC_CONSTRAINTS];
945 let ku = ku_ext(&[0], true);
946 let unknown_crit = raw_ext(&[0x55, 0x1d, 0x25], true, &[0x05, 0x00]); let unknown_noncrit = raw_ext(&[0x55, 0x1d, 0x25], false, &[0x05, 0x00]);
948 let with_crit = der(0x30, &[ku.clone(), unknown_crit].concat());
949 let with_noncrit = der(0x30, &[ku, unknown_noncrit].concat());
950 assert!(find_extension(&with_crit, oid::KEY_USAGE).is_some());
951 assert!(find_extension(&with_crit, oid::BASIC_CONSTRAINTS).is_none());
952 assert!(has_unknown_critical(&with_crit, known));
953 assert!(!has_unknown_critical(&with_noncrit, known));
954 }
955
956 fn trio() -> (Certificate, Certificate, Certificate) {
960 let (rk, ik, lk) = (key(1), key(2), key(3));
961 let (rn, in_, ln) = (name(b"root"), name(b"int"), name(b"leaf"));
962 let ca_exts = [ku_ext(&[5], true), bc_ext(true, None, true)].concat();
963 let root = cert(&rk, &rn, &rn, &rk.public_key(), &ca_exts);
964 let int = cert(&rk, &rn, &in_, &ik.public_key(), &ca_exts);
965 let leaf = cert(&ik, &in_, &ln, &lk.public_key(), &ku_ext(&[0], true));
966 (leaf, int, root)
967 }
968
969 #[test]
970 fn valid_chain_to_anchor() {
971 let (leaf, int, root) = trio();
972 assert!(verify_chain(&[leaf, int], &[root], None));
973 }
974
975 #[test]
976 fn wrong_signing_key_rejected() {
977 let (rk, ik, lk) = (key(1), key(2), key(3));
979 let (rn, in_, ln) = (name(b"root"), name(b"int"), name(b"leaf"));
980 let ca_exts = [ku_ext(&[5], true), bc_ext(true, None, true)].concat();
981 let root = cert(&rk, &rn, &rn, &rk.public_key(), &ca_exts);
982 let int = cert(&rk, &rn, &in_, &ik.public_key(), &ca_exts);
983 let bad_leaf = cert(&rk, &in_, &ln, &lk.public_key(), &ku_ext(&[0], true));
984 assert!(!verify_chain(&[bad_leaf, int], &[root], None));
985 }
986
987 #[test]
988 fn non_ca_intermediate_rejected() {
989 let (rk, ik, lk) = (key(1), key(2), key(3));
990 let (rn, in_, ln) = (name(b"root"), name(b"int"), name(b"leaf"));
991 let ca_exts = [ku_ext(&[5], true), bc_ext(true, None, true)].concat();
992 let root = cert(&rk, &rn, &rn, &rk.public_key(), &ca_exts);
993 let int = cert(&rk, &rn, &in_, &ik.public_key(), &ku_ext(&[5], true));
995 let leaf = cert(&ik, &in_, &ln, &lk.public_key(), &ku_ext(&[0], true));
996 assert!(!verify_chain(&[leaf, int], &[root], None));
997 }
998
999 #[test]
1000 fn broken_name_link_rejected() {
1001 let (rk, ik, lk) = (key(1), key(2), key(3));
1002 let (rn, in_, ln) = (name(b"root"), name(b"int"), name(b"leaf"));
1003 let ca_exts = [ku_ext(&[5], true), bc_ext(true, None, true)].concat();
1004 let root = cert(&rk, &rn, &rn, &rk.public_key(), &ca_exts);
1005 let int = cert(&rk, &rn, &in_, &ik.public_key(), &ca_exts);
1006 let leaf = cert(
1008 &ik,
1009 &name(b"other"),
1010 &ln,
1011 &lk.public_key(),
1012 &ku_ext(&[0], true),
1013 );
1014 assert!(!verify_chain(&[leaf, int], &[root], None));
1015 }
1016
1017 #[test]
1018 fn over_max_depth_rejected() {
1019 let chain: Vec<Certificate> = (0..=MAX_CHAIN_DEPTH)
1022 .map(|i| {
1023 let k = key(u8::try_from(i + 1).unwrap());
1024 let n = name(b"x");
1025 cert(&k, &n, &n, &k.public_key(), &ku_ext(&[0], true))
1026 })
1027 .collect();
1028 assert!(chain.len() > MAX_CHAIN_DEPTH);
1029 assert!(!verify_chain(&chain, &[], None));
1030 }
1031
1032 #[test]
1033 fn time_window_enforced() {
1034 let (leaf, int, root) = trio();
1035 let nb = leaf.not_before();
1036 let after = X509Time {
1037 year: leaf.not_after().year + 1,
1038 ..leaf.not_after()
1039 };
1040 let chain = [leaf, int];
1041 let anchors = [root];
1042 assert!(verify_chain(&chain, &anchors, Some(nb)));
1043 assert!(!verify_chain(&chain, &anchors, Some(after)));
1044 }
1045
1046 #[test]
1047 fn try_all_anchors_second_valid() {
1048 let (rk, ik, lk) = (key(1), key(2), key(3));
1049 let decoy = key(9);
1050 let (rn, in_, ln) = (name(b"root"), name(b"int"), name(b"leaf"));
1051 let ca_exts = [ku_ext(&[5], true), bc_ext(true, None, true)].concat();
1052 let real_root = cert(&rk, &rn, &rn, &rk.public_key(), &ca_exts);
1053 let decoy_root = cert(&decoy, &rn, &rn, &decoy.public_key(), &ca_exts); let int = cert(&rk, &rn, &in_, &ik.public_key(), &ca_exts);
1055 let leaf = cert(&ik, &in_, &ln, &lk.public_key(), &ku_ext(&[0], true));
1056 let chain = [leaf, int];
1057 assert!(verify_chain(&chain, &[decoy_root, real_root], None));
1059 let decoy_only = cert(&decoy, &rn, &rn, &decoy.public_key(), &ca_exts);
1060 assert!(!verify_chain(&chain, &[decoy_only], None));
1061 }
1062
1063 #[test]
1064 fn unknown_critical_extension_rejected() {
1065 let (rk, ik, lk) = (key(1), key(2), key(3));
1066 let (rn, in_, ln) = (name(b"root"), name(b"int"), name(b"leaf"));
1067 let ca_exts = [ku_ext(&[5], true), bc_ext(true, None, true)].concat();
1068 let root = cert(&rk, &rn, &rn, &rk.public_key(), &ca_exts);
1069 let int = cert(&rk, &rn, &in_, &ik.public_key(), &ca_exts);
1070 let anchors = [root];
1071 let crit = [
1073 ku_ext(&[0], true),
1074 raw_ext(&[0x55, 0x1d, 0x25], true, &[0x05, 0x00]),
1075 ]
1076 .concat();
1077 let leaf_crit = cert(&ik, &in_, &ln, &lk.public_key(), &crit);
1078 let int2 = cert(&rk, &rn, &in_, &ik.public_key(), &ca_exts);
1079 assert!(!verify_chain(&[leaf_crit, int2], &anchors, None));
1080 let noncrit = [
1082 ku_ext(&[0], true),
1083 raw_ext(&[0x55, 0x1d, 0x25], false, &[0x05, 0x00]),
1084 ]
1085 .concat();
1086 let leaf_ok = cert(&ik, &in_, &ln, &lk.public_key(), &noncrit);
1087 assert!(verify_chain(&[leaf_ok, int], &anchors, None));
1088 }
1089
1090 #[test]
1091 fn self_signed_leaf_as_own_anchor() {
1092 let sk = key(7);
1094 let sn = name(b"self");
1095 let leaf = cert(&sk, &sn, &sn, &sk.public_key(), &ku_ext(&[0], true));
1096 let anchor = cert(&sk, &sn, &sn, &sk.public_key(), &ku_ext(&[0], true));
1097 assert!(verify_chain(&[leaf], &[anchor], None));
1098 }
1099}
1100
1101#[cfg(test)]
1102mod tests {
1103 use super::*;
1104 use alloc::vec::Vec;
1105
1106 fn tlv(tag: u8, content: &[u8]) -> Vec<u8> {
1107 assert!(content.len() < 128, "test helper: short-form lengths only");
1108 let mut out = alloc::vec![tag, u8::try_from(content.len()).unwrap()];
1109 out.extend_from_slice(content);
1110 out
1111 }
1112
1113 fn utc(s: &str) -> Vec<u8> {
1116 tlv(TAG_UTC_TIME, s.as_bytes())
1117 }
1118 fn gtime(s: &str) -> Vec<u8> {
1119 tlv(TAG_GENERALIZED_TIME, s.as_bytes())
1120 }
1121
1122 #[test]
1123 fn time_utctime_parses() {
1124 let der = utc("260611120000Z");
1125 let (t, rest) = read_time(&der).unwrap();
1126 assert!(rest.is_empty());
1127 assert_eq!(
1128 t,
1129 X509Time {
1130 year: 2026,
1131 month: 6,
1132 day: 11,
1133 hour: 12,
1134 minute: 0,
1135 second: 0
1136 }
1137 );
1138 }
1139
1140 #[test]
1141 fn time_utctime_pivot() {
1142 assert_eq!(read_time(&utc("500101000000Z")).unwrap().0.year, 1950);
1143 assert_eq!(read_time(&utc("490101000000Z")).unwrap().0.year, 2049);
1144 }
1145
1146 #[test]
1147 fn time_generalizedtime_parses() {
1148 let (t, _) = read_time(>ime("20991231235959Z")).unwrap();
1149 assert_eq!(
1150 t,
1151 X509Time {
1152 year: 2099,
1153 month: 12,
1154 day: 31,
1155 hour: 23,
1156 minute: 59,
1157 second: 59
1158 }
1159 );
1160 }
1161
1162 #[test]
1163 fn time_ordering_is_chronological() {
1164 let (a, _) = read_time(&utc("260611120000Z")).unwrap();
1165 let (b, _) = read_time(&utc("260611120001Z")).unwrap();
1166 let (c, _) = read_time(>ime("20991231235959Z")).unwrap();
1167 assert!(a < b && b < c);
1168 }
1169
1170 #[test]
1171 fn time_rejects_malformed() {
1172 for bad in [
1173 utc("260611120000"), utc("2606111200000"), utc("26061112000xZ"), utc("261311120000Z"), utc("260600120000Z"), utc("260611240000Z"), utc("260611126000Z"), utc("260611120060Z"), gtime("20260611120000+0800Z"), gtime("2026061112000.5Z"), tlv(0x16, b"260611120000Z"), ] {
1185 assert!(read_time(&bad).is_none(), "accepted {bad:02x?}");
1186 }
1187 }
1188
1189 fn algid(params_null: bool) -> Vec<u8> {
1192 let mut body = tlv(0x06, oid::SM2_SIGN_WITH_SM3);
1195 if params_null {
1196 body.extend_from_slice(&[0x05, 0x00]);
1197 }
1198 tlv(0x30, &body)
1199 }
1200
1201 #[test]
1202 fn algid_absent_and_null_params_accepted() {
1203 for null in [false, true] {
1204 let a = algid(null);
1205 let (span, rest) = read_sm2_sig_algid(&a).expect("valid algid rejected");
1206 assert_eq!(span, &a[..]);
1207 assert!(rest.is_empty());
1208 }
1209 }
1210
1211 #[test]
1212 fn algid_mixed_forms_are_unequal_spans() {
1213 let absent = algid(false);
1216 let null = algid(true);
1217 let (s1, _) = read_sm2_sig_algid(&absent).unwrap();
1218 let (s2, _) = read_sm2_sig_algid(&null).unwrap();
1219 assert_ne!(s1, s2);
1220 }
1221
1222 #[test]
1223 fn algid_rejects_wrong_oid_and_bad_params() {
1224 let wrong = tlv(
1226 0x30,
1227 &tlv(0x06, &[0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02]),
1228 );
1229 assert!(read_sm2_sig_algid(&wrong).is_none());
1230 let mut body = tlv(0x06, oid::SM2_SIGN_WITH_SM3);
1232 body.extend_from_slice(&[0x30, 0x00]);
1233 assert!(read_sm2_sig_algid(&tlv(0x30, &body)).is_none());
1234 let mut body = tlv(0x06, oid::SM2_SIGN_WITH_SM3);
1236 body.extend_from_slice(&[0x05, 0x00, 0x00]);
1237 assert!(read_sm2_sig_algid(&tlv(0x30, &body)).is_none());
1238 }
1239
1240 fn extension(oid_content: &[u8], critical: Option<u8>, value: &[u8]) -> Vec<u8> {
1243 let mut body = tlv(0x06, oid_content);
1244 if let Some(b) = critical {
1245 body.extend_from_slice(&tlv(TAG_BOOLEAN, &[b]));
1246 }
1247 body.extend_from_slice(&tlv(0x04, value));
1248 tlv(0x30, &body)
1249 }
1250
1251 #[test]
1252 fn extensions_shape_ok() {
1253 let e1 = extension(&[0x55, 0x1d, 0x0f], Some(0xFF), &[0x03, 0x02, 0x01, 0x06]);
1254 let e2 = extension(&[0x55, 0x1d, 0x13], None, &[0x30, 0x00]);
1255 let mut both = e1;
1256 both.extend_from_slice(&e2);
1257 assert!(check_extensions_shape(&tlv(0x30, &both)).is_some());
1258 }
1259
1260 #[test]
1261 fn extensions_shape_rejects() {
1262 assert!(check_extensions_shape(&tlv(0x30, &[])).is_none());
1264 assert!(check_extensions_shape(&tlv(0x30, &tlv(0x04, &[0x00]))).is_none());
1266 let mut bad = tlv(0x06, &[0x55, 0x1d, 0x0f]);
1268 bad.extend_from_slice(&tlv(0x04, &[0x00]));
1269 bad.push(0x00);
1270 assert!(check_extensions_shape(&tlv(0x30, &tlv(0x30, &bad))).is_none());
1271 let ok = extension(&[0x55, 0x1d, 0x0f], None, &[0x00]);
1273 let mut outer = tlv(0x30, &ok);
1274 outer.push(0x00);
1275 assert!(check_extensions_shape(&outer).is_none());
1276 }
1277}