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 encoding(self) -> Encoding {
66 self.encoding
67 }
68 pub(crate) fn execution_in<'q, W: Work>(
69 self,
70 work: &'q W,
71 ) -> structured_asn1::memory::Execution<'q>
72 where
73 'a: 'q,
74 {
75 work.execution_for(self.parser)
76 }
77
78 pub(crate) fn offset(self) -> u64 {
80 self.at
81 }
82
83 pub(crate) fn as_bytes(self) -> &'a [u8] {
84 self.bytes
85 }
86
87 pub(crate) fn open<'operation, W: Work>(
90 self,
91 execution: &'operation W,
92 field: &'static str,
93 ) -> Result<(ScopedReader<'a, 'operation>, Element<'a>)>
94 where
95 'a: 'operation,
96 {
97 let mut reader = execution
98 .read_scoped_nested(self.parser, self.bytes, self.at, self.encoding, self.outer)
99 .field(field)?;
100 let element = reader
101 .next_element()
102 .field(field)?
103 .ok_or_else(|| Error::new(ErrorCode::MissingField, field, reader.offset()))?;
104 if !reader.is_empty() {
105 return Err(Error::new(ErrorCode::TrailingData, field, reader.offset()));
106 }
107 Ok((reader, element))
108 }
109}
110
111#[derive(Debug, Clone, Copy)]
114struct AlgorithmFields<'a> {
115 algorithm: Oid<'a>,
116 parameter_start: Option<NonZeroUsize>,
117 null_parameter: bool,
118 der: &'a [u8],
119 offset: u64,
120 field: &'static str,
121 parser: &'a Parser,
122 outer: u32,
123 encoding: Encoding,
124 indefinite: bool,
125}
126
127#[derive(Debug)]
141pub struct AlgorithmReading<'a> {
142 fields: AlgorithmFields<'a>,
143 fault: Option<Error>,
144}
145
146impl<'a> AlgorithmReading<'a> {
147 #[must_use]
149 pub fn algorithm(&self) -> Oid<'a> {
150 self.fields.algorithm
151 }
152
153 #[must_use]
155 pub fn parameters(&self) -> Option<&'a [u8]> {
156 parameter_bytes(
157 self.fields.der,
158 self.fields.parameter_start,
159 self.fields.indefinite,
160 )
161 }
162
163 #[must_use]
166 pub fn parameters_span(&self) -> Option<Span> {
167 let start = self.fields.parameter_start?.get();
168 Some(Span {
169 start: self.fields.offset + start as u64,
170 length: self.parameters()?.len() as u64,
171 })
172 }
173
174 #[must_use]
177 pub fn has_null_parameter(&self) -> bool {
178 self.fields.null_parameter
179 }
180
181 #[must_use]
183 pub fn as_bytes(&self) -> &'a [u8] {
184 self.fields.der
185 }
186
187 #[must_use]
189 pub fn offset(&self) -> u64 {
190 self.fields.offset
191 }
192
193 #[must_use]
195 pub fn encoding(&self) -> Encoding {
196 self.fields.encoding
197 }
198
199 #[must_use]
203 pub fn same_session(&self, parent: &Reader<'_>) -> bool {
204 core::ptr::eq(self.fields.parser, parent.parser())
205 }
206
207 #[must_use]
209 pub fn fault(&self) -> Option<&Error> {
210 self.fault.as_ref()
211 }
212
213 #[must_use]
216 pub fn identifier(&self) -> Option<AlgorithmIdentifier<'a>> {
217 if self.fault.is_some() {
218 return None;
219 }
220 Some(self.fields.identifier())
221 }
222
223 pub fn require_identifier(&self) -> Result<AlgorithmIdentifier<'a>> {
227 match &self.fault {
228 Some(error) => Err(error.clone()),
229 None => Ok(self.fields.identifier()),
230 }
231 }
232
233 pub fn same_written_in(&self, other: &Self, parent: &Reader<'_>) -> Result<bool> {
238 written_matches(&self.fields, &other.fields, parent, false)
239 }
240
241 fn into_identifier(self) -> Result<AlgorithmIdentifier<'a>> {
242 match self.fault {
243 Some(error) => Err(error),
244 None => Ok(self.fields.identifier()),
245 }
246 }
247}
248
249impl<'a> AlgorithmFields<'a> {
250 fn identifier(self) -> AlgorithmIdentifier<'a> {
252 AlgorithmIdentifier {
253 algorithm: self.algorithm,
254 parameter_start: self.parameter_start,
255 null_parameter: self.null_parameter,
256 der: self.der,
257 offset: self.offset,
258 field: self.field,
259 parser: self.parser,
260 outer: self.outer,
261 encoding: self.encoding,
262 indefinite: self.indefinite,
263 }
264 }
265}
266
267fn parameter_bytes(bytes: &[u8], start: Option<NonZeroUsize>, indefinite: bool) -> Option<&[u8]> {
268 let start = start?.get();
269 let end = bytes.len() - if indefinite { 2 } else { 0 };
270 Some(&bytes[start..end])
271}
272
273trait WrittenValue {
274 fn oid_bytes(&self) -> &[u8];
275 fn parameter_bytes(&self) -> Option<&[u8]>;
276 fn valid_null(&self) -> bool;
277 fn producer(&self) -> &Parser;
278 fn field(&self) -> &'static str;
279 fn offset(&self) -> u64;
280}
281
282impl WrittenValue for AlgorithmFields<'_> {
283 fn oid_bytes(&self) -> &[u8] {
284 self.algorithm.as_bytes()
285 }
286 fn parameter_bytes(&self) -> Option<&[u8]> {
287 parameter_bytes(self.der, self.parameter_start, self.indefinite)
288 }
289 fn valid_null(&self) -> bool {
290 self.null_parameter
291 }
292 fn producer(&self) -> &Parser {
293 self.parser
294 }
295 fn field(&self) -> &'static str {
296 self.field
297 }
298 fn offset(&self) -> u64 {
299 self.offset
300 }
301}
302
303impl WrittenValue for AlgorithmIdentifier<'_> {
304 fn oid_bytes(&self) -> &[u8] {
305 self.algorithm.as_bytes()
306 }
307 fn parameter_bytes(&self) -> Option<&[u8]> {
308 self.parameters()
309 }
310 fn valid_null(&self) -> bool {
311 self.null_parameter
312 }
313 fn producer(&self) -> &Parser {
314 self.parser
315 }
316 fn field(&self) -> &'static str {
317 self.field
318 }
319 fn offset(&self) -> u64 {
320 self.offset
321 }
322}
323
324fn require_written_parsers(
325 left: &impl WrittenValue,
326 right: &impl WrittenValue,
327 parent: &Reader<'_>,
328) -> Result<()> {
329 if !core::ptr::eq(left.producer(), parent.parser()) {
330 return Err(Error::new(
331 ErrorCode::ForeignReader,
332 left.field(),
333 left.offset(),
334 ));
335 }
336 if !core::ptr::eq(right.producer(), parent.parser()) {
337 return Err(Error::new(
338 ErrorCode::ForeignReader,
339 right.field(),
340 right.offset(),
341 ));
342 }
343 Ok(())
344}
345
346fn written_matches(
347 left: &impl WrittenValue,
348 right: &impl WrittenValue,
349 parent: &Reader<'_>,
350 defaults: bool,
351) -> Result<bool> {
352 require_written_parsers(left, right, parent)?;
353 written_values(left, right, parent, defaults)
354}
355
356fn written_values(
357 left: &impl WrittenValue,
358 right: &impl WrittenValue,
359 parent: &Reader<'_>,
360 defaults: bool,
361) -> Result<bool> {
362 let charge = |amount| {
363 parent.charge(amount).map_err(|error| {
364 Error::new(
365 ErrorCode::Encoding(error.code()),
366 right.field(),
367 right.offset(),
368 )
369 })
370 };
371 charge(1)?;
372 let kind = left.oid_bytes();
373 if kind.len() != right.oid_bytes().len() {
374 return Ok(false);
375 }
376 charge(kind.len() as u64)?;
377 if kind != right.oid_bytes() {
378 return Ok(false);
379 }
380 if defaults || (left.valid_null() && right.valid_null()) {
381 return Ok(true);
382 }
383 let (Some(first), Some(second)) = (left.parameter_bytes(), right.parameter_bytes()) else {
384 return Ok(left.parameter_bytes().is_none() && right.parameter_bytes().is_none());
385 };
386 if first.len() != second.len() {
387 return Ok(false);
388 }
389 charge(first.len() as u64)?;
390 Ok(first == second)
391}
392
393impl<'a> AlgorithmIdentifier<'a> {
394 #[must_use]
397 pub fn has_null_parameter(self) -> bool {
398 self.null_parameter
399 }
400
401 pub fn same_written_in(self, other: &Self, parent: &Reader<'_>) -> Result<bool> {
410 self.value_matches(other, parent, false)
411 }
412
413 pub fn digest_matches_in(self, other: &Self, parent: &Reader<'_>) -> Result<bool> {
423 self.value_matches(other, parent, true)
424 }
425
426 fn value_matches(self, other: &Self, parent: &Reader<'_>, digest: bool) -> Result<bool> {
427 require_written_parsers(&self, other, parent)?;
428 let sha2 = if digest {
429 let known = self.validate_digest_params(parent)?;
430 other.validate_digest_params(parent)?;
431 known
432 } else {
433 false
434 };
435 written_values(&self, other, parent, sha2)
436 }
437
438 fn validate_digest_params(self, parent: &Reader<'_>) -> Result<bool> {
439 let charge = |amount| {
440 parent.charge(amount).map_err(|error| {
441 Error::new(ErrorCode::Encoding(error.code()), self.field, self.offset)
442 })
443 };
444 charge(1)?;
445 let kind = self.algorithm.as_bytes();
446 if kind.len() != 9 {
447 return Ok(false);
448 }
449 charge(9)?;
450 if kind[..8] != [0x60, 0x86, 0x48, 1, 0x65, 3, 4, 2] || kind[8] < 1 || kind[8] > 4 {
451 return Ok(false);
452 }
453 if self.parameter_start.is_some() && !self.null_parameter {
454 return Err(Error::new(
458 ErrorCode::MalformedValue,
459 self.field,
460 self.offset,
461 ));
462 }
463 Ok(true)
464 }
465 #[must_use]
467 pub fn algorithm(self) -> Oid<'a> {
468 self.algorithm
469 }
470
471 #[must_use]
478 pub fn parameters(self) -> Option<&'a [u8]> {
479 parameter_bytes(self.der, self.parameter_start, self.indefinite)
480 }
481
482 #[must_use]
484 pub fn offset(self) -> u64 {
485 self.offset
486 }
487
488 #[must_use]
490 pub fn encoding(self) -> Encoding {
491 self.encoding
492 }
493
494 pub fn parameters_reader_in<'query>(
507 self,
508 parent: &Reader<'query>,
509 field: &'static str,
510 ) -> Result<Option<Reader<'query>>>
511 where
512 'a: 'query,
513 {
514 if !self.same_session(parent) {
515 return Err(Error::new(ErrorCode::ForeignReader, field, self.offset));
516 }
517 let at = self
518 .parameter_start
519 .map_or(self.offset, |start| self.offset + start.get() as u64);
520 parent
521 .execution()
522 .charge_work(1)
523 .map_err(|reason| Error::resource(reason, field, at))?;
524 let Some(parameter) = self.parameters() else {
525 return Ok(None);
526 };
527 self.parser
528 .read_nested_query_in(parent, parameter, at, self.encoding, self.outer)
529 .field(field)
530 .map(Some)
531 }
532
533 pub(crate) fn query_in<'operation, W: Work>(
535 &self,
536 execution: &'operation W,
537 ) -> structured_asn1::memory::Execution<'operation>
538 where
539 'a: 'operation,
540 {
541 execution.execution_for(self.parser)
542 }
543
544 pub(crate) fn source_parser(self) -> &'a Parser {
545 self.parser
546 }
547
548 #[must_use]
551 pub fn execution_origin(self) -> Producer<'a> {
552 Producer {
553 parser: self.parser,
554 }
555 }
556
557 pub(crate) fn parameters_nested(self) -> Option<Nested<'a>> {
559 let start = self.parameter_start?.get();
560 Some(self.nested(self.parameters()?, self.offset + start as u64))
561 }
562
563 pub(crate) fn nested(self, bytes: &'a [u8], at: u64) -> Nested<'a> {
566 Nested {
567 bytes,
568 at,
569 parser: self.parser,
570 outer: self.outer,
571 encoding: self.encoding,
572 }
573 }
574
575 #[must_use]
579 pub fn same_session(self, parent: &ScopedReader<'_, '_>) -> bool {
580 core::ptr::eq(self.parser, parent.parser())
581 }
582
583 #[must_use]
588 pub fn as_bytes(self) -> &'a [u8] {
589 self.der
590 }
591
592 #[must_use]
595 pub fn has_no_parameters(self) -> bool {
596 self.parameters().is_none() || self.null_parameter
600 }
601
602 pub fn matches(self, other: &AlgorithmIdentifier<'_>, execution: &Memory) -> Result<bool> {
643 self.matches_with(other, |work| {
644 execution
645 .charge_work(work)
646 .map_err(|reason| Error::resource(reason, self.field, self.offset))
647 })
648 }
649
650 pub(crate) fn matches_in(
651 self,
652 other: &AlgorithmIdentifier<'_>,
653 parent: &Reader<'_>,
654 ) -> Result<bool> {
655 self.matches_with(other, |work| {
656 parent.charge(work).map_err(|error| {
657 Error::new(ErrorCode::Encoding(error.code()), self.field, self.offset)
658 })
659 })
660 }
661
662 fn matches_with(
663 self,
664 other: &AlgorithmIdentifier<'_>,
665 mut charge: impl FnMut(u64) -> Result<()>,
666 ) -> Result<bool> {
667 charge(1)?;
668 if self.algorithm.as_bytes().len() != other.algorithm.as_bytes().len() {
669 return Ok(false);
670 }
671 charge(self.algorithm.as_bytes().len() as u64)?;
672 if self.algorithm != other.algorithm {
673 return Ok(false);
674 }
675 if self.has_no_parameters() && other.has_no_parameters() {
676 return Ok(true);
677 }
678 let (Some(left), Some(right)) = (self.parameters(), other.parameters()) else {
679 return Ok(false);
680 };
681 if left.len() != right.len() {
682 return Ok(false);
683 }
684 charge(left.len() as u64)?;
685 Ok(left == right)
686 }
687}
688
689pub fn read<'a>(
700 parent: &ScopedReader<'a, '_>,
701 element: &Element<'a>,
702 field: &'static str,
703) -> Result<AlgorithmIdentifier<'a>> {
704 read_tagged(
705 parent,
706 element,
707 Tag::constructed(universal::SEQUENCE),
708 field,
709 )
710}
711
712pub fn read_implicit<'a>(
721 parent: &Reader<'a>,
722 element: &Element<'a>,
723 number: u32,
724 field: &'static str,
725) -> Result<AlgorithmIdentifier<'a>> {
726 read_tagged(parent, element, Tag::context(true, number), field)
727}
728
729pub fn read_inspection<'a>(
736 parent: &Reader<'a>,
737 element: &Element<'a>,
738 field: &'static str,
739) -> Result<AlgorithmReading<'a>> {
740 read_fields::<true>(
741 parent,
742 element,
743 Tag::constructed(universal::SEQUENCE),
744 field,
745 )
746}
747
748pub fn read_implicit_inspection<'a>(
750 parent: &Reader<'a>,
751 element: &Element<'a>,
752 number: u32,
753 field: &'static str,
754) -> Result<AlgorithmReading<'a>> {
755 read_fields::<true>(parent, element, Tag::context(true, number), field)
756}
757
758fn read_fields<'a, const INSPECTION: bool>(
759 parent: &ScopedReader<'a, '_>,
760 element: &Element<'a>,
761 expected: Tag,
762 field: &'static str,
763) -> Result<AlgorithmReading<'a>> {
764 let fail = |code| Error::new(code, field, element.span().start);
765 if element.tag() != expected {
766 return Err(fail(ErrorCode::Encoding(
767 structured_asn1::ErrorCode::UnexpectedTag,
768 )));
769 }
770 let mut inside = parent.enter(element).field(field)?;
771 let algorithm = inside.read_oid().field(field)?;
772 let parameter = inside.next_element().field(field)?;
773 let mut fault = None;
774 let mut null_parameter = false;
775 if let Some(parameter) = ¶meter {
776 match crate::name::walk_der(&inside, parameter, field, crate::name::Strings::Checked) {
777 Ok(()) => {
778 null_parameter = parameter.tag() == Tag::primitive(universal::NULL);
783 }
784 Err(error) => {
785 if !INSPECTION || error.is_resource() || error.code() == ErrorCode::ForeignReader {
786 return Err(error);
787 }
788 fault = Some(error);
789 }
790 }
791 }
792 if !inside.is_empty() {
793 return Err(fail(ErrorCode::TrailingData));
794 }
795 let parameter_start = match parameter {
796 None => None,
797 Some(parameter) => {
798 let start = usize::try_from(parameter.span().start - element.span().start)
799 .map_err(|_| fail(ErrorCode::ValueTooLarge))?;
800 Some(NonZeroUsize::new(start).expect("the algorithm OID precedes its parameters"))
801 }
802 };
803 Ok(AlgorithmReading {
804 fields: AlgorithmFields {
805 algorithm,
806 parameter_start,
807 null_parameter,
808 der: element.as_bytes(),
809 offset: element.span().start,
810 field,
811 parser: parent.parser(),
812 outer: parent.depth(),
813 encoding: inside.encoding(),
814 indefinite: element.is_indefinite(),
815 },
816 fault,
817 })
818}
819
820fn read_tagged<'a>(
821 parent: &ScopedReader<'a, '_>,
822 element: &Element<'a>,
823 expected: Tag,
824 field: &'static str,
825) -> Result<AlgorithmIdentifier<'a>> {
826 read_fields::<false>(parent, element, expected, field)?.into_identifier()
827}
828
829#[cfg(test)]
830mod tests;