Skip to main content

structured_cms/attribute_certificate/
role.rs

1//! Original role assertions (RFC5755 §4.4.5 / Appendix B).
2//!
3//! Decoding neither authenticates the role authority nor grants a permission.
4//! A role specification certificate need not exist; no URI is dereferenced.
5//! <https://www.rfc-editor.org/rfc/rfc5755#section-4.4.5>
6
7use super::{end, names, sequence, tag};
8use crate::attribute::Attribute;
9use crate::signer::required;
10use crate::{Error, ErrorCode, Result};
11use structured_asn1::memory::{OwnedVec, Work};
12use structured_asn1::{Element, Encoding, Oid, ScopedReader, Tag};
13use structured_pkix::general_name::{self, GeneralName};
14
15const FIELD: &str = "attributeCertificate.role";
16
17/// `id-at-role` (2.5.4.72), RFC5755 §4.4.5 / Appendix B.
18pub const IDENTIFIER: Oid<'static> = Oid::from_bytes(&[0x55, 4, 72]);
19
20/// A complete DER role assertion, borrowing the original document. Authority
21/// metadata retains its capacity charge independently of the shorter query.
22#[derive(Debug)]
23pub struct RoleSyntax<'a> {
24    element: Element<'a>,
25    authority_element: Option<Element<'a>>,
26    authority: Option<OwnedVec<GeneralName<'a>>>,
27    name_wrapper: Element<'a>,
28    name_element: Element<'a>,
29    name: &'a str,
30}
31
32impl<'a> RoleSyntax<'a> {
33    /// Reads exactly one standalone role value. AC signed information is DER
34    /// even when a BER envelope carries it (RFC5755 §4.1).
35    pub fn read(parent: &mut ScopedReader<'a, '_>) -> Result<Self> {
36        let element = required(parent, FIELD)?;
37        let reading = Self::read_element(parent, &element)?;
38        end(parent, FIELD)?;
39        Ok(reading)
40    }
41
42    /// Reads an original element under its producing source/depth and current
43    /// execution. All fields and trailing bytes are checked before success.
44    pub fn read_element(parent: &ScopedReader<'a, '_>, element: &Element<'a>) -> Result<Self> {
45        let mut der = parent
46            .reread(element, Encoding::Der)
47            .map_err(|e| Error::encoding(e, FIELD))?;
48        let element = required(&mut der, FIELD)?;
49        tag(&element, sequence(), FIELD)?;
50        end(&der, FIELD)?;
51        let mut inside = der.enter(&element).map_err(|e| Error::encoding(e, FIELD))?;
52        let mut next = required(&mut inside, FIELD)?;
53        let (authority_element, authority) = if next.tag() == Tag::context(true, 0) {
54            // Appendix B is IMPLICIT TAGS: replace the GeneralNames SEQUENCE
55            // tag, but retain the GeneralName CHOICE tag inside [1] below.
56            let authority = names(&inside, &next, FIELD)?;
57            let original = next;
58            next = required(&mut inside, FIELD)?;
59            (Some(original), Some(authority))
60        } else {
61            (None, None)
62        };
63        tag(&next, Tag::context(true, 1), FIELD)?;
64        end(&inside, FIELD)?;
65        let mut wrapped = inside.enter(&next).map_err(|e| Error::encoding(e, FIELD))?;
66        let name_element = required(&mut wrapped, FIELD)?;
67        // RFC5755 §4.4.5 requires the URI CHOICE, not an arbitrary GeneralName.
68        // Preflight the tag before decoding an unrelated allocating Name.
69        tag(&name_element, Tag::context(false, 6), FIELD)?;
70        end(&wrapped, FIELD)?;
71        let GeneralName::Uri(name) =
72            general_name::read(&wrapped, &name_element, FIELD).map_err(Error::pkix)?
73        else {
74            unreachable!("URI tag preflight")
75        };
76        Ok(Self {
77            element,
78            authority_element,
79            authority,
80            name_wrapper: next,
81            name_element,
82            name,
83        })
84    }
85
86    /// Reads every value of one registered `id-at-role` Attribute in source
87    /// order. RFC5755 §4.4.5 permits multiple values, unlike group/charging
88    /// singleton syntax. Empty or invalid later values refuse the whole read;
89    /// no successful partial catalogue or authorization fact is returned.
90    pub fn read_attribute<W: Work>(attribute: &Attribute<'a>, work: &W) -> Result<OwnedVec<Self>> {
91        let execution = attribute.query_in(work);
92        // One fixed-width OID comparison and cardinality metadata. Longer
93        // attacker-selected OIDs fail on length, without scanning their bytes.
94        execution
95            .charge_work(4)
96            .map_err(|e| Error::resource(e, FIELD, attribute.span().start))?;
97        if attribute.kind() != IDENTIFIER {
98            return Err(Error::schema(
99                ErrorCode::UnexpectedContentType,
100                FIELD,
101                attribute.span().start,
102            ));
103        }
104        if attribute.values().is_empty() {
105            return Err(Error::schema(
106                ErrorCode::AttributeCardinality,
107                FIELD,
108                attribute.span().start,
109            ));
110        }
111        let mut values = execution.vector();
112        // The immutable Attribute already supplies the complete count. Reserve
113        // the result once, avoiding descriptor moves on geometric growth.
114        values
115            .try_reserve_exact(attribute.values().len())
116            .map_err(|e| Error::resource(e, FIELD, attribute.span().start))?;
117        for index in 0..attribute.values().len() {
118            let mut reader = attribute
119                .value_reader_scoped(index, &execution, FIELD)?
120                .ok_or_else(|| {
121                    Error::schema(
122                        ErrorCode::AttributeCardinality,
123                        FIELD,
124                        attribute.span().start,
125                    )
126                })?;
127            let at = reader.offset();
128            let value = Self::read(&mut reader)?;
129            values
130                .try_push(value)
131                .map_err(|e| Error::resource(e, FIELD, at))?;
132        }
133        Ok(values.into_owned())
134    }
135
136    /// Original whole `RoleSyntax` encoding.
137    #[must_use]
138    pub fn element(&self) -> Element<'a> {
139        self.element
140    }
141    /// Optional original authority names, not authenticated by this reader.
142    #[must_use]
143    pub fn authority(&self) -> Option<&[GeneralName<'a>]> {
144        self.authority.as_deref()
145    }
146    /// Original `[0] IMPLICIT GeneralNames`, if written.
147    #[must_use]
148    pub fn authority_element(&self) -> Option<Element<'a>> {
149        self.authority_element
150    }
151    /// Original mandatory `[1] EXPLICIT GeneralName` wrapper.
152    #[must_use]
153    pub fn name_wrapper(&self) -> Element<'a> {
154        self.name_wrapper
155    }
156    /// Original URI CHOICE element, inside the explicit wrapper.
157    #[must_use]
158    pub fn name_element(&self) -> Element<'a> {
159        self.name_element
160    }
161    /// Original validated URI, without normalization, copying or acquisition.
162    #[must_use]
163    pub fn name(&self) -> &'a str {
164        self.name
165    }
166}