hsts: when a dupe host adds subdomains, use that

Otherwise a weaker earlier entry is allowed to override a later more
restrictive one.

Add test 1638 to verify.

Closes #21108
This commit is contained in:
Daniel Stenberg 2026-03-26 17:28:34 +01:00
parent 5172ba5475
commit e1fdbdd16f
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
6 changed files with 105 additions and 3 deletions

View File

@ -636,7 +636,7 @@ parameter is the not negative integer number of seconds for the delay. This
'delay' attribute is intended for specific test cases, and normally not
needed.
### `<file name="%LOGDIR/filename" [nonewline="yes"][crlf="yes"]>`
### `<file name="%LOGDIR/filename" [options]>`
This creates the named file with this content before the test case is run,
which is useful if the test case needs a file to act on.
@ -646,6 +646,9 @@ off.
`crlf=yes` forces the newlines to become CRLF even if not written so in the
test.
`mode="text"` normalizes the line endings to make them compare as text on all
platforms.
### `<file1>`
1 to 4 can be appended to 'file' to create more files.

View File

@ -35,6 +35,15 @@ void curlx_str_assign(struct Curl_str *out, const char *str, size_t len)
out->len = len;
}
/* remove bytes from the end of the string, never remove more bytes than what
the string holds! */
void curlx_str_trim(struct Curl_str *out, size_t len)
{
DEBUGASSERT(out);
DEBUGASSERT(out->len >= len);
out->len -= len;
}
/* Get a word until the first DELIM or end of string. At least one byte long.
return non-zero on error */
int curlx_str_until(const char **linep, struct Curl_str *out,

View File

@ -44,6 +44,7 @@ struct Curl_str {
void curlx_str_init(struct Curl_str *out);
void curlx_str_assign(struct Curl_str *out, const char *str, size_t len);
void curlx_str_trim(struct Curl_str *out, size_t len);
#define curlx_str(x) ((x)->str)
#define curlx_strlen(x) ((x)->len)

View File

@ -407,6 +407,7 @@ static CURLcode hsts_add(struct hsts *h, const char *line)
char dbuf[MAX_HSTS_DATELEN + 1];
time_t expires = 0;
const char *hp = curlx_str(&host);
size_t hlen;
/* The date parser works on a null-terminated string. The maximum length
is upheld by curlx_str_quotedword(). */
@ -420,17 +421,26 @@ static CURLcode hsts_add(struct hsts *h, const char *line)
if(hp[0] == '.') {
curlx_str_nudge(&host, 1);
hp = curlx_str(&host);
subdomain = TRUE;
}
hlen = curlx_strlen(&host);
if(hlen && (hp[hlen - 1] == '.'))
/* strip off any trailing dot */
curlx_str_trim(&host, 1);
/* only add it if not already present */
e = Curl_hsts(h, curlx_str(&host), curlx_strlen(&host), subdomain);
if(!e)
result = hsts_create(h, curlx_str(&host), curlx_strlen(&host),
subdomain, expires);
else if(curlx_str_casecompare(&host, e->host)) {
/* the same hostname, use the largest expire time */
/* the same hostname, use the largest expire time and keep the
strictest subdomain policy */
if(expires > e->expires)
e->expires = expires;
if(subdomain)
e->includeSubDomains = TRUE;
}
if(result)
return result;

View File

@ -217,7 +217,7 @@ test1614 test1615 test1616 test1617 test1618 \
test1620 test1621 test1622 test1623 test1624 test1625 test1626 test1627 \
\
test1630 test1631 test1632 test1633 test1634 test1635 test1636 test1637 \
\
test1638 \
test1640 test1641 test1642 test1643 \
\
test1650 test1651 test1652 test1653 test1654 test1655 test1656 test1657 \

79
tests/data/test1638 Normal file
View File

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="US-ASCII"?>
<testcase>
<info>
<keywords>
HTTP
HTTP proxy
HSTS
</keywords>
</info>
<reply>
# we use this as response to a CONNECT
<connect crlf="headers" nocheck="yes">
HTTP/1.1 200 not OK at all
Date: Tue, 09 Nov 2010 14:49:00 GMT
Server: test-server/fake
Connection: close
Funny-head: yesyes
</connect>
<data crlf="headers" nocheck="yes">
HTTP/1.1 200 not OK at all
Date: Tue, 09 Nov 2010 14:49:00 GMT
Server: test-server/fake
Content-Length: 6
Connection: close
Funny-head: yesyes
-foo-
</data>
</reply>
<client>
<server>
http
</server>
<features>
HSTS
proxy
https
large-time
</features>
<file name="%LOGDIR/hsts%TESTNUMBER">
# comment in input file
foo.example. "20391001 04:47:41"
.foo.example. "20291001 04:47:41"
</file>
<name>
HSTS duplicate domains where the update adds subdomains
</name>
<command>
-x http://%HOSTIP:%HTTPPORT http://this.hsts.example/%TESTNUMBER --hsts %LOGDIR/hsts%TESTNUMBER
</command>
<disable>
test-duphandle
</disable>
</client>
<verify>
<protocol crlf="headers">
GET http://this.hsts.example/%TESTNUMBER HTTP/1.1
Host: this.hsts.example
User-Agent: curl/%VERSION
Accept: */*
Proxy-Connection: Keep-Alive
</protocol>
<file name="%LOGDIR/hsts%TESTNUMBER" mode="text">
# Your HSTS cache. https://curl.se/docs/hsts.html
# This file was generated by libcurl! Edit at your own risk.
.foo.example "20391001 04:47:41"
</file>
</verify>
</testcase>