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