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