1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 26 #include "precompiled_xmlsecurity.hxx" 27 28 #include <documentdigitalsignatures.hxx> 29 #include <xmlsecurity/digitalsignaturesdialog.hxx> 30 #include <xmlsecurity/certificateviewer.hxx> 31 #include <xmlsecurity/macrosecurity.hxx> 32 #include <xmlsecurity/biginteger.hxx> 33 #include <xmlsecurity/global.hrc> 34 35 #include <xmloff/xmluconv.hxx> 36 37 #include <../dialogs/resourcemanager.hxx> 38 #include <com/sun/star/embed/XStorage.hpp> 39 #include <com/sun/star/embed/XTransactedObject.hpp> 40 #include <com/sun/star/embed/ElementModes.hpp> 41 #include <com/sun/star/ucb/XContent.hpp> 42 #include <com/sun/star/ucb/XContentProvider.hpp> 43 #include <com/sun/star/ucb/XContentIdentifierFactory.hpp> 44 #include <com/sun/star/ucb/XCommandEnvironment.hpp> 45 #include <com/sun/star/ucb/XCommandProcessor.hpp> 46 #include <com/sun/star/ucb/Command.hpp> 47 #include <tools/urlobj.hxx> 48 #include <vcl/msgbox.hxx> 49 #include <unotools/securityoptions.hxx> 50 #include <com/sun/star/security/CertificateValidity.hpp> 51 #include <com/sun/star/security/SerialNumberAdapter.hpp> 52 #include <ucbhelper/contentbroker.hxx> 53 #include <unotools/ucbhelper.hxx> 54 #include <comphelper/componentcontext.hxx> 55 #include "comphelper/documentconstants.hxx" 56 57 #include "com/sun/star/lang/IllegalArgumentException.hpp" 58 59 #include <stdio.h> 60 61 62 using namespace ::com::sun::star; 63 using namespace ::com::sun::star::uno; 64 namespace css = ::com::sun::star; 65 66 #define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) ) 67 68 DocumentDigitalSignatures::DocumentDigitalSignatures( const Reference< XComponentContext >& rxCtx ): 69 mxCtx(rxCtx), 70 m_sODFVersion(ODFVER_012_TEXT), 71 m_nArgumentsCount(0), 72 m_bHasDocumentSignature(false) 73 { 74 } 75 76 void DocumentDigitalSignatures::initialize( const Sequence< Any >& aArguments) 77 { 78 if (aArguments.getLength() == 0 || aArguments.getLength() > 2) 79 throw css::lang::IllegalArgumentException( 80 OUSTR("DocumentDigitalSignatures::initialize requires one or two arguments"), 81 Reference<XInterface>(static_cast<XInitialization*>(this), UNO_QUERY), 0); 82 83 m_nArgumentsCount = aArguments.getLength(); 84 85 if (!(aArguments[0] >>= m_sODFVersion)) 86 throw css::lang::IllegalArgumentException( 87 OUSTR("DocumentDigitalSignatures::initialize: the first arguments must be a string"), 88 Reference<XInterface>(static_cast<XInitialization*>(this), UNO_QUERY), 0); 89 90 if (aArguments.getLength() == 2 91 && !(aArguments[1] >>= m_bHasDocumentSignature)) 92 throw css::lang::IllegalArgumentException( 93 OUSTR("DocumentDigitalSignatures::initialize: the second arguments must be a bool"), 94 Reference<XInterface>(static_cast<XInitialization*>(this), UNO_QUERY), 1); 95 96 //the Version is supported as of ODF1.2, so for and 1.1 document or older we will receive the 97 //an empty string. In this case we set it to ODFVER_010_TEXT. Then we can later check easily 98 //if initialize was called. Only then m_sODFVersion.getLength() is greater than 0 99 if (m_sODFVersion.getLength() == 0) 100 m_sODFVersion = ODFVER_010_TEXT; 101 } 102 103 sal_Bool DocumentDigitalSignatures::signDocumentContent( 104 const Reference< css::embed::XStorage >& rxStorage, 105 const Reference< css::io::XStream >& xSignStream) 106 { 107 OSL_ENSURE(m_sODFVersion.getLength(), "DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2"); 108 return ImplViewSignatures( rxStorage, xSignStream, SignatureModeDocumentContent, false ); 109 } 110 111 Sequence< css::security::DocumentSignatureInformation > 112 DocumentDigitalSignatures::verifyDocumentContentSignatures( 113 const Reference< css::embed::XStorage >& rxStorage, 114 const Reference< css::io::XInputStream >& xSignInStream ) 115 { 116 OSL_ENSURE(m_sODFVersion.getLength(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2"); 117 return ImplVerifySignatures( rxStorage, xSignInStream, SignatureModeDocumentContent ); 118 } 119 120 void DocumentDigitalSignatures::showDocumentContentSignatures( 121 const Reference< css::embed::XStorage >& rxStorage, 122 const Reference< css::io::XInputStream >& xSignInStream ) 123 { 124 OSL_ENSURE(m_sODFVersion.getLength(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2"); 125 ImplViewSignatures( rxStorage, xSignInStream, SignatureModeDocumentContent, true ); 126 } 127 128 ::rtl::OUString DocumentDigitalSignatures::getDocumentContentSignatureDefaultStreamName() 129 { 130 return DocumentSignatureHelper::GetDocumentContentSignatureDefaultStreamName(); 131 } 132 133 sal_Bool DocumentDigitalSignatures::signScriptingContent( 134 const Reference< css::embed::XStorage >& rxStorage, 135 const Reference< css::io::XStream >& xSignStream ) 136 { 137 OSL_ENSURE(m_sODFVersion.getLength(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2"); 138 OSL_ENSURE(m_nArgumentsCount == 2, "DocumentDigitalSignatures: Service was not initialized properly"); 139 return ImplViewSignatures( rxStorage, xSignStream, SignatureModeMacros, false ); 140 } 141 142 Sequence< css::security::DocumentSignatureInformation > 143 DocumentDigitalSignatures::verifyScriptingContentSignatures( 144 const Reference< css::embed::XStorage >& rxStorage, 145 const Reference< css::io::XInputStream >& xSignInStream ) 146 { 147 OSL_ENSURE(m_sODFVersion.getLength(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2"); 148 return ImplVerifySignatures( rxStorage, xSignInStream, SignatureModeMacros ); 149 } 150 151 void DocumentDigitalSignatures::showScriptingContentSignatures( 152 const Reference< css::embed::XStorage >& rxStorage, 153 const Reference< css::io::XInputStream >& xSignInStream ) 154 { 155 OSL_ENSURE(m_sODFVersion.getLength(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2"); 156 ImplViewSignatures( rxStorage, xSignInStream, SignatureModeMacros, true ); 157 } 158 159 ::rtl::OUString DocumentDigitalSignatures::getScriptingContentSignatureDefaultStreamName() 160 { 161 return DocumentSignatureHelper::GetScriptingContentSignatureDefaultStreamName(); 162 } 163 164 165 sal_Bool DocumentDigitalSignatures::signPackage( 166 const Reference< css::embed::XStorage >& rxStorage, 167 const Reference< css::io::XStream >& xSignStream ) 168 { 169 OSL_ENSURE(m_sODFVersion.getLength(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2"); 170 return ImplViewSignatures( rxStorage, xSignStream, SignatureModePackage, false ); 171 } 172 173 Sequence< css::security::DocumentSignatureInformation > 174 DocumentDigitalSignatures::verifyPackageSignatures( 175 const Reference< css::embed::XStorage >& rxStorage, 176 const Reference< css::io::XInputStream >& xSignInStream ) 177 { 178 OSL_ENSURE(m_sODFVersion.getLength(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2"); 179 return ImplVerifySignatures( rxStorage, xSignInStream, SignatureModePackage ); 180 } 181 182 void DocumentDigitalSignatures::showPackageSignatures( 183 const Reference< css::embed::XStorage >& rxStorage, 184 const Reference< css::io::XInputStream >& xSignInStream ) 185 { 186 OSL_ENSURE(m_sODFVersion.getLength(),"DocumentDigitalSignatures: ODF Version not set, assuming minimum 1.2"); 187 ImplViewSignatures( rxStorage, xSignInStream, SignatureModePackage, true ); 188 } 189 190 ::rtl::OUString DocumentDigitalSignatures::getPackageSignatureDefaultStreamName( ) 191 { 192 return DocumentSignatureHelper::GetPackageSignatureDefaultStreamName(); 193 } 194 195 196 sal_Bool DocumentDigitalSignatures::ImplViewSignatures( 197 const Reference< css::embed::XStorage >& rxStorage, 198 const Reference< css::io::XInputStream >& xSignStream, 199 DocumentSignatureMode eMode, bool bReadOnly ) 200 { 201 Reference< io::XStream > xStream; 202 if ( xSignStream.is() ) 203 xStream = Reference< io::XStream >( xSignStream, UNO_QUERY ); 204 return ImplViewSignatures( rxStorage, xStream, eMode, bReadOnly ); 205 } 206 207 sal_Bool DocumentDigitalSignatures::ImplViewSignatures( 208 const Reference< css::embed::XStorage >& rxStorage, const Reference< css::io::XStream >& xSignStream, 209 DocumentSignatureMode eMode, bool bReadOnly ) 210 { 211 sal_Bool bChanges = sal_False; 212 DigitalSignaturesDialog aSignaturesDialog( 213 NULL, mxCtx, eMode, bReadOnly, m_sODFVersion, m_bHasDocumentSignature); 214 bool bInit = aSignaturesDialog.Init(); 215 DBG_ASSERT( bInit, "Error initializing security context!" ); 216 if ( bInit ) 217 { 218 aSignaturesDialog.SetStorage( rxStorage ); 219 aSignaturesDialog.SetSignatureStream( xSignStream ); 220 if ( aSignaturesDialog.Execute() ) 221 { 222 if ( aSignaturesDialog.SignaturesChanged() ) 223 { 224 bChanges = sal_True; 225 // If we have a storage and no stream, we are responsible for commit 226 if ( rxStorage.is() && !xSignStream.is() ) 227 { 228 uno::Reference< embed::XTransactedObject > xTrans( rxStorage, uno::UNO_QUERY ); 229 xTrans->commit(); 230 } 231 } 232 } 233 } 234 else 235 { 236 WarningBox aBox( NULL, XMLSEC_RES( RID_XMLSECWB_NO_MOZILLA_PROFILE ) ); 237 aBox.Execute(); 238 } 239 240 return bChanges; 241 } 242 243 Sequence< css::security::DocumentSignatureInformation > 244 DocumentDigitalSignatures::ImplVerifySignatures( 245 const Reference< css::embed::XStorage >& rxStorage, 246 const Reference< css::io::XInputStream >& xSignStream, DocumentSignatureMode eMode ) 247 { 248 if (!rxStorage.is()) 249 { 250 DBG_ASSERT(0, "Error, no XStorage provided"); 251 return Sequence<css::security::DocumentSignatureInformation>(); 252 } 253 // First check for the InputStream, to avoid unnecessary initialization of the security environemnt... 254 SignatureStreamHelper aStreamHelper; 255 Reference< io::XInputStream > xInputStream = xSignStream; 256 257 if ( !xInputStream.is() ) 258 { 259 aStreamHelper = DocumentSignatureHelper::OpenSignatureStream( rxStorage, embed::ElementModes::READ, eMode ); 260 if ( aStreamHelper.xSignatureStream.is() ) 261 xInputStream = Reference< io::XInputStream >( aStreamHelper.xSignatureStream, UNO_QUERY ); 262 } 263 264 if ( !xInputStream.is() ) 265 return Sequence< ::com::sun::star::security::DocumentSignatureInformation >(0); 266 267 268 XMLSignatureHelper aSignatureHelper( mxCtx ); 269 270 bool bInit = aSignatureHelper.Init(); 271 272 DBG_ASSERT( bInit, "Error initializing security context!" ); 273 274 if ( !bInit ) 275 return Sequence< ::com::sun::star::security::DocumentSignatureInformation >(0); 276 277 aSignatureHelper.SetStorage(rxStorage, m_sODFVersion); 278 279 aSignatureHelper.StartMission(); 280 281 aSignatureHelper.ReadAndVerifySignature( xInputStream ); 282 283 aSignatureHelper.EndMission(); 284 285 Reference< ::com::sun::star::xml::crypto::XSecurityEnvironment > xSecEnv = aSignatureHelper.GetSecurityEnvironment(); 286 287 SignatureInformations aSignInfos = aSignatureHelper.GetSignatureInformations(); 288 int nInfos = aSignInfos.size(); 289 Sequence< css::security::DocumentSignatureInformation > aInfos(nInfos); 290 css::security::DocumentSignatureInformation* arInfos = aInfos.getArray(); 291 292 if ( nInfos ) 293 { 294 Reference<security::XSerialNumberAdapter> xSerialNumberAdapter = 295 ::com::sun::star::security::SerialNumberAdapter::create(mxCtx); 296 297 for( int n = 0; n < nInfos; ++n ) 298 { 299 DocumentSignatureAlgorithm mode = DocumentSignatureHelper::getDocumentAlgorithm( 300 m_sODFVersion, aSignInfos[n]); 301 const std::vector< rtl::OUString > aElementsToBeVerified = 302 DocumentSignatureHelper::CreateElementList( 303 rxStorage, ::rtl::OUString(), eMode, mode); 304 305 const SignatureInformation& rInfo = aSignInfos[n]; 306 css::security::DocumentSignatureInformation& rSigInfo = arInfos[n]; 307 308 if (rInfo.ouX509Certificate.getLength()) 309 rSigInfo.Signer = xSecEnv->createCertificateFromAscii( rInfo.ouX509Certificate ) ; 310 if (!rSigInfo.Signer.is()) 311 rSigInfo.Signer = xSecEnv->getCertificate( rInfo.ouX509IssuerName, xSerialNumberAdapter->toSequence( rInfo.ouX509SerialNumber ) ); 312 313 // --> PB 2004-12-14 #i38744# time support again 314 Date aDate( rInfo.stDateTime.Day, rInfo.stDateTime.Month, rInfo.stDateTime.Year ); 315 Time aTime( rInfo.stDateTime.Hours, rInfo.stDateTime.Minutes, 316 rInfo.stDateTime.Seconds, rInfo.stDateTime.HundredthSeconds ); 317 rSigInfo.SignatureDate = aDate.GetDate(); 318 rSigInfo.SignatureTime = aTime.GetTime(); 319 320 // Verify certificate 321 //We have patched our version of libxmlsec, so that it does not verify the certificates. This has two 322 //reasons. First we want two separate status for signature and certificate. Second libxmlsec calls 323 //CERT_VerifyCertificate (solaris, linux) falsely, so that it always regards the certificate as valid. 324 //On Window the checking of the certificate path is buggy. It does name matching (issuer, subject name) 325 //to find the parent certificate. It does not take into account that there can be several certificates 326 //with the same subject name. 327 if (rSigInfo.Signer.is()) 328 { 329 try { 330 rSigInfo.CertificateStatus = xSecEnv->verifyCertificate(rSigInfo.Signer, 331 Sequence<Reference<css::security::XCertificate> >()); 332 } catch (SecurityException& ) { 333 OSL_ENSURE(0, "Verification of certificate failed"); 334 rSigInfo.CertificateStatus = css::security::CertificateValidity::INVALID; 335 } 336 } 337 else 338 { 339 //We should always be able to get the certificates because it is contained in the document, 340 //unless the document is damaged so that signature xml file could not be parsed. 341 rSigInfo.CertificateStatus = css::security::CertificateValidity::INVALID; 342 } 343 344 rSigInfo.SignatureIsValid = ( rInfo.nStatus == ::com::sun::star::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED ); 345 346 347 if ( rSigInfo.SignatureIsValid ) 348 { 349 rSigInfo.SignatureIsValid = 350 DocumentSignatureHelper::checkIfAllFilesAreSigned( 351 aElementsToBeVerified, rInfo, mode); 352 } 353 if (eMode == SignatureModeDocumentContent) 354 rSigInfo.PartialDocumentSignature = 355 ! DocumentSignatureHelper::isOOo3_2_Signature(aSignInfos[n]); 356 357 } 358 } 359 return aInfos; 360 361 } 362 363 void DocumentDigitalSignatures::manageTrustedSources( ) 364 { 365 // MT: i45295 366 // SecEnv is only needed to display certificate information from trusted sources. 367 // Macro Security also has some options where no security environment is needed, so raise dialog anyway. 368 // Later I should change the code so the Dialog creates the SecEnv on demand... 369 370 Reference< dcss::xml::crypto::XSecurityEnvironment > xSecEnv; 371 372 XMLSignatureHelper aSignatureHelper( mxCtx ); 373 if ( aSignatureHelper.Init() ) 374 xSecEnv = aSignatureHelper.GetSecurityEnvironment(); 375 376 MacroSecurity aDlg( NULL, mxCtx, xSecEnv ); 377 aDlg.Execute(); 378 } 379 380 void DocumentDigitalSignatures::showCertificate( 381 const Reference< css::security::XCertificate >& _Certificate ) 382 { 383 XMLSignatureHelper aSignatureHelper( mxCtx ); 384 385 bool bInit = aSignatureHelper.Init(); 386 387 DBG_ASSERT( bInit, "Error initializing security context!" ); 388 389 if ( bInit ) 390 { 391 CertificateViewer aViewer( NULL, aSignatureHelper.GetSecurityEnvironment(), _Certificate, sal_False ); 392 aViewer.Execute(); 393 } 394 395 } 396 397 ::sal_Bool DocumentDigitalSignatures::isAuthorTrusted( 398 const Reference< css::security::XCertificate >& Author ) 399 { 400 sal_Bool bFound = sal_False; 401 402 Reference<security::XSerialNumberAdapter> xSerialNumberAdapter = 403 ::com::sun::star::security::SerialNumberAdapter::create(mxCtx); 404 405 ::rtl::OUString sSerialNum = xSerialNumberAdapter->toString( Author->getSerialNumber() ); 406 407 Sequence< SvtSecurityOptions::Certificate > aTrustedAuthors = SvtSecurityOptions().GetTrustedAuthors(); 408 const SvtSecurityOptions::Certificate* pAuthors = aTrustedAuthors.getConstArray(); 409 const SvtSecurityOptions::Certificate* pAuthorsEnd = pAuthors + aTrustedAuthors.getLength(); 410 for ( ; pAuthors != pAuthorsEnd; ++pAuthors ) 411 { 412 SvtSecurityOptions::Certificate aAuthor = *pAuthors; 413 if ( ( aAuthor[0] == Author->getIssuerName() ) && ( aAuthor[1] == sSerialNum ) ) 414 { 415 bFound = sal_True; 416 break; 417 } 418 } 419 420 return bFound; 421 } 422 423 ::sal_Bool DocumentDigitalSignatures::isLocationTrusted( const ::rtl::OUString& Location ) 424 { 425 sal_Bool bFound = sal_False; 426 INetURLObject aLocObj( Location ); 427 INetURLObject aLocObjLowCase( Location.toAsciiLowerCase() ); // will be used for case insensitive comparing 428 429 ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XContentProvider > xContentProvider; 430 ::ucbhelper::ContentBroker* pBroker = NULL; 431 432 //warning free code 433 //if ( aLocObj.GetProtocol() == INET_PROT_FILE && ( pBroker = ::ucbhelper::ContentBroker::get() ) ) 434 // xContentProvider = pBroker->getContentProviderInterface(); 435 if ( aLocObj.GetProtocol() == INET_PROT_FILE) 436 { 437 pBroker = ::ucbhelper::ContentBroker::get(); 438 if (pBroker) 439 xContentProvider = pBroker->getContentProviderInterface(); 440 } 441 442 Sequence< ::rtl::OUString > aSecURLs = SvtSecurityOptions().GetSecureURLs(); 443 const ::rtl::OUString* pSecURLs = aSecURLs.getConstArray(); 444 const ::rtl::OUString* pSecURLsEnd = pSecURLs + aSecURLs.getLength(); 445 for ( ; pSecURLs != pSecURLsEnd && !bFound; ++pSecURLs ) 446 bFound = ::utl::UCBContentHelper::IsSubPath( *pSecURLs, Location, xContentProvider ); 447 448 return bFound; 449 } 450 451 void DocumentDigitalSignatures::addAuthorToTrustedSources( 452 const Reference< css::security::XCertificate >& Author ) 453 { 454 SvtSecurityOptions aSecOpts; 455 456 Reference<security::XSerialNumberAdapter> xSerialNumberAdapter = 457 ::com::sun::star::security::SerialNumberAdapter::create(mxCtx); 458 459 SvtSecurityOptions::Certificate aNewCert( 3 ); 460 aNewCert[ 0 ] = Author->getIssuerName(); 461 aNewCert[ 1 ] = xSerialNumberAdapter->toString( Author->getSerialNumber() ); 462 463 rtl::OUStringBuffer aStrBuffer; 464 SvXMLUnitConverter::encodeBase64(aStrBuffer, Author->getEncoded()); 465 aNewCert[ 2 ] = aStrBuffer.makeStringAndClear(); 466 467 468 Sequence< SvtSecurityOptions::Certificate > aTrustedAuthors = aSecOpts.GetTrustedAuthors(); 469 sal_Int32 nCnt = aTrustedAuthors.getLength(); 470 aTrustedAuthors.realloc( nCnt + 1 ); 471 aTrustedAuthors[ nCnt ] = aNewCert; 472 473 aSecOpts.SetTrustedAuthors( aTrustedAuthors ); 474 } 475 476 void DocumentDigitalSignatures::addLocationToTrustedSources( const ::rtl::OUString& Location ) 477 { 478 SvtSecurityOptions aSecOpt; 479 480 Sequence< ::rtl::OUString > aSecURLs = aSecOpt.GetSecureURLs(); 481 sal_Int32 nCnt = aSecURLs.getLength(); 482 aSecURLs.realloc( nCnt + 1 ); 483 aSecURLs[ nCnt ] = Location; 484 485 aSecOpt.SetSecureURLs( aSecURLs ); 486 } 487 488 rtl::OUString DocumentDigitalSignatures::GetImplementationName() 489 { 490 return rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.security.DocumentDigitalSignatures" ) ); 491 } 492 493 Sequence< rtl::OUString > DocumentDigitalSignatures::GetSupportedServiceNames() 494 { 495 Sequence < rtl::OUString > aRet(1); 496 rtl::OUString* pArray = aRet.getArray(); 497 pArray[0] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.security.DocumentDigitalSignatures" ) ); 498 return aRet; 499 } 500 501 502 Reference< XInterface > DocumentDigitalSignatures_CreateInstance( 503 const Reference< XComponentContext >& rCtx) 504 { 505 return (cppu::OWeakObject*) new DocumentDigitalSignatures( rCtx ); 506 } 507