desktop/qa/data/blank_text.docx |binary desktop/qa/desktop_lib/test_desktop_lib.cxx | 242 ++++++---- desktop/source/lib/init.cxx | 78 +++ include/LibreOfficeKit/LibreOfficeKit.h | 10 include/LibreOfficeKit/LibreOfficeKit.hxx | 12 include/sfx2/DocumentSigner.hxx | 41 + sfx2/Library_sfx.mk | 1 sfx2/source/appl/appopen.cxx | 16 sfx2/source/doc/DocumentSigner.cxx | 125 +++++ xmlsecurity/Library_xsec_xmlsec.mk | 1 xmlsecurity/inc/documentsignaturemanager.hxx | 2 xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx | 21 xmlsecurity/source/helper/documentsignaturehelper.cxx | 6 xmlsecurity/source/helper/documentsignaturemanager.cxx | 77 ++- xmlsecurity/source/xmlsec/nss/nssinitializer.cxx | 131 ++++- xmlsecurity/source/xmlsec/nss/securityenvironment_nssimpl.cxx | 56 +- xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.cxx | 23 xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.hxx | 2 18 files changed, 664 insertions(+), 180 deletions(-)
New commits: commit 277f4e186ce4a3f109c470b54a0accdb6c74e8cb Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> AuthorDate: Mon Dec 31 12:27:39 2018 +0100 Commit: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> CommitDate: Thu Jan 3 07:34:39 2019 +0100 lok: add signDocument to "Office" iface - to sign not opened docs. LOKit function "signDocument" can sign document without the need to open them. This is useful to sign PDF documents after they are created from a currently opened (ODF, DOCX) document. This adds DocumentDigner to sfx2, which could also be used in desktop LibreOffice without opening them and in further tests. Reviewed-on: https://gerrit.libreoffice.org/65767 Tested-by: Jenkins Reviewed-by: Tomaž Vajngerl <qui...@gmail.com> (cherry picked from commit a8cb7cf68ff661b502e7c006fe4330098b5b0944) Change-Id: Id6f242e817f594aa672f94f9c6f9b34e4035d46a diff --git a/desktop/qa/desktop_lib/test_desktop_lib.cxx b/desktop/qa/desktop_lib/test_desktop_lib.cxx index 78f064a49c0a..27070b4440a3 100644 --- a/desktop/qa/desktop_lib/test_desktop_lib.cxx +++ b/desktop/qa/desktop_lib/test_desktop_lib.cxx @@ -125,6 +125,7 @@ public: void testInsertCertificate_DER_ODT(); void testInsertCertificate_PEM_ODT(); void testInsertCertificate_PEM_DOCX(); + void testSignDocument_PEM_PDF(); void testABI(); CPPUNIT_TEST_SUITE(DesktopLOKTest); @@ -173,6 +174,7 @@ public: CPPUNIT_TEST(testInsertCertificate_DER_ODT); CPPUNIT_TEST(testInsertCertificate_PEM_ODT); CPPUNIT_TEST(testInsertCertificate_PEM_DOCX); + CPPUNIT_TEST(testSignDocument_PEM_PDF); CPPUNIT_TEST(testABI); CPPUNIT_TEST_SUITE_END(); @@ -2484,6 +2486,66 @@ void DesktopLOKTest::testInsertCertificate_PEM_DOCX() comphelper::LibreOfficeKit::setActive(false); } +void DesktopLOKTest::testSignDocument_PEM_PDF() +{ + comphelper::LibreOfficeKit::setActive(); + + // Load the document, save it into a temp file and load that file again + LibLODocument_Impl* pDocument = loadDoc("blank_text.odt"); + utl::TempFile aTempFile; + aTempFile.EnableKillingFile(); + + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT(mxComponent.is()); + pDocument->m_pDocumentClass->initializeForRendering(pDocument, "{}"); + Scheduler::ProcessEventsToIdle(); + + std::vector<unsigned char> aCertificate; + std::vector<unsigned char> aPrivateKey; + + { + readFileIntoByteVector("test-cert-chain-1.pem", aCertificate); + + bool bResult = pDocument->m_pDocumentClass->addCertificate( + pDocument, aCertificate.data(), int(aCertificate.size())); + CPPUNIT_ASSERT(bResult); + } + + { + readFileIntoByteVector("test-cert-chain-2.pem", aCertificate); + + bool bResult = pDocument->m_pDocumentClass->addCertificate( + pDocument, aCertificate.data(), int(aCertificate.size())); + CPPUNIT_ASSERT(bResult); + } + + { + readFileIntoByteVector("test-cert-chain-3.pem", aCertificate); + + bool bResult = pDocument->m_pDocumentClass->addCertificate( + pDocument, aCertificate.data(), int(aCertificate.size())); + CPPUNIT_ASSERT(bResult); + } + + CPPUNIT_ASSERT(pDocument->pClass->saveAs(pDocument, aTempFile.GetURL().toUtf8().getStr(), "pdf", nullptr)); + + closeDoc(); + + Scheduler::ProcessEventsToIdle(); + + readFileIntoByteVector("test-cert-signing.pem", aCertificate); + readFileIntoByteVector("test-PK-signing.pem", aPrivateKey); + + LibLibreOffice_Impl aOffice; + bool bResult = aOffice.m_pOfficeClass->signDocument(&aOffice, aTempFile.GetURL().toUtf8().getStr(), + aCertificate.data(), int(aCertificate.size()), + aPrivateKey.data(), int(aPrivateKey.size())); + + CPPUNIT_ASSERT(bResult); + + comphelper::LibreOfficeKit::setActive(false); +} + namespace { size_t documentClassOffset(int i) diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx index f534d9a9b23a..333da4cba3db 100644 --- a/desktop/source/lib/init.cxx +++ b/desktop/source/lib/init.cxx @@ -93,6 +93,7 @@ #include <sfx2/msgpool.hxx> #include <sfx2/dispatch.hxx> #include <sfx2/lokhelper.hxx> +#include <sfx2/DocumentSigner.hxx> #include <svx/dialmgr.hxx> #include <svx/dialogs.hrc> #include <svx/strings.hrc> @@ -1425,6 +1426,13 @@ static void lo_setDocumentPassword(LibreOfficeKit* pThis, static char* lo_getVersionInfo(LibreOfficeKit* pThis); static int lo_runMacro (LibreOfficeKit* pThis, const char* pURL); +static bool lo_signDocument(LibreOfficeKit* pThis, + const char* pUrl, + const unsigned char* pCertificateBinary, + const int nCertificateBinarySize, + const unsigned char* pPrivateKeyBinary, + const int nPrivateKeyBinarySize); + LibLibreOffice_Impl::LibLibreOffice_Impl() : m_pOfficeClass( gOfficeClass.lock() ) , maThread(nullptr) @@ -1447,6 +1455,7 @@ LibLibreOffice_Impl::LibLibreOffice_Impl() m_pOfficeClass->setDocumentPassword = lo_setDocumentPassword; m_pOfficeClass->getVersionInfo = lo_getVersionInfo; m_pOfficeClass->runMacro = lo_runMacro; + m_pOfficeClass->signDocument = lo_signDocument; gOfficeClass = m_pOfficeClass; } @@ -1674,6 +1683,75 @@ static int lo_runMacro(LibreOfficeKit* pThis, const char *pURL) return false; } +static bool lo_signDocument(LibreOfficeKit* /*pThis*/, + const char* pURL, + const unsigned char* pCertificateBinary, + const int nCertificateBinarySize, + const unsigned char* pPrivateKeyBinary, + const int nPrivateKeyBinarySize) +{ + OUString aURL(getAbsoluteURL(pURL)); + if (aURL.isEmpty()) + return false; + + if (!xContext.is()) + return false; + + uno::Sequence<sal_Int8> aCertificateSequence; + + std::string aCertificateString(reinterpret_cast<const char*>(pCertificateBinary), nCertificateBinarySize); + std::string aCertificateBase64String = extractCertificate(aCertificateString); + if (!aCertificateBase64String.empty()) + { + OUString aBase64OUString = OUString::createFromAscii(aCertificateBase64String.c_str()); + comphelper::Base64::decode(aCertificateSequence, aBase64OUString); + } + else + { + aCertificateSequence.realloc(nCertificateBinarySize); + std::copy(pCertificateBinary, pCertificateBinary + nCertificateBinarySize, aCertificateSequence.begin()); + } + + uno::Sequence<sal_Int8> aPrivateKeySequence; + std::string aPrivateKeyString(reinterpret_cast<const char*>(pPrivateKeyBinary), nPrivateKeyBinarySize); + std::string aPrivateKeyBase64String = extractPrivateKey(aPrivateKeyString); + if (!aPrivateKeyBase64String.empty()) + { + OUString aBase64OUString = OUString::createFromAscii(aPrivateKeyBase64String.c_str()); + comphelper::Base64::decode(aPrivateKeySequence, aBase64OUString); + } + else + { + aPrivateKeySequence.realloc(nPrivateKeyBinarySize); + std::copy(pPrivateKeyBinary, pPrivateKeyBinary + nPrivateKeyBinarySize, aPrivateKeySequence.begin()); + } + + uno::Reference<xml::crypto::XSEInitializer> xSEInitializer = xml::crypto::SEInitializer::create(xContext); + uno::Reference<xml::crypto::XXMLSecurityContext> xSecurityContext; + xSecurityContext = xSEInitializer->createSecurityContext(OUString()); + if (!xSecurityContext.is()) + return false; + + uno::Reference<xml::crypto::XSecurityEnvironment> xSecurityEnvironment; + xSecurityEnvironment = xSecurityContext->getSecurityEnvironment(); + uno::Reference<xml::crypto::XCertificateCreator> xCertificateCreator(xSecurityEnvironment, uno::UNO_QUERY); + + if (!xCertificateCreator.is()) + return false; + + uno::Reference<security::XCertificate> xCertificate; + xCertificate = xCertificateCreator->createDERCertificateWithPrivateKey(aCertificateSequence, aPrivateKeySequence); + + if (!xCertificate.is()) + return false; + + sfx2::DocumentSigner aDocumentSigner(aURL); + if (!aDocumentSigner.signDocument(xCertificate)) + return false; + + return true; +} + static void lo_registerCallback (LibreOfficeKit* pThis, LibreOfficeKitCallback pCallback, void* pData) diff --git a/include/LibreOfficeKit/LibreOfficeKit.h b/include/LibreOfficeKit/LibreOfficeKit.h index 0581513d7701..479344cfc971 100644 --- a/include/LibreOfficeKit/LibreOfficeKit.h +++ b/include/LibreOfficeKit/LibreOfficeKit.h @@ -94,6 +94,16 @@ struct _LibreOfficeKitClass @since LibreOffice 6.0 */ int (*runMacro) (LibreOfficeKit *pThis, const char* pURL); + + /** @see lok::Office::signDocument(). + @since LibreOffice 6.2 + */ + bool (*signDocument) (LibreOfficeKit* pThis, + const char* pUrl, + const unsigned char* pCertificateBinary, + const int nCertificateBinarySize, + const unsigned char* pPrivateKeyBinary, + const int nPrivateKeyBinarySize); }; #define LIBREOFFICEKIT_DOCUMENT_HAS(pDoc,member) LIBREOFFICEKIT_HAS_MEMBER(LibreOfficeKitDocumentClass,member,(pDoc)->pClass->nSize) diff --git a/include/LibreOfficeKit/LibreOfficeKit.hxx b/include/LibreOfficeKit/LibreOfficeKit.hxx index ffcb87f4e5d0..8709f5418722 100644 --- a/include/LibreOfficeKit/LibreOfficeKit.hxx +++ b/include/LibreOfficeKit/LibreOfficeKit.hxx @@ -763,6 +763,18 @@ public: { return mpThis->pClass->runMacro( mpThis, pURL ); } + + /** + * Exports the document and signes its content. + */ + bool signDocument(const char* pURL, + const unsigned char* pCertificateBinary, const int nCertificateBinarySize, + const unsigned char* pPrivateKeyBinary, const int nPrivateKeyBinarySize) + { + return mpThis->pClass->signDocument(mpThis, pURL, + pCertificateBinary, nCertificateBinarySize, + pPrivateKeyBinary, nPrivateKeyBinarySize); + } }; /// Factory method to create a lok::Office instance. diff --git a/include/sfx2/DocumentSigner.hxx b/include/sfx2/DocumentSigner.hxx new file mode 100644 index 000000000000..1f4326ef3976 --- /dev/null +++ b/include/sfx2/DocumentSigner.hxx @@ -0,0 +1,41 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#ifndef INCLUDED_SFX2_DOCUMENTSIGNER_HXX +#define INCLUDED_SFX2_DOCUMENTSIGNER_HXX + +#include <sal/config.h> +#include <sfx2/dllapi.h> + +#include <memory> + +#include <com/sun/star/security/XCertificate.hpp> + +namespace sfx2 +{ +class SFX2_DLLPUBLIC DocumentSigner +{ +private: + OUString m_aUrl; + +public: + DocumentSigner(OUString const& rUrl) + : m_aUrl(rUrl) + { + } + + bool signDocument(css::uno::Reference<css::security::XCertificate> const& rxCertificate); +}; + +} // namespace sfx2 + +#endif // INCLUDED_SFX2_DOCUMENTSIGNER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sfx2/Library_sfx.mk b/sfx2/Library_sfx.mk index 19beea4765e5..3d7e8ac3559e 100644 --- a/sfx2/Library_sfx.mk +++ b/sfx2/Library_sfx.mk @@ -202,6 +202,7 @@ $(eval $(call gb_Library_add_exception_objects,sfx,\ sfx2/source/dialog/tplpitem \ sfx2/source/dialog/versdlg \ sfx2/source/doc/DocumentMetadataAccess \ + sfx2/source/doc/DocumentSigner \ sfx2/source/doc/Metadatable \ sfx2/source/doc/QuerySaveDocument \ sfx2/source/doc/SfxDocumentMetaData \ diff --git a/sfx2/source/doc/DocumentSigner.cxx b/sfx2/source/doc/DocumentSigner.cxx new file mode 100644 index 000000000000..4a07aa81cca9 --- /dev/null +++ b/sfx2/source/doc/DocumentSigner.cxx @@ -0,0 +1,125 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#include <sfx2/DocumentSigner.hxx> + +#include <tools/stream.hxx> +#include <unotools/ucbstreamhelper.hxx> +#include <unotools/streamwrap.hxx> + +#include <comphelper/storagehelper.hxx> +#include <comphelper/processfactory.hxx> + +#include <com/sun/star/embed/XStorage.hpp> +#include <com/sun/star/embed/StorageFormats.hpp> +#include <com/sun/star/embed/XTransactedObject.hpp> +#include <com/sun/star/security/DocumentSignatureInformation.hpp> +#include <com/sun/star/security/DocumentDigitalSignatures.hpp> +#include <com/sun/star/io/WrongFormatException.hpp> +#include <com/sun/star/io/XStream.hpp> + +using namespace css; + +namespace sfx2 +{ +bool DocumentSigner::signDocument(uno::Reference<security::XCertificate> const& rxCertificate) +{ + std::unique_ptr<SvStream> pStream( + utl::UcbStreamHelper::CreateStream(m_aUrl, StreamMode::READ | StreamMode::WRITE)); + uno::Reference<io::XStream> xInputStream(new utl::OStreamWrapper(*pStream)); + + bool bHasValidDocumentSignature = true; + + bool bResult = false; + uno::Reference<embed::XStorage> xWriteableZipStore; + try + { + xWriteableZipStore = comphelper::OStorageHelper::GetStorageOfFormatFromStream( + ZIP_STORAGE_FORMAT_STRING, xInputStream); + } + catch (const io::IOException&) + { + } + + OUString aODFVersion(comphelper::OStorageHelper::GetODFVersionFromStorage(xWriteableZipStore)); + + uno::Reference<security::XDocumentDigitalSignatures> xSigner( + security::DocumentDigitalSignatures::createWithVersionAndValidSignature( + comphelper::getProcessComponentContext(), aODFVersion, bHasValidDocumentSignature)); + + try + { + uno::Reference<embed::XStorage> xMetaInf; + uno::Reference<container::XNameAccess> xNameAccess(xWriteableZipStore, uno::UNO_QUERY); + if (xNameAccess.is() && xNameAccess->hasByName("META-INF")) + { + xMetaInf = xWriteableZipStore->openStorageElement("META-INF", + embed::ElementModes::READWRITE); + if (!xMetaInf.is()) + throw uno::RuntimeException(); + } + if (xMetaInf.is()) + { + uno::Reference<embed::XStorage> xStorage; + xStorage = comphelper::OStorageHelper::GetStorageOfFormatFromStream( + ZIP_STORAGE_FORMAT_STRING, xInputStream); + + // ODF. + uno::Reference<io::XStream> xStream; + xStream.set( + xMetaInf->openStreamElement(xSigner->getDocumentContentSignatureDefaultStreamName(), + embed::ElementModes::READWRITE), + uno::UNO_SET_THROW); + bool bSuccess = xSigner->signDocumentWithCertificate(rxCertificate, xStorage, xStream); + if (bSuccess) + { + uno::Reference<embed::XTransactedObject> xTransact(xMetaInf, uno::UNO_QUERY_THROW); + xTransact->commit(); + xTransact.set(xWriteableZipStore, uno::UNO_QUERY_THROW); + xTransact->commit(); + bResult = true; + } + } + else if (xWriteableZipStore.is()) + { + uno::Reference<embed::XStorage> xStorage; + xStorage = comphelper::OStorageHelper::GetStorageOfFormatFromStream( + ZIP_STORAGE_FORMAT_STRING, xInputStream); + + // OOXML. + uno::Reference<io::XStream> xStream; + + // We need read-write to be able to add the signature relation. + bool bSuccess = xSigner->signDocumentWithCertificate(rxCertificate, xStorage, xStream); + + if (bSuccess) + { + uno::Reference<embed::XTransactedObject> xTransact(xWriteableZipStore, + uno::UNO_QUERY_THROW); + xTransact->commit(); + bResult = true; + } + } + else + { + // Something not ZIP based: e.g. PDF. + bResult = xSigner->signDocumentWithCertificate( + rxCertificate, uno::Reference<embed::XStorage>(), xInputStream); + } + } + catch (const uno::Exception&) + { + } + return bResult; +} + +} // namespace sfx2 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ commit 48595091cae4248711c4fc48e68887e9f138c8ad Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> AuthorDate: Mon Dec 31 12:14:19 2018 +0100 Commit: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> CommitDate: Thu Jan 3 07:34:31 2019 +0100 NSS: create a temporary database instead of in-memory When initializing for the in-memory database (NSS_NoDB_Init) the internal slot is read-only so a lot of actions (PK11_ImportCert) fails. Instead of that we create a new cert/key database inside the tmp directory and delete it on exit. This way there are no limitations and all the actions perform as expected. Change-Id: Iadec5dd8f3459be56ba57d077057eacf3e0797fc Reviewed-on: https://gerrit.libreoffice.org/65765 Tested-by: Jenkins Reviewed-by: Tomaž Vajngerl <qui...@gmail.com> (cherry picked from commit 87eec1b90b6ecd83455f09168430c23f73c25c86) diff --git a/xmlsecurity/Library_xsec_xmlsec.mk b/xmlsecurity/Library_xsec_xmlsec.mk index 1ef27dbc6602..e75fb773fbf8 100644 --- a/xmlsecurity/Library_xsec_xmlsec.mk +++ b/xmlsecurity/Library_xsec_xmlsec.mk @@ -45,6 +45,7 @@ $(eval $(call gb_Library_use_libraries,xsec_xmlsec,\ svl \ tl \ xo \ + utl \ )) ifeq ($(SYSTEM_XMLSEC),) diff --git a/xmlsecurity/source/xmlsec/nss/nssinitializer.cxx b/xmlsecurity/source/xmlsec/nss/nssinitializer.cxx index 575be2a2702c..99db97559588 100644 --- a/xmlsecurity/source/xmlsec/nss/nssinitializer.cxx +++ b/xmlsecurity/source/xmlsec/nss/nssinitializer.cxx @@ -38,6 +38,8 @@ #include <osl/file.hxx> #include <osl/thread.h> #include <sal/log.hxx> +#include <unotools/tempfile.hxx> +#include <salhelper/singletonref.hxx> #include "seinitializer_nssimpl.hxx" @@ -46,6 +48,7 @@ #include "ciphercontext.hxx" #include <memory> +#include <vector> #include <nspr.h> #include <cert.h> @@ -69,6 +72,97 @@ extern "C" void nsscrypto_finalize(); namespace { +class InitNSSPrivate +{ +private: + std::unique_ptr<utl::TempFile> m_pTempFileDatabaseDirectory; + + static void scanDirsAndFiles(OUString const & rDirURL, std::vector<OUString> & rDirs, std::vector<OUString> & rFiles) + { + if (rDirURL.isEmpty()) + return; + osl::Directory aDirectory(rDirURL); + + if (osl::FileBase::E_None != aDirectory.open()) + return; + + osl::DirectoryItem aDirectoryItem; + + while (osl::FileBase::E_None == aDirectory.getNextItem(aDirectoryItem)) + { + osl::FileStatus aFileStatus(osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileURL | osl_FileStatus_Mask_FileName); + + if (osl::FileBase::E_None == aDirectoryItem.getFileStatus(aFileStatus)) + { + if (aFileStatus.isDirectory()) + { + const OUString aFileName(aFileStatus.getFileName()); + if (!aFileName.isEmpty()) + rDirs.push_back(aFileName); + } + else if (aFileStatus.isRegular()) + { + const OUString aFileName(aFileStatus.getFileName()); + if (!aFileName.isEmpty()) + rFiles.push_back(aFileName); + + } + } + } + } + + static bool deleteDirRecursively(OUString const & rDirURL) + { + std::vector<OUString> aDirs; + std::vector<OUString> aFiles; + bool bError(false); + + scanDirsAndFiles(rDirURL, aDirs, aFiles); + + for (const auto& sDir : aDirs) + { + const OUString aNewDirURL(rDirURL + "/" + sDir); + bError |= deleteDirRecursively(aNewDirURL); + } + + for (const auto& sFile : aFiles) + { + OUString aNewFileURL(rDirURL + "/" + sFile); + bError |= (osl::FileBase::E_None != osl::File::remove(aNewFileURL)); + } + + bError |= (osl::FileBase::E_None != osl::Directory::remove(rDirURL)); + + return bError; + } + +public: + OUString getTempDatabasePath() + { + if (!m_pTempFileDatabaseDirectory) + { + m_pTempFileDatabaseDirectory.reset(new utl::TempFile(nullptr, true)); + m_pTempFileDatabaseDirectory->EnableKillingFile(); + } + return m_pTempFileDatabaseDirectory->GetFileName(); + } + + void reset() + { + if (m_pTempFileDatabaseDirectory) + { + deleteDirRecursively(m_pTempFileDatabaseDirectory->GetURL()); + m_pTempFileDatabaseDirectory.reset(); + } + } +}; + +salhelper::SingletonRef<InitNSSPrivate>* getInitNSSPrivate() +{ + static salhelper::SingletonRef<InitNSSPrivate> aInitNSSPrivate; + return &aInitNSSPrivate; +} + bool nsscrypto_initialize( const css::uno::Reference< css::uno::XComponentContext > &rxContext, bool & out_nss_init ); struct InitNSSInitialize @@ -235,7 +329,7 @@ OString getMozillaCurrentProfile( const css::uno::Reference< css::uno::XComponen //return true - whole initialization was successful //param out_nss_init = true: at least the NSS initialization (NSS_InitReadWrite //was successful and therefore NSS_Shutdown should be called when terminating. -bool nsscrypto_initialize( const css::uno::Reference< css::uno::XComponentContext > &rxContext, bool & out_nss_init ) +bool nsscrypto_initialize(css::uno::Reference<css::uno::XComponentContext> const & rxContext, bool & out_nss_init) { // this method must be called only once, no need for additional lock OString sCertDir; @@ -249,9 +343,9 @@ bool nsscrypto_initialize( const css::uno::Reference< css::uno::XComponentContex PR_Init( PR_USER_THREAD, PR_PRIORITY_NORMAL, 1 ) ; - bool bSuccess = true; + bool bSuccess = false; // there might be no profile - if ( !sCertDir.isEmpty() ) + if (!sCertDir.isEmpty()) { if (sCertDir.indexOf(':') == -1) //might be env var with explicit prefix { @@ -267,26 +361,31 @@ bool nsscrypto_initialize( const css::uno::Reference< css::uno::XComponentContex sCertDir = "dbm:" + sCertDir; } } - if( NSS_InitReadWrite( sCertDir.getStr() ) != SECSuccess ) + if (NSS_InitReadWrite(sCertDir.getStr()) != SECSuccess) { SAL_INFO("xmlsecurity.xmlsec", "Initializing NSS with profile failed."); int errlen = PR_GetErrorTextLength(); - if(errlen > 0) + if (errlen > 0) { std::unique_ptr<char[]> const error(new char[errlen + 1]); PR_GetErrorText(error.get()); SAL_INFO("xmlsecurity.xmlsec", error.get()); } - bSuccess = false; + } + else + { + bSuccess = true; } } - if( sCertDir.isEmpty() || !bSuccess ) + if (!bSuccess) // Try to create a database in temp dir { - SAL_INFO("xmlsecurity.xmlsec", "Initializing NSS without profile."); - if ( NSS_NoDB_Init(nullptr) != SECSuccess ) + SAL_INFO("xmlsecurity.xmlsec", "Initializing NSS with a temporary profile."); + OUString rString = (*getInitNSSPrivate())->getTempDatabasePath(); + + if (NSS_InitReadWrite(rString.toUtf8().getStr()) != SECSuccess) { - SAL_INFO("xmlsecurity.xmlsec", "Initializing NSS without profile failed."); + SAL_INFO("xmlsecurity.xmlsec", "Initializing NSS with a temporary profile."); int errlen = PR_GetErrorTextLength(); if(errlen > 0) { @@ -294,7 +393,15 @@ bool nsscrypto_initialize( const css::uno::Reference< css::uno::XComponentContex PR_GetErrorText(error.get()); SAL_INFO("xmlsecurity.xmlsec", error.get()); } - return false ; + return false; + } + // Initialize and set empty password if needed + PK11SlotInfo* pSlot = PK11_GetInternalKeySlot(); + if (pSlot) + { + if (PK11_NeedUserInit(pSlot)) + PK11_InitPin(pSlot, nullptr, nullptr); + PK11_FreeSlot(pSlot); } } out_nss_init = true; @@ -388,6 +495,8 @@ extern "C" void nsscrypto_finalize() } PK11_LogoutAll(); (void)NSS_Shutdown(); + + (*getInitNSSPrivate())->reset(); } ONSSInitializer::ONSSInitializer( diff --git a/xmlsecurity/source/xmlsec/nss/securityenvironment_nssimpl.cxx b/xmlsecurity/source/xmlsec/nss/securityenvironment_nssimpl.cxx index d58d4e7b95b5..5595598d295b 100644 --- a/xmlsecurity/source/xmlsec/nss/securityenvironment_nssimpl.cxx +++ b/xmlsecurity/source/xmlsec/nss/securityenvironment_nssimpl.cxx @@ -41,6 +41,7 @@ #include <osl/thread.h> #include "secerror.hxx" +#include <prerror.h> // added for password exception #include <com/sun/star/security/NoPasswordException.hpp> @@ -537,15 +538,34 @@ X509Certificate_NssImpl* SecurityEnvironment_NssImpl::createAndAddCertificateFro if (!pCERTCertificate) return nullptr; - OString aTrustString = OUStringToOString(raString, RTL_TEXTENCODING_ASCII_US); + SECStatus aStatus; + OString aTrustString = OUStringToOString(raString, RTL_TEXTENCODING_ASCII_US); CERTCertTrust aTrust; - if (CERT_DecodeTrustString(&aTrust, aTrustString.getStr()) != SECSuccess) + + aStatus = CERT_DecodeTrustString(&aTrust, aTrustString.getStr()); + + if (aStatus != SECSuccess) + return nullptr; + + PK11SlotInfo* pSlot = PK11_GetInternalKeySlot(); + + if (!pSlot) return nullptr; - if (CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), pCERTCertificate, &aTrust) != SECSuccess) + aStatus = PK11_ImportCert(pSlot, pCERTCertificate, CK_INVALID_HANDLE, nullptr, PR_FALSE); + + if (aStatus != SECSuccess) return nullptr; + aStatus = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), pCERTCertificate, &aTrust); + + if (aStatus != SECSuccess) + return nullptr; + + + PK11_FreeSlot(pSlot); + X509Certificate_NssImpl* pX509Certificate = new X509Certificate_NssImpl(); pX509Certificate->setCert(pCERTCertificate); return pX509Certificate; @@ -933,12 +953,10 @@ xmlSecKeysMngrPtr SecurityEnvironment_NssImpl::createKeysManager() { // Adopt the private key of the signing certificate, if it has any. if (auto pCertificate = dynamic_cast<X509Certificate_NssImpl*>(m_xSigningCertificate.get())) { - SECKEYPrivateKey* pPrivateKey = pCertificate->getPrivateKey(); - SECKEYPrivateKey* copy - = pPrivateKey == nullptr ? nullptr : SECKEY_CopyPrivateKey(pPrivateKey); - if (copy) + SECKEYPrivateKey* pPrivateKey = SECKEY_CopyPrivateKey(pCertificate->getPrivateKey()); + if (pPrivateKey) { - xmlSecKeyDataPtr pKeyData = xmlSecNssPKIAdoptKey(copy, nullptr); + xmlSecKeyDataPtr pKeyData = xmlSecNssPKIAdoptKey(pPrivateKey, nullptr); xmlSecKeyPtr pKey = xmlSecKeyCreate(); xmlSecKeySetValue(pKey, pKeyData); xmlSecNssAppDefaultKeysMngrAdoptKey(pKeysMngr, pKey); @@ -965,42 +983,40 @@ SECKEYPrivateKey* SecurityEnvironment_NssImpl::insertPrivateKey(css::uno::Sequen if (!pSlot) return nullptr; - SECItem pDerPrivateKeyInfo; - pDerPrivateKeyInfo.data = reinterpret_cast<unsigned char *>(const_cast<sal_Int8 *>(raPrivateKey.getConstArray())); - pDerPrivateKeyInfo.len = raPrivateKey.getLength(); + SECItem aDerPrivateKeyInfo; + aDerPrivateKeyInfo.data = reinterpret_cast<unsigned char *>(const_cast<sal_Int8 *>(raPrivateKey.getConstArray())); + aDerPrivateKeyInfo.len = raPrivateKey.getLength(); - const unsigned int aKeyUsage = KU_KEY_ENCIPHERMENT | KU_DATA_ENCIPHERMENT | KU_DIGITAL_SIGNATURE; + const unsigned int aKeyUsage = KU_ALL; SECKEYPrivateKey* pPrivateKey = nullptr; - bool bPermanent = false; - bool bSensitive = false; + bool bPermanent = PR_FALSE; + bool bPrivate = PR_TRUE; SECStatus nStatus = PK11_ImportDERPrivateKeyInfoAndReturnKey( - pSlot, &pDerPrivateKeyInfo, nullptr, nullptr, bPermanent, bSensitive, + pSlot, &aDerPrivateKeyInfo, nullptr, nullptr, bPermanent, bPrivate, aKeyUsage, &pPrivateKey, nullptr); if (nStatus != SECSuccess) return nullptr; + PK11_FreeSlot(pSlot); + return pPrivateKey; } uno::Reference<security::XCertificate> SecurityEnvironment_NssImpl::createDERCertificateWithPrivateKey( Sequence<sal_Int8> const & raDERCertificate, Sequence<sal_Int8> const & raPrivateKey) { - SECKEYPrivateKey* pPrivateKey = insertPrivateKey(raPrivateKey); if (!pPrivateKey) return uno::Reference<security::XCertificate>(); - X509Certificate_NssImpl* pX509Certificate = createAndAddCertificateFromPackage(raDERCertificate, "TCu,Cu,Tu"); - + X509Certificate_NssImpl* pX509Certificate = createAndAddCertificateFromPackage(raDERCertificate, "TCu,TCu,TCu"); if (!pX509Certificate) return uno::Reference<security::XCertificate>(); - pX509Certificate->setCustomPrivateKey(pPrivateKey); - return pX509Certificate; } diff --git a/xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.cxx b/xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.cxx index 1bda73af613b..1b08b561f902 100644 --- a/xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.cxx +++ b/xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.cxx @@ -45,8 +45,7 @@ using ::com::sun::star::security::XCertificate ; using ::com::sun::star::util::DateTime ; X509Certificate_NssImpl::X509Certificate_NssImpl() : - m_pCert(nullptr), - m_pPrivateKey(nullptr) + m_pCert(nullptr) { } @@ -331,25 +330,13 @@ void X509Certificate_NssImpl::setRawCert( const Sequence< sal_Int8 >& rawCert ) m_pCert = cert ; } -void X509Certificate_NssImpl::setCustomPrivateKey(SECKEYPrivateKey* pPrivateKey) -{ - m_pPrivateKey = pPrivateKey; -} - SECKEYPrivateKey* X509Certificate_NssImpl::getPrivateKey() { - if (m_pPrivateKey) - { - return m_pPrivateKey; - } - else + if (m_pCert && m_pCert->slot) { - if (m_pCert && m_pCert->slot) - { - SECKEYPrivateKey* pPrivateKey = PK11_FindPrivateKeyFromCert(m_pCert->slot, m_pCert, nullptr); - if (pPrivateKey) - return pPrivateKey; - } + SECKEYPrivateKey* pPrivateKey = PK11_FindPrivateKeyFromCert(m_pCert->slot, m_pCert, nullptr); + if (pPrivateKey) + return pPrivateKey; } return nullptr; } diff --git a/xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.hxx b/xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.hxx index 8f0fd2ac4287..e50cf1025166 100644 --- a/xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.hxx +++ b/xmlsecurity/source/xmlsec/nss/x509certificate_nssimpl.hxx @@ -41,7 +41,6 @@ class X509Certificate_NssImpl : public ::cppu::WeakImplHelper< { private: CERTCertificate* m_pCert; - SECKEYPrivateKey* m_pPrivateKey; public: X509Certificate_NssImpl() ; @@ -94,7 +93,6 @@ class X509Certificate_NssImpl : public ::cppu::WeakImplHelper< /// @throws css::uno::RuntimeException void setRawCert( const css::uno::Sequence< sal_Int8 >& rawCert ) ; - void setCustomPrivateKey(SECKEYPrivateKey* pPrivateKey); SECKEYPrivateKey* getPrivateKey(); // XServiceInfo commit 368830fbaef27d3a392d09e5f5c9aa35859b792a Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> AuthorDate: Mon Dec 31 10:09:03 2018 +0100 Commit: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> CommitDate: Thu Jan 3 07:34:26 2019 +0100 Remove some useless whitespaces Reviewed-on: https://gerrit.libreoffice.org/65764 Tested-by: Jenkins Reviewed-by: Tomaž Vajngerl <qui...@gmail.com> (cherry picked from commit a8d51dc85627514ce7f983eb4e0514ef00f84b1e) Change-Id: Iebf7add3dd937afb6dad07a10ecbe768c0a79d36 diff --git a/sfx2/source/appl/appopen.cxx b/sfx2/source/appl/appopen.cxx index 6c5d833af317..4992156f2fa9 100644 --- a/sfx2/source/appl/appopen.cxx +++ b/sfx2/source/appl/appopen.cxx @@ -675,9 +675,9 @@ void SfxApplication::OpenDocExec_Impl( SfxRequest& rReq ) // intercept all incoming interactions and provide useful information // later if the following transaction was finished. - ::sfx2::PreventDuplicateInteraction* pHandler = new ::sfx2::PreventDuplicateInteraction(::comphelper::getProcessComponentContext()); - css::uno::Reference< css::task::XInteractionHandler > xHandler (static_cast< css::task::XInteractionHandler* >(pHandler), css::uno::UNO_QUERY); - css::uno::Reference< css::task::XInteractionHandler > xWrappedHandler; + sfx2::PreventDuplicateInteraction* pHandler = new sfx2::PreventDuplicateInteraction(comphelper::getProcessComponentContext()); + uno::Reference<task::XInteractionHandler> xHandler(static_cast< css::task::XInteractionHandler* >(pHandler), css::uno::UNO_QUERY); + uno::Reference<task::XInteractionHandler> xWrappedHandler; // wrap existing handler or create new UUI handler const SfxUnoAnyItem* pInteractionItem = rReq.GetArg<SfxUnoAnyItem>(SID_INTERACTIONHANDLER); @@ -693,8 +693,8 @@ void SfxApplication::OpenDocExec_Impl( SfxRequest& rReq ) rReq.AppendItem( SfxUnoAnyItem(SID_INTERACTIONHANDLER,css::uno::makeAny(xHandler)) ); // define rules for this handler - css::uno::Type aInteraction = ::cppu::UnoType<css::task::ErrorCodeRequest>::get(); - ::sfx2::PreventDuplicateInteraction::InteractionInfo aRule (aInteraction, 1); + css::uno::Type aInteraction = ::cppu::UnoType<css::task::ErrorCodeRequest>::get(); + ::sfx2::PreventDuplicateInteraction::InteractionInfo aRule(aInteraction, 1); pHandler->addInteractionRule(aRule); if (!aDocService.isEmpty()) @@ -816,9 +816,9 @@ void SfxApplication::OpenDocExec_Impl( SfxRequest& rReq ) // Mark without URL cannot be handled by hyperlink code if ( bHyperlinkUsed && !aFileName.isEmpty() && aFileName[0] != '#' ) { - Reference< css::document::XTypeDetection > xTypeDetection( ::comphelper::getProcessServiceFactory()->createInstance( - "com.sun.star.document.TypeDetection"), - UNO_QUERY ); + uno::Reference<document::XTypeDetection> xTypeDetection( + comphelper::getProcessServiceFactory()->createInstance("com.sun.star.document.TypeDetection"), UNO_QUERY); + if ( xTypeDetection.is() ) { URL aURL; diff --git a/xmlsecurity/source/helper/documentsignaturehelper.cxx b/xmlsecurity/source/helper/documentsignaturehelper.cxx index 509d3699a294..b0b57ee2758d 100644 --- a/xmlsecurity/source/helper/documentsignaturehelper.cxx +++ b/xmlsecurity/source/helper/documentsignaturehelper.cxx @@ -521,17 +521,17 @@ bool DocumentSignatureHelper::equalsReferenceUriManifestPath( OUString DocumentSignatureHelper::GetDocumentContentSignatureDefaultStreamName() { - return OUString( "documentsignatures.xml" ); + return OUString("documentsignatures.xml"); } OUString DocumentSignatureHelper::GetScriptingContentSignatureDefaultStreamName() { - return OUString( "macrosignatures.xml" ); + return OUString("macrosignatures.xml"); } OUString DocumentSignatureHelper::GetPackageSignatureDefaultStreamName() { - return OUString( "packagesignatures.xml" ); + return OUString("packagesignatures.xml"); } void DocumentSignatureHelper::writeDigestMethod( commit ec17d9778b26f762af30c964a6170d4933cdcea4 Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> AuthorDate: Wed Dec 26 20:46:16 2018 +0100 Commit: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> CommitDate: Thu Jan 3 07:34:23 2019 +0100 lok: add test signing DOCX -> testInsertCertificate_PEM_DOCX Change-Id: I1918041793935b012e60fe64073480ed4b9581d5 Reviewed-on: https://gerrit.libreoffice.org/65630 Tested-by: Jenkins Reviewed-by: Tomaž Vajngerl <qui...@gmail.com> (cherry picked from commit 936f6a85649c0fd71eee484e7399d445f4040586) diff --git a/desktop/qa/data/blank_text.docx b/desktop/qa/data/blank_text.docx new file mode 100644 index 000000000000..028a35b6ca58 Binary files /dev/null and b/desktop/qa/data/blank_text.docx differ diff --git a/desktop/qa/desktop_lib/test_desktop_lib.cxx b/desktop/qa/desktop_lib/test_desktop_lib.cxx index 18e20c8fd4d7..78f064a49c0a 100644 --- a/desktop/qa/desktop_lib/test_desktop_lib.cxx +++ b/desktop/qa/desktop_lib/test_desktop_lib.cxx @@ -124,6 +124,7 @@ public: void testGetSignatureState_Signed(); void testInsertCertificate_DER_ODT(); void testInsertCertificate_PEM_ODT(); + void testInsertCertificate_PEM_DOCX(); void testABI(); CPPUNIT_TEST_SUITE(DesktopLOKTest); @@ -171,6 +172,7 @@ public: CPPUNIT_TEST(testGetSignatureState_NonSigned); CPPUNIT_TEST(testInsertCertificate_DER_ODT); CPPUNIT_TEST(testInsertCertificate_PEM_ODT); + CPPUNIT_TEST(testInsertCertificate_PEM_DOCX); CPPUNIT_TEST(testABI); CPPUNIT_TEST_SUITE_END(); @@ -2420,6 +2422,68 @@ void DesktopLOKTest::testInsertCertificate_PEM_ODT() comphelper::LibreOfficeKit::setActive(false); } +void DesktopLOKTest::testInsertCertificate_PEM_DOCX() +{ + comphelper::LibreOfficeKit::setActive(); + + // Load the document, save it into a temp file and load that file again + LibLODocument_Impl* pDocument = loadDoc("blank_text.docx"); + utl::TempFile aTempFile; + aTempFile.EnableKillingFile(); + CPPUNIT_ASSERT(pDocument->pClass->saveAs(pDocument, aTempFile.GetURL().toUtf8().getStr(), "docx", nullptr)); + closeDoc(); + + mxComponent = loadFromDesktop(aTempFile.GetURL(), "com.sun.star.text.TextDocument"); + pDocument = new LibLODocument_Impl(mxComponent); + + Scheduler::ProcessEventsToIdle(); + CPPUNIT_ASSERT(mxComponent.is()); + pDocument->m_pDocumentClass->initializeForRendering(pDocument, "{}"); + Scheduler::ProcessEventsToIdle(); + + std::vector<unsigned char> aCertificate; + std::vector<unsigned char> aPrivateKey; + + { + readFileIntoByteVector("test-cert-chain-1.pem", aCertificate); + + bool bResult = pDocument->m_pDocumentClass->addCertificate( + pDocument, aCertificate.data(), int(aCertificate.size())); + CPPUNIT_ASSERT(bResult); + } + + { + readFileIntoByteVector("test-cert-chain-2.pem", aCertificate); + + bool bResult = pDocument->m_pDocumentClass->addCertificate( + pDocument, aCertificate.data(), int(aCertificate.size())); + CPPUNIT_ASSERT(bResult); + } + + { + readFileIntoByteVector("test-cert-chain-3.pem", aCertificate); + + bool bResult = pDocument->m_pDocumentClass->addCertificate( + pDocument, aCertificate.data(), int(aCertificate.size())); + CPPUNIT_ASSERT(bResult); + } + + { + readFileIntoByteVector("test-cert-signing.pem", aCertificate); + readFileIntoByteVector("test-PK-signing.pem", aPrivateKey); + + bool bResult = pDocument->m_pDocumentClass->insertCertificate(pDocument, + aCertificate.data(), int(aCertificate.size()), + aPrivateKey.data(), int(aPrivateKey.size())); + CPPUNIT_ASSERT(bResult); + } + + int nState = pDocument->m_pDocumentClass->getSignatureState(pDocument); + CPPUNIT_ASSERT_EQUAL(int(5), nState); + + comphelper::LibreOfficeKit::setActive(false); +} + namespace { size_t documentClassOffset(int i) commit e41179f81ba8e8fd5b44e5d1dc0484a120f1e401 Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> AuthorDate: Wed Dec 26 20:44:57 2018 +0100 Commit: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> CommitDate: Thu Jan 3 07:34:19 2019 +0100 lok: simplify and cleanup testInsertCertificate_{PEM,DER}_ODT Change-Id: I61891d1295a342e546cab56ef80315c9f5018f90 Reviewed-on: https://gerrit.libreoffice.org/65629 Tested-by: Jenkins Reviewed-by: Tomaž Vajngerl <qui...@gmail.com> (cherry picked from commit 5cd86cacc1ea69bcf94d298a385e4f711e9bce3c) diff --git a/desktop/qa/desktop_lib/test_desktop_lib.cxx b/desktop/qa/desktop_lib/test_desktop_lib.cxx index e7858c625106..18e20c8fd4d7 100644 --- a/desktop/qa/desktop_lib/test_desktop_lib.cxx +++ b/desktop/qa/desktop_lib/test_desktop_lib.cxx @@ -60,6 +60,8 @@ public: { } + void readFileIntoByteVector(OUString const & sFilename, std::vector<sal_uInt8> & rByteVector); + virtual void setUp() override { UnoApiTest::setUp(); @@ -120,8 +122,8 @@ public: void testExtractParameter(); void testGetSignatureState_NonSigned(); void testGetSignatureState_Signed(); - void testInsertCertificate(); - void testInsertCertificatePEM(); + void testInsertCertificate_DER_ODT(); + void testInsertCertificate_PEM_ODT(); void testABI(); CPPUNIT_TEST_SUITE(DesktopLOKTest); @@ -167,8 +169,8 @@ public: CPPUNIT_TEST(testExtractParameter); CPPUNIT_TEST(testGetSignatureState_Signed); CPPUNIT_TEST(testGetSignatureState_NonSigned); - CPPUNIT_TEST(testInsertCertificate); - CPPUNIT_TEST(testInsertCertificatePEM); + CPPUNIT_TEST(testInsertCertificate_DER_ODT); + CPPUNIT_TEST(testInsertCertificate_PEM_ODT); CPPUNIT_TEST(testABI); CPPUNIT_TEST_SUITE_END(); @@ -2250,6 +2252,16 @@ void DesktopLOKTest::testExtractParameter() comphelper::LibreOfficeKit::setActive(false); } +void DesktopLOKTest::readFileIntoByteVector(OUString const & sFilename, std::vector<unsigned char> & rByteVector) +{ + rByteVector.clear(); + OUString aURL; + createFileURL(sFilename, aURL); + SvFileStream aStream(aURL, StreamMode::READ); + rByteVector.resize(aStream.remainingSize()); + aStream.ReadBytes(rByteVector.data(), aStream.remainingSize()); +} + void DesktopLOKTest::testGetSignatureState_Signed() { comphelper::LibreOfficeKit::setActive(); @@ -2259,28 +2271,16 @@ void DesktopLOKTest::testGetSignatureState_Signed() int nState = pDocument->m_pDocumentClass->getSignatureState(pDocument); CPPUNIT_ASSERT_EQUAL(int(4), nState); + std::vector<unsigned char> aCertificate; { - OUString aCertificateURL; - createFileURL("rootCA.der", aCertificateURL); - SvFileStream aCertificateStream(aCertificateURL, StreamMode::READ); - std::vector<unsigned char> aCertificate; - aCertificate.resize(aCertificateStream.remainingSize()); - aCertificateStream.ReadBytes(aCertificate.data(), aCertificateStream.remainingSize()); - + readFileIntoByteVector("rootCA.der", aCertificate); bool bResult = pDocument->m_pDocumentClass->addCertificate( pDocument, aCertificate.data(), int(aCertificate.size())); CPPUNIT_ASSERT(bResult); } { - OUString aCertificateURL; - createFileURL("intermediateRootCA.der", aCertificateURL); - SvFileStream aCertificateStream(aCertificateURL, StreamMode::READ); - std::vector<unsigned char> aCertificate; - aCertificate.resize(aCertificateStream.remainingSize()); - aCertificateStream.ReadBytes(aCertificate.data(), aCertificateStream.remainingSize()); - - + readFileIntoByteVector("intermediateRootCA.der", aCertificate); bool bResult = pDocument->m_pDocumentClass->addCertificate( pDocument, aCertificate.data(), int(aCertificate.size())); CPPUNIT_ASSERT(bResult); @@ -2303,7 +2303,7 @@ void DesktopLOKTest::testGetSignatureState_NonSigned() comphelper::LibreOfficeKit::setActive(false); } -void DesktopLOKTest::testInsertCertificate() +void DesktopLOKTest::testInsertCertificate_DER_ODT() { comphelper::LibreOfficeKit::setActive(); @@ -2322,13 +2322,11 @@ void DesktopLOKTest::testInsertCertificate() pDocument->m_pDocumentClass->initializeForRendering(pDocument, "{}"); Scheduler::ProcessEventsToIdle(); + std::vector<unsigned char> aCertificate; + std::vector<unsigned char> aPrivateKey; + { - OUString aCertificateURL; - createFileURL("rootCA.der", aCertificateURL); - SvFileStream aCertificateStream(aCertificateURL, StreamMode::READ); - std::vector<unsigned char> aCertificate; - aCertificate.resize(aCertificateStream.remainingSize()); - aCertificateStream.ReadBytes(aCertificate.data(), aCertificateStream.remainingSize()); + readFileIntoByteVector("rootCA.der", aCertificate); bool bResult = pDocument->m_pDocumentClass->addCertificate( pDocument, aCertificate.data(), int(aCertificate.size())); @@ -2336,13 +2334,7 @@ void DesktopLOKTest::testInsertCertificate() } { - OUString aCertificateURL; - createFileURL("intermediateRootCA.der", aCertificateURL); - SvFileStream aCertificateStream(aCertificateURL, StreamMode::READ); - std::vector<unsigned char> aCertificate; - aCertificate.resize(aCertificateStream.remainingSize()); - aCertificateStream.ReadBytes(aCertificate.data(), aCertificateStream.remainingSize()); - + readFileIntoByteVector("intermediateRootCA.der", aCertificate); bool bResult = pDocument->m_pDocumentClass->addCertificate( pDocument, aCertificate.data(), int(aCertificate.size())); @@ -2350,20 +2342,8 @@ void DesktopLOKTest::testInsertCertificate() } { - OUString aCertificateURL; - createFileURL("certificate.der", aCertificateURL); - SvFileStream aCertificateStream(aCertificateURL, StreamMode::READ); - std::vector<unsigned char> aCertificate; - aCertificate.resize(aCertificateStream.remainingSize()); - aCertificateStream.ReadBytes(aCertificate.data(), aCertificateStream.remainingSize()); - - - OUString aPrivateKeyURL; - createFileURL("certificatePrivateKey.der", aPrivateKeyURL); - SvFileStream aPrivateKeyStream(aPrivateKeyURL, StreamMode::READ); - std::vector<unsigned char> aPrivateKey; - aPrivateKey.resize(aPrivateKeyStream.remainingSize()); - aPrivateKeyStream.ReadBytes(aPrivateKey.data(), aPrivateKeyStream.remainingSize()); + readFileIntoByteVector("certificate.der", aCertificate); + readFileIntoByteVector("certificatePrivateKey.der", aPrivateKey); bool bResult = pDocument->m_pDocumentClass->insertCertificate(pDocument, aCertificate.data(), int(aCertificate.size()), @@ -2378,7 +2358,7 @@ void DesktopLOKTest::testInsertCertificate() } -void DesktopLOKTest::testInsertCertificatePEM() +void DesktopLOKTest::testInsertCertificate_PEM_ODT() { comphelper::LibreOfficeKit::setActive(); @@ -2397,13 +2377,11 @@ void DesktopLOKTest::testInsertCertificatePEM() pDocument->m_pDocumentClass->initializeForRendering(pDocument, "{}"); Scheduler::ProcessEventsToIdle(); + std::vector<unsigned char> aCertificate; + std::vector<unsigned char> aPrivateKey; + { - OUString aCertificateURL; - createFileURL("test-cert-chain-1.pem", aCertificateURL); - SvFileStream aCertificateStream(aCertificateURL, StreamMode::READ); - std::vector<unsigned char> aCertificate; - aCertificate.resize(aCertificateStream.remainingSize()); - aCertificateStream.ReadBytes(aCertificate.data(), aCertificateStream.remainingSize()); + readFileIntoByteVector("test-cert-chain-1.pem", aCertificate); bool bResult = pDocument->m_pDocumentClass->addCertificate( pDocument, aCertificate.data(), int(aCertificate.size())); @@ -2411,13 +2389,7 @@ void DesktopLOKTest::testInsertCertificatePEM() } { - OUString aCertificateURL; - createFileURL("test-cert-chain-2.pem", aCertificateURL); - SvFileStream aCertificateStream(aCertificateURL, StreamMode::READ); - std::vector<unsigned char> aCertificate; - aCertificate.resize(aCertificateStream.remainingSize()); - aCertificateStream.ReadBytes(aCertificate.data(), aCertificateStream.remainingSize()); - + readFileIntoByteVector("test-cert-chain-2.pem", aCertificate); bool bResult = pDocument->m_pDocumentClass->addCertificate( pDocument, aCertificate.data(), int(aCertificate.size())); @@ -2425,13 +2397,7 @@ void DesktopLOKTest::testInsertCertificatePEM() } { - OUString aCertificateURL; - createFileURL("test-cert-chain-3.pem", aCertificateURL); - SvFileStream aCertificateStream(aCertificateURL, StreamMode::READ); - std::vector<unsigned char> aCertificate; - aCertificate.resize(aCertificateStream.remainingSize()); - aCertificateStream.ReadBytes(aCertificate.data(), aCertificateStream.remainingSize()); - + readFileIntoByteVector("test-cert-chain-3.pem", aCertificate); bool bResult = pDocument->m_pDocumentClass->addCertificate( pDocument, aCertificate.data(), int(aCertificate.size())); @@ -2439,20 +2405,8 @@ void DesktopLOKTest::testInsertCertificatePEM() } { - OUString aCertificateURL; - createFileURL("test-cert-signing.pem", aCertificateURL); - SvFileStream aCertificateStream(aCertificateURL, StreamMode::READ); - std::vector<unsigned char> aCertificate; - aCertificate.resize(aCertificateStream.remainingSize()); - aCertificateStream.ReadBytes(aCertificate.data(), aCertificateStream.remainingSize()); - - - OUString aPrivateKeyURL; - createFileURL("test-PK-signing.pem", aPrivateKeyURL); - SvFileStream aPrivateKeyStream(aPrivateKeyURL, StreamMode::READ); - std::vector<unsigned char> aPrivateKey; - aPrivateKey.resize(aPrivateKeyStream.remainingSize()); - aPrivateKeyStream.ReadBytes(aPrivateKey.data(), aPrivateKeyStream.remainingSize()); + readFileIntoByteVector("test-cert-signing.pem", aCertificate); + readFileIntoByteVector("test-PK-signing.pem", aPrivateKey); bool bResult = pDocument->m_pDocumentClass->insertCertificate(pDocument, aCertificate.data(), int(aCertificate.size()), commit 540f4c06a025ede65addf3b894feab7b9ffece12 Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> AuthorDate: Mon Dec 24 15:11:30 2018 +0100 Commit: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> CommitDate: Thu Jan 3 07:34:03 2019 +0100 Fix signing empty Configurations2/accelerator/current.xml When determining if a file is an XML file for siging, we need to read the manifest file to get an accurate detection. In case when we were signing in the GUI the manifest file was read when the storage was set. When we didn't sign over the GUI, the manifest was never read: the code was only present in the GUI code - "documentsignaturesdialog.cxx" so the detection was wrong and isXML returned "true" for current.xml. With this we move the manifest reading to DigitalSignatureManager, where the manifest is read when needed. Reviewed-on: https://gerrit.libreoffice.org/65600 Tested-by: Jenkins Reviewed-by: Tomaž Vajngerl <qui...@gmail.com> (cherry picked from commit 49fcd3bbb30f93763fc5cb80fa6ac5cec5d00834) Change-Id: If45a32af6410bc5f7c5afdb976b182bd69ab7d6b diff --git a/desktop/qa/desktop_lib/test_desktop_lib.cxx b/desktop/qa/desktop_lib/test_desktop_lib.cxx index 2b571921738c..e7858c625106 100644 --- a/desktop/qa/desktop_lib/test_desktop_lib.cxx +++ b/desktop/qa/desktop_lib/test_desktop_lib.cxx @@ -2371,6 +2371,9 @@ void DesktopLOKTest::testInsertCertificate() CPPUNIT_ASSERT(bResult); } + int nState = pDocument->m_pDocumentClass->getSignatureState(pDocument); + CPPUNIT_ASSERT_EQUAL(int(1), nState); + comphelper::LibreOfficeKit::setActive(false); } @@ -2457,6 +2460,9 @@ void DesktopLOKTest::testInsertCertificatePEM() CPPUNIT_ASSERT(bResult); } + int nState = pDocument->m_pDocumentClass->getSignatureState(pDocument); + CPPUNIT_ASSERT_EQUAL(int(1), nState); + comphelper::LibreOfficeKit::setActive(false); } diff --git a/xmlsecurity/inc/documentsignaturemanager.hxx b/xmlsecurity/inc/documentsignaturemanager.hxx index bae54619cbd5..6c70e55224dd 100644 --- a/xmlsecurity/inc/documentsignaturemanager.hxx +++ b/xmlsecurity/inc/documentsignaturemanager.hxx @@ -59,6 +59,8 @@ public: * differently when they are signed (c14n transformation) */ bool isXML(const OUString& rURI); + bool readManifest(); + SignatureStreamHelper ImplOpenSignatureStream(sal_Int32 nStreamOpenMode, 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, diff --git a/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx b/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx index 8a1ba46860a6..4ac46e1d4163 100644 --- a/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx +++ b/xmlsecurity/source/dialogs/digitalsignaturesdialog.cxx @@ -36,7 +36,6 @@ #include <com/sun/star/security/CertificateKind.hpp> #include <com/sun/star/security/XDocumentDigitalSignatures.hpp> #include <com/sun/star/xml/dom/XDocumentBuilder.hpp> -#include <com/sun/star/packages/manifest/ManifestReader.hpp> #include <com/sun/star/system/SystemShellExecute.hpp> #include <com/sun/star/system/SystemShellExecuteFlags.hpp> #include <com/sun/star/system/SystemShellExecuteException.hpp> @@ -232,26 +231,6 @@ void DigitalSignaturesDialog::SetStorage( const css::uno::Reference < css::embed { maSignatureManager.mxStore = rxStore; maSignatureManager.maSignatureHelper.SetStorage( maSignatureManager.mxStore, m_sODFVersion); - - Reference < css::packages::manifest::XManifestReader > xReader = - css::packages::manifest::ManifestReader::create(mxCtx); - - uno::Reference<container::XNameAccess> xNameAccess(rxStore, uno::UNO_QUERY); - if (!xNameAccess.is()) - return; - - if (xNameAccess->hasByName("META-INF")) - { - //Get the manifest.xml - Reference < css::embed::XStorage > xSubStore(rxStore->openStorageElement( - "META-INF", css::embed::ElementModes::READ), UNO_QUERY_THROW); - - Reference< css::io::XInputStream > xStream( - xSubStore->openStreamElement("manifest.xml", css::embed::ElementModes::READ), - UNO_QUERY_THROW); - - maSignatureManager.m_manifest = xReader->readManifestSequence(xStream); - } } void DigitalSignaturesDialog::SetSignatureStream( const css::uno::Reference < css::io::XStream >& rxStream ) diff --git a/xmlsecurity/source/helper/documentsignaturemanager.cxx b/xmlsecurity/source/helper/documentsignaturemanager.cxx index c65b73c3b85d..e95b92be1e28 100644 --- a/xmlsecurity/source/helper/documentsignaturemanager.cxx +++ b/xmlsecurity/source/helper/documentsignaturemanager.cxx @@ -29,6 +29,8 @@ #include <com/sun/star/embed/XTransactedObject.hpp> #include <com/sun/star/xml/crypto/SEInitializer.hpp> #include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/packages/manifest/ManifestReader.hpp> #include <comphelper/storagehelper.hxx> #include <rtl/ustrbuf.hxx> @@ -119,6 +121,40 @@ bool DocumentSignatureManager::IsXAdESRelevant() } #endif +bool DocumentSignatureManager::readManifest() +{ + // Check if manifest was already read + if (m_manifest.getLength() > 0) + return true; + + if (!mxContext.is()) + return false; + + if (!mxStore.is()) + return false; + + uno::Reference<packages::manifest::XManifestReader> xReader + = packages::manifest::ManifestReader::create(mxContext); + + uno::Reference<container::XNameAccess> xNameAccess(mxStore, uno::UNO_QUERY); + if (!xNameAccess.is()) + return false; + + if (xNameAccess->hasByName("META-INF")) + { + //Get the manifest.xml + uno::Reference<embed::XStorage> xSubStore( + mxStore->openStorageElement("META-INF", embed::ElementModes::READ), uno::UNO_QUERY_THROW); + + uno::Reference<io::XInputStream> xStream( + xSubStore->openStreamElement("manifest.xml", css::embed::ElementModes::READ), + uno::UNO_QUERY_THROW); + + m_manifest = xReader->readManifestSequence(xStream); + } + return true; +} + /* 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 @@ -134,27 +170,30 @@ bool DocumentSignatureManager::isXML(const OUString& rURI) const OUString sPropMediaType("MediaType"); const OUString sPropDigest("Digest"); - for (int i = 0; i < m_manifest.getLength(); i++) + if (readManifest()) { - const uno::Sequence<beans::PropertyValue>& entry = m_manifest[i]; - OUString sPath, sMediaType; - bool bEncrypted = false; - for (int j = 0; j < entry.getLength(); j++) + for (int i = 0; i < m_manifest.getLength(); i++) { - const beans::PropertyValue& prop = entry[j]; - - if (prop.Name == sPropFullPath) - prop.Value >>= sPath; - else if (prop.Name == sPropMediaType) - prop.Value >>= sMediaType; - else if (prop.Name == sPropDigest) - bEncrypted = true; - } - if (DocumentSignatureHelper::equalsReferenceUriManifestPath(rURI, sPath)) - { - bIsXML = sMediaType == "text/xml" && ! bEncrypted; - bPropsAvailable = true; - break; + const uno::Sequence<beans::PropertyValue>& entry = m_manifest[i]; + OUString sPath, sMediaType; + bool bEncrypted = false; + for (int j = 0; j < entry.getLength(); j++) + { + const beans::PropertyValue& prop = entry[j]; + + if (prop.Name == sPropFullPath) + prop.Value >>= sPath; + else if (prop.Name == sPropMediaType) + prop.Value >>= sMediaType; + else if (prop.Name == sPropDigest) + bEncrypted = true; + } + if (DocumentSignatureHelper::equalsReferenceUriManifestPath(rURI, sPath)) + { + bIsXML = sMediaType == "text/xml" && !bEncrypted; + bPropsAvailable = true; + break; + } } } if (!bPropsAvailable) _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits