Skip to content

Commit 6b8880d

Browse files
committed
Handle ASiC-S XAdES signatures
IB-7593 Signed-off-by: Raul Metsma <[email protected]>
1 parent ecdcd14 commit 6b8880d

File tree

8 files changed

+96
-169
lines changed

8 files changed

+96
-169
lines changed

src/ASiC_S.cpp

Lines changed: 44 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,12 @@
2020
#include "ASiC_S.h"
2121

2222
#include "SignatureTST.h"
23-
#include "crypto/Digest.h"
23+
#include "SignatureXAdES_LTA.h"
2424
#include "util/File.h"
2525
#include "util/log.h"
2626
#include "util/ZipSerialize.h"
2727

2828
#include <algorithm>
29-
#include <fstream>
3029
#include <sstream>
3130

3231
using namespace digidoc;
@@ -37,37 +36,58 @@ using namespace std;
3736
* Initialize ASiCS container.
3837
*/
3938
ASiC_S::ASiC_S(): ASiContainer(MIMETYPE_ASIC_S)
40-
{
41-
}
39+
{}
4240

4341
/**
4442
* Opens ASiC-S container from a file
4543
*/
4644
ASiC_S::ASiC_S(const string &path): ASiContainer(MIMETYPE_ASIC_S)
4745
{
48-
auto z = load(path, false, {MIMETYPE_ASIC_S});
49-
loadContainer(*z);
50-
}
46+
auto z = load(path, false, {mediaType()});
47+
static const string_view metaInf = "META-INF/";
5148

52-
void ASiC_S::save(const string & /*path*/)
53-
{
54-
THROW("Not implemented.");
55-
}
49+
for(const string &file: z->list())
50+
{
51+
if(file == "mimetype" ||
52+
(metaInf.size() < file.size() && file.compare(0, metaInf.size(), metaInf) == 0))
53+
{
54+
if(file == "META-INF/timestamp.tst")
55+
{
56+
if(!signatures().empty())
57+
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));
61+
}
62+
if(file == "META-INF/signatures.xml")
63+
{
64+
if(!signatures().empty())
65+
THROW("Can not add signature to ASiC-S container which already contains a signature.");
66+
stringstream data;
67+
z->extract(file, data);
68+
addSignature(make_unique<SignatureXAdES_LTA>(data, this, true));
69+
}
70+
continue;
71+
}
5672

57-
void ASiC_S::addDataFile(const string &path, const string &mediaType)
58-
{
59-
if(!dataFiles().empty())
60-
THROW("Can not add document to ASiC-S container which already contains a document.");
61-
62-
ASiContainer::addDataFile(path, mediaType);
73+
const auto directory = File::directory(file);
74+
if(directory.empty() || directory == "/" || directory == "./")
75+
{
76+
if(!dataFiles().empty())
77+
THROW("Can not add document to ASiC-S container which already contains a document.");
78+
addDataFile(dataStream(file, *z), file, "application/octet-stream");
79+
}
80+
}
81+
82+
if(dataFiles().empty())
83+
THROW("ASiC-S container does not contain any data objects.");
84+
if(signatures().empty())
85+
THROW("ASiC-S container does not contain any signatures.");
6386
}
6487

65-
void ASiC_S::addDataFile(unique_ptr<istream> is, const string &fileName, const string &mediaType)
88+
void ASiC_S::save(const string & /*path*/)
6689
{
67-
if(!dataFiles().empty())
68-
THROW("Can not add document to ASiC-S container which already contains a document.");
69-
70-
ASiContainer::addDataFile(move(is), fileName, mediaType);
90+
THROW("Not implemented.");
7191
}
7292

7393
unique_ptr<Container> ASiC_S::createInternal(const string & /*path*/)
@@ -83,57 +103,11 @@ void ASiC_S::addAdESSignature(istream & /*signature*/)
83103
unique_ptr<Container> ASiC_S::openInternal(const string &path)
84104
{
85105
if (!isContainerSimpleFormat(path))
86-
return nullptr;
106+
return {};
87107
DEBUG("ASiC_S::openInternal(%s)", path.c_str());
88108
return unique_ptr<Container>(new ASiC_S(path));
89109
}
90110

