1use crate::{
11 Error,
12 source::{Node, Value},
13};
14use structured_asn1::{
15 Oid, Reader,
16 memory::{OwnedVec, Work},
17};
18use structured_cms::{attribute::Placement, signer::SignerInfo};
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub enum Kind {
23 ArchiveV1,
25 ArchiveV2,
27 LongTermValidation,
29 EvidenceRecordInternal,
31 EvidenceRecordExternal,
33 References,
35 SignatureReferences,
37}
38impl Kind {
39 pub(crate) fn from_oid(value: Oid<'_>) -> Option<Self> {
40 let bytes = value.as_bytes();
41 if bytes.len() == 11 {
42 if bytes[..10] != [42, 134, 72, 134, 247, 13, 1, 9, 16, 2] {
43 return None;
44 }
45 match bytes[10] {
46 27 => Some(Self::ArchiveV1),
47 48 => Some(Self::ArchiveV2),
48 26 => Some(Self::References),
49 25 => Some(Self::SignatureReferences),
50 49 => Some(Self::EvidenceRecordInternal),
51 50 => Some(Self::EvidenceRecordExternal),
52 _ => None,
53 }
54 } else if bytes == [4, 0, 0x8d, 0x45, 2, 2] {
55 Some(Self::LongTermValidation)
56 } else {
57 None
58 }
59 }
60 pub(crate) fn is_reference_timestamp(self) -> bool {
61 matches!(self, Self::References | Self::SignatureReferences)
62 }
63 pub(crate) fn is_archive(self) -> bool {
64 matches!(self, Self::ArchiveV1 | Self::ArchiveV2)
65 }
66 pub(crate) fn is_evidence(self) -> bool {
67 matches!(
68 self,
69 Self::EvidenceRecordInternal | Self::EvidenceRecordExternal | Self::LongTermValidation
70 )
71 }
72}
73
74#[derive(Debug, Clone, Copy)]
76pub struct Required<'document> {
77 pub signature: Node,
79 pub property: Node,
81 pub kind: Kind,
83 pub placement: Placement,
85 pub value: Option<Value<'document>>,
87}
88
89pub(crate) fn roots<'d, W: Work>(
90 message: &structured_cms::SignedData<'d>,
91 parent: &Reader<'d>,
92 work: &W,
93) -> crate::Result<OwnedVec<Required<'d>, W>> {
94 let mut out = work.vector();
95 for signer in message.signers() {
96 parent
97 .charge(1)
98 .map_err(|cause| Error::encoding(cause, "cades.preservation"))?;
99 collect(signer, parent, &mut out)?;
100 }
101 Ok(out)
102}
103
104pub(crate) fn collect<'d, W: Work>(
105 signer: &SignerInfo<'d>,
106 parent: &Reader<'d>,
107 out: &mut OwnedVec<Required<'d>, W>,
108) -> crate::Result<()> {
109 signer.require_session(parent, "cades.preservation")?;
110 for (placement, set) in [
111 (Placement::Signed, signer.signed_attributes()),
112 (Placement::Unsigned, signer.unsigned_attributes()),
113 ] {
114 let Some(set) = set else {
115 continue;
116 };
117 for attribute in set.items() {
118 parent
119 .charge(5 * (1 + attribute.kind().as_bytes().len().min(11) as u64))
120 .map_err(|cause| Error::encoding(cause, "cades.preservation"))?;
121 let kind = Kind::from_oid(attribute.kind());
122 let Some(kind) = kind else {
123 continue;
124 };
125 let resource =
126 |cause| Error::resource(cause, "cades.preservation", attribute.span().start);
127 if attribute.values().is_empty() {
128 out.try_push(Required {
129 signature: Node::of(signer.span()),
130 property: Node::of(attribute.span()),
131 kind,
132 placement,
133 value: None,
134 })
135 .map_err(resource)?;
136 }
137 for (ordinal, value) in attribute.values().iter().enumerate() {
138 let reader = attribute
139 .value_reader_in(ordinal, parent, "cades.preservation")?
140 .ok_or(Error::Foreign {
141 at: value.span().start,
142 })?;
143 out.try_push(Required {
144 signature: Node::of(signer.span()),
145 property: Node::of(attribute.span()),
146 kind,
147 placement,
148 value: Some(Value::of(&reader, *value, "cades.preservation")),
149 })
150 .map_err(resource)?;
151 }
152 }
153 }
154 Ok(())
155}