diff options
author | Jeremy Lainé <jeremy.laine@m4x.org> | 2014-08-23 12:46:05 +0200 |
---|---|---|
committer | Oliver Wolff <oliver.wolff@digia.com> | 2014-08-24 06:01:05 +0200 |
commit | 4040bc21ab09408cb6f188c4c747fb55499d9f5c (patch) | |
tree | 756a57c1a0f7590082d55e9d76467991bf375bbc /src/network/ssl/qsslcertificate.cpp | |
parent | 2d0072b0b3992b82385c72c2dad7e754d35e0bf7 (diff) |
Added QAsn1Element
This element can be used for backends that do not offer all the
information that is needed when implementing a ssl certificate backend.
WinRT and the SecureTransport lack functionality in this area for
example.
The sources and tests are added for ssl and openssl configurations in order
to be tested. The condition for adding these can be changed as soon
as they are used by an actual implementation
Change-Id: I2b836133105afdc178bf3b1ee7d732bea069effa
Reviewed-by: Andrew Knight <andrew.knight@digia.com>
Diffstat (limited to 'src/network/ssl/qsslcertificate.cpp')
-rw-r--r-- | src/network/ssl/qsslcertificate.cpp | 150 |
1 files changed, 150 insertions, 0 deletions
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++) { |