[Libreoffice-commits] core.git: Branch 'distro/collabora/cp-4.3' - 29 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 vcl/Library_vcl.mk vcl/source

Tor Lillqvist tml at collabora.com
Thu Mar 5 08:27:21 PST 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 
 vcl/Library_vcl.mk                                         |    5 
 vcl/source/gdi/pdfwriter_impl.cxx                          | 1430 ++++++++++++-
 19 files changed, 1912 insertions(+), 99 deletions(-)

New commits:
commit a631ee21f2478c976bce23898d84a6529296087f
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)
    
    Conflicts:
    	filter/source/pdf/impdialog.cxx
    	include/sal/log-areas.dox
    
    Change-Id: Ia86fa0f59dcfee8e9d332a028a3fad37f4019fe0

diff --git a/cui/source/options/tsaurls.cxx b/cui/source/options/tsaurls.cxx
index 9db3801..cf50fbc 100644
--- a/cui/source/options/tsaurls.cxx
+++ b/cui/source/options/tsaurls.cxx
@@ -17,7 +17,7 @@
 
 using namespace ::com::sun::star;
 
-TSAURLsDialog::TSAURLsDialog(vcl::Window* pParent)
+TSAURLsDialog::TSAURLsDialog(Window* pParent)
     : ModalDialog(pParent, "TSAURLDialog", "cui/ui/tsaurldialog.ui")
 {
     get(m_pAddBtn, "add");
@@ -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/cui/source/options/tsaurls.hxx b/cui/source/options/tsaurls.hxx
index aba7491..cc9f2de 100644
--- a/cui/source/options/tsaurls.hxx
+++ b/cui/source/options/tsaurls.hxx
@@ -30,7 +30,7 @@ private:
     void AddTSAURL(const OUString &rURL);
 
 public:
-    TSAURLsDialog(vcl::Window* pParent);
+    TSAURLsDialog(Window* pParent);
     virtual ~TSAURLsDialog();
 
 };
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 63e446f3..005dd2f 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/svapp.hxx"
 #include "vcl/msgbox.hxx"
 #include <vcl/settings.hxx>
@@ -1541,10 +1542,12 @@ ImpPDFTabSigningPage::ImpPDFTabSigningPage(Window* pParent, const SfxItemSet& rC
     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 ) );
 }
 
 
@@ -1569,6 +1572,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;
@@ -1583,11 +1604,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( Window* pParent,
                                           const SfxItemSet& rAttrSet)
 {
@@ -1616,6 +1643,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 c6238ea..50bba41 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( Window* pParent,
diff --git a/filter/uiconfig/ui/pdfsignpage.ui b/filter/uiconfig/ui/pdfsignpage.ui
index ff9395f..73c61ae 100644
--- a/filter/uiconfig/ui/pdfsignpage.ui
+++ b/filter/uiconfig/ui/pdfsignpage.ui
@@ -173,6 +173,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>
@@ -236,6 +250,20 @@
                     <property name="height">1</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 c12740c..6d7e8e7 100644
--- a/include/sal/log-areas.dox
+++ b/include/sal/log-areas.dox
@@ -172,6 +172,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.tiff
 @li @c filter.xslt - xslt import/export
 @li @c oox.cscode - see oox/source/drawingml/customshapes/README
diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index e7a18b7..7fa5b14 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -6943,7 +6943,8 @@ bool PDFWriterImpl::finalizeSignature()
         src.reqPolicy.data = NULL;
         src.reqPolicy.len = 0;
 
-        unsigned int nNonce = comphelper::rng::uniform_uint_distribution(0, SAL_MAX_UINT32);
+        srand( unsigned( time( NULL ) ));
+        unsigned int nNonce = rand();
         src.nonce.type = siUnsignedInteger;
         src.nonce.data = reinterpret_cast<unsigned char*>(&nNonce);
         src.nonce.len = sizeof(nNonce);
@@ -7414,7 +7415,8 @@ bool PDFWriterImpl::finalizeSignature()
         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);
+        srand( unsigned( time( NULL ) ));
+        unsigned int nNonce = rand();
 
         aTsPara.pszTSAPolicyId = NULL;
         aTsPara.fRequestCerts = TRUE;
commit a56459cae72f17ebeba408a451451880639bcabf
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 1ac0ed7..4050991 100644
--- a/cui/Library_cui.mk
+++ b/cui/Library_cui.mk
@@ -162,6 +162,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 cd18592..c53ba48 100644
--- a/cui/UIConfig_cui.mk
+++ b/cui/UIConfig_cui.mk
@@ -180,6 +180,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 8938483..86a9968 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(Window* pParent, const SfxItemSet& rSet)
     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(Window* pParent, const SfxItemSet& rSet)
     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 c76a8eb..1fc54b8 100644
--- a/cui/source/options/optinet2.hxx
+++ b/cui/source/options/optinet2.hxx
@@ -125,9 +125,7 @@ protected:
 // class SvxSecurityTabPage ---------------------------------------------
 
 class SvtSecurityOptions;
-
 class CertPathDialog;
-
 class SvxSecurityTabPage : public SfxTabPage
 {
     using TabPage::ActivatePage;
@@ -149,6 +147,9 @@ private:
     VclContainer*       m_pCertFrame;
     PushButton*         m_pCertPathPB;
 
+    VclContainer*       m_pTSAURLsFrame;
+    PushButton*         m_pTSAURLsPB;
+
     SvtSecurityOptions*         mpSecOptions;
     svx::SecurityOptionsDialog* mpSecOptDlg;
 
@@ -163,6 +164,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 55c9439..9690d3a 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 54707b2..f03319b 100644
--- a/officecfg/registry/schema/org/openoffice/Office/Common.xcs
+++ b/officecfg/registry/schema/org/openoffice/Office/Common.xcs
@@ -2518,6 +2518,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 46868c9eebc5909f40f813414d74b9b5ea484a99
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 7cffddd..63e446f3 100644
--- a/filter/source/pdf/impdialog.cxx
+++ b/filter/source/pdf/impdialog.cxx
@@ -433,7 +433,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 );
 
@@ -497,6 +498,10 @@ Sequence< PropertyValue > ImpPDFTabDialog::GetFilterData()
     aRet[ nLength - nElementAdded ].Value <<= maSignCertificate;
     nElementAdded--;
 
+    aRet[ nLength - nElementAdded ].Name = "SignatureTSA";
+    aRet[ nLength - nElementAdded ].Value <<= msSignTSA;
+    nElementAdded--;
+
     return aRet;
 }
 
