From 193ac144d877c161b7118152671693b1c420060f Mon Sep 17 00:00:00 2001 From: "hyuna0213.jo" Date: Tue, 25 Aug 2015 15:12:39 +0900 Subject: [PATCH] merge master code to build iotivity current cloud-interface branch code failed to build iotivity stack. so I merge latest master code that the build issue is resolved to build full source code. Change-Id: I6f6393806f3d4b5c5b861fe61941cea13bb45904 Signed-off-by: hyuna0213.jo Reviewed-on: https://gerrit.iotivity.org/gerrit/2265 Reviewed-by: Jaehong Jo Reviewed-by: Jon A. Cruz Tested-by: Jon A. Cruz --- auto_build.sh | 28 +- build_common/darwin/SConscript | 3 + ...HE_PSK_WITH_AES_128_CBC_SHA_256-cipher-su.patch | 746 +++++++++ ...ng-implementation-about-the-anonymous-cip.patch | 690 ++++++++ extlibs/tinydtls/crypto.c | 137 +- extlibs/tinydtls/crypto.h | 10 + extlibs/tinydtls/dtls.c | 502 +++++- extlibs/tinydtls/dtls.h | 6 +- extlibs/tinydtls/global.h | 3 +- extlibs/tinydtls/tests/dtls-client.c | 16 +- extlibs/tinydtls/tests/dtls-server.c | 8 +- resource/csdk/connectivity/api/cacommon.h | 1 + .../csdk/connectivity/common/src/caremotehandler.c | 1 + resource/csdk/connectivity/common/src/logger.c | 8 +- resource/csdk/connectivity/inc/caadapternetdtls.h | 2 +- resource/csdk/connectivity/inc/caipinterface.h | 8 +- .../src/adapter_util/caadapternetdtls.c | 12 +- .../src/bt_edr_adapter/android/caedrserver.c | 2 + .../connectivity/src/bt_edr_adapter/caedradapter.c | 2 - resource/csdk/connectivity/src/camessagehandler.c | 69 +- resource/csdk/connectivity/src/caprotocolmessage.c | 13 +- .../src/ip_adapter/android/caipnwmonitor.c | 4 +- .../src/ip_adapter/arduino/caipnwmonitor_eth.cpp | 6 +- .../src/ip_adapter/arduino/caipnwmonitor_wifi.cpp | 6 +- .../csdk/connectivity/src/ip_adapter/caipadapter.c | 5 +- .../csdk/connectivity/src/ip_adapter/caipserver.c | 11 +- .../src/ip_adapter/linux/caipnwmonitor.c | 6 +- .../src/ip_adapter/tizen/caipnwmonitor.c | 345 +++- resource/csdk/security/SConscript | 53 +- .../csdk/security/include/internal/amaclresource.h | 79 + .../csdk/security/include/internal/credresource.h | 27 + .../csdk/security/include/internal/doxmresource.h | 2 + .../security/include/internal/srmresourcestrings.h | 21 +- .../csdk/security/include/internal/svcresource.h | 58 + resource/csdk/security/include/iotvticalendar.h | 191 +++ resource/csdk/security/include/pbkdf2.h | 62 + resource/csdk/security/include/pinoxmcommon.h | 78 + .../security/include/securevirtualresourcetypes.h | 29 +- resource/csdk/security/include/srmutility.h | 25 +- resource/csdk/security/provisioning/README.txt | 53 + resource/csdk/security/provisioning/SConscript | 20 +- .../include/internal/credentialgenerator.h | 13 +- .../include/internal/ownershiptransfermanager.h | 98 ++ .../include/internal/secureresourceprovider.h | 62 + .../provisioning/include/ocprovisioningmanager.h | 155 ++ .../provisioning/include/oxm/oxmjustworks.h | 70 + .../provisioning/include/oxm/oxmrandompin.h | 73 + .../csdk/security/provisioning/include/pmtypes.h | 66 + .../csdk/security/provisioning/include/pmutility.h | 61 + .../provisioning/include/provisioningmanager.h | 159 -- .../csdk/security/provisioning/sample/SConscript | 14 +- .../provisioning/sample/oic_svr_db_client.json | 43 + .../sample/oic_svr_db_server_justworks.json | 45 + .../sample/oic_svr_db_server_randompin.json | 45 + .../provisioning/sample/provisioningclient.c | 479 ++++-- .../provisioning/sample/sampleserver_justworks.cpp | 466 ++++++ .../provisioning/sample/sampleserver_randompin.cpp | 485 ++++++ .../provisioning/src/credentialgenerator.c | 116 +- .../provisioning/src/ocprovisioningmanager.c | 402 +++++ .../provisioning/src/ownershiptransfermanager.c | 1148 ++++++++++++++ .../csdk/security/provisioning/src/oxmjustworks.c | 108 ++ .../csdk/security/provisioning/src/oxmrandompin.c | 145 ++ .../csdk/security/provisioning/src/pmutility.c | 475 ++++++ .../provisioning/src/provisioningmanager.c | 1669 -------------------- .../provisioning/src/secureresourceprovider.c | 491 ++++++ .../csdk/security/provisioning/unittest/SConscript | 8 +- .../security/provisioning/unittest/otmunittest.cpp | 100 ++ .../provisioning/unittest/pmutilitytest.cpp | 90 ++ .../provisioning/unittest/provisioningmanager.cpp | 58 - .../unittest/secureresourceprovider.cpp | 72 + resource/csdk/security/src/aclresource.c | 332 +++- resource/csdk/security/src/amaclresource.c | 403 +++++ resource/csdk/security/src/credresource.c | 243 ++- resource/csdk/security/src/doxmresource.c | 173 +- resource/csdk/security/src/iotvticalendar.c | 418 +++++ resource/csdk/security/src/oxmpincommon.c | 110 ++ resource/csdk/security/src/pbkdf2.c | 149 ++ resource/csdk/security/src/policyengine.c | 67 +- resource/csdk/security/src/psinterface.c | 49 +- resource/csdk/security/src/pstatresource.c | 2 +- resource/csdk/security/src/resourcemanager.c | 12 +- resource/csdk/security/src/secureresourcemanager.c | 1 - resource/csdk/security/src/srmresourcestrings.c | 21 +- resource/csdk/security/src/srmutility.c | 46 +- resource/csdk/security/src/svcresource.c | 383 +++++ resource/csdk/security/unittest/SConscript | 5 +- .../csdk/security/unittest/aclresourcetest.cpp | 203 ++- .../csdk/security/unittest/credentialresource.cpp | 143 +- resource/csdk/security/unittest/doxmresource.cpp | 10 +- .../csdk/security/unittest/iotvticalendartest.cpp | 302 ++++ resource/csdk/security/unittest/oic_unittest.json | 42 +- resource/csdk/security/unittest/pstatresource.cpp | 2 +- resource/csdk/security/unittest/srmtestcommon.cpp | 73 + resource/csdk/security/unittest/srmtestcommon.h | 27 + resource/csdk/security/unittest/srmutility.cpp | 11 +- .../csdk/security/unittest/svcresourcetest.cpp | 81 + .../stack/samples/linux/secure/occlientbasicops.h | 5 + .../samples/linux/secure/ocserverbasicops.cpp | 9 +- .../samples/linux/secure/oic_svr_db_client.json | 3 +- .../samples/linux/secure/oic_svr_db_server.json | 42 +- .../samples/tizen/build/packaging/com.oic.ri.spec | 1 + resource/csdk/stack/src/ocserverrequest.c | 10 + resource/csdk/stack/src/ocstack.c | 75 +- resource/csdk/stack/src/oicgroup.c | 36 +- resource/include/OCPlatform.h | 321 ++-- resource/include/OCPlatform_impl.h | 52 +- .../src/resourceBroker/include/DevicePresence.h | 11 +- .../src/resourceBroker/src/DevicePresence.cpp | 23 +- .../src/resourceContainer/SConscript | 2 +- 109 files changed, 11689 insertions(+), 2773 deletions(-) create mode 100644 extlibs/tinydtls/0001-Add-TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256-cipher-su.patch create mode 100644 extlibs/tinydtls/0001-Fix-the-wrong-implementation-about-the-anonymous-cip.patch create mode 100755 resource/csdk/security/include/internal/amaclresource.h create mode 100644 resource/csdk/security/include/internal/svcresource.h create mode 100644 resource/csdk/security/include/iotvticalendar.h create mode 100644 resource/csdk/security/include/pbkdf2.h create mode 100644 resource/csdk/security/include/pinoxmcommon.h create mode 100644 resource/csdk/security/provisioning/README.txt create mode 100644 resource/csdk/security/provisioning/include/internal/ownershiptransfermanager.h create mode 100644 resource/csdk/security/provisioning/include/internal/secureresourceprovider.h create mode 100644 resource/csdk/security/provisioning/include/ocprovisioningmanager.h create mode 100644 resource/csdk/security/provisioning/include/oxm/oxmjustworks.h create mode 100644 resource/csdk/security/provisioning/include/oxm/oxmrandompin.h create mode 100644 resource/csdk/security/provisioning/include/pmtypes.h create mode 100644 resource/csdk/security/provisioning/include/pmutility.h delete mode 100644 resource/csdk/security/provisioning/include/provisioningmanager.h create mode 100644 resource/csdk/security/provisioning/sample/oic_svr_db_client.json create mode 100644 resource/csdk/security/provisioning/sample/oic_svr_db_server_justworks.json create mode 100644 resource/csdk/security/provisioning/sample/oic_svr_db_server_randompin.json create mode 100644 resource/csdk/security/provisioning/sample/sampleserver_justworks.cpp create mode 100644 resource/csdk/security/provisioning/sample/sampleserver_randompin.cpp create mode 100644 resource/csdk/security/provisioning/src/ocprovisioningmanager.c create mode 100644 resource/csdk/security/provisioning/src/ownershiptransfermanager.c create mode 100644 resource/csdk/security/provisioning/src/oxmjustworks.c create mode 100644 resource/csdk/security/provisioning/src/oxmrandompin.c create mode 100644 resource/csdk/security/provisioning/src/pmutility.c delete mode 100644 resource/csdk/security/provisioning/src/provisioningmanager.c create mode 100644 resource/csdk/security/provisioning/src/secureresourceprovider.c create mode 100644 resource/csdk/security/provisioning/unittest/otmunittest.cpp create mode 100644 resource/csdk/security/provisioning/unittest/pmutilitytest.cpp delete mode 100644 resource/csdk/security/provisioning/unittest/provisioningmanager.cpp create mode 100644 resource/csdk/security/provisioning/unittest/secureresourceprovider.cpp create mode 100644 resource/csdk/security/src/amaclresource.c create mode 100644 resource/csdk/security/src/iotvticalendar.c create mode 100644 resource/csdk/security/src/oxmpincommon.c create mode 100644 resource/csdk/security/src/pbkdf2.c create mode 100644 resource/csdk/security/src/svcresource.c create mode 100644 resource/csdk/security/unittest/iotvticalendartest.cpp create mode 100644 resource/csdk/security/unittest/srmtestcommon.cpp create mode 100644 resource/csdk/security/unittest/srmtestcommon.h create mode 100644 resource/csdk/security/unittest/svcresourcetest.cpp diff --git a/auto_build.sh b/auto_build.sh index 750f641..352f3b6 100755 --- a/auto_build.sh +++ b/auto_build.sh @@ -63,27 +63,41 @@ function build_android() # Note: for android, as oic-resource uses C++11 feature stoi and to_string, # it requires gcc-4.9, currently only android-ndk-r10(for linux) # and windows android-ndk-r10(64bit target version) support these features. - echo "*********** Build Boost for android ***********" - # disable parallel build for android as gradle depends on scons to finish first - export SCONSFLAGS="-Q" + # Parallel builds for android are disabled as gradle depends on + # scons to finish first + SCONSFLAGS="-Q" build_android_x86 $1 $2 + SCONSFLAGS="-Q" build_android_armeabi $1 $2 +} + +function build_android_x86() +{ echo "*********** Build for android x86 *************" scons TARGET_OS=android TARGET_ARCH=x86 RELEASE=$1 TARGET_TRANSPORT=IP $2 scons TARGET_OS=android TARGET_ARCH=x86 RELEASE=$1 TARGET_TRANSPORT=BT $2 scons TARGET_OS=android TARGET_ARCH=x86 RELEASE=$1 TARGET_TRANSPORT=BLE $2 +<<<<<<< HEAD echo "*********** Build for android x86_64 *************" scons TARGET_OS=android TARGET_ARCH=x86_64 RELEASE=$1 TARGET_TRANSPORT=IP $2 scons TARGET_OS=android TARGET_ARCH=x86_64 RELEASE=$1 TARGET_TRANSPORT=BT $2 scons TARGET_OS=android TARGET_ARCH=x86_64 RELEASE=$1 TARGET_TRANSPORT=BLE $2 +======= +} +>>>>>>> origin/master +function build_android_armeabi() +{ echo "*********** Build for android armeabi *************" scons TARGET_OS=android TARGET_ARCH=armeabi RELEASE=$1 TARGET_TRANSPORT=IP $2 scons TARGET_OS=android TARGET_ARCH=armeabi RELEASE=$1 TARGET_TRANSPORT=BT $2 scons TARGET_OS=android TARGET_ARCH=armeabi RELEASE=$1 TARGET_TRANSPORT=BLE $2 +<<<<<<< HEAD # enable parallel build export SCONSFLAGS="-Q -j 4" +======= +>>>>>>> origin/master } function build_arduino() @@ -191,6 +205,14 @@ then then build_android true build_android false + elif [ $1 = 'android_x86' ] + then + build_android_x86 true + build_android_x86 false + elif [ $1 = 'android_armeabi' ] + then + build_android_armeabi true + build_android_armeabi false elif [ $1 = 'arduino' ] then build_arduino true diff --git a/build_common/darwin/SConscript b/build_common/darwin/SConscript index 4cbb981..73bb047 100644 --- a/build_common/darwin/SConscript +++ b/build_common/darwin/SConscript @@ -58,6 +58,9 @@ else: env.AppendUnique(CCFLAGS = ['-g']) env.AppendUnique(LINKFLAGS = ['-g']) +if env.get('LOGGING'): + env.AppendUnique(CPPDEFINES = ['-DTB_LOG']) + if target_os == 'darwin': sys_root = tc_path + '/Platforms/MacOSX.platform/Developer/SDKs/MacOSX' + sys_version + '.sdk/' else: diff --git a/extlibs/tinydtls/0001-Add-TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256-cipher-su.patch b/extlibs/tinydtls/0001-Add-TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256-cipher-su.patch new file mode 100644 index 0000000..5221174 --- /dev/null +++ b/extlibs/tinydtls/0001-Add-TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256-cipher-su.patch @@ -0,0 +1,746 @@ +From 947179cd0d3646359272cc0645e5049e2426f9e0 Mon Sep 17 00:00:00 2001 +From: Sachin Agrawal +Date: Thu, 6 Aug 2015 15:13:29 -0700 +Subject: [PATCH 1/1] Add TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256 cipher suite + in tinydtls + +[Patch #1] Initial upload +[Patch #2] Add function to calculate the pre-master key of ECDHE_PSK cipher suite. +[Patch #3] Update codes according to review comments +[Patch #4] Modify code alignment. + +Change-Id: I70be3a8e9469cc1913373d820b4a3d4f4a6d6d0d +Signed-off-by: leechul +Signed-off-by: Sachin Agrawal +--- + extlibs/tinydtls/crypto.c | 41 +++- + extlibs/tinydtls/crypto.h | 9 + + extlibs/tinydtls/dtls.c | 401 ++++++++++++++++++++++++++++++++-- + extlibs/tinydtls/global.h | 1 + + extlibs/tinydtls/tests/dtls-client.c | 8 +- + 5 files changed, 444 insertions(+), 16 deletions(-) + +diff --git a/extlibs/tinydtls/crypto.c b/extlibs/tinydtls/crypto.c +index 3fbb993..deaf581 100644 +--- a/extlibs/tinydtls/crypto.c ++++ b/extlibs/tinydtls/crypto.c +@@ -641,6 +641,41 @@ dtls_ecdsa_verify_sig(const unsigned char *pub_key_x, + } + #endif /* DTLS_ECC */ + ++#if defined(DTLS_PSK) && defined(DTLS_ECC) ++int dtls_ecdhe_psk_pre_master_secret(unsigned char *psk, size_t psklen, ++ unsigned char *ecc_priv_key, ++ unsigned char *ecc_pub_key_x, ++ unsigned char *ecc_pub_key_y, ++ size_t ecc_key_size, ++ unsigned char *result, ++ size_t result_len) ++{ ++ uint8_t eccPublicKey[64]; ++ uint8_t eccPrivateKey[32]; ++ unsigned char *p = result; ++ ++ if (result_len < uECC_BYTES + psklen + (sizeof(uint16) * 2)) { ++ return -1; ++ } ++ ++ dtls_int_to_uint16(p, uECC_BYTES); ++ p += sizeof(uint16); ++ ++ memcpy(eccPublicKey, ecc_pub_key_x, 32); ++ memcpy(eccPublicKey + 32, ecc_pub_key_y, 32); ++ memcpy(eccPrivateKey, ecc_priv_key, 32); ++ uECC_shared_secret(eccPublicKey, eccPrivateKey, p); ++ p += uECC_BYTES; ++ ++ dtls_int_to_uint16(p, psklen); ++ p += sizeof(uint16); ++ ++ memcpy(p, psk, psklen); ++ ++ return uECC_BYTES + psklen + (sizeof(uint16) * 2); ++} ++#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */ ++ + int + dtls_encrypt(const unsigned char *src, size_t length, + unsigned char *buf, +@@ -665,7 +700,8 @@ dtls_encrypt(const unsigned char *src, size_t length, + memmove(buf, src, length); + ret = dtls_ccm_encrypt(&ctx->data, src, length, buf, nounce, aad, la); + } +- if(cipher == TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256) { ++ if(cipher == TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256 || ++ cipher == TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256) { + ret = rijndael_set_key(&ctx->data.ctx, key, 8 * keylen); + if (ret < 0) { + /* cleanup everything in case the key has the wrong size */ +@@ -708,7 +744,8 @@ dtls_decrypt(const unsigned char *src, size_t length, + ret = dtls_ccm_decrypt(&ctx->data, src, length, buf, nounce, aad, la); + } + +- if(cipher == TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256) { ++ if(cipher == TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256 || ++ cipher == TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256) { + ret = rijndael_set_key(&ctx->data.ctx, key, 8 * keylen); + if (ret < 0) { + /* cleanup everything in case the key has the wrong size */ +diff --git a/extlibs/tinydtls/crypto.h b/extlibs/tinydtls/crypto.h +index a81d306..f4cfc66 100644 +--- a/extlibs/tinydtls/crypto.h ++++ b/extlibs/tinydtls/crypto.h +@@ -39,6 +39,7 @@ + #include "numeric.h" + #include "hmac.h" + #include "ccm.h" ++#include "ecc/ecc.h" + + /* TLS_PSK_WITH_AES_128_CCM_8 */ + #define DTLS_MAC_KEY_LENGTH 0 +@@ -129,6 +130,13 @@ typedef struct { + dtls_compression_t compression; /**< compression method */ + dtls_cipher_t cipher; /**< cipher type */ + unsigned int do_client_auth:1; ++ ++#ifdef DTLS_ECC && DTLS_PSK ++ struct keyx_t { ++ dtls_handshake_parameters_ecc_t ecc; ++ dtls_handshake_parameters_psk_t psk; ++ } keyx; ++#else /* DTLS_ECC && DTLS_PSK */ + union { + #ifdef DTLS_ECC + dtls_handshake_parameters_ecc_t ecc; +@@ -137,6 +145,7 @@ typedef struct { + dtls_handshake_parameters_psk_t psk; + #endif /* DTLS_PSK */ + } keyx; ++#endif /* DTLS_ECC && DTLS_PSK */ + } dtls_handshake_parameters_t; + + /* The following macros provide access to the components of the +diff --git a/extlibs/tinydtls/dtls.c b/extlibs/tinydtls/dtls.c +index b5b8fd1..6104a08 100644 +--- a/extlibs/tinydtls/dtls.c ++++ b/extlibs/tinydtls/dtls.c +@@ -506,6 +506,17 @@ static inline int is_tls_ecdh_anon_with_aes_128_cbc_sha_256(dtls_cipher_t cipher + #endif + } + ++/** returns true if the cipher matches TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256 */ ++static inline int is_tls_ecdhe_psk_with_aes_128_cbc_sha_256(dtls_cipher_t cipher) ++{ ++#if defined(DTLS_ECC) && defined(DTLS_PSK) ++ return cipher == TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256; ++#else ++ return 0; ++#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */ ++} ++ ++ + + /** returns true if the application is configured for psk */ + static inline int is_psk_supported(dtls_context_t *ctx) +@@ -549,6 +560,17 @@ static inline int is_ecdh_anon_supported(dtls_context_t *ctx) + #endif + } + ++/** returns true if ecdhe_psk_with_aes_128_cbc_sha_256 is supported */ ++static inline int is_ecdhe_psk_supported(dtls_context_t *ctx) ++{ ++#if defined(DTLS_ECC) && defined(DTLS_PSK) ++ return is_psk_supported(ctx); ++#else ++ return 0; ++#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */ ++} ++ ++ + /** + * Returns @c 1 if @p code is a cipher suite other than @c + * TLS_NULL_WITH_NULL_NULL that we recognize. +@@ -563,14 +585,17 @@ known_cipher(dtls_context_t *ctx, dtls_cipher_t code, int is_client) { + int psk; + int ecdsa; + int ecdh_anon; ++ int ecdhe_psk; + + psk = is_psk_supported(ctx); + ecdsa = is_ecdsa_supported(ctx, is_client); + ecdh_anon = is_ecdh_anon_supported(ctx); ++ ecdhe_psk = is_ecdhe_psk_supported(ctx); + + return (psk && is_tls_psk_with_aes_128_ccm_8(code)) || + (ecdsa && is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(code)) || +- (ecdh_anon && is_tls_ecdh_anon_with_aes_128_cbc_sha_256(code)); ++ (ecdh_anon && is_tls_ecdh_anon_with_aes_128_cbc_sha_256(code)) || ++ (ecdhe_psk && is_tls_ecdhe_psk_with_aes_128_cbc_sha_256(code)); + } + + /** +@@ -676,7 +701,11 @@ calculate_key_block(dtls_context_t *ctx, + dtls_peer_t *peer, + session_t *session, + dtls_peer_type role) { +- unsigned char *pre_master_secret; ++#if defined(DTLS_PSK) && defined(DTLS_ECC) ++ unsigned char pre_master_secret[MAX_KEYBLOCK_LENGTH + uECC_BYTES]; ++#else ++ unsigned char pre_master_secret[MAX_KEYBLOCK_LENGTH]; ++#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */ + int pre_master_len = 0; + dtls_security_parameters_t *security = dtls_security_params_next(peer); + uint8 master_secret[DTLS_MASTER_SECRET_LENGTH]; +@@ -685,8 +714,6 @@ calculate_key_block(dtls_context_t *ctx, + return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); + } + +- pre_master_secret = security->key_block; +- + switch (handshake->cipher) { + #ifdef DTLS_PSK + case TLS_PSK_WITH_AES_128_CCM_8: { +@@ -733,6 +760,35 @@ calculate_key_block(dtls_context_t *ctx, + break; + } + #endif /* DTLS_ECC */ ++#if defined(DTLS_PSK) && defined(DTLS_ECC) ++ case TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256: { ++ unsigned char psk[DTLS_PSK_MAX_KEY_LEN]; ++ int psklen; ++ ++ psklen = CALL(ctx, get_psk_info, session, DTLS_PSK_KEY, ++ handshake->keyx.psk.identity, ++ handshake->keyx.psk.id_length, ++ psk, DTLS_PSK_MAX_KEY_LEN); ++ if (psklen < 0) { ++ dtls_crit("no psk key for session available\n"); ++ return psklen; ++ } ++ ++ pre_master_len = dtls_ecdhe_psk_pre_master_secret(psk, psklen, ++ handshake->keyx.ecc.own_eph_priv, ++ handshake->keyx.ecc.other_eph_pub_x, ++ handshake->keyx.ecc.other_eph_pub_y, ++ sizeof(handshake->keyx.ecc.own_eph_priv), ++ pre_master_secret, ++ MAX_KEYBLOCK_LENGTH + uECC_BYTES); ++ ++ if (pre_master_len < 0) { ++ dtls_crit("the curve was too long, for the pre master secret\n"); ++ return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); ++ } ++ break; ++ } ++#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */ + default: + dtls_crit("calculate_key_block: unknown cipher\n"); + return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); +@@ -1113,6 +1169,56 @@ check_client_keyexchange(dtls_context_t *ctx, + data += sizeof(handshake->keyx.ecc.other_eph_pub_y); + } + #endif /* DTLS_ECC */ ++#if defined(DTLS_PSK) && defined(DTLS_ECC) ++ if (is_tls_ecdhe_psk_with_aes_128_cbc_sha_256(handshake->cipher)) { ++ int id_length; ++ ++ if (length < DTLS_HS_LENGTH + DTLS_CKXEC_LENGTH) { ++ dtls_debug("The client key exchange is too short\n"); ++ return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); ++ } ++ data += DTLS_HS_LENGTH; ++ ++ //PSK hint ++ id_length = dtls_uint16_to_int(data); ++ data += sizeof(uint16); ++ ++ if (DTLS_HS_LENGTH + DTLS_CKXPSK_LENGTH_MIN + DTLS_CKXEC_LENGTH + id_length != length) { ++ dtls_debug("The identity has a wrong length\n"); ++ return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); ++ } ++ ++ if (id_length > DTLS_PSK_MAX_CLIENT_IDENTITY_LEN) { ++ dtls_warn("please use a smaller client identity\n"); ++ return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); ++ } ++ ++ handshake->keyx.psk.id_length = id_length; ++ memcpy(handshake->keyx.psk.identity, data, id_length); ++ data += id_length; ++ ++ //ECDH public ++ if (dtls_uint8_to_int(data) != 1 + 2 * DTLS_EC_KEY_SIZE) { ++ dtls_alert("expected 65 bytes long public point\n"); ++ return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); ++ } ++ data += sizeof(uint8); ++ ++ if (dtls_uint8_to_int(data) != 4) { ++ dtls_alert("expected uncompressed public point\n"); ++ return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); ++ } ++ data += sizeof(uint8); ++ ++ memcpy(handshake->keyx.ecc.other_eph_pub_x, data, ++ sizeof(handshake->keyx.ecc.other_eph_pub_x)); ++ data += sizeof(handshake->keyx.ecc.other_eph_pub_x); ++ ++ memcpy(handshake->keyx.ecc.other_eph_pub_y, data, ++ sizeof(handshake->keyx.ecc.other_eph_pub_y)); ++ data += sizeof(handshake->keyx.ecc.other_eph_pub_y); ++ } ++#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */ + #ifdef DTLS_PSK + if (is_tls_psk_with_aes_128_ccm_8(handshake->cipher)) { + int id_length; +@@ -1286,7 +1392,8 @@ dtls_prepare_record(dtls_peer_t *peer, dtls_security_parameters_t *security, + p += data_len_array[i]; + res += data_len_array[i]; + } +- } else if (is_tls_ecdh_anon_with_aes_128_cbc_sha_256(security->cipher)) { ++ } else if (is_tls_ecdh_anon_with_aes_128_cbc_sha_256(security->cipher) || ++ is_tls_ecdhe_psk_with_aes_128_cbc_sha_256(security->cipher)) { + + unsigned char nonce[DTLS_CBC_IV_LENGTH]; + +@@ -2116,6 +2223,80 @@ dtls_send_server_key_exchange_ecdh(dtls_context_t *ctx, dtls_peer_t *peer, + } + #endif /* DTLS_ECC */ + ++#if defined(DTLS_PSK) && defined(DTLS_ECC) ++static int dtls_send_server_key_exchange_ecdhe_psk(dtls_context_t *ctx, dtls_peer_t *peer, ++ const unsigned char *psk_hint, size_t psk_hint_len) ++{ ++ /* The ASN.1 Integer representation of an 32 byte unsigned int could be ++ * 33 bytes long add space for that */ ++ uint8 buf[DTLS_SKEXEC_LENGTH + DTLS_SKEXECPSK_LENGTH_MAX + 2]; ++ uint8 *p; ++ uint8 *ephemeral_pub_x; ++ uint8 *ephemeral_pub_y; ++ dtls_handshake_parameters_t *config = peer->handshake_params; ++ ++ /* ServerKeyExchange ++ * Please see Session 2, RFC 5489. ++ ++ struct { ++ select (KeyExchangeAlgorithm) { ++ //other cases for rsa, diffie_hellman, etc. ++ case ec_diffie_hellman_psk: // NEW ++ opaque psk_identity_hint<0..2^16-1>; ++ ServerECDHParams params; ++ }; ++ } ServerKeyExchange; */ ++ p = buf; ++ ++ assert(psk_hint_len <= DTLS_PSK_MAX_CLIENT_IDENTITY_LEN); ++ if (psk_hint_len > DTLS_PSK_MAX_CLIENT_IDENTITY_LEN) { ++ // should never happen ++ dtls_warn("psk identity hint is too long\n"); ++ return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); ++ } ++ ++ // psk_identity_hint ++ dtls_int_to_uint16(p, psk_hint_len); ++ p += sizeof(uint16); ++ ++ memcpy(p, psk_hint, psk_hint_len); ++ p += psk_hint_len; ++ ++ /* ServerECDHParams. */ ++ /* ECCurveType curve_type: named_curve */ ++ dtls_int_to_uint8(p, TLS_EC_CURVE_TYPE_NAMED_CURVE); ++ p += sizeof(uint8); ++ ++ /* NamedCurve namedcurve: secp256r1 */ ++ dtls_int_to_uint16(p, TLS_EXT_ELLIPTIC_CURVES_SECP256R1); ++ p += sizeof(uint16); ++ ++ dtls_int_to_uint8(p, 1 + 2 * DTLS_EC_KEY_SIZE); ++ p += sizeof(uint8); ++ ++ /* This should be an uncompressed point, but I do not have access to the spec. */ ++ dtls_int_to_uint8(p, 4); ++ p += sizeof(uint8); ++ ++ /* store the pointer to the x component of the pub key and make space */ ++ ephemeral_pub_x = p; ++ p += DTLS_EC_KEY_SIZE; ++ ++ /* store the pointer to the y component of the pub key and make space */ ++ ephemeral_pub_y = p; ++ p += DTLS_EC_KEY_SIZE; ++ ++ dtls_ecdsa_generate_key(config->keyx.ecc.own_eph_priv, ++ ephemeral_pub_x, ephemeral_pub_y, ++ DTLS_EC_KEY_SIZE); ++ ++ assert(p - buf <= sizeof(buf)); ++ ++ return dtls_send_handshake_msg(ctx, peer, DTLS_HT_SERVER_KEY_EXCHANGE, ++ buf, p - buf); ++} ++#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */ ++ + #ifdef DTLS_PSK + static int + dtls_send_server_key_exchange_psk(dtls_context_t *ctx, dtls_peer_t *peer, +@@ -2207,6 +2388,7 @@ dtls_send_server_hello_msgs(dtls_context_t *ctx, dtls_peer_t *peer) + int res; + int ecdsa; + int ecdh_anon; ++ int ecdhe_psk; + + res = dtls_send_server_hello(ctx, peer); + +@@ -2217,6 +2399,7 @@ dtls_send_server_hello_msgs(dtls_context_t *ctx, dtls_peer_t *peer) + + ecdsa = is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(peer->handshake_params->cipher); + ecdh_anon = is_tls_ecdh_anon_with_aes_128_cbc_sha_256(peer->handshake_params->cipher); ++ ecdhe_psk = is_tls_ecdhe_psk_with_aes_128_cbc_sha_256(peer->handshake_params->cipher); + + #ifdef DTLS_ECC + if(ecdh_anon) { +@@ -2261,7 +2444,31 @@ dtls_send_server_hello_msgs(dtls_context_t *ctx, dtls_peer_t *peer) + } + } + #endif /* DTLS_ECC */ ++#if defined(DTLS_PSK) && defined(DTLS_ECC) ++ else if(ecdhe_psk) { ++ unsigned char psk_hint[DTLS_PSK_MAX_CLIENT_IDENTITY_LEN]; ++ int psk_len; ++ ++ /* The identity hint is optional, therefore we ignore the result ++ * and check psk only. */ ++ psk_len = CALL(ctx, get_psk_info, &peer->session, DTLS_PSK_HINT, ++ NULL, 0, psk_hint, DTLS_PSK_MAX_CLIENT_IDENTITY_LEN); + ++ if (psk_len < 0) { ++ dtls_debug("dtls_server_hello: cannot create ServerKeyExchange\n"); ++ return psk_len; ++ } ++ ++ if (psk_len > 0) { ++ res = dtls_send_server_key_exchange_ecdhe_psk(ctx, peer, psk_hint, (size_t)psk_len); ++ ++ if (res < 0) { ++ dtls_debug("dtls_server_hello(with ECDHE): cannot prepare Server Key Exchange record\n"); ++ return res; ++ } ++ } ++ } ++#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */ + #ifdef DTLS_PSK + if (is_tls_psk_with_aes_128_ccm_8(peer->handshake_params->cipher)) { + unsigned char psk_hint[DTLS_PSK_MAX_CLIENT_IDENTITY_LEN]; +@@ -2308,7 +2515,11 @@ dtls_send_ccs(dtls_context_t *ctx, dtls_peer_t *peer) { + static int + dtls_send_client_key_exchange(dtls_context_t *ctx, dtls_peer_t *peer) + { ++#if defined(DTLS_PSK) && defined(DTLS_ECC) ++ uint8 buf[DTLS_CKXEC_LENGTH + 2 + DTLS_PSK_MAX_CLIENT_IDENTITY_LEN]; ++#else + uint8 buf[DTLS_CKXEC_LENGTH]; ++#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */ + uint8 client_id[DTLS_PSK_MAX_CLIENT_IDENTITY_LEN]; + uint8 *p; + dtls_handshake_parameters_t *handshake = peer->handshake_params; +@@ -2368,6 +2579,60 @@ dtls_send_client_key_exchange(dtls_context_t *ctx, dtls_peer_t *peer) + break; + } + #endif /* DTLS_ECC */ ++#if defined(DTLS_PSK) && defined(DTLS_ECC) ++ case TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256: { ++ int psk_len; ++ uint8 *ephemeral_pub_x; ++ uint8 *ephemeral_pub_y; ++ ++ /* Please see Session 2, RFC 5489. ++ struct { ++ select (KeyExchangeAlgorithm) { ++ // other cases for rsa, diffie_hellman, etc. ++ case ec_diffie_hellman_psk: ++ opaque psk_identity<0..2^16-1>; ++ ClientECDiffieHellmanPublic public; ++ } exchange_keys; ++ } ClientKeyExchange; ++ */ ++ ++ psk_len = CALL(ctx, get_psk_info, &peer->session, DTLS_PSK_IDENTITY, ++ NULL, 0, ++ client_id, ++ sizeof(client_id)); ++ if (psk_len < 0) { ++ dtls_crit("no psk identity set in kx\n"); ++ return psk_len; ++ } ++ ++ if (psk_len + sizeof(uint16) > DTLS_CKXEC_LENGTH) { ++ dtls_warn("the psk identity is too long\n"); ++ return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); ++ } ++ ++ dtls_int_to_uint16(p, psk_len); ++ p += sizeof(uint16); ++ ++ memcpy(p, client_id, psk_len); ++ p += psk_len; ++ ++ dtls_int_to_uint8(p, 1 + 2 * DTLS_EC_KEY_SIZE); ++ p += sizeof(uint8); ++ ++ dtls_int_to_uint8(p, 4); ++ p += sizeof(uint8); ++ ++ ephemeral_pub_x = p; ++ p += DTLS_EC_KEY_SIZE; ++ ephemeral_pub_y = p; ++ p += DTLS_EC_KEY_SIZE; ++ ++ dtls_ecdsa_generate_key(peer->handshake_params->keyx.ecc.own_eph_priv, ++ ephemeral_pub_x, ephemeral_pub_y, ++ DTLS_EC_KEY_SIZE); ++ break; ++ } ++#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */ + default: + dtls_crit("cipher not supported\n"); + return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); +@@ -2457,6 +2722,7 @@ dtls_send_client_hello(dtls_context_t *ctx, dtls_peer_t *peer, + int psk = 0; + int ecdsa = 0; + int ecdh_anon = 0; ++ int ecdhe_psk = 0; + dtls_handshake_parameters_t *handshake = peer->handshake_params; + dtls_tick_t now; + +@@ -2471,14 +2737,18 @@ dtls_send_client_hello(dtls_context_t *ctx, dtls_peer_t *peer, + case TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256: + ecdh_anon = is_ecdh_anon_supported(ctx); + break; ++ case TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256: ++ ecdhe_psk = is_ecdhe_psk_supported(ctx); ++ break; + default: + psk = is_psk_supported(ctx); + ecdsa = is_ecdsa_supported(ctx, 1); + ecdh_anon = is_ecdh_anon_supported(ctx); ++ ecdhe_psk = is_ecdhe_psk_supported(ctx); + break; + } + +- cipher_size = 2 + (ecdsa ? 2 : 0) + (psk ? 2 : 0) + (ecdh_anon ? 2 : 0); ++ cipher_size = 2 + (ecdsa ? 2 : 0) + (psk ? 2 : 0) + (ecdh_anon ? 2 : 0) + (ecdhe_psk ? 2 : 0); + extension_size = (ecdsa) ? (2 + 6 + 6 + 8 + 6) : 0; + + if (cipher_size == 0) { +@@ -2533,6 +2803,10 @@ dtls_send_client_hello(dtls_context_t *ctx, dtls_peer_t *peer, + dtls_int_to_uint16(p, TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8); + p += sizeof(uint16); + } ++ if (ecdhe_psk) { ++ dtls_int_to_uint16(p, TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256); ++ p += sizeof(uint16); ++ } + + /* compression method */ + dtls_int_to_uint8(p, 1); +@@ -2900,8 +3174,97 @@ check_server_key_exchange_ecdh(dtls_context_t *ctx, + + return 0; + } +- + #endif /* DTLS_ECC */ ++#if defined(DTLS_PSK) && defined(DTLS_ECC) ++check_server_key_exchange_ecdhe_psk(dtls_context_t *ctx, ++ dtls_peer_t *peer, ++ uint8 *data, size_t data_length) ++{ ++ dtls_handshake_parameters_t *config = peer->handshake_params; ++ uint16_t psk_len = 0; ++ ++ /* ServerKeyExchange ++ * Please see Session 2, RFC 5489. ++ ++ struct { ++ select (KeyExchangeAlgorithm) { ++ //other cases for rsa, diffie_hellman, etc. ++ case ec_diffie_hellman_psk: // NEW ++ opaque psk_identity_hint<0..2^16-1>; ++ ServerECDHParams params; ++ }; ++ } ServerKeyExchange; */ ++ ++ update_hs_hash(peer, data, data_length); ++ ++ assert(is_tls_ecdhe_psk_with_aes_128_cbc_sha_256(config->cipher)); ++ ++ data += DTLS_HS_LENGTH; ++ ++ psk_len = dtls_uint16_to_int(data); ++ data += sizeof(uint16); ++ ++ if (psk_len != data_length - DTLS_HS_LENGTH - DTLS_SKEXEC_ECDH_ANON_LENGTH - sizeof(uint16)) { ++ dtls_warn("the length of the server identity hint is worng\n"); ++ return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR); ++ } ++ ++ if (psk_len > DTLS_PSK_MAX_CLIENT_IDENTITY_LEN) { ++ dtls_warn("please use a smaller server identity hint\n"); ++ return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); ++ } ++ ++ // store the psk_identity_hint in config->keyx.psk for later use ++ config->keyx.psk.id_length = psk_len; ++ memcpy(config->keyx.psk.identity, data, psk_len); ++ ++ data += psk_len; ++ data_length -= psk_len; ++ ++ if (data_length < DTLS_HS_LENGTH + DTLS_SKEXEC_ECDH_ANON_LENGTH) { ++ dtls_alert("the packet length does not match the expected\n"); ++ return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR); ++ } ++ ++ if (dtls_uint8_to_int(data) != TLS_EC_CURVE_TYPE_NAMED_CURVE) { ++ dtls_alert("Only named curves supported\n"); ++ return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); ++ } ++ data += sizeof(uint8); ++ data_length -= sizeof(uint8); ++ ++ if (dtls_uint16_to_int(data) != TLS_EXT_ELLIPTIC_CURVES_SECP256R1) { ++ dtls_alert("secp256r1 supported\n"); ++ return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); ++ } ++ data += sizeof(uint16); ++ data_length -= sizeof(uint16); ++ ++ if (dtls_uint8_to_int(data) != 1 + 2 * DTLS_EC_KEY_SIZE) { ++ dtls_alert("expected 65 bytes long public point\n"); ++ return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); ++ } ++ data += sizeof(uint8); ++ data_length -= sizeof(uint8); ++ ++ if (dtls_uint8_to_int(data) != 4) { ++ dtls_alert("expected uncompressed public point\n"); ++ return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR); ++ } ++ data += sizeof(uint8); ++ data_length -= sizeof(uint8); ++ ++ memcpy(config->keyx.ecc.other_eph_pub_x, data, sizeof(config->keyx.ecc.other_eph_pub_x)); ++ data += sizeof(config->keyx.ecc.other_eph_pub_x); ++ data_length -= sizeof(config->keyx.ecc.other_eph_pub_x); ++ ++ memcpy(config->keyx.ecc.other_eph_pub_y, data, sizeof(config->keyx.ecc.other_eph_pub_y)); ++ data += sizeof(config->keyx.ecc.other_eph_pub_y); ++ data_length -= sizeof(config->keyx.ecc.other_eph_pub_y); ++ ++ return 0; ++} ++#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */ + + #ifdef DTLS_PSK + static int +@@ -3113,7 +3476,8 @@ decrypt_verify(dtls_peer_t *peer, uint8 *packet, size_t length, + if (security->cipher == TLS_NULL_WITH_NULL_NULL) { + /* no cipher suite selected */ + return clen; +- } else if (is_tls_ecdh_anon_with_aes_128_cbc_sha_256(security->cipher)) { ++ } else if (is_tls_ecdh_anon_with_aes_128_cbc_sha_256(security->cipher) || ++ is_tls_ecdhe_psk_with_aes_128_cbc_sha_256(security->cipher)) { + + unsigned char nonce[DTLS_CBC_IV_LENGTH]; + +@@ -3169,17 +3533,17 @@ decrypt_verify(dtls_peer_t *peer, uint8 *packet, size_t length, + dtls_kb_remote_write_key(security, peer->role), + dtls_kb_key_size(security, peer->role), + A_DATA, A_DATA_LEN, +- security->cipher); ++ security->cipher); + } + + if (clen < 0) + dtls_warn("decryption failed\n"); + else { + #ifndef NDEBUG +- dtls_debug("decrypt_verify(): found %i bytes cleartext\n", clen); ++ dtls_debug("decrypt_verify(): found %i bytes cleartext\n", clen); + #endif +- dtls_security_params_free_other(peer); +- dtls_debug_dump("cleartext", *cleartext, clen); ++ dtls_security_params_free_other(peer); ++ dtls_debug_dump("cleartext", *cleartext, clen); + } + + return clen; +@@ -3282,7 +3646,8 @@ handle_handshake_msg(dtls_context_t *ctx, dtls_peer_t *peer, session_t *session, + } + if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(peer->handshake_params->cipher)) + peer->state = DTLS_STATE_WAIT_SERVERCERTIFICATE; //ecdsa +- else if (is_tls_ecdh_anon_with_aes_128_cbc_sha_256(peer->handshake_params->cipher)) ++ else if (is_tls_ecdh_anon_with_aes_128_cbc_sha_256(peer->handshake_params->cipher) || ++ is_tls_ecdhe_psk_with_aes_128_cbc_sha_256(peer->handshake_params->cipher)) + peer->state = DTLS_STATE_WAIT_SERVERKEYEXCHANGE; //ecdh + else + peer->state = DTLS_STATE_WAIT_SERVERHELLODONE; //psk +@@ -3329,6 +3694,16 @@ handle_handshake_msg(dtls_context_t *ctx, dtls_peer_t *peer, session_t *session, + err = check_server_key_exchange_ecdh(ctx, peer, data, data_length); + } + #endif /* DTLS_ECC */ ++ ++#if defined(DTLS_PSK) && defined(DTLS_ECC) ++ if (is_tls_ecdhe_psk_with_aes_128_cbc_sha_256(peer->handshake_params->cipher)) { ++ if (state != DTLS_STATE_WAIT_SERVERKEYEXCHANGE) { ++ return dtls_alert_fatal_create(DTLS_ALERT_UNEXPECTED_MESSAGE); ++ } ++ err = check_server_key_exchange_ecdhe_psk(ctx, peer, data, data_length); ++ } ++#endif defined(DTLS_PSK) && defined(DTLS_ECC) ++ + #ifdef DTLS_PSK + if (is_tls_psk_with_aes_128_ccm_8(peer->handshake_params->cipher)) { + if (state != DTLS_STATE_WAIT_SERVERHELLODONE) { +diff --git a/extlibs/tinydtls/global.h b/extlibs/tinydtls/global.h +index 169c726..8b3c518 100644 +--- a/extlibs/tinydtls/global.h ++++ b/extlibs/tinydtls/global.h +@@ -75,6 +75,7 @@ typedef enum { + TLS_NULL_WITH_NULL_NULL = 0x0000, /**< NULL cipher */ + TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256 = 0xC018, /**< see RFC 4492 */ + TLS_PSK_WITH_AES_128_CCM_8 = 0xC0A8, /**< see RFC 6655 */ ++ TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256 = 0xC037, /**< see RFC 5489 */ + TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 = 0xC0AE /**< see RFC 7251 */ + } dtls_cipher_t; + +diff --git a/extlibs/tinydtls/tests/dtls-client.c b/extlibs/tinydtls/tests/dtls-client.c +index dfc822a..dfd34c8 100644 +--- a/extlibs/tinydtls/tests/dtls-client.c ++++ b/extlibs/tinydtls/tests/dtls-client.c +@@ -311,7 +311,8 @@ usage( const char *program, const char *version) { + "\t-c num\t\tcipher suite (default: 1)\n" + "\t\t\t1: TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256 \n" + "\t\t\t2: TLS_PSK_WITH_AES_128_CCM_8\n" +- "\t\t\t3: TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8\n", ++ "\t\t\t3: TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8\n" ++ "\t\t\t4: TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256\n", + program, version, program, DEFAULT_PORT); + } + +@@ -430,6 +431,11 @@ main(int argc, char **argv) { + selected_cipher = TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 ; + ecdh_anon_enalbe = DTLS_CIPHER_DISABLE; + } ++ else if( strcmp(optarg, "4") == 0) ++ { ++ selected_cipher = TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256; ++ ecdh_anon_enalbe = DTLS_CIPHER_DISABLE; ++ } + break; + default: + usage(argv[0], dtls_package_version()); +-- +1.7.9.5 + diff --git a/extlibs/tinydtls/0001-Fix-the-wrong-implementation-about-the-anonymous-cip.patch b/extlibs/tinydtls/0001-Fix-the-wrong-implementation-about-the-anonymous-cip.patch new file mode 100644 index 0000000..e2b8e65 --- /dev/null +++ b/extlibs/tinydtls/0001-Fix-the-wrong-implementation-about-the-anonymous-cip.patch @@ -0,0 +1,690 @@ +From 1ee27820ccad59423711c83fb01ff58939511f3b Mon Sep 17 00:00:00 2001 +From: Sachin Agrawal +Date: Mon, 29 Jun 2015 22:26:21 -0700 +Subject: [PATCH 1/1] Fix the wrong implementation about the anonymous cipher + suite of tinydtls. (NOTE : This patch has been modified + based on RFC 5246) + +1. IV for CBC block operation + - Apply the random IV for CBC block operations according to section 6.2.3.2 of RFC 5246. + +2. MAC calculation + - Apply HMAC for DTLS MAC calculation according to section 6.2.3.1 of RFC 5246. + +3. CBC padding + - Apply PKCS#5 padding for CBC block cipher accroding to section 6.2.3.2 of RFC 5246. + +4. Change the cipher suite name TLS_ECDH_anon_WITH_AES_128_CBC_SHA + to TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256. + +5. Fix the minor bug in dtls sample. + +Change-Id: I8783caa6ac04fe2d46e242efe56e3205646b1038 +Signed-off-by: leechul +Signed-off-by: Sachin Agrawal +--- + extlibs/tinydtls/crypto.c | 100 +++++++++++++----- + extlibs/tinydtls/crypto.h | 1 + + extlibs/tinydtls/dtls.c | 111 +++++++++++++++----- + extlibs/tinydtls/dtls.h | 6 +- + extlibs/tinydtls/global.h | 2 +- + extlibs/tinydtls/tests/dtls-client.c | 8 +- + extlibs/tinydtls/tests/dtls-server.c | 8 +- + resource/csdk/connectivity/api/cainterface.h | 4 +- + resource/csdk/connectivity/inc/caadapternetdtls.h | 2 +- + .../src/adapter_util/caadapternetdtls.c | 2 +- + .../provisioning/src/provisioningmanager.c | 2 +- + 11 files changed, 180 insertions(+), 66 deletions(-) + +diff --git a/extlibs/tinydtls/crypto.c b/extlibs/tinydtls/crypto.c +index 5082535..3fbb993 100644 +--- a/extlibs/tinydtls/crypto.c ++++ b/extlibs/tinydtls/crypto.c +@@ -58,6 +58,7 @@ + #include "sha2/sha2.h" + #include "prng.h" + #include "netq.h" ++#include "hmac.h" + + #ifndef WITH_CONTIKI + #include +@@ -329,6 +330,7 @@ dtls_ccm_decrypt(aes128_t *ccm_ctx, const unsigned char *src, + + static size_t + dtls_cbc_encrypt(aes128_t *aes_ctx, ++ unsigned char *key, size_t keylen, + const unsigned char *iv, + const unsigned char *src, size_t srclen, + unsigned char *buf) { +@@ -336,18 +338,35 @@ dtls_cbc_encrypt(aes128_t *aes_ctx, + unsigned char cbc[DTLS_BLK_LENGTH]; + unsigned char tmp[DTLS_BLK_LENGTH]; + unsigned char *pos; +- dtls_hash_ctx shactx; ++ const unsigned char *dtls_hdr = NULL; + int i, j; + int blocks; ++ dtls_hmac_context_t* hmac_ctx = NULL; ++ int paddinglen = 0; + + pos = buf; + +- dtls_hash_init(&shactx); +- dtls_hash_update(&shactx, src, srclen); +- dtls_hash_finalize(pos + srclen, &shactx); ++ dtls_hdr = src - DTLS_CBC_IV_LENGTH - sizeof(dtls_record_header_t); ++ ++ //Calculate MAC : Append the MAC code to end of content ++ hmac_ctx = dtls_hmac_new(key, keylen); ++ dtls_mac(hmac_ctx, ++ dtls_hdr, ++ src, srclen, ++ buf + srclen); ++ dtls_hmac_free(hmac_ctx); ++ ++ dtls_debug_dump("[MAC]", ++ buf + srclen, ++ DTLS_HMAC_DIGEST_SIZE); ++ ++ paddinglen = DTLS_BLK_LENGTH - ((srclen + DTLS_HMAC_DIGEST_SIZE) % DTLS_BLK_LENGTH); ++ ++ //TLS padding ++ memset(buf + (srclen + DTLS_HMAC_DIGEST_SIZE), paddinglen - 1, paddinglen); + + memcpy(cbc, iv, DTLS_BLK_LENGTH); +- blocks = (srclen + SHA256_DIGEST_LENGTH) / DTLS_BLK_LENGTH; ++ blocks = (srclen + DTLS_HMAC_DIGEST_SIZE + paddinglen) / DTLS_BLK_LENGTH; + + for (i = 0; i < blocks; i++) { + for (j = 0; j < DTLS_BLK_LENGTH; j++) { +@@ -360,14 +379,17 @@ dtls_cbc_encrypt(aes128_t *aes_ctx, + pos += DTLS_BLK_LENGTH; + } + +- dtls_debug_dump("Encrypted Data:", buf, srclen + SHA256_DIGEST_LENGTH); +- +- return srclen + SHA256_DIGEST_LENGTH; ++ dtls_debug_dump("[Encrypted Data]", ++ buf, ++ srclen + DTLS_HMAC_DIGEST_SIZE + paddinglen); ++ ++ return srclen + DTLS_HMAC_DIGEST_SIZE + paddinglen; + } + + + static size_t + dtls_cbc_decrypt(aes128_t *aes_ctx, ++ unsigned char *key, size_t keylen, + const unsigned char *iv, + const unsigned char *src, size_t srclen, + unsigned char *buf) { +@@ -375,14 +397,17 @@ dtls_cbc_decrypt(aes128_t *aes_ctx, + unsigned char cbc[DTLS_BLK_LENGTH]; + unsigned char tmp[DTLS_BLK_LENGTH]; + unsigned char tmp2[DTLS_BLK_LENGTH]; +- unsigned char msg_hash[SHA256_DIGEST_LENGTH]; ++ unsigned char mac_buf[DTLS_HMAC_DIGEST_SIZE] = {0,}; ++ const unsigned char *dtls_hdr = NULL; + unsigned char *pos; +- dtls_hash_ctx shactx; + int i, j; + int blocks; ++ int depaddinglen = 0; ++ dtls_hmac_context_t* hmac_ctx = NULL; + + pos = buf; +- memcpy(pos, src, srclen); ++ ++ dtls_hdr = src - DTLS_CBC_IV_LENGTH - sizeof(dtls_record_header_t); + + memcpy(cbc, iv, DTLS_BLK_LENGTH); + blocks = srclen / DTLS_BLK_LENGTH; +@@ -401,19 +426,46 @@ dtls_cbc_decrypt(aes128_t *aes_ctx, + pos += DTLS_BLK_LENGTH; + } + +- dtls_hash_init(&shactx); +- dtls_hash_update(&shactx, buf, srclen - SHA256_DIGEST_LENGTH); +- dtls_hash_finalize(msg_hash, &shactx); +- +- dtls_debug_dump("decrypted data:", buf, srclen); ++ //de-padding ++ depaddinglen = buf[srclen -1]; + +- if(memcmp(msg_hash, buf + (srclen - SHA256_DIGEST_LENGTH), SHA256_DIGEST_LENGTH) != 0) ++ //Calculate MAC ++ hmac_ctx = dtls_hmac_new(key, keylen); ++ if(!hmac_ctx) { ++ return -1; ++ } ++ dtls_mac(hmac_ctx, dtls_hdr, buf, ++ srclen - DTLS_HMAC_DIGEST_SIZE - depaddinglen - 1, ++ mac_buf); ++ dtls_hmac_free(hmac_ctx); ++ ++ dtls_debug_dump("[MAC]", ++ mac_buf, ++ DTLS_HMAC_DIGEST_SIZE); ++ dtls_debug_dump("[Decrypted data]", ++ buf, ++ srclen - DTLS_HMAC_DIGEST_SIZE - depaddinglen - 1); ++ ++ //verify the MAC ++ if(memcmp(mac_buf, ++ buf + (srclen - DTLS_HMAC_DIGEST_SIZE - depaddinglen - 1), ++ DTLS_HMAC_DIGEST_SIZE) != 0) + { +- dtls_warn("message is broken\n"); ++ dtls_crit("Failed to verification of MAC\n"); + return -1; + } + +- return srclen - SHA256_DIGEST_LENGTH; ++ //verify the padding bytes ++ for (i =0; i < depaddinglen; i++) ++ { ++ if (buf[srclen - depaddinglen - 1 + i] != depaddinglen) ++ { ++ dtls_crit("Failed to verify padding bytes\n"); ++ return -1; ++ } ++ } ++ ++ return srclen - DTLS_HMAC_DIGEST_SIZE - depaddinglen - 1; + } + + #ifdef DTLS_PSK +@@ -523,8 +575,6 @@ void + dtls_ecdsa_create_sig_hash(const unsigned char *priv_key, size_t key_size, + const unsigned char *sign_hash, size_t sign_hash_size, + uint32_t point_r[9], uint32_t point_s[9]) { +- int ret; +- + uint8_t privateKey[32]; + uint8_t hashValue[32]; + uint8_t sign[64]; +@@ -615,7 +665,7 @@ dtls_encrypt(const unsigned char *src, size_t length, + memmove(buf, src, length); + ret = dtls_ccm_encrypt(&ctx->data, src, length, buf, nounce, aad, la); + } +- if(cipher == TLS_ECDH_anon_WITH_AES_128_CBC_SHA) { ++ if(cipher == TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256) { + ret = rijndael_set_key(&ctx->data.ctx, key, 8 * keylen); + if (ret < 0) { + /* cleanup everything in case the key has the wrong size */ +@@ -625,7 +675,7 @@ dtls_encrypt(const unsigned char *src, size_t length, + + if (src != buf) + memmove(buf, src, length); +- ret = dtls_cbc_encrypt(&ctx->data, nounce, src, length, buf); ++ ret = dtls_cbc_encrypt(&ctx->data, key, keylen, nounce, src, length, buf); + } + + error: +@@ -658,7 +708,7 @@ dtls_decrypt(const unsigned char *src, size_t length, + ret = dtls_ccm_decrypt(&ctx->data, src, length, buf, nounce, aad, la); + } + +- if(cipher == TLS_ECDH_anon_WITH_AES_128_CBC_SHA) { ++ if(cipher == TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256) { + ret = rijndael_set_key(&ctx->data.ctx, key, 8 * keylen); + if (ret < 0) { + /* cleanup everything in case the key has the wrong size */ +@@ -668,7 +718,7 @@ dtls_decrypt(const unsigned char *src, size_t length, + + if (src != buf) + memmove(buf, src, length); +- ret = dtls_cbc_decrypt(&ctx->data, nounce, src, length, buf); ++ ret = dtls_cbc_decrypt(&ctx->data, key, keylen, nounce, src, length, buf); + } + + error: +diff --git a/extlibs/tinydtls/crypto.h b/extlibs/tinydtls/crypto.h +index dd13ffa..a81d306 100644 +--- a/extlibs/tinydtls/crypto.h ++++ b/extlibs/tinydtls/crypto.h +@@ -46,6 +46,7 @@ + #define DTLS_BLK_LENGTH 16 /* AES-128 */ + #define DTLS_MAC_LENGTH DTLS_HMAC_DIGEST_SIZE + #define DTLS_IV_LENGTH 4 /* length of nonce_explicit */ ++#define DTLS_CBC_IV_LENGTH 16 + + /** + * Maximum size of the generated keyblock. Note that MAX_KEYBLOCK_LENGTH must +diff --git a/extlibs/tinydtls/dtls.c b/extlibs/tinydtls/dtls.c +index 41e68a5..b5b8fd1 100644 +--- a/extlibs/tinydtls/dtls.c ++++ b/extlibs/tinydtls/dtls.c +@@ -496,11 +496,11 @@ static inline int is_tls_psk_with_aes_128_ccm_8(dtls_cipher_t cipher) + #endif /* DTLS_PSK */ + } + +-/** returns true if the cipher matches TLS_ECDH_anon_WITH_AES_128_CBC_SHA */ +-static inline int is_tls_ecdh_anon_with_aes_128_cbc_sha(dtls_cipher_t cipher) ++/** returns true if the cipher matches TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256 */ ++static inline int is_tls_ecdh_anon_with_aes_128_cbc_sha_256(dtls_cipher_t cipher) + { + #ifdef DTLS_ECC +- return cipher == TLS_ECDH_anon_WITH_AES_128_CBC_SHA; ++ return cipher == TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256; + #else + return 0; + #endif +@@ -570,7 +570,7 @@ known_cipher(dtls_context_t *ctx, dtls_cipher_t code, int is_client) { + + return (psk && is_tls_psk_with_aes_128_ccm_8(code)) || + (ecdsa && is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(code)) || +- (ecdh_anon && is_tls_ecdh_anon_with_aes_128_cbc_sha(code)); ++ (ecdh_anon && is_tls_ecdh_anon_with_aes_128_cbc_sha_256(code)); + } + + /** +@@ -719,7 +719,7 @@ calculate_key_block(dtls_context_t *ctx, + #endif /* DTLS_PSK */ + #ifdef DTLS_ECC + case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8: +- case TLS_ECDH_anon_WITH_AES_128_CBC_SHA: { ++ case TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256: { + pre_master_len = dtls_ecdh_pre_master_secret(handshake->keyx.ecc.own_eph_priv, + handshake->keyx.ecc.other_eph_pub_x, + handshake->keyx.ecc.other_eph_pub_y, +@@ -1084,7 +1084,7 @@ check_client_keyexchange(dtls_context_t *ctx, + + #ifdef DTLS_ECC + if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(handshake->cipher) || +- is_tls_ecdh_anon_with_aes_128_cbc_sha(handshake->cipher) ) { ++ is_tls_ecdh_anon_with_aes_128_cbc_sha_256(handshake->cipher) ) { + + if (length < DTLS_HS_LENGTH + DTLS_CKXEC_LENGTH) { + dtls_debug("The client key exchange is too short\n"); +@@ -1286,6 +1286,51 @@ dtls_prepare_record(dtls_peer_t *peer, dtls_security_parameters_t *security, + p += data_len_array[i]; + res += data_len_array[i]; + } ++ } else if (is_tls_ecdh_anon_with_aes_128_cbc_sha_256(security->cipher)) { ++ ++ unsigned char nonce[DTLS_CBC_IV_LENGTH]; ++ ++ /** Add IV into body of packet in case of AES CBC mode according to RFC 5246, Section 6.2.3.2 ++ * ++ * opaque IV[SecurityParameters.record_iv_length]; ++ * block-ciphered struct { ++ * opaque content[TLSCompressed.length]; ++ * opaque MAC[SecurityParameters.mac_length]; ++ * uint8 padding[GenericBlockCipher.padding_length]; ++ * uint8 padding_length; ++ * }; ++ * ++ */ ++ ++ res = 0; ++ dtls_prng(nonce, DTLS_CBC_IV_LENGTH); ++ memcpy(p , nonce, DTLS_CBC_IV_LENGTH); ++ p += DTLS_CBC_IV_LENGTH; ++ res += DTLS_CBC_IV_LENGTH; ++ ++ for (i = 0; i < data_array_len; i++) { ++ /* check the minimum that we need for packets that are not encrypted */ ++ if (*rlen < res + DTLS_RH_LENGTH + data_len_array[i]) { ++ dtls_debug("dtls_prepare_record: send buffer too small\n"); ++ return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); ++ } ++ ++ memcpy(p, data_array[i], data_len_array[i]); ++ p += data_len_array[i]; ++ res += data_len_array[i]; ++ } ++ ++ res = dtls_encrypt(start + DTLS_CBC_IV_LENGTH, res - DTLS_CBC_IV_LENGTH, ++ start + DTLS_CBC_IV_LENGTH, nonce, ++ dtls_kb_local_write_key(security, peer->role), ++ dtls_kb_key_size(security, peer->role), ++ NULL, 0, ++ security->cipher); ++ if (res < 0) ++ return res; ++ ++ res += DTLS_CBC_IV_LENGTH; ++ + } else { /* TLS_PSK_WITH_AES_128_CCM_8 or TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 */ + /** + * length of additional_data for the AEAD cipher which consists of +@@ -1299,8 +1344,6 @@ dtls_prepare_record(dtls_peer_t *peer, dtls_security_parameters_t *security, + dtls_debug("dtls_prepare_record(): encrypt using TLS_PSK_WITH_AES_128_CCM_8\n"); + } else if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(security->cipher)) { + dtls_debug("dtls_prepare_record(): encrypt using TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8\n"); +- } else if (is_tls_ecdh_anon_with_aes_128_cbc_sha(security->cipher)) { +- dtls_debug("dtls_prepare_record() : encrypt using TLS_ECDH_anon_WITH_AES_128_CBC_SHA\n"); + } else { + dtls_debug("dtls_prepare_record(): encrypt using unknown cipher\n"); + } +@@ -1363,7 +1406,7 @@ dtls_prepare_record(dtls_peer_t *peer, dtls_security_parameters_t *security, + + memset(nonce, 0, DTLS_CCM_BLOCKSIZE); + memcpy(nonce, dtls_kb_local_iv(security, peer->role), +- dtls_kb_iv_size(security, peer->role)); ++ dtls_kb_iv_size(security, peer->role)); + memcpy(nonce + dtls_kb_iv_size(security, peer->role), start, 8); /* epoch + seq_num */ + + dtls_debug_dump("nonce:", nonce, DTLS_CCM_BLOCKSIZE); +@@ -1378,7 +1421,8 @@ dtls_prepare_record(dtls_peer_t *peer, dtls_security_parameters_t *security, + memcpy(A_DATA, &DTLS_RECORD_HEADER(sendbuf)->epoch, 8); /* epoch and seq_num */ + memcpy(A_DATA + 8, &DTLS_RECORD_HEADER(sendbuf)->content_type, 3); /* type and version */ + dtls_int_to_uint16(A_DATA + 11, res - 8); /* length */ +- ++ ++ + res = dtls_encrypt(start + 8, res - 8, start + 8, nonce, + dtls_kb_local_write_key(security, peer->role), + dtls_kb_key_size(security, peer->role), +@@ -1388,7 +1432,7 @@ dtls_prepare_record(dtls_peer_t *peer, dtls_security_parameters_t *security, + if (res < 0) + return res; + +- res += 8; /* increment res by size of nonce_explicit */ ++ res += 8; /* increment res by size of nonce_explicit */ + dtls_debug_dump("message:", start, res); + } + +@@ -2172,7 +2216,7 @@ dtls_send_server_hello_msgs(dtls_context_t *ctx, dtls_peer_t *peer) + } + + ecdsa = is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(peer->handshake_params->cipher); +- ecdh_anon = is_tls_ecdh_anon_with_aes_128_cbc_sha(peer->handshake_params->cipher); ++ ecdh_anon = is_tls_ecdh_anon_with_aes_128_cbc_sha_256(peer->handshake_params->cipher); + + #ifdef DTLS_ECC + if(ecdh_anon) { +@@ -2301,7 +2345,7 @@ dtls_send_client_key_exchange(dtls_context_t *ctx, dtls_peer_t *peer) + #endif /* DTLS_PSK */ + #ifdef DTLS_ECC + case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8: +- case TLS_ECDH_anon_WITH_AES_128_CBC_SHA: { ++ case TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256: { + uint8 *ephemeral_pub_x; + uint8 *ephemeral_pub_y; + +@@ -2424,7 +2468,7 @@ dtls_send_client_hello(dtls_context_t *ctx, dtls_peer_t *peer, + case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8: + ecdsa = is_ecdsa_supported(ctx, 1); + break; +- case TLS_ECDH_anon_WITH_AES_128_CBC_SHA: ++ case TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256: + ecdh_anon = is_ecdh_anon_supported(ctx); + break; + default: +@@ -2478,7 +2522,7 @@ dtls_send_client_hello(dtls_context_t *ctx, dtls_peer_t *peer, + p += sizeof(uint16); + + if (ecdh_anon) { +- dtls_int_to_uint16(p, TLS_ECDH_anon_WITH_AES_128_CBC_SHA); ++ dtls_int_to_uint16(p, TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256); + p += sizeof(uint16); + } + if (psk) { +@@ -2809,7 +2853,7 @@ check_server_key_exchange_ecdh(dtls_context_t *ctx, + + update_hs_hash(peer, data, data_length); + +- assert(is_tls_ecdh_anon_with_aes_128_cbc_sha(config->cipher)); ++ assert(is_tls_ecdh_anon_with_aes_128_cbc_sha_256(config->cipher)); + + data += DTLS_HS_LENGTH; + +@@ -3069,6 +3113,23 @@ decrypt_verify(dtls_peer_t *peer, uint8 *packet, size_t length, + if (security->cipher == TLS_NULL_WITH_NULL_NULL) { + /* no cipher suite selected */ + return clen; ++ } else if (is_tls_ecdh_anon_with_aes_128_cbc_sha_256(security->cipher)) { ++ ++ unsigned char nonce[DTLS_CBC_IV_LENGTH]; ++ ++ if (clen < (DTLS_CBC_IV_LENGTH + DTLS_HMAC_DIGEST_SIZE)) /* need at least IV and MAC */ ++ return -1; ++ ++ memcpy(nonce, *cleartext , DTLS_CBC_IV_LENGTH); ++ clen -= DTLS_CBC_IV_LENGTH; ++ *cleartext += DTLS_CBC_IV_LENGTH ; ++ ++ clen = dtls_decrypt(*cleartext, clen, *cleartext, nonce, ++ dtls_kb_remote_write_key(security, peer->role), ++ dtls_kb_key_size(security, peer->role), ++ NULL, 0, ++ security->cipher); ++ + } else { /* TLS_PSK_WITH_AES_128_CCM_8 or TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 */ + /** + * length of additional_data for the AEAD cipher which consists of +@@ -3083,7 +3144,7 @@ decrypt_verify(dtls_peer_t *peer, uint8 *packet, size_t length, + + memset(nonce, 0, DTLS_CCM_BLOCKSIZE); + memcpy(nonce, dtls_kb_remote_iv(security, peer->role), +- dtls_kb_iv_size(security, peer->role)); ++ dtls_kb_iv_size(security, peer->role)); + + /* read epoch and seq_num from message */ + memcpy(nonce + dtls_kb_iv_size(security, peer->role), *cleartext, 8); +@@ -3108,17 +3169,19 @@ decrypt_verify(dtls_peer_t *peer, uint8 *packet, size_t length, + dtls_kb_remote_write_key(security, peer->role), + dtls_kb_key_size(security, peer->role), + A_DATA, A_DATA_LEN, +- security->cipher); +- if (clen < 0) +- dtls_warn("decryption failed\n"); +- else { ++ security->cipher); ++ } ++ ++ if (clen < 0) ++ dtls_warn("decryption failed\n"); ++ else { + #ifndef NDEBUG + dtls_debug("decrypt_verify(): found %i bytes cleartext\n", clen); + #endif + dtls_security_params_free_other(peer); + dtls_debug_dump("cleartext", *cleartext, clen); +- } + } ++ + return clen; + } + +@@ -3219,7 +3282,7 @@ handle_handshake_msg(dtls_context_t *ctx, dtls_peer_t *peer, session_t *session, + } + if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(peer->handshake_params->cipher)) + peer->state = DTLS_STATE_WAIT_SERVERCERTIFICATE; //ecdsa +- else if (is_tls_ecdh_anon_with_aes_128_cbc_sha(peer->handshake_params->cipher)) ++ else if (is_tls_ecdh_anon_with_aes_128_cbc_sha_256(peer->handshake_params->cipher)) + peer->state = DTLS_STATE_WAIT_SERVERKEYEXCHANGE; //ecdh + else + peer->state = DTLS_STATE_WAIT_SERVERHELLODONE; //psk +@@ -3259,7 +3322,7 @@ handle_handshake_msg(dtls_context_t *ctx, dtls_peer_t *peer, session_t *session, + err = check_server_key_exchange_ecdsa(ctx, peer, data, data_length); + } + +- if (is_tls_ecdh_anon_with_aes_128_cbc_sha(peer->handshake_params->cipher)) { ++ if (is_tls_ecdh_anon_with_aes_128_cbc_sha_256(peer->handshake_params->cipher)) { + if (state != DTLS_STATE_WAIT_SERVERKEYEXCHANGE) { + return dtls_alert_fatal_create(DTLS_ALERT_UNEXPECTED_MESSAGE); + } +diff --git a/extlibs/tinydtls/dtls.h b/extlibs/tinydtls/dtls.h +index a2ab86e..7d2bc19 100644 +--- a/extlibs/tinydtls/dtls.h ++++ b/extlibs/tinydtls/dtls.h +@@ -238,7 +238,7 @@ typedef struct dtls_context_t { + + dtls_handler_t *h; /**< callback handlers */ + +- dtls_cipher_enable_t is_anon_ecdh_eabled; /**< enable/disable the TLS_ECDH_anon_WITH_AES_128_CBC_SHA */ ++ dtls_cipher_enable_t is_anon_ecdh_eabled; /**< enable/disable the TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256 */ + + dtls_cipher_t selected_cipher; /**< selected ciper suite for handshake */ + +@@ -268,7 +268,7 @@ static inline void dtls_set_handler(dtls_context_t *ctx, dtls_handler_t *h) { + } + + /** +- * @brief Enabling the TLS_ECDH_anon_WITH_AES_128_CBC_SHA ++ * @brief Enabling the TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256 + * + * @param ctx The DTLS context to use. + * @param is_enable DTLS_CIPHER_ENABLE(1) or DTLS_CIPHER_DISABLE(0) +@@ -279,7 +279,7 @@ void dtls_enables_anon_ecdh(dtls_context_t* ctx, dtls_cipher_enable_t is_enable) + * @brief Select the cipher suite for handshake + * + * @param ctx The DTLS context to use. +- * @param cipher TLS_ECDH_anon_WITH_AES_128_CBC_SHA (0xC018) ++ * @param cipher TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256 (0xC018) + * TLS_PSK_WITH_AES_128_CCM_8 (0xX0A8) + * TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 (0xC0AE) + */ +diff --git a/extlibs/tinydtls/global.h b/extlibs/tinydtls/global.h +index 441710f..169c726 100644 +--- a/extlibs/tinydtls/global.h ++++ b/extlibs/tinydtls/global.h +@@ -73,7 +73,7 @@ typedef unsigned char uint48[6]; + /** Known cipher suites.*/ + typedef enum { + TLS_NULL_WITH_NULL_NULL = 0x0000, /**< NULL cipher */ +- TLS_ECDH_anon_WITH_AES_128_CBC_SHA = 0xC018, /**< see RFC 4492 */ ++ TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256 = 0xC018, /**< see RFC 4492 */ + TLS_PSK_WITH_AES_128_CCM_8 = 0xC0A8, /**< see RFC 6655 */ + TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 = 0xC0AE /**< see RFC 7251 */ + } dtls_cipher_t; +diff --git a/extlibs/tinydtls/tests/dtls-client.c b/extlibs/tinydtls/tests/dtls-client.c +index 35521e9..dfc822a 100644 +--- a/extlibs/tinydtls/tests/dtls-client.c ++++ b/extlibs/tinydtls/tests/dtls-client.c +@@ -309,7 +309,7 @@ usage( const char *program, const char *version) { + "\t-p port\t\tlisten on specified port (default is %d)\n" + "\t-v num\t\tverbosity level (default: 3)\n" + "\t-c num\t\tcipher suite (default: 1)\n" +- "\t\t\t1: TLS_ECDH_anon_WITH_AES_128_CBC_SHA \n" ++ "\t\t\t1: TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256 \n" + "\t\t\t2: TLS_PSK_WITH_AES_128_CCM_8\n" + "\t\t\t3: TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8\n", + program, version, program, DEFAULT_PORT); +@@ -347,7 +347,7 @@ main(int argc, char **argv) { + log_t log_level = DTLS_LOG_WARN; + int fd, result; + int on = 1; +- dtls_cipher_t selected_cipher = TLS_ECDH_anon_WITH_AES_128_CBC_SHA; ++ dtls_cipher_t selected_cipher = TLS_NULL_WITH_NULL_NULL; + dtls_cipher_enable_t ecdh_anon_enalbe = DTLS_CIPHER_ENABLE; + int opt, res; + session_t dst; +@@ -417,7 +417,7 @@ main(int argc, char **argv) { + case 'c': + if( strcmp(optarg, "1") == 0) + { +- selected_cipher = TLS_ECDH_anon_WITH_AES_128_CBC_SHA; ++ selected_cipher = TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256; + ecdh_anon_enalbe = DTLS_CIPHER_ENABLE; + } + else if( strcmp(optarg, "2") == 0) +@@ -500,7 +500,7 @@ main(int argc, char **argv) { + /* select cipher suite */ + dtls_select_cipher(dtls_context, selected_cipher); + +- /* enable/disable tls_ecdh_anon_with_aes_128_cbc_sha */ ++ /* enable/disable tls_ecdh_anon_with_aes_128_cbc_sha_256 */ + dtls_enables_anon_ecdh(dtls_context, ecdh_anon_enalbe); + + dtls_set_handler(dtls_context, &cb); +diff --git a/extlibs/tinydtls/tests/dtls-server.c b/extlibs/tinydtls/tests/dtls-server.c +index d3da1a7..5893084 100644 +--- a/extlibs/tinydtls/tests/dtls-server.c ++++ b/extlibs/tinydtls/tests/dtls-server.c +@@ -254,8 +254,8 @@ usage(const char *program, const char *version) { + "\t-p port\t\tlisten on specified port (default is %d)\n" + "\t-v num\t\tverbosity level (default: 3)\n" + "\t-a enable|disable\t(default: disable)\n" +- "\t\t\t\tenable:enable TLS_ECDH_anon_with_AES_128_CBC_SHA\n" +- "\t\t\t\tdisable:disable TLS_ECDH_anon_with_AES_128_CBC_SHA\n", ++ "\t\t\t\tenable:enable TLS_ECDH_anon_with_AES_128_CBC_SHA_256\n" ++ "\t\t\t\tdisable:disable TLS_ECDH_anon_with_AES_128_CBC_SHA_256\n", + program, version, program, DEFAULT_PORT); + } + +@@ -280,7 +280,7 @@ main(int argc, char **argv) { + struct timeval timeout; + int fd, opt, result; + int on = 1; +- int ecdh_anon_enalbe = DTLS_CIPHER_DISABLE; ++ dtls_cipher_enable_t ecdh_anon_enalbe = DTLS_CIPHER_DISABLE; + struct sockaddr_in6 listen_addr; + + memset(&listen_addr, 0, sizeof(struct sockaddr_in6)); +@@ -356,7 +356,7 @@ main(int argc, char **argv) { + + the_context = dtls_new_context(&fd); + +- /* enable/disable tls_ecdh_anon_with_aes_128_cbc_sha */ ++ /* enable/disable tls_ecdh_anon_with_aes_128_cbc_sha_256 */ + dtls_enables_anon_ecdh(the_context, ecdh_anon_enalbe); + + dtls_set_handler(the_context, &cb); +diff --git a/resource/csdk/connectivity/api/cainterface.h b/resource/csdk/connectivity/api/cainterface.h +index 760df09..2f10fd5 100644 +--- a/resource/csdk/connectivity/api/cainterface.h ++++ b/resource/csdk/connectivity/api/cainterface.h +@@ -290,7 +290,7 @@ CAResult_t CAHandleRequestResponse(); + * Select the cipher suite for dtls handshake + * + * @param[IN] cipher cipher suite (Note : Make sure endianness) +- * 0xC018 : TLS_ECDH_anon_WITH_AES_128_CBC_SHA ++ * 0xC018 : TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256 + * 0xC0A8 : TLS_PSK_WITH_AES_128_CCM_8 + * 0xC0AE : TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 + * +@@ -301,7 +301,7 @@ CAResult_t CAHandleRequestResponse(); + CAResult_t CASelectCipherSuite(const uint16_t cipher); + + /** +- * Enable TLS_ECDH_anon_WITH_AES_128_CBC_SHA cipher suite in dtls ++ * Enable TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256 cipher suite in dtls + * + * @param[IN] enable TRUE/FALSE enables/disables anonymous cipher suite + * +diff --git a/resource/csdk/connectivity/inc/caadapternetdtls.h b/resource/csdk/connectivity/inc/caadapternetdtls.h +index f9f99d8..274321e 100644 +--- a/resource/csdk/connectivity/inc/caadapternetdtls.h ++++ b/resource/csdk/connectivity/inc/caadapternetdtls.h +@@ -160,7 +160,7 @@ void CADTLSSetCredentialsCallback(CAGetDTLSCredentialsHandler credCallback); + * Select the cipher suite for dtls handshake + * + * @param[in] cipher cipher suite +- * 0xC018 : TLS_ECDH_anon_WITH_AES_128_CBC_SHA ++ * 0xC018 : TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256 + * 0xC0A8 : TLS_PSK_WITH_AES_128_CCM_8 + * 0xC0AE : TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 + * +diff --git a/resource/csdk/connectivity/src/adapter_util/caadapternetdtls.c b/resource/csdk/connectivity/src/adapter_util/caadapternetdtls.c +index 8f01c06..6fd83e8 100644 +--- a/resource/csdk/connectivity/src/adapter_util/caadapternetdtls.c ++++ b/resource/csdk/connectivity/src/adapter_util/caadapternetdtls.c +@@ -598,7 +598,7 @@ CAResult_t CADtlsEnableAnonECDHCipherSuite(const bool enable) + dtls_enables_anon_ecdh(g_caDtlsContext->dtlsContext, + enable == true ? DTLS_CIPHER_ENABLE : DTLS_CIPHER_DISABLE); + ca_mutex_unlock(g_dtlsContextMutex); +- OIC_LOG_V(DEBUG, NET_DTLS_TAG, "TLS_ECDH_anon_WITH_AES_128_CBC_SHA is %s", ++ OIC_LOG_V(DEBUG, NET_DTLS_TAG, "TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256 is %s", + enable ? "enabled" : "disabled"); + + OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT CADtlsEnablesAnonEcdh"); +diff --git a/resource/csdk/security/provisioning/src/provisioningmanager.c b/resource/csdk/security/provisioning/src/provisioningmanager.c +index defe4e6..301614d 100644 +--- a/resource/csdk/security/provisioning/src/provisioningmanager.c ++++ b/resource/csdk/security/provisioning/src/provisioningmanager.c +@@ -1031,7 +1031,7 @@ static SPResult updateOperationMode(unsigned short timeout, SPTargetDeviceInfo_t + */ + static SPResult initiateDtlsHandshake(const SPTargetDeviceInfo_t *deviceInfo) + { +- CAResult_t caresult = CASelectCipherSuite(TLS_ECDH_anon_WITH_AES_128_CBC_SHA); ++ CAResult_t caresult = CASelectCipherSuite(TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256); + + if (CA_STATUS_OK != caresult) + { +-- +1.7.9.5 + diff --git a/extlibs/tinydtls/crypto.c b/extlibs/tinydtls/crypto.c index 5082535..deaf581 100644 --- a/extlibs/tinydtls/crypto.c +++ b/extlibs/tinydtls/crypto.c @@ -58,6 +58,7 @@ #include "sha2/sha2.h" #include "prng.h" #include "netq.h" +#include "hmac.h" #ifndef WITH_CONTIKI #include @@ -329,6 +330,7 @@ dtls_ccm_decrypt(aes128_t *ccm_ctx, const unsigned char *src, static size_t dtls_cbc_encrypt(aes128_t *aes_ctx, + unsigned char *key, size_t keylen, const unsigned char *iv, const unsigned char *src, size_t srclen, unsigned char *buf) { @@ -336,18 +338,35 @@ dtls_cbc_encrypt(aes128_t *aes_ctx, unsigned char cbc[DTLS_BLK_LENGTH]; unsigned char tmp[DTLS_BLK_LENGTH]; unsigned char *pos; - dtls_hash_ctx shactx; + const unsigned char *dtls_hdr = NULL; int i, j; int blocks; + dtls_hmac_context_t* hmac_ctx = NULL; + int paddinglen = 0; pos = buf; - dtls_hash_init(&shactx); - dtls_hash_update(&shactx, src, srclen); - dtls_hash_finalize(pos + srclen, &shactx); + dtls_hdr = src - DTLS_CBC_IV_LENGTH - sizeof(dtls_record_header_t); + + //Calculate MAC : Append the MAC code to end of content + hmac_ctx = dtls_hmac_new(key, keylen); + dtls_mac(hmac_ctx, + dtls_hdr, + src, srclen, + buf + srclen); + dtls_hmac_free(hmac_ctx); + + dtls_debug_dump("[MAC]", + buf + srclen, + DTLS_HMAC_DIGEST_SIZE); + + paddinglen = DTLS_BLK_LENGTH - ((srclen + DTLS_HMAC_DIGEST_SIZE) % DTLS_BLK_LENGTH); + + //TLS padding + memset(buf + (srclen + DTLS_HMAC_DIGEST_SIZE), paddinglen - 1, paddinglen); memcpy(cbc, iv, DTLS_BLK_LENGTH); - blocks = (srclen + SHA256_DIGEST_LENGTH) / DTLS_BLK_LENGTH; + blocks = (srclen + DTLS_HMAC_DIGEST_SIZE + paddinglen) / DTLS_BLK_LENGTH; for (i = 0; i < blocks; i++) { for (j = 0; j < DTLS_BLK_LENGTH; j++) { @@ -360,14 +379,17 @@ dtls_cbc_encrypt(aes128_t *aes_ctx, pos += DTLS_BLK_LENGTH; } - dtls_debug_dump("Encrypted Data:", buf, srclen + SHA256_DIGEST_LENGTH); - - return srclen + SHA256_DIGEST_LENGTH; + dtls_debug_dump("[Encrypted Data]", + buf, + srclen + DTLS_HMAC_DIGEST_SIZE + paddinglen); + + return srclen + DTLS_HMAC_DIGEST_SIZE + paddinglen; } static size_t dtls_cbc_decrypt(aes128_t *aes_ctx, + unsigned char *key, size_t keylen, const unsigned char *iv, const unsigned char *src, size_t srclen, unsigned char *buf) { @@ -375,14 +397,17 @@ dtls_cbc_decrypt(aes128_t *aes_ctx, unsigned char cbc[DTLS_BLK_LENGTH]; unsigned char tmp[DTLS_BLK_LENGTH]; unsigned char tmp2[DTLS_BLK_LENGTH]; - unsigned char msg_hash[SHA256_DIGEST_LENGTH]; + unsigned char mac_buf[DTLS_HMAC_DIGEST_SIZE] = {0,}; + const unsigned char *dtls_hdr = NULL; unsigned char *pos; - dtls_hash_ctx shactx; int i, j; int blocks; + int depaddinglen = 0; + dtls_hmac_context_t* hmac_ctx = NULL; pos = buf; - memcpy(pos, src, srclen); + + dtls_hdr = src - DTLS_CBC_IV_LENGTH - sizeof(dtls_record_header_t); memcpy(cbc, iv, DTLS_BLK_LENGTH); blocks = srclen / DTLS_BLK_LENGTH; @@ -401,19 +426,46 @@ dtls_cbc_decrypt(aes128_t *aes_ctx, pos += DTLS_BLK_LENGTH; } - dtls_hash_init(&shactx); - dtls_hash_update(&shactx, buf, srclen - SHA256_DIGEST_LENGTH); - dtls_hash_finalize(msg_hash, &shactx); - - dtls_debug_dump("decrypted data:", buf, srclen); + //de-padding + depaddinglen = buf[srclen -1]; - if(memcmp(msg_hash, buf + (srclen - SHA256_DIGEST_LENGTH), SHA256_DIGEST_LENGTH) != 0) + //Calculate MAC + hmac_ctx = dtls_hmac_new(key, keylen); + if(!hmac_ctx) { + return -1; + } + dtls_mac(hmac_ctx, dtls_hdr, buf, + srclen - DTLS_HMAC_DIGEST_SIZE - depaddinglen - 1, + mac_buf); + dtls_hmac_free(hmac_ctx); + + dtls_debug_dump("[MAC]", + mac_buf, + DTLS_HMAC_DIGEST_SIZE); + dtls_debug_dump("[Decrypted data]", + buf, + srclen - DTLS_HMAC_DIGEST_SIZE - depaddinglen - 1); + + //verify the MAC + if(memcmp(mac_buf, + buf + (srclen - DTLS_HMAC_DIGEST_SIZE - depaddinglen - 1), + DTLS_HMAC_DIGEST_SIZE) != 0) { - dtls_warn("message is broken\n"); + dtls_crit("Failed to verification of MAC\n"); return -1; } - return srclen - SHA256_DIGEST_LENGTH; + //verify the padding bytes + for (i =0; i < depaddinglen; i++) + { + if (buf[srclen - depaddinglen - 1 + i] != depaddinglen) + { + dtls_crit("Failed to verify padding bytes\n"); + return -1; + } + } + + return srclen - DTLS_HMAC_DIGEST_SIZE - depaddinglen - 1; } #ifdef DTLS_PSK @@ -523,8 +575,6 @@ void dtls_ecdsa_create_sig_hash(const unsigned char *priv_key, size_t key_size, const unsigned char *sign_hash, size_t sign_hash_size, uint32_t point_r[9], uint32_t point_s[9]) { - int ret; - uint8_t privateKey[32]; uint8_t hashValue[32]; uint8_t sign[64]; @@ -591,6 +641,41 @@ dtls_ecdsa_verify_sig(const unsigned char *pub_key_x, } #endif /* DTLS_ECC */ +#if defined(DTLS_PSK) && defined(DTLS_ECC) +int dtls_ecdhe_psk_pre_master_secret(unsigned char *psk, size_t psklen, + unsigned char *ecc_priv_key, + unsigned char *ecc_pub_key_x, + unsigned char *ecc_pub_key_y, + size_t ecc_key_size, + unsigned char *result, + size_t result_len) +{ + uint8_t eccPublicKey[64]; + uint8_t eccPrivateKey[32]; + unsigned char *p = result; + + if (result_len < uECC_BYTES + psklen + (sizeof(uint16) * 2)) { + return -1; + } + + dtls_int_to_uint16(p, uECC_BYTES); + p += sizeof(uint16); + + memcpy(eccPublicKey, ecc_pub_key_x, 32); + memcpy(eccPublicKey + 32, ecc_pub_key_y, 32); + memcpy(eccPrivateKey, ecc_priv_key, 32); + uECC_shared_secret(eccPublicKey, eccPrivateKey, p); + p += uECC_BYTES; + + dtls_int_to_uint16(p, psklen); + p += sizeof(uint16); + + memcpy(p, psk, psklen); + + return uECC_BYTES + psklen + (sizeof(uint16) * 2); +} +#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */ + int dtls_encrypt(const unsigned char *src, size_t length, unsigned char *buf, @@ -615,7 +700,8 @@ dtls_encrypt(const unsigned char *src, size_t length, memmove(buf, src, length); ret = dtls_ccm_encrypt(&ctx->data, src, length, buf, nounce, aad, la); } - if(cipher == TLS_ECDH_anon_WITH_AES_128_CBC_SHA) { + if(cipher == TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256 || + cipher == TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256) { ret = rijndael_set_key(&ctx->data.ctx, key, 8 * keylen); if (ret < 0) { /* cleanup everything in case the key has the wrong size */ @@ -625,7 +711,7 @@ dtls_encrypt(const unsigned char *src, size_t length, if (src != buf) memmove(buf, src, length); - ret = dtls_cbc_encrypt(&ctx->data, nounce, src, length, buf); + ret = dtls_cbc_encrypt(&ctx->data, key, keylen, nounce, src, length, buf); } error: @@ -658,7 +744,8 @@ dtls_decrypt(const unsigned char *src, size_t length, ret = dtls_ccm_decrypt(&ctx->data, src, length, buf, nounce, aad, la); } - if(cipher == TLS_ECDH_anon_WITH_AES_128_CBC_SHA) { + if(cipher == TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256 || + cipher == TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256) { ret = rijndael_set_key(&ctx->data.ctx, key, 8 * keylen); if (ret < 0) { /* cleanup everything in case the key has the wrong size */ @@ -668,7 +755,7 @@ dtls_decrypt(const unsigned char *src, size_t length, if (src != buf) memmove(buf, src, length); - ret = dtls_cbc_decrypt(&ctx->data, nounce, src, length, buf); + ret = dtls_cbc_decrypt(&ctx->data, key, keylen, nounce, src, length, buf); } error: diff --git a/extlibs/tinydtls/crypto.h b/extlibs/tinydtls/crypto.h index dd13ffa..f4cfc66 100644 --- a/extlibs/tinydtls/crypto.h +++ b/extlibs/tinydtls/crypto.h @@ -39,6 +39,7 @@ #include "numeric.h" #include "hmac.h" #include "ccm.h" +#include "ecc/ecc.h" /* TLS_PSK_WITH_AES_128_CCM_8 */ #define DTLS_MAC_KEY_LENGTH 0 @@ -46,6 +47,7 @@ #define DTLS_BLK_LENGTH 16 /* AES-128 */ #define DTLS_MAC_LENGTH DTLS_HMAC_DIGEST_SIZE #define DTLS_IV_LENGTH 4 /* length of nonce_explicit */ +#define DTLS_CBC_IV_LENGTH 16 /** * Maximum size of the generated keyblock. Note that MAX_KEYBLOCK_LENGTH must @@ -128,6 +130,13 @@ typedef struct { dtls_compression_t compression; /**< compression method */ dtls_cipher_t cipher; /**< cipher type */ unsigned int do_client_auth:1; + +#ifdef DTLS_ECC && DTLS_PSK + struct keyx_t { + dtls_handshake_parameters_ecc_t ecc; + dtls_handshake_parameters_psk_t psk; + } keyx; +#else /* DTLS_ECC && DTLS_PSK */ union { #ifdef DTLS_ECC dtls_handshake_parameters_ecc_t ecc; @@ -136,6 +145,7 @@ typedef struct { dtls_handshake_parameters_psk_t psk; #endif /* DTLS_PSK */ } keyx; +#endif /* DTLS_ECC && DTLS_PSK */ } dtls_handshake_parameters_t; /* The following macros provide access to the components of the diff --git a/extlibs/tinydtls/dtls.c b/extlibs/tinydtls/dtls.c index 41e68a5..6104a08 100644 --- a/extlibs/tinydtls/dtls.c +++ b/extlibs/tinydtls/dtls.c @@ -496,16 +496,27 @@ static inline int is_tls_psk_with_aes_128_ccm_8(dtls_cipher_t cipher) #endif /* DTLS_PSK */ } -/** returns true if the cipher matches TLS_ECDH_anon_WITH_AES_128_CBC_SHA */ -static inline int is_tls_ecdh_anon_with_aes_128_cbc_sha(dtls_cipher_t cipher) +/** returns true if the cipher matches TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256 */ +static inline int is_tls_ecdh_anon_with_aes_128_cbc_sha_256(dtls_cipher_t cipher) { #ifdef DTLS_ECC - return cipher == TLS_ECDH_anon_WITH_AES_128_CBC_SHA; + return cipher == TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256; #else return 0; #endif } +/** returns true if the cipher matches TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256 */ +static inline int is_tls_ecdhe_psk_with_aes_128_cbc_sha_256(dtls_cipher_t cipher) +{ +#if defined(DTLS_ECC) && defined(DTLS_PSK) + return cipher == TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256; +#else + return 0; +#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */ +} + + /** returns true if the application is configured for psk */ static inline int is_psk_supported(dtls_context_t *ctx) @@ -549,6 +560,17 @@ static inline int is_ecdh_anon_supported(dtls_context_t *ctx) #endif } +/** returns true if ecdhe_psk_with_aes_128_cbc_sha_256 is supported */ +static inline int is_ecdhe_psk_supported(dtls_context_t *ctx) +{ +#if defined(DTLS_ECC) && defined(DTLS_PSK) + return is_psk_supported(ctx); +#else + return 0; +#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */ +} + + /** * Returns @c 1 if @p code is a cipher suite other than @c * TLS_NULL_WITH_NULL_NULL that we recognize. @@ -563,14 +585,17 @@ known_cipher(dtls_context_t *ctx, dtls_cipher_t code, int is_client) { int psk; int ecdsa; int ecdh_anon; + int ecdhe_psk; psk = is_psk_supported(ctx); ecdsa = is_ecdsa_supported(ctx, is_client); ecdh_anon = is_ecdh_anon_supported(ctx); + ecdhe_psk = is_ecdhe_psk_supported(ctx); return (psk && is_tls_psk_with_aes_128_ccm_8(code)) || (ecdsa && is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(code)) || - (ecdh_anon && is_tls_ecdh_anon_with_aes_128_cbc_sha(code)); + (ecdh_anon && is_tls_ecdh_anon_with_aes_128_cbc_sha_256(code)) || + (ecdhe_psk && is_tls_ecdhe_psk_with_aes_128_cbc_sha_256(code)); } /** @@ -676,7 +701,11 @@ calculate_key_block(dtls_context_t *ctx, dtls_peer_t *peer, session_t *session, dtls_peer_type role) { - unsigned char *pre_master_secret; +#if defined(DTLS_PSK) && defined(DTLS_ECC) + unsigned char pre_master_secret[MAX_KEYBLOCK_LENGTH + uECC_BYTES]; +#else + unsigned char pre_master_secret[MAX_KEYBLOCK_LENGTH]; +#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */ int pre_master_len = 0; dtls_security_parameters_t *security = dtls_security_params_next(peer); uint8 master_secret[DTLS_MASTER_SECRET_LENGTH]; @@ -685,8 +714,6 @@ calculate_key_block(dtls_context_t *ctx, return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); } - pre_master_secret = security->key_block; - switch (handshake->cipher) { #ifdef DTLS_PSK case TLS_PSK_WITH_AES_128_CCM_8: { @@ -719,7 +746,7 @@ calculate_key_block(dtls_context_t *ctx, #endif /* DTLS_PSK */ #ifdef DTLS_ECC case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8: - case TLS_ECDH_anon_WITH_AES_128_CBC_SHA: { + case TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256: { pre_master_len = dtls_ecdh_pre_master_secret(handshake->keyx.ecc.own_eph_priv, handshake->keyx.ecc.other_eph_pub_x, handshake->keyx.ecc.other_eph_pub_y, @@ -733,6 +760,35 @@ calculate_key_block(dtls_context_t *ctx, break; } #endif /* DTLS_ECC */ +#if defined(DTLS_PSK) && defined(DTLS_ECC) + case TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256: { + unsigned char psk[DTLS_PSK_MAX_KEY_LEN]; + int psklen; + + psklen = CALL(ctx, get_psk_info, session, DTLS_PSK_KEY, + handshake->keyx.psk.identity, + handshake->keyx.psk.id_length, + psk, DTLS_PSK_MAX_KEY_LEN); + if (psklen < 0) { + dtls_crit("no psk key for session available\n"); + return psklen; + } + + pre_master_len = dtls_ecdhe_psk_pre_master_secret(psk, psklen, + handshake->keyx.ecc.own_eph_priv, + handshake->keyx.ecc.other_eph_pub_x, + handshake->keyx.ecc.other_eph_pub_y, + sizeof(handshake->keyx.ecc.own_eph_priv), + pre_master_secret, + MAX_KEYBLOCK_LENGTH + uECC_BYTES); + + if (pre_master_len < 0) { + dtls_crit("the curve was too long, for the pre master secret\n"); + return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); + } + break; + } +#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */ default: dtls_crit("calculate_key_block: unknown cipher\n"); return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); @@ -1084,7 +1140,7 @@ check_client_keyexchange(dtls_context_t *ctx, #ifdef DTLS_ECC if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(handshake->cipher) || - is_tls_ecdh_anon_with_aes_128_cbc_sha(handshake->cipher) ) { + is_tls_ecdh_anon_with_aes_128_cbc_sha_256(handshake->cipher) ) { if (length < DTLS_HS_LENGTH + DTLS_CKXEC_LENGTH) { dtls_debug("The client key exchange is too short\n"); @@ -1113,6 +1169,56 @@ check_client_keyexchange(dtls_context_t *ctx, data += sizeof(handshake->keyx.ecc.other_eph_pub_y); } #endif /* DTLS_ECC */ +#if defined(DTLS_PSK) && defined(DTLS_ECC) + if (is_tls_ecdhe_psk_with_aes_128_cbc_sha_256(handshake->cipher)) { + int id_length; + + if (length < DTLS_HS_LENGTH + DTLS_CKXEC_LENGTH) { + dtls_debug("The client key exchange is too short\n"); + return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); + } + data += DTLS_HS_LENGTH; + + //PSK hint + id_length = dtls_uint16_to_int(data); + data += sizeof(uint16); + + if (DTLS_HS_LENGTH + DTLS_CKXPSK_LENGTH_MIN + DTLS_CKXEC_LENGTH + id_length != length) { + dtls_debug("The identity has a wrong length\n"); + return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); + } + + if (id_length > DTLS_PSK_MAX_CLIENT_IDENTITY_LEN) { + dtls_warn("please use a smaller client identity\n"); + return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); + } + + handshake->keyx.psk.id_length = id_length; + memcpy(handshake->keyx.psk.identity, data, id_length); + data += id_length; + + //ECDH public + if (dtls_uint8_to_int(data) != 1 + 2 * DTLS_EC_KEY_SIZE) { + dtls_alert("expected 65 bytes long public point\n"); + return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); + } + data += sizeof(uint8); + + if (dtls_uint8_to_int(data) != 4) { + dtls_alert("expected uncompressed public point\n"); + return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); + } + data += sizeof(uint8); + + memcpy(handshake->keyx.ecc.other_eph_pub_x, data, + sizeof(handshake->keyx.ecc.other_eph_pub_x)); + data += sizeof(handshake->keyx.ecc.other_eph_pub_x); + + memcpy(handshake->keyx.ecc.other_eph_pub_y, data, + sizeof(handshake->keyx.ecc.other_eph_pub_y)); + data += sizeof(handshake->keyx.ecc.other_eph_pub_y); + } +#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */ #ifdef DTLS_PSK if (is_tls_psk_with_aes_128_ccm_8(handshake->cipher)) { int id_length; @@ -1286,6 +1392,52 @@ dtls_prepare_record(dtls_peer_t *peer, dtls_security_parameters_t *security, p += data_len_array[i]; res += data_len_array[i]; } + } else if (is_tls_ecdh_anon_with_aes_128_cbc_sha_256(security->cipher) || + is_tls_ecdhe_psk_with_aes_128_cbc_sha_256(security->cipher)) { + + unsigned char nonce[DTLS_CBC_IV_LENGTH]; + + /** Add IV into body of packet in case of AES CBC mode according to RFC 5246, Section 6.2.3.2 + * + * opaque IV[SecurityParameters.record_iv_length]; + * block-ciphered struct { + * opaque content[TLSCompressed.length]; + * opaque MAC[SecurityParameters.mac_length]; + * uint8 padding[GenericBlockCipher.padding_length]; + * uint8 padding_length; + * }; + * + */ + + res = 0; + dtls_prng(nonce, DTLS_CBC_IV_LENGTH); + memcpy(p , nonce, DTLS_CBC_IV_LENGTH); + p += DTLS_CBC_IV_LENGTH; + res += DTLS_CBC_IV_LENGTH; + + for (i = 0; i < data_array_len; i++) { + /* check the minimum that we need for packets that are not encrypted */ + if (*rlen < res + DTLS_RH_LENGTH + data_len_array[i]) { + dtls_debug("dtls_prepare_record: send buffer too small\n"); + return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); + } + + memcpy(p, data_array[i], data_len_array[i]); + p += data_len_array[i]; + res += data_len_array[i]; + } + + res = dtls_encrypt(start + DTLS_CBC_IV_LENGTH, res - DTLS_CBC_IV_LENGTH, + start + DTLS_CBC_IV_LENGTH, nonce, + dtls_kb_local_write_key(security, peer->role), + dtls_kb_key_size(security, peer->role), + NULL, 0, + security->cipher); + if (res < 0) + return res; + + res += DTLS_CBC_IV_LENGTH; + } else { /* TLS_PSK_WITH_AES_128_CCM_8 or TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 */ /** * length of additional_data for the AEAD cipher which consists of @@ -1299,8 +1451,6 @@ dtls_prepare_record(dtls_peer_t *peer, dtls_security_parameters_t *security, dtls_debug("dtls_prepare_record(): encrypt using TLS_PSK_WITH_AES_128_CCM_8\n"); } else if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(security->cipher)) { dtls_debug("dtls_prepare_record(): encrypt using TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8\n"); - } else if (is_tls_ecdh_anon_with_aes_128_cbc_sha(security->cipher)) { - dtls_debug("dtls_prepare_record() : encrypt using TLS_ECDH_anon_WITH_AES_128_CBC_SHA\n"); } else { dtls_debug("dtls_prepare_record(): encrypt using unknown cipher\n"); } @@ -1363,7 +1513,7 @@ dtls_prepare_record(dtls_peer_t *peer, dtls_security_parameters_t *security, memset(nonce, 0, DTLS_CCM_BLOCKSIZE); memcpy(nonce, dtls_kb_local_iv(security, peer->role), - dtls_kb_iv_size(security, peer->role)); + dtls_kb_iv_size(security, peer->role)); memcpy(nonce + dtls_kb_iv_size(security, peer->role), start, 8); /* epoch + seq_num */ dtls_debug_dump("nonce:", nonce, DTLS_CCM_BLOCKSIZE); @@ -1378,7 +1528,8 @@ dtls_prepare_record(dtls_peer_t *peer, dtls_security_parameters_t *security, memcpy(A_DATA, &DTLS_RECORD_HEADER(sendbuf)->epoch, 8); /* epoch and seq_num */ memcpy(A_DATA + 8, &DTLS_RECORD_HEADER(sendbuf)->content_type, 3); /* type and version */ dtls_int_to_uint16(A_DATA + 11, res - 8); /* length */ - + + res = dtls_encrypt(start + 8, res - 8, start + 8, nonce, dtls_kb_local_write_key(security, peer->role), dtls_kb_key_size(security, peer->role), @@ -1388,7 +1539,7 @@ dtls_prepare_record(dtls_peer_t *peer, dtls_security_parameters_t *security, if (res < 0) return res; - res += 8; /* increment res by size of nonce_explicit */ + res += 8; /* increment res by size of nonce_explicit */ dtls_debug_dump("message:", start, res); } @@ -2072,6 +2223,80 @@ dtls_send_server_key_exchange_ecdh(dtls_context_t *ctx, dtls_peer_t *peer, } #endif /* DTLS_ECC */ +#if defined(DTLS_PSK) && defined(DTLS_ECC) +static int dtls_send_server_key_exchange_ecdhe_psk(dtls_context_t *ctx, dtls_peer_t *peer, + const unsigned char *psk_hint, size_t psk_hint_len) +{ + /* The ASN.1 Integer representation of an 32 byte unsigned int could be + * 33 bytes long add space for that */ + uint8 buf[DTLS_SKEXEC_LENGTH + DTLS_SKEXECPSK_LENGTH_MAX + 2]; + uint8 *p; + uint8 *ephemeral_pub_x; + uint8 *ephemeral_pub_y; + dtls_handshake_parameters_t *config = peer->handshake_params; + + /* ServerKeyExchange + * Please see Session 2, RFC 5489. + + struct { + select (KeyExchangeAlgorithm) { + //other cases for rsa, diffie_hellman, etc. + case ec_diffie_hellman_psk: // NEW + opaque psk_identity_hint<0..2^16-1>; + ServerECDHParams params; + }; + } ServerKeyExchange; */ + p = buf; + + assert(psk_hint_len <= DTLS_PSK_MAX_CLIENT_IDENTITY_LEN); + if (psk_hint_len > DTLS_PSK_MAX_CLIENT_IDENTITY_LEN) { + // should never happen + dtls_warn("psk identity hint is too long\n"); + return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); + } + + // psk_identity_hint + dtls_int_to_uint16(p, psk_hint_len); + p += sizeof(uint16); + + memcpy(p, psk_hint, psk_hint_len); + p += psk_hint_len; + + /* ServerECDHParams. */ + /* ECCurveType curve_type: named_curve */ + dtls_int_to_uint8(p, TLS_EC_CURVE_TYPE_NAMED_CURVE); + p += sizeof(uint8); + + /* NamedCurve namedcurve: secp256r1 */ + dtls_int_to_uint16(p, TLS_EXT_ELLIPTIC_CURVES_SECP256R1); + p += sizeof(uint16); + + dtls_int_to_uint8(p, 1 + 2 * DTLS_EC_KEY_SIZE); + p += sizeof(uint8); + + /* This should be an uncompressed point, but I do not have access to the spec. */ + dtls_int_to_uint8(p, 4); + p += sizeof(uint8); + + /* store the pointer to the x component of the pub key and make space */ + ephemeral_pub_x = p; + p += DTLS_EC_KEY_SIZE; + + /* store the pointer to the y component of the pub key and make space */ + ephemeral_pub_y = p; + p += DTLS_EC_KEY_SIZE; + + dtls_ecdsa_generate_key(config->keyx.ecc.own_eph_priv, + ephemeral_pub_x, ephemeral_pub_y, + DTLS_EC_KEY_SIZE); + + assert(p - buf <= sizeof(buf)); + + return dtls_send_handshake_msg(ctx, peer, DTLS_HT_SERVER_KEY_EXCHANGE, + buf, p - buf); +} +#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */ + #ifdef DTLS_PSK static int dtls_send_server_key_exchange_psk(dtls_context_t *ctx, dtls_peer_t *peer, @@ -2163,6 +2388,7 @@ dtls_send_server_hello_msgs(dtls_context_t *ctx, dtls_peer_t *peer) int res; int ecdsa; int ecdh_anon; + int ecdhe_psk; res = dtls_send_server_hello(ctx, peer); @@ -2172,7 +2398,8 @@ dtls_send_server_hello_msgs(dtls_context_t *ctx, dtls_peer_t *peer) } ecdsa = is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(peer->handshake_params->cipher); - ecdh_anon = is_tls_ecdh_anon_with_aes_128_cbc_sha(peer->handshake_params->cipher); + ecdh_anon = is_tls_ecdh_anon_with_aes_128_cbc_sha_256(peer->handshake_params->cipher); + ecdhe_psk = is_tls_ecdhe_psk_with_aes_128_cbc_sha_256(peer->handshake_params->cipher); #ifdef DTLS_ECC if(ecdh_anon) { @@ -2217,7 +2444,31 @@ dtls_send_server_hello_msgs(dtls_context_t *ctx, dtls_peer_t *peer) } } #endif /* DTLS_ECC */ +#if defined(DTLS_PSK) && defined(DTLS_ECC) + else if(ecdhe_psk) { + unsigned char psk_hint[DTLS_PSK_MAX_CLIENT_IDENTITY_LEN]; + int psk_len; + /* The identity hint is optional, therefore we ignore the result + * and check psk only. */ + psk_len = CALL(ctx, get_psk_info, &peer->session, DTLS_PSK_HINT, + NULL, 0, psk_hint, DTLS_PSK_MAX_CLIENT_IDENTITY_LEN); + + if (psk_len < 0) { + dtls_debug("dtls_server_hello: cannot create ServerKeyExchange\n"); + return psk_len; + } + + if (psk_len > 0) { + res = dtls_send_server_key_exchange_ecdhe_psk(ctx, peer, psk_hint, (size_t)psk_len); + + if (res < 0) { + dtls_debug("dtls_server_hello(with ECDHE): cannot prepare Server Key Exchange record\n"); + return res; + } + } + } +#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */ #ifdef DTLS_PSK if (is_tls_psk_with_aes_128_ccm_8(peer->handshake_params->cipher)) { unsigned char psk_hint[DTLS_PSK_MAX_CLIENT_IDENTITY_LEN]; @@ -2264,7 +2515,11 @@ dtls_send_ccs(dtls_context_t *ctx, dtls_peer_t *peer) { static int dtls_send_client_key_exchange(dtls_context_t *ctx, dtls_peer_t *peer) { +#if defined(DTLS_PSK) && defined(DTLS_ECC) + uint8 buf[DTLS_CKXEC_LENGTH + 2 + DTLS_PSK_MAX_CLIENT_IDENTITY_LEN]; +#else uint8 buf[DTLS_CKXEC_LENGTH]; +#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */ uint8 client_id[DTLS_PSK_MAX_CLIENT_IDENTITY_LEN]; uint8 *p; dtls_handshake_parameters_t *handshake = peer->handshake_params; @@ -2301,7 +2556,7 @@ dtls_send_client_key_exchange(dtls_context_t *ctx, dtls_peer_t *peer) #endif /* DTLS_PSK */ #ifdef DTLS_ECC case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8: - case TLS_ECDH_anon_WITH_AES_128_CBC_SHA: { + case TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256: { uint8 *ephemeral_pub_x; uint8 *ephemeral_pub_y; @@ -2324,6 +2579,60 @@ dtls_send_client_key_exchange(dtls_context_t *ctx, dtls_peer_t *peer) break; } #endif /* DTLS_ECC */ +#if defined(DTLS_PSK) && defined(DTLS_ECC) + case TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256: { + int psk_len; + uint8 *ephemeral_pub_x; + uint8 *ephemeral_pub_y; + + /* Please see Session 2, RFC 5489. + struct { + select (KeyExchangeAlgorithm) { + // other cases for rsa, diffie_hellman, etc. + case ec_diffie_hellman_psk: + opaque psk_identity<0..2^16-1>; + ClientECDiffieHellmanPublic public; + } exchange_keys; + } ClientKeyExchange; + */ + + psk_len = CALL(ctx, get_psk_info, &peer->session, DTLS_PSK_IDENTITY, + NULL, 0, + client_id, + sizeof(client_id)); + if (psk_len < 0) { + dtls_crit("no psk identity set in kx\n"); + return psk_len; + } + + if (psk_len + sizeof(uint16) > DTLS_CKXEC_LENGTH) { + dtls_warn("the psk identity is too long\n"); + return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); + } + + dtls_int_to_uint16(p, psk_len); + p += sizeof(uint16); + + memcpy(p, client_id, psk_len); + p += psk_len; + + dtls_int_to_uint8(p, 1 + 2 * DTLS_EC_KEY_SIZE); + p += sizeof(uint8); + + dtls_int_to_uint8(p, 4); + p += sizeof(uint8); + + ephemeral_pub_x = p; + p += DTLS_EC_KEY_SIZE; + ephemeral_pub_y = p; + p += DTLS_EC_KEY_SIZE; + + dtls_ecdsa_generate_key(peer->handshake_params->keyx.ecc.own_eph_priv, + ephemeral_pub_x, ephemeral_pub_y, + DTLS_EC_KEY_SIZE); + break; + } +#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */ default: dtls_crit("cipher not supported\n"); return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); @@ -2413,6 +2722,7 @@ dtls_send_client_hello(dtls_context_t *ctx, dtls_peer_t *peer, int psk = 0; int ecdsa = 0; int ecdh_anon = 0; + int ecdhe_psk = 0; dtls_handshake_parameters_t *handshake = peer->handshake_params; dtls_tick_t now; @@ -2424,17 +2734,21 @@ dtls_send_client_hello(dtls_context_t *ctx, dtls_peer_t *peer, case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8: ecdsa = is_ecdsa_supported(ctx, 1); break; - case TLS_ECDH_anon_WITH_AES_128_CBC_SHA: + case TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256: ecdh_anon = is_ecdh_anon_supported(ctx); break; + case TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256: + ecdhe_psk = is_ecdhe_psk_supported(ctx); + break; default: psk = is_psk_supported(ctx); ecdsa = is_ecdsa_supported(ctx, 1); ecdh_anon = is_ecdh_anon_supported(ctx); + ecdhe_psk = is_ecdhe_psk_supported(ctx); break; } - cipher_size = 2 + (ecdsa ? 2 : 0) + (psk ? 2 : 0) + (ecdh_anon ? 2 : 0); + cipher_size = 2 + (ecdsa ? 2 : 0) + (psk ? 2 : 0) + (ecdh_anon ? 2 : 0) + (ecdhe_psk ? 2 : 0); extension_size = (ecdsa) ? (2 + 6 + 6 + 8 + 6) : 0; if (cipher_size == 0) { @@ -2478,7 +2792,7 @@ dtls_send_client_hello(dtls_context_t *ctx, dtls_peer_t *peer, p += sizeof(uint16); if (ecdh_anon) { - dtls_int_to_uint16(p, TLS_ECDH_anon_WITH_AES_128_CBC_SHA); + dtls_int_to_uint16(p, TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256); p += sizeof(uint16); } if (psk) { @@ -2489,6 +2803,10 @@ dtls_send_client_hello(dtls_context_t *ctx, dtls_peer_t *peer, dtls_int_to_uint16(p, TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8); p += sizeof(uint16); } + if (ecdhe_psk) { + dtls_int_to_uint16(p, TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256); + p += sizeof(uint16); + } /* compression method */ dtls_int_to_uint8(p, 1); @@ -2809,7 +3127,7 @@ check_server_key_exchange_ecdh(dtls_context_t *ctx, update_hs_hash(peer, data, data_length); - assert(is_tls_ecdh_anon_with_aes_128_cbc_sha(config->cipher)); + assert(is_tls_ecdh_anon_with_aes_128_cbc_sha_256(config->cipher)); data += DTLS_HS_LENGTH; @@ -2856,8 +3174,97 @@ check_server_key_exchange_ecdh(dtls_context_t *ctx, return 0; } - #endif /* DTLS_ECC */ +#if defined(DTLS_PSK) && defined(DTLS_ECC) +check_server_key_exchange_ecdhe_psk(dtls_context_t *ctx, + dtls_peer_t *peer, + uint8 *data, size_t data_length) +{ + dtls_handshake_parameters_t *config = peer->handshake_params; + uint16_t psk_len = 0; + + /* ServerKeyExchange + * Please see Session 2, RFC 5489. + + struct { + select (KeyExchangeAlgorithm) { + //other cases for rsa, diffie_hellman, etc. + case ec_diffie_hellman_psk: // NEW + opaque psk_identity_hint<0..2^16-1>; + ServerECDHParams params; + }; + } ServerKeyExchange; */ + + update_hs_hash(peer, data, data_length); + + assert(is_tls_ecdhe_psk_with_aes_128_cbc_sha_256(config->cipher)); + + data += DTLS_HS_LENGTH; + + psk_len = dtls_uint16_to_int(data); + data += sizeof(uint16); + + if (psk_len != data_length - DTLS_HS_LENGTH - DTLS_SKEXEC_ECDH_ANON_LENGTH - sizeof(uint16)) { + dtls_warn("the length of the server identity hint is worng\n"); + return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR); + } + + if (psk_len > DTLS_PSK_MAX_CLIENT_IDENTITY_LEN) { + dtls_warn("please use a smaller server identity hint\n"); + return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR); + } + + // store the psk_identity_hint in config->keyx.psk for later use + config->keyx.psk.id_length = psk_len; + memcpy(config->keyx.psk.identity, data, psk_len); + + data += psk_len; + data_length -= psk_len; + + if (data_length < DTLS_HS_LENGTH + DTLS_SKEXEC_ECDH_ANON_LENGTH) { + dtls_alert("the packet length does not match the expected\n"); + return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR); + } + + if (dtls_uint8_to_int(data) != TLS_EC_CURVE_TYPE_NAMED_CURVE) { + dtls_alert("Only named curves supported\n"); + return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); + } + data += sizeof(uint8); + data_length -= sizeof(uint8); + + if (dtls_uint16_to_int(data) != TLS_EXT_ELLIPTIC_CURVES_SECP256R1) { + dtls_alert("secp256r1 supported\n"); + return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); + } + data += sizeof(uint16); + data_length -= sizeof(uint16); + + if (dtls_uint8_to_int(data) != 1 + 2 * DTLS_EC_KEY_SIZE) { + dtls_alert("expected 65 bytes long public point\n"); + return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); + } + data += sizeof(uint8); + data_length -= sizeof(uint8); + + if (dtls_uint8_to_int(data) != 4) { + dtls_alert("expected uncompressed public point\n"); + return dtls_alert_fatal_create(DTLS_ALERT_DECODE_ERROR); + } + data += sizeof(uint8); + data_length -= sizeof(uint8); + + memcpy(config->keyx.ecc.other_eph_pub_x, data, sizeof(config->keyx.ecc.other_eph_pub_x)); + data += sizeof(config->keyx.ecc.other_eph_pub_x); + data_length -= sizeof(config->keyx.ecc.other_eph_pub_x); + + memcpy(config->keyx.ecc.other_eph_pub_y, data, sizeof(config->keyx.ecc.other_eph_pub_y)); + data += sizeof(config->keyx.ecc.other_eph_pub_y); + data_length -= sizeof(config->keyx.ecc.other_eph_pub_y); + + return 0; +} +#endif /* defined(DTLS_PSK) && defined(DTLS_ECC) */ #ifdef DTLS_PSK static int @@ -3069,6 +3476,24 @@ decrypt_verify(dtls_peer_t *peer, uint8 *packet, size_t length, if (security->cipher == TLS_NULL_WITH_NULL_NULL) { /* no cipher suite selected */ return clen; + } else if (is_tls_ecdh_anon_with_aes_128_cbc_sha_256(security->cipher) || + is_tls_ecdhe_psk_with_aes_128_cbc_sha_256(security->cipher)) { + + unsigned char nonce[DTLS_CBC_IV_LENGTH]; + + if (clen < (DTLS_CBC_IV_LENGTH + DTLS_HMAC_DIGEST_SIZE)) /* need at least IV and MAC */ + return -1; + + memcpy(nonce, *cleartext , DTLS_CBC_IV_LENGTH); + clen -= DTLS_CBC_IV_LENGTH; + *cleartext += DTLS_CBC_IV_LENGTH ; + + clen = dtls_decrypt(*cleartext, clen, *cleartext, nonce, + dtls_kb_remote_write_key(security, peer->role), + dtls_kb_key_size(security, peer->role), + NULL, 0, + security->cipher); + } else { /* TLS_PSK_WITH_AES_128_CCM_8 or TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 */ /** * length of additional_data for the AEAD cipher which consists of @@ -3083,7 +3508,7 @@ decrypt_verify(dtls_peer_t *peer, uint8 *packet, size_t length, memset(nonce, 0, DTLS_CCM_BLOCKSIZE); memcpy(nonce, dtls_kb_remote_iv(security, peer->role), - dtls_kb_iv_size(security, peer->role)); + dtls_kb_iv_size(security, peer->role)); /* read epoch and seq_num from message */ memcpy(nonce + dtls_kb_iv_size(security, peer->role), *cleartext, 8); @@ -3108,17 +3533,19 @@ decrypt_verify(dtls_peer_t *peer, uint8 *packet, size_t length, dtls_kb_remote_write_key(security, peer->role), dtls_kb_key_size(security, peer->role), A_DATA, A_DATA_LEN, - security->cipher); - if (clen < 0) - dtls_warn("decryption failed\n"); - else { + security->cipher); + } + + if (clen < 0) + dtls_warn("decryption failed\n"); + else { #ifndef NDEBUG - dtls_debug("decrypt_verify(): found %i bytes cleartext\n", clen); + dtls_debug("decrypt_verify(): found %i bytes cleartext\n", clen); #endif - dtls_security_params_free_other(peer); - dtls_debug_dump("cleartext", *cleartext, clen); - } + dtls_security_params_free_other(peer); + dtls_debug_dump("cleartext", *cleartext, clen); } + return clen; } @@ -3219,7 +3646,8 @@ handle_handshake_msg(dtls_context_t *ctx, dtls_peer_t *peer, session_t *session, } if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(peer->handshake_params->cipher)) peer->state = DTLS_STATE_WAIT_SERVERCERTIFICATE; //ecdsa - else if (is_tls_ecdh_anon_with_aes_128_cbc_sha(peer->handshake_params->cipher)) + else if (is_tls_ecdh_anon_with_aes_128_cbc_sha_256(peer->handshake_params->cipher) || + is_tls_ecdhe_psk_with_aes_128_cbc_sha_256(peer->handshake_params->cipher)) peer->state = DTLS_STATE_WAIT_SERVERKEYEXCHANGE; //ecdh else peer->state = DTLS_STATE_WAIT_SERVERHELLODONE; //psk @@ -3259,13 +3687,23 @@ handle_handshake_msg(dtls_context_t *ctx, dtls_peer_t *peer, session_t *session, err = check_server_key_exchange_ecdsa(ctx, peer, data, data_length); } - if (is_tls_ecdh_anon_with_aes_128_cbc_sha(peer->handshake_params->cipher)) { + if (is_tls_ecdh_anon_with_aes_128_cbc_sha_256(peer->handshake_params->cipher)) { if (state != DTLS_STATE_WAIT_SERVERKEYEXCHANGE) { return dtls_alert_fatal_create(DTLS_ALERT_UNEXPECTED_MESSAGE); } err = check_server_key_exchange_ecdh(ctx, peer, data, data_length); } #endif /* DTLS_ECC */ + +#if defined(DTLS_PSK) && defined(DTLS_ECC) + if (is_tls_ecdhe_psk_with_aes_128_cbc_sha_256(peer->handshake_params->cipher)) { + if (state != DTLS_STATE_WAIT_SERVERKEYEXCHANGE) { + return dtls_alert_fatal_create(DTLS_ALERT_UNEXPECTED_MESSAGE); + } + err = check_server_key_exchange_ecdhe_psk(ctx, peer, data, data_length); + } +#endif defined(DTLS_PSK) && defined(DTLS_ECC) + #ifdef DTLS_PSK if (is_tls_psk_with_aes_128_ccm_8(peer->handshake_params->cipher)) { if (state != DTLS_STATE_WAIT_SERVERHELLODONE) { diff --git a/extlibs/tinydtls/dtls.h b/extlibs/tinydtls/dtls.h index a2ab86e..7d2bc19 100644 --- a/extlibs/tinydtls/dtls.h +++ b/extlibs/tinydtls/dtls.h @@ -238,7 +238,7 @@ typedef struct dtls_context_t { dtls_handler_t *h; /**< callback handlers */ - dtls_cipher_enable_t is_anon_ecdh_eabled; /**< enable/disable the TLS_ECDH_anon_WITH_AES_128_CBC_SHA */ + dtls_cipher_enable_t is_anon_ecdh_eabled; /**< enable/disable the TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256 */ dtls_cipher_t selected_cipher; /**< selected ciper suite for handshake */ @@ -268,7 +268,7 @@ static inline void dtls_set_handler(dtls_context_t *ctx, dtls_handler_t *h) { } /** - * @brief Enabling the TLS_ECDH_anon_WITH_AES_128_CBC_SHA + * @brief Enabling the TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256 * * @param ctx The DTLS context to use. * @param is_enable DTLS_CIPHER_ENABLE(1) or DTLS_CIPHER_DISABLE(0) @@ -279,7 +279,7 @@ void dtls_enables_anon_ecdh(dtls_context_t* ctx, dtls_cipher_enable_t is_enable) * @brief Select the cipher suite for handshake * * @param ctx The DTLS context to use. - * @param cipher TLS_ECDH_anon_WITH_AES_128_CBC_SHA (0xC018) + * @param cipher TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256 (0xC018) * TLS_PSK_WITH_AES_128_CCM_8 (0xX0A8) * TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 (0xC0AE) */ diff --git a/extlibs/tinydtls/global.h b/extlibs/tinydtls/global.h index 441710f..8b3c518 100644 --- a/extlibs/tinydtls/global.h +++ b/extlibs/tinydtls/global.h @@ -73,8 +73,9 @@ typedef unsigned char uint48[6]; /** Known cipher suites.*/ typedef enum { TLS_NULL_WITH_NULL_NULL = 0x0000, /**< NULL cipher */ - TLS_ECDH_anon_WITH_AES_128_CBC_SHA = 0xC018, /**< see RFC 4492 */ + TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256 = 0xC018, /**< see RFC 4492 */ TLS_PSK_WITH_AES_128_CCM_8 = 0xC0A8, /**< see RFC 6655 */ + TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256 = 0xC037, /**< see RFC 5489 */ TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 = 0xC0AE /**< see RFC 7251 */ } dtls_cipher_t; diff --git a/extlibs/tinydtls/tests/dtls-client.c b/extlibs/tinydtls/tests/dtls-client.c index 35521e9..dfd34c8 100644 --- a/extlibs/tinydtls/tests/dtls-client.c +++ b/extlibs/tinydtls/tests/dtls-client.c @@ -309,9 +309,10 @@ usage( const char *program, const char *version) { "\t-p port\t\tlisten on specified port (default is %d)\n" "\t-v num\t\tverbosity level (default: 3)\n" "\t-c num\t\tcipher suite (default: 1)\n" - "\t\t\t1: TLS_ECDH_anon_WITH_AES_128_CBC_SHA \n" + "\t\t\t1: TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256 \n" "\t\t\t2: TLS_PSK_WITH_AES_128_CCM_8\n" - "\t\t\t3: TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8\n", + "\t\t\t3: TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8\n" + "\t\t\t4: TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256\n", program, version, program, DEFAULT_PORT); } @@ -347,7 +348,7 @@ main(int argc, char **argv) { log_t log_level = DTLS_LOG_WARN; int fd, result; int on = 1; - dtls_cipher_t selected_cipher = TLS_ECDH_anon_WITH_AES_128_CBC_SHA; + dtls_cipher_t selected_cipher = TLS_NULL_WITH_NULL_NULL; dtls_cipher_enable_t ecdh_anon_enalbe = DTLS_CIPHER_ENABLE; int opt, res; session_t dst; @@ -417,7 +418,7 @@ main(int argc, char **argv) { case 'c': if( strcmp(optarg, "1") == 0) { - selected_cipher = TLS_ECDH_anon_WITH_AES_128_CBC_SHA; + selected_cipher = TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256; ecdh_anon_enalbe = DTLS_CIPHER_ENABLE; } else if( strcmp(optarg, "2") == 0) @@ -430,6 +431,11 @@ main(int argc, char **argv) { selected_cipher = TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 ; ecdh_anon_enalbe = DTLS_CIPHER_DISABLE; } + else if( strcmp(optarg, "4") == 0) + { + selected_cipher = TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256; + ecdh_anon_enalbe = DTLS_CIPHER_DISABLE; + } break; default: usage(argv[0], dtls_package_version()); @@ -500,7 +506,7 @@ main(int argc, char **argv) { /* select cipher suite */ dtls_select_cipher(dtls_context, selected_cipher); - /* enable/disable tls_ecdh_anon_with_aes_128_cbc_sha */ + /* enable/disable tls_ecdh_anon_with_aes_128_cbc_sha_256 */ dtls_enables_anon_ecdh(dtls_context, ecdh_anon_enalbe); dtls_set_handler(dtls_context, &cb); diff --git a/extlibs/tinydtls/tests/dtls-server.c b/extlibs/tinydtls/tests/dtls-server.c index d3da1a7..5893084 100644 --- a/extlibs/tinydtls/tests/dtls-server.c +++ b/extlibs/tinydtls/tests/dtls-server.c @@ -254,8 +254,8 @@ usage(const char *program, const char *version) { "\t-p port\t\tlisten on specified port (default is %d)\n" "\t-v num\t\tverbosity level (default: 3)\n" "\t-a enable|disable\t(default: disable)\n" - "\t\t\t\tenable:enable TLS_ECDH_anon_with_AES_128_CBC_SHA\n" - "\t\t\t\tdisable:disable TLS_ECDH_anon_with_AES_128_CBC_SHA\n", + "\t\t\t\tenable:enable TLS_ECDH_anon_with_AES_128_CBC_SHA_256\n" + "\t\t\t\tdisable:disable TLS_ECDH_anon_with_AES_128_CBC_SHA_256\n", program, version, program, DEFAULT_PORT); } @@ -280,7 +280,7 @@ main(int argc, char **argv) { struct timeval timeout; int fd, opt, result; int on = 1; - int ecdh_anon_enalbe = DTLS_CIPHER_DISABLE; + dtls_cipher_enable_t ecdh_anon_enalbe = DTLS_CIPHER_DISABLE; struct sockaddr_in6 listen_addr; memset(&listen_addr, 0, sizeof(struct sockaddr_in6)); @@ -356,7 +356,7 @@ main(int argc, char **argv) { the_context = dtls_new_context(&fd); - /* enable/disable tls_ecdh_anon_with_aes_128_cbc_sha */ + /* enable/disable tls_ecdh_anon_with_aes_128_cbc_sha_256 */ dtls_enables_anon_ecdh(the_context, ecdh_anon_enalbe); dtls_set_handler(the_context, &cb); diff --git a/resource/csdk/connectivity/api/cacommon.h b/resource/csdk/connectivity/api/cacommon.h index b7a659a..184ef64 100644 --- a/resource/csdk/connectivity/api/cacommon.h +++ b/resource/csdk/connectivity/api/cacommon.h @@ -391,6 +391,7 @@ typedef struct { CAResponseResult_t result; /**< Result for response by resource model */ CAInfo_t info; /**< Information of the response */ + bool isMulticast; } CAResponseInfo_t; /** diff --git a/resource/csdk/connectivity/common/src/caremotehandler.c b/resource/csdk/connectivity/common/src/caremotehandler.c index cca8bd8..7b6ce44 100644 --- a/resource/csdk/connectivity/common/src/caremotehandler.c +++ b/resource/csdk/connectivity/common/src/caremotehandler.c @@ -129,6 +129,7 @@ CAResponseInfo_t *CACloneResponseInfo(const CAResponseInfo_t *rep) return NULL; } + clone->isMulticast = rep->isMulticast; clone->result = rep->result; return clone; } diff --git a/resource/csdk/connectivity/common/src/logger.c b/resource/csdk/connectivity/common/src/logger.c index 2a751ff..bcdc905 100644 --- a/resource/csdk/connectivity/common/src/logger.c +++ b/resource/csdk/connectivity/common/src/logger.c @@ -74,7 +74,7 @@ static const char *LEVEL[] = static android_LogPriority LEVEL[] = { ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, ANDROID_LOG_WARN, ANDROID_LOG_ERROR, ANDROID_LOG_FATAL}; #endif -#elif defined __linux__ +#elif defined (__linux__) || defined (__APPLE__) static const char *LEVEL[] __attribute__ ((unused)) = { "DEBUG", "INFO", "WARNING", "ERROR", "FATAL"}; #elif defined ARDUINO @@ -116,7 +116,7 @@ void OICLogInit() void OICLogShutdown() { -#ifdef __linux__ +#if defined(__linux__) || defined(__APPLE__) if (logCtx && logCtx->destroy) { logCtx->destroy(logCtx); @@ -147,7 +147,7 @@ void OICLog(LogLevel level, const char *tag, const char *logStr) __android_log_write(LEVEL[level], tag, logStr); #endif -#elif defined __linux__ +#elif defined __linux__ || defined __APPLE__ if (logCtx && logCtx->write_level) { logCtx->write_level(logCtx, LEVEL_XTABLE[level], logStr); @@ -158,7 +158,7 @@ void OICLog(LogLevel level, const char *tag, const char *logStr) int min = 0; int sec = 0; int ms = 0; -#ifdef _POSIX_TIMERS +#if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0 struct timespec when = { 0, 0 }; clockid_t clk = CLOCK_REALTIME; #ifdef CLOCK_REALTIME_COARSE diff --git a/resource/csdk/connectivity/inc/caadapternetdtls.h b/resource/csdk/connectivity/inc/caadapternetdtls.h index e6940d8..d766451 100644 --- a/resource/csdk/connectivity/inc/caadapternetdtls.h +++ b/resource/csdk/connectivity/inc/caadapternetdtls.h @@ -138,7 +138,7 @@ void CADTLSSetCredentialsCallback(CAGetDTLSCredentialsHandler credCallback); * Select the cipher suite for dtls handshake * * @param[in] cipher cipher suite - * 0xC018 : TLS_ECDH_anon_WITH_AES_128_CBC_SHA + * 0xC018 : TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256 * 0xC0A8 : TLS_PSK_WITH_AES_128_CCM_8 * 0xC0AE : TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 * diff --git a/resource/csdk/connectivity/inc/caipinterface.h b/resource/csdk/connectivity/inc/caipinterface.h index 677b1f9..7aeb391 100644 --- a/resource/csdk/connectivity/inc/caipinterface.h +++ b/resource/csdk/connectivity/inc/caipinterface.h @@ -193,18 +193,18 @@ int CAGetPollingInterval(int interval); void CAWakeUpForChange(); /** - * @brief Initializes network monitor. + * Start network monitor. * * @return ::CA_STATUS_OK or Appropriate error code. */ -CAResult_t CAIPInitializeNetworkMonitor(); +CAResult_t CAIPStartNetworkMonitor(); /** - * @brief Terminates network monitor. + * Stops network monitor. * * @return ::CA_STATUS_OK or Appropriate error code. */ -CAResult_t CAIPTerminateNetworkMonitor(); +CAResult_t CAIPStopNetworkMonitor(); /** * @brief Set callback for error handling. diff --git a/resource/csdk/connectivity/src/adapter_util/caadapternetdtls.c b/resource/csdk/connectivity/src/adapter_util/caadapternetdtls.c index af9ed9a..780a6aa 100644 --- a/resource/csdk/connectivity/src/adapter_util/caadapternetdtls.c +++ b/resource/csdk/connectivity/src/adapter_util/caadapternetdtls.c @@ -118,9 +118,10 @@ static CAResult_t CAAddIdToPeerInfoList(const char *peerAddr, uint32_t port, { OIC_LOG(ERROR, NET_DTLS_TAG, "u_arraylist_add failed!"); OICFree(peer); + return CA_STATUS_FAILED; } - return result; + return CA_STATUS_OK; } static void CAFreePeerInfoList() @@ -302,10 +303,11 @@ static CAResult_t CADtlsCacheMsg(stCACacheMessage_t *msg) if (!result) { OIC_LOG(ERROR, NET_DTLS_TAG, "u_arraylist_add failed!"); + return CA_STATUS_FAILED; } OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT"); - return result; + return CA_STATUS_OK; } @@ -437,11 +439,13 @@ static int32_t CASendSecureData(dtls_context_t *context, stCADtlsAddrInfo_t *addrInfo = (stCADtlsAddrInfo_t *)session; - CAEndpoint_t endpoint; + CAEndpoint_t endpoint = {.adapter = CA_DEFAULT_ADAPTER}; + CAConvertAddrToName(&(addrInfo->addr.st), endpoint.addr, &endpoint.port); endpoint.flags = addrInfo->addr.st.ss_family == AF_INET ? CA_IPV4 : CA_IPV6; endpoint.flags |= CA_SECURE; endpoint.adapter = CA_ADAPTER_IP; + endpoint.interface = session->ifindex; int type = 0; //Mutex is not required for g_caDtlsContext. It will be called in same thread. @@ -644,7 +648,7 @@ CAResult_t CADtlsEnableAnonECDHCipherSuite(const bool enable) dtls_enables_anon_ecdh(g_caDtlsContext->dtlsContext, enable == true ? DTLS_CIPHER_ENABLE : DTLS_CIPHER_DISABLE); ca_mutex_unlock(g_dtlsContextMutex); - OIC_LOG_V(DEBUG, NET_DTLS_TAG, "TLS_ECDH_anon_WITH_AES_128_CBC_SHA is %s", + OIC_LOG_V(DEBUG, NET_DTLS_TAG, "TLS_ECDH_anon_WITH_AES_128_CBC_SHA_256 is %s", enable ? "enabled" : "disabled"); OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT CADtlsEnablesAnonEcdh"); diff --git a/resource/csdk/connectivity/src/bt_edr_adapter/android/caedrserver.c b/resource/csdk/connectivity/src/bt_edr_adapter/android/caedrserver.c index 20e0c22..c54411a 100644 --- a/resource/csdk/connectivity/src/bt_edr_adapter/android/caedrserver.c +++ b/resource/csdk/connectivity/src/bt_edr_adapter/android/caedrserver.c @@ -1145,6 +1145,7 @@ void CAEDRNatvieCloseServerTask(JNIEnv* env) jmethodID jni_mid_close = (*env)->GetMethodID(env, jni_cid_InputStream, "close", "()V"); (*env)->CallVoidMethod(env, g_inputStream, jni_mid_close); (*env)->DeleteGlobalRef(env, g_inputStream); + g_inputStream = NULL; } if (g_serverSocket) @@ -1167,6 +1168,7 @@ void CAEDRNatvieCloseServerTask(JNIEnv* env) } (*env)->CallVoidMethod(env, g_serverSocket, jni_mid_accept); (*env)->DeleteGlobalRef(env, g_serverSocket); + g_serverSocket = NULL; OIC_LOG(DEBUG, TAG, "[EDR][Native] close accept obj"); } diff --git a/resource/csdk/connectivity/src/bt_edr_adapter/caedradapter.c b/resource/csdk/connectivity/src/bt_edr_adapter/caedradapter.c index d1bf5b4..7048867 100644 --- a/resource/csdk/connectivity/src/bt_edr_adapter/caedradapter.c +++ b/resource/csdk/connectivity/src/bt_edr_adapter/caedradapter.c @@ -370,8 +370,6 @@ void CATerminateEDR() { OIC_LOG(DEBUG, EDR_ADAPTER_TAG, "IN"); - // Stop EDR adapter - CAStopEDR(); // Terminate EDR Network Monitor CAEDRTerminateNetworkMonitor(); diff --git a/resource/csdk/connectivity/src/camessagehandler.c b/resource/csdk/connectivity/src/camessagehandler.c index f746cac..a4749c9 100644 --- a/resource/csdk/connectivity/src/camessagehandler.c +++ b/resource/csdk/connectivity/src/camessagehandler.c @@ -538,21 +538,45 @@ static CAResult_t CAProcessSendData(const CAData_t *data) } } #endif - CALogPDUInfo(pdu, data->remoteEndpoint->flags); + } + else + { + OIC_LOG(ERROR,TAG,"Failed to generate multicast PDU"); + CASendErrorInfo(data->remoteEndpoint, info, CA_SEND_FAILED); + return CA_SEND_FAILED; + } + } + else if (NULL != data->responseInfo) + { + OIC_LOG(DEBUG, TAG, "responseInfo is available.."); - res = CASendMulticastData(data->remoteEndpoint, pdu->hdr, pdu->length); - if (CA_STATUS_OK != res) + info = &data->responseInfo->info; + pdu = CAGeneratePDU(data->responseInfo->result, info, data->remoteEndpoint); + + if (NULL != pdu) + { +#ifdef WITH_BWT + if (CA_ADAPTER_GATT_BTLE != data->remoteEndpoint->adapter +#ifdef CI_ADAPTER + && CA_IPV4_TCP != data->remoteEndpoint->flags +#endif + ) { - OIC_LOG_V(ERROR, TAG, "send failed:%d", res); - CAErrorHandler(data->remoteEndpoint, pdu->hdr, pdu->length, res); - coap_delete_pdu(pdu); - return res; + // Blockwise transfer + if (NULL != info) + { + CAResult_t res = CAAddBlockOption(&pdu, *info, + data->remoteEndpoint); + if (CA_STATUS_OK != res) + { + OIC_LOG(INFO, TAG, "to write block option has failed"); + CAErrorHandler(data->remoteEndpoint, pdu->hdr, pdu->length, res); + coap_delete_pdu(pdu); + return res; + } + } } - - OIC_LOG(DEBUG, TAG, "pdu to send :"); - OIC_LOG_BUFFER(DEBUG, TAG, pdu->hdr, pdu->length); - - coap_delete_pdu(pdu); +#endif } else { @@ -563,12 +587,27 @@ static CAResult_t CAProcessSendData(const CAData_t *data) } else { - OIC_LOG(ERROR, TAG, "request info is empty"); + OIC_LOG(ERROR, TAG, "request or response info is empty"); return CA_SEND_FAILED; } + + CALogPDUInfo(pdu, data->remoteEndpoint->flags); + + OIC_LOG(DEBUG, TAG, "pdu to send :"); + OIC_LOG_BUFFER(DEBUG, TAG, pdu->hdr, pdu->length); + + res = CASendMulticastData(data->remoteEndpoint, pdu->hdr, pdu->length); + if (CA_STATUS_OK != res) + { + OIC_LOG_V(ERROR, TAG, "send failed:%d", res); + CAErrorHandler(data->remoteEndpoint, pdu->hdr, pdu->length, res); + coap_delete_pdu(pdu); + return res; + } + + coap_delete_pdu(pdu); } - OIC_LOG(DEBUG, TAG, "OUT"); return CA_STATUS_OK; } @@ -842,7 +881,7 @@ static CAData_t* CAPrepareSendData(const CAEndpoint_t *endpoint, const void *sen return NULL; } - cadata->type = SEND_TYPE_UNICAST; + cadata->type = response->isMulticast ? SEND_TYPE_MULTICAST : SEND_TYPE_UNICAST; cadata->responseInfo = response; } else diff --git a/resource/csdk/connectivity/src/caprotocolmessage.c b/resource/csdk/connectivity/src/caprotocolmessage.c index 23af19c..874d634 100644 --- a/resource/csdk/connectivity/src/caprotocolmessage.c +++ b/resource/csdk/connectivity/src/caprotocolmessage.c @@ -126,6 +126,9 @@ coap_pdu_t *CAGeneratePDU(uint32_t code, const CAInfo_t *info, const CAEndpoint_ { OIC_LOG(DEBUG, TAG, "IN"); + VERIFY_NON_NULL_RET(info, TAG, "info", NULL); + VERIFY_NON_NULL_RET(endpoint, TAG, "endpoint", NULL); + coap_pdu_t *pdu = NULL; // RESET have to use only 4byte (empty message) @@ -264,6 +267,13 @@ coap_pdu_t *CAParsePDU(const char *data, uint32_t length, uint32_t *outCode, coap_delete_pdu(outpdu); return NULL; } + if (outpdu->hdr->coap_hdr_udp_t.token_length > CA_MAX_TOKEN_LEN) + { + OIC_LOG_V(ERROR, TAG, "token length has been exceed : %d", + outpdu->hdr->coap_hdr_udp_t.token_length); + coap_delete_pdu(outpdu); + return NULL; + } } if (outCode) @@ -279,7 +289,8 @@ coap_pdu_t *CAGeneratePDUImpl(code_t code, coap_list_t *options, const CAInfo_t const CAEndpoint_t *endpoint) { OIC_LOG(DEBUG, TAG, "IN"); - VERIFY_NON_NULL_RET(info, TAG, "info is NULL", NULL); + VERIFY_NON_NULL_RET(info, TAG, "info", NULL); + VERIFY_NON_NULL_RET(endpoint, TAG, "endpoint", NULL); coap_transport_type transport; diff --git a/resource/csdk/connectivity/src/ip_adapter/android/caipnwmonitor.c b/resource/csdk/connectivity/src/ip_adapter/android/caipnwmonitor.c index 7896334..6efe5f0 100755 --- a/resource/csdk/connectivity/src/ip_adapter/android/caipnwmonitor.c +++ b/resource/csdk/connectivity/src/ip_adapter/android/caipnwmonitor.c @@ -49,12 +49,12 @@ CAResult_t CAIPJniInit(); #define MAX_INTERFACE_INFO_LENGTH 1024 // allows 32 interfaces from SIOCGIFCONF -CAResult_t CAIPInitializeNetworkMonitor() +CAResult_t CAIPStartNetworkMonitor() { return CAIPJniInit(); } -CAResult_t CAIPTerminateNetworkMonitor() +CAResult_t CAIPStopNetworkMonitor() { return CA_STATUS_OK; } diff --git a/resource/csdk/connectivity/src/ip_adapter/arduino/caipnwmonitor_eth.cpp b/resource/csdk/connectivity/src/ip_adapter/arduino/caipnwmonitor_eth.cpp index 06fca45..c9ef984 100644 --- a/resource/csdk/connectivity/src/ip_adapter/arduino/caipnwmonitor_eth.cpp +++ b/resource/csdk/connectivity/src/ip_adapter/arduino/caipnwmonitor_eth.cpp @@ -45,12 +45,12 @@ // defined & used (as-is defined in the linux socket headers). #define AF_INET (2) -CAResult_t CAIPInitializeNetworkMonitor() +CAResult_t CAIPStartNetworkMonitor() { return CA_STATUS_OK; } -CAResult_t CAIPTerminateNetworkMonitor() +CAResult_t CAIPStopNetworkMonitor() { return CA_STATUS_OK; } @@ -104,7 +104,7 @@ u_arraylist_t *CAIPGetInterfaceInformation(int desiredIndex) goto exit; } - OIC_LOG_V(ERROR, TAG, "Added interface: %s (%d)", ifitem->name, ifitem->family); + OIC_LOG_V(DEBUG, TAG, "Added interface: %s (%d)", ifitem->name, ifitem->family); return iflist; diff --git a/resource/csdk/connectivity/src/ip_adapter/arduino/caipnwmonitor_wifi.cpp b/resource/csdk/connectivity/src/ip_adapter/arduino/caipnwmonitor_wifi.cpp index f35de3c..3323c4a 100644 --- a/resource/csdk/connectivity/src/ip_adapter/arduino/caipnwmonitor_wifi.cpp +++ b/resource/csdk/connectivity/src/ip_adapter/arduino/caipnwmonitor_wifi.cpp @@ -46,12 +46,12 @@ // defined & used (as-is defined in the linux socket headers). #define AF_INET (2) -CAResult_t CAIPInitializeNetworkMonitor() +CAResult_t CAIPStartNetworkMonitor() { return CA_STATUS_OK; } -CAResult_t CAIPTerminateNetworkMonitor() +CAResult_t CAIPStopNetworkMonitor() { return CA_STATUS_OK; } @@ -108,7 +108,7 @@ u_arraylist_t *CAIPGetInterfaceInformation(int desiredIndex) goto exit; } - OIC_LOG_V(ERROR, TAG, "Added interface: %s (%d)", ifitem->name, ifitem->family); + OIC_LOG_V(DEBUG, TAG, "Added interface: %s (%d)", ifitem->name, ifitem->family); return iflist; diff --git a/resource/csdk/connectivity/src/ip_adapter/caipadapter.c b/resource/csdk/connectivity/src/ip_adapter/caipadapter.c index f2ba419..2528db8 100644 --- a/resource/csdk/connectivity/src/ip_adapter/caipadapter.c +++ b/resource/csdk/connectivity/src/ip_adapter/caipadapter.c @@ -264,7 +264,6 @@ CAResult_t CAInitializeIP(CARegisterConnectivityCallback registerCallback, caglobals.ip.threadpool = handle; CAIPSetPacketReceiveCallback(CAIPPacketReceivedCB); - CAIPInitializeNetworkMonitor(); #ifdef __WITH_DTLS__ CAAdapterNetDtlsInit(); @@ -291,6 +290,7 @@ CAResult_t CAStartIP() { OIC_LOG(DEBUG, TAG, "IN"); + CAIPStartNetworkMonitor(); #ifdef SINGLE_THREAD uint16_t unicastPort = 55555; // Address is hardcoded as we are using Single Interface @@ -418,6 +418,7 @@ CAResult_t CAStopIP() CAIPDeinitializeQueueHandles(); #endif + CAIPStopNetworkMonitor(); CAIPStopServer(); OIC_LOG(DEBUG, TAG, "OUT"); @@ -428,8 +429,6 @@ void CATerminateIP() { OIC_LOG(DEBUG, TAG, "IN"); - CAIPTerminateNetworkMonitor(); - #ifdef __WITH_DTLS__ CADTLSSetAdapterCallbacks(NULL, NULL, 0); #endif diff --git a/resource/csdk/connectivity/src/ip_adapter/caipserver.c b/resource/csdk/connectivity/src/ip_adapter/caipserver.c index 6ead6a4..fd0f166 100644 --- a/resource/csdk/connectivity/src/ip_adapter/caipserver.c +++ b/resource/csdk/connectivity/src/ip_adapter/caipserver.c @@ -512,7 +512,15 @@ void CAWakeUpForChange() { if (caglobals.ip.shutdownFds[1] != -1) { - write(caglobals.ip.shutdownFds[1], "w", 1); + ssize_t len = 0; + do + { + len = write(caglobals.ip.shutdownFds[1], "w", 1); + } while ((len == -1) && (errno == EINTR)); + if ((len == -1) && (errno != EINTR) && (errno != EPIPE)) + { + OIC_LOG_V(DEBUG, TAG, "write failed: %s", strerror(errno)); + } } } @@ -625,7 +633,6 @@ static void CAProcessNewInterface(CAInterface_t *ifitem) inaddr.s_addr = ifitem->ipv4addr; applyMulticastToInterface4(inaddr); } - static void CAHandleNetlink() { #ifdef __linux__ diff --git a/resource/csdk/connectivity/src/ip_adapter/linux/caipnwmonitor.c b/resource/csdk/connectivity/src/ip_adapter/linux/caipnwmonitor.c index fd889ee..c70e9cc 100644 --- a/resource/csdk/connectivity/src/ip_adapter/linux/caipnwmonitor.c +++ b/resource/csdk/connectivity/src/ip_adapter/linux/caipnwmonitor.c @@ -36,12 +36,12 @@ #define TAG "IP_MONITOR" -CAResult_t CAIPInitializeNetworkMonitor() +CAResult_t CAIPStartNetworkMonitor() { return CA_STATUS_OK; } -CAResult_t CAIPTerminateNetworkMonitor() +CAResult_t CAIPStopNetworkMonitor() { return CA_STATUS_OK; } @@ -138,7 +138,7 @@ u_arraylist_t *CAIPGetInterfaceInformation(int desiredIndex) goto exit; } - OIC_LOG_V(ERROR, TAG, "Added interface: %s (%d)", ifitem->name, family); + OIC_LOG_V(DEBUG, TAG, "Added interface: %s (%d)", ifitem->name, family); } freeifaddrs(ifp); diff --git a/resource/csdk/connectivity/src/ip_adapter/tizen/caipnwmonitor.c b/resource/csdk/connectivity/src/ip_adapter/tizen/caipnwmonitor.c index b81b357..47e11b4 100644 --- a/resource/csdk/connectivity/src/ip_adapter/tizen/caipnwmonitor.c +++ b/resource/csdk/connectivity/src/ip_adapter/tizen/caipnwmonitor.c @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include "caadapterutils.h" #include "logger.h" @@ -35,25 +37,182 @@ #include "oic_string.h" #define TAG "IP_MONITOR" +#define MAX_INTERFACE_INFO_LENGTH (1024) -CAResult_t CAIPInitializeNetworkMonitor() +static CAInterface_t *CANewInterfaceItem(int index, char *name, int family, + uint32_t addr, int flags); + +static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index, + char *name, int family, uint32_t addr, int flags); + +static void CAWIFIConnectionStateChangedCb(wifi_connection_state_e state, wifi_ap_h ap, + void *userData); + +static void CAWIFIDeviceStateChangedCb(wifi_device_state_e state, void *userData); + + +int CAGetPollingInterval(int interval) { - return CA_STATUS_OK; + return interval; } -CAResult_t CAIPTerminateNetworkMonitor() +CAInterface_t *CAFindInterfaceChange() { - return CA_STATUS_OK; + char buf[MAX_INTERFACE_INFO_LENGTH] = { 0 }; + struct ifconf ifc = { .ifc_len = MAX_INTERFACE_INFO_LENGTH, .ifc_buf = buf }; + + int s = caglobals.ip.u6.fd != -1 ? caglobals.ip.u6.fd : caglobals.ip.u4.fd; + if (ioctl(s, SIOCGIFCONF, &ifc) < 0) + { + OIC_LOG_V(ERROR, TAG, "SIOCGIFCONF failed: %s", strerror(errno)); + return NULL; + } + + CAInterface_t *foundNewInterface = NULL; + + struct ifreq* ifr = ifc.ifc_req; + size_t interfaces = ifc.ifc_len / sizeof (ifc.ifc_req[0]); + size_t ifreqsize = ifc.ifc_len; + + CAIfItem_t *previous = (CAIfItem_t *)OICMalloc(ifreqsize); + if (!previous) + { + OIC_LOG(ERROR, TAG, "OICMalloc failed"); + return NULL; + } + + memcpy(previous, caglobals.ip.nm.ifItems, ifreqsize); + size_t numprevious = caglobals.ip.nm.numIfItems; + + if (ifreqsize > caglobals.ip.nm.sizeIfItems) + { + + CAIfItem_t *items = (CAIfItem_t *)OICRealloc(caglobals.ip.nm.ifItems, ifreqsize); + if (!items) + { + OIC_LOG(ERROR, TAG, "OICRealloc failed"); + OICFree(previous); + return NULL; + } + caglobals.ip.nm.ifItems = items; + caglobals.ip.nm.sizeIfItems = ifreqsize; + } + + caglobals.ip.nm.numIfItems = 0; + for (size_t i = 0; i < interfaces; i++) + { + struct ifreq* item = &ifr[i]; + char *name = item->ifr_name; + struct sockaddr_in *sa4 = (struct sockaddr_in *)&item->ifr_addr; + uint32_t ipv4addr = sa4->sin_addr.s_addr; + + if (ioctl(s, SIOCGIFFLAGS, item) < 0) + { + OIC_LOG_V(ERROR, TAG, "SIOCGIFFLAGS failed: %s", strerror(errno)); + continue; + } + int16_t flags = item->ifr_flags; + if ((flags & IFF_LOOPBACK) || !(flags & IFF_RUNNING)) + { + continue; + } + if (ioctl(s, SIOCGIFINDEX, item) < 0) + { + OIC_LOG_V(ERROR, TAG, "SIOCGIFINDEX failed: %s", strerror(errno)); + continue; + } + + int ifIndex = item->ifr_ifindex; + caglobals.ip.nm.ifItems[i].ifIndex = ifIndex; // refill interface list + caglobals.ip.nm.numIfItems++; + + if (foundNewInterface) + { + continue; // continue updating interface list + } + + // see if this interface didn't previously exist + bool found = false; + for (size_t j = 0; j < numprevious; j++) + { + if (ifIndex == previous[j].ifIndex) + { + found = true; + break; + } + } + if (found) + { + OIC_LOG_V(INFO, TAG, "Interface found: %s", name); + continue; + } + + foundNewInterface = CANewInterfaceItem(ifIndex, name, AF_INET, ipv4addr, flags); + } + + OICFree(previous); + return foundNewInterface; } -int CAGetPollingInterval(int interval) +CAResult_t CAIPStartNetworkMonitor() { - return interval; + OIC_LOG(DEBUG, TAG, "IN"); + + // Initialize Wifi service + wifi_error_e ret = wifi_initialize(); + if (WIFI_ERROR_NONE != ret) + { + OIC_LOG(ERROR, TAG, "wifi_initialize failed"); + return CA_STATUS_FAILED; + } + + // Set callback for receiving state changes + ret = wifi_set_device_state_changed_cb(CAWIFIDeviceStateChangedCb, NULL); + if (WIFI_ERROR_NONE != ret) + { + OIC_LOG(ERROR, TAG, "wifi_set_device_state_changed_cb failed"); + return CA_STATUS_FAILED; + } + + // Set callback for receiving connection state changes + ret = wifi_set_connection_state_changed_cb(CAWIFIConnectionStateChangedCb, NULL); + if (WIFI_ERROR_NONE != ret) + { + OIC_LOG(ERROR, TAG, "wifi_set_connection_state_changed_cb failed"); + return CA_STATUS_FAILED; + } + + OIC_LOG(DEBUG, TAG, "OUT"); + return CA_STATUS_OK; } -CAInterface_t *CAFindInterfaceChange() +CAResult_t CAIPStopNetworkMonitor() { - return NULL; + OIC_LOG(DEBUG, TAG, "IN"); + + // Reset callback for receiving state changes + wifi_error_e ret = wifi_unset_device_state_changed_cb(); + if (WIFI_ERROR_NONE != ret) + { + OIC_LOG(ERROR, TAG, "wifi_unset_device_state_changed_cb failed"); + } + + // Reset callback for receiving connection state changes + ret = wifi_unset_connection_state_changed_cb(); + if (WIFI_ERROR_NONE != ret) + { + OIC_LOG(ERROR, TAG, "wifi_unset_connection_state_changed_cb failed"); + } + + // Deinitialize Wifi service + ret = wifi_deinitialize(); + if (WIFI_ERROR_NONE != ret) + { + OIC_LOG(ERROR, TAG, "wifi_deinitialize failed"); + } + + OIC_LOG(DEBUG, TAG, "OUT"); + return CA_STATUS_OK; } u_arraylist_t *CAIPGetInterfaceInformation(int desiredIndex) @@ -65,66 +224,168 @@ u_arraylist_t *CAIPGetInterfaceInformation(int desiredIndex) return NULL; } - struct ifaddrs *ifp = NULL; - if (-1 == getifaddrs(&ifp)) + char buf[MAX_INTERFACE_INFO_LENGTH] = { 0 }; + struct ifconf ifc = { .ifc_len = MAX_INTERFACE_INFO_LENGTH, .ifc_buf = buf }; + + int s = caglobals.ip.u6.fd != -1 ? caglobals.ip.u6.fd : caglobals.ip.u4.fd; + if (ioctl(s, SIOCGIFCONF, &ifc) < 0) { - OIC_LOG_V(ERROR, TAG, "Failed to get ifaddrs: %s", strerror(errno)); + OIC_LOG_V(ERROR, TAG, "SIOCGIFCONF failed: %s", strerror(errno)); u_arraylist_destroy(iflist); return NULL; } - struct ifaddrs *ifa = NULL; - for (ifa = ifp; ifa; ifa = ifa->ifa_next) + struct ifreq* ifr = ifc.ifc_req; + size_t interfaces = ifc.ifc_len / sizeof (ifc.ifc_req[0]); + size_t ifreqsize = ifc.ifc_len; + + if (ifreqsize > caglobals.ip.nm.sizeIfItems) { - int family = ifa->ifa_addr->sa_family; - if ((ifa->ifa_flags & IFF_LOOPBACK) || (AF_INET != family && AF_INET6 != family)) + CAIfItem_t *items = (CAIfItem_t *)OICRealloc(caglobals.ip.nm.ifItems, ifreqsize); + if (!items) { - continue; + OIC_LOG(ERROR, TAG, "OICRealloc failed"); + goto exit; } + caglobals.ip.nm.ifItems = items; + caglobals.ip.nm.sizeIfItems = ifreqsize; + } + + caglobals.ip.nm.numIfItems = 0; + for (size_t i = 0; i < interfaces; i++) + { + CAResult_t result = CA_STATUS_OK; + struct ifreq* item = &ifr[i]; + char *name = item->ifr_name; + struct sockaddr_in *sa4 = (struct sockaddr_in *)&item->ifr_addr; + uint32_t ipv4addr = sa4->sin_addr.s_addr; - int ifindex = if_nametoindex(ifa->ifa_name); - int length = u_arraylist_length(iflist); - int already = false; - for (int i = length-1; i >= 0; i--) + if (ioctl(s, SIOCGIFFLAGS, item) < 0) { - CAInterface_t *ifitem = (CAInterface_t *)u_arraylist_get(iflist, i); - if (ifitem->index == ifindex && ifitem->family == family) - { - already = true; - break; - } + OIC_LOG_V(ERROR, TAG, "SIOCGIFFLAGS failed: %s", strerror(errno)); + continue; } - if (already) + int16_t flags = item->ifr_flags; + if ((flags & IFF_LOOPBACK) || !(flags & IFF_RUNNING)) { continue; } + if (ioctl(s, SIOCGIFINDEX, item) < 0) + { + OIC_LOG_V(ERROR, TAG, "SIOCGIFINDEX failed: %s", strerror(errno)); + continue; + } + + int ifindex = item->ifr_ifindex; + caglobals.ip.nm.ifItems[i].ifIndex = ifindex; + caglobals.ip.nm.numIfItems++; - CAInterface_t *ifitem = (CAInterface_t *)OICCalloc(1, sizeof(CAInterface_t)); - if (!ifitem) + if (desiredIndex && (ifindex != desiredIndex)) { - OIC_LOG(ERROR, TAG, "Malloc failed"); - goto exit; + continue; } - OICStrcpy(ifitem->name, INTERFACE_NAME_MAX, ifa->ifa_name); - ifitem->index = ifindex; - ifitem->family = family; - ifitem->ipv4addr = ((struct sockaddr_in *)(ifa->ifa_addr))->sin_addr.s_addr; - ifitem->flags = ifa->ifa_flags; + // Add IPv4 interface + result = CAAddInterfaceItem(iflist, ifindex, name, AF_INET, ipv4addr, flags); + if (CA_STATUS_OK != result) + { + goto exit; + } - bool result = u_arraylist_add(iflist, ifitem); - if (!result) + // Add IPv6 interface + result = CAAddInterfaceItem(iflist, ifindex, name, AF_INET6, ipv4addr, flags); + if (CA_STATUS_OK != result) { - OIC_LOG(ERROR, TAG, "u_arraylist_add failed."); goto exit; } } - - freeifaddrs(ifp); return iflist; exit: - freeifaddrs(ifp); u_arraylist_destroy(iflist); return NULL; } + +static CAResult_t CAAddInterfaceItem(u_arraylist_t *iflist, int index, + char *name, int family, uint32_t addr, int flags) +{ + CAInterface_t *ifitem = CANewInterfaceItem(index, name, family, addr, flags); + if (!ifitem) + { + return CA_STATUS_FAILED; + } + bool result = u_arraylist_add(iflist, ifitem); + if (!result) + { + OIC_LOG(ERROR, TAG, "u_arraylist_add failed."); + OICFree(ifitem); + return CA_STATUS_FAILED; + } + + return CA_STATUS_OK; +} + +static CAInterface_t *CANewInterfaceItem(int index, char *name, int family, + uint32_t addr, int flags) +{ + CAInterface_t *ifitem = (CAInterface_t *)OICCalloc(1, sizeof (CAInterface_t)); + if (!ifitem) + { + OIC_LOG(ERROR, TAG, "Malloc failed"); + return NULL; + } + + OICStrcpy(ifitem->name, INTERFACE_NAME_MAX, name); + ifitem->index = index; + ifitem->family = family; + ifitem->ipv4addr = addr; + ifitem->flags = flags; + + return ifitem; +} + +void CAWIFIConnectionStateChangedCb(wifi_connection_state_e state, wifi_ap_h ap, + void *userData) +{ + OIC_LOG(DEBUG, TAG, "IN"); + + if (WIFI_CONNECTION_STATE_ASSOCIATION == state + || WIFI_CONNECTION_STATE_CONFIGURATION == state) + { + OIC_LOG(DEBUG, TAG, "Connection is in Association State"); + return; + } + + if (WIFI_CONNECTION_STATE_CONNECTED == state) + { + CAWakeUpForChange(); + } + else + { + u_arraylist_t *iflist = CAIPGetInterfaceInformation(0); + if (!iflist) + { + OIC_LOG_V(ERROR, TAG, "get interface info failed"); + return; + } + } + + OIC_LOG(DEBUG, TAG, "OUT"); +} + +void CAWIFIDeviceStateChangedCb(wifi_device_state_e state, void *userData) +{ + OIC_LOG(DEBUG, TAG, "IN"); + + if (WIFI_DEVICE_STATE_ACTIVATED == state) + { + OIC_LOG(DEBUG, TAG, "Wifi is in Activated State"); + } + else + { + CAWIFIConnectionStateChangedCb(WIFI_CONNECTION_STATE_DISCONNECTED, NULL, NULL); + OIC_LOG(DEBUG, TAG, "Wifi is in Deactivated State"); + } + + OIC_LOG(DEBUG, TAG, "OUT"); +} diff --git a/resource/csdk/security/SConscript b/resource/csdk/security/SConscript index 379aec5..033a4d7 100644 --- a/resource/csdk/security/SConscript +++ b/resource/csdk/security/SConscript @@ -40,7 +40,7 @@ if target_os == 'arduino': ###################################################################### libocsrm_env.PrependUnique(CPPPATH = [ '../../../extlibs/cjson/', -# '../../../extlibs/tinydtls/', + '../../../extlibs/tinydtls/', '../logger/include', '../ocrandom/include', '../stack/include', @@ -82,19 +82,44 @@ if not env.get('RELEASE'): # Source files and Targets ###################################################################### OCSRM_SRC = 'src/' -libocsrm_src = [ - OCSRM_SRC + 'secureresourcemanager.c', - OCSRM_SRC + 'resourcemanager.c', - OCSRM_SRC + 'aclresource.c', - OCSRM_SRC + 'pstatresource.c', - OCSRM_SRC + 'doxmresource.c', - OCSRM_SRC + 'credresource.c', - OCSRM_SRC + 'policyengine.c', - OCSRM_SRC + 'psinterface.c', - OCSRM_SRC + 'srmresourcestrings.c', - OCSRM_SRC + 'srmutility.c', - OCSRM_SRC + 'base64.c' - ] +if env.get('SECURED') == '1': + libocsrm_src = [ + OCSRM_SRC + 'secureresourcemanager.c', + OCSRM_SRC + 'resourcemanager.c', + OCSRM_SRC + 'aclresource.c', + OCSRM_SRC + 'amaclresource.c', + OCSRM_SRC + 'pstatresource.c', + OCSRM_SRC + 'doxmresource.c', + OCSRM_SRC + 'credresource.c', + OCSRM_SRC + 'svcresource.c', + OCSRM_SRC + 'policyengine.c', + OCSRM_SRC + 'psinterface.c', + OCSRM_SRC + 'srmresourcestrings.c', + OCSRM_SRC + 'srmutility.c', + OCSRM_SRC + 'iotvticalendar.c', + OCSRM_SRC + 'oxmpincommon.c', + OCSRM_SRC + 'base64.c', + #pbkdf2.c is required to PIN based OxM only. + #But we did not use a separate build options to prevent the build command becomes complicated. + OCSRM_SRC + 'pbkdf2.c' + ] +else: + libocsrm_src = [ + OCSRM_SRC + 'secureresourcemanager.c', + OCSRM_SRC + 'resourcemanager.c', + OCSRM_SRC + 'aclresource.c', + OCSRM_SRC + 'amaclresource.c', + OCSRM_SRC + 'pstatresource.c', + OCSRM_SRC + 'doxmresource.c', + OCSRM_SRC + 'credresource.c', + OCSRM_SRC + 'svcresource.c', + OCSRM_SRC + 'policyengine.c', + OCSRM_SRC + 'psinterface.c', + OCSRM_SRC + 'srmresourcestrings.c', + OCSRM_SRC + 'srmutility.c', + OCSRM_SRC + 'iotvticalendar.c', + OCSRM_SRC + 'base64.c' + ] libocsrm = libocsrm_env.StaticLibrary('libocsrm', libocsrm_src) diff --git a/resource/csdk/security/include/internal/amaclresource.h b/resource/csdk/security/include/internal/amaclresource.h new file mode 100755 index 0000000..e1f4f5b --- /dev/null +++ b/resource/csdk/security/include/internal/amaclresource.h @@ -0,0 +1,79 @@ +//****************************************************************** +// +// Copyright 2015 Intel Mobile Communications GmbH 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 IOTVT_SRM_AMACLR_H +#define IOTVT_SRM_AMACLR_H + +/** + * @file + * + * This file contains the APIs for the /oic/sec/amacl resource is an ACL structure that + * specifies which resources will use an Access Manager Service (AMS) to resolve access decisions. + * It dynamically obtains an ACL using an AMS. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Initialize Amacl resource by loading data from persistent storage. + * + * @retval OC_STACK_OK for Success, otherwise some error value + */ +OCStackResult InitAmaclResource(); + +/** + * Perform cleanup for Amacl resources. + * + * @retval none + */ +void DeInitAmaclResource(); + +/** + * This method is used by PolicyEngine to retrieve Amacl for a Subject. + * + * @param subjectId ID of the subject for which Amacl is required. + * @param savePtr is used internally by @ref GetAmaclResourceData to maintain index between + * successive calls for same subjectId. + * + * @retval reference to @ref OicSecAmacl_t if Amacl is found, else NULL + * + * @note On the first call to @ref GetAmaclResourceData, savePtr should point to NULL + */ +const OicSecAmacl_t* GetAmaclResourceData(const OicUuid_t* subjectId, OicSecAmacl_t **savePtr); + +/** + * This function converts Amacl data into JSON format. + * Caller needs to invoke 'free' when done using + * returned string. + * @param Amacl instance of OicSecAmacl_t structure. + * + * @retval pointer to Amacl in json format. + */ +char* BinToAmaclJSON(const OicSecAmacl_t * amacl); + +#ifdef __cplusplus +} +#endif + +#endif //IOTVT_SRM_AMACLR_H + + diff --git a/resource/csdk/security/include/internal/credresource.h b/resource/csdk/security/include/internal/credresource.h index 9ae31bd..2170521 100644 --- a/resource/csdk/security/include/internal/credresource.h +++ b/resource/csdk/security/include/internal/credresource.h @@ -100,6 +100,15 @@ OicSecCred_t * GenerateCredential(const OicUuid_t* subject, OicSecCredType_t cre */ OCStackResult AddCredential(OicSecCred_t * cred); +/** + * Function to remove the credential from SVR DB. + * + * @param credId Credential ID to be deleted. + * + * @return OC_STACK_OK for success and errorcode otherwise. + */ +OCStackResult RemoveCredential(const OicUuid_t* credId); + #if defined(__WITH_DTLS__) /** * This internal callback is used by lower stack (i.e. CA layer) to @@ -114,6 +123,24 @@ OCStackResult AddCredential(OicSecCred_t * cred); * @retval none */ void GetDtlsPskCredentials(CADtlsPskCredsBlob_t **credInfo); + +/** + * Add temporal PSK to PIN based OxM + * + * @param[in] tmpSubject UUID of target device + * @param[in] credType Type of credential to be added + * @param[in] pin numeric characters + * @param[in] pinSize length of 'pin' + * @param[in] ownersLen Number of owners + * @param[in] owners Array of owners + * @param[out] tmpCredSubject Generated credential's subject. + * + * @return OC_STACK_OK for success and errorcode otherwise. + */ +OCStackResult AddTmpPskWithPIN(const OicUuid_t* tmpSubject, OicSecCredType_t credType, + const char * pin, size_t pinSize, + size_t ownersLen, const OicUuid_t * owners, OicUuid_t* tmpCredSubject); + #endif /* __WITH_DTLS__ */ /** diff --git a/resource/csdk/security/include/internal/doxmresource.h b/resource/csdk/security/include/internal/doxmresource.h index cd8477e..e0f2fc9 100644 --- a/resource/csdk/security/include/internal/doxmresource.h +++ b/resource/csdk/security/include/internal/doxmresource.h @@ -21,6 +21,8 @@ #ifndef IOTVT_SRM_DOXM_H #define IOTVT_SRM_DOXM_H +#include "octypes.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/resource/csdk/security/include/internal/srmresourcestrings.h b/resource/csdk/security/include/internal/srmresourcestrings.h index 017eb79..9974717 100644 --- a/resource/csdk/security/include/internal/srmresourcestrings.h +++ b/resource/csdk/security/include/internal/srmresourcestrings.h @@ -26,6 +26,11 @@ extern const char * SVR_DB_FILE_NAME; extern const char * OIC_MI_DEF; +//AMACL +extern const char * OIC_RSRC_TYPE_SEC_AMACL; +extern const char * OIC_RSRC_AMACL_URI; +extern const char * OIC_JSON_AMACL_NAME; + //ACL extern const char * OIC_RSRC_TYPE_SEC_ACL; extern const char * OIC_RSRC_ACL_URI; @@ -47,8 +52,14 @@ extern const char * OIC_RSRC_TYPE_SEC_CRED; extern const char * OIC_RSRC_CRED_URI; extern const char * OIC_JSON_CRED_NAME; +//SVC +extern const char * OIC_RSRC_TYPE_SEC_SVC; +extern const char * OIC_RSRC_SVC_URI; +extern const char * OIC_JSON_SVC_NAME; + extern const char * OIC_JSON_SUBJECT_NAME; extern const char * OIC_JSON_RESOURCES_NAME; +extern const char * OIC_JSON_AMSS_NAME; extern const char * OIC_JSON_PERMISSION_NAME; extern const char * OIC_JSON_OWNERS_NAME; extern const char * OIC_JSON_OWNER_NAME; @@ -63,6 +74,8 @@ extern const char * OIC_JSON_CREDTYPE_NAME; extern const char * OIC_JSON_PUBLICDATA_NAME; extern const char * OIC_JSON_PRIVATEDATA_NAME; extern const char * OIC_JSON_PERIOD_NAME; +extern const char * OIC_JSON_PERIODS_NAME; +extern const char * OIC_JSON_RECURRENCES_NAME; extern const char * OIC_JSON_ISOP_NAME; extern const char * OIC_JSON_COMMIT_HASH_NAME; extern const char * OIC_JSON_DEVICE_ID_NAME; @@ -70,6 +83,8 @@ extern const char * OIC_JSON_CM_NAME; extern const char * OIC_JSON_TM_NAME; extern const char * OIC_JSON_OM_NAME; extern const char * OIC_JSON_SM_NAME; +extern const char * OIC_JSON_SERVICE_DEVICE_ID; +extern const char * OIC_JSON_SERVICE_TYPE; extern OicUuid_t WILDCARD_SUBJECT_ID; extern size_t WILDCARD_SUBJECT_ID_LEN; @@ -78,9 +93,9 @@ extern const char * WILDCARD_RESOURCE_URI; //Ownership Transfer Methods extern const char * OXM_JUST_WORKS; extern const char * OXM_MODE_SWITCH; -extern const char * RANDOM_DEVICE_PIN; -extern const char * PRE_PROVISIONED_DEVICE_PIN; -extern const char * PRE_PROVISIONED_STRONG_CREDENTIAL; +extern const char * OXM_RANDOM_DEVICE_PIN; +extern const char * OXM_PRE_PROVISIONED_DEVICE_PIN; +extern const char * OXM_PRE_PROVISIONED_STRONG_CREDENTIAL; extern const char * OIC_SEC_TRUE; extern const char * OIC_SEC_FALSE; diff --git a/resource/csdk/security/include/internal/svcresource.h b/resource/csdk/security/include/internal/svcresource.h new file mode 100644 index 0000000..9db42c5 --- /dev/null +++ b/resource/csdk/security/include/internal/svcresource.h @@ -0,0 +1,58 @@ +//****************************************************************** +// +// Copyright 2015 Intel Mobile Communications GmbH 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 IOTVT_SRM_SVCR_H +#define IOTVT_SRM_SVCR_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Initialize SVC resource by loading data from persistent storage. + * + * @retval OC_STACK_OK for Success, otherwise some error value + */ +OCStackResult InitSVCResource(); + +/** + * Perform cleanup for SVC resources. + * + * @retval none + */ +void DeInitSVCResource(); + +/** + * This function converts SVC data into JSON format. + * Caller needs to invoke 'free' when done using + * returned string. + * @param svc instance of OicSecSvc_t structure. + * + * @retval pointer to SVC in json format. + */ +char* BinToSvcJSON(const OicSecSvc_t * svc); + +#ifdef __cplusplus +} +#endif + +#endif //IOTVT_SRM_SVCR_H + + diff --git a/resource/csdk/security/include/iotvticalendar.h b/resource/csdk/security/include/iotvticalendar.h new file mode 100644 index 0000000..2d77be0 --- /dev/null +++ b/resource/csdk/security/include/iotvticalendar.h @@ -0,0 +1,191 @@ +//****************************************************************** +// +// Copyright 2015 Intel Mobile Communications GmbH 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 IOTVT_ICALENDAR_H +#define IOTVT_ICALENDAR_H + +//Not supported on Arduino due lack of absolute time need to implement iCalendar +#ifndef WITH_ARDUINO + +#include // for uint8_t typedef +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define FREQ_DAILY (1) +#define MAX_BYDAY_SIZE (7) //7 days of week +#define TM_YEAR_OFFSET (1900) //tm_year field of c-lang tm date-time struct + //represents number of years since 1900. +#define TM_DST_OFFSET (1) //c-lang tm struct Daylight Saving Time offset. +#define TOTAL_HOURS (24) //Total hours in a day. + +typedef struct IotvtICalRecur IotvtICalRecur_t; +typedef struct IotvtICalPeriod IotvtICalPeriod_t; + +/* + * date-time = date "T" time + * + * date = date-value + * date-value = date-fullyear date-month date-mday + * date-fullyear = 4DIGIT + * date-month = 2DIGIT ;01-12 + * date-mday = 2DIGIT ;01-28, 01-29, 01-30, 01-31 + * ;based on month/year + * + * time = time-hour time-minute time-second [time-utc] + * time-hour = 2DIGIT ;00-23 + * time-minute = 2DIGIT ;00-59 + * time-second = 2DIGIT ;00-60 + * ;The "60" value is used to account for "leap" seconds. + * + * Date-Time Forms: + * 1. Date with Local time + * 20150626T150000 + */ +typedef struct tm IotvtICalDateTime_t; //c-lang tm date-time struct + +/* + * Bit mask for weekdays + */ +typedef enum +{ + NO_WEEKDAY = 0X0, + SUNDAY = (0x1 << 0), + MONDAY = (0x1 << 1), + TUESDAY = (0x1 << 2), + WEDNESDAY = (0x1 << 3), + THURSDAY = (0x1 << 4), + FRIDAY = (0x1 << 5), + SATURDAY = (0x1 << 6) +}IotvtICalWeekdayBM_t; + +/* + * Result code for IotvtICalendar + */ +typedef enum +{ + IOTVTICAL_SUCCESS = 0, //successfully completed operation + IOTVTICAL_VALID_ACCESS, //access is within allowable time + IOTVTICAL_INVALID_ACCESS, //access is not within allowable time + IOTVTICAL_INVALID_PARAMETER, //invalid method parameter + IOTVTICAL_INVALID_RRULE, //rrule is not well form, missing FREQ + IOTVTICAL_INVALID_PERIOD, //period is not well form, start-datetime is after end-datetime + IOTVTICAL_ERROR //encounter error +}IotvtICalResult_t; + +/* + * Grammar for iCalendar data type PERIOD + * + * period = date-time "/" date-time ; start-time / end-time. + * ;The start-time MUST be before the end-time. + * + */ +struct IotvtICalPeriod +{ + IotvtICalDateTime_t startDateTime; + IotvtICalDateTime_t endDateTime; +}; + +/* + * Grammar for iCalendar data type RECUR + * + * recur = "FREQ"=freq *( + * ( ";" "UNTIL" "=" enddate ) / + * ( ";" "BYDAY" "=" bywdaylist ) / + * ) + * + * freq = "DAILY" + * enddate = date + * bywdaylist = weekday/ ( weekday *("," weekday) ) + * weekday = "SU" / "MO" / "TU" / "WE" / "TH" / "FR" / "SA" + * + * Example: + * 1."Allow access on every Monday, Wednesday & Friday between 3pm to 5pm" + * PERIOD:20150626T150000/20150626T170000 + * RRULE: FREQ=DAILY; BYDAY=MO, WE, FR + * 2."Allow access every Monday, Wednesday & Friday from 3pm to 5pm until + * July 3rd, 2015" + * PERIOD:20150626T150000/20150626T170000 + * RRULE: FREQ=DAILY; UNTIL=20150703; BYDAY=MO, WE, FR + */ +struct IotvtICalRecur +{ + uint16_t freq; + IotvtICalDateTime_t until; + IotvtICalWeekdayBM_t byDay; +}; + +/** + * This API is used by policy engine to checks if the + * request to access resource is within valid time. + * + * @param period string representing period. + * @param recur string representing recurrence rule + * + * @return IOTVTICAL_VALID_ACCESS -- if the request is within valid time period + * IOTVTICAL_INVALID_ACCESS -- if the request is not within valid time period + * IOTVTICAL_INVALID_PARAMETER -- if parameter are invalid + * IOTVTICAL_INVALID_PERIOD -- if period string has invalid format + * IOTVTICAL_INVALID_RRULE -- if rrule string has invalid format + * + *Eg: if(IOTVTICAL_VALID_ACCESS == IsRequestWithinValidTime(period, recur)) + * { + * //Access within allowable time + * } + * else + * { + * //Access is not within allowable time. + * } + */ +IotvtICalResult_t IsRequestWithinValidTime(char *period, char *recur); + +/** + * Parses periodStr and populate struct IotvtICalPeriod_t + * + * @param periodStr string to be parsed. + * @param period IotvtICalPeriod_t struct to be populated. + * + * @return IOTVTICAL_INVALID_PARAMETER -- if parameter are invalid + * IOTVTICAL_INVALID_PERIOD -- if period string has invalid format + * IOTVTICAL_INVALID_SUCCESS -- if no error while parsing + */ +IotvtICalResult_t ParsePeriod(const char *periodStr, IotvtICalPeriod_t *period); + +/** + * Parses recurStr and populate struct IotvtICalRecur_t + * + * @param recurStr string to be parsed. + * @param recur IotvtICalPeriod_t struct to be populated. + * + * @return IOTVTICAL_INVALID_PARAMETER -- if parameter are invalid + * IOTVTICAL_INVALID_PERIOD -- if period string has invalid format + * IOTVTICAL_INVALID_RRULE -- if rrule string has invalid format + */ +IotvtICalResult_t ParseRecur(const char *recurStr, IotvtICalRecur_t *recur); + +#ifdef __cplusplus +} +#endif +#endif +#endif //IOTVT_ICALENDAR_H diff --git a/resource/csdk/security/include/pbkdf2.h b/resource/csdk/security/include/pbkdf2.h new file mode 100644 index 0000000..ff2e3e5 --- /dev/null +++ b/resource/csdk/security/include/pbkdf2.h @@ -0,0 +1,62 @@ +/* ***************************************************************** + * + * Copyright 2015 Samsung Electronics 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 _PBKDF2_H +#define _PBKDF2_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * The number of iterations desired to derived key. + * (Recommened by RFC 2898) + */ +#define PBKDF_ITERATIONS 1000 + +/** + * Function to derive cryptographic key from the password. (RFC 2898) + * In this implementation, HMAC with SHA2 is considered as a pseudorandom function + * + * @param[in] passwd is the master password from which a derived key is generated. + * @param[in] pLen is the byte size of the passwd. + * @param[in] salt is a cryptographic salt. + * @param[in] saltlen is the byte size of the salt. + * @param[in] iteration is the number of iterations desired. + * @param[in] keyLen is the desired byte size of the derived key. (should be the same as + * derivedKey size) + * @param[out] derivedKey is the generated derived key + * + * @return 0 on success + */ +int DeriveCryptoKeyFromPassword(const unsigned char* passwd, size_t pLen, + const uint8_t* salt, const size_t saltLen, + const size_t iterations, + const size_t keyLen, uint8_t* derivedKey); + +#ifdef __cplusplus +} +#endif +#endif // _PBKDF2_H + diff --git a/resource/csdk/security/include/pinoxmcommon.h b/resource/csdk/security/include/pinoxmcommon.h new file mode 100644 index 0000000..b4658ad --- /dev/null +++ b/resource/csdk/security/include/pinoxmcommon.h @@ -0,0 +1,78 @@ +/* ***************************************************************** + * + * Copyright 2015 Samsung Electronics 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 PIN_CALLBACK_DEF_H_ +#define PIN_CALLBACK_DEF_H_ + +#ifdef __cplusplus + extern "C" { +#endif // __cplusplus + +#define OXM_RANDOM_PIN_SIZE 8 + +/** + * Function pointer to print pin code + */ +typedef void (*GeneratePinCallback)(char* pinData, size_t pinSize); + +/** + * Function pointer to input pin code + */ +typedef void (*InputPinCallback)(char* pinBuf, size_t bufSize); + +/** + * Function to setting generate PIN callback from user + * + * @param[in] pinCB implementation of generate PIN callback + */ +void SetGeneratePinCB(GeneratePinCallback pinCB); + +/** + * Function to setting input PIN callback from user + * + * @param[in] pinCB implementation of input PIN callback + */ +void SetInputPinCB(InputPinCallback pinCB); + +/** + * Function to generate random PIN. + * This function will send generated PIN to user via callback. + * + * @param[in,out] pinBuffer Buffer to store the generated PIN data. + * @param[in] bufferSize Size of buffer + * @return OC_STACK_SUCCESS in case of success and other value otherwise. + */ +OCStackResult GeneratePin(char* pinBuffer, size_t bufferSize); + +/** + * Function to input PIN callback via input callback + * + * @param[in,out] pinBuffer Buffer to store the inputed PIN data. + * @param[in] bufferSize Size of buffer + * @return OC_STACK_SUCCESS in case of success and other value otherwise. + */ +OCStackResult InputPin(char* pinBuffer, size_t bufferSize); + + +#ifdef __cplusplus +} +#endif + +#endif //PIN_CALLBACK_DEF_H_ diff --git a/resource/csdk/security/include/securevirtualresourcetypes.h b/resource/csdk/security/include/securevirtualresourcetypes.h index 6df713b..2f69026 100644 --- a/resource/csdk/security/include/securevirtualresourcetypes.h +++ b/resource/csdk/security/include/securevirtualresourcetypes.h @@ -58,7 +58,9 @@ extern "C" { #define SUBJECT_NOT_FOUND_DEF (1 << 3) #define RESOURCE_NOT_FOUND_DEF (1 << 4) #define POLICY_ENGINE_ERROR_DEF (1 << 5) +#define INVALID_PERIOD_DEF (1 << 6) #define REASON_MASK_DEF (INSUFFICIENT_PERMISSION_DEF | \ + INVALID_PERIOD_DEF | \ SUBJECT_NOT_FOUND_DEF | \ RESOURCE_NOT_FOUND_DEF | \ POLICY_ENGINE_ERROR_DEF) @@ -102,6 +104,8 @@ typedef enum { ACCESS_GRANTED = ACCESS_GRANTED_DEF, ACCESS_DENIED = ACCESS_DENIED_DEF, + ACCESS_DENIED_INVALID_PERIOD = ACCESS_DENIED_DEF + | INVALID_PERIOD_DEF, ACCESS_DENIED_INSUFFICIENT_PERMISSION = ACCESS_DENIED_DEF | INSUFFICIENT_PERMISSION_DEF, ACCESS_DENIED_SUBJECT_NOT_FOUND = ACCESS_DENIED_DEF @@ -208,6 +212,13 @@ typedef enum OicSecDpom SINGLE_SERVICE_CLIENT_DRIVEN = 0x3, } OicSecDpom_t; +typedef enum OicSecSvcType +{ + SERVICE_UNKNOWN = 0x0, + ACCESS_MGMT_SERVICE = 0x1, //urn:oic.sec.ams +} OicSecSvcType_t; + + //TODO: Need more clarification on deviceIDFormat field type. #if 0 typedef enum @@ -222,7 +233,8 @@ typedef enum OIC_MODE_SWITCH = 0x1, OIC_RANDOM_DEVICE_PIN = 0x2, OIC_PRE_PROVISIONED_DEVICE_PIN = 0x3, - OIC_PRE_PROVISION_STRONG_CREDENTIAL = 0x4 + OIC_PRE_PROVISION_STRONG_CREDENTIAL = 0x4, + OIC_OXM_COUNT }OicSecOxm_t; typedef struct OicSecJwk OicSecJwk_t; @@ -279,9 +291,9 @@ struct OicSecAcl size_t resourcesLen; // the number of elts in Resources char **resources; // 1:R:M:Y:String uint16_t permission; // 2:R:S:Y:UINT16 - size_t periodsLen; // the number of elts in Periods - char **periods; // 3:R:M*:N:String (<--M*; see Spec) - char *recurrences; // 5:R:M:N:String + size_t prdRecrLen; // the number of elts in Periods + char **periods; // 3:R:M*:N:String (<--M*; see Spec) + char **recurrences; // 5:R:M:N:String size_t ownersLen; // the number of elts in Owners OicUuid_t *owners; // 8:R:M:Y:oic.uuid // NOTE: we are using UUID for Owners instead of Svc type for mid-April @@ -302,13 +314,14 @@ struct OicSecAmacl size_t resourcesLen; // the number of elts in Resources char **resources; // 0:R:M:Y:String size_t amssLen; // the number of elts in Amss - OicSecSvc_t *amss; // 1:R:M:Y:acl + OicUuid_t *amss; // 1:R:M:Y:acl size_t ownersLen; // the number of elts in Owners OicUuid_t *owners; // 2:R:M:Y:oic.uuid // NOTE: we are using UUID for Owners instead of Svc type for mid-April // SRM version only; this will change to Svc type for full implementation. //TODO change Owners type to oic.sec.svc //OicSecSvc_t *Owners; // 2:R:M:Y:oic.sec.svc + OicSecAmacl_t *next; }; /** @@ -408,7 +421,11 @@ struct OicSecSacl struct OicSecSvc { // :::: - //TODO fill in from OIC Security Spec + OicUuid_t svcdid; //0:R:S:Y:oic.uuid + OicSecSvcType_t svct; //1:R:M:Y:OIC Service Type + size_t ownersLen; //2:the number of elts in Owners + OicUuid_t *owners; //3:R:M:Y:oic.uuid + OicSecSvc_t *next; }; #ifdef __cplusplus diff --git a/resource/csdk/security/include/srmutility.h b/resource/csdk/security/include/srmutility.h index d811e25..9230ef6 100644 --- a/resource/csdk/security/include/srmutility.h +++ b/resource/csdk/security/include/srmutility.h @@ -22,6 +22,8 @@ #define IOTVT_SRM_UTILITY_H #include "ocstack.h" +#include "cJSON.h" +#include "securevirtualresourcetypes.h" #ifdef __cplusplus extern "C" { @@ -62,8 +64,8 @@ struct OicParseQueryIter * @note Invoking function must define "exit:" label for goto functionality to work correctly. * */ -#define VERIFY_SUCCESS(tag, op, logLevel) { if (!(op)) \ - {OC_LOG((logLevel), tag, PCF(#op " failed!!")); goto exit;} } +#define VERIFY_SUCCESS(tag, op, logLevel) do{ if (!(op)) \ + {OC_LOG((logLevel), tag, PCF(#op " failed!!")); goto exit; } }while(0) /** * @def VERIFY_NON_NULL @@ -72,8 +74,8 @@ struct OicParseQueryIter * @note Invoking function must define "exit:" label for goto functionality to work correctly. * */ -#define VERIFY_NON_NULL(tag, arg, logLevel) { if (NULL == (arg)) \ - { OC_LOG((logLevel), tag, PCF(#arg " is NULL")); goto exit; } } +#define VERIFY_NON_NULL(tag, arg, logLevel) do{ if (NULL == (arg)) \ + { OC_LOG((logLevel), tag, PCF(#arg " is NULL")); goto exit; } }while(0) /** * This method initializes the OicParseQueryIter_t struct @@ -97,6 +99,21 @@ void ParseQueryIterInit(unsigned char * query, OicParseQueryIter_t * parseIter); */ OicParseQueryIter_t * GetNextQuery(OicParseQueryIter_t * parseIter); + + +/** + * This method acts as a helper funtion for JSON unmarshalling by various SVR's. + * + * @param jsonRoot - root JSON node containing the OicUuid array + * @param arrayItem - name of the JSON OicUuid array item + * @param numUuids - pointer to the number of OicUuid's available in JSON array + * @param uuids - pointer to the array of OicUuid's + * + * @return ::OC_STACK_OK on success, some other value upon failure. + */ +OCStackResult AddUuidArray(cJSON* jsonRoot, const char* arrayItem, + size_t *numUuids, OicUuid_t** uuids ); + #ifdef __cplusplus } #endif // __cplusplus diff --git a/resource/csdk/security/provisioning/README.txt b/resource/csdk/security/provisioning/README.txt new file mode 100644 index 0000000..ca99cfb --- /dev/null +++ b/resource/csdk/security/provisioning/README.txt @@ -0,0 +1,53 @@ +Quick guide : How to make provisioning tool and servers. + +1. Provisioning Tool. + + 1-1. Callback function registration + Register the callback functions of ownership transfer method(OxM) using OTMSetOwnershipTransferCallbackData API. + You can use default OxM callback implementation located in resource/csdk/security/provisioning/include/oxm. + + [Sample code for just-works OxM] + OTMCallbackData_t justWorksCBData = {}; + justWorksCBData.loadSecretCB = LoadSecretJustWorksCallback; + justWorksCBData.createSecureSessionCB = CreateSecureSessionJustWorksCallback; + justWorksCBData.createSelectOxmPayloadCB = CreateJustWorksSelectOxmPayload; + justWorksCBData.createOwnerTransferPayloadCB = CreateJustWorksOwnerTransferPayload; + OTMSetOwnershipTransferCallbackData(OIC_JUST_WORKS, &justWorksCBData); + + 1-2. Find un-owned devices using OCDiscoverUnownedDevices API. + OCDiscoverUnownedDevices will fill the unowned device list in second parameter. + + [Sample code for unowned device discovery] + OCProvisionDev_t* pDeviceList = NULL; + OCStackResult res = OCDiscoverUnownedDevices(PREDEFINED_TIMEOUT, &pDeviceList); + if(OC_STACK_OK != res) + { + //error + } + + NOTE : We also provide OCDiscoverOwnedDevices API to find owned devices. + + 1-3. Performing ownership transfer + We provided OCDoOwnershipTransfer API to perform ownership transfer. + In order to perform ownership transfer, unowned device list is required generated by OCDiscoverUnownedDevices API. + OCDoOwnershipTransfer will require the result callback as 3rd paramter. + This callback function will be invoked when ownership transfer is finished. + You can check result of ownership transfer for each devices as array of OCProvisionResult_t. + + 1-4. Find owned devices using OCDiscoverOwendDevices API. + 1-5. Provision credential between two owned devices. + If you have owned devices, + You can send a credential to two owned devices using OCProvisionPairwiseDevices. + You can also send ACL in this process. + + 1-6. Free memory. + We provide ODDeleteDiscoverdDevices API to free list of OCProvisionDev_t. + Please delete your device list before the exit your application. + + +2. Server. + The samples are resource/csdk/security/provisioning/sample + 2-1. Just-works OxM. + If you use just-works OxM to server. + You don't need any modification for your server. + diff --git a/resource/csdk/security/provisioning/SConscript b/resource/csdk/security/provisioning/SConscript index d5cc915..86317a1 100644 --- a/resource/csdk/security/provisioning/SConscript +++ b/resource/csdk/security/provisioning/SConscript @@ -35,12 +35,14 @@ provisioning_env.AppendUnique(CPPPATH = [ '../../ocmalloc/include', 'include', 'include/internal', + 'include/oxm', '../../resource/csdk/security/include', '../../../../extlibs/cjson/', - '../../../../../extlibs/tinydtlsra/', + '../../../../../extlibs/tinydtls/', '../../connectivity/inc', '../../connectivity/external/inc', '../../connectivity/common/inc', + '../../connectivity/lib/libcoap-4.1.1', '../../connectivity/api', '../include', '../include/internal' @@ -78,13 +80,17 @@ if target_os in ['darwin', 'ios']: # Source files and Targets ###################################################################### provisioning_src = [ - 'src/provisioningmanager.c', - 'src/credentialgenerator.c' - ] -provisioningserver = provisioning_env.StaticLibrary('ocspapi', provisioning_src) + 'src/pmutility.c', + 'src/credentialgenerator.c', + 'src/ownershiptransfermanager.c', + 'src/secureresourceprovider.c', + 'src/ocprovisioningmanager.c', + 'src/oxmjustworks.c', + 'src/oxmrandompin.c' ] +provisioningserver = provisioning_env.StaticLibrary('ocpmapi', provisioning_src) -provisioning_env.InstallTarget(provisioningserver, 'libocspapi') -provisioning_env.UserInstallTargetLib(provisioningserver, 'libocspapi') +provisioning_env.InstallTarget(provisioningserver, 'libocpmapi') +provisioning_env.UserInstallTargetLib(provisioningserver, 'libocpmapi') if target_os in ['linux']: SConscript('sample/SConscript') diff --git a/resource/csdk/security/provisioning/include/internal/credentialgenerator.h b/resource/csdk/security/provisioning/include/internal/credentialgenerator.h index 259a608..470e820 100644 --- a/resource/csdk/security/provisioning/include/internal/credentialgenerator.h +++ b/resource/csdk/security/provisioning/include/internal/credentialgenerator.h @@ -18,25 +18,26 @@ * * *****************************************************************/ -#ifndef SP_CREDENTIAL_GENERATOR_H -#define SP_CREDENTIAL_GENERATOR_H +#ifndef PM_CREDENTIAL_GENERATOR_H +#define PM_CREDENTIAL_GENERATOR_H #include "ocstack.h" #include "securevirtualresourcetypes.h" -#include "provisioningmanager.h" /** * Function to generate credentials according to the type. * * @param[in] type Type of credential. + * @param[in] keysize size of key. * @param[in] ptDeviceId Device ID of provisioning tool. * @param[in] firstDeviceId DeviceID of the first device. * @param[in] secondDeviceId DeviceID of the second device. * @param[out] firstCred Generated credential for first device. * @param[out] secondCred Generated credential for second device. - * @return SP_SUCCESS on success + * @return OC_STACK_OK on success */ -SPResult SPGeneratePairWiseCredentials(OicSecCredType_t type, const OicUuid_t *ptDeviceId, +OCStackResult PMGeneratePairWiseCredentials(OicSecCredType_t type, size_t keySize, + const OicUuid_t *ptDeviceId, const OicUuid_t *firstDeviceId, const OicUuid_t *secondDeviceId, OicSecCred_t **firstCred, @@ -45,4 +46,4 @@ SPResult SPGeneratePairWiseCredentials(OicSecCredType_t type, const OicUuid_t *p #ifdef __cplusplus } #endif -#endif //SP_CREDENTIAL_GENERATOR_H +#endif //PM_CREDENTIAL_GENERATOR_H diff --git a/resource/csdk/security/provisioning/include/internal/ownershiptransfermanager.h b/resource/csdk/security/provisioning/include/internal/ownershiptransfermanager.h new file mode 100644 index 0000000..64f7368 --- /dev/null +++ b/resource/csdk/security/provisioning/include/internal/ownershiptransfermanager.h @@ -0,0 +1,98 @@ +/* ***************************************************************** + * + * Copyright 2015 Samsung Electronics 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 OTM_OWNERSHIPTRANSFERMANAGER_H_ +#define OTM_OWNERSHIPTRANSFERMANAGER_H_ + +#include "pmtypes.h" +#include "ocstack.h" +#include "octypes.h" +#include "securevirtualresourcetypes.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#define OXM_STRING_MAX_LENGTH 32 + + +/** + * Context for ownership transfer(OT) + */ +typedef struct OTMContext{ + void* userCtx; /**< Context for user**/ + OCProvisionDev_t* selectedDeviceInfo; /**< Selected device info for OT */ + OicUuid_t tempCredId; +}OTMContext_t; + +/** + * Do ownership transfer for un-owned device. + * + * @param[in] ctx Application context would be returned in result callback + * @param[in] selectedDeviceInfo selected device information + * @param[in] resultCB Result callback function to be invoked when ownership transfer finished. + * @return OC_STACK_OK in case of success and other value otherwise. + */ +OCStackResult OTMDoOwnershipTransfer(void* ctx, + OCProvisionDev_t* selectedDeviceInfo, OCProvisionResultCB resultCB); + +/* + *Callback for load secret for temporal secure session + * + * e.g) in case of PIN based, input the pin through this callback + * in case of X.509 based, input the certificate through this callback + */ +typedef OCStackResult (*OTMLoadSecret)(OTMContext_t* otmCtx); + + +/* + * Callback for create secure channel using secret inputed from OTMLoadSecret callback + */ +typedef OCStackResult (*OTMCreateSecureSession)(OTMContext_t* otmCtx); + +/* + * Callback for creating CoAP payload. + */ +typedef char* (*OTMCreatePayloadCallback)(OTMContext_t* otmCtx); + +/** + * Required callback for performing ownership transfer + */ +typedef struct OTMCallbackData{ + OTMLoadSecret loadSecretCB; + OTMCreateSecureSession createSecureSessionCB; + OTMCreatePayloadCallback createSelectOxmPayloadCB; + OTMCreatePayloadCallback createOwnerTransferPayloadCB; +}OTMCallbackData_t; + +/** + * Set the callbacks for ownership transfer + * + * @param[in] oxm Ownership transfer method + * @param[in] callbackData the implementation of the ownership transfer function for each step. + * @return OC_STACK_OK in case of success and other value otherwise. + */ +OCStackResult OTMSetOwnershipTransferCallbackData(OicSecOxm_t oxm, OTMCallbackData_t* callbackData); + + +#ifdef __cplusplus +} +#endif +#endif //OTM_OWNERSHIPTRANSFERMANAGER_H_ \ No newline at end of file diff --git a/resource/csdk/security/provisioning/include/internal/secureresourceprovider.h b/resource/csdk/security/provisioning/include/internal/secureresourceprovider.h new file mode 100644 index 0000000..1ea7fd6 --- /dev/null +++ b/resource/csdk/security/provisioning/include/internal/secureresourceprovider.h @@ -0,0 +1,62 @@ +/* ***************************************************************** + * + * Copyright 2015 Samsung Electronics 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 SRP_SECURERESOURCEPROVIDER_H +#define SRP_SECURERESOURCEPROVIDER_H + +#include "ocstack.h" +#include "securevirtualresourcetypes.h" +#include "pmtypes.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * API to send ACL information to resource. + * + * @param[in] selectedDeviceInfo Selected target device. + * @param[in] acl ACL to provision. + * @param[in] resultCallback callback provided by API user, callback will be called when + * provisioning request recieves a response from resource server. + * @return SP_SUCCESS in case of success and other value otherwise. + */ +OCStackResult SRPProvisionACL(void *ctx, const OCProvisionDev_t *selectedDeviceInfo, + OicSecAcl_t *acl, OCProvisionResultCB resultCallback); + +/** + * API to provision credential to devices. + * + * @param[in] type Type of credentials to be provisioned to the device. + * @param[in] pDev1 Pointer to PMOwnedDeviceInfo_t instance,respresenting resource to be provsioned. + @param[in] pDev2 Pointer to PMOwnedDeviceInfo_t instance,respresenting resource to be provsioned. + * @param[in] resultCallback callback provided by API user, callback will be called when + * provisioning request recieves a response from first resource server. + * @return OC_STACK_OK in case of success and other value otherwise. + */ +OCStackResult SRPProvisionCredentials(void *ctx,OicSecCredType_t type, size_t keySize, + const OCProvisionDev_t *pDev1, + const OCProvisionDev_t *pDev2, + OCProvisionResultCB resultCallback); +#ifdef __cplusplus +} +#endif +#endif //SRP_SECURERESOURCEPROVIDER_H diff --git a/resource/csdk/security/provisioning/include/ocprovisioningmanager.h b/resource/csdk/security/provisioning/include/ocprovisioningmanager.h new file mode 100644 index 0000000..f7169c1 --- /dev/null +++ b/resource/csdk/security/provisioning/include/ocprovisioningmanager.h @@ -0,0 +1,155 @@ +/* ***************************************************************** + * + * Copyright 2015 Samsung Electronics 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 OCPROVISIONINGMANAGER_H_ +#define OCPROVISIONINGMANAGER_H_ + +#include "octypes.h" +#include "pmtypes.h" +#include "ownershiptransfermanager.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** + * The function is responsible for initializaton of the provisioning manager. It will load + * provisioning database which have owned device's list and their linked status. + * In addition, if there is a device(s) which has not up-to-date credentials, this function will + * automatically try to update the deivce(s). + * + * @param[in] dbPath file path of the sqlite3 db + * + * @return OC_STACK_OK in case of success and other value otherwise. + */ +OCStackResult OCProvisionInit(const char* dbPath); + +/** + * The function is responsible for discovery of device is current subnet. It will list + * all the device in subnet which are not yet owned. Please call OCInit with OC_CLIENT_SERVER as + * OCMode. + * + * @param[in] timeout Timeout in seconds, value till which function will listen to responses from + * client before returning the list of devices. + * @param[out] ppList List of candidate devices to be provisioned + * @return OTM_SUCCESS in case of success and other value otherwise. + */ +OCStackResult OCDiscoverUnownedDevices(unsigned short waittime, OCProvisionDev_t **ppList); + +/** + * Do ownership transfer for un-owned device. + * + * @param[in] ctx Application context would be returned in result callback + * @param[in] targetDevices List of devices to perform ownership transfer. + * @param[in] resultCallback Result callback function to be invoked when ownership transfer finished. + * @return OC_STACK_OK in case of success and other value otherwise. + */ +OCStackResult OCDoOwnershipTransfer(void* ctx, + OCProvisionDev_t *targetDevices, + OCProvisionResultCB resultCallback); + +/** + * API to register for particular OxM. + * + * @param[in] Ownership transfer method. + * @param[in] Implementation of callback functions for owership transfer. + * @return OC_STACK_OK in case of success and other value otherwise. + */ +OCStackResult OCSetOwnerTransferCallbackData(OicSecOxm_t oxm, OTMCallbackData_t* callbackData); + +/** + * The function is responsible for discovery of owned device is current subnet. It will list + * all the device in subnet which are owned by calling provisioning client. + * + * @param[in] timeout Timeout in seconds, value till which function will listen to responses from + * client before returning the list of devices. + * @param[out] ppList List of device owned by provisioning tool. + * @return OTM_SUCCESS in case of success and other value otherwise. + */ +OCStackResult OCDiscoverOwnedDevices(unsigned short timeout, OCProvisionDev_t **ppList); + +/** + * API to provision credentials between two devices and ACLs for the devices who act as a server. + * + * @param[in] ctx Application context would be returned in result callback. + * @param[in] type Type of credentials to be provisioned to the device. + * @param[in] pDev1 Pointer to OCProvisionDev_t instance,respresenting device to be provisioned. + * @param[in] acl ACL for device 1. If this is not required set NULL. + * @param[in] pDev2 Pointer to OCProvisionDev_t instance,respresenting device to be provisioned. + * @param[in] acl ACL for device 2. If this is not required set NULL. + * @param[in] resultCallback callback provided by API user, callback will be called when + * provisioning request recieves a response from first resource server. + * @return OC_STACK_OK in case of success and other value otherwise. + */ +OCStackResult OCProvisionPairwiseDevices(void* ctx, OicSecCredType_t type, size_t keySize, + const OCProvisionDev_t *pDev1, OicSecAcl_t *pDev1Acl, + const OCProvisionDev_t *pDev2, OicSecAcl_t *pDev2Acl, + OCProvisionResultCB resultCallback); + +/** + * API to send ACL information to device. + * + * @param[in] ctx Application context would be returned in result callback. + * @param[in] selectedDeviceInfo Selected target device. + * @param[in] acl ACL to provision. + * @param[in] resultCallback callback provided by API user, callback will be called when provisioning + request recieves a response from resource server. + * @return OC_STACK_OK in case of success and other value otherwise. + */ +OCStackResult OCProvisionACL(void *ctx, const OCProvisionDev_t *selectedDeviceInfo, OicSecAcl_t *acl, + OCProvisionResultCB resultCallback); + +/** + * API to provision credential to devices. + * + * @param[in] ctx Application context would be returned in result callback. + * @param[in] type Type of credentials to be provisioned to the device. + * @param[in] pDev1 Pointer to OCProvisionDev_t instance,respresenting resource to be provsioned. + @param[in] pDev2 Pointer to OCProvisionDev_t instance,respresenting resource to be provsioned. + * @param[in] resultCallback callback provided by API user, callback will be called when + * provisioning request recieves a response from first resource server. + * @return OC_STACK_OK in case of success and other value otherwise. + */ +OCStackResult OCProvisionCredentials(void *ctx, OicSecCredType_t type, size_t keySize, + const OCProvisionDev_t *pDev1, + const OCProvisionDev_t *pDev2, + OCProvisionResultCB resultCallback); + +/** + * API to delete memory allocated to linked list created by OCDiscover_XXX_Devices API. + * + * @param[in] ppList Pointer to OCProvisionDev_t which should be deleted. + */ +void OCDeleteDiscoveredDevices(OCProvisionDev_t **ppList); + +/** + * API to delete memory allocated to OCProvisionResult_t list in callback function. + * + * @note: This function must be called in the callback implementation after checking results. + * + * @param[in] pList Pointer to OCProvisionResult_t list which should be deleted. + */ +void OCDeleteProvisionResults(OCProvisionResult_t *pList); + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif /* OCPROVISIONINGMANAGER_H_ */ diff --git a/resource/csdk/security/provisioning/include/oxm/oxmjustworks.h b/resource/csdk/security/provisioning/include/oxm/oxmjustworks.h new file mode 100644 index 0000000..4f2b112 --- /dev/null +++ b/resource/csdk/security/provisioning/include/oxm/oxmjustworks.h @@ -0,0 +1,70 @@ +/* ***************************************************************** + * + * Copyright 2015 Samsung Electronics 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 OXM_JUST_WORKS_H_ +#define OXM_JUST_WORKS_H_ + +#include "ocstack.h" +#include "securevirtualresourcetypes.h" +#include "ownershiptransfermanager.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// +//Declaration of default callback functions for just works OxM. +// + +/** + * In case of just works OxM, no need to implement. + */ +OCStackResult LoadSecretJustWorksCallback(OTMContext_t* UNUSED_PARAM); + +/** + * To establish a secure channel with anonymous cipher suite + * + * @param[in] selectedDeviceInfo Selected device infomation + * @return OC_STACK_SUCCESS in case of success and other value otherwise. + */ +OCStackResult CreateSecureSessionJustWorksCallback(OTMContext_t* otmCtx); + +/** + * Generate payload for select OxM request. + * + * @param[in] selectedDeviceInfo Selected device infomation + * @return DOXM JSON payload including the selected OxM. + * NOTE : Returned memory should be deallocated by caller. + */ +char* CreateJustWorksSelectOxmPayload(OTMContext_t* otmCtx); + +/** + * Generate payload for owner transfer request. + * + * @param[in] selectedDeviceInfo Selected device infomation + * @return DOXM JSON payload including the owner information. + * NOTE : Returned memory should be deallocated by caller. + */ +char* CreateJustWorksOwnerTransferPayload(OTMContext_t* otmCtx); + +#ifdef __cplusplus +} +#endif +#endif //OXM_JUST_WORKS_H_ \ No newline at end of file diff --git a/resource/csdk/security/provisioning/include/oxm/oxmrandompin.h b/resource/csdk/security/provisioning/include/oxm/oxmrandompin.h new file mode 100644 index 0000000..db5556f --- /dev/null +++ b/resource/csdk/security/provisioning/include/oxm/oxmrandompin.h @@ -0,0 +1,73 @@ +/* ***************************************************************** + * + * Copyright 2015 Samsung Electronics 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 OXM_RANDOM_PIN_H_ +#define OXM_RANDOM_PIN_H_ + +#include "ocstack.h" +#include "securevirtualresourcetypes.h" +#include "ownershiptransfermanager.h" +#include "pmtypes.h" +#include "pinoxmcommon.h" + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#define OXM_PBKDF2_ITERATIONS 1000 + +/** + * Callback implementation to input the PIN code from user. + * + * @otmCtx Context of OTM, It includes current device infomation. + * @return OC_STACK_SUCCESS in case of success and other value otherwise. + */ +OCStackResult InputPinCodeCallback(OTMContext_t* otmCtx); + +/** + * Callback implemenration to establish a secure channel with PSK cipher suite + * + * @param[in] selectedDeviceInfo Selected device infomation + * @return OC_STACK_SUCCESS in case of success and other value otherwise. + */ +OCStackResult CreateSecureSessionRandomPinCallbak(OTMContext_t* otmCtx); + +/** + * Generate payload for select OxM request. + * + * @param[in] selectedDeviceInfo Selected device infomation + * @return DOXM JSON payload including the selected OxM. + * NOTE : Returned memory should be deallocated by caller. + */ +char* CreatePinBasedSelectOxmPayload(OTMContext_t* otmCtx); + +/** + * Generate payload for owner transfer request. + * + * @param[in] selectedDeviceInfo Selected device infomation + * @return DOXM JSON payload including the owner information. + * NOTE : Returned memory should be deallocated by caller. + */ +char* CreatePinBasedOwnerTransferPayload(OTMContext_t* otmCtx); + +#ifdef __cplusplus +} +#endif +#endif //OXM_RANDOM_PIN_H_ \ No newline at end of file diff --git a/resource/csdk/security/provisioning/include/pmtypes.h b/resource/csdk/security/provisioning/include/pmtypes.h new file mode 100644 index 0000000..377ce2b --- /dev/null +++ b/resource/csdk/security/provisioning/include/pmtypes.h @@ -0,0 +1,66 @@ +/* ***************************************************************** + * + * Copyright 2015 Samsung Electronics 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_PROVISIONING_TYPES_H +#define OC_PROVISIONING_TYPES_H + +#include +#include "securevirtualresourcetypes.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Device Information of discoverd unowned/owned device(s) for provisioning. + */ +typedef struct OCProvisionDev +{ + OCDevAddr endpoint; /**< target address **/ + OicSecPstat_t *pstat; /**< Pointer to target's pstat resource. **/ + OicSecDoxm_t *doxm; /**< Pointer to target's doxm resource. **/ + uint16_t securePort; /**< secure port **/ + struct OCProvisionDev *next; /**< Next pointer. **/ +}OCProvisionDev_t; + +/** + * Result information for each target device. + */ +typedef struct OCPMResult{ + OicUuid_t deviceId; + OCStackResult res; +}OCProvisionResult_t; + +/** + * Callback function definition of provisioning API + * + * @param[OUT] ctx - If user set his/her context, it will be returned here. + * @param[OUT] nOfRes - total number of results, it depends on using which provisioning API. + * @param[OUT] arr - Array of OCPMResult_t, each OCPMResult_t contains result for target Device. + * @param[OUT} hasError - If there is no error, it's returned with 'false' but if there is a single + * or more error is/are occured during operation, it will be 'true'. + */ +typedef void (*OCProvisionResultCB)(void* ctx, int nOfRes, OCProvisionResult_t *arr, bool hasError); + +#ifdef __cplusplus +} +#endif + +#endif //OC_PROVISIONING_TYPES_H \ No newline at end of file diff --git a/resource/csdk/security/provisioning/include/pmutility.h b/resource/csdk/security/provisioning/include/pmutility.h new file mode 100644 index 0000000..79f98b5 --- /dev/null +++ b/resource/csdk/security/provisioning/include/pmutility.h @@ -0,0 +1,61 @@ +/* ***************************************************************** + * + * Copyright 2015 Samsung Electronics 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 _PM_UTILITY_H_ +#define _PM_UTILITY_H_ + +#include +#include "ocstack.h" +#include "pmtypes.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define DEFAULT_SECURE_PORT 5684 + +#define COAPS_PREFIX "coaps://" +#define COAP_PREFIX "coap://" +#define COAPS_QUERY "coaps://%s:%d%s" +#define COAP_QUERY "coap://%s:%d%s" + +/** + * Discover owned/unowned devices in the same IP subnet. . + * + * @param[in] waittime Timeout in seconds. + * @param[in] isOwned bool flag for owned / unowned discovery + * @param[in] ppList List of OCProvisionDev_t. + * + * @return OC_STACK_OK on success otherwise error. + */ +OCStackResult PMDeviceDiscovery(unsigned short waittime, bool isOwned, OCProvisionDev_t **ppList); + +/** + * This function deletes list of provision target devices + * + * @param[in] pList List of OCProvisionDev_t. + */ +void DeleteDeviceList(OCProvisionDev_t **pList); + +#ifdef __cplusplus +} +#endif +#endif //_PM_UTILITY_H_ diff --git a/resource/csdk/security/provisioning/include/provisioningmanager.h b/resource/csdk/security/provisioning/include/provisioningmanager.h deleted file mode 100644 index cf23b88..0000000 --- a/resource/csdk/security/provisioning/include/provisioningmanager.h +++ /dev/null @@ -1,159 +0,0 @@ -/* ***************************************************************** - * - * Copyright 2015 Samsung Electronics 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 SP_PROVISION_API_H -#define SP_PROVISION_API_H - -#include "ocstack.h" -#include "securevirtualresourcetypes.h" - -#ifdef __cplusplus -extern "C" -{ -#endif - -/** - * Error Code. - */ -typedef enum -{ - SP_RESULT_SUCCESS = 0, - SP_RESULT_INVALID_PARAM, - SP_RESULT_MEM_ALLOCATION_FAIL, - SP_RESULT_INTERNAL_ERROR, - SP_RESULT_TIMEOUT, - SP_RESULT_CONN_INVALID_PARAM, - SP_RESULT_CONN_ADAPTER_NOT_ENABLED, - SP_RESULT_CONN_SERVER_STARTED_ALREADY, - SP_RESULT_CONN_SERVER_NOT_STARTED, - SP_RESULT_CONN_DESTINATION_NOT_REACHABLE, - SP_RESULT_CONN_SOCKET_OPERATION_FAILED, - SP_RESULT_CONN_SEND_FAILED, - SP_RESULT_CONN_RECEIVE_FAILED, - SP_RESULT_CONN_MEMORY_ALLOC_FAILED, - SP_RESULT_CONN_REQUEST_TIMEOUT, - SP_RESULT_CONN_DESTINATION_DISCONNECTED, - SP_RESULT_CONN_STATUS_FAILED, - SP_RESULT_CONN_NOT_SUPPORTED - -} SPResult; - -typedef struct SPTargetDeviceInfo SPTargetDeviceInfo_t; -typedef struct SPDevInfo SPDevInfo_t; - -/** - * Device Info structure. - */ -struct SPTargetDeviceInfo -{ - OCDevAddr endpoint; /**< target address **/ - OicSecPstat_t *pstat; /**< Pointer to target's pstat resource. **/ - OicSecDoxm_t *doxm; /**< Pointer to target's doxm resource. **/ - uint16_t securePort; /**< Secure port **/ - SPTargetDeviceInfo_t *next; /**< Next pointer. **/ -}; - -/** - * Owned target device info - */ -struct SPDevInfo -{ - OCDevAddr endpoint; /**< target address **/ - OicUuid_t deviceId; /**< Device ID. **/ - SPDevInfo_t *next; /**< Next pointer. **/ -}; - -/** - * The function is responsible for discovery of device is current subnet. It will list - * all the device in subnet which are not yet owned. Please call OCInit with OC_CLIENT_SERVER as - * OCMode. - * - * @param[in] timeout Timeout in seconds, value till which function will listen to responses from - * client before returning the list of devices. - * @param[out] list List of provision candidate devices. - * @return SP_SUCCESS in case of success and other value otherwise. - */ -SPResult SPProvisioningDiscovery(unsigned short timeout, - SPTargetDeviceInfo_t **list); - -/** - * The function is reponsible for following activities: - * - Send post to /oic/sec/doxm resource with selected ownership transfer method - * - Get pstat resource of target device to enumerate supported operation modes. - * - Select and let the target device know the selected methods. - * - Initiate anon handshake and save owner PSK - * - Update doxm resource of target device with ownership info. - * - * @param[in] timeout Timeout value in secs till which call REST request will wait before - * returning error in case of 0 function will wait till success. - * @param[in] selectedDeviceInfo Device information. - * @return SP_SUCCESS in case of success and other value otherwise. - */ -SPResult SPInitProvisionContext(unsigned short timeout, - SPTargetDeviceInfo_t *selectedDeviceInfo); - -/** - * Function to send ACL information to resource. - * - * @param[in] timeout Timeout value in secs till which call to REST request will wait before - * returning error in case of 0 function will wait till success. - * @param[in] selectedDeviceInfo Selected target device. - * @param[in] acl ACL to provision - * @return SP_SUCCESS in case of success and other value otherwise. - */ -SPResult SPProvisionACL(unsigned short timeout, const SPTargetDeviceInfo_t *selectedDeviceInfo, - OicSecAcl_t *acl); - -/** - * Function to send credential information to list of resources. - * - * @param[in] timeout Timeout value in secs till which call to REST request will wait before - * returning error in case of 0 function will wait till success. - * @param[in] type Type of credentials to be provisioned to the device. - * @param[in] pDevList List of devices to be provisioned with the specified credential. - * - * @return SP_SUCCESS in case of success and other value otherwise. - */ -SPResult SPProvisionCredentials(unsigned short timeout, OicSecCredType_t type, - const SPDevInfo_t *pDevList); - -/** - * Function to confirm the ACL post request to check whether its updated at - * resource server end properly or not. - * - * @param[in] timeout Timeout value in seconds till which call REST request will wait - * before returning error in case of 0 function will wait till success. - * @param[in] context Provisioning context - * @return SP_SUCCESS on success - */ -SPResult SPFinalizeProvisioning(unsigned short timeout, - SPTargetDeviceInfo_t *selectedDeviceInfo); - -/** - * Function to end Provisioning session. - * - * @return SP_SUCCESS on success - */ -SPResult SPTerminateProvisioning(); - -#ifdef __cplusplus -} -#endif -#endif //SP_PROVISION_API_H diff --git a/resource/csdk/security/provisioning/sample/SConscript b/resource/csdk/security/provisioning/sample/SConscript index 1947307..46e270e 100644 --- a/resource/csdk/security/provisioning/sample/SConscript +++ b/resource/csdk/security/provisioning/sample/SConscript @@ -32,8 +32,10 @@ provisioning_env.AppendUnique(CPPPATH = [ '../../../logger/include', '../../../stack/include', '../../../security/include', + '../../../security/provisioning/include/internal', '../../../../oc_logger/include', '../include', + '../include/oxm', '../../include', '../../../../../extlibs/tinydtls', '../../../../../extlibs/cjson', @@ -49,7 +51,7 @@ provisioning_env.AppendUnique(CXXFLAGS = ['-std=c++0x', '-Wall', '-pthread', '-f provisioning_env.AppendUnique(RPATH = [env.get('BUILD_DIR')]) provisioning_env.AppendUnique(LIBS = ['-lpthread']) provisioning_env.AppendUnique(LIBPATH = [env.get('BUILD_DIR')]) -provisioning_env.PrependUnique(LIBS = ['ocspapi','oc', 'oc_logger', 'ocsrm','m', 'octbstack', 'connectivity_abstraction', 'coap']) +provisioning_env.PrependUnique(LIBS = ['ocpmapi','oc', 'oc_logger', 'ocsrm','m', 'octbstack', 'connectivity_abstraction', 'coap']) if env.get('SECURED') == '1': provisioning_env.AppendUnique(LIBS = ['tinydtls']) @@ -62,8 +64,10 @@ provisioning_env.AppendUnique(CPPDEFINES = ['TB_LOG']) ###################################################################### provisioningclient = provisioning_env.Program('provisioningclient', 'provisioningclient.c') +sampleserver_justworks = provisioning_env.Program('sampleserver_justworks', 'sampleserver_justworks.cpp') +sampleserver_randompin = provisioning_env.Program('sampleserver_randompin', 'sampleserver_randompin.cpp') -Alias("sample", [provisioningclient]) +Alias("samples", [provisioningclient, sampleserver_justworks, sampleserver_randompin]) provisioning_env.AppendTarget('samples') @@ -72,6 +76,8 @@ sec_provisioning_src_dir = src_dir + '/resource/csdk/security/provisioning/sampl sec_provisioning_build_dir = env.get('BUILD_DIR') +'/resource/csdk/security/provisioning/sample/' provisioning_env.Alias("install", provisioning_env.Install( sec_provisioning_build_dir, - sec_provisioning_src_dir + 'oic_svr_db_prov_tool.json')) + sec_provisioning_src_dir + 'oic_svr_db_client.json')) provisioning_env.Alias("install", provisioning_env.Install( sec_provisioning_build_dir, - sec_provisioning_src_dir + 'oic_svr_db_unowned_server.json')) + sec_provisioning_src_dir + 'oic_svr_db_server_justworks.json')) +provisioning_env.Alias("install", provisioning_env.Install( sec_provisioning_build_dir, + sec_provisioning_src_dir + 'oic_svr_db_server_randompin.json')) diff --git a/resource/csdk/security/provisioning/sample/oic_svr_db_client.json b/resource/csdk/security/provisioning/sample/oic_svr_db_client.json new file mode 100644 index 0000000..49fb2a8 --- /dev/null +++ b/resource/csdk/security/provisioning/sample/oic_svr_db_client.json @@ -0,0 +1,43 @@ +{ + "acl": [ + { + "sub": "Kg==", + "rsrc": [ + "/oic/res", + "/oic/d", + "/oic/p", + "/oic/res/types/d", + "/oic/ad" + ], + "perms": 2, + "ownrs" : ["YWRtaW5EZXZpY2VVVUlEMA=="] + }, + { + "sub": "Kg==", + "rsrc": [ + "/oic/sec/doxm", + "/oic/sec/pstat", + "/oic/sec/acl", + "/oic/sec/cred" + ], + "perms": 7, + "ownrs" : ["YWRtaW5EZXZpY2VVVUlEMA=="] + } + ], + "pstat": { + "isop": true, + "deviceid": "YWRtaW5EZXZpY2VVVUlEMA==", + "ch": 0, + "cm": 0, + "tm": 0, + "om": 3, + "sm": [3] + }, + "doxm": { + "oxm": [0], + "oxmsel": 0, + "owned": true, + "deviceid": "YWRtaW5EZXZpY2VVVUlEMA==", + "ownr": "YWRtaW5EZXZpY2VVVUlEMA==" + } +} diff --git a/resource/csdk/security/provisioning/sample/oic_svr_db_server_justworks.json b/resource/csdk/security/provisioning/sample/oic_svr_db_server_justworks.json new file mode 100644 index 0000000..dab0d70 --- /dev/null +++ b/resource/csdk/security/provisioning/sample/oic_svr_db_server_justworks.json @@ -0,0 +1,45 @@ +{ + "acl": [ + { + "sub": "Kg==", + "rsrc": [ + "/oic/res", + "/oic/res/d", + "/oic/res/types/d", + "/oic/presence" + ], + "perms": 2, + "ownrs" : [ + "anVzdHdvcmtzRGV2VVVJRA==" + ] + }, + { + "sub": "Kg==", + "rsrc": [ + "/oic/sec/doxm", + "/oic/sec/pstat", + "/oic/sec/acl", + "/oic/sec/cred" + ], + "perms": 6, + "ownrs" : [ + "anVzdHdvcmtzRGV2VVVJRA==" + ] + } + ], + "pstat": { + "isop": false, + "deviceid": "anVzdHdvcmtzRGV2VVVJRA==", + "commithash": 0, + "cm": 0, + "tm": 0, + "om": 3, + "sm": [3] + }, + "doxm": { + "oxm": [0], + "oxmsel": 0, + "owned": false, + "deviceid": "anVzdHdvcmtzRGV2VVVJRA==" + } +} diff --git a/resource/csdk/security/provisioning/sample/oic_svr_db_server_randompin.json b/resource/csdk/security/provisioning/sample/oic_svr_db_server_randompin.json new file mode 100644 index 0000000..a3a4b6f --- /dev/null +++ b/resource/csdk/security/provisioning/sample/oic_svr_db_server_randompin.json @@ -0,0 +1,45 @@ +{ + "acl": [ + { + "sub": "Kg==", + "rsrc": [ + "/oic/res", + "/oic/res/d", + "/oic/res/types/d", + "/oic/presence" + ], + "perms": 2, + "ownrs" : [ + "cmFuZG9tUGluRGV2VVVJRA==" + ] + }, + { + "sub": "Kg==", + "rsrc": [ + "/oic/sec/doxm", + "/oic/sec/pstat", + "/oic/sec/acl", + "/oic/sec/cred" + ], + "perms": 6, + "ownrs" : [ + "cmFuZG9tUGluRGV2VVVJRA==" + ] + } + ], + "pstat": { + "isop": false, + "deviceid": "cmFuZG9tUGluRGV2VVVJRA==", + "commithash": 0, + "cm": 0, + "tm": 0, + "om": 3, + "sm": [3] + }, + "doxm": { + "oxm": [0,2], + "oxmsel": 0, + "owned": false, + "deviceid": "cmFuZG9tUGluRGV2VVVJRA==" + } +} diff --git a/resource/csdk/security/provisioning/sample/provisioningclient.c b/resource/csdk/security/provisioning/sample/provisioningclient.c index b342959..ee16b58 100644 --- a/resource/csdk/security/provisioning/sample/provisioningclient.c +++ b/resource/csdk/security/provisioning/sample/provisioningclient.c @@ -21,56 +21,64 @@ #include #include #include -#include + #include "logger.h" #include "oic_malloc.h" #include "utlist.h" -#include "securevirtualresourcetypes.h" -#include "provisioningmanager.h" +#include "ocprovisioningmanager.h" +#include "secureresourceprovider.h" +#include "oxmjustworks.h" +#include "oxmrandompin.h" +#include "pinoxmcommon.h" +#include "oic_string.h" #define MAX_URI_LENGTH (64) #define MAX_PERMISSION_LENGTH (5) -#define MAX_INPUT_ID_LENGTH (16) -#define PREDEFINED_TIMEOUT (10) #define CREATE (1) #define READ (2) #define UPDATE (4) #define DELETE (8) #define NOTIFY (16) #define DASH '-' +#define PREDEFINED_TIMEOUT (10) +#define MAX_OWNED_DEVICE (10) #define TAG "provisioningclient" -static OicSecAcl_t *gAcl = NULL; -static char PROV_TOOL_DB_FILE[] = "oic_svr_db_prov_tool.json"; +static char CRED_FILE[] = "oic_svr_db_client.json"; +static OicSecAcl_t *gAcl1 = NULL; +static OicSecAcl_t *gAcl2 = NULL; +static int gOwnershipState = 0; + +typedef enum +{ + ownershipDone = 1 << 1, + finalizeDone = 1 << 2, + provisionCredDone = 1 << 3, + provisionAclDone = 1 << 4 +} StateManager; + /** - * Perform cleanup for ACL list - * - * @param[in] ACL list + * Perform cleanup for ACL + * @param[in] ACL */ -static void DeleteACLList(OicSecAcl_t *acl) +static void deleteACL(OicSecAcl_t *acl) { if (acl) { - OicSecAcl_t *aclTmp1 = NULL; - OicSecAcl_t *aclTmp2 = NULL; - LL_FOREACH_SAFE(acl, aclTmp1, aclTmp2) + /* Clean Resources */ + for (size_t i = 0; i < (acl)->resourcesLen; i++) { - LL_DELETE(acl, aclTmp1); + OICFree((acl)->resources[i]); + } + OICFree((acl)->resources); - /* Clean Resources */ - for (int i = 0; i < aclTmp1->resourcesLen; i++) - { - OICFree(aclTmp1->resources[i]); - } - OICFree(aclTmp1->resources); + /* Clean Owners */ + OICFree((acl)->owners); - /* Clean Owners */ - OICFree(aclTmp1->owners); + /* Clean ACL node itself */ + OICFree((acl)); - /* Clean ACL node itself */ - OICFree(aclTmp1); - } acl = NULL; } } @@ -80,17 +88,15 @@ static void DeleteACLList(OicSecAcl_t *acl) * * @param[in] temp_psm Input data of ACL permission string * @param[in,out] pms The pointer of ACL permission value - * @return 0 on success otherwise a positive error value - * @retval SP_RESULT_SUCCESS Successful - * @retval SP_RESULT_INVALID_PARAM Invaild input arguments + * @return 0 on success otherwise -1. */ -static SPResult CalculateAclPermission(const char *temp_pms, uint16_t *pms) +static int CalculateAclPermission(const char *temp_pms, uint16_t *pms) { int i = 0; if (NULL == temp_pms || NULL == pms) { - return SP_RESULT_INVALID_PARAM; + return -1; } *pms = 0; while (temp_pms[i] != '\0') @@ -134,25 +140,23 @@ static SPResult CalculateAclPermission(const char *temp_pms, uint16_t *pms) } default: { - return SP_RESULT_INVALID_PARAM; + return -1; } } } - return SP_RESULT_SUCCESS; + return 0; } /** * Get the ACL property from user * * @param[in] ACL Datastructure to save user inputs - * @return 0 on success otherwise a positive error value - * @retval SP_RESULT_SUCCESS Successful - * @retval SP_RESULT_MEM_ALLOCATION_FAIL Memmory allocation failure + * @return 0 on success otherwise -1. */ -static SPResult InputACL(OicSecAcl_t *acl) +static int InputACL(OicSecAcl_t *acl) { - int unused __attribute__((unused)); - char temp_id [MAX_INPUT_ID_LENGTH + 4] = {0,}; + int ret; + char temp_id [UUID_LENGTH + 4] = {0,}; char temp_rsc[MAX_URI_LENGTH + 1] = {0,}; char temp_pms[MAX_PERMISSION_LENGTH + 1] = {0,}; printf("******************************************************************************\n"); @@ -162,37 +166,65 @@ static SPResult InputACL(OicSecAcl_t *acl) printf("-URN identifying the subject\n"); printf("ex) 1111-1111-1111-1111 (16 Numbers except to '-')\n"); printf("Subject : "); - unused = scanf("%19s", temp_id); + char *ptr = NULL; + ret = scanf("%19ms", &ptr); + if(1==ret) + { + OICStrcpy(temp_id, sizeof(temp_id), ptr); + OICFree(ptr); + } + else + { + printf("Error while input\n"); + return -1; + } int j = 0; for (int i = 0; temp_id[i] != '\0'; i++) { if (DASH != temp_id[i]) + { + if(j>UUID_LENGTH) + { + printf("Invalid input\n"); + return -1; + } acl->subject.id[j++] = temp_id[i]; + } } //Set Resource. - printf("Num. of Resource : "); - unused = scanf("%zu", &acl->resourcesLen); + printf("Num. of Resource : \n"); + ret = scanf("%zu", &acl->resourcesLen); printf("-URI of resource\n"); printf("ex)/oic/sh/temp/0 (Max_URI_Length: 64 Byte )\n"); - acl->resources = (char **)OICMalloc(acl->resourcesLen * sizeof(char *)); + acl->resources = (char **)OICCalloc(acl->resourcesLen, sizeof(char *)); if (NULL == acl->resources) { OC_LOG(ERROR, TAG, "Error while memory allocation"); - return SP_RESULT_MEM_ALLOCATION_FAIL; + return -1; } - for (int i = 0; i < acl->resourcesLen; i++) + for (size_t i = 0; i < acl->resourcesLen; i++) { - printf("[%d]Resource : ", i + 1); - unused = scanf("%64s", temp_rsc); - acl->resources[i] = (char *)OICMalloc((strlen(temp_rsc) + 1) * sizeof(char)); + printf("[%zu]Resource : ", i + 1); + char *ptr_tempRsc = NULL; + ret = scanf("%64ms", &ptr_tempRsc); + if (1==ret) + { + OICStrcpy(temp_rsc, sizeof(temp_rsc), ptr_tempRsc); + OICFree(ptr_tempRsc); + } + else + { + printf("Error while input\n"); + return -1; + } + acl->resources[i] = OICStrdup(temp_rsc); + if (NULL == acl->resources[i]) { OC_LOG(ERROR, TAG, "Error while memory allocation"); - return SP_RESULT_MEM_ALLOCATION_FAIL; + return -1; } - strncpy(acl->resources[i], temp_rsc, strlen(temp_rsc)); - acl->resources[i][strlen(temp_rsc)] = '\0'; } // Set Permission do @@ -200,24 +232,47 @@ static SPResult InputACL(OicSecAcl_t *acl) printf("-Set the permission(C,R,U,D,N)\n"); printf("ex) CRUDN, CRU_N,..(5 Charaters)\n"); printf("Permission : "); - unused = scanf("%5s", temp_pms); + char *ptr_temp_pms = NULL; + ret = scanf("%5ms", &ptr_temp_pms); + if(1 == ret) + { + OICStrcpy(temp_pms, sizeof(temp_pms), ptr_temp_pms); + OICFree(ptr_temp_pms); + + } + else + { + printf("Error while input\n"); + return -1; + } } - while (SP_RESULT_SUCCESS != CalculateAclPermission(temp_pms, &(acl->permission)) ); + while (0 != CalculateAclPermission(temp_pms, &(acl->permission)) ); // Set Rowner printf("Num. of Rowner : "); - unused = scanf("%zu", &acl->ownersLen); + ret = scanf("%zu", &acl->ownersLen); printf("-URN identifying the rowner\n"); printf("ex) 1111-1111-1111-1111 (16 Numbers except to '-')\n"); acl->owners = (OicUuid_t *)OICCalloc(acl->ownersLen, sizeof(OicUuid_t)); if (NULL == acl->owners) { OC_LOG(ERROR, TAG, "Error while memory allocation"); - return SP_RESULT_MEM_ALLOCATION_FAIL; + return -1; } - for (int i = 0; i < acl->ownersLen; i++) + for (size_t i = 0; i < acl->ownersLen; i++) { - printf("[%d]Rowner : ", i + 1); - unused = scanf("%19s", temp_id); + printf("[%zu]Rowner : ", i + 1); + char *ptr_temp_id = NULL; + ret = scanf("%19ms", &ptr_temp_id); + if (1 == ret) + { + OICStrcpy(temp_id, sizeof(temp_id), ptr_temp_id); + OICFree(ptr_temp_id); + } + else + { + printf("Error while input\n"); + return -1; + } j = 0; for (int k = 0; temp_id[k] != '\0'; k++) { @@ -227,27 +282,116 @@ static SPResult InputACL(OicSecAcl_t *acl) } } } - return SP_RESULT_SUCCESS; + return 0; +} + + +//FILE *client_fopen(const char *path, const char *mode) +FILE *client_fopen(const char* UNUSED_PARAM , const char *mode) +{ + (void)UNUSED_PARAM; + return fopen(CRED_FILE, mode); +} + +void PrintfResult(const char* procName, void* ctx, int nOfRes, OCProvisionResult_t *arr, bool hasError) +{ + printf("-----------------------------------------------------------\n"); + if(!hasError) + { + printf("%s was successfully done.\n", procName); + } + else + { + for(int i = 0; i < nOfRes; i++) + { + printf("UUID : "); + for(int j = 0; j < UUID_LENGTH; i++) + { + printf("%c", arr[i].deviceId.id[j]); + } + printf("\t"); + printf("Result=%d\n", arr[i].res); + } + } + + if(ctx) + { + printf("Context is %s\n", (char*)ctx); + } + printf("-----------------------------------------------------------\n"); +} + +void ProvisionCredCB(void* ctx, int nOfRes, OCProvisionResult_t *arr, bool hasError) +{ + if(!hasError) + { + gOwnershipState = 1; + PrintfResult("Provision Credential", ctx, nOfRes, arr, hasError); + } +} + +void ProvisionAclCB(void* ctx, int nOfRes, OCProvisionResult_t *arr, bool hasError) +{ + if(!hasError) + { + gOwnershipState = 1; + PrintfResult("Provision ACL", ctx, nOfRes, arr, hasError); + } } -FILE* client_fopen(const char *path, const char *mode) +void ProvisionPairwiseCB(void* ctx, int nOfRes, OCProvisionResult_t *arr, bool hasError) { - (void)path; - return fopen(PROV_TOOL_DB_FILE, mode); + if(!hasError) + { + gOwnershipState = 1; + PrintfResult("Provision Pairwise Credential", ctx, nOfRes, arr, hasError); + } +} + +void OwnershipTransferCB(void* ctx, int nOfRes, OCProvisionResult_t *arr, bool hasError) +{ + if(!hasError) + { + gOwnershipState = 1; + PrintfResult("Ownership transfer", ctx, nOfRes, arr, hasError); + } +} + +void InputPinCB(char* pinBuf, size_t bufSize) +{ + if(pinBuf) + { + printf("INPUT PIN : "); + char *ptr = NULL; + int ret = scanf("%ms", &ptr); + if(1 == ret) + { + OICStrcpy(pinBuf, bufSize, ptr); + OICFree(ptr); + } + else + { + printf("Error in input\n"); + return; + } + } } /** - * Provisioning client sample using ProvisioningAPI on provisioningmanager.c - * To change network type use command line option -w for Wifi and -e for Ethernet + * Provisioning client sample using ProvisioningAPI */ -int main(int argc, char **argv) +int main() { - SPResult res = SP_RESULT_SUCCESS; - SPTargetDeviceInfo_t *pDeviceList = NULL; - gAcl = (OicSecAcl_t *)OICMalloc(sizeof(OicSecAcl_t)); + OCStackResult res = OC_STACK_OK; + int unused; + (void)unused; // Initialize Persistent Storage for SVR database - OCPersistentStorage ps = {}; + OCPersistentStorage ps = { .open = NULL, + .read = NULL, + .write = NULL, + .close = NULL, + .unlink = NULL }; ps.open = client_fopen; ps.read = fread; ps.write = fwrite; @@ -255,72 +399,175 @@ int main(int argc, char **argv) ps.unlink = unlink; OCRegisterPersistentStorageHandler(&ps); - if (OCInit(NULL, 0, OC_CLIENT_SERVER) != OC_STACK_OK) + if (OC_STACK_OK != OCInit(NULL, 0, OC_CLIENT_SERVER)) { OC_LOG(ERROR, TAG, "OCStack init error"); - return 0; + goto error; } - if (NULL == gAcl) + OCProvisionDev_t* pDeviceList = NULL; + res = OCDiscoverUnownedDevices(PREDEFINED_TIMEOUT, &pDeviceList); + if(OC_STACK_OK != res) { - OC_LOG(ERROR, TAG, "Error while memory allocation"); - return SP_RESULT_MEM_ALLOCATION_FAIL; + OC_LOG_V(ERROR, TAG, "Failed to PMDeviceDiscovery : %d", res); + goto error; + } + + OCProvisionDev_t* pCurDev = pDeviceList; + int i; + while(pCurDev !=NULL) + { + for(i = 0; i < UUID_LENGTH; i++) + printf("%c", pCurDev->doxm->deviceID.id[i]); + printf("\n"); + pCurDev = pCurDev->next; + } + + //Register callback function to each OxM + OTMCallbackData_t justWorksCBData = {.loadSecretCB=NULL, + .createSecureSessionCB=NULL, + .createSelectOxmPayloadCB=NULL, + .createOwnerTransferPayloadCB=NULL}; + justWorksCBData.loadSecretCB = LoadSecretJustWorksCallback; + justWorksCBData.createSecureSessionCB = CreateSecureSessionJustWorksCallback; + justWorksCBData.createSelectOxmPayloadCB = CreateJustWorksSelectOxmPayload; + justWorksCBData.createOwnerTransferPayloadCB = CreateJustWorksOwnerTransferPayload; + OTMSetOwnershipTransferCallbackData(OIC_JUST_WORKS, &justWorksCBData); + + OTMCallbackData_t pinBasedCBData = {.loadSecretCB=NULL, + .createSecureSessionCB=NULL, + .createSelectOxmPayloadCB=NULL, + .createOwnerTransferPayloadCB=NULL}; + pinBasedCBData.loadSecretCB = InputPinCodeCallback; + pinBasedCBData.createSecureSessionCB = CreateSecureSessionRandomPinCallbak; + pinBasedCBData.createSelectOxmPayloadCB = CreatePinBasedSelectOxmPayload; + pinBasedCBData.createOwnerTransferPayloadCB = CreatePinBasedOwnerTransferPayload; + OTMSetOwnershipTransferCallbackData(OIC_RANDOM_DEVICE_PIN, &pinBasedCBData); + + SetInputPinCB(&InputPinCB); + + char* myContext = "OTM Context"; + //Perform ownership transfer + res = OCDoOwnershipTransfer((void*)myContext, pDeviceList, OwnershipTransferCB); + if(OC_STACK_OK == res) + { + OC_LOG(INFO, TAG, "Request for ownership transfer is sent successfully."); + } + else + { + OC_LOG_V(ERROR, TAG, "Failed to OCDoOwnershipTransfer : %d", res); + } + + gOwnershipState = 0; + while ( gOwnershipState == 0 ) + { + if (OCProcess() != OC_STACK_OK) + { + OC_LOG(ERROR, TAG, "OCStack process error"); + goto error; + } + sleep(1); } - res = SPProvisioningDiscovery(PREDEFINED_TIMEOUT, &pDeviceList); - if (SP_RESULT_SUCCESS == res) +// Credential & ACL provisioning between two devices. + + OCProvisionDev_t *pOwnedList = NULL; + OCProvisionDev_t *pOwnedDevices [MAX_OWNED_DEVICE] = {0,}; + int nOwnedDevice = 0; + + res = OCDiscoverOwnedDevices(PREDEFINED_TIMEOUT, &pOwnedList); + if (OC_STACK_OK == res) { - while (pDeviceList != NULL) + printf("################## Owned Device List #######################\n"); + while (pOwnedList != NULL) { - printf("-Provisioning device ID : "); - for (int i = 0; i < MAX_INPUT_ID_LENGTH; i++) + nOwnedDevice ++; + printf(" %d : ", nOwnedDevice); + for (int i = 0; i < UUID_LENGTH; i++) { - if (pDeviceList->doxm->deviceID.id[i] == '\0') - { - break; - } - printf("%c", pDeviceList->doxm->deviceID.id[i]); + printf("%c", pOwnedList->doxm->deviceID.id[i]); } printf("\n"); - res = SPInitProvisionContext(PREDEFINED_TIMEOUT, pDeviceList); - if (SP_RESULT_SUCCESS != res) - { - OC_LOG(ERROR, TAG, "Error while init provisioning Context"); - goto error; - } - res = InputACL(gAcl); - if (SP_RESULT_SUCCESS != res) - { - OC_LOG(ERROR, TAG, "Error while user ACL input "); - goto error; - } - res = SPProvisionACL(PREDEFINED_TIMEOUT, pDeviceList, gAcl); - if (SP_RESULT_SUCCESS != res) - { - OC_LOG(ERROR, TAG, "Error while provisioning ACL"); - goto error; - } - res = SPFinalizeProvisioning(PREDEFINED_TIMEOUT, pDeviceList); - if (SP_RESULT_SUCCESS == res) - { - printf("Provisioning Success~!!\n"); - } - else if (SP_RESULT_SUCCESS != res) - { - OC_LOG(ERROR, TAG, "Error while Finalize Provisioning"); - goto error; - } - pDeviceList = pDeviceList->next; + pOwnedDevices[nOwnedDevice] = pOwnedList; + pOwnedList = pOwnedList->next; } } else { - OC_LOG(ERROR, TAG, "Error while Provisioning Discovery"); + OC_LOG(ERROR, TAG, "Error while Owned Device Discovery"); + } + + int Device1 = 0; + int Device2 = 0; + + printf("Select 2 devices for Credential & ACL provisioning\n"); + printf("Device 1: "); + unused = scanf("%d", &Device1); + printf("Device 2: "); + unused = scanf("%d", &Device2); + + + gAcl1 = (OicSecAcl_t *)OICCalloc(1,sizeof(OicSecAcl_t)); + if (NULL == gAcl1) + { + OC_LOG(ERROR, TAG, "Error while memory allocation"); + goto error; + } + + gAcl2 = (OicSecAcl_t *)OICCalloc(1,sizeof(OicSecAcl_t)); + if (NULL == gAcl2) + { + OC_LOG(ERROR, TAG, "Error while memory allocation"); + goto error; + } + + printf("Input ACL for Device1\n"); + if ( 0 == InputACL(gAcl1)) + { + printf("Success Input ACL\n"); + } + else + { + OC_LOG(ERROR, TAG, "InputACL error"); + goto error; + } + + printf("Input ACL for Device2\n"); + if (0 == InputACL(gAcl2)) + { + printf("Success Input ACL\n"); + } + else + { + OC_LOG(ERROR, TAG, "InputACL error"); + goto error; + } + char *ctx = "DUMMY"; + OCProvisionPairwiseDevices(ctx,SYMMETRIC_PAIR_WISE_KEY, OWNER_PSK_LENGTH_128, pOwnedDevices[Device1], + gAcl1, pOwnedDevices[Device2], gAcl2, ProvisionPairwiseCB); + + gOwnershipState = 0; + while ( gOwnershipState == 0 ) + { + if (OCProcess() != OC_STACK_OK) + { + OC_LOG(ERROR, TAG, "OCStack process error"); + goto error; + } + sleep(1); + } + + if (OCStop() != OC_STACK_OK) + { + OC_LOG(ERROR, TAG, "OCStack process error"); goto error; } error: - DeleteACLList(gAcl); - SPTerminateProvisioning(); + deleteACL(gAcl1); + deleteACL(gAcl2); + OCDeleteDiscoveredDevices(&pDeviceList); + OCDeleteDiscoveredDevices(&pOwnedList); + return 0; } diff --git a/resource/csdk/security/provisioning/sample/sampleserver_justworks.cpp b/resource/csdk/security/provisioning/sample/sampleserver_justworks.cpp new file mode 100644 index 0000000..1bbaf41 --- /dev/null +++ b/resource/csdk/security/provisioning/sample/sampleserver_justworks.cpp @@ -0,0 +1,466 @@ +/****************************************************************** +* +* Copyright 2015 Samsung Electronics 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. +* +******************************************************************/ +/////////////////////////////////////////////////////////////////////// +//NOTE : This sample server is generated based on ocserverbasicops.cpp +/////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include +#include "ocstack.h" +#include "logger.h" +#include "ocpayload.h" + +#define TAG "SAMPLE_JUSTWORKS" + +int gQuitFlag = 0; + +/* Structure to represent a LED resource */ +typedef struct LEDRESOURCE{ + OCResourceHandle handle; + bool state; + int power; +} LEDResource; + +static LEDResource LED; +// This variable determines instance number of the LED resource. +// Used by POST method to create a new instance of LED resource. +static int gCurrLedInstance = 0; +#define SAMPLE_MAX_NUM_POST_INSTANCE 2 +static LEDResource gLedInstance[SAMPLE_MAX_NUM_POST_INSTANCE]; + +char *gResourceUri= (char *)"/a/led"; + +//Secure Virtual Resource database for Iotivity Server +//It contains Server's Identity and the PSK credentials +//of other devices which the server trusts +static char CRED_FILE[] = "oic_svr_db_server_justworks.json"; + +/* Function that creates a new LED resource by calling the + * OCCreateResource() method. + */ +int createLEDResource (char *uri, LEDResource *ledResource, bool resourceState, int resourcePower); + +/* This method converts the payload to JSON format */ +OCRepPayload* constructResponse (OCEntityHandlerRequest *ehRequest); + +/* Following methods process the PUT, GET, POST + * requests + */ +OCEntityHandlerResult ProcessGetRequest (OCEntityHandlerRequest *ehRequest, + OCRepPayload **payload); +OCEntityHandlerResult ProcessPutRequest (OCEntityHandlerRequest *ehRequest, + OCRepPayload **payload); +OCEntityHandlerResult ProcessPostRequest (OCEntityHandlerRequest *ehRequest, + OCEntityHandlerResponse *response, + OCRepPayload **payload); + +/* Entity Handler callback functions */ +OCEntityHandlerResult +OCEntityHandlerCb (OCEntityHandlerFlag flag, + OCEntityHandlerRequest *entityHandlerRequest, + void* callbackParam); + +const char *getResult(OCStackResult result) { + switch (result) { + case OC_STACK_OK: + return "OC_STACK_OK"; + case OC_STACK_RESOURCE_CREATED: + return "OC_STACK_RESOURCE_CREATED"; + case OC_STACK_RESOURCE_DELETED: + return "OC_STACK_RESOURCE_DELETED"; + case OC_STACK_INVALID_URI: + return "OC_STACK_INVALID_URI"; + case OC_STACK_INVALID_QUERY: + return "OC_STACK_INVALID_QUERY"; + case OC_STACK_INVALID_IP: + return "OC_STACK_INVALID_IP"; + case OC_STACK_INVALID_PORT: + return "OC_STACK_INVALID_PORT"; + case OC_STACK_INVALID_CALLBACK: + return "OC_STACK_INVALID_CALLBACK"; + case OC_STACK_INVALID_METHOD: + return "OC_STACK_INVALID_METHOD"; + case OC_STACK_NO_MEMORY: + return "OC_STACK_NO_MEMORY"; + case OC_STACK_COMM_ERROR: + return "OC_STACK_COMM_ERROR"; + case OC_STACK_INVALID_PARAM: + return "OC_STACK_INVALID_PARAM"; + case OC_STACK_NOTIMPL: + return "OC_STACK_NOTIMPL"; + case OC_STACK_NO_RESOURCE: + return "OC_STACK_NO_RESOURCE"; + case OC_STACK_RESOURCE_ERROR: + return "OC_STACK_RESOURCE_ERROR"; + case OC_STACK_SLOW_RESOURCE: + return "OC_STACK_SLOW_RESOURCE"; + case OC_STACK_NO_OBSERVERS: + return "OC_STACK_NO_OBSERVERS"; + #ifdef WITH_PRESENCE + case OC_STACK_PRESENCE_STOPPED: + return "OC_STACK_PRESENCE_STOPPED"; + #endif + case OC_STACK_ERROR: + return "OC_STACK_ERROR"; + default: + return "UNKNOWN"; + } +} + +OCRepPayload* getPayload(const char* uri, int64_t power, bool state) +{ + OCRepPayload* payload = OCRepPayloadCreate(); + if(!payload) + { + OC_LOG(ERROR, TAG, PCF("Failed to allocate Payload")); + return NULL; + } + + OCRepPayloadSetUri(payload, uri); + OCRepPayloadSetPropBool(payload, "state", state); + OCRepPayloadSetPropInt(payload, "power", power); + + return payload; +} + +//This function takes the request as an input and returns the response +OCRepPayload* constructResponse (OCEntityHandlerRequest *ehRequest) +{ + if(ehRequest->payload && ehRequest->payload->type != PAYLOAD_TYPE_REPRESENTATION) + { + OC_LOG(ERROR, TAG, PCF("Incoming payload not a representation")); + return NULL; + } + + OCRepPayload* input = (OCRepPayload*)(ehRequest->payload); + + LEDResource *currLEDResource = &LED; + + if (ehRequest->resource == gLedInstance[0].handle) + { + currLEDResource = &gLedInstance[0]; + gResourceUri = (char *) "/a/led/0"; + } + else if (ehRequest->resource == gLedInstance[1].handle) + { + currLEDResource = &gLedInstance[1]; + gResourceUri = (char *) "/a/led/1"; + } + + if(OC_REST_PUT == ehRequest->method) + { + // Get pointer to query + int64_t pow; + if(OCRepPayloadGetPropInt(input, "power", &pow)) + { + currLEDResource->power =pow; + } + + bool state; + if(OCRepPayloadGetPropBool(input, "state", &state)) + { + currLEDResource->state = state; + } + } + + return getPayload(gResourceUri, currLEDResource->power, currLEDResource->state); +} + +OCEntityHandlerResult ProcessGetRequest (OCEntityHandlerRequest *ehRequest, + OCRepPayload **payload) +{ + OCEntityHandlerResult ehResult; + + OCRepPayload *getResp = constructResponse(ehRequest); + + if(getResp) + { + *payload = getResp; + ehResult = OC_EH_OK; + } + else + { + ehResult = OC_EH_ERROR; + } + + return ehResult; +} + +OCEntityHandlerResult ProcessPutRequest (OCEntityHandlerRequest *ehRequest, + OCRepPayload **payload) +{ + OCEntityHandlerResult ehResult; + + OCRepPayload *putResp = constructResponse(ehRequest); + + if(putResp) + { + *payload = putResp; + ehResult = OC_EH_OK; + } + else + { + ehResult = OC_EH_ERROR; + } + + return ehResult; +} + +OCEntityHandlerResult ProcessPostRequest (OCEntityHandlerRequest *ehRequest, + OCEntityHandlerResponse *response, OCRepPayload **payload) +{ + OCRepPayload *respPLPost_led = NULL; + OCEntityHandlerResult ehResult = OC_EH_OK; + + /* + * The entity handler determines how to process a POST request. + * Per the REST paradigm, POST can also be used to update representation of existing + * resource or create a new resource. + * In the sample below, if the POST is for /a/led then a new instance of the LED + * resource is created with default representation (if representation is included in + * POST payload it can be used as initial values) as long as the instance is + * lesser than max new instance count. Once max instance count is reached, POST on + * /a/led updated the representation of /a/led (just like PUT) + */ + + if (ehRequest->resource == LED.handle) + { + if (gCurrLedInstance < SAMPLE_MAX_NUM_POST_INSTANCE) + { + // Create new LED instance + char newLedUri[15] = "/a/led/"; + int newLedUriLength = strlen(newLedUri); + snprintf (newLedUri + newLedUriLength, sizeof(newLedUri)-newLedUriLength, "%d", gCurrLedInstance); + + respPLPost_led = OCRepPayloadCreate(); + OCRepPayloadSetUri(respPLPost_led, gResourceUri); + OCRepPayloadSetPropString(respPLPost_led, "createduri", newLedUri); + + if (0 == createLEDResource (newLedUri, &gLedInstance[gCurrLedInstance], false, 0)) + { + OC_LOG (INFO, TAG, "Created new LED instance"); + gLedInstance[gCurrLedInstance].state = 0; + gLedInstance[gCurrLedInstance].power = 0; + gCurrLedInstance++; + strncpy ((char *)response->resourceUri, newLedUri, MAX_URI_LENGTH); + ehResult = OC_EH_RESOURCE_CREATED; + } + } + else + { + respPLPost_led = constructResponse(ehRequest); + } + } + else + { + for (int i = 0; i < SAMPLE_MAX_NUM_POST_INSTANCE; i++) + { + if (ehRequest->resource == gLedInstance[i].handle) + { + if (i == 0) + { + respPLPost_led = constructResponse(ehRequest); + break; + } + else if (i == 1) + { + respPLPost_led = constructResponse(ehRequest); + } + } + } + } + + if (respPLPost_led != NULL) + { + *payload = respPLPost_led; + ehResult = OC_EH_OK; + } + else + { + OC_LOG_V (INFO, TAG, "Payload was NULL"); + ehResult = OC_EH_ERROR; + } + + return ehResult; +} + +OCEntityHandlerResult +OCEntityHandlerCb (OCEntityHandlerFlag flag, + OCEntityHandlerRequest *entityHandlerRequest, + void* callbackParam) +{ + OC_LOG_V (INFO, TAG, "Inside entity handler - flags: 0x%x", flag); + (void)callbackParam; + OCEntityHandlerResult ehResult = OC_EH_ERROR; + + OCEntityHandlerResponse response; + memset(&response, 0, sizeof(response)); + + // Validate pointer + if (!entityHandlerRequest) + { + OC_LOG (ERROR, TAG, "Invalid request pointer"); + return OC_EH_ERROR; + } + + OCRepPayload* payload = NULL; + + if (flag & OC_REQUEST_FLAG) + { + OC_LOG (INFO, TAG, "Flag includes OC_REQUEST_FLAG"); + if (entityHandlerRequest) + { + if (OC_REST_GET == entityHandlerRequest->method) + { + OC_LOG (INFO, TAG, "Received OC_REST_GET from client"); + ehResult = ProcessGetRequest (entityHandlerRequest, &payload); + } + else if (OC_REST_PUT == entityHandlerRequest->method) + { + OC_LOG (INFO, TAG, "Received OC_REST_PUT from client"); + ehResult = ProcessPutRequest (entityHandlerRequest, &payload); + } + else if (OC_REST_POST == entityHandlerRequest->method) + { + OC_LOG (INFO, TAG, "Received OC_REST_POST from client"); + ehResult = ProcessPostRequest (entityHandlerRequest, &response, &payload); + } + else + { + OC_LOG_V (INFO, TAG, "Received unsupported method %d from client", + entityHandlerRequest->method); + ehResult = OC_EH_ERROR; + } + + if (ehResult == OC_EH_OK && ehResult != OC_EH_FORBIDDEN) + { + // Format the response. Note this requires some info about the request + response.requestHandle = entityHandlerRequest->requestHandle; + response.resourceHandle = entityHandlerRequest->resource; + response.ehResult = ehResult; + response.payload = (OCPayload*)(payload); + response.numSendVendorSpecificHeaderOptions = 0; + memset(response.sendVendorSpecificHeaderOptions, 0, + sizeof(response.sendVendorSpecificHeaderOptions)); + memset(response.resourceUri, 0, sizeof(response.resourceUri)); + // Indicate that response is NOT in a persistent buffer + response.persistentBufferFlag = 0; + + // Send the response + if (OCDoResponse(&response) != OC_STACK_OK) + { + OC_LOG(ERROR, TAG, "Error sending response"); + ehResult = OC_EH_ERROR; + } + } + } + } + + OCPayloadDestroy(response.payload); + return ehResult; +} + +/* SIGINT handler: set gQuitFlag to 1 for graceful termination */ +void handleSigInt(int signum) +{ + if (signum == SIGINT) + { + gQuitFlag = 1; + } +} + +FILE* server_fopen(const char *path, const char *mode) +{ + (void)path; + return fopen(CRED_FILE, mode); +} + +int main() +{ + struct timespec timeout; + + OC_LOG(DEBUG, TAG, "OCServer is starting..."); + + // Initialize Persistent Storage for SVR database + OCPersistentStorage ps = {server_fopen, fread, fwrite, fclose, unlink}; + + OCRegisterPersistentStorageHandler(&ps); + + if (OCInit(NULL, 0, OC_SERVER) != OC_STACK_OK) + { + OC_LOG(ERROR, TAG, "OCStack init error"); + return 0; + } + + /* + * Declare and create the example resource: LED + */ + createLEDResource(gResourceUri, &LED, false, 0); + + timeout.tv_sec = 0; + timeout.tv_nsec = 100000000L; + + // Break from loop with Ctrl-C + OC_LOG(INFO, TAG, "Entering ocserver main loop..."); + signal(SIGINT, handleSigInt); + while (!gQuitFlag) + { + if (OCProcess() != OC_STACK_OK) + { + OC_LOG(ERROR, TAG, "OCStack process error"); + return 0; + } + nanosleep(&timeout, NULL); + } + + OC_LOG(INFO, TAG, "Exiting ocserver main loop..."); + + if (OCStop() != OC_STACK_OK) + { + OC_LOG(ERROR, TAG, "OCStack process error"); + } + + return 0; +} + +int createLEDResource (char *uri, LEDResource *ledResource, bool resourceState, int resourcePower) +{ + if (!uri) + { + OC_LOG(ERROR, TAG, "Resource URI cannot be NULL"); + return -1; + } + + ledResource->state = resourceState; + ledResource->power= resourcePower; + OCStackResult res = OCCreateResource(&(ledResource->handle), + "core.led", + OC_RSRVD_INTERFACE_DEFAULT, + uri, + OCEntityHandlerCb, + NULL, + OC_DISCOVERABLE|OC_OBSERVABLE | OC_SECURE); + OC_LOG_V(INFO, TAG, "Created LED resource with result: %s", getResult(res)); + + return 0; +} diff --git a/resource/csdk/security/provisioning/sample/sampleserver_randompin.cpp b/resource/csdk/security/provisioning/sample/sampleserver_randompin.cpp new file mode 100644 index 0000000..bd9560f --- /dev/null +++ b/resource/csdk/security/provisioning/sample/sampleserver_randompin.cpp @@ -0,0 +1,485 @@ +/****************************************************************** +* +* Copyright 2015 Samsung Electronics 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. +* +******************************************************************/ +/////////////////////////////////////////////////////////////////////// +//NOTE : This sample server is generated based on ocserverbasicops.cpp +/////////////////////////////////////////////////////////////////////// +#include +#include +#include +#include +#include +#include +#include "ocstack.h" +#include "logger.h" +#include "ocpayload.h" +#include "pinoxmcommon.h" + +#define TAG "SAMPLE_RANDOMPIN" + +int gQuitFlag = 0; + +/* Structure to represent a LED resource */ +typedef struct LEDRESOURCE{ + OCResourceHandle handle; + bool state; + int power; +} LEDResource; + +static LEDResource LED; +// This variable determines instance number of the LED resource. +// Used by POST method to create a new instance of LED resource. +static int gCurrLedInstance = 0; +#define SAMPLE_MAX_NUM_POST_INSTANCE 2 +static LEDResource gLedInstance[SAMPLE_MAX_NUM_POST_INSTANCE]; + +char *gResourceUri= (char *)"/a/led"; + +//Secure Virtual Resource database for Iotivity Server +//It contains Server's Identity and the PSK credentials +//of other devices which the server trusts +static char CRED_FILE[] = "oic_svr_db_server_randompin.json"; + +/* Function that creates a new LED resource by calling the + * OCCreateResource() method. + */ +int createLEDResource (char *uri, LEDResource *ledResource, bool resourceState, int resourcePower); + +/* This method converts the payload to JSON format */ +OCRepPayload* constructResponse (OCEntityHandlerRequest *ehRequest); + +/* Following methods process the PUT, GET, POST + * requests + */ +OCEntityHandlerResult ProcessGetRequest (OCEntityHandlerRequest *ehRequest, + OCRepPayload **payload); +OCEntityHandlerResult ProcessPutRequest (OCEntityHandlerRequest *ehRequest, + OCRepPayload **payload); +OCEntityHandlerResult ProcessPostRequest (OCEntityHandlerRequest *ehRequest, + OCEntityHandlerResponse *response, + OCRepPayload **payload); + +/* Entity Handler callback functions */ +OCEntityHandlerResult +OCEntityHandlerCb (OCEntityHandlerFlag flag, + OCEntityHandlerRequest *entityHandlerRequest, + void* callbackParam); + +const char *getResult(OCStackResult result) { + switch (result) { + case OC_STACK_OK: + return "OC_STACK_OK"; + case OC_STACK_RESOURCE_CREATED: + return "OC_STACK_RESOURCE_CREATED"; + case OC_STACK_RESOURCE_DELETED: + return "OC_STACK_RESOURCE_DELETED"; + case OC_STACK_INVALID_URI: + return "OC_STACK_INVALID_URI"; + case OC_STACK_INVALID_QUERY: + return "OC_STACK_INVALID_QUERY"; + case OC_STACK_INVALID_IP: + return "OC_STACK_INVALID_IP"; + case OC_STACK_INVALID_PORT: + return "OC_STACK_INVALID_PORT"; + case OC_STACK_INVALID_CALLBACK: + return "OC_STACK_INVALID_CALLBACK"; + case OC_STACK_INVALID_METHOD: + return "OC_STACK_INVALID_METHOD"; + case OC_STACK_NO_MEMORY: + return "OC_STACK_NO_MEMORY"; + case OC_STACK_COMM_ERROR: + return "OC_STACK_COMM_ERROR"; + case OC_STACK_INVALID_PARAM: + return "OC_STACK_INVALID_PARAM"; + case OC_STACK_NOTIMPL: + return "OC_STACK_NOTIMPL"; + case OC_STACK_NO_RESOURCE: + return "OC_STACK_NO_RESOURCE"; + case OC_STACK_RESOURCE_ERROR: + return "OC_STACK_RESOURCE_ERROR"; + case OC_STACK_SLOW_RESOURCE: + return "OC_STACK_SLOW_RESOURCE"; + case OC_STACK_NO_OBSERVERS: + return "OC_STACK_NO_OBSERVERS"; + #ifdef WITH_PRESENCE + case OC_STACK_PRESENCE_STOPPED: + return "OC_STACK_PRESENCE_STOPPED"; + #endif + case OC_STACK_ERROR: + return "OC_STACK_ERROR"; + default: + return "UNKNOWN"; + } +} + +OCRepPayload* getPayload(const char* uri, int64_t power, bool state) +{ + OCRepPayload* payload = OCRepPayloadCreate(); + if(!payload) + { + OC_LOG(ERROR, TAG, PCF("Failed to allocate Payload")); + return NULL; + } + + OCRepPayloadSetUri(payload, uri); + OCRepPayloadSetPropBool(payload, "state", state); + OCRepPayloadSetPropInt(payload, "power", power); + + return payload; +} + +//This function takes the request as an input and returns the response +OCRepPayload* constructResponse (OCEntityHandlerRequest *ehRequest) +{ + if(ehRequest->payload && ehRequest->payload->type != PAYLOAD_TYPE_REPRESENTATION) + { + OC_LOG(ERROR, TAG, PCF("Incoming payload not a representation")); + return NULL; + } + + OCRepPayload* input = (OCRepPayload*)(ehRequest->payload); + + LEDResource *currLEDResource = &LED; + + if (ehRequest->resource == gLedInstance[0].handle) + { + currLEDResource = &gLedInstance[0]; + gResourceUri = (char *) "/a/led/0"; + } + else if (ehRequest->resource == gLedInstance[1].handle) + { + currLEDResource = &gLedInstance[1]; + gResourceUri = (char *) "/a/led/1"; + } + + if(OC_REST_PUT == ehRequest->method) + { + // Get pointer to query + int64_t pow; + if(OCRepPayloadGetPropInt(input, "power", &pow)) + { + currLEDResource->power =pow; + } + + bool state; + if(OCRepPayloadGetPropBool(input, "state", &state)) + { + currLEDResource->state = state; + } + } + + return getPayload(gResourceUri, currLEDResource->power, currLEDResource->state); +} + +OCEntityHandlerResult ProcessGetRequest (OCEntityHandlerRequest *ehRequest, + OCRepPayload **payload) +{ + OCEntityHandlerResult ehResult; + + OCRepPayload *getResp = constructResponse(ehRequest); + + if(getResp) + { + *payload = getResp; + ehResult = OC_EH_OK; + } + else + { + ehResult = OC_EH_ERROR; + } + + return ehResult; +} + +OCEntityHandlerResult ProcessPutRequest (OCEntityHandlerRequest *ehRequest, + OCRepPayload **payload) +{ + OCEntityHandlerResult ehResult; + + OCRepPayload *putResp = constructResponse(ehRequest); + + if(putResp) + { + *payload = putResp; + ehResult = OC_EH_OK; + } + else + { + ehResult = OC_EH_ERROR; + } + + return ehResult; +} + +OCEntityHandlerResult ProcessPostRequest (OCEntityHandlerRequest *ehRequest, + OCEntityHandlerResponse *response, OCRepPayload **payload) +{ + OCRepPayload *respPLPost_led = NULL; + OCEntityHandlerResult ehResult = OC_EH_OK; + + /* + * The entity handler determines how to process a POST request. + * Per the REST paradigm, POST can also be used to update representation of existing + * resource or create a new resource. + * In the sample below, if the POST is for /a/led then a new instance of the LED + * resource is created with default representation (if representation is included in + * POST payload it can be used as initial values) as long as the instance is + * lesser than max new instance count. Once max instance count is reached, POST on + * /a/led updated the representation of /a/led (just like PUT) + */ + + if (ehRequest->resource == LED.handle) + { + if (gCurrLedInstance < SAMPLE_MAX_NUM_POST_INSTANCE) + { + // Create new LED instance + char newLedUri[15] = "/a/led/"; + int newLedUriLength = strlen(newLedUri); + snprintf (newLedUri + newLedUriLength, sizeof(newLedUri)-newLedUriLength, "%d", gCurrLedInstance); + + respPLPost_led = OCRepPayloadCreate(); + OCRepPayloadSetUri(respPLPost_led, gResourceUri); + OCRepPayloadSetPropString(respPLPost_led, "createduri", newLedUri); + + if (0 == createLEDResource (newLedUri, &gLedInstance[gCurrLedInstance], false, 0)) + { + OC_LOG (INFO, TAG, "Created new LED instance"); + gLedInstance[gCurrLedInstance].state = 0; + gLedInstance[gCurrLedInstance].power = 0; + gCurrLedInstance++; + strncpy ((char *)response->resourceUri, newLedUri, MAX_URI_LENGTH); + ehResult = OC_EH_RESOURCE_CREATED; + } + } + else + { + respPLPost_led = constructResponse(ehRequest); + } + } + else + { + for (int i = 0; i < SAMPLE_MAX_NUM_POST_INSTANCE; i++) + { + if (ehRequest->resource == gLedInstance[i].handle) + { + if (i == 0) + { + respPLPost_led = constructResponse(ehRequest); + break; + } + else if (i == 1) + { + respPLPost_led = constructResponse(ehRequest); + } + } + } + } + + if (respPLPost_led != NULL) + { + *payload = respPLPost_led; + ehResult = OC_EH_OK; + } + else + { + OC_LOG_V (INFO, TAG, "Payload was NULL"); + ehResult = OC_EH_ERROR; + } + + return ehResult; +} + +OCEntityHandlerResult +OCEntityHandlerCb (OCEntityHandlerFlag flag, + OCEntityHandlerRequest *entityHandlerRequest, + void* callbackParam) +{ + OC_LOG_V (INFO, TAG, "Inside entity handler - flags: 0x%x", flag); + (void)callbackParam; + OCEntityHandlerResult ehResult = OC_EH_ERROR; + + OCEntityHandlerResponse response; + memset(&response, 0, sizeof(response)); + + // Validate pointer + if (!entityHandlerRequest) + { + OC_LOG (ERROR, TAG, "Invalid request pointer"); + return OC_EH_ERROR; + } + + OCRepPayload* payload = NULL; + + if (flag & OC_REQUEST_FLAG) + { + OC_LOG (INFO, TAG, "Flag includes OC_REQUEST_FLAG"); + if (entityHandlerRequest) + { + if (OC_REST_GET == entityHandlerRequest->method) + { + OC_LOG (INFO, TAG, "Received OC_REST_GET from client"); + ehResult = ProcessGetRequest (entityHandlerRequest, &payload); + } + else if (OC_REST_PUT == entityHandlerRequest->method) + { + OC_LOG (INFO, TAG, "Received OC_REST_PUT from client"); + ehResult = ProcessPutRequest (entityHandlerRequest, &payload); + } + else if (OC_REST_POST == entityHandlerRequest->method) + { + OC_LOG (INFO, TAG, "Received OC_REST_POST from client"); + ehResult = ProcessPostRequest (entityHandlerRequest, &response, &payload); + } + else + { + OC_LOG_V (INFO, TAG, "Received unsupported method %d from client", + entityHandlerRequest->method); + ehResult = OC_EH_ERROR; + } + + if (ehResult == OC_EH_OK && ehResult != OC_EH_FORBIDDEN) + { + // Format the response. Note this requires some info about the request + response.requestHandle = entityHandlerRequest->requestHandle; + response.resourceHandle = entityHandlerRequest->resource; + response.ehResult = ehResult; + response.payload = (OCPayload*)(payload); + response.numSendVendorSpecificHeaderOptions = 0; + memset(response.sendVendorSpecificHeaderOptions, 0, + sizeof(response.sendVendorSpecificHeaderOptions)); + memset(response.resourceUri, 0, sizeof(response.resourceUri)); + // Indicate that response is NOT in a persistent buffer + response.persistentBufferFlag = 0; + + // Send the response + if (OCDoResponse(&response) != OC_STACK_OK) + { + OC_LOG(ERROR, TAG, "Error sending response"); + ehResult = OC_EH_ERROR; + } + } + } + } + + OCPayloadDestroy(response.payload); + return ehResult; +} + +/* SIGINT handler: set gQuitFlag to 1 for graceful termination */ +void handleSigInt(int signum) +{ + if (signum == SIGINT) + { + gQuitFlag = 1; + } +} + +FILE* server_fopen(const char *path, const char *mode) +{ + (void)path; + return fopen(CRED_FILE, mode); +} + +void GeneratePinCB(char* pin, size_t pinSize) +{ + if(NULL == pin || pinSize <= 0) + { + OC_LOG(INFO, TAG, "Invalid PIN"); + return; + } + + OC_LOG(INFO, TAG, "============================"); + OC_LOG_V(INFO, TAG, " PIN CODE : %s", pin); + OC_LOG(INFO, TAG, "============================"); +} + +int main() +{ + struct timespec timeout; + + OC_LOG(DEBUG, TAG, "OCServer is starting..."); + + // Initialize Persistent Storage for SVR database + OCPersistentStorage ps = {server_fopen, fread, fwrite, fclose, unlink}; + OCRegisterPersistentStorageHandler(&ps); + + if (OCInit(NULL, 0, OC_SERVER) != OC_STACK_OK) + { + OC_LOG(ERROR, TAG, "OCStack init error"); + return 0; + } + + /** + * If server supported random pin based ownership transfer, + * callback of print PIN should be registered before runing server. + */ + SetGeneratePinCB(&GeneratePinCB); + + /* + * Declare and create the example resource: LED + */ + createLEDResource(gResourceUri, &LED, false, 0); + + timeout.tv_sec = 0; + timeout.tv_nsec = 100000000L; + + // Break from loop with Ctrl-C + OC_LOG(INFO, TAG, "Entering ocserver main loop..."); + signal(SIGINT, handleSigInt); + while (!gQuitFlag) + { + if (OCProcess() != OC_STACK_OK) + { + OC_LOG(ERROR, TAG, "OCStack process error"); + return 0; + } + nanosleep(&timeout, NULL); + } + + OC_LOG(INFO, TAG, "Exiting ocserver main loop..."); + + if (OCStop() != OC_STACK_OK) + { + OC_LOG(ERROR, TAG, "OCStack process error"); + } + + return 0; +} + +int createLEDResource (char *uri, LEDResource *ledResource, bool resourceState, int resourcePower) +{ + if (!uri) + { + OC_LOG(ERROR, TAG, "Resource URI cannot be NULL"); + return -1; + } + + ledResource->state = resourceState; + ledResource->power= resourcePower; + OCStackResult res = OCCreateResource(&(ledResource->handle), + "core.led", + OC_RSRVD_INTERFACE_DEFAULT, + uri, + OCEntityHandlerCb, + NULL, + OC_DISCOVERABLE|OC_OBSERVABLE | OC_SECURE); + OC_LOG_V(INFO, TAG, "Created LED resource with result: %s", getResult(res)); + + return 0; +} diff --git a/resource/csdk/security/provisioning/src/credentialgenerator.c b/resource/csdk/security/provisioning/src/credentialgenerator.c index 8e96518..0343627 100644 --- a/resource/csdk/security/provisioning/src/credentialgenerator.c +++ b/resource/csdk/security/provisioning/src/credentialgenerator.c @@ -18,59 +18,97 @@ * * *****************************************************************/ #include - -#include "provisioningmanager.h" #include "credentialgenerator.h" #include "oic_malloc.h" #include "logger.h" #include "credresource.h" #include "ocrandom.h" #include "base64.h" -#define TAG "SPProvisionAPI" -#define KEY_LENGTH 16 +#include "stdbool.h" +#include "securevirtualresourcetypes.h" -SPResult SPGeneratePairWiseCredentials(OicSecCredType_t type, const OicUuid_t *ptDeviceId, - const OicUuid_t *firstDeviceId, - const OicUuid_t *secondDeviceId, - OicSecCred_t **firstCred, - OicSecCred_t **secondCred) -{ +#define TAG "SRPAPI-CG" - if (NULL == ptDeviceId || NULL == firstDeviceId || NULL == secondDeviceId) - { - return SP_RESULT_INVALID_PARAM; - } - uint8_t privData[KEY_LENGTH] = {0,}; - OCFillRandomMem(privData, KEY_LENGTH); +/** + * @def PM_VERIFY_SUCCESS + * @brief Macro to verify success of operation. + * eg: PM_VERIFY_SUCCESS(TAG, OC_STACK_OK == foo(), OC_STACK_ERROR, ERROR); + * @note Invoking function must define "bail:" label for goto functionality to work correctly and + * must define "OCStackResult res" for setting error code. + * */ +#define PM_VERIFY_SUCCESS(tag, op, errCode, logLevel) { if (!(op)) \ + {OC_LOG((logLevel), tag, PCF(#op " failed!!")); res = errCode; goto bail;} } +/** + * @def PM_VERIFY_NON_NULL + * @brief Macro to verify argument is not equal to NULL. + * eg: PM_VERIFY_NON_NULL(TAG, ptrData, ERROR); + * @note Invoking function must define "bail:" label for goto functionality to work correctly. + * */ +#define PM_VERIFY_NON_NULL(tag, arg, errCode, logLevel) { if (NULL == (arg)) \ + { OC_LOG((logLevel), tag, PCF(#arg " is NULL")); res = errCode; goto bail;} } - uint32_t outLen = 0; - char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(privData)) + 1] = {}; - B64Result b64Ret = b64Encode(privData, sizeof(privData), base64Buff, - sizeof(base64Buff), &outLen); - if (B64_OK != b64Ret) - { - OC_LOG(ERROR, TAG, "Error while encoding key"); - return SP_RESULT_INTERNAL_ERROR; - } +OCStackResult PMGeneratePairWiseCredentials(OicSecCredType_t type, size_t keySize, + const OicUuid_t *ptDeviceId, + const OicUuid_t *firstDeviceId, const OicUuid_t *secondDeviceId, + OicSecCred_t **firstCred, OicSecCred_t **secondCred) +{ - // TODO currently owner array is 1. only provisioning tool's id. - OicSecCred_t *tempFirstCred = GenerateCredential(secondDeviceId, type, NULL, base64Buff, 1, - ptDeviceId); - if (NULL == tempFirstCred) + if (NULL == ptDeviceId || NULL == firstDeviceId || NULL != *firstCred || \ + NULL == secondDeviceId || NULL != *secondCred) { - OC_LOG(ERROR, TAG, "Error while generating credential."); - return SP_RESULT_INTERNAL_ERROR; + OC_LOG(INFO, TAG, "Invalid params"); + return OC_STACK_INVALID_PARAM; } - // TODO currently owner array is 1. only provisioning tool's id. - OicSecCred_t *tempSecondCred = GenerateCredential(firstDeviceId, type, NULL, base64Buff, 1, - ptDeviceId); - if (NULL == tempSecondCred) + if(!(keySize == OWNER_PSK_LENGTH_128 || keySize == OWNER_PSK_LENGTH_256)) { - DeleteCredList(tempFirstCred); - OC_LOG(ERROR, TAG, "Error while generating credential."); - return SP_RESULT_INTERNAL_ERROR; + OC_LOG(INFO, TAG, "Invalid key size"); + return OC_STACK_INVALID_PARAM; } + OCStackResult res = OC_STACK_ERROR; + uint8_t* privData = NULL; + char* base64Buff = NULL; + OicSecCred_t *tempFirstCred = NULL; + OicSecCred_t *tempSecondCred = NULL; + + size_t privDataKeySize = keySize; + + privData = (uint8_t*) OICCalloc(privDataKeySize,sizeof(uint8_t)); + PM_VERIFY_NON_NULL(TAG, privData, OC_STACK_NO_MEMORY, ERROR); + + OCFillRandomMem(privData,privDataKeySize); + + uint32_t outLen = 0; + + base64Buff = (char*) OICCalloc(B64ENCODE_OUT_SAFESIZE(privDataKeySize) + 1, sizeof(char)); + PM_VERIFY_NON_NULL(TAG, base64Buff, OC_STACK_NO_MEMORY, ERROR); + int memReq = (B64ENCODE_OUT_SAFESIZE(privDataKeySize) + 1) * sizeof(char); + B64Result b64Ret = b64Encode(privData, privDataKeySize*sizeof(uint8_t), base64Buff, + memReq, &outLen); + PM_VERIFY_SUCCESS(TAG, B64_OK == b64Ret, OC_STACK_ERROR, ERROR); + + // TODO: currently owner array is 1. only provisioning tool's id. + tempFirstCred = GenerateCredential(secondDeviceId, type, NULL, base64Buff, 1, ptDeviceId); + PM_VERIFY_NON_NULL(TAG, tempFirstCred, OC_STACK_ERROR, ERROR); + + // TODO: currently owner array is 1. only provisioning tool's id. + tempSecondCred = GenerateCredential(firstDeviceId, type, NULL, base64Buff, 1, ptDeviceId); + PM_VERIFY_NON_NULL(TAG, tempSecondCred, OC_STACK_ERROR, ERROR); + *firstCred = tempFirstCred; *secondCred = tempSecondCred; - return SP_RESULT_SUCCESS; + res = OC_STACK_OK; + +bail: + OICFree(privData); + OICFree(base64Buff); + + if(res != OC_STACK_OK) + { + OICFree(tempFirstCred); + OICFree(tempSecondCred); + *firstCred = NULL; + *secondCred = NULL; + } + + return res; } diff --git a/resource/csdk/security/provisioning/src/ocprovisioningmanager.c b/resource/csdk/security/provisioning/src/ocprovisioningmanager.c new file mode 100644 index 0000000..cdef12d --- /dev/null +++ b/resource/csdk/security/provisioning/src/ocprovisioningmanager.c @@ -0,0 +1,402 @@ +/* ***************************************************************** + * + * Copyright 2015 Samsung Electronics 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 +#include +#include +#include "ocprovisioningmanager.h" +#include "pmutility.h" +#include "ownershiptransfermanager.h" +#include "oic_malloc.h" +#include "logger.h" +#include "secureresourceprovider.h" + +#define TAG "OCPMAPI" + +typedef struct Linkdata Linkdata_t; +struct Linkdata +{ + void *ctx; + const OCProvisionDev_t *pDev1; + OicSecAcl_t *pDev1Acl; + const OCProvisionDev_t *pDev2; + OicSecAcl_t *pDev2Acl; + OCProvisionResult_t *resArr; + int numOfResults; + int currentCountResults; + OCProvisionResultCB resultCallback; + +}; + +/** + * The function is responsible for discovery of device is current subnet. It will list + * all the device in subnet which are not yet owned. Please call OCInit with OC_CLIENT_SERVER as + * OCMode. + * + * @param[in] timeout Timeout in seconds, value till which function will listen to responses from + * client before returning the list of devices. + * @param[out] ppList List of candidate devices to be provisioned + * @return OTM_SUCCESS in case of success and other value otherwise. + */ +OCStackResult OCDiscoverUnownedDevices(unsigned short timeout, OCProvisionDev_t **ppList) +{ + if( ppList == NULL || *ppList != NULL) + { + return OC_STACK_INVALID_PARAM; + } + + return PMDeviceDiscovery(timeout, false, ppList); +} + +/** + * The function is responsible for discovery of owned device is current subnet. It will list + * all the device in subnet which are owned by calling provisioning client. + * + * @param[in] timeout Timeout in seconds, value till which function will listen to responses from + * client before returning the list of devices. + * @param[out] ppList List of device owned by provisioning tool. + * @return OTM_SUCCESS in case of success and other value otherwise. + */ +OCStackResult OCDiscoverOwnedDevices(unsigned short timeout, OCProvisionDev_t **ppList) +{ + if( ppList == NULL || *ppList != NULL) + { + return OC_STACK_INVALID_PARAM; + } + + return PMDeviceDiscovery(timeout, true, ppList); +} + +/** + * API to register for particular OxM. + * + * @param[in] Ownership transfer method. + * @param[in] Implementation of callback functions for owership transfer. + * @return OC_STACK_OK in case of success and other value otherwise. + */ +OCStackResult OCSetOwnerTransferCallbackData(OicSecOxm_t oxm, OTMCallbackData_t* callbackData) +{ + if(NULL == callbackData) + { + return OC_STACK_INVALID_PARAM; + } + + return OTMSetOwnershipTransferCallbackData(oxm, callbackData); +} + +OCStackResult OCDoOwnershipTransfer(void* ctx, + OCProvisionDev_t *targetDevices, + OCProvisionResultCB resultCallback) +{ + if( NULL == targetDevices ) + { + return OC_STACK_INVALID_PARAM; + } + + return OTMDoOwnershipTransfer(ctx, targetDevices, resultCallback); +} + +/** + * This function deletes memory allocated to linked list created by OCDiscover_XXX_Devices API. + * + * @param[in] pList Pointer to OCProvisionDev_t which should be deleted. + */ +void OCDeleteDiscoveredDevices(OCProvisionDev_t **ppList) +{ + DeleteDeviceList(ppList); +} + +/** + * this function sends ACL information to resource. + * + * @param[in] ctx Application context would be returned in result callback. + * @param[in] selectedDeviceInfo Selected target device. + * @param[in] acl ACL to provision. + * @param[in] resultCallback callback provided by API user, callback will be called when provisioning + request recieves a response from resource server. + * @return OC_STACK_OK in case of success and other value otherwise. + */ +OCStackResult OCProvisionACL(void* ctx, const OCProvisionDev_t *selectedDeviceInfo, OicSecAcl_t *acl, + OCProvisionResultCB resultCallback) +{ + return SRPProvisionACL(ctx, selectedDeviceInfo, acl, resultCallback); +} + +/** + * function to provision credential to devices. + * + * @param[in] ctx Application context would be returned in result callback. + * @param[in] type Type of credentials to be provisioned to the device. + * @param[in] pDev1 Pointer to OCProvisionDev_t instance,respresenting resource to be provsioned. + @param[in] pDev2 Pointer to OCProvisionDev_t instance,respresenting resource to be provsioned. + * @param[in] resultCallback callback provided by API user, callback will be called when + * provisioning request recieves a response from first resource server. + * @return OC_STACK_OK in case of success and other value otherwise. + */ +OCStackResult OCProvisionCredentials(void *ctx, OicSecCredType_t type, size_t keySize, + const OCProvisionDev_t *pDev1, + const OCProvisionDev_t *pDev2, + OCProvisionResultCB resultCallback) +{ + return SRPProvisionCredentials(ctx, type, keySize, + pDev1, pDev2, resultCallback); + +} + +/** + * Internal Function to update result in link result array. + */ +static void UpdateLinkResults(Linkdata_t *link, int device, OCStackResult stackresult) +{ + + OC_LOG_V(INFO,TAG,"value of link->currentCountResults is %d",link->currentCountResults); + if(1 == device) + { + memcpy(link->resArr[(link->currentCountResults)].deviceId.id, link->pDev1->doxm->deviceID.id,UUID_LENGTH); + } + else + { + memcpy(link->resArr[(link->currentCountResults)].deviceId.id, link->pDev2->doxm->deviceID.id,UUID_LENGTH); + } + link->resArr[(link->currentCountResults)].res = stackresult; + ++(link->currentCountResults); + +} + +/** + * Callback to handle ACL provisioning for device 2. + */ +static void AclProv2CB(void* ctx, int nOfRes, OCProvisionResult_t *arr, bool hasError) +{ + + if (NULL == ctx) + { + OC_LOG(ERROR,TAG,"Context is Null in ACLProv 2"); + return; + } + (void)nOfRes; + Linkdata_t *link = (Linkdata_t*)ctx; + OCProvisionResultCB resultCallback = link->resultCallback; + + + if(hasError) + { + UpdateLinkResults(link, 2,arr[0].res); + OC_LOG(ERROR,TAG,"Error occured while ACL provisioning device 1"); + ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults, + link->resArr, + true); + OICFree(link->resArr); + OICFree(link) ; + return; + } + UpdateLinkResults(link, 2, arr[0].res); + ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults, + link->resArr, + false); + OICFree(link->resArr); + OICFree(link); + return; +} + +/** + * Callback to handle ACL provisioning for device 1 + */ +static void AclProv1CB(void* ctx, int nOfRes, OCProvisionResult_t *arr, bool hasError) +{ + + if (NULL == ctx) + { + OC_LOG(ERROR,TAG,"Context is Null in ACLProv1"); + return; + } + (void)nOfRes; + Linkdata_t *link = (Linkdata_t*)ctx; + OCProvisionResultCB resultCallback = link->resultCallback; + + if(hasError) + { + OC_LOG(ERROR,TAG,"Error occured while ACL provisioning device 1"); + UpdateLinkResults(link, 1, arr[0].res); + ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults, + link->resArr, + true); + OICFree(link->resArr); + OICFree(link); + return; + } + UpdateLinkResults(link, 1, arr[0].res); + if (NULL != link->pDev2Acl) + { + OCStackResult res = SRPProvisionACL(ctx, link->pDev2, link->pDev2Acl, &AclProv2CB); + if (OC_STACK_OK!=res) + { + UpdateLinkResults(link, 2, res); + ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults, + link->resArr, + true); + + } + } + else + { + ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults, + link->resArr, + false); + OICFree(link->resArr); + OICFree(link); + } + + return; +} + +/** + * Callback to handle credential provisioning. + */ +static void ProvisionCredsCB(void* ctx, int nOfRes, OCProvisionResult_t *arr, bool hasError) +{ + if (NULL == ctx) + { + OC_LOG(ERROR,TAG,"Error occured while credential provisioning"); + return; + } + Linkdata_t *link = (Linkdata_t*)ctx; + OCProvisionResultCB resultCallback = link->resultCallback; + OC_LOG_V(INFO, TAG, "has error returned %d",hasError); + UpdateLinkResults(link, 1, arr[0].res); + UpdateLinkResults(link, 2, arr[1].res); + if (hasError) + { + OC_LOG(ERROR,TAG,"Error occured while credential provisioning"); + ((OCProvisionResultCB)(resultCallback))(link->ctx, nOfRes, + link->resArr, + true); + OICFree(link->resArr); + OICFree(link); + return; + } + if (NULL != link->pDev1Acl) + { + + OCStackResult res = SRPProvisionACL(ctx, link->pDev1, link->pDev1Acl, &AclProv1CB); + if (OC_STACK_OK!=res) + { + OC_LOG(ERROR, TAG, "Error while provisioning ACL for device 1"); + UpdateLinkResults(link, 1, res); + ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults, + link->resArr, + true); + OICFree(link->resArr); + OICFree(link); + } + } + else if (NULL!=link->pDev2Acl) + { + OC_LOG(ERROR, TAG, "ACL for device 1 is NULL"); + OCStackResult res = SRPProvisionACL(ctx, link->pDev2, link->pDev2Acl, &AclProv2CB); + if (OC_STACK_OK!=res) + { + OC_LOG(ERROR, TAG, "Error while provisioning ACL for device 2"); + UpdateLinkResults(link, 2, res); + ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults, + link->resArr, + true); + OICFree(link->resArr); + OICFree(link); + } + + } + else + { + OC_LOG(INFO, TAG, "ACLs of both devices are NULL"); + ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults, + link->resArr, + false); + OICFree(link->resArr); + OICFree(link); + } + return; +} +/** + * function to provision credentials between two devices and ACLs for the devices who act as a server. + * + * @param[in] ctx Application context would be returned in result callback. + * @param[in] type Type of credentials to be provisioned to the device. + * @param[in] pDev1 Pointer to OCProvisionDev_t instance,respresenting resource to be provsioned. + * @param[in] acl ACL for device 1. If this is not required set NULL. + * @param[in] pDev2 Pointer to OCProvisionDev_t instance,respresenting resource to be provsioned. + * @param[in] acl ACL for device 2. If this is not required set NULL. + * @param[in] resultCallback callback provided by API user, callback will be called when + * provisioning request recieves a response from first resource server. + * @return OC_STACK_OK in case of success and other value otherwise. + */ +OCStackResult OCProvisionPairwiseDevices(void* ctx, OicSecCredType_t type, size_t keySize, + const OCProvisionDev_t *pDev1, OicSecAcl_t *pDev1Acl, + const OCProvisionDev_t *pDev2, OicSecAcl_t *pDev2Acl, + OCProvisionResultCB resultCallback) +{ + + if(!pDev1 || !pDev2 || !resultCallback) + { + OC_LOG(ERROR, TAG, "OCProvisionPairwiseDevices : Invalid parameters"); + return OC_STACK_INVALID_PARAM; + } + if (!(keySize == OWNER_PSK_LENGTH_128 || keySize == OWNER_PSK_LENGTH_256)) + { + OC_LOG(INFO, TAG, "OCProvisionPairwiseDevices : Invalid key size"); + return OC_STACK_INVALID_PARAM; + } + int noOfResults = 2; // Initial Value + if (NULL!=pDev1Acl) + { + ++noOfResults; + } + if(NULL!=pDev2Acl) + { + ++noOfResults; + } + Linkdata_t *link = (Linkdata_t*) OICMalloc(sizeof(Linkdata_t)); + if(!link) + { + OC_LOG(ERROR, TAG, "Failed to memory allocation"); + return OC_STACK_NO_MEMORY; + } + OC_LOG_V(INFO,TAG, "Maximum no od results %d",noOfResults); + + link->pDev1 = pDev1; + link->pDev1Acl = pDev1Acl; + link->pDev2 = pDev2; + link->pDev2Acl = pDev2Acl; + link->ctx = ctx; + // 1 call for each device for credential provisioning. implict call by SRPProvisioning credential + // 1 call for ACL provisioning for device 1 and 1 call for ACL provisioning for device 2. + link->numOfResults = noOfResults; + link->resultCallback = resultCallback; + link->currentCountResults = 0; + link->resArr = (OCProvisionResult_t*) OICMalloc(sizeof(OCProvisionResult_t)*noOfResults); + OCStackResult res = SRPProvisionCredentials(link, type, keySize, + pDev1, pDev2, &ProvisionCredsCB); + if (res != OC_STACK_OK) + { + OICFree(link->resArr); + OICFree(link); + } + return res; + +} diff --git a/resource/csdk/security/provisioning/src/ownershiptransfermanager.c b/resource/csdk/security/provisioning/src/ownershiptransfermanager.c new file mode 100644 index 0000000..e1f69f0 --- /dev/null +++ b/resource/csdk/security/provisioning/src/ownershiptransfermanager.c @@ -0,0 +1,1148 @@ +/* ***************************************************************** + * + * Copyright 2015 Samsung Electronics 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. + * + * *****************************************************************/ + +// Defining _POSIX_C_SOURCE macro with 199309L (or greater) as value +// causes header files to expose definitions +// corresponding to the POSIX.1b, Real-time extensions +// (IEEE Std 1003.1b-1993) specification +// +// For this specific file, see use of clock_gettime, +// Refer to http://pubs.opengroup.org/stage7tc1/functions/clock_gettime.html +// and to http://man7.org/linux/man-pages/man2/clock_gettime.2.html +#ifndef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200809L +#endif + +#include +#include +#include +#include +#include + +#include "logger.h" +#include "oic_malloc.h" +#include "oic_string.h" +#include "cacommon.h" +#include "cainterface.h" +#include "base64.h" +#include "cJSON.h" + +#include "srmresourcestrings.h" +#include "doxmresource.h" +#include "pstatresource.h" +#include "credresource.h" +#include "aclresource.h" +#include "ownershiptransfermanager.h" +#include "securevirtualresourcetypes.h" +#include "oxmjustworks.h" +#include "pmtypes.h" +#include "pmutility.h" +#include "srmutility.h" + +// TODO: Not yet supported. +//#include "oxmrandompin.h" + +#define DEFAULT_CONTEXT_VALUE 0x99 +#define DEFAULT_SECURE_PORT 5684 + +#define TAG "OTM" + +OCProvisionResultCB g_resultCallback; +OCProvisionResult_t* g_resultArray = NULL; +size_t g_resultArraySize = 0; +bool g_hasError = false; + +/** + * Possible states of ownership transfer manager module. + */ +typedef enum +{ + SP_NO_MASK = (0 ), + SP_DISCOVERY_STARTED = (0x1 << 1), + SP_DISCOVERY_ERROR = (0x1 << 2), + SP_DISCOVERY_DONE = (0x1 << 3), + SP_UP_OWN_TR_METH_STARTED = (0x1 << 4), + SP_UP_OWN_TR_METH_ERROR = (0x1 << 5), + SP_UP_OWN_TR_METH_DONE = (0x1 << 6), + SP_LIST_METHODS_STARTED = (0x1 << 7), + SP_LIST_METHODS_ERROR = (0x1 << 8), + SP_LIST_METHODS_DONE = (0x1 << 9), + SP_UPDATE_OP_MODE_STARTED = (0x1 << 10), + SP_UPDATE_OP_MODE_ERROR = (0x1 << 11), + SP_UPDATE_OP_MODE_DONE = (0x1 << 12), + SP_UPDATE_OWNER_STARTED = (0x1 << 13), + SP_UPDATE_OWNER_ERROR = (0x1 << 14), + SP_UPDATE_OWNER_DONE = (0x1 << 15) +} OTMStates; + + + +/** + * Array to store the callbacks for each owner transfer method. + */ +OTMCallbackData_t g_OTMDatas[OIC_OXM_COUNT]; + +/** + * Variable for storing provisioning tool's provisioning capabilities + * Must be in decreasing order of preference. More prefered method should + * have lower array index. + */ +static OicSecDpom_t gProvisioningToolCapability[] = { SINGLE_SERVICE_CLIENT_DRIVEN }; + +/** + * Number of supported provisioning methods + * current version supports only one. + */ +static size_t gNumOfProvisioningMethodsPT = 1; + +/** + * Function to getting string of ownership transfer method + */ +static const char* GetOxmString(OicSecOxm_t oxmType) +{ + switch(oxmType) + { + case OIC_JUST_WORKS: + return OXM_JUST_WORKS; + case OIC_MODE_SWITCH: + return OXM_MODE_SWITCH; + case OIC_RANDOM_DEVICE_PIN: + return OXM_RANDOM_DEVICE_PIN; + case OIC_PRE_PROVISIONED_DEVICE_PIN: + return OXM_PRE_PROVISIONED_DEVICE_PIN; + case OIC_PRE_PROVISION_STRONG_CREDENTIAL: + return OXM_PRE_PROVISIONED_STRONG_CREDENTIAL; + default: + return NULL; + } +} + +/** + * Function to select appropriate provisioning method. + * + * @param[in] supportedMethods Array of supported methods + * @param[in] numberOfMethods number of supported methods + * @param[out] selectedMethod Selected methods + * @return SP_SUCCESS on success + */ +static OCStackResult SelectProvisioningMethod(const OicSecOxm_t *supportedMethods, + size_t numberOfMethods, + OicSecOxm_t *selectedMethod) +{ + OC_LOG(DEBUG, TAG, "IN SelectProvisioningMethod"); + + if(numberOfMethods == 0 || !supportedMethods) + { + OC_LOG(WARNING, TAG, "Could not find a supported OxM."); + return OC_STACK_ERROR; + } + + *selectedMethod = supportedMethods[0]; + for(size_t i = 0; i < numberOfMethods; i++) + { + if(*selectedMethod < supportedMethods[i]) + { + *selectedMethod = supportedMethods[i]; + } + } + + return OC_STACK_OK; +} + +/** + * Function to select operation mode.This function will return most secure common operation mode. + * + * @param[in] selectedDeviceInfo selected device information to performing provisioning. + * @param[out] selectedMode selected operation mode + * @return SP_SUCCESS on success + */ +static void SelectOperationMode(const OCProvisionDev_t *selectedDeviceInfo, + OicSecDpom_t *selectedMode) +{ + OC_LOG(DEBUG, TAG, "IN SelectOperationMode"); + + size_t i = 0; + size_t j = 0; + + while (i < gNumOfProvisioningMethodsPT && j < selectedDeviceInfo->pstat->smLen) + { + if (gProvisioningToolCapability[i] < selectedDeviceInfo->pstat->sm[j]) + { + i++; + } + else if (selectedDeviceInfo->pstat->sm[j] < gProvisioningToolCapability[i]) + { + j++; + } + else /* if gProvisioningToolCapability[i] == deviceSupportedMethods[j] */ + { + *selectedMode = gProvisioningToolCapability[j]; + break; + } + } + OC_LOG(DEBUG, TAG, "OUT SelectOperationMode"); +} + +/** + * Function to update owner transfer mode + * + * @param[in] otmCtx Context value of ownership transfer. + * @return OC_STACK_OK on success + */ +static OCStackResult PutOwnerTransferModeToResource(OTMContext_t* otmCtx); + +/** + * Function to send request to resource to get its pstat resource information. + * + * @param[in] otmCtx Context value of ownership transfer. + * @return OC_STACK_OK on success + */ +static OCStackResult GetProvisioningStatusResource(OTMContext_t* otmCtx); + + +/** + * Function to send ownerShip info. This function would update Owned as true and + * owner as UUID for provisioning tool + * + * @param[in] otmCtx Context value of ownership transfer. + * @return OC_STACK_OK on success + */ +static OCStackResult PutOwnershipInformation(OTMContext_t* otmCtx); + +/** + * Function to update the operation mode. As per the spec. Operation mode in client driven + * single service provisioning it will be updated to 0x3 + * + * @param[in] otmCtx Context value of ownership transfer. + * @param[in] selectedOperationMode selected operation mode + * @return OC_STACK_OK on success + */ +static OCStackResult PutUpdateOperationMode(OTMContext_t* otmCtx, + OicSecDpom_t selectedOperationMode); + +/** + * Function to start ownership transfer. + * This function will send the first request for provisioning, + * The next request message is sent from the response handler for this request. + * + * @param[in] ctx context value passed to callback from calling function. + * @param[in] selectedDevice selected device information to performing provisioning. + * @return OC_STACK_OK on success + */ +static OCStackResult StartOwnershipTransfer(void* ctx, OCProvisionDev_t* selectedDevice); + +/* + * Function to finalize provisioning. + * This function will send default ACL and commit hash. + * + * @param[in] otmCtx Context value of ownership transfer. + * @return OC_STACK_OK on success + */ +static OCStackResult FinalizeProvisioning(OTMContext_t* otmCtx); + + +static bool IsComplete() +{ + for(size_t i = 0; i < g_resultArraySize; i++) + { + if(OC_STACK_CONTINUE == g_resultArray[i].res) + { + return false; + } + } + + return true; +} + +/** + * Function to save the result of provisioning. + * + * @param[in,out] otmCtx Context value of ownership transfer. + * @param[in] res result of provisioning + */ +static void SetResult(OTMContext_t* otmCtx, const OCStackResult res) +{ + OC_LOG(DEBUG, TAG, "IN SetResult"); + + if(!otmCtx) + { + OC_LOG(WARNING, TAG, "OTMContext is NULL"); + return; + } + + if(otmCtx->selectedDeviceInfo) + { + for(size_t i = 0; i < g_resultArraySize; i++) + { + if(memcmp(otmCtx->selectedDeviceInfo->doxm->deviceID.id, + g_resultArray[i].deviceId.id, UUID_LENGTH) == 0) + { + g_resultArray[i].res = res; + if(OC_STACK_OK != res) + { + g_hasError = true; + } + } + } + + //If all request is completed, invoke the user callback. + if(IsComplete()) + { + g_resultCallback(otmCtx->userCtx, g_resultArraySize, g_resultArray, g_hasError); + } + else + { + if(OC_STACK_OK != StartOwnershipTransfer(otmCtx->userCtx, + otmCtx->selectedDeviceInfo->next)) + { + OC_LOG(ERROR, TAG, "Failed to StartOwnershipTransfer"); + } + } + } + + OC_LOG(DEBUG, TAG, "OUT SetResult"); + + OICFree(otmCtx); +} + + +/** + * Function to save ownerPSK at provisioning tool end. + * + * @param[in] selectedDeviceInfo selected device information to performing provisioning. + * @return OC_STACK_OK on success + */ +static OCStackResult SaveOwnerPSK(OCProvisionDev_t *selectedDeviceInfo) +{ + OC_LOG(DEBUG, TAG, "IN SaveOwnerPSK"); + + OCStackResult res = OC_STACK_ERROR; + + CAEndpoint_t endpoint; + memset(&endpoint, 0x00, sizeof(CAEndpoint_t)); + OICStrcpy(endpoint.addr, MAX_ADDR_STR_SIZE_CA, selectedDeviceInfo->endpoint.addr); + endpoint.addr[MAX_ADDR_STR_SIZE_CA - 1] = '\0'; + endpoint.port = selectedDeviceInfo->securePort; + + OicUuid_t ptDeviceID = {.id={0}}; + if (OC_STACK_OK != GetDoxmDeviceID(&ptDeviceID)) + { + OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID"); + return res; + } + + uint8_t ownerPSK[OWNER_PSK_LENGTH_128] = {0}; + + //Generating OwnerPSK + CAResult_t pskRet = CAGenerateOwnerPSK(&endpoint, + (uint8_t *)GetOxmString(selectedDeviceInfo->doxm->oxmSel), + strlen(GetOxmString(selectedDeviceInfo->doxm->oxmSel)), ptDeviceID.id, + sizeof(ptDeviceID.id), selectedDeviceInfo->doxm->deviceID.id, + sizeof(selectedDeviceInfo->doxm->deviceID.id), ownerPSK, + OWNER_PSK_LENGTH_128); + + if (CA_STATUS_OK == pskRet) + { + OC_LOG(INFO, TAG,"ownerPSK dump:\n"); + OC_LOG_BUFFER(INFO, TAG,ownerPSK, OWNER_PSK_LENGTH_128); + //Generating new credential for provisioning tool + size_t ownLen = 1; + uint32_t outLen = 0; + + char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(ownerPSK)) + 1] = {}; + B64Result b64Ret = b64Encode(ownerPSK, sizeof(ownerPSK), base64Buff, sizeof(base64Buff), + &outLen); + VERIFY_SUCCESS(TAG, B64_OK == b64Ret, ERROR); + + OicSecCred_t *cred = GenerateCredential(&selectedDeviceInfo->doxm->deviceID, + SYMMETRIC_PAIR_WISE_KEY, NULL, + base64Buff, ownLen, &ptDeviceID); + VERIFY_NON_NULL(TAG, cred, ERROR); + + res = AddCredential(cred); + if(res != OC_STACK_OK) + { + DeleteCredList(cred); + return res; + } + } + else + { + OC_LOG(ERROR, TAG, "CAGenerateOwnerPSK failed"); + } + + OC_LOG(DEBUG, TAG, "OUT SaveOwnerPSK"); +exit: + return res; +} + +/** + * Callback handler for OwnerShipTransferModeHandler API. + * + * @param[in] ctx ctx value passed to callback from calling function. + * @param[in] UNUSED handle to an invocation + * @param[in] clientResponse Response from queries to remote servers. + * @return OC_STACK_DELETE_TRANSACTION to delete the transaction + * and OC_STACK_KEEP_TRANSACTION to keep it. + */ +static OCStackApplicationResult OwnerTransferModeHandler(void *ctx, OCDoHandle UNUSED, + OCClientResponse *clientResponse) +{ + OC_LOG(DEBUG, TAG, "IN OwnerTransferModeHandler"); + + VERIFY_NON_NULL(TAG, clientResponse, WARNING); + VERIFY_NON_NULL(TAG, ctx, WARNING); + + OTMContext_t* otmCtx = (OTMContext_t*)ctx; + (void)UNUSED; + if(clientResponse->result == OC_STACK_OK) + { + OC_LOG(INFO, TAG, "OwnerTransferModeHandler : response result = OC_STACK_OK"); + //Send request : GET /oic/sec/pstat + OCStackResult res = GetProvisioningStatusResource(otmCtx); + if(OC_STACK_OK != res) + { + OC_LOG(WARNING, TAG, "Failed to get pstat information"); + SetResult(otmCtx, res); + } + } + else + { + OC_LOG_V(WARNING, TAG, "OwnerTransferModeHandler : Client response is incorrect : %d", + clientResponse->result); + SetResult(otmCtx, clientResponse->result); + } + + OC_LOG(DEBUG, TAG, "OUT OwnerTransferModeHandler"); + +exit: + return OC_STACK_DELETE_TRANSACTION; +} + +/** + * Callback handler for ProvisioningStatusResouceHandler API. + * + * @param[in] ctx ctx value passed to callback from calling function. + * @param[in] UNUSED handle to an invocation + * @param[in] clientResponse Response from queries to remote servers. + * @return OC_STACK_DELETE_TRANSACTION to delete the transaction + * and OC_STACK_KEEP_TRANSACTION to keep it. + */ +static OCStackApplicationResult ListMethodsHandler(void *ctx, OCDoHandle UNUSED, + OCClientResponse *clientResponse) +{ + OC_LOG(DEBUG, TAG, "IN ListMethodsHandler"); + + VERIFY_NON_NULL(TAG, clientResponse, WARNING); + VERIFY_NON_NULL(TAG, ctx, WARNING); + + OTMContext_t* otmCtx = (OTMContext_t*)ctx; + (void)UNUSED; + if (OC_STACK_OK == clientResponse->result) + { + if (NULL == clientResponse->payload) + { + OC_LOG(INFO, TAG, "Skiping Null payload"); + SetResult(otmCtx, OC_STACK_ERROR); + return OC_STACK_DELETE_TRANSACTION; + } + + if (PAYLOAD_TYPE_SECURITY != clientResponse->payload->type) + { + OC_LOG(INFO, TAG, "Unknown payload type"); + SetResult(otmCtx, OC_STACK_ERROR); + return OC_STACK_DELETE_TRANSACTION; + } + + OicSecPstat_t* pstat = JSONToPstatBin( + ((OCSecurityPayload*)clientResponse->payload)->securityData); + if(NULL == pstat) + { + OC_LOG(ERROR, TAG, "Error while converting json to pstat bin"); + SetResult(otmCtx, OC_STACK_ERROR); + return OC_STACK_DELETE_TRANSACTION; + } + otmCtx->selectedDeviceInfo->pstat = pstat; + + //Select operation mode (Currently supported SINGLE_SERVICE_CLIENT_DRIVEN only) + OicSecDpom_t selectedOperationMode; + SelectOperationMode(otmCtx->selectedDeviceInfo, &selectedOperationMode); + + //Send request : PUT /oic/sec/pstat [{"OM":"0x11", .. }] + OCStackResult res = PutUpdateOperationMode(otmCtx, selectedOperationMode); + if (OC_STACK_OK != res) + { + OC_LOG(ERROR, TAG, "Error while updating operation mode."); + SetResult(otmCtx, res); + } + } + else + { + OC_LOG_V(WARNING, TAG, "ListMethodsHandler : Client response is incorrect : %d", + clientResponse->result); + SetResult(otmCtx, clientResponse->result); + } + + OC_LOG(DEBUG, TAG, "OUT ListMethodsHandler"); +exit: + return OC_STACK_DELETE_TRANSACTION; +} + +/** + * Callback handler for OwnershipInformationHandler API. + * + * @param[in] ctx ctx value passed to callback from calling function. + * @param[in] UNUSED handle to an invocation + * @param[in] clientResponse Response from queries to remote servers. + * @return OC_STACK_DELETE_TRANSACTION to delete the transaction + * and OC_STACK_KEEP_TRANSACTION to keep it. + */ +static OCStackApplicationResult OwnershipInformationHandler(void *ctx, OCDoHandle UNUSED, + OCClientResponse *clientResponse) +{ + VERIFY_NON_NULL(TAG, clientResponse, WARNING); + VERIFY_NON_NULL(TAG, ctx, WARNING); + + OC_LOG(DEBUG, TAG, "IN OwnershipInformationHandler"); + (void)UNUSED; + OCStackResult res = OC_STACK_OK; + OTMContext_t* otmCtx = (OTMContext_t*)ctx; + if (OC_STACK_OK == clientResponse->result) + { + if(OIC_RANDOM_DEVICE_PIN == otmCtx->selectedDeviceInfo->doxm->oxmSel) + { + res = RemoveCredential(&otmCtx->tempCredId); + if(OC_STACK_RESOURCE_DELETED != res) + { + OC_LOG_V(ERROR, TAG, "Failed to remove temporal PSK : %d", res); + return OC_STACK_DELETE_TRANSACTION; + } + } + + res = SaveOwnerPSK(otmCtx->selectedDeviceInfo); + if(OC_STACK_OK != res) + { + OC_LOG(ERROR, TAG, "OperationModeUpdate : Failed to owner PSK generation"); + SetResult(otmCtx, res); + return OC_STACK_DELETE_TRANSACTION; + } + + CAEndpoint_t* endpoint = (CAEndpoint_t *)&otmCtx->selectedDeviceInfo->endpoint; + endpoint->port = otmCtx->selectedDeviceInfo->securePort; + CAResult_t closeRes = CACloseDtlsSession(endpoint); + if(CA_STATUS_OK != closeRes) + { + OC_LOG(ERROR, TAG, "Failed to close DTLS session"); + SetResult(otmCtx, closeRes); + return OC_STACK_DELETE_TRANSACTION; + } + + OC_LOG(INFO, TAG, "Ownership transfer was successfully completed."); + OC_LOG(INFO, TAG, "Start defualt ACL & commit-hash provisioning."); + + res = FinalizeProvisioning(otmCtx); + if(OC_STACK_OK != res) + { + SetResult(otmCtx, res); + } + } + else + { + res = clientResponse->result; + } + + OC_LOG(DEBUG, TAG, "OUT OwnershipInformationHandler"); + +exit: + return OC_STACK_DELETE_TRANSACTION; +} + +/** + * Response handler for update operation mode. + * + * @param[in] ctx ctx value passed to callback from calling function. + * @param[in] UNUSED handle to an invocation + * @param[in] clientResponse Response from queries to remote servers. + * @return OC_STACK_DELETE_TRANSACTION to delete the transaction + * and OC_STACK_KEEP_TRANSACTION to keep it. + */ +static OCStackApplicationResult OperationModeUpdateHandler(void *ctx, OCDoHandle UNUSED, + OCClientResponse *clientResponse) +{ + OC_LOG(DEBUG, TAG, "IN OperationModeUpdateHandler"); + + VERIFY_NON_NULL(TAG, clientResponse, WARNING); + VERIFY_NON_NULL(TAG, ctx, WARNING); + + OTMContext_t* otmCtx = (OTMContext_t*)ctx; + (void) UNUSED; + if (OC_STACK_OK == clientResponse->result) + { + OCStackResult res = OC_STACK_ERROR; + OicSecOxm_t selOxm = otmCtx->selectedDeviceInfo->doxm->oxmSel; + //DTLS Handshake + //Load secret for temporal secure session. + if(g_OTMDatas[selOxm].loadSecretCB) + { + res = g_OTMDatas[selOxm].loadSecretCB(otmCtx); + if(OC_STACK_OK != res) + { + OC_LOG(ERROR, TAG, "OperationModeUpdate : Failed to load secret"); + SetResult(otmCtx, res); + return OC_STACK_DELETE_TRANSACTION; + } + } + + //Try DTLS handshake to generate secure session + if(g_OTMDatas[selOxm].createSecureSessionCB) + { + res = g_OTMDatas[selOxm].createSecureSessionCB(otmCtx); + if(OC_STACK_OK != res) + { + OC_LOG(ERROR, TAG, "OperationModeUpdate : Failed to create DTLS session"); + SetResult(otmCtx, res); + return OC_STACK_DELETE_TRANSACTION; + } + } + + //Send request : PUT /oic/sec/doxm [{"Owned":"True", .. , "Owner":"PT's UUID"}] + res = PutOwnershipInformation(otmCtx); + if(OC_STACK_OK != res) + { + OC_LOG(ERROR, TAG, "OperationModeUpdate : Failed to send owner information"); + SetResult(otmCtx, res); + } + } + else + { + OC_LOG(ERROR, TAG, "Error while update operation mode"); + SetResult(otmCtx, clientResponse->result); + } + + OC_LOG(DEBUG, TAG, "OUT OperationModeUpdateHandler"); + +exit: + return OC_STACK_DELETE_TRANSACTION; +} + + +static OCStackResult PutOwnerTransferModeToResource(OTMContext_t* otmCtx) +{ + OC_LOG(DEBUG, TAG, "IN PutOwnerTransferModeToResource"); + + if(!otmCtx || !otmCtx->selectedDeviceInfo) + { + OC_LOG(ERROR, TAG, "Invailed parameters"); + return OC_STACK_INVALID_PARAM; + } + + OCProvisionDev_t* deviceInfo = otmCtx->selectedDeviceInfo; + OicSecOxm_t selectedOxm = deviceInfo->doxm->oxmSel; + char query[MAX_QUERY_LENGTH] = {}; + sprintf(query, "%s%s:%d%s", COAP_PREFIX, + deviceInfo->endpoint.addr, deviceInfo->endpoint.port, + OIC_RSRC_DOXM_URI); + OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload)); + if(!secPayload) + { + OC_LOG(ERROR, TAG, "Failed to memory allocation"); + return OC_STACK_NO_MEMORY; + } + secPayload->base.type = PAYLOAD_TYPE_SECURITY; + secPayload->securityData = g_OTMDatas[selectedOxm].createSelectOxmPayloadCB(otmCtx); + if (NULL == secPayload->securityData) + { + OICFree(secPayload); + OC_LOG(ERROR, TAG, "Error while converting bin to json"); + return OC_STACK_ERROR; + } + OC_LOG_V(DEBUG, TAG, "Payload : %s", secPayload->securityData); + + OCCallbackData cbData; + cbData.cb = &OwnerTransferModeHandler; + cbData.context = (void *)otmCtx; + cbData.cd = NULL; + + // TODO: 6th argument need to be changed, if we have to use CT_FLAG_SECURE + OCStackResult res = OCDoResource(NULL, OC_REST_PUT, query, + &deviceInfo->endpoint, (OCPayload*)secPayload, + CT_ADAPTER_IP, OC_LOW_QOS, &cbData, NULL, 0); + if (res != OC_STACK_OK) + { + OC_LOG(ERROR, TAG, "OCStack resource error"); + } + + OC_LOG(DEBUG, TAG, "OUT PutOwnerTransferModeToResource"); + + return res; +} + +static OCStackResult GetProvisioningStatusResource(OTMContext_t* otmCtx) +{ + OC_LOG(DEBUG, TAG, "IN GetProvisioningStatusResource"); + + if(!otmCtx || !otmCtx->selectedDeviceInfo) + { + OC_LOG(ERROR, TAG, "Invailed parameters"); + return OC_STACK_INVALID_PARAM; + } + + OCProvisionDev_t* deviceInfo = otmCtx->selectedDeviceInfo; + char query[MAX_QUERY_LENGTH] = {}; + sprintf(query, "%s%s:%d%s", COAP_PREFIX, + deviceInfo->endpoint.addr, deviceInfo->endpoint.port, + OIC_RSRC_PSTAT_URI); + OCCallbackData cbData; + cbData.cb = &ListMethodsHandler; + cbData.context = (void *)otmCtx; + cbData.cd = NULL; + + // TODO: 6th argument need to be changed, if we have to use CT_FLAG_SECURE + OCStackResult res = OCDoResource(NULL, OC_REST_GET, query, NULL, NULL, + CT_ADAPTER_IP, OC_LOW_QOS, &cbData, NULL, 0); + if (res != OC_STACK_OK) + { + OC_LOG(ERROR, TAG, "OCStack resource error"); + } + + OC_LOG(DEBUG, TAG, "OUT GetProvisioningStatusResource"); + + return res; +} + + +static OCStackResult PutOwnershipInformation(OTMContext_t* otmCtx) +{ + OC_LOG(DEBUG, TAG, "IN PutOwnershipInformation"); + + if(!otmCtx || !otmCtx->selectedDeviceInfo) + { + OC_LOG(ERROR, TAG, "Invailed parameters"); + return OC_STACK_INVALID_PARAM; + } + + OCProvisionDev_t* deviceInfo = otmCtx->selectedDeviceInfo; + char query[MAX_QUERY_LENGTH] = {}; + sprintf(query, "%s%s:%d%s", COAPS_PREFIX, + deviceInfo->endpoint.addr, deviceInfo->securePort, + OIC_RSRC_DOXM_URI); + //OwnershipInformationHandler + OicSecOxm_t selOxm = deviceInfo->doxm->oxmSel; + OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload)); + if(!secPayload) + { + OC_LOG(ERROR, TAG, "Failed to memory allocation"); + return OC_STACK_NO_MEMORY; + } + secPayload->base.type = PAYLOAD_TYPE_SECURITY; + secPayload->securityData = g_OTMDatas[selOxm].createOwnerTransferPayloadCB(otmCtx); + if (NULL == secPayload->securityData) + { + OICFree(secPayload); + OC_LOG(ERROR, TAG, "Error while converting doxm bin to json"); + return OC_STACK_INVALID_PARAM; + } + + OCCallbackData cbData; + cbData.cb = &OwnershipInformationHandler; + cbData.context = (void *)otmCtx; + cbData.cd = NULL; + // TODO: 6th argument need to be changed, if we have to use CT_FLAG_SECURE + OCStackResult res = OCDoResource(NULL, OC_REST_PUT, query, 0, (OCPayload*)secPayload, + CT_ADAPTER_IP, OC_LOW_QOS, &cbData, NULL, 0); + if (res != OC_STACK_OK) + { + OC_LOG(ERROR, TAG, "OCStack resource error"); + } + + OC_LOG(DEBUG, TAG, "OUT PutOwnershipInformation"); + + return res; +} + +static OCStackResult PutUpdateOperationMode(OTMContext_t* otmCtx, + OicSecDpom_t selectedOperationMode) +{ + OC_LOG(DEBUG, TAG, "IN PutUpdateOperationMode"); + + if(!otmCtx || !otmCtx->selectedDeviceInfo) + { + return OC_STACK_INVALID_PARAM; + } + + OCProvisionDev_t* deviceInfo = otmCtx->selectedDeviceInfo; + char query[MAX_QUERY_LENGTH] = {}; + sprintf(query, "%s%s:%d%s", COAP_PREFIX, + deviceInfo->endpoint.addr, deviceInfo->endpoint.port, + OIC_RSRC_PSTAT_URI); + deviceInfo->pstat->om = selectedOperationMode; + + OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload)); + if(!secPayload) + { + OC_LOG(ERROR, TAG, "Failed to memory allocation"); + return OC_STACK_NO_MEMORY; + } + secPayload->base.type = PAYLOAD_TYPE_SECURITY; + secPayload->securityData = BinToPstatJSON(deviceInfo->pstat); + if (NULL == secPayload->securityData) + { + OICFree(secPayload); + OC_LOG(ERROR, TAG, "Error while converting pstat bin to json"); + return OC_STACK_INVALID_PARAM; + } + + OCCallbackData cbData; + cbData.cb = &OperationModeUpdateHandler; + cbData.context = (void *)otmCtx; + cbData.cd = NULL; + + OCStackResult res = OCDoResource(NULL, OC_REST_PUT, query, 0, (OCPayload*)secPayload, + CT_ADAPTER_IP, OC_LOW_QOS, &cbData, NULL, 0); + if (res != OC_STACK_OK) + { + OC_LOG(ERROR, TAG, "OCStack resource error"); + } + + OC_LOG(DEBUG, TAG, "OUT PutUpdateOperationMode"); + + return res; +} + +static OCStackResult StartOwnershipTransfer(void* ctx, OCProvisionDev_t* selectedDevice) +{ + OC_LOG(INFO, TAG, "IN StartOwnershipTransfer"); + OTMContext_t* otmCtx = (OTMContext_t*)OICMalloc(sizeof(OTMContext_t)); + if(!otmCtx) + { + OC_LOG(ERROR, TAG, "Failed to create OTM Context"); + return OC_STACK_NO_MEMORY; + } + otmCtx->userCtx = ctx; + otmCtx->selectedDeviceInfo = selectedDevice; + + //Set to the lowest level OxM, and then find more higher level OxM. + OCStackResult res = SelectProvisioningMethod(selectedDevice->doxm->oxm, + selectedDevice->doxm->oxmLen, + &selectedDevice->doxm->oxmSel); + if(OC_STACK_OK != res) + { + OC_LOG(ERROR, TAG, "Failed to select the provisioning method"); + SetResult(otmCtx, res); + return res; + } + OC_LOG_V(DEBUG, TAG, "Selected provisoning method = %d", selectedDevice->doxm->oxmSel); + + //Send Req: PUT /oic/sec/doxm [{..."OxmSel" :g_OTMDatas[Index of Selected OxM].OXMString,...}] + res = PutOwnerTransferModeToResource(otmCtx); + if(OC_STACK_OK != res) + { + OC_LOG(WARNING, TAG, "Failed to select the provisioning method"); + SetResult(otmCtx, res); + return res; + } + + OC_LOG(INFO, TAG, "OUT StartOwnershipTransfer"); + + return res; + +} + +OCStackResult OTMSetOwnershipTransferCallbackData(OicSecOxm_t oxmType, OTMCallbackData_t* data) +{ + OC_LOG(DEBUG, TAG, "IN OTMSetOwnerTransferCallbackData"); + + if(!data) + { + OC_LOG(ERROR, TAG, "OTMSetOwnershipTransferCallbackData : Invalid parameters"); + return OC_STACK_INVALID_PARAM; + } + if(oxmType >= OIC_OXM_COUNT) + { + OC_LOG(INFO, TAG, "Unknow ownership transfer method"); + return OC_STACK_INVALID_PARAM; + } + + g_OTMDatas[oxmType].loadSecretCB= data->loadSecretCB; + g_OTMDatas[oxmType].createSecureSessionCB = data->createSecureSessionCB; + g_OTMDatas[oxmType].createSelectOxmPayloadCB = data->createSelectOxmPayloadCB; + g_OTMDatas[oxmType].createOwnerTransferPayloadCB = data->createOwnerTransferPayloadCB; + + OC_LOG(DEBUG, TAG, "OUT OTMSetOwnerTransferCallbackData"); + + return OC_STACK_OK; +} + +/** + * NOTE : Unowned discovery should be done before performing OTMDoOwnershipTransfer + */ +OCStackResult OTMDoOwnershipTransfer(void* ctx, + OCProvisionDev_t *selectedDevicelist, + OCProvisionResultCB resultCallback) +{ + OC_LOG(DEBUG, TAG, "IN OTMDoOwnershipTransfer"); + + if (NULL == selectedDevicelist || NULL == resultCallback ) + { + return OC_STACK_INVALID_PARAM; + } + + g_resultCallback = resultCallback; + g_hasError = false; + + OCProvisionDev_t* pCurDev = selectedDevicelist; + + //Counting number of selected devices. + g_resultArraySize = 0; + while(NULL != pCurDev) + { + g_resultArraySize++; + pCurDev = pCurDev->next; + } + + if(g_resultArray) + { + OICFree(g_resultArray); + } + g_resultArray = + (OCProvisionResult_t*)OICMalloc(sizeof(OCProvisionResult_t) * g_resultArraySize); + if(NULL == g_resultArray) + { + OC_LOG(ERROR, TAG, "OTMDoOwnershipTransfer : Failed to memory allocation"); + return OC_STACK_NO_MEMORY; + } + + pCurDev = selectedDevicelist; + //Fill the device UUID for result array. + for(size_t devIdx = 0; devIdx < g_resultArraySize; devIdx++) + { + memcpy(g_resultArray[devIdx].deviceId.id, + pCurDev->doxm->deviceID.id, + UUID_LENGTH); + g_resultArray[devIdx].res = OC_STACK_CONTINUE; + pCurDev = pCurDev->next; + } + + StartOwnershipTransfer(ctx, selectedDevicelist); + + OC_LOG(DEBUG, TAG, "OUT OTMDoOwnershipTransfer"); + + return (g_hasError ? OC_STACK_ERROR : OC_STACK_OK); +} + +/** + * Callback handler of SRPFinalizeProvisioning. + * + * @param[in] ctx ctx value passed to callback from calling function. + * @param[in] UNUSED handle to an invocation + * @param[in] clientResponse Response from queries to remote servers. + * @return OC_STACK_DELETE_TRANSACTION to delete the transaction + * and OC_STACK_KEEP_TRANSACTION to keep it. + */ +static OCStackApplicationResult FinalizeProvisioningCB(void *ctx, OCDoHandle UNUSED, + OCClientResponse *clientResponse) +{ + OC_LOG_V(INFO, TAG, "IN FinalizeProvisioningCB."); + + VERIFY_NON_NULL(TAG, clientResponse, ERROR); + VERIFY_NON_NULL(TAG, ctx, ERROR); + + OTMContext_t* otmCtx = (OTMContext_t*)ctx; + (void)UNUSED; + if(OC_STACK_OK == clientResponse->result) + { + SetResult(otmCtx, OC_STACK_OK); + } +exit: + return OC_STACK_DELETE_TRANSACTION; +} + +/** + * Callback handler of default ACL provisioning. + * + * @param[in] ctx ctx value passed to callback from calling function. + * @param[in] UNUSED handle to an invocation + * @param[in] clientResponse Response from queries to remote servers. + * @return OC_STACK_DELETE_TRANSACTION to delete the transaction + * and OC_STACK_KEEP_TRANSACTION to keep it. + */ +static OCStackApplicationResult ProvisionDefaultACLCB(void *ctx, OCDoHandle UNUSED, + OCClientResponse *clientResponse) +{ + OC_LOG_V(INFO, TAG, "IN ProvisionDefaultACLCB."); + + VERIFY_NON_NULL(TAG, clientResponse, ERROR); + VERIFY_NON_NULL(TAG, ctx, ERROR); + + OTMContext_t* otmCtx = (OTMContext_t*) ctx; + (void)UNUSED; + + if (OC_STACK_RESOURCE_CREATED == clientResponse->result) + { + OC_LOG_V(INFO, TAG, "Staring commit hash task."); + // TODO hash currently have fixed value 0. + uint16_t aclHash = 0; + otmCtx->selectedDeviceInfo->pstat->commitHash = aclHash; + otmCtx->selectedDeviceInfo->pstat->tm = NORMAL; + OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload)); + if(!secPayload) + { + OC_LOG(ERROR, TAG, "Failed to memory allocation"); + return OC_STACK_NO_MEMORY; + } + secPayload->base.type = PAYLOAD_TYPE_SECURITY; + secPayload->securityData = BinToPstatJSON(otmCtx->selectedDeviceInfo->pstat); + if (NULL == secPayload->securityData) + { + OICFree(secPayload); + SetResult(otmCtx, OC_STACK_INVALID_JSON); + return OC_STACK_DELETE_TRANSACTION; + } + OC_LOG_V(INFO, TAG, "Created payload for commit hash: %s",secPayload->securityData); + + char uri[MAX_QUERY_LENGTH] = { 0 }; + size_t uriLen = sizeof(uri); + + snprintf(uri, uriLen - 1, COAPS_QUERY, otmCtx->selectedDeviceInfo->endpoint.addr, + otmCtx->selectedDeviceInfo->securePort, OIC_RSRC_PSTAT_URI); + uri[uriLen - 1] = '\0'; + OCCallbackData cbData = {.context=NULL, .cb=NULL, .cd=NULL}; + cbData.cb = &FinalizeProvisioningCB; + cbData.context = (void*)otmCtx; // forward context to SRPFinalizeProvisioningCB + cbData.cd = NULL; + + // TODO change value of CT_ADAPTER_IP with val from discovery + OCStackResult ret = OCDoResource(NULL, OC_REST_PUT, uri, 0, (OCPayload*)secPayload, + CT_ADAPTER_IP, OC_HIGH_QOS, &cbData, NULL, 0); + OC_LOG_V(INFO, TAG, "OCDoResource returned: %d",ret); + if (ret != OC_STACK_OK) + { + OC_LOG(ERROR, TAG, "OCStack resource error"); + SetResult(otmCtx, ret); + } + } + else + { + OC_LOG_V(INFO, TAG, "Error occured in provisionDefaultACLCB :: %d\n", + clientResponse->result); + SetResult(otmCtx, clientResponse->result); + } +exit: + return OC_STACK_DELETE_TRANSACTION; +} + + +OCStackResult FinalizeProvisioning(OTMContext_t* otmCtx) +{ + OC_LOG(INFO, TAG, "IN FinalizeProvisioning"); + + if(!otmCtx) + { + OC_LOG(ERROR, TAG, "OTMContext is NULL"); + return OC_STACK_INVALID_PARAM; + } + if(!otmCtx->selectedDeviceInfo) + { + OC_LOG(ERROR, TAG, "Can't find device information in OTMContext"); + OICFree(otmCtx); + return OC_STACK_INVALID_PARAM; + } + // Provision Default ACL to device + OicSecAcl_t defaultAcl = + { {.id={0}}, + 1, + NULL, + 0x001F, + 0, + NULL, + NULL, + 1, + NULL, + NULL, + }; + + OicUuid_t provTooldeviceID = {.id={0}}; + if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID)) + { + OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID"); + SetResult(otmCtx, OC_STACK_ERROR); + return OC_STACK_ERROR; + } + OC_LOG(INFO, TAG, "Retieved deviceID"); + memcpy(defaultAcl.subject.id, provTooldeviceID.id, sizeof(defaultAcl.subject.id)); + char *wildCardResource = "*"; + defaultAcl.resources = &wildCardResource; + + defaultAcl.owners = (OicUuid_t *) OICCalloc(1, UUID_LENGTH); + if(!defaultAcl.owners) + { + OC_LOG(ERROR, TAG, "Failed to memory allocation for default ACL"); + SetResult(otmCtx, OC_STACK_NO_MEMORY); + return OC_STACK_NO_MEMORY; + } + memcpy(defaultAcl.owners->id, provTooldeviceID.id, UUID_LENGTH); + OC_LOG(INFO, TAG, "Provisioning default ACL"); + + OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload)); + if(!secPayload) + { + OC_LOG(ERROR, TAG, "Failed to memory allocation"); + return OC_STACK_NO_MEMORY; + } + secPayload->base.type = PAYLOAD_TYPE_SECURITY; + secPayload->securityData = BinToAclJSON(&defaultAcl); + OICFree(defaultAcl.owners); + if(!secPayload->securityData) + { + OICFree(secPayload); + OC_LOG(INFO, TAG, "FinalizeProvisioning : Failed to BinToAclJSON"); + SetResult(otmCtx, OC_STACK_ERROR); + return OC_STACK_ERROR; + } + OC_LOG_V(INFO, TAG, "Provisioning default ACL : %s",secPayload->securityData); + + char uri[MAX_QUERY_LENGTH] = { 0 }; + + size_t uriLen = sizeof(uri); + snprintf(uri, uriLen - 1, COAPS_QUERY, otmCtx->selectedDeviceInfo->endpoint.addr, + otmCtx->selectedDeviceInfo->securePort, OIC_RSRC_ACL_URI); + uri[uriLen - 1] = '\0'; + OC_LOG_V(INFO, TAG, "Request URI for Provisioning default ACL : %s",uri); + + OCCallbackData cbData = {.context=NULL, .cb=NULL, .cd=NULL}; + cbData.cb = &ProvisionDefaultACLCB; + cbData.context = (void *)otmCtx; + cbData.cd = NULL; + + OCStackResult ret = OCDoResource(NULL, OC_REST_POST, uri, + &otmCtx->selectedDeviceInfo->endpoint, (OCPayload*)secPayload, + CT_ADAPTER_IP, OC_HIGH_QOS, &cbData, NULL, 0); + if (OC_STACK_OK != ret) + { + SetResult(otmCtx, ret); + return ret; + } + + OC_LOG(INFO, TAG, "OUT FinalizeProvisioning"); + + return ret; + +} + diff --git a/resource/csdk/security/provisioning/src/oxmjustworks.c b/resource/csdk/security/provisioning/src/oxmjustworks.c new file mode 100644 index 0000000..2d1988c --- /dev/null +++ b/resource/csdk/security/provisioning/src/oxmjustworks.c @@ -0,0 +1,108 @@ +/* ***************************************************************** + * + * Copyright 2015 Samsung Electronics 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 +#include "ocstack.h" +#include "securevirtualresourcetypes.h" +#include "doxmresource.h" +#include "cacommon.h" +#include "cainterface.h" +#include "oic_malloc.h" +#include "logger.h" +#include "global.h" +#include "pmtypes.h" +#include "ownershiptransfermanager.h" + +#define TAG "OXM_JustWorks" + +char* CreateJustWorksSelectOxmPayload(OTMContext_t* otmCtx) +{ + if(!otmCtx || !otmCtx->selectedDeviceInfo) + { + return NULL; + } + + otmCtx->selectedDeviceInfo->doxm->oxmSel = OIC_JUST_WORKS; + return BinToDoxmJSON(otmCtx->selectedDeviceInfo->doxm); +} + +char* CreateJustWorksOwnerTransferPayload(OTMContext_t* otmCtx) +{ + if(!otmCtx || !otmCtx->selectedDeviceInfo) + { + return NULL; + } + + OicUuid_t uuidPT = {.id={0}}; + + if (OC_STACK_OK != GetDoxmDeviceID(&uuidPT)) + { + OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID"); + return NULL; + } + memcpy(otmCtx->selectedDeviceInfo->doxm->owner.id, uuidPT.id , UUID_LENGTH); + otmCtx->selectedDeviceInfo->doxm->owned = true; + + return BinToDoxmJSON(otmCtx->selectedDeviceInfo->doxm); +} + +OCStackResult LoadSecretJustWorksCallback(OTMContext_t* UNUSED_PARAM) +{ + //In case of 'just works', secret data not required + (void)UNUSED_PARAM; + return OC_STACK_OK; +} + +OCStackResult CreateSecureSessionJustWorksCallback(OTMContext_t* otmCtx) +{ + OC_LOG(INFO, TAG, "IN CreateSecureSessionJustWorksCallback"); + if(!otmCtx || !otmCtx->selectedDeviceInfo) + { + return OC_STACK_INVALID_PARAM; + } + + CAResult_t caresult = CAEnableAnonECDHCipherSuite(true); + if (CA_STATUS_OK != caresult) + { + OC_LOG_V(ERROR, TAG, "Unable to enable anon cipher suite"); + return OC_STACK_ERROR; + } + OC_LOG(INFO, TAG, "Anonymous cipher suite Enabled."); + + OCProvisionDev_t* selDevInfo = otmCtx->selectedDeviceInfo; + CAEndpoint_t *endpoint = (CAEndpoint_t *)OICCalloc(1, sizeof (CAEndpoint_t)); + if(NULL == endpoint) + { + return OC_STACK_NO_MEMORY; + } + memcpy(endpoint,&selDevInfo->endpoint,sizeof(CAEndpoint_t)); + endpoint->port = selDevInfo->securePort; + + caresult = CAInitiateHandshake(endpoint); + OICFree(endpoint); + if (CA_STATUS_OK != caresult) + { + OC_LOG_V(ERROR, TAG, "DTLS handshake failure."); + return OC_STACK_ERROR; + } + + OC_LOG(INFO, TAG, "OUT CreateSecureSessionJustWorksCallback"); + return OC_STACK_OK; +} diff --git a/resource/csdk/security/provisioning/src/oxmrandompin.c b/resource/csdk/security/provisioning/src/oxmrandompin.c new file mode 100644 index 0000000..ea09fb4 --- /dev/null +++ b/resource/csdk/security/provisioning/src/oxmrandompin.c @@ -0,0 +1,145 @@ +/* ***************************************************************** + * + * Copyright 2015 Samsung Electronics 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 + +#include "ocstack.h" +#include "ocsecurityconfig.h" +#include "securevirtualresourcetypes.h" +#include "doxmresource.h" +#include "credresource.h" +#include "cacommon.h" +#include "cainterface.h" +#include "ocrandom.h" +#include "oic_malloc.h" +#include "logger.h" +#include "pbkdf2.h" +#include "global.h" +#include "base64.h" +#include "oxmrandompin.h" +#include "ownershiptransfermanager.h" +#include "pinoxmcommon.h" + +#define TAG "OXM_RandomPIN" + +char* CreatePinBasedSelectOxmPayload(OTMContext_t* otmCtx) +{ + if(!otmCtx || !otmCtx->selectedDeviceInfo) + { + return NULL; + } + + otmCtx->selectedDeviceInfo->doxm->oxmSel = OIC_RANDOM_DEVICE_PIN; + + OicUuid_t uuidPT = {.id={0}}; + if (OC_STACK_OK != GetDoxmDeviceID(&uuidPT)) + { + OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID"); + return NULL; + } + memcpy(otmCtx->selectedDeviceInfo->doxm->owner.id, uuidPT.id, UUID_LENGTH); + + return BinToDoxmJSON(otmCtx->selectedDeviceInfo->doxm); +} + +char* CreatePinBasedOwnerTransferPayload(OTMContext_t* otmCtx) +{ + if(!otmCtx || !otmCtx->selectedDeviceInfo) + { + return NULL; + } + + OicUuid_t uuidPT = {.id={0}}; + + if (OC_STACK_OK != GetDoxmDeviceID(&uuidPT)) + { + OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID"); + return NULL; + } + memcpy(otmCtx->selectedDeviceInfo->doxm->owner.id, uuidPT.id , UUID_LENGTH); + otmCtx->selectedDeviceInfo->doxm->owned = true; + + return BinToDoxmJSON(otmCtx->selectedDeviceInfo->doxm); +} + +OCStackResult InputPinCodeCallback(OTMContext_t* otmCtx) +{ + if(!otmCtx || !otmCtx->selectedDeviceInfo) + { + return OC_STACK_INVALID_PARAM; + } + + uint8_t pinData[OXM_RANDOM_PIN_SIZE + 1]; + + OCStackResult res = InputPin((char*)pinData, OXM_RANDOM_PIN_SIZE + 1); + if(OC_STACK_OK != res) + { + OC_LOG(ERROR, TAG, "Failed to input PIN"); + return res; + } + + OicUuid_t deviceUUID = {.id={0}}; + if (OC_STACK_OK != GetDoxmDeviceID(&deviceUUID)) + { + OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID"); + return OC_STACK_ERROR; + } + + res = AddTmpPskWithPIN(&otmCtx->selectedDeviceInfo->doxm->deviceID, + SYMMETRIC_PAIR_WISE_KEY, + (char*)pinData, OXM_RANDOM_PIN_SIZE, + 1, &deviceUUID, &otmCtx->tempCredId); + if(res != OC_STACK_OK) + { + OC_LOG_V(ERROR, TAG, "Failed to save the temporal PSK : %d", res); + } + + return res; +} + +OCStackResult CreateSecureSessionRandomPinCallbak(OTMContext_t* otmCtx) +{ + OC_LOG(INFO, TAG, "IN CreateSecureSessionRandomPinCallbak"); + + if(!otmCtx || !otmCtx->selectedDeviceInfo) + { + return OC_STACK_INVALID_PARAM; + } + + OCProvisionDev_t* selDevInfo = otmCtx->selectedDeviceInfo; + CAEndpoint_t *endpoint = (CAEndpoint_t *)OICCalloc(1, sizeof (CAEndpoint_t)); + if(NULL == endpoint) + { + return OC_STACK_NO_MEMORY; + } + memcpy(endpoint,&selDevInfo->endpoint,sizeof(CAEndpoint_t)); + endpoint->port = selDevInfo->securePort; + CAResult_t caresult = CAInitiateHandshake(endpoint); + OICFree(endpoint); + if (CA_STATUS_OK != caresult) + { + OC_LOG_V(ERROR, TAG, "DTLS handshake failure."); + return OC_STACK_ERROR; + } + + OC_LOG(INFO, TAG, "OUT CreateSecureSessionRandomPinCallbak"); + + return OC_STACK_OK; +} diff --git a/resource/csdk/security/provisioning/src/pmutility.c b/resource/csdk/security/provisioning/src/pmutility.c new file mode 100644 index 0000000..0f46c36 --- /dev/null +++ b/resource/csdk/security/provisioning/src/pmutility.c @@ -0,0 +1,475 @@ +/* ***************************************************************** + * + * Copyright 2015 Samsung Electronics 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 _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200112L +#endif + +#include +#include +#include +#include + +#include "ocstack.h" +#include "oic_malloc.h" +#include "oic_string.h" +#include "logger.h" +#include "cJSON.h" +#include "utlist.h" +#include "ocpayload.h" + +#include "securevirtualresourcetypes.h" +#include "srmresourcestrings.h" //@note: SRM's internal header +#include "doxmresource.h" //@note: SRM's internal header +#include "pstatresource.h" //@note: SRM's internal header + +#include "pmtypes.h" +#include "pmutility.h" + +#define TAG ("PM-UTILITY") + +/** + * Function to search node in linked list that matches given IP and port. + * + * @param[in] pList List of OCProvisionDev_t. + * @param[in] addr address of target device. + * @param[in] port port of remote server. + * + * @return pointer of OCProvisionDev_t if exist, otherwise NULL + */ +OCProvisionDev_t* GetDevice(OCProvisionDev_t **ppDevicesList, const char* addr, const uint16_t port) +{ + if(NULL == addr || NULL == *ppDevicesList) + { + OC_LOG_V(ERROR, TAG, "Invalid Input parameters in [%s]\n", __FUNCTION__); + return NULL; + } + + OCProvisionDev_t *ptr = NULL; + LL_FOREACH(*ppDevicesList, ptr) + { + if( strcmp(ptr->endpoint.addr, addr) == 0 && port == ptr->endpoint.port) + { + return ptr; + } + } + + return NULL; +} + + +/** + * Add device information to list. + * + * @param[in] pList List of OCProvisionDev_t. + * @param[in] addr address of target device. + * @param[in] port port of remote server. + * @param[in] adapter adapter type of endpoint. + * @param[in] doxm pointer to doxm instance. + * + * @return OC_STACK_OK for success and errorcode otherwise. + */ +OCStackResult AddDevice(OCProvisionDev_t **ppDevicesList, const char* addr, const uint16_t port, + OCTransportAdapter adapter, OicSecDoxm_t *doxm) +{ + if (NULL == addr) + { + return OC_STACK_INVALID_PARAM; + } + + OCProvisionDev_t *ptr = GetDevice(ppDevicesList, addr, port); + if(!ptr) + { + ptr = (OCProvisionDev_t *)OICCalloc(1, sizeof (OCProvisionDev_t)); + if (NULL == ptr) + { + OC_LOG(ERROR, TAG, "Error while allocating memory for linkedlist node !!"); + return OC_STACK_NO_MEMORY; + } + + OICStrcpy(ptr->endpoint.addr, MAX_ADDR_STR_SIZE, addr); + ptr->endpoint.port = port; + ptr->doxm = doxm; + ptr->securePort = DEFAULT_SECURE_PORT; + ptr->endpoint.adapter = adapter; + ptr->next = NULL; + + LL_PREPEND(*ppDevicesList, ptr); + } + + return OC_STACK_OK; +} + +/** + * Function to set secure port information from the given list of devices. + * + * @param[in] pList List of OCProvisionDev_t. + * @param[in] addr address of target device. + * @param[in] port port of remote server. + * @param[in] secureport secure port information. + * + * @return OC_STACK_OK for success and errorcode otherwise. + */ +OCStackResult UpdateSecurePortOfDevice(OCProvisionDev_t **ppDevicesList, const char *addr, uint16_t port, + uint16_t securePort) +{ + OCProvisionDev_t *ptr = GetDevice(ppDevicesList, addr, port); + + if(!ptr) + { + OC_LOG(ERROR, TAG, "Can not find device information in the discovery device list"); + return OC_STACK_ERROR; + } + + ptr->securePort = securePort; + + return OC_STACK_OK; +} + +/** + * This function deletes list of provision target devices + * + * @param[in] pList List of OCProvisionDev_t. + */ +void DeleteDeviceList(OCProvisionDev_t **ppDevicesList) +{ + if(*ppDevicesList) + { + OCProvisionDev_t *del = NULL, *tmp = NULL; + LL_FOREACH_SAFE(*ppDevicesList, del, tmp) + { + LL_DELETE(*ppDevicesList, del); + + DeleteDoxmBinData(del->doxm); + DeletePstatBinData(del->pstat); + OICFree(del); + } + } +} + +/** + * Timeout implementation for secure discovery. When performing secure discovery, + * we should wait a certain period of time for getting response of each devices. + * + * @param[in] waittime Timeout in seconds. + * @return OC_STACK_OK on success otherwise error. + */ +OCStackResult PMTimeout(unsigned short waittime) +{ + struct timespec startTime = {.tv_sec=0, .tv_nsec=0}; + struct timespec currTime = {.tv_sec=0, .tv_nsec=0}; + + OCStackResult res = OC_STACK_OK; +#ifdef _POSIX_MONOTONIC_CLOCK + int clock_res = clock_gettime(CLOCK_MONOTONIC, &startTime); +#else + int clock_res = clock_gettime(CLOCK_REALTIME, &startTime); +#endif + if (0 != clock_res) + { + return OC_STACK_ERROR; + } + while (OC_STACK_OK == res) + { +#ifdef _POSIX_MONOTONIC_CLOCK + clock_res = clock_gettime(CLOCK_MONOTONIC, &currTime); +#else + clock_res = clock_gettime(CLOCK_REALTIME, &currTime); +#endif + if (0 != clock_res) + { + return OC_STACK_TIMEOUT; + } + long elapsed = (currTime.tv_sec - startTime.tv_sec); + if (elapsed > waittime) + { + return OC_STACK_OK; + } + res = OCProcess(); + } + + return res; +} + +/** + * Extract secure port information from payload of discovery response. + * + * @param[in] jsonStr response payload of /oic/res discovery. + * + * @return Secure port + */ +uint16_t GetSecurePortFromJSON(char* jsonStr) +{ + // TODO: Modify error handling + if (NULL == jsonStr) + { + return 0; + } + cJSON *jsonProp = NULL; + cJSON *jsonP = NULL; + cJSON *jsonPort = NULL; + + cJSON *jsonRoot = cJSON_Parse(jsonStr); + if(!jsonRoot) + { + // TODO: Add error log & return default secure port + return 0; + } + + jsonProp = cJSON_GetObjectItem(jsonRoot, "prop"); + if(!jsonProp) + { + // TODO: Add error log & return default secure port + return 0; + } + + jsonP = cJSON_GetObjectItem(jsonProp, "p"); + if(!jsonP) + { + // TODO: Add error log & return default secure port + return 0; + } + + jsonPort = cJSON_GetObjectItem(jsonP, "port"); + if(!jsonPort) + { + // TODO: Add error log & return default secure port + return 0; + } + + return (uint16_t)jsonPort->valueint; +} + + +/** + * Callback handler for getting secure port information using /oic/res discovery. + * + * @param[in] ctx user context + * @param[in] handle Handle for response + * @param[in] clientResponse Response information(It will contain payload) + * + * @return OC_STACK_KEEP_TRANSACTION to keep transaction and + * OC_STACK_DELETE_TRANSACTION to delete it. + */ +static OCStackApplicationResult SecurePortDiscoveryHandler(void *ctx, OCDoHandle UNUSED, + OCClientResponse *clientResponse) +{ + if (ctx == NULL) + { + OC_LOG(ERROR, TAG, "Lost List of device information"); + return OC_STACK_KEEP_TRANSACTION; + } + (void)UNUSED; + if (clientResponse) + { + if (NULL == clientResponse->payload) + { + OC_LOG(INFO, TAG, "Skiping Null payload"); + } + else + { + if (PAYLOAD_TYPE_DISCOVERY != clientResponse->payload->type) + { + OC_LOG(INFO, TAG, "Wrong payload type"); + return OC_STACK_KEEP_TRANSACTION; + } + + OCDiscoveryPayload* discover = (OCDiscoveryPayload*) clientResponse->payload; + uint16_t securePort = 0; + + if (discover && discover->resources && discover->resources->secure) + { + securePort = discover->resources->port; + } + else + { + OC_LOG(INFO, TAG, "Secure Port info is missing"); + return OC_STACK_KEEP_TRANSACTION; + } + + OCProvisionDev_t** ppDevicesList = (OCProvisionDev_t**) ctx; + + OCStackResult res = UpdateSecurePortOfDevice(ppDevicesList, clientResponse->devAddr.addr, + clientResponse->devAddr.port, securePort); + if (OC_STACK_OK != res) + { + OC_LOG(ERROR, TAG, "Error while getting secure port."); + return OC_STACK_KEEP_TRANSACTION; + } + OC_LOG(INFO, TAG, "Exiting SecurePortDiscoveryHandler."); + } + + return OC_STACK_KEEP_TRANSACTION; + } + else + { + OC_LOG(INFO, TAG, "Skiping Null response"); + } + return OC_STACK_DELETE_TRANSACTION; +} + +/** + * Callback handler for PMDeviceDiscovery API. + * + * @param[in] ctx User context + * @param[in] handle Handler for response + * @param[in] clientResponse Response information (It will contain payload) + * @return OC_STACK_KEEP_TRANSACTION to keep transaction and + * OC_STACK_DELETE_TRANSACTION to delete it. + */ +static OCStackApplicationResult DeviceDiscoveryHandler(void *ctx, OCDoHandle UNUSED, + OCClientResponse *clientResponse) +{ + if (ctx == NULL) + { + OC_LOG(ERROR, TAG, "Lost List of device information"); + return OC_STACK_KEEP_TRANSACTION; + } + (void)UNUSED; + if (clientResponse) + { + if (NULL == clientResponse->payload) + { + OC_LOG(INFO, TAG, "Skiping Null payload"); + return OC_STACK_KEEP_TRANSACTION; + } + if (OC_STACK_OK != clientResponse->result) + { + OC_LOG(INFO, TAG, "Error in response"); + return OC_STACK_KEEP_TRANSACTION; + } + else + { + if (PAYLOAD_TYPE_SECURITY != clientResponse->payload->type) + { + OC_LOG(INFO, TAG, "Unknown payload type"); + return OC_STACK_KEEP_TRANSACTION; + } + OicSecDoxm_t *ptrDoxm = JSONToDoxmBin( + ((OCSecurityPayload*)clientResponse->payload)->securityData); + if (NULL == ptrDoxm) + { + OC_LOG(INFO, TAG, "Ignoring malformed JSON"); + return OC_STACK_KEEP_TRANSACTION; + } + else + { + OC_LOG(DEBUG, TAG, "Successfully converted doxm json to bin."); + + OCProvisionDev_t **ppDevicesList = (OCProvisionDev_t**) ctx; + + OCStackResult res = AddDevice(ppDevicesList, clientResponse->devAddr.addr, + clientResponse->devAddr.port, + clientResponse->devAddr.adapter, ptrDoxm); + if (OC_STACK_OK != res) + { + OC_LOG(ERROR, TAG, "Error while adding data to linkedlist."); + DeleteDoxmBinData(ptrDoxm); + return OC_STACK_KEEP_TRANSACTION; + } + + //Try to the unicast discovery to getting secure port + char query[MAX_QUERY_LENGTH] = { 0, }; + sprintf(query, "%s%s:%d%s", + COAP_PREFIX, + clientResponse->devAddr.addr, clientResponse->devAddr.port, + OC_RSRVD_WELL_KNOWN_URI); + + OCCallbackData cbData; + cbData.cb = &SecurePortDiscoveryHandler; + cbData.context = ctx; + cbData.cd = NULL; + OCStackResult ret = OCDoResource(NULL, OC_REST_GET, query, 0, 0, + CT_ADAPTER_IP, OC_LOW_QOS, &cbData, NULL, 0); + // TODO: Should we use the default secure port in case of error? + if(OC_STACK_OK != ret) + { + UpdateSecurePortOfDevice(ppDevicesList, clientResponse->devAddr.addr, + clientResponse->devAddr.port, DEFAULT_SECURE_PORT); + } + else + { + OC_LOG_V(ERROR, TAG, "OCDoResource with [%s] Success", query); + } + OC_LOG(INFO, TAG, "Exiting ProvisionDiscoveryHandler."); + } + + return OC_STACK_KEEP_TRANSACTION; + } + } + else + { + OC_LOG(INFO, TAG, "Skiping Null response"); + return OC_STACK_KEEP_TRANSACTION; + } + + return OC_STACK_DELETE_TRANSACTION; +} + +/** + * Discover owned/unowned devices in the same IP subnet. . + * + * @param[in] waittime Timeout in seconds. + * @param[in] isOwned bool flag for owned / unowned discovery + * @param[in] ppDevicesList List of OCProvisionDev_t. + * + * @return OC_STACK_OK on success otherwise error. + */ +OCStackResult PMDeviceDiscovery(unsigned short waittime, bool isOwned, OCProvisionDev_t **ppDevicesList) +{ + OC_LOG(DEBUG, TAG, "IN PMDeviceDiscovery"); + + if (NULL != *ppDevicesList) + { + OC_LOG(ERROR, TAG, "List is not null can cause memory leak"); + return OC_STACK_INVALID_PARAM; + } + + const char DOXM_OWNED_FALSE_MULTICAST_QUERY[] = "/oic/sec/doxm?Owned=FALSE"; + const char DOXM_OWNED_TRUE_MULTICAST_QUERY[] = "/oic/sec/doxm?Owned=TRUE"; + + OCCallbackData cbData; + cbData.cb = &DeviceDiscoveryHandler; + cbData.context = (void *)ppDevicesList; + cbData.cd = NULL; + OCStackResult res = OC_STACK_ERROR; + + const char* query = isOwned ? DOXM_OWNED_TRUE_MULTICAST_QUERY : + DOXM_OWNED_FALSE_MULTICAST_QUERY; + + res = OCDoResource(NULL, OC_REST_DISCOVER, query, 0, 0, + CT_DEFAULT, OC_LOW_QOS, &cbData, NULL, 0); + if (res != OC_STACK_OK) + { + OC_LOG(ERROR, TAG, "OCStack resource error"); + goto exit; + } + + //Waiting for each response. + res = PMTimeout(waittime); + if(OC_STACK_OK != res) + { + OC_LOG(ERROR, TAG, "Failed to wait response for secure discovery."); + goto exit; + } + + OC_LOG(DEBUG, TAG, "OUT PMDeviceDiscovery"); +exit: + return res; +} diff --git a/resource/csdk/security/provisioning/src/provisioningmanager.c b/resource/csdk/security/provisioning/src/provisioningmanager.c deleted file mode 100644 index bcd5e4d..0000000 --- a/resource/csdk/security/provisioning/src/provisioningmanager.c +++ /dev/null @@ -1,1669 +0,0 @@ -/* ***************************************************************** - * - * Copyright 2015 Samsung Electronics 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. - * - * *****************************************************************/ - -// Defining _POSIX_C_SOURCE macro with 199309L (or greater) as value -// causes header files to expose definitions -// corresponding to the POSIX.1b, Real-time extensions -// (IEEE Std 1003.1b-1993) specification -// -// For this specific file, see use of clock_gettime, -// Refer to http://pubs.opengroup.org/stage7tc1/functions/clock_gettime.html -// and to http://man7.org/linux/man-pages/man2/clock_gettime.2.html - -#ifndef _POSIX_C_SOURCE -#define _POSIX_C_SOURCE 200809L -#endif - -#include -#include -#include -#include -#include - -#include "cJSON.h" -#include "ocpayload.h" -#include "ocpayloadcbor.h" -#include "oic_malloc.h" -#include "logger.h" -#include "cacommon.h" -#include "cainterface.h" -#include "provisioningmanager.h" -#include "credentialgenerator.h" -#include "global.h" -#include "base64.h" -#include "aclresource.h" -#include "doxmresource.h" -#include "pstatresource.h" -#include "srmresourcestrings.h" -#include "credresource.h" -#include "oic_string.h" -#include "secureresourcemanager.h" - -typedef enum -{ - SP_NO_MASK = (0 ), - SP_DISCOVERY_STARTED = (0x1 << 1), - SP_DISCOVERY_ERROR = (0x1 << 2), - SP_DISCOVERY_DONE = (0x1 << 3), - SP_SEC_RES_INFO_STARTED = (0x1 << 4), - SP_SEC_RES_INFO_ERROR = (0x1 << 5), - SP_SEC_RES_INFO_DONE = (0x1 << 6), - SP_UP_OWN_TR_METH_STARTED = (0x1 << 7), - SP_UP_OWN_TR_METH_ERROR = (0x1 << 8), - SP_UP_OWN_TR_METH_DONE = (0x1 << 9), - SP_LIST_METHODS_STARTED = (0x1 << 10), - SP_LIST_METHODS_ERROR = (0x1 << 11), - SP_LIST_METHODS_DONE = (0x1 << 12), - SP_UPDATE_OP_MODE_STARTED = (0x1 << 13), - SP_UPDATE_OP_MODE_ERROR = (0x1 << 14), - SP_UPDATE_OP_MODE_DONE = (0x1 << 15), - SP_UPDATE_OWNER_STARTED = (0x1 << 16), - SP_UPDATE_OWNER_ERROR = (0x1 << 17), - SP_UPDATE_OWNER_DONE = (0x1 << 18), - SP_PROV_ACL_STARTED = (0x1 << 19), - SP_PROV_ACL_ERROR = (0x1 << 20), - SP_PROV_ACL_DONE = (0x1 << 21), - SP_UP_HASH_STARTED = (0x1 << 22), - SP_UP_HASH_ERROR = (0x1 << 23), - SP_UP_HASH_DONE = (0x1 << 24), - SP_PROV_CRED_STARTED = (0x1 << 25), - SP_PROV_CRED_ERROR = (0x1 << 26), - SP_PROV_CRED_DONE = (0x1 << 27) -} SPProvisioningStates; - -#define SP_MAX_BUF_LEN 1024 -#define TAG "SPProvisionAPI" -#define COAP_QUERY "coap://%s:%d%s" -#define COAPS_QUERY "coaps://%s:%d%s" - -bool (*handler)(const CAEndpoint_t *, const CAResponseInfo_t *); - -/** - * CA token to keep track of response. - */ -static CAToken_t gToken = NULL; - -/** - * start pointer for discovered device linked list. - */ -static SPTargetDeviceInfo_t *gStartOfDiscoveredDevices = NULL; - -/** - * current pointer of device linked list. - */ -static SPTargetDeviceInfo_t *gCurrent = NULL; - -/** - * Variable to keep track of various request. - */ -static uint32_t gStateManager = 0; - -/** - * Variable for storing provisioning tool's provisioning capabilities - * Must be in decreasing order of preference. More prefered method should - * have lower array index. - */ -static OicSecDpom_t gProvisioningToolCapability[] = { SINGLE_SERVICE_CLIENT_DRIVEN }; - -/** - * Number of supported provisioning methods - * current version supports only one. - */ -static int gNumOfProvisioningMethodsPT = 1; - -/** - * Global variable to save pstat. - */ -static OicSecPstat_t *gPstat = NULL; - -/** - * Secure String copy function - * @param[in] destination Pointer to destination string. - * @param[in] source Pointer to source string. - * @return pointer to destination string, NULL in case of error. - */ -static inline char *SPStringCopy(char *destination, const char *source, size_t num) -{ - if (strncpy(destination, source, num)) - { - destination[num - 1] = '\0'; - return destination; - } - return NULL; -} - -/** - * Function to convert CA result code to SP result code. - * - * @return result code of SP corresponding to that of CA. - */ -static SPResult convertCAResultToSPResult(CAResult_t caResult) -{ - switch (caResult) - { - case CA_STATUS_OK: - { - return SP_RESULT_SUCCESS; - } - case CA_STATUS_INVALID_PARAM: - { - return SP_RESULT_CONN_INVALID_PARAM; - } - case CA_ADAPTER_NOT_ENABLED: - { - return SP_RESULT_CONN_SERVER_STARTED_ALREADY; - } - case CA_SERVER_STARTED_ALREADY: - { - return SP_RESULT_CONN_SERVER_STARTED_ALREADY; - } - case CA_SERVER_NOT_STARTED: - { - return SP_RESULT_CONN_SERVER_NOT_STARTED; - } - case CA_DESTINATION_NOT_REACHABLE: - { - return SP_RESULT_CONN_DESTINATION_NOT_REACHABLE; - } - case CA_SOCKET_OPERATION_FAILED: - { - return SP_RESULT_CONN_SOCKET_OPERATION_FAILED; - } - case CA_SEND_FAILED: - { - return SP_RESULT_CONN_SEND_FAILED; - } - case CA_RECEIVE_FAILED: - { - return SP_RESULT_CONN_RECEIVE_FAILED; - } - case CA_MEMORY_ALLOC_FAILED: - { - return SP_RESULT_CONN_MEMORY_ALLOC_FAILED; - } - case CA_REQUEST_TIMEOUT: - { - return SP_RESULT_CONN_REQUEST_TIMEOUT; - } - case CA_DESTINATION_DISCONNECTED: - { - return SP_RESULT_CONN_DESTINATION_DISCONNECTED; - } - case CA_STATUS_FAILED: - { - return SP_RESULT_CONN_STATUS_FAILED; - } - case CA_NOT_SUPPORTED: - { - return SP_RESULT_CONN_NOT_SUPPORTED; - } - default: - { - return SP_RESULT_INTERNAL_ERROR; - } - } -} - -/** - * Function to delete memory allocated to linked list. - * - */ -static void deleteList() -{ - SPTargetDeviceInfo_t *current = gStartOfDiscoveredDevices; - - while (current) - { - SPTargetDeviceInfo_t *next = current->next; - DeleteDoxmBinData(current->doxm); - DeletePstatBinData(current->pstat); - OICFree(current); - current = next; - } - gStartOfDiscoveredDevices = NULL; -} - -/** - * Timeout implementation. - * @param[in] timeout Timeout in seconds. with 0 it will wait forever for success. - * @param[in] mask Mask of operation and 0 for no mask. - * @return SP_RESULT_SUCCESS on success otherwise error. - */ -static SPResult SPTimeout(unsigned short timeout, uint32_t mask) -{ - struct timespec startTime = {}; - struct timespec currTime = {}; - - CAResult_t res = SP_RESULT_SUCCESS; -#ifdef _POSIX_MONOTONIC_CLOCK - int clock_res = clock_gettime(CLOCK_MONOTONIC, &startTime); -#else - int clock_res = clock_gettime(CLOCK_REALTIME, &startTime); -#endif - if (0 != clock_res) - { - return SP_RESULT_INTERNAL_ERROR; - } - while (CA_STATUS_OK == res) - { - res = CAHandleRequestResponse(); -#ifdef _POSIX_MONOTONIC_CLOCK - clock_res = clock_gettime(CLOCK_MONOTONIC, &currTime); -#else - clock_res = clock_gettime(CLOCK_REALTIME, &currTime); -#endif - if (0 != clock_res) - { - return SP_RESULT_INTERNAL_ERROR; - } - long elapsed = (currTime.tv_sec - startTime.tv_sec); - if (SP_NO_MASK == mask) - { - if (elapsed > timeout) - { - return SP_RESULT_SUCCESS; - } - } - else - { - if (gStateManager & mask) - { - return SP_RESULT_SUCCESS; - } - if ((elapsed > timeout) && timeout) - { - return SP_RESULT_INTERNAL_ERROR; - } - } - } - return convertCAResultToSPResult(res); -} - -/** - * Function to send request to resource server. - * @param[in] method method to be used for sending rquest. - * @param[in] endpoint endpoint address - * @param[in] secure use secure connection - * @param[in] resourceUri resourceUri token. - * @param[in] payload Payload to be sent with data. NULL is case message - * doesn't have payload. - * @param[in] payloadLen Size of data to be sent. - * @return CA_STATUS_OK on success, otherwise error code. - */ -static CAResult_t sendCARequest(CAMethod_t method, - const OCDevAddr *devAddr, - OCTransportFlags secure, - const char *resourceUri, - char *payload, int payloadLen) -{ - if (payload && '\0' != (*(payload + payloadLen))) - { - OC_LOG(ERROR, TAG, "Payload not properly terminated."); - return CA_STATUS_INVALID_PARAM; - } - - if (CA_STATUS_OK != CAGenerateToken(&gToken, CA_MAX_TOKEN_LEN)) - { - OC_LOG(ERROR, TAG, "Error while generating token"); - return CA_MEMORY_ALLOC_FAILED; - } - - CAEndpoint_t *endpoint = NULL; - if (CA_STATUS_OK != CACreateEndpoint(devAddr->flags | (CATransportFlags_t)secure, - devAddr->adapter, devAddr->addr, - devAddr->port, &endpoint)) - { - OC_LOG(ERROR, TAG, "Failed to create remote endpoint"); - CADestroyEndpoint(endpoint); - return CA_STATUS_FAILED; - } - - OCSecurityPayload secPayload = {}; - secPayload.securityData = payload; - secPayload.base.type = PAYLOAD_TYPE_SECURITY; - - CARequestInfo_t requestInfo = {}; - requestInfo.method = method; - requestInfo.isMulticast = false; - OCConvertPayload((OCPayload*)(&secPayload), &requestInfo.info.payload, - &requestInfo.info.payloadSize); - - requestInfo.info.type = CA_MSG_CONFIRM; - requestInfo.info.token = gToken; - requestInfo.info.tokenLength = CA_MAX_TOKEN_LEN; - requestInfo.info.resourceUri = (CAURI_t)resourceUri; - - CAResult_t caResult = CA_STATUS_OK; - caResult = CASendRequest(endpoint, &requestInfo); - if (CA_STATUS_OK != caResult) - { - OC_LOG(ERROR, TAG, "Send Request Error !!"); - } - CADestroyEndpoint(endpoint); - return caResult; -} - -/** - * addDevice to list. - * - * @param[in] endpoint Endpoint information - * @param[in] doxm pointer to doxm instance. - * @return SP_RESULT_SUCCESS for success and errorcode otherwise. - */ -static SPResult addDevice(const CAEndpoint_t *endpoint, OicSecDoxm_t* doxm) -{ - if (NULL == endpoint) - { - return SP_RESULT_INVALID_PARAM; - } - SPTargetDeviceInfo_t *ptr = (SPTargetDeviceInfo_t *)OICCalloc(1, sizeof (SPTargetDeviceInfo_t)); - if (NULL == ptr) - { - OC_LOG(ERROR, TAG, "Error while allocating memory for linkedlist node !!"); - return SP_RESULT_MEM_ALLOCATION_FAIL; - } - - memcpy(&(ptr->endpoint), endpoint, sizeof(CAEndpoint_t)); - ptr->doxm = doxm; - - ptr->next = NULL; - - if (NULL == gStartOfDiscoveredDevices) - { - gStartOfDiscoveredDevices = ptr; - gCurrent = ptr; - } - else - { - gCurrent->next = ptr; - gCurrent = ptr; - } - return SP_RESULT_SUCCESS; -} - -/** - * updateDevice to update resource info for the endpoint. - * - * @param[in] endpoint Endpoint information - * @param[in] port secure port. - * @return SP_RESULT_SUCCESS for success and errorcode otherwise. - */ - -static SPResult updateDevice(const CAEndpoint_t *endpoint, uint16_t port) -{ - if (NULL == endpoint) - { - return SP_RESULT_INVALID_PARAM; - } - SPTargetDeviceInfo_t *ptr = gStartOfDiscoveredDevices; - while(ptr) - { - if(0 == strcmp(ptr->endpoint.addr, endpoint->addr) && - ptr->endpoint.port == endpoint->port) - { - ptr->securePort = port; - return SP_RESULT_SUCCESS; - } - ptr = ptr->next; - } - return SP_RESULT_INTERNAL_ERROR; -} - -/** - * Function to provide timeframe in which response can be received. - * - * @param[in] timeout Timeout in seconds. - * @return SP_RESULT_SUCCESS on success , otherwise error code. - */ -static SPResult SPWaitForResponse(unsigned short timeout) -{ - return SPTimeout(timeout, SP_NO_MASK); -} - -/** - * Function to select appropriate provisioning method. - * - * @param[in] supportedMethodsList List of supported methods - * @param[out] selectedMethod Selected methods - * @return SP_SUCCESS on success - */ -static SPResult selectProvisioningMethod(OicSecOxm_t *supportedMethods, size_t numberOfMethods, - OicSecOxm_t *selectedMethod) -{ - /* - TODO Logic to find appropiate method and assign it to out param - for beachhead release method at index 0 will be returned. - */ - *selectedMethod = supportedMethods[0]; - return SP_RESULT_SUCCESS; -} - -/** - * Response handler for discovery. - * - * @param[in] object Remote endpoint object - * @param[in] requestInfo Datastructure containing request information. - * @return true is CA token matches request token, false otherwise. - */ -static bool ProvisionDiscoveryHandler(const CAEndpoint_t *object, - const CAResponseInfo_t *responseInfo) -{ - if ((gStateManager & SP_DISCOVERY_STARTED) && gToken) - { - // Response handler for discovery. - if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength)) - { - OC_LOG(INFO, TAG, "Inside ProvisionDiscoveryHandler."); - if (NULL == responseInfo->info.payload) - { - OC_LOG(INFO, TAG, "Skiping Null payload"); - } - else - { - OCPayload* payload = NULL; - OCStackResult result = OCParsePayload(&payload, responseInfo->info.payload, - responseInfo->info.payloadSize); - - OicSecDoxm_t *ptrDoxm = NULL; - - if(result == OC_STACK_OK && payload->type == PAYLOAD_TYPE_SECURITY) - { - ptrDoxm = JSONToDoxmBin(((OCSecurityPayload*)payload)->securityData); - } - - OCPayloadDestroy(payload); - - if (NULL == ptrDoxm) - { - OC_LOG(INFO, TAG, "Ignoring malformed JSON"); - } - else - { - OC_LOG(DEBUG, TAG, "Successfully converted doxm json to bin."); - - SPResult res = addDevice(object, ptrDoxm); - if (SP_RESULT_SUCCESS != res) - { - OC_LOG(ERROR, TAG, "Error while adding data to linkedlist."); - gStateManager = gStateManager | SP_DISCOVERY_ERROR; - DeleteDoxmBinData(ptrDoxm); - return true; - } - OC_LOG(INFO, TAG, "Exiting ProvisionDiscoveryHandler."); - gStateManager |= SP_DISCOVERY_DONE; - } - } - return true; - } - } - return false; -} - -/** - * Response handler for discovery. - * - * @param[in] object Remote endpoint object - * @param[in] requestInfo Datastructure containing request information. - * @return true is CA token matches request token, false otherwise. - */ - -static bool ProvisionSecureResourceInfoHandler(const CAEndpoint_t *object, - const CAResponseInfo_t *responseInfo) -{ - if (!object || !responseInfo) - { - return false; - } - - if ((gStateManager & SP_SEC_RES_INFO_STARTED) && gToken) - { - // Response handler for discovery. - if (0 == memcmp(gToken, responseInfo->info.token, CA_MAX_TOKEN_LEN)) - { - OC_LOG(INFO, TAG, "Inside ProvisionSecureResourceInfoHandler."); - if (NULL == responseInfo->info.payload) - { - OC_LOG(ERROR, TAG, "Exiting ProvisionSecureResourceInfoHandler."); - gStateManager |= SP_SEC_RES_INFO_ERROR; - } - else - { - OCPayload* payload = NULL; - OCStackResult result = OCParsePayload(&payload, responseInfo->info.payload, - responseInfo->info.payloadSize); - - OCDiscoveryPayload* discover = (OCDiscoveryPayload*) payload; - // Discovered secure resource payload contains secure port; update the device - // with the secure port using endpoint. - if (result == OC_STACK_OK && discover) - { - if (updateDevice(object, discover->resources->port) == SP_RESULT_SUCCESS) - { - gStateManager |= SP_SEC_RES_INFO_DONE; - } - else - { - gStateManager |= SP_SEC_RES_INFO_ERROR; - } - OC_LOG(INFO, TAG, "Exiting ProvisionSecureResourceInfoHandler."); - } - - OCPayloadDestroy(payload); - } - return true; - } - else - { - OC_LOG(ERROR, TAG, "Error in ProvisionSecureResourceInfoHandler."); - gStateManager |= SP_SEC_RES_INFO_ERROR; - return false; - } - } - return false; -} - -/** - * Response handler ownership transfer. - * - * @param[in] object Remote endpoint object - * @param[in] requestInfo Datastructure containing request information. - * @return true is CA token matches request token, false otherwise. - */ -static bool OwnerShipTransferModeHandler(const CAEndpoint_t *object, - const CAResponseInfo_t *responseInfo) -{ - if ((gStateManager & SP_UP_OWN_TR_METH_STARTED) && gToken) - { - // response handler for ownership tranfer - OC_LOG(INFO, TAG, "Inside OwnerShipTransferModeHandler."); - if (memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength) == 0) - { - OC_LOG_V(DEBUG, TAG, "Response result for OwnerShipTransferMode: %d", responseInfo->result); - if (CA_SUCCESS == responseInfo->result) - { - gStateManager |= SP_UP_OWN_TR_METH_DONE; - OC_LOG(INFO, TAG, "Exiting OwnerShipTransferModeHandler."); - } - else - { - gStateManager |= SP_UP_OWN_TR_METH_ERROR; - OC_LOG(ERROR, TAG, "Error in OwnerShipTransferModeHandler."); - } - return true; - } - } - return false; -} - -/** - * Response handler list methods. - * - * @param[in] object Remote endpoint object - * @param[in] requestInfo Datastructure containing request information. - * @return true is CA token matches request token, false otherwise. - */ -static bool ListMethodsHandler(const CAEndpoint_t *object, - const CAResponseInfo_t *responseInfo) -{ - if ((gStateManager & SP_LIST_METHODS_STARTED) && gToken) - { - OC_LOG(INFO, TAG, "Inside ListMethodsHandler."); - if (memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength) == 0) - { - OC_LOG_V(DEBUG, TAG, "Response result for ListMethodsHandler: %d", responseInfo->result); - if (CA_SUCCESS == responseInfo->result) - { - OC_LOG_V (DEBUG, TAG, "Response Payload: %s", responseInfo->info.payload); - // Temp logic to trim oc attribute from json - // JSONToPstatBin should handle OC in JSON. - if (NULL == responseInfo->info.payload) - { - OC_LOG(ERROR, TAG, "response payload is null."); - gStateManager |= SP_LIST_METHODS_ERROR; - return true; - } - - OCPayload* payload = NULL; - OCStackResult result = OCParsePayload(&payload, responseInfo->info.payload, - responseInfo->info.payloadSize); - - OicSecPstat_t *pstat = NULL; - - if(result == OC_STACK_OK && payload->type == PAYLOAD_TYPE_SECURITY) - { - pstat = JSONToPstatBin(((OCSecurityPayload*)payload)->securityData); - } - - OCPayloadDestroy(payload); - - if (NULL == pstat) - { - OC_LOG(ERROR, TAG, "Error while converting json to pstat bin"); - gStateManager |= SP_LIST_METHODS_ERROR; - return true; - } - DeletePstatBinData(gPstat); - - gPstat = pstat; - gStateManager |= SP_LIST_METHODS_DONE; - - OC_LOG(INFO, TAG, "Exiting ListMethodsHandler."); - } - return true; - } - } - return false; -} - -/** - * Response handler for update operation mode. - * - * @param[in] object Remote endpoint object - * @param[in] requestInfo Datastructure containing request information. - * @return true is CA token matches request token, false otherwise. - */ -static bool OperationModeUpdateHandler(const CAEndpoint_t *object, - const CAResponseInfo_t *responseInfo) -{ - if ((gStateManager & SP_UPDATE_OP_MODE_STARTED) && gToken) - { - if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength)) - { - OC_LOG(INFO, TAG, "Inside OperationModeUpdateHandler."); - OC_LOG_V(DEBUG, TAG, "Response result for OperationModeUpdateHandler: %d", responseInfo->result); - if (CA_SUCCESS == responseInfo->result) - { - gStateManager |= SP_UPDATE_OP_MODE_DONE; - OC_LOG(INFO, TAG, "Exiting OperationModeUpdateHandler."); - } - else - { - gStateManager |= SP_UPDATE_OP_MODE_ERROR; - OC_LOG(ERROR, TAG, "Error in OperationModeUpdateHandler."); - } - return true; - } - } - return false; -} - -/** - * Response handler for ownership transfer. - * - * @param[in] object Remote endpoint object - * @param[in] requestInfo Datastructure containing request information. - * @return true is CA token matches request token, false otherwise. - */ -static bool OwnerShipUpdateHandler(const CAEndpoint_t *object, - const CAResponseInfo_t *responseInfo) -{ - if ((gStateManager & SP_UPDATE_OWNER_STARTED) && gToken) - { - // response handler for ownership tranfer - if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength)) - { - OC_LOG(INFO, TAG, "Inside OwnerShipUpdateHandler."); - OC_LOG_V(DEBUG, TAG, "Response result for OwnerShipUpdateHandler: %d", responseInfo->result); - if (CA_SUCCESS == responseInfo->result) - { - gStateManager |= SP_UPDATE_OWNER_DONE; - OC_LOG(INFO, TAG, "Exiting OwnerShipUpdateHandler."); - } - else - { - gStateManager |= SP_UPDATE_OWNER_ERROR; - OC_LOG(ERROR, TAG, "Error in OwnerShipUpdateHandler."); - } - return true; - } - } - return false; -} - -/** - * Response handler for ACL provisioning. - * - * @param[in] object Remote endpoint object - * @param[in] requestInfo Datastructure containing request information. - * @return true is CA token matches request token, false otherwise. - */ -static bool ACLProvisioningHandler(const CAEndpoint_t *object, - const CAResponseInfo_t *responseInfo) -{ - if ((gStateManager & SP_PROV_ACL_STARTED) && gToken) - { - - // response handler for ACL provisioning. - if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength)) - { - OC_LOG(INFO, TAG, "Inside ACLProvisioningHandler."); - OC_LOG_V(DEBUG, TAG, "Response result for ACLProvisioningHandler: %d", responseInfo->result); - if (CA_CREATED == responseInfo->result) - { - OC_LOG(INFO, TAG, "Exiting ACLProvisioningHandler."); - gStateManager |= SP_PROV_ACL_DONE; - } - else - { - OC_LOG(ERROR, TAG, "Error in ACLProvisioningHandler."); - gStateManager |= SP_PROV_ACL_ERROR; - } - return true; - } - } - return false; -} - -/** - * Response handler for provisioning finalization. - * - * @param[in] object Remote endpoint object - * @param[in] requestInfo Datastructure containing request information. - * @return true is CA token matches request token, false otherwise. - */ -static bool FinalizeProvisioningHandler(const CAEndpoint_t *object, - const CAResponseInfo_t *responseInfo) -{ - if ((gStateManager & SP_UP_HASH_STARTED) && gToken) - { - // response handler for finalize provisioning. - if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength)) - { - OC_LOG(INFO, TAG, "Inside FinalizeProvisioningHandler."); - OC_LOG_V(DEBUG, TAG, "Response result for FinalizeProvisioningHandler: %d", responseInfo->result); - if (CA_SUCCESS == responseInfo->result) - { - gStateManager |= SP_UP_HASH_DONE; - OC_LOG(INFO, TAG, "Exiting FinalizeProvisioningHandler."); - } - else - { - gStateManager |= SP_UP_HASH_ERROR; - OC_LOG(ERROR, TAG, "Error in FinalizeProvisioningHandler."); - } - return true; - } - } - return false; -} - -/** - * Response handler for Credential provisioning. - * - * @param[in] object Remote endpoint object - * @param[in] requestInfo Datastructure containing request information. - * @return true is CA token matches request token, false otherwise. - */ -static bool CredProvisioningHandler(const CAEndpoint_t *object, - const CAResponseInfo_t *responseInfo) -{ - if ((gStateManager & SP_PROV_CRED_STARTED) && gToken) - { - // response handler for CRED provisioning. - OC_LOG(INFO, TAG, "Inside CredProvisioningHandler."); - OC_LOG_V(DEBUG, TAG, "Response result for CredProvisioningHandler: %d", responseInfo->result); - if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength)) - { - if (CA_CREATED == responseInfo->result) - { - gStateManager |= SP_PROV_CRED_DONE; - OC_LOG(INFO, TAG, "Exiting CredProvisioningHandler."); - } - else - { - gStateManager |= SP_PROV_CRED_ERROR; - OC_LOG(ERROR, TAG, "Error in CredProvisioningHandler."); - } - return true; - } - } - return false; -} - -/** - * Response Handler - * - * @param[in] object Remote endpoint object - * @param[in] responseInfo Datastructure containing response information. - * @return true if received response is for provisioning API false otherwise. - */ -static bool SPResponseHandler(const CAEndpoint_t *object, - const CAResponseInfo_t *responseInfo) -{ - bool isProvResponse = false; - if ((NULL != responseInfo) && (NULL != responseInfo->info.token)) - { - isProvResponse = handler(object, responseInfo); - } - return isProvResponse; -} - -/** - * Function to find the resources using multicast discovery. - * - * @param[in] timeout timeout in secs - * @return SP_RESULT_SUCCESS normally otherwise error code. - */ -static SPResult findResource(unsigned short timeout) -{ - static char DOXM_OWNED_FALSE_MULTICAST_QUERY[] = "/oic/sec/doxm?Owned=FALSE"; - CAResult_t res = CAGenerateToken(&gToken, CA_MAX_TOKEN_LEN); - if (CA_STATUS_OK != res) - { - OC_LOG(ERROR, TAG, "Error while generating token."); - return SP_RESULT_INTERNAL_ERROR; - } - - CAEndpoint_t endpoint = {}; - - // Only IP is supported currently for provisioning and ownership transfer - endpoint.adapter = CA_ADAPTER_IP; - endpoint.flags = CA_IPV4 | CA_IPV6 | CA_SCOPE_LINK; - - CAMessageType_t msgType = CA_MSG_NONCONFIRM; - CAInfo_t requestData = { 0 }; - requestData.token = gToken; - requestData.tokenLength = CA_MAX_TOKEN_LEN; - requestData.payload = NULL; - requestData.payloadSize = 0; - requestData.type = msgType; - requestData.resourceUri = DOXM_OWNED_FALSE_MULTICAST_QUERY; - CARequestInfo_t requestInfo = { 0 }; - requestInfo.method = CA_GET; - requestInfo.info = requestData; - requestInfo.isMulticast = true; - res = CASendRequest(&endpoint, &requestInfo); - - handler = &ProvisionDiscoveryHandler; - gStateManager |= SP_DISCOVERY_STARTED; - if (CA_STATUS_OK != res) - { - OC_LOG(ERROR, TAG, "Error while finding resource."); - return convertCAResultToSPResult(res); - } - else - { - OC_LOG(INFO, TAG, "Discovery Request sent successfully"); - } - return SPWaitForResponse(timeout); -} - -/** - * Function to get the secure resource info. - * - * @param[in] devAddr Device address for the destination - * @param[in] timeout timeout in secs - * @return SP_RESULT_SUCCESS normally otherwise error code. - */ -static SPResult getSecureResourceInfo(OCDevAddr *devAddr, unsigned short timeout) -{ - char OIC_UNICAST_SEC_QUERY[] = "/oic/res?rt=oic.sec.doxm"; - CAResult_t res = CAGenerateToken(&gToken, CA_MAX_TOKEN_LEN); - if (CA_STATUS_OK != res) - { - OC_LOG(ERROR, TAG, "Error while generating token."); - return SP_RESULT_INTERNAL_ERROR; - } - - CAInfo_t requestData = {}; - requestData.token = gToken; - requestData.tokenLength = CA_MAX_TOKEN_LEN; - requestData.payload = NULL; - requestData.payloadSize = 0; - requestData.type = CA_MSG_NONCONFIRM; - requestData.resourceUri = OIC_UNICAST_SEC_QUERY; - CARequestInfo_t requestInfo = { 0 }; - requestInfo.method = CA_GET; - requestInfo.info = requestData; - requestInfo.isMulticast = false; - handler = &ProvisionSecureResourceInfoHandler; - res = CASendRequest((CAEndpoint_t*)devAddr, &requestInfo); - - gStateManager |= SP_SEC_RES_INFO_STARTED; - if (CA_STATUS_OK != res) - { - OC_LOG(ERROR, TAG, "Error while finding secure resource."); - return convertCAResultToSPResult(res); - } - else - { - OC_LOG(INFO, TAG, "Secure resource info request sent successfully"); - } - return SPWaitForResponse(timeout); -} - -/** - * Function to update the operation mode. As per the spec. Operation mode in client driven - * single service provisioning it will be updated to 0x3 - * - * @param[in] timeout timeout for operation. - * @param[in] deviceInfo Device Info. - * @return SP_SUCCESS on success - */ -static SPResult updateOwnerTransferModeToResource(unsigned short timeout, - SPTargetDeviceInfo_t *deviceInfo, OicSecOxm_t selectedMethod) -{ - SPResult res = SP_RESULT_INTERNAL_ERROR; - - deviceInfo->doxm->oxmSel = selectedMethod; - char *payload = BinToDoxmJSON(deviceInfo->doxm); - if (NULL == payload) - { - OC_LOG(ERROR, TAG, "Error while converting bin to json"); - return SP_RESULT_INTERNAL_ERROR; - } - OC_LOG_V(DEBUG, TAG, "Payload: %s", payload); - int payloadLen = strlen(payload); - - handler = &OwnerShipTransferModeHandler; - gStateManager |= SP_UP_OWN_TR_METH_STARTED; - - CAResult_t result = sendCARequest(CA_PUT, - &deviceInfo->endpoint, - OC_DEFAULT_FLAGS, - OIC_RSRC_DOXM_URI, - payload, payloadLen); - OICFree(payload); - if (CA_STATUS_OK != result) - { - OC_LOG(ERROR, TAG, "Error while sending request."); - CADestroyToken(gToken); - return convertCAResultToSPResult(result); - } - res = SPTimeout(timeout, SP_UP_OWN_TR_METH_DONE); - if (SP_RESULT_SUCCESS != res) - { - OC_LOG(ERROR, TAG, "Internal Error occured"); - CADestroyToken(gToken); - return SP_RESULT_TIMEOUT; - } - CADestroyToken(gToken); - return SP_RESULT_SUCCESS; -} - -/** - * Function to send request to resource to get its pstat resource information. - * - * @param[in] timeout timeout for operation. - * @param[in] deviceInfo Device Info. - * @return SP_SUCCESS on success - */ -static SPResult getProvisioningStatusResource(unsigned short timeout, - SPTargetDeviceInfo_t *deviceInfo) -{ - handler = &ListMethodsHandler; - gStateManager |= SP_LIST_METHODS_STARTED; - - CAResult_t result = sendCARequest(CA_GET, - &deviceInfo->endpoint, - OC_DEFAULT_FLAGS, - OIC_RSRC_PSTAT_URI, - NULL, 0); - if (CA_STATUS_OK != result) - { - OC_LOG(ERROR, TAG, "Failure while sending request."); - CADestroyToken(gToken); - return convertCAResultToSPResult(result); - } - SPResult res = SPTimeout(timeout, SP_LIST_METHODS_DONE); - if (SP_RESULT_SUCCESS != res) - { - OC_LOG(ERROR, TAG, "Timeout while getting method list."); - CADestroyToken(gToken); - return SP_RESULT_TIMEOUT; - } - if (gStateManager && SP_LIST_METHODS_DONE) - { - deviceInfo->pstat = gPstat; - CADestroyToken(gToken); - OC_LOG(DEBUG, TAG, "getProvisioningStatusResource completed."); - return SP_RESULT_SUCCESS; - } - CADestroyToken(gToken); - return SP_RESULT_INTERNAL_ERROR; -} - -/** - * Function to update the operation mode. As per the spec. Operation mode in client driven - * single service provisioning it will be updated to 0x3 - * - * @param[in] timeout timeout for operation. - * @param[in] deviceInfo Device Info. - * @return SP_SUCCESS on success - */ -static SPResult updateOperationMode(unsigned short timeout, - SPTargetDeviceInfo_t *deviceInfo, - OicSecDpom_t selectedOperationMode) -{ - - SPResult res = SP_RESULT_INTERNAL_ERROR; - - deviceInfo->pstat->om = selectedOperationMode; - - char *payloadBuffer = BinToPstatJSON(deviceInfo->pstat); - if (NULL == payloadBuffer) - { - OC_LOG(ERROR, TAG, "Error while converting pstat bin to json"); - return SP_RESULT_INTERNAL_ERROR; - } - - size_t payloadLen = strlen(payloadBuffer); - handler = &OperationModeUpdateHandler; - gStateManager |= SP_UPDATE_OP_MODE_STARTED; - - CAResult_t result = sendCARequest(CA_PUT, - &deviceInfo->endpoint, - OC_DEFAULT_FLAGS, - OIC_RSRC_PSTAT_URI, - payloadBuffer, payloadLen); - if (CA_STATUS_OK != result) - { - OC_LOG(ERROR, TAG, "Error while sending request."); - CADestroyToken(gToken); - OICFree(payloadBuffer); - return convertCAResultToSPResult(result); - } - res = SPTimeout(timeout, SP_UPDATE_OP_MODE_DONE); - if (SP_RESULT_SUCCESS != res) - { - OC_LOG(ERROR, TAG, "Internal Error occured"); - CADestroyToken(gToken); - OICFree(payloadBuffer); - return SP_RESULT_TIMEOUT; - } - CADestroyToken(gToken); - OICFree(payloadBuffer); - - if (gStateManager & SP_UPDATE_OP_MODE_DONE) - { - return SP_RESULT_SUCCESS; - } - return SP_RESULT_INTERNAL_ERROR; -} - -/** - * Function to initiate DTLS handshake. - * - * @param[in] deviceInfo Provisioning context - * @return SP_SUCCESS on success - */ -static SPResult initiateDtlsHandshake(const CAEndpoint_t *endpoint) -{ - CAResult_t caresult = CAEnableAnonECDHCipherSuite(true); - if (CA_STATUS_OK != caresult) - { - OC_LOG_V(ERROR, TAG, "Unable to enable anon cipher suite"); - return SP_RESULT_INTERNAL_ERROR; - } - OC_LOG(INFO, TAG, "Anonymous cipher suite Enabled."); - - caresult = CAInitiateHandshake(endpoint); - if (CA_STATUS_OK != caresult) - { - OC_LOG_V(ERROR, TAG, "DTLS handshake failure."); - } - - return SP_RESULT_SUCCESS; -} - -/** - * Function to send ownerShip info. This function would update Owned as true and - * owner as UUID for provisioning tool - * - * @param[in] timeout timeout value for the operation. - * @param[in] deviceInfo provisioning context. - * @return SP_SUCCESS on success - */ -static SPResult sendOwnershipInfo(unsigned short timeout, - SPTargetDeviceInfo_t *selectedDeviceInfo) -{ - OicUuid_t provTooldeviceID = {}; - - if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID)) - { - OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID"); - return SP_RESULT_INTERNAL_ERROR; - } - memcpy(selectedDeviceInfo->doxm->owner.id, provTooldeviceID.id , UUID_LENGTH); - - selectedDeviceInfo->doxm->owned = true; - - char *payloadBuffer = BinToDoxmJSON(selectedDeviceInfo->doxm); - if (NULL == payloadBuffer) - { - OC_LOG(ERROR, TAG, "Error while converting doxm bin to json"); - return SP_RESULT_INTERNAL_ERROR; - } - int payloadLen = strlen(payloadBuffer); - - handler = &OwnerShipUpdateHandler; - gStateManager |= SP_UPDATE_OWNER_STARTED; - - CAResult_t result = sendCARequest(CA_PUT, - &selectedDeviceInfo->endpoint, - OC_FLAG_SECURE, - OIC_RSRC_DOXM_URI, - payloadBuffer, payloadLen); - if (CA_STATUS_OK != result) - { - OC_LOG(ERROR, TAG, "Error while sending request."); - CADestroyToken(gToken); - OICFree(payloadBuffer); - return convertCAResultToSPResult(result); - } - SPResult res = SPTimeout(timeout, SP_UPDATE_OWNER_DONE); - if (SP_RESULT_SUCCESS != res) - { - OC_LOG(ERROR, TAG, "Internal Error occured"); - CADestroyToken(gToken); - OICFree(payloadBuffer); - return SP_RESULT_TIMEOUT; - } - CADestroyToken(gToken); - OICFree(payloadBuffer); - return SP_RESULT_SUCCESS; -} - -/** - * Function to save ownerPSK at provisioning tool end. - * - * @return SP_SUCCESS on success - */ -static SPResult saveOwnerPSK(SPTargetDeviceInfo_t *selectedDeviceInfo) -{ - SPResult result = SP_RESULT_INTERNAL_ERROR; - - CAEndpoint_t endpoint = {}; - OICStrcpy(endpoint.addr, MAX_ADDR_STR_SIZE_CA, selectedDeviceInfo->endpoint.addr); - endpoint.port = selectedDeviceInfo->securePort; - - OicUuid_t provTooldeviceID = {}; - if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID)) - { - OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID"); - return result; - } - - uint8_t ownerPSK[OWNER_PSK_LENGTH_128] = {}; - - //Generating OwnerPSK - CAResult_t pskRet = CAGenerateOwnerPSK(&endpoint, - (uint8_t *)OXM_JUST_WORKS, strlen(OXM_JUST_WORKS), provTooldeviceID.id, - sizeof(provTooldeviceID.id), selectedDeviceInfo->doxm->deviceID.id, - sizeof(selectedDeviceInfo->doxm->deviceID.id), ownerPSK, - OWNER_PSK_LENGTH_128); - - if (CA_STATUS_OK == pskRet) - { - OC_LOG(INFO, TAG,"ownerPSK dump:\n"); - OC_LOG_BUFFER(INFO, TAG,ownerPSK, OWNER_PSK_LENGTH_128); - //Generating new credential for provisioning tool - size_t ownLen = 1; - uint32_t outLen = 0; - - char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(ownerPSK)) + 1] = {}; - B64Result b64Ret = b64Encode(ownerPSK, sizeof(ownerPSK), base64Buff, sizeof(base64Buff), - &outLen); - if (B64_OK == b64Ret) - { - OicSecCred_t *cred = GenerateCredential(&selectedDeviceInfo->doxm->deviceID, - SYMMETRIC_PAIR_WISE_KEY, NULL, - base64Buff, ownLen, &provTooldeviceID); - if (cred) - { - //Update the SVR database. - if (OC_STACK_OK == AddCredential(cred)) - { - result = SP_RESULT_SUCCESS; - } - else - { - OC_LOG(ERROR, TAG, "AddCredential failed"); - } - } - else - { - OC_LOG(ERROR, TAG, "GenerateCredential failed"); - } - } - else - { - OC_LOG(ERROR, TAG, "b64Encode failed"); - } - } - else - { - OC_LOG(ERROR, TAG, "CAGenerateOwnerPSK failed"); - } - return result; -} - -/** - * Function to select operation mode.This function will return most secure common operation mode. - * - * @param[out] selectedMode selected operation mode - * @return SP_SUCCESS on success - */ -static void selectOperationMode(const SPTargetDeviceInfo_t *selectedDeviceInfo, - OicSecDpom_t **selectedMode) -{ - int i = 0; - int j = 0; - while (i < gNumOfProvisioningMethodsPT && j < selectedDeviceInfo->pstat->smLen) - { - if (gProvisioningToolCapability[i] < selectedDeviceInfo->pstat->sm[j]) - { - i++; - } - else if (selectedDeviceInfo->pstat->sm[j] < gProvisioningToolCapability[i]) - { - j++; - } - else /* if gProvisioningToolCapability[i] == deviceSupportedMethods[j] */ - { - *selectedMode = &(gProvisioningToolCapability[j]); - break; - } - } -} - -/** - * Function to perform onwership tranfer based to ownership transfer mode. - * - * @param[in] timeout timeout in secs to perform operation. 0 timeout means - function will wait forever. - * @param[in] selectedDeviceInfo instance of SPTargetDeviceInfo_t structure. - * @return SP_SUCCESS on success - */ -static SPResult doOwnerShipTransfer(unsigned short timeout, - SPTargetDeviceInfo_t *selectedDeviceInfo) -{ - OicSecDpom_t *selectedOperationMode = NULL; - selectOperationMode(selectedDeviceInfo, &selectedOperationMode); - - SPResult res = updateOperationMode(timeout, selectedDeviceInfo, *selectedOperationMode); - if (SP_RESULT_SUCCESS != res) - { - OC_LOG(ERROR, TAG, "Error while updating operation mode."); - return SP_RESULT_INTERNAL_ERROR; - } - if (*selectedOperationMode == SINGLE_SERVICE_CLIENT_DRIVEN) - { - CAEndpoint_t endpoint = {0}; - OICStrcpy(endpoint.addr, MAX_ADDR_STR_SIZE_CA, selectedDeviceInfo->endpoint.addr); - endpoint.port = selectedDeviceInfo->securePort; - - res = initiateDtlsHandshake(&endpoint); - if (SP_RESULT_SUCCESS == res) - { - selectedDeviceInfo->endpoint.port = selectedDeviceInfo->securePort; - res = sendOwnershipInfo(timeout, selectedDeviceInfo); - if (SP_RESULT_SUCCESS != res) - { - OC_LOG(ERROR, TAG, "Error while updating ownership information."); - } - res = saveOwnerPSK(selectedDeviceInfo); - - //Close temporal DTLS session - if(CA_STATUS_OK != CACloseDtlsSession(&endpoint)) - { - OC_LOG(WARNING, TAG, "doOwnerShipTransfer() : failed to close the dtls session"); - } - } - else - { - OC_LOG(ERROR, TAG, "Error during initiating DTLS handshake."); - } - - //Disable Anonymous ECDH cipher suite before leaving this method - if(CA_STATUS_OK != CAEnableAnonECDHCipherSuite(false)) - { - OC_LOG(WARNING, TAG, "doOwnerShipTransfer() : failed to disable Anon ECDH cipher suite"); - } - } - return (res != SP_RESULT_SUCCESS) ? SP_RESULT_INTERNAL_ERROR : SP_RESULT_SUCCESS; - -} -/** - * The function is responsible for discovering secure resources(such as, /oic/sec/doxm etc) with - * OC_EXPLICIT_DISCOVERABLE on a OIC device which needs to be provisioned. - * - * @param[in] timeout Timeout in seconds, value till which function will listen to responses from - * client before returning the list of devices. - * @param[in] selectedDeviceInfo Device information. - * @return SP_SUCCESS in case of success and other value otherwise. - */ -static SPResult discoverSecureResource(unsigned short timeout, - SPTargetDeviceInfo_t *selectedDeviceInfo) -{ - if (NULL == selectedDeviceInfo) - { - OC_LOG(ERROR, TAG, "List is not null can cause memory leak"); - return SP_RESULT_INVALID_PARAM; - } - SPResult smResponse = SP_RESULT_SUCCESS; - smResponse = getSecureResourceInfo(&selectedDeviceInfo->endpoint, timeout); - if (SP_RESULT_SUCCESS != smResponse) - { - return SP_RESULT_INTERNAL_ERROR; - } - if (gStateManager & SP_SEC_RES_INFO_DONE) - { - if (gStateManager & SP_SEC_RES_INFO_ERROR) - { - return SP_RESULT_INTERNAL_ERROR; - } - return SP_RESULT_SUCCESS; - } - return SP_RESULT_INTERNAL_ERROR; -} - -/** - * Function to provision credentials to specific device. - * - * @param[in] timeout timeout in secs to perform operation. 0 timeout means function will - wait till success. - * @param[in] cred credential to be provisioned. - * @param[in] deviceInfo Instance of SPDevInfo_t structure. Representing a selected device for - provisioning. - * @return SP_SUCCESS on success - */ -SPResult provisionCredentials(unsigned short timeout, const OicSecCred_t *cred, - const SPDevInfo_t *deviceInfo) -{ - char *credJson = NULL; - credJson = BinToCredJSON(cred); - if (NULL == credJson) - { - OC_LOG(ERROR, TAG, "Memory allocation problem"); - return SP_RESULT_MEM_ALLOCATION_FAIL; - } - - int payloadLen = strlen(credJson); - handler = &CredProvisioningHandler; - gStateManager |= SP_PROV_CRED_STARTED; - - CAResult_t result = sendCARequest(CA_POST, - &deviceInfo->endpoint, - OC_FLAG_SECURE, - OIC_RSRC_CRED_URI, - credJson, payloadLen); - OICFree(credJson); - if (CA_STATUS_OK != result) - { - OC_LOG(ERROR, TAG, "Internal Error while sending Credentials."); - CADestroyToken(gToken); - return convertCAResultToSPResult(result); - } - - SPResult res = SPTimeout(timeout, SP_PROV_CRED_DONE); - if (SP_RESULT_SUCCESS != res) - { - OC_LOG(ERROR, TAG, "Internal Error occured"); - CADestroyToken(gToken); - return SP_RESULT_TIMEOUT; - } - CADestroyToken(gToken); - gStateManager = 0; - return res; -} - -SPResult SPProvisioningDiscovery(unsigned short timeout, - SPTargetDeviceInfo_t **list) -{ - if (NULL != *list) - { - OC_LOG(ERROR, TAG, "List is not null can cause memory leak"); - return SP_RESULT_INVALID_PARAM; - } - SRMRegisterProvisioningResponseHandler(SPResponseHandler); - SPResult smResponse = SP_RESULT_SUCCESS; - smResponse = findResource(timeout); - if (SP_RESULT_SUCCESS != smResponse) - { - return SP_RESULT_INTERNAL_ERROR; - } - if (gStateManager & SP_DISCOVERY_DONE) - { - if (gStateManager & SP_DISCOVERY_ERROR) - { - return SP_RESULT_INTERNAL_ERROR; - } - *list = gStartOfDiscoveredDevices; - return SP_RESULT_SUCCESS; - } - return SP_RESULT_INTERNAL_ERROR; -} - -SPResult SPInitProvisionContext(unsigned short timeout, - SPTargetDeviceInfo_t *selectedDeviceInfo) -{ - if (NULL == selectedDeviceInfo ) - { - return SP_RESULT_INVALID_PARAM; - } - SPResult res = SP_RESULT_SUCCESS; - - //Discover secure resource and update the device info. - res = discoverSecureResource(timeout, selectedDeviceInfo); - if (SP_RESULT_SUCCESS != res) - { - OC_LOG(ERROR, TAG, "Error in discoverSecureResource"); - return SP_RESULT_INTERNAL_ERROR; - } - - OicSecOxm_t selectedMethod = OIC_JUST_WORKS; - - selectProvisioningMethod(selectedDeviceInfo->doxm->oxm, selectedDeviceInfo->doxm->oxmLen, - &selectedMethod); - OC_LOG_V(DEBUG, TAG, "Selected method %d:", selectedMethod); - res = updateOwnerTransferModeToResource(timeout, selectedDeviceInfo, selectedMethod); - - if (SP_RESULT_SUCCESS != res) - { - OC_LOG(ERROR, TAG, "Error while updating owner transfer mode."); - return SP_RESULT_INTERNAL_ERROR; - } - - res = getProvisioningStatusResource(timeout, selectedDeviceInfo); - if (SP_RESULT_SUCCESS != res) - { - OC_LOG(ERROR, TAG, "Error while getting provisioning status."); - return SP_RESULT_INTERNAL_ERROR; - } - OC_LOG(INFO, TAG, "Starting ownership transfer"); - return doOwnerShipTransfer(timeout, selectedDeviceInfo); - -} - -SPResult SPProvisionACL(unsigned short timeout, const SPTargetDeviceInfo_t *selectedDeviceInfo, - OicSecAcl_t *acl) -{ - if (NULL == selectedDeviceInfo || NULL == acl) - { - return SP_RESULT_INVALID_PARAM; - } - char *aclString = NULL; - aclString = BinToAclJSON(acl); - - if (NULL == aclString) - { - OC_LOG(ERROR, TAG, "Memory allocation problem"); - return SP_RESULT_MEM_ALLOCATION_FAIL; - } - - int payloadLen = strlen(aclString); - handler = &ACLProvisioningHandler; - gStateManager |= SP_PROV_ACL_STARTED; - - CAResult_t result = sendCARequest(CA_POST, - &selectedDeviceInfo->endpoint, - OC_FLAG_SECURE, - OIC_RSRC_ACL_URI, - aclString, payloadLen); - OICFree(aclString); - if (CA_STATUS_OK != result) - { - OC_LOG(ERROR, TAG, "Internal Error while sending ACL."); - CADestroyToken(gToken); - return convertCAResultToSPResult(result); - } - - SPResult res = SPTimeout(timeout, SP_PROV_ACL_DONE); - if (SP_RESULT_SUCCESS != res) - { - OC_LOG(ERROR, TAG, "Internal Error occured"); - CADestroyToken(gToken); - return SP_RESULT_TIMEOUT; - } - CADestroyToken(gToken); - return res; -} - -SPResult SPProvisionCredentials(unsigned short timeout, OicSecCredType_t type, - const SPDevInfo_t *pDevList) -{ - if (NULL == pDevList) - { - return SP_RESULT_INVALID_PARAM; - } - const SPDevInfo_t *curr = pDevList; - OicUuid_t provTooldeviceID = {}; - if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID)) - { - OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID"); - return SP_RESULT_INTERNAL_ERROR; - } - //TODO Need to support other key types in future. - switch (type) - { - case SYMMETRIC_PAIR_WISE_KEY: - { - if (NULL == curr->next) - { - return SP_RESULT_INVALID_PARAM; - } - // Devices if present after second node will not be considered. - // in scenario-2. 2 devices are provisioned with credentials. - const SPDevInfo_t *firstDevice = curr; - const SPDevInfo_t *secondDevice = curr->next; - - OicSecCred_t *firstCred = NULL; - OicSecCred_t *secondCred = NULL; - - SPResult res = SPGeneratePairWiseCredentials(type, &provTooldeviceID, - &firstDevice->deviceId, &secondDevice->deviceId, - &firstCred, &secondCred); - if (res != SP_RESULT_SUCCESS) - { - OC_LOG(ERROR, TAG, "error while generating credentials"); - return SP_RESULT_INTERNAL_ERROR; - } - res = provisionCredentials(timeout, firstCred, firstDevice); - if (SP_RESULT_SUCCESS != res) - { - OC_LOG_V(ERROR, TAG, "Credentials provisioning Error"); - DeleteCredList(firstCred); - DeleteCredList(secondCred); - return SP_RESULT_INTERNAL_ERROR; - } - res = provisionCredentials(timeout, secondCred, secondDevice); - if (SP_RESULT_SUCCESS != res) - { - OC_LOG_V(ERROR, TAG, "Credentials provisioning Error"); - DeleteCredList(firstCred); - DeleteCredList(secondCred); - return SP_RESULT_INTERNAL_ERROR; - } - DeleteCredList(firstCred); - DeleteCredList(secondCred); - return SP_RESULT_SUCCESS; - } - default: - { - OC_LOG(ERROR, TAG, "Invalid option."); - return SP_RESULT_INVALID_PARAM; - } - return SP_RESULT_INTERNAL_ERROR; - } -} - -SPResult SPFinalizeProvisioning(unsigned short timeout, - SPTargetDeviceInfo_t *selectedDeviceInfo) -{ - // TODO - if (NULL == selectedDeviceInfo) - { - OC_LOG(ERROR, TAG, "Target device Info is NULL."); - return SP_RESULT_INVALID_PARAM; - } - - uint16_t aclHash = 0; // value for beachhead version. - selectedDeviceInfo->pstat->commitHash = aclHash; - selectedDeviceInfo->pstat->tm = NORMAL; - char *payloadBuffer = BinToPstatJSON(selectedDeviceInfo->pstat); - if (NULL == payloadBuffer) - { - OC_LOG(ERROR, TAG, "Error while converting pstat bin to json"); - return SP_RESULT_INTERNAL_ERROR; - } - int payloadLen = strlen(payloadBuffer); - - handler = &FinalizeProvisioningHandler; - gStateManager |= SP_UP_HASH_STARTED; - - CAResult_t result = sendCARequest(CA_PUT, - &selectedDeviceInfo->endpoint, - OC_FLAG_SECURE, - OIC_RSRC_PSTAT_URI, - payloadBuffer, payloadLen); - OICFree(payloadBuffer); - if (CA_STATUS_OK != result) - { - OC_LOG(ERROR, TAG, "Internal Error occured"); - CADestroyToken(gToken); - return convertCAResultToSPResult(result); - } - - SPResult res = SPTimeout(timeout, SP_UP_HASH_DONE); - if (SP_RESULT_SUCCESS != res) - { - OC_LOG(ERROR, TAG, "Internal Error occured"); - CADestroyToken(gToken); - return SP_RESULT_TIMEOUT; - } - - result = CACloseDtlsSession((CAEndpoint_t*)&selectedDeviceInfo->endpoint); - if (CA_STATUS_OK != result) - { - OC_LOG(WARNING, TAG, "Failed to close the DTLS session."); - } - - CADestroyToken(gToken); - gStateManager = 0; - gPstat = NULL; - return res; -} - -SPResult SPTerminateProvisioning() -{ - deleteList(); - return SP_RESULT_SUCCESS;; -} diff --git a/resource/csdk/security/provisioning/src/secureresourceprovider.c b/resource/csdk/security/provisioning/src/secureresourceprovider.c new file mode 100644 index 0000000..4ac8e32 --- /dev/null +++ b/resource/csdk/security/provisioning/src/secureresourceprovider.c @@ -0,0 +1,491 @@ +/* ***************************************************************** + * + * Copyright 2015 Samsung Electronics 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 +#include +#include +#include + +#include "ocprovisioningmanager.h" +#include "secureresourceprovider.h" +#include "logger.h" +#include "oic_malloc.h" +#include "aclresource.h" +#include "pstatresource.h" +#include "srmresourcestrings.h" +#include "credresource.h" +#include "doxmresource.h" +#include "credentialgenerator.h" +#include "cainterface.h" +#include "cJSON.h" +#include "pmtypes.h" +#include "pmutility.h" + +#define SRP_MAX_URI_LENGTH 512 +#define TAG "SRPAPI" + +/** + * Macro to verify argument is not equal to NULL. + * eg: VERIFY_NON_NULL(TAG, ptrData, ERROR,OC_STACK_ERROR); + */ +#define VERIFY_NON_NULL(tag, arg, logLevel, retValue) { if (NULL == (arg)) \ + { OC_LOG((logLevel), tag, (#arg " is NULL")); return retValue; } } + +/** + * Macro to verify success of operation. + * eg: VERIFY_SUCCESS(TAG, OC_STACK_OK == foo(), ERROR, OC_STACK_ERROR); + */ +#define VERIFY_SUCCESS(tag, op, logLevel, retValue) { if (!(op)) \ + {OC_LOG((logLevel), tag, (#op " failed!!")); return retValue;} } + +/** + * Structure to carry credential data to callback. + */ +typedef struct CredentialData CredentialData_t; +struct CredentialData +{ + void *ctx; /**< Pointer to user context.**/ + const OCProvisionDev_t *deviceInfo1; /**< Pointer to OCProvisionDev_t.**/ + const OCProvisionDev_t *deviceInfo2; /**< Pointer to OCProvisionDev_t.**/ + OicSecCred_t *credInfo; /**< Pointer to OicSecCred_t.**/ + OicSecCred_t *credInfoFirst; /**< Pointer to OicSecCred_t.**/ + OCProvisionResultCB resultCallback; /**< Pointer to result callback.**/ + OCProvisionResult_t *resArr; /**< Result array.**/ + int numOfResults; /**< Number of results in result array.**/ +}; + +/** + * Structure to carry ACL provision API data to callback. + */ +typedef struct ACLData ACLData_t; +struct ACLData +{ + void *ctx; /**< Pointer to user context.**/ + const OCProvisionDev_t *deviceInfo; /**< Pointer to PMDevInfo_t.**/ + OCProvisionResultCB resultCallback; /**< Pointer to result callback.**/ + OCProvisionResult_t *resArr; /**< Result array.**/ + int numOfResults; /**< Number of results in result array.**/ +}; + +/** + * Function prototype + */ +static OCStackResult provisionCredentials(const OicSecCred_t *cred, + const OCProvisionDev_t *deviceInfo, CredentialData_t *credData, + OCClientResponseHandler responseHandler); + + +/** + * Internal function to update result in result array. + */ +static void registerResultForCredProvisioning(CredentialData_t *credData, + OCStackResult stackresult, int cause) +{ + + OC_LOG_V(INFO,TAG,"value of credData->numOfResults is %d",credData->numOfResults); + if(1 == cause) + { + memcpy(credData->resArr[(credData->numOfResults)].deviceId.id, + credData->deviceInfo1->doxm->deviceID.id,UUID_LENGTH); + } + else + { + memcpy(credData->resArr[(credData->numOfResults)].deviceId.id, + credData->deviceInfo2->doxm->deviceID.id,UUID_LENGTH); + } + credData->resArr[(credData->numOfResults)].res = stackresult; + ++(credData->numOfResults); +} + +/** + * Callback handler for handling callback of provisioning device 2. + * + * @param[in] ctx ctx value passed to callback from calling function. + * @param[in] UNUSED handle to an invocation + * @param[in] clientResponse Response from queries to remote servers. + * @return OC_STACK_DELETE_TRANSACTION to delete the transaction + * and OC_STACK_KEEP_TRANSACTION to keep it. + */ +static OCStackApplicationResult provisionCredentialCB2(void *ctx, OCDoHandle UNUSED, + OCClientResponse *clientResponse) +{ + VERIFY_NON_NULL(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION); + CredentialData_t *credData = (CredentialData_t *) ctx; + (void)UNUSED; + + OCProvisionResultCB resultCallback = credData->resultCallback; + OC_LOG(INFO, TAG, "provisionCredentialCB2 called"); + if (clientResponse) + { + if(OC_STACK_RESOURCE_CREATED == clientResponse->result) + { + registerResultForCredProvisioning(credData, OC_STACK_RESOURCE_CREATED, 2); + ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults, + credData->resArr, + false); + OICFree(credData->resArr); + OICFree(credData); + return OC_STACK_DELETE_TRANSACTION; + } + + } + OC_LOG(INFO, TAG, "provisionCredentialCB2 received Null clientResponse"); + registerResultForCredProvisioning(credData, OC_STACK_ERROR, 2); + ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults, + credData->resArr, + true); + OICFree(credData->resArr); + OICFree(credData); + return OC_STACK_DELETE_TRANSACTION; +} + +/** + * Callback handler for handling callback of provisioning device 1. + * + * @param[in] ctx ctx value passed to callback from calling function. + * @param[in] UNUSED handle to an invocation + * @param[in] clientResponse Response from queries to remote servers. + * @return OC_STACK_DELETE_TRANSACTION to delete the transaction + * and OC_STACK_KEEP_TRANSACTION to keep it. + */ +static OCStackApplicationResult provisionCredentialCB1(void *ctx, OCDoHandle UNUSED, + OCClientResponse *clientResponse) +{ + VERIFY_NON_NULL(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION); + (void)UNUSED; + CredentialData_t* credData = (CredentialData_t*) ctx; + OICFree(credData->credInfoFirst); + const OCProvisionDev_t *deviceInfo = credData->deviceInfo2; + OicSecCred_t *credInfo = credData->credInfo; + const OCProvisionResultCB resultCallback = credData->resultCallback; + if (clientResponse) + { + if (OC_STACK_RESOURCE_CREATED == clientResponse->result) + { + // send credentials to second device + registerResultForCredProvisioning(credData, OC_STACK_RESOURCE_CREATED,1); + OCStackResult res = provisionCredentials(credInfo, deviceInfo, credData, + provisionCredentialCB2); + DeleteCredList(credInfo); + if (OC_STACK_OK != res) + { + registerResultForCredProvisioning(credData, res,2); + ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults, + credData->resArr, + true); + OICFree(credData->resArr); + OICFree(credData); + credData = NULL; + } + } + else + { + registerResultForCredProvisioning(credData, OC_STACK_ERROR,1); + ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults, + credData->resArr, + true); + OICFree(credData->resArr); + OICFree(credData); + credData = NULL; + } + } + else + { + OC_LOG(INFO, TAG, "provisionCredentialCB received Null clientResponse for first device"); + registerResultForCredProvisioning(credData, OC_STACK_ERROR,1); + ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults, + credData->resArr, + true); + DeleteCredList(credInfo); + OICFree(credData->resArr); + OICFree(credData); + credData = NULL; + } + return OC_STACK_DELETE_TRANSACTION; +} + + + +/** + * Internal function for handling credential generation and sending credential to resource server. + * + * @param[in] cred Instance of cred resource. + * @param[in] deviceInfo information about device to which credential is to be provisioned. + * @param[in] responseHandler callbak called by OC stack when request API receives response. + * @return OC_STACK_OK in case of success and other value otherwise. + */ +static OCStackResult provisionCredentials(const OicSecCred_t *cred, + const OCProvisionDev_t *deviceInfo, CredentialData_t *credData, + OCClientResponseHandler responseHandler) +{ + OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload)); + if(!secPayload) + { + OC_LOG(ERROR, TAG, "Failed to memory allocation"); + return OC_STACK_NO_MEMORY; + } + secPayload->base.type = PAYLOAD_TYPE_SECURITY; + secPayload->securityData = BinToCredJSON(cred); + if(NULL == secPayload->securityData) + { + OICFree(secPayload); + OC_LOG(ERROR, TAG, "Failed to BinToCredJSON"); + return OC_STACK_NO_MEMORY; + } + + OC_LOG_V(INFO, TAG, "Credential for provisioning : %s",secPayload->securityData); + char uri[SRP_MAX_URI_LENGTH] = { 0 }; + + size_t uriLen = sizeof(uri); + snprintf(uri, uriLen - 1, COAPS_QUERY, deviceInfo->endpoint.addr, deviceInfo->securePort, + OIC_RSRC_CRED_URI); + + uri[uriLen - 1] = '\0'; + OC_LOG_V(INFO, TAG, "URI for Credential provisioning : %s",uri); + OCCallbackData cbData = {.context=NULL, .cb=NULL, .cd=NULL}; + cbData.cb = responseHandler; + cbData.context = (void *) credData; + cbData.cd = NULL; + + OCDoHandle handle = NULL; + OCMethod method = OC_REST_POST; + // TODO replace CT_ADAPTER_IP with value from discovery + OCStackResult ret = OCDoResource(&handle, method, uri, 0, (OCPayload*)secPayload, + CT_ADAPTER_IP, OC_HIGH_QOS, &cbData, NULL, 0); + OC_LOG_V(INFO, TAG, "OCDoResource::Credential provisioning returned : %d",ret); + if (ret != OC_STACK_OK) + { + OC_LOG(ERROR, TAG, "OCStack resource error"); + return ret; + } + return OC_STACK_OK; +} + +OCStackResult SRPProvisionCredentials(void *ctx, OicSecCredType_t type, size_t keySize, + const OCProvisionDev_t *pDev1, + const OCProvisionDev_t *pDev2, + OCProvisionResultCB resultCallback) +{ + VERIFY_NON_NULL(TAG, pDev1, ERROR, OC_STACK_INVALID_PARAM); + VERIFY_NON_NULL(TAG, pDev2, ERROR, OC_STACK_INVALID_PARAM); + VERIFY_NON_NULL(TAG, resultCallback, ERROR, OC_STACK_INVALID_CALLBACK); + + if (!(keySize == OWNER_PSK_LENGTH_128 || keySize == OWNER_PSK_LENGTH_256)) + { + OC_LOG(INFO, TAG, "Invalid key size"); + return OC_STACK_INVALID_PARAM; + } + + OC_LOG(INFO, TAG, "In SRPProvisionCredentials"); + + OicUuid_t provTooldeviceID = {{0,}}; + if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID)) + { + OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID"); + return OC_STACK_ERROR; + } + OC_LOG(INFO, TAG, "retrieved deviceid"); + switch (type) + { + case SYMMETRIC_PAIR_WISE_KEY: + { + const OCProvisionDev_t *firstDevice = pDev1; + const OCProvisionDev_t *secondDevice = pDev2; + + OicSecCred_t *firstCred = NULL; + OicSecCred_t *secondCred = NULL; + OCStackResult res = PMGeneratePairWiseCredentials(type, keySize, &provTooldeviceID, + &firstDevice->doxm->deviceID, &secondDevice->doxm->deviceID, + &firstCred, &secondCred); + VERIFY_SUCCESS(TAG, (res==OC_STACK_OK), ERROR, OC_STACK_ERROR); + OC_LOG(INFO, TAG, "Credentials generated successfully"); + CredentialData_t *credData = (CredentialData_t *) OICMalloc(sizeof(CredentialData_t)); + if (NULL == credData) + { + OC_LOG(ERROR, TAG, "Memory allocation problem"); + return OC_STACK_NO_MEMORY; + } + memset(credData, 0x00, sizeof(CredentialData_t)); + credData->deviceInfo1 = firstDevice; + credData->deviceInfo2 = secondDevice; + credData->credInfo = secondCred; + credData->ctx = ctx; + credData->credInfoFirst = firstCred; + credData->numOfResults = 0; + credData->resultCallback = resultCallback; + // first call to provision creds to device1. + // second call to provision creds to device2. + int noOfRiCalls = 2; + credData->resArr = + (OCProvisionResult_t*)OICMalloc(sizeof(OCProvisionResult_t) * noOfRiCalls); + if (NULL == credData->resArr) + { + OC_LOG(ERROR, TAG, "Memory allocation problem"); + return OC_STACK_NO_MEMORY; + } + memset(credData->resArr, 0x00, sizeof(sizeof(OCProvisionResult_t)*noOfRiCalls)); + res = provisionCredentials(firstCred, firstDevice, credData, &provisionCredentialCB1); + if (OC_STACK_OK != res) + { + DeleteCredList(firstCred); + DeleteCredList(secondCred); + OICFree(credData->resArr); + OICFree(credData); + } + OC_LOG_V(INFO, TAG, "provisionCredentials returned: %d",res); + VERIFY_SUCCESS(TAG, (res==OC_STACK_OK), ERROR, OC_STACK_ERROR); + return res; + } + default: + { + OC_LOG(ERROR, TAG, "Invalid option."); + return OC_STACK_INVALID_PARAM; + } + } + return OC_STACK_ERROR; +} + +/** + * Internal Function to store results in result array during ACL provisioning. + */ +static void registerResultForACLProvisioning(ACLData_t *aclData, + OCStackResult stackresult) +{ + OC_LOG_V(INFO, TAG, "Inside registerResultForACLProvisioning aclData->numOfResults is %d\n", + aclData->numOfResults); + memcpy(aclData->resArr[(aclData->numOfResults)].deviceId.id, + aclData->deviceInfo->doxm->deviceID.id, UUID_LENGTH); + aclData->resArr[(aclData->numOfResults)].res = stackresult; + ++(aclData->numOfResults); +} + +/** + * Callback handler of SRPProvisionACL. + * + * @param[in] ctx ctx value passed to callback from calling function. + * @param[in] UNUSED handle to an invocation + * @param[in] clientResponse Response from queries to remote servers. + * @return OC_STACK_DELETE_TRANSACTION to delete the transaction + * and OC_STACK_KEEP_TRANSACTION to keep it. + */ +static OCStackApplicationResult SRPProvisionACLCB(void *ctx, OCDoHandle UNUSED, + OCClientResponse *clientResponse) +{ + OC_LOG_V(INFO, TAG, "Inside SRPProvisionACLCB."); + (void)UNUSED; + VERIFY_NON_NULL(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION); + ACLData_t *aclData = (ACLData_t*)ctx; + OCProvisionResultCB resultCallback = aclData->resultCallback; + + if (clientResponse) + { + if(OC_STACK_RESOURCE_CREATED == clientResponse->result) + { + registerResultForACLProvisioning(aclData, OC_STACK_RESOURCE_CREATED); + ((OCProvisionResultCB)(resultCallback))(aclData->ctx, aclData->numOfResults, + aclData->resArr, + false); + OICFree(aclData->resArr); + OICFree(aclData); + return OC_STACK_DELETE_TRANSACTION; + } + } + registerResultForACLProvisioning(aclData, OC_STACK_ERROR); + ((OCProvisionResultCB)(resultCallback))(aclData->ctx, aclData->numOfResults, + aclData->resArr, + true); + OC_LOG_V(ERROR, TAG, "SRPProvisionACLCB received Null clientResponse"); + OICFree(aclData->resArr); + OICFree(aclData); + return OC_STACK_DELETE_TRANSACTION; +} + +OCStackResult SRPProvisionACL(void *ctx, const OCProvisionDev_t *selectedDeviceInfo, + OicSecAcl_t *acl, OCProvisionResultCB resultCallback) +{ + VERIFY_NON_NULL(TAG, selectedDeviceInfo, ERROR, OC_STACK_INVALID_PARAM); + VERIFY_NON_NULL(TAG, acl, ERROR, OC_STACK_INVALID_PARAM); + VERIFY_NON_NULL(TAG, resultCallback, ERROR, OC_STACK_INVALID_CALLBACK); + + OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload)); + if(!secPayload) + { + OC_LOG(ERROR, TAG, "Failed to memory allocation"); + return OC_STACK_NO_MEMORY; + } + secPayload->base.type = PAYLOAD_TYPE_SECURITY; + secPayload->securityData = BinToAclJSON(acl); + if(NULL == secPayload->securityData) + { + OICFree(secPayload); + OC_LOG(ERROR, TAG, "Failed to BinToAclJSON"); + return OC_STACK_NO_MEMORY; + } + OC_LOG_V(INFO, TAG, "ACL : %s", secPayload->securityData); + + char uri[SRP_MAX_URI_LENGTH] = {0}; + size_t uriLen = sizeof(uri); + + snprintf(uri, uriLen - 1, COAPS_QUERY, selectedDeviceInfo->endpoint.addr, + selectedDeviceInfo->securePort, OIC_RSRC_ACL_URI); + uri[uriLen - 1] = '\0'; + + OC_LOG_V(INFO, TAG, "URI : %s", uri); + OCCallbackData cbData = {.context=NULL, .cb=NULL, .cd=NULL}; + cbData.cb = &SRPProvisionACLCB; + ACLData_t *aclData = (ACLData_t *) OICMalloc(sizeof(ACLData_t)); + if (aclData == NULL) + { + OICFree(secPayload); + OC_LOG(ERROR, TAG, "Unable to allocate memory"); + return OC_STACK_NO_MEMORY; + } + memset(aclData, 0x00, sizeof(ACLData_t)); + aclData->deviceInfo = selectedDeviceInfo; + aclData->resultCallback = resultCallback; + aclData->numOfResults=0; + aclData->ctx = ctx; + // call to provision ACL to device1. + int noOfRiCalls = 1; + aclData->resArr = (OCProvisionResult_t*)OICMalloc(sizeof(OCProvisionResult_t)*noOfRiCalls); + if (aclData->resArr == NULL) + { + OICFree(secPayload); + OC_LOG(ERROR, TAG, "Unable to allocate memory"); + return OC_STACK_NO_MEMORY; + } + memset(aclData->resArr, 0x00, sizeof(sizeof(OCProvisionResult_t)*noOfRiCalls)); + cbData.context = (void *)aclData; + cbData.cd = NULL; + OCMethod method = OC_REST_POST; + OCDoHandle handle = NULL; + OC_LOG(DEBUG, TAG, "Sending ACL info to resource server"); + // TODO replace CT_ADAPTER_IP with value from discovery + + OCStackResult ret = OCDoResource(&handle, method, uri, + &selectedDeviceInfo->endpoint, (OCPayload*)secPayload, + CT_ADAPTER_IP, OC_HIGH_QOS, &cbData, NULL, 0); + if (ret != OC_STACK_OK) + { + OICFree(aclData->resArr); + OICFree(aclData); + } + VERIFY_SUCCESS(TAG, (OC_STACK_OK == ret), ERROR, OC_STACK_ERROR); + return OC_STACK_OK; +} diff --git a/resource/csdk/security/provisioning/unittest/SConscript b/resource/csdk/security/provisioning/unittest/SConscript index e6b59ed..8a95db0 100644 --- a/resource/csdk/security/provisioning/unittest/SConscript +++ b/resource/csdk/security/provisioning/unittest/SConscript @@ -35,17 +35,19 @@ sptest_env.PrependUnique(CPPPATH = [ '../../include', '../../../../../extlibs/tinydtls', '../include/internal', + '../include/oxm', '../../../logger/include', '../../../stack/include', '../../../../oc_logger/include', '../../../../../extlibs/gtest/gtest-1.7.0/include', - '../include' + '../include', + '../include/internal' ]) sptest_env.AppendUnique(CXXFLAGS = ['-std=c++0x', '-Wall', '-pthread']) sptest_env.AppendUnique(LIBS = ['-lpthread']) sptest_env.AppendUnique(LIBPATH = [env.get('BUILD_DIR')]) sptest_env.AppendUnique(LIBPATH = [src_dir + '/extlibs/gtest/gtest-1.7.0/lib/.libs']) -sptest_env.PrependUnique(LIBS = [ 'ocspapi', +sptest_env.PrependUnique(LIBS = [ 'ocpmapi', 'ocsrm', 'octbstack', 'oc_logger', @@ -63,7 +65,7 @@ if not env.get('RELEASE'): ###################################################################### # Source files and Targets ###################################################################### -unittest = sptest_env.Program('unittest', ['provisioningmanager.cpp']) +unittest = sptest_env.Program('unittest', ['pmutilitytest.cpp', 'otmunittest.cpp', 'secureresourceprovider.cpp']) Alias("test", [unittest]) diff --git a/resource/csdk/security/provisioning/unittest/otmunittest.cpp b/resource/csdk/security/provisioning/unittest/otmunittest.cpp new file mode 100644 index 0000000..9f69a11 --- /dev/null +++ b/resource/csdk/security/provisioning/unittest/otmunittest.cpp @@ -0,0 +1,100 @@ +/* ***************************************************************** + * + * Copyright 2015 Samsung Electronics 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 "gtest/gtest.h" +#include "oxmjustworks.h" +#include "oxmrandompin.h" +#include "ownershiptransfermanager.h" +#include "ocstack.h" +#include "utlist.h" + +using namespace std; + +TEST(JustWorksOxMTest, NullParam) +{ + + OTMContext_t* otmCtx = NULL; + OCStackResult res = OC_STACK_ERROR; + char* payloadRes; + + //LoadSecretJustWorksCallback always returns OC_STACK_OK. + res = LoadSecretJustWorksCallback(otmCtx); + EXPECT_TRUE(OC_STACK_OK == res); + + res = CreateSecureSessionJustWorksCallback(otmCtx); + EXPECT_TRUE(OC_STACK_INVALID_PARAM == res); + + payloadRes = CreateJustWorksSelectOxmPayload(otmCtx); + EXPECT_TRUE(NULL == payloadRes); + + payloadRes = CreateJustWorksOwnerTransferPayload(otmCtx); + EXPECT_TRUE(NULL == payloadRes); + + OTMContext_t otmCtx2; + otmCtx2.selectedDeviceInfo = NULL; + + //LoadSecretJustWorksCallback always returns OC_STACK_OK. + res = LoadSecretJustWorksCallback(&otmCtx2); + EXPECT_TRUE(OC_STACK_OK == res); + + res = CreateSecureSessionJustWorksCallback(&otmCtx2); + EXPECT_TRUE(OC_STACK_INVALID_PARAM == res); + + payloadRes = CreateJustWorksSelectOxmPayload(&otmCtx2); + EXPECT_TRUE(NULL == payloadRes); + + payloadRes = CreateJustWorksOwnerTransferPayload(&otmCtx2); + EXPECT_TRUE(NULL == payloadRes); +} + +TEST(RandomPinOxMTest, NullParam) +{ + OTMContext_t* otmCtx = NULL; + OCStackResult res = OC_STACK_ERROR; + char* payloadRes; + + //LoadSecretJustWorksCallback always returns OC_STACK_OK. + res = InputPinCodeCallback(otmCtx); + EXPECT_TRUE(OC_STACK_INVALID_PARAM == res); + + res = CreateSecureSessionRandomPinCallbak(otmCtx); + EXPECT_TRUE(OC_STACK_INVALID_PARAM == res); + + payloadRes = CreatePinBasedSelectOxmPayload(otmCtx); + EXPECT_TRUE(NULL == payloadRes); + + payloadRes = CreatePinBasedOwnerTransferPayload(otmCtx); + EXPECT_TRUE(NULL == payloadRes); + + OTMContext_t otmCtx2; + otmCtx2.selectedDeviceInfo = NULL; + + //LoadSecretJustWorksCallback always returns OC_STACK_OK. + res = InputPinCodeCallback(&otmCtx2); + EXPECT_TRUE(OC_STACK_INVALID_PARAM == res); + + res = CreateSecureSessionRandomPinCallbak(&otmCtx2); + EXPECT_TRUE(OC_STACK_INVALID_PARAM == res); + + payloadRes = CreatePinBasedSelectOxmPayload(&otmCtx2); + EXPECT_TRUE(NULL == payloadRes); + + payloadRes = CreatePinBasedOwnerTransferPayload(&otmCtx2); + EXPECT_TRUE(NULL == payloadRes); +} diff --git a/resource/csdk/security/provisioning/unittest/pmutilitytest.cpp b/resource/csdk/security/provisioning/unittest/pmutilitytest.cpp new file mode 100644 index 0000000..378c606 --- /dev/null +++ b/resource/csdk/security/provisioning/unittest/pmutilitytest.cpp @@ -0,0 +1,90 @@ +/* ***************************************************************** + * + * Copyright 2015 Samsung Electronics 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 "gtest/gtest.h" +#include "pmutility.h" +#include "ocstack.h" +#include "utlist.h" + +using namespace std; + +#ifdef __cplusplus +extern "C" { +#endif + +extern OCStackResult AddDevice(OCProvisionDev_t **ppList, const char* addr, const uint16_t port, + OCTransportAdapter adapter, OicSecDoxm_t *doxm); +#ifdef __cplusplus +} +#endif + +OCProvisionDev_t* gList = NULL; + +// List add Tests +TEST(ProvisionListTest, Addition) +{ + OCProvisionDev_t* el = NULL; + OCStackResult res = OC_STACK_ERROR; + OicSecDoxm_t* pDoxm = NULL; + int cnt =0; + + // The first addition + res = AddDevice(&gList, "10.20.30.40", 5684, OC_DEFAULT_ADAPTER, pDoxm); + EXPECT_TRUE(OC_STACK_OK == res); + EXPECT_TRUE(NULL != gList); + + LL_FOREACH(gList,el){ ++cnt; }; + //LL_COUNT(gList, el, cnt); + EXPECT_TRUE(1 == cnt); + + // Same node must not be inserted + res = AddDevice(&gList, "10.20.30.40", 5684, OC_ADAPTER_IP, pDoxm); + EXPECT_TRUE(OC_STACK_OK == res); + EXPECT_TRUE(NULL != gList); + + cnt = 0; + LL_FOREACH(gList,el){ ++cnt; }; + //LL_COUNT(gList, el, cnt); + EXPECT_TRUE(1 == cnt); + + // Differnet node must be inserted + res = AddDevice(&gList, "110.120.130.140", 6789, OC_DEFAULT_ADAPTER, pDoxm); + EXPECT_TRUE(OC_STACK_OK == res); + EXPECT_TRUE(NULL != gList); + + cnt = 0; + LL_FOREACH(gList,el){ ++cnt; }; + //LL_COUNT(gList, el, cnt); + EXPECT_TRUE(2 == cnt); +} + +// List Delete Tests +TEST(ProvisionListTest, Deletion) +{ + OCProvisionDev_t* el = NULL; + int cnt =0; + + // Delete whole + DeleteDeviceList(&gList); + gList = NULL; + + LL_FOREACH(gList,el){ ++cnt; }; + //LL_COUNT(gList, el, cnt); + EXPECT_TRUE(0 == cnt); +} \ No newline at end of file diff --git a/resource/csdk/security/provisioning/unittest/provisioningmanager.cpp b/resource/csdk/security/provisioning/unittest/provisioningmanager.cpp deleted file mode 100644 index 11f7dc2..0000000 --- a/resource/csdk/security/provisioning/unittest/provisioningmanager.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* ***************************************************************** - * - * Copyright 2015 Samsung Electronics 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 "gtest/gtest.h" - -#include "provisioningmanager.h" - - -static OicSecAcl_t acl; -SPTargetDeviceInfo_t list; -SPTargetDeviceInfo_t *ptr = &list; - -TEST(SPProvisioningDiscoveryTest, NotNullList) -{ - EXPECT_EQ(SP_RESULT_INVALID_PARAM, SPProvisioningDiscovery(0, &ptr)); -} - -TEST(SPInitProvisionContextTest, NullDeviceInfo) -{ - EXPECT_EQ(SP_RESULT_INVALID_PARAM, SPInitProvisionContext(0, NULL)); -} - -TEST(SPProvisionACLTest, NullDeviceInfo) -{ - EXPECT_EQ(SP_RESULT_INVALID_PARAM, SPProvisionACL(0, NULL, &acl)); -} - -TEST(SPFinalizeProvisioningTest, NullDeviceInfo) -{ - EXPECT_EQ(SP_RESULT_INVALID_PARAM, SPFinalizeProvisioning(0, NULL)); -} - -TEST(SPTerminateProvisioningTest, ValidCase) -{ - EXPECT_EQ(SP_RESULT_SUCCESS, SPTerminateProvisioning()); -} - -TEST(SPProvisionCredentialsTest, NullList) -{ - EXPECT_EQ(SP_RESULT_INVALID_PARAM, SPProvisionCredentials(0, 0, NULL)); -} diff --git a/resource/csdk/security/provisioning/unittest/secureresourceprovider.cpp b/resource/csdk/security/provisioning/unittest/secureresourceprovider.cpp new file mode 100644 index 0000000..6c8e3d6 --- /dev/null +++ b/resource/csdk/security/provisioning/unittest/secureresourceprovider.cpp @@ -0,0 +1,72 @@ +/* ***************************************************************** + * + * Copyright 2015 Samsung Electronics 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 "gtest/gtest.h" +#include "secureresourceprovider.h" + + +static OicSecAcl_t acl; +static OCProvisionDev_t pDev1; +static OCProvisionDev_t pDev2; +static OicSecCredType_t credType; + +static void provisioningCB (void* UNUSED1, int UNUSED2, OCProvisionResult_t *UNUSED3, bool UNUSED4) +{ + //dummy callback + (void) UNUSED1; + (void) UNUSED2; + (void) UNUSED3; + (void) UNUSED4; +} + +TEST(SRPProvisionACLTest, NullDeviceInfo) +{ + EXPECT_EQ(OC_STACK_INVALID_PARAM, SRPProvisionACL(NULL, NULL, &acl, &provisioningCB)); +} + +TEST(SRPProvisionACLTest, NullCallback) +{ + EXPECT_EQ(OC_STACK_INVALID_CALLBACK, SRPProvisionACL(NULL, &pDev1, &acl, NULL)); +} + +TEST(SRPProvisionACLTest, NullACL) +{ + EXPECT_EQ(OC_STACK_INVALID_PARAM, SRPProvisionACL(NULL, &pDev1, NULL, &provisioningCB)); +} + +TEST(SRPProvisionCredentialsTest, NullDevice1) +{ + EXPECT_EQ(OC_STACK_INVALID_PARAM, SRPProvisionCredentials(NULL, credType, + OWNER_PSK_LENGTH_128, NULL, + &pDev2, &provisioningCB)); +} + +TEST(SRPProvisionCredentialsTest, NullCallback) +{ + EXPECT_EQ(OC_STACK_INVALID_CALLBACK, SRPProvisionCredentials(NULL, credType, + OWNER_PSK_LENGTH_128, + &pDev1, &pDev2, NULL)); +} + +TEST(SRPProvisionCredentialsTest, InvalidKeySize) +{ + EXPECT_EQ(OC_STACK_INVALID_PARAM, SRPProvisionCredentials(NULL, credType, + 0, &pDev1, &pDev2, + &provisioningCB)); +} \ No newline at end of file diff --git a/resource/csdk/security/src/aclresource.c b/resource/csdk/security/src/aclresource.c index bc18c20..1b858f8 100644 --- a/resource/csdk/security/src/aclresource.c +++ b/resource/csdk/security/src/aclresource.c @@ -23,6 +23,7 @@ #include "ocstack.h" #include "logger.h" #include "oic_malloc.h" +#include "oic_string.h" #include "cJSON.h" #include "base64.h" #include "resourcemanager.h" @@ -32,14 +33,54 @@ #include "srmresourcestrings.h" #include "doxmresource.h" #include "srmutility.h" +#include "ocserverrequest.h" #include +#ifdef WITH_ARDUINO #include +#else +#include +#endif #define TAG PCF("SRM-ACL") -OicSecAcl_t *gAcl = NULL; +OicSecAcl_t *gAcl = NULL; static OCResourceHandle gAclHandle = NULL; +/** + * This function frees OicSecAcl_t object's fields and object itself. + */ +static void FreeACE(OicSecAcl_t *ace) +{ + size_t i; + if(NULL == ace) + { + OC_LOG (INFO, TAG, PCF("Invalid Parameter")); + return; + } + + // Clean Resources + for (i = 0; i < ace->resourcesLen; i++) + { + OICFree(ace->resources[i]); + } + OICFree(ace->resources); + + //Clean Period & Recurrence + for(i = 0; i < ace->prdRecrLen; i++) + { + OICFree(ace->periods[i]); + OICFree(ace->recurrences[i]); + } + OICFree(ace->periods); + OICFree(ace->recurrences); + + // Clean Owners + OICFree(ace->owners); + + // Clean ACL node itself + OICFree(ace); +} + void DeleteACLList(OicSecAcl_t* acl) { if (acl) @@ -49,19 +90,7 @@ void DeleteACLList(OicSecAcl_t* acl) LL_FOREACH_SAFE(acl, aclTmp1, aclTmp2) { LL_DELETE(acl, aclTmp1); - - // Clean Resources - for (size_t i = 0; i < aclTmp1->resourcesLen; i++) - { - OICFree(aclTmp1->resources[i]); - } - OICFree(aclTmp1->resources); - - // Clean Owners - OICFree(aclTmp1->owners); - - // Clean ACL node itself - OICFree(aclTmp1); + FreeACE(aclTmp1); } } } @@ -122,6 +151,34 @@ char * BinToAclJSON(const OicSecAcl_t * acl) // Permissions -- Mandatory cJSON_AddNumberToObject (jsonAcl, OIC_JSON_PERMISSION_NAME, acl->permission); + //Period & Recurrence -- Not Mandatory + if(0 != acl->prdRecrLen) + { + cJSON *jsonPeriodArray = NULL; + cJSON_AddItemToObject (jsonAcl, OIC_JSON_PERIODS_NAME, + jsonPeriodArray = cJSON_CreateArray()); + VERIFY_NON_NULL(TAG, jsonPeriodArray, ERROR); + for (size_t i = 0; i < acl->prdRecrLen; i++) + { + cJSON_AddItemToArray (jsonPeriodArray, + cJSON_CreateString(acl->periods[i])); + } + } + + //Recurrence -- Not Mandatory + if(0 != acl->prdRecrLen && acl->recurrences) + { + cJSON *jsonRecurArray = NULL; + cJSON_AddItemToObject (jsonAcl, OIC_JSON_RECURRENCES_NAME, + jsonRecurArray = cJSON_CreateArray()); + VERIFY_NON_NULL(TAG, jsonRecurArray, ERROR); + for (size_t i = 0; i < acl->prdRecrLen; i++) + { + cJSON_AddItemToArray (jsonRecurArray, + cJSON_CreateString(acl->recurrences[i])); + } + } + // Owners -- Mandatory cJSON *jsonOwnrArray = NULL; cJSON_AddItemToObject (jsonAcl, OIC_JSON_OWNERS_NAME, jsonOwnrArray = cJSON_CreateArray()); @@ -228,15 +285,71 @@ OicSecAcl_t * JSONToAclBin(const char * jsonStr) jsonObjLen = strlen(jsonRsrc->valuestring) + 1; acl->resources[idxx] = (char*)OICMalloc(jsonObjLen); VERIFY_NON_NULL(TAG, (acl->resources[idxx]), ERROR); - strncpy(acl->resources[idxx], jsonRsrc->valuestring, jsonObjLen); + OICStrcpy(acl->resources[idxx], jsonObjLen, jsonRsrc->valuestring); } while ( ++idxx < acl->resourcesLen); // Permissions -- Mandatory - jsonObj = cJSON_GetObjectItem(jsonAcl, OIC_JSON_PERMISSION_NAME); + jsonObj = cJSON_GetObjectItem(jsonAcl, + OIC_JSON_PERMISSION_NAME); VERIFY_NON_NULL(TAG, jsonObj, ERROR); VERIFY_SUCCESS(TAG, cJSON_Number == jsonObj->type, ERROR); acl->permission = jsonObj->valueint; + //Period -- Not Mandatory + cJSON *jsonPeriodObj = cJSON_GetObjectItem(jsonAcl, + OIC_JSON_PERIODS_NAME); + if(jsonPeriodObj) + { + VERIFY_SUCCESS(TAG, cJSON_Array == jsonPeriodObj->type, + ERROR); + acl->prdRecrLen = cJSON_GetArraySize(jsonPeriodObj); + if(acl->prdRecrLen > 0) + { + acl->periods = (char**)OICCalloc(acl->prdRecrLen, + sizeof(char*)); + VERIFY_NON_NULL(TAG, acl->periods, ERROR); + + cJSON *jsonPeriod = NULL; + for(size_t i = 0; i < acl->prdRecrLen; i++) + { + jsonPeriod = cJSON_GetArrayItem(jsonPeriodObj, i); + VERIFY_NON_NULL(TAG, jsonPeriod, ERROR); + + jsonObjLen = strlen(jsonPeriod->valuestring) + 1; + acl->periods[i] = (char*)OICMalloc(jsonObjLen); + VERIFY_NON_NULL(TAG, acl->periods[i], ERROR); + OICStrcpy(acl->periods[i], jsonObjLen, + jsonPeriod->valuestring); + } + } + } + + //Recurrence -- Not mandatory + cJSON *jsonRecurObj = cJSON_GetObjectItem(jsonAcl, + OIC_JSON_RECURRENCES_NAME); + if(jsonRecurObj) + { + VERIFY_SUCCESS(TAG, cJSON_Array == jsonRecurObj->type, + ERROR); + if(acl->prdRecrLen > 0) + { + acl->recurrences = (char**)OICCalloc(acl->prdRecrLen, + sizeof(char*)); + VERIFY_NON_NULL(TAG, acl->recurrences, ERROR); + + cJSON *jsonRecur = NULL; + for(size_t i = 0; i < acl->prdRecrLen; i++) + { + jsonRecur = cJSON_GetArrayItem(jsonRecurObj, i); + jsonObjLen = strlen(jsonRecur->valuestring) + 1; + acl->recurrences[i] = (char*)OICMalloc(jsonObjLen); + VERIFY_NON_NULL(TAG, acl->recurrences[i], ERROR); + OICStrcpy(acl->recurrences[i], jsonObjLen, + jsonRecur->valuestring); + } + } + } + // Owners -- Mandatory jsonObj = cJSON_GetObjectItem(jsonAcl, OIC_JSON_OWNERS_NAME); VERIFY_NON_NULL(TAG, jsonObj, ERROR); @@ -279,6 +392,119 @@ exit: return headAcl; } +static bool UpdatePersistentStorage(const OicSecAcl_t *acl) +{ + // Convert ACL data into JSON for update to persistent storage + char *jsonStr = BinToAclJSON(acl); + if (jsonStr) + { + cJSON *jsonAcl = cJSON_Parse(jsonStr); + OICFree(jsonStr); + + if ((jsonAcl) && (OC_STACK_OK == UpdateSVRDatabase(OIC_JSON_ACL_NAME, jsonAcl))) + { + return true; + } + cJSON_Delete(jsonAcl); + } + return false; +} +/* + * This method removes ACE for the subject and resource from the ACL + * + * @param subject - subject of the ACE + * @param resource - resource of the ACE + * + * @return + * OC_STACK_RESOURCE_DELETED on success + * OC_STACK_NO_RESOURC on failure to find the appropriate ACE + * OC_STACK_INVALID_PARAM on invalid parameter + */ +static OCStackResult RemoveACE(const OicUuid_t * subject, + const char * resource) +{ + OC_LOG(INFO, TAG, PCF("IN RemoveACE")); + + OicSecAcl_t *acl = NULL; + OicSecAcl_t *tempAcl = NULL; + bool deleteFlag = false; + OCStackResult ret = OC_STACK_NO_RESOURCE; + + if(memcmp(subject->id, &WILDCARD_SUBJECT_ID, sizeof(subject->id)) == 0) + { + OC_LOG_V (INFO, TAG, PCF("%s received invalid parameter"), __func__ ); + return OC_STACK_INVALID_PARAM; + } + + //If resource is NULL then delete all the ACE for the subject. + if(NULL == resource) + { + LL_FOREACH_SAFE(gAcl, acl, tempAcl) + { + if(memcmp(acl->subject.id, subject->id, sizeof(subject->id)) == 0) + { + LL_DELETE(gAcl, acl); + FreeACE(acl); + deleteFlag = true; + } + } + } + else + { + //Looping through ACL to find the right ACE to delete. If the required resource is the only + //resource in the ACE for the subject then delete the whole ACE. If there are more resources + //than the required resource in the ACE, for the subject then just delete the resource from + //the resource array + LL_FOREACH_SAFE(gAcl, acl, tempAcl) + { + if(memcmp(acl->subject.id, subject->id, sizeof(subject->id)) == 0) + { + if(1 == acl->resourcesLen && strcmp(acl->resources[0], resource) == 0) + { + LL_DELETE(gAcl, acl); + FreeACE(acl); + deleteFlag = true; + break; + } + else + { + int resPos = -1; + size_t i; + for(i = 0; i < acl->resourcesLen; i++) + { + if(strcmp(acl->resources[i], resource) == 0) + { + resPos = i; + break; + } + } + if((0 <= resPos)) + { + OICFree(acl->resources[resPos]); + acl->resources[resPos] = NULL; + acl->resourcesLen -= 1; + for(i = resPos; i < acl->resourcesLen; i++) + { + acl->resources[i] = acl->resources[i+1]; + } + deleteFlag = true; + break; + } + } + } + } + } + + if(deleteFlag) + { + if(UpdatePersistentStorage(gAcl)) + { + ret = OC_STACK_RESOURCE_DELETED; + } + } + return ret; +} + static OCEntityHandlerResult HandleACLGetRequest (const OCEntityHandlerRequest * ehRequest) { // Convert ACL data into JSON for transmission @@ -311,19 +537,9 @@ static OCEntityHandlerResult HandleACLPostRequest (const OCEntityHandlerRequest // Append the new ACL to existing ACL LL_APPEND(gAcl, newAcl); - // Convert ACL data into JSON for update to persistent storage - char *jsonStr = BinToAclJSON(gAcl); - if (jsonStr) + if(UpdatePersistentStorage(gAcl)) { - cJSON *jsonAcl = cJSON_Parse(jsonStr); - OICFree(jsonStr); - - if ((jsonAcl) && - (OC_STACK_OK == UpdateSVRDatabase(OIC_JSON_ACL_NAME, jsonAcl))) - { - ehRet = OC_EH_RESOURCE_CREATED; - } - cJSON_Delete(jsonAcl); + ehRet = OC_EH_RESOURCE_CREATED; } } @@ -334,6 +550,57 @@ static OCEntityHandlerResult HandleACLPostRequest (const OCEntityHandlerRequest return ehRet; } +static OCEntityHandlerResult HandleACLDeleteRequest(const OCEntityHandlerRequest *ehRequest) +{ + OC_LOG (INFO, TAG, PCF("Processing ACLDeleteRequest")); + OCEntityHandlerResult ehRet = OC_EH_ERROR; + + if(NULL == ehRequest->query) + { + return ehRet; + } + OicParseQueryIter_t parseIter = {.attrPos=NULL}; + OicUuid_t subject = {.id={0}}; + char * resource = NULL; + + //Parsing REST query to get subject & resource + ParseQueryIterInit((unsigned char *)ehRequest->query, &parseIter); + + while(GetNextQuery(&parseIter)) + { + if(strncasecmp((char *)parseIter.attrPos, OIC_JSON_SUBJECT_NAME, parseIter.attrLen) == 0) + { + unsigned char base64Buff[sizeof(((OicUuid_t*)0)->id)] = {}; + uint32_t outLen = 0; + B64Result b64Ret = B64_OK; + + b64Ret = b64Decode((char *)parseIter.valPos, parseIter.valLen, base64Buff, + sizeof(base64Buff), &outLen); + + VERIFY_SUCCESS(TAG, (b64Ret == B64_OK && outLen <= sizeof(subject.id)), ERROR); + memcpy(subject.id, base64Buff, outLen); + } + if(strncasecmp((char *)parseIter.attrPos, OIC_JSON_RESOURCES_NAME, parseIter.attrLen) == 0) + { + resource = (char *)OICMalloc(parseIter.valLen); + VERIFY_NON_NULL(TAG, resource, ERROR); + OICStrcpy(resource, sizeof(resource), (char *)parseIter.valPos); + } + } + + if(OC_STACK_RESOURCE_DELETED == RemoveACE(&subject, resource)) + { + ehRet = OC_EH_RESOURCE_DELETED; + } + OICFree(resource); + + // Send payload to request originator + SendSRMResponse(ehRequest, ehRet, NULL); + +exit: + return ehRet; +} + /* * This internal method is the entity handler for ACL resources and * will handle REST request (GET/PUT/POST/DEL) for them. @@ -342,6 +609,7 @@ OCEntityHandlerResult ACLEntityHandler (OCEntityHandlerFlag flag, OCEntityHandlerRequest * ehRequest, void* callbackParameter) { + OC_LOG(INFO, TAG, PCF("Received request ACLEntityHandler")); (void)callbackParameter; OCEntityHandlerResult ehRet = OC_EH_ERROR; @@ -364,6 +632,10 @@ OCEntityHandlerResult ACLEntityHandler (OCEntityHandlerFlag flag, ehRet = HandleACLPostRequest(ehRequest); break; + case OC_REST_DELETE: + ehRet = HandleACLDeleteRequest(ehRequest); + break; + default: ehRet = OC_EH_ERROR; SendSRMResponse(ehRequest, ehRet, NULL); @@ -450,11 +722,11 @@ OCStackResult GetDefaultACL(OicSecAcl_t** defaultAcl) size_t len = strlen(rsrcs[i]) + 1; acl->resources[i] = (char*)OICMalloc(len * sizeof(char)); VERIFY_NON_NULL(TAG, (acl->resources[i]), ERROR); - strncpy(acl->resources[i], rsrcs[i], len); + OICStrcpy(acl->resources[i], len, rsrcs[i]); } acl->permission = PERMISSION_READ; - acl->periodsLen = 0; + acl->prdRecrLen = 0; acl->periods = NULL; acl->recurrences = NULL; diff --git a/resource/csdk/security/src/amaclresource.c b/resource/csdk/security/src/amaclresource.c new file mode 100644 index 0000000..5b80fbe --- /dev/null +++ b/resource/csdk/security/src/amaclresource.c @@ -0,0 +1,403 @@ +//****************************************************************** +// +// Copyright 2015 Intel Mobile Communications GmbH 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 +#include +#include "ocstack.h" +#include "logger.h" +#include "oic_malloc.h" +#include "oic_string.h" +#include "cJSON.h" +#include "base64.h" +#include "resourcemanager.h" +#include "psinterface.h" +#include "utlist.h" +#include "srmresourcestrings.h" +#include "amaclresource.h" +#include "srmutility.h" +#include +#include + +#define TAG PCF("SRM-AMACL") + +OicSecAmacl_t *gAmacl = NULL; +static OCResourceHandle gAmaclHandle = NULL; + +void DeleteAmaclList(OicSecAmacl_t* amacl) +{ + if (amacl) + { + OicSecAmacl_t *amaclTmp1 = NULL, *amaclTmp2 = NULL; + LL_FOREACH_SAFE(amacl, amaclTmp1, amaclTmp2) + { + unsigned int i = 0; + + LL_DELETE(amacl, amaclTmp1); + + // Clean Resources + for (i = 0; i < amaclTmp1->resourcesLen; i++) + { + OICFree(amaclTmp1->resources[i]); + } + OICFree(amaclTmp1->resources); + + // Clean Amss + OICFree(amaclTmp1->amss); + + // Clean Owners + OICFree(amaclTmp1->owners); + + // Clean Amacl node itself + OICFree(amaclTmp1); + } + } +} + +/* + * This internal method converts AMACL data into JSON format. + * + * Note: Caller needs to invoke 'free' when finished using the return string. + */ +char * BinToAmaclJSON(const OicSecAmacl_t * amacl) +{ + cJSON *jsonRoot = NULL; + char *jsonStr = NULL; + + if (amacl) + { + jsonRoot = cJSON_CreateObject(); + VERIFY_NON_NULL(TAG, jsonRoot, ERROR); + + cJSON *jsonAmaclArray = NULL; + cJSON_AddItemToObject (jsonRoot, OIC_JSON_AMACL_NAME, jsonAmaclArray = cJSON_CreateArray()); + VERIFY_NON_NULL(TAG, jsonAmaclArray, ERROR); + + while(amacl) + { + char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(((OicUuid_t*)0)->id)) + 1] = {}; + uint32_t outLen = 0; + B64Result b64Ret = B64_OK; + + cJSON *jsonAmacl = cJSON_CreateObject(); + + // Resources -- Mandatory + cJSON *jsonRsrcArray = NULL; + cJSON_AddItemToObject(jsonAmacl, OIC_JSON_RESOURCES_NAME, jsonRsrcArray = + cJSON_CreateArray()); + VERIFY_NON_NULL(TAG, jsonRsrcArray, ERROR); + for (unsigned int i = 0; i < amacl->resourcesLen; i++) + { + cJSON_AddItemToArray(jsonRsrcArray, cJSON_CreateString(amacl->resources[i])); + } + + // Amss -- Mandatory + cJSON *jsonAmsArray = NULL; + cJSON_AddItemToObject(jsonAmacl, OIC_JSON_AMSS_NAME, jsonAmsArray = + cJSON_CreateArray()); + VERIFY_NON_NULL(TAG, jsonAmsArray, ERROR); + for (unsigned int i = 0; i < amacl->amssLen; i++) + { + outLen = 0; + + b64Ret = b64Encode(amacl->amss[i].id, sizeof(((OicUuid_t*) 0)->id), base64Buff, + sizeof(base64Buff), &outLen); + VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR); + + cJSON_AddItemToArray(jsonAmsArray, cJSON_CreateString(base64Buff)); + } + + // Owners -- Mandatory + cJSON *jsonOwnrArray = NULL; + cJSON_AddItemToObject(jsonAmacl, OIC_JSON_OWNERS_NAME, jsonOwnrArray = + cJSON_CreateArray()); + VERIFY_NON_NULL(TAG, jsonOwnrArray, ERROR); + for (unsigned int i = 0; i < amacl->ownersLen; i++) + { + outLen = 0; + + b64Ret = b64Encode(amacl->owners[i].id, sizeof(((OicUuid_t*) 0)->id), base64Buff, + sizeof(base64Buff), &outLen); + VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR); + + cJSON_AddItemToArray(jsonOwnrArray, cJSON_CreateString(base64Buff)); + } + + // Attach current amacl node to Amacl Array + cJSON_AddItemToArray(jsonAmaclArray, jsonAmacl); + amacl = amacl->next; + } + + jsonStr = cJSON_PrintUnformatted(jsonRoot); + } + +exit: + if (jsonRoot) + { + cJSON_Delete(jsonRoot); + } + return jsonStr; +} + + + + +/* + * This internal method converts JSON AMACL into binary AMACL. + */ +OicSecAmacl_t * JSONToAmaclBin(const char * jsonStr) +{ + OCStackResult ret = OC_STACK_ERROR; + OicSecAmacl_t * headAmacl = NULL; + OicSecAmacl_t * prevAmacl = NULL; + cJSON *jsonRoot = NULL; + cJSON *jsonAmaclArray = NULL; + + VERIFY_NON_NULL(TAG, jsonStr, ERROR); + + jsonRoot = cJSON_Parse(jsonStr); + VERIFY_NON_NULL(TAG, jsonRoot, ERROR); + + jsonAmaclArray = cJSON_GetObjectItem(jsonRoot, OIC_JSON_AMACL_NAME); + VERIFY_NON_NULL(TAG, jsonAmaclArray, INFO); + + if (cJSON_Array == jsonAmaclArray->type) + { + int numAmacl = cJSON_GetArraySize(jsonAmaclArray); + int idx = 0; + + VERIFY_SUCCESS(TAG, numAmacl > 0, INFO); + do + { + cJSON *jsonAmacl = cJSON_GetArrayItem(jsonAmaclArray, idx); + VERIFY_NON_NULL(TAG, jsonAmacl, ERROR); + + OicSecAmacl_t *amacl = (OicSecAmacl_t*)OICCalloc(1, sizeof(OicSecAmacl_t)); + VERIFY_NON_NULL(TAG, amacl, ERROR); + + headAmacl = (headAmacl) ? headAmacl : amacl; + if (prevAmacl) + { + prevAmacl->next = amacl; + } + + size_t jsonObjLen = 0; + cJSON *jsonObj = NULL; + + // Resources -- Mandatory + jsonObj = cJSON_GetObjectItem(jsonAmacl, OIC_JSON_RESOURCES_NAME); + VERIFY_NON_NULL(TAG, jsonObj, ERROR); + VERIFY_SUCCESS(TAG, cJSON_Array == jsonObj->type, ERROR); + + amacl->resourcesLen = cJSON_GetArraySize(jsonObj); + VERIFY_SUCCESS(TAG, amacl->resourcesLen > 0, ERROR); + amacl->resources = (char**)OICCalloc(amacl->resourcesLen, sizeof(char*)); + VERIFY_NON_NULL(TAG, (amacl->resources), ERROR); + + size_t idxx = 0; + do + { + cJSON *jsonRsrc = cJSON_GetArrayItem(jsonObj, idxx); + VERIFY_NON_NULL(TAG, jsonRsrc, ERROR); + + jsonObjLen = strlen(jsonRsrc->valuestring) + 1; + amacl->resources[idxx] = (char*)OICMalloc(jsonObjLen); + VERIFY_NON_NULL(TAG, (amacl->resources[idxx]), ERROR); + OICStrcpy(amacl->resources[idxx], jsonObjLen, jsonRsrc->valuestring); + } while ( ++idxx < amacl->resourcesLen); + + // Amss -- Mandatory + VERIFY_SUCCESS( TAG, OC_STACK_OK == AddUuidArray(jsonAmacl, OIC_JSON_AMSS_NAME, + &(amacl->amssLen), &(amacl->amss)), ERROR); + + // Owners -- Mandatory + VERIFY_SUCCESS( TAG, OC_STACK_OK == AddUuidArray(jsonAmacl, OIC_JSON_OWNERS_NAME, + &(amacl->ownersLen), &(amacl->owners)), ERROR); + + prevAmacl = amacl; + } while( ++idx < numAmacl); + } + + ret = OC_STACK_OK; + +exit: + cJSON_Delete(jsonRoot); + if (OC_STACK_OK != ret) + { + DeleteAmaclList(headAmacl); + headAmacl = NULL; + } + return headAmacl; +} + +static OCEntityHandlerResult HandleAmaclGetRequest (const OCEntityHandlerRequest * ehRequest) +{ + // Convert Amacl data into JSON for transmission + char* jsonStr = BinToAmaclJSON(gAmacl); + + OCEntityHandlerResult ehRet = (jsonStr ? OC_EH_OK : OC_EH_ERROR); + + // Send response payload to request originator + SendSRMResponse(ehRequest, ehRet, jsonStr); + + OICFree(jsonStr); + + OC_LOG_V (INFO, TAG, PCF("%s RetVal %d"), __func__ , ehRet); + return ehRet; +} + +static OCEntityHandlerResult HandleAmaclPostRequest (const OCEntityHandlerRequest * ehRequest) +{ + OCEntityHandlerResult ehRet = OC_EH_ERROR; + + // Convert JSON Amacl data into binary. This will also validate the Amacl data received. + OicSecAmacl_t* newAmacl = JSONToAmaclBin(((OCSecurityPayload*)ehRequest->payload)->securityData); + + if (newAmacl) + { + // Append the new Amacl to existing Amacl + LL_APPEND(gAmacl, newAmacl); + + // Convert Amacl data into JSON for update to persistent storage + char *jsonStr = BinToAmaclJSON(gAmacl); + if (jsonStr) + { + cJSON *jsonAmacl = cJSON_Parse(jsonStr); + OICFree(jsonStr); + + if ((jsonAmacl) && + (OC_STACK_OK == UpdateSVRDatabase(OIC_JSON_AMACL_NAME, jsonAmacl))) + { + ehRet = OC_EH_RESOURCE_CREATED; + } + cJSON_Delete(jsonAmacl); + } + } + + // Send payload to request originator + SendSRMResponse(ehRequest, ehRet, NULL); + + OC_LOG_V (INFO, TAG, PCF("%s RetVal %d"), __func__ , ehRet); + return ehRet; +} + +/* + * This internal method is the entity handler for Amacl resources and + * will handle REST request (GET/PUT/POST/DEL) for them. + */ +OCEntityHandlerResult AmaclEntityHandler (OCEntityHandlerFlag flag, + OCEntityHandlerRequest * ehRequest, + void* callbackParameter) +{ + (void) callbackParameter; + OCEntityHandlerResult ehRet = OC_EH_ERROR; + + if (!ehRequest) + { + return ehRet; + } + + if (flag & OC_REQUEST_FLAG) + { + OC_LOG (INFO, TAG, PCF("Flag includes OC_REQUEST_FLAG")); + switch (ehRequest->method) + { + case OC_REST_GET: + ehRet = HandleAmaclGetRequest(ehRequest); + break; + + case OC_REST_POST: + ehRet = HandleAmaclPostRequest(ehRequest); + break; + + default: + ehRet = OC_EH_ERROR; + SendSRMResponse(ehRequest, ehRet, NULL); + } + } + + return ehRet; +} + +/* + * This internal method is used to create '/oic/sec/amacl' resource. + */ +OCStackResult CreateAmaclResource() +{ + OCStackResult ret; + + ret = OCCreateResource(&gAmaclHandle, + OIC_RSRC_TYPE_SEC_AMACL, + OIC_MI_DEF, + OIC_RSRC_AMACL_URI, + AmaclEntityHandler, + NULL, + OC_OBSERVABLE); + + if (OC_STACK_OK != ret) + { + OC_LOG (FATAL, TAG, PCF("Unable to instantiate Amacl resource")); + DeInitAmaclResource(); + } + return ret; +} + +/** + * Initialize Amacl resource by loading data from persistent storage. + * + * @retval OC_STACK_OK for Success, otherwise some error value + */ +OCStackResult InitAmaclResource() +{ + OCStackResult ret = OC_STACK_ERROR; + + // Read Amacl resource from PS + char* jsonSVRDatabase = GetSVRDatabase(); + + if (jsonSVRDatabase) + { + // Convert JSON Amacl into binary format + gAmacl = JSONToAmaclBin(jsonSVRDatabase); + OICFree(jsonSVRDatabase); + } + + // Instantiate 'oic/sec/amacl' resource + ret = CreateAmaclResource(); + + if (OC_STACK_OK != ret) + { + DeInitAmaclResource(); + } + return ret; +} + +/** + * Perform cleanup for Amacl resources. + * + * @retval none + */ +void DeInitAmaclResource() +{ + OCDeleteResource(gAmaclHandle); + gAmaclHandle = NULL; + + DeleteAmaclList(gAmacl); + gAmacl = NULL; +} diff --git a/resource/csdk/security/src/credresource.c b/resource/csdk/security/src/credresource.c index 30f1b08..901e5d5 100644 --- a/resource/csdk/security/src/credresource.c +++ b/resource/csdk/security/src/credresource.c @@ -33,45 +33,62 @@ #include "base64.h" #include "srmutility.h" #include "cainterface.h" +#include "pbkdf2.h" #include +#ifdef WITH_ARDUINO #include +#else +#include +#endif #include - #define TAG PCF("SRM-CREDL") + static OicSecCred_t *gCred = NULL; static OCResourceHandle gCredHandle = NULL; -void DeleteCredList(OicSecCred_t* cred) +/** + * This function frees OicSecCred_t object's fields and object itself. + */ +static void FreeCred(OicSecCred_t *cred) { - if (cred) + if(NULL == cred) { - OicSecCred_t *credTmp1 = NULL, *credTmp2 = NULL; - LL_FOREACH_SAFE(cred, credTmp1, credTmp2) - { - LL_DELETE(cred, credTmp1); - - //Note: Need further clarification on roleID data type + OC_LOG (INFO, TAG, PCF("Invalid Parameter")); + return; + } + //Note: Need further clarification on roleID data type #if 0 - //Clean roleIds - OICFree(credTmp1->roleIds); + //Clean roleIds + OICFree(cred->roleIds); #endif - //Clean PublicData - OICFree(credTmp1->publicData.data); + //Clean PublicData + OICFree(cred->publicData.data); - //Clean PrivateData - OICFree(credTmp1->privateData.data); + //Clean PrivateData + OICFree(cred->privateData.data); - //Clean Period - OICFree(credTmp1->period); + //Clean Period + OICFree(cred->period); - //Clean Owners - OICFree(credTmp1->owners); + //Clean Owners + OICFree(cred->owners); - //Clean Cred node itself - OICFree(credTmp1); + //Clean Cred node itself + OICFree(cred); +} + +void DeleteCredList(OicSecCred_t* cred) +{ + if (cred) + { + OicSecCred_t *credTmp1 = NULL, *credTmp2 = NULL; + LL_FOREACH_SAFE(cred, credTmp1, credTmp2) + { + LL_DELETE(cred, credTmp1); + FreeCred(credTmp1); } } } @@ -290,7 +307,7 @@ OicSecCred_t * JSONToCredBin(const char * jsonStr) //Owners -- Mandatory jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_OWNERS_NAME); VERIFY_NON_NULL(TAG, jsonObj, ERROR); - VERIFY_SUCCESS(TAG, cJSON_Array == jsonObj->type, ERROR) + VERIFY_SUCCESS(TAG, cJSON_Array == jsonObj->type, ERROR); cred->ownersLen = cJSON_GetArraySize(jsonObj); VERIFY_SUCCESS(TAG, cred->ownersLen > 0, ERROR); cred->owners = (OicUuid_t*)OICCalloc(cred->ownersLen, sizeof(OicUuid_t)); @@ -396,7 +413,35 @@ exit: return cred; } -/* +static bool UpdatePersistentStorage(const OicSecCred_t *cred) +{ + bool ret = false; + + // Convert Cred data into JSON for update to persistent storage + char *jsonStr = BinToCredJSON(cred); + if (jsonStr) + { + cJSON *jsonCred = cJSON_Parse(jsonStr); + OICFree(jsonStr); + + if ((jsonCred) && + (OC_STACK_OK == UpdateSVRDatabase(OIC_JSON_CRED_NAME, jsonCred))) + { + ret = true; + } + cJSON_Delete(jsonCred ); + } + else //Empty cred list + { + if (OC_STACK_OK == UpdateSVRDatabase(OIC_JSON_CRED_NAME, NULL)) + { + ret = true; + } + } + return ret; +} + +/** * Compare function used LL_SORT for sorting credentials * * @param first pointer to OicSecCred_t struct @@ -459,6 +504,8 @@ static uint16_t GetCredId() exit: return 0; } + + /** * This function adds the new cred to the credential list. * @@ -471,7 +518,6 @@ exit: OCStackResult AddCredential(OicSecCred_t * newCred) { OCStackResult ret = OC_STACK_ERROR; - char * jsonStr = NULL; VERIFY_SUCCESS(TAG, NULL != newCred, ERROR); @@ -483,23 +529,41 @@ OCStackResult AddCredential(OicSecCred_t * newCred) //Append the new Cred to existing list LL_APPEND(gCred, newCred); - //Convert CredList to JSON and update the persistent Storage - jsonStr = BinToCredJSON(gCred); - - if(jsonStr) + if(UpdatePersistentStorage(gCred)) { - cJSON *jsonCred = cJSON_Parse(jsonStr); - OICFree(jsonStr); + ret = OC_STACK_OK; + } + +exit: + return ret; +} - if((jsonCred) && (OC_STACK_OK == UpdateSVRDatabase(OIC_JSON_CRED_NAME, jsonCred))) +OCStackResult RemoveCredential(const OicUuid_t *subject) +{ + OCStackResult ret = OC_STACK_ERROR; + OicSecCred_t *cred = NULL; + OicSecCred_t *tempCred = NULL; + bool deleteFlag = false; + + LL_FOREACH_SAFE(gCred, cred, tempCred) + { + if(memcmp(cred->subject.id, subject->id, sizeof(subject->id)) == 0) { - ret = OC_STACK_OK; + LL_DELETE(gCred, cred); + FreeCred(cred); + deleteFlag = 1; } - cJSON_Delete(jsonCred); } -exit: + if(deleteFlag) + { + if(UpdatePersistentStorage(gCred)) + { + ret = OC_STACK_RESOURCE_DELETED; + } + } return ret; + } static OCEntityHandlerResult HandlePostRequest(const OCEntityHandlerRequest * ehRequest) @@ -521,6 +585,49 @@ static OCEntityHandlerResult HandlePostRequest(const OCEntityHandlerRequest * eh return ret; } +static OCEntityHandlerResult HandleDeleteRequest(const OCEntityHandlerRequest *ehRequest) +{ + OC_LOG_V (INFO, TAG, PCF("Processing CredDeleteRequest")); + + OCEntityHandlerResult ehRet = OC_EH_ERROR; + + if(NULL == ehRequest->query) + { + return ehRet; + } + + OicParseQueryIter_t parseIter = {.attrPos=NULL}; + OicUuid_t subject = {.id={0}}; + + //Parsing REST query to get the subject + ParseQueryIterInit((unsigned char *)ehRequest->query, &parseIter); + while(GetNextQuery(&parseIter)) + { + if(strncasecmp((char *)parseIter.attrPos, OIC_JSON_SUBJECT_NAME, + parseIter.attrLen) == 0) + { + unsigned char base64Buff[sizeof(((OicUuid_t*)0)->id)] = {}; + uint32_t outLen = 0; + B64Result b64Ret = B64_OK; + + b64Ret = b64Decode((char *)parseIter.valPos, parseIter.valLen, + base64Buff, sizeof(base64Buff), &outLen); + + VERIFY_SUCCESS(TAG, (b64Ret == B64_OK && outLen <= sizeof(subject.id)), ERROR); + memcpy(subject.id, base64Buff, outLen); + } + } + + if(OC_STACK_RESOURCE_DELETED == RemoveCredential(&subject)) + { + ehRet = OC_EH_RESOURCE_DELETED; + } + +exit: + return ehRet; +} + + /* * This internal method is the entity handler for Cred resources * to handle REST request (PUT/POST/DEL) @@ -548,6 +655,9 @@ OCEntityHandlerResult CredEntityHandler (OCEntityHandlerFlag flag, case OC_REST_POST: ret = HandlePostRequest(ehRequest); break; + case OC_REST_DELETE: + ret = HandleDeleteRequest(ehRequest); + break; default: ret = OC_EH_ERROR; break; @@ -657,16 +767,16 @@ const OicSecCred_t* GetCredResourceData(const OicUuid_t* subject) { OicSecCred_t *cred = NULL; - if ( NULL == subject) + if ( NULL == subject) { - return NULL; + return NULL; } LL_FOREACH(gCred, cred) { if(memcmp(cred->subject.id, subject->id, sizeof(subject->id)) == 0) { - return cred; + return cred; } } return NULL; @@ -694,7 +804,7 @@ void GetDtlsPskCredentials(CADtlsPskCredsBlob_t **credInfo) caBlob = (CADtlsPskCredsBlob_t *)OICCalloc(sizeof(CADtlsPskCredsBlob_t), 1); if (caBlob) { - OicUuid_t deviceID = {}; + OicUuid_t deviceID = {.id={}}; // Retrieve Device ID from doxm resource and copy in PSK creds blob VERIFY_SUCCESS(TAG, GetDoxmDeviceID(&deviceID) == OC_STACK_OK, ERROR); @@ -752,4 +862,61 @@ exit: } OICFree(caBlob); } + +/** + * Add temporal PSK to PIN based OxM + * + * @param[in] tmpSubject UUID of target device + * @param[in] credType Type of credential to be added + * @param[in] pin numeric characters + * @param[in] pinSize length of 'pin' + * @param[in] ownersLen Number of owners + * @param[in] owners Array of owners + * @param[out] tmpCredSubject Generated credential's subject. + * + * @return OC_STACK_OK for success and errorcode otherwise. + */ +OCStackResult AddTmpPskWithPIN(const OicUuid_t* tmpSubject, OicSecCredType_t credType, + const char * pin, size_t pinSize, + size_t ownersLen, const OicUuid_t * owners, OicUuid_t* tmpCredSubject) +{ + OCStackResult ret = OC_STACK_ERROR; + + if(tmpSubject == NULL || pin == NULL || pinSize == 0 || tmpCredSubject == NULL) + { + return OC_STACK_INVALID_PARAM; + } + + uint8_t privData[OWNER_PSK_LENGTH_128] = {0,}; + int dtlsRes = DeriveCryptoKeyFromPassword((const unsigned char *)pin, pinSize, owners->id, + UUID_LENGTH, PBKDF_ITERATIONS, + OWNER_PSK_LENGTH_128, privData); + VERIFY_SUCCESS(TAG, (dtlsRes == 0) , ERROR); + + uint32_t outLen = 0; + char base64Buff[B64ENCODE_OUT_SAFESIZE(OWNER_PSK_LENGTH_128) + 1] = {}; + B64Result b64Ret = b64Encode(privData, OWNER_PSK_LENGTH_128, base64Buff, + sizeof(base64Buff), &outLen); + VERIFY_SUCCESS(TAG, (B64_OK == b64Ret), ERROR); + + OicSecCred_t* cred = GenerateCredential(tmpSubject, credType, NULL, + base64Buff, ownersLen, owners); + if(NULL == cred) + { + OC_LOG(ERROR, TAG, "GeneratePskWithPIN() : Failed to generate credential"); + return OC_STACK_ERROR; + } + + memcpy(tmpCredSubject->id, cred->subject.id, UUID_LENGTH); + + ret = AddCredential(cred); + if( OC_STACK_OK != ret) + { + OC_LOG(ERROR, TAG, "GeneratePskWithPIN() : Failed to add credential"); + } + +exit: + return ret; +} + #endif /* __WITH_DTLS__ */ diff --git a/resource/csdk/security/src/doxmresource.c b/resource/csdk/security/src/doxmresource.c index 8251214..0423a21 100644 --- a/resource/csdk/security/src/doxmresource.c +++ b/resource/csdk/security/src/doxmresource.c @@ -34,6 +34,12 @@ #include "credresource.h" #include "ocserverrequest.h" #include "srmutility.h" +#include "pinoxmcommon.h" + +#ifdef __WITH_DTLS__ +#include "global.h" +#endif + #include #include @@ -229,7 +235,7 @@ OicSecDoxm_t * JSONToDoxmBin(const char * jsonStr) jsonObj = cJSON_GetObjectItem(jsonDoxm, OIC_JSON_OXM_SEL_NAME); if(jsonObj) { - VERIFY_SUCCESS(TAG, cJSON_Number == jsonObj->type, ERROR) + VERIFY_SUCCESS(TAG, cJSON_Number == jsonObj->type, ERROR); doxm->oxmSel = (OicSecOxm_t)jsonObj->valueint; } else // PUT/POST JSON may not have oxmsel so set it to the gDoxm->oxmSel @@ -242,7 +248,7 @@ OicSecDoxm_t * JSONToDoxmBin(const char * jsonStr) jsonObj = cJSON_GetObjectItem(jsonDoxm, OIC_JSON_OWNED_NAME); if(jsonObj) { - VERIFY_SUCCESS(TAG, (cJSON_True == jsonObj->type || cJSON_False == jsonObj->type), ERROR) + VERIFY_SUCCESS(TAG, (cJSON_True == jsonObj->type || cJSON_False == jsonObj->type), ERROR); doxm->owned = jsonObj->valueint; } else // PUT/POST JSON may not have owned so set it to the gDomx->owned @@ -277,16 +283,19 @@ OicSecDoxm_t * JSONToDoxmBin(const char * jsonStr) strncpy((char *)doxm->deviceID.id, (char *)gDoxm->deviceID.id, sizeof(doxm->deviceID.id)); } - // Owner -- will be empty when device state is unowned. - if (true == doxm->owned) + //Owner -- will be empty when device status is unowned. + jsonObj = cJSON_GetObjectItem(jsonDoxm, OIC_JSON_OWNER_NAME); + if(true == doxm->owned) { - jsonObj = cJSON_GetObjectItem(jsonDoxm, OIC_JSON_OWNER_NAME); VERIFY_NON_NULL(TAG, jsonObj, ERROR); - VERIFY_SUCCESS(TAG, cJSON_String == jsonObj->type, ERROR) - outLen = 0; + } + if(jsonObj) + { + VERIFY_SUCCESS(TAG, (cJSON_String == jsonObj->type), ERROR); + outLen = 0; b64Ret = b64Decode(jsonObj->valuestring, strlen(jsonObj->valuestring), base64Buff, sizeof(base64Buff), &outLen); - VERIFY_SUCCESS(TAG, (b64Ret == B64_OK && outLen <= sizeof(doxm->owner.id)), ERROR); + VERIFY_SUCCESS(TAG, ((b64Ret == B64_OK) && (outLen <= sizeof(doxm->owner.id))), ERROR); memcpy(doxm->owner.id, base64Buff, outLen); } @@ -348,7 +357,7 @@ static bool ValidateQuery(unsigned char * query) return false; } - OicParseQueryIter_t parseIter = {0}; + OicParseQueryIter_t parseIter = {.attrPos = NULL}; ParseQueryIterInit(query, &parseIter); @@ -408,6 +417,51 @@ static OCEntityHandlerResult HandleDoxmGetRequest (const OCEntityHandlerRequest return ehRet; } +#ifdef __WITH_DTLS__ +/* + * Generating new credential for provisioning tool + * + * PSK generated by + */ +static OCEntityHandlerResult AddOwnerPSK(const CAEndpoint_t* endpoint, + OicSecDoxm_t* ptDoxm, + const uint8_t* label, const size_t labelLen) +{ + size_t ownLen = 1; + uint32_t outLen = 0; + OicSecCred_t *cred = NULL; + uint8_t ownerPSK[OWNER_PSK_LENGTH_128] = {}; + + CAResult_t pskRet = CAGenerateOwnerPSK(endpoint, + label, labelLen, + ptDoxm->owner.id, sizeof(ptDoxm->owner.id), + gDoxm->deviceID.id, sizeof(gDoxm->deviceID.id), + ownerPSK, OWNER_PSK_LENGTH_128); + + VERIFY_SUCCESS(TAG, pskRet == CA_STATUS_OK, ERROR); + + char base64Buff[B64ENCODE_OUT_SAFESIZE(OWNER_PSK_LENGTH_128) + 1] = {}; + B64Result b64Ret = b64Encode(ownerPSK, OWNER_PSK_LENGTH_128, base64Buff, + sizeof(base64Buff), &outLen); + VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR); + + OC_LOG (INFO, TAG, PCF("Doxm EntityHandle generating Credential")); + cred = GenerateCredential(&ptDoxm->owner, SYMMETRIC_PAIR_WISE_KEY, + NULL, base64Buff, ownLen, &ptDoxm->owner); + VERIFY_NON_NULL(TAG, cred, ERROR); + + //Adding provisioning tool credential to cred Resource. + VERIFY_SUCCESS(TAG, OC_STACK_OK == AddCredential(cred), ERROR); + + gDoxm->owned = true; + memcpy(&(gDoxm->owner), &(ptDoxm->owner), sizeof(OicUuid_t)); + + return OC_EH_OK; + +exit: + return OC_EH_ERROR; +} +#endif //__WITH_DTLS__ static OCEntityHandlerResult HandleDoxmPutRequest (const OCEntityHandlerRequest * ehRequest) { @@ -455,40 +509,16 @@ static OCEntityHandlerResult HandleDoxmPutRequest (const OCEntityHandlerRequest * */ #ifdef __WITH_DTLS__ - CAResult_t pskRet; - OCServerRequest *request = (OCServerRequest *)ehRequest->requestHandle; - uint8_t ownerPSK[OWNER_PSK_LENGTH_128] = {}; //Generating OwnerPSK OC_LOG (INFO, TAG, PCF("Doxm EntityHandle generating OwnerPSK")); - pskRet = CAGenerateOwnerPSK((CAEndpoint_t *)&request->devAddr, - (uint8_t*) OXM_JUST_WORKS, strlen(OXM_JUST_WORKS), - newDoxm->owner.id, sizeof(newDoxm->owner.id), - gDoxm->deviceID.id, sizeof(gDoxm->deviceID.id), - ownerPSK, OWNER_PSK_LENGTH_128); - - VERIFY_SUCCESS(TAG, pskRet == CA_STATUS_OK, ERROR); - - //Generating new credential for provisioning tool - size_t ownLen = 1; - uint32_t outLen = 0; - char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(ownerPSK)) + 1] = {}; - B64Result b64Ret = b64Encode(ownerPSK, sizeof(ownerPSK), base64Buff, - sizeof(base64Buff), &outLen); - VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR); + //Generate new credential for provisioning tool + ehRet = AddOwnerPSK((CAEndpoint_t *)&request->devAddr, newDoxm, + (uint8_t*) OXM_JUST_WORKS, strlen(OXM_JUST_WORKS)); - OC_LOG (INFO, TAG, PCF("Doxm EntityHandle generating Credential")); - OicSecCred_t *cred = GenerateCredential(&newDoxm->owner, SYMMETRIC_PAIR_WISE_KEY, - NULL, base64Buff, ownLen, &newDoxm->owner); - VERIFY_NON_NULL(TAG, cred, ERROR); - - //Adding provisioning tool credential to cred Resource. - VERIFY_SUCCESS(TAG, OC_STACK_OK == AddCredential(cred), ERROR); - - gDoxm->owned = true; - memcpy(&(gDoxm->owner), &(newDoxm->owner), sizeof(OicUuid_t)); + VERIFY_SUCCESS(TAG, ehRet = OC_EH_OK, ERROR); // Update new state in persistent storage if (true == UpdatePersistentStorage(gDoxm)) @@ -515,6 +545,75 @@ static OCEntityHandlerResult HandleDoxmPutRequest (const OCEntityHandlerRequest #endif //__WITH_DTLS__ } } + else if(OIC_RANDOM_DEVICE_PIN == newDoxm->oxmSel) + { + //this temp Credential ID is used to track temporal Cred Id + static OicUuid_t tmpCredId = {.id={0}}; + static bool tmpCredGenFlag = false; + + if ((false == gDoxm->owned) && (false == newDoxm->owned)) + { +#ifdef __WITH_DTLS__ + CAEnableAnonECDHCipherSuite(false); + OC_LOG(DEBUG, TAG, "ECDH_ANON CipherSuite is DISABLED"); + CASelectCipherSuite(TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256); + + char ranPin[OXM_RANDOM_PIN_SIZE + 1] = {0,}; + if(OC_STACK_OK == GeneratePin(ranPin, OXM_RANDOM_PIN_SIZE + 1)) + { + if(tmpCredGenFlag) + { + OC_LOG(DEBUG, TAG, "Corrupted PSK is detected!!!"); + VERIFY_SUCCESS(TAG, + OC_STACK_RESOURCE_DELETED == RemoveCredential(&tmpCredId), + ERROR); + } + + OCStackResult res = AddTmpPskWithPIN( &(newDoxm->owner), SYMMETRIC_PAIR_WISE_KEY, + ranPin, OXM_RANDOM_PIN_SIZE, 1, &(newDoxm->owner), &tmpCredId); + VERIFY_SUCCESS(TAG, res == OC_STACK_OK, ERROR); + tmpCredGenFlag = true; + ehRet = OC_EH_OK; + } + else + { + OC_LOG(ERROR, TAG, "Failed to generate random PIN"); + ehRet = OC_EH_ERROR; + } + +#endif //__WITH_DTLS__ + } + + /* + * When current state of the device is un-owned and Provisioning + * Tool is attempting to change the state to 'Owned' with a + * qualified value for the field 'Owner' + */ + if ((false == gDoxm->owned) && (true == newDoxm->owned) && + (memcmp(&(newDoxm->owner), &emptyOwner, sizeof(OicUuid_t)) != 0)) + { +#ifdef __WITH_DTLS__ + OCServerRequest * request = (OCServerRequest *)ehRequest->requestHandle; + + //Remove Temporal Credential resource + if(tmpCredGenFlag) + { + VERIFY_SUCCESS(TAG, + OC_STACK_RESOURCE_DELETED == RemoveCredential(&tmpCredId), + ERROR); + tmpCredGenFlag = false; + } + + //Generate new credential for provisioning tool + ehRet = AddOwnerPSK((CAEndpoint_t*)(&request->devAddr), newDoxm, + (uint8_t*)OXM_RANDOM_DEVICE_PIN, strlen(OXM_RANDOM_DEVICE_PIN)); + VERIFY_SUCCESS(TAG, OC_EH_OK == ehRet, ERROR); + + //Update new state in persistent storage + ehRet = (UpdatePersistentStorage(gDoxm) == true) ? OC_EH_OK : OC_EH_ERROR; +#endif + } + } } exit: diff --git a/resource/csdk/security/src/iotvticalendar.c b/resource/csdk/security/src/iotvticalendar.c new file mode 100644 index 0000000..8276365 --- /dev/null +++ b/resource/csdk/security/src/iotvticalendar.c @@ -0,0 +1,418 @@ +//****************************************************************** +// +// Copyright 2015 Intel Mobile Communications GmbH 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. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +//Not supported on Arduino due lack of absolute time need to implement iCalendar +#ifndef WITH_ARDUINO + +#define _XOPEN_SOURCE //Needed by strptime +#include +#include "iotvticalendar.h" +#include "oic_string.h" + +static char dtFormat[] = "%Y%m%dT%H%M%S"; //date-time format +static char dFormat[] = "%Y%m%d"; // date format + +static const char FREQ[] = "FREQ"; +static const char UNTIL[] = "UNTIL"; +static const char BYDAY[] = "BYDAY"; +static const char DAILY[] = "DAILY"; + + +/** + * Parses periodStr and populate struct IotvtICalPeriod_t + * + * @param periodStr string to be parsed. + * @param period IotvtICalPeriod_t struct to be populated. + * + * @return IOTVTICAL_INVALID_PARAMETER -- if parameter are invalid + * IOTVTICAL_INVALID_PERIOD -- if period string has invalid format + * IOTVTICAL_INVALID_SUCCESS -- if no error while parsing + */ +IotvtICalResult_t ParsePeriod(const char *periodStr, IotvtICalPeriod_t *period) +{ + if((NULL == periodStr) || (NULL == period)) + { + return IOTVTICAL_INVALID_PARAMETER; + } + + char *endDTPos; + char *fmt = ""; + int startDTLen; + int endDTLen; + + //Finding length of startDateTime and endDateTime in period + //startDateTime and endDateTime can have form YYYYmmdd or YYYYmmddTHHMMSS + //startDateTime and endDateTime must be same form + //Eg: periodStr = "20150629T153050/20150630T203055" + // periodStr = "20150629/20150630" + if(NULL == (endDTPos = strchr(periodStr, '/'))) + { + return IOTVTICAL_INVALID_PERIOD; + } + endDTPos += 1; + startDTLen = endDTPos - periodStr - 1; + endDTLen = strlen(endDTPos); + + //Checking if both startDateTime and endDateTime are of same form + if(startDTLen == endDTLen) + { + if(8 == startDTLen) //YYYYmmdd + { + fmt = dFormat; + } + else if(15 == startDTLen) //YYYYmmddTHHMMSS + { + fmt = dtFormat; + } + else + { + return IOTVTICAL_INVALID_PERIOD; + } + } + else + { + return IOTVTICAL_INVALID_PERIOD; + } + + //Checking if startDateTime has right format + if(NULL != strptime(periodStr, fmt, &period->startDateTime)) + { + //Checking if endDateTime has right format + if(NULL != strptime(endDTPos, fmt, &period->endDateTime)) + { + //Checking if endDateTime is after startDateTime + if(difftime(mktime(&period->endDateTime), + mktime(&period->startDateTime)) > 0) + { + //mktime increases value of tm_hour by 1 if tm_isdst is set. + //The tm_hour value in period's startDateTime and endDatetime + //should remain same irrespective of daylight saving time. + if(period->startDateTime.tm_isdst) + { + period->startDateTime.tm_hour = + (period->startDateTime.tm_hour + TOTAL_HOURS - TM_DST_OFFSET) % TOTAL_HOURS; + } + if(period->endDateTime.tm_isdst) + { + period->endDateTime.tm_hour = + (period->endDateTime.tm_hour + TOTAL_HOURS - TM_DST_OFFSET) % TOTAL_HOURS; + } + return IOTVTICAL_SUCCESS; + } + } + } + return IOTVTICAL_INVALID_PERIOD; +} + + +/** + * Parses untilRule and populate "until" field of struct IotvtICalRecur_t + * + * @param untilRule string to be parsed. + * @param recur IotvtICalRecur_t struct to be populated. + * + * @return IOTVTICAL_ERRRO -- if untilRule has invalid format + * IOTVTICAL_INVALID_SUCCESS -- if no error while parsing + */ +static IotvtICalResult_t ParseDate(char *untilRule, IotvtICalRecur_t *recur) +{ + char *date = strchr(untilRule, '='); + + if(NULL == date) + { + return IOTVTICAL_ERROR; + } + date += 1; + + if(strlen(date) == 8) //YYYYmmdd + { + if(NULL != strptime(date, dFormat, &recur->until)) + { + return IOTVTICAL_SUCCESS; + } + } + return IOTVTICAL_ERROR; +} + + +/** + * Parses bydayRule and populate "byDay" field of struct IotvtICalRecur_t + * + * @param bydayRule string to be parsed. + * @param recur IotvtICalRecur_t struct to be populated. + * + * @return IOTVTICAL_ERRRO -- if bydayRule has empty weekday list or invalid weekdays + * IOTVTICAL_INVALID_SUCCESS -- if no error while parsing + */ +static IotvtICalResult_t ParseByday(char *bydayRule, IotvtICalRecur_t *recur) +{ + if(strstr(bydayRule, "SU")) + { + recur->byDay = recur->byDay | SUNDAY; + } + if(strstr(bydayRule, "MO")) + { + recur->byDay = recur->byDay | MONDAY; + } + if(strstr(bydayRule, "TU")) + { + recur->byDay = recur->byDay | TUESDAY; + } + if(strstr(bydayRule, "WE")) + { + recur->byDay = recur->byDay | WEDNESDAY; + } + if(strstr(bydayRule, "TH")) + { + recur->byDay = recur->byDay | THURSDAY; + } + if(strstr(bydayRule, "FR")) + { + recur->byDay = recur->byDay | FRIDAY; + } + if(strstr(bydayRule, "SA")) + { + recur->byDay = recur->byDay | SATURDAY; + } + + //Checking if byDay list is empty or has inValid weekdays + if(recur->byDay == NO_WEEKDAY) + { + return IOTVTICAL_ERROR; + } + + return IOTVTICAL_SUCCESS; +} + + +/** + * Parses recurStr and populate struct IotvtICalRecur_t + * + * @param recurStr string to be parsed. + * @param recur IotvtICalPeriod_t struct to be populated. + * + * @return IOTVTICAL_INVALID_PARAMETER -- if parameter are invalid + * IOTVTICAL_INVALID_PERIOD -- if period string has invalid format + * IOTVTICAL_INVALID_RRULE -- if rrule string has invalid format + */ +IotvtICalResult_t ParseRecur(const char *recurStr, IotvtICalRecur_t *recur) +{ + + if((NULL == recurStr) || (NULL == recur)) + { + return IOTVTICAL_INVALID_PARAMETER; + } + + const char *startPos=""; + const char *endPos=""; + char buf[50]; + int freqFlag = 0; //valid RRULE must have "FREQ" parameter. + //flag to track if RRULE has "FREQ" or not + + startPos = recurStr; + //Iterates though recurrence rule + //Eg, RRULE: FREQ=DAILY; UNTIL=20150703; BYDAY=MO, WE, FR + while('\0' != startPos) + { + endPos = strchr(startPos, ';'); + if(endPos) + { + endPos += 1; + } + OICStrcpy(buf, (endPos - startPos), startPos); + if(NULL != strstr(buf, FREQ)) + { + if(NULL != strstr(buf, DAILY)) + { + recur->freq = FREQ_DAILY; + freqFlag = 1; + } + else + { + return IOTVTICAL_INVALID_RRULE; + } + } + else if(NULL != strstr(buf, UNTIL)) + { + if(IOTVTICAL_SUCCESS != ParseDate(buf, recur)) + { + return IOTVTICAL_INVALID_RRULE; + } + } + else if(NULL != strstr(buf, BYDAY)) + { + if(IOTVTICAL_SUCCESS != ParseByday(buf, recur)) + { + return IOTVTICAL_INVALID_RRULE; + }; + } + startPos = endPos; + } + + if(1 != freqFlag) + { + return IOTVTICAL_INVALID_RRULE; + } + + return IOTVTICAL_SUCCESS; +} + +/** + * Computes number of days between two dates. + * + * @param date1 earlier date. + * @param date2 later date. + * + * @return number of days between date1 & date2. + */ +static int DiffDays(IotvtICalDateTime_t *date1, IotvtICalDateTime_t *date2) +{ + int days; + int leapDays=0; + + if(date2->tm_year > date1->tm_year) + { + for(int y = date1->tm_year; y < date2->tm_year; y++) + { + y += TM_YEAR_OFFSET; + if(y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) + { + leapDays += 1; + } + } + } + + days = (365 * date2->tm_year + date2->tm_yday + leapDays) - + (365 * date1->tm_year + date1->tm_yday); + + return days; +} + + +/** + * Computes number of seconds between two time. + * + * @param time1 earlier time. + * @param date2 later time. + * + * @return number of seconds between time1 and time2. + */ +static int DiffSecs(IotvtICalDateTime_t *time1, IotvtICalDateTime_t *time2) +{ + return (3600 * time2->tm_hour + 60 * time2->tm_min + time2->tm_sec) - + (3600 * time1->tm_hour + 60 * time1->tm_min + time1->tm_sec); +} + + +/** + * This API is used by policy engine to checks if the + * request to access resource is within valid time. + * + * @param period string representing period. + * @param recur string representing recurrence rule + * + * @return IOTVTICAL_VALID_ACCESS -- if the request is within valid time period + * IOTVTICAL_INVALID_ACCESS -- if the request is not within valid time period + * IOTVTICAL_INVALID_PARAMETER -- if parameter are invalid + * IOTVTICAL_INVALID_PERIOD -- if period string has invalid format + * IOTVTICAL_INVALID_RRULE -- if rrule string has invalid format + */ + +IotvtICalResult_t IsRequestWithinValidTime(char *periodStr, char *recurStr) +{ + //NULL recur rule means no recurring patter exist. + //Period can't be null. Period is used with or without + //recur rule to compute allowable access time. + if(NULL == periodStr) + { + return IOTVTICAL_INVALID_PARAMETER; + } + + IotvtICalPeriod_t period = {.startDateTime={.tm_sec=0}}; + IotvtICalRecur_t recur = {.freq=0}; + IotvtICalResult_t ret = IOTVTICAL_INVALID_ACCESS; + + time_t rawTime = time(0); + IotvtICalDateTime_t *currentTime = localtime(&rawTime); + + ret = ParsePeriod(periodStr, &period); + if(ret != IOTVTICAL_SUCCESS) + { + return ret; + } + + //If recur is NULL then the access time is between period's startDate and endDate + if(NULL == recurStr) + { + if((0 <= DiffDays(&period.startDateTime, currentTime)) && + (0 <= DiffDays(currentTime, &period.endDateTime))) + { + ret = IOTVTICAL_VALID_ACCESS; + } + } + + //If recur is not NULL then the access time is between period's startTime and + //endTime on days specified in "BYDAY" list. The first instance of recurrence + //is computed from period's startDate and the last instance is computed from + //"UNTIL". If "UNTIL" is not specified then the recurrence goes for forever. + //Eg, RRULE: FREQ=DAILY; UNTIL=20150703; BYDAY=MO, WE, FR + if(NULL != recurStr) + { + ret = ParseRecur(recurStr, &recur); + if(ret != IOTVTICAL_SUCCESS) + { + return ret; + } + + if((0 <= DiffSecs(&period.startDateTime, currentTime))&& + (0 <= DiffSecs(currentTime, &period.endDateTime)) && + (0 <= DiffDays(&period.startDateTime, currentTime))) + { + IotvtICalDateTime_t emptyDT = {.tm_sec=0}; + ret = IOTVTICAL_VALID_ACCESS; + + //"UNTIL" is an optional parameter of RRULE, checking if until present in recur + if(0 != memcmp(&recur.until, &emptyDT, sizeof(IotvtICalDateTime_t))) + { + if(0 > DiffDays(currentTime, &recur.until)) + { + ret = IOTVTICAL_INVALID_ACCESS; + } + } + + //"BYDAY" is an optional parameter of RRULE, checking if byday present in recur + if(NO_WEEKDAY != recur.byDay) + { + + int isValidWD = (0x1 << currentTime->tm_wday) & recur.byDay; //Valid weekdays + if(!isValidWD) + { + ret = IOTVTICAL_INVALID_ACCESS; + } + } + } + else + { + ret = IOTVTICAL_INVALID_ACCESS; + } + } + return ret; +} +#endif diff --git a/resource/csdk/security/src/oxmpincommon.c b/resource/csdk/security/src/oxmpincommon.c new file mode 100644 index 0000000..fc7c0f3 --- /dev/null +++ b/resource/csdk/security/src/oxmpincommon.c @@ -0,0 +1,110 @@ +/* ***************************************************************** + * + * Copyright 2015 Samsung Electronics 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 "ocstack.h" +#include "ocrandom.h" +#include "logger.h" +#include "pinoxmcommon.h" + +#define TAG PCF("PIN_OXM_COMMON") + +static GeneratePinCallback gGenPinCallback = NULL; +static InputPinCallback gInputPinCallback = NULL; + +void SetInputPinCB(InputPinCallback pinCB) +{ + if(NULL == pinCB) + { + OC_LOG(ERROR, TAG, "Failed to set callback for input pin."); + return; + } + + gInputPinCallback = pinCB; +} + +void SetGeneratePinCB(GeneratePinCallback pinCB) +{ + if(NULL == pinCB) + { + OC_LOG(ERROR, TAG, "Failed to set callback for generate pin."); + return; + } + + gGenPinCallback = pinCB; +} + +OCStackResult GeneratePin(char* pinBuffer, size_t bufferSize) +{ + if(!pinBuffer) + { + OC_LOG(ERROR, TAG, "PIN buffer is NULL"); + return OC_STACK_INVALID_PARAM; + } + if(OXM_RANDOM_PIN_SIZE + 1 > bufferSize) + { + OC_LOG(ERROR, TAG, "PIN buffer size is too small"); + return OC_STACK_INVALID_PARAM; + } + for(size_t i = 0; i < OXM_RANDOM_PIN_SIZE; i++) + { + pinBuffer[i] = OCGetRandomRange((uint32_t)'0', (uint32_t)'9'); + } + pinBuffer[OXM_RANDOM_PIN_SIZE] = '\0'; + + if(gGenPinCallback) + { + gGenPinCallback(pinBuffer, OXM_RANDOM_PIN_SIZE); + } + else + { + OC_LOG(ERROR, TAG, "Invoke PIN callback failed!"); + OC_LOG(ERROR, TAG, "Callback for genrate PIN should be registered to use PIN based OxM."); + return OC_STACK_ERROR; + } + + return OC_STACK_OK; +} + + +OCStackResult InputPin(char* pinBuffer, size_t bufferSize) +{ + if(!pinBuffer) + { + OC_LOG(ERROR, TAG, "PIN buffer is NULL"); + return OC_STACK_INVALID_PARAM; + } + if(OXM_RANDOM_PIN_SIZE + 1 > bufferSize) + { + OC_LOG(ERROR, TAG, "PIN buffer size is too small"); + return OC_STACK_INVALID_PARAM; + } + + if(gInputPinCallback) + { + gInputPinCallback(pinBuffer, OXM_RANDOM_PIN_SIZE + 1); + } + else + { + OC_LOG(ERROR, TAG, "Invoke PIN callback failed!"); + OC_LOG(ERROR, TAG, "Callback for input PIN should be registered to use PIN based OxM."); + return OC_STACK_ERROR; + } + + return OC_STACK_OK; +} diff --git a/resource/csdk/security/src/pbkdf2.c b/resource/csdk/security/src/pbkdf2.c new file mode 100644 index 0000000..1ddabed --- /dev/null +++ b/resource/csdk/security/src/pbkdf2.c @@ -0,0 +1,149 @@ +/* ***************************************************************** + * + * Copyright 2015 Samsung Electronics 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 +#include +#include "pbkdf2.h" +#include "hmac.h" +#include "debug.h" +#include "logger.h" + +#define TAG "PBDKF2" +#define XOR_BUF(in, out, bufSize)\ +do{\ + size_t i=0;\ + for(i=0; i< (bufSize); i++)\ + {\ + (out)[i] = (in)[i] ^ (out)[i];\ + }\ +}while(0)\ + + +static int isLittle() +{ + static int a = 1; + static int flag = -1; + if (flag == -1) + { + if ( ((uint8_t *)&a)[0] == 0x1) // little + flag = 1; + else + flag = 0; + } + return flag; +} + +static void GetBigEndianBuf(uint8_t *buf, int num) +{ + uint8_t *nBuf = (uint8_t *)# + if ( isLittle() == 1 ) + { + size_t i = 0; + for (i = 0; i < sizeof(int); i++) + { + buf[i] = nBuf[ sizeof(int) - i - 1]; + } + } + else + { + memcpy(buf, nBuf, sizeof(int)); + } +} + +// TODO: Add comments to explain implementation. +int DeriveCryptoKeyFromPassword(const unsigned char *passwd, size_t pLen, + const uint8_t *salt, const size_t saltLen, + const size_t iterations, + const size_t keyLen, uint8_t *derivedKey) +{ + int res = 0; + uint8_t buf[DTLS_HMAC_DIGEST_SIZE]; + uint8_t uBuf[DTLS_HMAC_DIGEST_SIZE]; + + size_t nBlocks = 0; + size_t nOctetInLastBlock = 0; + + nBlocks = (size_t)ceil ((double)keyLen / (double)DTLS_HMAC_DIGEST_SIZE); + nOctetInLastBlock = keyLen - (nBlocks - 1) * DTLS_HMAC_DIGEST_SIZE; + + dtls_hmac_context_t *ctx = NULL; + ctx = dtls_hmac_new( (const unsigned char *)passwd, pLen); + if (NULL == ctx) + { + OC_LOG(ERROR, TAG, "DTLS HMAC Context is NULL"); + goto bail; + } + + size_t i = 1; + size_t idx = 0; //index for buffer + size_t counter = 0; + while (i != nBlocks + 1) + { + counter = 0 ; + dtls_hmac_init(ctx, (const unsigned char *)passwd, pLen); + while (counter != iterations) + { + if (counter == 0) + { + uint8_t intBuf[4] = {0x00, 0x00, 0x00, 0x00}; + dtls_hmac_update(ctx, salt, saltLen); + GetBigEndianBuf(intBuf, i); + dtls_hmac_update(ctx, intBuf, 4); + + int len = dtls_hmac_finalize(ctx, buf); + if (DTLS_HMAC_DIGEST_SIZE != len) + { + OC_LOG(ERROR, TAG, "DTLS HMAC is failed"); + res = -1; + } + memcpy(uBuf, buf, DTLS_HMAC_DIGEST_SIZE); + } + else + { + dtls_hmac_init(ctx, (const unsigned char *)passwd, pLen); + dtls_hmac_update(ctx, buf, DTLS_HMAC_DIGEST_SIZE); + int len = dtls_hmac_finalize(ctx, buf); + if (DTLS_HMAC_DIGEST_SIZE != len) + { + OC_LOG(ERROR, TAG, "DTLS HMAC is failed"); + res = -1; + } + XOR_BUF(buf, uBuf, DTLS_HMAC_DIGEST_SIZE); + } + counter++; + } + + + if (i == nBlocks) + { + memcpy(derivedKey + idx, uBuf, nOctetInLastBlock); + } + else + { + memcpy(derivedKey + idx, uBuf, DTLS_HMAC_DIGEST_SIZE); + idx += DTLS_HMAC_DIGEST_SIZE; + } + i++; + } + +bail: + dtls_hmac_free(ctx); + return res; +} + diff --git a/resource/csdk/security/src/policyengine.c b/resource/csdk/security/src/policyengine.c index c39814d..9a61f00 100644 --- a/resource/csdk/security/src/policyengine.c +++ b/resource/csdk/security/src/policyengine.c @@ -27,6 +27,7 @@ #include "aclresource.h" #include "srmutility.h" #include "doxmresource.h" +#include "iotvticalendar.h" #include #define TAG PCF("SRM-PE") @@ -187,23 +188,56 @@ exit: } /** - * Check whether 'resource' is in the passed ACL. - * @param resource The resource to search for. + * Check whether 'resource' is getting accessed within the valid time period. * @param acl The ACL to check. - * @return true if 'resource' found, otherwise false. + * @return + * true if access is within valid time period or if the period or recurrence is not present. + * false if period and recurrence present and the access is not within valid time period. */ - bool IsResourceInAcl(const char *resource, const OicSecAcl_t *acl) - { - for(size_t n = 0; n < acl->resourcesLen; n++) +static bool IsAccessWithinValidTime(const OicSecAcl_t *acl) +{ +#ifndef WITH_ARDUINO //Period & Recurrence not supported on Arduino due + //lack of absolute time + if(NULL== acl || NULL == acl->periods || 0 == acl->prdRecrLen) + { + return true; + } + + for(size_t i = 0; i < acl->prdRecrLen; i++) { - if(0 == strcmp(resource, acl->resources[n]) || // TODO null terms? - 0 == strcmp(WILDCARD_RESOURCE_URI, acl->resources[n])) + if(IOTVTICAL_VALID_ACCESS == IsRequestWithinValidTime(acl->periods[i], + acl->recurrences[i])) { + OC_LOG(INFO, TAG, PCF("Access request is in allowed time period")); return true; } } + OC_LOG(INFO, TAG, PCF("Access request is in invalid time period")); return false; - } + +#else + return true; +#endif +} + +/** + * Check whether 'resource' is in the passed ACL. + * @param resource The resource to search for. + * @param acl The ACL to check. + * @return true if 'resource' found, otherwise false. + */ + bool IsResourceInAcl(const char *resource, const OicSecAcl_t *acl) +{ + for(size_t n = 0; n < acl->resourcesLen; n++) + { + if(0 == strcmp(resource, acl->resources[n]) || // TODO null terms? + 0 == strcmp(WILDCARD_RESOURCE_URI, acl->resources[n])) + { + return true; + } + } + return false; +} /** * Find ACLs containing context->subject. @@ -241,12 +275,17 @@ void ProcessAccessRequest(PEContext_t *context) OC_LOG(INFO, TAG, PCF("ProcessAccessRequest(): \ found matching resource in ACL.")); context->matchingAclFound = true; - // Found the resource, so it's down to permission. - context->retVal = ACCESS_DENIED_INSUFFICIENT_PERMISSION; - if(IsPermissionAllowingRequest(currentAcl->permission, \ - context->permission)) + + // Found the resource, so it's down to valid period & permission. + context->retVal = ACCESS_DENIED_INVALID_PERIOD; + if(IsAccessWithinValidTime(currentAcl)) { - context->retVal = ACCESS_GRANTED; + context->retVal = ACCESS_DENIED_INSUFFICIENT_PERMISSION; + if(IsPermissionAllowingRequest(currentAcl->permission, \ + context->permission)) + { + context->retVal = ACCESS_GRANTED; + } } } } diff --git a/resource/csdk/security/src/psinterface.c b/resource/csdk/security/src/psinterface.c index f295fce..746a164 100644 --- a/resource/csdk/security/src/psinterface.c +++ b/resource/csdk/security/src/psinterface.c @@ -128,6 +128,7 @@ OCStackResult UpdateSVRDatabase(const char* rsrcName, cJSON* jsonObj) { OCStackResult ret = OC_STACK_ERROR; cJSON *jsonSVRDb = NULL; + OCPersistentStorage* ps = NULL; // Read SVR database from PS char* jsonSVRDbStr = GetSVRDatabase(); @@ -140,7 +141,13 @@ OCStackResult UpdateSVRDatabase(const char* rsrcName, cJSON* jsonObj) OICFree(jsonSVRDbStr); jsonSVRDbStr = NULL; - if (jsonObj->child ) + //If Cred resource gets updated with empty list then delete the Cred + //object from database. + if(NULL == jsonObj && (0 == strcmp(rsrcName, OIC_JSON_CRED_NAME))) + { + cJSON_DeleteItemFromObject(jsonSVRDb, rsrcName); + } + else if (jsonObj->child ) { // Create a duplicate of the JSON object which was passed. cJSON* jsonDuplicateObj = cJSON_Duplicate(jsonObj, 1); @@ -164,31 +171,31 @@ OCStackResult UpdateSVRDatabase(const char* rsrcName, cJSON* jsonObj) // Replace the modified json object in existing SVR database json cJSON_ReplaceItemInObject(jsonSVRDb, rsrcName, jsonDuplicateObj->child); } + } - // Generate string representation of updated SVR database json object - jsonSVRDbStr = cJSON_PrintUnformatted(jsonSVRDb); - VERIFY_NON_NULL(TAG,jsonSVRDbStr, ERROR); + // Generate string representation of updated SVR database json object + jsonSVRDbStr = cJSON_PrintUnformatted(jsonSVRDb); + VERIFY_NON_NULL(TAG,jsonSVRDbStr, ERROR); - // Update the persistent storage with new SVR database - OCPersistentStorage* ps = SRMGetPersistentStorageHandler(); - if (ps && ps->open) + // Update the persistent storage with new SVR database + ps = SRMGetPersistentStorageHandler(); + if (ps && ps->open) + { + FILE* fp = ps->open(SVR_DB_FILE_NAME, "w"); + if (fp) { - FILE* fp = ps->open(SVR_DB_FILE_NAME, "w"); - if (fp) + size_t bytesWritten = ps->write(jsonSVRDbStr, 1, strlen(jsonSVRDbStr), fp); + if (bytesWritten == strlen(jsonSVRDbStr)) { - size_t bytesWritten = ps->write(jsonSVRDbStr, 1, strlen(jsonSVRDbStr), fp); - if (bytesWritten == strlen(jsonSVRDbStr)) - { - ret = OC_STACK_OK; - } - OC_LOG_V(INFO, TAG, PCF("Written %d bytes into SVR database file"), bytesWritten); - ps->close(fp); - fp = NULL; - } - else - { - OC_LOG (ERROR, TAG, PCF("Unable to open SVR database file!! ")); + ret = OC_STACK_OK; } + OC_LOG_V(INFO, TAG, PCF("Written %d bytes into SVR database file"), bytesWritten); + ps->close(fp); + fp = NULL; + } + else + { + OC_LOG (ERROR, TAG, PCF("Unable to open SVR database file!! ")); } } diff --git a/resource/csdk/security/src/pstatresource.c b/resource/csdk/security/src/pstatresource.c index 63df79c..7ca79b1 100644 --- a/resource/csdk/security/src/pstatresource.c +++ b/resource/csdk/security/src/pstatresource.c @@ -254,7 +254,7 @@ static OCEntityHandlerResult HandlePstatPutRequest(const OCEntityHandlerRequest */ for(size_t i=0; i< gPstat->smLen; i++) { - if(gPstat->sm[i] == omJson->valueint) + if(gPstat->sm[i] == (unsigned int)omJson->valueint) { gPstat->om = (OicSecDpom_t)omJson->valueint; break; diff --git a/resource/csdk/security/src/resourcemanager.c b/resource/csdk/security/src/resourcemanager.c index 7e61926..5eefbd4 100644 --- a/resource/csdk/security/src/resourcemanager.c +++ b/resource/csdk/security/src/resourcemanager.c @@ -24,6 +24,8 @@ #include "pstatresource.h" #include "doxmresource.h" #include "credresource.h" +#include "svcresource.h" +#include "amaclresource.h" #include "oic_malloc.h" #include "oic_string.h" #include "logger.h" @@ -45,7 +47,7 @@ OCStackResult SendSRMResponse(const OCEntityHandlerRequest *ehRequest, OCEntityHandlerResult ehRet, const char *rspPayload) { OC_LOG (INFO, TAG, PCF("SRM sending SRM response")); - OCEntityHandlerResponse response = {0}; + OCEntityHandlerResponse response = {.requestHandle = NULL}; if (ehRequest) { OCSecurityPayload ocPayload = {.base = {.type = PAYLOAD_TYPE_INVALID}}; @@ -91,6 +93,14 @@ OCStackResult InitSecureResources( ) { ret = InitCredResource(); } + if(OC_STACK_OK == ret) + { + ret = InitSVCResource(); + } + if(OC_STACK_OK == ret) + { + ret = InitAmaclResource(); + } if(OC_STACK_OK != ret) { //TODO: Update the default behavior if one of the SVR fails diff --git a/resource/csdk/security/src/secureresourcemanager.c b/resource/csdk/security/src/secureresourcemanager.c index 48e7bfc..ab56071 100644 --- a/resource/csdk/security/src/secureresourcemanager.c +++ b/resource/csdk/security/src/secureresourcemanager.c @@ -236,7 +236,6 @@ OCStackResult SRMRegisterPersistentStorageHandler(OCPersistentStorage* persisten OCPersistentStorage* SRMGetPersistentStorageHandler() { - OC_LOG(INFO, TAG, PCF("SRMGetPersistentStorageHandler !!")); return gPersistentStorageHandler; } diff --git a/resource/csdk/security/src/srmresourcestrings.c b/resource/csdk/security/src/srmresourcestrings.c index 02a5f0e..4cca17b 100644 --- a/resource/csdk/security/src/srmresourcestrings.c +++ b/resource/csdk/security/src/srmresourcestrings.c @@ -24,6 +24,11 @@ const char * SVR_DB_FILE_NAME = "oic_svr_db.json"; const char * OIC_MI_DEF = "oic.mi.def"; +//AMACL +const char * OIC_RSRC_TYPE_SEC_AMACL = "oic.sec.amacl"; +const char * OIC_RSRC_AMACL_URI = "/oic/sec/amacl"; +const char * OIC_JSON_AMACL_NAME = "amacl"; + //ACL const char * OIC_RSRC_TYPE_SEC_ACL = "oic.sec.acl"; const char * OIC_RSRC_ACL_URI = "/oic/sec/acl"; @@ -44,8 +49,15 @@ const char * OIC_RSRC_TYPE_SEC_CRED = "oic.sec.cred"; const char * OIC_RSRC_CRED_URI = "/oic/sec/cred"; const char * OIC_JSON_CRED_NAME = "cred"; +//svc +const char * OIC_RSRC_TYPE_SEC_SVC = "oic.sec.svc"; +const char * OIC_RSRC_SVC_URI = "/oic/sec/svc"; +const char * OIC_JSON_SVC_NAME = "svc"; + + const char * OIC_JSON_SUBJECT_NAME = "sub"; const char * OIC_JSON_RESOURCES_NAME = "rsrc"; +const char * OIC_JSON_AMSS_NAME = "amss"; const char * OIC_JSON_PERMISSION_NAME = "perms"; const char * OIC_JSON_OWNERS_NAME = "ownrs"; const char * OIC_JSON_OWNER_NAME = "ownr"; @@ -67,7 +79,11 @@ const char * OIC_JSON_ROLEIDS_NAME = "roleid"; const char * OIC_JSON_CREDTYPE_NAME = "credtyp"; const char * OIC_JSON_PUBLICDATA_NAME = "pbdata"; const char * OIC_JSON_PRIVATEDATA_NAME = "pvdata"; -const char * OIC_JSON_PERIOD_NAME = "period"; +const char * OIC_JSON_SERVICE_DEVICE_ID = "svcdid"; +const char * OIC_JSON_SERVICE_TYPE = "svct"; +const char * OIC_JSON_PERIOD_NAME = "prd"; +const char * OIC_JSON_PERIODS_NAME = "prds"; +const char * OIC_JSON_RECURRENCES_NAME = "recurs"; OicUuid_t WILDCARD_SUBJECT_ID = {"*"}; size_t WILDCARD_SUBJECT_ID_LEN = 1; @@ -83,5 +99,6 @@ const char * OXM_PRE_PROVISIONED_STRONG_CREDENTIAL = "oic.sec.doxm.ppsc"; const char * OIC_SEC_TRUE = "true"; const char * OIC_SEC_FALSE = "false"; -const char * OIC_SEC_REST_QUERY_SEPARATOR = "&"; +const char * OIC_SEC_REST_QUERY_SEPARATOR = ";"; char OIC_SEC_REST_QUERY_DELIMETER = '='; + diff --git a/resource/csdk/security/src/srmutility.c b/resource/csdk/security/src/srmutility.c index 3f97b57..510a5c5 100644 --- a/resource/csdk/security/src/srmutility.c +++ b/resource/csdk/security/src/srmutility.c @@ -23,6 +23,8 @@ #include "srmutility.h" #include "srmresourcestrings.h" #include "logger.h" +#include "oic_malloc.h" +#include "base64.h" #define TAG PCF("SRM-UTILITY") @@ -47,7 +49,6 @@ void ParseQueryIterInit(unsigned char * query, OicParseQueryIter_t * parseIter) (unsigned char *)OIC_SEC_REST_QUERY_SEPARATOR, (unsigned char *) "", 0, &parseIter->pi); } - /** * This method fills the OicParseQueryIter_t struct with next REST query's * attribute's and value's information @@ -84,3 +85,46 @@ OicParseQueryIter_t * GetNextQuery(OicParseQueryIter_t * parseIter) } return NULL; } + + +// TODO This functionality is replicated in all SVR's and therefore we need +// to encapsulate it in a common method. However, this may not be the right +// file for this method. +OCStackResult AddUuidArray(cJSON* jsonRoot, const char* arrayItem, + size_t *numUuids, OicUuid_t** uuids ) +{ + size_t idxx = 0; + cJSON* jsonObj = cJSON_GetObjectItem(jsonRoot, arrayItem); + VERIFY_NON_NULL(TAG, jsonObj, ERROR); + VERIFY_SUCCESS(TAG, cJSON_Array == jsonObj->type, ERROR); + + *numUuids = cJSON_GetArraySize(jsonObj); + VERIFY_SUCCESS(TAG, *numUuids > 0, ERROR); + *uuids = (OicUuid_t*)OICCalloc(*numUuids, sizeof(OicUuid_t)); + VERIFY_NON_NULL(TAG, *uuids, ERROR); + + do + { + unsigned char base64Buff[sizeof(((OicUuid_t*)0)->id)] = {}; + uint32_t outLen = 0; + B64Result b64Ret = B64_OK; + + cJSON *jsonOwnr = cJSON_GetArrayItem(jsonObj, idxx); + VERIFY_NON_NULL(TAG, jsonOwnr, ERROR); + VERIFY_SUCCESS(TAG, cJSON_String == jsonOwnr->type, ERROR); + + outLen = 0; + b64Ret = b64Decode(jsonOwnr->valuestring, strlen(jsonOwnr->valuestring), base64Buff, + sizeof(base64Buff), &outLen); + + VERIFY_SUCCESS(TAG, (b64Ret == B64_OK && outLen <= sizeof((*uuids)[idxx].id)), + ERROR); + memcpy((*uuids)[idxx].id, base64Buff, outLen); + } while ( ++idxx < *numUuids); + + return OC_STACK_OK; + +exit: + return OC_STACK_ERROR; + +} diff --git a/resource/csdk/security/src/svcresource.c b/resource/csdk/security/src/svcresource.c new file mode 100644 index 0000000..abd6bc4 --- /dev/null +++ b/resource/csdk/security/src/svcresource.c @@ -0,0 +1,383 @@ +//****************************************************************** +// +// Copyright 2015 Intel Mobile Communications GmbH 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 "ocstack.h" +#include "logger.h" +#include "oic_malloc.h" +#include "cJSON.h" +#include "base64.h" +#include "resourcemanager.h" +#include "psinterface.h" +#include "svcresource.h" +#include "utlist.h" +#include "srmresourcestrings.h" +#include "srmutility.h" +#include +#include + +#define TAG PCF("SRM-SVC") + +OicSecSvc_t *gSvc = NULL; +static OCResourceHandle gSvcHandle = NULL; + +void DeleteSVCList(OicSecSvc_t* svc) +{ + if (svc) + { + OicSecSvc_t *svcTmp1 = NULL, *svcTmp2 = NULL; + LL_FOREACH_SAFE(svc, svcTmp1, svcTmp2) + { + LL_DELETE(svc, svcTmp1); + + // Clean Owners + OICFree(svcTmp1->owners); + + // Clean SVC node itself + OICFree(svcTmp1); + } + } +} + +/* + * This internal method converts SVC data into JSON format. + * + * Note: Caller needs to invoke 'free' when finished done using + * return string. + */ +char * BinToSvcJSON(const OicSecSvc_t * svc) +{ + cJSON *jsonRoot = NULL; + char *jsonStr = NULL; + + if (svc) + { + jsonRoot = cJSON_CreateObject(); + VERIFY_NON_NULL(TAG, jsonRoot, ERROR); + + cJSON *jsonSvcArray = NULL; + cJSON_AddItemToObject (jsonRoot, OIC_JSON_SVC_NAME, jsonSvcArray = cJSON_CreateArray()); + VERIFY_NON_NULL(TAG, jsonSvcArray, ERROR); + + while(svc) + { + char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(((OicUuid_t*)0)->id)) + 1] = {}; + uint32_t outLen = 0; + B64Result b64Ret = B64_OK; + + cJSON *jsonSvc = cJSON_CreateObject(); + + // Service Device Identity + outLen = 0; + b64Ret = b64Encode(svc->svcdid.id, sizeof(OicUuid_t), base64Buff, + sizeof(base64Buff), &outLen); + VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR); + cJSON_AddStringToObject(jsonSvc, OIC_JSON_SERVICE_DEVICE_ID, base64Buff ); + + // Service Type + cJSON_AddNumberToObject (jsonSvc, OIC_JSON_SERVICE_TYPE, svc->svct); + + // Owners + cJSON *jsonOwnrArray = NULL; + cJSON_AddItemToObject (jsonSvc, OIC_JSON_OWNERS_NAME, jsonOwnrArray = cJSON_CreateArray()); + VERIFY_NON_NULL(TAG, jsonOwnrArray, ERROR); + for (unsigned int i = 0; i < svc->ownersLen; i++) + { + outLen = 0; + + b64Ret = b64Encode(svc->owners[i].id, sizeof(((OicUuid_t*)0)->id), base64Buff, + sizeof(base64Buff), &outLen); + VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR); + + cJSON_AddItemToArray (jsonOwnrArray, cJSON_CreateString(base64Buff)); + } + + // Attach current svc node to Svc Array + cJSON_AddItemToArray(jsonSvcArray, jsonSvc); + svc = svc->next; + } + + jsonStr = cJSON_PrintUnformatted(jsonRoot); + } + +exit: + if (jsonRoot) + { + cJSON_Delete(jsonRoot); + } + return jsonStr; +} + +/* + * This internal method converts JSON SVC into binary SVC. + */ +OicSecSvc_t * JSONToSvcBin(const char * jsonStr) +{ + OCStackResult ret = OC_STACK_ERROR; + OicSecSvc_t * headSvc = NULL; + OicSecSvc_t * prevSvc = NULL; + cJSON *jsonRoot = NULL; + cJSON *jsonSvcArray = NULL; + + VERIFY_NON_NULL(TAG, jsonStr, ERROR); + + jsonRoot = cJSON_Parse(jsonStr); + VERIFY_NON_NULL(TAG, jsonRoot, ERROR); + + jsonSvcArray = cJSON_GetObjectItem(jsonRoot, OIC_JSON_SVC_NAME); + VERIFY_NON_NULL(TAG, jsonSvcArray, INFO); + + if (cJSON_Array == jsonSvcArray->type) + { + int numSvc = cJSON_GetArraySize(jsonSvcArray); + int idx = 0; + + VERIFY_SUCCESS(TAG, numSvc > 0, INFO); + do + { + cJSON *jsonSvc = cJSON_GetArrayItem(jsonSvcArray, idx); + VERIFY_NON_NULL(TAG, jsonSvc, ERROR); + + OicSecSvc_t *svc = (OicSecSvc_t*)OICCalloc(1, sizeof(OicSecSvc_t)); + VERIFY_NON_NULL(TAG, svc, ERROR); + + headSvc = (headSvc) ? headSvc : svc; + if (prevSvc) + { + prevSvc->next = svc; + } + + cJSON *jsonObj = NULL; + + unsigned char base64Buff[sizeof(((OicUuid_t*)0)->id)] = {}; + uint32_t outLen = 0; + B64Result b64Ret = B64_OK; + + // Service Device Identity + jsonObj = cJSON_GetObjectItem(jsonSvc, OIC_JSON_SERVICE_DEVICE_ID); + VERIFY_NON_NULL(TAG, jsonObj, ERROR); + VERIFY_SUCCESS(TAG, cJSON_String == jsonObj->type, ERROR); + outLen = 0; + b64Ret = b64Decode(jsonObj->valuestring, strlen(jsonObj->valuestring), base64Buff, + sizeof(base64Buff), &outLen); + VERIFY_SUCCESS(TAG, (b64Ret == B64_OK && outLen <= sizeof(svc->svcdid.id)), ERROR); + memcpy(svc->svcdid.id, base64Buff, outLen); + + // Service Type + jsonObj = cJSON_GetObjectItem(jsonSvc, OIC_JSON_SERVICE_TYPE); + VERIFY_NON_NULL(TAG, jsonObj, ERROR); + VERIFY_SUCCESS(TAG, cJSON_Number == jsonObj->type, ERROR); + svc->svct = (OicSecSvcType_t)jsonObj->valueint; + + // Resource Owners + jsonObj = cJSON_GetObjectItem(jsonSvc, OIC_JSON_OWNERS_NAME); + VERIFY_NON_NULL(TAG, jsonObj, ERROR); + VERIFY_SUCCESS(TAG, cJSON_Array == jsonObj->type, ERROR); + + svc->ownersLen = cJSON_GetArraySize(jsonObj); + VERIFY_SUCCESS(TAG, svc->ownersLen > 0, ERROR); + svc->owners = (OicUuid_t*)OICCalloc(svc->ownersLen, sizeof(OicUuid_t)); + VERIFY_NON_NULL(TAG, (svc->owners), ERROR); + + size_t idxx = 0; + do + { + cJSON *jsonOwnr = cJSON_GetArrayItem(jsonObj, idxx); + VERIFY_NON_NULL(TAG, jsonOwnr, ERROR); + VERIFY_SUCCESS(TAG, cJSON_String == jsonOwnr->type, ERROR); + + outLen = 0; + b64Ret = b64Decode(jsonOwnr->valuestring, strlen(jsonOwnr->valuestring), base64Buff, + sizeof(base64Buff), &outLen); + + VERIFY_SUCCESS(TAG, (b64Ret == B64_OK && outLen <= sizeof(svc->owners[idxx].id)), + ERROR); + memcpy(svc->owners[idxx].id, base64Buff, outLen); + } while ( ++idxx < svc->ownersLen); + + prevSvc = svc; + } while( ++idx < numSvc); + } + + ret = OC_STACK_OK; + +exit: + cJSON_Delete(jsonRoot); + if (OC_STACK_OK != ret) + { + DeleteSVCList(headSvc); + headSvc = NULL; + } + return headSvc; +} + +static OCEntityHandlerResult HandleSVCGetRequest (const OCEntityHandlerRequest * ehRequest) +{ + // Convert SVC data into JSON for transmission + char* jsonStr = BinToSvcJSON(gSvc); + + OCEntityHandlerResult ehRet = (jsonStr ? OC_EH_OK : OC_EH_ERROR); + + // Send response payload to request originator + SendSRMResponse(ehRequest, ehRet, jsonStr); + + OICFree(jsonStr); + + OC_LOG_V (INFO, TAG, PCF("%s RetVal %d"), __func__ , ehRet); + return ehRet; +} + +static OCEntityHandlerResult HandleSVCPostRequest (const OCEntityHandlerRequest * ehRequest) +{ + OCEntityHandlerResult ehRet = OC_EH_ERROR; + + // Convert JSON SVC data into binary. This will also validate the SVC data received. + OicSecSvc_t* newSvc = JSONToSvcBin(((OCSecurityPayload*)ehRequest->payload)->securityData); + + if (newSvc) + { + // Append the new SVC to existing SVC + LL_APPEND(gSvc, newSvc); + + // Convert SVC data into JSON for update to persistent storage + char *jsonStr = BinToSvcJSON(gSvc); + if (jsonStr) + { + cJSON *jsonSvc = cJSON_Parse(jsonStr); + OICFree(jsonStr); + + if ((jsonSvc) && + (OC_STACK_OK == UpdateSVRDatabase(OIC_JSON_SVC_NAME, jsonSvc))) + { + ehRet = OC_EH_RESOURCE_CREATED; + } + cJSON_Delete(jsonSvc); + } + } + + // Send payload to request originator + SendSRMResponse(ehRequest, ehRet, NULL); + + OC_LOG_V (INFO, TAG, PCF("%s RetVal %d"), __func__ , ehRet); + return ehRet; +} + +/* + * This internal method is the entity handler for SVC resources and + * will handle REST request (GET/PUT/POST/DEL) for them. + */ +OCEntityHandlerResult SVCEntityHandler (OCEntityHandlerFlag flag, + OCEntityHandlerRequest * ehRequest, + void* callbackParameter) +{ + (void) callbackParameter; + OCEntityHandlerResult ehRet = OC_EH_ERROR; + + if (!ehRequest) + { + return ehRet; + } + + if (flag & OC_REQUEST_FLAG) + { + switch (ehRequest->method) + { + case OC_REST_GET: + ehRet = HandleSVCGetRequest(ehRequest); + break; + + case OC_REST_POST: + ehRet = HandleSVCPostRequest(ehRequest); + break; + + default: + ehRet = OC_EH_ERROR; + SendSRMResponse(ehRequest, ehRet, NULL); + } + } + + return ehRet; +} + +/* + * This internal method is used to create '/oic/sec/svc' resource. + */ +OCStackResult CreateSVCResource() +{ + OCStackResult ret; + + ret = OCCreateResource(&gSvcHandle, + OIC_RSRC_TYPE_SEC_SVC, + OIC_MI_DEF, + OIC_RSRC_SVC_URI, + SVCEntityHandler, + NULL, + OC_OBSERVABLE); + + if (OC_STACK_OK != ret) + { + OC_LOG (FATAL, TAG, PCF("Unable to instantiate SVC resource")); + DeInitSVCResource(); + } + return ret; +} + + +OCStackResult InitSVCResource() +{ + OCStackResult ret = OC_STACK_ERROR; + + OC_LOG_V (INFO, TAG, PCF("Begin %s "), __func__ ); + + // Read SVC resource from PS + char* jsonSVRDatabase = GetSVRDatabase(); + + if (jsonSVRDatabase) + { + // Convert JSON SVC into binary format + gSvc = JSONToSvcBin(jsonSVRDatabase); + OICFree(jsonSVRDatabase); + } + + // Instantiate 'oic.sec.svc' + ret = CreateSVCResource(); + + if (OC_STACK_OK != ret) + { + DeInitSVCResource(); + } + + OC_LOG_V (INFO, TAG, PCF("%s RetVal %d"), __func__ , ret); + return ret; +} + +/** + * Perform cleanup for SVC resources. + * + * @retval none + */ +void DeInitSVCResource() +{ + OCDeleteResource(gSvcHandle); + gSvcHandle = NULL; + + DeleteSVCList(gSvc); + gSvc = NULL; +} + diff --git a/resource/csdk/security/unittest/SConscript b/resource/csdk/security/unittest/SConscript index d1193ac..be35bb3 100644 --- a/resource/csdk/security/unittest/SConscript +++ b/resource/csdk/security/unittest/SConscript @@ -75,7 +75,10 @@ unittest = srmtest_env.Program('unittest', ['aclresourcetest.cpp', 'securityresourcemanager.cpp', 'credentialresource.cpp', 'srmutility.cpp', - 'base64tests.cpp']) + 'iotvticalendartest.cpp', + 'base64tests.cpp', + 'svcresourcetest.cpp', + 'srmtestcommon.cpp']) Alias("test", [unittest]) diff --git a/resource/csdk/security/unittest/aclresourcetest.cpp b/resource/csdk/security/unittest/aclresourcetest.cpp index 5dd5a6a..9bbca6c 100644 --- a/resource/csdk/security/unittest/aclresourcetest.cpp +++ b/resource/csdk/security/unittest/aclresourcetest.cpp @@ -26,21 +26,27 @@ #include "ocstack.h" #include "ocpayload.h" #include "oic_malloc.h" +#include "oic_string.h" #include "cJSON.h" #include "cainterface.h" #include "secureresourcemanager.h" #include "securevirtualresourcetypes.h" #include "srmresourcestrings.h" #include "aclresource.h" +#include "srmtestcommon.h" +#include "srmutility.h" +#include "logger.h" using namespace std; +#define TAG PCF("SRM-ACL-UT") + #ifdef __cplusplus extern "C" { #endif + extern char * BinToAclJSON(const OicSecAcl_t * acl); extern OicSecAcl_t * JSONToAclBin(const char * jsonStr); -char* ReadFile(const char* filename); extern void DeleteACLList(OicSecAcl_t* acl); OCStackResult GetDefaultACL(OicSecAcl_t** defaultAcl); OCEntityHandlerResult ACLEntityHandler (OCEntityHandlerFlag flag, @@ -55,56 +61,6 @@ const char* ACL1_JSON_FILE_NAME = "oic_unittest_acl1.json"; #define NUM_ACE_FOR_WILDCARD_IN_ACL1_JSON (2) -char* ReadFile(const char* filename) -{ - - FILE *fp = NULL; - char *data = NULL; - struct stat st; - // TODO: Find the location of the executable and concatenate the SVR file name - // before opening it. - fp = fopen(filename, "r"); - if (fp) - { - if (stat(filename, &st) == 0) - { - data = (char*)OICMalloc(st.st_size); - if (data) - { - if (fread(data, 1, st.st_size, fp) != (size_t)st.st_size) - { - printf("Error in reading file %s", filename); - } - } - } - fclose(fp); - } - else - { - printf("Unable to open %s file", filename); - } - - return data; -} - -void SetPersistentHandler(OCPersistentStorage *ps, bool set) -{ - if (set) - { - ps->open = fopen; - ps->read = fread; - ps->write = fwrite; - ps->close = fclose; - ps->unlink = unlink; - } - else - { - memset(ps, 0, sizeof(OCPersistentStorage)); - } - EXPECT_EQ(OC_STACK_OK, - OCRegisterPersistentStorageHandler(ps)); -} - // JSON Marshalling Tests TEST(ACLResourceTest, JSONMarshallingTests) { @@ -181,14 +137,14 @@ TEST(ACLResourceTest, GetDefaultACLTests) // 'POST' ACL tests TEST(ACLResourceTest, ACLPostTest) { - OCEntityHandlerRequest ehReq = {}; + OCEntityHandlerRequest ehReq = OCEntityHandlerRequest(); // Read an ACL from the file char *jsonStr = ReadFile(ACL1_JSON_FILE_NAME); if (jsonStr) { - static OCPersistentStorage ps = - { }; + static OCPersistentStorage ps = OCPersistentStorage(); + SetPersistentHandler(&ps, true); // Create Entity Handler POST request payload @@ -249,4 +205,143 @@ TEST(ACLResourceTest, GetACLResourceTests) OICFree(jsonStr); } } +//'DELETE' ACL test +TEST(ACLResourceTest, ACLDeleteWithSingleResourceTest) +{ + OCEntityHandlerRequest ehReq = OCEntityHandlerRequest(); + static OCPersistentStorage ps = OCPersistentStorage(); + char *jsonStr = NULL; + OicSecAcl_t acl = OicSecAcl_t(); + OicSecAcl_t* savePtr = NULL; + const OicSecAcl_t* subjectAcl1 = NULL; + const OicSecAcl_t* subjectAcl2 = NULL; + OCEntityHandlerResult ehRet = OC_EH_ERROR; + char query[] = "sub=MjIyMjIyMjIyMjIyMjIyMg==;rsrc=/a/led"; + + SetPersistentHandler(&ps, true); + + //ACE to POST + memcpy(acl.subject.id, "2222222222222222", sizeof(acl.subject.id)); + acl.resourcesLen = 1; + acl.resources = (char**)OICCalloc(acl.resourcesLen, sizeof(char*)); + VERIFY_NON_NULL(TAG, acl.resources, ERROR); + acl.resources[0] = (char*)OICMalloc(strlen("/a/led")+1); + VERIFY_NON_NULL(TAG, acl.resources[0], ERROR); + OICStrcpy(acl.resources[0], sizeof(acl.resources[0]), "/a/led"); + acl.permission = 6; + acl.ownersLen = 1; + acl.owners = (OicUuid_t*)OICCalloc(acl.ownersLen, sizeof(OicUuid_t)); + VERIFY_NON_NULL(TAG, acl.owners, ERROR); + memcpy(acl.owners->id, "1111111111111111", sizeof(acl.owners->id)); + + //GET json POST payload + jsonStr = BinToAclJSON(&acl); + VERIFY_NON_NULL(TAG, jsonStr, ERROR); + + // Create Entity Handler POST request payload + ehReq.method = OC_REST_POST; + ehReq.payload = (OCPayload*)OCSecurityPayloadCreate(jsonStr); + ehRet = ACLEntityHandler(OC_REQUEST_FLAG, &ehReq); + EXPECT_TRUE(OC_EH_ERROR == ehRet); + + // Verify if SRM contains ACE for the subject + savePtr = NULL; + subjectAcl1 = GetACLResourceData(&acl.subject, &savePtr); + EXPECT_TRUE(NULL != subjectAcl1); + + // Create Entity Handler DELETE request + ehReq.method = OC_REST_DELETE; + ehReq.query = (char*)OICMalloc(strlen(query)+1); + VERIFY_NON_NULL(TAG, ehReq.query, ERROR); + OICStrcpy(ehReq.query, strlen(query)+1, query); + ehRet = ACLEntityHandler(OC_REQUEST_FLAG, &ehReq); + EXPECT_TRUE(OC_EH_ERROR == ehRet); + + // Verify if SRM has deleted ACE for the subject + savePtr = NULL; + subjectAcl2 = GetACLResourceData(&acl.subject, &savePtr); + EXPECT_TRUE(NULL == subjectAcl2); + +exit: + // Perform cleanup + if(NULL != subjectAcl1) + { + DeInitACLResource(); + } + OCPayloadDestroy(ehReq.payload); + OICFree(ehReq.query); + OICFree(jsonStr); + +} + +TEST(ACLResourceTest, ACLDeleteWithMultiResourceTest) +{ + OCEntityHandlerRequest ehReq = OCEntityHandlerRequest(); + static OCPersistentStorage ps = OCPersistentStorage(); + OicSecAcl_t acl = OicSecAcl_t(); + char *jsonStr = NULL; + OicSecAcl_t* savePtr = NULL; + const OicSecAcl_t* subjectAcl1 = NULL; + const OicSecAcl_t* subjectAcl2 = NULL; + OCEntityHandlerResult ehRet = OC_EH_ERROR; + char query[] = "sub=MjIyMjIyMjIyMjIyMjIyMg==;rsrc=/a/led"; + + SetPersistentHandler(&ps, true); + + memcpy(acl.subject.id, "2222222222222222", sizeof(acl.subject.id)); + acl.resourcesLen = 2; + acl.resources = (char**)OICCalloc(acl.resourcesLen, sizeof(char*)); + VERIFY_NON_NULL(TAG, acl.resources, ERROR); + acl.resources[0] = (char*)OICMalloc(strlen("/a/led")+1); + VERIFY_NON_NULL(TAG, acl.resources[0], ERROR); + OICStrcpy(acl.resources[0], sizeof(acl.resources[0]), "/a/led"); + acl.resources[1] = (char*)OICMalloc(strlen("/a/fan")+1); + VERIFY_NON_NULL(TAG, acl.resources[1], ERROR); + OICStrcpy(acl.resources[1], sizeof(acl.resources[1]), "/a/fan"); + acl.permission = 6; + acl.ownersLen = 1; + acl.owners = (OicUuid_t*)OICCalloc(acl.ownersLen, sizeof(OicUuid_t)); + VERIFY_NON_NULL(TAG, acl.owners, ERROR); + memcpy(acl.owners->id, "1111111111111111", sizeof(acl.owners->id)); + + jsonStr = BinToAclJSON(&acl); + VERIFY_NON_NULL(TAG, jsonStr, ERROR); + + // Create Entity Handler POST request payload + ehReq.method = OC_REST_POST; + ehReq.payload = (OCPayload*)OCSecurityPayloadCreate(jsonStr); + ehRet = ACLEntityHandler(OC_REQUEST_FLAG, &ehReq); + EXPECT_TRUE(OC_EH_ERROR == ehRet); + + // Verify if SRM contains ACE for the subject with two resources + savePtr = NULL; + subjectAcl1 = GetACLResourceData(&acl.subject, &savePtr); + EXPECT_TRUE(NULL != subjectAcl1); + EXPECT_TRUE(subjectAcl1->resourcesLen == 2); + + // Create Entity Handler DELETE request + ehReq.method = OC_REST_DELETE; + ehReq.query = (char*)OICMalloc(strlen(query)+1); + VERIFY_NON_NULL(TAG, ehReq.query, ERROR); + OICStrcpy(ehReq.query, strlen(query)+1, query); + + ehRet = ACLEntityHandler(OC_REQUEST_FLAG, &ehReq); + EXPECT_TRUE(OC_EH_ERROR == ehRet); + + // Verify if SRM contains ACL for the subject but only with one resource + savePtr = NULL; + subjectAcl2 = GetACLResourceData(&acl.subject, &savePtr); + EXPECT_TRUE(NULL != subjectAcl2); + EXPECT_TRUE(subjectAcl2->resourcesLen == 1); + +exit: + // Perform cleanup + if(NULL != subjectAcl1) + { + DeInitACLResource(); + } + OCPayloadDestroy(ehReq.payload); + OICFree(ehReq.query); + OICFree(jsonStr); +} diff --git a/resource/csdk/security/unittest/credentialresource.cpp b/resource/csdk/security/unittest/credentialresource.cpp index 962b9cc..1ee9238 100644 --- a/resource/csdk/security/unittest/credentialresource.cpp +++ b/resource/csdk/security/unittest/credentialresource.cpp @@ -18,11 +18,14 @@ #include "gtest/gtest.h" #include "ocstack.h" +#include "ocpayload.h" #include "resourcemanager.h" #include "securevirtualresourcetypes.h" #include "credresource.h" #include "oic_malloc.h" #include "oic_string.h" +#include "srmtestcommon.h" +#include "srmutility.h" #include "logger.h" #define TAG PCF("SRM-CRED-UT") @@ -40,76 +43,73 @@ OicSecCred_t * JSONToCredBin(const char * jsonStr); void InitSecCredInstance(OicSecCred_t * cred); void DeleteCredList(OicSecCred_t* cred); const OicSecCred_t* GetCredResourceData(const OicUuid_t* subject); + #ifdef __cplusplus } #endif + OicSecCred_t * getCredList() { - OicSecCred_t * cred = (OicSecCred_t*)OICCalloc(1, sizeof(OicSecCred_t)); - if(!cred) - { - return NULL; - } + + OicSecCred_t * cred = NULL; + size_t sz = 0; + + cred = (OicSecCred_t*)OICCalloc(1, sizeof(OicSecCred_t)); + VERIFY_NON_NULL(TAG, cred, ERROR); cred->credId = 1234; OICStrcpy((char *)cred->subject.id, sizeof(cred->subject.id), "subject1"); #if 0 cred->roleIdsLen = 2; cred->roleIds = (OicSecRole_t *)OICCalloc(cred->roleIdsLen, sizeof(OicSecRole_t)); + VERIFY_NON_NULL(TAG, cred->roleIds, ERROR); OICStrcpy((char *)cred->roleIds[0].id, sizeof(cred->roleIds[0].id), "role11"); OICStrcpy((char *)cred->roleIds[1].id, sizeof(cred->roleIds[1].id), "role12"); + #endif cred->credType = 1; + cred->privateData.data = (char *)OICCalloc(1, strlen("My private Key11") + 1); + VERIFY_NON_NULL(TAG, cred->privateData.data, ERROR); + strcpy(cred->privateData.data, "My private Key11"); cred->ownersLen = 1; cred->owners = (OicUuid_t*)OICCalloc(cred->ownersLen, sizeof(OicUuid_t)); - if(!cred->owners) - { - OICFree(cred); - return NULL; - } + VERIFY_NON_NULL(TAG, cred->owners, ERROR); OICStrcpy((char *)cred->owners[0].id, sizeof(cred->owners[0].id), "ownersId11"); cred->next = (OicSecCred_t*)OICCalloc(1, sizeof(OicSecCred_t)); - if(!cred->next) - { - OICFree(cred->owners); - OICFree(cred); - return NULL; - } + VERIFY_NON_NULL(TAG, cred->next, ERROR); cred->next->credId = 5678; OICStrcpy((char *)cred->next->subject.id, sizeof(cred->next->subject.id), "subject2"); #if 0 cred->next->roleIdsLen = 0; #endif cred->next->credType = 1; - size_t data_size = strlen("My private Key21") + 1; - cred->next->privateData.data = (char *)OICCalloc(1, data_size); - if(!cred->next->privateData.data) - { - OICFree(cred->next); - OICFree(cred->owners); - OICFree(cred); - return NULL; - } - OICStrcpy(cred->next->privateData.data, data_size,"My private Key21"); + sz = strlen("My private Key21") + 1; + cred->next->privateData.data = (char *)OICCalloc(1, sz); + VERIFY_NON_NULL(TAG, cred->next->privateData.data, ERROR); + OICStrcpy(cred->next->privateData.data, sz,"My private Key21"); #if 0 - cred->next->publicData.data = (char *)OICCalloc(1, strlen("My Public Key123") + 1); - OICStrcpy(cred->next->publicData.data, sizeof(cred->next->publicData.data),"My Public Key123"); + sz = strlen("My Public Key123") + 1 + cred->next->publicData.data = (char *)OICCalloc(1, sz); + VERIFY_NON_NULL(TAG, cred->next->publicData.data, ERROR); + OICStrcpy(cred->next->publicData.data, sz,"My Public Key123"); #endif cred->next->ownersLen = 2; cred->next->owners = (OicUuid_t*)OICCalloc(cred->next->ownersLen, sizeof(OicUuid_t)); - if(!cred->next->owners) - { - OICFree(cred->next->privateData.data); - OICFree(cred->next); - OICFree(cred->owners); - OICFree(cred); - return NULL; - } + VERIFY_NON_NULL(TAG, cred->next->owners, ERROR); OICStrcpy((char *)cred->next->owners[0].id, sizeof(cred->next->owners[0].id), "ownersId21"); OICStrcpy((char *)cred->next->owners[1].id, sizeof(cred->next->owners[1].id), "ownersId22"); + + return cred; + +exit: + if(cred) + { + DeleteCredList(cred); + cred = NULL; + } return cred; } @@ -161,18 +161,75 @@ TEST(CreateCredResourceTest, CreateCredResource) TEST(CredEntityHandlerTest, CredEntityHandlerWithDummyRequest) { OCEntityHandlerRequest req; - EXPECT_EQ(OC_EH_ERROR, CredEntityHandler(OCEntityHandlerFlag::OC_REQUEST_FLAG, &req)); + EXPECT_EQ(OC_EH_ERROR, + CredEntityHandler(OCEntityHandlerFlag::OC_REQUEST_FLAG, &req)); } TEST(CredEntityHandlerTest, CredEntityHandlerWithNULLRequest) { - EXPECT_EQ(OC_EH_ERROR, CredEntityHandler(OCEntityHandlerFlag::OC_REQUEST_FLAG, NULL)); + EXPECT_EQ(OC_EH_ERROR, + CredEntityHandler(OCEntityHandlerFlag::OC_REQUEST_FLAG, NULL)); } TEST(CredEntityHandlerTest, CredEntityHandlerInvalidFlag) { OCEntityHandlerRequest req; - EXPECT_EQ(OC_EH_ERROR, CredEntityHandler(OCEntityHandlerFlag::OC_OBSERVE_FLAG, &req)); + EXPECT_EQ(OC_EH_ERROR, + CredEntityHandler(OCEntityHandlerFlag::OC_OBSERVE_FLAG, &req)); +} + +//Cred DELETE request +TEST(CredEntityHandlerTest, CredEntityHandlerDeleteTest) +{ + OCEntityHandlerRequest ehReq = OCEntityHandlerRequest(); + static OCPersistentStorage ps = OCPersistentStorage(); + const OicSecCred_t* subjectCred1 = NULL; + const OicSecCred_t* subjectCred2 = NULL; + char *jsonStr = NULL; + OCEntityHandlerResult ehRet = OC_EH_ERROR; + char query[] = "sub=c3ViamVjdDE="; + + SetPersistentHandler(&ps, true); + + OicSecCred_t *cred = getCredList(); + VERIFY_NON_NULL(TAG, cred, ERROR); + + jsonStr = BinToCredJSON(cred); + VERIFY_NON_NULL(TAG, jsonStr, ERROR); + + // Create Entity Handler POST request payload + ehReq.method = OC_REST_POST; + ehReq.payload = (OCPayload*)OCSecurityPayloadCreate(jsonStr); + ehRet = CredEntityHandler(OC_REQUEST_FLAG, &ehReq); + EXPECT_TRUE(OC_EH_ERROR == ehRet); + + // Verify if SRM contains Credential for the subject + subjectCred1 = GetCredResourceData(&cred->subject); + EXPECT_TRUE(NULL != subjectCred1); + + // Create Entity Handler DELETE request + ehReq.method = OC_REST_DELETE; + ehReq.query = (char*)OICMalloc(strlen(query)+1); + VERIFY_NON_NULL(TAG, ehReq.query, ERROR); + OICStrcpy(ehReq.query, strlen(query)+1, query); + + ehRet = CredEntityHandler(OC_REQUEST_FLAG, &ehReq); + EXPECT_TRUE(OC_EH_ERROR == ehRet); + + // Verify if SRM has deleted ACE for the subject + subjectCred2 = GetCredResourceData(&cred->subject); + EXPECT_TRUE(NULL == subjectCred2); + +exit: + // Perform cleanup + OICFree(ehReq.query); + OICFree(jsonStr); + OCPayloadDestroy(ehReq.payload); + if(NULL != cred) + { + DeInitCredResource(); + DeleteCredList(cred); + } } //BinToCredJSON Tests @@ -189,6 +246,7 @@ TEST(BinToCredJSONTest, BinToCredJSONValidCred) json = BinToCredJSON(cred); + OC_LOG_V(INFO, TAG, PCF("BinToCredJSON:%s\n"), json); EXPECT_TRUE(json != NULL); DeleteCredList(cred); OICFree(json); @@ -202,7 +260,7 @@ TEST(JSONToCredBinTest, JSONToCredBinValidJSON) EXPECT_TRUE(json != NULL); OicSecCred_t *cred2 = JSONToCredBin(json); - EXPECT_TRUE(cred2 == NULL); + EXPECT_TRUE(cred2 != NULL); DeleteCredList(cred1); DeleteCredList(cred2); OICFree(json); @@ -225,7 +283,7 @@ TEST(CredGenerateCredentialTest, GenerateCredentialValidInput) OicUuid_t owners[1]; OICStrcpy((char *)owners[0].id, sizeof(owners[0].id), "ownersId21"); - OicUuid_t subject = {0}; + OicUuid_t subject = {{0}}; OICStrcpy((char *)subject.id, sizeof(subject.id), "subject11"); char privateKey[] = "My private Key11"; @@ -236,6 +294,7 @@ TEST(CredGenerateCredentialTest, GenerateCredentialValidInput) privateKey, 1, owners); printCred(cred); + EXPECT_TRUE(NULL != cred); DeleteCredList(cred); } @@ -244,7 +303,7 @@ TEST(GenerateAndAddCredentialTest, GenerateAndAddCredentialValidInput) OicUuid_t owners[1]; OICStrcpy((char *)owners[0].id, sizeof(owners[0].id), "ownersId11"); - OicUuid_t subject = {0}; + OicUuid_t subject = {{0}}; OICStrcpy((char *)subject.id, sizeof(subject.id), "subject11"); char privateKey[] = "My private Key11"; diff --git a/resource/csdk/security/unittest/doxmresource.cpp b/resource/csdk/security/unittest/doxmresource.cpp index 5d68e03..cfee71a 100644 --- a/resource/csdk/security/unittest/doxmresource.cpp +++ b/resource/csdk/security/unittest/doxmresource.cpp @@ -25,11 +25,15 @@ #include "ocserverrequest.h" #include "oic_string.h" #include "oic_malloc.h" +#include "logger.h" + +#define TAG PCF("SRM-DOXM") #ifdef __cplusplus extern "C" { #endif + //Declare Doxm resource methods for testing OCStackResult CreateDoxmResource(); OCEntityHandlerResult DoxmEntityHandler (OCEntityHandlerFlag flag, @@ -44,6 +48,7 @@ OCEntityHandlerResult HandleDoxmGetRequest (const OCEntityHandlerRequest * ehReq } #endif + OicSecDoxm_t * getBinDoxm() { OicSecDoxm_t * doxm = (OicSecDoxm_t*)OICCalloc(1, sizeof(OicSecDoxm_t)); @@ -126,8 +131,8 @@ TEST(DoxmEntityHandlerTest, DoxmEntityHandlerInvalidFlag) TEST(DoxmEntityHandlerTest, DoxmEntityHandlerValidRequest) { EXPECT_EQ(OC_STACK_INVALID_PARAM, InitDoxmResource()); - char query[] = "oxm=0&owned=false&owner=owner1"; - OCEntityHandlerRequest req = {0}; + char query[] = "oxm=0;owned=false;owner=owner1"; + OCEntityHandlerRequest req = OCEntityHandlerRequest(); req.method = OC_REST_GET; req.query = OICStrdup(query); EXPECT_EQ(OC_EH_ERROR, DoxmEntityHandler(OCEntityHandlerFlag::OC_REQUEST_FLAG, &req)); @@ -147,6 +152,7 @@ TEST(BinToDoxmJSONTest, BinToDoxmJSONValidDoxm) OicSecDoxm_t * doxm = getBinDoxm(); char * json = BinToDoxmJSON(doxm); + OC_LOG_V(INFO, TAG, PCF("BinToDoxmJSON:%s"), json); EXPECT_TRUE(json != NULL); DeleteDoxmBinData(doxm); diff --git a/resource/csdk/security/unittest/iotvticalendartest.cpp b/resource/csdk/security/unittest/iotvticalendartest.cpp new file mode 100644 index 0000000..2d207cd --- /dev/null +++ b/resource/csdk/security/unittest/iotvticalendartest.cpp @@ -0,0 +1,302 @@ +// Copyright 2015 Intel Mobile Communications GmbH 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. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +//Not supported on Arduino due lack of absolute time need to implement iCalendar +#ifndef WITH_ARDUINO + +#include "gtest/gtest.h" +#include "iotvticalendar.h" +#include "logger.h" + +#define TAG PCF("CALENDAR-UT") + +static void printPeriod(IotvtICalPeriod_t *period) +{ + if(NULL == period) + { + return; + } + + OC_LOG_V(INFO, TAG, PCF("period->startDateTime.tm_year = %d"),period->startDateTime.tm_year); + OC_LOG_V(INFO, TAG, PCF("period->startDateTime.tm_mon = %d"),period->startDateTime.tm_mon); + OC_LOG_V(INFO, TAG, PCF("period->startDateTime.tm_mday = %d"),period->startDateTime.tm_mday); + OC_LOG_V(INFO, TAG, PCF("period->startDateTime.tm_hour = %d"),period->startDateTime.tm_hour); + OC_LOG_V(INFO, TAG, PCF("period->startDateTime.tm_min = %d"),period->startDateTime.tm_min); + OC_LOG_V(INFO, TAG, PCF("period->startDateTime.tm_sec = %d"),period->startDateTime.tm_sec); + + OC_LOG_V(INFO, TAG, PCF("period->endDateTime.tm_year = %d"),period->endDateTime.tm_year); + OC_LOG_V(INFO, TAG, PCF("period->endDateTime.tm_mon = %d"),period->endDateTime.tm_mon); + OC_LOG_V(INFO, TAG, PCF("period->endDateTime.tm_mday = %d"),period->endDateTime.tm_mday); + OC_LOG_V(INFO, TAG, PCF("period->endDateTime.tm_hour = %d"),period->endDateTime.tm_hour); + OC_LOG_V(INFO, TAG, PCF("period->endDateTime.tm_min = %d"),period->endDateTime.tm_min); + OC_LOG_V(INFO, TAG, PCF("period->startDateTime.tm_sec = %d"),period->endDateTime.tm_sec); +} + + +static void printRecur(IotvtICalRecur_t *recur) +{ + OC_LOG_V(INFO, TAG, PCF("recur->freq = %d"), recur->freq); + OC_LOG_V(INFO, TAG, PCF("recur->until.tm_year = %d"), recur->until.tm_year); + OC_LOG_V(INFO, TAG, PCF("recur->until.tm_mon = %d"), recur->until.tm_mon); + OC_LOG_V(INFO, TAG, PCF("recur->until.tm_mday = %d"), recur->until.tm_mday); + + if(recur->byDay & SUNDAY) + { + OC_LOG_V(INFO, TAG, PCF("recur->byDay = %s"), "Sunday"); + } + if(recur->byDay & MONDAY) + { + OC_LOG_V(INFO, TAG, PCF("recur->byDay = %s"), "Monday"); + } + if(recur->byDay & TUESDAY) + { + OC_LOG_V(INFO, TAG, PCF("recur->byDay = %s"), "Tuesday"); + } + if(recur->byDay & WEDNESDAY) + { + OC_LOG_V(INFO, TAG, PCF("recur->byDay = %s"), "Wednesday"); + } + if(recur->byDay & THURSDAY) + { + OC_LOG_V(INFO, TAG, PCF("recur->byDay = %s"), "Thursday"); + } + if(recur->byDay & FRIDAY) + { + OC_LOG_V(INFO, TAG, PCF("recur->byDay = %s"), "Friday"); + } + if(recur->byDay & SATURDAY) + { + OC_LOG_V(INFO, TAG, PCF("recur->byDay = %s"), "Saturday"); + } +} + +//ParsePeriod Tests +TEST(ParsePeriodTest, ParsePeriodValidDateTime) +{ + char periodStr[] = "20150629T153050/20150630T233055"; + IotvtICalPeriod_t period = IotvtICalPeriod_t(); + EXPECT_EQ(IOTVTICAL_SUCCESS, ParsePeriod(periodStr,&period)); + printPeriod(&period); +} + +TEST(ParsePeriodTest, ParsePeriodValidDate) +{ + char periodStr[] = "20150629/20150630"; + IotvtICalPeriod_t period = IotvtICalPeriod_t(); + EXPECT_EQ(IOTVTICAL_SUCCESS, ParsePeriod(periodStr,&period)); + printPeriod(&period); +} + +TEST(ParsePeriodTest, ParsePeriodMismatchStartDTEndDT1) +{ + char periodStr[] = "20150629T153050/20150630"; + IotvtICalPeriod_t period = IotvtICalPeriod_t(); + EXPECT_EQ(IOTVTICAL_INVALID_PERIOD, ParsePeriod(periodStr,&period)); +} + +TEST(ParsePeriodTest, ParsePeriodMismatchStartDTEndDT2) +{ + char periodStr[] = "20150629/20150630T203055"; + IotvtICalPeriod_t period = IotvtICalPeriod_t(); + EXPECT_EQ(IOTVTICAL_INVALID_PERIOD, ParsePeriod(periodStr,&period)); +} + +TEST(ParsePeriodTest, ParsePeriodInvalidStartDT1) +{ + char periodStr[] = "20150629T1530/20150630T203055"; + IotvtICalPeriod_t period = IotvtICalPeriod_t(); + EXPECT_EQ(IOTVTICAL_INVALID_PERIOD, ParsePeriod(periodStr,&period)); +} + +TEST(ParsePeriodTest, ParsePeriodInvalidEndtDT2) +{ + char periodStr[] = "20150629T153050/20150630203055"; + IotvtICalPeriod_t period = IotvtICalPeriod_t(); + EXPECT_EQ(IOTVTICAL_INVALID_PERIOD, ParsePeriod(periodStr,&period)); +} + +TEST(ParsePeriodTest, ParsePeriodInvalidStartD3) +{ + char periodStr[] = "201506/20150630"; + IotvtICalPeriod_t period = IotvtICalPeriod_t(); + EXPECT_EQ(IOTVTICAL_INVALID_PERIOD, ParsePeriod(periodStr,&period)); +} + +TEST(ParsePeriodTest, ParsePeriodInvalidEndD4) +{ + char periodStr[] = "20150629/201530"; + IotvtICalPeriod_t period = IotvtICalPeriod_t(); + EXPECT_EQ(IOTVTICAL_INVALID_PERIOD, ParsePeriod(periodStr,&period)); +} + +TEST(ParsePeriodTest, ParsePeriodEndDTBeforeStartDT) +{ + char periodStr[] = "20150630T203055/20150629T153050"; + IotvtICalPeriod_t period = IotvtICalPeriod_t(); + EXPECT_EQ(IOTVTICAL_INVALID_PERIOD, ParsePeriod(periodStr,&period)); +} +TEST(ParsePeriodTest, ParsePeriodEndDBeforeStartD) +{ + char periodStr[] = "20150630/20150629"; + IotvtICalPeriod_t period = IotvtICalPeriod_t(); + EXPECT_EQ(IOTVTICAL_INVALID_PERIOD, ParsePeriod(periodStr,&period)); +} + +TEST(ParseRecurTest, ParseRecurValid1) +{ + char recurStr[] = "FREQ=DAILY; UNTIL=20150703; BYDAY=MO, WE, FR"; + IotvtICalRecur_t recur = IotvtICalRecur_t(); + EXPECT_EQ(IOTVTICAL_SUCCESS, ParseRecur(recurStr, &recur)); + printRecur(&recur); +} + +TEST(ParseRecurTest, ParseRecurValid2) +{ + char recurStr[] = "FREQ=DAILY"; + IotvtICalRecur_t recur = IotvtICalRecur_t(); + EXPECT_EQ(IOTVTICAL_SUCCESS, ParseRecur(recurStr, &recur)); + printRecur(&recur); +} + +TEST(ParseRecurTest, ParseRecurInValidFreq1) +{ + char recurStr[] = "FREQ=WEEKLY; UNTIL=20150703; BYDAY=TU"; + IotvtICalRecur_t recur = IotvtICalRecur_t(); + EXPECT_EQ(IOTVTICAL_INVALID_RRULE, ParseRecur(recurStr, &recur)); +} + +TEST(ParseRecurTest, ParseRecurInValidFreq2) +{ + char recurStr[] = "UNTIL=20150703; BYDAY=TU"; + IotvtICalRecur_t recur = IotvtICalRecur_t(); + EXPECT_EQ(IOTVTICAL_INVALID_RRULE, ParseRecur(recurStr, &recur)); +} + +TEST(ParseRecurTest, ParseRecurInValidUntil) +{ + char recurStr[] = "FREQ=DAILY; UNTIL=20150703T095055; BYDAY=MO, WE, FR"; + IotvtICalRecur_t recur = IotvtICalRecur_t(); + EXPECT_EQ(IOTVTICAL_INVALID_RRULE, ParseRecur(recurStr, &recur)); +} + +TEST(ParseRecurTest, ParseRecurInValidByday) +{ + char recurStr[] = "FREQ=DAILY; UNTIL=20150703; BYDAY="; + IotvtICalRecur_t recur = IotvtICalRecur_t(); + EXPECT_EQ(IOTVTICAL_INVALID_RRULE, ParseRecur(recurStr, &recur)); +} + +//FIXME: ALL IsRequestWithinValidTime tests will fail after 20151230 +TEST(IsRequestWithinValidTimeTest, IsRequestWithinValidTimeValidPeriod1) +{ + char periodStr[] = "20150630/20151230"; + EXPECT_EQ(IOTVTICAL_VALID_ACCESS, IsRequestWithinValidTime(periodStr, NULL)); +} + +TEST(IsRequestWithinValidTimeTest, IsRequestWithinValidTimeValidPeriodAndRecur1) +{ + //Daily on days MO, WE & FR from 6:00:00am to 8:00:00pm until 20151230 + char recurStr[] = "FREQ=DAILY; UNTIL=20151230; BYDAY=MO, WE, FR"; + char periodStr[] = "20150630T060000/20150630T200000"; + + time_t rt = time(0); + IotvtICalDateTime_t *ct = localtime(&rt); + + int byDay = MONDAY | WEDNESDAY | FRIDAY; + int isValidWD = (0x1 << ct->tm_wday) & byDay; + + if(isValidWD && 6 <= ct->tm_hour && 20>= ct->tm_hour) + { + EXPECT_EQ(IOTVTICAL_VALID_ACCESS, IsRequestWithinValidTime(periodStr, recurStr)); + } + else + { + EXPECT_EQ(IOTVTICAL_INVALID_ACCESS, IsRequestWithinValidTime(periodStr, recurStr)); + } +} + +TEST(IsRequestWithinValidTimeTest, IsRequestWithinValidTimeValidPeriodAndRecur2) +{ + //Daily forever from 6:00:00am to 8:00:00pm + char recurStr[] = "FREQ=DAILY"; + char periodStr[] = "20150630T060000/20150630T200000"; + + time_t rt = time(0); + IotvtICalDateTime_t *ct = localtime(&rt); + + if(6 <= ct->tm_hour && 20>= ct->tm_hour) + { + EXPECT_EQ(IOTVTICAL_VALID_ACCESS, IsRequestWithinValidTime(periodStr, recurStr)); + } + else + { + EXPECT_EQ(IOTVTICAL_INVALID_ACCESS, IsRequestWithinValidTime(periodStr, recurStr)); + } +} + +TEST(IsRequestWithinValidTimeTest, IsRequestWithinValidTimeValidPeriodAndRecur3) +{ + //Daily until 20151230 from 6:00:00am to 8:00:00pm + char recurStr[] = "FREQ=DAILY; UNTIL=20151230"; + char periodStr[] = "20150630T060000/20150630T200000"; + + time_t rt = time(0); + IotvtICalDateTime_t *ct = localtime(&rt); + + if(6 <= ct->tm_hour && 20>= ct->tm_hour) + { + EXPECT_EQ(IOTVTICAL_VALID_ACCESS, IsRequestWithinValidTime(periodStr, recurStr)); + } + else + { + EXPECT_EQ(IOTVTICAL_INVALID_ACCESS, IsRequestWithinValidTime(periodStr, recurStr)); + } +} + +TEST(IsRequestWithinValidTimeTest, IsRequestWithinValidTimeValidPeriodAndRecur4) +{ + //Daily forever on days MO, WE & Fr from 6:00:00am to 8:00:00pm + char recurStr[] = "FREQ=DAILY; BYDAY=MO, WE, FR"; + char periodStr[] = "20150630T060000/20150630T200000"; + + time_t rt = time(0); + IotvtICalDateTime_t *ct = localtime(&rt); + + int byDay = MONDAY | WEDNESDAY | FRIDAY; + int isValidWD = (0x1 << ct->tm_wday) & byDay; + + if(isValidWD && 6 <= ct->tm_hour && 20>= ct->tm_hour) + { + EXPECT_EQ(IOTVTICAL_VALID_ACCESS, IsRequestWithinValidTime(periodStr, recurStr)); + } + else + { + EXPECT_EQ(IOTVTICAL_INVALID_ACCESS, IsRequestWithinValidTime(periodStr, recurStr)); + } +} + +TEST(IsRequestWithinValidTimeTest, IsRequestWithinValidTimeInValidPeriodAndValidRecur) +{ + //Daily forever on days MO, WE & Fr + char recurStr[] = "FREQ=DAILY; BYDAY=MO, WE, FR"; + char periodStr[] = "20150630/20150730"; + + EXPECT_EQ(IOTVTICAL_INVALID_ACCESS, IsRequestWithinValidTime(periodStr, recurStr)); +} + +#endif diff --git a/resource/csdk/security/unittest/oic_unittest.json b/resource/csdk/security/unittest/oic_unittest.json index 9ebfbdd..54cd36a 100644 --- a/resource/csdk/security/unittest/oic_unittest.json +++ b/resource/csdk/security/unittest/oic_unittest.json @@ -33,5 +33,45 @@ "tm": 48, "om": 0, "sm": [3, 1] - } + }, + + "amacl": [ + { + "rsrc": ["/a/led", "/a/fan"], + "amss": [ + "NTU1NTU1NTU1NTU1NTU1NQ==", + "NjY2NjY2NjY2NjY2NjY2Ng==" + ], + "ownrs" : [ + "MjIyMjIyMjIyMjIyMjIyMg==" + ] + }, + { + "rsrc": ["/b/led", "/b/fan"], + "amss": [ + "NTU1NTU1NTU1NTU1NTU1NQ==", + "NjY2NjY2NjY2NjY2NjY2Ng==" + ], + "ownrs" : [ + "MjIyMjIyMjIyMjIyMjIyMg==" + ] + } + ], + +"svc": [ + { + "svcdid": "NTU1NTU1NTU1NTU1NTU1NQ==", + "svct": 1, + "ownrs" : [ + "OTk5OTk5OTk5OTk5OTk5OQ==" + ] + }, + { + "svcdid": "NjY2NjY2NjY2NjY2NjY2Ng==", + "svct": 1, + "ownrs" : [ + "OTk5OTk5OTk5OTk5OTk5OQ==" + ] + } + ] } diff --git a/resource/csdk/security/unittest/pstatresource.cpp b/resource/csdk/security/unittest/pstatresource.cpp index c899ea5..03c8a68 100644 --- a/resource/csdk/security/unittest/pstatresource.cpp +++ b/resource/csdk/security/unittest/pstatresource.cpp @@ -27,6 +27,7 @@ #include "base64.h" #include "cainterface.h" #include "secureresourcemanager.h" +#include "srmtestcommon.h" #include "ocpayload.h" #include #ifdef __cplusplus @@ -38,7 +39,6 @@ OCEntityHandlerResult PstatEntityHandler (OCEntityHandlerFlag flag, OCEntityHandlerRequest * ehRequest); char * BinToPstatJSON(const OicSecPstat_t * pstat); OicSecPstat_t * JSONToPstatBin(const char * jsonStr); -char* ReadFile(const char* filename); const char* UNIT_TEST_JSON_FILE_NAME = "oic_unittest.json"; #ifdef __cplusplus } diff --git a/resource/csdk/security/unittest/srmtestcommon.cpp b/resource/csdk/security/unittest/srmtestcommon.cpp new file mode 100644 index 0000000..6f51329 --- /dev/null +++ b/resource/csdk/security/unittest/srmtestcommon.cpp @@ -0,0 +1,73 @@ +//****************************************************************** +// +// Copyright 2015 Intel Mobile Communications GmbH 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 "gtest/gtest.h" +#include "oic_malloc.h" +#include "ocstack.h" + +char* ReadFile(const char* filename) +{ + + FILE *fp = NULL; + char *data = NULL; + struct stat st; + // TODO: Find the location of the executable and concatenate the SVR file name + // before opening it. + fp = fopen(filename, "r"); + if (fp) + { + if (stat(filename, &st) == 0) + { + data = (char*)OICMalloc(st.st_size); + if (data) + { + if (fread(data, 1, st.st_size, fp) != (size_t)st.st_size) + { + printf("Error in reading file %s", filename); + } + } + } + fclose(fp); + } + else + { + printf("Unable to open %s file", filename); + } + + return data; +} + +void SetPersistentHandler(OCPersistentStorage *ps, bool set) +{ + if (set) + { + ps->open = fopen; + ps->read = fread; + ps->write = fwrite; + ps->close = fclose; + ps->unlink = unlink; + } + else + { + memset(ps, 0, sizeof(OCPersistentStorage)); + } + EXPECT_EQ(OC_STACK_OK, + OCRegisterPersistentStorageHandler(ps)); +} diff --git a/resource/csdk/security/unittest/srmtestcommon.h b/resource/csdk/security/unittest/srmtestcommon.h new file mode 100644 index 0000000..1a8685e --- /dev/null +++ b/resource/csdk/security/unittest/srmtestcommon.h @@ -0,0 +1,27 @@ +//****************************************************************** +// +// Copyright 2015 Intel Mobile Communications GmbH 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 IOTVT_SRM_TEST_COMMON_H +#define IOTVT_SRM_TEST_COMMON_H + +char* ReadFile(const char* filename); +void SetPersistentHandler(OCPersistentStorage *ps, bool set); + +#endif //IOTVT_SRM_TEST_COMMON_H diff --git a/resource/csdk/security/unittest/srmutility.cpp b/resource/csdk/security/unittest/srmutility.cpp index 225e3e3..0464d5a 100644 --- a/resource/csdk/security/unittest/srmutility.cpp +++ b/resource/csdk/security/unittest/srmutility.cpp @@ -21,37 +21,36 @@ #include "srmutility.h" #include "oic_string.h" - //ParseRestQuery Tests TEST(ParseRestQueryTest, ParseRestQueryEmpty) { unsigned char query[] = ""; - OicParseQueryIter_t parseIter = {0}; + OicParseQueryIter_t parseIter = OicParseQueryIter_t(); ParseQueryIterInit(query, &parseIter); EXPECT_EQ(NULL, GetNextQuery(&parseIter)); } + TEST(ParseRestQueryTest, ParseSingleRestQuery) { char attr[10], val[10]; unsigned char query[] = "owned=false"; - OicParseQueryIter_t parseIter = {0}; + OicParseQueryIter_t parseIter = OicParseQueryIter_t(); ParseQueryIterInit(query, &parseIter); EXPECT_NE((OicParseQueryIter_t *)NULL, GetNextQuery(&parseIter)); OICStrcpyPartial(attr, sizeof(attr), (char *)parseIter.attrPos, parseIter.attrLen); OICStrcpyPartial(val, sizeof(val), (char *)parseIter.valPos, parseIter.valLen); printf("\nAttribute: %s value: %s\n\n", attr, val); - } TEST(ParseRestQueryTest, ParseRestMultipleQuery) { char attr[10], val[10]; - unsigned char query[] = "oxm=0&owned=true&owner=owner1"; + unsigned char query[] = "oxm=0;owned=true;owner=owner1"; - OicParseQueryIter_t parseIter = {0}; + OicParseQueryIter_t parseIter = OicParseQueryIter_t(); ParseQueryIterInit(query, &parseIter); printf("\n"); while(GetNextQuery(&parseIter)) diff --git a/resource/csdk/security/unittest/svcresourcetest.cpp b/resource/csdk/security/unittest/svcresourcetest.cpp new file mode 100644 index 0000000..5c3f75e --- /dev/null +++ b/resource/csdk/security/unittest/svcresourcetest.cpp @@ -0,0 +1,81 @@ +//****************************************************************** +// +// Copyright 2015 Intel Mobile Communications GmbH 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 "gtest/gtest.h" +#include +#include +#include +#include +#include "ocstack.h" +#include "oic_malloc.h" +#include "cJSON.h" +#include "cainterface.h" +#include "secureresourcemanager.h" +#include "securevirtualresourcetypes.h" +#include "srmresourcestrings.h" +#include "svcresource.h" +#include "srmtestcommon.h" + +using namespace std; + +#ifdef __cplusplus +extern "C" { +#endif +extern char * BinToSvcJSON(const OicSecSvc_t * svc); +extern OicSecSvc_t * JSONToSvcBin(const char * jsonStr); +extern void DeleteSVCList(OicSecSvc_t* svc); +#ifdef __cplusplus +} +#endif + +static const char* JSON_FILE_NAME = "oic_unittest.json"; + +#define NUM_SVC_IN_JSON_DB (2) + + +// JSON Marshalling Tests +TEST(SVCResourceTest, JSONMarshallingTests) +{ + char *jsonStr1 = ReadFile(JSON_FILE_NAME); + if (jsonStr1) + { + OicSecSvc_t * svc = JSONToSvcBin(jsonStr1); + EXPECT_TRUE(NULL != svc); + + int cnt = 0; + OicSecSvc_t * tempSvc = svc; + while(tempSvc) + { + + EXPECT_EQ(tempSvc->svct, ACCESS_MGMT_SERVICE); + cnt++; + tempSvc = tempSvc->next; + } + EXPECT_EQ(cnt, NUM_SVC_IN_JSON_DB); + + char * jsonStr2 = BinToSvcJSON(svc); + EXPECT_TRUE(NULL != jsonStr2); + + OICFree(jsonStr1); + OICFree(jsonStr2); + DeleteSVCList(svc); + } +} + diff --git a/resource/csdk/stack/samples/linux/secure/occlientbasicops.h b/resource/csdk/stack/samples/linux/secure/occlientbasicops.h index 3fed75a..4a07306 100644 --- a/resource/csdk/stack/samples/linux/secure/occlientbasicops.h +++ b/resource/csdk/stack/samples/linux/secure/occlientbasicops.h @@ -24,6 +24,11 @@ #include "ocstack.h" //----------------------------------------------------------------------------- +// Defines +//----------------------------------------------------------------------------- +#define DEFAULT_CONTEXT_VALUE 0x99 + +//----------------------------------------------------------------------------- // Typedefs //----------------------------------------------------------------------------- diff --git a/resource/csdk/stack/samples/linux/secure/ocserverbasicops.cpp b/resource/csdk/stack/samples/linux/secure/ocserverbasicops.cpp index 37df0ac..a48bc3f 100644 --- a/resource/csdk/stack/samples/linux/secure/ocserverbasicops.cpp +++ b/resource/csdk/stack/samples/linux/secure/ocserverbasicops.cpp @@ -30,6 +30,7 @@ #include "ocserverbasicops.h" #include "common.h" + int gQuitFlag = 0; static LEDResource LED; @@ -226,12 +227,12 @@ OCEntityHandlerResult ProcessPostRequest (OCEntityHandlerRequest *ehRequest, OCEntityHandlerResult OCEntityHandlerCb (OCEntityHandlerFlag flag, OCEntityHandlerRequest *entityHandlerRequest, - void* callbackParam) + void* /*callbackParam*/) { OC_LOG_V (INFO, TAG, "Inside entity handler - flags: 0x%x", flag); OCEntityHandlerResult ehResult = OC_EH_ERROR; - OCEntityHandlerResponse response = {}; + OCEntityHandlerResponse response = OCEntityHandlerResponse(); // Validate pointer if (!entityHandlerRequest) @@ -311,14 +312,14 @@ FILE* server_fopen(const char *path, const char *mode) return fopen(CRED_FILE, mode); } -int main(int argc, char* argv[]) +int main(int /*argc*/, char* /*argv*/[]) { struct timespec timeout; OC_LOG(DEBUG, TAG, "OCServer is starting..."); // Initialize Persistent Storage for SVR database - OCPersistentStorage ps = {}; + OCPersistentStorage ps = OCPersistentStorage(); ps.open = server_fopen; ps.read = fread; ps.write = fwrite; diff --git a/resource/csdk/stack/samples/linux/secure/oic_svr_db_client.json b/resource/csdk/stack/samples/linux/secure/oic_svr_db_client.json index 17dc43f..5a2cc55 100644 --- a/resource/csdk/stack/samples/linux/secure/oic_svr_db_client.json +++ b/resource/csdk/stack/samples/linux/secure/oic_svr_db_client.json @@ -8,7 +8,8 @@ "/oic/p", "/oic/res/types/d", "/oic/ad", - "/oic/sec/acl" + "/oic/sec/acl", + "/oic/sec/amacl" ], "perms": 2, "ownrs" : ["MjIyMjIyMjIyMjIyMjIyMg=="] diff --git a/resource/csdk/stack/samples/linux/secure/oic_svr_db_server.json b/resource/csdk/stack/samples/linux/secure/oic_svr_db_server.json index 1f8ad5c..8621818 100644 --- a/resource/csdk/stack/samples/linux/secure/oic_svr_db_server.json +++ b/resource/csdk/stack/samples/linux/secure/oic_svr_db_server.json @@ -8,7 +8,8 @@ "/oic/p", "/oic/res/types/d", "/oic/ad", - "/oic/sec/acl" + "/oic/sec/acl", + "/oic/sec/amacl" ], "perms": 2, "ownrs" : ["MTExMTExMTExMTExMTExMQ=="] @@ -24,8 +25,31 @@ }, { "sub": "MjIyMjIyMjIyMjIyMjIyMg==", + "rsrc": ["/oic/sec/acl", + "/oic/sec/cred"], + "perms": 8, + "ownrs" : ["MjIyMjIyMjIyMjIyMjIyMg=="] + }, + { + "sub": "MjIyMjIyMjIyMjIyMjIyMg==", + "rsrc": ["/a/led"], + "perms": 6, + "ownrs" : ["MjIyMjIyMjIyMjIyMjIyMg=="] + }, + { + "sub": "MTExMTIyMjIzMzMzNDQ0NA==", "rsrc": ["/a/led"], "perms": 6, + "prds" : ["20150630T060000/20150630T220000", "20150630T060000/20150630T200000"], + "recurs" : ["FREQ=DAILY; BYDAY=MO, WE, FR", "FREQ=DAILY; BYDAY=TU, TH; UNTIL=20160630"], + "ownrs" : ["MjIyMjIyMjIyMjIyMjIyMg=="] + }, + { + "sub": "Nzc3Nzc3Nzc3Nzc3Nzc3Nw==", + "rsrc": ["/a/led"], + "perms": 6, + "prds" : ["20150630T060000/20150630T220000"], + "recurs" : ["FREQ=DAILY; UNTIL=20150630"], "ownrs" : ["MjIyMjIyMjIyMjIyMjIyMg=="] } ], @@ -43,7 +67,7 @@ "oxmsel": 0, "owned": true, "deviceid": "MTExMTExMTExMTExMTExMQ==", - "ownr": "MjIyMjIyMjIyMjIyMjIyMg==" + "ownr": "YWRtaW5EZXZpY2VVVUlEAA==" }, "cred": [{ "credid": 1, @@ -51,5 +75,19 @@ "credtyp": 1, "pvdata": "QUFBQUFBQUFBQUFBQUFBQQ==", "ownrs" : ["MjIyMjIyMjIyMjIyMjIyMg=="] + }, + { + "credid": 2, + "sub": "MTExMTIyMjIzMzMzNDQ0NA==", + "credtyp": 1, + "pvdata": "QUFBQUFBQUFBQUFBQUFBQQ==", + "ownrs" : ["MjIyMjIyMjIyMjIyMjIyMg=="] + }, + { + "credid": 3, + "sub": "Nzc3Nzc3Nzc3Nzc3Nzc3Nw==", + "credtyp": 1, + "pvdata": "QUFBQUFBQUFBQUFBQUFBQQ==", + "ownrs" : ["MjIyMjIyMjIyMjIyMjIyMg=="] }] } diff --git a/resource/csdk/stack/samples/tizen/build/packaging/com.oic.ri.spec b/resource/csdk/stack/samples/tizen/build/packaging/com.oic.ri.spec index a5a7128..9ec2214 100644 --- a/resource/csdk/stack/samples/tizen/build/packaging/com.oic.ri.spec +++ b/resource/csdk/stack/samples/tizen/build/packaging/com.oic.ri.spec @@ -63,6 +63,7 @@ cp resource/oc_logger/include/targets/oc_console_logger.h %{DEST_INC_DIR} cp resource/oc_logger/include/targets/oc_ostream_logger.h %{DEST_INC_DIR} cp resource/csdk/stack/include/ocpresence.h %{DEST_INC_DIR} cp resource/csdk/stack/include/ocpayload.h %{DEST_INC_DIR} +cp resource/c_common/platform_features.h %{DEST_INC_DIR} cp extlibs/cjson/cJSON.h %{DEST_INC_DIR} cp -rf %{ROOTDIR}/com.oic.ri.pc %{DEST_LIB_DIR}/pkgconfig/ diff --git a/resource/csdk/stack/src/ocserverrequest.c b/resource/csdk/stack/src/ocserverrequest.c index 43efdc5..0390061 100644 --- a/resource/csdk/stack/src/ocserverrequest.c +++ b/resource/csdk/stack/src/ocserverrequest.c @@ -509,6 +509,15 @@ OCStackResult HandleSingleResponse(OCEntityHandlerResponse * ehResponse) // Put the JSON prefix and suffix around the payload if(ehResponse->payload) { + if (ehResponse->payload->type == PAYLOAD_TYPE_PRESENCE) + { + responseInfo.isMulticast = true; + } + else + { + responseInfo.isMulticast = false; + } + OCStackResult result; if((result = OCConvertPayload(ehResponse->payload, &responseInfo.info.payload, &responseInfo.info.payloadSize)) @@ -529,6 +538,7 @@ OCStackResult HandleSingleResponse(OCEntityHandlerResponse * ehResponse) } else { + responseInfo.isMulticast = false; responseInfo.info.payload = NULL; responseInfo.info.payloadSize = 0; } diff --git a/resource/csdk/stack/src/ocstack.c b/resource/csdk/stack/src/ocstack.c index e438bc6..654b785 100644 --- a/resource/csdk/stack/src/ocstack.c +++ b/resource/csdk/stack/src/ocstack.c @@ -399,6 +399,7 @@ void CopyEndpointToDevAddr(const CAEndpoint_t *in, OCDevAddr *out) out->flags = CAToOCTransportFlags(in->flags); OICStrcpy(out->addr, sizeof(out->addr), in->addr); out->port = in->port; + out->interface = in->interface; } void CopyDevAddrToEndpoint(const OCDevAddr *in, CAEndpoint_t *out) @@ -410,36 +411,7 @@ void CopyDevAddrToEndpoint(const OCDevAddr *in, CAEndpoint_t *out) out->flags = OCToCATransportFlags(in->flags); OICStrcpy(out->addr, sizeof(out->addr), in->addr); out->port = in->port; -} - -static OCStackResult OCCreateEndpoint(OCDevAddr *devAddr, CAEndpoint_t **endpoint) -{ - VERIFY_NON_NULL(devAddr, FATAL, OC_STACK_INVALID_PARAM); - VERIFY_NON_NULL(endpoint, FATAL, OC_STACK_INVALID_PARAM); - - CAEndpoint_t *ep = (CAEndpoint_t *)OICMalloc(sizeof (CAEndpoint_t)); - if (!ep) - { - return OC_STACK_NO_MEMORY; - } - - ep->adapter = (CATransportAdapter_t)devAddr->adapter; - if (!ep->adapter) - { - ep->adapter = CA_ADAPTER_IP; - } - ep->flags = OCToCATransportFlags(devAddr->flags); - OICStrcpy(ep->addr, sizeof(ep->addr), devAddr->addr); - ep->port = devAddr->port; - - *endpoint = ep; - - return OC_STACK_OK; -} - -static void OCDestroyEndpoint(CAEndpoint_t *endpoint) -{ - free(endpoint); + out->interface = in->interface; } void FixUpClientResponse(OCClientResponse *cr) @@ -832,8 +804,6 @@ OCStackResult HandlePresenceResponse(const CAEndpoint_t *endpoint, // check for multiicast presence CAEndpoint_t ep = { .adapter = endpoint->adapter, .flags = endpoint->flags }; - OICStrcpy(ep.addr, sizeof(ep.addr), OC_MULTICAST_IP); - ep.port = OC_MULTICAST_PORT; uriLen = FormCanonicalPresenceUri(&ep, OC_RSRVD_PRESENCE_URI, presenceUri); @@ -2003,7 +1973,7 @@ OCStackResult OCDoResource(OCDoHandle *handle, uint8_t tokenLength = CA_MAX_TOKEN_LEN; ClientCB *clientCB = NULL; OCDoHandle resHandle = NULL; - CAEndpoint_t *endpoint = NULL; + CAEndpoint_t endpoint = {.adapter = CA_DEFAULT_ADAPTER}; OCDevAddr tmpDevAddr = { OC_DEFAULT_ADAPTER }; uint32_t ttl = 0; OCTransportAdapter adapter; @@ -2141,8 +2111,8 @@ OCStackResult OCDoResource(OCDoHandle *handle, requestInfo.info.numOptions = numOptions; } - // create remote endpoint - result = OCCreateEndpoint(devAddr, &endpoint); + CopyDevAddrToEndpoint(devAddr, &endpoint); + if(payload) { if((result = @@ -2159,8 +2129,6 @@ OCStackResult OCDoResource(OCDoHandle *handle, requestInfo.info.payloadSize = 0; } - - if (result != OC_STACK_OK) { OC_LOG(ERROR, TAG, PCF("CACreateEndpoint error")); @@ -2172,7 +2140,7 @@ OCStackResult OCDoResource(OCDoHandle *handle, if (method == OC_REST_PRESENCE) { char *presenceUri = NULL; - result = OCPreparePresence(endpoint, resourceUri, &presenceUri); + result = OCPreparePresence(&endpoint, resourceUri, &presenceUri); if (OC_STACK_OK != result) { goto exit; @@ -2198,7 +2166,7 @@ OCStackResult OCDoResource(OCDoHandle *handle, resourceType = NULL; // Client CB list entry now owns it // send request - caResult = CASendRequest(endpoint, &requestInfo); + caResult = CASendRequest(&endpoint, &requestInfo); if (caResult != CA_STATUS_OK) { OC_LOG(ERROR, TAG, PCF("CASendRequest")); @@ -2230,7 +2198,6 @@ exit: OICFree(devAddr); OICFree(resourceUri); OICFree(resourceType); - OICFree(endpoint); if (hdrOptionMemAlloc) { OICFree(requestInfo.info.options); @@ -2259,7 +2226,7 @@ OCStackResult OCCancel(OCDoHandle handle, OCQualityOfService qos, OCHeaderOption * Remove the callback associated on client side. */ OCStackResult ret = OC_STACK_OK; - CAEndpoint_t* endpoint = NULL; + CAEndpoint_t endpoint = {.adapter = CA_DEFAULT_ADAPTER}; CAResult_t caResult; CAInfo_t requestData = {.type = CA_MSG_CONFIRM}; CARequestInfo_t requestInfo = {.method = CA_GET}; @@ -2306,15 +2273,10 @@ OCStackResult OCCancel(OCDoHandle handle, OCQualityOfService qos, OCHeaderOption requestInfo.method = CA_GET; requestInfo.info = requestData; - ret = OCCreateEndpoint(clientCB->devAddr, &endpoint); - if (ret != OC_STACK_OK) - { - OC_LOG(ERROR, TAG, PCF("CACreateEndpoint error")); - goto Error; - } + CopyDevAddrToEndpoint(clientCB->devAddr, &endpoint); // send request - caResult = CASendRequest(endpoint, &requestInfo); + caResult = CASendRequest(&endpoint, &requestInfo); if (caResult != CA_STATUS_OK) { OC_LOG(ERROR, TAG, PCF("CASendRequest error")); @@ -2335,7 +2297,6 @@ OCStackResult OCCancel(OCDoHandle handle, OCQualityOfService qos, OCHeaderOption } Error: - OCDestroyEndpoint(endpoint); if (requestData.numOptions > 0) { OICFree(requestData.options); @@ -2344,7 +2305,6 @@ Error: { OICFree (requestData.resourceUri); } - return ret; } @@ -2442,18 +2402,13 @@ OCStackResult OCProcessPresence() } CAResult_t caResult = CA_STATUS_OK; - CAEndpoint_t* endpoint = NULL; + CAEndpoint_t endpoint = {.adapter = CA_DEFAULT_ADAPTER}; CAInfo_t requestData = {.type = CA_MSG_CONFIRM}; CARequestInfo_t requestInfo = {.method = CA_GET}; OC_LOG(DEBUG, TAG, PCF("time to test server presence")); - result = OCCreateEndpoint(cbNode->devAddr, &endpoint); - if (result != OC_STACK_OK) - { - OC_LOG(ERROR, TAG, PCF("CACreateEndpoint error")); - goto exit; - } + CopyDevAddrToEndpoint(cbNode->devAddr, &endpoint); requestData.type = CA_MSG_NONCONFIRM; requestData.token = cbNode->token; @@ -2462,8 +2417,7 @@ OCStackResult OCProcessPresence() requestInfo.method = CA_GET; requestInfo.info = requestData; - caResult = CASendRequest(endpoint, &requestInfo); - OCDestroyEndpoint(endpoint); + caResult = CASendRequest(&endpoint, &requestInfo); if (caResult != CA_STATUS_OK) { @@ -2479,6 +2433,7 @@ exit: { OC_LOG(ERROR, TAG, PCF("OCProcessPresence error")); } + return result; } #endif // WITH_PRESENCE @@ -2522,8 +2477,6 @@ OCStackResult OCStartPresence(const uint32_t ttl) presenceState = OC_PRESENCE_INITIALIZED; OCDevAddr devAddr = { OC_DEFAULT_ADAPTER }; - OICStrcpy(devAddr.addr, sizeof(devAddr.addr), OC_MULTICAST_IP); - devAddr.port = OC_MULTICAST_PORT; CAToken_t caToken = NULL; CAResult_t caResult = CAGenerateToken(&caToken, tokenLength); diff --git a/resource/csdk/stack/src/oicgroup.c b/resource/csdk/stack/src/oicgroup.c index 1ff11a8..3dd175d 100644 --- a/resource/csdk/stack/src/oicgroup.c +++ b/resource/csdk/stack/src/oicgroup.c @@ -731,8 +731,14 @@ exit: OCStackResult BuildStringFromActionSet(OCActionSet* actionset, char** desc) { + // Can't use the macros here as they are hardcoded to 'exit' and will + // result in dereferencing a null pointer. + if (!actionset || !desc) + { + return OC_STACK_INVALID_PARAM; + } char temp[1024] = { 0 }; - int remaining = 1023; + size_t remaining = sizeof(temp) - 1; OCStackResult res = OC_STACK_ERROR; OCAction *action = actionset->head; @@ -752,6 +758,11 @@ OCStackResult BuildStringFromActionSet(OCActionSet* actionset, char** desc) while (action != NULL) { + if (remaining < (strlen("uri=") + strlen(action->resourceUri) + 1)) + { + res = OC_STACK_ERROR; + goto exit; + } strcat(temp, "uri="); remaining -= strlen("uri="); strcat(temp, action->resourceUri); @@ -762,16 +773,28 @@ OCStackResult BuildStringFromActionSet(OCActionSet* actionset, char** desc) OCCapability *capas = action->head; while (capas != NULL) { + if (remaining < (strlen(capas->capability) + + 1 + strlen(capas->status))) + { + res = OC_STACK_ERROR; + goto exit; + } + strcat(temp, capas->capability); remaining -= strlen(capas->capability); strcat(temp, "="); remaining--; strcat(temp, capas->status); - remaining -= strlen(capas->capability); + remaining -= strlen(capas->status); capas = capas->next; if (capas != NULL) { + if (remaining < 1) + { + res = OC_STACK_ERROR; + goto exit; + } strcat(temp, "|"); } } @@ -779,21 +802,24 @@ OCStackResult BuildStringFromActionSet(OCActionSet* actionset, char** desc) action = action->next; if (action != NULL) { + if (remaining < strlen(ACTION_DELIMITER)) + { + res = OC_STACK_ERROR; + goto exit; + } strcat(temp, ACTION_DELIMITER); remaining--; } } - *desc = (char *) OICMalloc(1024 - remaining); + *desc = OICStrdup(temp); VARIFY_POINTER_NULL(*desc, res, exit); - strcpy(*desc, temp); return OC_STACK_OK; exit: OCFREE(*desc); return res; - } OCStackApplicationResult ActionSetCB(void* context, OCDoHandle handle, diff --git a/resource/include/OCPlatform.h b/resource/include/OCPlatform.h index 4643819..04a1848 100644 --- a/resource/include/OCPlatform.h +++ b/resource/include/OCPlatform.h @@ -32,7 +32,7 @@ namespace OC { /** - * @brief: This namespace contains the main entrance/functionality of the product. + * This namespace contains the main entrance/functionality of the product. * It may be used with OC::OCPlatform::functionName. To set a custom configuration, * the implementer must make a call to OCPlatform::Configure before the first usage * of a function in this namespace. @@ -41,7 +41,7 @@ namespace OC { /** * API for overwriting the default configuration of the OCPlatform object. - * Note: Any calls made to this AFTER the first call to OCPlatform::Instance + * @note Any calls made to this AFTER the first call to OCPlatform::Instance * will have no affect */ void Configure(const PlatformConfig& config); @@ -55,10 +55,12 @@ namespace OC * @param OCResourceHandle resource handle of the resource * @param QualityOfService the quality of communication * - * @return OCStackResult return value of this API. Returns OC_STACK_OK if success. - * NOTE: This API is for server side only. - * NOTE: OCResourceHandle is defined in ocstack.h. - * NOTE: OCStackResult is defined in ocstack.h. + * @return Returns ::OC_STACK_OK if success. + * @note This API is for server side only. + * @note OCResourceHandle is defined in ocstack.h + * @note OCStackResult is defined in ocstack.h. + * @see notifyAllObservers(OCResourceHandle) + * @see notifyAllObservers(OCResourceHandle, QualityOfService) */ OCStackResult notifyAllObservers(OCResourceHandle resourceHandle); OCStackResult notifyAllObservers(OCResourceHandle resourceHandle, QualityOfService QoS); @@ -73,11 +75,10 @@ namespace OC * resource change. * @param QualityOfService the quality of communication * - * @return OCStackResult return value of this API. Returns OC_STACK_OK if success. - * - * NOTE: This API is for server side only. - * NOTE: OCResourceHandle is defined in ocstack.h. - * NOTE: OCStackResult is defined in ocstack.h. + * @return Returns ::OC_STACK_OK if success. + * @note This API is for server side only. + * @note OCResourceHandle is defined in ocstack.h. + * @note OCStackResult is defined in ocstack.h. */ OCStackResult notifyListOfObservers( OCResourceHandle resourceHandle, @@ -91,15 +92,15 @@ namespace OC /** * API for Service and Resource Discovery. - * NOTE: This API applies to client side only. + * @note This API applies to client side only. * - * @param host - Host IP Address of a service to direct resource discovery query. If null or + * @param host Host IP Address of a service to direct resource discovery query. If null or * empty, performs multicast resource discovery query - * @param resourceURI - name of the resource. If null or empty, performs search for all + * @param resourceURI name of the resource. If null or empty, performs search for all * resource names - * @param connectivityType - @ref OCConnectivityType type of connectivity indicating the + * @param connectivityType ::OCConnectivityType type of connectivity indicating the * interface. Example: OC_WIFI, OC_ETHERNET, OC_ALL - * @param handler - Handles callbacks, success states and failure states. + * @param resourceHandler Handles callbacks, success states and failure states. * * Four modes of discovery defined as follows: * (NULL/Empty, NULL/Empty) - Performs ALL service discovery AND ALL resource @@ -112,11 +113,11 @@ namespace OC * from a particular service. * @param QualityOfService the quality of communication * - * @return OCStackResult return value of this API. Returns OC_STACK_OK if success. - * NOTE: First parameter 'host' currently represents an IP address. This will change in + * @return Returns ::OC_STACK_OK if success. + * @note First parameter 'host' currently represents an IP address. This will change in * future and will refer to endpoint interface so that we can refer to other transports such * as BTH etc. - * NOTE: OCStackResult is defined in ocstack.h. + * @note OCStackResult is defined in ocstack.h. */ OCStackResult findResource(const std::string& host, const std::string& resourceURI, OCConnectivityType connectivityType, FindCallback resourceHandler); @@ -128,14 +129,16 @@ namespace OC * API for Device Discovery * * - * @param host - Host IP Address. If null or empty, Multicast is performed. - * @param deviceURI - Uri containing address to the virtual device in C Stack + * @param host Host IP Address. If null or empty, Multicast is performed. + * @param deviceURI Uri containing address to the virtual device in C Stack ("/oic/d") - * @param connectivityType - @ref OCConnectivityType type of connectivity indicating the + * @param connectivityType ::OCConnectivityType type of connectivity indicating the * interface. Example: OC_WIFI, OC_ETHERNET, OC_ALL - * @param deviceInfoHandler - device discovery callback + * @param deviceInfoHandler device discovery callback * @param QoS the quality of communication * + * @return Returns ::OC_STACK_OK if success. + * @note OCStackResult is defined in ocstack.h. */ OCStackResult getDeviceInfo(const std::string& host, const std::string& deviceURI, OCConnectivityType connectivityType, FindDeviceCallback deviceInfoHandler); @@ -147,14 +150,16 @@ namespace OC * API for Platform Discovery * * - * @param host - Host IP Address. If null or empty, Multicast is performed. - * @param platformURI - Uri containing address to the virtual platform in C Stack + * @param host Host IP Address. If null or empty, Multicast is performed. + * @param platformURI Uri containing address to the virtual platform in C Stack ("/oic/p") - * @param connectivityType - @ref OCConnectivityType type of connectivity indicating the + * @param connectivityType ::OCConnectivityType type of connectivity indicating the * interface. Example: OC_WIFI, OC_ETHERNET, OC_ALL - * @param platformInfoHandler - platform discovery callback + * @param platformInfoHandler platform discovery callback * @param QoS the quality of communication * + * @return Returns ::OC_STACK_OK if success. + * @note OCStackResult is defined in ocstack.h. */ OCStackResult getPlatformInfo(const std::string& host, const std::string& platformURI, OCConnectivityType connectivityType, FindPlatformCallback platformInfoHandler); @@ -164,21 +169,21 @@ namespace OC /** * This API registers a resource with the server - * NOTE: This API applies to server side only. - * - * @param resourceHandle - Upon successful registration, resourceHandle will be filled - * @param resourceURI - The URI of the resource. Example: "a/light". See NOTE below - * @param resourceTypeName - The resource type. Example: "light" - * @param resourceInterface - The resource interface (whether it is collection etc). - * @param entityHandler - entity handler callback. - * @param resourceProperty - indicates the property of the resource. Defined in ocstack.h. + * @note This API applies to server side only. + * + * @param resourceHandle Upon successful registration, resourceHandle will be filled + * @param resourceURI The URI of the resource. Example: "a/light". See NOTE below + * @param resourceTypeName The resource type. Example: "light" + * @param resourceInterface The resource interface (whether it is collection etc). + * @param entityHandler entity handler callback. + * @param resourceProperty indicates the property of the resource. Defined in ocstack.h. * setting resourceProperty as OC_DISCOVERABLE will allow Discovery of this resource * setting resourceProperty as OC_OBSERVABLE will allow observation * settings resourceProperty as OC_DISCOVERABLE | OC_OBSERVABLE will allow both discovery and * observation * - * @return OCStackResult return value of this API. Returns OC_STACK_OK if success. - * NOTE: "a/light" is a relative URI. + * @return Returns ::OC_STACK_OK if success. + * @note "a/light" is a relative URI. * Above relative URI will be prepended (by core) with a host IP + namespace "oic" * Therefore, fully qualified URI format would be //HostIP-Address/namespace/relativeURI" * Example, a relative URI: 'a/light' will result in a fully qualified URI: @@ -187,7 +192,7 @@ namespace OC * qualified URI OR * first parameter can take fully qualified URI and core will take that as is for further * operations - * NOTE: OCStackResult is defined in ocstack.h. + * @note OCStackResult is defined in ocstack.h. */ OCStackResult registerResource(OCResourceHandle& resourceHandle, std::string& resourceURI, @@ -198,12 +203,13 @@ namespace OC /** * This API registers a resource with the server - * NOTE: This API applies to server & client side. + * @note This API applies to server & client side. - * @param resourceHandle - Upon successful registration, resourceHandle will be filled - * @param OCResource - The instance of OCResource that all data filled. + * @param resourceHandle Upon successful registration, resourceHandle will be filled + * @param OCResource The instance of OCResource that all data filled. * - * @return OCStackResult return value of this API. Returns OC_STACK_OK if success. + * @return Returns ::OC_STACK_OK if success. + * @note OCStackResult is defined in ocstack.h. */ OCStackResult registerResource(OCResourceHandle& resourceHandle, const std::shared_ptr< OCResource > resource); @@ -211,67 +217,60 @@ namespace OC /** * Register Device Info * - * @param deviceInfo - structure containing all the device specific information - * - * @return - * OC_STACK_OK - no errors - * OC_STACK_ERROR - stack process error + * @param deviceInfo structure containing all the device specific information + * @return Returns ::OC_STACK_OK if no errors and ::OC_STACK_ERROR in case of stack process error */ OCStackResult registerDeviceInfo(const OCDeviceInfo deviceInfo); /** * Register Platform Info * - * @param platformInfo - structure containing all the platform specific information - * - * @return - * OC_STACK_OK - no errors - * OC_STACK_ERROR - stack process error + * @param platformInfo structure containing all the platform specific information + * @return Returns ::OC_STACK_OK if no errors and ::OC_STACK_ERROR in case of stack process error */ OCStackResult registerPlatformInfo(const OCPlatformInfo platformInfo); /** * Set default device entity handler * - * @param entityHandler - entity handler to handle requests for - * any undefined resources or default actions. - * if NULL is passed it removes the device default entity handler. - * - * @return - * OC_STACK_OK - no errors - * OC_STACK_ERROR - stack process error + * @param entityHandler entity handler to handle requests for + * any undefined resources or default actions. + * if NULL is passed it removes the device default entity handler. + * @return Returns ::OC_STACK_OK if no errors and ::OC_STACK_ERROR in case of stack process error */ OCStackResult setDefaultDeviceEntityHandler(EntityHandler entityHandler); /** * This API unregisters a resource with the server - * NOTE: This API applies to server side only. + * @note This API applies to server side only. * - * @param resourceHandle - This is the resource handle which we which to unregister from the + * @param resourceHandle This is the resource handle which we need to unregister from the * server * - * @return OCStackResult return value of this API. Returns OC_STACK_OK if success. - * NOTE: OCStackResult is defined in ocstack.h. + * @return Returns ::OC_STACK_OK if success. + * @note OCStackResult is defined in ocstack.h. */ OCStackResult unregisterResource(const OCResourceHandle& resourceHandle); /** * Add a resource to a collection resource. * - * @param collectionHandle - handle to the collection resource - * @param resourceHandle - handle to resource to be added to the collection resource - * - * @return OCStackResult return value of this API. Returns OC_STACK_OK if success.
- * NOTE: OCStackResult is defined in ocstack.h.
- * NOTE: bindResource must be used only after the both collection resource and - * resource to add under a collections are created and respective handles obtained
- * Example:
- * Step 1: registerResource(homeResourceHandle, "a/home", "home", Link_Interface, - * entityHandler, OC_DISCOVERABLE | OC_OBSERVABLE);
- * Step 2: registerResource(kitchenResourceHandle, "a/kitchen", "kitchen", Link_Interface, - * entityHandler, OC_DISCOVERABLE | OC_OBSERVABLE);
- * Step 3: bindResource(homeResourceHandle, kitchenResourceHandle);
- * At the end of Step 3, resource "a/home" will contain a reference to "a/kitchen".
+ * @param collectionHandle handle to the collection resource + * @param resourceHandle handle to resource to be added to the collection resource + * + * @return Returns ::OC_STACK_OK if success. + * @note OCStackResult is defined in ocstack.h. + * @note bindResource must be used only after the both collection resource and + * resource to add under a collections are created and respective handles obtained + * + * @par Example: + * -# registerResource(homeResourceHandle, "a/home", "home", Link_Interface, + * entityHandler, OC_DISCOVERABLE | OC_OBSERVABLE); + * -# registerResource(kitchenResourceHandle, "a/kitchen", "kitchen", Link_Interface, + * entityHandler, OC_DISCOVERABLE | OC_OBSERVABLE); + * -# bindResource(homeResourceHandle, kitchenResourceHandle); + * @par + * At the end of Step 3, resource "a/home" will contain a reference to "a/kitchen". */ OCStackResult bindResource(const OCResourceHandle collectionHandle, const OCResourceHandle resourceHandle); @@ -279,27 +278,29 @@ namespace OC /** * Add multiple resources to a collection resource. * - * @param collectionHandle - handle to the collection resource + * @param collectionHandle handle to the collection resource * @param addedResourceHandleList reference to list of resource handles to be added to the * collection resource * - * @return OCStackResult return value of this API. Returns OC_STACK_OK if success.
- * NOTE: OCStackResult is defined in ocstack.h.
- * NOTE: bindResources must be used only after the both collection resource and + * @return Returns ::OC_STACK_OK if success. + * @note OCStackResult is defined in ocstack.h. + * @note bindResources must be used only after the both collection resource and * list of resources to add under a collection are created and respective handles - * obtained
- * Example:
- * Step 1: registerResource(homeResourceHandle, "a/home", "home", Link_Interface, - * homeEntityHandler, OC_DISCOVERABLE | OC_OBSERVABLE);
- * Step 2: registerResource(kitchenResourceHandle, "a/kitchen", "kitchen", Link_Interface, - * kitchenEntityHandler, OC_DISCOVERABLE | OC_OBSERVABLE);
- * Step 3: registerResource(roomResourceHandle, "a/room", "room", Link_Interface, - * roomEntityHandler, OC_DISCOVERABLE | OC_OBSERVABLE);
- * Step 4: std::vector rList; rList.push_back(kitchenResourceHandle); - * rList.push_back(roomResourceHandle);
- * Step 5: bindResource(homeResourceHandle, rList);
+ * obtained. + * + * @par Example: + * -# registerResource(homeResourceHandle, "a/home", "home", Link_Interface, + * homeEntityHandler, OC_DISCOVERABLE | OC_OBSERVABLE); + * -# registerResource(kitchenResourceHandle, "a/kitchen", "kitchen", Link_Interface, + * kitchenEntityHandler, OC_DISCOVERABLE | OC_OBSERVABLE); + * -# registerResource(roomResourceHandle, "a/room", "room", Link_Interface, + * roomEntityHandler, OC_DISCOVERABLE | OC_OBSERVABLE); + * -# std::vector rList; rList.push_back(kitchenResourceHandle); + * rList.push_back(roomResourceHandle); + * -# bindResource(homeResourceHandle, rList); + * @par * At the end of Step 5, resource "a/home" will contain a references to "a/kitchen" and - * "a/room"
+ * "a/room" */ OCStackResult bindResources(const OCResourceHandle collectionHandle, const std::vector& addedResourceHandleList); @@ -307,21 +308,23 @@ namespace OC /** * Unbind a resource from a collection resource. * - * @param collectionHandle - handle to the collection resource + * @param collectionHandle handle to the collection resource * @param resourceHandle resource handle to be unbound from the collection resource * - * @return OCStackResult return value of this API. Returns OC_STACK_OK if success.
- * NOTE: OCStackResult is defined in ocstack.h.
- * NOTE: unbindResource must be used only after the both collection resource and - * resource to unbind from a collection are created and respective handles obtained
- * Example
- * Step 1: registerResource(homeResourceHandle, "a/home", "home", Link_Interface, - * entityHandler, OC_DISCOVERABLE | OC_OBSERVABLE);
- * Step 2: registerResource(kitchenResourceHandle, "a/kitchen", "kitchen", Link_Interface, - * entityHandler, OC_DISCOVERABLE | OC_OBSERVABLE);
- * Step 3: bindResource(homeResourceHandle, kitchenResourceHandle);
- * Step 4: unbindResource(homeResourceHandle, kitchenResourceHandle);
- * At the end of Step 4, resource "a/home" will no longer reference "a/kitchen".
+ * @return Returns ::OC_STACK_OK if success. + * @note OCStackResult is defined in ocstack.h. + * @note unbindResource must be used only after the both collection resource and + * resource to unbind from a collection are created and respective handles obtained + * + * @par Example: + * -# registerResource(homeResourceHandle, "a/home", "home", Link_Interface, + * entityHandler, OC_DISCOVERABLE | OC_OBSERVABLE); + * -# registerResource(kitchenResourceHandle, "a/kitchen", "kitchen", Link_Interface, + * entityHandler, OC_DISCOVERABLE | OC_OBSERVABLE); + * -# bindResource(homeResourceHandle, kitchenResourceHandle); + * -# unbindResource(homeResourceHandle, kitchenResourceHandle); + * @par + * At the end of Step 4, resource "a/home" will no longer reference "a/kitchen". */ OCStackResult unbindResource(const OCResourceHandle collectionHandle, const OCResourceHandle resourceHandle); @@ -329,49 +332,50 @@ namespace OC /** * Unbind resources from a collection resource. * - * @param collectionHandle - handle to the collection resource + * @param collectionHandle handle to the collection resource * @param resourceHandleList List of resource handles to be unbound from the collection * resource * - * @return OCStackResult return value of this API. Returns OC_STACK_OK if success.
- * - * NOTE: OCStackResult is defined in ocstack.h.
- * NOTE: unbindResources must be used only after the both collection resource and + * @return Returns ::OC_STACK_OK if success. + * @note OCStackResult is defined in ocstack.h. + * @note unbindResources must be used only after the both collection resource and * list of resources resource to unbind from a collection are created and respective handles - * obtained.
- * Example
- * Step 1: registerResource(homeResourceHandle, "a/home", "home", Link_Interface, - * homeEntityHandler, OC_DISCOVERABLE | OC_OBSERVABLE);
- * Step 2: registerResource(kitchenResourceHandle, "a/kitchen", "kitchen", Link_Interface, - * kitchenEntityHandler, OC_DISCOVERABLE | OC_OBSERVABLE);
- * Step 3: registerResource(roomResourceHandle, "a/room", "room", Link_Interface, - * roomEntityHandler, OC_DISCOVERABLE | OC_OBSERVABLE);
- * Step 4: std::vector rList; rList.push_back(kitchenResourceHandle); - * rList.push_back(roomResourceHandle);
- * Step 5: bindResource(homeResourceHandle, rList);
- * Step 6: unbindResources(homeResourceHandle, rList);
+ * obtained. + * + * @par Example: + * -# registerResource(homeResourceHandle, "a/home", "home", Link_Interface, + * homeEntityHandler, OC_DISCOVERABLE | OC_OBSERVABLE); + * -# registerResource(kitchenResourceHandle, "a/kitchen", "kitchen", Link_Interface, + * kitchenEntityHandler, OC_DISCOVERABLE | OC_OBSERVABLE); + * -# registerResource(roomResourceHandle, "a/room", "room", Link_Interface, + * roomEntityHandler, OC_DISCOVERABLE | OC_OBSERVABLE); + * -# std::vector rList; rList.push_back(kitchenResourceHandle); + * rList.push_back(roomResourceHandle); + * -# bindResource(homeResourceHandle, rList); + * -# unbindResources(homeResourceHandle, rList); + * @par * At the end of Step 6, resource "a/home" will no longer reference to "a/kitchen" and - * "a/room"
+ * "a/room" */ OCStackResult unbindResources(const OCResourceHandle collectionHandle, const std::vector& resourceHandleList); /** * Binds a type to a particular resource - * @param resourceHandle - handle to the resource - * @param resourceTypeName - new typename to bind to the resource - - * @return OCStackResult - return value of the API. Returns OCSTACK_OK if success
+ * @param resourceHandle handle to the resource + * @param resourceTypeName new typename to bind to the resource + * + * @return Returns ::OC_STACK_OK if success. */ OCStackResult bindTypeToResource(const OCResourceHandle& resourceHandle, const std::string& resourceTypeName); /** * Binds an interface to a particular resource - * @param resourceHandle - handle to the resource - * @param resourceInterfaceName - new interface to bind to the resource - - * @return OCStackResult - return value of the API. Returns OCSTACK_OK if success
+ * @param resourceHandle handle to the resource + * @param resourceInterfaceName new interface to bind to the resource + * + * @return Returns ::OC_STACK_OK if success. */ OCStackResult bindInterfaceToResource(const OCResourceHandle& resourceHandle, const std::string& resourceInterfaceName); @@ -380,13 +384,13 @@ namespace OC /** * Start Presence announcements. * - * @param ttl - time to live - * Note: If ttl is '0', then the default stack value will be used (60 Seconds). - * - * If ttl is greater than OC_MAX_PRESENCE_TTL_SECONDS, then the ttl will be set to - * OC_MAX_PRESENCE_TTL_SECONDS. - * - * @return OCStackResult - Returns OCSTACK_OK if success
+ * @param ttl time to live + * @par + * If ttl is '0', then the default stack value will be used (60 Seconds). + * If ttl is greater than OC_MAX_PRESENCE_TTL_SECONDS, then the ttl will be set to + * OC_MAX_PRESENCE_TTL_SECONDS. + * @par + * @return Returns ::OC_STACK_OK if success. * * Server can call this function when it comes online for the * first time, or when it comes back online from offline mode, @@ -398,7 +402,7 @@ namespace OC /** * Stop Presence announcements. * - * @return OCStackResult - Returns OCSTACK_OK if success
+ * @return Returns ::OC_STACK_OK if success. * * Server can call this function when it is terminating, * going offline, or when going away from network. @@ -411,18 +415,18 @@ namespace OC * every time a server adds/removes/alters a resource, starts or is intentionally * stopped (potentially more to be added later). * - * @param presenceHandle - a handle object that can be used to identify this subscription + * @param presenceHandle a handle object that can be used to identify this subscription * request. It can be used to unsubscribe from these events in the future. * It will be set upon successful return of this method. - * @param host - The IP address/addressable name of the server to subscribe to. + * @param host The IP address/addressable name of the server to subscribe to. * This should be in the format coap://address:port - * @param connectivityType - @ref OCConnectivityType type of connectivity indicating the + * @param connectivityType ::OCConnectivityType type of connectivity indicating the * interface. Example: OC_WIFI, OC_ETHERNET, OC_ALL - * @param resourceType - a resource type specified as a filter for subscription callbacks. - * @param presenceHandler - callback function that will receive notifications/subscription + * @param resourceType a resource type specified as a filter for subscription callbacks. + * @param presenceHandler callback function that will receive notifications/subscription * events * - * @return OCStackResult - return value of the API. Returns OCSTACK_OK if success
+ * @return Returns ::OC_STACK_OK if success. */ OCStackResult subscribePresence(OCPresenceHandle& presenceHandle, const std::string& host, OCConnectivityType connectivityType, SubscribeCallback presenceHandler); @@ -435,10 +439,10 @@ namespace OC * you may for a short time still receive events from the server since it may take time * for the unsubscribe to take effect. * - * @param presenceHandle - the handle object provided by the subscribePresence call that + * @param presenceHandle the handle object provided by the subscribePresence call that * identifies this subscription. * - * @return OCStackResult - return value of the API. Returns OCSTACK_OK if success
+ * @return Returns ::OC_STACK_OK if success. */ OCStackResult unsubscribePresence(OCPresenceHandle presenceHandle); @@ -452,23 +456,23 @@ namespace OC * to be a Client or Client/Server. Otherwise, this will return an empty * shared ptr. * - * @param host - a string containing a resolvable host address of the server + * @param host a string containing a resolvable host address of the server * holding the resource. Currently this should be in the format * coap://address:port, though in the future, we expect this to * change to //address:port * - * @param uri - the rest of the resource's URI that will permit messages to be + * @param uri the rest of the resource's URI that will permit messages to be * properly routed. Example: /a/light * - * @param connectivityType - @ref OCConnectivityType type of connectivity indicating the + * @param connectivityType ::OCConnectivityType type of connectivity indicating the * interface. Example: OC_WIFI, OC_ETHERNET, OC_ALL * - * @param isObservable - a boolean containing whether the resource supports observation + * @param isObservable a boolean containing whether the resource supports observation * - * @param resourceTypes - a collection of resource types implemented by the resource + * @param resourceTypes a collection of resource types implemented by the resource * - * @param interfaces - a collection of interfaces that the resource supports/implements - * @return OCResource::Ptr - a shared pointer to the new resource object + * @param interfaces a collection of interfaces that the resource supports/implements + * @return OCResource::Ptr a shared pointer to the new resource object */ OCResource::Ptr constructResourceObject(const std::string& host, const std::string& uri, @@ -479,9 +483,10 @@ namespace OC /** * Allows application entity handler to send response to an incoming request. * - * @param pResponse - OCResourceResponse pointer that will permit to set values related - * to resource response.
- * @return OCStackResult - return value of the API. Returns OCSTACK_OK if success
+ * @param pResponse OCResourceResponse pointer that will permit to set values related + * to resource response. + * + * @return Returns ::OC_STACK_OK if success. */ OCStackResult sendResponse(const std::shared_ptr pResponse); } diff --git a/resource/include/OCPlatform_impl.h b/resource/include/OCPlatform_impl.h index 7b23a56..78b95e8 100644 --- a/resource/include/OCPlatform_impl.h +++ b/resource/include/OCPlatform_impl.h @@ -96,12 +96,13 @@ namespace OC /** * API for Device Discovery * - * @param host - Host IP Address. If null or empty, Multicast is performed. - * @param resourceURI - Uri containing address to the virtual device in C Stack + * @param host Host IP Address. If null or empty, Multicast is performed. + * @param deviceURI Uri containing address to the virtual device in C Stack * ("/oic/d") - * + * @param deviceInfoHandler device discovery callback * @param QualityOfService the quality of communication - * + * @return Returns ::OC_STACK_OK if success. + * @note OCStackResult is defined in ocstack.h. */ OCStackResult getDeviceInfo(const std::string& host, const std::string& deviceURI, FindDeviceCallback deviceInfoHandler); @@ -111,12 +112,13 @@ namespace OC /** * API for Platform Discovery * - * @param host - Host IP Address. If null or empty, Multicast is performed. - * @param resourceURI - Uri containing address to the virtual platform in C Stack + * @param host Host IP Address. If null or empty, Multicast is performed. + * @param platformURI Uri containing address to the virtual platform in C Stack * ("/oic/p") - * + * @param platformInfoHandler platform discovery callback * @param QualityOfService the quality of communication - * + * @return Returns ::OC_STACK_OK if success. + * @note OCStackResult is defined in ocstack.h. */ OCStackResult getPlatformInfo(const std::string& host, const std::string& platformURI, FindPlatformCallback platformInfoHandler); @@ -125,21 +127,21 @@ namespace OC /** * This API registers a resource with the server - * NOTE: This API applies to server side only. + * @note This API applies to server side only. * - * @param resourceHandle - Upon successful registration, resourceHandle will be filled - * @param resourceURI - The URI of the resource. Example: "a/light". See NOTE below - * @param resourceTypeName - The resource type. Example: "light" - * @param resourceInterface - The resource interface (whether it is collection etc). - * @param entityHandler - entity handler callback. - * @param resourceProperty - indicates the property of the resource. Defined in ocstack.h. + * @param resourceHandle Upon successful registration, resourceHandle will be filled + * @param resourceURI The URI of the resource. Example: "a/light". See NOTE below + * @param resourceTypeName The resource type. Example: "light" + * @param resourceInterface The resource interface (whether it is collection etc). + * @param entityHandler entity handler callback. + * @param resourceProperty indicates the property of the resource. Defined in ocstack.h. * setting resourceProperty as OC_DISCOVERABLE will allow Discovery of this resource * setting resourceProperty as OC_OBSERVABLE will allow observation * settings resourceProperty as OC_DISCOVERABLE | OC_OBSERVABLE will allow both discovery * and observation * - * @return OCStackResult return value of this API. Returns OC_STACK_OK if success. - * NOTE: "a/light" is a relative URI. + * @return Returns ::OC_STACK_OK if success. + * @note "a/light" is a relative URI. * Above relative URI will be prepended (by core) with a host IP + namespace "oc" * Therefore, fully qualified URI format would be //HostIP-Address/namespace/relativeURI" * Example, a relative URI: 'a/light' will result in a fully qualified URI: @@ -148,7 +150,7 @@ namespace OC * qualified URI OR * first parameter can take fully qualified URI and core will take that as is for further * operations - * NOTE: OCStackResult is defined in ocstack.h. + * @note OCStackResult is defined in ocstack.h. */ OCStackResult registerResource(OCResourceHandle& resourceHandle, std::string& resourceURI, @@ -163,22 +165,20 @@ namespace OC /** * This API registers all the device specific information * - * @param OCDeviceInfo - Structure containing all the device related information - * - * @return OCStackResult return value of the API. Returns OC_STACK_OK if success + * @param deviceInfo Structure containing all the device related information * - * Note: OCDeviceInfo is defined in OCStack.h + * @return Returns ::OC_STACK_OK if success + * @note OCDeviceInfo is defined in OCStack.h */ OCStackResult registerDeviceInfo(const OCDeviceInfo deviceInfo); /** * This API registers all the platform specific information * - * @param OCPlatformInfo - Structure containing all the platform related information - * - * @return OCStackResult return value of the API. Returns OC_STACK_OK if success + * @param platformInfo Structure containing all the platform related information * - * Note: OCPlatformInfo is defined in OCStack.h + * @return Returns ::OC_STACK_OK if success + * @note OCPlatformInfo is defined in OCStack.h */ OCStackResult registerPlatformInfo(const OCPlatformInfo platformInfo); diff --git a/service/resource-encapsulation/src/resourceBroker/include/DevicePresence.h b/service/resource-encapsulation/src/resourceBroker/include/DevicePresence.h index a964e65..cfb7bc9 100644 --- a/service/resource-encapsulation/src/resourceBroker/include/DevicePresence.h +++ b/service/resource-encapsulation/src/resourceBroker/include/DevicePresence.h @@ -23,7 +23,7 @@ #include #include -#include +#include #include "BrokerTypes.h" #include "ResourcePresence.h" @@ -49,13 +49,14 @@ namespace OIC bool isEmptyResourcePresence() const; const std::string getAddress() const; - DEVICE_STATE getDeviceState() const; + DEVICE_STATE getDeviceState() const noexcept; + private: std::list resourcePresenceList; std::string address; - boost::atomic state; - boost::atomic_bool isRunningTimeOut; + std::atomic_int state; + std::atomic_bool isRunningTimeOut; std::mutex timeoutMutex; std::condition_variable condition; @@ -69,6 +70,8 @@ namespace OIC void changeAllPresenceMode(BROKER_MODE mode); void subscribeCB(OCStackResult ret,const unsigned int seq, const std::string& Hostaddress); void timeOutCB(TimerID id); + + void setDeviceState(DEVICE_STATE); }; } // namespace Service } // namespace OIC diff --git a/service/resource-encapsulation/src/resourceBroker/src/DevicePresence.cpp b/service/resource-encapsulation/src/resourceBroker/src/DevicePresence.cpp index 629ef14..aade9e9 100644 --- a/service/resource-encapsulation/src/resourceBroker/src/DevicePresence.cpp +++ b/service/resource-encapsulation/src/resourceBroker/src/DevicePresence.cpp @@ -27,7 +27,7 @@ namespace OIC { DevicePresence::DevicePresence() { - state = DEVICE_STATE::REQUESTED; + setDeviceState(DEVICE_STATE::REQUESTED); presenceTimerHandle = 0; isRunningTimeOut = false; @@ -69,10 +69,17 @@ namespace OIC presenceTimerHandle = presenceTimer.post(BROKER_DEVICE_PRESENCE_TIMEROUT, pTimeoutCB); } - DEVICE_STATE DevicePresence::getDeviceState() const + + DEVICE_STATE DevicePresence::getDeviceState() const noexcept { - return state; + return static_cast< DEVICE_STATE >(state.load()); } + + void DevicePresence::setDeviceState(DEVICE_STATE newState) + { + state = static_cast< int >(newState); + } + const std::string DevicePresence::getAddress() const { OC_LOG_V(DEBUG, BROKER_TAG, "getAddress()"); @@ -130,9 +137,9 @@ namespace OIC case OC_STACK_CONTINUE: { OC_LOG_V(DEBUG, BROKER_TAG, "SEQ# %d",seq); - state = DEVICE_STATE::ALIVE; + setDeviceState(DEVICE_STATE::ALIVE); OC_LOG_V(DEBUG, BROKER_TAG, "device state : %d", - (int)(state.load(boost::memory_order_consume))); + (int)getDeviceState()); changeAllPresenceMode(BROKER_MODE::DEVICE_PRESENCE_MODE); presenceTimerHandle = presenceTimer.post(BROKER_DEVICE_PRESENCE_TIMEROUT, pTimeoutCB); @@ -146,14 +153,14 @@ namespace OIC case OC_STACK_PRESENCE_TIMEOUT: case OC_STACK_PRESENCE_DO_NOT_HANDLE: { - state = DEVICE_STATE::LOST_SIGNAL; + setDeviceState(DEVICE_STATE::LOST_SIGNAL); changeAllPresenceMode(BROKER_MODE::NON_PRESENCE_MODE); break; } default: { OC_LOG_V(DEBUG, BROKER_TAG, "Presence Lost Signal because unknown type"); - state = DEVICE_STATE::LOST_SIGNAL; + setDeviceState(DEVICE_STATE::LOST_SIGNAL); changeAllPresenceMode(BROKER_MODE::NON_PRESENCE_MODE); break; } @@ -168,7 +175,7 @@ namespace OIC OC_LOG_V(DEBUG, BROKER_TAG, "Timeout execution. will be discard after receiving cb message"); - state = DEVICE_STATE::LOST_SIGNAL; + setDeviceState(DEVICE_STATE::LOST_SIGNAL); changeAllPresenceMode(BROKER_MODE::NON_PRESENCE_MODE); isRunningTimeOut = false; diff --git a/service/resource-encapsulation/src/resourceContainer/SConscript b/service/resource-encapsulation/src/resourceContainer/SConscript index 2934a06..966cc12 100644 --- a/service/resource-encapsulation/src/resourceContainer/SConscript +++ b/service/resource-encapsulation/src/resourceContainer/SConscript @@ -177,7 +177,7 @@ else: HueBundle = hue_resource_bundle_env.SharedLibrary('HueBundle', hue_resource_bundle_src) hue_resource_bundle_env.InstallTarget(HueBundle, 'libHueBundle') - lib_env = conf2.Finish() +lib_env = conf2.Finish() ###################################################################### # build resource container unit tests -- 2.7.4