Branch libreoffice-5-0-4
[LibreOffice.git] / xmlsecurity / source / component / documentdigitalsignatures.cxx
blob287b5cf50125c95ca5f8f23dc1a772a787013d40
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
47 #include <stdio.h>
50 using namespace css;
51 using namespace css::uno;
53 DocumentDigitalSignatures::DocumentDigitalSignatures( const Reference< XComponentContext >& rxCtx ):
54 mxCtx(rxCtx),
55 m_sODFVersion(ODFVER_012_TEXT),
56 m_nArgumentsCount(0),
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!" );
230 if ( bInit )
232 aSignaturesDialog->SetStorage( rxStorage );
233 aSignaturesDialog->SetSignatureStream( xSignStream );
234 if ( aSignaturesDialog->Execute() )
236 if ( aSignaturesDialog->SignaturesChanged() )
238 bChanges = true;
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 );
243 xTrans->commit();
248 else
250 ScopedVclPtrInstance< MessageDialog > aBox(nullptr, XMLSEC_RES(RID_XMLSECWB_NO_MOZILLA_PROFILE), VCL_MESSAGE_WARNING);
251 aBox->Execute();
254 return bChanges;
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)
262 if (!rxStorage.is())
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!" );
288 if ( !bInit )
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();
306 if ( nInfos )
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())
343 try {
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;
351 else
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]);
373 return aInfos;
377 void DocumentDigitalSignatures::manageTrustedSources( ) throw (RuntimeException, std::exception)
379 // MT: i45295
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 );
391 aDlg->Execute();
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!" );
403 if ( bInit )
405 ScopedVclPtrInstance< CertificateViewer > aViewer( nullptr, aSignatureHelper.GetSecurityEnvironment(), _Certificate, false );
406 aViewer->Execute();
411 sal_Bool DocumentDigitalSignatures::isAuthorTrusted(
412 const Reference< css::security::XCertificate >& Author ) throw (RuntimeException, std::exception)
414 bool bFound = false;
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 ) )
429 bFound = true;
430 break;
434 return bFound;
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();
452 if ( !xCert.is() )
453 return Reference< css::security::XCertificate >(0);
455 return xCert;
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";
511 return aRet;
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: */