static SigV4Status_t generateCanonicalURI()

in source/sigv4.c [57:724]


    static SigV4Status_t generateCanonicalURI( const char * pUri,
                                               size_t uriLen,
                                               bool encodeTwice,
                                               CanonicalContext_t * pCanonicalRequest );

/**
 * @brief Canonicalize the query string HTTP URL, beginning (but not
 * including) at the "?" character. Does not include "/".
 *
 * @param[in] pQuery HTTP request query.
 * @param[in] queryLen Length of pQuery.
 * @param[in] doubleEncodeEqualsInParmsValues whether to double-encode any equals ( = ) characters in parameter values.
 * @param[in, out] pCanonicalContext Struct to maintain intermediary buffer
 * and state of canonicalization.
 */
    static SigV4Status_t generateCanonicalQuery( const char * pQuery,
                                                 size_t queryLen,
                                                 const bool doubleEncodeEqualsInParmsValues,
                                                 CanonicalContext_t * pCanonicalContext );

/**
 * @brief Determine if a character can be written without needing URI encoding when generating Canonical Request.
 *
 * @param[in] c The character to evaluate.
 * @param[in] encodeSlash Whether slashes may be encoded.
 *
 * @return `true` if the character does not need encoding, `false` if it does.
 */
    static bool isAllowedChar( char c,
                               bool encodeSlash );

/**
 * @brief Compare two SigV4 data structures lexicographically, without case-sensitivity.
 *
 * @param[in] pFirstVal SigV4 key value data structure to sort.
 * @param[in] pSecondVal SigV4 key value data structure to sort.
 *
 * @return Returns a value less than 0 if @pFirstVal < @pSecondVal, or
 * a value greater than 0 if @pSecondVal < @pFirstVal. 0 is never returned in
 * order to provide stability to quickSort() calls.
 */
    static int32_t cmpHeaderField( const void * pFirstVal,
                                   const void * pSecondVal );

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

/**
 * @brief Converts an integer value to its ASCII representation, and stores the
 * result in the provided buffer.
 *
 * @param[in] value The value to convert to ASCII.
 * @param[in, out] pBuffer The starting location of the buffer on input, and the
 * ending location on output.
 * @param[in] bufferLen Width of value to write (padded with leading 0s if
 * necessary).
 */
static void intToAscii( int32_t value,
                        char ** pBuffer,
                        size_t bufferLen );

/**
 * @brief Extract all header key-value pairs from the passed headers data and add them
 * to the canonical request.
 *
 * @param[in] pHeaders HTTP headers to canonicalize.
 * @param[in] headersLen Length of HTTP headers to canonicalize.
 * @param[in] flags Flag to indicate if headers are already
 * in the canonical form.
 * @param[out] canonicalRequest Struct to maintain intermediary buffer
 * and state of canonicalization.
 * @param[out] pSignedHeaders The starting location of the signed headers.
 * @param[out] pSignedHeadersLen The length of the signed headers.
 *
 * @return Following statuses will be returned by the function:
 * #SigV4Success if headers are successfully added to the canonical request.
 * #SigV4InsufficientMemory if canonical request buffer cannot accommodate the header.
 * #SigV4InvalidParameter if HTTP headers are invalid.
 * #SigV4MaxHeaderPairCountExceeded if number of headers that needs to be canonicalized
 * exceed the SIGV4_MAX_HTTP_HEADER_COUNT macro defined in the config file.
 */
static SigV4Status_t generateCanonicalAndSignedHeaders( const char * pHeaders,
                                                        size_t headersLen,
                                                        uint32_t flags,
                                                        CanonicalContext_t * canonicalRequest,
                                                        char ** pSignedHeaders,
                                                        size_t * pSignedHeadersLen );

/**
 * @brief Append Signed Headers to the Canonical Request buffer.
 *
 * @param[in] headerCount Number of headers which needs to be appended.
 * @param[in] flags Flag to indicate if headers are already
 * in the canonical form.
 * @param[in,out] pCanonicalRequest Struct to maintain intermediary buffer
 * and state of canonicalization.
 * @param[out] pSignedHeaders The starting location of the signed headers.
 * @param[out] pSignedHeadersLen The length of the signed headers.
 */
