1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "documentdigitalsignatures.hxx"
21 #include <xmlsecurity/digitalsignaturesdialog.hxx>
22 #include <xmlsecurity/certificatechooser.hxx>
23 #include <xmlsecurity/certificateviewer.hxx>
24 #include <xmlsecurity/macrosecurity.hxx>
25 #include <xmlsecurity/biginteger.hxx>
26 #include <xmlsecurity/global.hrc>
28 #include <sax/tools/converter.hxx>
30 #include <../dialogs/resourcemanager.hxx>
31 #include <com/sun/star/embed/XStorage.hpp>
32 #include <com/sun/star/embed/XTransactedObject.hpp>
33 #include <com/sun/star/embed/ElementModes.hpp>
34 #include <com/sun/star/ucb/XContent.hpp>
35 #include <com/sun/star/ucb/XContentIdentifierFactory.hpp>
36 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
37 #include <com/sun/star/ucb/XCommandProcessor.hpp>
38 #include <com/sun/star/ucb/Command.hpp>
39 #include <vcl/layout.hxx>
40 #include <unotools/securityoptions.hxx>
41 #include <com/sun/star/security/CertificateValidity.hpp>
42 #include <com/sun/star/security/SerialNumberAdapter.hpp>
43 #include <comphelper/documentconstants.hxx>
44 #include <cppuhelper/supportsservice.hxx>
45 #include <com/sun/star/lang/IllegalArgumentException.hpp>
51 using namespace css::uno
;
53 DocumentDigitalSignatures::DocumentDigitalSignatures( const Reference
< XComponentContext
>& rxCtx
):
55 m_sODFVersion(ODFVER_012_TEXT
),
57 m_bHasDocumentSignature(false)
61 void DocumentDigitalSignatures::initialize( const Sequence
< Any
>& aArguments
)
62 throw (css::uno::Exception
, css::uno::RuntimeException
, std::exception
)
64 if (aArguments
.getLength() > 2)
65 throw css::lang::IllegalArgumentException(
66 "DocumentDigitalSignatures::initialize requires zero, one, or two arguments",
67 static_cast<XInitialization
*>(this), 0);
69 m_nArgumentsCount
= aArguments
.getLength();
71 if (aArguments
.getLength() > 0)
73 if (!(aArguments
[0] >>= m_sODFVersion
))
74 throw css::lang::IllegalArgumentException(
75 "DocumentDigitalSignatures::initialize: the first arguments must be a string",
76 static_cast<XInitialization
*>(this), 0);
78 if (aArguments
.getLength() == 2
79 && !(aArguments
[1] >>= m_bHasDocumentSignature
))
80 throw css::lang::IllegalArgumentException(
81 "DocumentDigitalSignatures::initialize: the second arguments must be a bool",
82 static_cast<XInitialization
*>(this), 1);
84 //the Version is supported as of ODF1.2, so for and 1.1 document or older we will receive the
85 //an empty string. In this case we set it to ODFVER_010_TEXT. Then we can later check easily
86 //if initialize was called. Only then m_sODFVersion.getLength() is greater than 0
87 if (m_sODFVersion
.isEmpty())
88 m_sODFVersion
= ODFVER_010_TEXT
;
92 OUString
DocumentDigitalSignatures::getImplementationName()
93 throw (css::uno::RuntimeException
, std::exception
)
95 return GetImplementationName();
98 sal_Bool
DocumentDigitalSignatures::supportsService(
99 OUString
const & ServiceName
)
100 throw (css::uno::RuntimeException
, std::exception
)
102 return cppu::supportsService(this, ServiceName
);
105 css::uno::Sequence
<OUString
>
106 DocumentDigitalSignatures::getSupportedServiceNames()
107 throw (css::uno::RuntimeException
, std::exception
)
109 return GetSupportedServiceNames();
112 sal_Bool
DocumentDigitalSignatures::signDocumentContent(
113 const Reference
< css::embed::XStorage
>& rxStorage
,
114 const Reference
< css::io::XStream
>& xSignStream
)
115 throw (RuntimeException
, std::exception
)
117 OSL_ENSURE(!m_sODFVersion
.isEmpty(), "DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2");
118 return ImplViewSignatures( rxStorage
, xSignStream
, SignatureModeDocumentContent
, false );
121 Sequence
< css::security::DocumentSignatureInformation
>
122 DocumentDigitalSignatures::verifyDocumentContentSignatures(
123 const Reference
< css::embed::XStorage
>& rxStorage
,
124 const Reference
< css::io::XInputStream
>& xSignInStream
) throw (RuntimeException
, std::exception
)
126 OSL_ENSURE(!m_sODFVersion
.isEmpty(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2");
127 return ImplVerifySignatures( rxStorage
, xSignInStream
, SignatureModeDocumentContent
);
130 void DocumentDigitalSignatures::showDocumentContentSignatures(
131 const Reference
< css::embed::XStorage
>& rxStorage
,
132 const Reference
< css::io::XInputStream
>& xSignInStream
) throw (RuntimeException
, std::exception
)
134 OSL_ENSURE(!m_sODFVersion
.isEmpty(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2");
135 ImplViewSignatures( rxStorage
, xSignInStream
, SignatureModeDocumentContent
, true );
138 OUString
DocumentDigitalSignatures::getDocumentContentSignatureDefaultStreamName()
139 throw (css::uno::RuntimeException
, std::exception
)
141 return DocumentSignatureHelper::GetDocumentContentSignatureDefaultStreamName();
144 sal_Bool
DocumentDigitalSignatures::signScriptingContent(
145 const Reference
< css::embed::XStorage
>& rxStorage
,
146 const Reference
< css::io::XStream
>& xSignStream
) throw (RuntimeException
, std::exception
)
148 OSL_ENSURE(!m_sODFVersion
.isEmpty(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2");
149 OSL_ENSURE(m_nArgumentsCount
== 2, "DocumentDigitalSignatures: Service was not initialized properly");
150 return ImplViewSignatures( rxStorage
, xSignStream
, SignatureModeMacros
, false );
153 Sequence
< css::security::DocumentSignatureInformation
>
154 DocumentDigitalSignatures::verifyScriptingContentSignatures(
155 const Reference
< css::embed::XStorage
>& rxStorage
,
156 const Reference
< css::io::XInputStream
>& xSignInStream
) throw (RuntimeException
, std::exception
)
158 OSL_ENSURE(!m_sODFVersion
.isEmpty(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2");
159 return ImplVerifySignatures( rxStorage
, xSignInStream
, SignatureModeMacros
);
162 void DocumentDigitalSignatures::showScriptingContentSignatures(
163 const Reference
< css::embed::XStorage
>& rxStorage
,
164 const Reference
< css::io::XInputStream
>& xSignInStream
) throw (RuntimeException
, std::exception
)
166 OSL_ENSURE(!m_sODFVersion
.isEmpty(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2");
167 ImplViewSignatures( rxStorage
, xSignInStream
, SignatureModeMacros
, true );
170 OUString
DocumentDigitalSignatures::getScriptingContentSignatureDefaultStreamName()
171 throw (css::uno::RuntimeException
, std::exception
)
173 return DocumentSignatureHelper::GetScriptingContentSignatureDefaultStreamName();
177 sal_Bool
DocumentDigitalSignatures::signPackage(
178 const Reference
< css::embed::XStorage
>& rxStorage
,
179 const Reference
< css::io::XStream
>& xSignStream
) throw (RuntimeException
, std::exception
)
181 OSL_ENSURE(!m_sODFVersion
.isEmpty(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2");
182 return ImplViewSignatures( rxStorage
, xSignStream
, SignatureModePackage
, false );
185 Sequence
< css::security::DocumentSignatureInformation
>
186 DocumentDigitalSignatures::verifyPackageSignatures(
187 const Reference
< css::embed::XStorage
>& rxStorage
,
188 const Reference
< css::io::XInputStream
>& xSignInStream
) throw (RuntimeException
, std::exception
)
190 OSL_ENSURE(!m_sODFVersion
.isEmpty(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2");
191 return ImplVerifySignatures( rxStorage
, xSignInStream
, SignatureModePackage
);
194 void DocumentDigitalSignatures::showPackageSignatures(
195 const Reference
< css::embed::XStorage
>& rxStorage
,
196 const Reference
< css::io::XInputStream
>& xSignInStream
) throw (RuntimeException
, std::exception
)
198 OSL_ENSURE(!m_sODFVersion
.isEmpty(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2");
199 ImplViewSignatures( rxStorage
, xSignInStream
, SignatureModePackage
, true );
202 OUString
DocumentDigitalSignatures::getPackageSignatureDefaultStreamName( )
203 throw (::com::sun::star::uno::RuntimeException
, std::exception
)
205 return DocumentSignatureHelper::GetPackageSignatureDefaultStreamName();
209 bool DocumentDigitalSignatures::ImplViewSignatures(
210 const Reference
< css::embed::XStorage
>& rxStorage
,
211 const Reference
< css::io::XInputStream
>& xSignStream
,
212 DocumentSignatureMode eMode
, bool bReadOnly
) throw (RuntimeException
, std::exception
)
214 Reference
< io::XStream
> xStream
;
215 if ( xSignStream
.is() )
216 xStream
= Reference
< io::XStream
>( xSignStream
, UNO_QUERY
);
217 return ImplViewSignatures( rxStorage
, xStream
, eMode
, bReadOnly
);
220 bool DocumentDigitalSignatures::ImplViewSignatures(
221 const Reference
< css::embed::XStorage
>& rxStorage
, const Reference
< css::io::XStream
>& xSignStream
,
222 DocumentSignatureMode eMode
, bool bReadOnly
) throw (RuntimeException
, std::exception
)
224 bool bChanges
= false;
225 ScopedVclPtrInstance
<DigitalSignaturesDialog
> aSignaturesDialog(
226 nullptr, mxCtx
, eMode
, bReadOnly
, m_sODFVersion
,
227 m_bHasDocumentSignature
);
228 bool bInit
= aSignaturesDialog
->Init();
229 DBG_ASSERT( bInit
, "Error initializing security context!" );
232 aSignaturesDialog
->SetStorage( rxStorage
);
233 aSignaturesDialog
->SetSignatureStream( xSignStream
);
234 if ( aSignaturesDialog
->Execute() )
236 if ( aSignaturesDialog
->SignaturesChanged() )
239 // If we have a storage and no stream, we are responsible for commit
240 if ( rxStorage
.is() && !xSignStream
.is() )
242 uno::Reference
< embed::XTransactedObject
> xTrans( rxStorage
, uno::UNO_QUERY
);
250 ScopedVclPtrInstance
< MessageDialog
> aBox(nullptr, XMLSEC_RES(RID_XMLSECWB_NO_MOZILLA_PROFILE
), VCL_MESSAGE_WARNING
);
257 Sequence
< css::security::DocumentSignatureInformation
>
258 DocumentDigitalSignatures::ImplVerifySignatures(
259 const Reference
< css::embed::XStorage
>& rxStorage
,
260 const Reference
< css::io::XInputStream
>& xSignStream
, DocumentSignatureMode eMode
) throw (RuntimeException
)
264 DBG_ASSERT(false, "Error, no XStorage provided");
265 return Sequence
<css::security::DocumentSignatureInformation
>();
267 // First check for the InputStream, to avoid unnecessary initialization of the security environemnt...
268 SignatureStreamHelper aStreamHelper
;
269 Reference
< io::XInputStream
> xInputStream
= xSignStream
;
271 if ( !xInputStream
.is() )
273 aStreamHelper
= DocumentSignatureHelper::OpenSignatureStream( rxStorage
, embed::ElementModes::READ
, eMode
);
274 if ( aStreamHelper
.xSignatureStream
.is() )
275 xInputStream
= Reference
< io::XInputStream
>( aStreamHelper
.xSignatureStream
, UNO_QUERY
);
278 if ( !xInputStream
.is() )
279 return Sequence
< ::com::sun::star::security::DocumentSignatureInformation
>(0);
282 XMLSignatureHelper
aSignatureHelper( mxCtx
);
284 bool bInit
= aSignatureHelper
.Init();
286 DBG_ASSERT( bInit
, "Error initializing security context!" );
289 return Sequence
< ::com::sun::star::security::DocumentSignatureInformation
>(0);
291 aSignatureHelper
.SetStorage(rxStorage
, m_sODFVersion
);
293 aSignatureHelper
.StartMission();
295 aSignatureHelper
.ReadAndVerifySignature( xInputStream
);
297 aSignatureHelper
.EndMission();
299 Reference
< ::com::sun::star::xml::crypto::XSecurityEnvironment
> xSecEnv
= aSignatureHelper
.GetSecurityEnvironment();
301 SignatureInformations aSignInfos
= aSignatureHelper
.GetSignatureInformations();
302 int nInfos
= aSignInfos
.size();
303 Sequence
< css::security::DocumentSignatureInformation
> aInfos(nInfos
);
304 css::security::DocumentSignatureInformation
* arInfos
= aInfos
.getArray();
308 Reference
<security::XSerialNumberAdapter
> xSerialNumberAdapter
=
309 ::com::sun::star::security::SerialNumberAdapter::create(mxCtx
);
311 for( int n
= 0; n
< nInfos
; ++n
)
313 DocumentSignatureAlgorithm mode
= DocumentSignatureHelper::getDocumentAlgorithm(
314 m_sODFVersion
, aSignInfos
[n
]);
315 const std::vector
< OUString
> aElementsToBeVerified
=
316 DocumentSignatureHelper::CreateElementList(
317 rxStorage
, eMode
, mode
);
319 const SignatureInformation
& rInfo
= aSignInfos
[n
];
320 css::security::DocumentSignatureInformation
& rSigInfo
= arInfos
[n
];
322 if (!rInfo
.ouX509Certificate
.isEmpty())
323 rSigInfo
.Signer
= xSecEnv
->createCertificateFromAscii( rInfo
.ouX509Certificate
) ;
324 if (!rSigInfo
.Signer
.is())
325 rSigInfo
.Signer
= xSecEnv
->getCertificate( rInfo
.ouX509IssuerName
, xSerialNumberAdapter
->toSequence( rInfo
.ouX509SerialNumber
) );
327 // Time support again (#i38744#)
328 Date
aDate( rInfo
.stDateTime
.Day
, rInfo
.stDateTime
.Month
, rInfo
.stDateTime
.Year
);
329 tools::Time
aTime( rInfo
.stDateTime
.Hours
, rInfo
.stDateTime
.Minutes
,
330 rInfo
.stDateTime
.Seconds
, rInfo
.stDateTime
.NanoSeconds
);
331 rSigInfo
.SignatureDate
= aDate
.GetDate();
332 rSigInfo
.SignatureTime
= aTime
.GetTime();
334 // Verify certificate
335 //We have patched our version of libxmlsec, so that it does not verify the certificates. This has two
336 //reasons. First we want two separate status for signature and certificate. Second libxmlsec calls
337 //CERT_VerifyCertificate (Solaris, Linux) falsely, so that it always regards the certificate as valid.
338 //On Windows the checking of the certificate path is buggy. It does name matching (issuer, subject name)
339 //to find the parent certificate. It does not take into account that there can be several certificates
340 //with the same subject name.
341 if (rSigInfo
.Signer
.is())
344 rSigInfo
.CertificateStatus
= xSecEnv
->verifyCertificate(rSigInfo
.Signer
,
345 Sequence
<Reference
<css::security::XCertificate
> >());
346 } catch (SecurityException
& ) {
347 OSL_FAIL("Verification of certificate failed");
348 rSigInfo
.CertificateStatus
= css::security::CertificateValidity::INVALID
;
353 //We should always be able to get the certificates because it is contained in the document,
354 //unless the document is damaged so that signature xml file could not be parsed.
355 rSigInfo
.CertificateStatus
= css::security::CertificateValidity::INVALID
;
358 rSigInfo
.SignatureIsValid
= ( rInfo
.nStatus
== ::com::sun::star::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED
);
361 if ( rSigInfo
.SignatureIsValid
)
363 rSigInfo
.SignatureIsValid
=
364 DocumentSignatureHelper::checkIfAllFilesAreSigned(
365 aElementsToBeVerified
, rInfo
, mode
);
367 if (eMode
== SignatureModeDocumentContent
)
368 rSigInfo
.PartialDocumentSignature
=
369 ! DocumentSignatureHelper::isOOo3_2_Signature(aSignInfos
[n
]);
377 void DocumentDigitalSignatures::manageTrustedSources( ) throw (RuntimeException
, std::exception
)
380 // SecEnv is only needed to display certificate information from trusted sources.
381 // Macro Security also has some options where no security environment is needed, so raise dialog anyway.
382 // Later I should change the code so the Dialog creates the SecEnv on demand...
384 Reference
< css::xml::crypto::XSecurityEnvironment
> xSecEnv
;
386 XMLSignatureHelper
aSignatureHelper( mxCtx
);
387 if ( aSignatureHelper
.Init() )
388 xSecEnv
= aSignatureHelper
.GetSecurityEnvironment();
390 ScopedVclPtrInstance
< MacroSecurity
> aDlg( nullptr, mxCtx
, xSecEnv
);
394 void DocumentDigitalSignatures::showCertificate(
395 const Reference
< css::security::XCertificate
>& _Certificate
) throw (RuntimeException
, std::exception
)
397 XMLSignatureHelper
aSignatureHelper( mxCtx
);
399 bool bInit
= aSignatureHelper
.Init();
401 DBG_ASSERT( bInit
, "Error initializing security context!" );
405 ScopedVclPtrInstance
< CertificateViewer
> aViewer( nullptr, aSignatureHelper
.GetSecurityEnvironment(), _Certificate
, false );
411 sal_Bool
DocumentDigitalSignatures::isAuthorTrusted(
412 const Reference
< css::security::XCertificate
>& Author
) throw (RuntimeException
, std::exception
)
416 Reference
<security::XSerialNumberAdapter
> xSerialNumberAdapter
=
417 ::com::sun::star::security::SerialNumberAdapter::create(mxCtx
);
419 OUString sSerialNum
= xSerialNumberAdapter
->toString( Author
->getSerialNumber() );
421 Sequence
< SvtSecurityOptions::Certificate
> aTrustedAuthors
= SvtSecurityOptions().GetTrustedAuthors();
422 const SvtSecurityOptions::Certificate
* pAuthors
= aTrustedAuthors
.getConstArray();
423 const SvtSecurityOptions::Certificate
* pAuthorsEnd
= pAuthors
+ aTrustedAuthors
.getLength();
424 for ( ; pAuthors
!= pAuthorsEnd
; ++pAuthors
)
426 SvtSecurityOptions::Certificate aAuthor
= *pAuthors
;
427 if ( ( aAuthor
[0] == Author
->getIssuerName() ) && ( aAuthor
[1] == sSerialNum
) )
437 Reference
< css::security::XCertificate
> DocumentDigitalSignatures::chooseCertificate() throw (RuntimeException
, std::exception
)
439 Reference
< css::xml::crypto::XSecurityEnvironment
> xSecEnv
;
441 XMLSignatureHelper
aSignatureHelper( mxCtx
);
442 if ( aSignatureHelper
.Init() )
443 xSecEnv
= aSignatureHelper
.GetSecurityEnvironment();
445 ScopedVclPtrInstance
< CertificateChooser
> aChooser( nullptr, mxCtx
, xSecEnv
, aSignatureHelper
.GetSignatureInformations());
447 if (aChooser
->Execute() != RET_OK
)
448 return Reference
< css::security::XCertificate
>(0);
450 Reference
< css::security::XCertificate
> xCert
= aChooser
->GetSelectedCertificate();
453 return Reference
< css::security::XCertificate
>(0);
459 sal_Bool
DocumentDigitalSignatures::isLocationTrusted( const OUString
& Location
) throw (RuntimeException
, std::exception
)
461 return SvtSecurityOptions().isTrustedLocationUri(Location
);
464 void DocumentDigitalSignatures::addAuthorToTrustedSources(
465 const Reference
< css::security::XCertificate
>& Author
) throw (RuntimeException
, std::exception
)
467 SvtSecurityOptions aSecOpts
;
469 Reference
<security::XSerialNumberAdapter
> xSerialNumberAdapter
=
470 ::com::sun::star::security::SerialNumberAdapter::create(mxCtx
);
472 SvtSecurityOptions::Certificate
aNewCert( 3 );
473 aNewCert
[ 0 ] = Author
->getIssuerName();
474 aNewCert
[ 1 ] = xSerialNumberAdapter
->toString( Author
->getSerialNumber() );
476 OUStringBuffer aStrBuffer
;
477 ::sax::Converter::encodeBase64(aStrBuffer
, Author
->getEncoded());
478 aNewCert
[ 2 ] = aStrBuffer
.makeStringAndClear();
481 Sequence
< SvtSecurityOptions::Certificate
> aTrustedAuthors
= aSecOpts
.GetTrustedAuthors();
482 sal_Int32 nCnt
= aTrustedAuthors
.getLength();
483 aTrustedAuthors
.realloc( nCnt
+ 1 );
484 aTrustedAuthors
[ nCnt
] = aNewCert
;
486 aSecOpts
.SetTrustedAuthors( aTrustedAuthors
);
489 void DocumentDigitalSignatures::addLocationToTrustedSources( const OUString
& Location
) throw (RuntimeException
, std::exception
)
491 SvtSecurityOptions aSecOpt
;
493 Sequence
< OUString
> aSecURLs
= aSecOpt
.GetSecureURLs();
494 sal_Int32 nCnt
= aSecURLs
.getLength();
495 aSecURLs
.realloc( nCnt
+ 1 );
496 aSecURLs
[ nCnt
] = Location
;
498 aSecOpt
.SetSecureURLs( aSecURLs
);
501 OUString
DocumentDigitalSignatures::GetImplementationName() throw (RuntimeException
)
503 return OUString( "com.sun.star.security.DocumentDigitalSignatures" );
506 Sequence
< OUString
> DocumentDigitalSignatures::GetSupportedServiceNames() throw (css::uno::RuntimeException
)
508 Sequence
< OUString
> aRet(1);
509 OUString
* pArray
= aRet
.getArray();
510 pArray
[0] = "com.sun.star.security.DocumentDigitalSignatures";
515 Reference
< XInterface
> DocumentDigitalSignatures_CreateInstance(
516 const Reference
< XComponentContext
>& rCtx
) throw ( Exception
)
518 return (cppu::OWeakObject
*) new DocumentDigitalSignatures( rCtx
);
521 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */