1use super::{View, syntax};
4use crate::{Error, Result, preservation::Kind};
5use structured_asn1::{
6 Element, Encoding, Parser, Reader,
7 length::DerLength,
8 memory::{OwnedVec, Work},
9};
10use structured_cms::{
11 ErrorCode,
12 attribute::{Attribute, Placement},
13 content::ContentInfo,
14 stream::{Receiver, Refused, Source},
15};
16
17const FIELD: &str = "cades.evidence.object";
18
19enum Header<'d> {
20 Original(&'d [u8]),
21 Definite { tag: u8, length: DerLength },
22}
23struct Frame<'d> {
24 header: Header<'d>,
25 prefix: &'d [u8],
26 suffix: &'d [u8],
27 indefinite: bool,
28 length: u64,
29}
30impl<'d> Frame<'d> {
31 fn body(element: Element<'d>, tag: u8, length: u64) -> Result<Self> {
32 let old = element.contents_span();
33 let header_len = usize::try_from(old.start - element.span().start)
34 .map_err(|_| syntax(ErrorCode::LengthOverflow, element.span()))?;
35 let header = if element.is_indefinite() || length == old.length {
36 Header::Original(&element.as_bytes()[..header_len])
37 } else {
38 Header::Definite {
39 tag,
40 length: DerLength::new(length),
41 }
42 };
43 let header_length = match &header {
44 Header::Original(bytes) => bytes.len() as u64,
45 Header::Definite { length, .. } => 1 + length.as_bytes().len() as u64,
46 };
47 let total = header_length
48 .checked_add(length)
49 .and_then(|value| value.checked_add(if element.is_indefinite() { 2 } else { 0 }))
50 .ok_or_else(|| syntax(ErrorCode::LengthOverflow, element.span()))?;
51 Ok(Self {
52 header,
53 prefix: &[],
54 suffix: &[],
55 indefinite: element.is_indefinite(),
56 length: total,
57 })
58 }
59 fn around(element: Element<'d>, tag: u8, child: Element<'d>, replacement: u64) -> Result<Self> {
60 let outer = element.contents_span();
61 let inner = child.span();
62 if inner.start < outer.start || inner.end() > outer.end() {
63 return Err(Error::Foreign { at: inner.start });
64 }
65 let start = usize::try_from(inner.start - outer.start)
66 .map_err(|_| syntax(ErrorCode::LengthOverflow, inner))?;
67 let end = usize::try_from(inner.end() - outer.start)
68 .map_err(|_| syntax(ErrorCode::LengthOverflow, inner))?;
69 let prefix = &element.contents()[..start];
70 let suffix = &element.contents()[end..];
71 let length = (prefix.len() as u64)
72 .checked_add(replacement)
73 .and_then(|value| value.checked_add(suffix.len() as u64))
74 .ok_or_else(|| syntax(ErrorCode::LengthOverflow, outer))?;
75 let mut frame = Self::body(element, tag, length)?;
76 frame.prefix = prefix;
77 frame.suffix = suffix;
78 Ok(frame)
79 }
80 fn begin<W: Work>(
81 &self,
82 out: &mut impl Receiver,
83 work: &W,
84 ) -> core::result::Result<(), ObjectError> {
85 work.charge_work(1).map_err(ObjectError::Resource)?;
86 match &self.header {
87 Header::Original(bytes) => out.write(bytes).map_err(ObjectError::Receiver)?,
88 Header::Definite { tag, length } => {
89 out.write(&[*tag]).map_err(ObjectError::Receiver)?;
90 out.write(length.as_bytes())
91 .map_err(ObjectError::Receiver)?;
92 }
93 }
94 out.write(self.prefix).map_err(ObjectError::Receiver)
95 }
96 fn end<W: Work>(
97 &self,
98 out: &mut impl Receiver,
99 work: &W,
100 ) -> core::result::Result<(), ObjectError> {
101 work.charge_work(1).map_err(ObjectError::Resource)?;
102 out.write(self.suffix).map_err(ObjectError::Receiver)?;
103 if self.indefinite {
104 out.write(&[0, 0]).map_err(ObjectError::Receiver)?;
105 }
106 Ok(())
107 }
108}
109
110fn enclosing_frames<'d>(
111 message: &structured_cms::SignedData<'d>,
112 content: &ContentInfo<'d>,
113 envelope: Element<'d>,
114 first: Element<'d>,
115 signer: Frame<'d>,
116) -> Result<[Frame<'d>; 5]> {
117 let signer_set = Frame::around(message.signer_set_element(), 0x31, first, signer.length)?;
118 let body = Frame::around(
119 *content.content(),
120 0x30,
121 message.signer_set_element(),
122 signer_set.length,
123 )?;
124 let explicit = Frame::around(
125 content.content_wrapper(),
126 0xa0,
127 *content.content(),
128 body.length,
129 )?;
130 let outer = Frame::around(envelope, 0x30, content.content_wrapper(), explicit.length)?;
131 Ok([outer, explicit, body, signer_set, signer])
132}
133
134#[derive(Debug)]
136pub enum ObjectError {
137 Resource(structured_asn1::memory::MemoryError),
139 Receiver(Refused),
141 PriorProcessing(Error),
143}
144
145#[derive(Debug)]
147pub enum SnapshotError {
148 Current(Error),
150 Prior(Error),
152 Changed {
154 current: structured_asn1::Span,
156 prior: structured_asn1::Span,
158 },
159}
160pub struct CmsSnapshot<'a, 'd> {
165 envelope: Element<'d>,
166 message: &'a structured_cms::SignedData<'d>,
167 frames: [Frame<'d>; 5],
168 parser: &'d Parser,
169 encoding: Encoding,
170 depth: u32,
171}
172impl<'a, 'd> CmsSnapshot<'a, 'd> {
173 pub fn capture(
175 message: &'a structured_cms::SignedData<'d>,
176 envelope: Element<'d>,
177 operation: &Reader<'d>,
178 ) -> Result<Self> {
179 let content = container(message, envelope, operation)?;
180 let first = message
181 .signers()
182 .first()
183 .ok_or_else(|| syntax(ErrorCode::MissingField, envelope.span()))?;
184 let signer = if let Some(unsigned) = first.unsigned_attributes() {
185 Frame::around(
186 *first.element(),
187 0x30,
188 *unsigned.element(),
189 unsigned.element().as_bytes().len() as u64,
190 )?
191 } else {
192 let mut frame = Frame::body(
193 *first.element(),
194 0x30,
195 first.element().contents_span().length,
196 )?;
197 frame.prefix = first.element().contents();
198 frame
199 };
200 let frames = enclosing_frames(message, &content, envelope, *first.element(), signer)?;
201 Ok(Self {
202 envelope,
203 message,
204 frames,
205 parser: operation.parser(),
206 encoding: operation.encoding(),
207 depth: operation.depth(),
208 })
209 }
210}
211struct Original<'d> {
212 element: Element<'d>,
213 parser: &'d Parser,
214 encoding: Encoding,
215 depth: u32,
216}
217
218pub struct CmsObject<'a, 'd> {
222 frames: [Frame<'d>; 5],
223 unsigned: Option<Frame<'d>>,
224 attributes: &'a [Attribute<'d>],
225 keep: OwnedVec<bool>,
226 target: usize,
227 original: Option<Original<'d>>,
228}
229impl<'d> CmsObject<'_, 'd> {
230 #[must_use]
234 pub fn occurrence(&self) -> usize {
235 self.target
236 }
237 pub(super) fn coverage(
238 &self,
239 view: &View<'_, '_, 'd>,
240 operation: &Reader<'d>,
241 ) -> Result<OwnedVec<structured_asn1::Span>> {
242 let work = operation.execution();
243 let mut ranges = work.vector();
244 let message = view.prepared.document().message();
245 let mut fields = message.fields_source().reader_in(&work)?;
246 while let Some(element) = fields
247 .next_element()
248 .map_err(|cause| Error::encoding(cause, FIELD))?
249 {
250 if element.span() != message.signer_set_element().span() {
251 ranges
252 .try_push(element.span())
253 .map_err(|cause| Error::resource(cause, FIELD, element.span().start))?;
254 }
255 }
256 let first = message
257 .signers()
258 .first()
259 .expect("CmsObject admitted first signer");
260 let source = first.fields();
261 ranges
262 .try_push(structured_asn1::Span {
263 start: source.identity[0].span().start,
264 length: source.signature[1].span().end() - source.identity[0].span().start,
265 })
266 .map_err(|cause| Error::resource(cause, FIELD, first.span().start))?;
267 for signer in message.signers().iter().skip(1) {
268 ranges
269 .try_push(signer.span())
270 .map_err(|cause| Error::resource(cause, FIELD, signer.span().start))?;
271 }
272 for (ordinal, attribute) in self.attributes.iter().enumerate() {
273 work.charge_work(1)
274 .map_err(|cause| Error::resource(cause, FIELD, attribute.span().start))?;
275 if self.keep[ordinal] {
276 ranges
277 .try_push(attribute.span())
278 .map_err(|cause| Error::resource(cause, FIELD, attribute.span().start))?;
279 }
280 }
281 Ok(ranges.into_owned())
282 }
283}
284impl Source for CmsObject<'_, '_> {
285 type Error = ObjectError;
286 fn stream<W: Work>(
287 &mut self,
288 out: &mut impl Receiver,
289 work: &W,
290 ) -> core::result::Result<(), ObjectError> {
291 if let Some(original) = &self.original {
292 let origin = work
295 .read_scoped_source(
296 original.parser,
297 original.element.as_bytes(),
298 original.element.span().start,
299 original.encoding,
300 original.depth,
301 )
302 .map_err(|cause| ObjectError::PriorProcessing(Error::encoding(cause, FIELD)))?;
303 origin
304 .charge(1)
305 .map_err(|cause| ObjectError::PriorProcessing(Error::encoding(cause, FIELD)))?;
306 return out
307 .write(original.element.as_bytes())
308 .map_err(ObjectError::Receiver);
309 }
310 for frame in &self.frames {
311 frame.begin(out, work)?;
312 }
313 if let Some(unsigned) = &self.unsigned {
314 unsigned.begin(out, work)?;
315 for (index, attribute) in self.attributes.iter().enumerate() {
316 work.charge_work(1).map_err(ObjectError::Resource)?;
317 if self.keep[index] {
318 out.write(attribute.as_bytes())
319 .map_err(ObjectError::Receiver)?;
320 }
321 }
322 unsigned.end(out, work)?;
323 }
324 for frame in self.frames.iter().rev() {
325 frame.end(out, work)?;
326 }
327 Ok(())
328 }
329}
330impl<'a, 'd> View<'a, '_, 'd> {
331 pub fn cms_object(
335 &self,
336 envelope: Element<'d>,
337 operation: &Reader<'d>,
338 ) -> Result<CmsObject<'a, 'd>> {
339 let required = self.entry.required;
340 let message = self.prepared.document().message();
341 message.require_session(operation, FIELD)?;
342 operation
343 .charge(12)
344 .map_err(|cause| Error::encoding(cause, FIELD))?;
345 if required.placement != Placement::Unsigned
346 || !matches!(
347 required.kind,
348 Kind::EvidenceRecordInternal | Kind::EvidenceRecordExternal
349 )
350 {
351 return Err(Error::Foreign {
352 at: required.property.span().start,
353 });
354 }
355 let first = message
356 .signers()
357 .first()
358 .ok_or_else(|| syntax(ErrorCode::MissingField, envelope.span()))?;
359 if first.span() != required.signature.span() {
360 return Err(Error::Foreign {
361 at: required.signature.span().start,
362 });
363 }
364 let content = container(message, envelope, operation)?;
365 let unsigned = first
366 .unsigned_attributes()
367 .ok_or_else(|| syntax(ErrorCode::MissingField, first.span()))?;
368 let work = operation.execution();
369 let mut keep = work.vector();
370 keep.try_reserve_exact(unsigned.items().len())
371 .map_err(|cause| Error::resource(cause, FIELD, unsigned.element().span().start))?;
372 let mut target = None;
373 let mut occurrence = 0;
374 let mut retained = 0u64;
375 for attribute in unsigned.items() {
376 work.charge_work(1 + attribute.kind().as_bytes().len().min(11) as u64)
377 .map_err(|cause| Error::resource(cause, FIELD, attribute.span().start))?;
378 let evidence = matches!(
379 Kind::from_oid(attribute.kind()),
380 Some(Kind::EvidenceRecordInternal | Kind::EvidenceRecordExternal)
381 );
382 if evidence && attribute.values().len() != 1 {
383 return Err(syntax(ErrorCode::AttributeCardinality, attribute.span()));
384 }
385 if attribute.span() == required.property.span() {
386 target = Some(occurrence);
387 }
388 let selected = !evidence || target.is_none();
389 if selected {
390 retained = retained
391 .checked_add(attribute.as_bytes().len() as u64)
392 .ok_or_else(|| syntax(ErrorCode::LengthOverflow, attribute.span()))?;
393 }
394 keep.try_push(selected)
395 .map_err(|cause| Error::resource(cause, FIELD, attribute.span().start))?;
396 if evidence {
397 occurrence += 1;
398 }
399 }
400 let target = target.ok_or(Error::Foreign {
401 at: required.property.span().start,
402 })?;
403 let modified = if retained == 0 {
404 None
405 } else {
406 Some(Frame::body(*unsigned.element(), 0xa1, retained)?)
407 };
408 let signer = Frame::around(
409 *first.element(),
410 0x30,
411 *unsigned.element(),
412 modified.as_ref().map_or(0, |frame| frame.length),
413 )?;
414 let frames = enclosing_frames(message, &content, envelope, *first.element(), signer)?;
415 Ok(CmsObject {
416 frames,
417 unsigned: modified,
418 attributes: unsigned.items(),
419 keep: keep.into_owned(),
420 target,
421 original: None,
422 })
423 }
424 pub fn cms_object_snapshot(
429 &self,
430 envelope: Element<'d>,
431 snapshot: &CmsSnapshot<'_, 'd>,
432 operation: &Reader<'d>,
433 ) -> core::result::Result<CmsObject<'a, 'd>, SnapshotError> {
434 let mut selected = self
435 .cms_object(envelope, operation)
436 .map_err(SnapshotError::Current)?;
437 let current = operation.execution();
438 let origin = current
439 .read_scoped_source(
440 snapshot.parser,
441 snapshot.envelope.as_bytes(),
442 snapshot.envelope.span().start,
443 snapshot.encoding,
444 snapshot.depth,
445 )
446 .map_err(|cause| SnapshotError::Prior(Error::encoding(cause, FIELD)))?;
447 let work = origin.execution();
448 let current = self.required().property.span();
449 let prior_span = snapshot.envelope.span();
450 let changed = || SnapshotError::Changed {
451 current,
452 prior: prior_span,
453 };
454 let at = prior_span.start;
455 for (actual, prior) in selected.frames.iter().zip(&snapshot.frames) {
456 if !same(actual.prefix, prior.prefix, &work, at).map_err(SnapshotError::Prior)?
457 || !same(actual.suffix, prior.suffix, &work, at).map_err(SnapshotError::Prior)?
458 {
459 return Err(changed());
460 }
461 }
462 let prior = snapshot.message.signers()[0]
463 .unsigned_attributes()
464 .map_or(&[][..], |attributes| attributes.items());
465 let mut next = 0;
466 for (ordinal, attribute) in selected.attributes.iter().enumerate() {
467 work.charge_work(1)
468 .map_err(|cause| SnapshotError::Prior(Error::resource(cause, FIELD, at)))?;
469 if !selected.keep[ordinal] {
470 continue;
471 }
472 let previous = prior.get(next).ok_or_else(changed)?;
473 if !same(attribute.as_bytes(), previous.as_bytes(), &work, at)
474 .map_err(SnapshotError::Prior)?
475 {
476 return Err(changed());
477 }
478 next += 1;
479 }
480 if next != prior.len() {
481 return Err(changed());
482 }
483 selected.original = Some(Original {
484 element: snapshot.envelope,
485 parser: snapshot.parser,
486 encoding: snapshot.encoding,
487 depth: snapshot.depth,
488 });
489 Ok(selected)
490 }
491}
492
493fn same<W: Work>(left: &[u8], right: &[u8], work: &W, at: u64) -> Result<bool> {
494 work.charge_work(1)
495 .map_err(|cause| Error::resource(cause, FIELD, at))?;
496 if left.len() != right.len() {
497 return Ok(false);
498 }
499 work.charge_work(left.len() as u64)
500 .map_err(|cause| Error::resource(cause, FIELD, at))?;
501 Ok(left == right)
502}
503fn container<'d>(
504 message: &structured_cms::SignedData<'d>,
505 envelope: Element<'d>,
506 operation: &Reader<'d>,
507) -> Result<ContentInfo<'d>> {
508 message.require_session(operation, FIELD)?;
509 let (content, _) = ContentInfo::read_element(operation, &envelope)?;
510 operation
511 .charge(1 + content.kind().as_bytes().len() as u64)
512 .map_err(|cause| Error::encoding(cause, FIELD))?;
513 if content.kind() != structured_cms::oid::SIGNED_DATA {
514 return Err(syntax(ErrorCode::UnexpectedContentType, envelope.span()));
515 }
516 if content.content().span() != message.span()
517 || !core::ptr::eq(
518 content.content().as_bytes().as_ptr(),
519 message.as_bytes().as_ptr(),
520 )
521 {
522 return Err(Error::Foreign {
523 at: envelope.span().start,
524 });
525 }
526 Ok(content)
527}