diff options
18 files changed, 201 insertions, 62 deletions
diff --git a/xmlsecurity/inc/digitalsignaturesdialog.hxx b/xmlsecurity/inc/digitalsignaturesdialog.hxx index f58dccf995be..c9226e676989 100644 --- a/xmlsecurity/inc/digitalsignaturesdialog.hxx +++ b/xmlsecurity/inc/digitalsignaturesdialog.hxx @@ -70,6 +70,8 @@ private: VclPtr<FixedImage> m_pSigsOldSignatureImg; VclPtr<FixedText> m_pSigsOldSignatureFI; + VclPtr<CheckBox> m_pXAdESCompliantCB; + VclPtr<PushButton> m_pViewBtn; VclPtr<PushButton> m_pAddBtn; VclPtr<PushButton> m_pRemoveBtn; @@ -82,6 +84,9 @@ private: bool m_bHasDocumentSignature; bool m_bWarningShowSignMacro; + bool m_bXAdESCompliant; + + DECL_LINK(XAdESCompliantCheckBoxHdl, CheckBox&, void); DECL_LINK(ViewButtonHdl, Button*, void); DECL_LINK(AddButtonHdl, Button*, void); DECL_LINK(RemoveButtonHdl, Button*, void); @@ -90,7 +95,7 @@ private: DECL_LINK(StartVerifySignatureHdl, LinkParamNone*, bool ); DECL_LINK(OKButtonHdl, Button*, void ); - void ImplGetSignatureInformations(bool bUseTempStream, bool bCacheLastSignature = true); + void ImplGetSignatureInformations(bool bUseTempStream, bool bCacheLastSignature); void ImplFillSignaturesBox(); void ImplShowSignaturesDetails(); diff --git a/xmlsecurity/inc/documentsignaturemanager.hxx b/xmlsecurity/inc/documentsignaturemanager.hxx index 097c0e144803..fd981d7d98b5 100644 --- a/xmlsecurity/inc/documentsignaturemanager.hxx +++ b/xmlsecurity/inc/documentsignaturemanager.hxx @@ -57,7 +57,7 @@ public: bool isXML(const OUString& rURI); SignatureStreamHelper ImplOpenSignatureStream(sal_Int32 eStreamMode, bool bTempStream); /// Add a new signature, using xCert as a signing certificate, and rDescription as description. - bool add(const css::uno::Reference<css::security::XCertificate>& xCert, const OUString& rDescription, sal_Int32& nSecurityId); + bool add(const css::uno::Reference<css::security::XCertificate>& xCert, const OUString& rDescription, sal_Int32& nSecurityId, bool bXAdESCompliantIfODF); /// Remove signature at nPosition. void remove(sal_uInt16 nPosition); /// Read signatures from either a temp stream or the real storage. @@ -66,6 +66,10 @@ public: void write(); /// Lazy creation of PDF helper. PDFSignatureHelper& getPDFSignatureHelper(); +#if 0 + // Checks if the document is a kind where it is relevant to distinguish between using XAdES or not + bool IsXAdESRelevant(); +#endif }; #endif // INCLUDED_XMLSECURITY_INC_DOCUMENTSIGNATUREMANAGER_HXX diff --git a/xmlsecurity/inc/sigstruct.hxx b/xmlsecurity/inc/sigstruct.hxx index 610845cb0ae2..e662d36cb4a8 100644 --- a/xmlsecurity/inc/sigstruct.hxx +++ b/xmlsecurity/inc/sigstruct.hxx @@ -23,6 +23,7 @@ #include <rtl/ustring.hxx> #include <com/sun/star/util/DateTime.hpp> #include <com/sun/star/xml/crypto/SecurityOperationStatus.hpp> +#include <com/sun/star/xml/crypto/DigestID.hpp> #include <com/sun/star/uno/Sequence.hxx> #include <vector> @@ -41,11 +42,23 @@ struct SignatureReferenceInformation { SignatureReferenceType nType; OUString ouURI; + // For ODF: XAdES digests (SHA256) or the old SHA1, from css::xml::crypto::DigestID + sal_Int32 nDigestID; OUString ouDigestValue; - SignatureReferenceInformation( SignatureReferenceType type, const OUString& uri ) + SignatureReferenceInformation() : + nType(SignatureReferenceType::SAMEDOCUMENT), + ouURI(""), + nDigestID(css::xml::crypto::DigestID::SHA1), + ouDigestValue("") + { + } + + SignatureReferenceInformation( SignatureReferenceType type, sal_Int32 digestID, const OUString& uri ) : + SignatureReferenceInformation() { nType = type; + nDigestID = digestID; ouURI = uri; } }; @@ -57,6 +70,8 @@ struct SignatureInformation sal_Int32 nSecurityId; sal_Int32 nSecurityEnvironmentIndex; css::xml::crypto::SecurityOperationStatus nStatus; + // For ODF: XAdES digests (SHA256) or the old SHA1, from css::xml::crypto::DigestID + sal_Int32 nDigestID; SignatureReferenceInformations vSignatureReferenceInfors; OUString ouX509IssuerName; OUString ouX509SerialNumber; diff --git a/xmlsecurity/inc/xmlsignaturehelper.hxx b/xmlsecurity/inc/xmlsignaturehelper.hxx index 3ff3a9cfc385..8e0c65809e7b 100644 --- a/xmlsecurity/inc/xmlsignaturehelper.hxx +++ b/xmlsecurity/inc/xmlsignaturehelper.hxx @@ -172,8 +172,8 @@ public: void SetDateTime( sal_Int32 nSecurityId, const Date& rDate, const tools::Time& rTime ); void SetDescription(sal_Int32 nSecurityId, const OUString& rDescription); - void AddForSigning( sal_Int32 securityId, const OUString& uri, const OUString& objectURL, bool bBinary ); - bool CreateAndWriteSignature( const css::uno::Reference< css::xml::sax::XDocumentHandler >& xDocumentHandler ); + void AddForSigning( sal_Int32 securityId, const OUString& uri, const OUString& objectURL, bool bBinary, bool bXAdESCompliantIfODF ); + bool CreateAndWriteSignature( const css::uno::Reference< css::xml::sax::XDocumentHandler >& xDocumentHandler, bool bXAdESCompliantIfODF ); bool ReadAndVerifySignature( const css::uno::Reference< css::io::XInputStream >& xInputStream ); // MT: ??? I think only for adding/removing, not for new signatures... diff --git a/xmlsecurity/qa/unit/signing/signing.cxx b/xmlsecurity/qa/unit/signing/signing.cxx index d6833b44bb16..847ef9aea8fe 100644 --- a/xmlsecurity/qa/unit/signing/signing.cxx +++ b/xmlsecurity/qa/unit/signing/signing.cxx @@ -202,7 +202,7 @@ void SigningTest::testDescription() CPPUNIT_ASSERT(xCertificate.is()); OUString aDescription("SigningTest::testDescription"); sal_Int32 nSecurityId; - aManager.add(xCertificate, aDescription, nSecurityId); + aManager.add(xCertificate, aDescription, nSecurityId, false); // Read back the signature and make sure that the description survives the roundtrip. aManager.read(/*bUseTempStream=*/true); @@ -235,7 +235,7 @@ void SigningTest::testOOXMLDescription() CPPUNIT_ASSERT(xCertificate.is()); OUString aDescription("SigningTest::testDescription"); sal_Int32 nSecurityId; - aManager.add(xCertificate, aDescription, nSecurityId); + aManager.add(xCertificate, aDescription, nSecurityId, false); // Read back the signature and make sure that the description survives the roundtrip. aManager.read(/*bUseTempStream=*/true); @@ -267,7 +267,7 @@ void SigningTest::testOOXMLAppend() uno::Reference<security::XCertificate> xCertificate = getCertificate(aManager.maSignatureHelper); CPPUNIT_ASSERT(xCertificate.is()); sal_Int32 nSecurityId; - aManager.add(xCertificate, OUString(), nSecurityId); + aManager.add(xCertificate, OUString(), nSecurityId, false); // Read back the signatures and make sure that we have the expected amount. aManager.read(/*bUseTempStream=*/true); diff --git a/xmlsecurity/source/component/documentdigitalsignatures.cxx b/xmlsecurity/source/component/documentdigitalsignatures.cxx index 08da227b3ebd..4320a88dc59e 100644 --- a/xmlsecurity/source/component/documentdigitalsignatures.cxx +++ b/xmlsecurity/source/component/documentdigitalsignatures.cxx @@ -57,6 +57,10 @@ DocumentDigitalSignatures::DocumentDigitalSignatures( const Reference< XComponen { } +DocumentDigitalSignatures::~DocumentDigitalSignatures() +{ +} + void DocumentDigitalSignatures::initialize( const Sequence< Any >& aArguments) throw (css::uno::Exception, css::uno::RuntimeException, std::exception) { diff --git a/xmlsecurity/source/component/documentdigitalsignatures.hxx b/xmlsecurity/source/component/documentdigitalsignatures.hxx index bd07304ed20c..8f6515c9d570 100644 --- a/xmlsecurity/source/component/documentdigitalsignatures.hxx +++ b/xmlsecurity/source/component/documentdigitalsignatures.hxx @@ -45,7 +45,9 @@ class DocumentDigitalSignatures : public cppu::WeakImplHelper { private: css::uno::Reference< css::uno::XComponentContext > mxCtx; - // will be set by XInitialization. If not we assume true. false means an earlier version. + // will be set by XInitialization. If not we assume true. false means an earlier version (whatever that means, + // this is a string, not a boolean). + // Note that the code talks about "ODF version" even if this class is also used to sign OOXML. OUString m_sODFVersion; //The number of arguments which were passed in XInitialization::initialize int m_nArgumentsCount; @@ -58,6 +60,7 @@ private: public: explicit DocumentDigitalSignatures( const css::uno::Reference< css::uno::XComponentContext>& rxCtx ); + virtual ~DocumentDigitalSignatures() override; // for service registration... static OUString GetImplementationName() throw (css::uno::RuntimeException); diff --git a/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx b/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx index f6bddb69d502..5d8ab1d38849 100644 --- a/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx +++ b/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx @@ -116,6 +116,7 @@ DigitalSignaturesDialog::DigitalSignaturesDialog( get(m_pHintDocFT, "dochint"); get(m_pHintBasicFT, "macrohint"); get(m_pHintPackageFT, "packagehint"); + get(m_pXAdESCompliantCB, "xadescompliant"); get(m_pViewBtn, "view"); get(m_pAddBtn, "sign"); get(m_pRemoveBtn, "remove"); @@ -129,6 +130,8 @@ DigitalSignaturesDialog::DigitalSignaturesDialog( get(m_pSigsOldSignatureImg, "oldsignatureimg"); get(m_pSigsOldSignatureFI, "oldsignatureft"); + m_bXAdESCompliant = !DocumentSignatureHelper::isODFPre_1_2(m_sODFVersion); + Size aControlSize(275, 109); const long nControlWidth = aControlSize.Width(); aControlSize = LogicToPixel(aControlSize, MapUnit::MapAppFont); @@ -151,6 +154,9 @@ DigitalSignaturesDialog::DigitalSignaturesDialog( m_pSignaturesLB->SetSelectHdl( LINK( this, DigitalSignaturesDialog, SignatureHighlightHdl ) ); m_pSignaturesLB->SetDoubleClickHdl( LINK( this, DigitalSignaturesDialog, SignatureSelectHdl ) ); + m_pXAdESCompliantCB->SetToggleHdl( LINK( this, DigitalSignaturesDialog, XAdESCompliantCheckBoxHdl ) ); + m_pXAdESCompliantCB->Check(m_bXAdESCompliant); + m_pViewBtn->SetClickHdl( LINK( this, DigitalSignaturesDialog, ViewButtonHdl ) ); m_pViewBtn->Disable(); @@ -196,6 +202,7 @@ void DigitalSignaturesDialog::dispose() m_pSigsNotvalidatedFI.clear(); m_pSigsOldSignatureImg.clear(); m_pSigsOldSignatureFI.clear(); + m_pXAdESCompliantCB.clear(); m_pViewBtn.clear(); m_pAddBtn.clear(); m_pRemoveBtn.clear(); @@ -315,9 +322,24 @@ short DigitalSignaturesDialog::Execute() { // Verify Signatures and add certificates to ListBox... mbVerifySignatures = true; - ImplGetSignatureInformations(false); + ImplGetSignatureInformations(/*bUseTempStream=*/false, /*bCacheLastSignature=*/true); ImplFillSignaturesBox(); + // FIXME: Disable the "Use XAdES compliant signatures" checkbox if it is irrelevant. If it is + // enabled, set its initial state based on existing signatures, if any. + + // If it is OOXML, the checkbox is irrelevant. + + // How to find out here whether it is OOXML? I don't want to create a SignatureStreamHelper and + // check its nStorageFormat as that seems overly complicated and seems to have weird indirect + // consequences, as I noticed when I tried to use DocumentSignatureManager::IsXAdESRelevant() + // (which now is in #if 0). + + if (maSignatureManager.maCurrentSignatureInformations.size() > 0) + { + // If the document has only SHA-1 signatures we probably want it to stay that way? + } + // Only verify once, content will not change. // But for refreshing signature information, StartVerifySignatureHdl will be called after each add/remove mbVerifySignatures = false; @@ -346,6 +368,11 @@ IMPL_LINK_NOARG(DigitalSignaturesDialog, SignatureSelectHdl, SvTreeListBox*, boo return false; } +IMPL_LINK_NOARG(DigitalSignaturesDialog, XAdESCompliantCheckBoxHdl, CheckBox&, void) +{ + m_bXAdESCompliant = m_pXAdESCompliantCB->IsChecked(); +} + IMPL_LINK_NOARG(DigitalSignaturesDialog, ViewButtonHdl, Button*, void) { ImplShowSignaturesDetails(); @@ -363,7 +390,7 @@ IMPL_LINK_NOARG(DigitalSignaturesDialog, AddButtonHdl, Button*, void) if ( aChooser->Execute() == RET_OK ) { sal_Int32 nSecurityId; - if (!maSignatureManager.add(aChooser->GetSelectedCertificate(), aChooser->GetDescription(), nSecurityId)) + if (!maSignatureManager.add(aChooser->GetSelectedCertificate(), aChooser->GetDescription(), nSecurityId, m_bXAdESCompliant)) return; mbSignaturesChanged = true; @@ -382,7 +409,7 @@ IMPL_LINK_NOARG(DigitalSignaturesDialog, AddButtonHdl, Button*, void) // will not contain // SecurityOperationStatus_OPERATION_SUCCEEDED mbVerifySignatures = true; - ImplGetSignatureInformations(true, /*bCacheLastSignature=*/false); + ImplGetSignatureInformations(/*bUseTempStream=*/true, /*bCacheLastSignature=*/false); ImplFillSignaturesBox(); } } @@ -391,7 +418,7 @@ IMPL_LINK_NOARG(DigitalSignaturesDialog, AddButtonHdl, Button*, void) { OSL_FAIL( "Exception while adding a signature!" ); // Don't keep invalid entries... - ImplGetSignatureInformations(true, /*bCacheLastSignature=*/false); + ImplGetSignatureInformations(/*bUseTempStream=*/true, /*bCacheLastSignature=*/false); ImplFillSignaturesBox(); } } @@ -415,7 +442,7 @@ IMPL_LINK_NOARG(DigitalSignaturesDialog, RemoveButtonHdl, Button*, void) { OSL_FAIL( "Exception while removing a signature!" ); // Don't keep invalid entries... - ImplGetSignatureInformations(true); + ImplGetSignatureInformations(/*bUseTempStream=*/true, /*bCacheLastSignature=*/true); ImplFillSignaturesBox(); } } diff --git a/xmlsecurity/source/helper/documentsignaturemanager.cxx b/xmlsecurity/source/helper/documentsignaturemanager.cxx index 3e33e100e2f2..b88714f9c54b 100644 --- a/xmlsecurity/source/helper/documentsignaturemanager.cxx +++ b/xmlsecurity/source/helper/documentsignaturemanager.cxx @@ -58,6 +58,28 @@ PDFSignatureHelper& DocumentSignatureManager::getPDFSignatureHelper() return *mpPDFSignatureHelper; } +#if 0 // For some reason does not work +bool DocumentSignatureManager::IsXAdESRelevant() +{ + if (mxStore.is()) + { + // ZIP-based: ODF or OOXML. + maSignatureHelper.StartMission(); + + SignatureStreamHelper aStreamHelper = ImplOpenSignatureStream(embed::ElementModes::READ, /*bUseTempStream=*/true); + if (aStreamHelper.nStorageFormat == embed::StorageFormats::OFOPXML) + { + maSignatureHelper.EndMission(); + return false; + } + // FIXME: How to figure out if it is ODF 1.2? + maSignatureHelper.EndMission(); + return true; + } + return false; +} +#endif + /* Using the zip storage, we cannot get the properties "MediaType" and "IsEncrypted" We use the manifest to find out if a file is xml and if it is encrypted. The parameter is an encoded uri. However, the manifest contains paths. Therefore @@ -193,7 +215,7 @@ SignatureStreamHelper DocumentSignatureManager::ImplOpenSignatureStream(sal_Int3 return aHelper; } -bool DocumentSignatureManager::add(const uno::Reference<security::XCertificate>& xCert, const OUString& rDescription, sal_Int32& nSecurityId) +bool DocumentSignatureManager::add(const uno::Reference<security::XCertificate>& xCert, const OUString& rDescription, sal_Int32& nSecurityId, bool bXAdESCompliantIfODF) { if (!xCert.is()) { @@ -250,7 +272,7 @@ bool DocumentSignatureManager::add(const uno::Reference<security::XCertificate>& for (sal_Int32 n = 0; n < nElements; n++) { bool bBinaryMode = !isXML(aElements[n]); - maSignatureHelper.AddForSigning(nSecurityId, aElements[n], aElements[n], bBinaryMode); + maSignatureHelper.AddForSigning(nSecurityId, aElements[n], aElements[n], bBinaryMode, bXAdESCompliantIfODF); } maSignatureHelper.SetDateTime(nSecurityId, Date(Date::SYSTEM), tools::Time(tools::Time::SYSTEM)); @@ -275,7 +297,7 @@ bool DocumentSignatureManager::add(const uno::Reference<security::XCertificate>& XMLSignatureHelper::ExportSignature(xDocumentHandler, maCurrentSignatureInformations[n]); // Create a new one... - maSignatureHelper.CreateAndWriteSignature(xDocumentHandler); + maSignatureHelper.CreateAndWriteSignature(xDocumentHandler, bXAdESCompliantIfODF); // That's it... XMLSignatureHelper::CloseDocumentHandler(xDocumentHandler); diff --git a/xmlsecurity/source/helper/ooxmlsecparser.cxx b/xmlsecurity/source/helper/ooxmlsecparser.cxx index cc764b69b0be..8535c8279c49 100644 --- a/xmlsecurity/source/helper/ooxmlsecparser.cxx +++ b/xmlsecurity/source/helper/ooxmlsecparser.cxx @@ -59,7 +59,7 @@ throw (xml::sax::SAXException, uno::RuntimeException, std::exception) { OUString aURI = xAttribs->getValueByName("URI"); if (aURI.startsWith("#")) - m_pXSecController->addReference(aURI.copy(1)); + m_pXSecController->addReference(aURI.copy(1), xml::crypto::DigestID::SHA1); else { m_aReferenceURI = aURI; @@ -73,7 +73,7 @@ throw (xml::sax::SAXException, uno::RuntimeException, std::exception) OUString aAlgorithm = xAttribs->getValueByName("Algorithm"); if (aAlgorithm == ALGO_RELATIONSHIP) { - m_pXSecController->addStreamReference(m_aReferenceURI, /*isBinary=*/false); + m_pXSecController->addStreamReference(m_aReferenceURI, /*isBinary=*/false, /*nDigestID=*/xml::crypto::DigestID::SHA256); m_bReferenceUnresolved = false; } } @@ -132,10 +132,10 @@ void SAL_CALL OOXMLSecParser::endElement(const OUString& rName) throw (xml::sax: if (m_bReferenceUnresolved) { // No transform algorithm found, assume binary. - m_pXSecController->addStreamReference(m_aReferenceURI, /*isBinary=*/true); + m_pXSecController->addStreamReference(m_aReferenceURI, /*isBinary=*/true, /*nDigestID=*/xml::crypto::DigestID::SHA256); m_bReferenceUnresolved = false; } - m_pXSecController->setDigestValue(m_aDigestValue); + m_pXSecController->setDigestValue(xml::crypto::DigestID::SHA256, m_aDigestValue); } else if (rName == "DigestValue" && !m_bInCertDigest) m_bInDigestValue = false; diff --git a/xmlsecurity/source/helper/xmlsignaturehelper.cxx b/xmlsecurity/source/helper/xmlsignaturehelper.cxx index 7267e5f3b840..c3106332dac7 100644 --- a/xmlsecurity/source/helper/xmlsignaturehelper.cxx +++ b/xmlsecurity/source/helper/xmlsignaturehelper.cxx @@ -145,9 +145,9 @@ void XMLSignatureHelper::SetDescription(sal_Int32 nSecurityId, const OUString& r mpXSecController->setDescription(nSecurityId, rDescription); } -void XMLSignatureHelper::AddForSigning( sal_Int32 nSecurityId, const OUString& uri, const OUString& objectURL, bool bBinary ) +void XMLSignatureHelper::AddForSigning( sal_Int32 nSecurityId, const OUString& uri, const OUString& objectURL, bool bBinary, bool bXAdESCompliantIfODF ) { - mpXSecController->signAStream( nSecurityId, uri, objectURL, bBinary ); + mpXSecController->signAStream( nSecurityId, uri, objectURL, bBinary, bXAdESCompliantIfODF ); } @@ -221,11 +221,11 @@ void XMLSignatureHelper::ExportOOXMLSignature(const uno::Reference<embed::XStora } } -bool XMLSignatureHelper::CreateAndWriteSignature( const uno::Reference< xml::sax::XDocumentHandler >& xDocumentHandler ) +bool XMLSignatureHelper::CreateAndWriteSignature( const uno::Reference< xml::sax::XDocumentHandler >& xDocumentHandler, bool bXAdESCompliantIfODF ) { mbError = false; - if ( !mpXSecController->WriteSignature( xDocumentHandler ) ) + if ( !mpXSecController->WriteSignature( xDocumentHandler, bXAdESCompliantIfODF ) ) { mbError = true; } diff --git a/xmlsecurity/source/helper/xsecctl.cxx b/xmlsecurity/source/helper/xsecctl.cxx index d4467a929e8f..380adf7e905b 100644 --- a/xmlsecurity/source/helper/xsecctl.cxx +++ b/xmlsecurity/source/helper/xsecctl.cxx @@ -65,6 +65,7 @@ XSecController::XSecController( const cssu::Reference<cssu::XComponentContext>& , m_bIsSAXEventKeeperSticky(false) , m_nReservedSignatureId(0) , m_bVerifyCurrentSignature(false) + , m_nDigestID(cssxc::DigestID::SHA1) { } @@ -614,9 +615,12 @@ void XSecController::exportSignature( /* Write SignatureMethod element */ pAttributeList = new SvXMLAttributeList(); + + // Assume that all Reference elements use the same DigestMethod:Algorithm, and that the + // SignatureMethod:Algorithm should be the corresponding one. pAttributeList->AddAttribute( "Algorithm", - ALGO_RSASHA1); + (vReferenceInfors[0].nDigestID == cssxc::DigestID::SHA1 ? OUString(ALGO_RSASHA1) : OUString(ALGO_RSASHA256))); xDocumentHandler->startElement( "SignatureMethod", cssu::Reference< cssxs::XAttributeList > (pAttributeList) ); xDocumentHandler->endElement( "SignatureMethod" ); @@ -676,7 +680,7 @@ void XSecController::exportSignature( pAttributeList = new SvXMLAttributeList(); pAttributeList->AddAttribute( "Algorithm", - ALGO_XMLDSIGSHA1); + (refInfor.nDigestID == cssxc::DigestID::SHA1 ? OUString(ALGO_XMLDSIGSHA1) : OUString(ALGO_XMLDSIGSHA256))); xDocumentHandler->startElement( "DigestMethod", cssu::Reference< cssxs::XAttributeList > (pAttributeList) ); diff --git a/xmlsecurity/source/helper/xsecctl.hxx b/xmlsecurity/source/helper/xsecctl.hxx index a2dc326623a1..eaf4e66da1e7 100644 --- a/xmlsecurity/source/helper/xsecctl.hxx +++ b/xmlsecurity/source/helper/xsecctl.hxx @@ -78,10 +78,10 @@ public: xReferenceResolvedListener = xListener; } - void addReference( SignatureReferenceType type, const OUString& uri, sal_Int32 keeperId ) + void addReference( SignatureReferenceType type, sal_Int32 digestID, const OUString& uri, sal_Int32 keeperId ) { signatureInfor.vSignatureReferenceInfors.push_back( - SignatureReferenceInformation(type, uri)); + SignatureReferenceInformation(type, digestID, uri)); vKeeperIds.push_back( keeperId ); } }; @@ -254,6 +254,13 @@ private: * representing whether to verify the current signature */ bool m_bVerifyCurrentSignature; + + /* + * the type of signature to generate (from the css::xml::crypto::DigestID alternatives) when there is a choice, + * in practice currently SHA1 or SHA256 for ODF. + */ + sal_Int32 m_nDigestID; + public: /* * An xUriBinding is provided to map Uris to XInputStream interfaces. @@ -281,23 +288,28 @@ private: */ static OUString createId(); css::uno::Reference< css::xml::crypto::sax::XReferenceResolvedListener > prepareSignatureToWrite( - InternalSignatureInformation& signatureInfo, sal_Int32 nStorageFormat = 0 ); + InternalSignatureInformation& signatureInfo, + sal_Int32 nStorageFormat, + bool bXAdESCompliantIfODF ); /* * For signature verification */ void addSignature(); - void addReference( const OUString& ouUri); + void addReference( + const OUString& ouUri, + sal_Int32 nDigestID ); void addStreamReference( const OUString& ouUri, - bool isBinary ); + bool isBinary, + sal_Int32 nDigestID ); void setReferenceCount() const; void setX509IssuerName( OUString& ouX509IssuerName ); void setX509SerialNumber( OUString& ouX509SerialNumber ); void setX509Certificate( OUString& ouX509Certificate ); void setSignatureValue( OUString& ouSignatureValue ); - void setDigestValue( OUString& ouDigestValue ); + void setDigestValue( sal_Int32 nDigestID, OUString& ouDigestValue ); void setDate( OUString& ouDate ); void setDescription(const OUString& rDescription); @@ -342,7 +354,7 @@ public: /* * For signature generation */ - void signAStream( sal_Int32 securityId, const OUString& uri, const OUString& objectURL, bool isBinary); + void signAStream( sal_Int32 securityId, const OUString& uri, const OUString& objectURL, bool isBinary, bool bXAdESCompliantIfODF); /** sets data that describes the certificate. @@ -384,7 +396,8 @@ public: void setDescription(sal_Int32 nSecurityId, const OUString& rDescription); bool WriteSignature( - const css::uno::Reference< css::xml::sax::XDocumentHandler >& xDocumentHandler ); + const css::uno::Reference< css::xml::sax::XDocumentHandler >& xDocumentHandler, + bool bXAdESCompliantIfODF); /* * For signature verification diff --git a/xmlsecurity/source/helper/xsecparser.cxx b/xmlsecurity/source/helper/xsecparser.cxx index 9dd1dc79fc84..c16949838c8f 100644 --- a/xmlsecurity/source/helper/xsecparser.cxx +++ b/xmlsecurity/source/helper/xsecparser.cxx @@ -25,6 +25,7 @@ #include <string.h> namespace cssu = com::sun::star::uno; +namespace cssxc = com::sun::star::xml::crypto; namespace cssxs = com::sun::star::xml::sax; XSecParser::XSecParser(XSecController* pXSecController, @@ -39,6 +40,7 @@ XSecParser::XSecParser(XSecController* pXSecController, , m_pXSecController(pXSecController) , m_xNextHandler(xNextHandler) , m_bReferenceUnresolved(false) + , m_nReferenceDigestID(cssxc::DigestID::SHA1) { } @@ -113,7 +115,7 @@ void SAL_CALL XSecParser::startElement( /* * remove the first character '#' from the attribute value */ - m_pXSecController->addReference( ouUri.copy(1) ); + m_pXSecController->addReference( ouUri.copy(1), m_nReferenceDigestID ); } else { @@ -124,6 +126,21 @@ void SAL_CALL XSecParser::startElement( m_bReferenceUnresolved = true; } } + else if (aName == "DigestMethod") + { + OUString ouAlgorithm = xAttribs->getValueByName("Algorithm"); + + SAL_WARN_IF( ouAlgorithm.isEmpty(), "xmlsecurity.helper", "no Algorithm in Reference" ); + if (!ouAlgorithm.isEmpty()) + { + SAL_WARN_IF( ouAlgorithm != ALGO_XMLDSIGSHA1 && ouAlgorithm != ALGO_XMLDSIGSHA256, + "xmlsecurity.helper", "Algorithm neither SHA1 or SHA256"); + if (ouAlgorithm == ALGO_XMLDSIGSHA1) + m_nReferenceDigestID = cssxc::DigestID::SHA1; + else if (ouAlgorithm == ALGO_XMLDSIGSHA256) + m_nReferenceDigestID = cssxc::DigestID::SHA256; + } + } else if (aName == "Transform") { if ( m_bReferenceUnresolved ) @@ -135,7 +152,7 @@ void SAL_CALL XSecParser::startElement( * a xml stream */ { - m_pXSecController->addStreamReference( m_currentReferenceURI, false); + m_pXSecController->addStreamReference( m_currentReferenceURI, false, m_nReferenceDigestID ); m_bReferenceUnresolved = false; } } @@ -219,11 +236,11 @@ void SAL_CALL XSecParser::endElement( const OUString& aName ) * it must be a octet stream */ { - m_pXSecController->addStreamReference( m_currentReferenceURI, true); + m_pXSecController->addStreamReference( m_currentReferenceURI, true, m_nReferenceDigestID ); m_bReferenceUnresolved = false; } - m_pXSecController->setDigestValue( m_ouDigestValue ); + m_pXSecController->setDigestValue( m_nReferenceDigestID, m_ouDigestValue ); } else if ( aName == "SignedInfo" ) { diff --git a/xmlsecurity/source/helper/xsecparser.hxx b/xmlsecurity/source/helper/xsecparser.hxx index 204ff67876dd..530fa9aa5fd7 100644 --- a/xmlsecurity/source/helper/xsecparser.hxx +++ b/xmlsecurity/source/helper/xsecparser.hxx @@ -95,6 +95,10 @@ private: OUString m_currentReferenceURI; bool m_bReferenceUnresolved; + // Relevant for ODF. The digest algorithm selected by the current DigestMethod element's + // Algorithm attribute in the current Reference element. From css::xml::crypto::DigestID. + sal_Int32 m_nReferenceDigestID; + private: static OUString getIdAttr(const css::uno::Reference< css::xml::sax::XAttributeList >& xAttribs ); diff --git a/xmlsecurity/source/helper/xsecsign.cxx b/xmlsecurity/source/helper/xsecsign.cxx index 5b27c1378c9b..a6b5a21b041d 100644 --- a/xmlsecurity/source/helper/xsecsign.cxx +++ b/xmlsecurity/source/helper/xsecsign.cxx @@ -59,7 +59,9 @@ OUString XSecController::createId() } cssu::Reference< cssxc::sax::XReferenceResolvedListener > XSecController::prepareSignatureToWrite( - InternalSignatureInformation& internalSignatureInfor, sal_Int32 nStorageFormat ) + InternalSignatureInformation& internalSignatureInfor, + sal_Int32 nStorageFormat, + bool bXAdESCompliantIfODF) { sal_Int32 nSecurityId = internalSignatureInfor.signatureInfor.nSecurityId; SignatureReferenceInformations& vReferenceInfors = internalSignatureInfor.signatureInfor.vSignatureReferenceInfors; @@ -165,28 +167,30 @@ cssu::Reference< cssxc::sax::XReferenceResolvedListener > XSecController::prepar cssu::Reference<cssxc::sax::XKeyCollector> keyCollector (xReferenceResolvedListener, cssu::UNO_QUERY); keyCollector->setKeyId(0); + const sal_Int32 digestID = bXAdESCompliantIfODF ? cssxc::DigestID::SHA256 : cssxc::DigestID::SHA1; + if (nStorageFormat != embed::StorageFormats::OFOPXML) { internalSignatureInfor.signatureInfor.ouSignatureId = createId(); internalSignatureInfor.signatureInfor.ouPropertyId = createId(); - internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, internalSignatureInfor.signatureInfor.ouPropertyId, -1 ); + internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, internalSignatureInfor.signatureInfor.ouPropertyId, -1 ); size++; if (!internalSignatureInfor.signatureInfor.ouDescription.isEmpty()) { // Only mention the hash of the description in the signature if it's non-empty. internalSignatureInfor.signatureInfor.ouDescriptionPropertyId = createId(); - internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, internalSignatureInfor.signatureInfor.ouDescriptionPropertyId, -1); + internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, internalSignatureInfor.signatureInfor.ouDescriptionPropertyId, -1); size++; } } else { - internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, "idPackageObject", -1); + internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, "idPackageObject", -1); size++; - internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, "idOfficeObject", -1); + internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, "idOfficeObject", -1); size++; - internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, "idSignedProperties", -1); + internalSignatureInfor.addReference(SignatureReferenceType::SAMEDOCUMENT, digestID, "idSignedProperties", -1); size++; } @@ -204,21 +208,22 @@ cssu::Reference< cssxc::sax::XReferenceResolvedListener > XSecController::prepar return xReferenceResolvedListener; } -void XSecController::signAStream( sal_Int32 securityId, const OUString& uri, const OUString& /*objectURL*/, bool isBinary) +void XSecController::signAStream( sal_Int32 securityId, const OUString& uri, const OUString& /*objectURL*/, bool isBinary, bool bXAdESCompliantIfODF) { - SignatureReferenceType type = isBinary ? SignatureReferenceType::BINARYSTREAM : SignatureReferenceType::XMLSTREAM; + const SignatureReferenceType type = isBinary ? SignatureReferenceType::BINARYSTREAM : SignatureReferenceType::XMLSTREAM; + const sal_Int32 digestID = bXAdESCompliantIfODF ? cssxc::DigestID::SHA256 : cssxc::DigestID::SHA1; int index = findSignatureInfor( securityId ); if (index == -1) { InternalSignatureInformation isi(securityId, nullptr); - isi.addReference(type, uri, -1); + isi.addReference(type, digestID, uri, -1); m_vInternalSignatureInformations.push_back( isi ); } else { - m_vInternalSignatureInformations[index].addReference(type, uri, -1); + m_vInternalSignatureInformations[index].addReference(type, digestID, uri, -1); } } @@ -302,8 +307,11 @@ void XSecController::setDescription(sal_Int32 nSecurityId, const OUString& rDesc } bool XSecController::WriteSignature( - const cssu::Reference<cssxs::XDocumentHandler>& xDocumentHandler ) + const cssu::Reference<cssxs::XDocumentHandler>& xDocumentHandler, + bool bXAdESCompliantIfODF ) { + (void) bXAdESCompliantIfODF; + bool rc = false; SAL_WARN_IF( !xDocumentHandler.is(), "xmlsecurity.helper", "I really need a document handler!" ); @@ -336,11 +344,9 @@ bool XSecController::WriteSignature( { InternalSignatureInformation &isi = m_vInternalSignatureInformations[i]; - /* - * prepare the signature creator - */ - isi.xReferenceResolvedListener - = prepareSignatureToWrite( isi ); + // Prepare the signature creator. + // 0 is not a documented value of embed::StorageFormats, ugh + isi.xReferenceResolvedListener = prepareSignatureToWrite( isi, 0, bXAdESCompliantIfODF ); exportSignature( xSEKHandler, isi.signatureInfor ); } @@ -383,7 +389,7 @@ bool XSecController::WriteOOXMLSignature(const uno::Reference<embed::XStorage>& for (InternalSignatureInformation & rInformation : m_vInternalSignatureInformations) { // Prepare the signature creator. - rInformation.xReferenceResolvedListener = prepareSignatureToWrite(rInformation, embed::StorageFormats::OFOPXML); + rInformation.xReferenceResolvedListener = prepareSignatureToWrite(rInformation, embed::StorageFormats::OFOPXML, false); exportOOXMLSignature(xRootStorage, xSEKHandler, rInformation.signatureInfor); } diff --git a/xmlsecurity/source/helper/xsecverify.cxx b/xmlsecurity/source/helper/xsecverify.cxx index 46946feea6d3..2fcead5a0ff3 100644 --- a/xmlsecurity/source/helper/xsecverify.cxx +++ b/xmlsecurity/source/helper/xsecverify.cxx @@ -114,7 +114,7 @@ void XSecController::addSignature() m_vInternalSignatureInformations.push_back( isi ); } -void XSecController::addReference( const OUString& ouUri) +void XSecController::addReference( const OUString& ouUri, sal_Int32 nDigestID ) { if (m_vInternalSignatureInformations.empty()) { @@ -122,12 +122,13 @@ void XSecController::addReference( const OUString& ouUri) return; } InternalSignatureInformation &isi = m_vInternalSignatureInformations.back(); - isi.addReference(SignatureReferenceType::SAMEDOCUMENT,ouUri, -1 ); + isi.addReference(SignatureReferenceType::SAMEDOCUMENT, nDigestID, ouUri, -1 ); } void XSecController::addStreamReference( const OUString& ouUri, - bool isBinary ) + bool isBinary, + sal_Int32 nDigestID ) { SignatureReferenceType type = (isBinary?SignatureReferenceType::BINARYSTREAM:SignatureReferenceType::XMLSTREAM); @@ -154,7 +155,7 @@ void XSecController::addStreamReference( } } - isi.addReference(type, ouUri, -1); + isi.addReference(type, nDigestID, ouUri, -1); } void XSecController::setReferenceCount() const @@ -235,7 +236,7 @@ void XSecController::setSignatureValue( OUString& ouSignatureValue ) isi.signatureInfor.ouSignatureValue = ouSignatureValue; } -void XSecController::setDigestValue( OUString& ouDigestValue ) +void XSecController::setDigestValue( sal_Int32 nDigestID, OUString& ouDigestValue ) { if (m_vInternalSignatureInformations.empty()) { @@ -250,6 +251,7 @@ void XSecController::setDigestValue( OUString& ouDigestValue ) } SignatureReferenceInformation &reference = isi.signatureInfor.vSignatureReferenceInfors.back(); + reference.nDigestID = nDigestID; reference.ouDigestValue = ouDigestValue; } diff --git a/xmlsecurity/uiconfig/ui/digitalsignaturesdialog.ui b/xmlsecurity/uiconfig/ui/digitalsignaturesdialog.ui index 4eebb5ea6887..10c0685b0aa7 100644 --- a/xmlsecurity/uiconfig/ui/digitalsignaturesdialog.ui +++ b/xmlsecurity/uiconfig/ui/digitalsignaturesdialog.ui @@ -139,7 +139,7 @@ </object> <packing> <property name="left_attach">0</property> - <property name="top_attach">6</property> + <property name="top_attach">7</property> <property name="width">1</property> <property name="height">1</property> </packing> @@ -366,6 +366,19 @@ <property name="height">1</property> </packing> </child> + <child> + <object class="GtkCheckButton" id="xadescompliant"> + <property name="label" translatable="yes">Use XAdES-compliant signature when there is a choice</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="left_attach">0</property> + <property name="top_attach">6</property> + </packing> + </child> </object> <packing> <property name="expand">True</property> |