static SigV4Status_t appendSignedHeaders( size_t headerCount,
                                          uint32_t flags,
                                          CanonicalContext_t * pCanonicalRequest,
                                          char ** pSignedHeaders,
                                          size_t * pSignedHeadersLen );

/**
 * @brief Canonicalize headers and append it to the Canonical Request buffer.
 *
 * @param[in] headerCount Number of headers which needs to be appended.
 * @param[in] flags Flag to indicate if headers are already
 * in the canonical form.
 * @param[in,out] pCanonicalRequest Struct to maintain intermediary buffer
 * and state of canonicalization.
 *
 * @return Following statuses will be returned by the function:
 * #SigV4Success if headers are successfully added to the canonical request.
 * #SigV4InsufficientMemory if canonical request buffer cannot accommodate the header.
 */
static SigV4Status_t appendCanonicalizedHeaders( size_t headerCount,
                                                 uint32_t flags,
                                                 CanonicalContext_t * pCanonicalRequest );

/**
 * @brief Store the location of HTTP request hashed payload in the HTTP request.
 *
 * @param[in] headerIndex Index of request Header in the list of parsed headers.
 * @param[in] pAmzSHA256Header Literal for x-amz-content-sha256 header in HTTP request.
 * @param[in] amzSHA256HeaderLen Length of @p pAmzSHA256Header.
 * @param[in,out] pCanonicalRequest Struct to maintain intermediary buffer
 * and state of canonicalization.
 */
static void storeHashedPayloadLocation( size_t headerIndex,
                                        const char * pAmzSHA256Header,
                                        size_t amzSHA256HeaderLen,
                                        CanonicalContext_t * pCanonicalRequest );

/**
 * @brief Parse each header key and value pair from HTTP headers.
 *
 * @param[in] pHeaders HTTP headers to parse.
 * @param[in] headersDataLen Length of HTTP headers to parse.
 * @param[in] flags Flag to indicate if headers are already
 * in the canonical form.
 * @param[out] headerCount Count of key-value pairs parsed from pData.
 * @param[out] pCanonicalRequest Struct to maintain intermediary buffer
 * and state of canonicalization.
 *
 * @return Following statuses will be returned by the function:
 * #SigV4Success if header key or value is successfully added to the canonical request.
 * #SigV4InsufficientMemory if canonical request buffer cannot accommodate the header.
 * #SigV4MaxHeaderPairCountExceeded if number of key-value entries in the headers data
 * exceeds the SIGV4_MAX_HTTP_HEADER_COUNT macro defined in the config file.
 */
static SigV4Status_t parseHeaderKeyValueEntries( const char * pHeaders,
                                                 size_t headersDataLen,
                                                 uint32_t flags,
                                                 size_t * headerCount,
                                                 CanonicalContext_t * pCanonicalRequest );

/**
 * @brief Copy header key or header value to the Canonical Request buffer.
 *
 * @param[in] pData Header Key or value to be copied to the canonical request.
 * @param[in] dataLen Length of Header Key or value.
 * @param[in] flags Flag to indicate if headers are already
 * in the canonical form.
 * @param[in] separator Character separating the multiple key-value pairs or key and values.
 * @param[in,out] pCanonicalRequest Struct to maintain intermediary buffer
 * and state of canonicalization.
 *
 * @return Following statuses will be returned by the function:
 * #SigV4Success if the headers are successfully added to the canonical request.
 * #SigV4InsufficientMemory if canonical request buffer cannot accommodate the header.
 */
static SigV4Status_t copyHeaderStringToCanonicalBuffer( const char * pData,
                                                        size_t dataLen,
                                                        uint32_t flags,
                                                        char separator,
                                                        CanonicalContext_t * pCanonicalRequest );

/**
 * @brief Helper function to determine whether a header string character represents a space
 * that can be trimmed when creating "Canonical Headers".
 * All leading and trailing spaces in the header strings need to be trimmed. Also, sequential spaces
 * in the header value need to be trimmed to a single space.
 *
 * Example of modifying header field for Canonical Headers:
 * Actual header pair:                 |      Modifier header pair
 * My-Header2:    "a   b   c"  \n      |      my-header2:"a b c"\n
 *
 * @param[in] value Header value or key string to be trimmed.
 * @param[in] index Index of current character.
 * @param[in] valLen Length of the string.
 * @param[in] trimmedLength Current length of trimmed string.
 *
 * @return `true` if the character needs to be trimmed, else `false`.
 */
static bool isTrimmableSpace( const char * value,
                              size_t index,
                              size_t valLen,
                              size_t trimmedLength );

/**
 * @brief Generate the canonical request but excluding the canonical headers
 * and anything that goes after it. Write it onto @p pSignedHeaders and update
 * it to point to the next location to write the rest of the canonical request.
 *
 * @param[in] pParams The application-defined parameters used to
 * generate the canonical request.
 * @param[in] pCanonicalContext The context of the canonical request.
 * @param[in,out] pSignedHeaders The location to start writing the canonical request and
 * becomes the location to write the rest of it when this function returns.
 * @param[in,out] pSignedHeadersLen The amount of buffer available and becomes the number
 * of bytes actually written when this function returns.
 * @return SigV4InsufficientMemory if the length of the canonical request output
 * buffer cannot fit the actual request before the headers, #SigV4Success otherwise.
 */
static SigV4Status_t generateCanonicalRequestUntilHeaders( const SigV4Parameters_t * pParams,
                                                           CanonicalContext_t * pCanonicalContext,
                                                           char ** pSignedHeaders,
                                                           size_t * pSignedHeadersLen );

/**
 * @brief Generates the prefix of the Authorization header of the format:
 * "<algorithm> Credential=<access key ID>/<credential scope>, SignedHeaders=<SignedHeaders>, Signature="
 *
 * @param[in] pParams The application-defined parameters used to
 * generate the canonical request.
 * @param[in] pAlgorithm The signing algorithm used for SigV4 authentication.
 * @param[in] algorithmLen The length of @p pAlgorithm.
 * @param[in] pSignedHeaders The signed headers of the SigV4 request.
 * @param[in] signedHeadersLen The length of @p pSignedHeaders.
 * @param[in,out] pAuthBuf The authorization buffer where to write the prefix.
 * Pointer is updated with the next location to write the value of the signature.
 * @param[in, out] pAuthPrefixLen On input, it should contain the total length of @p pAuthBuf.
 * On output, this will be filled with the length of the Authorization header, if
 * operation is successful.
 *
 * @return #SigV4InsufficientMemory if the length of the authorization buffer, @p pAuthBuf
 * is insufficient to store the entire authorization header value (i.e. Prefix + HexEncoded Signature);
 * otherwise #SigV4Success.
 */
static SigV4Status_t generateAuthorizationValuePrefix( const SigV4Parameters_t * pParams,
                                                       const char * pAlgorithm,
                                                       size_t algorithmLen,
                                                       const char * pSignedHeaders,
                                                       size_t signedHeadersLen,
                                                       char * pAuthBuf,
                                                       size_t * pAuthPrefixLen );

/**
 * @brief Write a line in the canonical request.
 * @note Used whenever there are components of the request that
 * are already canonicalized.
 *
 * @param[in] pLine The line to write to the canonical request.
 * @param[in] lineLen The length of @p pLine
 * @param[in,out] pCanonicalContext The canonical context where
 * the line should be written.
 * @return SigV4InsufficientMemory if the length of the canonical request
 * buffer cannot write the desired line, #SigV4Success otherwise.
 */
static SigV4Status_t writeLineToCanonicalRequest( const char * pLine,
                                                  size_t lineLen,
                                                  CanonicalContext_t * pCanonicalContext );

/**
 * @brief Set a query parameter key in the canonical request.
 *
 * @param[in] currentParameter The index of the query key to set
 * @param[in] pKey The pointer to the query key
 * @param[in] keyLen The length of @p pKey
 * @param[in,out] pCanonicalRequest The canonical request containing the
 * query parameter array of keys and values
 */
static void setQueryParameterKey( size_t currentParameter,
                                  const char * pKey,
                                  size_t keyLen,
                                  CanonicalContext_t * pCanonicalRequest );

/**
 * @brief Set a query parameter value in the canonical request.
 *
 * @param[in] currentParameter The index of the query value to set
 * @param[in] pValue The pointer to the query value
 * @param[in] valueLen The length of @p pValue
 * @param[in,out] pCanonicalRequest The canonical request containing the
 * query parameter array of keys and values
 */
static void setQueryParameterValue( size_t currentParameter,
                                    const char * pValue,
                                    size_t valueLen,
                                    CanonicalContext_t * pCanonicalRequest );

/**
 * @brief Convert the character to lowercase.
 *
 * @param[in] inputChar character to be lowercased.
 *
 * @return Input character converted to lowercase.
 */
static char lowercaseCharacter( char inputChar );

/**
 * @brief Write the HTTP request payload hash to the canonical request.
 *
 * @param[in] pParams The application-defined parameters used for writing
 * the payload hash.
 * @param[out] pCanonicalContext The canonical context where the payload
 * hash should be written.
 *
 * @return SigV4InsufficientMemory if the length of the canonical request
 * buffer cannot write the desired line, #SigV4Success otherwise.
 */
static SigV4Status_t writePayloadHashToCanonicalRequest( const SigV4Parameters_t * pParams,
                                                         CanonicalContext_t * pCanonicalContext );

/**
 * @brief Generates the key for the HMAC operation.
 *
 * @note This function can be called multiple times before calling
 * #hmacIntermediate. Appending multiple substrings, then calling #hmacAddKey
 * on the appended string is also equivalent to calling #hmacAddKey on
 * each individual substring.
 * @note This function accepts a const char * so that string literals
 * can be passed in.
 *
 * @param[in] pHmacContext The context used for HMAC calculation.
 * @param[in] pKey The key used as input for HMAC calculation.
 * @param[in] keyLen The length of @p pKey.
 * @param[in] isKeyPrefix Flag to indicate whether the passed key is
 * prefix of a complete key for an HMAC operation. If this is a prefix,
 * then it will be stored in cache for use with remaining part of the
 * key that will be provided in a subsequent call to @ref hmacAddKey.
 *
 * @return Zero on success, all other return values are failures.
 */
static int32_t hmacAddKey( HmacContext_t * pHmacContext,
                           const char * pKey,
                           size_t keyLen,
                           bool isKeyPrefix );

/**
 * @brief Generates the intermediate hash output in the HMAC signing process.
 * This represents the H( K' ^ i_pad || message ) part of the HMAC algorithm.
 *
 * @note This MUST be ONLY called after #hmacAddKey; otherwise results in
 * undefined behavior. Likewise, one SHOULD NOT call #hmacAddKey after
 * calling #hmacIntermediate. One must call #hmacFinal first before calling
 * #hmacAddKey again.
 *
 * @param[in] pHmacContext The context used for HMAC calculation.
 * @param[in] pData The data used as input for HMAC calculation.
 * @param[in] dataLen The length of @p pData.
 *
 * @return Zero on success, all other return values are failures.
 */
static int32_t hmacIntermediate( HmacContext_t * pHmacContext,
                                 const char * pData,
                                 size_t dataLen );

/**
 * @brief Generates the end output of the HMAC algorithm.
 *
 * This represents the second hash operation in the HMAC algorithm:
 *   H( K' ^ o_pad || Intermediate Hash Output )
 * where the Intermediate Hash Output is generated from the call
 * to @ref hmacIntermediate.
 *
 * @param[in] pHmacContext The context used for HMAC calculation.
 * @param[out] pMac The buffer onto which to write the HMAC digest.
 * @param[in] macLen The length of @p pMac.
 *
 * @return Zero on success, all other return values are failures.
 */
static int32_t hmacFinal( HmacContext_t * pHmacContext,
                          char * pMac,
                          size_t macLen );

/**
 * @brief Generates the complete HMAC digest given a key and value, then write
 * the digest in the provided output buffer.
 *
 * @param[in] pHmacContext The context used for the current HMAC calculation.
 * @param[in] pKey The key passed as input to the HMAC function.
 * @param[in] keyLen The length of @p pKey.
 * @param[in] pData The data passed as input to the HMAC function.
 * @param[in] dataLen The length of @p pData.
 * @param[out] pOutput The buffer onto which to write the HMAC digest.
 * @param[out] outputLen The length of @p pOutput and must be greater
 * than pCryptoInterface->hashDigestLen for this function to succeed.
 * @return Zero on success, all other return values are failures.
 */
static int32_t completeHmac( HmacContext_t * pHmacContext,
                             const char * pKey,
                             size_t keyLen,
                             const char * pData,
                             size_t dataLen,
                             char * pOutput,
                             size_t outputLen );

/**
 * @brief Generates the complete hash of an input string, then write
 * the digest in the provided output buffer.
 * @note Unlike #completeHashAndHexEncode, this function will not
 * encode the hash and will simply output the bytes written by the
 * hash function.
 *
 * @param[in] pInput The data passed as input to the hash function.
 * @param[in] inputLen The length of @p pInput.
 * @param[out] pOutput The buffer onto which to write the hash.
 * @param[out] outputLen The length of @p pOutput and must be greater
 * than pCryptoInterface->hashDigestLen for this function to succeed.
 * @param[in] pCryptoInterface The interface used to call hash functions.
 * @return Zero on success, all other return values are failures.
 */
static int32_t completeHash( const uint8_t * pInput,
                             size_t inputLen,
                             uint8_t * pOutput,
                             size_t outputLen,
                             const SigV4CryptoInterface_t * pCryptoInterface );

/**
 * @brief Generate the complete hash of an input string, then write
 * the digest in an intermediary buffer before hex encoding and
 * writing it onto @p pOutput.
 *
 * @param[in] pInput The data passed as input to the hash function.
 * @param[in] inputLen The length of @p pInput.
 * @param[out] pOutput The buffer onto which to write the hex-encoded hash.
 * @param[out] pOutputLen The length of @p pOutput and must be greater
 * than pCryptoInterface->hashDigestLen * 2 for this function to succeed.
 * @param[in] pCryptoInterface The interface used to call hash functions.
 * @return Zero on success, all other return values are failures.
 */
static SigV4Status_t completeHashAndHexEncode( const char * pInput,
                                               size_t inputLen,
                                               char * pOutput,
                                               size_t * pOutputLen,
                                               const SigV4CryptoInterface_t * pCryptoInterface );

/**
 * @brief Generate the prefix of the string to sign containing the
 * algorithm and date then write it onto @p pBufStart.
 * @note This function assumes that enough bytes remain in @p pBufStart in
 * order to write the algorithm and date.
 *
 * @param[in] pBufStart The starting location of the buffer to write the string
 * to sign.
 * @param[in] pAlgorithm The algorithm used for generating the SigV4 signature.
 * @param[in] algorithmLen The length of @p pAlgorithm.
 * @param[in] pDateIso8601 The date used as part of the string to sign.
 * @return The number of bytes written to @p pBufStart.
 */
static size_t writeStringToSignPrefix( char * pBufStart,
                                       const char * pAlgorithm,
                                       size_t algorithmLen,
                                       const char * pDateIso8601 );

/**
 * @brief Generate the string to sign and write it onto a #SigV4String_t.
 *
 * @param[in] pParams The application-defined parameters used to
 * generate the string to sign.
 * @param[in] pAlgorithm The algorithm used for generating the SigV4 signature.
 * @param[in] algorithmLen The length of @p pAlgorithm.
 * @param[in,out] pCanonicalContext The context of the canonical request.
 * @return SigV4InsufficientMemory if the length of the canonical request output
 * buffer cannot fit the string to sign, #SigV4Success otherwise.
 */
