summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Hartmann <peter.hartmann@nokia.com>2010-08-04 11:59:49 +0200
committerSamuli Piippo <samuli.piippo@digia.com>2011-06-09 13:06:39 +0300
commit5b890cd81b652584a151ba418478074e34f61c41 (patch)
tree2ccd1fbf62b51b31cfbdc2fac5edfc8e4a21540f
parent52fe778df2310660c84db581c53e2c3fae2cc42a (diff)
downloadqt4-tools-5b890cd81b652584a151ba418478074e34f61c41.tar.gz
QSslCertificate: support expiration dates > 2049
X509 has two time formats: UTC, where the year is in two-digit format, and generalized time with four-digit years. This patch allows dates specified generalized time. Reviewed-by: Thiago Macieira Task-number: QTBUG-12489 (cherry picked from commit a77dbcdbb7022cc754ba87aea9a4fc471d1e4495)
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols.cpp121
-rw-r--r--tests/auto/qsslcertificate/more-certificates/cert-large-expiration-date.pem15
-rw-r--r--tests/auto/qsslcertificate/tst_qsslcertificate.cpp15
3 files changed, 101 insertions, 50 deletions
diff --git a/src/network/ssl/qsslsocket_openssl_symbols.cpp b/src/network/ssl/qsslsocket_openssl_symbols.cpp
index f4842aae10..b5347ad134 100644
--- a/src/network/ssl/qsslsocket_openssl_symbols.cpp
+++ b/src/network/ssl/qsslsocket_openssl_symbols.cpp
@@ -755,74 +755,95 @@ bool q_resolveOpenSslSymbols()
//==============================================================================
QDateTime q_getTimeFromASN1(const ASN1_TIME *aTime)
{
- char lBuffer[24];
- char *pBuffer = lBuffer;
-
size_t lTimeLength = aTime->length;
char *pString = (char *) aTime->data;
if (aTime->type == V_ASN1_UTCTIME) {
+
+ char lBuffer[24];
+ char *pBuffer = lBuffer;
+
if ((lTimeLength < 11) || (lTimeLength > 17))
return QDateTime();
memcpy(pBuffer, pString, 10);
pBuffer += 10;
pString += 10;
- } else {
- if (lTimeLength < 13)
- return QDateTime();
-
- memcpy(pBuffer, pString, 12);
- pBuffer += 12;
- pString += 12;
- }
- if ((*pString == 'Z') || (*pString == '-') || (*pString == '+')) {
- *pBuffer++ = '0';
- *pBuffer++ = '0';
- } else {
- *pBuffer++ = *pString++;
- *pBuffer++ = *pString++;
- // Skip any fractional seconds...
- if (*pString == '.') {
- pString++;
- while ((*pString >= '0') && (*pString <= '9'))
+ if ((*pString == 'Z') || (*pString == '-') || (*pString == '+')) {
+ *pBuffer++ = '0';
+ *pBuffer++ = '0';
+ } else {
+ *pBuffer++ = *pString++;
+ *pBuffer++ = *pString++;
+ // Skip any fractional seconds...
+ if (*pString == '.') {
pString++;
+ while ((*pString >= '0') && (*pString <= '9'))
+ pString++;
+ }
}
- }
- *pBuffer++ = 'Z';
- *pBuffer++ = '\0';
+ *pBuffer++ = 'Z';
+ *pBuffer++ = '\0';
- time_t lSecondsFromUCT;
- if (*pString == 'Z') {
- lSecondsFromUCT = 0;
- } else {
- if ((*pString != '+') && (*pString != '-'))
- return QDateTime();
+ time_t lSecondsFromUCT;
+ if (*pString == 'Z') {
+ lSecondsFromUCT = 0;
+ } else {
+ if ((*pString != '+') && (*pString != '-'))
+ return QDateTime();
+
+ lSecondsFromUCT = ((pString[1] - '0') * 10 + (pString[2] - '0')) * 60;
+ lSecondsFromUCT += (pString[3] - '0') * 10 + (pString[4] - '0');
+ lSecondsFromUCT *= 60;
+ if (*pString == '-')
+ lSecondsFromUCT = -lSecondsFromUCT;
+ }
+
+ tm lTime;
+ lTime.tm_sec = ((lBuffer[10] - '0') * 10) + (lBuffer[11] - '0');
+ lTime.tm_min = ((lBuffer[8] - '0') * 10) + (lBuffer[9] - '0');
+ lTime.tm_hour = ((lBuffer[6] - '0') * 10) + (lBuffer[7] - '0');
+ lTime.tm_mday = ((lBuffer[4] - '0') * 10) + (lBuffer[5] - '0');
+ lTime.tm_mon = (((lBuffer[2] - '0') * 10) + (lBuffer[3] - '0')) - 1;
+ lTime.tm_year = ((lBuffer[0] - '0') * 10) + (lBuffer[1] - '0');
+ if (lTime.tm_year < 50)
+ lTime.tm_year += 100; // RFC 2459
+
+ QDate resDate(lTime.tm_year + 1900, lTime.tm_mon + 1, lTime.tm_mday);
+ QTime resTime(lTime.tm_hour, lTime.tm_min, lTime.tm_sec);
+
+ QDateTime result(resDate, resTime, Qt::UTC);
+ result = result.addSecs(lSecondsFromUCT);
+ return result;
+
+ } else if (aTime->type == V_ASN1_GENERALIZEDTIME) {
- lSecondsFromUCT = ((pString[1] - '0') * 10 + (pString[2] - '0')) * 60;
- lSecondsFromUCT += (pString[3] - '0') * 10 + (pString[4] - '0');
- lSecondsFromUCT *= 60;
- if (*pString == '-')
- lSecondsFromUCT = -lSecondsFromUCT;
+ if (lTimeLength < 15)
+ return QDateTime(); // hopefully never triggered
+
+ // generalized time is always YYYYMMDDHHMMSSZ (RFC 2459, section 4.1.2.5.2)
+ tm lTime;
+ lTime.tm_sec = ((pString[12] - '0') * 10) + (pString[13] - '0');
+ lTime.tm_min = ((pString[10] - '0') * 10) + (pString[11] - '0');
+ lTime.tm_hour = ((pString[8] - '0') * 10) + (pString[9] - '0');
+ lTime.tm_mday = ((pString[6] - '0') * 10) + (pString[7] - '0');
+ lTime.tm_mon = (((pString[4] - '0') * 10) + (pString[5] - '0'));
+ lTime.tm_year = ((pString[0] - '0') * 1000) + ((pString[1] - '0') * 100) +
+ ((pString[2] - '0') * 10) + (pString[3] - '0');
+
+ QDate resDate(lTime.tm_year, lTime.tm_mon, lTime.tm_mday);
+ QTime resTime(lTime.tm_hour, lTime.tm_min, lTime.tm_sec);
+
+ QDateTime result(resDate, resTime, Qt::UTC);
+ return result;
+
+ } else {
+ qWarning("unsupported date format detected");
+ return QDateTime();
}
- tm lTime;
- lTime.tm_sec = ((lBuffer[10] - '0') * 10) + (lBuffer[11] - '0');
- lTime.tm_min = ((lBuffer[8] - '0') * 10) + (lBuffer[9] - '0');
- lTime.tm_hour = ((lBuffer[6] - '0') * 10) + (lBuffer[7] - '0');
- lTime.tm_mday = ((lBuffer[4] - '0') * 10) + (lBuffer[5] - '0');
- lTime.tm_mon = (((lBuffer[2] - '0') * 10) + (lBuffer[3] - '0')) - 1;
- lTime.tm_year = ((lBuffer[0] - '0') * 10) + (lBuffer[1] - '0');
- if (lTime.tm_year < 50)
- lTime.tm_year += 100; // RFC 2459
-
- QDate resDate(lTime.tm_year + 1900, lTime.tm_mon + 1, lTime.tm_mday);
- QTime resTime(lTime.tm_hour, lTime.tm_min, lTime.tm_sec);
- QDateTime result(resDate, resTime, Qt::UTC);
- result = result.addSecs(lSecondsFromUCT);
- return result;
}
QT_END_NAMESPACE
diff --git a/tests/auto/qsslcertificate/more-certificates/cert-large-expiration-date.pem b/tests/auto/qsslcertificate/more-certificates/cert-large-expiration-date.pem
new file mode 100644
index 0000000000..416dd4da04
--- /dev/null
+++ b/tests/auto/qsslcertificate/more-certificates/cert-large-expiration-date.pem
@@ -0,0 +1,15 @@
+-----BEGIN CERTIFICATE-----
+MIICWjCCAcOgAwIBAgIJAM7bMShFxAVAMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
+BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
+aWRnaXRzIFB0eSBMdGQwIBcNMTAwODA0MDk1MzQxWhgPMjA1MTA4MjkwOTUzNDFa
+MEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJ
+bnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJ
+AoGBAM2q22/WNMmn8cC+5EEYGeICySLmp9W6Ay6eKHr0Xxp3X3epETuPfvAuxp7r
+OtkS18EMUegkUj8jw0IMEcbyHKFC/rTCaYOt93CxGBXMIChiMPAsFeYzGa/D6xzA
+kfcRaJRQ+Ek3CDLXPnXfo7xpABXezYcPXAJrgsgBfWrwHdxzAgMBAAGjUDBOMB0G
+A1UdDgQWBBSKbhnnl5uP2X+zuwFP6GovUpUN2TAfBgNVHSMEGDAWgBSKbhnnl5uP
+2X+zuwFP6GovUpUN2TAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAKF0
+jl02liwFfupmzC5oxz2T3IyjEa21fm7QBMQJvQr5OTuX1/C7DAl7g/6/h7BH6JS3
+qpx5rXGet8SZmG8dODL4o3U4xOXnNzch7HtQixWwlx4XnFAXPMHflFX7YC5QQNHq
+I8Y8IW+XjAYWpYJywWMUZIbr1/9y9gn1beYEE3pq
+-----END CERTIFICATE-----
diff --git a/tests/auto/qsslcertificate/tst_qsslcertificate.cpp b/tests/auto/qsslcertificate/tst_qsslcertificate.cpp
index d25bb0b75b..201c0d46c8 100644
--- a/tests/auto/qsslcertificate/tst_qsslcertificate.cpp
+++ b/tests/auto/qsslcertificate/tst_qsslcertificate.cpp
@@ -110,6 +110,7 @@ private slots:
void nulInCN();
void nulInSan();
void largeSerialNumber();
+ void largeExpirationDate();
// ### add tests for certificate bundles (multiple certificates concatenated into a single
// structure); both PEM and DER formatted
#endif
@@ -799,6 +800,20 @@ void tst_QSslCertificate::largeSerialNumber()
QCOMPARE(cert.serialNumber(), QByteArray("01:02:03:04:05:06:07:08:09:10:aa:bb:cc:dd:ee:ff:17:18:19:20"));
}
+void tst_QSslCertificate::largeExpirationDate() // QTBUG-12489
+{
+ QList<QSslCertificate> certList =
+ QSslCertificate::fromPath(SRCDIR "more-certificates/cert-large-expiration-date.pem");
+
+ QCOMPARE(certList.size(), 1);
+
+ const QSslCertificate &cert = certList.at(0);
+ QVERIFY(!cert.isNull());
+ QCOMPARE(cert.effectiveDate().toUTC(), QDateTime(QDate(2010, 8, 4), QTime(9, 53, 41), Qt::UTC));
+ // if the date is larger than 2049, then the generalized time format is used
+ QCOMPARE(cert.expiryDate().toUTC(), QDateTime(QDate(2051, 8, 29), QTime(9, 53, 41), Qt::UTC));
+}
+
#endif // QT_NO_OPENSSL
QTEST_MAIN(tst_QSslCertificate)