File indexing completed on 2024-09-01 10:25:49
0001 /* 0002 This file is part of the KDE project 0003 SPDX-FileCopyrightText: 2009 Andreas Hartmetz <ahartmetz@gmail.com> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "sslui.h" 0009 0010 #include <KLocalizedString> 0011 #include <KMessageBox> 0012 #include <ksslcertificatemanager.h> 0013 #include <ksslerroruidata_p.h> 0014 #include <ksslinfodialog.h> 0015 0016 #if KIOWIDGETS_BUILD_DEPRECATED_SINCE(5, 64) 0017 bool KIO::SslUi::askIgnoreSslErrors(const KTcpSocket *socket, RulesStorage storedRules) 0018 { 0019 KSslErrorUiData uiData(socket); 0020 return askIgnoreSslErrors(uiData, storedRules); 0021 } 0022 #endif 0023 0024 bool KIO::SslUi::askIgnoreSslErrors(const KSslErrorUiData &uiData, RulesStorage storedRules) 0025 { 0026 const KSslErrorUiData::Private *ud = KSslErrorUiData::Private::get(&uiData); 0027 if (ud->sslErrors.isEmpty()) { 0028 return true; 0029 } 0030 0031 const QList<QSslError> fatalErrors = KSslCertificateManager::nonIgnorableErrors(ud->sslErrors); 0032 if (!fatalErrors.isEmpty()) { 0033 // TODO message "sorry, fatal error, you can't override it" 0034 return false; 0035 } 0036 if (ud->certificateChain.isEmpty()) { 0037 // SSL without certificates is quite useless and should never happen 0038 KMessageBox::error(nullptr, 0039 i18n("The remote host did not send any SSL certificates.\n" 0040 "Aborting because the identity of the host cannot be established.")); 0041 return false; 0042 } 0043 0044 KSslCertificateManager *const cm = KSslCertificateManager::self(); 0045 KSslCertificateRule rule(ud->certificateChain.first(), ud->host); 0046 if (storedRules & RecallRules) { 0047 rule = cm->rule(ud->certificateChain.first(), ud->host); 0048 // remove previously seen and acknowledged errors 0049 const QList<QSslError> remainingErrors = rule.filterErrors(ud->sslErrors); 0050 if (remainingErrors.isEmpty()) { 0051 // qDebug() << "Error list empty after removing errors to be ignored. Continuing."; 0052 return true; 0053 } 0054 } 0055 0056 // ### We don't ask to permanently reject the certificate 0057 0058 QString message = i18n("The server failed the authenticity check (%1).\n\n", ud->host); 0059 for (const QSslError &err : std::as_const(ud->sslErrors)) { 0060 message.append(err.errorString() + QLatin1Char('\n')); 0061 } 0062 message = message.trimmed(); 0063 0064 int msgResult; 0065 do { 0066 msgResult = KMessageBox::warningTwoActionsCancel(nullptr, 0067 message, 0068 i18n("Server Authentication"), 0069 KGuiItem(i18n("&Details"), QStringLiteral("help-about")), 0070 KGuiItem(i18n("Co&ntinue"), QStringLiteral("arrow-right"))); 0071 if (msgResult == KMessageBox::PrimaryAction) { 0072 // Details was chosen - show the certificate and error details 0073 0074 QList<QList<QSslError::SslError>> meh; // parallel list to cert list :/ 0075 0076 meh.reserve(ud->certificateChain.size()); 0077 for (const QSslCertificate &cert : std::as_const(ud->certificateChain)) { 0078 QList<QSslError::SslError> errors; 0079 for (const QSslError &error : std::as_const(ud->sslErrors)) { 0080 if (error.certificate() == cert) { 0081 // we keep only the error code enum here 0082 errors.append(error.error()); 0083 } 0084 } 0085 meh.append(errors); 0086 } 0087 0088 KSslInfoDialog *dialog = new KSslInfoDialog(); 0089 dialog->setSslInfo(ud->certificateChain, ud->ip, ud->host, ud->sslProtocol, ud->cipher, ud->usedBits, ud->bits, meh); 0090 dialog->exec(); 0091 } else if (msgResult == KMessageBox::Cancel) { 0092 return false; 0093 } 0094 // fall through on KMessageBox::SecondaryAction 0095 } while (msgResult == KMessageBox::PrimaryAction); 0096 0097 if (storedRules & StoreRules) { 0098 // Save the user's choice to ignore the SSL errors. 0099 0100 msgResult = KMessageBox::warningTwoActions(nullptr, 0101 i18n("Would you like to accept this " 0102 "certificate forever without " 0103 "being prompted?"), 0104 i18n("Server Authentication"), 0105 KGuiItem(i18n("&Forever"), QStringLiteral("flag-green")), 0106 KGuiItem(i18n("&Current Session only"), QStringLiteral("chronometer"))); 0107 QDateTime ruleExpiry = QDateTime::currentDateTime(); 0108 if (msgResult == KMessageBox::PrimaryAction) { 0109 // accept forever ("for a very long time") 0110 ruleExpiry = ruleExpiry.addYears(1000); 0111 } else { 0112 // accept "for a short time", half an hour. 0113 ruleExpiry = ruleExpiry.addSecs(30 * 60); 0114 } 0115 0116 // TODO special cases for wildcard domain name in the certificate! 0117 // rule = KSslCertificateRule(d->socket.peerCertificateChain().first(), whatever); 0118 0119 rule.setExpiryDateTime(ruleExpiry); 0120 rule.setIgnoredErrors(ud->sslErrors); 0121 cm->setRule(rule); 0122 } 0123 0124 return true; 0125 }