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 offset(self) -> u64 {
50 self.at
51 }
52
53 pub(crate) fn as_bytes(self) -> &'a [u8] {
54 self.bytes
55 }
56
57 pub(crate) fn open<'operation, W: Work>(
60 self,
61 execution: &'operation W,
62 field: &'static str,
63 ) -> Result<(ScopedReader<'a, 'operation>, Element<'a>)>
64 where
65 'a: 'operation,
66 {
67 let mut reader = execution
68 .read_scoped_nested(self.parser, self.bytes, self.at, self.encoding, self.outer)
69 .field(field)?;
70 let element = reader
71 .next_element()
72 .field(field)?
73 .ok_or_else(|| Error::new(ErrorCode::MissingField, field, reader.offset()))?;
74 if !reader.is_empty() {
75 return Err(Error::new(ErrorCode::TrailingData, field, reader.offset()));
76 }
77 Ok((reader, element))
78 }
79}
80
81#[derive(Debug, Clone, Copy)]
84struct AlgorithmFields<'a> {
85 algorithm: Oid<'a>,
86 parameter_start: Option<NonZeroUsize>,
87 null_parameter: bool,
88 der: &'a [u8],
89 offset: u64,
90 field: &'static str,
91 parser: &'a Parser,
92 outer: u32,
93 encoding: Encoding,
94 indefinite: bool,
95}
96
97#[derive(Debug)]
111pub struct AlgorithmReading<'a> {
112 fields: AlgorithmFields<'a>,
113 fault: Option<Error>,
114}
115
116impl<'a> AlgorithmReading<'a> {
117 #[must_use]
119 pub fn algorithm(&self) -> Oid<'a> {
120 self.fields.algorithm
121 }
122
123 #[must_use]
125 pub fn parameters(&self) -> Option<&'a [u8]> {
126 parameter_bytes(
127 self.fields.der,
128 self.fields.parameter_start,
129 self.fields.indefinite,
130 )
131 }
132
133 #[must_use]
136 pub fn parameters_span(&self) -> Option<Span> {
137 let start = self.fields.parameter_start?.get();
138 Some(Span {
139 start: self.fields.offset + start as u64,
140 length: self.parameters()?.len() as u64,
141 })
142 }
143
144 #[must_use]
147 pub fn has_null_parameter(&self) -> bool {
148 self.fields.null_parameter
149 }
150
151 #[must_use]
153 pub fn as_bytes(&self) -> &'a [u8] {
154 self.fields.der
155 }
156
157 #[must_use]
159 pub fn offset(&self) -> u64 {
160 self.fields.offset
161 }
162
163 #[must_use]
165 pub fn encoding(&self) -> Encoding {
166 self.fields.encoding
167 }
168
169 #[must_use]
173 pub fn same_session(&self, parent: &Reader<'_>) -> bool {
174 core::ptr::eq(self.fields.parser, parent.parser())
175 }
176
177 #[must_use]
179 pub fn fault(&self) -> Option<&Error> {
180 self.fault.as_ref()
181 }
182
183 #[must_use]
186 pub fn identifier(&self) -> Option<AlgorithmIdentifier<'a>> {
187 if self.fault.is_some() {
188 return None;
189 }
190 Some(self.fields.identifier())
191 }
192
193 pub fn require_identifier(&self) -> Result<AlgorithmIdentifier<'a>> {
197 match &self.fault {
198 Some(error) => Err(error.clone()),
199 None => Ok(self.fields.identifier()),
200 }
201 }
202
203 pub fn same_written_in(&self, other: &Self, parent: &Reader<'_>) -> Result<bool> {
208 written_matches(&self.fields, &other.fields, parent, false)
209 }
210
211 fn into_identifier(self) -> Result<AlgorithmIdentifier<'a>> {
212 match self.fault {
213 Some(error) => Err(error),
214 None => Ok(self.fields.identifier()),
215 }
216 }
217}
218
219impl<'a> AlgorithmFields<'a> {
220 fn identifier(self) -> AlgorithmIdentifier<'a> {
222 AlgorithmIdentifier {
223 algorithm: self.algorithm,
224 parameter_start: self.parameter_start,
225 null_parameter: self.null_parameter,
226 der: self.der,
227 offset: self.offset,
228 field: self.field,
229 parser: self.parser,
230 outer: self.outer,
231 encoding: self.encoding,
232 indefinite: self.indefinite,
233 }
234 }
235}
236
237fn parameter_bytes(bytes: &[u8], start: Option<NonZeroUsize>, indefinite: bool) -> Option<&[u8]> {
238 let start = start?.get();
239 let end = bytes.len() - if indefinite { 2 } else { 0 };
240 Some(&bytes[start..end])
241}
242
243trait WrittenValue {
244 fn oid_bytes(&self) -> &[u8];
245 fn parameter_bytes(&self) -> Option<&[u8]>;
246 fn valid_null(&self) -> bool;
247 fn producer(&self) -> &Parser;
248 fn field(&self) -> &'static str;
249 fn offset(&self) -> u64;
250}
251
252impl WrittenValue for AlgorithmFields<'_> {
253 fn oid_bytes(&self) -> &[u8] {
254 self.algorithm.as_bytes()
255 }
256 fn parameter_bytes(&self) -> Option<&[u8]> {
257 parameter_bytes(self.der, self.parameter_start, self.indefinite)
258 }
259 fn valid_null(&self) -> bool {
260 self.null_parameter
261 }
262 fn producer(&self) -> &Parser {
263 self.parser
264 }
265 fn field(&self) -> &'static str {
266 self.field
267 }
268 fn offset(&self) -> u64 {
269 self.offset
270 }
271}
272
273impl WrittenValue for AlgorithmIdentifier<'_> {
274 fn oid_bytes(&self) -> &[u8] {
275 self.algorithm.as_bytes()
276 }
277 fn parameter_bytes(&self) -> Option<&[u8]> {
278 self.parameters()
279 }
280 fn valid_null(&self) -> bool {
281 self.null_parameter
282 }
283 fn producer(&self) -> &Parser {
284 self.parser
285 }
286 fn field(&self) -> &'static str {
287 self.field
288 }
289 fn offset(&self) -> u64 {
290 self.offset
291 }
292}
293
294fn require_written_parsers(
295 left: &impl WrittenValue,
296 right: &impl WrittenValue,
297 parent: &Reader<'_>,
298) -> Result<()> {
299 if !core::ptr::eq(left.producer(), parent.parser()) {
300 return Err(Error::new(
301 ErrorCode::ForeignReader,
302 left.field(),
303 left.offset(),
304 ));
305 }
306 if !core::ptr::eq(right.producer(), parent.parser()) {
307 return Err(Error::new(
308 ErrorCode::ForeignReader,
309 right.field(),
310 right.offset(),
311 ));
312 }
313 Ok(())
314}
315
316fn written_matches(
317 left: &impl WrittenValue,
318 right: &impl WrittenValue,
319 parent: &Reader<'_>,
320 defaults: bool,
321) -> Result<bool> {
322 require_written_parsers(left, right, parent)?;
323 written_values(left, right, parent, defaults)
324}
325
326fn written_values(
327 left: &impl WrittenValue,
328 right: &impl WrittenValue,
329 parent: &Reader<'_>,
330 defaults: bool,
331) -> Result<bool> {
332 let charge = |amount| {
333 parent.charge(amount).map_err(|error| {
334 Error::new(
335 ErrorCode::Encoding(error.code()),
336 right.field(),
337 right.offset(),
338 )
339 })
340 };
341 charge(1)?;
342 let kind = left.oid_bytes();
343 if kind.len() != right.oid_bytes().len() {
344 return Ok(false);
345 }
346 charge(kind.len() as u64)?;
347 if kind != right.oid_bytes() {
348 return Ok(false);
349 }
350 if defaults || (left.valid_null() && right.valid_null()) {
351 return Ok(true);
352 }
353 let (Some(first), Some(second)) = (left.parameter_bytes(), right.parameter_bytes()) else {
354 return Ok(left.parameter_bytes().is_none() && right.parameter_bytes().is_none());
355 };
356 if first.len() != second.len() {
357 return Ok(false);
358 }
359 charge(first.len() as u64)?;
360 Ok(first == second)
361}
362
363impl<'a> AlgorithmIdentifier<'a> {
364 #[must_use]
367 pub fn has_null_parameter(self) -> bool {
368 self.null_parameter
369 }
370
371 pub fn same_written_in(self, other: &Self, parent: &Reader<'_>) -> Result<bool> {
380 self.value_matches(other, parent, false)
381 }
382
383 pub fn digest_matches_in(self, other: &Self, parent: &Reader<'_>) -> Result<bool> {
393 self.value_matches(other, parent, true)
394 }
395
396 fn value_matches(self, other: &Self, parent: &Reader<'_>, digest: bool) -> Result<bool> {
397 require_written_parsers(&self, other, parent)?;
398 let sha2 = if digest {
399 let known = self.validate_digest_params(parent)?;
400 other.validate_digest_params(parent)?;
401 known
402 } else {
403 false
404 };
405 written_values(&self, other, parent, sha2)
406 }
407
408 fn validate_digest_params(self, parent: &Reader<'_>) -> Result<bool> {
409 let charge = |amount| {
410 parent.charge(amount).map_err(|error| {
411 Error::new(ErrorCode::Encoding(error.code()), self.field, self.offset)
412 })
413 };
414 charge(1)?;
415 let kind = self.algorithm.as_bytes();
416 if kind.len() != 9 {
417 return Ok(false);
418 }
419 charge(9)?;
420 if kind[..8] != [0x60, 0x86, 0x48, 1, 0x65, 3, 4, 2] || kind[8] < 1 || kind[8] > 4 {
421 return Ok(false);
422 }
423 if self.parameter_start.is_some() && !self.null_parameter {
424 return Err(Error::new(
428 ErrorCode::MalformedValue,
429 self.field,
430 self.offset,
431 ));
432 }
433 Ok(true)
434 }
435 #[must_use]
437 pub fn algorithm(self) -> Oid<'a> {
438 self.algorithm
439 }
440
441 #[must_use]
448 pub fn parameters(self) -> Option<&'a [u8]> {
449 parameter_bytes(self.der, self.parameter_start, self.indefinite)
450 }
451
452 #[must_use]
454 pub fn offset(self) -> u64 {
455 self.offset
456 }
457
458 #[must_use]
460 pub fn encoding(self) -> Encoding {
461 self.encoding
462 }
463
464 pub fn parameters_reader_in<'query>(
477 self,
478 parent: &Reader<'query>,
479 field: &'static str,
480 ) -> Result<Option<Reader<'query>>>
481 where
482 'a: 'query,
483 {
484 if !self.same_session(parent) {
485 return Err(Error::new(ErrorCode::ForeignReader, field, self.offset));
486 }
487 let at = self
488 .parameter_start
489 .map_or(self.offset, |start| self.offset + start.get() as u64);
490 parent
491 .execution()
492 .charge_work(1)
493 .map_err(|reason| Error::resource(reason, field, at))?;
494 let Some(parameter) = self.parameters() else {
495 return Ok(None);
496 };
497 self.parser
498 .read_nested_query_in(parent, parameter, at, self.encoding, self.outer)
499 .field(field)
500 .map(Some)
501 }
502
503 pub(crate) fn query_in<'operation, W: Work>(
505 &self,
506 execution: &'operation W,
507 ) -> structured_asn1::memory::Execution<'operation>
508 where
509 'a: 'operation,
510 {
511 execution.execution_for(self.parser)
512 }
513
514 pub(crate) fn parameters_nested(self) -> Option<Nested<'a>> {
516 let start = self.parameter_start?.get();
517 Some(self.nested(self.parameters()?, self.offset + start as u64))
518 }
519
520 pub(crate) fn nested(self, bytes: &'a [u8], at: u64) -> Nested<'a> {
523 Nested {
524 bytes,
525 at,
526 parser: self.parser,
527 outer: self.outer,
528 encoding: self.encoding,
529 }
530 }
531
532 #[must_use]
536 pub fn same_session(self, parent: &ScopedReader<'_, '_>) -> bool {
537 core::ptr::eq(self.parser, parent.parser())
538 }
539
540 #[must_use]
545 pub fn as_bytes(self) -> &'a [u8] {
546 self.der
547 }
548
549 #[must_use]
552 pub fn has_no_parameters(self) -> bool {
553 self.parameters().is_none() || self.null_parameter
557 }
558
559 pub fn matches(self, other: &AlgorithmIdentifier<'_>, execution: &Memory) -> Result<bool> {
600 self.matches_with(other, |work| {
601 execution
602 .charge_work(work)
603 .map_err(|reason| Error::resource(reason, self.field, self.offset))
604 })
605 }
606
607 pub(crate) fn matches_in(
608 self,
609 other: &AlgorithmIdentifier<'_>,
610 parent: &Reader<'_>,
611 ) -> Result<bool> {
612 self.matches_with(other, |work| {
613 parent.charge(work).map_err(|error| {
614 Error::new(ErrorCode::Encoding(error.code()), self.field, self.offset)
615 })
616 })
617 }
618
619 fn matches_with(
620 self,
621 other: &AlgorithmIdentifier<'_>,
622 mut charge: impl FnMut(u64) -> Result<()>,
623 ) -> Result<bool> {
624 charge(1)?;
625 if self.algorithm.as_bytes().len() != other.algorithm.as_bytes().len() {
626 return Ok(false);
627 }
628 charge(self.algorithm.as_bytes().len() as u64)?;
629 if self.algorithm != other.algorithm {
630 return Ok(false);
631 }
632 if self.has_no_parameters() && other.has_no_parameters() {
633 return Ok(true);
634 }
635 let (Some(left), Some(right)) = (self.parameters(), other.parameters()) else {
636 return Ok(false);
637 };
638 if left.len() != right.len() {
639 return Ok(false);
640 }
641 charge(left.len() as u64)?;
642 Ok(left == right)
643 }
644}
645
646pub fn read<'a>(
657 parent: &ScopedReader<'a, '_>,
658 element: &Element<'a>,
659 field: &'static str,
660) -> Result<AlgorithmIdentifier<'a>> {
661 read_tagged(
662 parent,
663 element,
664 Tag::constructed(universal::SEQUENCE),
665 field,
666 )
667}
668
669pub fn read_implicit<'a>(
678 parent: &Reader<'a>,
679 element: &Element<'a>,
680 number: u32,
681 field: &'static str,
682) -> Result<AlgorithmIdentifier<'a>> {
683 read_tagged(parent, element, Tag::context(true, number), field)
684}
685
686pub fn read_inspection<'a>(
693 parent: &Reader<'a>,
694 element: &Element<'a>,
695 field: &'static str,
696) -> Result<AlgorithmReading<'a>> {
697 read_fields::<true>(
698 parent,
699 element,
700 Tag::constructed(universal::SEQUENCE),
701 field,
702 )
703}
704
705pub fn read_implicit_inspection<'a>(
707 parent: &Reader<'a>,
708 element: &Element<'a>,
709 number: u32,
710 field: &'static str,
711) -> Result<AlgorithmReading<'a>> {
712 read_fields::<true>(parent, element, Tag::context(true, number), field)
713}
714
715fn read_fields<'a, const INSPECTION: bool>(
716 parent: &ScopedReader<'a, '_>,
717 element: &Element<'a>,
718 expected: Tag,
719 field: &'static str,
720) -> Result<AlgorithmReading<'a>> {
721 let fail = |code| Error::new(code, field, element.span().start);
722 if element.tag() != expected {
723 return Err(fail(ErrorCode::Encoding(
724 structured_asn1::ErrorCode::UnexpectedTag,
725 )));
726 }
727 let mut inside = parent.enter(element).field(field)?;
728 let algorithm = inside.read_oid().field(field)?;
729 let parameter = inside.next_element().field(field)?;
730 let mut fault = None;
731 let mut null_parameter = false;
732 if let Some(parameter) = ¶meter {
733 match crate::name::walk_der(&inside, parameter, field, crate::name::Strings::Checked) {
734 Ok(()) => {
735 null_parameter = parameter.tag() == Tag::primitive(universal::NULL);
740 }
741 Err(error) => {
742 if !INSPECTION || error.is_resource() || error.code() == ErrorCode::ForeignReader {
743 return Err(error);
744 }
745 fault = Some(error);
746 }
747 }
748 }
749 if !inside.is_empty() {
750 return Err(fail(ErrorCode::TrailingData));
751 }
752 let parameter_start = match parameter {
753 None => None,
754 Some(parameter) => {
755 let start = usize::try_from(parameter.span().start - element.span().start)
756 .map_err(|_| fail(ErrorCode::ValueTooLarge))?;
757 Some(NonZeroUsize::new(start).expect("the algorithm OID precedes its parameters"))
758 }
759 };
760 Ok(AlgorithmReading {
761 fields: AlgorithmFields {
762 algorithm,
763 parameter_start,
764 null_parameter,
765 der: element.as_bytes(),
766 offset: element.span().start,
767 field,
768 parser: parent.parser(),
769 outer: parent.depth(),
770 encoding: inside.encoding(),
771 indefinite: element.is_indefinite(),
772 },
773 fault,
774 })
775}
776
777fn read_tagged<'a>(
778 parent: &ScopedReader<'a, '_>,
779 element: &Element<'a>,
780 expected: Tag,
781 field: &'static str,
782) -> Result<AlgorithmIdentifier<'a>> {
783 read_fields::<false>(parent, element, expected, field)?.into_identifier()
784}
785
786#[cfg(test)]
787mod tests;