From ad2538d4732ca78575c6038d9d905382cf11e9b1 Mon Sep 17 00:00:00 2001 From: dartraiden Date: Thu, 13 Feb 2025 23:08:12 +0300 Subject: libcurl: update to 8.12.1 --- libs/libcurl/src/http_aws_sigv4.c | 152 +++++++++++++++++++++----------------- 1 file changed, 86 insertions(+), 66 deletions(-) (limited to 'libs/libcurl/src/http_aws_sigv4.c') diff --git a/libs/libcurl/src/http_aws_sigv4.c b/libs/libcurl/src/http_aws_sigv4.c index 007c355642..3c2f67de8b 100644 --- a/libs/libcurl/src/http_aws_sigv4.c +++ b/libs/libcurl/src/http_aws_sigv4.c @@ -35,6 +35,7 @@ #include "parsedate.h" #include "sendf.h" #include "escape.h" +#include "strparse.h" #include @@ -118,8 +119,6 @@ static void trim_headers(struct curl_slist *head) /* maximum length for the aws sivg4 parts */ #define MAX_SIGV4_LEN 64 -#define MAX_SIGV4_LEN_TXT "64" - #define DATE_HDR_KEY_LEN (MAX_SIGV4_LEN + sizeof("X--Date")) /* string been x-PROVIDER-date:TIMESTAMP, I need +1 for ':' */ @@ -160,7 +159,8 @@ static int compare_header_names(const char *a, const char *b) static CURLcode make_headers(struct Curl_easy *data, const char *hostname, char *timestamp, - char *provider1, + const char *provider1, + size_t plen, /* length of provider1 */ char **date_header, char *content_sha256_header, struct dynbuf *canonical_headers, @@ -174,16 +174,16 @@ static CURLcode make_headers(struct Curl_easy *data, struct curl_slist *l; bool again = TRUE; - /* provider1 mid */ - Curl_strntolower(provider1, provider1, strlen(provider1)); - provider1[0] = Curl_raw_toupper(provider1[0]); - - msnprintf(date_hdr_key, DATE_HDR_KEY_LEN, "X-%s-Date", provider1); + msnprintf(date_hdr_key, DATE_HDR_KEY_LEN, "X-%.*s-Date", + (int)plen, provider1); + /* provider1 ucfirst */ + Curl_strntolower(&date_hdr_key[2], provider1, plen); + date_hdr_key[2] = Curl_raw_toupper(provider1[0]); - /* provider1 lowercase */ - Curl_strntolower(provider1, provider1, 1); /* first byte only */ msnprintf(date_full_hdr, DATE_FULL_HDR_LEN, - "x-%s-date:%s", provider1, timestamp); + "x-%.*s-date:%s", (int)plen, provider1, timestamp); + /* provider1 lowercase */ + Curl_strntolower(&date_full_hdr[2], provider1, plen); if(!Curl_checkheaders(data, STRCONST("Host"))) { char *fullhost; @@ -336,6 +336,7 @@ fail: /* try to parse a payload hash from the content-sha256 header */ static char *parse_content_sha_hdr(struct Curl_easy *data, const char *provider1, + size_t plen, size_t *value_len) { char key[CONTENT_SHA256_KEY_LEN]; @@ -343,7 +344,8 @@ static char *parse_content_sha_hdr(struct Curl_easy *data, char *value; size_t len; - key_len = msnprintf(key, sizeof(key), "x-%s-content-sha256", provider1); + key_len = msnprintf(key, sizeof(key), "x-%.*s-content-sha256", + (int)plen, provider1); value = Curl_checkheaders(data, key, key_len); if(!value) @@ -389,6 +391,7 @@ static CURLcode calc_payload_hash(struct Curl_easy *data, static CURLcode calc_s3_payload_hash(struct Curl_easy *data, Curl_HttpReq httpreq, char *provider1, + size_t plen, unsigned char *sha_hash, char *sha_hex, char *header) { @@ -415,7 +418,7 @@ static CURLcode calc_s3_payload_hash(struct Curl_easy *data, /* format the required content-sha256 header */ msnprintf(header, CONTENT_SHA256_HDR_LEN, - "x-%s-content-sha256: %s", provider1, sha_hex); + "x-%.*s-content-sha256: %s", (int)plen, provider1, sha_hex); ret = CURLE_OK; fail: @@ -432,6 +435,8 @@ static int compare_func(const void *a, const void *b) const struct pair *aa = a; const struct pair *bb = b; /* If one element is empty, the other is always sorted higher */ + if(aa->len == 0 && bb->len == 0) + return 0; if(aa->len == 0) return -1; if(bb->len == 0) @@ -571,12 +576,11 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy) CURLcode result = CURLE_OUT_OF_MEMORY; struct connectdata *conn = data->conn; size_t len; - const char *arg; - char provider0[MAX_SIGV4_LEN + 1]=""; - char provider1[MAX_SIGV4_LEN + 1]=""; - char region[MAX_SIGV4_LEN + 1]=""; - char service[MAX_SIGV4_LEN + 1]=""; - bool sign_as_s3 = FALSE; + char *line; + struct Curl_str provider0; + struct Curl_str provider1; + struct Curl_str region = { NULL, 0}; + struct Curl_str service = { NULL, 0}; const char *hostname = conn->host.name; time_t clock; struct tm tm; @@ -625,27 +629,31 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy) * AWS is the default because most of non-amazon providers * are still using aws:amz as a prefix. */ - arg = data->set.str[STRING_AWS_SIGV4] ? - data->set.str[STRING_AWS_SIGV4] : "aws:amz"; + line = data->set.str[STRING_AWS_SIGV4] ? + data->set.str[STRING_AWS_SIGV4] : (char *)"aws:amz"; - /* provider1[:provider2[:region[:service]]] + /* provider0[:provider1[:region[:service]]] No string can be longer than N bytes of non-whitespace */ - (void)sscanf(arg, "%" MAX_SIGV4_LEN_TXT "[^:]" - ":%" MAX_SIGV4_LEN_TXT "[^:]" - ":%" MAX_SIGV4_LEN_TXT "[^:]" - ":%" MAX_SIGV4_LEN_TXT "s", - provider0, provider1, region, service); - if(!provider0[0]) { + if(Curl_str_until(&line, &provider0, MAX_SIGV4_LEN, ':')) { failf(data, "first aws-sigv4 provider cannot be empty"); result = CURLE_BAD_FUNCTION_ARGUMENT; goto fail; } - else if(!provider1[0]) - strcpy(provider1, provider0); + if(Curl_str_single(&line, ':') || + Curl_str_until(&line, &provider1, MAX_SIGV4_LEN, ':')) { + provider1.str = provider0.str; + provider1.len = provider0.len; + } + else if(Curl_str_single(&line, ':') || + Curl_str_until(&line, ®ion, MAX_SIGV4_LEN, ':') || + Curl_str_single(&line, ':') || + Curl_str_until(&line, &service, MAX_SIGV4_LEN, ':')) { + /* nothing to do */ + } - if(!service[0]) { + if(!service.len) { char *hostdot = strchr(hostname, '.'); if(!hostdot) { failf(data, "aws-sigv4: service missing in parameters and hostname"); @@ -658,12 +666,13 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy) result = CURLE_URL_MALFORMAT; goto fail; } - memcpy(service, hostname, len); - service[len] = '\0'; + service.str = (char *)hostname; + service.len = len; - infof(data, "aws_sigv4: picked service %s from host", service); + infof(data, "aws_sigv4: picked service %.*s from host", + (int)service.len, service.str); - if(!region[0]) { + if(!region.len) { const char *reg = hostdot + 1; const char *hostreg = strchr(reg, '.'); if(!hostreg) { @@ -677,25 +686,29 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy) result = CURLE_URL_MALFORMAT; goto fail; } - memcpy(region, reg, len); - region[len] = '\0'; - infof(data, "aws_sigv4: picked region %s from host", region); + region.str = (char *)reg; + region.len = len; + infof(data, "aws_sigv4: picked region %.*s from host", + (int)region.len, region.str); } } Curl_http_method(data, conn, &method, &httpreq); - /* AWS S3 requires a x-amz-content-sha256 header, and supports special - * values like UNSIGNED-PAYLOAD */ - sign_as_s3 = (strcasecompare(provider0, "aws") && - strcasecompare(service, "s3")); - - payload_hash = parse_content_sha_hdr(data, provider1, &payload_hash_len); + payload_hash = parse_content_sha_hdr(data, provider1.str, provider1.len, + &payload_hash_len); if(!payload_hash) { + /* AWS S3 requires a x-amz-content-sha256 header, and supports special + * values like UNSIGNED-PAYLOAD */ + bool sign_as_s3 = ((provider0.len == 3) && + strncasecompare(provider0.str, "aws", 3)) && + ((service.len == 2) && strncasecompare(service.str, "s3", 2)); + if(sign_as_s3) - result = calc_s3_payload_hash(data, httpreq, provider1, sha_hash, - sha_hex, content_sha256_hdr); + result = calc_s3_payload_hash(data, httpreq, + provider1.str, provider1.len, + sha_hash, sha_hex, content_sha256_hdr); else result = calc_payload_hash(data, sha_hash, sha_hex); if(result) @@ -726,7 +739,8 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy) goto fail; } - result = make_headers(data, hostname, timestamp, provider1, + result = make_headers(data, hostname, timestamp, + provider1.str, provider1.len, &date_header, content_sha256_hdr, &canonical_headers, &signed_headers); if(result) @@ -771,14 +785,18 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy) DEBUGF(infof(data, "Canonical request: %s", canonical_request)); - /* provider 0 lowercase */ - Curl_strntolower(provider0, provider0, strlen(provider0)); - request_type = aprintf("%s4_request", provider0); + request_type = aprintf("%.*s4_request", (int)provider0.len, provider0.str); if(!request_type) goto fail; - credential_scope = aprintf("%s/%s/%s/%s", - date, region, service, request_type); + /* provider0 is lowercased *after* aprintf() so that the buffer can be + written to */ + Curl_strntolower(request_type, request_type, provider0.len); + + credential_scope = aprintf("%s/%.*s/%.*s/%s", + date, (int)region.len, region.str, + (int)service.len, service.str, + request_type); if(!credential_scope) goto fail; @@ -788,42 +806,41 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy) sha256_to_hex(sha_hex, sha_hash); - /* provider 0 uppercase */ - Curl_strntoupper(provider0, provider0, strlen(provider0)); - /* * Google allows using RSA key instead of HMAC, so this code might change * in the future. For now we only support HMAC. */ - str_to_sign = aprintf("%s4-HMAC-SHA256\n" /* Algorithm */ + str_to_sign = aprintf("%.*s4-HMAC-SHA256\n" /* Algorithm */ "%s\n" /* RequestDateTime */ "%s\n" /* CredentialScope */ "%s", /* HashedCanonicalRequest in hex */ - provider0, + (int)provider0.len, provider0.str, timestamp, credential_scope, sha_hex); - if(!str_to_sign) { + if(!str_to_sign) goto fail; - } - /* provider 0 uppercase */ - secret = aprintf("%s4%s", provider0, + /* make provider0 part done uppercase */ + Curl_strntoupper(str_to_sign, provider0.str, provider0.len); + + secret = aprintf("%.*s4%s", (int)provider0.len, provider0.str, data->state.aptr.passwd ? data->state.aptr.passwd : ""); if(!secret) goto fail; + /* make provider0 part done uppercase */ + Curl_strntoupper(secret, provider0.str, provider0.len); HMAC_SHA256(secret, strlen(secret), date, strlen(date), sign0); - HMAC_SHA256(sign0, sizeof(sign0), region, strlen(region), sign1); - HMAC_SHA256(sign1, sizeof(sign1), service, strlen(service), sign0); + HMAC_SHA256(sign0, sizeof(sign0), region.str, region.len, sign1); + HMAC_SHA256(sign1, sizeof(sign1), service.str, service.len, sign0); HMAC_SHA256(sign0, sizeof(sign0), request_type, strlen(request_type), sign1); HMAC_SHA256(sign1, sizeof(sign1), str_to_sign, strlen(str_to_sign), sign0); sha256_to_hex(sha_hex, sign0); - /* provider 0 uppercase */ - auth_headers = aprintf("Authorization: %s4-HMAC-SHA256 " + auth_headers = aprintf("Authorization: %.*s4-HMAC-SHA256 " "Credential=%s/%s, " "SignedHeaders=%s, " "Signature=%s\r\n" @@ -834,7 +851,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy) */ "%s" "%s", /* optional sha256 header includes \r\n */ - provider0, + (int)provider0.len, provider0.str, user, credential_scope, Curl_dyn_ptr(&signed_headers), @@ -844,6 +861,9 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy) if(!auth_headers) { goto fail; } + /* provider 0 uppercase */ + Curl_strntoupper(&auth_headers[sizeof("Authorization: ") - 1], + provider0.str, provider0.len); Curl_safefree(data->state.aptr.userpwd); data->state.aptr.userpwd = auth_headers; -- cgit v1.2.3