diff --git a/etc/schema/OpenDocument_dsig.xsd b/etc/schema/OpenDocument_dsig.xsd index f2b05aa0..c15e16d2 100644 --- a/etc/schema/OpenDocument_dsig.xsd +++ b/etc/schema/OpenDocument_dsig.xsd @@ -34,6 +34,7 @@ + diff --git a/src/SignatureXAdES_B.cpp b/src/SignatureXAdES_B.cpp index f5d2c64c..8bcd81bb 100644 --- a/src/SignatureXAdES_B.cpp +++ b/src/SignatureXAdES_B.cpp @@ -86,6 +86,11 @@ const map SignatureXAdES_B::policylist{ namespace digidoc { +constexpr XMLName DigestMethod {"DigestMethod", DSIG_NS}; +constexpr XMLName DigestValue {"DigestValue", DSIG_NS}; +constexpr XMLName X509IssuerName {"X509IssuerName", DSIG_NS}; +constexpr XMLName X509SerialNumber {"X509SerialNumber", DSIG_NS}; + thread_local ASiContainer *cb_doc {}; thread_local Exception *cb_exception {}; @@ -523,8 +528,8 @@ vector SignatureXAdES_B::dataToSign() const void SignatureXAdES_B::checkCertID(XMLNode certID, const X509Cert &cert) { auto issuerSerial = certID/"IssuerSerial"; - string_view certIssuerName = issuerSerial/XMLName{"X509IssuerName", DSIG_NS}; - string_view certSerialNumber = issuerSerial/XMLName{"X509SerialNumber", DSIG_NS}; + string_view certIssuerName = issuerSerial/X509IssuerName; + string_view certSerialNumber = issuerSerial/X509SerialNumber; if(X509Crypto(cert).compareIssuerToString(certIssuerName) == 0 && cert.serial() == certSerialNumber) return checkDigest(certID/"CertDigest", cert); DEBUG("certIssuerName: \"%.*s\"", int(certIssuerName.size()), certIssuerName.data()); @@ -535,8 +540,8 @@ void SignatureXAdES_B::checkCertID(XMLNode certID, const X509Cert &cert) void SignatureXAdES_B::checkDigest(XMLNode digest, const vector &data) { - auto calcDigest = Digest((digest/XMLName{"DigestMethod", DSIG_NS}).property("Algorithm")).result(data); - vector digestValue = digest/XMLName{"DigestValue", DSIG_NS}; + auto calcDigest = Digest((digest/DigestMethod).property("Algorithm")).result(data); + vector digestValue = digest/DigestValue; if(digestValue == calcDigest) return; DEBUGMEM("Document cert digest", digestValue.data(), digestValue.size()); @@ -655,14 +660,14 @@ void SignatureXAdES_B::setSigningCertificate(string_view name, const X509Cert& x Digest digest; auto certDigest = cert + "CertDigest"; - (certDigest + XMLName{"DigestMethod", DSIG_NS}).setProperty("Algorithm", digest.uri()); - certDigest + XMLName{"DigestValue", DSIG_NS} = digest.result(x509); + (certDigest + DigestMethod).setProperty("Algorithm", digest.uri()); + certDigest + DigestValue = digest.result(x509); if(name == "SigningCertificate") { auto issuerSerial = cert + "IssuerSerial"; - (issuerSerial + XMLName{"X509IssuerName", DSIG_NS}) = x509.issuerName(); - issuerSerial + XMLName{"X509SerialNumber", DSIG_NS} = x509.serial(); + (issuerSerial + X509IssuerName) = x509.issuerName(); + issuerSerial + X509SerialNumber = x509.serial(); } } diff --git a/src/SignatureXAdES_LTA.cpp b/src/SignatureXAdES_LTA.cpp index 845428e3..87f4ea91 100644 --- a/src/SignatureXAdES_LTA.cpp +++ b/src/SignatureXAdES_LTA.cpp @@ -21,112 +21,95 @@ #include "ASiC_E.h" #include "Conf.h" +#include "DataFile_p.h" #include "crypto/Digest.h" #include "crypto/TS.h" #include "crypto/X509Cert.h" #include "util/DateTime.h" +#include "util/File.h" + +#include +#include using namespace digidoc; using namespace digidoc::util; using namespace std; +namespace digidoc +{ +constexpr XMLName ArchiveTimeStamp {"ArchiveTimeStamp", XADESv141_NS}; +} + void SignatureXAdES_LTA::calcArchiveDigest(Digest *digest, string_view canonicalizationMethod) const { -#if 0 - try { - XSECProvider prov; - auto deleteSig = [&](DSIGSignature *s) { prov.releaseSignature(s); }; - 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->setIdByAttributeName(true); - sig->load(); - - safeBuffer m_errStr; - m_errStr.sbXMLChIn((const XMLCh*)u""); - - array buf{}; - DSIGReferenceList *list = sig->getReferenceList(); - for(size_t i = 0; i < list->getSize(); ++i) - { - 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); - } - } - catch(const Parsing &e) - { - stringstream s; - s << e; - THROW("Failed to calculate digest: %s", s.str().c_str()); - } - catch(const xsd::cxx::xml::invalid_utf16_string & /* ex */) { - THROW("Failed to calculate digest"); - } - catch(const XSECException &e) + for(auto ref = signature/"SignedInfo"/"Reference"; ref; ref++) { - try { - string result = xsd::cxx::xml::transcode(e.getMsg()); - THROW("Failed to calculate digest: %s", result.c_str()); - } catch(const xsd::cxx::xml::invalid_utf16_string & /* ex */) { - THROW("Failed to calculate digest"); + auto uri = ref.property("URI"); + if(ref.property("Type") == REF_TYPE) + { + auto sp = qualifyingProperties()/"SignedProperties"; + if(uri.front() != '#' || sp.property("Id") != uri.substr(1)) + THROW("Invalid SignedProperties ID"); + signatures->c14n(digest, canonicalizationMethod, sp); + continue; } - } - catch(XMLException &e) - { - try { - string result = xsd::cxx::xml::transcode(e.getMessage()); - THROW("Failed to calculate digest: %s", result.c_str()); - } catch(const xsd::cxx::xml::invalid_utf16_string & /* ex */) { - THROW("Failed to calculate digest"); + + string uriPath = File::fromUriPath(uri); + if(uriPath.front() == '/') + uriPath.erase(0); + + auto files = bdoc->dataFiles(); + auto file = find_if(files.cbegin(), files.cend(), [&uriPath](DataFile *file) { + return file->fileName() == uriPath; + }); + if(file == files.cend()) + THROW("Filed to find reference URI in container"); + + std::istream *is = static_cast(*file)->m_is.get(); + array buf{}; + is->clear(); + is->seekg(0); + while(*is) + { + is->read((char*)buf.data(), streamsize(buf.size())); + if(is->gcount() > 0) + digest->update(buf.data(), size_t(is->gcount())); } } - catch(...) - { - THROW("Failed to calculate digest"); - } - for(const auto *name: {u"SignedInfo", u"SignatureValue", u"KeyInfo"}) + for(const auto *name: {"SignedInfo", "SignatureValue", "KeyInfo"}) { - try { - calcDigestOnNode(digest, DSIG_NS, name, canonicalizationMethod); - } catch(const Exception &) { - DEBUG("Element %s not found", xsd::cxx::xml::transcode(name).data()); - } + if(auto elem = signature/name) + signatures->c14n(digest, canonicalizationMethod, elem); + else + DEBUG("Element %s not found", name); } + auto usp = unsignedSignatureProperties(); for(const auto *name: { - u"SignatureTimeStamp", - u"CounterSignature", - u"CompleteCertificateRefs", - u"CompleteRevocationRefs", - u"AttributeCertificateRefs", - u"AttributeRevocationRefs", - u"CertificateValues", - u"RevocationValues", - u"SigAndRefsTimeStamp", - u"RefsOnlyTimeStamp" }) + "SignatureTimeStamp", + "CounterSignature", + "CompleteCertificateRefs", + "CompleteRevocationRefs", + "AttributeCertificateRefs", + "AttributeRevocationRefs", + "CertificateValues", + "RevocationValues", + "SigAndRefsTimeStamp", + "RefsOnlyTimeStamp" }) { - try { - calcDigestOnNode(digest, Signatures::XADES_NAMESPACE, name, canonicalizationMethod); - } catch(const Exception &) { - DEBUG("Element %s not found", xsd::cxx::xml::transcode(name).data()); - } + if(auto elem = usp/name) + signatures->c14n(digest, canonicalizationMethod, elem); + else + DEBUG("Element %s not found", name); } - try { - calcDigestOnNode(digest, Signatures::XADESv141_NAMESPACE, u"TimeStampValidationData", canonicalizationMethod); - } catch(const Exception &) { + if(auto elem = usp/XMLName{"TimeStampValidationData", XADESv141_NS}) + signatures->c14n(digest, canonicalizationMethod, elem); + else DEBUG("Element TimeStampValidationData not found"); - } //ds:Object -#endif } void SignatureXAdES_LTA::extendSignatureProfile(const string &profile) @@ -134,38 +117,24 @@ void SignatureXAdES_LTA::extendSignatureProfile(const string &profile) SignatureXAdES_LT::extendSignatureProfile(profile); if(profile != ASiC_E::ASIC_TSA_PROFILE) return; -#if 0 Digest calc; - calcArchiveDigest(&calc, signature->signedInfo().canonicalizationMethod().algorithm()); + auto method = canonicalizationMethod(); + calcArchiveDigest(&calc, method); + TS tsa(CONF(TSUrl), calc); - vector der = tsa; - auto &usp = unsignedSignatureProperties(); - auto ts = make_unique(); - ts->id(id() + "-A0"); - ts->canonicalizationMethod(signature->signedInfo().canonicalizationMethod()); - ts->encapsulatedTimeStamp().push_back(make_unique( - Base64Binary(der.data(), der.size(), der.size(), false))); - usp.archiveTimeStampV141().push_back(std::move(ts)); - usp.contentOrder().emplace_back(UnsignedSignaturePropertiesType::archiveTimeStampV141Id, - usp.archiveTimeStampV141().size() - 1); - signatures->reloadDOM(); -#endif + auto usp = unsignedSignatureProperties(); + auto ts = usp + ArchiveTimeStamp; + ts.setNS(ts.addNS(XADESv141_NS, "xades141")); + ts.setProperty("Id", id() + "-A0"); + (ts + CanonicalizationMethod).setProperty("Algorithm", method); + ts + EncapsulatedTimeStamp = tsa; } TS SignatureXAdES_LTA::tsaFromBase64() const { -#if 0 try { - if(unsignedSignatureProperties().archiveTimeStampV141().empty()) - return {}; - const xadesv141::ArchiveTimeStampType &ts = unsignedSignatureProperties().archiveTimeStampV141().front(); - if(ts.encapsulatedTimeStamp().empty()) - return {}; - const GenericTimeStampType::EncapsulatedTimeStampType &bin = - ts.encapsulatedTimeStamp().front(); - return {(const unsigned char*)bin.data(), bin.size()}; + return {unsignedSignatureProperties()/ArchiveTimeStamp/EncapsulatedTimeStamp}; } catch(const Exception &) {} -#endif return {}; } @@ -196,24 +165,16 @@ void SignatureXAdES_LTA::validate(const string &policy) const return; } -#if 0 try { - if(unsignedSignatureProperties().archiveTimeStampV141().empty()) + auto ts = unsignedSignatureProperties()/ArchiveTimeStamp; + if(!ts) THROW("Missing ArchiveTimeStamp element"); - - const xadesv141::ArchiveTimeStampType &ts = unsignedSignatureProperties().archiveTimeStampV141().front(); - if(ts.encapsulatedTimeStamp().empty()) - THROW("Missing EncapsulatedTimeStamp"); - verifyTS(ts, exception, [this](Digest *digest, string_view canonicalizationMethod) { calcArchiveDigest(digest, canonicalizationMethod); }); } catch(const Exception &e) { exception.addCause(e); } -#else - EXCEPTION_ADD(exception, "LTA validation is not supported"); -#endif if(!exception.causes().empty()) throw exception; } diff --git a/src/SignatureXAdES_T.cpp b/src/SignatureXAdES_T.cpp index 20b38f64..37bbe42f 100644 --- a/src/SignatureXAdES_T.cpp +++ b/src/SignatureXAdES_T.cpp @@ -75,7 +75,7 @@ void SignatureXAdES_T::extendSignatureProfile(const std::string &profile) TS tsa(CONF(TSUrl), calc); auto ts = usp + "SignatureTimeStamp"; ts.setProperty("Id", id() + Log::format("-T%zu", i)); - (ts + XMLName{"CanonicalizationMethod", DSIG_NS}).setProperty("Algorithm", method); + (ts + CanonicalizationMethod).setProperty("Algorithm", method); ts + "EncapsulatedTimeStamp" = tsa; } @@ -197,7 +197,7 @@ XMLNode SignatureXAdES_T::unsignedSignatureProperties() const TS SignatureXAdES_T::verifyTS(XMLNode timestamp, digidoc::Exception &exception, std::function &&calcDigest) { - auto ets = timestamp/XMLName{"EncapsulatedTimeStamp", XADES_NS}; + auto ets = timestamp/EncapsulatedTimeStamp; if(!ets) THROW("Missing EncapsulatedTimeStamp"); if(ets + 1) @@ -205,7 +205,7 @@ TS SignatureXAdES_T::verifyTS(XMLNode timestamp, digidoc::Exception &exception, TS ts(ets); Digest calc(ts.digestMethod()); - calcDigest(&calc, (timestamp/XMLName{"CanonicalizationMethod", DSIG_NS}).property("Algorithm")); + calcDigest(&calc, (timestamp/CanonicalizationMethod).property("Algorithm")); ts.verify(calc.result()); diff --git a/src/SignatureXAdES_T.h b/src/SignatureXAdES_T.h index 1dac3320..359e03ed 100644 --- a/src/SignatureXAdES_T.h +++ b/src/SignatureXAdES_T.h @@ -27,6 +27,8 @@ namespace digidoc { class TS; +constexpr XMLName EncapsulatedTimeStamp {"EncapsulatedTimeStamp", XADES_NS}; +constexpr XMLName CanonicalizationMethod {"CanonicalizationMethod", DSIG_NS}; class SignatureXAdES_T: public SignatureXAdES_B { diff --git a/src/XMLDocument.h b/src/XMLDocument.h index 3ff954ab..0b6dd148 100644 --- a/src/XMLDocument.h +++ b/src/XMLDocument.h @@ -108,8 +108,6 @@ struct XMLElem using sv = std::string_view; using pcxmlChar = const xmlChar *; - static constexpr sv whitespace {" \n\r\f\t\v"}; - template constexpr static auto safe(C c, P p) noexcept { @@ -173,6 +171,7 @@ struct XMLElem constexpr operator sv() const noexcept { + constexpr sv whitespace {" \n\r\f\t\v"}; auto *text = children(&value_type::children, XML_TEXT_NODE); auto result = to_string_view(text, &std::decay_t::content); result.remove_prefix(std::min(result.find_first_not_of(whitespace), result.size())); @@ -218,6 +217,11 @@ struct XMLNode: public XMLElem return xmlSearchNsByHref(nullptr, d, ns.empty() ? nullptr : pcxmlChar(ns.data())); } + void setNS(xmlNsPtr ns) + { + xmlSetNs(d, ns); + } + constexpr sv property(sv name, sv ns = {}) const noexcept { return find(XMLElem{children(&value_type::properties, XML_ATTRIBUTE_NODE)}, name, ns); @@ -337,7 +341,7 @@ struct XMLDocument: public unique_xml_t, public XMLNode { doc.d = xmlNewNode(nullptr, pcxmlChar(name.data())); if(!href.empty()) - xmlSetNs(doc.d, doc.addNS(href, prefix)); + doc.setNS(doc.addNS(href, prefix)); xmlDocSetRootElement(doc.get(), doc.d); } return doc;