@@ -1598,7 +1603,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 c8a317b..c6238ea 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 164eff9..ae396a4 100644
--- a/filter/source/pdf/pdfexport.cxx
+++ b/filter/source/pdf/pdfexport.cxx
@@ -557,6 +557,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);
 
@@ -788,6 +790,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 9357c91..4fc40b5 100644
--- a/include/vcl/pdfwriter.hxx
+++ b/include/vcl/pdfwriter.hxx
@@ -631,6 +631,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 c9a6547e5daa9ac8b47eb955af5399653b6c84c0
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 7e3daf6..e7a18b7 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -7217,13 +7217,6 @@ bool PDFWriterImpl::finalizeSignature()
     // Prepare buffer and calculate PDF file digest
     CHECK_RETURN( (osl_File_E_None == osl_setFilePos(m_aFile, 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;
 
@@ -7231,7 +7224,6 @@ bool PDFWriterImpl::finalizeSignature()
         bytesRead1 != (sal_uInt64)m_nSignatureContentOffset - 1)
     {
         SAL_WARN("vcl.pdfwriter", "First buffer read failed");
-        CertFreeCertificateContext(pCertContext);
         return false;
     }
 
@@ -7243,12 +7235,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));
@@ -7260,45 +7258,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() )
     {
@@ -7306,104 +7329,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 2fdc9c2cf1b9797f090b9b3c5fec96f4b0352bb5
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 b07859c..7e3daf6 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -6912,7 +6912,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;
@@ -6934,7 +6934,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 c54a53d96d1280e86ef55c69bab7fa99f67b3314
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 4b884bf..b07859c 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -6719,6 +6719,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)
@@ -7279,6 +7290,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 e3c43448136f7d422a25e37bf51aabda1913f643
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 c0fdbf7..4b884bf 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -6198,6 +6198,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 {
@@ -6592,7 +6617,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)
@@ -6641,7 +6667,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);
@@ -6803,20 +6829,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;
@@ -6824,8 +6923,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;
@@ -6846,12 +6945,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;
         }
@@ -6875,6 +6976,7 @@ bool PDFWriterImpl::finalizeSignature()
         if (!curl)
         {
             SAL_WARN("vcl.pdfwriter", "curl_easy_init failed");
+            free(pass);
             SECITEM_FreeItem(timestamp_request, PR_TRUE);
             return false;
         }
