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