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)]
39pub(crate) struct Nested<'a> {
40 bytes: &'a [u8],
41 at: u64,
42 parser: &'a Parser,
43 outer: u32,
44 encoding: Encoding,
45}
46
47impl<'a> Nested<'a> {
48 pub(crate) fn encoding(self) -> Encoding {
49 self.encoding
50 }
51 pub(crate) fn execution_in<'q, W: Work>(
52 self,
53 work: &'q W,
54 ) -> structured_asn1::memory::Execution<'q>
55 where
56 'a: 'q,
57 {
58 work.execution_for(self.parser)
59 }
60
61 pub(crate) fn offset(self) -> u64 {
63 self.at
64 }
65
66 pub(crate) fn as_bytes(self) -> &'a [u8] {
67 self.bytes
68 }
69
70 pub(crate) fn open<'operation, W: Work>(
73 self,
74 execution: &'operation W,
75 field: &'static str,
76 ) -> Result<(ScopedReader<'a, 'operation>, Element<'a>)>
77 where
78 'a: 'operation,
79 {
80 let mut reader = execution
81 .read_scoped_nested(self.parser, self.bytes, self.at, self.encoding, self.outer)
82 .field(field)?;
83 let element = reader
84 .next_element()
85 .field(field)?
86 .ok_or_else(|| Error::new(ErrorCode::MissingField, field, reader.offset()))?;
87 if !reader.is_empty() {
88 return Err(Error::new(ErrorCode::TrailingData, field, reader.offset()));
89 }
90 Ok((reader, element))
91 }
92}
93
94#[derive(Debug, Clone, Copy)]
97struct AlgorithmFields<'a> {
98 algorithm: Oid<'a>,
99 parameter_start: Option<NonZeroUsize>,
100 null_parameter: bool,
101 der: &'a [u8],
102 offset: u64,
103 field: &'static str,
104 parser: &'a Parser,
105 outer: u32,
106 encoding: Encoding,
107 indefinite: bool,
108}
109
110#[derive(Debug)]
124pub struct AlgorithmReading<'a> {
125 fields: AlgorithmFields<'a>,
126 fault: Option<Error>,
127}
128
129impl<'a> AlgorithmReading<'a> {
130 #[must_use]
132 pub fn algorithm(&self) -> Oid<'a> {
133 self.fields.algorithm
134 }
135
136 #[must_use]
138 pub fn parameters(&self) -> Option<&'a [u8]> {
139 parameter_bytes(
140 self.fields.der,
141 self.fields.parameter_start,
142 self.fields.indefinite,
143 )
144 }
145
146 #[must_use]
149 pub fn parameters_span(&self) -> Option<Span> {
150 let start = self.fields.parameter_start?.get();
151 Some(Span {
152 start: self.fields.offset + start as u64,
153 length: self.parameters()?.len() as u64,
154 })
155 }
156
157 #[must_use]
160 pub fn has_null_parameter(&self) -> bool {
161 self.fields.null_parameter
162 }
163
164 #[must_use]
166 pub fn as_bytes(&self) -> &'a [u8] {
167 self.fields.der
168 }
169
170 #[must_use]
172 pub fn offset(&self) -> u64 {
173 self.fields.offset
174 }
175
176 #[must_use]
178 pub fn encoding(&self) -> Encoding {
179 self.fields.encoding
180 }
181
182 #[must_use]
186 pub fn same_session(&self, parent: &Reader<'_>) -> bool {
187 core::ptr::eq(self.fields.parser, parent.parser())
188 }
189
190 #[must_use]
192 pub fn fault(&self) -> Option<&Error> {
193 self.fault.as_ref()
194 }
195
196 #[must_use]
199 pub fn identifier(&self) -> Option<AlgorithmIdentifier<'a>> {
200 if self.fault.is_some() {
201 return None;
202 }
203 Some(self.fields.identifier())
204 }
205
206 pub fn require_identifier(&self) -> Result<AlgorithmIdentifier<'a>> {
210 match &self.fault {
211 Some(error) => Err(error.clone()),
212 None => Ok(self.fields.identifier()),
213 }
214 }
215
216 pub fn same_written_in(&self, other: &Self, parent: &Reader<'_>) -> Result<bool> {
221 written_matches(&self.fields, &other.fields, parent, false)
222 }
223
224 fn into_identifier(self) -> Result<AlgorithmIdentifier<'a>> {
225 match self.fault {
226 Some(error) => Err(error),
227 None => Ok(self.fields.identifier()),
228 }
229 }
230}
231
232impl<'a> AlgorithmFields<'a> {
233 fn identifier(self) -> AlgorithmIdentifier<'a> {
235 AlgorithmIdentifier {
236 algorithm: self.algorithm,
237 parameter_start: self.parameter_start,
238 null_parameter: self.null_parameter,
239 der: self.der,
240 offset: self.offset,
241 field: self.field,
242 parser: self.parser,
243 outer: self.outer,
244 encoding: self.encoding,
245 indefinite: self.indefinite,
246 }
247 }
248}
249
250fn parameter_bytes(bytes: &[u8], start: Option<NonZeroUsize>, indefinite: bool) -> Option<&[u8]> {
251 let start = start?.get();
252 let end = bytes.len() - if indefinite { 2 } else { 0 };
253 Some(&bytes[start..end])
254}
255
256trait WrittenValue {
257 fn oid_bytes(&self) -> &[u8];
258 fn parameter_bytes(&self) -> Option<&[u8]>;
259 fn valid_null(&self) -> bool;
260 fn producer(&self) -> &Parser;
261 fn field(&self) -> &'static str;
262 fn offset(&self) -> u64;
263}
264
265impl WrittenValue for AlgorithmFields<'_> {
266 fn oid_bytes(&self) -> &[u8] {
267 self.algorithm.as_bytes()
268 }
269 fn parameter_bytes(&self) -> Option<&[u8]> {
270 parameter_bytes(self.der, self.parameter_start, self.indefinite)
271 }
272 fn valid_null(&self) -> bool {
273 self.null_parameter
274 }
275 fn producer(&self) -> &Parser {
276 self.parser
277 }
278 fn field(&self) -> &'static str {
279 self.field
280 }
281 fn offset(&self) -> u64 {
282 self.offset
283 }
284}
285
286impl WrittenValue for AlgorithmIdentifier<'_> {
287 fn oid_bytes(&self) -> &[u8] {
288 self.algorithm.as_bytes()
289 }
290 fn parameter_bytes(&self) -> Option<&[u8]> {
291 self.parameters()
292 }
293 fn valid_null(&self) -> bool {
294 self.null_parameter
295 }
296 fn producer(&self) -> &Parser {
297 self.parser
298 }
299 fn field(&self) -> &'static str {
300 self.field
301 }
302 fn offset(&self) -> u64 {
303 self.offset
304 }
305}
306
307fn require_written_parsers(
308 left: &impl WrittenValue,
309 right: &impl WrittenValue,
310 parent: &Reader<'_>,
311) -> Result<()> {
312 if !core::ptr::eq(left.producer(), parent.parser()) {
313 return Err(Error::new(
314 ErrorCode::ForeignReader,
315 left.field(),
316 left.offset(),
317 ));
318 }
319 if !core::ptr::eq(right.producer(), parent.parser()) {
320 return Err(Error::new(
321 ErrorCode::ForeignReader,
322 right.field(),
323 right.offset(),
324 ));
325 }
326 Ok(())
327}
328
329fn written_matches(
330 left: &impl WrittenValue,
331 right: &impl WrittenValue,
332 parent: &Reader<'_>,
333 defaults: bool,
334) -> Result<bool> {
335 require_written_parsers(left, right, parent)?;
336 written_values(left, right, parent, defaults)
337}
338
339fn written_values(
340 left: &impl WrittenValue,
341 right: &impl WrittenValue,
342 parent: &Reader<'_>,
343 defaults: bool,
344) -> Result<bool> {
345 let charge = |amount| {
346 parent.charge(amount).map_err(|error| {
347 Error::new(
348 ErrorCode::Encoding(error.code()),
349 right.field(),
350 right.offset(),
351 )
352 })
353 };
354 charge(1)?;
355 let kind = left.oid_bytes();
356 if kind.len() != right.oid_bytes().len() {
357 return Ok(false);
358 }
359 charge(kind.len() as u64)?;
360 if kind != right.oid_bytes() {
361 return Ok(false);
362 }
363 if defaults || (left.valid_null() && right.valid_null()) {
364 return Ok(true);
365 }
366 let (Some(first), Some(second)) = (left.parameter_bytes(), right.parameter_bytes()) else {
367 return Ok(left.parameter_bytes().is_none() && right.parameter_bytes().is_none());
368 };
369 if first.len() != second.len() {
370 return Ok(false);
371 }
372 charge(first.len() as u64)?;
373 Ok(first == second)
374}
375
376impl<'a> AlgorithmIdentifier<'a> {
377 #[must_use]
380 pub fn has_null_parameter(self) -> bool {
381 self.null_parameter
382 }
383
384 pub fn same_written_in(self, other: &Self, parent: &Reader<'_>) -> Result<bool> {
393 self.value_matches(other, parent, false)
394 }
395
396 pub fn digest_matches_in(self, other: &Self, parent: &Reader<'_>) -> Result<bool> {
406 self.value_matches(other, parent, true)
407 }
408
409 fn value_matches(self, other: &Self, parent: &Reader<'_>, digest: bool) -> Result<bool> {
410 require_written_parsers(&self, other, parent)?;
411 let sha2 = if digest {
412 let known = self.validate_digest_params(parent)?;
413 other.validate_digest_params(parent)?;
414 known
415 } else {
416 false
417 };
418 written_values(&self, other, parent, sha2)
419 }
420
421 fn validate_digest_params(self, parent: &Reader<'_>) -> Result<bool> {
422 let charge = |amount| {
423 parent.charge(amount).map_err(|error| {
424 Error::new(ErrorCode::Encoding(error.code()), self.field, self.offset)
425 })
426 };
427 charge(1)?;
428 let kind = self.algorithm.as_bytes();
429 if kind.len() != 9 {
430 return Ok(false);
431 }
432 charge(9)?;
433 if kind[..8] != [0x60, 0x86, 0x48, 1, 0x65, 3, 4, 2] || kind[8] < 1 || kind[8] > 4 {
434 return Ok(false);
435 }
436 if self.parameter_start.is_some() && !self.null_parameter {
437 return Err(Error::new(
441 ErrorCode::MalformedValue,
442 self.field,
443 self.offset,
444 ));
445 }
446 Ok(true)
447 }
448 #[must_use]
450 pub fn algorithm(self) -> Oid<'a> {
451 self.algorithm
452 }
453
454 #[must_use]
461 pub fn parameters(self) -> Option<&'a [u8]> {
462 parameter_bytes(self.der, self.parameter_start, self.indefinite)
463 }
464
465 #[must_use]
467 pub fn offset(self) -> u64 {
468 self.offset
469 }
470
471 #[must_use]
473 pub fn encoding(self) -> Encoding {
474 self.encoding
475 }
476
477 pub fn parameters_reader_in<'query>(
490 self,
491 parent: &Reader<'query>,
492 field: &'static str,
493 ) -> Result<Option<Reader<'query>>>
494 where
495 'a: 'query,
496 {
497 if !self.same_session(parent) {
498 return Err(Error::new(ErrorCode::ForeignReader, field, self.offset));
499 }
500 let at = self
501 .parameter_start
502 .map_or(self.offset, |start| self.offset + start.get() as u64);
503 parent
504 .execution()
505 .charge_work(1)
506 .map_err(|reason| Error::resource(reason, field, at))?;
507 let Some(parameter) = self.parameters() else {
508 return Ok(None);
509 };
510 self.parser
511 .read_nested_query_in(parent, parameter, at, self.encoding, self.outer)
512 .field(field)
513 .map(Some)
514 }
515
516 pub(crate) fn query_in<'operation, W: Work>(
518 &self,
519 execution: &'operation W,
520 ) -> structured_asn1::memory::Execution<'operation>
521 where
522 'a: 'operation,
523 {
524 execution.execution_for(self.parser)
525 }
526
527 pub(crate) fn source_parser(self) -> &'a Parser {
528 self.parser
529 }
530
531 pub(crate) fn parameters_nested(self) -> Option<Nested<'a>> {
533 let start = self.parameter_start?.get();
534 Some(self.nested(self.parameters()?, self.offset + start as u64))
535 }
536
537 pub(crate) fn nested(self, bytes: &'a [u8], at: u64) -> Nested<'a> {
540 Nested {
541 bytes,
542 at,
543 parser: self.parser,
544 outer: self.outer,
545 encoding: self.encoding,
546 }
547 }
548
549 #[must_use]
553 pub fn same_session(self, parent: &ScopedReader<'_, '_>) -> bool {
554 core::ptr::eq(self.parser, parent.parser())
555 }
556
557 #[must_use]
562 pub fn as_bytes(self) -> &'a [u8] {
563 self.der
564 }
565
566 #[must_use]
569 pub fn has_no_parameters(self) -> bool {
570 self.parameters().is_none() || self.null_parameter
574 }
575
576 pub fn matches(self, other: &AlgorithmIdentifier<'_>, execution: &Memory) -> Result<bool> {
617 self.matches_with(other, |work| {
618 execution
619 .charge_work(work)
620 .map_err(|reason| Error::resource(reason, self.field, self.offset))
621 })
622 }
623
624 pub(crate) fn matches_in(
625 self,
626 other: &AlgorithmIdentifier<'_>,
627 parent: &Reader<'_>,
628 ) -> Result<bool> {
629 self.matches_with(other, |work| {
630 parent.charge(work).map_err(|error| {
631 Error::new(ErrorCode::Encoding(error.code()), self.field, self.offset)
632 })
633 })
634 }
635
636 fn matches_with(
637 self,
638 other: &AlgorithmIdentifier<'_>,
639 mut charge: impl FnMut(u64) -> Result<()>,
640 ) -> Result<bool> {
641 charge(1)?;
642 if self.algorithm.as_bytes().len() != other.algorithm.as_bytes().len() {
643 return Ok(false);
644 }
645 charge(self.algorithm.as_bytes().len() as u64)?;
646 if self.algorithm != other.algorithm {
647 return Ok(false);
648 }
649 if self.has_no_parameters() && other.has_no_parameters() {
650 return Ok(true);
651 }
652 let (Some(left), Some(right)) = (self.parameters(), other.parameters()) else {
653 return Ok(false);
654 };
655 if left.len() != right.len() {
656 return Ok(false);
657 }
658 charge(left.len() as u64)?;
659 Ok(left == right)
660 }
661}
662
663pub fn read<'a>(
674 parent: &ScopedReader<'a, '_>,
675 element: &Element<'a>,
676 field: &'static str,
677) -> Result<AlgorithmIdentifier<'a>> {
678 read_tagged(
679 parent,
680 element,
681 Tag::constructed(universal::SEQUENCE),
682 field,
683 )
684}
685
686pub fn read_implicit<'a>(
695 parent: &Reader<'a>,
696 element: &Element<'a>,
697 number: u32,
698 field: &'static str,
699) -> Result<AlgorithmIdentifier<'a>> {
700 read_tagged(parent, element, Tag::context(true, number), field)
701}
702
703pub fn read_inspection<'a>(
710 parent: &Reader<'a>,
711 element: &Element<'a>,
712 field: &'static str,
713) -> Result<AlgorithmReading<'a>> {
714 read_fields::<true>(
715 parent,
716 element,
717 Tag::constructed(universal::SEQUENCE),
718 field,
719 )
720}
721
722pub fn read_implicit_inspection<'a>(
724 parent: &Reader<'a>,
725 element: &Element<'a>,
726 number: u32,
727 field: &'static str,
728) -> Result<AlgorithmReading<'a>> {
729 read_fields::<true>(parent, element, Tag::context(true, number), field)
730}
731
732fn read_fields<'a, const INSPECTION: bool>(
733 parent: &ScopedReader<'a, '_>,
734 element: &Element<'a>,
735 expected: Tag,
736 field: &'static str,
737) -> Result<AlgorithmReading<'a>> {
738 let fail = |code| Error::new(code, field, element.span().start);
739 if element.tag() != expected {
740 return Err(fail(ErrorCode::Encoding(
741 structured_asn1::ErrorCode::UnexpectedTag,
742 )));
743 }
744 let mut inside = parent.enter(element).field(field)?;
745 let algorithm = inside.read_oid().field(field)?;
746 let parameter = inside.next_element().field(field)?;
747 let mut fault = None;
748 let mut null_parameter = false;
749 if let Some(parameter) = ¶meter {
750 match crate::name::walk_der(&inside, parameter, field, crate::name::Strings::Checked) {
751 Ok(()) => {
752 null_parameter = parameter.tag() == Tag::primitive(universal::NULL);
757 }
758 Err(error) => {
759 if !INSPECTION || error.is_resource() || error.code() == ErrorCode::ForeignReader {
760 return Err(error);
761 }
762 fault = Some(error);
763 }
764 }
765 }
766 if !inside.is_empty() {
767 return Err(fail(ErrorCode::TrailingData));
768 }
769 let parameter_start = match parameter {
770 None => None,
771 Some(parameter) => {
772 let start = usize::try_from(parameter.span().start - element.span().start)
773 .map_err(|_| fail(ErrorCode::ValueTooLarge))?;
774 Some(NonZeroUsize::new(start).expect("the algorithm OID precedes its parameters"))
775 }
776 };
777 Ok(AlgorithmReading {
778 fields: AlgorithmFields {
779 algorithm,
780 parameter_start,
781 null_parameter,
782 der: element.as_bytes(),
783 offset: element.span().start,
784 field,
785 parser: parent.parser(),
786 outer: parent.depth(),
787 encoding: inside.encoding(),
788 indefinite: element.is_indefinite(),
789 },
790 fault,
791 })
792}
793
794fn read_tagged<'a>(
795 parent: &ScopedReader<'a, '_>,
796 element: &Element<'a>,
797 expected: Tag,
798 field: &'static str,
799) -> Result<AlgorithmIdentifier<'a>> {
800 read_fields::<false>(parent, element, expected, field)?.into_identifier()
801}
802
803#[cfg(test)]
804mod tests;