1use crate::error::{Error, ErrorCode, Located, Result};
9use core::num::NonZeroUsize;
10use structured_asn1::memory::{Memory, Work};
11use structured_asn1::{Element, Encoding, Oid, Parser, Reader, ScopedReader, Span, Tag, universal};
12
13pub mod digest;
14pub mod ml_dsa;
15pub mod pss;
16pub mod signature;
17
18#[derive(Debug, Clone, Copy)]
20pub struct AlgorithmIdentifier<'a> {
21 algorithm: Oid<'a>,
22 parameter_start: Option<NonZeroUsize>,
25 null_parameter: bool,
26 der: &'a [u8],
27 offset: u64,
28 field: &'static str,
29 parser: &'a Parser,
30 outer: u32,
31 encoding: Encoding,
32 indefinite: bool,
33}
34
35#[derive(Debug, Clone, Copy)]
38pub struct Producer<'a> {
39 parser: &'a Parser,
40}
41impl<'a> Producer<'a> {
42 #[must_use]
44 pub fn execution_in<'q, W: Work>(&self, work: &'q W) -> structured_asn1::memory::Execution<'q>
45 where
46 'a: 'q,
47 {
48 work.execution_for(self.parser)
49 }
50}
51
52#[derive(Debug, Clone, Copy)]
56pub(crate) struct Nested<'a> {
57 bytes: &'a [u8],
58 at: u64,
59 parser: &'a Parser,
60 outer: u32,
61 encoding: Encoding,
62}
63
64impl<'a> Nested<'a> {
65 pub(crate) fn execution_origin(self) -> Producer<'a> {
66 Producer {
67 parser: self.parser,
68 }
69 }
70
71 pub(crate) fn encoding(self) -> Encoding {
72 self.encoding
73 }
74 pub(crate) fn execution_in<'q, W: Work>(
75 self,
76 work: &'q W,
77 ) -> structured_asn1::memory::Execution<'q>
78 where
79 'a: 'q,
80 {
81 work.execution_for(self.parser)
82 }
83
84 pub(crate) fn offset(self) -> u64 {
86 self.at
87 }
88
89 pub(crate) fn as_bytes(self) -> &'a [u8] {
90 self.bytes
91 }
92
93 pub(crate) fn open<'operation, W: Work>(
96 self,
97 execution: &'operation W,
98 field: &'static str,
99 ) -> Result<(ScopedReader<'a, 'operation>, Element<'a>)>
100 where
101 'a: 'operation,
102 {
103 let mut reader = execution
104 .read_scoped_nested(self.parser, self.bytes, self.at, self.encoding, self.outer)
105 .field(field)?;
106 let element = reader
107 .next_element()
108 .field(field)?
109 .ok_or_else(|| Error::new(ErrorCode::MissingField, field, reader.offset()))?;
110 if !reader.is_empty() {
111 return Err(Error::new(ErrorCode::TrailingData, field, reader.offset()));
112 }
113 Ok((reader, element))
114 }
115}
116
117#[derive(Debug, Clone, Copy)]
120struct AlgorithmFields<'a> {
121 algorithm: Oid<'a>,
122 parameter_start: Option<NonZeroUsize>,
123 null_parameter: bool,
124 der: &'a [u8],
125 offset: u64,
126 field: &'static str,
127 parser: &'a Parser,
128 outer: u32,
129 encoding: Encoding,
130 indefinite: bool,
131}
132
133#[derive(Debug)]
147pub struct AlgorithmReading<'a> {
148 fields: AlgorithmFields<'a>,
149 fault: Option<Error>,
150}
151
152impl<'a> AlgorithmReading<'a> {
153 #[must_use]
155 pub fn algorithm(&self) -> Oid<'a> {
156 self.fields.algorithm
157 }
158
159 #[must_use]
161 pub fn parameters(&self) -> Option<&'a [u8]> {
162 parameter_bytes(
163 self.fields.der,
164 self.fields.parameter_start,
165 self.fields.indefinite,
166 )
167 }
168
169 #[must_use]
172 pub fn parameters_span(&self) -> Option<Span> {
173 let start = self.fields.parameter_start?.get();
174 Some(Span {
175 start: self.fields.offset + start as u64,
176 length: self.parameters()?.len() as u64,
177 })
178 }
179
180 #[must_use]
183 pub fn has_null_parameter(&self) -> bool {
184 self.fields.null_parameter
185 }
186
187 #[must_use]
189 pub fn as_bytes(&self) -> &'a [u8] {
190 self.fields.der
191 }
192
193 #[must_use]
195 pub fn offset(&self) -> u64 {
196 self.fields.offset
197 }
198
199 #[must_use]
201 pub fn encoding(&self) -> Encoding {
202 self.fields.encoding
203 }
204
205 #[must_use]
209 pub fn same_session(&self, parent: &Reader<'_>) -> bool {
210 core::ptr::eq(self.fields.parser, parent.parser())
211 }
212
213 #[must_use]
215 pub fn fault(&self) -> Option<&Error> {
216 self.fault.as_ref()
217 }
218
219 #[must_use]
222 pub fn identifier(&self) -> Option<AlgorithmIdentifier<'a>> {
223 if self.fault.is_some() {
224 return None;
225 }
226 Some(self.fields.identifier())
227 }
228
229 pub fn require_identifier(&self) -> Result<AlgorithmIdentifier<'a>> {
233 match &self.fault {
234 Some(error) => Err(error.clone()),
235 None => Ok(self.fields.identifier()),
236 }
237 }
238
239 pub fn same_written_in(&self, other: &Self, parent: &Reader<'_>) -> Result<bool> {
244 written_matches(&self.fields, &other.fields, parent, false)
245 }
246
247 fn into_identifier(self) -> Result<AlgorithmIdentifier<'a>> {
248 match self.fault {
249 Some(error) => Err(error),
250 None => Ok(self.fields.identifier()),
251 }
252 }
253}
254
255impl<'a> AlgorithmFields<'a> {
256 fn identifier(self) -> AlgorithmIdentifier<'a> {
258 AlgorithmIdentifier {
259 algorithm: self.algorithm,
260 parameter_start: self.parameter_start,
261 null_parameter: self.null_parameter,
262 der: self.der,
263 offset: self.offset,
264 field: self.field,
265 parser: self.parser,
266 outer: self.outer,
267 encoding: self.encoding,
268 indefinite: self.indefinite,
269 }
270 }
271}
272
273fn parameter_bytes(bytes: &[u8], start: Option<NonZeroUsize>, indefinite: bool) -> Option<&[u8]> {
274 let start = start?.get();
275 let end = bytes.len() - if indefinite { 2 } else { 0 };
276 Some(&bytes[start..end])
277}
278
279trait WrittenValue {
280 fn oid_bytes(&self) -> &[u8];
281 fn parameter_bytes(&self) -> Option<&[u8]>;
282 fn valid_null(&self) -> bool;
283 fn producer(&self) -> &Parser;
284 fn field(&self) -> &'static str;
285 fn offset(&self) -> u64;
286}
287
288impl WrittenValue for AlgorithmFields<'_> {
289 fn oid_bytes(&self) -> &[u8] {
290 self.algorithm.as_bytes()
291 }
292 fn parameter_bytes(&self) -> Option<&[u8]> {
293 parameter_bytes(self.der, self.parameter_start, self.indefinite)
294 }
295 fn valid_null(&self) -> bool {
296 self.null_parameter
297 }
298 fn producer(&self) -> &Parser {
299 self.parser
300 }
301 fn field(&self) -> &'static str {
302 self.field
303 }
304 fn offset(&self) -> u64 {
305 self.offset
306 }
307}
308
309impl WrittenValue for AlgorithmIdentifier<'_> {
310 fn oid_bytes(&self) -> &[u8] {
311 self.algorithm.as_bytes()
312 }
313 fn parameter_bytes(&self) -> Option<&[u8]> {
314 self.parameters()
315 }
316 fn valid_null(&self) -> bool {
317 self.null_parameter
318 }
319 fn producer(&self) -> &Parser {
320 self.parser
321 }
322 fn field(&self) -> &'static str {
323 self.field
324 }
325 fn offset(&self) -> u64 {
326 self.offset
327 }
328}
329
330fn require_written_parsers(
331 left: &impl WrittenValue,
332 right: &impl WrittenValue,
333 parent: &Reader<'_>,
334) -> Result<()> {
335 if !core::ptr::eq(left.producer(), parent.parser()) {
336 return Err(Error::new(
337 ErrorCode::ForeignReader,
338 left.field(),
339 left.offset(),
340 ));
341 }
342 if !core::ptr::eq(right.producer(), parent.parser()) {
343 return Err(Error::new(
344 ErrorCode::ForeignReader,
345 right.field(),
346 right.offset(),
347 ));
348 }
349 Ok(())
350}
351
352fn written_matches(
353 left: &impl WrittenValue,
354 right: &impl WrittenValue,
355 parent: &Reader<'_>,
356 defaults: bool,
357) -> Result<bool> {
358 require_written_parsers(left, right, parent)?;
359 written_values(left, right, parent, defaults)
360}
361
362fn written_values(
363 left: &impl WrittenValue,
364 right: &impl WrittenValue,
365 parent: &Reader<'_>,
366 defaults: bool,
367) -> Result<bool> {
368 let charge = |amount| {
369 parent.charge(amount).map_err(|error| {
370 Error::new(
371 ErrorCode::Encoding(error.code()),
372 right.field(),
373 right.offset(),
374 )
375 })
376 };
377 charge(1)?;
378 let kind = left.oid_bytes();
379 if kind.len() != right.oid_bytes().len() {
380 return Ok(false);
381 }
382 charge(kind.len() as u64)?;
383 if kind != right.oid_bytes() {
384 return Ok(false);
385 }
386 if defaults || (left.valid_null() && right.valid_null()) {
387 return Ok(true);
388 }
389 let (Some(first), Some(second)) = (left.parameter_bytes(), right.parameter_bytes()) else {
390 return Ok(left.parameter_bytes().is_none() && right.parameter_bytes().is_none());
391 };
392 if first.len() != second.len() {
393 return Ok(false);
394 }
395 charge(first.len() as u64)?;
396 Ok(first == second)
397}
398
399impl<'a> AlgorithmIdentifier<'a> {
400 #[must_use]
403 pub fn has_null_parameter(self) -> bool {
404 self.null_parameter
405 }
406
407 pub fn same_written_in(self, other: &Self, parent: &Reader<'_>) -> Result<bool> {
416 self.value_matches(other, parent, false)
417 }
418
419 pub fn digest_matches_in(self, other: &Self, parent: &Reader<'_>) -> Result<bool> {
429 self.value_matches(other, parent, true)
430 }
431
432 fn value_matches(self, other: &Self, parent: &Reader<'_>, digest: bool) -> Result<bool> {
433 require_written_parsers(&self, other, parent)?;
434 let sha2 = if digest {
435 let known = self.validate_digest_params(parent)?;
436 other.validate_digest_params(parent)?;
437 known
438 } else {
439 false
440 };
441 written_values(&self, other, parent, sha2)
442 }
443
444 fn validate_digest_params(self, parent: &Reader<'_>) -> Result<bool> {
445 let charge = |amount| {
446 parent.charge(amount).map_err(|error| {
447 Error::new(ErrorCode::Encoding(error.code()), self.field, self.offset)
448 })
449 };
450 charge(1)?;
451 let kind = self.algorithm.as_bytes();
452 if kind.len() != 9 {
453 return Ok(false);
454 }
455 charge(9)?;
456 if kind[..8] != [0x60, 0x86, 0x48, 1, 0x65, 3, 4, 2] || kind[8] < 1 || kind[8] > 4 {
457 return Ok(false);
458 }
459 if self.parameter_start.is_some() && !self.null_parameter {
460 return Err(Error::new(
464 ErrorCode::MalformedValue,
465 self.field,
466 self.offset,
467 ));
468 }
469 Ok(true)
470 }
471 #[must_use]
473 pub fn algorithm(self) -> Oid<'a> {
474 self.algorithm
475 }
476
477 #[must_use]
484 pub fn parameters(self) -> Option<&'a [u8]> {
485 parameter_bytes(self.der, self.parameter_start, self.indefinite)
486 }
487
488 #[must_use]
490 pub fn offset(self) -> u64 {
491 self.offset
492 }
493
494 #[must_use]
496 pub fn encoding(self) -> Encoding {
497 self.encoding
498 }
499
500 pub fn parameters_reader_in<'query>(
513 self,
514 parent: &Reader<'query>,
515 field: &'static str,
516 ) -> Result<Option<Reader<'query>>>
517 where
518 'a: 'query,
519 {
520 if !self.same_session(parent) {
521 return Err(Error::new(ErrorCode::ForeignReader, field, self.offset));
522 }
523 let at = self
524 .parameter_start
525 .map_or(self.offset, |start| self.offset + start.get() as u64);
526 parent
527 .execution()
528 .charge_work(1)
529 .map_err(|reason| Error::resource(reason, field, at))?;
530 let Some(parameter) = self.parameters() else {
531 return Ok(None);
532 };
533 self.parser
534 .read_nested_query_in(parent, parameter, at, self.encoding, self.outer)
535 .field(field)
536 .map(Some)
537 }
538
539 pub(crate) fn query_in<'operation, W: Work>(
541 &self,
542 execution: &'operation W,
543 ) -> structured_asn1::memory::Execution<'operation>
544 where
545 'a: 'operation,
546 {
547 execution.execution_for(self.parser)
548 }
549
550 pub(crate) fn source_parser(self) -> &'a Parser {
551 self.parser
552 }
553
554 #[must_use]
557 pub fn execution_origin(self) -> Producer<'a> {
558 Producer {
559 parser: self.parser,
560 }
561 }
562
563 pub(crate) fn parameters_nested(self) -> Option<Nested<'a>> {
565 let start = self.parameter_start?.get();
566 Some(self.nested(self.parameters()?, self.offset + start as u64))
567 }
568
569 pub(crate) fn nested(self, bytes: &'a [u8], at: u64) -> Nested<'a> {
572 Nested {
573 bytes,
574 at,
575 parser: self.parser,
576 outer: self.outer,
577 encoding: self.encoding,
578 }
579 }
580
581 #[must_use]
585 pub fn same_session(self, parent: &ScopedReader<'_, '_>) -> bool {
586 core::ptr::eq(self.parser, parent.parser())
587 }
588
589 #[must_use]
594 pub fn as_bytes(self) -> &'a [u8] {
595 self.der
596 }
597
598 #[must_use]
601 pub fn has_no_parameters(self) -> bool {
602 self.parameters().is_none() || self.null_parameter
606 }
607
608 pub fn matches(self, other: &AlgorithmIdentifier<'_>, execution: &Memory) -> Result<bool> {
649 self.matches_with(other, |work| {
650 execution
651 .charge_work(work)
652 .map_err(|reason| Error::resource(reason, self.field, self.offset))
653 })
654 }
655
656 pub(crate) fn matches_in(
657 self,
658 other: &AlgorithmIdentifier<'_>,
659 parent: &Reader<'_>,
660 ) -> Result<bool> {
661 self.matches_with(other, |work| {
662 parent.charge(work).map_err(|error| {
663 Error::new(ErrorCode::Encoding(error.code()), self.field, self.offset)
664 })
665 })
666 }
667
668 fn matches_with(
669 self,
670 other: &AlgorithmIdentifier<'_>,
671 mut charge: impl FnMut(u64) -> Result<()>,
672 ) -> Result<bool> {
673 charge(1)?;
674 if self.algorithm.as_bytes().len() != other.algorithm.as_bytes().len() {
675 return Ok(false);
676 }
677 charge(self.algorithm.as_bytes().len() as u64)?;
678 if self.algorithm != other.algorithm {
679 return Ok(false);
680 }
681 if self.has_no_parameters() && other.has_no_parameters() {
682 return Ok(true);
683 }
684 let (Some(left), Some(right)) = (self.parameters(), other.parameters()) else {
685 return Ok(false);
686 };
687 if left.len() != right.len() {
688 return Ok(false);
689 }
690 charge(left.len() as u64)?;
691 Ok(left == right)
692 }
693}
694
695pub fn read<'a>(
706 parent: &ScopedReader<'a, '_>,
707 element: &Element<'a>,
708 field: &'static str,
709) -> Result<AlgorithmIdentifier<'a>> {
710 read_tagged(
711 parent,
712 element,
713 Tag::constructed(universal::SEQUENCE),
714 field,
715 )
716}
717
718pub fn read_implicit<'a>(
727 parent: &Reader<'a>,
728 element: &Element<'a>,
729 number: u32,
730 field: &'static str,
731) -> Result<AlgorithmIdentifier<'a>> {
732 read_tagged(parent, element, Tag::context(true, number), field)
733}
734
735pub fn read_inspection<'a>(
742 parent: &Reader<'a>,
743 element: &Element<'a>,
744 field: &'static str,
745) -> Result<AlgorithmReading<'a>> {
746 read_fields::<true>(
747 parent,
748 element,
749 Tag::constructed(universal::SEQUENCE),
750 field,
751 )
752}
753
754pub fn read_implicit_inspection<'a>(
756 parent: &Reader<'a>,
757 element: &Element<'a>,
758 number: u32,
759 field: &'static str,
760) -> Result<AlgorithmReading<'a>> {
761 read_fields::<true>(parent, element, Tag::context(true, number), field)
762}
763
764fn read_fields<'a, const INSPECTION: bool>(
765 parent: &ScopedReader<'a, '_>,
766 element: &Element<'a>,
767 expected: Tag,
768 field: &'static str,
769) -> Result<AlgorithmReading<'a>> {
770 let fail = |code| Error::new(code, field, element.span().start);
771 if element.tag() != expected {
772 return Err(fail(ErrorCode::Encoding(
773 structured_asn1::ErrorCode::UnexpectedTag,
774 )));
775 }
776 let mut inside = parent.enter(element).field(field)?;
777 let algorithm = inside.read_oid().field(field)?;
778 let parameter = inside.next_element().field(field)?;
779 let mut fault = None;
780 let mut null_parameter = false;
781 if let Some(parameter) = ¶meter {
782 match crate::name::walk_der(&inside, parameter, field, crate::name::Strings::Checked) {
783 Ok(()) => {
784 null_parameter = parameter.tag() == Tag::primitive(universal::NULL);
789 }
790 Err(error) => {
791 if !INSPECTION || error.is_resource() || error.code() == ErrorCode::ForeignReader {
792 return Err(error);
793 }
794 fault = Some(error);
795 }
796 }
797 }
798 if !inside.is_empty() {
799 return Err(fail(ErrorCode::TrailingData));
800 }
801 let parameter_start = match parameter {
802 None => None,
803 Some(parameter) => {
804 let start = usize::try_from(parameter.span().start - element.span().start)
805 .map_err(|_| fail(ErrorCode::ValueTooLarge))?;
806 Some(NonZeroUsize::new(start).expect("the algorithm OID precedes its parameters"))
807 }
808 };
809 Ok(AlgorithmReading {
810 fields: AlgorithmFields {
811 algorithm,
812 parameter_start,
813 null_parameter,
814 der: element.as_bytes(),
815 offset: element.span().start,
816 field,
817 parser: parent.parser(),
818 outer: parent.depth(),
819 encoding: inside.encoding(),
820 indefinite: element.is_indefinite(),
821 },
822 fault,
823 })
824}
825
826fn read_tagged<'a>(
827 parent: &ScopedReader<'a, '_>,
828 element: &Element<'a>,
829 expected: Tag,
830 field: &'static str,
831) -> Result<AlgorithmIdentifier<'a>> {
832 read_fields::<false>(parent, element, expected, field)?.into_identifier()
833}
834
835#[cfg(test)]
836mod tests;