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 dstu4145;
15pub mod ml_dsa;
16pub mod pss;
17pub mod signature;
18
19#[derive(Debug, Clone, Copy)]
21pub struct AlgorithmIdentifier<'a> {
22 algorithm: Oid<'a>,
23 parameter_start: Option<NonZeroUsize>,
26 null_parameter: bool,
27 der: &'a [u8],
28 offset: u64,
29 field: &'static str,
30 parser: &'a Parser,
31 outer: u32,
32 encoding: Encoding,
33 indefinite: bool,
34}
35
36#[derive(Debug, Clone, Copy)]
39pub struct Producer<'a> {
40 parser: &'a Parser,
41}
42impl<'a> Producer<'a> {
43 pub(crate) const fn from_parser(parser: &'a Parser) -> Self {
44 Self { parser }
45 }
46 pub fn charge_work_in<W: Work>(
49 &self,
50 work: &W,
51 amount: u64,
52 ) -> core::result::Result<(), structured_asn1::memory::MemoryError> {
53 work.charge_work_from([self.parser, self.parser], amount)
54 }
55
56 pub fn charge_work_with<W: Work>(
59 &self,
60 other: Self,
61 work: &W,
62 amount: u64,
63 ) -> core::result::Result<(), structured_asn1::memory::MemoryError> {
64 work.charge_work_from([self.parser, other.parser], amount)
65 }
66
67 #[must_use]
69 pub fn execution_in<'q, W: Work>(&self, work: &'q W) -> structured_asn1::memory::Execution<'q>
70 where
71 'a: 'q,
72 {
73 work.execution_for(self.parser)
74 }
75}
76
77#[derive(Debug, Clone, Copy)]
81pub(crate) struct Nested<'a> {
82 bytes: &'a [u8],
83 at: u64,
84 parser: &'a Parser,
85 outer: u32,
86 encoding: Encoding,
87}
88
89impl<'a> Nested<'a> {
90 pub(crate) fn execution_origin(self) -> Producer<'a> {
91 Producer {
92 parser: self.parser,
93 }
94 }
95
96 pub(crate) fn encoding(self) -> Encoding {
97 self.encoding
98 }
99 pub(crate) fn execution_in<'q, W: Work>(
100 self,
101 work: &'q W,
102 ) -> structured_asn1::memory::Execution<'q>
103 where
104 'a: 'q,
105 {
106 work.execution_for(self.parser)
107 }
108
109 pub(crate) fn offset(self) -> u64 {
111 self.at
112 }
113
114 pub(crate) fn as_bytes(self) -> &'a [u8] {
115 self.bytes
116 }
117
118 pub(crate) fn open<'operation, W: Work>(
121 self,
122 execution: &'operation W,
123 field: &'static str,
124 ) -> Result<(ScopedReader<'a, 'operation>, Element<'a>)>
125 where
126 'a: 'operation,
127 {
128 let mut reader = execution
129 .read_scoped_nested(self.parser, self.bytes, self.at, self.encoding, self.outer)
130 .field(field)?;
131 let element = reader
132 .next_element()
133 .field(field)?
134 .ok_or_else(|| Error::new(ErrorCode::MissingField, field, reader.offset()))?;
135 if !reader.is_empty() {
136 return Err(Error::new(ErrorCode::TrailingData, field, reader.offset()));
137 }
138 Ok((reader, element))
139 }
140}
141
142#[derive(Debug, Clone, Copy)]
145struct AlgorithmFields<'a> {
146 algorithm: Oid<'a>,
147 parameter_start: Option<NonZeroUsize>,
148 null_parameter: bool,
149 der: &'a [u8],
150 offset: u64,
151 field: &'static str,
152 parser: &'a Parser,
153 outer: u32,
154 encoding: Encoding,
155 indefinite: bool,
156}
157
158#[derive(Debug)]
172pub struct AlgorithmReading<'a> {
173 fields: AlgorithmFields<'a>,
174 fault: Option<Error>,
175}
176
177impl<'a> AlgorithmReading<'a> {
178 #[must_use]
180 pub fn algorithm(&self) -> Oid<'a> {
181 self.fields.algorithm
182 }
183
184 #[must_use]
186 pub fn parameters(&self) -> Option<&'a [u8]> {
187 parameter_bytes(
188 self.fields.der,
189 self.fields.parameter_start,
190 self.fields.indefinite,
191 )
192 }
193
194 #[must_use]
197 pub fn parameters_span(&self) -> Option<Span> {
198 let start = self.fields.parameter_start?.get();
199 Some(Span {
200 start: self.fields.offset + start as u64,
201 length: self.parameters()?.len() as u64,
202 })
203 }
204
205 #[must_use]
208 pub fn has_null_parameter(&self) -> bool {
209 self.fields.null_parameter
210 }
211
212 #[must_use]
214 pub fn as_bytes(&self) -> &'a [u8] {
215 self.fields.der
216 }
217
218 #[must_use]
220 pub fn offset(&self) -> u64 {
221 self.fields.offset
222 }
223
224 #[must_use]
226 pub fn encoding(&self) -> Encoding {
227 self.fields.encoding
228 }
229
230 #[must_use]
234 pub fn same_session(&self, parent: &Reader<'_>) -> bool {
235 core::ptr::eq(self.fields.parser, parent.parser())
236 }
237
238 #[must_use]
240 pub fn fault(&self) -> Option<&Error> {
241 self.fault.as_ref()
242 }
243
244 #[must_use]
247 pub fn identifier(&self) -> Option<AlgorithmIdentifier<'a>> {
248 if self.fault.is_some() {
249 return None;
250 }
251 Some(self.fields.identifier())
252 }
253
254 pub fn require_identifier(&self) -> Result<AlgorithmIdentifier<'a>> {
258 match &self.fault {
259 Some(error) => Err(error.clone()),
260 None => Ok(self.fields.identifier()),
261 }
262 }
263
264 pub fn same_written_in(&self, other: &Self, parent: &Reader<'_>) -> Result<bool> {
269 written_matches(&self.fields, &other.fields, parent, false)
270 }
271
272 fn into_identifier(self) -> Result<AlgorithmIdentifier<'a>> {
273 match self.fault {
274 Some(error) => Err(error),
275 None => Ok(self.fields.identifier()),
276 }
277 }
278}
279
280impl<'a> AlgorithmFields<'a> {
281 fn identifier(self) -> AlgorithmIdentifier<'a> {
283 AlgorithmIdentifier {
284 algorithm: self.algorithm,
285 parameter_start: self.parameter_start,
286 null_parameter: self.null_parameter,
287 der: self.der,
288 offset: self.offset,
289 field: self.field,
290 parser: self.parser,
291 outer: self.outer,
292 encoding: self.encoding,
293 indefinite: self.indefinite,
294 }
295 }
296}
297
298fn parameter_bytes(bytes: &[u8], start: Option<NonZeroUsize>, indefinite: bool) -> Option<&[u8]> {
299 let start = start?.get();
300 let end = bytes.len() - if indefinite { 2 } else { 0 };
301 Some(&bytes[start..end])
302}
303
304trait WrittenValue {
305 fn oid_bytes(&self) -> &[u8];
306 fn parameter_bytes(&self) -> Option<&[u8]>;
307 fn valid_null(&self) -> bool;
308 fn producer(&self) -> &Parser;
309 fn field(&self) -> &'static str;
310 fn offset(&self) -> u64;
311}
312
313impl WrittenValue for AlgorithmFields<'_> {
314 fn oid_bytes(&self) -> &[u8] {
315 self.algorithm.as_bytes()
316 }
317 fn parameter_bytes(&self) -> Option<&[u8]> {
318 parameter_bytes(self.der, self.parameter_start, self.indefinite)
319 }
320 fn valid_null(&self) -> bool {
321 self.null_parameter
322 }
323 fn producer(&self) -> &Parser {
324 self.parser
325 }
326 fn field(&self) -> &'static str {
327 self.field
328 }
329 fn offset(&self) -> u64 {
330 self.offset
331 }
332}
333
334impl WrittenValue for AlgorithmIdentifier<'_> {
335 fn oid_bytes(&self) -> &[u8] {
336 self.algorithm.as_bytes()
337 }
338 fn parameter_bytes(&self) -> Option<&[u8]> {
339 self.parameters()
340 }
341 fn valid_null(&self) -> bool {
342 self.null_parameter
343 }
344 fn producer(&self) -> &Parser {
345 self.parser
346 }
347 fn field(&self) -> &'static str {
348 self.field
349 }
350 fn offset(&self) -> u64 {
351 self.offset
352 }
353}
354
355fn require_written_parsers(
356 left: &impl WrittenValue,
357 right: &impl WrittenValue,
358 parent: &Reader<'_>,
359) -> Result<()> {
360 if !core::ptr::eq(left.producer(), parent.parser()) {
361 return Err(Error::new(
362 ErrorCode::ForeignReader,
363 left.field(),
364 left.offset(),
365 ));
366 }
367 if !core::ptr::eq(right.producer(), parent.parser()) {
368 return Err(Error::new(
369 ErrorCode::ForeignReader,
370 right.field(),
371 right.offset(),
372 ));
373 }
374 Ok(())
375}
376
377fn written_matches(
378 left: &impl WrittenValue,
379 right: &impl WrittenValue,
380 parent: &Reader<'_>,
381 defaults: bool,
382) -> Result<bool> {
383 require_written_parsers(left, right, parent)?;
384 written_values(left, right, parent, defaults)
385}
386
387fn written_values(
388 left: &impl WrittenValue,
389 right: &impl WrittenValue,
390 parent: &Reader<'_>,
391 defaults: bool,
392) -> Result<bool> {
393 let charge = |amount| {
394 parent.charge(amount).map_err(|error| {
395 Error::new(
396 ErrorCode::Encoding(error.code()),
397 right.field(),
398 right.offset(),
399 )
400 })
401 };
402 charge(1)?;
403 let kind = left.oid_bytes();
404 if kind.len() != right.oid_bytes().len() {
405 return Ok(false);
406 }
407 charge(kind.len() as u64)?;
408 if kind != right.oid_bytes() {
409 return Ok(false);
410 }
411 if defaults || (left.valid_null() && right.valid_null()) {
412 return Ok(true);
413 }
414 let (Some(first), Some(second)) = (left.parameter_bytes(), right.parameter_bytes()) else {
415 return Ok(left.parameter_bytes().is_none() && right.parameter_bytes().is_none());
416 };
417 if first.len() != second.len() {
418 return Ok(false);
419 }
420 charge(first.len() as u64)?;
421 Ok(first == second)
422}
423
424impl<'a> AlgorithmIdentifier<'a> {
425 #[must_use]
428 pub fn has_null_parameter(self) -> bool {
429 self.null_parameter
430 }
431
432 pub fn same_written_in(self, other: &Self, parent: &Reader<'_>) -> Result<bool> {
441 self.value_matches(other, parent, false)
442 }
443
444 pub fn digest_matches_in(self, other: &Self, parent: &Reader<'_>) -> Result<bool> {
454 self.value_matches(other, parent, true)
455 }
456
457 fn value_matches(self, other: &Self, parent: &Reader<'_>, digest: bool) -> Result<bool> {
458 require_written_parsers(&self, other, parent)?;
459 let sha2 = if digest {
460 let known = self.validate_digest_params(parent)?;
461 other.validate_digest_params(parent)?;
462 known
463 } else {
464 false
465 };
466 written_values(&self, other, parent, sha2)
467 }
468
469 fn validate_digest_params(self, parent: &Reader<'_>) -> Result<bool> {
470 let charge = |amount| {
471 parent.charge(amount).map_err(|error| {
472 Error::new(ErrorCode::Encoding(error.code()), self.field, self.offset)
473 })
474 };
475 charge(1)?;
476 let kind = self.algorithm.as_bytes();
477 if kind.len() != 9 {
478 return Ok(false);
479 }
480 charge(9)?;
481 if kind[..8] != [0x60, 0x86, 0x48, 1, 0x65, 3, 4, 2] || kind[8] < 1 || kind[8] > 4 {
482 return Ok(false);
483 }
484 if self.parameter_start.is_some() && !self.null_parameter {
485 return Err(Error::new(
489 ErrorCode::MalformedValue,
490 self.field,
491 self.offset,
492 ));
493 }
494 Ok(true)
495 }
496 #[must_use]
498 pub fn algorithm(self) -> Oid<'a> {
499 self.algorithm
500 }
501
502 #[must_use]
509 pub fn parameters(self) -> Option<&'a [u8]> {
510 parameter_bytes(self.der, self.parameter_start, self.indefinite)
511 }
512
513 #[must_use]
515 pub fn offset(self) -> u64 {
516 self.offset
517 }
518
519 #[must_use]
521 pub fn encoding(self) -> Encoding {
522 self.encoding
523 }
524
525 pub fn parameters_reader_in<'query>(
538 self,
539 parent: &Reader<'query>,
540 field: &'static str,
541 ) -> Result<Option<Reader<'query>>>
542 where
543 'a: 'query,
544 {
545 if !self.same_session(parent) {
546 return Err(Error::new(ErrorCode::ForeignReader, field, self.offset));
547 }
548 let at = self
549 .parameter_start
550 .map_or(self.offset, |start| self.offset + start.get() as u64);
551 parent
552 .execution()
553 .charge_work(1)
554 .map_err(|reason| Error::resource(reason, field, at))?;
555 let Some(parameter) = self.parameters() else {
556 return Ok(None);
557 };
558 self.parser
559 .read_nested_query_in(parent, parameter, at, self.encoding, self.outer)
560 .field(field)
561 .map(Some)
562 }
563
564 pub(crate) fn query_in<'operation, W: Work>(
566 &self,
567 execution: &'operation W,
568 ) -> structured_asn1::memory::Execution<'operation>
569 where
570 'a: 'operation,
571 {
572 execution.execution_for(self.parser)
573 }
574
575 pub(crate) fn source_parser(self) -> &'a Parser {
576 self.parser
577 }
578
579 #[must_use]
582 pub fn execution_origin(self) -> Producer<'a> {
583 Producer {
584 parser: self.parser,
585 }
586 }
587
588 pub(crate) fn parameters_nested(self) -> Option<Nested<'a>> {
590 let start = self.parameter_start?.get();
591 Some(self.nested(self.parameters()?, self.offset + start as u64))
592 }
593
594 pub(crate) fn nested(self, bytes: &'a [u8], at: u64) -> Nested<'a> {
597 Nested {
598 bytes,
599 at,
600 parser: self.parser,
601 outer: self.outer,
602 encoding: self.encoding,
603 }
604 }
605
606 #[must_use]
610 pub fn same_session(self, parent: &ScopedReader<'_, '_>) -> bool {
611 core::ptr::eq(self.parser, parent.parser())
612 }
613
614 #[must_use]
619 pub fn as_bytes(self) -> &'a [u8] {
620 self.der
621 }
622
623 #[must_use]
626 pub fn has_no_parameters(self) -> bool {
627 self.parameters().is_none() || self.null_parameter
631 }
632
633 pub fn matches(self, other: &AlgorithmIdentifier<'_>, execution: &Memory) -> Result<bool> {
674 self.matches_with(other, |work| {
675 execution
676 .charge_work(work)
677 .map_err(|reason| Error::resource(reason, self.field, self.offset))
678 })
679 }
680
681 pub(crate) fn matches_in(
682 self,
683 other: &AlgorithmIdentifier<'_>,
684 parent: &Reader<'_>,
685 ) -> Result<bool> {
686 self.matches_with(other, |work| {
687 parent.charge(work).map_err(|error| {
688 Error::new(ErrorCode::Encoding(error.code()), self.field, self.offset)
689 })
690 })
691 }
692
693 fn matches_with(
694 self,
695 other: &AlgorithmIdentifier<'_>,
696 mut charge: impl FnMut(u64) -> Result<()>,
697 ) -> Result<bool> {
698 charge(1)?;
699 if self.algorithm.as_bytes().len() != other.algorithm.as_bytes().len() {
700 return Ok(false);
701 }
702 charge(self.algorithm.as_bytes().len() as u64)?;
703 if self.algorithm != other.algorithm {
704 return Ok(false);
705 }
706 if self.has_no_parameters() && other.has_no_parameters() {
707 return Ok(true);
708 }
709 let (Some(left), Some(right)) = (self.parameters(), other.parameters()) else {
710 return Ok(false);
711 };
712 if left.len() != right.len() {
713 return Ok(false);
714 }
715 charge(left.len() as u64)?;
716 Ok(left == right)
717 }
718}
719
720pub fn read<'a>(
731 parent: &ScopedReader<'a, '_>,
732 element: &Element<'a>,
733 field: &'static str,
734) -> Result<AlgorithmIdentifier<'a>> {
735 read_tagged(
736 parent,
737 element,
738 Tag::constructed(universal::SEQUENCE),
739 field,
740 )
741}
742
743pub fn read_implicit<'a>(
752 parent: &Reader<'a>,
753 element: &Element<'a>,
754 number: u32,
755 field: &'static str,
756) -> Result<AlgorithmIdentifier<'a>> {
757 read_tagged(parent, element, Tag::context(true, number), field)
758}
759
760pub fn read_inspection<'a>(
767 parent: &Reader<'a>,
768 element: &Element<'a>,
769 field: &'static str,
770) -> Result<AlgorithmReading<'a>> {
771 read_fields::<true>(
772 parent,
773 element,
774 Tag::constructed(universal::SEQUENCE),
775 field,
776 )
777}
778
779pub fn read_implicit_inspection<'a>(
781 parent: &Reader<'a>,
782 element: &Element<'a>,
783 number: u32,
784 field: &'static str,
785) -> Result<AlgorithmReading<'a>> {
786 read_fields::<true>(parent, element, Tag::context(true, number), field)
787}
788
789fn read_fields<'a, const INSPECTION: bool>(
790 parent: &ScopedReader<'a, '_>,
791 element: &Element<'a>,
792 expected: Tag,
793 field: &'static str,
794) -> Result<AlgorithmReading<'a>> {
795 let fail = |code| Error::new(code, field, element.span().start);
796 if element.tag() != expected {
797 return Err(fail(ErrorCode::Encoding(
798 structured_asn1::ErrorCode::UnexpectedTag,
799 )));
800 }
801 let mut inside = parent.enter(element).field(field)?;
802 let algorithm = inside.read_oid().field(field)?;
803 let parameter = inside.next_element().field(field)?;
804 let mut fault = None;
805 let mut null_parameter = false;
806 if let Some(parameter) = ¶meter {
807 match crate::name::walk_der(&inside, parameter, field, crate::name::Strings::Checked) {
808 Ok(()) => {
809 null_parameter = parameter.tag() == Tag::primitive(universal::NULL);
814 }
815 Err(error) => {
816 if !INSPECTION || error.is_resource() || error.code() == ErrorCode::ForeignReader {
817 return Err(error);
818 }
819 fault = Some(error);
820 }
821 }
822 }
823 if !inside.is_empty() {
824 return Err(fail(ErrorCode::TrailingData));
825 }
826 let parameter_start = match parameter {
827 None => None,
828 Some(parameter) => {
829 let start = usize::try_from(parameter.span().start - element.span().start)
830 .map_err(|_| fail(ErrorCode::ValueTooLarge))?;
831 Some(NonZeroUsize::new(start).expect("the algorithm OID precedes its parameters"))
832 }
833 };
834 Ok(AlgorithmReading {
835 fields: AlgorithmFields {
836 algorithm,
837 parameter_start,
838 null_parameter,
839 der: element.as_bytes(),
840 offset: element.span().start,
841 field,
842 parser: parent.parser(),
843 outer: parent.depth(),
844 encoding: inside.encoding(),
845 indefinite: element.is_indefinite(),
846 },
847 fault,
848 })
849}
850
851fn read_tagged<'a>(
852 parent: &ScopedReader<'a, '_>,
853 element: &Element<'a>,
854 expected: Tag,
855 field: &'static str,
856) -> Result<AlgorithmIdentifier<'a>> {
857 read_fields::<false>(parent, element, expected, field)?.into_identifier()
858}
859
860#[cfg(test)]
861mod tests;