summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2021-09-14 16:20:47 +0200
committerDaniel Stenberg <daniel@haxx.se>2021-09-15 14:37:36 +0200
commit54f6d836d8f2407e841fcda1684662aff34b8cb1 (patch)
treec70e61aecf3c53ef2d5919aa79f0fb243b4a1fca
parentd5a70e77b2ba43a27ecba1c400b52e2c22b4fa6d (diff)
downloadcurl-54f6d836d8f2407e841fcda1684662aff34b8cb1.tar.gz
hsts: handle unlimited expiry
When setting a blank expire string, meaning unlimited, curl would pass TIME_T_MAX to getime_r() when creating the output, while on 64 bit systems such a large value cannot be convetered to a tm struct making curl to exit the loop with an error instead. It can't be converted because the year it would represent doesn't fit in the 'int tm_year' field! Starting now, unlimited expiry is instead handled differently by using a human readable expiry date spelled out as "unlimited" instead of trying to use a distant actual date. Test 1660 and 1915 have been updated to help verify this change. Reported-by: Jonathan Cardoso Fixes #7720 Closes #7721
-rw-r--r--lib/hsts.c40
-rw-r--r--tests/data/test16604
-rw-r--r--tests/data/test19156
-rw-r--r--tests/libtest/lib1915.c25
4 files changed, 47 insertions, 28 deletions
diff --git a/lib/hsts.c b/lib/hsts.c
index 853c7dfea..fa91cf63f 100644
--- a/lib/hsts.c
+++ b/lib/hsts.c
@@ -49,6 +49,7 @@
#define MAX_HSTS_HOSTLENSTR "256"
#define MAX_HSTS_DATELEN 64
#define MAX_HSTS_DATELENSTR "64"
+#define UNLIMITED "unlimited"
#ifdef DEBUGBUILD
/* to play well with debug builds, we can *set* a fixed time this will
@@ -283,13 +284,17 @@ static CURLcode hsts_push(struct Curl_easy *data,
e.namelen = strlen(sts->host);
e.includeSubDomains = sts->includeSubDomains;
- result = Curl_gmtime((time_t)sts->expires, &stamp);
- if(result)
- return result;
+ if(sts->expires != TIME_T_MAX) {
+ result = Curl_gmtime((time_t)sts->expires, &stamp);
+ if(result)
+ return result;
- msnprintf(e.expire, sizeof(e.expire), "%d%02d%02d %02d:%02d:%02d",
- stamp.tm_year + 1900, stamp.tm_mon + 1, stamp.tm_mday,
- stamp.tm_hour, stamp.tm_min, stamp.tm_sec);
+ msnprintf(e.expire, sizeof(e.expire), "%d%02d%02d %02d:%02d:%02d",
+ stamp.tm_year + 1900, stamp.tm_mon + 1, stamp.tm_mday,
+ stamp.tm_hour, stamp.tm_min, stamp.tm_sec);
+ }
+ else
+ strcpy(e.expire, UNLIMITED);
sc = data->set.hsts_write(data, &e, i,
data->set.hsts_write_userp);
@@ -303,14 +308,18 @@ static CURLcode hsts_push(struct Curl_easy *data,
static CURLcode hsts_out(struct stsentry *sts, FILE *fp)
{
struct tm stamp;
- CURLcode result = Curl_gmtime((time_t)sts->expires, &stamp);
- if(result)
- return result;
-
- fprintf(fp, "%s%s \"%d%02d%02d %02d:%02d:%02d\"\n",
- sts->includeSubDomains ? ".": "", sts->host,
- stamp.tm_year + 1900, stamp.tm_mon + 1, stamp.tm_mday,
- stamp.tm_hour, stamp.tm_min, stamp.tm_sec);
+ if(sts->expires != TIME_T_MAX) {
+ CURLcode result = Curl_gmtime((time_t)sts->expires, &stamp);
+ if(result)
+ return result;
+ fprintf(fp, "%s%s \"%d%02d%02d %02d:%02d:%02d\"\n",
+ sts->includeSubDomains ? ".": "", sts->host,
+ stamp.tm_year + 1900, stamp.tm_mon + 1, stamp.tm_mday,
+ stamp.tm_hour, stamp.tm_min, stamp.tm_sec);
+ }
+ else
+ fprintf(fp, "%s%s \"%s\"\n",
+ sts->includeSubDomains ? ".": "", sts->host, UNLIMITED);
return CURLE_OK;
}
@@ -403,7 +412,8 @@ static CURLcode hsts_add(struct hsts *h, char *line)
"%" MAX_HSTS_HOSTLENSTR "s \"%" MAX_HSTS_DATELENSTR "[^\"]\"",
host, date);
if(2 == rc) {
- time_t expires = Curl_getdate_capped(date);
+ time_t expires = strcmp(date, UNLIMITED) ? Curl_getdate_capped(date) :
+ TIME_T_MAX;
CURLcode result;
char *p = host;
bool subdomain = FALSE;
diff --git a/tests/data/test1660 b/tests/data/test1660
index 3ddd8d427..cbbcf7587 100644
--- a/tests/data/test1660
+++ b/tests/data/test1660
@@ -20,6 +20,7 @@ HSTS
# This file was generated by libcurl! Edit at your own risk.
.readfrom.example "20211001 04:47:41"
.old.example "20161001 04:47:41"
+.new.example "unlimited"
</file>
# This date is exactly "20190124 22:34:21" UTC
@@ -59,7 +60,7 @@ foo.example.com [example.com]: 1569905261 includeSubDomains
'forexample.net' is not HSTS
'example.net' is not HSTS
expire.example [expire.example]: 1548369268
-Number of entries: 3
+Number of entries: 4
expire.example [expire.example]: 1548369268
expire.example [expire.example]: 1548369268
expire.example [expire.example]: 1548369268
@@ -74,6 +75,7 @@ expire.example [expire.example]: 1548369268
<file name="log/hsts%TESTNUMBER" mode="text">
# Your HSTS cache. https://curl.se/docs/hsts.html
# This file was generated by libcurl! Edit at your own risk.
+.new.example "unlimited"
.example.com "20191001 04:47:41"
example.org "20200124 22:34:21"
</file>
diff --git a/tests/data/test1915 b/tests/data/test1915
index 047a16e2e..d0b2862f9 100644
--- a/tests/data/test1915
+++ b/tests/data/test1915
@@ -42,9 +42,9 @@ http://%HOSTIP:%NOLISTENPORT/not-there/%TESTNUMBER
</errorcode>
<stdout>
[0/4] 1.example.com 20370320 01:02:03
-[1/4] 2.example.com 20370320 01:02:03
-[2/4] 3.example.com 20370320 01:02:03
-[3/4] 4.example.com 20370320 01:02:03
+[1/4] 2.example.com 20370320 03:02:01
+[2/4] 3.example.com 20370319 01:02:03
+[3/4] 4.example.com unlimited
</stdout>
</verify>
</testcase>
diff --git a/tests/libtest/lib1915.c b/tests/libtest/lib1915.c
index 7b4d91d3c..2bd6ffce8 100644
--- a/tests/libtest/lib1915.c
+++ b/tests/libtest/lib1915.c
@@ -25,12 +25,18 @@
#include "warnless.h"
#include "memdebug.h"
-static const char *preload_hosts[] = {
- "1.example.com",
- "2.example.com",
- "3.example.com",
- "4.example.com",
- NULL /* end of list marker */
+struct entry {
+ const char *name;
+ const char *exp;
+};
+
+static struct entry preload_hosts[] = {
+ /* curl turns 39 that day just before 31-bit time_t overflow */
+ { "1.example.com", "20370320 01:02:03" },
+ { "2.example.com", "20370320 03:02:01" },
+ { "3.example.com", "20370319 01:02:03" },
+ { "4.example.com", "" },
+ { NULL, NULL } /* end of list marker */
};
struct state {
@@ -42,15 +48,16 @@ static CURLSTScode hstsread(CURL *easy, struct curl_hstsentry *e,
void *userp)
{
const char *host;
+ const char *expire;
struct state *s = (struct state *)userp;
(void)easy;
- host = preload_hosts[s->index++];
+ host = preload_hosts[s->index].name;
+ expire = preload_hosts[s->index++].exp;
if(host && (strlen(host) < e->namelen)) {
strcpy(e->name, host);
e->includeSubDomains = FALSE;
- strcpy(e->expire, "20370320 01:02:03"); /* curl turns 39 that day
- just before 31-bit time_t overflow */
+ strcpy(e->expire, expire);
fprintf(stderr, "add '%s'\n", host);
}
else