mirror of
https://github.com/curl/curl.git
synced 2026-06-15 14:15:38 +03:00
sigv4: URL encode the user name in the header
- split into sub functions - add 'aws-sigv4' as keyword for many tests Verify with test 3222 Reported-by: Trail of Bits Closes #21923
This commit is contained in:
parent
cb4b3e75e8
commit
c7cba2fd2d
21 changed files with 349 additions and 159 deletions
|
|
@ -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, ®ion, 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(®ion)) {
|
||||
if(curlx_str_until(&p, ®ion, 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(®ion), curlx_str(®ion));
|
||||
(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;
|
||||
}
|
||||
|
||||
infof(data, "aws_sigv4: Canonical request (enclosed in []) - [%s]",
|
||||
canonical_request);
|
||||
result = CURLE_OK;
|
||||
fail:
|
||||
curlx_dyn_free(&canonical_query);
|
||||
curlx_dyn_free(&canonical_path);
|
||||
return result;
|
||||
}
|
||||
|
||||
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(®ion),
|
||||
curlx_str(®ion),
|
||||
(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(®ion), curlx_strlen(®ion), 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), str_to_sign, strlen(str_to_sign), sign0);
|
||||
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);
|
||||
|
||||
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,
|
||||
®ion, &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, ®ion, &service,
|
||||
date, timestamp, canonical_request,
|
||||
&request_type, &credential_scope,
|
||||
&str_to_sign);
|
||||
}
|
||||
if(!result)
|
||||
result = sign_and_set_auth_headers(data, &provider0, ®ion, &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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
\
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
<keywords>
|
||||
HTTP
|
||||
CURLOPT_AWS_SIGV4
|
||||
aws-sigv4
|
||||
</keywords>
|
||||
</info>
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
<keywords>
|
||||
HTTP
|
||||
CURLOPT_AWS_SIGV4
|
||||
aws-sigv4
|
||||
</keywords>
|
||||
</info>
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
<keywords>
|
||||
HTTP
|
||||
CURLOPT_AWS_SIGV4
|
||||
aws-sigv4
|
||||
</keywords>
|
||||
</info>
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
<keywords>
|
||||
HTTP
|
||||
CURLOPT_AWS_SIGV4
|
||||
aws-sigv4
|
||||
</keywords>
|
||||
</info>
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
HTTP
|
||||
HTTP POST
|
||||
CURLOPT_AWS_SIGV4
|
||||
aws-sigv4
|
||||
</keywords>
|
||||
</info>
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
HTTP
|
||||
HTTP POST
|
||||
CURLOPT_AWS_SIGV4
|
||||
aws-sigv4
|
||||
</keywords>
|
||||
</info>
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
<keywords>
|
||||
HTTP
|
||||
CURLOPT_AWS_SIGV4
|
||||
aws-sigv4
|
||||
</keywords>
|
||||
</info>
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
<keywords>
|
||||
HTTP
|
||||
CURLOPT_AWS_SIGV4
|
||||
aws-sigv4
|
||||
</keywords>
|
||||
</info>
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
<keywords>
|
||||
HTTP
|
||||
CURLOPT_AWS_SIGV4
|
||||
aws-sigv4
|
||||
</keywords>
|
||||
</info>
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
<keywords>
|
||||
HTTP
|
||||
CURLOPT_AWS_SIGV4
|
||||
aws-sigv4
|
||||
</keywords>
|
||||
</info>
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
<keywords>
|
||||
HTTP
|
||||
CURLOPT_AWS_SIGV4
|
||||
aws-sigv4
|
||||
</keywords>
|
||||
</info>
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
<keywords>
|
||||
HTTP
|
||||
CURLOPT_AWS_SIGV4
|
||||
aws-sigv4
|
||||
</keywords>
|
||||
</info>
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
<keywords>
|
||||
HTTP
|
||||
CURLOPT_AWS_SIGV4
|
||||
aws-sigv4
|
||||
</keywords>
|
||||
</info>
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
<keywords>
|
||||
HTTP
|
||||
CURLOPT_AWS_SIGV4
|
||||
aws-sigv4
|
||||
</keywords>
|
||||
</info>
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
<keywords>
|
||||
HTTP
|
||||
CURLOPT_AWS_SIGV4
|
||||
aws-sigv4
|
||||
</keywords>
|
||||
</info>
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
<keywords>
|
||||
HTTP
|
||||
CURLOPT_AWS_SIGV4
|
||||
aws-sigv4
|
||||
</keywords>
|
||||
</info>
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
<keywords>
|
||||
HTTP
|
||||
CURLOPT_AWS_SIGV4
|
||||
aws-sigv4
|
||||
</keywords>
|
||||
</info>
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
<keywords>
|
||||
HTTP
|
||||
CURLOPT_AWS_SIGV4
|
||||
aws-sigv4
|
||||
</keywords>
|
||||
</info>
|
||||
|
||||
|
|
|
|||
57
tests/data/test3222
Normal file
57
tests/data/test3222
Normal file
|
|
@ -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>
|
||||
Loading…
Add table
Add a link
Reference in a new issue