hsts: only match the exact strings
No binary (build failed)
—
(log yok)
| @@ -223,53 +223,55 @@ CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname, | |
| return CURLE_OK; | |
| do { | |
| - | curlx_str_passblanks(&p); |
| - | if(curl_strnequal("max-age", p, 7)) { |
| - | bool quoted = FALSE; |
| - | int rc; |
| - | |
| - | if(gotma) |
| - | return CURLE_BAD_FUNCTION_ARGUMENT; |
| + | struct Curl_str word; |
| + | struct Curl_str val = { 0 }; |
| + | int rc; |
| + | bool assign = FALSE; |
| - | p += 7; |
| + | do { |
| curlx_str_passblanks(&p); | |
| - | if(curlx_str_single(&p, '=')) |
| - | return CURLE_BAD_FUNCTION_ARGUMENT; |
| + | if(*p == ';') |
| + | p++; |
| + | else |
| + | break; |
| + | } while(1); |
| + | if(curlx_str_cspn(&p, &word, ";=\r\n \t")) |
| + | break; |
| + | |
| + | curlx_str_passblanks(&p); |
| + | if(!curlx_str_single(&p, '=')) { |
| + | assign = TRUE; |
| curlx_str_passblanks(&p); | |
| - | if(!curlx_str_single(&p, '\"')) |
| - | quoted = TRUE; |
| + | if(*p == '\"') { |
| + | if(curlx_str_quotedword(&p, &val, MAX_HSTS_LINE)) |
| + | break; |
| + | } |
| + | else { |
| + | if(curlx_str_cspn(&p, &val, ", ;\r\n")) |
| + | break; |
| + | } |
| + | } |
| - | rc = curlx_str_number(&p, &expires, TIME_T_MAX); |
| + | if(assign && curlx_str_casecompare(&word, "max-age")) { |
| + | const char *vp = curlx_str(&val); |
| + | if(gotma) |
| + | return CURLE_BAD_FUNCTION_ARGUMENT; |
| + | rc = curlx_str_number(&vp, &expires, TIME_T_MAX); |
| if(rc == STRE_OVERFLOW) | |
| expires = CURL_OFF_T_MAX; | |
| else if(rc) | |
| /* invalid max-age */ | |
| return CURLE_BAD_FUNCTION_ARGUMENT; | |
| - | if(quoted) { |
| - | if(*p != '\"') |
| - | return CURLE_BAD_FUNCTION_ARGUMENT; |
| - | p++; |
| - | } |
| gotma = TRUE; | |
| } | |
| - | else if(curl_strnequal("includesubdomains", p, 17)) { |
| + | else if(curlx_str_casecompare(&word, "includesubdomains")) { |
| if(gotinc) | |
| return CURLE_BAD_FUNCTION_ARGUMENT; | |
| subdomains = TRUE; | |
| - | p += 17; |
| gotinc = TRUE; | |
| } | |
| - | else { |
| - | /* unknown directive, do a lame attempt to skip */ |
| - | while(*p && (*p != ';')) |
| - | p++; |
| - | } |
| - | |
| - | curlx_str_passblanks(&p); |
| - | if(*p == ';') |
| - | p++; |
| } while(*p); | |
| if(!gotma) | |
| @@ -142,6 +142,23 @@ static CURLcode test_unit1660(const char *arg) | |
| showsts(e, chost); | |
| } | |
| + | result = Curl_hsts_parse(h, "prefix.example", |
| + | "max-age=60; includeSubDomainsExtra"); |
| + | fail_if(result, "failed to parse unknown HSTS directive"); |
| + | e = hsts_check(h, "child.prefix.example", |
| + | strlen("child.prefix.example"), TRUE); |
| + | fail_if(e, "unknown directive enabled subdomain matching"); |
| + | result = Curl_hsts_parse(h, "prefix.example", "max-age=0"); |
| + | fail_if(result, "failed to remove HSTS test entry"); |
| + | |
| + | result = Curl_hsts_parse(h, "unknown.example", |
| + | "max-age-extra=1; max-age=60"); |
| + | fail_if(result, "failed to ignore unknown HSTS directive"); |
| + | e = hsts_check(h, "unknown.example", strlen("unknown.example"), FALSE); |
| + | fail_if(!e, "recognized directive after unknown directive was ignored"); |
| + | result = Curl_hsts_parse(h, "unknown.example", "max-age=0"); |
| + | fail_if(result, "failed to remove HSTS test entry"); |
| + | |
| curl_mprintf("Number of entries: %zu\n", Curl_llist_count(&h->list)); | |
| /* verify that it is exists for 7 seconds */ | |