]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
sigv4: URL encode the user name in the header
authorDaniel Stenberg <daniel@haxx.se>
Tue, 9 Jun 2026 09:40:41 +0000 (11:40 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Tue, 9 Jun 2026 11:34:27 +0000 (13:34 +0200)
- split into sub functions
- add 'aws-sigv4' as keyword for many tests

Verify with test 3222

Reported-by: Trail of Bits
Closes #21923

21 files changed:
lib/http_aws_sigv4.c
tests/data/Makefile.am
tests/data/test1933
tests/data/test1934
tests/data/test1935
tests/data/test1936
tests/data/test1937
tests/data/test1938
tests/data/test1955
tests/data/test1956
tests/data/test1957
tests/data/test1959
tests/data/test1970
tests/data/test1971
tests/data/test1972
tests/data/test1973
tests/data/test1974
tests/data/test1975
tests/data/test1976
tests/data/test1978
tests/data/test3222 [new file with mode: 0644]

index 308970bb89d266f46f74791a8e25226955e855d4..7a61bfb729c0a19c2e962fd448e0040faf707151 100644 (file)
@@ -817,67 +817,14 @@ fail:
   return result;
 }
 
-CURLcode Curl_output_aws_sigv4(struct Curl_easy *data)
+static CURLcode parse_sigv4_params(struct Curl_easy *data,
+                                   const char *hostname,
+                                   struct Curl_str *provider0,
+                                   struct Curl_str *provider1,
+                                   struct Curl_str *region,
+                                   struct Curl_str *service)
 {
-  CURLcode result = CURLE_OUT_OF_MEMORY;
-  struct connectdata *conn = data->conn;
-  const 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->origin->hostname;
-  time_t clock;
-  struct tm tm;
-  char timestamp[TIMESTAMP_SIZE];
-  char date[9];
-  struct dynbuf canonical_headers;
-  struct dynbuf signed_headers;
-  struct dynbuf canonical_query;
-  struct dynbuf canonical_path;
-  char *date_header = NULL;
-  Curl_HttpReq httpreq;
-  const char *method = NULL;
-  const char *payload_hash = NULL;
-  size_t payload_hash_len = 0;
-  unsigned char sha_hash[CURL_SHA256_DIGEST_LENGTH];
-  char sha_hex[SHA256_HEX_LENGTH];
-  char content_sha256_hdr[CONTENT_SHA256_HDR_LEN + 2] = ""; /* add \r\n */
-  char *canonical_request = NULL;
-  char *request_type = NULL;
-  char *credential_scope = NULL;
-  char *str_to_sign = NULL;
-  const char *user = Curl_creds_user(data->state.creds);
-  const char *passwd = Curl_creds_passwd(data->state.creds);
-  char *secret = NULL;
-  unsigned char sign0[CURL_SHA256_DIGEST_LENGTH] = { 0 };
-  unsigned char sign1[CURL_SHA256_DIGEST_LENGTH] = { 0 };
-  char *auth_headers = NULL;
-
-  if(data->set.path_as_is) {
-    failf(data, "Cannot use sigv4 authentication with path-as-is flag");
-    return CURLE_BAD_FUNCTION_ARGUMENT;
-  }
-
-  if(Curl_checkheaders(data, STRCONST("Authorization"))) {
-    /* Authorization already present, Bailing out */
-    return CURLE_OK;
-  }
-
-  /* we init those buffers here, so goto fail will free initialized dynbuf */
-  curlx_dyn_init(&canonical_headers, CURL_MAX_HTTP_HEADER);
-  curlx_dyn_init(&canonical_query, CURL_MAX_HTTP_HEADER);
-  curlx_dyn_init(&signed_headers, CURL_MAX_HTTP_HEADER);
-  curlx_dyn_init(&canonical_path, CURL_MAX_HTTP_HEADER);
-
-  /*
-   * Parameters parsing
-   * Google and Outscale use the same OSC or GOOG,
-   * but Amazon uses AWS and AMZ for header arguments.
-   * AWS is the default because most of non-amazon providers
-   * are still using aws:amz as a prefix.
-   */
-  line = data->set.str[STRING_AWS_SIGV4];
+  const char *line = data->set.str[STRING_AWS_SIGV4];
   if(!line || !*line)
     line = "aws:amz";
 
@@ -885,71 +832,89 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data)
 
      No string can be longer than N bytes of non-whitespace
   */
