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 <tools/urlobj.hxx>
40 #include <vcl/msgbox.hxx>
41 #include <unotools/securityoptions.hxx>
42 #include <com/sun/star/security/CertificateValidity.hpp>
43 #include <com/sun/star/security/SerialNumberAdapter.hpp>
44 #include <unotools/ucbhelper.hxx>
45 #include <comphelper/componentcontext.hxx>
46 #include "comphelper/documentconstants.hxx"
48 #include "com/sun/star/lang/IllegalArgumentException.hpp"
53 using namespace ::com::sun::star
;
54 using namespace ::com::sun::star::uno
;
56 DocumentDigitalSignatures::DocumentDigitalSignatures( const Reference
< XComponentContext
>& rxCtx
):
58 m_sODFVersion(ODFVER_012_TEXT
),
60 m_bHasDocumentSignature(false)
64 void DocumentDigitalSignatures::initialize( const Sequence
< Any
>& aArguments
)
65 throw (css::uno::Exception
, css::uno::RuntimeException
)
67 if (aArguments
.getLength() > 2)
68 throw css::lang::IllegalArgumentException(
69 "DocumentDigitalSignatures::initialize requires zero, one, or two arguments",
70 Reference
<XInterface
>(static_cast<XInitialization
*>(this), UNO_QUERY
), 0);
72 m_nArgumentsCount
= aArguments
.getLength();
74 if (aArguments
.getLength() > 0)
76 if (!(aArguments
[0] >>= m_sODFVersion
))
77 throw css::lang::IllegalArgumentException(
78 "DocumentDigitalSignatures::initialize: the first arguments must be a string",
79 Reference
<XInterface
>(static_cast<XInitialization
*>(this), UNO_QUERY
), 0);
81 if (aArguments
.getLength() == 2
82 && !(aArguments
[1] >>= m_bHasDocumentSignature
))
83 throw css::lang::IllegalArgumentException(
84 "DocumentDigitalSignatures::initialize: the second arguments must be a bool",
85 Reference
<XInterface
>(static_cast<XInitialization
*>(this), UNO_QUERY
), 1);
87 //the Version is supported as of ODF1.2, so for and 1.1 document or older we will receive the
88 //an empty string. In this case we set it to ODFVER_010_TEXT. Then we can later check easily
89 //if initialize was called. Only then m_sODFVersion.getLength() is greater than 0
90 if (m_sODFVersion
.isEmpty())
91 m_sODFVersion
= ODFVER_010_TEXT
;
95 sal_Bool
DocumentDigitalSignatures::signDocumentContent(
96 const Reference
< css::embed::XStorage
>& rxStorage
,
97 const Reference
< css::io::XStream
>& xSignStream
)
98 throw (RuntimeException
)
100 OSL_ENSURE(!m_sODFVersion
.isEmpty(), "DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2");
101 return ImplViewSignatures( rxStorage
, xSignStream
, SignatureModeDocumentContent
, false );
104 Sequence
< css::security::DocumentSignatureInformation
>
105 DocumentDigitalSignatures::verifyDocumentContentSignatures(
106 const Reference
< css::embed::XStorage
>& rxStorage
,
107 const Reference
< css::io::XInputStream
>& xSignInStream
) throw (RuntimeException
)
109 OSL_ENSURE(!m_sODFVersion
.isEmpty(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2");
110 return ImplVerifySignatures( rxStorage
, xSignInStream
, SignatureModeDocumentContent
);
113 void DocumentDigitalSignatures::showDocumentContentSignatures(
114 const Reference
< css::embed::XStorage
>& rxStorage
,
115 const Reference
< css::io::XInputStream
>& xSignInStream
) throw (RuntimeException
)
117 OSL_ENSURE(!m_sODFVersion
.isEmpty(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2");
118 ImplViewSignatures( rxStorage
, xSignInStream
, SignatureModeDocumentContent
, true );
121 OUString
DocumentDigitalSignatures::getDocumentContentSignatureDefaultStreamName()
122 throw (css::uno::RuntimeException
)
124 return DocumentSignatureHelper::GetDocumentContentSignatureDefaultStreamName();
127 sal_Bool
DocumentDigitalSignatures::signScriptingContent(
128 const Reference
< css::embed::XStorage
>& rxStorage
,
129 const Reference
< css::io::XStream
>& xSignStream
) throw (RuntimeException
)
131 OSL_ENSURE(!m_sODFVersion
.isEmpty(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2");
132 OSL_ENSURE(m_nArgumentsCount
== 2, "DocumentDigitalSignatures: Service was not initialized properly");
133 return ImplViewSignatures( rxStorage
, xSignStream
, SignatureModeMacros
, false );
136 Sequence
< css::security::DocumentSignatureInformation
>
137 DocumentDigitalSignatures::verifyScriptingContentSignatures(
138 const Reference
< css::embed::XStorage
>& rxStorage
,
139 const Reference
< css::io::XInputStream
>& xSignInStream
) throw (RuntimeException
)
141 OSL_ENSURE(!m_sODFVersion
.isEmpty(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2");
142 return ImplVerifySignatures( rxStorage
, xSignInStream
, SignatureModeMacros
);
145 void DocumentDigitalSignatures::showScriptingContentSignatures(
146 const Reference
< css::embed::XStorage
>& rxStorage
,
147 const Reference
< css::io::XInputStream
>& xSignInStream
) throw (RuntimeException
)
149 OSL_ENSURE(!m_sODFVersion
.isEmpty(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2");
150 ImplViewSignatures( rxStorage
, xSignInStream
, SignatureModeMacros
, true );
153 OUString
DocumentDigitalSignatures::getScriptingContentSignatureDefaultStreamName()
154 throw (css::uno::RuntimeException
)
156 return DocumentSignatureHelper::GetScriptingContentSignatureDefaultStreamName();
160 sal_Bool
DocumentDigitalSignatures::signPackage(
161 const Reference
< css::embed::XStorage
>& rxStorage
,
162 const Reference
< css::io::XStream
>& xSignStream
) throw (RuntimeException
)
164 OSL_ENSURE(!m_sODFVersion
.isEmpty(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2");
165 return ImplViewSignatures( rxStorage
, xSignStream
, SignatureModePackage
, false );
168 Sequence
< css::security::DocumentSignatureInformation
>
169 DocumentDigitalSignatures::verifyPackageSignatures(
170 const Reference
< css::embed::XStorage
>& rxStorage
,
171 const Reference
< css::io::XInputStream
>& xSignInStream
) throw (RuntimeException
)
173 OSL_ENSURE(!m_sODFVersion
.isEmpty(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2");
174 return ImplVerifySignatures( rxStorage
, xSignInStream
, SignatureModePackage
);
177 void DocumentDigitalSignatures::showPackageSignatures(
178 const Reference
< css::embed::XStorage
>& rxStorage
,
179 const Reference
< css::io::XInputStream
>& xSignInStream
) throw (RuntimeException
)
181 OSL_ENSURE(!m_sODFVersion
.isEmpty(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2");
182 ImplViewSignatures( rxStorage
, xSignInStream
, SignatureModePackage
, true );
185 OUString
DocumentDigitalSignatures::getPackageSignatureDefaultStreamName( )
186 throw (::com::sun::star::uno::RuntimeException
)
188 return DocumentSignatureHelper::GetPackageSignatureDefaultStreamName();
192 sal_Bool
DocumentDigitalSignatures::ImplViewSignatures(
193 const Reference
< css::embed::XStorage
>& rxStorage
,
194 const Reference
< css::io::XInputStream
>& xSignStream
,
195 DocumentSignatureMode eMode
, bool bReadOnly
) throw (RuntimeException
)
197 Reference
< io::XStream
> xStream
;
198 if ( xSignStream
.is() )
199 xStream
= Reference
< io::XStream
>( xSignStream
, UNO_QUERY
);
200 return ImplViewSignatures( rxStorage
, xStream
, eMode
, bReadOnly
);
203 sal_Bool
DocumentDigitalSignatures::ImplViewSignatures(
204 const Reference
< css::embed::XStorage
>& rxStorage
, const Reference
< css::io::XStream
>& xSignStream
,
205 DocumentSignatureMode eMode
, bool bReadOnly
) throw (RuntimeException
)
207 sal_Bool bChanges
= sal_False
;
208 DigitalSignaturesDialog
aSignaturesDialog(
209 NULL
, mxCtx
, eMode
, bReadOnly
, m_sODFVersion
, m_bHasDocumentSignature
);
210 bool bInit
= aSignaturesDialog
.Init();
211 DBG_ASSERT( bInit
, "Error initializing security context!" );
214 aSignaturesDialog
.SetStorage( rxStorage
);
215 aSignaturesDialog
.SetSignatureStream( xSignStream
);
216 if ( aSignaturesDialog
.Execute() )
218 if ( aSignaturesDialog
.SignaturesChanged() )
221 // If we have a storage and no stream, we are responsible for commit
222 if ( rxStorage
.is() && !xSignStream
.is() )
224 uno::Reference
< embed::XTransactedObject
> xTrans( rxStorage
, uno::UNO_QUERY
);
232 WarningBox
aBox( NULL
, XMLSEC_RES( RID_XMLSECWB_NO_MOZILLA_PROFILE
) );
239 Sequence
< css::security::DocumentSignatureInformation
>
240 DocumentDigitalSignatures::ImplVerifySignatures(
241 const Reference
< css::embed::XStorage
>& rxStorage
,
242 const Reference
< css::io::XInputStream
>& xSignStream
, DocumentSignatureMode eMode
) throw (RuntimeException
)
246 DBG_ASSERT(0, "Error, no XStorage provided");
247 return Sequence
<css::security::DocumentSignatureInformation
>();
249 // First check for the InputStream, to avoid unnecessary initialization of the security environemnt...
250 SignatureStreamHelper aStreamHelper
;
251 Reference
< io::XInputStream
> xInputStream
= xSignStream
;
253 if ( !xInputStream
.is() )
255 aStreamHelper
= DocumentSignatureHelper::OpenSignatureStream( rxStorage
, embed::ElementModes::READ
, eMode
);
256 if ( aStreamHelper
.xSignatureStream
.is() )
257 xInputStream
= Reference
< io::XInputStream
>( aStreamHelper
.xSignatureStream
, UNO_QUERY
);
260 if ( !xInputStream
.is() )
261 return Sequence
< ::com::sun::star::security::DocumentSignatureInformation
>(0);
264 XMLSignatureHelper
aSignatureHelper( mxCtx
);
266 bool bInit
= aSignatureHelper
.Init();
268 DBG_ASSERT( bInit
, "Error initializing security context!" );
271 return Sequence
< ::com::sun::star::security::DocumentSignatureInformation
>(0);
273 aSignatureHelper
.SetStorage(rxStorage
, m_sODFVersion
);
275 aSignatureHelper
.StartMission();
277 aSignatureHelper
.ReadAndVerifySignature( xInputStream
);
279 aSignatureHelper
.EndMission();
281 Reference
< ::com::sun::star::xml::crypto::XSecurityEnvironment
> xSecEnv
= aSignatureHelper
.GetSecurityEnvironment();
283 SignatureInformations aSignInfos
= aSignatureHelper
.GetSignatureInformations();
284 int nInfos
= aSignInfos
.size();
285 Sequence
< css::security::DocumentSignatureInformation
> aInfos(nInfos
);
286 css::security::DocumentSignatureInformation
* arInfos
= aInfos
.getArray();
290 Reference
<security::XSerialNumberAdapter
> xSerialNumberAdapter
=
291 ::com::sun::star::security::SerialNumberAdapter::create(mxCtx
);
293 for( int n
= 0; n
< nInfos
; ++n
)
295 DocumentSignatureAlgorithm mode
= DocumentSignatureHelper::getDocumentAlgorithm(
296 m_sODFVersion
, aSignInfos
[n
]);
297 const std::vector
< OUString
> aElementsToBeVerified
=
298 DocumentSignatureHelper::CreateElementList(
299 rxStorage
, OUString(), eMode
, mode
);
301 const SignatureInformation
& rInfo
= aSignInfos
[n
];
302 css::security::DocumentSignatureInformation
& rSigInfo
= arInfos
[n
];
304 if (!rInfo
.ouX509Certificate
.isEmpty())
305 rSigInfo
.Signer
= xSecEnv
->createCertificateFromAscii( rInfo
.ouX509Certificate
) ;
306 if (!rSigInfo
.Signer
.is())
307 rSigInfo
.Signer
= xSecEnv
->getCertificate( rInfo
.ouX509IssuerName
, xSerialNumberAdapter
->toSequence( rInfo
.ouX509SerialNumber
) );
309 // Time support again (#i38744#)
310 Date
aDate( rInfo
.stDateTime
.Day
, rInfo
.stDateTime
.Month
, rInfo
.stDateTime
.Year
);
311 Time
aTime( rInfo
.stDateTime
.Hours
, rInfo
.stDateTime
.Minutes
,
312 rInfo
.stDateTime
.Seconds
, rInfo
.stDateTime
.NanoSeconds
);
313 rSigInfo
.SignatureDate
= aDate
.GetDate();
314 rSigInfo
.SignatureTime
= aTime
.GetTime();
316 // Verify certificate
317 //We have patched our version of libxmlsec, so that it does not verify the certificates. This has two
318 //reasons. First we want two separate status for signature and certificate. Second libxmlsec calls
319 //CERT_VerifyCertificate (solaris, linux) falsly, so that it always regards the certificate as valid.
320 //On Window the checking of the certificate path is buggy. It does name matching (issuer, subject name)
321 //to find the parent certificate. It does not take into account that there can be several certificates
322 //with the same subject name.
323 if (rSigInfo
.Signer
.is())
326 rSigInfo
.CertificateStatus
= xSecEnv
->verifyCertificate(rSigInfo
.Signer
,
327 Sequence
<Reference
<css::security::XCertificate
> >());
328 } catch (SecurityException
& ) {
329 OSL_FAIL("Verification of certificate failed");
330 rSigInfo
.CertificateStatus
= css::security::CertificateValidity::INVALID
;
335 //We should always be aible to get the certificates because it is contained in the document,
336 //unless the document is damaged so that signature xml file could not be parsed.
337 rSigInfo
.CertificateStatus
= css::security::CertificateValidity::INVALID
;
340 rSigInfo
.SignatureIsValid
= ( rInfo
.nStatus
== ::com::sun::star::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED
);
343 if ( rSigInfo
.SignatureIsValid
)
345 rSigInfo
.SignatureIsValid
=
346 DocumentSignatureHelper::checkIfAllFilesAreSigned(
347 aElementsToBeVerified
, rInfo
, mode
);
349 if (eMode
== SignatureModeDocumentContent
)
350 rSigInfo
.PartialDocumentSignature
=
351 ! DocumentSignatureHelper::isOOo3_2_Signature(aSignInfos
[n
]);
359 void DocumentDigitalSignatures::manageTrustedSources( ) throw (RuntimeException
)
362 // SecEnv is only needed to display certificate information from trusted sources.
363 // Macro Security also has some options where no security environment is needed, so raise dialog anyway.
364 // Later I should change the code so the Dialog creates the SecEnv on demand...
366 Reference
< css::xml::crypto::XSecurityEnvironment
> xSecEnv
;
368 XMLSignatureHelper
aSignatureHelper( mxCtx
);
369 if ( aSignatureHelper
.Init() )
370 xSecEnv
= aSignatureHelper
.GetSecurityEnvironment();
372 MacroSecurity
aDlg( NULL
, mxCtx
, xSecEnv
);
376 void DocumentDigitalSignatures::showCertificate(
377 const Reference
< css::security::XCertificate
>& _Certificate
) throw (RuntimeException
)
379 XMLSignatureHelper
aSignatureHelper( mxCtx
);
381 bool bInit
= aSignatureHelper
.Init();
383 DBG_ASSERT( bInit
, "Error initializing security context!" );
387 CertificateViewer
aViewer( NULL
, aSignatureHelper
.GetSecurityEnvironment(), _Certificate
, sal_False
);
393 ::sal_Bool
DocumentDigitalSignatures::isAuthorTrusted(
394 const Reference
< css::security::XCertificate
>& Author
) throw (RuntimeException
)
396 sal_Bool bFound
= sal_False
;
398 Reference
<security::XSerialNumberAdapter
> xSerialNumberAdapter
=
399 ::com::sun::star::security::SerialNumberAdapter::create(mxCtx
);
401 OUString sSerialNum
= xSerialNumberAdapter
->toString( Author
->getSerialNumber() );
403 Sequence
< SvtSecurityOptions::Certificate
> aTrustedAuthors
= SvtSecurityOptions().GetTrustedAuthors();
404 const SvtSecurityOptions::Certificate
* pAuthors
= aTrustedAuthors
.getConstArray();
405 const SvtSecurityOptions::Certificate
* pAuthorsEnd
= pAuthors
+ aTrustedAuthors
.getLength();
406 for ( ; pAuthors
!= pAuthorsEnd
; ++pAuthors
)
408 SvtSecurityOptions::Certificate aAuthor
= *pAuthors
;
409 if ( ( aAuthor
[0] == Author
->getIssuerName() ) && ( aAuthor
[1] == sSerialNum
) )
419 Reference
< css::security::XCertificate
> DocumentDigitalSignatures::chooseCertificate() throw (RuntimeException
)
421 Reference
< css::xml::crypto::XSecurityEnvironment
> xSecEnv
;
423 XMLSignatureHelper
aSignatureHelper( mxCtx
);
424 if ( aSignatureHelper
.Init() )
425 xSecEnv
= aSignatureHelper
.GetSecurityEnvironment();
427 CertificateChooser
aChooser( NULL
, mxCtx
, xSecEnv
, aSignatureHelper
.GetSignatureInformations());
429 if (aChooser
.Execute() != RET_OK
)
430 return Reference
< css::security::XCertificate
>(0);
432 Reference
< css::security::XCertificate
> xCert
= aChooser
.GetSelectedCertificate();
435 return Reference
< css::security::XCertificate
>(0);
441 ::sal_Bool
DocumentDigitalSignatures::isLocationTrusted( const OUString
& Location
) throw (RuntimeException
)
443 sal_Bool bFound
= sal_False
;
444 INetURLObject
aLocObj( Location
);
445 INetURLObject
aLocObjLowCase( Location
.toAsciiLowerCase() ); // will be used for case insensitive comparing
447 Sequence
< OUString
> aSecURLs
= SvtSecurityOptions().GetSecureURLs();
448 const OUString
* pSecURLs
= aSecURLs
.getConstArray();
449 const OUString
* pSecURLsEnd
= pSecURLs
+ aSecURLs
.getLength();
450 for ( ; pSecURLs
!= pSecURLsEnd
&& !bFound
; ++pSecURLs
)
451 bFound
= ::utl::UCBContentHelper::IsSubPath( *pSecURLs
, Location
);
456 void DocumentDigitalSignatures::addAuthorToTrustedSources(
457 const Reference
< css::security::XCertificate
>& Author
) throw (RuntimeException
)
459 SvtSecurityOptions aSecOpts
;
461 Reference
<security::XSerialNumberAdapter
> xSerialNumberAdapter
=
462 ::com::sun::star::security::SerialNumberAdapter::create(mxCtx
);
464 SvtSecurityOptions::Certificate
aNewCert( 3 );
465 aNewCert
[ 0 ] = Author
->getIssuerName();
466 aNewCert
[ 1 ] = xSerialNumberAdapter
->toString( Author
->getSerialNumber() );
468 OUStringBuffer aStrBuffer
;
469 ::sax::Converter::encodeBase64(aStrBuffer
, Author
->getEncoded());
470 aNewCert
[ 2 ] = aStrBuffer
.makeStringAndClear();
473 Sequence
< SvtSecurityOptions::Certificate
> aTrustedAuthors
= aSecOpts
.GetTrustedAuthors();
474 sal_Int32 nCnt
= aTrustedAuthors
.getLength();
475 aTrustedAuthors
.realloc( nCnt
+ 1 );
476 aTrustedAuthors
[ nCnt
] = aNewCert
;
478 aSecOpts
.SetTrustedAuthors( aTrustedAuthors
);
481 void DocumentDigitalSignatures::addLocationToTrustedSources( const OUString
& Location
) throw (RuntimeException
)
483 SvtSecurityOptions aSecOpt
;
485 Sequence
< OUString
> aSecURLs
= aSecOpt
.GetSecureURLs();
486 sal_Int32 nCnt
= aSecURLs
.getLength();
487 aSecURLs
.realloc( nCnt
+ 1 );
488 aSecURLs
[ nCnt
] = Location
;
490 aSecOpt
.SetSecureURLs( aSecURLs
);
493 OUString
DocumentDigitalSignatures::GetImplementationName() throw (RuntimeException
)
495 return OUString( "com.sun.star.security.DocumentDigitalSignatures" );
498 Sequence
< OUString
> DocumentDigitalSignatures::GetSupportedServiceNames() throw (css::uno::RuntimeException
)
500 Sequence
< OUString
> aRet(1);
501 OUString
* pArray
= aRet
.getArray();
502 pArray
[0] = OUString( "com.sun.star.security.DocumentDigitalSignatures" );
507 Reference
< XInterface
> DocumentDigitalSignatures_CreateInstance(
508 const Reference
< XComponentContext
>& rCtx
) throw ( Exception
)
510 return (cppu::OWeakObject
*) new DocumentDigitalSignatures( rCtx
);
513 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */