1use crate::asn1::{
3 constructed_tag, primitive_tag, ASN1Fmt, BerLength, BerLengthFmt, Class, LengthFmt,
4 OctetStringFmt, Tag, TagFmt, BER,
5};
6use crate::combinators::{
7 bytes::ExactLen,
8 mapped::spec::FnSpecMapper,
9 recursive::{
10 BundledSpecs, ParamRecSpecs, ParserRecBody, ProductiveRecBody, SafeParserRecBody,
11 SpecRecBody,
12 },
13 tail::RepeatTillEnd,
14 Bind, FixWith, Mapped, Repeat, Sum, Void,
15};
16use crate::core::exec::fns::*;
17use crate::core::exec::parser::*;
18use crate::core::exec::{
19 input::InputBuf, ByteLen, OutputBuf, PResult, ParseError, Parser, PreSerializeError, Prepare,
20 Serializer,
21};
22use crate::core::{proof::*, spec::*};
23use crate::Never;
24#[cfg(feature = "alloc")]
25use alloc::vec::Vec;
26use vstd::prelude::*;
27#[cfg(feature = "alloc")]
28use vstd::slice::slice_to_vec;
29
30use super::any::{EocFmt, EocValue, EOC};
31use Sum::Inl as L;
32use Sum::Inr as R;
33
34verus! {
35
36type BerOctetStringWireType = (
37 Tag,
38 Sum<(usize, Seq<u8>), Sum<(BerLength, Sum<Seq<Seq<u8>>, (Seq<Seq<u8>>, EocValue)>), Never>>,
39);
40
41type BerOctetStringBodyFmt<Rec> = Mapped<
42 Bind<
43 TagFmt,
44 spec_fn(Tag) -> Sum<
45 Bind<LengthFmt<BER>, spec_fn(usize) -> ExactLen<OctetStringFmt, usize>>,
46 Sum<
47 Bind<
48 BerLengthFmt,
49 spec_fn(BerLength) -> Sum<
50 ExactLen<RepeatTillEnd<Rec>, usize>,
51 Repeat<Rec, EocFmt>,
52 >,
53 >,
54 Void,
55 >,
56 >,
57 >,
58 FnSpecMapper<BerOctetStringWireType, Seq<u8>>,
59>;
60
61pub open spec fn ber_octet_string_rec_body(
67 tag: Tag,
68 rec: ParamRecSpecs<Tag, Seq<u8>>,
69) -> BerOctetStringBodyFmt<BundledSpecs<Seq<u8>>> {
70 #[verusfmt::skip]
71 Mapped {
72 inner: Bind(TagFmt, |parsed_tag: Tag|
73 match parsed_tag {
74 t if t == primitive_tag(tag) =>
75 L(Bind(LengthFmt::<BER>, |len: usize| ExactLen(len, OctetStringFmt))),
76 t if t == constructed_tag(tag) =>
77 R(L(Bind(BerLengthFmt, |len: BerLength|
78 match len {
79 BerLength::Definite(len) =>
80 L(ExactLen(len, RepeatTillEnd(rec(TagFmt::OCTET_STRING)))),
81 BerLength::Indefinite =>
82 R(Repeat(rec(TagFmt::OCTET_STRING), EOC)),
83 }))),
84 _ => R(R(Void("Tag must match the configured BER OCTET STRING identity"))),
85 },
86 ),
87 mapper: (
88 |parsed: BerOctetStringWireType|
89 match parsed.1 {
90 L((_len, bytes)) => bytes,
91 R(L((_len, inner))) => match inner {
92 L(segments) => segments.flatten(),
93 R((segments, _eoc)) => segments.flatten(),
94 },
95 R(R(_)) => arbitrary(), },
97 |bytes: Seq<u8>| (primitive_tag(tag), L((bytes.len() as usize, bytes))),
98 ),
99 }
100}
101
102pub struct BerOctetStringRecBody;
103
104impl SpecRecBody for BerOctetStringRecBody {
105 type Param = Tag;
106
107 type T = Seq<u8>;
108
109 type Body = BerOctetStringBodyFmt<BundledSpecs<Seq<u8>>>;
110
111 open spec fn spec_body(
112 &self,
113 tag: Self::Param,
114 rec: ParamRecSpecs<Self::Param, Self::T>,
115 ) -> Self::Body {
116 ber_octet_string_rec_body(tag, rec)
117 }
118}
119
120mod recursive_proofs {
121 use super::*;
122
123 impl SafeParserRecBody for BerOctetStringRecBody {
124 proof fn lemma_body_safe_inv_preservation(
125 &self,
126 tag: Tag,
127 rec: ParamRecSpecs<Tag, Seq<u8>>,
128 ) {
129 }
130 }
131
132 impl ProductiveRecBody for BerOctetStringRecBody {
133 proof fn lemma_body_productive_inv_preservation(
134 &self,
135 tag: Tag,
136 rec: ParamRecSpecs<Tag, Seq<u8>>,
137 ) {
138 }
139 }
140
141}
142
143pub open spec fn ber_octet_string_normalized_fmt(tag: Tag) -> ASN1Fmt<OctetStringFmt, BER> {
145 ASN1Fmt(primitive_tag(tag), OctetStringFmt)
146}
147
148#[derive(Clone, Copy)]
154pub struct BerOctetStringFmt<const LIMIT: usize>(pub Tag);
155
156impl<const LIMIT: usize> BerOctetStringFmt<LIMIT> {
157 #[verifier::allow_in_spec]
159 pub const fn universal() -> Self
160 returns
161 Self(TagFmt::OCTET_STRING),
162 {
163 Self(TagFmt::OCTET_STRING)
164 }
165
166 #[verifier::allow_in_spec]
168 pub const fn implicit(class: Class, number: u64) -> Self
169 returns
170 Self(
171 Tag {
172 class,
173 constructed: false,
174 number: crate::asn1::tag::tag_num_from_uint(number),
175 },
176 ),
177 {
178 Self(Tag { class, constructed: false, number: crate::asn1::tag::tag_num_from_uint(number) })
179 }
180}
181
182mod derived_specs {
183 use super::*;
184
185 impl<const LIMIT: usize> SpecParser for BerOctetStringFmt<LIMIT> {
186 type PVal = Seq<u8>;
187
188 open spec fn spec_parse(&self, ibuf: Seq<u8>) -> Option<(int, Self::PVal)> {
189 FixWith::<LIMIT, _, _>(BerOctetStringRecBody, self.0).spec_parse(ibuf)
190 }
191 }
192
193 impl<const LIMIT: usize> Consistency for BerOctetStringFmt<LIMIT> {
194 type Val = Seq<u8>;
195
196 open spec fn consistent(&self, value: Self::Val) -> bool {
197 ber_octet_string_normalized_fmt(self.0).consistent(value)
198 }
199 }
200
201 impl<const LIMIT: usize> SpecSerializerDps for BerOctetStringFmt<LIMIT> {
202 type SValue = Seq<u8>;
203
204 open spec fn spec_serialize_dps(&self, value: Self::SValue, obuf: Seq<u8>) -> Seq<u8> {
205 ber_octet_string_normalized_fmt(self.0).spec_serialize_dps(value, obuf)
206 }
207 }
208
209 impl<const LIMIT: usize> SpecSerializer for BerOctetStringFmt<LIMIT> {
210 type SVal = Seq<u8>;
211
212 open spec fn spec_serialize(&self, value: Self::SVal) -> Seq<u8> {
213 ber_octet_string_normalized_fmt(self.0).spec_serialize(value)
214 }
215 }
216
217 impl<const LIMIT: usize> SpecByteLen for BerOctetStringFmt<LIMIT> {
218 type T = Seq<u8>;
219
220 open spec fn byte_len(&self, value: Self::T) -> nat {
221 ber_octet_string_normalized_fmt(self.0).byte_len(value)
222 }
223 }
224
225}
226
227mod derived_proofs {
228 use super::*;
229
230 impl<const LIMIT: usize> SafeParser for BerOctetStringFmt<LIMIT> {
231 proof fn lemma_parse_safe(&self, ibuf: Seq<u8>) {
232 FixWith::<LIMIT, _, _>(BerOctetStringRecBody, self.0).lemma_parse_safe(ibuf);
233 }
234 }
235
236 impl<const LIMIT: usize> Productive for BerOctetStringFmt<LIMIT> {
237 proof fn lemma_productive(&self, ibuf: Seq<u8>) {
238 FixWith::<LIMIT, _, _>(BerOctetStringRecBody, self.0).lemma_productive(ibuf);
239 }
240 }
241
242 impl<const LIMIT: usize> GoodSerializer for BerOctetStringFmt<LIMIT> {
243 proof fn lemma_serialize_len(&self, value: Seq<u8>) {
244 ber_octet_string_normalized_fmt(self.0).lemma_serialize_len(value);
245 }
246 }
247
248 impl<const LIMIT: usize> NonTailFmt for BerOctetStringFmt<LIMIT> {
249 proof fn lemma_serialize_dps_prepend(&self, value: Seq<u8>, obuf: Seq<u8>) {
250 let normalized = ber_octet_string_normalized_fmt(self.0);
251 normalized.lemma_serialize_dps_prepend(value, obuf);
252 }
253
254 proof fn lemma_serialize_dps_len(&self, value: Seq<u8>, obuf: Seq<u8>) {
255 let normalized = ber_octet_string_normalized_fmt(self.0);
256 normalized.lemma_serialize_dps_len(value, obuf);
257 }
258 }
259
260 impl<const LIMIT: usize> EquivSerializersGeneral for BerOctetStringFmt<LIMIT> {
261 proof fn lemma_serialize_equiv(&self, value: Seq<u8>, obuf: Seq<u8>) {
262 let normalized = ber_octet_string_normalized_fmt(self.0);
263 normalized.lemma_serialize_equiv(value, obuf);
264 }
265 }
266
267 impl<const LIMIT: usize> EquivSerializers for BerOctetStringFmt<LIMIT> {
268 proof fn lemma_serialize_equiv_on_empty(&self, value: Seq<u8>) {
269 self.lemma_serialize_equiv(value, Seq::empty());
270 }
271 }
272
273 impl<const LIMIT: usize> SPRoundTripDps for BerOctetStringFmt<LIMIT> {
274 proof fn theorem_serialize_dps_parse_roundtrip(&self, value: Seq<u8>, obuf: Seq<u8>) {
275 let normalized = ber_octet_string_normalized_fmt(self.0);
276 normalized.theorem_serialize_dps_parse_roundtrip(value, obuf);
277 }
278 }
279
280}
281
282impl<const LIMIT: usize, Output: OutputBuf> Serializer<Output, [u8]> for BerOctetStringFmt<LIMIT> {
283 fn serialize_into(&self, value: &[u8], obuf: &mut Output) {
284 let tag = Tag { class: self.0.class, constructed: false, number: self.0.number };
285 let normalized = ASN1Fmt::<OctetStringFmt, BER>(tag, OctetStringFmt);
286 normalized.serialize_into(value, obuf);
287 }
288}
289
290impl<const LIMIT: usize> Prepare<[u8]> for BerOctetStringFmt<LIMIT> {
291 fn prepare(&self, value: &[u8]) -> Result<usize, PreSerializeError> {
292 let tag = Tag { class: self.0.class, constructed: false, number: self.0.number };
293 let normalized = ASN1Fmt::<OctetStringFmt, BER>(tag, OctetStringFmt);
294 normalized.prepare(value)
295 }
296}
297
298impl<const LIMIT: usize> ByteLen<[u8]> for BerOctetStringFmt<LIMIT> {
299 fn length(&self, value: &[u8]) -> usize {
300 let tag = Tag { class: self.0.class, constructed: false, number: self.0.number };
301 let normalized = ASN1Fmt::<OctetStringFmt, BER>(tag, OctetStringFmt);
302 normalized.length(value)
303 }
304}
305
306#[cfg(feature = "alloc")]
307impl<const LIMIT: usize, Output: OutputBuf> Serializer<Output, Vec<u8>> for BerOctetStringFmt<
308 LIMIT,
309> {
310 fn serialize_into(&self, value: &Vec<u8>, obuf: &mut Output) {
311 self.serialize_into(value.as_slice(), obuf)
312 }
313}
314
315#[cfg(feature = "alloc")]
316impl<const LIMIT: usize> Prepare<Vec<u8>> for BerOctetStringFmt<LIMIT> {
317 fn prepare(&self, value: &Vec<u8>) -> Result<usize, PreSerializeError> {
318 self.prepare(value.as_slice())
319 }
320}
321
322#[cfg(feature = "alloc")]
323impl<const LIMIT: usize> ByteLen<Vec<u8>> for BerOctetStringFmt<LIMIT> {
324 fn length(&self, value: &Vec<u8>) -> usize {
325 self.length(value.as_slice())
326 }
327}
328
329#[cfg(feature = "alloc")]
330fn flatten_octet_segments(segments: Vec<Vec<u8>>) -> (flat: Vec<u8>)
331 ensures
332 flat@ == segments.deep_view().flatten(),
333{
334 broadcast use vstd::seq_lib::group_seq_properties;
335
336 let mut flat = Vec::new();
337 let ghost segment_views = segments.deep_view();
338 for i in 0..segments.len()
339 invariant
340 segments.deep_view() == segment_views,
341 flat@ == segment_views.take(i as int).flatten(),
342 {
343 let segment = &segments[i];
344 proof {
345 let prefix = segment_views.take(i as int);
346 prefix.lemma_flatten_push(segment@);
347 assert(segment_views[i as int] == segment@);
348 assert(segment_views.take(i as int + 1) == prefix.push(segment@));
349 }
350 flat.extend_from_slice(&segment);
351 }
352 flat
353}
354
355spec fn flattened_result(r: Option<(int, Seq<Seq<u8>>)>) -> Option<(int, Seq<u8>)> {
356 match r {
357 Some((n, segments)) => Some((n, segments.flatten())),
358 None => None,
359 }
360}
361
362spec fn flattened_result_eoc(r: Option<(int, (Seq<Seq<u8>>, EocValue))>) -> Option<(int, Seq<u8>)> {
363 match r {
364 Some((n, (segments, _eoc))) => Some((n, segments.flatten())),
365 None => None,
366 }
367}
368
369#[inline(always)]
370#[cfg(feature = "alloc")]
371fn parse_segments_flatten<I, P>(parser: &P, ibuf: &I) -> (r: PResult<Vec<u8>>) where
372 I: InputBuf,
373 P: Parser<I, PT = Vec<Vec<u8>>, PVal = Seq<Seq<u8>>>,
374
375 requires
376 parser.exec_inv(),
377 ensures
378 parse_matches_spec(r, flattened_result(parser.spec_parse(ibuf@))),
379{
380 let (n, segments) = parser.parse(ibuf)?;
381 let flat = flatten_octet_segments(segments);
382 assert(flat.deep_view() == flat@);
383 Ok((n, flat))
384}
385
386#[inline(always)]
387#[cfg(feature = "alloc")]
388fn parse_segments_eoc_flatten<I, P>(parser: &P, ibuf: &I) -> (r: PResult<Vec<u8>>) where
389 I: InputBuf,
390 P: Parser<I, PT = (Vec<Vec<u8>>, EocValue), PVal = (Seq<Seq<u8>>, EocValue)>,
391
392 requires
393 parser.exec_inv(),
394 ensures
395 parse_matches_spec(r, flattened_result_eoc(parser.spec_parse(ibuf@))),
396{
397 let (n, (segments, _eoc)) = parser.parse(ibuf)?;
398 let flat = flatten_octet_segments(segments);
399 assert(flat.deep_view() == flat@);
400 Ok((n, flat))
401}
402
403#[cfg(feature = "alloc")]
404impl<'i> ParserRecBody<&'i [u8]> for BerOctetStringRecBody {
405 type EP = Tag;
406
407 type O = Vec<u8>;
408
409 fn parse_body<Exec>(
410 &self,
411 expected: &Tag,
412 Ghost(spec_rec): Ghost<ParamRecSpecs<Tag, Seq<u8>>>,
413 exec_rec: Exec,
414 ibuf: &&'i [u8],
415 ) -> PResult<Vec<u8>> where Exec: Fn(&Tag, &&'i [u8]) -> PResult<Vec<u8>> {
416 use crate::core::exec::bridge_lemmas::*;
417 use crate::combinators::congruence::*;
418
419 broadcast use crate::core::spec::SafeParser::lemma_parse_safe;
420 broadcast use crate::asn1::tag::lemma_const_tag_fmt_exec_inv;
421 broadcast use lemma_parser_congruent_reflexive;
422
423 let _ = ibuf.len();
424 let (tag_len, actual_tag) = TagFmt.parse(ibuf)?;
425 let rest = ibuf.skip(tag_len);
426
427 if actual_tag == primitive_tag(*expected) {
428 let (length_len, content_len) = LengthFmt::<BER>.parse(&rest)?;
429 let content_bytes = rest.skip(length_len);
430 let (content_len, v) = ExactLen(content_len, OctetStringFmt).parse(&content_bytes)?;
431 let v = slice_to_vec(v);
432 assert(v.deep_view() == v@);
433 let total = tag_len + length_len + content_len;
434 Ok((total, v))
435 } else if actual_tag == constructed_tag(*expected) {
436 let (length_len, content_len) = BerLengthFmt.parse(&rest)?;
437 let content_bytes = rest.skip(length_len);
438 let ghost child_spec = spec_rec(TagFmt::OCTET_STRING);
439 let child_exec = |input: &&'i [u8]| -> (r: PResult<Vec<u8>>)
440 ensures
441 parse_matches_spec(r, child_spec.2(input@)),
442 { exec_rec(&TagFmt::OCTET_STRING, input) };
443 let child: &FnParser<&'i [u8], Vec<u8>, BundledSpecs<Seq<u8>>, _> = &FnParser::new(
446 child_exec,
447 Ghost(child_spec),
448 );
449 proof {
450 lemma_ref_parser_exec_inv::<&'i [u8], _>(child);
451 lemma_ref_safe_productive_inv(child);
452 lemma_ref_fn_parser_congruence(child);
453 }
454
455 let (content_len, v) = match content_len {
456 BerLength::Definite(content_len) => {
457 let ghost repeated_spec = RepeatTillEnd(child_spec);
458 let repeated = RepeatTillEnd(child);
459 let exact = ExactLen(content_len, repeated);
460 proof {
461 lemma_repeat_till_end_parser_exec_inv::<&'i [u8], _>(&repeated);
462 lemma_exact_len_parser_exec_inv::<&'i [u8], _, _>(&exact);
463 lemma_repeat_till_end_parser_congruence(child, child_spec);
464 lemma_exact_len_parser_congruence(content_len, repeated, repeated_spec);
465 reveal(parser_congruent);
466 }
467 parse_segments_flatten(&exact, &content_bytes)?
468 },
469 BerLength::Indefinite => {
470 let repeated = Repeat(child, EOC);
471 proof {
472 lemma_pair_parser_exec_inv::<&'i [u8], _, _>(&EOC);
473 lemma_repeat_parser_exec_inv::<&'i [u8], _, _>(&repeated);
474 lemma_repeat_parser_congruence(child, child_spec, EOC, EOC);
475 reveal(parser_congruent);
476 }
477 parse_segments_eoc_flatten(&repeated, &content_bytes)?
478 },
479 };
480 let total = tag_len + length_len + content_len;
481 Ok((total, v))
482 } else {
483 Err(ParseError::custom("Tag must match the configured BER OCTET STRING identity"))
484 }
485 }
486}
487
488#[cfg(feature = "alloc")]
489impl<'i, const LIMIT: usize> Parser<&'i [u8]> for BerOctetStringFmt<LIMIT> {
490 type PT = Vec<u8>;
491
492 fn parse(&self, ibuf: &&'i [u8]) -> PResult<Self::PT> {
493 FixWith::<LIMIT, _, _>(BerOctetStringRecBody, self.0).parse(ibuf)
494 }
495}
496
497}