VirtualBox

source: vbox/trunk/src/libs/curl-8.7.1/lib/http_aws_sigv4.c@ 106542

最後變更 在這個檔案從106542是 104083,由 vboxsync 提交於 11 月 前

curl-8.7.1: Applied and adjusted our curl changes to 8.4.0. bugref:10639

  • 屬性 svn:eol-style 設為 native
檔案大小: 23.6 KB
 
1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.haxx.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 * SPDX-License-Identifier: curl
22 *
23 ***************************************************************************/
24
25#include "curl_setup.h"
26
27#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_AWS)
28
29#include "urldata.h"
30#include "strcase.h"
31#include "strdup.h"
32#include "http_aws_sigv4.h"
33#include "curl_sha256.h"
34#include "transfer.h"
35#include "parsedate.h"
36#include "sendf.h"
37#include "escape.h"
38
39#include <time.h>
40
41/* The last 3 #include files should be in this order */
42#include "curl_printf.h"
43#include "curl_memory.h"
44#include "memdebug.h"
45
46#include "slist.h"
47
48#define HMAC_SHA256(k, kl, d, dl, o) \
49 do { \
50 result = Curl_hmacit(Curl_HMAC_SHA256, \
51 (unsigned char *)k, \
52 kl, \
53 (unsigned char *)d, \
54 dl, o); \
55 if(result) { \
56 goto fail; \
57 } \
58 } while(0)
59
60#define TIMESTAMP_SIZE 17
61
62/* hex-encoded with trailing null */
63#define SHA256_HEX_LENGTH (2 * SHA256_DIGEST_LENGTH + 1)
64
65static void sha256_to_hex(char *dst, unsigned char *sha)
66{
67 Curl_hexencode(sha, SHA256_DIGEST_LENGTH,
68 (unsigned char *)dst, SHA256_HEX_LENGTH);
69}
70
71static char *find_date_hdr(struct Curl_easy *data, const char *sig_hdr)
72{
73 char *tmp = Curl_checkheaders(data, sig_hdr, strlen(sig_hdr));
74
75 if(tmp)
76 return tmp;
77 return Curl_checkheaders(data, STRCONST("Date"));
78}
79
80/* remove whitespace, and lowercase all headers */
81static void trim_headers(struct curl_slist *head)
82{
83 struct curl_slist *l;
84 for(l = head; l; l = l->next) {
85 char *value; /* to read from */
86 char *store;
87 size_t colon = strcspn(l->data, ":");
88 Curl_strntolower(l->data, l->data, colon);
89
90 value = &l->data[colon];
91 if(!*value)
92 continue;
93 ++value;
94 store = value;
95
96 /* skip leading whitespace */
97 while(*value && ISBLANK(*value))
98 value++;
99
100 while(*value) {
101 int space = 0;
102 while(*value && ISBLANK(*value)) {
103 value++;
104 space++;
105 }
106 if(space) {
107 /* replace any number of consecutive whitespace with a single space,
108 unless at the end of the string, then nothing */
109 if(*value)
110 *store++ = ' ';
111 }
112 else
113 *store++ = *value++;
114 }
115 *store = 0; /* null terminate */
116 }
117}
118
119/* maximum length for the aws sivg4 parts */
120#define MAX_SIGV4_LEN 64
121#define MAX_SIGV4_LEN_TXT "64"
122
123#define DATE_HDR_KEY_LEN (MAX_SIGV4_LEN + sizeof("X--Date"))
124
125#define MAX_HOST_LEN 255
126/* FQDN + host: */
127#define FULL_HOST_LEN (MAX_HOST_LEN + sizeof("host:"))
128
129/* string been x-PROVIDER-date:TIMESTAMP, I need +1 for ':' */
130#define DATE_FULL_HDR_LEN (DATE_HDR_KEY_LEN + TIMESTAMP_SIZE + 1)
131
132/* timestamp should point to a buffer of at last TIMESTAMP_SIZE bytes */
133static CURLcode make_headers(struct Curl_easy *data,
134 const char *hostname,
135 char *timestamp,
136 char *provider1,
137 char **date_header,
138 char *content_sha256_header,
139 struct dynbuf *canonical_headers,
140 struct dynbuf *signed_headers)
141{
142 char date_hdr_key[DATE_HDR_KEY_LEN];
143 char date_full_hdr[DATE_FULL_HDR_LEN];
144 struct curl_slist *head = NULL;
145 struct curl_slist *tmp_head = NULL;
146 CURLcode ret = CURLE_OUT_OF_MEMORY;
147 struct curl_slist *l;
148 int again = 1;
149
150 /* provider1 mid */
151 Curl_strntolower(provider1, provider1, strlen(provider1));
152 provider1[0] = Curl_raw_toupper(provider1[0]);
153
154 msnprintf(date_hdr_key, DATE_HDR_KEY_LEN, "X-%s-Date", provider1);
155
156 /* provider1 lowercase */
157 Curl_strntolower(provider1, provider1, 1); /* first byte only */
158 msnprintf(date_full_hdr, DATE_FULL_HDR_LEN,
159 "x-%s-date:%s", provider1, timestamp);
160
161 if(Curl_checkheaders(data, STRCONST("Host"))) {
162 head = NULL;
163 }
164 else {
165 char full_host[FULL_HOST_LEN + 1];
166
167 if(data->state.aptr.host) {
168 size_t pos;
169
170 if(strlen(data->state.aptr.host) > FULL_HOST_LEN) {
171 ret = CURLE_URL_MALFORMAT;
172 goto fail;
173 }
174 strcpy(full_host, data->state.aptr.host);
175 /* remove /r/n as the separator for canonical request must be '\n' */
176 pos = strcspn(full_host, "\n\r");
177 full_host[pos] = 0;
178 }
179 else {
180 if(strlen(hostname) > MAX_HOST_LEN) {
181 ret = CURLE_URL_MALFORMAT;
182 goto fail;
183 }
184 msnprintf(full_host, FULL_HOST_LEN, "host:%s", hostname);
185 }
186
187 head = curl_slist_append(NULL, full_host);
188 if(!head)
189 goto fail;
190 }
191
192
193 if(*content_sha256_header) {
194 tmp_head = curl_slist_append(head, content_sha256_header);
195 if(!tmp_head)
196 goto fail;
197 head = tmp_head;
198 }
199
200 /* copy user headers to our header list. the logic is based on how http.c
201 handles user headers.
202
203 user headers in format 'name:' with no value are used to signal that an
204 internal header of that name should be removed. those user headers are not
205 added to this list.
206
207 user headers in format 'name;' with no value are used to signal that a
208 header of that name with no value should be sent. those user headers are
209 added to this list but in the format that they will be sent, ie the
210 semi-colon is changed to a colon for format 'name:'.
211
212 user headers with a value of whitespace only, or without a colon or
213 semi-colon, are not added to this list.
214 */
215 for(l = data->set.headers; l; l = l->next) {
216 char *dupdata, *ptr;
217 char *sep = strchr(l->data, ':');
218 if(!sep)
219 sep = strchr(l->data, ';');
220 if(!sep || (*sep == ':' && !*(sep + 1)))
221 continue;
222 for(ptr = sep + 1; ISSPACE(*ptr); ++ptr)
223 ;
224 if(!*ptr && ptr != sep + 1) /* a value of whitespace only */
225 continue;
226 dupdata = strdup(l->data);
227 if(!dupdata)
228 goto fail;
229 dupdata[sep - l->data] = ':';
230 tmp_head = Curl_slist_append_nodup(head, dupdata);
231 if(!tmp_head) {
232 free(dupdata);
233 goto fail;
234 }
235 head = tmp_head;
236 }
237
238 trim_headers(head);
239
240 *date_header = find_date_hdr(data, date_hdr_key);
241 if(!*date_header) {
242 tmp_head = curl_slist_append(head, date_full_hdr);
243 if(!tmp_head)
244 goto fail;
245 head = tmp_head;
246 *date_header = curl_maprintf("%s: %s\r\n", date_hdr_key, timestamp);
247 }
248 else {
249 char *value;
250 char *endp;
251 value = strchr(*date_header, ':');
252 if(!value) {
253 *date_header = NULL;
254 goto fail;
255 }
256 ++value;
257 while(ISBLANK(*value))
258 ++value;
259 endp = value;
260 while(*endp && ISALNUM(*endp))
261 ++endp;
262 /* 16 bytes => "19700101T000000Z" */
263 if((endp - value) == TIMESTAMP_SIZE - 1) {
264 memcpy(timestamp, value, TIMESTAMP_SIZE - 1);
265 timestamp[TIMESTAMP_SIZE - 1] = 0;
266 }
267 else
268 /* bad timestamp length */
269 timestamp[0] = 0;
270 *date_header = NULL;
271 }
272
273 /* alpha-sort in a case sensitive manner */
274 do {
275 again = 0;
276 for(l = head; l; l = l->next) {
277 struct curl_slist *next = l->next;
278
279 if(next && strcmp(l->data, next->data) > 0) {
280 char *tmp = l->data;
281
282 l->data = next->data;
283 next->data = tmp;
284 again = 1;
285 }
286 }
287 } while(again);
288
289 for(l = head; l; l = l->next) {
290 char *tmp;
291
292 if(Curl_dyn_add(canonical_headers, l->data))
293 goto fail;
294 if(Curl_dyn_add(canonical_headers, "\n"))
295 goto fail;
296
297 tmp = strchr(l->data, ':');
298 if(tmp)
299 *tmp = 0;
300
301 if(l != head) {
302 if(Curl_dyn_add(signed_headers, ";"))
303 goto fail;
304 }
305 if(Curl_dyn_add(signed_headers, l->data))
306 goto fail;
307 }
308
309 ret = CURLE_OK;
310fail:
311 curl_slist_free_all(head);
312
313 return ret;
314}
315
316#define CONTENT_SHA256_KEY_LEN (MAX_SIGV4_LEN + sizeof("X--Content-Sha256"))
317/* add 2 for ": " between header name and value */
318#define CONTENT_SHA256_HDR_LEN (CONTENT_SHA256_KEY_LEN + 2 + \
319 SHA256_HEX_LENGTH)
320
321/* try to parse a payload hash from the content-sha256 header */
322static char *parse_content_sha_hdr(struct Curl_easy *data,
323 const char *provider1,
324 size_t *value_len)
325{
326 char key[CONTENT_SHA256_KEY_LEN];
327 size_t key_len;
328 char *value;
329 size_t len;
330
331 key_len = msnprintf(key, sizeof(key), "x-%s-content-sha256", provider1);
332
333 value = Curl_checkheaders(data, key, key_len);
334 if(!value)
335 return NULL;
336
337 value = strchr(value, ':');
338 if(!value)
339 return NULL;
340 ++value;
341
342 while(*value && ISBLANK(*value))
343 ++value;
344
345 len = strlen(value);
346 while(len > 0 && ISBLANK(value[len-1]))
347 --len;
348
349 *value_len = len;
350 return value;
351}
352
353static CURLcode calc_payload_hash(struct Curl_easy *data,
354 unsigned char *sha_hash, char *sha_hex)
355{
356 const char *post_data = data->set.postfields;
357 size_t post_data_len = 0;
358 CURLcode result;
359
360 if(post_data) {
361 if(data->set.postfieldsize < 0)
362 post_data_len = strlen(post_data);
363 else
364 post_data_len = (size_t)data->set.postfieldsize;
365 }
366 result = Curl_sha256it(sha_hash, (const unsigned char *) post_data,
367 post_data_len);
368 if(!result)
369 sha256_to_hex(sha_hex, sha_hash);
370 return result;
371}
372
373#define S3_UNSIGNED_PAYLOAD "UNSIGNED-PAYLOAD"
374
375static CURLcode calc_s3_payload_hash(struct Curl_easy *data,
376 Curl_HttpReq httpreq, char *provider1,
377 unsigned char *sha_hash,
378 char *sha_hex, char *header)
379{
380 bool empty_method = (httpreq == HTTPREQ_GET || httpreq == HTTPREQ_HEAD);
381 /* The request method or filesize indicate no request payload */
382 bool empty_payload = (empty_method || data->set.filesize == 0);
383 /* The POST payload is in memory */
384 bool post_payload = (httpreq == HTTPREQ_POST && data->set.postfields);
385 CURLcode ret = CURLE_OUT_OF_MEMORY;
386
387 if(empty_payload || post_payload) {
388 /* Calculate a real hash when we know the request payload */
389 ret = calc_payload_hash(data, sha_hash, sha_hex);
390 if(ret)
391 goto fail;
392 }
393 else {
394 /* Fall back to s3's UNSIGNED-PAYLOAD */
395 size_t len = sizeof(S3_UNSIGNED_PAYLOAD) - 1;
396 DEBUGASSERT(len < SHA256_HEX_LENGTH); /* 16 < 65 */
397 memcpy(sha_hex, S3_UNSIGNED_PAYLOAD, len);
398 sha_hex[len] = 0;
399 }
400
401 /* format the required content-sha256 header */
402 msnprintf(header, CONTENT_SHA256_HDR_LEN,
403 "x-%s-content-sha256: %s", provider1, sha_hex);
404
405 ret = CURLE_OK;
406fail:
407 return ret;
408}
409
410struct pair {
411 const char *p;
412 size_t len;
413};
414
415static int compare_func(const void *a, const void *b)
416{
417 const struct pair *aa = a;
418 const struct pair *bb = b;
419 /* If one element is empty, the other is always sorted higher */
420 if(aa->len == 0)
421 return -1;
422 if(bb->len == 0)
423 return 1;
424 return strncmp(aa->p, bb->p, aa->len < bb->len ? aa->len : bb->len);
425}
426
427#define MAX_QUERYPAIRS 64
428
429static CURLcode canon_query(struct Curl_easy *data,
430 const char *query, struct dynbuf *dq)
431{
432 CURLcode result = CURLE_OK;
433 int entry = 0;
434 int i;
435 const char *p = query;
436 struct pair array[MAX_QUERYPAIRS];
437 struct pair *ap = &array[0];
438 if(!query)
439 return result;
440
441 /* sort the name=value pairs first */
442 do {
443 char *amp;
444 entry++;
445 ap->p = p;
446 amp = strchr(p, '&');
447 if(amp)
448 ap->len = amp - p; /* excluding the ampersand */
449 else {
450 ap->len = strlen(p);
451 break;
452 }
453 ap++;
454 p = amp + 1;
455 } while(entry < MAX_QUERYPAIRS);
456 if(entry == MAX_QUERYPAIRS) {
457 /* too many query pairs for us */
458 failf(data, "aws-sigv4: too many query pairs in URL");
459 return CURLE_URL_MALFORMAT;
460 }
461
462 qsort(&array[0], entry, sizeof(struct pair), compare_func);
463
464 ap = &array[0];
465 for(i = 0; !result && (i < entry); i++, ap++) {
466 size_t len;
467 const char *q = ap->p;
468 bool found_equals = false;
469 if(!ap->len)
470 continue;
471 for(len = ap->len; len && !result; q++, len--) {
472 if(ISALNUM(*q))
473 result = Curl_dyn_addn(dq, q, 1);
474 else {
475 switch(*q) {
476 case '-':
477 case '.':
478 case '_':
479 case '~':
480 /* allowed as-is */
481 result = Curl_dyn_addn(dq, q, 1);
482 break;
483 case '=':
484 /* allowed as-is */
485 result = Curl_dyn_addn(dq, q, 1);
486 found_equals = true;
487 break;
488 case '%':
489 /* uppercase the following if hexadecimal */
490 if(ISXDIGIT(q[1]) && ISXDIGIT(q[2])) {
491 char tmp[3]="%";
492 tmp[1] = Curl_raw_toupper(q[1]);
493 tmp[2] = Curl_raw_toupper(q[2]);
494 result = Curl_dyn_addn(dq, tmp, 3);
495 q += 2;
496 len -= 2;
497 }
498 else
499 /* '%' without a following two-digit hex, encode it */
500 result = Curl_dyn_addn(dq, "%25", 3);
501 break;
502 default: {
503 /* URL encode */
504 const char hex[] = "0123456789ABCDEF";
505 char out[3]={'%'};
506 out[1] = hex[((unsigned char)*q)>>4];
507 out[2] = hex[*q & 0xf];
508 result = Curl_dyn_addn(dq, out, 3);
509 break;
510 }
511 }
512 }
513 }
514 if(!result && !found_equals) {
515 /* queries without value still need an equals */
516 result = Curl_dyn_addn(dq, "=", 1);
517 }
518 if(!result && i < entry - 1) {
519 /* insert ampersands between query pairs */
520 result = Curl_dyn_addn(dq, "&", 1);
521 }
522 }
523 return result;
524}
525
526
527CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
528{
529 CURLcode result = CURLE_OUT_OF_MEMORY;
530 struct connectdata *conn = data->conn;
531 size_t len;
532 const char *arg;
533 char provider0[MAX_SIGV4_LEN + 1]="";
534 char provider1[MAX_SIGV4_LEN + 1]="";
535 char region[MAX_SIGV4_LEN + 1]="";
536 char service[MAX_SIGV4_LEN + 1]="";
537 bool sign_as_s3 = false;
538 const char *hostname = conn->host.name;
539 time_t clock;
540 struct tm tm;
541 char timestamp[TIMESTAMP_SIZE];
542 char date[9];
543 struct dynbuf canonical_headers;
544 struct dynbuf signed_headers;
545 struct dynbuf canonical_query;
546 char *date_header = NULL;
547 Curl_HttpReq httpreq;
548 const char *method = NULL;
549 char *payload_hash = NULL;
550 size_t payload_hash_len = 0;
551 unsigned char sha_hash[SHA256_DIGEST_LENGTH];
552 char sha_hex[SHA256_HEX_LENGTH];
553 char content_sha256_hdr[CONTENT_SHA256_HDR_LEN + 2] = ""; /* add \r\n */
554 char *canonical_request = NULL;
555 char *request_type = NULL;
556 char *credential_scope = NULL;
557 char *str_to_sign = NULL;
558 const char *user = data->state.aptr.user ? data->state.aptr.user : "";
559 char *secret = NULL;
560 unsigned char sign0[SHA256_DIGEST_LENGTH] = {0};
561 unsigned char sign1[SHA256_DIGEST_LENGTH] = {0};
562 char *auth_headers = NULL;
563
564 DEBUGASSERT(!proxy);
565 (void)proxy;
566
567 if(Curl_checkheaders(data, STRCONST("Authorization"))) {
568 /* Authorization already present, Bailing out */
569 return CURLE_OK;
570 }
571
572 /* we init those buffers here, so goto fail will free initialized dynbuf */
573 Curl_dyn_init(&canonical_headers, CURL_MAX_HTTP_HEADER);
574 Curl_dyn_init(&canonical_query, CURL_MAX_HTTP_HEADER);
575 Curl_dyn_init(&signed_headers, CURL_MAX_HTTP_HEADER);
576
577 /*
578 * Parameters parsing
579 * Google and Outscale use the same OSC or GOOG,
580 * but Amazon uses AWS and AMZ for header arguments.
581 * AWS is the default because most of non-amazon providers
582 * are still using aws:amz as a prefix.
583 */
584 arg = data->set.str[STRING_AWS_SIGV4] ?
585 data->set.str[STRING_AWS_SIGV4] : "aws:amz";
586
587 /* provider1[:provider2[:region[:service]]]
588
589 No string can be longer than N bytes of non-whitespace
590 */
591 (void)sscanf(arg, "%" MAX_SIGV4_LEN_TXT "[^:]"
592 ":%" MAX_SIGV4_LEN_TXT "[^:]"
593 ":%" MAX_SIGV4_LEN_TXT "[^:]"
594 ":%" MAX_SIGV4_LEN_TXT "s",
595 provider0, provider1, region, service);
596 if(!provider0[0]) {
597 failf(data, "first aws-sigv4 provider can't be empty");
598 result = CURLE_BAD_FUNCTION_ARGUMENT;
599 goto fail;
600 }
601 else if(!provider1[0])
602 strcpy(provider1, provider0);
603
604 if(!service[0]) {
605 char *hostdot = strchr(hostname, '.');
606 if(!hostdot) {
607 failf(data, "aws-sigv4: service missing in parameters and hostname");
608 result = CURLE_URL_MALFORMAT;
609 goto fail;
610 }
611 len = hostdot - hostname;
612 if(len > MAX_SIGV4_LEN) {
613 failf(data, "aws-sigv4: service too long in hostname");
614 result = CURLE_URL_MALFORMAT;
615 goto fail;
616 }
617 memcpy(service, hostname, len);
618 service[len] = '\0';
619
620 infof(data, "aws_sigv4: picked service %s from host", service);
621
622 if(!region[0]) {
623 const char *reg = hostdot + 1;
624 const char *hostreg = strchr(reg, '.');
625 if(!hostreg) {
626 failf(data, "aws-sigv4: region missing in parameters and hostname");
627 result = CURLE_URL_MALFORMAT;
628 goto fail;
629 }
630 len = hostreg - reg;
631 if(len > MAX_SIGV4_LEN) {
632 failf(data, "aws-sigv4: region too long in hostname");
633 result = CURLE_URL_MALFORMAT;
634 goto fail;
635 }
636 memcpy(region, reg, len);
637 region[len] = '\0';
638 infof(data, "aws_sigv4: picked region %s from host", region);
639 }
640 }
641
642 Curl_http_method(data, conn, &method, &httpreq);
643
644 /* AWS S3 requires a x-amz-content-sha256 header, and supports special
645 * values like UNSIGNED-PAYLOAD */
646 sign_as_s3 = (strcasecompare(provider0, "aws") &&
647 strcasecompare(service, "s3"));
648
649 payload_hash = parse_content_sha_hdr(data, provider1, &payload_hash_len);
650
651 if(!payload_hash) {
652 if(sign_as_s3)
653 result = calc_s3_payload_hash(data, httpreq, provider1, sha_hash,
654 sha_hex, content_sha256_hdr);
655 else
656 result = calc_payload_hash(data, sha_hash, sha_hex);
657 if(result)
658 goto fail;
659
660 payload_hash = sha_hex;
661 /* may be shorter than SHA256_HEX_LENGTH, like S3_UNSIGNED_PAYLOAD */
662 payload_hash_len = strlen(sha_hex);
663 }
664
665#ifdef DEBUGBUILD
666 {
667 char *force_timestamp = getenv("CURL_FORCETIME");
668 if(force_timestamp)
669 clock = 0;
670 else
671 time(&clock);
672 }
673#else
674 time(&clock);
675#endif
676 result = Curl_gmtime(clock, &tm);
677 if(result) {
678 goto fail;
679 }
680 if(!strftime(timestamp, sizeof(timestamp), "%Y%m%dT%H%M%SZ", &tm)) {
681 result = CURLE_OUT_OF_MEMORY;
682 goto fail;
683 }
684
685 result = make_headers(data, hostname, timestamp, provider1,
686 &date_header, content_sha256_hdr,
687 &canonical_headers, &signed_headers);
688 if(result)
689 goto fail;
690
691 if(*content_sha256_hdr) {
692 /* make_headers() needed this without the \r\n for canonicalization */
693 size_t hdrlen = strlen(content_sha256_hdr);
694 DEBUGASSERT(hdrlen + 3 < sizeof(content_sha256_hdr));
695 memcpy(content_sha256_hdr + hdrlen, "\r\n", 3);
696 }
697
698 memcpy(date, timestamp, sizeof(date));
699 date[sizeof(date) - 1] = 0;
700
701 result = canon_query(data, data->state.up.query, &canonical_query);
702 if(result)
703 goto fail;
704 result = CURLE_OUT_OF_MEMORY;
705
706 canonical_request =
707 curl_maprintf("%s\n" /* HTTPRequestMethod */
708 "%s\n" /* CanonicalURI */
709 "%s\n" /* CanonicalQueryString */
710 "%s\n" /* CanonicalHeaders */
711 "%s\n" /* SignedHeaders */
712 "%.*s", /* HashedRequestPayload in hex */
713 method,
714 data->state.up.path,
715 Curl_dyn_ptr(&canonical_query) ?
716 Curl_dyn_ptr(&canonical_query) : "",
717 Curl_dyn_ptr(&canonical_headers),
718 Curl_dyn_ptr(&signed_headers),
719 (int)payload_hash_len, payload_hash);
720 if(!canonical_request)
721 goto fail;
722
723 DEBUGF(infof(data, "Canonical request: %s", canonical_request));
724
725 /* provider 0 lowercase */
726 Curl_strntolower(provider0, provider0, strlen(provider0));
727 request_type = curl_maprintf("%s4_request", provider0);
728 if(!request_type)
729 goto fail;
730
731 credential_scope = curl_maprintf("%s/%s/%s/%s",
732 date, region, service, request_type);
733 if(!credential_scope)
734 goto fail;
735
736 if(Curl_sha256it(sha_hash, (unsigned char *) canonical_request,
737 strlen(canonical_request)))
738 goto fail;
739
740 sha256_to_hex(sha_hex, sha_hash);
741
742 /* provider 0 uppercase */
743 Curl_strntoupper(provider0, provider0, strlen(provider0));
744
745 /*
746 * Google allows using RSA key instead of HMAC, so this code might change
747 * in the future. For now we only support HMAC.
748 */
749 str_to_sign = curl_maprintf("%s4-HMAC-SHA256\n" /* Algorithm */
750 "%s\n" /* RequestDateTime */
751 "%s\n" /* CredentialScope */
752 "%s", /* HashedCanonicalRequest in hex */
753 provider0,
754 timestamp,
755 credential_scope,
756 sha_hex);
757 if(!str_to_sign) {
758 goto fail;
759 }
760
761 /* provider 0 uppercase */
762 secret = curl_maprintf("%s4%s", provider0,
763 data->state.aptr.passwd ?
764 data->state.aptr.passwd : "");
765 if(!secret)
766 goto fail;
767
768 HMAC_SHA256(secret, strlen(secret), date, strlen(date), sign0);
769 HMAC_SHA256(sign0, sizeof(sign0), region, strlen(region), sign1);
770 HMAC_SHA256(sign1, sizeof(sign1), service, strlen(service), sign0);
771 HMAC_SHA256(sign0, sizeof(sign0), request_type, strlen(request_type), sign1);
772 HMAC_SHA256(sign1, sizeof(sign1), str_to_sign, strlen(str_to_sign), sign0);
773
774 sha256_to_hex(sha_hex, sign0);
775
776 /* provider 0 uppercase */
777 auth_headers = curl_maprintf("Authorization: %s4-HMAC-SHA256 "
778 "Credential=%s/%s, "
779 "SignedHeaders=%s, "
780 "Signature=%s\r\n"
781 /*
782 * date_header is added here, only if it wasn't
783 * user-specified (using CURLOPT_HTTPHEADER).
784 * date_header includes \r\n
785 */
786 "%s"
787 "%s", /* optional sha256 header includes \r\n */
788 provider0,
789 user,
790 credential_scope,
791 Curl_dyn_ptr(&signed_headers),
792 sha_hex,
793 date_header ? date_header : "",
794 content_sha256_hdr);
795 if(!auth_headers) {
796 goto fail;
797 }
798
799 Curl_safefree(data->state.aptr.userpwd);
800 data->state.aptr.userpwd = auth_headers;
801 data->state.authhost.done = TRUE;
802 result = CURLE_OK;
803
804fail:
805 Curl_dyn_free(&canonical_query);
806 Curl_dyn_free(&canonical_headers);
807 Curl_dyn_free(&signed_headers);
808 free(canonical_request);
809 free(request_type);
810 free(credential_scope);
811 free(str_to_sign);
812 free(secret);
813 free(date_header);
814 return result;
815}
816
817#endif /* !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_AWS) */
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette