Note: better to sort queries automatically for more information refer to Amazon S3 document: http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html
| 352 | // for more information refer to Amazon S3 document: |
| 353 | // http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-query-string-auth.html |
| 354 | void SignRequestV4(const string &method, HTTPHeaders *headers, const string &origRegion, |
| 355 | const string &path, const string &query, const S3Credential &cred) { |
| 356 | struct tm tm_info; |
| 357 | char date_str[DATE_STR_LEN] = {0}; |
| 358 | char timestamp_str[TIME_STAMP_STR_LEN] = {0}; |
| 359 | |
| 360 | char canonical_hex[SHA256_DIGEST_STRING_LENGTH] = {0}; |
| 361 | char signature_hex[SHA256_DIGEST_STRING_LENGTH] = {0}; |
| 362 | |
| 363 | unsigned char key_date[SHA256_DIGEST_LENGTH] = {0}; |
| 364 | unsigned char key_region[SHA256_DIGEST_LENGTH] = {0}; |
| 365 | unsigned char key_service[SHA256_DIGEST_LENGTH] = {0}; |
| 366 | unsigned char signing_key[SHA256_DIGEST_LENGTH] = {0}; |
| 367 | |
| 368 | // YYYYMMDD'T'HHMMSS'Z' |
| 369 | time_t t = time(NULL); |
| 370 | gmtime_r(&t, &tm_info); |
| 371 | strftime(timestamp_str, TIME_STAMP_STR_LEN, "%Y%m%dT%H%M%SZ", &tm_info); |
| 372 | |
| 373 | // for unit tests' convenience |
| 374 | if (!headers->Get(X_AMZ_DATE)) { |
| 375 | headers->Add(X_AMZ_DATE, timestamp_str); |
| 376 | } |
| 377 | memcpy(date_str, headers->Get(X_AMZ_DATE), DATE_STR_LEN - 1); |
| 378 | |
| 379 | stringstream canonical_str; |
| 380 | |
| 381 | canonical_str << method << "\n" |
| 382 | << path << "\n" |
| 383 | << query << "\nhost:" << headers->Get(HOST) |
| 384 | << "\nx-amz-content-sha256:" << headers->Get(X_AMZ_CONTENT_SHA256) |
| 385 | << "\nx-amz-date:" << headers->Get(X_AMZ_DATE); |
| 386 | |
| 387 | string signed_headers; |
| 388 | if (headers->Get(X_AMZ_SERVER_SIDE_ENCRYPTION) != NULL) { |
| 389 | canonical_str << "\nx-amz-server-side-encryption:" |
| 390 | << headers->Get(X_AMZ_SERVER_SIDE_ENCRYPTION) << "\n\n" |
| 391 | << "host;x-amz-content-sha256;x-amz-date;x-amz-server-side-encryption\n" |
| 392 | << headers->Get(X_AMZ_CONTENT_SHA256); |
| 393 | |
| 394 | signed_headers = "host;x-amz-content-sha256;x-amz-date;x-amz-server-side-encryption"; |
| 395 | } else { |
| 396 | canonical_str << "\n\n" |
| 397 | << "host;x-amz-content-sha256;x-amz-date\n" |
| 398 | << headers->Get(X_AMZ_CONTENT_SHA256); |
| 399 | |
| 400 | signed_headers = "host;x-amz-content-sha256;x-amz-date"; |
| 401 | } |
| 402 | |
| 403 | sha256_hex(canonical_str.str().c_str(), canonical_hex); |
| 404 | |
| 405 | // http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region |
| 406 | string region = origRegion; |
| 407 | FindAndReplace(region, "external-1", "us-east-1"); |
| 408 | |
| 409 | stringstream string2sign_str; |
| 410 | string2sign_str << "AWS4-HMAC-SHA256\n" |
| 411 | << headers->Get(X_AMZ_DATE) << "\n" |