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