diff --git a/src/include/com/amazonaws/kinesis/video/common/Include.h b/src/include/com/amazonaws/kinesis/video/common/Include.h index 730b0b2bb..f718a46eb 100644 --- a/src/include/com/amazonaws/kinesis/video/common/Include.h +++ b/src/include/com/amazonaws/kinesis/video/common/Include.h @@ -98,6 +98,11 @@ extern "C" { */ #define MAX_REGION_NAME_LEN 128 +/** + * Maximum allowed service name length + */ +#define MAX_SERVICE_NAME_LEN 128 + /** * Maximum allowed user agent string length */ @@ -483,6 +488,7 @@ struct __RequestInfo { //!< NOTE: The body will follow the main struct UINT32 bodySize; //!< Size of the body in bytes CHAR url[MAX_URI_CHAR_LEN + 1]; //!< The URL for the request + CHAR service[MAX_SERVICE_NAME_LEN + 1]; //!< The AWS service for the request CHAR certPath[MAX_PATH_LEN + 1]; //!< CA Certificate path to use - optional CHAR sslCertPath[MAX_PATH_LEN + 1]; //!< SSL Certificate file path to use - optional CHAR sslPrivateKeyPath[MAX_PATH_LEN + 1]; //!< SSL Certificate private key file path to use - optional diff --git a/src/source/Common/AwsV4Signer.c b/src/source/Common/AwsV4Signer.c index 3eddaf44c..4c58739bf 100644 --- a/src/source/Common/AwsV4Signer.c +++ b/src/source/Common/AwsV4Signer.c @@ -73,7 +73,8 @@ STATUS generateAwsSigV4Signature(PRequestInfo pRequestInfo, PCHAR dateTimeStr, B hmacSize = SIZEOF(hmac); CHK_STATUS(generateRequestHmac((PBYTE) pScratchBuf, curSize, (PBYTE) dateTimeStr, SIGNATURE_DATE_STRING_LEN * SIZEOF(CHAR), hmac, &hmacSize)); CHK_STATUS(generateRequestHmac(hmac, hmacSize, (PBYTE) pRequestInfo->region, (UINT32) STRLEN(pRequestInfo->region), hmac, &hmacSize)); - CHK_STATUS(generateRequestHmac(hmac, hmacSize, (PBYTE) KINESIS_VIDEO_SERVICE_NAME, (UINT32) STRLEN(KINESIS_VIDEO_SERVICE_NAME), hmac, &hmacSize)); + CHK_STATUS(generateRequestHmac(hmac, hmacSize, (PBYTE) pRequestInfo->service, (UINT32) STRNLEN(pRequestInfo->service, MAX_SERVICE_NAME_LEN), hmac, + &hmacSize)); CHK_STATUS(generateRequestHmac(hmac, hmacSize, (PBYTE) AWS_SIG_V4_SIGNATURE_END, (UINT32) STRLEN(AWS_SIG_V4_SIGNATURE_END), hmac, &hmacSize)); CHK_STATUS(generateRequestHmac(hmac, hmacSize, (PBYTE) pSignedStr, signedStrLen * SIZEOF(CHAR), hmac, &hmacSize)); @@ -117,6 +118,12 @@ STATUS signAwsRequestInfo(PRequestInfo pRequestInfo) CHK(pRequestInfo != NULL && pRequestInfo->pAwsCredentials != NULL, STATUS_NULL_ARG); + // signAwsRequestInfo is a public api function, if service is not specified default to "kinesisvideo" so no breaking changes are introduced to the + // api + if (pRequestInfo->service[0] == L'\0') { + STRNCPY(pRequestInfo->service, KINESIS_VIDEO_SERVICE_NAME, MAX_SERVICE_NAME_LEN); + } + // Generate the time CHK_STATUS(generateSignatureDateTime(pRequestInfo->currentTime, dateTimeStr)); @@ -167,6 +174,12 @@ STATUS signAwsRequestInfoQueryParam(PRequestInfo pRequestInfo) CHK(pRequestInfo != NULL && pRequestInfo->pAwsCredentials != NULL, STATUS_NULL_ARG); + // signAwsRequestInfoQueryParam is a public api function, if service is not specified default to "kinesisvideo" so no breaking changes are + // introduced to the api + if (pRequestInfo->service[0] == L'\0') { + STRNCPY(pRequestInfo->service, KINESIS_VIDEO_SERVICE_NAME, MAX_SERVICE_NAME_LEN); + } + // Generate the time CHK_STATUS(generateSignatureDateTime(pRequestInfo->currentTime, dateTimeStr)); @@ -498,8 +511,13 @@ STATUS generateCanonicalRequestString(PRequestInfo pRequestInfo, PCHAR pRequestS len = SHA256_DIGEST_LENGTH * 2; CHK(curLen + len <= requestLen, STATUS_BUFFER_TOO_SMALL); if (pRequestInfo->body == NULL) { - // Streaming treats this portion as if the body were empty - CHK_STATUS(hexEncodedSha256((PBYTE) EMPTY_STRING, 0, pCurPtr)); + if (STRNCMP(pRequestInfo->service, KINESIS_VIDEO_SERVICE_NAME, MAX_SERVICE_NAME_LEN) == 0) { + // Streaming treats this portion as if the body were empty + CHK_STATUS(hexEncodedSha256((PBYTE) EMPTY_STRING, 0, pCurPtr)); + } else { + len = (UINT32) (ARRAY_SIZE(PREDEFINED_UNSIGNED_PAYLOAD) - 1); + MEMCPY(pCurPtr, PREDEFINED_UNSIGNED_PAYLOAD, SIZEOF(CHAR) * len); + } } else { // standard signing CHK_STATUS(hexEncodedSha256((PBYTE) pRequestInfo->body, pRequestInfo->bodySize, pCurPtr)); @@ -678,14 +696,14 @@ STATUS generateCredentialScope(PRequestInfo pRequestInfo, PCHAR dateTimeStr, PCH CHK(pRequestInfo != NULL && dateTimeStr != NULL && pScopeLen != NULL, STATUS_NULL_ARG); // Calculate the max string length with a null terminator at the end - scopeLen = SIGNATURE_DATE_TIME_STRING_LEN + 1 + MAX_REGION_NAME_LEN + 1 + (UINT32) STRLEN(KINESIS_VIDEO_SERVICE_NAME) + 1 + + scopeLen = SIGNATURE_DATE_TIME_STRING_LEN + 1 + MAX_REGION_NAME_LEN + 1 + (UINT32) STRNLEN(pRequestInfo->service, MAX_SERVICE_NAME_LEN) + 1 + (UINT32) STRLEN(AWS_SIG_V4_SIGNATURE_END) + 1; // Early exit on buffer calculation CHK(pScope != NULL, retStatus); scopeLen = (UINT32) SNPRINTF(pScope, *pScopeLen, CREDENTIAL_SCOPE_TEMPLATE, SIGNATURE_DATE_STRING_LEN, dateTimeStr, pRequestInfo->region, - KINESIS_VIDEO_SERVICE_NAME, AWS_SIG_V4_SIGNATURE_END); + pRequestInfo->service, AWS_SIG_V4_SIGNATURE_END); CHK(scopeLen > 0 && scopeLen <= *pScopeLen, STATUS_BUFFER_TOO_SMALL); CleanUp: @@ -707,15 +725,15 @@ STATUS generateEncodedCredentials(PRequestInfo pRequestInfo, PCHAR dateTimeStr, CHK(pRequestInfo != NULL && dateTimeStr != NULL && pCredsLen != NULL, STATUS_NULL_ARG); // Calculate the max string length with '/' and a null terminator at the end - credsLen = MAX_ACCESS_KEY_LEN + 1 + SIGNATURE_DATE_TIME_STRING_LEN + 1 + MAX_REGION_NAME_LEN + 1 + (UINT32) STRLEN(KINESIS_VIDEO_SERVICE_NAME) + - 1 + (UINT32) STRLEN(AWS_SIG_V4_SIGNATURE_END) + 1; + credsLen = MAX_ACCESS_KEY_LEN + 1 + SIGNATURE_DATE_TIME_STRING_LEN + 1 + MAX_REGION_NAME_LEN + 1 + + (UINT32) STRNLEN(pRequestInfo->service, MAX_SERVICE_NAME_LEN) + 1 + (UINT32) STRLEN(AWS_SIG_V4_SIGNATURE_END) + 1; // Early exit on buffer calculation CHK(pCreds != NULL, retStatus); credsLen = (UINT32) SNPRINTF(pCreds, *pCredsLen, URL_ENCODED_CREDENTIAL_TEMPLATE, pRequestInfo->pAwsCredentials->accessKeyIdLen, pRequestInfo->pAwsCredentials->accessKeyId, SIGNATURE_DATE_STRING_LEN, dateTimeStr, pRequestInfo->region, - KINESIS_VIDEO_SERVICE_NAME, AWS_SIG_V4_SIGNATURE_END); + pRequestInfo->service, AWS_SIG_V4_SIGNATURE_END); CHK(credsLen > 0 && credsLen <= *pCredsLen, STATUS_BUFFER_TOO_SMALL); CleanUp: diff --git a/src/source/Common/AwsV4Signer.h b/src/source/Common/AwsV4Signer.h index 951c7f068..ea9a7f622 100644 --- a/src/source/Common/AwsV4Signer.h +++ b/src/source/Common/AwsV4Signer.h @@ -51,14 +51,14 @@ extern "C" { #define AUTH_HEADER_TEMPLATE "%s Credential=%.*s/%s, SignedHeaders=%.*s, Signature=%s" // Authentication query template -#define AUTH_QUERY_TEMPLATE "&X-Amz-Algorithm=%s&X-Amz-Credential=%s&X-Amz-Date=%s&X-Amz-Expires=%u&X-Amz-SignedHeaders=%.*s" +#define AUTH_QUERY_TEMPLATE "?X-Amz-Algorithm=%s&X-Amz-Credential=%s&X-Amz-Date=%s&X-Amz-Expires=%u&X-Amz-SignedHeaders=%.*s" // Token query param template #define SECURITY_TOKEN_PARAM_TEMPLATE "&X-Amz-Security-Token=%s" // Authentication query template #define AUTH_QUERY_TEMPLATE_WITH_TOKEN \ - "&X-Amz-Algorithm=%s&X-Amz-Credential=%s&X-Amz-Date=%s&X-Amz-Expires=%u&X-Amz-SignedHeaders=%.*s" SECURITY_TOKEN_PARAM_TEMPLATE + "?X-Amz-Algorithm=%s&X-Amz-Credential=%s&X-Amz-Date=%s&X-Amz-Expires=%u&X-Amz-SignedHeaders=%.*s" SECURITY_TOKEN_PARAM_TEMPLATE // Signature query param template #define SIGNATURE_PARAM_TEMPLATE "&X-Amz-Signature=%s" @@ -82,6 +82,8 @@ extern "C" { #define KVS_MAX_HMAC_SIZE 64 +#define PREDEFINED_UNSIGNED_PAYLOAD "UNSIGNED-PAYLOAD" + //////////////////////////////////////////////////// // Function definitions ////////////////////////////////////////////////////