/************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * Copyright 2000, 2010 Oracle and/or its affiliates. * * OpenOffice.org - a multi-platform office productivity suite * * This file is part of OpenOffice.org. * * OpenOffice.org is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 * only, as published by the Free Software Foundation. * * OpenOffice.org is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License version 3 for more details * (a copy is included in the LICENSE file that accompanied this code). * * You should have received a copy of the GNU Lesser General Public License * version 3 along with OpenOffice.org. If not, see * * for a copy of the LGPLv3 License. * ************************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_xmlsecurity.hxx" #include #include #include #include #include #include #include #include <../dialogs/resourcemanager.hxx> #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "comphelper/documentconstants.hxx" #include "com/sun/star/lang/IllegalArgumentException.hpp" #include using namespace ::com::sun::star; using namespace ::com::sun::star::uno; namespace css = ::com::sun::star; #define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) ) DocumentDigitalSignatures::DocumentDigitalSignatures( const Reference< XComponentContext >& rxCtx ): mxCtx(rxCtx), m_sODFVersion(ODFVER_012_TEXT), m_nArgumentsCount(0), m_bHasDocumentSignature(false) { } void DocumentDigitalSignatures::initialize( const Sequence< Any >& aArguments) throw (css::uno::Exception, css::uno::RuntimeException) { if (aArguments.getLength() == 0 || aArguments.getLength() > 2) throw css::lang::IllegalArgumentException( OUSTR("DocumentDigitalSignatures::initialize requires one or two arguments"), Reference(static_cast(this), UNO_QUERY), 0); m_nArgumentsCount = aArguments.getLength(); if (!(aArguments[0] >>= m_sODFVersion)) throw css::lang::IllegalArgumentException( OUSTR("DocumentDigitalSignatures::initialize: the first arguments must be a string"), Reference(static_cast(this), UNO_QUERY), 0); if (aArguments.getLength() == 2 && !(aArguments[1] >>= m_bHasDocumentSignature)) throw css::lang::IllegalArgumentException( OUSTR("DocumentDigitalSignatures::initialize: the second arguments must be a bool"), Reference(static_cast(this), UNO_QUERY), 1); //the Version is supported as of ODF1.2, so for and 1.1 document or older we will receive the //an empty string. In this case we set it to ODFVER_010_TEXT. Then we can later check easily //if initialize was called. Only then m_sODFVersion.getLength() is greater than 0 if (m_sODFVersion.getLength() == 0) m_sODFVersion = ODFVER_010_TEXT; } sal_Bool DocumentDigitalSignatures::signDocumentContent( const Reference< css::embed::XStorage >& rxStorage, const Reference< css::io::XStream >& xSignStream) throw (RuntimeException) { OSL_ENSURE(m_sODFVersion.getLength(), "DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2"); return ImplViewSignatures( rxStorage, xSignStream, SignatureModeDocumentContent, false ); } Sequence< css::security::DocumentSignatureInformation > DocumentDigitalSignatures::verifyDocumentContentSignatures( const Reference< css::embed::XStorage >& rxStorage, const Reference< css::io::XInputStream >& xSignInStream ) throw (RuntimeException) { OSL_ENSURE(m_sODFVersion.getLength(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2"); return ImplVerifySignatures( rxStorage, xSignInStream, SignatureModeDocumentContent ); } void DocumentDigitalSignatures::showDocumentContentSignatures( const Reference< css::embed::XStorage >& rxStorage, const Reference< css::io::XInputStream >& xSignInStream ) throw (RuntimeException) { OSL_ENSURE(m_sODFVersion.getLength(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2"); ImplViewSignatures( rxStorage, xSignInStream, SignatureModeDocumentContent, true ); } ::rtl::OUString DocumentDigitalSignatures::getDocumentContentSignatureDefaultStreamName() throw (css::uno::RuntimeException) { return DocumentSignatureHelper::GetDocumentContentSignatureDefaultStreamName(); } sal_Bool DocumentDigitalSignatures::signScriptingContent( const Reference< css::embed::XStorage >& rxStorage, const Reference< css::io::XStream >& xSignStream ) throw (RuntimeException) { OSL_ENSURE(m_sODFVersion.getLength(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2"); OSL_ENSURE(m_nArgumentsCount == 2, "DocumentDigitalSignatures: Service was not initialized properly"); return ImplViewSignatures( rxStorage, xSignStream, SignatureModeMacros, false ); } Sequence< css::security::DocumentSignatureInformation > DocumentDigitalSignatures::verifyScriptingContentSignatures( const Reference< css::embed::XStorage >& rxStorage, const Reference< css::io::XInputStream >& xSignInStream ) throw (RuntimeException) { OSL_ENSURE(m_sODFVersion.getLength(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2"); return ImplVerifySignatures( rxStorage, xSignInStream, SignatureModeMacros ); } void DocumentDigitalSignatures::showScriptingContentSignatures( const Reference< css::embed::XStorage >& rxStorage, const Reference< css::io::XInputStream >& xSignInStream ) throw (RuntimeException) { OSL_ENSURE(m_sODFVersion.getLength(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2"); ImplViewSignatures( rxStorage, xSignInStream, SignatureModeMacros, true ); } ::rtl::OUString DocumentDigitalSignatures::getScriptingContentSignatureDefaultStreamName() throw (css::uno::RuntimeException) { return DocumentSignatureHelper::GetScriptingContentSignatureDefaultStreamName(); } sal_Bool DocumentDigitalSignatures::signPackage( const Reference< css::embed::XStorage >& rxStorage, const Reference< css::io::XStream >& xSignStream ) throw (RuntimeException) { OSL_ENSURE(m_sODFVersion.getLength(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2"); return ImplViewSignatures( rxStorage, xSignStream, SignatureModePackage, false ); } Sequence< css::security::DocumentSignatureInformation > DocumentDigitalSignatures::verifyPackageSignatures( const Reference< css::embed::XStorage >& rxStorage, const Reference< css::io::XInputStream >& xSignInStream ) throw (RuntimeException) { OSL_ENSURE(m_sODFVersion.getLength(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2"); return ImplVerifySignatures( rxStorage, xSignInStream, SignatureModePackage ); } void DocumentDigitalSignatures::showPackageSignatures( const Reference< css::embed::XStorage >& rxStorage, const Reference< css::io::XInputStream >& xSignInStream ) throw (RuntimeException) { OSL_ENSURE(m_sODFVersion.getLength(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2"); ImplViewSignatures( rxStorage, xSignInStream, SignatureModePackage, true ); } ::rtl::OUString DocumentDigitalSignatures::getPackageSignatureDefaultStreamName( ) throw (::com::sun::star::uno::RuntimeException) { return DocumentSignatureHelper::GetPackageSignatureDefaultStreamName(); } sal_Bool DocumentDigitalSignatures::ImplViewSignatures( const Reference< css::embed::XStorage >& rxStorage, const Reference< css::io::XInputStream >& xSignStream, DocumentSignatureMode eMode, bool bReadOnly ) throw (RuntimeException) { Reference< io::XStream > xStream; if ( xSignStream.is() ) xStream = Reference< io::XStream >( xSignStream, UNO_QUERY ); return ImplViewSignatures( rxStorage, xStream, eMode, bReadOnly ); } sal_Bool DocumentDigitalSignatures::ImplViewSignatures( const Reference< css::embed::XStorage >& rxStorage, const Reference< css::io::XStream >& xSignStream, DocumentSignatureMode eMode, bool bReadOnly ) throw (RuntimeException) { sal_Bool bChanges = sal_False; DigitalSignaturesDialog aSignaturesDialog( NULL, mxCtx, eMode, bReadOnly, m_sODFVersion, m_bHasDocumentSignature); bool bInit = aSignaturesDialog.Init(); DBG_ASSERT( bInit, "Error initializing security context!" ); if ( bInit ) { aSignaturesDialog.SetStorage( rxStorage ); aSignaturesDialog.SetSignatureStream( xSignStream ); if ( aSignaturesDialog.Execute() ) { if ( aSignaturesDialog.SignaturesChanged() ) { bChanges = sal_True; // If we have a storage and no stream, we are responsible for commit if ( rxStorage.is() && !xSignStream.is() ) { uno::Reference< embed::XTransactedObject > xTrans( rxStorage, uno::UNO_QUERY ); xTrans->commit(); } } } } else { WarningBox aBox( NULL, XMLSEC_RES( RID_XMLSECWB_NO_MOZILLA_PROFILE ) ); aBox.Execute(); } return bChanges; } Sequence< css::security::DocumentSignatureInformation > DocumentDigitalSignatures::ImplVerifySignatures( const Reference< css::embed::XStorage >& rxStorage, const Reference< css::io::XInputStream >& xSignStream, DocumentSignatureMode eMode ) throw (RuntimeException) { if (!rxStorage.is()) { DBG_ASSERT(0, "Error, no XStorage provided"); return Sequence(); } // First check for the InputStream, to avoid unnecessary initialization of the security environemnt... SignatureStreamHelper aStreamHelper; Reference< io::XInputStream > xInputStream = xSignStream; if ( !xInputStream.is() ) { aStreamHelper = DocumentSignatureHelper::OpenSignatureStream( rxStorage, embed::ElementModes::READ, eMode ); if ( aStreamHelper.xSignatureStream.is() ) xInputStream = Reference< io::XInputStream >( aStreamHelper.xSignatureStream, UNO_QUERY ); } if ( !xInputStream.is() ) return Sequence< ::com::sun::star::security::DocumentSignatureInformation >(0); XMLSignatureHelper aSignatureHelper( mxCtx ); bool bInit = aSignatureHelper.Init(); DBG_ASSERT( bInit, "Error initializing security context!" ); if ( !bInit ) return Sequence< ::com::sun::star::security::DocumentSignatureInformation >(0); aSignatureHelper.SetStorage(rxStorage, m_sODFVersion); aSignatureHelper.StartMission(); aSignatureHelper.ReadAndVerifySignature( xInputStream ); aSignatureHelper.EndMission(); Reference< ::com::sun::star::xml::crypto::XSecurityEnvironment > xSecEnv = aSignatureHelper.GetSecurityEnvironment(); SignatureInformations aSignInfos = aSignatureHelper.GetSignatureInformations(); int nInfos = aSignInfos.size(); Sequence< css::security::DocumentSignatureInformation > aInfos(nInfos); css::security::DocumentSignatureInformation* arInfos = aInfos.getArray(); if ( nInfos ) { Reference xSerialNumberAdapter = ::com::sun::star::security::SerialNumberAdapter::create(mxCtx); for( int n = 0; n < nInfos; ++n ) { DocumentSignatureAlgorithm mode = DocumentSignatureHelper::getDocumentAlgorithm( m_sODFVersion, aSignInfos[n]); const std::vector< rtl::OUString > aElementsToBeVerified = DocumentSignatureHelper::CreateElementList( rxStorage, ::rtl::OUString(), eMode, mode); const SignatureInformation& rInfo = aSignInfos[n]; css::security::DocumentSignatureInformation& rSigInfo = arInfos[n]; if (rInfo.ouX509Certificate.getLength()) rSigInfo.Signer = xSecEnv->createCertificateFromAscii( rInfo.ouX509Certificate ) ; if (!rSigInfo.Signer.is()) rSigInfo.Signer = xSecEnv->getCertificate( rInfo.ouX509IssuerName, xSerialNumberAdapter->toSequence( rInfo.ouX509SerialNumber ) ); // --> PB 2004-12-14 #i38744# time support again Date aDate( rInfo.stDateTime.Day, rInfo.stDateTime.Month, rInfo.stDateTime.Year ); Time aTime( rInfo.stDateTime.Hours, rInfo.stDateTime.Minutes, rInfo.stDateTime.Seconds, rInfo.stDateTime.HundredthSeconds ); rSigInfo.SignatureDate = aDate.GetDate(); rSigInfo.SignatureTime = aTime.GetTime(); // Verify certificate //We have patched our version of libxmlsec, so that it does not verify the certificates. This has two //reasons. First we want two separate status for signature and certificate. Second libxmlsec calls //CERT_VerifyCertificate (solaris, linux) falsly, so that it always regards the certificate as valid. //On Window the checking of the certificate path is buggy. It does name matching (issuer, subject name) //to find the parent certificate. It does not take into account that there can be several certificates //with the same subject name. if (rSigInfo.Signer.is()) { try { rSigInfo.CertificateStatus = xSecEnv->verifyCertificate(rSigInfo.Signer, Sequence >()); } catch (SecurityException& ) { OSL_ENSURE(0, "Verification of certificate failed"); rSigInfo.CertificateStatus = css::security::CertificateValidity::INVALID; } } else { //We should always be aible to get the certificates because it is contained in the document, //unless the document is damaged so that signature xml file could not be parsed. rSigInfo.CertificateStatus = css::security::CertificateValidity::INVALID; } rSigInfo.SignatureIsValid = ( rInfo.nStatus == ::com::sun::star::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED ); if ( rSigInfo.SignatureIsValid ) { rSigInfo.SignatureIsValid = DocumentSignatureHelper::checkIfAllFilesAreSigned( aElementsToBeVerified, rInfo, mode); } if (eMode == SignatureModeDocumentContent) rSigInfo.PartialDocumentSignature = ! DocumentSignatureHelper::isOOo3_2_Signature(aSignInfos[n]); } } return aInfos; } void DocumentDigitalSignatures::manageTrustedSources( ) throw (RuntimeException) { // MT: i45295 // SecEnv is only needed to display certificate information from trusted sources. // Macro Security also has some options where no security environment is needed, so raise dialog anyway. // Later I should change the code so the Dialog creates the SecEnv on demand... Reference< dcss::xml::crypto::XSecurityEnvironment > xSecEnv; XMLSignatureHelper aSignatureHelper( mxCtx ); if ( aSignatureHelper.Init() ) xSecEnv = aSignatureHelper.GetSecurityEnvironment(); MacroSecurity aDlg( NULL, mxCtx, xSecEnv ); aDlg.Execute(); } void DocumentDigitalSignatures::showCertificate( const Reference< css::security::XCertificate >& _Certificate ) throw (RuntimeException) { XMLSignatureHelper aSignatureHelper( mxCtx ); bool bInit = aSignatureHelper.Init(); DBG_ASSERT( bInit, "Error initializing security context!" ); if ( bInit ) { CertificateViewer aViewer( NULL, aSignatureHelper.GetSecurityEnvironment(), _Certificate, sal_False ); aViewer.Execute(); } } ::sal_Bool DocumentDigitalSignatures::isAuthorTrusted( const Reference< css::security::XCertificate >& Author ) throw (RuntimeException) { sal_Bool bFound = sal_False; Reference xSerialNumberAdapter = ::com::sun::star::security::SerialNumberAdapter::create(mxCtx); ::rtl::OUString sSerialNum = xSerialNumberAdapter->toString( Author->getSerialNumber() ); Sequence< SvtSecurityOptions::Certificate > aTrustedAuthors = SvtSecurityOptions().GetTrustedAuthors(); const SvtSecurityOptions::Certificate* pAuthors = aTrustedAuthors.getConstArray(); const SvtSecurityOptions::Certificate* pAuthorsEnd = pAuthors + aTrustedAuthors.getLength(); for ( ; pAuthors != pAuthorsEnd; ++pAuthors ) { SvtSecurityOptions::Certificate aAuthor = *pAuthors; if ( ( aAuthor[0] == Author->getIssuerName() ) && ( aAuthor[1] == sSerialNum ) ) { bFound = sal_True; break; } } return bFound; } ::sal_Bool DocumentDigitalSignatures::isLocationTrusted( const ::rtl::OUString& Location ) throw (RuntimeException) { sal_Bool bFound = sal_False; INetURLObject aLocObj( Location ); INetURLObject aLocObjLowCase( Location.toAsciiLowerCase() ); // will be used for case insensitive comparing ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XContentProvider > xContentProvider; ::ucbhelper::ContentBroker* pBroker = NULL; //warning free code //if ( aLocObj.GetProtocol() == INET_PROT_FILE && ( pBroker = ::ucbhelper::ContentBroker::get() ) ) // xContentProvider = pBroker->getContentProviderInterface(); if ( aLocObj.GetProtocol() == INET_PROT_FILE) { pBroker = ::ucbhelper::ContentBroker::get(); if (pBroker) xContentProvider = pBroker->getContentProviderInterface(); } Sequence< ::rtl::OUString > aSecURLs = SvtSecurityOptions().GetSecureURLs(); const ::rtl::OUString* pSecURLs = aSecURLs.getConstArray(); const ::rtl::OUString* pSecURLsEnd = pSecURLs + aSecURLs.getLength(); for ( ; pSecURLs != pSecURLsEnd && !bFound; ++pSecURLs ) bFound = ::utl::UCBContentHelper::IsSubPath( *pSecURLs, Location, xContentProvider ); return bFound; } void DocumentDigitalSignatures::addAuthorToTrustedSources( const Reference< css::security::XCertificate >& Author ) throw (RuntimeException) { SvtSecurityOptions aSecOpts; Reference xSerialNumberAdapter = ::com::sun::star::security::SerialNumberAdapter::create(mxCtx); SvtSecurityOptions::Certificate aNewCert( 3 ); aNewCert[ 0 ] = Author->getIssuerName(); aNewCert[ 1 ] = xSerialNumberAdapter->toString( Author->getSerialNumber() ); rtl::OUStringBuffer aStrBuffer; SvXMLUnitConverter::encodeBase64(aStrBuffer, Author->getEncoded()); aNewCert[ 2 ] = aStrBuffer.makeStringAndClear(); Sequence< SvtSecurityOptions::Certificate > aTrustedAuthors = aSecOpts.GetTrustedAuthors(); sal_Int32 nCnt = aTrustedAuthors.getLength(); aTrustedAuthors.realloc( nCnt + 1 ); aTrustedAuthors[ nCnt ] = aNewCert; aSecOpts.SetTrustedAuthors( aTrustedAuthors ); } void DocumentDigitalSignatures::addLocationToTrustedSources( const ::rtl::OUString& Location ) throw (RuntimeException) { SvtSecurityOptions aSecOpt; Sequence< ::rtl::OUString > aSecURLs = aSecOpt.GetSecureURLs(); sal_Int32 nCnt = aSecURLs.getLength(); aSecURLs.realloc( nCnt + 1 ); aSecURLs[ nCnt ] = Location; aSecOpt.SetSecureURLs( aSecURLs ); } rtl::OUString DocumentDigitalSignatures::GetImplementationName() throw (RuntimeException) { return rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.security.DocumentDigitalSignatures" ) ); } Sequence< rtl::OUString > DocumentDigitalSignatures::GetSupportedServiceNames() throw (cssu::RuntimeException) { Sequence < rtl::OUString > aRet(1); rtl::OUString* pArray = aRet.getArray(); pArray[0] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.security.DocumentDigitalSignatures" ) ); return aRet; } Reference< XInterface > DocumentDigitalSignatures_CreateInstance( const Reference< XComponentContext >& rCtx) throw ( Exception ) { return (cppu::OWeakObject*) new DocumentDigitalSignatures( rCtx ); }