static void TEST_URL_Encoding(void) { typedef struct { const char* src_buf; size_t src_size; size_t src_read; const char* dst_buf; size_t dst_size; size_t dst_written; int/*bool*/ ok; } STestArg; static const STestArg s_TestEncode[] = { { "", 0, 0, "", 0, 0, 1/*true*/ }, { "abc", 3, 3, "abc", 3, 3, 1/*true*/ }, { "_ _%_;_\n_", 7, 0, "", 0, 0, 1/*true*/ }, { "_ _%_;_\n_", 0, 0, "", 0, 0, 1/*true*/ }, { "_ _%_;_\n_", 0, 0, "", 7, 0, 1/*true*/ }, { "_ _%_;_\n_:_\\_\"_", 15, 15, "_+_%25_%3B_%0A_%3A_%5C_%22_", 27, 27, 1/*true*/ }, { "_ _%_;_\n_:_\\_\"_", 15, 13, "_+_%25_%3B_%0A_%3A_%5C_%22_", 25, 23, 1/*true*/ }, { "_%_", 3, 1, "_%25_", 2, 1, 1/*true*/ }, { "_ _%_;_\n_", 7, 7, "_+_%25_%3B_%0A", 100, 11, 1/*true*/ } }; static const STestArg s_TestDecode[] = { { "", 0, 0, "", 0, 0, 1/*true*/ }, { "%25", 1, 0, "", 0, 0, 1/*true*/ }, { "%25", 2, 0, "", 0, 0, 1/*true*/ }, { "%25", 3, 3, "%", 1, 1, 1/*true*/ }, { "%25", 3, 0, "%", 0, 0, 1/*true*/ }, { "%%%", 2, 0, "", 1, 0, 0/*false*/ }, { "%%%", 3, 0, "", 1, 0, 0/*false*/ }, { "%xy", 3, 0, "", 1, 0, 0/*false*/ }, { "\n", 1, 0, "", 1, 0, 0/*false*/ }, { "a\t", 2, 1, "a", 1, 1, 1/*true*/ }, { "#\n", 1, 0, "", 0, 0, 1/*true*/ }, { "%a-", 3, 0, "", 1, 0, 0/*false*/ }, { "%a-", 3, 0, "", 0, 0, 1/*true*/ }, { "_+_%25_%3B_%0A_%3A_%5C_%22_", 27, 27, "_ _%_;_\n_:_\\_\"_", 15, 15, 1/*true*/ }, { "_+_%25_%3B_%0A_%3A_%5C_%22_", 25, 23, "_ _%_;_\n_:_\\_\"_", 13, 13, 1/*true*/ }, { "_+_%25_%3B_%0A_%3A_%5C_%22_", 27, 23, "_ _%_;_\n_:_\\_\"_", 13, 13, 1/*true*/ } }; static const STestArg s_TestDecodeEx[] = { { "", 0, 0, "", 0, 0, 1/*true*/ }, { "%25", 3, 0, "%", 0, 0, 1/*true*/ }, { "%%%", 2, 0, "", 1, 0, 0/*false*/ }, { "%xy", 3, 0, "", 1, 0, 0/*false*/ }, { "\n", 1, 0, "", 1, 0, 0/*false*/ }, { ">>a", 3, 3, ">>a", 3, 3, 1/*true*/ }, { ">b[", 3, 3, ">b[", 4, 3, 1/*true*/ }, { ">b]", 3, 2, ">b", 3, 2, 1/*true*/ }, { "[b]", 3, 2, "[b", 3, 2, 1/*true*/ }, { "<b>", 3, 0, "", 3, 0, 0/*false*/ }, { "<e>", 3, 0, "", 5, 0, 0/*false*/ } }; size_t i; size_t src_read, dst_written; char dst[1024]; #define ARRAY_DIM(arr) (sizeof(arr)/sizeof((arr)[0])) CORE_LOG(eLOG_Note, "URL encoding test started"); for (i = 0; i < ARRAY_DIM(s_TestEncode); i++) { const STestArg* arg = &s_TestEncode[i]; URL_Encode(arg->src_buf, arg->src_size, &src_read, dst, arg->dst_size, &dst_written); assert(src_read == arg->src_read); assert(dst_written == arg->dst_written); assert(!dst_written || !memcmp(dst, arg->dst_buf, dst_written)); } for (i = 0; i < ARRAY_DIM(s_TestDecode); i++) { const STestArg* arg = &s_TestDecode[i]; int/*bool*/ ok = URL_Decode(arg->src_buf, arg->src_size, &src_read, dst, arg->dst_size, &dst_written); assert(ok == arg->ok); assert(src_read == arg->src_read); assert(dst_written == arg->dst_written); assert(!dst_written || !memcmp(dst, arg->dst_buf, dst_written)); } for (i = 0; i < ARRAY_DIM(s_TestDecodeEx); i++) { const STestArg* arg = &s_TestDecodeEx[i]; int/*bool*/ ok = URL_DecodeEx(arg->src_buf, arg->src_size, &src_read, dst, arg->dst_size, &dst_written, "[>"); assert(ok == arg->ok); assert(src_read == arg->src_read); assert(dst_written == arg->dst_written); assert(!dst_written || !memcmp(dst, arg->dst_buf, dst_written)); } CORE_LOG(eLOG_Note, "URL encoding test completed"); }
char* prov_auth_construct_sas_token(PROV_AUTH_HANDLE handle, const char* token_scope, const char* key_name, size_t expiry_time) { char* result; char expire_token[64] = { 0 }; if (handle == NULL || token_scope == NULL || key_name == NULL) { LogError("Invalid handle parameter handle: %p, token_scope: %p, key_name: %p", handle, token_scope, key_name); result = NULL; } else if (handle->sec_type == PROV_AUTH_TYPE_X509) { LogError("Invalid type for operation"); result = NULL; } else if (size_tToString(expire_token, sizeof(expire_token), expiry_time) != 0) { result = NULL; LogError("Failure creating expire token"); } else { size_t len = strlen(token_scope) + strlen(expire_token) + 3; char* payload = malloc(len + 1); if (payload == NULL) { result = NULL; LogError("Failure allocating payload for sas token."); } else { unsigned char* data_value; size_t data_len; (void)sprintf(payload, "%s\n%s", token_scope, expire_token); /* Codes_SRS_SECURE_ENCLAVE_CLIENT_07_031: [ prov_auth_get_certificate shall import the specified cert into the client using hsm_client_get_cert secure enclave function. ] */ if (sign_sas_data(handle, payload, &data_value, &data_len) == 0) { STRING_HANDLE urlEncodedSignature; STRING_HANDLE base64Signature; STRING_HANDLE sas_token_handle; if ((base64Signature = Azure_Base64_Encode_Bytes(data_value, data_len)) == NULL) { result = NULL; LogError("Failure constructing base64 encoding."); } else if ((urlEncodedSignature = URL_Encode(base64Signature)) == NULL) { result = NULL; LogError("Failure constructing url Signature."); STRING_delete(base64Signature); } else { sas_token_handle = STRING_construct_sprintf("SharedAccessSignature sr=%s&sig=%s&se=%s&skn=%s", token_scope, STRING_c_str(urlEncodedSignature), expire_token, key_name); if (sas_token_handle == NULL) { result = NULL; LogError("Failure constructing url Signature."); } else { const char* temp_sas_token = STRING_c_str(sas_token_handle); if (mallocAndStrcpy_s(&result, temp_sas_token) != 0) { LogError("Failure allocating and copying string."); result = NULL; } STRING_delete(sas_token_handle); } STRING_delete(base64Signature); STRING_delete(urlEncodedSignature); } free(data_value); } else { result = NULL; LogError("Failure generate sas token."); } free(payload); } } return result; }
STRING_HANDLE SASToken_Create(STRING_HANDLE key, STRING_HANDLE scope, STRING_HANDLE keyName, size_t expiry) { STRING_HANDLE result = NULL; char tokenExpirationTime[32] = { 0 }; /*Codes_SRS_SASTOKEN_06_001: [If key is NULL then SASToken_Create shall return NULL.]*/ /*Codes_SRS_SASTOKEN_06_003: [If scope is NULL then SASToken_Create shall return NULL.]*/ /*Codes_SRS_SASTOKEN_06_007: [If keyName is NULL then SASToken_Create shall return NULL.]*/ if ((key == NULL) || (scope == NULL) || (keyName == NULL)) { LogError("Invalid Parameter to SASToken_Create. handle key: %p, handle scope: %p, handle keyName: %p\r\n", key, scope, keyName); } else { BUFFER_HANDLE decodedKey; /*Codes_SRS_SASTOKEN_06_029: [The key parameter is decoded from base64.]*/ if ((decodedKey = Base64_Decoder(STRING_c_str(key))) == NULL) { /*Codes_SRS_SASTOKEN_06_030: [If there is an error in the decoding then SASToken_Create shall return NULL.]*/ LogError("Unable to decode the key for generating the SAS.\r\n"); } else { /*Codes_SRS_SASTOKEN_06_026: [If the conversion to string form fails for any reason then SASToken_Create shall return NULL.]*/ if (size_tToString(tokenExpirationTime, sizeof(tokenExpirationTime), expiry) != 0) { LogError("For some reason converting seconds to a string failed. No SAS can be generated.\r\n"); } else { STRING_HANDLE toBeHashed = NULL; BUFFER_HANDLE hash = NULL; if (((hash = BUFFER_new()) == NULL) || ((toBeHashed = STRING_new()) == NULL) || ((result = STRING_new()) == NULL)) { LogError("Unable to allocate memory to prepare SAS token.\r\n") } else { /*Codes_SRS_SASTOKEN_06_009: [The scope is the basis for creating a STRING_HANDLE.]*/ /*Codes_SRS_SASTOKEN_06_010: [A "\n" is appended to that string.]*/ /*Codes_SRS_SASTOKEN_06_011: [tokenExpirationTime is appended to that string.]*/ if ((STRING_concat_with_STRING(toBeHashed, scope) != 0) || (STRING_concat(toBeHashed, "\n") != 0) || (STRING_concat(toBeHashed, tokenExpirationTime) != 0)) { LogError("Unable to build the input to the HMAC to prepare SAS token.\r\n"); STRING_delete(result); result = NULL; } else { STRING_HANDLE base64Signature = NULL; STRING_HANDLE urlEncodedSignature = NULL; /*Codes_SRS_SASTOKEN_06_013: [If an error is returned from the HMAC256 function then NULL is returned from SASToken_Create.]*/ /*Codes_SRS_SASTOKEN_06_012: [An HMAC256 hash is calculated using the decodedKey, over toBeHashed.]*/ /*Codes_SRS_SASTOKEN_06_014: [If there are any errors from the following operations then NULL shall be returned.]*/ /*Codes_SRS_SASTOKEN_06_015: [The hash is base 64 encoded.]*/ /*Codes_SRS_SASTOKEN_06_028: [base64Signature shall be url encoded.]*/ /*Codes_SRS_SASTOKEN_06_016: [The string "SharedAccessSignature sr=" is the first part of the result of SASToken_Create.]*/ /*Codes_SRS_SASTOKEN_06_017: [The scope parameter is appended to result.]*/ /*Codes_SRS_SASTOKEN_06_018: [The string "&sig=" is appended to result.]*/ /*Codes_SRS_SASTOKEN_06_019: [The string urlEncodedSignature shall be appended to result.]*/ /*Codes_SRS_SASTOKEN_06_020: [The string "&se=" shall be appended to result.]*/ /*Codes_SRS_SASTOKEN_06_021: [tokenExpirationTime is appended to result.]*/ /*Codes_SRS_SASTOKEN_06_022: [The string "&skn=" is appended to result.]*/ /*Codes_SRS_SASTOKEN_06_023: [The argument keyName is appended to result.]*/ if ((HMACSHA256_ComputeHash(BUFFER_u_char(decodedKey), BUFFER_length(decodedKey), (const unsigned char*)STRING_c_str(toBeHashed), STRING_length(toBeHashed), hash) != HMACSHA256_OK) || ((base64Signature = Base64_Encode(hash)) == NULL) || ((urlEncodedSignature = URL_Encode(base64Signature)) == NULL) || (STRING_copy(result, "SharedAccessSignature sr=") != 0) || (STRING_concat_with_STRING(result, scope) != 0) || (STRING_concat(result, "&sig=") != 0) || (STRING_concat_with_STRING(result, urlEncodedSignature) != 0) || (STRING_concat(result, "&se=") != 0) || (STRING_concat(result, tokenExpirationTime) != 0) || (STRING_concat(result, "&skn=") != 0) || (STRING_concat_with_STRING(result, keyName) != 0)) { LogError("Unable to build the SAS token.\r\n"); STRING_delete(result); result = NULL; } else { /* everything OK */ } STRING_delete(base64Signature); STRING_delete(urlEncodedSignature); } } STRING_delete(toBeHashed); BUFFER_delete(hash); } BUFFER_delete(decodedKey); } } return result; }