[Libreoffice-commits] core.git: Branch 'distro/collabora/cp-4.4' - 39 commits - cui/Library_cui.mk cui/source cui/uiconfig cui/UIConfig_cui.mk filter/Library_pdffilter.mk filter/source filter/uiconfig include/sal include/vcl officecfg/registry sw/source vcl/Library_vcl.mk vcl/source vcl/win

Tor Lillqvist tml at collabora.com
Wed Apr 8 02:48:10 PDT 2015


 cui/Library_cui.mk                                         |    1 
 cui/UIConfig_cui.mk                                        |    1 
 cui/source/options/optinet2.cxx                            |   18 
 cui/source/options/optinet2.hxx                            |    6 
 cui/source/options/tsaurls.cxx                             |  120 +
 cui/source/options/tsaurls.hxx                             |   40 
 cui/uiconfig/ui/optsecuritypage.ui                         |   75 
 cui/uiconfig/ui/tsaurldialog.ui                            |  230 ++
 filter/Library_pdffilter.mk                                |    4 
 filter/source/pdf/impdialog.cxx                            |   39 
 filter/source/pdf/impdialog.hxx                            |    3 
 filter/source/pdf/pdfexport.cxx                            |    3 
 filter/source/pdf/pdfexport.hxx                            |    1 
 filter/uiconfig/ui/pdfsignpage.ui                          |   28 
 include/sal/log-areas.dox                                  |    1 
 include/vcl/pdfwriter.hxx                                  |    1 
 officecfg/registry/schema/org/openoffice/Office/Common.xcs |    5 
 sw/source/core/inc/SwPortionHandler.hxx                    |    2 
 sw/source/filter/ww8/ww8atr.cxx                            |    2 
 vcl/Library_vcl.mk                                         |    5 
 vcl/source/gdi/pdfwriter_impl.cxx                          | 1437 ++++++++++++-
 vcl/win/source/app/salinst.cxx                             |    5 
 22 files changed, 1924 insertions(+), 103 deletions(-)

New commits:
commit 1da9e017e8304ce78030e9c7b2d4656da4b58da4
Author: Tor Lillqvist <tml at collabora.com>
Date:   Mon Feb 16 18:07:47 2015 +0200

    tdf#88428: Add GUI to select one of user-configured Time Stamp Authorities
    
    Work in progress. The selection not used for anything yet.
    
    (cherry picked from commit b8b9d51b8cf1cafe1a94e1baf957f3f282abb32f)
    
    Change-Id: Ia86fa0f59dcfee8e9d332a028a3fad37f4019fe0

