diff --git a/common/custom_claims.c b/common/custom_claims.c new file mode 100644 index 0000000000..683c4bb4b6 --- /dev/null +++ b/common/custom_claims.c @@ -0,0 +1,286 @@ +// Copyright (c) Open Enclave SDK contributors. +// Licensed under the MIT License. + +#include +#include +#include +#include + +#include "common.h" + +/** + * Serialized buffer will have a header with version and number of + * claims + */ +typedef struct _oe_custom_claims_header +{ + uint64_t version; + uint64_t num_claims; +} oe_custom_claims_header_t; + +/** + * Serialized entry for custom claims. Each entry will have the name and value + * sizes and then the contents of the name and value respectively. + */ +typedef struct _oe_custom_claims_entry +{ + uint64_t name_size; + uint64_t value_size; + uint8_t name[]; + // name_size bytes follow. + // value_size_bytes follow. +} oe_custom_claims_entry_t; + +oe_result_t oe_free_serialized_custom_claims(uint8_t* custom_claims_buffer) +{ + oe_free(custom_claims_buffer); + return OE_OK; +} + +static void _free_claim(oe_claim_t* claim) +{ + oe_free(claim->name); + oe_free(claim->value); +} + +oe_result_t oe_free_custom_claims(oe_claim_t* claims, size_t claims_length) +{ + if (!claims) + return OE_OK; + + for (size_t i = 0; i < claims_length; i++) + _free_claim(&claims[i]); + oe_free(claims); + return OE_OK; +} + +static oe_result_t _add_claim( + oe_claim_t* claim, + const uint8_t* name, + size_t name_size, // Must cover the '\0' at end of string + const void* value, + size_t value_size) +{ + if (*(name + name_size - 1) != '\0') + return OE_CONSTRAINT_FAILED; + + claim->name = (char*)oe_malloc(name_size); + if (claim->name == NULL) + return OE_OUT_OF_MEMORY; + oe_memcpy_s(claim->name, name_size, name, name_size); + + claim->value = (uint8_t*)oe_malloc(value_size); + if (claim->value == NULL) + { + oe_free(claim->name); + claim->name = NULL; + return OE_OUT_OF_MEMORY; + } + oe_memcpy_s(claim->value, value_size, value, value_size); + claim->value_size = value_size; + + return OE_OK; +} + +static oe_result_t _fill_array_with_custom_claims( + const uint8_t* claims_buffer, + size_t claims_buffer_size, + oe_claim_t* claims) +{ + oe_result_t result = OE_UNEXPECTED; + oe_custom_claims_header_t* header = + (oe_custom_claims_header_t*)claims_buffer; + size_t claims_index = 0; + + if (claims_buffer_size < sizeof(*header)) + { + OE_RAISE(OE_CONSTRAINT_FAILED); + } + + claims_buffer += sizeof(*header); + claims_buffer_size -= sizeof(*header); + for (uint64_t i = 0; i < header->num_claims; i++) + { + oe_custom_claims_entry_t* entry = + (oe_custom_claims_entry_t*)claims_buffer; + uint64_t size = 0; + + // Sanity check sizes. + if (claims_buffer_size < sizeof(*entry)) + OE_RAISE(OE_CONSTRAINT_FAILED); + + OE_CHECK(oe_safe_add_u64(sizeof(*entry), entry->name_size, &size)); + OE_CHECK(oe_safe_add_u64(size, entry->value_size, &size)); + + if (claims_buffer_size < size) + OE_RAISE(OE_CONSTRAINT_FAILED); + + // Add the claim. + OE_CHECK(_add_claim( + &claims[claims_index++], + entry->name, + entry->name_size, + entry->name + entry->name_size, + entry->value_size)); + + OE_CHECK( + oe_safe_sub_u64(claims_buffer_size, size, &claims_buffer_size)); + claims_buffer += size; + } + + result = OE_OK; + +done: + if (result != OE_OK) + { + for (size_t i = 0; i < claims_index; i++) + _free_claim(&claims[i]); + } + return result; +} + +oe_result_t oe_deserialize_custom_claims( + const uint8_t* claims_buffer, + size_t claims_buffer_size, + oe_claim_t** claims_out, + size_t* claims_length_out) +{ + oe_result_t result = OE_UNEXPECTED; + oe_custom_claims_header_t* claims_header = NULL; + oe_claim_t* claims = NULL; + uint64_t claims_length = 0; + uint64_t claims_size = 0; + + if (claims_buffer_size < sizeof(oe_custom_claims_header_t)) + { + OE_RAISE(OE_CONSTRAINT_FAILED); + } + + claims_header = (oe_custom_claims_header_t*)(claims_buffer); + + if (claims_header == NULL) + { + OE_RAISE(OE_INVALID_PARAMETER); + } + + if (claims_header->version != OE_CUSTOM_CLAIMS_VERSION) + { + OE_RAISE(OE_CONSTRAINT_FAILED); + } + + claims_length = claims_header->num_claims; + + OE_CHECK(oe_safe_mul_u64(claims_length, sizeof(oe_claim_t), &claims_size)); + + claims = (oe_claim_t*)oe_malloc(claims_size); + if (claims == NULL) + OE_RAISE(OE_OUT_OF_MEMORY); + + OE_CHECK(_fill_array_with_custom_claims( + claims_buffer, claims_buffer_size, claims)); + + *claims_out = claims; + *claims_length_out = claims_header->num_claims; + claims = NULL; + result = OE_OK; + +done: + if (claims) + oe_free_custom_claims(claims, claims_length); + return result; +} + +static oe_result_t _get_claims_size( + const oe_claim_t* custom_claims, + size_t custom_claims_length, + size_t* size) +{ + oe_result_t result = OE_UNEXPECTED; + + if (!custom_claims) + return OE_OK; + + OE_CHECK(oe_safe_add_u64(*size, sizeof(oe_custom_claims_header_t), size)); + + for (size_t i = 0; i < custom_claims_length; i++) + { + OE_CHECK( + oe_safe_add_u64(*size, sizeof(oe_custom_claims_entry_t), size)); + OE_CHECK( + oe_safe_add_u64(*size, oe_strlen(custom_claims[i].name) + 1, size)); + OE_CHECK(oe_safe_add_u64(*size, custom_claims[i].value_size, size)); + } + result = OE_OK; +done: + return result; +} + +static void _fill_buffer_with_custom_claims( + const oe_claim_t* custom_claims, + size_t custom_claims_length, + uint8_t* claims) +{ + // Custom claims structure would be: + // - oe_custom_claims_header_t + // - N claim entries of oe_sgx_custom_claims_entry_t + // claims buffer is previously allocated with appropriate size, + // copy corresponding values + oe_custom_claims_header_t* header = (oe_custom_claims_header_t*)claims; + header->version = OE_CUSTOM_CLAIMS_VERSION; + header->num_claims = custom_claims ? custom_claims_length : 0; + claims += sizeof(oe_custom_claims_header_t); + + if (!custom_claims) + return; + + for (size_t i = 0; i < custom_claims_length; i++) + { + oe_custom_claims_entry_t* entry = (oe_custom_claims_entry_t*)claims; + entry->name_size = oe_strlen(custom_claims[i].name) + 1; + entry->value_size = custom_claims[i].value_size; + oe_memcpy_s( + entry->name, + entry->name_size, + custom_claims[i].name, + entry->name_size); + oe_memcpy_s( + entry->name + entry->name_size, + entry->value_size, + custom_claims[i].value, + entry->value_size); + // move to next claim + claims += sizeof(*entry) + entry->name_size + entry->value_size; + } +} + +oe_result_t oe_serialize_custom_claims( + const oe_claim_t* custom_claims, + size_t custom_claims_length, + uint8_t** claims_out, + size_t* claims_size_out) +{ + uint8_t* claims = NULL; + size_t claims_size = 0; + oe_result_t result = OE_UNEXPECTED; + + // Get claims size. + OE_CHECK( + _get_claims_size(custom_claims, custom_claims_length, &claims_size)); + + // Allocate memory and set the claims. + claims = (uint8_t*)oe_malloc(claims_size); + if (claims == NULL) + OE_RAISE(OE_OUT_OF_MEMORY); + _fill_buffer_with_custom_claims( + custom_claims, custom_claims_length, claims); + + *claims_out = claims; + *claims_size_out = claims_size; + claims = NULL; + result = OE_OK; + +done: + if (claims != NULL) + oe_free(claims); + return result; +} diff --git a/enclave/CMakeLists.txt b/enclave/CMakeLists.txt index de3cf51b94..d654465cf2 100644 --- a/enclave/CMakeLists.txt +++ b/enclave/CMakeLists.txt @@ -35,6 +35,7 @@ add_enclave_library( STATIC attest_plugin.c ../common/attest_plugin.c + ../common/custom_claims.c ../common/datetime.c ../common/sha.c asym_keys.c diff --git a/host/CMakeLists.txt b/host/CMakeLists.txt index cb64f55fc1..f177ca9848 100644 --- a/host/CMakeLists.txt +++ b/host/CMakeLists.txt @@ -333,6 +333,7 @@ list( APPEND PLATFORM_HOST_ONLY_SRC ../common/attest_plugin.c + ../common/custom_claims.c ../common/datetime.c ../common/safecrt.c ../common/sha.c diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index 6ce559a03b..e98bd5184f 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -33,6 +33,7 @@ install( DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/openenclave/attestation/sgx) install( FILES openenclave/attestation/verifier.h + openenclave/attestation/custom_claims.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/openenclave/attestation/ COMPONENT OEHOSTVERIFY) install( diff --git a/include/openenclave/attestation/custom_claims.h b/include/openenclave/attestation/custom_claims.h new file mode 100644 index 0000000000..a633c10d80 --- /dev/null +++ b/include/openenclave/attestation/custom_claims.h @@ -0,0 +1,79 @@ +// Copyright (c) Open Enclave SDK contributors. +// Licensed under the MIT License. + +#ifndef _OE_CUSTOM_CLAIMS +#define _OE_CUSTOM_CLAIMS + +#include +#include + +OE_EXTERNC_BEGIN +#define OE_CUSTOM_CLAIMS_VERSION 1 + +/** + * oe_free_serialized_custom_claims + * + * Free buffer of serialized custom claims. + * + * @param[in] custom_claims_buffer Serialized Custom claims + * buffer to free. + * @retval OE_OK on success. + */ +oe_result_t oe_free_serialized_custom_claims(uint8_t* custom_claims_buffer); + +/** + * oe_free_custom_claims + * + * Free list of custom claims. + * + * @param[in] custom_claims Custom claims array to free. + * @param[in] custom_claims_length Length of custom_claims. + * @retval OE_OK on success. + */ +oe_result_t oe_free_custom_claims( + oe_claim_t* custom_claims, + size_t custom_claims_length); + +/** + * oe_serialize_custom_claims + * + * Serializes a list of custom claims. + * + * @param[in] custom_claims Custom claims to serialize. + * @param[in] custom_claims_length Length of custom_claims. + * @param[out] claims_out Pointer to the address of a dynamically + * allocated buffer holding the serialized custom claims. + * @param[out] claims_size_out Size of the serialized custom claims. + * @retval OE_OK on success. + * @retval OE_INVALID_PARAMETER At least one parameter is invalid. + * @retval An appropriate error code on failure. + */ +oe_result_t oe_serialize_custom_claims( + const oe_claim_t* custom_claims, + size_t custom_claims_length, + uint8_t** claims_out, + size_t* claims_size_out); + +/** + * oe_deserialize_custom_claims + * + * Deserialize custom claim buffer + * + * @param[in] claims_buffer Pointer to the serialized custom claims buffer. + * @param[in] claims_buffer_size Size of the serialized custom claims buffer + * buffer. + * @param[out] claims_out Pointer to the address of a dynamically allocated + * buffer holding the list of custom claims. + * @param[out] claims_length_out The length of the claims_out list. + * @retval OE_OK on success. + * @retval OE_INVALID_PARAMETER At least one parameter is invalid. + * @retval An appropriate error code on failure. + */ +oe_result_t oe_deserialize_custom_claims( + const uint8_t* claims_buffer, + size_t claims_buffer_size, + oe_claim_t** claims_out, + size_t* claims_length_out); +OE_EXTERNC_END + +#endif //_OE_CUSTOM_CLAIMS diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d14edcff32..c346d771d2 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -85,6 +85,7 @@ if (UNIX add_subdirectory(child_thread) add_subdirectory(cppException) add_subdirectory(crypto_crls_cert_chains) + add_subdirectory(custom_claims) add_subdirectory(debug-mode) add_subdirectory(ecall) add_subdirectory(ecall_ocall) diff --git a/tests/custom_claims/CMakeLists.txt b/tests/custom_claims/CMakeLists.txt new file mode 100644 index 0000000000..69324b9b47 --- /dev/null +++ b/tests/custom_claims/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright (c) Open Enclave SDK contributors. +# Licensed under the MIT License. + +add_subdirectory(host) + +if (BUILD_ENCLAVES) + add_subdirectory(enc) +endif () + +add_enclave_test(tests/custom_claims custom_claims_host custom_claims_enc) diff --git a/tests/custom_claims/custom_claims.edl b/tests/custom_claims/custom_claims.edl new file mode 100644 index 0000000000..31682c783c --- /dev/null +++ b/tests/custom_claims/custom_claims.edl @@ -0,0 +1,17 @@ +// Copyright (c) Open Enclave SDK contributors. +// Licensed under the MIT License. + +enclave { + from "openenclave/edl/logging.edl" import oe_write_ocall; + from "openenclave/edl/fcntl.edl" import *; +#ifdef OE_SGX + from "openenclave/edl/sgx/platform.edl" import *; +#else + from "openenclave/edl/optee/platform.edl" import *; +#endif + + trusted { + public int enc_custom_claims(); + }; + +}; diff --git a/tests/custom_claims/enc/CMakeLists.txt b/tests/custom_claims/enc/CMakeLists.txt new file mode 100644 index 0000000000..49860dae37 --- /dev/null +++ b/tests/custom_claims/enc/CMakeLists.txt @@ -0,0 +1,25 @@ +# Copyright (c) Open Enclave SDK contributors. +# Licensed under the MIT License. + +set(EDL_FILE ../custom_claims.edl) + +add_custom_command( + OUTPUT custom_claims_t.h custom_claims_t.c + DEPENDS ${EDL_FILE} edger8r + COMMAND + edger8r --trusted ${EDL_FILE} --search-path ${PROJECT_SOURCE_DIR}/include + ${DEFINE_OE_SGX} --search-path ${CMAKE_CURRENT_SOURCE_DIR}) + +add_enclave( + TARGET + custom_claims_enc + UUID + 8479af9f-2ee8-4ccd-8336-8696dde57a11 + SOURCES + enc.c + ../test_common/tests.c + ${CMAKE_CURRENT_BINARY_DIR}/custom_claims_t.c) + +enclave_include_directories(custom_claims_enc PRIVATE + ${CMAKE_CURRENT_BINARY_DIR}) +enclave_link_libraries(custom_claims_enc oelibc) diff --git a/tests/custom_claims/enc/enc.c b/tests/custom_claims/enc/enc.c new file mode 100644 index 0000000000..91c815394d --- /dev/null +++ b/tests/custom_claims/enc/enc.c @@ -0,0 +1,23 @@ +// Copyright (c) Open Enclave SDK contributors. +// Licensed under the MIT License. + +#include + +#include "../test_common/tests.h" +#include "custom_claims_t.h" + +int enc_custom_claims() +{ + printf("====== begin custom claim enclave tests\n"); + _test_custom_claims_seriaize_deserialize(); + printf("====== end custom claim enclave tests\n"); + return 0; +} + +OE_SET_ENCLAVE_SGX( + 1, /* ProductID */ + 1, /* SecurityVersion */ + true, /* Debug */ + 1024, /* NumHeapPages */ + 1024, /* NumStackPages */ + 2); /* NumTCS */ diff --git a/tests/custom_claims/host/CMakeLists.txt b/tests/custom_claims/host/CMakeLists.txt new file mode 100644 index 0000000000..3ddf35d39b --- /dev/null +++ b/tests/custom_claims/host/CMakeLists.txt @@ -0,0 +1,18 @@ +# Copyright (c) Open Enclave SDK contributors. +# Licensed under the MIT License. + +set(EDL_FILE ../custom_claims.edl) + +add_custom_command( + OUTPUT custom_claims_u.h custom_claims_u.c + DEPENDS ${EDL_FILE} edger8r + COMMAND + edger8r --untrusted ${EDL_FILE} --search-path ${PROJECT_SOURCE_DIR}/include + ${DEFINE_OE_SGX} --search-path ${CMAKE_CURRENT_SOURCE_DIR}) + +add_executable(custom_claims_host host.c ../test_common/tests.c + custom_claims_u.c) + +target_include_directories(custom_claims_host + PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) +target_link_libraries(custom_claims_host oehost) diff --git a/tests/custom_claims/host/host.c b/tests/custom_claims/host/host.c new file mode 100644 index 0000000000..1b25e4f94b --- /dev/null +++ b/tests/custom_claims/host/host.c @@ -0,0 +1,45 @@ +// Copyright (c) Open Enclave SDK contributors. +// Licensed under the MIT License. + +#include + +#include "../test_common/tests.h" +#include "custom_claims_u.h" + +int main(int argc, const char* argv[]) +{ + oe_result_t result; + oe_enclave_t* enclave = NULL; + + if (argc != 2) + { + fprintf(stderr, "Usage: %s ENCLAVE_PATH\n", argv[0]); + return 1; + } + + const uint32_t flags = oe_get_create_flags(); + + if ((result = oe_create_custom_claims_enclave( + argv[1], OE_ENCLAVE_TYPE_AUTO, flags, NULL, 0, &enclave)) != OE_OK) + oe_put_err("oe_create_enclave(): result=%u", result); + + int return_val; + + result = enc_custom_claims(enclave, &return_val); + + if (result != OE_OK) + oe_put_err("oe_call_enclave() failed: result=%u", result); + + if (return_val != 0) + oe_put_err("ECALL failed args.result=%d", return_val); + + result = oe_terminate_enclave(enclave); + if (result != OE_OK) + oe_put_err("oe_terminate_enclave() failed: result=%u", result); + + printf("=== begin custom claim host tests\n"); + _test_custom_claims_seriaize_deserialize(); + printf("=== end custom claim host tests\n"); + + return 0; +} diff --git a/tests/custom_claims/test_common/tests.c b/tests/custom_claims/test_common/tests.c new file mode 100644 index 0000000000..90c9584bae --- /dev/null +++ b/tests/custom_claims/test_common/tests.c @@ -0,0 +1,55 @@ +// Copyright (c) Open Enclave SDK contributors. +// Licensed under the MIT License. + +#include "tests.h" + +void _test_custom_claims_seriaize_deserialize() +{ + printf("====== begin _test_custom_claims_seriaize_deserialize\n"); + uint8_t* claims_out = NULL; + size_t claims_size_out = 0; + oe_claim_t* claims1 = NULL; + size_t claims_len = 0; + + oe_claim_t custom_claims[2] = {{.name = CLAIM1_NAME, + .value = (uint8_t*)CLAIM1_VALUE, + .value_size = sizeof(CLAIM1_VALUE)}, + {.name = CLAIM2_NAME, + .value = (uint8_t*)CLAIM2_VALUE, + .value_size = sizeof(CLAIM2_VALUE)}}; + + printf("====== _test_custom_claims_seriaize_deserialize call " + "oe_claims_serialize\n"); + OE_TEST( + oe_serialize_custom_claims( + custom_claims, 2, &claims_out, &claims_size_out) == OE_OK); + + printf("====== _test_custom_claims_serde call oe_claims_deserialize\n"); + OE_TEST( + oe_deserialize_custom_claims( + claims_out, claims_size_out, &claims1, &claims_len) == OE_OK); + + OE_TEST(strcmp(claims1[0].name, CLAIM1_NAME) == 0); + OE_TEST(strcmp((char*)claims1[0].value, CLAIM1_VALUE) == 0); + OE_TEST(strcmp(claims1[1].name, CLAIM2_NAME) == 0); + OE_TEST(strcmp((char*)claims1[1].value, CLAIM2_VALUE) == 0); + OE_TEST(claims_len == 2); + + for (size_t i = 0; i < claims_len; ++i) + { + printf( + "====== _test_custom_claims_seriaize_deserialize claim %s %s\n", + claims1[i].name, + claims1[i].value); + } + + OE_TEST(oe_free_custom_claims(claims1, claims_len) == OE_OK); + claims_len = 0; + claims1 = NULL; + + OE_TEST(oe_free_serialized_custom_claims(claims_out) == OE_OK); + claims_out = NULL; + claims_size_out = 0; + + printf("====== end _test_custom_claims_seriaize_deserialize\n"); +} diff --git a/tests/custom_claims/test_common/tests.h b/tests/custom_claims/test_common/tests.h new file mode 100644 index 0000000000..28421e1d1d --- /dev/null +++ b/tests/custom_claims/test_common/tests.h @@ -0,0 +1,25 @@ +// Copyright (c) Open Enclave SDK contributors. +// Licensed under the MIT License. + +#ifndef _CUSTOM_CLAIMS_TESTS +#define _CUSTOM_CLAIMS_TESTS + +#include +#include +#include +#include + +#include +#include +#include + +#include "../../../common/common.h" + +#define CLAIM1_NAME "Claim1" +#define CLAIM1_VALUE "Value1" +#define CLAIM2_NAME "Claim2" +#define CLAIM2_VALUE "Value2" + +void _test_custom_claims_seriaize_deserialize(); + +#endif // _CUSTOM_CLAIMS_TESTS