1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 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/. 8 * 9 * This file incorporates work covered by the following license notice: 10 * 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 . 18 */ 19 20 #include <digitalsignaturesdialog.hxx> 21 #include <certificatechooser.hxx> 22 #include <certificateviewer.hxx> 23 #include <biginteger.hxx> 24 #include <sax/tools/converter.hxx> 25 26 #include <com/sun/star/embed/XStorage.hpp> 27 #include <com/sun/star/embed/ElementModes.hpp> 28 #include <com/sun/star/embed/StorageFormats.hpp> 29 #include <com/sun/star/container/XNameAccess.hpp> 30 #include <com/sun/star/lang/XComponent.hpp> 31 #include <com/sun/star/security/NoPasswordException.hpp> 32 #include <com/sun/star/lang/DisposedException.hpp> 33 #include <com/sun/star/beans/XPropertySet.hpp> 34 #include <com/sun/star/security/CertificateValidity.hpp> 35 #include <com/sun/star/packages/WrongPasswordException.hpp> 36 #include <com/sun/star/security/CertificateKind.hpp> 37 #include <com/sun/star/security/XDocumentDigitalSignatures.hpp> 38 #include <com/sun/star/xml/dom/XDocumentBuilder.hpp> 39 #include <com/sun/star/packages/manifest/ManifestReader.hpp> 40 #include <com/sun/star/system/SystemShellExecute.hpp> 41 #include <com/sun/star/system/SystemShellExecuteFlags.hpp> 42 #include <com/sun/star/system/SystemShellExecuteException.hpp> 43 44 #include <osl/file.hxx> 45 #include <rtl/ustrbuf.hxx> 46 #include <rtl/uri.hxx> 47 #include <sal/log.hxx> 48 49 #include <tools/date.hxx> 50 #include <tools/time.hxx> 51 #include <svtools/treelistentry.hxx> 52 53 #include <strings.hrc> 54 #include <resourcemanager.hxx> 55 56 #include <vcl/weld.hxx> 57 #include <unotools/configitem.hxx> 58 59 using namespace css::security; 60 using namespace css::uno; 61 using namespace css; 62 63 namespace 64 { 65 class SaveODFItem: public utl::ConfigItem 66 { 67 private: 68 sal_Int16 m_nODF; 69 70 virtual void ImplCommit() override; 71 72 public: 73 virtual void Notify( const css::uno::Sequence< OUString >& aPropertyNames ) override; 74 SaveODFItem(); 75 //See group ODF in Common.xcs 76 bool isLessODF1_2() 77 { 78 return m_nODF < 3; 79 } 80 }; 81 82 void SaveODFItem::ImplCommit() {} 83 void SaveODFItem::Notify( const css::uno::Sequence< OUString >& ) {} 84 85 SaveODFItem::SaveODFItem(): utl::ConfigItem("Office.Common/Save"), m_nODF(0) 86 { 87 OUString sDef("ODF/DefaultVersion"); 88 Sequence< css::uno::Any > aValues = GetProperties( Sequence<OUString>(&sDef,1) ); 89 if ( aValues.getLength() != 1) 90 throw uno::RuntimeException( 91 "[xmlsecurity] Could not open property Office.Common/Save/ODF/DefaultVersion", 92 nullptr); 93 94 sal_Int16 nTmp = 0; 95 if ( !(aValues[0] >>= nTmp) ) 96 throw uno::RuntimeException( 97 "[xmlsecurity]SaveODFItem::SaveODFItem(): Wrong Type!", 98 nullptr ); 99 100 m_nODF = nTmp; 101 } 102 } 103 104 DigitalSignaturesDialog::DigitalSignaturesDialog( 105 vcl::Window* pParent, 106 uno::Reference< uno::XComponentContext >& rxCtx, DocumentSignatureMode eMode, 107 bool bReadOnly, const OUString& sODFVersion, bool bHasDocumentSignature) 108 : ModalDialog(pParent, "DigitalSignaturesDialog", "xmlsec/ui/digitalsignaturesdialog.ui") 109 , mxCtx(rxCtx) 110 , maSignatureManager(rxCtx, eMode) 111 , m_sODFVersion (sODFVersion) 112 , m_bHasDocumentSignature(bHasDocumentSignature) 113 , m_bWarningShowSignMacro(false) 114 { 115 get(m_pHintDocFT, "dochint"); 116 get(m_pHintBasicFT, "macrohint"); 117 get(m_pHintPackageFT, "packagehint"); 118 get(m_pAdESCompliantCB, "adescompliant"); 119 get(m_pViewBtn, "view"); 120 get(m_pAddBtn, "sign"); 121 get(m_pRemoveBtn, "remove"); 122 get(m_pCloseBtn, "close"); 123 get(m_pStartCertMgrBtn, "start_certmanager"); 124 get(m_pSigsValidImg, "validimg"); 125 get(m_pSigsValidFI, "validft"); 126 get(m_pSigsInvalidImg, "invalidimg"); 127 get(m_pSigsInvalidFI, "invalidft"); 128 get(m_pSigsNotvalidatedImg, "notvalidatedimg"); 129 get(m_pSigsNotvalidatedFI, "notvalidatedft"); 130 get(m_pSigsOldSignatureImg, "oldsignatureimg"); 131 get(m_pSigsOldSignatureFI, "oldsignatureft"); 132 133 m_bAdESCompliant = !DocumentSignatureHelper::isODFPre_1_2(m_sODFVersion); 134 135 Size aControlSize(375, 109); 136 const long nControlWidth = aControlSize.Width(); 137 aControlSize = LogicToPixel(aControlSize, MapMode(MapUnit::MapAppFont)); 138 SvSimpleTableContainer *pSignatures = get<SvSimpleTableContainer>("signatures"); 139 pSignatures->set_width_request(aControlSize.Width()); 140 pSignatures->set_height_request(aControlSize.Height()); 141 142 m_pSignaturesLB = VclPtr<SvSimpleTable>::Create(*pSignatures); 143 // Give the first column 6 percent, try to distribute the rest equally. 144 static long aTabs[] = { 0, 6*nControlWidth/100, 25*nControlWidth/100, 44*nControlWidth/100, 62*nControlWidth/100, 81*nControlWidth/100 }; 145 m_pSignaturesLB->SetTabs(SAL_N_ELEMENTS(aTabs), aTabs); 146 147 m_pSignaturesLB->InsertHeaderEntry("\t" + get<FixedText>("signed")->GetText() + "\t" 148 + get<FixedText>("issued")->GetText() + "\t" + get<FixedText>("date")->GetText() + "\t" 149 + get<FixedText>("description")->GetText() + "\t" + get<FixedText>("type")->GetText()); 150 151 mbVerifySignatures = true; 152 mbSignaturesChanged = false; 153 154 m_pSignaturesLB->SetSelectHdl( LINK( this, DigitalSignaturesDialog, SignatureHighlightHdl ) ); 155 m_pSignaturesLB->SetDoubleClickHdl( LINK( this, DigitalSignaturesDialog, SignatureSelectHdl ) ); 156 157 m_pAdESCompliantCB->SetToggleHdl( LINK( this, DigitalSignaturesDialog, AdESCompliantCheckBoxHdl ) ); 158 m_pAdESCompliantCB->Check(m_bAdESCompliant); 159 160 m_pViewBtn->SetClickHdl( LINK( this, DigitalSignaturesDialog, ViewButtonHdl ) ); 161 m_pViewBtn->Disable(); 162 163 m_pAddBtn->SetClickHdl( LINK( this, DigitalSignaturesDialog, AddButtonHdl ) ); 164 if ( bReadOnly ) 165 m_pAddBtn->Disable(); 166 167 m_pRemoveBtn->SetClickHdl( LINK( this, DigitalSignaturesDialog, RemoveButtonHdl ) ); 168 m_pRemoveBtn->Disable(); 169 170 m_pStartCertMgrBtn->SetClickHdl( LINK( this, DigitalSignaturesDialog, CertMgrButtonHdl ) ); 171 172 m_pCloseBtn->SetClickHdl( LINK( this, DigitalSignaturesDialog, OKButtonHdl) ); 173 174 switch( maSignatureManager.meSignatureMode ) 175 { 176 case DocumentSignatureMode::Content: 177 m_pHintDocFT->Show(); 178 break; 179 case DocumentSignatureMode::Macros: 180 m_pHintBasicFT->Show(); 181 break; 182 case DocumentSignatureMode::Package: 183 m_pHintPackageFT->Show(); 184 break; 185 } 186 } 187 188 DigitalSignaturesDialog::~DigitalSignaturesDialog() 189 { 190 disposeOnce(); 191 } 192 193 void DigitalSignaturesDialog::dispose() 194 { 195 m_pSignaturesLB.disposeAndClear(); 196 m_pHintDocFT.clear(); 197 m_pHintBasicFT.clear(); 198 m_pHintPackageFT.clear(); 199 m_pSigsValidImg.clear(); 200 m_pSigsValidFI.clear(); 201 m_pSigsInvalidImg.clear(); 202 m_pSigsInvalidFI.clear(); 203 m_pSigsNotvalidatedImg.clear(); 204 m_pSigsNotvalidatedFI.clear(); 205 m_pSigsOldSignatureImg.clear(); 206 m_pSigsOldSignatureFI.clear(); 207 m_pAdESCompliantCB.clear(); 208 m_pViewBtn.clear(); 209 m_pAddBtn.clear(); 210 m_pRemoveBtn.clear(); 211 m_pCloseBtn.clear(); 212 m_pStartCertMgrBtn.clear(); 213 ModalDialog::dispose(); 214 } 215 216 bool DigitalSignaturesDialog::Init() 217 { 218 bool bInit = maSignatureManager.init(); 219 220 SAL_WARN_IF( !bInit, "xmlsecurity.dialogs", "Error initializing security context!" ); 221 222 if ( bInit ) 223 { 224 maSignatureManager.maSignatureHelper.SetStartVerifySignatureHdl( LINK( this, DigitalSignaturesDialog, StartVerifySignatureHdl ) ); 225 } 226 227 return bInit; 228 } 229 230 void DigitalSignaturesDialog::SetStorage( const css::uno::Reference < css::embed::XStorage >& rxStore ) 231 { 232 if (!rxStore.is()) 233 { 234 // PDF supports AdES. 235 m_bAdESCompliant = true; 236 m_pAdESCompliantCB->Check(m_bAdESCompliant); 237 return; 238 } 239 240 maSignatureManager.mxStore = rxStore; 241 maSignatureManager.maSignatureHelper.SetStorage( maSignatureManager.mxStore, m_sODFVersion); 242 243 Reference < css::packages::manifest::XManifestReader > xReader = 244 css::packages::manifest::ManifestReader::create(mxCtx); 245 246 uno::Reference<container::XNameAccess> xNameAccess(rxStore, uno::UNO_QUERY); 247 if (!xNameAccess.is()) 248 return; 249 250 if (xNameAccess->hasByName("META-INF")) 251 { 252 //Get the manifest.xml 253 Reference < css::embed::XStorage > xSubStore(rxStore->openStorageElement( 254 "META-INF", css::embed::ElementModes::READ), UNO_QUERY_THROW); 255 256 Reference< css::io::XInputStream > xStream( 257 xSubStore->openStreamElement("manifest.xml", css::embed::ElementModes::READ), 258 UNO_QUERY_THROW); 259 260 maSignatureManager.m_manifest = xReader->readManifestSequence(xStream); 261 } 262 } 263 264 void DigitalSignaturesDialog::SetSignatureStream( const css::uno::Reference < css::io::XStream >& rxStream ) 265 { 266 maSignatureManager.mxSignatureStream = rxStream; 267 } 268 269 bool DigitalSignaturesDialog::canAddRemove() 270 { 271 //FIXME: this func needs some cleanup, such as real split between 272 //'canAdd' and 'canRemove' case 273 bool ret = true; 274 275 uno::Reference<container::XNameAccess> xNameAccess(maSignatureManager.mxStore, uno::UNO_QUERY); 276 if (xNameAccess.is() && xNameAccess->hasByName("[Content_Types].xml")) 277 // It's always possible to append an OOXML signature. 278 return ret; 279 280 if (!maSignatureManager.mxStore.is()) 281 // It's always possible to append a PDF signature. 282 return ret; 283 284 OSL_ASSERT(maSignatureManager.mxStore.is()); 285 bool bDoc1_1 = DocumentSignatureHelper::isODFPre_1_2(m_sODFVersion); 286 SaveODFItem item; 287 bool bSave1_1 = item.isLessODF1_2(); 288 289 // see specification 290 //cvs: specs/www/appwide/security/Electronic_Signatures_and_Security.sxw 291 //Paragraph 'Behavior with regard to ODF 1.2' 292 //For both, macro and document 293 if ( (!bSave1_1 && bDoc1_1) || (bSave1_1 && bDoc1_1) ) 294 { 295 //#4 296 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetFrameWeld(), 297 VclMessageType::Warning, VclButtonsType::Ok, 298 XsResId(STR_XMLSECDLG_OLD_ODF_FORMAT))); 299 xBox->run(); 300 ret = false; 301 } 302 303 //As of OOo 3.2 the document signature includes in macrosignatures.xml. That is 304 //adding a macro signature will break an existing document signature. 305 //The sfx2 will remove the documentsignature when the user adds a macro signature 306 if (maSignatureManager.meSignatureMode == DocumentSignatureMode::Macros 307 && ret) 308 { 309 if (m_bHasDocumentSignature && !m_bWarningShowSignMacro) 310 { 311 //The warning says that the document signatures will be removed if the user 312 //continues. He can then either press 'OK' or 'NO' 313 //It the user presses 'Add' or 'Remove' several times then, then the warning 314 //is shown every time until the user presses 'OK'. From then on, the warning 315 //is not displayed anymore as long as the signatures dialog is alive. 316 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetFrameWeld(), 317 VclMessageType::Question, VclButtonsType::YesNo, 318 XsResId(STR_XMLSECDLG_QUERY_REMOVEDOCSIGNBEFORESIGN))); 319 if (xBox->run() == RET_NO) 320 ret = false; 321 else 322 m_bWarningShowSignMacro = true; 323 324 } 325 } 326 return ret; 327 } 328 329 bool DigitalSignaturesDialog::canAdd() 330 { 331 return canAddRemove(); 332 } 333 334 bool DigitalSignaturesDialog::canRemove() 335 { 336 bool bRet = true; 337 338 if ( maSignatureManager.meSignatureMode == DocumentSignatureMode::Content ) 339 { 340 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetFrameWeld(), 341 VclMessageType::Question, VclButtonsType::YesNo, 342 XsResId(STR_XMLSECDLG_QUERY_REALLYREMOVE))); 343 short nDlgRet = xBox->run(); 344 bRet = ( nDlgRet == RET_YES ); 345 } 346 347 return (bRet && canAddRemove()); 348 } 349 350 short DigitalSignaturesDialog::Execute() 351 { 352 // Verify Signatures and add certificates to ListBox... 353 mbVerifySignatures = true; 354 ImplGetSignatureInformations(/*bUseTempStream=*/false, /*bCacheLastSignature=*/true); 355 ImplFillSignaturesBox(); 356 357 // FIXME: Disable the "Use XAdES compliant signatures" checkbox if it is irrelevant. If it is 358 // enabled, set its initial state based on existing signatures, if any. 359 360 // If it is OOXML, the checkbox is irrelevant. 361 362 // How to find out here whether it is OOXML? I don't want to create a SignatureStreamHelper and 363 // check its nStorageFormat as that seems overly complicated and seems to have weird indirect 364 // consequences, as I noticed when I tried to use DocumentSignatureManager::IsXAdESRelevant() 365 // (which now is in #if 0). 366 367 if (maSignatureManager.maCurrentSignatureInformations.size() > 0) 368 { 369 // If the document has only SHA-1 signatures we probably want it to stay that way? 370 } 371 372 // Only verify once, content will not change. 373 // But for refreshing signature information, StartVerifySignatureHdl will be called after each add/remove 374 mbVerifySignatures = false; 375 376 return Dialog::Execute(); 377 } 378 379 IMPL_LINK_NOARG(DigitalSignaturesDialog, SignatureHighlightHdl, SvTreeListBox*, void) 380 { 381 bool bSel = m_pSignaturesLB->FirstSelected(); 382 m_pViewBtn->Enable( bSel ); 383 if ( m_pAddBtn->IsEnabled() ) // not read only 384 m_pRemoveBtn->Enable( bSel ); 385 } 386 387 IMPL_LINK_NOARG(DigitalSignaturesDialog, OKButtonHdl, Button*, void) 388 { 389 if (mbSignaturesChanged) 390 maSignatureManager.write(m_bAdESCompliant); 391 392 EndDialog(RET_OK); 393 } 394 395 IMPL_LINK_NOARG(DigitalSignaturesDialog, SignatureSelectHdl, SvTreeListBox*, bool) 396 { 397 ImplShowSignaturesDetails(); 398 return false; 399 } 400 401 IMPL_LINK_NOARG(DigitalSignaturesDialog, AdESCompliantCheckBoxHdl, CheckBox&, void) 402 { 403 m_bAdESCompliant = m_pAdESCompliantCB->IsChecked(); 404 } 405 406 IMPL_LINK_NOARG(DigitalSignaturesDialog, ViewButtonHdl, Button*, void) 407 { 408 ImplShowSignaturesDetails(); 409 } 410 411 IMPL_LINK_NOARG(DigitalSignaturesDialog, AddButtonHdl, Button*, void) 412 { 413 if( ! canAdd()) 414 return; 415 try 416 { 417 std::vector<uno::Reference<xml::crypto::XXMLSecurityContext>> xSecContexts; 418 xSecContexts.push_back(maSignatureManager.getSecurityContext()); 419 // Gpg signing is only possible with ODF >= 1.2 documents 420 if (DocumentSignatureHelper::CanSignWithGPG(maSignatureManager.mxStore, m_sODFVersion)) 421 xSecContexts.push_back(maSignatureManager.getGpgSecurityContext()); 422 423 ScopedVclPtrInstance< CertificateChooser > aChooser( this, mxCtx, xSecContexts, UserAction::Sign ); 424 if ( aChooser->Execute() == RET_OK ) 425 { 426 sal_Int32 nSecurityId; 427 if (!maSignatureManager.add(aChooser->GetSelectedCertificates()[0], aChooser->GetSelectedSecurityContext(), 428 aChooser->GetDescription(), nSecurityId, m_bAdESCompliant)) 429 return; 430 mbSignaturesChanged = true; 431 432 xml::crypto::SecurityOperationStatus nStatus = xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED; 433 434 if (maSignatureManager.mxStore.is()) 435 // In the PDF case the signature information is only available after parsing. 436 nStatus = maSignatureManager.maSignatureHelper.GetSignatureInformation( nSecurityId ).nStatus; 437 438 if ( nStatus == css::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED ) 439 { 440 mbSignaturesChanged = true; 441 442 // Can't simply remember current information, need parsing for getting full information :( 443 // We need to verify the signatures again, otherwise the status in the signature information 444 // will not contain 445 // SecurityOperationStatus_OPERATION_SUCCEEDED 446 mbVerifySignatures = true; 447 ImplGetSignatureInformations(/*bUseTempStream=*/true, /*bCacheLastSignature=*/false); 448 ImplFillSignaturesBox(); 449 } 450 } 451 } 452 catch ( uno::Exception& ) 453 { 454 OSL_FAIL( "Exception while adding a signature!" ); 455 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetFrameWeld(), 456 VclMessageType::Error, VclButtonsType::Ok, 457 XsResId(STR_XMLSECDLG_SIGNING_FAILED))); 458 xBox->run(); 459 // Don't keep invalid entries... 460 ImplGetSignatureInformations(/*bUseTempStream=*/true, /*bCacheLastSignature=*/false); 461 ImplFillSignaturesBox(); 462 } 463 } 464 465 IMPL_LINK_NOARG(DigitalSignaturesDialog, RemoveButtonHdl, Button*, void) 466 { 467 if (!canRemove()) 468 return; 469 if( m_pSignaturesLB->FirstSelected() ) 470 { 471 try 472 { 473 sal_uInt16 nSelected = static_cast<sal_uInt16>(reinterpret_cast<sal_uIntPtr>( m_pSignaturesLB->FirstSelected()->GetUserData() )); 474 maSignatureManager.remove(nSelected); 475 476 mbSignaturesChanged = true; 477 478 ImplFillSignaturesBox(); 479 } 480 catch ( uno::Exception& ) 481 { 482 OSL_FAIL( "Exception while removing a signature!" ); 483 // Don't keep invalid entries... 484 ImplGetSignatureInformations(/*bUseTempStream=*/true, /*bCacheLastSignature=*/true); 485 ImplFillSignaturesBox(); 486 } 487 } 488 } 489 490 IMPL_STATIC_LINK(DigitalSignaturesDialog, CertMgrButtonHdl, Button*, pButton, void) 491 { 492 #ifdef _WIN32 493 // FIXME: call GpgME::dirInfo("bindir") somewhere in 494 // SecurityEnvironmentGpg or whatnot 495 // FIXME: perhaps poke GpgME for uiserver, and hope it returns something useful? 496 const OUString aGUIServers[] = { OUString("kleopatra.exe"), OUString("launch-gpa.exe"), OUString("gpa.exe"), 497 OUString("bin\\kleopatra.exe"), OUString("bin\\launch-gpa.exe"), OUString("bin\\gpa.exe") }; 498 const char* const cPath = "C:\\Program Files (x86)\\GNU\\GnuPG"; 499 #else 500 const OUString aGUIServers[] = { OUString("kleopatra"), OUString("seahorse"), OUString("gpa"), OUString("kgpg") }; 501 const char* cPath = getenv("PATH"); 502 #endif 503 504 if (cPath) 505 { 506 OUString aPath(cPath, strlen(cPath), osl_getThreadTextEncoding()); 507 OUString sFoundGUIServer, sExecutable; 508 509 for ( auto const &rServer : aGUIServers ) 510 { 511 osl::FileBase::RC searchError = osl::File::searchFileURL(rServer, aPath, sFoundGUIServer ); 512 if (searchError == osl::FileBase::E_None) 513 { 514 osl::File::getSystemPathFromFileURL( sFoundGUIServer, sExecutable ); 515 break; 516 } 517 518 } 519 520 if ( !sExecutable.isEmpty() ) 521 { 522 uno::Reference< uno::XComponentContext > xContext = 523 ::comphelper::getProcessComponentContext(); 524 uno::Reference< css::system::XSystemShellExecute > xSystemShell( 525 css::system::SystemShellExecute::create(xContext) ); 526 527 xSystemShell->execute( sExecutable, OUString(), 528 css::system::SystemShellExecuteFlags::DEFAULTS ); 529 } 530 else 531 { 532 std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(pButton->GetFrameWeld(), 533 VclMessageType::Info, VclButtonsType::Ok, 534 XsResId(STR_XMLSECDLG_NO_CERT_MANAGER))); 535 xInfoBox->run(); 536 } 537 } 538 } 539 540 IMPL_LINK_NOARG(DigitalSignaturesDialog, StartVerifySignatureHdl, LinkParamNone*, bool) 541 { 542 return mbVerifySignatures; 543 } 544 545 void DigitalSignaturesDialog::ImplFillSignaturesBox() 546 { 547 m_pSignaturesLB->Clear(); 548 549 size_t nInfos = maSignatureManager.maCurrentSignatureInformations.size(); 550 size_t nValidSigs = 0, nValidCerts = 0; 551 bool bAllNewSignatures = true; 552 553 if( nInfos ) 554 { 555 for( size_t n = 0; n < nInfos; ++n ) 556 { 557 DocumentSignatureAlgorithm mode = DocumentSignatureHelper::getDocumentAlgorithm( 558 m_sODFVersion, maSignatureManager.maCurrentSignatureInformations[n]); 559 std::vector< OUString > aElementsToBeVerified; 560 if (maSignatureManager.mxStore.is()) 561 aElementsToBeVerified = DocumentSignatureHelper::CreateElementList(maSignatureManager.mxStore, maSignatureManager.meSignatureMode, mode); 562 563 const SignatureInformation& rInfo = maSignatureManager.maCurrentSignatureInformations[n]; 564 uno::Reference< css::security::XCertificate > xCert = getCertificate(rInfo); 565 566 OUString aSubject; 567 OUString aIssuer; 568 OUString aDateTimeStr; 569 OUString aDescription; 570 OUString aType; 571 572 bool bSigValid = false; 573 bool bCertValid = false; 574 if( xCert.is() ) 575 { 576 //check the validity of the cert 577 try { 578 sal_Int32 certResult = getSecurityEnvironmentForCertificate(xCert)->verifyCertificate(xCert, 579 Sequence<uno::Reference<security::XCertificate> >()); 580 581 bCertValid = certResult == css::security::CertificateValidity::VALID; 582 if ( bCertValid ) 583 nValidCerts++; 584 585 } catch (css::uno::SecurityException& ) { 586 OSL_FAIL("Verification of certificate failed"); 587 bCertValid = false; 588 } 589 590 aSubject = XmlSec::GetContentPart( xCert->getSubjectName() ); 591 aIssuer = XmlSec::GetContentPart( xCert->getIssuerName() ); 592 } 593 else if (!rInfo.ouGpgCertificate.isEmpty()) 594 { 595 // In case we don't have the gpg key locally, get some data from the document 596 aIssuer = rInfo.ouGpgOwner; 597 } 598 599 aDateTimeStr = XmlSec::GetDateTimeString( rInfo.stDateTime ); 600 aDescription = rInfo.ouDescription; 601 602 // Decide type string. 603 if (maSignatureManager.mxStore.is()) 604 { 605 // OpenPGP 606 if (!rInfo.ouGpgCertificate.isEmpty()) 607 aType = "OpenPGP"; 608 // XML based: XAdES or not. 609 else if (!rInfo.ouCertDigest.isEmpty()) 610 aType = "XAdES"; 611 else 612 aType = "XML-DSig"; 613 } 614 else 615 { 616 // Assume PDF: PAdES or not. 617 if (rInfo.bHasSigningCertificate) 618 aType = "PAdES"; 619 else 620 aType = "PDF"; 621 } 622 623 bSigValid = ( rInfo.nStatus == css::xml::crypto::SecurityOperationStatus_OPERATION_SUCCEEDED ); 624 625 if ( bSigValid ) 626 { 627 bSigValid = DocumentSignatureHelper::checkIfAllFilesAreSigned( 628 aElementsToBeVerified, rInfo, mode); 629 630 if( bSigValid ) 631 nValidSigs++; 632 } 633 634 Image aImage; 635 if (!bSigValid) 636 { 637 aImage = m_pSigsInvalidImg->GetImage(); 638 } 639 else if (bSigValid && !bCertValid) 640 { 641 aImage = m_pSigsNotvalidatedImg->GetImage(); 642 } 643 //Check if the signature is a "old" document signature, that is, which was created 644 //by an version of OOo previous to 3.2 645 // If there is no storage, then it's pointless to check storage 646 // stream references. 647 else if (maSignatureManager.meSignatureMode == DocumentSignatureMode::Content 648 && bSigValid && bCertValid && (maSignatureManager.mxStore.is() && !DocumentSignatureHelper::isOOo3_2_Signature( 649 maSignatureManager.maCurrentSignatureInformations[n]))) 650 { 651 aImage = m_pSigsNotvalidatedImg->GetImage(); 652 bAllNewSignatures = false; 653 } 654 else if (maSignatureManager.meSignatureMode == DocumentSignatureMode::Content 655 && bSigValid && bCertValid && DocumentSignatureHelper::isOOo3_2_Signature( 656 maSignatureManager.maCurrentSignatureInformations[n])) 657 { 658 aImage = m_pSigsValidImg->GetImage(); 659 } 660 else if (maSignatureManager.meSignatureMode == DocumentSignatureMode::Macros 661 && bSigValid && bCertValid) 662 { 663 aImage = m_pSigsValidImg->GetImage(); 664 } 665 666 SvTreeListEntry* pEntry = m_pSignaturesLB->InsertEntry( OUString(), aImage, aImage ); 667 m_pSignaturesLB->SetEntryText( aSubject, pEntry, 1 ); 668 m_pSignaturesLB->SetEntryText( aIssuer, pEntry, 2 ); 669 m_pSignaturesLB->SetEntryText( aDateTimeStr, pEntry, 3 ); 670 m_pSignaturesLB->SetEntryText(aDescription, pEntry, 4); 671 m_pSignaturesLB->SetEntryText(aType, pEntry, 5); 672 pEntry->SetUserData( reinterpret_cast<void*>(n) ); // misuse user data as index 673 } 674 } 675 676 bool bAllSigsValid = (nValidSigs == nInfos); 677 bool bAllCertsValid = (nValidCerts == nInfos); 678 bool bShowValidState = nInfos && (bAllSigsValid && bAllCertsValid && bAllNewSignatures); 679 680 m_pSigsValidImg->Show( bShowValidState); 681 m_pSigsValidFI->Show( bShowValidState ); 682 683 bool bShowInvalidState = nInfos && !bAllSigsValid; 684 685 m_pSigsInvalidImg->Show( bShowInvalidState ); 686 m_pSigsInvalidFI->Show( bShowInvalidState ); 687 688 bool bShowNotValidatedState = nInfos && bAllSigsValid && !bAllCertsValid; 689 690 m_pSigsNotvalidatedImg->Show(bShowNotValidatedState); 691 m_pSigsNotvalidatedFI->Show(bShowNotValidatedState); 692 693 //bAllNewSignatures is always true if we are not in document mode 694 bool bShowOldSignature = nInfos && bAllSigsValid && bAllCertsValid && !bAllNewSignatures; 695 m_pSigsOldSignatureImg->Show(bShowOldSignature); 696 m_pSigsOldSignatureFI->Show(bShowOldSignature); 697 698 SignatureHighlightHdl( nullptr ); 699 } 700 701 uno::Reference<security::XCertificate> DigitalSignaturesDialog::getCertificate(const SignatureInformation& rInfo) 702 { 703 uno::Reference<xml::crypto::XSecurityEnvironment> xSecEnv = maSignatureManager.getSecurityEnvironment(); 704 uno::Reference<xml::crypto::XSecurityEnvironment> xGpgSecEnv = maSignatureManager.getGpgSecurityEnvironment(); 705 uno::Reference<security::XCertificate> xCert; 706 707 //First we try to get the certificate which is embedded in the XML Signature 708 if (xSecEnv.is() && !rInfo.ouX509Certificate.isEmpty()) 709 xCert = xSecEnv->createCertificateFromAscii(rInfo.ouX509Certificate); 710 else { 711 //There must be an embedded certificate because we use it to get the 712 //issuer name. We cannot use /Signature/KeyInfo/X509Data/X509IssuerName 713 //because it could be modified by an attacker. The issuer is displayed 714 //in the digital signature dialog. 715 //Comparing the X509IssuerName with the one from the X509Certificate in order 716 //to find out if the X509IssuerName was modified does not work. See #i62684 717 SAL_WARN( "xmlsecurity.dialogs", "Could not find embedded certificate!"); 718 } 719 720 //In case there is no embedded certificate we try to get it from a local store 721 if (!xCert.is() && xSecEnv.is()) 722 xCert = xSecEnv->getCertificate( rInfo.ouX509IssuerName, xmlsecurity::numericStringToBigInteger( rInfo.ouX509SerialNumber ) ); 723 if (!xCert.is() && xGpgSecEnv.is()) 724 xCert = xGpgSecEnv->getCertificate( rInfo.ouGpgKeyID, xmlsecurity::numericStringToBigInteger("") ); 725 726 SAL_WARN_IF( !xCert.is(), "xmlsecurity.dialogs", "Certificate not found and can't be created!" ); 727 728 return xCert; 729 } 730 731 uno::Reference<xml::crypto::XSecurityEnvironment> DigitalSignaturesDialog::getSecurityEnvironmentForCertificate(const uno::Reference<security::XCertificate>& xCert) 732 { 733 if (xCert->getCertificateKind() == CertificateKind_OPENPGP) 734 return maSignatureManager.getGpgSecurityEnvironment(); 735 else if (xCert->getCertificateKind() == CertificateKind_X509) 736 return maSignatureManager.getSecurityEnvironment(); 737 738 throw RuntimeException("Unknown certificate kind"); 739 } 740 741 //If bUseTempStream is true then the temporary signature stream is used. 742 //Otherwise the real signature stream is used. 743 void DigitalSignaturesDialog::ImplGetSignatureInformations(bool bUseTempStream, bool bCacheLastSignature) 744 { 745 maSignatureManager.read(bUseTempStream, bCacheLastSignature); 746 mbVerifySignatures = false; 747 } 748 749 void DigitalSignaturesDialog::ImplShowSignaturesDetails() 750 { 751 if( m_pSignaturesLB->FirstSelected() ) 752 { 753 sal_uInt16 nSelected = static_cast<sal_uInt16>(reinterpret_cast<sal_uIntPtr>( m_pSignaturesLB->FirstSelected()->GetUserData() )); 754 const SignatureInformation& rInfo = maSignatureManager.maCurrentSignatureInformations[ nSelected ]; 755 uno::Reference<security::XCertificate> xCert = getCertificate(rInfo); 756 757 if ( xCert.is() ) 758 { 759 uno::Reference<xml::crypto::XSecurityEnvironment> xSecEnv = getSecurityEnvironmentForCertificate(xCert); 760 ScopedVclPtrInstance<CertificateViewer> aViewer(this, xSecEnv, xCert, false); 761 aViewer->Execute(); 762 } 763 else 764 { 765 std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(), 766 VclMessageType::Info, VclButtonsType::Ok, 767 XsResId(STR_XMLSECDLG_NO_CERT_FOUND))); 768 xInfoBox->run(); 769 } 770 } 771 } 772 773 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 774