-  if(curlx_str_until(&line, &provider0, MAX_SIGV4_LEN, ':')) {
+  if(curlx_str_until(&line, provider0, MAX_SIGV4_LEN, ':')) {
     failf(data, "first aws-sigv4 provider cannot be empty");
-    result = CURLE_BAD_FUNCTION_ARGUMENT;
-    goto fail;
+    return CURLE_BAD_FUNCTION_ARGUMENT;
   }
   if(curlx_str_single(&line, ':') ||
-     curlx_str_until(&line, &provider1, MAX_SIGV4_LEN, ':')) {
-    provider1 = provider0;
+     curlx_str_until(&line, provider1, MAX_SIGV4_LEN, ':')) {
+    *provider1 = *provider0;
   }
   else if(curlx_str_single(&line, ':') ||
-          curlx_str_until(&line, &region, MAX_SIGV4_LEN, ':') ||
+          curlx_str_until(&line, region, MAX_SIGV4_LEN, ':') ||
           curlx_str_single(&line, ':') ||
-          curlx_str_until(&line, &service, MAX_SIGV4_LEN, ':')) {
+          curlx_str_until(&line, service, MAX_SIGV4_LEN, ':')) {
     /* nothing to do */
   }
 
-  if(!curlx_strlen(&service)) {
+  if(!curlx_strlen(service)) {
     const char *p = hostname;
-    if(curlx_str_until(&p, &service, MAX_SIGV4_LEN, '.') ||
+    if(curlx_str_until(&p, service, MAX_SIGV4_LEN, '.') ||
        curlx_str_single(&p, '.')) {
       failf(data, "aws-sigv4: service missing in parameters and hostname");
-      result = CURLE_URL_MALFORMAT;
-      goto fail;
+      return CURLE_URL_MALFORMAT;
     }
 
     infof(data, "aws_sigv4: picked service %.*s from host",
-          (int)curlx_strlen(&service), curlx_str(&service));
+          (int)curlx_strlen(service), curlx_str(service));
 
-    if(!curlx_strlen(&region)) {
-      if(curlx_str_until(&p, &region, MAX_SIGV4_LEN, '.') ||
+    if(!curlx_strlen(region)) {
+      if(curlx_str_until(&p, region, MAX_SIGV4_LEN, '.') ||
          curlx_str_single(&p, '.')) {
         failf(data, "aws-sigv4: region missing in parameters and hostname");
-        result = CURLE_URL_MALFORMAT;
-        goto fail;
+        return CURLE_URL_MALFORMAT;
       }
       infof(data, "aws_sigv4: picked region %.*s from host",
-            (int)curlx_strlen(&region), curlx_str(&region));
+            (int)curlx_strlen(region), curlx_str(region));
     }
   }
 
-  Curl_http_method(data, &method, &httpreq);
+  return CURLE_OK;
+}
 
-  payload_hash =
-    parse_content_sha_hdr(data, curlx_str(&provider1),
-                          curlx_strlen(&provider1), &payload_hash_len);
+static CURLcode get_payload_hash(struct Curl_easy *data,
+                                 Curl_HttpReq httpreq,
+                                 struct Curl_str *provider0,
+                                 struct Curl_str *provider1,
+                                 struct Curl_str *service,
+                                 unsigned char *sha_hash,
+                                 char *sha_hex,
+                                 char *content_sha256_hdr,
+                                 const char **payload_hash_out,
+                                 size_t *payload_hash_len_out)
+{
+  *payload_hash_out =
+    parse_content_sha_hdr(data, curlx_str(provider1),
+                          curlx_strlen(provider1), payload_hash_len_out);
 
-  if(!payload_hash) {
+  if(!*payload_hash_out) {
+    CURLcode result;
     /* AWS S3 requires a x-amz-content-sha256 header, and supports special
      * values like UNSIGNED-PAYLOAD */
-    bool sign_as_s3 = curlx_str_casecompare(&provider0, "aws") &&
-                      curlx_str_casecompare(&service, "s3");
+    bool sign_as_s3 = curlx_str_casecompare(provider0, "aws") &&
+                      curlx_str_casecompare(service, "s3");
 
     if(sign_as_s3)
-      result = calc_s3_payload_hash(data, httpreq, curlx_str(&provider1),
-                                    curlx_strlen(&provider1), sha_hash,
+      result = calc_s3_payload_hash(data, httpreq, curlx_str(provider1),
+                                    curlx_strlen(provider1), sha_hash,
                                     sha_hex, content_sha256_hdr);
     else
       result = calc_payload_hash(data, sha_hash, sha_hex);
     if(result)
-      goto fail;
+      return result;
 
-    payload_hash = sha_hex;
+    *payload_hash_out = sha_hex;
     /* may be shorter than SHA256_HEX_LENGTH, like S3_UNSIGNED_PAYLOAD */
-    payload_hash_len = strlen(sha_hex);
+    *payload_hash_len_out = strlen(sha_hex);
   }
+  return CURLE_OK;
+}
+
+static CURLcode get_timestamp(char *timestamp, size_t stampsize)
+{
+  time_t clock;
+  struct tm tm;
+  CURLcode result;
 
 #ifdef DEBUGBUILD
   {
@@ -963,43 +928,54 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data)
   clock = time(NULL);
 #endif
   result = curlx_gmtime(clock, &tm);
-  if(result) {
-    goto fail;
-  }
-  if(!strftime(timestamp, sizeof(timestamp), "%Y%m%dT%H%M%SZ", &tm)) {
-    result = CURLE_OUT_OF_MEMORY;
-    goto fail;
-  }
+  if(result)
+    return result;
+
+  if(!strftime(timestamp, stampsize, "%Y%m%dT%H%M%SZ", &tm))
+    return CURLE_OUT_OF_MEMORY;
+
+  return CURLE_OK;
+}
+
+static CURLcode make_canonical_request(struct Curl_easy *data,
+                                       const char *hostname,
+                                       char *timestamp,
+                                       struct Curl_str *provider1,
+                                       struct Curl_str *service,
+                                       const char *method,
+                                       const char *payload_hash,
+                                       size_t payload_hash_len,
+                                       char **date_header_out,
+                                       char *content_sha256_hdr,
+                                       struct dynbuf *canonical_headers,
+                                       struct dynbuf *signed_headers,
+                                       char **canonical_request_out)
+{
+  struct dynbuf canonical_query;
+  struct dynbuf canonical_path;
+  CURLcode result;
+
+  curlx_dyn_init(&canonical_query, CURL_MAX_HTTP_HEADER);
+  curlx_dyn_init(&canonical_path, CURL_MAX_HTTP_HEADER);
 
   result = make_headers(data, hostname, timestamp,
-                        curlx_str(&provider1), curlx_strlen(&provider1),
-                        &date_header, content_sha256_hdr,
-                        &canonical_headers, &signed_headers);
+                        curlx_str(provider1), curlx_strlen(provider1),
+                        date_header_out, content_sha256_hdr,
+                        canonical_headers, signed_headers);
   if(result)
     goto fail;
 
-  if(*content_sha256_hdr) {
-    /* make_headers() needed this without the \r\n for canonicalization */
-    size_t hdrlen = strlen(content_sha256_hdr);
-    DEBUGASSERT(hdrlen + 3 < sizeof(content_sha256_hdr));
-    memcpy(content_sha256_hdr + hdrlen, "\r\n", 3);
-  }
-
-  memcpy(date, timestamp, sizeof(date));
-  date[sizeof(date) - 1] = 0;
-
   result = canon_query(data->state.up.query, &canonical_query);
   if(result)
     goto fail;
 
   result = canon_path(data->state.up.path, strlen(data->state.up.path),
                       &canonical_path,
-                      should_urlencode(&service));
+                      should_urlencode(service));
   if(result)
     goto fail;
-  result = CURLE_OUT_OF_MEMORY;
 
-  canonical_request =
+  *canonical_request_out =
     curl_maprintf("%s\n" /* HTTPRequestMethod */
                   "%s\n" /* CanonicalURI */
                   "%s\n" /* CanonicalQueryString */
@@ -1010,37 +986,65 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data)
                   curlx_dyn_ptr(&canonical_path),
                   curlx_dyn_ptr(&canonical_query) ?
                   curlx_dyn_ptr(&canonical_query) : "",
-                  curlx_dyn_ptr(&canonical_headers),
-                  curlx_dyn_ptr(&signed_headers),
+                  curlx_dyn_ptr(canonical_headers),
+                  curlx_dyn_ptr(signed_headers),
                   (int)payload_hash_len, payload_hash);
-  if(!canonical_request)
+  if(!*canonical_request_out) {
+    result = CURLE_OUT_OF_MEMORY;
     goto fail;
+  }
+
+  result = CURLE_OK;
+fail:
+  curlx_dyn_free(&canonical_query);
+  curlx_dyn_free(&canonical_path);
+  return result;
+}
 
-  infof(data, "aws_sigv4: Canonical request (enclosed in []) - [%s]",
-        canonical_request);
+static CURLcode make_string_to_sign(struct Curl_easy *data,
+                                    struct Curl_str *provider0,
+                                    struct Curl_str *region,
+                                    struct Curl_str *service,
+                                    const char *date,
+                                    const char *timestamp,
+                                    const char *canonical_request,
+                                    char **request_type_out,
+                                    char **credential_scope_out,
+                                    char **str_to_sign_out)
+{
+  char *request_type;
+  char *credential_scope;
+  char *str_to_sign;
+  unsigned char sha_hash[CURL_SHA256_DIGEST_LENGTH];
+  char sha_hex[SHA256_HEX_LENGTH];
 
   request_type = curl_maprintf("%.*s4_request",
-                               (int)curlx_strlen(&provider0),
-                               curlx_str(&provider0));
+                               (int)curlx_strlen(provider0),
+                               curlx_str(provider0));
   if(!request_type)
-    goto fail;
+    return CURLE_OUT_OF_MEMORY;
 
   /* provider0 is lowercased *after* curl_maprintf() so that the buffer
      can be written to */
-  Curl_strntolower(request_type, request_type, curlx_strlen(&provider0));
+  Curl_strntolower(request_type, request_type, curlx_strlen(provider0));
 
   credential_scope = curl_maprintf("%s/%.*s/%.*s/%s", date,
-                                   (int)curlx_strlen(&region),
-                                   curlx_str(&region),
-                                   (int)curlx_strlen(&service),
-                                   curlx_str(&service),
+                                   (int)curlx_strlen(region),
+                                   curlx_str(region),
+                                   (int)curlx_strlen(service),
+                                   curlx_str(service),
                                    request_type);
-  if(!credential_scope)
-    goto fail;
+  if(!credential_scope) {
+    curlx_free(request_type);
+    return CURLE_OUT_OF_MEMORY;
+  }
 
-  if(Curl_sha256it(sha_hash, (unsigned char *)canonical_request,
-                   strlen(canonical_request)))
-    goto fail;
+  if(Curl_sha256it(sha_hash, (const unsigned char *)canonical_request,
+                   strlen(canonical_request))) {
+    curlx_free(request_type);
+    curlx_free(credential_scope);
+    return CURLE_OUT_OF_MEMORY;
+  }
 
   sha256_to_hex(sha_hex, sha_hash);
 
@@ -1052,35 +1056,69 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data)
                               "%s\n" /* RequestDateTime */
                               "%s\n" /* CredentialScope */
                               "%s",  /* HashedCanonicalRequest in hex */
