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, Span, Tag, universal};
12
13#[derive(Debug, Clone, Copy)]
15pub struct AlgorithmIdentifier<'a> {
16 algorithm: Oid<'a>,
17 parameter_start: Option<NonZeroUsize>,
20 null_parameter: bool,
21 der: &'a [u8],
22 offset: u64,
23 field: &'static str,
24 parser: &'a Parser,
25 outer: u32,
26 encoding: Encoding,
27 indefinite: bool,
28}
29
30#[derive(Debug, Clone, Copy)]
33struct AlgorithmFields<'a> {
34 algorithm: Oid<'a>,
35 parameter_start: Option<NonZeroUsize>,
36 null_parameter: bool,
37 der: &'a [u8],
38 offset: u64,
39 field: &'static str,
40 parser: &'a Parser,
41 outer: u32,
42 encoding: Encoding,
43 indefinite: bool,
44}
45
46#[derive(Debug)]
60pub struct AlgorithmReading<'a> {
61 fields: AlgorithmFields<'a>,
62 fault: Option<Error>,
63}
64
65impl<'a> AlgorithmReading<'a> {
66 #[must_use]
68 pub fn algorithm(&self) -> Oid<'a> {
69 self.fields.algorithm
70 }
71
72 #[must_use]
74 pub fn parameters(&self) -> Option<&'a [u8]> {
75 parameter_bytes(
76 self.fields.der,
77 self.fields.parameter_start,
78 self.fields.indefinite,
79 )
80 }
81
82 #[must_use]
85 pub fn parameters_span(&self) -> Option<Span> {
86 let start = self.fields.parameter_start?.get();
87 Some(Span {
88 start: self.fields.offset + start as u64,
89 length: self.parameters()?.len() as u64,
90 })
91 }
92
93 #[must_use]
96 pub fn has_null_parameter(&self) -> bool {
97 self.fields.null_parameter
98 }
99
100 #[must_use]
102 pub fn as_bytes(&self) -> &'a [u8] {
103 self.fields.der
104 }
105
106 #[must_use]
108 pub fn offset(&self) -> u64 {
109 self.fields.offset
110 }
111
112 #[must_use]
114 pub fn encoding(&self) -> Encoding {
115 self.fields.encoding
116 }
117
118 #[must_use]
122 pub fn same_session(&self, parent: &Reader<'_>) -> bool {
123 core::ptr::eq(self.fields.parser, parent.parser())
124 }
125
126 #[must_use]
128 pub fn fault(&self) -> Option<&Error> {
129 self.fault.as_ref()
130 }
131
132 #[must_use]
135 pub fn identifier(&self) -> Option<AlgorithmIdentifier<'a>> {
136 if self.fault.is_some() {
137 return None;
138 }
139 Some(self.fields.identifier())
140 }
141
142 pub fn require_identifier(&self) -> Result<AlgorithmIdentifier<'a>> {
146 match &self.fault {
147 Some(error) => Err(error.clone()),
148 None => Ok(self.fields.identifier()),
149 }
150 }
151
152 pub fn same_written_in(&self, other: &Self, parent: &Reader<'_>) -> Result<bool> {
157 written_matches(&self.fields, &other.fields, parent, false)
158 }
159
160 fn into_identifier(self) -> Result<AlgorithmIdentifier<'a>> {
161 match self.fault {
162 Some(error) => Err(error),
163 None => Ok(self.fields.identifier()),
164 }
165 }
166}
167
168impl<'a> AlgorithmFields<'a> {
169 fn identifier(self) -> AlgorithmIdentifier<'a> {
171 AlgorithmIdentifier {
172 algorithm: self.algorithm,
173 parameter_start: self.parameter_start,
174 null_parameter: self.null_parameter,
175 der: self.der,
176 offset: self.offset,
177 field: self.field,
178 parser: self.parser,
179 outer: self.outer,
180 encoding: self.encoding,
181 indefinite: self.indefinite,
182 }
183 }
184}
185
186fn parameter_bytes(bytes: &[u8], start: Option<NonZeroUsize>, indefinite: bool) -> Option<&[u8]> {
187 let start = start?.get();
188 let end = bytes.len() - if indefinite { 2 } else { 0 };
189 Some(&bytes[start..end])
190}
191
192trait WrittenValue {
193 fn oid_bytes(&self) -> &[u8];
194 fn parameter_bytes(&self) -> Option<&[u8]>;
195 fn valid_null(&self) -> bool;
196 fn producer(&self) -> &Parser;
197 fn field(&self) -> &'static str;
198 fn offset(&self) -> u64;
199}
200
201impl WrittenValue for AlgorithmFields<'_> {
202 fn oid_bytes(&self) -> &[u8] {
203 self.algorithm.as_bytes()
204 }
205 fn parameter_bytes(&self) -> Option<&[u8]> {
206 parameter_bytes(self.der, self.parameter_start, self.indefinite)
207 }
208 fn valid_null(&self) -> bool {
209 self.null_parameter
210 }
211 fn producer(&self) -> &Parser {
212 self.parser
213 }
214 fn field(&self) -> &'static str {
215 self.field
216 }
217 fn offset(&self) -> u64 {
218 self.offset
219 }
220}
221
222impl WrittenValue for AlgorithmIdentifier<'_> {
223 fn oid_bytes(&self) -> &[u8] {
224 self.algorithm.as_bytes()
225 }
226 fn parameter_bytes(&self) -> Option<&[u8]> {
227 self.parameters()
228 }
229 fn valid_null(&self) -> bool {
230 self.null_parameter
231 }
232 fn producer(&self) -> &Parser {
233 self.parser
234 }
235 fn field(&self) -> &'static str {
236 self.field
237 }
238 fn offset(&self) -> u64 {
239 self.offset
240 }
241}
242
243fn require_written_parsers(
244 left: &impl WrittenValue,
245 right: &impl WrittenValue,
246 parent: &Reader<'_>,
247) -> Result<()> {
248 if !core::ptr::eq(left.producer(), parent.parser()) {
249 return Err(Error::new(
250 ErrorCode::ForeignReader,
251 left.field(),
252 left.offset(),
253 ));
254 }
255 if !core::ptr::eq(right.producer(), parent.parser()) {
256 return Err(Error::new(
257 ErrorCode::ForeignReader,
258 right.field(),
259 right.offset(),
260 ));
261 }
262 Ok(())
263}
264
265fn written_matches(
266 left: &impl WrittenValue,
267 right: &impl WrittenValue,
268 parent: &Reader<'_>,
269 defaults: bool,
270) -> Result<bool> {
271 require_written_parsers(left, right, parent)?;
272 written_values(left, right, parent, defaults)
273}
274
275fn written_values(
276 left: &impl WrittenValue,
277 right: &impl WrittenValue,
278 parent: &Reader<'_>,
279 defaults: bool,
280) -> Result<bool> {
281 let charge = |amount| {
282 parent.charge(amount).map_err(|error| {
283 Error::new(
284 ErrorCode::Encoding(error.code()),
285 right.field(),
286 right.offset(),
287 )
288 })
289 };
290 charge(1)?;
291 let kind = left.oid_bytes();
292 if kind.len() != right.oid_bytes().len() {
293 return Ok(false);
294 }
295 charge(kind.len() as u64)?;
296 if kind != right.oid_bytes() {
297 return Ok(false);
298 }
299 if defaults || (left.valid_null() && right.valid_null()) {
300 return Ok(true);
301 }
302 let (Some(first), Some(second)) = (left.parameter_bytes(), right.parameter_bytes()) else {
303 return Ok(left.parameter_bytes().is_none() && right.parameter_bytes().is_none());
304 };
305 if first.len() != second.len() {
306 return Ok(false);
307 }
308 charge(first.len() as u64)?;
309 Ok(first == second)
310}
311
312impl<'a> AlgorithmIdentifier<'a> {
313 #[must_use]
316 pub fn has_null_parameter(self) -> bool {
317 self.null_parameter
318 }
319
320 pub fn same_written_in(self, other: &Self, parent: &Reader<'_>) -> Result<bool> {
329 self.value_matches(other, parent, false)
330 }
331
332 pub fn digest_matches_in(self, other: &Self, parent: &Reader<'_>) -> Result<bool> {
342 self.value_matches(other, parent, true)
343 }
344
345 fn value_matches(self, other: &Self, parent: &Reader<'_>, digest: bool) -> Result<bool> {
346 require_written_parsers(&self, other, parent)?;
347 let sha2 = if digest {
348 let known = self.validate_digest_params(parent)?;
349 other.validate_digest_params(parent)?;
350 known
351 } else {
352 false
353 };
354 written_values(&self, other, parent, sha2)
355 }
356
357 fn validate_digest_params(self, parent: &Reader<'_>) -> Result<bool> {
358 let charge = |amount| {
359 parent.charge(amount).map_err(|error| {
360 Error::new(ErrorCode::Encoding(error.code()), self.field, self.offset)
361 })
362 };
363 charge(1)?;
364 let kind = self.algorithm.as_bytes();
365 if kind.len() != 9 {
366 return Ok(false);
367 }
368 charge(9)?;
369 if kind[..8] != [0x60, 0x86, 0x48, 1, 0x65, 3, 4, 2] || kind[8] < 1 || kind[8] > 4 {
370 return Ok(false);
371 }
372 if self.parameter_start.is_some() && !self.null_parameter {
373 return Err(Error::new(
377 ErrorCode::MalformedValue,
378 self.field,
379 self.offset,
380 ));
381 }
382 Ok(true)
383 }
384 #[must_use]
386 pub fn algorithm(self) -> Oid<'a> {
387 self.algorithm
388 }
389
390 #[must_use]
397 pub fn parameters(self) -> Option<&'a [u8]> {
398 parameter_bytes(self.der, self.parameter_start, self.indefinite)
399 }
400
401 #[must_use]
403 pub fn offset(self) -> u64 {
404 self.offset
405 }
406
407 #[must_use]
409 pub fn encoding(self) -> Encoding {
410 self.encoding
411 }
412
413 pub fn parameters_reader_in<'query>(
426 self,
427 parent: &Reader<'query>,
428 field: &'static str,
429 ) -> Result<Option<Reader<'query>>>
430 where
431 'a: 'query,
432 {
433 if !self.same_session(parent) {
434 return Err(Error::new(ErrorCode::ForeignReader, field, self.offset));
435 }
436 let at = self
437 .parameter_start
438 .map_or(self.offset, |start| self.offset + start.get() as u64);
439 parent
440 .execution()
441 .charge_work(1)
442 .map_err(|reason| Error::resource(reason, field, at))?;
443 let Some(parameter) = self.parameters() else {
444 return Ok(None);
445 };
446 self.parser
447 .read_nested_query_in(parent, parameter, at, self.encoding, self.outer)
448 .field(field)
449 .map(Some)
450 }
451
452 #[must_use]
456 pub fn same_session(self, parent: &Reader<'_>) -> bool {
457 core::ptr::eq(self.parser, parent.parser())
458 }
459
460 #[must_use]
465 pub fn as_bytes(self) -> &'a [u8] {
466 self.der
467 }
468
469 #[must_use]
472 pub fn has_no_parameters(self) -> bool {
473 self.parameters()
475 .is_none_or(|parameters| parameters == [0x05, 0x00])
476 }
477
478 pub fn matches(self, other: &AlgorithmIdentifier<'_>, execution: &Memory) -> Result<bool> {
519 self.matches_with(other, |work| {
520 execution
521 .charge_work(work)
522 .map_err(|reason| Error::resource(reason, self.field, self.offset))
523 })
524 }
525
526 pub(crate) fn matches_in(
527 self,
528 other: &AlgorithmIdentifier<'_>,
529 parent: &Reader<'_>,
530 ) -> Result<bool> {
531 self.matches_with(other, |work| {
532 parent.charge(work).map_err(|error| {
533 Error::new(ErrorCode::Encoding(error.code()), self.field, self.offset)
534 })
535 })
536 }
537
538 fn matches_with(
539 self,
540 other: &AlgorithmIdentifier<'_>,
541 mut charge: impl FnMut(u64) -> Result<()>,
542 ) -> Result<bool> {
543 charge(1)?;
544 if self.algorithm.as_bytes().len() != other.algorithm.as_bytes().len() {
545 return Ok(false);
546 }
547 charge(self.algorithm.as_bytes().len() as u64)?;
548 if self.algorithm != other.algorithm {
549 return Ok(false);
550 }
551 if self.has_no_parameters() && other.has_no_parameters() {
552 return Ok(true);
553 }
554 let (Some(left), Some(right)) = (self.parameters(), other.parameters()) else {
555 return Ok(false);
556 };
557 if left.len() != right.len() {
558 return Ok(false);
559 }
560 charge(left.len() as u64)?;
561 Ok(left == right)
562 }
563}
564
565pub fn read<'a>(
576 parent: &Reader<'a>,
577 element: &Element<'a>,
578 field: &'static str,
579) -> Result<AlgorithmIdentifier<'a>> {
580 read_tagged(
581 parent,
582 element,
583 Tag::constructed(universal::SEQUENCE),
584 field,
585 )
586}
587
588pub fn read_implicit<'a>(
597 parent: &Reader<'a>,
598 element: &Element<'a>,
599 number: u32,
600 field: &'static str,
601) -> Result<AlgorithmIdentifier<'a>> {
602 read_tagged(parent, element, Tag::context(true, number), field)
603}
604
605pub fn read_inspection<'a>(
612 parent: &Reader<'a>,
613 element: &Element<'a>,
614 field: &'static str,
615) -> Result<AlgorithmReading<'a>> {
616 read_fields::<true>(
617 parent,
618 element,
619 Tag::constructed(universal::SEQUENCE),
620 field,
621 )
622}
623
624pub fn read_implicit_inspection<'a>(
626 parent: &Reader<'a>,
627 element: &Element<'a>,
628 number: u32,
629 field: &'static str,
630) -> Result<AlgorithmReading<'a>> {
631 read_fields::<true>(parent, element, Tag::context(true, number), field)
632}
633
634fn read_fields<'a, const INSPECTION: bool>(
635 parent: &Reader<'a>,
636 element: &Element<'a>,
637 expected: Tag,
638 field: &'static str,
639) -> Result<AlgorithmReading<'a>> {
640 let fail = |code| Error::new(code, field, element.span().start);
641 if element.tag() != expected {
642 return Err(fail(ErrorCode::Encoding(
643 structured_asn1::ErrorCode::UnexpectedTag,
644 )));
645 }
646 let mut inside = parent.enter(element).field(field)?;
647 let algorithm = inside.read_oid().field(field)?;
648 let parameter = inside.next_element().field(field)?;
649 let mut fault = None;
650 let mut null_parameter = false;
651 if let Some(parameter) = ¶meter {
652 match crate::name::walk_der(&inside, parameter, field, crate::name::Strings::Checked) {
653 Ok(()) => {
654 null_parameter = parameter.tag() == Tag::primitive(universal::NULL);
659 }
660 Err(error) => {
661 if !INSPECTION || error.is_resource() || error.code() == ErrorCode::ForeignReader {
662 return Err(error);
663 }
664 fault = Some(error);
665 }
666 }
667 }
668 if !inside.is_empty() {
669 return Err(fail(ErrorCode::TrailingData));
670 }
671 let parameter_start = match parameter {
672 None => None,
673 Some(parameter) => {
674 let start = usize::try_from(parameter.span().start - element.span().start)
675 .map_err(|_| fail(ErrorCode::ValueTooLarge))?;
676 Some(NonZeroUsize::new(start).expect("the algorithm OID precedes its parameters"))
677 }
678 };
679 Ok(AlgorithmReading {
680 fields: AlgorithmFields {
681 algorithm,
682 parameter_start,
683 null_parameter,
684 der: element.as_bytes(),
685 offset: element.span().start,
686 field,
687 parser: parent.parser(),
688 outer: parent.depth(),
689 encoding: inside.encoding(),
690 indefinite: element.is_indefinite(),
691 },
692 fault,
693 })
694}
695
696fn read_tagged<'a>(
697 parent: &Reader<'a>,
698 element: &Element<'a>,
699 expected: Tag,
700 field: &'static str,
701) -> Result<AlgorithmIdentifier<'a>> {
702 read_fields::<false>(parent, element, expected, field)?.into_identifier()
703}
704
705#[cfg(test)]
706mod tests;