Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Validate CAdES signature in SiVa service
Browse files Browse the repository at this point in the history
IB-6671

Signed-off-by: Raul Metsma <raul@metsma.ee>
metsma committed Sep 4, 2023
1 parent c9d4ca7 commit ba11081
Showing 4 changed files with 69 additions and 42 deletions.
47 changes: 21 additions & 26 deletions src/ASiContainer.cpp
Original file line number Diff line number Diff line change
@@ -154,7 +154,7 @@ unique_ptr<iostream> ASiContainer::dataStream(const string &path, const ZipSeria
{
unique_ptr<iostream> data;
if(d->properties[path].size > MAX_MEM_FILE)
data = make_unique<fstream>(File::encodeName(File::tempFileName()).c_str(), fstream::in|fstream::out|fstream::binary|fstream::trunc);
data = make_unique<fstream>(File::encodeName(File::tempFileName()), fstream::in|fstream::out|fstream::binary|fstream::trunc);
else
data = make_unique<stringstream>();
z.extract(path, *data);
@@ -180,28 +180,28 @@ void ASiContainer::addDataFile(const string &path, const string &mediaType)

ZipSerialize::Properties prop { appInfo(), File::modifiedTime(path), File::fileSize(path) };
bool useTempFile = prop.size > MAX_MEM_FILE;
zproperty(File::fileName(path), move(prop));
zproperty(File::fileName(path), std::move(prop));
unique_ptr<istream> is;
if(useTempFile)
{
is = make_unique<ifstream>(File::encodeName(path).c_str(), ifstream::binary);
is = make_unique<ifstream>(File::encodeName(path), ifstream::binary);
}
else
{
stringstream *data = new stringstream;
if(ifstream file(File::encodeName(path).c_str(), ifstream::binary); file)
unique_ptr<stringstream> data = make_unique<stringstream>();
if(ifstream file(File::encodeName(path), ifstream::binary); file)
*data << file.rdbuf();
is.reset(data);
is = std::move(data);
}
addDataFilePrivate(move(is), fileName, mediaType);
addDataFilePrivate(std::move(is), fileName, mediaType);
}

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

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

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

/**
@@ -235,7 +235,7 @@ void ASiContainer::removeDataFile(unsigned int id)
THROW("Can not remove document from container which has signatures, remove all signatures before removing document.");
if(id >= d->documents.size())
THROW("Incorrect document id %u, there are only %zu documents in container.", id, dataFiles().size());
vector<DataFile*>::const_iterator it = (d->documents.cbegin() + id);
auto it = d->documents.cbegin() + id;
delete *it;
d->documents.erase(it);
}
@@ -256,7 +256,7 @@ void ASiContainer::removeSignature(unsigned int id)
{
if(id >= d->signatures.size())
THROW("Incorrect signature id %u, there are only %zu signatures in container.", id, d->signatures.size());
vector<Signature*>::const_iterator it = (d->signatures.cbegin() + id);
auto it = d->signatures.cbegin() + id;
delete *it;
d->signatures.erase(it);
}
@@ -280,15 +280,14 @@ string ASiContainer::zpath() const

ZipSerialize::Properties ASiContainer::zproperty(const string &file) const
{
map<string, ZipSerialize::Properties>::const_iterator i = d->properties.find(file);
if(i != d->properties.cend())
if(auto i = d->properties.find(file); i != d->properties.cend())
return i->second;
return d->properties[file] = { appInfo(), time(nullptr), 0 };
}

void ASiContainer::zproperty(const string &file, ZipSerialize::Properties &&prop)
{
d->properties[file] = move(prop);
d->properties[file] = std::move(prop);
}

/**
@@ -301,20 +300,16 @@ void ASiContainer::zproperty(const string &file, ZipSerialize::Properties &&prop
string ASiContainer::readMimetype(istream &is)
{
DEBUG("ASiContainer::readMimetype()");
array<unsigned char,3> bom{};
is.read((char*)bom.data(), bom.size());
// Contains UTF-16 BOM
if((bom[0] == 0xFF && bom[1] == 0xEF) ||
(bom[0] == 0xEF && bom[1] == 0xFF))
THROW("Mimetype file must be UTF-8 format.");
// does not contain UTF-8 BOM reset pos
if(bom[0] != 0xEF || bom[1] != 0xBB || bom[2] != 0xBF)
is.seekg(0, ios::beg);

string text;
is >> text;
if(is.fail())
if(!is)
THROW("Failed to read mimetype.");

// Contains UTF-16 BOM
if((text[0] == char(0xFF) && text[1] == char(0xEF)) ||
(text[0] == char(0xEF) && text[1] == char(0xFF)))
THROW("Mimetype file must be UTF-8 format.");
// does not contain UTF-8 BOM reset pos
if(text[0] != char(0xEF) || text[1] != char(0xBB) || text[2] != char(0xBF))
text.erase(text.cbegin(), text.cbegin() + 3);
return text;
}
4 changes: 2 additions & 2 deletions src/ASiContainer.h
Original file line number Diff line number Diff line change
@@ -58,6 +58,8 @@ namespace digidoc
void removeSignature(unsigned int id) override;
std::vector<Signature*> signatures() const override;

static std::string readMimetype(std::istream &is);

protected:
ASiContainer(const std::string &mimetype);

@@ -72,8 +74,6 @@ namespace digidoc
ZipSerialize::Properties zproperty(const std::string &file) const;
void zproperty(const std::string &file, ZipSerialize::Properties &&prop);

static std::string readMimetype(std::istream &path);

private:
DISABLE_COPY(ASiContainer);

58 changes: 45 additions & 13 deletions src/SiVaContainer.cpp
Original file line number Diff line number Diff line change
@@ -24,13 +24,15 @@

#include "SiVaContainer.h"

#include "ASiContainer.h"
#include "Conf.h"
#include "DataFile_p.h"
#include "Signature.h"
#include "crypto/Connect.h"
#include "crypto/Digest.h"
#include "util/File.h"
#include "util/log.h"
#include "util/ZipSerialize.h"
#include "xml/xml.hxx"
#include "xml/SecureDOMParser.h"

@@ -142,27 +144,59 @@ void SignatureSiVa::validate(const string &policy) const
}


SiVaContainer::SiVaContainer(const string &path, const string &ext, bool useHashCode)
SiVaContainer::SiVaContainer(const string &path, bool useHashCode)
: d(make_unique<Private>())
{
string ext = File::fileExtension(path);
DEBUG("SiVaContainer::SiVaContainer(%s, %s, %d)", path.c_str(), ext.c_str(), useHashCode);
unique_ptr<istream> ifs = make_unique<ifstream>(File::encodeName(d->path = path), ifstream::binary);
auto fileName = File::fileName(path);
istream *is = ifs.get();
static const array asic {"asice", "sce", "asics", "scs"};
if(ext == "ddoc")
{
d->mediaType = "application/x-ddoc";
d->ddoc = move(ifs);
d->ddoc = std::move(ifs);
ifs = parseDDoc(useHashCode);
is = ifs.get();
}
else
else if(ext == "pdf")
{
d->mediaType = "application/pdf";
d->dataFiles.push_back(new DataFilePrivate(move(ifs), fileName, "application/pdf"));
d->dataFiles.push_back(new DataFilePrivate(std::move(ifs), fileName, "application/pdf"));
}
else if(find(asic.cbegin(), asic.cend(), ext) != asic.cend())
{
ZipSerialize z(path, false);
vector<string> list = z.list();
if(list.empty() || list.front() != "mimetype")
THROW("Missing mimetype");
stringstream data;
z.extract(list.front(), data);
if(d->mediaType = ASiContainer::readMimetype(data);
d->mediaType != ASiContainer::MIMETYPE_ASIC_E && d->mediaType != ASiContainer::MIMETYPE_ASIC_S)
THROW("Unknown file");
if(none_of(list.cbegin(), list.cend(), [](const string &file) { return file.find("p7s") != string::npos; }))
THROW("Unknown file");

static const string metaInf = "META-INF/";
for(const string &file: list)
{
if(file == "mimetype" || file.substr(0, metaInf.size()) == metaInf)
continue;
const auto directory = File::directory(file);
if(directory.empty() || directory == "/" || directory == "./")
{
auto data = make_unique<stringstream>();
z.extract(file, *data);
d->dataFiles.push_back(new DataFilePrivate(std::move(data), file, "application/octet-stream"));
}
}
}
else
THROW("Unknown file");

array<XMLByte, 48*100> buf{};
array<XMLByte, 4800> buf{};
string b64;
is->clear();
is->seekg(0);
@@ -182,7 +216,7 @@ SiVaContainer::SiVaContainer(const string &path, const string &ext, bool useHash

string req = json({
{"filename", fileName},
{"document", move(b64)},
{"document", std::move(b64)},
{"signaturePolicy", "POLv4"}
}).dump();
Connect::Result r = Connect(CONF(verifyServiceUri), "POST", 0, CONF(verifyServiceCerts)).exec({
@@ -314,15 +348,13 @@ vector<DataFile *> SiVaContainer::dataFiles() const

unique_ptr<Container> SiVaContainer::openInternal(const string &path)
{
static const array supported {"pdf", "ddoc"};
string ext = File::fileExtension(path);
if(find(supported.cbegin(), supported.cend(), ext) == supported.cend())
return {};
try {
return unique_ptr<Container>(new SiVaContainer(path, ext, true));
return unique_ptr<Container>(new SiVaContainer(path, true));
} catch(const Exception &e) {
if(e.msg().find("Bad digest for DataFile") == 0)
return unique_ptr<Container>(new SiVaContainer(path, ext, false));
return unique_ptr<Container>(new SiVaContainer(path, false));
if(e.msg() == "Unknown file")
return {};
throw;
}
}
@@ -337,7 +369,7 @@ unique_ptr<istream> SiVaContainer::parseDDoc(bool useHashCode)
DOMNodeList *nodeList = dom->getElementsByTagName(cpXMLCh(u"DataFile"));
for(XMLSize_t i = 0; i < nodeList->getLength(); ++i)
{
DOMElement *item = static_cast<DOMElement*>(nodeList->item(i));
auto *item = static_cast<DOMElement*>(nodeList->item(i));
if(!item)
continue;

2 changes: 1 addition & 1 deletion src/SiVaContainer.h
Original file line number Diff line number Diff line change
@@ -102,7 +102,7 @@ class SiVaContainer final: public Container
static std::unique_ptr<Container> openInternal(const std::string &path);

private:
SiVaContainer(const std::string &path, const std::string &ext, bool useHashCode);
SiVaContainer(const std::string &path, bool useHashCode);
DISABLE_COPY(SiVaContainer);

std::unique_ptr<std::istream> parseDDoc(bool useHashCode);

0 comments on commit ba11081

Please sign in to comment.