Skip to main content

structured_cms/enveloped/
recipient.rs

1//! One recipient schema; all algorithm/key decisions remain explicit callbacks.
2use super::{EncodedValue, algorithm, end, enter, number, tag, version};
3use crate::{
4    Error, ErrorCode, Octets, Result,
5    signer::{SignerIdentifier, required},
6};
7use structured_asn1::memory::{OwnedVec, Work};
8use structured_asn1::{Element, Oid, Reader, Tag, universal};
9use structured_pkix::AlgorithmIdentifier;
10
11const FIELD: &str = "envelopedData.recipientInfos";
12
13/// Common KEK/recipient key identifier and its original optional metadata.
14#[derive(Debug)]
15pub struct KeyIdentifier<'a> {
16    identifier: Octets<'a>,
17    date: Option<Element<'a>>,
18    other: Option<(Oid<'a>, Option<Element<'a>>)>,
19    encoding: structured_asn1::Encoding,
20}
21
22/// All three sender-key choices of RFC5652 §6.2.2.
23#[derive(Debug)]
24pub enum Originator<'a> {
25    /// Original issuer/serial or subject-key identifier, not a trusted signer.
26    Identifier(SignerIdentifier<'a>),
27    /// Uncertified sender key. Bits preserve their original primitive or BER
28    /// constructed encoding; the common ASN.1 string walker validated them.
29    Key {
30        /// Original algorithm, including parameter provenance.
31        algorithm: AlgorithmIdentifier<'a>,
32        /// Original validated BIT STRING, not a fabricated SPKI.
33        bits: EncodedValue<'a>,
34    },
35}
36/// One key-agreement recipient's actual certificate identifier and encrypted key.
37#[derive(Debug)]
38pub struct RecipientKey<'a> {
39    /// Original issuer/serial or full recipient-key identifier.
40    pub identifier: AgreementIdentifier<'a>,
41    /// Original encrypted content-encryption key.
42    pub encrypted: Octets<'a>,
43}
44/// Both key-agreement recipient-identifier alternatives (§6.2.2).
45#[derive(Debug)]
46pub enum AgreementIdentifier<'a> {
47    /// Original issuer DN and serial, using the same CMS identity kernel.
48    IssuerAndSerial(SignerIdentifier<'a>),
49    /// `[0] IMPLICIT RecipientKeyIdentifier`, including date/other metadata.
50    KeyIdentifier(KeyIdentifier<'a>),
51}
52/// All five CMS `RecipientInfo` alternatives, without engine dispatch or key lookup.
53#[derive(Debug)]
54pub enum Recipient<'a> {
55    /// Public-key transport (§6.2.1); version is 0 for issuer/serial, 2 for SKI.
56    Transport {
57        /// Declared version, checked against the identifier alternative.
58        version: u64,
59        /// Original selected recipient identity; never an implicit key hint.
60        identifier: SignerIdentifier<'a>,
61        /// Actual key-encryption algorithm and original parameters.
62        algorithm: AlgorithmIdentifier<'a>,
63        /// Original encrypted content-encryption key.
64        encrypted: Octets<'a>,
65    },
66    /// Key agreement (§6.2.2), always version3.
67    Agreement {
68        /// Original sender-key alternative.
69        originator: Originator<'a>,
70        /// Optional explicit user-keying material; absence stays distinct.
71        ukm: Option<Octets<'a>>,
72        /// Original key-encryption algorithm.
73        algorithm: AlgorithmIdentifier<'a>,
74        /// All original recipient encrypted keys, not just the first.
75        keys: OwnedVec<RecipientKey<'a>>,
76    },
77    /// Pre-distributed symmetric KEK (§6.2.3), always version4.
78    Kek {
79        /// Original KEK identifier, date and additional open value.
80        identifier: KeyIdentifier<'a>,
81        /// Original key-encryption algorithm.
82        algorithm: AlgorithmIdentifier<'a>,
83        /// Original encrypted content-encryption key.
84        encrypted: Octets<'a>,
85    },
86    /// Password/shared-secret recipient (§6.2.4), always version0.
87    Password {
88        /// Optional original `[0] IMPLICIT` key derivation algorithm. Absence
89        /// means externally supplied KEK, not an invented default KDF.
90        derivation: Option<AlgorithmIdentifier<'a>>,
91        /// Original key-encryption algorithm.
92        algorithm: AlgorithmIdentifier<'a>,
93        /// Original encrypted content-encryption key.
94        encrypted: Octets<'a>,
95    },
96    /// Named open key-management format (§6.2.5), including RFC9629 KEM.
97    Other {
98        /// Exact format OID. Unknown is not absence or key-transport fallback.
99        kind: Oid<'a>,
100        /// Whole original open value, to be interpreted by its actual owner.
101        value: EncodedValue<'a>,
102    },
103}
104impl<'a> Recipient<'a> {
105    pub(super) fn is_transport_zero(&self) -> bool {
106        matches!(self, Self::Transport { version: 0, .. })
107    }
108    pub(super) fn read(parent: &Reader<'a>, element: &Element<'a>) -> Result<Self> {
109        let mut inside = enter(parent, element, FIELD)?;
110        let result = match element.tag() {
111            t if t == Tag::constructed(universal::SEQUENCE) => {
112                let (version, at) = number(&mut inside, FIELD)?;
113                let value = required(&mut inside, FIELD)?;
114                let identifier = SignerIdentifier::read_as(&inside, &value, FIELD)?;
115                let expected = if matches!(identifier, SignerIdentifier::IssuerAndSerial { .. }) {
116                    0
117                } else {
118                    2
119                };
120                if version != expected {
121                    return Err(Error::schema(ErrorCode::UnsupportedVersion, FIELD, at));
122                }
123                let value = required(&mut inside, FIELD)?;
124                let algorithm = algorithm(&inside, &value, FIELD)?;
125                let encrypted = octets(&mut inside)?;
126                Self::Transport {
127                    version,
128                    identifier,
129                    algorithm,
130                    encrypted,
131                }
132            }
133            t if t == Tag::context(true, 1) => Self::agreement(parent, &mut inside)?,
134            t if t == Tag::context(true, 2) => {
135                version(&mut inside, 4, FIELD)?;
136                let value = inside
137                    .expect(Tag::constructed(universal::SEQUENCE))
138                    .map_err(|e| Error::encoding(e, FIELD))?;
139                let identifier = KeyIdentifier::read(&inside, &value)?;
140                let value = required(&mut inside, FIELD)?;
141                let algorithm = algorithm(&inside, &value, FIELD)?;
142                let encrypted = octets(&mut inside)?;
143                Self::Kek {
144                    identifier,
145                    algorithm,
146                    encrypted,
147                }
148            }
149            t if t == Tag::context(true, 3) => {
150                version(&mut inside, 0, FIELD)?;
151                let mut value = required(&mut inside, FIELD)?;
152                let derivation = if value.tag() == Tag::context(true, 0) {
153                    let derivation =
154                        structured_pkix::algorithm::read_implicit(&inside, &value, 0, FIELD)
155                            .map_err(Error::pkix)?;
156                    value = required(&mut inside, FIELD)?;
157                    Some(derivation)
158                } else {
159                    None
160                };
161                let algorithm = algorithm(&inside, &value, FIELD)?;
162                let encrypted = octets(&mut inside)?;
163                Self::Password {
164                    derivation,
165                    algorithm,
166                    encrypted,
167                }
168            }
169            t if t == Tag::context(true, 4) => {
170                let kind = inside.read_oid().map_err(|e| Error::encoding(e, FIELD))?;
171                let value = required(&mut inside, FIELD)?;
172                structured_pkix::der::conforms(&inside, &value, FIELD).map_err(Error::pkix)?;
173                Self::Other {
174                    kind,
175                    value: EncodedValue::new(&inside, value),
176                }
177            }
178            _ => {
179                return Err(Error::schema(
180                    ErrorCode::UnknownField,
181                    FIELD,
182                    element.span().start,
183                ));
184            }
185        };
186        end(&inside, FIELD)?;
187        Ok(result)
188    }
189}
190impl<'a> Recipient<'a> {
191    fn agreement(parent: &Reader<'a>, inside: &mut Reader<'a>) -> Result<Self> {
192        version(inside, 3, FIELD)?;
193        let wrapper = inside
194            .expect(Tag::context(true, 0))
195            .map_err(|e| Error::encoding(e, FIELD))?;
196        let mut explicit = enter(inside, &wrapper, FIELD)?;
197        let value = required(&mut explicit, FIELD)?;
198        let originator = if value.tag() == Tag::context(true, 1) {
199            let mut key = enter(&explicit, &value, FIELD)?;
200            let value = required(&mut key, FIELD)?;
201            let algorithm = algorithm(&key, &value, FIELD)?;
202            let bits = required(&mut key, FIELD)?;
203            if bits.tag() != Tag::primitive(universal::BIT_STRING)
204                && bits.tag() != Tag::constructed(universal::BIT_STRING)
205            {
206                return Err(Error::schema(
207                    ErrorCode::UnexpectedTag,
208                    FIELD,
209                    bits.span().start,
210                ));
211            }
212            // The common iterative string walker retains the original BER/DER
213            // contract and enforces final-fragment padding before provider work.
214            structured_pkix::der::conforms(&key, &bits, FIELD).map_err(Error::pkix)?;
215            end(&key, FIELD)?;
216            Originator::Key {
217                algorithm,
218                bits: EncodedValue::new(&key, bits),
219            }
220        } else {
221            Originator::Identifier(SignerIdentifier::read_as(&explicit, &value, FIELD)?)
222        };
223        end(&explicit, FIELD)?;
224        let mut value = required(inside, FIELD)?;
225        let ukm = if value.tag() == Tag::context(true, 1) {
226            let mut explicit = enter(inside, &value, FIELD)?;
227            let ukm = octets(&mut explicit)?;
228            end(&explicit, FIELD)?;
229            value = required(inside, FIELD)?;
230            Some(ukm)
231        } else {
232            None
233        };
234        let algorithm = algorithm(inside, &value, FIELD)?;
235        let set = inside
236            .expect(Tag::constructed(universal::SEQUENCE))
237            .map_err(|e| Error::encoding(e, FIELD))?;
238        let mut members = enter(inside, &set, FIELD)?;
239        let work = parent.execution();
240        let mut keys = work.vector();
241        while let Some(value) = members
242            .next_element()
243            .map_err(|e| Error::encoding(e, FIELD))?
244        {
245            keys.try_reserve(1)
246                .map_err(|e| Error::resource(e, FIELD, value.span().start))?;
247            tag(&value, Tag::constructed(universal::SEQUENCE), FIELD)?;
248            let mut entry = enter(&members, &value, FIELD)?;
249            let value = required(&mut entry, FIELD)?;
250            let identifier = if value.tag() == Tag::context(true, 0) {
251                AgreementIdentifier::KeyIdentifier(KeyIdentifier::read(&entry, &value)?)
252            } else {
253                tag(&value, Tag::constructed(universal::SEQUENCE), FIELD)?;
254                AgreementIdentifier::IssuerAndSerial(SignerIdentifier::read_as(
255                    &entry, &value, FIELD,
256                )?)
257            };
258            let encrypted = octets(&mut entry)?;
259            end(&entry, FIELD)?;
260            keys.try_push(RecipientKey {
261                identifier,
262                encrypted,
263            })
264            .map_err(|e| Error::resource(e, FIELD, value.span().start))?;
265        }
266        // RFC5652 §6.2.2 transfers a key to one or more recipients, even though
267        // RecipientEncryptedKeys' ASN.1 SEQUENCE OF has no SIZE annotation.
268        // https://www.rfc-editor.org/rfc/rfc5652#section-6.2.2
269        if keys.is_empty() {
270            return Err(Error::schema(
271                ErrorCode::MissingField,
272                FIELD,
273                set.span().start,
274            ));
275        }
276        Ok(Self::Agreement {
277            originator,
278            ukm,
279            algorithm,
280            keys: keys.into_owned(),
281        })
282    }
283}
284impl<'a> KeyIdentifier<'a> {
285    /// Original key identifier octets, preserving constructed BER fragments.
286    /// The immutable owner also supplies the optional fields' source context.
287    #[must_use]
288    pub fn identifier(&self) -> &Octets<'a> {
289        &self.identifier
290    }
291    /// Original optional `GeneralizedTime`, validated under the actual BER/DER
292    /// contract. No lossy second/nanosecond projection or key-age policy.
293    #[must_use]
294    pub fn date(&self) -> Option<EncodedValue<'a>> {
295        self.date
296            .map(|element| self.encoded(element, self.identifier.outer_depth()))
297    }
298    /// Original additional key attribute OID and OPTIONAL open value (§10.2.7).
299    /// Source metadata is stored once per key identifier, without heap indirection.
300    #[must_use]
301    pub fn other(&self) -> Option<(Oid<'a>, Option<EncodedValue<'a>>)> {
302        self.other.map(|(kind, value)| {
303            // A present value was read after a successful enter of its enclosing
304            // OtherKeyAttribute; that descent already proved this addition safe.
305            let depth = self.identifier.outer_depth();
306            debug_assert!(depth < u32::MAX);
307            (kind, value.map(|element| self.encoded(element, depth + 1)))
308        })
309    }
310    fn encoded(&self, element: Element<'a>, depth: u32) -> EncodedValue<'a> {
311        EncodedValue {
312            element,
313            parser: self.identifier.parser(),
314            encoding: self.encoding,
315            depth,
316        }
317    }
318    fn read(parent: &Reader<'a>, element: &Element<'a>) -> Result<Self> {
319        let mut inside = enter(parent, element, FIELD)?;
320        let identifier = octets(&mut inside)?;
321        let mut next = inside
322            .next_element()
323            .map_err(|e| Error::encoding(e, FIELD))?;
324        let date = if let Some(value) = next.as_ref().filter(|e| {
325            e.tag().number() == Some(universal::GENERALIZED_TIME)
326                && e.tag().class() == structured_asn1::Class::Universal
327        }) {
328            structured_pkix::der::conforms(&inside, value, FIELD).map_err(Error::pkix)?;
329            let time = *value;
330            next = inside
331                .next_element()
332                .map_err(|e| Error::encoding(e, FIELD))?;
333            Some(time)
334        } else {
335            None
336        };
337        let other = if let Some(value) = next {
338            tag(&value, Tag::constructed(universal::SEQUENCE), FIELD)?;
339            let mut fields = enter(&inside, &value, FIELD)?;
340            let kind = fields.read_oid().map_err(|e| Error::encoding(e, FIELD))?;
341            let other = fields
342                .next_element()
343                .map_err(|e| Error::encoding(e, FIELD))?;
344            if let Some(value) = other.as_ref() {
345                structured_pkix::der::conforms(&fields, value, FIELD).map_err(Error::pkix)?;
346            }
347            end(&fields, FIELD)?;
348            Some((kind, other))
349        } else {
350            None
351        };
352        end(&inside, FIELD)?;
353        Ok(Self {
354            identifier,
355            date,
356            other,
357            encoding: inside.encoding(),
358        })
359    }
360}
361fn octets<'a>(parent: &mut Reader<'a>) -> Result<Octets<'a>> {
362    let value = required(parent, FIELD)?;
363    Octets::read(parent, &value, FIELD)
364}