From: Austin Moore Date: Sun, 4 Aug 2024 03:43:45 +0000 (-0400) Subject: aws_sigv4: fix canon order for headers with same prefix X-Git-Tag: curl-8_10_0~372 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=cf3e3d93d11ec17b47d7403392431fdb0fd7342e;p=thirdparty%2Fcurl.git aws_sigv4: fix canon order for headers with same prefix If a request containing two headers that have equivalent prefixes (ex. "x-amz-meta-test:test" and "x-amz-meta-test-two:test2") AWS expects the header with the shorter name to come first. The previous implementation used `strcmp` on the full header. Using the example, this would result in a comparison between the ':' and '-' chars and sort "x-amz-meta-test-two" before "x-amz-meta-test", which produces a different "StringToSign" than the one calculated by AWS. Test 1976 verifies Closes #14370 --- diff --git a/lib/http_aws_sigv4.c b/lib/http_aws_sigv4.c index 9e4f720165..7fe24a4c6f 100644 --- a/lib/http_aws_sigv4.c +++ b/lib/http_aws_sigv4.c @@ -129,6 +129,37 @@ static void trim_headers(struct curl_slist *head) /* string been x-PROVIDER-date:TIMESTAMP, I need +1 for ':' */ #define DATE_FULL_HDR_LEN (DATE_HDR_KEY_LEN + TIMESTAMP_SIZE + 1) +/* alphabetically compare two headers by their name, expecting + headers to use ':' at this point */ +static int compare_header_names(const char *a, const char *b) +{ + const char *colon_a; + const char *colon_b; + size_t len_a; + size_t len_b; + size_t min_len; + int cmp; + + colon_a = strchr(a, ':'); + colon_b = strchr(b, ':'); + + DEBUGASSERT(colon_a); + DEBUGASSERT(colon_b); + + len_a = colon_a ? (size_t)(colon_a - a) : strlen(a); + len_b = colon_b ? (size_t)(colon_b - b) : strlen(b); + + min_len = (len_a < len_b) ? len_a : len_b; + + cmp = strncmp(a, b, min_len); + + /* return the shorter of the two if one is shorter */ + if(!cmp) + return (int)(len_a - len_b); + + return cmp; +} + /* timestamp should point to a buffer of at last TIMESTAMP_SIZE bytes */ static CURLcode make_headers(struct Curl_easy *data, const char *hostname, @@ -267,13 +298,13 @@ static CURLcode make_headers(struct Curl_easy *data, *date_header = NULL; } - /* alpha-sort in a case sensitive manner */ + /* alpha-sort by header name in a case sensitive manner */ do { again = 0; for(l = head; l; l = l->next) { struct curl_slist *next = l->next; - if(next && strcmp(l->data, next->data) > 0) { + if(next && compare_header_names(l->data, next->data) > 0) { char *tmp = l->data; l->data = next->data; diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index 96de5fdcc3..aa329174a5 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -233,7 +233,7 @@ test1916 test1917 test1918 test1919 \ test1933 test1934 test1935 test1936 test1937 test1938 test1939 test1940 \ test1941 test1942 test1943 test1944 test1945 test1946 test1947 test1948 \ test1955 test1956 test1957 test1958 test1959 test1960 test1964 \ -test1970 test1971 test1972 test1973 test1974 test1975 \ +test1970 test1971 test1972 test1973 test1974 test1975 test1976 \ \ test2000 test2001 test2002 test2003 test2004 \ \ diff --git a/tests/data/test1976 b/tests/data/test1976 new file mode 100644 index 0000000000..7c04bc6553 --- /dev/null +++ b/tests/data/test1976 @@ -0,0 +1,60 @@ + + + +HTTP +CURLOPT_AWS_SIGV4 + + + +# Server-side + + +HTTP/1.1 200 OK +Date: Thu, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Content-Length: 0 + + + + +# Client-side + + +http + + +SSL +Debug +crypto + + +HTTP AWS_SIGV4 canonical request header sorting test + + +-X PUT -H "X-Amz-Meta-Test-Two: test2" -H "x-amz-meta-test: test" --aws-sigv4 "aws:amz:us-east-1:s3" -u "xxx:yyy" http://%HOSTIP:%HTTPPORT/%TESTNUMBER + + + +# Verify data after the test has been "shot" + + +^User-Agent:.* +^Content-Length:.* +^Accept:.* + + +# Strip the actual signature. We only care about header order in this test +s/Signature=[a-f0-9]{64}/Signature=stripped/ + + +PUT /%TESTNUMBER HTTP/1.1 +Host: %HOSTIP:%HTTPPORT +Authorization: AWS4-HMAC-SHA256 Credential=xxx/19700101/us-east-1/s3/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date;x-amz-meta-test;x-amz-meta-test-two, Signature=stripped +X-Amz-Date: 19700101T000000Z +x-amz-content-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +X-Amz-Meta-Test-Two: test2 +x-amz-meta-test: test + + + +