113498266Sopenharmony_ci/*************************************************************************** 213498266Sopenharmony_ci * _ _ ____ _ 313498266Sopenharmony_ci * Project ___| | | | _ \| | 413498266Sopenharmony_ci * / __| | | | |_) | | 513498266Sopenharmony_ci * | (__| |_| | _ <| |___ 613498266Sopenharmony_ci * \___|\___/|_| \_\_____| 713498266Sopenharmony_ci * 813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 913498266Sopenharmony_ci * 1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which 1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms 1213498266Sopenharmony_ci * are also available at https://curl.haxx.se/docs/copyright.html. 1313498266Sopenharmony_ci * 1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell 1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is 1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file. 1713498266Sopenharmony_ci * 1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 1913498266Sopenharmony_ci * KIND, either express or implied. 2013498266Sopenharmony_ci * 2113498266Sopenharmony_ci * SPDX-License-Identifier: curl 2213498266Sopenharmony_ci * 2313498266Sopenharmony_ci ***************************************************************************/ 2413498266Sopenharmony_ci 2513498266Sopenharmony_ci#include "curl_setup.h" 2613498266Sopenharmony_ci 2713498266Sopenharmony_ci#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_AWS) 2813498266Sopenharmony_ci 2913498266Sopenharmony_ci#include "urldata.h" 3013498266Sopenharmony_ci#include "strcase.h" 3113498266Sopenharmony_ci#include "strdup.h" 3213498266Sopenharmony_ci#include "http_aws_sigv4.h" 3313498266Sopenharmony_ci#include "curl_sha256.h" 3413498266Sopenharmony_ci#include "transfer.h" 3513498266Sopenharmony_ci#include "parsedate.h" 3613498266Sopenharmony_ci#include "sendf.h" 3713498266Sopenharmony_ci#include "escape.h" 3813498266Sopenharmony_ci 3913498266Sopenharmony_ci#include <time.h> 4013498266Sopenharmony_ci 4113498266Sopenharmony_ci/* The last 3 #include files should be in this order */ 4213498266Sopenharmony_ci#include "curl_printf.h" 4313498266Sopenharmony_ci#include "curl_memory.h" 4413498266Sopenharmony_ci#include "memdebug.h" 4513498266Sopenharmony_ci 4613498266Sopenharmony_ci#include "slist.h" 4713498266Sopenharmony_ci 4813498266Sopenharmony_ci#define HMAC_SHA256(k, kl, d, dl, o) \ 4913498266Sopenharmony_ci do { \ 5013498266Sopenharmony_ci result = Curl_hmacit(Curl_HMAC_SHA256, \ 5113498266Sopenharmony_ci (unsigned char *)k, \ 5213498266Sopenharmony_ci kl, \ 5313498266Sopenharmony_ci (unsigned char *)d, \ 5413498266Sopenharmony_ci dl, o); \ 5513498266Sopenharmony_ci if(result) { \ 5613498266Sopenharmony_ci goto fail; \ 5713498266Sopenharmony_ci } \ 5813498266Sopenharmony_ci } while(0) 5913498266Sopenharmony_ci 6013498266Sopenharmony_ci#define TIMESTAMP_SIZE 17 6113498266Sopenharmony_ci 6213498266Sopenharmony_ci/* hex-encoded with trailing null */ 6313498266Sopenharmony_ci#define SHA256_HEX_LENGTH (2 * SHA256_DIGEST_LENGTH + 1) 6413498266Sopenharmony_ci 6513498266Sopenharmony_cistatic void sha256_to_hex(char *dst, unsigned char *sha) 6613498266Sopenharmony_ci{ 6713498266Sopenharmony_ci Curl_hexencode(sha, SHA256_DIGEST_LENGTH, 6813498266Sopenharmony_ci (unsigned char *)dst, SHA256_HEX_LENGTH); 6913498266Sopenharmony_ci} 7013498266Sopenharmony_ci 7113498266Sopenharmony_cistatic char *find_date_hdr(struct Curl_easy *data, const char *sig_hdr) 7213498266Sopenharmony_ci{ 7313498266Sopenharmony_ci char *tmp = Curl_checkheaders(data, sig_hdr, strlen(sig_hdr)); 7413498266Sopenharmony_ci 7513498266Sopenharmony_ci if(tmp) 7613498266Sopenharmony_ci return tmp; 7713498266Sopenharmony_ci return Curl_checkheaders(data, STRCONST("Date")); 7813498266Sopenharmony_ci} 7913498266Sopenharmony_ci 8013498266Sopenharmony_ci/* remove whitespace, and lowercase all headers */ 8113498266Sopenharmony_cistatic void trim_headers(struct curl_slist *head) 8213498266Sopenharmony_ci{ 8313498266Sopenharmony_ci struct curl_slist *l; 8413498266Sopenharmony_ci for(l = head; l; l = l->next) { 8513498266Sopenharmony_ci char *value; /* to read from */ 8613498266Sopenharmony_ci char *store; 8713498266Sopenharmony_ci size_t colon = strcspn(l->data, ":"); 8813498266Sopenharmony_ci Curl_strntolower(l->data, l->data, colon); 8913498266Sopenharmony_ci 9013498266Sopenharmony_ci value = &l->data[colon]; 9113498266Sopenharmony_ci if(!*value) 9213498266Sopenharmony_ci continue; 9313498266Sopenharmony_ci ++value; 9413498266Sopenharmony_ci store = value; 9513498266Sopenharmony_ci 9613498266Sopenharmony_ci /* skip leading whitespace */ 9713498266Sopenharmony_ci while(*value && ISBLANK(*value)) 9813498266Sopenharmony_ci value++; 9913498266Sopenharmony_ci 10013498266Sopenharmony_ci while(*value) { 10113498266Sopenharmony_ci int space = 0; 10213498266Sopenharmony_ci while(*value && ISBLANK(*value)) { 10313498266Sopenharmony_ci value++; 10413498266Sopenharmony_ci space++; 10513498266Sopenharmony_ci } 10613498266Sopenharmony_ci if(space) { 10713498266Sopenharmony_ci /* replace any number of consecutive whitespace with a single space, 10813498266Sopenharmony_ci unless at the end of the string, then nothing */ 10913498266Sopenharmony_ci if(*value) 11013498266Sopenharmony_ci *store++ = ' '; 11113498266Sopenharmony_ci } 11213498266Sopenharmony_ci else 11313498266Sopenharmony_ci *store++ = *value++; 11413498266Sopenharmony_ci } 11513498266Sopenharmony_ci *store = 0; /* null terminate */ 11613498266Sopenharmony_ci } 11713498266Sopenharmony_ci} 11813498266Sopenharmony_ci 11913498266Sopenharmony_ci/* maximum length for the aws sivg4 parts */ 12013498266Sopenharmony_ci#define MAX_SIGV4_LEN 64 12113498266Sopenharmony_ci#define MAX_SIGV4_LEN_TXT "64" 12213498266Sopenharmony_ci 12313498266Sopenharmony_ci#define DATE_HDR_KEY_LEN (MAX_SIGV4_LEN + sizeof("X--Date")) 12413498266Sopenharmony_ci 12513498266Sopenharmony_ci#define MAX_HOST_LEN 255 12613498266Sopenharmony_ci/* FQDN + host: */ 12713498266Sopenharmony_ci#define FULL_HOST_LEN (MAX_HOST_LEN + sizeof("host:")) 12813498266Sopenharmony_ci 12913498266Sopenharmony_ci/* string been x-PROVIDER-date:TIMESTAMP, I need +1 for ':' */ 13013498266Sopenharmony_ci#define DATE_FULL_HDR_LEN (DATE_HDR_KEY_LEN + TIMESTAMP_SIZE + 1) 13113498266Sopenharmony_ci 13213498266Sopenharmony_ci/* timestamp should point to a buffer of at last TIMESTAMP_SIZE bytes */ 13313498266Sopenharmony_cistatic CURLcode make_headers(struct Curl_easy *data, 13413498266Sopenharmony_ci const char *hostname, 13513498266Sopenharmony_ci char *timestamp, 13613498266Sopenharmony_ci char *provider1, 13713498266Sopenharmony_ci char **date_header, 13813498266Sopenharmony_ci char *content_sha256_header, 13913498266Sopenharmony_ci struct dynbuf *canonical_headers, 14013498266Sopenharmony_ci struct dynbuf *signed_headers) 14113498266Sopenharmony_ci{ 14213498266Sopenharmony_ci char date_hdr_key[DATE_HDR_KEY_LEN]; 14313498266Sopenharmony_ci char date_full_hdr[DATE_FULL_HDR_LEN]; 14413498266Sopenharmony_ci struct curl_slist *head = NULL; 14513498266Sopenharmony_ci struct curl_slist *tmp_head = NULL; 14613498266Sopenharmony_ci CURLcode ret = CURLE_OUT_OF_MEMORY; 14713498266Sopenharmony_ci struct curl_slist *l; 14813498266Sopenharmony_ci int again = 1; 14913498266Sopenharmony_ci 15013498266Sopenharmony_ci /* provider1 mid */ 15113498266Sopenharmony_ci Curl_strntolower(provider1, provider1, strlen(provider1)); 15213498266Sopenharmony_ci provider1[0] = Curl_raw_toupper(provider1[0]); 15313498266Sopenharmony_ci 15413498266Sopenharmony_ci msnprintf(date_hdr_key, DATE_HDR_KEY_LEN, "X-%s-Date", provider1); 15513498266Sopenharmony_ci 15613498266Sopenharmony_ci /* provider1 lowercase */ 15713498266Sopenharmony_ci Curl_strntolower(provider1, provider1, 1); /* first byte only */ 15813498266Sopenharmony_ci msnprintf(date_full_hdr, DATE_FULL_HDR_LEN, 15913498266Sopenharmony_ci "x-%s-date:%s", provider1, timestamp); 16013498266Sopenharmony_ci 16113498266Sopenharmony_ci if(Curl_checkheaders(data, STRCONST("Host"))) { 16213498266Sopenharmony_ci head = NULL; 16313498266Sopenharmony_ci } 16413498266Sopenharmony_ci else { 16513498266Sopenharmony_ci char full_host[FULL_HOST_LEN + 1]; 16613498266Sopenharmony_ci 16713498266Sopenharmony_ci if(data->state.aptr.host) { 16813498266Sopenharmony_ci size_t pos; 16913498266Sopenharmony_ci 17013498266Sopenharmony_ci if(strlen(data->state.aptr.host) > FULL_HOST_LEN) { 17113498266Sopenharmony_ci ret = CURLE_URL_MALFORMAT; 17213498266Sopenharmony_ci goto fail; 17313498266Sopenharmony_ci } 17413498266Sopenharmony_ci strcpy(full_host, data->state.aptr.host); 17513498266Sopenharmony_ci /* remove /r/n as the separator for canonical request must be '\n' */ 17613498266Sopenharmony_ci pos = strcspn(full_host, "\n\r"); 17713498266Sopenharmony_ci full_host[pos] = 0; 17813498266Sopenharmony_ci } 17913498266Sopenharmony_ci else { 18013498266Sopenharmony_ci if(strlen(hostname) > MAX_HOST_LEN) { 18113498266Sopenharmony_ci ret = CURLE_URL_MALFORMAT; 18213498266Sopenharmony_ci goto fail; 18313498266Sopenharmony_ci } 18413498266Sopenharmony_ci msnprintf(full_host, FULL_HOST_LEN, "host:%s", hostname); 18513498266Sopenharmony_ci } 18613498266Sopenharmony_ci 18713498266Sopenharmony_ci head = curl_slist_append(NULL, full_host); 18813498266Sopenharmony_ci if(!head) 18913498266Sopenharmony_ci goto fail; 19013498266Sopenharmony_ci } 19113498266Sopenharmony_ci 19213498266Sopenharmony_ci 19313498266Sopenharmony_ci if(*content_sha256_header) { 19413498266Sopenharmony_ci tmp_head = curl_slist_append(head, content_sha256_header); 19513498266Sopenharmony_ci if(!tmp_head) 19613498266Sopenharmony_ci goto fail; 19713498266Sopenharmony_ci head = tmp_head; 19813498266Sopenharmony_ci } 19913498266Sopenharmony_ci 20013498266Sopenharmony_ci /* copy user headers to our header list. the logic is based on how http.c 20113498266Sopenharmony_ci handles user headers. 20213498266Sopenharmony_ci 20313498266Sopenharmony_ci user headers in format 'name:' with no value are used to signal that an 20413498266Sopenharmony_ci internal header of that name should be removed. those user headers are not 20513498266Sopenharmony_ci added to this list. 20613498266Sopenharmony_ci 20713498266Sopenharmony_ci user headers in format 'name;' with no value are used to signal that a 20813498266Sopenharmony_ci header of that name with no value should be sent. those user headers are 20913498266Sopenharmony_ci added to this list but in the format that they will be sent, ie the 21013498266Sopenharmony_ci semi-colon is changed to a colon for format 'name:'. 21113498266Sopenharmony_ci 21213498266Sopenharmony_ci user headers with a value of whitespace only, or without a colon or 21313498266Sopenharmony_ci semi-colon, are not added to this list. 21413498266Sopenharmony_ci */ 21513498266Sopenharmony_ci for(l = data->set.headers; l; l = l->next) { 21613498266Sopenharmony_ci char *dupdata, *ptr; 21713498266Sopenharmony_ci char *sep = strchr(l->data, ':'); 21813498266Sopenharmony_ci if(!sep) 21913498266Sopenharmony_ci sep = strchr(l->data, ';'); 22013498266Sopenharmony_ci if(!sep || (*sep == ':' && !*(sep + 1))) 22113498266Sopenharmony_ci continue; 22213498266Sopenharmony_ci for(ptr = sep + 1; ISSPACE(*ptr); ++ptr) 22313498266Sopenharmony_ci ; 22413498266Sopenharmony_ci if(!*ptr && ptr != sep + 1) /* a value of whitespace only */ 22513498266Sopenharmony_ci continue; 22613498266Sopenharmony_ci dupdata = strdup(l->data); 22713498266Sopenharmony_ci if(!dupdata) 22813498266Sopenharmony_ci goto fail; 22913498266Sopenharmony_ci dupdata[sep - l->data] = ':'; 23013498266Sopenharmony_ci tmp_head = Curl_slist_append_nodup(head, dupdata); 23113498266Sopenharmony_ci if(!tmp_head) { 23213498266Sopenharmony_ci free(dupdata); 23313498266Sopenharmony_ci goto fail; 23413498266Sopenharmony_ci } 23513498266Sopenharmony_ci head = tmp_head; 23613498266Sopenharmony_ci } 23713498266Sopenharmony_ci 23813498266Sopenharmony_ci trim_headers(head); 23913498266Sopenharmony_ci 24013498266Sopenharmony_ci *date_header = find_date_hdr(data, date_hdr_key); 24113498266Sopenharmony_ci if(!*date_header) { 24213498266Sopenharmony_ci tmp_head = curl_slist_append(head, date_full_hdr); 24313498266Sopenharmony_ci if(!tmp_head) 24413498266Sopenharmony_ci goto fail; 24513498266Sopenharmony_ci head = tmp_head; 24613498266Sopenharmony_ci *date_header = curl_maprintf("%s: %s\r\n", date_hdr_key, timestamp); 24713498266Sopenharmony_ci } 24813498266Sopenharmony_ci else { 24913498266Sopenharmony_ci char *value; 25013498266Sopenharmony_ci char *endp; 25113498266Sopenharmony_ci value = strchr(*date_header, ':'); 25213498266Sopenharmony_ci if(!value) { 25313498266Sopenharmony_ci *date_header = NULL; 25413498266Sopenharmony_ci goto fail; 25513498266Sopenharmony_ci } 25613498266Sopenharmony_ci ++value; 25713498266Sopenharmony_ci while(ISBLANK(*value)) 25813498266Sopenharmony_ci ++value; 25913498266Sopenharmony_ci endp = value; 26013498266Sopenharmony_ci while(*endp && ISALNUM(*endp)) 26113498266Sopenharmony_ci ++endp; 26213498266Sopenharmony_ci /* 16 bytes => "19700101T000000Z" */ 26313498266Sopenharmony_ci if((endp - value) == TIMESTAMP_SIZE - 1) { 26413498266Sopenharmony_ci memcpy(timestamp, value, TIMESTAMP_SIZE - 1); 26513498266Sopenharmony_ci timestamp[TIMESTAMP_SIZE - 1] = 0; 26613498266Sopenharmony_ci } 26713498266Sopenharmony_ci else 26813498266Sopenharmony_ci /* bad timestamp length */ 26913498266Sopenharmony_ci timestamp[0] = 0; 27013498266Sopenharmony_ci *date_header = NULL; 27113498266Sopenharmony_ci } 27213498266Sopenharmony_ci 27313498266Sopenharmony_ci /* alpha-sort in a case sensitive manner */ 27413498266Sopenharmony_ci do { 27513498266Sopenharmony_ci again = 0; 27613498266Sopenharmony_ci for(l = head; l; l = l->next) { 27713498266Sopenharmony_ci struct curl_slist *next = l->next; 27813498266Sopenharmony_ci 27913498266Sopenharmony_ci if(next && strcmp(l->data, next->data) > 0) { 28013498266Sopenharmony_ci char *tmp = l->data; 28113498266Sopenharmony_ci 28213498266Sopenharmony_ci l->data = next->data; 28313498266Sopenharmony_ci next->data = tmp; 28413498266Sopenharmony_ci again = 1; 28513498266Sopenharmony_ci } 28613498266Sopenharmony_ci } 28713498266Sopenharmony_ci } while(again); 28813498266Sopenharmony_ci 28913498266Sopenharmony_ci for(l = head; l; l = l->next) { 29013498266Sopenharmony_ci char *tmp; 29113498266Sopenharmony_ci 29213498266Sopenharmony_ci if(Curl_dyn_add(canonical_headers, l->data)) 29313498266Sopenharmony_ci goto fail; 29413498266Sopenharmony_ci if(Curl_dyn_add(canonical_headers, "\n")) 29513498266Sopenharmony_ci goto fail; 29613498266Sopenharmony_ci 29713498266Sopenharmony_ci tmp = strchr(l->data, ':'); 29813498266Sopenharmony_ci if(tmp) 29913498266Sopenharmony_ci *tmp = 0; 30013498266Sopenharmony_ci 30113498266Sopenharmony_ci if(l != head) { 30213498266Sopenharmony_ci if(Curl_dyn_add(signed_headers, ";")) 30313498266Sopenharmony_ci goto fail; 30413498266Sopenharmony_ci } 30513498266Sopenharmony_ci if(Curl_dyn_add(signed_headers, l->data)) 30613498266Sopenharmony_ci goto fail; 30713498266Sopenharmony_ci } 30813498266Sopenharmony_ci 30913498266Sopenharmony_ci ret = CURLE_OK; 31013498266Sopenharmony_cifail: 31113498266Sopenharmony_ci curl_slist_free_all(head); 31213498266Sopenharmony_ci 31313498266Sopenharmony_ci return ret; 31413498266Sopenharmony_ci} 31513498266Sopenharmony_ci 31613498266Sopenharmony_ci#define CONTENT_SHA256_KEY_LEN (MAX_SIGV4_LEN + sizeof("X--Content-Sha256")) 31713498266Sopenharmony_ci/* add 2 for ": " between header name and value */ 31813498266Sopenharmony_ci#define CONTENT_SHA256_HDR_LEN (CONTENT_SHA256_KEY_LEN + 2 + \ 31913498266Sopenharmony_ci SHA256_HEX_LENGTH) 32013498266Sopenharmony_ci 32113498266Sopenharmony_ci/* try to parse a payload hash from the content-sha256 header */ 32213498266Sopenharmony_cistatic char *parse_content_sha_hdr(struct Curl_easy *data, 32313498266Sopenharmony_ci const char *provider1, 32413498266Sopenharmony_ci size_t *value_len) 32513498266Sopenharmony_ci{ 32613498266Sopenharmony_ci char key[CONTENT_SHA256_KEY_LEN]; 32713498266Sopenharmony_ci size_t key_len; 32813498266Sopenharmony_ci char *value; 32913498266Sopenharmony_ci size_t len; 33013498266Sopenharmony_ci 33113498266Sopenharmony_ci key_len = msnprintf(key, sizeof(key), "x-%s-content-sha256", provider1); 33213498266Sopenharmony_ci 33313498266Sopenharmony_ci value = Curl_checkheaders(data, key, key_len); 33413498266Sopenharmony_ci if(!value) 33513498266Sopenharmony_ci return NULL; 33613498266Sopenharmony_ci 33713498266Sopenharmony_ci value = strchr(value, ':'); 33813498266Sopenharmony_ci if(!value) 33913498266Sopenharmony_ci return NULL; 34013498266Sopenharmony_ci ++value; 34113498266Sopenharmony_ci 34213498266Sopenharmony_ci while(*value && ISBLANK(*value)) 34313498266Sopenharmony_ci ++value; 34413498266Sopenharmony_ci 34513498266Sopenharmony_ci len = strlen(value); 34613498266Sopenharmony_ci while(len > 0 && ISBLANK(value[len-1])) 34713498266Sopenharmony_ci --len; 34813498266Sopenharmony_ci 34913498266Sopenharmony_ci *value_len = len; 35013498266Sopenharmony_ci return value; 35113498266Sopenharmony_ci} 35213498266Sopenharmony_ci 35313498266Sopenharmony_cistatic CURLcode calc_payload_hash(struct Curl_easy *data, 35413498266Sopenharmony_ci unsigned char *sha_hash, char *sha_hex) 35513498266Sopenharmony_ci{ 35613498266Sopenharmony_ci const char *post_data = data->set.postfields; 35713498266Sopenharmony_ci size_t post_data_len = 0; 35813498266Sopenharmony_ci CURLcode result; 35913498266Sopenharmony_ci 36013498266Sopenharmony_ci if(post_data) { 36113498266Sopenharmony_ci if(data->set.postfieldsize < 0) 36213498266Sopenharmony_ci post_data_len = strlen(post_data); 36313498266Sopenharmony_ci else 36413498266Sopenharmony_ci post_data_len = (size_t)data->set.postfieldsize; 36513498266Sopenharmony_ci } 36613498266Sopenharmony_ci result = Curl_sha256it(sha_hash, (const unsigned char *) post_data, 36713498266Sopenharmony_ci post_data_len); 36813498266Sopenharmony_ci if(!result) 36913498266Sopenharmony_ci sha256_to_hex(sha_hex, sha_hash); 37013498266Sopenharmony_ci return result; 37113498266Sopenharmony_ci} 37213498266Sopenharmony_ci 37313498266Sopenharmony_ci#define S3_UNSIGNED_PAYLOAD "UNSIGNED-PAYLOAD" 37413498266Sopenharmony_ci 37513498266Sopenharmony_cistatic CURLcode calc_s3_payload_hash(struct Curl_easy *data, 37613498266Sopenharmony_ci Curl_HttpReq httpreq, char *provider1, 37713498266Sopenharmony_ci unsigned char *sha_hash, 37813498266Sopenharmony_ci char *sha_hex, char *header) 37913498266Sopenharmony_ci{ 38013498266Sopenharmony_ci bool empty_method = (httpreq == HTTPREQ_GET || httpreq == HTTPREQ_HEAD); 38113498266Sopenharmony_ci /* The request method or filesize indicate no request payload */ 38213498266Sopenharmony_ci bool empty_payload = (empty_method || data->set.filesize == 0); 38313498266Sopenharmony_ci /* The POST payload is in memory */ 38413498266Sopenharmony_ci bool post_payload = (httpreq == HTTPREQ_POST && data->set.postfields); 38513498266Sopenharmony_ci CURLcode ret = CURLE_OUT_OF_MEMORY; 38613498266Sopenharmony_ci 38713498266Sopenharmony_ci if(empty_payload || post_payload) { 38813498266Sopenharmony_ci /* Calculate a real hash when we know the request payload */ 38913498266Sopenharmony_ci ret = calc_payload_hash(data, sha_hash, sha_hex); 39013498266Sopenharmony_ci if(ret) 39113498266Sopenharmony_ci goto fail; 39213498266Sopenharmony_ci } 39313498266Sopenharmony_ci else { 39413498266Sopenharmony_ci /* Fall back to s3's UNSIGNED-PAYLOAD */ 39513498266Sopenharmony_ci size_t len = sizeof(S3_UNSIGNED_PAYLOAD) - 1; 39613498266Sopenharmony_ci DEBUGASSERT(len < SHA256_HEX_LENGTH); /* 16 < 65 */ 39713498266Sopenharmony_ci memcpy(sha_hex, S3_UNSIGNED_PAYLOAD, len); 39813498266Sopenharmony_ci sha_hex[len] = 0; 39913498266Sopenharmony_ci } 40013498266Sopenharmony_ci 40113498266Sopenharmony_ci /* format the required content-sha256 header */ 40213498266Sopenharmony_ci msnprintf(header, CONTENT_SHA256_HDR_LEN, 40313498266Sopenharmony_ci "x-%s-content-sha256: %s", provider1, sha_hex); 40413498266Sopenharmony_ci 40513498266Sopenharmony_ci ret = CURLE_OK; 40613498266Sopenharmony_cifail: 40713498266Sopenharmony_ci return ret; 40813498266Sopenharmony_ci} 40913498266Sopenharmony_ci 41013498266Sopenharmony_cistruct pair { 41113498266Sopenharmony_ci const char *p; 41213498266Sopenharmony_ci size_t len; 41313498266Sopenharmony_ci}; 41413498266Sopenharmony_ci 41513498266Sopenharmony_cistatic int compare_func(const void *a, const void *b) 41613498266Sopenharmony_ci{ 41713498266Sopenharmony_ci const struct pair *aa = a; 41813498266Sopenharmony_ci const struct pair *bb = b; 41913498266Sopenharmony_ci /* If one element is empty, the other is always sorted higher */ 42013498266Sopenharmony_ci if(aa->len == 0) 42113498266Sopenharmony_ci return -1; 42213498266Sopenharmony_ci if(bb->len == 0) 42313498266Sopenharmony_ci return 1; 42413498266Sopenharmony_ci return strncmp(aa->p, bb->p, aa->len < bb->len ? aa->len : bb->len); 42513498266Sopenharmony_ci} 42613498266Sopenharmony_ci 42713498266Sopenharmony_ci#define MAX_QUERYPAIRS 64 42813498266Sopenharmony_ci 42913498266Sopenharmony_cistatic CURLcode canon_query(struct Curl_easy *data, 43013498266Sopenharmony_ci const char *query, struct dynbuf *dq) 43113498266Sopenharmony_ci{ 43213498266Sopenharmony_ci CURLcode result = CURLE_OK; 43313498266Sopenharmony_ci int entry = 0; 43413498266Sopenharmony_ci int i; 43513498266Sopenharmony_ci const char *p = query; 43613498266Sopenharmony_ci struct pair array[MAX_QUERYPAIRS]; 43713498266Sopenharmony_ci struct pair *ap = &array[0]; 43813498266Sopenharmony_ci if(!query) 43913498266Sopenharmony_ci return result; 44013498266Sopenharmony_ci 44113498266Sopenharmony_ci /* sort the name=value pairs first */ 44213498266Sopenharmony_ci do { 44313498266Sopenharmony_ci char *amp; 44413498266Sopenharmony_ci entry++; 44513498266Sopenharmony_ci ap->p = p; 44613498266Sopenharmony_ci amp = strchr(p, '&'); 44713498266Sopenharmony_ci if(amp) 44813498266Sopenharmony_ci ap->len = amp - p; /* excluding the ampersand */ 44913498266Sopenharmony_ci else { 45013498266Sopenharmony_ci ap->len = strlen(p); 45113498266Sopenharmony_ci break; 45213498266Sopenharmony_ci } 45313498266Sopenharmony_ci ap++; 45413498266Sopenharmony_ci p = amp + 1; 45513498266Sopenharmony_ci } while(entry < MAX_QUERYPAIRS); 45613498266Sopenharmony_ci if(entry == MAX_QUERYPAIRS) { 45713498266Sopenharmony_ci /* too many query pairs for us */ 45813498266Sopenharmony_ci failf(data, "aws-sigv4: too many query pairs in URL"); 45913498266Sopenharmony_ci return CURLE_URL_MALFORMAT; 46013498266Sopenharmony_ci } 46113498266Sopenharmony_ci 46213498266Sopenharmony_ci qsort(&array[0], entry, sizeof(struct pair), compare_func); 46313498266Sopenharmony_ci 46413498266Sopenharmony_ci ap = &array[0]; 46513498266Sopenharmony_ci for(i = 0; !result && (i < entry); i++, ap++) { 46613498266Sopenharmony_ci size_t len; 46713498266Sopenharmony_ci const char *q = ap->p; 46813498266Sopenharmony_ci bool found_equals = false; 46913498266Sopenharmony_ci if(!ap->len) 47013498266Sopenharmony_ci continue; 47113498266Sopenharmony_ci for(len = ap->len; len && !result; q++, len--) { 47213498266Sopenharmony_ci if(ISALNUM(*q)) 47313498266Sopenharmony_ci result = Curl_dyn_addn(dq, q, 1); 47413498266Sopenharmony_ci else { 47513498266Sopenharmony_ci switch(*q) { 47613498266Sopenharmony_ci case '-': 47713498266Sopenharmony_ci case '.': 47813498266Sopenharmony_ci case '_': 47913498266Sopenharmony_ci case '~': 48013498266Sopenharmony_ci /* allowed as-is */ 48113498266Sopenharmony_ci result = Curl_dyn_addn(dq, q, 1); 48213498266Sopenharmony_ci break; 48313498266Sopenharmony_ci case '=': 48413498266Sopenharmony_ci /* allowed as-is */ 48513498266Sopenharmony_ci result = Curl_dyn_addn(dq, q, 1); 48613498266Sopenharmony_ci found_equals = true; 48713498266Sopenharmony_ci break; 48813498266Sopenharmony_ci case '%': 48913498266Sopenharmony_ci /* uppercase the following if hexadecimal */ 49013498266Sopenharmony_ci if(ISXDIGIT(q[1]) && ISXDIGIT(q[2])) { 49113498266Sopenharmony_ci char tmp[3]="%"; 49213498266Sopenharmony_ci tmp[1] = Curl_raw_toupper(q[1]); 49313498266Sopenharmony_ci tmp[2] = Curl_raw_toupper(q[2]); 49413498266Sopenharmony_ci result = Curl_dyn_addn(dq, tmp, 3); 49513498266Sopenharmony_ci q += 2; 49613498266Sopenharmony_ci len -= 2; 49713498266Sopenharmony_ci } 49813498266Sopenharmony_ci else 49913498266Sopenharmony_ci /* '%' without a following two-digit hex, encode it */ 50013498266Sopenharmony_ci result = Curl_dyn_addn(dq, "%25", 3); 50113498266Sopenharmony_ci break; 50213498266Sopenharmony_ci default: { 50313498266Sopenharmony_ci /* URL encode */ 50413498266Sopenharmony_ci const char hex[] = "0123456789ABCDEF"; 50513498266Sopenharmony_ci char out[3]={'%'}; 50613498266Sopenharmony_ci out[1] = hex[((unsigned char)*q)>>4]; 50713498266Sopenharmony_ci out[2] = hex[*q & 0xf]; 50813498266Sopenharmony_ci result = Curl_dyn_addn(dq, out, 3); 50913498266Sopenharmony_ci break; 51013498266Sopenharmony_ci } 51113498266Sopenharmony_ci } 51213498266Sopenharmony_ci } 51313498266Sopenharmony_ci } 51413498266Sopenharmony_ci if(!result && !found_equals) { 51513498266Sopenharmony_ci /* queries without value still need an equals */ 51613498266Sopenharmony_ci result = Curl_dyn_addn(dq, "=", 1); 51713498266Sopenharmony_ci } 51813498266Sopenharmony_ci if(!result && i < entry - 1) { 51913498266Sopenharmony_ci /* insert ampersands between query pairs */ 52013498266Sopenharmony_ci result = Curl_dyn_addn(dq, "&", 1); 52113498266Sopenharmony_ci } 52213498266Sopenharmony_ci } 52313498266Sopenharmony_ci return result; 52413498266Sopenharmony_ci} 52513498266Sopenharmony_ci 52613498266Sopenharmony_ci 52713498266Sopenharmony_ciCURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy) 52813498266Sopenharmony_ci{ 52913498266Sopenharmony_ci CURLcode result = CURLE_OUT_OF_MEMORY; 53013498266Sopenharmony_ci struct connectdata *conn = data->conn; 53113498266Sopenharmony_ci size_t len; 53213498266Sopenharmony_ci const char *arg; 53313498266Sopenharmony_ci char provider0[MAX_SIGV4_LEN + 1]=""; 53413498266Sopenharmony_ci char provider1[MAX_SIGV4_LEN + 1]=""; 53513498266Sopenharmony_ci char region[MAX_SIGV4_LEN + 1]=""; 53613498266Sopenharmony_ci char service[MAX_SIGV4_LEN + 1]=""; 53713498266Sopenharmony_ci bool sign_as_s3 = false; 53813498266Sopenharmony_ci const char *hostname = conn->host.name; 53913498266Sopenharmony_ci time_t clock; 54013498266Sopenharmony_ci struct tm tm; 54113498266Sopenharmony_ci char timestamp[TIMESTAMP_SIZE]; 54213498266Sopenharmony_ci char date[9]; 54313498266Sopenharmony_ci struct dynbuf canonical_headers; 54413498266Sopenharmony_ci struct dynbuf signed_headers; 54513498266Sopenharmony_ci struct dynbuf canonical_query; 54613498266Sopenharmony_ci char *date_header = NULL; 54713498266Sopenharmony_ci Curl_HttpReq httpreq; 54813498266Sopenharmony_ci const char *method = NULL; 54913498266Sopenharmony_ci char *payload_hash = NULL; 55013498266Sopenharmony_ci size_t payload_hash_len = 0; 55113498266Sopenharmony_ci unsigned char sha_hash[SHA256_DIGEST_LENGTH]; 55213498266Sopenharmony_ci char sha_hex[SHA256_HEX_LENGTH]; 55313498266Sopenharmony_ci char content_sha256_hdr[CONTENT_SHA256_HDR_LEN + 2] = ""; /* add \r\n */ 55413498266Sopenharmony_ci char *canonical_request = NULL; 55513498266Sopenharmony_ci char *request_type = NULL; 55613498266Sopenharmony_ci char *credential_scope = NULL; 55713498266Sopenharmony_ci char *str_to_sign = NULL; 55813498266Sopenharmony_ci const char *user = data->state.aptr.user ? data->state.aptr.user : ""; 55913498266Sopenharmony_ci char *secret = NULL; 56013498266Sopenharmony_ci unsigned char sign0[SHA256_DIGEST_LENGTH] = {0}; 56113498266Sopenharmony_ci unsigned char sign1[SHA256_DIGEST_LENGTH] = {0}; 56213498266Sopenharmony_ci char *auth_headers = NULL; 56313498266Sopenharmony_ci 56413498266Sopenharmony_ci DEBUGASSERT(!proxy); 56513498266Sopenharmony_ci (void)proxy; 56613498266Sopenharmony_ci 56713498266Sopenharmony_ci if(Curl_checkheaders(data, STRCONST("Authorization"))) { 56813498266Sopenharmony_ci /* Authorization already present, Bailing out */ 56913498266Sopenharmony_ci return CURLE_OK; 57013498266Sopenharmony_ci } 57113498266Sopenharmony_ci 57213498266Sopenharmony_ci /* we init those buffers here, so goto fail will free initialized dynbuf */ 57313498266Sopenharmony_ci Curl_dyn_init(&canonical_headers, CURL_MAX_HTTP_HEADER); 57413498266Sopenharmony_ci Curl_dyn_init(&canonical_query, CURL_MAX_HTTP_HEADER); 57513498266Sopenharmony_ci Curl_dyn_init(&signed_headers, CURL_MAX_HTTP_HEADER); 57613498266Sopenharmony_ci 57713498266Sopenharmony_ci /* 57813498266Sopenharmony_ci * Parameters parsing 57913498266Sopenharmony_ci * Google and Outscale use the same OSC or GOOG, 58013498266Sopenharmony_ci * but Amazon uses AWS and AMZ for header arguments. 58113498266Sopenharmony_ci * AWS is the default because most of non-amazon providers 58213498266Sopenharmony_ci * are still using aws:amz as a prefix. 58313498266Sopenharmony_ci */ 58413498266Sopenharmony_ci arg = data->set.str[STRING_AWS_SIGV4] ? 58513498266Sopenharmony_ci data->set.str[STRING_AWS_SIGV4] : "aws:amz"; 58613498266Sopenharmony_ci 58713498266Sopenharmony_ci /* provider1[:provider2[:region[:service]]] 58813498266Sopenharmony_ci 58913498266Sopenharmony_ci No string can be longer than N bytes of non-whitespace 59013498266Sopenharmony_ci */ 59113498266Sopenharmony_ci (void)sscanf(arg, "%" MAX_SIGV4_LEN_TXT "[^:]" 59213498266Sopenharmony_ci ":%" MAX_SIGV4_LEN_TXT "[^:]" 59313498266Sopenharmony_ci ":%" MAX_SIGV4_LEN_TXT "[^:]" 59413498266Sopenharmony_ci ":%" MAX_SIGV4_LEN_TXT "s", 59513498266Sopenharmony_ci provider0, provider1, region, service); 59613498266Sopenharmony_ci if(!provider0[0]) { 59713498266Sopenharmony_ci failf(data, "first aws-sigv4 provider can't be empty"); 59813498266Sopenharmony_ci result = CURLE_BAD_FUNCTION_ARGUMENT; 59913498266Sopenharmony_ci goto fail; 60013498266Sopenharmony_ci } 60113498266Sopenharmony_ci else if(!provider1[0]) 60213498266Sopenharmony_ci strcpy(provider1, provider0); 60313498266Sopenharmony_ci 60413498266Sopenharmony_ci if(!service[0]) { 60513498266Sopenharmony_ci char *hostdot = strchr(hostname, '.'); 60613498266Sopenharmony_ci if(!hostdot) { 60713498266Sopenharmony_ci failf(data, "aws-sigv4: service missing in parameters and hostname"); 60813498266Sopenharmony_ci result = CURLE_URL_MALFORMAT; 60913498266Sopenharmony_ci goto fail; 61013498266Sopenharmony_ci } 61113498266Sopenharmony_ci len = hostdot - hostname; 61213498266Sopenharmony_ci if(len > MAX_SIGV4_LEN) { 61313498266Sopenharmony_ci failf(data, "aws-sigv4: service too long in hostname"); 61413498266Sopenharmony_ci result = CURLE_URL_MALFORMAT; 61513498266Sopenharmony_ci goto fail; 61613498266Sopenharmony_ci } 61713498266Sopenharmony_ci memcpy(service, hostname, len); 61813498266Sopenharmony_ci service[len] = '\0'; 61913498266Sopenharmony_ci 62013498266Sopenharmony_ci infof(data, "aws_sigv4: picked service %s from host", service); 62113498266Sopenharmony_ci 62213498266Sopenharmony_ci if(!region[0]) { 62313498266Sopenharmony_ci const char *reg = hostdot + 1; 62413498266Sopenharmony_ci const char *hostreg = strchr(reg, '.'); 62513498266Sopenharmony_ci if(!hostreg) { 62613498266Sopenharmony_ci failf(data, "aws-sigv4: region missing in parameters and hostname"); 62713498266Sopenharmony_ci result = CURLE_URL_MALFORMAT; 62813498266Sopenharmony_ci goto fail; 62913498266Sopenharmony_ci } 63013498266Sopenharmony_ci len = hostreg - reg; 63113498266Sopenharmony_ci if(len > MAX_SIGV4_LEN) { 63213498266Sopenharmony_ci failf(data, "aws-sigv4: region too long in hostname"); 63313498266Sopenharmony_ci result = CURLE_URL_MALFORMAT; 63413498266Sopenharmony_ci goto fail; 63513498266Sopenharmony_ci } 63613498266Sopenharmony_ci memcpy(region, reg, len); 63713498266Sopenharmony_ci region[len] = '\0'; 63813498266Sopenharmony_ci infof(data, "aws_sigv4: picked region %s from host", region); 63913498266Sopenharmony_ci } 64013498266Sopenharmony_ci } 64113498266Sopenharmony_ci 64213498266Sopenharmony_ci Curl_http_method(data, conn, &method, &httpreq); 64313498266Sopenharmony_ci 64413498266Sopenharmony_ci /* AWS S3 requires a x-amz-content-sha256 header, and supports special 64513498266Sopenharmony_ci * values like UNSIGNED-PAYLOAD */ 64613498266Sopenharmony_ci sign_as_s3 = (strcasecompare(provider0, "aws") && 64713498266Sopenharmony_ci strcasecompare(service, "s3")); 64813498266Sopenharmony_ci 64913498266Sopenharmony_ci payload_hash = parse_content_sha_hdr(data, provider1, &payload_hash_len); 65013498266Sopenharmony_ci 65113498266Sopenharmony_ci if(!payload_hash) { 65213498266Sopenharmony_ci if(sign_as_s3) 65313498266Sopenharmony_ci result = calc_s3_payload_hash(data, httpreq, provider1, sha_hash, 65413498266Sopenharmony_ci sha_hex, content_sha256_hdr); 65513498266Sopenharmony_ci else 65613498266Sopenharmony_ci result = calc_payload_hash(data, sha_hash, sha_hex); 65713498266Sopenharmony_ci if(result) 65813498266Sopenharmony_ci goto fail; 65913498266Sopenharmony_ci 66013498266Sopenharmony_ci payload_hash = sha_hex; 66113498266Sopenharmony_ci /* may be shorter than SHA256_HEX_LENGTH, like S3_UNSIGNED_PAYLOAD */ 66213498266Sopenharmony_ci payload_hash_len = strlen(sha_hex); 66313498266Sopenharmony_ci } 66413498266Sopenharmony_ci 66513498266Sopenharmony_ci#ifdef DEBUGBUILD 66613498266Sopenharmony_ci { 66713498266Sopenharmony_ci char *force_timestamp = getenv("CURL_FORCETIME"); 66813498266Sopenharmony_ci if(force_timestamp) 66913498266Sopenharmony_ci clock = 0; 67013498266Sopenharmony_ci else 67113498266Sopenharmony_ci time(&clock); 67213498266Sopenharmony_ci } 67313498266Sopenharmony_ci#else 67413498266Sopenharmony_ci time(&clock); 67513498266Sopenharmony_ci#endif 67613498266Sopenharmony_ci result = Curl_gmtime(clock, &tm); 67713498266Sopenharmony_ci if(result) { 67813498266Sopenharmony_ci goto fail; 67913498266Sopenharmony_ci } 68013498266Sopenharmony_ci if(!strftime(timestamp, sizeof(timestamp), "%Y%m%dT%H%M%SZ", &tm)) { 68113498266Sopenharmony_ci result = CURLE_OUT_OF_MEMORY; 68213498266Sopenharmony_ci goto fail; 68313498266Sopenharmony_ci } 68413498266Sopenharmony_ci 68513498266Sopenharmony_ci result = make_headers(data, hostname, timestamp, provider1, 68613498266Sopenharmony_ci &date_header, content_sha256_hdr, 68713498266Sopenharmony_ci &canonical_headers, &signed_headers); 68813498266Sopenharmony_ci if(result) 68913498266Sopenharmony_ci goto fail; 69013498266Sopenharmony_ci 69113498266Sopenharmony_ci if(*content_sha256_hdr) { 69213498266Sopenharmony_ci /* make_headers() needed this without the \r\n for canonicalization */ 69313498266Sopenharmony_ci size_t hdrlen = strlen(content_sha256_hdr); 69413498266Sopenharmony_ci DEBUGASSERT(hdrlen + 3 < sizeof(content_sha256_hdr)); 69513498266Sopenharmony_ci memcpy(content_sha256_hdr + hdrlen, "\r\n", 3); 69613498266Sopenharmony_ci } 69713498266Sopenharmony_ci 69813498266Sopenharmony_ci memcpy(date, timestamp, sizeof(date)); 69913498266Sopenharmony_ci date[sizeof(date) - 1] = 0; 70013498266Sopenharmony_ci 70113498266Sopenharmony_ci result = canon_query(data, data->state.up.query, &canonical_query); 70213498266Sopenharmony_ci if(result) 70313498266Sopenharmony_ci goto fail; 70413498266Sopenharmony_ci result = CURLE_OUT_OF_MEMORY; 70513498266Sopenharmony_ci 70613498266Sopenharmony_ci canonical_request = 70713498266Sopenharmony_ci curl_maprintf("%s\n" /* HTTPRequestMethod */ 70813498266Sopenharmony_ci "%s\n" /* CanonicalURI */ 70913498266Sopenharmony_ci "%s\n" /* CanonicalQueryString */ 71013498266Sopenharmony_ci "%s\n" /* CanonicalHeaders */ 71113498266Sopenharmony_ci "%s\n" /* SignedHeaders */ 71213498266Sopenharmony_ci "%.*s", /* HashedRequestPayload in hex */ 71313498266Sopenharmony_ci method, 71413498266Sopenharmony_ci data->state.up.path, 71513498266Sopenharmony_ci Curl_dyn_ptr(&canonical_query) ? 71613498266Sopenharmony_ci Curl_dyn_ptr(&canonical_query) : "", 71713498266Sopenharmony_ci Curl_dyn_ptr(&canonical_headers), 71813498266Sopenharmony_ci Curl_dyn_ptr(&signed_headers), 71913498266Sopenharmony_ci (int)payload_hash_len, payload_hash); 72013498266Sopenharmony_ci if(!canonical_request) 72113498266Sopenharmony_ci goto fail; 72213498266Sopenharmony_ci 72313498266Sopenharmony_ci DEBUGF(infof(data, "Canonical request: %s", canonical_request)); 72413498266Sopenharmony_ci 72513498266Sopenharmony_ci /* provider 0 lowercase */ 72613498266Sopenharmony_ci Curl_strntolower(provider0, provider0, strlen(provider0)); 72713498266Sopenharmony_ci request_type = curl_maprintf("%s4_request", provider0); 72813498266Sopenharmony_ci if(!request_type) 72913498266Sopenharmony_ci goto fail; 73013498266Sopenharmony_ci 73113498266Sopenharmony_ci credential_scope = curl_maprintf("%s/%s/%s/%s", 73213498266Sopenharmony_ci date, region, service, request_type); 73313498266Sopenharmony_ci if(!credential_scope) 73413498266Sopenharmony_ci goto fail; 73513498266Sopenharmony_ci 73613498266Sopenharmony_ci if(Curl_sha256it(sha_hash, (unsigned char *) canonical_request, 73713498266Sopenharmony_ci strlen(canonical_request))) 73813498266Sopenharmony_ci goto fail; 73913498266Sopenharmony_ci 74013498266Sopenharmony_ci sha256_to_hex(sha_hex, sha_hash); 74113498266Sopenharmony_ci 74213498266Sopenharmony_ci /* provider 0 uppercase */ 74313498266Sopenharmony_ci Curl_strntoupper(provider0, provider0, strlen(provider0)); 74413498266Sopenharmony_ci 74513498266Sopenharmony_ci /* 74613498266Sopenharmony_ci * Google allows using RSA key instead of HMAC, so this code might change 74713498266Sopenharmony_ci * in the future. For now we only support HMAC. 74813498266Sopenharmony_ci */ 74913498266Sopenharmony_ci str_to_sign = curl_maprintf("%s4-HMAC-SHA256\n" /* Algorithm */ 75013498266Sopenharmony_ci "%s\n" /* RequestDateTime */ 75113498266Sopenharmony_ci "%s\n" /* CredentialScope */ 75213498266Sopenharmony_ci "%s", /* HashedCanonicalRequest in hex */ 75313498266Sopenharmony_ci provider0, 75413498266Sopenharmony_ci timestamp, 75513498266Sopenharmony_ci credential_scope, 75613498266Sopenharmony_ci sha_hex); 75713498266Sopenharmony_ci if(!str_to_sign) { 75813498266Sopenharmony_ci goto fail; 75913498266Sopenharmony_ci } 76013498266Sopenharmony_ci 76113498266Sopenharmony_ci /* provider 0 uppercase */ 76213498266Sopenharmony_ci secret = curl_maprintf("%s4%s", provider0, 76313498266Sopenharmony_ci data->state.aptr.passwd ? 76413498266Sopenharmony_ci data->state.aptr.passwd : ""); 76513498266Sopenharmony_ci if(!secret) 76613498266Sopenharmony_ci goto fail; 76713498266Sopenharmony_ci 76813498266Sopenharmony_ci HMAC_SHA256(secret, strlen(secret), date, strlen(date), sign0); 76913498266Sopenharmony_ci HMAC_SHA256(sign0, sizeof(sign0), region, strlen(region), sign1); 77013498266Sopenharmony_ci HMAC_SHA256(sign1, sizeof(sign1), service, strlen(service), sign0); 77113498266Sopenharmony_ci HMAC_SHA256(sign0, sizeof(sign0), request_type, strlen(request_type), sign1); 77213498266Sopenharmony_ci HMAC_SHA256(sign1, sizeof(sign1), str_to_sign, strlen(str_to_sign), sign0); 77313498266Sopenharmony_ci 77413498266Sopenharmony_ci sha256_to_hex(sha_hex, sign0); 77513498266Sopenharmony_ci 77613498266Sopenharmony_ci /* provider 0 uppercase */ 77713498266Sopenharmony_ci auth_headers = curl_maprintf("Authorization: %s4-HMAC-SHA256 " 77813498266Sopenharmony_ci "Credential=%s/%s, " 77913498266Sopenharmony_ci "SignedHeaders=%s, " 78013498266Sopenharmony_ci "Signature=%s\r\n" 78113498266Sopenharmony_ci /* 78213498266Sopenharmony_ci * date_header is added here, only if it wasn't 78313498266Sopenharmony_ci * user-specified (using CURLOPT_HTTPHEADER). 78413498266Sopenharmony_ci * date_header includes \r\n 78513498266Sopenharmony_ci */ 78613498266Sopenharmony_ci "%s" 78713498266Sopenharmony_ci "%s", /* optional sha256 header includes \r\n */ 78813498266Sopenharmony_ci provider0, 78913498266Sopenharmony_ci user, 79013498266Sopenharmony_ci credential_scope, 79113498266Sopenharmony_ci Curl_dyn_ptr(&signed_headers), 79213498266Sopenharmony_ci sha_hex, 79313498266Sopenharmony_ci date_header ? date_header : "", 79413498266Sopenharmony_ci content_sha256_hdr); 79513498266Sopenharmony_ci if(!auth_headers) { 79613498266Sopenharmony_ci goto fail; 79713498266Sopenharmony_ci } 79813498266Sopenharmony_ci 79913498266Sopenharmony_ci Curl_safefree(data->state.aptr.userpwd); 80013498266Sopenharmony_ci data->state.aptr.userpwd = auth_headers; 80113498266Sopenharmony_ci data->state.authhost.done = TRUE; 80213498266Sopenharmony_ci result = CURLE_OK; 80313498266Sopenharmony_ci 80413498266Sopenharmony_cifail: 80513498266Sopenharmony_ci Curl_dyn_free(&canonical_query); 80613498266Sopenharmony_ci Curl_dyn_free(&canonical_headers); 80713498266Sopenharmony_ci Curl_dyn_free(&signed_headers); 80813498266Sopenharmony_ci free(canonical_request); 80913498266Sopenharmony_ci free(request_type); 81013498266Sopenharmony_ci free(credential_scope); 81113498266Sopenharmony_ci free(str_to_sign); 81213498266Sopenharmony_ci free(secret); 81313498266Sopenharmony_ci free(date_header); 81413498266Sopenharmony_ci return result; 81513498266Sopenharmony_ci} 81613498266Sopenharmony_ci 81713498266Sopenharmony_ci#endif /* !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_AWS) */ 818