1use super::*;
2use vstd::prelude::*;
3use vstd::slice::slice_subrange;
4
5verus! {
6
7#[derive(Debug, View)]
9pub struct ASN1Tag;
10
11#[derive(Debug)]
12pub struct TagValue {
13 pub class: TagClass,
14 pub form: TagForm,
15
16 pub num: u8,
19}
20
21impl View for TagValue {
22 type V = TagValue;
23
24 open spec fn view(&self) -> Self::V {
25 *self
26 }
27}
28
29#[derive(Debug)]
30pub enum TagClass {
31 Universal,
32 Application,
33 ContextSpecific,
34 Private,
35}
36
37#[derive(Debug)]
38pub enum TagForm {
39 Primitive,
40 Constructed,
41}
42
43impl TagValue {
44 #[inline(always)]
45 pub fn eq(self, other: TagValue) -> (res: bool)
46 ensures res == (self == other)
47 {
48 (match (self.class, other.class) {
50 (TagClass::Universal, TagClass::Universal) => true,
51 (TagClass::Application, TagClass::Application) => true,
52 (TagClass::ContextSpecific, TagClass::ContextSpecific) => true,
53 (TagClass::Private, TagClass::Private) => true,
54 _ => false,
55 }) && (match (self.form, other.form) {
56 (TagForm::Primitive, TagForm::Primitive) => true,
57 (TagForm::Constructed, TagForm::Constructed) => true,
58 _ => false,
59 }) && self.num == other.num
60 }
61
62 #[inline(always)]
64 pub fn clone(&self) -> (res: TagValue)
65 ensures res == *self
66 {
67 TagValue {
68 class: match self.class {
69 TagClass::Universal => TagClass::Universal,
70 TagClass::Application => TagClass::Application,
71 TagClass::ContextSpecific => TagClass::ContextSpecific,
72 TagClass::Private => TagClass::Private,
73 },
74 form: match self.form {
75 TagForm::Primitive => TagForm::Primitive,
76 TagForm::Constructed => TagForm::Constructed,
77 },
78 num: self.num,
79 }
80 }
81}
82
83impl SpecCombinator for ASN1Tag {
84 type SpecResult = TagValue;
85
86 closed spec fn spec_parse(&self, s: Seq<u8>) -> Result<(usize, Self::SpecResult), ()> {
87 if s.len() == 0 {
88 Err(())
89 } else {
90 let class_num = s[0] >> 6 & 0b11;
91 let class = if class_num == 0 {
92 TagClass::Universal
93 } else if class_num == 1 {
94 TagClass::Application
95 } else if class_num == 2 {
96 TagClass::ContextSpecific
97 } else {
98 TagClass::Private
99 };
100
101 let form_num = s[0] >> 5 & 1;
102 let form = if form_num == 0 {
103 TagForm::Primitive
104 } else {
105 TagForm::Constructed
106 };
107
108 Ok((1, TagValue {
109 class,
110 form,
111 num: s[0] & 0b11111,
112 }))
113 }
114 }
115
116 proof fn spec_parse_wf(&self, s: Seq<u8>) {}
117
118 closed spec fn spec_serialize(&self, v: Self::SpecResult) -> Result<Seq<u8>, ()> {
119 let class: u8 = match v.class {
120 TagClass::Universal => 0,
121 TagClass::Application => 1,
122 TagClass::ContextSpecific => 2,
123 _ => 3,
124 };
125
126 let form: u8 = match v.form {
127 TagForm::Primitive => 0,
128 _ => 1,
129 };
130
131 if v.num > 0b11111 {
132 Err(())
133 } else {
134 Ok(seq![(class << 6) | (form << 5) | (v.num & 0b11111)])
135 }
136 }
137}
138
139impl SecureSpecCombinator for ASN1Tag {
140 open spec fn is_prefix_secure() -> bool {
141 true
142 }
143
144 proof fn theorem_serialize_parse_roundtrip(&self, v: Self::SpecResult) {
145 let class_num: u8 = match v.class {
146 TagClass::Universal => 0,
147 TagClass::Application => 1,
148 TagClass::ContextSpecific => 2,
149 _ => 3,
150 };
151
152 let form_num: u8 = match v.form {
153 TagForm::Primitive => 0,
154 _ => 1,
155 };
156
157 let num = v.num;
158
159 assert(
161 0 <= class_num < 4 &&
162 0 <= form_num < 2 &&
163 0 <= num <= 0b11111 ==> {
164 let ser = (class_num << 6) | (form_num << 5) | (num & 0b11111);
165 &&& ser >> 6 & 0b11 == class_num
166 &&& ser >> 5 & 1 == form_num
167 &&& ser & 0b11111 == num
168 }) by (bit_vector);
169 }
170
171 proof fn theorem_parse_serialize_roundtrip(&self, buf: Seq<u8>) {
172 let tag = buf[0];
173
174 assert(
176 (tag >> 6 & 0b11) << 6 | (tag >> 5 & 1) << 5 | ((tag & 0b11111) & 0b11111) == tag
177 ) by (bit_vector);
178
179 assert(tag >> 6 & 0b11 < 4) by (bit_vector);
181 assert(tag >> 5 & 1 < 2) by (bit_vector);
182 assert(tag & 0b11111 <= 0b11111) by (bit_vector);
183
184 if let Ok((n, v)) = self.spec_parse(buf) {
185 let ser = self.spec_serialize(v).unwrap();
186 assert(ser =~= buf.subrange(0, 1));
187 }
188 }
189
190 proof fn lemma_prefix_secure(&self, s1: Seq<u8>, s2: Seq<u8>) {}
191}
192
193impl Combinator for ASN1Tag {
194 type Result<'a> = TagValue;
195 type Owned = TagValue;
196
197 closed spec fn spec_length(&self) -> Option<usize> {
198 Some(1)
199 }
200
201 fn length(&self) -> Option<usize> {
202 Some(1)
203 }
204
205 #[inline]
206 fn parse<'a>(&self, s: &'a [u8]) -> (res: Result<(usize, Self::Result<'a>), ParseError>) {
207 if s.len() == 0 {
208 return Err(ParseError::UnexpectedEndOfInput);
209 } else {
210 let class_num = s[0] >> 6 & 0b11;
211 let class = if class_num == 0 {
212 TagClass::Universal
213 } else if class_num == 1 {
214 TagClass::Application
215 } else if class_num == 2 {
216 TagClass::ContextSpecific
217 } else {
218 TagClass::Private
219 };
220
221 let form_num = s[0] >> 5 & 1;
222 let form = if form_num == 0 {
223 TagForm::Primitive
224 } else {
225 TagForm::Constructed
226 };
227
228 Ok((1, TagValue {
229 class,
230 form,
231 num: s[0] & 0b11111,
232 }))
233 }
234 }
235
236 #[inline]
237 fn serialize(&self, v: Self::Result<'_>, data: &mut Vec<u8>, pos: usize) -> (res: Result<usize, SerializeError>) {
238 let class: u8 = match v.class {
239 TagClass::Universal => 0,
240 TagClass::Application => 1,
241 TagClass::ContextSpecific => 2,
242 _ => 3,
243 };
244
245 let form: u8 = match v.form {
246 TagForm::Primitive => 0,
247 _ => 1,
248 };
249
250 if v.num > 0b11111 {
251 return Err(SerializeError::Other("Invalid tag number".to_string()));
252 }
253
254 if pos < data.len() {
255 let tag = (class << 6) | (form << 5) | (v.num & 0b11111);
256 data.set(pos, tag);
257 assert(data@ == seq_splice(old(data)@, pos, seq![tag]));
258 Ok(1)
259 } else {
260 Err(SerializeError::InsufficientBuffer)
261 }
262 }
263}
264
265pub trait ASN1Tagged
270{
271 spec fn spec_tag(&self) -> TagValue;
272 fn tag(&self) -> (res: TagValue)
273 ensures res == self.spec_tag();
274}
275
276pub trait ViewWithASN1Tagged: View + ASN1Tagged where
279 Self::V: ASN1Tagged,
280{
281 proof fn lemma_view_preserves_tag(&self)
282 ensures self@.spec_tag() == self.spec_tag();
283}
284
285#[derive(Debug)]
288pub struct ASN1<T>(pub T);
289
290impl<T: View> View for ASN1<T> {
291 type V = ASN1<T::V>;
292
293 open spec fn view(&self) -> Self::V {
294 ASN1(self.0.view())
295 }
296}
297
298impl<T: ASN1Tagged> ASN1Tagged for ASN1<T> {
299 open spec fn spec_tag(&self) -> TagValue {
300 self.0.spec_tag()
301 }
302
303 #[inline(always)]
304 fn tag(&self) -> TagValue {
305 self.0.tag()
306 }
307}
308
309impl<T: ASN1Tagged + ViewWithASN1Tagged> ViewWithASN1Tagged for ASN1<T> where
310 T::V: ASN1Tagged,
311{
312 proof fn lemma_view_preserves_tag(&self) {
313 self.0.lemma_view_preserves_tag();
314 }
315}
316
317impl<T: ASN1Tagged + SpecCombinator> SpecCombinator for ASN1<T> {
318 type SpecResult = <T as SpecCombinator>::SpecResult;
319
320 closed spec fn spec_parse(&self, s: Seq<u8>) -> Result<(usize, Self::SpecResult), ()> {
321 match (ASN1Tag, self.0).spec_parse(s) {
322 Ok((n, (tag, v))) =>
323 if tag == self.0.spec_tag() {
324 Ok((n, v))
325 } else {
326 Err(())
327 }
328 Err(()) => Err(()),
329 }
330 }
331
332 proof fn spec_parse_wf(&self, s: Seq<u8>) {
333 (ASN1Tag, self.0).spec_parse_wf(s);
334 }
335
336 closed spec fn spec_serialize(&self, v: Self::SpecResult) -> Result<Seq<u8>, ()> {
337 (ASN1Tag, self.0).spec_serialize((self.0.spec_tag(), v))
338 }
339}
340
341impl<T: ASN1Tagged + SecureSpecCombinator> SecureSpecCombinator for ASN1<T> {
342 open spec fn is_prefix_secure() -> bool {
343 T::is_prefix_secure()
344 }
345
346 proof fn theorem_serialize_parse_roundtrip(&self, v: Self::SpecResult) {
347 (ASN1Tag, self.0).theorem_serialize_parse_roundtrip((self.0.spec_tag(), v));
348 }
349
350 proof fn theorem_parse_serialize_roundtrip(&self, buf: Seq<u8>) {
351 (ASN1Tag, self.0).theorem_parse_serialize_roundtrip(buf);
352 }
353
354 proof fn lemma_prefix_secure(&self, s1: Seq<u8>, s2: Seq<u8>) {
355 (ASN1Tag, self.0).lemma_prefix_secure(s1, s2);
356 }
357}
358
359impl<T: ASN1Tagged + Combinator> Combinator for ASN1<T> where
360 <T as View>::V: SecureSpecCombinator<SpecResult = <<T as Combinator>::Owned as View>::V>,
362 <T as View>::V: ASN1Tagged,
363 T: ViewWithASN1Tagged,
364{
365 type Result<'a> = T::Result<'a>;
366 type Owned = T::Owned;
367
368 open spec fn spec_length(&self) -> Option<usize> {
369 match self.0.spec_length() {
370 Some(len) => len.checked_add(1),
371 None => None,
372 }
373 }
374
375 fn length(&self) -> Option<usize> {
376 match self.0.length() {
377 Some(len) => len.checked_add(1),
378 None => None,
379 }
380 }
381
382 open spec fn parse_requires(&self) -> bool {
383 self.0.parse_requires()
384 }
385
386 #[inline(always)]
387 fn parse<'a>(&self, s: &'a [u8]) -> (res: Result<(usize, Self::Result<'a>), ParseError>) {
388 proof {
389 self.0.lemma_view_preserves_tag();
390 }
391
392 let (n1, tag) = ASN1Tag.parse(s)?;
393 let (n2, v) = self.0.parse(slice_subrange(s, n1, s.len()))?;
394
395 if tag.eq(self.0.tag()) && n1 <= usize::MAX - n2 {
396 Ok((n1 + n2, v))
397 } else {
398 Err(ParseError::Other("Unmatching tags".to_string()))
399 }
400 }
401
402 open spec fn serialize_requires(&self) -> bool {
403 self.0.serialize_requires()
404 }
405
406 #[inline(always)]
407 fn serialize(&self, v: Self::Result<'_>, data: &mut Vec<u8>, pos: usize) -> (res: Result<usize, SerializeError>) {
408 proof {
409 self.0.lemma_view_preserves_tag();
410 }
411
412 let n1 = ASN1Tag.serialize(self.0.tag(), data, pos)?;
413 if n1 > usize::MAX - pos || n1 + pos > data.len() {
414 return Err(SerializeError::InsufficientBuffer);
415 }
416
417 let n2 = self.0.serialize(v, data, pos + n1)?;
418
419 if n1 <= usize::MAX - n2 {
420 assert(data@ =~= seq_splice(old(data)@, pos, self@.spec_serialize(v@).unwrap()));
421 Ok(n1 + n2)
422 } else {
423 Err(SerializeError::SizeOverflow)
424 }
425 }
426}
427
428impl<T1, T2> DisjointFrom<ASN1<T1>> for ASN1<T2> where
430 T1: ASN1Tagged + SpecCombinator,
431 T2: ASN1Tagged + SpecCombinator,
432{
433 open spec fn disjoint_from(&self, other: &ASN1<T1>) -> bool {
434 self.0.spec_tag() != other.0.spec_tag()
435 }
436
437 proof fn parse_disjoint_on(&self, other: &ASN1<T1>, buf: Seq<u8>) {}
438}
439
440impl<T1, T2, S> DisjointFrom<(ASN1<T1>, S)> for ASN1<T2> where
442 T1: ASN1Tagged + SpecCombinator + SecureSpecCombinator,
443 T2: ASN1Tagged + SpecCombinator,
444 S: SpecCombinator,
445{
446 open spec fn disjoint_from(&self, other: &(ASN1<T1>, S)) -> bool {
447 self.0.spec_tag() != other.0.0.spec_tag()
448 }
449
450 proof fn parse_disjoint_on(&self, other: &(ASN1<T1>, S), buf: Seq<u8>) {}
451}
452
453impl<T1, T2, S> DisjointFrom<Pair<ASN1<T1>, S>> for ASN1<T2> where
459 T1: ASN1Tagged + SecureSpecCombinator,
460 T2: ASN1Tagged + SecureSpecCombinator,
461 S: SecureSpecCombinator,
462{
463 open spec fn disjoint_from(&self, other: &Pair<ASN1<T1>, S>) -> bool {
464 self.0.spec_tag() != other.0.0.spec_tag()
465 }
466
467 proof fn parse_disjoint_on(&self, other: &Pair<ASN1<T1>, S>, buf: Seq<u8>) {}
468}
469
470impl<T1, T2, S> DisjointFrom<ASN1<T2>> for Pair<ASN1<T1>, S> where
472 T1: ASN1Tagged + SecureSpecCombinator,
473 T2: ASN1Tagged + SecureSpecCombinator,
474 S: SecureSpecCombinator,
475{
476 open spec fn disjoint_from(&self, other: &ASN1<T2>) -> bool {
477 other.0.spec_tag() != self.0.0.spec_tag()
478 }
479
480 proof fn parse_disjoint_on(&self, other: &ASN1<T2>, buf: Seq<u8>) {}
481}
482
483impl<T> DisjointFrom<ASN1<T>> for End where
484 T: ASN1Tagged + SpecCombinator,
485{
486 open spec fn disjoint_from(&self, other: &ASN1<T>) -> bool { true }
487 proof fn parse_disjoint_on(&self, other: &ASN1<T>, buf: Seq<u8>) {}
488}
489
490impl<T1, T2> DisjointFrom<ASN1<T1>> for Cond<ASN1<T2>> where
491 T1: ASN1Tagged + SpecCombinator,
492 T2: ASN1Tagged + SpecCombinator,
493 {
494 open spec fn disjoint_from(&self, other: &ASN1<T1>) -> bool {
495 self.inner.0.spec_tag() != other.0.spec_tag()
496 }
497
498 proof fn parse_disjoint_on(&self, other: &ASN1<T1>, buf: Seq<u8>) {}
499}
500
501impl<T1, T2> DisjointFrom<Cached<ASN1<T1>>> for ASN1<T2> where
502 T1: ASN1Tagged + SpecCombinator,
503 T2: ASN1Tagged + SpecCombinator,
504{
505 open spec fn disjoint_from(&self, other: &Cached<ASN1<T1>>) -> bool {
506 self.0.spec_tag() != other.0.0.spec_tag()
507 }
508
509 proof fn parse_disjoint_on(&self, other: &Cached<ASN1<T1>>, buf: Seq<u8>) {}
510}
511
512impl<T1, T2, S> DisjointFrom<Cached<ASN1<T2>>> for Pair<ASN1<T1>, S> where
513 T1: ASN1Tagged + SecureSpecCombinator,
514 T2: ASN1Tagged + SecureSpecCombinator,
515 S: SecureSpecCombinator,
516{
517 open spec fn disjoint_from(&self, other: &Cached<ASN1<T2>>) -> bool {
518 other.0.0.spec_tag() != self.0.0.spec_tag()
519 }
520
521 proof fn parse_disjoint_on(&self, other: &Cached<ASN1<T2>>, buf: Seq<u8>) {}
522}
523
524#[allow(unused_macros)]
526#[macro_export]
527macro_rules! asn1_tagged {
528 ($ty:ident, $tag:expr) => {
529 ::builtin_macros::verus! {
530 impl ASN1Tagged for $ty {
531 open spec fn spec_tag(&self) -> TagValue {
532 $tag
533 }
534
535 fn tag(&self) -> TagValue {
536 $tag
537 }
538 }
539
540 impl ViewWithASN1Tagged for $ty {
541 proof fn lemma_view_preserves_tag(&self) {}
542 }
543 }
544 };
545}
546pub use asn1_tagged;
547
548#[allow(unused_macros)]
550macro_rules! tag_of {
551 (BOOLEAN) => {
552 TagValue {
553 class: TagClass::Universal,
554 form: TagForm::Primitive,
555 num: 0x01,
556 }
557 };
558
559 (INTEGER) => {
560 TagValue {
561 class: TagClass::Universal,
562 form: TagForm::Primitive,
563 num: 0x02,
564 }
565 };
566
567 (BIT_STRING) => {
568 TagValue {
569 class: TagClass::Universal,
570 form: TagForm::Primitive,
571 num: 0x03,
572 }
573 };
574
575 (OCTET_STRING) => {
576 TagValue {
577 class: TagClass::Universal,
578 form: TagForm::Primitive,
579 num: 0x04,
580 }
581 };
582
583 (NULL) => {
584 TagValue {
585 class: TagClass::Universal,
586 form: TagForm::Primitive,
587 num: 0x05,
588 }
589 };
590
591 (OBJECT_IDENTIFIER) => {
592 TagValue {
593 class: TagClass::Universal,
594 form: TagForm::Primitive,
595 num: 0x06,
596 }
597 };
598
599 (SEQUENCE) => {
600 TagValue {
601 class: TagClass::Universal,
602 form: TagForm::Constructed,
603 num: 0x10,
604 }
605 };
606
607 (SET) => {
608 TagValue {
609 class: TagClass::Universal,
610 form: TagForm::Constructed,
611 num: 0x11,
612 }
613 };
614
615 (UTF8_STRING) => {
616 TagValue {
617 class: TagClass::Universal,
618 form: TagForm::Primitive,
619 num: 0x0c,
620 }
621 };
622
623 (PRINTABLE_STRING) => {
624 TagValue {
625 class: TagClass::Universal,
626 form: TagForm::Primitive,
627 num: 0x13,
628 }
629 };
630
631 (TELETEX_STRING) => {
632 TagValue {
633 class: TagClass::Universal,
634 form: TagForm::Primitive,
635 num: 0x14,
636 }
637 };
638
639 (IA5_STRING) => {
640 TagValue {
641 class: TagClass::Universal,
642 form: TagForm::Primitive,
643 num: 0x16,
644 }
645 };
646
647 (UNIVERSAL_STRING) => {
648 TagValue {
649 class: TagClass::Universal,
650 form: TagForm::Primitive,
651 num: 0x1c,
652 }
653 };
654
655 (BMP_STRING) => {
656 TagValue {
657 class: TagClass::Universal,
658 form: TagForm::Primitive,
659 num: 0x1e,
660 }
661 };
662
663 (UTC_TIME) => {
664 TagValue {
665 class: TagClass::Universal,
666 form: TagForm::Primitive,
667 num: 0x17,
668 }
669 };
670
671 (GENERALIZED_TIME) => {
672 TagValue {
673 class: TagClass::Universal,
674 form: TagForm::Primitive,
675 num: 0x18,
676 }
677 };
678
679 (IMPLICIT $num:literal) => {
680 TagValue {
681 class: TagClass::ContextSpecific,
682 form: TagForm::Primitive,
683 num: $num,
684 }
685 };
686
687 (EXPLICIT $num:literal) => {
688 TagValue {
689 class: TagClass::ContextSpecific,
690 form: TagForm::Constructed,
691 num: $num,
692 }
693 };
694}
695pub(crate) use tag_of;
696
697#[allow(unused_macros)]
700macro_rules! placeholder {
701 ($($tag:tt)*) => {
702 ASN1(ImplicitTag(tag_of!($($tag)*), OctetString))
703 };
704}
705pub(crate) use placeholder;
706
707#[allow(unused_macros)]
708macro_rules! placeholder_type {
709 () => { ASN1<ImplicitTag<OctetString>> };
710}
711pub(crate) use placeholder_type;
712
713}