Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Canonicalize and Generate A String to Sign #5

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
392 changes: 392 additions & 0 deletions source/include/sigv4.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,392 @@
/*
* SigV4 Utility Library v1.0.0
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

/**
* @file sigv4.h
* @brief Interface for the SigV4 Client Utility Library.
*/

#ifndef SIGV4_H_
#define SIGV4_H_

/* Standard includes. */
#include <stdint.h>
#include <stddef.h>

/* SIGV4_DO_NOT_USE_CUSTOM_CONFIG allows building of the SigV4 library without a
* config file. If a config file is provided, the SIGV4_DO_NOT_USE_CUSTOM_CONFIG
* macro must not be defined.
*/
#ifndef SIGV4_DO_NOT_USE_CUSTOM_CONFIG
#include "sigv4_config.h"
#endif

/* Include config defaults header to get default values of configurations not
* defined in sigv4_config.h file. */
#include "sigv4_config_defaults.h"

/* Convenience macros for library optimization */

/** @addtogroup sigv4_constants
* @{
*/
/**< AWS identifier for this utility's SigV4 signing algorithms. */
#define SIGV4_AWS4_HMAC_SHA256 "AWS4-HMAC-SHA256"

/**< AWS identifier for S3 SigV4 streaming upload. */
#define SIGV4_STREAMING_AWS4_HMAC_SHA256_PAYLOAD "STREAMING-AWS4-HMAC-SHA256-PAYLOAD"

/**< AWS identifiers for Amazon specific HTTP header fields. */
#define SIGV4_HTTP_X_AMZ_DATE_HEADER "x-amz-date"
#define SIGV4_HTTP_X_AMZ_SECURITY_TOKEN_HEADER "x-amz-security-token"
#define SIGV4_HTTP_X_AMZ_CONTENT_SHA256_HEADER "x-amz-content-sha256"
#define SIGV4_HTTP_X_AMZ_STORAGE_CLASS_HEADER "x-amz-storage-class"
Comment on lines +53 to +62
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can these be internal constants instead of exposing in the public API?


/**< Lengths of the security tokens. */
#define SIGV4_ACCESS_KEY_ID_LENGTH 20U
#define SIGV4_SECRET_ACCESS_KEY_LENGTH 40U

/**< Set this to one to statically enable support for canonicalizing the URI,
* headers, and query in this utility.*/
#define SIGV4_USE_CANONICAL_SUPPORT 1
/** @}*/

/**
* @defgroup sigv4_canonical_flags SigV4HttpParameters_t Flags
* @brief Flags for SigV4HttpParameters_t.flags. These flags inform the library
* of parameters already in canonical form.
*
* Flags should be bitwise-ORed with each other to change the behavior of
* #SigV4_GenerateHTTPAuthorization.
*/

/**
* @ingroup sigv4_canonical_flags
* @brief Set this flag to indicate that the HTTP request path input is already
* canonicalized.
*
* This flag is valid only for #SigV4HttpParameters_t.flags.
*/
#define SIGV4_HTTP_PATH_IS_CANONICAL_FLAG 0x1U

/**
* @ingroup sigv4_canonical_flags
* @brief Set this flag to indicate that the HTTP request query input is already
* canonicalized.
*
* This flag is valid only for #SigV4HttpParameters_t.flags.
*/
#define SIGV4_HTTP_QUERY_IS_CANONICAL_FLAG 0x2U

/**
* @ingroup sigv4_canonical_flags
* @brief Set this flag to indicate that the HTTP request headers input is
* already canonicalized.
*
* This flag is valid only for #SigV4HttpParameters_t.flags.
*/
#define SIGV4_HTTP_HEADERS_ARE_CANONICAL_FLAG 0x4U

/**
* @ingroup sigv4_canonical_flags
* @brief Set this flag to indicate that the HTTP request path, query, and
* headers are all already canonicalized.
*
* This flag is valid only for #SigV4HttpParameters_t.flags.
*/
#define SIGV4_HTTP_ALL_ARE_CANONICAL_FLAG 0x8U

