Skip to content

Commit 16b2b29

Browse files
authored
Merge pull request #25 from wojtekmach/wm-sign_v4-body-digest
Add `body_digest` option to `sign_v4/10`
2 parents 4d595af + b784c8f commit 16b2b29

File tree

1 file changed

+41
-6
lines changed

1 file changed

+41
-6
lines changed

Diff for: src/aws_signature.erl

+41-6
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ sign_v4(AccessKeyID, SecretAccessKey, Region, Service, DateTime, Method, URL, He
4949
%% this results in each segment being URI-encoded twice, as expected
5050
%% by AWS. Defaults to `true'.
5151
%% </dd>
52+
%% <dt>`body_digest'</dt>
53+
%% <dd>
54+
%% Optional SHA256 digest of the request body. This option can be used to provide
55+
%% a fixed digest value, such as "UNSIGNED-PAYLOAD", when sending requests without
56+
%% signing the body.
57+
%% </dd>
5258
%% </dl>
5359
-spec sign_v4(AccessKeyID, SecretAccessKey, Region, Service, DateTime, Method, URL, Headers, Body, Options) -> FinalHeaders
5460
when AccessKeyID :: binary(),
@@ -61,7 +67,9 @@ sign_v4(AccessKeyID, SecretAccessKey, Region, Service, DateTime, Method, URL, He
6167
Headers :: headers(),
6268
Body :: binary(),
6369
Options :: [Option],
64-
Option :: {uri_encode_path, boolean()},
70+
Option ::
71+
{uri_encode_path, boolean()}
72+
| {body_digest, binary()},
6573
FinalHeaders :: headers().
6674
sign_v4(AccessKeyID, SecretAccessKey, Region, Service, DateTime, Method, URL, Headers, Body, Options)
6775
when is_binary(AccessKeyID),
@@ -80,9 +88,16 @@ sign_v4(AccessKeyID, SecretAccessKey, Region, Service, DateTime, Method, URL, He
8088
LongDate = format_datetime_long(DateTime),
8189
ShortDate = format_datetime_short(DateTime),
8290
FinalHeaders0 = add_date_header(Headers, LongDate),
83-
FinalHeaders = add_content_hash_header(FinalHeaders0, Body),
8491

85-
BodyDigest = aws_signature_utils:sha256_hexdigest(Body),
92+
BodyDigest =
93+
case proplists:get_value(body_digest, Options, undefined) of
94+
undefined ->
95+
aws_signature_utils:sha256_hexdigest(Body);
96+
Digest ->
97+
Digest
98+
end,
99+
100+
FinalHeaders = add_content_hash_header(FinalHeaders0, BodyDigest),
86101
CanonicalRequest = canonical_request(Method, URLMap, FinalHeaders, BodyDigest, URIEncodePath),
87102
HashedCanonicalRequest = aws_signature_utils:sha256_hexdigest(CanonicalRequest),
88103
CredentialScope = credential_scope(ShortDate, Region, Service),
@@ -344,9 +359,8 @@ build_final_url_with_signature(OriginalURL, URLMap, QueryParams, Signature) ->
344359
%% This header is required for S3 when using the v4 signature. Adding it
345360
%% in requests for all services does not cause any issues.
346361
-spec add_content_hash_header(headers(), binary()) -> headers().
347-
add_content_hash_header(Headers, Body) ->
348-
HashedBody = aws_signature_utils:sha256_hexdigest(Body),
349-
[{<<"X-Amz-Content-SHA256">>, HashedBody} | Headers].
362+
add_content_hash_header(Headers, BodyDigest) ->
363+
[{<<"X-Amz-Content-SHA256">>, BodyDigest} | Headers].
350364

351365
%% Generates an AWS4-HMAC-SHA256 authorization signature.
352366
-spec authorization(binary(), binary(), binary(), binary()) -> binary().
@@ -624,6 +638,27 @@ sign_v4_reference_example_4_test() ->
624638

625639
?assertEqual(Actual, Expected).
626640

641+
sign_v4_unsigned_payload_test() ->
642+
AccessKeyID = <<"AKIAIOSFODNN7EXAMPLE">>,
643+
SecretAccessKey = <<"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY">>,
644+
Region = <<"us-east-1">>,
645+
Service = <<"s3">>,
646+
DateTime = {{2013, 5, 24}, {0, 0, 0}},
647+
Method = <<"GET">>,
648+
URL = <<"https://examplebucket.s3.amazonaws.com?max-keys=2&prefix=J">>,
649+
Headers = [{<<"Host">>, <<"examplebucket.s3.amazonaws.com">>}],
650+
Body = <<"foo">>,
651+
652+
Actual = sign_v4(AccessKeyID, SecretAccessKey, Region, Service, DateTime, Method, URL, Headers, Body, [{body_digest, <<"UNSIGNED-PAYLOAD">>}]),
653+
654+
Expected = [
655+
{<<"Authorization">>, <<"AWS4-HMAC-SHA256 Credential=AKIAIOSFODNN7EXAMPLE/20130524/us-east-1/s3/aws4_request,SignedHeaders=host;x-amz-content-sha256;x-amz-date,Signature=b1a076428fa68c2c42202ee5a5718b8207f725e451e2157d6b1c393e01fc2e68">>},
656+
{<<"X-Amz-Content-SHA256">>, <<"UNSIGNED-PAYLOAD">>},
657+
{<<"X-Amz-Date">>, <<"20130524T000000Z">>},
658+
{<<"Host">>, <<"examplebucket.s3.amazonaws.com">>}],
659+
660+
?assertEqual(Actual, Expected).
661+
627662
sign_v4_event_test() ->
628663
SecretAccessKey = <<"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY">>,
629664
Region = <<"us-east-1">>,

0 commit comments

Comments
 (0)