summaryrefslogtreecommitdiffstats
path: root/src/network
diff options
context:
space:
mode:
Diffstat (limited to 'src/network')
-rw-r--r--src/network/ssl/qasn1element.cpp291
-rw-r--r--src/network/ssl/qasn1element_p.h116
-rw-r--r--src/network/ssl/qsslcertificate.cpp150
-rw-r--r--src/network/ssl/qsslcertificate_p.h9
-rw-r--r--src/network/ssl/ssl.pri6
5 files changed, 570 insertions, 2 deletions
diff --git a/src/network/ssl/qasn1element.cpp b/src/network/ssl/qasn1element.cpp
new file mode 100644
index 0000000000..d282a02827
--- /dev/null
+++ b/src/network/ssl/qasn1element.cpp
@@ -0,0 +1,291 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Jeremy Lainé <jeremy.laine@m4x.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "qasn1element_p.h"
+
+#include <QtCore/qdatastream.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qvector.h>
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+typedef QMap<QByteArray, QByteArray> OidNameMap;
+static OidNameMap createOidMap()
+{
+ OidNameMap oids;
+ // used by unit tests
+ oids.insert(oids.end(), QByteArrayLiteral("0.9.2342.19200300.100.1.5"), QByteArrayLiteral("favouriteDrink"));
+ oids.insert(oids.end(), QByteArrayLiteral("1.2.840.113549.1.9.1"), QByteArrayLiteral("emailAddress"));
+ oids.insert(oids.end(), QByteArrayLiteral("2.5.4.10"), QByteArrayLiteral("O"));
+ oids.insert(oids.end(), QByteArrayLiteral("2.5.4.11"), QByteArrayLiteral("OU"));
+ oids.insert(oids.end(), QByteArrayLiteral("2.5.4.12"), QByteArrayLiteral("title"));
+ oids.insert(oids.end(), QByteArrayLiteral("2.5.4.13"), QByteArrayLiteral("description"));
+ oids.insert(oids.end(), QByteArrayLiteral("2.5.4.17"), QByteArrayLiteral("postalCode"));
+ oids.insert(oids.end(), QByteArrayLiteral("2.5.4.3"), QByteArrayLiteral("CN"));
+ oids.insert(oids.end(), QByteArrayLiteral("2.5.4.4"), QByteArrayLiteral("SN"));
+ oids.insert(oids.end(), QByteArrayLiteral("2.5.4.41"), QByteArrayLiteral("name"));
+ oids.insert(oids.end(), QByteArrayLiteral("2.5.4.42"), QByteArrayLiteral("GN"));
+ oids.insert(oids.end(), QByteArrayLiteral("2.5.4.43"), QByteArrayLiteral("initials"));
+ oids.insert(oids.end(), QByteArrayLiteral("2.5.4.46"), QByteArrayLiteral("dnQualifier"));
+ oids.insert(oids.end(), QByteArrayLiteral("2.5.4.5"), QByteArrayLiteral("serialNumber"));
+ oids.insert(oids.end(), QByteArrayLiteral("2.5.4.6"), QByteArrayLiteral("C"));
+ oids.insert(oids.end(), QByteArrayLiteral("2.5.4.7"), QByteArrayLiteral("L"));
+ oids.insert(oids.end(), QByteArrayLiteral("2.5.4.8"), QByteArrayLiteral("ST"));
+ oids.insert(oids.end(), QByteArrayLiteral("2.5.4.9"), QByteArrayLiteral("street"));
+ return oids;
+}
+Q_GLOBAL_STATIC_WITH_ARGS(OidNameMap, oidNameMap, (createOidMap()))
+
+QAsn1Element::QAsn1Element(quint8 type, const QByteArray &value)
+ : mType(type)
+ , mValue(value)
+{
+}
+
+bool QAsn1Element::read(QDataStream &stream)
+{
+ // type
+ quint8 tmpType;
+ stream >> tmpType;
+ if (!tmpType)
+ return false;
+
+ // length
+ qint64 length = 0;
+ quint8 first;
+ stream >> first;
+ if (first & 0x80) {
+ // long form
+ const quint8 bytes = (first & 0x7f);
+ if (bytes > 7)
+ return false;
+
+ quint8 b;
+ for (int i = 0; i < bytes; i++) {
+ stream >> b;
+ length = (length << 8) | b;
+ }
+ } else {
+ // short form
+ length = (first & 0x7f);
+ }
+
+ // value
+ QByteArray tmpValue;
+ tmpValue.resize(length);
+ int count = stream.readRawData(tmpValue.data(), tmpValue.size());
+ if (count != length)
+ return false;
+
+ mType = tmpType;
+ mValue.swap(tmpValue);
+ return true;
+}
+
+bool QAsn1Element::read(const QByteArray &data)
+{
+ QDataStream stream(data);
+ return read(stream);
+}
+
+void QAsn1Element::write(QDataStream &stream) const
+{
+ // type
+ stream << mType;
+
+ // length
+ qint64 length = mValue.size();
+ if (length >= 128) {
+ // long form
+ quint8 encodedLength = 0x80;
+ QByteArray ba;
+ while (length) {
+ ba.prepend(quint8((length & 0xff)));
+ length >>= 8;
+ encodedLength += 1;
+ }
+ stream << encodedLength;
+ stream.writeRawData(ba.data(), ba.size());
+ } else {
+ // short form
+ stream << quint8(length);
+ }
+
+ // value
+ stream.writeRawData(mValue.data(), mValue.size());
+}
+
+QAsn1Element QAsn1Element::fromInteger(unsigned int val)
+{
+ QAsn1Element elem(QAsn1Element::IntegerType);
+ while (val > 127) {
+ elem.mValue.prepend(val & 0xff);
+ val >>= 8;
+ }
+ elem.mValue.prepend(val & 0x7f);
+ return elem;
+}
+
+QAsn1Element QAsn1Element::fromVector(const QVector<QAsn1Element> &items)
+{
+ QAsn1Element seq;
+ seq.mType = SequenceType;
+ QDataStream stream(&seq.mValue, QIODevice::WriteOnly);
+ for (QVector<QAsn1Element>::const_iterator it = items.cbegin(), end = items.cend(); it != end; ++it)
+ it->write(stream);
+ return seq;
+}
+
+QAsn1Element QAsn1Element::fromObjectId(const QByteArray &id)
+{
+ QAsn1Element elem;
+ elem.mType = ObjectIdentifierType;
+ QList<QByteArray> bits = id.split('.');
+ Q_ASSERT(bits.size() > 2);
+ elem.mValue += quint8((bits[0].toUInt() * 40 + bits[1].toUInt()));
+ for (int i = 2; i < bits.size(); ++i) {
+ char buffer[std::numeric_limits<unsigned int>::digits / 7 + 2];
+ char *pBuffer = buffer + sizeof(buffer);
+ *--pBuffer = '\0';
+ unsigned int node = bits[i].toUInt();
+ *--pBuffer = quint8((node & 0x7f));
+ node >>= 7;
+ while (node) {
+ *--pBuffer = quint8(((node & 0x7f) | 0x80));
+ node >>= 7;
+ }
+ elem.mValue += pBuffer;
+ }
+ return elem;
+}
+
+QDateTime QAsn1Element::toDateTime() const
+{
+ if (mValue.endsWith('Z')) {
+ if (mType == UtcTimeType && mValue.size() == 13)
+ return QDateTime(QDate(2000 + mValue.mid(0, 2).toInt(),
+ mValue.mid(2, 2).toInt(),
+ mValue.mid(4, 2).toInt()),
+ QTime(mValue.mid(6, 2).toInt(),
+ mValue.mid(8, 2).toInt(),
+ mValue.mid(10, 2).toInt()),
+ Qt::UTC);
+ else if (mType == GeneralizedTimeType && mValue.size() == 15)
+ return QDateTime(QDate(mValue.mid(0, 4).toInt(),
+ mValue.mid(4, 2).toInt(),
+ mValue.mid(6, 2).toInt()),
+ QTime(mValue.mid(8, 2).toInt(),
+ mValue.mid(10, 2).toInt(),
+ mValue.mid(12, 2).toInt()),
+ Qt::UTC);
+ }
+ return QDateTime();
+}
+
+QMultiMap<QByteArray, QString> QAsn1Element::toInfo() const
+{
+ QMultiMap<QByteArray, QString> info;
+ QAsn1Element elem;
+ QDataStream issuerStream(mValue);
+ while (elem.read(issuerStream) && elem.mType == QAsn1Element::SetType) {
+ QAsn1Element issuerElem;
+ QDataStream setStream(elem.mValue);
+ if (issuerElem.read(setStream) && issuerElem.mType == QAsn1Element::SequenceType) {
+ QVector<QAsn1Element> elems = issuerElem.toVector();
+ if (elems.size() == 2) {
+ const QByteArray key = elems.front().toObjectName();
+ if (!key.isEmpty())
+ info.insert(key, elems.back().toString());
+ }
+ }
+ }
+ return info;
+}
+
+QVector<QAsn1Element> QAsn1Element::toVector() const
+{
+ QVector<QAsn1Element> items;
+ if (mType == SequenceType) {
+ QAsn1Element elem;
+ QDataStream stream(mValue);
+ while (elem.read(stream))
+ items << elem;
+ }
+ return items;
+}
+
+QByteArray QAsn1Element::toObjectId() const
+{
+ QByteArray key;
+ if (mType == ObjectIdentifierType && !mValue.isEmpty()) {
+ quint8 b = mValue[0];
+ key += QByteArray::number(b / 40) + '.' + QByteArray::number (b % 40);
+ unsigned int val = 0;
+ for (int i = 1; i < mValue.size(); ++i) {
+ b = mValue[i];
+ val = (val << 7) | (b & 0x7f);
+ if (!(b & 0x80)) {
+ key += '.' + QByteArray::number(val);
+ val = 0;
+ }
+ }
+ }
+ return key;
+}
+
+QByteArray QAsn1Element::toObjectName() const
+{
+ QByteArray key = toObjectId();
+ return oidNameMap->value(key, key);
+}
+
+QString QAsn1Element::toString() const
+{
+ if (mType == PrintableStringType || mType == TeletexStringType)
+ return QString::fromLatin1(mValue, mValue.size());
+ if (mType == Utf8StringType)
+ return QString::fromUtf8(mValue, mValue.size());
+ return QString();
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/ssl/qasn1element_p.h b/src/network/ssl/qasn1element_p.h
new file mode 100644
index 0000000000..6b3179ac35
--- /dev/null
+++ b/src/network/ssl/qasn1element_p.h
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Jeremy Lainé <jeremy.laine@m4x.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QASN1ELEMENT_P_H
+#define QASN1ELEMENT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the QLibrary class. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qdatetime.h>
+#include <QtCore/qmap.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_AUTOTEST_EXPORT QAsn1Element
+{
+public:
+ enum ElementType {
+ // universal
+ IntegerType = 0x02,
+ BitStringType = 0x03,
+ OctetStringType = 0x04,
+ NullType = 0x05,
+ ObjectIdentifierType = 0x06,
+ Utf8StringType = 0x0c,
+ PrintableStringType = 0x13,
+ TeletexStringType = 0x14,
+ UtcTimeType = 0x17,
+ GeneralizedTimeType = 0x18,
+ SequenceType = 0x30,
+ SetType = 0x31,
+
+ // application
+ Rfc822NameType = 0x81,
+ DnsNameType = 0x82,
+
+ // context specific
+ Context0Type = 0xA0,
+ Context3Type = 0xA3
+ };
+
+ explicit QAsn1Element(quint8 type = 0, const QByteArray &value = QByteArray());
+ bool read(QDataStream &data);
+ bool read(const QByteArray &data);
+ void write(QDataStream &data) const;
+
+ static QAsn1Element fromInteger(unsigned int val);
+ static QAsn1Element fromVector(const QVector<QAsn1Element> &items);
+ static QAsn1Element fromObjectId(const QByteArray &id);
+
+ QDateTime toDateTime() const;
+ QMultiMap<QByteArray, QString> toInfo() const;
+ QVector<QAsn1Element> toVector() const;
+ QByteArray toObjectId() const;
+ QByteArray toObjectName() const;
+ QString toString() const;
+
+ quint8 type() const { return mType; }
+ QByteArray value() const { return mValue; }
+
+private:
+ quint8 mType;
+ QByteArray mValue;
+};
+Q_DECLARE_TYPEINFO(QAsn1Element, Q_MOVABLE_TYPE);
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/network/ssl/qsslcertificate.cpp b/src/network/ssl/qsslcertificate.cpp
index 47ea3343ea..bae78f4347 100644
--- a/src/network/ssl/qsslcertificate.cpp
+++ b/src/network/ssl/qsslcertificate.cpp
@@ -122,6 +122,7 @@
#include "qsslcertificate.h"
#include "qsslcertificate_p.h"
+#include "qasn1element_p.h"
#include "qsslkey_p.h"
#include <QtCore/qdir.h>
@@ -641,6 +642,155 @@ static const char *certificate_blacklist[] = {
0
};
+bool QSslCertificatePrivate::parse(const QByteArray &data)
+{
+#ifndef QT_NO_OPENSSL
+ Q_UNUSED(data);
+#else
+ QAsn1Element root;
+
+ QDataStream dataStream(data);
+ if (!root.read(dataStream) || root.type() != QAsn1Element::SequenceType)
+ return false;
+
+ QDataStream rootStream(root.value());
+ QAsn1Element cert;
+ if (!cert.read(rootStream) || cert.type() != QAsn1Element::SequenceType)
+ return false;
+
+ // version or serial number
+ QAsn1Element elem;
+ QDataStream certStream(cert.value());
+ if (!elem.read(certStream))
+ return false;
+
+ if (elem.type() == QAsn1Element::Context0Type) {
+ QDataStream versionStream(elem.value());
+ if (!elem.read(versionStream) || elem.type() != QAsn1Element::IntegerType)
+ return false;
+
+ versionString = QByteArray::number(elem.value()[0] + 1);
+ if (!elem.read(certStream))
+ return false;
+ } else {
+ versionString = QByteArray::number(1);
+ }
+
+ // serial number
+ if (elem.type() != QAsn1Element::IntegerType)
+ return false;
+
+ QByteArray hexString;
+ hexString.reserve(elem.value().size() * 3);
+ for (int a = 0; a < elem.value().size(); ++a) {
+ const quint8 b = elem.value().at(a);
+ if (b || !hexString.isEmpty()) { // skip leading zeros
+ hexString += QByteArray::number(b, 16).rightJustified(2, '0');
+ hexString += ':';
+ }
+ }
+ hexString.chop(1);
+ serialNumberString = hexString;
+
+ // algorithm ID
+ if (!elem.read(certStream) || elem.type() != QAsn1Element::SequenceType)
+ return false;
+
+ //qDebug() << "algorithm ID" << elem.type() << elem.length << elem.value().toHex();
+
+ // issuer info
+ if (!elem.read(certStream) || elem.type() != QAsn1Element::SequenceType)
+ return false;
+
+ QByteArray issuerDer = data.mid(dataStream.device()->pos() - elem.value().length(), elem.value().length());
+ issuerInfo = elem.toInfo();
+
+ // validity period
+ if (!elem.read(certStream) || elem.type() != QAsn1Element::SequenceType)
+ return false;
+
+ QDataStream validityStream(elem.value());
+ if (!elem.read(validityStream) || (elem.type() != QAsn1Element::UtcTimeType && elem.type() != QAsn1Element::GeneralizedTimeType))
+ return false;
+
+ notValidBefore = elem.toDateTime();
+ if (!elem.read(validityStream) || (elem.type() != QAsn1Element::UtcTimeType && elem.type() != QAsn1Element::GeneralizedTimeType))
+ return false;
+
+ notValidAfter = elem.toDateTime();
+
+ // subject name
+ if (!elem.read(certStream) || elem.type() != QAsn1Element::SequenceType)
+ return false;
+
+ QByteArray subjectDer = data.mid(dataStream.device()->pos() - elem.value().length(), elem.value().length());
+ subjectInfo = elem.toInfo();
+ subjectMatchesIssuer = issuerDer == subjectDer;
+
+ // public key
+ qint64 keyStart = certStream.device()->pos();
+ if (!elem.read(certStream) || elem.type() != QAsn1Element::SequenceType)
+ return false;
+
+ publicKeyDerData.resize(certStream.device()->pos() - keyStart);
+ QDataStream keyStream(elem.value());
+ if (!elem.read(keyStream) || elem.type() != QAsn1Element::SequenceType)
+ return false;
+
+
+ // key algorithm
+ if (!elem.read(elem.value()) || elem.type() != QAsn1Element::ObjectIdentifierType)
+ return false;
+
+ const QByteArray oid = elem.toObjectId();
+ if (oid == "1.2.840.113549.1.1.1")
+ publicKeyAlgorithm = QSsl::Rsa;
+ else if (oid == "1.2.840.10040.4.1")
+ publicKeyAlgorithm = QSsl::Dsa;
+ else
+ publicKeyAlgorithm = QSsl::Opaque;
+
+ certStream.device()->seek(keyStart);
+ certStream.readRawData(publicKeyDerData.data(), publicKeyDerData.size());
+
+ // extensions
+ while (elem.read(certStream)) {
+ if (elem.type() == QAsn1Element::Context3Type) {
+ if (elem.read(elem.value()) && elem.type() == QAsn1Element::SequenceType) {
+ QDataStream extStream(elem.value());
+ while (elem.read(extStream) && elem.type() == QAsn1Element::SequenceType) {
+ QAsn1Element oidElem, valElem;
+ QDataStream seqStream(elem.value());
+ if (oidElem.read(seqStream) && oidElem.type() == QAsn1Element::ObjectIdentifierType &&
+ valElem.read(seqStream) && valElem.type() == QAsn1Element::OctetStringType) {
+ // alternative name
+ if (oidElem.toObjectId() == QByteArray("2.5.29.17")) {
+ QAsn1Element sanElem;
+ if (sanElem.read(valElem.value()) && sanElem.type() == QAsn1Element::SequenceType) {
+ QDataStream nameStream(sanElem.value());
+ QAsn1Element nameElem;
+ while (nameElem.read(nameStream)) {
+ if (nameElem.type() == QAsn1Element::Rfc822NameType) {
+ subjectAlternativeNames.insert(QSsl::EmailEntry, QString::fromLatin1(nameElem.value(), nameElem.value().size()));
+ } else if (nameElem.type() == QAsn1Element::DnsNameType) {
+ subjectAlternativeNames.insert(QSsl::DnsEntry, QString::fromLatin1(nameElem.value(), nameElem.value().size()));
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ derData = data.left(dataStream.device()->pos());
+ null = false;
+
+#endif // QT_NO_OPENSSL
+ return true;
+}
+
bool QSslCertificatePrivate::isBlacklisted(const QSslCertificate &certificate)
{
for (int a = 0; certificate_blacklist[a] != 0; a++) {
diff --git a/src/network/ssl/qsslcertificate_p.h b/src/network/ssl/qsslcertificate_p.h
index 4bee9edcb9..0eeff0db41 100644
--- a/src/network/ssl/qsslcertificate_p.h
+++ b/src/network/ssl/qsslcertificate_p.h
@@ -99,9 +99,18 @@ public:
QDateTime notValidAfter;
QDateTime notValidBefore;
+#ifdef QT_NO_OPENSSL
+ bool subjectMatchesIssuer;
+ QSsl::KeyAlgorithm publicKeyAlgorithm;
+ QByteArray publicKeyDerData;
+ QMultiMap<QSsl::AlternativeNameEntryType, QString> subjectAlternativeNames;
+
+ QByteArray derData;
+#endif
X509 *x509;
void init(const QByteArray &data, QSsl::EncodingFormat format);
+ bool parse(const QByteArray &data);
static QByteArray asn1ObjectId(ASN1_OBJECT *object);
static QByteArray asn1ObjectName(ASN1_OBJECT *object);
diff --git a/src/network/ssl/ssl.pri b/src/network/ssl/ssl.pri
index 0fbeb1d369..f7dceeb579 100644
--- a/src/network/ssl/ssl.pri
+++ b/src/network/ssl/ssl.pri
@@ -1,6 +1,7 @@
# OpenSSL support; compile in QSslSocket.
contains(QT_CONFIG, ssl) | contains(QT_CONFIG, openssl) | contains(QT_CONFIG, openssl-linked) {
- HEADERS += ssl/qssl.h \
+ HEADERS += ssl/qasn1element_p.h \
+ ssl/qssl.h \
ssl/qsslcertificate.h \
ssl/qsslcertificate_p.h \
ssl/qsslconfiguration.h \
@@ -14,7 +15,8 @@ contains(QT_CONFIG, ssl) | contains(QT_CONFIG, openssl) | contains(QT_CONFIG, op
ssl/qsslsocket_p.h \
ssl/qsslcertificateextension.h \
ssl/qsslcertificateextension_p.h
- SOURCES += ssl/qssl.cpp \
+ SOURCES += ssl/qasn1element.cpp \
+ ssl/qssl.cpp \
ssl/qsslcertificate.cpp \
ssl/qsslconfiguration.cpp \
ssl/qsslcipher.cpp \