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}
288
289#[derive(Clone, Copy, Debug, PartialEq, Eq)]
295pub struct BasicConstraints {
296 pub is_ca: bool,
298 pub path_len: Option<u32>,
300}
301
302impl BasicConstraints {
303 fn parse(seq_tlv: &[u8]) -> Option<Self> {
307 let (content, rest) = reader::read_sequence(seq_tlv)?;
308 if !rest.is_empty() {
309 return None;
310 }
311 let (is_ca, after) = match reader::read_tlv(content, TAG_BOOLEAN) {
312 Some((b, r)) => {
313 if b.len() != 1 {
314 return None;
315 }
316 (b[0] != 0, r)
317 }
318 None => (false, content),
319 };
320 let path_len = if after.is_empty() {
321 None
322 } else {
323 let (int, r) = reader::read_integer(after)?;
324 if !r.is_empty() || int.len() > 4 {
325 return None;
326 }
327 let mut v = 0u32;
328 for &byte in int {
329 v = (v << 8) | u32::from(byte);
330 }
331 Some(v)
332 };
333 Some(Self { is_ca, path_len })
334 }
335}
336
337fn find_extension<'a>(ext_tlv: &'a [u8], extn_id: &[u8]) -> Option<&'a [u8]> {
343 let (seq, _) = reader::read_sequence(ext_tlv)?;
344 let mut exts = seq;
345 while !exts.is_empty() {
346 let ext = next_extension(exts)?;
347 if ext.oid == extn_id {
348 return Some(ext.value);
349 }
350 exts = ext.rest;
351 }
352 None
353}
354
355fn has_unknown_critical(ext_tlv: &[u8], known: &[&[u8]]) -> bool {
360 let Some((seq, _)) = reader::read_sequence(ext_tlv) else {
361 return false;
362 };
363 let mut exts = seq;
364 while !exts.is_empty() {
365 let Some(ext) = next_extension(exts) else {
366 return false;
367 };
368 if ext.critical && !known.contains(&ext.oid) {
369 return true;
370 }
371 exts = ext.rest;
372 }
373 false
374}
375
376pub struct Certificate {
383 tbs: Vec<u8>,
384 serial: Vec<u8>,
385 issuer: Vec<u8>,
386 subject: Vec<u8>,
387 extensions: Option<Vec<u8>>,
388 sig: Vec<u8>,
389 not_before: X509Time,
390 not_after: X509Time,
391 subject_key: Sm2PublicKey,
392}
393
394impl Certificate {
395 #[must_use]
403 pub fn from_der(der: &[u8]) -> Option<Self> {
404 let (cert, rest) = reader::read_sequence(der)?;
405 if !rest.is_empty() {
406 return None;
407 }
408
409 let (tbs_content, after_tbs) = reader::read_sequence(cert)?;
412 let tbs_span = &cert[..cert.len() - after_tbs.len()];
413
414 let (ver_content, cur) = reader::read_context_tagged_explicit(tbs_content, 0)?;
418 let (ver_int, ver_rest) = reader::read_integer(ver_content)?;
419 if ver_int != [2] || !ver_rest.is_empty() {
420 return None;
421 }
422
423 let (serial, cur) = reader::read_integer(cur)?;
428 if serial.is_empty() || serial.len() > 20 {
429 return None;
430 }
431
432 let (algid_inner, cur) = read_sm2_sig_algid(cur)?;
435
436 let (_, after_issuer) = reader::read_sequence(cur)?;
438 let issuer = &cur[..cur.len() - after_issuer.len()];
439 let cur = after_issuer;
440
441 let (val_content, cur) = reader::read_sequence(cur)?;
443 let (not_before, val_rest) = read_time(val_content)?;
444 let (not_after, val_rest) = read_time(val_rest)?;
445 if !val_rest.is_empty() {
446 return None;
447 }
448
449 let (_, after_subject) = reader::read_sequence(cur)?;
451 let subject = &cur[..cur.len() - after_subject.len()];
452 let cur = after_subject;
453
454 let (_, after_spki) = reader::read_sequence(cur)?;
458 let spki_span = &cur[..cur.len() - after_spki.len()];
459 let subject_key = crate::spki::decode(spki_span)?;
460 let cur = after_spki;
461
462 let cur = match reader::read_context_tagged_implicit(cur, 1) {
464 Some((_, r)) => r,
465 None => cur,
466 };
467 let cur = match reader::read_context_tagged_implicit(cur, 2) {
468 Some((_, r)) => r,
469 None => cur,
470 };
471
472 let (extensions, cur) = match reader::read_context_tagged_explicit(cur, 3) {
475 Some((ext_content, r)) => {
476 check_extensions_shape(ext_content)?;
477 (Some(ext_content), r)
478 }
479 None => (None, cur),
480 };
481 if !cur.is_empty() {
483 return None;
484 }
485
486 let (algid_outer, after_alg) = read_sm2_sig_algid(after_tbs)?;
490 if algid_outer != algid_inner {
491 return None;
492 }
493
494 let (unused, sig, after_sig) = reader::read_bit_string(after_alg)?;
499 if unused != 0 || !after_sig.is_empty() {
500 return None;
501 }
502
503 Some(Self {
504 tbs: tbs_span.to_vec(),
505 serial: serial.to_vec(),
506 issuer: issuer.to_vec(),
507 subject: subject.to_vec(),
508 extensions: extensions.map(<[u8]>::to_vec),
509 sig: sig.to_vec(),
510 not_before,
511 not_after,
512 subject_key,
513 })
514 }
515
516 #[must_use]
525 pub fn verify_signature(&self, issuer: &Sm2PublicKey) -> bool {
526 self.verify_signature_with_id(issuer, DEFAULT_SIGNER_ID)
527 }
528
529 #[must_use]
532 pub fn verify_signature_with_id(&self, issuer: &Sm2PublicKey, id: &[u8]) -> bool {
533 verify_with_id(issuer, id, &self.tbs, &self.sig)
534 }
535
536 #[must_use]
539 pub const fn subject_public_key(&self) -> Sm2PublicKey {
540 self.subject_key
541 }
542
543 #[must_use]
546 pub fn tbs_raw(&self) -> &[u8] {
547 &self.tbs
548 }
549
550 #[must_use]
554 pub fn serial_raw(&self) -> &[u8] {
555 &self.serial
556 }
557
558 #[must_use]
561 pub fn issuer_raw(&self) -> &[u8] {
562 &self.issuer
563 }
564
565 #[must_use]
567 pub fn subject_raw(&self) -> &[u8] {
568 &self.subject
569 }
570
571 #[must_use]
577 pub fn extensions_raw(&self) -> Option<&[u8]> {
578 self.extensions.as_deref()
579 }
580
581 #[must_use]
584 pub const fn not_before(&self) -> X509Time {
585 self.not_before
586 }
587
588 #[must_use]
590 pub const fn not_after(&self) -> X509Time {
591 self.not_after
592 }
593
594 #[must_use]
600 pub fn is_self_issued(&self) -> bool {
601 self.issuer == self.subject
602 }
603
604 #[must_use]
608 pub fn key_usage(&self) -> Option<KeyUsage> {
609 KeyUsage::parse(find_extension(self.extensions.as_deref()?, oid::KEY_USAGE)?)
610 }
611
612 #[must_use]
616 pub fn basic_constraints(&self) -> Option<BasicConstraints> {
617 BasicConstraints::parse(find_extension(
618 self.extensions.as_deref()?,
619 oid::BASIC_CONSTRAINTS,
620 )?)
621 }
622
623 #[cfg(feature = "tlcp")]
630 pub(crate) fn subject_is_empty(&self) -> bool {
631 reader::read_sequence(&self.subject).is_none_or(|(content, _)| content.is_empty())
632 }
633}
634
635pub const MAX_CHAIN_DEPTH: usize = 8;
641
642const KNOWN_EXTS: &[&[u8]] = &[oid::KEY_USAGE, oid::BASIC_CONSTRAINTS];
645
646fn within_window(cert: &Certificate, at: Option<X509Time>) -> bool {
647 at.is_none_or(|t| cert.not_before <= t && t <= cert.not_after)
648}
649
650fn is_ca_issuer(cert: &Certificate) -> bool {
654 cert.basic_constraints().is_some_and(|bc| bc.is_ca)
655 && cert.key_usage().is_some_and(KeyUsage::key_cert_sign)
656}
657
658#[must_use]
682pub fn verify_chain(
683 chain: &[Certificate],
684 anchors: &[Certificate],
685 at_time: Option<X509Time>,
686) -> bool {
687 if chain.is_empty() || chain.len() > MAX_CHAIN_DEPTH {
688 return false;
689 }
690 for cert in chain {
691 if cert
692 .extensions
693 .as_deref()
694 .is_some_and(|e| has_unknown_critical(e, KNOWN_EXTS))
695 {
696 return false;
697 }
698 if !within_window(cert, at_time) {
699 return false;
700 }
701 }
702 for i in 0..chain.len() - 1 {
704 let (subj, iss) = (&chain[i], &chain[i + 1]);
705 if subj.issuer_raw() != iss.subject_raw() {
706 return false;
707 }
708 if !subj.verify_signature(&iss.subject_public_key()) {
709 return false;
710 }
711 if !is_ca_issuer(iss) {
712 return false;
713 }
714 }
715 let top = &chain[chain.len() - 1];
719 anchors.iter().any(|a| {
720 a.subject_raw() == top.issuer_raw()
721 && within_window(a, at_time)
722 && top.verify_signature(&a.subject_public_key())
723 })
724}
725
726#[cfg(test)]
730pub(crate) mod test_support {
731 use crate::sm2::{DEFAULT_SIGNER_ID, Sm2PrivateKey, Sm2PublicKey, sign_with_id};
732 use alloc::vec::Vec;
733 use getrandom::SysRng;
734
735 #[allow(clippy::cast_possible_truncation)]
737 pub fn der(tag: u8, content: &[u8]) -> Vec<u8> {
738 let mut out = alloc::vec![tag];
739 let n = content.len();
740 if n < 128 {
741 out.push(n as u8);
742 } else {
743 let mut len_bytes = Vec::new();
744 let mut v = n;
745 while v > 0 {
746 len_bytes.push((v & 0xff) as u8);
747 v >>= 8;
748 }
749 len_bytes.reverse();
750 out.push(0x80 | len_bytes.len() as u8);
751 out.extend_from_slice(&len_bytes);
752 }
753 out.extend_from_slice(content);
754 out
755 }
756
757 pub fn name(label: &[u8]) -> Vec<u8> {
760 der(0x30, label)
761 }
762
763 pub fn key(seed: u8) -> Sm2PrivateKey {
765 let mut b = [0u8; 32];
766 b[31] = seed.max(1);
767 Option::from(Sm2PrivateKey::from_bytes_be(&b)).expect("valid test scalar")
768 }
769
770 pub fn ku_ext(bits: &[u8], critical: bool) -> Vec<u8> {
772 let mut val = [0u8; 2];
773 for &b in bits {
774 val[(b / 8) as usize] |= 1 << (7 - (b % 8));
775 }
776 let nbytes = usize::from(bits.iter().any(|&b| b >= 8)) + 1;
777 let mut bs = alloc::vec![0u8]; bs.extend_from_slice(&val[..nbytes]);
779 extension(
780 crate::asn1::oid::KEY_USAGE,
781 critical,
782 &der(0x04, &der(0x03, &bs)),
783 )
784 }
785
786 #[allow(clippy::cast_possible_truncation)]
788 pub fn bc_ext(is_ca: bool, path_len: Option<u32>, critical: bool) -> Vec<u8> {
789 let mut seq = Vec::new();
790 if is_ca {
791 seq.extend_from_slice(&[0x01, 0x01, 0xFF]);
792 }
793 if let Some(p) = path_len {
794 seq.extend_from_slice(&der(0x02, &[p as u8]));
795 }
796 extension(
797 crate::asn1::oid::BASIC_CONSTRAINTS,
798 critical,
799 &der(0x04, &der(0x30, &seq)),
800 )
801 }
802
803 pub fn raw_ext(oid_bytes: &[u8], critical: bool, value_inner: &[u8]) -> Vec<u8> {
805 extension(oid_bytes, critical, &der(0x04, value_inner))
806 }
807
808 fn extension(oid_bytes: &[u8], critical: bool, octet_string_tlv: &[u8]) -> Vec<u8> {
809 let mut body = der(0x06, oid_bytes);
810 if critical {
811 body.extend_from_slice(&[0x01, 0x01, 0xFF]);
812 }
813 body.extend_from_slice(octet_string_tlv);
814 der(0x30, &body)
815 }
816
817 pub fn mint(
821 issuer_key: &Sm2PrivateKey,
822 issuer_name: &[u8],
823 subject_name: &[u8],
824 subject_key: &Sm2PublicKey,
825 exts: &[u8],
826 not_before: &str,
827 not_after: &str,
828 ) -> Vec<u8> {
829 let algid = der(0x30, &der(0x06, crate::asn1::oid::SM2_SIGN_WITH_SM3));
830 let mut tbs_body = der(0xA0, &der(0x02, &[0x02])); tbs_body.extend_from_slice(&der(0x02, &[0x01])); tbs_body.extend_from_slice(&algid);
833 tbs_body.extend_from_slice(issuer_name);
834 let validity = der(
835 0x30,
836 &[
837 der(0x17, not_before.as_bytes()),
838 der(0x17, not_after.as_bytes()),
839 ]
840 .concat(),
841 );
842 tbs_body.extend_from_slice(&validity);
843 tbs_body.extend_from_slice(subject_name);
844 tbs_body.extend_from_slice(&crate::spki::encode(subject_key));
845 if !exts.is_empty() {
846 tbs_body.extend_from_slice(&der(0xA3, &der(0x30, exts)));
847 }
848 let tbs = der(0x30, &tbs_body);
849 let sig = sign_with_id(issuer_key, DEFAULT_SIGNER_ID, &tbs, &mut SysRng).expect("sign tbs");
850 let mut sig_bs = alloc::vec![0u8]; sig_bs.extend_from_slice(&sig);
852 let mut cert = tbs;
853 cert.extend_from_slice(&algid);
854 cert.extend_from_slice(&der(0x03, &sig_bs));
855 der(0x30, &cert)
856 }
857
858 pub fn cert(
860 issuer_key: &Sm2PrivateKey,
861 issuer_name: &[u8],
862 subject_name: &[u8],
863 subject_key: &Sm2PublicKey,
864 exts: &[u8],
865 ) -> super::Certificate {
866 let der_bytes = mint(
867 issuer_key,
868 issuer_name,
869 subject_name,
870 subject_key,
871 exts,
872 "260101000000Z",
873 "270101000000Z",
874 );
875 super::Certificate::from_der(&der_bytes).expect("minted cert parses")
876 }
877}
878
879#[cfg(test)]
880mod v1_8_tests {
881 use super::test_support::*;
882 use super::*;
883 use alloc::vec::Vec;
884
885 #[test]
888 fn keyusage_bit_order() {
889 let k = KeyUsage::parse(&[0x03, 0x02, 0x05, 0xA0]).unwrap();
891 assert!(k.digital_signature() && k.key_encipherment());
892 assert!(!k.content_commitment() && !k.key_agreement() && !k.key_cert_sign());
893 let k2 = KeyUsage::parse(&[0x03, 0x03, 0x07, 0x80, 0x80]).unwrap();
895 assert!(k2.digital_signature() && k2.decipher_only());
896 assert!(KeyUsage::parse(&[0x03, 0x02, 0x05, 0xA0, 0x00]).is_none());
898 assert!(KeyUsage::parse(&[0x03, 0x02, 0x08, 0xA0]).is_none());
899 }
900
901 #[test]
902 fn basicconstraints_reader() {
903 let ca = BasicConstraints::parse(&[0x30, 0x03, 0x01, 0x01, 0xFF]).unwrap();
904 assert!(ca.is_ca && ca.path_len.is_none());
905 let ca_pl =
906 BasicConstraints::parse(&[0x30, 0x06, 0x01, 0x01, 0xFF, 0x02, 0x01, 0x00]).unwrap();
907 assert!(ca_pl.is_ca && ca_pl.path_len == Some(0));
908 let empty = BasicConstraints::parse(&[0x30, 0x00]).unwrap();
909 assert!(!empty.is_ca && empty.path_len.is_none());
910 assert!(BasicConstraints::parse(&[0x30, 0x03, 0x01, 0x01, 0xFF, 0x00]).is_none());
912 }
913
914 #[test]
915 fn extension_helpers() {
916 let known: &[&[u8]] = &[oid::KEY_USAGE, oid::BASIC_CONSTRAINTS];
917 let ku = ku_ext(&[0], true);
918 let unknown_crit = raw_ext(&[0x55, 0x1d, 0x25], true, &[0x05, 0x00]); let unknown_noncrit = raw_ext(&[0x55, 0x1d, 0x25], false, &[0x05, 0x00]);
920 let with_crit = der(0x30, &[ku.clone(), unknown_crit].concat());
921 let with_noncrit = der(0x30, &[ku, unknown_noncrit].concat());
922 assert!(find_extension(&with_crit, oid::KEY_USAGE).is_some());
923 assert!(find_extension(&with_crit, oid::BASIC_CONSTRAINTS).is_none());
924 assert!(has_unknown_critical(&with_crit, known));
925 assert!(!has_unknown_critical(&with_noncrit, known));
926 }
927
928 fn trio() -> (Certificate, Certificate, Certificate) {
932 let (rk, ik, lk) = (key(1), key(2), key(3));
933 let (rn, in_, ln) = (name(b"root"), name(b"int"), name(b"leaf"));
934 let ca_exts = [ku_ext(&[5], true), bc_ext(true, None, true)].concat();
935 let root = cert(&rk, &rn, &rn, &rk.public_key(), &ca_exts);
936 let int = cert(&rk, &rn, &in_, &ik.public_key(), &ca_exts);
937 let leaf = cert(&ik, &in_, &ln, &lk.public_key(), &ku_ext(&[0], true));
938 (leaf, int, root)
939 }
940
941 #[test]
942 fn valid_chain_to_anchor() {
943 let (leaf, int, root) = trio();
944 assert!(verify_chain(&[leaf, int], &[root], None));
945 }
946
947 #[test]
948 fn wrong_signing_key_rejected() {
949 let (rk, ik, lk) = (key(1), key(2), key(3));
951 let (rn, in_, ln) = (name(b"root"), name(b"int"), name(b"leaf"));
952 let ca_exts = [ku_ext(&[5], true), bc_ext(true, None, true)].concat();
953 let root = cert(&rk, &rn, &rn, &rk.public_key(), &ca_exts);
954 let int = cert(&rk, &rn, &in_, &ik.public_key(), &ca_exts);
955 let bad_leaf = cert(&rk, &in_, &ln, &lk.public_key(), &ku_ext(&[0], true));
956 assert!(!verify_chain(&[bad_leaf, int], &[root], None));
957 }
958
959 #[test]
960 fn non_ca_intermediate_rejected() {
961 let (rk, ik, lk) = (key(1), key(2), key(3));
962 let (rn, in_, ln) = (name(b"root"), name(b"int"), name(b"leaf"));
963 let ca_exts = [ku_ext(&[5], true), bc_ext(true, None, true)].concat();
964 let root = cert(&rk, &rn, &rn, &rk.public_key(), &ca_exts);
965 let int = cert(&rk, &rn, &in_, &ik.public_key(), &ku_ext(&[5], true));
967 let leaf = cert(&ik, &in_, &ln, &lk.public_key(), &ku_ext(&[0], true));
968 assert!(!verify_chain(&[leaf, int], &[root], None));
969 }
970
971 #[test]
972 fn broken_name_link_rejected() {
973 let (rk, ik, lk) = (key(1), key(2), key(3));
974 let (rn, in_, ln) = (name(b"root"), name(b"int"), name(b"leaf"));
975 let ca_exts = [ku_ext(&[5], true), bc_ext(true, None, true)].concat();
976 let root = cert(&rk, &rn, &rn, &rk.public_key(), &ca_exts);
977 let int = cert(&rk, &rn, &in_, &ik.public_key(), &ca_exts);
978 let leaf = cert(
980 &ik,
981 &name(b"other"),
982 &ln,
983 &lk.public_key(),
984 &ku_ext(&[0], true),
985 );
986 assert!(!verify_chain(&[leaf, int], &[root], None));
987 }
988
989 #[test]
990 fn over_max_depth_rejected() {
991 let chain: Vec<Certificate> = (0..=MAX_CHAIN_DEPTH)
994 .map(|i| {
995 let k = key(u8::try_from(i + 1).unwrap());
996 let n = name(b"x");
997 cert(&k, &n, &n, &k.public_key(), &ku_ext(&[0], true))
998 })
999 .collect();
1000 assert!(chain.len() > MAX_CHAIN_DEPTH);
1001 assert!(!verify_chain(&chain, &[], None));
1002 }
1003
1004 #[test]
1005 fn time_window_enforced() {
1006 let (leaf, int, root) = trio();
1007 let nb = leaf.not_before();
1008 let after = X509Time {
1009 year: leaf.not_after().year + 1,
1010 ..leaf.not_after()
1011 };
1012 let chain = [leaf, int];
1013 let anchors = [root];
1014 assert!(verify_chain(&chain, &anchors, Some(nb)));
1015 assert!(!verify_chain(&chain, &anchors, Some(after)));
1016 }
1017
1018 #[test]
1019 fn try_all_anchors_second_valid() {
1020 let (rk, ik, lk) = (key(1), key(2), key(3));
1021 let decoy = key(9);
1022 let (rn, in_, ln) = (name(b"root"), name(b"int"), name(b"leaf"));
1023 let ca_exts = [ku_ext(&[5], true), bc_ext(true, None, true)].concat();
1024 let real_root = cert(&rk, &rn, &rn, &rk.public_key(), &ca_exts);
1025 let decoy_root = cert(&decoy, &rn, &rn, &decoy.public_key(), &ca_exts); let int = cert(&rk, &rn, &in_, &ik.public_key(), &ca_exts);
1027 let leaf = cert(&ik, &in_, &ln, &lk.public_key(), &ku_ext(&[0], true));
1028 let chain = [leaf, int];
1029 assert!(verify_chain(&chain, &[decoy_root, real_root], None));
1031 let decoy_only = cert(&decoy, &rn, &rn, &decoy.public_key(), &ca_exts);
1032 assert!(!verify_chain(&chain, &[decoy_only], None));
1033 }
1034
1035 #[test]
1036 fn unknown_critical_extension_rejected() {
1037 let (rk, ik, lk) = (key(1), key(2), key(3));
1038 let (rn, in_, ln) = (name(b"root"), name(b"int"), name(b"leaf"));
1039 let ca_exts = [ku_ext(&[5], true), bc_ext(true, None, true)].concat();
1040 let root = cert(&rk, &rn, &rn, &rk.public_key(), &ca_exts);
1041 let int = cert(&rk, &rn, &in_, &ik.public_key(), &ca_exts);
1042 let anchors = [root];
1043 let crit = [
1045 ku_ext(&[0], true),
1046 raw_ext(&[0x55, 0x1d, 0x25], true, &[0x05, 0x00]),
1047 ]
1048 .concat();
1049 let leaf_crit = cert(&ik, &in_, &ln, &lk.public_key(), &crit);
1050 let int2 = cert(&rk, &rn, &in_, &ik.public_key(), &ca_exts);
1051 assert!(!verify_chain(&[leaf_crit, int2], &anchors, None));
1052 let noncrit = [
1054 ku_ext(&[0], true),
1055 raw_ext(&[0x55, 0x1d, 0x25], false, &[0x05, 0x00]),
1056 ]
1057 .concat();
1058 let leaf_ok = cert(&ik, &in_, &ln, &lk.public_key(), &noncrit);
1059 assert!(verify_chain(&[leaf_ok, int], &anchors, None));
1060 }
1061
1062 #[test]
1063 fn self_signed_leaf_as_own_anchor() {
1064 let sk = key(7);
1066 let sn = name(b"self");
1067 let leaf = cert(&sk, &sn, &sn, &sk.public_key(), &ku_ext(&[0], true));
1068 let anchor = cert(&sk, &sn, &sn, &sk.public_key(), &ku_ext(&[0], true));
1069 assert!(verify_chain(&[leaf], &[anchor], None));
1070 }
1071}
1072
1073#[cfg(test)]
1074mod tests {
1075 use super::*;
1076 use alloc::vec::Vec;
1077
1078 fn tlv(tag: u8, content: &[u8]) -> Vec<u8> {
1079 assert!(content.len() < 128, "test helper: short-form lengths only");
1080 let mut out = alloc::vec![tag, u8::try_from(content.len()).unwrap()];
1081 out.extend_from_slice(content);
1082 out
1083 }
1084
1085 fn utc(s: &str) -> Vec<u8> {
1088 tlv(TAG_UTC_TIME, s.as_bytes())
1089 }
1090 fn gtime(s: &str) -> Vec<u8> {
1091 tlv(TAG_GENERALIZED_TIME, s.as_bytes())
1092 }
1093
1094 #[test]
1095 fn time_utctime_parses() {
1096 let der = utc("260611120000Z");
1097 let (t, rest) = read_time(&der).unwrap();
1098 assert!(rest.is_empty());
1099 assert_eq!(
1100 t,
1101 X509Time {
1102 year: 2026,
1103 month: 6,
1104 day: 11,
1105 hour: 12,
1106 minute: 0,
1107 second: 0
1108 }
1109 );
1110 }
1111
1112 #[test]
1113 fn time_utctime_pivot() {
1114 assert_eq!(read_time(&utc("500101000000Z")).unwrap().0.year, 1950);
1115 assert_eq!(read_time(&utc("490101000000Z")).unwrap().0.year, 2049);
1116 }
1117
1118 #[test]
1119 fn time_generalizedtime_parses() {
1120 let (t, _) = read_time(>ime("20991231235959Z")).unwrap();
1121 assert_eq!(
1122 t,
1123 X509Time {
1124 year: 2099,
1125 month: 12,
1126 day: 31,
1127 hour: 23,
1128 minute: 59,
1129 second: 59
1130 }
1131 );
1132 }
1133
1134 #[test]
1135 fn time_ordering_is_chronological() {
1136 let (a, _) = read_time(&utc("260611120000Z")).unwrap();
1137 let (b, _) = read_time(&utc("260611120001Z")).unwrap();
1138 let (c, _) = read_time(>ime("20991231235959Z")).unwrap();
1139 assert!(a < b && b < c);
1140 }
1141
1142 #[test]
1143 fn time_rejects_malformed() {
1144 for bad in [
1145 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"), ] {
1157 assert!(read_time(&bad).is_none(), "accepted {bad:02x?}");
1158 }
1159 }
1160
1161 fn algid(params_null: bool) -> Vec<u8> {
1164 let mut body = tlv(0x06, oid::SM2_SIGN_WITH_SM3);
1167 if params_null {
1168 body.extend_from_slice(&[0x05, 0x00]);
1169 }
1170 tlv(0x30, &body)
1171 }
1172
1173 #[test]
1174 fn algid_absent_and_null_params_accepted() {
1175 for null in [false, true] {
1176 let a = algid(null);
1177 let (span, rest) = read_sm2_sig_algid(&a).expect("valid algid rejected");
1178 assert_eq!(span, &a[..]);
1179 assert!(rest.is_empty());
1180 }
1181 }
1182
1183 #[test]
1184 fn algid_mixed_forms_are_unequal_spans() {
1185 let absent = algid(false);
1188 let null = algid(true);
1189 let (s1, _) = read_sm2_sig_algid(&absent).unwrap();
1190 let (s2, _) = read_sm2_sig_algid(&null).unwrap();
1191 assert_ne!(s1, s2);
1192 }
1193
1194 #[test]
1195 fn algid_rejects_wrong_oid_and_bad_params() {
1196 let wrong = tlv(
1198 0x30,
1199 &tlv(0x06, &[0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02]),
1200 );
1201 assert!(read_sm2_sig_algid(&wrong).is_none());
1202 let mut body = tlv(0x06, oid::SM2_SIGN_WITH_SM3);
1204 body.extend_from_slice(&[0x30, 0x00]);
1205 assert!(read_sm2_sig_algid(&tlv(0x30, &body)).is_none());
1206 let mut body = tlv(0x06, oid::SM2_SIGN_WITH_SM3);
1208 body.extend_from_slice(&[0x05, 0x00, 0x00]);
1209 assert!(read_sm2_sig_algid(&tlv(0x30, &body)).is_none());
1210 }
1211
1212 fn extension(oid_content: &[u8], critical: Option<u8>, value: &[u8]) -> Vec<u8> {
1215 let mut body = tlv(0x06, oid_content);
1216 if let Some(b) = critical {
1217 body.extend_from_slice(&tlv(TAG_BOOLEAN, &[b]));
1218 }
1219 body.extend_from_slice(&tlv(0x04, value));
1220 tlv(0x30, &body)
1221 }
1222
1223 #[test]
1224 fn extensions_shape_ok() {
1225 let e1 = extension(&[0x55, 0x1d, 0x0f], Some(0xFF), &[0x03, 0x02, 0x01, 0x06]);
1226 let e2 = extension(&[0x55, 0x1d, 0x13], None, &[0x30, 0x00]);
1227 let mut both = e1;
1228 both.extend_from_slice(&e2);
1229 assert!(check_extensions_shape(&tlv(0x30, &both)).is_some());
1230 }
1231
1232 #[test]
1233 fn extensions_shape_rejects() {
1234 assert!(check_extensions_shape(&tlv(0x30, &[])).is_none());
1236 assert!(check_extensions_shape(&tlv(0x30, &tlv(0x04, &[0x00]))).is_none());
1238 let mut bad = tlv(0x06, &[0x55, 0x1d, 0x0f]);
1240 bad.extend_from_slice(&tlv(0x04, &[0x00]));
1241 bad.push(0x00);
1242 assert!(check_extensions_shape(&tlv(0x30, &tlv(0x30, &bad))).is_none());
1243 let ok = extension(&[0x55, 0x1d, 0x0f], None, &[0x00]);
1245 let mut outer = tlv(0x30, &ok);
1246 outer.push(0x00);
1247 assert!(check_extensions_shape(&outer).is_none());
1248 }
1249}