diff --git a/cui/source/options/tsaurls.cxx b/cui/source/options/tsaurls.cxx
index 9db3801..09b5b1b 100644
--- a/cui/source/options/tsaurls.cxx
+++ b/cui/source/options/tsaurls.cxx
@@ -50,7 +50,7 @@ TSAURLsDialog::TSAURLsDialog(vcl::Window* pParent)
 
 IMPL_LINK_NOARG(TSAURLsDialog, OKHdl_Impl)
 {
-    std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
+    boost::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
 
     css::uno::Sequence<OUString> aNewValue(m_aURLs.size());
     size_t n(0);
diff --git a/filter/Library_pdffilter.mk b/filter/Library_pdffilter.mk
index b3a62d7..6de7d34 100644
--- a/filter/Library_pdffilter.mk
+++ b/filter/Library_pdffilter.mk
@@ -30,6 +30,10 @@ $(eval $(call gb_Library_set_include,pdffilter,\
 	$$(INCLUDE) \
 ))
 
+$(eval $(call gb_Library_use_custom_headers,pdffilter,\
+	officecfg/registry \
+))
+
 $(eval $(call gb_Library_use_libraries,pdffilter,\
 	svt \
 	sfx \
diff --git a/filter/source/pdf/impdialog.cxx b/filter/source/pdf/impdialog.cxx
index b28e84b..b3ab73d 100644
--- a/filter/source/pdf/impdialog.cxx
+++ b/filter/source/pdf/impdialog.cxx
@@ -21,6 +21,7 @@
 
 #include "impdialog.hxx"
 #include "impdialog.hrc"
+#include <officecfg/Office/Common.hxx>
 #include <vcl/layout.hxx>
 #include <vcl/settings.hxx>
 #include <vcl/svapp.hxx>
@@ -1542,10 +1543,12 @@ ImpPDFTabSigningPage::ImpPDFTabSigningPage(vcl::Window* pParent, const SfxItemSe
     get(mpEdSignLocation, "location");
     get(mpEdSignContactInfo, "contact");
     get(mpEdSignReason, "reason");
+    get(mpLBSignTSA, "tsa");
 
     mpPbSignCertSelect->Enable( true );
     mpPbSignCertSelect->SetClickHdl( LINK( this, ImpPDFTabSigningPage, ClickmaPbSignCertSelect ) );
     mpPbSignCertClear->SetClickHdl( LINK( this, ImpPDFTabSigningPage, ClickmaPbSignCertClear ) );
+    mpLBSignTSA->SetSelectHdl( LINK( this, ImpPDFTabSigningPage, SelectLBSignTSA ) );
 }
 
 
@@ -1570,6 +1573,24 @@ IMPL_LINK_NOARG( ImpPDFTabSigningPage, ClickmaPbSignCertSelect )
         mpEdSignPassword->Enable( true );
         mpEdSignContactInfo->Enable( true );
         mpEdSignReason->Enable( true );
+
+        try
+        {
+            css::uno::Sequence<OUString> aTSAURLs(officecfg::Office::Common::Security::Scripting::TSAURLs::get());
+
+            for (auto i = aTSAURLs.begin(); i != aTSAURLs.end(); ++i)
+            {
+                mpLBSignTSA->InsertEntry( *i );
+            }
+        }
+        catch (const uno::Exception &e)
+        {
+            SAL_INFO("filter.pdf", "TSAURLsDialog::TSAURLsDialog(): caught exception" << e.Message);
+        }
+
+        // If more than only the "None" entry is there, enable the ListBox
+        if (mpLBSignTSA->GetEntryCount() > 1)
+            mpLBSignTSA->Enable();
     }
 
     return 0;
@@ -1584,11 +1605,17 @@ IMPL_LINK_NOARG( ImpPDFTabSigningPage, ClickmaPbSignCertClear )
     mpEdSignPassword->Enable( false );
     mpEdSignContactInfo->Enable( false );
     mpEdSignReason->Enable( false );
+    mpLBSignTSA->Enable( false );
 
     return 0;
 }
 
 
+IMPL_LINK_NOARG( ImpPDFTabSigningPage, SelectLBSignTSA )
+{
+    return 0;
+}
+
 SfxTabPage*  ImpPDFTabSigningPage::Create( vcl::Window* pParent,
                                           const SfxItemSet* rAttrSet)
 {
@@ -1617,6 +1644,7 @@ void ImpPDFTabSigningPage::SetFilterConfigItem( const  ImpPDFTabDialog* paParent
     mpEdSignPassword->Enable( false );
     mpEdSignContactInfo->Enable( false );
     mpEdSignReason->Enable( false );
+    mpLBSignTSA->Enable( false );
     mpPbSignCertClear->Enable( false );
 
     if (paParent->mbSignPDF)
diff --git a/filter/source/pdf/impdialog.hxx b/filter/source/pdf/impdialog.hxx
index 0fdd9d3..dc4a787 100644
--- a/filter/source/pdf/impdialog.hxx
+++ b/filter/source/pdf/impdialog.hxx
@@ -420,10 +420,12 @@ class ImpPDFTabSigningPage : public SfxTabPage
     Edit*                       mpEdSignLocation;
     Edit*                       mpEdSignContactInfo;
     Edit*                       mpEdSignReason;
+    ListBox*                    mpLBSignTSA;
     com::sun::star::uno::Reference< com::sun::star::security::XCertificate > maSignCertificate;
 
     DECL_LINK( ClickmaPbSignCertSelect, void* );
     DECL_LINK( ClickmaPbSignCertClear, void* );
+    DECL_LINK( SelectLBSignTSA, void* );
 
 public:
     ImpPDFTabSigningPage( vcl::Window* pParent,
diff --git a/filter/uiconfig/ui/pdfsignpage.ui b/filter/uiconfig/ui/pdfsignpage.ui
index 4090c85..fe10e29 100644
--- a/filter/uiconfig/ui/pdfsignpage.ui
+++ b/filter/uiconfig/ui/pdfsignpage.ui
@@ -151,6 +151,20 @@
                   </packing>
                 </child>
                 <child>
+                  <object class="GtkComboBoxText" id="tsa">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="has_entry">False</property>
+                    <items>
+                      <item translatable="yes">None</item>
+                    </items>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="top_attach">4</property>
+                  </packing>
+                </child>
+                <child>
                   <object class="GtkLabel" id="label7">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
@@ -206,6 +220,20 @@
                     <property name="top_attach">3</property>
                   </packing>
                 </child>
+                <child>
+                  <object class="GtkLabel" id="label15">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">1</property>
+                    <property name="label" translatable="yes">Time Stamp Authority:</property>
+                    <property name="use_underline">True</property>
+                    <property name="mnemonic_widget">reason</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">4</property>
+                  </packing>
+                </child>
               </object>
               <packing>
                 <property name="left_attach">0</property>
diff --git a/include/sal/log-areas.dox b/include/sal/log-areas.dox
index baea1d4..3d2a060 100644
--- a/include/sal/log-areas.dox
+++ b/include/sal/log-areas.dox
@@ -175,6 +175,7 @@ certain functionality.
 @li @c filter.ms - escher import/export
 @li @c filter.odfflatxml
 @li @c filter.os2met
+ at li @c filter.pdf
 @li @c filter.pict
 @li @c filter.tiff
 @li @c filter.xslt - xslt import/export
commit 1391fd84ef6d9e60bdc28d1b93fbed80420bd3fd
Author: Tor Lillqvist <tml at collabora.com>
Date:   Mon Feb 16 14:02:23 2015 +0200

    tdf#88427: Add GUI to enter and maintain a list of Time Stamping Authorities
    
    It is just a simple list of entered URLs, accessed from the Security page. No
    sanity checks for now. No selection of a "default" one for now. Implementation
    is much simpler this way. The actual selection of one TSA (or none) is done
    when exporting to PDF.
    
    Change-Id: I0392eabc9b9629a6f0a767d1b2337622a61c120f
    (cherry picked from commit 24ad0629ae9edad83514e329e7173b94a8680ea6)

diff --git a/cui/Library_cui.mk b/cui/Library_cui.mk
index 6df06f9..833af3c 100644
--- a/cui/Library_cui.mk
+++ b/cui/Library_cui.mk
@@ -168,6 +168,7 @@ $(eval $(call gb_Library_add_exception_objects,cui,\
     cui/source/options/sdbcdriverenum \
     cui/source/options/securityoptions \
     cui/source/options/treeopt \
+    cui/source/options/tsaurls \
     cui/source/options/webconninfo \
     cui/source/tabpages/align \
     cui/source/tabpages/autocdlg \
diff --git a/cui/UIConfig_cui.mk b/cui/UIConfig_cui.mk
index d8cd178..36f5942 100644
--- a/cui/UIConfig_cui.mk
+++ b/cui/UIConfig_cui.mk
@@ -197,6 +197,7 @@ $(eval $(call gb_UIConfig_add_uifiles,cui,\
 	cui/uiconfig/ui/textflowpage \
 	cui/uiconfig/ui/thesaurus \
 	cui/uiconfig/ui/transparencytabpage \
+	cui/uiconfig/ui/tsaurldialog \
 	cui/uiconfig/ui/twolinespage \
 	cui/uiconfig/ui/wordcompletionpage \
 	cui/uiconfig/ui/zoomdialog \
diff --git a/cui/source/options/optinet2.cxx b/cui/source/options/optinet2.cxx
index d1b3b5c..10b6f67 100644
--- a/cui/source/options/optinet2.cxx
+++ b/cui/source/options/optinet2.cxx
@@ -85,6 +85,7 @@
 #include "securityoptions.hxx"
 #include "webconninfo.hxx"
 #include "certpath.hxx"
+#include "tsaurls.hxx"
 
 using namespace ::com::sun::star;
 using namespace ::com::sun::star::uno;
@@ -601,6 +602,8 @@ SvxSecurityTabPage::SvxSecurityTabPage(vcl::Window* pParent, const SfxItemSet& r
     get(m_pMacroSecPB, "macro");
     get(m_pCertFrame, "certificatepath");
     get(m_pCertPathPB, "cert");
+    get(m_pTSAURLsFrame, "tsaurls");
+    get(m_pTSAURLsPB, "tsas");
     m_sPasswordStoringDeactivateStr = get<FixedText>("nopasswordsave")->GetText();
 
     InitControls();
@@ -612,6 +615,7 @@ SvxSecurityTabPage::SvxSecurityTabPage(vcl::Window* pParent, const SfxItemSet& r
     m_pShowConnectionsPB->SetClickHdl( LINK( this, SvxSecurityTabPage, ShowPasswordsHdl ) );
     m_pMacroSecPB->SetClickHdl( LINK( this, SvxSecurityTabPage, MacroSecPBHdl ) );
     m_pCertPathPB->SetClickHdl( LINK( this, SvxSecurityTabPage, CertPathPBHdl ) );
+    m_pTSAURLsPB->SetClickHdl( LINK( this, SvxSecurityTabPage, TSAURLsPBHdl ) );
 
     ActivatePage( rSet );
 }
@@ -782,6 +786,20 @@ IMPL_LINK_NOARG(SvxSecurityTabPage, CertPathPBHdl)
     return 0;
 }
 
+IMPL_LINK_NOARG(SvxSecurityTabPage, TSAURLsPBHdl)
+{
+    // Unlike the mpCertPathDlg, we *don't* keep the same dialog object around between
+    // invocations. Seems clearer to my little brain that way.
+
+    TSAURLsDialog* pTSAURLsDlg = new TSAURLsDialog(this);
+
+    pTSAURLsDlg->Execute();
+
+    delete pTSAURLsDlg;
+
+    return 0;
+}
+
 IMPL_LINK_NOARG(SvxSecurityTabPage, MacroSecPBHdl)
 {
     try
diff --git a/cui/source/options/optinet2.hxx b/cui/source/options/optinet2.hxx
index c7d81b7..5bb9c05 100644
--- a/cui/source/options/optinet2.hxx
+++ b/cui/source/options/optinet2.hxx
@@ -123,9 +123,7 @@ protected:
 // class SvxSecurityTabPage ---------------------------------------------
 
 class SvtSecurityOptions;
-
 class CertPathDialog;
-
 class SvxSecurityTabPage : public SfxTabPage
 {
     using TabPage::ActivatePage;
@@ -147,6 +145,9 @@ private:
     VclContainer*       m_pCertFrame;
     PushButton*         m_pCertPathPB;
 
+    VclContainer*       m_pTSAURLsFrame;
+    PushButton*         m_pTSAURLsPB;
+
     SvtSecurityOptions*         mpSecOptions;
     svx::SecurityOptionsDialog* mpSecOptDlg;
 
@@ -161,6 +162,7 @@ private:
     DECL_LINK(ShowPasswordsHdl, void *);
     DECL_LINK(MacroSecPBHdl, void* );
     DECL_LINK(CertPathPBHdl, void* );
+    DECL_LINK(TSAURLsPBHdl, void* );
 
     void                InitControls();
 
diff --git a/cui/source/options/tsaurls.cxx b/cui/source/options/tsaurls.cxx
new file mode 100644
index 0000000..9db3801
--- /dev/null
+++ b/cui/source/options/tsaurls.cxx
@@ -0,0 +1,120 @@
+/* -*- 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 <officecfg/Office/Common.hxx>
+#include <svx/svxdlg.hxx>
+#include <cuires.hrc>
+
+#include "tsaurls.hxx"
+
+#include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
+
+using namespace ::com::sun::star;
+
+TSAURLsDialog::TSAURLsDialog(vcl::Window* pParent)
+    : ModalDialog(pParent, "TSAURLDialog", "cui/ui/tsaurldialog.ui")
+{
+    get(m_pAddBtn, "add");
+    get(m_pDeleteBtn, "delete");
+    get(m_pOKBtn, "ok");
+    get(m_pURLListBox, "urls");
+
+    m_pURLListBox->SetDropDownLineCount(8);
+    m_pURLListBox->set_width_request(m_pURLListBox->approximate_char_width() * 32);
+    m_pOKBtn->Disable();
+
+    m_pAddBtn->SetClickHdl( LINK( this, TSAURLsDialog, AddHdl_Impl ) );
+    m_pDeleteBtn->SetClickHdl( LINK( this, TSAURLsDialog, DeleteHdl_Impl ) );
+    m_pOKBtn->SetClickHdl( LINK( this, TSAURLsDialog, OKHdl_Impl ) );
+
+    try
+    {
+        css::uno::Sequence<OUString> aUserSetTSAURLs(officecfg::Office::Common::Security::Scripting::TSAURLs::get());
+
+        for (auto i = aUserSetTSAURLs.begin(); i != aUserSetTSAURLs.end(); ++i)
+        {
+            AddTSAURL(*i);
+        }
+    }
+    catch (const uno::Exception &e)
+    {
+        SAL_WARN("cui.options", "TSAURLsDialog::TSAURLsDialog(): caught exception" << e.Message);
+    }
+}
+
+IMPL_LINK_NOARG(TSAURLsDialog, OKHdl_Impl)
+{
+    std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
+
+    css::uno::Sequence<OUString> aNewValue(m_aURLs.size());
+    size_t n(0);
+
+    for (auto i = m_aURLs.cbegin(); i != m_aURLs.cend(); ++i)
+        aNewValue[n++] = *i;
+    officecfg::Office::Common::Security::Scripting::TSAURLs::set(aNewValue, batch);
+    batch->commit();
+
+    EndDialog(RET_OK);
+
+    return 0;
+}
+
+TSAURLsDialog::~TSAURLsDialog()
+{
+}
+
+void TSAURLsDialog::AddTSAURL(const OUString& rURL)
+{
+    m_aURLs.insert(rURL);
+
+    m_pURLListBox->SetUpdateMode(false);
+    m_pURLListBox->Clear();
+
+    for (auto i = m_aURLs.cbegin(); i != m_aURLs.cend(); ++i)
+    {
+        m_pURLListBox->InsertEntry(*i);
+    }
+
+    m_pURLListBox->SetUpdateMode(true);
+}
+
+IMPL_LINK_NOARG(TSAURLsDialog, AddHdl_Impl)
+{
+    OUString aURL;
+    OUString aDesc( get<FixedText>("enteraurl")->GetText() );
+
+    SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+    boost::scoped_ptr<AbstractSvxNameDialog> pDlg(pFact->CreateSvxNameDialog( m_pAddBtn, aURL, aDesc));
+
+    if ( pDlg->Execute() == RET_OK )
+    {
+        pDlg->GetName( aURL );
+
+        AddTSAURL(aURL);
+        m_pOKBtn->Enable();
+    }
+
+    return 0;
+}
+
+IMPL_LINK_NOARG(TSAURLsDialog, DeleteHdl_Impl)
+{
+    sal_Int32 nSel = m_pURLListBox->GetSelectEntryPos();
+
+    if (nSel == LISTBOX_ENTRY_NOTFOUND)
+        return 0;
+
+    m_aURLs.erase(m_pURLListBox->GetEntry(nSel));
+    m_pURLListBox->RemoveEntry(nSel);
+    m_pOKBtn->Enable();
+
+    return 0;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/source/options/tsaurls.hxx b/cui/source/options/tsaurls.hxx
new file mode 100644
index 0000000..aba7491
--- /dev/null
+++ b/cui/source/options/tsaurls.hxx
@@ -0,0 +1,40 @@
+/* -*- 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_CUI_SOURCE_OPTIONS_TSAURLS_HXX
+#define INCLUDED_CUI_SOURCE_OPTIONS_TSAURLS_HXX
+
+#include <vcl/lstbox.hxx>
+#include <vcl/button.hxx>
+
+class TSAURLsDialog : public ModalDialog
+{
+private:
+    ListBox* m_pURLListBox;
+    PushButton* m_pAddBtn;
+    PushButton* m_pDeleteBtn;
+    OKButton*   m_pOKBtn;
+
+    DECL_LINK(AddHdl_Impl, void *);
+    DECL_LINK(DeleteHdl_Impl, void *);
+    DECL_LINK(OKHdl_Impl, void *);
+
+    std::set<OUString> m_aURLs;
+
+    void AddTSAURL(const OUString &rURL);
+
+public:
+    TSAURLsDialog(vcl::Window* pParent);
+    virtual ~TSAURLsDialog();
+
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/cui/uiconfig/ui/optsecuritypage.ui b/cui/uiconfig/ui/optsecuritypage.ui
index 007bbc6..46b342a 100644
--- a/cui/uiconfig/ui/optsecuritypage.ui
+++ b/cui/uiconfig/ui/optsecuritypage.ui
@@ -8,6 +8,81 @@
     <property name="border_width">6</property>
     <property name="row_spacing">12</property>
     <child>
+      <object class="GtkFrame" id="tsaurls">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="hexpand">True</property>
+        <property name="label_xalign">0</property>
+        <property name="shadow_type">none</property>
+        <child>
+          <object class="GtkAlignment" id="alignment5">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="hexpand">True</property>
+            <property name="top_padding">6</property>
+            <property name="left_padding">12</property>
+            <child>
+              <object class="GtkGrid" id="grid8">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="hexpand">True</property>
+                <property name="column_spacing">24</property>
+                <child>
+                  <object class="GtkLabel" id="label9">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="hexpand">True</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes">Maintain a list of Time Stamping Authority (TSA) URLs to be optionally for digital signatures in PDF export.</property>
+                    <property name="wrap">True</property>
+                    <property name="max_width_chars">56</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">0</property>
+                    <property name="top_attach">0</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkButton" id="tsas">
+                    <property name="label" translatable="yes">_TSAs...</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="valign">center</property>
+                    <property name="use_underline">True</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="top_attach">0</property>
+                    <property name="width">1</property>
+                    <property name="height">1</property>
+                  </packing>
+                </child>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child type="label">
+          <object class="GtkLabel" id="label10">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">TSAs</property>
+            <attributes>
+              <attribute name="weight" value="bold"/>
+            </attributes>
+          </object>
+        </child>
+      </object>
+      <packing>
+        <property name="left_attach">0</property>
+        <property name="top_attach">4</property>
+        <property name="width">1</property>
+        <property name="height">1</property>
+      </packing>
+    </child>
+    <child>
       <object class="GtkFrame" id="certificatepath">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
diff --git a/cui/uiconfig/ui/tsaurldialog.ui b/cui/uiconfig/ui/tsaurldialog.ui
new file mode 100644
index 0000000..37ed401
--- /dev/null
+++ b/cui/uiconfig/ui/tsaurldialog.ui
@@ -0,0 +1,230 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.16.1 -->
+<interface>
+  <requires lib="gtk+" version="3.0"/>
+  <!-- interface-requires LibreOffice 1.0 -->
+  <object class="GtkDialog" id="TSAURLDialog">
+    <property name="can_focus">False</property>
+    <property name="border_width">6</property>
+    <property name="title" translatable="yes">Time Stamping Authority URLs</property>
+    <property name="type_hint">normal</property>
+    <child internal-child="vbox">
+      <object class="GtkBox" id="dialog-vbox1">
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">12</property>
+        <child internal-child="action_area">
+          <object class="GtkButtonBox" id="dialog-action_area1">
+            <property name="can_focus">False</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="ok">
+                <property name="label">gtk-ok</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="can_default">True</property>
+                <property name="has_default">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="cancel">
+                <property name="label">gtk-cancel</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="help">
+                <property name="label">gtk-help</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">2</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="add">
+                <property name="label" translatable="yes">_Add...</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="can_default">True</property>
+                <property name="has_default">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_underline">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">3</property>
+                <property name="secondary">True</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="delete">
+                <property name="label" translatable="yes">_Delete...</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="can_default">True</property>
+                <property name="has_default">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_underline">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">4</property>
+                <property name="secondary">True</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkFrame" id="frame1">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="hexpand">True</property>
+            <property name="vexpand">True</property>
+            <property name="label_xalign">0</property>
+            <property name="shadow_type">none</property>
+            <child>
+              <object class="GtkAlignment" id="alignment1">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="hexpand">True</property>
+                <property name="vexpand">True</property>
+                <property name="top_padding">6</property>
+                <property name="left_padding">12</property>
+                <child>
+                  <object class="GtkGrid" id="grid1">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="hexpand">True</property>
+                    <property name="vexpand">True</property>
+                    <property name="row_spacing">6</property>
+                    <child>
+                      <object class="GtkLabel" id="label2">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="xalign">0</property>
+                        <property name="yalign">0</property>
+                        <property name="label" translatable="yes">Add or delete Time Stamp Authority URLs</property>
+                        <property name="use_underline">True</property>
+                        <property name="wrap">True</property>
+                        <property name="mnemonic_widget">paths</property>
+                        <property name="max_width_chars">60</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">0</property>
+                        <property name="width">1</property>
+                        <property name="height">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkGrid" id="grid2">
+                        <property name="can_focus">False</property>
+                        <property name="no_show_all">True</property>
+                        <child>
+                          <object class="GtkLabel" id="enteraurl">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="hexpand">True</property>
+                            <property name="label" translatable="yes">Enter a Time Stamp Authority URL</property>
+                          </object>
+                          <packing>
+                            <property name="left_attach">2</property>
+                            <property name="top_attach">0</property>
+                            <property name="width">1</property>
+                            <property name="height">1</property>
+                          </packing>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="left_attach">0</property>
+                        <property name="top_attach">1</property>
+                        <property name="width">1</property>
+                        <property name="height">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkScrolledWindow" id="scrolledwindow1">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="hexpand">True</property>
+                        <property name="vexpand">True</property>
+                        <property name="shadow_type">in</property>
+                        <child>
+                          <object class="GtkTreeView" id="urls:border">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="hexpand">True</property>
+                            <property name="vexpand">True</property>
+                            <child internal-child="selection">
+                              <object class="GtkTreeSelection" id="urls-selection"/>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="left_attach">0</property>
+                            <property name="top_attach">2</property>
+                            <property name="width">1</property>
+                            <property name="height">1</property>
+                          </packing>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child type="label">
+              <object class="GtkLabel" id="label1">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">TSA URL</property>
+                <attributes>
+                  <attribute name="weight" value="bold"/>
+                </attributes>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="0">ok</action-widget>
+      <action-widget response="0">cancel</action-widget>
+      <action-widget response="0">help</action-widget>
+      <action-widget response="0">add</action-widget>
+    </action-widgets>
+  </object>
+</interface>
diff --git a/officecfg/registry/schema/org/openoffice/Office/Common.xcs b/officecfg/registry/schema/org/openoffice/Office/Common.xcs
index d16fc17..fc9a67b 100644
--- a/officecfg/registry/schema/org/openoffice/Office/Common.xcs
+++ b/officecfg/registry/schema/org/openoffice/Office/Common.xcs
@@ -2510,6 +2510,11 @@
             <desc>Contains the path to the users NSS certificate directory.</desc>
           </info>
         </prop>
+        <prop oor:name="TSAURLs" oor:type="oor:string-list" oor:nillable="false">
+          <info>
+            <desc>Contains the URLs or Time Stamping Authority servers.</desc>
+          </info>
+        </prop>
         <prop oor:name="WarnPrintDoc" oor:type="xs:boolean" oor:nillable="false">
           <info>
             <desc>Specifies whether to warn when printing documents with
commit 06f0e92888841ec9a19bbd2af96a4667341da3ff
Author: Tor Lillqvist <tml at collabora.com>
Date:   Tue Feb 17 10:35:54 2015 +0200

    tdf#88431: Pass the selected Time Stamp Authority, if any, along to vcl
    
    Work in progress. If a TSA is selected, pass it along to the signature
    generation in vcl.
    
    Change-Id: Ibe105b6d02ab9241b93dd66ab3cb1fa8c6d10093
    (cherry picked from commit d83e6e9cdb727b3ca2938048e115ba38886d4c70)

diff --git a/filter/source/pdf/impdialog.cxx b/filter/source/pdf/impdialog.cxx
index f835d7a..b28e84b 100644
--- a/filter/source/pdf/impdialog.cxx
+++ b/filter/source/pdf/impdialog.cxx
@@ -434,7 +434,8 @@ Sequence< PropertyValue > ImpPDFTabDialog::GetFilterData()
 
     Sequence< PropertyValue > aRet( maConfigItem.GetFilterData() );
 
-    int nElementAdded = 11;
+    // OMG, this is horrible coding style...
+    int nElementAdded = 12;
 
     aRet.realloc( aRet.getLength() + nElementAdded );
 
@@ -498,6 +499,10 @@ Sequence< PropertyValue > ImpPDFTabDialog::GetFilterData()
     aRet[ nLength - nElementAdded ].Value <<= maSignCertificate;
     nElementAdded--;
 
+    aRet[ nLength - nElementAdded ].Name = "SignatureTSA";
+    aRet[ nLength - nElementAdded ].Value <<= msSignTSA;
+    nElementAdded--;
+
     return aRet;
 }
 
@@ -1599,7 +1604,9 @@ void ImpPDFTabSigningPage::GetFilterConfigItem( ImpPDFTabDialog* paParent  )
     paParent->msSignPassword = mpEdSignPassword->GetText();
     paParent->msSignContact = mpEdSignContactInfo->GetText();
     paParent->msSignReason = mpEdSignReason->GetText();
-
+    // Entry 0 is 'None'
+    if (mpLBSignTSA->GetSelectEntryPos() >= 1)
+        paParent->msSignTSA = mpLBSignTSA->GetSelectEntry();
 }
 
 
diff --git a/filter/source/pdf/impdialog.hxx b/filter/source/pdf/impdialog.hxx
index 42f5c2a..0fdd9d3 100644
--- a/filter/source/pdf/impdialog.hxx
+++ b/filter/source/pdf/impdialog.hxx
@@ -153,6 +153,7 @@ protected:
     OUString             msSignContact;
     OUString             msSignReason;
     com::sun::star::uno::Reference< com::sun::star::security::XCertificate > maSignCertificate;
+    OUString             msSignTSA;
 
     OUString             maWatermarkText;
 
diff --git a/filter/source/pdf/pdfexport.cxx b/filter/source/pdf/pdfexport.cxx
index 9e83456..b5449b7 100644
--- a/filter/source/pdf/pdfexport.cxx
+++ b/filter/source/pdf/pdfexport.cxx
@@ -556,6 +556,8 @@ bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >&
                     rFilterData[ nData ].Value >>= msSignPassword;
                 else if ( rFilterData[ nData ].Name == "SignatureCertificate" )
                     rFilterData[ nData ].Value >>= maSignCertificate;
+                else if ( rFilterData[ nData ].Name == "SignatureTSA" )
+                    rFilterData[ nData ].Value >>= msSignTSA;
             }
             aContext.URL        = aURL.GetMainURL(INetURLObject::DECODE_TO_IURI);
 
@@ -787,6 +789,7 @@ bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >&
             aContext.SignReason = msSignReason;
             aContext.SignPassword = msSignPassword;
             aContext.SignCertificate = maSignCertificate;
+            aContext.SignTSA = msSignTSA;
 
 // all context data set, time to create the printing device
             boost::scoped_ptr<PDFWriter> pPDFWriter(new PDFWriter( aContext, xEnc ));
diff --git a/filter/source/pdf/pdfexport.hxx b/filter/source/pdf/pdfexport.hxx
index 38a050d..5123bdc 100644
--- a/filter/source/pdf/pdfexport.hxx
+++ b/filter/source/pdf/pdfexport.hxx
@@ -108,6 +108,7 @@ private:
     OUString                msSignReason;
     OUString                msSignPassword;
     Reference< security::XCertificate > maSignCertificate;
+    OUString                msSignTSA;
 
     void                    ImplWriteWatermark( ::vcl::PDFWriter& rWriter, const Size& rPageSize );
 public:
diff --git a/include/vcl/pdfwriter.hxx b/include/vcl/pdfwriter.hxx
index 5b4b35d..f15e8ca 100644
--- a/include/vcl/pdfwriter.hxx
+++ b/include/vcl/pdfwriter.hxx
@@ -632,6 +632,7 @@ The following structure describes the permissions used in PDF security
                                                         // 0 here specifies a default handling
         PDFWriter::ColorMode            ColorMode;
         com::sun::star::uno::Reference< com::sun::star::security::XCertificate> SignCertificate;
+        OUString                   SignTSA;
 
         PDFWriterContext() :
                 RelFsys( false ), //i56629, i49415?, i64585?
commit 43f9c546c61f616e914aba969057e71b4aaae178
Author: Tor Lillqvist <tml at collabora.com>
Date:   Mon Mar 23 09:28:19 2015 +0200

    Add comment that a "missing" 'break' is intentional fall-through
    
    Also, add one missing 'break', which however did not have any effect on code
    semantics, as the next case label only contained a 'break' anyway. (So I guess
    it could be claimed that it is also a case of intentional fall-through...)
    
    Thanks to fedor_qd for pointing these out.
    
    Change-Id: I430a71b59c78391e92da7ca14290a4e3cdade496
    (cherry picked from commit ee2a8ecd577e5fa31d73b92252a7fb05449b6dd9)

diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index 20e3f16..ad9c5e7 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -9650,6 +9650,7 @@ void PDFWriterImpl::drawStraightTextLine( OStringBuffer& aLine, long nWidth, Fon
                 nLinePos    = HCONV( pFontEntry->maMetric.mnDUnderlineOffset1 );
                 nLinePos2   = HCONV( pFontEntry->maMetric.mnDUnderlineOffset2 );
             }
+            break;
         default:
             break;
     }
@@ -10986,6 +10987,7 @@ bool PDFWriterImpl::writeGradientFunction( GradientEmit& rObject )
             aCol[1] = rObject.m_aGradient.GetEndColor().GetGreen();
             aCol[2] = rObject.m_aGradient.GetEndColor().GetBlue();
             CHECK_RETURN( writeBuffer( aCol, 3 ) );
+            // fall-through
         case GradientStyle_LINEAR:
         {
             aCol[0] = rObject.m_aGradient.GetStartColor().GetRed();
commit a5d20560b7e85a9f1e142ca0f64f574191debfd4
Author: Tor Lillqvist <tml at collabora.com>
Date:   Thu Mar 12 00:31:18 2015 +0200

    Fix crash when timestamping PDF signature
    
    Using the NSS API for CMS and ASN.1-based stuff in general correctly is
    extremely hard. It is very easy to do things slightly wrong. Of course no
    compiler warnings are produced. You just get code that happens to work by
    accident when compiled with one compiler, but not another, or depending on
    contents of uninitialised memory, or the phase of the moon.
    
    The problem was that the "values" field of a NSSCMSAttribute struct apparently
    is supposed to point to *two* SECItem pointers, one pointing to the actual
    value, and a NULL one.
    
    Anyway, now valgrind finally does not complain about any use of uninitialised
    memory.
    
    Most likely my earlier recent commits to this file were not necessary after
    all. They just seemed to help by accident, at least at one stage. But
    whatever...
    
    Change-Id: Ic98401b5d151bbb2398f809f47699f670e9720fa
    (cherry picked from commit 33434f47ac44f5cb4612a11b1c28c4582976cb25)

diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index 21b7d6a..20e3f16 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -6874,7 +6874,9 @@ bool PDFWriterImpl::finalizeSignature()
     SECItem response_item;
     NSSCMSAttribute timestamp;
     SECItem values[2];
-    SECItem *valuesp = values;
+    SECItem *valuesp[2];
+    valuesp[0] = values;
+    valuesp[1] = NULL;
     SECOidData typetag;
 
     if( !m_aContext.SignTSA.isEmpty() )
@@ -7130,12 +7132,15 @@ bool PDFWriterImpl::finalizeSignature()
 
         // timestamp.type filled in below
 
+        // Not sure if we actually need two entries in the values array, now when valuesp is an
+        // array too, the pointer to the values array followed by a null pointer. But I don't feel
+        // like experimenting.
         values[0] = response.timeStampToken;
         values[1].type = siBuffer;
         values[1].data = NULL;
         values[1].len = 0;
 
-        timestamp.values = &valuesp;
+        timestamp.values = valuesp;
 
         typetag.oid.data = NULL;
         // id-aa-timeStampToken OBJECT IDENTIFIER ::= { iso(1)
commit a9f746c124332a2b02340068fdc391d829ae47f8
Author: Tor Lillqvist <tml at collabora.com>
Date:   Wed Mar 11 22:31:47 2015 +0200

    Don't bother with macros that are dummy on Unix in Unix-only code
    
    In NSS's <secasn1t.h>, for non-Windows:
    
     #define SEC_ASN1_SUB(x)        x
     #define SEC_ASN1_XTRN          0
     #define SEC_ASN1_MKSUB(x)
    
    Change-Id: Ie42d881cebffdd060309d6a15d8d9c319c260699
    (cherry picked from commit 20e5de21225bfd2b55fcff6afcc235b035b38134)

diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index f77de08..21b7d6a 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -6280,16 +6280,10 @@ TimeStampResp ::= SEQUENCE  {
      timeStampToken TimeStampToken OPTIONAL  }
 */
 
-SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
-SEC_ASN1_MKSUB(MessageImprint_Template)
-SEC_ASN1_MKSUB(Extensions_Template)
-SEC_ASN1_MKSUB(PKIStatusInfo_Template)
-SEC_ASN1_MKSUB(Any_Template)
-
 const SEC_ASN1Template MessageImprint_Template[] =
 {
     { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(MessageImprint) },
-    { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(MessageImprint, hashAlgorithm), SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate), 0 },
+    { SEC_ASN1_INLINE, offsetof(MessageImprint, hashAlgorithm), SECOID_AlgorithmIDTemplate, 0 },
     { SEC_ASN1_OCTET_STRING, offsetof(MessageImprint, hashedMessage), 0, 0 },
     { 0, 0, 0, 0 }
 };
@@ -6312,11 +6306,11 @@ const SEC_ASN1Template TimeStampReq_Template[] =
 {
     { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(TimeStampReq) },
     { SEC_ASN1_INTEGER, offsetof(TimeStampReq, version), 0, 0 },
-    { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(TimeStampReq, messageImprint), SEC_ASN1_SUB(MessageImprint_Template), 0 },
+    { SEC_ASN1_INLINE, offsetof(TimeStampReq, messageImprint), MessageImprint_Template, 0 },
     { SEC_ASN1_OBJECT_ID | SEC_ASN1_OPTIONAL, offsetof(TimeStampReq, reqPolicy), 0, 0 },
     { SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL, offsetof(TimeStampReq, nonce), 0, 0 },
     { SEC_ASN1_BOOLEAN | SEC_ASN1_OPTIONAL, offsetof(TimeStampReq, certReq), 0, 0 },
-    { SEC_ASN1_XTRN | SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | 0, offsetof(TimeStampReq, extensions), SEC_ASN1_SUB(Extensions_Template), 0 },
+    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | 0, offsetof(TimeStampReq, extensions), Extensions_Template, 0 },
     { 0, 0, 0, 0 }
 };
 
@@ -6348,8 +6342,8 @@ typedef struct {
 const SEC_ASN1Template TimeStampResp_Template[] =
 {
     { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(TimeStampResp) },
-    { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(TimeStampResp, status), SEC_ASN1_SUB(PKIStatusInfo_Template), 0 },
-    { SEC_ASN1_ANY | SEC_ASN1_OPTIONAL, offsetof(TimeStampResp, timeStampToken), SEC_ASN1_SUB(Any_Template), 0 },
+    { SEC_ASN1_INLINE, offsetof(TimeStampResp, status), PKIStatusInfo_Template, 0 },
+    { SEC_ASN1_ANY | SEC_ASN1_OPTIONAL, offsetof(TimeStampResp, timeStampToken), Any_Template, 0 },
     { 0, 0, 0, 0 }
 };
 
commit 77f1490d3b1442205375d797e1ce7d63166ccf69
Author: Tor Lillqvist <tml at collabora.com>
Date:   Wed Mar 11 09:56:57 2015 +0200

    Move more variables out of the timestamping block
    
    One or more pointers into them apparently gets stored into the NSSCMSMessage
    data structures during the my_NSS_CMSSignerInfo_AddUnauthAttr() call, and thus
    when the variables go out of scope said data can and will be reused for some
    arbitrary other thing, and those pointers in the NSSCMSMessage will point to
    bogus data.
    
    Avoids a crash when compiled with gcc. (No crash when compiled with Clang, it
    apparently allocates nested block stack variables differently.)
    
    (The Windows MSVC build uses a different code path entirely here.)
    
    Change-Id: Ic941d766904a216cce86ee6bd38864801b9110e8
    (cherry picked from commit 90a684b32b93988e890d854deff384addd875de9)

diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index 14917a1..f77de08 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -6874,6 +6874,10 @@ bool PDFWriterImpl::finalizeSignature()
 
     char *pass(strdup(OUStringToOString( m_aContext.SignPassword, RTL_TEXTENCODING_UTF8 ).getStr()));
 
+    TimeStampReq src;
+    OStringBuffer response_buffer;
+    TimeStampResp response;
+    SECItem response_item;
     NSSCMSAttribute timestamp;
     SECItem values[2];
     SECItem *valuesp = values;
@@ -6944,7 +6948,6 @@ bool PDFWriterImpl::finalizeSignature()
             fclose(out);
         }
 #endif
-        TimeStampReq src;
 
         unsigned char cOne = 1;
         src.version.type = siUnsignedInteger;
@@ -7045,8 +7048,6 @@ bool PDFWriterImpl::finalizeSignature()
             return false;
         }
 
-        OStringBuffer response_buffer;
-
         if ((rc = curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_buffer)) != CURLE_OK ||
             (rc = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, AppendToBuffer)) != CURLE_OK)
         {
@@ -7110,10 +7111,8 @@ bool PDFWriterImpl::finalizeSignature()
         curl_easy_cleanup(curl);
         SECITEM_FreeItem(timestamp_request, PR_TRUE);
 
-        TimeStampResp response;
         memset(&response, 0, sizeof(response));
 
-        SECItem response_item;
         response_item.type = siBuffer;
         response_item.data = reinterpret_cast<unsigned char*>(const_cast<char*>(response_buffer.getStr()));
         response_item.len = response_buffer.getLength();
commit eee4c121a71c0e4c45b88a28aa8761e9b9b9eb69
Author: Tor Lillqvist <tml at collabora.com>
Date:   Tue Mar 10 16:07:57 2015 +0200

    Fix signature overflow check in the NSS case
    
    We didn't actually check this correctly at all, but gladly overwrote the
    allocated part of the output PDF, thus obviously rendering it invalid.
    
    The parameter passed to PORT_NewArea is a default chunk size, not a maximum
    anything, so it was misleading, even if not wrong as such, to pass
    MAX_SIGNATURE_CONTENT_LENGTH to it. Use 10000 instead.
    
    No need to do the overflow check twice in the Win32 case.
    
    Change-Id: Ifa796dbb74b32e857f7184c1e8ada97ba124b020
    (cherry picked from commit 07ca1c58d779f4daa4c84895d914780a1c814944)

diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index 1c72957..14917a1 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -6897,7 +6897,7 @@ bool PDFWriterImpl::finalizeSignature()
         SECItem ts_cms_output;
         ts_cms_output.data = 0;
         ts_cms_output.len = 0;
-        PLArenaPool *ts_arena = PORT_NewArena(MAX_SIGNATURE_CONTENT_LENGTH);
+        PLArenaPool *ts_arena = PORT_NewArena(10000);
         NSSCMSEncoderContext *ts_cms_ecx;
         ts_cms_ecx = NSS_CMSEncoder_Start(ts_cms_msg, NULL, NULL, &ts_cms_output, ts_arena, PDFSigningPKCS7PasswordCallback, pass, NULL, NULL, NULL, NULL);
 
@@ -7180,7 +7180,7 @@ bool PDFWriterImpl::finalizeSignature()
     SECItem cms_output;
     cms_output.data = 0;
     cms_output.len = 0;
-    PLArenaPool *arena = PORT_NewArena(MAX_SIGNATURE_CONTENT_LENGTH);
+    PLArenaPool *arena = PORT_NewArena(10000);
     NSSCMSEncoderContext *cms_ecx;
 
     // Possibly it would work to even just pass NULL for the password callback function and its
@@ -7214,11 +7214,20 @@ bool PDFWriterImpl::finalizeSignature()
     }
 #endif
 
+    if (cms_output.len*2 > MAX_SIGNATURE_CONTENT_LENGTH)
+    {
+        SAL_WARN("vcl.pdfwriter", "Signature requires more space (" << cms_output.len*2 << ") than we reserved (" << MAX_SIGNATURE_CONTENT_LENGTH << ")");
+        NSS_CMSMessage_Destroy(cms_msg);
+        return false;
+    }
+
     OStringBuffer cms_hexbuffer;
 
     for (unsigned int i = 0; i < cms_output.len ; i++)
         appendHex(cms_output.data[i], cms_hexbuffer);
 
+    assert(cms_hexbuffer.getLength() <= MAX_SIGNATURE_CONTENT_LENGTH);
+
     // Set file pointer to the m_nSignatureContentOffset, we're ready to overwrite PKCS7 object
     nWritten = 0;
     CHECK_RETURN( (osl::File::E_None == m_aFile.setPos(osl_Pos_Absolut, m_nSignatureContentOffset)) );
@@ -7376,15 +7385,6 @@ bool PDFWriterImpl::finalizeSignature()
             return false;
         }
 
-        if (nTsSigLen*2 > MAX_SIGNATURE_CONTENT_LENGTH)
-        {
-            SAL_WARN("vcl.pdfwriter", "Signature requires more space (" << nTsSigLen*2 << ") than we reserved (" << MAX_SIGNATURE_CONTENT_LENGTH << ")");
-            CryptMsgClose(hDecodedMsg);
-            CryptMsgClose(hMsg);
-            CertFreeCertificateContext(pCertContext);
-            return false;
-        }
-
         SAL_INFO("vcl.pdfwriter", "nTsSigLen=" << nTsSigLen);
 
         boost::scoped_array<BYTE> pTsSig(new BYTE[nTsSigLen]);
commit cae2ca285c8ba43d6403573796c41f381711aa34
Author: Michael Stahl <mstahl at redhat.com>
Date:   Wed Mar 4 17:05:47 2015 +0100

    vcl: tweak some optional usage of Windows 7 or later symbols...
    
    ... so that -D_WIN32_WINNT=0x0502 does not break the build.
    
    Change-Id: I423ba9c194dc4928d59e1713255bce9c3150bcc2
    (cherry picked from commit fe045dca6124c9627c1cfa9dac4072ae75292910)

diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index 060b3c1..1c72957 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -85,6 +85,10 @@
 
 #ifdef _WIN32
 // WinCrypt headers for PDF signing
+// Note: this uses Windows 7 APIs and requires the relevant data types;
+// the functions that don't exist in WinXP must be looked up at runtime!
+#undef _WIN32_WINNT
+#define _WIN32_WINNT _WIN32_WINNT_WIN7
 #include <prewin.h>
 #include <wincrypt.h>
 #include <postwin.h>
diff --git a/vcl/win/source/app/salinst.cxx b/vcl/win/source/app/salinst.cxx
index dcb81f0..e0fd511 100644
--- a/vcl/win/source/app/salinst.cxx
+++ b/vcl/win/source/app/salinst.cxx
@@ -985,6 +985,11 @@ void WinSalInstance::AddToRecentDocumentList(const OUString& rFileUrl, const OUS
                         OUString sApplicationID("TheDocumentFoundation.LibreOffice.");
                         sApplicationID += sApplicationName;
 
+#if _WIN32_WINNT < _WIN32_WINNT_WIN7
+// just define Windows 7 only constant locally...
+#define SHARD_APPIDINFO  0x00000004
+#endif
+
                         typedef struct {
                             IShellItem *psi;
                             PCWSTR     pszAppID;
commit 09b0cfbb6db3e1412e387a8c8cc0d3eeb49c78d6
Author: Tor Lillqvist <tml at collabora.com>
Date:   Fri Feb 27 17:24:44 2015 +0200

    tdf#84881: Timestamp the right data (Win32 version)
    
    Now Adobe Reader is satisfied with the signature timestamp also for a
    PDF signed and timestamped on Windows.
    
    My gleeful commit comment from yesterday about how much simpler the
    Win32 crypto API was to use for this task was not entirely true. It is
    simpler than using NSS and curl, but not as simple as I had hoped. Oh
    well, I am not really surprised.
    
    I now use the "low-level" message functions instead of the single
    "simplified" CryptSignMessage(). And just like with NSS, I need to
    create the message twice; first to get the signature to timestamp, and
    then a second time to attach the timestamp. But now I wonder whether
    doing CryptSignMessage() twice would work too. Anyway, won't touch the
    code now for a while.
    
    I am actually a bit surprised that the code works... Must have been my
    lucky day. Or then I just am good at making educated guesses at what
    an API does, even if the documentation doesn't make it perfectly
    clear. Especially, I am a bit surprised that calling
    CryptMsgGetParam(hMsg, CMSG_BARE_CONTENT_PARAM) returns (just) the
    signature. OTOH, what else would it return?
    
    Change-Id: Iec20c7605cf3d841b9e1787184c7b665837f1bc2
    (cherry picked from commit 2c78736c19a8f2a1df0f406c3e92f5ac55576148)

diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index 7bc1119..060b3c1 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -7230,13 +7230,6 @@ bool PDFWriterImpl::finalizeSignature()
     // Prepare buffer and calculate PDF file digest
     CHECK_RETURN( (osl::File::E_None == m_aFile.setPos(osl_Pos_Absolut, 0)) );
 
-    PCCERT_CONTEXT pCertContext = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, reinterpret_cast<const BYTE*>(n_derArray), n_derLength);
-    if (pCertContext == NULL)
-    {
-        SAL_WARN("vcl.pdfwriter", "CertCreateCertificateContext failed: " << WindowsError(GetLastError()));
-        return false;
-    }
-
     boost::scoped_array<char> buffer1(new char[m_nSignatureContentOffset - 1]);
     sal_uInt64 bytesRead1;
 
@@ -7244,7 +7237,6 @@ bool PDFWriterImpl::finalizeSignature()
         bytesRead1 != (sal_uInt64)m_nSignatureContentOffset - 1)
     {
         SAL_WARN("vcl.pdfwriter", "First buffer read failed");
-        CertFreeCertificateContext(pCertContext);
         return false;
     }
 
@@ -7256,12 +7248,18 @@ bool PDFWriterImpl::finalizeSignature()
         bytesRead2 != (sal_uInt64) nLastByteRangeNo)
     {
         SAL_WARN("vcl.pdfwriter", "Second buffer read failed");
-        CertFreeCertificateContext(pCertContext);
         return false;
     }
 
     OString pass = OUStringToOString( m_aContext.SignPassword, RTL_TEXTENCODING_UTF8 );
 
+    PCCERT_CONTEXT pCertContext = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, reinterpret_cast<const BYTE*>(n_derArray), n_derLength);
+    if (pCertContext == NULL)
+    {
+        SAL_WARN("vcl.pdfwriter", "CertCreateCertificateContext failed: " << WindowsError(GetLastError()));
+        return false;
+    }
+
     CRYPT_SIGN_MESSAGE_PARA aPara;
 
     memset(&aPara, 0, sizeof(aPara));
@@ -7273,45 +7271,70 @@ bool PDFWriterImpl::finalizeSignature()
     aPara.cMsgCert = 1;
     aPara.rgpMsgCert = &pCertContext;
 
-    const BYTE *aBuffers[] =
-        { reinterpret_cast<BYTE*>(buffer1.get()), reinterpret_cast<BYTE*>(buffer2.get()) };
-    DWORD aBufferLens[] =
-        { bytesRead1, bytesRead2 };
-    assert(SAL_N_ELEMENTS(aBuffers) == SAL_N_ELEMENTS(aBufferLens));
-
-    DWORD nSigLen(0);
+    HCRYPTPROV hCryptProv;
+    DWORD nKeySpec;
+    BOOL bFreeNeeded;
 
-    if (!CryptSignMessage(&aPara, TRUE, SAL_N_ELEMENTS(aBuffers), aBuffers, aBufferLens, NULL, &nSigLen))
+    if (!CryptAcquireCertificatePrivateKey(pCertContext,
+                                           CRYPT_ACQUIRE_CACHE_FLAG,
+                                           NULL,
+                                           &hCryptProv,
+                                           &nKeySpec,
+                                           &bFreeNeeded))
     {
-        SAL_WARN("vcl.pdfwriter", "CryptSignMessage failed: " << WindowsError(GetLastError()));
+        SAL_WARN("vcl.pdfwriter", "CryptAcquireCertificatePrivateKey failed: " << WindowsError(GetLastError()));
         CertFreeCertificateContext(pCertContext);
         return false;
     }
+    assert(!bFreeNeeded);
 
-    if (nSigLen*2 > MAX_SIGNATURE_CONTENT_LENGTH)
+    CMSG_SIGNER_ENCODE_INFO aSignerInfo;
+
+    memset(&aSignerInfo, 0, sizeof(aSignerInfo));
+    aSignerInfo.cbSize = sizeof(aSignerInfo);
+    aSignerInfo.pCertInfo = pCertContext->pCertInfo;
+    aSignerInfo.hCryptProv = hCryptProv;
+    aSignerInfo.dwKeySpec = nKeySpec;
+    aSignerInfo.HashAlgorithm.pszObjId = szOID_RSA_SHA1RSA;
+    aSignerInfo.HashAlgorithm.Parameters.cbData = 0;
+
+    CMSG_SIGNED_ENCODE_INFO aSignedInfo;
+    memset(&aSignedInfo, 0, sizeof(aSignedInfo));
+    aSignedInfo.cbSize = sizeof(aSignedInfo);
+    aSignedInfo.cSigners = 1;
+    aSignedInfo.rgSigners = &aSignerInfo;
+
+    CERT_BLOB aCertBlob;
+
+    aCertBlob.cbData = pCertContext->cbCertEncoded;
+    aCertBlob.pbData = pCertContext->pbCertEncoded;
+
+    aSignedInfo.cCertEncoded = 1;
+    aSignedInfo.rgCertEncoded = &aCertBlob;
+
+    HCRYPTMSG hMsg;
+    if (!(hMsg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
+                                      CMSG_DETACHED_FLAG,
+                                      CMSG_SIGNED,
+                                      &aSignedInfo,
+                                      NULL,
+                                      NULL)))
     {
-        SAL_WARN("vcl.pdfwriter", "Signature requires more space (" << nSigLen*2 << ") than we reserved (" << MAX_SIGNATURE_CONTENT_LENGTH << ")");
+        SAL_WARN("vcl.pdfwriter", "CryptMsgOpenToEncode failed: " << WindowsError(GetLastError()));
         CertFreeCertificateContext(pCertContext);
         return false;
     }
 
-    SAL_INFO("vcl.pdfwriter", "Signature size is " << nSigLen << " bytes");
-
-    boost::scoped_array<BYTE> pSig(new BYTE[nSigLen]);
-    if (!CryptSignMessage(&aPara, TRUE, SAL_N_ELEMENTS(aBuffers), aBuffers, aBufferLens, pSig.get(), &nSigLen))
+    if (!CryptMsgUpdate(hMsg, (const BYTE *)buffer1.get(), bytesRead1, FALSE) ||
+        !CryptMsgUpdate(hMsg, (const BYTE *)buffer2.get(), bytesRead2, TRUE))
     {
-        SAL_WARN("vcl.pdfwriter", "CryptSignMessage failed: " << WindowsError(GetLastError()));
+        SAL_WARN("vcl.pdfwriter", "CryptMsgUpdate failed: " << WindowsError(GetLastError()));
+        CryptMsgClose(hMsg);
         CertFreeCertificateContext(pCertContext);
         return false;
     }
 
-#ifdef DBG_UTIL
-    {
-        FILE *out = fopen("PDFWRITER.signature.data", "wb");
-        fwrite(pSig.get(), nSigLen, 1, out);
-        fclose(out);
-    }
-#endif
+    PCRYPT_TIMESTAMP_CONTEXT pTsContext = NULL;
 
     if( !m_aContext.SignTSA.isEmpty() )
     {
@@ -7319,104 +7342,215 @@ bool PDFWriterImpl::finalizeSignature()
         if (!crts)
         {
             SAL_WARN("vcl.pdfwriter", "Could not find the CryptRetrieveTimeStamp function in crypt32.dll: " << WindowsError(GetLastError()));
+            CryptMsgClose(hMsg);
             CertFreeCertificateContext(pCertContext);
             return false;
         }
-        else
+
+        HCRYPTMSG hDecodedMsg;
+        if (!(hDecodedMsg = CryptMsgOpenToDecode(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
+                                                 CMSG_DETACHED_FLAG,
+                                                 CMSG_SIGNED,
+                                                 NULL,
+                                                 NULL,
+                                                 NULL)))
         {
-            CRYPT_TIMESTAMP_PARA aTsPara;
-
-            unsigned int nNonce = comphelper::rng::uniform_uint_distribution(0, SAL_MAX_UINT32);
-
-            aTsPara.pszTSAPolicyId = NULL;
-            aTsPara.fRequestCerts = TRUE;
-            aTsPara.Nonce.cbData = sizeof(nNonce);
-            aTsPara.Nonce.pbData = (BYTE *)&nNonce;
-            aTsPara.cExtension = 0;
-            aTsPara.rgExtension = NULL;
-
-            PCRYPT_TIMESTAMP_CONTEXT pTsContext = NULL;
-
-            if (!(*crts)(m_aContext.SignTSA.getStr(),
-                         0,
-                         10000,
-                         szOID_NIST_sha256,
-                         &aTsPara,
-                         pSig.get(),
-                         nSigLen,
-                         &pTsContext,
-                         NULL,
-                         NULL))
-            {
-                SAL_WARN("vcl.pdfwriter", "CryptRetrieveTimeStamp failed: " << WindowsError(GetLastError()));
-                CertFreeCertificateContext(pCertContext);
-                return false;
-            }
+            SAL_WARN("vcl.pdfwriter", "CryptMsgOpenToDecode failed: " << WindowsError(GetLastError()));
+            CryptMsgClose(hMsg);
+            CertFreeCertificateContext(pCertContext);
+            return false;
+        }
 
-            SAL_INFO("vcl.pdfwriter", "Time stamp size is " << pTsContext->cbEncoded << " bytes");
+        DWORD nTsSigLen = 0;
 
-#ifdef DBG_UTIL
-            {
-                FILE *out = fopen("PDFWRITER.tstoken.data", "wb");
-                fwrite(pTsContext->pbEncoded, pTsContext->cbEncoded, 1, out);
-                fclose(out);
-            }
-#endif
+        if (!CryptMsgGetParam(hMsg, CMSG_BARE_CONTENT_PARAM, 0, NULL, &nTsSigLen))
+        {
+            SAL_WARN("vcl.pdfwriter", "CryptMsgGetParam(CMSG_BARE_CONTENT_PARAM) failed: " << WindowsError(GetLastError()));
+            CryptMsgClose(hDecodedMsg);
+            CryptMsgClose(hMsg);
+            CertFreeCertificateContext(pCertContext);
+            return false;
+        }
 
-            CRYPT_INTEGER_BLOB aTimestampBlob;
-            aTimestampBlob.cbData = pTsContext->cbEncoded;
-            aTimestampBlob.pbData = pTsContext->pbEncoded;
+        if (nTsSigLen*2 > MAX_SIGNATURE_CONTENT_LENGTH)
+        {
+            SAL_WARN("vcl.pdfwriter", "Signature requires more space (" << nTsSigLen*2 << ") than we reserved (" << MAX_SIGNATURE_CONTENT_LENGTH << ")");
+            CryptMsgClose(hDecodedMsg);
+            CryptMsgClose(hMsg);
+            CertFreeCertificateContext(pCertContext);
+            return false;
+        }
 
-            CRYPT_ATTRIBUTE aTimestampAttribute;
-            aTimestampAttribute.pszObjId = "1.2.840.113549.1.9.16.2.14";
-            aTimestampAttribute.cValue = 1;
-            aTimestampAttribute.rgValue = &aTimestampBlob;
+        SAL_INFO("vcl.pdfwriter", "nTsSigLen=" << nTsSigLen);
 
-            aPara.cUnauthAttr = 1;
-            aPara.rgUnauthAttr = &aTimestampAttribute;
+        boost::scoped_array<BYTE> pTsSig(new BYTE[nTsSigLen]);
 
-            nSigLen = 0;
-            if (!CryptSignMessage(&aPara, TRUE, SAL_N_ELEMENTS(aBuffers), aBuffers, aBufferLens, NULL, &nSigLen))
-            {
-                SAL_WARN("vcl.pdfwriter", "CryptSignMessage failed: " << WindowsError(GetLastError()));
-                CryptMemFree(pTsContext);
-                CertFreeCertificateContext(pCertContext);
-                return false;
-            }
+        if (!CryptMsgGetParam(hMsg, CMSG_BARE_CONTENT_PARAM, 0, pTsSig.get(), &nTsSigLen))
+        {
+            SAL_WARN("vcl.pdfwriter", "CryptMsgGetParam(CMSG_BARE_CONTENT_PARAM) failed: " << WindowsError(GetLastError()));
+            CryptMsgClose(hDecodedMsg);
+            CryptMsgClose(hMsg);
+            CertFreeCertificateContext(pCertContext);
+            return false;
+        }
 
-            if (nSigLen*2 > MAX_SIGNATURE_CONTENT_LENGTH)
-            {
-                SAL_WARN("vcl.pdfwriter", "Signature requires more space (" << nSigLen*2 << ") than we reserved (" << MAX_SIGNATURE_CONTENT_LENGTH << ")");
-                CryptMemFree(pTsContext);
-                CertFreeCertificateContext(pCertContext);
-                return false;
-            }
+        if (!CryptMsgUpdate(hDecodedMsg, pTsSig.get(), nTsSigLen, TRUE))
+        {
+            SAL_WARN("vcl.pdfwriter", "CryptMsgUpdate failed: " << WindowsError(GetLastError()));
+            CryptMsgClose(hDecodedMsg);
+            CryptMsgClose(hMsg);
+            CertFreeCertificateContext(pCertContext);
+            return false;
+        }
 
-            SAL_INFO("vcl.pdfwriter", "Signature size including timestamp is " << nSigLen << " bytes");
+        DWORD nDecodedSignerInfoLen = 0;
+        if (!CryptMsgGetParam(hDecodedMsg, CMSG_SIGNER_INFO_PARAM, 0, NULL, &nDecodedSignerInfoLen))
+        {
+            SAL_WARN("vcl.pdfwriter", "CryptMsgGetParam(CMSG_SIGNER_INFO_PARAM) failed: " << WindowsError(GetLastError()));
+            CryptMsgClose(hDecodedMsg);
+            CryptMsgClose(hMsg);
+            CertFreeCertificateContext(pCertContext);
+            return false;
+        }
 
-            pSig.reset(new BYTE[nSigLen]);
+        boost::scoped_array<BYTE> pDecodedSignerInfoBuf(new BYTE[nDecodedSignerInfoLen]);
 
-            if (!CryptSignMessage(&aPara, TRUE, SAL_N_ELEMENTS(aBuffers), aBuffers, aBufferLens, pSig.get(), &nSigLen))
-            {
-                SAL_WARN("vcl.pdfwriter", "CryptSignMessage failed: " << WindowsError(GetLastError()));
-                CryptMemFree(pTsContext);
-                CertFreeCertificateContext(pCertContext);
-                return false;
-            }
+        if (!CryptMsgGetParam(hDecodedMsg, CMSG_SIGNER_INFO_PARAM, 0, pDecodedSignerInfoBuf.get(), &nDecodedSignerInfoLen))
+        {
+            SAL_WARN("vcl.pdfwriter", "CryptMsgGetParam(CMSG_SIGNER_INFO_PARAM) failed: " << WindowsError(GetLastError()));
+            CryptMsgClose(hDecodedMsg);
+            CryptMsgClose(hMsg);
+            CertFreeCertificateContext(pCertContext);
+            return false;
+        }
+
+        CMSG_SIGNER_INFO *pDecodedSignerInfo = (CMSG_SIGNER_INFO *) pDecodedSignerInfoBuf.get();
+
+        CRYPT_TIMESTAMP_PARA aTsPara;
+        unsigned int nNonce = comphelper::rng::uniform_uint_distribution(0, SAL_MAX_UINT32);
+
+        aTsPara.pszTSAPolicyId = NULL;
+        aTsPara.fRequestCerts = TRUE;
+        aTsPara.Nonce.cbData = sizeof(nNonce);
+        aTsPara.Nonce.pbData = (BYTE *)&nNonce;
+        aTsPara.cExtension = 0;
+        aTsPara.rgExtension = NULL;
+
+        if (!(*crts)(m_aContext.SignTSA.getStr(),
+                     0,
+                     10000,
+                     szOID_NIST_sha256,
+                     &aTsPara,
+                     pDecodedSignerInfo->EncryptedHash.pbData,
+                     pDecodedSignerInfo->EncryptedHash.cbData,
+                     &pTsContext,
+                     NULL,
+                     NULL))
+        {
+            SAL_WARN("vcl.pdfwriter", "CryptRetrieveTimeStamp failed: " << WindowsError(GetLastError()));
+            CryptMsgClose(hDecodedMsg);
+            CryptMsgClose(hMsg);
+            CertFreeCertificateContext(pCertContext);
+            return false;
+        }
+
+        SAL_INFO("vcl.pdfwriter", "Time stamp size is " << pTsContext->cbEncoded << " bytes");
 
 #ifdef DBG_UTIL
-            {
-                FILE *out = fopen("PDFWRITER.ts_signature.data", "wb");
-                fwrite(pSig.get(), nSigLen, 1, out);
-                fclose(out);
-            }
+        {
+            FILE *out = fopen("PDFWRITER.tstoken.data", "wb");
+            fwrite(pTsContext->pbEncoded, pTsContext->cbEncoded, 1, out);
+            fclose(out);
+        }
 #endif
 
+        // I tried to use CryptMsgControl() with CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR to add the
+        // timestamp, but that failed with "The parameter is incorrect". Probably it is too late to
+        // modify the message once its data has already been encoded as part of the
+        // CryptMsgGetParam() with CMSG_BARE_CONTENT_PARAM above. So close the message and re-do its
+        // creation steps, but now with an amended aSignerInfo.
+
+        CRYPT_INTEGER_BLOB aTimestampBlob;
+        aTimestampBlob.cbData = pTsContext->cbEncoded;
+        aTimestampBlob.pbData = pTsContext->pbEncoded;
+
+        CRYPT_ATTRIBUTE aTimestampAttribute;
+        aTimestampAttribute.pszObjId = "1.2.840.113549.1.9.16.2.14";
+        aTimestampAttribute.cValue = 1;
+        aTimestampAttribute.rgValue = &aTimestampBlob;
+
+        aSignerInfo.cUnauthAttr = 1;
+        aSignerInfo.rgUnauthAttr = &aTimestampAttribute;
+
+        CryptMsgClose(hMsg);
+
+        if (!(hMsg = CryptMsgOpenToEncode(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
+                                          CMSG_DETACHED_FLAG,
+                                          CMSG_SIGNED,
+                                          &aSignedInfo,
+                                          NULL,
+                                          NULL)) ||
+            !CryptMsgUpdate(hMsg, (const BYTE *)buffer1.get(), bytesRead1, FALSE) ||
+            !CryptMsgUpdate(hMsg, (const BYTE *)buffer2.get(), bytesRead2, TRUE))
+        {
+            SAL_WARN("vcl.pdfwriter", "Re-creating the message failed: " << WindowsError(GetLastError()));
             CryptMemFree(pTsContext);
+            CryptMsgClose(hDecodedMsg);
+            CryptMsgClose(hMsg);
+            CertFreeCertificateContext(pCertContext);
+            return false;
         }
+
+        CryptMsgClose(hDecodedMsg);
     }
 
+    DWORD nSigLen = 0;
+
+    if (!CryptMsgGetParam(hMsg, CMSG_CONTENT_PARAM, 0, NULL, &nSigLen))
+    {
+        SAL_WARN("vcl.pdfwriter", "CryptMsgGetParam(CMSG_CONTENT_PARAM) failed: " << WindowsError(GetLastError()));
+        if (pTsContext)
+            CryptMemFree(pTsContext);
+        CryptMsgClose(hMsg);
+        CertFreeCertificateContext(pCertContext);
+        return false;
+    }
+
+    if (nSigLen*2 > MAX_SIGNATURE_CONTENT_LENGTH)
+    {
+        SAL_WARN("vcl.pdfwriter", "Signature requires more space (" << nSigLen*2 << ") than we reserved (" << MAX_SIGNATURE_CONTENT_LENGTH << ")");
+        if (pTsContext)
+            CryptMemFree(pTsContext);
+        CryptMsgClose(hMsg);
+        CertFreeCertificateContext(pCertContext);
+        return false;
+    }
+
+    SAL_INFO("vcl.pdfwriter", "Signature size is " << nSigLen << " bytes");
+    boost::scoped_array<BYTE> pSig(new BYTE[nSigLen]);
+
+    if (!CryptMsgGetParam(hMsg, CMSG_CONTENT_PARAM, 0, pSig.get(), &nSigLen))
+    {
+        SAL_WARN("vcl.pdfwriter", "CryptMsgGetParam(CMSG_CONTENT_PARAM) failed: " << WindowsError(GetLastError()));
+        if (pTsContext)
+            CryptMemFree(pTsContext);
+        CryptMsgClose(hMsg);
+        CertFreeCertificateContext(pCertContext);
+        return false;
+    }
+
+#ifdef DBG_UTIL
+    {
+        FILE *out = fopen("PDFWRITER.signature.data", "wb");
+        fwrite(pSig.get(), nSigLen, 1, out);
+        fclose(out);
+    }
+#endif
+
     // Release resources
+    if (pTsContext)
+        CryptMemFree(pTsContext);
+    CryptMsgClose(hMsg);
     CertFreeCertificateContext(pCertContext);
 
     OStringBuffer cms_hexbuffer;
commit eedfac6d087b1eecef77d243f82123b264b7013d
Author: Tor Lillqvist <tml at collabora.com>
Date:   Fri Feb 27 10:36:57 2015 +0200

    tdf#84881: Timestamp the right data (NSS version)
    
    Now Adobe Reader is satisfied with the signature timestamp.
    
    I just need to figure out how to do the corresponding fix for the Win32
    version, too.
    
    Change-Id: Ie2cce177a9a356e729ca157b4c181e95a2c60c91
    (cherry picked from commit ce0e240ef10566f1cc334386dbde83b43ebb9281)

diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index 450b4d5..7bc1119 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -6925,7 +6925,7 @@ bool PDFWriterImpl::finalizeSignature()
         }
 
         HASH_Begin(ts_hc.get());
