From f329064aa2b4a041c531543a4cc8bf3087a425df Mon Sep 17 00:00:00 2001 From: Daniel Adam Date: Fri, 10 Mar 2023 19:45:02 +0100 Subject: [PATCH] Fix issues reported by SonarCloud --- CMakeLists.txt | 2 +- api/README.MD | 83 +++++ api/cloud/oc_cloud.c | 26 +- api/cloud/oc_cloud_access.c | 17 +- api/cloud/oc_cloud_access_internal.h | 14 +- api/cloud/oc_cloud_context.c | 2 +- api/cloud/oc_cloud_deregister.c | 6 +- api/cloud/oc_cloud_internal.h | 1 - api/cloud/oc_cloud_manager.c | 13 +- api/cloud/oc_cloud_store.c | 42 +-- api/cloud/unittest/cloud_store_test.cpp | 97 ++--- api/cloud/unittest/cloud_test.cpp | 14 - api/oc_client_role.c | 4 +- api/oc_core_res.c | 5 +- api/oc_discovery.c | 9 +- api/oc_endpoint.c | 12 +- api/oc_helpers.c | 74 ++-- api/oc_introspection.c | 3 +- api/oc_main.c | 5 +- api/oc_rep_internal.h | 2 +- api/oc_server_api.c | 8 +- api/oc_swupdate.c | 40 +- api/unittest/resourcetest.cpp | 1 + api/unittest/storagetest.cpp | 1 + apps/client_certification_tests.c | 20 +- apps/cloud_client.c | 5 +- apps/secure_mcast_client.c | 6 +- apps/smart_lock_linux.c | 5 +- include/oc_cred.h | 4 +- include/oc_endpoint.h | 4 +- include/oc_helpers.h | 17 +- onboarding_tool/obtmain.c | 16 +- port/linux/Makefile | 2 +- port/unittest/connectivitytest.cpp | 240 ++++++------ port/windows/vs2015/IoTivity-lite.vcxproj | 2 +- .../vs2015/IoTivity-lite.vcxproj.filters | 2 +- python/oc_python.c | 4 +- security/oc_acl.c | 89 ++--- security/oc_ael.c | 50 ++- security/oc_ael.h | 2 +- security/oc_cred.c | 162 ++++---- security/oc_cred_internal.h | 37 +- security/oc_csr.c | 2 +- security/oc_obt.c | 40 +- security/oc_obt_otm_cert.c | 10 +- security/oc_obt_otm_justworks.c | 10 +- security/oc_obt_otm_randompin.c | 10 +- security/oc_pki.c | 51 ++- security/oc_pstat.c | 337 +++++++++-------- security/oc_pstat.h | 20 +- security/oc_sdi.c | 327 +++++++++++------ security/oc_sdi.h | 50 --- security/oc_sdi_internal.h | 139 +++++++ security/oc_sp.c | 111 +++--- security/oc_sp_internal.h | 29 ++ security/oc_store.c | 202 ++++------ security/oc_svr.c | 10 +- security/unittest/acltest.cpp | 4 +- security/unittest/credtest.cpp | 116 ++++++ security/unittest/keypairtest.cpp | 3 +- security/unittest/pstattest.cpp | 42 ++- security/unittest/sditest.cpp | 345 ++++++++++++++++++ security/unittest/sptest.cpp | 58 ++- tests/gtest/Device.cpp | 2 +- tests/gtest/Device.h | 2 +- tests/gtest/RepPool.cpp | 2 + util/oc_mem_trace.c | 4 +- util/oc_mmem.c | 4 +- 68 files changed, 1944 insertions(+), 1134 deletions(-) create mode 100644 api/README.MD delete mode 100644 security/oc_sdi.h create mode 100644 security/oc_sdi_internal.h create mode 100644 security/unittest/credtest.cpp create mode 100644 security/unittest/sditest.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 04ed611848..22855a6882 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -822,7 +822,7 @@ if(BUILD_TESTING AND(UNIX OR MINGW)) file(GLOB PLATFORMTEST_SRC port/unittest/*.cpp) file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/storage_test) - package_add_test(platformtest ${PLATFORMTEST_SRC}) + package_add_test(platformtest ${COMMONTEST_SRC} ${PLATFORMTEST_SRC}) file(GLOB MESSAGINGTEST_SRC messaging/coap/unittest/*.cpp) package_add_test(messagingtest ${MESSAGINGTEST_SRC}) diff --git a/api/README.MD b/api/README.MD new file mode 100644 index 0000000000..cca6bc3db8 --- /dev/null +++ b/api/README.MD @@ -0,0 +1,83 @@ +# Features + +## Dynamic and static allocation + +Whether dynamic or static allocation is enabled is determined by the macro `OC_DYNAMIC_ALLOCATION`. + +It effects the structures that are aliases of `struct oc_mmem` (`oc_handle_t`, `oc_string_t`, `oc_array_t`, `oc_string_array_t,` and `oc_byte_string_array_t`), which are allocated by `_oc_mmem_alloc` and deallocated by `_oc_mmem_free`. + +With dynamic allocation standard `malloc` and `free` calls are used. + +### Static allocation + +With static allocation preallocated static buffers are used. + +Allocation: + +* Take the desired number of bytes from the start of the unused part of the static buffer (if there are not enough available bytes in the buffer then `NULL` is returned) +* Append the allocated variable to a global linked list of allocated variables + +Deallocation: + +* Reallocate data of all variables allocated after the variable currently being deallocated (ie they appear later in the global linked list) and write over the bytes previously used by the deallocated variable. +* Increase the number of available bytes in the static buffer by the size of the deallocated variable. + +#### Pitfalls + +* Be careful when passing `oc_handle_t`, `oc_string_t`, `oc_array_t`, `oc_string_array_t,` and `oc_byte_string_array_t` by value. + +On allocation the pointer of the allocated variable is stored in the global linked list of allocations. If you copy a variable by value then pointer to this copy won't be in the global linked list and if you attempt a deallocation with this copy you will cause memory corruption. + +Invalid code: + +```C +oc_string_t str1; +oc_new_string(&str, "test", strlen("test")); + +oc_string_t str2 = str1; +oc_free_string(&str2); // error, memory corruption + +``` + +Valid code: + +```C +oc_string_t str1; +oc_new_string(&str, "test", strlen("test")); + +oc_string_t str2; +oc_copy_string(&str2, &str1); +``` + +* Be careful when storing pointer to internal data of a `oc_handle_t`, `oc_string_t`, `oc_array_t`, `oc_string_array_t,` and `oc_byte_string_array_t` variable. + +If you store a pointer to internal data of a variable and then another variable, that has been allocated sooner is deallocated, then the stored pointer is invalidated. + +Invalid code: + +```C +oc_string_t first; +oc_new_string(&first, "first", strlen("first")); + +oc_string_t second; +oc_new_string(&second, "second", strlen("second")); + + +const char* second_str = oc_string(second); +oc_free_string(&first); // second_str is now invalidated, because the variable second was allocated later and thus its internal data is reallocated after the variable first is deallocated + +printf("%s", second_str); +``` + +Valid code: + +```C +oc_string_t first; +oc_new_string(&first, "first", strlen("first")); + +oc_string_t second; +oc_new_string(&second, "second", strlen("second")); + +oc_free_string(&first); +printf("%s", oc_string(second)); +``` diff --git a/api/cloud/oc_cloud.c b/api/cloud/oc_cloud.c index ba8ec39db1..c25a3cde62 100644 --- a/api/cloud/oc_cloud.c +++ b/api/cloud/oc_cloud.c @@ -78,19 +78,6 @@ cloud_manager_cb(oc_cloud_context_t *ctx) } } -void -cloud_set_string(oc_string_t *dst, const char *data, size_t len) -{ - if (oc_string(*dst)) { - oc_free_string(dst); - } - if (data && len) { - oc_new_string(dst, data, len); - } else { - memset(dst, 0, sizeof(*dst)); - } -} - static oc_event_callback_retval_t start_manager(void *user_data) { @@ -166,19 +153,18 @@ cloud_set_cloudconf(oc_cloud_context_t *ctx, const cloud_conf_update_t *data) assert(ctx != NULL); assert(data != NULL); if (data->auth_provider && data->auth_provider_len) { - cloud_set_string(&ctx->store.auth_provider, data->auth_provider, - data->auth_provider_len); + oc_set_string(&ctx->store.auth_provider, data->auth_provider, + data->auth_provider_len); } if (data->access_token && data->access_token_len) { - cloud_set_string(&ctx->store.access_token, data->access_token, - data->access_token_len); + oc_set_string(&ctx->store.access_token, data->access_token, + data->access_token_len); } if (data->ci_server && data->ci_server_len) { - cloud_set_string(&ctx->store.ci_server, data->ci_server, - data->ci_server_len); + oc_set_string(&ctx->store.ci_server, data->ci_server, data->ci_server_len); } if (data->sid && data->sid_len) { - cloud_set_string(&ctx->store.sid, data->sid, data->sid_len); + oc_set_string(&ctx->store.sid, data->sid, data->sid_len); } } diff --git a/api/cloud/oc_cloud_access.c b/api/cloud/oc_cloud_access.c index de780cc059..e13f8b3e5e 100644 --- a/api/cloud/oc_cloud_access.c +++ b/api/cloud/oc_cloud_access.c @@ -141,15 +141,16 @@ oc_cloud_access_register(oc_cloud_access_conf_t conf, const char *auth_provider, return oc_do_post(); } -oc_string_t +void cloud_access_deregister_query(const char *uid, const char *access_token, - size_t device) + size_t device, oc_string_t *query) { + assert(query != NULL); oc_string_t q_uid; oc_concat_strings(&q_uid, "uid=", uid); char uuid[OC_UUID_LEN] = { 0 }; - oc_uuid_to_str(oc_core_get_device_id(device), uuid, OC_UUID_LEN); + oc_uuid_to_str(oc_core_get_device_id(device), uuid, sizeof(uuid)); oc_string_t q_di; oc_concat_strings(&q_di, "&di=", uuid); oc_string_t q_uid_di; @@ -157,18 +158,16 @@ cloud_access_deregister_query(const char *uid, const char *access_token, oc_free_string(&q_uid); oc_free_string(&q_di); - oc_string_t q_uid_di_at; if (access_token != NULL) { oc_string_t q_at; oc_concat_strings(&q_at, "&accesstoken=", access_token); - oc_concat_strings(&q_uid_di_at, oc_string(q_uid_di), oc_string(q_at)); + oc_concat_strings(query, oc_string(q_uid_di), oc_string(q_at)); oc_free_string(&q_at); } else { - oc_new_string(&q_uid_di_at, oc_string(q_uid_di), oc_string_len(q_uid_di)); + oc_new_string(query, oc_string(q_uid_di), oc_string_len(q_uid_di)); } oc_free_string(&q_uid_di); - return q_uid_di_at; } bool @@ -187,8 +186,8 @@ oc_cloud_access_deregister(oc_cloud_access_conf_t conf, const char *uid, } #endif /* OC_SECURITY */ - oc_string_t query = - cloud_access_deregister_query(uid, access_token, conf.device); + oc_string_t query; + cloud_access_deregister_query(uid, access_token, conf.device, &query); bool s; if (conf.timeout > 0) { diff --git a/api/cloud/oc_cloud_access_internal.h b/api/cloud/oc_cloud_access_internal.h index a80536baba..210ecd6cf3 100644 --- a/api/cloud/oc_cloud_access_internal.h +++ b/api/cloud/oc_cloud_access_internal.h @@ -34,11 +34,17 @@ extern "C" { /** * @brief Generate URI query for deregister request. * - * @return URI query, must be freed by caller + * The format of the generated string is uid=${uid}&di={device + * uuid}&at=${access_token} or uid=${uid}&di={device uuid} based on whether + * access token is NULL or not. + * + * @param uid uid (cannot be NULL) + * @param access_token access token + * @param device device index + * @param query output variable (cannot be NULL) */ -oc_string_t cloud_access_deregister_query(const char *uid, - const char *access_token, - size_t device); +void cloud_access_deregister_query(const char *uid, const char *access_token, + size_t device, oc_string_t *query); #ifdef __cplusplus } #endif diff --git a/api/cloud/oc_cloud_context.c b/api/cloud/oc_cloud_context.c index 7caf01a3a5..0ed25643ba 100644 --- a/api/cloud/oc_cloud_context.c +++ b/api/cloud/oc_cloud_context.c @@ -177,7 +177,7 @@ cloud_context_has_permanent_access_token(const oc_cloud_context_t *ctx) void cloud_context_clear_access_token(oc_cloud_context_t *ctx) { - cloud_set_string(&ctx->store.access_token, NULL, 0); + oc_set_string(&ctx->store.access_token, NULL, 0); ctx->store.expires_in = 0; } diff --git a/api/cloud/oc_cloud_deregister.c b/api/cloud/oc_cloud_deregister.c index 28f2d73aca..e08ba21d8b 100644 --- a/api/cloud/oc_cloud_deregister.c +++ b/api/cloud/oc_cloud_deregister.c @@ -157,8 +157,10 @@ check_accesstoken_for_deregister(oc_cloud_context_t *ctx) // to the request query if the resulting query size is within the limit. #define DEREGISTER_EMPTY_QUERY_HEADER_SIZE 38 - oc_string_t query = cloud_access_deregister_query( - oc_string(ctx->store.uid), oc_string(ctx->store.access_token), ctx->device); + oc_string_t query; + cloud_access_deregister_query(oc_string(ctx->store.uid), + oc_string(ctx->store.access_token), ctx->device, + &query); size_t query_size = oc_string_len(query); oc_free_string(&query); diff --git a/api/cloud/oc_cloud_internal.h b/api/cloud/oc_cloud_internal.h index d1941a0a45..4f0a57a561 100644 --- a/api/cloud/oc_cloud_internal.h +++ b/api/cloud/oc_cloud_internal.h @@ -83,7 +83,6 @@ void cloud_reset_delayed_callback_ms(void *cb_data, oc_trigger_t callback, uint64_t milliseconds); void cloud_manager_cb(oc_cloud_context_t *ctx); -void cloud_set_string(oc_string_t *dst, const char *data, size_t len); void cloud_set_last_error(oc_cloud_context_t *ctx, oc_cloud_error_t error); void cloud_set_cps(oc_cloud_context_t *ctx, oc_cps_t cps); void cloud_set_cps_and_last_error(oc_cloud_context_t *ctx, oc_cps_t cps, diff --git a/api/cloud/oc_cloud_manager.c b/api/cloud/oc_cloud_manager.c index 06bdded958..8b60290b2a 100644 --- a/api/cloud/oc_cloud_manager.c +++ b/api/cloud/oc_cloud_manager.c @@ -256,10 +256,9 @@ cloud_manager_handle_register_response(oc_cloud_context_t *ctx, return false; } - cloud_set_string(&ctx->store.access_token, access_token, access_token_size); - cloud_set_string(&ctx->store.refresh_token, refresh_token, - refresh_token_size); - cloud_set_string(&ctx->store.uid, uid, uid_size); + oc_set_string(&ctx->store.access_token, access_token, access_token_size); + oc_set_string(&ctx->store.refresh_token, refresh_token, refresh_token_size); + oc_set_string(&ctx->store.uid, uid, uid_size); ctx->store.expires_in = expires_in; if (ctx->store.expires_in > 0) { ctx->store.status |= OC_CLOUD_TOKEN_EXPIRY; @@ -285,7 +284,7 @@ cloud_manager_handle_redirect_response(oc_cloud_context_t *ctx, memset(ctx->cloud_ep, 0, sizeof(oc_endpoint_t)); ctx->cloud_ep_state = OC_SESSION_DISCONNECTED; } - cloud_set_string(&ctx->store.ci_server, value, size); + oc_set_string(&ctx->store.ci_server, value, size); return true; } @@ -699,8 +698,8 @@ cloud_manager_handle_refresh_token_response(oc_cloud_context_t *ctx, return false; } - cloud_set_string(&ctx->store.access_token, access_value, access_size); - cloud_set_string(&ctx->store.refresh_token, refresh_value, refresh_size); + oc_set_string(&ctx->store.access_token, access_value, access_size); + oc_set_string(&ctx->store.refresh_token, refresh_value, refresh_size); ctx->store.expires_in = expires_in; if (ctx->store.expires_in > 0) { ctx->store.status |= OC_CLOUD_TOKEN_EXPIRY; diff --git a/api/cloud/oc_cloud_store.c b/api/cloud/oc_cloud_store.c index b43717b06e..dd81b81a90 100644 --- a/api/cloud/oc_cloud_store.c +++ b/api/cloud/oc_cloud_store.c @@ -189,38 +189,38 @@ cloud_store_parse_string_property(const oc_rep_t *rep, oc_cloud_store_t *store) assert(rep->type == OC_REP_STRING); if (oc_rep_is_property(rep, CLOUD_XSTR(CLOUD_CI_SERVER), CLOUD_XSTRLEN(CLOUD_CI_SERVER))) { - cloud_set_string(&store->ci_server, oc_string(rep->value.string), - oc_string_len(rep->value.string)); + oc_set_string(&store->ci_server, oc_string(rep->value.string), + oc_string_len(rep->value.string)); return true; } if (oc_rep_is_property(rep, CLOUD_XSTR(CLOUD_SID), CLOUD_XSTRLEN(CLOUD_SID))) { - cloud_set_string(&store->sid, oc_string(rep->value.string), - oc_string_len(rep->value.string)); + oc_set_string(&store->sid, oc_string(rep->value.string), + oc_string_len(rep->value.string)); return true; } if (oc_rep_is_property(rep, CLOUD_XSTR(CLOUD_AUTH_PROVIDER), CLOUD_XSTRLEN(CLOUD_AUTH_PROVIDER))) { - cloud_set_string(&store->auth_provider, oc_string(rep->value.string), - oc_string_len(rep->value.string)); + oc_set_string(&store->auth_provider, oc_string(rep->value.string), + oc_string_len(rep->value.string)); return true; } if (oc_rep_is_property(rep, CLOUD_XSTR(CLOUD_UID), CLOUD_XSTRLEN(CLOUD_UID))) { - cloud_set_string(&store->uid, oc_string(rep->value.string), - oc_string_len(rep->value.string)); + oc_set_string(&store->uid, oc_string(rep->value.string), + oc_string_len(rep->value.string)); return true; } if (oc_rep_is_property(rep, CLOUD_XSTR(CLOUD_ACCESS_TOKEN), CLOUD_XSTRLEN(CLOUD_ACCESS_TOKEN))) { - cloud_set_string(&store->access_token, oc_string(rep->value.string), - oc_string_len(rep->value.string)); + oc_set_string(&store->access_token, oc_string(rep->value.string), + oc_string_len(rep->value.string)); return true; } if (oc_rep_is_property(rep, CLOUD_XSTR(CLOUD_REFRESH_TOKEN), CLOUD_XSTRLEN(CLOUD_REFRESH_TOKEN))) { - cloud_set_string(&store->refresh_token, oc_string(rep->value.string), - oc_string_len(rep->value.string)); + oc_set_string(&store->refresh_token, oc_string(rep->value.string), + oc_string_len(rep->value.string)); return true; } @@ -323,21 +323,21 @@ cloud_store_initialize(oc_cloud_store_t *store) { cloud_store_deinitialize(store); #define DEFAULT_CLOUD_CIS "coaps+tcp://127.0.0.1" - cloud_set_string(&store->ci_server, DEFAULT_CLOUD_CIS, - strlen(DEFAULT_CLOUD_CIS)); + oc_set_string(&store->ci_server, DEFAULT_CLOUD_CIS, + strlen(DEFAULT_CLOUD_CIS)); #define DEFAULT_CLOUD_SID "00000000-0000-0000-0000-000000000000" - cloud_set_string(&store->sid, DEFAULT_CLOUD_SID, strlen(DEFAULT_CLOUD_SID)); + oc_set_string(&store->sid, DEFAULT_CLOUD_SID, strlen(DEFAULT_CLOUD_SID)); } void cloud_store_deinitialize(oc_cloud_store_t *store) { - cloud_set_string(&store->ci_server, NULL, 0); - cloud_set_string(&store->auth_provider, NULL, 0); - cloud_set_string(&store->uid, NULL, 0); - cloud_set_string(&store->access_token, NULL, 0); - cloud_set_string(&store->refresh_token, NULL, 0); - cloud_set_string(&store->sid, NULL, 0); + oc_set_string(&store->ci_server, NULL, 0); + oc_set_string(&store->auth_provider, NULL, 0); + oc_set_string(&store->uid, NULL, 0); + oc_set_string(&store->access_token, NULL, 0); + oc_set_string(&store->refresh_token, NULL, 0); + oc_set_string(&store->sid, NULL, 0); store->status = 0; store->expires_in = 0; store->cps = OC_CPS_UNINITIALIZED; diff --git a/api/cloud/unittest/cloud_store_test.cpp b/api/cloud/unittest/cloud_store_test.cpp index 4564de227e..df92bb0fe8 100644 --- a/api/cloud/unittest/cloud_store_test.cpp +++ b/api/cloud/unittest/cloud_store_test.cpp @@ -18,11 +18,13 @@ ******************************************************************/ #include "oc_api.h" +#include "oc_config.h" #include "oc_cloud_internal.h" #include "oc_cloud_store_internal.h" #include "oc_collection.h" #include "port/oc_storage.h" #include "port/oc_storage_internal.h" +#include "tests/gtest/Device.h" #include #include @@ -45,53 +47,8 @@ class TestCloudStore : public testing::Test { public: - static oc_handler_t s_handler; - static pthread_mutex_t s_mutex; - static pthread_cond_t s_cv; static oc_cloud_context_t s_context; - static int appInit(void) - { - int result = oc_init_platform("OCFCloud", nullptr, nullptr); - result |= oc_add_device("/oic/d", "oic.d.light", "Lamp", "ocf.1.0.0", - "ocf.res.1.0.0", nullptr, nullptr); - return result; - } - - static void signalEventLoop(void) { pthread_cond_signal(&s_cv); } - - static oc_event_callback_retval_t quitEvent(void *data) - { - auto *quit = static_cast(data); - *quit = true; - return OC_EVENT_DONE; - } - - static void poolEvents(uint16_t seconds) - { - bool quit = false; - oc_set_delayed_callback(&quit, quitEvent, seconds); - - while (true) { - pthread_mutex_lock(&s_mutex); - oc_clock_time_t next_event = oc_main_poll(); - if (quit) { - pthread_mutex_unlock(&s_mutex); - break; - } - if (next_event == 0) { - pthread_cond_wait(&s_cv, &s_mutex); - } else { - struct timespec ts; - ts.tv_sec = (next_event / OC_CLOCK_SECOND); - ts.tv_nsec = static_cast((next_event % OC_CLOCK_SECOND) * 1.e09 / - OC_CLOCK_SECOND); - pthread_cond_timedwait(&s_cv, &s_mutex, &ts); - } - pthread_mutex_unlock(&s_mutex); - } - } - static void validateDefaults(const oc_cloud_store_t *store) { EXPECT_STREQ(DEFAULT_CLOUD_CIS, oc_string(store->ci_server)); @@ -105,7 +62,7 @@ class TestCloudStore : public testing::Test { EXPECT_EQ(0, store->cps); } -#ifdef OC_SECURITY +#ifdef OC_STORAGE static void compareStores(const oc_cloud_store_t *s1, const oc_cloud_store_t *s2) { @@ -120,7 +77,7 @@ class TestCloudStore : public testing::Test { EXPECT_EQ(s1->cps, s2->cps); EXPECT_EQ(s1->status, s2->status); } -#endif /* OC_SECURITY */ +#endif /* OC_STORAGE */ static void freeStore(oc_cloud_store_t *store) { @@ -134,22 +91,23 @@ class TestCloudStore : public testing::Test { static void SetUpTestCase() { -#ifdef OC_SECURITY - EXPECT_EQ(0, oc_storage_config(CLOUD_STORAGE)); -#endif /* OC_SECURITY */ - s_handler.init = &appInit; - s_handler.signal_event_loop = &signalEventLoop; - int ret = oc_main_init(&s_handler); - ASSERT_EQ(0, ret); +#ifdef OC_STORAGE + ASSERT_EQ(0, oc_storage_config(CLOUD_STORAGE)); +#endif /* OC_STORAGE */ + ASSERT_TRUE(oc::TestDevice::StartServer()); memset(&s_context, 0, sizeof(s_context)); } static void TearDownTestCase() { - oc_main_shutdown(); -#ifdef OC_SECURITY + oc::TestDevice::StopServer(); +#ifdef OC_STORAGE EXPECT_EQ(0, oc_storage_reset()); -#endif /* OC_SECURITY */ + for (const auto &entry : + std::filesystem::directory_iterator(CLOUD_STORAGE)) { + std::filesystem::remove_all(entry.path()); + } +#endif /* OC_STORAGE */ } void SetUp() override @@ -169,35 +127,34 @@ class TestCloudStore : public testing::Test { void TearDown() override { freeStore(&m_store); +#ifdef OC_STORAGE for (const auto &entry : std::filesystem::directory_iterator(CLOUD_STORAGE)) { std::filesystem::remove_all(entry.path()); } +#endif /* OC_STORAGE */ } oc_cloud_store_t m_store; }; -oc_handler_t TestCloudStore::s_handler; -pthread_mutex_t TestCloudStore::s_mutex; -pthread_cond_t TestCloudStore::s_cv; oc_cloud_context_t TestCloudStore::s_context; TEST_F(TestCloudStore, dump_async) { cloud_store_dump_async(&m_store); - poolEvents(1); + oc::TestDevice::PoolEvents(1); oc_cloud_store_t store1; memset(&store1, 0, sizeof(store1)); store1.device = m_store.device; -#ifdef OC_SECURITY +#ifdef OC_STORAGE EXPECT_EQ(0, cloud_store_load(&store1)); compareStores(&m_store, &store1); -#else +#else /* !OC_STORAGE */ EXPECT_NE(0, cloud_store_load(&store1)); validateDefaults(&store1); -#endif +#endif /* OC_STORAGE */ freeStore(&store1); } @@ -214,21 +171,21 @@ TEST_F(TestCloudStore, load_defaults) TEST_F(TestCloudStore, dump) { -#ifdef OC_SECURITY +#ifdef OC_STORAGE EXPECT_LE(0, cloud_store_dump(&m_store)); -#else +#else /* !OC_STORAGE */ EXPECT_NE(0, cloud_store_dump(&m_store)); -#endif +#endif /* OC_STORAGE */ oc_cloud_store_t store1; memset(&store1, 0, sizeof(store1)); store1.device = m_store.device; -#ifdef OC_SECURITY +#ifdef OC_STORAGE EXPECT_EQ(0, cloud_store_load(&store1)); compareStores(&m_store, &store1); -#else +#else /* !OC_STORAGE */ EXPECT_NE(0, cloud_store_load(&store1)); validateDefaults(&store1); -#endif +#endif /* OC_STORAGE */ freeStore(&store1); } diff --git a/api/cloud/unittest/cloud_test.cpp b/api/cloud/unittest/cloud_test.cpp index 28507c4a80..1ca777d417 100644 --- a/api/cloud/unittest/cloud_test.cpp +++ b/api/cloud/unittest/cloud_test.cpp @@ -104,20 +104,6 @@ TEST_F(TestCloud, cloud_status) EXPECT_EQ(ctx->store.status, status); } -TEST_F(TestCloud, cloud_set_string) -{ - oc_string_t str; - memset(&str, 0, sizeof(str)); - cloud_set_string(&str, "a", 1); - EXPECT_STREQ("a", oc_string(str)); - - cloud_set_string(&str, nullptr, 1); - EXPECT_EQ(nullptr, oc_string(str)); - - cloud_set_string(&str, "b", 0); - EXPECT_EQ(nullptr, oc_string(str)); -} - TEST_F(TestCloud, cloud_set_last_error) { oc_cloud_context_t *ctx = oc_cloud_get_context(0); diff --git a/api/oc_client_role.c b/api/oc_client_role.c index 5a0cbbee43..df091aec98 100644 --- a/api/oc_client_role.c +++ b/api/oc_client_role.c @@ -46,12 +46,12 @@ serialize_role_credential(CborEncoder *roles_array, const oc_sec_cred_t *cr) oc_rep_close_object(role, roleid); } /* credusage */ - oc_rep_set_text_string(role, credusage, "oic.sec.cred.rolecert"); + oc_rep_set_text_string(role, credusage, OC_CREDUSAGE_ROLE_CERT_STR); /* publicdata */ if (oc_string_len(cr->publicdata.data) > 0) { oc_rep_set_object(role, publicdata); oc_rep_set_text_string(publicdata, data, oc_string(cr->publicdata.data)); - oc_rep_set_text_string(publicdata, encoding, "oic.sec.encoding.pem"); + oc_rep_set_text_string(publicdata, encoding, OC_ENCODING_PEM_STR); oc_rep_close_object(role, publicdata); } oc_rep_end_object(roles_array, role); diff --git a/api/oc_core_res.c b/api/oc_core_res.c index 6afeefebcb..dcd18bf59e 100644 --- a/api/oc_core_res.c +++ b/api/oc_core_res.c @@ -44,6 +44,7 @@ #ifdef OC_SECURITY #include "security/oc_doxm_internal.h" #include "security/oc_pstat.h" +#include "security/oc_sdi_internal.h" #include "security/oc_tls.h" #endif /* OC_SECURITY */ @@ -841,8 +842,8 @@ oc_core_get_resource_type_by_uri(const char *uri) return OCF_SEC_ROLES; } #endif /* OC_PKI */ - if (core_is_resource_uri(uri, uri_len, "/oic/sec/sdi", - OC_CHAR_ARRAY_LEN("/oic/sec/sdi"))) { + if (core_is_resource_uri(uri, uri_len, OCF_SEC_SDI_URI, + OC_CHAR_ARRAY_LEN(OCF_SEC_SDI_URI))) { return OCF_SEC_SDI; } #endif /* OC_SECURITY */ diff --git a/api/oc_discovery.c b/api/oc_discovery.c index b492f23f17..b19c1737b5 100644 --- a/api/oc_discovery.c +++ b/api/oc_discovery.c @@ -44,7 +44,7 @@ #ifdef OC_SECURITY #include "security/oc_pstat.h" -#include "security/oc_sdi.h" +#include "security/oc_sdi_internal.h" #include "security/oc_tls.h" #endif @@ -810,7 +810,7 @@ oc_core_discovery_handler(oc_request_t *request, oc_interface_mask_t iface_mask, const char *q; int ql = oc_get_query_value(request, "sduuid", &q); if (ql > 0) { - const oc_sec_sdi_t *s = oc_sec_get_sdi(device); + const oc_sec_sdi_t *s = oc_sec_sdi_get(device); if (s->priv) { oc_ignore_request(request); OC_DBG("private sdi"); @@ -862,7 +862,7 @@ oc_core_discovery_handler(oc_request_t *request, oc_interface_mask_t iface_mask, oc_process_baseline_interface( oc_core_get_resource_by_index(OCF_RES, device)); #ifdef OC_SECURITY - oc_sec_sdi_t *s = oc_sec_get_sdi(device); + const oc_sec_sdi_t *s = oc_sec_sdi_get(device); if (!s->priv) { char uuid[OC_UUID_LEN]; oc_uuid_to_str(&s->uuid, uuid, OC_UUID_LEN); @@ -962,10 +962,11 @@ oc_wkcore_discovery_handler(oc_request_t *request, oc_endpoint_t *eps = oc_connectivity_get_endpoints(request->resource->device); - oc_string_t ep, uri; + oc_string_t uri; memset(&uri, 0, sizeof(oc_string_t)); while (eps != NULL) { if (eps->flags & SECURED) { + oc_string_t ep; if (oc_endpoint_to_string(eps, &ep) == 0) { length = clf_add_str_to_buffer(oc_string(ep), oc_string_len(ep)); response_length += length; diff --git a/api/oc_endpoint.c b/api/oc_endpoint.c index 7b3b354219..d10a95822d 100644 --- a/api/oc_endpoint.c +++ b/api/oc_endpoint.c @@ -369,7 +369,7 @@ typedef struct endpoint_uri_t } endpoint_uri_t; static int -parse_endpoint_flags(oc_string_t *endpoint_str) +parse_endpoint_flags(const oc_string_t *endpoint_str) { const char *ep = oc_string(*endpoint_str); size_t ep_len = oc_string_len(*endpoint_str); @@ -395,8 +395,8 @@ parse_endpoint_flags(oc_string_t *endpoint_str) } static bool -parse_endpoint_uri(oc_string_t *endpoint_str, endpoint_uri_t *endpoint_uri, - bool parse_uri) +parse_endpoint_uri(const oc_string_t *endpoint_str, + endpoint_uri_t *endpoint_uri, bool parse_uri) { const char *ep = oc_string(*endpoint_str); int flags = parse_endpoint_flags(endpoint_str); @@ -512,8 +512,8 @@ dns_lookup(const char *domain, oc_string_t *addr, transport_flags flags) #endif /* OC_DNS_LOOKUP && (OC_DNS_LOOKUP_IPV6 || OC_IPV4) */ static int -oc_parse_endpoint_string(oc_string_t *endpoint_str, oc_endpoint_t *endpoint, - oc_string_t *uri) +oc_parse_endpoint_string(const oc_string_t *endpoint_str, + oc_endpoint_t *endpoint, oc_string_t *uri) { endpoint_uri_t ep_uri = { 0 }; if (!parse_endpoint_uri(endpoint_str, &ep_uri, uri != NULL)) { @@ -583,7 +583,7 @@ oc_parse_endpoint_string(oc_string_t *endpoint_str, oc_endpoint_t *endpoint, } int -oc_string_to_endpoint(oc_string_t *endpoint_str, oc_endpoint_t *endpoint, +oc_string_to_endpoint(const oc_string_t *endpoint_str, oc_endpoint_t *endpoint, oc_string_t *uri) { if (endpoint && endpoint_str) { diff --git a/api/oc_helpers.c b/api/oc_helpers.c index f8b7dda1a3..4a229234e5 100644 --- a/api/oc_helpers.c +++ b/api/oc_helpers.c @@ -23,10 +23,11 @@ #include "port/oc_log.h" #include "port/oc_random.h" #include -#include #include +#include +#include -static bool mmem_initialized = false; +static bool g_mmem_initialized = false; static void oc_malloc( @@ -35,9 +36,9 @@ oc_malloc( #endif oc_handle_t *block, size_t num_items, pool pool_type) { - if (!mmem_initialized) { + if (!g_mmem_initialized) { oc_mmem_init(); - mmem_initialized = true; + g_mmem_initialized = true; } size_t alloc_ret = _oc_mmem_alloc( #ifdef OC_MEMORY_TRACE @@ -112,10 +113,43 @@ _oc_free_string( } void -oc_set_string(oc_string_t *ocstring, const char *str, size_t str_len) +oc_set_string(oc_string_t *dst, const char *str, size_t str_len) { - oc_free_string(ocstring); - oc_new_string(ocstring, str, str_len); + assert(dst != NULL); + + if (str == NULL || str_len == 0) { + oc_free_string(dst); + memset(dst, 0, sizeof(*dst)); + return; + } +#ifdef OC_DYNAMIC_ALLOCATION + oc_free_string(dst); + oc_new_string(dst, str, str_len); +#else /* !OC_DYNAMIC_ALLOCATION */ + oc_string_t copy; + // create a oc_string_t to ensure that str won't get invalidated by + // oc_free_string + oc_new_string(©, str, str_len); + oc_free_string(dst); + oc_new_string(dst, oc_string(copy), oc_string_len(copy)); + oc_free_string(©); +#endif /* OC_DYNAMIC_ALLOCATION */ +} + +void +oc_copy_string(oc_string_t *dst, const oc_string_t *src) +{ + assert(dst != NULL); + if (dst == src) { + return; + } + + oc_free_string(dst); + if (src == NULL || oc_string(*src) == NULL) { + memset(dst, 0, sizeof(*dst)); + return; + } + oc_new_string(dst, oc_string(*src), oc_string_len(*src)); } void @@ -178,9 +212,8 @@ _oc_alloc_string_array( #endif ocstringarray, size * STRING_ARRAY_ITEM_MAX_LEN); - size_t i, pos; - for (i = 0; i < size; i++) { - pos = i * STRING_ARRAY_ITEM_MAX_LEN; + for (size_t i = 0; i < size; ++i) { + size_t pos = i * STRING_ARRAY_ITEM_MAX_LEN; memcpy((char *)oc_string(*ocstringarray) + pos, (const char *)"", 1); } } @@ -203,16 +236,13 @@ bool _oc_byte_string_array_add_item(oc_string_array_t *ocstringarray, const char str[], size_t str_len) { - bool success = false; - size_t i; - for (i = 0; i < oc_byte_string_array_get_allocated_size(*ocstringarray); - i++) { + for (size_t i = 0; + i < oc_byte_string_array_get_allocated_size(*ocstringarray); ++i) { if (oc_byte_string_array_get_item_size(*ocstringarray, i) == 0) { - success = oc_byte_string_array_set_item(*ocstringarray, str, str_len, i); - break; + return oc_byte_string_array_set_item(*ocstringarray, str, str_len, i); } } - return success; + return false; } bool @@ -232,15 +262,13 @@ _oc_copy_string_to_array(oc_string_array_t *ocstringarray, const char str[], bool _oc_string_array_add_item(oc_string_array_t *ocstringarray, const char str[]) { - bool success = false; - size_t i; - for (i = 0; i < oc_string_array_get_allocated_size(*ocstringarray); i++) { + for (size_t i = 0; i < oc_string_array_get_allocated_size(*ocstringarray); + ++i) { if (oc_string_array_get_item_size(*ocstringarray, i) == 0) { - success = oc_string_array_set_item(*ocstringarray, str, i); - break; + return oc_string_array_set_item(*ocstringarray, str, i); } } - return success; + return false; } void diff --git a/api/oc_introspection.c b/api/oc_introspection.c index 8cd94faa7d..4f975092bd 100644 --- a/api/oc_introspection.c +++ b/api/oc_introspection.c @@ -109,11 +109,12 @@ oc_core_introspection_wk_handler(oc_request_t *request, /* We are interested in only a single coap:// endpoint on this logical device. */ oc_endpoint_t *eps = oc_connectivity_get_endpoints(request->resource->device); - oc_string_t ep, uri; + oc_string_t uri; memset(&uri, 0, sizeof(oc_string_t)); while (eps != NULL) { if ((interface_index == -1 || eps->interface_index == interface_index) && !(eps->flags & SECURED) && (eps->flags == conn)) { + oc_string_t ep; if (oc_endpoint_to_string(eps, &ep) == 0) { oc_concat_strings(&uri, oc_string(ep), "/oc/introspection"); oc_free_string(&ep); diff --git a/api/oc_main.c b/api/oc_main.c index fb53ee41cd..d4cdddb56f 100644 --- a/api/oc_main.c +++ b/api/oc_main.c @@ -49,7 +49,7 @@ #ifdef OC_PKI #include "security/oc_keypair_internal.h" #endif /* OC_PKI */ -#include "security/oc_sdi.h" +#include "security/oc_sdi_internal.h" #endif /* OC_SECURITY */ #ifdef OC_CLOUD @@ -407,10 +407,11 @@ oc_main_shutdown(void) #ifdef OC_SECURITY oc_tls_shutdown(); + + oc_sec_svr_free(); #ifdef OC_PKI oc_sec_ecdsa_free_keypairs(); #endif /* OC_PKI */ - oc_sec_svr_free(); #endif /* OC_SECURITY */ #ifdef OC_SOFTWARE_UPDATE diff --git a/api/oc_rep_internal.h b/api/oc_rep_internal.h index ba27daa71f..9a4e663032 100644 --- a/api/oc_rep_internal.h +++ b/api/oc_rep_internal.h @@ -43,7 +43,7 @@ bool oc_rep_is_property(const oc_rep_t *rep, const char *propname, * @brief Check whether the name and type of the property object matches one of * the Common resource properties. * - * @param rep bject to check (cannot be NULL) + * @param rep object to check (cannot be NULL) * @return true if property name matches * @return false otherwise * diff --git a/api/oc_server_api.c b/api/oc_server_api.c index 40322795e5..ddccb47d03 100644 --- a/api/oc_server_api.c +++ b/api/oc_server_api.c @@ -209,10 +209,10 @@ oc_resource_tag_locn(oc_resource_t *resource, oc_locn_t locn) } static void -resource_encode_name(oc_string_t name) +resource_encode_name(const char *name) { - if (oc_string_len(name) > 0) { - oc_rep_set_text_string(root, n, oc_string(name)); + if (name != NULL) { + oc_rep_set_text_string(root, n, name); } } @@ -282,7 +282,7 @@ oc_process_baseline_interface_with_filter( oc_process_baseline_interface_filter_fn_t filter, void *filter_data) { if (filter == NULL || filter(OC_BASELINE_PROP_NAME, filter_data)) { - resource_encode_name(resource->name); + resource_encode_name(oc_string(resource->name)); } if (filter == NULL || filter(OC_BASELINE_PROP_RT, filter_data)) { oc_rep_set_string_array(root, rt, resource->types); diff --git a/api/oc_swupdate.c b/api/oc_swupdate.c index beae841a4f..390dce7f8b 100644 --- a/api/oc_swupdate.c +++ b/api/oc_swupdate.c @@ -43,7 +43,7 @@ static oc_swupdate_t sw[OC_MAX_NUM_DEVICES]; void oc_create_swupdate_resource(size_t device); void oc_swupdate_encode(oc_interface_mask_t interfaces, size_t device); -void oc_swupdate_decode(oc_rep_t *rep, size_t device); +void oc_swupdate_decode(const oc_rep_t *rep, size_t device); static const oc_swupdate_cb_t *cb; @@ -53,37 +53,21 @@ oc_swupdate_set_impl(const oc_swupdate_cb_t *swupdate_impl) cb = swupdate_impl; } +static int +oc_swupdate_on_load(const oc_rep_t *rep, size_t device, void *data) +{ + (void)data; + oc_swupdate_decode(rep, device); + return 0; +} + static void oc_load_sw(size_t device) { - char svr_tag[OC_STORAGE_SVR_TAG_MAX]; - if (oc_storage_gen_svr_tag("sw", device, svr_tag, sizeof(svr_tag)) < 0) { - OC_ERR("cannot load swupdate: cannot generate svr tag"); - return; - } - -#ifdef OC_DYNAMIC_ALLOCATION - uint8_t *buf = malloc(OC_MAX_APP_DATA_SIZE); - if (!buf) { + if (oc_storage_load_resource("sw", device, oc_swupdate_on_load, NULL) <= 0) { + OC_ERR("failed to load swupdate from storage"); return; } -#else /* OC_DYNAMIC_ALLOCATION */ - uint8_t buf[OC_MAX_APP_DATA_SIZE]; -#endif /* !OC_DYNAMIC_ALLOCATION */ - - long ret = oc_storage_read(svr_tag, buf, OC_MAX_APP_DATA_SIZE); - if (ret > 0) { - OC_MEMB_LOCAL(rep_objects, oc_rep_t, OC_MAX_NUM_REP_OBJECTS); - oc_rep_set_pool(&rep_objects); - oc_rep_t *rep = NULL; - oc_parse_rep(buf, (int)ret, &rep); - oc_swupdate_decode(rep, device); - oc_free_rep(rep); - } - -#ifdef OC_DYNAMIC_ALLOCATION - free(buf); -#endif /* OC_DYNAMIC_ALLOCATION */ } static void @@ -395,7 +379,7 @@ schedule_update(void *data) } void -oc_swupdate_decode(oc_rep_t *rep, size_t device) +oc_swupdate_decode(const oc_rep_t *rep, size_t device) { oc_swupdate_t *s = &sw[device]; /* loop over all the properties in the input document */ diff --git a/api/unittest/resourcetest.cpp b/api/unittest/resourcetest.cpp index ec43dc0ea2..b04c7ada87 100644 --- a/api/unittest/resourcetest.cpp +++ b/api/unittest/resourcetest.cpp @@ -25,6 +25,7 @@ #include "oc_enums.h" #include "oc_ri.h" #include "tests/gtest/Device.h" +#include "tests/gtest/RepPool.h" #include #include diff --git a/api/unittest/storagetest.cpp b/api/unittest/storagetest.cpp index 17f3d1e68f..c7e8383854 100644 --- a/api/unittest/storagetest.cpp +++ b/api/unittest/storagetest.cpp @@ -53,6 +53,7 @@ class TestCommonStorage : public testing::Test { static void TearDownTestCase() { + ASSERT_EQ(0, oc_storage_reset()); for (const auto &entry : std::filesystem::directory_iterator(testStorage)) { std::filesystem::remove_all(entry.path()); } diff --git a/apps/client_certification_tests.c b/apps/client_certification_tests.c index 71785e8e53..8dc02b23c0 100644 --- a/apps/client_certification_tests.c +++ b/apps/client_certification_tests.c @@ -23,6 +23,7 @@ #include "oc_pki.h" #include "oc_swupdate.h" #include "port/oc_clock.h" +#include "util/oc_macros.h" #include #include #include @@ -481,7 +482,9 @@ discovery(const char *di, const char *uri, oc_string_array_t types, resource_t *l = (resource_t *)oc_memb_alloc(&resources_m); if (l) { oc_endpoint_list_copy(&l->endpoint, endpoint); - int uri_len = (strlen(uri) >= 64) ? 63 : strlen(uri); + size_t uri_len = strlen(uri); + uri_len = + uri_len > OC_CHAR_ARRAY_LEN(l->uri) ? OC_CHAR_ARRAY_LEN(l->uri) : uri_len; memcpy(l->uri, uri, uri_len); l->uri[uri_len] = '\0'; oc_list_add(resources, l); @@ -698,14 +701,15 @@ add_device_to_list(const oc_uuid_t *uuid, const char *device_name, oc_list_add(list, device); } - if (device_name) { - size_t len = strlen(device_name); - len = (len > 63) ? 63 : len; - strncpy(device->device_name, device_name, len); - device->device_name[len] = '\0'; - } else { - device->device_name[0] = '\0'; + size_t len = 0; + if (device_name != NULL) { + len = strlen(device_name); + len = (len > OC_CHAR_ARRAY_LEN(device->device_name)) + ? OC_CHAR_ARRAY_LEN(device->device_name) + : len; + memcpy(device->device_name, device_name, len); } + device->device_name[len] = '\0'; return true; } diff --git a/apps/cloud_client.c b/apps/cloud_client.c index 0b5fe6b85e..e44af89dca 100644 --- a/apps/cloud_client.c +++ b/apps/cloud_client.c @@ -20,6 +20,7 @@ #include "oc_api.h" #include "oc_pki.h" +#include "util/oc_macros.h" #include #include #if defined(_WIN32) @@ -262,7 +263,9 @@ discovery(const char *anchor, const char *uri, oc_string_array_t types, resource_t *l = (resource_t *)oc_memb_alloc(&resources_m); if (l) { oc_endpoint_list_copy(&l->endpoint, endpoint); - int uri_len = (strlen(uri) >= 64) ? 63 : strlen(uri); + size_t uri_len = strlen(uri); + uri_len = + uri_len > OC_CHAR_ARRAY_LEN(l->uri) ? OC_CHAR_ARRAY_LEN(l->uri) : uri_len; memcpy(l->uri, uri, uri_len); l->uri[uri_len] = '\0'; oc_list_add(resources, l); diff --git a/apps/secure_mcast_client.c b/apps/secure_mcast_client.c index 8ff38824a4..1e7e316349 100644 --- a/apps/secure_mcast_client.c +++ b/apps/secure_mcast_client.c @@ -17,6 +17,7 @@ ******************************************************************/ #include "oc_api.h" +#include "util/oc_macros.h" #include #include #include @@ -343,7 +344,10 @@ discovery(const char *di, const char *uri, oc_string_array_t types, PRINT("\n##Discovered light switch##\n"); oc_endpoint_list_copy(&l->endpoint, endpoint); if (oc_list_length(light_switches) == 0) { - int uri_len = (strlen(uri) >= 64) ? 63 : strlen(uri); + size_t uri_len = strlen(uri); + uri_len = uri_len > OC_CHAR_ARRAY_LEN(mcast_uri) + ? OC_CHAR_ARRAY_LEN(mcast_uri) + : uri_len; memcpy(mcast_uri, uri, uri_len); mcast_uri[uri_len] = '\0'; } diff --git a/apps/smart_lock_linux.c b/apps/smart_lock_linux.c index 955e208411..aa00d02631 100644 --- a/apps/smart_lock_linux.c +++ b/apps/smart_lock_linux.c @@ -18,6 +18,7 @@ #include "oc_api.h" #include "port/oc_clock.h" +#include "util/oc_macros.h" #include #include @@ -338,7 +339,9 @@ discovery(const char *di, const char *uri, oc_string_array_t types, oc_smartlock_t *l = (oc_smartlock_t *)oc_memb_alloc(&smartlocks_m); if (l) { oc_endpoint_list_copy(&l->endpoint, endpoint); - int uri_len = (strlen(uri) >= 64) ? 63 : strlen(uri); + size_t uri_len = strlen(uri); + uri_len = + uri_len > OC_CHAR_ARRAY_LEN(l->uri) ? OC_CHAR_ARRAY_LEN(l->uri) : uri_len; memcpy(l->uri, uri, uri_len); l->uri[uri_len] = '\0'; oc_list_add(smartlocks, l); diff --git a/include/oc_cred.h b/include/oc_cred.h index 192c8fbe56..128bf189dc 100644 --- a/include/oc_cred.h +++ b/include/oc_cred.h @@ -187,7 +187,7 @@ const char *oc_cred_read_credusage(oc_sec_credusage_t credusage); * @return oc_sec_credusage_t credential usage type */ OC_API -oc_sec_credusage_t oc_cred_parse_credusage(oc_string_t *credusage_string); +oc_sec_credusage_t oc_cred_parse_credusage(const oc_string_t *credusage_string); #endif /* OC_PKI */ @@ -207,7 +207,7 @@ const char *oc_cred_read_encoding(oc_sec_encoding_t encoding); * @return oc_sec_encoding_t credential encoding type */ OC_API -oc_sec_encoding_t oc_cred_parse_encoding(oc_string_t *encoding_string); +oc_sec_encoding_t oc_cred_parse_encoding(const oc_string_t *encoding_string); /** * @brief credential type to string diff --git a/include/oc_endpoint.h b/include/oc_endpoint.h index 7959212505..df89417291 100644 --- a/include/oc_endpoint.h +++ b/include/oc_endpoint.h @@ -161,8 +161,8 @@ int oc_endpoint_to_string(const oc_endpoint_t *endpoint, * @return int 0 success */ OC_API -int oc_string_to_endpoint(oc_string_t *endpoint_str, oc_endpoint_t *endpoint, - oc_string_t *uri); +int oc_string_to_endpoint(const oc_string_t *endpoint_str, + oc_endpoint_t *endpoint, oc_string_t *uri); /** * @brief parse path component (ie. the part after the first '/') of a uri diff --git a/include/oc_helpers.h b/include/oc_helpers.h index b6559dffe1..4f35669c01 100644 --- a/include/oc_helpers.h +++ b/include/oc_helpers.h @@ -267,12 +267,23 @@ void _oc_free_array( /** * @brief reset ocstring contents * - * @param ocstring ocstring to be reset - * @param str not terminated string which will replace current str + * @param dst ocstring to be reset (cannot be NULL) + * @param str string which will replace current str (if NULL then the data of + * ocstring is freed and ocstring is memset to zeroes) * @param str_len size of the string */ OC_API -void oc_set_string(oc_string_t *ocstring, const char *str, size_t str_len); +void oc_set_string(oc_string_t *dst, const char *str, size_t str_len); + +/** + * @brief copy ocstring + * + * @param dst destination (cannot be NULL) + * @param src source (if NULL data of destination is freed and the destination + * is memset to zeroes) + */ +OC_API +void oc_copy_string(oc_string_t *dst, const oc_string_t *src); /** * @brief new array diff --git a/onboarding_tool/obtmain.c b/onboarding_tool/obtmain.c index 8b03545ac0..d96af2510c 100644 --- a/onboarding_tool/obtmain.c +++ b/onboarding_tool/obtmain.c @@ -20,6 +20,7 @@ #include "oc_core_res.h" #include "oc_obt.h" #include "port/oc_clock.h" +#include "util/oc_macros.h" #if defined(_WIN32) #include #elif defined(__linux__) @@ -255,14 +256,15 @@ add_device_to_list(const oc_uuid_t *uuid, const char *device_name, oc_list_add(list, device); } - if (device_name) { - size_t len = strlen(device_name); - len = (len > 63) ? 63 : len; - strncpy(device->device_name, device_name, len); - device->device_name[len] = '\0'; - } else { - device->device_name[0] = '\0'; + size_t len = 0; + if (device_name != NULL) { + len = strlen(device_name); + len = len > OC_CHAR_ARRAY_LEN(device->device_name) + ? OC_CHAR_ARRAY_LEN(device->device_name) + : len; + memcpy(device->device_name, device_name, len); } + device->device_name[len] = '\0'; return true; } diff --git a/port/linux/Makefile b/port/linux/Makefile index 2a37e9d01e..5951206e3b 100644 --- a/port/linux/Makefile +++ b/port/linux/Makefile @@ -340,7 +340,7 @@ $(PLATFORM_TEST_OBJ_DIR)/%.o: $(PLATFORM_TEST_DIR)/%.cpp @mkdir -p ${@D} $(CXX) $< -o $@ $(GTEST_CPPFLAGS) $(TEST_CXXFLAGS) $(EXTRA_CFLAGS) $(HEADER_DIR) -c -platformtest: $(PLATFORM_TEST_OBJ_FILES) libiotivity-lite-client-server.a | $(GTEST) +platformtest: $(PLATFORM_TEST_OBJ_FILES) $(COMMON_TEST_OBJ_FILES) libiotivity-lite-client-server.a | $(GTEST) $(CXX) $(GTEST_CPPFLAGS) $(TEST_CXXFLAGS) $(EXTRA_CFLAGS) $(HEADER_DIR) -l:gtest_main.a -liotivity-lite-client-server -L$(OUT_DIR) -L$(GTEST_DIR)/make -lpthread $^ -o $@ $(CLOUD_TEST_OBJ_DIR)/%.o: $(CLOUD_TEST_DIR)/%.cpp diff --git a/port/unittest/connectivitytest.cpp b/port/unittest/connectivitytest.cpp index 5e69d6a935..0978804b20 100644 --- a/port/unittest/connectivitytest.cpp +++ b/port/unittest/connectivitytest.cpp @@ -19,134 +19,40 @@ #include "api/oc_tcp_internal.h" #include "messaging/coap/coap.h" #include "messaging/coap/coap_signal.h" +#include "oc_api.h" +#include "oc_buffer.h" +#include "oc_network_monitor.h" #include "port/oc_connectivity.h" #include "port/oc_connectivity_internal.h" #include "port/oc_network_event_handler_internal.h" #include "util/oc_atomic.h" #include "util/oc_features.h" -#include "oc_api.h" -#include "oc_buffer.h" -#include "oc_network_monitor.h" +#include "tests/gtest/Device.h" + #include #include #include #include #include #include -#include #include static const size_t g_device = 0; class TestConnectivity : public testing::Test { public: - static pthread_mutex_t s_mutex; - static pthread_cond_t s_cv; - static oc_handler_t s_handler; - static std::atomic s_terminate; - static std::atomic s_is_callback_received; - - static int appInit(void) { return 0; } - - static void signalEventLoop(void) { pthread_cond_signal(&s_cv); } - - static oc_event_callback_retval_t quitEvent(void *) - { - s_terminate.store(true); - return OC_EVENT_DONE; - } - - static void poolEvents(uint16_t seconds) - { - s_terminate.store(false); - oc_set_delayed_callback(nullptr, quitEvent, seconds); - - while (!s_terminate) { - pthread_mutex_lock(&s_mutex); - oc_clock_time_t next_event = oc_main_poll(); - if (s_terminate) { - pthread_mutex_unlock(&s_mutex); - break; - } - if (next_event == 0) { - pthread_cond_wait(&s_cv, &s_mutex); - } else { - struct timespec ts; - ts.tv_sec = (next_event / OC_CLOCK_SECOND); - ts.tv_nsec = static_cast((next_event % OC_CLOCK_SECOND) * 1.e09 / - OC_CLOCK_SECOND); - pthread_cond_timedwait(&s_cv, &s_mutex, &ts); - } - pthread_mutex_unlock(&s_mutex); - } - } - -protected: void SetUp() override { - s_is_callback_received.store(false); - s_terminate.store(false); - s_handler.init = &appInit; - s_handler.signal_event_loop = &signalEventLoop; - int ret = oc_main_init(&s_handler); - ASSERT_EQ(0, ret); - ASSERT_EQ(0, oc_connectivity_init(g_device)); - poolEvents(1); // give some time for everything to start-up + is_callback_received.store(false); + oc_network_event_handler_mutex_init(); } - void TearDown() override - { - oc_connectivity_shutdown(g_device); - oc_main_shutdown(); - } + void TearDown() override { oc_network_event_handler_mutex_destroy(); } -public: - static oc_endpoint_t *findEndpoint(size_t device); - static oc_endpoint_t createEndpoint(const std::string &ep_str); + static std::atomic is_callback_received; }; -pthread_mutex_t TestConnectivity::s_mutex; -pthread_cond_t TestConnectivity::s_cv; -oc_handler_t TestConnectivity::s_handler; -std::atomic TestConnectivity::s_terminate{ false }; -std::atomic TestConnectivity::s_is_callback_received{ false }; - -oc_endpoint_t * -TestConnectivity::findEndpoint(size_t device) -{ - int flags = 0; -#ifdef OC_SECURITY - flags |= SECURED; -#endif /* OC_SECURITY */ -#ifdef OC_IPV4 - flags |= IPV4; -#endif /* OC_IPV4 */ -#ifdef OC_TCP - flags |= TCP; -#endif /* OC_TCP */ - - oc_endpoint_t *ep = oc_connectivity_get_endpoints(device); - while (ep != nullptr) { - if (flags == 0 || (ep->flags & flags) == flags) { - break; - } - ep = ep->next; - } - EXPECT_NE(nullptr, ep); - return ep; -} - -oc_endpoint_t -TestConnectivity::createEndpoint(const std::string &ep_str) -{ - oc_string_t ep_ocstr; - oc_new_string(&ep_ocstr, ep_str.c_str(), ep_str.length()); - oc_endpoint_t ep{}; - int ret = oc_string_to_endpoint(&ep_ocstr, &ep, nullptr); - oc_free_string(&ep_ocstr); - EXPECT_EQ(0, ret) << "cannot convert endpoint " << ep_str; - return ep; -} +std::atomic TestConnectivity::is_callback_received{ false }; TEST(TestConnectivity_init, oc_connectivity_init) { @@ -155,17 +61,11 @@ TEST(TestConnectivity_init, oc_connectivity_init) oc_connectivity_shutdown(g_device); } -TEST_F(TestConnectivity, oc_connectivity_get_endpoints) -{ - oc_endpoint_t *ep = oc_connectivity_get_endpoints(g_device); - EXPECT_NE(nullptr, ep); -} - static void interface_event_handler(oc_interface_event_t event) { EXPECT_EQ(NETWORK_INTERFACE_UP, event); - TestConnectivity::s_is_callback_received.store(true); + TestConnectivity::is_callback_received.store(true); } TEST_F(TestConnectivity, oc_add_network_interface_event_callback) @@ -192,7 +92,7 @@ TEST_F(TestConnectivity, handle_network_interface_event_callback) { oc_add_network_interface_event_callback(interface_event_handler); handle_network_interface_event_callback(NETWORK_INTERFACE_UP); - EXPECT_EQ(true, s_is_callback_received); + EXPECT_EQ(true, is_callback_received); } #endif /* OC_NETWORK_MONITOR */ @@ -201,7 +101,7 @@ session_event_handler(const oc_endpoint_t *ep, oc_session_state_t state) { EXPECT_NE(nullptr, ep); EXPECT_EQ(OC_SESSION_CONNECTED, state); - TestConnectivity::s_is_callback_received.store(true); + TestConnectivity::is_callback_received.store(true); } TEST_F(TestConnectivity, oc_add_session_event_callback) @@ -229,11 +129,12 @@ TEST_F(TestConnectivity, handle_session_event_callback) oc_add_session_event_callback(session_event_handler); oc_endpoint_t ep{}; handle_session_event_callback(&ep, OC_SESSION_CONNECTED); - EXPECT_EQ(true, s_is_callback_received); + EXPECT_EQ(true, is_callback_received); } #endif /* OC_SESSION_EVENTS */ #ifdef OC_TCP + TEST_F(TestConnectivity, oc_tcp_get_csm_state_P) { oc_endpoint_t ep{}; @@ -249,17 +150,77 @@ TEST_F(TestConnectivity, oc_tcp_get_csm_state_N) EXPECT_EQ(CSM_ERROR, ret); } +#endif /* OC_TCP */ + +class TestConnectivityWithServer : public testing::Test { +public: + void SetUp() override + { + is_callback_received.store(false); + ASSERT_TRUE(oc::TestDevice::StartServer()); + } + + void TearDown() override { oc::TestDevice::StopServer(); } + + static oc_endpoint_t *findEndpoint(size_t device); + static oc_endpoint_t createEndpoint(const std::string &ep_str); + + static std::atomic is_callback_received; +}; + +std::atomic TestConnectivityWithServer::is_callback_received{ false }; + +oc_endpoint_t * +TestConnectivityWithServer::findEndpoint(size_t device) +{ + int flags = 0; +#ifdef OC_SECURITY + flags |= SECURED; +#endif /* OC_SECURITY */ +#ifdef OC_IPV4 + flags |= IPV4; +#endif /* OC_IPV4 */ +#ifdef OC_TCP + flags |= TCP; +#endif /* OC_TCP */ + + oc_endpoint_t *ep = oc::TestDevice::GetEndpoint(device, flags); + EXPECT_NE(nullptr, ep); + return ep; +} + +oc_endpoint_t +TestConnectivityWithServer::createEndpoint(const std::string &ep_str) +{ + oc_string_t ep_ocstr; + oc_new_string(&ep_ocstr, ep_str.c_str(), ep_str.length()); + oc_endpoint_t ep{}; + int ret = oc_string_to_endpoint(&ep_ocstr, &ep, nullptr); + oc_free_string(&ep_ocstr); + EXPECT_EQ(0, ret) << "cannot convert endpoint " << ep_str; + return ep; +} + +TEST_F(TestConnectivityWithServer, oc_connectivity_get_endpoints) +{ + oc_endpoint_t *ep = oc_connectivity_get_endpoints(g_device); + EXPECT_NE(nullptr, ep); +} + +#ifdef OC_TCP + #ifdef OC_HAS_FEATURE_TCP_ASYNC_CONNECT + static void on_tcp_connect(const oc_endpoint_t *, int state, void *) { OC_DBG("on_tcp_connect"); EXPECT_EQ(OC_TCP_SOCKET_STATE_CONNECTED, state); - TestConnectivity::s_terminate.store(true); + oc::TestDevice::Terminate(); } #endif /* OC_HAS_FEATURE_TCP_ASYNC_CONNECT */ -TEST_F(TestConnectivity, oc_tcp_update_csm_state_P) +TEST_F(TestConnectivityWithServer, oc_tcp_update_csm_state_P) { oc_endpoint_t *ep = findEndpoint(g_device); #ifdef OC_HAS_FEATURE_TCP_ASYNC_CONNECT @@ -267,7 +228,7 @@ TEST_F(TestConnectivity, oc_tcp_update_csm_state_P) EXPECT_LE(0, ret); if (ret == OC_TCP_SOCKET_STATE_CONNECTING) { OC_DBG("oc_tcp_update_csm_state_P wait"); - poolEvents(10); + oc::TestDevice::PoolEvents(10); } EXPECT_EQ(OC_TCP_SOCKET_STATE_CONNECTED, oc_tcp_connection_state(ep)); #else /* !OC_HAS_FEATURE_TCP_ASYNC_CONNECT */ @@ -288,7 +249,7 @@ TEST_F(TestConnectivity, oc_tcp_update_csm_state_P) EXPECT_EQ(CSM_DONE, oc_tcp_get_csm_state(ep)); } -TEST_F(TestConnectivity, oc_tcp_update_csm_state_N) +TEST_F(TestConnectivityWithServer, oc_tcp_update_csm_state_N) { oc_endpoint_t *ep = findEndpoint(g_device); ASSERT_NE(nullptr, ep); @@ -301,7 +262,7 @@ TEST_F(TestConnectivity, oc_tcp_update_csm_state_N) } #ifdef OC_HAS_FEATURE_TCP_ASYNC_CONNECT -TEST_F(TestConnectivity, oc_tcp_connect_fail) +TEST_F(TestConnectivityWithServer, oc_tcp_connect_fail) { oc_endpoint_t ep = createEndpoint("coaps+tcp://[ff02::158]:12345"); // unreachable address @@ -313,16 +274,16 @@ on_tcp_connect_timeout(const oc_endpoint_t *, int state, void *) { OC_DBG("on_tcp_connect_timeout"); EXPECT_EQ(OC_TCP_SOCKET_ERROR_TIMEOUT, state); - TestConnectivity::s_is_callback_received.store(true); - TestConnectivity::s_terminate.store(true); + TestConnectivityWithServer::is_callback_received.store(true); + oc::TestDevice::Terminate(); } -TEST_F(TestConnectivity, oc_tcp_connect_timeout) +TEST_F(TestConnectivityWithServer, oc_tcp_connect_timeout) { oc_endpoint_t ep = createEndpoint( "coaps+tcp://[::1]:12345"); // reachable address, but inactive port - oc_tcp_set_connect_retry(2, 2); // timeout 2s, 2 retries -> total 6s + oc_tcp_set_connect_retry(2, 2); const unsigned connect_timeout = 6; EXPECT_EQ(OC_TCP_SOCKET_STATE_CONNECTING, oc_tcp_connect(&ep, on_tcp_connect_timeout, this)); @@ -335,30 +296,31 @@ TEST_F(TestConnectivity, oc_tcp_connect_timeout) EXPECT_EQ(OC_SEND_MESSAGE_QUEUED, oc_send_buffer2(msg, true)); OC_DBG("oc_tcp_connect_timeout wait"); - poolEvents(connect_timeout + 2); // +2 to be sure + oc::TestDevice::PoolEvents(connect_timeout + 2); // +2 to be sure EXPECT_EQ(-1, oc_tcp_connection_state(&ep)); oc_message_unref(msg); + // restore defaults oc_tcp_set_connect_retry(OC_TCP_CONNECT_RETRY_MAX_COUNT, OC_TCP_CONNECT_RETRY_TIMEOUT); } -TEST_F(TestConnectivity, oc_tcp_connect_repeat_fail) +TEST_F(TestConnectivityWithServer, oc_tcp_connect_repeat_fail) { oc_endpoint_t *ep = findEndpoint(g_device); int ret = oc_tcp_connect(ep, on_tcp_connect, this); EXPECT_LE(0, ret); if (ret == OC_TCP_SOCKET_STATE_CONNECTING) { OC_DBG("oc_tcp_connect_repeat_fail wait"); - poolEvents(10); + oc::TestDevice::PoolEvents(10); } EXPECT_EQ(OC_TCP_SOCKET_STATE_CONNECTED, oc_tcp_connection_state(ep)); EXPECT_EQ(OC_TCP_SOCKET_ERROR_EXISTS_CONNECTED, oc_tcp_connect(ep, nullptr, this)); } -TEST_F(TestConnectivity, oc_tcp_connecting_repeat_fail) +TEST_F(TestConnectivityWithServer, oc_tcp_connecting_repeat_fail) { oc_endpoint_t ep = createEndpoint( "coaps+tcp://[::1]:12345"); // reachable address, but inactive port @@ -368,14 +330,14 @@ TEST_F(TestConnectivity, oc_tcp_connecting_repeat_fail) } /** create a TCP session, wait for it to connect and send data */ -TEST_F(TestConnectivity, oc_tcp_send_buffer2) +TEST_F(TestConnectivityWithServer, oc_tcp_send_buffer2) { oc_endpoint_t *ep = findEndpoint(g_device); int ret = oc_tcp_connect(ep, on_tcp_connect, this); EXPECT_LE(0, ret); if (ret == OC_TCP_SOCKET_STATE_CONNECTING) { OC_DBG("oc_tcp_send_buffer2 wait"); - poolEvents(5); + oc::TestDevice::PoolEvents(5); } EXPECT_EQ(OC_TCP_SOCKET_STATE_CONNECTED, oc_tcp_connection_state(ep)); @@ -395,7 +357,7 @@ TEST_F(TestConnectivity, oc_tcp_send_buffer2) /** fail sending a message to an address without an ongoing or waiting TCP * session */ -TEST_F(TestConnectivity, oc_tcp_send_buffer2_not_connected) +TEST_F(TestConnectivityWithServer, oc_tcp_send_buffer2_not_connected) { oc_endpoint_t ep = createEndpoint("coaps+tcp://[ff02::158]:12345"); oc_message_t *msg = oc_allocate_message(); @@ -412,20 +374,28 @@ TEST_F(TestConnectivity, oc_tcp_send_buffer2_not_connected) } #if defined(OC_DNS_LOOKUP) && (defined(OC_DNS_LOOKUP_IPV6) || defined(OC_IPV4)) -/** connecting to existing but not listening endpoint should timeout after 5 - * retries */ -TEST_F(TestConnectivity, oc_tcp_send_buffer2_drop) +/** connecting to existing but not listening endpoint should timeout after max + * number of allowed retries */ +TEST_F(TestConnectivityWithServer, oc_tcp_send_buffer2_drop) { + // timeout 2s, 2 retries -> total 6s + oc_tcp_set_connect_retry(2, 2); + oc_endpoint_t ep = createEndpoint("coap+tcp://openconnectivity.org:3456"); ASSERT_EQ(OC_TCP_SOCKET_STATE_CONNECTING, oc_tcp_connect(&ep, on_tcp_connect_timeout, this)); - while (!s_is_callback_received) { + while (!is_callback_received) { OC_DBG("oc_tcp_send_buffer2_drop wait"); - poolEvents(5); + oc::TestDevice::PoolEvents(5); } + + // restore defaults + oc_tcp_set_connect_retry(OC_TCP_CONNECT_RETRY_MAX_COUNT, + OC_TCP_CONNECT_RETRY_TIMEOUT); } #endif /* OC_DNS_LOOKUP && (OC_DNS_LOOKUP_IPV6 || OC_IPV4) */ #endif /* OC_HAS_FEATURE_TCP_ASYNC_CONNECT */ + #endif /* OC_TCP */ diff --git a/port/windows/vs2015/IoTivity-lite.vcxproj b/port/windows/vs2015/IoTivity-lite.vcxproj index d205bc708e..9ddc69dd0f 100644 --- a/port/windows/vs2015/IoTivity-lite.vcxproj +++ b/port/windows/vs2015/IoTivity-lite.vcxproj @@ -274,7 +274,7 @@ - + diff --git a/port/windows/vs2015/IoTivity-lite.vcxproj.filters b/port/windows/vs2015/IoTivity-lite.vcxproj.filters index e40db92efc..e86c7bb91e 100644 --- a/port/windows/vs2015/IoTivity-lite.vcxproj.filters +++ b/port/windows/vs2015/IoTivity-lite.vcxproj.filters @@ -736,7 +736,7 @@ Security - + Security diff --git a/python/oc_python.c b/python/oc_python.c index 6f62fb6edc..4ce363dcf8 100644 --- a/python/oc_python.c +++ b/python/oc_python.c @@ -421,12 +421,12 @@ add_device_to_list(const oc_uuid_t *uuid, const char *device_name, if (!device) { return false; } - memcpy(device->uuid.id, uuid->id, 16); + memcpy(device->uuid.id, uuid->id, sizeof(device->uuid.id)); oc_list_add(list, device); } size_t len = 0; - if (device_name) { + if (device_name != NULL) { len = strlen(device_name); len = (len > 63) ? 63 : len; memcpy(device->device_name, device_name, len); diff --git a/security/oc_acl.c b/security/oc_acl.c index 5437a3a4cb..80c6dd2697 100644 --- a/security/oc_acl.c +++ b/security/oc_acl.c @@ -103,12 +103,13 @@ get_new_aceid(size_t device) } static oc_ace_res_t * -oc_sec_ace_find_resource(oc_ace_res_t *start, oc_sec_ace_t *ace, +oc_sec_ace_find_resource(oc_ace_res_t *start, const oc_sec_ace_t *ace, const char *href, oc_ace_wildcard_t wildcard) { int skip = 0; - if (href && href[0] != '/') + if (href && href[0] != '/') { skip = 1; + } oc_ace_res_t *res = start; if (!res) { res = (oc_ace_res_t *)oc_list_head(ace->resources); @@ -117,7 +118,8 @@ oc_sec_ace_find_resource(oc_ace_res_t *start, oc_sec_ace_t *ace, } while (res != NULL) { - bool positive = false, match = true; + bool positive = false; + bool match = true; if (href && oc_string_len(res->href) > 0) { if ((strlen(href) + skip) != oc_string_len(res->href) || memcmp(oc_string(res->href) + skip, href, @@ -218,11 +220,9 @@ oc_sec_acl_find_subject(oc_sec_ace_t *start, oc_ace_subject_type_t type, } static uint16_t -oc_ace_get_permission(oc_sec_ace_t *ace, const oc_resource_t *resource, +oc_ace_get_permission(const oc_sec_ace_t *ace, const oc_resource_t *resource, bool is_DCR, bool is_public) { - uint16_t permission = 0; - /* If the resource is discoverable and exposes >=1 unsecured endpoints * then match with ACEs bearing any of the 3 wildcard resources. * If the resource is discoverable and does not expose any unsecured endpoint, @@ -243,9 +243,9 @@ oc_ace_get_permission(oc_sec_ace_t *ace, const oc_resource_t *resource, } } + uint16_t permission = 0; oc_ace_res_t *res = oc_sec_ace_find_resource(NULL, ace, oc_string(resource->uri), wc); - while (res != NULL) { permission |= ace->permission; @@ -317,14 +317,15 @@ dump_acl(size_t device) #endif /* OC_DEBUG */ static uint16_t -get_role_permissions(oc_sec_cred_t *role_cred, const oc_resource_t *resource, - size_t device, bool is_DCR, bool is_public) +get_role_permissions(const oc_sec_cred_t *role_cred, + const oc_resource_t *resource, size_t device, bool is_DCR, + bool is_public) { uint16_t permission = 0; oc_sec_ace_t *match = NULL; do { match = oc_sec_acl_find_subject(match, OC_SUBJECT_ROLE, - (oc_ace_subject_t *)&role_cred->role, + (const oc_ace_subject_t *)&role_cred->role, /*aceid*/ -1, /*permission*/ 0, /*tag*/ NULL, /*match_tag*/ false, device); @@ -460,7 +461,6 @@ oc_sec_check_acl(oc_method_t method, const oc_resource_t *resource, } const oc_sec_pstat_t *pstat = oc_sec_get_pstat(endpoint->device); - const oc_tls_peer_t *peer = oc_tls_get_peer(endpoint); /* All unicast requests which are not received over the open Device DOC * shall be rejected with an appropriate error message (e.g. forbidden), * regardless of the configuration of the ACEs in the "/oic/sec/acl2" @@ -501,6 +501,7 @@ oc_sec_check_acl(oc_method_t method, const oc_resource_t *resource, * regardless of the configuration of the ACEs in the "/oic/sec/acl2" * Resource. */ + const oc_tls_peer_t *peer = oc_tls_get_peer(endpoint); if (peer && peer->doc && is_DCR) { OC_DBG("oc_sec_check_acl: connection is DOC and request directed to DCR - " "access granted"); @@ -568,7 +569,7 @@ oc_sec_check_acl(oc_method_t method, const oc_resource_t *resource, uint16_t permission = 0; oc_sec_ace_t *match = NULL; - if (uuid) { + if (uuid != NULL) { do { match = oc_sec_acl_find_subject( match, OC_SUBJECT_UUID, (const oc_ace_subject_t *)uuid, /*aceid*/ -1, @@ -598,9 +599,9 @@ oc_sec_check_acl(oc_method_t method, const oc_resource_t *resource, } #ifdef OC_PKI else { - oc_sec_cred_t *role_cred = peer ? oc_sec_get_roles(peer) : NULL, *next; + const oc_sec_cred_t *role_cred = peer ? oc_sec_get_roles(peer) : NULL; while (role_cred) { - next = role_cred->next; + const oc_sec_cred_t *next = role_cred->next; uint32_t flags = 0; if (oc_certs_validate_role_cert(role_cred->ctx, &flags) < 0 || flags != 0) { @@ -622,27 +623,28 @@ oc_sec_check_acl(oc_method_t method, const oc_resource_t *resource, #endif /* OC_PKI */ } - /* Access to SVRs via auth-crypt ACEs is prohibited */ - if (!is_SVR && endpoint->flags & SECURED) { - oc_ace_subject_t _auth_crypt; - memset(&_auth_crypt, 0, sizeof(oc_ace_subject_t)); - _auth_crypt.conn = OC_CONN_AUTH_CRYPT; - do { - match = oc_sec_acl_find_subject(match, OC_SUBJECT_CONN, &_auth_crypt, - /*aceid*/ -1, /*permission*/ 0, - /*tag*/ NULL, /*match_tag*/ false, - endpoint->device); - if (match) { - permission |= oc_ace_get_permission(match, resource, is_DCR, is_public); - OC_DBG("oc_check_acl: Found ACE with permission %d for auth-crypt " - "connection", - permission); - } - } while (match); - } - - /* Access to SVRs via anon-clear ACEs is prohibited */ if (!is_SVR) { + /* Access to SVRs via auth-crypt ACEs is prohibited */ + if (endpoint->flags & SECURED) { + oc_ace_subject_t _auth_crypt; + memset(&_auth_crypt, 0, sizeof(oc_ace_subject_t)); + _auth_crypt.conn = OC_CONN_AUTH_CRYPT; + do { + match = oc_sec_acl_find_subject(match, OC_SUBJECT_CONN, &_auth_crypt, + /*aceid*/ -1, /*permission*/ 0, + /*tag*/ NULL, /*match_tag*/ false, + endpoint->device); + if (match) { + permission |= + oc_ace_get_permission(match, resource, is_DCR, is_public); + OC_DBG("oc_check_acl: Found ACE with permission %d for auth-crypt " + "connection", + permission); + } + } while (match); + } + + /* Access to SVRs via anon-clear ACEs is prohibited */ oc_ace_subject_t _anon_clear; memset(&_anon_clear, 0, sizeof(oc_ace_subject_t)); _anon_clear.conn = OC_CONN_ANON_CLEAR; @@ -1087,16 +1089,16 @@ oc_sec_decode_acl(const oc_rep_t *rep, bool from_storage, size_t device, } break; case OC_REP_OBJECT_ARRAY: { - oc_rep_t *aclist2 = rep->value.object_array; + const oc_rep_t *aclist2 = rep->value.object_array; while (aclist2 != NULL) { oc_ace_subject_t subject; + memset(&subject, 0, sizeof(oc_ace_subject_t)); oc_ace_subject_type_t subject_type = 0; uint16_t permission = 0; int aceid = -1; char *tag = NULL; - oc_rep_t *resources = 0; - memset(&subject, 0, sizeof(oc_ace_subject_t)); - oc_rep_t *ace = aclist2->value.object; + const oc_rep_t *resources = 0; + const oc_rep_t *ace = aclist2->value.object; while (ace != NULL) { len = oc_string_len(ace->name); switch (ace->type) { @@ -1120,7 +1122,7 @@ oc_sec_decode_acl(const oc_rep_t *rep, bool from_storage, size_t device, resources = ace->value.object_array; break; case OC_REP_OBJECT: { - oc_rep_t *sub = ace->value.object; + const oc_rep_t *sub = ace->value.object; while (sub != NULL) { len = oc_string_len(sub->name); if (len == 4 && memcmp(oc_string(sub->name), "uuid", 4) == 0) { @@ -1231,16 +1233,15 @@ oc_sec_decode_acl(const oc_rep_t *rep, bool from_storage, size_t device, /* The following code block attaches "coap" endpoints to resources linked to an anon-clear ACE. This logic is being - currently disabled to comply with the SH spec which requires - that all vertical resources not expose a "coap" endpoint. + currently disabled to comply with the SH spec which + requires that all vertical resources not expose a "coap" endpoint. #ifdef OC_SERVER if (subject_type == OC_SUBJECT_CONN && subject.conn == OC_CONN_ANON_CLEAR) { if (href) { oc_resource_t *r = - oc_ri_get_app_resource_by_uri(href, strlen(href), device); - if (r) { - oc_resource_make_public(r); + oc_ri_get_app_resource_by_uri(href, strlen(href), + device); if (r) { oc_resource_make_public(r); } } else { oc_resource_t *r = oc_ri_get_app_resources(); diff --git a/security/oc_ael.c b/security/oc_ael.c index 99c95bbd7b..44ec45d395 100644 --- a/security/oc_ael.c +++ b/security/oc_ael.c @@ -283,10 +283,10 @@ oc_sec_ael_encode(size_t device, oc_interface_mask_t iface_mask, } bool -oc_sec_ael_decode(size_t device, oc_rep_t *rep, bool from_storage) +oc_sec_ael_decode(size_t device, const oc_rep_t *rep, bool from_storage) { oc_sec_ael_t *a = &ael[device]; - oc_rep_t *repc = rep; + const oc_rep_t *repc = rep; for (; repc; repc = repc->next) { size_t len = oc_string_len(repc->name); switch (repc->type) { @@ -295,15 +295,22 @@ oc_sec_ael_decode(size_t device, oc_rep_t *rep, bool from_storage) if (len == 14 && memcmp(oc_string(repc->name), "categoryfilter", 14) == 0) { a->categoryfilter = (uint8_t)repc->value.integer; - } else if (len == 14 && - memcmp(oc_string(repc->name), "priorityfilter", 14) == 0) { + continue; + } + if (len == 14 && + memcmp(oc_string(repc->name), "priorityfilter", 14) == 0) { a->priorityfilter = (uint8_t)repc->value.integer; - } else if (from_storage && len == 8 && - memcmp(oc_string(repc->name), "maxspace", 8) == 0) { + continue; + } + if (from_storage && len == 8 && + memcmp(oc_string(repc->name), "maxspace", 8) == 0) { a->maxsize = (size_t)repc->value.integer; - } else if (from_storage && len == 4 && - memcmp(oc_string(repc->name), "unit", 4) == 0) { + continue; + } + if (from_storage && len == 4 && + memcmp(oc_string(repc->name), "unit", 4) == 0) { a->unit = (oc_sec_ael_unit_t)repc->value.integer; + continue; } break; default: @@ -317,37 +324,42 @@ oc_sec_ael_decode(size_t device, oc_rep_t *rep, bool from_storage) case OC_REP_OBJECT_ARRAY: if (from_storage && len == 6 && memcmp(oc_string(rep->name), "events", 6) == 0) { - for (oc_rep_t *event = rep->value.object_array; event; + for (const oc_rep_t *event = rep->value.object_array; event; event = event->next) { uint8_t category = 0; uint8_t priority = 0; oc_clock_time_t timestamp = 0; - char *aeid = NULL; - char *message = NULL; + const char *aeid = NULL; + const char *message = NULL; size_t aux_sz = 0; - char *aux[AEL_AUX_INFO_MAX_ITEMS] = { 0 }; - for (oc_rep_t *r = event->value.object; r; r = r->next) { + const char *aux[AEL_AUX_INFO_MAX_ITEMS] = { 0 }; + for (const oc_rep_t *r = event->value.object; r; r = r->next) { size_t l = oc_string_len(r->name); switch (r->type) { /* category, priority, timestamp */ case OC_REP_INT: if (l == 8 && memcmp(oc_string(r->name), "category", 8) == 0) { category = (uint8_t)r->value.integer; - } else if (l == 8 && - memcmp(oc_string(r->name), "priority", 8) == 0) { + continue; + } + if (l == 8 && memcmp(oc_string(r->name), "priority", 8) == 0) { priority = (uint8_t)r->value.integer; - } else if (l == 9 && - memcmp(oc_string(r->name), "timestamp", 9) == 0) { + continue; + } + if (l == 9 && memcmp(oc_string(r->name), "timestamp", 9) == 0) { timestamp = (oc_clock_time_t)r->value.integer; + continue; } break; /* aeid, message */ case OC_REP_STRING: if (l == 4 && memcmp(oc_string(r->name), "aeid", 4) == 0) { aeid = oc_string(r->value.string); - } else if (l == 7 && - memcmp(oc_string(r->name), "message", 7) == 0) { + continue; + } + if (l == 7 && memcmp(oc_string(r->name), "message", 7) == 0) { message = oc_string(r->value.string); + continue; } break; /* auxiliaryinfo */ diff --git a/security/oc_ael.h b/security/oc_ael.h index 61231821fb..6c6735d984 100644 --- a/security/oc_ael.h +++ b/security/oc_ael.h @@ -103,7 +103,7 @@ void post_ael(oc_request_t *request, oc_interface_mask_t iface_mask, bool oc_sec_ael_encode(size_t device, oc_interface_mask_t iface_mask, bool to_storage); -bool oc_sec_ael_decode(size_t device, oc_rep_t *rep, bool from_storage); +bool oc_sec_ael_decode(size_t device, const oc_rep_t *rep, bool from_storage); #ifdef __cplusplus } diff --git a/security/oc_cred.c b/security/oc_cred.c index 51e0515bdf..319307b9da 100644 --- a/security/oc_cred.c +++ b/security/oc_cred.c @@ -33,6 +33,7 @@ #include "port/oc_assert.h" #include "port/oc_log.h" #include "util/oc_list.h" +#include "util/oc_macros.h" #include "util/oc_memb.h" #include @@ -436,7 +437,7 @@ get_device_uuid(size_t device) static bool oc_sec_verify_role_cred(const oc_tls_peer_t *client, oc_sec_credusage_t credusage, size_t public_key_len, - oc_string_t public_key, size_t publicdata_size, + const oc_string_t *public_key, size_t publicdata_size, const uint8_t *publicdata) { if (credusage != OC_CREDUSAGE_ROLE_CERT) { @@ -446,7 +447,7 @@ oc_sec_verify_role_cred(const oc_tls_peer_t *client, return false; } if (client->public_key.size > 0 && - memcmp(oc_cast(public_key, uint8_t) + public_key.size - public_key_len, + memcmp(oc_cast(*public_key, uint8_t) + public_key->size - public_key_len, oc_cast(client->public_key, uint8_t) + client->public_key.size - public_key_len, public_key_len) != 0) { @@ -468,13 +469,13 @@ oc_sec_is_equal_cred_data(oc_cred_data_t creddata, const uint8_t *data, } static bool -oc_sec_is_equal_cred_tag(oc_string_t credtag, const char *tag) +oc_sec_is_equal_cred_tag(const oc_string_t *credtag, const char *tag) { - size_t credtag_size = credtag.size; + size_t credtag_size = credtag->size; size_t tag_size = tag != NULL ? strlen(tag) + 1 : 0; return (credtag_size == tag_size) && ((tag == NULL) || - (memcmp(oc_string(credtag), tag, credtag_size) == 0)); + (memcmp(oc_string(*credtag), tag, credtag_size) == 0)); } static bool @@ -508,7 +509,7 @@ oc_sec_is_duplicate_cred(const oc_sec_cred_t *cred, oc_sec_credtype_t credtype, !oc_uuid_is_equal(cred->subjectuuid, subject) || !oc_sec_is_equal_cred_data(cred->privatedata, privatedata, privatedata_size) || - !oc_sec_is_equal_cred_tag(cred->tag, tag)) { + !oc_sec_is_equal_cred_tag(&cred->tag, tag)) { return false; } @@ -529,7 +530,8 @@ oc_sec_is_duplicate_cred(const oc_sec_cred_t *cred, oc_sec_credtype_t credtype, #ifdef OC_PKI static oc_ecdsa_keypair_t * oc_sec_get_valid_ecdsa_keypair(size_t device, size_t public_key_len, - oc_string_t public_key, size_t publicdata_size, + const oc_string_t *public_key, + size_t publicdata_size, const uint8_t *publicdata) { oc_ecdsa_keypair_t *kp = oc_sec_ecdsa_get_keypair(device); @@ -537,7 +539,7 @@ oc_sec_get_valid_ecdsa_keypair(size_t device, size_t public_key_len, return NULL; } if (memcmp(kp->public_key, - oc_cast(public_key, uint8_t) + public_key.size - public_key_len, + oc_cast(*public_key, uint8_t) + public_key->size - public_key_len, public_key_len) != 0) { return NULL; } @@ -575,8 +577,9 @@ oc_sec_add_new_cred(size_t device, bool roles_resource, } if (roles_resource && - !oc_sec_verify_role_cred(client, credusage, (size_t)public_key_len, - public_key, publicdata_size, publicdata)) { + (credtype != OC_CREDTYPE_CERT || + !oc_sec_verify_role_cred(client, credusage, (size_t)public_key_len, + &public_key, publicdata_size, publicdata))) { goto add_new_cred_error; } #endif /* OC_PKI */ @@ -589,7 +592,7 @@ oc_sec_add_new_cred(size_t device, bool roles_resource, oc_ecdsa_keypair_t *kp = NULL; if (credusage == OC_CREDUSAGE_IDENTITY_CERT && privatedata_size == 0) { kp = oc_sec_get_valid_ecdsa_keypair( - device, (size_t)public_key_len, public_key, publicdata_size, publicdata); + device, (size_t)public_key_len, &public_key, publicdata_size, publicdata); if (!kp) { goto add_new_cred_error; } @@ -648,7 +651,7 @@ oc_sec_add_new_cred(size_t device, bool roles_resource, if (publicdata_size > 0 && oc_sec_is_equal_cred_data(cred->publicdata, publicdata, publicdata_size) && - oc_sec_is_equal_cred_tag(cred->tag, tag)) { + oc_sec_is_equal_cred_tag(&cred->tag, tag)) { oc_free_string(&public_key); return cred->credid; } @@ -666,7 +669,7 @@ oc_sec_add_new_cred(size_t device, bool roles_resource, /* Trying to add a duplicate role credential, so ignore */ if (oc_sec_is_equal_cred_data(roles->publicdata, publicdata, publicdata_size) && - oc_sec_is_equal_cred_tag(roles->tag, tag)) { + oc_sec_is_equal_cred_tag(&roles->tag, tag)) { oc_free_string(&public_key); return roles->credid; } @@ -832,15 +835,15 @@ oc_cred_read_credusage(oc_sec_credusage_t credusage) { switch (credusage) { case OC_CREDUSAGE_TRUSTCA: - return "oic.sec.cred.trustca"; + return OC_CREDUSAGE_TRUSTCA_STR; case OC_CREDUSAGE_IDENTITY_CERT: - return "oic.sec.cred.cert"; + return OC_CREDUSAGE_IDENTITY_CERT_STR; case OC_CREDUSAGE_ROLE_CERT: - return "oic.sec.cred.rolecert"; + return OC_CREDUSAGE_ROLE_CERT_STR; case OC_CREDUSAGE_MFG_TRUSTCA: - return "oic.sec.cred.mfgtrustca"; + return OC_CREDUSAGE_MFG_TRUSTCA_STR; case OC_CREDUSAGE_MFG_CERT: - return "oic.sec.cred.mfgcert"; + return OC_CREDUSAGE_MFG_CERT_STR; default: break; } @@ -853,15 +856,15 @@ oc_cred_read_encoding(oc_sec_encoding_t encoding) { switch (encoding) { case OC_ENCODING_BASE64: - return "oic.sec.encoding.base64"; + return OC_ENCODING_BASE64_STR; case OC_ENCODING_RAW: - return "oic.sec.encoding.raw"; + return OC_ENCODING_RAW_STR; #ifdef OC_PKI case OC_ENCODING_PEM: - return "oic.sec.encoding.pem"; + return OC_ENCODING_PEM_STR; #endif /* OC_PKI */ case OC_ENCODING_HANDLE: - return "oic.sec.encoding.handle"; + return OC_ENCODING_HANDLE_STR; default: break; } @@ -977,7 +980,7 @@ oc_sec_encode_cred(size_t device, oc_interface_mask_t iface_mask, if (strlen(encoding_string) > 7) { oc_rep_set_text_string(privatedata, encoding, encoding_string); } else { - oc_rep_set_text_string(privatedata, encoding, "oic.sec.encoding.raw"); + oc_rep_set_text_string(privatedata, encoding, OC_ENCODING_RAW_STR); } oc_rep_close_object(creds, privatedata); #ifdef OC_OSCORE @@ -1052,30 +1055,36 @@ oc_sec_encode_cred(size_t device, oc_interface_mask_t iface_mask, #ifdef OC_PKI oc_sec_credusage_t -oc_cred_parse_credusage(oc_string_t *credusage_string) +oc_cred_usage_from_string(const char *str, size_t str_len) { - oc_sec_credusage_t credusage = 0; - if (oc_string_len(*credusage_string) == 20 && - memcmp("oic.sec.cred.trustca", oc_string(*credusage_string), 20) == 0) { - credusage = OC_CREDUSAGE_TRUSTCA; - } else if (oc_string_len(*credusage_string) == 17 && - memcmp("oic.sec.cred.cert", oc_string(*credusage_string), 17) == - 0) { - credusage = OC_CREDUSAGE_IDENTITY_CERT; - } else if (oc_string_len(*credusage_string) == 21 && - memcmp("oic.sec.cred.rolecert", oc_string(*credusage_string), - 21) == 0) { - credusage = OC_CREDUSAGE_ROLE_CERT; - } else if (oc_string_len(*credusage_string) == 23 && - memcmp("oic.sec.cred.mfgtrustca", oc_string(*credusage_string), - 23) == 0) { - credusage = OC_CREDUSAGE_MFG_TRUSTCA; - } else if (oc_string_len(*credusage_string) == 20 && - memcmp("oic.sec.cred.mfgcert", oc_string(*credusage_string), 20) == - 0) { - credusage = OC_CREDUSAGE_MFG_CERT; - } - return credusage; + if (str_len == OC_CHAR_ARRAY_LEN(OC_CREDUSAGE_TRUSTCA_STR) && + memcmp(OC_CREDUSAGE_TRUSTCA_STR, str, str_len) == 0) { + return OC_CREDUSAGE_TRUSTCA; + } + if (str_len == OC_CHAR_ARRAY_LEN(OC_CREDUSAGE_IDENTITY_CERT_STR) && + memcmp(OC_CREDUSAGE_IDENTITY_CERT_STR, str, str_len) == 0) { + return OC_CREDUSAGE_IDENTITY_CERT; + } + if (str_len == OC_CHAR_ARRAY_LEN(OC_CREDUSAGE_ROLE_CERT_STR) && + memcmp(OC_CREDUSAGE_ROLE_CERT_STR, str, str_len) == 0) { + return OC_CREDUSAGE_ROLE_CERT; + } + if (str_len == OC_CHAR_ARRAY_LEN(OC_CREDUSAGE_MFG_TRUSTCA_STR) && + memcmp(OC_CREDUSAGE_MFG_TRUSTCA_STR, str, str_len) == 0) { + return OC_CREDUSAGE_MFG_TRUSTCA; + } + if (str_len == OC_CHAR_ARRAY_LEN(OC_CREDUSAGE_MFG_CERT_STR) && + memcmp(OC_CREDUSAGE_MFG_CERT_STR, str, str_len) == 0) { + return OC_CREDUSAGE_MFG_CERT; + } + return OC_CREDUSAGE_NULL; +} + +oc_sec_credusage_t +oc_cred_parse_credusage(const oc_string_t *credusage_string) +{ + return oc_cred_usage_from_string(oc_string(*credusage_string), + oc_string_len(*credusage_string)); } static bool @@ -1194,29 +1203,34 @@ oc_cred_verify_certificate_chain(const oc_sec_cred_t *cred, #endif /* OC_PKI */ oc_sec_encoding_t -oc_cred_parse_encoding(oc_string_t *encoding_string) +oc_cred_encoding_from_string(const char *str, size_t str_len) { - oc_sec_encoding_t encoding = 0; - if (oc_string_len(*encoding_string) == 23 && - memcmp("oic.sec.encoding.base64", oc_string(*encoding_string), 23) == 0) { - encoding = OC_ENCODING_BASE64; - } else if (oc_string_len(*encoding_string) == 20 && - memcmp("oic.sec.encoding.raw", oc_string(*encoding_string), 20) == - 0) { - encoding = OC_ENCODING_RAW; - } else if (oc_string_len(*encoding_string) == 23 && - memcmp("oic.sec.encoding.handle", oc_string(*encoding_string), - 23) == 0) { - encoding = OC_ENCODING_HANDLE; + if (str_len == OC_CHAR_ARRAY_LEN(OC_ENCODING_BASE64_STR) && + memcmp(OC_ENCODING_BASE64_STR, str, str_len) == 0) { + return OC_ENCODING_BASE64; + } + if (str_len == OC_CHAR_ARRAY_LEN(OC_ENCODING_RAW_STR) && + memcmp(OC_ENCODING_RAW_STR, str, str_len) == 0) { + return OC_ENCODING_RAW; + } + if (str_len == OC_CHAR_ARRAY_LEN(OC_ENCODING_HANDLE_STR) && + memcmp(OC_ENCODING_HANDLE_STR, str, str_len) == 0) { + return OC_ENCODING_HANDLE; } #ifdef OC_PKI - else if (oc_string_len(*encoding_string) == 20 && - memcmp("oic.sec.encoding.pem", oc_string(*encoding_string), 20) == - 0) { - encoding = OC_ENCODING_PEM; + if (str_len == OC_CHAR_ARRAY_LEN(OC_ENCODING_PEM_STR) && + memcmp(OC_ENCODING_PEM_STR, str, str_len) == 0) { + return OC_ENCODING_PEM; } #endif /* OC_PKI */ - return encoding; + return OC_ENCODING_UNSUPPORTED; +} + +oc_sec_encoding_t +oc_cred_parse_encoding(const oc_string_t *encoding_string) +{ + return oc_cred_encoding_from_string(oc_string(*encoding_string), + oc_string_len(*encoding_string)); } #ifdef OC_OSCORE @@ -1297,28 +1311,32 @@ oc_sec_decode_cred(const oc_rep_t *rep, oc_sec_cred_t **owner, case OC_REP_OBJECT_ARRAY: { if (len == 5 && (memcmp(oc_string(rep->name), "creds", 5) == 0 || memcmp(oc_string(rep->name), "roles", 5) == 0)) { - oc_rep_t *creds_array = rep->value.object_array; + const oc_rep_t *creds_array = rep->value.object_array; /* array of oic.sec.cred */ while (creds_array != NULL) { - oc_rep_t *cred = creds_array->value.object; + const oc_rep_t *cred = creds_array->value.object; int credid = -1; oc_sec_credtype_t credtype = 0; - char *role = NULL, *authority = NULL, *subjectuuid = NULL, - *privatedata = NULL; + const char *role = NULL; + const char *authority = NULL; + const char *subjectuuid = NULL; + const char *privatedata = NULL; oc_sec_encoding_t privatedatatype = 0; size_t privatedata_size = 0; #ifdef OC_PKI oc_sec_credusage_t credusage = 0; - char *publicdata = NULL; + const char *publicdata = NULL; oc_sec_encoding_t publicdatatype = 0; size_t publicdata_size = 0; #endif /* OC_PKI */ #ifdef OC_OSCORE - const char *sid = NULL, *rid = NULL, *desc = NULL; + const char *sid = NULL; + const char *rid = NULL; + const char *desc = NULL; uint64_t ssn = 0; #endif /* OC_OSCORE */ bool owner_cred = false; - char *tag = NULL; + const char *tag = NULL; bool non_empty = false; while (cred != NULL) { non_empty = true; @@ -1361,7 +1379,7 @@ oc_sec_decode_cred(const oc_rep_t *rep, oc_sec_cred_t **owner, #endif /* OC_PKI */ ) { size_t *size = 0; - char **pubpriv = 0; + const char **pubpriv = 0; oc_sec_encoding_t *encoding = 0; if (len == 11) { size = &privatedata_size; diff --git a/security/oc_cred_internal.h b/security/oc_cred_internal.h index 17ed5f493a..e4e07dd757 100644 --- a/security/oc_cred_internal.h +++ b/security/oc_cred_internal.h @@ -39,6 +39,20 @@ typedef struct ///< credential replaced a previously existing one } oc_sec_add_new_cred_data_t; +#define OC_ENCODING_BASE64_STR "oic.sec.encoding.base64" +#define OC_ENCODING_RAW_STR "oic.sec.encoding.raw" +#define OC_ENCODING_HANDLE_STR "oic.sec.encoding.handle" +#ifdef OC_PKI +#define OC_ENCODING_PEM_STR "oic.sec.encoding.pem" + +#define OC_CREDUSAGE_TRUSTCA_STR "oic.sec.cred.trustca" +#define OC_CREDUSAGE_IDENTITY_CERT_STR "oic.sec.cred.cert" +#define OC_CREDUSAGE_ROLE_CERT_STR "oic.sec.cred.rolecert" +#define OC_CREDUSAGE_MFG_TRUSTCA_STR "oic.sec.cred.mfgtrustca" +#define OC_CREDUSAGE_MFG_CERT_STR "oic.sec.cred.mfgcert" + +#endif /* OC_PKI */ + int oc_sec_add_new_cred( size_t device, bool roles_resource, const struct oc_tls_peer_t *client, int credid, oc_sec_credtype_t credtype, oc_sec_credusage_t credusage, @@ -58,9 +72,28 @@ bool oc_sec_decode_cred(const oc_rep_t *rep, oc_sec_cred_t **owner, const struct oc_tls_peer_t *client, size_t device, oc_sec_on_apply_cred_cb_t on_apply_cred_cb, void *on_apply_cred_data); + +/** + * @brief Parse cred encoding from string + * + * @param str string (cannot be NULL) + * @param str_len length of \p str + * @return oc_sec_encoding_t parsed encoding + */ +oc_sec_encoding_t oc_cred_encoding_from_string(const char *str, size_t str_len); + +/** + * @brief Parse cred usage from string + * + * @param str string (cannot be NULL) + * @param str_len length of \p str + * @return oc_sec_credusage_t parsed usage + */ +oc_sec_credusage_t oc_cred_usage_from_string(const char *str, size_t str_len); + /** - * @brief Allocate and initialize a new credential and append it to global list - * of device credentials. + * @brief Allocate and initialize a new credential and append it to global + * list of device credentials. * * @param subjectuuid subject uuid (cannot be NULL) * @param credtype credential type diff --git a/security/oc_csr.c b/security/oc_csr.c index e42671e8a1..f1c9a69a8f 100644 --- a/security/oc_csr.c +++ b/security/oc_csr.c @@ -246,7 +246,7 @@ get_csr(oc_request_t *request, oc_interface_mask_t iface_mask, void *data) oc_core_get_resource_by_index(OCF_SEC_CSR, device)); } oc_rep_set_text_string(root, csr, (const char *)csr); - oc_rep_set_text_string(root, encoding, "oic.sec.encoding.pem"); + oc_rep_set_text_string(root, encoding, OC_ENCODING_PEM_STR); oc_rep_end_root_object(); oc_send_response(request, OC_STATUS_OK); diff --git a/security/oc_obt.c b/security/oc_obt.c index 8391827cb0..7fa1609dd1 100644 --- a/security/oc_obt.c +++ b/security/oc_obt.c @@ -42,7 +42,7 @@ check oc_config.h and make sure OC_STORAGE is defined if OC_SECURITY is defined. #include "security/oc_keypair_internal.h" #include "security/oc_obt_internal.h" #include "security/oc_pstat.h" -#include "security/oc_sdi.h" +#include "security/oc_sdi_internal.h" #include "security/oc_tls.h" #include @@ -1044,7 +1044,7 @@ device1oscore_cred(oc_client_response_t *data) oc_rep_set_object(creds, privatedata); oc_rep_set_byte_string(privatedata, data, p->secret, OSCORE_MASTER_SECRET_LEN); - oc_rep_set_text_string(privatedata, encoding, "oic.sec.encoding.raw"); + oc_rep_set_text_string(privatedata, encoding, OC_ENCODING_RAW_STR); oc_rep_close_object(creds, privatedata); oc_rep_set_object(creds, oscore); @@ -1105,7 +1105,7 @@ device2oscore_RFPRO(int status, void *data) oc_rep_set_object(creds, privatedata); oc_rep_set_byte_string(privatedata, data, p->secret, OSCORE_MASTER_SECRET_LEN); - oc_rep_set_text_string(privatedata, encoding, "oic.sec.encoding.raw"); + oc_rep_set_text_string(privatedata, encoding, OC_ENCODING_RAW_STR); oc_rep_close_object(creds, privatedata); oc_rep_set_object(creds, oscore); @@ -1288,7 +1288,7 @@ deviceoscoregroup_RFPRO(int status, void *data) oc_rep_set_object(creds, privatedata); oc_rep_set_byte_string(privatedata, data, g_group_secret, OSCORE_MASTER_SECRET_LEN); - oc_rep_set_text_string(privatedata, encoding, "oic.sec.encoding.raw"); + oc_rep_set_text_string(privatedata, encoding, OC_ENCODING_RAW_STR); oc_rep_close_object(creds, privatedata); oc_rep_set_object(creds, oscore); @@ -1505,7 +1505,7 @@ device1_cred(oc_client_response_t *data) oc_rep_set_object(creds, privatedata); oc_rep_set_byte_string(privatedata, data, p->key, 16); - oc_rep_set_text_string(privatedata, encoding, "oic.sec.encoding.raw"); + oc_rep_set_text_string(privatedata, encoding, OC_ENCODING_RAW_STR); oc_rep_close_object(creds, privatedata); oc_rep_object_array_end_item(creds); @@ -1547,7 +1547,7 @@ device2_RFPRO(int status, void *data) oc_rep_set_object(creds, privatedata); oc_rep_set_byte_string(privatedata, data, p->key, 16); - oc_rep_set_text_string(privatedata, encoding, "oic.sec.encoding.raw"); + oc_rep_set_text_string(privatedata, encoding, OC_ENCODING_RAW_STR); oc_rep_close_object(creds, privatedata); oc_rep_object_array_end_item(creds); @@ -1857,12 +1857,14 @@ device_CSR(oc_client_response_t *data) goto err_device_CSR; } - size_t encoding_len = 0; - char *encoding = NULL; - if (!oc_rep_get_string(data->payload, "encoding", &encoding, &encoding_len)) { + size_t enc_len = 0; + char *enc = NULL; + if (!oc_rep_get_string(data->payload, "encoding", &enc, &enc_len) || + enc_len == 0) { goto err_device_CSR; } - if (encoding_len != 20 || memcmp(encoding, "oic.sec.encoding.pem", 20) != 0) { + oc_sec_encoding_t encoding = oc_cred_encoding_from_string(enc, enc_len); + if (encoding != OC_ENCODING_PEM) { goto err_device_CSR; } @@ -1896,12 +1898,12 @@ device_CSR(oc_client_response_t *data) oc_rep_set_object(creds, publicdata); oc_rep_set_text_string(publicdata, data, (const char *)cert_pem); - oc_rep_set_text_string(publicdata, encoding, "oic.sec.encoding.pem"); + oc_rep_set_text_string(publicdata, encoding, OC_ENCODING_PEM_STR); oc_rep_close_object(creds, publicdata); if (p->roles) { - oc_rep_set_text_string(creds, credusage, "oic.sec.cred.rolecert"); + oc_rep_set_text_string(creds, credusage, OC_CREDUSAGE_ROLE_CERT_STR); } else { - oc_rep_set_text_string(creds, credusage, "oic.sec.cred.cert"); + oc_rep_set_text_string(creds, credusage, OC_CREDUSAGE_IDENTITY_CERT_STR); } oc_rep_object_array_end_item(creds); oc_rep_close_array(root, creds); @@ -1969,10 +1971,10 @@ device_RFPRO(int status, void *data) oc_rep_set_object(creds, publicdata); oc_rep_set_text_string(publicdata, data, oc_string(root->publicdata.data)); - oc_rep_set_text_string(publicdata, encoding, "oic.sec.encoding.pem"); + oc_rep_set_text_string(publicdata, encoding, OC_ENCODING_PEM_STR); oc_rep_close_object(creds, publicdata); - oc_rep_set_text_string(creds, credusage, "oic.sec.cred.trustca"); + oc_rep_set_text_string(creds, credusage, OC_CREDUSAGE_TRUSTCA_STR); oc_rep_object_array_end_item(creds); oc_rep_close_array(root, creds); @@ -2184,10 +2186,10 @@ trustanchor_device_RFPRO(int status, void *response_data) oc_rep_set_object(creds, publicdata); oc_rep_set_text_string(publicdata, data, p->trustanchor); - oc_rep_set_text_string(publicdata, encoding, "oic.sec.encoding.pem"); + oc_rep_set_text_string(publicdata, encoding, OC_ENCODING_PEM_STR); oc_rep_close_object(creds, publicdata); - oc_rep_set_text_string(creds, credusage, "oic.sec.cred.trustca"); + oc_rep_set_text_string(creds, credusage, OC_CREDUSAGE_TRUSTCA_STR); oc_rep_object_array_end_item(creds); oc_rep_close_array(root, creds); @@ -3655,7 +3657,7 @@ oc_obt_general_delete(const oc_uuid_t *uuid, const char *query, const char *url, void oc_obt_set_sd_info(const char *name, bool priv) { - oc_sec_sdi_t *sdi = oc_sec_get_sdi(0); + oc_sec_sdi_t *sdi = oc_sec_sdi_get(0); oc_free_string(&sdi->name); oc_new_string(&sdi->name, name, strlen(name)); sdi->priv = priv; @@ -3723,7 +3725,7 @@ oc_obt_self_own(size_t device) oc_sec_acl_add_bootstrap_acl(device); - oc_sec_sdi_t *sdi = oc_sec_get_sdi(device); + oc_sec_sdi_t *sdi = oc_sec_sdi_get(device); const oc_device_info_t *self = oc_core_get_device_info(device); oc_gen_uuid(&sdi->uuid); oc_new_string(&sdi->name, oc_string(self->name), oc_string_len(self->name)); diff --git a/security/oc_obt_otm_cert.c b/security/oc_obt_otm_cert.c index c5e72fe1f8..ad38fb0753 100644 --- a/security/oc_obt_otm_cert.c +++ b/security/oc_obt_otm_cert.c @@ -31,7 +31,7 @@ #include "security/oc_doxm_internal.h" #include "security/oc_obt_internal.h" #include "security/oc_pstat.h" -#include "security/oc_sdi.h" +#include "security/oc_sdi_internal.h" #include "security/oc_tls.h" /* Manufacturer certificate-based ownership transfer */ @@ -172,7 +172,7 @@ obt_cert_14(oc_client_response_t *data) if (o->sdi) { oc_rep_object_array_start_item(resources); - oc_rep_set_text_string(resources, href, "/oic/sec/sdi"); + oc_rep_set_text_string(resources, href, OCF_SEC_SDI_URI); oc_rep_object_array_end_item(resources); } @@ -301,7 +301,7 @@ obt_cert_10(oc_client_response_t *data) goto err_obt_cert_10; } - oc_sec_sdi_t *sdi = oc_sec_get_sdi(0); + const oc_sec_sdi_t *sdi = oc_sec_sdi_get(0); char sdi_uuid[OC_UUID_LEN]; oc_uuid_to_str(&sdi->uuid, sdi_uuid, OC_UUID_LEN); @@ -309,7 +309,7 @@ obt_cert_10(oc_client_response_t *data) */ const oc_device_t *device = o->device; const oc_endpoint_t *ep = oc_obt_get_secure_endpoint(device->endpoint); - if (oc_init_post("/oic/sec/sdi", ep, NULL, &obt_cert_11, HIGH_QOS, o)) { + if (oc_init_post(OCF_SEC_SDI_URI, ep, NULL, &obt_cert_11, HIGH_QOS, o)) { oc_rep_start_root_object(); oc_rep_set_text_string(root, uuid, sdi_uuid); oc_rep_set_text_string(root, name, oc_string(sdi->name)); @@ -380,7 +380,7 @@ obt_cert_9(oc_client_response_t *data) oc_rep_set_text_string(creds, subjectuuid, uuid); oc_rep_set_object(creds, privatedata); - oc_rep_set_text_string(privatedata, encoding, "oic.sec.encoding.raw"); + oc_rep_set_text_string(privatedata, encoding, OC_ENCODING_RAW_STR); oc_rep_set_byte_string(privatedata, data, (const uint8_t *)"", 0); oc_rep_close_object(creds, privatedata); diff --git a/security/oc_obt_otm_justworks.c b/security/oc_obt_otm_justworks.c index 488d3cac84..0d3f4f5618 100644 --- a/security/oc_obt_otm_justworks.c +++ b/security/oc_obt_otm_justworks.c @@ -30,7 +30,7 @@ #include "security/oc_doxm_internal.h" #include "security/oc_obt_internal.h" #include "security/oc_pstat.h" -#include "security/oc_sdi.h" +#include "security/oc_sdi_internal.h" #include "security/oc_tls.h" /* Just-works ownership transfer */ @@ -171,7 +171,7 @@ obt_jw_14(oc_client_response_t *data) if (o->sdi) { oc_rep_object_array_start_item(resources); - oc_rep_set_text_string(resources, href, "/oic/sec/sdi"); + oc_rep_set_text_string(resources, href, OCF_SEC_SDI_URI); oc_rep_object_array_end_item(resources); } @@ -300,7 +300,7 @@ obt_jw_10(oc_client_response_t *data) goto err_obt_jw_10; } - oc_sec_sdi_t *sdi = oc_sec_get_sdi(0); + const oc_sec_sdi_t *sdi = oc_sec_sdi_get(0); char sdi_uuid[OC_UUID_LEN]; oc_uuid_to_str(&sdi->uuid, sdi_uuid, OC_UUID_LEN); @@ -308,7 +308,7 @@ obt_jw_10(oc_client_response_t *data) */ const oc_device_t *device = o->device; const oc_endpoint_t *ep = oc_obt_get_secure_endpoint(device->endpoint); - if (oc_init_post("/oic/sec/sdi", ep, NULL, &obt_jw_11, HIGH_QOS, o)) { + if (oc_init_post(OCF_SEC_SDI_URI, ep, NULL, &obt_jw_11, HIGH_QOS, o)) { oc_rep_start_root_object(); oc_rep_set_text_string(root, uuid, sdi_uuid); oc_rep_set_text_string(root, name, oc_string(sdi->name)); @@ -379,7 +379,7 @@ obt_jw_9(oc_client_response_t *data) oc_rep_set_text_string(creds, subjectuuid, uuid); oc_rep_set_object(creds, privatedata); - oc_rep_set_text_string(privatedata, encoding, "oic.sec.encoding.raw"); + oc_rep_set_text_string(privatedata, encoding, OC_ENCODING_RAW_STR); oc_rep_set_byte_string(privatedata, data, (const uint8_t *)"", 0); oc_rep_close_object(creds, privatedata); diff --git a/security/oc_obt_otm_randompin.c b/security/oc_obt_otm_randompin.c index 69c73ce9a0..edee121f24 100644 --- a/security/oc_obt_otm_randompin.c +++ b/security/oc_obt_otm_randompin.c @@ -30,7 +30,7 @@ #include "security/oc_doxm_internal.h" #include "security/oc_obt_internal.h" #include "security/oc_pstat.h" -#include "security/oc_sdi.h" +#include "security/oc_sdi_internal.h" #include "security/oc_tls.h" /* Random PIN OTM */ @@ -174,7 +174,7 @@ obt_rdp_12(oc_client_response_t *data) if (o->sdi) { oc_rep_object_array_start_item(resources); - oc_rep_set_text_string(resources, href, "/oic/sec/sdi"); + oc_rep_set_text_string(resources, href, OCF_SEC_SDI_URI); oc_rep_object_array_end_item(resources); } @@ -303,7 +303,7 @@ obt_rdp_8(oc_client_response_t *data) goto err_obt_rdp_8; } - oc_sec_sdi_t *sdi = oc_sec_get_sdi(0); + const oc_sec_sdi_t *sdi = oc_sec_sdi_get(0); char sdi_uuid[OC_UUID_LEN]; oc_uuid_to_str(&sdi->uuid, sdi_uuid, OC_UUID_LEN); @@ -311,7 +311,7 @@ obt_rdp_8(oc_client_response_t *data) */ const oc_device_t *device = o->device; const oc_endpoint_t *ep = oc_obt_get_secure_endpoint(device->endpoint); - if (oc_init_post("/oic/sec/sdi", ep, NULL, &obt_rdp_9, HIGH_QOS, o)) { + if (oc_init_post(OCF_SEC_SDI_URI, ep, NULL, &obt_rdp_9, HIGH_QOS, o)) { oc_rep_start_root_object(); oc_rep_set_text_string(root, uuid, sdi_uuid); oc_rep_set_text_string(root, name, oc_string(sdi->name)); @@ -382,7 +382,7 @@ obt_rdp_7(oc_client_response_t *data) oc_rep_set_text_string(creds, subjectuuid, uuid); oc_rep_set_object(creds, privatedata); - oc_rep_set_text_string(privatedata, encoding, "oic.sec.encoding.raw"); + oc_rep_set_text_string(privatedata, encoding, OC_ENCODING_RAW_STR); oc_rep_set_byte_string(privatedata, data, (const uint8_t *)"", 0); oc_rep_close_object(creds, privatedata); diff --git a/security/oc_pki.c b/security/oc_pki.c index 23869df190..1a9ab17f64 100644 --- a/security/oc_pki.c +++ b/security/oc_pki.c @@ -37,7 +37,6 @@ pki_add_intermediate_cert(size_t device, int credid, const unsigned char *cert, size_t cert_size) { OC_DBG("attempting to add an intermediate CA certificate"); - int ret = 0; oc_sec_creds_t *creds = oc_sec_get_creds(device); oc_sec_cred_t *c = oc_list_head(creds->creds); for (; c != NULL && c->credid != credid; c = c->next) @@ -60,7 +59,7 @@ pki_add_intermediate_cert(size_t device, int credid, const unsigned char *cert, c_size += 1; } - ret = mbedtls_x509_crt_parse(&int_ca, cert, c_size); + int ret = mbedtls_x509_crt_parse(&int_ca, cert, c_size); if (ret < 0) { OC_ERR("could not parse intermediate cert: %d", ret); return -1; @@ -103,36 +102,34 @@ pki_add_intermediate_cert(size_t device, int credid, const unsigned char *cert, /* Confirm that the intermediate cert is the issuer of the last cert * in the chain, if not return. */ - if (oc_certs_is_subject_the_issuer(&int_ca, id_cert) == 0) { - oc_string_t chain = c->publicdata.data; - size_t new_publicdata_size = oc_string_len(chain) + c_size; - oc_alloc_string(&c->publicdata.data, new_publicdata_size); - memcpy(oc_string(c->publicdata.data), oc_string(chain), - oc_string_len(chain)); - memcpy(oc_string(c->publicdata.data) + oc_string_len(chain), cert, - cert_size); - oc_string(c->publicdata.data)[new_publicdata_size - 1] = '\0'; - oc_free_string(&chain); - OC_DBG("adding a new intermediate CA cert to /oic/sec/cred"); - oc_sec_dump_cred(device); - ret = 1; - } else { - OC_ERR("supplied intermediate CA cert is not issuer of identity cert"); - ret = -1; + if (oc_certs_is_subject_the_issuer(&int_ca, id_cert) != 0) { + OC_ERR("could not add intermediate CA cert to /oic/sec/cred: supplied " + "intermediate CA cert is not issuer of identity cert"); + mbedtls_x509_crt_free(&int_ca); + mbedtls_x509_crt_free(&id_cert_chain); + return -1; } + oc_string_t chain; + oc_new_string(&chain, oc_string(c->publicdata.data), + oc_string_len(c->publicdata.data)); + oc_free_string(&c->publicdata.data); + size_t new_publicdata_size = oc_string_len(chain) + c_size; + oc_alloc_string(&c->publicdata.data, new_publicdata_size); + memcpy(oc_string(c->publicdata.data), oc_string(chain), oc_string_len(chain)); + memcpy(oc_string(c->publicdata.data) + oc_string_len(chain), cert, cert_size); + oc_string(c->publicdata.data)[new_publicdata_size - 1] = '\0'; + oc_free_string(&chain); + OC_DBG("adding a new intermediate CA cert to /oic/sec/cred"); + oc_sec_dump_cred(device); + mbedtls_x509_crt_free(&int_ca); mbedtls_x509_crt_free(&id_cert_chain); - if (ret > 0) { - OC_DBG( - "added intermediate CA(identity cred credid=%d) cert to /oic/sec/cred", - credid); - oc_tls_resolve_new_identity_certs(); - return credid; - } - OC_ERR("could not add intermediate CA cert to /oic/sec/cred"); - return -1; + OC_DBG("added intermediate CA(identity cred credid=%d) cert to /oic/sec/cred", + credid); + oc_tls_resolve_new_identity_certs(); + return credid; } static int diff --git a/security/oc_pstat.c b/security/oc_pstat.c index ebb200efb8..df91739300 100644 --- a/security/oc_pstat.c +++ b/security/oc_pstat.c @@ -30,10 +30,11 @@ #include "oc_cred_internal.h" #include "oc_doxm_internal.h" #include "oc_roles_internal.h" -#include "oc_sdi.h" +#include "oc_sdi_internal.h" #include "oc_sp_internal.h" #include "oc_store.h" #include "oc_tls.h" +#include "port/oc_assert.h" #ifdef OC_CLOUD #include "api/cloud/oc_cloud_internal.h" @@ -47,20 +48,21 @@ #include "api/oc_swupdate_internal.h" #endif /* OC_SOFTWARE_UPDATE */ +#include + #ifdef OC_DYNAMIC_ALLOCATION -#include "port/oc_assert.h" #include -static oc_sec_pstat_t *pstat; +static oc_sec_pstat_t *g_pstat = NULL; #else /* OC_DYNAMIC_ALLOCATION */ -static oc_sec_pstat_t pstat[OC_MAX_NUM_DEVICES]; +static oc_sec_pstat_t g_pstat[OC_MAX_NUM_DEVICES] = { 0 }; #endif /* !OC_DYNAMIC_ALLOCATION */ void oc_sec_pstat_free(void) { #ifdef OC_DYNAMIC_ALLOCATION - if (pstat) { - free(pstat); + if (g_pstat != NULL) { + free(g_pstat); } #endif /* OC_DYNAMIC_ALLOCATION */ } @@ -69,19 +71,18 @@ void oc_sec_pstat_init(void) { #ifdef OC_DYNAMIC_ALLOCATION - pstat = + g_pstat = (oc_sec_pstat_t *)calloc(oc_core_get_num_devices(), sizeof(oc_sec_pstat_t)); - if (!pstat) { + if (!g_pstat) { oc_abort("Insufficient memory"); } #endif /* OC_DYNAMIC_ALLOCATION */ } static bool -nil_uuid(oc_uuid_t *uuid) +nil_uuid(const oc_uuid_t *uuid) { - int i; - for (i = 0; i < 16; i++) { + for (size_t i = 0; i < sizeof(uuid->id); ++i) { if (uuid->id[i] != 0) { return false; } @@ -91,7 +92,7 @@ nil_uuid(oc_uuid_t *uuid) #ifdef OC_DEBUG static void -dump_pstat_dos(oc_sec_pstat_t *ps) +dump_pstat_dos(const oc_sec_pstat_t *ps) { switch (ps->s) { case OC_DOS_RESET: @@ -116,7 +117,7 @@ dump_pstat_dos(oc_sec_pstat_t *ps) static bool valid_transition(size_t device, oc_dostype_t state) { - switch (pstat[device].s) { + switch (g_pstat[device].s) { case OC_DOS_RESET: if (state == OC_DOS_RESET || state == OC_DOS_RFOTM) return true; @@ -150,14 +151,105 @@ close_all_tls_sessions(void *data) return OC_EVENT_DONE; } +static bool +pstat_check_ps_state(const oc_sec_pstat_t *ps) +{ + switch (ps->s) { + case OC_DOS_RFPRO: + if (ps->isop || (ps->cm & 0xC3) != 0 || (ps->tm & 0xC3) != 0) { + return false; + } + break; + case OC_DOS_RFNOP: + if (!ps->isop || (ps->cm & 0xC3) != 0 || (ps->tm & 0xC3) != 0) { + return false; + } + break; + case OC_DOS_SRESET: + if (ps->isop || ps->cm != 1 || (ps->tm & 0xC3)) { + return false; + } + break; + case OC_DOS_RESET: + case OC_DOS_RFOTM: + if (ps->isop || (ps->cm & 0xC3) != 2 || (ps->tm & 0xC3) != 0) { + return false; + } + break; + default: + break; + } + + return true; +} + +static bool +pstat_check_state(const oc_sec_pstat_t *ps, size_t device) +{ + if (!pstat_check_ps_state(ps)) { + OC_DBG("pstat:invalid state"); + return false; + } + + if (nil_uuid(&ps->rowneruuid)) { + OC_DBG("pstat:rowneruuid is nil"); + return false; + } + if (!oc_sec_find_creds_for_subject(NULL, &ps->rowneruuid, device)) { + OC_DBG("Could not find credential for pstat:rowneruuid"); + return false; + } + + const oc_sec_doxm_t *doxm = oc_sec_get_doxm(device); + if (!doxm->owned) { + OC_DBG("doxm:owned is false"); + return false; + } + if (nil_uuid(&doxm->devowneruuid)) { + OC_DBG("doxm:devowneruuid is nil"); + return false; + } + if (nil_uuid(&doxm->deviceuuid)) { + OC_DBG("doxm:deviceuuid is nil"); + return false; + } + if (nil_uuid(&doxm->rowneruuid)) { + OC_DBG("doxm:rowneruuid is nil"); + return false; + } + if (!oc_sec_find_creds_for_subject(NULL, &doxm->rowneruuid, device)) { + OC_DBG("Could not find credential for doxm:rowneruuid"); + return false; + } + + const oc_sec_acl_t *acl = oc_sec_get_acl(device); + if (nil_uuid(&acl->rowneruuid)) { + OC_DBG("acl2:rowneruuid is nil"); + return false; + } + if (!oc_sec_find_creds_for_subject(NULL, &acl->rowneruuid, device)) { + OC_DBG("Could not find credential for acl2:rowneruuid"); + return false; + } + + const oc_sec_creds_t *creds = oc_sec_get_creds(device); + if (nil_uuid(&creds->rowneruuid)) { + OC_DBG("cred:rowneruuid is nil"); + return false; + } + if (!oc_sec_find_creds_for_subject(NULL, &creds->rowneruuid, device)) { + OC_DBG("Could not find credential for cred:rowneruuid"); + return false; + } + + return true; +} + static bool oc_pstat_handle_state(oc_sec_pstat_t *ps, size_t device, bool from_storage, bool close_all_tls_connections_immediately) { OC_DBG("oc_pstat: Entering pstat_handle_state"); - oc_sec_acl_t *acl = oc_sec_get_acl(device); - oc_sec_doxm_t *doxm = oc_sec_get_doxm(device); - oc_sec_creds_t *creds = oc_sec_get_creds(device); switch (ps->s) { case OC_DOS_RESET: { ps->p = true; @@ -205,13 +297,14 @@ oc_pstat_handle_state(oc_sec_pstat_t *ps, size_t device, bool from_storage, ps->s = OC_DOS_RFOTM; ps->cm = 2; ps->tm = 0; - if (doxm->owned || !nil_uuid(&doxm->devowneruuid) || ps->isop || - (ps->cm & 0xC3) != 2 || (ps->tm & 0xC3) != 0) { + const oc_sec_doxm_t *doxm = oc_sec_get_doxm(device); + if (doxm->owned || !nil_uuid(&doxm->devowneruuid) || + !pstat_check_ps_state(ps)) { #ifdef OC_DEBUG if (!nil_uuid(&doxm->devowneruuid)) { - OC_ERR("non-Nil doxm:devowneruuid in RFOTM"); + OC_DBG("non-Nil doxm:devowneruuid in RFOTM"); } - OC_ERR("ERROR in RFOTM\n"); + OC_DBG("ERROR in RFOTM\n"); #endif /* OC_DEBUG */ goto pstat_state_error; } @@ -232,11 +325,11 @@ oc_pstat_handle_state(oc_sec_pstat_t *ps, size_t device, bool from_storage, oc_set_drop_commands(device, true); } if (fp->cb != NULL) { - memcpy(&pstat[device], ps, sizeof(oc_sec_pstat_t)); + oc_sec_pstat_copy(&g_pstat[device], ps); OC_DBG("oc_pstat: invoking the factory presets callback"); fp->cb(device, fp->data); OC_DBG("oc_pstat: returned from the factory presets callback"); - memcpy(ps, &pstat[device], sizeof(oc_sec_pstat_t)); + oc_sec_pstat_copy(ps, &g_pstat[device]); } coap_set_global_status_code(status_code); ps->p = false; @@ -246,51 +339,8 @@ oc_pstat_handle_state(oc_sec_pstat_t *ps, size_t device, bool from_storage, ps->cm = 0; ps->tm = 0; ps->isop = false; - if (!doxm->owned || nil_uuid(&doxm->devowneruuid) || - nil_uuid(&doxm->deviceuuid) || ps->isop || (ps->cm & 0xC3) != 0 || - (ps->tm & 0xC3) != 0 || nil_uuid(&ps->rowneruuid) || - nil_uuid(&doxm->rowneruuid) || nil_uuid(&acl->rowneruuid) || - nil_uuid(&creds->rowneruuid) || - !oc_sec_find_creds_for_subject(NULL, &ps->rowneruuid, device) || - !oc_sec_find_creds_for_subject(NULL, &doxm->rowneruuid, device) || - !oc_sec_find_creds_for_subject(NULL, &acl->rowneruuid, device) || - !oc_sec_find_creds_for_subject(NULL, &creds->rowneruuid, device)) { -#ifdef OC_DEBUG - if (!doxm->owned) { - OC_ERR("doxm:owned is false"); - } - if (nil_uuid(&doxm->devowneruuid)) { - OC_ERR("doxm:devowneruuid is nil"); - } - if (nil_uuid(&doxm->deviceuuid)) { - OC_ERR("doxm:deviceuuid is nil"); - } - if (nil_uuid(&ps->rowneruuid)) { - OC_ERR("pstat:rowneruuid is nil"); - } - if (nil_uuid(&doxm->rowneruuid)) { - OC_ERR("doxm:rowneruuid is nil"); - } - if (nil_uuid(&acl->rowneruuid)) { - OC_ERR("acl2:rowneruuid is nil"); - } - if (nil_uuid(&creds->rowneruuid)) { - OC_ERR("cred:rowneruuid is nil"); - } - if (!oc_sec_find_creds_for_subject(NULL, &ps->rowneruuid, device)) { - OC_ERR("Could not find credential for pstat:rowneruuid"); - } - if (!oc_sec_find_creds_for_subject(NULL, &doxm->rowneruuid, device)) { - OC_ERR("Could not find credential for doxm:rowneruuid"); - } - if (!oc_sec_find_creds_for_subject(NULL, &acl->rowneruuid, device)) { - OC_ERR("Could not find credential for acl2:rowneruuid"); - } - if (!oc_sec_find_creds_for_subject(NULL, &creds->rowneruuid, device)) { - OC_ERR("Could not find credential for cred:rowneruuid"); - } - OC_ERR("ERROR in RFPRO\n"); -#endif /* OC_DEBUG */ + if (!pstat_check_state(ps, device)) { + OC_DBG("ERROR in RFPRO\n"); goto pstat_state_error; } ps->p = false; @@ -300,51 +350,8 @@ oc_pstat_handle_state(oc_sec_pstat_t *ps, size_t device, bool from_storage, ps->cm = 0; ps->tm = 0; ps->isop = true; - if (!doxm->owned || nil_uuid(&doxm->devowneruuid) || - nil_uuid(&doxm->deviceuuid) || !ps->isop || (ps->cm & 0xC3) != 0 || - (ps->tm & 0xC3) != 0 || nil_uuid(&ps->rowneruuid) || - nil_uuid(&doxm->rowneruuid) || nil_uuid(&acl->rowneruuid) || - nil_uuid(&creds->rowneruuid) || - !oc_sec_find_creds_for_subject(NULL, &ps->rowneruuid, device) || - !oc_sec_find_creds_for_subject(NULL, &doxm->rowneruuid, device) || - !oc_sec_find_creds_for_subject(NULL, &acl->rowneruuid, device) || - !oc_sec_find_creds_for_subject(NULL, &creds->rowneruuid, device)) { -#ifdef OC_DEBUG - if (!doxm->owned) { - OC_ERR("doxm:owned is false"); - } - if (nil_uuid(&doxm->devowneruuid)) { - OC_ERR("doxm:devowneruuid is nil"); - } - if (nil_uuid(&doxm->deviceuuid)) { - OC_ERR("doxm:deviceuuid is nil"); - } - if (nil_uuid(&ps->rowneruuid)) { - OC_ERR("pstat:rowneruuid is nil"); - } - if (nil_uuid(&doxm->rowneruuid)) { - OC_ERR("doxm:rowneruuid is nil"); - } - if (nil_uuid(&acl->rowneruuid)) { - OC_ERR("acl2:rowneruuid is nil"); - } - if (nil_uuid(&creds->rowneruuid)) { - OC_ERR("cred:rowneruuid is nil"); - } - if (!oc_sec_find_creds_for_subject(NULL, &ps->rowneruuid, device)) { - OC_ERR("Could not find credential for pstat:rowneruuid"); - } - if (!oc_sec_find_creds_for_subject(NULL, &doxm->rowneruuid, device)) { - OC_ERR("Could not find credential for doxm:rowneruuid"); - } - if (!oc_sec_find_creds_for_subject(NULL, &acl->rowneruuid, device)) { - OC_ERR("Could not find credential for acl2:rowneruuid"); - } - if (!oc_sec_find_creds_for_subject(NULL, &creds->rowneruuid, device)) { - OC_ERR("Could not find credential for cred:rowneruuid"); - } - OC_ERR("ERROR in RFNOP\n"); -#endif /* OC_DEBUG */ + if (!pstat_check_state(ps, device)) { + OC_DBG("ERROR in RFNOP\n"); goto pstat_state_error; } ps->p = false; @@ -354,51 +361,8 @@ oc_pstat_handle_state(oc_sec_pstat_t *ps, size_t device, bool from_storage, ps->cm = 1; ps->tm = 0; ps->isop = false; - if (!doxm->owned || nil_uuid(&doxm->devowneruuid) || - nil_uuid(&doxm->deviceuuid) || ps->isop || ps->cm != 1 || - (ps->tm & 0xC3) != 0 || nil_uuid(&ps->rowneruuid) || - nil_uuid(&doxm->rowneruuid) || nil_uuid(&acl->rowneruuid) || - nil_uuid(&creds->rowneruuid) || - !oc_sec_find_creds_for_subject(NULL, &ps->rowneruuid, device) || - !oc_sec_find_creds_for_subject(NULL, &doxm->rowneruuid, device) || - !oc_sec_find_creds_for_subject(NULL, &acl->rowneruuid, device) || - !oc_sec_find_creds_for_subject(NULL, &creds->rowneruuid, device)) { -#ifdef OC_DEBUG - if (!doxm->owned) { - OC_ERR("doxm:owned is false"); - } - if (nil_uuid(&doxm->devowneruuid)) { - OC_ERR("doxm:devowneruuid is nil"); - } - if (nil_uuid(&doxm->deviceuuid)) { - OC_ERR("doxm:deviceuuid is nil"); - } - if (nil_uuid(&ps->rowneruuid)) { - OC_ERR("pstat:rowneruuid is nil"); - } - if (nil_uuid(&doxm->rowneruuid)) { - OC_ERR("doxm:rowneruuid is nil"); - } - if (nil_uuid(&acl->rowneruuid)) { - OC_ERR("acl2:rowneruuid is nil"); - } - if (nil_uuid(&creds->rowneruuid)) { - OC_ERR("cred:rowneruuid is nil"); - } - if (!oc_sec_find_creds_for_subject(NULL, &ps->rowneruuid, device)) { - OC_ERR("Could not find credential for pstat:rowneruuid"); - } - if (!oc_sec_find_creds_for_subject(NULL, &doxm->rowneruuid, device)) { - OC_ERR("Could not find credential for doxm:rowneruuid"); - } - if (!oc_sec_find_creds_for_subject(NULL, &acl->rowneruuid, device)) { - OC_ERR("Could not find credential for acl2:rowneruuid"); - } - if (!oc_sec_find_creds_for_subject(NULL, &creds->rowneruuid, device)) { - OC_ERR("Could not find credential for cred:rowneruuid"); - } - OC_ERR("ERROR in SRESET\n"); -#endif /* OC_DEBUG */ + if (!pstat_check_state(ps, device)) { + OC_DBG("ERROR in SRESET\n"); goto pstat_state_error; } ps->p = false; @@ -407,7 +371,7 @@ oc_pstat_handle_state(oc_sec_pstat_t *ps, size_t device, bool from_storage, return false; break; } - memmove(&pstat[device], ps, sizeof(oc_sec_pstat_t)); + oc_sec_pstat_copy(&g_pstat[device], ps); #ifdef OC_SERVER switch (ps->s) { case OC_DOS_RESET: @@ -434,15 +398,15 @@ oc_sec_pstat_t * oc_sec_get_pstat(size_t device) { #ifdef OC_DEBUG - dump_pstat_dos(&pstat[device]); + dump_pstat_dos(&g_pstat[device]); #endif /* OC_DEBUG */ - return &pstat[device]; + return &g_pstat[device]; } bool oc_sec_is_operational(size_t device) { - return pstat[device].isop; + return g_pstat[device].isop; } void @@ -453,12 +417,39 @@ oc_sec_pstat_default(size_t device) oc_sec_dump_pstat(device); } +void +oc_sec_pstat_copy(oc_sec_pstat_t *dst, const oc_sec_pstat_t *src) +{ + assert(src != NULL); + assert(dst != NULL); + + if (dst == src) { + return; + } + + dst->s = src->s; + dst->p = src->p; + dst->isop = src->isop; + dst->cm = src->cm; + dst->tm = src->tm; + dst->om = src->om; + dst->sm = src->sm; + memcpy(&dst->rowneruuid.id, src->rowneruuid.id, sizeof(src->rowneruuid.id)); +} + +void +oc_sec_pstat_clear(oc_sec_pstat_t *ps) +{ + assert(ps != NULL); + memset(ps, 0, sizeof(*ps)); +} + void oc_sec_encode_pstat(size_t device, oc_interface_mask_t iface_mask, bool to_storage) { #ifdef OC_DEBUG - dump_pstat_dos(&pstat[device]); + dump_pstat_dos(&g_pstat[device]); #endif /* OC_DEBUG */ char uuid[OC_UUID_LEN]; oc_rep_start_root_object(); @@ -467,15 +458,15 @@ oc_sec_encode_pstat(size_t device, oc_interface_mask_t iface_mask, oc_core_get_resource_by_index(OCF_SEC_PSTAT, device)); } oc_rep_set_object(root, dos); - oc_rep_set_boolean(dos, p, pstat[device].p); - oc_rep_set_int(dos, s, pstat[device].s); + oc_rep_set_boolean(dos, p, g_pstat[device].p); + oc_rep_set_int(dos, s, g_pstat[device].s); oc_rep_close_object(root, dos); - oc_rep_set_int(root, cm, pstat[device].cm); - oc_rep_set_int(root, tm, pstat[device].tm); - oc_rep_set_int(root, om, pstat[device].om); - oc_rep_set_int(root, sm, pstat[device].sm); - oc_rep_set_boolean(root, isop, pstat[device].isop); - oc_uuid_to_str(&pstat[device].rowneruuid, uuid, OC_UUID_LEN); + oc_rep_set_int(root, cm, g_pstat[device].cm); + oc_rep_set_int(root, tm, g_pstat[device].tm); + oc_rep_set_int(root, om, g_pstat[device].om); + oc_rep_set_int(root, sm, g_pstat[device].sm); + oc_rep_set_boolean(root, isop, g_pstat[device].isop); + oc_uuid_to_str(&g_pstat[device].rowneruuid, uuid, OC_UUID_LEN); oc_rep_set_text_string(root, rowneruuid, uuid); oc_rep_end_root_object(); } @@ -499,7 +490,7 @@ oc_pstat_handle_target_mode(size_t device, oc_dpmtype_t *tm) void oc_sec_pstat_set_current_mode(size_t device, oc_dpmtype_t cm) { - oc_sec_pstat_t *ps = &pstat[device]; + oc_sec_pstat_t *ps = &g_pstat[device]; ps->cm = cm; #ifdef OC_SERVER oc_notify_observers(oc_core_get_resource_by_index(OCF_SEC_PSTAT, device)); @@ -511,7 +502,7 @@ bool oc_sec_decode_pstat(const oc_rep_t *rep, bool from_storage, size_t device) { oc_sec_pstat_t ps; - memcpy(&ps, &pstat[device], sizeof(oc_sec_pstat_t)); + oc_sec_pstat_copy(&ps, &g_pstat[device]); #ifdef OC_DEBUG if (!from_storage) { dump_pstat_dos(&ps); @@ -603,7 +594,7 @@ oc_sec_decode_pstat(const oc_rep_t *rep, bool from_storage, size_t device) oc_pstat_handle_state(&ps, device, from_storage, false); return transition_success; } - memcpy(&pstat[device], &ps, sizeof(oc_sec_pstat_t)); + oc_sec_pstat_copy(&g_pstat[device], &ps); return true; } return false; diff --git a/security/oc_pstat.h b/security/oc_pstat.h index b4941d1084..640013e9cb 100644 --- a/security/oc_pstat.h +++ b/security/oc_pstat.h @@ -41,14 +41,14 @@ typedef enum { typedef struct { - oc_dostype_t s; - bool p; - bool isop; - oc_dpmtype_t cm; - oc_dpmtype_t tm; - int om; - int sm; - oc_uuid_t rowneruuid; + oc_dostype_t s; ///< Device Onboarding State + bool p; ///< Pending state + bool isop; ///< Is Device Operational oc_dpmtype_t cm; + oc_dpmtype_t cm; ///< Current Mode + oc_dpmtype_t tm; ///< Target Mode + int om; ///< Operational Mode + int sm; ///< Supported Mode + oc_uuid_t rowneruuid; ///< Resource Owner ID } oc_sec_pstat_t; void oc_sec_pstat_init(void); @@ -57,8 +57,12 @@ bool oc_sec_is_operational(size_t device); bool oc_sec_decode_pstat(const oc_rep_t *rep, bool from_storage, size_t device); void oc_sec_encode_pstat(size_t device, oc_interface_mask_t iface_mask, bool to_storage); + oc_sec_pstat_t *oc_sec_get_pstat(size_t device); void oc_sec_pstat_default(size_t device); +void oc_sec_pstat_copy(oc_sec_pstat_t *dst, const oc_sec_pstat_t *src); +void oc_sec_pstat_clear(oc_sec_pstat_t *pstat); + void get_pstat(oc_request_t *request, oc_interface_mask_t iface_mask, void *data); void post_pstat(oc_request_t *request, oc_interface_mask_t iface_mask, diff --git a/security/oc_sdi.c b/security/oc_sdi.c index 0228f0b8ab..007c339225 100644 --- a/security/oc_sdi.c +++ b/security/oc_sdi.c @@ -17,50 +17,59 @@ ******************************************************************/ #ifdef OC_SECURITY -#include "oc_sdi.h" + +#include "api/oc_core_res_internal.h" +#include "api/oc_rep_internal.h" +#include "oc_sdi_internal.h" #include "oc_api.h" #include "oc_core_res.h" #include "oc_pki.h" #include "oc_pstat.h" #include "oc_store.h" -#ifdef OC_DYNAMIC_ALLOCATION #include "port/oc_assert.h" +#include "util/oc_macros.h" + +#include #include -static oc_sec_sdi_t *sdi; + +#define OCF_SEC_SDI_PROP_UUID "uuid" +#define OCF_SEC_SDI_PROP_NAME "name" +#define OCF_SEC_SDI_PROP_PRIV "priv" + +#ifdef OC_DYNAMIC_ALLOCATION +static oc_sec_sdi_t *g_sdi = NULL; #else /* OC_DYNAMIC_ALLOCATION */ -static oc_sec_sdi_t sdi[OC_MAX_NUM_DEVICES]; +static oc_sec_sdi_t g_sdi[OC_MAX_NUM_DEVICES] = { 0 }; #endif /* !OC_DYNAMIC_ALLOCATION */ void oc_sec_sdi_init(void) { #ifdef OC_DYNAMIC_ALLOCATION - sdi = (oc_sec_sdi_t *)calloc(oc_core_get_num_devices(), sizeof(oc_sec_sdi_t)); - if (!sdi) { + g_sdi = + (oc_sec_sdi_t *)calloc(oc_core_get_num_devices(), sizeof(oc_sec_sdi_t)); + if (g_sdi == NULL) { oc_abort("Insufficient memory"); } -#endif +#endif /* OC_DYNAMIC_ALLOCATION */ } void oc_sec_sdi_free(void) { - size_t device; #ifdef OC_DYNAMIC_ALLOCATION - if (!sdi) { + if (g_sdi == NULL) { return; } -#endif - for (device = 0; device < oc_core_get_num_devices(); device++) { - if (oc_string_len(sdi[device].name) > 0) { - oc_free_string(&(sdi[device].name)); +#endif /* OC_DYNAMIC_ALLOCATION */ + for (size_t device = 0; device < oc_core_get_num_devices(); ++device) { + if (oc_string(g_sdi[device].name) != NULL) { + oc_free_string(&(g_sdi[device].name)); } } #ifdef OC_DYNAMIC_ALLOCATION - if (sdi) { - free(sdi); - } + free(g_sdi); #endif /* OC_DYNAMIC_ALLOCATION */ } @@ -68,153 +77,245 @@ void oc_sec_sdi_default(size_t device) { #ifdef OC_DYNAMIC_ALLOCATION - if (!sdi) { + if (g_sdi == NULL) { return; } -#endif - sdi[device].priv = false; - memset(&(sdi[device].uuid), 0, sizeof(oc_uuid_t)); - if (oc_string_len(sdi[device].name) > 0) { - oc_free_string(&sdi[device].name); +#endif /* OC_DYNAMIC_ALLOCATION */ + g_sdi[device].priv = false; + memset(&(g_sdi[device].uuid), 0, sizeof(oc_uuid_t)); + if (oc_string(g_sdi[device].name) != NULL) { + oc_free_string(&g_sdi[device].name); } oc_sec_dump_sdi(device); } +void +oc_sec_sdi_copy(oc_sec_sdi_t *dst, const oc_sec_sdi_t *src) +{ + assert(src != NULL); + assert(dst != NULL); + + if (dst == src) { + return; + } + + dst->priv = src->priv; + memcpy(&dst->uuid, &src->uuid, sizeof(src->uuid)); + oc_copy_string(&dst->name, &src->name); +} + +void +oc_sec_sdi_clear(oc_sec_sdi_t *sdi) +{ + assert(sdi != NULL); + sdi->priv = false; + memset(&sdi->uuid, 0, sizeof(sdi->uuid)); + oc_free_string(&sdi->name); +} + +typedef struct sdi_decode_data_t +{ + const oc_string_t *uuid; + const oc_string_t *name; + bool priv; + bool priv_found; +} sdi_decode_data_t; + +static bool +sdi_decode_string_property(const oc_rep_t *rep, oc_dostype_t state, + bool from_storage, sdi_decode_data_t *data) +{ + assert(rep->type == OC_REP_STRING); + + if (oc_rep_is_property(rep, OCF_SEC_SDI_PROP_UUID, + OC_CHAR_ARRAY_LEN(OCF_SEC_SDI_PROP_UUID))) { + if (!from_storage && state != OC_DOS_RFOTM) { + OC_ERR("oc_sdi: Can set uuid property only in RFOTM"); + return false; + } + if (oc_string_len(rep->value.string) < OC_UUID_LEN - 1) { + OC_ERR("oc_sdi: Invalid uuid %s", oc_string(rep->value.string)); + return false; + } + data->uuid = &rep->value.string; + return true; + } + + if (oc_rep_is_property(rep, OCF_SEC_SDI_PROP_NAME, + OC_CHAR_ARRAY_LEN(OCF_SEC_SDI_PROP_NAME))) { + if (!from_storage && state != OC_DOS_RFOTM && state != OC_DOS_RFPRO && + state != OC_DOS_SRESET) { + OC_ERR("oc_sdi: Can't set name property in pstate %d", state); + return false; + } + + data->name = &rep->value.string; + return true; + } + + OC_ERR("oc_sdi: Unknown property %s", oc_string(rep->name)); + return true; +} + +static bool +sdi_decode_bool_property(const oc_rep_t *rep, oc_dostype_t state, + bool from_storage, sdi_decode_data_t *data) +{ + assert(rep->type == OC_REP_BOOL); + + if (oc_rep_is_property(rep, OCF_SEC_SDI_PROP_PRIV, + OC_CHAR_ARRAY_LEN(OCF_SEC_SDI_PROP_PRIV))) { + if (!from_storage && state != OC_DOS_RFOTM && state != OC_DOS_RFPRO && + state != OC_DOS_SRESET) { + OC_ERR("oc_sdi: Can't set priv property in pstate %d", state); + return false; + } + + data->priv = rep->value.boolean; + data->priv_found = true; + return true; + } + + OC_ERR("oc_sdi: Unknown property %s", oc_string(rep->name)); + return true; +} + bool -oc_sec_decode_sdi(oc_rep_t *rep, bool from_storage, size_t device) +oc_sec_sdi_decode_with_state(const oc_rep_t *rep, oc_dostype_t state, + bool from_storage, oc_sec_sdi_t *sdi) { - bool suc = false; - oc_sec_sdi_t *s = oc_sec_get_sdi(device); - const oc_sec_pstat_t *ps = oc_sec_get_pstat(device); + assert(sdi != NULL); - while (rep != NULL) { - size_t len = oc_string_len(rep->name); + sdi_decode_data_t sdi_data = { 0 }; + for (; rep != NULL; rep = rep->next) { switch (rep->type) { case OC_REP_STRING: - if (len == 4 && memcmp("uuid", oc_string(rep->name), 4) == 0) { - - if (!from_storage && ps->s != OC_DOS_RFOTM) { - OC_ERR("oc_sdi: Can set uuid property only in RFOTM"); - return false; - } - if (oc_string_len(rep->value.string) < OC_UUID_LEN - 1) { - OC_ERR("oc_sdi: Invalid uuid %s", oc_string(rep->value.string)); - return false; - } - oc_str_to_uuid(oc_string(rep->value.string), &s->uuid); - suc = true; - } else if (len == 4 && memcmp("name", oc_string(rep->name), 4) == 0) { - - if (!from_storage && ps->s != OC_DOS_RFOTM && ps->s != OC_DOS_RFPRO && - ps->s != OC_DOS_SRESET) { - OC_ERR("oc_sdi: Can't set name property in pstate %d", ps->s); - return false; - } - - if (oc_string_len(s->name) > 0) { - oc_free_string(&s->name); - } - if (oc_string_len(rep->value.string) > 0) { - oc_new_string(&s->name, oc_string(rep->value.string), - oc_string_len(rep->value.string)); - } - suc = true; - } else { - OC_ERR("oc_sdi: Unknown property %s", oc_string(rep->name)); + if (!sdi_decode_string_property(rep, state, from_storage, &sdi_data)) { + return false; } break; case OC_REP_BOOL: - if (len == 4 && memcmp(oc_string(rep->name), "priv", 4) == 0) { - - if (!from_storage && ps->s != OC_DOS_RFOTM && ps->s != OC_DOS_RFPRO && - ps->s != OC_DOS_SRESET) { - OC_ERR("oc_sdi: Can't set priv property in pstate %d", ps->s); - return false; - } - - s->priv = rep->value.boolean; - suc = true; - } else { - OC_ERR("oc_sdi: Unknown property %s", oc_string(rep->name)); + if (!sdi_decode_bool_property(rep, state, from_storage, &sdi_data)) { + return false; } break; default: OC_ERR("oc_sdi: Unknown type, property %s", oc_string(rep->name)); break; } - rep = rep->next; } - return suc; + + if (sdi_data.uuid == NULL && sdi_data.name == NULL && !sdi_data.priv_found) { + OC_DBG("no sdi property found"); + return false; + } + + if (sdi_data.uuid != NULL) { + oc_str_to_uuid(oc_string(*sdi_data.uuid), &sdi->uuid); + } + if (sdi_data.name != NULL) { + if (oc_string(sdi->name) != NULL) { + oc_free_string(&sdi->name); + } + if (oc_string_len(*sdi_data.name) > 0) { + oc_new_string(&sdi->name, oc_string(*sdi_data.name), + oc_string_len(*sdi_data.name)); + } + } + if (sdi_data.priv_found) { + sdi->priv = sdi_data.priv; + } + return true; } -void -oc_sec_encode_sdi(size_t device, bool to_storage) +bool +oc_sec_sdi_decode(size_t device, const oc_rep_t *rep, bool from_storage) { - char uuid[37]; - oc_sec_sdi_t *s = oc_sec_get_sdi(device); + const oc_sec_pstat_t *ps = oc_sec_get_pstat(device); + return oc_sec_sdi_decode_with_state(rep, ps->s, from_storage, + oc_sec_sdi_get(device)); +} - oc_uuid_to_str(&s->uuid, uuid, OC_UUID_LEN); +int +oc_sec_sdi_encode_with_resource(const oc_sec_sdi_t *sdi, + const oc_resource_t *sdi_res, + oc_interface_mask_t iface_mask) +{ + assert(oc_rep_get_cbor_errno() == CborNoError); + assert(sdi != NULL); - if (to_storage) { - oc_rep_start_root_object(); + oc_rep_start_root_object(); + if ((iface_mask & OC_IF_BASELINE) != 0) { + assert(sdi_res != NULL); + oc_process_baseline_interface(sdi_res); } + char uuid[OC_UUID_LEN]; + oc_uuid_to_str(&sdi->uuid, uuid, sizeof(uuid)); oc_rep_set_text_string(root, uuid, uuid); - oc_rep_set_text_string(root, name, oc_string(s->name)); + oc_rep_set_text_string(root, name, oc_string(sdi->name)); + + oc_rep_set_boolean(root, priv, sdi->priv); - oc_rep_set_boolean(root, priv, s->priv); + oc_rep_end_root_object(); - if (to_storage) { - oc_rep_end_root_object(); + return oc_rep_get_cbor_errno(); +} + +int +oc_sec_sdi_encode(size_t device, oc_interface_mask_t iface_mask) +{ + const oc_sec_sdi_t *sdi = oc_sec_sdi_get(device); + const oc_resource_t *sdi_res = NULL; + if ((iface_mask & OC_IF_BASELINE) != 0) { + sdi_res = oc_core_get_resource_by_index(OCF_SEC_SDI, device); } + return oc_sec_sdi_encode_with_resource(sdi, sdi_res, iface_mask); } oc_sec_sdi_t * -oc_sec_get_sdi(size_t device) +oc_sec_sdi_get(size_t device) { - return &sdi[device]; + return &g_sdi[device]; } -void -get_sdi(oc_request_t *request, oc_interface_mask_t iface_mask, void *data) +static void +sdi_resource_get(oc_request_t *request, oc_interface_mask_t iface_mask, + void *data) { (void)data; - switch (iface_mask) { - case OC_IF_BASELINE: { - - oc_rep_start_root_object(); - - oc_process_baseline_interface( - oc_core_get_resource_by_index(OCF_SEC_SDI, request->resource->device)); - oc_sec_encode_sdi(request->resource->device, false); - - oc_rep_end_root_object(); - - oc_send_response(request, OC_STATUS_OK); - } break; - case OC_IF_RW: { - oc_sec_encode_sdi(request->resource->device, true); - oc_send_response(request, OC_STATUS_OK); - } break; - default: - break; + int err = oc_sec_sdi_encode(request->resource->device, iface_mask); + if (err != CborNoError) { + OC_ERR("oc_sdi: cannot encode GET request data(error=%d)", err); + oc_send_response(request, OC_STATUS_INTERNAL_SERVER_ERROR); + return; } + oc_send_response(request, OC_STATUS_OK); } -void -post_sdi(oc_request_t *request, oc_interface_mask_t iface_mask, void *data) +static void +sdi_resource_post(oc_request_t *request, oc_interface_mask_t iface_mask, + void *data) { (void)iface_mask; (void)data; size_t device = request->resource->device; - if (oc_sec_decode_sdi(request->request_payload, false, device)) { - oc_send_response(request, OC_STATUS_CHANGED); - request->response->response_buffer->response_length = 0; - oc_sec_dump_sdi(device); - } else { + if (!oc_sec_sdi_decode(device, request->request_payload, false)) { oc_send_response(request, OC_STATUS_BAD_REQUEST); + return; } + oc_send_response(request, OC_STATUS_CHANGED); + oc_sec_dump_sdi(device); +} + +void +oc_sec_sdi_create_resource(size_t device) +{ + oc_core_populate_resource( + OCF_SEC_SDI, device, OCF_SEC_SDI_URI, OCF_SEC_SDI_IF_MASK, + OCF_SEC_SDI_DEFAULT_IF, OC_DISCOVERABLE | OC_SECURE, sdi_resource_get, + /*put*/ NULL, sdi_resource_post, /*delete*/ NULL, 1, OCF_SEC_SDI_RT); } #endif /* OC_SECURITY */ diff --git a/security/oc_sdi.h b/security/oc_sdi.h deleted file mode 100644 index 044c4fdee6..0000000000 --- a/security/oc_sdi.h +++ /dev/null @@ -1,50 +0,0 @@ -/**************************************************************************** - * - * Copyright (c) 2020, Beijing OPPO telecommunications corp., ltd. - * - * Licensed under the Apache License, Version 2.0 (the "License"), - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ******************************************************************/ - -#ifndef OC_SDI_H -#define OC_SDI_H - -#include "oc_ri.h" -#include "oc_uuid.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct -{ - bool priv; - oc_uuid_t uuid; - oc_string_t name; -} oc_sec_sdi_t; - -void oc_sec_sdi_init(void); -void oc_sec_sdi_free(void); -void oc_sec_sdi_default(size_t device); -bool oc_sec_decode_sdi(oc_rep_t *rep, bool from_storage, size_t device); -void oc_sec_encode_sdi(size_t device, bool to_storage); -oc_sec_sdi_t *oc_sec_get_sdi(size_t device); -void get_sdi(oc_request_t *request, oc_interface_mask_t iface_mask, void *data); -void post_sdi(oc_request_t *request, oc_interface_mask_t iface_mask, - void *data); - -#ifdef __cplusplus -} -#endif - -#endif /* OC_SDI_H */ diff --git a/security/oc_sdi_internal.h b/security/oc_sdi_internal.h new file mode 100644 index 0000000000..fce2e39023 --- /dev/null +++ b/security/oc_sdi_internal.h @@ -0,0 +1,139 @@ +/**************************************************************************** + * + * Copyright (c) 2020, Beijing OPPO telecommunications corp., ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"), + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************/ + +#ifndef OC_SDI_INTERAL_H +#define OC_SDI_INTERAL_H + +#include "oc_ri.h" +#include "oc_uuid.h" +#include "oc_pstat.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Security Domain Information (SDI) Resource + +// Data of a SDI resource +typedef struct +{ + bool priv; // privacy flag, indicates whether the SDI is copied to "/oic/res", + // and thus whether it is publicly visible or private. + oc_uuid_t uuid; // UUID that identifies the Security Domain + oc_string_t name; // human-friendly name for the Security Domain +} oc_sec_sdi_t; + +#define OCF_SEC_SDI_URI "/oic/sec/sdi" +#define OCF_SEC_SDI_RT "oic.r.sdi" +#define OCF_SEC_SDI_IF_MASK (OC_IF_BASELINE | OC_IF_RW) +#define OCF_SEC_SDI_DEFAULT_IF (OC_IF_RW) +#define OCF_SEC_SDI_STORE_NAME "sdi" + +/** + * @brief Allocate sdi resource data for all devices. + */ +void oc_sec_sdi_init(void); + +/** + * @brief Deallocate all sdi resource data. + */ +void oc_sec_sdi_free(void); + +/** + * @brief Reset sdi resource data to empty values. + * + * @param device device index + */ +void oc_sec_sdi_default(size_t device); + +/** + * @brief Get pointer to the sdi representation of given device + * + * @param device device index + * @return oc_sec_sdi_t* sdi data for given device + */ +oc_sec_sdi_t *oc_sec_sdi_get(size_t device); + +/** + * @brief Copy SDI data from source to destination + * + * @param dst destination (cannot be NULL) + * @param src source (cannot be NULL) + */ +void oc_sec_sdi_copy(oc_sec_sdi_t *dst, const oc_sec_sdi_t *src); + +/** + * @brief Deallocate all data and set them to zero. + * + * @param sdi sdi to clear (cannot be NULL) + */ +void oc_sec_sdi_clear(oc_sec_sdi_t *sdi); + +/** + * @brief Encode sdi to global encoder + * + * @param device device index + * @param sdi_res resource with baseline properties (only used when iface_mask + * contains OC_IF_BASELINE) + * @param iface_mask encoding interface + * @return 0 on success + * @return <0 on error + */ +int oc_sec_sdi_encode_with_resource(const oc_sec_sdi_t *sdi, + const oc_resource_t *sdi_res, + oc_interface_mask_t iface_mask); + +/** + * @brief Convenience wrapper for oc_sec_sdi_encode_with_resource. Will encode + * global sdi data and resource associated with given device. + */ +int oc_sec_sdi_encode(size_t device, oc_interface_mask_t iface_mask); + +/** + * @brief Decode representation to structure. + * + * @param rep representation to decode (cannot be NULL) + * @param state device state (some properties are only modifiable in selected + * state, otherwise an error is returned) + * @param from_storage data is loaded from storage (device state checks are + * disabled if true) + * @param[out] sdi output structure to store the decoded data (cannot be NULL) + * @return true on success + * @return false on failure + */ +bool oc_sec_sdi_decode_with_state(const oc_rep_t *rep, oc_dostype_t state, + bool from_storage, oc_sec_sdi_t *sdi); + +/** + * @brief Convenience wrapper for oc_sec_sdi_decode_with_state. Will encode + * global sdi data associated with given device. + */ +bool oc_sec_sdi_decode(size_t device, const oc_rep_t *rep, bool from_storage); + +/** + * @brief Create sdi (/oic/sec/sdi) resource for given device + * + * @param device device index + */ +void oc_sec_sdi_create_resource(size_t); + +#ifdef __cplusplus +} +#endif + +#endif /* OC_SDI_INTERAL_H */ diff --git a/security/oc_sp.c b/security/oc_sp.c index cfd01a0b93..297404affa 100644 --- a/security/oc_sp.c +++ b/security/oc_sp.c @@ -24,10 +24,12 @@ #include "oc_pki.h" #include "oc_pstat.h" #include "oc_store.h" +#include "port/oc_assert.h" #include "util/oc_macros.h" +#include + #ifdef OC_DYNAMIC_ALLOCATION -#include "port/oc_assert.h" #include static oc_sec_sp_t *g_sp = NULL; static oc_sec_sp_t *g_sp_mfg_default = NULL; @@ -36,11 +38,6 @@ static oc_sec_sp_t g_sp[OC_MAX_NUM_DEVICES] = { 0 }; static oc_sec_sp_t g_sp_mfg_default[OC_MAX_NUM_DEVICES] = { 0 }; #endif /* !OC_DYNAMIC_ALLOCATION */ -#define OC_SP_BASELINE_OID "1.3.6.1.4.1.51414.0.0.1.0" -#define OC_SP_BLACK_OID "1.3.6.1.4.1.51414.0.0.2.0" -#define OC_SP_BLUE_OID "1.3.6.1.4.1.51414.0.0.3.0" -#define OC_SP_PURPLE_OID "1.3.6.1.4.1.51414.0.0.4.0" - void oc_pki_set_security_profile(size_t device, unsigned supported_profiles, oc_sp_types_t current_profile, int mfg_credid) @@ -91,33 +88,66 @@ oc_sec_sp_default(size_t device) g_sp[device] = g_sp_mfg_default[device]; } -static oc_sp_types_t -sp_from_string(const char *sp_string) +void +oc_sec_sp_copy(oc_sec_sp_t *dst, const oc_sec_sp_t *src) +{ + assert(src != NULL); + assert(dst != NULL); + + if (dst == src) { + return; + } + + dst->supported_profiles = src->supported_profiles; + dst->current_profile = src->current_profile; + dst->credid = src->credid; +} + +void +oc_sec_sp_clear(oc_sec_sp_t *sp) +{ + assert(sp != NULL); + memset(sp, 0, sizeof(*sp)); +} + +oc_sp_types_t +oc_sec_sp_type_from_string(const char *str, size_t str_len) { - size_t sp_string_len = strlen(sp_string); - if (sp_string_len == OC_CHAR_ARRAY_LEN(OC_SP_BASELINE_OID) && - memcmp(OC_SP_BASELINE_OID, sp_string, - OC_CHAR_ARRAY_LEN(OC_SP_BASELINE_OID)) == 0) { + if (str_len == OC_CHAR_ARRAY_LEN(OC_SP_BASELINE_OID) && + memcmp(OC_SP_BASELINE_OID, str, str_len) == 0) { return OC_SP_BASELINE; } - if (sp_string_len == OC_CHAR_ARRAY_LEN(OC_SP_BLACK_OID) && - memcmp(OC_SP_BLACK_OID, sp_string, OC_CHAR_ARRAY_LEN(OC_SP_BLACK_OID)) == - 0) { + if (str_len == OC_CHAR_ARRAY_LEN(OC_SP_BLACK_OID) && + memcmp(OC_SP_BLACK_OID, str, str_len) == 0) { return OC_SP_BLACK; } - if (sp_string_len == OC_CHAR_ARRAY_LEN(OC_SP_BLUE_OID) && - memcmp(OC_SP_BLUE_OID, sp_string, OC_CHAR_ARRAY_LEN(OC_SP_BLUE_OID)) == - 0) { + if (str_len == OC_CHAR_ARRAY_LEN(OC_SP_BLUE_OID) && + memcmp(OC_SP_BLUE_OID, str, str_len) == 0) { return OC_SP_BLUE; } - if (sp_string_len == OC_CHAR_ARRAY_LEN(OC_SP_PURPLE_OID) && - memcmp(OC_SP_PURPLE_OID, sp_string, - OC_CHAR_ARRAY_LEN(OC_SP_PURPLE_OID)) == 0) { + if (str_len == OC_CHAR_ARRAY_LEN(OC_SP_PURPLE_OID) && + memcmp(OC_SP_PURPLE_OID, str, str_len) == 0) { return OC_SP_PURPLE; } return 0; } +const char * +oc_sec_sp_type_to_string(oc_sp_types_t sp_type) +{ + switch (sp_type) { + case OC_SP_BASELINE: + return OC_SP_BASELINE_OID; + case OC_SP_BLACK: + return OC_SP_BLACK_OID; + case OC_SP_BLUE: + return OC_SP_BLUE_OID; + case OC_SP_PURPLE: + return OC_SP_PURPLE_OID; + } + return NULL; +} + bool oc_sec_decode_sp(const oc_rep_t *rep, size_t device) { @@ -131,8 +161,8 @@ oc_sec_decode_sp(const oc_rep_t *rep, size_t device) case OC_REP_STRING: if (len == 14 && memcmp("currentprofile", oc_string(rep->name), 14) == 0) { - oc_sp_types_t current_profile = - sp_from_string(oc_string(rep->value.string)); + oc_sp_types_t current_profile = oc_sec_sp_type_from_string( + oc_string(rep->value.string), oc_string_len(rep->value.string)); if ((current_profile & g_sp[device].supported_profiles) == 0) { return false; } @@ -146,7 +176,7 @@ oc_sec_decode_sp(const oc_rep_t *rep, size_t device) for (size_t i = 0; i < oc_string_array_get_allocated_size(rep->value.array); ++i) { const char *p = oc_string_array_get_item(rep->value.array, i); - supported_profiles |= sp_from_string(p); + supported_profiles |= oc_sec_sp_type_from_string(p, strlen(p)); } g_sp[device].supported_profiles = supported_profiles; } @@ -160,22 +190,6 @@ oc_sec_decode_sp(const oc_rep_t *rep, size_t device) return true; } -static const char * -sp_to_string(oc_sp_types_t sp_type) -{ - switch (sp_type) { - case OC_SP_BASELINE: - return OC_SP_BASELINE_OID; - case OC_SP_BLACK: - return OC_SP_BLACK_OID; - case OC_SP_BLUE: - return OC_SP_BLUE_OID; - case OC_SP_PURPLE: - return OC_SP_PURPLE_OID; - } - return NULL; -} - void oc_sec_encode_sp(size_t device, oc_interface_mask_t iface_mask, bool to_storage) { @@ -184,20 +198,25 @@ oc_sec_encode_sp(size_t device, oc_interface_mask_t iface_mask, bool to_storage) oc_process_baseline_interface( oc_core_get_resource_by_index(OCF_SEC_SP, device)); } - oc_rep_set_text_string(root, currentprofile, - sp_to_string(g_sp[device].current_profile)); + oc_rep_set_text_string( + root, currentprofile, + oc_sec_sp_type_to_string(g_sp[device].current_profile)); oc_rep_set_array(root, supportedprofiles); if ((g_sp[device].supported_profiles & OC_SP_BASELINE) != 0) { - oc_rep_add_text_string(supportedprofiles, sp_to_string(OC_SP_BASELINE)); + oc_rep_add_text_string(supportedprofiles, + oc_sec_sp_type_to_string(OC_SP_BASELINE)); } if ((g_sp[device].supported_profiles & OC_SP_BLACK) != 0) { - oc_rep_add_text_string(supportedprofiles, sp_to_string(OC_SP_BLACK)); + oc_rep_add_text_string(supportedprofiles, + oc_sec_sp_type_to_string(OC_SP_BLACK)); } if ((g_sp[device].supported_profiles & OC_SP_BLUE) != 0) { - oc_rep_add_text_string(supportedprofiles, sp_to_string(OC_SP_BLUE)); + oc_rep_add_text_string(supportedprofiles, + oc_sec_sp_type_to_string(OC_SP_BLUE)); } if ((g_sp[device].supported_profiles & OC_SP_PURPLE) != 0) { - oc_rep_add_text_string(supportedprofiles, sp_to_string(OC_SP_PURPLE)); + oc_rep_add_text_string(supportedprofiles, + oc_sec_sp_type_to_string(OC_SP_PURPLE)); } oc_rep_close_array(root, supportedprofiles); oc_rep_end_root_object(); diff --git a/security/oc_sp_internal.h b/security/oc_sp_internal.h index ba19ad9f95..cc33c68ccc 100644 --- a/security/oc_sp_internal.h +++ b/security/oc_sp_internal.h @@ -26,6 +26,11 @@ extern "C" { #endif +#define OC_SP_BASELINE_OID "1.3.6.1.4.1.51414.0.0.1.0" +#define OC_SP_BLACK_OID "1.3.6.1.4.1.51414.0.0.2.0" +#define OC_SP_BLUE_OID "1.3.6.1.4.1.51414.0.0.3.0" +#define OC_SP_PURPLE_OID "1.3.6.1.4.1.51414.0.0.4.0" + typedef struct { unsigned supported_profiles; // mask of supported oc_sp_types_t @@ -38,8 +43,32 @@ void oc_sec_sp_free(void); bool oc_sec_decode_sp(const oc_rep_t *rep, size_t device); void oc_sec_encode_sp(size_t device, oc_interface_mask_t iface_mask, bool to_storage); + oc_sec_sp_t *oc_sec_get_sp(size_t device); void oc_sec_sp_default(size_t device); +void oc_sec_sp_copy(oc_sec_sp_t *dst, const oc_sec_sp_t *src); +void oc_sec_sp_clear(oc_sec_sp_t *sp); + +/** + * @brief Parse security profile type from string + * + * @param str string to parse (cannot be NULL) + * @param str_len length of \p str + * + * @return oc_sp_types_t on success + * @return 0 on failure + */ +oc_sp_types_t oc_sec_sp_type_from_string(const char *str, size_t str_len); + +/** + * @brief Encode security profile type to string + * + * @param sp_type type to encode + * @return encoded C-string on success + * @return NULL on failure + */ +const char *oc_sec_sp_type_to_string(oc_sp_types_t sp_type); + void get_sp(oc_request_t *request, oc_interface_mask_t iface_mask, void *data); void post_sp(oc_request_t *request, oc_interface_mask_t iface_mask, void *data); diff --git a/security/oc_store.c b/security/oc_store.c index 018a8e4166..2e63cd08e9 100644 --- a/security/oc_store.c +++ b/security/oc_store.c @@ -29,127 +29,93 @@ #include "oc_keypair_internal.h" #include "oc_pstat.h" #include "oc_rep.h" -#include "oc_sdi.h" +#include "oc_sdi_internal.h" #include "oc_sp_internal.h" #include "oc_tls.h" #include "port/oc_storage.h" +static int +store_decode_doxm(const oc_rep_t *rep, size_t device, void *data) +{ + (void)data; + if (!oc_sec_decode_doxm(rep, /*from_storage*/ true, /*doc*/ false, device)) { + OC_ERR("cannot load doxm: cannot decode representation"); + return -1; + } + return 0; +} + void oc_sec_load_doxm(size_t device) { - oc_storage_buffer_t sb = oc_storage_get_buffer(OC_MAX_APP_DATA_SIZE); -#ifndef OC_APP_DATA_STORAGE_BUFFER - if (sb.buffer == NULL) { - OC_ERR("cannot load %s from store: cannot allocate buffer", "doxm"); + if (oc_storage_load_resource("doxm", device, store_decode_doxm, NULL) <= 0) { oc_sec_doxm_default(device); + OC_ERR("failed to load doxm from storage for device(%zu)", device); return; } -#endif /* !OC_APP_DATA_STORAGE_BUFFER */ - - char svr_tag[OC_STORAGE_SVR_TAG_MAX]; - oc_storage_gen_svr_tag("doxm", device, svr_tag, sizeof(svr_tag)); - long ret = oc_storage_read(svr_tag, sb.buffer, sb.size); - if (ret > 0) { - OC_MEMB_LOCAL(rep_objects, oc_rep_t, OC_MAX_NUM_REP_OBJECTS); - oc_rep_set_pool(&rep_objects); - oc_rep_t *rep = NULL; - oc_parse_rep(sb.buffer, (int)ret, &rep); - oc_sec_decode_doxm(rep, true, false, device); - oc_free_rep(rep); - } - oc_storage_free_buffer(sb); + OC_DBG("%s resource loaded from storage for device(%zu)", "doxm", device); oc_uuid_t *deviceuuid = oc_core_get_device_id(device); const oc_sec_doxm_t *doxm = oc_sec_get_doxm(device); memcpy(deviceuuid, &doxm->deviceuuid, sizeof(oc_uuid_t)); } +static int +store_encode_doxm(size_t device, void *data) +{ + (void)data; + oc_sec_encode_doxm(device, /*iface_mask*/ 0, true); + return 0; +} + void oc_sec_dump_doxm(size_t device) { - oc_storage_buffer_t sb = oc_storage_get_buffer(OC_MIN_APP_DATA_SIZE); -#ifndef OC_APP_DATA_STORAGE_BUFFER - if (sb.buffer == NULL) { - OC_ERR("cannot dump %s to store: cannot allocate buffer", "doxm"); - return; + long ret = oc_storage_save_resource("doxm", device, store_encode_doxm, NULL); + if (ret <= 0) { + OC_ERR("cannot dump doxm to storage: error(%ld)", ret); } - oc_rep_new_realloc(&sb.buffer, OC_MIN_APP_DATA_SIZE, OC_MAX_APP_DATA_SIZE); -#else /* !OC_APP_DATA_STORAGE_BUFFER */ - oc_rep_new(sb.buffer, OC_MIN_APP_DATA_SIZE); -#endif /* OC_APP_DATA_STORAGE_BUFFER */ +} - oc_sec_encode_doxm(device, 0, true); -#ifndef OC_APP_DATA_STORAGE_BUFFER - sb.buffer = oc_rep_shrink_encoder_buf(sb.buffer); - sb.size = (size_t)oc_rep_get_encoder_buffer_size(); -#endif /* !OC_APP_DATA_STORAGE_BUFFER */ - int size = oc_rep_get_encoded_payload_size(); - if (size > 0) { - OC_DBG("oc_store: encoded doxm size %d", size); - char svr_tag[OC_STORAGE_SVR_TAG_MAX]; - oc_storage_gen_svr_tag("doxm", device, svr_tag, sizeof(svr_tag)); - oc_storage_write(svr_tag, sb.buffer, size); +static int +store_decode_pstat(const oc_rep_t *rep, size_t device, void *data) +{ + (void)data; + if (!oc_sec_decode_pstat(rep, true, device)) { + OC_ERR("cannot decode pstat"); + return -1; } - oc_storage_free_buffer(sb); + return 0; } void oc_sec_load_pstat(size_t device) { - oc_storage_buffer_t sb = oc_storage_get_buffer(OC_MAX_APP_DATA_SIZE); -#ifndef OC_APP_DATA_STORAGE_BUFFER - if (sb.buffer == NULL) { - OC_ERR("cannot load %s from store: cannot allocate buffer", "pstat"); + if (oc_storage_load_resource("pstat", device, store_decode_pstat, NULL) <= + 0) { oc_sec_pstat_default(device); + OC_ERR("failed to load pstat from storage for device(%zu)", device); return; } -#endif /* !OC_APP_DATA_STORAGE_BUFFER */ - - char svr_tag[OC_STORAGE_SVR_TAG_MAX]; - oc_storage_gen_svr_tag("pstat", device, svr_tag, sizeof(svr_tag)); - long ret = oc_storage_read(svr_tag, sb.buffer, sb.size); - if (ret > 0) { - OC_MEMB_LOCAL(rep_objects, oc_rep_t, OC_MAX_NUM_REP_OBJECTS); - oc_rep_set_pool(&rep_objects); - oc_rep_t *rep = NULL; - oc_parse_rep(sb.buffer, (int)ret, &rep); - oc_sec_decode_pstat(rep, true, device); - oc_free_rep(rep); - } - oc_storage_free_buffer(sb); + OC_DBG("%s resource loaded from storage for device(%zu)", "pstat", device); +} - if (ret <= 0) { - oc_sec_pstat_default(device); - } +static int +store_encode_pstat(size_t device, void *data) +{ + (void)data; + oc_sec_encode_pstat(device, /*iface_mask*/ 0, /*to_storage*/ true); + return 0; } void oc_sec_dump_pstat(size_t device) { - oc_storage_buffer_t sb = oc_storage_get_buffer(OC_MIN_APP_DATA_SIZE); -#ifndef OC_APP_DATA_STORAGE_BUFFER - if (sb.buffer == NULL) { - OC_ERR("cannot dump %s to store: cannot allocate buffer", "pstat"); - return; - } - oc_rep_new_realloc(&sb.buffer, OC_MIN_APP_DATA_SIZE, OC_MAX_APP_DATA_SIZE); -#else /* !OC_APP_DATA_STORAGE_BUFFER */ - oc_rep_new(sb.buffer, OC_MIN_APP_DATA_SIZE); -#endif /* OC_APP_DATA_STORAGE_BUFFER */ - - oc_sec_encode_pstat(device, 0, true); -#ifndef OC_APP_DATA_STORAGE_BUFFER - sb.buffer = oc_rep_shrink_encoder_buf(sb.buffer); - sb.size = (size_t)oc_rep_get_encoder_buffer_size(); -#endif /* !OC_APP_DATA_STORAGE_BUFFER */ - int size = oc_rep_get_encoded_payload_size(); - if (size > 0) { - OC_DBG("oc_store: encoded pstat size %d", size); - char svr_tag[OC_STORAGE_SVR_TAG_MAX]; - oc_storage_gen_svr_tag("pstat", device, svr_tag, sizeof(svr_tag)); - oc_storage_write(svr_tag, sb.buffer, size); + long ret = + oc_storage_save_resource("pstat", device, store_encode_pstat, NULL); + if (ret <= 0) { + OC_ERR("cannot dump pstat to storage: error(%ld)", ret); } - oc_storage_free_buffer(sb); } void @@ -531,62 +497,44 @@ oc_sec_dump_ael(size_t device) oc_storage_free_buffer(sb); } +static int +store_decode_sdi(const oc_rep_t *rep, size_t device, void *data) +{ + (void)data; + if (!oc_sec_sdi_decode(device, rep, /*from_storage*/ true)) { + OC_ERR("cannot decode sdi"); + return -1; + } + return 0; +} + void oc_sec_load_sdi(size_t device) { - oc_storage_buffer_t sb = oc_storage_get_buffer(OC_MAX_APP_DATA_SIZE); -#ifndef OC_APP_DATA_STORAGE_BUFFER - if (sb.buffer == NULL) { - OC_ERR("cannot load %s from store: cannot allocate buffer", "sdi"); + if (oc_storage_load_resource(OCF_SEC_SDI_STORE_NAME, device, store_decode_sdi, + NULL) <= 0) { + OC_ERR("failed to load sdi from storage for device(%zu)", device); oc_sec_sdi_default(device); return; } -#endif /* !OC_APP_DATA_STORAGE_BUFFER */ + OC_DBG("%s resource loaded from storage for device(%zu)", "sdi", device); +} - char svr_tag[OC_STORAGE_SVR_TAG_MAX]; - oc_storage_gen_svr_tag("sdi", device, svr_tag, sizeof(svr_tag)); - long ret = oc_storage_read(svr_tag, sb.buffer, sb.size); - if (ret > 0) { - OC_MEMB_LOCAL(rep_objects, oc_rep_t, OC_MAX_NUM_REP_OBJECTS); - oc_rep_set_pool(&rep_objects); - oc_rep_t *rep = NULL; - oc_parse_rep(sb.buffer, (int)ret, &rep); - oc_sec_decode_sdi(rep, true, device); - oc_free_rep(rep); - } else { - oc_sec_sdi_default(device); - } - oc_storage_free_buffer(sb); +static int +store_encode_sdi(size_t device, void *data) +{ + (void)data; + return oc_sec_sdi_encode(device, /*iface_mask*/ 0); } void oc_sec_dump_sdi(size_t device) { - oc_storage_buffer_t sb = oc_storage_get_buffer(OC_MIN_APP_DATA_SIZE); -#ifndef OC_APP_DATA_STORAGE_BUFFER - if (sb.buffer == NULL) { - OC_ERR("cannot dump %s to store: cannot allocate buffer", "sdi"); - return; - } - oc_rep_new_realloc(&sb.buffer, OC_MIN_APP_DATA_SIZE, OC_MAX_APP_DATA_SIZE); -#else /* !OC_APP_DATA_STORAGE_BUFFER */ - oc_rep_new(sb.buffer, OC_MIN_APP_DATA_SIZE); -#endif /* OC_APP_DATA_STORAGE_BUFFER */ - - /* sdi */ - oc_sec_encode_sdi(device, true); -#ifndef OC_APP_DATA_STORAGE_BUFFER - sb.buffer = oc_rep_shrink_encoder_buf(sb.buffer); - sb.size = (size_t)oc_rep_get_encoder_buffer_size(); -#endif /* !OC_APP_DATA_STORAGE_BUFFER */ - int size = oc_rep_get_encoded_payload_size(); - if (size > 0) { - OC_DBG("oc_store: encoded sdi size %d", size); - char svr_tag[OC_STORAGE_SVR_TAG_MAX]; - oc_storage_gen_svr_tag("sdi", device, svr_tag, sizeof(svr_tag)); - oc_storage_write(svr_tag, sb.buffer, size); + long ret = oc_storage_save_resource(OCF_SEC_SDI_STORE_NAME, device, + store_encode_sdi, NULL); + if (ret <= 0) { + OC_ERR("cannot dump sdi to store: error(%ld)", ret); } - oc_storage_free_buffer(sb); } #endif /* OC_SECURITY */ diff --git a/security/oc_svr.c b/security/oc_svr.c index 46727cded7..beb9c19a7f 100644 --- a/security/oc_svr.c +++ b/security/oc_svr.c @@ -30,7 +30,7 @@ #include "oc_doxm_internal.h" #include "oc_pstat.h" #include "oc_ri.h" -#include "oc_sdi.h" +#include "oc_sdi_internal.h" #include "oc_sp_internal.h" #include "port/oc_log.h" @@ -39,8 +39,8 @@ oc_sec_svr_create(void) { oc_sec_doxm_init(); oc_sec_pstat_init(); - oc_sec_cred_init(); oc_sec_acl_init(); + oc_sec_cred_init(); oc_sec_ael_init(); oc_sec_sp_init(); oc_sec_sdi_init(); @@ -68,9 +68,7 @@ oc_sec_svr_create(void) oc_core_populate_resource( OCF_SEC_SP, i, "/oic/sec/sp", OC_IF_RW | OC_IF_BASELINE, OC_IF_RW, OC_DISCOVERABLE | OC_SECURE, get_sp, 0, post_sp, 0, 1, "oic.r.sp"); - oc_core_populate_resource( - OCF_SEC_SDI, i, "/oic/sec/sdi", OC_IF_BASELINE | OC_IF_RW, OC_IF_RW, - OC_DISCOVERABLE | OC_SECURE, get_sdi, 0, post_sdi, 0, 1, "oic.r.sdi"); + oc_sec_sdi_create_resource(i); #ifdef OC_PKI oc_core_populate_resource( OCF_SEC_CSR, i, OCF_SEC_CSR_URI, OC_IF_RW | OC_IF_BASELINE, OC_IF_RW, @@ -89,8 +87,8 @@ oc_sec_svr_free(void) oc_sec_sdi_free(); oc_sec_sp_free(); oc_sec_ael_free(); - oc_sec_acl_free(); oc_sec_cred_free(); + oc_sec_acl_free(); oc_sec_pstat_free(); oc_sec_doxm_free(); } diff --git a/security/unittest/acltest.cpp b/security/unittest/acltest.cpp index 80bf157838..bb01421b66 100644 --- a/security/unittest/acltest.cpp +++ b/security/unittest/acltest.cpp @@ -16,6 +16,8 @@ * ******************************************************************/ +#ifdef OC_SECURITY + #include "api/oc_core_res_internal.h" #include "oc_acl.h" #include "oc_api.h" @@ -33,8 +35,6 @@ #include "gtest/gtest.h" #include -#ifdef OC_SECURITY - static const std::string kDeviceURI{ "/oic/d" }; static const std::string kDeviceType{ "oic.d.light" }; static const std::string kDeviceName{ "Table Lamp" }; diff --git a/security/unittest/credtest.cpp b/security/unittest/credtest.cpp new file mode 100644 index 0000000000..1d50698c80 --- /dev/null +++ b/security/unittest/credtest.cpp @@ -0,0 +1,116 @@ +/****************************************************************** + * + * Copyright 2022 Daniel Adam, All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"), + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************/ + +#ifdef OC_SECURITY + +#include "oc_cred.h" +#include "oc_helpers.h" +#include "security/oc_cred_internal.h" +#include "util/oc_macros.h" + +#include + +class TestCred : public testing::Test {}; + +TEST_F(TestCred, ParseEncoding) +{ + oc_string_t enc{}; + oc_set_string(&enc, "", 0); + EXPECT_EQ(OC_ENCODING_UNSUPPORTED, oc_cred_parse_encoding(&enc)); + + oc_set_string(&enc, OC_ENCODING_BASE64_STR, + OC_CHAR_ARRAY_LEN(OC_ENCODING_BASE64_STR)); + EXPECT_EQ(OC_ENCODING_BASE64, oc_cred_parse_encoding(&enc)); + + oc_set_string(&enc, OC_ENCODING_RAW_STR, + OC_CHAR_ARRAY_LEN(OC_ENCODING_RAW_STR)); + EXPECT_EQ(OC_ENCODING_RAW, oc_cred_parse_encoding(&enc)); + + oc_set_string(&enc, OC_ENCODING_HANDLE_STR, + OC_CHAR_ARRAY_LEN(OC_ENCODING_HANDLE_STR)); + EXPECT_EQ(OC_ENCODING_HANDLE, oc_cred_parse_encoding(&enc)); + +#ifdef OC_PKI + oc_set_string(&enc, OC_ENCODING_PEM_STR, + OC_CHAR_ARRAY_LEN(OC_ENCODING_PEM_STR)); + EXPECT_EQ(OC_ENCODING_PEM, oc_cred_parse_encoding(&enc)); +#endif /* OC_PKI */ + + oc_free_string(&enc); +} + +TEST_F(TestCred, ReadEncoding) +{ + EXPECT_STREQ(OC_ENCODING_BASE64_STR, + oc_cred_read_encoding(OC_ENCODING_BASE64)); + EXPECT_STREQ(OC_ENCODING_RAW_STR, oc_cred_read_encoding(OC_ENCODING_RAW)); + EXPECT_STREQ(OC_ENCODING_HANDLE_STR, + oc_cred_read_encoding(OC_ENCODING_HANDLE)); +#ifdef OC_PKI + EXPECT_STREQ(OC_ENCODING_PEM_STR, oc_cred_read_encoding(OC_ENCODING_PEM)); +#endif /* OC_PKI */ +} + +#ifdef OC_PKI + +TEST_F(TestCred, ParseCredUsage) +{ + oc_string_t usage{}; + oc_set_string(&usage, "", 0); + EXPECT_EQ(OC_CREDUSAGE_NULL, oc_cred_parse_credusage(&usage)); + + oc_set_string(&usage, OC_CREDUSAGE_TRUSTCA_STR, + OC_CHAR_ARRAY_LEN(OC_CREDUSAGE_TRUSTCA_STR)); + EXPECT_EQ(OC_CREDUSAGE_TRUSTCA, oc_cred_parse_credusage(&usage)); + + oc_set_string(&usage, OC_CREDUSAGE_IDENTITY_CERT_STR, + OC_CHAR_ARRAY_LEN(OC_CREDUSAGE_IDENTITY_CERT_STR)); + EXPECT_EQ(OC_CREDUSAGE_IDENTITY_CERT, oc_cred_parse_credusage(&usage)); + + oc_set_string(&usage, OC_CREDUSAGE_ROLE_CERT_STR, + OC_CHAR_ARRAY_LEN(OC_CREDUSAGE_ROLE_CERT_STR)); + EXPECT_EQ(OC_CREDUSAGE_ROLE_CERT, oc_cred_parse_credusage(&usage)); + + oc_set_string(&usage, OC_CREDUSAGE_MFG_TRUSTCA_STR, + OC_CHAR_ARRAY_LEN(OC_CREDUSAGE_MFG_TRUSTCA_STR)); + EXPECT_EQ(OC_CREDUSAGE_MFG_TRUSTCA, oc_cred_parse_credusage(&usage)); + + oc_set_string(&usage, OC_CREDUSAGE_MFG_CERT_STR, + OC_CHAR_ARRAY_LEN(OC_CREDUSAGE_MFG_CERT_STR)); + EXPECT_EQ(OC_CREDUSAGE_MFG_CERT, oc_cred_parse_credusage(&usage)); + + oc_free_string(&usage); +} + +TEST_F(TestCred, ReadCredUsage) +{ + EXPECT_STREQ(OC_CREDUSAGE_TRUSTCA_STR, + oc_cred_read_credusage(OC_CREDUSAGE_TRUSTCA)); + EXPECT_STREQ(OC_CREDUSAGE_IDENTITY_CERT_STR, + oc_cred_read_credusage(OC_CREDUSAGE_IDENTITY_CERT)); + EXPECT_STREQ(OC_CREDUSAGE_ROLE_CERT_STR, + oc_cred_read_credusage(OC_CREDUSAGE_ROLE_CERT)); + EXPECT_STREQ(OC_CREDUSAGE_MFG_TRUSTCA_STR, + oc_cred_read_credusage(OC_CREDUSAGE_MFG_TRUSTCA)); + EXPECT_STREQ(OC_CREDUSAGE_MFG_CERT_STR, + oc_cred_read_credusage(OC_CREDUSAGE_MFG_CERT)); +} + +#endif /* OC_PKI */ + +#endif /* OC_SECURITY */ diff --git a/security/unittest/keypairtest.cpp b/security/unittest/keypairtest.cpp index c08a975001..cab71b1a14 100644 --- a/security/unittest/keypairtest.cpp +++ b/security/unittest/keypairtest.cpp @@ -380,9 +380,9 @@ TEST_F(TestKeyPair, DecodeForDevice) static std::vector generateKeypairs(mbedtls_ecp_group_id grpid, size_t count) { - oc::RepPool pool{}; std::vector keypairs{}; for (size_t i = 0; i < count; ++i) { + oc::RepPool pool{}; oc_ecdsa_keypair_t kp_in = oc::GetOCKeyPair(grpid); keypairs.push_back(kp_in); @@ -391,7 +391,6 @@ generateKeypairs(mbedtls_ecp_group_id grpid, size_t count) auto rep = pool.ParsePayload(); EXPECT_TRUE(oc_sec_ecdsa_decode_keypair_for_device(rep.get(), /*device*/ i)) << "error for ec(" << grpid << ")"; - pool.Clear(); } return keypairs; } diff --git a/security/unittest/pstattest.cpp b/security/unittest/pstattest.cpp index b5db4248f7..a182a11e4d 100644 --- a/security/unittest/pstattest.cpp +++ b/security/unittest/pstattest.cpp @@ -79,25 +79,53 @@ class TestPstat : public testing::Test { static bool IsEqual(const oc_sec_pstat_t &lhs, const oc_sec_pstat_t &rhs) { - return lhs.s == rhs.s && lhs.p == rhs.p && lhs.isop == rhs.isop && lhs.cm == rhs.cm && lhs.tm == rhs.tm && lhs.om == rhs.om && lhs.sm == rhs.sm && oc_uuid_is_equal(lhs.rowneruuid, rhs.rowneruuid); } + + static void ExpectEqual(const oc_sec_pstat_t &lhs, const oc_sec_pstat_t &rhs) + { + EXPECT_EQ(lhs.s, rhs.s); + EXPECT_EQ(lhs.p, rhs.p); + EXPECT_EQ(lhs.isop, rhs.isop); + EXPECT_EQ(lhs.cm, rhs.cm); + EXPECT_EQ(lhs.tm, rhs.tm); + EXPECT_EQ(lhs.om, rhs.om); + EXPECT_EQ(lhs.sm, rhs.sm); + } }; +TEST_F(TestPstat, Copy) +{ + oc_sec_pstat_t ps1; + ps1.s = OC_DOS_SRESET; + ps1.p = true; + ps1.isop = true; + ps1.cm = OC_DPM_SSV; + ps1.tm = OC_DPM_NSA; + ps1.om = 4; + ps1.sm = 4; + + oc_sec_pstat_t ps2{}; + oc_sec_pstat_copy(&ps2, &ps1); + ExpectEqual(ps1, ps2); + + oc_sec_pstat_copy(&ps1, &ps1); + ExpectEqual(ps2, ps1); + + oc_sec_pstat_clear(&ps1); + EXPECT_FALSE(IsEqual(ps1, ps2)); +} + TEST_F(TestPstat, DumpAndLoad) { // load default values and dump them to storage oc_sec_pstat_default(0); oc_sec_pstat_t def{}; - oc_sec_pstat_t *ps = oc_sec_get_pstat(0); - ASSERT_NE(nullptr, ps); - memcpy(&def, ps, sizeof(oc_sec_pstat_t)); - // overwrite pstat data with 0 - memset(ps, 0, sizeof(oc_sec_pstat_t)); - + oc_sec_pstat_copy(&def, oc_sec_get_pstat(0)); + oc_sec_pstat_clear(oc_sec_get_pstat(0)); EXPECT_FALSE(IsEqual(def, *oc_sec_get_pstat(0))); // load values from storage diff --git a/security/unittest/sditest.cpp b/security/unittest/sditest.cpp new file mode 100644 index 0000000000..19ffb034a6 --- /dev/null +++ b/security/unittest/sditest.cpp @@ -0,0 +1,345 @@ +/****************************************************************** + * + * Copyright 2023 Daniel Adam, All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"), + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************/ + +#ifdef OC_SECURITY + +#include "api/oc_ri_internal.h" +#include "api/oc_storage_internal.h" +#include "oc_acl.h" +#include "oc_core_res.h" +#include "oc_helpers.h" +#include "oc_store.h" +#include "oc_uuid.h" +#include "port/oc_random.h" +#include "port/oc_storage.h" +#include "port/oc_storage_internal.h" +#include "security/oc_sdi_internal.h" +#include "tests/gtest/Device.h" +#include "tests/gtest/RepPool.h" + +#include +#include +#include + +static const std::string testStorage{ "storage_test" }; + +class TestSdi : public testing::Test { +public: + static void SetUpTestCase() { oc_random_init(); } + + static void TearDownTestCase() { oc_random_destroy(); } + + static oc_sec_sdi_t createSdi(bool priv, const std::string &name, + oc_sec_sdi_t &sdi) + { + sdi.priv = priv; + oc_gen_uuid(&sdi.uuid); + oc_new_string(&sdi.name, name.c_str(), name.length()); + return sdi; + } + + static bool isEqual(oc_sec_sdi_t &lhs, oc_sec_sdi_t &rhs) + { + return lhs.priv == rhs.priv && oc_uuid_is_equal(lhs.uuid, rhs.uuid) && + oc_string_len(lhs.name) == oc_string_len(rhs.name) && + (oc_string(lhs.name) == oc_string(rhs.name) || + memcmp(oc_string(lhs.name), oc_string(rhs.name), + oc_string_len(lhs.name))); + } + + static void expectEqual(oc_sec_sdi_t &lhs, oc_sec_sdi_t &rhs) + { + EXPECT_EQ(lhs.priv, rhs.priv); + EXPECT_TRUE(oc_uuid_is_equal(lhs.uuid, rhs.uuid)); + if (oc_string(lhs.name) == nullptr) { + EXPECT_EQ(nullptr, oc_string(rhs.name)); + } else { + EXPECT_STREQ(oc_string(lhs.name), oc_string(rhs.name)); + } + } +}; + +#ifndef DYNAMIC_ALLOCATION + +TEST_F(TestSdi, EncodeFail) +{ + // not enough memory to encode to encode sdi + oc::RepPool pool{ 10 }; + + oc_sec_sdi_t sdi{}; + createSdi(true, "test", sdi); + EXPECT_NE( + 0, oc_sec_sdi_encode_with_resource(&sdi, nullptr, OCF_SEC_SDI_DEFAULT_IF)); + + oc_free_string(&sdi.name); +} + +#endif /* !DYNAMIC_ALLOCATION */ + +TEST_F(TestSdi, Encode) +{ + oc::RepPool pool{}; + + oc_sec_sdi_t sdi{}; + createSdi(true, "test", sdi); + EXPECT_EQ( + 0, oc_sec_sdi_encode_with_resource(&sdi, nullptr, OCF_SEC_SDI_DEFAULT_IF)); + + oc_free_string(&sdi.name); +} + +TEST_F(TestSdi, DecodeFromStorageFail_MissingProperties) +{ + oc::RepPool pool{}; + + oc_rep_start_root_object(); + oc_rep_set_text_string(root, test, "test"); + oc_rep_end_root_object(); + + auto rep = pool.ParsePayload(); + oc_sec_sdi_t sdi_parsed{}; + EXPECT_FALSE( + oc_sec_sdi_decode_with_state(rep.get(), OC_DOS_RFOTM, true, &sdi_parsed)); +} + +TEST_F(TestSdi, DecodeFail_InvalidStateForUUID) +{ + oc::RepPool pool{}; + + oc_rep_start_root_object(); + oc_uuid_t uuid{}; + oc_gen_uuid(&uuid); + std::array uuid_str{}; + oc_uuid_to_str(&uuid, &uuid_str[0], uuid_str.size()); + oc_rep_set_text_string(root, uuid, uuid_str.data()); + oc_rep_end_root_object(); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + + // can only set uuid in RFOTM when no from storage + auto rep = pool.ParsePayload(); + oc_sec_sdi_t sdi_parsed{}; + EXPECT_FALSE( + oc_sec_sdi_decode_with_state(rep.get(), OC_DOS_RFPRO, false, &sdi_parsed)); +} + +TEST_F(TestSdi, DecodeFail_InvalidStateForName) +{ + oc::RepPool pool{}; + + oc_rep_start_root_object(); + oc_rep_set_text_string(root, name, "test"); + oc_rep_end_root_object(); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + + // can set name only in OC_DOS_RFOTM, OC_DOS_RFPRO or OC_DOS_SRESET + auto rep = pool.ParsePayload(); + oc_sec_sdi_t sdi_parsed{}; + EXPECT_FALSE( + oc_sec_sdi_decode_with_state(rep.get(), OC_DOS_RESET, false, &sdi_parsed)); +} + +TEST_F(TestSdi, DecodeFail_InvalidStateForPriv) +{ + oc::RepPool pool{}; + + oc_rep_start_root_object(); + oc_rep_set_boolean(root, priv, false); + oc_rep_end_root_object(); + ASSERT_EQ(CborNoError, oc_rep_get_cbor_errno()); + + // can set priv only in OC_DOS_RFOTM, OC_DOS_RFPRO or OC_DOS_SRESET + auto rep = pool.ParsePayload(); + oc_sec_sdi_t sdi_parsed{}; + EXPECT_FALSE( + oc_sec_sdi_decode_with_state(rep.get(), OC_DOS_RFNOP, false, &sdi_parsed)); +} + +TEST_F(TestSdi, Decode) +{ + oc::RepPool pool{}; + + oc_sec_sdi_t sdi{}; + createSdi(true, "test123", sdi); + EXPECT_EQ( + 0, oc_sec_sdi_encode_with_resource(&sdi, nullptr, OCF_SEC_SDI_DEFAULT_IF)); + + auto rep = pool.ParsePayload(); + oc_sec_sdi_t sdi_parsed{}; + EXPECT_TRUE( + oc_sec_sdi_decode_with_state(rep.get(), OC_DOS_RFOTM, false, &sdi_parsed)); + + TestSdi::expectEqual(sdi, sdi_parsed); + + oc_free_string(&sdi_parsed.name); + oc_free_string(&sdi.name); +} + +class TestSdiWithServer : public testing::Test { +public: + static void SetUpTestCase() + { + ASSERT_EQ(0, oc_storage_config(testStorage.c_str())); + + ASSERT_TRUE(oc::TestDevice::StartServer()); +#ifdef OC_HAS_FEATURE_RESOURCE_ACCESS_IN_RFOTM + oc_resource_t *sdi = + oc_core_get_resource_by_index(OCF_SEC_SDI, /*device*/ 0); + ASSERT_NE(nullptr, sdi); + oc_resource_set_access_in_RFOTM( + sdi, true, + static_cast(OC_PERM_RETRIEVE | OC_PERM_UPDATE)); +#endif /* OC_HAS_FEATURE_RESOURCE_ACCESS_IN_RFOTM */ + } + + static void TearDownTestCase() + { + oc::TestDevice::StopServer(); + + ASSERT_EQ(0, oc_storage_reset()); + for (const auto &entry : std::filesystem::directory_iterator(testStorage)) { + std::filesystem::remove_all(entry.path()); + } + } +}; + +TEST_F(TestSdiWithServer, GetResourceByIndex) +{ + EXPECT_NE(nullptr, oc_core_get_resource_by_index(OCF_SEC_SDI, /*device*/ 0)); +} + +TEST_F(TestSdiWithServer, GetResourceByURI) +{ + oc_resource_t *res = + oc_core_get_resource_by_uri(OCF_SEC_SDI_URI, /*device*/ 0); + EXPECT_NE(nullptr, res); + + EXPECT_STREQ(OCF_SEC_SDI_URI, oc_string(res->uri)); +} + +#ifdef OC_HAS_FEATURE_RESOURCE_ACCESS_IN_RFOTM + +TEST_F(TestSdiWithServer, GetRequest) +{ + // get insecure connection to the testing device + const oc_endpoint_t *ep = oc::TestDevice::GetEndpoint(/*device*/ 0, -SECURED); + ASSERT_NE(nullptr, ep); + + auto get_handler = [](oc_client_response_t *data) { + EXPECT_EQ(OC_STATUS_OK, data->code); + oc::TestDevice::Terminate(); + OC_DBG("GET payload: %s", oc::RepPool::GetJson(data->payload).data()); + auto *sdi = static_cast(data->user_data); + EXPECT_TRUE(oc_sec_sdi_decode_with_state(data->payload, OC_DOS_RFOTM, + /*from_storage*/ false, sdi)); + }; + + oc_sec_sdi_t sdi{}; + EXPECT_TRUE(oc_do_get(OCF_SEC_SDI_URI, ep, "if=" OC_IF_BASELINE_STR, + get_handler, HIGH_QOS, &sdi)); + oc::TestDevice::PoolEvents(5); + + oc_sec_sdi_t *s = oc_sec_sdi_get(0); + ASSERT_NE(nullptr, s); + TestSdi::expectEqual(*s, sdi); +} + +TEST_F(TestSdiWithServer, PostRequest) +{ + const oc_endpoint_t *ep = oc::TestDevice::GetEndpoint(/*device*/ 0, -SECURED); + ASSERT_NE(nullptr, ep); + + auto post_handler = [](oc_client_response_t *data) { + EXPECT_EQ(OC_STATUS_CHANGED, data->code); + oc::TestDevice::Terminate(); + OC_DBG("POST payload: %s", oc::RepPool::GetJson(data->payload).data()); + // TODO: fill response in SDI + auto *invoked = static_cast(data->user_data); + *invoked = true; + }; + + bool invoked = false; + ASSERT_TRUE(oc_init_post(OCF_SEC_SDI_URI, ep, nullptr, post_handler, HIGH_QOS, + &invoked)); + + oc_sec_sdi_t sdi_new{}; + TestSdi::createSdi(true, "new sdi name", sdi_new); + oc_sec_sdi_encode_with_resource(&sdi_new, /*sdi_res*/ nullptr, + static_cast(0)); + + EXPECT_TRUE(oc_do_post()); + oc::TestDevice::PoolEvents(5); + + TestSdi::expectEqual(*oc_sec_sdi_get(0), sdi_new); + + oc_free_string(&sdi_new.name); +} + +#endif /* OC_HAS_FEATURE_RESOURCE_ACCESS_IN_RFOTM */ + +TEST_F(TestSdiWithServer, Copy) +{ + oc_sec_sdi_t sdi1{}; + TestSdi::createSdi(true, "test", sdi1); + oc_uuid_t uuid = sdi1.uuid; + + oc_sec_sdi_copy(&sdi1, &sdi1); + EXPECT_TRUE(sdi1.priv); + EXPECT_TRUE(oc_uuid_is_equal(uuid, sdi1.uuid)); + EXPECT_STREQ("test", oc_string(sdi1.name)); + + oc_sec_sdi_t sdi2{}; + oc_sec_sdi_copy(&sdi2, &sdi1); + + EXPECT_EQ(sdi1.priv, sdi2.priv); + EXPECT_TRUE(oc_uuid_is_equal(sdi1.uuid, sdi2.uuid)); + EXPECT_STREQ(oc_string(sdi1.name), oc_string(sdi2.name)); + + oc_sec_sdi_clear(&sdi1); + EXPECT_NE(sdi1.priv, sdi2.priv); + EXPECT_FALSE(oc_uuid_is_equal(sdi1.uuid, sdi2.uuid)); + EXPECT_STRNE(oc_string(sdi1.name), oc_string(sdi2.name)); + + oc_free_string(&sdi2.name); + oc_free_string(&sdi1.name); +} + +TEST_F(TestSdiWithServer, DumpAndLoad) +{ + // load default values and dump them to storage + oc_sec_sdi_default(0); + + oc_sec_sdi_t def{}; + const oc_sec_sdi_t *sdi = oc_sec_sdi_get(0); + oc_sec_sdi_copy(&def, sdi); + + // overwrite sdi data + oc_sec_sdi_t sdi_new{}; + TestSdi::createSdi(true, "test", sdi_new); + oc_sec_sdi_copy(oc_sec_sdi_get(0), &sdi_new); + + EXPECT_TRUE(!TestSdi::isEqual(def, *oc_sec_sdi_get(0))); + + // load values from storage + oc_sec_load_sdi(0); + EXPECT_TRUE(TestSdi::isEqual(def, *oc_sec_sdi_get(0))); + + oc_free_string(&sdi_new.name); + oc_free_string(&def.name); +} + +#endif /* OC_SECURITY */ diff --git a/security/unittest/sptest.cpp b/security/unittest/sptest.cpp index 229d311c3d..d1d193b5fe 100644 --- a/security/unittest/sptest.cpp +++ b/security/unittest/sptest.cpp @@ -22,6 +22,7 @@ #include "api/oc_storage_internal.h" #include "oc_api.h" #include "oc_ri.h" +#include "oc_sp.h" #include "oc_store.h" #include "port/oc_connectivity.h" #include "port/oc_network_event_handler_internal.h" @@ -84,20 +85,65 @@ class TestSecurityProfile : public testing::Test { lhs.current_profile == rhs.current_profile && lhs.credid == rhs.credid; } + + static void ExpectEqual(const oc_sec_sp_t &lhs, const oc_sec_sp_t &rhs) + { + EXPECT_EQ(lhs.supported_profiles, rhs.supported_profiles); + EXPECT_EQ(lhs.current_profile, rhs.current_profile); + EXPECT_EQ(lhs.credid, rhs.credid); + } }; +TEST_F(TestSecurityProfile, Copy) +{ + oc_sec_sp_t sp1; + sp1.supported_profiles = OC_SP_BASELINE | OC_SP_BLACK | OC_SP_BLUE; + sp1.current_profile = OC_SP_BLACK; + sp1.credid = 42; + + oc_sec_sp_t sp2{}; + oc_sec_sp_copy(&sp2, &sp1); + ExpectEqual(sp1, sp2); + + oc_sec_sp_copy(&sp1, &sp1); + ExpectEqual(sp2, sp1); + + oc_sec_sp_clear(&sp1); + EXPECT_FALSE(IsEqual(sp1, sp2)); +} + +TEST_F(TestSecurityProfile, FromString) +{ + EXPECT_EQ(0, oc_sec_sp_type_from_string("", 0)); + + EXPECT_EQ(OC_SP_BASELINE, oc_sec_sp_type_from_string( + OC_SP_BASELINE_OID, strlen(OC_SP_BASELINE_OID))); + EXPECT_EQ(OC_SP_BLACK, oc_sec_sp_type_from_string(OC_SP_BLACK_OID, + strlen(OC_SP_BLACK_OID))); + EXPECT_EQ(OC_SP_BLUE, + oc_sec_sp_type_from_string(OC_SP_BLUE_OID, strlen(OC_SP_BLUE_OID))); + EXPECT_EQ(OC_SP_PURPLE, oc_sec_sp_type_from_string(OC_SP_PURPLE_OID, + strlen(OC_SP_PURPLE_OID))); +} + +TEST_F(TestSecurityProfile, ToString) +{ + EXPECT_EQ(nullptr, oc_sec_sp_type_to_string(static_cast(0))); + + EXPECT_STREQ(OC_SP_BASELINE_OID, oc_sec_sp_type_to_string(OC_SP_BASELINE)); + EXPECT_STREQ(OC_SP_BLACK_OID, oc_sec_sp_type_to_string(OC_SP_BLACK)); + EXPECT_STREQ(OC_SP_BLUE_OID, oc_sec_sp_type_to_string(OC_SP_BLUE)); + EXPECT_STREQ(OC_SP_PURPLE_OID, oc_sec_sp_type_to_string(OC_SP_PURPLE)); +} + TEST_F(TestSecurityProfile, DumpAndLoad) { // load default values and dump them to storage oc_sec_sp_default(0); oc_sec_sp_t def{}; - oc_sec_sp_t *sp = oc_sec_get_sp(0); - ASSERT_NE(nullptr, sp); - memcpy(&def, sp, sizeof(oc_sec_sp_t)); - // overwrite doxm data with 0 - memset(sp, 0, sizeof(oc_sec_sp_t)); - + oc_sec_sp_copy(&def, oc_sec_get_sp(0)); + oc_sec_sp_clear(oc_sec_get_sp(0)); EXPECT_FALSE(IsEqual(def, *oc_sec_get_sp(0))); // load values from storage diff --git a/tests/gtest/Device.cpp b/tests/gtest/Device.cpp index 7f5e22ade6..7d80f4fa6f 100644 --- a/tests/gtest/Device.cpp +++ b/tests/gtest/Device.cpp @@ -273,7 +273,7 @@ TestDevice::ClearDynamicResources() #endif /* OC_SERVER */ -const oc_endpoint_t * +oc_endpoint_t * TestDevice::GetEndpoint(size_t device, int flags) { oc_endpoint_t *ep = oc_connectivity_get_endpoints(device); diff --git a/tests/gtest/Device.h b/tests/gtest/Device.h index 1dc2514c3a..c36dbe89bd 100644 --- a/tests/gtest/Device.h +++ b/tests/gtest/Device.h @@ -147,7 +147,7 @@ class TestDevice { static void ClearDynamicResources(); #endif /* OC_SERVER */ - static const oc_endpoint_t *GetEndpoint(size_t device, int flags = 0); + static oc_endpoint_t *GetEndpoint(size_t device, int flags = 0); private: static int SetSystemTime(oc_clock_time_t time, void *user_data); diff --git a/tests/gtest/RepPool.cpp b/tests/gtest/RepPool.cpp index 30ceb3e8d8..197813e1a3 100644 --- a/tests/gtest/RepPool.cpp +++ b/tests/gtest/RepPool.cpp @@ -50,6 +50,8 @@ RepPool::Clear() #else buffer_.resize(size_); oc_rep_new(buffer_.data(), buffer_.size()); + memset(rep_objects_alloc_, 0, OC_MAX_NUM_REP_OBJECTS * sizeof(char)); + memset(rep_objects_pool_, 0, OC_MAX_NUM_REP_OBJECTS * sizeof(oc_rep_t)); #endif /* OC_DYNAMIC_ALLOCATION */ } diff --git a/util/oc_mem_trace.c b/util/oc_mem_trace.c index 2d1b5c430e..95bab0ed42 100644 --- a/util/oc_mem_trace.c +++ b/util/oc_mem_trace.c @@ -108,7 +108,7 @@ oc_mem_trace_add_pace(const char *func, int size, int type, void *address) oc_list_add((&mInfo)->mem_log_list, mem_log_item); } -void +static void oc_mem_trace_print_paces(void) { int cnt = 0; @@ -117,7 +117,7 @@ oc_mem_trace_print_paces(void) PRINT("=================================================================="); PRINT("=================\n"); - PRINT(" %2s %-22s %11s %5s %5s %5s %5s \n", "No.", "Func", + PRINT(" %2s %-22s %11s %9s %5s %5s %5s \n", "No.", "Func", "Address", "Size", "Req", "Cur", "Peak"); PRINT("------------------------------------------------------------------"); PRINT("-----------------\n"); diff --git a/util/oc_mmem.c b/util/oc_mmem.c index 7389310fcc..826b76ff38 100644 --- a/util/oc_mmem.c +++ b/util/oc_mmem.c @@ -82,7 +82,7 @@ _oc_mmem_alloc( #ifdef OC_DYNAMIC_ALLOCATION m->ptr = malloc(size); m->size = size; -#else /* OC_DYNAMIC_ALLOCATION */ +#else /* !OC_DYNAMIC_ALLOCATION */ if (avail_bytes < size) { OC_WRN("byte pool exhausted"); return 0; @@ -91,7 +91,7 @@ _oc_mmem_alloc( m->ptr = &bytes[OC_BYTES_POOL_SIZE - avail_bytes]; m->size = size; avail_bytes -= size; -#endif /* !OC_DYNAMIC_ALLOCATION */ +#endif /* OC_DYNAMIC_ALLOCATION */ break; case INT_POOL: bytes_allocated += size * sizeof(int64_t);