3333#include " util/log.h"
3434
3535#include < functional>
36+ #include < map>
3637#include < sstream>
3738
3839using namespace digidoc ;
3940using namespace std ;
4041
4142struct SignatureTST ::Data {
42- std::string name, mime, data;
43- bool root = false ;
43+ string name, mime, data;
44+ unique_ptr<map<string, vector<unsigned char >>> cache = make_unique<map<string, vector<unsigned char >>>();
45+
46+ Data (string _name, string _mime, string _data)
47+ : name(std::move(_name))
48+ , mime(std::move(_mime))
49+ , data(std::move(_data))
50+ {}
4451
4552 Digest digest (Digest digest = {}) const
4653 {
4754 digest.update ((const unsigned char *)data.data (), data.size ());
4855 return digest;
4956 }
57+ const vector<unsigned char >& digestCache (string method) const
58+ {
59+ if (auto it = cache->find (method); it != cache->cend ()) {
60+ return it->second ;
61+ }
62+ return (*cache)[std::move (method)] = digest ({method}).result ();
63+ }
5064};
5165
5266SignatureTST::SignatureTST (bool manifest, const ZipSerialize &z, ASiC_S *asicSDoc)
5367 : asicSDoc(asicSDoc)
5468{
5569 auto data = z.extract <stringstream>(" META-INF/timestamp.tst" ).str ();
5670 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+ if (manifest)
72+ {
73+ XMLSchema schema (util::File::path (Conf::instance ()->xsdPath (), " en_31916201v010101.xsd" ));
74+ string file = " META-INF/ASiCArchiveManifest.xml" ;
75+ string mime = " text/xml" ;
76+ while (!file.empty ()) {
77+ auto xml = z.extract <stringstream>(file);
78+ XMLDocument doc = XMLDocument::openStream (xml, {" ASiCManifest" , ASiContainer::ASIC_NS});
79+ schema.validate (doc);
80+ auto ref = doc/" SigReference" ;
81+ string uri = util::File::fromUriPath (ref[" URI" ]);
82+ string tst = z.extract <stringstream>(uri).str ();
83+ metadata.emplace_back (std::move (file), std::move (mime), xml.str ());
84+ metadata.emplace_back (std::move (uri), string (ref[" MimeType" ]), std::move (tst));
85+ file.clear ();
7186
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" );
87+ for (auto ref = doc/" DataObjectReference" ; ref; ref++)
88+ {
89+ if (ref[" Rootfile" ] == " true" )
90+ {
91+ file = util::File::fromUriPath (ref[" URI" ]);
92+ mime = ref[" MimeType" ];
93+ }
94+ }
95+ }
96+ }
97+ metadata.emplace_back (" META-INF/timestamp.tst" , " application/vnd.etsi.timestamp-token" , std::move (data));
7998}
8099
81100SignatureTST::SignatureTST (ASiC_S *asicSDoc, Signer *signer)
@@ -86,7 +105,7 @@ SignatureTST::SignatureTST(ASiC_S *asicSDoc, Signer *signer)
86105 dataFile->digest (digest);
87106 timestampToken = make_unique<TS>(digest, signer->userAgent ());
88107 vector<unsigned char > der = *timestampToken;
89- metadata.push_back ({ " META-INF/timestamp.tst" , " application/vnd.etsi.timestamp-token" , {der.cbegin (), der.cend ()} });
108+ metadata.emplace_back ( " META-INF/timestamp.tst" , " application/vnd.etsi.timestamp-token" , string {der.cbegin (), der.cend ()});
90109}
91110
92111SignatureTST::~SignatureTST () = default ;
@@ -105,10 +124,10 @@ string SignatureTST::ArchiveTimeStampTime() const
105124 return {};
106125}
107126
108- std:: vector<TSAInfo> SignatureTST::ArchiveTimeStamps () const
127+ vector<TSAInfo> SignatureTST::ArchiveTimeStamps () const
109128{
110- std:: vector<TSAInfo> result;
111- for (auto i = metadata.cbegin () + 1 ; i != metadata. cend () ; ++i)
129+ vector<TSAInfo> result;
130+ for (auto i = metadata.crbegin (), end = next (metadata. crend (), 1 ) ; i != end ; ++i)
112131 {
113132 if (i->mime != " application/vnd.etsi.timestamp-token" )
114133 continue ;
@@ -120,12 +139,14 @@ std::vector<TSAInfo> SignatureTST::ArchiveTimeStamps() const
120139
121140void SignatureTST::extendSignatureProfile (Signer *signer)
122141{
123-
124- string tstName = " META-INF/timestamp001.tst" ;
125- for (size_t i = 1 ;
126- any_of (metadata, [&tstName](const auto &f) { return f.name == tstName; });
127- tstName = Log::format (" META-INF/timestamp%03zu.tst" , ++i));
128-
142+ auto nextName = [this ](const char *pattern) {
143+ string name = Log::format (pattern, 1 );
144+ for (size_t i = 1 ;
145+ any_of (metadata, [&name](const auto &f) { return f.name == name; });
146+ name = Log::format (pattern, ++i));
147+ return name;
148+ };
149+ string tstName = nextName (" META-INF/timestamp%03zu.tst" );
129150 auto doc = XMLDocument::create (" ASiCManifest" , ASiContainer::ASIC_NS, " asic" );
130151 auto ref = doc + " SigReference" ;
131152 ref.setProperty (" MimeType" , " application/vnd.etsi.timestamp-token" );
@@ -151,26 +172,20 @@ void SignatureTST::extendSignatureProfile(Signer *signer)
151172 addRef (file->fileName (), file->mediaType (), false , digest);
152173 for (auto &data: metadata)
153174 {
154- if (data.name == " META-INF/ASiCArchiveManifest.xml" )
155- {
156- string mfsName = " META-INF/ASiCArchiveManifest001.xml" ;
157- for (size_t i = 0 ;
158- any_of (metadata, [&mfsName](const auto &f) { return f.name == mfsName; });
159- mfsName = Log::format (" META-INF/ASiCArchiveManifest%03zu.xml" , ++i));
160- data.name = mfsName;
161- data.root = true ;
162- }
163- addRef (data.name , data.mime , data.root , data.digest ());
175+ bool root = data.name == " META-INF/ASiCArchiveManifest.xml" ;
176+ if (root)
177+ data.name = nextName (" META-INF/ASiCArchiveManifest%03zu.xml" );
178+ addRef (data.name , data.mime , root, data.digest ());
164179 }
165180
166181 string data;
167182 doc.save ([&data](const char *buf, size_t size) {
168183 data.append (buf, size);
169184 return size;
170185 }, true );
171- metadata.push_back ( {" META-INF/ASiCArchiveManifest.xml" , " text/xml" , std::move (data)});
172- vector<unsigned char > der = TS (metadata. back (). digest (), signer->userAgent ());
173- metadata.push_back ( {tstName, " application/vnd.etsi.timestamp-token" , {der.cbegin (), der.cend ()}});
186+ auto i = metadata.insert (metadata. cbegin (), {" META-INF/ASiCArchiveManifest.xml" , " text/xml" , std::move (data)});
187+ vector<unsigned char > der = TS (i-> digest (), signer->userAgent ());
188+ metadata.insert ( next (i), {tstName, " application/vnd.etsi.timestamp-token" , string {der.cbegin (), der.cend ()}});
174189}
175190
176191X509Cert SignatureTST::TimeStampCertificate () const
@@ -218,8 +233,7 @@ void SignatureTST::validate() const
218233 EXCEPTION_ADD (exception, " Failed to parse timestamp token." );
219234 throw exception;
220235 }
221- DataFile *file = asicSDoc->dataFiles ().front ();
222- vector<string> list {file->fileName ()};
236+ const DataFile *file = asicSDoc->dataFiles ().front ();
223237 try
224238 {
225239 auto digestMethod = signatureMethod ();
@@ -238,26 +252,28 @@ void SignatureTST::validate() const
238252 }
239253 try
240254 {
241- for (const auto &manifest: metadata)
255+ vector<string> list {file->fileName ()};
256+ for (auto i = metadata.crbegin (); i != metadata.crend (); ++i)
242257 {
243- if (manifest. mime != " text/xml" )
258+ if (i-> mime != " text/xml" )
244259 continue ;
245- istringstream is (manifest. data );
260+ istringstream is (i-> data );
246261 XMLDocument doc = XMLDocument::openStream (is, {" ASiCManifest" , ASiContainer::ASIC_NS});
247262 vector<string> add;
263+ add.reserve (metadata.size ());
248264 for (auto ref = doc/" DataObjectReference" ; ref; ref++)
249265 {
250- string_view method = ( ref/DigestMethod)[" Algorithm" ];
266+ string method (( ref/DigestMethod)[" Algorithm" ]) ;
251267 const auto &uri = add.emplace_back (util::File::fromUriPath (ref[" URI" ]));
252268 vector<unsigned char > digest;
253269 if (file->fileName () == uri)
254- digest = file->calcDigest (string ( method) );
270+ digest = file->calcDigest (method);
255271 else
256272 {
257- auto i = find_if (metadata.cbegin (), metadata.cend (), [&uri](const auto &d) { return d.name == uri; });
258- if (i == metadata.cend ())
273+ auto j = find_if (metadata.cbegin (), metadata.cend (), [&uri](const auto &d) { return d.name == uri; });
274+ if (j == metadata.cend ())
259275 THROW (" File not found '%s'." , uri.c_str ());
260- digest = i-> digest ( method). result ( );
276+ digest = j-> digestCache ( std::move ( method));
261277 }
262278 if (vector<unsigned char > digestValue = ref/DigestValue; digest != digestValue)
263279 THROW (" Reference '%s' digest does not match" , uri.c_str ());
@@ -280,7 +296,7 @@ void SignatureTST::validate() const
280296 throw exception;
281297}
282298
283- std:: vector<unsigned char > SignatureTST::dataToSign () const
299+ vector<unsigned char > SignatureTST::dataToSign () const
284300{
285301 return asicSDoc->dataFiles ().front ()->calcDigest (signatureMethod ());
286302}
@@ -290,7 +306,7 @@ vector<unsigned char> SignatureTST::messageImprint() const
290306 return timestampToken->messageImprint ();
291307}
292308
293- void SignatureTST::setSignatureValue (const std:: vector<unsigned char > & /* signatureValue*/ )
309+ void SignatureTST::setSignatureValue (const vector<unsigned char > & /* signatureValue*/ )
294310{
295311 THROW (" Not implemented." );
296312}
@@ -303,6 +319,6 @@ string SignatureTST::profile() const
303319
304320void SignatureTST::save (const ZipSerialize &z) const
305321{
306- for (const auto &[name, mime, data, root]: metadata)
307- z.addFile (name, asicSDoc->zproperty (name))(data);
322+ for (auto i = metadata. crbegin (); i != metadata. crend (); ++i )
323+ z.addFile (i-> name , asicSDoc->zproperty (i-> name ))(i-> data );
308324}
0 commit comments