--- /dev/null
+From bdfe0e312f9c2cd34df7bfff070dfe8a9e82d147 Mon Sep 17 00:00:00 2001
+From: leechul <chuls.lee@samsung.com>
+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 <chuls.lee@samsung.com>
+Signed-off-by: Sachin Agrawal <sachin.agrawal@intel.com>
+---
+ 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 <stdint.h>
+
++#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 <bergmann@tzi.org>\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 <bergmann@tzi.org>\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
+
#include <stdint.h>
+#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 */
#include "crypto.h"
#include "ccm.h"
#include "ecc/ecc.h"
+#include "aes/rijndael.h"
+#include "sha2/sha2.h"
#include "prng.h"
#include "netq.h"
}
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) {
}
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) {
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,
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();
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();
/** 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 {
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 */
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;
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
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 */
#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
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.
#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)
{
#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.
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));
}
/**
}
#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) {
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");
}
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
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");
}
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;
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);
#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;
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 */
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;
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));
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);
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) {
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;
}
}
}
#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;
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);
#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 */
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");
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);
}
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;
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) {
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,
}
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
{
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;
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) {
}
#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);
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);
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;
}
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)) {
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
}
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),
*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 */
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
*/
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
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;
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
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_ */
+++ /dev/null
-/*
- * Copyright (c) 2009 Chris K Cockrum <ckc@cockrum.net>
- *
- * Copyright (c) 2013 Jens Trillmann <jtrillma@tzi.de>
- * Copyright (c) 2013 Marc Müller-Weinhardt <muewei@tzi.de>
- * Copyright (c) 2013 Lars Schmertmann <lars@tzi.de>
- * Copyright (c) 2013 Hauke Mehrtens <hauke@hauke-m.de>
- *
- * 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 <ckc@cockrum.net>.
- *
- * [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 <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-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
+++ /dev/null
-/*
- * Copyright (c) 2009 Chris K Cockrum <ckc@cockrum.net>
- *
- * Copyright (c) 2013 Jens Trillmann <jtrillma@tzi.de>
- * Copyright (c) 2013 Marc Müller-Weinhardt <muewei@tzi.de>
- * Copyright (c) 2013 Lars Schmertmann <lars@tzi.de>
- * Copyright (c) 2013 Hauke Mehrtens <hauke@hauke-m.de>
- *
- * 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 <ckc@cockrum.net>.
- *
- * [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 <inttypes.h>
-
-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
+++ /dev/null
-/*
- * Copyright (c) 2009 Chris K Cockrum <ckc@cockrum.net>
- *
- * Copyright (c) 2013 Jens Trillmann <jtrillma@tzi.de>
- * Copyright (c) 2013 Marc Müller-Weinhardt <muewei@tzi.de>
- * Copyright (c) 2013 Lars Schmertmann <lars@tzi.de>
- * Copyright (c) 2013 Hauke Mehrtens <hauke@hauke-m.de>
- *
- * 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 <ckc@cockrum.net>.
- *
- * [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 <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-
-#include "ecc.h"
-#include "test_helper.h"
-
-#ifdef CONTIKI
-#include "contiki.h"
-#else
-#include <time.h>
-#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 */
+++ /dev/null
-/*
- * Copyright (c) 2009 Chris K Cockrum <ckc@cockrum.net>
- *
- * Copyright (c) 2013 Jens Trillmann <jtrillma@tzi.de>
- * Copyright (c) 2013 Marc Müller-Weinhardt <muewei@tzi.de>
- * Copyright (c) 2013 Lars Schmertmann <lars@tzi.de>
- * Copyright (c) 2013 Hauke Mehrtens <hauke@hauke-m.de>
- *
- * 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 <ckc@cockrum.net>.
- *
- * [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 <assert.h>
-#include <string.h>
-#include <stdio.h>
-#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 */
/** 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 */
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,
fprintf(stderr, "%s v%s -- DTLS client implementation\n"
"(c) 2011-2014 Olaf Bergmann <bergmann@tzi.org>\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"
#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);
}
* Below command tests this feature.
*/
#define DTLS_CLIENT_CMD_REHANDSHAKE "client:rehandshake"
+
int
main(int argc, char **argv) {
fd_set rfds, wfds;
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;
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' : {
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);
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);
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,
fprintf(stderr, "%s v%s -- DTLS server implementation\n"
"(c) 2011-2014 Olaf Bergmann <bergmann@tzi.org>\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);
}
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));
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) {
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);
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) {
#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
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 <string.h> /* memcmp,strlen */
#include <stddef.h> /* ptrdiff_t */
char **_da_dst = (char**)(&(dst)); \
*_da_dst = (char*)(src); \
} while(0)
-#else
+#else
#define DECLTYPE_ASSIGN(dst,src) \
do { \
(dst) = DECLTYPE(dst)(src); \
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
#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; \
} \
} 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 <unistd.h> to get the prototype for write(2). */
#ifdef HASH_EMIT_KEYS
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
} 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 { \
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; \
/* 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
#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) \
} \
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 { \
/* 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) \
} \
} 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 { \
#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); \
#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 {
/* 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.
* 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;
* 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
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.
* 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;
#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)
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) *
} 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); \
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 */
# Build connectivity
SConscript('csdk/connectivity/SConscript')
+# Build libocsrm
+SConscript('csdk/security/SConscript')
+
# Build liboctbstack
SConscript('csdk/SConscript')
'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'])
OCTBSTACK_SRC + 'ocserverrequest.c',
OCTBSTACK_SRC + 'occollection.c',
OCTBSTACK_SRC + 'oicgroup.c',
- 'security/src/ocsecurity.c',
'logger/src/logger.c',
'ocrandom/src/ocrandom.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
} 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
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;
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 */
* @param GetDTLSCredentials [IN] GetDTLS Credetials callback
* @return #CA_STATUS_OK
*/
-CAResult_t CARegisterDTLSCredentialsHandler(
- CAGetDTLSCredentialsHandler GetDTLSCredentials);
+CAResult_t CARegisterDTLSCredentialsHandler(CAGetDTLSCredentialsHandler GetDTLSCredentials);
#endif //__WITH_DTLS__
/**
*/
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
#include "caadapterutils.h"
#include "ocsecurityconfig.h"
#include "cainterface.h"
+#include "cacommon.h"
/**
* Currently DTLS supported adapters(2) WIFI and ETHENET for linux platform.
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
*/
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
{
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
*
*/
void CADTLSSetAdapterCallbacks(CAPacketReceivedCallback recvCallback,
- CAPacketSendCallback sendCallback, eDtlsAdapterType_t type);
+ CAPacketSendCallback sendCallback, CATransportType_t type);
/**
* @brief Register callback to get DTLS PSK credentials.
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.
*
* @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
const uint16_t port,
void *data,
uint32_t dataLen,
- uint8_t *cacheFlag,
- eDtlsAdapterType_t type);
+ CATransportType_t type);
/**
* @fn CAAdapterNetDtlsDecrypt
const uint16_t port,
uint8_t *data,
uint32_t dataLen,
- eDtlsAdapterType_t type);
+ CATransportType_t type);
#endif /* CA_ADAPTER_NET_DTLS_H_ */
* @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.
secured = sample_env.get('SECURED')
root_dir = './../../'
-
#####################################################################
# Source files and Target(s)
######################################################################
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])
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')
#include "caipinterface.h"
#include "dtls.h"
#include "oic_malloc.h"
+#include "global.h"
/**
* @def NET_DTLS_TAG
*/
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
*/
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)
{
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.
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");
OIC_LOG(DEBUG, NET_DTLS_TAG, "IN");
VERIFY_NON_NULL_VOID(msg, NET_DTLS_TAG, "msg");
- OICFree(msg->destSession);
OICFree(msg->data);
OICFree(msg);
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);
}
u_arraylist_free(&g_caDtlsContext->cacheList);
g_caDtlsContext->cacheList = NULL;
- ca_mutex_unlock(g_dtlsListMutex);
OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT");
}
{
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;
}
{
OIC_LOG(ERROR, NET_DTLS_TAG, "u_arraylist_add failed!");
}
- ca_mutex_unlock(g_dtlsListMutex);
OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT");
return result;
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)
{
++list_index;
}
}
- ca_mutex_unlock(g_dtlsListMutex);
OIC_LOG(DEBUG, NET_DTLS_TAG, "OUT");
}
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;
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;
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;
}
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);
{
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;
}
}
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);
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();
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)
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");
}
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");
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;
}
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);
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)
{
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);
return CA_STATUS_FAILED;
}
-
}
info->isSecured = remoteEndpoint->isSecured;
+ info->identity = remoteEndpoint->identity;
return info;
}
#include "canetworkconfigurator.h"
#include "cainterfacecontroller.h"
#include "logger.h"
+#ifdef __WITH_DTLS__
+#include "caadapternetdtls.h"
+#endif
#define TAG PCF("CA")
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__ */
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);
#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");
}
endPoint->addressInfo.IP.port = port;
endPoint->isSecured = isSecured;
+ if (identity)
+ {
+ endPoint->identity = *identity;
+ }
+
void *buf = OICCalloc(dataLength + 1, sizeof(char));
if (!buf)
#ifdef __WITH_DTLS__
CAAdapterNetDtlsInit();
- CADTLSSetAdapterCallbacks(CAIPPacketReceivedCB, CAIPPacketSendCB, DTLS_IP);
+ CADTLSSetAdapterCallbacks(CAIPPacketReceivedCB, CAIPPacketSendCB, CA_IPV4);
#endif
CAConnectivityHandler_t ipHandler;
CAStopIP();
#ifdef __WITH_DTLS__
- CADTLSSetAdapterCallbacks(NULL, NULL, DTLS_IP);
+ CADTLSSetAdapterCallbacks(NULL, NULL, CA_IPV4);
#endif
CAIPSetPacketReceiveCallback(NULL);
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,
#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
{
g_adapterEthServerContext->packetReceivedCallback(srcIPAddress, srcPort,
recvBuffer, recvLen,
- false);
+ false, NULL);
}
ca_mutex_unlock(g_mutexAdapterServerContext);
--- /dev/null
+LAST UPDATED 5/27/2015
+
+To build the IoTivity stack with the security features enabled:
+
+1) Build IoTivity with security enabled:
+ $ cd <iotivity-base>
+ $ scons resource SECURED=1
+
+2) Verify functionality using secure sample apps:
+ $ cd <iotivity-base>/out/<...>/release/resource/csdk/stack/samples/linux/secure
+ $ export LD_LIBRARY_PATH=<iotivity-base>/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!
+
--- /dev/null
+# //******************************************************************
+# //
+# // 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')
+
--- /dev/null
+ /******************************************************************
+ *
+ * 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 <stdint.h>
+#include <stdio.h>
+
+#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
--- /dev/null
+//******************************************************************
+//
+// 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
+
+
--- /dev/null
+//******************************************************************
+//
+// 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
+
+
--- /dev/null
+//******************************************************************
+//
+// 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
+
+
--- /dev/null
+//******************************************************************
+//
+// 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 <stdlib.h>
+#include <stdint.h>
+
+
+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
//******************************************************************
//
-// Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
+// Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
-#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
--- /dev/null
+//******************************************************************
+//
+// 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
+
+
--- /dev/null
+//******************************************************************
+//
+// 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 <stdlib.h>
+#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
+
+
--- /dev/null
+//******************************************************************
+//
+// 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_ */
--- /dev/null
+//******************************************************************
+//
+// 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
+
+++ /dev/null
-//******************************************************************
-//
-// 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 <stdint.h>
-
-#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
-
-
-
--- /dev/null
+//******************************************************************
+//
+// 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 <stdint.h> // for uint8_t typedef
+#include <stdbool.h>
+
+#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
+{
+ // <Attribute ID>:<Read/Write>:<Multiple/Single>:<Mandatory?>:<Type>
+ //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
+{
+ // <Attribute ID>:<Read/Write>:<Multiple/Single>:<Mandatory?>:<Type>
+ 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
+{
+ // <Attribute ID>:<Read/Write>:<Multiple/Single>:<Mandatory?>:<Type>
+ 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
+{
+ // <Attribute ID>:<Read/Write>:<Multiple/Single>:<Mandatory?>:<Type>
+ 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
+{
+ // <Attribute ID>:<Read/Write>:<Multiple/Single>:<Mandatory?>:<Type>
+ 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
+{
+ // <Attribute ID>:<Read/Write>:<Multiple/Single>:<Mandatory?>:<Type>
+ 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
+{
+ // <Attribute ID>:<Read/Write>:<Multiple/Single>:<Mandatory?>:<Type>
+ //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
+{
+ // <Attribute ID>:<Read/Write>:<Multiple/Single>:<Mandatory?>:<Type>
+ //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
+{
+ // <Attribute ID>:<Read/Write>:<Multiple/Single>:<Mandatory?>:<Type>
+ //TODO fill in from OIC Security Spec
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //OC_SECURITY_RESOURCE_TYPES_H
//******************************************************************
//
-// Copyright 2014 Intel Mobile Communications GmbH All Rights Reserved.
+// Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
-#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 <stdio.h>
+#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
--- /dev/null
+# //******************************************************************
+# //
+# // 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')
--- /dev/null
+/* *****************************************************************
+ *
+ * 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
--- /dev/null
+/* *****************************************************************
+ *
+ * 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
--- /dev/null
+# //******************************************************************
+# //
+# // 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'))
--- /dev/null
+{
+ "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"
+ }
+}
--- /dev/null
+/******************************************************************
+*
+* 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 <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <getopt.h>
+#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;
+}
--- /dev/null
+/* *****************************************************************
+ *
+ * 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 <string.h>
+
+#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;
+}
--- /dev/null
+/* *****************************************************************
+ *
+ * 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 <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <stdbool.h>
+
+#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;;
+}
--- /dev/null
+# //******************************************************************
+# //
+# // 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')
+
--- /dev/null
+/* *****************************************************************
+ *
+ * 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));
+}
--- /dev/null
+//******************************************************************
+//
+// 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 <stdlib.h>
+#include <string.h>
+#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 <stdlib.h>
+#include <string.h>
+
+#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;
+}
--- /dev/null
+/******************************************************************
+ *
+ * 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;
+}
+
--- /dev/null
+//******************************************************************
+//
+// 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 <stdlib.h>
+#include <string.h>
+
+#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__ */
--- /dev/null
+//******************************************************************
+//
+// 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 <stdlib.h>
+#include <string.h>
+
+#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;
+}
+++ /dev/null
-//******************************************************************
-//
-// 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 <string.h>
-
-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 ( ;(i<secConfigData->numBlob) && 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 ( ;(i<cfgData->numBlob) && 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;
-}
-
-
-
--- /dev/null
+//******************************************************************
+//
+// 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 <string.h>
+
+#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;
+}
--- /dev/null
+//******************************************************************
+//
+// 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 <stdlib.h>
+#include <string.h>
+
+#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;
+}
--- /dev/null
+//******************************************************************
+//
+// 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 <stdlib.h>
+#include <string.h>
+
+#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);
+}
+
--- /dev/null
+//******************************************************************
+//
+// 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 <string.h>
+
+#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;
+}
--- /dev/null
+//******************************************************************
+//
+// 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 <string.h>
+
+#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);
+}
--- /dev/null
+//******************************************************************
+//
+// 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 <stdlib.h>
+#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";
+
--- /dev/null
+# //******************************************************************
+# //
+# // 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')
+
--- /dev/null
+//******************************************************************
+//
+// 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 <pwd.h>
+#include <grp.h>
+#include <linux/limits.h>
+#include <sys/stat.h>
+#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);
+ }
+}
+
--- /dev/null
+ /******************************************************************
+ *
+ * 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 <stdlib.h>
+#include <stdint.h>
+
+// 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));
+ }
+ }
+}
+
--- /dev/null
+// 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
+
+
--- /dev/null
+// 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
--- /dev/null
+{
+ "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=="
+ }
+}
--- /dev/null
+{
+ "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]
+ }
+}
--- /dev/null
+{
+ "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=="
+ ]
+ }
+ ]
+}
--- /dev/null
+{
+ "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=="
+ ]
+ }
+ ]
+}
--- /dev/null
+//******************************************************************
+//
+// 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 <pwd.h>
+#include <grp.h>
+#include <linux/limits.h>
+#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);
+}
--- /dev/null
+//******************************************************************
+//
+// 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 <unistd.h>
+#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);
+ }
+}
--- /dev/null
+//******************************************************************
+//
+// 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 <pwd.h>
+#include <grp.h>
+#include <linux/limits.h>
+#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);
+}
#ifndef OCSTACK_H_
#define OCSTACK_H_
+#include <stdio.h>
#include <stdint.h>
#include "octypes.h"
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
/**
* 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;
/**
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
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')
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':
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.
}
cJSON *format;
- char *jsonResponse;
+ cJSON *putJson = NULL;
+ char *jsonResponse = NULL;
LEDResource *currLEDResource = &LED;
if (ehRequest->resource == gLedInstance[0].handle)
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);
if(!format)
{
OC_LOG (ERROR, TAG, "format object not created properly");
- cJSON_Delete(json);
- return NULL;
+ goto exit;
}
cJSON_AddItemToObject(json, "rep", format);
cJSON_AddNumberToObject(format, "power", currLEDResource->power);
jsonResponse = cJSON_Print(json);
+
+exit:
+ cJSON_Delete(putJson);
cJSON_Delete(json);
return jsonResponse;
}
######################################################################
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'))
+
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#include "common.h"
-#include "ocsecurity.h"
+#include "ocstack.h"
#include "logger.h"
#include <stdio.h>
#include <stdlib.h>
#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:
/* 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);
+++ /dev/null
-//******************************************************************
-//
-// 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 <stdio.h>
-#include <time.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-
-#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;
-}
-
-
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;
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;
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;
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);
coapServerPort = ss.str();
}
}
+
+ // If we discovered a secure resource, exit from here
+ if (coapSecureResource)
+ {
+ break;
+ }
}
}
cJSON_Delete(root);
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)
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);
cJSON_AddNumberToObject(format, "power", currLEDResource->power);
jsonResponse = cJSON_Print(json);
+
+exit:
+ cJSON_Delete(putJson);
cJSON_Delete(json);
return jsonResponse;
}
}
}
+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");
}
/*
- * 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);
--- /dev/null
+{
+ "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=="]
+ }]
+}
--- /dev/null
+{
+ "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=="]
+ }]
+}
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;
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;
#include "ocrandom.h"
#include "oic_malloc.h"
#include "ocserverrequest.h"
-#include "ocsecurityinternal.h"
-
+#include "secureresourcemanager.h"
#include "cacommon.h"
#include "cainterface.h"
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)
{
}
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
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)
{
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;
}
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()
{
&(((OCResource *) presenceResource.handle)->resourceProperties),
OC_ACTIVE, 0);
#endif
+
+ if (result == OC_STACK_OK)
+ {
+ result = SRMInitSecureResources();
+ }
+
return result;
}
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.
'../../stack/include',
'../../stack/include/internal',
'../../connectivity/api',
+ '../../connectivity/external/inc',
'../../extlibs/cjson',
'../../../oc_logger/include',
'../../../../extlibs/gtest/gtest-1.7.0/include'
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',
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,
//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());
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,
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",
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));
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,
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",
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());
}
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",
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,
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",
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
SConscript('csdk/stack/test/SConscript')
SConscript('csdk/connectivity/test/SConscript')
+
'../csdk/security/include',
'../csdk/stack/include/internal',
'../csdk/connectivity/api',
+ '../csdk/connectivity/external/inc',
'../csdk/ocsocket/include',
'../csdk/ocrandom/include',
'../csdk/logger/include',