-                              (int)curlx_strlen(&provider0),
-                              curlx_str(&provider0),
+                              (int)curlx_strlen(provider0),
+                              curlx_str(provider0),
                               timestamp,
                               credential_scope,
                               sha_hex);
-  if(!str_to_sign)
-    goto fail;
+  if(!str_to_sign) {
+    curlx_free(request_type);
+    curlx_free(credential_scope);
+    return CURLE_OUT_OF_MEMORY;
+  }
 
   /* make provider0 part done uppercase */
-  Curl_strntoupper(str_to_sign, curlx_str(&provider0),
-                   curlx_strlen(&provider0));
+  Curl_strntoupper(str_to_sign, curlx_str(provider0),
+                   curlx_strlen(provider0));
 
   infof(data, "aws_sigv4: String to sign (enclosed in []) - [%s]",
         str_to_sign);
 
-  secret = curl_maprintf("%.*s4%s", (int)curlx_strlen(&provider0),
-                         curlx_str(&provider0), passwd);
+  *request_type_out = request_type;
+  *credential_scope_out = credential_scope;
+  *str_to_sign_out = str_to_sign;
+  return CURLE_OK;
+}
+
+static CURLcode sign_and_set_auth_headers(struct Curl_easy *data,
+                                          struct Curl_str *provider0,
+                                          struct Curl_str *region,
+                                          struct Curl_str *service,
+                                          const char *request_type,
+                                          const char *credential_scope,
+                                          const char *date,
+                                          const char *str_to_sign,
+                                          const char *date_header,
+                                          const char *content_sha256_hdr,
+                                          struct dynbuf *signed_headers)
+{
+  CURLcode result = CURLE_OUT_OF_MEMORY;
+  const char *passwd = Curl_creds_passwd(data->state.creds);
+  char *secret = NULL;
+  unsigned char sign0[CURL_SHA256_DIGEST_LENGTH] = { 0 };
+  unsigned char sign1[CURL_SHA256_DIGEST_LENGTH] = { 0 };
+  char sha_hex[SHA256_HEX_LENGTH];
+  char *auth_headers = NULL;
+  char *user = curl_escape(Curl_creds_user(data->state.creds), 0);
+  if(!user)
+    return CURLE_OUT_OF_MEMORY;
+
+  secret = curl_maprintf("%.*s4%s", (int)curlx_strlen(provider0),
+                         curlx_str(provider0), passwd);
   if(!secret)
     goto fail;
   /* make provider0 part done uppercase */
-  Curl_strntoupper(secret, curlx_str(&provider0), curlx_strlen(&provider0));
+  Curl_strntoupper(secret, curlx_str(provider0), curlx_strlen(provider0));
 
   HMAC_SHA256(secret, strlen(secret), date, strlen(date), sign0);
   HMAC_SHA256(sign0, sizeof(sign0),
-              curlx_str(&region), curlx_strlen(&region), sign1);
+              curlx_str(region), curlx_strlen(region), sign1);
+  HMAC_SHA256(sign1, sizeof(sign1),
+              curlx_str(service), curlx_strlen(service), sign0);
+  HMAC_SHA256(sign0, sizeof(sign0),
+              request_type, strlen(request_type), sign1);
   HMAC_SHA256(sign1, sizeof(sign1),
-              curlx_str(&service), curlx_strlen(&service), 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);
+              str_to_sign, strlen(str_to_sign), sign0);
 
   sha256_to_hex(sha_hex, sign0);
 
