diff options
author | Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk> | 2021-10-27 14:15:17 +0200 |
---|---|---|
committer | Xisco Fauli <xiscofauli@libreoffice.org> | 2021-11-02 12:05:07 +0100 |
commit | 369b883ac9cda5acae77e6df9edc00d1f1213b10 (patch) | |
tree | 42f39c808aa0b28330cb52a6f184e1e2135e86c2 | |
parent | 2dc90967977617f58a9d47e6ae89175919eef4b2 (diff) |
xmlsec: signing the document fails the 3rd time (invalid signature)
Signing the document 3 or more times produces an invalid signature.
The cause of this is that xmlsec is confused because we have 3
signatures, which all have the same SignedProperties with the ID
"idSignedProperties", but it expect them to be unique.
This issue is fixed by making the ID unique with adding the ID of
the Signature to the SignedProperties ID, so this makes them unique
inside the same Signature.
Also UnsignedProperties have a unique ID usign the same approach,
but they aren't referenced - luckily.
Change-Id: I53c7249a82fc0623586548db9fa25bdc0e7c4101
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/124278
Tested-by: Jenkins
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
(cherry picked from commit fd5463343ab7f784070f1ab87a345eed20803d07)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/124197
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
-rw-r--r-- | xmlsecurity/qa/unit/signing/signing.cxx | 136 | ||||
-rw-r--r-- | xmlsecurity/source/helper/documentsignaturehelper.cxx | 2 | ||||
-rw-r--r-- | xmlsecurity/source/helper/ooxmlsecexporter.cxx | 4 | ||||
-rw-r--r-- | xmlsecurity/source/helper/xsecctl.cxx | 23 | ||||
-rw-r--r-- | xmlsecurity/source/helper/xsecsign.cxx | 10 |
5 files changed, 152 insertions, 23 deletions
diff --git a/xmlsecurity/qa/unit/signing/signing.cxx b/xmlsecurity/qa/unit/signing/signing.cxx index 4a726e0d7a2f..293e938863c4 100644 --- a/xmlsecurity/qa/unit/signing/signing.cxx +++ b/xmlsecurity/qa/unit/signing/signing.cxx @@ -980,13 +980,13 @@ CPPUNIT_TEST_FIXTURE(SigningTest, testXAdESNotype) // attribute", i.e. the signature without such an attribute was not preserved correctly. assertXPathNoAttribute(pXmlDoc, "/odfds:document-signatures/dsig:Signature[1]/dsig:SignedInfo/" - "dsig:Reference[@URI='#idSignedProperties']", + "dsig:Reference[starts-with(@URI, '#idSignedProperties')]", "Type"); // New signature always has the Type attribute. assertXPath(pXmlDoc, "/odfds:document-signatures/dsig:Signature[2]/dsig:SignedInfo/" - "dsig:Reference[@URI='#idSignedProperties']", + "dsig:Reference[starts-with(@URI, '#idSignedProperties')]", "Type", "http://uri.etsi.org/01903#SignedProperties"); } @@ -1045,12 +1045,132 @@ CPPUNIT_TEST_FIXTURE(SigningTest, testXAdES) // Assert that the digest of the signing certificate is included. assertXPath(pXmlDoc, "//xd:CertDigest", 1); - // Assert that the Type attribute on the idSignedProperties reference is - // not missing. - assertXPath(pXmlDoc, - "/odfds:document-signatures/dsig:Signature/dsig:SignedInfo/" - "dsig:Reference[@URI='#idSignedProperties']", - "Type", "http://uri.etsi.org/01903#SignedProperties"); + // Assert that the Type attribute is set on all URI's that start with #idSignedProperties + assertXPath(pXmlDoc, "//dsig:Reference[starts-with(@URI, '#idSignedProperties')]", "Type", + "http://uri.etsi.org/01903#SignedProperties"); +} + +CPPUNIT_TEST_FIXTURE(SigningTest, testSigningMultipleTimes_ODT) +{ + createDoc(""); + + utl::TempFile aTempFile; + aTempFile.EnableKillingFile(); + uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("writer8"); + xStorable->storeAsURL(aTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + + DocumentSignatureManager aManager(mxComponentContext, DocumentSignatureMode::Content); + CPPUNIT_ASSERT(aManager.init()); + uno::Reference<embed::XStorage> xStorage + = comphelper::OStorageHelper::GetStorageOfFormatFromURL( + ZIP_STORAGE_FORMAT_STRING, aTempFile.GetURL(), embed::ElementModes::READWRITE); + CPPUNIT_ASSERT(xStorage.is()); + aManager.setStore(xStorage); + aManager.getSignatureHelper().SetStorage(xStorage, "1.2"); + + // Create a signature. + uno::Reference<security::XCertificate> xCertificate + = getCertificate(aManager, svl::crypto::SignatureMethodAlgorithm::RSA); + if (!xCertificate.is()) + return; + sal_Int32 nSecurityId; + aManager.add(xCertificate, mxSecurityContext, /*rDescription=*/OUString(), nSecurityId, + /*bAdESCompliant=*/true); + + // Read back the signature and make sure that it's valid. + aManager.read(/*bUseTempStream=*/true); + { + std::vector<SignatureInformation>& rInformations + = aManager.getCurrentSignatureInformations(); + CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(1), rInformations.size()); + CPPUNIT_ASSERT_EQUAL(css::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED, + rInformations[0].nStatus); + } + + aManager.add(xCertificate, mxSecurityContext, /*rDescription=*/OUString(), nSecurityId, + /*bAdESCompliant=*/true); + aManager.read(/*bUseTempStream=*/true); + { + std::vector<SignatureInformation>& rInformations + = aManager.getCurrentSignatureInformations(); + CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(2), rInformations.size()); + CPPUNIT_ASSERT_EQUAL(css::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED, + rInformations[1].nStatus); + } + + aManager.add(xCertificate, mxSecurityContext, /*rDescription=*/OUString(), nSecurityId, + /*bAdESCompliant=*/true); + aManager.read(/*bUseTempStream=*/true); + { + std::vector<SignatureInformation>& rInformations + = aManager.getCurrentSignatureInformations(); + CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(3), rInformations.size()); + CPPUNIT_ASSERT_EQUAL(css::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED, + rInformations[2].nStatus); + } +} + +CPPUNIT_TEST_FIXTURE(SigningTest, testSigningMultipleTimes_OOXML) +{ + createDoc(""); + + utl::TempFile aTempFile; + aTempFile.EnableKillingFile(); + uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY); + utl::MediaDescriptor aMediaDescriptor; + aMediaDescriptor["FilterName"] <<= OUString("MS Word 2007 XML"); + xStorable->storeAsURL(aTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList()); + + DocumentSignatureManager aManager(mxComponentContext, DocumentSignatureMode::Content); + CPPUNIT_ASSERT(aManager.init()); + uno::Reference<embed::XStorage> xStorage + = comphelper::OStorageHelper::GetStorageOfFormatFromURL( + ZIP_STORAGE_FORMAT_STRING, aTempFile.GetURL(), embed::ElementModes::READWRITE); + CPPUNIT_ASSERT(xStorage.is()); + aManager.setStore(xStorage); + aManager.getSignatureHelper().SetStorage(xStorage, "1.2"); + + // Create a signature. + uno::Reference<security::XCertificate> xCertificate + = getCertificate(aManager, svl::crypto::SignatureMethodAlgorithm::ECDSA); + if (!xCertificate.is()) + return; + + sal_Int32 nSecurityId; + aManager.add(xCertificate, mxSecurityContext, "", nSecurityId, /*bAdESCompliant=*/false); + aManager.read(/*bUseTempStream=*/true); + { + std::vector<SignatureInformation>& rInformations + = aManager.getCurrentSignatureInformations(); + CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(1), rInformations.size()); + CPPUNIT_ASSERT_EQUAL(css::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED, + rInformations[0].nStatus); + } + + aManager.add(xCertificate, mxSecurityContext, "", nSecurityId, /*bAdESCompliant=*/false); + aManager.read(/*bUseTempStream=*/true); + { + std::vector<SignatureInformation>& rInformations + = aManager.getCurrentSignatureInformations(); + CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(2), rInformations.size()); + CPPUNIT_ASSERT_EQUAL(css::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED, + rInformations[1].nStatus); + } + + aManager.add(xCertificate, mxSecurityContext, "", nSecurityId, /*bAdESCompliant=*/false); + aManager.read(/*bUseTempStream=*/true); + { + std::vector<SignatureInformation>& rInformations + = aManager.getCurrentSignatureInformations(); + CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(3), rInformations.size()); + CPPUNIT_ASSERT_EQUAL(css::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED, + rInformations[2].nStatus); + } + aManager.write(/*bXAdESCompliantIfODF=*/true); + uno::Reference<embed::XTransactedObject> xTransactedObject(xStorage, uno::UNO_QUERY); + xTransactedObject->commit(); } /// Works with an existing good XAdES signature. diff --git a/xmlsecurity/source/helper/documentsignaturehelper.cxx b/xmlsecurity/source/helper/documentsignaturehelper.cxx index e05e1ee1aac2..2c0e4da159ee 100644 --- a/xmlsecurity/source/helper/documentsignaturehelper.cxx +++ b/xmlsecurity/source/helper/documentsignaturehelper.cxx @@ -528,7 +528,7 @@ void DocumentSignatureHelper::writeSignedProperties( { { rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList()); - pAttributeList->AddAttribute("Id", "idSignedProperties"); + pAttributeList->AddAttribute("Id", "idSignedProperties_" + signatureInfo.ouSignatureId); xDocumentHandler->startElement("xd:SignedProperties", uno::Reference<xml::sax::XAttributeList>(pAttributeList)); } diff --git a/xmlsecurity/source/helper/ooxmlsecexporter.cxx b/xmlsecurity/source/helper/ooxmlsecexporter.cxx index 324657a96ee0..443266b1a40a 100644 --- a/xmlsecurity/source/helper/ooxmlsecexporter.cxx +++ b/xmlsecurity/source/helper/ooxmlsecexporter.cxx @@ -160,7 +160,7 @@ void OOXMLSecExporter::Impl::writeSignedInfoReferences() { { rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList()); - if (rReference.ouURI != "idSignedProperties") + if (!rReference.ouURI.startsWith("idSignedProperties")) pAttributeList->AddAttribute("Type", "http://www.w3.org/2000/09/xmldsig#Object"); else @@ -170,7 +170,7 @@ void OOXMLSecExporter::Impl::writeSignedInfoReferences() m_xDocumentHandler->startElement( "Reference", uno::Reference<xml::sax::XAttributeList>(pAttributeList)); } - if (rReference.ouURI == "idSignedProperties") + if (rReference.ouURI.startsWith("idSignedProperties")) { m_xDocumentHandler->startElement( "Transforms", diff --git a/xmlsecurity/source/helper/xsecctl.cxx b/xmlsecurity/source/helper/xsecctl.cxx index 8ae170995d19..69099cc59ee4 100644 --- a/xmlsecurity/source/helper/xsecctl.cxx +++ b/xmlsecurity/source/helper/xsecctl.cxx @@ -532,7 +532,7 @@ void writeUnsignedProperties( { { rtl::Reference<SvXMLAttributeList> pAttributeList(new SvXMLAttributeList()); - pAttributeList->AddAttribute("Id", "idUnsignedProperties"); + pAttributeList->AddAttribute("Id", "idUnsignedProperties_" + signatureInfo.ouSignatureId); xDocumentHandler->startElement("xd:UnsignedProperties", uno::Reference<xml::sax::XAttributeList>(pAttributeList)); } @@ -649,16 +649,21 @@ void XSecController::exportSignature( * same-document reference */ { - pAttributeList->AddAttribute( + if (refInfor.ouURI.startsWith("idSignedProperties")) + { + pAttributeList->AddAttribute("URI", "#idSignedProperties_" + signatureInfo.ouSignatureId); + if (bXAdESCompliantIfODF && !refInfor.ouType.isEmpty()) + { + // The reference which points to the SignedProperties + // shall have this specific type. + pAttributeList->AddAttribute("Type", refInfor.ouType); + } + } + else + { + pAttributeList->AddAttribute( "URI", "#" + refInfor.ouURI); - - if (bXAdESCompliantIfODF && refInfor.ouURI == "idSignedProperties" && !refInfor.ouType.isEmpty()) - { - // The reference which points to the SignedProperties - // shall have this specific type. - pAttributeList->AddAttribute("Type", - refInfor.ouType); } } diff --git a/xmlsecurity/source/helper/xsecsign.cxx b/xmlsecurity/source/helper/xsecsign.cxx index 3d9cac6dc485..65c2b62374d9 100644 --- a/xmlsecurity/source/helper/xsecsign.cxx +++ b/xmlsecurity/source/helper/xsecsign.cxx @@ -134,8 +134,9 @@ css::uno::Reference< css::xml::crypto::sax::XReferenceResolvedListener > XSecCon if (bXAdESCompliantIfODF) { + OUString aId = "idSignedProperties_" + internalSignatureInfor.signatureInfor.ouSignatureId; // We write a new reference, so it's possible to use the correct type URI. - internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, "idSignedProperties", -1, "http://uri.etsi.org/01903#SignedProperties"); + internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, aId, -1, "http://uri.etsi.org/01903#SignedProperties"); size++; } @@ -147,13 +148,16 @@ css::uno::Reference< css::xml::crypto::sax::XReferenceResolvedListener > XSecCon size++; } } - else + else // OOXML { + internalSignatureInfor.signatureInfor.ouSignatureId = "idPackageSignature"; + internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, "idPackageObject", -1, OUString()); size++; internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, "idOfficeObject", -1, OUString()); size++; - internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, "idSignedProperties", -1, OUString()); + OUString aId = "idSignedProperties_" + internalSignatureInfor.signatureInfor.ouSignatureId; + internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, aId, -1, OUString()); size++; } |