QAsn1Element - fix toDateTime function

ASN UTCTime uses two characters to encode a year (YY). When converting it
into QDate, it's quite naive to just add 2000. According to RFC 2459,
these YY represent dates in the range [1950, 2049].
This patch also introduces a helper function doing the checked conversion
from a string to int (to be reused in the following-up patches).

Task-number: QTBUG-61934
Change-Id: I3f6f471d24e8357b83b2f5973023b2b842751389
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
bb10
Timur Pocheptsov 2017-07-14 10:40:49 +02:00
parent 4a7ec2d9b0
commit 07c0e0fdcf
2 changed files with 58 additions and 3 deletions

View File

@ -45,6 +45,8 @@
#include <QtCore/qvector.h>
#include <QDebug>
#include <locale>
QT_BEGIN_NAMESPACE
typedef QMap<QByteArray, QByteArray> OidNameMap;
@ -82,6 +84,27 @@ static OidNameMap createOidMap()
}
Q_GLOBAL_STATIC_WITH_ARGS(OidNameMap, oidNameMap, (createOidMap()))
static bool stringToNonNegativeInt(const QByteArray &asnString, int *val)
{
// Helper function for toDateTime(), which handles chunking of the original
// string into smaller sub-components, so we expect the whole 'asnString' to
// be a valid non-negative number.
Q_ASSERT(val);
// We want the C locale, as used by QByteArray; however, no leading sign is
// allowed (which QByteArray would accept), so we have to check the data:
const std::locale localeC;
for (char v : asnString) {
if (!std::isdigit(v, localeC))
return false;
}
bool ok = false;
*val = asnString.toInt(&ok);
Q_ASSERT(ok && *val >= 0);
return true;
}
QAsn1Element::QAsn1Element(quint8 type, const QByteArray &value)
: mType(type)
, mValue(value)
@ -231,15 +254,19 @@ bool QAsn1Element::toBool(bool *ok) const
QDateTime QAsn1Element::toDateTime() const
{
if (mValue.endsWith('Z')) {
if (mType == UtcTimeType && mValue.size() == 13)
return QDateTime(QDate(2000 + mValue.mid(0, 2).toInt(),
if (mType == UtcTimeType && mValue.size() == 13) {
int year = 0;
if (!stringToNonNegativeInt(mValue.mid(0, 2), &year))
return QDateTime();
// RFC 2459: YY represents a year in the range [1950, 2049]
return QDateTime(QDate(year < 50 ? 2000 + year : 1900 + year,
mValue.mid(2, 2).toInt(),
mValue.mid(4, 2).toInt()),
QTime(mValue.mid(6, 2).toInt(),
mValue.mid(8, 2).toInt(),
mValue.mid(10, 2).toInt()),
Qt::UTC);
else if (mType == GeneralizedTimeType && mValue.size() == 15)
} else if (mType == GeneralizedTimeType && mValue.size() == 15) {
return QDateTime(QDate(mValue.mid(0, 4).toInt(),
mValue.mid(4, 2).toInt(),
mValue.mid(6, 2).toInt()),
@ -247,6 +274,7 @@ QDateTime QAsn1Element::toDateTime() const
mValue.mid(10, 2).toInt(),
mValue.mid(12, 2).toInt()),
Qt::UTC);
}
}
return QDateTime();
}

View File

@ -134,6 +134,33 @@ void tst_QAsn1Element::dateTime_data()
QTest::newRow("UTCTime - no trailing Z")
<< QByteArray::fromHex("170d30373034313730373430323659")
<< QDateTime();
QTest::newRow("UTCTime - year 1950")
<< QByteArray::fromHex("170d3530313232343035353530305a")
<< QDateTime(QDate(1950, 12, 24), QTime(5, 55), Qt::UTC);
QTest::newRow("UTCTime - year 1999")
<< QByteArray::fromHex("170d3939313232343035353530305a")
<< QDateTime(QDate(1999, 12, 24), QTime(5, 55), Qt::UTC);
QTest::newRow("UTCTime - year 2000")
<< QByteArray::fromHex("170d3030313232343035353530305a")
<< QDateTime(QDate(2000, 12, 24), QTime(5, 55), Qt::UTC);
QTest::newRow("UTCTime - year 2049")
<< QByteArray::fromHex("170d3439313232343035353530305a")
<< QDateTime(QDate(2049, 12, 24), QTime(5, 55), Qt::UTC);
QTest::newRow("UTCTime - invalid year ('-9')")
<< QByteArray::fromHex("170d2d39313232343035353530305a")
<< QDateTime();
QTest::newRow("UTCTime - invalid year ('*9')")
<< QByteArray::fromHex("170d2a39313232343035353530305a")
<< QDateTime();
QTest::newRow("UTCTime - invalid year ('5*')")
<< QByteArray::fromHex("170d352a313232343035353530305a")
<< QDateTime();
QTest::newRow("UTCTime - invalid year ('AB')")
<< QByteArray::fromHex("170d4142313232343035353530305a")
<< QDateTime();
QTest::newRow("UTCTime - invalid year ('+1')")
<< QByteArray::fromHex("170d2b31313232343035353530305a")
<< QDateTime();
QTest::newRow("GeneralizedTime - 20510829095341Z")
<< QByteArray::fromHex("180f32303531303832393039353334315a")
<< QDateTime(QDate(2051, 8, 29), QTime(9, 53, 41), Qt::UTC);