@@ -6884,6 +6986,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;
@@ -6895,6 +6998,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);
@@ -6905,6 +7009,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;
@@ -6916,6 +7021,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;
@@ -6924,6 +7030,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;
@@ -6933,6 +7040,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;
@@ -6943,6 +7051,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;
@@ -6951,6 +7060,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;
@@ -6981,6 +7091,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;
         }
 
@@ -6990,6 +7101,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;
         }
 
@@ -7009,11 +7121,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;
 
@@ -7021,28 +7134,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 da4008f9d210b17adf98d1565d221a038270d672
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 10cbe47..c0fdbf7 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -6592,6 +6592,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
@@ -6711,41 +6803,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)
-    {
-        SAL_WARN("vcl.pdfwriter", "NSS_CMSSignerInfo_Create failed");
-        return false;
-    }
 
     NSSCMSAttribute timestamp;
     SECItem values[2];
@@ -6965,36 +7027,6 @@ bool PDFWriterImpl::finalizeSignature()
             return false;
         }
     }
-    else if (NSS_CMSSignerInfo_AddSigningTime(cms_signer, PR_Now()) != SECSuccess)
-    {
-        SAL_WARN("vcl.pdfwriter", "NSS_CMSSignerInfo_AddSigningTime failed");
-        return false;
-    }
-
-    if (NSS_CMSSignerInfo_IncludeCerts(cms_signer, NSSCMSCM_CertChain, certUsageEmailSigner) != SECSuccess)
-    {
-        SAL_WARN("vcl.pdfwriter", "NSS_CMSSignerInfo_IncludeCerts failed");
-        return false;
-    }
-
-    if (NSS_CMSSignedData_AddCertificate(cms_sd, cert) != SECSuccess)
-    {
-        SAL_WARN("vcl.pdfwriter", "NSS_CMSSignedData_AddCertificate failed");
-        return false;
-    }
-
-    if (NSS_CMSSignedData_AddSignerInfo(cms_sd, cms_signer) != SECSuccess)
-    {
-        SAL_WARN("vcl.pdfwriter", "NSS_CMSSignedData_AddSignerInfo failed");
-        return false;
-    }
-
-    if (NSS_CMSSignedData_SetDigestValue(cms_sd, SEC_OID_SHA1, &digest) != SECSuccess)
-    {
-        SAL_WARN("vcl.pdfwriter", "NSS_CMSSignedData_SetDigestValue failed");
-        return false;
-    }
-
     SECItem cms_output;
     cms_output.data = 0;
     cms_output.len = 0;
commit 5cf3b2d51cb439a07bc067fa401588d2d9ee6fae
Author: Tor Lillqvist <tml at collabora.com>
Date:   Tue Feb 24 17:39:29 2015 +0200

    tdf#84881: Bump MAX_SIGNATURE_CONTENT_LENGTH to 50000 for now
    
    Note that checks in the code against exceeding that limit apparently are
    broken, though. After the previous change I ended up with an invalid PDF where
    the signature hex string in the output PDF had brutally overrun its
    allocation.
    
    Now Adobe Reader says "The signature includes an embedded timestamp but it
    could not be verified". This is progress. Perhaps I just need to tell Adobe
    Reader to trust the certificate from the TSA I used.
    
    (cherry picked from commit ca2d878659400b783ae72267f47d0c719b50a1ad)
    
    Conflicts:
    	vcl/source/gdi/pdfwriter_impl.cxx
    
    Change-Id: I1e8644ee641592a985e0190b52bf76839f99b3e7

diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index 3fc15fa..10cbe47 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -103,7 +103,20 @@ using namespace vcl;
 #endif
 
 #if !defined(ANDROID) && !defined(IOS)
-#define MAX_SIGNATURE_CONTENT_LENGTH 0x4000
+// Is this length truly the maximum possible, or just a number that
+// seemed large enough when the author tested this (with some type of
+// certificates)? I suspect the latter.
+
+// Used to be 0x4000 = 16384, but a sample signed PDF (produced by
+// some other software) provided by the customer has a signature
+// content that is 30000 bytes. The SampleSignedPDFDocument.pdf from
+// Adobe has one that is 21942 bytes. So let's be careful. Pity this
+// can't be dynamic, at least not without restructuring the code. Also
+// note that the checks in the code for this being too small
+// apparently are broken, if this overflows you end up with an invalid
+// PDF. Need to fix that.
+
+#define MAX_SIGNATURE_CONTENT_LENGTH 50000
 #endif
 
 #ifdef DO_TEST_PDF
