Amazon Web Services
General Reference (Version 1.0)
« PreviousNext »
Did this page help you?  Yes | No |  Tell us about it...

Signature Version 2 Signing Process

You can use Signature Version 2 to sign Amazon Web Services Query API requests. The following services currently support Signature Version 2.

AWS Products that support Signature Version 2

Auto Scaling

Auto Scaling API Reference

CloudWatch

Amazon CloudWatch API Reference

AWS CloudFormation

AWS CloudFormation API Reference

Amazon Elastic Compute Cloud

Amazon Elastic Compute Cloud API Reference

Elastic Load Balancing

Elastic Load Balancing API Reference

Amazon ElastiCache

Amazon ElastiCache API Reference

AWS Elastic Beanstalk

API Reference Guide

Amazon Elastic MapReduce

Amazon Elastic MapReduce API Reference

AWS Identity and Access Management

IAM API Reference

AWS Import/Export

AWS Import/Export API Reference

Amazon Relational Database Service

Amazon Relational Database Service API Reference

Amazon Simple Notification Service

Amazon Simple Notification Service API Reference

Amazon SimpleDB

Amazon SimpleDB API Reference

Amazon SQS

Amazon Simple Queue Service API Reference


Components of a Query Request for AWS Signature Version 2

A web service requires that each HTTP or HTTPS Query request formatted for Signature Version 2 contain the following:

  • Endpoint—Also known as the host part of an HTTP request. This is the DNS name of the computer to which you send the Query request. This is different for each AWS Region. For the complete list of endpoints supported by a web service go to Regions and Endpoints in the Amazon Web Services General Reference.

    The endpoint, elasticmapreduce.amazonaws.com, shown in the example below, is the default endpoint and maps to the Region us-east-1.

  • Action—Specifies the action that you want a web service to perform.

    This value determines the parameters that are used in the request. For descriptions of all actions and their parameters, see the web services API documentation.

    The action in the example below is DescribeJobFlows, which causes a web service to return details about one or more job flows.

  • Required and optional parameters—Each action in a web service has a set of required and optional parameters that define the API call. For a list of parameters that must be included in every a web service action, see Common Request Parameters. For details about the specific parameters for a given action, see its entry in the web service API documentation.

  • AccessKeyId—A value distributed by AWS when you sign up for an AWS Account.

  • Timestamp—This is the time at which you make the request. Including this in the Query request helps prevent third parties from intercepting your request and re-submitting to a web service.

  • SignatureVersion—The version of the AWS signature protocol you're using.

  • SignatureMethod—The hash-based protocol you are using to calculate the signature. This can be either HMAC-SHA1 or HMAC-SHA256 for version 2 AWS signatures.

  • Signature—This is a calculated value that ensures the signature is valid and has not been tampered with in transit.

The following is an example Amazon EMR Query request formulated as an HTTPS GET request. (Note that in the actual Query request, there would be no spaces or newline characters. The request would appear as a continuous line of text. The version below has been formatted for human readability.)

https://elasticmapreduce.amazonaws.com?
Action=DescribeJobFlows&
JobFlowIds.member.1=JobFlowID&
AWSAccessKeyId=AccessKeyID&
Timestamp=2009-01-28T21%3A49%3A59.000Z&
SignatureVersion=2&
SignatureMethod=HmacSHA256&
Signature=calculated value
		

Note

Be sure to URI encode the GET request. For example, blank spaces in your HTTP GET request should be encoded as %20. Although an unencoded space is normally allowed by the HTTP protocol specification, the use of unencoded characters creates an invalid signature in your Query request. Do not encode spaces as a plus sign (+) as this will cause errors.

How to Generate an AWS Version 2 Signature for a Query Request

Web service requests are sent across the Internet and thus are vulnerable to tampering. To check that the request has not been altered, AWS calculates the signature to determine if any of the parameters or parameter values were changed en route. AWS requires a signature as part of every request.

The following topics describe the steps needed to calculate a signature using the AWS signature version 2.

Format the Query Request

Before you can sign the Query request, you must put the request into a completely unambiguous format. This is needed because there are different—and yet correct—ways to format a Query request, but the different variations would result in different HMAC signatures. Putting the request into an unambiguous, canonical, format before signing it ensures that your application and a web service will calculate the same signature for a given request.

