1use super::{
11 AttributeCertificate,
12 validation::usage::{AttributeUse, Checked},
13};
14use crate::{
15 Error, ErrorCode, Result,
16 attribute::Attribute,
17 enveloped::{EnvelopedData, oid_is},
18 signer::required,
19};
20use structured_asn1::memory::{Execution, OwnedVec, Work};
21use structured_asn1::{Element, Encoding, Integer, Oid, Reader, Span, Tag, universal};
22use structured_pkix::general_name::{self, GeneralName};
23
24pub const IDENTIFIER: Oid<'static> = Oid::from_bytes(&[43, 6, 1, 5, 5, 7, 10, 6]);
26pub const CONTENT_TYPE: Oid<'static> =
28 Oid::from_bytes(&[42, 134, 72, 134, 247, 13, 1, 9, 16, 1, 14]);
29const FIELD: &str = "attributeCertificate.encAttrs";
30const CLEAR: &str = "acClearAttrs";
31
32#[derive(Debug)]
34pub struct ClearAttrs<'a> {
35 pub issuer: GeneralName<'a>,
37 pub serial: Integer<'a>,
39 pub attributes: OwnedVec<Attribute<'a>>,
42 element: Element<'a>,
43}
44impl<'a> ClearAttrs<'a> {
45 pub fn read(parent: &mut Reader<'a>) -> Result<Self> {
48 let element = parent
49 .expect(Tag::constructed(universal::SEQUENCE))
50 .map_err(|e| Error::encoding(e, CLEAR))?;
51 let mut der = parent
52 .reread(&element, Encoding::Der)
53 .map_err(|e| Error::encoding(e, CLEAR))?;
54 let element = der
55 .expect(Tag::constructed(universal::SEQUENCE))
56 .map_err(|e| Error::encoding(e, CLEAR))?;
57 let mut inside = der.enter(&element).map_err(|e| Error::encoding(e, CLEAR))?;
58 let value = required(&mut inside, "acClearAttrs.acIssuer")?;
59 let issuer =
60 general_name::read(&inside, &value, "acClearAttrs.acIssuer").map_err(Error::pkix)?;
61 let serial = inside
62 .read_integer()
63 .map_err(|e| Error::encoding(e, "acClearAttrs.acSerial"))?;
64 let sequence = inside
65 .expect(Tag::constructed(universal::SEQUENCE))
66 .map_err(|e| Error::encoding(e, "acClearAttrs.attrs"))?;
67 let mut members = inside
68 .enter(&sequence)
69 .map_err(|e| Error::encoding(e, CLEAR))?;
70 let work = inside.execution();
71 let mut attributes = work.vector();
72 while let Some(element) = members
73 .next_element()
74 .map_err(|e| Error::encoding(e, CLEAR))?
75 {
76 attributes
77 .try_reserve(1)
78 .map_err(|e| Error::resource(e, CLEAR, element.span().start))?;
79 let value = Attribute::read(&members, &element, "acClearAttrs.attrs")?;
80 attributes
81 .try_push(value)
82 .map_err(|e| Error::resource(e, CLEAR, element.span().start))?;
83 }
84 end(&inside)?;
85 end(parent)?;
86 Ok(Self {
87 issuer,
88 serial,
89 attributes: attributes.into_owned(),
90 element,
91 })
92 }
93 #[must_use]
95 pub fn element(&self) -> &Element<'a> {
96 &self.element
97 }
98}
99
100pub enum Attempt<T> {
104 Decrypted(T),
106 NotRecipient,
108 Unsupported,
110 Rejected,
112}
113#[derive(Debug, Clone, Copy, PartialEq, Eq)]
115pub enum Rejection {
116 Decryption,
118 Issuer,
120 Serial,
122}
123#[derive(Debug)]
125pub enum Outcome<T> {
126 Processed(T),
128 NotRecipient,
130 Unsupported,
132 Rejected(Rejection),
134}
135#[derive(Debug, Clone, Copy, PartialEq, Eq)]
139pub struct PlaintextSource {
140 pub value: usize,
142 pub envelope: Span,
144}
145#[derive(Debug)]
147pub enum DecryptError<P, V> {
148 Processing(Error),
150 Provider {
152 envelope: Span,
154 cause: P,
156 },
157 Plaintext {
159 cause: Error,
161 source: PlaintextSource,
163 },
164 Visitor {
166 cause: V,
168 source: PlaintextSource,
170 },
171}
172pub struct Bound<'s> {
175 clear: ClearAttrs<'s>,
176 attributes: OwnedVec<AttributeUse>,
177 source: PlaintextSource,
178}
179impl Bound<'_> {
180 #[must_use]
182 pub fn clear(&self) -> &ClearAttrs<'_> {
183 &self.clear
184 }
185 #[must_use]
187 pub fn attributes(&self) -> &[AttributeUse] {
188 &self.attributes
189 }
190 #[must_use]
192 pub fn source(&self) -> PlaintextSource {
193 self.source
194 }
195}
196pub struct Encrypted<'r, 'a> {
200 certificate: &'r AttributeCertificate<'a>,
201 envelopes: OwnedVec<EnvelopedData<'a>>,
202}
203impl<'r, 'a> Encrypted<'r, 'a> {
204 pub fn read(
208 certificate: &'r AttributeCertificate<'a>,
209 parent: &Reader<'a>,
210 ) -> Result<Option<Self>> {
211 if !core::ptr::eq(certificate.parser, parent.parser()) {
212 return Err(Error::pkix(structured_pkix::Error::new(
213 structured_pkix::ErrorCode::ForeignReader,
214 FIELD,
215 certificate.element().span().start,
216 )));
217 }
218 let work = parent.execution();
219 let mut selected = None;
220 for attribute in &certificate.information().attributes {
221 work.charge_work(1)
222 .map_err(|e| Error::resource(e, FIELD, attribute.span().start))?;
223 if attribute.kind().as_bytes().len() != IDENTIFIER.as_bytes().len() {
224 continue;
225 }
226 work.charge_work(IDENTIFIER.as_bytes().len() as u64)
227 .map_err(|e| Error::resource(e, FIELD, attribute.span().start))?;
228 if attribute.kind() == IDENTIFIER {
229 selected = Some(attribute);
230 break;
231 }
232 }
233 let Some(attribute) = selected else {
234 return Ok(None);
235 };
236 let mut envelopes = work.vector();
237 envelopes
238 .try_reserve_exact(attribute.values().len())
239 .map_err(|e| Error::resource(e, FIELD, attribute.span().start))?;
240 for ordinal in 0..attribute.values().len() {
241 let mut reader = attribute
242 .value_reader_in(ordinal, parent, FIELD)?
243 .ok_or_else(|| {
244 Error::schema(ErrorCode::InvalidLocation, FIELD, attribute.span().start)
245 })?;
246 let envelope = EnvelopedData::read(&mut reader)?;
247 oid_is(
248 envelope.content.kind,
249 CONTENT_TYPE,
250 &reader,
251 FIELD,
252 envelope.element().span().start,
253 )?;
254 if envelope.content.ciphertext.is_none() {
255 return Err(Error::schema(
256 ErrorCode::DetachedContent,
257 FIELD,
258 envelope.element().span().start,
259 ));
260 }
261 envelopes
262 .try_push(envelope)
263 .map_err(|e| Error::resource(e, FIELD, attribute.span().start))?;
264 }
265 Ok(Some(Self {
266 certificate,
267 envelopes: envelopes.into_owned(),
268 }))
269 }
270 #[must_use]
273 pub fn envelopes(&self) -> &[EnvelopedData<'a>] {
274 &self.envelopes
275 }
276
277 pub fn decrypt_all<'p, 'd, 'c, S, P, V, R>(
296 &self,
297 checked: &Checked<'_, 'p, 'd, 'c, S>,
298 parent: &Reader<'_>,
299 mut provider: impl FnMut(
300 &EnvelopedData<'a>,
301 &Execution<'_>,
302 ) -> core::result::Result<Attempt<OwnedVec<u8>>, P>,
303 mut visitor: impl for<'scope> FnMut(
304 &Bound<'scope>,
305 &Execution<'_>,
306 ) -> core::result::Result<R, V>,
307 ) -> core::result::Result<OwnedVec<Outcome<R>>, DecryptError<P, V>> {
308 let physical = DecryptError::Processing;
309 if !core::ptr::eq(self.certificate.parser, parent.parser())
310 || !core::ptr::eq(self.certificate, checked.certificate())
311 {
312 return Err(physical(Error::schema(
313 ErrorCode::InvalidLocation,
314 FIELD,
315 self.certificate.element().span().start,
316 )));
317 }
318 let work = parent.execution();
319 let mut results = work.vector();
320 results
321 .try_reserve_exact(self.envelopes.len())
322 .map_err(|e| {
323 physical(Error::resource(
324 e,
325 FIELD,
326 self.certificate.element().span().start,
327 ))
328 })?;
329 for (ordinal, envelope) in self.envelopes.iter().enumerate() {
330 work.charge_work(1).map_err(|e| {
331 physical(Error::resource(e, FIELD, envelope.element().span().start))
332 })?;
333 let output = provider(envelope, &work).map_err(|cause| DecryptError::Provider {
334 envelope: envelope.element().span(),
335 cause,
336 })?;
337 let outcome = match output {
338 Attempt::NotRecipient => Outcome::NotRecipient,
339 Attempt::Unsupported => Outcome::Unsupported,
340 Attempt::Rejected => Outcome::Rejected(Rejection::Decryption),
341 Attempt::Decrypted(bytes) => {
342 if !bytes.memory().same_account(parent.memory()) {
343 return Err(physical(Error::schema(
344 ErrorCode::InvalidLocation,
345 FIELD,
346 envelope.element().span().start,
347 )));
348 }
349 self.visit(checked, parent, envelope, ordinal, &bytes, &mut visitor)?
350 }
351 };
352 results.try_push(outcome).map_err(|e| {
353 physical(Error::resource(e, FIELD, envelope.element().span().start))
354 })?;
355 }
356 Ok(results.into_owned())
357 }
358
359 fn visit<'p, 'd, 'c, S, P, V, R>(
360 &self,
361 checked: &Checked<'_, 'p, 'd, 'c, S>,
362 parent: &Reader<'_>,
363 envelope: &EnvelopedData<'a>,
364 ordinal: usize,
365 bytes: &[u8],
366 visitor: &mut impl for<'scope> FnMut(
367 &Bound<'scope>,
368 &Execution<'_>,
369 ) -> core::result::Result<R, V>,
370 ) -> core::result::Result<Outcome<R>, DecryptError<P, V>> {
371 let source = PlaintextSource {
372 value: ordinal,
373 envelope: envelope.element().span(),
374 };
375 let logical = |cause| DecryptError::Plaintext { cause, source };
376 let ciphertext = envelope
380 .content
381 .ciphertext
382 .as_ref()
383 .expect("encAttrs requires attached ciphertext");
384 let mut reader = self
385 .certificate
386 .parser
387 .read_nested_query_in(parent, bytes, 0, Encoding::Der, ciphertext.outer_depth())
388 .map_err(|e| logical(Error::encoding(e, CLEAR)))?;
389 let clear = ClearAttrs::read(&mut reader).map_err(logical)?;
390 let work = reader.execution();
391 let ac = self.certificate;
392 work.charge_work(3)
393 .map_err(|e| logical(Error::resource(e, CLEAR, clear.element.span().start)))?;
394 let left = clear.serial.as_bytes();
395 let right = ac.information().serial.as_bytes();
396 if left.len() != right.len() {
400 return Ok(Outcome::Rejected(Rejection::Serial));
401 }
402 work.charge_work(left.len() as u64 + right.len() as u64)
403 .map_err(|e| {
404 logical(Error::resource(
405 e,
406 "acClearAttrs.acSerial",
407 clear.element.span().start,
408 ))
409 })?;
410 if left != right {
411 return Ok(Outcome::Rejected(Rejection::Serial));
412 }
413 let Some([GeneralName::Directory(actual)]) = ac.information().issuer.names.as_deref()
417 else {
418 unreachable!("authenticated profile restricts issuer to one directoryName")
419 };
420 let GeneralName::Directory(claimed) = &clear.issuer else {
421 return Ok(Outcome::Rejected(Rejection::Issuer));
422 };
423 let actual = actual
424 .ordered(&work)
425 .map_err(|e| DecryptError::Processing(Error::pkix(e)))?;
426 let claimed = claimed
427 .ordered_in(&reader)
428 .map_err(|e| logical(Error::pkix(e)))?;
429 if claimed
430 .order(&actual, &work)
431 .map_err(|e| logical(Error::pkix(e)))?
432 != core::cmp::Ordering::Equal
433 {
434 return Ok(Outcome::Rejected(Rejection::Issuer));
435 }
436 let mut attributes = work.vector();
437 attributes
438 .try_reserve_exact(clear.attributes.len())
439 .map_err(|e| logical(Error::resource(e, CLEAR, clear.element.span().start)))?;
440 for (index, attribute) in clear.attributes.iter().enumerate() {
441 work.charge_work(1)
442 .map_err(|e| logical(Error::resource(e, CLEAR, attribute.span().start)))?;
443 let permission = checked
446 .allows(attribute.kind(), &work)
447 .map_err(DecryptError::Processing)?;
448 attributes
449 .try_push(AttributeUse { index, permission })
450 .map_err(|e| logical(Error::resource(e, CLEAR, attribute.span().start)))?;
451 }
452 let bound = Bound {
453 clear,
454 attributes: attributes.into_owned(),
455 source,
456 };
457 let output =
458 visitor(&bound, &work).map_err(|cause| DecryptError::Visitor { cause, source })?;
459 Ok(Outcome::Processed(output))
460 }
461}
462fn end(parent: &Reader<'_>) -> Result<()> {
463 if parent.is_empty() {
464 Ok(())
465 } else {
466 Err(Error::schema(
467 ErrorCode::TrailingData,
468 CLEAR,
469 parent.offset(),
470 ))
471 }
472}