xref: /aosp_15_r20/external/curl/lib/http_aws_sigv4.c (revision 6236dae45794135f37c4eb022389c904c8b0090d)
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.haxx.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 
25*6236dae4SAndroid Build Coastguard Worker #include "curl_setup.h"
26*6236dae4SAndroid Build Coastguard Worker 
27*6236dae4SAndroid Build Coastguard Worker #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_AWS)
28*6236dae4SAndroid Build Coastguard Worker 
29*6236dae4SAndroid Build Coastguard Worker #include "urldata.h"
30*6236dae4SAndroid Build Coastguard Worker #include "strcase.h"
31*6236dae4SAndroid Build Coastguard Worker #include "strdup.h"
32*6236dae4SAndroid Build Coastguard Worker #include "http_aws_sigv4.h"
33*6236dae4SAndroid Build Coastguard Worker #include "curl_sha256.h"
34*6236dae4SAndroid Build Coastguard Worker #include "transfer.h"
35*6236dae4SAndroid Build Coastguard Worker #include "parsedate.h"
36*6236dae4SAndroid Build Coastguard Worker #include "sendf.h"
37*6236dae4SAndroid Build Coastguard Worker #include "escape.h"
38*6236dae4SAndroid Build Coastguard Worker 
39*6236dae4SAndroid Build Coastguard Worker #include <time.h>
40*6236dae4SAndroid Build Coastguard Worker 
41*6236dae4SAndroid Build Coastguard Worker /* The last 3 #include files should be in this order */
42*6236dae4SAndroid Build Coastguard Worker #include "curl_printf.h"
43*6236dae4SAndroid Build Coastguard Worker #include "curl_memory.h"
44*6236dae4SAndroid Build Coastguard Worker #include "memdebug.h"
45*6236dae4SAndroid Build Coastguard Worker 
46*6236dae4SAndroid Build Coastguard Worker #include "slist.h"
47*6236dae4SAndroid Build Coastguard Worker 
48*6236dae4SAndroid Build Coastguard Worker #define HMAC_SHA256(k, kl, d, dl, o)           \
49*6236dae4SAndroid Build Coastguard Worker   do {                                         \
50*6236dae4SAndroid Build Coastguard Worker     result = Curl_hmacit(&Curl_HMAC_SHA256,    \
51*6236dae4SAndroid Build Coastguard Worker                          (unsigned char *)k,   \
52*6236dae4SAndroid Build Coastguard Worker                          kl,                   \
53*6236dae4SAndroid Build Coastguard Worker                          (unsigned char *)d,   \
54*6236dae4SAndroid Build Coastguard Worker                          dl, o);               \
55*6236dae4SAndroid Build Coastguard Worker     if(result) {                               \
56*6236dae4SAndroid Build Coastguard Worker       goto fail;                               \
57*6236dae4SAndroid Build Coastguard Worker     }                                          \
58*6236dae4SAndroid Build Coastguard Worker   } while(0)
59*6236dae4SAndroid Build Coastguard Worker 
60*6236dae4SAndroid Build Coastguard Worker #define TIMESTAMP_SIZE 17
61*6236dae4SAndroid Build Coastguard Worker 
62*6236dae4SAndroid Build Coastguard Worker /* hex-encoded with trailing null */
63*6236dae4SAndroid Build Coastguard Worker #define SHA256_HEX_LENGTH (2 * CURL_SHA256_DIGEST_LENGTH + 1)
64*6236dae4SAndroid Build Coastguard Worker 
sha256_to_hex(char * dst,unsigned char * sha)65*6236dae4SAndroid Build Coastguard Worker static void sha256_to_hex(char *dst, unsigned char *sha)
66*6236dae4SAndroid Build Coastguard Worker {
67*6236dae4SAndroid Build Coastguard Worker   Curl_hexencode(sha, CURL_SHA256_DIGEST_LENGTH,
68*6236dae4SAndroid Build Coastguard Worker                  (unsigned char *)dst, SHA256_HEX_LENGTH);
69*6236dae4SAndroid Build Coastguard Worker }
70*6236dae4SAndroid Build Coastguard Worker 
find_date_hdr(struct Curl_easy * data,const char * sig_hdr)71*6236dae4SAndroid Build Coastguard Worker static char *find_date_hdr(struct Curl_easy *data, const char *sig_hdr)
72*6236dae4SAndroid Build Coastguard Worker {
73*6236dae4SAndroid Build Coastguard Worker   char *tmp = Curl_checkheaders(data, sig_hdr, strlen(sig_hdr));
74*6236dae4SAndroid Build Coastguard Worker 
75*6236dae4SAndroid Build Coastguard Worker   if(tmp)
76*6236dae4SAndroid Build Coastguard Worker     return tmp;
77*6236dae4SAndroid Build Coastguard Worker   return Curl_checkheaders(data, STRCONST("Date"));
78*6236dae4SAndroid Build Coastguard Worker }
79*6236dae4SAndroid Build Coastguard Worker 
80*6236dae4SAndroid Build Coastguard Worker /* remove whitespace, and lowercase all headers */
trim_headers(struct curl_slist * head)81*6236dae4SAndroid Build Coastguard Worker static void trim_headers(struct curl_slist *head)
82*6236dae4SAndroid Build Coastguard Worker {
83*6236dae4SAndroid Build Coastguard Worker   struct curl_slist *l;
84*6236dae4SAndroid Build Coastguard Worker   for(l = head; l; l = l->next) {
85*6236dae4SAndroid Build Coastguard Worker     char *value; /* to read from */
86*6236dae4SAndroid Build Coastguard Worker     char *store;
87*6236dae4SAndroid Build Coastguard Worker     size_t colon = strcspn(l->data, ":");
88*6236dae4SAndroid Build Coastguard Worker     Curl_strntolower(l->data, l->data, colon);
89*6236dae4SAndroid Build Coastguard Worker 
90*6236dae4SAndroid Build Coastguard Worker     value = &l->data[colon];
91*6236dae4SAndroid Build Coastguard Worker     if(!*value)
92*6236dae4SAndroid Build Coastguard Worker       continue;
93*6236dae4SAndroid Build Coastguard Worker     ++value;
94*6236dae4SAndroid Build Coastguard Worker     store = value;
95*6236dae4SAndroid Build Coastguard Worker 
96*6236dae4SAndroid Build Coastguard Worker     /* skip leading whitespace */
97*6236dae4SAndroid Build Coastguard Worker     while(*value && ISBLANK(*value))
98*6236dae4SAndroid Build Coastguard Worker       value++;
99*6236dae4SAndroid Build Coastguard Worker 
100*6236dae4SAndroid Build Coastguard Worker     while(*value) {
101*6236dae4SAndroid Build Coastguard Worker       int space = 0;
102*6236dae4SAndroid Build Coastguard Worker       while(*value && ISBLANK(*value)) {
103*6236dae4SAndroid Build Coastguard Worker         value++;
104*6236dae4SAndroid Build Coastguard Worker         space++;
105*6236dae4SAndroid Build Coastguard Worker       }
106*6236dae4SAndroid Build Coastguard Worker       if(space) {
107*6236dae4SAndroid Build Coastguard Worker         /* replace any number of consecutive whitespace with a single space,
108*6236dae4SAndroid Build Coastguard Worker            unless at the end of the string, then nothing */
109*6236dae4SAndroid Build Coastguard Worker         if(*value)
110*6236dae4SAndroid Build Coastguard Worker           *store++ = ' ';
111*6236dae4SAndroid Build Coastguard Worker       }
112*6236dae4SAndroid Build Coastguard Worker       else
113*6236dae4SAndroid Build Coastguard Worker         *store++ = *value++;
114*6236dae4SAndroid Build Coastguard Worker     }
115*6236dae4SAndroid Build Coastguard Worker     *store = 0; /* null terminate */
116*6236dae4SAndroid Build Coastguard Worker   }
117*6236dae4SAndroid Build Coastguard Worker }
118*6236dae4SAndroid Build Coastguard Worker 
119*6236dae4SAndroid Build Coastguard Worker /* maximum length for the aws sivg4 parts */
120*6236dae4SAndroid Build Coastguard Worker #define MAX_SIGV4_LEN 64
121*6236dae4SAndroid Build Coastguard Worker #define MAX_SIGV4_LEN_TXT "64"
122*6236dae4SAndroid Build Coastguard Worker 
123*6236dae4SAndroid Build Coastguard Worker #define DATE_HDR_KEY_LEN (MAX_SIGV4_LEN + sizeof("X--Date"))
124*6236dae4SAndroid Build Coastguard Worker 
125*6236dae4SAndroid Build Coastguard Worker /* string been x-PROVIDER-date:TIMESTAMP, I need +1 for ':' */
126*6236dae4SAndroid Build Coastguard Worker #define DATE_FULL_HDR_LEN (DATE_HDR_KEY_LEN + TIMESTAMP_SIZE + 1)
127*6236dae4SAndroid Build Coastguard Worker 
128*6236dae4SAndroid Build Coastguard Worker /* alphabetically compare two headers by their name, expecting
129*6236dae4SAndroid Build Coastguard Worker    headers to use ':' at this point */
compare_header_names(const char * a,const char * b)130*6236dae4SAndroid Build Coastguard Worker static int compare_header_names(const char *a, const char *b)
131*6236dae4SAndroid Build Coastguard Worker {
132*6236dae4SAndroid Build Coastguard Worker   const char *colon_a;
133*6236dae4SAndroid Build Coastguard Worker   const char *colon_b;
134*6236dae4SAndroid Build Coastguard Worker   size_t len_a;
135*6236dae4SAndroid Build Coastguard Worker   size_t len_b;
136*6236dae4SAndroid Build Coastguard Worker   size_t min_len;
137*6236dae4SAndroid Build Coastguard Worker   int cmp;
138*6236dae4SAndroid Build Coastguard Worker 
139*6236dae4SAndroid Build Coastguard Worker   colon_a = strchr(a, ':');
140*6236dae4SAndroid Build Coastguard Worker   colon_b = strchr(b, ':');
141*6236dae4SAndroid Build Coastguard Worker 
142*6236dae4SAndroid Build Coastguard Worker   DEBUGASSERT(colon_a);
143*6236dae4SAndroid Build Coastguard Worker   DEBUGASSERT(colon_b);
144*6236dae4SAndroid Build Coastguard Worker 
145*6236dae4SAndroid Build Coastguard Worker   len_a = colon_a ? (size_t)(colon_a - a) : strlen(a);
146*6236dae4SAndroid Build Coastguard Worker   len_b = colon_b ? (size_t)(colon_b - b) : strlen(b);
147*6236dae4SAndroid Build Coastguard Worker 
148*6236dae4SAndroid Build Coastguard Worker   min_len = (len_a < len_b) ? len_a : len_b;
149*6236dae4SAndroid Build Coastguard Worker 
150*6236dae4SAndroid Build Coastguard Worker   cmp = strncmp(a, b, min_len);
151*6236dae4SAndroid Build Coastguard Worker 
152*6236dae4SAndroid Build Coastguard Worker   /* return the shorter of the two if one is shorter */
153*6236dae4SAndroid Build Coastguard Worker   if(!cmp)
154*6236dae4SAndroid Build Coastguard Worker     return (int)(len_a - len_b);
155*6236dae4SAndroid Build Coastguard Worker 
156*6236dae4SAndroid Build Coastguard Worker   return cmp;
157*6236dae4SAndroid Build Coastguard Worker }
158*6236dae4SAndroid Build Coastguard Worker 
159*6236dae4SAndroid Build Coastguard Worker /* timestamp should point to a buffer of at last TIMESTAMP_SIZE bytes */
make_headers(struct Curl_easy * data,const char * hostname,char * timestamp,char * provider1,char ** date_header,char * content_sha256_header,struct dynbuf * canonical_headers,struct dynbuf * signed_headers)160*6236dae4SAndroid Build Coastguard Worker static CURLcode make_headers(struct Curl_easy *data,
161*6236dae4SAndroid Build Coastguard Worker                              const char *hostname,
162*6236dae4SAndroid Build Coastguard Worker                              char *timestamp,
163*6236dae4SAndroid Build Coastguard Worker                              char *provider1,
164*6236dae4SAndroid Build Coastguard Worker                              char **date_header,
165*6236dae4SAndroid Build Coastguard Worker                              char *content_sha256_header,
166*6236dae4SAndroid Build Coastguard Worker                              struct dynbuf *canonical_headers,
167*6236dae4SAndroid Build Coastguard Worker                              struct dynbuf *signed_headers)
168*6236dae4SAndroid Build Coastguard Worker {
169*6236dae4SAndroid Build Coastguard Worker   char date_hdr_key[DATE_HDR_KEY_LEN];
170*6236dae4SAndroid Build Coastguard Worker   char date_full_hdr[DATE_FULL_HDR_LEN];
171*6236dae4SAndroid Build Coastguard Worker   struct curl_slist *head = NULL;
172*6236dae4SAndroid Build Coastguard Worker   struct curl_slist *tmp_head = NULL;
173*6236dae4SAndroid Build Coastguard Worker   CURLcode ret = CURLE_OUT_OF_MEMORY;
174*6236dae4SAndroid Build Coastguard Worker   struct curl_slist *l;
175*6236dae4SAndroid Build Coastguard Worker   bool again = TRUE;
176*6236dae4SAndroid Build Coastguard Worker 
177*6236dae4SAndroid Build Coastguard Worker   /* provider1 mid */
178*6236dae4SAndroid Build Coastguard Worker   Curl_strntolower(provider1, provider1, strlen(provider1));
179*6236dae4SAndroid Build Coastguard Worker   provider1[0] = Curl_raw_toupper(provider1[0]);
180*6236dae4SAndroid Build Coastguard Worker 
181*6236dae4SAndroid Build Coastguard Worker   msnprintf(date_hdr_key, DATE_HDR_KEY_LEN, "X-%s-Date", provider1);
182*6236dae4SAndroid Build Coastguard Worker 
183*6236dae4SAndroid Build Coastguard Worker   /* provider1 lowercase */
184*6236dae4SAndroid Build Coastguard Worker   Curl_strntolower(provider1, provider1, 1); /* first byte only */
185*6236dae4SAndroid Build Coastguard Worker   msnprintf(date_full_hdr, DATE_FULL_HDR_LEN,
186*6236dae4SAndroid Build Coastguard Worker             "x-%s-date:%s", provider1, timestamp);
187*6236dae4SAndroid Build Coastguard Worker 
188*6236dae4SAndroid Build Coastguard Worker   if(!Curl_checkheaders(data, STRCONST("Host"))) {
189*6236dae4SAndroid Build Coastguard Worker     char *fullhost;
190*6236dae4SAndroid Build Coastguard Worker 
191*6236dae4SAndroid Build Coastguard Worker     if(data->state.aptr.host) {
192*6236dae4SAndroid Build Coastguard Worker       /* remove /r/n as the separator for canonical request must be '\n' */
193*6236dae4SAndroid Build Coastguard Worker       size_t pos = strcspn(data->state.aptr.host, "\n\r");
194*6236dae4SAndroid Build Coastguard Worker       fullhost = Curl_memdup0(data->state.aptr.host, pos);
195*6236dae4SAndroid Build Coastguard Worker     }
196*6236dae4SAndroid Build Coastguard Worker     else
197*6236dae4SAndroid Build Coastguard Worker       fullhost = aprintf("host:%s", hostname);
198*6236dae4SAndroid Build Coastguard Worker 
199*6236dae4SAndroid Build Coastguard Worker     if(fullhost)
200*6236dae4SAndroid Build Coastguard Worker       head = Curl_slist_append_nodup(NULL, fullhost);
201*6236dae4SAndroid Build Coastguard Worker     if(!head) {
202*6236dae4SAndroid Build Coastguard Worker       free(fullhost);
203*6236dae4SAndroid Build Coastguard Worker       goto fail;
204*6236dae4SAndroid Build Coastguard Worker     }
205*6236dae4SAndroid Build Coastguard Worker   }
206*6236dae4SAndroid Build Coastguard Worker 
207*6236dae4SAndroid Build Coastguard Worker 
208*6236dae4SAndroid Build Coastguard Worker   if(*content_sha256_header) {
209*6236dae4SAndroid Build Coastguard Worker     tmp_head = curl_slist_append(head, content_sha256_header);
210*6236dae4SAndroid Build Coastguard Worker     if(!tmp_head)
211*6236dae4SAndroid Build Coastguard Worker       goto fail;
212*6236dae4SAndroid Build Coastguard Worker     head = tmp_head;
213*6236dae4SAndroid Build Coastguard Worker   }
214*6236dae4SAndroid Build Coastguard Worker 
215*6236dae4SAndroid Build Coastguard Worker   /* copy user headers to our header list. the logic is based on how http.c
216*6236dae4SAndroid Build Coastguard Worker      handles user headers.
217*6236dae4SAndroid Build Coastguard Worker 
218*6236dae4SAndroid Build Coastguard Worker      user headers in format 'name:' with no value are used to signal that an
219*6236dae4SAndroid Build Coastguard Worker      internal header of that name should be removed. those user headers are not
220*6236dae4SAndroid Build Coastguard Worker      added to this list.
221*6236dae4SAndroid Build Coastguard Worker 
222*6236dae4SAndroid Build Coastguard Worker      user headers in format 'name;' with no value are used to signal that a
223*6236dae4SAndroid Build Coastguard Worker      header of that name with no value should be sent. those user headers are
224*6236dae4SAndroid Build Coastguard Worker      added to this list but in the format that they will be sent, ie the
225*6236dae4SAndroid Build Coastguard Worker      semi-colon is changed to a colon for format 'name:'.
226*6236dae4SAndroid Build Coastguard Worker 
227*6236dae4SAndroid Build Coastguard Worker      user headers with a value of whitespace only, or without a colon or
228*6236dae4SAndroid Build Coastguard Worker      semi-colon, are not added to this list.
229*6236dae4SAndroid Build Coastguard Worker      */
230*6236dae4SAndroid Build Coastguard Worker   for(l = data->set.headers; l; l = l->next) {
231*6236dae4SAndroid Build Coastguard Worker     char *dupdata, *ptr;
232*6236dae4SAndroid Build Coastguard Worker     char *sep = strchr(l->data, ':');
233*6236dae4SAndroid Build Coastguard Worker     if(!sep)
234*6236dae4SAndroid Build Coastguard Worker       sep = strchr(l->data, ';');
235*6236dae4SAndroid Build Coastguard Worker     if(!sep || (*sep == ':' && !*(sep + 1)))
236*6236dae4SAndroid Build Coastguard Worker       continue;
237*6236dae4SAndroid Build Coastguard Worker     for(ptr = sep + 1; ISSPACE(*ptr); ++ptr)
238*6236dae4SAndroid Build Coastguard Worker       ;
239*6236dae4SAndroid Build Coastguard Worker     if(!*ptr && ptr != sep + 1) /* a value of whitespace only */
240*6236dae4SAndroid Build Coastguard Worker       continue;
241*6236dae4SAndroid Build Coastguard Worker     dupdata = strdup(l->data);
242*6236dae4SAndroid Build Coastguard Worker     if(!dupdata)
243*6236dae4SAndroid Build Coastguard Worker       goto fail;
244*6236dae4SAndroid Build Coastguard Worker     dupdata[sep - l->data] = ':';
245*6236dae4SAndroid Build Coastguard Worker     tmp_head = Curl_slist_append_nodup(head, dupdata);
246*6236dae4SAndroid Build Coastguard Worker     if(!tmp_head) {
247*6236dae4SAndroid Build Coastguard Worker       free(dupdata);
248*6236dae4SAndroid Build Coastguard Worker       goto fail;
249*6236dae4SAndroid Build Coastguard Worker     }
250*6236dae4SAndroid Build Coastguard Worker     head = tmp_head;
251*6236dae4SAndroid Build Coastguard Worker   }
252*6236dae4SAndroid Build Coastguard Worker 
253*6236dae4SAndroid Build Coastguard Worker   trim_headers(head);
254*6236dae4SAndroid Build Coastguard Worker 
255*6236dae4SAndroid Build Coastguard Worker   *date_header = find_date_hdr(data, date_hdr_key);
256*6236dae4SAndroid Build Coastguard Worker   if(!*date_header) {
257*6236dae4SAndroid Build Coastguard Worker     tmp_head = curl_slist_append(head, date_full_hdr);
258*6236dae4SAndroid Build Coastguard Worker     if(!tmp_head)
259*6236dae4SAndroid Build Coastguard Worker       goto fail;
260*6236dae4SAndroid Build Coastguard Worker     head = tmp_head;
261*6236dae4SAndroid Build Coastguard Worker     *date_header = aprintf("%s: %s\r\n", date_hdr_key, timestamp);
262*6236dae4SAndroid Build Coastguard Worker   }
263*6236dae4SAndroid Build Coastguard Worker   else {
264*6236dae4SAndroid Build Coastguard Worker     char *value;
265*6236dae4SAndroid Build Coastguard Worker     char *endp;
266*6236dae4SAndroid Build Coastguard Worker     value = strchr(*date_header, ':');
267*6236dae4SAndroid Build Coastguard Worker     if(!value) {
268*6236dae4SAndroid Build Coastguard Worker       *date_header = NULL;
269*6236dae4SAndroid Build Coastguard Worker       goto fail;
270*6236dae4SAndroid Build Coastguard Worker     }
271*6236dae4SAndroid Build Coastguard Worker     ++value;
272*6236dae4SAndroid Build Coastguard Worker     while(ISBLANK(*value))
273*6236dae4SAndroid Build Coastguard Worker       ++value;
274*6236dae4SAndroid Build Coastguard Worker     endp = value;
275*6236dae4SAndroid Build Coastguard Worker     while(*endp && ISALNUM(*endp))
276*6236dae4SAndroid Build Coastguard Worker       ++endp;
277*6236dae4SAndroid Build Coastguard Worker     /* 16 bytes => "19700101T000000Z" */
278*6236dae4SAndroid Build Coastguard Worker     if((endp - value) == TIMESTAMP_SIZE - 1) {
279*6236dae4SAndroid Build Coastguard Worker       memcpy(timestamp, value, TIMESTAMP_SIZE - 1);
280*6236dae4SAndroid Build Coastguard Worker       timestamp[TIMESTAMP_SIZE - 1] = 0;
281*6236dae4SAndroid Build Coastguard Worker     }
282*6236dae4SAndroid Build Coastguard Worker     else
283*6236dae4SAndroid Build Coastguard Worker       /* bad timestamp length */
284*6236dae4SAndroid Build Coastguard Worker       timestamp[0] = 0;
285*6236dae4SAndroid Build Coastguard Worker     *date_header = NULL;
286*6236dae4SAndroid Build Coastguard Worker   }
287*6236dae4SAndroid Build Coastguard Worker 
288*6236dae4SAndroid Build Coastguard Worker   /* alpha-sort by header name in a case sensitive manner */
289*6236dae4SAndroid Build Coastguard Worker   do {
290*6236dae4SAndroid Build Coastguard Worker     again = FALSE;
291*6236dae4SAndroid Build Coastguard Worker     for(l = head; l; l = l->next) {
292*6236dae4SAndroid Build Coastguard Worker       struct curl_slist *next = l->next;
293*6236dae4SAndroid Build Coastguard Worker 
294*6236dae4SAndroid Build Coastguard Worker       if(next && compare_header_names(l->data, next->data) > 0) {
295*6236dae4SAndroid Build Coastguard Worker         char *tmp = l->data;
296*6236dae4SAndroid Build Coastguard Worker 
297*6236dae4SAndroid Build Coastguard Worker         l->data = next->data;
298*6236dae4SAndroid Build Coastguard Worker         next->data = tmp;
299*6236dae4SAndroid Build Coastguard Worker         again = TRUE;
300*6236dae4SAndroid Build Coastguard Worker       }
301*6236dae4SAndroid Build Coastguard Worker     }
302*6236dae4SAndroid Build Coastguard Worker   } while(again);
303*6236dae4SAndroid Build Coastguard Worker 
304*6236dae4SAndroid Build Coastguard Worker   for(l = head; l; l = l->next) {
305*6236dae4SAndroid Build Coastguard Worker     char *tmp;
306*6236dae4SAndroid Build Coastguard Worker 
307*6236dae4SAndroid Build Coastguard Worker     if(Curl_dyn_add(canonical_headers, l->data))
308*6236dae4SAndroid Build Coastguard Worker       goto fail;
309*6236dae4SAndroid Build Coastguard Worker     if(Curl_dyn_add(canonical_headers, "\n"))
310*6236dae4SAndroid Build Coastguard Worker       goto fail;
311*6236dae4SAndroid Build Coastguard Worker 
312*6236dae4SAndroid Build Coastguard Worker     tmp = strchr(l->data, ':');
313*6236dae4SAndroid Build Coastguard Worker     if(tmp)
314*6236dae4SAndroid Build Coastguard Worker       *tmp = 0;
315*6236dae4SAndroid Build Coastguard Worker 
316*6236dae4SAndroid Build Coastguard Worker     if(l != head) {
317*6236dae4SAndroid Build Coastguard Worker       if(Curl_dyn_add(signed_headers, ";"))
318*6236dae4SAndroid Build Coastguard Worker         goto fail;
319*6236dae4SAndroid Build Coastguard Worker     }
320*6236dae4SAndroid Build Coastguard Worker     if(Curl_dyn_add(signed_headers, l->data))
321*6236dae4SAndroid Build Coastguard Worker       goto fail;
322*6236dae4SAndroid Build Coastguard Worker   }
323*6236dae4SAndroid Build Coastguard Worker 
324*6236dae4SAndroid Build Coastguard Worker   ret = CURLE_OK;
325*6236dae4SAndroid Build Coastguard Worker fail:
326*6236dae4SAndroid Build Coastguard Worker   curl_slist_free_all(head);
327*6236dae4SAndroid Build Coastguard Worker 
328*6236dae4SAndroid Build Coastguard Worker   return ret;
329*6236dae4SAndroid Build Coastguard Worker }
330*6236dae4SAndroid Build Coastguard Worker 
331*6236dae4SAndroid Build Coastguard Worker #define CONTENT_SHA256_KEY_LEN (MAX_SIGV4_LEN + sizeof("X--Content-Sha256"))
332*6236dae4SAndroid Build Coastguard Worker /* add 2 for ": " between header name and value */
333*6236dae4SAndroid Build Coastguard Worker #define CONTENT_SHA256_HDR_LEN (CONTENT_SHA256_KEY_LEN + 2 + \
334*6236dae4SAndroid Build Coastguard Worker                                 SHA256_HEX_LENGTH)
335*6236dae4SAndroid Build Coastguard Worker 
336*6236dae4SAndroid Build Coastguard Worker /* try to parse a payload hash from the content-sha256 header */
parse_content_sha_hdr(struct Curl_easy * data,const char * provider1,size_t * value_len)337*6236dae4SAndroid Build Coastguard Worker static char *parse_content_sha_hdr(struct Curl_easy *data,
338*6236dae4SAndroid Build Coastguard Worker                                    const char *provider1,
339*6236dae4SAndroid Build Coastguard Worker                                    size_t *value_len)
340*6236dae4SAndroid Build Coastguard Worker {
341*6236dae4SAndroid Build Coastguard Worker   char key[CONTENT_SHA256_KEY_LEN];
342*6236dae4SAndroid Build Coastguard Worker   size_t key_len;
343*6236dae4SAndroid Build Coastguard Worker   char *value;
344*6236dae4SAndroid Build Coastguard Worker   size_t len;
345*6236dae4SAndroid Build Coastguard Worker 
346*6236dae4SAndroid Build Coastguard Worker   key_len = msnprintf(key, sizeof(key), "x-%s-content-sha256", provider1);
347*6236dae4SAndroid Build Coastguard Worker 
348*6236dae4SAndroid Build Coastguard Worker   value = Curl_checkheaders(data, key, key_len);
349*6236dae4SAndroid Build Coastguard Worker   if(!value)
350*6236dae4SAndroid Build Coastguard Worker     return NULL;
351*6236dae4SAndroid Build Coastguard Worker 
352*6236dae4SAndroid Build Coastguard Worker   value = strchr(value, ':');
353*6236dae4SAndroid Build Coastguard Worker   if(!value)
354*6236dae4SAndroid Build Coastguard Worker     return NULL;
355*6236dae4SAndroid Build Coastguard Worker   ++value;
356*6236dae4SAndroid Build Coastguard Worker 
357*6236dae4SAndroid Build Coastguard Worker   while(*value && ISBLANK(*value))
358*6236dae4SAndroid Build Coastguard Worker     ++value;
359*6236dae4SAndroid Build Coastguard Worker 
360*6236dae4SAndroid Build Coastguard Worker   len = strlen(value);
361*6236dae4SAndroid Build Coastguard Worker   while(len > 0 && ISBLANK(value[len-1]))
362*6236dae4SAndroid Build Coastguard Worker     --len;
363*6236dae4SAndroid Build Coastguard Worker 
364*6236dae4SAndroid Build Coastguard Worker   *value_len = len;
365*6236dae4SAndroid Build Coastguard Worker   return value;
366*6236dae4SAndroid Build Coastguard Worker }
367*6236dae4SAndroid Build Coastguard Worker 
calc_payload_hash(struct Curl_easy * data,unsigned char * sha_hash,char * sha_hex)368*6236dae4SAndroid Build Coastguard Worker static CURLcode calc_payload_hash(struct Curl_easy *data,
369*6236dae4SAndroid Build Coastguard Worker                                   unsigned char *sha_hash, char *sha_hex)
370*6236dae4SAndroid Build Coastguard Worker {
371*6236dae4SAndroid Build Coastguard Worker   const char *post_data = data->set.postfields;
372*6236dae4SAndroid Build Coastguard Worker   size_t post_data_len = 0;
373*6236dae4SAndroid Build Coastguard Worker   CURLcode result;
374*6236dae4SAndroid Build Coastguard Worker 
375*6236dae4SAndroid Build Coastguard Worker   if(post_data) {
376*6236dae4SAndroid Build Coastguard Worker     if(data->set.postfieldsize < 0)
377*6236dae4SAndroid Build Coastguard Worker       post_data_len = strlen(post_data);
378*6236dae4SAndroid Build Coastguard Worker     else
379*6236dae4SAndroid Build Coastguard Worker       post_data_len = (size_t)data->set.postfieldsize;
380*6236dae4SAndroid Build Coastguard Worker   }
381*6236dae4SAndroid Build Coastguard Worker   result = Curl_sha256it(sha_hash, (const unsigned char *) post_data,
382*6236dae4SAndroid Build Coastguard Worker                          post_data_len);
383*6236dae4SAndroid Build Coastguard Worker   if(!result)
384*6236dae4SAndroid Build Coastguard Worker     sha256_to_hex(sha_hex, sha_hash);
385*6236dae4SAndroid Build Coastguard Worker   return result;
386*6236dae4SAndroid Build Coastguard Worker }
387*6236dae4SAndroid Build Coastguard Worker 
388*6236dae4SAndroid Build Coastguard Worker #define S3_UNSIGNED_PAYLOAD "UNSIGNED-PAYLOAD"
389*6236dae4SAndroid Build Coastguard Worker 
calc_s3_payload_hash(struct Curl_easy * data,Curl_HttpReq httpreq,char * provider1,unsigned char * sha_hash,char * sha_hex,char * header)390*6236dae4SAndroid Build Coastguard Worker static CURLcode calc_s3_payload_hash(struct Curl_easy *data,
391*6236dae4SAndroid Build Coastguard Worker                                      Curl_HttpReq httpreq, char *provider1,
392*6236dae4SAndroid Build Coastguard Worker                                      unsigned char *sha_hash,
393*6236dae4SAndroid Build Coastguard Worker                                      char *sha_hex, char *header)
394*6236dae4SAndroid Build Coastguard Worker {
395*6236dae4SAndroid Build Coastguard Worker   bool empty_method = (httpreq == HTTPREQ_GET || httpreq == HTTPREQ_HEAD);
396*6236dae4SAndroid Build Coastguard Worker   /* The request method or filesize indicate no request payload */
397*6236dae4SAndroid Build Coastguard Worker   bool empty_payload = (empty_method || data->set.filesize == 0);
398*6236dae4SAndroid Build Coastguard Worker   /* The POST payload is in memory */
399*6236dae4SAndroid Build Coastguard Worker   bool post_payload = (httpreq == HTTPREQ_POST && data->set.postfields);
400*6236dae4SAndroid Build Coastguard Worker   CURLcode ret = CURLE_OUT_OF_MEMORY;
401*6236dae4SAndroid Build Coastguard Worker 
402*6236dae4SAndroid Build Coastguard Worker   if(empty_payload || post_payload) {
403*6236dae4SAndroid Build Coastguard Worker     /* Calculate a real hash when we know the request payload */
404*6236dae4SAndroid Build Coastguard Worker     ret = calc_payload_hash(data, sha_hash, sha_hex);
405*6236dae4SAndroid Build Coastguard Worker     if(ret)
406*6236dae4SAndroid Build Coastguard Worker       goto fail;
407*6236dae4SAndroid Build Coastguard Worker   }
408*6236dae4SAndroid Build Coastguard Worker   else {
409*6236dae4SAndroid Build Coastguard Worker     /* Fall back to s3's UNSIGNED-PAYLOAD */
410*6236dae4SAndroid Build Coastguard Worker     size_t len = sizeof(S3_UNSIGNED_PAYLOAD) - 1;
411*6236dae4SAndroid Build Coastguard Worker     DEBUGASSERT(len < SHA256_HEX_LENGTH); /* 16 < 65 */
412*6236dae4SAndroid Build Coastguard Worker     memcpy(sha_hex, S3_UNSIGNED_PAYLOAD, len);
413*6236dae4SAndroid Build Coastguard Worker     sha_hex[len] = 0;
414*6236dae4SAndroid Build Coastguard Worker   }
415*6236dae4SAndroid Build Coastguard Worker 
416*6236dae4SAndroid Build Coastguard Worker   /* format the required content-sha256 header */
417*6236dae4SAndroid Build Coastguard Worker   msnprintf(header, CONTENT_SHA256_HDR_LEN,
418*6236dae4SAndroid Build Coastguard Worker             "x-%s-content-sha256: %s", provider1, sha_hex);
419*6236dae4SAndroid Build Coastguard Worker 
420*6236dae4SAndroid Build Coastguard Worker   ret = CURLE_OK;
421*6236dae4SAndroid Build Coastguard Worker fail:
422*6236dae4SAndroid Build Coastguard Worker   return ret;
423*6236dae4SAndroid Build Coastguard Worker }
424*6236dae4SAndroid Build Coastguard Worker 
425*6236dae4SAndroid Build Coastguard Worker struct pair {
426*6236dae4SAndroid Build Coastguard Worker   const char *p;
427*6236dae4SAndroid Build Coastguard Worker   size_t len;
428*6236dae4SAndroid Build Coastguard Worker };
429*6236dae4SAndroid Build Coastguard Worker 
compare_func(const void * a,const void * b)430*6236dae4SAndroid Build Coastguard Worker static int compare_func(const void *a, const void *b)
431*6236dae4SAndroid Build Coastguard Worker {
432*6236dae4SAndroid Build Coastguard Worker   const struct pair *aa = a;
433*6236dae4SAndroid Build Coastguard Worker   const struct pair *bb = b;
434*6236dae4SAndroid Build Coastguard Worker   /* If one element is empty, the other is always sorted higher */
435*6236dae4SAndroid Build Coastguard Worker   if(aa->len == 0)
436*6236dae4SAndroid Build Coastguard Worker     return -1;
437*6236dae4SAndroid Build Coastguard Worker   if(bb->len == 0)
438*6236dae4SAndroid Build Coastguard Worker     return 1;
439*6236dae4SAndroid Build Coastguard Worker   return strncmp(aa->p, bb->p, aa->len < bb->len ? aa->len : bb->len);
440*6236dae4SAndroid Build Coastguard Worker }
441*6236dae4SAndroid Build Coastguard Worker 
442*6236dae4SAndroid Build Coastguard Worker #define MAX_QUERYPAIRS 64
443*6236dae4SAndroid Build Coastguard Worker 
444*6236dae4SAndroid Build Coastguard Worker /**
445*6236dae4SAndroid Build Coastguard Worker  * found_equals have a double meaning,
446*6236dae4SAndroid Build Coastguard Worker  * detect if an equal have been found when called from canon_query,
447*6236dae4SAndroid Build Coastguard Worker  * and mark that this function is called to compute the path,
448*6236dae4SAndroid Build Coastguard Worker  * if found_equals is NULL.
449*6236dae4SAndroid Build Coastguard Worker  */
canon_string(const char * q,size_t len,struct dynbuf * dq,bool * found_equals)450*6236dae4SAndroid Build Coastguard Worker static CURLcode canon_string(const char *q, size_t len,
451*6236dae4SAndroid Build Coastguard Worker                              struct dynbuf *dq, bool *found_equals)
452*6236dae4SAndroid Build Coastguard Worker {
453*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
454*6236dae4SAndroid Build Coastguard Worker 
455*6236dae4SAndroid Build Coastguard Worker   for(; len && !result; q++, len--) {
456*6236dae4SAndroid Build Coastguard Worker     if(ISALNUM(*q))
457*6236dae4SAndroid Build Coastguard Worker       result = Curl_dyn_addn(dq, q, 1);
458*6236dae4SAndroid Build Coastguard Worker     else {
459*6236dae4SAndroid Build Coastguard Worker       switch(*q) {
460*6236dae4SAndroid Build Coastguard Worker       case '-':
461*6236dae4SAndroid Build Coastguard Worker       case '.':
462*6236dae4SAndroid Build Coastguard Worker       case '_':
463*6236dae4SAndroid Build Coastguard Worker       case '~':
464*6236dae4SAndroid Build Coastguard Worker         /* allowed as-is */
465*6236dae4SAndroid Build Coastguard Worker         result = Curl_dyn_addn(dq, q, 1);
466*6236dae4SAndroid Build Coastguard Worker         break;
467*6236dae4SAndroid Build Coastguard Worker       case '%':
468*6236dae4SAndroid Build Coastguard Worker         /* uppercase the following if hexadecimal */
469*6236dae4SAndroid Build Coastguard Worker         if(ISXDIGIT(q[1]) && ISXDIGIT(q[2])) {
470*6236dae4SAndroid Build Coastguard Worker           char tmp[3]="%";
471*6236dae4SAndroid Build Coastguard Worker           tmp[1] = Curl_raw_toupper(q[1]);
472*6236dae4SAndroid Build Coastguard Worker           tmp[2] = Curl_raw_toupper(q[2]);
473*6236dae4SAndroid Build Coastguard Worker           result = Curl_dyn_addn(dq, tmp, 3);
474*6236dae4SAndroid Build Coastguard Worker           q += 2;
475*6236dae4SAndroid Build Coastguard Worker           len -= 2;
476*6236dae4SAndroid Build Coastguard Worker         }
477*6236dae4SAndroid Build Coastguard Worker         else
478*6236dae4SAndroid Build Coastguard Worker           /* '%' without a following two-digit hex, encode it */
479*6236dae4SAndroid Build Coastguard Worker           result = Curl_dyn_addn(dq, "%25", 3);
480*6236dae4SAndroid Build Coastguard Worker         break;
481*6236dae4SAndroid Build Coastguard Worker       default: {
482*6236dae4SAndroid Build Coastguard Worker         const char hex[] = "0123456789ABCDEF";
483*6236dae4SAndroid Build Coastguard Worker         char out[3]={'%'};
484*6236dae4SAndroid Build Coastguard Worker 
485*6236dae4SAndroid Build Coastguard Worker         if(!found_equals) {
486*6236dae4SAndroid Build Coastguard Worker           /* if found_equals is NULL assuming, been in path */
487*6236dae4SAndroid Build Coastguard Worker           if(*q == '/') {
488*6236dae4SAndroid Build Coastguard Worker             /* allowed as if */
489*6236dae4SAndroid Build Coastguard Worker             result = Curl_dyn_addn(dq, q, 1);
490*6236dae4SAndroid Build Coastguard Worker             break;
491*6236dae4SAndroid Build Coastguard Worker           }
492*6236dae4SAndroid Build Coastguard Worker         }
493*6236dae4SAndroid Build Coastguard Worker         else {
494*6236dae4SAndroid Build Coastguard Worker           /* allowed as-is */
495*6236dae4SAndroid Build Coastguard Worker           if(*q == '=') {
496*6236dae4SAndroid Build Coastguard Worker             result = Curl_dyn_addn(dq, q, 1);
497*6236dae4SAndroid Build Coastguard Worker             *found_equals = TRUE;
498*6236dae4SAndroid Build Coastguard Worker             break;
499*6236dae4SAndroid Build Coastguard Worker           }
500*6236dae4SAndroid Build Coastguard Worker         }
501*6236dae4SAndroid Build Coastguard Worker         /* URL encode */
502*6236dae4SAndroid Build Coastguard Worker         out[1] = hex[((unsigned char)*q) >> 4];
503*6236dae4SAndroid Build Coastguard Worker         out[2] = hex[*q & 0xf];
504*6236dae4SAndroid Build Coastguard Worker         result = Curl_dyn_addn(dq, out, 3);
505*6236dae4SAndroid Build Coastguard Worker         break;
506*6236dae4SAndroid Build Coastguard Worker       }
507*6236dae4SAndroid Build Coastguard Worker       }
508*6236dae4SAndroid Build Coastguard Worker     }
509*6236dae4SAndroid Build Coastguard Worker   }
510*6236dae4SAndroid Build Coastguard Worker   return result;
511*6236dae4SAndroid Build Coastguard Worker }
512*6236dae4SAndroid Build Coastguard Worker 
513*6236dae4SAndroid Build Coastguard Worker 
canon_query(struct Curl_easy * data,const char * query,struct dynbuf * dq)514*6236dae4SAndroid Build Coastguard Worker static CURLcode canon_query(struct Curl_easy *data,
515*6236dae4SAndroid Build Coastguard Worker                             const char *query, struct dynbuf *dq)
516*6236dae4SAndroid Build Coastguard Worker {
517*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
518*6236dae4SAndroid Build Coastguard Worker   int entry = 0;
519*6236dae4SAndroid Build Coastguard Worker   int i;
520*6236dae4SAndroid Build Coastguard Worker   const char *p = query;
521*6236dae4SAndroid Build Coastguard Worker   struct pair array[MAX_QUERYPAIRS];
522*6236dae4SAndroid Build Coastguard Worker   struct pair *ap = &array[0];
523*6236dae4SAndroid Build Coastguard Worker   if(!query)
524*6236dae4SAndroid Build Coastguard Worker     return result;
525*6236dae4SAndroid Build Coastguard Worker 
526*6236dae4SAndroid Build Coastguard Worker   /* sort the name=value pairs first */
527*6236dae4SAndroid Build Coastguard Worker   do {
528*6236dae4SAndroid Build Coastguard Worker     char *amp;
529*6236dae4SAndroid Build Coastguard Worker     entry++;
530*6236dae4SAndroid Build Coastguard Worker     ap->p = p;
531*6236dae4SAndroid Build Coastguard Worker     amp = strchr(p, '&');
532*6236dae4SAndroid Build Coastguard Worker     if(amp)
533*6236dae4SAndroid Build Coastguard Worker       ap->len = amp - p; /* excluding the ampersand */
534*6236dae4SAndroid Build Coastguard Worker     else {
535*6236dae4SAndroid Build Coastguard Worker       ap->len = strlen(p);
536*6236dae4SAndroid Build Coastguard Worker       break;
537*6236dae4SAndroid Build Coastguard Worker     }
538*6236dae4SAndroid Build Coastguard Worker     ap++;
539*6236dae4SAndroid Build Coastguard Worker     p = amp + 1;
540*6236dae4SAndroid Build Coastguard Worker   } while(entry < MAX_QUERYPAIRS);
541*6236dae4SAndroid Build Coastguard Worker   if(entry == MAX_QUERYPAIRS) {
542*6236dae4SAndroid Build Coastguard Worker     /* too many query pairs for us */
543*6236dae4SAndroid Build Coastguard Worker     failf(data, "aws-sigv4: too many query pairs in URL");
544*6236dae4SAndroid Build Coastguard Worker     return CURLE_URL_MALFORMAT;
545*6236dae4SAndroid Build Coastguard Worker   }
546*6236dae4SAndroid Build Coastguard Worker 
547*6236dae4SAndroid Build Coastguard Worker   qsort(&array[0], entry, sizeof(struct pair), compare_func);
548*6236dae4SAndroid Build Coastguard Worker 
549*6236dae4SAndroid Build Coastguard Worker   ap = &array[0];
550*6236dae4SAndroid Build Coastguard Worker   for(i = 0; !result && (i < entry); i++, ap++) {
551*6236dae4SAndroid Build Coastguard Worker     const char *q = ap->p;
552*6236dae4SAndroid Build Coastguard Worker     bool found_equals = FALSE;
553*6236dae4SAndroid Build Coastguard Worker     if(!ap->len)
554*6236dae4SAndroid Build Coastguard Worker       continue;
555*6236dae4SAndroid Build Coastguard Worker     result = canon_string(q, ap->len, dq, &found_equals);
556*6236dae4SAndroid Build Coastguard Worker     if(!result && !found_equals) {
557*6236dae4SAndroid Build Coastguard Worker       /* queries without value still need an equals */
558*6236dae4SAndroid Build Coastguard Worker       result = Curl_dyn_addn(dq, "=", 1);
559*6236dae4SAndroid Build Coastguard Worker     }
560*6236dae4SAndroid Build Coastguard Worker     if(!result && i < entry - 1) {
561*6236dae4SAndroid Build Coastguard Worker       /* insert ampersands between query pairs */
562*6236dae4SAndroid Build Coastguard Worker       result = Curl_dyn_addn(dq, "&", 1);
563*6236dae4SAndroid Build Coastguard Worker     }
564*6236dae4SAndroid Build Coastguard Worker   }
565*6236dae4SAndroid Build Coastguard Worker   return result;
566*6236dae4SAndroid Build Coastguard Worker }
567*6236dae4SAndroid Build Coastguard Worker 
568*6236dae4SAndroid Build Coastguard Worker 
Curl_output_aws_sigv4(struct Curl_easy * data,bool proxy)569*6236dae4SAndroid Build Coastguard Worker CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
570*6236dae4SAndroid Build Coastguard Worker {
571*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OUT_OF_MEMORY;
572*6236dae4SAndroid Build Coastguard Worker   struct connectdata *conn = data->conn;
573*6236dae4SAndroid Build Coastguard Worker   size_t len;
574*6236dae4SAndroid Build Coastguard Worker   const char *arg;
575*6236dae4SAndroid Build Coastguard Worker   char provider0[MAX_SIGV4_LEN + 1]="";
576*6236dae4SAndroid Build Coastguard Worker   char provider1[MAX_SIGV4_LEN + 1]="";
577*6236dae4SAndroid Build Coastguard Worker   char region[MAX_SIGV4_LEN + 1]="";
578*6236dae4SAndroid Build Coastguard Worker   char service[MAX_SIGV4_LEN + 1]="";
579*6236dae4SAndroid Build Coastguard Worker   bool sign_as_s3 = FALSE;
580*6236dae4SAndroid Build Coastguard Worker   const char *hostname = conn->host.name;
581*6236dae4SAndroid Build Coastguard Worker   time_t clock;
582*6236dae4SAndroid Build Coastguard Worker   struct tm tm;
583*6236dae4SAndroid Build Coastguard Worker   char timestamp[TIMESTAMP_SIZE];
584*6236dae4SAndroid Build Coastguard Worker   char date[9];
585*6236dae4SAndroid Build Coastguard Worker   struct dynbuf canonical_headers;
586*6236dae4SAndroid Build Coastguard Worker   struct dynbuf signed_headers;
587*6236dae4SAndroid Build Coastguard Worker   struct dynbuf canonical_query;
588*6236dae4SAndroid Build Coastguard Worker   struct dynbuf canonical_path;
589*6236dae4SAndroid Build Coastguard Worker   char *date_header = NULL;
590*6236dae4SAndroid Build Coastguard Worker   Curl_HttpReq httpreq;
591*6236dae4SAndroid Build Coastguard Worker   const char *method = NULL;
592*6236dae4SAndroid Build Coastguard Worker   char *payload_hash = NULL;
593*6236dae4SAndroid Build Coastguard Worker   size_t payload_hash_len = 0;
594*6236dae4SAndroid Build Coastguard Worker   unsigned char sha_hash[CURL_SHA256_DIGEST_LENGTH];
595*6236dae4SAndroid Build Coastguard Worker   char sha_hex[SHA256_HEX_LENGTH];
596*6236dae4SAndroid Build Coastguard Worker   char content_sha256_hdr[CONTENT_SHA256_HDR_LEN + 2] = ""; /* add \r\n */
597*6236dae4SAndroid Build Coastguard Worker   char *canonical_request = NULL;
598*6236dae4SAndroid Build Coastguard Worker   char *request_type = NULL;
599*6236dae4SAndroid Build Coastguard Worker   char *credential_scope = NULL;
600*6236dae4SAndroid Build Coastguard Worker   char *str_to_sign = NULL;
601*6236dae4SAndroid Build Coastguard Worker   const char *user = data->state.aptr.user ? data->state.aptr.user : "";
602*6236dae4SAndroid Build Coastguard Worker   char *secret = NULL;
603*6236dae4SAndroid Build Coastguard Worker   unsigned char sign0[CURL_SHA256_DIGEST_LENGTH] = {0};
604*6236dae4SAndroid Build Coastguard Worker   unsigned char sign1[CURL_SHA256_DIGEST_LENGTH] = {0};
605*6236dae4SAndroid Build Coastguard Worker   char *auth_headers = NULL;
606*6236dae4SAndroid Build Coastguard Worker 
607*6236dae4SAndroid Build Coastguard Worker   DEBUGASSERT(!proxy);
608*6236dae4SAndroid Build Coastguard Worker   (void)proxy;
609*6236dae4SAndroid Build Coastguard Worker 
610*6236dae4SAndroid Build Coastguard Worker   if(Curl_checkheaders(data, STRCONST("Authorization"))) {
611*6236dae4SAndroid Build Coastguard Worker     /* Authorization already present, Bailing out */
612*6236dae4SAndroid Build Coastguard Worker     return CURLE_OK;
613*6236dae4SAndroid Build Coastguard Worker   }
614*6236dae4SAndroid Build Coastguard Worker 
615*6236dae4SAndroid Build Coastguard Worker   /* we init those buffers here, so goto fail will free initialized dynbuf */
616*6236dae4SAndroid Build Coastguard Worker   Curl_dyn_init(&canonical_headers, CURL_MAX_HTTP_HEADER);
617*6236dae4SAndroid Build Coastguard Worker   Curl_dyn_init(&canonical_query, CURL_MAX_HTTP_HEADER);
618*6236dae4SAndroid Build Coastguard Worker   Curl_dyn_init(&signed_headers, CURL_MAX_HTTP_HEADER);
619*6236dae4SAndroid Build Coastguard Worker   Curl_dyn_init(&canonical_path, CURL_MAX_HTTP_HEADER);
620*6236dae4SAndroid Build Coastguard Worker 
621*6236dae4SAndroid Build Coastguard Worker   /*
622*6236dae4SAndroid Build Coastguard Worker    * Parameters parsing
623*6236dae4SAndroid Build Coastguard Worker    * Google and Outscale use the same OSC or GOOG,
624*6236dae4SAndroid Build Coastguard Worker    * but Amazon uses AWS and AMZ for header arguments.
625*6236dae4SAndroid Build Coastguard Worker    * AWS is the default because most of non-amazon providers
626*6236dae4SAndroid Build Coastguard Worker    * are still using aws:amz as a prefix.
627*6236dae4SAndroid Build Coastguard Worker    */
628*6236dae4SAndroid Build Coastguard Worker   arg = data->set.str[STRING_AWS_SIGV4] ?
629*6236dae4SAndroid Build Coastguard Worker     data->set.str[STRING_AWS_SIGV4] : "aws:amz";
630*6236dae4SAndroid Build Coastguard Worker 
631*6236dae4SAndroid Build Coastguard Worker   /* provider1[:provider2[:region[:service]]]
632*6236dae4SAndroid Build Coastguard Worker 
633*6236dae4SAndroid Build Coastguard Worker      No string can be longer than N bytes of non-whitespace
634*6236dae4SAndroid Build Coastguard Worker   */
635*6236dae4SAndroid Build Coastguard Worker   (void)sscanf(arg, "%" MAX_SIGV4_LEN_TXT "[^:]"
636*6236dae4SAndroid Build Coastguard Worker                ":%" MAX_SIGV4_LEN_TXT "[^:]"
637*6236dae4SAndroid Build Coastguard Worker                ":%" MAX_SIGV4_LEN_TXT "[^:]"
638*6236dae4SAndroid Build Coastguard Worker                ":%" MAX_SIGV4_LEN_TXT "s",
639*6236dae4SAndroid Build Coastguard Worker                provider0, provider1, region, service);
640*6236dae4SAndroid Build Coastguard Worker   if(!provider0[0]) {
641*6236dae4SAndroid Build Coastguard Worker     failf(data, "first aws-sigv4 provider cannot be empty");
642*6236dae4SAndroid Build Coastguard Worker     result = CURLE_BAD_FUNCTION_ARGUMENT;
643*6236dae4SAndroid Build Coastguard Worker     goto fail;
644*6236dae4SAndroid Build Coastguard Worker   }
645*6236dae4SAndroid Build Coastguard Worker   else if(!provider1[0])
646*6236dae4SAndroid Build Coastguard Worker     strcpy(provider1, provider0);
647*6236dae4SAndroid Build Coastguard Worker 
648*6236dae4SAndroid Build Coastguard Worker   if(!service[0]) {
649*6236dae4SAndroid Build Coastguard Worker     char *hostdot = strchr(hostname, '.');
650*6236dae4SAndroid Build Coastguard Worker     if(!hostdot) {
651*6236dae4SAndroid Build Coastguard Worker       failf(data, "aws-sigv4: service missing in parameters and hostname");
652*6236dae4SAndroid Build Coastguard Worker       result = CURLE_URL_MALFORMAT;
653*6236dae4SAndroid Build Coastguard Worker       goto fail;
654*6236dae4SAndroid Build Coastguard Worker     }
655*6236dae4SAndroid Build Coastguard Worker     len = hostdot - hostname;
656*6236dae4SAndroid Build Coastguard Worker     if(len > MAX_SIGV4_LEN) {
657*6236dae4SAndroid Build Coastguard Worker       failf(data, "aws-sigv4: service too long in hostname");
658*6236dae4SAndroid Build Coastguard Worker       result = CURLE_URL_MALFORMAT;
659*6236dae4SAndroid Build Coastguard Worker       goto fail;
660*6236dae4SAndroid Build Coastguard Worker     }
661*6236dae4SAndroid Build Coastguard Worker     memcpy(service, hostname, len);
662*6236dae4SAndroid Build Coastguard Worker     service[len] = '\0';
663*6236dae4SAndroid Build Coastguard Worker 
664*6236dae4SAndroid Build Coastguard Worker     infof(data, "aws_sigv4: picked service %s from host", service);
665*6236dae4SAndroid Build Coastguard Worker 
666*6236dae4SAndroid Build Coastguard Worker     if(!region[0]) {
667*6236dae4SAndroid Build Coastguard Worker       const char *reg = hostdot + 1;
668*6236dae4SAndroid Build Coastguard Worker       const char *hostreg = strchr(reg, '.');
669*6236dae4SAndroid Build Coastguard Worker       if(!hostreg) {
670*6236dae4SAndroid Build Coastguard Worker         failf(data, "aws-sigv4: region missing in parameters and hostname");
671*6236dae4SAndroid Build Coastguard Worker         result = CURLE_URL_MALFORMAT;
672*6236dae4SAndroid Build Coastguard Worker         goto fail;
673*6236dae4SAndroid Build Coastguard Worker       }
674*6236dae4SAndroid Build Coastguard Worker       len = hostreg - reg;
675*6236dae4SAndroid Build Coastguard Worker       if(len > MAX_SIGV4_LEN) {
676*6236dae4SAndroid Build Coastguard Worker         failf(data, "aws-sigv4: region too long in hostname");
677*6236dae4SAndroid Build Coastguard Worker         result = CURLE_URL_MALFORMAT;
678*6236dae4SAndroid Build Coastguard Worker         goto fail;
679*6236dae4SAndroid Build Coastguard Worker       }
680*6236dae4SAndroid Build Coastguard Worker       memcpy(region, reg, len);
681*6236dae4SAndroid Build Coastguard Worker       region[len] = '\0';
682*6236dae4SAndroid Build Coastguard Worker       infof(data, "aws_sigv4: picked region %s from host", region);
683*6236dae4SAndroid Build Coastguard Worker     }
684*6236dae4SAndroid Build Coastguard Worker   }
685*6236dae4SAndroid Build Coastguard Worker 
686*6236dae4SAndroid Build Coastguard Worker   Curl_http_method(data, conn, &method, &httpreq);
687*6236dae4SAndroid Build Coastguard Worker 
688*6236dae4SAndroid Build Coastguard Worker   /* AWS S3 requires a x-amz-content-sha256 header, and supports special
689*6236dae4SAndroid Build Coastguard Worker    * values like UNSIGNED-PAYLOAD */
690*6236dae4SAndroid Build Coastguard Worker   sign_as_s3 = (strcasecompare(provider0, "aws") &&
691*6236dae4SAndroid Build Coastguard Worker                 strcasecompare(service, "s3"));
692*6236dae4SAndroid Build Coastguard Worker 
693*6236dae4SAndroid Build Coastguard Worker   payload_hash = parse_content_sha_hdr(data, provider1, &payload_hash_len);
694*6236dae4SAndroid Build Coastguard Worker 
695*6236dae4SAndroid Build Coastguard Worker   if(!payload_hash) {
696*6236dae4SAndroid Build Coastguard Worker     if(sign_as_s3)
697*6236dae4SAndroid Build Coastguard Worker       result = calc_s3_payload_hash(data, httpreq, provider1, sha_hash,
698*6236dae4SAndroid Build Coastguard Worker                                     sha_hex, content_sha256_hdr);
699*6236dae4SAndroid Build Coastguard Worker     else
700*6236dae4SAndroid Build Coastguard Worker       result = calc_payload_hash(data, sha_hash, sha_hex);
701*6236dae4SAndroid Build Coastguard Worker     if(result)
702*6236dae4SAndroid Build Coastguard Worker       goto fail;
703*6236dae4SAndroid Build Coastguard Worker 
704*6236dae4SAndroid Build Coastguard Worker     payload_hash = sha_hex;
705*6236dae4SAndroid Build Coastguard Worker     /* may be shorter than SHA256_HEX_LENGTH, like S3_UNSIGNED_PAYLOAD */
706*6236dae4SAndroid Build Coastguard Worker     payload_hash_len = strlen(sha_hex);
707*6236dae4SAndroid Build Coastguard Worker   }
708*6236dae4SAndroid Build Coastguard Worker 
709*6236dae4SAndroid Build Coastguard Worker #ifdef DEBUGBUILD
710*6236dae4SAndroid Build Coastguard Worker   {
711*6236dae4SAndroid Build Coastguard Worker     char *force_timestamp = getenv("CURL_FORCETIME");
712*6236dae4SAndroid Build Coastguard Worker     if(force_timestamp)
713*6236dae4SAndroid Build Coastguard Worker       clock = 0;
714*6236dae4SAndroid Build Coastguard Worker     else
715*6236dae4SAndroid Build Coastguard Worker       clock = time(NULL);
716*6236dae4SAndroid Build Coastguard Worker   }
717*6236dae4SAndroid Build Coastguard Worker #else
718*6236dae4SAndroid Build Coastguard Worker   clock = time(NULL);
719*6236dae4SAndroid Build Coastguard Worker #endif
720*6236dae4SAndroid Build Coastguard Worker   result = Curl_gmtime(clock, &tm);
721*6236dae4SAndroid Build Coastguard Worker   if(result) {
722*6236dae4SAndroid Build Coastguard Worker     goto fail;
723*6236dae4SAndroid Build Coastguard Worker   }
724*6236dae4SAndroid Build Coastguard Worker   if(!strftime(timestamp, sizeof(timestamp), "%Y%m%dT%H%M%SZ", &tm)) {
725*6236dae4SAndroid Build Coastguard Worker     result = CURLE_OUT_OF_MEMORY;
726*6236dae4SAndroid Build Coastguard Worker     goto fail;
727*6236dae4SAndroid Build Coastguard Worker   }
728*6236dae4SAndroid Build Coastguard Worker 
729*6236dae4SAndroid Build Coastguard Worker   result = make_headers(data, hostname, timestamp, provider1,
730*6236dae4SAndroid Build Coastguard Worker                         &date_header, content_sha256_hdr,
731*6236dae4SAndroid Build Coastguard Worker                         &canonical_headers, &signed_headers);
732*6236dae4SAndroid Build Coastguard Worker   if(result)
733*6236dae4SAndroid Build Coastguard Worker     goto fail;
734*6236dae4SAndroid Build Coastguard Worker 
735*6236dae4SAndroid Build Coastguard Worker   if(*content_sha256_hdr) {
736*6236dae4SAndroid Build Coastguard Worker     /* make_headers() needed this without the \r\n for canonicalization */
737*6236dae4SAndroid Build Coastguard Worker     size_t hdrlen = strlen(content_sha256_hdr);
738*6236dae4SAndroid Build Coastguard Worker     DEBUGASSERT(hdrlen + 3 < sizeof(content_sha256_hdr));
739*6236dae4SAndroid Build Coastguard Worker     memcpy(content_sha256_hdr + hdrlen, "\r\n", 3);
740*6236dae4SAndroid Build Coastguard Worker   }
741*6236dae4SAndroid Build Coastguard Worker 
742*6236dae4SAndroid Build Coastguard Worker   memcpy(date, timestamp, sizeof(date));
743*6236dae4SAndroid Build Coastguard Worker   date[sizeof(date) - 1] = 0;
744*6236dae4SAndroid Build Coastguard Worker 
745*6236dae4SAndroid Build Coastguard Worker   result = canon_query(data, data->state.up.query, &canonical_query);
746*6236dae4SAndroid Build Coastguard Worker   if(result)
747*6236dae4SAndroid Build Coastguard Worker     goto fail;
748*6236dae4SAndroid Build Coastguard Worker 
749*6236dae4SAndroid Build Coastguard Worker   result = canon_string(data->state.up.path, strlen(data->state.up.path),
750*6236dae4SAndroid Build Coastguard Worker                         &canonical_path, NULL);
751*6236dae4SAndroid Build Coastguard Worker   if(result)
752*6236dae4SAndroid Build Coastguard Worker     goto fail;
753*6236dae4SAndroid Build Coastguard Worker   result = CURLE_OUT_OF_MEMORY;
754*6236dae4SAndroid Build Coastguard Worker 
755*6236dae4SAndroid Build Coastguard Worker   canonical_request =
756*6236dae4SAndroid Build Coastguard Worker     aprintf("%s\n" /* HTTPRequestMethod */
757*6236dae4SAndroid Build Coastguard Worker             "%s\n" /* CanonicalURI */
758*6236dae4SAndroid Build Coastguard Worker             "%s\n" /* CanonicalQueryString */
759*6236dae4SAndroid Build Coastguard Worker             "%s\n" /* CanonicalHeaders */
760*6236dae4SAndroid Build Coastguard Worker             "%s\n" /* SignedHeaders */
761*6236dae4SAndroid Build Coastguard Worker             "%.*s",  /* HashedRequestPayload in hex */
762*6236dae4SAndroid Build Coastguard Worker             method,
763*6236dae4SAndroid Build Coastguard Worker             Curl_dyn_ptr(&canonical_path),
764*6236dae4SAndroid Build Coastguard Worker             Curl_dyn_ptr(&canonical_query) ?
765*6236dae4SAndroid Build Coastguard Worker             Curl_dyn_ptr(&canonical_query) : "",
766*6236dae4SAndroid Build Coastguard Worker             Curl_dyn_ptr(&canonical_headers),
767*6236dae4SAndroid Build Coastguard Worker             Curl_dyn_ptr(&signed_headers),
768*6236dae4SAndroid Build Coastguard Worker             (int)payload_hash_len, payload_hash);
769*6236dae4SAndroid Build Coastguard Worker   if(!canonical_request)
770*6236dae4SAndroid Build Coastguard Worker     goto fail;
771*6236dae4SAndroid Build Coastguard Worker 
772*6236dae4SAndroid Build Coastguard Worker   DEBUGF(infof(data, "Canonical request: %s", canonical_request));
773*6236dae4SAndroid Build Coastguard Worker 
774*6236dae4SAndroid Build Coastguard Worker   /* provider 0 lowercase */
775*6236dae4SAndroid Build Coastguard Worker   Curl_strntolower(provider0, provider0, strlen(provider0));
776*6236dae4SAndroid Build Coastguard Worker   request_type = aprintf("%s4_request", provider0);
777*6236dae4SAndroid Build Coastguard Worker   if(!request_type)
778*6236dae4SAndroid Build Coastguard Worker     goto fail;
779*6236dae4SAndroid Build Coastguard Worker 
780*6236dae4SAndroid Build Coastguard Worker   credential_scope = aprintf("%s/%s/%s/%s",
781*6236dae4SAndroid Build Coastguard Worker                              date, region, service, request_type);
782*6236dae4SAndroid Build Coastguard Worker   if(!credential_scope)
783*6236dae4SAndroid Build Coastguard Worker     goto fail;
784*6236dae4SAndroid Build Coastguard Worker 
785*6236dae4SAndroid Build Coastguard Worker   if(Curl_sha256it(sha_hash, (unsigned char *) canonical_request,
786*6236dae4SAndroid Build Coastguard Worker                    strlen(canonical_request)))
787*6236dae4SAndroid Build Coastguard Worker     goto fail;
788*6236dae4SAndroid Build Coastguard Worker 
789*6236dae4SAndroid Build Coastguard Worker   sha256_to_hex(sha_hex, sha_hash);
790*6236dae4SAndroid Build Coastguard Worker 
791*6236dae4SAndroid Build Coastguard Worker   /* provider 0 uppercase */
792*6236dae4SAndroid Build Coastguard Worker   Curl_strntoupper(provider0, provider0, strlen(provider0));
793*6236dae4SAndroid Build Coastguard Worker 
794*6236dae4SAndroid Build Coastguard Worker   /*
795*6236dae4SAndroid Build Coastguard Worker    * Google allows using RSA key instead of HMAC, so this code might change
796*6236dae4SAndroid Build Coastguard Worker    * in the future. For now we only support HMAC.
797*6236dae4SAndroid Build Coastguard Worker    */
798*6236dae4SAndroid Build Coastguard Worker   str_to_sign = aprintf("%s4-HMAC-SHA256\n" /* Algorithm */
799*6236dae4SAndroid Build Coastguard Worker                         "%s\n" /* RequestDateTime */
800*6236dae4SAndroid Build Coastguard Worker                         "%s\n" /* CredentialScope */
801*6236dae4SAndroid Build Coastguard Worker                         "%s",  /* HashedCanonicalRequest in hex */
802*6236dae4SAndroid Build Coastguard Worker                         provider0,
803*6236dae4SAndroid Build Coastguard Worker                         timestamp,
804*6236dae4SAndroid Build Coastguard Worker                         credential_scope,
805*6236dae4SAndroid Build Coastguard Worker                         sha_hex);
806*6236dae4SAndroid Build Coastguard Worker   if(!str_to_sign) {
807*6236dae4SAndroid Build Coastguard Worker     goto fail;
808*6236dae4SAndroid Build Coastguard Worker   }
809*6236dae4SAndroid Build Coastguard Worker 
810*6236dae4SAndroid Build Coastguard Worker   /* provider 0 uppercase */
811*6236dae4SAndroid Build Coastguard Worker   secret = aprintf("%s4%s", provider0,
812*6236dae4SAndroid Build Coastguard Worker                    data->state.aptr.passwd ?
813*6236dae4SAndroid Build Coastguard Worker                    data->state.aptr.passwd : "");
814*6236dae4SAndroid Build Coastguard Worker   if(!secret)
815*6236dae4SAndroid Build Coastguard Worker     goto fail;
816*6236dae4SAndroid Build Coastguard Worker 
817*6236dae4SAndroid Build Coastguard Worker   HMAC_SHA256(secret, strlen(secret), date, strlen(date), sign0);
818*6236dae4SAndroid Build Coastguard Worker   HMAC_SHA256(sign0, sizeof(sign0), region, strlen(region), sign1);
819*6236dae4SAndroid Build Coastguard Worker   HMAC_SHA256(sign1, sizeof(sign1), service, strlen(service), sign0);
820*6236dae4SAndroid Build Coastguard Worker   HMAC_SHA256(sign0, sizeof(sign0), request_type, strlen(request_type), sign1);
821*6236dae4SAndroid Build Coastguard Worker   HMAC_SHA256(sign1, sizeof(sign1), str_to_sign, strlen(str_to_sign), sign0);
822*6236dae4SAndroid Build Coastguard Worker 
823*6236dae4SAndroid Build Coastguard Worker   sha256_to_hex(sha_hex, sign0);
824*6236dae4SAndroid Build Coastguard Worker 
825*6236dae4SAndroid Build Coastguard Worker   /* provider 0 uppercase */
826*6236dae4SAndroid Build Coastguard Worker   auth_headers = aprintf("Authorization: %s4-HMAC-SHA256 "
827*6236dae4SAndroid Build Coastguard Worker                          "Credential=%s/%s, "
828*6236dae4SAndroid Build Coastguard Worker                          "SignedHeaders=%s, "
829*6236dae4SAndroid Build Coastguard Worker                          "Signature=%s\r\n"
830*6236dae4SAndroid Build Coastguard Worker                          /*
831*6236dae4SAndroid Build Coastguard Worker                           * date_header is added here, only if it was not
832*6236dae4SAndroid Build Coastguard Worker                           * user-specified (using CURLOPT_HTTPHEADER).
833*6236dae4SAndroid Build Coastguard Worker                           * date_header includes \r\n
834*6236dae4SAndroid Build Coastguard Worker                           */
835*6236dae4SAndroid Build Coastguard Worker                          "%s"
836*6236dae4SAndroid Build Coastguard Worker                          "%s", /* optional sha256 header includes \r\n */
837*6236dae4SAndroid Build Coastguard Worker                          provider0,
838*6236dae4SAndroid Build Coastguard Worker                          user,
839*6236dae4SAndroid Build Coastguard Worker                          credential_scope,
840*6236dae4SAndroid Build Coastguard Worker                          Curl_dyn_ptr(&signed_headers),
841*6236dae4SAndroid Build Coastguard Worker                          sha_hex,
842*6236dae4SAndroid Build Coastguard Worker                          date_header ? date_header : "",
843*6236dae4SAndroid Build Coastguard Worker                          content_sha256_hdr);
844*6236dae4SAndroid Build Coastguard Worker   if(!auth_headers) {
845*6236dae4SAndroid Build Coastguard Worker     goto fail;
846*6236dae4SAndroid Build Coastguard Worker   }
847*6236dae4SAndroid Build Coastguard Worker 
848*6236dae4SAndroid Build Coastguard Worker   Curl_safefree(data->state.aptr.userpwd);
849*6236dae4SAndroid Build Coastguard Worker   data->state.aptr.userpwd = auth_headers;
850*6236dae4SAndroid Build Coastguard Worker   data->state.authhost.done = TRUE;
851*6236dae4SAndroid Build Coastguard Worker   result = CURLE_OK;
852*6236dae4SAndroid Build Coastguard Worker 
853*6236dae4SAndroid Build Coastguard Worker fail:
854*6236dae4SAndroid Build Coastguard Worker   Curl_dyn_free(&canonical_query);
855*6236dae4SAndroid Build Coastguard Worker   Curl_dyn_free(&canonical_path);
856*6236dae4SAndroid Build Coastguard Worker   Curl_dyn_free(&canonical_headers);
857*6236dae4SAndroid Build Coastguard Worker   Curl_dyn_free(&signed_headers);
858*6236dae4SAndroid Build Coastguard Worker   free(canonical_request);
859*6236dae4SAndroid Build Coastguard Worker   free(request_type);
860*6236dae4SAndroid Build Coastguard Worker   free(credential_scope);
861*6236dae4SAndroid Build Coastguard Worker   free(str_to_sign);
862*6236dae4SAndroid Build Coastguard Worker   free(secret);
863*6236dae4SAndroid Build Coastguard Worker   free(date_header);
864*6236dae4SAndroid Build Coastguard Worker   return result;
865*6236dae4SAndroid Build Coastguard Worker }
866*6236dae4SAndroid Build Coastguard Worker 
867*6236dae4SAndroid Build Coastguard Worker #endif /* !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_AWS) */
868