ravenspoint
ravenspoint

Reputation: 20492

What has changed with the AWS Signature Version 4

A few years ago I wrote some C++ code to sign on to AWS ( Amazon Web Service ). It worked fine at the time. I haven't used it for a while, and now it does not work.

"com.amazon.coral.service#InvalidSignatureException"

I think I have narrowed it down to the hashing function. This unit test fails:

TEST( aws_hash )
{
    // unit test the hashing function used for AWS authentication
    // sample input and expected results from Signature Version 4 Test Suite
    // https://docs.aws.amazon.com/general/latest/gr/signature-v4-test-suite.html
    // specifically the get-vanilla-query
    // note that this is step 1 of the signing process an does not involve the secret key.

    // input string
    std::string query =
    "GET / HTTP/1.1\n"
    "Host:example.amazonaws.com\n"
    "X-Amz-Date:20150830T123600Z";

    // calculate hash of input
    SHA256 sha256;
    std::string thehash = sha256( query );

    // expected hash value from test suite
    // ( last line of get-vanilla-query.creq )
    std::string expected = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";

    // did we get the expected hash?
    CHECK_EQUAL( expected, thehash );
}

Outputs:

C:\unit_test\main.cpp(47): error: Failure in aws_hash:
Expected e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 
but was 509955df496ae2f4fdc25af95ccf5406099e4a2556523b7ed80f4fab21ac1869

The code for the hashing function I am using can be seen at https://github.com/JamesBremner/sha256

Is there some change I should be aware of?

Is there something wrong with my unit test?

Upvotes: 0

Views: 622

Answers (1)

Michael - sqlbot
Michael - sqlbot

Reputation: 179154

e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

This is the SHA-256 hash of an empty string (see https://crypto.stackexchange.com/a/26135/25027).

Signature V4 is entirely different from Signature V2. You hash the body first (the HTTP request body, which does not include the headers), using the value shown when there is no request body.

There is no part of the actual input to Signature V4 that coresponds to your // input string.

That is an example of the HTTP request that you will be sending, but it is not something that goes directly into the signing algorithm.

The canonical request structure is this:

CanonicalRequest =
  HTTPRequestMethod + '\n' +
  CanonicalURI + '\n' +
  CanonicalQueryString + '\n' +
  CanonicalHeaders + '\n' +
  SignedHeaders + '\n' +
  HexEncode(Hash(RequestPayload))

Here, in HexEncode(Hash(RequestPayload)), RequestPayload refers only to the request body -- not the headers. When there's no body, empty string is used, and the hash of an empty string is the value shown.

Upvotes: 1

Related Questions