diff options
author | Daniel Stenberg <daniel@haxx.se> | 2021-09-14 16:20:47 +0200 |
---|---|---|
committer | Daniel Stenberg <daniel@haxx.se> | 2021-09-15 14:37:36 +0200 |
commit | 54f6d836d8f2407e841fcda1684662aff34b8cb1 (patch) | |
tree | c70e61aecf3c53ef2d5919aa79f0fb243b4a1fca | |
parent | d5a70e77b2ba43a27ecba1c400b52e2c22b4fa6d (diff) | |
download | curl-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.c | 40 | ||||
-rw-r--r-- | tests/data/test1660 | 4 | ||||
-rw-r--r-- | tests/data/test1915 | 6 | ||||
-rw-r--r-- | tests/libtest/lib1915.c | 25 |
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 |