@@ -1090,27 +1128,28 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data)
                                "Credential=%s/%s, "
                                "SignedHeaders=%s, "
                                "Signature=%s\r\n"
+                               "%s"
+                               "%s%s",
+                               (int)curlx_strlen(provider0),
+                               curlx_str(provider0),
+                               user,
+                               credential_scope,
+                               curlx_dyn_ptr(signed_headers),
+                               sha_hex,
                                /*
                                 * date_header is added here, only if it was not
                                 * user-specified (using CURLOPT_HTTPHEADER).
                                 * date_header includes \r\n
                                 */
-                               "%s"
-                               "%s", /* optional sha256 header includes \r\n */
-                               (int)curlx_strlen(&provider0),
-                               curlx_str(&provider0),
-                               user,
-                               credential_scope,
-                               curlx_dyn_ptr(&signed_headers),
-                               sha_hex,
                                date_header ? date_header : "",
-                               content_sha256_hdr);
-  if(!auth_headers) {
+                               content_sha256_hdr,
+                               content_sha256_hdr[0] ? "\r\n": "");
+  if(!auth_headers)
     goto fail;
-  }
+
   /* provider 0 uppercase */
   Curl_strntoupper(&auth_headers[sizeof("Authorization: ") - 1],
-                   curlx_str(&provider0), curlx_strlen(&provider0));
+                   curlx_str(provider0), curlx_strlen(provider0));
 
   curlx_free(data->req.hd_auth);
   data->req.hd_auth = auth_headers;
