webpki/
x509.rs

1// Copyright 2015 Brian Smith.
2//
3// Permission to use, copy, modify, and/or distribute this software for any
4// purpose with or without fee is hereby granted, provided that the above
5// copyright notice and this permission notice appear in all copies.
6//
7// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
8// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
10// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14
15use crate::{der, Error};
16
17pub(crate) struct Extension<'a> {
18    pub(crate) critical: bool,
19    pub(crate) id: untrusted::Input<'a>,
20    pub(crate) value: untrusted::Input<'a>,
21}
22
23impl<'a> Extension<'a> {
24    pub(crate) fn parse(der: &mut untrusted::Reader<'a>) -> Result<Extension<'a>, Error> {
25        let id = der::expect_tag_and_get_value(der, der::Tag::OID)?;
26        let critical = der::optional_boolean(der)?;
27        let value = der::expect_tag_and_get_value(der, der::Tag::OctetString)?;
28        Ok(Extension {
29            id,
30            critical,
31            value,
32        })
33    }
34
35    pub(crate) fn unsupported(&self) -> Result<(), Error> {
36        match self.critical {
37            true => Err(Error::UnsupportedCriticalExtension),
38            false => Ok(()),
39        }
40    }
41}
42
43pub(crate) fn set_extension_once<T>(
44    destination: &mut Option<T>,
45    parser: impl Fn() -> Result<T, Error>,
46) -> Result<(), Error> {
47    match destination {
48        // The extension value has already been set, indicating that we encountered it
49        // more than once in our serialized data. That's invalid!
50        Some(..) => Err(Error::ExtensionValueInvalid),
51        None => {
52            *destination = Some(parser()?);
53            Ok(())
54        }
55    }
56}
57
58pub(crate) fn remember_extension(
59    extension: &Extension,
60    mut handler: impl FnMut(u8) -> Result<(), Error>,
61) -> Result<(), Error> {
62    // ISO arc for standard certificate and CRL extensions.
63    // https://www.rfc-editor.org/rfc/rfc5280#appendix-A.2
64    static ID_CE: [u8; 2] = oid![2, 5, 29];
65
66    if extension.id.len() != ID_CE.len() + 1
67        || !extension.id.as_slice_less_safe().starts_with(&ID_CE)
68    {
69        return extension.unsupported();
70    }
71
72    // safety: we verify len is non-zero and has the correct prefix above.
73    let last_octet = *extension.id.as_slice_less_safe().last().unwrap();
74    handler(last_octet)
75}