1use crate::{
4 Error, ErrorCode, Octets, Result,
5 stream::{Receiver, Refused, Source},
6};
7use core::cmp::Ordering;
8use structured_asn1::{
9 Class, Element, Encoding, Span, Tag,
10 length::DerLength,
11 memory::{HashWork, MemoryError, OwnedMap, OwnedVec, SortError, Work},
12 universal,
13};
14const FIELD: &str = "archive.der";
15
16#[derive(Clone, Copy)]
17pub(crate) enum Form {
18 Set,
19 Octets,
20 Omit,
21}
22#[derive(Clone, Copy, Hash, PartialEq, Eq)]
23struct Key(u64, u64);
24impl From<Span> for Key {
25 fn from(span: Span) -> Self {
26 Self(span.start, span.length)
27 }
28}
29impl HashWork for Key {
30 fn hash_work(&self) -> core::result::Result<u64, MemoryError> {
31 Ok(3)
32 }
33}
34pub(crate) struct Rules<W: Work> {
35 items: OwnedMap<Key, Form, W>,
36}
37impl<W: Work> Rules<W> {
38 pub(crate) fn new(work: &W) -> Self {
39 Self { items: work.map() }
40 }
41 pub(crate) fn insert(&mut self, span: Span, form: Form, _work: &W) -> Result<()> {
42 self.items
43 .try_insert(Key::from(span), form)
44 .map(|_| ())
45 .map_err(|cause| Error::resource(cause, FIELD, span.start))
46 }
47 pub(crate) fn algorithm(
48 &mut self,
49 identifier: structured_pkix::AlgorithmIdentifier<'_>,
50 work: &W,
51 ) -> Result<()> {
52 let at = identifier.offset();
53 work.charge_work(
54 1 + identifier
55 .algorithm()
56 .as_bytes()
57 .len()
58 .min(structured_pkix::oid::RSASSA_PSS.as_bytes().len()) as u64,
59 )
60 .map_err(|cause| Error::resource(cause, FIELD, at))?;
61 if identifier.algorithm() != structured_pkix::oid::RSASSA_PSS {
62 return Ok(());
63 }
64 if let Some(parameters) =
65 structured_pkix::algorithm::pss::read(identifier, work).map_err(Error::pkix)?
66 {
67 for element in parameters.written_defaults() {
68 self.insert(element.span(), Form::Omit, work)?;
69 }
70 }
71 Ok(())
72 }
73}
74enum Body<'d> {
75 Bytes(&'d [u8]),
76 Byte(u8),
77 Bits {
78 prefix: &'d [u8],
79 last: u8,
80 },
81 String(Octets<'d>),
82 Segments {
83 pieces: OwnedVec<&'d [u8]>,
84 unused: u8,
85 last: Option<u8>,
86 },
87 Children,
88}
89struct Node<'d> {
90 tag: &'d [u8],
91 primitive: Option<[u8; 1]>,
92 length: DerLength,
93 total: u64,
94 body: Body<'d>,
95 parent: Option<usize>,
96 first: Option<usize>,
97 next: Option<usize>,
98}
99pub(crate) struct Projection<'d> {
102 nodes: OwnedVec<Node<'d>>,
103}
104struct Frame<'d, 'w> {
105 reader: structured_asn1::ScopedReader<'d, 'w>,
106 index: usize,
107 last: Option<usize>,
108 sort: bool,
109 at: u64,
110}
111impl<'d> Projection<'d> {
112 pub(crate) fn new(
113 parent: &structured_asn1::ScopedReader<'d, '_>,
114 element: Element<'d>,
115 rules: &Rules<impl Work>,
116 ) -> Result<Self> {
117 let work = parent.execution();
118 let mut nodes = work.vector();
119 let mut frames = work.vector();
120 let (node, entered) = make(parent, element, rules, None)?;
121 nodes
122 .try_push(node)
123 .map_err(|cause| Error::resource(cause, FIELD, element.span().start))?;
124 if let Some((reader, sort)) = entered {
125 frames
126 .try_push(Frame {
127 reader,
128 index: 0,
129 last: None,
130 sort,
131 at: element.span().start,
132 })
133 .map_err(|cause| Error::resource(cause, FIELD, element.span().start))?;
134 }
135 while let Some(frame) = frames.last_mut() {
136 work.charge_work(1)
137 .map_err(|cause| Error::resource(cause, FIELD, frame.at))?;
138 if let Some(child) = frame
139 .reader
140 .next_element()
141 .map_err(|cause| Error::encoding(cause, FIELD))?
142 {
143 if matches!(
144 rules
145 .items
146 .get(&Key::from(child.span()), &work)
147 .map_err(|cause| Error::resource(cause, FIELD, child.span().start))?,
148 Some(Form::Omit)
149 ) {
150 continue;
151 }
152 let index = nodes.len();
153 let (node, entered) = make(&frame.reader, child, rules, Some(frame.index))?;
154 nodes
155 .try_push(node)
156 .map_err(|cause| Error::resource(cause, FIELD, child.span().start))?;
157 if let Some(previous) = frame.last {
158 nodes[previous].next = Some(index);
159 } else {
160 nodes[frame.index].first = Some(index);
161 }
162 frame.last = Some(index);
163 if let Some((reader, sort)) = entered {
164 frames
165 .try_push(Frame {
166 reader,
167 index,
168 last: None,
169 sort,
170 at: child.span().start,
171 })
172 .map_err(|cause| Error::resource(cause, FIELD, child.span().start))?;
173 }
174 } else {
175 let frame = frames.pop().expect("last frame exists");
176 if frame.sort {
177 sort_children(&mut nodes, frame.index, &work, frame.at)?;
178 }
179 let mut length = 0u64;
180 let mut next = nodes[frame.index].first;
181 while let Some(index) = next {
182 work.charge_work(1)
183 .map_err(|cause| Error::resource(cause, FIELD, frame.at))?;
184 length = length
185 .checked_add(nodes[index].total)
186 .ok_or_else(|| Error::schema(ErrorCode::LengthOverflow, FIELD, frame.at))?;
187 next = nodes[index].next;
188 }
189 finish(&mut nodes[frame.index], length, frame.at)?;
190 }
191 }
192 Ok(Self {
193 nodes: nodes.into_owned(),
194 })
195 }
196 pub(crate) fn len(&self) -> u64 {
197 self.nodes[0].total
198 }
199 pub(crate) fn feed<W: Work, E>(
200 &self,
201 work: &W,
202 mut write: impl FnMut(&[u8]) -> core::result::Result<(), E>,
203 ) -> core::result::Result<(), FeedError<E>> {
204 let mut cursor = Cursor::new(&self.nodes, 0);
205 while let Some(bytes) = cursor.next(work).map_err(FeedError::Resource)? {
206 write(bytes).map_err(FeedError::Callback)?;
207 }
208 Ok(())
209 }
210 pub(crate) fn write<W: Work>(
211 &self,
212 out: &mut impl Receiver,
213 work: &W,
214 ) -> core::result::Result<(), ProjectionError> {
215 let mut cursor = Cursor::new(&self.nodes, 0);
216 while let Some(bytes) = cursor.next(work).map_err(ProjectionError::Resource)? {
217 out.write(bytes).map_err(ProjectionError::Receiver)?;
218 }
219 Ok(())
220 }
221}
222fn finish(node: &mut Node<'_>, length: u64, at: u64) -> Result<()> {
223 node.length = DerLength::new(length);
224 let tag = if node.primitive.is_some() {
225 1
226 } else {
227 node.tag.len() as u64
228 };
229 node.total = length
230 .checked_add(node.length.as_bytes().len() as u64)
231 .and_then(|value| value.checked_add(tag))
232 .ok_or_else(|| Error::schema(ErrorCode::LengthOverflow, FIELD, at))?;
233 Ok(())
234}
235fn identifier<'d>(
236 element: Element<'d>,
237 parent: &structured_asn1::ScopedReader<'_, '_>,
238) -> Result<&'d [u8]> {
239 parent
243 .charge(1)
244 .map_err(|cause| Error::encoding(cause, FIELD))?;
245 let bytes = element.as_bytes();
246 if bytes[0] & 31 != 31 {
247 return Ok(&bytes[..1]);
248 }
249 let mut end = 1;
250 loop {
251 parent
252 .charge(1)
253 .map_err(|cause| Error::encoding(cause, FIELD))?;
254 let byte = bytes[end];
255 end += 1;
256 if byte & 128 == 0 {
257 return Ok(&bytes[..end]);
258 }
259 }
260}
261fn make<'d, 'w>(
262 parent: &structured_asn1::ScopedReader<'d, 'w>,
263 element: Element<'d>,
264 rules: &Rules<impl Work>,
265 owner: Option<usize>,
266) -> Result<(
267 Node<'d>,
268 Option<(structured_asn1::ScopedReader<'d, 'w>, bool)>,
269)> {
270 let at = element.span().start;
271 let tag = element.tag();
272 let form = rules
273 .items
274 .get(&Key::from(element.span()), &parent.execution())
275 .map_err(|cause| Error::resource(cause, FIELD, at))?
276 .copied();
277 let mut node = Node {
278 tag: identifier(element, parent)?,
279 primitive: None,
280 length: DerLength::new(0),
281 total: 0,
282 body: Body::Children,
283 parent: owner,
284 first: None,
285 next: None,
286 };
287 let string = matches!(form, Some(Form::Octets))
288 || (tag.class() == Class::Universal
289 && matches!(tag.number(), Some(4 | 12 | 18..=22 | 25..=28 | 30)));
290 if string {
291 let number = tag
292 .number()
293 .expect("known universal or implicit string tag");
294 let octets = Octets::projection_string(
295 parent,
296 &element,
297 number,
298 tag.class() != Class::Universal,
299 FIELD,
300 )?;
301 node.primitive = Some([node.tag[0] & !32]);
302 let length = octets.len() as u64;
303 node.body = Body::String(octets);
304 finish(&mut node, length, at)?;
305 return Ok((node, None));
306 }
307 if tag == Tag::constructed(universal::BIT_STRING) {
308 return Ok((bit_node(parent, element, node)?, None));
309 }
310 if tag.is_constructed() {
311 let reader = parent
312 .enter(&element)
313 .map_err(|cause| Error::encoding(cause, FIELD))?;
314 if tag.class() == Class::Universal && !matches!(tag.number(), Some(8 | 11 | 16 | 17 | 29)) {
315 structured_pkix::der::conforms(parent, &element, FIELD).map_err(Error::pkix)?;
319 return Err(Error::schema(ErrorCode::UnsupportedEncoding, FIELD, at));
320 }
321 return Ok((
322 node,
323 Some((
324 reader,
325 matches!(form, Some(Form::Set)) || tag == Tag::constructed(universal::SET),
326 )),
327 ));
328 }
329 let mut length = element.contents().len() as u64;
330 node.body = if tag == Tag::primitive(universal::BOOLEAN) {
331 let value = parent
332 .boolean(&element)
333 .map_err(|cause| Error::encoding(cause, FIELD))?;
334 length = 1;
335 Body::Byte(if value { 255 } else { 0 })
336 } else if tag == Tag::primitive(universal::BIT_STRING) {
337 let bits = parent
338 .bit_string(&element)
339 .map_err(|cause| Error::encoding(cause, FIELD))?;
340 if bits.unused_bits() != 0 {
341 let contents = element.contents();
342 Body::Bits {
343 prefix: &contents[..contents.len() - 1],
344 last: contents[contents.len() - 1] & (255 << bits.unused_bits()),
345 }
346 } else {
347 Body::Bytes(element.contents())
348 }
349 } else {
350 let strict = parent
351 .reread(&element, Encoding::Der)
352 .map_err(|cause| Error::encoding(cause, FIELD))?;
353 if let Err(cause) = structured_pkix::der::conforms(&strict, &element, FIELD) {
354 if cause.is_resource() {
355 return Err(Error::pkix(cause));
356 }
357 structured_pkix::der::conforms(parent, &element, FIELD).map_err(Error::pkix)?;
358 return Err(Error::schema(ErrorCode::UnsupportedEncoding, FIELD, at));
359 }
360 Body::Bytes(element.contents())
361 };
362 finish(&mut node, length, at)?;
363 Ok((node, None))
364}
365fn bit_node<'d>(
366 parent: &structured_asn1::ScopedReader<'d, '_>,
367 element: Element<'d>,
368 mut node: Node<'d>,
369) -> Result<Node<'d>> {
370 let at = element.span().start;
371 let work = parent.execution();
372 let mut pieces = work.vector();
373 let mut unused = 0u8;
374 let mut last = None;
375 let mut length = 1u64;
376 structured_pkix::der::bit_fragments(parent, &element, FIELD, |fragment, bits| {
377 let bytes = bits.as_bytes();
378 unused = bits.unused_bits();
379 length = length.checked_add(bytes.len() as u64).ok_or_else(|| {
380 structured_pkix::Error::new(
381 structured_pkix::ErrorCode::MalformedValue,
382 FIELD,
383 fragment.span().start,
384 )
385 })?;
386 let bytes = if unused == 0 {
387 bytes
388 } else {
389 last = Some(bytes[bytes.len() - 1] & (255 << unused));
390 &bytes[..bytes.len() - 1]
391 };
392 pieces
393 .try_push(bytes)
394 .map_err(|cause| structured_pkix::Error::resource(cause, FIELD, fragment.span().start))
395 })
396 .map_err(Error::pkix)?;
397 node.primitive = Some([node.tag[0] & !32]);
398 node.body = Body::Segments {
399 pieces: pieces.into_owned(),
400 unused,
401 last,
402 };
403 finish(&mut node, length, at)?;
404 Ok(node)
405}
406
407pub(crate) enum FeedError<E> {
408 Resource(MemoryError),
409 Callback(E),
410}
411#[derive(Debug)]
413pub enum ProjectionError {
414 Resource(MemoryError),
416 Receiver(Refused),
418}
419struct Cursor<'n, 'd> {
420 nodes: &'n [Node<'d>],
421 root: usize,
422 index: Option<usize>,
423 phase: u8,
424 piece: usize,
425}
426impl<'n, 'd> Cursor<'n, 'd> {
427 fn new(nodes: &'n [Node<'d>], root: usize) -> Self {
428 Self {
429 nodes,
430 root,
431 index: Some(root),
432 phase: 0,
433 piece: 0,
434 }
435 }
436 fn advance<W: Work>(
437 &mut self,
438 mut index: usize,
439 work: &W,
440 ) -> core::result::Result<(), MemoryError> {
441 loop {
442 work.charge_work(1)?;
443 if index == self.root {
444 self.index = None;
445 return Ok(());
446 }
447 if let Some(next) = self.nodes[index].next {
448 self.index = Some(next);
449 self.phase = 0;
450 self.piece = 0;
451 return Ok(());
452 }
453 index = self.nodes[index].parent.expect("non-root projection child");
454 }
455 }
456 fn next<W: Work>(&mut self, work: &W) -> core::result::Result<Option<&'n [u8]>, MemoryError> {
457 while let Some(index) = self.index {
458 work.charge_work(1)?;
459 let node = &self.nodes[index];
460 match self.phase {
461 0 => {
462 self.phase = 1;
463 return Ok(Some(
464 node.primitive.as_ref().map_or(node.tag, |tag| &tag[..]),
465 ));
466 }
467 1 => {
468 self.phase = 2;
469 return Ok(Some(node.length.as_bytes()));
470 }
471 _ => match &node.body {
472 Body::Children => {
473 if let Some(child) = node.first {
474 self.index = Some(child);
475 self.phase = 0;
476 self.piece = 0;
477 } else {
478 self.advance(index, work)?;
479 }
480 }
481 Body::Bytes(bytes) => {
482 self.advance(index, work)?;
483 return Ok(Some(bytes));
484 }
485 Body::Byte(byte) => {
486 self.advance(index, work)?;
487 return Ok(Some(core::slice::from_ref(byte)));
488 }
489 Body::Bits { prefix, last } => {
490 if self.piece == 0 {
491 self.piece = 1;
492 return Ok(Some(prefix));
493 }
494 self.advance(index, work)?;
495 return Ok(Some(core::slice::from_ref(last)));
496 }
497 Body::Segments {
498 pieces,
499 unused,
500 last,
501 } => {
502 if self.piece == 0 {
503 self.piece = 1;
504 return Ok(Some(core::slice::from_ref(unused)));
505 }
506 if let Some(bytes) = pieces.get(self.piece - 1) {
507 self.piece += 1;
508 return Ok(Some(bytes));
509 }
510 self.advance(index, work)?;
511 if let Some(last) = last {
512 return Ok(Some(core::slice::from_ref(last)));
513 }
514 }
515 Body::String(value) => {
516 if let Some(piece) = value.pieces().get(self.piece) {
517 self.piece += 1;
518 return Ok(Some(piece.as_bytes()));
519 }
520 self.advance(index, work)?;
521 }
522 },
523 }
524 }
525 Ok(None)
526 }
527}
528fn nonempty<'n, W: Work>(
529 cursor: &mut Cursor<'n, '_>,
530 work: &W,
531) -> core::result::Result<Option<&'n [u8]>, MemoryError> {
532 loop {
533 match cursor.next(work)? {
534 Some([]) => {}
535 other => return Ok(other),
536 }
537 }
538}
539fn compare<W: Work>(
540 nodes: &[Node<'_>],
541 a: usize,
542 b: usize,
543 work: &W,
544) -> core::result::Result<Ordering, MemoryError> {
545 let mut left = Cursor::new(nodes, a);
546 let mut right = Cursor::new(nodes, b);
547 let mut a = &[][..];
548 let mut b = &[][..];
549 loop {
550 if a.is_empty() {
551 a = match nonempty(&mut left, work)? {
552 Some(bytes) => bytes,
553 None => {
554 return Ok(if b.is_empty() && nonempty(&mut right, work)?.is_none() {
555 Ordering::Equal
556 } else {
557 Ordering::Less
558 });
559 }
560 };
561 }
562 if b.is_empty() {
563 b = match nonempty(&mut right, work)? {
564 Some(bytes) => bytes,
565 None => return Ok(Ordering::Greater),
566 };
567 }
568 let length = a.len().min(b.len());
569 work.charge_work(1 + length as u64)?;
570 let order = a[..length].cmp(&b[..length]);
571 if order != Ordering::Equal {
572 return Ok(order);
573 }
574 a = &a[length..];
575 b = &b[length..];
576 }
577}
578fn sort_children<W: Work>(nodes: &mut [Node<'_>], parent: usize, work: &W, at: u64) -> Result<()> {
579 let resource = |cause| Error::resource(cause, FIELD, at);
580 let mut indices = work.vector();
581 let mut next = nodes[parent].first;
582 while let Some(index) = next {
583 indices.try_push(index).map_err(resource)?;
584 next = nodes[index].next;
585 }
586 indices
587 .try_sort_unstable_by(|a, b| compare(nodes, *a, *b, work))
588 .map_err(|cause| match cause {
589 SortError::Resource(cause) | SortError::Comparison(cause) => resource(cause),
590 })?;
591 nodes[parent].first = indices.first().copied();
592 for (ordinal, index) in indices.iter().enumerate() {
593 work.charge_work(1).map_err(resource)?;
594 nodes[*index].next = indices.get(ordinal + 1).copied();
595 }
596 Ok(())
597}
598
599pub struct DerFields<'d> {
602 values: OwnedVec<Projection<'d>>,
603}
604impl Source for DerFields<'_> {
605 type Error = ProjectionError;
606 fn stream<W: Work>(
607 &mut self,
608 out: &mut impl Receiver,
609 work: &W,
610 ) -> core::result::Result<(), Self::Error> {
611 for value in &self.values {
612 work.charge_work(1).map_err(ProjectionError::Resource)?;
613 value.write(out, work)?;
614 }
615 Ok(())
616 }
617}
618impl<'d> crate::signer::Fields<'d> {
619 pub fn identity_der(
621 &self,
622 parent: &structured_asn1::ScopedReader<'d, '_>,
623 ) -> Result<DerFields<'d>> {
624 self.project(parent, &self.identity, self.identity[2])
625 }
626 pub fn signature_der(
629 &self,
630 parent: &structured_asn1::ScopedReader<'d, '_>,
631 ) -> Result<DerFields<'d>> {
632 self.project(parent, &self.signature, self.signature[0])
633 }
634 fn project(
635 &self,
636 parent: &structured_asn1::ScopedReader<'d, '_>,
637 elements: &[Element<'d>],
638 algorithm: Element<'d>,
639 ) -> Result<DerFields<'d>> {
640 parent
641 .charge(1)
642 .map_err(|cause| Error::encoding(cause, FIELD))?;
643 if !core::ptr::eq(self.parser, parent.parser()) || self.depth != parent.depth() {
644 return Err(Error::schema(
645 ErrorCode::InvalidLocation,
646 FIELD,
647 self.identity[0].span().start,
648 ));
649 }
650 let work = parent.execution();
651 let mut rules = Rules::new(&work);
652 let identifier =
653 structured_pkix::algorithm::read(parent, &algorithm, FIELD).map_err(Error::pkix)?;
654 rules.algorithm(identifier, &work)?;
655 if self.identity[1].tag().class() == Class::ContextSpecific {
656 rules.insert(self.identity[1].span(), Form::Octets, &work)?;
657 }
658 let mut values = work.vector();
659 values
660 .try_reserve_exact(elements.len())
661 .map_err(|cause| Error::resource(cause, FIELD, self.identity[0].span().start))?;
662 for element in elements {
663 values
664 .try_push(Projection::new(parent, *element, &rules)?)
665 .map_err(|cause| Error::resource(cause, FIELD, element.span().start))?;
666 }
667 Ok(DerFields {
668 values: values.into_owned(),
669 })
670 }
671}
672
673#[cfg(test)]
674mod tests;