@@ -1118,15 +1157,91 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data)
   result = CURLE_OK;
 
 fail:
-  curlx_dyn_free(&canonical_query);
-  curlx_dyn_free(&canonical_path);
+  curlx_free(user);
+  curlx_free(secret);
+  return result;
+}
+
+CURLcode Curl_output_aws_sigv4(struct Curl_easy *data)
+{
+  CURLcode result = CURLE_OUT_OF_MEMORY;
+  struct connectdata *conn = data->conn;
+  struct Curl_str provider0 = { NULL, 0 };
+  struct Curl_str provider1 = { NULL, 0 };
+  struct Curl_str region = { NULL, 0 };
+  struct Curl_str service = { NULL, 0 };
+  const char *hostname = conn->origin->hostname;
+  char timestamp[TIMESTAMP_SIZE];
+  char date[9];
+  struct dynbuf canonical_headers;
+  struct dynbuf signed_headers;
+  char *date_header = NULL;
+  Curl_HttpReq httpreq;
+  const char *method = NULL;
+  const char *payload_hash = NULL;
+  size_t payload_hash_len = 0;
+  unsigned char sha_hash[CURL_SHA256_DIGEST_LENGTH];
+  char sha_hex[SHA256_HEX_LENGTH];
+  char content_sha256_hdr[CONTENT_SHA256_HDR_LEN + 2] = ""; /* add \r\n */
+  char *canonical_request = NULL;
+  char *request_type = NULL;
+  char *credential_scope = NULL;
+  char *str_to_sign = NULL;
+
+  if(data->set.path_as_is) {
+    failf(data, "Cannot use sigv4 authentication with path-as-is flag");
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+  }
+
+  if(Curl_checkheaders(data, STRCONST("Authorization")))
+    /* Authorization already present, Bailing out */
+    return CURLE_OK;
+
+  /* we init those buffers here, so goto fail will free initialized dynbuf */
+  curlx_dyn_init(&canonical_headers, CURL_MAX_HTTP_HEADER);
+  curlx_dyn_init(&signed_headers, CURL_MAX_HTTP_HEADER);
+
+  result = parse_sigv4_params(data, hostname, &provider0, &provider1,
+                              &region, &service);
+  if(!result) {
+    Curl_http_method(data, &method, &httpreq);
+    result = get_payload_hash(data, httpreq, &provider0, &provider1, &service,
+                              sha_hash, sha_hex, content_sha256_hdr,
+                              &payload_hash, &payload_hash_len);
+  }
+
+  if(!result)
+    result = get_timestamp(timestamp, sizeof(timestamp));
+
+  if(!result)
+    result = make_canonical_request(data, hostname, timestamp,
+                                    &provider1, &service,
+                                    method, payload_hash, payload_hash_len,
+                                    &date_header, content_sha256_hdr,
+                                    &canonical_headers, &signed_headers,
+                                    &canonical_request);
+  if(!result) {
+    /* the timestamp might have been updated in make_canonical_request */
+    memcpy(date, timestamp, sizeof(date) - 1);
+    date[sizeof(date) - 1] = 0;
+
+    result = make_string_to_sign(data, &provider0, &region, &service,
+                                 date, timestamp, canonical_request,
+                                 &request_type, &credential_scope,
+                                 &str_to_sign);
+  }
+  if(!result)
+    result = sign_and_set_auth_headers(data, &provider0, &region, &service,
+                                       request_type, credential_scope,
+                                       date, str_to_sign, date_header,
+                                       content_sha256_hdr, &signed_headers);
+
   curlx_dyn_free(&canonical_headers);
   curlx_dyn_free(&signed_headers);
   curlx_free(canonical_request);
   curlx_free(request_type);
   curlx_free(credential_scope);
   curlx_free(str_to_sign);
-  curlx_free(secret);
   curlx_free(date_header);
   return result;
 }
