1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <documentsignaturemanager.hxx>
21 #include <config_gpgme.h>
22 
23 #include <gpg/SEInitializer.hxx>
24 
25 #include <com/sun/star/embed/StorageFormats.hpp>
26 #include <com/sun/star/embed/ElementModes.hpp>
27 #include <com/sun/star/embed/XStorage.hpp>
28 #include <com/sun/star/io/TempFile.hpp>
29 #include <com/sun/star/io/XTruncate.hpp>
30 #include <com/sun/star/embed/XTransactedObject.hpp>
31 #include <com/sun/star/xml/crypto/SEInitializer.hpp>
32 #include <com/sun/star/lang/XServiceInfo.hpp>
33 #include <com/sun/star/beans/PropertyValue.hpp>
34 #include <com/sun/star/packages/manifest/ManifestReader.hpp>
35 #include <com/sun/star/container/XNameAccess.hpp>
36 #include <com/sun/star/xml/sax/XDocumentHandler.hpp>
37 
38 #include <comphelper/base64.hxx>
39 #include <comphelper/storagehelper.hxx>
40 #include <rtl/ustrbuf.hxx>
41 #include <sal/log.hxx>
42 #include <tools/datetime.hxx>
43 
44 #include <certificate.hxx>
45 #include <biginteger.hxx>
46 
47 #include <xmlsec/xmlsec_init.hxx>
48 
49 #include <pdfsignaturehelper.hxx>
50 
51 #include <memory>
52 
53 using namespace css;
54 using namespace css::graphic;
55 using namespace css::uno;
56 
DocumentSignatureManager(const uno::Reference<uno::XComponentContext> & xContext,DocumentSignatureMode eMode)57 DocumentSignatureManager::DocumentSignatureManager(
58     const uno::Reference<uno::XComponentContext>& xContext, DocumentSignatureMode eMode)
59     : mxContext(xContext)
60     , maSignatureHelper(xContext)
61     , meSignatureMode(eMode)
62 {
63 }
64 
~DocumentSignatureManager()65 DocumentSignatureManager::~DocumentSignatureManager() { deInitXmlSec(); }
66 
init()67 bool DocumentSignatureManager::init()
68 {
69     SAL_WARN_IF(mxSEInitializer.is(), "xmlsecurity.helper",
70                 "DocumentSignatureManager::Init - mxSEInitializer already set!");
71     SAL_WARN_IF(mxSecurityContext.is(), "xmlsecurity.helper",
72                 "DocumentSignatureManager::Init - mxSecurityContext already set!");
73     SAL_WARN_IF(mxGpgSEInitializer.is(), "xmlsecurity.helper",
74                 "DocumentSignatureManager::Init - mxGpgSEInitializer already set!");
75 
76     // xmlsec is needed by both services, so init before those
77     initXmlSec();
78 
79     mxSEInitializer = xml::crypto::SEInitializer::create(mxContext);
80 #if HAVE_FEATURE_GPGME
81     mxGpgSEInitializer.set(new SEInitializerGpg());
82 #endif
83 
84     if (mxSEInitializer.is())
85         mxSecurityContext = mxSEInitializer->createSecurityContext(OUString());
86 
87 #if HAVE_FEATURE_GPGME
88     if (mxGpgSEInitializer.is())
89         mxGpgSecurityContext = mxGpgSEInitializer->createSecurityContext(OUString());
90 
91     return mxSecurityContext.is() || mxGpgSecurityContext.is();
92 #else
93     return mxSecurityContext.is();
94 #endif
95 }
96 
getPDFSignatureHelper()97 PDFSignatureHelper& DocumentSignatureManager::getPDFSignatureHelper()
98 {
99     bool bInit = true;
100     if (!mxSecurityContext.is())
101         bInit = init();
102 
103     SAL_WARN_IF(!bInit, "xmlsecurity.comp", "Error initializing security context!");
104 
105     if (!mpPDFSignatureHelper)
106         mpPDFSignatureHelper = std::make_unique<PDFSignatureHelper>();
107 
108     return *mpPDFSignatureHelper;
109 }
110 
111 #if 0 // For some reason does not work
112 bool DocumentSignatureManager::IsXAdESRelevant()
113 {
114     if (mxStore.is())
115     {
116         // ZIP-based: ODF or OOXML.
117         maSignatureHelper.StartMission();
118 
119         SignatureStreamHelper aStreamHelper = ImplOpenSignatureStream(embed::ElementModes::READ, /*bUseTempStream=*/true);
120         if (aStreamHelper.nStorageFormat == embed::StorageFormats::OFOPXML)
121         {
122             maSignatureHelper.EndMission();
123             return false;
124         }
125         // FIXME: How to figure out if it is ODF 1.2?
126         maSignatureHelper.EndMission();
127         return true;
128     }
129     return false;
130 }
131 #endif
132 
readManifest()133 bool DocumentSignatureManager::readManifest()
134 {
135     // Check if manifest was already read
136     if (m_manifest.hasElements())
137         return true;
138 
139     if (!mxContext.is())
140         return false;
141 
142     if (!mxStore.is())
143         return false;
144 
145     uno::Reference<packages::manifest::XManifestReader> xReader
146         = packages::manifest::ManifestReader::create(mxContext);
147 
148     if (mxStore->hasByName("META-INF"))
149     {
150         //Get the manifest.xml
151         uno::Reference<embed::XStorage> xSubStore(
152             mxStore->openStorageElement("META-INF", embed::ElementModes::READ), UNO_SET_THROW);
153 
154         uno::Reference<io::XInputStream> xStream(
155             xSubStore->openStreamElement("manifest.xml", css::embed::ElementModes::READ),
156             UNO_QUERY_THROW);
157 
158         m_manifest = xReader->readManifestSequence(xStream);
159     }
160     return true;
161 }
162 
163 /* Using the zip storage, we cannot get the properties "MediaType" and "IsEncrypted"
164     We use the manifest to find out if a file is xml and if it is encrypted.
165     The parameter is an encoded uri. However, the manifest contains paths. Therefore
166     the path is encoded as uri, so they can be compared.
167 */
isXML(const OUString & rURI)168 bool DocumentSignatureManager::isXML(const OUString& rURI)
169 {
170     SAL_WARN_IF(!mxStore.is(), "xmlsecurity.helper", "empty storage reference");
171 
172     bool bIsXML = false;
173     bool bPropsAvailable = false;
174     const OUString sPropFullPath("FullPath");
175     const OUString sPropMediaType("MediaType");
176     const OUString sPropDigest("Digest");
177 
178     if (readManifest())
179     {
180         for (const uno::Sequence<beans::PropertyValue>& entry : std::as_const(m_manifest))
181         {
182             OUString sPath;
183             OUString sMediaType;
184             bool bEncrypted = false;
185             for (const beans::PropertyValue& prop : entry)
186             {
187                 if (prop.Name == sPropFullPath)
188                     prop.Value >>= sPath;
189                 else if (prop.Name == sPropMediaType)
190                     prop.Value >>= sMediaType;
191                 else if (prop.Name == sPropDigest)
192                     bEncrypted = true;
193             }
194             if (DocumentSignatureHelper::equalsReferenceUriManifestPath(rURI, sPath))
195             {
196                 bIsXML = sMediaType == "text/xml" && !bEncrypted;
197                 bPropsAvailable = true;
198                 break;
199             }
200         }
201     }
202     if (!bPropsAvailable)
203     {
204         //This would be the case for at least mimetype, META-INF/manifest.xml
205         //META-INF/macrosignatures.xml.
206         //Files can only be encrypted if they are in the manifest.xml.
207         //That is, the current file cannot be encrypted, otherwise bPropsAvailable
208         //would be true.
209         sal_Int32 nSep = rURI.lastIndexOf('.');
210         if (nSep != -1)
211         {
212             OUString aExt = rURI.copy(nSep + 1);
213             if (aExt.equalsIgnoreAsciiCase("XML"))
214                 bIsXML = true;
215         }
216     }
217     return bIsXML;
218 }
219 
220 //If bTempStream is true, then a temporary stream is return. If it is false then, the actual
221 //signature stream is used.
222 //Every time the user presses Add a new temporary stream is created.
223 //We keep the temporary stream as member because ImplGetSignatureInformations
224 //will later access the stream to create DocumentSignatureInformation objects
225 //which are stored in maCurrentSignatureInformations.
ImplOpenSignatureStream(sal_Int32 nStreamOpenMode,bool bTempStream)226 SignatureStreamHelper DocumentSignatureManager::ImplOpenSignatureStream(sal_Int32 nStreamOpenMode,
227                                                                         bool bTempStream)
228 {
229     SignatureStreamHelper aHelper;
230     if (mxStore.is() && mxStore->hasByName("[Content_Types].xml"))
231         aHelper.nStorageFormat = embed::StorageFormats::OFOPXML;
232 
233     if (bTempStream)
234     {
235         if (nStreamOpenMode & embed::ElementModes::TRUNCATE)
236         {
237             //We write always into a new temporary stream.
238             mxTempSignatureStream.set(io::TempFile::create(mxContext), uno::UNO_QUERY_THROW);
239             if (aHelper.nStorageFormat != embed::StorageFormats::OFOPXML)
240                 aHelper.xSignatureStream = mxTempSignatureStream;
241             else
242             {
243                 mxTempSignatureStorage = comphelper::OStorageHelper::GetStorageOfFormatFromStream(
244                     ZIP_STORAGE_FORMAT_STRING, mxTempSignatureStream);
245                 aHelper.xSignatureStorage = mxTempSignatureStorage;
246             }
247         }
248         else
249         {
250             //When we read from the temp stream, then we must have previously
251             //created one.
252             SAL_WARN_IF(!mxTempSignatureStream.is(), "xmlsecurity.helper",
253                         "empty temp. signature stream reference");
254         }
255         aHelper.xSignatureStream = mxTempSignatureStream;
256         if (aHelper.nStorageFormat == embed::StorageFormats::OFOPXML)
257             aHelper.xSignatureStorage = mxTempSignatureStorage;
258     }
259     else
260     {
261         //No temporary stream
262         if (!mxSignatureStream.is())
263         {
264             //We may not have a dedicated stream for writing the signature
265             //So we take one directly from the storage
266             //Or DocumentDigitalSignatures::showDocumentContentSignatures was called,
267             //in which case Add/Remove is not allowed. This is done, for example, if the
268             //document is readonly
269             aHelper = DocumentSignatureHelper::OpenSignatureStream(mxStore, nStreamOpenMode,
270                                                                    meSignatureMode);
271         }
272         else
273         {
274             aHelper.xSignatureStream = mxSignatureStream;
275         }
276     }
277 
278     if (nStreamOpenMode & embed::ElementModes::TRUNCATE)
279     {
280         if (aHelper.xSignatureStream.is()
281             && aHelper.nStorageFormat != embed::StorageFormats::OFOPXML)
282         {
283             uno::Reference<io::XTruncate> xTruncate(aHelper.xSignatureStream, uno::UNO_QUERY_THROW);
284             xTruncate->truncate();
285         }
286     }
287     else if (bTempStream || mxSignatureStream.is())
288     {
289         //In case we read the signature stream from the storage directly,
290         //which is the case when DocumentDigitalSignatures::showDocumentContentSignatures
291         //then XSeakable is not supported
292         uno::Reference<io::XSeekable> xSeek(aHelper.xSignatureStream, uno::UNO_QUERY_THROW);
293         xSeek->seek(0);
294     }
295 
296     return aHelper;
297 }
298 
add(const uno::Reference<security::XCertificate> & xCert,const uno::Reference<xml::crypto::XXMLSecurityContext> & xSecurityContext,const OUString & rDescription,sal_Int32 & nSecurityId,bool bAdESCompliant,const OUString & rSignatureLineId,const Reference<XGraphic> & xValidGraphic,const Reference<XGraphic> & xInvalidGraphic)299 bool DocumentSignatureManager::add(
300     const uno::Reference<security::XCertificate>& xCert,
301     const uno::Reference<xml::crypto::XXMLSecurityContext>& xSecurityContext,
302     const OUString& rDescription, sal_Int32& nSecurityId, bool bAdESCompliant,
303     const OUString& rSignatureLineId, const Reference<XGraphic>& xValidGraphic,
304     const Reference<XGraphic>& xInvalidGraphic)
305 {
306     if (!xCert.is())
307     {
308         SAL_WARN("xmlsecurity.helper", "no certificate selected");
309         return false;
310     }
311 
312     // GPG or X509 key?
313     uno::Reference<lang::XServiceInfo> xServiceInfo(xSecurityContext, uno::UNO_QUERY);
314     if (xServiceInfo->getImplementationName()
315         == "com.sun.star.xml.security.gpg.XMLSecurityContext_GpgImpl")
316     {
317         // GPG keys only really have PGPKeyId and PGPKeyPacket
318         if (!mxStore.is())
319         {
320             SAL_WARN("xmlsecurity.helper", "cannot sign pdfs with GPG keys");
321             return false;
322         }
323 
324         maSignatureHelper.StartMission(xSecurityContext);
325 
326         nSecurityId = maSignatureHelper.GetNewSecurityId();
327 
328         OUStringBuffer aStrBuffer;
329         comphelper::Base64::encode(aStrBuffer, xCert->getEncoded());
330 
331         OUString aKeyId;
332         if (auto pCertificate = dynamic_cast<xmlsecurity::Certificate*>(xCert.get()))
333         {
334             OUStringBuffer aBuffer;
335             comphelper::Base64::encode(aBuffer, pCertificate->getSHA256Thumbprint());
336             aKeyId = aBuffer.makeStringAndClear();
337         }
338         else
339             SAL_WARN("xmlsecurity.helper",
340                      "XCertificate implementation without an xmlsecurity::Certificate one");
341 
342         maSignatureHelper.SetGpgCertificate(nSecurityId, aKeyId, aStrBuffer.makeStringAndClear(),
343                                             xCert->getIssuerName());
344     }
345     else
346     {
347         OUString aCertSerial = xmlsecurity::bigIntegerToNumericString(xCert->getSerialNumber());
348         if (aCertSerial.isEmpty())
349         {
350             SAL_WARN("xmlsecurity.helper", "Error in Certificate, problem with serial number!");
351             return false;
352         }
353 
354         if (!mxStore.is())
355         {
356             // Something not ZIP based, try PDF.
357             nSecurityId = getPDFSignatureHelper().GetNewSecurityId();
358             getPDFSignatureHelper().SetX509Certificate(xCert);
359             getPDFSignatureHelper().SetDescription(rDescription);
360             uno::Reference<io::XInputStream> xInputStream(mxSignatureStream, uno::UNO_QUERY);
361             if (!getPDFSignatureHelper().Sign(xInputStream, bAdESCompliant))
362             {
363                 SAL_WARN("xmlsecurity.helper", "PDFSignatureHelper::Sign() failed");
364                 return false;
365             }
366             return true;
367         }
368 
369         maSignatureHelper.StartMission(xSecurityContext);
370 
371         nSecurityId = maSignatureHelper.GetNewSecurityId();
372 
373         OUStringBuffer aStrBuffer;
374         comphelper::Base64::encode(aStrBuffer, xCert->getEncoded());
375 
376         OUString aCertDigest;
377         svl::crypto::SignatureMethodAlgorithm eAlgorithmID
378             = svl::crypto::SignatureMethodAlgorithm::RSA;
379         if (auto pCertificate = dynamic_cast<xmlsecurity::Certificate*>(xCert.get()))
380         {
381             OUStringBuffer aBuffer;
382             comphelper::Base64::encode(aBuffer, pCertificate->getSHA256Thumbprint());
383             aCertDigest = aBuffer.makeStringAndClear();
384 
385             eAlgorithmID = pCertificate->getSignatureMethodAlgorithm();
386         }
387         else
388             SAL_WARN("xmlsecurity.helper",
389                      "XCertificate implementation without an xmlsecurity::Certificate one");
390 
391         maSignatureHelper.SetX509Certificate(nSecurityId, xCert->getIssuerName(), aCertSerial,
392                                              aStrBuffer.makeStringAndClear(), aCertDigest,
393                                              eAlgorithmID);
394     }
395 
396     const uno::Sequence<uno::Reference<security::XCertificate>> aCertPath
397         = xSecurityContext->getSecurityEnvironment()->buildCertificatePath(xCert);
398 
399     OUStringBuffer aStrBuffer;
400     for (uno::Reference<security::XCertificate> const& rxCertificate : aCertPath)
401     {
402         comphelper::Base64::encode(aStrBuffer, rxCertificate->getEncoded());
403         OUString aString = aStrBuffer.makeStringAndClear();
404         maSignatureHelper.AddEncapsulatedX509Certificate(aString);
405     }
406 
407     std::vector<OUString> aElements = DocumentSignatureHelper::CreateElementList(
408         mxStore, meSignatureMode, DocumentSignatureAlgorithm::OOo3_2);
409     DocumentSignatureHelper::AppendContentTypes(mxStore, aElements);
410 
411     for (OUString const& rUri : aElements)
412     {
413         bool bBinaryMode = !isXML(rUri);
414         maSignatureHelper.AddForSigning(nSecurityId, rUri, bBinaryMode, bAdESCompliant);
415     }
416 
417     maSignatureHelper.SetDateTime(nSecurityId, DateTime(DateTime::SYSTEM));
418     maSignatureHelper.SetDescription(nSecurityId, rDescription);
419 
420     if (!rSignatureLineId.isEmpty())
421         maSignatureHelper.SetSignatureLineId(nSecurityId, rSignatureLineId);
422 
423     if (xValidGraphic.is())
424         maSignatureHelper.SetSignatureLineValidGraphic(nSecurityId, xValidGraphic);
425 
426     if (xInvalidGraphic.is())
427         maSignatureHelper.SetSignatureLineInvalidGraphic(nSecurityId, xInvalidGraphic);
428 
429     // We open a signature stream in which the existing and the new
430     //signature is written. ImplGetSignatureInformation (later in this function) will
431     //then read the stream and fill maCurrentSignatureInformations. The final signature
432     //is written when the user presses OK. Then only maCurrentSignatureInformation and
433     //a sax writer are used to write the information.
434     SignatureStreamHelper aStreamHelper
435         = ImplOpenSignatureStream(embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE, true);
436 
437     if (aStreamHelper.nStorageFormat != embed::StorageFormats::OFOPXML)
438     {
439         uno::Reference<io::XOutputStream> xOutputStream(aStreamHelper.xSignatureStream,
440                                                         uno::UNO_QUERY_THROW);
441         uno::Reference<xml::sax::XWriter> xSaxWriter
442             = maSignatureHelper.CreateDocumentHandlerWithHeader(xOutputStream);
443 
444         // Export old signatures...
445         uno::Reference<xml::sax::XDocumentHandler> xDocumentHandler(xSaxWriter,
446                                                                     uno::UNO_QUERY_THROW);
447         std::size_t nInfos = maCurrentSignatureInformations.size();
448         for (std::size_t n = 0; n < nInfos; n++)
449             XMLSignatureHelper::ExportSignature(xDocumentHandler, maCurrentSignatureInformations[n],
450                                                 bAdESCompliant);
451 
452         // Create a new one...
453         maSignatureHelper.CreateAndWriteSignature(xDocumentHandler, bAdESCompliant);
454 
455         // That's it...
456         XMLSignatureHelper::CloseDocumentHandler(xDocumentHandler);
457     }
458     else
459     {
460         // OOXML
461 
462         // Handle relations.
463         maSignatureHelper.EnsureSignaturesRelation(mxStore, /*bAdd=*/true);
464         // Old signatures + the new one.
465         int nSignatureCount = maCurrentSignatureInformations.size() + 1;
466         maSignatureHelper.ExportSignatureRelations(aStreamHelper.xSignatureStorage,
467                                                    nSignatureCount);
468 
469         // Export old signatures.
470         for (std::size_t i = 0; i < maCurrentSignatureInformations.size(); ++i)
471             maSignatureHelper.ExportOOXMLSignature(mxStore, aStreamHelper.xSignatureStorage,
472                                                    maCurrentSignatureInformations[i], i + 1);
473 
474         // Create a new signature.
475         maSignatureHelper.CreateAndWriteOOXMLSignature(mxStore, aStreamHelper.xSignatureStorage,
476                                                        nSignatureCount);
477 
478         // Flush objects.
479         uno::Reference<embed::XTransactedObject> xTransact(aStreamHelper.xSignatureStorage,
480                                                            uno::UNO_QUERY);
481         xTransact->commit();
482         uno::Reference<io::XOutputStream> xOutputStream(aStreamHelper.xSignatureStream,
483                                                         uno::UNO_QUERY);
484         xOutputStream->closeOutput();
485 
486         uno::Reference<io::XTempFile> xTempFile(aStreamHelper.xSignatureStream, uno::UNO_QUERY);
487         SAL_INFO("xmlsecurity.helper",
488                  "DocumentSignatureManager::add temporary storage at " << xTempFile->getUri());
489     }
490 
491     maSignatureHelper.EndMission();
492     return true;
493 }
494 
remove(sal_uInt16 nPosition)495 void DocumentSignatureManager::remove(sal_uInt16 nPosition)
496 {
497     if (!mxStore.is())
498     {
499         // Something not ZIP based, try PDF.
500         uno::Reference<io::XInputStream> xInputStream(mxSignatureStream, uno::UNO_QUERY);
501         if (!PDFSignatureHelper::RemoveSignature(xInputStream, nPosition))
502         {
503             SAL_WARN("xmlsecurity.helper", "PDFSignatureHelper::RemoveSignature() failed");
504             return;
505         }
506 
507         // Only erase when the removal was successful, it may fail for PDF.
508         // Also, erase the requested and all following signatures, as PDF signatures are always chained.
509         maCurrentSignatureInformations.erase(maCurrentSignatureInformations.begin() + nPosition,
510                                              maCurrentSignatureInformations.end());
511         return;
512     }
513 
514     maCurrentSignatureInformations.erase(maCurrentSignatureInformations.begin() + nPosition);
515 
516     // Export all other signatures...
517     SignatureStreamHelper aStreamHelper = ImplOpenSignatureStream(
518         embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE, /*bTempStream=*/true);
519 
520     if (aStreamHelper.nStorageFormat != embed::StorageFormats::OFOPXML)
521     {
522         uno::Reference<io::XOutputStream> xOutputStream(aStreamHelper.xSignatureStream,
523                                                         uno::UNO_QUERY_THROW);
524         uno::Reference<xml::sax::XWriter> xSaxWriter
525             = maSignatureHelper.CreateDocumentHandlerWithHeader(xOutputStream);
526 
527         uno::Reference<xml::sax::XDocumentHandler> xDocumentHandler(xSaxWriter,
528                                                                     uno::UNO_QUERY_THROW);
529         std::size_t nInfos = maCurrentSignatureInformations.size();
530         for (std::size_t n = 0; n < nInfos; ++n)
531             XMLSignatureHelper::ExportSignature(xDocumentHandler, maCurrentSignatureInformations[n],
532                                                 false /* ??? */);
533 
534         XMLSignatureHelper::CloseDocumentHandler(xDocumentHandler);
535     }
536     else
537     {
538         // OOXML
539 
540         // Handle relations.
541         int nSignatureCount = maCurrentSignatureInformations.size();
542         maSignatureHelper.ExportSignatureRelations(aStreamHelper.xSignatureStorage,
543                                                    nSignatureCount);
544 
545         // Export old signatures.
546         for (std::size_t i = 0; i < maCurrentSignatureInformations.size(); ++i)
547             maSignatureHelper.ExportOOXMLSignature(mxStore, aStreamHelper.xSignatureStorage,
548                                                    maCurrentSignatureInformations[i], i + 1);
549 
550         // Flush objects.
551         uno::Reference<embed::XTransactedObject> xTransact(aStreamHelper.xSignatureStorage,
552                                                            uno::UNO_QUERY);
553         xTransact->commit();
554         uno::Reference<io::XOutputStream> xOutputStream(aStreamHelper.xSignatureStream,
555                                                         uno::UNO_QUERY);
556         xOutputStream->closeOutput();
557 
558         uno::Reference<io::XTempFile> xTempFile(aStreamHelper.xSignatureStream, uno::UNO_QUERY);
559         SAL_INFO("xmlsecurity.helper", "DocumentSignatureManager::remove: temporary storage is at "
560                                            << xTempFile->getUri());
561     }
562 }
563 
read(bool bUseTempStream,bool bCacheLastSignature)564 void DocumentSignatureManager::read(bool bUseTempStream, bool bCacheLastSignature)
565 {
566     maCurrentSignatureInformations.clear();
567 
568     if (mxStore.is())
569     {
570         // ZIP-based: ODF or OOXML.
571         maSignatureHelper.StartMission(mxSecurityContext);
572 
573         SignatureStreamHelper aStreamHelper
574             = ImplOpenSignatureStream(embed::ElementModes::READ, bUseTempStream);
575         if (aStreamHelper.nStorageFormat != embed::StorageFormats::OFOPXML
576             && aStreamHelper.xSignatureStream.is())
577         {
578             uno::Reference<io::XInputStream> xInputStream(aStreamHelper.xSignatureStream,
579                                                           uno::UNO_QUERY);
580             maSignatureHelper.ReadAndVerifySignature(xInputStream);
581         }
582         else if (aStreamHelper.nStorageFormat == embed::StorageFormats::OFOPXML
583                  && aStreamHelper.xSignatureStorage.is())
584             maSignatureHelper.ReadAndVerifySignatureStorage(aStreamHelper.xSignatureStorage,
585                                                             bCacheLastSignature);
586         maSignatureHelper.EndMission();
587 
588         maCurrentSignatureInformations = maSignatureHelper.GetSignatureInformations();
589     }
590     else
591     {
592         // Something not ZIP based, try PDF.
593         uno::Reference<io::XInputStream> xInputStream(mxSignatureStream, uno::UNO_QUERY);
594         if (getPDFSignatureHelper().ReadAndVerifySignature(xInputStream))
595             maCurrentSignatureInformations = getPDFSignatureHelper().GetSignatureInformations();
596     }
597 }
598 
write(bool bXAdESCompliantIfODF)599 void DocumentSignatureManager::write(bool bXAdESCompliantIfODF)
600 {
601     if (!mxStore.is())
602     {
603         // Something not ZIP based, assume PDF, which is written directly in add() already.
604         return;
605     }
606 
607     // Export all other signatures...
608     SignatureStreamHelper aStreamHelper = ImplOpenSignatureStream(
609         embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE, false);
610 
611     if (aStreamHelper.xSignatureStream.is()
612         && aStreamHelper.nStorageFormat != embed::StorageFormats::OFOPXML)
613     {
614         // ODF
615         uno::Reference<io::XOutputStream> xOutputStream(aStreamHelper.xSignatureStream,
616                                                         uno::UNO_QUERY);
617         uno::Reference<xml::sax::XWriter> xSaxWriter
618             = maSignatureHelper.CreateDocumentHandlerWithHeader(xOutputStream);
619 
620         uno::Reference<xml::sax::XDocumentHandler> xDocumentHandler(xSaxWriter,
621                                                                     uno::UNO_QUERY_THROW);
622         std::size_t nInfos = maCurrentSignatureInformations.size();
623         for (std::size_t n = 0; n < nInfos; ++n)
624             XMLSignatureHelper::ExportSignature(xDocumentHandler, maCurrentSignatureInformations[n],
625                                                 bXAdESCompliantIfODF);
626 
627         XMLSignatureHelper::CloseDocumentHandler(xDocumentHandler);
628     }
629     else if (aStreamHelper.xSignatureStorage.is()
630              && aStreamHelper.nStorageFormat == embed::StorageFormats::OFOPXML)
631     {
632         // OOXML
633         std::size_t nSignatureCount = maCurrentSignatureInformations.size();
634         maSignatureHelper.ExportSignatureContentTypes(mxStore, nSignatureCount);
635         if (nSignatureCount > 0)
636             maSignatureHelper.ExportSignatureRelations(aStreamHelper.xSignatureStorage,
637                                                        nSignatureCount);
638         else
639         {
640             // Removing all signatures: then need to remove the signature relation as well.
641             maSignatureHelper.EnsureSignaturesRelation(mxStore, /*bAdd=*/false);
642             // Also remove the whole signature sub-storage: release our read-write reference + remove the element.
643             aStreamHelper = SignatureStreamHelper();
644             mxStore->removeElement("_xmlsignatures");
645         }
646 
647         for (std::size_t i = 0; i < nSignatureCount; ++i)
648             maSignatureHelper.ExportOOXMLSignature(mxStore, aStreamHelper.xSignatureStorage,
649                                                    maCurrentSignatureInformations[i], i + 1);
650     }
651 
652     // If stream was not provided, we are responsible for committing it...
653     if (!mxSignatureStream.is() && aStreamHelper.xSignatureStorage.is())
654     {
655         uno::Reference<embed::XTransactedObject> xTrans(aStreamHelper.xSignatureStorage,
656                                                         uno::UNO_QUERY);
657         xTrans->commit();
658     }
659 }
660 
getSecurityEnvironment()661 uno::Reference<xml::crypto::XSecurityEnvironment> DocumentSignatureManager::getSecurityEnvironment()
662 {
663     return mxSecurityContext.is() ? mxSecurityContext->getSecurityEnvironment()
664                                   : uno::Reference<xml::crypto::XSecurityEnvironment>();
665 }
666 
667 uno::Reference<xml::crypto::XSecurityEnvironment>
getGpgSecurityEnvironment()668 DocumentSignatureManager::getGpgSecurityEnvironment()
669 {
670     return mxGpgSecurityContext.is() ? mxGpgSecurityContext->getSecurityEnvironment()
671                                      : uno::Reference<xml::crypto::XSecurityEnvironment>();
672 }
673 
674 uno::Reference<xml::crypto::XXMLSecurityContext> const&
getSecurityContext() const675 DocumentSignatureManager::getSecurityContext() const
676 {
677     return mxSecurityContext;
678 }
679 
680 uno::Reference<xml::crypto::XXMLSecurityContext> const&
getGpgSecurityContext() const681 DocumentSignatureManager::getGpgSecurityContext() const
682 {
683     return mxGpgSecurityContext;
684 }
685 
686 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
687