diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 03a0c1377..4c59f5594 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -179,6 +179,10 @@ jobs: architecture: ${{ matrix.platform }} - name: Build xsd run: .\prepare_win_build_environment.ps1 -xsd + - name: Install WiX + run: | + dotnet tool install -g wix + wix extension -g add WixToolset.UI.wixext - name: Setup dev env uses: ilammy/msvc-dev-cmd@v1 with: diff --git a/build.ps1 b/build.ps1 index d70bcea53..9b72e3375 100644 --- a/build.ps1 +++ b/build.ps1 @@ -11,10 +11,7 @@ param( [string]$cmake = "cmake.exe", [string]$generator = "NMake Makefiles", [string]$vcvars = "vcvarsall", - [string]$wix = "$env:WIX", - [string]$heat = "$wix\bin\heat.exe", - [string]$candle = "$wix\bin\candle.exe", - [string]$light = "$wix\bin\light.exe", + [string]$wix = "wix.exe", [string]$swig = $null, [string]$doxygen = $null, [switch]$boost = $false, @@ -22,18 +19,21 @@ param( [string]$sign = $null ) +# Hack to fetch heat.exe tool +& dotnet new console -o wix-heat --force +& dotnet add wix-heat package WixToolset.Heat +$heat = Get-ChildItem "$env:USERPROFILE\.nuget\packages\WixToolset.Heat" -Include heat.exe -Recurse + $cmakeext = @() -$candleext = @() -$lightext = @() +$wixext = @() $target = @("all") if($swig) { $cmakeext += "-DSWIG_EXECUTABLE=$swig" - $candleext += "-dswig=$swig" + $wixext += "-d", "swig=$swig" } if($doxygen) { $cmakeext += "-DDOXYGEN_EXECUTABLE=$doxygen" - $candleext += "-ddocLocation=$platform/share/doc/libdigidocpp", "DocFilesFragment.wxs" - $lightext += "DocFilesFragment.wixobj" + $wixext += "-d", "docLocation=$platform/share/doc/libdigidocpp", "DocFilesFragment.wxs" } if($boost) { $cmakeext += "-DVCPKG_MANIFEST_FEATURES=tests" @@ -54,16 +54,21 @@ foreach($type in @("Debug", "RelWithDebInfo")) { } if($doxygen) { - & $heat dir $platform/share/doc/libdigidocpp -nologo -cg Documentation -gg -scom -sreg -sfrag -srd -dr DocumentationFolder -var var.docLocation -out DocFilesFragment.wxs + & $heat[0] dir $platform/share/doc/libdigidocpp -nologo -cg Documentation -gg -scom -sreg -sfrag -srd -dr DocumentationFolder -var var.docLocation -out DocFilesFragment.wxs } -& $heat dir $platform/include -nologo -cg Headers -gg -scom -sreg -sfrag -srd -dr HeadersFolder -var var.headersLocation -out HeadersFragment.wxs -& $candle -nologo -arch $platform "-dICON=$libdigidocpp/cmake/modules/ID.ico" "-dMSI_VERSION=$msiversion" ` - "-dvcpkg=$vcpkg_installed\vcpkg_installed_$platform\$platform-windows" "-dheadersLocation=$platform/include" ` - "-dlibdigidocpp=$platform" $candleext $libdigidocpp\libdigidocpp.wxs HeadersFragment.wxs -& $light -nologo -out $msi_name -ext WixUIExtension ` - "-dWixUIBannerBmp=$libdigidocpp/cmake/modules/banner.bmp" ` - "-dWixUIDialogBmp=$libdigidocpp/cmake/modules/dlgbmp.bmp" ` - $lightext libdigidocpp.wixobj HeadersFragment.wixobj + +& $heat[0] dir $platform/include -nologo -cg Headers -gg -scom -sreg -sfrag -srd -dr HeadersFolder -var var.headersLocation -out HeadersFragment.wxs +& $wix build -nologo -arch $platform -out $msi_name $wixext ` + -ext WixToolset.UI.wixext ` + -bv "WixUIBannerBmp=$libdigidocpp/cmake/modules/banner.bmp" ` + -bv "WixUIDialogBmp=$libdigidocpp/cmake/modules/dlgbmp.bmp" ` + -d "ICON=$libdigidocpp/cmake/modules/ID.ico" ` + -d "MSI_VERSION=$msiversion" ` + -d "vcpkg=$vcpkg_installed/vcpkg_installed_$platform/$platform-windows" ` + -d "libdigidocpp=$platform" ` + -d "headersLocation=$platform/include" ` + HeadersFragment.wxs ` + $libdigidocpp\libdigidocpp.wxs if($sign) { signtool.exe sign /a /v /s MY /n "$sign" /fd SHA256 /du http://installer.id.ee ` diff --git a/cmake b/cmake index 712a5c282..da3cafb07 160000 --- a/cmake +++ b/cmake @@ -1 +1 @@ -Subproject commit 712a5c2828c01282150b657ff6932cc32fc17947 +Subproject commit da3cafb0712eac8fbfddd7d37343016430b65b44 diff --git a/libdigidocpp.wxs b/libdigidocpp.wxs index 0b49336f6..9fa9f7038 100644 --- a/libdigidocpp.wxs +++ b/libdigidocpp.wxs @@ -1,17 +1,14 @@ - - + - - @@ -25,118 +22,117 @@ - - - - - - + + + + + + + "A newer version of [ProductName] is already installed. If you are trying to downgrade, please uninstall the newer version first." /> - - 1 - 1 + + + - - - - - - - - + + + + + + + - + - - - - - - - - - - - + + + + + + + + + + + - - - - + + + + - - - - - - + + + + + + - + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - + + - + - - - + + - - + + - - + + - + - + diff --git a/prepare_win_build_environment.ps1 b/prepare_win_build_environment.ps1 index 76de9cf75..07d778d97 100644 --- a/prepare_win_build_environment.ps1 +++ b/prepare_win_build_environment.ps1 @@ -3,10 +3,11 @@ param( [string]$vcpkg = "vcpkg\vcpkg.exe", [string]$git = "git.exe", [switch]$xsd = $false, + [switch]$wix = $false, [switch]$dependencies = $false ) -function xsd() { +if($xsd) { $client = new-object System.Net.WebClient & mkdir xsd foreach($xsdver in @("xsd-4.2.0-x86_64-windows10", "libxsd-4.2.0-windows")) { @@ -17,8 +18,9 @@ function xsd() { } } -if($xsd) { - xsd +if($wix) { + & dotnet tool install --global wix + & wix extension add -g WixToolset.UI.wixext } if($dependencies) { @@ -31,7 +33,3 @@ if($dependencies) { & $vcpkg install --clean-after-build --triplet x64-windows --x-feature=tests --x-install-root=vcpkg_installed_x64 } -if(!$xsd -and !$dependencies) { - xsd -} - diff --git a/src/SignatureXAdES_B.cpp b/src/SignatureXAdES_B.cpp index 17e64670c..99fbee19f 100644 --- a/src/SignatureXAdES_B.cpp +++ b/src/SignatureXAdES_B.cpp @@ -244,7 +244,7 @@ SignatureXAdES_B::SignatureXAdES_B(unsigned int id, ASiContainer *container, Sig // Signature->SignedInfo auto signedInfo = make_unique( - make_unique(/*URI_ID_EXC_C14N_NOC*/URI_ID_C14N11_NOC), + make_unique(URI_ID_C14N11_NOC), make_unique(X509Crypto(c).isRSAKey() ? Digest::toRsaUri(signer->method()) : Digest::toEcUri(signer->method()))); @@ -291,14 +291,16 @@ SignatureXAdES_B::SignatureXAdES_B(unsigned int id, ASiContainer *container, Sig string digestMethod = Conf::instance()->digestUri(); for(const DataFile *f: bdoc->dataFiles()) { - string referenceId = addReference(File::toUriPath(f->fileName()), digestMethod, f->calcDigest(digestMethod), {}); + string referenceId = addReference(File::toUriPath(f->fileName()), digestMethod, f->calcDigest(digestMethod)); addDataObjectFormat("#" + referenceId, f->mediaType()); } signatures->reloadDOM(); Digest calc(digestMethod); - calcDigestOnNode(&calc, Signatures::XADES_NAMESPACE, u"SignedProperties"); - addReference("#" + nr +"-SignedProperties", calc.uri(), calc.result(), "http://uri.etsi.org/01903#SignedProperties"); + calcDigestOnNode(&calc, Signatures::XADES_NAMESPACE, u"SignedProperties", + signature->signedInfo().canonicalizationMethod().algorithm()); + addReference("#" + nr +"-SignedProperties", calc.uri(), calc.result(), "http://uri.etsi.org/01903#SignedProperties", + signature->signedInfo().canonicalizationMethod().algorithm()); signatures->reloadDOM(); } @@ -543,7 +545,7 @@ void SignatureXAdES_B::validate(const string &policy) const m_errStr.sbXMLChIn((const XMLCh*)u""); if(!DSIGReference::verifyReferenceList(sig->getReferenceList(), m_errStr)) - //if(!sig->verify()) //xml-security-c < 2.0.0 does not support URI_ID_C14N11_NOC canonicalization + //if(!sig->verify()) //xml-security-c does not support URI_RSA_PSS_SHA { //string s = xml::transcode(sig->getErrMsgs()) string s = xml::transcode(m_errStr.rawXMLChBuffer()); @@ -672,7 +674,8 @@ vector SignatureXAdES_B::dataToSign() const { // Calculate SHA digest of the Signature->SignedInfo node. Digest calc(signatureMethod()); - calcDigestOnNode(&calc, URI_ID_DSIG, u"SignedInfo"); + calcDigestOnNode(&calc, URI_ID_DSIG, u"SignedInfo", + signature->signedInfo().canonicalizationMethod().algorithm()); return calc.result(); } @@ -801,15 +804,21 @@ void SignatureXAdES_B::addDataObjectFormat(const string &uri, const string &mime * @throws SignatureException throws exception if the digest method is not supported. */ string SignatureXAdES_B::addReference(const string& uri, const string& digestUri, - const vector &digestValue, const string& type) + const vector &digestValue, const string &type, const string &canon) { auto reference = make_unique(make_unique(digestUri), toBase64(digestValue)); - reference->uRI(uri); + reference->uRI(make_unique(uri)); if(!type.empty()) reference->type(type); + if(!canon.empty()) + { + reference->transforms(make_unique()); + reference->transforms()->transform().push_back(make_unique(canon)); + } + SignedInfoType::ReferenceSequence &seq = signature->signedInfo().reference(); - reference->id(id() + Log::format("-RefId%zu", seq.size())); + reference->id(make_unique(id() + Log::format("-RefId%zu", seq.size()))); seq.push_back(std::move(reference)); return seq.back().id().get(); @@ -994,18 +1003,16 @@ vector SignatureXAdES_B::getSignatureValue() const * @param ns signature tag namespace. * @param tagName signature tag name. */ -void SignatureXAdES_B::calcDigestOnNode(Digest* calc, const string& ns, +void SignatureXAdES_B::calcDigestOnNode(Digest* calc, string_view ns, u16string_view tagName, string_view canonicalizationMethod) const { try { auto *element = signatures->element(id()); - DOMNodeList *nodeList = element->getElementsByTagNameNS(xml::string(ns).c_str(), tagName.data()); + DOMNodeList *nodeList = element->getElementsByTagNameNS(xml::string(ns.data()).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(); + THROW("Could not find '%s' node which is in '%.*s' namespace in signature XML.", + xml::transcode(tagName.data()).c_str(), int(ns.size()), ns.data()); SecureDOMParser::calcDigestOnNode(calc, canonicalizationMethod, nodeList->item(0)); } catch(const Exception& e) diff --git a/src/SignatureXAdES_B.h b/src/SignatureXAdES_B.h index a3b72c95a..77f10e552 100644 --- a/src/SignatureXAdES_B.h +++ b/src/SignatureXAdES_B.h @@ -91,7 +91,7 @@ namespace digidoc std::vector signerRoles() const override; std::string addReference(const std::string& uri, const std::string& digestUri, - const std::vector &digestValue, const std::string& type = {}); + const std::vector &digestValue, const std::string& type = {}, const std::string &canon = {}); void addDataObjectFormat(const std::string& uri, const std::string& mime); std::shared_ptr signatures; @@ -100,8 +100,8 @@ namespace digidoc std::vector getSignatureValue() const; xades::QualifyingPropertiesType& qualifyingProperties() const; xades::SignedSignaturePropertiesType& getSignedSignatureProperties() const; - void calcDigestOnNode(Digest* calc, const std::string& ns, - std::u16string_view tagName, std::string_view canonicalizationMethod = {}) const; + void calcDigestOnNode(Digest* calc, std::string_view ns, + std::u16string_view tagName, std::string_view canonicalizationMethod) const; static void checkCertID(const xades::CertIDType &certID, const X509Cert &cert); static void checkDigest(const xades::DigestAlgAndValueType &digest, const std::vector &data); diff --git a/src/xml/SecureDOMParser.cpp b/src/xml/SecureDOMParser.cpp index 785d8eba6..7733cdfd2 100644 --- a/src/xml/SecureDOMParser.cpp +++ b/src/xml/SecureDOMParser.cpp @@ -91,6 +91,14 @@ SecureDOMParser::SecureDOMParser(const string &schema_location, bool dont_valida void SecureDOMParser::calcDigestOnNode(Digest *calc, string_view algorithmType, DOMNode *node) { + /* + * https://www.w3.org/TR/xmldsig-core1/ + * The Reference Processing Model (section 4.4.3.2 The Reference Processing Model) requires use of + * Canonical XML 1.0 [XML-C14N] as default processing behavior when a transformation is expecting an octet-stream. + */ + if(algorithmType.empty()) + algorithmType = URI_ID_C14N_NOC; + XSECC14n20010315 c14n(node->getOwnerDocument(), node); c14n.setCommentsProcessing(false); c14n.setUseNamespaceStack(true); @@ -113,7 +121,7 @@ void SecureDOMParser::calcDigestOnNode(Digest *calc, c14n.setInclusive11(); c14n.setCommentsProcessing(true); } else { - THROW("Unsupported canonicalization method '%s'", algorithmType.data()); + THROW("Unsupported canonicalization method '%.*s'", int(algorithmType.size()), algorithmType.data()); } array buffer{};