| 1 | /* |
| 2 | This file is part of the KDE project |
| 3 | SPDX-FileCopyrightText: 2000, 2001 George Staikos <staikos@kde.org> |
| 4 | SPDX-FileCopyrightText: 2000 Malte Starostik <malte@kde.org> |
| 5 | |
| 6 | SPDX-License-Identifier: LGPL-2.0-or-later |
| 7 | */ |
| 8 | |
| 9 | #include "ksslinfodialog.h" |
| 10 | #include "ksslcertificatebox.h" |
| 11 | #include "ui_sslinfo.h" |
| 12 | |
| 13 | #include <QDialogButtonBox> |
| 14 | |
| 15 | #include <QSslCertificate> |
| 16 | |
| 17 | #include <KIconLoader> // BarIcon |
| 18 | #include <KLocalizedString> |
| 19 | |
| 20 | class Q_DECL_HIDDEN KSslInfoDialog::KSslInfoDialogPrivate |
| 21 | { |
| 22 | public: |
| 23 | QList<QSslCertificate> certificateChain; |
| 24 | QList<QList<QSslError::SslError>> certificateErrors; |
| 25 | |
| 26 | bool isMainPartEncrypted; |
| 27 | bool auxPartsEncrypted; |
| 28 | |
| 29 | Ui::SslInfo ui; |
| 30 | KSslCertificateBox *subject; |
| 31 | KSslCertificateBox *issuer; |
| 32 | }; |
| 33 | |
| 34 | KSslInfoDialog::KSslInfoDialog(QWidget *parent) |
| 35 | : QDialog(parent) |
| 36 | , d(new KSslInfoDialogPrivate) |
| 37 | { |
| 38 | setWindowTitle(i18n("KDE SSL Information" )); |
| 39 | setAttribute(Qt::WA_DeleteOnClose); |
| 40 | |
| 41 | QVBoxLayout *layout = new QVBoxLayout(this); |
| 42 | |
| 43 | QWidget *mainWidget = new QWidget(this); |
| 44 | d->ui.setupUi(mainWidget); |
| 45 | layout->addWidget(mainWidget); |
| 46 | |
| 47 | d->subject = new KSslCertificateBox(d->ui.certParties); |
| 48 | d->issuer = new KSslCertificateBox(d->ui.certParties); |
| 49 | d->ui.certParties->addTab(widget: d->subject, i18nc("The receiver of the SSL certificate" , "Subject" )); |
| 50 | d->ui.certParties->addTab(widget: d->issuer, i18nc("The authority that issued the SSL certificate" , "Issuer" )); |
| 51 | |
| 52 | d->isMainPartEncrypted = true; |
| 53 | d->auxPartsEncrypted = true; |
| 54 | updateWhichPartsEncrypted(); |
| 55 | |
| 56 | QDialogButtonBox *buttonBox = new QDialogButtonBox(this); |
| 57 | buttonBox->setStandardButtons(QDialogButtonBox::Close); |
| 58 | connect(sender: buttonBox, signal: &QDialogButtonBox::accepted, context: this, slot: &QDialog::accept); |
| 59 | connect(sender: buttonBox, signal: &QDialogButtonBox::rejected, context: this, slot: &QDialog::reject); |
| 60 | layout->addWidget(buttonBox); |
| 61 | } |
| 62 | |
| 63 | KSslInfoDialog::~KSslInfoDialog() = default; |
| 64 | |
| 65 | void KSslInfoDialog::setMainPartEncrypted(bool mainEncrypted) |
| 66 | { |
| 67 | d->isMainPartEncrypted = mainEncrypted; |
| 68 | updateWhichPartsEncrypted(); |
| 69 | } |
| 70 | |
| 71 | void KSslInfoDialog::setAuxiliaryPartsEncrypted(bool auxEncrypted) |
| 72 | { |
| 73 | d->auxPartsEncrypted = auxEncrypted; |
| 74 | updateWhichPartsEncrypted(); |
| 75 | } |
| 76 | |
| 77 | void KSslInfoDialog::updateWhichPartsEncrypted() |
| 78 | { |
| 79 | if (d->isMainPartEncrypted) { |
| 80 | if (d->auxPartsEncrypted) { |
| 81 | d->ui.encryptionIndicator->setPixmap(QIcon::fromTheme(QStringLiteral("security-high" )).pixmap(extent: KIconLoader::SizeSmallMedium)); |
| 82 | d->ui.explanation->setText(i18n("Current connection is secured with SSL." )); |
| 83 | } else { |
| 84 | d->ui.encryptionIndicator->setPixmap(QIcon::fromTheme(QStringLiteral("security-medium" )).pixmap(extent: KIconLoader::SizeSmallMedium)); |
| 85 | d->ui.explanation->setText( |
| 86 | i18n("The main part of this document is secured " |
| 87 | "with SSL, but some parts are not." )); |
| 88 | } |
| 89 | } else { |
| 90 | if (d->auxPartsEncrypted) { |
| 91 | d->ui.encryptionIndicator->setPixmap(QIcon::fromTheme(QStringLiteral("security-medium" )).pixmap(extent: KIconLoader::SizeSmallMedium)); |
| 92 | d->ui.explanation->setText( |
| 93 | i18n("Some of this document is secured with SSL, " |
| 94 | "but the main part is not." )); |
| 95 | } else { |
| 96 | d->ui.encryptionIndicator->setPixmap(QIcon::fromTheme(QStringLiteral("security-low" )).pixmap(extent: KIconLoader::SizeSmallMedium)); |
| 97 | d->ui.explanation->setText(i18n("Current connection is not secured with SSL." )); |
| 98 | } |
| 99 | } |
| 100 | } |
| 101 | |
| 102 | void KSslInfoDialog::setSslInfo(const QList<QSslCertificate> &certificateChain, |
| 103 | const QString &ip, |
| 104 | const QString &host, |
| 105 | const QString &sslProtocol, |
| 106 | const QString &cipher, |
| 107 | int usedBits, |
| 108 | int bits, |
| 109 | const QList<QList<QSslError::SslError>> &validationErrors) |
| 110 | { |
| 111 | d->certificateChain = certificateChain; |
| 112 | d->certificateErrors = validationErrors; |
| 113 | |
| 114 | d->ui.certSelector->clear(); |
| 115 | for (const QSslCertificate &cert : certificateChain) { |
| 116 | QString name; |
| 117 | static const QSslCertificate::SubjectInfo si[] = {QSslCertificate::CommonName, QSslCertificate::Organization, QSslCertificate::OrganizationalUnitName}; |
| 118 | for (int j = 0; j < 3 && name.isEmpty(); j++) { |
| 119 | name = cert.subjectInfo(info: si[j]).join(sep: QLatin1String(", " )); |
| 120 | } |
| 121 | d->ui.certSelector->addItem(atext: name); |
| 122 | } |
| 123 | if (certificateChain.size() < 2) { |
| 124 | d->ui.certSelector->setEnabled(false); |
| 125 | } |
| 126 | connect(sender: d->ui.certSelector, signal: &QComboBox::currentIndexChanged, context: this, slot: &KSslInfoDialog::displayFromChain); |
| 127 | if (d->certificateChain.isEmpty()) { |
| 128 | d->certificateChain.append(t: QSslCertificate()); |
| 129 | } |
| 130 | displayFromChain(0); |
| 131 | |
| 132 | d->ui.ip->setText(ip); |
| 133 | d->ui.address->setText(host); |
| 134 | d->ui.sslVersion->setText(sslProtocol); |
| 135 | |
| 136 | const QStringList cipherInfo = cipher.split(sep: QLatin1Char('\n'), behavior: Qt::SkipEmptyParts); |
| 137 | if (cipherInfo.size() >= 4) { |
| 138 | d->ui.encryption->setText(i18nc("%1, using %2 bits of a %3 bit key" , |
| 139 | "%1, %2 %3" , |
| 140 | cipherInfo[0], |
| 141 | i18ncp("Part of: %1, using %2 bits of a %3 bit key" , "using %1 bit" , "using %1 bits" , usedBits), |
| 142 | i18ncp("Part of: %1, using %2 bits of a %3 bit key" , "of a %1 bit key" , "of a %1 bit key" , bits))); |
| 143 | d->ui.details->setText(QStringLiteral("Auth = %1, Kx = %2, MAC = %3" ).arg(args: cipherInfo[1], args: cipherInfo[2], args: cipherInfo[3])); |
| 144 | } else { |
| 145 | d->ui.encryption->setText(QString()); |
| 146 | d->ui.details->setText(QString()); |
| 147 | } |
| 148 | } |
| 149 | |
| 150 | void KSslInfoDialog::displayFromChain(int i) |
| 151 | { |
| 152 | const QSslCertificate &cert = d->certificateChain[i]; |
| 153 | |
| 154 | QString trusted; |
| 155 | const QList<QSslError::SslError> errorsList = d->certificateErrors[i]; |
| 156 | if (!errorsList.isEmpty()) { |
| 157 | trusted = i18nc("The certificate is not trusted" , "NO, there were errors:" ); |
| 158 | for (QSslError::SslError e : errorsList) { |
| 159 | QSslError classError(e); |
| 160 | trusted += QLatin1Char('\n') + classError.errorString(); |
| 161 | } |
| 162 | } else { |
| 163 | trusted = i18nc("The certificate is trusted" , "Yes" ); |
| 164 | } |
| 165 | d->ui.trusted->setText(trusted); |
| 166 | |
| 167 | QString vp = |
| 168 | i18nc("%1 is the effective date of the certificate, %2 is the expiry date" , "%1 to %2" , cert.effectiveDate().toString(), cert.expiryDate().toString()); |
| 169 | d->ui.validityPeriod->setText(vp); |
| 170 | |
| 171 | d->ui.serial->setText(QString::fromUtf8(ba: cert.serialNumber())); |
| 172 | d->ui.digest->setText(QString::fromUtf8(ba: cert.digest().toHex())); |
| 173 | d->ui.sha1Digest->setText(QString::fromUtf8(ba: cert.digest(algorithm: QCryptographicHash::Sha1).toHex())); |
| 174 | |
| 175 | d->subject->setCertificate(cert, party: KSslCertificateBox::Subject); |
| 176 | d->issuer->setCertificate(cert, party: KSslCertificateBox::Issuer); |
| 177 | } |
| 178 | |
| 179 | // static |
| 180 | QList<QList<QSslError::SslError>> KSslInfoDialog::certificateErrorsFromString(const QString &) |
| 181 | { |
| 182 | const QStringList sl = errorsString.split(sep: QLatin1Char('\n'), behavior: Qt::KeepEmptyParts); |
| 183 | QList<QList<QSslError::SslError>> ret; |
| 184 | ret.reserve(asize: sl.size()); |
| 185 | for (const QString &s : sl) { |
| 186 | QList<QSslError::SslError> certErrors; |
| 187 | const QStringList sl2 = s.split(sep: QLatin1Char('\t'), behavior: Qt::SkipEmptyParts); |
| 188 | for (const QString &s2 : sl2) { |
| 189 | bool didConvert; |
| 190 | QSslError::SslError error = static_cast<QSslError::SslError>(s2.toInt(ok: &didConvert)); |
| 191 | if (didConvert) { |
| 192 | certErrors.append(t: error); |
| 193 | } |
| 194 | } |
| 195 | ret.append(t: certErrors); |
| 196 | } |
| 197 | return ret; |
| 198 | } |
| 199 | |
| 200 | #include "moc_ksslinfodialog.cpp" |
| 201 | |