157 lines
5.5 KiB
C++
157 lines
5.5 KiB
C++
// Copyright 2007-2023 The Mumble Developers. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license
|
|
// that can be found in the LICENSE file at the root of the
|
|
// Mumble source tree or at <https://www.mumble.info/LICENSE>.
|
|
|
|
#include "ViewCert.h"
|
|
#include "QtUtils.h"
|
|
|
|
#include <QtNetwork/QSslKey>
|
|
#include <QtWidgets/QDialogButtonBox>
|
|
#include <QtWidgets/QGroupBox>
|
|
#include <QtWidgets/QHBoxLayout>
|
|
#include <QtWidgets/QListWidget>
|
|
#include <QtWidgets/QVBoxLayout>
|
|
|
|
static QStringList processQSslCertificateInfo(QStringList in) {
|
|
QStringList list;
|
|
foreach (QString str, in) { list << Mumble::QtUtils::decode_utf8_qssl_string(str); }
|
|
return list;
|
|
}
|
|
|
|
static void addQSslCertificateInfo(QStringList &l, const QString &label, const QStringList &items) {
|
|
foreach (const QString &item, items) { l << QString(QLatin1String("%1: %2")).arg(label, item); }
|
|
}
|
|
|
|
static QString certificateFriendlyName(const QSslCertificate &cert) {
|
|
QStringList cnList = processQSslCertificateInfo(cert.subjectInfo(QSslCertificate::CommonName));
|
|
QStringList orgList = processQSslCertificateInfo(cert.subjectInfo(QSslCertificate::Organization));
|
|
|
|
QString cn;
|
|
if (cnList.count() > 0) {
|
|
cn = cnList.at(0);
|
|
}
|
|
|
|
QString org;
|
|
if (orgList.count() > 0) {
|
|
org = orgList.at(0);
|
|
}
|
|
|
|
return QString(QLatin1String("%1 %2")).arg(cn, org);
|
|
}
|
|
|
|
ViewCert::ViewCert(QList< QSslCertificate > cl, QWidget *p) : QDialog(p) {
|
|
qlCerts = cl;
|
|
|
|
setWindowTitle(tr("Certificate Chain Details"));
|
|
|
|
QHBoxLayout *h;
|
|
QVBoxLayout *v;
|
|
QGroupBox *qcbChain, *qcbDetails;
|
|
|
|
qcbChain = new QGroupBox(tr("Certificate chain"), this);
|
|
h = new QHBoxLayout(qcbChain);
|
|
qlwChain = new QListWidget(qcbChain);
|
|
qlwChain->setObjectName(QLatin1String("Chain"));
|
|
|
|
// load certs into a set as a hacky fix to #2141
|
|
#if QT_VERSION >= 0x050400
|
|
QSet< QSslCertificate > qlCertSet;
|
|
#else
|
|
QList< QSslCertificate > qlCertSet;
|
|
#endif
|
|
foreach (QSslCertificate c, qlCerts) {
|
|
if (!qlCertSet.contains(c)) {
|
|
qlwChain->addItem(certificateFriendlyName(c));
|
|
qlCertSet << c;
|
|
}
|
|
}
|
|
h->addWidget(qlwChain);
|
|
|
|
qcbDetails = new QGroupBox(tr("Certificate details"), this);
|
|
h = new QHBoxLayout(qcbDetails);
|
|
qlwCert = new QListWidget(qcbDetails);
|
|
h->addWidget(qlwCert);
|
|
|
|
QDialogButtonBox *qdbb = new QDialogButtonBox(QDialogButtonBox::Ok, Qt::Horizontal, this);
|
|
|
|
v = new QVBoxLayout(this);
|
|
v->addWidget(qcbChain);
|
|
v->addWidget(qcbDetails);
|
|
v->addWidget(qdbb);
|
|
|
|
QMetaObject::connectSlotsByName(this);
|
|
connect(qdbb, SIGNAL(accepted()), this, SLOT(accept()));
|
|
|
|
resize(510, 300);
|
|
}
|
|
|
|
QString ViewCert::prettifyDigest(QString digest) {
|
|
QString pretty_digest = digest.toUpper();
|
|
int step = 2;
|
|
QChar separator = QChar::fromLatin1(':');
|
|
for (int i = step; i < pretty_digest.size(); i += step + 1) {
|
|
pretty_digest.insert(i, separator);
|
|
}
|
|
return pretty_digest;
|
|
}
|
|
|
|
void ViewCert::on_Chain_currentRowChanged(int idx) {
|
|
qlwCert->clear();
|
|
if ((idx < 0) || (idx >= qlCerts.size()))
|
|
return;
|
|
|
|
QStringList l;
|
|
const QSslCertificate &c = qlCerts.at(idx);
|
|
|
|
addQSslCertificateInfo(l, tr("Common Name"),
|
|
processQSslCertificateInfo(c.subjectInfo(QSslCertificate::CommonName)));
|
|
addQSslCertificateInfo(l, tr("Organization"),
|
|
processQSslCertificateInfo(c.subjectInfo(QSslCertificate::Organization)));
|
|
addQSslCertificateInfo(l, tr("Subunit"),
|
|
processQSslCertificateInfo(c.subjectInfo(QSslCertificate::OrganizationalUnitName)));
|
|
addQSslCertificateInfo(l, tr("Country"), processQSslCertificateInfo(c.subjectInfo(QSslCertificate::CountryName)));
|
|
addQSslCertificateInfo(l, tr("Locality"), processQSslCertificateInfo(c.subjectInfo(QSslCertificate::LocalityName)));
|
|
addQSslCertificateInfo(l, tr("State"),
|
|
processQSslCertificateInfo(c.subjectInfo(QSslCertificate::StateOrProvinceName)));
|
|
l << tr("Valid from: %1").arg(c.effectiveDate().toString());
|
|
l << tr("Valid to: %1").arg(c.expiryDate().toString());
|
|
l << tr("Serial: %1").arg(QString::fromLatin1(c.serialNumber().toHex()));
|
|
l << tr("Public Key: %1 bits %2")
|
|
.arg(c.publicKey().length())
|
|
.arg((c.publicKey().algorithm() == QSsl::Rsa) ? tr("RSA") : tr("DSA"));
|
|
l << tr("Digest (SHA-1): %1").arg(prettifyDigest(QString::fromLatin1(c.digest(QCryptographicHash::Sha1).toHex())));
|
|
l << tr("Digest (SHA-256): %1")
|
|
.arg(prettifyDigest(QString::fromLatin1(c.digest(QCryptographicHash::Sha256).toHex())));
|
|
|
|
const QMultiMap< QSsl::AlternativeNameEntryType, QString > &alts = c.subjectAlternativeNames();
|
|
QMultiMap< QSsl::AlternativeNameEntryType, QString >::const_iterator i;
|
|
|
|
for (i = alts.constBegin(); i != alts.constEnd(); ++i) {
|
|
switch (i.key()) {
|
|
case QSsl::EmailEntry: {
|
|
l << tr("Email: %1").arg(i.value());
|
|
} break;
|
|
case QSsl::DnsEntry: {
|
|
l << tr("DNS: %1").arg(i.value());
|
|
} break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
l << QString();
|
|
l << tr("Issued by:");
|
|
addQSslCertificateInfo(l, tr("Common Name"), processQSslCertificateInfo(c.issuerInfo(QSslCertificate::CommonName)));
|
|
addQSslCertificateInfo(l, tr("Organization"),
|
|
processQSslCertificateInfo(c.issuerInfo(QSslCertificate::Organization)));
|
|
addQSslCertificateInfo(l, tr("Unit Name"),
|
|
processQSslCertificateInfo(c.issuerInfo(QSslCertificate::OrganizationalUnitName)));
|
|
addQSslCertificateInfo(l, tr("Country"), processQSslCertificateInfo(c.issuerInfo(QSslCertificate::CountryName)));
|
|
addQSslCertificateInfo(l, tr("Locality"), processQSslCertificateInfo(c.issuerInfo(QSslCertificate::LocalityName)));
|
|
addQSslCertificateInfo(l, tr("State"),
|
|
processQSslCertificateInfo(c.issuerInfo(QSslCertificate::StateOrProvinceName)));
|
|
|
|
qlwCert->addItems(l);
|
|
}
|