91-
void ASiC_S::extractTimestamp(const ZipSerialize &z)
92-
{
93-
addSignature(make_unique<SignatureTST>(dataStream("META-INF/timestamp.tst", z), this));
94-
}
95-
96-
/**
97-
* Load container (datafile and timestamp).
98-
*
99-
* @param z Zip stream.
100-
* @param list List of files contained in the container.
101-
* @throws IOException exception is thrown if the manifest.xml file parsing failed.
102-
* @throws ContainerException
103-
*/
104-
void ASiC_S::loadContainer(const ZipSerialize &z)
105-
{
106-
DEBUG("ASiC_S::loadFileAndTimestamp()");
107-
const string metaInf = "META-INF/";
108-
const vector<string> &list = z.list();
109-
int files = 0;
110-
111-
for(const string &file: list)
112-
{
113-
if(file == "mimetype" ||
114-
file.substr(0, metaInf.size()) == metaInf)
115-
continue;
116-
117-
const auto directory = File::directory(file);
118-
if(directory.empty() || directory == "/" || directory == "./")
119-
{
120-
if(files > 0)
121-
{
122-
THROW("ASiC-S container contains more than one data objects.");
123-
}
124-
ASiContainer::addDataFile(dataStream(file, z), file, "application/octet-stream");
125-
files++;
126-
}
127-
}
128-
129-
if(files == 0)
130-
{
131-
THROW("ASiC-S container does not contain any data objects.");
132-
}
133-
134-
extractTimestamp(z);
135-
}
136-
137111
Signature* ASiC_S::prepareSignature(Signer * /*signer*/)
138112
{
139113
THROW("Not implemented.");
@@ -144,31 +118,6 @@ Signature *ASiC_S::sign(Signer * /*signer*/)
144118
THROW("Not implemented.");
145119
}
146120

