Skip to content

Commit fb38ed4

Browse files
authored
Check duplicate files in Zip all code paths (#626)
IB-8230 Signed-off-by: Raul Metsma <[email protected]>
1 parent db756a7 commit fb38ed4

File tree

11 files changed

+130
-182
lines changed

11 files changed

+130
-182
lines changed

src/ASiC_E.cpp

Lines changed: 10 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
#include "crypto/Digest.h"
2727
#include "crypto/Signer.h"
2828
#include "util/File.h"
29-
#include "util/ZipSerialize.h"
3029

3130
#include <algorithm>
3231
#include <set>
@@ -65,7 +64,7 @@ ASiC_E::ASiC_E(const string &path)
6564
, d(make_unique<Private>())
6665
{
6766
auto zip = load(path, true, {MIMETYPE_ASIC_E, MIMETYPE_ADOC});
68-
parseManifestAndLoadFiles(*zip);
67+
parseManifestAndLoadFiles(zip);
6968
}
7069

7170
ASiC_E::~ASiC_E()
@@ -99,7 +98,7 @@ void ASiC_E::save(const string &path)
9998

10099
stringstream mimetype;
101100
mimetype << mediaType();
102-
s.addFile("mimetype", mimetype, zproperty("mimetype"), ZipSerialize::DontCompress);
101+
s.addFile("mimetype", mimetype, zproperty("mimetype"), false);
103102

104103
stringstream manifest;
105104
createManifest(manifest);
@@ -193,32 +192,21 @@ void ASiC_E::createManifest(ostream &os)
193192
* Parses manifest file and checks that files described in manifest exist, also
194193
* checks that no extra file do exist that are not described in manifest.xml.
195194
*
196-
* Note: If non-ascii characters are present in XML data, we depend on the LANG variable to be set properly
197-
* (see iconv --list for the list of supported encoding values for libiconv).
198-
*
199195
* @param path directory on disk of the BDOC container.
200196
* @throws Exception exception is thrown if the manifest.xml file parsing failed.
201197
*/
202198
void ASiC_E::parseManifestAndLoadFiles(const ZipSerialize &z)
203199
{
204200
DEBUG("ASiC_E::readManifest()");
205201

206-
const vector<string> &list = z.list();
207-
auto mcount = size_t(count(list.cbegin(), list.cend(), "META-INF/manifest.xml"));
208-
if(mcount < 1)
209-
THROW("Manifest file is missing");
210-
if(mcount > 1)
211-
THROW("Found multiple manifest files");
212-
213202
try
214203
{
215-
stringstream manifestdata;
216-
z.extract("META-INF/manifest.xml", manifestdata);
204+
auto manifestdata = z.extract<stringstream>("META-INF/manifest.xml");
205+
auto doc = XMLDocument::openStream(manifestdata, {"manifest", MANIFEST_NS});
206+
doc.validateSchema(File::path(Conf::instance()->xsdPath(), "OpenDocument_manifest_v1_2.xsd"));
217207

218208
set<string_view> manifestFiles;
219209
bool mimeFound = false;
220-
auto doc = XMLDocument::openStream(manifestdata, {"manifest", MANIFEST_NS});
221-
doc.validateSchema(File::path(Conf::instance()->xsdPath(), "OpenDocument_manifest_v1_2.xsd"));
222210
for(auto file = doc/"file-entry"; file; file++)
223211
{
224212
auto full_path = file[{"full-path", MANIFEST_NS}];
@@ -239,24 +227,18 @@ void ASiC_E::parseManifestAndLoadFiles(const ZipSerialize &z)
239227
if(full_path.back() == '/') // Skip Directory entries
240228
continue;
241229

242-
auto fcount = size_t(count(list.cbegin(), list.cend(), full_path));
243-
if(fcount < 1)
244-
THROW("File described in manifest '%s' does not exist in container.", full_path.data());
245-
if(fcount > 1)
246-
THROW("Found multiple references of file '%s' in zip container.", full_path.data());
247-
248230
manifestFiles.insert(full_path);
249231
if(mediaType() == MIMETYPE_ADOC &&
250232
(full_path.compare(0, 9, "META-INF/") == 0 ||
251233
full_path.compare(0, 9, "metadata/") == 0))
252-
d->metadata.push_back(new DataFilePrivate(dataStream(string(full_path), z), string(full_path), string(media_type)));
234+
d->metadata.push_back(new DataFilePrivate(dataStream(full_path, z), string(full_path), string(media_type)));
253235
else
254-
addDataFilePrivate(dataStream(string(full_path), z), string(full_path), string(media_type));
236+
addDataFilePrivate(dataStream(full_path, z), string(full_path), string(media_type));
255237
}
256238
if(!mimeFound)
257239
THROW("Manifest is missing mediatype file entry.");
258240

259-
for(const string &file: list)
241+
for(const string &file: z.list())
260242
{
261243
/**
262244
* http://www.etsi.org/deliver/etsi_ts/102900_102999/102918/01.03.01_60/ts_102918v010301p.pdf
@@ -266,12 +248,9 @@ void ASiC_E::parseManifestAndLoadFiles(const ZipSerialize &z)
266248
if(file.compare(0, 9, "META-INF/") == 0 &&
267249
file.find("signatures") != string::npos)
268250
{
269-
if(count(list.begin(), list.end(), file) > 1)
270-
THROW("Multiple signature files with same name found '%s'", file.c_str());
271251
try
272252
{
273-
stringstream data;
274-
z.extract(file, data);
253+
auto data = z.extract<stringstream>(file);
275254
auto signatures = make_shared<Signatures>(data, this);
276255
for(auto s = signatures->signature(); s; s++)
277256
addSignature(make_unique<SignatureXAdES_LTA>(signatures, s, this));
@@ -285,7 +264,7 @@ void ASiC_E::parseManifestAndLoadFiles(const ZipSerialize &z)
285264

286265
if(file == "mimetype" || file.compare(0, 8,"META-INF") == 0)
287266
continue;
288-
if(manifestFiles.find(file) == manifestFiles.end())
267+
if(manifestFiles.count(file) == 0)
289268
THROW("File '%s' found in container is not described in manifest.", file.c_str());
290269
}
291270
}

src/ASiC_E.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@
2323

2424
namespace digidoc
2525
{
26-
class ZipSerialize;
27-
2826
/**
2927
* Implements the BDOC specification of the signed digital document container.
3028
* Container can contain several files and all these files can be signed using

src/ASiC_S.cpp

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
#include "SignatureXAdES_LTA.h"
2424
#include "util/File.h"
2525
#include "util/log.h"
26-
#include "util/ZipSerialize.h"
2726

2827
#include <algorithm>
2928
#include <sstream>
@@ -46,7 +45,7 @@ ASiC_S::ASiC_S(const string &path): ASiContainer(MIMETYPE_ASIC_S)
4645
auto z = load(path, false, {mediaType()});
4746
static const string_view metaInf = "META-INF/";
4847

49-
for(const string &file: z->list())
48+
for(const string &file: z.list())
5049
{
5150
if(file == "mimetype" ||
5251
(metaInf.size() < file.size() && file.compare(0, metaInf.size(), metaInf) == 0))
@@ -55,16 +54,13 @@ ASiC_S::ASiC_S(const string &path): ASiContainer(MIMETYPE_ASIC_S)
5554
{
5655
if(!signatures().empty())
5756
THROW("Can not add signature to ASiC-S container which already contains a signature.");
58-
stringstream data;
59-
z->extract(file, data);
60-
addSignature(make_unique<SignatureTST>(data, this));
57+
addSignature(make_unique<SignatureTST>(z.extract<stringstream>(file).str(), this));
6158
}
6259
if(file == "META-INF/signatures.xml")
6360
{
6461
if(!signatures().empty())
6562
THROW("Can not add signature to ASiC-S container which already contains a signature.");
66-
stringstream data;
67-
z->extract(file, data);
63+
auto data = z.extract<stringstream>(file);
6864
auto signatures = make_shared<Signatures>(data, this);
6965
for(auto s = signatures->signature(); s; s++)
7066
addSignature(make_unique<SignatureXAdES_LTA>(signatures, s, this));
@@ -77,7 +73,7 @@ ASiC_S::ASiC_S(const string &path): ASiContainer(MIMETYPE_ASIC_S)
7773
{
7874
if(!dataFiles().empty())
7975
THROW("Can not add document to ASiC-S container which already contains a document.");
80-
addDataFile(dataStream(file, *z), file, "application/octet-stream");
76+
addDataFile(dataStream(file, z), file, "application/octet-stream");
8177
}
8278
}
8379

@@ -139,7 +135,7 @@ bool ASiC_S::isContainerSimpleFormat(const string &path)
139135
{
140136
ZipSerialize z(path, false);
141137
vector<string> list = z.list();
142-
return !list.empty() && list.front() == "mimetype" && readMimetype(z) == MIMETYPE_ASIC_S;
138+
return list.front() == "mimetype" && readMimetype(z) == MIMETYPE_ASIC_S;
143139
}
144140
catch(const Exception &)
145141
{

src/ASiC_S.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@
2323

2424
namespace digidoc
2525
{
26-
class ZipSerialize;
27-
2826
/**
2927
* Implements the ASiC-S specification of the timestamped digital document container.
3028
* Container contains a single datafile object and one time assertion file.

src/ASiContainer.cpp

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class ASiContainer::Private
4242
string mimetype, path;
4343
vector<DataFile*> documents;
4444
vector<Signature*> signatures;
45-
map<string, ZipSerialize::Properties> properties;
45+
map<string, ZipSerialize::Properties, std::less<>> properties;
4646
};
4747

4848
/**
@@ -62,29 +62,26 @@ ASiContainer::ASiContainer(string_view mimetype)
6262
* @param supported supported mimetypes.
6363
* @return returns zip serializer for the container.
6464
*/
65-
unique_ptr<ZipSerialize> ASiContainer::load(const string &path, bool mimetypeRequired, const set<string_view> &supported)
65+
ZipSerialize ASiContainer::load(const string &path, bool mimetypeRequired, const set<string_view> &supported)
6666
{
6767
DEBUG("ASiContainer::ASiContainer(path = '%s')", path.c_str());
68-
auto z = make_unique<ZipSerialize>(d->path = path, false);
69-
70-
vector<string> list = z->list();
71-
if(list.empty())
72-
THROW("Failed to parse container");
68+
ZipSerialize z(d->path = path, false);
69+
vector<string> list = z.list();
7370

7471
// ETSI TS 102 918: mimetype has to be the first in the archive
7572
if(mimetypeRequired && list.front() != "mimetype")
7673
THROW("required mimetype not found");
7774

7875
if(list.front() == "mimetype")
7976
{
80-
d->mimetype = readMimetype(*z);
77+
d->mimetype = readMimetype(z);
8178
if(supported.find(d->mimetype) == supported.cend())
8279
THROW("Incorrect mimetype '%s'", d->mimetype.c_str());
8380
}
8481
DEBUG("mimetype = '%s'", d->mimetype.c_str());
8582

8683
for(const string &file: list)
87-
d->properties[file] = z->properties(file);
84+
d->properties[file] = z.properties(file);
8885

8986
return z;
9087
}
@@ -134,15 +131,11 @@ vector<Signature *> ASiContainer::signatures() const
134131
* @param z Zip container.
135132
* @return returns data as a stream.
136133
*/
137-
unique_ptr<iostream> ASiContainer::dataStream(const string &path, const ZipSerialize &z) const
134+
unique_ptr<iostream> ASiContainer::dataStream(string_view path, const ZipSerialize &z) const
138135
{
139-
unique_ptr<iostream> data;
140-
if(d->properties[path].size > MAX_MEM_FILE)
141-
data = make_unique<fstream>(File::tempFileName(), fstream::in|fstream::out|fstream::binary|fstream::trunc);
142-
else
143-
data = make_unique<stringstream>();
144-
z.extract(path, *data);
145-
return data;
136+
if(auto i = d->properties.find(path); i != d->properties.cend() && i->second.size > MAX_MEM_FILE)
137+
return make_unique<fstream>(z.extract<fstream>(path));
138+
return make_unique<stringstream>(z.extract<stringstream>(path));
146139
}
147140

148141
/**
@@ -275,9 +268,7 @@ const ZipSerialize::Properties& ASiContainer::zproperty(const string &file) cons
275268
string ASiContainer::readMimetype(const ZipSerialize &z)
276269
{
277270
DEBUG("ASiContainer::readMimetype()");
278-
stringstream is;
279-
z.extract("mimetype", is);
280-
string text = is.str();
271+
string text = z.extract<stringstream>("mimetype").str();
281272
text.erase(text.find_last_not_of(" \n\r\f\t\v") + 1);
282273
if(text.empty())
283274
THROW("Failed to read mimetype.");

src/ASiContainer.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ namespace digidoc
2828
{
2929
/**
3030
* Base class for the ASiC (Associated Signature Container) documents.
31-
* Implements the operations and data structures common for more specific ASiC
31+
* Implements the operations and data structures common for more specific ASiC
3232
* signature containers like ASiC-S and ASiC-E (e.g. Estonian BDoc).
3333
* See standards ETSI TS 102 918, ETSI TS 103 171, ETSI TS 103 174 for details.
3434
*
35-
* Contains methods for detecting the container type and manipulating the container's
35+
* Contains methods for detecting the container type and manipulating the container's
3636
* zip archive.
3737
*/
3838
class ASiContainer: public Container
@@ -60,8 +60,8 @@ namespace digidoc
6060

6161
void addDataFilePrivate(std::unique_ptr<std::istream> is, std::string fileName, std::string mediaType);
6262
Signature* addSignature(std::unique_ptr<Signature> &&signature);
63-
std::unique_ptr<std::iostream> dataStream(const std::string &path, const ZipSerialize &z) const;
64-
std::unique_ptr<ZipSerialize> load(const std::string &path, bool requireMimetype, const std::set<std::string_view> &supported);
63+
std::unique_ptr<std::iostream> dataStream(std::string_view path, const ZipSerialize &z) const;
64+
ZipSerialize load(const std::string &path, bool requireMimetype, const std::set<std::string_view> &supported);
6565
void deleteSignature(Signature* s);
6666

6767
void zpath(const std::string &file);

src/SiVaContainer.cpp

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ SiVaContainer::SiVaContainer(const string &path, ContainerOpenCB *cb, bool useHa
159159
static const string_view metaInf = "META-INF/";
160160
ZipSerialize z(path, false);
161161
vector<string> list = z.list();
162-
if(list.empty() || list.front() != "mimetype")
162+
if(list.front() != "mimetype")
163163
THROW("Missing mimetype");
164164
if(d->mediaType = ASiContainer::readMimetype(z);
165165
d->mediaType != ASiContainer::MIMETYPE_ASIC_E && d->mediaType != ASiContainer::MIMETYPE_ASIC_S)
@@ -173,13 +173,9 @@ SiVaContainer::SiVaContainer(const string &path, ContainerOpenCB *cb, bool useHa
173173
{
174174
if(file == "mimetype" || file.rfind(metaInf, 0) == 0)
175175
continue;
176-
const auto directory = File::directory(file);
177-
if(directory.empty() || directory == "/" || directory == "./")
178-
{
179-
auto data = make_unique<stringstream>();
180-
z.extract(file, *data);
181-
d->dataFiles.push_back(new DataFilePrivate(std::move(data), file, "application/octet-stream"));
182-
}
176+
if(const auto directory = File::directory(file);
177+
directory.empty() || directory == "/" || directory == "./")
178+
d->dataFiles.push_back(new DataFilePrivate(make_unique<stringstream>(z.extract<stringstream>(file)), file, "application/octet-stream"));
183179
}
184180
}
185181
else

src/SignatureTST.cpp

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,19 +29,10 @@
2929
using namespace digidoc;
3030
using namespace std;
3131

32-
SignatureTST::SignatureTST(istream &is, ASiC_S *asicSDoc): asicSDoc(asicSDoc)
33-
{
34-
is.seekg(0, istream::end);
35-
istream::pos_type pos = is.tellg();
36-
const auto size = pos < 0 ? 0 : (unsigned long)pos;
37-
is.clear();
38-
is.seekg(0, istream::beg);
39-
40-
vector<unsigned char> buf(size, 0);
41-
is.read((char*)buf.data(), streamsize(buf.size()));
42-
43-
timestampToken = make_unique<TS>(buf.data(), buf.size());
44-
}
32+
SignatureTST::SignatureTST(const string &data, ASiC_S *asicSDoc)
33+
: asicSDoc(asicSDoc)
34+
, timestampToken(make_unique<TS>((const unsigned char*)data.data(), data.size()))
35+
{}
4536

4637
SignatureTST::~SignatureTST() = default;
4738

@@ -93,8 +84,7 @@ void SignatureTST::validate() const
9384
try
9485
{
9586
const string digestMethod = timestampToken->digestMethod();
96-
const auto *dataFile = static_cast<const DataFilePrivate*>(asicSDoc->dataFiles().front());
97-
timestampToken->verify(dataFile->calcDigest(digestMethod));
87+
timestampToken->verify(asicSDoc->dataFiles().front()->calcDigest(digestMethod));
9888

9989
if(!Exception::hasWarningIgnore(Exception::ReferenceDigestWeak) &&
10090
Digest::isWeakDigest(digestMethod))

src/SignatureTST.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class TS;
3131
class SignatureTST final: public Signature
3232
{
3333
public:
34-
SignatureTST(std::istream &sigdata, ASiC_S *asicSDoc);
34+
SignatureTST(const std::string &data, ASiC_S *asicSDoc);
3535
~SignatureTST();
3636

3737
std::string trustedSigningTime() const final;

0 commit comments

Comments
 (0)