File indexing completed on 2024-07-14 14:34:05

0001 /*
0002     This file is part of the KDE project
0003     SPDX-FileCopyrightText: 2000, 2001 George Staikos <staikos@kde.org>
0004     SPDX-FileCopyrightText: 2000 Malte Starostik <malte@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-or-later
0007 */
0008 
0009 #include "ksslinfodialog.h"
0010 #include "ksslcertificatebox.h"
0011 #include "ksslerror_p.h"
0012 #include "ui_sslinfo.h"
0013 
0014 #include <QDialogButtonBox>
0015 
0016 #include <QSslCertificate>
0017 
0018 #include <KIconLoader> // BarIcon
0019 #include <KLocalizedString>
0020 
0021 class Q_DECL_HIDDEN KSslInfoDialog::KSslInfoDialogPrivate
0022 {
0023 public:
0024     QList<QSslCertificate> certificateChain;
0025     QList<QList<QSslError::SslError>> certificateErrors;
0026 
0027     bool isMainPartEncrypted;
0028     bool auxPartsEncrypted;
0029 
0030     Ui::SslInfo ui;
0031     KSslCertificateBox *subject;
0032     KSslCertificateBox *issuer;
0033 };
0034 
0035 KSslInfoDialog::KSslInfoDialog(QWidget *parent)
0036     : QDialog(parent)
0037     , d(new KSslInfoDialogPrivate)
0038 {
0039     setWindowTitle(i18n("KDE SSL Information"));
0040     setAttribute(Qt::WA_DeleteOnClose);
0041 
0042     QVBoxLayout *layout = new QVBoxLayout(this);
0043 
0044     QWidget *mainWidget = new QWidget(this);
0045     d->ui.setupUi(mainWidget);
0046     layout->addWidget(mainWidget);
0047 
0048     d->subject = new KSslCertificateBox(d->ui.certParties);
0049     d->issuer = new KSslCertificateBox(d->ui.certParties);
0050     d->ui.certParties->addTab(d->subject, i18nc("The receiver of the SSL certificate", "Subject"));
0051     d->ui.certParties->addTab(d->issuer, i18nc("The authority that issued the SSL certificate", "Issuer"));
0052 
0053     d->isMainPartEncrypted = true;
0054     d->auxPartsEncrypted = true;
0055     updateWhichPartsEncrypted();
0056 
0057     QDialogButtonBox *buttonBox = new QDialogButtonBox(this);
0058     buttonBox->setStandardButtons(QDialogButtonBox::Close);
0059     connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
0060     connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
0061     layout->addWidget(buttonBox);
0062 }
0063 
0064 KSslInfoDialog::~KSslInfoDialog() = default;
0065 
0066 void KSslInfoDialog::setMainPartEncrypted(bool mainEncrypted)
0067 {
0068     d->isMainPartEncrypted = mainEncrypted;
0069     updateWhichPartsEncrypted();
0070 }
0071 
0072 void KSslInfoDialog::setAuxiliaryPartsEncrypted(bool auxEncrypted)
0073 {
0074     d->auxPartsEncrypted = auxEncrypted;
0075     updateWhichPartsEncrypted();
0076 }
0077 
0078 void KSslInfoDialog::updateWhichPartsEncrypted()
0079 {
0080     if (d->isMainPartEncrypted) {
0081         if (d->auxPartsEncrypted) {
0082             d->ui.encryptionIndicator->setPixmap(QIcon::fromTheme(QStringLiteral("security-high")).pixmap(KIconLoader::SizeSmallMedium));
0083             d->ui.explanation->setText(i18n("Current connection is secured with SSL."));
0084         } else {
0085             d->ui.encryptionIndicator->setPixmap(QIcon::fromTheme(QStringLiteral("security-medium")).pixmap(KIconLoader::SizeSmallMedium));
0086             d->ui.explanation->setText(
0087                 i18n("The main part of this document is secured "
0088                      "with SSL, but some parts are not."));
0089         }
0090     } else {
0091         if (d->auxPartsEncrypted) {
0092             d->ui.encryptionIndicator->setPixmap(QIcon::fromTheme(QStringLiteral("security-medium")).pixmap(KIconLoader::SizeSmallMedium));
0093             d->ui.explanation->setText(
0094                 i18n("Some of this document is secured with SSL, "
0095                      "but the main part is not."));
0096         } else {
0097             d->ui.encryptionIndicator->setPixmap(QIcon::fromTheme(QStringLiteral("security-low")).pixmap(KIconLoader::SizeSmallMedium));
0098             d->ui.explanation->setText(i18n("Current connection is not secured with SSL."));
0099         }
0100     }
0101 }
0102 
0103 #ifndef KIO_ANDROID_STUB
0104 #if KIOCORE_BUILD_DEPRECATED_SINCE(5, 64)
0105 void KSslInfoDialog::setSslInfo(const QList<QSslCertificate> &certificateChain,
0106                                 const QString &ip,
0107                                 const QString &host,
0108                                 const QString &sslProtocol,
0109                                 const QString &cipher,
0110                                 int usedBits,
0111                                 int bits,
0112                                 const QList<QList<KSslError::Error>> &validationErrors)
0113 {
0114     QList<QList<QSslError::SslError>> qValidationErrors;
0115     qValidationErrors.reserve(validationErrors.size());
0116     for (const auto &l : validationErrors) {
0117         QList<QSslError::SslError> qErrors;
0118         qErrors.reserve(l.size());
0119         for (const KSslError::Error e : l) {
0120             qErrors.push_back(KSslErrorPrivate::errorFromKSslError(e));
0121         }
0122         qValidationErrors.push_back(qErrors);
0123     }
0124     setSslInfo(certificateChain, ip, host, sslProtocol, cipher, usedBits, bits, qValidationErrors);
0125 }
0126 #endif
0127 #endif
0128 
0129 void KSslInfoDialog::setSslInfo(const QList<QSslCertificate> &certificateChain,
0130                                 const QString &ip,
0131                                 const QString &host,
0132                                 const QString &sslProtocol,
0133                                 const QString &cipher,
0134                                 int usedBits,
0135                                 int bits,
0136                                 const QList<QList<QSslError::SslError>> &validationErrors)
0137 {
0138     d->certificateChain = certificateChain;
0139     d->certificateErrors = validationErrors;
0140 
0141     d->ui.certSelector->clear();
0142     for (const QSslCertificate &cert : certificateChain) {
0143         QString name;
0144         static const QSslCertificate::SubjectInfo si[] = {QSslCertificate::CommonName, QSslCertificate::Organization, QSslCertificate::OrganizationalUnitName};
0145         for (int j = 0; j < 3 && name.isEmpty(); j++) {
0146             name = cert.subjectInfo(si[j]).join(QLatin1String(", "));
0147         }
0148         d->ui.certSelector->addItem(name);
0149     }
0150     if (certificateChain.size() < 2) {
0151         d->ui.certSelector->setEnabled(false);
0152     }
0153     connect(d->ui.certSelector, qOverload<int>(&QComboBox::currentIndexChanged), this, &KSslInfoDialog::displayFromChain);
0154     if (d->certificateChain.isEmpty()) {
0155         d->certificateChain.append(QSslCertificate());
0156     }
0157     displayFromChain(0);
0158 
0159     d->ui.ip->setText(ip);
0160     d->ui.address->setText(host);
0161     d->ui.sslVersion->setText(sslProtocol);
0162 
0163     const QStringList cipherInfo = cipher.split(QLatin1Char('\n'), Qt::SkipEmptyParts);
0164     if (cipherInfo.size() >= 4) {
0165         d->ui.encryption->setText(i18nc("%1, using %2 bits of a %3 bit key",
0166                                         "%1, %2 %3",
0167                                         cipherInfo[0],
0168                                         i18ncp("Part of: %1, using %2 bits of a %3 bit key", "using %1 bit", "using %1 bits", usedBits),
0169                                         i18ncp("Part of: %1, using %2 bits of a %3 bit key", "of a %1 bit key", "of a %1 bit key", bits)));
0170         d->ui.details->setText(QStringLiteral("Auth = %1, Kx = %2, MAC = %3").arg(cipherInfo[1], cipherInfo[2], cipherInfo[3]));
0171     } else {
0172         d->ui.encryption->setText(QString());
0173         d->ui.details->setText(QString());
0174     }
0175 }
0176 
0177 void KSslInfoDialog::displayFromChain(int i)
0178 {
0179     const QSslCertificate &cert = d->certificateChain[i];
0180 
0181     QString trusted;
0182     const QList<QSslError::SslError> errorsList = d->certificateErrors[i];
0183     if (!errorsList.isEmpty()) {
0184         trusted = i18nc("The certificate is not trusted", "NO, there were errors:");
0185         for (QSslError::SslError e : errorsList) {
0186             QSslError classError(e);
0187             trusted += QLatin1Char('\n') + classError.errorString();
0188         }
0189     } else {
0190         trusted = i18nc("The certificate is trusted", "Yes");
0191     }
0192     d->ui.trusted->setText(trusted);
0193 
0194     QString vp =
0195         i18nc("%1 is the effective date of the certificate, %2 is the expiry date", "%1 to %2", cert.effectiveDate().toString(), cert.expiryDate().toString());
0196     d->ui.validityPeriod->setText(vp);
0197 
0198     d->ui.serial->setText(QString::fromUtf8(cert.serialNumber()));
0199     d->ui.digest->setText(QString::fromUtf8(cert.digest().toHex()));
0200     d->ui.sha1Digest->setText(QString::fromUtf8(cert.digest(QCryptographicHash::Sha1).toHex()));
0201 
0202     d->subject->setCertificate(cert, KSslCertificateBox::Subject);
0203     d->issuer->setCertificate(cert, KSslCertificateBox::Issuer);
0204 }
0205 
0206 #ifndef KIO_ANDROID_STUB
0207 #if KIOCORE_BUILD_DEPRECATED_SINCE(5, 65)
0208 // static
0209 QList<QList<KSslError::Error>> KSslInfoDialog::errorsFromString(const QString &es)
0210 {
0211     const QStringList sl = es.split(QLatin1Char('\n'), Qt::KeepEmptyParts);
0212     QList<QList<KSslError::Error>> ret;
0213     ret.reserve(sl.size());
0214     for (const QString &s : sl) {
0215         QList<KSslError::Error> certErrors;
0216         const QStringList sl2 = s.split(QLatin1Char('\t'), Qt::SkipEmptyParts);
0217         for (const QString &s2 : sl2) {
0218             bool didConvert;
0219             KSslError::Error error = KSslErrorPrivate::errorFromQSslError(static_cast<QSslError::SslError>(s2.toInt(&didConvert)));
0220             if (didConvert) {
0221                 certErrors.append(error);
0222             }
0223         }
0224         ret.append(certErrors);
0225     }
0226     return ret;
0227 }
0228 #endif
0229 #endif
0230 
0231 // static
0232 QList<QList<QSslError::SslError>> KSslInfoDialog::certificateErrorsFromString(const QString &errorsString)
0233 {
0234     const QStringList sl = errorsString.split(QLatin1Char('\n'), Qt::KeepEmptyParts);
0235     QList<QList<QSslError::SslError>> ret;
0236     ret.reserve(sl.size());
0237     for (const QString &s : sl) {
0238         QList<QSslError::SslError> certErrors;
0239         const QStringList sl2 = s.split(QLatin1Char('\t'), Qt::SkipEmptyParts);
0240         for (const QString &s2 : sl2) {
0241             bool didConvert;
0242             QSslError::SslError error = static_cast<QSslError::SslError>(s2.toInt(&didConvert));
0243             if (didConvert) {
0244                 certErrors.append(error);
0245             }
0246         }
0247         ret.append(certErrors);
0248     }
0249     return ret;
0250 }
0251 
0252 #include "moc_ksslinfodialog.cpp"