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 <qt_sanity_bot@ovi.com> Reviewed-by: Sergio Ahumada <sergio.ahumada@nokia.com>
This commit is contained in:
parent
cadbfc07b6
commit
2cf935b43e
@ -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<QString, QString> _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;
|
||||
}
|
||||
|
@ -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<QSsl::AlternateNameEntryType, QString> alternateSubjectNames() const;
|
||||
QDateTime effectiveDate() const;
|
||||
QDateTime expiryDate() const;
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user