Skip to content
This repository was archived by the owner on Apr 28, 2022. It is now read-only.

Commit c2dc492

Browse files
committed
[systemsettings] Allow certificate model to decode in-memory PEMs. Contributes to JB#40089
The certificate model code allows an X509 certificate (or bundle of certificates) to be loaded from disk so they can be used to the UI (e.g. for displaying certificate details). This change allows PEM data to be provided as a QByteArray, rather than as a file, allowing certificates store in memory to be accessed by the UI as well, without having to generate a temprory file. This change also exposes certificate summary info, providing some addition properties that help when displaying a summary of the certificate.
1 parent 4bbaa50 commit c2dc492

File tree

2 files changed

+74
-24
lines changed

2 files changed

+74
-24
lines changed

src/certificatemodel.cpp

Lines changed: 65 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
2-
* Copyright (C) 2016 Jolla Ltd.
3-
* COntact: Matt Vogt <[email protected]>
2+
* Copyright (c) 2016 - 2019 Jolla Ltd.
3+
* Copyright (c) 2019 Open Mobile Platform LLC.
44
*
55
* You may use this file under the terms of the BSD license as follows:
66
*
@@ -426,28 +426,47 @@ struct PKCS7File
426426
if (BIO_read_filename(input, const_cast<char *>(filename.constData())) <= 0) {
427427
qWarning() << "Unable to open PKCS7 file:" << path;
428428
} else {
429-
STACK_OF(X509_INFO) *certificateStack = PEM_X509_INFO_read_bio(input, NULL, NULL, NULL);
430-
if (!certificateStack) {
431-
qWarning() << "Unable to read PKCS7 file:" << path;
432-
} else {
433-
while (sk_X509_INFO_num(certificateStack)) {
434-
X509_INFO *certificateInfo = sk_X509_INFO_shift(certificateStack);
435-
if (certificateInfo->x509 != NULL) {
436-
certs.append(certificateInfo->x509);
437-
certificateInfo->x509 = NULL;
438-
}
439-
X509_INFO_free(certificateInfo);
440-
}
441-
442-
sk_X509_INFO_free(certificateStack);
443-
}
429+
read_pem_from_bio(input);
444430
}
445431

446432
BIO_free(input);
447433
}
448434
}
449435
}
450436

437+
explicit PKCS7File(const QByteArray &pem)
438+
{
439+
if (!isValid()) {
440+
qWarning() << "Unable to prepare X509 certificates structure";
441+
} else {
442+
BIO *input = BIO_new_mem_buf(pem.constData(), pem.length());
443+
if (!input) {
444+
qWarning() << "Unable to allocate new BIO while importing in-memory PEM";
445+
} else {
446+
read_pem_from_bio(input);
447+
BIO_free(input);
448+
}
449+
}
450+
}
451+
452+
void read_pem_from_bio(BIO *input) {
453+
STACK_OF(X509_INFO) *certificateStack = PEM_X509_INFO_read_bio(input, NULL, NULL, NULL);
454+
if (!certificateStack) {
455+
qWarning() << "Unable to read PKCS7 data";
456+
} else {
457+
while (sk_X509_INFO_num(certificateStack)) {
458+
X509_INFO *certificateInfo = sk_X509_INFO_shift(certificateStack);
459+
if (certificateInfo->x509 != NULL) {
460+
certs.append(certificateInfo->x509);
461+
certificateInfo->x509 = NULL;
462+
}
463+
X509_INFO_free(certificateInfo);
464+
}
465+
466+
sk_X509_INFO_free(certificateStack);
467+
}
468+
}
469+
451470
~PKCS7File()
452471
{
453472
}
@@ -498,11 +517,17 @@ class LibCrypto
498517
static Initializer init;
499518

