1*6236dae4SAndroid Build Coastguard Worker /***************************************************************************
2*6236dae4SAndroid Build Coastguard Worker * _ _ ____ _
3*6236dae4SAndroid Build Coastguard Worker * Project ___| | | | _ \| |
4*6236dae4SAndroid Build Coastguard Worker * / __| | | | |_) | |
5*6236dae4SAndroid Build Coastguard Worker * | (__| |_| | _ <| |___
6*6236dae4SAndroid Build Coastguard Worker * \___|\___/|_| \_\_____|
7*6236dae4SAndroid Build Coastguard Worker *
8*6236dae4SAndroid Build Coastguard Worker * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
9*6236dae4SAndroid Build Coastguard Worker *
10*6236dae4SAndroid Build Coastguard Worker * This software is licensed as described in the file COPYING, which
11*6236dae4SAndroid Build Coastguard Worker * you should have received as part of this distribution. The terms
12*6236dae4SAndroid Build Coastguard Worker * are also available at https://curl.se/docs/copyright.html.
13*6236dae4SAndroid Build Coastguard Worker *
14*6236dae4SAndroid Build Coastguard Worker * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15*6236dae4SAndroid Build Coastguard Worker * copies of the Software, and permit persons to whom the Software is
16*6236dae4SAndroid Build Coastguard Worker * furnished to do so, under the terms of the COPYING file.
17*6236dae4SAndroid Build Coastguard Worker *
18*6236dae4SAndroid Build Coastguard Worker * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19*6236dae4SAndroid Build Coastguard Worker * KIND, either express or implied.
20*6236dae4SAndroid Build Coastguard Worker *
21*6236dae4SAndroid Build Coastguard Worker * SPDX-License-Identifier: curl
22*6236dae4SAndroid Build Coastguard Worker *
23*6236dae4SAndroid Build Coastguard Worker ***************************************************************************/
24*6236dae4SAndroid Build Coastguard Worker #include "curlcheck.h"
25*6236dae4SAndroid Build Coastguard Worker
26*6236dae4SAndroid Build Coastguard Worker #include "urldata.h"
27*6236dae4SAndroid Build Coastguard Worker #include "hsts.h"
28*6236dae4SAndroid Build Coastguard Worker
29*6236dae4SAndroid Build Coastguard Worker static CURLcode
unit_setup(void)30*6236dae4SAndroid Build Coastguard Worker unit_setup(void)
31*6236dae4SAndroid Build Coastguard Worker {
32*6236dae4SAndroid Build Coastguard Worker return CURLE_OK;
33*6236dae4SAndroid Build Coastguard Worker }
34*6236dae4SAndroid Build Coastguard Worker
35*6236dae4SAndroid Build Coastguard Worker static void
unit_stop(void)36*6236dae4SAndroid Build Coastguard Worker unit_stop(void)
37*6236dae4SAndroid Build Coastguard Worker {
38*6236dae4SAndroid Build Coastguard Worker curl_global_cleanup();
39*6236dae4SAndroid Build Coastguard Worker }
40*6236dae4SAndroid Build Coastguard Worker
41*6236dae4SAndroid Build Coastguard Worker #if defined(CURL_DISABLE_HTTP) || defined(CURL_DISABLE_HSTS)
42*6236dae4SAndroid Build Coastguard Worker UNITTEST_START
43*6236dae4SAndroid Build Coastguard Worker {
44*6236dae4SAndroid Build Coastguard Worker puts("nothing to do when HTTP or HSTS are disabled");
45*6236dae4SAndroid Build Coastguard Worker }
46*6236dae4SAndroid Build Coastguard Worker UNITTEST_STOP
47*6236dae4SAndroid Build Coastguard Worker #else
48*6236dae4SAndroid Build Coastguard Worker
49*6236dae4SAndroid Build Coastguard Worker struct testit {
50*6236dae4SAndroid Build Coastguard Worker const char *host;
51*6236dae4SAndroid Build Coastguard Worker const char *chost; /* if non-NULL, use to lookup with */
52*6236dae4SAndroid Build Coastguard Worker const char *hdr; /* if NULL, just do the lookup */
53*6236dae4SAndroid Build Coastguard Worker const CURLcode result; /* parse result */
54*6236dae4SAndroid Build Coastguard Worker };
55*6236dae4SAndroid Build Coastguard Worker
56*6236dae4SAndroid Build Coastguard Worker static const struct testit headers[] = {
57*6236dae4SAndroid Build Coastguard Worker /* two entries read from disk cache, verify first */
58*6236dae4SAndroid Build Coastguard Worker { "-", "readfrom.example", NULL, CURLE_OK},
59*6236dae4SAndroid Build Coastguard Worker { "-", "old.example", NULL, CURLE_OK},
60*6236dae4SAndroid Build Coastguard Worker /* delete the remaining one read from disk */
61*6236dae4SAndroid Build Coastguard Worker { "readfrom.example", NULL, "max-age=\"0\"", CURLE_OK},
62*6236dae4SAndroid Build Coastguard Worker
63*6236dae4SAndroid Build Coastguard Worker { "example.com", NULL, "max-age=\"31536000\"\r\n", CURLE_OK },
64*6236dae4SAndroid Build Coastguard Worker { "example.com", NULL, "max-age=\"21536000\"\r\n", CURLE_OK },
65*6236dae4SAndroid Build Coastguard Worker { "example.com", NULL, "max-age=\"21536000\"; \r\n", CURLE_OK },
66*6236dae4SAndroid Build Coastguard Worker { "example.com", NULL, "max-age=\"21536000\"; includeSubDomains\r\n",
67*6236dae4SAndroid Build Coastguard Worker CURLE_OK },
68*6236dae4SAndroid Build Coastguard Worker { "example.org", NULL, "max-age=\"31536000\"\r\n", CURLE_OK },
69*6236dae4SAndroid Build Coastguard Worker { "this.example", NULL, "max=\"31536\";", CURLE_BAD_FUNCTION_ARGUMENT },
70*6236dae4SAndroid Build Coastguard Worker { "this.example", NULL, "max-age=\"31536", CURLE_BAD_FUNCTION_ARGUMENT },
71*6236dae4SAndroid Build Coastguard Worker { "this.example", NULL, "max-age=31536\"", CURLE_OK },
72*6236dae4SAndroid Build Coastguard Worker /* max-age=0 removes the entry */
73*6236dae4SAndroid Build Coastguard Worker { "this.example", NULL, "max-age=0", CURLE_OK },
74*6236dae4SAndroid Build Coastguard Worker { "another.example", NULL, "includeSubDomains; ",
75*6236dae4SAndroid Build Coastguard Worker CURLE_BAD_FUNCTION_ARGUMENT },
76*6236dae4SAndroid Build Coastguard Worker
77*6236dae4SAndroid Build Coastguard Worker /* Two max-age is illegal */
78*6236dae4SAndroid Build Coastguard Worker { "example.com", NULL,
79*6236dae4SAndroid Build Coastguard Worker "max-age=\"21536000\"; includeSubDomains; max-age=\"3\";",
80*6236dae4SAndroid Build Coastguard Worker CURLE_BAD_FUNCTION_ARGUMENT },
81*6236dae4SAndroid Build Coastguard Worker /* Two includeSubDomains is illegal */
82*6236dae4SAndroid Build Coastguard Worker { "2.example.com", NULL,
83*6236dae4SAndroid Build Coastguard Worker "max-age=\"21536000\"; includeSubDomains; includeSubDomains;",
84*6236dae4SAndroid Build Coastguard Worker CURLE_BAD_FUNCTION_ARGUMENT },
85*6236dae4SAndroid Build Coastguard Worker /* use a unknown directive "include" that should be ignored */
86*6236dae4SAndroid Build Coastguard Worker { "3.example.com", NULL, "max-age=\"21536000\"; include; includeSubDomains;",
87*6236dae4SAndroid Build Coastguard Worker CURLE_OK },
88*6236dae4SAndroid Build Coastguard Worker /* remove the "3.example.com" one, should still match the example.com */
89*6236dae4SAndroid Build Coastguard Worker { "3.example.com", NULL, "max-age=\"0\"; includeSubDomains;",
90*6236dae4SAndroid Build Coastguard Worker CURLE_OK },
91*6236dae4SAndroid Build Coastguard Worker { "-", "foo.example.com", NULL, CURLE_OK},
92*6236dae4SAndroid Build Coastguard Worker { "-", "foo.xample.com", NULL, CURLE_OK},
93*6236dae4SAndroid Build Coastguard Worker
94*6236dae4SAndroid Build Coastguard Worker /* should not match */
95*6236dae4SAndroid Build Coastguard Worker { "example.net", "forexample.net", "max-age=\"31536000\"\r\n", CURLE_OK },
96*6236dae4SAndroid Build Coastguard Worker
97*6236dae4SAndroid Build Coastguard Worker /* should not match either, since forexample.net is not in the example.net
98*6236dae4SAndroid Build Coastguard Worker domain */
99*6236dae4SAndroid Build Coastguard Worker { "example.net", "forexample.net",
100*6236dae4SAndroid Build Coastguard Worker "max-age=\"31536000\"; includeSubDomains\r\n", CURLE_OK },
101*6236dae4SAndroid Build Coastguard Worker /* remove example.net again */
102*6236dae4SAndroid Build Coastguard Worker { "example.net", NULL, "max-age=\"0\"; includeSubDomains\r\n", CURLE_OK },
103*6236dae4SAndroid Build Coastguard Worker
104*6236dae4SAndroid Build Coastguard Worker /* make this live for 7 seconds */
105*6236dae4SAndroid Build Coastguard Worker { "expire.example", NULL, "max-age=\"7\"\r\n", CURLE_OK },
106*6236dae4SAndroid Build Coastguard Worker { NULL, NULL, NULL, CURLE_OK }
107*6236dae4SAndroid Build Coastguard Worker };
108*6236dae4SAndroid Build Coastguard Worker
109*6236dae4SAndroid Build Coastguard Worker static void showsts(struct stsentry *e, const char *chost)
110*6236dae4SAndroid Build Coastguard Worker {
111*6236dae4SAndroid Build Coastguard Worker if(!e)
112*6236dae4SAndroid Build Coastguard Worker printf("'%s' is not HSTS\n", chost);
113*6236dae4SAndroid Build Coastguard Worker else {
114*6236dae4SAndroid Build Coastguard Worker printf("%s [%s]: %" CURL_FORMAT_CURL_OFF_T "%s\n",
115*6236dae4SAndroid Build Coastguard Worker chost, e->host, e->expires,
116*6236dae4SAndroid Build Coastguard Worker e->includeSubDomains ? " includeSubDomains" : "");
117*6236dae4SAndroid Build Coastguard Worker }
118*6236dae4SAndroid Build Coastguard Worker }
119*6236dae4SAndroid Build Coastguard Worker
120*6236dae4SAndroid Build Coastguard Worker UNITTEST_START
121*6236dae4SAndroid Build Coastguard Worker {
122*6236dae4SAndroid Build Coastguard Worker CURLcode result;
123*6236dae4SAndroid Build Coastguard Worker struct stsentry *e;
124*6236dae4SAndroid Build Coastguard Worker struct hsts *h = Curl_hsts_init();
125*6236dae4SAndroid Build Coastguard Worker int i;
126*6236dae4SAndroid Build Coastguard Worker const char *chost;
127*6236dae4SAndroid Build Coastguard Worker CURL *easy;
128*6236dae4SAndroid Build Coastguard Worker char savename[256];
129*6236dae4SAndroid Build Coastguard Worker
130*6236dae4SAndroid Build Coastguard Worker abort_unless(h, "Curl_hsts_init()");
131*6236dae4SAndroid Build Coastguard Worker
132*6236dae4SAndroid Build Coastguard Worker curl_global_init(CURL_GLOBAL_ALL);
133*6236dae4SAndroid Build Coastguard Worker easy = curl_easy_init();
134*6236dae4SAndroid Build Coastguard Worker if(!easy) {
135*6236dae4SAndroid Build Coastguard Worker Curl_hsts_cleanup(&h);
136*6236dae4SAndroid Build Coastguard Worker curl_global_cleanup();
137*6236dae4SAndroid Build Coastguard Worker abort_unless(easy, "curl_easy_init()");
138*6236dae4SAndroid Build Coastguard Worker }
139*6236dae4SAndroid Build Coastguard Worker
140*6236dae4SAndroid Build Coastguard Worker Curl_hsts_loadfile(easy, h, arg);
141*6236dae4SAndroid Build Coastguard Worker
142*6236dae4SAndroid Build Coastguard Worker for(i = 0; headers[i].host ; i++) {
143*6236dae4SAndroid Build Coastguard Worker if(headers[i].hdr) {
144*6236dae4SAndroid Build Coastguard Worker result = Curl_hsts_parse(h, headers[i].host, headers[i].hdr);
145*6236dae4SAndroid Build Coastguard Worker
146*6236dae4SAndroid Build Coastguard Worker if(result != headers[i].result) {
147*6236dae4SAndroid Build Coastguard Worker fprintf(stderr, "Curl_hsts_parse(%s) failed: %d\n",
148*6236dae4SAndroid Build Coastguard Worker headers[i].hdr, result);
149*6236dae4SAndroid Build Coastguard Worker unitfail++;
150*6236dae4SAndroid Build Coastguard Worker continue;
151*6236dae4SAndroid Build Coastguard Worker }
152*6236dae4SAndroid Build Coastguard Worker else if(result) {
153*6236dae4SAndroid Build Coastguard Worker printf("Input %u: error %d\n", i, (int) result);
154*6236dae4SAndroid Build Coastguard Worker continue;
155*6236dae4SAndroid Build Coastguard Worker }
156*6236dae4SAndroid Build Coastguard Worker }
157*6236dae4SAndroid Build Coastguard Worker
158*6236dae4SAndroid Build Coastguard Worker chost = headers[i].chost ? headers[i].chost : headers[i].host;
159*6236dae4SAndroid Build Coastguard Worker e = Curl_hsts(h, chost, TRUE);
160*6236dae4SAndroid Build Coastguard Worker showsts(e, chost);
161*6236dae4SAndroid Build Coastguard Worker }
162*6236dae4SAndroid Build Coastguard Worker
163*6236dae4SAndroid Build Coastguard Worker printf("Number of entries: %zu\n", Curl_llist_count(&h->list));
164*6236dae4SAndroid Build Coastguard Worker
165*6236dae4SAndroid Build Coastguard Worker /* verify that it is exists for 7 seconds */
166*6236dae4SAndroid Build Coastguard Worker chost = "expire.example";
167*6236dae4SAndroid Build Coastguard Worker for(i = 100; i < 110; i++) {
168*6236dae4SAndroid Build Coastguard Worker e = Curl_hsts(h, chost, TRUE);
169*6236dae4SAndroid Build Coastguard Worker showsts(e, chost);
170*6236dae4SAndroid Build Coastguard Worker deltatime++; /* another second passed */
171*6236dae4SAndroid Build Coastguard Worker }
172*6236dae4SAndroid Build Coastguard Worker
173*6236dae4SAndroid Build Coastguard Worker msnprintf(savename, sizeof(savename), "%s.save", arg);
174*6236dae4SAndroid Build Coastguard Worker (void)Curl_hsts_save(easy, h, savename);
175*6236dae4SAndroid Build Coastguard Worker Curl_hsts_cleanup(&h);
176*6236dae4SAndroid Build Coastguard Worker curl_easy_cleanup(easy);
177*6236dae4SAndroid Build Coastguard Worker curl_global_cleanup();
178*6236dae4SAndroid Build Coastguard Worker }
179*6236dae4SAndroid Build Coastguard Worker UNITTEST_STOP
180*6236dae4SAndroid Build Coastguard Worker #endif
181