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 20, 2023
1 parent 95c7c68 commit 59fd686
Showing 4 changed files with 51 additions and 26 deletions.
21 changes: 8 additions & 13 deletions src/ASiContainer.cpp
Original file line number Diff line number Diff line change
@@ -300,21 +300,16 @@ string ASiContainer::readMimetype(const ZipSerialize &z)
DEBUG("ASiContainer::readMimetype()");
stringstream is;
z.extract("mimetype", is);

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.");
// contains UTF-8 BOM, remove
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(const ZipSerialize &z);

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(const ZipSerialize &z);

private:
DISABLE_COPY(ASiContainer);

50 changes: 40 additions & 10 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,57 @@ 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);
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"));
}
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");
if(d->mediaType = ASiContainer::readMimetype(z);
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);
@@ -314,15 +346,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 +367,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 59fd686

Please sign in to comment.