ASN1: speed up parsing of certificate timestamps
By parsing QDate and QTime separately it will internally parse the values as-if-by UTC. This means we avoid the overhead of figuring out what the local timezone is repeatedly for each certificate. On Windows, with Schannel, this brings QAsn1Element::toDateTime from consuming more than 97% of the test time to below 10%. The test being tst_QSslSocket::systemCaCertificates. It also goes from taking 1 minute in debug, to 1 second. As a drive-by: add a (currently) failing test for Feb 29 2000, which fails because we decode the date as 1900 before adjusting it to 2000. But there is no 1900-02-29, so it returns an invalid date. As spotted by Eddy. Pick-to: 6.5 Change-Id: Iefa73a01d710129faf6412c4fa8bc2b5d7c98bbb Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io> Reviewed-by: Edward Welbourne <edward.welbourne@qt.io> (cherry picked from commit 731b759c00ce17072e3f93fdd7044490e51171ca)
This commit is contained in:
parent
23ea13f9d9
commit
80925cf84f
@ -6,6 +6,7 @@
|
||||
|
||||
#include <QtCore/qdatastream.h>
|
||||
#include <QtCore/qdatetime.h>
|
||||
#include <QtCore/qtimezone.h>
|
||||
#include <QtCore/qlist.h>
|
||||
#include <QDebug>
|
||||
#include <private/qtools_p.h>
|
||||
@ -224,15 +225,10 @@ QDateTime QAsn1Element::toDateTime() const
|
||||
return result;
|
||||
|
||||
if (mType == UtcTimeType && mValue.size() == 13) {
|
||||
result = QDateTime::fromString(QString::fromLatin1(mValue),
|
||||
QStringLiteral("yyMMddHHmmsst"));
|
||||
if (!result.isValid())
|
||||
const QLatin1StringView inputView(mValue);
|
||||
QDate date = QDate::fromString(inputView.first(6), u"yyMMdd");
|
||||
if (!date.isValid())
|
||||
return result;
|
||||
|
||||
Q_ASSERT(result.timeSpec() == Qt::UTC);
|
||||
|
||||
QDate date = result.date();
|
||||
|
||||
// RFC 2459:
|
||||
// Where YY is greater than or equal to 50, the year shall be
|
||||
// interpreted as 19YY; and
|
||||
@ -242,10 +238,15 @@ QDateTime QAsn1Element::toDateTime() const
|
||||
// QDateTime interprets the 'yy' format as 19yy, so we may need to adjust
|
||||
// the year (bring it in the [1950, 2049] range).
|
||||
if (date.year() < 1950)
|
||||
result.setDate(date.addYears(100));
|
||||
date = date.addYears(100);
|
||||
|
||||
Q_ASSERT(result.date().year() >= 1950);
|
||||
Q_ASSERT(result.date().year() <= 2049);
|
||||
Q_ASSERT(date.year() >= 1950);
|
||||
Q_ASSERT(date.year() <= 2049);
|
||||
|
||||
QTime time = QTime::fromString(inputView.sliced(6, 6), u"HHmmss");
|
||||
if (!time.isValid())
|
||||
return result;
|
||||
result = QDateTime(date, time, QTimeZone::UTC);
|
||||
} else if (mType == GeneralizedTimeType && mValue.size() == 15) {
|
||||
result = QDateTime::fromString(QString::fromLatin1(mValue),
|
||||
QStringLiteral("yyyyMMddHHmmsst"));
|
||||
|
@ -121,6 +121,9 @@ void tst_QAsn1Element::dateTime_data()
|
||||
QTest::newRow("UTCTime - year 2000")
|
||||
<< QByteArray::fromHex("170d3030313232343035353530305a")
|
||||
<< QDateTime(QDate(2000, 12, 24), QTime(5, 55), QTimeZone::UTC);
|
||||
QTest::newRow("UTCTime - leap day year 2000")
|
||||
<< QByteArray::fromHex("170d3030303232393035353530305a")
|
||||
<< QDateTime(QDate(2000, 2, 29), QTime(5, 55), QTimeZone::UTC);
|
||||
QTest::newRow("UTCTime - year 2049")
|
||||
<< QByteArray::fromHex("170d3439313232343035353530305a")
|
||||
<< QDateTime(QDate(2049, 12, 24), QTime(5, 55), QTimeZone::UTC);
|
||||
@ -163,6 +166,9 @@ void tst_QAsn1Element::dateTime()
|
||||
|
||||
QAsn1Element elem;
|
||||
QVERIFY(elem.read(encoded));
|
||||
QEXPECT_FAIL("UTCTime - leap day year 2000",
|
||||
"We decode as 1900, and then adjust to 2000. But there was no leap day in 1900!",
|
||||
Continue);
|
||||
QCOMPARE(elem.toDateTime(), value);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user