index 393f7531bdb2b69d605c3ef35bd42d221f0887e7..413f7a1143cfda0418a70c188afb4c87e99e3170 100644 (file)
@@ -281,7 +281,7 @@ test3100 test3101 test3102 test3103 test3104 test3105 test3106 \
 \
 test3200 test3201 test3202 test3203 test3204 test3205 test3206 test3207 \
 test3208 test3209 test3210 test3211 test3212 test3213 test3214 test3215 \
-test3216 test3217 test3218 test3219 test3220 test3221 \
+test3216 test3217 test3218 test3219 test3220 test3221 test3222 \
 \
 test3300 test3301 test3302 test3303 test3304 test3305 \
 \
index e1ef8b95ba13de195ede03ae6f5abac00929c925..cda12d19a121f2e42e71e3126fffb9a3e42ccc7b 100644 (file)
@@ -4,6 +4,7 @@
 <keywords>
 HTTP
 CURLOPT_AWS_SIGV4
+aws-sigv4
 </keywords>
 </info>
 
index 2128b299c2ebece9fd7ce07a98c3b90d976bcfac..9c52a0d0bdddf378aada9a5531afbc3c0807bdc8 100644 (file)
@@ -4,6 +4,7 @@
 <keywords>
 HTTP
 CURLOPT_AWS_SIGV4
