diff --git a/.github/workflows/cmake-linux.yml b/.github/workflows/cmake-linux.yml index a86a39137e..13299473fc 100644 --- a/.github/workflows/cmake-linux.yml +++ b/.github/workflows/cmake-linux.yml @@ -34,7 +34,7 @@ jobs: fail-fast: false matrix: include: - # default (secure on, pki on, dynamic allocation on, tcp off, oscore on, cloud off, maintenance resource off, software update off, well-known core resource off) + # default (secure on, pki on, dynamic allocation on, tcp off, oscore on, cloud off, maintenance resource on, software update on, well-known core resource on, push notifications on, plgd-time on) - args: "" # ipv4 on - args: "-DOC_IPV4_ENABLED=ON" @@ -49,11 +49,11 @@ jobs: # ipv4 on, tcp on, pki off - args: "-DOC_IPV4_ENABLED=ON -DOC_TCP_ENABLED=ON -DOC_PKI_ENABLED=OFF" # cloud on (ipv4+tcp on), collections create on, maintenance resource on - - args: "-DOC_CLOUD_ENABLED=ON -DOC_COLLECTIONS_IF_CREATE_ENABLED=ON -DOC_MNT_ENABLED=ON" - # debug on, cloud on (ipv4+tcp on), software update on - - args: "-DOC_DEBUG_ENABLED=ON -DOC_CLOUD_ENABLED=ON -DOC_SOFTWARE_UPDATE_ENABLED=ON" + - args: "-DOC_CLOUD_ENABLED=ON -DOC_COLLECTIONS_IF_CREATE_ENABLED=ON " # debug on, well-known core resource on - - args: "-DOC_DEBUG_ENABLED=ON -DOC_WKCORE_ENABLED=ON" + - args: "-DOC_DEBUG_ENABLED=ON" + # debug on, cloud on (ipv4+tcp on) + - args: "-DOC_CLOUD_ENABLED=ON -DOC_DEBUG_ENABLED=ON " # secure off, ipv4 on - args: "-DOC_SECURITY_ENABLED=OFF -DOC_IPV4_ENABLED=ON" # secure off, tcp on @@ -61,12 +61,12 @@ jobs: # secure off, ipv4 on, tcp on - args: "-DOC_SECURITY_ENABLED=OFF -DOC_TCP_ENABLED=ON -DOC_IPV4_ENABLED=ON" # collection create if on, push notification on - - args: "-DOC_COLLECTIONS_IF_CREATE_ENABLED=ON -DOC_PUSH_ENABLED=ON" - # everything off (dynamic allocation off, secure off, pki off, idd off, oscore off) - - args: "-DOC_DYNAMIC_ALLOCATION_ENABLED=OFF -DOC_SECURITY_ENABLED=OFF -DOC_PKI_ENABLED=OFF -DOC_IDD_API_ENABLED=OFF -DOC_OSCORE_ENABLED=OFF" + - args: "-DOC_COLLECTIONS_IF_CREATE_ENABLED=ON" + # everything off (dynamic allocation off, secure off, pki off, idd off, oscore off, well-known core resource off, software update off, push notifications off, plgd-time off) + - args: "-DOC_DYNAMIC_ALLOCATION_ENABLED=OFF -DOC_SECURITY_ENABLED=OFF -DOC_PKI_ENABLED=OFF -DOC_IDD_API_ENABLED=OFF -DOC_OSCORE_ENABLED=OFF -DOC_WKCORE_ENABLED=OFF -DOC_SOFTWARE_UPDATE_ENABLED=OFF -DOC_MNT_ENABLED=OFF -DOC_PUSH_ENABLED=OFF -DPLGD_DEV_TIME_ENABLED=OFF" uses: ./.github/workflows/unit-test-with-cfg.yml with: - build_args: ${{ matrix.args }} + build_args: -DOC_WKCORE_ENABLED=ON -DOC_SOFTWARE_UPDATE_ENABLED=ON -DOC_MNT_ENABLED=ON -DOC_PUSH_ENABLED=ON -DPLGD_DEV_TIME_ENABLED=ON ${{ matrix.args }} build_type: Debug clang: ${{ github.event_name == 'workflow_dispatch' && inputs.clang }} coverage: false @@ -76,8 +76,8 @@ jobs: cmake_linux_preinstalled: uses: ./.github/workflows/unit-test-with-cfg.yml with: - # cloud on (ipv4+tcp on), collections create on, maintenance resource on, well-known core resource on, software update on, push notification on - build_args: -DOC_CLOUD_ENABLED=ON -DOC_COLLECTIONS_IF_CREATE_ENABLED=ON -DOC_MNT_ENABLED=ON -DOC_WKCORE_ENABLED=ON -DOC_SOFTWARE_UPDATE_ENABLED=ON -DOC_PUSH_ENABLED=ON + # cloud on (ipv4+tcp on), collections create on, maintenance resource on, well-known core resource on, software update on, push notification on, plgd-time on + build_args: -DOC_CLOUD_ENABLED=ON -DOC_COLLECTIONS_IF_CREATE_ENABLED=ON -DOC_MNT_ENABLED=ON -DOC_WKCORE_ENABLED=ON -DOC_SOFTWARE_UPDATE_ENABLED=ON -DOC_PUSH_ENABLED=ON -DPLGD_DEV_TIME_ENABLED=ON build_type: Debug clang: ${{ github.event_name == 'workflow_dispatch' && inputs.clang }} coverage: false @@ -101,7 +101,7 @@ jobs: # - args: -DOC_MSAN_ENABLED=ON uses: ./.github/workflows/unit-test-with-cfg.yml with: - build_args: -DOC_CLOUD_ENABLED=ON -DOC_COLLECTIONS_IF_CREATE_ENABLED=ON -DOC_MNT_ENABLED=ON -DOC_WKCORE_ENABLED=ON -DOC_SOFTWARE_UPDATE_ENABLED=ON -DOC_PUSH_ENABLED=ON -DOC_RESOURCE_ACCESS_IN_RFOTM_ENABLED=ON ${{ matrix.args }} + build_args: -DOC_CLOUD_ENABLED=ON -DOC_COLLECTIONS_IF_CREATE_ENABLED=ON -DOC_MNT_ENABLED=ON -DOC_WKCORE_ENABLED=ON -DOC_SOFTWARE_UPDATE_ENABLED=ON -DOC_PUSH_ENABLED=ON -DOC_RESOURCE_ACCESS_IN_RFOTM_ENABLED=ON -DPLGD_DEV_TIME_ENABLED=ON ${{ matrix.args }} build_type: Debug clang: ${{ github.event_name == 'workflow_dispatch' && inputs.clang }} coverage: false diff --git a/api/cloud/unittest/cloud_access_test.cpp b/api/cloud/unittest/cloud_access_test.cpp index 558740b1b3..f6006c7382 100644 --- a/api/cloud/unittest/cloud_access_test.cpp +++ b/api/cloud/unittest/cloud_access_test.cpp @@ -19,12 +19,13 @@ #ifndef OC_SECURITY -#include - #include "oc_api.h" #include "oc_cloud_access.h" #include "oc_cloud_internal.h" #include "oc_endpoint.h" +#include "tests/gtest/Endpoint.h" + +#include class TestCloudAccess : public testing::Test { public: @@ -57,10 +58,7 @@ class TestCloudAccess : public testing::Test { int ret = oc_main_init(&s_handler); ASSERT_EQ(0, ret); - oc_string_t ep_str; - oc_new_string(&ep_str, "coap://224.0.1.187:5683", 23); - oc_string_to_endpoint(&ep_str, &s_endpoint, nullptr); - oc_free_string(&ep_str); + s_endpoint = oc::endpoint::FromString("coap://224.0.1.187:5683"); } static void TearDownTestCase() { oc_main_shutdown(); } diff --git a/api/cloud/unittest/rd_client_test.cpp b/api/cloud/unittest/rd_client_test.cpp index 487df38167..b9822dd10c 100644 --- a/api/cloud/unittest/rd_client_test.cpp +++ b/api/cloud/unittest/rd_client_test.cpp @@ -17,11 +17,12 @@ * ******************************************************************/ -#include - #include "oc_api.h" #include "oc_endpoint.h" #include "rd_client.h" +#include "tests/gtest/Endpoint.h" + +#include class TestRDClient : public testing::Test { public: @@ -54,10 +55,7 @@ class TestRDClient : public testing::Test { int ret = oc_main_init(&s_handler); ASSERT_EQ(0, ret); - oc_string_t ep_str; - oc_new_string(&ep_str, "coap://224.0.1.187:5683", 23); - oc_string_to_endpoint(&ep_str, &s_endpoint, nullptr); - oc_free_string(&ep_str); + s_endpoint = oc::endpoint::FromString("coap://224.0.1.187:5683"); } static void TearDownTestCase() { oc_main_shutdown(); } diff --git a/api/oc_endpoint.c b/api/oc_endpoint.c index d10a95822d..183c9ca304 100644 --- a/api/oc_endpoint.c +++ b/api/oc_endpoint.c @@ -17,23 +17,16 @@ ****************************************************************************/ #include "oc_endpoint.h" +#include "oc_endpoint_internal.h" #include "oc_core_res.h" #include "port/oc_connectivity.h" #include "port/oc_network_event_handler_internal.h" +#include "util/oc_macros.h" #include "util/oc_memb.h" #include #include #include -#define OC_SCHEME_COAP "coap://" -#define OC_SCHEME_COAP_LEN (sizeof(OC_SCHEME_COAP) - 1) -#define OC_SCHEME_COAPS "coaps://" -#define OC_SCHEME_COAPS_LEN (sizeof(OC_SCHEME_COAPS) - 1) -#define OC_SCHEME_COAP_TCP "coap+tcp://" -#define OC_SCHEME_COAP_TCP_LEN (sizeof(OC_SCHEME_COAP_TCP) - 1) -#define OC_SCHEME_COAPS_TCP "coaps+tcp://" -#define OC_SCHEME_COAPS_TCP_LEN (sizeof(OC_SCHEME_COAPS_TCP) - 1) - #define OC_IPV6_ADDRSTRLEN (46) #define OC_IPV4_ADDRSTRLEN (16) #define OC_IPV6_ADDRLEN (16) @@ -68,8 +61,8 @@ oc_endpoint_set_di(oc_endpoint_t *endpoint, const oc_uuid_t *di) memcpy(endpoint->di.id, di->id, sizeof(di->id)); } -static const char * -oc_endpoint_flags_to_scheme(transport_flags flags) +const char * +oc_endpoint_flags_to_scheme(unsigned flags) { #ifdef OC_TCP if ((flags & TCP) != 0) { @@ -374,21 +367,23 @@ 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); #ifdef OC_TCP - if (ep_len > OC_SCHEME_COAPS_TCP_LEN && - memcmp(OC_SCHEME_COAPS_TCP, ep, OC_SCHEME_COAPS_TCP_LEN) == 0) { + if (ep_len > OC_CHAR_ARRAY_LEN(OC_SCHEME_COAPS_TCP) && + memcmp(OC_SCHEME_COAPS_TCP, ep, OC_CHAR_ARRAY_LEN(OC_SCHEME_COAPS_TCP)) == + 0) { return TCP | SECURED; } - if (ep_len > OC_SCHEME_COAP_TCP_LEN && - memcmp(OC_SCHEME_COAP_TCP, ep, OC_SCHEME_COAP_TCP_LEN) == 0) { + if (ep_len > OC_CHAR_ARRAY_LEN(OC_SCHEME_COAP_TCP) && + memcmp(OC_SCHEME_COAP_TCP, ep, OC_CHAR_ARRAY_LEN(OC_SCHEME_COAP_TCP)) == + 0) { return TCP; } #endif /* OC_TCP */ - if (ep_len > OC_SCHEME_COAPS_LEN && - memcmp(OC_SCHEME_COAPS, ep, OC_SCHEME_COAPS_LEN) == 0) { + if (ep_len > OC_CHAR_ARRAY_LEN(OC_SCHEME_COAPS) && + memcmp(OC_SCHEME_COAPS, ep, OC_CHAR_ARRAY_LEN(OC_SCHEME_COAPS)) == 0) { return SECURED; } - if (ep_len > OC_SCHEME_COAP_LEN && - memcmp(OC_SCHEME_COAP, ep, OC_SCHEME_COAP_LEN) == 0) { + if (ep_len > OC_CHAR_ARRAY_LEN(OC_SCHEME_COAP) && + memcmp(OC_SCHEME_COAP, ep, OC_CHAR_ARRAY_LEN(OC_SCHEME_COAP)) == 0) { return 0; } return -1; @@ -410,17 +405,17 @@ parse_endpoint_uri(const oc_string_t *endpoint_str, switch (flags) { #ifdef OC_TCP case TCP | SECURED: - address = ep + OC_SCHEME_COAPS_TCP_LEN; + address = ep + OC_CHAR_ARRAY_LEN(OC_SCHEME_COAPS_TCP); break; case TCP: - address = ep + OC_SCHEME_COAP_TCP_LEN; + address = ep + OC_CHAR_ARRAY_LEN(OC_SCHEME_COAP_TCP); break; #endif /* OC_TCP */ case SECURED: - address = ep + OC_SCHEME_COAPS_LEN; + address = ep + OC_CHAR_ARRAY_LEN(OC_SCHEME_COAPS); break; case 0: - address = ep + OC_SCHEME_COAP_LEN; + address = ep + OC_CHAR_ARRAY_LEN(OC_SCHEME_COAP); break; default: OC_ERR("invalid endpoint(%s) uri scheme: %d", ep != NULL ? ep : "", flags); diff --git a/api/oc_endpoint_internal.h b/api/oc_endpoint_internal.h new file mode 100644 index 0000000000..9f0b0a9456 --- /dev/null +++ b/api/oc_endpoint_internal.h @@ -0,0 +1,38 @@ +/**************************************************************************** + * + * Copyright (c) 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. + * + ****************************************************************************/ + +#ifndef OC_ENDPOINT_INTERNAL_H +#define OC_ENDPOINT_INTERNAL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define OC_SCHEME_COAP "coap://" +#define OC_SCHEME_COAPS "coaps://" +#define OC_SCHEME_COAP_TCP "coap+tcp://" +#define OC_SCHEME_COAPS_TCP "coaps+tcp://" + +/** @brief Get scheme string for transport flags */ +const char *oc_endpoint_flags_to_scheme(unsigned flags); + +#ifdef __cplusplus +} +#endif + +#endif /* OC_ENDPOINT_INTERNAL_H */ diff --git a/api/oc_ri.c b/api/oc_ri.c index eb65fbd647..cd3ac496d7 100644 --- a/api/oc_ri.c +++ b/api/oc_ri.c @@ -74,6 +74,7 @@ #include "api/oc_session_events_internal.h" #endif /* OC_TCP */ +#include #include #include #include @@ -680,6 +681,17 @@ oc_ri_has_timed_event_callback(const void *cb_data, oc_trigger_t event_callback, return false; } +bool +oc_timed_event_callback_is_currently_processed(const void *cb_data, + oc_trigger_t event_callback) +{ + if (g_currently_processed_event_cb == NULL) { + return false; + } + return g_currently_processed_event_cb->callback == event_callback && + g_currently_processed_event_cb->data == cb_data; +} + void oc_ri_remove_timed_event_callback_by_filter( oc_trigger_t cb, oc_ri_timed_event_filter_t filter, const void *filter_data, @@ -1611,7 +1623,15 @@ free_client_cb(oc_client_cb_t *cb) if (!cb) { return; } - oc_list_remove(g_client_cbs, cb); + // assert that we don't leave a dangling pointer + assert(!oc_ri_is_client_cb_valid(cb)); + assert(oc_timed_event_callback_is_currently_processed( + cb, oc_ri_remove_client_cb) || + !oc_ri_has_timed_event_callback(cb, oc_ri_remove_client_cb, false)); + assert(oc_timed_event_callback_is_currently_processed( + cb, oc_ri_remove_client_cb_with_notify_timeout_async) || + !oc_ri_has_timed_event_callback( + cb, oc_ri_remove_client_cb_with_notify_timeout_async, false)); #ifdef OC_BLOCK_WISE oc_blockwise_scrub_buffers_for_client_cb(cb); #endif /* OC_BLOCK_WISE */ @@ -1620,24 +1640,39 @@ free_client_cb(oc_client_cb_t *cb) oc_memb_free(&g_client_cbs_s, cb); } +static void +ri_remove_client_cb_from_lists(oc_client_cb_t *cb) +{ + oc_ri_remove_timed_event_callback(cb, &oc_ri_remove_client_cb); + oc_ri_remove_timed_event_callback( + cb, &oc_ri_remove_client_cb_with_notify_timeout_async); + oc_list_remove(g_client_cbs, cb); +} + oc_event_callback_retval_t oc_ri_remove_client_cb(void *data) { - oc_ri_remove_timed_event_callback( - data, &oc_ri_remove_client_cb_with_notify_timeout_async); + oc_client_cb_t *cb = (oc_client_cb_t *)data; + ri_remove_client_cb_from_lists(cb); free_client_cb(data); return OC_EVENT_DONE; } +bool +oc_ri_client_cb_terminated(oc_status_t code) +{ + return code == OC_PING_TIMEOUT || code == OC_REQUEST_TIMEOUT || + code == OC_CONNECTION_CLOSED || code == OC_TRANSACTION_TIMEOUT || + code == OC_CANCELLED; +} + static void notify_client_cb_with_code(oc_client_cb_t *cb, oc_status_t code) { OC_DBG("notify_client_cb_with_code - calling handler with request timeout " "for %d %s", cb->method, oc_string(cb->uri)); - oc_ri_remove_timed_event_callback(cb, &oc_ri_remove_client_cb); - oc_ri_remove_timed_event_callback( - cb, &oc_ri_remove_client_cb_with_notify_timeout_async); + ri_remove_client_cb_from_lists(cb); oc_client_response_t client_response; memset(&client_response, 0, sizeof(oc_client_response_t)); @@ -1826,9 +1861,7 @@ oc_ri_client_cb_set_observe_seq(oc_client_cb_t *cb, int observe_seq, oc_endpoint_compare(&dup_cb->endpoint, endpoint) == 0) { OC_DBG("Freeing cb %s, token 0x%02X%02X", uri, dup_cb->token[0], dup_cb->token[1]); - oc_ri_remove_timed_event_callback(dup_cb, &oc_ri_remove_client_cb); - oc_ri_remove_timed_event_callback( - dup_cb, &oc_ri_remove_client_cb_with_notify_timeout_async); + ri_remove_client_cb_from_lists(dup_cb); free_client_cb(dup_cb); break; } @@ -1957,9 +1990,7 @@ oc_ri_invoke_client_cb(void *response, oc_client_cb_t *cb, oc_ri_free_client_cbs_by_mid_v1(mid, OC_CANCELLED); } } else { - oc_ri_remove_timed_event_callback(cb, &oc_ri_remove_client_cb); - oc_ri_remove_timed_event_callback( - cb, &oc_ri_remove_client_cb_with_notify_timeout_async); + ri_remove_client_cb_from_lists(cb); free_client_cb(cb); } #ifdef OC_BLOCK_WISE diff --git a/api/oc_ri_internal.h b/api/oc_ri_internal.h index 8267b8488b..01ee23f4b0 100644 --- a/api/oc_ri_internal.h +++ b/api/oc_ri_internal.h @@ -23,6 +23,9 @@ #include "oc_endpoint.h" #include "oc_ri.h" +#include +#include + #ifdef __cplusplus extern "C" { #endif @@ -54,6 +57,11 @@ extern "C" { #define OC_BASELINE_PROP_TAG_POS_DESC "tag-pos-desc" #define OC_BASELINE_PROP_FUNC_DESC "tag-func-desc" +/** Check if the code is one of the internal terminating code while + * automatically deallocate the client_cb via the notify_client_cb_with_code + * mechanism */ +bool oc_ri_client_cb_terminated(oc_status_t code); + /** * @brief removes the client callback. This is silent remove client without * trigger 'cb.handler'. @@ -73,6 +81,11 @@ oc_event_callback_retval_t oc_ri_remove_client_cb(void *cb); oc_event_callback_retval_t oc_ri_remove_client_cb_with_notify_timeout_async( void *cb); +/** @brief The callback and data pair is currently being processed by + * poll_event_callback_timers */ +bool oc_timed_event_callback_is_currently_processed( + const void *cb_data, oc_trigger_t event_callback); + #ifdef OC_BLOCK_WISE extern bool oc_ri_invoke_coap_entity_handler( void *request, void *response, oc_blockwise_state_t **request_state, diff --git a/api/plgd/plgd_time.c b/api/plgd/plgd_time.c index cb7934d327..418e887d4c 100644 --- a/api/plgd/plgd_time.c +++ b/api/plgd/plgd_time.c @@ -21,6 +21,7 @@ #ifdef OC_HAS_FEATURE_PLGD_TIME #include "plgd_time_internal.h" +#include "api/oc_buffer_internal.h" #include "api/oc_core_res_internal.h" #include "api/oc_rep_internal.h" #include "api/oc_resource_internal.h" @@ -34,17 +35,54 @@ #include "port/oc_log.h" #include "util/oc_compiler.h" #include "util/oc_macros.h" +#include "util/oc_memb.h" #ifdef OC_SECURITY #include "security/oc_pstat.h" #include "security/oc_security_internal.h" +#include "security/oc_tls_internal.h" #endif /* OC_SECURITY */ +#include #include #include #include #include +#ifdef OC_SECURITY +#include +#endif /* OC_SECURITY */ + +#ifdef OC_CLIENT + +typedef struct time_fetch_param_t +{ + plgd_time_on_fetch_fn_t on_fetch; + void *on_fetch_data; +#if defined(OC_TCP) || defined(OC_SECURITY) + bool close_peer_after_fetch; +#endif +} time_fetch_param_t; + +OC_MEMB(g_fetch_params_s, time_fetch_param_t, OC_MAX_NUM_DEVICES); + +static uint16_t PLGD_TIME_FETCH_TIMEOUT = 4; + +#if defined(OC_SECURITY) && defined(OC_PKI) + +typedef struct time_verify_certificate_params_t +{ + oc_pki_verify_certificate_cb_t verify_certificate; + oc_tls_peer_user_data_t peer_data; +} time_verify_certificate_params_t; + +OC_MEMB(g_time_verify_certificate_params_s, time_verify_certificate_params_t, + OC_MAX_NUM_DEVICES); + +#endif /* OC_SECURITY && OC_PKI */ + +#endif /* OC_CLIENT */ + static plgd_time_t g_oc_plgd_time = { 0 }; plgd_time_t * @@ -63,7 +101,7 @@ dev_set_system_time(void) OC_ERR("failed to set system time: error(%d)", ret); return; } - OC_DBG("system time set to: %ld", (long)pt); + OC_DBG("plgd-time: system time set to %ld", (long)pt); } void @@ -99,14 +137,14 @@ static int dev_time_set_time(oc_clock_time_t lst, bool dump, bool notify) { if (lst == 0) { - OC_DBG("plgd time reset"); + OC_DBG("plgd-time reset"); plgd_time_set(0, 0, dump, notify); return 0; } oc_clock_time_t updateTime = oc_clock_time_monotonic(); if (updateTime == (oc_clock_time_t)-1) { - OC_ERR("cannot set plgd time: cannot obtain system uptime"); + OC_ERR("cannot set plgd-time: cannot obtain system uptime"); return -1; } @@ -114,7 +152,7 @@ dev_time_set_time(oc_clock_time_t lst, bool dump, bool notify) char lst_ts[64] = { 0 }; oc_clock_encode_time_rfc3339(lst, lst_ts, sizeof(lst_ts)); uint64_t ut_s = (uint64_t)(updateTime / (double)OC_CLOCK_SECOND); - OC_DBG("plgd time: %s (update: %" PRIu64 ")", lst_ts, ut_s); + OC_DBG("plgd-time: %s (update: %" PRIu64 ")", lst_ts, ut_s); #endif /* OC_DEBUG */ plgd_time_set(lst, updateTime, dump, notify); @@ -149,13 +187,13 @@ static oc_clock_time_t dev_plgd_time(plgd_time_t pt) { if (!dev_time_is_active(pt)) { - OC_ERR("cannot get plgd time: not active"); + OC_ERR("cannot get plgd-time: not active"); return -1; } oc_clock_time_t cur = oc_clock_time_monotonic(); if (cur == (oc_clock_time_t)-1) { - OC_ERR("cannot get plgd time: cannot obtain system uptime"); + OC_ERR("cannot get plgd-time: cannot obtain system uptime"); return -1; } @@ -171,7 +209,7 @@ dev_plgd_time(plgd_time_t pt) char ts[64] = { 0 }; oc_clock_encode_time_rfc3339(time, ts, sizeof(ts)); long diff = (time - ptime) / OC_CLOCK_SECOND; - OC_DBG("calculated plgd time: %s, system time: %s, diff: %lds", pt_ts, ts, + OC_DBG("calculated plgd-time: %s, system time: %s, diff: %lds", pt_ts, ts, diff); #endif /* OC_DEBUG */ return ptime; @@ -194,7 +232,7 @@ plgd_time_set_status(plgd_time_status_t status) { #ifdef OC_DEBUG const char *status_str = plgd_time_status_to_str(status); - OC_DBG("plgd time status: %s", status_str != NULL ? status_str : "NULL"); + OC_DBG("plgd-time status: %s", status_str != NULL ? status_str : "NULL"); #endif /* OC_DEBUG */ g_oc_plgd_time.status = status; } @@ -294,7 +332,7 @@ dev_time_encode_property_time(plgd_time_t pt, int flags) { #ifdef OC_SECURITY if (!dev_time_property_is_accessible(PLGD_TIME_PROP_TIME, flags)) { - OC_DBG("cannot access property(%s)", PLGD_TIME_PROP_TIME); + OC_DBG("plgd-time: cannot access property(%s)", PLGD_TIME_PROP_TIME); return 0; } #else /* !OC_SECURITY */ @@ -305,7 +343,7 @@ dev_time_encode_property_time(plgd_time_t pt, int flags) oc_clock_time_t ct = dev_plgd_time(pt); if (ct == (oc_clock_time_t)-1 || oc_clock_encode_time_rfc3339(ct, time, sizeof(time)) == 0) { - OC_ERR("cannot encode plgd time: cannot encode time in rfc3339 format"); + OC_ERR("cannot encode plgd-time: cannot encode time in rfc3339 format"); return -1; } } @@ -318,7 +356,7 @@ dev_time_encode_property_status(plgd_time_t pt, int flags) { #ifdef OC_SECURITY if (!dev_time_property_is_accessible(PLGD_TIME_PROP_STATUS, flags)) { - OC_DBG("cannot access property(%s)", PLGD_TIME_PROP_STATUS); + OC_DBG("plgd-time: cannot access property(%s)", PLGD_TIME_PROP_STATUS); return; } #else /* !OC_SECURITY */ @@ -339,7 +377,8 @@ dev_time_encode_property_last_synced_time(plgd_time_t pt, int flags) if ((flags & PLGD_TIME_ENCODE_FLAG_TO_STORAGE) == 0 && !dev_time_property_is_accessible(PLGD_TIME_PROP_LAST_SYNCED_TIME, flags)) { - OC_DBG("cannot access property(%s)", PLGD_TIME_PROP_LAST_SYNCED_TIME); + OC_DBG("plgd-time: cannot access property(%s)", + PLGD_TIME_PROP_LAST_SYNCED_TIME); return 0; } #else /* !OC_SECURITY */ @@ -350,7 +389,7 @@ dev_time_encode_property_last_synced_time(plgd_time_t pt, int flags) if (dev_time_is_active(pt) && (oc_clock_encode_time_rfc3339(pt.store.last_synced_time, lst, sizeof(lst)) == 0)) { - OC_ERR("cannot encode plgd time: cannot encode last_synced_time"); + OC_ERR("cannot encode plgd-time: cannot encode last_synced_time"); return -1; } oc_rep_set_text_string(root, lastSyncedTime, lst); @@ -361,7 +400,7 @@ int plgd_time_encode(plgd_time_t pt, oc_interface_mask_t iface_mask, int flags) { if ((iface_mask & PLGD_TIME_IF_MASK) != iface_mask) { - OC_ERR("cannot encode plgd time: invalid interface(%d)", (int)iface_mask); + OC_ERR("cannot encode plgd-time: invalid interface(%d)", (int)iface_mask); return -1; } @@ -408,12 +447,12 @@ plgd_time_decode(const oc_rep_t *rep, plgd_time_t *pt) lst_rfc3339 = &rep->value.string; continue; } - OC_WRN("plgd time: unknown property (%s:%d)", oc_string(rep->name), + OC_WRN("plgd-time: unknown property (%s:%d)", oc_string(rep->name), (int)rep->type); } if (lst_rfc3339 == NULL) { - OC_ERR("cannot decode plgd time: property %s not found", + OC_ERR("cannot decode plgd-time: property %s not found", PLGD_TIME_PROP_LAST_SYNCED_TIME); return false; } @@ -441,7 +480,7 @@ plgd_time_dump(void) long ret = oc_storage_save_resource(PLGD_TIME_STORE_NAME, /*device*/ 0, store_encode_plgd_time, &g_oc_plgd_time); if (ret <= 0) { - OC_ERR("cannot dump plgd time to storage: error(%ld)", ret); + OC_ERR("cannot dump plgd-time to storage: error(%ld)", ret); return false; } return true; @@ -453,7 +492,7 @@ store_decode_plgd_time(const oc_rep_t *rep, size_t device, void *data) (void)device; plgd_time_t *pt = (plgd_time_t *)data; if (!plgd_time_decode(rep, pt)) { - OC_ERR("cannot load plgd time: cannot decode representation"); + OC_ERR("cannot load plgd-time: cannot decode representation"); return -1; } return 0; @@ -465,11 +504,11 @@ plgd_time_load(void) plgd_time_t pt = { 0 }; if (oc_storage_load_resource(PLGD_TIME_STORE_NAME, 0, store_decode_plgd_time, &pt) <= 0) { - OC_ERR("failed to load plgd time from storage"); + OC_ERR("failed to load plgd-time from storage"); return false; } - OC_DBG("plgd time loaded from storage"); + OC_DBG("plgd-time loaded from storage"); if (dev_time_set_time(pt.store.last_synced_time, false, false) != 0) { return false; } @@ -485,7 +524,7 @@ plgd_time_resource_post(oc_request_t *request, oc_interface_mask_t iface_mask, (void)data; plgd_time_t pt = { 0 }; if (!plgd_time_decode(request->request_payload, &pt)) { - OC_ERR("cannot decode data for plgd time resource"); + OC_ERR("cannot decode data for plgd-time resource"); oc_send_response(request, OC_STATUS_BAD_REQUEST); return; } @@ -498,7 +537,7 @@ plgd_time_resource_post(oc_request_t *request, oc_interface_mask_t iface_mask, int flags = PLGD_TIME_ENCODE_FLAG_SECURE; // post is protected by acls, so we // must have secure access if (plgd_time_encode(g_oc_plgd_time, OC_IF_RW, flags) != 0) { - OC_ERR("cannot encode plgd time resource"); + OC_ERR("cannot encode plgd-time resource"); oc_send_response(request, OC_STATUS_INTERNAL_SERVER_ERROR); return; } @@ -520,7 +559,7 @@ plgd_time_resource_get(oc_request_t *request, oc_interface_mask_t iface_mask, } #endif /* OC_SECURITY */ if (plgd_time_encode(g_oc_plgd_time, iface_mask, flags) != 0) { - OC_ERR("cannot encode plgd time resource"); + OC_ERR("cannot encode plgd-time resource"); oc_send_response(request, OC_STATUS_INTERNAL_SERVER_ERROR); return; } @@ -531,7 +570,7 @@ plgd_time_resource_get(oc_request_t *request, oc_interface_mask_t iface_mask, void plgd_time_create_resource(void) { - OC_DBG("plgd time: create resource"); + OC_DBG("plgd-time: create resource"); oc_core_populate_resource(PLGD_TIME, /*device*/ 0, PLGD_TIME_URI, PLGD_TIME_IF_MASK, PLGD_TIME_DEFAULT_IF, OC_DISCOVERABLE | OC_OBSERVABLE, @@ -545,7 +584,7 @@ plgd_time_configure(bool use_in_mbedtls, plgd_set_system_time_fn_t set_system_time, void *set_system_time_data) { - OC_DBG("plgd time: initialize feature"); + OC_DBG("plgd-time: initialize feature"); #ifdef OC_SECURITY if (use_in_mbedtls) { oc_mbedtls_platform_time_init(); @@ -560,4 +599,254 @@ plgd_time_configure(bool use_in_mbedtls, g_oc_plgd_time.set_system_time_data = set_system_time_data; } +#ifdef OC_CLIENT + +plgd_time_fetch_config_t +plgd_time_fetch_config(const oc_endpoint_t *endpoint, const char *uri, + plgd_time_on_fetch_fn_t on_fetch, void *on_fetch_data, + uint16_t timeout, int selected_identity_credid, + bool disable_time_verification) +{ + plgd_time_fetch_config_t fetch = { + .endpoint = endpoint, + .uri = uri, + .on_fetch = on_fetch, + .on_fetch_data = on_fetch_data, + .timeout = timeout, + }; + +#if defined(OC_SECURITY) && defined(OC_PKI) + fetch.selected_identity_credid = selected_identity_credid; + fetch.disable_time_verification = disable_time_verification; +#else /* !OC_SECURITY || !OC_PKI */ + (void)selected_identity_credid; + (void)disable_time_verification; +#endif /* OC_SECURITY && OC_PKI */ + + return fetch; +} + +static bool +dev_time_parse_fetch_response(const oc_rep_t *rep, oc_clock_time_t *time) +{ + assert(clock != NULL); + + const char *time_str = NULL; + size_t time_str_len = 0; + if (!oc_rep_get_string(rep, "time", (char **)&time_str, &time_str_len)) { + OC_ERR("fetch plgd-time failed: cannot find time property"); + return false; + } + + oc_clock_time_t ct = oc_clock_parse_time_rfc3339(time_str, time_str_len); + if (ct == (oc_clock_time_t)-1) { + OC_ERR("fetch plgd-time failed: parse clock time from string(%s)", + time_str); + return false; + } + + *time = ct; + return true; +} + +static void +dev_time_on_fetch(oc_client_response_t *data) +{ + time_fetch_param_t *fp = (time_fetch_param_t *)data->user_data; + oc_clock_time_t time = 0; + oc_status_t code = data->code; + if (code == OC_STATUS_OK && + !dev_time_parse_fetch_response(data->payload, &time)) { + code = OC_STATUS_INTERNAL_SERVER_ERROR; + } + + OC_DBG("plgd-time: on_fetch time=%d time=%u", (int)code, (unsigned)time); + fp->on_fetch(code, time, fp->on_fetch_data); +#if defined(OC_TCP) || defined(OC_SECURITY) + // session is closed automatically on timeout, close or cancel + if (fp->close_peer_after_fetch && oc_ri_client_cb_terminated(code)) { + OC_DBG("plgd-time: close fetch time session"); + oc_close_session(data->endpoint); + } +#endif /* OC_TCP || OC_SECURITY */ + + oc_memb_free(&g_fetch_params_s, fp); +} + +#if defined(OC_SECURITY) && defined(OC_PKI) + +static void +time_verify_certificate_params_free(void *data) +{ + if (data == NULL) { + return; + } + time_verify_certificate_params_t *vcp = + (time_verify_certificate_params_t *)data; + if (vcp->peer_data.free != NULL) { + vcp->peer_data.free(vcp->peer_data.data); + } + oc_memb_free(&g_time_verify_certificate_params_s, vcp); +} + +static int +dev_time_verify_certificate(oc_tls_peer_t *peer, const mbedtls_x509_crt *crt, + int depth, uint32_t *flags) +{ + OC_DBG("plgd-time: verifying certificate at depth %d, flags %u", depth, + *flags); + + time_verify_certificate_params_t *vcp = + (time_verify_certificate_params_t *)peer->user_data.data; + // set expected user data for verify_certificate + peer->user_data.data = vcp->peer_data.data; + peer->user_data.free = vcp->peer_data.free; + int ret = vcp->verify_certificate(peer, crt, depth, flags); + OC_DBG("plgd-time: default verification done (depth=%d, flags=%u)", depth, + *flags); + // restore overriden data for correct deallocation + peer->user_data.data = vcp; + peer->user_data.free = time_verify_certificate_params_free; + *flags &= + ~((uint32_t)(MBEDTLS_X509_BADCERT_EXPIRED | MBEDTLS_X509_BADCERT_FUTURE)); + OC_DBG("plgd-time: removed validity errors (flags=%u)", *flags); + + return ret; +} + +static bool +dev_time_add_peer(const oc_endpoint_t *ep, bool disable_time_verification) +{ + OC_DBG("plgd-time: add new peer"); + + time_verify_certificate_params_t *vcp = NULL; + if (disable_time_verification) { + vcp = (time_verify_certificate_params_t *)oc_memb_alloc( + &g_time_verify_certificate_params_s); + if (vcp == NULL) { + OC_ERR("plgd-time add peer failed: cannot allocate verify certificate " + "parameters"); + return false; + } + } + + oc_tls_peer_t *peer = oc_tls_add_peer(ep, MBEDTLS_SSL_IS_CLIENT); + if (peer == NULL) { + OC_ERR("plgd-time add peer failed: oc_tls_add_peer failed"); + oc_memb_free(&g_time_verify_certificate_params_s, vcp); + return false; + } + + if (vcp != NULL) { + OC_DBG("plgd-time: disable time verification for peer"); + vcp->verify_certificate = peer->verify_certificate; + vcp->peer_data.data = peer->user_data.data; + vcp->peer_data.free = peer->user_data.free; + peer->user_data.data = vcp; + peer->user_data.free = time_verify_certificate_params_free; + peer->verify_certificate = dev_time_verify_certificate; + } + + return true; +} + +#endif /* OC_SECURITY && OC_PKI */ + +#if defined(OC_TCP) || defined(OC_SECURITY) + +static bool +dev_time_has_session(const oc_endpoint_t *endpoint) +{ +#ifdef OC_SECURITY + if ((endpoint->flags & SECURED) != 0) { + const oc_tls_peer_t *peer = oc_tls_get_peer(endpoint); + OC_DBG("plgd-time: peer state=%d", peer != NULL ? peer->ssl_ctx.state : -1); + return peer != NULL; + } +#endif /* OC_SECURITY */ + +#ifdef OC_TCP + if ((endpoint->flags & TCP) != 0) { + int tcp = oc_tcp_connection_state(endpoint); + OC_DBG("plgd-time: session state=%d", tcp); + return tcp <= 0; + } +#endif /* OC_TCP */ + return false; +} + +#endif /* OC_SECURITY && OC_PKI */ + +bool +plgd_time_fetch(plgd_time_fetch_config_t fetch, unsigned *flags) +{ +#ifndef OC_TCP + (void)flags; +#endif /* !OC_TCP */ + assert(fetch.endpoint != NULL); + assert(fetch.uri != NULL); + + if (fetch.timeout == 0) { + fetch.timeout = PLGD_TIME_FETCH_TIMEOUT; + } + + time_fetch_param_t *fetch_params = + (time_fetch_param_t *)oc_memb_alloc(&g_fetch_params_s); + if (fetch_params == NULL) { + OC_ERR("cannot allocate fetch plgd-time parameters"); + return false; + } + +#if defined(OC_TCP) || defined(OC_SECURITY) + bool has_session = dev_time_has_session(fetch.endpoint); + OC_DBG("plgd-time: has_session=%d", (int)has_session); + + if (!has_session) { +#ifdef OC_TCP + if ((fetch.endpoint->flags & TCP) != 0 && flags != NULL) { + OC_DBG("plgd-time: append TCP_SESSION_OPENED to output flags"); + *flags |= PLGD_TIME_FETCH_FLAG_TCP_SESSION_OPENED; + } +#endif /* OC_TCP */ + + // no session was opened -> new one will be opened for fetching of time and + // closed when it is done + fetch_params->close_peer_after_fetch = true; + } +#endif /* OC_TCP || OC_SECURITY */ + +#if defined(OC_SECURITY) && defined(OC_PKI) + // dtls or tls -> if we don't have a connected peer already create a new one + // with disabled time verification on certificates + bool add_insecure_peer = + (fetch.endpoint->flags & SECURED) != 0 && !has_session; + if (add_insecure_peer) { + oc_tls_select_identity_cert_chain(fetch.selected_identity_credid); + + if (!dev_time_add_peer(fetch.endpoint, fetch.disable_time_verification)) { + oc_memb_free(&g_fetch_params_s, fetch_params); + return false; + } + } +#endif /* OC_SECURITY && OC_PKI */ + + fetch_params->on_fetch = fetch.on_fetch; + fetch_params->on_fetch_data = fetch.on_fetch_data; + + if (!oc_do_get_with_timeout(fetch.uri, fetch.endpoint, "", fetch.timeout, + dev_time_on_fetch, HIGH_QOS, fetch_params)) { + OC_ERR("failed to send fetch plgd-time request to endpoint"); +#if defined(OC_SECURITY) && defined(OC_PKI) + if (add_insecure_peer) { + oc_tls_remove_peer(fetch.endpoint); + } +#endif /* OC_SECURITY && OC_PKI */ + oc_memb_free(&g_fetch_params_s, fetch_params); + return false; + } + return true; +} + +#endif /* OC_CLIENT */ + #endif /* OC_HAS_FEATURE_PLGD_TIME */ diff --git a/api/unittest/eptest.cpp b/api/unittest/eptest.cpp index 0238bad55b..c0c546fc32 100644 --- a/api/unittest/eptest.cpp +++ b/api/unittest/eptest.cpp @@ -21,6 +21,7 @@ #include "oc_helpers.h" #include "oc_uuid.h" #include "port/oc_random.h" +#include "tests/gtest/Endpoint.h" #include #include @@ -52,32 +53,18 @@ class TestEndpoint : public testing::Test { #endif /* _WIN32 */ } - static int EndpointFromString(const std::string &addr, oc_endpoint_t *ep, - oc_string_t *uri) - { - oc_string_t s; - oc_new_string(&s, addr.c_str(), addr.length()); - int ret = oc_string_to_endpoint(&s, ep, uri); - oc_free_string(&s); - return ret; - } - static int EndpointCompareAddress(const std::string &addr1, const std::string &addr2) { - oc_endpoint_t ep1{}; - EXPECT_EQ(0, EndpointFromString(addr1, &ep1, nullptr)); - oc_endpoint_t ep2{}; - EXPECT_EQ(0, EndpointFromString(addr2, &ep2, nullptr)); + oc_endpoint_t ep1 = oc::endpoint::FromString(addr1); + oc_endpoint_t ep2 = oc::endpoint::FromString(addr2); return oc_endpoint_compare_address(&ep1, &ep2); } static int EndpointCompare(const std::string &addr1, const std::string &addr2) { - oc_endpoint_t ep1{}; - EXPECT_EQ(0, EndpointFromString(addr1, &ep1, nullptr)); - oc_endpoint_t ep2{}; - EXPECT_EQ(0, EndpointFromString(addr2, &ep2, nullptr)); + oc_endpoint_t ep1 = oc::endpoint::FromString(addr1); + oc_endpoint_t ep2 = oc::endpoint::FromString(addr2); return oc_endpoint_compare(&ep1, &ep2); } }; @@ -140,7 +127,7 @@ TEST_F(TestEndpoint, StringToEndpointIPv4) std::string spu0 = { "coaps://10.211.55.3:56789/a/light" }; oc_endpoint_t ep{}; oc_string_t uri{}; - int ret = EndpointFromString(spu0, &ep, &uri); + int ret = oc::endpoint::FromString(spu0, &ep, &uri); EXPECT_EQ(ret, 0) << "spu0 " << spu0; EXPECT_TRUE(ep.flags & IPV4); @@ -166,7 +153,7 @@ TEST_F(TestEndpoint, StringToEndpointTCP) for (size_t i = 0; i < spu2.size(); i++) { oc_endpoint_t ep{}; oc_string_t uri{}; - int ret = EndpointFromString(spu2[i], &ep, &uri); + int ret = oc::endpoint::FromString(spu2[i], &ep, &uri); EXPECT_EQ(ret, 0) << "spu2[" << i << "] " << spu2[i]; switch (i) { @@ -203,7 +190,7 @@ TEST_F(TestEndpoint, StringToEndpointTCP) for (size_t i = 0; i < spu3.size(); i++) { oc_endpoint_t ep{}; oc_string_t uri{}; - int ret = EndpointFromString(spu3[i], &ep, &uri); + int ret = oc::endpoint::FromString(spu3[i], &ep, &uri); switch (i) { case 0: #if defined(OC_IPV4) || defined(OC_DNS_LOOKUP_IPV6) @@ -277,7 +264,7 @@ TEST_F(TestEndpoint, StringToEndpointTCP) }; for (size_t i = 0; i < spu4.size(); i++) { oc_endpoint_t ep{}; - int ret = EndpointFromString(spu4[i], &ep, nullptr); + int ret = oc::endpoint::FromString(spu4[i], &ep, nullptr); EXPECT_EQ(ret, 0) << "spu4[" << i << "] " << spu4[i]; } } @@ -293,7 +280,7 @@ TEST_F(TestEndpoint, DNSStringToEndpoint) for (size_t i = 0; i < spu1.size(); i++) { oc_endpoint_t ep{}; oc_string_t uri{}; - int ret = EndpointFromString(spu1[i], &ep, &uri); + int ret = oc::endpoint::FromString(spu1[i], &ep, &uri); #if defined(OC_IPV4) || defined(OC_DNS_LOOKUP_IPV6) EXPECT_EQ(ret, 0) << "spu1[" << i << "] " << spu1[i]; @@ -471,7 +458,7 @@ TEST_F(TestEndpoint, IsEmpty) EXPECT_TRUE(oc_endpoint_is_empty(&endpoint)); std::string ep_str = "coap://[ff02::158]"; - EXPECT_EQ(0, EndpointFromString(ep_str, &endpoint, nullptr)); + EXPECT_EQ(0, oc::endpoint::FromString(ep_str, &endpoint, nullptr)); EXPECT_FALSE(oc_endpoint_is_empty(&endpoint)); } @@ -492,7 +479,7 @@ TEST_F(TestEndpoint, IsIPv6LinkLocal) for (const auto &addr : addrs_nonLL) { oc_endpoint_t ep{}; - EXPECT_EQ(0, EndpointFromString(addr, &ep, nullptr)); + EXPECT_EQ(0, oc::endpoint::FromString(addr, &ep, nullptr)); EXPECT_EQ(-1, oc_ipv6_endpoint_is_link_local(&ep)); } @@ -504,7 +491,7 @@ TEST_F(TestEndpoint, IsIPv6LinkLocal) for (const auto &addr : addrs_LL) { oc_endpoint_t ep{}; - EXPECT_EQ(0, EndpointFromString(addr, &ep, nullptr)); + EXPECT_EQ(0, oc::endpoint::FromString(addr, &ep, nullptr)); EXPECT_EQ(0, oc_ipv6_endpoint_is_link_local(&ep)); } } @@ -569,9 +556,7 @@ TEST_F(TestEndpoint, ListCopy) oc_endpoint_t *eps_copy = nullptr; EXPECT_EQ(0, oc_endpoint_list_copy(&eps_copy, nullptr)); - oc_endpoint_t model; - EXPECT_EQ(0, EndpointFromString("coap://[ff02::158]", &model, nullptr)); - + oc_endpoint_t model = oc::endpoint::FromString("coap://[ff02::158]"); auto make_endpoint_list = [&model](size_t size) { oc_endpoint_t *head = nullptr; for (size_t i = 0; i < size; ++i) { diff --git a/api/unittest/plgdtimetest.cpp b/api/unittest/plgdtimetest.cpp index 7e088d353e..cab006777b 100644 --- a/api/unittest/plgdtimetest.cpp +++ b/api/unittest/plgdtimetest.cpp @@ -21,21 +21,25 @@ #ifdef OC_HAS_FEATURE_PLGD_TIME #include "api/oc_core_res_internal.h" +#include "api/oc_endpoint_internal.h" #include "api/oc_rep_internal.h" #include "api/oc_ri_internal.h" #include "api/plgd/plgd_time_internal.h" #include "oc_acl.h" #include "oc_core_res.h" +#include "oc_network_monitor.h" #include "oc_ri.h" #include "port/oc_network_event_handler_internal.h" #include "port/oc_storage.h" #include "port/oc_storage_internal.h" #include "tests/gtest/Device.h" +#include "tests/gtest/Endpoint.h" #include "tests/gtest/RepPool.h" #include "util/oc_macros.h" #ifdef OC_SECURITY #include "security/oc_security_internal.h" +#include "security/oc_pstat.h" #endif /* OC_SECURITY */ #ifdef OC_HAS_FEATURE_PUSH @@ -436,6 +440,8 @@ TEST_F(TestPlgdTimeWithServer, PostRequest) EXPECT_TRUE(oc_do_post()); oc::TestDevice::PoolEvents(5); + EXPECT_EQ(PLGD_TIME_STATUS_IN_SYNC, plgd_time_status()); + EXPECT_EQ(yesterday, pt.lst); EXPECT_EQ(plgd_time_status(), pt.status); @@ -496,6 +502,129 @@ TEST_F(TestPlgdTimeWithServer, PutRequestFail) #endif /* !OC_SECURITY || OC_HAS_FEATURE_RESOURCE_ACCESS_IN_RFOTM */ +#ifdef OC_CLIENT + +TEST_F(TestPlgdTimeWithServer, FetchTimeFail) +{ + unsigned flags = 0; +#ifdef OC_SECURITY + flags |= SECURED; +#endif /* OC_SECURITY */ +#ifdef OC_TCP + flags |= TCP; +#endif /* OC_TCP */ + + std::string ep_str = + std::string(oc_endpoint_flags_to_scheme(flags)) + "[ff02::158]:12345"; + oc_endpoint_t ep = oc::endpoint::FromString(ep_str); + + auto fetch_handler = [](oc_status_t code, oc_clock_time_t, void *data) { + OC_DBG("fetch time handler timeout"); + EXPECT_TRUE(oc_ri_client_cb_terminated(code)); + *(static_cast(data)) = true; + oc::TestDevice::Terminate(); + }; + +#ifdef OC_SECURITY + if ((ep.flags & SECURED) != 0) { + oc_sec_self_own(/*device*/ 0); + } +#endif /* OC_SECURITY */ + + bool invoked = false; + unsigned fetch_flags = 0; + EXPECT_TRUE(plgd_time_fetch( + plgd_time_fetch_config(&ep, PLGD_TIME_URI, fetch_handler, &invoked, + /*timeout*/ 5, /*selected_identity_credid*/ -1, + /*disable_time_verification*/ true), + &fetch_flags)); + + oc::TestDevice::PoolEvents(5); + EXPECT_TRUE(invoked); + +#ifdef OC_SECURITY + oc_pstat_reset_device(/*device*/ 0, true); +#endif /* OC_SECURITY */ +} + +TEST_F(TestPlgdTimeWithServer, FetchTimeConnectInsecure) +{ + unsigned flags = 0; +#ifdef OC_TCP + flags |= TCP; +#endif /* OC_TCP */ + const oc_endpoint_t *ep = + oc::TestDevice::GetEndpoint(/*device*/ 0, flags, SECURED); + ASSERT_NE(nullptr, ep); + + auto fetch_handler = [](oc_status_t code, oc_clock_time_t time, void *data) { + OC_DBG("fetch time handler"); + EXPECT_EQ(OC_STATUS_OK, code); + auto *t = static_cast(data); + *t = time; + oc::TestDevice::Terminate(); + }; + +#if defined(OC_TCP) && defined(OC_SESSION_EVENTS) + struct TCPSessionData + { + bool disconnected; + const oc_endpoint_t *ep; + }; + + auto tcp_events = [](const oc_endpoint_t *endpoint, oc_session_state_t state, + void *data) { +#ifdef OC_DEBUG + oc_string_t ep_str{}; + oc_endpoint_to_string(endpoint, &ep_str); + OC_DBG("session event endpoint=%s state=%d", oc_string(ep_str), (int)state); + oc_free_string(&ep_str); +#endif /* OC_DEBUG */ + auto *tsd = static_cast(data); + if ((oc_endpoint_compare(endpoint, tsd->ep) == 0) && + (state == OC_SESSION_DISCONNECTED)) { + tsd->disconnected = true; + oc::TestDevice::Terminate(); + } + }; + + TCPSessionData tsd{}; + tsd.ep = ep; + if ((ep->flags & TCP) != 0) { + EXPECT_EQ(0, oc_add_session_event_callback_v1(tcp_events, &tsd)); + } +#endif /* OC_TCP && OC_SESSION_EVENTS */ + + oc_clock_time_t time = 0; + unsigned fetch_flags = 0; + EXPECT_TRUE(plgd_time_fetch( + plgd_time_fetch_config(ep, PLGD_TIME_URI, fetch_handler, &time, + /*timeout*/ 5, /*selected_identity_credid*/ -1, + /*disable_time_verification*/ true), + &fetch_flags)); + + oc::TestDevice::PoolEvents(5); + EXPECT_NE(0, time); + +#if defined(OC_TCP) && defined(OC_SESSION_EVENTS) + if (!tsd.disconnected && + (fetch_flags & PLGD_TIME_FETCH_FLAG_TCP_SESSION_OPENED) != 0) { + oc::TestDevice::PoolEvents(5); + } + if ((ep->flags & TCP) != 0) { + EXPECT_EQ(0, + oc_remove_session_event_callback_v1(tcp_events, nullptr, true)); + } +#endif /* OC_TCP && OC_SESSION_EVENTS */ +} + +TEST_F(TestPlgdTimeWithServer, FetchTimeAlreadyConnected) +{ + // TODO: use already connected endpoint +} + +#endif /* OC_CLIENT */ + #ifdef OC_SECURITY class TestMbedTLSPlgdTime : public testing::Test { diff --git a/include/oc_pki.h b/include/oc_pki.h index f7d0da3094..3e26283cd6 100644 --- a/include/oc_pki.h +++ b/include/oc_pki.h @@ -35,8 +35,9 @@ extern "C" { #include #include "oc_sp.h" -#include "mbedtls/mbedtls_config.h" -#include "mbedtls/x509_crt.h" +#include +#include +#include /** * Add a PKI identity certificate. diff --git a/include/oc_session_events.h b/include/oc_session_events.h index 019b595ac9..e142b45705 100644 --- a/include/oc_session_events.h +++ b/include/oc_session_events.h @@ -27,7 +27,6 @@ #include "oc_export.h" #include "oc_endpoint.h" -#include "util/oc_compiler.h" #ifdef __cplusplus extern "C" { @@ -49,12 +48,11 @@ typedef enum { * @param endpoint endpoint info which the session event is happened. * @param state enum values in oc_session_state_t. * - * @deprecated replaced by session_event_handler_v1_t in v2.2.5.4 + * @note will be removed with deprecated functions oc_add_session_event_callback + * and oc_remove_session_event_callback in the future */ typedef void (*session_event_handler_t)(const oc_endpoint_t *endpoint, - oc_session_state_t state) - OC_DEPRECATED( - "replaced by session_event_handler_v1_t, deprecated in v2.2.5.4"); + oc_session_state_t state); /** * @brief Callback function to pass the session event infomation to App. diff --git a/include/plgd/plgd_time.h b/include/plgd/plgd_time.h index 01a2bfad1d..2cdcee4975 100644 --- a/include/plgd/plgd_time.h +++ b/include/plgd/plgd_time.h @@ -40,6 +40,9 @@ * @{ */ +#include "oc_endpoint.h" +#include "oc_export.h" +#include "oc_ri.h" #include "port/oc_clock.h" #include @@ -79,6 +82,7 @@ typedef int (*plgd_set_system_time_fn_t)(oc_clock_time_t time, void *user_data); * * @see plgd_time_set_time */ +OC_API void plgd_time_configure(bool use_in_mbedtls, plgd_set_system_time_fn_t set_system_time, void *set_system_time_data); @@ -91,6 +95,7 @@ void plgd_time_configure(bool use_in_mbedtls, * * @see plgd_time_set_time */ +OC_API bool plgd_time_is_active(void); /** @@ -106,9 +111,11 @@ bool plgd_time_is_active(void); * * @see plgd_time_set_time */ +OC_API oc_clock_time_t plgd_time(void); /** @brief Calculate the number of seconds since the Unix Epoch */ +OC_API unsigned long plgd_time_seconds(void); /** @@ -125,15 +132,19 @@ unsigned long plgd_time_seconds(void); * @note on successful call the plgd time status is set to * PLGD_TIME_STATUS_IN_SYNC */ +OC_API int plgd_time_set_time(oc_clock_time_t time); /** @brief Get the latest synchronization time */ +OC_API oc_clock_time_t plgd_time_last_synced_time(void); /** @brief Set plgd time status */ +OC_API void plgd_time_set_status(plgd_time_status_t status); /** @brief Get plgd time status */ +OC_API plgd_time_status_t plgd_time_status(void); /** @@ -145,6 +156,7 @@ plgd_time_status_t plgd_time_status(void); * @note on successful call the plgd time status is set to * PLGD_TIME_STATUS_IN_SYNC_FROM_STORAGE */ +OC_API bool plgd_time_load(void); /** @@ -153,8 +165,98 @@ bool plgd_time_load(void); * @return true on success * @return false on failure */ +OC_API bool plgd_time_dump(void); +#ifdef OC_CLIENT + +/** + * @brief Callback invoked when plgd_time_fetch request receives a response or + * timeouts. + * + * @param code response code of the time fetch request + * @param time time provided by the endpoint (only valid if \p code is + * OC_STATUS_OK) + * @param data custom user data + */ +typedef void (*plgd_time_on_fetch_fn_t)(oc_status_t code, oc_clock_time_t time, + void *data); + +typedef struct +{ + const oc_endpoint_t + *endpoint; ///< endpoint to fetch the time (cannot be NULL) + const char *uri; ///< uri of the resource (cannot be NULL) + plgd_time_on_fetch_fn_t on_fetch; ///< callback invoked when request finishes + ///< or timeouts (cannot be NULL) + void *on_fetch_data; ///< custom user data passed to the on_fetch callback + + uint16_t timeout; ///< timeout in seconds of the fetch time request (default + ///< value defined by PLGD_TIME_FETCH_TIMEOUT is used if + ///< value is 0) +#if defined(OC_SECURITY) && defined(OC_PKI) + int + selected_identity_credid; ///< identity certificate to use for a created + ///< TLS session (set to -1 to use any available) + bool disable_time_verification; ///< ignore time validity checks when creating + ///< a new TLS session for plgd-time fetch +#endif +} plgd_time_fetch_config_t; + +/** Convenience wrapper to create plgd_time_fetch_config_t from arguments */ +OC_API +plgd_time_fetch_config_t plgd_time_fetch_config( + const oc_endpoint_t *endpoint, const char *uri, + plgd_time_on_fetch_fn_t on_fetch, void *on_fetch_data, uint16_t timeout, + int selected_identity_credid, bool disable_time_verification); + +#ifdef OC_TCP +typedef enum { + PLGD_TIME_FETCH_FLAG_TCP_SESSION_OPENED = + 1 << 0, // TCP session was opened and scheduled to close by plgd_time_fetch +} plgd_time_fetch_flags_t; + +#endif /* OC_TCP */ + +/** + * @brief Fetch time from an endpoint by a GET request + * + * For TLS/DTLS/TCP communication the request will use an existing session or a + * peer. If there is no existing session or peer then it will attempt to create + * it and after the request is finished it will be closed. (If the session or + * peer existed before the fetch time request it won't be closed.) + * + * The closing of TCP sessions in iotivity-lite is asynchronous and is executed + * on the network thread. There are no guarantees about the timing. The session + * might've be already closed before plgd_time_fetch returns or it might be + * closed some time later. This might cause an issue if you try to create a TCP + * connection to the same endpoint right away after calling plgd_time_fetch. If + * the asynchronous closing of the previous session hasn't finished yet then it + * will close your session, because in the current implementation sessions are + * indexed by the endpoint address and not by some unique IDs. You can avoid + * this problem by checking for PLGD_TIME_FETCH_FLAG_TCP_SESSION_OPENED. The + * flag is appended to \p flags when plgd_time_fetch opens a new TCP session. + * (When a new session is opened by plgd_time_fetch it will always be scheduled + * to close before the function returns). To check if a session is closed use + * oc_tcp_connection_state. To wait for a session to close use + * oc_add_session_event_callback_v1, which will invoke a custom callback when + * a session is disconnected. + * + * @param fetch fetch time configuration + * @param[out] flags output flags + * @return true on success + * @return false on failure + * + * @see plgd_time_fetch_config_t + * @see plgd_time_fetch_flags_t + * @see oc_add_session_event_callback_v1 + * @see oc_tcp_connection_state + */ +OC_API +bool plgd_time_fetch(plgd_time_fetch_config_t fetch, unsigned *flags); + +#endif /* OC_CLIENT */ + #ifdef __cplusplus } #endif diff --git a/port/unittest/connectivitytest.cpp b/port/unittest/connectivitytest.cpp index efe7c0c2a9..e07ff8d078 100644 --- a/port/unittest/connectivitytest.cpp +++ b/port/unittest/connectivitytest.cpp @@ -29,6 +29,7 @@ #include "util/oc_atomic.h" #include "util/oc_features.h" #include "tests/gtest/Device.h" +#include "tests/gtest/Endpoint.h" #include #include @@ -320,7 +321,6 @@ class TestConnectivityWithServer : public testing::Test { 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; }; @@ -346,18 +346,6 @@ TestConnectivityWithServer::findEndpoint(size_t device) 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); @@ -424,8 +412,8 @@ TEST_F(TestConnectivityWithServer, oc_tcp_update_csm_state_N) #ifdef OC_HAS_FEATURE_TCP_ASYNC_CONNECT TEST_F(TestConnectivityWithServer, oc_tcp_connect_fail) { - oc_endpoint_t ep = - createEndpoint("coaps+tcp://[ff02::158]:12345"); // unreachable address + oc_endpoint_t ep = oc::endpoint::FromString( + "coaps+tcp://[ff02::158]:12345"); // unreachable address EXPECT_EQ(-1, oc_tcp_connect(&ep, nullptr, this)); } @@ -440,7 +428,7 @@ on_tcp_connect_timeout(const oc_endpoint_t *, int state, void *) TEST_F(TestConnectivityWithServer, oc_tcp_connect_timeout) { - oc_endpoint_t ep = createEndpoint( + oc_endpoint_t ep = oc::endpoint::FromString( "coaps+tcp://[::1]:12345"); // reachable address, but inactive port // enough retries so they will run the whole duration of this test oc_tcp_set_connect_retry(UINT8_MAX, 5); @@ -468,6 +456,7 @@ TEST_F(TestConnectivityWithServer, oc_tcp_connect_timeout) EXPECT_EQ(OC_SEND_MESSAGE_QUEUED, oc_send_buffer2(msg, true)); OC_DBG("oc_tcp_connect_timeout wait"); + oc_tcp_set_connect_retry(0, 2); oc::TestDevice::PoolEvents(2); EXPECT_EQ(-1, oc_tcp_connection_state(&ep)); @@ -492,7 +481,7 @@ TEST_F(TestConnectivityWithServer, oc_tcp_connect_repeat_fail) TEST_F(TestConnectivityWithServer, oc_tcp_connecting_repeat_fail) { - oc_endpoint_t ep = createEndpoint( + oc_endpoint_t ep = oc::endpoint::FromString( "coaps+tcp://[::1]:12345"); // reachable address, but inactive port EXPECT_EQ(OC_TCP_SOCKET_STATE_CONNECTING, oc_tcp_connect(&ep, nullptr, this)); EXPECT_EQ(OC_TCP_SOCKET_ERROR_EXISTS_CONNECTING, @@ -529,13 +518,13 @@ TEST_F(TestConnectivityWithServer, oc_tcp_send_buffer2) * session */ TEST_F(TestConnectivityWithServer, oc_tcp_send_buffer2_not_connected) { - oc_endpoint_t ep = createEndpoint("coaps+tcp://[ff02::158]:12345"); + oc_endpoint_t ep = oc::endpoint::FromString("coaps+tcp://[ff02::158]:12345"); oc_message_t *msg = oc_allocate_message(); memcpy(&msg->endpoint, &ep, sizeof(oc_endpoint_t)); EXPECT_EQ(OC_TCP_SOCKET_ERROR_NOT_CONNECTED, oc_send_buffer2(msg, true)); #ifdef OC_IPV4 - oc_endpoint_t ep_ipv4 = createEndpoint("coaps+tcp://1.1.1.1:12345"); + oc_endpoint_t ep_ipv4 = oc::endpoint::FromString("coaps+tcp://1.1.1.1:12345"); memcpy(&msg->endpoint, &ep_ipv4, sizeof(oc_endpoint_t)); EXPECT_EQ(OC_TCP_SOCKET_ERROR_NOT_CONNECTED, oc_send_buffer2(msg, true)); #endif /* OC_IPV4 */ @@ -551,7 +540,8 @@ 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"); + oc_endpoint_t ep = + oc::endpoint::FromString("coap+tcp://openconnectivity.org:3456"); ASSERT_EQ(OC_TCP_SOCKET_STATE_CONNECTING, oc_tcp_connect(&ep, on_tcp_connect_timeout, this)); diff --git a/security/oc_cred.c b/security/oc_cred.c index 5da2168d59..ec2801bf63 100644 --- a/security/oc_cred.c +++ b/security/oc_cred.c @@ -18,20 +18,20 @@ #ifdef OC_SECURITY +#include "oc_cred_internal.h" #include "oc_api.h" #include "oc_base64.h" -#include "oc_certs_internal.h" #include "oc_config.h" #include "oc_core_res.h" -#include "oc_cred_internal.h" -#include "oc_doxm_internal.h" -#include "oc_keypair_internal.h" -#include "oc_pstat.h" -#include "oc_roles_internal.h" #include "oc_store.h" -#include "oc_tls_internal.h" #include "port/oc_assert.h" #include "port/oc_log.h" +#include "security/oc_certs_internal.h" +#include "security/oc_doxm_internal.h" +#include "security/oc_keypair_internal.h" +#include "security/oc_pstat.h" +#include "security/oc_roles_internal.h" +#include "security/oc_tls_internal.h" #include "util/oc_list.h" #include "util/oc_macros.h" #include "util/oc_memb.h" diff --git a/security/oc_obt.c b/security/oc_obt.c index c8b90e49e7..3770516807 100644 --- a/security/oc_obt.c +++ b/security/oc_obt.c @@ -38,10 +38,9 @@ check oc_config.h and make sure OC_STORAGE is defined if OC_SECURITY is defined. #include "security/oc_certs_internal.h" #include "security/oc_cred_internal.h" #include "security/oc_csr_internal.h" -#include "security/oc_doxm_internal.h" #include "security/oc_keypair_internal.h" #include "security/oc_obt_internal.h" -#include "security/oc_pstat.h" +#include "security/oc_security_internal.h" #include "security/oc_sdi_internal.h" #include "security/oc_tls_internal.h" #include @@ -3694,53 +3693,6 @@ oc_obt_generate_root_cred(void) } #endif /* OC_PKI */ -int -oc_obt_self_own(size_t device) -{ - OC_DBG("oc_obt: performing self-onboarding of device(%zu)", device); - const oc_uuid_t *uuid = oc_core_get_device_id(device); - if (uuid == NULL) { - return -1; - } - - oc_sec_acl_t *acl = oc_sec_get_acl(device); - memcpy(acl->rowneruuid.id, uuid->id, sizeof(uuid->id)); - - oc_sec_doxm_t *doxm = oc_sec_get_doxm(device); - memcpy(doxm->devowneruuid.id, uuid->id, sizeof(uuid->id)); - memcpy(doxm->deviceuuid.id, uuid->id, sizeof(uuid->id)); - memcpy(doxm->rowneruuid.id, uuid->id, sizeof(uuid->id)); - doxm->owned = true; - doxm->oxmsel = 0; - - oc_sec_creds_t *creds = oc_sec_get_creds(device); - memcpy(creds->rowneruuid.id, uuid->id, sizeof(uuid->id)); - - oc_sec_pstat_t *ps = oc_sec_get_pstat(device); - memcpy(ps->rowneruuid.id, uuid->id, sizeof(uuid->id)); - ps->tm = 0; - ps->cm = 0; - ps->isop = true; - ps->s = OC_DOS_RFNOP; - - oc_sec_acl_add_bootstrap_acl(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)); - sdi->priv = false; - - oc_sec_dump_pstat(device); - oc_sec_dump_doxm(device); - oc_sec_dump_cred(device); - oc_sec_dump_acl(device); - oc_sec_dump_ael(device); - oc_sec_dump_sdi(device); - - return 0; -} - /* OBT initialization and shutdown */ int oc_obt_init(void) @@ -3754,7 +3706,7 @@ oc_obt_init(void) return 0; } - if (oc_obt_self_own(/*device*/ 0) != 0) { + if (oc_sec_self_own(/*device*/ 0) != 0) { OC_DBG("oc_obt: returning from oc_obt_init() with errors"); return -1; } diff --git a/security/oc_obt_internal.h b/security/oc_obt_internal.h index d188950dfd..ffe757cc8b 100644 --- a/security/oc_obt_internal.h +++ b/security/oc_obt_internal.h @@ -228,9 +228,6 @@ void oc_obt_free_otm_ctx(oc_otm_ctx_t *ctx, int status, oc_obt_otm_t); oc_event_callback_retval_t oc_obt_otm_request_timeout_cb(void *data); bool oc_obt_is_otm_ctx_valid(const oc_otm_ctx_t *ctx); -// perform self-onboarding -int oc_obt_self_own(size_t device); - #ifdef OC_PKI typedef struct oc_obt_generate_root_cert_data_t diff --git a/security/oc_security.c b/security/oc_security.c index 08d6f8e121..1813ef618f 100644 --- a/security/oc_security.c +++ b/security/oc_security.c @@ -19,12 +19,23 @@ #ifdef OC_SECURITY #include "oc_security_internal.h" +#include "oc_acl.h" +#include "oc_core_res.h" +#include "oc_cred.h" +#include "oc_helpers.h" +#include "oc_store.h" +#include "oc_uuid.h" +#include "port/oc_log.h" +#include "security/oc_doxm_internal.h" +#include "security/oc_pstat.h" +#include "security/oc_sdi_internal.h" #include "util/oc_features.h" #ifdef OC_HAS_FEATURE_PLGD_TIME #include "api/plgd/plgd_time_internal.h" #endif /* OC_HAS_FEATURE_PLGD_TIME */ +#include #include #include #include @@ -57,6 +68,53 @@ oc_mbedtls_init(void) #endif /* OC_DEBUG */ } +int +oc_sec_self_own(size_t device) +{ + OC_DBG("performing self-onboarding of device(%zu)", device); + const oc_uuid_t *uuid = oc_core_get_device_id(device); + if (uuid == NULL) { + return -1; + } + + oc_sec_acl_t *acl = oc_sec_get_acl(device); + memcpy(acl->rowneruuid.id, uuid->id, sizeof(uuid->id)); + + oc_sec_doxm_t *doxm = oc_sec_get_doxm(device); + memcpy(doxm->devowneruuid.id, uuid->id, sizeof(uuid->id)); + memcpy(doxm->deviceuuid.id, uuid->id, sizeof(uuid->id)); + memcpy(doxm->rowneruuid.id, uuid->id, sizeof(uuid->id)); + doxm->owned = true; + doxm->oxmsel = 0; + + oc_sec_creds_t *creds = oc_sec_get_creds(device); + memcpy(creds->rowneruuid.id, uuid->id, sizeof(uuid->id)); + + oc_sec_pstat_t *ps = oc_sec_get_pstat(device); + memcpy(ps->rowneruuid.id, uuid->id, sizeof(uuid->id)); + ps->tm = 0; + ps->cm = 0; + ps->isop = true; + ps->s = OC_DOS_RFNOP; + + oc_sec_acl_add_bootstrap_acl(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)); + sdi->priv = false; + + oc_sec_dump_pstat(device); + oc_sec_dump_doxm(device); + oc_sec_dump_cred(device); + oc_sec_dump_acl(device); + oc_sec_dump_ael(device); + oc_sec_dump_sdi(device); + + return 0; +} + #ifdef OC_HAS_FEATURE_PLGD_TIME void diff --git a/security/oc_security_internal.h b/security/oc_security_internal.h index 69252b52b3..5551a12714 100644 --- a/security/oc_security_internal.h +++ b/security/oc_security_internal.h @@ -34,6 +34,15 @@ extern "C" { */ void oc_mbedtls_init(void); +/** + * @brief Perform self-onboarding. + * + * @param device device index + * @return 0 on success + * @return -1 on failure + */ +int oc_sec_self_own(size_t device); + #ifdef OC_HAS_FEATURE_PLGD_TIME /** diff --git a/security/oc_tls.c b/security/oc_tls.c index cb32ce4aa4..13e28573ea 100644 --- a/security/oc_tls.c +++ b/security/oc_tls.c @@ -53,19 +53,19 @@ #include "security/oc_oscore.h" #endif /* OC_OSCORE */ -#include "mbedtls/build_info.h" -#include "mbedtls/ctr_drbg.h" -#include "mbedtls/entropy.h" -#include "mbedtls/md.h" -#include "mbedtls/oid.h" -#include "mbedtls/pkcs5.h" -#include "mbedtls/ssl.h" -#include "mbedtls/ssl_cookie.h" -#include "mbedtls/timing.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include #ifdef OC_DEBUG -#include "mbedtls/debug.h" -#include "mbedtls/error.h" -#include "mbedtls/platform.h" +#include +#include +#include #endif /* OC_DEBUG */ #include diff --git a/security/oc_tls_internal.h b/security/oc_tls_internal.h index f3300a260f..3b8530b105 100644 --- a/security/oc_tls_internal.h +++ b/security/oc_tls_internal.h @@ -19,17 +19,20 @@ #ifndef OC_TLS_INTERNAL_H #define OC_TLS_INTERNAL_H -#include "mbedtls/ssl.h" -#include "mbedtls/ctr_drbg.h" #include "oc_pki.h" #include "oc_uuid.h" #include "port/oc_connectivity.h" #include "security/oc_cred_internal.h" -#include "security/oc_keypair_internal.h" #include "util/oc_etimer.h" #include "util/oc_list.h" #include "util/oc_process.h" + +#include +#include +#include #include +#include +#include #ifdef __cplusplus extern "C" { diff --git a/security/unittest/oscore_hkdf_test.cpp b/security/unittest/oscore_hkdf_test.cpp index 227f1617d8..a89f77d392 100644 --- a/security/unittest/oscore_hkdf_test.cpp +++ b/security/unittest/oscore_hkdf_test.cpp @@ -22,8 +22,8 @@ #include "port/oc_random.h" #include "security/oc_oscore_crypto.h" #include "security/oc_tls_internal.h" -#include #include +#include class TestOSCOREHKDF : public testing::Test { protected: diff --git a/security/unittest/tls_peer_test.cpp b/security/unittest/tls_peer_test.cpp index 53ed3fb6c9..9c1a4a913c 100644 --- a/security/unittest/tls_peer_test.cpp +++ b/security/unittest/tls_peer_test.cpp @@ -24,12 +24,12 @@ #include "oc_uuid.h" #include "security/oc_pstat.h" #include "security/oc_tls_internal.h" +#include "tests/gtest/Endpoint.h" #include -#include - #include #include +#include #include #include @@ -202,16 +202,6 @@ class TestTLSPeer : public testing::Test { } } - static oc_endpoint_t getEndpoint(const std::string &ep) - { - oc_string_t ep_str; - oc_new_string(&ep_str, ep.c_str(), ep.length()); - oc_endpoint_t endpoint; - EXPECT_EQ(0, oc_string_to_endpoint(&ep_str, &endpoint, nullptr)); - oc_free_string(&ep_str); - return endpoint; - } - static std::vector getClients() { std::vector clients{ createPeer("coaps://[ff02::41]:1336", @@ -258,7 +248,7 @@ class TestTLSPeer : public testing::Test { static void addPeers(const std::vector &peers) { for (const auto &p : peers) { - oc_endpoint_t ep = getEndpoint(p.address); + oc_endpoint_t ep = oc::endpoint::FromString(p.address); oc_tls_peer_t *peer = oc_tls_add_peer(&ep, p.role); ASSERT_NE(nullptr, peer); peer->uuid = p.uuid; @@ -310,13 +300,13 @@ TEST_F(TestTLSPeer, GetPeer) auto clients = getClients(); for (const auto &c : clients) { - oc_endpoint_t ep = getEndpoint(c.address); + oc_endpoint_t ep = oc::endpoint::FromString(c.address); ASSERT_EQ(nullptr, oc_tls_get_peer(&ep)); ASSERT_EQ(nullptr, oc_tls_get_peer_uuid(&ep)); } for (const auto &s : servers) { - oc_endpoint_t ep = getEndpoint(s.address); + oc_endpoint_t ep = oc::endpoint::FromString(s.address); const oc_tls_peer_t *peer = oc_tls_get_peer(&ep); ASSERT_NE(nullptr, peer); ASSERT_EQ(MBEDTLS_SSL_IS_SERVER, peer->role); @@ -410,7 +400,7 @@ TEST_F(TestTLSPeer, ResetDevice) #ifdef OC_PKI TEST_F(TestTLSPeer, VerifyCertificate) { - oc_endpoint_t ep = getEndpoint("coaps://[ff02::43]:1338"); + oc_endpoint_t ep = oc::endpoint::FromString("coaps://[ff02::43]:1338"); oc_tls_peer_t *peer = oc_tls_add_peer(&ep, MBEDTLS_SSL_IS_SERVER); ASSERT_NE(nullptr, peer); ASSERT_NE(nullptr, peer->ssl_conf.f_vrfy); diff --git a/security/unittest/tlstest.cpp b/security/unittest/tlstest.cpp index 6d952923b8..faa53cc7e0 100644 --- a/security/unittest/tlstest.cpp +++ b/security/unittest/tlstest.cpp @@ -22,9 +22,9 @@ #include "oc_api.h" #include "oc_endpoint.h" #include "oc_signal_event_loop.h" -#include "oc_tls_internal.h" #include "oc_core_res.h" #include "port/oc_network_event_handler_internal.h" +#include "security/oc_tls_internal.h" #ifdef OC_HAS_FEATURE_PUSH #include "api/oc_push_internal.h" diff --git a/swig/swig_interfaces/oc_session_events.i b/swig/swig_interfaces/oc_session_events.i index 49168cc5a5..ab83969e37 100644 --- a/swig/swig_interfaces/oc_session_events.i +++ b/swig/swig_interfaces/oc_session_events.i @@ -38,5 +38,4 @@ void jni_session_events_set_event_delay(int secs) } %} #define OC_API -#define OC_DEPRECATED(...) %include "oc_session_events.h" diff --git a/tests/gtest/Device.h b/tests/gtest/Device.h index 7ceea429ba..ecff81269b 100644 --- a/tests/gtest/Device.h +++ b/tests/gtest/Device.h @@ -147,6 +147,7 @@ class TestDevice { static void ClearDynamicResources(); #endif /* OC_SERVER */ + /** * @brief Get the Endpoint object * diff --git a/tests/gtest/Endpoint.cpp b/tests/gtest/Endpoint.cpp new file mode 100644 index 0000000000..b522e79784 --- /dev/null +++ b/tests/gtest/Endpoint.cpp @@ -0,0 +1,49 @@ +/**************************************************************************** + * + * 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. + * + ****************************************************************************/ + +#include "Endpoint.h" + +#include "oc_helpers.h" + +#include + +namespace oc::endpoint { + +oc_endpoint_t +FromString(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; +} + +int +FromString(const std::string &addr, oc_endpoint_t *ep, oc_string_t *uri) +{ + oc_string_t s; + oc_new_string(&s, addr.c_str(), addr.length()); + int ret = oc_string_to_endpoint(&s, ep, uri); + oc_free_string(&s); + return ret; +} + +} // namespace oc::endpoint diff --git a/tests/gtest/Endpoint.h b/tests/gtest/Endpoint.h new file mode 100644 index 0000000000..b7e5977225 --- /dev/null +++ b/tests/gtest/Endpoint.h @@ -0,0 +1,44 @@ +/**************************************************************************** + * + * 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. + * + ****************************************************************************/ + +#pragma once + +#include "oc_endpoint.h" +#include "oc_helpers.h" + +#include + +namespace oc::endpoint { + +/** + * @brief Parse endpoint from string. + */ +oc_endpoint_t FromString(const std::string &ep_str); + +/** + * @brief Parse endpoint and uri from string + * + * @param addr address to parse + * @param[out] ep parsed endpoint (cannot be NULL) + * @param[out] uri parsed uri + * @return int 0 on success + * @return int -1 on failure + */ +int FromString(const std::string &addr, oc_endpoint_t *ep, oc_string_t *uri); + +} // oc::endpoint