commit 10dd512d4d6fa446dc7014ef9274a2565a834c08
Author: Tor Lillqvist <tml at collabora.com>
Date:   Tue Feb 24 17:45:51 2015 +0200

    tdf#84881: Set TimeStampReq::certReq to true
    
    I think Adobe Reader expects the timestamp info to include the TSA's
    certificate.
    
    Change-Id: Iedf1c4a9952b12ac61b4ba7f73bee339480e821d
    (cherry picked from commit 4702f6ae2f671ac48e4cae3cd46d5941d021e533)

diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index df316ce..3fc15fa 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -6761,9 +6761,9 @@ bool PDFWriterImpl::finalizeSignature()
         src.nonce.data = reinterpret_cast<unsigned char*>(&nNonce);
         src.nonce.len = sizeof(nNonce);
 
-        src.certReq.type = siBuffer;
-        src.certReq.data = NULL;
-        src.certReq.len = 0;
+        src.certReq.type = siUnsignedInteger;
+        src.certReq.data = &cOne;
+        src.certReq.len = sizeof(cOne);
 
         src.extensions = NULL;
 
commit 8ad04451f74e015dca9e78d22c64b1642d237be5
Author: Tor Lillqvist <tml at collabora.com>
Date:   Tue Feb 24 17:34:58 2015 +0200

    tdf#84881: Move some variables one block level out
    
    It it scary to keep pointers to stack variables that have gone out of scope in
    a data structure that is in an outer block and used there later.
    
    Change-Id: Iced8b809d50089a4e6f9867be9b8501cce59d16f
    (cherry picked from commit 5ffeec96228e0adb829612ecb855cd28e2063f1d)

diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index 174db9e..df316ce 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -6734,6 +6734,11 @@ bool PDFWriterImpl::finalizeSignature()
         return false;
     }
 
+    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() )
     {
@@ -6913,20 +6918,15 @@ bool PDFWriterImpl::finalizeSignature()
             return false;
         }
 
-        NSSCMSAttribute timestamp;
-
         // timestamp.type filled in below
 
-        SECItem values[2];
         values[0] = response.timeStampToken;
         values[1].type = siBuffer;
         values[1].data = NULL;
         values[1].len = 0;
 
-        SECItem *valuesp = values;
         timestamp.values = &valuesp;
 
-        SECOidData typetag;
         typetag.oid.data = NULL;
         // id-aa-timeStampToken OBJECT IDENTIFIER ::= { iso(1)
         // member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-9(9)
commit 8aa7a9643ca73d00f932a2c59d9468ef8d006d42
Author: Tor Lillqvist <tml at collabora.com>
Date:   Tue Feb 24 15:29:05 2015 +0200

    tdf#84881: NSSCMSAttribute::type can't be null. Must be same as typeTag.oid?
    
    Why is a separate field then needed? Dunno, but probably because the type and
    values fields make up an encoded NSSCMSAttribute. (The comment in <nss/cmst.h>
    says so, but it took a while before I realized what it meant.) The typeTag and
    encoded fields are for NSS internal use or something.
    
    Now Adobe Reader says "The signature includes an embedded timestamp but it is
    invalid". Progress...
    
    Change-Id: I390947db8d414a7ceecc1f67aaeed5fa0f66fe6f
    (cherry picked from commit 167569bfea0bfa5f697ed7a25a354537bc97fa53)

diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index 06a5604..174db9e 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -6915,9 +6915,7 @@ bool PDFWriterImpl::finalizeSignature()
 
         NSSCMSAttribute timestamp;
 
-        timestamp.type.type = siBuffer;
-        timestamp.type.data = NULL;
-        timestamp.type.len = 0;
+        // timestamp.type filled in below
 
         SECItem values[2];
         values[0] = response.timeStampToken;
@@ -6940,11 +6938,13 @@ bool PDFWriterImpl::finalizeSignature()
         }
         typetag.offset = SEC_OID_UNKNOWN; // ???
         typetag.desc = "id-aa-timeStampToken";
-        typetag.mechanism = CKM_INVALID_MECHANISM; // ???
+        typetag.mechanism = CKM_SHA256; // ???
         typetag.supportedExtension = UNSUPPORTED_CERT_EXTENSION; // ???
         timestamp.typeTag = &typetag;
 
