1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: documentdigitalsignatures.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
33 #include "precompiled_xmlsecurity.hxx"
35 #include <documentdigitalsignatures.hxx>
36 #include <xmlsecurity/digitalsignaturesdialog.hxx>
37 #include <xmlsecurity/certificateviewer.hxx>
38 #include <xmlsecurity/macrosecurity.hxx>
39 #include <xmlsecurity/biginteger.hxx>
40 #include <xmlsecurity/global.hrc>
42 #include <xmloff/xmluconv.hxx>
44 #include <../dialogs/resourcemanager.hxx>
45 #include <com/sun/star/embed/XStorage.hpp>
46 #include <com/sun/star/embed/XTransactedObject.hpp>
47 #include <com/sun/star/embed/ElementModes.hpp>
48 #include <com/sun/star/ucb/XContent.hpp>
49 #include <com/sun/star/ucb/XContentProvider.hpp>
50 #include <com/sun/star/ucb/XContentIdentifierFactory.hpp>
51 #include <com/sun/star/ucb/XCommandEnvironment.hpp>
52 #include <com/sun/star/ucb/XCommandProcessor.hpp>
53 #include <com/sun/star/ucb/Command.hpp>
54 #include <tools/urlobj.hxx>
55 #include <vcl/msgbox.hxx>
56 #include <svtools/securityoptions.hxx>
57 #include <com/sun/star/security/CertificateValidity.hpp>
58 #include <com/sun/star/security/SerialNumberAdapter.hpp>
59 #include <ucbhelper/contentbroker.hxx>
60 #include <unotools/ucbhelper.hxx>
61 #include <comphelper/componentcontext.hxx>
62 #include "comphelper/documentconstants.hxx"
64 #include "com/sun/star/lang/IllegalArgumentException.hpp"
69 using namespace ::com::sun::star
;
70 using namespace ::com::sun::star::uno
;
71 namespace css
= ::com::sun::star
;
73 #define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) )
75 DocumentDigitalSignatures::DocumentDigitalSignatures( const Reference
< XComponentContext
>& rxCtx
):
77 m_sODFVersion(ODFVER_012_TEXT
),
79 m_bHasDocumentSignature(false)
83 void DocumentDigitalSignatures::initialize( const Sequence
< Any
>& aArguments
)
84 throw (css::uno::Exception
, css::uno::RuntimeException
)
86 if (aArguments
.getLength() == 0 || aArguments
.getLength() > 2)
87 throw css::lang::IllegalArgumentException(
88 OUSTR("DocumentDigitalSignatures::initialize requires one or two arguments"),
89 Reference
<XInterface
>(static_cast<XInitialization
*>(this), UNO_QUERY
), 0);
91 m_nArgumentsCount
= aArguments
.getLength();
93 if (!(aArguments
[0] >>= m_sODFVersion
))
94 throw css::lang::IllegalArgumentException(
95 OUSTR("DocumentDigitalSignatures::initialize: the first arguments must be a string"),
96 Reference
<XInterface
>(static_cast<XInitialization
*>(this), UNO_QUERY
), 0);
98 if (aArguments
.getLength() == 2
99 && !(aArguments
[1] >>= m_bHasDocumentSignature
))
100 throw css::lang::IllegalArgumentException(
101 OUSTR("DocumentDigitalSignatures::initialize: the second arguments must be a bool"),
102 Reference
<XInterface
>(static_cast<XInitialization
*>(this), UNO_QUERY
), 1);
104 //the Version is supported as of ODF1.2, so for and 1.1 document or older we will receive the
105 //an empty string. In this case we set it to ODFVER_010_TEXT. Then we can later check easily
106 //if initialize was called. Only then m_sODFVersion.getLength() is greater than 0
107 if (m_sODFVersion
.getLength() == 0)
108 m_sODFVersion
= ODFVER_010_TEXT
;
111 sal_Bool
DocumentDigitalSignatures::signDocumentContent(
112 const Reference
< css::embed::XStorage
>& rxStorage
,
113 const Reference
< css::io::XStream
>& xSignStream
)
114 throw (RuntimeException
)
116 OSL_ENSURE(m_sODFVersion
.getLength(), "DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2");
117 return ImplViewSignatures( rxStorage
, xSignStream
, SignatureModeDocumentContent
, false );
120 Sequence
< css::security::DocumentSignatureInformation
>
121 DocumentDigitalSignatures::verifyDocumentContentSignatures(
122 const Reference
< css::embed::XStorage
>& rxStorage
,
123 const Reference
< css::io::XInputStream
>& xSignInStream
) throw (RuntimeException
)
125 OSL_ENSURE(m_sODFVersion
.getLength(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2");
126 return ImplVerifySignatures( rxStorage
, xSignInStream
, SignatureModeDocumentContent
);
129 void DocumentDigitalSignatures::showDocumentContentSignatures(
130 const Reference
< css::embed::XStorage
>& rxStorage
,
131 const Reference
< css::io::XInputStream
>& xSignInStream
) throw (RuntimeException
)
133 OSL_ENSURE(m_sODFVersion
.getLength(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2");
134 ImplViewSignatures( rxStorage
, xSignInStream
, SignatureModeDocumentContent
, true );
137 ::rtl::OUString
DocumentDigitalSignatures::getDocumentContentSignatureDefaultStreamName()
138 throw (css::uno::RuntimeException
)
140 return DocumentSignatureHelper::GetDocumentContentSignatureDefaultStreamName();
143 sal_Bool
DocumentDigitalSignatures::signScriptingContent(
144 const Reference
< css::embed::XStorage
>& rxStorage
,
145 const Reference
< css::io::XStream
>& xSignStream
) throw (RuntimeException
)
147 OSL_ENSURE(m_sODFVersion
.getLength(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2");
148 OSL_ENSURE(m_nArgumentsCount
== 2, "DocumentDigitalSignatures: Service was not initialized properly");
149 return ImplViewSignatures( rxStorage
, xSignStream
, SignatureModeMacros
, false );
152 Sequence
< css::security::DocumentSignatureInformation
>
153 DocumentDigitalSignatures::verifyScriptingContentSignatures(
154 const Reference
< css::embed::XStorage
>& rxStorage
,
155 const Reference
< css::io::XInputStream
>& xSignInStream
) throw (RuntimeException
)
157 OSL_ENSURE(m_sODFVersion
.getLength(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2");
158 return ImplVerifySignatures( rxStorage
, xSignInStream
, SignatureModeMacros
);
161 void DocumentDigitalSignatures::showScriptingContentSignatures(
162 const Reference
< css::embed::XStorage
>& rxStorage
,
163 const Reference
< css::io::XInputStream
>& xSignInStream
) throw (RuntimeException
)
165 OSL_ENSURE(m_sODFVersion
.getLength(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2");
166 ImplViewSignatures( rxStorage
, xSignInStream
, SignatureModeMacros
, true );
169 ::rtl::OUString
DocumentDigitalSignatures::getScriptingContentSignatureDefaultStreamName()
170 throw (css::uno::RuntimeException
)
172 return DocumentSignatureHelper::GetScriptingContentSignatureDefaultStreamName();
176 sal_Bool
DocumentDigitalSignatures::signPackage(
177 const Reference
< css::embed::XStorage
>& rxStorage
,
178 const Reference
< css::io::XStream
>& xSignStream
) throw (RuntimeException
)
180 OSL_ENSURE(m_sODFVersion
.getLength(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2");
181 return ImplViewSignatures( rxStorage
, xSignStream
, SignatureModePackage
, false );
184 Sequence
< css::security::DocumentSignatureInformation
>
185 DocumentDigitalSignatures::verifyPackageSignatures(
186 const Reference
< css::embed::XStorage
>& rxStorage
,
187 const Reference
< css::io::XInputStream
>& xSignInStream
) throw (RuntimeException
)
189 OSL_ENSURE(m_sODFVersion
.getLength(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2");
190 return ImplVerifySignatures( rxStorage
, xSignInStream
, SignatureModePackage
);
193 void DocumentDigitalSignatures::showPackageSignatures(
194 const Reference
< css::embed::XStorage
>& rxStorage
,
195 const Reference
< css::io::XInputStream
>& xSignInStream
) throw (RuntimeException
)
197 OSL_ENSURE(m_sODFVersion
.getLength(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2");
198 ImplViewSignatures( rxStorage
, xSignInStream
, SignatureModePackage
, true );
201 ::rtl::OUString
DocumentDigitalSignatures::getPackageSignatureDefaultStreamName( )
202 throw (::com::sun::star::uno::RuntimeException
)
204 return DocumentSignatureHelper::GetPackageSignatureDefaultStreamName();
208 sal_Bool
DocumentDigitalSignatures::ImplViewSignatures(
209 const Reference
< css::embed::XStorage
>& rxStorage
,
210 const Reference
< css::io::XInputStream
>& xSignStream
,
211 DocumentSignatureMode eMode
, bool bReadOnly
) throw (RuntimeException
)
213 Reference
< io::XStream
> xStream
;
214 if ( xSignStream
.is() )
215 xStream
= Reference
< io::XStream
>( xSignStream
, UNO_QUERY
);
216 return ImplViewSignatures( rxStorage
, xStream
, eMode
, bReadOnly
);
219 sal_Bool
DocumentDigitalSignatures::ImplViewSignatures(
220 const Reference
< css::embed::XStorage
>& rxStorage
, const Reference
< css::io::XStream
>& xSignStream
,
221 DocumentSignatureMode eMode
, bool bReadOnly
) throw (RuntimeException
)
223 sal_Bool bChanges
= sal_False
;
224 DigitalSignaturesDialog
aSignaturesDialog(
225 NULL
, mxCtx
, eMode
, bReadOnly
, m_sODFVersion
, m_bHasDocumentSignature
);
226 bool bInit
= aSignaturesDialog
.Init( rtl::OUString() );
227 DBG_ASSERT( bInit
, "Error initializing security context!" );
230 aSignaturesDialog
.SetStorage( rxStorage
);
231 aSignaturesDialog
.SetSignatureStream( xSignStream
);
232 if ( aSignaturesDialog
.Execute() )
234 if ( aSignaturesDialog
.SignaturesChanged() )
237 // If we have a storage and no stream, we are responsible for commit
238 if ( rxStorage
.is() && !xSignStream
.is() )
240 uno::Reference
< embed::XTransactedObject
> xTrans( rxStorage
, uno::UNO_QUERY
);
248 WarningBox
aBox( NULL
, XMLSEC_RES( RID_XMLSECWB_NO_MOZILLA_PROFILE
) );
255 Sequence
< css::security::DocumentSignatureInformation
>
256 DocumentDigitalSignatures::ImplVerifySignatures(
257 const Reference
< css::embed::XStorage
>& rxStorage
,
258 const Reference
< css::io::XInputStream
>& xSignStream
, DocumentSignatureMode eMode
) throw (RuntimeException
)
262 DBG_ASSERT(0, "Error, no XStorage provided");
263 return Sequence
<css::security::DocumentSignatureInformation
>();
265 // First check for the InputStream, to avoid unnecessary initialization of the security environemnt...
266 SignatureStreamHelper aStreamHelper
;
267 Reference
< io::XInputStream
> xInputStream
= xSignStream
;
269 if ( !xInputStream
.is() )
271 aStreamHelper
= DocumentSignatureHelper::OpenSignatureStream( rxStorage
, embed::ElementModes::READ
, eMode
);
272 if ( aStreamHelper
.xSignatureStream
.is() )
273 xInputStream
= Reference
< io::XInputStream
>( aStreamHelper
.xSignatureStream
, UNO_QUERY
);
276 if ( !xInputStream
.is() )
277 return Sequence
< ::com::sun::star::security::DocumentSignatureInformation
>(0);
280 XMLSignatureHelper
aSignatureHelper( mxCtx
);
282 bool bInit
= aSignatureHelper
.Init( rtl::OUString() );
284 DBG_ASSERT( bInit
, "Error initializing security context!" );
287 return Sequence
< ::com::sun::star::security::DocumentSignatureInformation
>(0);
289 aSignatureHelper
.SetStorage(rxStorage
, m_sODFVersion
);
291 aSignatureHelper
.StartMission();
293 aSignatureHelper
.ReadAndVerifySignature( xInputStream
);
295 aSignatureHelper
.EndMission();
297 Reference
< ::com::sun::star::xml::crypto::XSecurityEnvironment
> xSecEnv
= aSignatureHelper
.GetSecurityEnvironment();
299 SignatureInformations aSignInfos
= aSignatureHelper
.GetSignatureInformations();
300 int nInfos
= aSignInfos
.size();
301 Sequence
< css::security::DocumentSignatureInformation
> aInfos(nInfos
);
302 css::security::DocumentSignatureInformation
* arInfos
= aInfos
.getArray();
306 Reference
<security::XSerialNumberAdapter
> xSerialNumberAdapter
=
307 ::com::sun::star::security::SerialNumberAdapter::create(mxCtx
);
309 for( int n
= 0; n
< nInfos
; ++n
)
311 DocumentSignatureAlgorithm mode
= DocumentSignatureHelper::getDocumentAlgorithm(
312 m_sODFVersion
, aSignInfos
[n
]);
313 const std::vector
< rtl::OUString
> aElementsToBeVerified
=
314 DocumentSignatureHelper::CreateElementList(
315 rxStorage
, ::rtl::OUString(), eMode
, mode
);
317 const SignatureInformation
& rInfo
= aSignInfos
[n
];
318 css::security::DocumentSignatureInformation
& rSigInfo
= arInfos
[n
];
320 if (rInfo
.ouX509Certificate
.getLength())
321 rSigInfo
.Signer
= xSecEnv
->createCertificateFromAscii( rInfo
.ouX509Certificate
) ;
322 if (!rSigInfo
.Signer
.is())
323 rSigInfo
.Signer
= xSecEnv
->getCertificate( rInfo
.ouX509IssuerName
, xSerialNumberAdapter
->toSequence( rInfo
.ouX509SerialNumber
) );
325 // --> PB 2004-12-14 #i38744# time support again
326 Date
aDate( rInfo
.stDateTime
.Day
, rInfo
.stDateTime
.Month
, rInfo
.stDateTime
.Year
);
327 Time
aTime( rInfo
.stDateTime
.Hours
, rInfo
.stDateTime
.Minutes
,
328 rInfo
.stDateTime
.Seconds
, rInfo
.stDateTime
.HundredthSeconds
);
329 rSigInfo
.SignatureDate
= aDate
.GetDate();
330 rSigInfo
.SignatureTime
= aTime
.GetTime();
332 // Verify certificate
333 //We have patched our version of libxmlsec, so that it does not verify the certificates. This has two
334 //reasons. First we want two separate status for signature and certificate. Second libxmlsec calls
335 //CERT_VerifyCertificate (solaris, linux) falsly, so that it always regards the certificate as valid.
336 //On Window the checking of the certificate path is buggy. It does name matching (issuer, subject name)
337 //to find the parent certificate. It does not take into account that there can be several certificates
338 //with the same subject name.
339 if (rSigInfo
.Signer
.is())
342 rSigInfo
.CertificateStatus
= xSecEnv
->verifyCertificate(rSigInfo
.Signer
,
343 Sequence
<Reference
<css::security::XCertificate
> >());
344 } catch (SecurityException
& ) {
345 OSL_ENSURE(0, "Verification of certificate failed");
346 rSigInfo
.CertificateStatus
= css::security::CertificateValidity::INVALID
;
351 //We should always be aible to get the certificates because it is contained in the document,
352 //unless the document is damaged so that signature xml file could not be parsed.
353 rSigInfo
.CertificateStatus
= css::security::CertificateValidity::INVALID
;
356 rSigInfo
.SignatureIsValid
= ( rInfo
.nStatus
== ::com::sun::star::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED
);
359 if ( rSigInfo
.SignatureIsValid
)
361 rSigInfo
.SignatureIsValid
=
362 DocumentSignatureHelper::checkIfAllFilesAreSigned(
363 aElementsToBeVerified
, rInfo
, mode
);
365 if (eMode
== SignatureModeDocumentContent
)
366 rSigInfo
.PartialDocumentSignature
=
367 ! DocumentSignatureHelper::isOOo3_2_Signature(aSignInfos
[n
]);
375 void DocumentDigitalSignatures::manageTrustedSources( ) throw (RuntimeException
)
378 // SecEnv is only needed to display certificate information from trusted sources.
379 // Macro Security also has some options where no security environment is needed, so raise dialog anyway.
380 // Later I should change the code so the Dialog creates the SecEnv on demand...
382 Reference
< dcss::xml::crypto::XSecurityEnvironment
> xSecEnv
;
384 XMLSignatureHelper
aSignatureHelper( mxCtx
);
385 if ( aSignatureHelper
.Init( rtl::OUString() ) )
386 xSecEnv
= aSignatureHelper
.GetSecurityEnvironment();
388 MacroSecurity
aDlg( NULL
, mxCtx
, xSecEnv
);
392 void DocumentDigitalSignatures::showCertificate(
393 const Reference
< css::security::XCertificate
>& _Certificate
) throw (RuntimeException
)
395 XMLSignatureHelper
aSignatureHelper( mxCtx
);
397 bool bInit
= aSignatureHelper
.Init( rtl::OUString() );
399 DBG_ASSERT( bInit
, "Error initializing security context!" );
403 CertificateViewer
aViewer( NULL
, aSignatureHelper
.GetSecurityEnvironment(), _Certificate
, FALSE
);
409 ::sal_Bool
DocumentDigitalSignatures::isAuthorTrusted(
410 const Reference
< css::security::XCertificate
>& Author
) throw (RuntimeException
)
412 sal_Bool bFound
= sal_False
;
414 Reference
<security::XSerialNumberAdapter
> xSerialNumberAdapter
=
415 ::com::sun::star::security::SerialNumberAdapter::create(mxCtx
);
417 ::rtl::OUString sSerialNum
= xSerialNumberAdapter
->toString( Author
->getSerialNumber() );
419 Sequence
< SvtSecurityOptions::Certificate
> aTrustedAuthors
= SvtSecurityOptions().GetTrustedAuthors();
420 const SvtSecurityOptions::Certificate
* pAuthors
= aTrustedAuthors
.getConstArray();
421 const SvtSecurityOptions::Certificate
* pAuthorsEnd
= pAuthors
+ aTrustedAuthors
.getLength();
422 for ( ; pAuthors
!= pAuthorsEnd
; ++pAuthors
)
424 SvtSecurityOptions::Certificate aAuthor
= *pAuthors
;
425 if ( ( aAuthor
[0] == Author
->getIssuerName() ) && ( aAuthor
[1] == sSerialNum
) )
435 ::sal_Bool
DocumentDigitalSignatures::isLocationTrusted( const ::rtl::OUString
& Location
) throw (RuntimeException
)
437 sal_Bool bFound
= sal_False
;
438 INetURLObject
aLocObj( Location
);
439 INetURLObject
aLocObjLowCase( Location
.toAsciiLowerCase() ); // will be used for case insensitive comparing
441 ::com::sun::star::uno::Reference
< ::com::sun::star::ucb::XContentProvider
> xContentProvider
;
442 ::ucbhelper::ContentBroker
* pBroker
= NULL
;
445 //if ( aLocObj.GetProtocol() == INET_PROT_FILE && ( pBroker = ::ucbhelper::ContentBroker::get() ) )
446 // xContentProvider = pBroker->getContentProviderInterface();
447 if ( aLocObj
.GetProtocol() == INET_PROT_FILE
)
449 pBroker
= ::ucbhelper::ContentBroker::get();
451 xContentProvider
= pBroker
->getContentProviderInterface();
454 Sequence
< ::rtl::OUString
> aSecURLs
= SvtSecurityOptions().GetSecureURLs();
455 const ::rtl::OUString
* pSecURLs
= aSecURLs
.getConstArray();
456 const ::rtl::OUString
* pSecURLsEnd
= pSecURLs
+ aSecURLs
.getLength();
457 for ( ; pSecURLs
!= pSecURLsEnd
&& !bFound
; ++pSecURLs
)
458 bFound
= ::utl::UCBContentHelper::IsSubPath( *pSecURLs
, Location
, xContentProvider
);
463 void DocumentDigitalSignatures::addAuthorToTrustedSources(
464 const Reference
< css::security::XCertificate
>& Author
) throw (RuntimeException
)
466 SvtSecurityOptions aSecOpts
;
468 Reference
<security::XSerialNumberAdapter
> xSerialNumberAdapter
=
469 ::com::sun::star::security::SerialNumberAdapter::create(mxCtx
);
471 SvtSecurityOptions::Certificate
aNewCert( 3 );
472 aNewCert
[ 0 ] = Author
->getIssuerName();
473 aNewCert
[ 1 ] = xSerialNumberAdapter
->toString( Author
->getSerialNumber() );
475 rtl::OUStringBuffer aStrBuffer
;
476 SvXMLUnitConverter::encodeBase64(aStrBuffer
, Author
->getEncoded());
477 aNewCert
[ 2 ] = aStrBuffer
.makeStringAndClear();
480 Sequence
< SvtSecurityOptions::Certificate
> aTrustedAuthors
= aSecOpts
.GetTrustedAuthors();
481 sal_Int32 nCnt
= aTrustedAuthors
.getLength();
482 aTrustedAuthors
.realloc( nCnt
+ 1 );
483 aTrustedAuthors
[ nCnt
] = aNewCert
;
485 aSecOpts
.SetTrustedAuthors( aTrustedAuthors
);
488 void DocumentDigitalSignatures::addLocationToTrustedSources( const ::rtl::OUString
& Location
) throw (RuntimeException
)
490 SvtSecurityOptions aSecOpt
;
492 Sequence
< ::rtl::OUString
> aSecURLs
= aSecOpt
.GetSecureURLs();
493 sal_Int32 nCnt
= aSecURLs
.getLength();
494 aSecURLs
.realloc( nCnt
+ 1 );
495 aSecURLs
[ nCnt
] = Location
;
497 aSecOpt
.SetSecureURLs( aSecURLs
);
500 rtl::OUString
DocumentDigitalSignatures::GetImplementationName() throw (RuntimeException
)
502 return rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.security.DocumentDigitalSignatures" ) );
505 Sequence
< rtl::OUString
> DocumentDigitalSignatures::GetSupportedServiceNames() throw (cssu::RuntimeException
)
507 Sequence
< rtl::OUString
> aRet(1);
508 rtl::OUString
* pArray
= aRet
.getArray();
509 pArray
[0] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.security.DocumentDigitalSignatures" ) );
514 Reference
< XInterface
> DocumentDigitalSignatures_CreateInstance(
515 const Reference
< XComponentContext
>& rCtx
) throw ( Exception
)
517 return (cppu::OWeakObject
*) new DocumentDigitalSignatures( rCtx
);