Skip to main content

structured_pkix/hybrid/
components.rs

1use super::{
2    ALT_SIGNATURE_ALGORITHM, ALT_SIGNATURE_VALUE, FIELD, Fault, SUBJECT_ALT_PUBLIC_KEY_INFO,
3    terminal,
4};
5use crate::algorithm::{self, AlgorithmIdentifier};
6use crate::error::Located;
7use crate::signature::SignatureValue;
8use crate::{Error, ErrorCode, Extensions, PublicKeyInfo, Result};
9use structured_asn1::memory::Work;
10use structured_asn1::{Element, ScopedReader, Span};
11
12/// One original component, its criticality when an extension, and its reading.
13/// Missing/malformed values remain inspectable; resource/caller failures are terminal.
14#[derive(Debug)]
15pub struct Component<'a, T> {
16    span: Option<Span>,
17    critical: Option<bool>,
18    bytes: Option<&'a [u8]>,
19    value: core::result::Result<Option<T>, Fault>,
20    field: &'static str,
21    at: u64,
22}
23impl<'a, T: Copy> Component<'a, T> {
24    pub(super) fn absent(field: &'static str) -> Self {
25        Self {
26            span: None,
27            critical: None,
28            bytes: None,
29            value: Ok(None),
30            field,
31            at: 0,
32        }
33    }
34    /// Original whole extension or attribute range; absent for a missing component.
35    #[must_use]
36    pub fn span(&self) -> Option<Span> {
37        self.span
38    }
39    /// An extension's criticality; attributes and absent values have none.
40    #[must_use]
41    pub fn critical(&self) -> Option<bool> {
42        self.critical
43    }
44    /// Original encoded payload, including malformed bytes when readable.
45    #[must_use]
46    pub fn as_bytes(&self) -> Option<&'a [u8]> {
47        self.bytes
48    }
49    /// Successfully decoded value, actual absence or the original conformance fault.
50    pub fn reading(&self) -> core::result::Result<Option<T>, Fault> {
51        self.value
52    }
53    pub(super) fn require(&self) -> Result<T> {
54        match self.value {
55            Ok(Some(value)) => Ok(value),
56            Ok(None) => Err(Error::new(ErrorCode::MissingField, self.field, self.at)),
57            Err(fault) => Err(fault.error()),
58        }
59    }
60    pub(super) fn read(
61        span: Span,
62        critical: Option<bool>,
63        bytes: &'a [u8],
64        field: &'static str,
65        action: impl FnOnce() -> Result<T>,
66    ) -> Result<Self> {
67        let value = match action() {
68            Ok(value) => Ok(Some(value)),
69            Err(error) if terminal(&error) => return Err(error),
70            Err(error) => Err(Fault::of(&error)),
71        };
72        Ok(Self {
73            span: Some(span),
74            critical,
75            bytes: Some(bytes),
76            value,
77            field,
78            at: span.start,
79        })
80    }
81}
82
83/// Independent alternative component readings. No mathematical or trust verdict.
84#[derive(Debug)]
85pub struct Components<'a> {
86    /// Subject's alternative SPKI (absent for a normal CRL).
87    pub key: Component<'a, PublicKeyInfo<'a>>,
88    /// Protected alternative signature algorithm.
89    pub algorithm: Component<'a, AlgorithmIdentifier<'a>>,
90    /// Alternative signature's original BIT STRING.
91    pub signature: Component<'a, SignatureValue<'a>>,
92}
93impl<'a> Components<'a> {
94    pub(super) fn empty(at: u64) -> Self {
95        let mut result = Self {
96            key: Component::absent("hybrid.subjectAltPublicKeyInfo"),
97            algorithm: Component::absent("hybrid.altSignatureAlgorithm"),
98            signature: Component::absent("hybrid.altSignatureValue"),
99        };
100        result.key.at = at;
101        result.algorithm.at = at;
102        result.signature.at = at;
103        result
104    }
105    pub(super) fn signature_fields(
106        &self,
107    ) -> Result<(AlgorithmIdentifier<'a>, SignatureValue<'a>, Span)> {
108        let algorithm = self.algorithm.require()?;
109        let signature = self.signature.require()?;
110        Ok((
111            algorithm,
112            signature,
113            self.signature
114                .span
115                .expect("a decoded signature has a source"),
116        ))
117    }
118}
119
120pub(super) fn extensions<'a, W: Work>(
121    extensions: &Extensions<'a>,
122    work: &W,
123    at: u64,
124) -> Result<Components<'a>> {
125    work.charge_work(1)
126        .map_err(|e| Error::resource(e, FIELD, at))?;
127    let mut output = Components::empty(at);
128    for extension in extensions.iter(work) {
129        let extension = extension?;
130        let kind = extension.kind();
131        // Admit OID comparisons before inspecting attacker-controlled contents.
132        super::identifier_work(kind, work, extension.span().start)?;
133        if kind == SUBJECT_ALT_PUBLIC_KEY_INFO {
134            output.key = Component::read(
135                extension.span(),
136                Some(extension.is_critical()),
137                extension.value(),
138                "hybrid.subjectAltPublicKeyInfo",
139                || {
140                    let mut reader = extension.reader_scoped(work).field(FIELD)?;
141                    let element = one(&mut reader)?;
142                    PublicKeyInfo::read_element(&reader, &element, FIELD)
143                },
144            )?;
145        } else if kind == ALT_SIGNATURE_ALGORITHM {
146            output.algorithm = Component::read(
147                extension.span(),
148                Some(extension.is_critical()),
149                extension.value(),
150                "hybrid.altSignatureAlgorithm",
151                || {
152                    let mut reader = extension.reader_scoped(work).field(FIELD)?;
153                    let element = one(&mut reader)?;
154                    algorithm::read(&reader, &element, FIELD)
155                },
156            )?;
157        } else if kind == ALT_SIGNATURE_VALUE {
158            output.signature = Component::read(
159                extension.span(),
160                Some(extension.is_critical()),
161                extension.value(),
162                "hybrid.altSignatureValue",
163                || {
164                    let mut reader = extension.reader_scoped(work).field(FIELD)?;
165                    let value = SignatureValue::read(&mut reader, FIELD)?;
166                    end(&reader)?;
167                    Ok(value)
168                },
169            )?;
170        }
171    }
172    Ok(output)
173}
174
175pub(super) fn one<'a>(reader: &mut ScopedReader<'a, '_>) -> Result<Element<'a>> {
176    let value = reader
177        .next_element()
178        .field(FIELD)?
179        .ok_or_else(|| Error::new(ErrorCode::MissingField, FIELD, reader.offset()))?;
180    end(reader)?;
181    Ok(value)
182}
183pub(super) fn end(reader: &ScopedReader<'_, '_>) -> Result<()> {
184    if !reader.is_empty() {
185        return Err(Error::new(ErrorCode::TrailingData, FIELD, reader.offset()));
186    }
187    Ok(())
188}