diff options
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++) { |