147-
148-
bool ASiC_S::isTimestampedASiC_S(const vector<string> &list)
149-
{
150-
DEBUG("isTimestampedASiC_S()");
151-
bool isASiCS = false;
152-
153-
auto dataFiles = 0;
154-
auto hasTimestamp = false;
155-
156-
// container has only one file in root folder and has a timestamp
157-
for(const string &file: list)
158-
{
159-
const auto directory = File::directory(file);
160-
if(directory.empty() || directory == "/" || directory == "./")
161-
dataFiles++;
162-
if(file == "META-INF/timestamp.tst")
163-
hasTimestamp = true;
164-
}
165-
166-
isASiCS = hasTimestamp && (dataFiles == 1);
167-
168-
DEBUG("ASiCS Container: %s", isASiCS ? "yes" : "no");
169-
return isASiCS;
170-
}
171-
172121
/**
173122
* Detect ASiC format based on file extentions, mimetype or zip contents.<br/>
174123
* Container format is simple (ASiC-S) or extended (ASiC-E).
@@ -185,26 +134,16 @@ bool ASiC_S::isContainerSimpleFormat(const string &path)
185134
return false;
186135
if(extension == ASICS_EXTENSION || extension == ASICS_EXTENSION_ABBR)
187136
return true;
188-
189137
DEBUG("Check if ASiC/zip containter");
190138
try
191139
{
192140
ZipSerialize z(path, false);
193141
vector<string> list = z.list();
194-
if(find(list.begin(), list.end(), "mimetype") != list.end())
195-
{
196-
stringstream iss;
197-
z.extract("mimetype", iss);
198-
if(readMimetype(iss) == MIMETYPE_ASIC_S)
199-
return true;
200-
}
201-
if(isTimestampedASiC_S(list))
202-
return true;
142+
return !list.empty() && list.front() == "mimetype" && readMimetype(z) == MIMETYPE_ASIC_S;
203143
}
204144
catch(const Exception &)
205145
{
206146
// Ignore the exception: not ASiC/zip document
207147
}
208-
209148
return false;
210149
}

src/ASiC_S.h

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,6 @@ namespace digidoc
3636
public:
3737
void save(const std::string &path = {}) override;
3838

39-
void addDataFile(const std::string &path, const std::string &mediaType) override;
40-
void addDataFile(std::unique_ptr<std::istream> is, const std::string &fileName, const std::string &mediaType) override;
41-
4239
void addAdESSignature(std::istream &sigdata) override;
4340
Signature* prepareSignature(Signer *signer) override;
4441
Signature* sign(Signer* signer) override;
@@ -50,11 +47,7 @@ namespace digidoc
5047
ASiC_S();
5148
ASiC_S(const std::string &path);
5249
DISABLE_COPY(ASiC_S);
53-
54-
void extractTimestamp(const ZipSerialize &z);
55-
void loadContainer(const ZipSerialize &z);
56-
50+
5751
static bool isContainerSimpleFormat(const std::string &path);
58-
static bool isTimestampedASiC_S(const std::vector<std::string> &list);
5952
};
6053
}

src/ASiContainer.cpp

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -79,29 +79,27 @@ ASiContainer::ASiContainer(const string &mimetype)
7979
unique_ptr<ZipSerialize> ASiContainer::load(const string &path, bool mimetypeRequired, const set<string> &supported)
8080
{
8181
DEBUG("ASiContainer::ASiContainer(path = '%s')", path.c_str());
82-
unique_ptr<ZipSerialize> z = make_unique<ZipSerialize>(d->path = path, false);
82+
auto z = make_unique<ZipSerialize>(d->path = path, false);
8383

8484
vector<string> list = z->list();
8585
if(list.empty())
8686
THROW("Failed to parse container");
8787

88-
for(const string &file: list)
89-
d->properties[file] = z->properties(file);
90-
91-
if(mimetypeRequired && list[0] != "mimetype")
88+
if(mimetypeRequired && list.front() != "mimetype")
9289
THROW("required mimetype not found");
9390

9491
// ETSI TS 102 918: mimetype has to be the first in the archive
9592
if(list.front() == "mimetype")
9693
{
97-
stringstream data;
98-
z->extract(list.front(), data);
99-
d->mimetype = readMimetype(data);
94+
d->mimetype = readMimetype(*z);
10095
DEBUG("mimetype = '%s'", d->mimetype.c_str());
10196
if(supported.find(d->mimetype) == supported.cend())
10297
THROW("Incorrect mimetype '%s'", d->mimetype.c_str());
10398
}
10499

100+
for(const string &file: list)
101+
d->properties[file] = z->properties(file);
102+
105103
return z;
106104
}
107105

@@ -154,7 +152,7 @@ unique_ptr<iostream> ASiContainer::dataStream(const string &path, const ZipSeria
154152
{
155153
unique_ptr<iostream> data;
156154
if(d->properties[path].size > MAX_MEM_FILE)
157-
data = make_unique<fstream>(File::encodeName(File::tempFileName()).c_str(), fstream::in|fstream::out|fstream::binary|fstream::trunc);
155+
data = make_unique<fstream>(File::encodeName(File::tempFileName()), fstream::in|fstream::out|fstream::binary|fstream::trunc);
158156
else
159157
data = make_unique<stringstream>();
160158
z.extract(path, *data);
@@ -180,28 +178,28 @@ void ASiContainer::addDataFile(const string &path, const string &mediaType)
180178

181179
ZipSerialize::Properties prop { appInfo(), File::modifiedTime(path), File::fileSize(path) };
182180
bool useTempFile = prop.size > MAX_MEM_FILE;
183-
zproperty(File::fileName(path), move(prop));
181+
zproperty(File::fileName(path), std::move(prop));
184182
unique_ptr<istream> is;
185183
if(useTempFile)
186184
{
187-
is = make_unique<ifstream>(File::encodeName(path).c_str(), ifstream::binary);
185+
is = make_unique<ifstream>(File::encodeName(path), ifstream::binary);
188186
}
189187
else
190188
{
191-
stringstream *data = new stringstream;
192-
if(ifstream file(File::encodeName(path).c_str(), ifstream::binary); file)
189+
auto data = make_unique<stringstream>();
190+
if(ifstream file{File::encodeName(path), ifstream::binary})
193191
*data << file.rdbuf();
194-
is.reset(data);
192+
is = std::move(data);
195193
}
196-
addDataFilePrivate(move(is), fileName, mediaType);
194+
addDataFilePrivate(std::move(is), fileName, mediaType);
197195
}
198196

199197
void ASiContainer::addDataFile(unique_ptr<istream> is, const string &fileName, const string &mediaType)
200198
{
201199
addDataFileChecks(fileName, mediaType);
202200
if(fileName.find_last_of("/\\") != string::npos)
203201
THROW("Document file '%s' cannot contain directory path.", fileName.c_str());
204-
addDataFilePrivate(move(is), fileName, mediaType);
202+
addDataFilePrivate(std::move(is), fileName, mediaType);
205203
}
206204

207205
void ASiContainer::addDataFileChecks(const string &fileName, const string &mediaType)
@@ -218,7 +216,7 @@ void ASiContainer::addDataFileChecks(const string &fileName, const string &media
218216

219217
void ASiContainer::addDataFilePrivate(unique_ptr<istream> is, const string &fileName, const string &mediaType)
220218
{
221-
d->documents.push_back(new DataFilePrivate(move(is), fileName, mediaType));
219+
d->documents.push_back(new DataFilePrivate(std::move(is), fileName, mediaType));
222220
}
223221

224222
/**
@@ -235,7 +233,7 @@ void ASiContainer::removeDataFile(unsigned int id)
235233
THROW("Can not remove document from container which has signatures, remove all signatures before removing document.");
236234
if(id >= d->documents.size())
237235
THROW("Incorrect document id %u, there are only %zu documents in container.", id, dataFiles().size());
238-
vector<DataFile*>::const_iterator it = (d->documents.cbegin() + id);
236+
auto it = d->documents.cbegin() + id;
239237
delete *it;
240238
d->documents.erase(it);
241239
}
@@ -256,7 +254,7 @@ void ASiContainer::removeSignature(unsigned int id)
256254
{
257255
if(id >= d->signatures.size())
258256
THROW("Incorrect signature id %u, there are only %zu signatures in container.", id, d->signatures.size());
259-
vector<Signature*>::const_iterator it = (d->signatures.cbegin() + id);
257+
auto it = d->signatures.cbegin() + id;
260258
delete *it;
261259
d->signatures.erase(it);
262260
}
@@ -280,15 +278,14 @@ string ASiContainer::zpath() const
280278

281279
ZipSerialize::Properties ASiContainer::zproperty(const string &file) const
282280
{
283-
map<string, ZipSerialize::Properties>::const_iterator i = d->properties.find(file);
284-
if(i != d->properties.cend())
281+
if(auto i = d->properties.find(file); i != d->properties.cend())
285282
return i->second;
286283
return d->properties[file] = { appInfo(), time(nullptr), 0 };
287284
}
288285

289286
void ASiContainer::zproperty(const string &file, ZipSerialize::Properties &&prop)
290287
{
291-
d->properties[file] = move(prop);
288+
d->properties[file] = std::move(prop);
292289
}
293290

294291
/**
@@ -298,9 +295,12 @@ void ASiContainer::zproperty(const string &file, ZipSerialize::Properties &&prop
298295
* @throws IOException exception is thrown if there was error reading mimetype file from disk.
299296
* @throws ContainerException exception is thrown if the parsed mimetype is incorrect.
300297
*/
301-
string ASiContainer::readMimetype(istream &is)
298+
string ASiContainer::readMimetype(const ZipSerialize &z)
302299
{
303300
DEBUG("ASiContainer::readMimetype()");
301+
stringstream is;
302+
z.extract("mimetype", is);
303+
304304
array<unsigned char,3> bom{};
305305
is.read((char*)bom.data(), bom.size());
306306
// Contains UTF-16 BOM

src/ASiContainer.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ namespace digidoc
7272
ZipSerialize::Properties zproperty(const std::string &file) const;
7373
void zproperty(const std::string &file, ZipSerialize::Properties &&prop);
7474

75-
static std::string readMimetype(std::istream &path);
76-
75+
static std::string readMimetype(const ZipSerialize &z);
76+
7777
private:
7878
DISABLE_COPY(ASiContainer);
7979

0 commit comments

Comments
 (0)