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};
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 mut constraints = Self {
169            permitted: inside.memory().vector(),
170            excluded: inside.memory().vector(),
171        };
172
173        // The schema fixes the order: permitted, then excluded. A tag at or
174        // below the last one read is a repeat or a field written backwards,
175        // and neither is this schema.
176        let mut last_number = None;
177        while let Some(field) = inside.next_element().field(FIELD)? {
178            let tag = extension::context_of(field.tag());
179            let subtrees = match tag {
180                Some((0, true)) if last_number.is_none() => &mut constraints.permitted,
181                Some((1, true)) if last_number < Some(1) => &mut constraints.excluded,
182                _ => {
183                    return Err(Error::new(
184                        ErrorCode::UnexpectedField,
185                        FIELD,
186                        field.span().start,
187                    ));
188                }
189            };
190            last_number = tag.map(|(number, _)| number);
191
192            let mut list = inside.enter(&field).field(FIELD)?;
193            while let Some(entry) = list.next_element().field(FIELD)? {
194                subtrees
195                    .try_push(read_subtree(&list, &entry, FIELD)?)
196                    .map_err(|reason| Error::resource(reason, FIELD, entry.span().start))?;
197            }
198            if subtrees.is_empty() {
199                return Err(Error::new(
200                    ErrorCode::EmptySequence,
201                    FIELD,
202                    field.span().start,
203                ));
204            }
205        }
206
207        // A constraint that permits nothing and excludes nothing constrains
208        // nothing, while being marked critical to say it must be obeyed.
209        if constraints.permitted.is_empty() && constraints.excluded.is_empty() {
210            return Err(fail(ErrorCode::MalformedValue));
211        }
212        Ok(constraints)
213    }
214}
215
216/// Limits on how policies are processed below this certificate.
217#[derive(Debug, Clone, Copy)]
218pub struct PolicyConstraints {
219    require_explicit_policy: Option<CertificateCount>,
220    inhibit_policy_mapping: Option<CertificateCount>,
221}
222
223impl PolicyConstraints {
224    /// After how many certificates a path must name a policy.
225    #[must_use]
226    pub fn require_explicit_policy(self) -> Option<CertificateCount> {
227        self.require_explicit_policy
228    }
229
230    /// After how many certificates policy mappings stop being honoured.
231    #[must_use]
232    pub fn inhibit_policy_mapping(self) -> Option<CertificateCount> {
233        self.inhibit_policy_mapping
234    }
235
236    /// Reads the value of a policy constraints extension.
237    pub fn read(extension: &Extension<'_>, execution: &Memory) -> Result<Self> {
238        const FIELD: &str = "extensions.policyConstraints";
239        let fail = |code| Error::new(code, FIELD, extension.span().start);
240
241        let mut inside = extension::sequence(extension, FIELD, execution)?;
242        let mut constraints = Self {
243            require_explicit_policy: None,
244            inhibit_policy_mapping: None,
245        };
246
247        // Fixed order here too: a tag at or below the last one read is not
248        // this schema.
249        let mut last_number = None;
250        while let Some(field) = inside.next_element().field(FIELD)? {
251            let tag = extension::context_of(field.tag());
252            match tag {
253                Some((0, false)) if last_number.is_none() => {
254                    constraints.require_explicit_policy = Some(read_count(&inside, &field, FIELD)?);
255                }
256                Some((1, false)) if last_number < Some(1) => {
257                    constraints.inhibit_policy_mapping = Some(read_count(&inside, &field, FIELD)?);
258                }
259                _ => {
260                    return Err(Error::new(
261                        ErrorCode::UnexpectedField,
262                        FIELD,
263                        field.span().start,
264                    ));
265                }
266            }
267            last_number = tag.map(|(number, _)| number);
268        }
269
270        // Neither field written is an extension that says nothing.
271        if constraints.require_explicit_policy.is_none()
272            && constraints.inhibit_policy_mapping.is_none()
273        {
274            return Err(fail(ErrorCode::MalformedValue));
275        }
276        Ok(constraints)
277    }
278}
279
280/// After how many certificates the identifier standing for any policy stops
281/// being accepted.
282#[derive(Debug, Clone, Copy)]
283pub struct InhibitAnyPolicy {
284    skip: CertificateCount,
285}
286
287impl InhibitAnyPolicy {
288    /// How many certificates it survives.
289    #[must_use]
290    pub fn skip(self) -> CertificateCount {
291        self.skip
292    }
293
294    /// Reads the value of an inhibit-any-policy extension.
295    pub fn read(extension: &Extension<'_>, execution: &Memory) -> Result<Self> {
296        const FIELD: &str = "extensions.inhibitAnyPolicy";
297        let fail = |code| Error::new(code, FIELD, extension.span().start);
298
299        let mut reader = extension.reader(execution).field(FIELD)?;
300        let element = reader
301            .next_element()
302            .field(FIELD)?
303            .ok_or_else(|| fail(ErrorCode::MissingField))?;
304        if element.tag() != Tag::primitive(universal::INTEGER) {
305            return Err(fail(ErrorCode::Encoding(
306                structured_asn1::ErrorCode::UnexpectedTag,
307            )));
308        }
309        let skip = read_count(&reader, &element, FIELD)?;
310        if !reader.is_empty() {
311            return Err(fail(ErrorCode::TrailingData));
312        }
313
314        Ok(Self { skip })
315    }
316}
317
318fn read_subtree<'a>(
319    parent: &structured_asn1::Reader<'a>,
320    element: &structured_asn1::Element<'a>,
321    field: &'static str,
322) -> Result<Subtree<'a>> {
323    let fail = |code| Error::new(code, field, element.span().start);
324
325    if element.tag() != Tag::constructed(universal::SEQUENCE) {
326        return Err(fail(ErrorCode::Encoding(
327            structured_asn1::ErrorCode::UnexpectedTag,
328        )));
329    }
330
331    let mut inside = parent.enter(element).field(field)?;
332    let base_element = inside
333        .next_element()
334        .field(field)?
335        .ok_or_else(|| fail(ErrorCode::MissingField))?;
336    let base = general_name::read_as(
337        &inside,
338        &base_element,
339        field,
340        general_name::AddressForm::WithMask,
341    )?;
342
343    // The profile requires the minimum to be zero and the maximum to be
344    // absent (RFC 5280 4.2.1.10): either written otherwise asks for a
345    // reading this profile does not define. Zero spelled out is refused
346    // under DER as a second spelling of the absent default (X.690 11.5) and
347    // read under BER, which carries no such rule.
348    let mut last_number = None;
349    while let Some(distance) = inside.next_element().field(field)? {
350        let tag = extension::context_of(distance.tag());
351        match tag {
352            Some((0, false)) if last_number.is_none() => {
353                let count = read_count(&inside, &distance, field)?;
354                if !count.is_zero() || inside.encoding().is_der() {
355                    return Err(Error::new(
356                        ErrorCode::MalformedValue,
357                        field,
358                        distance.span().start,
359                    ));
360                }
361            }
362            _ => {
363                return Err(Error::new(
364                    ErrorCode::UnexpectedField,
365                    field,
366                    distance.span().start,
367                ));
368            }
369        }
370        last_number = tag.map(|(number, _)| number);
371    }
372
373    Ok(Subtree { base })
374}
375
376/// Reads a count of certificates, which is never negative.
377fn read_count(
378    parent: &structured_asn1::Reader<'_>,
379    element: &structured_asn1::Element<'_>,
380    field: &'static str,
381) -> Result<CertificateCount> {
382    let value = parent.integer(element).field(field)?;
383    // Below zero is outside the schema, which bounds every one of these
384    // fields at zero (RFC 5280 4.2.1.9, 4.2.1.11, 4.2.1.14).
385    if value.is_negative() {
386        return Err(Error::new(
387            ErrorCode::MalformedValue,
388            field,
389            element.span().start,
390        ));
391    }
392    // Above the type is still inside the schema, whose upper bound is MAX:
393    // the count is understood, and what it says is that nothing reaches it.
394    Ok(value.as_u32().map_or(
395        CertificateCount::BeyondAnyPath,
396        CertificateCount::Certificates,
397    ))
398}
399
400#[cfg(test)]
401mod tests;