Kaydet (Commit) f82e3b03 authored tarafından Miklos Vajna's avatar Miklos Vajna Kaydeden (comit) Michael Stahl

tdf#123747 xmlsecurity, ODF sign roundtrip: preserve invalid reference type

Only add the correct type to new signatures to avoid breaking the hash
of old ones.

(cherry picked from commit 8a9d8238)

Conflicts:
	xmlsecurity/qa/unit/signing/signing.cxx

Change-Id: I30f892b292f84a0575a3d4ef5ccf3eddbe0090ca
Reviewed-on: https://gerrit.libreoffice.org/70451
Tested-by: Jenkins
Tested-by: 's avatarXisco Faulí <xiscofauli@libreoffice.org>
Reviewed-by: 's avatarMichael Stahl <Michael.Stahl@cib.de>
üst 99ec13e6
...@@ -48,6 +48,8 @@ struct SignatureReferenceInformation ...@@ -48,6 +48,8 @@ struct SignatureReferenceInformation
// For ODF: XAdES digests (SHA256) or the old SHA1, from css::xml::crypto::DigestID // For ODF: XAdES digests (SHA256) or the old SHA1, from css::xml::crypto::DigestID
sal_Int32 nDigestID; sal_Int32 nDigestID;
OUString ouDigestValue; OUString ouDigestValue;
/// Type of the reference: an URI (newer idSignedProperties references) or empty.
OUString ouType;
SignatureReferenceInformation() : SignatureReferenceInformation() :
nType(SignatureReferenceType::SAMEDOCUMENT), nType(SignatureReferenceType::SAMEDOCUMENT),
...@@ -57,12 +59,13 @@ struct SignatureReferenceInformation ...@@ -57,12 +59,13 @@ struct SignatureReferenceInformation
{ {
} }
SignatureReferenceInformation( SignatureReferenceType type, sal_Int32 digestID, const OUString& uri ) : SignatureReferenceInformation( SignatureReferenceType type, sal_Int32 digestID, const OUString& uri, const OUString& rType ) :
SignatureReferenceInformation() SignatureReferenceInformation()
{ {
nType = type; nType = type;
nDigestID = digestID; nDigestID = digestID;
ouURI = uri; ouURI = uri;
ouType = rType;
} }
}; };
......
...@@ -89,10 +89,10 @@ public: ...@@ -89,10 +89,10 @@ public:
xReferenceResolvedListener = xListener; xReferenceResolvedListener = xListener;
} }
void addReference( SignatureReferenceType type, sal_Int32 digestID, const OUString& uri, sal_Int32 keeperId ) void addReference( SignatureReferenceType type, sal_Int32 digestID, const OUString& uri, sal_Int32 keeperId, const OUString& rType )
{ {
signatureInfor.vSignatureReferenceInfors.push_back( signatureInfor.vSignatureReferenceInfors.push_back(
SignatureReferenceInformation(type, digestID, uri)); SignatureReferenceInformation(type, digestID, uri, rType));
vKeeperIds.push_back( keeperId ); vKeeperIds.push_back( keeperId );
} }
}; };
...@@ -261,7 +261,8 @@ private: ...@@ -261,7 +261,8 @@ private:
void switchGpgSignature(); void switchGpgSignature();
void addReference( void addReference(
const OUString& ouUri, const OUString& ouUri,
sal_Int32 nDigestID ); sal_Int32 nDigestID,
const OUString& ouType );
void addStreamReference( void addStreamReference(
const OUString& ouUri, const OUString& ouUri,
bool isBinary, bool isBinary,
......
...@@ -101,6 +101,7 @@ public: ...@@ -101,6 +101,7 @@ public:
#endif #endif
void test96097Calc(); void test96097Calc();
void test96097Doc(); void test96097Doc();
void testXAdESNotype();
/// Creates a XAdES signature from scratch. /// Creates a XAdES signature from scratch.
void testXAdES(); void testXAdES();
/// Works with an existing good XAdES signature. /// Works with an existing good XAdES signature.
...@@ -144,6 +145,7 @@ public: ...@@ -144,6 +145,7 @@ public:
#endif #endif
CPPUNIT_TEST(test96097Calc); CPPUNIT_TEST(test96097Calc);
CPPUNIT_TEST(test96097Doc); CPPUNIT_TEST(test96097Doc);
CPPUNIT_TEST(testXAdESNotype);
CPPUNIT_TEST(testXAdES); CPPUNIT_TEST(testXAdES);
CPPUNIT_TEST(testXAdESGood); CPPUNIT_TEST(testXAdESGood);
CPPUNIT_TEST(testSignatureLineOOXML); CPPUNIT_TEST(testSignatureLineOOXML);
...@@ -781,6 +783,65 @@ void SigningTest::test96097Doc() ...@@ -781,6 +783,65 @@ void SigningTest::test96097Doc()
} }
} }
void SigningTest::testXAdESNotype()
{
// Create a working copy.
utl::TempFile aTempFile;
aTempFile.EnableKillingFile();
OUString aURL = aTempFile.GetURL();
CPPUNIT_ASSERT_EQUAL(
osl::File::RC::E_None,
osl::File::copy(m_directories.getURLFromSrc(DATA_DIRECTORY) + "notype-xades.odt", aURL));
// Read existing signature.
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.mxStore = xStorage;
aManager.maSignatureHelper.SetStorage(xStorage, "1.2");
aManager.read(/*bUseTempStream=*/false);
// Create a new 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);
// Write to storage.
aManager.read(/*bUseTempStream=*/true);
aManager.write(/*bXAdESCompliantIfODF=*/true);
uno::Reference<embed::XTransactedObject> xTransactedObject(xStorage, uno::UNO_QUERY);
xTransactedObject->commit();
// Parse the resulting XML.
uno::Reference<embed::XStorage> xMetaInf
= xStorage->openStorageElement("META-INF", embed::ElementModes::READ);
uno::Reference<io::XInputStream> xInputStream(
xMetaInf->openStreamElement("documentsignatures.xml", embed::ElementModes::READ),
uno::UNO_QUERY);
std::shared_ptr<SvStream> pStream(utl::UcbStreamHelper::CreateStream(xInputStream, true));
xmlDocPtr pXmlDoc = parseXmlStream(pStream.get());
// Without the accompanying fix in place, this test would have failed with "unexpected 'Type'
// 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']",
"Type");
// New signature always has the Type attribute.
assertXPath(pXmlDoc,
"/odfds:document-signatures/dsig:Signature[2]/dsig:SignedInfo/"
"dsig:Reference[@URI='#idSignedProperties']",
"Type", "http://uri.etsi.org/01903#SignedProperties");
}
void SigningTest::testXAdES() void SigningTest::testXAdES()
{ {
// Create an empty document, store it to a tempfile and load it as a storage. // Create an empty document, store it to a tempfile and load it as a storage.
......
...@@ -72,7 +72,7 @@ void SAL_CALL OOXMLSecParser::startElement(const OUString& rName, const uno::Ref ...@@ -72,7 +72,7 @@ void SAL_CALL OOXMLSecParser::startElement(const OUString& rName, const uno::Ref
{ {
OUString aURI = xAttribs->getValueByName("URI"); OUString aURI = xAttribs->getValueByName("URI");
if (aURI.startsWith("#")) if (aURI.startsWith("#"))
m_pXSecController->addReference(aURI.copy(1), xml::crypto::DigestID::SHA1); m_pXSecController->addReference(aURI.copy(1), xml::crypto::DigestID::SHA1, OUString());
else else
{ {
m_aReferenceURI = aURI; m_aReferenceURI = aURI;
......
...@@ -662,12 +662,12 @@ void XSecController::exportSignature( ...@@ -662,12 +662,12 @@ void XSecController::exportSignature(
"URI", "URI",
"#" + refInfor.ouURI); "#" + refInfor.ouURI);
if (bXAdESCompliantIfODF && refInfor.ouURI == "idSignedProperties") if (bXAdESCompliantIfODF && refInfor.ouURI == "idSignedProperties" && !refInfor.ouType.isEmpty())
{ {
// The reference which points to the SignedProperties // The reference which points to the SignedProperties
// shall have this specific type. // shall have this specific type.
pAttributeList->AddAttribute("Type", pAttributeList->AddAttribute("Type",
"http://uri.etsi.org/01903#SignedProperties"); refInfor.ouType);
} }
} }
......
...@@ -129,12 +129,14 @@ void SAL_CALL XSecParser::startElement( ...@@ -129,12 +129,14 @@ void SAL_CALL XSecParser::startElement(
{ {
OUString ouUri = xAttribs->getValueByName("URI"); OUString ouUri = xAttribs->getValueByName("URI");
SAL_WARN_IF( ouUri.isEmpty(), "xmlsecurity.helper", "URI is empty" ); SAL_WARN_IF( ouUri.isEmpty(), "xmlsecurity.helper", "URI is empty" );
// Remember the type of this reference.
OUString ouType = xAttribs->getValueByName("Type");
if (ouUri.startsWith("#")) if (ouUri.startsWith("#"))
{ {
/* /*
* remove the first character '#' from the attribute value * remove the first character '#' from the attribute value
*/ */
m_pXSecController->addReference( ouUri.copy(1), m_nReferenceDigestID ); m_pXSecController->addReference( ouUri.copy(1), m_nReferenceDigestID, ouType );
} }
else else
{ {
......
...@@ -138,12 +138,13 @@ cssu::Reference< cssxc::sax::XReferenceResolvedListener > XSecController::prepar ...@@ -138,12 +138,13 @@ cssu::Reference< cssxc::sax::XReferenceResolvedListener > XSecController::prepar
{ {
internalSignatureInfor.signatureInfor.ouSignatureId = createId(); internalSignatureInfor.signatureInfor.ouSignatureId = createId();
internalSignatureInfor.signatureInfor.ouPropertyId = createId(); internalSignatureInfor.signatureInfor.ouPropertyId = createId();
internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, internalSignatureInfor.signatureInfor.ouPropertyId, -1 ); internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, internalSignatureInfor.signatureInfor.ouPropertyId, -1, OUString() );
size++; size++;
if (bXAdESCompliantIfODF) if (bXAdESCompliantIfODF)
{ {
internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, "idSignedProperties", -1); // 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");
size++; size++;
} }
...@@ -151,17 +152,17 @@ cssu::Reference< cssxc::sax::XReferenceResolvedListener > XSecController::prepar ...@@ -151,17 +152,17 @@ cssu::Reference< cssxc::sax::XReferenceResolvedListener > XSecController::prepar
{ {
// Only mention the hash of the description in the signature if it's non-empty. // Only mention the hash of the description in the signature if it's non-empty.
internalSignatureInfor.signatureInfor.ouDescriptionPropertyId = createId(); internalSignatureInfor.signatureInfor.ouDescriptionPropertyId = createId();
internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, internalSignatureInfor.signatureInfor.ouDescriptionPropertyId, -1); internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, internalSignatureInfor.signatureInfor.ouDescriptionPropertyId, -1, OUString());
size++; size++;
} }
} }
else else
{ {
internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, "idPackageObject", -1); internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, "idPackageObject", -1, OUString());
size++; size++;
internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, "idOfficeObject", -1); internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, "idOfficeObject", -1, OUString());
size++; size++;
internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, "idSignedProperties", -1); internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, "idSignedProperties", -1, OUString());
size++; size++;
} }
...@@ -189,7 +190,7 @@ void XSecController::signAStream( sal_Int32 securityId, const OUString& uri, boo ...@@ -189,7 +190,7 @@ void XSecController::signAStream( sal_Int32 securityId, const OUString& uri, boo
if (index == -1) if (index == -1)
{ {
InternalSignatureInformation isi(securityId, nullptr); InternalSignatureInformation isi(securityId, nullptr);
isi.addReference(type, digestID, uri, -1); isi.addReference(type, digestID, uri, -1, OUString());
m_vInternalSignatureInformations.push_back( isi ); m_vInternalSignatureInformations.push_back( isi );
} }
else else
...@@ -197,7 +198,7 @@ void XSecController::signAStream( sal_Int32 securityId, const OUString& uri, boo ...@@ -197,7 +198,7 @@ void XSecController::signAStream( sal_Int32 securityId, const OUString& uri, boo
// use sha512 for gpg signing unconditionally // use sha512 for gpg signing unconditionally
if (!m_vInternalSignatureInformations[index].signatureInfor.ouGpgCertificate.isEmpty()) if (!m_vInternalSignatureInformations[index].signatureInfor.ouGpgCertificate.isEmpty())
digestID = cssxc::DigestID::SHA512; digestID = cssxc::DigestID::SHA512;
m_vInternalSignatureInformations[index].addReference(type, digestID, uri, -1); m_vInternalSignatureInformations[index].addReference(type, digestID, uri, -1, OUString());
} }
} }
......
...@@ -148,7 +148,7 @@ void XSecController::switchGpgSignature() ...@@ -148,7 +148,7 @@ void XSecController::switchGpgSignature()
#endif #endif
} }
void XSecController::addReference( const OUString& ouUri, sal_Int32 nDigestID ) void XSecController::addReference( const OUString& ouUri, sal_Int32 nDigestID, const OUString& ouType )
{ {
if (m_vInternalSignatureInformations.empty()) if (m_vInternalSignatureInformations.empty())
{ {
...@@ -156,7 +156,7 @@ void XSecController::addReference( const OUString& ouUri, sal_Int32 nDigestID ) ...@@ -156,7 +156,7 @@ void XSecController::addReference( const OUString& ouUri, sal_Int32 nDigestID )
return; return;
} }
InternalSignatureInformation &isi = m_vInternalSignatureInformations.back(); InternalSignatureInformation &isi = m_vInternalSignatureInformations.back();
isi.addReference(SignatureReferenceType::SAMEDOCUMENT, nDigestID, ouUri, -1 ); isi.addReference(SignatureReferenceType::SAMEDOCUMENT, nDigestID, ouUri, -1, ouType );
} }
void XSecController::addStreamReference( void XSecController::addStreamReference(
...@@ -189,7 +189,7 @@ void XSecController::addStreamReference( ...@@ -189,7 +189,7 @@ void XSecController::addStreamReference(
} }
} }
isi.addReference(type, nDigestID, ouUri, -1); isi.addReference(type, nDigestID, ouUri, -1, OUString());
} }
void XSecController::setReferenceCount() const void XSecController::setReferenceCount() const
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment