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

Support presigned URL signature "UNSIGNED-PAYLOAD" and expose EncodeURI #89

Merged
merged 14 commits into from
Feb 23, 2024
Merged
35 changes: 35 additions & 0 deletions source/include/sigv4.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@

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

/* *INDENT-OFF* */
Expand Down Expand Up @@ -125,6 +126,15 @@
*/
#define SIGV4_HTTP_PAYLOAD_IS_HASH 0x8U

/**
* @ingroup sigv4_canonical_flags
* @brief Set this flag to indicate that the HTTP request payload is
* already hashed.
*
* This flag is valid only for #SigV4HttpParameters_t.flags.
*/
#define SIGV4_HTTP_PAYLOAD_IS_UNSIGNED 0x10U

/**
* @ingroup sigv4_canonical_flags
* @brief Set this flag to indicate that the HTTP request path, query, and
Expand Down Expand Up @@ -565,6 +575,31 @@ SigV4Status_t SigV4_AwsIotDateToIso8601( const char * pDate,
size_t dateISO8601Len );
/* @[declare_sigV4_awsIotDateToIso8601_function] */

#if ( SIGV4_USE_CANONICAL_SUPPORT == 1 )

/**
* @brief Normalize a URI string according to RFC 3986 and fill destination
* buffer with the formatted string.
*
* @param[in] pUri The URI string to encode.
* @param[in] uriLen Length of pUri.
* @param[out] pCanonicalURI The resulting canonicalized URI.
* @param[in, out] canonicalURILen input: the length of pCanonicalURI,
* output: the length of the generated canonical URI.
* @param[in] encodeSlash Option to indicate if slashes should be encoded.
* @param[in] doubleEncodeEquals Option to indicate if equals should be double-encoded.
*/
/* @[declare_sigV4_EncodeURI_function] */
SigV4Status_t SigV4_EncodeURI( const char * pUri,
size_t uriLen,
char * pCanonicalURI,
size_t * canonicalURILen,
bool encodeSlash,
bool doubleEncodeEquals );
/* @[declare_sigV4_encodeURI_function] */

#endif /* #if (SIGV4_USE_CANONICAL_SUPPORT == 1) */

/* *INDENT-OFF* */
#ifdef __cplusplus
}
Expand Down
77 changes: 32 additions & 45 deletions source/sigv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@

#include <assert.h>
#include <string.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

Expand All @@ -41,25 +40,6 @@

#if ( SIGV4_USE_CANONICAL_SUPPORT == 1 )

/**
* @brief Normalize a URI string according to RFC 3986 and fill destination
* buffer with the formatted string.
*
* @param[in] pUri The URI string to encode.
* @param[in] uriLen Length of pUri.
* @param[out] pCanonicalURI The resulting canonicalized URI.
* @param[in, out] canonicalURILen input: the length of pCanonicalURI,
* output: the length of the generated canonical URI.
* @param[in] encodeSlash Option to indicate if slashes should be encoded.
* @param[in] doubleEncodeEquals Option to indicate if equals should be double-encoded.
*/
static SigV4Status_t encodeURI( const char * pUri,
size_t uriLen,
char * pCanonicalURI,
size_t * canonicalURILen,
bool encodeSlash,
bool doubleEncodeEquals );

/**
* @brief Canonicalize the full URI path. The input URI starts after the
* HTTP host and ends at the question mark character ("?") that begins the
Expand Down Expand Up @@ -1316,12 +1296,12 @@ static void generateCredentialScope( const SigV4Parameters_t * pSigV4Params,

/*-----------------------------------------------------------*/