/**
* @ingroup sigv4_enum_types
* @brief Return status of the SigV4 Utility Library.
*/
typedef enum SigV4Status
{
/**
* @brief The SigV4 Utility library function completed successfully.
*
* Functions that may return this value:
* - #SigV4_GenerateHTTPAuthorization
* - #SigV4_AwsIotDateToIso8601
*/
SigV4Success,

/**
* @brief The SigV4 Utility library function received an invalid input
* parameter.
*
* Functions that may return this value:
* - #SigV4_GenerateHTTPAuthorization
* - #SigV4_AwsIotDateToIso8601
*/
SigV4InvalidParameter,

/**
* @brief The application buffer was not large enough for the specified hash
* function.
*
* Functions that may return this value:
* - #SigV4_GenerateHTTPAuthorization
*/
SigV4InsufficientMemory,

/**
* @brief An error occurred while formatting the provided date header.
*
* Functions that may return this value:
* - #SigV4_AwsIotDateToIso8601
*/
SigV4ISOFormattingError
} SigV4Status_t;

/**
* @ingroup sigv4_struct_types
* @brief The cryptography interface used to supply the user-defined hash
* implementation.
*/
typedef struct SigV4CryptoInterface
{
/**
* @brief Initializes the @p pHashContext.
*
* @param[in] pHashContext Context used to maintain the hash's current state
* during incremental updates.
*
* @return Zero on success, all other return values are failures.
*/
int32_t ( * hashInit )( void * pHashContext );

/**
* @brief Calculates an ongoing hash update (SHA-256, for example).
*
* @param[in] pHashContext Context used to maintain the hash's current state
* during incremental updates.
* @param[in] pInput Buffer holding the data to hash.
* @param[in] inputLen length of the input buffer data.
*
* @return Zero on success, all other return values are failures.
*/
int32_t ( * hashUpdate )( void * pHashContext,
const uint8_t * pInput,
size_t inputLen );

/**
* @brief Calculates the final binary digest of the hash from the context.
*
* @param[in] pHashContext Context used to maintain the hash's current state
* during incremental updates.
* @param[out] pOutput The buffer used to place final hash binary digest
* output.
* @param[in] outputLen The length of the pOutput buffer. This is defined in
* #SIGV4_HASH_DIGEST_LENGTH.
*
* @return Zero on success, all other return values are failures.
*/
int32_t ( * hashFinal )( void * pHashContext,
uint8_t * pOutput,
size_t outputLen );

/* Context for the hashInit, hashUpdate, and hashFinal interfaces. */
void * pHashContext;
} SigV4CryptoInterface_t;

/**
* @ingroup sigv4_struct_types
* @brief Configurations of the HTTP request used to create the Canonical
* Request.
*/
typedef struct SigV4HttpParameters
{
/**
* @brief The HTTP method: GET, POST, PUT, etc.
*/
const char * pHttpMethod;
size_t httpMethodLen;

/**
* @brief These flags are used to indicate if the path, query, or headers are already
* in the canonical form. This is to bypass the internal sorting, white space
* trimming, and encoding done by the library. This is a performance optimization
* option. Please see https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
* for information on generating a canonical path, query, and headers string.
* #define SIGV4_HTTP_PATH_IS_CANONICAL_FLAG 0x1
* #define SIGV4_HTTP_QUERY_IS_CANONICAL_FLAG 0x2
* #define SIGV4_HTTP_HEADERS_ARE_CANONICAL_FLAG 0x4
* #define SIGV4_HTTP_ALL_ARE_CANONICAL_FLAG 0x8
*/
uint32_t flags;

/**
* @brief The path in the HTTP request. This is the absolute request URI,
* which contains everything in the URI following the HTTP host until the
* question mark character ("?") that begins any query string parameters
* (e.g. "/path/to/item.txt"). If #SIGV4_HTTP_PATH_IS_CANONICAL_FLAG is set,
* then this input must already be in canonical form.
*/
const char * pPath;
size_t pathLen;

/**
* @brief The HTTP request query from the URL. This contains all characters
* following character that denotes the start of the query. If
* #SIGV4_HTTP_QUERY_IS_CANONICAL_FLAG is set, then this input must already
* be in canonical form.
*/
const char * pQuery;
size_t queryLen;

/**
* @brief The headers from the HTTP request that we want to sign. This
* should be the raw headers in HTTP request format. If
* #SIGV4_HTTP_HEADERS_IS_CANONICAL_FLAG is set, then this input must
* already be in canonical form.
*/
const char * pHeaders;
size_t headersLen;

/**
* @brief The HTTP response body, if one exists (ex. PUT request). If this
* body is chunked, then this field should be set with
* STREAMING-AWS4-HMAC-SHA256-PAYLOAD.
*/
const char * pPayload;
size_t payloadLen;
} SigV4HttpParameters_t;

