From 104b0886064177f23558c935bc30c87afca78e85 Mon Sep 17 00:00:00 2001 From: Raul Metsma Date: Fri, 7 Jul 2023 09:33:36 +0300 Subject: [PATCH] Support multiple signatures in single XML IB-7602 Signed-off-by: Raul Metsma --- src/ASiC_E.cpp | 15 +- src/ASiC_E.h | 2 +- src/ASiC_S.cpp | 4 +- src/SiVaContainer.cpp | 8 +- src/SignatureXAdES_B.cpp | 284 +++++++++++++++++++----------------- src/SignatureXAdES_B.h | 49 +++++-- src/SignatureXAdES_LT.cpp | 10 +- src/SignatureXAdES_LT.h | 2 +- src/SignatureXAdES_LTA.cpp | 17 +-- src/SignatureXAdES_T.cpp | 10 +- src/util/File.cpp | 7 +- src/util/File.h | 2 +- src/xml/SecureDOMParser.cpp | 8 +- src/xml/SecureDOMParser.h | 3 +- 14 files changed, 230 insertions(+), 191 deletions(-) diff --git a/src/ASiC_E.cpp b/src/ASiC_E.cpp index 0ad265482..296b65c04 100644 --- a/src/ASiC_E.cpp +++ b/src/ASiC_E.cpp @@ -33,7 +33,6 @@ #include -#include #include using namespace digidoc; @@ -119,7 +118,7 @@ void ASiC_E::save(const string &path) SignatureXAdES_B *signature = static_cast(iter); stringstream ofs; - signature->saveToXml(ofs); + signature->signatures->save(ofs); s.addFile(file, ofs, zproperty(file)); } } @@ -138,7 +137,7 @@ unique_ptr ASiC_E::createInternal(const string &path) * @param sigdata signature, which is added to the container. * @throws Exception throws exception if there are no documents in container. */ -void ASiC_E::addAdESSignature(istream &sigdata) +void ASiC_E::addAdESSignature(istream &data) { if(dataFiles().empty()) THROW("No documents in container, can not add signature."); @@ -147,7 +146,9 @@ void ASiC_E::addAdESSignature(istream &sigdata) try { - addSignature(make_unique(sigdata, this)); + auto signatures = make_shared(data, this); + for(size_t i = 0, count = signatures->count(); i < count; ++i) + addSignature(make_unique(signatures, i, this)); } catch(const Exception &e) { @@ -287,7 +288,9 @@ void ASiC_E::parseManifestAndLoadFiles(const ZipSerialize &z) { stringstream data; z.extract(file, data); - addSignature(make_unique(data, this, true)); + auto signatures = make_shared(data, this); + for(size_t i = 0, count = signatures->count(); i < count; ++i) + addSignature(make_unique(signatures, i, this)); } catch(const Exception &e) { @@ -354,7 +357,7 @@ Signature* ASiC_E::prepareSignature(Signer *signer) Signature *ASiC_E::sign(Signer* signer) { - SignatureXAdES_LTA *s = static_cast(prepareSignature(signer)); + auto *s = static_cast(prepareSignature(signer)); try { s->setSignatureValue(signer->sign(s->signatureMethod(), s->dataToSign())); diff --git a/src/ASiC_E.h b/src/ASiC_E.h index f268c21e8..d54ab69ba 100644 --- a/src/ASiC_E.h +++ b/src/ASiC_E.h @@ -46,7 +46,7 @@ namespace digidoc void save(const std::string &path = {}) final; std::vector metaFiles() const; - void addAdESSignature(std::istream &sigdata) final; + void addAdESSignature(std::istream &data) final; Signature* prepareSignature(Signer *signer) final; Signature* sign(Signer* signer) final; diff --git a/src/ASiC_S.cpp b/src/ASiC_S.cpp index e49c4678e..f7c7e6fec 100644 --- a/src/ASiC_S.cpp +++ b/src/ASiC_S.cpp @@ -65,7 +65,9 @@ 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); - addSignature(make_unique(data, this, true)); + auto signatures = make_shared(data, this); + for(size_t i = 0, count = signatures->count(); i < count; ++i) + addSignature(make_unique(signatures, i, this)); } continue; } diff --git a/src/SiVaContainer.cpp b/src/SiVaContainer.cpp index 4f1676e00..49420c3ff 100644 --- a/src/SiVaContainer.cpp +++ b/src/SiVaContainer.cpp @@ -152,14 +152,14 @@ SiVaContainer::SiVaContainer(const string &path, const string &ext, bool useHash if(ext == "ddoc") { d->mediaType = "application/x-ddoc"; - d->ddoc = move(ifs); + d->ddoc = std::move(ifs); ifs = parseDDoc(useHashCode); is = ifs.get(); } else { 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")); } array buf{}; @@ -182,7 +182,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({ @@ -357,7 +357,7 @@ unique_ptr SiVaContainer::parseDDoc(bool useHashCode) if(!useHashCode) continue; Digest calc(URI_SHA1); - SecureDOMParser::calcDigestOnNode(&calc, "http://www.w3.org/TR/2001/REC-xml-c14n-20010315", dom.get(), item); + SecureDOMParser::calcDigestOnNode(&calc, "http://www.w3.org/TR/2001/REC-xml-c14n-20010315", item); vector digest = calc.result(); XMLSize_t size = 0; if(XMLByte *out = Base64::encode(digest.data(), XMLSize_t(digest.size()), &size)) diff --git a/src/SignatureXAdES_B.cpp b/src/SignatureXAdES_B.cpp index fdf5b0fb8..2d6c44ffa 100644 --- a/src/SignatureXAdES_B.cpp +++ b/src/SignatureXAdES_B.cpp @@ -57,10 +57,10 @@ using namespace xercesc; using namespace xml_schema; namespace xml = xsd::cxx::xml; -const string SignatureXAdES_B::XADES_NAMESPACE = "http://uri.etsi.org/01903/v1.3.2#"; -const string SignatureXAdES_B::XADESv141_NAMESPACE = "http://uri.etsi.org/01903/v1.4.1#"; -const string SignatureXAdES_B::ASIC_NAMESPACE = "http://uri.etsi.org/02918/v1.2.1#"; -const string SignatureXAdES_B::OPENDOCUMENT_NAMESPACE = "urn:oasis:names:tc:opendocument:xmlns:digitalsignature:1.0"; +const string Signatures::XADES_NAMESPACE = "http://uri.etsi.org/01903/v1.3.2#"; +const string Signatures::XADESv141_NAMESPACE = "http://uri.etsi.org/01903/v1.4.1#"; +const string Signatures::ASIC_NAMESPACE = "http://uri.etsi.org/02918/v1.2.1#"; +const string Signatures::OPENDOCUMENT_NAMESPACE = "urn:oasis:names:tc:opendocument:xmlns:digitalsignature:1.0"; const map SignatureXAdES_B::policylist = { {"urn:oid:1.3.6.1.4.1.10015.1000.3.2.1",{ // https://www.sk.ee/repository/bdoc-spec21.pdf // SHA-1 @@ -114,11 +114,132 @@ static Base64Binary toBase64(const vector &v) } +Signatures::Signatures() + : asicsignature(make_unique()) +{} + + +Signatures::Signatures(istream &data, ASiContainer *container) +{ + Properties properties; + const auto xsdPath = Conf::instance()->xsdPath(); + properties.schema_location(XADES_NAMESPACE, File::fullPathUrl(xsdPath + "/XAdES01903v132-201601-relaxed.xsd")); + properties.schema_location(XADESv141_NAMESPACE, File::fullPathUrl(xsdPath + "/XAdES01903v141-201601.xsd")); + properties.schema_location(URI_ID_DSIG, File::fullPathUrl(xsdPath + "/xmldsig-core-schema.xsd")); + properties.schema_location(ASIC_NAMESPACE, File::fullPathUrl(xsdPath + "/en_31916201v010101.xsd")); + properties.schema_location(OPENDOCUMENT_NAMESPACE, File::fullPathUrl(xsdPath + "/OpenDocument_dsig.xsd")); + parseDOM(data, properties.schema_location()); + + try + { + /* http://www.etsi.org/deliver/etsi_ts/102900_102999/102918/01.03.01_60/ts_102918v010301p.pdf + * 6.2.2 + * 3) The root element of each "*signatures*.xml" content shall be either: + * a) as specified in clause A.5, the recommended format; or + * b) as specified in OASIS Open Document Format [9]; or + * + * Case container is ADoc 1.0 then handle document-signatures root element + */ + if(container->mediaType() == ASiC_E::MIMETYPE_ADOC) + { + odfsignature = document_signatures(*doc, Flags::dont_initialize, properties); + if(odfsignature->signature().empty()) + THROW("Failed to parse signature XML"); + } + else + { + asicsignature = xAdESSignatures(*doc, Flags::dont_initialize, properties); + if(asicsignature->signature().empty()) + THROW("Failed to parse signature XML"); + } + // For calcDigestOnNode + data.clear(); + data.seekg(0); + parseDOM(data); + } + catch(const Parsing& e) + { + stringstream s; + s << e; + THROW("Failed to parse signature XML: %s", s.str().c_str()); + } + catch(const xsd::cxx::exception& e) + { + THROW("Failed to parse signature XML: %s", e.what()); + } +} + +Signatures::~Signatures() = default; + +size_t Signatures::count() const +{ + if(odfsignature) + return odfsignature->signature().size(); + return asicsignature->signature().size(); +} + +xercesc::DOMElement* Signatures::element(string_view id) const +{ + DOMNodeList *nodeList = doc->getElementsByTagNameNS(xml::string(URI_ID_DSIG).c_str(), u"Signature"); + for(XMLSize_t i = 0, count = nodeList->getLength(); i < count; ++i) + { + auto *elem = dynamic_cast(nodeList->item(i)); + if(id == xml::transcode(elem->getAttribute(u"Id"))) + return elem; + } + return {}; +} + +void Signatures::parseDOM(istream &data, const std::string &schema_location) +{ + doc = SecureDOMParser(schema_location).parseIStream(data); +} + +void Signatures::reloadDOM() +{ + // Parse Xerces DOM from file, to preserve the white spaces "as is" + // and get the same digest value on XML node. + // Canonical XML 1.0 specification (http://www.w3.org/TR/2001/REC-xml-c14n-20010315) + // needs all the white spaces from XML file "as is", otherwise the digests won't match. + // Therefore we have to use Xerces to parse the XML file each time a digest needs to be + // calculated on a XML node. If you are parsing XML files with a parser that doesn't + // preserve the white spaces you are DOOMED! + // Parse and return a copy of the Xerces DOM tree. + // Save to file an parse it again, to make XML Canonicalization work + // correctly as expected by the Canonical XML 1.0 specification. + // Hope, the next Canonical XMl specification fixes the white spaces preserving "bug". + stringstream ofs; + save(ofs); + parseDOM(ofs); +} + +void Signatures::save(ostream &os) const +{ + try + { + static const NamespaceInfomap map = [] { + NamespaceInfomap map; + map["ds"].name = URI_ID_DSIG; + map["xades"].name = XADES_NAMESPACE; + map["asic"].name = ASIC_NAMESPACE; + return map; + }(); + xAdESSignatures(os, *asicsignature, map, "UTF-8", Flags::dont_initialize); + } + catch(const xml::invalid_utf8_string &) + { + THROW("Failed to create signature XML file. Parameters must be in UTF-8."); + } + if(os.fail()) + THROW("Failed to create signature XML file."); +} + /** * Creates an empty BDOC-BES signature with mandatory XML nodes. */ -SignatureXAdES_B::SignatureXAdES_B(unsigned int id, ASiContainer *bdoc, Signer *signer) - : bdoc(bdoc) +SignatureXAdES_B::SignatureXAdES_B(unsigned int id, ASiContainer *container, Signer *signer) + : signatures(make_shared()) + , bdoc(container) { X509Cert c = signer->cert(); string nr = "S" + to_string(id); @@ -134,9 +255,8 @@ SignatureXAdES_B::SignatureXAdES_B(unsigned int id, ASiContainer *bdoc, Signer * signatureValue->id(nr + "-SIG"); // Signature (root) - asicsignature = make_unique(); - asicsignature->signature().push_back(make_unique(std::move(signedInfo), std::move(signatureValue))); - signature = &asicsignature->signature().front(); + signatures->asicsignature->signature().push_back(make_unique(std::move(signedInfo), std::move(signatureValue))); + signature = &signatures->asicsignature->signature().back(); signature->id(nr); // Signature->Object->QualifyingProperties->SignedProperties->SignedSignatureProperties @@ -177,9 +297,11 @@ SignatureXAdES_B::SignatureXAdES_B(unsigned int id, ASiContainer *bdoc, Signer * addDataObjectFormat("#" + referenceId, f->mediaType()); } + signatures->reloadDOM(); Digest calc(digestMethod); - calcDigestOnNode(&calc, XADES_NAMESPACE, u"SignedProperties"); + calcDigestOnNode(&calc, Signatures::XADES_NAMESPACE, u"SignedProperties"); addReference("#" + nr +"-SignedProperties", calc.uri(), calc.result(), "http://uri.etsi.org/01903#SignedProperties"); + signatures->reloadDOM(); } /** @@ -192,60 +314,14 @@ SignatureXAdES_B::SignatureXAdES_B(unsigned int id, ASiContainer *bdoc, Signer * * produced by other systems; default = false * @throws SignatureException */ -SignatureXAdES_B::SignatureXAdES_B(istream &sigdata, ASiContainer *bdoc, bool relaxSchemaValidation) - : bdoc(bdoc) +SignatureXAdES_B::SignatureXAdES_B(const std::shared_ptr &signatures, size_t i, ASiContainer *container) + : signatures(signatures) + , bdoc(container) { - try - { - stringstream is; - is << sigdata.rdbuf(); - sigdata_ = is.str(); - - Properties properties; - const auto *xadesShema = relaxSchemaValidation ? "/XAdES01903v132-201601-relaxed.xsd" : "/XAdES01903v132-201601.xsd"; - properties.schema_location(XADES_NAMESPACE, File::fullPathUrl(Conf::instance()->xsdPath() + xadesShema)); - properties.schema_location(XADESv141_NAMESPACE, File::fullPathUrl(Conf::instance()->xsdPath() + "/XAdES01903v141-201601.xsd")); - properties.schema_location(URI_ID_DSIG, File::fullPathUrl(Conf::instance()->xsdPath() + "/xmldsig-core-schema.xsd")); - properties.schema_location(ASIC_NAMESPACE, File::fullPathUrl(Conf::instance()->xsdPath() + "/en_31916201v010101.xsd")); - properties.schema_location(OPENDOCUMENT_NAMESPACE, File::fullPathUrl(Conf::instance()->xsdPath() + "/OpenDocument_dsig.xsd")); - unique_ptr doc(SecureDOMParser(properties.schema_location()).parseIStream(is)); - /* http://www.etsi.org/deliver/etsi_ts/102900_102999/102918/01.03.01_60/ts_102918v010301p.pdf - * 6.2.2 - * 3) The root element of each "*signatures*.xml" content shall be either: - * a) as specified in clause A.5, the recommended format; or - * b) as specified in OASIS Open Document Format [9]; or - * - * Case container is ADoc 1.0 then handle document-signatures root element - */ - if(bdoc->mediaType() == ASiC_E::MIMETYPE_ADOC) - { - odfsignature = document_signatures(*doc, Flags::dont_initialize, properties); - if(odfsignature->signature().size() > 1) - THROW("More than one signature in signatures.xml file is unsupported"); - if(odfsignature->signature().empty()) - THROW("Failed to parse signature XML"); - signature = &odfsignature->signature().front(); - } - else - { - asicsignature = xAdESSignatures(*doc, Flags::dont_initialize, properties); - if(asicsignature->signature().size() > 1) - THROW("More than one signature in signatures.xml file is unsupported"); - if(asicsignature->signature().empty()) - THROW("Failed to parse signature XML"); - signature = &asicsignature->signature().front(); - } - } - catch(const Parsing& e) - { - stringstream s; - s << e; - THROW("Failed to parse signature XML: %s", s.str().c_str()); - } - catch(const xsd::cxx::exception& e) - { - THROW("Failed to parse signature XML: %s", e.what()); - } + if(signatures->odfsignature) + signature = &signatures->odfsignature->signature().at(i); + else + signature = &signatures->asicsignature->signature().at(i); if(const auto &sp = qualifyingProperties().signedProperties()) { @@ -356,7 +432,7 @@ string SignatureXAdES_B::trustedSigningTime() const { return claimedSigningTime(); } - +#include string SignatureXAdES_B::SPUri() const { const SignedSignaturePropertiesType::SignaturePolicyIdentifierOptional &identifier = @@ -446,18 +522,15 @@ void SignatureXAdES_B::validate(const string &policy) const } try { - stringstream ofs; - saveToXml(ofs); - unique_ptr doc(SecureDOMParser().parseIStream(ofs)); - XSECProvider prov; auto deleteSig = [&](DSIGSignature *s) { prov.releaseSignature(s); }; - unique_ptr sig(prov.newSignatureFromDOM(doc.get()), deleteSig); - unique_ptr uriresolver(new URIResolver(bdoc)); - unique_ptr keyresolver(new XSECKeyInfoResolverDefault); + DOMNode *node = signatures->element(id()); + unique_ptr sig(prov.newSignatureFromDOM(node->getOwnerDocument(), node), deleteSig); + unique_ptr uriresolver = make_unique(bdoc); + unique_ptr keyresolver = make_unique(); sig->setURIResolver(uriresolver.get()); sig->setKeyInfoResolver(keyresolver.get()); - sig->registerIdAttributeName((const XMLCh*)u"ID"); + sig->registerIdAttributeName((const XMLCh*)u"Id"); sig->setIdByAttributeName(true); sig->load(); @@ -598,7 +671,7 @@ vector SignatureXAdES_B::dataToSign() const return calc.result(); } -void SignatureXAdES_B::checkCertID(const CertIDType &certID, const X509Cert &cert) const +void SignatureXAdES_B::checkCertID(const CertIDType &certID, const X509Cert &cert) { const X509IssuerSerialType::X509IssuerNameType &certIssuerName = certID.issuerSerial().x509IssuerName(); const X509IssuerSerialType::X509SerialNumberType &certSerialNumber = certID.issuerSerial().x509SerialNumber(); @@ -731,7 +804,7 @@ string SignatureXAdES_B::addReference(const string& uri, const string& digestUri reference->type(type); SignedInfoType::ReferenceSequence &seq = signature->signedInfo().reference(); - reference->id(id() + Log::format("-RefId%lu", (unsigned long)seq.size())); + reference->id(id() + Log::format("-RefId%zu", seq.size())); seq.push_back(std::move(reference)); return seq.back().id().get(); @@ -895,7 +968,7 @@ void SignatureXAdES_B::setSignatureValue(const vector &signatureV { SignatureValueType buffer = toBase64(signatureValue); signature->signatureValue().swap(buffer); - sigdata_.clear(); + signatures->reloadDOM(); } /** @@ -921,35 +994,14 @@ void SignatureXAdES_B::calcDigestOnNode(Digest* calc, const string& ns, { try { - // Parse Xerces DOM from file, to preserve the white spaces "as is" - // and get the same digest value on XML node. - // Canonical XML 1.0 specification (http://www.w3.org/TR/2001/REC-xml-c14n-20010315) - // needs all the white spaces from XML file "as is", otherwise the digests won't match. - // Therefore we have to use Xerces to parse the XML file each time a digest needs to be - // calculated on a XML node. If you are parsing XML files with a parser that doesn't - // preserve the white spaces you are DOOMED! - // Parse and return a copy of the Xerces DOM tree. - // Save to file an parse it again, to make XML Canonicalization work - // correctly as expected by the Canonical XML 1.0 specification. - // Hope, the next Canonical XMl specification fixes the white spaces preserving "bug". - stringstream ofs; - saveToXml(ofs); - unique_ptr doc(SecureDOMParser().parseIStream(ofs)); - - DOMNode *node = nullptr; - // Select node, on which the digest is calculated. - DOMNodeList* nodeList = doc->getElementsByTagNameNS(xml::string(ns).c_str(), tagName.data()); - if(nodeList->getLength() == 1) - node = nodeList->item(0); - - // Make sure that exactly one node was found. - if(!node) + auto *element = signatures->element(id()); + DOMNodeList *nodeList = element->getElementsByTagNameNS(xml::string(ns).c_str(), tagName.data()); + if(nodeList->getLength() != 1) THROW("Could not find '%s' node which is in '%s' namespace in signature XML.", xml::transcode(tagName.data()).data(), ns.c_str()); - if(canonicalizationMethod.empty()) canonicalizationMethod = signature->signedInfo().canonicalizationMethod().algorithm(); - SecureDOMParser::calcDigestOnNode(calc, canonicalizationMethod, doc.get(), node); + SecureDOMParser::calcDigestOnNode(calc, canonicalizationMethod, nodeList->item(0)); } catch(const Exception& e) { @@ -982,38 +1034,6 @@ void SignatureXAdES_B::calcDigestOnNode(Digest* calc, const string& ns, } } -/** - * Saves signature to file using XAdES XML format. - * - * @param os out stream, where the signature XML file is saved. - * @throws Exception throws exception if the signature file creation failed. - */ -void SignatureXAdES_B::saveToXml(ostream &os) const -{ - if(!sigdata_.empty()) - { - os << sigdata_; - return; - } - - try - { - NamespaceInfomap map; - map["ds"].name = URI_ID_DSIG; - map["xades"].name = XADES_NAMESPACE; - map["asic"].name = ASIC_NAMESPACE; - XAdESSignaturesType asic; - asic.signature().push_back(*signature); - xAdESSignatures(os, asic, map, "UTF-8", Flags::dont_initialize); - } - catch(const xml::invalid_utf8_string &) - { - THROW("Failed to create signature XML file. Parameters must be in UTF-8."); - } - if(os.fail()) - THROW("Failed to create signature XML file."); -} - string SignatureXAdES_B::city() const { // return elements from SignatureProductionPlace element or SignatureProductionPlaceV2 when available diff --git a/src/SignatureXAdES_B.h b/src/SignatureXAdES_B.h index bbadcd9bb..a3b72c95a 100644 --- a/src/SignatureXAdES_B.h +++ b/src/SignatureXAdES_B.h @@ -21,6 +21,8 @@ #include "Signature.h" +#include "xml/SecureDOMParser.h" + #include #include @@ -33,12 +35,38 @@ namespace digidoc namespace xades { class CertIDType; class DigestAlgAndValueType; class QualifyingPropertiesType; class SignedSignaturePropertiesType; } namespace asic { class XAdESSignaturesType; class Document_signatures; } + class Signatures + { + public: + explicit Signatures(); + Signatures(std::istream &data, ASiContainer *container); + ~Signatures(); + + xercesc::DOMElement* element(std::string_view id) const; + size_t count() const; + void reloadDOM(); + void save(std::ostream &os) const; + + static const std::string ASIC_NAMESPACE; + static const std::string OPENDOCUMENT_NAMESPACE; + static const std::string XADES_NAMESPACE; + static const std::string XADESv141_NAMESPACE; + + std::unique_ptr asicsignature; + std::unique_ptr odfsignature; + + private: + void parseDOM(std::istream &data, const std::string &schema_location = {}); + + std::unique_ptr doc; + }; + class SignatureXAdES_B : public Signature { public: SignatureXAdES_B(unsigned int id, ASiContainer *bdoc, Signer *signer); - SignatureXAdES_B(std::istream &sigdata, ASiContainer *bdoc, bool relaxSchemaValidation = false); + SignatureXAdES_B(const std::shared_ptr &signatures, size_t i, ASiContainer *container); ~SignatureXAdES_B() override; std::string id() const override; @@ -66,7 +94,7 @@ namespace digidoc const std::vector &digestValue, const std::string& type = {}); void addDataObjectFormat(const std::string& uri, const std::string& mime); - void saveToXml(std::ostream &os) const; + std::shared_ptr signatures; protected: std::vector getSignatureValue() const; @@ -74,18 +102,11 @@ namespace digidoc xades::SignedSignaturePropertiesType& getSignedSignatureProperties() const; void calcDigestOnNode(Digest* calc, const std::string& ns, std::u16string_view tagName, std::string_view canonicalizationMethod = {}) const; - void checkCertID(const xades::CertIDType &certID, const X509Cert &cert) const; - static void checkDigest(const xades::DigestAlgAndValueType &digest, const std::vector &data) ; - - static const std::string ASIC_NAMESPACE; - static const std::string XADES_NAMESPACE; - static const std::string XADESv141_NAMESPACE; - static const std::string OPENDOCUMENT_NAMESPACE; - dsig::SignatureType *signature = nullptr; - std::unique_ptr asicsignature; - std::unique_ptr odfsignature; - ASiContainer *bdoc; - std::string sigdata_; + static void checkCertID(const xades::CertIDType &certID, const X509Cert &cert); + static void checkDigest(const xades::DigestAlgAndValueType &digest, const std::vector &data); + + dsig::SignatureType *signature {}; + ASiContainer *bdoc {}; private: DISABLE_COPY(SignatureXAdES_B); diff --git a/src/SignatureXAdES_LT.cpp b/src/SignatureXAdES_LT.cpp index 491cd045c..a704a556d 100644 --- a/src/SignatureXAdES_LT.cpp +++ b/src/SignatureXAdES_LT.cpp @@ -46,8 +46,8 @@ SignatureXAdES_LT::SignatureXAdES_LT(unsigned int id, ASiContainer *bdoc, Signer : SignatureXAdES_T(id, bdoc, signer) {} -SignatureXAdES_LT::SignatureXAdES_LT(istream &sigdata, ASiContainer *bdoc, bool relaxSchemaValidation) -: SignatureXAdES_T(sigdata, bdoc, relaxSchemaValidation) +SignatureXAdES_LT::SignatureXAdES_LT(const std::shared_ptr &signatures, size_t i, ASiContainer *container) + : SignatureXAdES_T(signatures, i, container) { try { // ADOC files are default T level, take OCSP response to create temporary LT level @@ -58,7 +58,7 @@ SignatureXAdES_LT::SignatureXAdES_LT(istream &sigdata, ASiContainer *bdoc, bool X509Cert issuer = X509CertStore::instance()->findIssuer(cert, X509CertStore::OCSP); if(!issuer) THROW("Could not find certificate issuer '%s' in certificate store.", - cert.issuerName().c_str()); + cert.issuerName().c_str()); addOCSPValue(id().replace(0, 1, "N"), OCSP(cert, issuer)); } @@ -219,7 +219,7 @@ void SignatureXAdES_LT::extendSignatureProfile(const string &profile) X509Cert cert = signingCertificate(); X509Cert issuer = X509CertStore::instance()->findIssuer(cert, X509CertStore::CA); if(!issuer) - issuer = X509CertStore::instance()->issuerFromAIA(cert); + issuer = X509CertStore::issuerFromAIA(cert); if(!issuer) THROW("Could not find certificate issuer '%s' in certificate store or from AIA.", cert.issuerName().c_str()); @@ -229,7 +229,7 @@ void SignatureXAdES_LT::extendSignatureProfile(const string &profile) addCertificateValue(id() + "-CA-CERT", issuer); addOCSPValue(id().replace(0, 1, "N"), ocsp); - sigdata_.clear(); + signatures->reloadDOM(); } /** diff --git a/src/SignatureXAdES_LT.h b/src/SignatureXAdES_LT.h index 9ac01f031..8b7410dd8 100644 --- a/src/SignatureXAdES_LT.h +++ b/src/SignatureXAdES_LT.h @@ -30,7 +30,7 @@ class SignatureXAdES_LT: public SignatureXAdES_T { public: SignatureXAdES_LT(unsigned int id, ASiContainer *bdoc, Signer *signer); - SignatureXAdES_LT(std::istream &sigdata, ASiContainer *bdoc, bool relaxSchemaValidation = false); + SignatureXAdES_LT(const std::shared_ptr &signatures, size_t i, ASiContainer *container); std::string trustedSigningTime() const override; diff --git a/src/SignatureXAdES_LTA.cpp b/src/SignatureXAdES_LTA.cpp index b8dd13b4c..c487f5311 100644 --- a/src/SignatureXAdES_LTA.cpp +++ b/src/SignatureXAdES_LTA.cpp @@ -55,12 +55,10 @@ void SignatureXAdES_LTA::calcArchiveDigest(Digest *digest, string_view canonicalizationMethod) const { try { - stringstream ofs; - saveToXml(ofs); XSECProvider prov; auto deleteSig = [&](DSIGSignature *s) { prov.releaseSignature(s); }; - auto doc = SecureDOMParser().parseIStream(ofs); - unique_ptr sig(prov.newSignatureFromDOM(doc.get()), deleteSig); + DOMNode *node = signatures->element(id()); + unique_ptr sig(prov.newSignatureFromDOM(node->getOwnerDocument(), node), deleteSig); unique_ptr uriresolver = make_unique(bdoc); unique_ptr keyresolver = make_unique(); sig->setURIResolver(uriresolver.get()); @@ -72,15 +70,14 @@ void SignatureXAdES_LTA::calcArchiveDigest(Digest *digest, safeBuffer m_errStr; m_errStr.sbXMLChIn((const XMLCh*)u""); - std::array buf{}; + array buf{}; DSIGReferenceList *list = sig->getReferenceList(); for(size_t i = 0; i < list->getSize(); ++i) { - XSECBinTXFMInputStream *stream = list->item(i)->makeBinInputStream(); + unique_ptr stream(list->item(i)->makeBinInputStream()); for(XMLSize_t size = stream->readBytes(buf.data(), buf.size()); size > 0; size = stream->readBytes(buf.data(), buf.size())) digest->update(buf.data(), size); - delete stream; } } catch(const Parsing &e) @@ -137,14 +134,14 @@ void SignatureXAdES_LTA::calcArchiveDigest(Digest *digest, u"RefsOnlyTimeStamp" }) { try { - calcDigestOnNode(digest, XADES_NAMESPACE, name, canonicalizationMethod); + calcDigestOnNode(digest, Signatures::XADES_NAMESPACE, name, canonicalizationMethod); } catch(const Exception &) { DEBUG("Element %s not found", xsd::cxx::xml::transcode(name).data()); } } try { - calcDigestOnNode(digest, XADESv141_NAMESPACE, u"TimeStampValidationData", canonicalizationMethod); + calcDigestOnNode(digest, Signatures::XADESv141_NAMESPACE, u"TimeStampValidationData", canonicalizationMethod); } catch(const Exception &) { DEBUG("Element TimeStampValidationData not found"); } @@ -170,7 +167,7 @@ void SignatureXAdES_LTA::extendSignatureProfile(const string &profile) usp.archiveTimeStampV141().push_back(std::move(ts)); usp.contentOrder().emplace_back(UnsignedSignaturePropertiesType::archiveTimeStampV141Id, usp.archiveTimeStampV141().size() - 1); - sigdata_.clear(); + signatures->reloadDOM(); } TS SignatureXAdES_LTA::tsaFromBase64() const diff --git a/src/SignatureXAdES_T.cpp b/src/SignatureXAdES_T.cpp index cb4ce2ee8..8478ca943 100644 --- a/src/SignatureXAdES_T.cpp +++ b/src/SignatureXAdES_T.cpp @@ -92,7 +92,7 @@ void SignatureXAdES_T::extendSignatureProfile(const std::string &profile) usp.contentOrder().emplace_back(UnsignedSignaturePropertiesType::ContentOrderType( UnsignedSignaturePropertiesType::signatureTimeStampId, usp.signatureTimeStamp().size() - 1)); - sigdata_.clear(); + signatures->reloadDOM(); } TS SignatureXAdES_T::TimeStamp() const @@ -187,10 +187,8 @@ void SignatureXAdES_T::validate(const std::string &policy) const THROW("CertificateValues::EncapsulatedX509Certificate count does not equal with CompleteCertificateRefs::Cert"); for(size_t i = 0; i < ocspRefs->oCSPRef().size(); ++i) { - const auto &base64 = ocspValues->encapsulatedOCSPValue().at(i); - const auto &ocspRef = ocspRefs->oCSPRef().at(i); - OCSP ocsp((const unsigned char*)base64.data(), base64.size()); - checkDigest(ocspRef.digestAlgAndValue().get(), ocsp); + OCSP ocsp(ocspValues->encapsulatedOCSPValue().at(i)); + checkDigest(ocspRefs->oCSPRef().at(i).digestAlgAndValue().get(), ocsp); } } @@ -206,7 +204,7 @@ void SignatureXAdES_T::validate(const std::string &policy) const u"AttributeRevocationRefs" }) { try { - calcDigestOnNode(digest, XADES_NAMESPACE, name, canonicalizationMethod); + calcDigestOnNode(digest, Signatures::XADES_NAMESPACE, name, canonicalizationMethod); } catch(const Exception &) { DEBUG("Element %s not found", xsd::cxx::xml::transcode(name).data()); } diff --git a/src/util/File.cpp b/src/util/File.cpp index a9aecd2cc..c4dfbf958 100644 --- a/src/util/File.cpp +++ b/src/util/File.cpp @@ -345,13 +345,12 @@ string File::digidocppPath() * @param relativeFilePath file name to be appended to the full path * @return full file path in the format "file:///fullpath" in URI encoding. */ -string File::fullPathUrl(const string &path) +string File::fullPathUrl(string path) { #ifdef _WIN32 // Under windows replace the path delimiters - string result = path; - replace(result.begin(), result.end(), '\\', '/'); - return "file:///" + File::toUri(result); + replace(path.begin(), path.end(), '\\', '/'); + return "file:///" + File::toUri(path); #else return "file://" + File::toUri(path); #endif diff --git a/src/util/File.h b/src/util/File.h index 65983e980..5eefeb4b3 100644 --- a/src/util/File.h +++ b/src/util/File.h @@ -54,7 +54,7 @@ namespace digidoc static std::string fileName(const std::string& path); static std::string directory(const std::string& path); static std::string path(std::string dir, std::string_view relativePath); - static std::string fullPathUrl(const std::string &path); + static std::string fullPathUrl(std::string path); static std::string tempFileName(); static void createDirectory(std::string path); static void deleteTempFiles(); diff --git a/src/xml/SecureDOMParser.cpp b/src/xml/SecureDOMParser.cpp index dcc8ccec2..a397a7daa 100644 --- a/src/xml/SecureDOMParser.cpp +++ b/src/xml/SecureDOMParser.cpp @@ -87,9 +87,9 @@ SecureDOMParser::SecureDOMParser(const string &schema_location, bool dont_valida } void SecureDOMParser::calcDigestOnNode(Digest *calc, - string_view algorithmType, DOMDocument *doc, DOMNode *node) + string_view algorithmType, DOMNode *node) { - XSECC14n20010315 c14n(doc, node); + XSECC14n20010315 c14n(node->getOwnerDocument(), node); c14n.setCommentsProcessing(false); c14n.setUseNamespaceStack(true); @@ -114,7 +114,7 @@ void SecureDOMParser::calcDigestOnNode(Digest *calc, THROW("Unsupported canonicalization method '%s'", algorithmType.data()); } - std::array buffer{}; + array buffer{}; XMLSize_t bytes = 0; while((bytes = c14n.outputBuffer(buffer.data(), buffer.size())) > 0) calc->update(buffer.data(), bytes); @@ -131,7 +131,7 @@ void SecureDOMParser::doctypeDecl(const DTDElementDecl& root, DOMLSParserImpl::doctypeDecl(root, public_id, system_id, has_internal, has_external); } -unique_ptr SecureDOMParser::parseIStream(std::istream &is) +unique_ptr SecureDOMParser::parseIStream(istream &is) { // Wrap the standard input stream. Wrapper4InputSource wrap(new xml::sax::std_input_source(is)); diff --git a/src/xml/SecureDOMParser.h b/src/xml/SecureDOMParser.h index 6d697cfca..cc49ea3b4 100644 --- a/src/xml/SecureDOMParser.h +++ b/src/xml/SecureDOMParser.h @@ -33,8 +33,7 @@ class SecureDOMParser: public xercesc::DOMLSParserImpl SecureDOMParser(const std::string &schema_location = {}); SecureDOMParser(const std::string &schema_location, bool dont_validate); - static void calcDigestOnNode(Digest *calc, std::string_view algorithmType, - xercesc::DOMDocument *doc, xercesc::DOMNode *node); + static void calcDigestOnNode(Digest *calc, std::string_view algorithmType, xercesc::DOMNode *node); void doctypeDecl(const xercesc::DTDElementDecl& root, const XMLCh* const public_id,