summaryrefslogtreecommitdiffstats
path: root/src/network/ssl/qsslcertificate.cpp
diff options
context:
space:
mode:
authorJeremy Lainé <jeremy.laine@m4x.org>2014-08-23 12:46:05 +0200
committerOliver Wolff <oliver.wolff@digia.com>2014-08-24 06:01:05 +0200
commit4040bc21ab09408cb6f188c4c747fb55499d9f5c (patch)
tree756a57c1a0f7590082d55e9d76467991bf375bbc /src/network/ssl/qsslcertificate.cpp
parent2d0072b0b3992b82385c72c2dad7e754d35e0bf7 (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.cpp150
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++) {