The unambiguous string to sign is built up by concatenating the Query request components together as follows. As an example, let's generate the string to sign for the following call to the DescribeJobFlows API of Amazon EMR.

https://elasticmapreduce.amazonaws.com?Action=DescribeJobFlows
&Version=2009-03-31
&AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE
&SignatureVersion=2
&SignatureMethod=HmacSHA256
&Timestamp=2011-10-03T15%3A19%3A30
			

Note

We refer to the last four parameters in the preceding request (AWSAccessKeyID through Timestamp) as the authentication parameters. They're required in every request, and AWS uses them to identify who is sending the request and whether to grant the requested access. In some example Query requests we present in AWS documentation, we omit the authentication parameters to make it easier to focus on the ones relevant to the particular operation. We replace them with the following literal string to remind you that a real request includes the parameters: AUTHPARAMS.

To create the string to sign (Signature Version 2)

  1. Start with the request method (either GET or POST), followed by a newline character. (In the following, for human readability, the newline character is represented as \n.)

    GET\n					
    				
  2. Add the HTTP host header in lowercase, followed by a newline character. The port information is omitted if it is the standard port for the protocol (port 80 for HTTP and port 443 for HTTPS), but included if it is a non-standard port.

    elasticmapreduce.amazonaws.com\n
    				
  3. Add the URL-encoded version of each path segment of the URI (everything between the HTTP host header to the question mark character [?] that begins the query string parameters) followed by a newline character. Don't encode the forward slash (/) that delimits each path segment. If the absolute path is empty, use a forward slash (/).

    /\n
    				
  4. Add the query string components (the name-value pairs, not including the initial question mark (?) as UTF-8 characters which are URL encoded per RFC 3986 (hexadecimal characters must be uppercased) and sorted using lexicographic byte ordering. Lexicographic byte ordering is case sensitive.

    Separate parameter names from their values with the equal sign character (=) (ASCII character 61), even if the value is empty. Separate pairs of parameter and values with the ampersand character (&) (ASCII code 38). All reserved characters must be escaped. All unreserved characters must not be escaped. Concatenate the parameters and their values to make one long string with no spaces between them. Spaces within a parameter value, are allowed, but must be URL encoded as %20. In the concatenated string, period characters (.) are not escaped. RFC 3986 considers the period character an unreserved character, and thus it is not URL encoded.

    Note

    RFC 3986 does not specify what happens with ASCII control characters, extended UTF-8 characters, and other characters reserved by RFC 1738. Since any values may be passed into a string value, these other characters should be percent encoded as %XY where X and Y are uppercase hex characters. Extended UTF-8 characters take the form %XY%ZA... (this handles multi-bytes). The space character should be represented as '%20'. Spaces should not be encoded as the plus sign (+) as this will cause as error.

    The following example shows the query string components of a call to the Amazon EMR API DescribeJobFlows, processed as described above.

    AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE&Action=DescribeJobFlows&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2011-10-03T15%3A19%3A30&Version=2009-03-31
    				
  5. The string to sign for the call to DescribeJobFlows takes the following form:

    GET\n
    elasticmapreduce.amazonaws.com\n
    /\n
    AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE&Action=DescribeJobFlows&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2011-10-03T15%3A19%3A30&Version=2009-03-31
    		

Calculating the AWS Signature Version 2

After you've created the canonical string as described in Format the Query Request, you calculate the signature by creating a hash-based message authentication code (HMAC) using either the HMAC-SHA1 or HMAC-SHA256 protocols. The HMAC-SHA256 protocol is preferred.

The resulting signature must be base-64 encoded and then URI encoded.

Add the resulting value to the query request as a signature parameter, as shown below. You can then use the signed request in an HTTP or HTTPS call. A web service will then return the results of the call formatted as a response. For more information about the inputs and outputs of a web service API calls, go to the Amazon Elastic MapReduce Developer Guide.

https://elasticmapreduce.amazonaws.com?AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE&Action=DescribeJobFlows&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2011-10-03T15%3A19%3A30&Version=2009-03-31&Signature=i91nKc4PWAt0JJIdXwz9HxZCJDdiy6cf%2FMj6vPxyYIs%3D
			

The signature from the previous example was calculated by using the following canonical string and secret key as inputs to a keyed hash function:

  • Canonical query string:

    GET\n
    elasticmapreduce.amazonaws.com\n
    /\n
    AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE&Action=DescribeJobFlows&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2011-10-03T15%3A19%3A30&Version=2009-03-31
    		
  • Sample secret key:

    wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

The AWS SDKs offer functions to generate Query request signatures. To see an example using the AWS SDK for Java, go to Using the Java SDK to Sign a Query Request.

Troubleshooting Request Signatures Version 2

This section describes some error codes you might see when you are initially developing code to generate the signature to sign Query requests.

SignatureDoesNotMatch Signing Error in a web service

The following error response is returned when a web service attempts to validate the request signature by recalculating the signature value and generates a value that does not match the signature you appended to the request. This can occur because the request was altered between the time you sent it and the time it reached a web service endpoint (this is the case the signature is designed to detect) or because the signature was calculated improperly. A common cause of the error message below is not properly creating the string to sign, such as forgetting to URL encode characters such as the colon (:) and the forward slash (/) in Amazon S3 bucket names.

			
<ErrorResponse xmlns="http://elasticmapreduce.amazonaws.com/doc/2009-03-31">
  <Error>
    <Type>Sender</Type>
    <Code>SignatureDoesNotMatch</Code>
    <Message>The request signature we calculated does not match the signature you provided. 
    Check your AWS Secret Access Key and signing method. 
    Consult the service documentation for details.</Message>
  </Error>
  <RequestId>7589637b-e4b0-11e0-95d9-639f87241c66</RequestId>
</ErrorResponse>
		

IncompleteSignature Signing Error in a web service

The following error indicates that signature is missing information or has been improperly formed.

<ErrorResponse xmlns="http://elasticmapreduce.amazonaws.com/doc/2009-03-31">
  <Error>
    <Type>Sender</Type>
    <Code>IncompleteSignature</Code>
    <Message>Request must contain a signature that conforms to AWS standards</Message>
  </Error>
  <RequestId>7146d0dd-e48e-11e0-a276-bd10ea0cbb74</RequestId>
</ErrorResponse>

				

Using the Java SDK to Sign a Query Request

The following example uses the amazon.webservices.common package of the AWS SDK for Java to generate an AWS Signature Version 2 Query request signature. To do so, it creates an RFC 2104-compliant HMAC signature. For more information about HMAC, go to HMAC: Keyed-Hashing for Message Authentication.

Note

Java is used in this case as a sample implementation. You can use the programming language of your choice to implement the HMAC algorithm to sign Query requests.

import java.security.SignatureException;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import com.amazonaws.util.*;

/**
* This class defines common routines for generating
* authentication signatures for AWS Platform requests.
*/
public class Signature {
    private static final String HMAC_SHA256_ALGORITHM = "HmacSHA256";

    /**
     * Computes RFC 2104-compliant HMAC signature.
     * * @param data
     * The signed data.
     * @param key
     * The signing key.
     * @return
     * The Base64-encoded RFC 2104-compliant HMAC signature.
     * @throws
     * java.security.SignatureException when signature generation fails
     */
    public static String calculateRFC2104HMAC(String data, String key)
    throws java.security.SignatureException
    {
        String result;
        try {

            // Get an hmac_sha256 key from the raw key bytes.
            SecretKeySpec signingKey = new SecretKeySpec(key.getBytes("UTF8"), HMAC_SHA256_ALGORITHM);

            // Get an hmac_sha256 Mac instance and initialize with the signing key.
            Mac mac = Mac.getInstance(HMAC_SHA256_ALGORITHM);
            mac.init(signingKey);

            // Compute the hmac on input data bytes.
            byte[] rawHmac = mac.doFinal(data.getBytes("UTF8"));

            // Base64-encode the hmac by using the utility in the SDK
            result = BinaryUtils.toBase64(rawHmac);
            

        } catch (Exception e) {
            throw new SignatureException("Failed to generate HMAC : " + e.getMessage());
        }
        return result;
    }
}