Skip to content

Commit

Permalink
Validate ASiC-S manifest containers
Browse files Browse the repository at this point in the history
IB-8180

Signed-off-by: Raul Metsma <[email protected]>
  • Loading branch information
metsma committed Nov 28, 2024
1 parent 172a14d commit e18d0c4
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 5 deletions.
51 changes: 47 additions & 4 deletions src/ASiC_S.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

#include "ASiC_S.h"

#include "Conf.h"
#include "SignatureTST.h"
#include "SignatureXAdES_LTA.h"
#include "crypto/Signer.h"
Expand All @@ -32,6 +33,18 @@ using namespace digidoc;
using namespace digidoc::util;
using namespace std;

struct ASiC_S::Data {
std::string name, mime, data;

Digest digest(Digest digest = {}) const
{
digest.update((const unsigned char*)data.data(), data.size());
return digest;
}
};



/**
* Initialize ASiCS container.
*/
Expand All @@ -54,7 +67,9 @@ ASiC_S::ASiC_S(const string &path)
{
if(!signatures().empty())
THROW("Can not add signature to ASiC-S container which already contains a signature.");
addSignature(make_unique<SignatureTST>(z.extract<stringstream>(file).str(), this));
string tst = z.extract<stringstream>(file).str();
addSignature(make_unique<SignatureTST>(tst, this));
metadata.push_back({file, "application/vnd.etsi.timestamp-token", std::move(tst)});
}
else if(file == "META-INF/signatures.xml")
{
Expand All @@ -66,7 +81,27 @@ ASiC_S::ASiC_S(const string &path)
addSignature(make_unique<SignatureXAdES_LTA>(signatures, s, this));
}
else if(file == "META-INF/ASiCArchiveManifest.xml")
THROW("ASiCArchiveManifest are not supported.");
{
function<void(const string &, string_view)> add = [this, &add, &z](const string &file, string_view mime) {
auto xml = z.extract<stringstream>(file);
XMLDocument doc = XMLDocument::openStream(xml, {"ASiCManifest", ASIC_NS});
doc.validateSchema(util::File::path(Conf::instance()->xsdPath(), "en_31916201v010101.xsd"));

for(auto ref = doc/"DataObjectReference"; ref; ref++)
{
if(ref["Rootfile"] == "true")
add(util::File::fromUriPath(ref["URI"]), ref["MimeType"]);
}

auto ref = doc/"SigReference";
string uri = util::File::fromUriPath(ref["URI"]);
string tst = z.extract<stringstream>(uri).str();
addSignature(make_unique<SignatureTST>(file, ::move(doc), tst, this));
metadata.push_back({file, string(mime), xml.str()});
metadata.push_back({uri, string(ref["MimeType"]), std::move(tst)});
};
add(file, "text/xml");
}
else if(starts_with(file, "META-INF/"))
continue;
else if(const auto directory = File::directory(file);
Expand Down Expand Up @@ -112,6 +147,14 @@ void ASiC_S::canSave()
THROW("ASiC-S container supports only saving TimeStampToken signatures.");
}

Digest ASiC_S::fileDigest(const string &file, string_view method) const
{
if(auto i = find_if(metadata.cbegin(), metadata.cend(), [&file](const auto &d) { return d.name == file; });
i != metadata.cend())
return i->digest(method);
THROW("File not found %s.", file.c_str());
}

