From 809b1b1e9be15724a6d756b403328a95894e639f Mon Sep 17 00:00:00 2001 From: Sachin Agrawal Date: Thu, 4 Jun 2015 09:51:01 -0700 Subject: [PATCH] Merging security-M3 to master Added support for resource access control, anonymous ECDH, and Just Works Provisioning. Patch 1 : Squashed all security-M3 patches and rebased to common ancestor of security-M3 and master. Patch 2 : Rebased to master. (Arduino build fails). Patch 3-4 : Fix the unit test failures. Patch 5 : Fix the previsioning server send request issue by adding token length. Patch 6 : Fixed Arduino compilation. Patch 7 : Fixed DTLS handshake issue. Patch 8 : Fix the build issue. Patch 9 : Replaced strncmp with memcmp, As token handling is from null terminated string to byte buffer. Patch 10: Rebased with master. Patch 11-12: OSX Build Failure Fixes. Patch 13: Updated README related to secure-Iotivity stack. Patch 14: Fixed issues identified in Patch 5. Patch 15: Rebased with master to avoid merge conflicts. Patch 16: Updated commit message Change-Id: Icae698c3bf377862b561d6ebba1d784058d28adb Signed-off-by: Sachin Agrawal Signed-off-by: Sakthivel Samidurai Signed-off-by: Randeep Singh Reviewed-on: https://gerrit.iotivity.org/gerrit/1071 --- build_common/SConscript | 0 ...anonymous-ecdh-cipher-suite-into-tinydtls.patch | 1164 ++++++++++++++ extlibs/tinydtls/aes/rijndael.h | 1 + extlibs/tinydtls/crypto.c | 170 ++- extlibs/tinydtls/crypto.h | 15 +- extlibs/tinydtls/dtls.c | 339 ++++- extlibs/tinydtls/dtls.h | 52 +- extlibs/tinydtls/ecc/Makefile.contiki | 0 extlibs/tinydtls/ecc/Makefile.ecc | 0 extlibs/tinydtls/ecc/test_helper.c | 79 - extlibs/tinydtls/ecc/test_helper.h | 51 - extlibs/tinydtls/ecc/testecc.c | 226 --- extlibs/tinydtls/ecc/testfield.c | 290 ---- extlibs/tinydtls/global.h | 6 + extlibs/tinydtls/tests/dtls-client.c | 43 +- extlibs/tinydtls/tests/dtls-server.c | 21 +- extlibs/tinydtls/tinydtls.h | 2 +- extlibs/tinydtls/uthash.h | 74 +- extlibs/tinydtls/utlist.h | 20 +- resource/SConscript | 3 + resource/csdk/SConscript | 4 +- resource/csdk/connectivity/api/cacommon.h | 21 +- resource/csdk/connectivity/api/cainterface.h | 89 +- resource/csdk/connectivity/inc/caadapternetdtls.h | 110 +- resource/csdk/connectivity/inc/caipinterface.h | 3 +- .../csdk/connectivity/samples/linux/SConscript | 2 +- resource/csdk/connectivity/src/SConscript | 2 - .../src/adapter_util/caadapternetdtls.c | 486 ++++-- .../connectivity/src/adapter_util/caadapterutils.c | 1 + .../csdk/connectivity/src/caconnectivitymanager.c | 95 ++ .../csdk/connectivity/src/ip_adapter/caipadapter.c | 21 +- .../csdk/connectivity/src/ip_adapter/caipserver.c | 4 +- ...-building-and-running-secure-IoTivity-stack.txt | 17 + resource/csdk/security/SConscript | 102 ++ resource/csdk/security/include/base64.h | 88 ++ .../csdk/security/include/internal/aclresource.h | 71 + .../csdk/security/include/internal/credresource.h | 133 ++ .../csdk/security/include/internal/doxmresource.h | 102 ++ .../csdk/security/include/internal/policyengine.h | 88 ++ .../{ocsecurityinternal.h => psinterface.h} | 40 +- .../csdk/security/include/internal/pstatresource.h | 71 + .../security/include/internal/resourcemanager.h | 56 + .../include/internal/secureresourcemanager.h | 86 ++ .../security/include/internal/srmresourcestrings.h | 91 ++ resource/csdk/security/include/ocsecurityconfig.h | 103 -- .../security/include/securevirtualresourcetypes.h | 418 +++++ .../include/{ocsecurity.h => srmutility.h} | 36 +- resource/csdk/security/provisioning/SConscript | 87 ++ .../include/internal/credentialgenerator.h | 48 + .../provisioning/include/provisioningmanager.h | 174 +++ .../csdk/security/provisioning/sample/SConscript | 75 + .../security/provisioning/sample/oic_svr_db.json | 43 + .../provisioning/sample/provisioningclient.c | 326 ++++ .../provisioning/src/credentialgenerator.c | 76 + .../provisioning/src/provisioningmanager.c | 1592 ++++++++++++++++++++ .../csdk/security/provisioning/unittest/SConscript | 83 + .../provisioning/unittest/provisioningmanager.cpp | 56 + resource/csdk/security/src/aclresource.c | 595 ++++++++ resource/csdk/security/src/base64.c | 255 ++++ resource/csdk/security/src/credresource.c | 673 +++++++++ resource/csdk/security/src/doxmresource.c | 654 ++++++++ resource/csdk/security/src/ocsecurity.c | 237 --- resource/csdk/security/src/policyengine.c | 368 +++++ resource/csdk/security/src/psinterface.c | 200 +++ resource/csdk/security/src/pstatresource.c | 399 +++++ resource/csdk/security/src/resourcemanager.c | 110 ++ resource/csdk/security/src/secureresourcemanager.c | 263 ++++ resource/csdk/security/src/srmresourcestrings.c | 87 ++ resource/csdk/security/unittest/SConscript | 102 ++ .../csdk/security/unittest/aclresourcetest.cpp | 253 ++++ resource/csdk/security/unittest/base64tests.cpp | 260 ++++ .../csdk/security/unittest/credentialresource.cpp | 216 +++ resource/csdk/security/unittest/doxmresource.cpp | 163 ++ resource/csdk/security/unittest/oic_svr_db.json | 45 + resource/csdk/security/unittest/oic_unittest.json | 37 + .../csdk/security/unittest/oic_unittest_acl1.json | 53 + .../unittest/oic_unittest_default_acl.json | 21 + resource/csdk/security/unittest/policyengine.cpp | 110 ++ resource/csdk/security/unittest/pstatresource.cpp | 159 ++ .../security/unittest/securityresourcemanager.cpp | 156 ++ resource/csdk/stack/include/ocstack.h | 10 + resource/csdk/stack/include/octypes.h | 52 +- .../arduino/SimpleClientServer/ocserver/SConscript | 2 +- .../samples/linux/SimpleClientServer/SConscript | 4 +- .../linux/SimpleClientServer/occlientbasicops.cpp | 2 +- .../linux/SimpleClientServer/ocserverbasicops.cpp | 46 +- .../csdk/stack/samples/linux/secure/SConscript | 11 +- .../csdk/stack/samples/linux/secure/common.cpp | 41 +- resource/csdk/stack/samples/linux/secure/common.h | 3 - .../stack/samples/linux/secure/gen_sec_bin.cpp | 171 --- .../samples/linux/secure/occlientbasicops.cpp | 44 +- .../samples/linux/secure/ocserverbasicops.cpp | 62 +- .../samples/linux/secure/oic_svr_db_client.json | 49 + .../samples/linux/secure/oic_svr_db_server.json | 55 + resource/csdk/stack/src/ocserverrequest.c | 11 +- resource/csdk/stack/src/ocstack.c | 65 +- resource/csdk/stack/test/SConscript | 2 + resource/csdk/stack/test/stacktests.cpp | 56 +- resource/unit_tests.scons | 8 + resource/unittests/SConscript | 1 + 100 files changed, 11925 insertions(+), 1642 deletions(-) mode change 100644 => 100755 build_common/SConscript create mode 100644 extlibs/tinydtls/0001-Added-anonymous-ecdh-cipher-suite-into-tinydtls.patch mode change 100644 => 100755 extlibs/tinydtls/ecc/Makefile.contiki mode change 100644 => 100755 extlibs/tinydtls/ecc/Makefile.ecc delete mode 100644 extlibs/tinydtls/ecc/test_helper.c delete mode 100644 extlibs/tinydtls/ecc/test_helper.h delete mode 100644 extlibs/tinydtls/ecc/testecc.c delete mode 100644 extlibs/tinydtls/ecc/testfield.c mode change 100644 => 100755 resource/csdk/connectivity/samples/linux/SConscript mode change 100644 => 100755 resource/csdk/connectivity/src/SConscript create mode 100644 resource/csdk/security/README-building-and-running-secure-IoTivity-stack.txt create mode 100644 resource/csdk/security/SConscript create mode 100644 resource/csdk/security/include/base64.h create mode 100755 resource/csdk/security/include/internal/aclresource.h create mode 100644 resource/csdk/security/include/internal/credresource.h create mode 100644 resource/csdk/security/include/internal/doxmresource.h create mode 100644 resource/csdk/security/include/internal/policyengine.h rename resource/csdk/security/include/internal/{ocsecurityinternal.h => psinterface.h} (50%) create mode 100644 resource/csdk/security/include/internal/pstatresource.h create mode 100644 resource/csdk/security/include/internal/resourcemanager.h create mode 100644 resource/csdk/security/include/internal/secureresourcemanager.h create mode 100644 resource/csdk/security/include/internal/srmresourcestrings.h delete mode 100644 resource/csdk/security/include/ocsecurityconfig.h create mode 100644 resource/csdk/security/include/securevirtualresourcetypes.h rename resource/csdk/security/include/{ocsecurity.h => srmutility.h} (50%) create mode 100644 resource/csdk/security/provisioning/SConscript create mode 100644 resource/csdk/security/provisioning/include/internal/credentialgenerator.h create mode 100644 resource/csdk/security/provisioning/include/provisioningmanager.h create mode 100755 resource/csdk/security/provisioning/sample/SConscript create mode 100755 resource/csdk/security/provisioning/sample/oic_svr_db.json create mode 100755 resource/csdk/security/provisioning/sample/provisioningclient.c create mode 100644 resource/csdk/security/provisioning/src/credentialgenerator.c create mode 100644 resource/csdk/security/provisioning/src/provisioningmanager.c create mode 100644 resource/csdk/security/provisioning/unittest/SConscript create mode 100644 resource/csdk/security/provisioning/unittest/provisioningmanager.cpp create mode 100644 resource/csdk/security/src/aclresource.c create mode 100644 resource/csdk/security/src/base64.c create mode 100755 resource/csdk/security/src/credresource.c create mode 100755 resource/csdk/security/src/doxmresource.c delete mode 100644 resource/csdk/security/src/ocsecurity.c create mode 100644 resource/csdk/security/src/policyengine.c create mode 100644 resource/csdk/security/src/psinterface.c create mode 100644 resource/csdk/security/src/pstatresource.c create mode 100644 resource/csdk/security/src/resourcemanager.c create mode 100644 resource/csdk/security/src/secureresourcemanager.c create mode 100644 resource/csdk/security/src/srmresourcestrings.c create mode 100644 resource/csdk/security/unittest/SConscript create mode 100644 resource/csdk/security/unittest/aclresourcetest.cpp create mode 100644 resource/csdk/security/unittest/base64tests.cpp create mode 100644 resource/csdk/security/unittest/credentialresource.cpp create mode 100644 resource/csdk/security/unittest/doxmresource.cpp create mode 100644 resource/csdk/security/unittest/oic_svr_db.json create mode 100644 resource/csdk/security/unittest/oic_unittest.json create mode 100644 resource/csdk/security/unittest/oic_unittest_acl1.json create mode 100644 resource/csdk/security/unittest/oic_unittest_default_acl.json create mode 100644 resource/csdk/security/unittest/policyengine.cpp create mode 100644 resource/csdk/security/unittest/pstatresource.cpp create mode 100644 resource/csdk/security/unittest/securityresourcemanager.cpp delete mode 100644 resource/csdk/stack/samples/linux/secure/gen_sec_bin.cpp create mode 100644 resource/csdk/stack/samples/linux/secure/oic_svr_db_client.json create mode 100644 resource/csdk/stack/samples/linux/secure/oic_svr_db_server.json diff --git a/build_common/SConscript b/build_common/SConscript old mode 100644 new mode 100755 diff --git a/extlibs/tinydtls/0001-Added-anonymous-ecdh-cipher-suite-into-tinydtls.patch b/extlibs/tinydtls/0001-Added-anonymous-ecdh-cipher-suite-into-tinydtls.patch new file mode 100644 index 0000000..ba75317 --- /dev/null +++ b/extlibs/tinydtls/0001-Added-anonymous-ecdh-cipher-suite-into-tinydtls.patch @@ -0,0 +1,1164 @@ +From bdfe0e312f9c2cd34df7bfff070dfe8a9e82d147 Mon Sep 17 00:00:00 2001 +From: leechul +Date: Thu, 9 Apr 2015 16:25:43 +0900 +Subject: [PATCH 1/1] Added anonymous ecdh cipher suite into tinydtls + +Change-Id: I80fa2985587618ebe7debdacba45996614c4cf1b +Signed-off-by: leechul +Signed-off-by: Sachin Agrawal +--- + extlibs/tinydtls/aes/rijndael.h | 1 + + extlibs/tinydtls/crypto.c | 173 ++++++++++++++++--- + extlibs/tinydtls/crypto.h | 15 +- + extlibs/tinydtls/dtls.c | 301 +++++++++++++++++++++++++--------- + extlibs/tinydtls/dtls.h | 28 +++- + extlibs/tinydtls/global.h | 6 + + extlibs/tinydtls/tests/dtls-client.c | 42 ++++- + extlibs/tinydtls/tests/dtls-server.c | 21 ++- + 8 files changed, 468 insertions(+), 119 deletions(-) + mode change 100755 => 100644 extlibs/tinydtls/crypto.c + +diff --git a/extlibs/tinydtls/aes/rijndael.h b/extlibs/tinydtls/aes/rijndael.h +index 60e9bef..712798b 100755 +--- a/extlibs/tinydtls/aes/rijndael.h ++++ b/extlibs/tinydtls/aes/rijndael.h +@@ -30,6 +30,7 @@ + + #include + ++#define WITH_AES_DECRYPT 1 + #define AES_MAXKEYBITS (256) + #define AES_MAXKEYBYTES (AES_MAXKEYBITS>>3) + /* for 256-bit keys we need 14 rounds for a 128 we only need 10 round */ +diff --git a/extlibs/tinydtls/crypto.c b/extlibs/tinydtls/crypto.c +old mode 100755 +new mode 100644 +index 0113342..0ea1546 +--- a/extlibs/tinydtls/crypto.c ++++ b/extlibs/tinydtls/crypto.c +@@ -54,6 +54,8 @@ + #include "crypto.h" + #include "ccm.h" + #include "ecc/ecc.h" ++#include "aes/rijndael.h" ++#include "sha2/sha2.h" + #include "prng.h" + #include "netq.h" + +@@ -292,7 +294,7 @@ dtls_mac(dtls_hmac_context_t *hmac_ctx, + } + + static size_t +-dtls_ccm_encrypt(aes128_ccm_t *ccm_ctx, const unsigned char *src, size_t srclen, ++dtls_ccm_encrypt(aes128_t *ccm_ctx, const unsigned char *src, size_t srclen, + unsigned char *buf, + unsigned char *nounce, + const unsigned char *aad, size_t la) { +@@ -309,7 +311,7 @@ dtls_ccm_encrypt(aes128_ccm_t *ccm_ctx, const unsigned char *src, size_t srclen, + } + + static size_t +-dtls_ccm_decrypt(aes128_ccm_t *ccm_ctx, const unsigned char *src, ++dtls_ccm_decrypt(aes128_t *ccm_ctx, const unsigned char *src, + size_t srclen, unsigned char *buf, + unsigned char *nounce, + const unsigned char *aad, size_t la) { +@@ -325,6 +327,95 @@ dtls_ccm_decrypt(aes128_ccm_t *ccm_ctx, const unsigned char *src, + return len; + } + ++static size_t ++dtls_cbc_encrypt(aes128_t *aes_ctx, ++ const unsigned char *iv, ++ const unsigned char *src, size_t srclen, ++ unsigned char *buf) { ++ ++ unsigned char cbc[DTLS_BLK_LENGTH]; ++ unsigned char tmp[DTLS_BLK_LENGTH]; ++ unsigned char *pos; ++ dtls_hash_ctx shactx; ++ int i, j; ++ int blocks; ++ ++ pos = buf; ++ ++ dtls_hash_init(&shactx); ++ dtls_hash_update(&shactx, src, srclen); ++ dtls_hash_finalize(pos + srclen, &shactx); ++ ++ memcpy(cbc, iv, DTLS_BLK_LENGTH); ++ blocks = (srclen + SHA256_DIGEST_LENGTH) / DTLS_BLK_LENGTH; ++ ++ for (i = 0; i < blocks; i++) { ++ for (j = 0; j < DTLS_BLK_LENGTH; j++) { ++ cbc[j] ^= pos[j]; ++ } ++ ++ rijndael_encrypt(&aes_ctx->ctx, cbc, tmp); ++ memcpy(cbc, tmp, DTLS_BLK_LENGTH); ++ memcpy(pos, cbc, DTLS_BLK_LENGTH); ++ pos += DTLS_BLK_LENGTH; ++ } ++ ++ dtls_debug_dump("Encrypted Data:", buf, srclen + SHA256_DIGEST_LENGTH); ++ ++ return srclen + SHA256_DIGEST_LENGTH; ++} ++ ++ ++static size_t ++dtls_cbc_decrypt(aes128_t *aes_ctx, ++ const unsigned char *iv, ++ const unsigned char *src, size_t srclen, ++ unsigned char *buf) { ++ ++ 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 *pos; ++ dtls_hash_ctx shactx; ++ int i, j; ++ int blocks; ++ ++ pos = buf; ++ memcpy(pos, src, srclen); ++ ++ memcpy(cbc, iv, DTLS_BLK_LENGTH); ++ blocks = srclen / DTLS_BLK_LENGTH; ++ ++ for (i = 0; i < blocks; i++) ++ { ++ memcpy(tmp, pos, DTLS_BLK_LENGTH); ++ rijndael_decrypt(&aes_ctx->ctx, pos, tmp2); ++ memcpy(pos, tmp2, DTLS_BLK_LENGTH); ++ ++ for (j = 0; j < DTLS_BLK_LENGTH; j++) { ++ pos[j] ^= cbc[j]; ++ } ++ ++ memcpy(cbc, tmp, DTLS_BLK_LENGTH); ++ 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); ++ ++ if(memcmp(msg_hash, buf + (srclen - SHA256_DIGEST_LENGTH), SHA256_DIGEST_LENGTH) != 0) ++ { ++ dtls_warn("message is broken\n"); ++ return -1; ++ } ++ ++ return srclen - SHA256_DIGEST_LENGTH; ++} ++ + #ifdef DTLS_PSK + int + dtls_psk_pre_master_secret(unsigned char *key, size_t keylen, +@@ -432,13 +523,10 @@ 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]; + +- + uECC_sign(privateKey, hashValue, sign); + memcpy(point_r, sign, 32); + memcpy(point_s, sign + 32, 32); +@@ -505,21 +593,37 @@ dtls_encrypt(const unsigned char *src, size_t length, + unsigned char *buf, + unsigned char *nounce, + unsigned char *key, size_t keylen, +- const unsigned char *aad, size_t la) ++ const unsigned char *aad, size_t la, ++ const dtls_cipher_t cipher) + { +- int ret; ++ int ret = 0; + struct dtls_cipher_context_t *ctx = dtls_cipher_context_get(); + +- ret = rijndael_set_key_enc_only(&ctx->data.ctx, key, 8 * keylen); +- if (ret < 0) { +- /* cleanup everything in case the key has the wrong size */ +- dtls_warn("cannot set rijndael key\n"); +- goto error; ++ if(cipher == TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 || ++ cipher == TLS_PSK_WITH_AES_128_CCM_8) { ++ ret = rijndael_set_key_enc_only(&ctx->data.ctx, key, 8 * keylen); ++ if (ret < 0) { ++ /* cleanup everything in case the key has the wrong size */ ++ dtls_warn("cannot set rijndael key\n"); ++ goto error; ++ } ++ ++ if (src != buf) ++ 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) { ++ ret = rijndael_set_key(&ctx->data.ctx, key, 8 * keylen); ++ if (ret < 0) { ++ /* cleanup everything in case the key has the wrong size */ ++ dtls_warn("cannot set rijndael key\n"); ++ goto error; ++ } ++ ++ if (src != buf) ++ memmove(buf, src, length); ++ ret = dtls_cbc_encrypt(&ctx->data, nounce, src, length, buf); + } +- +- if (src != buf) +- memmove(buf, src, length); +- ret = dtls_ccm_encrypt(&ctx->data, src, length, buf, nounce, aad, la); + + error: + dtls_cipher_context_release(); +@@ -531,21 +635,38 @@ dtls_decrypt(const unsigned char *src, size_t length, + unsigned char *buf, + unsigned char *nounce, + unsigned char *key, size_t keylen, +- const unsigned char *aad, size_t la) ++ const unsigned char *aad, size_t la, ++ const dtls_cipher_t cipher) + { +- int ret; ++ int ret = 0; + struct dtls_cipher_context_t *ctx = dtls_cipher_context_get(); + +- ret = rijndael_set_key_enc_only(&ctx->data.ctx, key, 8 * keylen); +- if (ret < 0) { +- /* cleanup everything in case the key has the wrong size */ +- dtls_warn("cannot set rijndael key\n"); +- goto error; ++ if(cipher == TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 || ++ cipher == TLS_PSK_WITH_AES_128_CCM_8) { ++ ret = rijndael_set_key_enc_only(&ctx->data.ctx, key, 8 * keylen); ++ if (ret < 0) { ++ /* cleanup everything in case the key has the wrong size */ ++ dtls_warn("cannot set rijndael key\n"); ++ goto error; ++ } ++ ++ if (src != buf) ++ memmove(buf, src, length); ++ ret = dtls_ccm_decrypt(&ctx->data, src, length, buf, nounce, aad, la); + } + +- if (src != buf) +- memmove(buf, src, length); +- ret = dtls_ccm_decrypt(&ctx->data, src, length, buf, nounce, aad, la); ++ if(cipher == TLS_ECDH_anon_WITH_AES_128_CBC_SHA) { ++ ret = rijndael_set_key(&ctx->data.ctx, key, 8 * keylen); ++ if (ret < 0) { ++ /* cleanup everything in case the key has the wrong size */ ++ dtls_warn("cannot set rijndael key\n"); ++ goto error; ++ } ++ ++ if (src != buf) ++ memmove(buf, src, length); ++ ret = dtls_cbc_decrypt(&ctx->data, nounce, src, length, buf); ++ } + + error: + dtls_cipher_context_release(); +diff --git a/extlibs/tinydtls/crypto.h b/extlibs/tinydtls/crypto.h +index 972a174..dd13ffa 100644 +--- a/extlibs/tinydtls/crypto.h ++++ b/extlibs/tinydtls/crypto.h +@@ -69,11 +69,11 @@ typedef enum { + /** Crypto context for TLS_PSK_WITH_AES_128_CCM_8 cipher suite. */ + typedef struct { + rijndael_ctx ctx; /**< AES-128 encryption context */ +-} aes128_ccm_t; ++} aes128_t; + + typedef struct dtls_cipher_context_t { + /** numeric identifier of this cipher suite in host byte order. */ +- aes128_ccm_t data; /**< The crypto context */ ++ aes128_t data; /**< The crypto context */ + } dtls_cipher_context_t; + + typedef struct { +@@ -82,7 +82,8 @@ typedef struct { + uint8 other_eph_pub_y[32]; + uint8 other_pub_x[32]; + uint8 other_pub_y[32]; +-} dtls_handshake_parameters_ecdsa_t; ++} dtls_handshake_parameters_ecc_t; ++ + + /* This is the maximal supported length of the psk client identity and psk + * server identity hint */ +@@ -129,7 +130,7 @@ typedef struct { + unsigned int do_client_auth:1; + union { + #ifdef DTLS_ECC +- dtls_handshake_parameters_ecdsa_t ecdsa; ++ dtls_handshake_parameters_ecc_t ecc; + #endif /* DTLS_ECC */ + #ifdef DTLS_PSK + dtls_handshake_parameters_psk_t psk; +@@ -265,7 +266,8 @@ int dtls_encrypt(const unsigned char *src, size_t length, + unsigned char *buf, + unsigned char *nounce, + unsigned char *key, size_t keylen, +- const unsigned char *aad, size_t aad_length); ++ const unsigned char *aad, size_t aad_length, ++ const dtls_cipher_t cipher); + + /** + * Decrypts the given buffer \p src of given \p length, writing the +@@ -289,7 +291,8 @@ int dtls_decrypt(const unsigned char *src, size_t length, + unsigned char *buf, + unsigned char *nounce, + unsigned char *key, size_t keylen, +- const unsigned char *a_data, size_t a_data_length); ++ const unsigned char *a_data, size_t a_data_length, ++ const dtls_cipher_t cipher); + + /* helper functions */ + +diff --git a/extlibs/tinydtls/dtls.c b/extlibs/tinydtls/dtls.c +index a87d7f1..f9a9a0b 100644 +--- a/extlibs/tinydtls/dtls.c ++++ b/extlibs/tinydtls/dtls.c +@@ -79,6 +79,7 @@ + #define DTLS_SH_LENGTH (2 + DTLS_RANDOM_LENGTH + 1 + 2 + 1) + #define DTLS_CE_LENGTH (3 + 3 + 27 + DTLS_EC_KEY_SIZE + DTLS_EC_KEY_SIZE) + #define DTLS_SKEXEC_LENGTH (1 + 2 + 1 + 1 + DTLS_EC_KEY_SIZE + DTLS_EC_KEY_SIZE + 1 + 1 + 2 + 70) ++#define DTLS_SKEXEC_ECDH_ANON_LENGTH (1 + 2 + 1 + 1 + DTLS_EC_KEY_SIZE + DTLS_EC_KEY_SIZE) + #define DTLS_SKEXECPSK_LENGTH_MIN 2 + #define DTLS_SKEXECPSK_LENGTH_MAX 2 + DTLS_PSK_MAX_CLIENT_IDENTITY_LEN + #define DTLS_CKXPSK_LENGTH_MIN 2 +@@ -167,6 +168,24 @@ dtls_init() { + peer_init(); + } + ++ void ++ dtls_enables_anon_ecdh(dtls_context_t* ctx, dtls_cipher_enable_t is_enable) ++{ ++ if(ctx) ++ { ++ ctx->is_anon_ecdh_eabled = is_enable; ++ } ++} ++ ++void ++dtls_select_cipher(dtls_context_t* ctx, const dtls_cipher_t cipher) ++{ ++ if(ctx) ++ { ++ ctx->selected_cipher = cipher; ++ } ++} ++ + /* Calls cb_alert() with given arguments if defined, otherwise an + * error message is logged and the result is -1. This is just an + * internal helper. +@@ -477,6 +496,17 @@ 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) ++{ ++#ifdef DTLS_ECC ++ return cipher == TLS_ECDH_anon_WITH_AES_128_CBC_SHA; ++#else ++ return 0; ++#endif ++} ++ ++ + /** returns true if the application is configured for psk */ + static inline int is_psk_supported(dtls_context_t *ctx) + { +@@ -509,6 +539,16 @@ static inline int is_ecdsa_client_auth_supported(dtls_context_t *ctx) + #endif /* DTLS_ECC */ + } + ++/** returns true if ecdh_anon_with_aes_128_cbc_sha is supported */ ++static inline int is_ecdh_anon_supported(dtls_context_t *ctx) ++{ ++#ifdef DTLS_ECC ++ return ctx && (ctx->is_anon_ecdh_eabled == DTLS_CIPHER_ENABLE); ++#else ++ return 0; ++#endif ++} ++ + /** + * Returns @c 1 if @p code is a cipher suite other than @c + * TLS_NULL_WITH_NULL_NULL that we recognize. +@@ -522,11 +562,15 @@ static int + known_cipher(dtls_context_t *ctx, dtls_cipher_t code, int is_client) { + int psk; + int ecdsa; ++ int ecdh_anon; + + psk = is_psk_supported(ctx); + ecdsa = is_ecdsa_supported(ctx, is_client); ++ ecdh_anon = is_ecdh_anon_supported(ctx); ++ + return (psk && is_tls_psk_with_aes_128_ccm_8(code)) || +- (ecdsa && is_tls_ecdhe_ecdsa_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)); + } + + /** +@@ -674,11 +718,12 @@ calculate_key_block(dtls_context_t *ctx, + } + #endif /* DTLS_PSK */ + #ifdef DTLS_ECC +- case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8: { +- pre_master_len = dtls_ecdh_pre_master_secret(handshake->keyx.ecdsa.own_eph_priv, +- handshake->keyx.ecdsa.other_eph_pub_x, +- handshake->keyx.ecdsa.other_eph_pub_y, +- sizeof(handshake->keyx.ecdsa.own_eph_priv), ++ case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8: ++ case TLS_ECDH_anon_WITH_AES_128_CBC_SHA: { ++ 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, ++ sizeof(handshake->keyx.ecc.own_eph_priv), + pre_master_secret, + MAX_KEYBLOCK_LENGTH); + if (pre_master_len < 0) { +@@ -1038,7 +1083,8 @@ check_client_keyexchange(dtls_context_t *ctx, + uint8 *data, size_t length) { + + #ifdef DTLS_ECC +- if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(handshake->cipher)) { ++ if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(handshake->cipher) || ++ is_tls_ecdh_anon_with_aes_128_cbc_sha(handshake->cipher) ) { + + if (length < DTLS_HS_LENGTH + DTLS_CKXEC_LENGTH) { + dtls_debug("The client key exchange is too short\n"); +@@ -1058,13 +1104,13 @@ check_client_keyexchange(dtls_context_t *ctx, + } + data += sizeof(uint8); + +- memcpy(handshake->keyx.ecdsa.other_eph_pub_x, data, +- sizeof(handshake->keyx.ecdsa.other_eph_pub_x)); +- data += sizeof(handshake->keyx.ecdsa.other_eph_pub_x); ++ 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.ecdsa.other_eph_pub_y, data, +- sizeof(handshake->keyx.ecdsa.other_eph_pub_y)); +- data += sizeof(handshake->keyx.ecdsa.other_eph_pub_y); ++ 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 /* DTLS_ECC */ + #ifdef DTLS_PSK +@@ -1253,6 +1299,8 @@ 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"); + } +@@ -1332,9 +1380,10 @@ dtls_prepare_record(dtls_peer_t *peer, dtls_security_parameters_t *security, + 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), +- A_DATA, A_DATA_LEN); ++ dtls_kb_local_write_key(security, peer->role), ++ dtls_kb_key_size(security, peer->role), ++ A_DATA, A_DATA_LEN, ++ security->cipher); + + if (res < 0) + return res; +@@ -1753,8 +1802,8 @@ check_client_certificate_verify(dtls_context_t *ctx, + + dtls_hash_finalize(sha256hash, &hs_hash); + +- ret = dtls_ecdsa_verify_sig_hash(config->keyx.ecdsa.other_pub_x, config->keyx.ecdsa.other_pub_y, +- sizeof(config->keyx.ecdsa.other_pub_x), ++ ret = dtls_ecdsa_verify_sig_hash(config->keyx.ecc.other_pub_x, config->keyx.ecc.other_pub_y, ++ sizeof(config->keyx.ecc.other_pub_x), + sha256hash, sizeof(sha256hash), + result_r, result_s); + +@@ -1866,7 +1915,7 @@ dtls_send_server_hello(dtls_context_t *ctx, dtls_peer_t *peer) + #ifdef DTLS_ECC + static int + dtls_send_certificate_ecdsa(dtls_context_t *ctx, dtls_peer_t *peer, +- const dtls_ecdsa_key_t *key) ++ const dtls_ecc_key_t *key) + { + uint8 buf[DTLS_CE_LENGTH]; + uint8 *p; +@@ -1956,7 +2005,7 @@ dtls_add_ecdsa_signature_elem(uint8 *p, uint32_t *point_r, uint32_t *point_s) + + static int + dtls_send_server_key_exchange_ecdh(dtls_context_t *ctx, dtls_peer_t *peer, +- const dtls_ecdsa_key_t *key) ++ const dtls_ecc_key_t *key) + { + /* The ASN.1 Integer representation of an 32 byte unsigned int could be + * 33 bytes long add space for that */ +@@ -1967,9 +2016,11 @@ dtls_send_server_key_exchange_ecdh(dtls_context_t *ctx, dtls_peer_t *peer, + uint8 *ephemeral_pub_y; + uint32_t point_r[9]; + uint32_t point_s[9]; ++ int ecdsa; + dtls_handshake_parameters_t *config = peer->handshake_params; + +- /* ServerKeyExchange ++ ecdsa = is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(peer->handshake_params->cipher); ++ /* ServerKeyExchange + * + * Start message construction at beginning of buffer. */ + p = buf; +@@ -1998,18 +2049,20 @@ dtls_send_server_key_exchange_ecdh(dtls_context_t *ctx, dtls_peer_t *peer, + ephemeral_pub_y = p; + p += DTLS_EC_KEY_SIZE; + +- dtls_ecdsa_generate_key(config->keyx.ecdsa.own_eph_priv, +- ephemeral_pub_x, ephemeral_pub_y, +- DTLS_EC_KEY_SIZE); ++ dtls_ecdsa_generate_key(config->keyx.ecc.own_eph_priv, ++ ephemeral_pub_x, ephemeral_pub_y, ++ DTLS_EC_KEY_SIZE); + +- /* sign the ephemeral and its paramaters */ +- dtls_ecdsa_create_sig(key->priv_key, DTLS_EC_KEY_SIZE, +- config->tmp.random.client, DTLS_RANDOM_LENGTH, +- config->tmp.random.server, DTLS_RANDOM_LENGTH, +- key_params, p - key_params, +- point_r, point_s); ++ if(ecdsa) { ++ /* sign the ephemeral and its paramaters */ ++ dtls_ecdsa_create_sig(key->priv_key, DTLS_EC_KEY_SIZE, ++ config->tmp.random.client, DTLS_RANDOM_LENGTH, ++ config->tmp.random.server, DTLS_RANDOM_LENGTH, ++ key_params, p - key_params, ++ point_r, point_s); + +- p = dtls_add_ecdsa_signature_elem(p, point_r, point_s); ++ p = dtls_add_ecdsa_signature_elem(p, point_r, point_s); ++ } + + assert(p - buf <= sizeof(buf)); + +@@ -2107,6 +2160,8 @@ static int + dtls_send_server_hello_msgs(dtls_context_t *ctx, dtls_peer_t *peer) + { + int res; ++ int ecdsa; ++ int ecdh_anon; + + res = dtls_send_server_hello(ctx, peer); + +@@ -2115,9 +2170,20 @@ dtls_send_server_hello_msgs(dtls_context_t *ctx, dtls_peer_t *peer) + return res; + } + ++ 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); ++ + #ifdef DTLS_ECC +- if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(peer->handshake_params->cipher)) { +- const dtls_ecdsa_key_t *ecdsa_key; ++ if(ecdh_anon) { ++ res = dtls_send_server_key_exchange_ecdh(ctx, peer, NULL); ++ ++ if (res < 0) { ++ dtls_debug("dtls_server_hello(with ECDH): cannot prepare Server Key Exchange record\n"); ++ return res; ++ } ++ } ++ else if (ecdsa) { ++ const dtls_ecc_key_t *ecdsa_key; + + res = CALL(ctx, get_ecdsa_key, &peer->session, &ecdsa_key); + if (res < 0) { +@@ -2144,7 +2210,7 @@ dtls_send_server_hello_msgs(dtls_context_t *ctx, dtls_peer_t *peer) + res = dtls_send_server_certificate_request(ctx, peer); + + if (res < 0) { +- dtls_debug("dtls_server_hello: cannot prepare certificate Request record\n"); ++ dtls_debug("dtls_server_hello(with ECDSA): cannot prepare certificate Request record\n"); + return res; + } + } +@@ -2233,7 +2299,8 @@ 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_ECDHE_ECDSA_WITH_AES_128_CCM_8: ++ case TLS_ECDH_anon_WITH_AES_128_CBC_SHA: { + uint8 *ephemeral_pub_x; + uint8 *ephemeral_pub_y; + +@@ -2249,7 +2316,7 @@ dtls_send_client_key_exchange(dtls_context_t *ctx, dtls_peer_t *peer) + ephemeral_pub_y = p; + p += DTLS_EC_KEY_SIZE; + +- dtls_ecdsa_generate_key(peer->handshake_params->keyx.ecdsa.own_eph_priv, ++ dtls_ecdsa_generate_key(peer->handshake_params->keyx.ecc.own_eph_priv, + ephemeral_pub_x, ephemeral_pub_y, + DTLS_EC_KEY_SIZE); + +@@ -2270,7 +2337,7 @@ dtls_send_client_key_exchange(dtls_context_t *ctx, dtls_peer_t *peer) + #ifdef DTLS_ECC + static int + dtls_send_certificate_verify_ecdh(dtls_context_t *ctx, dtls_peer_t *peer, +- const dtls_ecdsa_key_t *key) ++ const dtls_ecc_key_t *key) + { + /* The ASN.1 Integer representation of an 32 byte unsigned int could be + * 33 bytes long add space for that */ +@@ -2342,16 +2409,32 @@ dtls_send_client_hello(dtls_context_t *ctx, dtls_peer_t *peer, + uint8 *p = buf; + uint8_t cipher_size; + uint8_t extension_size; +- int psk; +- int ecdsa; ++ int psk = 0; ++ int ecdsa = 0; ++ int ecdh_anon = 0; + dtls_handshake_parameters_t *handshake = peer->handshake_params; + dtls_tick_t now; + +- psk = is_psk_supported(ctx); +- ecdsa = is_ecdsa_supported(ctx, 1); ++ switch(ctx->selected_cipher) ++ { ++ case TLS_PSK_WITH_AES_128_CCM_8: ++ psk = is_psk_supported(ctx); ++ break; ++ 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: ++ ecdh_anon = is_ecdh_anon_supported(ctx); ++ break; ++ default: ++ psk = is_psk_supported(ctx); ++ ecdsa = is_ecdsa_supported(ctx, 1); ++ ecdh_anon = is_ecdh_anon_supported(ctx); ++ break; ++ } + +- cipher_size = 2 + ((ecdsa) ? 2 : 0) + ((psk) ? 2 : 0); +- extension_size = (ecdsa) ? 2 + 6 + 6 + 8 + 6: 0; ++ cipher_size = 2 + (ecdsa ? 2 : 0) + (psk ? 2 : 0) + (ecdh_anon ? 2 : 0); ++ extension_size = (ecdsa) ? (2 + 6 + 6 + 8 + 6) : 0; + + if (cipher_size == 0) { + dtls_crit("no cipher callbacks implemented\n"); +@@ -2393,14 +2476,18 @@ dtls_send_client_hello(dtls_context_t *ctx, dtls_peer_t *peer, + dtls_int_to_uint16(p, cipher_size - 2); + p += sizeof(uint16); + +- if (ecdsa) { +- dtls_int_to_uint16(p, TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8); ++ if (ecdh_anon) { ++ dtls_int_to_uint16(p, TLS_ECDH_anon_WITH_AES_128_CBC_SHA); + p += sizeof(uint16); + } + if (psk) { + dtls_int_to_uint16(p, TLS_PSK_WITH_AES_128_CCM_8); + p += sizeof(uint16); + } ++ if (ecdsa) { ++ dtls_int_to_uint16(p, TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8); ++ p += sizeof(uint16); ++ } + + /* compression method */ + dtls_int_to_uint8(p, 1); +@@ -2611,18 +2698,18 @@ check_server_certificate(dtls_context_t *ctx, + } + data += sizeof(cert_asn1_header); + +- memcpy(config->keyx.ecdsa.other_pub_x, data, +- sizeof(config->keyx.ecdsa.other_pub_x)); +- data += sizeof(config->keyx.ecdsa.other_pub_x); ++ memcpy(config->keyx.ecc.other_pub_x, data, ++ sizeof(config->keyx.ecc.other_pub_x)); ++ data += sizeof(config->keyx.ecc.other_pub_x); + +- memcpy(config->keyx.ecdsa.other_pub_y, data, +- sizeof(config->keyx.ecdsa.other_pub_y)); +- data += sizeof(config->keyx.ecdsa.other_pub_y); ++ memcpy(config->keyx.ecc.other_pub_y, data, ++ sizeof(config->keyx.ecc.other_pub_y)); ++ data += sizeof(config->keyx.ecc.other_pub_y); + + err = CALL(ctx, verify_ecdsa_key, &peer->session, +- config->keyx.ecdsa.other_pub_x, +- config->keyx.ecdsa.other_pub_y, +- sizeof(config->keyx.ecdsa.other_pub_x)); ++ config->keyx.ecc.other_pub_x, ++ config->keyx.ecc.other_pub_y, ++ sizeof(config->keyx.ecc.other_pub_x)); + if (err < 0) { + dtls_warn("The certificate was not accepted\n"); + return err; +@@ -2682,13 +2769,13 @@ check_server_key_exchange_ecdsa(dtls_context_t *ctx, + data += sizeof(uint8); + data_length -= sizeof(uint8); + +- memcpy(config->keyx.ecdsa.other_eph_pub_x, data, sizeof(config->keyx.ecdsa.other_eph_pub_y)); +- data += sizeof(config->keyx.ecdsa.other_eph_pub_y); +- data_length -= sizeof(config->keyx.ecdsa.other_eph_pub_y); ++ memcpy(config->keyx.ecc.other_eph_pub_x, 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); + +- memcpy(config->keyx.ecdsa.other_eph_pub_y, data, sizeof(config->keyx.ecdsa.other_eph_pub_y)); +- data += sizeof(config->keyx.ecdsa.other_eph_pub_y); +- data_length -= sizeof(config->keyx.ecdsa.other_eph_pub_y); ++ 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); + + ret = dtls_check_ecdsa_signature_elem(data, data_length, &result_r, &result_s); + if (ret < 0) { +@@ -2697,8 +2784,8 @@ check_server_key_exchange_ecdsa(dtls_context_t *ctx, + data += ret; + data_length -= ret; + +- ret = dtls_ecdsa_verify_sig(config->keyx.ecdsa.other_pub_x, config->keyx.ecdsa.other_pub_y, +- sizeof(config->keyx.ecdsa.other_pub_x), ++ ret = dtls_ecdsa_verify_sig(config->keyx.ecc.other_pub_x, config->keyx.ecc.other_pub_y, ++ sizeof(config->keyx.ecc.other_pub_x), + config->tmp.random.client, DTLS_RANDOM_LENGTH, + config->tmp.random.server, DTLS_RANDOM_LENGTH, + key_params, +@@ -2711,6 +2798,64 @@ check_server_key_exchange_ecdsa(dtls_context_t *ctx, + } + return 0; + } ++ ++static int ++check_server_key_exchange_ecdh(dtls_context_t *ctx, ++ dtls_peer_t *peer, ++ uint8 *data, size_t data_length) ++{ ++ dtls_handshake_parameters_t *config = peer->handshake_params; ++ ++ update_hs_hash(peer, data, data_length); ++ ++ assert(is_tls_ecdh_anon_with_aes_128_cbc_sha(config->cipher)); ++ ++ data += DTLS_HS_LENGTH; ++ ++ 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 /* DTLS_ECC */ + + #ifdef DTLS_PSK +@@ -2838,7 +2983,7 @@ check_server_hellodone(dtls_context_t *ctx, + { + int res; + #ifdef DTLS_ECC +- const dtls_ecdsa_key_t *ecdsa_key; ++ const dtls_ecc_key_t *ecdsa_key; + #endif /* DTLS_ECC */ + + dtls_handshake_parameters_t *handshake = peer->handshake_params; +@@ -2848,7 +2993,7 @@ check_server_hellodone(dtls_context_t *ctx, + update_hs_hash(peer, data, data_length); + + #ifdef DTLS_ECC +- if (handshake->do_client_auth) { ++ if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(handshake->cipher) && handshake->do_client_auth) { + + res = CALL(ctx, get_ecdsa_key, &peer->session, &ecdsa_key); + if (res < 0) { +@@ -2874,7 +3019,7 @@ check_server_hellodone(dtls_context_t *ctx, + } + + #ifdef DTLS_ECC +- if (handshake->do_client_auth) { ++ if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(handshake->cipher) && handshake->do_client_auth) { + + res = dtls_send_certificate_verify_ecdh(ctx, peer, ecdsa_key); + +@@ -2961,12 +3106,13 @@ decrypt_verify(dtls_peer_t *peer, uint8 *packet, size_t length, + clen = dtls_decrypt(*cleartext, clen, *cleartext, nonce, + dtls_kb_remote_write_key(security, peer->role), + dtls_kb_key_size(security, peer->role), +- A_DATA, A_DATA_LEN); ++ A_DATA, A_DATA_LEN, ++ security->cipher); + if (clen < 0) + dtls_warn("decryption failed\n"); + else { + #ifndef NDEBUG +- printf("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); +@@ -3071,9 +3217,11 @@ handle_handshake_msg(dtls_context_t *ctx, dtls_peer_t *peer, session_t *session, + return err; + } + if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(peer->handshake_params->cipher)) +- peer->state = DTLS_STATE_WAIT_SERVERCERTIFICATE; ++ peer->state = DTLS_STATE_WAIT_SERVERCERTIFICATE; //ecdsa ++ else if (is_tls_ecdh_anon_with_aes_128_cbc_sha(peer->handshake_params->cipher)) ++ peer->state = DTLS_STATE_WAIT_SERVERKEYEXCHANGE; //ecdh + else +- peer->state = DTLS_STATE_WAIT_SERVERHELLODONE; ++ peer->state = DTLS_STATE_WAIT_SERVERHELLODONE; //psk + /* update_hs_hash(peer, data, data_length); */ + + break; +@@ -3109,6 +3257,13 @@ 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 (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 */ + #ifdef DTLS_PSK + if (is_tls_psk_with_aes_128_ccm_8(peer->handshake_params->cipher)) { +@@ -3218,9 +3373,9 @@ 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) && + is_ecdsa_client_auth_supported(ctx)) +- peer->state = DTLS_STATE_WAIT_CERTIFICATEVERIFY; ++ peer->state = DTLS_STATE_WAIT_CERTIFICATEVERIFY; //ecdsa + else +- peer->state = DTLS_STATE_WAIT_CHANGECIPHERSPEC; ++ peer->state = DTLS_STATE_WAIT_CHANGECIPHERSPEC; //psk || ecdh_anon + break; + + #ifdef DTLS_ECC +@@ -3341,9 +3496,9 @@ 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) && + is_ecdsa_client_auth_supported(ctx)) +- peer->state = DTLS_STATE_WAIT_CLIENTCERTIFICATE; ++ peer->state = DTLS_STATE_WAIT_CLIENTCERTIFICATE; //ecdhe + else +- peer->state = DTLS_STATE_WAIT_CLIENTKEYEXCHANGE; ++ peer->state = DTLS_STATE_WAIT_CLIENTKEYEXCHANGE; //psk, ecdh_anon + + /* after sending the ServerHelloDone, we expect the + * ClientKeyExchange (possibly containing the PSK id), +diff --git a/extlibs/tinydtls/dtls.h b/extlibs/tinydtls/dtls.h +index 7ebde6b..4d82f72 100644 +--- a/extlibs/tinydtls/dtls.h ++++ b/extlibs/tinydtls/dtls.h +@@ -60,12 +60,12 @@ typedef enum dtls_credentials_type_t { + DTLS_PSK_HINT, DTLS_PSK_IDENTITY, DTLS_PSK_KEY + } dtls_credentials_type_t; + +-typedef struct dtls_ecdsa_key_t { ++typedef struct dtls_ecc_key_t { + dtls_ecdh_curve curve; + const unsigned char *priv_key; /** < private key as bytes > */ + const unsigned char *pub_key_x; /** < x part of the public key for the given private key > */ + const unsigned char *pub_key_y; /** < y part of the public key for the given private key > */ +-} dtls_ecdsa_key_t; ++} dtls_ecc_key_t; + + /** Length of the secret that is used for generating Hello Verify cookies. */ + #define DTLS_COOKIE_SECRET_LENGTH 12 +@@ -183,7 +183,7 @@ typedef struct { + */ + int (*get_ecdsa_key)(struct dtls_context_t *ctx, + const session_t *session, +- const dtls_ecdsa_key_t **result); ++ const dtls_ecc_key_t **result); + + /** + * Called during handshake to check the peer's pubic key in this +@@ -238,6 +238,10 @@ 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_t selected_cipher; /**< selected ciper suite for handshake */ ++ + unsigned char readbuf[DTLS_MAX_BUF]; + } dtls_context_t; + +@@ -263,6 +267,24 @@ static inline void dtls_set_handler(dtls_context_t *ctx, dtls_handler_t *h) { + ctx->h = h; + } + ++ /** ++ * @brief Enabling the TLS_ECDH_anon_WITH_AES_128_CBC_SHA ++ * ++ * @param ctx The DTLS context to use. ++ * @param is_enable DTLS_CIPHER_ENABLE(1) or DTLS_CIPHER_DISABLE(0) ++ */ ++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) ++ * TLS_PSK_WITH_AES_128_CCM_8 (0xX0A8) ++ * TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 (0xC0AE) ++ */ ++void dtls_select_cipher(dtls_context_t* ctx, const dtls_cipher_t cipher); ++ + /** + * Establishes a DTLS channel with the specified remote peer @p dst. + * This function returns @c 0 if that channel already exists, a value +diff --git a/extlibs/tinydtls/global.h b/extlibs/tinydtls/global.h +index f0977c8..441710f 100644 +--- a/extlibs/tinydtls/global.h ++++ b/extlibs/tinydtls/global.h +@@ -73,10 +73,16 @@ 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_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; + ++typedef enum { ++ DTLS_CIPHER_DISABLE = 0, ++ DTLS_CIPHER_ENABLE = 1 ++} dtls_cipher_enable_t; ++ + /** Known compression suites.*/ + typedef enum { + TLS_COMPRESSION_NULL = 0x0000 /* NULL compression */ +diff --git a/extlibs/tinydtls/tests/dtls-client.c b/extlibs/tinydtls/tests/dtls-client.c +index 65b0275..3a3e4ca 100644 +--- a/extlibs/tinydtls/tests/dtls-client.c ++++ b/extlibs/tinydtls/tests/dtls-client.c +@@ -147,8 +147,8 @@ get_psk_info(struct dtls_context_t *ctx UNUSED_PARAM, + static int + get_ecdsa_key(struct dtls_context_t *ctx, + const session_t *session, +- const dtls_ecdsa_key_t **result) { +- static const dtls_ecdsa_key_t ecdsa_key = { ++ const dtls_ecc_key_t **result) { ++ static const dtls_ecc_key_t ecdsa_key = { + .curve = DTLS_ECDH_CURVE_SECP256R1, + .priv_key = ecdsa_priv_key, + .pub_key_x = ecdsa_pub_key_x, +@@ -294,9 +294,9 @@ usage( const char *program, const char *version) { + fprintf(stderr, "%s v%s -- DTLS client implementation\n" + "(c) 2011-2014 Olaf Bergmann \n\n" + #ifdef DTLS_PSK +- "usage: %s [-i file] [-s file] [-k file] [-o file] [-p port] [-v num] addr [port]\n" ++ "usage: %s [-i file] [-s file] [-k file] [-o file] [-p port] [-v num] [-c num] addr [port]\n" + #else /* DTLS_PSK */ +- "usage: %s [-o file] [-p port] [-v num] addr [port]\n" ++ "usage: %s [-o file] [-p port] [-v num] [-c num] addr [port]\n" + #endif /* DTLS_PSK */ + #ifdef DTLS_PSK + "\t-i file\t\tread PSK Client identity from file\n" +@@ -305,7 +305,11 @@ usage( const char *program, const char *version) { + #endif /* DTLS_PSK */ + "\t-o file\t\toutput received data to this file (use '-' for STDOUT)\n" + "\t-p port\t\tlisten on specified port (default is %d)\n" +- "\t-v num\t\tverbosity level (default: 3)\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\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); + } + +@@ -334,6 +338,8 @@ 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_enable_t ecdh_anon_enalbe = DTLS_CIPHER_ENABLE; + int opt, res; + session_t dst; + +@@ -349,7 +355,7 @@ main(int argc, char **argv) { + memcpy(psk_key, PSK_DEFAULT_KEY, psk_key_length); + #endif /* DTLS_PSK */ + +- while ((opt = getopt(argc, argv, "p:o:v:" PSK_OPTIONS)) != -1) { ++ while ((opt = getopt(argc, argv, "p:o:v:c:" PSK_OPTIONS)) != -1) { + switch (opt) { + #ifdef DTLS_PSK + case 'i' : { +@@ -399,6 +405,23 @@ main(int argc, char **argv) { + case 'v' : + log_level = strtol(optarg, NULL, 10); + break; ++ case 'c': ++ if( strcmp(optarg, "1") == 0) ++ { ++ selected_cipher = TLS_ECDH_anon_WITH_AES_128_CBC_SHA; ++ ecdh_anon_enalbe = DTLS_CIPHER_ENABLE; ++ } ++ else if( strcmp(optarg, "2") == 0) ++ { ++ selected_cipher = TLS_PSK_WITH_AES_128_CCM_8 ; ++ ecdh_anon_enalbe = DTLS_CIPHER_DISABLE; ++ } ++ else if( strcmp(optarg, "3") == 0) ++ { ++ selected_cipher = TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 ; ++ ecdh_anon_enalbe = DTLS_CIPHER_DISABLE; ++ } ++ break; + default: + usage(argv[0], dtls_package_version()); + exit(1); +@@ -464,6 +487,13 @@ main(int argc, char **argv) { + exit(-1); + } + ++ ++ /* select cipher suite */ ++ dtls_select_cipher(dtls_context, selected_cipher); ++ ++ /* enable/disable tls_ecdh_anon_with_aes_128_cbc_sha */ ++ dtls_enables_anon_ecdh(dtls_context, ecdh_anon_enalbe); ++ + dtls_set_handler(dtls_context, &cb); + + dtls_connect(dtls_context, &dst); +diff --git a/extlibs/tinydtls/tests/dtls-server.c b/extlibs/tinydtls/tests/dtls-server.c +index ae1283e..d3da1a7 100644 +--- a/extlibs/tinydtls/tests/dtls-server.c ++++ b/extlibs/tinydtls/tests/dtls-server.c +@@ -113,8 +113,8 @@ get_psk_info(struct dtls_context_t *ctx, const session_t *session, + static int + get_ecdsa_key(struct dtls_context_t *ctx, + const session_t *session, +- const dtls_ecdsa_key_t **result) { +- static const dtls_ecdsa_key_t ecdsa_key = { ++ const dtls_ecc_key_t **result) { ++ static const dtls_ecc_key_t ecdsa_key = { + .curve = DTLS_ECDH_CURVE_SECP256R1, + .priv_key = ecdsa_priv_key, + .pub_key_x = ecdsa_pub_key_x, +@@ -249,10 +249,13 @@ usage(const char *program, const char *version) { + + fprintf(stderr, "%s v%s -- DTLS server implementation\n" + "(c) 2011-2014 Olaf Bergmann \n\n" +- "usage: %s [-A address] [-p port] [-v num]\n" ++ "usage: %s [-A address] [-p port] [-v num] [-a enable|disable]\n" + "\t-A address\t\tlisten on specified address (default is ::)\n" + "\t-p port\t\tlisten on specified port (default is %d)\n" +- "\t-v num\t\tverbosity level (default: 3)\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", + program, version, program, DEFAULT_PORT); + } + +@@ -277,6 +280,7 @@ main(int argc, char **argv) { + struct timeval timeout; + int fd, opt, result; + int on = 1; ++ int ecdh_anon_enalbe = DTLS_CIPHER_DISABLE; + struct sockaddr_in6 listen_addr; + + memset(&listen_addr, 0, sizeof(struct sockaddr_in6)); +@@ -290,7 +294,7 @@ main(int argc, char **argv) { + listen_addr.sin6_port = htons(DEFAULT_PORT); + listen_addr.sin6_addr = in6addr_any; + +- while ((opt = getopt(argc, argv, "A:p:v:")) != -1) { ++ while ((opt = getopt(argc, argv, "A:p:v:a:")) != -1) { + switch (opt) { + case 'A' : + if (resolve_address(optarg, (struct sockaddr *)&listen_addr) < 0) { +@@ -304,6 +308,10 @@ main(int argc, char **argv) { + case 'v' : + log_level = strtol(optarg, NULL, 10); + break; ++ case 'a': ++ if( strcmp(optarg, "enable") == 0) ++ ecdh_anon_enalbe = DTLS_CIPHER_ENABLE; ++ break; + default: + usage(argv[0], dtls_package_version()); + exit(1); +@@ -348,6 +356,9 @@ main(int argc, char **argv) { + + the_context = dtls_new_context(&fd); + ++ /* enable/disable tls_ecdh_anon_with_aes_128_cbc_sha */ ++ dtls_enables_anon_ecdh(the_context, ecdh_anon_enalbe); ++ + dtls_set_handler(the_context, &cb); + + while (1) { +-- +1.7.9.5 + diff --git a/extlibs/tinydtls/aes/rijndael.h b/extlibs/tinydtls/aes/rijndael.h index 60e9bef..712798b 100644 --- a/extlibs/tinydtls/aes/rijndael.h +++ b/extlibs/tinydtls/aes/rijndael.h @@ -30,6 +30,7 @@ #include +#define WITH_AES_DECRYPT 1 #define AES_MAXKEYBITS (256) #define AES_MAXKEYBYTES (AES_MAXKEYBITS>>3) /* for 256-bit keys we need 14 rounds for a 128 we only need 10 round */ diff --git a/extlibs/tinydtls/crypto.c b/extlibs/tinydtls/crypto.c index 0113342..5082535 100644 --- a/extlibs/tinydtls/crypto.c +++ b/extlibs/tinydtls/crypto.c @@ -54,6 +54,8 @@ #include "crypto.h" #include "ccm.h" #include "ecc/ecc.h" +#include "aes/rijndael.h" +#include "sha2/sha2.h" #include "prng.h" #include "netq.h" @@ -292,7 +294,7 @@ dtls_mac(dtls_hmac_context_t *hmac_ctx, } static size_t -dtls_ccm_encrypt(aes128_ccm_t *ccm_ctx, const unsigned char *src, size_t srclen, +dtls_ccm_encrypt(aes128_t *ccm_ctx, const unsigned char *src, size_t srclen, unsigned char *buf, unsigned char *nounce, const unsigned char *aad, size_t la) { @@ -309,7 +311,7 @@ dtls_ccm_encrypt(aes128_ccm_t *ccm_ctx, const unsigned char *src, size_t srclen, } static size_t -dtls_ccm_decrypt(aes128_ccm_t *ccm_ctx, const unsigned char *src, +dtls_ccm_decrypt(aes128_t *ccm_ctx, const unsigned char *src, size_t srclen, unsigned char *buf, unsigned char *nounce, const unsigned char *aad, size_t la) { @@ -325,6 +327,95 @@ dtls_ccm_decrypt(aes128_ccm_t *ccm_ctx, const unsigned char *src, return len; } +static size_t +dtls_cbc_encrypt(aes128_t *aes_ctx, + const unsigned char *iv, + const unsigned char *src, size_t srclen, + unsigned char *buf) { + + unsigned char cbc[DTLS_BLK_LENGTH]; + unsigned char tmp[DTLS_BLK_LENGTH]; + unsigned char *pos; + dtls_hash_ctx shactx; + int i, j; + int blocks; + + pos = buf; + + dtls_hash_init(&shactx); + dtls_hash_update(&shactx, src, srclen); + dtls_hash_finalize(pos + srclen, &shactx); + + memcpy(cbc, iv, DTLS_BLK_LENGTH); + blocks = (srclen + SHA256_DIGEST_LENGTH) / DTLS_BLK_LENGTH; + + for (i = 0; i < blocks; i++) { + for (j = 0; j < DTLS_BLK_LENGTH; j++) { + cbc[j] ^= pos[j]; + } + + rijndael_encrypt(&aes_ctx->ctx, cbc, tmp); + memcpy(cbc, tmp, DTLS_BLK_LENGTH); + memcpy(pos, cbc, DTLS_BLK_LENGTH); + pos += DTLS_BLK_LENGTH; + } + + dtls_debug_dump("Encrypted Data:", buf, srclen + SHA256_DIGEST_LENGTH); + + return srclen + SHA256_DIGEST_LENGTH; +} + + +static size_t +dtls_cbc_decrypt(aes128_t *aes_ctx, + const unsigned char *iv, + const unsigned char *src, size_t srclen, + unsigned char *buf) { + + 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 *pos; + dtls_hash_ctx shactx; + int i, j; + int blocks; + + pos = buf; + memcpy(pos, src, srclen); + + memcpy(cbc, iv, DTLS_BLK_LENGTH); + blocks = srclen / DTLS_BLK_LENGTH; + + for (i = 0; i < blocks; i++) + { + memcpy(tmp, pos, DTLS_BLK_LENGTH); + rijndael_decrypt(&aes_ctx->ctx, pos, tmp2); + memcpy(pos, tmp2, DTLS_BLK_LENGTH); + + for (j = 0; j < DTLS_BLK_LENGTH; j++) { + pos[j] ^= cbc[j]; + } + + memcpy(cbc, tmp, DTLS_BLK_LENGTH); + 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); + + if(memcmp(msg_hash, buf + (srclen - SHA256_DIGEST_LENGTH), SHA256_DIGEST_LENGTH) != 0) + { + dtls_warn("message is broken\n"); + return -1; + } + + return srclen - SHA256_DIGEST_LENGTH; +} + #ifdef DTLS_PSK int dtls_psk_pre_master_secret(unsigned char *key, size_t keylen, @@ -505,21 +596,37 @@ dtls_encrypt(const unsigned char *src, size_t length, unsigned char *buf, unsigned char *nounce, unsigned char *key, size_t keylen, - const unsigned char *aad, size_t la) + const unsigned char *aad, size_t la, + const dtls_cipher_t cipher) { - int ret; + int ret = 0; struct dtls_cipher_context_t *ctx = dtls_cipher_context_get(); - ret = rijndael_set_key_enc_only(&ctx->data.ctx, key, 8 * keylen); - if (ret < 0) { - /* cleanup everything in case the key has the wrong size */ - dtls_warn("cannot set rijndael key\n"); - goto error; + if(cipher == TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 || + cipher == TLS_PSK_WITH_AES_128_CCM_8) { + ret = rijndael_set_key_enc_only(&ctx->data.ctx, key, 8 * keylen); + if (ret < 0) { + /* cleanup everything in case the key has the wrong size */ + dtls_warn("cannot set rijndael key\n"); + goto error; + } + + if (src != buf) + 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) { + ret = rijndael_set_key(&ctx->data.ctx, key, 8 * keylen); + if (ret < 0) { + /* cleanup everything in case the key has the wrong size */ + dtls_warn("cannot set rijndael key\n"); + goto error; + } + + if (src != buf) + memmove(buf, src, length); + ret = dtls_cbc_encrypt(&ctx->data, nounce, src, length, buf); } - - if (src != buf) - memmove(buf, src, length); - ret = dtls_ccm_encrypt(&ctx->data, src, length, buf, nounce, aad, la); error: dtls_cipher_context_release(); @@ -531,21 +638,38 @@ dtls_decrypt(const unsigned char *src, size_t length, unsigned char *buf, unsigned char *nounce, unsigned char *key, size_t keylen, - const unsigned char *aad, size_t la) + const unsigned char *aad, size_t la, + const dtls_cipher_t cipher) { - int ret; + int ret = 0; struct dtls_cipher_context_t *ctx = dtls_cipher_context_get(); - ret = rijndael_set_key_enc_only(&ctx->data.ctx, key, 8 * keylen); - if (ret < 0) { - /* cleanup everything in case the key has the wrong size */ - dtls_warn("cannot set rijndael key\n"); - goto error; + if(cipher == TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 || + cipher == TLS_PSK_WITH_AES_128_CCM_8) { + ret = rijndael_set_key_enc_only(&ctx->data.ctx, key, 8 * keylen); + if (ret < 0) { + /* cleanup everything in case the key has the wrong size */ + dtls_warn("cannot set rijndael key\n"); + goto error; + } + + if (src != buf) + memmove(buf, src, length); + ret = dtls_ccm_decrypt(&ctx->data, src, length, buf, nounce, aad, la); } - if (src != buf) - memmove(buf, src, length); - ret = dtls_ccm_decrypt(&ctx->data, src, length, buf, nounce, aad, la); + if(cipher == TLS_ECDH_anon_WITH_AES_128_CBC_SHA) { + ret = rijndael_set_key(&ctx->data.ctx, key, 8 * keylen); + if (ret < 0) { + /* cleanup everything in case the key has the wrong size */ + dtls_warn("cannot set rijndael key\n"); + goto error; + } + + if (src != buf) + memmove(buf, src, length); + ret = dtls_cbc_decrypt(&ctx->data, nounce, src, length, buf); + } error: dtls_cipher_context_release(); diff --git a/extlibs/tinydtls/crypto.h b/extlibs/tinydtls/crypto.h index 972a174..dd13ffa 100644 --- a/extlibs/tinydtls/crypto.h +++ b/extlibs/tinydtls/crypto.h @@ -69,11 +69,11 @@ typedef enum { /** Crypto context for TLS_PSK_WITH_AES_128_CCM_8 cipher suite. */ typedef struct { rijndael_ctx ctx; /**< AES-128 encryption context */ -} aes128_ccm_t; +} aes128_t; typedef struct dtls_cipher_context_t { /** numeric identifier of this cipher suite in host byte order. */ - aes128_ccm_t data; /**< The crypto context */ + aes128_t data; /**< The crypto context */ } dtls_cipher_context_t; typedef struct { @@ -82,7 +82,8 @@ typedef struct { uint8 other_eph_pub_y[32]; uint8 other_pub_x[32]; uint8 other_pub_y[32]; -} dtls_handshake_parameters_ecdsa_t; +} dtls_handshake_parameters_ecc_t; + /* This is the maximal supported length of the psk client identity and psk * server identity hint */ @@ -129,7 +130,7 @@ typedef struct { unsigned int do_client_auth:1; union { #ifdef DTLS_ECC - dtls_handshake_parameters_ecdsa_t ecdsa; + dtls_handshake_parameters_ecc_t ecc; #endif /* DTLS_ECC */ #ifdef DTLS_PSK dtls_handshake_parameters_psk_t psk; @@ -265,7 +266,8 @@ int dtls_encrypt(const unsigned char *src, size_t length, unsigned char *buf, unsigned char *nounce, unsigned char *key, size_t keylen, - const unsigned char *aad, size_t aad_length); + const unsigned char *aad, size_t aad_length, + const dtls_cipher_t cipher); /** * Decrypts the given buffer \p src of given \p length, writing the @@ -289,7 +291,8 @@ int dtls_decrypt(const unsigned char *src, size_t length, unsigned char *buf, unsigned char *nounce, unsigned char *key, size_t keylen, - const unsigned char *a_data, size_t a_data_length); + const unsigned char *a_data, size_t a_data_length, + const dtls_cipher_t cipher); /* helper functions */ diff --git a/extlibs/tinydtls/dtls.c b/extlibs/tinydtls/dtls.c index a923386..41e68a5 100644 --- a/extlibs/tinydtls/dtls.c +++ b/extlibs/tinydtls/dtls.c @@ -79,6 +79,7 @@ #define DTLS_SH_LENGTH (2 + DTLS_RANDOM_LENGTH + 1 + 2 + 1) #define DTLS_CE_LENGTH (3 + 3 + 27 + DTLS_EC_KEY_SIZE + DTLS_EC_KEY_SIZE) #define DTLS_SKEXEC_LENGTH (1 + 2 + 1 + 1 + DTLS_EC_KEY_SIZE + DTLS_EC_KEY_SIZE + 1 + 1 + 2 + 70) +#define DTLS_SKEXEC_ECDH_ANON_LENGTH (1 + 2 + 1 + 1 + DTLS_EC_KEY_SIZE + DTLS_EC_KEY_SIZE) #define DTLS_SKEXECPSK_LENGTH_MIN 2 #define DTLS_SKEXECPSK_LENGTH_MAX 2 + DTLS_PSK_MAX_CLIENT_IDENTITY_LEN #define DTLS_CKXPSK_LENGTH_MIN 2 @@ -167,6 +168,24 @@ dtls_init() { peer_init(); } + void + dtls_enables_anon_ecdh(dtls_context_t* ctx, dtls_cipher_enable_t is_enable) +{ + if(ctx) + { + ctx->is_anon_ecdh_eabled = is_enable; + } +} + +void +dtls_select_cipher(dtls_context_t* ctx, const dtls_cipher_t cipher) +{ + if(ctx) + { + ctx->selected_cipher = cipher; + } +} + /* Calls cb_alert() with given arguments if defined, otherwise an * error message is logged and the result is -1. This is just an * internal helper. @@ -477,6 +496,17 @@ 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) +{ +#ifdef DTLS_ECC + return cipher == TLS_ECDH_anon_WITH_AES_128_CBC_SHA; +#else + return 0; +#endif +} + + /** returns true if the application is configured for psk */ static inline int is_psk_supported(dtls_context_t *ctx) { @@ -509,6 +539,16 @@ static inline int is_ecdsa_client_auth_supported(dtls_context_t *ctx) #endif /* DTLS_ECC */ } +/** returns true if ecdh_anon_with_aes_128_cbc_sha is supported */ +static inline int is_ecdh_anon_supported(dtls_context_t *ctx) +{ +#ifdef DTLS_ECC + return ctx && (ctx->is_anon_ecdh_eabled == DTLS_CIPHER_ENABLE); +#else + return 0; +#endif +} + /** * Returns @c 1 if @p code is a cipher suite other than @c * TLS_NULL_WITH_NULL_NULL that we recognize. @@ -522,11 +562,15 @@ static int known_cipher(dtls_context_t *ctx, dtls_cipher_t code, int is_client) { int psk; int ecdsa; + int ecdh_anon; psk = is_psk_supported(ctx); ecdsa = is_ecdsa_supported(ctx, is_client); + ecdh_anon = is_ecdh_anon_supported(ctx); + return (psk && is_tls_psk_with_aes_128_ccm_8(code)) || - (ecdsa && is_tls_ecdhe_ecdsa_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)); } /** @@ -674,11 +718,12 @@ calculate_key_block(dtls_context_t *ctx, } #endif /* DTLS_PSK */ #ifdef DTLS_ECC - case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8: { - pre_master_len = dtls_ecdh_pre_master_secret(handshake->keyx.ecdsa.own_eph_priv, - handshake->keyx.ecdsa.other_eph_pub_x, - handshake->keyx.ecdsa.other_eph_pub_y, - sizeof(handshake->keyx.ecdsa.own_eph_priv), + case TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8: + case TLS_ECDH_anon_WITH_AES_128_CBC_SHA: { + 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, + sizeof(handshake->keyx.ecc.own_eph_priv), pre_master_secret, MAX_KEYBLOCK_LENGTH); if (pre_master_len < 0) { @@ -1038,7 +1083,8 @@ check_client_keyexchange(dtls_context_t *ctx, uint8 *data, size_t length) { #ifdef DTLS_ECC - if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(handshake->cipher)) { + if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(handshake->cipher) || + is_tls_ecdh_anon_with_aes_128_cbc_sha(handshake->cipher) ) { if (length < DTLS_HS_LENGTH + DTLS_CKXEC_LENGTH) { dtls_debug("The client key exchange is too short\n"); @@ -1058,13 +1104,13 @@ check_client_keyexchange(dtls_context_t *ctx, } data += sizeof(uint8); - memcpy(handshake->keyx.ecdsa.other_eph_pub_x, data, - sizeof(handshake->keyx.ecdsa.other_eph_pub_x)); - data += sizeof(handshake->keyx.ecdsa.other_eph_pub_x); + 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.ecdsa.other_eph_pub_y, data, - sizeof(handshake->keyx.ecdsa.other_eph_pub_y)); - data += sizeof(handshake->keyx.ecdsa.other_eph_pub_y); + 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 /* DTLS_ECC */ #ifdef DTLS_PSK @@ -1253,6 +1299,8 @@ 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"); } @@ -1332,9 +1380,10 @@ dtls_prepare_record(dtls_peer_t *peer, dtls_security_parameters_t *security, 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), - A_DATA, A_DATA_LEN); + dtls_kb_local_write_key(security, peer->role), + dtls_kb_key_size(security, peer->role), + A_DATA, A_DATA_LEN, + security->cipher); if (res < 0) return res; @@ -1754,8 +1803,8 @@ check_client_certificate_verify(dtls_context_t *ctx, dtls_hash_finalize(sha256hash, &hs_hash); - ret = dtls_ecdsa_verify_sig_hash(config->keyx.ecdsa.other_pub_x, config->keyx.ecdsa.other_pub_y, - sizeof(config->keyx.ecdsa.other_pub_x), + ret = dtls_ecdsa_verify_sig_hash(config->keyx.ecc.other_pub_x, config->keyx.ecc.other_pub_y, + sizeof(config->keyx.ecc.other_pub_x), sha256hash, sizeof(sha256hash), result_r, result_s); @@ -1867,7 +1916,7 @@ dtls_send_server_hello(dtls_context_t *ctx, dtls_peer_t *peer) #ifdef DTLS_ECC static int dtls_send_certificate_ecdsa(dtls_context_t *ctx, dtls_peer_t *peer, - const dtls_ecdsa_key_t *key) + const dtls_ecc_key_t *key) { uint8 buf[DTLS_CE_LENGTH]; uint8 *p; @@ -1957,7 +2006,7 @@ dtls_add_ecdsa_signature_elem(uint8 *p, uint32_t *point_r, uint32_t *point_s) static int dtls_send_server_key_exchange_ecdh(dtls_context_t *ctx, dtls_peer_t *peer, - const dtls_ecdsa_key_t *key) + const dtls_ecc_key_t *key) { /* The ASN.1 Integer representation of an 32 byte unsigned int could be * 33 bytes long add space for that */ @@ -1968,9 +2017,11 @@ dtls_send_server_key_exchange_ecdh(dtls_context_t *ctx, dtls_peer_t *peer, uint8 *ephemeral_pub_y; uint32_t point_r[9]; uint32_t point_s[9]; + int ecdsa; dtls_handshake_parameters_t *config = peer->handshake_params; - /* ServerKeyExchange + ecdsa = is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(peer->handshake_params->cipher); + /* ServerKeyExchange * * Start message construction at beginning of buffer. */ p = buf; @@ -1999,18 +2050,20 @@ dtls_send_server_key_exchange_ecdh(dtls_context_t *ctx, dtls_peer_t *peer, ephemeral_pub_y = p; p += DTLS_EC_KEY_SIZE; - dtls_ecdsa_generate_key(config->keyx.ecdsa.own_eph_priv, - ephemeral_pub_x, ephemeral_pub_y, - DTLS_EC_KEY_SIZE); + dtls_ecdsa_generate_key(config->keyx.ecc.own_eph_priv, + ephemeral_pub_x, ephemeral_pub_y, + DTLS_EC_KEY_SIZE); - /* sign the ephemeral and its paramaters */ - dtls_ecdsa_create_sig(key->priv_key, DTLS_EC_KEY_SIZE, - config->tmp.random.client, DTLS_RANDOM_LENGTH, - config->tmp.random.server, DTLS_RANDOM_LENGTH, - key_params, p - key_params, - point_r, point_s); + if(ecdsa) { + /* sign the ephemeral and its paramaters */ + dtls_ecdsa_create_sig(key->priv_key, DTLS_EC_KEY_SIZE, + config->tmp.random.client, DTLS_RANDOM_LENGTH, + config->tmp.random.server, DTLS_RANDOM_LENGTH, + key_params, p - key_params, + point_r, point_s); - p = dtls_add_ecdsa_signature_elem(p, point_r, point_s); + p = dtls_add_ecdsa_signature_elem(p, point_r, point_s); + } assert(p - buf <= sizeof(buf)); @@ -2108,6 +2161,8 @@ static int dtls_send_server_hello_msgs(dtls_context_t *ctx, dtls_peer_t *peer) { int res; + int ecdsa; + int ecdh_anon; res = dtls_send_server_hello(ctx, peer); @@ -2116,9 +2171,20 @@ dtls_send_server_hello_msgs(dtls_context_t *ctx, dtls_peer_t *peer) return res; } + 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); + #ifdef DTLS_ECC - if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(peer->handshake_params->cipher)) { - const dtls_ecdsa_key_t *ecdsa_key; + if(ecdh_anon) { + res = dtls_send_server_key_exchange_ecdh(ctx, peer, NULL); + + if (res < 0) { + dtls_debug("dtls_server_hello(with ECDH): cannot prepare Server Key Exchange record\n"); + return res; + } + } + else if (ecdsa) { + const dtls_ecc_key_t *ecdsa_key; res = CALL(ctx, get_ecdsa_key, &peer->session, &ecdsa_key); if (res < 0) { @@ -2145,7 +2211,7 @@ dtls_send_server_hello_msgs(dtls_context_t *ctx, dtls_peer_t *peer) res = dtls_send_server_certificate_request(ctx, peer); if (res < 0) { - dtls_debug("dtls_server_hello: cannot prepare certificate Request record\n"); + dtls_debug("dtls_server_hello(with ECDSA): cannot prepare certificate Request record\n"); return res; } } @@ -2234,7 +2300,8 @@ 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_ECDHE_ECDSA_WITH_AES_128_CCM_8: + case TLS_ECDH_anon_WITH_AES_128_CBC_SHA: { uint8 *ephemeral_pub_x; uint8 *ephemeral_pub_y; @@ -2250,7 +2317,7 @@ dtls_send_client_key_exchange(dtls_context_t *ctx, dtls_peer_t *peer) ephemeral_pub_y = p; p += DTLS_EC_KEY_SIZE; - dtls_ecdsa_generate_key(peer->handshake_params->keyx.ecdsa.own_eph_priv, + dtls_ecdsa_generate_key(peer->handshake_params->keyx.ecc.own_eph_priv, ephemeral_pub_x, ephemeral_pub_y, DTLS_EC_KEY_SIZE); @@ -2271,7 +2338,7 @@ dtls_send_client_key_exchange(dtls_context_t *ctx, dtls_peer_t *peer) #ifdef DTLS_ECC static int dtls_send_certificate_verify_ecdh(dtls_context_t *ctx, dtls_peer_t *peer, - const dtls_ecdsa_key_t *key) + const dtls_ecc_key_t *key) { /* The ASN.1 Integer representation of an 32 byte unsigned int could be * 33 bytes long add space for that */ @@ -2343,16 +2410,32 @@ dtls_send_client_hello(dtls_context_t *ctx, dtls_peer_t *peer, uint8 *p = buf; uint8_t cipher_size; uint8_t extension_size; - int psk; - int ecdsa; + int psk = 0; + int ecdsa = 0; + int ecdh_anon = 0; dtls_handshake_parameters_t *handshake = peer->handshake_params; dtls_tick_t now; - psk = is_psk_supported(ctx); - ecdsa = is_ecdsa_supported(ctx, 1); + switch(ctx->selected_cipher) + { + case TLS_PSK_WITH_AES_128_CCM_8: + psk = is_psk_supported(ctx); + break; + 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: + ecdh_anon = is_ecdh_anon_supported(ctx); + break; + default: + psk = is_psk_supported(ctx); + ecdsa = is_ecdsa_supported(ctx, 1); + ecdh_anon = is_ecdh_anon_supported(ctx); + break; + } - cipher_size = 2 + ((ecdsa) ? 2 : 0) + ((psk) ? 2 : 0); - extension_size = (ecdsa) ? 2 + 6 + 6 + 8 + 6: 0; + cipher_size = 2 + (ecdsa ? 2 : 0) + (psk ? 2 : 0) + (ecdh_anon ? 2 : 0); + extension_size = (ecdsa) ? (2 + 6 + 6 + 8 + 6) : 0; if (cipher_size == 0) { dtls_crit("no cipher callbacks implemented\n"); @@ -2394,14 +2477,18 @@ dtls_send_client_hello(dtls_context_t *ctx, dtls_peer_t *peer, dtls_int_to_uint16(p, cipher_size - 2); p += sizeof(uint16); - if (ecdsa) { - dtls_int_to_uint16(p, TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8); + if (ecdh_anon) { + dtls_int_to_uint16(p, TLS_ECDH_anon_WITH_AES_128_CBC_SHA); p += sizeof(uint16); } if (psk) { dtls_int_to_uint16(p, TLS_PSK_WITH_AES_128_CCM_8); p += sizeof(uint16); } + if (ecdsa) { + dtls_int_to_uint16(p, TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8); + p += sizeof(uint16); + } /* compression method */ dtls_int_to_uint8(p, 1); @@ -2612,18 +2699,18 @@ check_server_certificate(dtls_context_t *ctx, } data += sizeof(cert_asn1_header); - memcpy(config->keyx.ecdsa.other_pub_x, data, - sizeof(config->keyx.ecdsa.other_pub_x)); - data += sizeof(config->keyx.ecdsa.other_pub_x); + memcpy(config->keyx.ecc.other_pub_x, data, + sizeof(config->keyx.ecc.other_pub_x)); + data += sizeof(config->keyx.ecc.other_pub_x); - memcpy(config->keyx.ecdsa.other_pub_y, data, - sizeof(config->keyx.ecdsa.other_pub_y)); - data += sizeof(config->keyx.ecdsa.other_pub_y); + memcpy(config->keyx.ecc.other_pub_y, data, + sizeof(config->keyx.ecc.other_pub_y)); + data += sizeof(config->keyx.ecc.other_pub_y); err = CALL(ctx, verify_ecdsa_key, &peer->session, - config->keyx.ecdsa.other_pub_x, - config->keyx.ecdsa.other_pub_y, - sizeof(config->keyx.ecdsa.other_pub_x)); + config->keyx.ecc.other_pub_x, + config->keyx.ecc.other_pub_y, + sizeof(config->keyx.ecc.other_pub_x)); if (err < 0) { dtls_warn("The certificate was not accepted\n"); return err; @@ -2683,13 +2770,13 @@ check_server_key_exchange_ecdsa(dtls_context_t *ctx, data += sizeof(uint8); data_length -= sizeof(uint8); - memcpy(config->keyx.ecdsa.other_eph_pub_x, data, sizeof(config->keyx.ecdsa.other_eph_pub_y)); - data += sizeof(config->keyx.ecdsa.other_eph_pub_y); - data_length -= sizeof(config->keyx.ecdsa.other_eph_pub_y); + memcpy(config->keyx.ecc.other_eph_pub_x, 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); - memcpy(config->keyx.ecdsa.other_eph_pub_y, data, sizeof(config->keyx.ecdsa.other_eph_pub_y)); - data += sizeof(config->keyx.ecdsa.other_eph_pub_y); - data_length -= sizeof(config->keyx.ecdsa.other_eph_pub_y); + 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); ret = dtls_check_ecdsa_signature_elem(data, data_length, &result_r, &result_s); if (ret < 0) { @@ -2698,8 +2785,8 @@ check_server_key_exchange_ecdsa(dtls_context_t *ctx, data += ret; data_length -= ret; - ret = dtls_ecdsa_verify_sig(config->keyx.ecdsa.other_pub_x, config->keyx.ecdsa.other_pub_y, - sizeof(config->keyx.ecdsa.other_pub_x), + ret = dtls_ecdsa_verify_sig(config->keyx.ecc.other_pub_x, config->keyx.ecc.other_pub_y, + sizeof(config->keyx.ecc.other_pub_x), config->tmp.random.client, DTLS_RANDOM_LENGTH, config->tmp.random.server, DTLS_RANDOM_LENGTH, key_params, @@ -2712,6 +2799,64 @@ check_server_key_exchange_ecdsa(dtls_context_t *ctx, } return 0; } + +static int +check_server_key_exchange_ecdh(dtls_context_t *ctx, + dtls_peer_t *peer, + uint8 *data, size_t data_length) +{ + dtls_handshake_parameters_t *config = peer->handshake_params; + + update_hs_hash(peer, data, data_length); + + assert(is_tls_ecdh_anon_with_aes_128_cbc_sha(config->cipher)); + + data += DTLS_HS_LENGTH; + + 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 /* DTLS_ECC */ #ifdef DTLS_PSK @@ -2839,7 +2984,7 @@ check_server_hellodone(dtls_context_t *ctx, { int res; #ifdef DTLS_ECC - const dtls_ecdsa_key_t *ecdsa_key; + const dtls_ecc_key_t *ecdsa_key; #endif /* DTLS_ECC */ dtls_handshake_parameters_t *handshake = peer->handshake_params; @@ -2849,7 +2994,7 @@ check_server_hellodone(dtls_context_t *ctx, update_hs_hash(peer, data, data_length); #ifdef DTLS_ECC - if (handshake->do_client_auth) { + if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(handshake->cipher) && handshake->do_client_auth) { res = CALL(ctx, get_ecdsa_key, &peer->session, &ecdsa_key); if (res < 0) { @@ -2875,7 +3020,7 @@ check_server_hellodone(dtls_context_t *ctx, } #ifdef DTLS_ECC - if (handshake->do_client_auth) { + if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(handshake->cipher) && handshake->do_client_auth) { res = dtls_send_certificate_verify_ecdh(ctx, peer, ecdsa_key); @@ -2962,12 +3107,13 @@ decrypt_verify(dtls_peer_t *peer, uint8 *packet, size_t length, clen = dtls_decrypt(*cleartext, clen, *cleartext, nonce, dtls_kb_remote_write_key(security, peer->role), dtls_kb_key_size(security, peer->role), - A_DATA, A_DATA_LEN); + A_DATA, A_DATA_LEN, + security->cipher); if (clen < 0) dtls_warn("decryption failed\n"); else { #ifndef NDEBUG - printf("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); @@ -3072,9 +3218,11 @@ handle_handshake_msg(dtls_context_t *ctx, dtls_peer_t *peer, session_t *session, return err; } if (is_tls_ecdhe_ecdsa_with_aes_128_ccm_8(peer->handshake_params->cipher)) - peer->state = DTLS_STATE_WAIT_SERVERCERTIFICATE; + peer->state = DTLS_STATE_WAIT_SERVERCERTIFICATE; //ecdsa + else if (is_tls_ecdh_anon_with_aes_128_cbc_sha(peer->handshake_params->cipher)) + peer->state = DTLS_STATE_WAIT_SERVERKEYEXCHANGE; //ecdh else - peer->state = DTLS_STATE_WAIT_SERVERHELLODONE; + peer->state = DTLS_STATE_WAIT_SERVERHELLODONE; //psk /* update_hs_hash(peer, data, data_length); */ break; @@ -3110,6 +3258,13 @@ 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 (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 */ #ifdef DTLS_PSK if (is_tls_psk_with_aes_128_ccm_8(peer->handshake_params->cipher)) { @@ -3219,9 +3374,9 @@ 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) && is_ecdsa_client_auth_supported(ctx)) - peer->state = DTLS_STATE_WAIT_CERTIFICATEVERIFY; + peer->state = DTLS_STATE_WAIT_CERTIFICATEVERIFY; //ecdsa else - peer->state = DTLS_STATE_WAIT_CHANGECIPHERSPEC; + peer->state = DTLS_STATE_WAIT_CHANGECIPHERSPEC; //psk || ecdh_anon break; #ifdef DTLS_ECC @@ -3342,9 +3497,9 @@ 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) && is_ecdsa_client_auth_supported(ctx)) - peer->state = DTLS_STATE_WAIT_CLIENTCERTIFICATE; + peer->state = DTLS_STATE_WAIT_CLIENTCERTIFICATE; //ecdhe else - peer->state = DTLS_STATE_WAIT_CLIENTKEYEXCHANGE; + peer->state = DTLS_STATE_WAIT_CLIENTKEYEXCHANGE; //psk, ecdh_anon /* after sending the ServerHelloDone, we expect the * ClientKeyExchange (possibly containing the PSK id), @@ -4030,6 +4185,44 @@ dtls_check_retransmit(dtls_context_t *context, clock_time_t *next) { *next = node->t; } +size_t +dtls_prf_with_current_keyblock(dtls_context_t *ctx, session_t *session, + const uint8_t* label, const uint32_t labellen, + const uint8_t* random1, const uint32_t random1len, + const uint8_t* random2, const uint32_t random2len, + uint8_t* buf, const uint32_t buflen) { + dtls_peer_t *peer = NULL; + dtls_security_parameters_t *security = NULL; + size_t keysize = 0; + + if(!ctx || !session || !label || !buf || labellen == 0 || buflen == 0) { + dtls_warn("dtls_prf_with_current_keyblock(): invalid parameter\n"); + return 0; + } + + peer = dtls_get_peer(ctx, session); + if (!peer) { + dtls_warn("dtls_prf_with_current_keyblock(): cannot find peer\n"); + return 0; + } + + security = dtls_security_params(peer); + if (!security) { + dtls_crit("dtls_prf_with_current_keyblock(): peer has empty security parameters\n"); + return 0; + } + + /* note that keysize should never be zero as bad things will happen */ + keysize = dtls_kb_size(security, peer->role); + assert(keysize > 0); + + return dtls_prf(security->key_block, keysize, + label, labellen, + random1, random1len, + random2, random2len, + buf, buflen); +} + #ifdef WITH_CONTIKI /*---------------------------------------------------------------------------*/ /* message retransmission */ diff --git a/extlibs/tinydtls/dtls.h b/extlibs/tinydtls/dtls.h index 7ebde6b..a2ab86e 100644 --- a/extlibs/tinydtls/dtls.h +++ b/extlibs/tinydtls/dtls.h @@ -60,12 +60,12 @@ typedef enum dtls_credentials_type_t { DTLS_PSK_HINT, DTLS_PSK_IDENTITY, DTLS_PSK_KEY } dtls_credentials_type_t; -typedef struct dtls_ecdsa_key_t { +typedef struct dtls_ecc_key_t { dtls_ecdh_curve curve; const unsigned char *priv_key; /** < private key as bytes > */ const unsigned char *pub_key_x; /** < x part of the public key for the given private key > */ const unsigned char *pub_key_y; /** < y part of the public key for the given private key > */ -} dtls_ecdsa_key_t; +} dtls_ecc_key_t; /** Length of the secret that is used for generating Hello Verify cookies. */ #define DTLS_COOKIE_SECRET_LENGTH 12 @@ -183,7 +183,7 @@ typedef struct { */ int (*get_ecdsa_key)(struct dtls_context_t *ctx, const session_t *session, - const dtls_ecdsa_key_t **result); + const dtls_ecc_key_t **result); /** * Called during handshake to check the peer's pubic key in this @@ -238,6 +238,10 @@ 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_t selected_cipher; /**< selected ciper suite for handshake */ + unsigned char readbuf[DTLS_MAX_BUF]; } dtls_context_t; @@ -263,6 +267,24 @@ static inline void dtls_set_handler(dtls_context_t *ctx, dtls_handler_t *h) { ctx->h = h; } + /** + * @brief Enabling the TLS_ECDH_anon_WITH_AES_128_CBC_SHA + * + * @param ctx The DTLS context to use. + * @param is_enable DTLS_CIPHER_ENABLE(1) or DTLS_CIPHER_DISABLE(0) + */ +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) + * TLS_PSK_WITH_AES_128_CCM_8 (0xX0A8) + * TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 (0xC0AE) + */ +void dtls_select_cipher(dtls_context_t* ctx, const dtls_cipher_t cipher); + /** * Establishes a DTLS channel with the specified remote peer @p dst. * This function returns @c 0 if that channel already exists, a value @@ -415,6 +437,30 @@ int dtls_handle_message(dtls_context_t *ctx, session_t *session, dtls_peer_t *dtls_get_peer(const dtls_context_t *context, const session_t *session); +/** +* Invokes the DTLS PRF using the current key block for @p session as +* key and @p label + @p random1 + @p random2 as its input. This function +* writes upto @p buflen bytes into the given output buffer @p buf. +* +* @param ctx The dtls context to use. +* @param session The session whose key shall be used. +* @param label A PRF label. +* @param labellen Actual length of @p label. +* @param random1 Random seed. +* @param random1len Actual length of @p random1 (may be zero). +* @param random2 Random seed. +* @param random2len Actual length of @p random2 (may be zero). +* @param buf Output buffer for generated random data. +* @param buflen Maximum size of @p buf. +* +* @return The actual number of bytes written to @p buf or @c 0 on error. +*/ +size_t dtls_prf_with_current_keyblock(dtls_context_t *ctx, session_t *session, + const uint8_t* label, const uint32_t labellen, + const uint8_t* random1, const uint32_t random1len, + const uint8_t* random2, const uint32_t random2len, + uint8_t* buf, const uint32_t buflen); + #endif /* _DTLS_DTLS_H_ */ diff --git a/extlibs/tinydtls/ecc/Makefile.contiki b/extlibs/tinydtls/ecc/Makefile.contiki old mode 100644 new mode 100755 diff --git a/extlibs/tinydtls/ecc/Makefile.ecc b/extlibs/tinydtls/ecc/Makefile.ecc old mode 100644 new mode 100755 diff --git a/extlibs/tinydtls/ecc/test_helper.c b/extlibs/tinydtls/ecc/test_helper.c deleted file mode 100644 index bda44ba..0000000 --- a/extlibs/tinydtls/ecc/test_helper.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2009 Chris K Cockrum - * - * Copyright (c) 2013 Jens Trillmann - * Copyright (c) 2013 Marc Müller-Weinhardt - * Copyright (c) 2013 Lars Schmertmann - * Copyright (c) 2013 Hauke Mehrtens - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * - * This implementation is based in part on the paper Implementation of an - * Elliptic Curve Cryptosystem on an 8-bit Microcontroller [0] by - * Chris K Cockrum . - * - * [0]: http://cockrum.net/Implementation_of_ECC_on_an_8-bit_microcontroller.pdf - * - * This is a efficient ECC implementation on the secp256r1 curve for 32 Bit CPU - * architectures. It provides basic operations on the secp256r1 curve and support - * for ECDH and ECDSA. - */ -#include "test_helper.h" -#include "ecc.h" -#include -#include -#include - -void ecc_printNumber(const uint32_t *x, int numberLength){ //here the values are turned to MSB! - int n; - - for(n = numberLength - 1; n >= 0; n--){ - printf("%08x", x[n]); - } - printf("\n"); -} - -void ecc_setRandom(uint32_t *secret){ - int i; - - for (i = 0; i < arrayLength; ++i) - { - secret[i] = rand(); - } -} -const uint32_t ecc_prime_m[8] = {0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, - 0x00000000, 0x00000000, 0x00000001, 0xffffffff}; - - -/* This is added after an static byte addition if the answer has a carry in MSB*/ -const uint32_t ecc_prime_r[8] = {0x00000001, 0x00000000, 0x00000000, 0xffffffff, - 0xffffffff, 0xffffffff, 0xfffffffe, 0x00000000}; - -#ifdef CONTIKI -void -test_assert(const char *file, int lineno) -{ - printf("Assertion failed: file %s, line %d.\n", file, lineno); - /* - * loop for a while; - * call _reset_vector__(); - */ -} -#endif diff --git a/extlibs/tinydtls/ecc/test_helper.h b/extlibs/tinydtls/ecc/test_helper.h deleted file mode 100644 index 38a194e..0000000 --- a/extlibs/tinydtls/ecc/test_helper.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2009 Chris K Cockrum - * - * Copyright (c) 2013 Jens Trillmann - * Copyright (c) 2013 Marc Müller-Weinhardt - * Copyright (c) 2013 Lars Schmertmann - * Copyright (c) 2013 Hauke Mehrtens - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * - * This implementation is based in part on the paper Implementation of an - * Elliptic Curve Cryptosystem on an 8-bit Microcontroller [0] by - * Chris K Cockrum . - * - * [0]: http://cockrum.net/Implementation_of_ECC_on_an_8-bit_microcontroller.pdf - * - * This is a efficient ECC implementation on the secp256r1 curve for 32 Bit CPU - * architectures. It provides basic operations on the secp256r1 curve and support - * for ECDH and ECDSA. - */ -#include - -extern const uint32_t ecc_prime_m[8]; -extern const uint32_t ecc_prime_r[8]; - -//debug function to print long numbers -void ecc_printNumber(const uint32_t *x, int numberLength); -void ecc_setRandom(uint32_t *secret); - -#ifdef CONTIKI -#undef assert -#define assert(e) ((e) ? (void)0 : test_assert(__FILE__, __LINE__)) -void test_assert(const char *, int); -#endif diff --git a/extlibs/tinydtls/ecc/testecc.c b/extlibs/tinydtls/ecc/testecc.c deleted file mode 100644 index b36d46b..0000000 --- a/extlibs/tinydtls/ecc/testecc.c +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright (c) 2009 Chris K Cockrum - * - * Copyright (c) 2013 Jens Trillmann - * Copyright (c) 2013 Marc Müller-Weinhardt - * Copyright (c) 2013 Lars Schmertmann - * Copyright (c) 2013 Hauke Mehrtens - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * - * This implementation is based in part on the paper Implementation of an - * Elliptic Curve Cryptosystem on an 8-bit Microcontroller [0] by - * Chris K Cockrum . - * - * [0]: http://cockrum.net/Implementation_of_ECC_on_an_8-bit_microcontroller.pdf - * - * This is a efficient ECC implementation on the secp256r1 curve for 32 Bit CPU - * architectures. It provides basic operations on the secp256r1 curve and support - * for ECDH and ECDSA. - */ - -#include -#include -#include -#include - -#include "ecc.h" -#include "test_helper.h" - -#ifdef CONTIKI -#include "contiki.h" -#else -#include -#endif /* CONTIKI */ - -//These are testvalues taken from the NIST P-256 definition -//6b17d1f2 e12c4247 f8bce6e5 63a440f2 77037d81 2deb33a0 f4a13945 d898c296 -uint32_t BasePointx[8] = { 0xd898c296, 0xf4a13945, 0x2deb33a0, 0x77037d81, - 0x63a440f2, 0xf8bce6e5, 0xe12c4247, 0x6b17d1f2}; - -//4fe342e2 fe1a7f9b 8ee7eb4a 7c0f9e16 2bce3357 6b315ece cbb64068 37bf51f5 -uint32_t BasePointy[8] = { 0x37bf51f5, 0xcbb64068, 0x6b315ece, 0x2bce3357, - 0x7c0f9e16, 0x8ee7eb4a, 0xfe1a7f9b, 0x4fe342e2}; - -//de2444be bc8d36e6 82edd27e 0f271508 617519b3 221a8fa0 b77cab39 89da97c9 -uint32_t Sx[8] = { 0x89da97c9, 0xb77cab39, 0x221a8fa0, 0x617519b3, - 0x0f271508, 0x82edd27e, 0xbc8d36e6, 0xde2444be}; - -//c093ae7f f36e5380 fc01a5aa d1e66659 702de80f 53cec576 b6350b24 3042a256 -uint32_t Sy[8] = { 0x3042a256, 0xb6350b24, 0x53cec576, 0x702de80f, - 0xd1e66659, 0xfc01a5aa, 0xf36e5380, 0xc093ae7f}; - -//55a8b00f 8da1d44e 62f6b3b2 5316212e 39540dc8 61c89575 bb8cf92e 35e0986b -uint32_t Tx[8] = { 0x35e0986b, 0xbb8cf92e, 0x61c89575, 0x39540dc8, - 0x5316212e, 0x62f6b3b2, 0x8da1d44e, 0x55a8b00f}; - -//5421c320 9c2d6c70 4835d82a c4c3dd90 f61a8a52 598b9e7a b656e9d8 c8b24316 -uint32_t Ty[8] = { 0xc8b24316, 0xb656e9d8, 0x598b9e7a, 0xf61a8a52, - 0xc4c3dd90, 0x4835d82a, 0x9c2d6c70, 0x5421c320}; - -//c51e4753 afdec1e6 b6c6a5b9 92f43f8d d0c7a893 3072708b 6522468b 2ffb06fd -uint32_t secret[8] = { 0x2ffb06fd, 0x6522468b, 0x3072708b, 0xd0c7a893, - 0x92f43f8d, 0xb6c6a5b9, 0xafdec1e6, 0xc51e4753}; - -//72b13dd4 354b6b81 745195e9 8cc5ba69 70349191 ac476bd4 553cf35a 545a067e -uint32_t resultAddx[8] = { 0x545a067e, 0x553cf35a, 0xac476bd4, 0x70349191, - 0x8cc5ba69, 0x745195e9, 0x354b6b81, 0x72b13dd4}; - -//8d585cbb 2e1327d7 5241a8a1 22d7620d c33b1331 5aa5c9d4 6d013011 744ac264 -uint32_t resultAddy[8] = { 0x744ac264, 0x6d013011, 0x5aa5c9d4, 0xc33b1331, - 0x22d7620d, 0x5241a8a1, 0x2e1327d7, 0x8d585cbb}; - -//7669e690 1606ee3b a1a8eef1 e0024c33 df6c22f3 b17481b8 2a860ffc db6127b0 -uint32_t resultDoublex[8] = { 0xdb6127b0, 0x2a860ffc, 0xb17481b8, 0xdf6c22f3, - 0xe0024c33, 0xa1a8eef1, 0x1606ee3b, 0x7669e690}; - -//fa878162 187a54f6 c39f6ee0 072f33de 389ef3ee cd03023d e10ca2c1 db61d0c7 -uint32_t resultDoubley[8] = { 0xdb61d0c7, 0xe10ca2c1, 0xcd03023d, 0x389ef3ee, - 0x072f33de, 0xc39f6ee0, 0x187a54f6, 0xfa878162}; - -//51d08d5f 2d427888 2946d88d 83c97d11 e62becc3 cfc18bed acc89ba3 4eeca03f -uint32_t resultMultx[8] = { 0x4eeca03f, 0xacc89ba3, 0xcfc18bed, 0xe62becc3, - 0x83c97d11, 0x2946d88d, 0x2d427888, 0x51d08d5f}; - -//75ee68eb 8bf626aa 5b673ab5 1f6e744e 06f8fcf8 a6c0cf30 35beca95 6a7b41d5 -uint32_t resultMulty[8] = { 0x6a7b41d5, 0x35beca95, 0xa6c0cf30, 0x06f8fcf8, - 0x1f6e744e, 0x5b673ab5, 0x8bf626aa, 0x75ee68eb}; - -static const uint32_t ecdsaTestMessage[] = { 0x65637572, 0x20612073, 0x68206F66, 0x20686173, 0x69732061, 0x68697320, 0x6F2C2054, 0x48616C6C}; - -static const uint32_t ecdsaTestSecret[] = {0x94A949FA, 0x401455A1, 0xAD7294CA, 0x896A33BB, 0x7A80E714, 0x4321435B, 0x51247A14, 0x41C1CB6B}; - -static const uint32_t ecdsaTestRand1[] = { 0x1D1E1F20, 0x191A1B1C, 0x15161718, 0x11121314, 0x0D0E0F10, 0x090A0B0C, 0x05060708, 0x01020304}; -static const uint32_t ecdsaTestresultR1[] = { 0xC3B4035F, 0x515AD0A6, 0xBF375DCA, 0x0CC1E997, 0x7F54FDCD, 0x04D3FECA, 0xB9E396B9, 0x515C3D6E}; -static const uint32_t ecdsaTestresultS1[] = { 0x5366B1AB, 0x0F1DBF46, 0xB0C8D3C4, 0xDB755B6F, 0xB9BF9243, 0xE644A8BE, 0x55159A59, 0x6F9E52A6}; - -static const uint32_t ecdsaTestRand2[] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x01FFFFFF}; -static const uint32_t ecdsaTestresultR2[] = { 0x14146C91, 0xE878724D, 0xCD4FF928, 0xCC24BC04, 0xAC403390, 0x650C0060, 0x4A30B3F1, 0x9C69B726}; -static const uint32_t ecdsaTestresultS2[] = { 0x433AAB6F, 0x808250B1, 0xE46F90F4, 0xB342E972, 0x18B2F7E4, 0x2DB981A2, 0x6A288FA4, 0x41CF59DB}; - -void addTest(){ - uint32_t tempx[8]; - uint32_t tempy[8]; - - ecc_ec_add(Tx, Ty, Sx, Sy, tempx, tempy); - assert(ecc_isSame(tempx, resultAddx, arrayLength)); - assert(ecc_isSame(tempy, resultAddy, arrayLength)); -} - -void doubleTest(){ - uint32_t tempx[8]; - uint32_t tempy[8]; - - ecc_ec_double(Sx, Sy, tempx, tempy); - assert(ecc_isSame(tempx, resultDoublex, arrayLength)); - assert(ecc_isSame(tempy, resultDoubley, arrayLength)); -} - -void multTest(){ - uint32_t tempx[8]; - uint32_t tempy[8]; - - ecc_ec_mult(Sx, Sy, secret, tempx, tempy); - assert(ecc_isSame(tempx, resultMultx, arrayLength)); - assert(ecc_isSame(tempy, resultMulty, arrayLength)); -} - -void eccdhTest(){ - uint32_t tempx[8]; - uint32_t tempy[8]; - uint32_t tempAx2[8]; - uint32_t tempAy2[8]; - uint32_t tempBx1[8]; - uint32_t tempBy1[8]; - uint32_t tempBx2[8]; - uint32_t tempBy2[8]; - uint32_t secretA[8]; - uint32_t secretB[8]; - ecc_setRandom(secretA); - ecc_printNumber(secretA, 8); - ecc_setRandom(secretB); - ecc_printNumber(secretB, 8); - ecc_ec_mult(BasePointx, BasePointy, secretA, tempx, tempy); - ecc_ec_mult(BasePointx, BasePointy, secretB, tempBx1, tempBy1); - //public key exchange - ecc_ec_mult(tempBx1, tempBy1, secretA, tempAx2, tempAy2); - ecc_ec_mult(tempx, tempy, secretB, tempBx2, tempBy2); - assert(ecc_isSame(tempAx2, tempBx2, arrayLength)); - assert(ecc_isSame(tempAy2, tempBy2, arrayLength)); - -} - -void ecdsaTest() { - int ret __attribute__((unused)); - uint32_t tempx[9]; - uint32_t tempy[9]; - uint32_t pub_x[8]; - uint32_t pub_y[8]; - - ecc_ec_mult(BasePointx, BasePointy, ecdsaTestSecret, pub_x, pub_y); - - ret = ecc_ecdsa_sign(ecdsaTestSecret, ecdsaTestMessage, ecdsaTestRand1, tempx, tempy); - assert(ecc_isSame(tempx, ecdsaTestresultR1, arrayLength)); - assert(ecc_isSame(tempy, ecdsaTestresultS1, arrayLength)); - assert(ret == 0); - - ret = ecc_ecdsa_validate(pub_x, pub_y, ecdsaTestMessage, tempx, tempy); - assert(!ret); - - - ret = ecc_ecdsa_sign(ecdsaTestSecret, ecdsaTestMessage, ecdsaTestRand2, tempx, tempy); - assert(ecc_isSame(tempx, ecdsaTestresultR2, arrayLength)); - assert(ecc_isSame(tempy, ecdsaTestresultS2, arrayLength)); - assert(ret == 0); - - ret = ecc_ecdsa_validate(pub_x, pub_y, ecdsaTestMessage, tempx, tempy); - assert(!ret); -} - -#ifdef CONTIKI -PROCESS(ecc_filed_test, "ECC test"); -AUTOSTART_PROCESSES(&ecc_filed_test); -PROCESS_THREAD(ecc_filed_test, ev, d) -{ - PROCESS_BEGIN(); - - srand(1234); - addTest(); - doubleTest(); - multTest(); - eccdhTest(); - ecdsaTest(); - printf("%s\n", "All Tests successful."); - - PROCESS_END(); -} -#else /* CONTIKI */ -int main(int argc, char const *argv[]) -{ - srand(time(NULL)); - addTest(); - doubleTest(); - multTest(); - eccdhTest(); - ecdsaTest(); - printf("%s\n", "All Tests successful."); - return 0; -} -#endif /* CONTIKI */ diff --git a/extlibs/tinydtls/ecc/testfield.c b/extlibs/tinydtls/ecc/testfield.c deleted file mode 100644 index 30a690e..0000000 --- a/extlibs/tinydtls/ecc/testfield.c +++ /dev/null @@ -1,290 +0,0 @@ -/* - * Copyright (c) 2009 Chris K Cockrum - * - * Copyright (c) 2013 Jens Trillmann - * Copyright (c) 2013 Marc Müller-Weinhardt - * Copyright (c) 2013 Lars Schmertmann - * Copyright (c) 2013 Hauke Mehrtens - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * - * This implementation is based in part on the paper Implementation of an - * Elliptic Curve Cryptosystem on an 8-bit Microcontroller [0] by - * Chris K Cockrum . - * - * [0]: http://cockrum.net/Implementation_of_ECC_on_an_8-bit_microcontroller.pdf - * - * This is a efficient ECC implementation on the secp256r1 curve for 32 Bit CPU - * architectures. It provides basic operations on the secp256r1 curve and support - * for ECDH and ECDSA. - */ -#include -#include -#include -#include "ecc.h" -#include "test_helper.h" - -#ifdef CONTIKI -#include "contiki.h" -#endif /* CONTIKI */ - -//arbitrary test values and results -uint32_t null[8] = { 0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000}; -uint32_t null64[16] = { 0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000}; -uint32_t one[8] = { 0x00000001,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000}; -uint32_t one64[16] = { 0x00000001,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000}; -uint32_t two[8] = { 0x00000002,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000}; -uint32_t two64[16] = { 0x00000002,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000}; -uint32_t three[8] = { 0x00000003,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000}; -uint32_t four[8] = {0x00000004,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000}; -uint32_t four64[16] = { 0x00000004,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000}; -uint32_t six[8] = { 0x00000006,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000}; -uint32_t eight[8] = { 0x00000008,0x00000000,0x00000000,0x00000000, - 0x00000000,0x00000000,0x00000000,0x00000000}; -uint32_t full[8] = { 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF}; -//00000000fffffffeffffffffffffffffffffffff000000000000000000000001_16 -uint32_t resultFullAdd[8] = { 0x00000001,0x00000000,0x00000000,0xFFFFFFFF, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFE,0x00000000}; -uint32_t primeMinusOne[8]= { 0xfffffffe,0xffffffff,0xffffffff,0x00000000, - 0x00000000,0x00000000,0x00000001,0xffffffff}; -uint32_t resultDoubleMod[8] = { 0xfffffffd,0xffffffff,0xffffffff,0x00000000, - 0x00000000,0x00000000,0x00000001,0xffffffff}; -//fffffffe00000002fffffffe0000000100000001fffffffe00000001fffffffc00000003fffffffcfffffffffffffffffffffffc000000000000000000000004_16 -uint32_t resultQuadMod[16] = { 0x00000004,0x00000000,0x00000000,0xFFFFFFFC, - 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFC,0x00000003, - 0xFFFFFFFC,0x00000001,0xFFFFFFFE,0x00000001, - 0x00000001,0xFFFFFFFE,0x00000002,0xFFFFFFFE}; -//00000002fffffffffffffffffffffffefffffffdffffffff0000000000000002_16 -uint32_t resultFullMod[8] = { 0x00000002,0x00000000,0xFFFFFFFF,0xFFFFFFFD, - 0xFFFFFFFE,0xFFFFFFFF,0xFFFFFFFF,0x00000002}; - -static const uint32_t orderMinusOne[8] = {0xFC632550, 0xF3B9CAC2, 0xA7179E84, 0xBCE6FAAD, - 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF}; -static const uint32_t orderResultDoubleMod[8] = {0xFC63254F, 0xF3B9CAC2, 0xA7179E84, 0xBCE6FAAD, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF}; - -uint32_t temp[8]; -uint32_t temp2[16]; - -void nullEverything(){ - memset(temp, 0, sizeof(temp)); - memset(temp2, 0, sizeof(temp)); -} - -void fieldAddTest(){ - assert(ecc_isSame(one, one, arrayLength)); - ecc_fieldAdd(one, null, ecc_prime_r, temp); - assert(ecc_isSame(temp, one, arrayLength)); - nullEverything(); - ecc_fieldAdd(one, one, ecc_prime_r, temp); - assert(ecc_isSame(temp, two, arrayLength)); - nullEverything(); - ecc_add(full, one, temp, 32); - assert(ecc_isSame(null, temp, arrayLength)); - nullEverything(); - ecc_fieldAdd(full, one, ecc_prime_r, temp); - assert(ecc_isSame(temp, resultFullAdd, arrayLength)); -} - -void fieldSubTest(){ - assert(ecc_isSame(one, one, arrayLength)); - ecc_fieldSub(one, null, ecc_prime_m, temp); - assert(ecc_isSame(one, temp, arrayLength)); - nullEverything(); - ecc_fieldSub(one, one, ecc_prime_m, temp); - assert(ecc_isSame(null, temp, arrayLength)); - nullEverything(); - ecc_fieldSub(null, one, ecc_prime_m, temp); - assert(ecc_isSame(primeMinusOne, temp, arrayLength)); -} - -void fieldMultTest(){ - ecc_fieldMult(one, null, temp2, arrayLength); - assert(ecc_isSame(temp2, null64, arrayLength * 2)); - nullEverything(); - ecc_fieldMult(one, two, temp2, arrayLength); - assert(ecc_isSame(temp2, two64, arrayLength * 2)); - nullEverything(); - ecc_fieldMult(two, two, temp2, arrayLength); - assert(ecc_isSame(temp2, four64, arrayLength * 2)); - nullEverything(); - ecc_fieldMult(primeMinusOne, primeMinusOne, temp2, arrayLength); - assert(ecc_isSame(temp2, resultQuadMod, arrayLength * 2)); - nullEverything(); - ecc_fieldInv(two, ecc_prime_m, ecc_prime_r, temp); - ecc_fieldMult(temp, two, temp2, arrayLength); - ecc_fieldModP(temp, temp2); - assert(ecc_isSame(temp, one, arrayLength)); -} - -void fieldModPTest(){ - ecc_fieldMult(primeMinusOne, primeMinusOne, temp2, arrayLength); - ecc_fieldModP(temp, temp2); - assert(ecc_isSame(temp, one, arrayLength)); - nullEverything(); - ecc_fieldModP(temp, one64); - assert(ecc_isSame(temp, one, arrayLength)); - nullEverything(); - ecc_fieldMult(two, primeMinusOne, temp2, arrayLength); - ecc_fieldModP(temp, temp2); - assert(ecc_isSame(temp, resultDoubleMod, arrayLength)); - nullEverything(); - /*fieldMult(full, full, temp2, arrayLength); //not working, maybe because of the number bigger than p^2? - fieldModP(temp, temp2); - assert(ecc_isSame(temp, resultFullMod, arrayLength));*/ -} - -void fieldModOTest(){ - ecc_fieldMult(orderMinusOne, orderMinusOne, temp2, arrayLength); - ecc_fieldModO(temp2, temp, arrayLength * 2); - assert(ecc_isSame(temp, one, arrayLength)); - nullEverything(); - ecc_fieldModO(one64, temp, arrayLength * 2); - assert(ecc_isSame(temp, one, arrayLength)); - nullEverything(); - ecc_fieldMult(two, orderMinusOne, temp2, arrayLength); - ecc_fieldModO(temp2, temp, arrayLength * 2); - assert(ecc_isSame(temp, orderResultDoubleMod, arrayLength)); - nullEverything(); -} - - -// void rShiftTest(){ -// printNumber(full, 32); -// rshift(full); -// printNumber(full, 32); -// printNumber(two, 32); -// rshift(two); -// printNumber(two, 32); -// printNumber(four, 32); -// rshift(four); -// printNumber(four, 32); -// } - -// void isOneTest(){ -// printf("%d\n", isone(one)); -// printf("%d\n", isone(two)); -// printf("%d\n", isone(four)); -// printf("%d\n", isone(full)); -// printf("%d\n", isone(null)); -// } - -void fieldInvTest(){ - nullEverything(); - ecc_fieldInv(two, ecc_prime_m, ecc_prime_r, temp); - ecc_fieldMult(temp, two, temp2, arrayLength); - ecc_fieldModP(temp, temp2); - assert(ecc_isSame(one, temp, arrayLength)); - nullEverything(); - ecc_fieldInv(eight, ecc_prime_m, ecc_prime_r, temp); - ecc_fieldMult(temp, eight, temp2, arrayLength); - ecc_fieldModP(temp, temp2); - assert(ecc_isSame(one, temp, arrayLength)); - nullEverything(); - ecc_fieldInv(three, ecc_prime_m, ecc_prime_r, temp); - ecc_fieldMult(temp, three, temp2, arrayLength); - ecc_fieldModP(temp, temp2); - assert(ecc_isSame(one, temp, arrayLength)); - nullEverything(); - ecc_fieldInv(six, ecc_prime_m, ecc_prime_r, temp); - ecc_fieldMult(temp, six, temp2, arrayLength); - ecc_fieldModP(temp, temp2); - assert(ecc_isSame(one, temp, arrayLength)); - nullEverything(); - ecc_fieldInv(primeMinusOne, ecc_prime_m, ecc_prime_r, temp); - ecc_fieldMult(temp, primeMinusOne, temp2, arrayLength); - ecc_fieldModP(temp, temp2); - assert(ecc_isSame(one, temp, arrayLength)); -} - -// void randomStuff(){ - -// } - -#ifdef CONTIKI -PROCESS(ecc_filed_test, "ECC field test"); -AUTOSTART_PROCESSES(&ecc_filed_test); -PROCESS_THREAD(ecc_filed_test, ev, d) -{ - PROCESS_BEGIN(); - - nullEverything(); - //randomStuff(); - nullEverything(); - fieldAddTest(); - nullEverything(); - fieldSubTest(); - nullEverything(); - fieldMultTest(); - nullEverything(); - fieldModPTest(); - nullEverything(); - fieldModOTest(); - nullEverything(); - fieldInvTest(); - nullEverything(); - //rShiftTest(); - //isOneTest(); - printf("%s\n", "All Tests succesfull!"); - - PROCESS_END(); -} -#else /* CONTIKI */ -int main(int argc, char const *argv[]) -{ - nullEverything(); - //randomStuff(); - nullEverything(); - fieldAddTest(); - nullEverything(); - fieldSubTest(); - nullEverything(); - fieldMultTest(); - nullEverything(); - fieldModPTest(); - nullEverything(); - fieldModOTest(); - nullEverything(); - fieldInvTest(); - nullEverything(); - //rShiftTest(); - //isOneTest(); - printf("%s\n", "All Tests succesfull!"); - return 0; -} -#endif /* CONTIKI */ diff --git a/extlibs/tinydtls/global.h b/extlibs/tinydtls/global.h index f0977c8..441710f 100644 --- a/extlibs/tinydtls/global.h +++ b/extlibs/tinydtls/global.h @@ -73,10 +73,16 @@ 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_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; +typedef enum { + DTLS_CIPHER_DISABLE = 0, + DTLS_CIPHER_ENABLE = 1 +} dtls_cipher_enable_t; + /** Known compression suites.*/ typedef enum { TLS_COMPRESSION_NULL = 0x0000 /* NULL compression */ diff --git a/extlibs/tinydtls/tests/dtls-client.c b/extlibs/tinydtls/tests/dtls-client.c index 1c48c1a..35521e9 100644 --- a/extlibs/tinydtls/tests/dtls-client.c +++ b/extlibs/tinydtls/tests/dtls-client.c @@ -148,8 +148,8 @@ get_psk_info(struct dtls_context_t *ctx UNUSED_PARAM, static int get_ecdsa_key(struct dtls_context_t *ctx, const session_t *session, - const dtls_ecdsa_key_t **result) { - static const dtls_ecdsa_key_t ecdsa_key = { + const dtls_ecc_key_t **result) { + static const dtls_ecc_key_t ecdsa_key = { .curve = DTLS_ECDH_CURVE_SECP256R1, .priv_key = ecdsa_priv_key, .pub_key_x = ecdsa_pub_key_x, @@ -296,9 +296,9 @@ usage( const char *program, const char *version) { fprintf(stderr, "%s v%s -- DTLS client implementation\n" "(c) 2011-2014 Olaf Bergmann \n\n" #ifdef DTLS_PSK - "usage: %s [-i file] [-s file] [-k file] [-o file] [-p port] [-v num] addr [port]\n" + "usage: %s [-i file] [-s file] [-k file] [-o file] [-p port] [-v num] [-c num] addr [port]\n" #else /* DTLS_PSK */ - "usage: %s [-o file] [-p port] [-v num] addr [port]\n" + "usage: %s [-o file] [-p port] [-v num] [-c num] addr [port]\n" #endif /* DTLS_PSK */ #ifdef DTLS_PSK "\t-i file\t\tread PSK Client identity from file\n" @@ -307,7 +307,11 @@ usage( const char *program, const char *version) { #endif /* DTLS_PSK */ "\t-o file\t\toutput received data to this file (use '-' for STDOUT)\n" "\t-p port\t\tlisten on specified port (default is %d)\n" - "\t-v num\t\tverbosity level (default: 3)\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\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); } @@ -333,6 +337,7 @@ static dtls_handler_t cb = { * Below command tests this feature. */ #define DTLS_CLIENT_CMD_REHANDSHAKE "client:rehandshake" + int main(int argc, char **argv) { fd_set rfds, wfds; @@ -342,6 +347,8 @@ 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_enable_t ecdh_anon_enalbe = DTLS_CIPHER_ENABLE; int opt, res; session_t dst; @@ -357,7 +364,7 @@ main(int argc, char **argv) { memcpy(psk_key, PSK_DEFAULT_KEY, psk_key_length); #endif /* DTLS_PSK */ - while ((opt = getopt(argc, argv, "p:o:v:" PSK_OPTIONS)) != -1) { + while ((opt = getopt(argc, argv, "p:o:v:c:" PSK_OPTIONS)) != -1) { switch (opt) { #ifdef DTLS_PSK case 'i' : { @@ -407,6 +414,23 @@ main(int argc, char **argv) { case 'v' : log_level = strtol(optarg, NULL, 10); break; + case 'c': + if( strcmp(optarg, "1") == 0) + { + selected_cipher = TLS_ECDH_anon_WITH_AES_128_CBC_SHA; + ecdh_anon_enalbe = DTLS_CIPHER_ENABLE; + } + else if( strcmp(optarg, "2") == 0) + { + selected_cipher = TLS_PSK_WITH_AES_128_CCM_8 ; + ecdh_anon_enalbe = DTLS_CIPHER_DISABLE; + } + else if( strcmp(optarg, "3") == 0) + { + selected_cipher = TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 ; + ecdh_anon_enalbe = DTLS_CIPHER_DISABLE; + } + break; default: usage(argv[0], dtls_package_version()); exit(1); @@ -472,6 +496,13 @@ main(int argc, char **argv) { exit(-1); } + + /* select cipher suite */ + dtls_select_cipher(dtls_context, selected_cipher); + + /* enable/disable tls_ecdh_anon_with_aes_128_cbc_sha */ + dtls_enables_anon_ecdh(dtls_context, ecdh_anon_enalbe); + dtls_set_handler(dtls_context, &cb); dtls_connect(dtls_context, &dst); diff --git a/extlibs/tinydtls/tests/dtls-server.c b/extlibs/tinydtls/tests/dtls-server.c index ae1283e..d3da1a7 100644 --- a/extlibs/tinydtls/tests/dtls-server.c +++ b/extlibs/tinydtls/tests/dtls-server.c @@ -113,8 +113,8 @@ get_psk_info(struct dtls_context_t *ctx, const session_t *session, static int get_ecdsa_key(struct dtls_context_t *ctx, const session_t *session, - const dtls_ecdsa_key_t **result) { - static const dtls_ecdsa_key_t ecdsa_key = { + const dtls_ecc_key_t **result) { + static const dtls_ecc_key_t ecdsa_key = { .curve = DTLS_ECDH_CURVE_SECP256R1, .priv_key = ecdsa_priv_key, .pub_key_x = ecdsa_pub_key_x, @@ -249,10 +249,13 @@ usage(const char *program, const char *version) { fprintf(stderr, "%s v%s -- DTLS server implementation\n" "(c) 2011-2014 Olaf Bergmann \n\n" - "usage: %s [-A address] [-p port] [-v num]\n" + "usage: %s [-A address] [-p port] [-v num] [-a enable|disable]\n" "\t-A address\t\tlisten on specified address (default is ::)\n" "\t-p port\t\tlisten on specified port (default is %d)\n" - "\t-v num\t\tverbosity level (default: 3)\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", program, version, program, DEFAULT_PORT); } @@ -277,6 +280,7 @@ main(int argc, char **argv) { struct timeval timeout; int fd, opt, result; int on = 1; + int ecdh_anon_enalbe = DTLS_CIPHER_DISABLE; struct sockaddr_in6 listen_addr; memset(&listen_addr, 0, sizeof(struct sockaddr_in6)); @@ -290,7 +294,7 @@ main(int argc, char **argv) { listen_addr.sin6_port = htons(DEFAULT_PORT); listen_addr.sin6_addr = in6addr_any; - while ((opt = getopt(argc, argv, "A:p:v:")) != -1) { + while ((opt = getopt(argc, argv, "A:p:v:a:")) != -1) { switch (opt) { case 'A' : if (resolve_address(optarg, (struct sockaddr *)&listen_addr) < 0) { @@ -304,6 +308,10 @@ main(int argc, char **argv) { case 'v' : log_level = strtol(optarg, NULL, 10); break; + case 'a': + if( strcmp(optarg, "enable") == 0) + ecdh_anon_enalbe = DTLS_CIPHER_ENABLE; + break; default: usage(argv[0], dtls_package_version()); exit(1); @@ -348,6 +356,9 @@ main(int argc, char **argv) { the_context = dtls_new_context(&fd); + /* enable/disable tls_ecdh_anon_with_aes_128_cbc_sha */ + dtls_enables_anon_ecdh(the_context, ecdh_anon_enalbe); + dtls_set_handler(the_context, &cb); while (1) { diff --git a/extlibs/tinydtls/tinydtls.h b/extlibs/tinydtls/tinydtls.h index 3fa228a..b1b8cdf 100644 --- a/extlibs/tinydtls/tinydtls.h +++ b/extlibs/tinydtls/tinydtls.h @@ -34,7 +34,7 @@ #define _DTLS_TINYDTLS_H_ /** Defined to 1 if tinydtls is built with support for ECC */ -/* #undef DTLS_ECC */ +#define DTLS_ECC 1 /** Defined to 1 if tinydtls is built with support for PSK */ #define DTLS_PSK 1 diff --git a/extlibs/tinydtls/uthash.h b/extlibs/tinydtls/uthash.h index 786c956..5125cc6 100644 --- a/extlibs/tinydtls/uthash.h +++ b/extlibs/tinydtls/uthash.h @@ -21,8 +21,8 @@ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef _DTLS_UTHASH_H -#define _DTLS_UTHASH_H +#ifndef UTHASH_H +#define UTHASH_H #include /* memcmp,strlen */ #include /* ptrdiff_t */ @@ -48,7 +48,7 @@ do { char **_da_dst = (char**)(&(dst)); \ *_da_dst = (char*)(src); \ } while(0) -#else +#else #define DECLTYPE_ASSIGN(dst,src) \ do { \ (dst) = DECLTYPE(dst)(src); \ @@ -119,9 +119,9 @@ do { HASH_BLOOM_BITTEST((tbl)->bloom_bv, (hashv & (uint32_t)((1ULL << (tbl)->bloom_nbits) - 1))) #else -#define HASH_BLOOM_MAKE(tbl) -#define HASH_BLOOM_FREE(tbl) -#define HASH_BLOOM_ADD(tbl,hashv) +#define HASH_BLOOM_MAKE(tbl) +#define HASH_BLOOM_FREE(tbl) +#define HASH_BLOOM_ADD(tbl,hashv) #define HASH_BLOOM_TEST(tbl,hashv) (1) #endif @@ -146,7 +146,7 @@ do { #define HASH_ADD(hh,head,fieldname,keylen_in,add) \ HASH_ADD_KEYPTR(hh,head,&add->fieldname,keylen_in,add) - + #define HASH_ADD_KEYPTR(hh,head,keyptr,keylen_in,add) \ do { \ unsigned _ha_bkt; \ @@ -298,10 +298,10 @@ do { } \ } while (0) #else -#define HASH_FSCK(hh,head) +#define HASH_FSCK(hh,head) #endif -/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to +/* When compiled with -DHASH_EMIT_KEYS, length-prefixed keys are emitted to * the descriptor to which this macro is defined for tuning the hash function. * The app can #include to get the prototype for write(2). */ #ifdef HASH_EMIT_KEYS @@ -311,12 +311,12 @@ do { write(HASH_EMIT_KEYS, &_klen, sizeof(_klen)); \ write(HASH_EMIT_KEYS, keyptr, fieldlen); \ } while (0) -#else -#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) +#else +#define HASH_EMIT_KEY(hh,head,keyptr,fieldlen) #endif /* default to Jenkin's hash unless overridden e.g. DHASH_FUNCTION=HASH_SAX */ -#ifdef HASH_FUNCTION +#ifdef HASH_FUNCTION #define HASH_FCN HASH_FUNCTION #else #define HASH_FCN HASH_JEN @@ -333,7 +333,7 @@ do { } while (0) -/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at +/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at * http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */ #define HASH_SAX(key,keylen,num_bkts,hashv,bkt) \ do { \ @@ -354,7 +354,7 @@ do { hashv = (hashv * 16777619) ^ _hf_key[_fn_i]; \ bkt = hashv & (num_bkts-1); \ } while(0); - + #define HASH_OAT(key,keylen,num_bkts,hashv,bkt) \ do { \ unsigned _ho_i; \ @@ -484,14 +484,14 @@ do { /* The MurmurHash exploits some CPU's (e.g. x86) tolerance for unaligned reads. * For other types of CPU's (e.g. Sparc) an unaligned read causes a bus error. * So MurmurHash comes in two versions, the faster unaligned one and the slower - * aligned one. We only use the faster one on CPU's where we know it's safe. + * aligned one. We only use the faster one on CPU's where we know it's safe. * * Note the preprocessor built-in defines can be emitted using: * * gcc -m64 -dM -E - < /dev/null (on gcc) * cc -## a.c (where a.c is a simple test file) (Sun Studio) */ -#if (defined(__i386__) || defined(__x86_64__)) +#if (defined(__i386__) || defined(__x86_64__)) #define HASH_MUR HASH_MUR_UNALIGNED #else #define HASH_MUR HASH_MUR_ALIGNED @@ -630,7 +630,7 @@ do { #endif /* HASH_USING_NO_STRICT_ALIASING */ /* key comparison function; return 0 if keys equal */ -#define HASH_KEYCMP(a,b,len) memcmp(a,b,len) +#define HASH_KEYCMP(a,b,len) memcmp(a,b,len) /* iterate over items in a known bucket to find desired item */ #define HASH_FIND_IN_BKT(tbl,hh,head,keyptr,keylen_in,out) \ @@ -671,36 +671,36 @@ do { } \ if (hh_del->hh_next) { \ hh_del->hh_next->hh_prev = hh_del->hh_prev; \ - } + } /* Bucket expansion has the effect of doubling the number of buckets * and redistributing the items into the new buckets. Ideally the * items will distribute more or less evenly into the new buckets * (the extent to which this is true is a measure of the quality of - * the hash function as it applies to the key domain). - * + * the hash function as it applies to the key domain). + * * With the items distributed into more buckets, the chain length * (item count) in each bucket is reduced. Thus by expanding buckets - * the hash keeps a bound on the chain length. This bounded chain + * the hash keeps a bound on the chain length. This bounded chain * length is the essence of how a hash provides constant time lookup. - * + * * The calculation of tbl->ideal_chain_maxlen below deserves some * explanation. First, keep in mind that we're calculating the ideal * maximum chain length based on the *new* (doubled) bucket count. * In fractions this is just n/b (n=number of items,b=new num buckets). - * Since the ideal chain length is an integer, we want to calculate + * Since the ideal chain length is an integer, we want to calculate * ceil(n/b). We don't depend on floating point arithmetic in this * hash, so to calculate ceil(n/b) with integers we could write - * + * * ceil(n/b) = (n/b) + ((n%b)?1:0) - * + * * and in fact a previous version of this hash did just that. * But now we have improved things a bit by recognizing that b is * always a power of two. We keep its base 2 log handy (call it lb), * so now we can write this with a bit shift and logical AND: - * + * * ceil(n/b) = (n>>lb) + ( (n & (b-1)) ? 1:0) - * + * */ #define HASH_EXPAND_BUCKETS(tbl) \ do { \ @@ -752,7 +752,7 @@ do { /* This is an adaptation of Simon Tatham's O(n log(n)) mergesort */ -/* Note that HASH_SORT assumes the hash handle name to be hh. +/* Note that HASH_SORT assumes the hash handle name to be hh. * HASH_SRT was added to allow the hash handle name to be passed in. */ #define HASH_SORT(head,cmpfcn) HASH_SRT(hh,head,cmpfcn) #define HASH_SRT(hh,head,cmpfcn) \ @@ -834,10 +834,10 @@ do { } \ } while (0) -/* This function selects items from one hash into another hash. - * The end result is that the selected items have dual presence - * in both hashes. There is no copy of the items made; rather - * they are added into the new hash through a secondary hash +/* This function selects items from one hash into another hash. + * The end result is that the selected items have dual presence + * in both hashes. There is no copy of the items made; rather + * they are added into the new hash through a secondary hash * hash handle that must be present in the structure. */ #define HASH_SELECT(hh_dst, dst, hh_src, src, cond) \ do { \ @@ -890,7 +890,7 @@ do { #ifdef NO_DECLTYPE #define HASH_ITER(hh,head,el,tmp) \ for((el)=(head), (*(char**)(&(tmp)))=(char*)((head)?(head)->hh.next:NULL); \ - el; (el)=(tmp),(*(char**)(&(tmp)))=(char*)((tmp)?(tmp)->hh.next:NULL)) + el; (el)=(tmp),(*(char**)(&(tmp)))=(char*)((tmp)?(tmp)->hh.next:NULL)) #else #define HASH_ITER(hh,head,el,tmp) \ for((el)=(head),(tmp)=DECLTYPE(el)((head)?(head)->hh.next:NULL); \ @@ -898,7 +898,7 @@ for((el)=(head),(tmp)=DECLTYPE(el)((head)?(head)->hh.next:NULL); #endif /* obtain a count of items in the hash */ -#define HASH_COUNT(head) HASH_CNT(hh,head) +#define HASH_COUNT(head) HASH_CNT(hh,head) #define HASH_CNT(hh,head) ((head)?((head)->hh.tbl->num_items):0) typedef struct UT_hash_bucket { @@ -907,7 +907,7 @@ typedef struct UT_hash_bucket { /* expand_mult is normally set to 0. In this situation, the max chain length * threshold is enforced at its default value, HASH_BKT_CAPACITY_THRESH. (If - * the bucket's chain exceeds this length, bucket expansion is triggered). + * the bucket's chain exceeds this length, bucket expansion is triggered). * However, setting expand_mult to a non-zero value delays bucket expansion * (that would be triggered by additions to this particular bucket) * until its chain length reaches a *multiple* of HASH_BKT_CAPACITY_THRESH. @@ -915,7 +915,7 @@ typedef struct UT_hash_bucket { * multiplier is to reduce bucket expansions, since they are expensive, in * situations where we know that a particular bucket tends to be overused. * It is better to let its chain length grow to a longer yet-still-bounded - * value, than to do an O(n) bucket expansion too often. + * value, than to do an O(n) bucket expansion too often. */ unsigned expand_mult; @@ -941,7 +941,7 @@ typedef struct UT_hash_table { * hash distribution; reaching them in a chain traversal takes >ideal steps */ unsigned nonideal_items; - /* ineffective expands occur when a bucket doubling was performed, but + /* ineffective expands occur when a bucket doubling was performed, but * afterward, more than half the items in the hash had nonideal chain * positions. If this happens on two consecutive expansions we inhibit any * further expansion, as it's not helping; this happens when the hash diff --git a/extlibs/tinydtls/utlist.h b/extlibs/tinydtls/utlist.h index 8b03b6b..9cd4532 100644 --- a/extlibs/tinydtls/utlist.h +++ b/extlibs/tinydtls/utlist.h @@ -21,12 +21,12 @@ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef _DTLS_UTLIST_H -#define _DTLS_UTLIST_H +#ifndef UTLIST_H +#define UTLIST_H #define UTLIST_VERSION 1.9.1 -/* +/* * This file contains macros to manipulate singly and doubly-linked lists. * * 1. LL_ macros: singly-linked lists. @@ -36,7 +36,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * To use singly-linked lists, your structure must have a "next" pointer. * To use doubly-linked lists, your structure must "prev" and "next" pointers. * Either way, the pointer to the head of the list must be initialized to NULL. - * + * * ----------------.EXAMPLE ------------------------- * struct item { * int id; @@ -83,7 +83,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define _PREVASGN(elt,list,to) { char **_alias = (char**)&((list)->prev); *_alias=(char*)(to); } #define _RS(list) { char **_alias = (char**)&(list); *_alias=_tmp; } #define _CASTASGN(a,b) { char **_alias = (char**)&(a); *_alias=(char*)(b); } -#else +#else #define _SV(elt,list) #define _NEXT(elt,list) ((elt)->next) #define _NEXTASGN(elt,list,to) ((elt)->next)=(to) @@ -369,14 +369,14 @@ do { LL_FOREACH(head,out) { \ if ((out)->field == (val)) break; \ } \ -} while(0) +} while(0) #define LL_SEARCH(head,out,elt,cmp) \ do { \ LL_FOREACH(head,out) { \ if ((cmp(out,elt))==0) break; \ } \ -} while(0) +} while(0) /****************************************************************************** * doubly linked list macros (non-circular) * @@ -465,7 +465,7 @@ do { } while (0); #define CDL_FOREACH(head,el) \ - for(el=head;el;el=(el->next==head ? 0L : el->next)) + for(el=head;el;el=(el->next==head ? 0L : el->next)) #define CDL_FOREACH_SAFE(head,el,tmp1,tmp2) \ for((el)=(head), ((tmp1)=(head)?((head)->prev):NULL); \ @@ -477,14 +477,14 @@ do { CDL_FOREACH(head,out) { \ if ((out)->field == (val)) break; \ } \ -} while(0) +} while(0) #define CDL_SEARCH(head,out,elt,cmp) \ do { \ CDL_FOREACH(head,out) { \ if ((cmp(out,elt))==0) break; \ } \ -} while(0) +} while(0) #endif /* _DTLS_UTLIST_H */ diff --git a/resource/SConscript b/resource/SConscript index d86a982..6a189b2 100644 --- a/resource/SConscript +++ b/resource/SConscript @@ -42,6 +42,9 @@ SConscript('c_common/SConscript') # Build connectivity SConscript('csdk/connectivity/SConscript') +# Build libocsrm +SConscript('csdk/security/SConscript') + # Build liboctbstack SConscript('csdk/SConscript') diff --git a/resource/csdk/SConscript b/resource/csdk/SConscript index a357e85..23635bc 100644 --- a/resource/csdk/SConscript +++ b/resource/csdk/SConscript @@ -49,10 +49,13 @@ liboctbstack_env.PrependUnique(CPPPATH = [ 'connectivity/lib/libcoap-4.1.1', 'connectivity/inc', 'connectivity/api', + 'connectivity/external/inc', 'security/include', 'security/include/internal', ]) +liboctbstack_env.AppendUnique(LIBS = ['ocsrm']) + if target_os not in ['arduino', 'windows', 'winrt']: liboctbstack_env.AppendUnique(CPPDEFINES = ['WITH_POSIX']) liboctbstack_env.AppendUnique(CFLAGS = ['-std=c99']) @@ -105,7 +108,6 @@ liboctbstack_src = [ OCTBSTACK_SRC + 'ocserverrequest.c', OCTBSTACK_SRC + 'occollection.c', OCTBSTACK_SRC + 'oicgroup.c', - 'security/src/ocsecurity.c', 'logger/src/logger.c', 'ocrandom/src/ocrandom.c' ] diff --git a/resource/csdk/connectivity/api/cacommon.h b/resource/csdk/connectivity/api/cacommon.h index d503b5a..ea05c4a 100644 --- a/resource/csdk/connectivity/api/cacommon.h +++ b/resource/csdk/connectivity/api/cacommon.h @@ -75,6 +75,11 @@ extern "C" #endif /** + *@brief Maximum length of the remoteEndpoint identity + */ +#define CA_MAX_ENDPOINT_IDENTITY_LEN (32) + +/** * @brief option types - the highest option number 63 */ #define CA_OPTION_IF_MATCH 1 @@ -158,6 +163,15 @@ typedef union } IP; } CAAddress_t; +/* + * @brief remoteEndpoint identity + */ +typedef struct +{ + uint16_t id_length; + unsigned char id[CA_MAX_ENDPOINT_IDENTITY_LEN]; +}CARemoteId_t; + /** * @enum CAMessageType_t * @brief Message Type for Base source code @@ -191,8 +205,9 @@ typedef struct CAURI_t resourceUri; /**< Resource URI information **/ CAAddress_t addressInfo; /**< Remote Endpoint address **/ - CATransportType_t transportType; /**< Transport Type of the endpoint**/ - bool isSecured; /**< Secure connection**/ + CATransportType_t transportType; /**< Connectivity of the endpoint**/ + bool isSecured; /**< Secure connection**/ + CARemoteId_t identity; /**< Endpoint identity **/ } CARemoteEndpoint_t; @@ -252,7 +267,9 @@ typedef enum CA_CREATED = 201, /**< Created */ CA_DELETED = 202, /**< Deleted */ CA_BAD_REQ = 400, /**< Bad Request */ + CA_UNAUTHORIZED_REQ = 401, /**< Unauthorized Request */ CA_BAD_OPT = 402, /**< Bad Option */ + CA_FORBIDDEN_REQ = 403, /**< Forbidden Request */ CA_NOT_FOUND = 404, /**< Not found */ CA_INTERNAL_SERVER_ERROR = 500, /**< Internal Server Error */ CA_RETRANSMIT_TIMEOUT = 504 /**< Retransmit timeout */ diff --git a/resource/csdk/connectivity/api/cainterface.h b/resource/csdk/connectivity/api/cainterface.h index 7cb0a4f..760df09 100644 --- a/resource/csdk/connectivity/api/cainterface.h +++ b/resource/csdk/connectivity/api/cainterface.h @@ -142,8 +142,7 @@ void CARegisterHandler(CARequestCallback ReqHandler, CAResponseCallback RespHand * @param GetDTLSCredentials [IN] GetDTLS Credetials callback * @return #CA_STATUS_OK */ -CAResult_t CARegisterDTLSCredentialsHandler( - CAGetDTLSCredentialsHandler GetDTLSCredentials); +CAResult_t CARegisterDTLSCredentialsHandler(CAGetDTLSCredentialsHandler GetDTLSCredentials); #endif //__WITH_DTLS__ /** @@ -284,6 +283,92 @@ CAResult_t CAGetNetworkInformation(CALocalConnectivity_t **info, uint32_t *size) */ CAResult_t CAHandleRequestResponse(); + +#ifdef __WITH_DTLS__ + +/** + * 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 + * 0xC0A8 : TLS_PSK_WITH_AES_128_CCM_8 + * 0xC0AE : TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 + * + * @retval CA_STATUS_OK Successful + * @retval CA_STATUS_INVALID_PARAM Invalid input argumets + * @retval CA_STATUS_FAILED Operation failed + */ +CAResult_t CASelectCipherSuite(const uint16_t cipher); + +/** + * Enable TLS_ECDH_anon_WITH_AES_128_CBC_SHA cipher suite in dtls + * + * @param[IN] enable TRUE/FALSE enables/disables anonymous cipher suite + * + * @retval CA_STATUS_OK Successful + * @retval CA_STATUS_FAILED Operation failed + * + * @note anonymous cipher suite should only be enabled for 'JustWorks' provisioning. + */ +CAResult_t CAEnableAnonECDHCipherSuite(const bool enable); + + +/** + * Generate ownerPSK using PRF + * OwnerPSK = TLS-PRF('master key' , 'oic.sec.doxm.jw', + * 'ID of new device(Resource Server)', + * 'ID of owner smart-phone(Provisioning Server)') + * + * @param[IN] addrInfo information of network address + * @param[IN] transportType transport type + * @param[IN] label Ownership transfer method e.g)"oic.sec.doxm.jw" + * @param[IN] labelLen Byte length of label + * @param[IN] rsrcServerDeviceID ID of new device(Resource Server) + * @param[IN] rsrcServerDeviceIDLen Byte length of rsrcServerDeviceID + * @param[IN] provServerDeviceID label of previous owner + * @param[IN] provServerDeviceIDLen byte length of provServerDeviceID + * @param[IN,OUT] ownerPSK Output buffer for owner PSK + * @param[IN] ownerPSKSize Byte length of the ownerPSK to be generated + * + * @retval CA_STATUS_OK Successful + * @retval CA_STATUS_FAILED Operation failed + */ +CAResult_t CAGenerateOwnerPSK(const CAAddress_t* addrInfo, + const CATransportType_t transportType, + const uint8_t* label, const size_t labelLen, + const uint8_t* rsrcServerDeviceID, + const size_t rsrcServerDeviceIDLen, + const uint8_t* provServerDeviceID, + const size_t provServerDeviceIDLen, + uint8_t* ownerPSK, const size_t ownerPSKSize); + +/** + * Initiate DTLS handshake with selected cipher suite + * + * @param[IN] addrInfo information of network address + * @param[IN] transportType transport type + * + * @retval CA_STATUS_OK Successful + * @retval CA_STATUS_FAILED Operation failed + */ +CAResult_t CAInitiateHandshake(const CAAddress_t* addrInfo, + const CATransportType_t transportType); + +/** + * Close the DTLS session + * + * @param[IN] addrInfo information of network address + * @param[IN] transportType transport type + * + * @retval CA_STATUS_OK Successful + * @retval CA_STATUS_FAILED Operation failed + */ +CAResult_t CACloseDtlsSession(const CAAddress_t* addrInfo, + const CATransportType_t transportType); + + +#endif /* __WITH_DTLS__ */ + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/resource/csdk/connectivity/inc/caadapternetdtls.h b/resource/csdk/connectivity/inc/caadapternetdtls.h index debf3d3..f9f99d8 100644 --- a/resource/csdk/connectivity/inc/caadapternetdtls.h +++ b/resource/csdk/connectivity/inc/caadapternetdtls.h @@ -26,6 +26,7 @@ #include "caadapterutils.h" #include "ocsecurityconfig.h" #include "cainterface.h" +#include "cacommon.h" /** * Currently DTLS supported adapters(2) WIFI and ETHENET for linux platform. @@ -38,10 +39,11 @@ extern void OCGetDtlsPskCredentials(CADtlsPskCredsBlob_t **credInfo); typedef void (*CAPacketReceivedCallback)(const char *ipAddress, const uint16_t port, - const void *data, const uint32_t dataLength, const bool isSecured); + const void *data, const uint32_t dataLength, + const bool isSecured, const CARemoteId_t *identity); typedef uint32_t (*CAPacketSendCallback)(const char *ipAddress, const uint16_t port, - const void *data, const uint32_t dataLength); + const void *data, const uint32_t dataLength); /** * @struct stCAAdapterCallbacks_t @@ -60,6 +62,8 @@ typedef struct CAAdapterCallbacks */ typedef struct stCADtlsContext { + u_arraylist_t *peerInfoList; /**< peerInfo list which holds the mapping between + peer id to it's n/w address */ u_arraylist_t *cacheList; /**< PDU's are cached until DTLS session is formed. */ struct dtls_context_t *dtlsContext; /**< Pointer to tinyDTLS context. */ struct stPacketInfo *packetInfo; /**< used by callback during @@ -116,20 +120,20 @@ typedef struct CACacheMessage { void *data; uint32_t dataLen; - stCADtlsAddrInfo_t *destSession; + stCADtlsAddrInfo_t destSession; } stCACacheMessage_t; + /** - * @enum eDtlsAdapterType_t - * @brief This enum is used as array index for storing adapter level callbacks. - * So Keeping 0 instead of "1 << 0". It is not going to be used as addition - * and removal of adapter. - * + * @struct stCADtlsPeerInfo_t + * @brief structure associates the peer psk id with peer n/w address */ -typedef enum +typedef struct stCADtlsPeerInfo { - DTLS_IP = 0, -} eDtlsAdapterType_t; + CAAddress_t address; + CARemoteId_t identity; +}stCADtlsPeerInfo_t; + /** * @fn CADTLSSetAdapterCallbacks @@ -143,7 +147,7 @@ typedef enum * */ void CADTLSSetAdapterCallbacks(CAPacketReceivedCallback recvCallback, - CAPacketSendCallback sendCallback, eDtlsAdapterType_t type); + CAPacketSendCallback sendCallback, CATransportType_t type); /** * @brief Register callback to get DTLS PSK credentials. @@ -153,6 +157,76 @@ void CADTLSSetAdapterCallbacks(CAPacketReceivedCallback recvCallback, 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 + * 0xC0A8 : TLS_PSK_WITH_AES_128_CCM_8 + * 0xC0AE : TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 + * + * @retval CA_STATUS_OK for success, otherwise some error value + */ +CAResult_t CADtlsSelectCipherSuite(const dtls_cipher_t cipher); + +/** + * Enable anonymous ECDH cipher suite for dtls handshake + * + * @param[in] enable TRUE/FALSE enables/disables anonymous cipher suite + * + * @retval CA_STATUS_OK for success, otherwise some error value + */ +CAResult_t CADtlsEnableAnonECDHCipherSuite(const bool enable); + +/** + * Initiate DTLS handshake with selected cipher suite + * + * @param[in] addrInfo information of network address + * @param[in] transportType transport type + * + * @retval CA_STATUS_OK for success, otherwise some error value + */ +CAResult_t CADtlsInitiateHandshake(const CAAddress_t* addrInfo, + const CATransportType_t transportType); + +/** + * Close the DTLS session + * + * @param[in] addrInfo information of network address + * @param[in] transportType transport type + * + * @retval CA_STATUS_OK for success, otherwise some error value + */ +CAResult_t CADtlsClose(const CAAddress_t* addrInfo, + const CATransportType_t transportType); + +/** + * Generate ownerPSK using PRF + * OwnerPSK = TLS-PRF('master key' , 'oic.sec.doxm.jw', + * 'ID of new device(Resource Server)', + * 'ID of owner smart-phone(Provisioning Server)') + * + * @param[in] addrInfo information of network address + * @param[in] transportType transport type + * @param[in] label Ownership transfer method e.g)"oic.sec.doxm.jw" + * @param[in] labelLen Byte length of label + * @param[in] rsrcServerDeviceID ID of new device(Resource Server) + * @param[in] rsrcServerDeviceIDLen Byte length of rsrcServerDeviceID + * @param[in] provServerDeviceID label of previous owner + * @param[in] provServerDeviceIDLen byte length of provServerDeviceID + * @param[in,out] ownerPSK Output buffer for owner PSK + * @param[in] ownerPSKSize Byte length of the ownerPSK to be generated + * + * @retval CA_STATUS_OK for success, otherwise some error value + */ +CAResult_t CADtlsGenerateOwnerPSK(const CAAddress_t* addrInfo, + const CATransportType_t transportType, + const uint8_t* label, const size_t labelLen, + const uint8_t* rsrcServerDeviceID, const size_t rsrcServerDeviceIDLen, + const uint8_t* provServerDeviceID, const size_t provServerDeviceIDLen, + uint8_t* ownerPSK, const size_t ownerPSKSize); +; + +/** * @fn CAAdapterNetDtlsInit * @brief initialize tinyDTLS library and other necessary intialization. * @@ -185,11 +259,8 @@ void CAAdapterNetDtlsDeInit(); * @param[in] port port to which data will be sent. * @param[in] data length of data. * @param[in] dataLen length of given data - * @param[out] decdata output variable to store the starting address - * of decrypted plaintext. - * @param[out] cacheFlag utput variable to indicate if pdu - * is cached and inform the caller to - * NOT free the memory holding pdu. + * @param[in] type transport at which packet needs to be send + * * @return 0 on success otherwise a positive error value. * @retval CA_STATUS_OK Successful * @retval CA_STATUS_INVALID_PARAM Invalid input argumets @@ -201,8 +272,7 @@ CAResult_t CAAdapterNetDtlsEncrypt(const char *remoteAddress, const uint16_t port, void *data, uint32_t dataLen, - uint8_t *cacheFlag, - eDtlsAdapterType_t type); + CATransportType_t type); /** * @fn CAAdapterNetDtlsDecrypt @@ -223,7 +293,7 @@ CAResult_t CAAdapterNetDtlsDecrypt(const char *remoteAddress, const uint16_t port, uint8_t *data, uint32_t dataLen, - eDtlsAdapterType_t type); + CATransportType_t type); #endif /* CA_ADAPTER_NET_DTLS_H_ */ diff --git a/resource/csdk/connectivity/inc/caipinterface.h b/resource/csdk/connectivity/inc/caipinterface.h index 092a51e..b440285 100644 --- a/resource/csdk/connectivity/inc/caipinterface.h +++ b/resource/csdk/connectivity/inc/caipinterface.h @@ -56,13 +56,14 @@ typedef enum * @param data [IN] Data received from remote OIC device. * @param dataLength [IN] Length of data in bytes. * @param isSecured [IN] Indicates the data is secure or not. + * @param identity [IN] Identity of the remote OIC device. * * @return NONE * @pre Callback must be registered using CAIPSetPacketReceiveCallback() */ typedef void (*CAIPPacketReceivedCallback)(const char *ipAddress, uint16_t port, const void *data, uint32_t dataLength, - bool isSecured); + bool isSecured, const CARemoteId_t *identity); /** * @brief Callback to be notified when exception occures on multicast/unicast server. diff --git a/resource/csdk/connectivity/samples/linux/SConscript b/resource/csdk/connectivity/samples/linux/SConscript old mode 100644 new mode 100755 index 9c0a0a3..b859463 --- a/resource/csdk/connectivity/samples/linux/SConscript +++ b/resource/csdk/connectivity/samples/linux/SConscript @@ -11,7 +11,6 @@ ca_transport = sample_env.get('TARGET_TRANSPORT') secured = sample_env.get('SECURED') root_dir = './../../' - ##################################################################### # Source files and Target(s) ###################################################################### @@ -41,6 +40,7 @@ sample_env.PrependUnique(RPATH = [sample_env.get('BUILD_DIR'), '.',]) sample_env.PrependUnique(LIBS = ['connectivity_abstraction', 'coap', 'pthread', 'rt']) if secured == '1': + current_dir=env.get('SRC_DIR') sample_env.AppendUnique(CPPPATH = [root_dir + 'external/inc/']) sample_env.AppendUnique(LIBS = ['tinydtls']) casample =sample_env.Program('casample', [sample_src]) diff --git a/resource/csdk/connectivity/src/SConscript b/resource/csdk/connectivity/src/SConscript old mode 100644 new mode 100755 index a95b933..9d2be70 --- a/resource/csdk/connectivity/src/SConscript +++ b/resource/csdk/connectivity/src/SConscript @@ -83,8 +83,6 @@ else: env.AppendUnique(CPPPATH = [extlib_dir + '/extlibs/tinydtls']) env.AppendUnique(CA_SRC = ca_common_src) - - if 'ALL' in ca_transport: env.SConscript(ca_path + 'ip_adapter/SConscript') env.SConscript(ca_path + 'bt_edr_adapter/SConscript') diff --git a/resource/csdk/connectivity/src/adapter_util/caadapternetdtls.c b/resource/csdk/connectivity/src/adapter_util/caadapternetdtls.c index 562a5fa..8f01c06 100644 --- a/resource/csdk/connectivity/src/adapter_util/caadapternetdtls.c +++ b/resource/csdk/connectivity/src/adapter_util/caadapternetdtls.c @@ -22,6 +22,7 @@ #include "caipinterface.h" #include "dtls.h" #include "oic_malloc.h" +#include "global.h" /** * @def NET_DTLS_TAG @@ -41,11 +42,6 @@ static stCADtlsContext_t *g_caDtlsContext = NULL; */ static ca_mutex g_dtlsContextMutex = NULL; -/** - * @var g_dtlsListMutex - * @brief Mutex to synchronize access to DTLS Cache. - */ -static ca_mutex g_dtlsListMutex = NULL; /** * @var g_getCredentialsCallback @@ -53,6 +49,115 @@ static ca_mutex g_dtlsListMutex = NULL; */ static CAGetDTLSCredentialsHandler g_getCredentialsCallback = NULL; +static stCADtlsPeerInfo_t * GetPeerInfo(const char *peerAddr, uint32_t port) +{ + uint32_t list_index = 0; + uint32_t list_length = 0; + + if(NULL == peerAddr || 0 == port) + { + OIC_LOG(ERROR, NET_DTLS_TAG, "CAPeerInfoListContains invalid parameters"); + return NULL; + } + + stCADtlsPeerInfo_t *peerInfo; + list_length = u_arraylist_length(g_caDtlsContext->peerInfoList); + for (list_index = 0; list_index < list_length; list_index++) + { + peerInfo = (stCADtlsPeerInfo_t *)u_arraylist_get(g_caDtlsContext->peerInfoList, list_index); + if (NULL == peerInfo) + { + continue; + } + + if((0 == strncmp(peerAddr, peerInfo->address.IP.ipAddress, CA_IPADDR_SIZE)) && + (port == peerInfo->address.IP.port)) + { + return peerInfo; + } + } + return NULL; +} + +static CAResult_t CAAddIdToPeerInfoList(const char *peerAddr, uint32_t port, + const unsigned char * id,uint16_t id_length) +{ + if(NULL == peerAddr || NULL == id || 0 == port || 0 == id_length) + { + OIC_LOG(ERROR, NET_DTLS_TAG, "CAAddIdToPeerInfoList invalid parameters"); + return CA_STATUS_INVALID_PARAM; + } + + if(NULL != GetPeerInfo(peerAddr, port)) + { + OIC_LOG(ERROR, NET_DTLS_TAG, "CAAddIdToPeerInfoList peer already exist"); + return CA_STATUS_FAILED; + } + + stCADtlsPeerInfo_t *peerInfo = (stCADtlsPeerInfo_t *) + OICCalloc(1, sizeof(stCADtlsPeerInfo_t)); + if (NULL == peerInfo) + { + OIC_LOG(ERROR, NET_DTLS_TAG, "peerInfo malloc failed!"); + return CA_MEMORY_ALLOC_FAILED; + } + + strncpy(peerInfo->address.IP.ipAddress, peerAddr, CA_IPADDR_SIZE); + peerInfo->address.IP.port = port; + memcpy(peerInfo->identity.id, id, id_length); + peerInfo->identity.id_length = id_length; + + CAResult_t result = u_arraylist_add(g_caDtlsContext->peerInfoList, (void *)peerInfo); + + if (CA_STATUS_OK != result) + { + OIC_LOG(ERROR, NET_DTLS_TAG, "u_arraylist_add failed!"); + OICFree(peerInfo); + } + + return result; +} + + +static void CAFreePeerInfoList() +{ + uint32_t list_length = u_arraylist_length(g_caDtlsContext->peerInfoList); + for (uint32_t list_index = 0; list_index < list_length; list_index++) + { + stCADtlsPeerInfo_t * peerInfo = (stCADtlsPeerInfo_t *)u_arraylist_get( + g_caDtlsContext->peerInfoList, list_index); + OICFree(peerInfo); + } + u_arraylist_free(&(g_caDtlsContext->peerInfoList)); + g_caDtlsContext->peerInfoList = NULL; +} + +static void CARemovePeerFromPeerInfoList(const char * addr, uint32_t port) +{ + if(NULL == addr || 0 >= port) + { + OIC_LOG(ERROR, NET_DTLS_TAG, "CADTLSGetPeerPSKId invalid parameters"); + return; + } + + uint32_t list_length = u_arraylist_length(g_caDtlsContext->peerInfoList); + for (uint32_t list_index = 0; list_index < list_length; list_index++) + { + stCADtlsPeerInfo_t * peerInfo = (stCADtlsPeerInfo_t *)u_arraylist_get( + g_caDtlsContext->peerInfoList,list_index); + if (NULL == peerInfo) + { + continue; + } + if((0 == strncmp(addr, peerInfo->address.IP.ipAddress, CA_IPADDR_SIZE)) && + (port == peerInfo->address.IP.port)) + { + OICFree(u_arraylist_remove(g_caDtlsContext->peerInfoList, list_index)); + return; + } + } +} + static eDtlsRet_t CAAdapterNetDtlsEncryptInternal(const stCADtlsAddrInfo_t *dstSession, uint8_t *data, uint32_t dataLen) { @@ -67,19 +172,15 @@ static eDtlsRet_t CAAdapterNetDtlsEncryptInternal(const stCADtlsAddrInfo_t *dstS return DTLS_FAIL; } - ca_mutex_lock(g_dtlsContextMutex); if (NULL == g_caDtlsContext) { OIC_LOG(ERROR, NET_DTLS_TAG, "Context is NULL"); - ca_mutex_unlock(g_dtlsContextMutex); return DTLS_FAIL; } int retLen = dtls_write(g_caDtlsContext->dtlsContext, (session_t *)dstSession, data, dataLen); OIC_LOG_V(DEBUG, NET_DTLS_TAG, "dtls_write retun len [%d]", retLen); - ca_mutex_unlock(g_dtlsContextMutex); - if (0 == retLen) { // A new DTLS session was initiated by tinyDTLS library and wait for callback. @@ -110,7 +211,6 @@ static eDtlsRet_t CAAdapterNetDtlsDecryptInternal(const stCADtlsAddrInfo_t *srcS eDtlsRet_t ret = DTLS_FAIL; - /// TODO: how to protect g_caDtlsContext as dtls_handle_message is blocking call if (dtls_handle_message(g_caDtlsContext->dtlsContext, (session_t *)srcSession, buf, bufLen) == 0) { OIC_LOG(DEBUG, NET_DTLS_TAG, "dtls_handle_message success"); @@ -126,7 +226,6 @@ static void CAFreeCacheMsg(stCACacheMessage_t *msg) OIC_LOG(DEBUG, NET_DTLS_TAG, "IN"); VERIFY_NON_NULL_VOID(msg, NET_DTLS_TAG, "msg"); - OICFree(msg->destSession); OICFree(msg->data); OICFree(msg); @@ -138,11 +237,9 @@ static void CAClearCacheList() OIC_LOG(DEBUG, NET_DTLS_TAG, "IN"); uint32_t list_index = 0; uint32_t list_length = 0; - ca_mutex_lock(g_dtlsListMutex); if (NULL == g_caDtlsContext) { OIC_LOG(ERROR, NET_DTLS_TAG, "Dtls Context is NULL"); - ca_mutex_unlock(g_dtlsListMutex); return; } list_length = u_arraylist_length(g_caDtlsContext->cacheList); @@ -157,7 +254,6 @@ static void CAClearCacheList() } u_arraylist_free(&g_caDtlsContext->cacheList); g_caDtlsContext->cacheList = NULL; - ca_mutex_unlock(g_dtlsListMutex); OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT"); } @@ -165,11 +261,9 @@ static CAResult_t CADtlsCacheMsg(stCACacheMessage_t *msg) { OIC_LOG(DEBUG, NET_DTLS_TAG, "IN"); - ca_mutex_lock(g_dtlsListMutex); if (NULL == g_caDtlsContext) { OIC_LOG(ERROR, NET_DTLS_TAG, "Dtls Context is NULL"); - ca_mutex_unlock(g_dtlsListMutex); return CA_STATUS_FAILED; } @@ -178,7 +272,6 @@ static CAResult_t CADtlsCacheMsg(stCACacheMessage_t *msg) { OIC_LOG(ERROR, NET_DTLS_TAG, "u_arraylist_add failed!"); } - ca_mutex_unlock(g_dtlsListMutex); OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT"); return result; @@ -200,15 +293,14 @@ static void CASendCachedMsg(const stCADtlsAddrInfo_t *dstSession) uint32_t list_index = 0; uint32_t list_length = 0; - ca_mutex_lock(g_dtlsListMutex); list_length = u_arraylist_length(g_caDtlsContext->cacheList); for (list_index = 0; list_index < list_length;) { stCACacheMessage_t *msg = (stCACacheMessage_t *)u_arraylist_get(g_caDtlsContext->cacheList, list_index); - if ((NULL != msg) && (true == CAIsAddressMatching(msg->destSession, dstSession))) + if ((NULL != msg) && (true == CAIsAddressMatching(&(msg->destSession), dstSession))) { - eDtlsRet_t ret = CAAdapterNetDtlsEncryptInternal(msg->destSession, + eDtlsRet_t ret = CAAdapterNetDtlsEncryptInternal(&(msg->destSession), msg->data, msg->dataLen); if (ret == DTLS_OK) { @@ -237,7 +329,6 @@ static void CASendCachedMsg(const stCADtlsAddrInfo_t *dstSession) ++list_index; } } - ca_mutex_unlock(g_dtlsListMutex); OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT"); } @@ -256,27 +347,28 @@ static int32_t CAReadDecryptedPayload(dtls_context_t *dtlsContext, char *remoteAddress = inet_ntoa(addrInfo->addr.sin.sin_addr); uint32_t port = ntohs(addrInfo->addr.sin.sin_port); - eDtlsAdapterType_t type = (eDtlsAdapterType_t)addrInfo->ifIndex; + CATransportType_t type = (CATransportType_t)addrInfo->ifIndex; - ca_mutex_lock(g_dtlsContextMutex); if (NULL == g_caDtlsContext) { OIC_LOG(ERROR, NET_DTLS_TAG, "Context is NULL"); - ca_mutex_unlock(g_dtlsContextMutex); return 0; } if ((0 <= type) && (MAX_SUPPORTED_ADAPTERS > type) && (NULL != g_caDtlsContext->adapterCallbacks[type].recvCallback)) { + // Get identity of sthe source of packet + stCADtlsPeerInfo_t * peerInfo = GetPeerInfo(remoteAddress, port); + g_caDtlsContext->adapterCallbacks[type].recvCallback(remoteAddress, port, - buf, bufLen, true); + buf, bufLen, true, + (peerInfo) ? &(peerInfo->identity) : NULL); } else { OIC_LOG_V(DEBUG, NET_DTLS_TAG, "recvCallback Callback or adapter type is wrong [%d]", type); } - ca_mutex_unlock(g_dtlsContextMutex); OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT"); return 0; @@ -302,7 +394,7 @@ static int32_t CASendSecureData(dtls_context_t *dtlsContext, char *remoteAddress = inet_ntoa(addrInfo->addr.sin.sin_addr); uint16_t port = ntohs(addrInfo->addr.sin.sin_port); - eDtlsAdapterType_t type = (eDtlsAdapterType_t)addrInfo->ifIndex; + CATransportType_t type = (CATransportType_t)addrInfo->ifIndex; //Mutex is not required for g_caDtlsContext. It will be called in same thread. int32_t sentLen = 0; @@ -341,6 +433,17 @@ static int32_t CAHandleSecureEvent(dtls_context_t *dtlsContext, CASendCachedMsg((stCADtlsAddrInfo_t *)session); } + if(DTLS_ALERT_LEVEL_FATAL == level && DTLS_ALERT_CLOSE_NOTIFY == code) + { + OIC_LOG(INFO, NET_DTLS_TAG, "Peer closing connection"); + + stCADtlsAddrInfo_t *addrInfo = (stCADtlsAddrInfo_t *)session; + char *peerAddr = inet_ntoa(addrInfo->addr.sin.sin_addr); + uint32_t port = ntohs(addrInfo->addr.sin.sin_port); + + CARemovePeerFromPeerInfoList(peerAddr, port); + } + OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT"); return 0; } @@ -355,6 +458,11 @@ static int32_t CAGetPskCredentials(dtls_context_t *ctx, OIC_LOG(DEBUG, NET_DTLS_TAG, "IN"); int32_t ret = -1; + if(NULL == ctx || NULL == session || NULL == result) + { + OIC_LOG(ERROR, NET_DTLS_TAG, "CAGetPskCredentials invalid parameters"); + return ret; + } VERIFY_NON_NULL_RET(g_getCredentialsCallback, NET_DTLS_TAG, "GetCredential callback", -1); VERIFY_NON_NULL_RET(result, NET_DTLS_TAG, "result", -1); @@ -391,6 +499,22 @@ static int32_t CAGetPskCredentials(dtls_context_t *ctx, { if (memcmp(desc, credInfo->creds[index].id, DTLS_PSK_ID_LEN) == 0) { + if(NULL != ctx->peers && DTLS_SERVER == ctx->peers->role ) + { + // TODO SRM needs identity of the remote end-point with every data packet to + // perform access control management. tinyDTLS 'frees' the handshake parameters + // data structure when handshake completes. Therefore, currently this is a + // workaround to cache remote end-point identity when tinyDTLS asks for PSK. + stCADtlsAddrInfo_t *addrInfo = (stCADtlsAddrInfo_t *)session; + char *peerAddress = inet_ntoa(addrInfo->addr.sin.sin_addr); + uint32_t port = ntohs(addrInfo->addr.sin.sin_port); + + CAResult_t result = CAAddIdToPeerInfoList(peerAddress, port, desc, descLen); + if(CA_STATUS_OK != result ) + { + OIC_LOG(ERROR, NET_DTLS_TAG, "Fail to add peer id to gDtlsPeerInfoList"); + } + } memcpy(result, credInfo->creds[index].psk, DTLS_PSK_PSK_LEN); ret = DTLS_PSK_PSK_LEN; } @@ -409,7 +533,7 @@ static int32_t CAGetPskCredentials(dtls_context_t *ctx, } void CADTLSSetAdapterCallbacks(CAPacketReceivedCallback recvCallback, - CAPacketSendCallback sendCallback, eDtlsAdapterType_t type) + CAPacketSendCallback sendCallback, CATransportType_t type) { OIC_LOG(DEBUG, NET_DTLS_TAG, "IN"); ca_mutex_lock(g_dtlsContextMutex); @@ -433,15 +557,199 @@ void CADTLSSetAdapterCallbacks(CAPacketReceivedCallback recvCallback, void CADTLSSetCredentialsCallback(CAGetDTLSCredentialsHandler credCallback) { + // TODO Does this method needs protection of DtlsContextMutex ? OIC_LOG(DEBUG, NET_DTLS_TAG, "IN"); g_getCredentialsCallback = credCallback; OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT"); } +CAResult_t CADtlsSelectCipherSuite(const dtls_cipher_t cipher) +{ + OIC_LOG(DEBUG, NET_DTLS_TAG, "IN CADtlsSelectCipherSuite"); + + ca_mutex_lock(g_dtlsContextMutex); + if (NULL == g_caDtlsContext) + { + OIC_LOG(ERROR, NET_DTLS_TAG, "Context is NULL"); + ca_mutex_unlock(g_dtlsContextMutex); + return CA_STATUS_FAILED; + } + dtls_select_cipher(g_caDtlsContext->dtlsContext, cipher); + ca_mutex_unlock(g_dtlsContextMutex); + + OIC_LOG_V(DEBUG, NET_DTLS_TAG, "Selected cipher suite is 0x%02X%02X\n", + ((uint8_t*)(&cipher))[1], ((uint8_t*)(&cipher))[0]); + OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT CADtlsSelectCipherSuite"); + + return CA_STATUS_OK ; +} + +CAResult_t CADtlsEnableAnonECDHCipherSuite(const bool enable) +{ + OIC_LOG(DEBUG, NET_DTLS_TAG, "IN CADtlsEnablesAnonEcdh"); + + ca_mutex_lock(g_dtlsContextMutex); + if (NULL == g_caDtlsContext) + { + OIC_LOG(ERROR, NET_DTLS_TAG, "Context is NULL"); + ca_mutex_unlock(g_dtlsContextMutex); + return CA_STATUS_FAILED; + } + 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", + enable ? "enabled" : "disabled"); + + OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT CADtlsEnablesAnonEcdh"); + + return CA_STATUS_OK ; +} + +CAResult_t CADtlsInitiateHandshake(const CAAddress_t* addrInfo, + const CATransportType_t transportType) +{ + stCADtlsAddrInfo_t dst = {}; + + OIC_LOG(DEBUG, NET_DTLS_TAG, "IN CADtlsInitiateHandshake"); + + if(!addrInfo) + { + return CA_STATUS_INVALID_PARAM; + } + + if(inet_aton(addrInfo->IP.ipAddress, &dst.addr.sin.sin_addr) == 0) + { + OIC_LOG(ERROR, NET_DTLS_TAG, "Failed to convert from ASCII to Network Address"); + return CA_STATUS_FAILED; + } + dst.addr.sin.sin_family = AF_INET; + dst.addr.sin.sin_port = htons(addrInfo->IP.port); + dst.size = sizeof(dst.addr); + + dst.ifIndex = transportType; + + ca_mutex_lock(g_dtlsContextMutex); + if(NULL == g_caDtlsContext) + { + OIC_LOG(ERROR, NET_DTLS_TAG, "Context is NULL"); + ca_mutex_unlock(g_dtlsContextMutex); + return CA_STATUS_FAILED; + } + + if(0 > dtls_connect(g_caDtlsContext->dtlsContext, (session_t*)(&dst))) + { + OIC_LOG(ERROR, NET_DTLS_TAG, "Failed to connect"); + ca_mutex_unlock(g_dtlsContextMutex); + return CA_STATUS_FAILED; + } + + ca_mutex_unlock(g_dtlsContextMutex); + + OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT CADtlsInitiateHandshake"); + + return CA_STATUS_OK; +} + +CAResult_t CADtlsClose(const CAAddress_t* addrInfo, const CATransportType_t transportType) +{ + stCADtlsAddrInfo_t dst = {}; + + OIC_LOG(DEBUG, NET_DTLS_TAG, "IN CADtlsDisconnect"); + + if(!addrInfo) + { + return CA_STATUS_INVALID_PARAM; + } + + if(inet_aton(addrInfo->IP.ipAddress, &dst.addr.sin.sin_addr) == 0) + { + OIC_LOG(ERROR, NET_DTLS_TAG, "Failed to convert from ASCII to Network Address"); + return CA_STATUS_FAILED; + } + dst.addr.sin.sin_family = AF_INET; + dst.addr.sin.sin_port = htons(addrInfo->IP.port); + dst.size = sizeof(dst.addr); + + dst.ifIndex = transportType; + + ca_mutex_lock(g_dtlsContextMutex); + if(NULL == g_caDtlsContext) + { + OIC_LOG(ERROR, NET_DTLS_TAG, "Context is NULL"); + ca_mutex_unlock(g_dtlsContextMutex); + return CA_STATUS_FAILED; + } + + if(0 > dtls_close(g_caDtlsContext->dtlsContext, (session_t*)(&dst))) + { + OIC_LOG(ERROR, NET_DTLS_TAG, "Failed to close the session"); + ca_mutex_unlock(g_dtlsContextMutex); + return CA_STATUS_FAILED; + } + + ca_mutex_unlock(g_dtlsContextMutex); + + OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT CADtlsDisconnect"); + + return CA_STATUS_OK; +} + +CAResult_t CADtlsGenerateOwnerPSK(const CAAddress_t* addrInfo, + const CATransportType_t transportType, + const uint8_t* label, const size_t labelLen, + const uint8_t* rsrcServerDeviceID, const size_t rsrcServerDeviceIDLen, + const uint8_t* provServerDeviceID, const size_t provServerDeviceIDLen, + uint8_t* ownerPSK, const size_t ownerPSKSize) +{ + OIC_LOG(DEBUG, NET_DTLS_TAG, "IN CADtlsGenerateOwnerPSK"); + + if(!addrInfo || !label || 0 == labelLen || !ownerPSK || 0 == ownerPSKSize) + { + return CA_STATUS_INVALID_PARAM; + } + + stCADtlsAddrInfo_t dst = {}; + + if(inet_aton(addrInfo->IP.ipAddress, &dst.addr.sin.sin_addr) == 0) + { + OIC_LOG(ERROR, NET_DTLS_TAG, "Failed to convert from ASCII to Network Address"); + return CA_STATUS_FAILED; + } + dst.addr.sin.sin_family = AF_INET; + dst.addr.sin.sin_port = htons(addrInfo->IP.port); + dst.size = sizeof(dst.addr); + + dst.ifIndex = transportType; + + ca_mutex_lock(g_dtlsContextMutex); + if (NULL == g_caDtlsContext) + { + OIC_LOG(ERROR, NET_DTLS_TAG, "Context is NULL"); + ca_mutex_unlock(g_dtlsContextMutex); + return CA_STATUS_FAILED; + } + + if( 0 == dtls_prf_with_current_keyblock(g_caDtlsContext->dtlsContext, (session_t*)(&dst), + label, labelLen, rsrcServerDeviceID, rsrcServerDeviceIDLen, + provServerDeviceID, provServerDeviceIDLen, ownerPSK, ownerPSKSize)) + { + OIC_LOG(ERROR, NET_DTLS_TAG, "Failed to DTLS PRF"); + ca_mutex_unlock(g_dtlsContextMutex); + return CA_STATUS_FAILED; + } + ca_mutex_unlock(g_dtlsContextMutex); + + OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT CADtlsGenerateOwnerPSK"); + + return CA_STATUS_OK; +} + CAResult_t CAAdapterNetDtlsInit() { OIC_LOG(DEBUG, NET_DTLS_TAG, "IN"); + // Initialize mutex for DtlsContext if (NULL == g_dtlsContextMutex) { g_dtlsContextMutex = ca_mutex_new(); @@ -454,47 +762,40 @@ CAResult_t CAAdapterNetDtlsInit() return CA_STATUS_OK; } - if (NULL == g_dtlsListMutex) - { - g_dtlsListMutex = ca_mutex_new(); - if (NULL == g_dtlsListMutex) - { - OIC_LOG(ERROR, NET_DTLS_TAG, "g_dtlsListMutex malloc failed"); - ca_mutex_free(g_dtlsContextMutex); - return CA_MEMORY_ALLOC_FAILED; - } - } - + // Lock DtlsContext mutex and create DtlsContext ca_mutex_lock(g_dtlsContextMutex); g_caDtlsContext = (stCADtlsContext_t *)OICCalloc(1, sizeof(stCADtlsContext_t)); if (NULL == g_caDtlsContext) { OIC_LOG(ERROR, NET_DTLS_TAG, "Context malloc failed"); - ca_mutex_free(g_dtlsListMutex); ca_mutex_unlock(g_dtlsContextMutex); ca_mutex_free(g_dtlsContextMutex); return CA_MEMORY_ALLOC_FAILED; } - ca_mutex_lock(g_dtlsListMutex); + + // Create PeerInfoList and CacheList + g_caDtlsContext->peerInfoList = u_arraylist_create(); g_caDtlsContext->cacheList = u_arraylist_create(); - if (NULL == g_caDtlsContext->cacheList) + if( (NULL == g_caDtlsContext->peerInfoList) || + (NULL == g_caDtlsContext->cacheList)) { - OIC_LOG(ERROR, NET_DTLS_TAG, "cacheList initialization failed!"); - ca_mutex_unlock(g_dtlsListMutex); - ca_mutex_free(g_dtlsListMutex); - ca_mutex_unlock(g_dtlsContextMutex); - ca_mutex_free(g_dtlsContextMutex); + OIC_LOG(ERROR, NET_DTLS_TAG, "peerInfoList or cacheList initialization failed!"); + CAClearCacheList(); + CAFreePeerInfoList(); OICFree(g_caDtlsContext); g_caDtlsContext = NULL; + ca_mutex_unlock(g_dtlsContextMutex); + ca_mutex_free(g_dtlsContextMutex); return CA_STATUS_FAILED; } - ca_mutex_unlock(g_dtlsListMutex); + // Initialize clock, crypto and other global vars in tinyDTLS library dtls_init(); + // Create tinydtls Context g_caDtlsContext->dtlsContext = dtls_new_context(g_caDtlsContext); if (NULL == g_caDtlsContext->dtlsContext) @@ -521,19 +822,28 @@ void CAAdapterNetDtlsDeInit() OIC_LOG(DEBUG, NET_DTLS_TAG, "IN"); VERIFY_NON_NULL_VOID(g_caDtlsContext, NET_DTLS_TAG, "context is NULL"); + VERIFY_NON_NULL_VOID(g_dtlsContextMutex, NET_DTLS_TAG, "context mutex is NULL"); + //Lock DtlsContext mutex ca_mutex_lock(g_dtlsContextMutex); + + // Clear all lists + CAFreePeerInfoList(); CAClearCacheList(); + + // De-initialize tinydtls context dtls_free_context(g_caDtlsContext->dtlsContext); g_caDtlsContext->dtlsContext = NULL; + + // De-initialize DtlsContext OICFree(g_caDtlsContext); g_caDtlsContext = NULL; - ca_mutex_unlock(g_dtlsContextMutex); + // Unlock DtlsContext mutex and de-initialize it + ca_mutex_unlock(g_dtlsContextMutex); ca_mutex_free(g_dtlsContextMutex); g_dtlsContextMutex = NULL; - ca_mutex_free(g_dtlsListMutex); - g_dtlsListMutex = NULL; + OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT"); } @@ -541,8 +851,7 @@ CAResult_t CAAdapterNetDtlsEncrypt(const char *remoteAddress, const uint16_t port, void *data, uint32_t dataLen, - uint8_t *cacheFlag, - eDtlsAdapterType_t adapterType) + CATransportType_t transportType) { OIC_LOG(DEBUG, NET_DTLS_TAG, "IN"); @@ -559,30 +868,35 @@ CAResult_t CAAdapterNetDtlsEncrypt(const char *remoteAddress, OIC_LOG_V(DEBUG, NET_DTLS_TAG, "Data to be encrypted dataLen [%d]", dataLen); - stCADtlsAddrInfo_t *addrInfo = (stCADtlsAddrInfo_t *)OICCalloc(1, sizeof(stCADtlsAddrInfo_t)); + stCADtlsAddrInfo_t addrInfo = {}; - VERIFY_NON_NULL_RET(addrInfo, NET_DTLS_TAG, "malloc failed" , CA_MEMORY_ALLOC_FAILED); - - addrInfo->addr.sin.sin_family = AF_INET; - addrInfo->addr.sin.sin_port = htons(port); + addrInfo.addr.sin.sin_family = AF_INET; + addrInfo.addr.sin.sin_port = htons(port); // Conversion from ASCII format to Network format - if (inet_aton(remoteAddress, &addrInfo->addr.sin.sin_addr) == 0) + if (inet_aton(remoteAddress, &addrInfo.addr.sin.sin_addr) == 0) { OIC_LOG(ERROR, NET_DTLS_TAG, "Failed to convert from ASCII to Network Address"); - OICFree(addrInfo); return CA_STATUS_FAILED; } - addrInfo->size = sizeof(addrInfo->addr); - addrInfo->ifIndex = adapterType; + addrInfo.size = sizeof(addrInfo.addr); + addrInfo.ifIndex = transportType; - eDtlsRet_t ret = CAAdapterNetDtlsEncryptInternal(addrInfo, data, dataLen); + ca_mutex_lock(g_dtlsContextMutex); + if(NULL == g_caDtlsContext) + { + OIC_LOG(ERROR, NET_DTLS_TAG, "Context is NULL"); + ca_mutex_unlock(g_dtlsContextMutex); + return CA_STATUS_FAILED; + } + + eDtlsRet_t ret = CAAdapterNetDtlsEncryptInternal(&addrInfo, data, dataLen); if (ret == DTLS_SESSION_INITIATED) { stCACacheMessage_t *message = (stCACacheMessage_t *)OICCalloc(1, sizeof(stCACacheMessage_t)); if (NULL == message) { OIC_LOG(ERROR, NET_DTLS_TAG, "calloc failed!"); - OICFree(addrInfo); + ca_mutex_unlock(g_dtlsContextMutex); return CA_MEMORY_ALLOC_FAILED; } @@ -590,8 +904,8 @@ CAResult_t CAAdapterNetDtlsEncrypt(const char *remoteAddress, if (NULL == message->data) { OIC_LOG(ERROR, NET_DTLS_TAG, "calloc failed!"); - OICFree(addrInfo); OICFree(message); + ca_mutex_unlock(g_dtlsContextMutex); return CA_MEMORY_ALLOC_FAILED; } memcpy(message->data, data, dataLen); @@ -599,23 +913,17 @@ CAResult_t CAAdapterNetDtlsEncrypt(const char *remoteAddress, message->destSession = addrInfo; CAResult_t result = CADtlsCacheMsg(message); - if (CA_STATUS_OK == result) - { - if (cacheFlag) - { - *cacheFlag = 1; - } - } - else + if (CA_STATUS_OK != result) { OIC_LOG(DEBUG, NET_DTLS_TAG, "CADtlsCacheMsg failed!"); CAFreeCacheMsg(message); } OIC_LOG_V(DEBUG, NET_DTLS_TAG, "OUT Initiating Dtls session [%d]", result); + ca_mutex_unlock(g_dtlsContextMutex); return result; } - OICFree(addrInfo); + ca_mutex_unlock(g_dtlsContextMutex); if (ret == DTLS_OK) { @@ -632,30 +940,35 @@ CAResult_t CAAdapterNetDtlsDecrypt(const char *remoteAddress, const uint16_t port, uint8_t *data, uint32_t dataLen, - eDtlsAdapterType_t adapterType) + CATransportType_t transportType) { OIC_LOG(DEBUG, NET_DTLS_TAG, "IN"); - stCADtlsAddrInfo_t *addrInfo = (stCADtlsAddrInfo_t *)OICCalloc(1, sizeof(stCADtlsAddrInfo_t)); + stCADtlsAddrInfo_t addrInfo = {}; - VERIFY_NON_NULL_RET(addrInfo, NET_DTLS_TAG, "calloc failed" , CA_MEMORY_ALLOC_FAILED); - - addrInfo->addr.sin.sin_family = AF_INET; - addrInfo->addr.sin.sin_port = htons(port); + addrInfo.addr.sin.sin_family = AF_INET; + addrInfo.addr.sin.sin_port = htons(port); // Conversion from ASCII format to Network format - if (inet_aton(remoteAddress, &addrInfo->addr.sin.sin_addr) == 0) + if (inet_aton(remoteAddress, &addrInfo.addr.sin.sin_addr) == 0) { OIC_LOG(ERROR, NET_DTLS_TAG, "Failed to convert from ASCII to Network Address"); - OICFree(addrInfo); return CA_STATUS_FAILED; } - addrInfo->size = sizeof(addrInfo->addr); - addrInfo->ifIndex = adapterType; + addrInfo.size = sizeof(addrInfo.addr); + addrInfo.ifIndex = transportType; + + ca_mutex_lock(g_dtlsContextMutex); + if(NULL == g_caDtlsContext) + { + OIC_LOG(ERROR, NET_DTLS_TAG, "Context is NULL"); + ca_mutex_unlock(g_dtlsContextMutex); + return CA_STATUS_FAILED; + } - eDtlsRet_t ret = CAAdapterNetDtlsDecryptInternal(addrInfo, data, dataLen); + eDtlsRet_t ret = CAAdapterNetDtlsDecryptInternal(&addrInfo, data, dataLen); + ca_mutex_unlock(g_dtlsContextMutex); - OICFree(addrInfo); if (DTLS_OK == ret || DTLS_HS_MSG == ret) { OIC_LOG_V(DEBUG, NET_DTLS_TAG, "Successfully Decrypted or Handshake msg recvd [%d]", ret); @@ -667,4 +980,3 @@ CAResult_t CAAdapterNetDtlsDecrypt(const char *remoteAddress, return CA_STATUS_FAILED; } - diff --git a/resource/csdk/connectivity/src/adapter_util/caadapterutils.c b/resource/csdk/connectivity/src/adapter_util/caadapterutils.c index c073b62..8479c55 100644 --- a/resource/csdk/connectivity/src/adapter_util/caadapterutils.c +++ b/resource/csdk/connectivity/src/adapter_util/caadapterutils.c @@ -263,6 +263,7 @@ CARemoteEndpoint_t *CAAdapterCopyRemoteEndpoint(const CARemoteEndpoint_t *remote } info->isSecured = remoteEndpoint->isSecured; + info->identity = remoteEndpoint->identity; return info; } diff --git a/resource/csdk/connectivity/src/caconnectivitymanager.c b/resource/csdk/connectivity/src/caconnectivitymanager.c index 264b885..c5dd281 100644 --- a/resource/csdk/connectivity/src/caconnectivitymanager.c +++ b/resource/csdk/connectivity/src/caconnectivitymanager.c @@ -30,6 +30,9 @@ #include "canetworkconfigurator.h" #include "cainterfacecontroller.h" #include "logger.h" +#ifdef __WITH_DTLS__ +#include "caadapternetdtls.h" +#endif #define TAG PCF("CA") @@ -351,3 +354,95 @@ CAResult_t CAHandleRequestResponse() return CA_STATUS_OK; } +#ifdef __WITH_DTLS__ + +CAResult_t CASelectCipherSuite(const uint16_t cipher) +{ + OIC_LOG_V(DEBUG, TAG, "CASelectCipherSuite"); + + return CADtlsSelectCipherSuite(cipher); +} + +CAResult_t CAEnableAnonECDHCipherSuite(const bool enable) +{ + OIC_LOG_V(DEBUG, TAG, "CAEnableAnonECDHCipherSuite"); + + return CADtlsEnableAnonECDHCipherSuite(enable); +} + +CAResult_t CAGenerateOwnerPSK(const CAAddress_t* addrInfo, + const CATransportType_t transportType, + const uint8_t* label, const size_t labelLen, + const uint8_t* rsrcServerDeviceID, const size_t rsrcServerDeviceIDLen, + const uint8_t* provServerDeviceID, const size_t provServerDeviceIDLen, + uint8_t* ownerPSK, const size_t ownerPSKSize) +{ + OIC_LOG_V(DEBUG, TAG, "IN : CAGenerateOwnerPSK"); + + CAResult_t res = CA_STATUS_OK; + + //newOwnerLabel and prevOwnerLabe can be NULL + if(!addrInfo || !label || 0 == labelLen || !ownerPSK || 0 == ownerPSKSize) + { + return CA_STATUS_INVALID_PARAM; + } + + res = CADtlsGenerateOwnerPSK(addrInfo, transportType, label, labelLen, + rsrcServerDeviceID, rsrcServerDeviceIDLen, + provServerDeviceID, provServerDeviceIDLen, + ownerPSK, ownerPSKSize); + if(CA_STATUS_OK != res) + { + OIC_LOG_V(ERROR, TAG, "Failed to CAGenerateOwnerPSK : %d", res); + } + + OIC_LOG_V(DEBUG, TAG, "OUT : CAGenerateOwnerPSK"); + + return res; +} + +CAResult_t CAInitiateHandshake(const CAAddress_t* addrInfo, + const CATransportType_t transportType) +{ + OIC_LOG_V(DEBUG, TAG, "IN : CAInitiateHandshake"); + CAResult_t res = CA_STATUS_OK; + + if(!addrInfo) + { + return CA_STATUS_INVALID_PARAM; + } + + res = CADtlsInitiateHandshake(addrInfo, transportType); + if(CA_STATUS_OK != res) + { + OIC_LOG_V(ERROR, TAG, "Failed to CADtlsInitiateHandshake : %d", res); + } + + OIC_LOG_V(DEBUG, TAG, "OUT : CAInitiateHandshake"); + + return res; +} + +CAResult_t CACloseDtlsSession(const CAAddress_t* addrInfo, + const CATransportType_t transportType) +{ + OIC_LOG_V(DEBUG, TAG, "IN : CACloseDtlsSession"); + CAResult_t res = CA_STATUS_OK; + + if(!addrInfo) + { + return CA_STATUS_INVALID_PARAM; + } + + res = CADtlsClose(addrInfo, transportType); + if(CA_STATUS_OK != res) + { + OIC_LOG_V(ERROR, TAG, "Failed to CADtlsClose : %d", res); + } + + OIC_LOG_V(DEBUG, TAG, "OUT : CACloseDtlsSession"); + + return res; +} + +#endif /* __WITH_DTLS__ */ diff --git a/resource/csdk/connectivity/src/ip_adapter/caipadapter.c b/resource/csdk/connectivity/src/ip_adapter/caipadapter.c index bd9af23..0a455f4 100644 --- a/resource/csdk/connectivity/src/ip_adapter/caipadapter.c +++ b/resource/csdk/connectivity/src/ip_adapter/caipadapter.c @@ -110,7 +110,8 @@ static void CAIPNotifyNetworkChange(const char *address, uint16_t port, static void CAIPConnectionStateCB(const char *ipAddress, CANetworkStatus_t status); static void CAIPPacketReceivedCB(const char *ipAddress, uint16_t port, const void *data, - uint32_t dataLength, bool isSecured); + uint32_t dataLength, bool isSecured, + const CARemoteId_t *identity); #ifdef __WITH_DTLS__ static uint32_t CAIPPacketSendCB(const char *ipAddress, uint16_t port, const void *data, uint32_t dataLength); @@ -277,7 +278,8 @@ uint32_t CAIPPacketSendCB(const char *ipAddress, uint16_t port, #endif void CAIPPacketReceivedCB(const char *ipAddress, uint16_t port, const void *data, - uint32_t dataLength, bool isSecured) + uint32_t dataLength, bool isSecured, + const CARemoteId_t *identity) { OIC_LOG(DEBUG, IP_ADAPTER_TAG, "IN"); @@ -296,6 +298,11 @@ void CAIPPacketReceivedCB(const char *ipAddress, uint16_t port, const void *data } endPoint->addressInfo.IP.port = port; endPoint->isSecured = isSecured; + if (identity) + { + endPoint->identity = *identity; + } + void *buf = OICCalloc(dataLength + 1, sizeof(char)); if (!buf) @@ -352,7 +359,7 @@ CAResult_t CAInitializeIP(CARegisterConnectivityCallback registerCallback, #ifdef __WITH_DTLS__ CAAdapterNetDtlsInit(); - CADTLSSetAdapterCallbacks(CAIPPacketReceivedCB, CAIPPacketSendCB, DTLS_IP); + CADTLSSetAdapterCallbacks(CAIPPacketReceivedCB, CAIPPacketSendCB, CA_IPV4); #endif CAConnectivityHandler_t ipHandler; @@ -703,7 +710,7 @@ void CATerminateIP() CAStopIP(); #ifdef __WITH_DTLS__ - CADTLSSetAdapterCallbacks(NULL, NULL, DTLS_IP); + CADTLSSetAdapterCallbacks(NULL, NULL, CA_IPV4); #endif CAIPSetPacketReceiveCallback(NULL); @@ -749,17 +756,15 @@ void CAIPSendDataThread(void *threadData) else { OIC_LOG(DEBUG, IP_ADAPTER_TAG, "CAAdapterNetDtlsEncrypt called!"); - uint8_t cacheFlag = 0; CAResult_t result = CAAdapterNetDtlsEncrypt(address, port, ipData->data, - ipData->dataLen, &cacheFlag, - DTLS_IP); + ipData->dataLen, CA_IPV4); if (CA_STATUS_OK != result) { OIC_LOG(ERROR, IP_ADAPTER_TAG, "CAAdapterNetDtlsEncrypt failed!"); } OIC_LOG_V(DEBUG, IP_ADAPTER_TAG, - "CAAdapterNetDtlsEncrypt returned with cache[%d]", cacheFlag); + "CAAdapterNetDtlsEncrypt returned with result[%d]", result); } #else CAIPSendData(address, port, ipData->data, ipData->dataLen, false, diff --git a/resource/csdk/connectivity/src/ip_adapter/caipserver.c b/resource/csdk/connectivity/src/ip_adapter/caipserver.c index 38f164c..e08faed 100644 --- a/resource/csdk/connectivity/src/ip_adapter/caipserver.c +++ b/resource/csdk/connectivity/src/ip_adapter/caipserver.c @@ -266,7 +266,7 @@ static void CAReceiveHandler(void *data) #ifdef __WITH_DTLS__ CAResult_t ret = CAAdapterNetDtlsDecrypt(srcIPAddress, srcPort, (uint8_t *)recvBuffer, recvLen, - DTLS_IP); + CA_IPV4); OIC_LOG_V(DEBUG, IP_SERVER_TAG, "CAAdapterNetDtlsDecrypt returns [%d]", ret); #endif @@ -279,7 +279,7 @@ static void CAReceiveHandler(void *data) { g_adapterEthServerContext->packetReceivedCallback(srcIPAddress, srcPort, recvBuffer, recvLen, - false); + false, NULL); } ca_mutex_unlock(g_mutexAdapterServerContext); diff --git a/resource/csdk/security/README-building-and-running-secure-IoTivity-stack.txt b/resource/csdk/security/README-building-and-running-secure-IoTivity-stack.txt new file mode 100644 index 0000000..9def457 --- /dev/null +++ b/resource/csdk/security/README-building-and-running-secure-IoTivity-stack.txt @@ -0,0 +1,17 @@ +LAST UPDATED 5/27/2015 + +To build the IoTivity stack with the security features enabled: + +1) Build IoTivity with security enabled: + $ cd + $ scons resource SECURED=1 + +2) Verify functionality using secure sample apps: + $ cd /out/<...>/release/resource/csdk/stack/samples/linux/secure + $ export LD_LIBRARY_PATH=/out/<...>/release + $ ./ocserverbasicops & + $ ./occlientbasicops -t 1 + Message "INFO: occlientbasicops: Secure -- YES" indicates success! + $ ./occlientbasicops -t 2 + Completion of 'GET' and 'PUT' query successfully indicates success! + diff --git a/resource/csdk/security/SConscript b/resource/csdk/security/SConscript new file mode 100644 index 0000000..24b4be1 --- /dev/null +++ b/resource/csdk/security/SConscript @@ -0,0 +1,102 @@ +# //****************************************************************** +# // +# // 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. +# // +# //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +# +# libocsrm (share library) build script +## + +Import('env') + +lib_env = env.Clone() +SConscript(env.get('SRC_DIR') + '/resource/third_party_libs.scons', 'lib_env') + +libocsrm_env = lib_env.Clone() + +target_os = env.get('TARGET_OS') +# As in the source code, it includes arduino Time library (C++) +# It requires compile the .c with g++ +if target_os == 'arduino': + libocsrm_env.Replace(CC = env.get('CXX')) + libocsrm_env.Replace(CFLAGS = env.get('CXXFLAGS')) + +###################################################################### +# Build flags +###################################################################### +libocsrm_env.PrependUnique(CPPPATH = [ + '../../../extlibs/cjson/', + '../logger/include', + '../ocrandom/include', + '../stack/include', + '../stack/include/internal', + '../../oc_logger/include', + '../connectivity/lib/libcoap-4.1.1', + '../connectivity/external/inc', + '../connectivity/inc', + '../connectivity/api', + '../security/include', + '../security/include/internal', + ]) + +if target_os not in ['arduino', 'windows', 'winrt']: + libocsrm_env.AppendUnique(CPPDEFINES = ['WITH_POSIX']) + libocsrm_env.AppendUnique(CFLAGS = ['-std=c99']) + +if target_os not in ['windows', 'winrt']: + libocsrm_env.AppendUnique(CFLAGS = ['-Wall']) + +libocsrm_env.AppendUnique(LIBPATH = [env.get('BUILD_DIR')]) +libocsrm_env.AppendUnique(LIBS = ['coap', 'm']) + +if target_os == 'arduino': + libocsrm_env.AppendUnique(CPPDEFINES = ['NDEBUG', 'WITH_ARDUINO']) +else: + libocsrm_env.AppendUnique(CFLAGS = ['-fPIC']) + +if target_os in ['darwin', 'ios']: + libocsrm_env.AppendUnique(CPPDEFINES = ['_DARWIN_C_SOURCE']) + libocsrm_env.AppendUnique(LIBPATH = [env.get('BUILD_DIR')]) + libocsrm_env.AppendUnique(LIBS = ['coap']) + +if not env.get('RELEASE'): + libocsrm_env.AppendUnique(CPPDEFINES = ['TB_LOG']) + +###################################################################### +# 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 + 'base64.c' + ] + +libocsrm = libocsrm_env.StaticLibrary('libocsrm', libocsrm_src) + +libocsrm_env.InstallTarget(libocsrm, 'libocsrm') + +if env.get('SECURED') == '1': + SConscript('provisioning/SConscript') + diff --git a/resource/csdk/security/include/base64.h b/resource/csdk/security/include/base64.h new file mode 100644 index 0000000..4d5837d --- /dev/null +++ b/resource/csdk/security/include/base64.h @@ -0,0 +1,88 @@ + /****************************************************************** + * + * 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 _IOTVT_B64_H_ +#define _IOTVT_B64_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Macro to calculate the size of 'output' buffer required for + * a 'input' buffer of length x during Base64 encoding operation. + */ +#define B64ENCODE_OUT_SAFESIZE(x) ((((x) + 3 - 1)/3) * 4 + 1) + +/** + * Macro to calculate the size of 'output' buffer required for + * a 'input' buffer of length x during Base64 decoding operation. + */ +#define B64DECODE_OUT_SAFESIZE(x) (((x)*3)/4) + +/** + * Result code of base64 functions + */ +typedef enum { + B64_OK = 0, + B64_INVALID_PARAM, + B64_OUTPUT_BUFFER_TOO_SMALL, + B64_ERROR +}B64Result; + +/** + * Encode the plain message in base64. + * + * @param[in] in Plain message + * @param[in] inLen Byte length of 'in' + * @param[in,out] outBuf Output buffer + * Base64 encoded message will be written into 'outBuf' + * NOTE : This method adds a NULL to the string configuration + * @param[in] outBufSize Size of output buffer + * @param[out] outLen Byte length of encoded message + * + * @return B64_OK for Success, otherwise some error value + */ +B64Result b64Encode(const uint8_t* in, const size_t inLen, + char* outBuf, const size_t outBufSize, uint32_t *outLen); + +/** + * Decode the encoded message in base64. + * + * @param[in] in Base64 encoded message + * @param[in] inLen Byte lenth of 'in' + * @param[in, out] outBuf Output buffer + * Base64 decoded message will be written into 'outBuf' + * @param[in] outBufSize Size of output buffer + * @param[out] outLen Byte length of decoded message + * + * @return B64_OK for Success, otherwise some error value + */ +B64Result b64Decode(const char* in, const size_t inLen, + uint8_t* outBuf, size_t outBufSize, uint32_t *outLen); + +#ifdef __cplusplus +} +#endif + +#endif //IOTVT_B64_H diff --git a/resource/csdk/security/include/internal/aclresource.h b/resource/csdk/security/include/internal/aclresource.h new file mode 100755 index 0000000..ce9fa60 --- /dev/null +++ b/resource/csdk/security/include/internal/aclresource.h @@ -0,0 +1,71 @@ +//****************************************************************** +// +// 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_ACLR_H +#define IOTVT_SRM_ACLR_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Initialize ACL resource by loading data from persistent storage. + * + * @retval OC_STACK_OK for Success, otherwise some error value + */ +OCStackResult InitACLResource(); + +/** + * Perform cleanup for ACL resources. + * + * @retval none + */ +void DeInitACLResource(); + +/** + * This method is used by PolicyEngine to retrieve ACL for a Subject. + * + * @param subjectId ID of the subject for which ACL is required. + * @param savePtr is used internally by @ref GetACLResourceData to maintain index between + * successive calls for same subjectId. + * + * @retval reference to @ref OicSecAcl_t if ACL is found, else NULL + * + * @note On the first call to @ref GetACLResourceData, savePtr should point to NULL + */ +const OicSecAcl_t* GetACLResourceData(const OicUuid_t* subjectId, OicSecAcl_t **savePtr); + +/** + * This function converts ACL data into JSON format. + * Caller needs to invoke 'free' when done using + * returned string. + * @param acl instance of OicSecAcl_t structure. + * + * @retval pointer to ACL in json format. + */ +char* BinToAclJSON(const OicSecAcl_t * acl); + +#ifdef __cplusplus +} +#endif + +#endif //IOTVT_SRM_ACLR_H + + diff --git a/resource/csdk/security/include/internal/credresource.h b/resource/csdk/security/include/internal/credresource.h new file mode 100644 index 0000000..9ae31bd --- /dev/null +++ b/resource/csdk/security/include/internal/credresource.h @@ -0,0 +1,133 @@ +//****************************************************************** +// +// 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_CREDR_H +#define IOTVT_SRM_CREDR_H + +#include "ocsecurityconfig.h" +#include "cainterface.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Initialize credential resource by loading data from persistent storage. + * + * @retval + * OC_STACK_OK - no errors + * OC_STACK_ERROR - stack process error + */ +OCStackResult InitCredResource(); + +/** + * Perform cleanup for credential resources. + * + * @retval + * OC_STACK_OK - no errors + * OC_STACK_ERROR - stack process error + * OC_STACK_NO_RESOURCE - resource not found + * OC_STACK_INVALID_PARAM - invalid param + */ +OCStackResult DeInitCredResource(); + +/** + * This method is used by tinydtls/SRM to retrieve credential for given Subject. + * + * @param subject - subject for which credential is required. + * + * @retval + * reference to OicSecCred_t - if credential is found + * NULL - if credential not found + */ +const OicSecCred_t* GetCredResourceData(const OicUuid_t* subjectId); + +/** + * This function converts credential data into JSON format. + * Caller needs to invoke 'free' when done using + * returned string. + * @param cred pointer to instance of OicSecCred_t structure. + * + * @retval + * pointer to JSON credential representation - if credential for subjectId found + * NULL - if credential for subjectId not found + */ +char* BinToCredJSON(const OicSecCred_t* cred); + +/** + * This function generates the bin credential data. + * + * @param subject pointer to subject of this credential. + * @param credType credential type. + * @param publicData public data such as public key. + * @param privateData private data such as private key. + * @param ownersLen length of owners array + * @param owners array of owners. + * + * @retval + * pointer to instance of OicSecCred_t - success + * NULL - error + */ +OicSecCred_t * GenerateCredential(const OicUuid_t* subject, OicSecCredType_t credType, + const char * publicData, const char * privateData, size_t ownersLen, + const OicUuid_t * owners); + +/** + * This function adds the new cred to the credential list. + * + * @param cred pointer to new credential. + * + * @retval + * OC_STACK_OK - cred not NULL and persistent storage gets updated + * OC_STACK_ERROR - cred is NULL or fails to update persistent storage + */ +OCStackResult AddCredential(OicSecCred_t * cred); + +#if defined(__WITH_DTLS__) +/** + * This internal callback is used by lower stack (i.e. CA layer) to + * retrieve PSK credentials from RI security layer. + * + * Note: When finished, caller should initialize memory to zeroes and + * invoke OCFree to delete @p credInfo. + * + * @param credInfo + * binary blob containing PSK credentials + * + * @retval none + */ +void GetDtlsPskCredentials(CADtlsPskCredsBlob_t **credInfo); +#endif /* __WITH_DTLS__ */ + +/** + * Function to deallocate allocated memory to OicSecCred_t + * + * @param cred pointer to cred type + * + */ +void DeleteCredList(OicSecCred_t* cred); + +#ifdef __cplusplus +} +#endif + +#endif //IOTVT_SRM_CREDR_H + + diff --git a/resource/csdk/security/include/internal/doxmresource.h b/resource/csdk/security/include/internal/doxmresource.h new file mode 100644 index 0000000..cd8477e --- /dev/null +++ b/resource/csdk/security/include/internal/doxmresource.h @@ -0,0 +1,102 @@ +//****************************************************************** +// +// 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_DOXM_H +#define IOTVT_SRM_DOXM_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Initialize DOXM resource by loading data from persistent storage. + * + * @retval OC_STACK_OK for Success, otherwise some error value + */ +OCStackResult InitDoxmResource(); + +/** + * Perform cleanup for DOXM resources. + * + * @retval OC_STACK_OK for Success, otherwise some error value + */ +OCStackResult DeInitDoxmResource(); + +/** + * This method is used by SRM to retrieve DOXM resource data.. + * + * @retval reference to @ref OicSecDoxm_t, binary format of Doxm resource data + */ +const OicSecDoxm_t* GetDoxmResourceData(); + +/** + * This method converts JSON DOXM into binary DOXM. + * The JSON DOXM can be from persistent database or + * or received as PUT/POST request. + * + * @param[in] jsonStr doxm data in json string. + * @return pointer to OicSecDoxm_t. + * + * @note Caller needs to invoke OCFree after done + * using the return pointer + */ +OicSecDoxm_t * JSONToDoxmBin(const char * jsonStr); + +/** + * This method converts DOXM data into JSON format. + * Caller needs to invoke 'free' when finished done using + * return string + * + * @param[in] doxm Pointer to OicSecDoxm_t. + * @return pointer to json string. + * + * @note Caller needs to invoke OCFree after done + * using the return pointer + */ +char * BinToDoxmJSON(const OicSecDoxm_t * doxm); + +/** + * This method returns the SRM device ID for this device. + * + * @retval OC_STACK_OK for Success, otherwise some error value + */ +OCStackResult GetDoxmDeviceID(OicUuid_t *deviceID); + +/** + * @brief Gets the OicUuid_t value for the owner of this device. + * + * @return OC_STACK_OK if devOwner is a valid UUID, otherwise OC_STACK_ERROR. + */ +OCStackResult GetDoxmDevOwnerId(OicUuid_t *devOwner); + +/** This function deallocates the memory for OicSecDoxm_t . + * + * @param[in] doxm Pointer to OicSecDoxm_t. + */ +void DeleteDoxmBinData(OicSecDoxm_t* doxm); + + +#ifdef __cplusplus +} +#endif + +#endif //IOTVT_SRM_DOXMR_H + + diff --git a/resource/csdk/security/include/internal/policyengine.h b/resource/csdk/security/include/internal/policyengine.h new file mode 100644 index 0000000..a792bfa --- /dev/null +++ b/resource/csdk/security/include/internal/policyengine.h @@ -0,0 +1,88 @@ +//****************************************************************** +// +// 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_PE_H +#define IOTVT_SRM_PE_H + +#include "ocstack.h" +#include "logger.h" +#include "securevirtualresourcetypes.h" +#include "cainterface.h" +#include +#include + + +typedef enum PEState +{ + STOPPED = 0, + AWAITING_REQUEST, + BUSY +} PEState_t; + +typedef struct PEContext +{ + PEState_t state; + OicUuid_t *subject; + char *resource; + uint16_t permission; + bool matchingAclFound; + SRMAccessResponse_t retVal; +} PEContext_t; + +/** + * Check whether a request should be allowed. + * + * @param context Pointer to Policy Engine context to use. + * @param subjectId Pointer to Id of the requesting entity. + * @param resource Pointer to URI of Resource being requested. + * @param permission Requested permission. + * + * @return ACCESS_GRANTED if request should go through, + * otherwise some flavor of ACCESS_DENIED + */ +SRMAccessResponse_t CheckPermission( + PEContext_t *context, + const OicUuid_t *subjectId, + const char *resource, + const uint16_t requestedPermission); + +/** + * Initialize the Policy Engine. Call this before calling CheckPermission(). + * TODO Eventually this and DeInit() need to be called from a new + * "SRMInit(SRMContext_t *)" function, TBD after BeachHead. + * @param context Pointer to Policy Engine context to initialize. + * @return OC_STACK_OK for Success, otherwise some error value + */ +OCStackResult InitPolicyEngine(PEContext_t *context); + +/** + * De-Initialize the Policy Engine. Call this before exiting to allow Policy + * Engine to do cleanup on context. + * @param context Pointer to Policy Engine context to de-initialize. + * @return none + */ +void DeInitPolicyEngine(PEContext_t *context); + +/** + * Return the uint16_t CRUDN permission corresponding to passed CAMethod_t. + */ +uint16_t GetPermissionFromCAMethod_t(const CAMethod_t method); + +#endif //IOTVT_SRM_PE_H diff --git a/resource/csdk/security/include/internal/ocsecurityinternal.h b/resource/csdk/security/include/internal/psinterface.h similarity index 50% rename from resource/csdk/security/include/internal/ocsecurityinternal.h rename to resource/csdk/security/include/internal/psinterface.h index d080546..b48c674 100644 --- a/resource/csdk/security/include/internal/ocsecurityinternal.h +++ b/resource/csdk/security/include/internal/psinterface.h @@ -1,6 +1,6 @@ //****************************************************************** // -// Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved. +// Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved. // //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= // @@ -18,35 +18,29 @@ // //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -#ifndef OC_SECURITY_INTERNAL_H -#define OC_SECURITY_INTERNAL_H - -#include "ocsecurityconfig.h" +#ifndef IOTVT_SRM_PSI_H +#define IOTVT_SRM_PSI_H /** - * This callback is used by lower stack (i.e. CA layer) to retrieve PSK - * credentials from RI security layer. - * - * Note: When finished, caller should initialize memory to zeroes and - * invoke OCFree to delete @p credInfo. + * Reads the Secure Virtual Database from PS into dynamically allocated + * memory buffer. * - * @param credInfo - * binary blob containing PSK credentials + * @note Caller of this method MUST use OCFree() method to release memory + * referenced by return value. * - * @retval none + * @retval reference to memory buffer containing SVR database. */ -#ifdef __WITH_DTLS__ -void GetDtlsPskCredentials(CADtlsPskCredsBlob_t **credInfo); -#endif //__WITH_DTLS__ - +char * GetSVRDatabase(); /** - * This internal API removes/clears the global variable holding the security - * config data. This needs to be invoked when OIC stack is shutting down. + * This method is used by a entity handlers of SVR's to update + * SVR database. * - * @retval none + * @param rsrcName string denoting the SVR name ("acl", "cred", "pstat" etc). + * @param jsonObj JSON object containing the SVR contents. + * + * @retval OC_STACK_OK for Success, otherwise some error value */ -void DeinitOCSecurityInfo(); - -#endif //OC_SECURITY_INTERNAL_H +OCStackResult UpdateSVRDatabase(const char* rsrcName, cJSON* jsonObj); +#endif //IOTVT_SRM_PSI_H diff --git a/resource/csdk/security/include/internal/pstatresource.h b/resource/csdk/security/include/internal/pstatresource.h new file mode 100644 index 0000000..40c41ab --- /dev/null +++ b/resource/csdk/security/include/internal/pstatresource.h @@ -0,0 +1,71 @@ +//****************************************************************** +// +// 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_PSTATR_H +#define IOTVT_SRM_PSTATR_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Initialize Pstat resource by loading data from persistent storage. + * + * @retval OC_STACK_OK for Success, otherwise some error value + */ +OCStackResult InitPstatResource(); + +/** + * Perform cleanup for Pstat resources. + * + * @retval OC_STACK_OK for Success, otherwise some error value + */ +OCStackResult DeInitPstatResource(); + +/** + * This method converts JSON PSTAT into binary PSTAT. + * + * @param[in] jsonStr pstat data in json string. + * @return pointer to OicSecPstat_t. + */ +OicSecPstat_t * JSONToPstatBin(const char * jsonStr); + +/** + * This method converts pstat data into JSON format. + * + * @param[in] pstat pstat data in binary format. + * @return pointer to pstat json string. + */ +char * BinToPstatJSON(const OicSecPstat_t * pstat); + +/** This function deallocates the memory for OicSecPstat_t. + * + * @param[in] pstat Pointer to OicSecPstat_t. + */ +void DeletePstatBinData(OicSecPstat_t* pstat); + + +#ifdef __cplusplus +} +#endif + +#endif //IOTVT_SRM_PSTATR_H + + diff --git a/resource/csdk/security/include/internal/resourcemanager.h b/resource/csdk/security/include/internal/resourcemanager.h new file mode 100644 index 0000000..3e946f5 --- /dev/null +++ b/resource/csdk/security/include/internal/resourcemanager.h @@ -0,0 +1,56 @@ +//****************************************************************** +// +// 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_RM_H +#define IOTVT_SRM_RM_H + +#include +#include "ocstack.h" +#include "securevirtualresourcetypes.h" + +/** + * Initialize all secure resources ( /oic/sec/cred, /oic/sec/acl, /oic/sec/pstat etc). + * + * @retval OC_STACK_OK for Success, otherwise some error value + */ +OCStackResult InitSecureResources(); + +/** + * Perform cleanup for secure resources ( /oic/sec/cred, /oic/sec/acl, /oic/sec/pstat etc). + * + * @retval OC_STACK_OK for Success, otherwise some error value + */ +OCStackResult DestroySecureResources(); + +/** + * This method is used by all secure resource modules to send responses to REST queries. + * + * @param ehRequest pointer to entity handler request data structure. + * @param ehRet result code from entity handler. + * @param rspPayload response payload in JSON. + * + * @retval OC_STACK_OK for Success, otherwise some error value + */ +OCStackResult SendSRMResponse(const OCEntityHandlerRequest *ehRequest, + OCEntityHandlerResult ehRet, const char *rspPayload); + +#endif //IOTVT_SRM_RM_H + + diff --git a/resource/csdk/security/include/internal/secureresourcemanager.h b/resource/csdk/security/include/internal/secureresourcemanager.h new file mode 100644 index 0000000..f07579e --- /dev/null +++ b/resource/csdk/security/include/internal/secureresourcemanager.h @@ -0,0 +1,86 @@ +//****************************************************************** +// +// 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 SECURITYRESOURCEMANAGER_H_ +#define SECURITYRESOURCEMANAGER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Register Persistent storage callback. + * @param persistentStorageHandler [IN] Pointers to open, read, write, close & unlink handlers. + * @return + * OC_STACK_OK - No errors; Success + * OC_STACK_INVALID_PARAM - Invalid parameter + */ +OCStackResult SRMRegisterPersistentStorageHandler(OCPersistentStorage* persistentStorageHandler); + +/** + * @brief Get Persistent storage handler pointer. + * @return + * The pointer to Persistent Storage callback handler + */ +OCPersistentStorage* SRMGetPersistentStorageHandler(); + +/** + * @brief Register request and response callbacks. + * Requests and responses are delivered in these callbacks. + * @param reqHandler [IN] Request handler callback ( for GET,PUT ..etc) + * @param respHandler [IN] Response handler callback. + * @param errHandler [IN] Error handler callback. + * @return + * OC_STACK_OK - No errors; Success + * OC_STACK_INVALID_PARAM - Invalid parameter + */ +OCStackResult SRMRegisterHandler(CARequestCallback reqHandler, + CAResponseCallback respHandler, + CAErrorCallback errHandler); + +/** + * @brief Initialize all secure resources ( /oic/sec/cred, /oic/sec/acl, /oic/sec/pstat etc). + * @return OC_STACK_OK for Success, otherwise some error value + */ +OCStackResult SRMInitSecureResources(); + +/** + * @brief Perform cleanup for secure resources ( /oic/sec/cred, /oic/sec/acl, /oic/sec/pstat etc). + * @return none + */ +void SRMDeInitSecureResources(); + +/** + * @brief Initialize Policy Engine context. + * @return OC_STACK_OK for Success, otherwise some error value. + */ +OCStackResult SRMInitPolicyEngine(); + +/** + * @brief Cleanup Policy Engine context. + * @return none + */ +void SRMDeInitPolicyEngine(); + +#ifdef __cplusplus +} +#endif + +#endif /* SECURITYRESOURCEMANAGER_H_ */ diff --git a/resource/csdk/security/include/internal/srmresourcestrings.h b/resource/csdk/security/include/internal/srmresourcestrings.h new file mode 100644 index 0000000..51f3720 --- /dev/null +++ b/resource/csdk/security/include/internal/srmresourcestrings.h @@ -0,0 +1,91 @@ +//****************************************************************** +// +// 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_RSRC_STRINGS_H +#define IOTVT_SRM_RSRC_STRINGS_H + +#include "securevirtualresourcetypes.h" + +extern const char * SVR_DB_FILE_NAME; +extern const char * OIC_MI_DEF; + +extern const char * OIC_RSRC_CORE_URI; +extern const char * OIC_RSRC_CORE_D_URI; +extern const char * OIC_RSRC_CORE_P_URI; +extern const char * OIC_RSRC_PRESENCE_URI; +extern const char * OIC_RSRC_TYPES_D_URI; + +//ACL +extern const char * OIC_RSRC_TYPE_SEC_ACL; +extern const char * OIC_RSRC_ACL_URI; +extern const char * OIC_JSON_ACL_NAME; + +//PSTAT +extern const char * OIC_RSRC_TYPE_SEC_PSTAT; +extern const char * OIC_RSRC_PSTAT_URI; +extern const char * OIC_JSON_PSTAT_NAME; + + +//DOXM +extern const char * OIC_RSRC_TYPE_SEC_DOXM; +extern const char * OIC_RSRC_DOXM_URI; +extern const char * OIC_JSON_DOXM_NAME; + +//cred +extern const char * OIC_RSRC_TYPE_SEC_CRED; +extern const char * OIC_RSRC_CRED_URI; +extern const char * OIC_JSON_CRED_NAME; + +extern const char * OIC_JSON_SUBJECT_NAME; +extern const char * OIC_JSON_RESOURCES_NAME; +extern const char * OIC_JSON_PERMISSION_NAME; +extern const char * OIC_JSON_OWNERS_NAME; +extern const char * OIC_JSON_OWNER_NAME; +extern const char * OIC_JSON_OWNED_NAME; +extern const char * OIC_JSON_OXM_NAME; +extern const char * OIC_JSON_OXM_TYPE_NAME; +extern const char * OIC_JSON_OXM_SEL_NAME; +extern const char * OIC_JSON_DEVICE_ID_FORMAT_NAME; +extern const char * OIC_JSON_CREDID_NAME; +extern const char * OIC_JSON_ROLEIDS_NAME; +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_ISOP_NAME; +extern const char * OIC_JSON_COMMIT_HASH_NAME; +extern const char * OIC_JSON_DEVICE_ID_NAME; +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 OicUuid_t WILDCARD_SUBJECT_ID; +extern size_t WILDCARD_SUBJECT_ID_LEN; + +//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; + +#endif //IOTVT_SRM_RSRC_STRINGS_H + diff --git a/resource/csdk/security/include/ocsecurityconfig.h b/resource/csdk/security/include/ocsecurityconfig.h deleted file mode 100644 index fa5d164..0000000 --- a/resource/csdk/security/include/ocsecurityconfig.h +++ /dev/null @@ -1,103 +0,0 @@ -//****************************************************************** -// -// Copyright 2014 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 OC_SECURITY_CONFIG_H -#define OC_SECURITY_CONFIG_H - -#include - -#define DTLS_PSK_ID_LEN 16 -#define DTLS_PSK_PSK_LEN 16 - -#define OCSecConfigVer_1 1 /**< Initial version supporting PSK Credentials */ -#define OCSecConfigVer_CurrentVersion OCSecConfigVer_1 - -typedef enum{ - OC_BLOB_TYPE_PSK = 1, /**< Security blob holding PSK data */ -} OCBlobType; - - -/** - * Credentials of a peer device. Includes identity and the associated PSK. - */ -typedef struct -{ - unsigned char id[DTLS_PSK_ID_LEN]; /**< identity of the peer device */ - unsigned char psk[DTLS_PSK_PSK_LEN]; /**< psk of the peer device */ -} OCDtlsPskCreds; - - -/** - * Binary blob containing device identity and the credentials for all devices - * trusted by this device. - */ -typedef struct -{ - unsigned char identity[DTLS_PSK_ID_LEN]; /**< identity of self */ - uint32_t num; /**< number of credentials in this blob */ - OCDtlsPskCreds creds[1]; /**< list of credentials. Size of this - array is determined by 'num' variable. */ -} OCDtlsPskCredsBlob; - - -/** - * Generic definition of a security blob. A security blob can contain - * info of various types, such as : PSK info, certificates, - * access control lists(ACL) etc. - */ -typedef struct -{ - uint16_t type; /**< Type of blob */ - uint16_t len; /**< length of blob data */ - uint8_t val[1]; /**< A variable size array holding blob data */ -} OCSecBlob; - - -/** - * This structure defines the security related configuration data for - * Iotivity applications. - */ -typedef struct -{ - uint16_t version; /**< version of the config data */ - uint16_t numBlob; /**< number of security blobs in this config data */ - uint8_t blob[1]; /**< A variable size array holding a blob */ -} OCSecConfigData; - -/** - * Interprets @p blob as pointer to a OCSecBlob and advances to - * the next blob in the OCSecConfigData - */ -#define config_data_next_blob(blob) \ - ((OCSecBlob*)((blob)->val + (blob)->len)); - -/** - * Configuration data for security will be stored in below fashion in a - * flat file on persistent storage. - * - * -------------------------------------------------------------- - * | OCSecConfigData| OCSecBlob #1 | OCSecBlob #2 | OCSecBlob #3| - * -------------------------------------------------------------- - */ - -#endif //OC_SECURITY_CONFIG_H - - - diff --git a/resource/csdk/security/include/securevirtualresourcetypes.h b/resource/csdk/security/include/securevirtualresourcetypes.h new file mode 100644 index 0000000..6df713b --- /dev/null +++ b/resource/csdk/security/include/securevirtualresourcetypes.h @@ -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. +// +//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= + +/** + * Data type definitions for all oic.sec.* types defined in the + * OIC Security Specification. + * + * Note that throughout, ptrs are used rather than arrays. There + * are two primary reasons for this: + * 1) The Spec defines many structures with optional fields, so pre- + * allocating these would be wasteful. + * 2) There are in many cases arrays of Strings or arrays of Structs, + * which could not be defined as variable length arrays (e.g. array[]) + * without breaking from the structure order and definition in the Spec. + * + * The primary drawback to this decision is that marshalling functions + * will have to be written by hand to marshal these structures (e.g. to/from + * Persistent Storage, or across memory boundaries). + * + * TODO reconcile against latest OIC Security Spec to ensure all fields correct. + * (Last checked against v0.95) + */ + +#ifndef OC_SECURITY_RESOURCE_TYPES_H +#define OC_SECURITY_RESOURCE_TYPES_H + +#include // for uint8_t typedef +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Values used to create bit-maskable enums for single-value + * response with embedded code. + */ +#define ACCESS_GRANTED_DEF (1 << 0) +#define ACCESS_DENIED_DEF (1 << 1) +#define INSUFFICIENT_PERMISSION_DEF (1 << 2) +#define SUBJECT_NOT_FOUND_DEF (1 << 3) +#define RESOURCE_NOT_FOUND_DEF (1 << 4) +#define POLICY_ENGINE_ERROR_DEF (1 << 5) +#define REASON_MASK_DEF (INSUFFICIENT_PERMISSION_DEF | \ + SUBJECT_NOT_FOUND_DEF | \ + RESOURCE_NOT_FOUND_DEF | \ + POLICY_ENGINE_ERROR_DEF) + + +/** + * Access policy in least significant bits (from Spec): + * 1st lsb: C (Create) + * 2nd lsb: R (Read, Observe, Discover) + * 3rd lsb: U (Write, Update) + * 4th lsb: D (Delete) + * 5th lsb: N (Notify) + */ +#define PERMISSION_CREATE (1 << 0) +#define PERMISSION_READ (1 << 1) +#define PERMISSION_WRITE (1 << 2) +#define PERMISSION_DELETE (1 << 3) +#define PERMISSION_NOTIFY (1 << 4) +#define PERMISSION_FULL_CONTROL (PERMISSION_CREATE | \ + PERMISSION_READ | \ + PERMISSION_WRITE | \ + PERMISSION_DELETE | \ + PERMISSION_NOTIFY) + +/** + * @brief Response type for all Action requests from CA layer; + * may include a reason code. + * + * To extract codes use GetReasonCode function on SRMAccessResponse: + * + * SRMAccessResponse_t response = SRMRequestHandler(obj, info); + * if(SRM_TRUE == IsAccessGranted(response)) { + * SRMAccessResponseReasonCode_t reason = GetReasonCode(response); + * switch(reason) { + * case INSUFFICIENT_PERMISSION: + * ...etc. + * } + * } + */ +typedef enum +{ + ACCESS_GRANTED = ACCESS_GRANTED_DEF, + ACCESS_DENIED = ACCESS_DENIED_DEF, + ACCESS_DENIED_INSUFFICIENT_PERMISSION = ACCESS_DENIED_DEF + | INSUFFICIENT_PERMISSION_DEF, + ACCESS_DENIED_SUBJECT_NOT_FOUND = ACCESS_DENIED_DEF + | SUBJECT_NOT_FOUND_DEF, + ACCESS_DENIED_RESOURCE_NOT_FOUND = ACCESS_DENIED_DEF + | RESOURCE_NOT_FOUND_DEF, + ACCESS_DENIED_POLICY_ENGINE_ERROR = ACCESS_DENIED_DEF + | POLICY_ENGINE_ERROR_DEF, +} SRMAccessResponse_t; + +/** + * Reason code for SRMAccessResponse. + */ +typedef enum +{ + NO_REASON_GIVEN = 0, + INSUFFICIENT_PERMISSION = INSUFFICIENT_PERMISSION_DEF, + SUBJECT_NOT_FOUND = SUBJECT_NOT_FOUND_DEF, + RESOURCE_NOT_FOUND = RESOURCE_NOT_FOUND_DEF, +} SRMAccessResponseReasonCode_t; + +/** + * Extract Reason Code from Access Response. + */ +static inline SRMAccessResponseReasonCode_t GetReasonCode( + SRMAccessResponse_t response) +{ + SRMAccessResponseReasonCode_t reason = + (SRMAccessResponseReasonCode_t)(response & REASON_MASK_DEF); + return reason; +} + +/** + * Returns 'true' iff request should be passed on to RI layer. + */ +static inline bool IsAccessGranted(SRMAccessResponse_t response) +{ + if(ACCESS_GRANTED == (response & ACCESS_GRANTED)) + { + return true; + } + else + { + return false; + } +} + +typedef struct OicSecAcl OicSecAcl_t; + +typedef struct OicSecAmacl OicSecAmacl_t; + +typedef struct OicSecCred OicSecCred_t; + +/** + * @brief /oic/sec/credtype (Credential Type) data type. + * Derived from OIC Security Spec /oic/sec/cred; see Spec for details. + * 0: no security mode + * 1: symmetric pair-wise key + * 2: symmetric group key + * 4: asymmetric key + * 8: signed asymmetric key (aka certificate) + * 16: PIN /password + */ +typedef uint16_t OicSecCredType_t; + +/** + * Aid for assigning/testing vals with OicSecCredType_t. + * Example: + * OicSecCredType_t ct = PIN_PASSWORD | ASYMMETRIC_KEY; + * if((ct & PIN_PASSWORD) == PIN_PASSWORD) + * { + * // ct contains PIN_PASSWORD flag. + * } + */ +typedef enum OSCTBitmask +{ + NO_SECURITY_MODE = 0x0, + SYMMETRIC_PAIR_WISE_KEY = (0x1 << 0), + SYMMETRIC_GROUP_KEY = (0x1 << 1), + ASYMMETRIC_KEY = (0x1 << 2), + SIGNED_ASYMMETRIC_KEY = (0x1 << 3), + PIN_PASSWORD = (0x1 << 4), +} OSCTBitmask_t; + +typedef struct OicSecDoxm OicSecDoxm_t; + +typedef enum OicSecDpm +{ + NORMAL = 0x0, + RESET = (0x1 << 0), + TAKE_OWNER = (0x1 << 1), + BOOTSTRAP_SERVICE = (0x1 << 2), + SECURITY_MANAGEMENT_SERVICES = (0x1 << 3), + PROVISION_CREDENTIALS = (0x1 << 4), + PROVISION_ACLS = (0x1 << 5), + // << 6 THROUGH 15 RESERVED +} OicSecDpm_t; + +typedef enum OicSecDpom +{ + MULTIPLE_SERVICE_SERVER_DRIVEN = 0x0, + SINGLE_SERVICE_SERVER_DRIVEN = 0x1, + MULTIPLE_SERVICE_CLIENT_DRIVEN = 0x2, + SINGLE_SERVICE_CLIENT_DRIVEN = 0x3, +} OicSecDpom_t; + +//TODO: Need more clarification on deviceIDFormat field type. +#if 0 +typedef enum +{ + URN = 0x0 +}OicSecDvcIdFrmt_t; +#endif + +typedef enum +{ + OIC_JUST_WORKS = 0x0, + OIC_MODE_SWITCH = 0x1, + OIC_RANDOM_DEVICE_PIN = 0x2, + OIC_PRE_PROVISIONED_DEVICE_PIN = 0x3, + OIC_PRE_PROVISION_STRONG_CREDENTIAL = 0x4 +}OicSecOxm_t; + +typedef struct OicSecJwk OicSecJwk_t; + +typedef struct OicSecPstat OicSecPstat_t; + +typedef struct OicSecRole OicSecRole_t; + +typedef struct OicSecSacl OicSecSacl_t; + +typedef struct OicSecSvc OicSecSvc_t; + +typedef char *OicUrn_t; //TODO is URN type defined elsewhere? + +typedef struct OicUuid OicUuid_t; //TODO is UUID type defined elsewhere? + + +/** + * @brief /oic/uuid (Universal Unique Identifier) data type. + */ +#define UUID_LENGTH 128/8 // 128-bit GUID length +//TODO: Confirm the length and type of ROLEID. +#define ROLEID_LENGTH 128/8 // 128-bit ROLEID length +#define OWNER_PSK_LENGTH_128 128/8 //byte size of 128-bit key size +#define OWNER_PSK_LENGTH_256 256/8 //byte size of 256-bit key size + +struct OicUuid +{ + // :::: + //TODO fill in unless this is defined elsewhere? + uint8_t id[UUID_LENGTH]; +}; + +/** + * @brief /oic/sec/jwk (JSON Web Key) data type. + * See JSON Web Key (JWK) draft-ietf-jose-json-web-key-41 + */ +#define JWK_LENGTH 256/8 // 256 bit key length +struct OicSecJwk +{ + char *data; +}; + +/** + * @brief /oic/sec/acl (Access Control List) data type. + * Derived from OIC Security Spec; see Spec for details. + */ +struct OicSecAcl +{ + // :::: + OicUuid_t subject; // 0:R:S:Y:uuid TODO: this deviates + // from spec and needs to be updated + // in spec (where it's a String). + 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 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 + // SRM version only; this will change to Svc type for full implementation. + //TODO change Owners type to oic.sec.svc + //OicSecSvc_t *Owners; // 6:R:M:Y:oic.sec.svc + OicSecAcl_t *next; +}; + +/** + * @brief /oic/sec/amacl (Access Manager Service Accesss Control List) + * data type. + * Derived from OIC Security Spec; see Spec for details. + */ +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 + 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 +}; + +/** + * @brief /oic/sec/cred (Credential) data type. + * Derived from OIC Security Spec; see Spec for details. + */ +struct OicSecCred +{ + // :::: + uint16_t credId; // 0:R:S:Y:UINT16 + OicUuid_t subject; // 1:R:S:Y:oic.uuid + //Note: Need further clarification on roleID data type + //NOTE: Need further clarification on roleId datatype. + //size_t roleIdsLen; // the number of elts in RoleIds + //OicSecRole_t *roleIds; // 2:R:M:N:oic.sec.role + OicSecCredType_t credType; // 3:R:S:Y:oic.sec.credtype + OicSecJwk_t publicData; // 5:R:S:N:oic.sec.jwk + OicSecJwk_t privateData; // 6:R:S:N:oic.sec.jwk + char *period; // 7:R:S: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 + // SRM version only; this will change to Svc type for full implementation. + //OicSecSvc_t *Owners; // 8:R:M:Y:oic.sec.svc + //TODO change Owners type to oic.sec.svc + OicSecCred_t *next; +}; + +/** + * @brief /oic/sec/doxm (Device Owner Transfer Methods) data type + * Derived from OIC Security Spec; see Spec for details. + */ +struct OicSecDoxm +{ + // :::: + OicUrn_t *oxmType; // 0:R:M:N:URN + size_t oxmTypeLen; // the number of elts in OxmType + OicSecOxm_t *oxm; // 1:R:M:N:UINT16 + size_t oxmLen; // the number of elts in Oxm + OicSecOxm_t oxmSel; // 2:R/W:S:Y:UINT16 + bool owned; // 3:R:S:Y:Boolean + //TODO: Need more clarification on deviceIDFormat field type. + //OicSecDvcIdFrmt_t deviceIDFormat; // 4:R:S:Y:UINT8 + OicUuid_t deviceID; // 5:R:S:Y:oic.uuid + OicUuid_t owner; // 6:R:S:Y:oic.uuid + // NOTE: we are using UUID for Owner instead of Svc type for mid-April + // SRM version only; this will change to Svc type for full implementation. + //OicSecSvc_t Owner; // 5:R:S:Y:oic.sec.svc + //TODO change Owner type to oic.sec.svc +}; + +/** + * @brief /oic/sec/pstat (Provisioning Status) data type. + * NOTE: this struct is ahead of Spec v0.95 in definition to include Sm. + * TODO: change comment when reconciled to Spec v0.96. + */ +struct OicSecPstat +{ + // :::: + bool isOp; // 0:R:S:Y:Boolean + OicSecDpm_t cm; // 1:R:S:Y:oic.sec.dpm + OicSecDpm_t tm; // 2:RW:S:Y:oic.sec.dpm + OicUuid_t deviceID; // 3:R:S:Y:oic.uuid + OicSecDpom_t om; // 4:RW:M:Y:oic.sec.dpom + size_t smLen; // the number of elts in Sm + OicSecDpom_t *sm; // 5:R:M:Y:oic.sec.dpom + uint16_t commitHash; // 6:R:S:Y:oic.sec.sha256 + //TODO: this is supposed to be a 256-bit uint; temporarily use uint16_t + //TODO: need to decide which 256 bit and 128 bit types to use... boost? +}; + +/** + * @brief /oic/sec/role (Role) data type. + * Derived from OIC Security Spec; see Spec for details. + */ +struct OicSecRole +{ + // :::: + //TODO fill in with Role definition + uint8_t id[ROLEID_LENGTH]; +}; + +/** + * @brief /oic/sec/sacl (Signed Access Control List) data type. + * Derived from OIC Security Spec; see Spec for details. + */ +struct OicSecSacl +{ + // :::: + //TODO fill in from OIC Security Spec +}; + +/** + * @brief /oic/sec/svc (Service requiring a secure connection) data type. + * Derived from OIC Security Spec; see Spec for details. + */ +struct OicSecSvc +{ + // :::: + //TODO fill in from OIC Security Spec +}; + +#ifdef __cplusplus +} +#endif + +#endif //OC_SECURITY_RESOURCE_TYPES_H diff --git a/resource/csdk/security/include/ocsecurity.h b/resource/csdk/security/include/srmutility.h similarity index 50% rename from resource/csdk/security/include/ocsecurity.h rename to resource/csdk/security/include/srmutility.h index 1d1b3e4..34f3237 100644 --- a/resource/csdk/security/include/ocsecurity.h +++ b/resource/csdk/security/include/srmutility.h @@ -1,6 +1,6 @@ //****************************************************************** // -// Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved. +// Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved. // //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= // @@ -18,33 +18,39 @@ // //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= -#ifndef OC_SECURITY_H -#define OC_SECURITY_H +#ifndef IOTVT_SRM_UTILITY_H +#define IOTVT_SRM_UTILITY_H #include "ocstack.h" -#include "ocsecurityconfig.h" -#include +#include "uthash.h" #ifdef __cplusplus extern "C" { #endif // __cplusplus /** - * Provides the Security Configuration data to OC stack. + * @def VERIFY_SUCCESS + * @brief Macro to verify success of operation. + * eg: VERIFY_SUCCESS(TAG, OC_STACK_OK == foo(), ERROR); + * @note Invoking function must define "exit:" label for goto functionality to work correctly. * - * @param cfgData - * binary blob containing config data - * @param len - * length of binary blob + */ +#define VERIFY_SUCCESS(tag, op, logLevel) { if (!(op)) \ + {OC_LOG((logLevel), tag, PCF(#op " failed!!")); goto exit;} } + +/** + * @def VERIFY_NON_NULL + * @brief Macro to verify argument is not equal to NULL. + * eg: VERIFY_NON_NULL(TAG, ptrData, ERROR); + * @note Invoking function must define "exit:" label for goto functionality to work correctly. * - * @retval OC_STACK_OK for Success, otherwise some error value */ -OCStackResult OCSecSetConfigData(const OCSecConfigData *cfgData, - size_t len); +#define VERIFY_NON_NULL(tag, arg, logLevel) { if (NULL == (arg)) \ + { OC_LOG((logLevel), tag, PCF(#arg " is NULL")); goto exit; } } + #ifdef __cplusplus } #endif // __cplusplus -#endif //OC_SECURITY_H - +#endif //IOTVT_SRM_UTILITY_H diff --git a/resource/csdk/security/provisioning/SConscript b/resource/csdk/security/provisioning/SConscript new file mode 100644 index 0000000..dea14c7 --- /dev/null +++ b/resource/csdk/security/provisioning/SConscript @@ -0,0 +1,87 @@ +# //****************************************************************** +# // +# // 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. +# // +# //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +# + +Import('env') + +provisioning_env = env.Clone() + +###################################################################### +# Build flags +###################################################################### +provisioning_env.AppendUnique(CPPPATH = [ + '../../stack/include', + '../../ocrandom/include', + '../../logger/include', + '../../../oc_logger/include', + '../../ocmalloc/include', + 'include', + 'include/internal', + '../../resource/csdk/security/include', + '../../../../extlibs/cjson/', + '../../../../../extlibs/tinydtlsra/', + '../../connectivity/inc', + '../../connectivity/external/inc', + '../../connectivity/common/inc', + '../../connectivity/api', + '../include', + '../include/internal' + ]) +target_os = env.get('TARGET_OS') +provisioning_env.AppendUnique(CFLAGS = ['-D__WITH_DTLS__']) +provisioning_env.AppendUnique(CFLAGS = ['-std=c99']) +if target_os not in ['windows', 'winrt']: + provisioning_env.AppendUnique(CXXFLAGS = ['-std=c++0x', '-Wall', '-pthread', '-D__WITH_DTLS__']) + + # Note: 'pthread' is in libc for android. On other platform, if use + # new gcc(>4.9?) it isn't required, otherwise, it's required + if target_os != 'android': + provisioning_env.AppendUnique(LIBS = ['-lpthread']) + + +provisioning_env.AppendUnique(LIBPATH = [env.get('BUILD_DIR')]) +provisioning_env.PrependUnique(LIBS = ['oc', 'octbstack', 'oc_logger', 'connectivity_abstraction', 'coap']) + +provisioning_env.AppendUnique(LIBS = ['tinydtls']) + +provisioning_env.ParseConfig('pkg-config --libs glib-2.0'); + +if target_os == 'android': + provisioning_env.AppendUnique(CXXFLAGS = ['-frtti', '-fexceptions']) + provisioning_env.AppendUnique(LIBS = ['gnustl_static']) + + if not env.get('RELEASE'): + provisioning_env.AppendUnique(LIBS = ['log']) + +if target_os in ['darwin', 'ios']: + provisioning_env.AppendUnique(CPPDEFINES = ['_DARWIN_C_SOURCE']) + +###################################################################### +# Source files and Targets +###################################################################### +provisioning_src = [ + 'src/provisioningmanager.c', + 'src/credentialgenerator.c' + ] +provisioningserver = provisioning_env.StaticLibrary('ocspapi', provisioning_src) + +provisioning_env.InstallTarget(provisioningserver, 'libocspapi') + +SConscript('sample/SConscript') diff --git a/resource/csdk/security/provisioning/include/internal/credentialgenerator.h b/resource/csdk/security/provisioning/include/internal/credentialgenerator.h new file mode 100644 index 0000000..259a608 --- /dev/null +++ b/resource/csdk/security/provisioning/include/internal/credentialgenerator.h @@ -0,0 +1,48 @@ +/* ***************************************************************** + * + * 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_CREDENTIAL_GENERATOR_H +#define SP_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] 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 + */ +SPResult SPGeneratePairWiseCredentials(OicSecCredType_t type, const OicUuid_t *ptDeviceId, + const OicUuid_t *firstDeviceId, + const OicUuid_t *secondDeviceId, + OicSecCred_t **firstCred, + OicSecCred_t **secondCred); + +#ifdef __cplusplus +} +#endif +#endif //SP_CREDENTIAL_GENERATOR_H diff --git a/resource/csdk/security/provisioning/include/provisioningmanager.h b/resource/csdk/security/provisioning/include/provisioningmanager.h new file mode 100644 index 0000000..ccf85fa --- /dev/null +++ b/resource/csdk/security/provisioning/include/provisioningmanager.h @@ -0,0 +1,174 @@ +/* ***************************************************************** + * + * 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; + +/** + * Connectivity types. + */ +typedef enum +{ + SP_IPV4 = (1 << 0), + SP_IPV6 = (1 << 1), + SP_CONN_EDR = (1 << 2), + SP_CONN_LE = (1 << 3) +} SPConnectivityType; + +typedef struct SPTargetDeviceInfo SPTargetDeviceInfo_t; +typedef struct SPDevInfo SPDevInfo_t; + +/** + * Device Info structure. + */ +struct SPTargetDeviceInfo +{ + char ip[DEV_ADDR_SIZE_MAX]; /**< IP address in IPv4 dot-decimal notation. **/ + int port; /**< Remote endpoint port. **/ + SPConnectivityType connType; /**< Connectivity type. **/ + OicSecPstat_t *pstat; /**< Pointer to target's pstat resource. **/ + OicSecDoxm_t *doxm; /**< Pointer to target's doxm resource. **/ + SPTargetDeviceInfo_t *next; /**< Next pointer. **/ +}; + +/** + * Owned target device info + */ +struct SPDevInfo +{ + OicUuid_t deviceId; /**< Device ID. **/ + char ip[DEV_ADDR_SIZE_MAX]; /**< IP address in IPv4 dot-decimal notation. **/ + int port; /**< Remote endpoint port. **/ + SPConnectivityType connType; /**< Connectivity type. **/ + 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 new file mode 100755 index 0000000..1152bd9 --- /dev/null +++ b/resource/csdk/security/provisioning/sample/SConscript @@ -0,0 +1,75 @@ +# //****************************************************************** +# // +# // 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. +# // +# //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +# + +Import('env') + +provisioning_env = env.Clone() + +###################################################################### +# Build flags +###################################################################### +provisioning_env.AppendUnique(CPPPATH = [ + '../../../stack/include', + '../../../ocrandom/include', + '../../../logger/include', + '../../../stack/include', + '../../../security/include', + '../../../../oc_logger/include', + '../include', + '../../include', + '../../../../../extlibs/tinydtls', + '../../../../../extlibs/cjson', + '../../../../../extlibs/base64', + '../../../connectivity/inc', + '../../../connectivity/common/inc', + '../../../connectivity/lib/libcoap-4.1.1', + '../../../connectivity/api' + ]) + +provisioning_env.AppendUnique(CFLAGS = ['-D__WITH_DTLS__','-std=c99']) +provisioning_env.AppendUnique(CXXFLAGS = ['-std=c++0x', '-Wall', '-pthread', '-fpermissive']) +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']) + +if env.get('SECURED') == '1': + provisioning_env.AppendUnique(LIBS = ['tinydtls']) +provisioning_env.ParseConfig('pkg-config --libs glib-2.0'); + +provisioning_env.AppendUnique(CPPDEFINES = ['TB_LOG']) + +###################################################################### +# Source files and Targets +###################################################################### + +provisioningclient = provisioning_env.Program('provisioningclient', 'provisioningclient.c') + +Alias("sample", [provisioningclient]) + +provisioning_env.AppendTarget('samples') + +src_dir = provisioning_env.get('SRC_DIR') +sec_provisioning_src_dir = src_dir + '/resource/csdk/security/provisioning/sample/' +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.json')) diff --git a/resource/csdk/security/provisioning/sample/oic_svr_db.json b/resource/csdk/security/provisioning/sample/oic_svr_db.json new file mode 100755 index 0000000..8e92810 --- /dev/null +++ b/resource/csdk/security/provisioning/sample/oic_svr_db.json @@ -0,0 +1,43 @@ +{ + "acl": [ + { + "sub": "Kg==", + "rsrc": [ + "/oic/res", + "/oic/d", + "/oic/p", + "/oic/res/types/d", + "/oic/ad" + ], + "perms": 2, + "ownrs" : ["YWRtaW5EZXZpY2VVVUlE"] + }, + { + "sub": "Kg==", + "rsrc": [ + "/oic/sec/doxm", + "/oic/sec/pstat", + "/oic/sec/acl", + "/oic/sec/cred" + ], + "perms": 7, + "ownrs" : ["YWRtaW5EZXZpY2VVVUlE"] + } + ], + "pstat": { + "isop": true, + "deviceid": "YWRtaW5EZXZpY2VVVUlE", + "commithash": 0, + "cm": 0, + "tm": 0, + "om": 3, + "sm": [3] + }, + "doxm": { + "oxm": [0], + "oxmsel": 0, + "owned": true, + "deviceid": "YWRtaW5EZXZpY2VVVUlE", + "ownr": "YWRtaW5EZXZpY2VVVUlE" + } +} diff --git a/resource/csdk/security/provisioning/sample/provisioningclient.c b/resource/csdk/security/provisioning/sample/provisioningclient.c new file mode 100755 index 0000000..2284155 --- /dev/null +++ b/resource/csdk/security/provisioning/sample/provisioningclient.c @@ -0,0 +1,326 @@ +/****************************************************************** +* +* 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 "logger.h" +#include "oic_malloc.h" +#include "utlist.h" +#include "securevirtualresourcetypes.h" +#include "provisioningmanager.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 TAG "provisioningclient" + +static OicSecAcl_t *gAcl = NULL; +static char CRED_FILE[] = "oic_svr_db.json"; + +/** + * Perform cleanup for ACL list + * + * @param[in] ACL list + */ +static void DeleteACLList(OicSecAcl_t *acl) +{ + if (acl) + { + OicSecAcl_t *aclTmp1 = NULL; + OicSecAcl_t *aclTmp2 = NULL; + LL_FOREACH_SAFE(acl, aclTmp1, aclTmp2) + { + LL_DELETE(acl, aclTmp1); + + /* Clean Resources */ + for (int i = 0; i < aclTmp1->resourcesLen; i++) + { + OICFree(aclTmp1->resources[i]); + } + OICFree(aclTmp1->resources); + + /* Clean Owners */ + OICFree(aclTmp1->owners); + + /* Clean ACL node itself */ + OICFree(aclTmp1); + } + acl = NULL; + } +} + +/** + * Calculate ACL permission from string to bit + * + * @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 + */ +static SPResult CalculateAclPermission(const char *temp_pms, uint16_t *pms) +{ + int i = 0; + + if (NULL == temp_pms || NULL == pms) + { + return SP_RESULT_INVALID_PARAM; + } + *pms = 0; + while (temp_pms[i] != '\0') + { + switch (temp_pms[i]) + { + case 'C': + { + *pms += CREATE; + i++; + break; + } + case 'R': + { + *pms += READ; + i++; + break; + } + case 'U': + { + *pms += UPDATE; + i++; + break; + } + case 'D': + { + *pms += DELETE; + i++; + break; + } + case 'N': + { + *pms += NOTIFY; + i++; + break; + } + case '_': + { + i++; + break; + } + default: + { + return SP_RESULT_INVALID_PARAM; + } + } + } + return SP_RESULT_SUCCESS; +} + +/** + * 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 + */ +static SPResult InputACL(OicSecAcl_t *acl) +{ + int unused __attribute__((unused)); + char temp_id [MAX_INPUT_ID_LENGTH + 4] = {0,}; + char temp_rsc[MAX_URI_LENGTH + 1] = {0,}; + char temp_pms[MAX_PERMISSION_LENGTH + 1] = {0,}; + printf("******************************************************************************\n"); + printf("-Set ACL policy for target device\n"); + printf("******************************************************************************\n"); + //Set Subject. + printf("-URN identifying the subject\n"); + printf("ex) 1111-1111-1111-1111 (16 Numbers except to '-')\n"); + printf("Subject : "); + unused = scanf("%19s", temp_id); + int j = 0; + for (int i = 0; temp_id[i] != '\0'; i++) + { + if (DASH != temp_id[i]) + acl->subject.id[j++] = temp_id[i]; + } + + //Set Resource. + printf("Num. of Resource : "); + unused = 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 *)); + if (NULL == acl->resources) + { + OC_LOG(ERROR, TAG, "Error while memory allocation"); + return SP_RESULT_MEM_ALLOCATION_FAIL; + } + for (int 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)); + if (NULL == acl->resources[i]) + { + OC_LOG(ERROR, TAG, "Error while memory allocation"); + return SP_RESULT_MEM_ALLOCATION_FAIL; + } + strncpy(acl->resources[i], temp_rsc, strlen(temp_rsc)); + acl->resources[i][strlen(temp_rsc)] = '\0'; + } + // Set Permission + do + { + 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); + } + while (SP_RESULT_SUCCESS != CalculateAclPermission(temp_pms, &(acl->permission)) ); + // Set Rowner + printf("Num. of Rowner : "); + unused = 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; + } + for (int i = 0; i < acl->ownersLen; i++) + { + printf("[%d]Rowner : ", i + 1); + unused = scanf("%19s", temp_id); + j = 0; + for (int k = 0; temp_id[k] != '\0'; k++) + { + if (DASH != temp_id[k]) + { + acl->owners[i].id[j++] = temp_id[k]; + } + } + } + return SP_RESULT_SUCCESS; +} + +FILE* client_fopen(const char *path, const char *mode) +{ + (void)path; + return fopen(CRED_FILE, mode); +} + +/** + * Provisioning client sample using ProvisioningAPI on provisioningmanager.c + * To change network type use command line option -w for Wifi and -e for Ethernet + */ +int main(int argc, char **argv) +{ + SPResult res = SP_RESULT_SUCCESS; + SPTargetDeviceInfo_t *pDeviceList = NULL; + gAcl = (OicSecAcl_t *)OICMalloc(sizeof(OicSecAcl_t)); + + // Initialize Persistent Storage for SVR database + OCPersistentStorage ps = {}; + ps.open = client_fopen; + ps.read = fread; + ps.write = fwrite; + ps.close = fclose; + ps.unlink = unlink; + OCRegisterPersistentStorageHandler(&ps); + + if (OCInit(NULL, 0, OC_CLIENT_SERVER) != OC_STACK_OK) + { + OC_LOG(ERROR, TAG, "OCStack init error"); + return 0; + } + + if (NULL == gAcl) + { + OC_LOG(ERROR, TAG, "Error while memory allocation"); + return SP_RESULT_MEM_ALLOCATION_FAIL; + } + + res = SPProvisioningDiscovery(PREDEFINED_TIMEOUT, &pDeviceList); + if (SP_RESULT_SUCCESS == res) + { + while (pDeviceList != NULL) + { + printf("-Provisioning device ID : "); + for (int i = 0; i < MAX_INPUT_ID_LENGTH; i++) + { + if (pDeviceList->doxm->deviceID.id[i] == '\0') + { + break; + } + printf("%c", pDeviceList->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; + } + } + else + { + OC_LOG(ERROR, TAG, "Error while Provisioning Discovery"); + goto error; + } + +error: + DeleteACLList(gAcl); + SPTerminateProvisioning(); + return 0; +} diff --git a/resource/csdk/security/provisioning/src/credentialgenerator.c b/resource/csdk/security/provisioning/src/credentialgenerator.c new file mode 100644 index 0000000..8e96518 --- /dev/null +++ b/resource/csdk/security/provisioning/src/credentialgenerator.c @@ -0,0 +1,76 @@ +/* ***************************************************************** + * + * 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 "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 + +SPResult SPGeneratePairWiseCredentials(OicSecCredType_t type, const OicUuid_t *ptDeviceId, + const OicUuid_t *firstDeviceId, + const OicUuid_t *secondDeviceId, + OicSecCred_t **firstCred, + OicSecCred_t **secondCred) +{ + + if (NULL == ptDeviceId || NULL == firstDeviceId || NULL == secondDeviceId) + { + return SP_RESULT_INVALID_PARAM; + } + uint8_t privData[KEY_LENGTH] = {0,}; + OCFillRandomMem(privData, KEY_LENGTH); + + 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; + } + + // TODO currently owner array is 1. only provisioning tool's id. + OicSecCred_t *tempFirstCred = GenerateCredential(secondDeviceId, type, NULL, base64Buff, 1, + ptDeviceId); + if (NULL == tempFirstCred) + { + OC_LOG(ERROR, TAG, "Error while generating credential."); + return SP_RESULT_INTERNAL_ERROR; + } + // TODO currently owner array is 1. only provisioning tool's id. + OicSecCred_t *tempSecondCred = GenerateCredential(firstDeviceId, type, NULL, base64Buff, 1, + ptDeviceId); + if (NULL == tempSecondCred) + { + DeleteCredList(tempFirstCred); + OC_LOG(ERROR, TAG, "Error while generating credential."); + return SP_RESULT_INTERNAL_ERROR; + } + *firstCred = tempFirstCred; + *secondCred = tempSecondCred; + return SP_RESULT_SUCCESS; +} diff --git a/resource/csdk/security/provisioning/src/provisioningmanager.c b/resource/csdk/security/provisioning/src/provisioningmanager.c new file mode 100644 index 0000000..defe4e6 --- /dev/null +++ b/resource/csdk/security/provisioning/src/provisioningmanager.c @@ -0,0 +1,1592 @@ +/* ***************************************************************** + * + * 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 "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" + +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), + SP_PROV_ACL_STARTED = (0x1 << 16), + SP_PROV_ACL_ERROR = (0x1 << 17), + SP_PROV_ACL_DONE = (0x1 << 18), + SP_UP_HASH_STARTED = (0x1 << 19), + SP_UP_HASH_ERROR = (0x1 << 20), + SP_UP_HASH_DONE = (0x1 << 21), + SP_PROV_CRED_STARTED = (0x1 << 22), + SP_PROV_CRED_ERROR = (0x1 << 23), + SP_PROV_CRED_DONE = (0x1 << 24) + +} SPProvisioningStates; + +#define SP_MAX_BUF_LEN 1024 +#define TAG "SPProvisionAPI" +#define COAP_QUERY "coap://%s:%d%s" +#define COAPS_QUERY "coaps://%s:%d%s" +#define CA_SECURE_PORT 5684 + +void (*handler)(const CARemoteEndpoint_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; + } + } +} + +/** + * Convert SP network types to CA network types, + * + * @param[in] connType connection type. + * @return CA connectivity type corresponding to SP connectivity type. + */ +static CATransportType_t getConnectivity(SPConnectivityType connType) +{ + switch (connType) + { + case SP_IPV4: + { + return CA_IPV4; + } + case SP_IPV6: + { + return CA_IPV6; + } + case SP_CONN_EDR: + { + return CA_EDR; + } + case SP_CONN_LE: + { + return CA_LE; + } + default: + { + return CA_IPV4; + } + } + return CA_IPV4; +} + +/** + * Convert CA network types to SP network types, + * + * @param[in] connType connection type. + * @return SPConnectitivty type corresponding to CATransportType_t. + */ +static SPConnectivityType getConnectivitySP(CATransportType_t connType) +{ + switch (connType) + { + case CA_IPV4: + { + return SP_IPV4; + } + case CA_IPV6: + { + return SP_IPV6; + } + case CA_EDR: + { + return SP_CONN_EDR; + } + case CA_LE: + { + return SP_CONN_LE; + } + default: + { + return SP_IPV4; + } + } + return SP_IPV4; +} + +/** + * 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] uri Request URI. + * @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. + * @param[in] token CA token. + * @param[in] method method to be used for sending rquest. + * @param[in] conntype Connectivity type. + * @return CA_STATUS_OK on success, otherwise error code. + */ +static CAResult_t sendCARequest(CAURI_t uri, char *payload, int payloadLen, + CAToken_t token, CAMethod_t method, SPConnectivityType conntype) +{ + CARemoteEndpoint_t *endpoint = NULL; + CATransportType_t caConnType = getConnectivity(conntype); + if (CA_STATUS_OK != CACreateRemoteEndpoint(uri, caConnType, &endpoint) || !endpoint) + { + OC_LOG(ERROR, TAG, "Failed to create remote endpoint"); + CADestroyRemoteEndpoint(endpoint); + return CA_STATUS_FAILED; + } + // TODO: it can be CA_MSG_NONCONFIRM or CA_MSG_CONFIRM. Pass it as a parameter. + CAMessageType_t msgType = CA_MSG_NONCONFIRM; + CAInfo_t requestData = { 0 }; + requestData.token = token; + requestData.tokenLength = CA_MAX_TOKEN_LEN; + if (payload && '\0' != (*(payload + payloadLen))) + { + OC_LOG(ERROR, TAG, "Payload not properly terminated."); + CADestroyRemoteEndpoint(endpoint); + return CA_STATUS_INVALID_PARAM; + } + requestData.payload = payload; + requestData.type = msgType; + CARequestInfo_t requestInfo = { 0 }; + requestInfo.method = method; + requestInfo.info = requestData; + CAResult_t caResult = CA_STATUS_OK; + caResult = CASendRequest(endpoint, &requestInfo); + if (CA_STATUS_OK != caResult) + { + OC_LOG(ERROR, TAG, "Send Request Error !!"); + } + CADestroyRemoteEndpoint(endpoint); + return caResult; +} + +/** + * addDevice to list. + * + * @param[in] ip IP of target device. + * @param[in] port port of remote server. + * @param[in] connType connectivity type of endpoint. + * @param[in] doxm pointer to doxm instance. + * @return SP_RESULT_SUCCESS for success and errorcode otherwise. + */ +static SPResult addDevice(const char *ip, int port, SPConnectivityType connType, OicSecDoxm_t *doxm) +{ + if (NULL == ip || 0 >= port) + { + 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; + } + + SPStringCopy(ptr->ip, ip, sizeof(ptr->ip)); + ptr->port = port; + ptr->connType = connType; + + ptr->doxm = doxm; + + ptr->next = NULL; + + if (NULL == gStartOfDiscoveredDevices) + { + gStartOfDiscoveredDevices = ptr; + gCurrent = ptr; + } + else + { + gCurrent->next = ptr; + gCurrent = ptr; + } + return SP_RESULT_SUCCESS; +} + +/** + * 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. + */ +static void ProvisionDiscoveryHandler(const CARemoteEndpoint_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"); + return; + } + // temp logic for trimming oc attribute from the json. + // JSONToBin should handle oc attribute. + char *pTempPayload = (char *)OICMalloc(strlen(responseInfo->info.payload)); + if (NULL == pTempPayload) + { + OC_LOG(ERROR, TAG, "Error while Memory allocation."); + gStateManager = gStateManager | SP_DISCOVERY_ERROR; + return; + } + + strcpy(pTempPayload, responseInfo->info.payload + 8); + pTempPayload[strlen(pTempPayload) - 2] = '\0'; + OC_LOG_V(DEBUG, TAG, "Trimmed payload: %s", pTempPayload); + OicSecDoxm_t *ptrDoxm = JSONToDoxmBin(pTempPayload); + + if (NULL == ptrDoxm) + { + OC_LOG(ERROR, TAG, "Error while converting doxm json to binary"); + OICFree(pTempPayload); + gStateManager = gStateManager | SP_DISCOVERY_ERROR; + return; + } + OC_LOG(DEBUG, TAG, "Successfully converted pstat json to bin."); + OICFree(pTempPayload); + + SPConnectivityType connType = getConnectivitySP(object->transportType); + SPResult res = addDevice(object->addressInfo.IP.ipAddress, object->addressInfo.IP.port, + connType, ptrDoxm); + if (SP_RESULT_SUCCESS != res) + { + OC_LOG(ERROR, TAG, "Error while adding data to linkedlist."); + gStateManager = gStateManager | SP_DISCOVERY_ERROR; + DeleteDoxmBinData(ptrDoxm); + return; + } + OC_LOG(INFO, TAG, "Exiting ProvisionDiscoveryHandler."); + gStateManager |= SP_DISCOVERY_DONE; + } + } +} + +/** + * Response handler ownership transfer. + * + * @param[in] object Remote endpoint object + * @param[in] requestInfo Datastructure containing request information. + */ +static void OwnerShipTransferModeHandler(const CARemoteEndpoint_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."); + } + } + } +} + +/** + * Response handler list methods. + * + * @param[in] object Remote endpoint object + * @param[in] requestInfo Datastructure containing request information. + */ +static void ListMethodsHandler(const CARemoteEndpoint_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; + } + + char *pTempPayload = (char *)OICMalloc(strlen(responseInfo->info.payload)); + if (NULL == pTempPayload) + { + OC_LOG(ERROR, TAG, "Error in memory allocation."); + gStateManager |= SP_LIST_METHODS_ERROR; + return; + } + + strcpy(pTempPayload, responseInfo->info.payload + 8); + pTempPayload[strlen(pTempPayload) - 2] = '\0'; + + OicSecPstat_t *pstat = JSONToPstatBin(pTempPayload); + if (NULL == pstat) + { + OC_LOG(ERROR, TAG, "Error while converting json to pstat bin"); + OICFree(pTempPayload); + gStateManager |= SP_LIST_METHODS_ERROR; + return; + } + OICFree(pTempPayload); + DeletePstatBinData(gPstat); + + gPstat = pstat; + gStateManager |= SP_LIST_METHODS_DONE; + + OC_LOG(INFO, TAG, "Exiting ListMethodsHandler."); + } + } + } +} + +/** + * Response handler for update operation mode. + * + * @param[in] object Remote endpoint object + * @param[in] requestInfo Datastructure containing request information. + */ +static void OperationModeUpdateHandler(const CARemoteEndpoint_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."); + } + } + } +} + +/** + * Response handler for ownership transfer. + * + * @param[in] object Remote endpoint object + * @param[in] requestInfo Datastructure containing request information. + */ +static void OwnerShipUpdateHandler(const CARemoteEndpoint_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."); + } + } + } +} + +/** + * Response handler for ACL provisioning. + * + * @param[in] object Remote endpoint object + * @param[in] requestInfo Datastructure containing request information. + */ +static void ACLProvisioningHandler(const CARemoteEndpoint_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; + } + } + } +} + +/** + * Response handler for provisioning finalization. + * + * @param[in] object Remote endpoint object + * @param[in] requestInfo Datastructure containing request information. + */ +static void FinalizeProvisioningHandler(const CARemoteEndpoint_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."); + } + } + } +} + +/** + * Response handler for Credential provisioning. + * + * @param[in] object Remote endpoint object + * @param[in] requestInfo Datastructure containing request information. + */ +static void CredProvisioningHandler(const CARemoteEndpoint_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."); + } + } + } +} + +/** + * Response Handler + * + * @param[in] object Remote endpoint object + * @param[in] responseInfo Datastructure containing response information. + */ +static void SPResponseHandler(const CARemoteEndpoint_t *object, + const CAResponseInfo_t *responseInfo) +{ + if ((NULL != responseInfo) && (NULL != responseInfo->info.token)) + { + handler(object, responseInfo); + } +} + +/** + * Error Handler + * + * @param[in] object Remote endpoint object + * @param[in] errorInfo Datastructure containing error information. + */ +static void SPErrorHandler(const CARemoteEndpoint_t *object, + const CAErrorInfo_t *errorInfo) +{ + OC_LOG(INFO, TAG, "Error Handler."); +} + +/** + * Request Handler + * + * @param[in] object Remote endpoint object + * @param[in] requestInfo Datastructure containing request information. + */ +static void SPRequestHandler(const CARemoteEndpoint_t *object, const CARequestInfo_t *requestInfo) +{ + OC_LOG(INFO, TAG, "Request Handler."); +} + +/** + * 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; + } + res = CAFindResource(DOXM_OWNED_FALSE_MULTICAST_QUERY, gToken, CA_MAX_TOKEN_LEN); + 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 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; + char uri[CA_MAX_URI_LENGTH] = {0}; + size_t uriLen = sizeof(uri); + snprintf(uri, uriLen - 1, COAP_QUERY, deviceInfo->ip, + deviceInfo->port, OIC_RSRC_DOXM_URI); + uri[uriLen - 1] = '\0'; + + 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); + + CAMethod_t method = CA_PUT; + if (CA_STATUS_OK != CAGenerateToken(&gToken, CA_MAX_TOKEN_LEN)) + { + OC_LOG(ERROR, TAG, "Error while generating token"); + OICFree(payload); + return SP_RESULT_INTERNAL_ERROR; + } + handler = &OwnerShipTransferModeHandler; + gStateManager |= SP_UP_OWN_TR_METH_STARTED; + + CAResult_t result = sendCARequest(uri, payload, payloadLen, gToken, method, + deviceInfo->connType); + 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) +{ + char uri[CA_MAX_URI_LENGTH] = {0}; + size_t uriLen = sizeof(uri); + snprintf(uri, uriLen - 1, COAP_QUERY, deviceInfo->ip, + deviceInfo->port, OIC_RSRC_PSTAT_URI); + uri[uriLen - 1] = '\0'; + CAMethod_t method = CA_GET; + if (CA_STATUS_OK != CAGenerateToken(&gToken, CA_MAX_TOKEN_LEN)) + { + OC_LOG(ERROR, TAG, "Error while generating token"); + return SP_RESULT_INTERNAL_ERROR; + } + handler = &ListMethodsHandler; + gStateManager |= SP_LIST_METHODS_STARTED; + CAResult_t result = sendCARequest(uri, NULL, 0, gToken, method, deviceInfo->connType); + 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; + + char uri[CA_MAX_URI_LENGTH] = {0}; + size_t uriLen = sizeof(uri); + snprintf(uri, uriLen - 1, COAP_QUERY, deviceInfo->ip, + deviceInfo->port , OIC_RSRC_PSTAT_URI); + uri[uriLen - 1] = '\0'; + + + 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); + + CAMethod_t method = CA_PUT; + if (CA_STATUS_OK != CAGenerateToken(&gToken, CA_MAX_TOKEN_LEN)) + { + OC_LOG(ERROR, TAG, "Error while generating token"); + if (payloadBuffer) + { + OICFree(payloadBuffer); + } + return SP_RESULT_INTERNAL_ERROR; + } + handler = &OperationModeUpdateHandler; + gStateManager |= SP_UPDATE_OP_MODE_STARTED; + CAResult_t result = sendCARequest(uri, payloadBuffer, payloadLen, gToken, method, + deviceInfo->connType); + 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 SPTargetDeviceInfo_t *deviceInfo) +{ + CAResult_t caresult = CASelectCipherSuite(TLS_ECDH_anon_WITH_AES_128_CBC_SHA); + + if (CA_STATUS_OK != caresult) + { + OC_LOG(ERROR, TAG, "Unable to select cipher suite"); + return SP_RESULT_INTERNAL_ERROR; + } + OC_LOG(INFO, TAG, "Anonymous cipher suite selected. "); + 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."); + + CAAddress_t address = {}; + strncpy(address.IP.ipAddress, deviceInfo->ip, DEV_ADDR_SIZE_MAX); + address.IP.ipAddress[DEV_ADDR_SIZE_MAX - 1] = '\0'; + address.IP.port = CA_SECURE_PORT; + + caresult = CAInitiateHandshake(&address, deviceInfo->connType); + 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) +{ + char uri[CA_MAX_URI_LENGTH] = {0}; + size_t uriLen = sizeof(uri); + snprintf(uri, uriLen - 1, COAPS_QUERY, selectedDeviceInfo->ip, + CA_SECURE_PORT, OIC_RSRC_DOXM_URI); + uri[uriLen - 1] = '\0'; + + 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); + + CAMethod_t method = CA_PUT; + if (CA_STATUS_OK != CAGenerateToken(&gToken, CA_MAX_TOKEN_LEN)) + { + OC_LOG(ERROR, TAG, "Error while generating token"); + OICFree(payloadBuffer); + return SP_RESULT_INTERNAL_ERROR; + + } + handler = &OwnerShipUpdateHandler; + gStateManager |= SP_UPDATE_OWNER_STARTED; + + CAResult_t result = sendCARequest(uri, payloadBuffer, payloadLen, gToken, method, + selectedDeviceInfo->connType); + 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; + CAAddress_t address = {}; + strncpy(address.IP.ipAddress, selectedDeviceInfo->ip, DEV_ADDR_SIZE_MAX); + address.IP.ipAddress[DEV_ADDR_SIZE_MAX - 1] = '\0'; + address.IP.port = CA_SECURE_PORT; + + 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(&address, selectedDeviceInfo->connType, + (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) + { + res = initiateDtlsHandshake(selectedDeviceInfo); + if (SP_RESULT_SUCCESS != res) + { + OC_LOG(ERROR, TAG, "Error while DTLS handshake."); + return SP_RESULT_INTERNAL_ERROR; + } + + res = sendOwnershipInfo(timeout, selectedDeviceInfo); + if (SP_RESULT_SUCCESS != res) + { + OC_LOG(ERROR, TAG, "Error while updating ownership information."); + return SP_RESULT_INTERNAL_ERROR; + } + + saveOwnerPSK(selectedDeviceInfo); + } + return SP_RESULT_SUCCESS; + +} + +/** + * 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; + } + + char uri[CA_MAX_URI_LENGTH] = {0}; + size_t uriLen = sizeof(uri); + snprintf(uri, uriLen - 1, COAPS_QUERY, deviceInfo->ip, + CA_SECURE_PORT, OIC_RSRC_CRED_URI); + uri[uriLen - 1] = '\0'; + + int payloadLen = strlen(credJson); + CAMethod_t method = CA_POST; + if (CA_STATUS_OK != CAGenerateToken(&gToken, CA_MAX_TOKEN_LEN)) + { + OC_LOG(ERROR, TAG, "Error while generating token"); + return SP_RESULT_INTERNAL_ERROR; + } + handler = &CredProvisioningHandler; + gStateManager |= SP_PROV_CRED_STARTED; + CAResult_t result = sendCARequest(uri, credJson, payloadLen, gToken, method, + deviceInfo->connType); + 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); + 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"); + } + + CARegisterHandler(SPRequestHandler, SPResponseHandler, SPErrorHandler); + 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; + 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; + } + + char uri[CA_MAX_URI_LENGTH] = {0}; + size_t uriLen = sizeof(uri); + snprintf(uri, uriLen - 1, COAPS_QUERY, selectedDeviceInfo->ip, + CA_SECURE_PORT, OIC_RSRC_ACL_URI); + uri[uriLen - 1] = '\0'; + + int payloadLen = strlen(aclString); + CAMethod_t method = CA_POST; + if (CA_STATUS_OK != CAGenerateToken(&gToken, CA_MAX_TOKEN_LEN)) + { + OC_LOG(ERROR, TAG, "Error while generating token"); + OICFree(aclString); + return SP_RESULT_INTERNAL_ERROR; + + } + handler = &ACLProvisioningHandler; + gStateManager |= SP_PROV_ACL_STARTED; + + CAResult_t result = sendCARequest(uri, aclString, payloadLen, gToken, method, + selectedDeviceInfo->connType); + 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; + } + char uri[CA_MAX_URI_LENGTH] = {0}; + size_t uriLen = sizeof(uri); + snprintf(uri, uriLen - 1, COAPS_QUERY, selectedDeviceInfo->ip, + CA_SECURE_PORT, OIC_RSRC_PSTAT_URI); + uri[uriLen - 1] = '\0'; + + 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); + + CAMethod_t method = CA_PUT; + if (CA_STATUS_OK != CAGenerateToken(&gToken, CA_MAX_TOKEN_LEN)) + { + OC_LOG(ERROR, TAG, "Error while generating token"); + OICFree(payloadBuffer); + return SP_RESULT_INTERNAL_ERROR; + } + handler = &FinalizeProvisioningHandler; + gStateManager |= SP_UP_HASH_STARTED; + CAResult_t result = sendCARequest(uri, payloadBuffer, payloadLen, gToken, method, + selectedDeviceInfo->connType); + 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; + } + + CAAddress_t address = {}; + strncpy(address.IP.ipAddress, selectedDeviceInfo->ip, DEV_ADDR_SIZE_MAX); + address.IP.ipAddress[DEV_ADDR_SIZE_MAX - 1] = '\0'; + address.IP.port = CA_SECURE_PORT; + + result = CACloseDtlsSession(&address, selectedDeviceInfo->connType); + if (CA_STATUS_OK != result) + { + OC_LOG_V(ERROR, TAG, "DTLS handshake failure."); + } + + CADestroyToken(gToken); + gStateManager = 0; + gPstat = NULL; + return res; +} + +SPResult SPTerminateProvisioning() +{ + deleteList(); + return SP_RESULT_SUCCESS;; +} diff --git a/resource/csdk/security/provisioning/unittest/SConscript b/resource/csdk/security/provisioning/unittest/SConscript new file mode 100644 index 0000000..e6b59ed --- /dev/null +++ b/resource/csdk/security/provisioning/unittest/SConscript @@ -0,0 +1,83 @@ +# //****************************************************************** +# // +# // 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. +# // +# //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +# + +Import('env') +import os +import os.path +sptest_env = env.Clone() + +src_dir = sptest_env.get('SRC_DIR') + +###################################################################### +# Build flags +###################################################################### +sptest_env.PrependUnique(CPPPATH = [ + '../../../connectivity/inc', + '../../../connectivity/api', + '../../include', + '../../../../../extlibs/tinydtls', + '../include/internal', + '../../../logger/include', + '../../../stack/include', + '../../../../oc_logger/include', + '../../../../../extlibs/gtest/gtest-1.7.0/include', + '../include' + ]) +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', + 'ocsrm', + 'octbstack', + 'oc_logger', + 'connectivity_abstraction', + 'coap', + 'gtest', + 'gtest_main']) + +if env.get('SECURED') == '1': + sptest_env.AppendUnique(LIBS = ['tinydtls']) + +if not env.get('RELEASE'): + sptest_env.AppendUnique(CPPDEFINES = ['TB_LOG']) + +###################################################################### +# Source files and Targets +###################################################################### +unittest = sptest_env.Program('unittest', ['provisioningmanager.cpp']) + +Alias("test", [unittest]) + +env.AppendTarget('test') +if env.get('TEST') == '1': + target_os = env.get('TARGET_OS') + if target_os == 'linux': + out_dir = env.get('BUILD_DIR') + result_dir = env.get('BUILD_DIR') + '/test_out/' + if not os.path.isdir(result_dir): + os.makedirs(result_dir) + sptest_env.AppendENVPath('GTEST_OUTPUT', ['xml:'+ result_dir]) + sptest_env.AppendENVPath('LD_LIBRARY_PATH', [out_dir]) + sptest_env.AppendENVPath('LD_LIBRARY_PATH', ['./extlibs/gtest/gtest-1.7.0/lib/.libs']) + ut = sptest_env.Command ('ut', None, out_dir + '/resource/csdk/security/unittest/unittest') + AlwaysBuild ('ut') + diff --git a/resource/csdk/security/provisioning/unittest/provisioningmanager.cpp b/resource/csdk/security/provisioning/unittest/provisioningmanager.cpp new file mode 100644 index 0000000..f38b085 --- /dev/null +++ b/resource/csdk/security/provisioning/unittest/provisioningmanager.cpp @@ -0,0 +1,56 @@ +/* ***************************************************************** + * + * 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; + +TEST(SPProvisioningDiscoveryTest, NullConectivity) +{ + EXPECT_EQ(SP_RESULT_INVALID_PARAM, SPProvisioningDiscovery(0, NULL)); +} + +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/src/aclresource.c b/resource/csdk/security/src/aclresource.c new file mode 100644 index 0000000..679151b --- /dev/null +++ b/resource/csdk/security/src/aclresource.c @@ -0,0 +1,595 @@ +//****************************************************************** +// +// 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 "cJSON.h" +#include "base64.h" +#include "resourcemanager.h" +#include "aclresource.h" +#include "psinterface.h" +#include "utlist.h" +#include "srmresourcestrings.h" +#include "doxmresource.h" +#include "srmutility.h" +#include +#include + +#define TAG PCF("SRM-ACL") + +OicSecAcl_t *gAcl = NULL; +static OCResourceHandle gAclHandle = NULL; + +void DeleteACLList(OicSecAcl_t* acl) +{ + if (acl) + { + OicSecAcl_t *aclTmp1 = NULL, *aclTmp2 = NULL; + LL_FOREACH_SAFE(acl, aclTmp1, aclTmp2) + { + int i = 0; + + LL_DELETE(acl, aclTmp1); + + // Clean Resources + for (i = 0; i < aclTmp1->resourcesLen; i++) + { + OICFree(aclTmp1->resources[i]); + } + OICFree(aclTmp1->resources); + + // Clean Owners + OICFree(aclTmp1->owners); + + // Clean ACL node itself + OICFree(aclTmp1); + } + } +} + +/* + * This internal method converts ACL data into JSON format. + * + * Note: Caller needs to invoke 'free' when finished done using + * return string. + */ +char * BinToAclJSON(const OicSecAcl_t * acl) +{ + cJSON *jsonRoot = NULL; + char *jsonStr = NULL; + + if (acl) + { + jsonRoot = cJSON_CreateObject(); + VERIFY_NON_NULL(TAG, jsonRoot, ERROR); + + cJSON *jsonAclArray = NULL; + cJSON_AddItemToObject (jsonRoot, OIC_JSON_ACL_NAME, jsonAclArray = cJSON_CreateArray()); + VERIFY_NON_NULL(TAG, jsonAclArray, ERROR); + + while(acl) + { + char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(((OicUuid_t*)0)->id)) + 1] = {}; + uint32_t outLen = 0; + size_t inLen = 0; + B64Result b64Ret = B64_OK; + + cJSON *jsonAcl = cJSON_CreateObject(); + + // Subject -- Mandatory + outLen = 0; + if (memcmp(&(acl->subject), &WILDCARD_SUBJECT_ID, sizeof(OicUuid_t)) == 0) + { + inLen = WILDCARD_SUBJECT_ID_LEN; + } + else + { + inLen = sizeof(OicUuid_t); + } + b64Ret = b64Encode(acl->subject.id, inLen, base64Buff, + sizeof(base64Buff), &outLen); + VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR); + cJSON_AddStringToObject(jsonAcl, OIC_JSON_SUBJECT_NAME, base64Buff ); + + // Resources -- Mandatory + cJSON *jsonRsrcArray = NULL; + cJSON_AddItemToObject (jsonAcl, OIC_JSON_RESOURCES_NAME, jsonRsrcArray = cJSON_CreateArray()); + VERIFY_NON_NULL(TAG, jsonRsrcArray, ERROR); + for (int i = 0; i < acl->resourcesLen; i++) + { + cJSON_AddItemToArray (jsonRsrcArray, cJSON_CreateString(acl->resources[i])); + } + + // Permissions -- Mandatory + cJSON_AddNumberToObject (jsonAcl, OIC_JSON_PERMISSION_NAME, acl->permission); + + // Owners -- Mandatory + cJSON *jsonOwnrArray = NULL; + cJSON_AddItemToObject (jsonAcl, OIC_JSON_OWNERS_NAME, jsonOwnrArray = cJSON_CreateArray()); + VERIFY_NON_NULL(TAG, jsonOwnrArray, ERROR); + for (int i = 0; i < acl->ownersLen; i++) + { + outLen = 0; + + b64Ret = b64Encode(acl->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 acl node to Acl Array + cJSON_AddItemToArray(jsonAclArray, jsonAcl); + acl = acl->next; + } + + jsonStr = cJSON_PrintUnformatted(jsonRoot); + } + +exit: + if (jsonRoot) + { + cJSON_Delete(jsonRoot); + } + return jsonStr; +} + +/* + * This internal method converts JSON ACL into binary ACL. + */ +OicSecAcl_t * JSONToAclBin(const char * jsonStr) +{ + OCStackResult ret = OC_STACK_ERROR; + OicSecAcl_t * headAcl = NULL; + OicSecAcl_t * prevAcl = NULL; + cJSON *jsonRoot = NULL; + cJSON *jsonAclArray = NULL; + + VERIFY_NON_NULL(TAG, jsonStr, ERROR); + + jsonRoot = cJSON_Parse(jsonStr); + VERIFY_NON_NULL(TAG, jsonRoot, ERROR); + + jsonAclArray = cJSON_GetObjectItem(jsonRoot, OIC_JSON_ACL_NAME); + VERIFY_NON_NULL(TAG, jsonAclArray, ERROR); + + if (cJSON_Array == jsonAclArray->type) + { + int numAcl = cJSON_GetArraySize(jsonAclArray); + int idx = 0; + + VERIFY_SUCCESS(TAG, numAcl > 0, INFO); + do + { + cJSON *jsonAcl = cJSON_GetArrayItem(jsonAclArray, idx); + VERIFY_NON_NULL(TAG, jsonAcl, ERROR); + + OicSecAcl_t *acl = (OicSecAcl_t*)OICCalloc(1, sizeof(OicSecAcl_t)); + VERIFY_NON_NULL(TAG, acl, ERROR); + + headAcl = (headAcl) ? headAcl : acl; + if (prevAcl) + { + prevAcl->next = acl; + } + + size_t jsonObjLen = 0; + cJSON *jsonObj = NULL; + + unsigned char base64Buff[sizeof(((OicUuid_t*)0)->id)] = {}; + uint32_t outLen = 0; + B64Result b64Ret = B64_OK; + + // Subject -- Mandatory + jsonObj = cJSON_GetObjectItem(jsonAcl, OIC_JSON_SUBJECT_NAME); + 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(acl->subject.id)), ERROR); + memcpy(acl->subject.id, base64Buff, outLen); + + // Resources -- Mandatory + jsonObj = cJSON_GetObjectItem(jsonAcl, OIC_JSON_RESOURCES_NAME); + VERIFY_NON_NULL(TAG, jsonObj, ERROR); + VERIFY_SUCCESS(TAG, cJSON_Array == jsonObj->type, ERROR); + + acl->resourcesLen = cJSON_GetArraySize(jsonObj); + VERIFY_SUCCESS(TAG, acl->resourcesLen > 0, ERROR); + acl->resources = (char**)OICCalloc(acl->resourcesLen, sizeof(char*)); + VERIFY_NON_NULL(TAG, (acl->resources), ERROR); + + int idxx = 0; + do + { + cJSON *jsonRsrc = cJSON_GetArrayItem(jsonObj, idxx); + VERIFY_NON_NULL(TAG, jsonRsrc, ERROR); + + 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); + } while ( ++idxx < acl->resourcesLen); + + // Permissions -- Mandatory + 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; + + // Owners -- Mandatory + jsonObj = cJSON_GetObjectItem(jsonAcl, OIC_JSON_OWNERS_NAME); + VERIFY_NON_NULL(TAG, jsonObj, ERROR); + VERIFY_SUCCESS(TAG, cJSON_Array == jsonObj->type, ERROR); + + acl->ownersLen = cJSON_GetArraySize(jsonObj); + VERIFY_SUCCESS(TAG, acl->ownersLen > 0, ERROR); + acl->owners = (OicUuid_t*)OICCalloc(acl->ownersLen, sizeof(OicUuid_t)); + VERIFY_NON_NULL(TAG, (acl->owners), ERROR); + + 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(acl->owners[idxx].id)), + ERROR); + memcpy(acl->owners[idxx].id, base64Buff, outLen); + } while ( ++idxx < acl->ownersLen); + + prevAcl = acl; + } while( ++idx < numAcl); + } + + ret = OC_STACK_OK; + +exit: + cJSON_Delete(jsonRoot); + if (OC_STACK_OK != ret) + { + DeleteACLList(headAcl); + headAcl = NULL; + } + return headAcl; +} + +static OCEntityHandlerResult HandleACLGetRequest (const OCEntityHandlerRequest * ehRequest) +{ + // Convert ACL data into JSON for transmission + char* jsonStr = BinToAclJSON(gAcl); + + /* + * A device should 'always' have a default ACL. Therefore, + * jsonStr should never be NULL. + */ + 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 HandleACLPostRequest (const OCEntityHandlerRequest * ehRequest) +{ + OCEntityHandlerResult ehRet = OC_EH_ERROR; + + // Convert JSON ACL data into binary. This will also validate the ACL data received. + OicSecAcl_t* newAcl = JSONToAclBin((char *)(ehRequest->reqJSONPayload)); + + if (newAcl) + { + // 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) + { + 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); + } + } + + // 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 ACL resources and + * will handle REST request (GET/PUT/POST/DEL) for them. + */ +OCEntityHandlerResult ACLEntityHandler (OCEntityHandlerFlag flag, + OCEntityHandlerRequest * ehRequest) +{ + OCEntityHandlerResult ehRet = OC_EH_ERROR; + + if (!ehRequest) + { + return ehRet; + } + + if (flag & OC_REQUEST_FLAG) + { + // TODO : Handle PUT and DEL methods + OC_LOG (INFO, TAG, PCF("Flag includes OC_REQUEST_FLAG")); + switch (ehRequest->method) + { + case OC_REST_GET: + ehRet = HandleACLGetRequest(ehRequest); + break; + + case OC_REST_POST: + ehRet = HandleACLPostRequest(ehRequest); + break; + + default: + ehRet = OC_EH_ERROR; + SendSRMResponse(ehRequest, ehRet, NULL); + } + } + + return ehRet; +} + +/* + * This internal method is used to create '/oic/sec/acl' resource. + */ +OCStackResult CreateACLResource() +{ + OCStackResult ret; + + ret = OCCreateResource(&gAclHandle, + OIC_RSRC_TYPE_SEC_ACL, + OIC_MI_DEF, + OIC_RSRC_ACL_URI, + ACLEntityHandler, + OC_OBSERVABLE); + + if (OC_STACK_OK != ret) + { + OC_LOG (FATAL, TAG, PCF("Unable to instantiate ACL resource")); + DeInitACLResource(); + } + return ret; +} + +/* + * This internal method is to retrieve the default ACL. + * If SVR database in persistent storage got corrupted or + * is not available for some reason, a default ACL is created + * which allows user to initiate ACL provisioning again. + */ +OCStackResult GetDefaultACL(OicSecAcl_t** defaultAcl) +{ + OCStackResult ret = OC_STACK_ERROR; + + OicUuid_t ownerId = {}; + + /* + * TODO In future, when new virtual resources will be added in OIC + * specification, Iotivity stack should be able to add them in + * existing SVR database. To support this, we need to add 'versioning' + * mechanism in SVR database. + */ + + const char *rsrcs[] = { + OIC_RSRC_CORE_URI, + OIC_RSRC_CORE_D_URI, + OIC_RSRC_CORE_P_URI, + OIC_RSRC_TYPES_D_URI, + OIC_RSRC_PRESENCE_URI, + OIC_RSRC_ACL_URI, + OIC_RSRC_DOXM_URI, + OIC_RSRC_PSTAT_URI, + }; + + if (!defaultAcl) + { + return OC_STACK_INVALID_PARAM; + } + + OicSecAcl_t *acl = (OicSecAcl_t *)OICCalloc(1, sizeof(OicSecAcl_t)); + VERIFY_NON_NULL(TAG, acl, ERROR); + + // Subject -- Mandatory + memcpy(&(acl->subject), &WILDCARD_SUBJECT_ID, sizeof(acl->subject)); + + // Resources -- Mandatory + acl->resourcesLen = sizeof(rsrcs)/sizeof(rsrcs[0]); + + acl->resources = (char**)OICCalloc(acl->resourcesLen, sizeof(char*)); + VERIFY_NON_NULL(TAG, (acl->resources), ERROR); + + for (int i = 0; i < acl->resourcesLen; i++) + { + 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); + } + + acl->permission = PERMISSION_READ; + acl->periodsLen = 0; + acl->periods = NULL; + acl->recurrences = NULL; + + // Device ID is the owner of this default ACL + ret = GetDoxmDeviceID( &ownerId); + VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, FATAL); + + acl->ownersLen = 1; + acl->owners = (OicUuid_t*)OICMalloc(sizeof(OicUuid_t)); + VERIFY_NON_NULL(TAG, (acl->owners), ERROR); + memcpy(acl->owners, &ownerId, sizeof(OicUuid_t)); + + acl->next = NULL; + + *defaultAcl = acl; + ret = OC_STACK_OK; + +exit: + + if (ret != OC_STACK_OK) + { + DeleteACLList(acl); + acl = NULL; + } + + return ret; +} + +/** + * Initialize ACL resource by loading data from persistent storage. + * + * @retval OC_STACK_OK for Success, otherwise some error value + */ +OCStackResult InitACLResource() +{ + OCStackResult ret = OC_STACK_ERROR; + + // Read ACL resource from PS + char* jsonSVRDatabase = GetSVRDatabase(); + + if (jsonSVRDatabase) + { + // Convert JSON ACL into binary format + gAcl = JSONToAclBin(jsonSVRDatabase); + OICFree(jsonSVRDatabase); + } + /* + * If SVR database in persistent storage got corrupted or + * is not available for some reason, a default ACL is created + * which allows user to initiate ACL provisioning again. + */ + if (!jsonSVRDatabase || !gAcl) + { + GetDefaultACL(&gAcl); + // TODO Needs to update persistent storage + } + VERIFY_NON_NULL(TAG, gAcl, FATAL); + + // Instantiate 'oic.sec.acl' + ret = CreateACLResource(); + +exit: + if (OC_STACK_OK != ret) + { + DeInitACLResource(); + } + return ret; +} + +/** + * Perform cleanup for ACL resources. + * + * @retval none + */ +void DeInitACLResource() +{ + OCDeleteResource(gAclHandle); + gAclHandle = NULL; + + DeleteACLList(gAcl); + gAcl = NULL; +} + +/** + * This method is used by PolicyEngine to retrieve ACL for a Subject. + * + * @param subjectId ID of the subject for which ACL is required. + * @param savePtr is used internally by @ref GetACLResourceData to maintain index between + * successive calls for same subjectId. + * + * @retval reference to @ref OicSecAcl_t if ACL is found, else NULL + * + * @note On the first call to @ref GetACLResourceData, savePtr should point to NULL + */ +const OicSecAcl_t* GetACLResourceData(const OicUuid_t* subjectId, OicSecAcl_t **savePtr) +{ + OicSecAcl_t *acl = NULL; + OicSecAcl_t *begin = NULL; + + if ( NULL == subjectId) + { + return NULL; + } + + /* + * savePtr MUST point to NULL if this is the 'first' call to retrieve ACL for + * subjectID. + */ + if (NULL == *savePtr) + { + begin = gAcl; + } + else + { + /* + * If this is a 'successive' call, search for location pointed by + * savePtr and assign 'begin' to the next ACL after it in the linked + * list and start searching from there. + */ + LL_FOREACH(gAcl, acl) + { + if (acl == *savePtr) + { + begin = acl->next; + } + } + } + + // Find the next ACL corresponding to the 'subjectID' and return it. + LL_FOREACH(begin, acl) + { + if (memcmp(&(acl->subject), subjectId, sizeof(OicUuid_t)) == 0) + { + *savePtr = acl; + return acl; + } + } + + // Cleanup in case no ACL is found + *savePtr = NULL; + return NULL; +} diff --git a/resource/csdk/security/src/base64.c b/resource/csdk/security/src/base64.c new file mode 100644 index 0000000..3b20cf5 --- /dev/null +++ b/resource/csdk/security/src/base64.c @@ -0,0 +1,255 @@ +/****************************************************************** + * + * 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 "base64.h" + +/**< base character of Base64 */ +static const char g_b64TransTbl[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef"\ + "ghijklmnopqrstuvwxyz0123456789+/"; + +/** + * base64 block encode function + * + * @param[in] in octet stream, max 3 byte + * @param[out] out base64 encoded stream, 4 byte + * @param[in] len byte-length of in + * + * @return B64_OK for Success, otherwise some error value + */ +static B64Result b64EncodeBlk(const uint8_t* in, char* out, uint32_t len) +{ + if (NULL == in || NULL == out || 0 == len ) + { + return B64_INVALID_PARAM; + } + + out[0] = g_b64TransTbl[in[0] >> 2]; + + if(1 == len) + { + out[1] = g_b64TransTbl[((in[0] & 0x03) << 4)]; + } + else + { + out[1] = g_b64TransTbl[((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4)]; + } + + if(2 == len) + { + out[2] = g_b64TransTbl[((in[1] & 0x0f) << 2)]; + } + else if (1 < len) + { + out[2] = g_b64TransTbl[((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6)]; + } + else + { + out[2] = '='; + } + + if (2 < len) + { + out[3] = g_b64TransTbl[in[2] & 0x3f]; + } + else + { + out[3] = '='; + } + + return B64_OK; +} + +/** + * Encode the plain message in base64. + * + * @param[in] in Plain message + * @param[in] inLen Byte length of 'in' + * @param[in,out] outBuf Output buffer + * Base64 encoded message will be written into 'out' + * NOTE : This method adds a NULL to the string configuration + * @param[in] outBufSize Size of output buffer + * @param[out] outLen Byte length of encoded message + * + * @return B64_OK for Success, otherwise some error value +*/ +B64Result b64Encode(const uint8_t* in, const size_t inLen, + char* outBuf, const size_t outBufSize, uint32_t* outLen) +{ + uint32_t i; + uint32_t minBufSize; + + if (NULL == in || 0 == inLen || NULL == outBuf || NULL == outLen ) + { + return B64_INVALID_PARAM; + } + + *outLen = ((inLen / 3) * 3 == inLen) ? + ((inLen / 3) * 4) : + (((inLen / 3) + 1) * 4); + minBufSize = (*outLen + 1); + if(outBufSize < minBufSize) + { + return B64_OUTPUT_BUFFER_TOO_SMALL; + } + + for (i = 0; i < inLen / 3; i++) + { + if(B64_OK != b64EncodeBlk(in + i * 3, outBuf + i * 4, 3)) + { + return B64_INVALID_PARAM; + } + } + + if (i * 3 != inLen) + { + if(B64_OK != b64EncodeBlk(in + i * 3, outBuf + i * 4, inLen - i * 3)) + { + return B64_INVALID_PARAM; + } + } + + outBuf[*outLen] = '\0'; + + return B64_OK; +} + +/** + * Get decoded value + * + * @param[in] c Base64 encoded charactor + * + * @return decoded value, 6-bit + */ +static uint32_t b64GetVal(char c) +{ + if (('A' <= c) && ('Z' >= c)) + { + return c - 'A'; + } + else if (('a' <= c) && ('z' >= c)) + { + return c - 'a' + 26; + } + else if (('0' <= c) && ('9' >= c)) + { + return c - '0' + 52; + } + else if ('+' == c) + { + return 62; + } + else if ('/' == c) + { + return 63; + } + else if ('=' == c) + { + return 0; + } + + return 0; +} + +/** + * base64 block decode function + * + * @param[in] in Base64 encoded stream, 4 bytes + * @param[out] out Octet stream, 3 bytes + * + * @return B64_OK for Success, otherwise some error value + */ +static B64Result b64DecodeBlk(const char* in, uint8_t* out) +{ + uint32_t val; + + if(NULL == in || NULL == out) + { + return B64_INVALID_PARAM; + } + + val = (b64GetVal(in[0]) << 18) | (b64GetVal(in[1]) << 12) | + (b64GetVal(in[2]) << 6) | (b64GetVal(in[3])); + + out[0] = (val >> 16) & 0xff; + + if ('=' != in[2]) + { + out[1] = (val >> 8) & 0xff; + } + if ('=' != in[3]) + { + out[2] = val & 0xff; + } + + return B64_OK; +} + +/** + * Decode the encoded message in base64. + * + * @param[in] in Base64 encoded message + * @param[in] inLen Byte lenth of 'in' + * @param[in, out] outBuf Output buffer + * Base64 decoded message will be written into 'out' + * @param[in] outBufSize Size of output buffer + * @param[out] outLen Byte length of decoded message + * + * @return B64_OK for Success, otherwise some error value + */ +B64Result b64Decode(const char* in, const size_t inLen, + uint8_t* outBuf, size_t outBufSize, uint32_t* outLen) +{ + uint32_t i; + uint32_t minBufSize; + + if (NULL == in || 0 == inLen || 0 != (inLen & 0x03) || NULL == outBuf || NULL == outLen) + { + return B64_INVALID_PARAM; + } + + *outLen = (inLen / 4) * 3; + minBufSize = (inLen / 4) * 3; + if('=' == in[inLen - 1]) + { + minBufSize--; + (*outLen)--; + } + if('=' == in[inLen - 2]) + { + minBufSize--; + (*outLen)--; + } + if(outBufSize < minBufSize) + { + return B64_OUTPUT_BUFFER_TOO_SMALL; + } + + for (i = 0; i < inLen / 4; i++) + { + if(B64_OK != b64DecodeBlk(in + i * 4, outBuf + i * 3)) + { + return B64_INVALID_PARAM; + } + } + + return B64_OK; +} + diff --git a/resource/csdk/security/src/credresource.c b/resource/csdk/security/src/credresource.c new file mode 100755 index 0000000..53b286c --- /dev/null +++ b/resource/csdk/security/src/credresource.c @@ -0,0 +1,673 @@ +//****************************************************************** +// +// 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 "resourcemanager.h" +#include "psinterface.h" +#include "utlist.h" +#include "srmresourcestrings.h" +#include "credresource.h" +#include "ocrandom.h" +#include "doxmresource.h" +#include "base64.h" +#include "srmutility.h" +#include "cainterface.h" +#include +#include + +#define TAG PCF("SRM-CREDL") + +static OicSecCred_t *gCred = NULL; +static OCResourceHandle gCredHandle = NULL; + +void DeleteCredList(OicSecCred_t* cred) +{ + if (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 +#if 0 + //Clean roleIds + OICFree(credTmp1->roleIds); +#endif + + //Clean PublicData + OICFree(credTmp1->publicData.data); + + //Clean PrivateData + OICFree(credTmp1->privateData.data); + + //Clean Period + OICFree(credTmp1->period); + + //Clean Owners + OICFree(credTmp1->owners); + + //Clean Cred node itself + OICFree(credTmp1); + } + } +} + +/** + * This function converts credential data into JSON format. + * Caller needs to invoke 'free' when done using + * returned string. + * @param cred pointer to instance of OicSecCred_t structure. + * + * @retval + * pointer to JSON credential representation - if credential for subjectId found + * NULL - if credential for subjectId not found + */ +char * BinToCredJSON(const OicSecCred_t * cred) +{ + cJSON *jsonRoot = NULL; + char *jsonStr = NULL; + + if (cred) + { + char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(((OicUuid_t*)0)->id)) + 1] = {}; + uint32_t outLen = 0; + B64Result b64Ret = B64_OK; + + jsonRoot = cJSON_CreateObject(); + VERIFY_NON_NULL(TAG, jsonRoot, ERROR); + + cJSON *jsonCredArray = NULL; + cJSON_AddItemToObject(jsonRoot, OIC_JSON_CRED_NAME, + jsonCredArray = cJSON_CreateArray()); + VERIFY_NON_NULL(TAG, jsonCredArray, ERROR); + + while(cred) + { + cJSON *jsonCred = cJSON_CreateObject(); + VERIFY_NON_NULL(TAG, jsonCred, ERROR); + + //CredID -- Mandatory + cJSON_AddNumberToObject(jsonCred, OIC_JSON_CREDID_NAME, (int)cred->credId); + + //Subject -- Mandatory + outLen = 0; + memset(base64Buff, 0, sizeof(base64Buff)); + b64Ret = b64Encode(cred->subject.id, sizeof(cred->subject.id), base64Buff, + sizeof(base64Buff), &outLen); + VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR); + cJSON_AddStringToObject(jsonCred, OIC_JSON_SUBJECT_NAME, base64Buff); + + //Note: Need further clarification on roleID data type +#if 0 + //RoleId -- Not Mandatory + if(cred->roleIdsLen > 0) + { + cJSON *jsonRoleIdsArray = NULL; + cJSON_AddItemToObject (jsonCred, OIC_JSON_ROLEIDS_NAME, + jsonRoleIdsArray = cJSON_CreateArray()); + VERIFY_NON_NULL(TAG, jsonRoleIdsArray, ERROR); + for (size_t i = 0; i < cred->roleIdsLen; i++) + { + cJSON_AddItemToArray (jsonRoleIdsArray, + cJSON_CreateString((char *)cred->roleIds[i].id)); + } + } +#endif + + //CredType -- Mandatory + cJSON_AddNumberToObject(jsonCred, OIC_JSON_CREDTYPE_NAME,(int)cred->credType); + +#if 0 + //PublicData -- Not Mandatory + if(cred->publicData.data) + { + cJSON_AddStringToObject(jsonCred, OIC_JSON_PUBLICDATA_NAME, cred->publicData.data); + } +#endif + //PrivateData -- Not Mandatory + if(cred->privateData.data) + { + cJSON_AddStringToObject(jsonCred, OIC_JSON_PRIVATEDATA_NAME, cred->privateData.data); + } + + //Period -- Not Mandatory + if(cred->period) + { + cJSON_AddStringToObject(jsonCred, OIC_JSON_PERIOD_NAME, + cred->period); + } + + //Owners -- Mandatory + cJSON *jsonOwnrArray = NULL; + cJSON_AddItemToObject (jsonCred, OIC_JSON_OWNERS_NAME, + jsonOwnrArray = cJSON_CreateArray()); + VERIFY_NON_NULL(TAG, jsonOwnrArray, ERROR); + for (size_t i = 0; i < cred->ownersLen; i++) + { + outLen = 0; + memset(base64Buff, 0, sizeof(base64Buff)); + b64Ret = b64Encode(cred->owners[i].id, sizeof(cred->owners[i].id), + base64Buff, sizeof(base64Buff), &outLen); + VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR); + cJSON_AddItemToArray (jsonOwnrArray, + cJSON_CreateString((char *)(base64Buff))); + } + + /* Attach current cred node to cred Array */ + cJSON_AddItemToArray(jsonCredArray, jsonCred); + cred = cred->next; + } + + jsonStr = cJSON_PrintUnformatted(jsonRoot); + } + +exit: + if (jsonRoot) + { + cJSON_Delete(jsonRoot); + } + return jsonStr; +} + +/* + * This internal method converts JSON cred into binary cred. + */ +OicSecCred_t * JSONToCredBin(const char * jsonStr) +{ + OCStackResult ret = OC_STACK_ERROR; + OicSecCred_t * headCred = NULL; + OicSecCred_t * prevCred = NULL; + cJSON *jsonCredArray = NULL; + + cJSON *jsonRoot = cJSON_Parse(jsonStr); + VERIFY_NON_NULL(TAG, jsonRoot, ERROR); + + jsonCredArray = cJSON_GetObjectItem(jsonRoot, OIC_JSON_CRED_NAME); + VERIFY_NON_NULL(TAG, jsonCredArray, ERROR); + if (cJSON_Array == jsonCredArray->type) + { + int numCred = cJSON_GetArraySize(jsonCredArray); + int idx = 0; + + unsigned char base64Buff[sizeof(((OicUuid_t*)0)->id)] = {}; + uint32_t outLen = 0; + B64Result b64Ret = B64_OK; + + VERIFY_SUCCESS(TAG, numCred > 0, ERROR); + do + { + cJSON *jsonCred = cJSON_GetArrayItem(jsonCredArray, idx); + VERIFY_NON_NULL(TAG, jsonCred, ERROR); + + OicSecCred_t *cred = (OicSecCred_t*)OICCalloc(1, sizeof(OicSecCred_t)); + VERIFY_NON_NULL(TAG, cred, ERROR); + + headCred = (headCred) ? headCred : cred; + if (prevCred) + { + prevCred->next = cred; + } + size_t jsonObjLen = 0; + cJSON *jsonObj = NULL; + + //CredId -- Mandatory + jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_CREDID_NAME); + VERIFY_NON_NULL(TAG, jsonObj, ERROR); + VERIFY_SUCCESS(TAG, cJSON_Number == jsonObj->type, ERROR) + cred->credId = jsonObj->valueint; + + //subject -- Mandatory + jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_SUBJECT_NAME); + VERIFY_NON_NULL(TAG, jsonObj, ERROR); + VERIFY_SUCCESS(TAG, cJSON_String == jsonObj->type, ERROR) + outLen = 0; + memset(base64Buff, 0, sizeof(base64Buff)); + b64Ret = b64Decode(jsonObj->valuestring, strlen(jsonObj->valuestring), + base64Buff, sizeof(base64Buff), &outLen); + VERIFY_SUCCESS(TAG, (b64Ret == B64_OK && outLen <= sizeof(cred->subject.id)), + ERROR); + memcpy(cred->subject.id, base64Buff, outLen); + + //CredType -- Mandatory + jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_CREDTYPE_NAME); + VERIFY_NON_NULL(TAG, jsonObj, ERROR); + VERIFY_SUCCESS(TAG, cJSON_Number == jsonObj->type, ERROR) + cred->credType = jsonObj->valueint; + + //PrivateData is mandatory for some of the credential types listed below. + jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_PRIVATEDATA_NAME); + if ((cred->credType & SYMMETRIC_PAIR_WISE_KEY) || + (cred->credType & SYMMETRIC_GROUP_KEY) || + (cred->credType & PIN_PASSWORD)) + { + VERIFY_NON_NULL(TAG, jsonObj, ERROR); + VERIFY_SUCCESS(TAG, cJSON_String == jsonObj->type, ERROR); + } + if(jsonObj && cJSON_String == jsonObj->type) + { + jsonObjLen = strlen(jsonObj->valuestring) + 1; + cred->privateData.data = (char *)OICMalloc(jsonObjLen); + VERIFY_NON_NULL(TAG, (cred->privateData.data), ERROR); + strncpy((char *)cred->privateData.data, (char *)jsonObj->valuestring, jsonObjLen); + } + + //Period -- Not Mandatory + jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_PERIOD_NAME); + if(jsonObj && cJSON_String == jsonObj->type) + { + jsonObjLen = strlen(jsonObj->valuestring) + 1; + cred->period = (char *)OICMalloc(jsonObjLen); + VERIFY_NON_NULL(TAG, cred->period, ERROR); + strncpy(cred->period, jsonObj->valuestring, jsonObjLen); + } + + //Owners -- Mandatory + jsonObj = cJSON_GetObjectItem(jsonCred, OIC_JSON_OWNERS_NAME); + VERIFY_NON_NULL(TAG, jsonObj, 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)); + VERIFY_NON_NULL(TAG, (cred->owners), ERROR); + for(size_t i = 0; i < cred->ownersLen; i++) + { + cJSON *jsonOwnr = cJSON_GetArrayItem(jsonObj, i); + VERIFY_NON_NULL(TAG, jsonOwnr, ERROR); + VERIFY_SUCCESS(TAG, cJSON_String == jsonOwnr->type, ERROR); + outLen = 0; + memset(base64Buff, 0, sizeof(base64Buff)); + b64Ret = b64Decode(jsonOwnr->valuestring, strlen(jsonOwnr->valuestring), + base64Buff, sizeof(base64Buff), &outLen); + VERIFY_SUCCESS(TAG, (b64Ret == B64_OK && + outLen <= sizeof(cred->owners[i].id)), ERROR); + memcpy(cred->owners[i].id, base64Buff, outLen); + } + prevCred = cred; + } while( ++idx < numCred); + } + + ret = OC_STACK_OK; + +exit: + cJSON_Delete(jsonRoot); + if (OC_STACK_OK != ret) + { + DeleteCredList(headCred); + headCred = NULL; + } + return headCred; +} + +/** + * This function generates the bin credential data. + * + * @param subject pointer to subject of this credential. + * @param credType credential type. + * @param publicData public data such as public key. + * @param privateData private data such as private key. + * @param ownersLen length of owners array + * @param owners array of owners. + * + * @retval + * pointer to instance of OicSecCred_t - success + * NULL - error + */ +OicSecCred_t * GenerateCredential(const OicUuid_t * subject, OicSecCredType_t credType, + const char * publicData, const char * privateData, + size_t ownersLen, const OicUuid_t * owners) +{ + OCStackResult ret = OC_STACK_ERROR; + + OicSecCred_t *cred = (OicSecCred_t*)OICCalloc(1, sizeof(OicSecCred_t)); + VERIFY_NON_NULL(TAG, cred, ERROR); + + //TODO:Need more clarification on credId + OCFillRandomMem((uint8_t*)&cred->credId, sizeof(cred->credId)); + + VERIFY_NON_NULL(TAG, subject, ERROR); + memcpy(cred->subject.id, subject->id , sizeof(cred->subject.id)); + + //TODO: check credType has one of the values {0, 1, 2, 4, 6, 8, 16} + cred->credType = credType; + +#if 0 + if(publicData) + { + cred->publicData.data = (char *)OICMalloc(strlen(publicData)+1); + VERIFY_NON_NULL(TAG, cred->publicData.data, ERROR); + strncpy((char *)cred->publicData.data, publicData, strlen(publicData)+1); + } +#endif + + if(privateData) + { + cred->privateData.data = (char *)OICMalloc(strlen(privateData)+1); + VERIFY_NON_NULL(TAG, cred->privateData.data, ERROR); + strncpy((char *)cred->privateData.data, privateData, strlen(privateData)+1); + } + + VERIFY_SUCCESS(TAG, ownersLen > 0, ERROR); + cred->ownersLen = ownersLen; + + cred->owners = (OicUuid_t*)OICCalloc(cred->ownersLen, sizeof(OicUuid_t)); + VERIFY_NON_NULL(TAG, cred->owners, ERROR); + for(size_t i = 0; i < cred->ownersLen; i++) + { + memcpy(cred->owners[i].id, owners[i].id, sizeof(cred->owners[i].id)); + } + + ret = OC_STACK_OK; +exit: + if (OC_STACK_OK != ret) + { + DeleteCredList(cred); + cred = NULL; + } + return cred; +} + +/** + * This function adds the new cred to the credential list. + * + * @param cred pointer to new credential. + * + * @retval + * OC_STACK_OK - cred not NULL and persistent storage gets updated + * OC_STACK_ERROR - cred is NULL or fails to update persistent storage + */ +OCStackResult AddCredential(OicSecCred_t * newCred) +{ + OCStackResult ret = OC_STACK_ERROR; + + if(NULL == newCred) + { + return OC_STACK_ERROR; + } + + //Append the new Cred to existing list + LL_APPEND(gCred, newCred); + + //Convert CredList to JSON and update the persistent Storage + char * jsonStr = BinToCredJSON(gCred); + + if(jsonStr) + { + cJSON *jsonCred = cJSON_Parse(jsonStr); + OICFree(jsonStr); + + if((jsonCred) && (OC_STACK_OK == UpdateSVRDatabase(OIC_JSON_CRED_NAME, jsonCred))) + { + ret = OC_STACK_OK; + } + cJSON_Delete(jsonCred); + } + + return ret; +} + +static OCEntityHandlerResult HandlePostRequest(const OCEntityHandlerRequest * ehRequest) +{ + OCEntityHandlerResult ret = OC_EH_ERROR; + + //Get binary representation of json + OicSecCred_t * cred = JSONToCredBin((char *)ehRequest->reqJSONPayload); + + if(cred) + { + //Append the new Cred to existing list + ret = (OC_STACK_OK == AddCredential(cred))? OC_EH_RESOURCE_CREATED : OC_EH_ERROR; + } + + return ret; +} + +/* + * This internal method is the entity handler for Cred resources + * to handle REST request (PUT/POST/DEL) + */ +OCEntityHandlerResult CredEntityHandler (OCEntityHandlerFlag flag, + OCEntityHandlerRequest * ehRequest) +{ + OCEntityHandlerResult ret = OC_EH_ERROR; + + if(!ehRequest) + { + return OC_EH_ERROR; + } + if (flag & OC_REQUEST_FLAG) + { + OC_LOG (INFO, TAG, PCF("Flag includes OC_REQUEST_FLAG")); + //TODO : Handle PUT/DEL methods + switch(ehRequest->method) + { + case OC_REST_GET: + ret = OC_EH_FORBIDDEN; + break; + case OC_REST_POST: + ret = HandlePostRequest(ehRequest); + break; + default: + ret = OC_EH_ERROR; + break; + } + } + + //Send payload to request originator + ret = (SendSRMResponse(ehRequest, ret, NULL) == OC_STACK_OK ? + ret : OC_EH_ERROR); + + return ret; +} + +/* + * This internal method is used to create '/oic/sec/Cred' resource. + */ +OCStackResult CreateCredResource() +{ + OCStackResult ret; + + ret = OCCreateResource(&gCredHandle, + OIC_RSRC_TYPE_SEC_CRED, + OIC_MI_DEF, + OIC_RSRC_CRED_URI, + CredEntityHandler, + OC_RES_PROP_NONE); + + if (OC_STACK_OK != ret) + { + OC_LOG (FATAL, TAG, PCF("Unable to instantiate Cred resource")); + DeInitCredResource(); + } + return ret; +} + +/** + * Get the default value + * @retval NULL for now. Update it when we finalize the default info. + */ +static OicSecCred_t* GetCredDefault() +{ + return NULL; +} + +/** + * Initialize Cred resource by loading data from persistent storage. + * + * @retval + * OC_STACK_OK - no errors + * OC_STACK_ERROR - stack process error + */ +OCStackResult InitCredResource() +{ + OCStackResult ret = OC_STACK_ERROR; + + //Read Cred resource from PS + char* jsonSVRDatabase = GetSVRDatabase(); + + if (jsonSVRDatabase) + { + //Convert JSON Cred into binary format + gCred = JSONToCredBin(jsonSVRDatabase); + } + /* + * If SVR database in persistent storage got corrupted or + * is not available for some reason, a default Cred is created + * which allows user to initiate Cred provisioning again. + */ + if (!jsonSVRDatabase || !gCred) + { + gCred = GetCredDefault(); + } + //Instantiate 'oic.sec.cred' + ret = CreateCredResource(); + OICFree(jsonSVRDatabase); + return ret; +} + +/** + * Perform cleanup for Cred resources. + * + * @return + * OC_STACK_OK - no errors + * OC_STACK_ERROR - stack process error + * OC_STACK_NO_RESOURCE - resource not found + * OC_STACK_INVALID_PARAM - invalid param + */ +OCStackResult DeInitCredResource() +{ + OCStackResult result = OCDeleteResource(gCredHandle); + DeleteCredList(gCred); + gCred = NULL; + return result; +} + +/** + * This method is used by tinydtls/SRM to retrieve credential for given Subject. + * + * @param subject - subject for which credential is required. + * + * @retval + * reference to OicSecCred_t - if credential is found + * NULL - if credential not found + */ +const OicSecCred_t* GetCredResourceData(const OicUuid_t* subject) +{ + OicSecCred_t *cred = NULL; + + if ( NULL == subject) + { + return NULL; + } + + LL_FOREACH(gCred, cred) + { + if(memcmp(cred->subject.id, subject->id, sizeof(subject->id)) == 0) + { + return cred; + } + } + return NULL; +} + + +#if defined(__WITH_DTLS__) +/** + * This internal callback is used by lower stack (i.e. CA layer) to + * retrieve PSK credentials from RI security layer. + * + * Note: When finished, caller should initialize memory to zeros and + * invoke OICFree to delete @p credInfo. + * + * @param credInfo + * binary blob containing PSK credentials + * + * @retval none + */ +void GetDtlsPskCredentials(CADtlsPskCredsBlob_t **credInfo) +{ + CADtlsPskCredsBlob_t * caBlob = NULL; + if(credInfo) + { + caBlob = (CADtlsPskCredsBlob_t *)OICCalloc(sizeof(CADtlsPskCredsBlob_t), 1); + if (caBlob) + { + OicUuid_t deviceID = {}; + + // Retrieve Device ID from doxm resource and copy in PSK creds blob + VERIFY_SUCCESS(TAG, GetDoxmDeviceID(&deviceID) == OC_STACK_OK, ERROR); + memcpy(caBlob->identity, deviceID.id, sizeof(caBlob->identity)); + + OicSecCred_t *cred = NULL; + size_t count = 0; + LL_FOREACH(gCred, cred) + { + // Currently, Iotivity supports only symmetric pair wise key credentials + if (cred->credType == SYMMETRIC_PAIR_WISE_KEY) + { + ++count; + } + } + caBlob->num = count; + if (caBlob->num) + { + caBlob->creds = + (OCDtlsPskCreds*) OICMalloc(caBlob->num * sizeof(OCDtlsPskCreds)); + VERIFY_NON_NULL(TAG, caBlob->creds, ERROR); + + unsigned int i = 0; + LL_FOREACH(gCred, cred) + { + if ((cred->credType == SYMMETRIC_PAIR_WISE_KEY) && + (i < count)) + + { + // Copy subject ID + memcpy(caBlob->creds[i].id, cred->subject.id, + sizeof(caBlob->creds[i].id)); + + // Convert PSK from JSON to binary before copying + uint32_t outLen = 0; + B64Result b64Ret = b64Decode(cred->privateData.data, + strlen(cred->privateData.data), caBlob->creds[i].psk, + sizeof(caBlob->creds[i].psk), &outLen); + VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR); + i++; + } + } + } + } + *credInfo = caBlob; + // Return from here after making the credential list + return; + } + +exit: + if (caBlob) + { + memset(caBlob->creds, 0, caBlob->num * sizeof(OCDtlsPskCreds)); + OICFree(caBlob->creds); + } + OICFree(caBlob); +} +#endif /* __WITH_DTLS__ */ diff --git a/resource/csdk/security/src/doxmresource.c b/resource/csdk/security/src/doxmresource.c new file mode 100755 index 0000000..eb6df1b --- /dev/null +++ b/resource/csdk/security/src/doxmresource.c @@ -0,0 +1,654 @@ +//****************************************************************** +// +// 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 "resourcemanager.h" +#include "doxmresource.h" +#include "psinterface.h" +#include "utlist.h" +#include "srmresourcestrings.h" +#include "securevirtualresourcetypes.h" +#include "base64.h" +#include "ocrandom.h" +#include "cainterface.h" +#include "credresource.h" +#include "ocserverrequest.h" +#include "srmutility.h" +#include "uthash.h" +#include +#include + +#define TAG PCF("SRM-DOXM") + +static OicSecDoxm_t *gDoxm = NULL; +static OCResourceHandle gDoxmHandle = NULL; + +static OicSecOxm_t gOicSecDoxmJustWorks = OIC_JUST_WORKS; +static OicSecDoxm_t gDefaultDoxm = +{ + NULL, /* OicUrn_t *oxmType */ + 0, /* size_t oxmTypeLen */ + &gOicSecDoxmJustWorks, /* uint16_t *oxm */ + 1, /* size_t oxmLen */ + OIC_JUST_WORKS, /* uint16_t oxmSel */ + false, /* bool owned */ + {}, /* OicUuid_t deviceID */ + {}, /* OicUuid_t owner */ +}; + +void DeleteDoxmBinData(OicSecDoxm_t* doxm) +{ + if (doxm) + { + //Clean oxmType + for(int i = 0; i < doxm->oxmTypeLen; i++) + { + OICFree(doxm->oxmType[i]); + } + OICFree(doxm->oxmType); + + //clean oxm + OICFree(doxm->oxm); + + //Clean doxm itself + OICFree(doxm); + } +} + +char * BinToDoxmJSON(const OicSecDoxm_t * doxm) +{ + if (NULL == doxm) + { + return NULL; + } + + char *jsonStr = NULL; + cJSON *jsonDoxm = NULL; + char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(((OicUuid_t*)0)->id)) + 1] = {}; + uint32_t outLen = 0; + B64Result b64Ret = B64_OK; + + cJSON *jsonRoot = cJSON_CreateObject(); + VERIFY_NON_NULL(TAG, jsonRoot, ERROR); + + jsonDoxm = cJSON_CreateObject(); + VERIFY_NON_NULL(TAG, jsonDoxm, ERROR); + cJSON_AddItemToObject(jsonRoot, OIC_JSON_DOXM_NAME, jsonDoxm ); + + //OxmType -- Not Mandatory + if(doxm->oxmTypeLen > 0) + { + cJSON *jsonOxmTyArray = cJSON_CreateArray(); + VERIFY_NON_NULL(TAG, jsonOxmTyArray, ERROR); + cJSON_AddItemToObject (jsonDoxm, OIC_JSON_OXM_TYPE_NAME, jsonOxmTyArray ); + for (size_t i = 0; i < doxm->oxmTypeLen; i++) + { + cJSON_AddItemToArray (jsonOxmTyArray, cJSON_CreateString(doxm->oxmType[i])); + } + } + + //Oxm -- Not Mandatory + if(doxm->oxmLen > 0) + { + cJSON *jsonOxmArray = cJSON_CreateArray(); + VERIFY_NON_NULL(TAG, jsonOxmArray, ERROR); + cJSON_AddItemToObject (jsonDoxm, OIC_JSON_OXM_NAME,jsonOxmArray ); + for (size_t i = 0; i < doxm->oxmLen; i++) + { + cJSON_AddItemToArray (jsonOxmArray, cJSON_CreateNumber(doxm->oxm[i])); + } + } + + //OxmSel -- Mandatory + cJSON_AddNumberToObject(jsonDoxm, OIC_JSON_OXM_SEL_NAME, (int)doxm->oxmSel); + + //Owned -- Mandatory + cJSON_AddBoolToObject(jsonDoxm, OIC_JSON_OWNED_NAME, doxm->owned); + + //TODO: Need more clarification on deviceIDFormat field type. +#if 0 + //DeviceIdFormat -- Mandatory + cJSON_AddNumberToObject(jsonDoxm, OIC_JSON_DEVICE_ID_FORMAT_NAME, doxm->deviceIDFormat); +#endif + + //DeviceId -- Mandatory + outLen = 0; + b64Ret = b64Encode(doxm->deviceID.id, sizeof(doxm->deviceID.id), base64Buff, + sizeof(base64Buff), &outLen); + VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR); + cJSON_AddStringToObject(jsonDoxm, OIC_JSON_DEVICE_ID_NAME, base64Buff); + + //Owner -- Mandatory + outLen = 0; + b64Ret = b64Encode(doxm->owner.id, sizeof(doxm->owner.id), base64Buff, + sizeof(base64Buff), &outLen); + VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR); + cJSON_AddStringToObject(jsonDoxm, OIC_JSON_OWNER_NAME, base64Buff); + + jsonStr = cJSON_PrintUnformatted(jsonRoot); + +exit: + if (jsonRoot) + { + cJSON_Delete(jsonRoot); + } + return jsonStr; +} + +OicSecDoxm_t * JSONToDoxmBin(const char * jsonStr) +{ + + if (NULL == jsonStr) + { + return NULL; + } + + OCStackResult ret = OC_STACK_ERROR; + OicSecDoxm_t *doxm = NULL; + cJSON *jsonDoxm = NULL; + cJSON *jsonObj = NULL; + + size_t jsonObjLen = 0; + unsigned char base64Buff[sizeof(((OicUuid_t*)0)->id)] = {}; + uint32_t outLen = 0; + B64Result b64Ret = B64_OK; + + cJSON *jsonRoot = cJSON_Parse(jsonStr); + VERIFY_NON_NULL(TAG, jsonRoot, ERROR); + + jsonDoxm = cJSON_GetObjectItem(jsonRoot, OIC_JSON_DOXM_NAME); + VERIFY_NON_NULL(TAG, jsonDoxm, ERROR); + + doxm = (OicSecDoxm_t*)OICCalloc(1, sizeof(OicSecDoxm_t)); + VERIFY_NON_NULL(TAG, doxm, ERROR); + + //OxmType -- not Mandatory + jsonObj = cJSON_GetObjectItem(jsonDoxm, OIC_JSON_OXM_TYPE_NAME); + if ((jsonObj) && (cJSON_Array == jsonObj->type)) + { + doxm->oxmTypeLen = cJSON_GetArraySize(jsonObj); + VERIFY_SUCCESS(TAG, doxm->oxmTypeLen > 0, ERROR); + + doxm->oxmType = (OicUrn_t *)OICCalloc(doxm->oxmTypeLen, sizeof(char *)); + VERIFY_NON_NULL(TAG, (doxm->oxmType), ERROR); + + for(int i = 0; i < doxm->oxmTypeLen ; i++) + { + cJSON *jsonOxmTy = cJSON_GetArrayItem(jsonObj, i); + VERIFY_NON_NULL(TAG, jsonOxmTy, ERROR); + + jsonObjLen = strlen(jsonOxmTy->valuestring) + 1; + doxm->oxmType[i] = (char*)OICMalloc(jsonObjLen); + VERIFY_NON_NULL(TAG, doxm->oxmType[i], ERROR); + strncpy((char *)doxm->oxmType[i], (char *)jsonOxmTy->valuestring, jsonObjLen); + } + } + + //Oxm -- not Mandatory + jsonObj = cJSON_GetObjectItem(jsonDoxm, OIC_JSON_OXM_NAME); + if (jsonObj && cJSON_Array == jsonObj->type) + { + doxm->oxmLen = cJSON_GetArraySize(jsonObj); + VERIFY_SUCCESS(TAG, doxm->oxmLen > 0, ERROR); + + doxm->oxm = (OicSecOxm_t*)OICCalloc(doxm->oxmLen, sizeof(short)); + VERIFY_NON_NULL(TAG, doxm->oxm, ERROR); + + for(int i = 0; i < doxm->oxmLen ; i++) + { + cJSON *jsonOxm = cJSON_GetArrayItem(jsonObj, i); + VERIFY_NON_NULL(TAG, jsonOxm, ERROR); + doxm->oxm[i] = (OicSecOxm_t)jsonOxm->valueint; + } + } + + //OxmSel -- Mandatory + jsonObj = cJSON_GetObjectItem(jsonDoxm, OIC_JSON_OXM_SEL_NAME); + if(jsonObj) + { + 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 + { + VERIFY_NON_NULL(TAG, gDoxm, ERROR); + doxm->oxmSel = gDoxm->oxmSel; + } + + //Owned -- Mandatory + jsonObj = cJSON_GetObjectItem(jsonDoxm, OIC_JSON_OWNED_NAME); + if(jsonObj) + { + 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 + { + VERIFY_NON_NULL(TAG, gDoxm, ERROR); + doxm->owned = gDoxm->owned; + } + + //DeviceId -- Mandatory + jsonObj = cJSON_GetObjectItem(jsonDoxm, OIC_JSON_DEVICE_ID_NAME); + if(jsonObj) + { + VERIFY_SUCCESS(TAG, cJSON_String == jsonObj->type, ERROR); + if(jsonObj && cJSON_String == jsonObj->type) + { + //Check for empty string, in case DeviceId field has not been set yet + if (jsonObj->valuestring[0]) + { + outLen = 0; + b64Ret = b64Decode(jsonObj->valuestring, strlen(jsonObj->valuestring), base64Buff, + sizeof(base64Buff), &outLen); + VERIFY_SUCCESS(TAG, (b64Ret == B64_OK && outLen <= sizeof(doxm->deviceID.id)), + ERROR); + memcpy(doxm->deviceID.id, base64Buff, outLen); + } + } + } + else // PUT/POST JSON will not have deviceID so set it to the gDoxm->deviceID.id + { + VERIFY_NON_NULL(TAG, gDoxm, ERROR); + VERIFY_SUCCESS(TAG, strcmp((char *)gDoxm->deviceID.id, "") != 0, ERROR); + 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) + { + jsonObj = cJSON_GetObjectItem(jsonDoxm, OIC_JSON_OWNER_NAME); + 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(doxm->owner.id)), ERROR); + memcpy(doxm->owner.id, base64Buff, outLen); + } + + ret = OC_STACK_OK; + +exit: + cJSON_Delete(jsonRoot); + if (OC_STACK_OK != ret) + { + DeleteDoxmBinData(doxm); + doxm = NULL; + } + + return doxm; +} + +static bool UpdatePersistentStorage(OicSecDoxm_t * doxm) +{ + bool bRet = false; + + if (NULL != doxm) + { + // Convert Doxm data into JSON for update to persistent storage + char *jsonStr = BinToDoxmJSON(doxm); + if (jsonStr) + { + cJSON *jsonDoxm = cJSON_Parse(jsonStr); + OICFree(jsonStr); + + if (jsonDoxm && + (OC_STACK_OK == UpdateSVRDatabase(OIC_JSON_DOXM_NAME, jsonDoxm))) + { + bRet = true; + } + cJSON_Delete(jsonDoxm); + } + } + + return bRet; +} + +static OCEntityHandlerResult HandleDoxmGetRequest (const OCEntityHandlerRequest * ehRequest) +{ + // Convert Doxm data into JSON for transmission + char* jsonStr = BinToDoxmJSON(gDoxm); + + /* + * A device should 'always' have a default Doxm. Therefore, + * jsonStr should never be NULL. + */ + OCEntityHandlerResult ehRet = (jsonStr ? OC_EH_OK : OC_EH_ERROR); + + // Send response payload to request originator + if(OC_STACK_OK != SendSRMResponse(ehRequest, ehRet, jsonStr)) + { + OC_LOG (ERROR, TAG, PCF("SendSRMResponse failed in HandlePstatGetRequest")); + } + + OICFree(jsonStr); + + return ehRet; +} + + +static OCEntityHandlerResult HandleDoxmPutRequest (const OCEntityHandlerRequest * ehRequest) +{ + OCEntityHandlerResult ehRet = OC_EH_ERROR; + OicUuid_t emptyOwner = {}; + + /* + * Convert JSON Doxm data into binary. This will also validate + * the Doxm data received. + */ + OicSecDoxm_t* newDoxm = JSONToDoxmBin((char *)(ehRequest->reqJSONPayload)); + + if (newDoxm) + { + // Iotivity SRM ONLY supports OIC_JUST_WORKS now + if (OIC_JUST_WORKS == newDoxm->oxmSel) + { + /* + * If current state of the device is un-owned, enable + * anonymous ECDH cipher in tinyDTLS so that Provisioning + * tool can initiate JUST_WORKS ownership transfer process. + */ + if ((false == gDoxm->owned) && (false == newDoxm->owned)) + { +#ifdef __WITH_DTLS__ + ehRet = (CAEnableAnonECDHCipherSuite(true) == CA_STATUS_OK) ? OC_EH_OK : OC_EH_ERROR; +#endif //__WITH_DTLS__ + goto exit; + } + + /* + * 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)) + { + /* + * Generate OwnerPSK and create credential for Provisioning + * tool with the generated OwnerPSK. + * Update persistent storage and disable anonymous ECDH cipher + * + */ +#ifdef __WITH_DTLS__ + CAResult_t pskRet; + + OCServerRequest * request = (OCServerRequest *)ehRequest->requestHandle; + uint8_t ownerPSK[OWNER_PSK_LENGTH_128] = {}; + + //Generating OwnerPSK + pskRet = CAGenerateOwnerPSK(&request->addressInfo, + request->connectivityType, + (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); + + 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)); + + // Update new state in persistent storage + if (true == UpdatePersistentStorage(gDoxm)) + { + ehRet = OC_EH_OK; + } + else + { + ehRet = OC_EH_ERROR; + + /* + * If persistent storage update failed, revert back the state + * for global variable. + */ + gDoxm->owned = false; + memset(&(gDoxm->owner), 0, sizeof(OicUuid_t)); + } + + /* + * Disable anonymous ECDH cipher in tinyDTLS since device is now + * in owned state. + */ + CAEnableAnonECDHCipherSuite(false); +#endif //__WITH_DTLS__ + } + } + } + +exit: + + //Send payload to request originator + if(OC_STACK_OK != SendSRMResponse(ehRequest, ehRet, NULL)) + { + OC_LOG (ERROR, TAG, PCF("SendSRMResponse failed in HandlePstatPostRequest")); + } + DeleteDoxmBinData(newDoxm); + + return ehRet; +} + +/* + * This internal method is the entity handler for DOXM resources. + */ +OCEntityHandlerResult DoxmEntityHandler (OCEntityHandlerFlag flag, + OCEntityHandlerRequest * ehRequest) +{ + OCEntityHandlerResult ehRet = OC_EH_ERROR; + + if(NULL == 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 = HandleDoxmGetRequest(ehRequest); + break; + + case OC_REST_PUT: + ehRet = HandleDoxmPutRequest(ehRequest); + break; + + default: + ehRet = OC_EH_ERROR; + SendSRMResponse(ehRequest, ehRet, NULL); + break; + } + } + + return ehRet; +} + +/* + * This internal method is used to create '/oic/sec/doxm' resource. + */ +OCStackResult CreateDoxmResource() +{ + OCStackResult ret; + + ret = OCCreateResource(&gDoxmHandle, + OIC_RSRC_TYPE_SEC_DOXM, + OIC_MI_DEF, + OIC_RSRC_DOXM_URI, + DoxmEntityHandler, + OC_OBSERVABLE); + + if (OC_STACK_OK != ret) + { + OC_LOG (FATAL, TAG, PCF("Unable to instantiate Doxm resource")); + DeInitDoxmResource(); + } + return ret; +} + +/** + * Checks if DeviceID is generated during provisioning for the new device. + * If DeviceID is NULL then generates the new DeviceID. + * Once DeviceID is assigned to the device it does not change for the lifetime of the device. + * + */ +void CheckDeviceID() +{ + //TODO: Save this deviceID at secure location so that we can retrieve it if the + //JSON gets corrupted. + if(strcmp((char *)gDoxm->deviceID.id, "") == 0 ) + { + OCFillRandomMem(gDoxm->deviceID.id, sizeof(gDoxm->deviceID.id)); + } +} + +/** + * Get the default value. + * @retval the gDefaultDoxm pointer; + */ +static OicSecDoxm_t* GetDoxmDefault() +{ + OC_LOG (INFO, TAG, PCF("GetDoxmToDefault")); + return &gDefaultDoxm; +} + +/** + * This method is used by SRM to retrieve DOXM resource data. + * + * @retval reference to @ref OicSecDoxm_t, binary format of Doxm resource data + */ +const OicSecDoxm_t* GetDoxmResourceData() +{ + return gDoxm; +} + +/** + * Initialize DOXM resource by loading data from persistent storage. + * + * @retval OC_STACK_OK for Success, otherwise some error value + */ +OCStackResult InitDoxmResource() +{ + OCStackResult ret = OC_STACK_ERROR; + + //Read DOXM resource from PS + char* jsonSVRDatabase = GetSVRDatabase(); + if(jsonSVRDatabase) + { + //Convert JSON DOXM into binary format + gDoxm = JSONToDoxmBin(jsonSVRDatabase); + } + /* + * If SVR database in persistent storage got corrupted or + * is not available for some reason, a default doxm is created + * which allows user to initiate doxm provisioning again. + */ + if(!jsonSVRDatabase || !gDoxm) + { + gDoxm = GetDoxmDefault(); + } + CheckDeviceID(); + //Instantiate 'oic.sec.doxm' + ret = CreateDoxmResource(); + OICFree(jsonSVRDatabase); + return ret; +} + +/** + * Perform cleanup for DOXM resources. + * + * @return + * OC_STACK_OK - no error + * OC_STACK_ERROR - stack process error + * + */ +OCStackResult DeInitDoxmResource() +{ + OCStackResult ret = OCDeleteResource(gDoxmHandle); + if(gDoxm != &gDefaultDoxm) + { + DeleteDoxmBinData(gDoxm); + } + gDoxm = NULL; + + if(OC_STACK_OK == ret) + { + return OC_STACK_OK; + } + else + { + return OC_STACK_ERROR; + } +} + + +/** + * This method returns the SRM device ID for this device. + * + * @retval OC_STACK_OK for Success, otherwise some error value + */ +OCStackResult GetDoxmDeviceID(OicUuid_t *deviceID) +{ + if(deviceID && gDoxm) + { + *deviceID = gDoxm->deviceID; + return OC_STACK_OK; + } + return OC_STACK_ERROR; +} + +/** + * @brief Gets the OicUuid_t value for the owner of this device. + * + * @return OC_STACK_OK if devOwner is a valid UUID, otherwise OC_STACK_ERROR. + */ +OCStackResult GetDoxmDevOwnerId(OicUuid_t *devOwner) +{ + OCStackResult retVal = OC_STACK_ERROR; + if(gDoxm) + { + if(gDoxm->owned) { + *devOwner = gDoxm->owner; // TODO change to devOwner when available + retVal = OC_STACK_OK; + } + } + return retVal; +} diff --git a/resource/csdk/security/src/ocsecurity.c b/resource/csdk/security/src/ocsecurity.c deleted file mode 100644 index 27e5b79..0000000 --- a/resource/csdk/security/src/ocsecurity.c +++ /dev/null @@ -1,237 +0,0 @@ -//****************************************************************** -// -// Copyright 2014 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 "oic_malloc.h" -#include "ocsecurity.h" -#include "ocsecurityconfig.h" -#include "cainterface.h" -#include - -static OCSecConfigData* secConfigData; -static int secConfigDataLen; - - -/** - * This internal API removes/clears the global variable holding the security - * config data. This needs to be invoked when OIC stack is shutting down. - * - * @retval none - */ -void DeinitOCSecurityInfo() -{ - if (secConfigData) - { - // Initialize sensitive data to zeroes before freeing. - memset(secConfigData, 0, secConfigDataLen); - - OICFree(secConfigData); - secConfigData = NULL; - } -} - -/** - * This internal callback is used by lower stack (i.e. CA layer) to - * retrieve PSK credentials from RI security layer. - * - * Note: When finished, caller should initialize memory to zeroes and - * invoke OICFree to delete @p credInfo. - * - * @param credInfo - * binary blob containing PSK credentials - * - * @retval none - */ -#ifdef __WITH_DTLS__ -void GetDtlsPskCredentials(CADtlsPskCredsBlob_t **credInfo) -{ - // CA layer interface publishes security data structures ONLY if - // stack is compiled in SECURED mode - CADtlsPskCredsBlob_t * caBlob = NULL; - if(secConfigData && credInfo) - { - unsigned int i = 0; - OCSecBlob * osb = (OCSecBlob*)secConfigData->blob; - for ( ;(inumBlob) && osb; i++) - { - if (osb->type == OC_BLOB_TYPE_PSK) - { - caBlob = (CADtlsPskCredsBlob_t *)OICCalloc(sizeof(CADtlsPskCredsBlob_t), 1); - if (caBlob) - { - OCDtlsPskCredsBlob * ocBlob = (OCDtlsPskCredsBlob *)osb->val; - - memcpy(caBlob->identity, ocBlob->identity, sizeof(caBlob->identity)); - caBlob->num = ocBlob->num; - caBlob->creds = - (OCDtlsPskCreds*) OICMalloc(caBlob->num * sizeof(OCDtlsPskCreds)); - if (caBlob->creds) - { - memcpy(caBlob->creds, ocBlob->creds, - caBlob->num * sizeof(OCDtlsPskCreds)); - *credInfo = caBlob; - // We copied the credential blob in the CA data structure. - // Let's get out of here. - return; - } - } - break; - } - osb = config_data_next_blob(osb); - } - } - - // Clear memory if any memory allocation failed above - if(caBlob) - { - OICFree(caBlob->creds); - OICFree(caBlob); - } -} -#endif //__WITH_DTLS__ - - -/** - * This method validates the sanctity of OCDtlsPskCredsBlob. - * - * @param secBlob - * binary blob containing PSK credentials - * - * @retval OC_STACK_OK for Success, otherwise some error value - */ -static -OCStackResult ValidateBlobTypePSK(const OCSecBlob *secBlob) -{ - OCDtlsPskCredsBlob *pskCredsBlob; - uint16_t validLen; - - if(!secBlob || secBlob->len == 0) - { - return OC_STACK_INVALID_PARAM; - } - - pskCredsBlob = (OCDtlsPskCredsBlob *)secBlob->val; - - //calculate the expected length of PSKCredsBlob - if(pskCredsBlob->num >= 1) - { - validLen = sizeof(OCDtlsPskCredsBlob) + - (pskCredsBlob->num - 1) * sizeof(OCDtlsPskCredsBlob); - } - else - { - validLen = sizeof(OCDtlsPskCredsBlob); - } - - if(secBlob->len != validLen) - return OC_STACK_INVALID_PARAM; - - return OC_STACK_OK; -} - - -/** - * This method validates the sanctity of configuration data provided - * by application to OC stack. - * - * @param cfgdata - * binary blob containing credentials and other config data - * @param len - * length of binary blob - * - * @retval OC_STACK_OK for Success, otherwise some error value - */ -static -OCStackResult ValidateSecConfigData(const OCSecConfigData *cfgData, - size_t len) -{ - OCStackResult ret = OC_STACK_OK; - unsigned int i = 0; - OCSecBlob * osb = NULL; - - if (!cfgData || (len == 0)) - { - return OC_STACK_INVALID_PARAM; - } - - if (cfgData->version != OCSecConfigVer_CurrentVersion) - { - return OC_STACK_INVALID_PARAM; - } - - osb = (OCSecBlob*)cfgData->blob; - for ( ;(inumBlob) && osb; i++) - { - if (osb->type == OC_BLOB_TYPE_PSK) - { - ret = ValidateBlobTypePSK(osb); - } - else - { - return OC_STACK_INVALID_PARAM; - } - - if (ret != OC_STACK_OK) - { - return ret; - } - osb = config_data_next_blob(osb); - } - - return ret; -} - - - -/** - * Provides the Security configuration data to OC stack. - * - * @param cfgdata - * binary blob containing credentials and other config data - * @param len - * length of binary blob - * - * @retval OC_STACK_OK for Success, otherwise some error value - */ -OCStackResult OCSecSetConfigData(const OCSecConfigData *cfgData, - size_t len) -{ - // Validate the data inside blob before consuming - if (cfgData && ValidateSecConfigData(cfgData, len) == OC_STACK_OK) - { - // Remove existing blob - DeinitOCSecurityInfo(); - // Allocate storage for new blob - secConfigData = (OCSecConfigData*)OICMalloc(len); - if (secConfigData) - { - memcpy(secConfigData, cfgData, len); - secConfigDataLen = len; - return OC_STACK_OK; - } - - return OC_STACK_NO_MEMORY; - } - - return OC_STACK_INVALID_PARAM; -} - - - diff --git a/resource/csdk/security/src/policyengine.c b/resource/csdk/security/src/policyengine.c new file mode 100644 index 0000000..28ece4a --- /dev/null +++ b/resource/csdk/security/src/policyengine.c @@ -0,0 +1,368 @@ +//****************************************************************** +// +// 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 "oic_malloc.h" +#include "policyengine.h" +#include "resourcemanager.h" +#include "securevirtualresourcetypes.h" +#include "srmresourcestrings.h" +#include "logger.h" +#include "aclresource.h" +#include "srmutility.h" +#include "doxmresource.h" +#include + +#define TAG PCF("SRM-PE") + +/** + * Return the uint16_t CRUDN permission corresponding to passed CAMethod_t. + */ +uint16_t GetPermissionFromCAMethod_t(const CAMethod_t method) +{ + uint16_t perm = 0; + switch(method) + { + case CA_GET: + perm = (uint16_t)PERMISSION_READ; + break; + case CA_POST: // For now we treat all PUT & POST as Write + case CA_PUT: // because we don't know if resource exists yet. + perm = (uint16_t)PERMISSION_WRITE; + break; + case CA_DELETE: + perm = (uint16_t)PERMISSION_DELETE; + break; + default: // if not recognized, must assume requesting full control + perm = (uint16_t)PERMISSION_FULL_CONTROL; + break; + } + return perm; +} + +/** + * @brief Compares two OicUuid_t structs. + * @return true if the two OicUuid_t structs are equal, else false. + */ +bool UuidCmp(OicUuid_t *firstId, OicUuid_t *secondId) +{ + // TODO use VERIFY macros to check for null when they are merged. + if(NULL == firstId || NULL == secondId) + { + return false; + } + for(int i = 0; i < UUID_LENGTH; i++) + { + if(firstId->id[i] != secondId->id[i]) + { + return false; + } + } + return true; +} + + +/** + * Set the state and clear other stateful context vars. + */ +void SetPolicyEngineState(PEContext_t *context, const PEState_t state) +{ + // Clear stateful context variables. + OICFree(context->subject); + context->subject = NULL; + OICFree(context->resource); + context->resource = NULL; + context->permission = 0x0; + context->matchingAclFound = false; + context->retVal = ACCESS_DENIED_POLICY_ENGINE_ERROR; + + // Set state. + context->state = state; +} + +/** + * @brief Compare the request's subject to DevOwner. + * + * @return true if context->subjectId == GetDoxmDevOwner(), else false + */ +bool IsRequestFromDevOwner(PEContext_t *context) +{ + bool retVal = false; + OicUuid_t owner; + + if(OC_STACK_OK == GetDoxmDevOwnerId(&owner)) + { + retVal = UuidCmp(context->subject, &owner); + } + + return retVal; +} + +/** + * Bitwise check to see if 'permission' contains 'request'. + * @param permission The allowed CRUDN permission. + * @param request The CRUDN permission being requested. + * @return true if 'permission' bits include all 'request' bits. + */ +static inline bool IsPermissionAllowingRequest(const uint16_t permission, + const uint16_t request) +{ + if(request == (request & permission)) + { + return true; + } + else + { + return false; + } +} + +/** + * Compare the passed subject to the wildcard (aka anonymous) subjectId. + * @return true if 'subject' is the wildcard, false if it is not. + */ +static inline bool IsWildCardSubject(OicUuid_t *subject) +{ + // Because always comparing to string literal, use strcmp() + if(0 == memcmp(subject, &WILDCARD_SUBJECT_ID, sizeof(OicUuid_t))) + { + return true; + } + else + { + return false; + } +} + +/** + * Copy the subject, resource and permission into the context fields. + */ +void CopyParamsToContext( + PEContext_t *context, + const OicUuid_t *subjectId, + const char *resource, + const uint16_t requestedPermission) +{ + size_t length = 0; + + // Free any existing subject. + OICFree(context->subject); + // Copy the subjectId into context. + context->subject = (OicUuid_t*)OICMalloc(sizeof(OicUuid_t)); + VERIFY_NON_NULL(TAG, context->subject, ERROR); + memcpy(context->subject, subjectId, sizeof(OicUuid_t)); + + // Copy the resource string into context. + length = strlen(resource) + 1; + if(0 < length) + { + OICFree(context->resource); + context->resource = (char*)OICMalloc(length); + VERIFY_NON_NULL(TAG, context->resource, ERROR); + strncpy(context->resource, resource, length); + context->resource[length - 1] = '\0'; + } + + // Assign the permission field. + context->permission = requestedPermission; + +exit: + return; +} + +/** + * 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? + { + return true; + } + } + return false; + } + +/** + * Find ACLs containing context->subject. + * Search each ACL for requested resource. + * If resource found, check for context->permission. + * Set context->retVal to result from first ACL found which contains + * correct subject AND resource. + * + * @retval void + */ +void ProcessAccessRequest(PEContext_t *context) +{ + OC_LOG(INFO, TAG, PCF("Entering ProcessAccessRequest()")); + if(NULL != context) + { + const OicSecAcl_t *currentAcl = NULL; + OicSecAcl_t *savePtr = NULL; + + // Start out assuming subject not found. + context->retVal = ACCESS_DENIED_SUBJECT_NOT_FOUND; + do + { + OC_LOG(INFO, TAG, PCF("ProcessAccessRequest(): getting ACL...")); + currentAcl = GetACLResourceData(context->subject, &savePtr); + char *tmp = (char*)OICMalloc(sizeof(OicUuid_t) +1); + memcpy(tmp, context->subject, sizeof(OicUuid_t)); + tmp[sizeof(OicUuid_t) + 1] = '\0'; + if(NULL != currentAcl) + { + // Found the subject, so how about resource? + OC_LOG(INFO, TAG, PCF("ProcessAccessRequest(): \ + found ACL matching subject.")); + context->retVal = ACCESS_DENIED_RESOURCE_NOT_FOUND; + OC_LOG(INFO, TAG, PCF("ProcessAccessRequest(): \ + Searching for resource...")); + if(IsResourceInAcl(context->resource, currentAcl)) + { + 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)) + { + context->retVal = ACCESS_GRANTED; + } + } + } + else + { + OC_LOG(INFO, TAG, PCF("ProcessAccessRequest(): \ + no ACL found matching subject .")); + } + } + while((NULL != currentAcl) && (false == context->matchingAclFound)); + } + if(IsAccessGranted(context->retVal)) + { + OC_LOG(INFO, TAG, PCF("ProcessAccessRequest(): \ + Leaving ProcessAccessRequest(ACCESS_GRANTED)")); + } + else + { + OC_LOG(INFO, TAG, PCF("ProcessAccessRequest(): \ + Leaving ProcessAccessRequest(ACCESS_DENIED)")); + } +} + +/** + * Check whether a request should be allowed. + * @param context Pointer to (Initialized) Policy Engine context to use. + * @param subjectId Pointer to Id of the requesting entity. + * @param resource Pointer to URI of Resource being requested. + * @param permission Requested permission. + * @return ACCESS_GRANTED if request should go through, + * otherwise some flavor of ACCESS_DENIED + */ +SRMAccessResponse_t CheckPermission( + PEContext_t *context, + const OicUuid_t *subjectId, + const char *resource, + const uint16_t requestedPermission) +{ + SRMAccessResponse_t retVal = ACCESS_DENIED_POLICY_ENGINE_ERROR; + + VERIFY_NON_NULL(TAG, context, ERROR); + VERIFY_NON_NULL(TAG, subjectId, ERROR); + VERIFY_NON_NULL(TAG, resource, ERROR); + + // Each state machine context can only be processing one request at a time. + // Therefore if the context is not in AWAITING_REQUEST state, return error. + // Otherwise, change to BUSY state and begin processing request. + if(AWAITING_REQUEST == context->state) + { + SetPolicyEngineState(context, BUSY); + CopyParamsToContext(context, subjectId, resource, requestedPermission); + // Before doing any processing, check if request coming + // from DevOwner and if so, always GRANT. + if(IsRequestFromDevOwner(context)) + { + context->retVal = ACCESS_GRANTED; + } + else + { + ProcessAccessRequest(context); + // If matching ACL not found, and subject != wildcard, try wildcard. + if((false == context->matchingAclFound) && \ + (false == IsWildCardSubject(context->subject))) + { + OICFree(context->subject); + context->subject = (OicUuid_t*)OICMalloc(sizeof(OicUuid_t)); + VERIFY_NON_NULL(TAG, context->subject, ERROR); + memcpy(context->subject, &WILDCARD_SUBJECT_ID, + sizeof(OicUuid_t)); + ProcessAccessRequest(context); // TODO anonymous subj can result + // in confusing err code return. + } + } + } + else + { + context->retVal = ACCESS_DENIED_POLICY_ENGINE_ERROR; + } + + // Capture retVal before resetting state for next request. + retVal = context->retVal; + SetPolicyEngineState(context, AWAITING_REQUEST); + +exit: + return retVal; +} + +/** + * Initialize the Policy Engine. Call this before calling CheckPermission(). + * @param context Pointer to Policy Engine context to initialize. + * @return OC_STACK_OK for Success, otherwise some error value + */ +OCStackResult InitPolicyEngine(PEContext_t *context) +{ + if(NULL != context) + { + SetPolicyEngineState(context, AWAITING_REQUEST); + } + + return OC_STACK_OK; +} + +/** + * De-Initialize the Policy Engine. Call this before exiting to allow Policy + * Engine to do cleanup on context. + * @param context Pointer to Policy Engine context to de-initialize. + * @return none + */ +void DeInitPolicyEngine(PEContext_t *context) +{ + if(NULL != context) + { + SetPolicyEngineState(context, STOPPED); + } + + return; +} diff --git a/resource/csdk/security/src/psinterface.c b/resource/csdk/security/src/psinterface.c new file mode 100644 index 0000000..f295fce --- /dev/null +++ b/resource/csdk/security/src/psinterface.c @@ -0,0 +1,200 @@ +//****************************************************************** +// +// 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 "cainterface.h" +#include "secureresourcemanager.h" +#include "resourcemanager.h" +#include "srmresourcestrings.h" +#include "srmutility.h" +#include +#include + +#define TAG PCF("SRM-PSI") + +//SVR database buffer block size +const size_t DB_FILE_SIZE_BLOCK = 1023; + +/** + * Gets the Secure Virtual Database size. + * + * @param ps pointer of OCPersistentStorage for the SVR name ("acl", "cred", "pstat" etc). + * + * @retval total size of the SVR database. + */ +size_t GetSVRDatabaseSize(OCPersistentStorage* ps) +{ + size_t size = 0; + if (!ps) + { + return size; + } + size_t bytesRead = 0; + char buffer[DB_FILE_SIZE_BLOCK]; + FILE* fp = ps->open(SVR_DB_FILE_NAME, "r"); + if (fp) + { + do + { + bytesRead = ps->read(buffer, 1, DB_FILE_SIZE_BLOCK, fp); + size += bytesRead; + } while (bytesRead > 0); + ps->close(fp); + } + return size; +} + +/** + * Reads the Secure Virtual Database from PS into dynamically allocated + * memory buffer. + * + * @note Caller of this method MUST use OICFree() method to release memory + * referenced by return value. + * + * @retval reference to memory buffer containing SVR database. + */ +char * GetSVRDatabase() +{ + char * jsonStr = NULL; + FILE * fp = NULL; + OCPersistentStorage* ps = SRMGetPersistentStorageHandler(); + int size = GetSVRDatabaseSize(ps); + if (0 == size) + { + OC_LOG (ERROR, TAG, PCF("FindSVRDatabaseSize failed")); + return NULL; + } + + if (ps && ps->open) + { + // Open default SRM database file. An app could change the path for its server. + fp = ps->open(SVR_DB_FILE_NAME, "r"); + if (fp) + { + jsonStr = (char*)OICMalloc(size + 1); + VERIFY_NON_NULL(TAG, jsonStr, FATAL); + size_t bytesRead = ps->read(jsonStr, 1, size, fp); + jsonStr[bytesRead] = '\0'; + + OC_LOG_V(INFO, TAG, PCF("Read %d bytes from SVR database file"), bytesRead); + ps->close(fp); + fp = NULL; + } + else + { + OC_LOG (ERROR, TAG, PCF("Unable to open SVR database file!!")); + } + } + +exit: + if (ps && fp) + { + ps->close(fp); + } + return jsonStr; +} + + +/** + * This method is used by a entity handlers of SVR's to update + * SVR database. + * + * @param rsrcName string denoting the SVR name ("acl", "cred", "pstat" etc). + * @param jsonObj JSON object containing the SVR contents. + * + * @retval OC_STACK_OK for Success, otherwise some error value + */ +OCStackResult UpdateSVRDatabase(const char* rsrcName, cJSON* jsonObj) +{ + OCStackResult ret = OC_STACK_ERROR; + cJSON *jsonSVRDb = NULL; + + // Read SVR database from PS + char* jsonSVRDbStr = GetSVRDatabase(); + VERIFY_NON_NULL(TAG,jsonSVRDbStr, ERROR); + + // Use cJSON_Parse to parse the existing SVR database + jsonSVRDb = cJSON_Parse(jsonSVRDbStr); + VERIFY_NON_NULL(TAG,jsonSVRDb, ERROR); + + OICFree(jsonSVRDbStr); + jsonSVRDbStr = NULL; + + if (jsonObj->child ) + { + // Create a duplicate of the JSON object which was passed. + cJSON* jsonDuplicateObj = cJSON_Duplicate(jsonObj, 1); + VERIFY_NON_NULL(TAG,jsonDuplicateObj, ERROR); + + cJSON* jsonObj = cJSON_GetObjectItem(jsonSVRDb, rsrcName); + + /* + ACL, PStat & Doxm resources at least have default entries in the database but + Cred resource may have no entries. The first cred resource entry (for provisioning tool) + is created when the device is owned by provisioning tool and it's ownerpsk is generated.*/ + if((strcmp(rsrcName, OIC_JSON_CRED_NAME) == 0) && (!jsonObj)) + { + // Add the fist cred object in existing SVR database json + cJSON_AddItemToObject(jsonSVRDb, rsrcName, jsonDuplicateObj->child); + } + else + { + VERIFY_NON_NULL(TAG,jsonObj, ERROR); + + // 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); + + // Update the persistent storage with new SVR database + OCPersistentStorage* ps = SRMGetPersistentStorageHandler(); + if (ps && ps->open) + { + 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)) + { + 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!! ")); + } + } + } + +exit: + OICFree(jsonSVRDbStr); + cJSON_Delete(jsonSVRDb); + + return ret; +} diff --git a/resource/csdk/security/src/pstatresource.c b/resource/csdk/security/src/pstatresource.c new file mode 100644 index 0000000..19702a7 --- /dev/null +++ b/resource/csdk/security/src/pstatresource.c @@ -0,0 +1,399 @@ +//****************************************************************** +// +// 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 "resourcemanager.h" +#include "pstatresource.h" +#include "psinterface.h" +#include "utlist.h" +#include "base64.h" +#include "srmresourcestrings.h" +#include "srmutility.h" +#include +#include + +#define TAG PCF("SRM-PSTAT") + +static OicSecDpom_t gSm = SINGLE_SERVICE_CLIENT_DRIVEN; +static OicSecPstat_t gDefaultPstat = +{ + false, // bool isOwned + (OicSecDpm_t)(TAKE_OWNER | BOOTSTRAP_SERVICE | SECURITY_MANAGEMENT_SERVICES | + PROVISION_CREDENTIALS | PROVISION_ACLS), // OicSecDpm_t cm + (OicSecDpm_t)(TAKE_OWNER | BOOTSTRAP_SERVICE | SECURITY_MANAGEMENT_SERVICES | + PROVISION_CREDENTIALS | PROVISION_ACLS), // OicSecDpm_t tm + {}, // OicUuid_t deviceID + SINGLE_SERVICE_CLIENT_DRIVEN, // OicSecDpom_t om */ + 1, // the number of elts in Sms + &gSm, // OicSecDpom_t *sm + 0, // uint16_t commitHash +}; +static OicSecPstat_t *gPstat = NULL; +static OCResourceHandle gPstatHandle = NULL; + +void DeletePstatBinData(OicSecPstat_t* pstat) +{ + if (pstat) + { + //Clean 'supported modes' field + OICFree(pstat->sm); + + //Clean pstat itself + OICFree(pstat); + } +} + +char * BinToPstatJSON(const OicSecPstat_t * pstat) +{ + if(NULL == pstat) + { + return NULL; + } + + cJSON *jsonPstat = NULL; + char *jsonStr = NULL; + cJSON *jsonSmArray = NULL; + char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(((OicUuid_t*) 0)->id)) + 1] = {}; + uint32_t outLen = 0; + B64Result b64Ret = B64_OK; + + cJSON *jsonRoot = cJSON_CreateObject(); + VERIFY_NON_NULL(TAG, jsonRoot, INFO); + + cJSON_AddItemToObject(jsonRoot, OIC_JSON_PSTAT_NAME, jsonPstat=cJSON_CreateObject()); + cJSON_AddBoolToObject(jsonPstat, OIC_JSON_ISOP_NAME, pstat->isOp); + + b64Ret = b64Encode(pstat->deviceID.id, + sizeof(pstat->deviceID.id), base64Buff, sizeof(base64Buff), &outLen); + VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR); + + cJSON_AddStringToObject(jsonPstat, OIC_JSON_DEVICE_ID_NAME, base64Buff); + cJSON_AddNumberToObject(jsonPstat, OIC_JSON_COMMIT_HASH_NAME, pstat->commitHash); + cJSON_AddNumberToObject(jsonPstat, OIC_JSON_CM_NAME, (int)pstat->cm); + cJSON_AddNumberToObject(jsonPstat, OIC_JSON_TM_NAME, (int)pstat->tm); + cJSON_AddNumberToObject(jsonPstat, OIC_JSON_OM_NAME, (int)pstat->om); + + cJSON_AddItemToObject(jsonPstat, OIC_JSON_SM_NAME, jsonSmArray = cJSON_CreateArray()); + VERIFY_NON_NULL(TAG, jsonSmArray, INFO); + for (int i = 0; i < pstat->smLen; i++) + { + cJSON_AddItemToArray(jsonSmArray, cJSON_CreateNumber((int )pstat->sm[i])); + } + jsonStr = cJSON_Print(jsonRoot); + +exit: + if (jsonRoot) + { + cJSON_Delete(jsonRoot); + } + return jsonStr; +} + +OicSecPstat_t * JSONToPstatBin(const char * jsonStr) +{ + if(NULL == jsonStr) + { + return NULL; + } + + OCStackResult ret = OC_STACK_ERROR; + OicSecPstat_t *pstat = NULL; + cJSON *jsonPstat = NULL; + cJSON *jsonObj = NULL; + + unsigned char base64Buff[sizeof(((OicUuid_t*) 0)->id)] = {}; + uint32_t outLen = 0; + B64Result b64Ret = B64_OK; + + cJSON *jsonRoot = cJSON_Parse(jsonStr); + VERIFY_NON_NULL(TAG, jsonRoot, INFO); + + jsonPstat = cJSON_GetObjectItem(jsonRoot, OIC_JSON_PSTAT_NAME); + VERIFY_NON_NULL(TAG, jsonPstat, INFO); + + pstat = (OicSecPstat_t*)OICCalloc(1, sizeof(OicSecPstat_t)); + VERIFY_NON_NULL(TAG, pstat, INFO); + jsonObj = cJSON_GetObjectItem(jsonPstat, OIC_JSON_ISOP_NAME); + VERIFY_NON_NULL(TAG, jsonObj, ERROR); + VERIFY_SUCCESS(TAG, (cJSON_True == jsonObj->type || cJSON_False == jsonObj->type) , ERROR); + pstat->isOp = jsonObj->valueint; + + jsonObj = cJSON_GetObjectItem(jsonPstat, OIC_JSON_DEVICE_ID_NAME); + VERIFY_NON_NULL(TAG, jsonObj, ERROR); + VERIFY_SUCCESS(TAG, cJSON_String == jsonObj->type, ERROR); + b64Ret = b64Decode(jsonObj->valuestring, strlen(jsonObj->valuestring), base64Buff, + sizeof(base64Buff), &outLen); + VERIFY_SUCCESS(TAG, (b64Ret == B64_OK && outLen <= sizeof(pstat->deviceID.id)), ERROR); + memcpy(pstat->deviceID.id, base64Buff, outLen); + + jsonObj = cJSON_GetObjectItem(jsonPstat, OIC_JSON_COMMIT_HASH_NAME); + VERIFY_NON_NULL(TAG, jsonObj, ERROR); + VERIFY_SUCCESS(TAG, cJSON_Number == jsonObj->type, ERROR); + pstat->commitHash = jsonObj->valueint; + + jsonObj = cJSON_GetObjectItem(jsonPstat, OIC_JSON_CM_NAME); + VERIFY_NON_NULL(TAG, jsonObj, ERROR); + VERIFY_SUCCESS(TAG, cJSON_Number == jsonObj->type, ERROR); + pstat->cm = (OicSecDpm_t)jsonObj->valueint; + + jsonObj = cJSON_GetObjectItem(jsonPstat, OIC_JSON_OM_NAME); + VERIFY_NON_NULL(TAG, jsonObj, ERROR); + VERIFY_SUCCESS(TAG, cJSON_Number == jsonObj->type, ERROR); + pstat->om = (OicSecDpom_t)jsonObj->valueint; + + jsonObj = cJSON_GetObjectItem(jsonPstat, OIC_JSON_SM_NAME); + VERIFY_NON_NULL(TAG, jsonObj, ERROR); + if (cJSON_Array == jsonObj->type) + { + pstat->smLen = cJSON_GetArraySize(jsonObj); + int idxx = 0; + VERIFY_SUCCESS(TAG, pstat->smLen != 0, ERROR); + pstat->sm = (OicSecDpom_t*)OICCalloc(pstat->smLen, sizeof(OicSecDpom_t)); + VERIFY_NON_NULL(TAG, pstat->sm, ERROR); + do + { + cJSON *jsonSm = cJSON_GetArrayItem(jsonObj, idxx); + VERIFY_NON_NULL(TAG, jsonSm, ERROR); + pstat->sm[idxx] = (OicSecDpom_t)jsonSm->valueint; + }while ( ++idxx < pstat->smLen); + } + ret = OC_STACK_OK; + +exit: + cJSON_Delete(jsonRoot); + if (OC_STACK_OK != ret) + { + OC_LOG (ERROR, TAG, PCF("JSONToPstatBin failed")); + DeletePstatBinData(pstat); + pstat = NULL; + } + return pstat; +} + +/** + * The entity handler determines how to process a GET request. + */ +static OCEntityHandlerResult HandlePstatGetRequest (const OCEntityHandlerRequest * ehRequest) +{ + // Convert ACL data into JSON for transmission + char* jsonStr = BinToPstatJSON(gPstat); + + // A device should always have a default pstat. Therefore, jsonStr should never be NULL. + OCEntityHandlerResult ehRet = (jsonStr ? OC_EH_OK : OC_EH_ERROR); + + // Send response payload to request originator + SendSRMResponse(ehRequest, ehRet, jsonStr); + OICFree(jsonStr); + return ehRet; +} + +/** + * 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. + * For pstat, it updates only tm and om. + */ +static OCEntityHandlerResult HandlePstatPutRequest(const OCEntityHandlerRequest *ehRequest) +{ + OCEntityHandlerResult ehRet = OC_EH_ERROR; + cJSON *postJson = NULL; + + if (ehRequest->resource) + { + postJson = cJSON_Parse((char *) ehRequest->reqJSONPayload); + VERIFY_NON_NULL(TAG, postJson, INFO); + cJSON *jsonPstat = cJSON_GetObjectItem(postJson, OIC_JSON_PSTAT_NAME); + VERIFY_NON_NULL(TAG, jsonPstat, INFO); + cJSON *commitHashJson = cJSON_GetObjectItem(jsonPstat, OIC_JSON_COMMIT_HASH_NAME); + uint16_t commitHash = 0; + if (commitHashJson) + { + commitHash = commitHashJson->valueint; + } + cJSON *tmJson = cJSON_GetObjectItem(jsonPstat, OIC_JSON_TM_NAME); + if (tmJson && gPstat) + { + gPstat->tm = (OicSecDpm_t)tmJson->valueint; + if(0 == tmJson->valueint && gPstat->commitHash == commitHash) + { + gPstat->isOp = true; + gPstat->cm = NORMAL; + OC_LOG (INFO, TAG, PCF("CommitHash is valid and isOp is TRUE")); + } + else + { + OC_LOG (INFO, TAG, PCF("CommitHash is not valid")); + } + } + cJSON *omJson = cJSON_GetObjectItem(jsonPstat, OIC_JSON_OM_NAME); + if (omJson && gPstat) + { + /* + * Check if the operation mode is in the supported provisioning services + * operation mode list. + */ + for(size_t i=0; i< gPstat->smLen; i++) + { + if(gPstat->sm[i] == omJson->valueint) + { + gPstat->om = (OicSecDpom_t)omJson->valueint; + break; + } + } + } + // Convert pstat data into JSON for update to persistent storage + char *jsonStr = BinToPstatJSON(gPstat); + if (jsonStr) + { + cJSON *jsonPstat = cJSON_Parse(jsonStr); + OICFree(jsonStr); + if (OC_STACK_OK == UpdateSVRDatabase(OIC_JSON_PSTAT_NAME, jsonPstat)) + { + ehRet = OC_EH_OK; + } + } + } + exit: + //Send payload to request originator + if(OC_STACK_OK != SendSRMResponse(ehRequest, ehRet, NULL)) + { + OC_LOG (ERROR, TAG, PCF("SendSRMResponse failed in HandlePstatPostRequest")); + } + cJSON_Delete(postJson); + return ehRet; +} + +/** + * This internal method is the entity handler for pstat resources. + */ +OCEntityHandlerResult PstatEntityHandler(OCEntityHandlerFlag flag, + OCEntityHandlerRequest * ehRequest) +{ + OCEntityHandlerResult ehRet = OC_EH_ERROR; + // This method will handle REST request (GET/POST) for /oic/sec/pstat + if (flag & OC_REQUEST_FLAG) + { + OC_LOG (INFO, TAG, PCF("Flag includes OC_REQUEST_FLAG")); + switch (ehRequest->method) + { + case OC_REST_GET: + ehRet = HandlePstatGetRequest(ehRequest); + break; + case OC_REST_PUT: + ehRet = HandlePstatPutRequest(ehRequest); + break; + default: + ehRet = OC_EH_ERROR; + SendSRMResponse(ehRequest, ehRet, NULL); + break; + } + } + return ehRet; +} + +/** + * This internal method is used to create '/oic/sec/pstat' resource. + */ +OCStackResult CreatePstatResource() +{ + OCStackResult ret; + + ret = OCCreateResource(&gPstatHandle, + OIC_RSRC_TYPE_SEC_PSTAT, + OIC_MI_DEF, + OIC_RSRC_PSTAT_URI, + PstatEntityHandler, + OC_RES_PROP_NONE); + + if (ret != OC_STACK_OK) + { + OC_LOG (FATAL, TAG, PCF("Unable to instantiate pstat resource")); + DeInitPstatResource(); + } + return ret; +} + +/** + * Post ACL hander update the commitHash during ACL provisioning. + */ +void SetCommitHash(uint16_t commitHash) +{ + gPstat->commitHash = commitHash; +} + +/** + * Get the default value + * @retval the gDefaultPstat pointer + */ +static OicSecPstat_t* GetPstatDefault() +{ + return &gDefaultPstat; +} + +/** + * Initialize pstat resource by loading data from persistent storage. + * + * @retval OC_STACK_OK for Success, otherwise some error value + */ +OCStackResult InitPstatResource() +{ + OCStackResult ret = OC_STACK_ERROR; + + // Read Pstat resource from PS + char* jsonSVRDatabase = GetSVRDatabase(); + if (jsonSVRDatabase) + { + // Convert JSON Pstat into binary format + gPstat = JSONToPstatBin(jsonSVRDatabase); + } + /* + * If SVR database in persistent storage got corrupted or + * is not available for some reason, a default pstat is created + * which allows user to initiate pstat provisioning again. + */ + if(!jsonSVRDatabase || !gPstat) + { + gPstat = GetPstatDefault(); + } + // Instantiate 'oic.sec.pstat' + ret = CreatePstatResource(); + + OICFree(jsonSVRDatabase); + return ret; +} + +/** + * Perform cleanup for pstat resources. + * + * @retval OC_STACK_OK for Success, otherwise some error value + */ +OCStackResult DeInitPstatResource() +{ + if(gPstat != &gDefaultPstat) + { + DeletePstatBinData(gPstat); + gPstat = NULL; + } + return OCDeleteResource(gPstatHandle); +} + diff --git a/resource/csdk/security/src/resourcemanager.c b/resource/csdk/security/src/resourcemanager.c new file mode 100644 index 0000000..5a41bb9 --- /dev/null +++ b/resource/csdk/security/src/resourcemanager.c @@ -0,0 +1,110 @@ +//****************************************************************** +// +// 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 "resourcemanager.h" +#include "securevirtualresourcetypes.h" +#include "aclresource.h" +#include "pstatresource.h" +#include "doxmresource.h" +#include "credresource.h" +#include "oic_malloc.h" +#include "logger.h" +#include "utlist.h" +#include + +#define TAG PCF("SRM-RM") + +/** + * This method is used by all secure resource modules to send responses to REST queries. + * + * @param ehRequest pointer to entity handler request data structure. + * @param ehRet result code from entity handler. + * @param rspPayload response payload in JSON. + * + * @retval OC_STACK_OK for Success, otherwise some error value + */ +OCStackResult SendSRMResponse(const OCEntityHandlerRequest *ehRequest, + OCEntityHandlerResult ehRet, const char *rspPayload) +{ + OCEntityHandlerResponse response = {}; + if (ehRequest) + { + response.requestHandle = ehRequest->requestHandle; + response.resourceHandle = ehRequest->resource; + response.ehResult = ehRet; + response.payload = (char *)rspPayload; + response.payloadSize = (rspPayload ? strlen(rspPayload) : 0); + response.persistentBufferFlag = 0; + + return OCDoResponse(&response); + } + return OC_STACK_ERROR; +} + +/** + * Initialize all secure resources ( /oic/sec/cred, /oic/sec/acl, /oic/sec/pstat etc). + * + * @retval OC_STACK_OK for Success, otherwise some error value + */ +OCStackResult InitSecureResources( ) +{ + OCStackResult ret; + + /* + * doxm resource should be initialized first as it contains the DeviceID + * which MAY be used during initialization of other resources. + */ + + ret = InitDoxmResource(); + + if(OC_STACK_OK == ret) + { + ret = InitPstatResource(); + } + if(OC_STACK_OK == ret) + { + ret = InitACLResource(); + } + if(OC_STACK_OK == ret) + { + ret = InitCredResource(); + } + if(OC_STACK_OK != ret) + { + //TODO: Update the default behavior if one of the SVR fails + DestroySecureResources(); + } + return ret; +} + +/** + * Perform cleanup for secure resources ( /oic/sec/cred, /oic/sec/acl, /oic/sec/pstat etc). + * + * @retval OC_STACK_OK for Success, otherwise some error value + */ +OCStackResult DestroySecureResources( ) +{ + DeInitACLResource(); + DeInitCredResource(); + DeInitDoxmResource(); + DeInitPstatResource(); + + return OC_STACK_OK; +} diff --git a/resource/csdk/security/src/secureresourcemanager.c b/resource/csdk/security/src/secureresourcemanager.c new file mode 100644 index 0000000..e3fd498 --- /dev/null +++ b/resource/csdk/security/src/secureresourcemanager.c @@ -0,0 +1,263 @@ +//****************************************************************** +// +// 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 "cainterface.h" +#include "secureresourcemanager.h" +#include "resourcemanager.h" +#include "credresource.h" +#include "policyengine.h" +#include + +#define TAG PCF("SRM") + +//Request Callback handler +static CARequestCallback gRequestHandler = NULL; +//Response Callback handler +static CAResponseCallback gResponseHandler = NULL; +//Error Callback handler +static CAErrorCallback gErrorHandler = NULL; +//Persistent Storage callback handler for open/read/write/close/unlink +static OCPersistentStorage *gPersistentStorageHandler = NULL; + +/** + * A single global Policy Engine context will suffice as long + * as SRM is single-threaded. + */ +PEContext_t g_policyEngineContext; + +/** + * @brief Handle the request from the SRM. + * @param endPoint [IN] Endpoint object from which the response is received. + * @param requestInfo [IN] Information for the request. + * @return NONE + */ +void SRMRequestHandler(const CARemoteEndpoint_t *endPoint, const CARequestInfo_t *requestInfo) +{ + OC_LOG(INFO, TAG, PCF("Received request from remote device")); + + if (!endPoint || !requestInfo) + { + OC_LOG(ERROR, TAG, PCF("Invalid arguments")); + return; + } + + // Copy the subjectID + OicUuid_t subjectId = {}; + memcpy(subjectId.id, endPoint->identity.id, sizeof(subjectId.id)); + + //Check the URI has the query and skip it before checking the permission + char *uri = strstr(endPoint->resourceUri, "?"); + int position = 0; + if (uri) + { + position = uri - endPoint->resourceUri; + } + if (position > MAX_URI_LENGTH) + { + OC_LOG(ERROR, TAG, PCF("URI length is too long")); + return; + } + SRMAccessResponse_t response = ACCESS_DENIED; + if (position > 0) + { + char newUri[MAX_URI_LENGTH + 1]; + strncpy(newUri, endPoint->resourceUri, (position)); + newUri[position] = '\0'; + //Skip query and pass the newUri. + response = CheckPermission(&g_policyEngineContext, &subjectId, newUri, + GetPermissionFromCAMethod_t(requestInfo->method)); + + } + else + { + //Pass endPoint->resourceUri if there is no query info. + response = CheckPermission(&g_policyEngineContext, &subjectId, endPoint->resourceUri, + GetPermissionFromCAMethod_t(requestInfo->method)); + } + if (IsAccessGranted(response) && gRequestHandler) + { + return (gRequestHandler(endPoint, requestInfo)); + } + + // Form a 'access deny' or 'Error' response and send to peer + CAResponseInfo_t responseInfo = {}; + memcpy(&responseInfo.info, &(requestInfo->info), sizeof(responseInfo.info)); + responseInfo.info.payload = NULL; + if (!gRequestHandler) + { + responseInfo.result = CA_INTERNAL_SERVER_ERROR; + } + else + { + /* + * TODO Enhance this logic more to decide between + * CA_UNAUTHORIZED_REQ or CA_FORBIDDEN_REQ depending + * upon SRMAccessResponseReasonCode_t + */ + responseInfo.result = CA_UNAUTHORIZED_REQ; + } + + if (CA_STATUS_OK != CASendResponse(endPoint, &responseInfo)) + { + OC_LOG(ERROR, TAG, PCF("Failed in sending response to a unauthorized request!")); + } +} + +/** + * @brief Handle the response from the SRM. + * @param endPoint [IN] The remote endpoint. + * @param responseInfo [IN] Response information from the endpoint. + * @return NONE + */ +void SRMResponseHandler(const CARemoteEndpoint_t *endPoint, const CAResponseInfo_t *responseInfo) +{ + OC_LOG(INFO, TAG, PCF("Received response from remote device")); + if (gResponseHandler) + { + gResponseHandler(endPoint, responseInfo); + } +} + + +/** + * @brief Handle the error from the SRM. + * @param endPoint [IN] The remote endpoint. + * @param errorInfo [IN] Error information from the endpoint. + * @return NONE + */ +void SRMErrorHandler(const CARemoteEndpoint_t *endPoint, const CAErrorInfo_t *errorInfo) +{ + OC_LOG(INFO, TAG, PCF("Received error from remote device")); + if (gErrorHandler) + { + gErrorHandler(endPoint, errorInfo); + } +} + + +/** + * @brief Register request and response callbacks. + * Requests and responses are delivered in these callbacks. + * @param reqHandler [IN] Request handler callback ( for GET,PUT ..etc) + * @param respHandler [IN] Response handler callback. + * @return + * OC_STACK_OK - No errors; Success + * OC_STACK_INVALID_PARAM - invalid parameter + */ +OCStackResult SRMRegisterHandler(CARequestCallback reqHandler, + CAResponseCallback respHandler, + CAErrorCallback errHandler) +{ + OC_LOG(INFO, TAG, PCF("SRMRegisterHandler !!")); + if( !reqHandler || !respHandler || !errHandler) + { + OC_LOG(ERROR, TAG, PCF("Callback handlers are invalid")); + return OC_STACK_INVALID_PARAM; + } + gRequestHandler = reqHandler; + gResponseHandler = respHandler; + gErrorHandler = errHandler; + + +#if defined(__WITH_DTLS__) + CARegisterHandler(SRMRequestHandler, SRMResponseHandler, SRMErrorHandler); +#else + CARegisterHandler(reqHandler, respHandler, errHandler); +#endif /* __WITH_DTLS__ */ + return OC_STACK_OK; +} + +/** + * @brief Register Persistent storage callback. + * @param persistentStorageHandler [IN] Pointers to open, read, write, close & unlink handlers. + * @return + * OC_STACK_OK - No errors; Success + * OC_STACK_INVALID_PARAM - Invalid parameter + */ +OCStackResult SRMRegisterPersistentStorageHandler(OCPersistentStorage* persistentStorageHandler) +{ + OC_LOG(INFO, TAG, PCF("SRMRegisterPersistentStorageHandler !!")); + if(!persistentStorageHandler) + { + OC_LOG(ERROR, TAG, PCF("The persistent storage handler is invalid")); + return OC_STACK_INVALID_PARAM; + } + gPersistentStorageHandler = persistentStorageHandler; + return OC_STACK_OK; +} + +/** + * @brief Get Persistent storage handler pointer. + * @return + * The pointer to Persistent Storage callback handler + */ + +OCPersistentStorage* SRMGetPersistentStorageHandler() +{ + OC_LOG(INFO, TAG, PCF("SRMGetPersistentStorageHandler !!")); + return gPersistentStorageHandler; +} + + +/** + * @brief Initialize all secure resources ( /oic/sec/cred, /oic/sec/acl, /oic/sec/pstat etc). + * @retval OC_STACK_OK for Success, otherwise some error value + */ +OCStackResult SRMInitSecureResources() +{ + // TODO: temporarily returning OC_STACK_OK every time until default + // behavior (for when SVR DB is missing) is settled. + InitSecureResources(); + +#if defined(__WITH_DTLS__) + CARegisterDTLSCredentialsHandler(GetDtlsPskCredentials); +#endif // (__WITH_DTLS__) + + return OC_STACK_OK; +} + +/** + * @brief Perform cleanup for secure resources ( /oic/sec/cred, /oic/sec/acl, /oic/sec/pstat etc). + * @retval none + */ +void SRMDeInitSecureResources() +{ + DestroySecureResources(); +} + +/** + * @brief Initialize Policy Engine. + * @return OC_STACK_OK for Success, otherwise some error value. + */ +OCStackResult SRMInitPolicyEngine() +{ + return InitPolicyEngine(&g_policyEngineContext); +} + +/** + * @brief Cleanup Policy Engine. + * @return none + */ +void SRMDeInitPolicyEngine() +{ + return DeInitPolicyEngine(&g_policyEngineContext); +} diff --git a/resource/csdk/security/src/srmresourcestrings.c b/resource/csdk/security/src/srmresourcestrings.c new file mode 100644 index 0000000..0a26ecc --- /dev/null +++ b/resource/csdk/security/src/srmresourcestrings.c @@ -0,0 +1,87 @@ +//****************************************************************** +// +// 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 "securevirtualresourcetypes.h" + +const char * SVR_DB_FILE_NAME = "oic_svr_db.json"; +const char * OIC_MI_DEF = "oic.mi.def"; + +const char * OIC_RSRC_CORE_URI = "/oic/res"; +const char * OIC_RSRC_CORE_D_URI = "/oic/res/d"; +const char * OIC_RSRC_CORE_P_URI = "/oic/p"; +const char * OIC_RSRC_PRESENCE_URI = "/oic/ad"; +const char * OIC_RSRC_TYPES_D_URI = "/oic/res/types/d"; + +//ACL +const char * OIC_RSRC_TYPE_SEC_ACL = "oic.sec.acl"; +const char * OIC_RSRC_ACL_URI = "/oic/sec/acl"; +const char * OIC_JSON_ACL_NAME = "acl"; + +//Pstat +const char * OIC_RSRC_TYPE_SEC_PSTAT = "oic.sec.pstat"; +const char * OIC_RSRC_PSTAT_URI = "/oic/sec/pstat"; +const char * OIC_JSON_PSTAT_NAME = "pstat"; + +//doxm +const char * OIC_RSRC_TYPE_SEC_DOXM = "oic.sec.doxm"; +const char * OIC_RSRC_DOXM_URI = "/oic/sec/doxm"; +const char * OIC_JSON_DOXM_NAME = "doxm"; + +//cred +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"; + +const char * OIC_JSON_SUBJECT_NAME = "sub"; +const char * OIC_JSON_RESOURCES_NAME = "rsrc"; +const char * OIC_JSON_PERMISSION_NAME = "perms"; +const char * OIC_JSON_OWNERS_NAME = "ownrs"; +const char * OIC_JSON_OWNER_NAME = "ownr"; +const char * OIC_JSON_OWNED_NAME = "owned"; +const char * OIC_JSON_OXM_NAME = "oxm"; +const char * OIC_JSON_OXM_TYPE_NAME = "oxmtype"; +const char * OIC_JSON_OXM_SEL_NAME = "oxmsel"; +const char * OIC_JSON_DEVICE_ID_FORMAT_NAME = "dvcidfrmt"; +const char * OIC_JSON_ISOP_NAME = "isop"; +const char * OIC_JSON_COMMIT_HASH_NAME = "commithash"; +const char * OIC_JSON_DEVICE_ID_NAME = "deviceid"; +const char * OIC_JSON_CM_NAME = "cm"; +const char * OIC_JSON_TM_NAME = "tm"; +const char * OIC_JSON_OM_NAME = "om"; +const char * OIC_JSON_SM_NAME = "sm"; +const char * OIC_JSON_CREDID_NAME = "credid"; +const char * OIC_JSON_SUBJECTID_NAME = "subid"; +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"; + +OicUuid_t WILDCARD_SUBJECT_ID = {"*"}; +size_t WILDCARD_SUBJECT_ID_LEN = 1 ; + +//Ownership Transfer Methods +const char * OXM_JUST_WORKS = "oic.sec.doxm.jw"; +const char * OXM_MODE_SWITCH = "oic.sec.doxm.ms"; +const char * OXM_RANDOM_DEVICE_PIN = "oic.sec.doxm.rdp"; +const char * OXM_PRE_PROVISIONED_DEVICE_PIN = "oic.sec.doxm.ppdp"; +const char * OXM_PRE_PROVISIONED_STRONG_CREDENTIAL = "oic.sec.doxm.ppsc"; + diff --git a/resource/csdk/security/unittest/SConscript b/resource/csdk/security/unittest/SConscript new file mode 100644 index 0000000..7aea344 --- /dev/null +++ b/resource/csdk/security/unittest/SConscript @@ -0,0 +1,102 @@ +# //****************************************************************** +# // +# // 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. +# // +# //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +# + +Import('env') +import os +import os.path +srmtest_env = env.Clone() + +src_dir = srmtest_env.get('SRC_DIR') + +###################################################################### +# Build flags +###################################################################### +srmtest_env.PrependUnique(CPPPATH = [ + '../../ocmalloc/include', + '../../connectivity/inc', + '../../connectivity/api', + '../../connectivity/external/inc', + '../include', + '../include/internal', + '../../logger/include', + '../../ocmalloc/include', + '../../stack/include', + '../../stack/include/internal', + '../../../oc_logger/include', + '../../../../extlibs/gtest/gtest-1.7.0/include', + '../../../../extlibs/cjson/', + '../include' + ]) +srmtest_env.AppendUnique(CXXFLAGS = ['-std=c++0x', '-Wall', '-pthread']) +srmtest_env.AppendUnique(LIBS = ['-lpthread']) +srmtest_env.AppendUnique(LIBPATH = [env.get('BUILD_DIR')]) +srmtest_env.AppendUnique(LIBPATH = [src_dir + '/extlibs/gtest/gtest-1.7.0/lib/.libs']) +srmtest_env.PrependUnique(LIBS = ['ocsrm', + 'octbstack', + 'oc_logger', + 'connectivity_abstraction', + 'coap', + 'gtest', + 'gtest_main']) + +if env.get('SECURED') == '1': + srmtest_env.AppendUnique(LIBS = ['tinydtls']) + +if not env.get('RELEASE'): + srmtest_env.AppendUnique(CPPDEFINES = ['TB_LOG']) + +###################################################################### +# Source files and Targets +###################################################################### +unittest = srmtest_env.Program('unittest', ['aclresourcetest.cpp', + 'pstatresource.cpp', + 'doxmresource.cpp', + 'policyengine.cpp', + 'securityresourcemanager.cpp', + 'credentialresource.cpp', + 'base64tests.cpp']) + +Alias("test", [unittest]) + +unittest_src_dir = src_dir + '/resource/csdk/security/unittest/' +unittest_build_dir = env.get('BUILD_DIR') +'/resource/csdk/security/unittest' + +srmtest_env.Alias("install", srmtest_env.Install( unittest_build_dir, + unittest_src_dir + 'oic_unittest.json')) +srmtest_env.Alias("install", srmtest_env.Install( unittest_build_dir, + unittest_src_dir + 'oic_unittest_acl1.json')) +srmtest_env.Alias("install", srmtest_env.Install( unittest_build_dir, + unittest_src_dir + 'oic_unittest_default_acl.json')) + +env.AppendTarget('test') +if env.get('TEST') == '1': + target_os = env.get('TARGET_OS') + if target_os == 'linux': + out_dir = env.get('BUILD_DIR') + result_dir = env.get('BUILD_DIR') + '/test_out/' + if not os.path.isdir(result_dir): + os.makedirs(result_dir) + srmtest_env.AppendENVPath('GTEST_OUTPUT', ['xml:'+ result_dir]) + srmtest_env.AppendENVPath('LD_LIBRARY_PATH', [out_dir]) + srmtest_env.AppendENVPath('LD_LIBRARY_PATH', ['./extlibs/gtest/gtest-1.7.0/lib/.libs']) + ut = srmtest_env.Command ('ut', None, out_dir + '/resource/csdk/security/unittest/unittest') + AlwaysBuild ('ut') + diff --git a/resource/csdk/security/unittest/aclresourcetest.cpp b/resource/csdk/security/unittest/aclresourcetest.cpp new file mode 100644 index 0000000..0e6f5b7 --- /dev/null +++ b/resource/csdk/security/unittest/aclresourcetest.cpp @@ -0,0 +1,253 @@ +//****************************************************************** +// +// 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 "aclresource.h" + +using namespace std; + +#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, + OCEntityHandlerRequest * ehRequest); +#ifdef __cplusplus +} +#endif + +const char* JSON_FILE_NAME = "oic_unittest.json"; +const char* DEFAULT_ACL_JSON_FILE_NAME = "oic_unittest_default_acl.json"; +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) +{ + char *jsonStr1 = ReadFile(ACL1_JSON_FILE_NAME); + if (jsonStr1) + { + cJSON_Minify(jsonStr1); + /* Workaround : cJSON_Minify does not remove all the unwanted characters + from the end. Here is an attempt to remove those characters */ + int len = strlen(jsonStr1); + while (len > 0) + { + if (jsonStr1[--len] == '}') + { + break; + } + } + jsonStr1[len + 1] = 0; + + OicSecAcl_t * acl = JSONToAclBin(jsonStr1); + EXPECT_TRUE(NULL != acl); + + char * jsonStr2 = BinToAclJSON(acl); + EXPECT_TRUE(NULL != jsonStr2); + + if (jsonStr1 && jsonStr2) + { + EXPECT_STREQ(jsonStr1, jsonStr2); + } + + OICFree(jsonStr1); + OICFree(jsonStr2); + DeleteACLList(acl); + } +} + +// Default ACL tests +TEST(ACLResourceTest, GetDefaultACLTests) +{ + // Read default ACL from the file + char *jsonStr = ReadFile(DEFAULT_ACL_JSON_FILE_NAME); + if (jsonStr) + { + OicSecAcl_t * acl = JSONToAclBin(jsonStr); + EXPECT_TRUE(NULL != acl); + + // Invoke API to generate default ACL + OicSecAcl_t * defaultAcl = NULL; + OCStackResult ret = GetDefaultACL(&defaultAcl); + EXPECT_TRUE(NULL == defaultAcl); + + EXPECT_TRUE(OC_STACK_ERROR == ret); + + // Verify if the SRM generated default ACL matches with unit test default + if (acl && defaultAcl) + { + EXPECT_TRUE(memcmp(&(acl->subject), &(defaultAcl->subject), sizeof(OicUuid_t)) == 0); + EXPECT_EQ(acl->resourcesLen, defaultAcl->resourcesLen); + for (size_t i = 0; i < acl->resourcesLen; i++) + { + EXPECT_EQ(strlen(acl->resources[i]), strlen(defaultAcl->resources[i])); + EXPECT_TRUE( + memcmp(acl->resources[i], defaultAcl->resources[i], + strlen(acl->resources[i])) == 0); + } + EXPECT_EQ(acl->permission, defaultAcl->permission); + } + + // Perform cleanup + DeleteACLList(acl); + DeleteACLList(defaultAcl); + OICFree(jsonStr); + } +} + + +// 'POST' ACL tests +TEST(ACLResourceTest, ACLPostTest) +{ + OCEntityHandlerRequest ehReq = {}; + + // Read an ACL from the file + char *jsonStr = ReadFile(ACL1_JSON_FILE_NAME); + if (jsonStr) + { + static OCPersistentStorage ps = + { }; + SetPersistentHandler(&ps, true); + + // Create Entity Handler POST request payload + ehReq.method = OC_REST_POST; + ehReq.reqJSONPayload = jsonStr; + + OCEntityHandlerResult ehRet = ACLEntityHandler(OC_REQUEST_FLAG, &ehReq); + EXPECT_TRUE(OC_EH_ERROR == ehRet); + + // Convert JSON into OicSecAcl_t for verification + OicSecAcl_t * acl = JSONToAclBin(jsonStr); + EXPECT_TRUE(NULL != acl); + + // Verify if SRM contains ACL for the subject + OicSecAcl_t* savePtr = NULL; + const OicSecAcl_t* subjectAcl = GetACLResourceData(&(acl->subject), &savePtr); + EXPECT_TRUE(NULL != subjectAcl); + + // Perform cleanup + DeleteACLList(acl); + DeInitACLResource(); + OICFree(jsonStr); + } +} + + +// GetACLResource tests +TEST(ACLResourceTest, GetACLResourceTests) +{ + // gAcl is a pointer to the the global ACL used by SRM + extern OicSecAcl_t *gAcl; + + // Read an ACL from the file + char *jsonStr = ReadFile(ACL1_JSON_FILE_NAME); + if (jsonStr) + { + gAcl = JSONToAclBin(jsonStr); + EXPECT_TRUE(NULL != gAcl); + + // Verify that ACL file contains 2 ACE entries for 'WILDCARD' subject + const OicSecAcl_t* acl = NULL; + OicSecAcl_t* savePtr = NULL; + OicUuid_t subject = WILDCARD_SUBJECT_ID; + int count = 0; + + do + { + acl = GetACLResourceData(&subject, &savePtr); + count = (NULL != acl) ? count + 1 : count; + } while (acl != NULL); + + EXPECT_EQ(count, NUM_ACE_FOR_WILDCARD_IN_ACL1_JSON); + + /* Perform cleanup */ + DeleteACLList(gAcl); + gAcl = NULL; + OICFree(jsonStr); + } +} + diff --git a/resource/csdk/security/unittest/base64tests.cpp b/resource/csdk/security/unittest/base64tests.cpp new file mode 100644 index 0000000..4cce483 --- /dev/null +++ b/resource/csdk/security/unittest/base64tests.cpp @@ -0,0 +1,260 @@ + /****************************************************************** + * + * 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 "base64.h" +#include +#include + +// Tests for base64 encode function +TEST(B64EncodeTest, ValidInputForEncoding) +{ + char buf[128]; + uint32_t outputLength; + uint32_t expectedLength; + uint32_t i=0; + B64Result res = B64_OK; + + const char* input = "IoTivity base64~!@#$%^&*()-=0123456789<>?;:'[]{},.\"\\|"; + + /**< expected output is generated from + "http://www.convertstring.com/EncodeDecode/Base64Encode" */ + const char* expectedOutput[53] = { + "SQ==", + "SW8=", + "SW9U", + "SW9UaQ==", + "SW9UaXY=", + "SW9UaXZp", + "SW9UaXZpdA==", + "SW9UaXZpdHk=", + "SW9UaXZpdHkg", + "SW9UaXZpdHkgYg==", + "SW9UaXZpdHkgYmE=", + "SW9UaXZpdHkgYmFz", + "SW9UaXZpdHkgYmFzZQ==", + "SW9UaXZpdHkgYmFzZTY=", + "SW9UaXZpdHkgYmFzZTY0", + "SW9UaXZpdHkgYmFzZTY0fg==", + "SW9UaXZpdHkgYmFzZTY0fiE=", + "SW9UaXZpdHkgYmFzZTY0fiFA", + "SW9UaXZpdHkgYmFzZTY0fiFAIw==", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQ=", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQl", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXg==", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiY=", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYq", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKA==", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCk=", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCkt", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPQ==", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTA=", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAx", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMg==", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM=", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NQ==", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY=", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3OA==", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3ODk=", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3ODk8", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3ODk8Pg==", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3ODk8Pj8=", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3ODk8Pj87", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3ODk8Pj87Og==", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3ODk8Pj87Oic=", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3ODk8Pj87Oidb", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3ODk8Pj87OidbXQ==", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3ODk8Pj87OidbXXs=", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3ODk8Pj87OidbXXt9", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3ODk8Pj87OidbXXt9LA==", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3ODk8Pj87OidbXXt9LC4=", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3ODk8Pj87OidbXXt9LC4i", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3ODk8Pj87OidbXXt9LC4iXA==", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3ODk8Pj87OidbXXt9LC4iXHw=" + }; + + for(i=0; i< strlen(input); i++) + { + memset(buf, 0, sizeof(buf)); + + expectedLength = strlen(expectedOutput[i]); + + res = b64Encode((uint8_t*)input, i + 1, buf, 128, &outputLength); + + EXPECT_EQ(B64_OK, res); + EXPECT_EQ(expectedLength, outputLength); + EXPECT_EQ(0, strcmp(expectedOutput[i], buf)); + } +} + +// Tests for base64 decode function +TEST(B64DeodeTest, ValidInputForDecoding) +{ + uint8_t buf[128]; + uint32_t outputLength; + uint32_t i=0; + B64Result res = B64_OK; + + const char* input[53] = { + "SQ==", + "SW8=", + "SW9U", + "SW9UaQ==", + "SW9UaXY=", + "SW9UaXZp", + "SW9UaXZpdA==", + "SW9UaXZpdHk=", + "SW9UaXZpdHkg", + "SW9UaXZpdHkgYg==", + "SW9UaXZpdHkgYmE=", + "SW9UaXZpdHkgYmFz", + "SW9UaXZpdHkgYmFzZQ==", + "SW9UaXZpdHkgYmFzZTY=", + "SW9UaXZpdHkgYmFzZTY0", + "SW9UaXZpdHkgYmFzZTY0fg==", + "SW9UaXZpdHkgYmFzZTY0fiE=", + "SW9UaXZpdHkgYmFzZTY0fiFA", + "SW9UaXZpdHkgYmFzZTY0fiFAIw==", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQ=", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQl", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXg==", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiY=", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYq", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKA==", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCk=", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCkt", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPQ==", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTA=", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAx", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMg==", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM=", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NQ==", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY=", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3OA==", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3ODk=", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3ODk8", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3ODk8Pg==", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3ODk8Pj8=", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3ODk8Pj87", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3ODk8Pj87Og==", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3ODk8Pj87Oic=", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3ODk8Pj87Oidb", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3ODk8Pj87OidbXQ==", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3ODk8Pj87OidbXXs=", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3ODk8Pj87OidbXXt9", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3ODk8Pj87OidbXXt9LA==", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3ODk8Pj87OidbXXt9LC4=", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3ODk8Pj87OidbXXt9LC4i", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3ODk8Pj87OidbXXt9LC4iXA==", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3ODk8Pj87OidbXXt9LC4iXHw=" + }; + const char* expectedOutput = "IoTivity base64~!@#$%^&*()-=0123456789<>?;:'[]{},.\"\\|"; + + for(i=0; i< (sizeof(input)/sizeof(char*)); i++) + { + memset(buf, 0, sizeof(buf)); + + res = b64Decode(input[i], strlen(input[i]), buf, 128, &outputLength); + + EXPECT_EQ(B64_OK, res); + EXPECT_EQ(i + 1, outputLength); + EXPECT_EQ(0, memcmp(expectedOutput, buf, i + 1)); + } +} + +// Tests for base64 decode function +TEST(B64DeodeTest, InvalidInputForDecoding) +{ + uint8_t buf[128]; + uint32_t outputLength; + uint32_t i=0; + + const char* input[53] = { + "SQ=", + "Sw8=", + "SW1U", + "SW9Uaq==", + "SW9uaXY=", + "SW91UaXZp", + "SW9UaXZpdA.==", + "Sw9UAXZpdHk=", + "SW9UAXZpdHkg", + "SW9UaXZpdhkgYg==", + "SW9UaXZpd5kgYmE=", + "SW9UaXZ1dHkgYmFz", + "SW9UaXZpdHkgymFzZQ==", + "SW9UaXZpdHkgYmFzZTY==", + "SW9UaXZpdHkgYmFzZTY0=", + "SW9UaXZpdHkgYmFzZTY0fg=", + "SW9UaXZpdHkgYmFzZTY0fiE==", + "SW8UaXZpdHkgYmFzZTY0fiFA", + "SW9UaxzPDHkgYmFzZTY0fiFAIw==", + "SW9UaXZpdHKGYmFzZTY0fiFAIyQ=", + "SW9UaXZpdHkgYmFZztY0fiFAIyQl=", + "SW8UaXZpdHkgYmFzZTY0fiFAIyQlXg=", + "#SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiY=", + "SSW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYq", + "SW9UaXZpdHkgYmFzZTY0fiFAiyQlXiYqKA==", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCk===", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKckt", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKcktpQ==", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQiXiYqKCktPTA=", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAx=", + "SW9UaXZpdHkgYmFzZTY0fifAIyQlXiYqKCktPTAxmg=", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM#1=", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM1", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0Nq==", + "sw9uaxzpdhkgymfzzty0fifaiyqlxiyqKcktptaxmjm0nty=", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0nTY3", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3Ok==", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3OA==", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3ODk8Pg", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3ODk8Pg=", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjm0NTY3ODk8Pj9=", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXqKCktPTAxMjM0NTY3ODk8Pj87=", + "SW9UaXZpdHkgYmFzZTY0fiFaIyiYqKCktPTAxMjM0NTY3ODk8Pj87Og==", + "W9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3ODk8Pj87Oic1=", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCkTAxMjM0NTY3ODk8Pj87Oidb==", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYCktPTAxMjM0NTY3ODk8Pj87Oidbxq==", + "SW9UaXZpdHkgYmzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3ODk8Pj87Oidbxxs=", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCkPTAxMjM0NTY3ODk8Pj87OidbXXT9", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3ODk8Pj87OidbXXt9la==", + "SW9UaXZpdHkgYzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3ODk8Pj87OidbXXt9Lc4=", + "SW9UaXZpdHkgYmFzZ0fiFAIyQlXiYqKCktPTAxMjM0NTY3ODk8Pj87OidbXXt9lC4i", + "SW9UaXZpdHkgYmFzZTY0fiFAIyQlXiYqKCktPTAxMjM0NTY3ODk8Pj87OidbXXt9lc4iXA==", + "SW9UaXZpdHkgYmFzZTY0fiFqKCktPTAxMjM0NTY3ODk8Pj87OidbXXt9LC4ixHw=" + }; + const char* expectedOutput = "IoTivity base64~!@#$%^&*()-=0123456789<>?;:'[]{},.\"\\|"; + + for(i=0; i< (sizeof(input)/sizeof(char*)); i++) + { + memset(buf, 0, sizeof(buf)); + + if( B64_OK == b64Decode(input[i], strlen(input[i]), buf, 128, &outputLength) ) + { + EXPECT_NE(0, memcmp(expectedOutput, buf, i + 1)); + } + } +} + diff --git a/resource/csdk/security/unittest/credentialresource.cpp b/resource/csdk/security/unittest/credentialresource.cpp new file mode 100644 index 0000000..31c5b55 --- /dev/null +++ b/resource/csdk/security/unittest/credentialresource.cpp @@ -0,0 +1,216 @@ +// 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 "ocstack.h" +#include "resourcemanager.h" +#include "securevirtualresourcetypes.h" +#include "credresource.h" +#include "oic_malloc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//Declare Cred resource methods for testing +OCStackResult CreateCredResource(); +OCEntityHandlerResult CredEntityHandler (OCEntityHandlerFlag flag, + OCEntityHandlerRequest * ehRequest); +char * BinToCredJSON(const OicSecCred_t * pstat); +OicSecCred_t * JSONToCredBin(const char * jsonStr); +void InitSecCredInstance(OicSecCred_t * cred); +void DeleteCredList(OicSecCred_t* cred); +#ifdef __cplusplus +} +#endif + +OicSecCred_t * getCredList() +{ + OicSecCred_t * cred = (OicSecCred_t*)OICCalloc(1, sizeof(OicSecCred_t)); + cred->credId = 1234; + strcpy((char *)cred->subject.id, "subject1"); + +#if 0 + cred->roleIdsLen = 2; + cred->roleIds = (OicSecRole_t *)OICCalloc(cred->roleIdsLen, sizeof(OicSecRole_t)); + strcpy((char *)cred->roleIds[0].id, "role11"); + strcpy((char *)cred->roleIds[1].id, "role12"); +#endif + + cred->credType = 1; + cred->ownersLen = 1; + cred->owners = (OicUuid_t*)OICCalloc(cred->ownersLen, sizeof(OicUuid_t)); + strcpy((char *)cred->owners[0].id, "ownersId11"); + + cred->next = (OicSecCred_t*)OICCalloc(1, sizeof(OicSecCred_t)); + cred->next->credId = 5678; + strcpy((char *)cred->next->subject.id, "subject2"); +#if 0 + cred->next->roleIdsLen = 0; +#endif + cred->next->credType = 1; + cred->next->privateData.data = (char *)OICCalloc(1, strlen("My private Key21") + 1); + strcpy(cred->next->privateData.data, "My private Key21"); +#if 0 + cred->next->publicData.data = (char *)OICCalloc(1, strlen("My Public Key123") + 1); + strcpy(cred->next->publicData.data, "My Public Key123"); +#endif + cred->next->ownersLen = 2; + cred->next->owners = (OicUuid_t*)OICCalloc(cred->next->ownersLen, sizeof(OicUuid_t)); + strcpy((char *)cred->next->owners[0].id, "ownersId21"); + strcpy((char *)cred->next->owners[1].id, "ownersId22"); + return cred; +} + + //InitCredResource Tests +TEST(InitCredResourceTest, InitCredResource) +{ + EXPECT_EQ(OC_STACK_INVALID_PARAM, InitCredResource()); +} + +//DeInitCredResource Tests +TEST(DeInitCredResourceTest, DeInitCredResource) +{ + EXPECT_EQ(OC_STACK_INVALID_PARAM, DeInitCredResource()); +} + +//CreateCredResource Tests +TEST(CreateCredResourceTest, CreateCredResource) +{ + EXPECT_EQ(OC_STACK_INVALID_PARAM, CreateCredResource()); +} + + //CredEntityHandler Tests +TEST(CredEntityHandlerTest, CredEntityHandlerWithDummyRequest) +{ + OCEntityHandlerRequest 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)); +} + +TEST(CredEntityHandlerTest, CredEntityHandlerInvalidFlag) +{ + OCEntityHandlerRequest req; + EXPECT_EQ(OC_EH_ERROR, CredEntityHandler(OCEntityHandlerFlag::OC_OBSERVE_FLAG, &req)); +} + +//BinToCredJSON Tests +TEST(BinToCredJSONTest, BinToCredJSONNullCred) +{ + char* value = BinToCredJSON(NULL); + EXPECT_TRUE(value == NULL); +} + +TEST(BinToCredJSONTest, BinToCredJSONValidCred) +{ + char* json = NULL; + OicSecCred_t * cred = getCredList(); + + json = BinToCredJSON(cred); + + printf("BinToCredJSON:%s\n", json); + EXPECT_TRUE(json != NULL); + DeleteCredList(cred); + OICFree(json); +} + +//JSONToCredBin Tests +TEST(JSONToCredBinTest, JSONToCredBinValidJSON) +{ + OicSecCred_t* cred1 = getCredList(); + char* json = BinToCredJSON(cred1); + + EXPECT_TRUE(json != NULL); + OicSecCred_t *cred2 = JSONToCredBin(json); + EXPECT_TRUE(cred2 == NULL); + DeleteCredList(cred1); + DeleteCredList(cred2); + OICFree(json); +} + +TEST(JSONToCredBinTest, JSONToCredBinNullJSON) +{ + OicSecCred_t *cred = JSONToCredBin(NULL); + EXPECT_TRUE(cred == NULL); +} + +//GetCredResourceData Test +TEST(CredGetResourceDataTest, GetCredResourceDataNULLSubject) +{ + EXPECT_TRUE(NULL == GetCredResourceData(NULL)); +} + +TEST(CredGenerateCredentialTest, GenerateCredentialValidInput) +{ + OicUuid_t owners[1]; + strcpy((char *)owners[0].id, "ownersId21"); + + OicUuid_t subject = {}; + strcpy((char *)subject.id, "subject11"); + + char privateKey[] = "My private Key11"; + + OicSecCred_t * cred = NULL; + + cred = GenerateCredential(&subject, SYMMETRIC_PAIR_WISE_KEY, NULL, + privateKey, 1, owners); + printf("cred->credId = %d\n", cred->credId); + printf("cred->subject.id = %s\n", cred->subject.id); + printf("cred->credType = %d\n", cred->credType); + printf("cred->privateData.data = %s\n", cred->privateData.data); + printf("cred->ownersLen = %zd\n", cred->ownersLen); + printf("cred->owners[0].id = %s\n", cred->owners[0].id); + + EXPECT_TRUE(NULL != cred); + DeleteCredList(cred); +} + +TEST(CredAddCredentialTest, GenerateCredentialValidInput) +{ + OicUuid_t owners[1]; + strcpy((char *)owners[0].id, "ownersId21"); + + OicUuid_t subject = {}; + strcpy((char *)subject.id, "subject11"); + + char privateKey[] = "My private Key11"; + + OicSecCred_t * cred = NULL; + + cred = GenerateCredential(&subject, SYMMETRIC_PAIR_WISE_KEY, NULL, + privateKey, 1, owners); + EXPECT_TRUE(NULL != cred); + + EXPECT_EQ(OC_STACK_ERROR, AddCredential(cred)); + + DeleteCredList(cred); + +} +#if 0 +TEST(CredGetResourceDataTest, GetCredResourceDataValidSubject) +{ + OicSecCred_t* cred = getCredList(); + EXPECT_TRUE(NULL != GetCredResourceData(cred->subject)); +} +#endif + + diff --git a/resource/csdk/security/unittest/doxmresource.cpp b/resource/csdk/security/unittest/doxmresource.cpp new file mode 100644 index 0000000..13e03b7 --- /dev/null +++ b/resource/csdk/security/unittest/doxmresource.cpp @@ -0,0 +1,163 @@ +// 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 "ocstack.h" +#include "resourcemanager.h" +#include "securevirtualresourcetypes.h" +#include "srmresourcestrings.h" +#include "doxmresource.h" +#include "ocserverrequest.h" +#include "oic_malloc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//Declare Doxm resource methods for testing +OCStackResult CreateDoxmResource(); +OCEntityHandlerResult DoxmEntityHandler (OCEntityHandlerFlag flag, + OCEntityHandlerRequest * ehRequest); +char * BinToDoxmJSON(const OicSecDoxm_t * doxm); +OicSecDoxm_t * JSONToDoxmBin(const char * jsonStr); +void InitSecDoxmInstance(OicSecDoxm_t * doxm); +OCEntityHandlerResult HandleDoxmPostRequest (const OCEntityHandlerRequest * ehRequest); +void DeleteDoxmBinData(OicSecDoxm_t* doxm); +#ifdef __cplusplus +} +#endif + +OicSecDoxm_t * getBinDoxm() +{ + OicSecDoxm_t * doxm = (OicSecDoxm_t*)OICCalloc(1, sizeof(OicSecDoxm_t)); + doxm->oxmTypeLen = 1; + doxm->oxmType = (OicUrn_t *)OICCalloc(doxm->oxmTypeLen, sizeof(char *)); + doxm->oxmType[0] = (char*)OICMalloc(strlen(OXM_JUST_WORKS) + 1); + strcpy(doxm->oxmType[0], OXM_JUST_WORKS); + doxm->oxmLen = 1; + doxm->oxm = (OicSecOxm_t *)OICCalloc(doxm->oxmLen, sizeof(short)); + doxm->oxm[0] = OIC_JUST_WORKS; + doxm->oxmSel = OIC_JUST_WORKS; + doxm->owned = true; + //TODO: Need more clarification on deviceIDFormat field type. + //doxm.deviceIDFormat = URN; + strcpy((char *) doxm->deviceID.id, "deviceId"); + strcpy((char *)doxm->owner.id, "ownersId"); + return doxm; +} + + //InitDoxmResource Tests +TEST(InitDoxmResourceTest, InitDoxmResource) +{ + EXPECT_EQ(OC_STACK_INVALID_PARAM, InitDoxmResource()); +} + +//DeInitDoxmResource Tests +TEST(DeInitDoxmResourceTest, DeInitDoxmResource) +{ + EXPECT_EQ(OC_STACK_ERROR, DeInitDoxmResource()); +} + +//CreateDoxmResource Tests +TEST(CreateDoxmResourceTest, CreateDoxmResource) +{ + EXPECT_EQ(OC_STACK_INVALID_PARAM, CreateDoxmResource()); +} + + //DoxmEntityHandler Tests +TEST(DoxmEntityHandlerTest, DoxmEntityHandlerWithDummyRequest) +{ + OCEntityHandlerRequest req; + EXPECT_EQ(OC_EH_ERROR, DoxmEntityHandler(OCEntityHandlerFlag::OC_REQUEST_FLAG, &req)); +} + +TEST(DoxmEntityHandlerTest, DoxmEntityHandlerWithNULLRequest) +{ + EXPECT_EQ(OC_EH_ERROR, DoxmEntityHandler(OCEntityHandlerFlag::OC_REQUEST_FLAG, NULL)); +} + +TEST(DoxmEntityHandlerTest, DoxmEntityHandlerInvalidFlag) +{ + OCEntityHandlerRequest req; + EXPECT_EQ(OC_EH_ERROR, DoxmEntityHandler(OCEntityHandlerFlag::OC_OBSERVE_FLAG, &req)); +} + +//BinToDoxmJSON Tests +TEST(BinToDoxmJSONTest, BinToDoxmJSONNullDoxm) +{ + char* value = BinToDoxmJSON(NULL); + EXPECT_TRUE(value == NULL); +} + +TEST(BinToDoxmJSONTest, BinToDoxmJSONValidDoxm) +{ + OicSecDoxm_t * doxm = getBinDoxm(); + + char * json = BinToDoxmJSON(doxm); + printf("BinToDoxmJSON:%s\n", json); + EXPECT_TRUE(json != NULL); + + DeleteDoxmBinData(doxm); + OICFree(json); +} + +//JSONToDoxmBin Tests +TEST(JSONToDoxmBinTest, JSONToDoxmBinValidJSON) +{ + OicSecDoxm_t * doxm1 = getBinDoxm(); + char * json = BinToDoxmJSON(doxm1); + EXPECT_TRUE(json != NULL); + + OicSecDoxm_t *doxm2 = JSONToDoxmBin(json); + EXPECT_TRUE(doxm2 != NULL); + + DeleteDoxmBinData(doxm1); + OICFree(json); +} + +TEST(JSONToDoxmBinTest, JSONToDoxmBinNullJSON) +{ + OicSecDoxm_t *doxm = JSONToDoxmBin(NULL); + EXPECT_TRUE(doxm == NULL); +} + +//GetDoxmResourceData Test +TEST(DoxmGetResourceDataTest, GetDoxmResourceData) +{ + EXPECT_TRUE(NULL == GetDoxmResourceData()); +} +#if 0 +TEST(HandleDoxmPostRequestTest, HandleDoxmPostRequestValidInput) +{ + OCEntityHandlerRequest ehRequest = {}; + OCServerRequest svRequest = {}; + + OicSecDoxm_t * doxm = getBinDoxm(); + + strcpy(svRequest.addressInfo.IP.ipAddress, "10.10.10.10"); + svRequest.addressInfo.IP.port = 2345; + svRequest.connectivityType = CA_ETHERNET; + + ehRequest.reqJSONPayload = (unsigned char *) BinToDoxmJSON(doxm); + ehRequest.requestHandle = (OCRequestHandle) &svRequest; + + EXPECT_EQ(OC_EH_ERROR, HandleDoxmPostRequest(&ehRequest)); + DeleteDoxmBinData(doxm); + OICFree(ehRequest.reqJSONPayload); +} +#endif diff --git a/resource/csdk/security/unittest/oic_svr_db.json b/resource/csdk/security/unittest/oic_svr_db.json new file mode 100644 index 0000000..721a8bf --- /dev/null +++ b/resource/csdk/security/unittest/oic_svr_db.json @@ -0,0 +1,45 @@ +{ + "acl": [ + { + "sub": "Kg==", + "rsrc": [ + "/oic/res", + "/oic/d", + "/oic/p", + "/oic/res/types/d", + "/oic/ad" + ], + "perms": 2, + "ownrs" : [ + "MjIyMjIyMjIyMjIyMjIyMg==" + ] + }, + { + "sub": "Kg==", + "rsrc": [ + "/oic/sec/doxm", + "/oic/sec/pstat", + "/oic/sec/acl" + ], + "perms": 6, + "ownrs" : [ + "MjIyMjIyMjIyMjIyMjIyMg==" + ] + } + ], + "pstat": { + "isop": false, + "deviceid": "ZGV2aWNlaWQAAAAAABhanw==", + "commithash": 0, + "cm": 0, + "tm": 0, + "om": 3, + "sm": [3] + }, + "doxm": { + "oxm": [0], + "oxmsel": 0, + "owned": false, + "deviceid": "MjIyMjIyMjIyMjIyMjIyMg==" + } +} diff --git a/resource/csdk/security/unittest/oic_unittest.json b/resource/csdk/security/unittest/oic_unittest.json new file mode 100644 index 0000000..7663880 --- /dev/null +++ b/resource/csdk/security/unittest/oic_unittest.json @@ -0,0 +1,37 @@ +{ + "acl": [ + { + "sub": "MTExMTExMTExMTExMTExMQ==", + "rsrc": [ + "/oic/light", + "/oic/fan" + ], + "perms": 255, + "ownrs" : [ + "MjIyMjIyMjIyMjIyMjIyMg==" + ] + }, + { + "sub": "MzMzMzMzMzMzMzMzMzMzMw==", + "rsrc": [ + "/oic/light", + "/oic/garage" + ], + "perms": 255, + "ownrs" : [ + "MjIyMjIyMjIyMjIyMjIyMg==", + "NDQ0NDQ0NDQ0NDQ0NDQ0NA==" + ] + } + ], + + "pstat": { + "isop": false, + "deviceid": "ZGV2aWNlaWQAAAAAABhanw==", + "commithash": 1234, + "cm": 63, + "tm": 48, + "om": 0, + "sm": [3, 1] + } +} diff --git a/resource/csdk/security/unittest/oic_unittest_acl1.json b/resource/csdk/security/unittest/oic_unittest_acl1.json new file mode 100644 index 0000000..a179c2c --- /dev/null +++ b/resource/csdk/security/unittest/oic_unittest_acl1.json @@ -0,0 +1,53 @@ +{ + "acl": [ + { + "sub": "Kg==", + "rsrc": [ + "/oic/res", + "/oic/d", + "/oic/p", + "/oic/res/types/d", + "/oic/ad", + "/oic/sec/acl" + ], + "perms": 2, + "ownrs" : [ + "MjIyMjIyMjIyMjIyMjIyMg==" + ] + }, + { + "sub": "Kg==", + "rsrc": [ + "/oic/sec/doxm", + "/oic/sec/pstat" + ], + "perms": 6, + "ownrs" : [ + "MjIyMjIyMjIyMjIyMjIyMg==" + ] + }, + { + "sub": "MTExMTExMTExMTExMTExMQ==", + "rsrc": [ + "/oic/light", + "/oic/fan" + ], + "perms": 255, + "ownrs" : [ + "MjIyMjIyMjIyMjIyMjIyMg==" + ] + }, + { + "sub": "MzMzMzMzMzMzMzMzMzMzMw==", + "rsrc": [ + "/oic/light", + "/oic/garage" + ], + "perms": 255, + "ownrs" : [ + "MjIyMjIyMjIyMjIyMjIyMg==", + "NDQ0NDQ0NDQ0NDQ0NDQ0NA==" + ] + } + ] +} diff --git a/resource/csdk/security/unittest/oic_unittest_default_acl.json b/resource/csdk/security/unittest/oic_unittest_default_acl.json new file mode 100644 index 0000000..7f3d449 --- /dev/null +++ b/resource/csdk/security/unittest/oic_unittest_default_acl.json @@ -0,0 +1,21 @@ +{ + "acl": [ + { + "sub": "Kg==", + "rsrc": [ + "/oic/res", + "/oic/d", + "/oic/p", + "/oic/res/types/d", + "/oic/ad", + "/oic/sec/acl", + "/oic/sec/doxm", + "/oic/sec/pstat" + ], + "perms": 2, + "ownrs" : [ + "MjIyMjIyMjIyMjIyMjIyMg==" + ] + } + ] +} diff --git a/resource/csdk/security/unittest/policyengine.cpp b/resource/csdk/security/unittest/policyengine.cpp new file mode 100644 index 0000000..8ad43a8 --- /dev/null +++ b/resource/csdk/security/unittest/policyengine.cpp @@ -0,0 +1,110 @@ +//****************************************************************** +// +// 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 "ocstack.h" +#include "cainterface.h" +#include "srmresourcestrings.h" + +using namespace std; + +#define PE_UT_TAG "\tPE-UT-message: " + +#ifdef __cplusplus +extern "C" { +#endif + +#include "policyengine.h" +#include "doxmresource.h" + +// test parameters +PEContext_t g_peContext; + +#ifdef __cplusplus +} +#endif + +OicUuid_t g_subjectIdA = {"SubjectA"}; +OicUuid_t g_subjectIdB = {"SubjectB"}; +OicUuid_t g_devOwner; +char g_resource1[] = "Resource1"; +char g_resource2[] = "Resource2"; + +//Policy Engine Core Tests +TEST(PolicyEngineCore, InitPolicyEngine) +{ + EXPECT_EQ(OC_STACK_OK, InitPolicyEngine(&g_peContext)); +} + +TEST(PolicyEngineCore, CheckPermissionNoAcls) +{ + EXPECT_EQ(ACCESS_DENIED_SUBJECT_NOT_FOUND, + CheckPermission(&g_peContext, + &g_subjectIdA, + g_resource1, + PERMISSION_READ)); +} + +//TODO This won't work until we figure out how to OcInit() or equivalent. +TEST(PolicyEngineCore, CheckDevOwnerRequest) +{ + if(OC_STACK_OK == InitDoxmResource()) + { + if(OC_STACK_OK == GetDoxmDevOwnerId(&g_devOwner)) + { + printf("%s", PE_UT_TAG); + for(int i = 0; i < UUID_LENGTH; i++) + { + printf("%d", g_devOwner.id[i]); + } + printf("\n"); + EXPECT_EQ(ACCESS_GRANTED, + CheckPermission(&g_peContext, + &g_devOwner, + g_resource1, + PERMISSION_FULL_CONTROL)); + } + else + { + printf("%s WARNING: InitDoxmResource() returned ERROR!\n", \ + PE_UT_TAG); + } + } + else + { + printf("%s WARNING: GetDoxmDevOwnerId() returned ERROR!\n", PE_UT_TAG); + } + + +} + +TEST(PolicyEngineCore, DeInitPolicyEngine) +{ + DeInitPolicyEngine(&g_peContext); + EXPECT_EQ(STOPPED, g_peContext.state); + EXPECT_EQ(NULL, g_peContext.subject); + EXPECT_EQ(NULL, g_peContext.resource); + EXPECT_EQ((uint16_t)0, g_peContext.permission); + EXPECT_FALSE(g_peContext.matchingAclFound); + EXPECT_EQ(ACCESS_DENIED_POLICY_ENGINE_ERROR, g_peContext.retVal); +} diff --git a/resource/csdk/security/unittest/pstatresource.cpp b/resource/csdk/security/unittest/pstatresource.cpp new file mode 100644 index 0000000..dcdac77 --- /dev/null +++ b/resource/csdk/security/unittest/pstatresource.cpp @@ -0,0 +1,159 @@ +//****************************************************************** +// +// 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 "ocstack.h" +#include "resourcemanager.h" +#include "pstatresource.h" +#include "oic_malloc.h" +#include "cJSON.h" +#include "base64.h" +#include "cainterface.h" +#include "secureresourcemanager.h" +#include +#ifdef __cplusplus +extern "C" { +#endif +//Declare Provision status resource methods for testing +OCStackResult CreatePstatResource(); +OCEntityHandlerResult PstatEntityHandler (OCEntityHandlerFlag flag, + OCEntityHandlerRequest * ehRequest); +char * BinToPstatJSON(const OicSecPstat_t * pstat); +OicSecPstat_t * JSONToPstatBin(const char * jsonStr); +char* ReadFile(const char* filename); +extern char* JSON_FILE_NAME; +#ifdef __cplusplus +} +#endif + +//InitPstatResource Tests +TEST(InitPstatResourceTest, InitPstatResource) +{ + EXPECT_EQ(OC_STACK_INVALID_PARAM, InitPstatResource()); +} + + +//DeInitPstatResource Tests +TEST(DeInitPstatResourceTest, DeInitPstatResource) +{ + EXPECT_EQ(OC_STACK_INVALID_PARAM, DeInitPstatResource()); +} + +//CreatePstatResource Tests +TEST(CreatePstatResourceTest, CreatePstatResource) +{ + EXPECT_EQ(OC_STACK_INVALID_PARAM, CreatePstatResource()); +} + +//PstatEntityHandler Tests +TEST(PstatEntityHandlerTest, PstatEntityHandlerWithDummyRequest) +{ + OCEntityHandlerRequest req; + EXPECT_EQ(OC_EH_ERROR, PstatEntityHandler(OCEntityHandlerFlag::OC_REQUEST_FLAG, &req)); +} + +TEST(PstatEntityHandlerTest, PstatEntityHandlerWithPostRequest) +{ + OCEntityHandlerRequest req; + req.method = OC_REST_POST; + req.reqJSONPayload = (char*)"{ \"pstat\": { \"tm\": 0, \"om\": 3 }}"; + EXPECT_EQ(OC_EH_ERROR, PstatEntityHandler(OCEntityHandlerFlag::OC_REQUEST_FLAG, &req)); +} + +TEST(PstatEntityHandlerTest, PstatEntityHandlerInvalidRequest) +{ + EXPECT_EQ(OC_EH_ERROR, PstatEntityHandler(OCEntityHandlerFlag::OC_OBSERVE_FLAG, NULL)); +} + +//BinToJSON Tests +TEST(BinToJSONTest, BinToNullJSON) +{ + char* value = BinToPstatJSON(NULL); + EXPECT_TRUE(value == NULL); +} + +TEST(JSONToBinTest, NullJSONToBin) +{ + OicSecPstat_t *pstat1 = JSONToPstatBin(NULL); + EXPECT_TRUE(pstat1 == NULL); +} + +TEST(MarshalingAndUnMarshalingTest, BinToPstatJSONAndJSONToPstatBin) +{ + const char* id = "ZGV2aWNlaWQAAAAAABhanw=="; + OicSecPstat_t pstat; + pstat.cm = NORMAL; + pstat.commitHash = 0; + uint32_t outLen = 0; + unsigned char base64Buff[sizeof(((OicUuid_t*) 0)->id)] = {}; + EXPECT_EQ(B64_OK, b64Decode(id, strlen(id), base64Buff, sizeof(base64Buff), &outLen)); + memcpy(pstat.deviceID.id, base64Buff, outLen); + pstat.isOp = true; + pstat.tm = NORMAL; + pstat.om = SINGLE_SERVICE_CLIENT_DRIVEN; + pstat.smLen = 2; + pstat.sm = (OicSecDpom_t*)OICCalloc(pstat.smLen, sizeof(OicSecDpom_t)); + pstat.sm[0] = SINGLE_SERVICE_CLIENT_DRIVEN; + pstat.sm[1] = SINGLE_SERVICE_SERVER_DRIVEN; + char* jsonPstat = BinToPstatJSON(&pstat); + printf("BinToJSON Dump:\n%s\n\n", jsonPstat); + EXPECT_TRUE(jsonPstat != NULL); + OicSecPstat_t *pstat1 = JSONToPstatBin(jsonPstat); + EXPECT_TRUE(pstat1 != NULL); + OICFree(pstat1->sm); + OICFree(pstat1); + OICFree(jsonPstat); + OICFree(pstat.sm); +} + +TEST(PstatTests, JSONMarshalliingTests) +{ + char *jsonStr1 = ReadFile(JSON_FILE_NAME); + if (NULL != jsonStr1) + { + cJSON_Minify(jsonStr1); + /* Workaround : cJSON_Minify does not remove all the unwanted characters + from the end. Here is an attempt to remove those characters */ + int len = strlen(jsonStr1); + while (len > 0) + { + if (jsonStr1[--len] == '}') + { + break; + } + } + jsonStr1[len + 1] = 0; + + OicSecPstat_t* pstat = JSONToPstatBin(jsonStr1); + EXPECT_TRUE(NULL != pstat); + + char* jsonStr2 = BinToPstatJSON(pstat); + printf("BinToPstatJSON Dump:\n%s\n\n", jsonStr2); + EXPECT_STRNE(jsonStr1, jsonStr2); + + OICFree(jsonStr1); + OICFree(jsonStr2); + OICFree(pstat); + } + else + { + printf("Please copy %s into unittest folder\n", JSON_FILE_NAME); + } +} diff --git a/resource/csdk/security/unittest/securityresourcemanager.cpp b/resource/csdk/security/unittest/securityresourcemanager.cpp new file mode 100644 index 0000000..2259e41 --- /dev/null +++ b/resource/csdk/security/unittest/securityresourcemanager.cpp @@ -0,0 +1,156 @@ +//****************************************************************** +// +// 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 "ocstack.h" +#include "cainterface.h" +#include "secureresourcemanager.h" + +using namespace std; + +// Helper Methods +void UTRequestHandler(const CARemoteEndpoint_t *endPoint, const CARequestInfo_t *requestInfo) +{ + EXPECT_TRUE(true) << "UTRequestHandler\n"; +} + +void UTResponseHandler(const CARemoteEndpoint_t *endPoint, const CAResponseInfo_t *responseInfo) +{ + EXPECT_TRUE(true) << "UTResponseHandler\n"; +} + +void UTErrorHandler(const CARemoteEndpoint_t *endPoint, const CAErrorInfo_t *errorInfo) +{ + EXPECT_TRUE(true) << "UTErrorHandler\n"; +} + +FILE *utopen(const char *path, const char *mode) +{ + EXPECT_TRUE((path != NULL)) << "utopen\n"; + FILE *stream = fopen(path, mode); + return stream; + +} + +size_t utread(void *ptr, size_t size, size_t nmemb, FILE *stream) +{ + return fread(ptr, size, nmemb, stream); +} + +size_t utwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) +{ + return fwrite(ptr, size, nmemb, stream); +} + +int utclose(FILE *fp) +{ + EXPECT_TRUE((fp != NULL)) << "utclose\n"; + return fclose(fp); +} +int utunlink(const char *path) +{ + EXPECT_TRUE((path != NULL)) << "utunlink\n"; + return unlink(path); +} +static OCPersistentStorage gpsi; + +//RegisterHandler Tests +TEST(RegisterHandlerTest, RegisterNullRequestHandler) +{ + EXPECT_EQ(OC_STACK_INVALID_PARAM, SRMRegisterHandler(NULL, UTResponseHandler, NULL)); +} + +TEST(RegisterHandlerTest, RegisterNullResponseHandler) +{ + EXPECT_EQ(OC_STACK_INVALID_PARAM, SRMRegisterHandler(UTRequestHandler, NULL, NULL)); +} + +TEST(RegisterHandlerTest, RegisterNullHandler) +{ + EXPECT_EQ(OC_STACK_INVALID_PARAM, SRMRegisterHandler(NULL, NULL, NULL)); +} + +TEST(RegisterHandlerTest, RegisterValidHandler) +{ + EXPECT_EQ(OC_STACK_OK, SRMRegisterHandler(UTRequestHandler, UTResponseHandler, UTErrorHandler)); +} + +// PersistentStorageHandler Tests +TEST(PersistentStorageHandlerTest, RegisterNullHandler) +{ + EXPECT_EQ(OC_STACK_INVALID_PARAM, + SRMRegisterPersistentStorageHandler(NULL)); +} + +TEST(PersistentStorageHandlerTest, RegisterValidHandler) +{ + gpsi.open = utopen; + gpsi.read = utread; + gpsi.write = utwrite; + gpsi.close = utclose; + gpsi.unlink = utunlink; + + EXPECT_EQ(OC_STACK_OK, + SRMRegisterPersistentStorageHandler(&gpsi)); + OCPersistentStorage *ps = SRMGetPersistentStorageHandler(); + EXPECT_TRUE(&gpsi == ps); +} + +TEST(PersistentStorageHandlerTest, PersistentStorageValidHandlers) +{ + OCPersistentStorage *psi = SRMGetPersistentStorageHandler(); + EXPECT_TRUE(psi != NULL); + + unsigned char buf[PATH_MAX]; + FILE* streamIn = NULL; + FILE* streamOut = NULL; + struct passwd *pw = getpwuid(getuid()); + const char *homeDir = pw->pw_dir; + char inFilePath [PATH_MAX]; + char outFilePath [PATH_MAX]; + snprintf(inFilePath, PATH_MAX, "%s/iotivity/Readme.scons.txt", homeDir ); + snprintf(outFilePath, PATH_MAX, "%s/Downloads/Readme.scons.out.txt", homeDir ); + + streamIn = psi->open(inFilePath, "r"); + streamOut = psi->open(outFilePath, "w"); + + if (streamIn && streamOut) + { + size_t value = 1; + while (value) + { + value = psi->read(buf, 1, sizeof(buf), streamIn); + psi->write(buf, 1, value, streamOut); + } + } + + if (streamIn) + { + psi->close(streamIn); + } + if (streamOut) + { + psi->close(streamOut); + } + psi->unlink(outFilePath); +} diff --git a/resource/csdk/stack/include/ocstack.h b/resource/csdk/stack/include/ocstack.h index 28ecba8..ae30a0a 100644 --- a/resource/csdk/stack/include/ocstack.h +++ b/resource/csdk/stack/include/ocstack.h @@ -21,6 +21,7 @@ #ifndef OCSTACK_H_ #define OCSTACK_H_ +#include #include #include "octypes.h" @@ -118,6 +119,15 @@ OCStackResult OCDoResource(OCDoHandle *handle, OCMethod method, const char *requ OCStackResult OCCancel(OCDoHandle handle, OCQualityOfService qos, OCHeaderOption * options, uint8_t numOptions); +/** + * @brief Register Persistent storage callback. + * @param persistentStorageHandler [IN] Pointers to open, read, write, close & unlink handlers. + * @return + * OC_STACK_OK - No errors; Success + * OC_STACK_INVALID_PARAM - Invalid parameter + */ +OCStackResult OCRegisterPersistentStorageHandler(OCPersistentStorage* persistentStorageHandler); + #ifdef WITH_PRESENCE /** * When operating in @ref OCServer or @ref OCClientServer mode, this API will start sending out diff --git a/resource/csdk/stack/include/octypes.h b/resource/csdk/stack/include/octypes.h index b6d35d3..76c4ccf 100644 --- a/resource/csdk/stack/include/octypes.h +++ b/resource/csdk/stack/include/octypes.h @@ -202,23 +202,26 @@ typedef enum /** * Resource Properties. * - * ::OC_ACTIVE When this bit is set, the resource is initialized, otherwise the resource - * is 'inactive'. 'inactive' signifies that the resource has been marked for - * deletion or is already deleted. - * ::OC_DISCOVERABLE When this bit is set, the resource is allowed to be discovered by clients. - * ::OC_OBSERVABLE When this bit is set, the resource is allowed to be observed by clients. - * ::OC_SLOW When this bit is set, the resource has been marked as 'slow'. 'slow' signifies - * that responses from this resource can expect delays in processing its - * requests from clients. - * ::OC_SECURE When this bit is set, the resource is a secure resource. + * ::OC_RES_PROP_NONE When none of the bits are set, the resource is non-discoverable & + * non-observable by the client. + * ::OC_ACTIVE When this bit is set, the resource is initialized, otherwise the resource + * is 'inactive'. 'inactive' signifies that the resource has been marked for + * deletion or is already deleted. + * ::OC_DISCOVERABLE When this bit is set, the resource is allowed to be discovered by clients. + * ::OC_OBSERVABLE When this bit is set, the resource is allowed to be observed by clients. + * ::OC_SLOW When this bit is set, the resource has been marked as 'slow'. 'slow' + * signifies that responses from this resource can expect delays in + * processing its requests from clients. + * ::OC_SECURE When this bit is set, the resource is a secure resource. */ typedef enum { - OC_ACTIVE = (1 << 0), - OC_DISCOVERABLE = (1 << 1), - OC_OBSERVABLE = (1 << 2), - OC_SLOW = (1 << 3), - OC_SECURE = (1 << 4) + OC_RES_PROP_NONE = (0), + OC_ACTIVE = (1 << 0), + OC_DISCOVERABLE = (1 << 1), + OC_OBSERVABLE = (1 << 2), + OC_SLOW = (1 << 3), + OC_SECURE = (1 << 4) } OCResourceProperty; /** @@ -320,6 +323,27 @@ typedef enum OC_OBSERVE_NO_OPTION = 2 } OCObserveAction; + +/** + * Persistent storage handlers. An app must provide OCPersistentStorage handler pointers when it + * calls OCRegisterPersistentStorageHandler. + */ +typedef struct { + /* + * Persistent storage open handler points to default file path. + * Application can point to appropriate SVR database path for its Iotivity Server. + */ + FILE* (* open)(const char *path, const char *mode); + // Persistent storage read handler + size_t (* read)(void *ptr, size_t size, size_t nmemb, FILE *stream); + // Persistent storage write handler + size_t (* write)(const void *ptr, size_t size, size_t nmemb, FILE *stream); + // Persistent storage close handler + int (* close)(FILE *fp); + // Persistent storage unlink handler + int (* unlink)(const char *path); +} OCPersistentStorage; + typedef struct { // Action associated with observation request diff --git a/resource/csdk/stack/samples/arduino/SimpleClientServer/ocserver/SConscript b/resource/csdk/stack/samples/arduino/SimpleClientServer/ocserver/SConscript index 6f03453..d3e39c2 100644 --- a/resource/csdk/stack/samples/arduino/SimpleClientServer/ocserver/SConscript +++ b/resource/csdk/stack/samples/arduino/SimpleClientServer/ocserver/SConscript @@ -33,7 +33,7 @@ arduino_simplecs_env.PrependUnique(CPPPATH = [ arduino_simplecs_env.AppendUnique(LIBPATH = [env.get('BUILD_DIR')]) arduino_simplecs_env.AppendUnique(CPPDEFINES = ['TB_LOG']) -arduino_simplecs_env.PrependUnique(LIBS = ['octbstack', 'connectivity_abstraction','coap']) +arduino_simplecs_env.PrependUnique(LIBS = ['octbstack', 'ocsrm', 'connectivity_abstraction','coap']) arduino_simplecs = arduino_simplecs_env.Program('SimpleClientServer', 'ocserver.cpp') env.CreateBin('SimpleClientServer') diff --git a/resource/csdk/stack/samples/linux/SimpleClientServer/SConscript b/resource/csdk/stack/samples/linux/SimpleClientServer/SConscript index ab43795..6f9a37e 100644 --- a/resource/csdk/stack/samples/linux/SimpleClientServer/SConscript +++ b/resource/csdk/stack/samples/linux/SimpleClientServer/SConscript @@ -38,9 +38,9 @@ samples_env.AppendUnique(LIBS = ['-lpthread' ]) samples_env.AppendUnique(LIBPATH = [env.get('BUILD_DIR')]) if target_os in ['darwin', 'ios']: - samples_env.PrependUnique(LIBS = ['m','octbstack', 'connectivity_abstraction','coap' ]) + samples_env.PrependUnique(LIBS = ['m','octbstack', 'ocsrm', 'connectivity_abstraction','coap' ]) elif target_os not in ['arduino']: - samples_env.PrependUnique(LIBS = ['m', 'octbstack', 'oc_logger', 'connectivity_abstraction', 'coap']) + samples_env.PrependUnique(LIBS = ['m', 'octbstack', 'ocsrm', 'oc_logger', 'connectivity_abstraction', 'coap']) samples_env.AppendUnique(LIBS = ['rt']) if env.get('SECURED') == '1': diff --git a/resource/csdk/stack/samples/linux/SimpleClientServer/occlientbasicops.cpp b/resource/csdk/stack/samples/linux/SimpleClientServer/occlientbasicops.cpp index e2f6a61..961a917 100644 --- a/resource/csdk/stack/samples/linux/SimpleClientServer/occlientbasicops.cpp +++ b/resource/csdk/stack/samples/linux/SimpleClientServer/occlientbasicops.cpp @@ -39,7 +39,7 @@ static int UNICAST_DISCOVERY = 0; static int TEST_CASE = 0; static const char UNICAST_DISCOVERY_QUERY[] = "coap://%s:6298/oic/res"; -static std::string putPayload = "{\"state\":\"off\",\"power\":10}"; +static std::string putPayload = "{\"oic\":[{\"rep\":{\"power\":15,\"state\":true}}]}"; //The following variable determines the interface protocol (IPv4, IPv6, etc) //to be used for sending unicast messages. Default set to IPv4. diff --git a/resource/csdk/stack/samples/linux/SimpleClientServer/ocserverbasicops.cpp b/resource/csdk/stack/samples/linux/SimpleClientServer/ocserverbasicops.cpp index 43b913f..e053160 100644 --- a/resource/csdk/stack/samples/linux/SimpleClientServer/ocserverbasicops.cpp +++ b/resource/csdk/stack/samples/linux/SimpleClientServer/ocserverbasicops.cpp @@ -57,7 +57,8 @@ char* constructJsonResponse (OCEntityHandlerRequest *ehRequest) } cJSON *format; - char *jsonResponse; + cJSON *putJson = NULL; + char *jsonResponse = NULL; LEDResource *currLEDResource = &LED; if (ehRequest->resource == gLedInstance[0].handle) @@ -73,18 +74,37 @@ char* constructJsonResponse (OCEntityHandlerRequest *ehRequest) if(OC_REST_PUT == ehRequest->method) { - cJSON *putJson = cJSON_Parse((char *)ehRequest->reqJSONPayload); + cJSON* jsonObj = NULL; + putJson = cJSON_Parse(ehRequest->reqJSONPayload); + if(putJson) + { + jsonObj = cJSON_GetObjectItem(putJson,"oic"); + if (jsonObj) + { + jsonObj = cJSON_GetArrayItem(jsonObj, 0); + if (jsonObj) + { + jsonObj = cJSON_GetObjectItem(jsonObj, "rep"); + } + } + } + if (NULL == jsonObj) + { + OC_LOG_V(ERROR, TAG, "Failed to parse JSON: %s", ehRequest->reqJSONPayload); + goto exit; + } - if(!putJson) + cJSON* prop = cJSON_GetObjectItem(jsonObj,"power"); + if (prop) { - OC_LOG (ERROR, TAG, "putJson object not created properly"); - cJSON_Delete(json); - return NULL; + currLEDResource->power =prop->valueint; + } + + prop = cJSON_GetObjectItem(jsonObj,"state"); + if (prop) + { + currLEDResource->state = prop->valueint; } - currLEDResource->state = ( !strcmp(cJSON_GetObjectItem(putJson,"state")->valuestring , - "on") ? true:false); - currLEDResource->power = cJSON_GetObjectItem(putJson,"power")->valuedouble; - cJSON_Delete(putJson); } cJSON_AddStringToObject(json,"href",gResourceUri); @@ -93,8 +113,7 @@ char* constructJsonResponse (OCEntityHandlerRequest *ehRequest) if(!format) { OC_LOG (ERROR, TAG, "format object not created properly"); - cJSON_Delete(json); - return NULL; + goto exit; } cJSON_AddItemToObject(json, "rep", format); @@ -102,6 +121,9 @@ char* constructJsonResponse (OCEntityHandlerRequest *ehRequest) cJSON_AddNumberToObject(format, "power", currLEDResource->power); jsonResponse = cJSON_Print(json); + +exit: + cJSON_Delete(putJson); cJSON_Delete(json); return jsonResponse; } diff --git a/resource/csdk/stack/samples/linux/secure/SConscript b/resource/csdk/stack/samples/linux/secure/SConscript index 71e298f..b6dd32c 100644 --- a/resource/csdk/stack/samples/linux/secure/SConscript +++ b/resource/csdk/stack/samples/linux/secure/SConscript @@ -65,10 +65,17 @@ samples_env.AppendUnique(CPPDEFINES = ['TB_LOG']) ###################################################################### ocserverbasicops = samples_env.Program('ocserverbasicops', ['common.cpp', 'ocserverbasicops.cpp']) occlientbasicops = samples_env.Program('occlientbasicops', ['common.cpp', 'occlientbasicops.cpp']) -gen_sec_bin = samples_env.Program('gen_sec_bin', ['gen_sec_bin.cpp']) - Alias("samples", [ocserverbasicops, occlientbasicops]) env.AppendTarget('samples') +src_dir = samples_env.get('SRC_DIR') +sec_samples_src_dir = src_dir + '/resource/csdk/stack/samples/linux/secure/' +sec_samples_build_dir = env.get('BUILD_DIR') +'/resource/csdk/stack/samples/linux/secure' + +samples_env.Alias("install", samples_env.Install( sec_samples_build_dir, + sec_samples_src_dir + 'oic_svr_db_server.json')) +samples_env.Alias("install", samples_env.Install( sec_samples_build_dir, + sec_samples_src_dir + 'oic_svr_db_client.json')) + diff --git a/resource/csdk/stack/samples/linux/secure/common.cpp b/resource/csdk/stack/samples/linux/secure/common.cpp index 7c04494..8137da0 100644 --- a/resource/csdk/stack/samples/linux/secure/common.cpp +++ b/resource/csdk/stack/samples/linux/secure/common.cpp @@ -19,7 +19,7 @@ //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= #include "common.h" -#include "ocsecurity.h" +#include "ocstack.h" #include "logger.h" #include #include @@ -28,45 +28,6 @@ #define TAG "sample-common" -OCStackResult SetCredentials(const char* filename) { - - FILE *fp = NULL; - uint8_t *data = NULL; - struct stat st; - OCStackResult ret = OC_STACK_ERROR; - - fp = fopen(filename, "rb"); - if (fp) - { - if (stat(filename, &st) == 0) - { - data = (uint8_t*)malloc(st.st_size); - if (data) - { - if (fread(data, 1, st.st_size, fp) == (size_t)st.st_size) - { - // Provide credentials to OC Stack - ret = OCSecSetConfigData((OCSecConfigData *)data, - st.st_size); - } - else - { - OC_LOG_V(FATAL, TAG, "Error in reading file %s", filename); - } - } - } - fclose(fp); - } - else - { - OC_LOG_V(FATAL, TAG, "Unable to open %s file", filename); - } - - free(data); - - return ret; -} - const char *getResult(OCStackResult result) { switch (result) { case OC_STACK_OK: diff --git a/resource/csdk/stack/samples/linux/secure/common.h b/resource/csdk/stack/samples/linux/secure/common.h index ac73c1d..ea899c3 100644 --- a/resource/csdk/stack/samples/linux/secure/common.h +++ b/resource/csdk/stack/samples/linux/secure/common.h @@ -26,9 +26,6 @@ /* Get the result in string format. */ const char *getResult(OCStackResult result); -/* Read the credentials from persistent storage and provide to OC stack. */ -OCStackResult SetCredentials(const char* filename); - /* Removes the new line character from a NULL terminated C string. */ void StripNewLineChar(char* str); diff --git a/resource/csdk/stack/samples/linux/secure/gen_sec_bin.cpp b/resource/csdk/stack/samples/linux/secure/gen_sec_bin.cpp deleted file mode 100644 index c30aada..0000000 --- a/resource/csdk/stack/samples/linux/secure/gen_sec_bin.cpp +++ /dev/null @@ -1,171 +0,0 @@ -//****************************************************************** -// -// Copyright 2014 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 "ocsecurityconfig.h" -#include "logger.h" -#include -#include -#include -#include -#include - -#define TAG "gen_sec_bin" - -//scratch buffer -const int WORK_BUF_LEN = 512; - -const char SERVER_CRED_FILE[] = "server_cred.bin"; -const char CLIENT_CRED_FILE[] = "client_cred.bin"; - -static void printStruct(const char * device, OCSecConfigData* s) -{ - if (device && s) - { - OC_LOG(INFO, TAG, device); - OC_LOG_V(INFO, TAG, "Version - %d", s->version); - OC_LOG_V(INFO, TAG, "Number of blobs - %d", s->numBlob); - - OCSecBlob* osb = (OCSecBlob*)(s->blob); - OC_LOG_V(INFO, TAG, "Blob Type - %d", osb->type); - OC_LOG_V(INFO, TAG, "Blob Data Length - %d", osb->len); - - OCDtlsPskCredsBlob* odpcb = (OCDtlsPskCredsBlob*)(osb->val); - OC_LOG(INFO, TAG, "My Identity :"); - OC_LOG_BUFFER(INFO, TAG, odpcb->identity, DTLS_PSK_ID_LEN); - - OC_LOG_V(INFO, TAG, "Number of trusted Peers - %d", odpcb->num); - OC_LOG(INFO, TAG, "Peer Identity :"); - OC_LOG_BUFFER(INFO, TAG, odpcb->creds[0].id, DTLS_PSK_ID_LEN); - OC_LOG(INFO, TAG, "Peer Psk :"); - OC_LOG_BUFFER(INFO, TAG, odpcb->creds[0].psk, DTLS_PSK_PSK_LEN); - } -} - - -static int SizeOfOCConfigData (OCSecConfigData *oscd) -{ - int len = 0; - if(oscd) - { - int i = 0; - OCSecBlob * osb; - len = len + sizeof(OCSecConfigData) - sizeof(uint8_t); - - //go to first blob - osb = (OCSecBlob*)(oscd->blob); - for( i =0; i < oscd->numBlob; i++) - { - len += (sizeof(OCSecBlob) - sizeof(uint8_t) + osb->len); - osb = config_data_next_blob(osb); - } - } - return len; -} - -int main() -{ - unsigned char buf_s[WORK_BUF_LEN]; - unsigned char buf_c[WORK_BUF_LEN]; - - srand(time(NULL)); - - OCSecConfigData * oscd_s = (OCSecConfigData*)buf_s; - OCSecConfigData * oscd_c = (OCSecConfigData*)buf_c; - oscd_s->version = oscd_c->version = OCSecConfigVer_CurrentVersion; - - //Only storing 1 blob of type 'OC_BLOB_TYPE_PSK' - oscd_s->numBlob = oscd_c->numBlob = 1; - - OCSecBlob * osb_s = (OCSecBlob*)oscd_s->blob; - OCSecBlob * osb_c = (OCSecBlob*)oscd_c->blob; - osb_s->type = osb_c->type = OC_BLOB_TYPE_PSK; - //length of this blob will be the length to contain PSK credentials - // for '1' peer device - osb_s->len = osb_c->len = sizeof(OCDtlsPskCredsBlob); - - OCDtlsPskCredsBlob * odpcb_s = (OCDtlsPskCredsBlob*)(osb_s->val); - OCDtlsPskCredsBlob * odpcb_c = (OCDtlsPskCredsBlob*)(osb_c->val); - - odpcb_s->num = odpcb_c->num = 1; - - for(int i = 0; i < DTLS_PSK_ID_LEN; i++) - { - odpcb_c->creds[0].id[i] = odpcb_s->identity[i] = rand() % (2^8); - - odpcb_s->creds[0].id[i] = odpcb_c->identity[i] = rand() % (2^8); - - odpcb_c->creds[0].psk[i] = odpcb_s->creds[0].psk[i] = rand() % (2^8); - } - - // Print Credentials - printStruct("Server", oscd_s); - printStruct("Client", oscd_c); - - // Write to files - FILE* fps, *fpc; - if ((fps = (FILE*) fopen("server_cred.bin", "wb")) != NULL) - { - fwrite(oscd_s, SizeOfOCConfigData(oscd_s), 1, fps); - fclose(fps); - } - - - if ((fpc = (FILE*) fopen("client_cred.bin", "wb")) != NULL) - { - fwrite(oscd_c, SizeOfOCConfigData(oscd_c), 1, fpc); - fclose(fpc); - } - - struct stat st; - memset(buf_s, 0, sizeof(buf_s)); - memset(buf_c, 0, sizeof(buf_c)); - // Read from files; print and verify manually - if ((fps = (FILE*) fopen(SERVER_CRED_FILE, "rb")) != NULL) - { - stat(SERVER_CRED_FILE, &st); - if ((sizeof(buf_s) < (unsigned int)st.st_size) || - (fread(buf_s, 1, st.st_size, fps) != (unsigned int)st.st_size)) - { - OC_LOG(INFO, TAG, PCF("Reading from the file failed.")); - } - fclose(fps); - } - - - if ((fpc = (FILE*) fopen(CLIENT_CRED_FILE, "rb")) != NULL) - { - stat(CLIENT_CRED_FILE, &st); - if ((sizeof(buf_c) < (unsigned int)st.st_size) || - (fread(buf_c, 1, st.st_size, fpc) != (unsigned int)st.st_size)) - { - OC_LOG(INFO, TAG, PCF("Reading from the file failed.")); - } - fclose(fpc); - } - - printf("\n\n"); - OC_LOG(INFO, TAG, PCF("Reading from file and printing again to verify manually")); - printStruct("Server", (OCSecConfigData*)buf_s); - printStruct("Client", (OCSecConfigData*)buf_c); - - return 1; -} - - diff --git a/resource/csdk/stack/samples/linux/secure/occlientbasicops.cpp b/resource/csdk/stack/samples/linux/secure/occlientbasicops.cpp index 5088121..e791a28 100644 --- a/resource/csdk/stack/samples/linux/secure/occlientbasicops.cpp +++ b/resource/csdk/stack/samples/linux/secure/occlientbasicops.cpp @@ -47,10 +47,10 @@ static int coapSecureResource; static OCConnectivityType ocConnType; -//File containing Client's Identity and the PSK credentials +//Secure Virtual Resource database for Iotivity Client application +//It contains Client's Identity and the PSK credentials //of other devices which the client trusts -//This can be generated using 'gen_sec_bin' application -static char CRED_FILE[] = "client_cred.bin"; +static char CRED_FILE[] = "oic_svr_db_client.json"; int gQuitFlag = 0; @@ -286,6 +286,12 @@ int InitDiscovery() return ret; } +FILE* client_fopen(const char *path, const char *mode) +{ + (void)path; + return fopen(CRED_FILE, mode); +} + int main(int argc, char* argv[]) { int opt; @@ -314,23 +320,22 @@ int main(int argc, char* argv[]) return -1; } + // Initialize Persistent Storage for SVR database + OCPersistentStorage ps = {}; + ps.open = client_fopen; + ps.read = fread; + ps.write = fwrite; + ps.close = fclose; + ps.unlink = unlink; + OCRegisterPersistentStorageHandler(&ps); + /* Initialize OCStack*/ - if (OCInit(NULL, 0, OC_CLIENT) != OC_STACK_OK) + if (OCInit(NULL, 0, OC_CLIENT_SERVER) != OC_STACK_OK) { OC_LOG(ERROR, TAG, "OCStack init error"); return 0; } - /* - * Read DTLS PSK credentials from persistent storage and - * set in the OC stack. - */ - if (SetCredentials(CRED_FILE) != OC_STACK_OK) - { - OC_LOG(ERROR, TAG, "SetCredentials failed"); - return 0; - } - InitDiscovery(); timeout.tv_sec = 0; @@ -410,9 +415,10 @@ int parseClientResponse(OCClientResponse * clientResponse) if (oc->type == cJSON_Array) { - if (cJSON_GetArraySize(oc) > 0) + int numRsrcs = cJSON_GetArraySize(oc); + for(int i = 0; i < numRsrcs; i++) { - cJSON * resource = cJSON_GetArrayItem(oc, 0); + cJSON * resource = cJSON_GetArrayItem(oc, i); if (cJSON_GetObjectItem(resource, "href")) { coapServerResource.assign(cJSON_GetObjectItem(resource, "href")->valuestring); @@ -446,6 +452,12 @@ int parseClientResponse(OCClientResponse * clientResponse) coapServerPort = ss.str(); } } + + // If we discovered a secure resource, exit from here + if (coapSecureResource) + { + break; + } } } cJSON_Delete(root); diff --git a/resource/csdk/stack/samples/linux/secure/ocserverbasicops.cpp b/resource/csdk/stack/samples/linux/secure/ocserverbasicops.cpp index 440b667..a6ec6af 100644 --- a/resource/csdk/stack/samples/linux/secure/ocserverbasicops.cpp +++ b/resource/csdk/stack/samples/linux/secure/ocserverbasicops.cpp @@ -41,18 +41,19 @@ static LEDResource gLedInstance[SAMPLE_MAX_NUM_POST_INSTANCE]; char *gResourceUri= (char *)"/a/led"; -//File containing Server's Identity and the PSK credentials +//Secure Virtual Resource database for Iotivity Server +//It contains Server's Identity and the PSK credentials //of other devices which the server trusts -//This can be generated using 'gen_sec_bin' application -static char CRED_FILE[] = "server_cred.bin"; +static char CRED_FILE[] = "oic_svr_db_server.json"; //This function takes the request as an input and returns the response //in JSON format. char* constructJsonResponse (OCEntityHandlerRequest *ehRequest) { cJSON *json = cJSON_CreateObject(); + cJSON *putJson = NULL; cJSON *format; - char *jsonResponse; + char *jsonResponse = NULL; LEDResource *currLEDResource = &LED; if (ehRequest->resource == gLedInstance[0].handle) @@ -68,17 +69,29 @@ char* constructJsonResponse (OCEntityHandlerRequest *ehRequest) if(OC_REST_PUT == ehRequest->method) { - cJSON *putJson = cJSON_Parse(ehRequest->reqJSONPayload); - if(!putJson) + cJSON* jsonObj = NULL; + putJson = cJSON_Parse(ehRequest->reqJSONPayload); + if(putJson) + { + jsonObj = cJSON_GetObjectItem(putJson,"oic"); + if (jsonObj) + { + jsonObj = cJSON_GetArrayItem(jsonObj, 0); + if (jsonObj) + { + jsonObj = cJSON_GetObjectItem(jsonObj, "rep"); + } + } + } + if (NULL == jsonObj) { OC_LOG_V(ERROR, TAG, "Failed to parse JSON: %s", ehRequest->reqJSONPayload); - return NULL; + goto exit; } - currLEDResource->state = ( !strcmp(cJSON_GetObjectItem(putJson,"state")->valuestring , - "on") ? true:false); - currLEDResource->power = cJSON_GetObjectItem(putJson,"power")->valuedouble; - cJSON_Delete(putJson); + currLEDResource->state = ( !strcmp(cJSON_GetObjectItem(jsonObj,"state")->valuestring , + "on") ? true:false); + currLEDResource->power = cJSON_GetObjectItem(jsonObj,"power")->valuedouble; } cJSON_AddStringToObject(json,"href",gResourceUri); @@ -87,6 +100,9 @@ char* constructJsonResponse (OCEntityHandlerRequest *ehRequest) cJSON_AddNumberToObject(format, "power", currLEDResource->power); jsonResponse = cJSON_Print(json); + +exit: + cJSON_Delete(putJson); cJSON_Delete(json); return jsonResponse; } @@ -310,12 +326,27 @@ void handleSigInt(int signum) } } +FILE* server_fopen(const char *path, const char *mode) +{ + (void)path; + return fopen(CRED_FILE, mode); +} + int main(int argc, char* argv[]) { struct timespec timeout; OC_LOG(DEBUG, TAG, "OCServer is starting..."); + // Initialize Persistent Storage for SVR database + OCPersistentStorage ps = {}; + ps.open = server_fopen; + ps.read = fread; + ps.write = fwrite; + ps.close = fclose; + ps.unlink = unlink; + OCRegisterPersistentStorageHandler(&ps); + if (OCInit(NULL, 0, OC_SERVER) != OC_STACK_OK) { OC_LOG(ERROR, TAG, "OCStack init error"); @@ -323,15 +354,6 @@ int main(int argc, char* argv[]) } /* - * Read DTLS PSK credentials from persistent storage and - * set in the OC stack. - */ - if (SetCredentials(CRED_FILE) != OC_STACK_OK) - { - OC_LOG(ERROR, TAG, "SetCredentials failed"); - return 0; - } - /* * Declare and create the example resource: LED */ createLEDResource(gResourceUri, &LED, false, 0); 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 new file mode 100644 index 0000000..aba0590 --- /dev/null +++ b/resource/csdk/stack/samples/linux/secure/oic_svr_db_client.json @@ -0,0 +1,49 @@ +{ + "acl": [ + { + "sub": "Kg==", + "rsrc": [ + "/oic/res", + "/oic/d", + "/oic/p", + "/oic/res/types/d", + "/oic/ad", + "/oic/sec/acl" + ], + "perms": 2, + "ownrs" : ["MjIyMjIyMjIyMjIyMjIyMg=="] + }, + { + "sub": "Kg==", + "rsrc": [ + "/oic/sec/doxm", + "/oic/sec/pstat" + ], + "perms": 2, + "ownrs" : ["MjIyMjIyMjIyMjIyMjIyMg=="] + } + ], + "pstat": { + "isop": true, + "deviceid": "ZGV2aWNlaWQAAAAAABhanw==", + "commithash": 0, + "cm": 0, + "tm": 0, + "om": 3, + "sm": [3] + }, + "doxm": { + "oxm": [0], + "oxmsel": 0, + "owned": true, + "deviceid": "MjIyMjIyMjIyMjIyMjIyMg==", + "ownr": "MjIyMjIyMjIyMjIyMjIyMg==" + }, + "cred": [{ + "credid": 1, + "sub": "MTExMTExMTExMTExMTExMQ==", + "credtyp": 1, + "pvdata": "QUFBQUFBQUFBQUFBQUFBQQ==", + "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 new file mode 100644 index 0000000..a23287d --- /dev/null +++ b/resource/csdk/stack/samples/linux/secure/oic_svr_db_server.json @@ -0,0 +1,55 @@ +{ + "acl": [ + { + "sub": "Kg==", + "rsrc": [ + "/oic/res", + "/oic/d", + "/oic/p", + "/oic/res/types/d", + "/oic/ad", + "/oic/sec/acl" + ], + "perms": 2, + "ownrs" : ["MTExMTExMTExMTExMTExMQ=="] + }, + { + "sub": "Kg==", + "rsrc": [ + "/oic/sec/doxm", + "/oic/sec/pstat" + ], + "perms": 2, + "ownrs" : ["MTExMTExMTExMTExMTExMQ=="] + }, + { + "sub": "MjIyMjIyMjIyMjIyMjIyMg==", + "rsrc": ["/a/led"], + "perms": 6, + "ownrs" : ["MjIyMjIyMjIyMjIyMjIyMg=="] + } + ], + "pstat": { + "isop": true, + "deviceid": "ZGV2aWNlaWQAAAAAABhanw==", + "commithash": 0, + "cm": 0, + "tm": 0, + "om": 3, + "sm": [3] + }, + "doxm": { + "oxm": [0], + "oxmsel": 0, + "owned": true, + "deviceid": "MTExMTExMTExMTExMTExMQ==", + "ownr": "MjIyMjIyMjIyMjIyMjIyMg==" + }, + "cred": [{ + "credid": 1, + "sub": "MjIyMjIyMjIyMjIyMjIyMg==", + "credtyp": 1, + "pvdata": "QUFBQUFBQUFBQUFBQUFBQQ==", + "ownrs" : ["MjIyMjIyMjIyMjIyMjIyMg=="] + }] +} diff --git a/resource/csdk/stack/src/ocserverrequest.c b/resource/csdk/stack/src/ocserverrequest.c index d0a018f..5a3bfc0 100644 --- a/resource/csdk/stack/src/ocserverrequest.c +++ b/resource/csdk/stack/src/ocserverrequest.c @@ -420,7 +420,7 @@ CAResponseResult_t ConvertEHResultToCAResult (OCEntityHandlerResult result) caResult = CA_SUCCESS; break; case OC_EH_FORBIDDEN: - caResult = CA_BAD_REQ; + caResult = CA_UNAUTHORIZED_REQ; break; case OC_EH_RESOURCE_NOT_FOUND: caResult = CA_NOT_FOUND; @@ -557,11 +557,16 @@ OCStackResult HandleSingleResponse(OCEntityHandlerResponse * ehResponse) responseInfo.info.options = NULL; } - char payload[MAX_RESPONSE_LENGTH + OC_JSON_PREFIX_LEN + OC_JSON_SUFFIX_LEN] = {}; + char payload[MAX_RESPONSE_LENGTH + OC_JSON_PREFIX_LEN + OC_JSON_SUFFIX_LEN + 1] = {}; // Put the JSON prefix and suffix around the payload strcpy(payload, (const char *)OC_JSON_PREFIX); - strncat(payload, (const char *)ehResponse->payload, ehResponse->payloadSize); + if(ehResponse->payloadSize) + { + strncat(payload, (const char *)ehResponse->payload, + ehResponse->payloadSize < MAX_RESPONSE_LENGTH ? + ehResponse->payloadSize : MAX_RESPONSE_LENGTH); + } strcat(payload, (const char *)OC_JSON_SUFFIX); responseInfo.info.payload = (CAPayload_t)payload; diff --git a/resource/csdk/stack/src/ocstack.c b/resource/csdk/stack/src/ocstack.c index 73dacb9..c17b752 100644 --- a/resource/csdk/stack/src/ocstack.c +++ b/resource/csdk/stack/src/ocstack.c @@ -41,8 +41,7 @@ #include "ocrandom.h" #include "oic_malloc.h" #include "ocserverrequest.h" -#include "ocsecurityinternal.h" - +#include "secureresourcemanager.h" #include "cacommon.h" #include "cainterface.h" @@ -1865,18 +1864,20 @@ OCStackResult OCInit(const char *ipAddr, uint16_t port, OCMode mode) result = CAResultToOCResult(OCSelectNetwork()); VERIFY_SUCCESS(result, OC_STACK_OK); - CARegisterHandler(HandleCARequests, HandleCAResponses, HandleCAErrorResponse); switch (myStackMode) { case OC_CLIENT: + CARegisterHandler(HandleCARequests, HandleCAResponses, HandleCAErrorResponse); result = CAResultToOCResult(CAStartDiscoveryServer()); OC_LOG(INFO, TAG, PCF("Client mode: CAStartDiscoveryServer")); break; case OC_SERVER: + SRMRegisterHandler(HandleCARequests, HandleCAResponses, HandleCAErrorResponse); result = CAResultToOCResult(CAStartListeningServer()); OC_LOG(INFO, TAG, PCF("Server mode: CAStartListeningServer")); break; case OC_CLIENT_SERVER: + SRMRegisterHandler(HandleCARequests, HandleCAResponses, HandleCAErrorResponse); result = CAResultToOCResult(CAStartListeningServer()); if(result == OC_STACK_OK) { @@ -1886,12 +1887,6 @@ OCStackResult OCInit(const char *ipAddr, uint16_t port, OCMode mode) } VERIFY_SUCCESS(result, OC_STACK_OK); -#if defined(__WITH_DTLS__) - result = (CARegisterDTLSCredentialsHandler(GetDtlsPskCredentials) == CA_STATUS_OK) ? - OC_STACK_OK : OC_STACK_ERROR; - VERIFY_SUCCESS(result, OC_STACK_OK); -#endif // (__WITH_DTLS__) - #ifdef WITH_PRESENCE PresenceTimeOutSize = sizeof(PresenceTimeOut)/sizeof(PresenceTimeOut[0]) - 1; #endif // WITH_PRESENCE @@ -1905,6 +1900,13 @@ OCStackResult OCInit(const char *ipAddr, uint16_t port, OCMode mode) result = initResources(); } + // Initialize the SRM Policy Engine + if(result == OC_STACK_OK) + { + result = SRMInitPolicyEngine(); + // TODO after BeachHead delivery: consolidate into single SRMInit() + } + exit: if(result != OC_STACK_OK) { @@ -1948,8 +1950,11 @@ OCStackResult OCStop() DeleteObserverList(); // Remove all the client callbacks DeleteClientCBList(); - // Deinit security blob - DeinitOCSecurityInfo(); + + // De-init the SRM Policy Engine + // TODO after BeachHead delivery: consolidate into single SRMDeInit() + SRMDeInitPolicyEngine(); + stackState = OC_STACK_UNINITIALIZED; return OC_STACK_OK; } @@ -2362,6 +2367,36 @@ OCStackResult OCCancel(OCDoHandle handle, OCQualityOfService qos, OCHeaderOption return ret; } +/** + * @brief Register Persistent storage callback. + * @param persistentStorageHandler [IN] Pointers to open, read, write, close & unlink handlers. + * @return + * OC_STACK_OK - No errors; Success + * OC_STACK_INVALID_PARAM - Invalid parameter + */ +OCStackResult OCRegisterPersistentStorageHandler(OCPersistentStorage* persistentStorageHandler) +{ + OC_LOG(INFO, TAG, PCF("RegisterPersistentStorageHandler !!")); + if(!persistentStorageHandler) + { + OC_LOG(ERROR, TAG, PCF("The persistent storage handler is invalid")); + return OC_STACK_INVALID_PARAM; + } + else + { + if( !persistentStorageHandler->open || + !persistentStorageHandler->close || + !persistentStorageHandler->read || + !persistentStorageHandler->unlink || + !persistentStorageHandler->write) + { + OC_LOG(ERROR, TAG, PCF("The persistent storage handler is invalid")); + return OC_STACK_INVALID_PARAM; + } + } + return SRMRegisterPersistentStorageHandler(persistentStorageHandler); +} + #ifdef WITH_PRESENCE OCStackResult OCProcessPresence() { @@ -3471,6 +3506,12 @@ OCStackResult initResources() &(((OCResource *) presenceResource.handle)->resourceProperties), OC_ACTIVE, 0); #endif + + if (result == OC_STACK_OK) + { + result = SRMInitSecureResources(); + } + return result; } @@ -3523,6 +3564,8 @@ void deleteAllResources() pointer = temp; } + SRMDeInitSecureResources(); + #ifdef WITH_PRESENCE // Ensure that the last resource to be deleted is the presence resource. This allows for all // presence notification attributed to their deletion to be processed. diff --git a/resource/csdk/stack/test/SConscript b/resource/csdk/stack/test/SConscript index 1fe5464..27f9905 100644 --- a/resource/csdk/stack/test/SConscript +++ b/resource/csdk/stack/test/SConscript @@ -36,6 +36,7 @@ stacktest_env.PrependUnique(CPPPATH = [ '../../stack/include', '../../stack/include/internal', '../../connectivity/api', + '../../connectivity/external/inc', '../../extlibs/cjson', '../../../oc_logger/include', '../../../../extlibs/gtest/gtest-1.7.0/include' @@ -47,6 +48,7 @@ stacktest_env.AppendUnique(LIBPATH = [env.get('BUILD_DIR')]) stacktest_env.AppendUnique(LIBPATH = [src_dir + '/extlibs/gtest/gtest-1.7.0/lib/.libs']) stacktest_env.PrependUnique(LIBS = ['m', 'octbstack', + 'ocsrm', 'connectivity_abstraction', 'coap', 'gtest', diff --git a/resource/csdk/stack/test/stacktests.cpp b/resource/csdk/stack/test/stacktests.cpp index 1e3d93f..590bda3 100644 --- a/resource/csdk/stack/test/stacktests.cpp +++ b/resource/csdk/stack/test/stacktests.cpp @@ -713,6 +713,8 @@ TEST(StackResource, StackTestResourceDiscoverOneResourceBad) itst::DeadmanTimer killSwitch(SHORT_TEST_TIMEOUT); OC_LOG(INFO, TAG, "Starting StackTestResourceDiscoverOneResourceBad test"); InitStack(OC_SERVER); + uint8_t numResources = 0; + EXPECT_EQ(OC_STACK_OK, OCGetNumberOfResources(&numResources)); OCResourceHandle handle; EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handle, @@ -726,10 +728,9 @@ TEST(StackResource, StackTestResourceDiscoverOneResourceBad) //EXPECT_EQ(OC_STACK_INVALID_URI, OCHandleServerRequest(&res, uri, query, req, rsp)); EXPECT_EQ(OC_STACK_OK, OCDeleteResource(handle)); - uint8_t numResources = 0; - uint8_t numExpectedResources = InitNumExpectedResources(); + uint8_t numExpectedResources = 0; - EXPECT_EQ(OC_STACK_OK, OCGetNumberOfResources(&numResources)); + EXPECT_EQ(OC_STACK_OK, OCGetNumberOfResources(&numExpectedResources)); EXPECT_EQ(numExpectedResources, numResources); EXPECT_EQ(OC_STACK_OK, OCStop()); @@ -1048,10 +1049,9 @@ TEST(StackBind, BindContainedResourceGood) InitStack(OC_SERVER); uint8_t numResources = 0; - uint8_t numExpectedResources = InitNumExpectedResources(); + uint8_t numExpectedResources = 0; - EXPECT_EQ(OC_STACK_OK, OCGetNumberOfResources(&numResources)); - EXPECT_EQ(numExpectedResources, numResources); + EXPECT_EQ(OC_STACK_OK, OCGetNumberOfResources(&numExpectedResources)); OCResourceHandle containerHandle; EXPECT_EQ(OC_STACK_OK, OCCreateResource(&containerHandle, @@ -1192,12 +1192,11 @@ TEST(StackResourceAccess, GetResourceByIndex) InitStack(OC_SERVER); uint8_t numResources = 0; - uint8_t numExpectedResources = InitNumExpectedResources(); - uint8_t resourceIndex = InitResourceIndex(); - - EXPECT_EQ(OC_STACK_OK, OCGetNumberOfResources(&numResources)); - EXPECT_EQ(numExpectedResources, numResources); - + uint8_t numExpectedResources = 0; + uint8_t resourceIndex = 0; + uint8_t prevResources = 0; + EXPECT_EQ(OC_STACK_OK, OCGetNumberOfResources(&numExpectedResources)); + prevResources = numExpectedResources; OCResourceHandle containerHandle; EXPECT_EQ(OC_STACK_OK, OCCreateResource(&containerHandle, "core.led", @@ -1267,7 +1266,7 @@ TEST(StackResourceAccess, GetResourceByIndex) OC_DISCOVERABLE|OC_OBSERVABLE)); EXPECT_EQ(OC_STACK_OK, OCGetNumberOfResources(&numResources)); EXPECT_EQ(++numExpectedResources, numResources); - + resourceIndex += prevResources; EXPECT_EQ(containerHandle, OCGetResourceHandle(resourceIndex)); EXPECT_EQ(handle0, OCGetResourceHandle(++resourceIndex)); EXPECT_EQ(handle1, OCGetResourceHandle(++resourceIndex)); @@ -1286,10 +1285,9 @@ TEST(StackResourceAccess, DeleteHeadResource) InitStack(OC_SERVER); uint8_t numResources = 0; - uint8_t numExpectedResources = InitNumExpectedResources(); + uint8_t numExpectedResources = 0; - EXPECT_EQ(OC_STACK_OK, OCGetNumberOfResources(&numResources)); - EXPECT_EQ(numExpectedResources, numResources); + EXPECT_EQ(OC_STACK_OK, OCGetNumberOfResources(&numExpectedResources)); OCResourceHandle handle0; EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handle0, @@ -1315,12 +1313,9 @@ TEST(StackResourceAccess, DeleteHeadResource2) InitStack(OC_SERVER); uint8_t numResources = 0; - uint8_t numExpectedResources = InitNumExpectedResources(); - uint8_t resourceIndex = InitResourceIndex(); - - EXPECT_EQ(OC_STACK_OK, OCGetNumberOfResources(&numResources)); - EXPECT_EQ(numExpectedResources, numResources); + uint8_t numExpectedResources = 0; + EXPECT_EQ(OC_STACK_OK, OCGetNumberOfResources(&numExpectedResources)); OCResourceHandle handle0; EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handle0, "core.led", @@ -1345,7 +1340,7 @@ TEST(StackResourceAccess, DeleteHeadResource2) EXPECT_EQ(OC_STACK_OK, OCGetNumberOfResources(&numResources)); EXPECT_EQ(--numExpectedResources, numResources); - EXPECT_EQ(handle1, OCGetResourceHandle(resourceIndex)); + EXPECT_EQ(handle1, OCGetResourceHandle(numResources - 1)); EXPECT_EQ(OC_STACK_OK, OCStop()); } @@ -1358,12 +1353,10 @@ TEST(StackResourceAccess, DeleteLastResource) InitStack(OC_SERVER); uint8_t numResources = 0; - uint8_t numExpectedResources = InitNumExpectedResources(); - uint8_t resourceIndex = InitResourceIndex(); - - EXPECT_EQ(OC_STACK_OK, OCGetNumberOfResources(&numResources)); - EXPECT_EQ(numExpectedResources, numResources); + uint8_t numExpectedResources = 0; + EXPECT_EQ(OC_STACK_OK, OCGetNumberOfResources(&numExpectedResources)); + OCResourceHandle handle0; EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handle0, "core.led", @@ -1388,7 +1381,7 @@ TEST(StackResourceAccess, DeleteLastResource) EXPECT_EQ(OC_STACK_OK, OCGetNumberOfResources(&numResources)); EXPECT_EQ(--numExpectedResources, numResources); - EXPECT_EQ(handle0, OCGetResourceHandle(resourceIndex)); + EXPECT_EQ(handle0, OCGetResourceHandle(numResources - 1)); OCResourceHandle handle2; EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handle2, @@ -1410,12 +1403,11 @@ TEST(StackResourceAccess, DeleteMiddleResource) InitStack(OC_SERVER); uint8_t numResources = 0; - uint8_t numExpectedResources = InitNumExpectedResources(); + uint8_t numExpectedResources = 0; uint8_t resourceIndex = InitResourceIndex(); - EXPECT_EQ(OC_STACK_OK, OCGetNumberOfResources(&numResources)); - EXPECT_EQ(numExpectedResources, numResources); - + EXPECT_EQ(OC_STACK_OK, OCGetNumberOfResources(&numExpectedResources)); + resourceIndex = numExpectedResources; OCResourceHandle handle0; EXPECT_EQ(OC_STACK_OK, OCCreateResource(&handle0, "core.led", diff --git a/resource/unit_tests.scons b/resource/unit_tests.scons index a5f1368..14b13e2 100644 --- a/resource/unit_tests.scons +++ b/resource/unit_tests.scons @@ -48,9 +48,16 @@ if target_os == 'linux': SConscript('csdk/connectivity/test/SConscript') + # Build Security Resource Manager unit tests + SConscript('csdk/security/unittest/SConscript') + # Build C++ unit tests SConscript('unittests/SConscript') + # Build Provisioning API unit test + if env.get('SECURED') == '1': + SConscript('csdk/security/provisioning/unittest/SConscript') + elif target_os == 'darwin': # Verify that 'google unit test' library is installed. If not, # get it and install it @@ -60,3 +67,4 @@ elif target_os == 'darwin': SConscript('csdk/stack/test/SConscript') SConscript('csdk/connectivity/test/SConscript') + diff --git a/resource/unittests/SConscript b/resource/unittests/SConscript index cdb9ca7..3050b78 100644 --- a/resource/unittests/SConscript +++ b/resource/unittests/SConscript @@ -34,6 +34,7 @@ unittests_env.PrependUnique(CPPPATH = [ '../csdk/security/include', '../csdk/stack/include/internal', '../csdk/connectivity/api', + '../csdk/connectivity/external/inc', '../csdk/ocsocket/include', '../csdk/ocrandom/include', '../csdk/logger/include', -- 2.7.4