+aws-sigv4
 </keywords>
 </info>
 
index 158620a3bd29696f96225e6302dc63ae58e2cd83..f92c7e8ea2d3ab55af5106680c4418ea52f8b5b3 100644 (file)
@@ -4,6 +4,7 @@
 <keywords>
 HTTP
 CURLOPT_AWS_SIGV4
+aws-sigv4
 </keywords>
 </info>
 
index 330fccc75650e344d9639b29558d57b6c1a62f5c..e43eb0be6916470ab148b7305a4f7515a48aff1b 100644 (file)
@@ -4,6 +4,7 @@
 <keywords>
 HTTP
 CURLOPT_AWS_SIGV4
+aws-sigv4
 </keywords>
 </info>
 
index 19049410be9864ba30c2cf2a6f9fd750bad7a3f2..2043053e59db55fef32513daf773776834e9626f 100644 (file)
@@ -5,6 +5,7 @@
 HTTP
 HTTP POST
 CURLOPT_AWS_SIGV4
+aws-sigv4
 </keywords>
 </info>
 
index 91e27f876833dc4dc4bd9848045e1deeb8d06a89..a2ea20fc9662e374b9d63f1ffb56615c28037644 100644 (file)
@@ -5,6 +5,7 @@
 HTTP
 HTTP POST
 CURLOPT_AWS_SIGV4
+aws-sigv4
 </keywords>
 </info>
 
index 7b84f746bd044f872fec77c21b7be24d662eb761..82349c25395bff6515e7c02f115a52b7a353711d 100644 (file)
@@ -4,6 +4,7 @@
 <keywords>
 HTTP
 CURLOPT_AWS_SIGV4
+aws-sigv4
 </keywords>
 </info>
 
index 3e8a9f9ce4490816d7921a1f4b86a2a735e703a8..f3ad8b859a1476b9928a47e5e60b9c8e8f96ff95 100644 (file)
@@ -4,6 +4,7 @@
 <keywords>
 HTTP
 CURLOPT_AWS_SIGV4
+aws-sigv4
 </keywords>
 </info>
 
index 181eabb9f5af8390b2c58537c3236a7aedb45d17..77b48b238897050380a579a4f372cb197979fe2b 100644 (file)
@@ -4,6 +4,7 @@
 <keywords>
 HTTP
 CURLOPT_AWS_SIGV4
+aws-sigv4
 </keywords>
 </info>
 
index 7f0357da8f4b0ca2ceae60d3a51eedea2dc1dd08..27a778c305ac3f9eba34ec01e849f15e390a3dca 100644 (file)
@@ -4,6 +4,7 @@
 <keywords>
 HTTP
 CURLOPT_AWS_SIGV4
+aws-sigv4
 </keywords>
 </info>
 
index e697cabfeec64248b0972839c5c41a1df377bf83..8dae28c75339629f82959e599c0359cab02c4faa 100644 (file)
@@ -4,6 +4,7 @@
 <keywords>
 HTTP
 CURLOPT_AWS_SIGV4
