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 pss;
14
15#[derive(Debug, Clone, Copy)]
17pub struct AlgorithmIdentifier<'a> {
18 algorithm: Oid<'a>,
19 parameter_start: Option<NonZeroUsize>,
22 null_parameter: bool,
23 der: &'a [u8],
24 offset: u64,
25 field: &'static str,
26 parser: &'a Parser,
27 outer: u32,
28 encoding: Encoding,
29 indefinite: bool,
30}
31
32#[derive(Debug, Clone, Copy)]
36pub(crate) struct Nested<'a> {
37 bytes: &'a [u8],
38 at: u64,
39 parser: &'a Parser,
40 outer: u32,
41 encoding: Encoding,
42}
43
44impl<'a> Nested<'a> {
45 pub(crate) fn as_bytes(self) -> &'a [u8] {
46 self.bytes
47 }
48
49 pub(crate) fn open<'operation, W: Work>(
52 self,
53 execution: &'operation W,
54 field: &'static str,
55 ) -> Result<(ScopedReader<'a, 'operation>, Element<'a>)>
56 where
57 'a: 'operation,
58 {
59 let mut reader = execution
60 .read_scoped_nested(self.parser, self.bytes, self.at, self.encoding, self.outer)
61 .field(field)?;
62 let element = reader
63 .next_element()
64 .field(field)?
65 .ok_or_else(|| Error::new(ErrorCode::MissingField, field, reader.offset()))?;
66 if !reader.is_empty() {
67 return Err(Error::new(ErrorCode::TrailingData, field, reader.offset()));
68 }
69 Ok((reader, element))
70 }
71}
72
73#[derive(Debug, Clone, Copy)]
76struct AlgorithmFields<'a> {
77 algorithm: Oid<'a>,
78 parameter_start: Option<NonZeroUsize>,
79 null_parameter: bool,
80 der: &'a [u8],
81 offset: u64,
82 field: &'static str,
83 parser: &'a Parser,
84 outer: u32,
85 encoding: Encoding,
86 indefinite: bool,
87}
88
89#[derive(Debug)]
103pub struct AlgorithmReading<'a> {
104 fields: AlgorithmFields<'a>,
105 fault: Option<Error>,
106}
107
108impl<'a> AlgorithmReading<'a> {
109 #[must_use]
111 pub fn algorithm(&self) -> Oid<'a> {
112 self.fields.algorithm
113 }
114
115 #[must_use]
117 pub fn parameters(&self) -> Option<&'a [u8]> {
118 parameter_bytes(
119 self.fields.der,
120 self.fields.parameter_start,
121 self.fields.indefinite,
122 )
123 }
124
125 #[must_use]
128 pub fn parameters_span(&self) -> Option<Span> {
129 let start = self.fields.parameter_start?.get();
130 Some(Span {
131 start: self.fields.offset + start as u64,
132 length: self.parameters()?.len() as u64,
133 })
134 }
135
136 #[must_use]
139 pub fn has_null_parameter(&self) -> bool {
140 self.fields.null_parameter
141 }
142
143 #[must_use]
145 pub fn as_bytes(&self) -> &'a [u8] {
146 self.fields.der
147 }
148
149 #[must_use]
151 pub fn offset(&self) -> u64 {
152 self.fields.offset
153 }
154
155 #[must_use]
157 pub fn encoding(&self) -> Encoding {
158 self.fields.encoding
159 }
160
161 #[must_use]
165 pub fn same_session(&self, parent: &Reader<'_>) -> bool {
166 core::ptr::eq(self.fields.parser, parent.parser())
167 }
168
169 #[must_use]
171 pub fn fault(&self) -> Option<&Error> {
172 self.fault.as_ref()
173 }
174
175 #[must_use]
178 pub fn identifier(&self) -> Option<AlgorithmIdentifier<'a>> {
179 if self.fault.is_some() {
180 return None;
181 }
182 Some(self.fields.identifier())
183 }
184
185 pub fn require_identifier(&self) -> Result<AlgorithmIdentifier<'a>> {
189 match &self.fault {
190 Some(error) => Err(error.clone()),
191 None => Ok(self.fields.identifier()),
192 }
193 }
194
195 pub fn same_written_in(&self, other: &Self, parent: &Reader<'_>) -> Result<bool> {
200 written_matches(&self.fields, &other.fields, parent, false)
201 }
202
203 fn into_identifier(self) -> Result<AlgorithmIdentifier<'a>> {
204 match self.fault {
205 Some(error) => Err(error),
206 None => Ok(self.fields.identifier()),
207 }
208 }
209}
210
211impl<'a> AlgorithmFields<'a> {
212 fn identifier(self) -> AlgorithmIdentifier<'a> {
214 AlgorithmIdentifier {
215 algorithm: self.algorithm,
216 parameter_start: self.parameter_start,
217 null_parameter: self.null_parameter,
218 der: self.der,
219 offset: self.offset,
220 field: self.field,
221 parser: self.parser,
222 outer: self.outer,
223 encoding: self.encoding,
224 indefinite: self.indefinite,
225 }
226 }
227}
228
229fn parameter_bytes(bytes: &[u8], start: Option<NonZeroUsize>, indefinite: bool) -> Option<&[u8]> {
230 let start = start?.get();
231 let end = bytes.len() - if indefinite { 2 } else { 0 };
232 Some(&bytes[start..end])
233}
234
235trait WrittenValue {
236 fn oid_bytes(&self) -> &[u8];
237 fn parameter_bytes(&self) -> Option<&[u8]>;
238 fn valid_null(&self) -> bool;
239 fn producer(&self) -> &Parser;
240 fn field(&self) -> &'static str;
241 fn offset(&self) -> u64;
242}
243
244impl WrittenValue for AlgorithmFields<'_> {
245 fn oid_bytes(&self) -> &[u8] {
246 self.algorithm.as_bytes()
247 }
248 fn parameter_bytes(&self) -> Option<&[u8]> {
249 parameter_bytes(self.der, self.parameter_start, self.indefinite)
250 }
251 fn valid_null(&self) -> bool {
252 self.null_parameter
253 }
254 fn producer(&self) -> &Parser {
255 self.parser
256 }
257 fn field(&self) -> &'static str {
258 self.field
259 }
260 fn offset(&self) -> u64 {
261 self.offset
262 }
263}
264
265impl WrittenValue for AlgorithmIdentifier<'_> {
266 fn oid_bytes(&self) -> &[u8] {
267 self.algorithm.as_bytes()
268 }
269 fn parameter_bytes(&self) -> Option<&[u8]> {
270 self.parameters()
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
286fn require_written_parsers(
287 left: &impl WrittenValue,
288 right: &impl WrittenValue,
289 parent: &Reader<'_>,
290) -> Result<()> {
291 if !core::ptr::eq(left.producer(), parent.parser()) {
292 return Err(Error::new(
293 ErrorCode::ForeignReader,
294 left.field(),
295 left.offset(),
296 ));
297 }
298 if !core::ptr::eq(right.producer(), parent.parser()) {
299 return Err(Error::new(
300 ErrorCode::ForeignReader,
301 right.field(),
302 right.offset(),
303 ));
304 }
305 Ok(())
306}
307
308fn written_matches(
309 left: &impl WrittenValue,
310 right: &impl WrittenValue,
311 parent: &Reader<'_>,
312 defaults: bool,
313) -> Result<bool> {
314 require_written_parsers(left, right, parent)?;
315 written_values(left, right, parent, defaults)
316}
317
318fn written_values(
319 left: &impl WrittenValue,
320 right: &impl WrittenValue,
321 parent: &Reader<'_>,
322 defaults: bool,
323) -> Result<bool> {
324 let charge = |amount| {
325 parent.charge(amount).map_err(|error| {
326 Error::new(
327 ErrorCode::Encoding(error.code()),
328 right.field(),
329 right.offset(),
330 )
331 })
332 };
333 charge(1)?;
334 let kind = left.oid_bytes();
335 if kind.len() != right.oid_bytes().len() {
336 return Ok(false);
337 }
338 charge(kind.len() as u64)?;
339 if kind != right.oid_bytes() {
340 return Ok(false);
341 }
342 if defaults || (left.valid_null() && right.valid_null()) {
343 return Ok(true);
344 }
345 let (Some(first), Some(second)) = (left.parameter_bytes(), right.parameter_bytes()) else {
346 return Ok(left.parameter_bytes().is_none() && right.parameter_bytes().is_none());
347 };
348 if first.len() != second.len() {
349 return Ok(false);
350 }
351 charge(first.len() as u64)?;
352 Ok(first == second)
353}
354
355impl<'a> AlgorithmIdentifier<'a> {
356 #[must_use]
359 pub fn has_null_parameter(self) -> bool {
360 self.null_parameter
361 }
362
363 pub fn same_written_in(self, other: &Self, parent: &Reader<'_>) -> Result<bool> {
372 self.value_matches(other, parent, false)
373 }
374
375 pub fn digest_matches_in(self, other: &Self, parent: &Reader<'_>) -> Result<bool> {
385 self.value_matches(other, parent, true)
386 }
387
388 fn value_matches(self, other: &Self, parent: &Reader<'_>, digest: bool) -> Result<bool> {
389 require_written_parsers(&self, other, parent)?;
390 let sha2 = if digest {
391 let known = self.validate_digest_params(parent)?;
392 other.validate_digest_params(parent)?;
393 known
394 } else {
395 false
396 };
397 written_values(&self, other, parent, sha2)
398 }
399
400 fn validate_digest_params(self, parent: &Reader<'_>) -> Result<bool> {
401 let charge = |amount| {
402 parent.charge(amount).map_err(|error| {
403 Error::new(ErrorCode::Encoding(error.code()), self.field, self.offset)
404 })
405 };
406 charge(1)?;
407 let kind = self.algorithm.as_bytes();
408 if kind.len() != 9 {
409 return Ok(false);
410 }
411 charge(9)?;
412 if kind[..8] != [0x60, 0x86, 0x48, 1, 0x65, 3, 4, 2] || kind[8] < 1 || kind[8] > 4 {
413 return Ok(false);
414 }
415 if self.parameter_start.is_some() && !self.null_parameter {
416 return Err(Error::new(
420 ErrorCode::MalformedValue,
421 self.field,
422 self.offset,
423 ));
424 }
425 Ok(true)
426 }
427 #[must_use]
429 pub fn algorithm(self) -> Oid<'a> {
430 self.algorithm
431 }
432
433 #[must_use]
440 pub fn parameters(self) -> Option<&'a [u8]> {
441 parameter_bytes(self.der, self.parameter_start, self.indefinite)
442 }
443
444 #[must_use]
446 pub fn offset(self) -> u64 {
447 self.offset
448 }
449
450 #[must_use]
452 pub fn encoding(self) -> Encoding {
453 self.encoding
454 }
455
456 pub fn parameters_reader_in<'query>(
469 self,
470 parent: &Reader<'query>,
471 field: &'static str,
472 ) -> Result<Option<Reader<'query>>>
473 where
474 'a: 'query,
475 {
476 if !self.same_session(parent) {
477 return Err(Error::new(ErrorCode::ForeignReader, field, self.offset));
478 }
479 let at = self
480 .parameter_start
481 .map_or(self.offset, |start| self.offset + start.get() as u64);
482 parent
483 .execution()
484 .charge_work(1)
485 .map_err(|reason| Error::resource(reason, field, at))?;
486 let Some(parameter) = self.parameters() else {
487 return Ok(None);
488 };
489 self.parser
490 .read_nested_query_in(parent, parameter, at, self.encoding, self.outer)
491 .field(field)
492 .map(Some)
493 }
494
495 pub(crate) fn parameters_nested(self) -> Option<Nested<'a>> {
497 let start = self.parameter_start?.get();
498 Some(self.nested(self.parameters()?, self.offset + start as u64))
499 }
500
501 pub(crate) fn nested(self, bytes: &'a [u8], at: u64) -> Nested<'a> {
504 Nested {
505 bytes,
506 at,
507 parser: self.parser,
508 outer: self.outer,
509 encoding: self.encoding,
510 }
511 }
512
513 #[must_use]
517 pub fn same_session(self, parent: &ScopedReader<'_, '_>) -> bool {
518 core::ptr::eq(self.parser, parent.parser())
519 }
520
521 #[must_use]
526 pub fn as_bytes(self) -> &'a [u8] {
527 self.der
528 }
529
530 #[must_use]
533 pub fn has_no_parameters(self) -> bool {
534 self.parameters()
536 .is_none_or(|parameters| parameters == [0x05, 0x00])
537 }
538
539 pub fn matches(self, other: &AlgorithmIdentifier<'_>, execution: &Memory) -> Result<bool> {
580 self.matches_with(other, |work| {
581 execution
582 .charge_work(work)
583 .map_err(|reason| Error::resource(reason, self.field, self.offset))
584 })
585 }
586
587 pub(crate) fn matches_in(
588 self,
589 other: &AlgorithmIdentifier<'_>,
590 parent: &Reader<'_>,
591 ) -> Result<bool> {
592 self.matches_with(other, |work| {
593 parent.charge(work).map_err(|error| {
594 Error::new(ErrorCode::Encoding(error.code()), self.field, self.offset)
595 })
596 })
597 }
598
599 fn matches_with(
600 self,
601 other: &AlgorithmIdentifier<'_>,
602 mut charge: impl FnMut(u64) -> Result<()>,
603 ) -> Result<bool> {
604 charge(1)?;
605 if self.algorithm.as_bytes().len() != other.algorithm.as_bytes().len() {
606 return Ok(false);
607 }
608 charge(self.algorithm.as_bytes().len() as u64)?;
609 if self.algorithm != other.algorithm {
610 return Ok(false);
611 }
612 if self.has_no_parameters() && other.has_no_parameters() {
613 return Ok(true);
614 }
615 let (Some(left), Some(right)) = (self.parameters(), other.parameters()) else {
616 return Ok(false);
617 };
618 if left.len() != right.len() {
619 return Ok(false);
620 }
621 charge(left.len() as u64)?;
622 Ok(left == right)
623 }
624}
625
626pub fn read<'a>(
637 parent: &ScopedReader<'a, '_>,
638 element: &Element<'a>,
639 field: &'static str,
640) -> Result<AlgorithmIdentifier<'a>> {
641 read_tagged(
642 parent,
643 element,
644 Tag::constructed(universal::SEQUENCE),
645 field,
646 )
647}
648
649pub fn read_implicit<'a>(
658 parent: &Reader<'a>,
659 element: &Element<'a>,
660 number: u32,
661 field: &'static str,
662) -> Result<AlgorithmIdentifier<'a>> {
663 read_tagged(parent, element, Tag::context(true, number), field)
664}
665
666pub fn read_inspection<'a>(
673 parent: &Reader<'a>,
674 element: &Element<'a>,
675 field: &'static str,
676) -> Result<AlgorithmReading<'a>> {
677 read_fields::<true>(
678 parent,
679 element,
680 Tag::constructed(universal::SEQUENCE),
681 field,
682 )
683}
684
685pub fn read_implicit_inspection<'a>(
687 parent: &Reader<'a>,
688 element: &Element<'a>,
689 number: u32,
690 field: &'static str,
691) -> Result<AlgorithmReading<'a>> {
692 read_fields::<true>(parent, element, Tag::context(true, number), field)
693}
694
695fn read_fields<'a, const INSPECTION: bool>(
696 parent: &ScopedReader<'a, '_>,
697 element: &Element<'a>,
698 expected: Tag,
699 field: &'static str,
700) -> Result<AlgorithmReading<'a>> {
701 let fail = |code| Error::new(code, field, element.span().start);
702 if element.tag() != expected {
703 return Err(fail(ErrorCode::Encoding(
704 structured_asn1::ErrorCode::UnexpectedTag,
705 )));
706 }
707 let mut inside = parent.enter(element).field(field)?;
708 let algorithm = inside.read_oid().field(field)?;
709 let parameter = inside.next_element().field(field)?;
710 let mut fault = None;
711 let mut null_parameter = false;
712 if let Some(parameter) = ¶meter {
713 match crate::name::walk_der(&inside, parameter, field, crate::name::Strings::Checked) {
714 Ok(()) => {
715 null_parameter = parameter.tag() == Tag::primitive(universal::NULL);
720 }
721 Err(error) => {
722 if !INSPECTION || error.is_resource() || error.code() == ErrorCode::ForeignReader {
723 return Err(error);
724 }
725 fault = Some(error);
726 }
727 }
728 }
729 if !inside.is_empty() {
730 return Err(fail(ErrorCode::TrailingData));
731 }
732 let parameter_start = match parameter {
733 None => None,
734 Some(parameter) => {
735 let start = usize::try_from(parameter.span().start - element.span().start)
736 .map_err(|_| fail(ErrorCode::ValueTooLarge))?;
737 Some(NonZeroUsize::new(start).expect("the algorithm OID precedes its parameters"))
738 }
739 };
740 Ok(AlgorithmReading {
741 fields: AlgorithmFields {
742 algorithm,
743 parameter_start,
744 null_parameter,
745 der: element.as_bytes(),
746 offset: element.span().start,
747 field,
748 parser: parent.parser(),
749 outer: parent.depth(),
750 encoding: inside.encoding(),
751 indefinite: element.is_indefinite(),
752 },
753 fault,
754 })
755}
756
757fn read_tagged<'a>(
758 parent: &ScopedReader<'a, '_>,
759 element: &Element<'a>,
760 expected: Tag,
761 field: &'static str,
762) -> Result<AlgorithmIdentifier<'a>> {
763 read_fields::<false>(parent, element, expected, field)?.into_identifier()
764}
765
766#[cfg(test)]
767mod tests;