static SigV4Status_t writeStringToSign( const SigV4Parameters_t * pParams,
                                        const char * pAlgorithm,
                                        size_t algorithmLen,
                                        CanonicalContext_t * pCanonicalContext );

/**
 * @brief Generate the signing key and write it onto a #SigV4String_t.
 *
 * @param[in] pSigV4Params The application-defined parameters used to
 * generate the signing key.
 * @param[in] pHmacContext The context used for the current HMAC calculation.
 * @param[out] pSigningKey The #SigV4String_t onto which the signing key will be written.
 * @param[in,out] pBytesRemaining The number of bytes remaining in the canonical buffer.
 * @return SigV4InsufficientMemory if the length of @p pSigningKey was insufficient to
 * fit the actual signing key, #SigV4Success otherwise.
 */
static SigV4Status_t generateSigningKey( const SigV4Parameters_t * pSigV4Params,
                                         HmacContext_t * pHmacContext,
                                         SigV4String_t * pSigningKey,
                                         size_t * pBytesRemaining );

/**
 * @brief Format the credential scope for the authorization header.
 * Credential scope includes the access key ID, date, region, and service parameters, and
 * ends with "aws4_request" terminator.
 *
 * @param[in] pSigV4Params The application parameters defining the credential's scope.
 * @param[in, out] pCredScope The credential scope in the SigV4 format.
 */
static void generateCredentialScope( const SigV4Parameters_t * pSigV4Params,
                                     SigV4String_t * pCredScope );

/**
 * @brief Check if the date represents a valid leap year day.
 *
 * @param[in] pDateElements The date representation to be verified.
 *
 * @return #SigV4Success if the date corresponds to a valid leap year,
 * #SigV4ISOFormattingError otherwise.
 */
static SigV4Status_t checkLeap( const SigV4DateTime_t * pDateElements );

/**
 * @brief Verify the date stored in a SigV4DateTime_t date representation.
 *
 * @param[in] pDateElements The date representation to be verified.
 *
 * @return #SigV4Success if the date is valid, and #SigV4ISOFormattingError if
 * any member of SigV4DateTime_t is invalid or represents an out-of-range date.
 */
static SigV4Status_t validateDateTime( const SigV4DateTime_t * pDateElements );

/**
 * @brief Append the value of a date element to the internal date representation
 * structure.
 *
 * @param[in] formatChar The specifier identifying the struct member to fill.
 * @param[in] result The value to assign to the specified struct member.
 * @param[out] pDateElements The date representation structure to modify.
 */
static void addToDate( const char formatChar,
                       int32_t result,
                       SigV4DateTime_t * pDateElements );

/**
 * @brief Interpret the value of the specified characters in date, based on the
 * format specifier, and append to the internal date representation.
 *
 * @param[in] pDate The date to be parsed.
 * @param[in] formatChar The format specifier used to interpret characters.
 * @param[in] readLoc The index of pDate to read from.
 * @param[in] lenToRead The number of characters to read.
 * @param[out] pDateElements The date representation to modify.
 *
 * @return #SigV4Success if parsing succeeded, #SigV4ISOFormattingError if the
 * characters read did not match the format specifier.
 */
static SigV4Status_t scanValue( const char * pDate,
                                const char formatChar,
                                size_t readLoc,
                                size_t lenToRead,
                                SigV4DateTime_t * pDateElements );

