From c90d29791b7020352b8544482d1ea81135051522 Mon Sep 17 00:00:00 2001 From: Raul Metsma Date: Thu, 11 Apr 2024 13:52:25 +0300 Subject: [PATCH] Implement LTA support IB-7996 Signed-off-by: Raul Metsma --- .github/workflows/build.yml | 7 +- etc/schema/OpenDocument_dsig.xsd | 1 + prepare_osx_build_environment.sh | 2 +- src/ASiC_E.cpp | 4 +- src/SiVaContainer.cpp | 8 +- src/SignatureXAdES_B.cpp | 71 ++++---- src/SignatureXAdES_B.h | 12 +- src/SignatureXAdES_LT.cpp | 4 +- src/SignatureXAdES_LTA.cpp | 188 ++++++++------------- src/SignatureXAdES_T.cpp | 13 +- src/SignatureXAdES_T.h | 1 + src/XMLDocument.h | 23 ++- src/XmlConf.cpp | 8 +- src/crypto/TSL.cpp | 12 +- vcpkg-ports/openssl/windows/portfile.cmake | 2 +- vcpkg.json | 2 +- 16 files changed, 166 insertions(+), 192 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ad3242a76..c593f7af7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -159,7 +159,7 @@ jobs: - name: Prepare vcpkg uses: lukka/run-vcpkg@v11 with: - vcpkgGitCommitId: 4065f37d0a6628ef17cf6ee15385f9091f1075bc + vcpkgGitCommitId: 1de2026f28ead93ff1773e6e680387643e914ea1 vcpkgJsonGlob: ./vcpkg.json runVcpkgInstall: true runVcpkgFormatString: "[`install`, `--recurse`, `--clean-after-build`, `--x-install-root`, `$[env.VCPKG_INSTALLED_DIR]`, `--triplet`, `$[env.VCPKG_DEFAULT_TRIPLET]`, `--x-feature`, `tests`]" @@ -169,9 +169,10 @@ jobs: - name: Install dependencies run: choco install doxygen.install -y > $null - uses: actions/setup-python@v5 + if: matrix.platform == 'x86' with: - python-version: 3.11 - architecture: ${{ matrix.platform }} + python-version: 3.12 + architecture: x86 - name: Install WiX run: | dotnet tool install -g wix --version 5.0.0 diff --git a/etc/schema/OpenDocument_dsig.xsd b/etc/schema/OpenDocument_dsig.xsd index f2b05aa06..c15e16d27 100644 --- a/etc/schema/OpenDocument_dsig.xsd +++ b/etc/schema/OpenDocument_dsig.xsd @@ -34,6 +34,7 @@ + diff --git a/prepare_osx_build_environment.sh b/prepare_osx_build_environment.sh index 643bec77b..4fca64e20 100755 --- a/prepare_osx_build_environment.sh +++ b/prepare_osx_build_environment.sh @@ -2,7 +2,7 @@ set -e OPENSSL_DIR=openssl-3.0.14 -LIBXML2_DIR=libxml2-2.12.8 +LIBXML2_DIR=libxml2-2.12.9 XMLSEC_DIR=xmlsec1-1.3.5 ANDROID_NDK=android-ndk-r26d FREETYPE_DIR=freetype-2.10.1 diff --git a/src/ASiC_E.cpp b/src/ASiC_E.cpp index dec7b7901..46a2802ea 100644 --- a/src/ASiC_E.cpp +++ b/src/ASiC_E.cpp @@ -221,8 +221,8 @@ void ASiC_E::parseManifestAndLoadFiles(const ZipSerialize &z) doc.validateSchema(File::path(Conf::instance()->xsdPath(), "OpenDocument_manifest_v1_2.xsd")); for(auto file = doc/"file-entry"; file; file++) { - auto full_path = file.property("full-path", MANIFEST_NS); - auto media_type = file.property("media-type", MANIFEST_NS); + auto full_path = file[{"full-path", MANIFEST_NS}]; + auto media_type = file[{"media-type", MANIFEST_NS}]; DEBUG("full_path = '%s', media_type = '%s'", full_path.data(), media_type.data()); if(manifestFiles.find(full_path) != manifestFiles.end()) diff --git a/src/SiVaContainer.cpp b/src/SiVaContainer.cpp index 48c9dbbcc..0d4fc96a1 100644 --- a/src/SiVaContainer.cpp +++ b/src/SiVaContainer.cpp @@ -350,15 +350,15 @@ unique_ptr SiVaContainer::parseDDoc(bool useHashCode) auto doc = XMLDocument::openStream(*d->ddoc, {}, true); for(auto dataFile = doc/"DataFile"; dataFile; dataFile++) { - auto contentType = dataFile.property("ContentType"); + auto contentType = dataFile["ContentType"]; if(contentType == "HASHCODE") THROW("Currently supports only content types EMBEDDED_BASE64 for DDOC format"); if(contentType != "EMBEDDED_BASE64") continue; d->dataFiles.push_back(new DataFilePrivate(base64_decode(dataFile), - string(dataFile.property("Filename")), - string(dataFile.property("MimeType")), - string(dataFile.property("Id")))); + string(dataFile["Filename"]), + string(dataFile["MimeType"]), + string(dataFile["Id"]))); if(!useHashCode) continue; Digest calc(URI_SHA1); diff --git a/src/SignatureXAdES_B.cpp b/src/SignatureXAdES_B.cpp index f5d2c64cb..28a7b6b76 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 {}; @@ -200,14 +205,14 @@ SignatureXAdES_B::SignatureXAdES_B(unsigned int id, ASiContainer *container, Sig signature = *signatures + XMLName{"Signature", DSIG_NS}; signature.setProperty("Id", nr); auto signedInfo = signature + "SignedInfo"; - (signedInfo + "CanonicalizationMethod").setProperty("Algorithm", canonMethod); + (signedInfo + CanonicalizationMethod).setProperty("Algorithm", canonMethod); (signedInfo + "SignatureMethod").setProperty("Algorithm", X509Crypto(c).isRSAKey() ? Digest::toRsaUri(signer->method()) : Digest::toEcUri(signer->method())); (signature + "SignatureValue").setProperty("Id", nr + "-SIG"); signature + "KeyInfo" + "X509Data" + "X509Certificate" = c; - auto qualifyingProperties = signature + "Object" + XMLName{"QualifyingProperties", XADES_NS}; + auto qualifyingProperties = signature + "Object" + QualifyingProperties; qualifyingProperties.setProperty("Target", "#" + nr); auto signedProperties = qualifyingProperties + "SignedProperties"; @@ -262,7 +267,7 @@ SignatureXAdES_B::SignatureXAdES_B(const std::shared_ptr &signatures THROW("Signature block contains more than one 'Object' block."); // QualifyingProperties - XMLNode qp = object/XMLName{"QualifyingProperties", XADES_NS}; + XMLNode qp = object/QualifyingProperties; if(!qp) THROW("Signature block 'QualifyingProperties' is missing."); if(qp + 1) @@ -307,13 +312,13 @@ SignatureXAdES_B::SignatureXAdES_B(const std::shared_ptr &signatures string_view SignatureXAdES_B::canonicalizationMethod() const noexcept { - return (signature/"SignedInfo"/"CanonicalizationMethod").property("Algorithm"); + return (signature/"SignedInfo"/CanonicalizationMethod)["Algorithm"]; } string SignatureXAdES_B::policy() const { if(auto id = signedSignatureProperties()/"SignaturePolicyIdentifier"/"SignaturePolicyId"/"SigPolicyId"/"Identifier"; - id && id.property("Qualifier") == "OIDAsURN") + id && id["Qualifier"] == "OIDAsURN") return string(id); return {}; } @@ -390,8 +395,8 @@ void SignatureXAdES_B::validate(const string &policy) const { #if 0 //Disabled IB-3684 auto hash = id/"SigPolicyHash"; - auto algo = hash[{"DigestMethod", DSIG_NS}].property("Algorithm"); - vector digest = hash[{"DigestValue", DSIG_NS}]; + auto algo = (hash/DigestMethod)["Algorithm"]; + vector digest = hash/DigestValue; bool valid = false; if(algo == URI_SHA1) valid = digest == p->second.SHA1; @@ -424,7 +429,7 @@ void SignatureXAdES_B::validate(const string &policy) const for(auto data = sdop/"DataObjectFormat"; data; data++) { if(auto mime = data/"MimeType") - mimeinfo.emplace(data.property("ObjectReference"), mime); + mimeinfo.emplace(data["ObjectReference"], mime); } } else @@ -435,18 +440,18 @@ void SignatureXAdES_B::validate(const string &policy) const } map signatureref; - string_view signedPropertiesId = sp.property("Id"); + string_view signedPropertiesId = sp["Id"]; bool signedInfoFound = false; for(auto ref = signature/"SignedInfo"/"Reference"; ref; ref++) { - auto uri = ref.property("URI"); + auto uri = ref["URI"]; if(uri.empty()) { EXCEPTION_ADD(exception, "Reference URI missing"); continue; } - if(auto algo = (ref/"DigestMethod").property("Algorithm"); + if(auto algo = (ref/DigestMethod)["Algorithm"]; !Exception::hasWarningIgnore(Exception::ReferenceDigestWeak) && (algo == URI_SHA1 || algo == URI_SHA224)) { @@ -455,18 +460,18 @@ void SignatureXAdES_B::validate(const string &policy) const exception.addCause(e); } - if(uri.front() == '#' && uri.substr(1) == signedPropertiesId && ref.property("Type") == REF_TYPE) + if(uri.front() == '#' && uri.substr(1) == signedPropertiesId && ref["Type"] == REF_TYPE) signedInfoFound = true; else if(!sdop) continue; // DataObjectProperties is missing, no need to match later MediaTypes - else if(ref.property("Id").empty()) + else if(ref["Id"].empty()) EXCEPTION_ADD(exception, "Reference '%.*s' ID missing", int(uri.size()), uri.data()); else { string uriPath = File::fromUriPath(uri); if(uriPath.front() == '/') uriPath.erase(0); - signatureref.emplace(uriPath, mimeinfo[string("#").append(ref.property("Id"))]); + signatureref.emplace(uriPath, mimeinfo[string("#").append(ref["Id"])]); } } if(!signedInfoFound) @@ -516,15 +521,15 @@ vector SignatureXAdES_B::dataToSign() const { Digest calc(signatureMethod()); auto signedInfo = signature/"SignedInfo"; - signatures->c14n(&calc, (signedInfo/"CanonicalizationMethod").property("Algorithm"), signedInfo); + signatures->c14n(&calc, (signedInfo/CanonicalizationMethod)["Algorithm"], signedInfo); return calc.result(); } 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)["Algorithm"]).result(data); + vector digestValue = digest/DigestValue; if(digestValue == calcDigest) return; DEBUGMEM("Document cert digest", digestValue.data(), digestValue.size()); @@ -636,8 +641,8 @@ string SignatureXAdES_B::addReference(const string& uri, const string& digestUri if(!canon.empty()) (reference + "Transforms" + "Transform").setProperty("Algorithm", canon); - (reference + "DigestMethod").setProperty("Algorithm", digestUri); - reference + "DigestValue" = digestValue; + (reference + DigestMethod).setProperty("Algorithm", digestUri); + reference + DigestValue = digestValue; return refId; } @@ -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(); } } @@ -712,17 +717,9 @@ void SignatureXAdES_B::setSignerRoles(string_view name, const vector &ro * * @param signatureValue signature value. */ -void SignatureXAdES_B::setSignatureValue(const vector &signatureValue) -{ - signature/"SignatureValue" = signatureValue; -} - -/** - * @return returns signature value. - */ -vector SignatureXAdES_B::getSignatureValue() const +void SignatureXAdES_B::setSignatureValue(const vector &value) { - return signature/"SignatureValue"; + signatureValue() = value; } string SignatureXAdES_B::city() const @@ -781,12 +778,12 @@ X509Cert SignatureXAdES_B::signingCertificate() const string SignatureXAdES_B::id() const { - return string(signature.property("Id")); + return string(signature["Id"]); } string SignatureXAdES_B::signatureMethod() const { - return string((signature/"SignedInfo"/"SignatureMethod").property("Algorithm")); + return string((signature/"SignedInfo"/"SignatureMethod")["Algorithm"]); } /** diff --git a/src/SignatureXAdES_B.h b/src/SignatureXAdES_B.h index 00223b177..b1d03dde1 100644 --- a/src/SignatureXAdES_B.h +++ b/src/SignatureXAdES_B.h @@ -34,6 +34,9 @@ namespace digidoc constexpr std::string_view XADESv141_NS {"http://uri.etsi.org/01903/v1.4.1#"}; constexpr std::string_view REF_TYPE {"http://uri.etsi.org/01903#SignedProperties"}; + constexpr XMLName QualifyingProperties {"QualifyingProperties", XADES_NS}; + constexpr XMLName CanonicalizationMethod {"CanonicalizationMethod", DSIG_NS}; + class ASiContainer; class Signer; class Signatures: public XMLDocument @@ -63,7 +66,7 @@ namespace digidoc void validate() const final; void validate(const std::string &policy) const override; std::vector dataToSign() const final; - void setSignatureValue(const std::vector &signatureValue) final; + void setSignatureValue(const std::vector &value) final; // Xades properties std::string policy() const final; @@ -80,10 +83,13 @@ namespace digidoc protected: std::string_view canonicalizationMethod() const noexcept; - std::vector getSignatureValue() const; + constexpr XMLNode signatureValue() const noexcept + { + return signature/"SignatureValue"; + } constexpr XMLNode qualifyingProperties() const noexcept { - return signature/"Object"/XMLName{"QualifyingProperties", XADES_NS}; + return signature/"Object"/QualifyingProperties; } constexpr XMLNode signedSignatureProperties() const noexcept; static void checkCertID(XMLNode certID, const X509Cert &cert); diff --git a/src/SignatureXAdES_LT.cpp b/src/SignatureXAdES_LT.cpp index 46e6e485b..e4ad59603 100644 --- a/src/SignatureXAdES_LT.cpp +++ b/src/SignatureXAdES_LT.cpp @@ -44,7 +44,7 @@ SignatureXAdES_LT::SignatureXAdES_LT(const std::shared_ptr &signatur { try { // ADOC files are default T level, take OCSP response to create temporary LT level - if(bdoc->mediaType() == ASiContainer::MIMETYPE_ADOC && + if(container->mediaType() == ASiContainer::MIMETYPE_ADOC && !(unsignedSignatureProperties()/"RevocationValues")) { X509Cert cert = signingCertificate(); @@ -149,7 +149,7 @@ void SignatureXAdES_LT::validate(const string &policy) const string method = Digest::digestInfoUri(ocsp.nonce()); if(method.empty()) THROW("Nonce digest method is missing"); - vector digest = Digest(method).result(getSignatureValue()); + vector digest = Digest(method).result(signatureValue()); vector respDigest = Digest::digestInfoDigest(ocsp.nonce()); if(digest != respDigest) { diff --git a/src/SignatureXAdES_LTA.cpp b/src/SignatureXAdES_LTA.cpp index 845428e32..965dd0e03 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["URI"]; + if(ref["Type"] == REF_TYPE) + { + auto sp = qualifyingProperties()/"SignedProperties"; + if(uri.front() != '#' || sp["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,23 @@ 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 ts = unsignedSignatureProperties() + 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 +164,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 20b38f647..39ae1ef19 100644 --- a/src/SignatureXAdES_T.cpp +++ b/src/SignatureXAdES_T.cpp @@ -70,12 +70,12 @@ void SignatureXAdES_T::extendSignatureProfile(const std::string &profile) Digest calc; auto method = canonicalizationMethod(); - signatures->c14n(&calc, method, signature/"SignatureValue"); + signatures->c14n(&calc, method, signatureValue()); 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; } @@ -110,7 +110,7 @@ void SignatureXAdES_T::validate(const std::string &policy) const THROW("More than one SignatureTimeStamp is not supported"); TS tsa = verifyTS(ts, exception, [this](Digest *digest, string_view canonicalizationMethod) { - signatures->c14n(digest, canonicalizationMethod, signature/"SignatureValue"); + signatures->c14n(digest, canonicalizationMethod, signatureValue()); }); tm tm = tsa.time(); @@ -164,7 +164,7 @@ void SignatureXAdES_T::validate(const std::string &policy) const for(auto sigAndRefsTS = usp/"SigAndRefsTimeStamp"; sigAndRefsTS; sigAndRefsTS++) { verifyTS(sigAndRefsTS, exception, [this, usp](Digest *digest, string_view canonicalizationMethod) { - signatures->c14n(digest, canonicalizationMethod, signature/"SignatureValue"); + signatures->c14n(digest, canonicalizationMethod, signatureValue()); for(const auto *name: { "SignatureTimeStamp", "CompleteCertificateRefs", @@ -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,10 +205,9 @@ 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)["Algorithm"]); ts.verify(calc.result()); - if(ts.digestMethod() == URI_SHA1 && !Exception::hasWarningIgnore(Exception::ReferenceDigestWeak)) { diff --git a/src/SignatureXAdES_T.h b/src/SignatureXAdES_T.h index 1dac3320c..5d618097a 100644 --- a/src/SignatureXAdES_T.h +++ b/src/SignatureXAdES_T.h @@ -27,6 +27,7 @@ namespace digidoc { class TS; +constexpr XMLName EncapsulatedTimeStamp {"EncapsulatedTimeStamp", XADES_NS}; class SignatureXAdES_T: public SignatureXAdES_B { diff --git a/src/XMLDocument.h b/src/XMLDocument.h index 3ff954aba..d57fd3641 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,9 +217,9 @@ struct XMLNode: public XMLElem return xmlSearchNsByHref(nullptr, d, ns.empty() ? nullptr : pcxmlChar(ns.data())); } - constexpr sv property(sv name, sv ns = {}) const noexcept + void setNS(xmlNsPtr ns) { - return find(XMLElem{children(&value_type::properties, XML_ATTRIBUTE_NODE)}, name, ns); + xmlSetNs(d, ns); } void setProperty(sv name, sv value, sv ns) const noexcept @@ -277,10 +276,20 @@ struct XMLNode: public XMLElem return operator +({name, ns()}); } - constexpr auto operator+(int n) noexcept + constexpr sv operator[](const char *name) const noexcept + { + return operator [](XMLName{name, {}}); + } + + constexpr sv operator[](const XMLName &n) const noexcept + { + return find(XMLElem{children(&value_type::properties, XML_ATTRIBUTE_NODE)}, n.name, n.ns); + } + + constexpr auto operator+(int i) noexcept { XMLNode c{*this}; - for(int i = 0; c && i < n; ++i, c++); + for(; c && i > 0; --i, c++); return c; } @@ -337,7 +346,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; diff --git a/src/XmlConf.cpp b/src/XmlConf.cpp index 91d193553..d38446401 100644 --- a/src/XmlConf.cpp +++ b/src/XmlConf.cpp @@ -156,13 +156,13 @@ void XmlConf::Private::init(const string& path, bool global) { if(elem.name() == "ocsp") { - ocsp.emplace(elem.property("issuer"), elem); + ocsp.emplace(elem["issuer"], elem); continue; } - auto paramName = elem.property("name"); + auto paramName = elem["name"]; string_view value = elem; optional lock; - if(auto val = elem.property("lock"); !val.empty()) + if(auto val = elem["lock"]; !val.empty()) lock = val == "true"; auto setValue = [&](auto ¶m) { if(paramName != param.name) @@ -229,7 +229,7 @@ void XmlConf::Private::setUserConf(XmlConfParam ¶m, A value) // Remove old entries for(auto i = doc.begin(); i != doc.end();) { - if(XMLNode n{*i}; n.name() == "param" && n.property("name") == param.name) + if(XMLNode n{*i}; n.name() == "param" && n["name"] == param.name) i = XMLNode::erase(i); else ++i; diff --git a/src/crypto/TSL.cpp b/src/crypto/TSL.cpp index 266b28c87..43349b84a 100644 --- a/src/crypto/TSL.cpp +++ b/src/crypto/TSL.cpp @@ -307,7 +307,7 @@ bool TSL::parseInfo(XMLNode info, Service &s) vector qualifiers; for(auto extension = info/"ServiceInformationExtensions"/"Extension"; extension; extension++) { - if(extension.property("Critical") == "true") + if(extension["Critical"] == "true") { if(auto takenOverByType = extension/"TakenOverByType") WARN("Found critical extension TakenOverByType '%s'", toString(takenOverByType/"TSPName").data()); @@ -324,11 +324,11 @@ bool TSL::parseInfo(XMLNode info, Service &s) Qualifier &q = qualifiers.emplace_back(); for(auto qualifier = element/"Qualifiers"/"Qualifier"; qualifier; qualifier++) { - if(auto uri = qualifier.property("uri"); !uri.empty()) + if(auto uri = qualifier["uri"]; !uri.empty()) q.qualifiers.emplace_back(uri); } auto criteriaList = element/"CriteriaList"; - q.assert_ = criteriaList.property("assert"); + q.assert_ = criteriaList["assert"]; for(auto criteria: criteriaList) { if(criteria.name() == "KeyUsage" && criteria.ns() == ECC_NS) @@ -336,7 +336,7 @@ bool TSL::parseInfo(XMLNode info, Service &s) map &usage = q.keyUsage.emplace_back(); for(auto bit = criteria/"KeyUsageBit"; bit; bit++) { - auto name = bit.property("name"); + auto name = bit["name"]; auto value = string_view(bit) == "true"; if(name == "digitalSignature") usage[X509Cert::DigitalSignature] = value; @@ -398,7 +398,7 @@ vector TSL::pivotURLs() const vector result; for(auto uriNode = schemeInformation/"SchemeInformationURI"/"URI"; uriNode; uriNode++) { - if(uriNode.property("lang", XML_NS) != "en") + if(uriNode[{"lang", XML_NS}] != "en") continue; if(string_view uri = uriNode; uri.find("pivot") != string::npos && uri.find(current) == string::npos) result.emplace_back(uri); @@ -496,7 +496,7 @@ string_view TSL::territory() const noexcept string_view TSL::toString(XMLNode obj, string_view lang) noexcept { for(auto n = obj/"Name"; n; n++) - if(n.property("lang", XML_NS) == lang) + if(n[{"lang", XML_NS}] == lang) return n; return obj/"Name"; } diff --git a/vcpkg-ports/openssl/windows/portfile.cmake b/vcpkg-ports/openssl/windows/portfile.cmake index d35f30972..1155b1202 100644 --- a/vcpkg-ports/openssl/windows/portfile.cmake +++ b/vcpkg-ports/openssl/windows/portfile.cmake @@ -22,7 +22,7 @@ elseif(VCPKG_TARGET_ARCHITECTURE STREQUAL "arm64") elseif(VCPKG_DETECTED_CMAKE_C_COMPILER_ID MATCHES "Clang") set(OPENSSL_ARCH VC-CLANG-WIN64-CLANGASM-ARM) else() - set(OPENSSL_ARCH VC-WIN64-CLANGASM-ARM) + set(OPENSSL_ARCH VC-WIN64-ARM) endif() else() message(FATAL_ERROR "Unsupported target architecture: ${VCPKG_TARGET_ARCHITECTURE}") diff --git a/vcpkg.json b/vcpkg.json index f217378e7..36c5b76f9 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -12,7 +12,7 @@ "features": { "tests": { "description": "Build tests", "dependencies": ["boost-test"] } }, - "builtin-baseline": "4065f37d0a6628ef17cf6ee15385f9091f1075bc", + "builtin-baseline": "1de2026f28ead93ff1773e6e680387643e914ea1", "vcpkg-configuration": { "overlay-ports": [ "vcpkg-ports/openssl",