diff --git a/src/ASiC_E.cpp b/src/ASiC_E.cpp index 46a2802ea..d5fbd2835 100644 --- a/src/ASiC_E.cpp +++ b/src/ASiC_E.cpp @@ -36,16 +36,19 @@ using namespace digidoc; using namespace digidoc::util; using namespace std; -const string_view ASiC_E::ASIC_TM_PROFILE = "time-mark"; -const string_view ASiC_E::ASIC_TS_PROFILE = "time-stamp"; -const string_view ASiC_E::ASIC_TSA_PROFILE = "time-stamp-archive"; -const string_view ASiC_E::ASIC_TMA_PROFILE = "time-mark-archive"; constexpr string_view MANIFEST_NS {"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0"}; class ASiC_E::Private { public: + string unique_name() const + { + string file; + for(unsigned int i = 0; signatures.count(file = Log::format("META-INF/signatures%u.xml", i++)); ); + return file; + } vector metadata; + map signatures; }; /** @@ -58,7 +61,7 @@ ASiC_E::ASiC_E() } /** - * Opens BDOC container from a file + * Opens ASiC container from a file */ ASiC_E::ASiC_E(const string &path) : ASiContainer(MIMETYPE_ASIC_E) @@ -102,24 +105,28 @@ void ASiC_E::save(const string &path) s.addFile("mimetype", mimetype, zproperty("mimetype"), ZipSerialize::DontCompress); stringstream manifest; - createManifest(manifest); + if(!createManifest().save(manifest)) + THROW("Failed to create manifest XML"); s.addFile("META-INF/manifest.xml", manifest, zproperty("META-INF/manifest.xml")); for(const DataFile *file: dataFiles()) s.addFile(file->fileName(), *(static_cast(file)->m_is), zproperty(file->fileName())); std::set saved; - unsigned int i = 0; for(Signature *iter: signatures()) { - string file = Log::format("META-INF/signatures%u.xml", i++); - auto *signature = static_cast(iter); - if(!saved.insert(signature->signatures.get()).second) + auto *signatures = static_cast(iter)->signatures.get(); + if(!saved.insert(signatures).second) continue; + auto name = find_if(d->signatures.cbegin(), d->signatures.cend(), [signatures](const auto &k){ + return k.second == signatures; + }); + if(name == d->signatures.cend()) + THROW("Unkown signature object"); stringstream ofs; - if(!signature->signatures->save(ofs)) + if(!signatures->save(ofs)) THROW("Failed to create signature XML file."); - s.addFile(file, ofs, zproperty(file)); + s.addFile(name->first, ofs, zproperty(name->first)); } } @@ -143,12 +150,9 @@ void ASiC_E::addAdESSignature(istream &data) THROW("No documents in container, can not add signature."); if(mediaType() != MIMETYPE_ASIC_E) THROW("'%s' format is not supported", mediaType().c_str()); - try { - auto signatures = make_shared(data, this); - for(auto s = signatures->signature(); s; s++) - addSignature(make_unique(signatures, s, this)); + loadSignatures(data, d->unique_name()); } catch(const Exception &e) { @@ -165,14 +169,10 @@ unique_ptr ASiC_E::openInternal(const string &path) /** * Creates BDoc container manifest file and returns its path. * - * Note: If non-ascii characters are present in XML data, we depend on the LANG variable to be set properly - * (see iconv --list for the list of supported encoding values for libiconv). - * - * * @return returns created manifest file path. * @throws Exception exception is thrown if manifest file creation failed. */ -void ASiC_E::createManifest(ostream &os) +XMLDocument ASiC_E::createManifest() const { DEBUG("ASiC_E::createManifest()"); auto doc = XMLDocument::create("manifest", MANIFEST_NS, "manifest"); @@ -185,8 +185,15 @@ void ASiC_E::createManifest(ostream &os) add("/", mediaType()); for(const DataFile *file: dataFiles()) add(file->fileName(), file->mediaType()); - if(!doc.save(os)) - THROW("Failed to create manifest XML"); + return doc; +} + +void ASiC_E::loadSignatures(istream &data, const string &file) +{ + auto signatures = make_shared(data, mediaType()); + d->signatures.emplace(file, signatures.get()); + for(auto s = signatures->signature(); s; s++) + addSignature(make_unique(signatures, s, this)); } /** @@ -214,11 +221,11 @@ void ASiC_E::parseManifestAndLoadFiles(const ZipSerialize &z) { stringstream manifestdata; z.extract("META-INF/manifest.xml", manifestdata); + auto doc = XMLDocument::openStream(manifestdata, {"manifest", MANIFEST_NS}); + doc.validateSchema(File::path(Conf::instance()->xsdPath(), "OpenDocument_manifest_v1_2.xsd")); set manifestFiles; bool mimeFound = false; - auto doc = XMLDocument::openStream(manifestdata, {"manifest", MANIFEST_NS}); - doc.validateSchema(File::path(Conf::instance()->xsdPath(), "OpenDocument_manifest_v1_2.xsd")); for(auto file = doc/"file-entry"; file; file++) { auto full_path = file[{"full-path", MANIFEST_NS}]; @@ -272,9 +279,7 @@ void ASiC_E::parseManifestAndLoadFiles(const ZipSerialize &z) { stringstream data; z.extract(file, data); - auto signatures = make_shared(data, this); - for(auto s = signatures->signature(); s; s++) - addSignature(make_unique(signatures, s, this)); + loadSignatures(data, file); } catch(const Exception &e) { @@ -307,7 +312,9 @@ Signature* ASiC_E::prepareSignature(Signer *signer) THROW("No documents in container, can not sign container."); if(!signer) THROW("Null pointer in ASiC_E::sign"); - return addSignature(make_unique(newSignatureId(), this, signer)); + auto signatures = make_shared(); + d->signatures.emplace(d->unique_name(), signatures.get()); + return addSignature(make_unique(signatures, newSignatureId(), this, signer)); } Signature *ASiC_E::sign(Signer* signer) diff --git a/src/ASiC_E.h b/src/ASiC_E.h index 0ed9b99fe..0adaff405 100644 --- a/src/ASiC_E.h +++ b/src/ASiC_E.h @@ -23,6 +23,7 @@ namespace digidoc { + struct XMLDocument; class ZipSerialize; /** @@ -36,10 +37,10 @@ namespace digidoc class ASiC_E final : public ASiContainer { public: - static const std::string_view ASIC_TM_PROFILE; - static const std::string_view ASIC_TS_PROFILE; - static const std::string_view ASIC_TMA_PROFILE; - static const std::string_view ASIC_TSA_PROFILE; + static constexpr std::string_view ASIC_TM_PROFILE = "time-mark"; + static constexpr std::string_view ASIC_TS_PROFILE = "time-stamp"; + static constexpr std::string_view ASIC_TMA_PROFILE = "time-mark-archive"; + static constexpr std::string_view ASIC_TSA_PROFILE = "time-stamp-archive"; ~ASiC_E() final; void save(const std::string &path = {}) final; @@ -56,7 +57,8 @@ namespace digidoc ASiC_E(); ASiC_E(const std::string &path); DISABLE_COPY(ASiC_E); - void createManifest(std::ostream &os); + XMLDocument createManifest() const; + void loadSignatures(std::istream &data, const std::string &file); void parseManifestAndLoadFiles(const ZipSerialize &z); class Private; diff --git a/src/ASiC_S.cpp b/src/ASiC_S.cpp index 1dd0df8bc..044c88d62 100644 --- a/src/ASiC_S.cpp +++ b/src/ASiC_S.cpp @@ -65,7 +65,7 @@ ASiC_S::ASiC_S(const string &path): ASiContainer(MIMETYPE_ASIC_S) THROW("Can not add signature to ASiC-S container which already contains a signature."); stringstream data; z->extract(file, data); - auto signatures = make_shared(data, this); + auto signatures = make_shared(data, mediaType()); for(auto s = signatures->signature(); s; s++) addSignature(make_unique(signatures, s, this)); } diff --git a/src/SignatureXAdES_B.cpp b/src/SignatureXAdES_B.cpp index 157456074..9f487a7fe 100644 --- a/src/SignatureXAdES_B.cpp +++ b/src/SignatureXAdES_B.cpp @@ -190,7 +190,7 @@ int initXmlSecCallback() return is; }, [](void *ctx, char *buf, int len) -> int { - auto *is = static_cast(ctx); + auto *is = static_cast(ctx); is->read(buf, len); return int(is->gcount()); }, @@ -207,7 +207,7 @@ Signatures::Signatures() addNS(XADES_NS, "xades"); } -Signatures::Signatures(istream &data, ASiContainer *container) +Signatures::Signatures(istream &data, string_view mediaType) : XMLDocument(openStream(data)) { /* http://www.etsi.org/deliver/etsi_ts/102900_102999/102918/01.03.01_60/ts_102918v010301p.pdf @@ -219,7 +219,7 @@ Signatures::Signatures(istream &data, ASiContainer *container) * Case container is ADoc 1.0 then handle document-signatures root element */ try { - if(container->mediaType() == ASiC_E::MIMETYPE_ADOC && name() == "document-signatures" && ns() == OPENDOCUMENT_NS) + if(mediaType == ASiC_E::MIMETYPE_ADOC && name() == "document-signatures" && ns() == OPENDOCUMENT_NS) validateSchema(File::path(Conf::instance()->xsdPath(), "OpenDocument_dsig.xsd")); else validateSchema(File::path(Conf::instance()->xsdPath(), "en_31916201v010101.xsd")); @@ -234,8 +234,8 @@ Signatures::Signatures(istream &data, ASiContainer *container) /** * Creates an empty BDOC-BES signature with mandatory XML nodes. */ -SignatureXAdES_B::SignatureXAdES_B(unsigned int id, ASiContainer *container, Signer *signer) - : signatures(make_shared()) +SignatureXAdES_B::SignatureXAdES_B(const shared_ptr &signatures, unsigned int id, ASiContainer *container, Signer *signer) + : signatures(signatures) , bdoc(container) { X509Cert c = signer->cert(); @@ -295,7 +295,7 @@ SignatureXAdES_B::SignatureXAdES_B(unsigned int id, ASiContainer *container, Sig * @param bdoc BDOC container * @throws SignatureException */ -SignatureXAdES_B::SignatureXAdES_B(const std::shared_ptr &signatures, XMLNode s, ASiContainer *container) +SignatureXAdES_B::SignatureXAdES_B(const shared_ptr &signatures, XMLNode s, ASiContainer *container) : signatures(signatures) , signature(s) , bdoc(container) diff --git a/src/SignatureXAdES_B.h b/src/SignatureXAdES_B.h index ee84bea9e..67605d1a0 100644 --- a/src/SignatureXAdES_B.h +++ b/src/SignatureXAdES_B.h @@ -43,7 +43,7 @@ namespace digidoc { public: explicit Signatures(); - Signatures(std::istream &data, ASiContainer *container); + Signatures(std::istream &data, std::string_view mediaType); constexpr XMLNode signature() const noexcept { @@ -55,7 +55,7 @@ namespace digidoc { public: - SignatureXAdES_B(unsigned int id, ASiContainer *bdoc, Signer *signer); + SignatureXAdES_B(const std::shared_ptr &signatures, unsigned int id, ASiContainer *bdoc, Signer *signer); SignatureXAdES_B(const std::shared_ptr &signatures, XMLNode s, ASiContainer *container); ~SignatureXAdES_B(); diff --git a/src/SignatureXAdES_LT.cpp b/src/SignatureXAdES_LT.cpp index e4ad59603..a69940d67 100644 --- a/src/SignatureXAdES_LT.cpp +++ b/src/SignatureXAdES_LT.cpp @@ -35,11 +35,11 @@ using namespace digidoc; using namespace std; -SignatureXAdES_LT::SignatureXAdES_LT(unsigned int id, ASiContainer *bdoc, Signer *signer) -: SignatureXAdES_T(id, bdoc, signer) +SignatureXAdES_LT::SignatureXAdES_LT(const shared_ptr &signatures, unsigned int id, ASiContainer *bdoc, Signer *signer) +: SignatureXAdES_T(signatures, id, bdoc, signer) {} -SignatureXAdES_LT::SignatureXAdES_LT(const std::shared_ptr &signatures, XMLNode s, ASiContainer *container) +SignatureXAdES_LT::SignatureXAdES_LT(const shared_ptr &signatures, XMLNode s, ASiContainer *container) : SignatureXAdES_T(signatures, s, container) { try { diff --git a/src/SignatureXAdES_LT.h b/src/SignatureXAdES_LT.h index 1cab1a7c3..47b345061 100644 --- a/src/SignatureXAdES_LT.h +++ b/src/SignatureXAdES_LT.h @@ -29,7 +29,7 @@ class OCSP; class SignatureXAdES_LT: public SignatureXAdES_T { public: - SignatureXAdES_LT(unsigned int id, ASiContainer *bdoc, Signer *signer); + SignatureXAdES_LT(const std::shared_ptr &signatures, unsigned int id, ASiContainer *bdoc, Signer *signer); SignatureXAdES_LT(const std::shared_ptr &signatures, XMLNode s, ASiContainer *container); std::string trustedSigningTime() const override;