/**
 * @brief Parses date according to format string parameter, and populates date
 * representation struct SigV4DateTime_t with its elements.
 *
 * @param[in] pDate The date to be parsed.
 * @param[in] dateLen Length of pDate, the date to be formatted.
 * @param[in] pFormat The format string used to extract date pDateElements from
 * pDate. This string, among other characters, may contain specifiers of the
 * form "%LV", where L is the number of characters to be read, and V is one of
 * {Y, M, D, h, m, s, *}, representing a year, month, day, hour, minute, second,
 * or skipped (un-parsed) value, respectively.
 * @param[in] formatLen Length of the format string pFormat.
 * @param[out] pDateElements The deconstructed date representation of pDate.
 *
 * @return #SigV4Success if all format specifiers were matched successfully,
 * #SigV4ISOFormattingError otherwise.
 */
static SigV4Status_t parseDate( const char * pDate,
                                size_t dateLen,
                                const char * pFormat,
                                size_t formatLen,
                                SigV4DateTime_t * pDateElements );

/**
 * @brief Verify input parameters to the SigV4_GenerateHTTPAuthorization API.
 *
 * @param[in] pParams Complete SigV4 configurations passed by application.
 * @param[in] pAuthBuf The user-supplied buffer for filling Authorization Header.
 * @param[in] authBufLen The user-supplied size value of @p pAuthBuf buffer.
 * @param[in] pSignature The user-supplied pointer memory to store starting location of
 * Signature in Authorization Buffer.
 * @param[in] signatureLen The user-supplied pointer to store length of Signature.
 *
 * @return #SigV4Success if successful, #SigV4InvalidParameter otherwise.
 */
static SigV4Status_t verifyParamsToGenerateAuthHeaderApi( const SigV4Parameters_t * pParams,
                                                          const char * pAuthBuf,
                                                          const size_t * authBufLen,
                                                          char * const * pSignature,
                                                          const size_t * signatureLen );

/**
 * @brief Assign default arguments based on parameters set in @p pParams.
 *
 * @param[in] pParams Complete SigV4 configurations passed by application.
 * @param[out] pAlgorithm The algorithm used for SigV4 authentication.
 * @param[out] algorithmLen The length of @p pAlgorithm.
 */
static void assignDefaultArguments( const SigV4Parameters_t * pParams,
                                    const char ** pAlgorithm,
                                    size_t * algorithmLen );

/**
 * @brief Hex digest of provided string parameter.
 *
 * @param[in] pInputStr String to encode.
 * @param[out] pHexOutput Hex representation of @p pInputStr.
 *
 * @return #SigV4Success if successful, #SigV4InsufficientMemory otherwise.
 */
static SigV4Status_t lowercaseHexEncode( const SigV4String_t * pInputStr,
                                         SigV4String_t * pHexOutput );

/**
 * @brief Calculate number of bytes needed for the credential scope.
 * @note This does not include the linefeed character.
 *
 * @param[in] pSigV4Params SigV4 configurations passed by application.
 *
 * @return Number of bytes needed for credential scope.
 */
static size_t sizeNeededForCredentialScope( const SigV4Parameters_t * pSigV4Params );

/**
 * @brief Copy a string into a char * buffer.
 * @note This function can be used to copy a string literal without
 * MISRA warnings.
 *
 * @note This function assumes the destination buffer is large enough to hold
 * the string to copy, so will always write @p length bytes.
 *
 * @param[in] destination The buffer to write.
 * @param[in] source String to copy.
 * @param[in] length Number of characters to copy.
 *
 * @return @p length The number of characters written from @p source into
 * @p destination.
 */
static size_t copyString( char * destination,
                          const char * source,
                          size_t length );

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

static void intToAscii( int32_t value,
                        char ** pBuffer,
                        size_t bufferLen )
{
    int32_t currentVal = value;
    size_t lenRemaining = bufferLen;

    assert( pBuffer != NULL );
    assert( bufferLen > 0U );

    /* Write base-10 remainder in its ASCII representation, and fill any
     * remaining width with '0' characters. */
    while( lenRemaining > 0U )
    {
        lenRemaining--;
        ( *pBuffer )[ lenRemaining ] = ( char ) ( ( currentVal % 10 ) + '0' );
        currentVal /= 10;
    }

    /* Move pointer to follow last written character. */
    *pBuffer = &( ( *pBuffer )[ bufferLen ] );
}