+aws-sigv4
 </keywords>
 </info>
 
index bc44cd3eaa82a9e25f34e3a74c5070b700695bbd..c303018c72df568009b213853541f5c87fa93f8a 100644 (file)
@@ -4,6 +4,7 @@
 <keywords>
 HTTP
 CURLOPT_AWS_SIGV4
+aws-sigv4
 </keywords>
 </info>
 
index 7de801da7e977ba42b911867dab2d978ed988ee1..d128dccf452c3e456241b63e9fbac1a6cb599d71 100644 (file)
@@ -4,6 +4,7 @@
 <keywords>
 HTTP
 CURLOPT_AWS_SIGV4
+aws-sigv4
 </keywords>
 </info>
 
index 896631f1514dfe5604359f31f63ad658f9680f80..c2527df686f4a19a92187da028636df014edfc76 100644 (file)
@@ -4,6 +4,7 @@
 <keywords>
 HTTP
 CURLOPT_AWS_SIGV4
+aws-sigv4
 </keywords>
 </info>
 
index 6a99684d8855d577dd198bb94293736aa2a9a51e..20a10a87056d533818af487a06930af06e831a36 100644 (file)
@@ -4,6 +4,7 @@
 <keywords>
 HTTP
 CURLOPT_AWS_SIGV4
+aws-sigv4
 </keywords>
 </info>
 
index a4d1a7f0f750c77d9fc17bcc6b7db8168aebe11d..e5d6272eda0ba33d52c1b70d10cf29e867ff67b3 100644 (file)
@@ -4,6 +4,7 @@
 <keywords>
 HTTP
 CURLOPT_AWS_SIGV4
+aws-sigv4
 </keywords>
 </info>
 
index 5a0ff39dc086b395f4adc3ec8453f2575f15d55c..3a09cc2ca31ea91375e34af6d54bf737a16a818e 100644 (file)
@@ -4,6 +4,7 @@
 <keywords>
 HTTP
 CURLOPT_AWS_SIGV4
+aws-sigv4
 </keywords>
 </info>
 
index 3ad4c670e2be80ad96dd7dbce55572f1c5abfd64..b2a4285b96aee4b10241d6d6e148150eb9b51516 100644 (file)
@@ -4,6 +4,7 @@
 <keywords>
 HTTP
 CURLOPT_AWS_SIGV4
+aws-sigv4
 </keywords>
 </info>
 
diff --git a/tests/data/test3222 b/tests/data/test3222
new file mode 100644 (file)
index 0000000..cf6caa1
--- /dev/null
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="US-ASCII"?>
+<testcase>
+<info>
+<keywords>
+HTTP
+aws-sigv4
+</keywords>
+</info>
+
+# Server-side
+<reply>
+<data crlf="headers">
+HTTP/1.1 200 OK
+Date: Tue, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
+ETag: "21025-dc7-39462498"
+Accept-Ranges: bytes
+Content-Length: 6
+Connection: close
+Content-Type: text/html
+Funny-head: yesyes
+
+-foo-
+</data>
+</reply>
+
+# Client-side
+<client>
+<server>
+http
+</server>
+<features>
+Debug
+aws
+</features>
+<name>
+aws-sigv4 with CRLF in username
+</name>
+<command>
+"http://user%0d%0a:secret@fake.fake.fake:8000/" --aws-sigv4 "aws:amz:us-east-2:es" --connect-to fake.fake.fake:8000:%HOSTIP:%HTTPPORT
+</command>
+</client>
+
+# Verify data after the test has been "shot"
+<verify>
+<protocol crlf="headers">
+GET / HTTP/1.1
+Host: fake.fake.fake:8000
+Authorization: AWS4-HMAC-SHA256 Credential=user%0D%0A/19700101/us-east-2/es/aws4_request, SignedHeaders=host;x-amz-date, Signature=e5747e9555c0e96f1067cc4bf9f6055e72a185178e5dd0c2909279ec1d66360b
+X-Amz-Date: 19700101T000000Z
+User-Agent: curl/%VERSION
+Accept: */*
+
+</protocol>
+</verify>
+</testcase>