500519
public:
501-
static QList<Certificate> getCertificates(const QString &bundlePath)
520+
template<class T>
521+
static QList<Certificate> getCertificates(const T &bundleData)
502522
{
503-
QList<Certificate> certificates;
523+
PKCS7File bundle(bundleData);
504524

505-
PKCS7File bundle(bundlePath);
525+
return bundleToCertificates(bundle);
526+
}
527+
private:
528+
static QList<Certificate> bundleToCertificates(PKCS7File &bundle)
529+
{
530+
QList<Certificate> certificates;
506531
if (bundle.isValid() && bundle.count() > 0) {
507532
certificates.reserve(bundle.count());
508533
bundle.getCertificates().for_each([&certificates](const X509Certificate &cert) {
@@ -514,6 +539,7 @@ class LibCrypto
514539
}
515540
};
516541

542+
517543
LibCrypto::Initializer LibCrypto::init;
518544

519545
const QList<QPair<QString, CertificateModel::BundleType> > &bundlePaths()
@@ -579,9 +605,24 @@ Certificate::Certificate(const X509Certificate &cert)
579605
}
580606
}
581607

608+
// Matches QSslCertificate::issuerDisplayName() introducd in Qt 5.12
609+
// Returns a name that describes the issuer. It returns the CommonName if
610+
// available, otherwise falls back to the Organization or the first
611+
// OrganizationalUnitName.
612+
m_issuerDisplayName = cert.issuerElement(NID_commonName);
613+
if (m_issuerDisplayName.isEmpty()) {
614+
m_issuerDisplayName = cert.issuerElement(NID_countryName);
615+
}
616+
if (m_issuerDisplayName.isEmpty()) {
617+
m_issuerDisplayName = cert.issuerElement(NID_organizationName);
618+
}
619+
582620
// Populate the details map
583621
m_details.insert(QStringLiteral("Version"), QVariant(cert.version()));
584622
m_details.insert(QStringLiteral("SerialNumber"), QVariant(cert.serialNumber()));
623+
m_details.insert(QStringLiteral("SubjectDisplayName"), QVariant(m_primaryName));
624+
m_details.insert(QStringLiteral("OrganizationName"), QVariant(m_organizationName));
625+
m_details.insert(QStringLiteral("IssuerDisplayName"), QVariant(m_issuerDisplayName));
585626

586627
QVariantMap validity;
587628
validity.insert(QStringLiteral("NotBefore"), QVariant(cert.notBefore()));
@@ -753,3 +794,7 @@ QList<Certificate> CertificateModel::getCertificates(const QString &bundlePath)
753794
return LibCrypto::getCertificates(bundlePath);
754795
}
755796

797+
QList<Certificate> CertificateModel::getCertificates(const QByteArray &pem)
798+
{
799+
return LibCrypto::getCertificates(pem);
800+
}

src/certificatemodel.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
2-
* Copyright (C) 2016 Jolla Ltd.
3-
* Contact: Matt Vogt <[email protected]>
2+
* Copyright (c) 2016 - 2019 Jolla Ltd.
3+
* Copyright (c) 2019 Open Mobile Platform LLC.
44
*
55
* You may use this file under the terms of the BSD license as follows:
66
*
@@ -38,7 +38,7 @@
3838
#include <QList>
3939
#include <QVariantMap>
4040

41-
#include <systemsettingsglobal.h>
41+
#include "systemsettingsglobal.h"
4242

4343

4444
struct X509Certificate;
@@ -60,6 +60,8 @@ class SYSTEMSETTINGS_EXPORT Certificate
6060

6161
QVariantMap details() const { return m_details; }
6262

63+
QString issuerDisplayName() const { return m_issuerDisplayName; }
64+
6365
private:
6466
QString m_commonName;
6567
QString m_countryName;
@@ -71,6 +73,8 @@ class SYSTEMSETTINGS_EXPORT Certificate
7173
QDateTime m_notValidBefore;
7274
QDateTime m_notValidAfter;
7375

76+
QString m_issuerDisplayName;
77+
7478
QVariantMap m_details;
7579
};
7680

@@ -115,8 +119,9 @@ class SYSTEMSETTINGS_EXPORT CertificateModel: public QAbstractListModel
115119
virtual QVariant data(const QModelIndex &index, int role) const;
116120

117121
static QList<Certificate> getCertificates(const QString &bundlePath);
122+
static QList<Certificate> getCertificates(const QByteArray &pem);
118123

119-
signals:
124+
Q_SIGNALS:
120125
void bundleTypeChanged();
121126
void bundlePathChanged();
122127

0 commit comments

Comments
 (0)