unique_ptr<Container> ASiC_S::openInternal(const string &path, ContainerOpenCB * /*cb*/)
{
if (!isContainerSimpleFormat(path))
Expand All @@ -129,8 +172,8 @@ void ASiC_S::save(const ZipSerialize &s)
{
if(zproperty("META-INF/manifest.xml").size && !createManifest().save(s.addFile("META-INF/manifest.xml", zproperty("META-INF/manifest.xml")), true))
THROW("Failed to create manifest XML");
if(auto list = signatures(); !list.empty())
s.addFile("META-INF/timestamp.tst", zproperty("META-INF/timestamp.tst"))(static_cast<SignatureTST*>(list.front())->save());
for(const auto &[name, mime, data]: metadata)
s.addFile(name, zproperty(name))(data);
}

Signature *ASiC_S::sign(Signer *signer)
Expand Down
7 changes: 7 additions & 0 deletions src/ASiC_S.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@

namespace digidoc
{
class Digest;

/**
* Implements the ASiC-S specification of the timestamped digital document container.
* Container contains a single datafile object and one time assertion file.
Expand All @@ -37,6 +39,8 @@ namespace digidoc
Signature* prepareSignature(Signer *signer) override;
Signature* sign(Signer* signer) override;

Digest fileDigest(const std::string &file, std::string_view method = {}) const;

static std::unique_ptr<Container> createInternal(const std::string &path);
static std::unique_ptr<Container> openInternal(const std::string &path, ContainerOpenCB *cb);

Expand All @@ -50,5 +54,8 @@ namespace digidoc
void save(const ZipSerialize &s) final;

static bool isContainerSimpleFormat(const std::string &path);

struct Data;
std::vector<Data> metadata;
};
}
29 changes: 29 additions & 0 deletions src/SignatureTST.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,29 @@
#include "crypto/TS.h"
#include "crypto/X509Cert.h"
#include "util/DateTime.h"
#include "util/File.h"
#include "util/log.h"

using namespace digidoc;
using namespace std;

constexpr std::string_view DSIG_NS {"http://www.w3.org/2000/09/xmldsig#"};
constexpr XMLName DigestMethod {"DigestMethod", DSIG_NS};
constexpr XMLName DigestValue {"DigestValue", DSIG_NS};

SignatureTST::SignatureTST(const string &data, ASiC_S *asicSDoc)
: asicSDoc(asicSDoc)
, timestampToken(make_unique<TS>((const unsigned char*)data.data(), data.size()))
{}


SignatureTST::SignatureTST(string current, XMLDocument &&xml, const string &data, ASiC_S *asicSDoc)
: SignatureTST(data, asicSDoc)
{
file = std::move(current);
doc = std::move(xml);
}

SignatureTST::SignatureTST(ASiC_S *asicSDoc)
: asicSDoc(asicSDoc)
{
Expand Down Expand Up @@ -101,6 +114,20 @@ void SignatureTST::validate() const
e.setCode(Exception::ReferenceDigestWeak);
exception.addCause(e);
}
if(doc)
{
DataFile *file = asicSDoc->dataFiles().front();
for(auto ref = doc/"DataObjectReference"; ref; ref++)
{
string_view method = (ref/DigestMethod)["Algorithm"];
auto uri = util::File::fromUriPath(ref["URI"]);
vector<unsigned char> digest = file->fileName() == uri ?
dynamic_cast<const DataFilePrivate*>(file)->calcDigest(string(method)) :
asicSDoc->fileDigest(uri, method).result();
if(vector<unsigned char> digestValue = ref/DigestValue; digest != digestValue)
THROW("Reference %s digest does not match", uri.c_str());
}
}
}
catch (const Exception& e)
{
Expand All @@ -113,6 +140,8 @@ void SignatureTST::validate() const

std::vector<unsigned char> SignatureTST::dataToSign() const
{
if(!file.empty())
return asicSDoc->fileDigest(file, signatureMethod()).result();
return asicSDoc->dataFiles().front()->calcDigest(signatureMethod());
}

Expand Down
5 changes: 4 additions & 1 deletion src/SignatureTST.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

#include "Signature.h"

#include <memory>
#include "XMLDocument.h"

namespace digidoc
{
Expand All @@ -32,6 +32,7 @@ class SignatureTST final: public Signature
{
public:
SignatureTST(const std::string &data, ASiC_S *asicSDoc);
SignatureTST(std::string current, XMLDocument &&xml, const std::string &data, ASiC_S *asicSDoc);
SignatureTST(ASiC_S *asicSDoc);
~SignatureTST();

Expand All @@ -58,6 +59,8 @@ class SignatureTST final: public Signature
private:
DISABLE_COPY(SignatureTST);
ASiC_S *asicSDoc {};
std::string file;
XMLDocument doc;
std::unique_ptr<TS> timestampToken;
};

Expand Down

0 comments on commit e18d0c4

Please sign in to comment.