structured_xades/produce/
basic.rs1use super::{DS, Datatype, Emit, Error, Event, Value, Work, Writer, XADES};
4use structured_pkix::Certificate;
5
6#[derive(Debug, Clone, Copy)]
9pub struct DataObject<'a> {
10 pub reference: &'a str,
12 pub mime_type: &'a str,
14}
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
18pub enum ReferenceKind {
19 SignedProperties,
21 CounterSignature,
23}
24impl ReferenceKind {
25 #[must_use]
27 pub const fn type_uri(self) -> &'static str {
28 match self {
29 Self::SignedProperties => crate::binding::SIGNED_PROPERTIES,
30 Self::CounterSignature => "http://uri.etsi.org/01903#CountersignedSignature",
31 }
32 }
33}
34
35#[derive(Debug, Clone, Copy)]
37pub struct BasicReferences<'a> {
38 pub signed_properties: &'a str,
40 pub counter_signature: Option<&'a str>,
42}
43
44pub struct Basic<'a, 'certificate> {
53 pub target: &'a str,
55 pub signed_properties_id: &'a str,
57 pub signing_time: &'a str,
59 pub certificate: &'a Certificate<'certificate>,
61 pub certificate_digest_method: &'a str,
63 pub certificate_digest: &'a [u8],
65 pub objects: &'a [DataObject<'a>],
67 pub counter_signature: Option<&'a str>,
69}
70
71impl Basic<'_, '_> {
72 pub fn write<'a, B: Writer, W: Work>(
81 &'a self,
82 writer: &mut B,
83 work: &W,
84 ) -> Result<BasicReferences<'a>, Error<B::Error>> {
85 work.charge_work(1).map_err(Error::Resource)?;
86 if self.target.is_empty()
87 || self.signed_properties_id.is_empty()
88 || self.signing_time.is_empty()
89 || self.certificate_digest_method.is_empty()
90 || self.certificate_digest.is_empty()
91 {
92 return Err(Error::Value("basic.required"));
93 }
94 if self.counter_signature.is_none() && self.objects.is_empty() {
95 return Err(Error::Value("basic.dataObjects"));
96 }
97 for object in self.objects {
98 work.charge_work(1).map_err(Error::Resource)?;
99 if object.reference.is_empty() {
100 return Err(Error::Value("dataObject.reference"));
101 }
102 let mut mime = structured_cms::mime::Syntax::<true>::new();
103 if !mime.feed(object.mime_type, work).map_err(Error::Resource)? || !mime.complete() {
104 return Err(Error::Value("dataObject.mimeType"));
105 }
106 }
107 let mut emit = Emit { writer, work };
108 emit.begin(XADES, "QualifyingProperties")?;
109 emit.attribute("Target", self.target)?;
110 emit.begin(XADES, "SignedProperties")?;
111 emit.attribute("Id", self.signed_properties_id)?;
112 emit.begin(XADES, "SignedSignatureProperties")?;
113 emit.begin(XADES, "SigningTime")?;
114 emit.event(Event::Text(Value {
115 lexical: self.signing_time,
116 datatype: Datatype::ZonedDateTime,
117 }))?;
118 emit.end()?;
119 emit.begin(XADES, "SigningCertificateV2")?;
120 emit.begin(XADES, "Cert")?;
121 emit.begin(XADES, "CertDigest")?;
122 emit.digest(self.certificate_digest_method, self.certificate_digest)?;
123 emit.end()?;
124 emit.end()?;
125 emit.end()?;
126 emit.end()?;
127 if !self.objects.is_empty() {
128 emit.begin(XADES, "SignedDataObjectProperties")?;
129 for object in self.objects {
130 emit.begin(XADES, "DataObjectFormat")?;
131 emit.attribute("ObjectReference", object.reference)?;
132 emit.text(XADES, "MimeType", object.mime_type)?;
133 emit.end()?;
134 }
135 emit.end()?;
136 }
137 emit.end()?;
138 emit.end()?;
139 Ok(BasicReferences {
140 signed_properties: self.signed_properties_id,
141 counter_signature: self.counter_signature,
142 })
143 }
144
145 pub fn write_key_info<B: Writer, W: Work>(
148 &self,
149 writer: &mut B,
150 work: &W,
151 ) -> Result<(), Error<B::Error>> {
152 let scoped = self.certificate.execution_in(work);
153 let mut emit = Emit {
154 writer,
155 work: &scoped,
156 };
157 emit.begin(DS, "KeyInfo")?;
158 emit.begin(DS, "X509Data")?;
159 emit.binary(DS, "X509Certificate", self.certificate.as_bytes())?;
160 emit.end()?;
161 emit.end()
162 }
163}