/**
* @ingroup sigv4_struct_types
* @brief Configurations for the AWS credentials used to generate the Signing
* Key.
*/
typedef struct SigV4Credentials
{
/**
* @brief The pAccessKeyId MUST be 20 characters long.
*/
const char * pAccessKeyId;
size_t accessKeyLen;

/**
* @brief The pSecretAccessKey MUST be 40 characters long.
*/
const char * pSecretAccessKey;
size_t secretAccessKeyLen;

/**
* @brief The Security Token from STS is of varying length. This can be NULL
* if the access key id and secret access key were not retrieved from a
* temporary token service.
*/
const char * pSecurityToken;
size_t securityTokenLen;

/**
* @brief The expiration time for the pAccessKeyId, pSecretAccessKey, and
* pSecurityToken if the credentials were retrieved from a temporary token
* service. This is in ISO8601 date and time format.
*/
const char * pExpiration;
size_t expirationLen;
} SigV4Credentials_t;

/**
* @ingroup sigv4_struct_types
* @brief Nested struct containing the above parameters required to create the
* String to Sign and the Signing Key.
*/
typedef struct SigV4Parameters
{
/**
* @brief The AccessKeyId, SecretAccessKey, and SecurityToken used to
* generate the Authorization header.
*/
SigV4Credentials_t * pCredentials;

/**
* @brief The date in ISO 8601 format, e.g. "20150830T123600Z". This is
* always 16 characters long.
*/
const char * pDateIso8601;
Copy link
Contributor

@aggarw13 aggarw13 Mar 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the date buffer is fixed, having it defined explicitly would be helpful for the user.

Suggested change
const char * pDateIso8601;
const char pDateIso8601[16];


/**
* @brief The target AWS region for the request. Please see
* https://docs.aws.amazon.com/general/latest/gr/rande.html for a list of
* region names and codes.
*/
const char * pRegion;
size_t regionLen;

/**
* @brief The target AWS service for the request. The service name can be
* found as the first segment of the service endpoint. Please see
* https://docs.aws.amazon.com/general/latest/gr/aws-service-information.html
* (https://docs.aws.amazon.com/general/latest/gr/aws-service-information.html)
* for your service of interest.
*/
const char * pService;
size_t serviceLen;

/**
* @brief The cryptography interface.
*/
SigV4CryptoInterface_t * pCryptoInterface;

/**
* @brief HTTP specific SigV4 parameters for canonical request calculation.
*/
SigV4HttpParameters_t * pHttpParameters;
} SigV4Parameters_t;

/**
* @brief Generates the HTTP Authorization header value.
*
* @param[in] pParams Parameters for generating the SigV4 signature.
* @param[out] pAuthBuf Buffer to hold the generated Authorization header value.
* @param[in, out] authBufLen Input: the length of pAuthBuf, output: the length
* of the authorization value written to the buffer.
* @param[out] pSignature Location of the signature in the authorization string.
* @param[out] signatureLen The length of pSignature.
*
* @return #SigV4Success if successful, error code otherwise.
*/
SigV4Status_t SigV4_GenerateHTTPAuthorization( const SigV4Parameters_t * pParams,
char * pAuthBuf,
size_t * authBufLen,
char ** pSignature,
size_t * signatureLen );

/**
* @brief Parse the date header value from the AWS IoT response.
* The AWS IoT response date is of the form: 2018-01-18T09:18:06Z.
*
* @param[in] pDate The date header value.
* @param[in] dateLen length of the pDate header value.
* @param[out] pDateISO8601 The ISO8601 format compliant date. This buffer must
* be 17 characters in length to account for the null terminator.
*
* @return #SigV4Success code if successful, error code otherwise.
*/
SigV4Status_t SigV4_AwsIotDateToIso8601( const char * pDate,
size_t dateLen,
char pDateISO8601[ 17 ] );
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this change will be rebased based on the recent updates in PR #3


#endif /* SIGV4_H_ */
Loading