20
20
#include " SignatureTST.h"
21
21
22
22
#include " ASiC_S.h"
23
+ #include " Conf.h"
23
24
#include " DataFile_p.h"
25
+ #include " XMLDocument.h"
24
26
#include " crypto/Digest.h"
25
27
#include " crypto/Signer.h"
26
28
#include " crypto/TS.h"
27
29
#include " crypto/X509Cert.h"
30
+ #include " util/algorithm.h"
28
31
#include " util/DateTime.h"
29
32
#include " util/File.h"
30
33
#include " util/log.h"
31
34
35
+ #include < functional>
36
+ #include < sstream>
37
+
32
38
using namespace digidoc ;
33
39
using namespace std ;
34
40
35
- constexpr std::string_view DSIG_NS { " http://www.w3.org/2000/09/xmldsig# " };
36
- constexpr XMLName DigestMethod { " DigestMethod " , DSIG_NS} ;
37
- constexpr XMLName DigestValue { " DigestValue " , DSIG_NS} ;
41
+ struct SignatureTST ::Data {
42
+ std::string name, mime, data ;
43
+ bool root = false ;
38
44
39
- SignatureTST::SignatureTST (const string &data, ASiC_S *asicSDoc)
40
- : asicSDoc(asicSDoc)
41
- , timestampToken(make_unique<TS>((const unsigned char *)data.data(), data.size()))
42
- {}
45
+ Digest digest (Digest digest = {}) const
46
+ {
47
+ digest.update ((const unsigned char *)data.data (), data.size ());
48
+ return digest;
49
+ }
50
+ };
43
51
44
- SignatureTST::SignatureTST (string current, XMLDocument &&xml, const string &data , ASiC_S *asicSDoc)
45
- : SignatureTST(data, asicSDoc)
52
+ SignatureTST::SignatureTST (bool manifest, const ZipSerialize &z , ASiC_S *asicSDoc)
53
+ : asicSDoc( asicSDoc)
46
54
{
47
- file = std::move (current);
48
- doc = std::move (xml);
55
+ auto data = z.extract <stringstream>(" META-INF/timestamp.tst" ).str ();
56
+ timestampToken = make_unique<TS>((const unsigned char *)data.data (), data.size ());
57
+ metadata.push_back ({" META-INF/timestamp.tst" , " application/vnd.etsi.timestamp-token" , std::move (data)});
58
+ if (!manifest)
59
+ return ;
60
+ XMLSchema schema (util::File::path (Conf::instance ()->xsdPath (), " en_31916201v010101.xsd" ));
61
+ function<void (const string &, string_view)> add = [this , &schema, &add, &z](const string &file, string_view mime) {
62
+ auto xml = z.extract <stringstream>(file);
63
+ XMLDocument doc = XMLDocument::openStream (xml, {" ASiCManifest" , ASiContainer::ASIC_NS});
64
+ schema.validate (doc);
65
+
66
+ for (auto ref = doc/" DataObjectReference" ; ref; ref++)
67
+ {
68
+ if (ref[" Rootfile" ] == " true" )
69
+ add (util::File::fromUriPath (ref[" URI" ]), ref[" MimeType" ]);
70
+ }
71
+
72
+ auto ref = doc/" SigReference" ;
73
+ string uri = util::File::fromUriPath (ref[" URI" ]);
74
+ string tst = z.extract <stringstream>(uri).str ();
75
+ metadata.push_back ({file, string (mime), xml.str ()});
76
+ metadata.push_back ({uri, string (ref[" MimeType" ]), std::move (tst)});
77
+ };
78
+ add (" META-INF/ASiCArchiveManifest.xml" , " text/xml" );
49
79
}
50
80
51
81
SignatureTST::SignatureTST (ASiC_S *asicSDoc, Signer *signer)
@@ -55,10 +85,25 @@ SignatureTST::SignatureTST(ASiC_S *asicSDoc, Signer *signer)
55
85
Digest digest;
56
86
dataFile->digest (digest);
57
87
timestampToken = make_unique<TS>(digest, signer->userAgent ());
88
+ vector<unsigned char > der = *timestampToken;
89
+ metadata.push_back ({" META-INF/timestamp.tst" , " application/vnd.etsi.timestamp-token" , {der.cbegin (), der.cend ()}});
58
90
}
59
91
60
92
SignatureTST::~SignatureTST () = default ;
61
93
94
+ std::vector<SignatureTST::TSAInfo> SignatureTST::ArchiveTimeStamps () const
95
+ {
96
+ std::vector<TSAInfo> result;
97
+ for (auto i = metadata.cbegin () + 1 ; i != metadata.cend (); ++i)
98
+ {
99
+ if (i->mime != " application/vnd.etsi.timestamp-token" )
100
+ continue ;
101
+ TS ts ((const unsigned char *)i->data .data (), i->data .size ());
102
+ result.push_back ({ts.cert (), util::date::to_string (ts.time ())});
103
+ }
104
+ return result;
105
+ }
106
+
62
107
X509Cert SignatureTST::TimeStampCertificate () const
63
108
{
64
109
return timestampToken->cert ();
@@ -106,28 +151,48 @@ void SignatureTST::validate() const
106
151
}
107
152
try
108
153
{
109
- timestampToken->verify (dataToSign ());
110
- if (auto digestMethod = signatureMethod ();
111
- !Exception::hasWarningIgnore (Exception::ReferenceDigestWeak) &&
154
+ auto digestMethod = signatureMethod ();
155
+ DataFile *file = asicSDoc->dataFiles ().front ();
156
+ timestampToken->verify (file->calcDigest (digestMethod));
157
+ if (!Exception::hasWarningIgnore (Exception::ReferenceDigestWeak) &&
112
158
Digest::isWeakDigest (digestMethod))
113
159
{
114
160
Exception e (EXCEPTION_PARAMS (" TimeStamp '%s' digest weak" , digestMethod.c_str ()));
115
161
e.setCode (Exception::ReferenceDigestWeak);
116
162
exception.addCause (e);
117
163
}
118
- if (doc)
164
+ vector<string> list {file->fileName ()};
165
+ for (const auto &manifest: metadata)
119
166
{
120
- DataFile *file = asicSDoc->dataFiles ().front ();
167
+ if (manifest.mime != " text/xml" )
168
+ continue ;
169
+ istringstream is (manifest.data );
170
+ XMLDocument doc = XMLDocument::openStream (is, {" ASiCManifest" , ASiContainer::ASIC_NS});
171
+ vector<string> add;
121
172
for (auto ref = doc/" DataObjectReference" ; ref; ref++)
122
173
{
123
174
string_view method = (ref/DigestMethod)[" Algorithm" ];
124
- auto uri = util::File::fromUriPath (ref[" URI" ]);
125
- vector<unsigned char > digest = file->fileName () == uri ?
126
- dynamic_cast <const DataFilePrivate*>(file)->calcDigest (string (method)) :
127
- asicSDoc->fileDigest (uri, method).result ();
175
+ const auto &uri = add.emplace_back (util::File::fromUriPath (ref[" URI" ]));
176
+ vector<unsigned char > digest;
177
+ if (file->fileName () == uri)
178
+ digest = file->calcDigest (string (method));
179
+ else
180
+ {
181
+ auto i = find_if (metadata.cbegin (), metadata.cend (), [&uri](const auto &d) { return d.name == uri; });
182
+ if (i == metadata.cend ())
183
+ THROW (" File not found '%s'." , uri.c_str ());
184
+ digest = i->digest (method).result ();
185
+ }
128
186
if (vector<unsigned char > digestValue = ref/DigestValue; digest != digestValue)
129
- THROW (" Reference %s digest does not match" , uri.c_str ());
187
+ THROW (" Reference '%s' digest does not match" , uri.c_str ());
188
+ }
189
+ // Check if all files in previous scope are present
190
+ for (const string &uri: list)
191
+ {
192
+ if (!contains (add, uri))
193
+ THROW (" Reference '%s' not found in manifest" , uri.c_str ());
130
194
}
195
+ list = std::move (add);
131
196
}
132
197
}
133
198
catch (const Exception& e)
@@ -141,8 +206,6 @@ void SignatureTST::validate() const
141
206
142
207
std::vector<unsigned char > SignatureTST::dataToSign () const
143
208
{
144
- if (!file.empty ())
145
- return asicSDoc->fileDigest (file, signatureMethod ()).result ();
146
209
return asicSDoc->dataFiles ().front ()->calcDigest (signatureMethod ());
147
210
}
148
211
@@ -162,7 +225,8 @@ string SignatureTST::profile() const
162
225
return string (ASiC_S::ASIC_TST_PROFILE);
163
226
}
164
227
165
- std::vector< unsigned char > SignatureTST::save () const
228
+ void SignatureTST::save (const ZipSerialize &z ) const
166
229
{
167
- return *timestampToken;
230
+ for (const auto &[name, mime, data, root]: metadata)
231
+ z.addFile (name, asicSDoc->zproperty (name))(data);
168
232
}
0 commit comments