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 <resourcemanager.hxx>
21 
22 #include <digitalsignaturesdialog.hxx>
23 #include <certificatechooser.hxx>
24 #include <certificateviewer.hxx>
25 #include <macrosecurity.hxx>
26 #include <biginteger.hxx>
27 #include <strings.hrc>
28 #include <pdfsignaturehelper.hxx>
29 #include <sax/tools/converter.hxx>
30 
31 #include <com/sun/star/embed/XStorage.hpp>
32 #include <com/sun/star/embed/StorageFormats.hpp>
33 #include <com/sun/star/embed/XTransactedObject.hpp>
34 #include <com/sun/star/embed/ElementModes.hpp>
35 #include <com/sun/star/lang/XInitialization.hpp>
36 #include <com/sun/star/lang/XServiceInfo.hpp>
37 #include <com/sun/star/ucb/XContent.hpp>
38 #include <com/sun/star/ucb/XContentIdentifierFactory.hpp>
39 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
40 #include <com/sun/star/ucb/XCommandProcessor.hpp>
41 #include <com/sun/star/ucb/Command.hpp>
42 #include <com/sun/star/uno/SecurityException.hpp>
43 #include <vcl/weld.hxx>
44 #include <vcl/svapp.hxx>
45 #include <tools/date.hxx>
46 #include <unotools/securityoptions.hxx>
47 #include <com/sun/star/security/CertificateValidity.hpp>
48 #include <com/sun/star/security/CertificateKind.hpp>
49 #include <comphelper/base64.hxx>
50 #include <comphelper/documentconstants.hxx>
51 #include <comphelper/propertyvalue.hxx>
52 #include <comphelper/sequence.hxx>
53 #include <cppuhelper/implbase.hxx>
54 #include <comphelper/xmlsechelper.hxx>
55 #include <cppuhelper/supportsservice.hxx>
56 #include <sal/log.hxx>
57 #include <com/sun/star/lang/IllegalArgumentException.hpp>
58 #include <com/sun/star/security/XDocumentDigitalSignatures.hpp>
59 #include <com/sun/star/xml/crypto/XXMLSecurityContext.hpp>
60 
61 #include <map>
62 
63 using namespace css;
64 using namespace css::uno;
65 using namespace css::lang;
66 using namespace css::security;
67 using namespace css::xml::crypto;
68 
69 class DocumentDigitalSignatures
70     : public cppu::WeakImplHelper<css::security::XDocumentDigitalSignatures,
71                                   css::lang::XInitialization, css::lang::XServiceInfo>
72 {
73 private:
74     css::uno::Reference<css::uno::XComponentContext> mxCtx;
75     css::uno::Reference<css::awt::XWindow> mxParentWindow;
76 
77     /// will be set by XInitialization. If not we assume true. false means an earlier version (whatever that means,
78     /// this is a string, not a boolean).
79     /// Note that the code talks about "ODF version" even if this class is also used to sign OOXML.
80     OUString m_sODFVersion;
81     /// The number of arguments which were passed in XInitialization::initialize
82     int m_nArgumentsCount;
83     /// Indicates if the document already contains a document signature
84     bool m_bHasDocumentSignature;
85 
86     /// @throws css::uno::RuntimeException
87     bool ImplViewSignatures(const css::uno::Reference<css::embed::XStorage>& rxStorage,
88                             const css::uno::Reference<css::io::XStream>& xSignStream,
89                             DocumentSignatureMode eMode, bool bReadOnly);
90     /// @throws css::uno::RuntimeException
91     void ImplViewSignatures(const css::uno::Reference<css::embed::XStorage>& rxStorage,
92                             const css::uno::Reference<css::io::XInputStream>& xSignStream,
93                             DocumentSignatureMode eMode, bool bReadOnly);
94     /// @throws css::uno::RuntimeException
95     css::uno::Sequence<css::security::DocumentSignatureInformation>
96     ImplVerifySignatures(const css::uno::Reference<css::embed::XStorage>& rxStorage,
97                          const ::com::sun::star::uno::Reference<css::io::XInputStream>& xSignStream,
98                          DocumentSignatureMode eMode);
99 
100     css::uno::Sequence<css::uno::Reference<css::security::XCertificate>>
101     chooseCertificatesImpl(std::map<OUString, OUString>& rProperties, const UserAction eAction,
102                            const CertificateKind certificateKind=CertificateKind_NONE);
103 
104 public:
105     explicit DocumentDigitalSignatures(
106         const css::uno::Reference<css::uno::XComponentContext>& rxCtx);
107 
108     //XInitialization
109     void SAL_CALL initialize(const css::uno::Sequence<css::uno::Any>& aArguments) override;
110 
111     OUString SAL_CALL getImplementationName() override;
112 
113     sal_Bool SAL_CALL supportsService(OUString const& ServiceName) override;
114 
115     css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
116 
117     // XDocumentDigitalSignatures
118     sal_Bool SAL_CALL
119     signDocumentContent(const css::uno::Reference<css::embed::XStorage>& xStorage,
120                         const css::uno::Reference<css::io::XStream>& xSignStream) override;
121     sal_Bool SAL_CALL signSignatureLine(
122         const css::uno::Reference<css::embed::XStorage>& Storage,
123         const css::uno::Reference<css::io::XStream>& xSignStream, const OUString& aSignatureLineId,
124         const Reference<css::security::XCertificate>& xCertificate,
125         const Reference<css::graphic::XGraphic>& xValidGraphic,
126         const Reference<css::graphic::XGraphic>& xInvalidGraphic,
127         const OUString& aComment) override;
128     css::uno::Sequence<css::security::DocumentSignatureInformation>
129         SAL_CALL verifyDocumentContentSignatures(
130             const css::uno::Reference<css::embed::XStorage>& xStorage,
131             const css::uno::Reference<css::io::XInputStream>& xSignInStream) override;
132     void SAL_CALL showDocumentContentSignatures(
133         const css::uno::Reference<css::embed::XStorage>& xStorage,
134         const css::uno::Reference<css::io::XInputStream>& xSignInStream) override;
135     OUString SAL_CALL getDocumentContentSignatureDefaultStreamName() override;
136     sal_Bool SAL_CALL
137     signScriptingContent(const css::uno::Reference<css::embed::XStorage>& xStorage,
138                          const css::uno::Reference<css::io::XStream>& xSignStream) override;
139     css::uno::Sequence<css::security::DocumentSignatureInformation>
140         SAL_CALL verifyScriptingContentSignatures(
141             const css::uno::Reference<css::embed::XStorage>& xStorage,
142             const css::uno::Reference<css::io::XInputStream>& xSignInStream) override;
143     void SAL_CALL showScriptingContentSignatures(
144         const css::uno::Reference<css::embed::XStorage>& xStorage,
145         const css::uno::Reference<css::io::XInputStream>& xSignInStream) override;
146     OUString SAL_CALL getScriptingContentSignatureDefaultStreamName() override;
147     sal_Bool SAL_CALL
148     signPackage(const css::uno::Reference<css::embed::XStorage>& Storage,
149                 const css::uno::Reference<css::io::XStream>& xSignStream) override;
150     css::uno::Sequence<css::security::DocumentSignatureInformation>
151         SAL_CALL verifyPackageSignatures(
152             const css::uno::Reference<css::embed::XStorage>& Storage,
153             const css::uno::Reference<css::io::XInputStream>& xSignInStream) override;
154     void SAL_CALL
155     showPackageSignatures(const css::uno::Reference<css::embed::XStorage>& xStorage,
156                           const css::uno::Reference<css::io::XInputStream>& xSignInStream) override;
157     OUString SAL_CALL getPackageSignatureDefaultStreamName() override;
158     void SAL_CALL
159     showCertificate(const css::uno::Reference<css::security::XCertificate>& Certificate) override;
160     void SAL_CALL manageTrustedSources() override;
161     sal_Bool SAL_CALL
162     isAuthorTrusted(const css::uno::Reference<css::security::XCertificate>& Author) override;
163     sal_Bool SAL_CALL isLocationTrusted(const OUString& Location) override;
164     void SAL_CALL addAuthorToTrustedSources(
165         const css::uno::Reference<css::security::XCertificate>& Author) override;
166     void SAL_CALL addLocationToTrustedSources(const OUString& Location) override;
167 
168     css::uno::Reference<css::security::XCertificate>
169         SAL_CALL chooseCertificate(OUString& rDescription) override;
170     css::uno::Reference<css::security::XCertificate>
171         SAL_CALL chooseSigningCertificate(OUString& rDescription) override;
172     css::uno::Reference<css::security::XCertificate>
173         SAL_CALL selectSigningCertificate(OUString& rDescription) override;
174     css::uno::Reference<css::security::XCertificate>
175         SAL_CALL selectSigningCertificateWithType(const CertificateKind certificateKind,
176                                                   OUString& rDescription) override;
177     css::uno::Sequence<css::uno::Reference<css::security::XCertificate>>
178         SAL_CALL chooseEncryptionCertificate() override;
179     css::uno::Reference<css::security::XCertificate> SAL_CALL chooseCertificateWithProps(
180         css::uno::Sequence<::com::sun::star::beans::PropertyValue>& Properties) override;
181 
182     sal_Bool SAL_CALL signDocumentWithCertificate(
183                             css::uno::Reference<css::security::XCertificate> const & xCertificate,
184                             css::uno::Reference<css::embed::XStorage> const & xStoragexStorage,
185                             css::uno::Reference<css::io::XStream> const & xStream) override;
186 
setParentWindow(const css::uno::Reference<css::awt::XWindow> & rParentwindow)187     void SAL_CALL setParentWindow(const css::uno::Reference<css::awt::XWindow>& rParentwindow) override
188     {
189         mxParentWindow = rParentwindow;
190     }
191 };
192 
DocumentDigitalSignatures(const Reference<XComponentContext> & rxCtx)193 DocumentDigitalSignatures::DocumentDigitalSignatures( const Reference< XComponentContext >& rxCtx ):
194     mxCtx(rxCtx),
195     m_sODFVersion(ODFVER_012_TEXT),
196     m_nArgumentsCount(0),
197     m_bHasDocumentSignature(false)
198 {
199 }
200 
initialize(const Sequence<Any> & aArguments)201 void DocumentDigitalSignatures::initialize( const Sequence< Any >& aArguments)
202 {
203     if (aArguments.getLength() > 2)
204         throw css::lang::IllegalArgumentException(
205           "DocumentDigitalSignatures::initialize requires zero, one, or two arguments",
206           static_cast<XInitialization*>(this), 0);
207 
208     m_nArgumentsCount = aArguments.getLength();
209 
210     if (aArguments.hasElements())
211     {
212         if (!(aArguments[0] >>= m_sODFVersion))
213             throw css::lang::IllegalArgumentException(
214                 "DocumentDigitalSignatures::initialize: the first arguments must be a string",
215                 static_cast<XInitialization*>(this), 0);
216 
217         if (aArguments.getLength() == 2
218             && !(aArguments[1] >>= m_bHasDocumentSignature))
219             throw css::lang::IllegalArgumentException(
220                 "DocumentDigitalSignatures::initialize: the second arguments must be a bool",
221                 static_cast<XInitialization*>(this), 1);
222 
223         //the Version is supported as of ODF1.2, so for and 1.1 document or older we will receive the
224         //an empty string. In this case we set it to ODFVER_010_TEXT. Then we can later check easily
225         //if initialize was called. Only then m_sODFVersion.getLength() is greater than 0
226         if (m_sODFVersion.isEmpty())
227             m_sODFVersion = ODFVER_010_TEXT;
228     }
229 }
230 
getImplementationName()231 OUString DocumentDigitalSignatures::getImplementationName()
232 {
233     return "com.sun.star.security.DocumentDigitalSignatures";
234 }
235 
supportsService(OUString const & ServiceName)236 sal_Bool DocumentDigitalSignatures::supportsService(
237     OUString const & ServiceName)
238 {
239     return cppu::supportsService(this, ServiceName);
240 }
241 
242 css::uno::Sequence<OUString>
getSupportedServiceNames()243 DocumentDigitalSignatures::getSupportedServiceNames()
244 {
245     Sequence<OUString> aRet{ "com.sun.star.security.DocumentDigitalSignatures" };
246     return aRet;
247 }
248 
signDocumentContent(const Reference<css::embed::XStorage> & rxStorage,const Reference<css::io::XStream> & xSignStream)249 sal_Bool DocumentDigitalSignatures::signDocumentContent(
250     const Reference< css::embed::XStorage >& rxStorage,
251     const Reference< css::io::XStream >& xSignStream)
252 {
253     OSL_ENSURE(!m_sODFVersion.isEmpty(), "DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2");
254     return ImplViewSignatures( rxStorage, xSignStream, DocumentSignatureMode::Content, false );
255 }
256 
signSignatureLine(const Reference<css::embed::XStorage> & rxStorage,const Reference<css::io::XStream> & xSignStream,const OUString & aSignatureLineId,const Reference<css::security::XCertificate> & xCertificate,const Reference<css::graphic::XGraphic> & xValidGraphic,const Reference<css::graphic::XGraphic> & xInvalidGraphic,const OUString & aComment)257 sal_Bool DocumentDigitalSignatures::signSignatureLine(
258     const Reference<css::embed::XStorage>& rxStorage,
259     const Reference<css::io::XStream>& xSignStream,
260     const OUString& aSignatureLineId,
261     const Reference<css::security::XCertificate>& xCertificate,
262     const Reference<css::graphic::XGraphic>& xValidGraphic,
263     const Reference<css::graphic::XGraphic>& xInvalidGraphic,
264     const OUString& aComment)
265 {
266     OSL_ENSURE(!m_sODFVersion.isEmpty(),
267                "DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2");
268 
269     DocumentSignatureManager aSignatureManager(mxCtx, DocumentSignatureMode::Content);
270 
271     if (!aSignatureManager.init())
272         return false;
273 
274     aSignatureManager.setStore(rxStorage);
275     aSignatureManager.getSignatureHelper().SetStorage(rxStorage, m_sODFVersion);
276     aSignatureManager.setSignatureStream(xSignStream);
277 
278     Reference<XXMLSecurityContext> xSecurityContext;
279     Reference<XServiceInfo> xServiceInfo(xCertificate, UNO_QUERY);
280     if (xServiceInfo->getImplementationName()
281         == "com.sun.star.xml.security.gpg.XCertificate_GpgImpl")
282         xSecurityContext = aSignatureManager.getGpgSecurityContext();
283     else
284         xSecurityContext = aSignatureManager.getSecurityContext();
285 
286     sal_Int32 nSecurityId;
287     bool bSuccess = aSignatureManager.add(xCertificate, xSecurityContext, aComment, nSecurityId,
288                                           true, aSignatureLineId, xValidGraphic, xInvalidGraphic);
289     if (!bSuccess)
290         return false;
291 
292     // Need to have this to verify the signature
293     aSignatureManager.read(/*bUseTempStream=*/true, /*bCacheLastSignature=*/false);
294     aSignatureManager.write(true);
295 
296     if (rxStorage.is() && !xSignStream.is())
297     {
298         uno::Reference<embed::XTransactedObject> xTrans(rxStorage, uno::UNO_QUERY);
299         xTrans->commit();
300     }
301 
302     return true;
303 }
304 
305 Sequence< css::security::DocumentSignatureInformation >
verifyDocumentContentSignatures(const Reference<css::embed::XStorage> & rxStorage,const Reference<css::io::XInputStream> & xSignInStream)306 DocumentDigitalSignatures::verifyDocumentContentSignatures(
307     const Reference< css::embed::XStorage >& rxStorage,
308     const Reference< css::io::XInputStream >& xSignInStream )
309 {
310     OSL_ENSURE(!m_sODFVersion.isEmpty(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2");
311     return ImplVerifySignatures( rxStorage, xSignInStream, DocumentSignatureMode::Content );
312 }
313 
showDocumentContentSignatures(const Reference<css::embed::XStorage> & rxStorage,const Reference<css::io::XInputStream> & xSignInStream)314 void DocumentDigitalSignatures::showDocumentContentSignatures(
315     const Reference< css::embed::XStorage >& rxStorage,
316     const Reference< css::io::XInputStream >& xSignInStream )
317 {
318     OSL_ENSURE(!m_sODFVersion.isEmpty(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2");
319     ImplViewSignatures( rxStorage, xSignInStream, DocumentSignatureMode::Content, true );
320 }
321 
getDocumentContentSignatureDefaultStreamName()322 OUString DocumentDigitalSignatures::getDocumentContentSignatureDefaultStreamName()
323 {
324     return DocumentSignatureHelper::GetDocumentContentSignatureDefaultStreamName();
325 }
326 
signScriptingContent(const Reference<css::embed::XStorage> & rxStorage,const Reference<css::io::XStream> & xSignStream)327 sal_Bool DocumentDigitalSignatures::signScriptingContent(
328     const Reference< css::embed::XStorage >& rxStorage,
329     const Reference< css::io::XStream >& xSignStream )
330 {
331     OSL_ENSURE(!m_sODFVersion.isEmpty(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2");
332     OSL_ENSURE(m_nArgumentsCount == 2, "DocumentDigitalSignatures: Service was not initialized properly");
333     return ImplViewSignatures( rxStorage, xSignStream, DocumentSignatureMode::Macros, false );
334 }
335 
336 Sequence< css::security::DocumentSignatureInformation >
verifyScriptingContentSignatures(const Reference<css::embed::XStorage> & rxStorage,const Reference<css::io::XInputStream> & xSignInStream)337 DocumentDigitalSignatures::verifyScriptingContentSignatures(
338     const Reference< css::embed::XStorage >& rxStorage,
339     const Reference< css::io::XInputStream >& xSignInStream )
340 {
341     OSL_ENSURE(!m_sODFVersion.isEmpty(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2");
342     return ImplVerifySignatures( rxStorage, xSignInStream, DocumentSignatureMode::Macros );
343 }
344 
showScriptingContentSignatures(const Reference<css::embed::XStorage> & rxStorage,const Reference<css::io::XInputStream> & xSignInStream)345 void DocumentDigitalSignatures::showScriptingContentSignatures(
346     const Reference< css::embed::XStorage >& rxStorage,
347     const Reference< css::io::XInputStream >& xSignInStream )
348 {
349     OSL_ENSURE(!m_sODFVersion.isEmpty(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2");
350     ImplViewSignatures( rxStorage, xSignInStream, DocumentSignatureMode::Macros, true );
351 }
352 
getScriptingContentSignatureDefaultStreamName()353 OUString DocumentDigitalSignatures::getScriptingContentSignatureDefaultStreamName()
354 {
355     return DocumentSignatureHelper::GetScriptingContentSignatureDefaultStreamName();
356 }
357 
358 
signPackage(const Reference<css::embed::XStorage> & rxStorage,const Reference<css::io::XStream> & xSignStream)359 sal_Bool DocumentDigitalSignatures::signPackage(
360     const Reference< css::embed::XStorage >& rxStorage,
361     const Reference< css::io::XStream >& xSignStream  )
362 {
363     OSL_ENSURE(!m_sODFVersion.isEmpty(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2");
364     return ImplViewSignatures( rxStorage, xSignStream, DocumentSignatureMode::Package, false );
365 }
366 
367 Sequence< css::security::DocumentSignatureInformation >
verifyPackageSignatures(const Reference<css::embed::XStorage> & rxStorage,const Reference<css::io::XInputStream> & xSignInStream)368 DocumentDigitalSignatures::verifyPackageSignatures(
369     const Reference< css::embed::XStorage >& rxStorage,
370     const Reference< css::io::XInputStream >& xSignInStream )
371 {
372     OSL_ENSURE(!m_sODFVersion.isEmpty(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2");
373     return ImplVerifySignatures( rxStorage, xSignInStream, DocumentSignatureMode::Package );
374 }
375 
showPackageSignatures(const Reference<css::embed::XStorage> & rxStorage,const Reference<css::io::XInputStream> & xSignInStream)376 void DocumentDigitalSignatures::showPackageSignatures(
377     const Reference< css::embed::XStorage >& rxStorage,
378     const Reference< css::io::XInputStream >& xSignInStream )
379 {
380     OSL_ENSURE(!m_sODFVersion.isEmpty(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2");
381     ImplViewSignatures( rxStorage, xSignInStream, DocumentSignatureMode::Package, true );
382 }
383 
getPackageSignatureDefaultStreamName()384 OUString DocumentDigitalSignatures::getPackageSignatureDefaultStreamName(  )
385 {
386     return DocumentSignatureHelper::GetPackageSignatureDefaultStreamName();
387 }
388 
389 
ImplViewSignatures(const Reference<css::embed::XStorage> & rxStorage,const Reference<css::io::XInputStream> & xSignStream,DocumentSignatureMode eMode,bool bReadOnly)390 void DocumentDigitalSignatures::ImplViewSignatures(
391     const Reference< css::embed::XStorage >& rxStorage,
392     const Reference< css::io::XInputStream >& xSignStream,
393     DocumentSignatureMode eMode, bool bReadOnly )
394 {
395     Reference< io::XStream > xStream;
396     if ( xSignStream.is() )
397         xStream.set( xSignStream, UNO_QUERY );
398     ImplViewSignatures( rxStorage, xStream, eMode, bReadOnly );
399 }
400 
ImplViewSignatures(const Reference<css::embed::XStorage> & rxStorage,const Reference<css::io::XStream> & xSignStream,DocumentSignatureMode eMode,bool bReadOnly)401 bool DocumentDigitalSignatures::ImplViewSignatures(
402     const Reference< css::embed::XStorage >& rxStorage, const Reference< css::io::XStream >& xSignStream,
403     DocumentSignatureMode eMode, bool bReadOnly )
404 {
405     bool bChanges = false;
406     DigitalSignaturesDialog aSignaturesDialog(
407         Application::GetFrameWeld(mxParentWindow), mxCtx, eMode, bReadOnly, m_sODFVersion,
408         m_bHasDocumentSignature);
409     bool bInit = aSignaturesDialog.Init();
410     SAL_WARN_IF( !bInit, "xmlsecurity.comp", "Error initializing security context!" );
411     if ( bInit )
412     {
413         aSignaturesDialog.SetStorage(rxStorage);
414 
415         aSignaturesDialog.SetSignatureStream( xSignStream );
416         if (aSignaturesDialog.run() == RET_OK)
417         {
418             if (aSignaturesDialog.SignaturesChanged())
419             {
420                 bChanges = true;
421                 // If we have a storage and no stream, we are responsible for commit
422                 if ( rxStorage.is() && !xSignStream.is() )
423                 {
424                     uno::Reference< embed::XTransactedObject > xTrans( rxStorage, uno::UNO_QUERY );
425                     xTrans->commit();
426                 }
427             }
428         }
429     }
430     else
431     {
432         std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(Application::GetFrameWeld(mxParentWindow),
433                                                   VclMessageType::Warning, VclButtonsType::Ok,
434                                                   XsResId(RID_XMLSECWB_NO_MOZILLA_PROFILE)));
435         xBox->run();
436     }
437 
438     return bChanges;
439 }
440 
441 Sequence< css::security::DocumentSignatureInformation >
ImplVerifySignatures(const Reference<css::embed::XStorage> & rxStorage,const Reference<css::io::XInputStream> & xSignStream,DocumentSignatureMode eMode)442 DocumentDigitalSignatures::ImplVerifySignatures(
443     const Reference< css::embed::XStorage >& rxStorage,
444     const Reference< css::io::XInputStream >& xSignStream, DocumentSignatureMode eMode )
445 {
446     DocumentSignatureManager aSignatureManager(mxCtx, eMode);
447 
448     bool bInit = aSignatureManager.init();
449 
450     SAL_WARN_IF(!bInit, "xmlsecurity.comp", "Error initializing security context!");
451 
452     if (!bInit)
453         return uno::Sequence<security::DocumentSignatureInformation>(0);
454 
455     if (!rxStorage.is())
456     {
457         if (xSignStream.is())
458         {
459             // Something not ZIP-based, try PDF.
460             PDFSignatureHelper& rSignatureHelper = aSignatureManager.getPDFSignatureHelper();
461             if (rSignatureHelper.ReadAndVerifySignature(xSignStream))
462                 return rSignatureHelper.GetDocumentSignatureInformations(aSignatureManager.getSecurityEnvironment());
463         }
464 
465         SAL_WARN( "xmlsecurity.comp", "Error, no XStorage provided");
466         return Sequence<css::security::DocumentSignatureInformation>();
467     }
468     // First check for the InputStream, to avoid unnecessary initialization of the security environment...
469     SignatureStreamHelper aStreamHelper;
470     Reference< io::XInputStream > xInputStream = xSignStream;
471 
472     if ( !xInputStream.is() )
473     {
474         aStreamHelper = DocumentSignatureHelper::OpenSignatureStream( rxStorage, embed::ElementModes::READ, eMode );
475         if ( aStreamHelper.xSignatureStream.is() )
476             xInputStream.set( aStreamHelper.xSignatureStream, UNO_QUERY );
477     }
478 
479     if (!xInputStream.is() && aStreamHelper.nStorageFormat != embed::StorageFormats::OFOPXML)
480         return Sequence< css::security::DocumentSignatureInformation >(0);
481 
482 
483     XMLSignatureHelper& rSignatureHelper = aSignatureManager.getSignatureHelper();
484     rSignatureHelper.SetStorage(rxStorage, m_sODFVersion);
485 
486     rSignatureHelper.StartMission(aSignatureManager.getSecurityContext());
487 
488     if (xInputStream.is())
489         rSignatureHelper.ReadAndVerifySignature(xInputStream);
490     else if (aStreamHelper.nStorageFormat == embed::StorageFormats::OFOPXML)
491         rSignatureHelper.ReadAndVerifySignatureStorage(aStreamHelper.xSignatureStorage);
492 
493     rSignatureHelper.EndMission();
494 
495     uno::Reference<xml::crypto::XSecurityEnvironment> xSecEnv = aSignatureManager.getSecurityEnvironment();
496     uno::Reference<xml::crypto::XSecurityEnvironment> xGpgSecEnv = aSignatureManager.getGpgSecurityEnvironment();
497 
498     SignatureInformations aSignInfos = rSignatureHelper.GetSignatureInformations();
499     int nInfos = aSignInfos.size();
500     Sequence< css::security::DocumentSignatureInformation > aInfos(nInfos);
501     css::security::DocumentSignatureInformation* arInfos = aInfos.getArray();
502 
503     if ( nInfos )
504     {
505         for( int n = 0; n < nInfos; ++n )
506         {
507             DocumentSignatureAlgorithm mode = DocumentSignatureHelper::getDocumentAlgorithm(
508                 m_sODFVersion, aSignInfos[n]);
509             const std::vector< OUString > aElementsToBeVerified =
510                 DocumentSignatureHelper::CreateElementList(
511                 rxStorage, eMode, mode);
512 
513             const SignatureInformation& rInfo = aSignInfos[n];
514             css::security::DocumentSignatureInformation& rSigInfo = arInfos[n];
515 
516             if (rInfo.ouGpgCertificate.isEmpty()) // X.509
517             {
518                 if (!rInfo.ouX509Certificate.isEmpty())
519                     rSigInfo.Signer = xSecEnv->createCertificateFromAscii( rInfo.ouX509Certificate ) ;
520                 if (!rSigInfo.Signer.is())
521                     rSigInfo.Signer = xSecEnv->getCertificate( rInfo.ouX509IssuerName,
522                                                                xmlsecurity::numericStringToBigInteger( rInfo.ouX509SerialNumber ) );
523 
524                 // On Windows checking the certificate path is buggy. It does name matching (issuer, subject name)
525                 // to find the parent certificate. It does not take into account that there can be several certificates
526                 // with the same subject name.
527 
528                 try {
529                     rSigInfo.CertificateStatus = xSecEnv->verifyCertificate(rSigInfo.Signer,
530                                                                             Sequence<Reference<css::security::XCertificate> >());
531                 } catch (SecurityException& ) {
532                     OSL_FAIL("Verification of certificate failed");
533                     rSigInfo.CertificateStatus = css::security::CertificateValidity::INVALID;
534                 }
535             }
536             else if (xGpgSecEnv.is()) // GPG
537             {
538                 // TODO not ideal to retrieve cert by keyID, might
539                 // collide, or PGPKeyID format might change - can't we
540                 // keep the xCert itself in rInfo?
541                 rSigInfo.Signer = xGpgSecEnv->getCertificate( rInfo.ouGpgKeyID, xmlsecurity::numericStringToBigInteger("") );
542                 rSigInfo.CertificateStatus = xGpgSecEnv->verifyCertificate(rSigInfo.Signer,
543                                                                            Sequence<Reference<css::security::XCertificate> >());
544             }
545 
546             // Time support again (#i38744#)
547             Date aDate( rInfo.stDateTime.Day, rInfo.stDateTime.Month, rInfo.stDateTime.Year );
548             tools::Time aTime( rInfo.stDateTime.Hours, rInfo.stDateTime.Minutes,
549                         rInfo.stDateTime.Seconds, rInfo.stDateTime.NanoSeconds );
550             rSigInfo.SignatureDate = aDate.GetDate();
551             rSigInfo.SignatureTime = aTime.GetTime() / tools::Time::nanoPerCenti;
552 
553             rSigInfo.SignatureIsValid = ( rInfo.nStatus == css::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED );
554 
555             // Signature line info (ID + Images)
556             if (!rInfo.ouSignatureLineId.isEmpty())
557                 rSigInfo.SignatureLineId = rInfo.ouSignatureLineId;
558 
559             if (rInfo.aValidSignatureImage.is())
560                 rSigInfo.ValidSignatureLineImage = rInfo.aValidSignatureImage;
561 
562             if (rInfo.aInvalidSignatureImage.is())
563                 rSigInfo.InvalidSignatureLineImage = rInfo.aInvalidSignatureImage;
564 
565             // OOXML intentionally doesn't sign metadata.
566             if ( rSigInfo.SignatureIsValid && aStreamHelper.nStorageFormat != embed::StorageFormats::OFOPXML)
567             {
568                  rSigInfo.SignatureIsValid =
569                       DocumentSignatureHelper::checkIfAllFilesAreSigned(
570                       aElementsToBeVerified, rInfo, mode);
571             }
572             if (eMode == DocumentSignatureMode::Content)
573             {
574                 if (aStreamHelper.nStorageFormat == embed::StorageFormats::OFOPXML)
575                     rSigInfo.PartialDocumentSignature = true;
576                 else
577                     rSigInfo.PartialDocumentSignature = !DocumentSignatureHelper::isOOo3_2_Signature(aSignInfos[n]);
578             }
579 
580         }
581     }
582     return aInfos;
583 
584 }
585 
manageTrustedSources()586 void DocumentDigitalSignatures::manageTrustedSources(  )
587 {
588     // MT: i45295
589     // SecEnv is only needed to display certificate information from trusted sources.
590     // Macro Security also has some options where no security environment is needed, so raise dialog anyway.
591     // Later I should change the code so the Dialog creates the SecEnv on demand...
592 
593     Reference< css::xml::crypto::XSecurityEnvironment > xSecEnv;
594 
595     DocumentSignatureManager aSignatureManager(mxCtx, {});
596     if (aSignatureManager.init())
597         xSecEnv = aSignatureManager.getSecurityEnvironment();
598 
599     MacroSecurity aDlg(Application::GetFrameWeld(mxParentWindow), xSecEnv);
600     aDlg.run();
601 }
602 
showCertificate(const Reference<css::security::XCertificate> & Certificate)603 void DocumentDigitalSignatures::showCertificate(
604     const Reference< css::security::XCertificate >& Certificate )
605 {
606     DocumentSignatureManager aSignatureManager(mxCtx, {});
607 
608     bool bInit = aSignatureManager.init();
609 
610     SAL_WARN_IF( !bInit, "xmlsecurity.comp", "Error initializing security context!" );
611 
612     if ( bInit )
613     {
614         CertificateViewer aViewer(Application::GetFrameWeld(mxParentWindow), aSignatureManager.getSecurityEnvironment(), Certificate, false, nullptr);
615         aViewer.run();
616     }
617 }
618 
isAuthorTrusted(const Reference<css::security::XCertificate> & Author)619 sal_Bool DocumentDigitalSignatures::isAuthorTrusted(
620     const Reference< css::security::XCertificate >& Author )
621 {
622     OUString sSerialNum = xmlsecurity::bigIntegerToNumericString( Author->getSerialNumber() );
623 
624     Sequence< SvtSecurityOptions::Certificate > aTrustedAuthors = SvtSecurityOptions().GetTrustedAuthors();
625 
626     return std::any_of(aTrustedAuthors.begin(), aTrustedAuthors.end(),
627         [&Author, &sSerialNum](const SvtSecurityOptions::Certificate& rAuthor) {
628             return ( rAuthor[0] == Author->getIssuerName() )
629                 && ( rAuthor[1] == sSerialNum );
630         });
631 }
632 
633 uno::Sequence<Reference<css::security::XCertificate>>
chooseCertificatesImpl(std::map<OUString,OUString> & rProperties,const UserAction eAction,const CertificateKind certificateKind)634 DocumentDigitalSignatures::chooseCertificatesImpl(std::map<OUString, OUString>& rProperties,
635                                                   const UserAction eAction,
636                                                   const CertificateKind certificateKind)
637 {
638     std::vector< Reference< css::xml::crypto::XXMLSecurityContext > > xSecContexts;
639 
640     DocumentSignatureManager aSignatureManager(mxCtx, {});
641     if (aSignatureManager.init()) {
642         xSecContexts.push_back(aSignatureManager.getSecurityContext());
643         // Don't include OpenPGP if only X.509 certs are requested
644         if (certificateKind == CertificateKind_NONE || certificateKind == CertificateKind_OPENPGP)
645             xSecContexts.push_back(aSignatureManager.getGpgSecurityContext());
646     }
647 
648     CertificateChooser aChooser(Application::GetFrameWeld(mxParentWindow), xSecContexts, eAction);
649 
650     uno::Sequence< Reference< css::security::XCertificate > > xCerts(1);
651     xCerts[0] = Reference< css::security::XCertificate >(nullptr);
652 
653     if (aChooser.run() != RET_OK)
654         return xCerts;
655 
656     xCerts = aChooser.GetSelectedCertificates();
657     rProperties["Description"] = aChooser.GetDescription();
658     rProperties["Usage"] = aChooser.GetUsageText();
659 
660     return xCerts;
661 }
662 
chooseCertificate(OUString & rDescription)663 Reference< css::security::XCertificate > DocumentDigitalSignatures::chooseCertificate(OUString& rDescription)
664 {
665     return chooseSigningCertificate( rDescription );
666 }
667 
chooseSigningCertificate(OUString & rDescription)668 Reference< css::security::XCertificate > DocumentDigitalSignatures::chooseSigningCertificate(OUString& rDescription)
669 {
670     std::map<OUString, OUString> aProperties;
671     Reference< css::security::XCertificate > xCert = chooseCertificatesImpl( aProperties, UserAction::Sign )[0];
672     rDescription = aProperties["Description"];
673     return xCert;
674 }
675 
selectSigningCertificate(OUString & rDescription)676 Reference< css::security::XCertificate > DocumentDigitalSignatures::selectSigningCertificate(OUString& rDescription)
677 {
678     std::map<OUString, OUString> aProperties;
679     Reference< css::security::XCertificate > xCert = chooseCertificatesImpl( aProperties, UserAction::SelectSign )[0];
680     rDescription = aProperties["Description"];
681     return xCert;
682 }
683 
684 Reference<css::security::XCertificate>
selectSigningCertificateWithType(const CertificateKind certificateKind,OUString & rDescription)685 DocumentDigitalSignatures::selectSigningCertificateWithType(const CertificateKind certificateKind,
686                                                             OUString& rDescription)
687 {
688     std::map<OUString, OUString> aProperties;
689     Reference<css::security::XCertificate> xCert
690         = chooseCertificatesImpl(aProperties, UserAction::SelectSign, certificateKind)[0];
691     rDescription = aProperties["Description"];
692     return xCert;
693 }
694 
chooseEncryptionCertificate()695 css::uno::Sequence< Reference< css::security::XCertificate > > DocumentDigitalSignatures::chooseEncryptionCertificate()
696 {
697     std::map<OUString, OUString> aProperties;
698     uno::Sequence< Reference< css::security::XCertificate > > aCerts=
699         chooseCertificatesImpl( aProperties, UserAction::Encrypt );
700     if (aCerts.getLength() == 1 && !aCerts[0].is())
701         // our error case contract is: empty sequence, so map that!
702         return uno::Sequence< Reference< css::security::XCertificate > >();
703     else
704         return aCerts;
705 }
706 
chooseCertificateWithProps(Sequence<::com::sun::star::beans::PropertyValue> & rProperties)707 css::uno::Reference< css::security::XCertificate > DocumentDigitalSignatures::chooseCertificateWithProps(Sequence<::com::sun::star::beans::PropertyValue>& rProperties)
708 {
709     std::map<OUString, OUString> aProperties;
710     auto xCert = chooseCertificatesImpl( aProperties, UserAction::Sign )[0];
711 
712     std::vector<css::beans::PropertyValue> vec;
713     vec.reserve(aProperties.size());
714     for (const auto& pair : aProperties)
715     {
716         vec.emplace_back(comphelper::makePropertyValue(pair.first, pair.second));
717     }
718 
719     rProperties = comphelper::containerToSequence(vec);
720     return xCert;
721 }
722 
isLocationTrusted(const OUString & Location)723 sal_Bool DocumentDigitalSignatures::isLocationTrusted( const OUString& Location )
724 {
725     return SvtSecurityOptions().isTrustedLocationUri(Location);
726 }
727 
addAuthorToTrustedSources(const Reference<css::security::XCertificate> & Author)728 void DocumentDigitalSignatures::addAuthorToTrustedSources(
729     const Reference< css::security::XCertificate >& Author )
730 {
731     SvtSecurityOptions aSecOpts;
732 
733     SvtSecurityOptions::Certificate aNewCert( 3 );
734     aNewCert[ 0 ] = Author->getIssuerName();
735     aNewCert[ 1 ] = xmlsecurity::bigIntegerToNumericString( Author->getSerialNumber() );
736 
737     OUStringBuffer aStrBuffer;
738     ::comphelper::Base64::encode(aStrBuffer, Author->getEncoded());
739     aNewCert[ 2 ] = aStrBuffer.makeStringAndClear();
740 
741 
742     Sequence< SvtSecurityOptions::Certificate > aTrustedAuthors = aSecOpts.GetTrustedAuthors();
743     sal_Int32 nCnt = aTrustedAuthors.getLength();
744     aTrustedAuthors.realloc( nCnt + 1 );
745     aTrustedAuthors[ nCnt ] = aNewCert;
746 
747     aSecOpts.SetTrustedAuthors( aTrustedAuthors );
748 }
749 
addLocationToTrustedSources(const OUString & Location)750 void DocumentDigitalSignatures::addLocationToTrustedSources( const OUString& Location )
751 {
752     SvtSecurityOptions aSecOpt;
753 
754     Sequence< OUString > aSecURLs = aSecOpt.GetSecureURLs();
755     sal_Int32 nCnt = aSecURLs.getLength();
756     aSecURLs.realloc( nCnt + 1 );
757     aSecURLs[ nCnt ] = Location;
758 
759     aSecOpt.SetSecureURLs( aSecURLs );
760 }
761 
signDocumentWithCertificate(css::uno::Reference<css::security::XCertificate> const & xCertificate,css::uno::Reference<css::embed::XStorage> const & xStorage,css::uno::Reference<css::io::XStream> const & xStream)762 sal_Bool DocumentDigitalSignatures::signDocumentWithCertificate(
763             css::uno::Reference<css::security::XCertificate> const & xCertificate,
764             css::uno::Reference<css::embed::XStorage> const & xStorage,
765             css::uno::Reference<css::io::XStream> const & xStream)
766 {
767     DocumentSignatureManager aSignatureManager(mxCtx, DocumentSignatureMode::Content);
768 
769     if (!aSignatureManager.init())
770         return false;
771 
772     aSignatureManager.setStore(xStorage);
773     aSignatureManager.getSignatureHelper().SetStorage(xStorage, m_sODFVersion);
774     aSignatureManager.setSignatureStream(xStream);
775 
776     Reference<XXMLSecurityContext> xSecurityContext;
777     Reference<XServiceInfo> xServiceInfo(xCertificate, UNO_QUERY);
778     xSecurityContext = aSignatureManager.getSecurityContext();
779 
780     sal_Int32 nSecurityId;
781 
782     bool bSuccess = aSignatureManager.add(xCertificate, xSecurityContext, "", nSecurityId, true);
783     if (!bSuccess)
784         return false;
785 
786     aSignatureManager.read(/*bUseTempStream=*/true, /*bCacheLastSignature=*/false);
787     aSignatureManager.write(true);
788 
789     if (xStorage.is() && !xStream.is())
790     {
791         uno::Reference<embed::XTransactedObject> xTransaction(xStorage, uno::UNO_QUERY);
792         xTransaction->commit();
793     }
794 
795     return true;
796 }
797 
798 extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
com_sun_star_security_DocumentDigitalSignatures_get_implementation(uno::XComponentContext * pCtx,uno::Sequence<uno::Any> const &)799 com_sun_star_security_DocumentDigitalSignatures_get_implementation(
800     uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/)
801 {
802     return cppu::acquire(
803         new DocumentDigitalSignatures(uno::Reference<uno::XComponentContext>(pCtx)));
804 }
805 
806 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
807