From 2cf935b43e41c6589159536652412dab443ff1f8 Mon Sep 17 00:00:00 2001 From: Richard Moore Date: Sat, 18 Jun 2011 09:22:11 +0100 Subject: Certificates can have each issuer and subject field many times THIS COMMIT BREAKS SOURCE COMPATIBILITY BETWEEN Qt 4 AND Qt 5 Qt4 assumed that there was only one entry of each type in the subject and issuer of a certificate. This is incorrect (eg. you can have many common names). In addition, some of the fields required by RFC3280 were not suppport. This change modifiers the API to return a list of entries of each type and adds support for the missing fields. It also updates the commonname matching code for SSL connections to handle multiple entries. Change-Id: I9457266a205def0a07c13de47094ff56ead42845 Merge-request: 5 Reviewed-on: http://codereview.qt.nokia.com/796 Reviewed-by: Qt Sanity Bot Reviewed-by: Sergio Ahumada --- src/network/ssl/qsslcertificate.cpp | 24 +++++++++++++++--------- src/network/ssl/qsslcertificate.h | 13 ++++++++----- src/network/ssl/qsslsocket_openssl.cpp | 29 ++++++++++++++++++----------- 3 files changed, 41 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/network/ssl/qsslcertificate.cpp b/src/network/ssl/qsslcertificate.cpp index 6100c68a2d..7403590f8c 100644 --- a/src/network/ssl/qsslcertificate.cpp +++ b/src/network/ssl/qsslcertificate.cpp @@ -307,6 +307,9 @@ static QString _q_SubjectInfoToString(QSslCertificate::SubjectInfo info) case QSslCertificate::OrganizationalUnitName: str = QLatin1String("OU"); break; case QSslCertificate::CountryName: str = QLatin1String("C"); break; case QSslCertificate::StateOrProvinceName: str = QLatin1String("ST"); break; + case QSslCertificate::DistinguishedNameQualifier: str = QLatin1String("dnQualifier"); break; + case QSslCertificate::SerialNumber: str = QLatin1String("serialNumber"); break; + case QSslCertificate::EmailAddress: str = QLatin1String("emailAddress"); break; } return str; } @@ -320,14 +323,14 @@ static QString _q_SubjectInfoToString(QSslCertificate::SubjectInfo info) \sa subjectInfo() */ -QString QSslCertificate::issuerInfo(SubjectInfo info) const +QStringList QSslCertificate::issuerInfo(SubjectInfo info) const { // lazy init if (d->issuerInfo.isEmpty() && d->x509) d->issuerInfo = _q_mapFromX509Name(q_X509_get_issuer_name(d->x509)); - return d->issuerInfo.value(_q_SubjectInfoToString(info)); + return d->issuerInfo.values(_q_SubjectInfoToString(info)); } /*! @@ -337,14 +340,14 @@ QString QSslCertificate::issuerInfo(SubjectInfo info) const \sa subjectInfo() */ -QString QSslCertificate::issuerInfo(const QByteArray &tag) const +QStringList QSslCertificate::issuerInfo(const QByteArray &tag) const { // lazy init if (d->issuerInfo.isEmpty() && d->x509) d->issuerInfo = _q_mapFromX509Name(q_X509_get_issuer_name(d->x509)); - return d->issuerInfo.value(QString::fromLatin1(tag)); + return d->issuerInfo.values(QString::fromLatin1(tag)); } /*! @@ -356,14 +359,14 @@ QString QSslCertificate::issuerInfo(const QByteArray &tag) const \sa issuerInfo() */ -QString QSslCertificate::subjectInfo(SubjectInfo info) const +QStringList QSslCertificate::subjectInfo(SubjectInfo info) const { // lazy init if (d->subjectInfo.isEmpty() && d->x509) d->subjectInfo = _q_mapFromX509Name(q_X509_get_subject_name(d->x509)); - return d->subjectInfo.value(_q_SubjectInfoToString(info)); + return d->subjectInfo.values(_q_SubjectInfoToString(info)); } /*! @@ -372,14 +375,14 @@ QString QSslCertificate::subjectInfo(SubjectInfo info) const \sa issuerInfo() */ -QString QSslCertificate::subjectInfo(const QByteArray &tag) const +QStringList QSslCertificate::subjectInfo(const QByteArray &tag) const { // lazy init if (d->subjectInfo.isEmpty() && d->x509) d->subjectInfo = _q_mapFromX509Name(q_X509_get_subject_name(d->x509)); - return d->subjectInfo.value(QString::fromLatin1(tag)); + return d->subjectInfo.values(QString::fromLatin1(tag)); } /*! @@ -711,7 +714,7 @@ static QMap _q_mapFromX509Name(X509_NAME *name) const char *obj = q_OBJ_nid2sn(q_OBJ_obj2nid(q_X509_NAME_ENTRY_get_object(e))); unsigned char *data = 0; int size = q_ASN1_STRING_to_UTF8(&data, q_X509_NAME_ENTRY_get_data(e)); - info[QString::fromUtf8(obj)] = QString::fromUtf8((char*)data, size); + info.insertMulti(QString::fromUtf8(obj), QString::fromUtf8((char*)data, size)); q_CRYPTO_free(data); } return info; @@ -867,6 +870,9 @@ QDebug operator<<(QDebug debug, QSslCertificate::SubjectInfo info) case QSslCertificate::LocalityName: debug << "LocalityName"; break; case QSslCertificate::OrganizationalUnitName: debug << "OrganizationalUnitName"; break; case QSslCertificate::StateOrProvinceName: debug << "StateOrProvinceName"; break; + case QSslCertificate::DistinguishedNameQualifier: debug << "DistinguishedNameQualifier"; break; + case QSslCertificate::SerialNumber: debug << "SerialNumber"; break; + case QSslCertificate::EmailAddress: debug << "EmailAddress"; break; } return debug; } diff --git a/src/network/ssl/qsslcertificate.h b/src/network/ssl/qsslcertificate.h index b942bd8a25..8abaa3f73e 100644 --- a/src/network/ssl/qsslcertificate.h +++ b/src/network/ssl/qsslcertificate.h @@ -76,7 +76,10 @@ public: LocalityName, OrganizationalUnitName, CountryName, - StateOrProvinceName + StateOrProvinceName, + DistinguishedNameQualifier, + SerialNumber, + EmailAddress }; QSslCertificate(QIODevice *device, QSsl::EncodingFormat format = QSsl::Pem); @@ -96,10 +99,10 @@ public: QByteArray version() const; QByteArray serialNumber() const; QByteArray digest(QCryptographicHash::Algorithm algorithm = QCryptographicHash::Md5) const; - QString issuerInfo(SubjectInfo info) const; - QString issuerInfo(const QByteArray &tag) const; - QString subjectInfo(SubjectInfo info) const; - QString subjectInfo(const QByteArray &tag) const; + QStringList issuerInfo(SubjectInfo info) const; + QStringList issuerInfo(const QByteArray &tag) const; + QStringList subjectInfo(SubjectInfo info) const; + QStringList subjectInfo(const QByteArray &tag) const; QMultiMap alternateSubjectNames() const; QDateTime effectiveDate() const; QDateTime expiryDate() const; diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp index fb41b7c9e9..1221db98c9 100644 --- a/src/network/ssl/qsslsocket_openssl.cpp +++ b/src/network/ssl/qsslsocket_openssl.cpp @@ -1262,10 +1262,17 @@ bool QSslSocketBackendPrivate::startHandshake() // if we're the server, don't check CN if (mode == QSslSocket::SslClientMode) { QString peerName = (verificationPeerName.isEmpty () ? q->peerName() : verificationPeerName); - QString commonName = configuration.peerCertificate.subjectInfo(QSslCertificate::CommonName); + QStringList commonNameList = configuration.peerCertificate.subjectInfo(QSslCertificate::CommonName); + bool matched = false; - if (!isMatchingHostname(commonName.toLower(), peerName.toLower())) { - bool matched = false; + foreach (const QString &commonName, commonNameList) { + if (isMatchingHostname(commonName.toLower(), peerName.toLower())) { + matched = true; + break; + } + } + + if (!matched) { foreach (const QString &altName, configuration.peerCertificate .alternateSubjectNames().values(QSsl::DnsEntry)) { if (isMatchingHostname(altName.toLower(), peerName.toLower())) { @@ -1273,15 +1280,15 @@ bool QSslSocketBackendPrivate::startHandshake() break; } } + } - if (!matched) { - // No matches in common names or alternate names. - QSslError error(QSslError::HostNameMismatch, configuration.peerCertificate); - errors << error; - emit q->peerVerifyError(error); - if (q->state() != QAbstractSocket::ConnectedState) - return false; - } + if (!matched) { + // No matches in common names or alternate names. + QSslError error(QSslError::HostNameMismatch, configuration.peerCertificate); + errors << error; + emit q->peerVerifyError(error); + if (q->state() != QAbstractSocket::ConnectedState) + return false; } } } else { -- cgit v1.2.3