From b1bc762851b3b328a8f09fcf2ae986c1e8c8656c Mon Sep 17 00:00:00 2001 From: Raul Metsma Date: Thu, 7 Oct 2021 15:11:54 +0300 Subject: [PATCH] Optimize DDoc memory handling IB-6868 Signed-off-by: Raul Metsma --- src/SiVaContainer.cpp | 85 +++++++++++++++++++------------------ src/SiVaContainer.h | 2 +- src/xml/SecureDOMParser.cpp | 11 ++--- src/xml/SecureDOMParser.h | 2 +- 4 files changed, 52 insertions(+), 48 deletions(-) diff --git a/src/SiVaContainer.cpp b/src/SiVaContainer.cpp index 7d711bc97..97f16acb0 100644 --- a/src/SiVaContainer.cpp +++ b/src/SiVaContainer.cpp @@ -55,29 +55,33 @@ using namespace xercesc; using json = nlohmann::json; static std::string base64_decode(const XMLCh *in) { - static const std::string b = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - static const std::vector T = [] { - std::vector T(256, -1); - for (size_t i = 0; i < b.size(); ++i) - T[b[i]] = i; - return T; - }(); + static constexpr std::array T{ + 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, + 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, + 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x3E, 0x64, 0x64, 0x64, 0x3F, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, + 0x64, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, + 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x64, 0x64, 0x64, 0x64, 0x64, + 0x64, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x64, 0x64, 0x64, 0x64, 0x64 + }; std::string out; - int val = 0; - int valb = -8; + int value = 0; + int bits = -8; for(; in; ++in) { const char c(*in); if(c == '\r' || c == '\n' || c == ' ') continue; - if(T[c] == -1) + uint8_t check = T[c]; + if(check == 0x64) break; - val = (val << 6) + T[c]; - if((valb += 6) < 0) + value = (value << 6) + check; + if((bits += 6) < 0) continue; - out.push_back(char((val >> valb) & 0xFF)); - valb -= 8; + out.push_back(char((value >> bits) & 0xFF)); + bits -= 8; } return out; } @@ -88,7 +92,7 @@ class SiVaContainer::Private { public: string path; - unique_ptr data; + unique_ptr ddoc; vector dataFiles; vector signatures; string mediaType; @@ -111,7 +115,7 @@ void SignatureSiVa::validate() const void SignatureSiVa::validate(const string &policy) const { - static const set QES = { "QESIG", "QES", "QESEAL", + static const set QES = { "QESIG", "QES", "QESEAL", "ADESEAL_QC", "ADESEAL" }; // Special treamtent for E-Seals Exception e(EXCEPTION_PARAMS("Signature validation")); for(const Exception &exception: _exceptions) @@ -149,14 +153,14 @@ SiVaContainer::SiVaContainer(const string &path, const string &ext, bool useHash if(ext == "DDOC") { d->mediaType = "application/x-ddoc"; - d->data = move(ifs); - ifs.reset(parseDDoc(*d->data, useHashCode)); + d->ddoc = move(ifs); + ifs = parseDDoc(useHashCode); is = ifs.get(); } else { d->mediaType = "application/pdf"; - d->dataFiles.push_back(new DataFilePrivate(move(ifs), File::fileName(path), "application/pdf", File::fileName(path))); + d->dataFiles.push_back(new DataFilePrivate(move(ifs), File::fileName(path), "application/pdf")); } array buf{}; @@ -175,6 +179,7 @@ SiVaContainer::SiVaContainer(const string &path, const string &ext, bool useHash b64.append((char*)out, size); delete out; } + ifs.release(); string url = CONF(verifyServiceUri); string req = json({ @@ -315,7 +320,7 @@ vector SiVaContainer::dataFiles() const unique_ptr SiVaContainer::openInternal(const string &path) { - static const set supported = {"PDF", "DDOC"}; + static const set supported = {"PDF", "DDOC"}; string ext = File::fileExtension(path); transform(ext.begin(), ext.end(), ext.begin(), ::toupper); if(!supported.count(ext)) @@ -329,15 +334,13 @@ unique_ptr SiVaContainer::openInternal(const string &path) } } -stringstream* SiVaContainer::parseDDoc(istream &is, bool useHashCode) +std::unique_ptr SiVaContainer::parseDDoc(bool useHashCode) { - auto transcode = [](const XMLCh *chr) { - return xsd::cxx::xml::transcode(chr); - }; + namespace xml = xsd::cxx::xml; + using cpXMLCh = const XMLCh*; try { - using cpXMLCh = const XMLCh*; - unique_ptr dom(SecureDOMParser().parseIStream(is)); + unique_ptr dom(SecureDOMParser().parseIStream(*d->ddoc)); DOMNodeList *nodeList = dom->getElementsByTagName(cpXMLCh(u"DataFile")); for(XMLSize_t i = 0; i < nodeList->getLength(); ++i) { @@ -353,7 +356,9 @@ stringstream* SiVaContainer::parseDDoc(istream &is, bool useHashCode) if(const XMLCh *b64 = item->getTextContent()) { d->dataFiles.push_back(new DataFilePrivate(make_unique(base64_decode(b64)), - transcode(item->getAttribute(cpXMLCh(u"Filename"))), transcode(item->getAttribute(cpXMLCh(u"MimeType"))), transcode(item->getAttribute(cpXMLCh(u"Id"))))); + xml::transcode(item->getAttribute(cpXMLCh(u"Filename"))), + xml::transcode(item->getAttribute(cpXMLCh(u"MimeType"))), + xml::transcode(item->getAttribute(cpXMLCh(u"Id"))))); } if(!useHashCode) @@ -366,7 +371,7 @@ stringstream* SiVaContainer::parseDDoc(istream &is, bool useHashCode) { item->setAttribute(cpXMLCh(u"ContentType"), cpXMLCh(u"HASHCODE")); item->setAttribute(cpXMLCh(u"DigestType"), cpXMLCh(u"sha1")); - xsd::cxx::xml::string outXMLCh(reinterpret_cast(out)); + xml::string outXMLCh(reinterpret_cast(out)); item->setAttribute(cpXMLCh(u"DigestValue"), outXMLCh.c_str()); item->setTextContent(nullptr); delete out; @@ -377,30 +382,30 @@ stringstream* SiVaContainer::parseDDoc(istream &is, bool useHashCode) unique_ptr pDomLsOutput(pImplement->createLSOutput()); unique_ptr pSerializer(pImplement->createLSSerializer()); unique_ptr result = make_unique(); - xsd::cxx::xml::dom::ostream_format_target out(*result); + xml::dom::ostream_format_target out(*result); pDomLsOutput->setByteStream(&out); pSerializer->setNewLine(cpXMLCh(u"\n")); pSerializer->write(dom.get(), pDomLsOutput.get()); - return result.release(); + return result; } catch(const XMLException& e) { try { - string result = transcode(e.getMessage()); + string result = xml::transcode(e.getMessage()); THROW("Failed to parse DDoc XML: %s", result.c_str()); - } catch(const xsd::cxx::xml::invalid_utf16_string & /* ex */) { + } catch(const xml::invalid_utf16_string & /* ex */) { THROW("Failed to parse DDoc XML."); } } catch(const DOMException& e) { try { - string result = transcode(e.getMessage()); + string result = xml::transcode(e.getMessage()); THROW("Failed to parse DDoc XML: %s", result.c_str()); - } catch(const xsd::cxx::xml::invalid_utf16_string & /* ex */) { + } catch(const xml::invalid_utf16_string & /* ex */) { THROW("Failed to parse DDoc XML."); } - } catch(const xsd::cxx::xml::invalid_utf16_string & /* ex */) { + } catch(const xml::invalid_utf16_string & /* ex */) { THROW("Failed to parse DDoc XML."); } catch(const Exception &) @@ -436,13 +441,11 @@ void SiVaContainer::removeSignature(unsigned int /*index*/) void SiVaContainer::save(const string &path) { string to = path.empty() ? d->path : path; - if(d->data) + if(d->ddoc) { - ofstream ofs(File::encodeName(to).c_str(), ofstream::binary); - d->data->clear(); - d->data->seekg(0); - ofs << d->data->rdbuf(); - ofs.close(); + d->ddoc->clear(); + d->ddoc->seekg(0); + ofstream(File::encodeName(to).c_str(), ofstream::binary) << d->ddoc->rdbuf(); } else d->dataFiles[0]->saveAs(to); diff --git a/src/SiVaContainer.h b/src/SiVaContainer.h index 04fcfc555..060796615 100644 --- a/src/SiVaContainer.h +++ b/src/SiVaContainer.h @@ -105,7 +105,7 @@ class SiVaContainer final: public Container SiVaContainer(const std::string &path, const std::string &ext, bool useHashCode); DISABLE_COPY(SiVaContainer); - std::stringstream* parseDDoc(std::istream &is, bool useHashCode); + std::unique_ptr parseDDoc(bool useHashCode); class Private; std::unique_ptr d; diff --git a/src/xml/SecureDOMParser.cpp b/src/xml/SecureDOMParser.cpp index 6b00cfb05..dcc8ccec2 100644 --- a/src/xml/SecureDOMParser.cpp +++ b/src/xml/SecureDOMParser.cpp @@ -34,6 +34,7 @@ DIGIDOCPP_WARNING_DISABLE_MSVC(4005) #include DIGIDOCPP_WARNING_POP +#include #include using namespace digidoc; @@ -86,7 +87,7 @@ SecureDOMParser::SecureDOMParser(const string &schema_location, bool dont_valida } void SecureDOMParser::calcDigestOnNode(Digest *calc, - const string &algorithmType, DOMDocument *doc, DOMNode *node) + string_view algorithmType, DOMDocument *doc, DOMNode *node) { XSECC14n20010315 c14n(doc, node); c14n.setCommentsProcessing(false); @@ -110,13 +111,13 @@ void SecureDOMParser::calcDigestOnNode(Digest *calc, c14n.setInclusive11(); c14n.setCommentsProcessing(true); } else { - THROW("Unsupported canonicalization method '%s'", algorithmType.c_str()); + THROW("Unsupported canonicalization method '%s'", algorithmType.data()); } - unsigned char buffer[1024]; + std::array buffer{}; XMLSize_t bytes = 0; - while((bytes = c14n.outputBuffer(buffer, 1024)) > 0) - calc->update(buffer, bytes); + while((bytes = c14n.outputBuffer(buffer.data(), buffer.size())) > 0) + calc->update(buffer.data(), bytes); } void SecureDOMParser::doctypeDecl(const DTDElementDecl& root, diff --git a/src/xml/SecureDOMParser.h b/src/xml/SecureDOMParser.h index 197a5910a..6d697cfca 100644 --- a/src/xml/SecureDOMParser.h +++ b/src/xml/SecureDOMParser.h @@ -33,7 +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, const std::string &algorithmType, + static void calcDigestOnNode(Digest *calc, std::string_view algorithmType, xercesc::DOMDocument *doc, xercesc::DOMNode *node); void doctypeDecl(const xercesc::DTDElementDecl& root,