-        HASH_Update(ts_hc.get(), reinterpret_cast<const unsigned char*>(ts_cms_output.data), ts_cms_output.len);
+        HASH_Update(ts_hc.get(), ts_cms_signer->encDigest.data, ts_cms_signer->encDigest.len);
         SECItem ts_digest;
         unsigned char ts_hash[SHA1_LENGTH];
         ts_digest.type = siBuffer;
@@ -6947,7 +6947,9 @@ bool PDFWriterImpl::finalizeSignature()
         src.version.data = &cOne;
         src.version.len = sizeof(cOne);
 
-        src.messageImprint.hashAlgorithm = ts_cms_signer->digestAlg;
+        src.messageImprint.hashAlgorithm.algorithm.data = NULL;
+        src.messageImprint.hashAlgorithm.parameters.data = NULL;
+        SECOID_SetAlgorithmID(NULL, &src.messageImprint.hashAlgorithm, SEC_OID_SHA1, NULL);
         src.messageImprint.hashedMessage = ts_digest;
 
         src.reqPolicy.type = siBuffer;
commit 175fd47370ae0ce1265b4229b2fc113e2f60cc26
Author: Tor Lillqvist <tml at collabora.com>
Date:   Thu Feb 26 21:14:38 2015 +0200

    tdf#84881: Add Windows implementation of timestamping of signature
    
    Luckily doable with much simpler code than the horrible NSS and curl mess used
    on Linux (and, sadly, OS X).
    
    Basically only one new API call needed: CryptRetrieveTimestamp(). A few hours
    of work, compared to about a week for the Linux case.
    
    However, amusingly, it causes the same message in Adobe Reader as when using
    the NSS code: "The signature includes an embedded timestamp but it could not
    be verified". Sigh.
    
    Change-Id: I98c973bd50b841d1ae3feb8a695bac29da538b6c
    (cherry picked from commit 00646102569739e0bf8929c271963f129d747a5a)

diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index 5ad98eb..450b4d5 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -6733,6 +6733,17 @@ NSSCMSMessage *CreateCMSMessage(PRTime time,
 
 #ifdef _WIN32
 
+typedef BOOL (WINAPI *PointerTo_CryptRetrieveTimeStamp)(LPCWSTR wszUrl,
+                                                        DWORD dwRetrievalFlags,
+                                                        DWORD dwTimeout,
+                                                        LPCSTR pszHashId,
+                                                        const CRYPT_TIMESTAMP_PARA *pPara,
+                                                        const BYTE *pbData,
+                                                        DWORD cbData,
+                                                        PCRYPT_TIMESTAMP_CONTEXT *ppTsContext,
+                                                        PCCERT_CONTEXT *ppTsSigner,
+                                                        HCERTSTORE phStore);
+
 namespace {
 
 OUString WindowsError(DWORD nErrorCode)
@@ -7292,6 +7303,117 @@ bool PDFWriterImpl::finalizeSignature()
         return false;
     }
 
+#ifdef DBG_UTIL
+    {
+        FILE *out = fopen("PDFWRITER.signature.data", "wb");
+        fwrite(pSig.get(), nSigLen, 1, out);
+        fclose(out);
+    }
+#endif
+
+    if( !m_aContext.SignTSA.isEmpty() )
+    {
+        PointerTo_CryptRetrieveTimeStamp crts = (PointerTo_CryptRetrieveTimeStamp) GetProcAddress(LoadLibrary("crypt32.dll"), "CryptRetrieveTimeStamp");
+        if (!crts)
+        {
+            SAL_WARN("vcl.pdfwriter", "Could not find the CryptRetrieveTimeStamp function in crypt32.dll: " << WindowsError(GetLastError()));
+            CertFreeCertificateContext(pCertContext);
+            return false;
+        }
+        else
+        {
+            CRYPT_TIMESTAMP_PARA aTsPara;
+
+            unsigned int nNonce = comphelper::rng::uniform_uint_distribution(0, SAL_MAX_UINT32);
+
+            aTsPara.pszTSAPolicyId = NULL;
+            aTsPara.fRequestCerts = TRUE;
+            aTsPara.Nonce.cbData = sizeof(nNonce);
+            aTsPara.Nonce.pbData = (BYTE *)&nNonce;
+            aTsPara.cExtension = 0;
+            aTsPara.rgExtension = NULL;
+
+            PCRYPT_TIMESTAMP_CONTEXT pTsContext = NULL;
+
+            if (!(*crts)(m_aContext.SignTSA.getStr(),
+                         0,
+                         10000,
+                         szOID_NIST_sha256,
+                         &aTsPara,
+                         pSig.get(),
+                         nSigLen,
+                         &pTsContext,
+                         NULL,
+                         NULL))
+            {
+                SAL_WARN("vcl.pdfwriter", "CryptRetrieveTimeStamp failed: " << WindowsError(GetLastError()));
+                CertFreeCertificateContext(pCertContext);
+                return false;
+            }
+
+            SAL_INFO("vcl.pdfwriter", "Time stamp size is " << pTsContext->cbEncoded << " bytes");
+
+#ifdef DBG_UTIL
+            {
+                FILE *out = fopen("PDFWRITER.tstoken.data", "wb");
+                fwrite(pTsContext->pbEncoded, pTsContext->cbEncoded, 1, out);
+                fclose(out);
+            }
+#endif
+
+            CRYPT_INTEGER_BLOB aTimestampBlob;
+            aTimestampBlob.cbData = pTsContext->cbEncoded;
+            aTimestampBlob.pbData = pTsContext->pbEncoded;
+
+            CRYPT_ATTRIBUTE aTimestampAttribute;
+            aTimestampAttribute.pszObjId = "1.2.840.113549.1.9.16.2.14";
+            aTimestampAttribute.cValue = 1;
+            aTimestampAttribute.rgValue = &aTimestampBlob;
+
+            aPara.cUnauthAttr = 1;
+            aPara.rgUnauthAttr = &aTimestampAttribute;
+
+            nSigLen = 0;
+            if (!CryptSignMessage(&aPara, TRUE, SAL_N_ELEMENTS(aBuffers), aBuffers, aBufferLens, NULL, &nSigLen))
+            {
+                SAL_WARN("vcl.pdfwriter", "CryptSignMessage failed: " << WindowsError(GetLastError()));
+                CryptMemFree(pTsContext);
+                CertFreeCertificateContext(pCertContext);
+                return false;
+            }
+
+            if (nSigLen*2 > MAX_SIGNATURE_CONTENT_LENGTH)
+            {
+                SAL_WARN("vcl.pdfwriter", "Signature requires more space (" << nSigLen*2 << ") than we reserved (" << MAX_SIGNATURE_CONTENT_LENGTH << ")");
+                CryptMemFree(pTsContext);
+                CertFreeCertificateContext(pCertContext);
+                return false;
+            }
+
+            SAL_INFO("vcl.pdfwriter", "Signature size including timestamp is " << nSigLen << " bytes");
+
+            pSig.reset(new BYTE[nSigLen]);
+
+            if (!CryptSignMessage(&aPara, TRUE, SAL_N_ELEMENTS(aBuffers), aBuffers, aBufferLens, pSig.get(), &nSigLen))
+            {
+                SAL_WARN("vcl.pdfwriter", "CryptSignMessage failed: " << WindowsError(GetLastError()));
+                CryptMemFree(pTsContext);
+                CertFreeCertificateContext(pCertContext);
+                return false;
+            }
+
+#ifdef DBG_UTIL
+            {
+                FILE *out = fopen("PDFWRITER.ts_signature.data", "wb");
+                fwrite(pSig.get(), nSigLen, 1, out);
+                fclose(out);
+            }
+#endif
+
+            CryptMemFree(pTsContext);
+        }
+    }
+
     // Release resources
     CertFreeCertificateContext(pCertContext);
 
commit ac99ce6cc69b46a50bacb29ff7301d2053deac69
Author: Tor Lillqvist <tml at collabora.com>
Date:   Wed Feb 25 22:39:27 2015 +0200

    tdf#84881: Try to fix "The signature includes an embedded timestamp but ...
    
    ... it could not be verified"
    
    I got some insight reading this question and reply on stackoverflow:
    http://stackoverflow.com/questions/18761993/steps-to-include-timestamp-in-pdf-signature
    
    I had been doing the timestamping wrong in the same way: I had timestamped the
    hash of the PDF document, not of the signature. That is wrong. If you think
    hard, it is obvious: It is the (rest of the) signature that needs an
    authenticated timestamp, not the PDF document contents. After all, if the
    document contents is timestamped, but not the signature, that doesn't prevent
    tampering with the signature after the timestamping. When you timestamp the
    signature, that proves the date of the signature. (And the signature proves
    the authenticity of the document contents.)
    
    So I had to re-engineer the code a bit. I create two originally identical NSS
    CMS messages with signatures, encode one signature into DER, take the hash of
    the signature, get a timestamp from the TSA for that hash. Then I add that
    timestamp to the other CMS message as an unsigned attribute of its signature,
    sign it, encode it, convert to hex, and store it the document.
    
    (I first tried to use just one CMS message, but NSS stopped with an assertion
    when I tried to encode the signature of the same message a second time, after
    adding the timestamp attribute to the signature. Go figure.)
    
    (I did verify the the encoded signatures, taken from what should be identical
    but separate CMS messages, was in fact identical. So I am fairly sure the idea
    described above is sound.)
    
    But, it doesn't help. Adobe Reader still complains "The signature includes an
    embedded timestamp but it could not be verified".
    
    Change-Id: I4e4cd0443005e82f597586942badc7145ef64160
    (cherry picked from commit 86796f127b15fd33374f2a18344dc944b7b8314d)

diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index a54adf9..5ad98eb 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -6212,6 +6212,31 @@ RevocationInfoChoice ::= CHOICE {
 
 RevocationInfoChoices ::= SET OF RevocationInfoChoice
 
+SignerIdentifier ::= CHOICE {
+    issuerAndSerialNumber IssuerAndSerialNumber,
+    subjectKeyIdentifier [0] SubjectKeyIdentifier }
+
+AttributeValue ::= ANY
+
+Attribute ::= SEQUENCE {
+    attrType OBJECT IDENTIFIER,
+    attrValues SET OF AttributeValue }
+
+SignedAttributes ::= SET SIZE (1..MAX) OF Attribute
+
+SignatureValue ::= OCTET STRING
+
+UnsignedAttributes ::= SET SIZE (1..MAX) OF Attribute
+
+SignerInfo ::= SEQUENCE {
+    version CMSVersion,
+    sid SignerIdentifier,
+    digestAlgorithm DigestAlgorithmIdentifier,
+    signedAttrs [0] IMPLICIT SignedAttributes OPTIONAL,
+    signatureAlgorithm SignatureAlgorithmIdentifier,
+    signature SignatureValue,
+    unsignedAttrs [1] IMPLICIT UnsignedAttributes OPTIONAL }
+
 SignerInfos ::= SET OF SignerInfo
 
 SignedData ::= SEQUENCE {
@@ -6606,7 +6631,8 @@ my_NSS_CMSSignerInfo_AddUnauthAttr(NSSCMSSignerInfo *signerinfo, NSSCMSAttribute
     return my_NSS_CMSAttributeArray_AddAttr(signerinfo->cmsg->poolp, &(signerinfo->unAuthAttr), attr);
 }
 
-NSSCMSMessage *CreateCMSMessage(NSSCMSSignedData **cms_sd,
+NSSCMSMessage *CreateCMSMessage(PRTime time,
+                                NSSCMSSignedData **cms_sd,
                                 NSSCMSSignerInfo **cms_signer,
                                 CERTCertificate *cert,
                                 SECItem *digest)
@@ -6655,7 +6681,7 @@ NSSCMSMessage *CreateCMSMessage(NSSCMSSignedData **cms_sd,
         return NULL;
     }
 
-    if (NSS_CMSSignerInfo_AddSigningTime(*cms_signer, PR_Now()) != SECSuccess)
+    if (NSS_CMSSignerInfo_AddSigningTime(*cms_signer, time) != SECSuccess)
     {
         SAL_WARN("vcl.pdfwriter", "NSS_CMSSignerInfo_AddSigningTime failed");
         NSS_CMSSignedData_Destroy(*cms_sd);
@@ -6816,20 +6842,93 @@ bool PDFWriterImpl::finalizeSignature()
     HASH_End(hc.get(), digest.data, &digest.len, SHA1_LENGTH);
     hc.clear();
 
+#ifdef DBG_UTIL
+    {
+        FILE *out = fopen("PDFWRITER.hash.data", "wb");
+        fwrite(hash, SHA1_LENGTH, 1, out);
+        fclose(out);
+    }
+#endif
+
+    PRTime now = PR_Now();
     NSSCMSSignedData *cms_sd;
     NSSCMSSignerInfo *cms_signer;
-    NSSCMSMessage *cms_msg = CreateCMSMessage(&cms_sd, &cms_signer, cert, &digest);
+    NSSCMSMessage *cms_msg = CreateCMSMessage(now, &cms_sd, &cms_signer, cert, &digest);
     if (!cms_msg)
         return false;
 
+    char *pass(strdup(OUStringToOString( m_aContext.SignPassword, RTL_TEXTENCODING_UTF8 ).getStr()));
+
     NSSCMSAttribute timestamp;
     SECItem values[2];
     SECItem *valuesp = values;
     SECOidData typetag;
 
-    // Now we have the hash algorithm as a SECItem available in cms_siger->digestAlg
     if( !m_aContext.SignTSA.isEmpty() )
     {
+        // Create another CMS message with the same contents as cms_msg, because it doesn't seem
+        // possible to encode a message twice (once to get something to timestamp, and then after
+        // adding the timestamp attribute).
+
+        NSSCMSSignedData *ts_cms_sd;
+        NSSCMSSignerInfo *ts_cms_signer;
+        NSSCMSMessage *ts_cms_msg = CreateCMSMessage(now, &ts_cms_sd, &ts_cms_signer, cert, &digest);
+        if (!ts_cms_msg)
+        {
+            free(pass);
+            return false;
+        }
+
+        SECItem ts_cms_output;
+        ts_cms_output.data = 0;
+        ts_cms_output.len = 0;
+        PLArenaPool *ts_arena = PORT_NewArena(MAX_SIGNATURE_CONTENT_LENGTH);
+        NSSCMSEncoderContext *ts_cms_ecx;
+        ts_cms_ecx = NSS_CMSEncoder_Start(ts_cms_msg, NULL, NULL, &ts_cms_output, ts_arena, PDFSigningPKCS7PasswordCallback, pass, NULL, NULL, NULL, NULL);
+
+        if (NSS_CMSEncoder_Finish(ts_cms_ecx) != SECSuccess)
+        {
+            SAL_WARN("vcl.pdfwriter", "NSS_CMSEncoder_Finish failed");
+            free(pass);
+            return false;
+        }
+
+        // I have compared the ts_cms_output produced here with the cms_output produced below, with
+        // the DONTCALLADDUNAUTHATTR env var set (i.e. without actually calling
+        // my_NSS_CMSSignerInfo_AddUnauthAttr()), and they are identical.
+
+#ifdef DBG_UTIL
+        {
+            FILE *out = fopen("PDFWRITER.ts_cms.data", "wb");
+            fwrite(ts_cms_output.data, ts_cms_output.len, 1, out);
+            fclose(out);
+        }
+#endif
+
+        HashContextScope ts_hc(HASH_Create(HASH_AlgSHA1));
+        if (!ts_hc.get())
+        {
+            SAL_WARN("vcl.pdfwriter", "HASH_Create failed");
+            free(pass);
+            return false;
+        }
+
+        HASH_Begin(ts_hc.get());
+        HASH_Update(ts_hc.get(), reinterpret_cast<const unsigned char*>(ts_cms_output.data), ts_cms_output.len);
+        SECItem ts_digest;
+        unsigned char ts_hash[SHA1_LENGTH];
+        ts_digest.type = siBuffer;
+        ts_digest.data = ts_hash;
+        HASH_End(ts_hc.get(), ts_digest.data, &ts_digest.len, SHA1_LENGTH);
+        ts_hc.clear();
+
+#ifdef DBG_UTIL
+        {
+            FILE *out = fopen("PDFWRITER.ts_hash.data", "wb");
+            fwrite(ts_hash, SHA1_LENGTH, 1, out);
+            fclose(out);
+        }
+#endif
         TimeStampReq src;
 
         unsigned char cOne = 1;
@@ -6837,8 +6936,8 @@ bool PDFWriterImpl::finalizeSignature()
         src.version.data = &cOne;
         src.version.len = sizeof(cOne);
 
-        src.messageImprint.hashAlgorithm = cms_signer->digestAlg;
-        src.messageImprint.hashedMessage = digest;
+        src.messageImprint.hashAlgorithm = ts_cms_signer->digestAlg;
+        src.messageImprint.hashedMessage = ts_digest;
 
         src.reqPolicy.type = siBuffer;
         src.reqPolicy.data = NULL;
@@ -6859,12 +6958,14 @@ bool PDFWriterImpl::finalizeSignature()
         if (timestamp_request == NULL)
         {
             SAL_WARN("vcl.pdfwriter", "SEC_ASN1EncodeItem failed");
+            free(pass);
             return false;
         }
 
         if (timestamp_request->data == NULL)
         {
             SAL_WARN("vcl.pdfwriter", "SEC_ASN1EncodeItem succeeded but got NULL data");
+            free(pass);
             SECITEM_FreeItem(timestamp_request, PR_TRUE);
             return false;
         }
@@ -6888,6 +6989,7 @@ bool PDFWriterImpl::finalizeSignature()
         if (!curl)
         {
             SAL_WARN("vcl.pdfwriter", "curl_easy_init failed");
+            free(pass);
             SECITEM_FreeItem(timestamp_request, PR_TRUE);
             return false;
         }
@@ -6897,6 +6999,7 @@ bool PDFWriterImpl::finalizeSignature()
         if ((rc = curl_easy_setopt(curl, CURLOPT_URL, OUStringToOString(m_aContext.SignTSA, RTL_TEXTENCODING_UTF8).getStr())) != CURLE_OK)
         {
             SAL_WARN("vcl.pdfwriter", "curl_easy_setopt(CURLOPT_URL) failed: " << curl_easy_strerror(rc));
+            free(pass);
             curl_easy_cleanup(curl);
             SECITEM_FreeItem(timestamp_request, PR_TRUE);
             return false;
@@ -6908,6 +7011,7 @@ bool PDFWriterImpl::finalizeSignature()
         if ((rc = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist)) != CURLE_OK)
         {
             SAL_WARN("vcl.pdfwriter", "curl_easy_setopt(CURLOPT_HTTPHEADER) failed: " << curl_easy_strerror(rc));
+            free(pass);
             curl_slist_free_all(slist);
             curl_easy_cleanup(curl);
             SECITEM_FreeItem(timestamp_request, PR_TRUE);
@@ -6918,6 +7022,7 @@ bool PDFWriterImpl::finalizeSignature()
             (rc = curl_easy_setopt(curl, CURLOPT_POSTFIELDS, timestamp_request->data)) != CURLE_OK)
         {
             SAL_WARN("vcl.pdfwriter", "curl_easy_setopt(CURLOPT_POSTFIELDSIZE or CURLOPT_POSTFIELDS) failed: " << curl_easy_strerror(rc));
+            free(pass);
             curl_easy_cleanup(curl);
             SECITEM_FreeItem(timestamp_request, PR_TRUE);
             return false;
@@ -6929,6 +7034,7 @@ bool PDFWriterImpl::finalizeSignature()
             (rc = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, AppendToBuffer)) != CURLE_OK)
         {
             SAL_WARN("vcl.pdfwriter", "curl_easy_setopt(CURLOPT_WRITEDATA or CURLOPT_WRITEFUNCTION) failed: " << curl_easy_strerror(rc));
+            free(pass);
             curl_easy_cleanup(curl);
             SECITEM_FreeItem(timestamp_request, PR_TRUE);
             return false;
@@ -6937,6 +7043,7 @@ bool PDFWriterImpl::finalizeSignature()
         if ((rc = curl_easy_setopt(curl, CURLOPT_POST, 1l)) != CURLE_OK)
         {
             SAL_WARN("vcl.pdfwriter", "curl_easy_setopt(CURLOPT_POST) failed: " << curl_easy_strerror(rc));
+            free(pass);
             curl_easy_cleanup(curl);
             SECITEM_FreeItem(timestamp_request, PR_TRUE);
             return false;
@@ -6946,6 +7053,7 @@ bool PDFWriterImpl::finalizeSignature()
         if ((rc = curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error_buffer)) != CURLE_OK)
         {
             SAL_WARN("vcl.pdfwriter", "curl_easy_setopt(CURLOPT_ERRORBUFFER) failed: " << curl_easy_strerror(rc));
+            free(pass);
             curl_easy_cleanup(curl);
             SECITEM_FreeItem(timestamp_request, PR_TRUE);
             return false;
@@ -6956,6 +7064,7 @@ bool PDFWriterImpl::finalizeSignature()
             (rc = curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10l)) != CURLE_OK)
         {
             SAL_WARN("vcl.pdfwriter", "curl_easy_setopt(CURLOPT_TIMEOUT or CURLOPT_CONNECTTIMEOUT) failed: " << curl_easy_strerror(rc));
+            free(pass);
             curl_easy_cleanup(curl);
             SECITEM_FreeItem(timestamp_request, PR_TRUE);
             return false;
@@ -6964,6 +7073,7 @@ bool PDFWriterImpl::finalizeSignature()
         if (curl_easy_perform(curl) != CURLE_OK)
         {
             SAL_WARN("vcl.pdfwriter", "curl_easy_perform failed: " << error_buffer);
+            free(pass);
             curl_easy_cleanup(curl);
             SECITEM_FreeItem(timestamp_request, PR_TRUE);
             return false;
@@ -6994,6 +7104,7 @@ bool PDFWriterImpl::finalizeSignature()
         if (SEC_ASN1DecodeItem(NULL, &response, TimeStampResp_Template, &response_item) != SECSuccess)
         {
             SAL_WARN("vcl.pdfwriter", "SEC_ASN1DecodeItem failed");
+            free(pass);
             return false;
         }
 
@@ -7003,6 +7114,7 @@ bool PDFWriterImpl::finalizeSignature()
             (response.status.status.data[0] != 0 && response.status.status.data[0] != 1))
         {
             SAL_WARN("vcl.pdfwriter", "Timestamp request was not granted");
+            free(pass);
             return false;
         }
 
@@ -7022,11 +7134,12 @@ bool PDFWriterImpl::finalizeSignature()
         if (my_SEC_StringToOID(NULL, &typetag.oid, "1.2.840.113549.1.9.16.2.14", 0) != SECSuccess)
         {
             SAL_WARN("vcl.pdfwriter", "SEC_StringToOID failed");
+            free(pass);
             return false;
         }
         typetag.offset = SEC_OID_UNKNOWN; // ???
         typetag.desc = "id-aa-timeStampToken";
-        typetag.mechanism = CKM_SHA256; // ???
+        typetag.mechanism = CKM_SHA_1; // ???
         typetag.supportedExtension = UNSUPPORTED_CERT_EXTENSION; // ???
         timestamp.typeTag = &typetag;
 
@@ -7034,28 +7147,30 @@ bool PDFWriterImpl::finalizeSignature()
 
         timestamp.encoded = PR_TRUE; // ???
 
+#ifdef DBG_UTIL
+        if (getenv("DONTCALLADDUNAUTHATTR"))
+            ;
+        else
+#endif
         if (my_NSS_CMSSignerInfo_AddUnauthAttr(cms_signer, &timestamp) != SECSuccess)
         {
             SAL_WARN("vcl.pdfwriter", "NSS_CMSSignerInfo_AddUnauthAttr failed");
+            free(pass);
             return false;
         }
     }
+
     SECItem cms_output;
     cms_output.data = 0;
     cms_output.len = 0;
     PLArenaPool *arena = PORT_NewArena(MAX_SIGNATURE_CONTENT_LENGTH);
     NSSCMSEncoderContext *cms_ecx;
 
-    //FIXME: Check if password is passed correctly to SEC_PKCS7CreateSignedData function
-
-    // Inded, it was not, I think, and that caused a crash as described in fdo#83937.
-    // Unfortunately I could not test this fix fully before my hardware token decided to
-    // block itself thanks to too many wrong PIN attempts. Possibly it would work to
-    // even just pass NULL for the password callback function and its argument here.
-    // After all, at least with the hardware token and associated software I tested
-    // with, the software itself pops up a dialog asking for the PIN (password).
+    // Possibly it would work to even just pass NULL for the password callback function and its
+    // argument here. After all, at least with the hardware token and associated software I tested
+    // with, the software itself pops up a dialog asking for the PIN (password). But I am not going
+    // to test it and risk locking up my token...
 
-    char *pass(strdup(OUStringToOString( m_aContext.SignPassword, RTL_TEXTENCODING_UTF8 ).getStr()));
     cms_ecx = NSS_CMSEncoder_Start(cms_msg, NULL, NULL, &cms_output, arena, PDFSigningPKCS7PasswordCallback, pass, NULL, NULL, NULL, NULL);
 
     if (!cms_ecx)
commit a4c0c2a91d1d8c8e5e099cd751f8c8cb3cfeefda
Author: Tor Lillqvist <tml at collabora.com>
Date:   Wed Feb 25 13:20:56 2015 +0200

    tdf#84881: Slight refactoring and redordering of function calls
    
    No change to functionality or end result. Preparation for an attempt to fix
    the remaining problem with RFC3161 timestamped signature.
    
    Change-Id: I5790a85399e9f94d816e8fab791a03d607113116
    (cherry picked from commit 0874849206a38cbe15cc981b6cb814d3a7abf38b)

diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index b4bbcae..a54adf9 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -6606,6 +6606,98 @@ my_NSS_CMSSignerInfo_AddUnauthAttr(NSSCMSSignerInfo *signerinfo, NSSCMSAttribute
     return my_NSS_CMSAttributeArray_AddAttr(signerinfo->cmsg->poolp, &(signerinfo->unAuthAttr), attr);
 }
 
+NSSCMSMessage *CreateCMSMessage(NSSCMSSignedData **cms_sd,
+                                NSSCMSSignerInfo **cms_signer,
+                                CERTCertificate *cert,
+                                SECItem *digest)
+{
+    NSSCMSMessage *result = NSS_CMSMessage_Create(NULL);
+    if (!result)
+    {
+        SAL_WARN("vcl.pdfwriter", "NSS_CMSMessage_Create failed");
+        return NULL;
+    }
+
+    *cms_sd = NSS_CMSSignedData_Create(result);
+    if (!*cms_sd)
+    {
+        SAL_WARN("vcl.pdfwriter", "NSS_CMSSignedData_Create failed");
+        NSS_CMSMessage_Destroy(result);
+        return NULL;
+    }
+
+    NSSCMSContentInfo *cms_cinfo = NSS_CMSMessage_GetContentInfo(result);
+    if (NSS_CMSContentInfo_SetContent_SignedData(result, cms_cinfo, *cms_sd) != SECSuccess)
+    {
+        SAL_WARN("vcl.pdfwriter", "NSS_CMSContentInfo_SetContent_SignedData failed");
+        NSS_CMSSignedData_Destroy(*cms_sd);
+        NSS_CMSMessage_Destroy(result);
+        return NULL;
+    }
+
+    cms_cinfo = NSS_CMSSignedData_GetContentInfo(*cms_sd);
+
+    // Attach NULL data as detached data
+    if (NSS_CMSContentInfo_SetContent_Data(result, cms_cinfo, NULL, PR_TRUE) != SECSuccess)
+    {
+        SAL_WARN("vcl.pdfwriter", "NSS_CMSContentInfo_SetContent_Data failed");
+        NSS_CMSSignedData_Destroy(*cms_sd);
+        NSS_CMSMessage_Destroy(result);
+        return NULL;
+    }
+
+    *cms_signer = NSS_CMSSignerInfo_Create(result, cert, SEC_OID_SHA1);
+    if (!*cms_signer)
+    {
+        SAL_WARN("vcl.pdfwriter", "NSS_CMSSignerInfo_Create failed");
+        NSS_CMSSignedData_Destroy(*cms_sd);
+        NSS_CMSMessage_Destroy(result);
+        return NULL;
+    }
+
+    if (NSS_CMSSignerInfo_AddSigningTime(*cms_signer, PR_Now()) != SECSuccess)
+    {
+        SAL_WARN("vcl.pdfwriter", "NSS_CMSSignerInfo_AddSigningTime failed");
+        NSS_CMSSignedData_Destroy(*cms_sd);
+        NSS_CMSMessage_Destroy(result);
+        return NULL;
+    }
+
+    if (NSS_CMSSignerInfo_IncludeCerts(*cms_signer, NSSCMSCM_CertChain, certUsageEmailSigner) != SECSuccess)
+    {
+        SAL_WARN("vcl.pdfwriter", "NSS_CMSSignerInfo_IncludeCerts failed");
+        NSS_CMSSignedData_Destroy(*cms_sd);
+        NSS_CMSMessage_Destroy(result);
+        return NULL;
+    }
+
+    if (NSS_CMSSignedData_AddCertificate(*cms_sd, cert) != SECSuccess)
+    {
+        SAL_WARN("vcl.pdfwriter", "NSS_CMSSignedData_AddCertificate failed");
+        NSS_CMSSignedData_Destroy(*cms_sd);
+        NSS_CMSMessage_Destroy(result);
+        return NULL;
+    }
+
+    if (NSS_CMSSignedData_AddSignerInfo(*cms_sd, *cms_signer) != SECSuccess)
+    {
+        SAL_WARN("vcl.pdfwriter", "NSS_CMSSignedData_AddSignerInfo failed");
+        NSS_CMSSignedData_Destroy(*cms_sd);
+        NSS_CMSMessage_Destroy(result);
+        return NULL;
+    }
+
+    if (NSS_CMSSignedData_SetDigestValue(*cms_sd, SEC_OID_SHA1, digest) != SECSuccess)
+    {
+        SAL_WARN("vcl.pdfwriter", "NSS_CMSSignedData_SetDigestValue failed");
+        NSS_CMSSignedData_Destroy(*cms_sd);
+        NSS_CMSMessage_Destroy(result);
+        return NULL;
+    }
+
+    return result;
+}
+
 #if 0
 {
 #endif
@@ -6724,41 +6816,11 @@ bool PDFWriterImpl::finalizeSignature()
     HASH_End(hc.get(), digest.data, &digest.len, SHA1_LENGTH);
     hc.clear();
 
-    NSSCMSMessage *cms_msg = NSS_CMSMessage_Create(NULL);
+    NSSCMSSignedData *cms_sd;
+    NSSCMSSignerInfo *cms_signer;
+    NSSCMSMessage *cms_msg = CreateCMSMessage(&cms_sd, &cms_signer, cert, &digest);
     if (!cms_msg)
-    {
-        SAL_WARN("vcl.pdfwriter", "NSS_CMSMessage_Create failed");
-        return false;
-    }
-
-    NSSCMSSignedData *cms_sd = NSS_CMSSignedData_Create(cms_msg);
-    if (!cms_sd)
-    {
-        SAL_WARN("vcl.pdfwriter", "NSS_CMSSignedData_Create failed");
-        return false;
-    }
-
-    NSSCMSContentInfo *cms_cinfo = NSS_CMSMessage_GetContentInfo(cms_msg);
-    if (NSS_CMSContentInfo_SetContent_SignedData(cms_msg, cms_cinfo, cms_sd) != SECSuccess)
-    {
-        SAL_WARN("vcl.pdfwriter", "NSS_CMSContentInfo_SetContent_SignedData failed");
-        return false;
-    }
-
-    cms_cinfo = NSS_CMSSignedData_GetContentInfo(cms_sd);
-    //attach NULL data as detached data
-    if (NSS_CMSContentInfo_SetContent_Data(cms_msg, cms_cinfo, NULL, PR_TRUE) != SECSuccess)
-    {
-        SAL_WARN("vcl.pdfwriter", "NSS_CMSContentInfo_SetContent_Data failed");
         return false;
-    }
-
-    NSSCMSSignerInfo *cms_signer = NSS_CMSSignerInfo_Create(cms_msg, cert, SEC_OID_SHA1);
-    if (!cms_signer)
-    {

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list