Skip to main content

structured_pkix/
constraints.rs

1//! What a certificate may certify below itself.
2
3use crate::error::{Error, ErrorCode, Located, Result};
4use crate::extension::{self, Extension};
5use crate::general_name::{self, GeneralName};
6use structured_asn1::memory::{Memory, OwnedVec, Work};
7use structured_asn1::{Tag, universal};
8
9/// A count of certificates a constraint names.
10///
11/// The fields counted here are `INTEGER (0..MAX)` (RFC 5280 4.2.1.9, 4.2.1.11
12/// and 4.2.1.14), so a count wider than any path that could be built is inside
13/// the schema. It is kept as what it is, a bound nothing reaches, rather than
14/// refused as malformed or folded into a number the certificate never wrote.
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub enum CertificateCount {
17    /// The count the certificate names.
18    Certificates(u32),
19    /// A count past what a path could hold, which therefore never binds.
20    BeyondAnyPath,
21}
22
23impl CertificateCount {
24    /// The count where a path could reach it, and `None` where nothing can.
25    #[must_use]
26    pub fn certificates(self) -> Option<u32> {
27        match self {
28            Self::Certificates(count) => Some(count),
29            Self::BeyondAnyPath => None,
30        }
31    }
32
33    /// Whether the count is zero, which is the only value some fields permit.
34    #[must_use]
35    pub fn is_zero(self) -> bool {
36        self == Self::Certificates(0)
37    }
38}
39
40/// Whether this is a certification authority, and how far below it a path may
41/// go.
42#[derive(Debug, Clone, Copy)]
43pub struct BasicConstraints {
44    authority: bool,
45    path_length: Option<CertificateCount>,
46}
47
48impl BasicConstraints {
49    /// Whether the certificate may sign other certificates.
50    #[must_use]
51    pub fn is_authority(self) -> bool {
52        self.authority
53    }
54
55    /// How many certificates may sit between this one and the one at the end
56    /// of the path, where the certificate says.
57    ///
58    /// Written without the flag above it constrains nothing, and is kept as
59    /// what the certificate said rather than dropped.
60    #[must_use]
61    pub fn path_length(self) -> Option<CertificateCount> {
62        self.path_length
63    }
64
65    /// Reads the value of a basic constraints extension.
66    pub fn read(extension: &Extension<'_>, execution: &Memory) -> Result<Self> {
67        const FIELD: &str = "extensions.basicConstraints";
68        let fail = |code| Error::new(code, FIELD, extension.span().start);
69
70        let mut inside = extension::sequence(extension, FIELD, execution)?;
71
72        // Absent means not an authority, which is what a certificate issued to
73        // a person leaves it at.
74        let mut authority = false;
75        let mut path_length = None;
76
77        let mut next = inside.next_element().field(FIELD)?;
78        if let Some(flag) = next
79            && flag.tag() == Tag::primitive(universal::BOOLEAN)
80        {
81            authority = inside.boolean(&flag).field(FIELD)?;
82            // X.690 11.5: DER omits a component equal to its default, and the
83            // flag defaults to false. Writing it out is a second spelling of
84            // the absent flag.
85            if !authority && inside.encoding().is_der() {
86                return Err(Error::new(
87                    ErrorCode::MalformedValue,
88                    FIELD,
89                    flag.span().start,
90                ));
91            }
92            next = inside.next_element().field(FIELD)?;
93        }
94
95        if let Some(length) = next {
96            if length.tag() != Tag::primitive(universal::INTEGER) {
97                return Err(fail(ErrorCode::Encoding(
98                    structured_asn1::ErrorCode::UnexpectedTag,
99                )));
100            }
101            // The path length must not be present unless the authority flag
102            // is asserted (RFC 5280 4.2.1.9): without it, the value
103            // constrains a path below a certificate that says it heads none.
104            if !authority {
105                return Err(Error::new(
106                    ErrorCode::UnexpectedField,
107                    FIELD,
108                    length.span().start,
109                ));
110            }
111            path_length = Some(read_count(&inside, &length, FIELD)?);
112        }
113
114        if !inside.is_empty() {
115            return Err(fail(ErrorCode::TrailingData));
116        }
117
118        Ok(Self {
119            authority,
120            path_length,
121        })
122    }
123}
124
125/// The name space a certification authority may certify within.
126#[derive(Debug)]
127pub struct NameConstraints<'a> {
128    permitted: OwnedVec<Subtree<'a>>,
129    excluded: OwnedVec<Subtree<'a>>,
130}
131
132/// One region of the name space, as a name every name in it sits under. The
133/// region starts at its base: the profile requires the minimum distance to
134/// be zero and the maximum to be absent, and a subtree written otherwise is
135/// refused when it is read.
136#[derive(Debug)]
137pub struct Subtree<'a> {
138    base: GeneralName<'a>,
139}
140
141impl<'a> Subtree<'a> {
142    /// The name the region is described by.
143    #[must_use]
144    pub fn base(&self) -> &GeneralName<'a> {
145        &self.base
146    }
147}
148
149impl<'a> NameConstraints<'a> {
150    /// The regions names below this certificate must sit in.
151    #[must_use]
152    pub fn permitted(&self) -> &[Subtree<'a>] {
153        &self.permitted
154    }
155
156    /// The regions they must not.
157    #[must_use]
158    pub fn excluded(&self) -> &[Subtree<'a>] {
159        &self.excluded
160    }
161
162    /// Reads the value of a name constraints extension.
163    pub fn read(extension: &Extension<'a>, execution: &Memory) -> Result<Self> {
164        const FIELD: &str = "extensions.nameConstraints";
165        let fail = |code| Error::new(code, FIELD, extension.span().start);
166
167        let mut inside = extension::sequence(extension, FIELD, execution)?;
168        let work = inside.execution_in(execution);
169        let mut permitted = work.vector();
170        let mut excluded = work.vector();
171
172        // The schema fixes the order: permitted, then excluded. A tag at or
173        // below the last one read is a repeat or a field written backwards,
174        // and neither is this schema.
175        let mut last_number = None;
176        while let Some(field) = inside.next_element().field(FIELD)? {
177            let tag = extension::context_of(field.tag());
178            let subtrees = match tag {
179                Some((0, true)) if last_number.is_none() => &mut permitted,
180                Some((1, true)) if last_number < Some(1) => &mut excluded,
181                _ => {
182                    return Err(Error::new(
183                        ErrorCode::UnexpectedField,
184                        FIELD,
185                        field.span().start,
186                    ));
187                }
188            };
189            last_number = tag.map(|(number, _)| number);
190
191            let mut list = inside.enter(&field).field(FIELD)?;
192            while let Some(entry) = list.next_element().field(FIELD)? {
193                subtrees
194                    .try_push(read_subtree(&list, &entry, FIELD)?)
195                    .map_err(|reason| Error::resource(reason, FIELD, entry.span().start))?;
196            }
197            if subtrees.is_empty() {
198                return Err(Error::new(
199                    ErrorCode::EmptySequence,
200                    FIELD,
201                    field.span().start,
202                ));
203            }
204        }
205
206        // A constraint that permits nothing and excludes nothing constrains
207        // nothing, while being marked critical to say it must be obeyed.
208        if permitted.is_empty() && excluded.is_empty() {
209            return Err(fail(ErrorCode::MalformedValue));
210        }
211        Ok(Self {
212            permitted: permitted.into_owned(),
213            excluded: excluded.into_owned(),
214        })
215    }
216}
217
218/// Limits on how policies are processed below this certificate.
219#[derive(Debug, Clone, Copy)]
220pub struct PolicyConstraints {
221    require_explicit_policy: Option<CertificateCount>,
222    inhibit_policy_mapping: Option<CertificateCount>,
223}
224
225impl PolicyConstraints {
226    /// After how many certificates a path must name a policy.
227    #[must_use]
228    pub fn require_explicit_policy(self) -> Option<CertificateCount> {
229        self.require_explicit_policy
230    }
231
232    /// After how many certificates policy mappings stop being honoured.
233    #[must_use]
234    pub fn inhibit_policy_mapping(self) -> Option<CertificateCount> {
235        self.inhibit_policy_mapping
236    }
237
238    /// Reads the value of a policy constraints extension.
239    pub fn read(extension: &Extension<'_>, execution: &Memory) -> Result<Self> {
240        const FIELD: &str = "extensions.policyConstraints";
241        let fail = |code| Error::new(code, FIELD, extension.span().start);
242
243        let mut inside = extension::sequence(extension, FIELD, execution)?;
244        let mut constraints = Self {
245            require_explicit_policy: None,
246            inhibit_policy_mapping: None,
247        };
248
249        // Fixed order here too: a tag at or below the last one read is not
250        // this schema.
251        let mut last_number = None;
252        while let Some(field) = inside.next_element().field(FIELD)? {
253            let tag = extension::context_of(field.tag());
254            match tag {
255                Some((0, false)) if last_number.is_none() => {
256                    constraints.require_explicit_policy = Some(read_count(&inside, &field, FIELD)?);
257                }
258                Some((1, false)) if last_number < Some(1) => {
259                    constraints.inhibit_policy_mapping = Some(read_count(&inside, &field, FIELD)?);
260                }
261                _ => {
262                    return Err(Error::new(
263                        ErrorCode::UnexpectedField,
264                        FIELD,
265                        field.span().start,
266                    ));
267                }
268            }
269            last_number = tag.map(|(number, _)| number);
270        }
271
272        // Neither field written is an extension that says nothing.
273        if constraints.require_explicit_policy.is_none()
274            && constraints.inhibit_policy_mapping.is_none()
275        {
276            return Err(fail(ErrorCode::MalformedValue));
277        }
278        Ok(constraints)
279    }
280}
281
282/// After how many certificates the identifier standing for any policy stops
283/// being accepted.
284#[derive(Debug, Clone, Copy)]
285pub struct InhibitAnyPolicy {
286    skip: CertificateCount,
287}
288
289impl InhibitAnyPolicy {
290    /// How many certificates it survives.
291    #[must_use]
292    pub fn skip(self) -> CertificateCount {
293        self.skip
294    }
295
296    /// Reads the value of an inhibit-any-policy extension.
297    pub fn read(extension: &Extension<'_>, execution: &Memory) -> Result<Self> {
298        const FIELD: &str = "extensions.inhibitAnyPolicy";
299        let fail = |code| Error::new(code, FIELD, extension.span().start);
300
301        let mut reader = extension.reader(execution).field(FIELD)?;
302        let element = reader
303            .next_element()
304            .field(FIELD)?
305            .ok_or_else(|| fail(ErrorCode::MissingField))?;
306        if element.tag() != Tag::primitive(universal::INTEGER) {
307            return Err(fail(ErrorCode::Encoding(
308                structured_asn1::ErrorCode::UnexpectedTag,
309            )));
310        }
311        let skip = read_count(&reader, &element, FIELD)?;
312        if !reader.is_empty() {
313            return Err(fail(ErrorCode::TrailingData));
314        }
315
316        Ok(Self { skip })
317    }
318}
319
320fn read_subtree<'a>(
321    parent: &structured_asn1::Reader<'a>,
322    element: &structured_asn1::Element<'a>,
323    field: &'static str,
324) -> Result<Subtree<'a>> {
325    let fail = |code| Error::new(code, field, element.span().start);
326
327    if element.tag() != Tag::constructed(universal::SEQUENCE) {
328        return Err(fail(ErrorCode::Encoding(
329            structured_asn1::ErrorCode::UnexpectedTag,
330        )));
331    }
332
333    let mut inside = parent.enter(element).field(field)?;
334    let base_element = inside
335        .next_element()
336        .field(field)?
337        .ok_or_else(|| fail(ErrorCode::MissingField))?;
338    let base = general_name::read_as(
339        &inside,
340        &base_element,
341        field,
342        general_name::AddressForm::WithMask,
343    )?;
344
345    // The profile requires the minimum to be zero and the maximum to be
346    // absent (RFC 5280 4.2.1.10): either written otherwise asks for a
347    // reading this profile does not define. Zero spelled out is refused
348    // under DER as a second spelling of the absent default (X.690 11.5) and
349    // read under BER, which carries no such rule.
350    let mut last_number = None;
351    while let Some(distance) = inside.next_element().field(field)? {
352        let tag = extension::context_of(distance.tag());
353        match tag {
354            Some((0, false)) if last_number.is_none() => {
355                let count = read_count(&inside, &distance, field)?;
356                if !count.is_zero() || inside.encoding().is_der() {
357                    return Err(Error::new(
358                        ErrorCode::MalformedValue,
359                        field,
360                        distance.span().start,
361                    ));
362                }
363            }
364            _ => {
365                return Err(Error::new(
366                    ErrorCode::UnexpectedField,
367                    field,
368                    distance.span().start,
369                ));
370            }
371        }
372        last_number = tag.map(|(number, _)| number);
373    }
374
375    Ok(Subtree { base })
376}
377
378/// Reads a count of certificates, which is never negative.
379fn read_count(
380    parent: &structured_asn1::Reader<'_>,
381    element: &structured_asn1::Element<'_>,
382    field: &'static str,
383) -> Result<CertificateCount> {
384    let value = parent.integer(element).field(field)?;
385    // Below zero is outside the schema, which bounds every one of these
386    // fields at zero (RFC 5280 4.2.1.9, 4.2.1.11, 4.2.1.14).
387    if value.is_negative() {
388        return Err(Error::new(
389            ErrorCode::MalformedValue,
390            field,
391            element.span().start,
392        ));
393    }
394    // Above the type is still inside the schema, whose upper bound is MAX:
395    // the count is understood, and what it says is that nothing reaches it.
396    Ok(value.as_u32().map_or(
397        CertificateCount::BeyondAnyPath,
398        CertificateCount::Certificates,
399    ))
400}
401
402#[cfg(test)]
403mod tests;