File indexing completed on 2023-11-26 07:34:15
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"