static SigV4Status_t encodeURI( const char * pUri,
size_t uriLen,
char * pCanonicalURI,
size_t * canonicalURILen,
bool encodeSlash,
bool doubleEncodeEquals )
SigV4Status_t SigV4_EncodeURI( const char * pUri,
size_t uriLen,
char * pCanonicalURI,
size_t * canonicalURILen,
bool encodeSlash,
bool doubleEncodeEquals )
{
size_t uriIndex = 0U, bytesConsumed = 0U;
size_t bufferLen = 0U;
Expand Down Expand Up @@ -1416,7 +1396,7 @@ static void generateCredentialScope( const SigV4Parameters_t * pSigV4Params,
/* If the canonical URI needs to be encoded twice, then we encode once here,
* and again at the end of the buffer. Afterwards, the second encode is copied
* to overwrite the first one. */
returnStatus = encodeURI( pUri, uriLen, pBufLoc, &encodedLen, false, false );
returnStatus = SigV4_EncodeURI( pUri, uriLen, pBufLoc, &encodedLen, false, false );

if( returnStatus == SigV4Success )
{
Expand All @@ -1428,12 +1408,12 @@ static void generateCredentialScope( const SigV4Parameters_t * pSigV4Params,
* written to a different position in the buffer. It should not be done
* at an overlapping position of the single-encoded URI. Once written,
* the double-encoded URI is moved to the starting location of the single-encoded URI. */
returnStatus = encodeURI( pBufLoc,
encodedLen,
pBufLoc + encodedLen,
&doubleEncodedLen,
false,
false );
returnStatus = SigV4_EncodeURI( pBufLoc,
encodedLen,
pBufLoc + encodedLen,
&doubleEncodedLen,
false,
false );

if( returnStatus == SigV4Success )
{
Expand Down Expand Up @@ -2078,12 +2058,12 @@ static void generateCredentialScope( const SigV4Parameters_t * pSigV4Params,
/* Encode parameter value if non-empty. Query parameters can have empty values. */
if( valueLen > 0U )
{
returnStatus = encodeURI( pValue,
valueLen,
pBufCur + 1U,
&valueBytesWritten,
true,
true );
returnStatus = SigV4_EncodeURI( pValue,
valueLen,
pBufCur + 1U,
&valueBytesWritten,
true,
false );
Copy link
Member

Choose a reason for hiding this comment

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

The unit test test_SigV4_GenerateHTTPAuthorization_Happy_Paths is failing because of this change [line 2066]. Can you please update the tests to match the changes in your PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for reviewing and apologies for missing that.
I completely forgot about this change so I excluded that my changes could ever cause a unit test failure.
I will review this now, maybe I'll propose a way to pass false here only with the flag SIGV4_HTTP_PAYLOAD_IS_UNSIGNED as to not upset other use cases.


if( returnStatus == SigV4Success )
{
Expand Down Expand Up @@ -2117,12 +2097,12 @@ static void generateCredentialScope( const SigV4Parameters_t * pSigV4Params,
assert( pCanonicalRequest->pQueryLoc[ paramsIndex ].key.dataLen > 0U );

encodedLen = remainingLen;
returnStatus = encodeURI( pCanonicalRequest->pQueryLoc[ paramsIndex ].key.pData,
pCanonicalRequest->pQueryLoc[ paramsIndex ].key.dataLen,
pBufLoc,
&encodedLen,
true /* Encode slash (/) */,
false /* Do not encode '='. */ );
returnStatus = SigV4_EncodeURI( pCanonicalRequest->pQueryLoc[ paramsIndex ].key.pData,
pCanonicalRequest->pQueryLoc[ paramsIndex ].key.dataLen,
pBufLoc,
&encodedLen,
true /* Encode slash (/) */,
false /* Do not double encode '='. */ );

if( returnStatus == SigV4Success )
{
Expand Down Expand Up @@ -3090,6 +3070,13 @@ static SigV4Status_t writePayloadHashToCanonicalRequest( const SigV4Parameters_t
/* Remove new line at the end of the payload. */
pCanonicalContext->pBufCur--;
}
else if( FLAG_IS_SET( pParams->pHttpParameters->flags, SIGV4_HTTP_PAYLOAD_IS_UNSIGNED ) )
{
/* Copy the UNSIGNED-PAYLOAD data in the headers data list. */
returnStatus = copyHeaderStringToCanonicalBuffer( "UNSIGNED-PAYLOAD", strlen( "UNSIGNED-PAYLOAD" ), pParams->pHttpParameters->flags, '\n', pCanonicalContext );
/* Remove new line at the end of the payload. */
pCanonicalContext->pBufCur--;
}
else
{
encodedLen = pCanonicalContext->bufRemaining;
Expand Down