-        timestamp.encoded = PR_TRUE;
+        timestamp.type = typetag.oid; // ???
+
+        timestamp.encoded = PR_TRUE; // ???
 
         if (my_NSS_CMSSignerInfo_AddUnauthAttr(cms_signer, &timestamp) != SECSuccess)
         {
commit 9f67d5c06c5da84976a70dddc6d5857526abc41e
Author: Tor Lillqvist <tml at collabora.com>
Date:   Tue Feb 24 11:50:54 2015 +0200

    tdf#84881: Fix typo in OID string for id-aa-timeStampToken
    
    Not that it seems to help. Adobe Reader still claims "signing time is from the
    clock on the signer's computer".
    
    (Why can't RFCs come with standard C header files (and Java and C# sources)
    defining macros/constants for the magic numbers, OIDs etc that the RFC
    defines?)
    
    Change-Id: I56e8cb4ef56e20345506a080e4d23764d2dfb956
    (cherry picked from commit c98f569d035861b6b8c74b469512fa2ae7c9576f)

diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index 419b5a4..06a5604 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -6933,7 +6933,7 @@ bool PDFWriterImpl::finalizeSignature()
         // id-aa-timeStampToken OBJECT IDENTIFIER ::= { iso(1)
         // member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-9(9)
         // smime(16) aa(2) 14 }
-        if (my_SEC_StringToOID(NULL, &typetag.oid, "1.2.840.113549.1.9.16.14", 0) != SECSuccess)
+        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");
             return false;
commit 77122b8b78ec94a25fb3de4ac9b7e6b0f0f3133c
Author: Tor Lillqvist <tml at collabora.com>
Date:   Mon Feb 23 20:09:11 2015 +0200

    SAL_WARNs are not for the end-user
    
    They can and should be terse, technical and informative. Simply say exactly
    what API function call failed. The tag and source file name in the SAL_WARN
    output should already tell a technical reader of the warning what
    functionality it is related to.
    
    Change-Id: I93509bddaca836bd6a07d2899b3faf693b071957
    (cherry picked from commit d1f679cacb2e17c4aa94ae6b9f15011c9ec74b25)

diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx
index 11fb1ae..419b5a4 100644
--- a/vcl/source/gdi/pdfwriter_impl.cxx
+++ b/vcl/source/gdi/pdfwriter_impl.cxx
@@ -6657,7 +6657,7 @@ bool PDFWriterImpl::finalizeSignature()
 
     if (!cert)
     {
-        SAL_WARN("vcl.pdfwriter", "PDF Signing: Error occurred, certificate cannot be reconstructed.");
+        SAL_WARN("vcl.pdfwriter", "CERT_DecodeCertFromPackage failed");
         return false;
     }
 
@@ -6667,7 +6667,7 @@ bool PDFWriterImpl::finalizeSignature()
     HashContextScope hc(HASH_Create(HASH_AlgSHA1));
     if (!hc.get())
     {
-        SAL_WARN("vcl.pdfwriter", "PDF Signing: SHA1 HASH_Create failed!");
+        SAL_WARN("vcl.pdfwriter", "HASH_Create failed");
         return false;
     }
 
@@ -6680,7 +6680,7 @@ bool PDFWriterImpl::finalizeSignature()
 
     CHECK_RETURN( (osl_File_E_None == osl_readFile( m_aFile, buffer.get(), m_nSignatureContentOffset - 1 , &bytesRead ) ) );
     if (bytesRead != (sal_uInt64)m_nSignatureContentOffset - 1)
-        SAL_WARN("vcl.pdfwriter", "PDF Signing: First buffer read failed!");
+        SAL_WARN("vcl.pdfwriter", "First buffer read failed");
 
     HASH_Update(hc.get(), reinterpret_cast<const unsigned char*>(buffer.get()), bytesRead);
 
@@ -6688,7 +6688,7 @@ bool PDFWriterImpl::finalizeSignature()
     buffer.reset(new char[nLastByteRangeNo + 1]);
     CHECK_RETURN( (osl_File_E_None == osl_readFile( m_aFile, buffer.get(), nLastByteRangeNo, &bytesRead ) ) );
     if (bytesRead != (sal_uInt64) nLastByteRangeNo)
-        SAL_WARN("vcl.pdfwriter", "PDF Signing: Second buffer read failed!");
+        SAL_WARN("vcl.pdfwriter", "Second buffer read failed");
 
     HASH_Update(hc.get(), reinterpret_cast<const unsigned char*>(buffer.get()), bytesRead);
 
@@ -6701,21 +6701,21 @@ bool PDFWriterImpl::finalizeSignature()
     NSSCMSMessage *cms_msg = NSS_CMSMessage_Create(NULL);
     if (!cms_msg)
     {
-        SAL_WARN("vcl.pdfwriter", "PDF signing: can't create new CMS message.");
+        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", "PDF signing: can't create CMS SignedData.");
+        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)
     {

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list