Multiple Ownership Transfer support.
authorChul Lee <chuls.lee@samsung.com>
Fri, 14 Oct 2016 11:25:42 +0000 (20:25 +0900)
committerRandeep Singh <randeep.s@samsung.com>
Fri, 14 Oct 2016 12:46:35 +0000 (12:46 +0000)
  - Patch #1 : Initial upload
  - Patch #2 : Apply the conditional compilation for Multiple Owner features.
               e.g.) scons SECURED=1 MULTIPLE_OWNER=1
  - Patch #3 : Remove compile error for arduino
  - Patch #4-5 : Rebased for latest 1.2-rel branch
  - Patch #6 : Updated according to comment.
  - Patch #7 : Updated according to comments.
  - Patch #8 : Fixed unittest error.
  - Patch #9-10 : Fix svace issues
  - Patch #11 : Rebased with latest 1.2-rel
  - Patch #12 : Updated according to Kevin's comments.
  - Patch #13 : Rebased with latest 1.2-rel
  - Patch #14-15 : Fix svace issues
  - Patch #16 : Rebased with latest 1.2-rel
  - Patch #17 : Apply the optional compile for CA layer.

[Overview]
This patch is to support the multiple ownership transfer(MOT).
We assume the MOT authenticated client is the SubOwner.
SubOwner can access the ALL resources with full permsion except the DOXM, ACL and CRED.

This patch includes following changes :
1. Update the doxm resource to include MOT related properties.
   - New Properties
     . x.org.iotivity.mom : Mode of MOT
     . x.org.iotivity.subowneruuid : List of SubOwner
   - SubOwner has READ permission for DOXM.
   - The resource server will be update subowner list of doxm
     when MOT authentication successfully done.

2. Update the cred, acl resource to include MOT related property.
   - New Properties
     . x.org.iotivity.eowneruuid : entry owner uuid for each entry.
   - SubOwner should set the eowner as subowner's UUID
     when provision the ACL and CRED.
   - SubOwner can access only those resources that registered as eowner.

3. Update the PolicyEngine for SubOwner's access control as following :
   - DOXM : READ ONLY
   - CRED/ACL : SubOwner can access only those resources that registerd as eowner.
     . SubOwner can not provision ACL which is include the DOXM, CRED, ACL, PSTAT.
   - PSTAT : FULL permission
   - Application Resources : FULL permission

4. Add Preconfigured-PIN OxM

5. Update the sample codes
   - Test Preconfigured PIN based MOT
     1. Run the sampleserver_justworks
     2. Run the provisioningclient
     [On the provisioningclient]
     3. Perform the UnOwned Device discovery [Menu:11]
     4. Perform the OTM [Menu:20]
     5. Perform the Owned Device Discovery [Menu:12]
     6. Change the server's 'mode of MOT' [Menu:70]
     7. Perform the MOT enabled device discovery [Menu:13]
        - Check the discovered device list.
     8. POST the preconfigured-PIN credential [Menu:71]
         - sample's preconfigured-PIN is '12341234'
     9. Change the server's 'oxmsel' [Menu:72]
         - '3' is preconfigured-PIN OxM
     10. Run the subownerclient
     [On the subownerclient]
     11. Perform the MOT enabled device discovery [Menu:10]
         - Check the discovered device list.
     12. Perform the MOT [Menu:20]
     13. Perform the Multiple Owned device discovery [Menu:11]
         - Check the discovered device list.
     14. Perform the ACL provisioning TEST [Menu:40]

   - Test Random PIN based MOT
     1. Run the sampleserver_randompin
     2. Run the provisioningclient
     [On the provisioningclient]
     3. Perform the UnOwned Device discovery [Menu:11]
     4. Perform the OTM [Menu:20]
     5. Perform the Owned Device Discovery [Menu:12]
     6. Change the server's 'mode of MOT' [Menu:70]
     7. Run the subownerclient
     [On the subownerclient]
     8. Perform the MOT enabled device discovery [Menu:10]
         - Check the discovered device list.
     9. Perform the MOT [Menu:20]
         In case of random PIN based MOT, PIN input required.
     [On the sampleserver_randompin]
     10. Press 'G' or 'g' on the sampleserver_randompin.
         server will generate and display the random PIN.
     11. Input the server's PIN number on the subownerclient side.
     12. Perform the Multiple Owned device discovery [Menu:11]
         - Check the discovered device list.
     13. Perform the ACL provisioning TEST [Menu:40]
     14. Press 'E' or 'e' on the sampleserver_randompin to exit server.

Change-Id: I5449834e766d256495537d9fb469eb4d597f4c7a
Signed-off-by: Chul Lee <chuls.lee@samsung.com>
Signed-off-by: Jongmin Choi <jminl.choi@samsung.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/12063
Tested-by: jenkins-iotivity <jenkins-iotivity@opendaylight.org>
Reviewed-by: Randeep Singh <randeep.s@samsung.com>
52 files changed:
build_common/SConscript
resource/csdk/connectivity/api/casecurityinterface.h
resource/csdk/connectivity/inc/ca_adapter_net_ssl.h
resource/csdk/connectivity/inc/caadapternetdtls.h
resource/csdk/connectivity/src/SConscript
resource/csdk/connectivity/src/adapter_util/ca_adapter_net_ssl.c
resource/csdk/connectivity/src/caconnectivitymanager.c
resource/csdk/security/SConscript
resource/csdk/security/include/internal/aclresource.h
resource/csdk/security/include/internal/credresource.h
resource/csdk/security/include/internal/doxmresource.h
resource/csdk/security/include/internal/policyengine.h
resource/csdk/security/include/internal/srmresourcestrings.h
resource/csdk/security/include/pinoxmcommon.h
resource/csdk/security/include/securevirtualresourcetypes.h
resource/csdk/security/provisioning/SConscript
resource/csdk/security/provisioning/include/internal/multipleownershiptransfermanager.h [new file with mode: 0644]
resource/csdk/security/provisioning/include/ocprovisioningmanager.h
resource/csdk/security/provisioning/include/oxm/oxmpreconfpin.h [new file with mode: 0644]
resource/csdk/security/provisioning/include/pmutility.h [changed mode: 0755->0644]
resource/csdk/security/provisioning/sample/SConscript
resource/csdk/security/provisioning/sample/cloud/cloudCommon.c
resource/csdk/security/provisioning/sample/oic_svr_db_client_owned_by_subowner.dat [new file with mode: 0644]
resource/csdk/security/provisioning/sample/oic_svr_db_client_owned_by_subowner.json [new file with mode: 0644]
resource/csdk/security/provisioning/sample/oic_svr_db_subowner_client.dat [new file with mode: 0644]
resource/csdk/security/provisioning/sample/oic_svr_db_subowner_client.json [new file with mode: 0644]
resource/csdk/security/provisioning/sample/provisioningclient.c
resource/csdk/security/provisioning/sample/sampleclient_owned_by_subowner.cpp [new file with mode: 0644]
resource/csdk/security/provisioning/sample/sampleserver_randompin.cpp
resource/csdk/security/provisioning/sample/subownerclient.c [new file with mode: 0644]
resource/csdk/security/provisioning/src/credentialgenerator.c
resource/csdk/security/provisioning/src/multipleownershiptransfermanager.c [new file with mode: 0644]
resource/csdk/security/provisioning/src/ocprovisioningmanager.c
resource/csdk/security/provisioning/src/ownershiptransfermanager.c
resource/csdk/security/provisioning/src/oxmpreconfpin.c [new file with mode: 0644]
resource/csdk/security/provisioning/src/oxmrandompin.c
resource/csdk/security/provisioning/src/pmutility.c [changed mode: 0755->0644]
resource/csdk/security/provisioning/unittest/SConscript
resource/csdk/security/provisioning/unittest/otmunittest.cpp [changed mode: 0755->0644]
resource/csdk/security/src/aclresource.c
resource/csdk/security/src/credresource.c
resource/csdk/security/src/doxmresource.c
resource/csdk/security/src/dpairingresource.c
resource/csdk/security/src/oxmpincommon.c
resource/csdk/security/src/policyengine.c [changed mode: 0644->0755]
resource/csdk/security/src/secureresourcemanager.c
resource/csdk/security/src/srmresourcestrings.c
resource/csdk/security/src/srmutility.c
resource/csdk/security/tool/json2cbor.c
resource/csdk/security/unittest/SConscript
resource/csdk/security/unittest/credentialresource.cpp
resource/provisioning/examples/cloudClient.cpp

index 840ee7b..4554e03 100644 (file)
@@ -112,6 +112,7 @@ else:
 
 help_vars.Add(EnumVariable('TARGET_ARCH', 'Target architecture', default_arch, os_arch_map[target_os]))
 help_vars.Add(EnumVariable('SECURED', 'Build with DTLS', '0', allowed_values=('0', '1')))
+help_vars.Add(EnumVariable('MULTIPLE_OWNER', 'Enable multiple owner', '0', allowed_values=('0', '1')))
 help_vars.Add(EnumVariable('TEST', 'Run unit tests', '0', allowed_values=('0', '1')))
 help_vars.Add(BoolVariable('LOGGING', 'Enable stack logging', logging_default))
 help_vars.Add(BoolVariable('UPLOAD', 'Upload binary ? (For Arduino)', require_upload))
index fa3c2ef..758bbba 100644 (file)
@@ -65,6 +65,20 @@ typedef enum
 typedef int (*CAgetPskCredentialsHandler)(CADtlsPskCredType_t type,
               const uint8_t *desc, size_t desc_len,
               uint8_t *result, size_t result_length);
+
+#if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
+#ifdef _ENABLE_MULTIPLE_OWNER_
+/**
+ * API to get a secure connected peer information
+ *
+ * @param[in] peer peer information includs IP address and port.
+ *
+ * @return  secure connected peer information on success, otherwise NULL
+ */
+const CASecureEndpoint_t *CAGetSecureEndpointData(const CAEndpoint_t *peer);
+#endif //_ENABLE_MULTIPLE_OWNER_
+#endif
+
 /**
  * This internal callback is used by CA layer to
  * retrieve all credential types from SRM
index a558137..ff1cff3 100644 (file)
@@ -171,6 +171,18 @@ CAResult_t CAsslGenerateOwnerPsk(const CAEndpoint_t *endpoint,
                     const uint8_t* rsrcServerDeviceId, const size_t rsrcServerDeviceIdLen,
                     const uint8_t* provServerDeviceId, const size_t provServerDeviceIdLen,
                     uint8_t* ownerPsk, const size_t ownerPskSize);
+
+#ifdef _ENABLE_MULTIPLE_OWNER_
+/**
+ * Gets CA secure endpoint info corresponding for endpoint.
+ *
+ * @param[in]  peer    remote address
+ *
+ * @return  CASecureEndpoint or NULL
+ */
+const CASecureEndpoint_t *GetCASecureEndpointData(const CAEndpoint_t* peer);
+#endif
+
 #ifdef __cplusplus
 }
 #endif //__cplusplus
index dcc2366..c9fe9ab 100644 (file)
@@ -132,12 +132,6 @@ void CADTLSSetAdapterCallbacks(CAPacketReceivedCallback recvCallback,
 void CADTLSSetHandshakeCallback(CAErrorCallback dtlsHandshakeCallback);
 
 /**
- * Register callback to get DTLS PSK credentials.
- * @param[in]  credCallback    callback to get DTLS PSK credentials.
- */
-void CADTLSSetCredentialsCallback(CAGetDTLSPskCredentialsHandler credCallback);
-
-/**
  * Select the cipher suite for dtls handshake
  *
  * @param[in] cipher    cipher suite
@@ -256,6 +250,18 @@ CAResult_t CAAdapterNetDtlsDecrypt(const CASecureEndpoint_t *sep,
                                    uint8_t *data,
                                    uint32_t dataLen);
 
+
+/**
+ * API to get a secure connected peer information
+ * NOTE : This API use the mutex lock to access 'g_caDtlsContext',
+ *        Please do not invoke this API for internal function of dtls adapter
+ *
+ * @param[in] peer peer information includs IP address and port.
+ *
+ * @ return  secure connected peer information on success, otherwise NULL
+ */
+CASecureEndpoint_t *CAGetSecurePeerInfo(const CAEndpoint_t *peer);
+
 #endif /* CA_ADAPTER_NET_DTLS_H_ */
 
 
index 573207f..6ac7921 100644 (file)
@@ -8,6 +8,7 @@ Import('env')
 ca_os = env.get('TARGET_OS')
 ca_transport = env.get('TARGET_TRANSPORT')
 secured = env.get('SECURED')
+multiple_owner = env.get('MULTIPLE_OWNER')
 with_ra = env.get ('WITH_RA')
 with_ra_ibb = env.get('WITH_RA_IBB')
 with_tcp = env.get('WITH_TCP')
@@ -84,6 +85,9 @@ if env.get('SECURED') == '1':
 if ((secured == '1') and (with_tcp == True)):
        env.AppendUnique(CPPDEFINES = ['__WITH_TLS__'])
 
+if (multiple_owner == '1'):
+       env.AppendUnique(CPPDEFINES=['_ENABLE_MULTIPLE_OWNER_'])
+
 
 ca_common_src = None
 
@@ -135,14 +139,14 @@ if 'ALL' in ca_transport:
                if with_ra:
                                transports.append('ra_adapter')
 
-               if ca_os in ['linux']: 
+               if ca_os in ['linux']:
                                transports.append('ip_adapter')
                                transports.append('bt_le_adapter')
-               elif ca_os in ['tizen']: 
+               elif ca_os in ['tizen']:
                                transports.append('ip_adapter')
                                transports.append('bt_edr_adapter')
                                transports.append('bt_le_adapter')
-               elif ca_os in ['android']: 
+               elif ca_os in ['android']:
                                transports.append('ip_adapter')
                                transports.append('bt_edr_adapter')
                                transports.append('bt_le_adapter')
index b88e2a0..d43b27a 100644 (file)
@@ -765,6 +765,45 @@ static SslEndPoint_t *GetSslPeer(const CAEndpoint_t *peer)
     OIC_LOG_V(DEBUG, NET_SSL_TAG, "Out %s", __func__);
     return NULL;
 }
+
+#ifdef _ENABLE_MULTIPLE_OWNER_
+/**
+ * Gets CA secure endpoint info corresponding for endpoint.
+ *
+ * @param[in]  peer    remote address
+ *
+ * @return  CASecureEndpoint or NULL
+ */
+const CASecureEndpoint_t *GetCASecureEndpointData(const CAEndpoint_t* peer)
+{
+    OIC_LOG_V(DEBUG, NET_SSL_TAG, "In %s", __func__);
+
+    // TODO: Added as workaround, need to debug
+    ca_mutex_unlock(g_sslContextMutex);
+
+    ca_mutex_lock(g_sslContextMutex);
+    if (NULL == g_caSslContext)
+    {
+        OIC_LOG(ERROR, NET_SSL_TAG, "Context is NULL");
+        ca_mutex_unlock(g_sslContextMutex);
+        return NULL;
+    }
+
+    SslEndPoint_t* sslPeer = GetSslPeer(peer);
+    if(sslPeer)
+    {
+        OIC_LOG_V(DEBUG, NET_SSL_TAG, "Out %s", __func__);
+        ca_mutex_unlock(g_sslContextMutex);
+        return &sslPeer->sep;
+    }
+
+    OIC_LOG(DEBUG, NET_SSL_TAG, "Return NULL");
+    OIC_LOG_V(DEBUG, NET_SSL_TAG, "Out %s", __func__);
+    ca_mutex_unlock(g_sslContextMutex);
+    return NULL;
+}
+#endif
+
 /**
  * Deletes cached message.
  *
@@ -1959,6 +1998,9 @@ CAResult_t CAsslGenerateOwnerPsk(const CAEndpoint_t *endpoint,
     VERIFY_NON_NULL_RET(provServerDeviceId, NET_SSL_TAG, "provId is NULL", CA_STATUS_INVALID_PARAM);
     VERIFY_NON_NULL_RET(ownerPsk, NET_SSL_TAG, "ownerPSK is NULL", CA_STATUS_INVALID_PARAM);
 
+    // TODO: Added as workaround, need to debug
+    ca_mutex_unlock(g_sslContextMutex);
+
     ca_mutex_lock(g_sslContextMutex);
     if (NULL == g_caSslContext)
     {
index f430de2..13ebf36 100644 (file)
@@ -140,11 +140,27 @@ void CARegisterHandler(CARequestCallback ReqHandler, CAResponseCallback RespHand
 
     CASetInterfaceCallbacks(ReqHandler, RespHandler, ErrorHandler);
 }
+
 #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
+#ifdef _ENABLE_MULTIPLE_OWNER_
+const CASecureEndpoint_t *CAGetSecureEndpointData(const CAEndpoint_t *peer)
+{
+    OIC_LOG(DEBUG, TAG, "IN CAGetSecurePeerInfo");
+
+    if (!g_isInitialized)
+    {
+        OIC_LOG(DEBUG, TAG, "CA is not initialized");
+        return NULL;
+    }
+
+    OIC_LOG(DEBUG, TAG, "OUT CAGetSecurePeerInfo");
+    return GetCASecureEndpointData(peer);
+}
+#endif //_ENABLE_MULTIPLE_OWNER_
+
 CAResult_t CAregisterSslHandshakeCallback(CAErrorCallback tlsHandshakeCallback)
 {
     OIC_LOG(DEBUG, TAG, "CAregisterSslHandshakeCallback");
-
     if(!g_isInitialized)
     {
         return CA_STATUS_NOT_INITIALIZED;
index a1e5f11..834e8b5 100644 (file)
@@ -88,6 +88,9 @@ if target_os in ['darwin', 'ios']:
 if env.get('LOGGING'):
        libocsrm_env.AppendUnique(CPPDEFINES = ['TB_LOG'])
 
+if env.get('MULTIPLE_OWNER') == '1':
+       libocsrm_env.AppendUnique(CPPDEFINES=['_ENABLE_MULTIPLE_OWNER_'])
+
 ######################################################################
 # Source files and Targets
 ######################################################################
index 93661b2..5fd9d7c 100644 (file)
@@ -62,6 +62,20 @@ const OicSecAce_t* GetACLResourceData(const OicUuid_t* subjectId, OicSecAce_t **
  */
 OCStackResult AclToCBORPayload(const OicSecAcl_t * acl, uint8_t **outPayload, size_t *size);
 
+#ifdef _ENABLE_MULTIPLE_OWNER_
+/**
+ * Function to check the ACL access of SubOwner
+ *
+ * @param[in] uuid SubOwner's UUID
+ * @param[in] cborPayload CBOR payload of ACL
+ * @param[in] size Byte length of cborPayload
+ *
+ * @return ::true for valid access, otherwise invalid access
+ */
+bool IsValidAclAccessForSubOwner(const OicUuid_t* uuid, const uint8_t *cborPayload, const size_t size);
+#endif //_ENABLE_MULTIPLE_OWNER_
+
+
 /**
  * This method removes ACE for the subject and resource from the ACL
  *
index 0ba8041..427efc7 100644 (file)
@@ -80,6 +80,19 @@ OicSecCred_t* GetCredResourceDataByCredId(const uint16_t credId);
 OCStackResult CredToCBORPayload(const OicSecCred_t* cred, uint8_t **cborPayload,
                                 size_t *cborSize, int secureFlag);
 
+#ifdef _ENABLE_MULTIPLE_OWNER_
+/**
+ * Function to check the credential access of SubOwner
+ *
+ * @param[in] uuid SubOwner's UUID
+ * @param[in] cborPayload CBOR payload of credential
+ * @param[in] size Byte length of cborPayload
+ *
+ * @return ::true for valid access, otherwise invalid access
+ */
+bool IsValidCredentialAccessForSubOwner(const OicUuid_t* uuid, const uint8_t *cborPayload, size_t size);
+#endif //_ENABLE_MULTIPLE_OWNER_
+
 /**
  * This function generates the bin credential data.
  *
@@ -88,13 +101,14 @@ OCStackResult CredToCBORPayload(const OicSecCred_t* cred, uint8_t **cborPayload,
  * @param publicData public data such as public key.
  * @param privateData private data such as private key.
  * @param rownerID Resource owner's UUID.
+ * @param eownerID Entry owner's UUID.
  *
  * @return pointer to instance of @ref OicSecCred_t if successful. else NULL in case of error.
 
  */
 OicSecCred_t * GenerateCredential(const OicUuid_t* subject, OicSecCredType_t credType,
                      const OicSecCert_t * publicData, const OicSecKey_t * privateData,
-                     const OicUuid_t * rownerID);
+                     const OicUuid_t * rownerID, const OicUuid_t * eownerID);
 
 /**
  * This function adds the new cred to the credential list.
index 70cf357..826c187 100644 (file)
@@ -22,6 +22,9 @@
 #define IOTVT_SRM_DOXM_H
 
 #include "octypes.h"
+#ifdef _ENABLE_MULTIPLE_OWNER_
+#include "cacommon.h"
+#endif //_ENABLE_MULTIPLE_OWNER_
 
 #ifdef __cplusplus
 extern "C" {
@@ -106,7 +109,7 @@ OCStackResult GetDoxmDevOwnerId(OicUuid_t *devownerid);
  * Gets the bool state of "isOwned" property on the doxm resource.
  *
  * @param isOwned a pointer to be assigned to isOwned property
- * @return ::OC_STACK_OK if isOwned is assigned correctly, else ::OC_STACK_ERROR. 
+ * @return ::OC_STACK_OK if isOwned is assigned correctly, else ::OC_STACK_ERROR.
  */
 OCStackResult GetDoxmIsOwned(bool *isOwned);
 
@@ -118,6 +121,17 @@ OCStackResult GetDoxmIsOwned(bool *isOwned);
  */
 OCStackResult GetDoxmRownerId(OicUuid_t *rowneruuid);
 
+#ifdef _ENABLE_MULTIPLE_OWNER_
+/**
+ * Compare the UUID to SubOwner.
+ *
+ * @param[in] uuid device UUID
+ *
+ * @return true if uuid exists in the SubOwner list of doxm, else false.
+ */
+bool IsSubOwner(const OicUuid_t* uuid);
+#endif //_ENABLE_MULTIPLE_OWNER_
+
 /** This function deallocates the memory for OicSecDoxm_t .
  *
  * @param doxm is the pointer to @ref OicSecDoxm_t.
@@ -130,6 +144,16 @@ void DeleteDoxmBinData(OicSecDoxm_t* doxm);
  */
 void RestoreDoxmToInitState();
 
+#if defined(__WITH_DTLS__) && defined(_ENABLE_MULTIPLE_OWNER_)
+/**
+ * Callback function to handle MOT DTLS handshake result.
+ * @param[out]   object           remote device information.
+ * @param[out]   errorInfo        CA Error information.
+ */
+void MultipleOwnerDTLSHandshakeCB(const CAEndpoint_t *object,
+                                const CAErrorInfo_t *errorInfo);
+#endif //__WITH_DTLS__ && _ENABLE_MULTIPLE_OWNER_
+
 #ifdef __cplusplus
 }
 #endif
index f28498e..f8b333c 100644 (file)
@@ -50,6 +50,11 @@ typedef struct PEContext
     bool        amsProcessing;
     SRMAccessResponse_t retVal;
     AmsMgrContext_t     *amsMgrContext;
+
+#ifdef _ENABLE_MULTIPLE_OWNER_
+    uint8_t* payload;
+    size_t payloadSize;
+#endif //_ENABLE_MULTIPLE_OWNER_
 } PEContext_t;
 
 /**
index ba7bcf6..88139fe 100644 (file)
@@ -101,9 +101,15 @@ 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_DEVOWNERID_NAME;
+#ifdef _ENABLE_MULTIPLE_OWNER_
+extern const char * OIC_JSON_SUBOWNERID_NAME;
+#endif //_ENABLE_MULTIPLE_OWNER_
 extern const char * OIC_JSON_OWNED_NAME;
 extern const char * OIC_JSON_OXM_NAME;
 extern const char * OIC_JSON_OXMS_NAME;
+#ifdef _ENABLE_MULTIPLE_OWNER_
+extern const char * OIC_JSON_MOM_NAME;
+#endif //_ENABLE_MULTIPLE_OWNER_
 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;
@@ -146,6 +152,9 @@ extern const char * OIC_JSON_REL_NAME;
 extern const char * OIC_JSON_RT_NAME;
 extern const char * OIC_JSON_IF_NAME;
 extern const char * OIC_JSON_ROWNERID_NAME;
+#ifdef _ENABLE_MULTIPLE_OWNER_
+extern const char * OIC_JSON_EOWNERID_NAME;
+#endif //_ENABLE_MULTIPLE_OWNER_
 extern const char * OIC_JSON_ENCODING_NAME;
 extern const char * OIC_JSON_DATA_NAME;
 extern const char * OIC_JSON_SEC_V_NAME;
@@ -164,6 +173,9 @@ extern const char * WILDCARD_RESOURCE_URI;
 extern const char * OXM_JUST_WORKS;
 extern const char * OXM_RANDOM_DEVICE_PIN;
 extern const char * OXM_MANUFACTURER_CERTIFICATE;
+#ifdef _ENABLE_MULTIPLE_OWNER_
+extern const char * OXM_PRECONF_PIN;
+#endif //_ENABLE_MULTIPLE_OWNER_
 
 extern const char * OIC_SEC_ENCODING_BASE64;
 extern const char * OIC_SEC_ENCODING_RAW;
index 67f07ac..f9b9178 100644 (file)
@@ -28,7 +28,9 @@
  extern "C" {
 #endif // __cplusplus
 
-#define OXM_RANDOM_PIN_SIZE 8
+#define OXM_RANDOM_PIN_SIZE (8)
+#define OXM_PRECONFIG_PIN_SIZE (OXM_RANDOM_PIN_SIZE)
+
 
 /**
  * Function pointer to print pin code.
@@ -54,6 +56,15 @@ void SetGeneratePinCB(GeneratePinCallback pinCB);
  */
 void SetInputPinCB(InputPinCallback pinCB);
 
+#ifdef _ENABLE_MULTIPLE_OWNER_
+/**
+ * Function to save the preconfig PIN getter from user.
+ *
+ * @param pinCB implementation of preconfig PIN function.
+ */
+void SetGetPreconfigPinCB(InputPinCallback pinCB);
+#endif //_ENABLE_MULTIPLE_OWNER_
+
 /**
  * Function to generate random PIN.
  * This function will send generated PIN to user via callback.
@@ -75,22 +86,45 @@ OCStackResult GeneratePin(char* pinBuffer, size_t bufferSize);
  */
 OCStackResult InputPin(char* pinBuffer, size_t bufferSize);
 
+
+#ifdef _ENABLE_MULTIPLE_OWNER_
+/**
+ * Function to save the Pre-configured PIN.
+ *
+ * @param[in] pinBuffer PIN data
+ * @param[in] pinLength byte length of PIN
+ *
+ * @return ::OC_STACK_SUCCESS in case of success or other value in ccase of error.
+ */
+OCStackResult SetPreconfigPin(const char* pinBuffer, size_t pinLength);
+
+/**
+ * Function to read preconfig PIN.
+ *
+ * @param[in,out] pinBuffer is the reference to the buffer to store the preconfigured PIN.
+ * @param[in] bufferSize is the size of buffer.
+ *
+ * @return ::OC_STACK_SUCCESS in case of success or other value in ccase of error.
+ */
+OCStackResult GetPreconfigPin(char* pinBuffer, size_t bufferSize);
+#endif
+
 #ifdef __WITH_DTLS__
 
 /**
  * This function is used by OTM and SRM to
  * register device UUID is required to derive the temporal PSK.
  */
-void SetUuidForRandomPinOxm(const OicUuid_t* uuid);
+void SetUuidForPinBasedOxm(const OicUuid_t* uuid);
 
 /**
- * This internal callback is used while PIN based ownership transfer.
+ * This internal callback is used while Random PIN based OTM.
  * This callback will be used to establish a temporary secure session according to
  * TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256.
  *
  * @param[in]  type type of PSK data required by tinyDTLS layer during DTLS handshake.
- * @param[in]  desc UNUSED.
- * @param[in]  desc_len UNUSED.
+ * @param[in]  UNUSED1 UNUSED.
+ * @param[in]  UNUSED2 UNUSED.
  * @param[out] result  Must be filled with the requested information.
  * @param[in]  result_length  Maximum size of @p result.
  *
@@ -100,6 +134,77 @@ void SetUuidForRandomPinOxm(const OicUuid_t* uuid);
 int32_t GetDtlsPskForRandomPinOxm( CADtlsPskCredType_t type,
               const unsigned char *UNUSED1, size_t UNUSED2,
               unsigned char *result, size_t result_length);
+
+#ifdef _ENABLE_MULTIPLE_OWNER_
+/**
+ * This internal callback is used while Random PIN based MOT.
+ * This callback will be used to establish a temporary secure session according to
+ * TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256.
+ *
+ * @param[in]  type type of PSK data required by tinyDTLS layer during DTLS handshake.
+ * @param[in]  UNUSED1 UNUSED.
+ * @param[in]  UNUSED2 UNUSED.
+ * @param[out] result  Must be filled with the requested information.
+ * @param[in]  result_length  Maximum size of @p result.
+ *
+ * @return The number of bytes written to @p result or a value
+ *         less than zero on error.
+ */
+int32_t GetDtlsPskForMotRandomPinOxm( CADtlsPskCredType_t type,
+              const unsigned char *UNUSED1, size_t UNUSED2,
+              unsigned char *result, size_t result_length);
+
+
+/**
+ * This internal callback is used while Preconfigured-PIN OTM.
+ * This callback will be used to establish a temporary secure session according to
+ * TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256.
+ *
+ * @param[in]  type type of PSK data required by tinyDTLS layer during DTLS handshake.
+ * @param[in]  UNUSED1 UNUSED.
+ * @param[in]  UNUSED2 UNUSED.
+ * @param[out] result  Must be filled with the requested information.
+ * @param[in]  result_length  Maximum size of @p result.
+ *
+ * @return The number of bytes written to @p result or a value
+ *         less than zero on error.
+ */
+int32_t GetDtlsPskForPreconfPinOxm( CADtlsPskCredType_t type,
+              const unsigned char *UNUSED1, size_t UNUSED2,
+              unsigned char *result, size_t result_length);
+
+
+/**
+ * This internal callback is used while Preconfigured-PIN MOT.
+ * This callback will be used to establish a temporary secure session according to
+ * TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256.
+ *
+ * @param[in]  type type of PSK data required by tinyDTLS layer during DTLS handshake.
+ * @param[in]  UNUSED1 UNUSED.
+ * @param[in]  UNUSED2 UNUSED.
+ * @param[out] result  Must be filled with the requested information.
+ * @param[in]  result_length  Maximum size of @p result.
+ *
+ * @return The number of bytes written to @p result or a value
+ *         less than zero on error.
+ */
+int32_t GetDtlsPskForMotPreconfPinOxm( CADtlsPskCredType_t type,
+              const unsigned char *UNUSED1, size_t UNUSED2,
+              unsigned char *result, size_t result_length);
+
+#endif //_ENABLE_MULTIPLE_OWNER_
+
+
+/**
+ * API to derive the PSK based on PIN and new device's UUID.
+ * New device's UUID should be set through SetUuidForPinBasedOxm() API before this API is invoked.
+ *
+ * @param[out] result generated PSK
+ *
+ * @return 0 for success, otherwise error.
+ */
+int DerivePSKUsingPIN(uint8_t* result);
+
 #endif //__WITH_DTLS__
 
 #ifdef __cplusplus
index 8e035d9..1641f48 100644 (file)
@@ -219,7 +219,10 @@ typedef enum OicSecDpm
     SECURITY_MANAGEMENT_SERVICES    = (0x1 << 3),
     PROVISION_CREDENTIALS           = (0x1 << 4),
     PROVISION_ACLS                  = (0x1 << 5),
-    // << 6 THROUGH 15 RESERVED
+#ifdef _ENABLE_MULTIPLE_OWNER_
+    TAKE_SUB_OWNER                  = (0x1 << 6),
+#endif
+    // << 7 THROUGH 15 RESERVED
 } OicSecDpm_t;
 
 // These types are taken from the Security Spec v1.1.12 /pstat resource definition
@@ -268,6 +271,9 @@ typedef enum
     OIC_JUST_WORKS                          = 0x0,
     OIC_RANDOM_DEVICE_PIN                   = 0x1,
     OIC_MANUFACTURER_CERTIFICATE           = 0x2,
+#ifdef _ENABLE_MULTIPLE_OWNER_
+    OIC_PRECONFIG_PIN                      = 0x3,
+#endif //_ENABLE_MULTIPLE_OWNER_
     OIC_OXM_COUNT
 }OicSecOxm_t;
 
@@ -280,6 +286,30 @@ typedef enum
     OIC_ENCODING_DER = 4
 }OicEncodingType_t;
 
+#ifdef _ENABLE_MULTIPLE_OWNER_
+typedef enum
+{
+    MOT_STATUS_READY = 0,
+    MOT_STATUS_IN_PROGRESS = 1,
+    MOT_STATUS_DONE = 2,
+}MotStatus_t;
+#endif //_ENABLE_MULTIPLE_OWNER_
+
+/*
+ * oic.sec.mom type definition
+ * TODO: This type will be included to OIC Security Spec.
+ * 0 : Disable multiple owner
+ * 1 : Enable multiple owner (Always on)
+ * 2 : Timely multiple owner enable
+ */
+typedef enum
+{
+    OIC_MULTIPLE_OWNER_DISABLE = 0,
+    OIC_MULTIPLE_OWNER_ENABLE = 1,
+    OIC_MULTIPLE_OWNER_TIMELY_ENABLE = 2,
+    OIC_NUMBER_OF_MOM_TYPE = 3
+}OicSecMomType_t;
+
 typedef struct OicSecKey OicSecKey_t;
 
 typedef struct OicSecPstat OicSecPstat_t;
@@ -294,6 +324,11 @@ typedef char *OicUrn_t; //TODO is URN type defined elsewhere?
 
 typedef struct OicUuid OicUuid_t; //TODO is UUID type defined elsewhere?
 
+#ifdef _ENABLE_MULTIPLE_OWNER_
+typedef struct OicSecSubOwner OicSecSubOwner_t;
+typedef struct OicSecMom OicSecMom_t;
+#endif //_ENABLE_MULTIPLE_OWNER_
+
 
 #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
 typedef struct OicSecCrl OicSecCrl_t;
@@ -355,10 +390,13 @@ struct OicSecValidity
 struct OicSecAce
 {
     // <Attribute ID>:<Read/Write>:<Multiple/Single>:<Mandatory?>:<Type>
-    OicUuid_t subjectuuid; // 0:R:S:Y:uuid
-    OicSecRsrc_t *resources; // 1:R:M:Y:Resource
-    uint16_t permission; // 2:R:S:Y:UINT16
-    OicSecValidity_t *validities; // 3:R:M:N:Time-interval
+    OicUuid_t subjectuuid;              // 0:R:S:Y:uuid
+    OicSecRsrc_t *resources;            // 1:R:M:Y:Resource
+    uint16_t permission;                // 2:R:S:Y:UINT16
+    OicSecValidity_t *validities;       // 3:R:M:N:Time-interval
+#ifdef _ENABLE_MULTIPLE_OWNER_
+    OicUuid_t* eownerID;                //4:R:S:N:oic.uuid
+#endif
     OicSecAce_t *next;
 };
 
@@ -409,10 +447,25 @@ struct OicSecCred
 #endif /* __WITH_DTLS__  or __WITH_TLS__*/
     OicSecKey_t         privateData;    // 6:R:S:N:oic.sec.key
     char                *period;        // 7:R:S:N:String
-    OicUuid_t           rownerID;        // 8:R:S:Y:oic.uuid
+    OicUuid_t           rownerID;       // 8:R:S:Y:oic.uuid
+#ifdef _ENABLE_MULTIPLE_OWNER_
+    OicUuid_t           *eownerID;      //9:R:S:N:oic.uuid
+#endif //_ENABLE_MULTIPLE_OWNER_
     OicSecCred_t        *next;
 };
 
+#ifdef _ENABLE_MULTIPLE_OWNER_
+struct OicSecSubOwner {
+    OicUuid_t uuid;
+    MotStatus_t status;
+    OicSecSubOwner_t* next;
+};
+
+struct OicSecMom{
+    OicSecMomType_t mode;
+};
+#endif //_ENABLE_MULTIPLE_OWNER_
+
 /**
  * /oic/sec/doxm (Device Owner Transfer Methods) data type
  * Derived from OIC Security Spec; see Spec for details.
@@ -432,7 +485,11 @@ struct OicSecDoxm
     OicUuid_t           deviceID;       // 6:R:S:Y:oic.uuid
     bool                dpc;            // 7:R:S:Y:Boolean
     OicUuid_t           owner;          // 8:R:S:Y:oic.uuid
-    OicUuid_t           rownerID;       // 9:R:S:Y:oic.uuid
+#ifdef _ENABLE_MULTIPLE_OWNER_
+    OicSecSubOwner_t* subOwners;        //9:R/W:M:N:oic.uuid
+    OicSecMom_t *mom;                   //10:R/W:S:N:oic.sec.mom
+#endif //_ENABLE_MULTIPLE_OWNER_
+    OicUuid_t           rownerID;       // 11:R:S:Y:oic.uuid
 };
 
 /**
index 4ef5a44..4b67035 100644 (file)
@@ -89,6 +89,9 @@ if target_os in ['darwin', 'ios']:
 if provisioning_env.get('LOGGING'):
     provisioning_env.AppendUnique(CPPDEFINES = ['TB_LOG'])
 
+if provisioning_env.get('MULTIPLE_OWNER') == '1':
+       provisioning_env.AppendUnique(CPPDEFINES=['_ENABLE_MULTIPLE_OWNER_'])
+
 ######################################################################
 # Source files and Targets
 ######################################################################
@@ -102,6 +105,11 @@ provisioning_src = [
        'src/oxmrandompin.c',
        'src/provisioningdatabasemanager.c' ]
 
+if provisioning_env.get('MULTIPLE_OWNER') == '1':
+       provisioning_src = provisioning_src + [
+               'src/multipleownershiptransfermanager.c',
+               'src/oxmpreconfpin.c']
+
 if provisioning_env.get('WITH_TCP') == True:
        provisioning_env.AppendUnique(CPPDEFINES= ['__WITH_TLS__'])
        provisioning_src = provisioning_src + [
diff --git a/resource/csdk/security/provisioning/include/internal/multipleownershiptransfermanager.h b/resource/csdk/security/provisioning/include/internal/multipleownershiptransfermanager.h
new file mode 100644 (file)
index 0000000..cd35605
--- /dev/null
@@ -0,0 +1,117 @@
+/* *****************************************************************
+ *
+ * Copyright 2016 Samsung Electronics All Rights Reserved.
+ *
+ *
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * *****************************************************************/
+
+#ifndef OTM_MULTIPLE_OWNERSHIPTRANSFERMANAGER_H_
+#define OTM_MULTIPLE_OWNERSHIPTRANSFERMANAGER_H_
+
+#include "pmtypes.h"
+#include "ocstack.h"
+#include "octypes.h"
+#include "securevirtualresourcetypes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+/**********************************************************************
+ * API for Super Owner
+ **********************************************************************/
+
+/**
+ * API to add 'doxm.oxms' to resource server.
+ *
+ * @param[in] targetDeviceInfo Selected target device.
+ * @param[in] newOxm  OxMs to be added (ref. oic.sec.oxm)
+ * @param[in] resultCallback callback provided by API user, callback will be called when
+ *            POST 'oxms' request recieves a response from resource server.
+ * @return OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult MOTAddMOTMethod(void *ctx, OCProvisionDev_t *targetDeviceInfo,
+                                 const OicSecOxm_t newOxm, OCProvisionResultCB resultCallback);
+
+/**
+ * API to update 'doxm.oxmsel' to resource server.
+ *
+ * @param[in] targetDeviceInfo Selected target device.
+ * @param[in] oxmSelValue Method of multiple ownership transfer (ref. oic.sec.oxm)
+ * @param[in] resultCallback callback provided by API user, callback will be called when
+ *            POST 'oxmsel' request recieves a response from resource server.
+ * @return OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult MOTSelectMOTMethod(void *ctx, const OCProvisionDev_t *targetDeviceInfo,
+        const OicSecOxm_t oxmSelValue, OCProvisionResultCB resultCallback);
+
+/**
+ * API to update 'doxm.mom' to resource server.
+ *
+ * @param[in] targetDeviceInfo Selected target device.
+ * @param[in] momType Mode of multiple ownership transfer (ref. oic.sec.mom)
+ * @param[in] resultCallback callback provided by API user, callback will be called when
+ *            POST 'mom' request recieves a response from resource server.
+ * @return OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult MOTChangeMode(void *ctx, const OCProvisionDev_t *targetDeviceInfo,
+        const OicSecMomType_t momType, OCProvisionResultCB resultCallback);
+
+/**
+ * API to provision preconfigured PIN to resource server.
+ *
+ * @param[in] targetDeviceInfo Selected target device.
+ * @param[in] preconfPIN Preconfig PIN which is used while multiple owner authentication
+ * @param[in] preconfPINLen Byte length of preconfig PIN
+ * @param[in] resultCallback callback provided by API user, callback will be called when
+ *            POST credential request recieves a response from resource server.
+ * @return OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult MOTProvisionPreconfigPIN(void *ctx, const OCProvisionDev_t *targetDeviceInfo,
+                                 const char* preconfPIN, size_t preconfPINLen, OCProvisionResultCB resultCallback);
+
+/**********************************************************************
+ * API for Sub Owner
+ **********************************************************************/
+
+/**
+ * API to perform the multiple ownership transfer.
+ *
+ * @param[in] ctx Application context would be returned in result callback
+ * @param[in] selectedDeviceList linked list of multiple ownership transfer candidate devices.
+ * @param[in] resultCB Result callback function to be invoked when multiple ownership transfer finished.
+ * @return OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult MOTDoOwnershipTransfer(void* ctx,
+                                     OCProvisionDev_t *selectedDevicelist,
+                                     OCProvisionResultCB resultCallback);
+
+
+/**
+ * API to add preconfigured PIN to local SVR DB.
+ *
+ * @param[in] targetDeviceInfo Selected target device.
+ * @param[in] preconfPIN Preconfig PIN which is used while multiple owner authentication
+ * @param[in] preconfPINLen Byte length of preconfig PIN
+ * @return OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult MOTAddPreconfigPIN(const OCProvisionDev_t *targetDeviceInfo,
+                                 const char* preconfPIN, size_t preconfPINLen);
+
+#ifdef __cplusplus
+}
+#endif
+#endif //OTM_MULTIPLE_OWNERSHIPTRANSFERMANAGER_H_
\ No newline at end of file
index 4dbf992..9531f4f 100755 (executable)
@@ -24,6 +24,9 @@
 #include "octypes.h"\r
 #include "pmtypes.h"\r
 #include "ownershiptransfermanager.h"\r
+#ifdef _ENABLE_MULTIPLE_OWNER_\r
+#include "securevirtualresourcetypes.h"\r
+#endif //_ENABLE_MULTIPLE_OWNER_\r
 \r
 #ifdef __cplusplus\r
 extern "C" {\r
@@ -78,6 +81,20 @@ OCStackResult OCDoOwnershipTransfer(void* ctx,
                                     OCProvisionDev_t *targetDevices,\r
                                     OCProvisionResultCB resultCallback);\r
 \r
+#ifdef _ENABLE_MULTIPLE_OWNER_\r
+/**\r
+ * API to perfrom multiple ownership transfer for MOT enabled device.\r
+ *\r
+ * @param[in] ctx Application context would be returned in result callback\r
+ * @param[in] targetDevices List of devices to perform ownership transfer.\r
+ * @param[in] resultCallback Result callback function to be invoked when ownership transfer finished.\r
+ * @return OC_STACK_OK in case of success and other value otherwise.\r
+ */\r
+OCStackResult OCDoMultipleOwnershipTransfer(void* ctx,\r
+                                      OCProvisionDev_t *targetDevices,\r
+                                      OCProvisionResultCB resultCallback);\r
+#endif //_ENABLE_MULTIPLE_OWNER_\r
+\r
 /**\r
  * API to register for particular OxM.\r
  *\r
@@ -98,6 +115,28 @@ OCStackResult OCSetOwnerTransferCallbackData(OicSecOxm_t oxm, OTMCallbackData_t*
  */\r
 OCStackResult OCDiscoverOwnedDevices(unsigned short timeout, OCProvisionDev_t **ppList);\r
 \r
+#ifdef _ENABLE_MULTIPLE_OWNER_\r
+/**\r
+ * The function is responsible for discovery of MOT enabled device is current subnet.\r
+ *\r
+ * @param[in] timeout Timeout in seconds, value till which function will listen to responses from\r
+ *                    server before returning the list of devices.\r
+ * @param[out] ppList List of MOT enabled devices.\r
+ * @return OC_STACK_OK in case of success and other value otherwise.\r
+ */\r
+OCStackResult OCDiscoverMultipleOwnerEnabledDevices(unsigned short timeout, OCProvisionDev_t **ppList);\r
+\r
+/**\r
+ * The function is responsible for discovery of Multiple Owned device is current subnet.\r
+ *\r
+ * @param[in] timeout Timeout in seconds, value till which function will listen to responses from\r
+ *                    server before returning the list of devices.\r
+ * @param[out] ppList List of Multiple Owned devices.\r
+ * @return OC_STACK_OK in case of success and other value otherwise.\r
+ */\r
+OCStackResult OCDiscoverMultipleOwnedDevices(unsigned short timeout, OCProvisionDev_t **ppList);\r
+#endif //_ENABLE_MULTIPLE_OWNER_\r
+\r
 /**\r
  * API to provision credentials between two devices and ACLs for the devices who act as a server.\r
  *\r
@@ -182,6 +221,62 @@ OCStackResult OCProvisionCredentials(void *ctx, OicSecCredType_t type, size_t ke
                                       const OCProvisionDev_t *pDev2,\r
                                       OCProvisionResultCB resultCallback);\r
 \r
+#ifdef _ENABLE_MULTIPLE_OWNER_\r
+/**\r
+ * API to provision preconfigured PIN to device(NOT LIST).\r
+ * If device does not support the Preconfigured PIN OxM,\r
+ * OCProvisionPreconfPin API will be update the device's Doxm\r
+ * and then try prevonfigured PIN provisioning once again.\r
+ *\r
+ * @param[in] ctx Application context would be returned in result callback.\r
+ * @param[in] targetDeviceInfo Selected target device.\r
+ * @param[in] preconfPin string of preconfigured PIN.\r
+ * @param[in] preconfPinLen string length of 'preconfPin'.\r
+ * @param[in] resultCallback callback provided by API user, callback will be called when\r
+ *            provisioning request recieves a response from first resource server.\r
+ * @return OC_STACK_OK in case of success and other value otherwise.\r
+ */\r
+OCStackResult OCProvisionPreconfPin(void* ctx,\r
+                                               OCProvisionDev_t *targetDeviceInfo,\r
+                                               const char * preconfPin, size_t preconfPinLen,\r
+                                               OCProvisionResultCB resultCallback);\r
+\r
+/**\r
+ * API to add preconfigured PIN to local SVR DB.\r
+ *\r
+ * @param[in] targetDeviceInfo Selected target device.\r
+ * @param[in] preconfPIN Preconfig PIN which is used while multiple owner authentication\r
+ * @param[in] preconfPINLen Byte length of preconfig PIN\r
+ * @return OC_STACK_OK in case of success and other value otherwise.\r
+ */\r
+OCStackResult OCAddPreconfigPIN(const OCProvisionDev_t *targetDeviceInfo,\r
+                                 const char* preconfPIN, size_t preconfPINLen);\r
+\r
+/**\r
+ * API to update 'doxm.mom' to resource server.\r
+ *\r
+ * @param[in] targetDeviceInfo Selected target device.\r
+ * @param[in] momType Mode of multiple ownership transfer (ref. oic.sec.mom)\r
+ * @param[in] resultCallback callback provided by API user, callback will be called when\r
+ *            POST 'mom' request recieves a response from resource server.\r
+ * @return OC_STACK_OK in case of success and other value otherwise.\r
+ */\r
+OCStackResult OCChangeMOTMode(void *ctx, const OCProvisionDev_t *targetDeviceInfo,\r
+                            const OicSecMomType_t momType, OCProvisionResultCB resultCallback);\r
+\r
+/**\r
+ * API to update 'doxm.oxmsel' to resource server.\r
+ *\r
+ * @param[in] targetDeviceInfo Selected target device.\r
+ * @param[in] oxmSelValue Method of multiple ownership transfer (ref. oic.sec.oxm)\r
+ * @param[in] resultCallback callback provided by API user, callback will be called when\r
+ *            POST 'oxmsel' request recieves a response from resource server.\r
+ * @return OC_STACK_OK in case of success and other value otherwise.\r
+ */\r
+OCStackResult OCSelectMOTMethod(void *ctx, const OCProvisionDev_t *targetDeviceInfo,\r
+                                 const OicSecOxm_t oxmSelValue, OCProvisionResultCB resultCallback);\r
+#endif //_ENABLE_MULTIPLE_OWNER_\r
+\r
 /**\r
  * Function to unlink devices.\r
  * This function will remove the credential & relasionship between the two devices.\r
diff --git a/resource/csdk/security/provisioning/include/oxm/oxmpreconfpin.h b/resource/csdk/security/provisioning/include/oxm/oxmpreconfpin.h
new file mode 100644 (file)
index 0000000..f00bb04
--- /dev/null
@@ -0,0 +1,82 @@
+//******************************************************************
+//
+// Copyright 2016 Samsung Electronics All Rights Reserved.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
+
+#ifndef OXM_PRECONF_PIN_H_
+#define OXM_PRECONF_PIN_H_
+
+#include "ocstack.h"
+#include "securevirtualresourcetypes.h"
+#include "ownershiptransfermanager.h"
+#include "pmtypes.h"
+#include "pinoxmcommon.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+/**
+ * Callback implementation to load preconfig PIN.
+ *
+ * @param otmCtx Context of OTM, It includes current device information.
+ *
+ * @return ::OC_STACK_SUCCESS in case of success and other value otherwise.
+ */
+OCStackResult LoadPreconfPinCodeCallback(OTMContext_t *otmCtx);
+
+/**
+ * Callback implementation to establish a secure channel with PSK cipher suite.
+ *
+ * @param otmCtx Context of OTM, It includes current device information.
+ *
+ * @return ::OC_STACK_SUCCESS in case of success and other value otherwise.
+ */
+OCStackResult CreateSecureSessionPreconfPinCallback(OTMContext_t *otmCtx);
+
+/**
+ * Generate payload for select OxM request.
+ *
+ * @param otmCtx Context of OTM, It includes current device information.
+ * @param cborPaylaod is the DOXM CBOR payload including the selected OxM.
+ * @note Returned memory should be deallocated by caller.
+ * @param cborSize is the size of the cborPayload.
+ *
+ * @return ::OC_STACK_SUCCESS in case of success and other value otherwise.
+ */
+OCStackResult CreatePreconfPinBasedSelectOxmPayload(OTMContext_t *otmCtx, uint8_t **cborPayload,
+                                             size_t *cborSize);
+
+/**
+ * Generate payload for owner transfer request.
+ *
+ * @param otmCtx Context of OTM, It includes current device information.
+ * @param cborPaylaod is the DOXM CBOR payload including the owner information.
+ * @note Returned memory should be deallocated by caller.
+ * @param cborSize is the size of the cborPayload.
+ *
+ * @return ::OC_STACK_SUCCESS in case of success and other value otherwise.
+ */
+OCStackResult CreatePreconfPinBasedOwnerTransferPayload(OTMContext_t *otmCtx, uint8_t **cborPayload,
+                                                 size_t *cborSize);
+
+#ifdef __cplusplus
+}
+#endif
+#endif //OXM_PRECONF_PIN_H_
+
old mode 100755 (executable)
new mode 100644 (file)
index a791a50..897ee94
@@ -67,6 +67,19 @@ OCStackResult PMSingleDeviceDiscovery(unsigned short waittime, const OicUuid_t*
  */
 OCStackResult PMDeviceDiscovery(unsigned short waittime, bool isOwned, OCProvisionDev_t **ppList);
 
+#ifdef _ENABLE_MULTIPLE_OWNER_
+/**
+ * Discover multiple OTM enabled devices in the same IP subnet.
+ *
+ * @param[in] waittime      Timeout in seconds.
+ * @param[in] isMultipleOwned       bool flag for MOT enabled / multiple owned discovery
+ * @param[in] ppDevicesList        List of OCProvisionDev_t.
+ *
+ * @return OC_STACK_OK on success otherwise error.
+ */
+OCStackResult PMMultipleOwnerDeviceDiscovery(unsigned short waittime, bool isMultipleOwned, OCProvisionDev_t **ppDevicesList);
+#endif //_ENABLE_MULTIPLE_OWNER_
+
 /**
  * This function deletes list of provision target devices
  *
index 45d7060..a301f90 100644 (file)
@@ -86,6 +86,9 @@ if env.get('SECURED') == '1':
     provisioning_env.AppendUnique(LIBS = ['mbedtls','mbedx509','mbedcrypto'])
 
 
+if env.get('MULTIPLE_OWNER') == '1':
+       provisioning_env.AppendUnique(CPPDEFINES = ['_ENABLE_MULTIPLE_OWNER_'])
+
 provisioning_env.AppendUnique(CPPDEFINES = ['TB_LOG'])
 
 if target_os == 'tizen':
@@ -99,6 +102,11 @@ if target_os == 'tizen':
 provisioningclient = provisioning_env.Program('provisioningclient', 'provisioningclient.c')
 sampleserver_justworks = provisioning_env.Program('sampleserver_justworks', 'sampleserver_justworks.cpp')
 sampleserver_randompin = provisioning_env.Program('sampleserver_randompin', 'sampleserver_randompin.cpp')
+
+if provisioning_env.get('MULTIPLE_OWNER') == '1':
+       subownerclient = provisioning_env.Program('subownerclient', 'subownerclient.c')
+       sampleclient_ownedbysubowner = provisioning_env.Program('sampleclient_ownedbysubowner', 'sampleclient_owned_by_subowner.cpp')
+
 if provisioning_env.get('WITH_TCP') == True:
     cloud_src = [
         'cloud/cloudAuth.c',
@@ -121,6 +129,13 @@ randompindat = provisioning_env.Install(sec_provisioning_build_dir,
                                     sec_provisioning_src_dir+ 'oic_svr_db_server_randompin.dat')
 randompin_with_emptyuuid_dat = provisioning_env.Install(sec_provisioning_build_dir,
                                     sec_provisioning_src_dir+ 'oic_svr_db_randompin_with_empty_deviceid.dat')
+
+if provisioning_env.get('MULTIPLE_OWNER') == '1':
+       subownerclientdat = provisioning_env.Install(sec_provisioning_build_dir,
+                                               sec_provisioning_src_dir + 'oic_svr_db_subowner_client.dat')
+       clientownedbysubownerdat = provisioning_env.Install(sec_provisioning_build_dir,
+                                               sec_provisioning_src_dir + 'oic_svr_db_client_owned_by_subowner.dat')
+
 if provisioning_env.get('WITH_TCP') == True:
     clouddat = provisioning_env.Install(sec_provisioning_build_dir,
                                         sec_provisioning_src_dir + 'cloud.dat')
@@ -129,6 +144,20 @@ if provisioning_env.get('WITH_TCP') == True:
     Alias("cloud", [clouddat, rootcert, cloudClient, cloudServer])
     provisioning_env.AppendTarget("cloud")
 
-Alias("samples", [provisioningclient, sampleserver_justworks, sampleserver_randompin, clientdat, justworksdat, randompindat, randompin_with_emptyuuid_dat])
+if provisioning_env.get('MULTIPLE_OWNER') == '1':
+       Alias("samples", [
+                                       provisioningclient, subownerclient, sampleclient_ownedbysubowner,
+                                       sampleserver_justworks, sampleserver_randompin,
+                                       clientdat, subownerclientdat, clientownedbysubownerdat,
+                                       justworksdat, randompindat, randompin_with_emptyuuid_dat
+                               ])
+else:
+       Alias("samples", [
+                                       provisioningclient,
+                                       sampleserver_justworks, sampleserver_randompin,
+                                       clientdat,
+                                       justworksdat, randompindat, randompin_with_emptyuuid_dat
+                               ])
+
 provisioning_env.AppendTarget('samples')
 
index 360ba42..ce7f7e1 100644 (file)
@@ -340,6 +340,7 @@ static OCStackResult saveTrustCert(void)
     if (!readFile(filename, (OCByteString *)&trustCertChainArray))
     {
         OIC_LOG_V(ERROR, TAG, "Can't read %s file", filename);
+        OICFree(((OCByteString *)&trustCertChainArray)->bytes);
         return OC_STACK_ERROR;
     }
     OIC_LOG_BUFFER(DEBUG, TAG, trustCertChainArray.data, trustCertChainArray.len);
diff --git a/resource/csdk/security/provisioning/sample/oic_svr_db_client_owned_by_subowner.dat b/resource/csdk/security/provisioning/sample/oic_svr_db_client_owned_by_subowner.dat
new file mode 100644 (file)
index 0000000..bc044c8
Binary files /dev/null and b/resource/csdk/security/provisioning/sample/oic_svr_db_client_owned_by_subowner.dat differ
diff --git a/resource/csdk/security/provisioning/sample/oic_svr_db_client_owned_by_subowner.json b/resource/csdk/security/provisioning/sample/oic_svr_db_client_owned_by_subowner.json
new file mode 100644 (file)
index 0000000..37b2a36
--- /dev/null
@@ -0,0 +1,110 @@
+{\r
+    "acl": {\r
+        "aclist": {\r
+            "aces": [\r
+                {\r
+                    "subjectuuid": "*",\r
+                    "resources": [\r
+                        {\r
+                            "href": "/oic/res",\r
+                            "rel": "",\r
+                            "rt": ["oic.wk.res"],\r
+                            "if": ["oic.if.ll"]\r
+                        },{\r
+                            "href": "/oic/d",\r
+                            "rel": "",\r
+                            "rt": ["oic.wk.d"],\r
+                            "if": ["oic.if.baseline", "oic.if.r"]\r
+                        },{\r
+                            "href": "/oic/p",\r
+                            "rel": "",\r
+                            "rt": ["oic.wk.p"],\r
+                            "if": ["oic.if.baseline", "oic.if.r"]\r
+                        }\r
+                    ],\r
+                    "permission": 2\r
+                },\r
+                {\r
+                    "subjectuuid": "*",\r
+                    "resources": [\r
+                        {\r
+                            "href": "/oic/sec/doxm",\r
+                            "rel": "",\r
+                            "rt": ["oic.r.doxm"],\r
+                            "if": ["oic.if.baseline"]\r
+                        },\r
+                        {\r
+                            "href": "/oic/sec/pstat",\r
+                            "rel": "",\r
+                            "rt": ["oic.r.pstat"],\r
+                            "if": ["oic.if.baseline"]\r
+                        },\r
+                        {\r
+                            "href": "/oic/sec/acl",\r
+                            "rel": "",\r
+                            "rt": ["oic.r.acl"],\r
+                            "if": ["oic.if.baseline"]\r
+                        },\r
+                        {\r
+                            "href": "/oic/sec/cred",\r
+                            "rel": "",\r
+                            "rt": ["oic.r.cred"],\r
+                            "if": ["oic.if.baseline"]\r
+                        }\r
+                    ],\r
+                    "permission": 6\r
+                },\r
+                {\r
+                    "subjectuuid": "*",\r
+                    "resources": [\r
+                        {\r
+                            "href": "/oic/sec/pconf",\r
+                            "rel": "",\r
+                            "rt": ["oic.r.pconf"],\r
+                            "if": ["oic.if.baseline"]\r
+                        },\r
+                        {\r
+                            "href": "/oic/sec/dpairing",\r
+                            "rel": "",\r
+                            "rt": ["oic.r.dpairing"],\r
+                            "if": ["oic.if.baseline"]\r
+                        }\r
+                    ],\r
+                    "permission": 6\r
+                },\r
+                {\r
+                    "subjectuuid": "*",\r
+                    "resources": [\r
+                        {\r
+                            "href": "/oic/sec/ver",\r
+                            "rel": "",\r
+                            "rt": ["oic.r.ver"],\r
+                            "if": ["oic.if.baseline"]\r
+                        }\r
+                    ],\r
+                    "permission": 2\r
+                }\r
+            ]\r
+        },\r
+        "rowneruuid" : "4F776E65-6442-7953-7562-4F776E657230"\r
+    },\r
+    "pstat": {\r
+        "isop": false,\r
+        "deviceuuid": "4F776E65-6442-7953-7562-4F776E657230",\r
+        "rowneruuid": "4F776E65-6442-7953-7562-4F776E657230",\r
+        "cm": 2,\r
+        "tm": 0,\r
+        "om": 3,\r
+        "sm": 3\r
+        },\r
+    "doxm": {\r
+        "oxms": [0],\r
+        "oxmsel": 0,\r
+        "sct": 1,\r
+        "owned": false,\r
+        "deviceuuid": "4F776E65-6442-7953-7562-4F776E657230",\r
+        "devowneruuid": "",\r
+        "rowneruuid": "4F776E65-6442-7953-7562-4F776E657230",\r
+        "x.org.iotivity.dpc": true\r
+    }\r
+}\r
diff --git a/resource/csdk/security/provisioning/sample/oic_svr_db_subowner_client.dat b/resource/csdk/security/provisioning/sample/oic_svr_db_subowner_client.dat
new file mode 100644 (file)
index 0000000..36568cd
Binary files /dev/null and b/resource/csdk/security/provisioning/sample/oic_svr_db_subowner_client.dat differ
diff --git a/resource/csdk/security/provisioning/sample/oic_svr_db_subowner_client.json b/resource/csdk/security/provisioning/sample/oic_svr_db_subowner_client.json
new file mode 100644 (file)
index 0000000..977cf87
--- /dev/null
@@ -0,0 +1,86 @@
+{\r
+    "acl": {\r
+        "aclist": {\r
+            "aces": [\r
+                {\r
+                    "subjectuuid": "*",\r
+                    "resources": [\r
+                        {\r
+                            "href": "/oic/res",\r
+                            "rel": "",\r
+                            "rt": ["oic.wk.res"],\r
+                            "if": ["oic.if.ll"]\r
+                        },{\r
+                            "href": "/oic/d",\r
+                            "rel": "",\r
+                            "rt": ["oic.wk.d"],\r
+                            "if": ["oic.if.baseline", "oic.if.r"]\r
+                        },{\r
+                            "href": "/oic/p",\r
+                            "rel": "",\r
+                            "rt": ["oic.wk.p"],\r
+                            "if": ["oic.if.baseline", "oic.if.r"]\r
+                        }\r
+                    ],\r
+                    "permission": 2\r
+                },\r
+                {\r
+                    "subjectuuid": "*",\r
+                    "resources": [\r
+                        {\r
+                            "href": "/oic/sec/doxm",\r
+                            "rel": "",\r
+                            "rt": ["oic.r.doxm"],\r
+                            "if": ["oic.if.baseline"]\r
+                        },\r
+                        {\r
+                            "href": "/oic/sec/pstat",\r
+                            "rel": "",\r
+                            "rt": ["oic.r.pstat"],\r
+                            "if": ["oic.if.baseline"]\r
+                        }\r
+                    ],\r
+                    "permission": 2\r
+                },\r
+                {\r
+                    "subjectuuid": "*",\r
+                    "resources": [\r
+                        {\r
+                            "href": "/oic/sec/pconf",\r
+                            "rel": "",\r
+                            "rt": ["oic.r.pconf"],\r
+                            "if": ["oic.if.baseline"]\r
+                        },\r
+                        {\r
+                            "href": "/oic/sec/dpairing",\r
+                            "rel": "",\r
+                            "rt": ["oic.r.dpairing"],\r
+                            "if": ["oic.if.baseline"]\r
+                        }\r
+                    ],\r
+                    "permission": 2\r
+                }\r
+            ]\r
+        },\r
+        "rowneruuid" : "5375624F-776E-6572-436C-69656E743030"\r
+    },\r
+    "pstat": {\r
+        "isop": true,\r
+        "cm": 0,\r
+        "tm": 0,\r
+        "om": 3,\r
+        "sm": 3,\r
+        "deviceuuid": "5375624F-776E-6572-436C-69656E743030",\r
+        "rowneruuid": "5375624F-776E-6572-436C-69656E743030"\r
+    },\r
+    "doxm": {\r
+        "oxms": [0],\r
+        "oxmsel": 0,\r
+        "sct": 1,\r
+        "owned": true,\r
+        "deviceuuid": "5375624F-776E-6572-436C-69656E743030",\r
+        "x.org.iotivity.dpc": false,\r
+        "devowneruuid": "5375624F-776E-6572-436C-69656E743030",\r
+        "rowneruuid": "5375624F-776E-6572-436C-69656E743030"\r
+    }\r
+}\r
index 4b6d958..145d95d 100644 (file)
@@ -47,6 +47,9 @@ extern "C"
 #define _10_DISCOV_ALL_DEVS_        10
 #define _11_DISCOV_UNOWN_DEVS_      11
 #define _12_DISCOV_OWN_DEVS_        12
+#ifdef _ENABLE_MULTIPLE_OWNER_
+#define _13_MOT_DISCOV_DEV_         13
+#endif //_ENABLE_MULTIPLE_OWNER_
 #define _20_REGIST_DEVS_            20
 #define _30_PROVIS_PAIR_DEVS_       30
 #define _31_PROVIS_CRED_            31
@@ -59,7 +62,12 @@ extern "C"
 #define _52_RESET_SELEC_DEV_        52
 #define _60_GET_CRED_               60
 #define _61_GET_ACL_                61
-#define _70_SELECT_PROTOCOL_        70
+#ifdef _ENABLE_MULTIPLE_OWNER_
+#define _70_MOT_CHANGE_MOM_         70
+#define _71_MOT_PROV_PRECONF_PIN_   71
+#define _72_MOT_OXM_SEL_            72
+#endif //_ENABLE_MULTIPLE_OWNER_
+#define _80_SELECT_PROTOCOL_        80
 #define _99_EXIT_PRVN_CLT_          99
 
 #define ACL_RESRC_MAX_NUM   16
@@ -89,6 +97,11 @@ static OCProvisionDev_t* g_own_list;
 static OCProvisionDev_t* g_unown_list;
 static int g_own_cnt;
 static int g_unown_cnt;
+#ifdef _ENABLE_MULTIPLE_OWNER_
+static OCProvisionDev_t* g_mot_enable_list;
+static int g_mot_enable_cnt;
+#endif //_ENABLE_MULTIPLE_OWNER_
+
 static bool g_doneCB;
 #ifdef __WITH_TLS__
 static int secure_protocol = 1;
@@ -247,6 +260,22 @@ static void syncDeviceCB(void* ctx, int nOfRes, OCProvisionResult_t* arr, bool h
     g_doneCB = true;
 }
 
+#ifdef _ENABLE_MULTIPLE_OWNER_
+static void updateDoxmForMOTCB(void* ctx, int nOfRes, OCProvisionResult_t* arr, bool hasError)
+{
+    if(!hasError)
+    {
+        OIC_LOG_V(INFO, TAG, "POST 'doxm' SUCCEEDED - ctx: %s", (char*) ctx);
+    }
+    else
+    {
+        OIC_LOG_V(ERROR, TAG, "POST 'doxm'  FAILED - ctx: %s", (char*) ctx);
+        printResultList((const OCProvisionResult_t*) arr, nOfRes);
+    }
+    g_doneCB = true;
+}
+#endif //_ENABLE_MULTIPLE_OWNER_
+
 static void inputPinCB(char* pin, size_t len)
 {
     if(!pin || OXM_RANDOM_PIN_SIZE>=len)
@@ -308,28 +337,6 @@ static int initProvisionClient(void)
         return -1;
     }
 
-    // register callback function(s) to each OxM
-    OTMCallbackData_t otmcb =
-    {
-        .loadSecretCB = LoadSecretJustWorksCallback,
-        .createSecureSessionCB = CreateSecureSessionJustWorksCallback,
-        .createSelectOxmPayloadCB = CreateJustWorksSelectOxmPayload,
-        .createOwnerTransferPayloadCB = CreateJustWorksOwnerTransferPayload
-    };
-    if(OC_STACK_OK != OCSetOwnerTransferCallbackData(OIC_JUST_WORKS, &otmcb))
-    {
-        OIC_LOG(ERROR, TAG, "OCSetOwnerTransferCallbackData error: OIC_JUST_WORKS");
-        return -1;
-    }
-    otmcb.loadSecretCB = InputPinCodeCallback;
-    otmcb.createSecureSessionCB = CreateSecureSessionRandomPinCallback;
-    otmcb.createSelectOxmPayloadCB = CreatePinBasedSelectOxmPayload;
-    otmcb.createOwnerTransferPayloadCB = CreatePinBasedOwnerTransferPayload;
-    if(OC_STACK_OK != OCSetOwnerTransferCallbackData(OIC_RANDOM_DEVICE_PIN, &otmcb))
-    {
-        OIC_LOG(ERROR, TAG, "OCSetOwnerTransferCallbackData error: OIC_RANDOM_DEVICE_PIN");
-        return -1;
-    }
     SetInputPinCB(inputPinCB);
 
     return 0;
@@ -422,6 +429,32 @@ static int discoverOwnedDevices(void)
     return 0;
 }
 
+#ifdef _ENABLE_MULTIPLE_OWNER_
+static int discoverMOTEnabledDevices(void)
+{
+    // delete owned device list before updating it
+    if(g_mot_enable_list)
+    {
+        OCDeleteDiscoveredDevices(g_mot_enable_list);
+        g_mot_enable_list = NULL;
+    }
+
+    // call |OCDiscoverOwnedDevices| API actually
+    printf("   Discovering Multiple Ownership Transfer Enabled Devices on Network..\n");
+    if(OC_STACK_OK != OCDiscoverMultipleOwnerEnabledDevices(DISCOVERY_TIMEOUT, &g_mot_enable_list))
+    {
+        OIC_LOG(ERROR, TAG, "OCDiscoverMultipleOwnerEnalbedDevices API error");
+        return -1;
+    }
+
+    // display the discovered owned list
+    printf("   > Discovered Multiple Ownership Transfer Enabled Devices\n");
+    g_mot_enable_cnt = printDevList(g_mot_enable_list);
+
+    return 0;
+}
+#endif //_ENABLE_MULTIPLE_OWNER_
+
 static int registerDevices(void)
 {
     // check |unown_list| for registering devices
@@ -1098,6 +1131,202 @@ static int removeDeviceWithUuid(void)
     return 0;
 }
 
+#ifdef _ENABLE_MULTIPLE_OWNER_
+static int changeMultipleOwnershipTrnasferMode(void)
+{
+    // check |own_list| for removing device
+    if(!g_own_list || 1>g_own_cnt)
+    {
+        printf("   > Owned Device List is Empty\n");
+        printf("   > Please Discover the Owned Devices, with [12] Menu\n");
+        return 0;  // normal case
+    }
+
+    // select device for removing it
+    int dev_num = 0;
+    for( ; ; )
+    {
+        printf("   > Enter Device Number, for MOT Device: ");
+        for(int ret=0; 1!=ret; )
+        {
+            ret = scanf("%d", &dev_num);
+            for( ; 0x20<=getchar(); );  // for removing overflow garbages
+                                        // '0x20<=code' is character region
+        }
+        if(0<dev_num && g_own_cnt>=dev_num)
+        {
+            break;
+        }
+        printf("     Entered Wrong Number. Please Enter Again\n");
+    }
+
+    int mom = 0;
+    for( ; ; )
+    {
+        printf("   0. Disable Multuple Ownership Transfer\n");
+        printf("   1. Enable Multuple Ownership Transfer\n");
+        printf("   2. (Not Supported yet) Timely Enable Multuple Ownership Transfer\n");
+        printf("   > Enter Mode of Multuple Ownership Transfer : ");
+        for(int ret=0; 1!=ret; )
+        {
+            ret = scanf("%d", &mom);
+            for( ; 0x20<=getchar(); );  // for removing overflow garbages
+                                        // '0x20<=code' is character region
+        }
+        if(0 <= dev_num && OIC_NUMBER_OF_MOM_TYPE > dev_num)
+        {
+            break;
+        }
+        printf("     Entered Wrong Number. Please Enter Again\n");
+    }
+
+    OCProvisionDev_t* motDev = getDevInst(g_own_list, dev_num);
+    if(OC_STACK_OK == MOTChangeMode(NULL, motDev, (OicSecMomType_t)dev_num, updateDoxmForMOTCB))
+    {
+        g_doneCB = false;
+    }
+    else
+    {
+        OIC_LOG(ERROR, TAG, "MOTChangeMode API error");
+        return -1;
+    }
+
+    if(waitCallbackRet())  // input |g_doneCB| flag implicitly
+    {
+        OIC_LOG(ERROR, TAG, "waitCallbackRet callback error");
+        return -1;
+    }
+
+    return 0;
+}
+
+static int selectMultipleOwnershipTrnasferMethod(void)
+{
+    // check |own_list| for removing device
+    if(!g_mot_enable_list || 1>g_mot_enable_cnt)
+    {
+        printf("   > Multiple Ownership Transfer Enabled Device List is Empty\n");
+        printf("   > Please Discover the Multiple Ownership Transfer Enabled Devices, with [13] Menu\n");
+        return 0;  // normal case
+    }
+
+    // select device for removing it
+    int dev_num = 0;
+    for( ; ; )
+    {
+        printf("   > Enter Device Number, for MOT Device: ");
+        for(int ret=0; 1!=ret; )
+        {
+            ret = scanf("%d", &dev_num);
+            for( ; 0x20<=getchar(); );  // for removing overflow garbages
+                                        // '0x20<=code' is character region
+        }
+        if(0<dev_num && g_mot_enable_cnt>=dev_num)
+        {
+            break;
+        }
+        printf("     Entered Wrong Number. Please Enter Again\n");
+    }
+
+    int oxm = 0;
+    for( ; ; )
+    {
+        printf("   0. (Not Supported)\n");
+        printf("   1. Random PIN OxM\n");
+        printf("   2. (Not Supported)\n");
+        printf("   3. Pre-Configured PIN OxM\n");
+        printf("   > Enter Number of  OxM for Multiple Ownership Transfer : ");
+        for(int ret=0; 1!=ret; )
+        {
+            ret = scanf("%d", &oxm);
+            for( ; 0x20<=getchar(); );  // for removing overflow garbages
+                                        // '0x20<=code' is character region
+        }
+        if(OIC_PRECONFIG_PIN == oxm || OIC_RANDOM_DEVICE_PIN == oxm)
+        {
+            break;
+        }
+        printf("     Entered Wrong Number. Please Enter Again\n");
+    }
+
+    OCProvisionDev_t* motDev = getDevInst(g_mot_enable_list, dev_num);
+    if(OC_STACK_OK ==  MOTSelectMOTMethod(NULL, motDev, (OicSecOxm_t)oxm, updateDoxmForMOTCB))
+    {
+        g_doneCB = false;
+    }
+    else
+    {
+        OIC_LOG(ERROR, TAG, "MOTSelectMOTMethod API error");
+        return -1;
+    }
+
+    if(waitCallbackRet())  // input |g_doneCB| flag implicitly
+    {
+        OIC_LOG(ERROR, TAG, "waitCallbackRet callback error");
+        return -1;
+    }
+
+    return 0;
+}
+
+static int provisionPreconfigPIN()
+{
+    // check |own_list| for removing device
+    if(!g_mot_enable_list || 1>g_mot_enable_cnt)
+    {
+        printf("   > Multiple Ownership Transfer Enabled Device List is Empty\n");
+        printf("   > Please Discover the Multiple Ownership Transfer Enabled Devices, with [13] Menu\n");
+        return 0;  // normal case
+    }
+
+    // select device for removing it
+    int dev_num = 0;
+    for( ; ; )
+    {
+        printf("   > Enter Device Number, for MOT Device: ");
+        for(int ret=0; 1!=ret; )
+        {
+            ret = scanf("%d", &dev_num);
+            for( ; 0x20<=getchar(); );  // for removing overflow garbages
+                                        // '0x20<=code' is character region
+        }
+        if(0<dev_num && g_mot_enable_cnt>=dev_num)
+        {
+            break;
+        }
+        printf("     Entered Wrong Number. Please Enter Again\n");
+    }
+
+    char preconfPIN[9] = {0};
+    printf("   > Input the PreconfigPIN (e.g. 12341234) : ");
+    for(int ret=0; 1!=ret; )
+    {
+        ret = scanf("%8s", preconfPIN);
+        for( ; 0x20<=getchar(); );  // for removing overflow garbages
+                                    // '0x20<=code' is character region
+    }
+
+    OCProvisionDev_t* motDev = getDevInst(g_mot_enable_list, dev_num);
+    if(OC_STACK_OK == OCProvisionPreconfPin(NULL, motDev, preconfPIN, strlen(preconfPIN), provisionCredCB))
+    {
+        g_doneCB = false;
+    }
+    else
+    {
+        OIC_LOG(ERROR, TAG, "OCProvisionPreconfPin API error");
+        return -1;
+    }
+
+    if(waitCallbackRet())  // input |g_doneCB| flag implicitly
+    {
+        OIC_LOG(ERROR, TAG, "waitCallbackRet callback error");
+        return -1;
+    }
+
+    return 0;
+}
+#endif //_ENABLE_MULTIPLE_OWNER_
+
 static int resetDevice(void)
 {
     // check |own_list| for removing device
@@ -1642,7 +1871,12 @@ static void printMenu(void)
     printf("** [A] DISCOVER DEVICES ON NETWORK\n");
     printf("** 10. Discover All Un/Owned Devices on Network\n");
     printf("** 11. Discover Only Unowned Devices on Network\n");
+#ifdef _ENABLE_MULTIPLE_OWNER_
+    printf("** 12. Discover Only Owned Devices on Network\n");
+    printf("** 13. Discover Multiple Ownership Transfer Enabled Devices on Network\n\n");
+#else
     printf("** 12. Discover Only Owned Devices on Network\n\n");
+#endif //_ENABLE_MULTIPLE_OWNER_
 
     printf("** [B] REGISTER/OWN ALL DISCOVERED UNOWNED DEVICES\n");
     printf("** 20. Register/Own All Discovered Unowned Devices\n\n");
@@ -1665,11 +1899,23 @@ static void printMenu(void)
     printf("** [F] GET SECURITY RESOURCE FOR DEBUGGING ONLY\n");
     printf("** 60. Get the Credential resources of the Selected Device\n");
     printf("** 61. Get the ACL resources of the Selected Device\n\n");
+
+#ifdef _ENABLE_MULTIPLE_OWNER_
+    printf("** [G] UPDATE THE MULTIPLE OWNERSHIP TRANSFER RELATED VALUE\n");
+    printf("** 70. Change the Multiple Ownership transfer MODE(update mom)\n");
+    printf("** 71. Provision Preconfigured PIN\n");
+    printf("** 72. Change the Multiple Ownership transfer METHOD(update oxmsel)\n\n");
+#endif //_ENABLE_MULTIPLE_OWNER_
+
 #ifdef __WITH_TLS__
-    printf("** [F] SELECT SECURE PROTOCOL DTLS/TLS\n");
-    printf("** 70. Select secure protocol(default DTLS)\n\n");
+    printf("** [H] SELECT SECURE PROTOCOL DTLS/TLS\n");
+    printf("** 80. Select secure protocol(default DTLS)\n\n");
+
+    printf("** [I] EXIT PROVISIONING CLIENT\n");
+#else
+    printf("** [H] EXIT PROVISIONING CLIENT\n");
 #endif
-    printf("** [F] EXIT PROVISIONING CLIENT\n");
+
     printf("** 99. Exit Provisionong Client\n\n");
 
     printf("************************************************************\n\n");
@@ -1705,6 +1951,10 @@ int main()
         goto PMCLT_ERROR;
     }
 
+#ifdef _ENABLE_MULTIPLE_OWNER_
+    SetPreconfigPin("12341234", 8);
+#endif //_ENABLE_MULTIPLE_OWNER_
+
     // main loop for provisioning manager
     int mn_num = 0;
     for( ; ; )
@@ -1739,6 +1989,14 @@ int main()
                 OIC_LOG(ERROR, TAG, "_12_DISCOV_OWN_DEVS_: error");
             }
             break;
+#ifdef _ENABLE_MULTIPLE_OWNER_
+        case _13_MOT_DISCOV_DEV_:
+            if(discoverMOTEnabledDevices())
+            {
+                OIC_LOG(ERROR, TAG, "_13_MOT_DISCOV_DEV_: error");
+            }
+            break;
+#endif //_ENABLE_MULTIPLE_OWNER_
         case _20_REGIST_DEVS_:
             if(registerDevices())
             {
@@ -1811,8 +2069,28 @@ int main()
                 OIC_LOG(ERROR, TAG, "_61_GET_ACL_: error");
             }
             break;
+#ifdef _ENABLE_MULTIPLE_OWNER_
+        case _70_MOT_CHANGE_MOM_:
+            if(changeMultipleOwnershipTrnasferMode())
+            {
+                OIC_LOG(ERROR, TAG, "_70_MOT_CHANGE_MOM_: error");
+            }
+            break;
+        case _71_MOT_PROV_PRECONF_PIN_:
+            if(provisionPreconfigPIN())
+            {
+                OIC_LOG(ERROR, TAG, "_71_MOT_PROV_PRECONF_PIN_: error");
+            }
+            break;
+        case _72_MOT_OXM_SEL_:
+            if(selectMultipleOwnershipTrnasferMethod())
+            {
+                OIC_LOG(ERROR, TAG, "_72_MOT_OXM_SEL_: error");
+            }
+            break;
+#endif //_ENABLE_MULTIPLE_OWNER_
 #ifdef __WITH_TLS__
-        case  _70_SELECT_PROTOCOL_:
+        case  _80_SELECT_PROTOCOL_:
             selectSecureProtocol();
             break;
 #endif
@@ -1831,6 +2109,9 @@ PMCLT_ERROR:
     }
     OCDeleteDiscoveredDevices(g_own_list);  // after here |g_own_list| points nothing
     OCDeleteDiscoveredDevices(g_unown_list);  // after here |g_unown_list| points nothing
+#ifdef _ENABLE_MULTIPLE_OWNER_
+    OCDeleteDiscoveredDevices(g_mot_enable_list);  // after here |g_motdev_list| points nothing
+#endif //_ENABLE_MULTIPLE_OWNER_
 
     if(g_svr_fname)
     {
diff --git a/resource/csdk/security/provisioning/sample/sampleclient_owned_by_subowner.cpp b/resource/csdk/security/provisioning/sample/sampleclient_owned_by_subowner.cpp
new file mode 100644 (file)
index 0000000..848a0cd
--- /dev/null
@@ -0,0 +1,540 @@
+/******************************************************************
+ *
+ * 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 "logger.h"
+#include "oic_malloc.h"
+#include "oic_string.h"
+#include "ocprovisioningmanager.h"
+#include "oxmjustworks.h"
+#include "oxmrandompin.h"
+#include "securevirtualresourcetypes.h"
+#include "srmutility.h"
+#include "pmtypes.h"
+
+#include <pthread.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif //__cplusplus
+
+#define TAG "ClientOwnedBySubOwner"
+static bool g_doneCB;
+
+static pthread_t oc_process_thread;
+static bool g_LoopFlag = true;
+
+static void* oc_process_loop(void* ptr)
+{
+    struct timespec timeout;
+    timeout.tv_sec  = 0;
+    timeout.tv_nsec = 100000000L;
+
+    while(g_LoopFlag)
+    {
+        OCProcess();
+        nanosleep(&timeout, NULL);
+    }
+    pthread_join(&oc_process_thread, NULL);
+    return NULL;
+}
+
+static void StartOCProcessThread()
+{
+    pthread_create(&oc_process_thread, NULL, oc_process_loop, NULL);
+}
+
+static void StopOCProcessThread()
+{
+    g_LoopFlag = false;
+}
+
+// declaration(s) for provisioning client using C-level provisioning API
+// user input definition for main loop on provisioning client
+#define _10_DISCOV_OWN_DEVS_    10
+#define _20_GET_LED_RESOURCE_ 20
+#define _21_PUT_LED_RESOURCE_ 21
+#define _99_EXIT_PRVN_CLT_      99
+
+#define DISCOVERY_TIMEOUT   5  // 10 sec
+#define CALLBACK_TIMEOUT    60  // 1 min
+
+static const char* SVR_DB_FILE_NAME = "oic_svr_db_client_owned_by_subowner.dat";
+        // '_' for separaing from the same constant variable in |srmresourcestrings.c|
+static const char* PRVN_DB_FILE_NAME = "oic_prvn_cobs.db";
+// |g_ctx| means provision manager application context and
+// the following, includes |un/own_list|, could be variables, which |g_ctx| has,
+// for accessing all function(s) for these, they are declared on global domain
+static const char* g_ctx = "Provision Manager Client Application Context";
+static char* g_svr_fname;
+static char* g_prvn_fname;
+static OCProvisionDev_t* g_own_list;
+static int g_own_cnt;
+
+// function declaration(s) for calling them before implementing
+static OCProvisionDev_t* getDevInst(const OCProvisionDev_t*, const int);
+static int printDevList(const OCProvisionDev_t*);
+static size_t printUuidList(const OCUuidList_t*);
+static int printResultList(const OCProvisionResult_t*, const int);
+static void printUuid(const OicUuid_t*);
+static FILE* fopen_prvnMng(const char*, const char*);
+static int waitCallbackRet(void);
+static int selectTwoDiffNum(int*, int*, const int, const char*);
+
+// callback function(s) for provisioning client using C-level provisioning API
+static void ownershipTransferCB(void* ctx, int nOfRes, OCProvisionResult_t* arr, bool hasError)
+{
+    if(!hasError)
+    {
+        OIC_LOG_V(INFO, TAG, "Ownership Transfer SUCCEEDED - ctx: %s", (char*) ctx);
+    }
+    else
+    {
+        OIC_LOG_V(ERROR, TAG, "Ownership Transfer FAILED - ctx: %s", (char*) ctx);
+        printResultList((const OCProvisionResult_t*) arr, nOfRes);
+    }
+    g_doneCB = true;
+}
+
+// response handler for LED requests.
+static void LedCB(void *ctx, OCDoHandle UNUSED,
+                                                    OCClientResponse *clientResponse)
+{
+    if(clientResponse)
+    {
+        if(clientResponse->result == OC_STACK_OK)
+        {
+            printf("Get OC_STACK_OK from server\n");
+            if(clientResponse->payload)
+            {
+                printf("Response ===================> %s\n", clientResponse->payload);
+            }
+        }
+        else
+        {
+            printf("Error in response : %d\n", clientResponse->result);
+        }
+    }
+    else
+    {
+        printf("Hit the response callback but can not find response data\n");
+    }
+
+    g_doneCB = true;
+}
+
+
+// function(s) for provisioning client using C-level provisioning API
+static int initProvisionClient(void)
+{
+    // initialize persistent storage for SVR DB
+       static OCPersistentStorage ps = {fopen_prvnMng, fread, fwrite, fclose, unlink};
+    if(OC_STACK_OK != OCRegisterPersistentStorageHandler(&ps))
+    {
+        OIC_LOG(ERROR, TAG, "OCRegisterPersistentStorageHandler error");
+        return -1;
+    }
+
+    // initialize OC stack and provisioning manager
+    if(OC_STACK_OK != OCInit(NULL, 0, OC_CLIENT_SERVER))
+    {
+        OIC_LOG(ERROR, TAG, "OCStack init error");
+        return -1;
+    }
+
+    if (access(PRVN_DB_FILE_NAME, F_OK) != -1)
+    {
+        printf("************************************************************\n");
+        printf("************Provisioning DB file already exists.************\n");
+        printf("************************************************************\n");
+    }
+    else
+    {
+        printf("*************************************************************\n");
+        printf("************No provisioning DB file, creating new************\n");
+        printf("*************************************************************\n");
+    }
+
+    if(OC_STACK_OK != OCInitPM(PRVN_DB_FILE_NAME))
+    {
+        OIC_LOG(ERROR, TAG, "OC_PM init error");
+        return -1;
+    }
+
+    return 0;
+}
+
+static int discoverOwnedDevices(void)
+{
+    // delete owned device list before updating it
+    if(g_own_list)
+    {
+        OCDeleteDiscoveredDevices(g_own_list);
+        g_own_list = NULL;
+    }
+
+    // call |OCDiscoverOwnedDevices| API actually
+    printf("   Discovering Only Owned Devices on Network..\n");
+    if(OC_STACK_OK != OCDiscoverOwnedDevices(DISCOVERY_TIMEOUT, &g_own_list))
+    {
+        OIC_LOG(ERROR, TAG, "OCDiscoverOwnedDevices API error");
+        return -1;
+    }
+
+    // display the discovered owned list
+    printf("   > Discovered Owned Devices\n");
+    g_own_cnt = printDevList(g_own_list);
+
+    return 0;
+}
+
+static OCProvisionDev_t* getDevInst(const OCProvisionDev_t* dev_lst, const int dev_num)
+{
+    if(!dev_lst || 0>=dev_num)
+    {
+        printf("     Device List is Empty..\n");
+        return NULL;
+    }
+
+    OCProvisionDev_t* lst = (OCProvisionDev_t*) dev_lst;
+    for(int i=0; lst; )
+    {
+        if(dev_num == ++i)
+        {
+            return lst;
+        }
+        lst = lst->next;
+    }
+
+    return NULL;  // in here |lst| is always |NULL|
+}
+
+static int printDevList(const OCProvisionDev_t* dev_lst)
+{
+    if(!dev_lst)
+    {
+        printf("     Device List is Empty..\n\n");
+        return 0;
+    }
+
+    OCProvisionDev_t* lst = (OCProvisionDev_t*) dev_lst;
+    int lst_cnt = 0;
+    for( ; lst; )
+    {
+        printf("     [%d] ", ++lst_cnt);
+        printUuid((const OicUuid_t*) &lst->doxm->deviceID);
+        printf("\n");
+        lst = lst->next;
+    }
+    printf("\n");
+
+    return lst_cnt;
+}
+
+static size_t printUuidList(const OCUuidList_t* uid_lst)
+{
+    if(!uid_lst)
+    {
+        printf("     Device List is Empty..\n\n");
+        return 0;
+    }
+
+    OCUuidList_t* lst = (OCUuidList_t*) uid_lst;
+    size_t lst_cnt = 0;
+    for( ; lst; )
+    {
+        printf("     [%zu] ", ++lst_cnt);
+        printUuid((const OicUuid_t*) &lst->dev);
+        printf("\n");
+        lst = lst->next;
+    }
+    printf("\n");
+
+    return lst_cnt;
+}
+
+static int printResultList(const OCProvisionResult_t* rslt_lst, const int rslt_cnt)
+{
+    if(!rslt_lst || 0>=rslt_cnt)
+    {
+        printf("     Device List is Empty..\n\n");
+        return 0;
+    }
+
+    int lst_cnt = 0;
+    for( ; rslt_cnt>lst_cnt; ++lst_cnt)
+    {
+        printf("     [%d] ", lst_cnt+1);
+        printUuid((const OicUuid_t*) &rslt_lst[lst_cnt].deviceId);
+        printf(" - result: %d\n", rslt_lst[lst_cnt].res);
+    }
+    printf("\n");
+
+    return lst_cnt;
+}
+
+static void printUuid(const OicUuid_t* uid)
+{
+    int i;
+    for(i=0; i<UUID_LENGTH; )
+    {
+        printf("%02X", (*uid).id[i++]);
+        if(i==4 || i==6 || i==8 || i==10)  // canonical format for UUID has '8-4-4-4-12'
+        {
+            printf("-");
+        }
+    }
+
+    printf("\t(");
+    for(i = 0; i < UUID_LENGTH; i++)
+    {
+        printf("%c", (*uid).id[i]);
+    }
+    printf(")");
+}
+
+static FILE* fopen_prvnMng(const char* path, const char* mode)
+{
+    (void)path;  // unused |path| parameter
+
+    // input |g_svr_db_fname| internally by force, not using |path| parameter
+    // because |OCPersistentStorage::open| is called |OCPersistentStorage| internally
+    // with its own |SVR_DB_FILE_NAME|
+    return fopen(SVR_DB_FILE_NAME, mode);
+}
+
+static int waitCallbackRet(void)
+{
+    for(int i=0; !g_doneCB && CALLBACK_TIMEOUT>i; ++i)
+    {
+        sleep(1);
+    }
+
+    return 0;
+}
+
+static void printMenu(void)
+{
+    printf("************************************************************\n");
+    printf("****** OIC MOT Client with using C-level API ******\n");
+    printf("************************************************************\n\n");
+
+    printf("** [A] DISCOVER DEVICES ON NETWORK\n");
+    printf("** 10. Discover Owned Devices on Network\n\n");
+
+    printf("** [B] SEND GET/PUT Request\n");
+    printf("** 20. Send GET request\n");
+    printf("** 21. Send PUT request\n\n");
+
+    printf("** [G] EXIT PROVISIONING CLIENT\n");
+    printf("** 99. Exit Provisionong Client\n\n");
+
+    printf("************************************************************\n\n");
+}
+
+#if 0 // Code for enabling path configuration for PDB and SVR DBf
+static void printUsage(void)
+{
+    printf("\n");
+    printf("OIC Provisioning Client with using C-level API\n");
+    printf("Usage: provisioningclient [option]...\n");
+    printf("\n");
+    printf("  -h                           print help for this provisioning client\n");
+    printf("  -p=[prvn_db_file_path/name]  input PRVN DB file path and name\n");
+    printf("                               if not exists, will load default DB file\n");
+    printf("                               (default: |oic_prvn_mng.db| on working dir)\n");
+    printf("                               (ex. -p=oic_prvn_mng.db)\n");
+    printf("  -s=[svr_db_file_path/name]   input SVR DB file path and name\n");
+    printf("                               if not exists, will load default DB file\n");
+    printf("                               (default: |oic_svr_db_client.json| on working dir)\n");
+    printf("                               (ex. -s=oic_svr_db_client.json)\n");
+    printf("\n");
+}
+#endif
+
+// main function for provisioning client using C-level provisioning API
+int main()
+{
+    OCProvisionDev_t* selDev = NULL;
+    int selDevNum = 0;
+    int mn_num = 0;
+
+    // initialize provisioning client
+    if(initProvisionClient())
+    {
+        OIC_LOG(ERROR, TAG, "ProvisionClient init error");
+        goto PMCLT_ERROR;
+    }
+
+    StartOCProcessThread();
+    printf("Client started...\n");
+    // main loop for provisioning manager
+    for( ; ; )
+    {
+        printf("\n");
+        printMenu();
+        printf(">> Enter Menu Number: ");
+        for(int ret=0; 1!=ret; )
+        {
+            ret = scanf("%d", &mn_num);
+            for( ; 0x20<=getchar(); );  // for removing overflow garbages
+                                        // '0x20<=code' is character region
+        }
+        printf("\n");
+        switch(mn_num)
+        {
+        case _10_DISCOV_OWN_DEVS_:
+            if(discoverOwnedDevices())
+            {
+                OIC_LOG(ERROR, TAG, "_12_DISCOV_OWN_DEVS_: error");
+            }
+            break;
+        case _20_GET_LED_RESOURCE_:
+        {
+            char query[256] = {0};
+            OCCallbackData cbData;
+            cbData.cb = &LedCB;
+            cbData.context = NULL;
+            cbData.cd = NULL;
+
+            printDevList(g_own_list);
+
+            for( ; ; )
+            {
+                printf("Select the device : ");
+                for(int ret=0; 1!=ret; )
+                {
+                    scanf(" %d", &selDevNum);
+                    for( ; 0x20<=getchar(); );  // for removing overflow garbages
+                                                // '0x20<=code' is character region
+                }
+                if(0<selDevNum && g_own_cnt>=selDevNum)
+                {
+                    break;
+                }
+                printf("     Entered Wrong Number. Please Enter Again\n");
+            }
+
+            selDev = getDevInst(g_own_list, selDevNum);
+            if(!selDev)
+            {
+                OIC_LOG(ERROR, TAG, "getDevInst: device instance empty");
+                goto PMCLT_ERROR;
+            }
+
+            g_doneCB = false;
+            snprintf(query, MAX_URI_LENGTH, "coaps://%s:%d/a/led", selDev->endpoint.addr, selDev->securePort);
+            if(OC_STACK_OK != OCDoResource(NULL, OC_REST_GET, query, NULL, NULL, selDev->connType, OC_LOW_QOS, &cbData, NULL, 0))
+            {
+                printf("********************************\n");
+                printf("Failed to send GET request to %s\n", query);
+                printf("********************************\n");
+                g_doneCB = true;
+                break;
+            }
+
+            waitCallbackRet();
+
+            break;
+        }
+        case _21_PUT_LED_RESOURCE_:
+        {
+            char query[256] = {0};
+            OCCallbackData cbData;
+            cbData.cb = &LedCB;
+            cbData.context = NULL;
+            cbData.cd = NULL;
+
+            printDevList(g_own_list);
+
+            for( ; ; )
+            {
+                printf("Select the device : ");
+                for(int ret=0; 1!=ret; )
+                {
+                    scanf(" %d", &selDevNum);
+                    for( ; 0x20<=getchar(); );  // for removing overflow garbages
+                                                // '0x20<=code' is character region
+                }
+                if(0<selDevNum && g_own_cnt>=selDevNum)
+                {
+                    break;
+                }
+                printf("     Entered Wrong Number. Please Enter Again\n");
+            }
+
+            selDev = getDevInst(g_own_list, selDevNum);
+            if(!selDev)
+            {
+                OIC_LOG(ERROR, TAG, "getDevInst: device instance empty");
+                goto PMCLT_ERROR;
+            }
+
+            g_doneCB = false;
+            snprintf(query, MAX_URI_LENGTH, "coaps://%s:%d/a/led", selDev->endpoint.addr, selDev->securePort);
+            if(OC_STACK_OK != OCDoResource(NULL, OC_REST_PUT, query, NULL, NULL, selDev->connType, OC_LOW_QOS, &cbData, NULL, 0))
+            {
+                printf("********************************\n");
+                printf("Failed to send PUT request to %s\n", query);
+                printf("********************************\n");
+                g_doneCB = true;
+                break;
+            }
+
+            waitCallbackRet();
+
+            break;
+        }
+        case _99_EXIT_PRVN_CLT_:
+            goto PMCLT_ERROR;
+        default:
+            printf(">> Entered Wrong Number. Please Enter Again\n\n");
+            break;
+        }
+    }
+
+PMCLT_ERROR:
+    if(OC_STACK_OK != OCStop())
+    {
+        OIC_LOG(ERROR, TAG, "OCStack stop error");
+    }
+    OCDeleteDiscoveredDevices(g_own_list);  // after here |g_own_list| points nothing
+
+    if(g_svr_fname)
+    {
+        OICFree(g_svr_fname);  // after here |g_svr_fname| points nothing
+    }
+    if(g_prvn_fname)
+    {
+        OICFree(g_prvn_fname);  // after here |g_prvn_fname| points nothing
+    }
+
+    StopOCProcessThread();
+
+    return 0;  // always return normal case
+}
+
+#ifdef __cplusplus
+}
+#endif //__cplusplus
index 56156ba..f8e651a 100644 (file)
@@ -48,6 +48,9 @@
 #define TAG "SAMPLE_RANDOMPIN"
 
 int gQuitFlag = 0;
+#ifdef _ENABLE_MULTIPLE_OWNER_
+static bool g_LoopFlag = true;
+#endif //_ENABLE_MULTIPLE_OWNER_
 
 /* Structure to represent a LED resource */
 typedef struct LEDRESOURCE{
@@ -142,6 +145,35 @@ const char *getResult(OCStackResult result) {
     }
 }
 
+#ifdef _ENABLE_MULTIPLE_OWNER_
+static pthread_t oc_process_thread;
+
+static void* oc_process_loop(void* ptr)
+{
+    struct timespec timeout;
+    timeout.tv_sec  = 0;
+    timeout.tv_nsec = 100000000L;
+
+    while(g_LoopFlag)
+    {
+        OCProcess();
+        nanosleep(&timeout, NULL);
+    }
+    pthread_join(&oc_process_thread, NULL);
+    return NULL;
+}
+
+static void StartOCProcessThread()
+{
+    pthread_create(&oc_process_thread, NULL, oc_process_loop, NULL);
+}
+
+static void StopOCProcessThread()
+{
+    g_LoopFlag = false;
+}
+#endif //_ENABLE_MULTIPLE_OWNER_
+
 OCRepPayload* getPayload(const char* uri, int64_t power, bool state)
 {
     OCRepPayload* payload = OCRepPayloadCreate();
@@ -425,8 +457,6 @@ void GeneratePinCB(char* pin, size_t pinSize)
 
 int main()
 {
-    struct timespec timeout;
-
     OIC_LOG(DEBUG, TAG, "OCServer is starting...");
 
     // Initialize Persistent Storage for SVR database
@@ -443,19 +473,42 @@ int main()
      * If server supported random pin based ownership transfer,
      * callback of print PIN should be registered before runing server.
      */
-    SetGeneratePinCB(&GeneratePinCB);
+    SetGeneratePinCB(GeneratePinCB);
 
     /*
      * Declare and create the example resource: LED
      */
     createLEDResource(gResourceUri, &LED, false, 0);
 
-    timeout.tv_sec  = 0;
-    timeout.tv_nsec = 100000000L;
-
     // Break from loop with Ctrl-C
     OIC_LOG(INFO, TAG, "Entering ocserver main loop...");
     signal(SIGINT, handleSigInt);
+
+#ifdef _ENABLE_MULTIPLE_OWNER_
+    StartOCProcessThread();
+
+    while(!gQuitFlag)
+    {
+        printf("Press 'G' to generate random PIN...\n");
+        printf("Press 'E' to exit...\n");
+        char in = getchar();
+        if('G' == in || 'g' == in)
+        {
+            char ranPin[OXM_RANDOM_PIN_SIZE + 1] = {0};
+            GeneratePin(ranPin, OXM_RANDOM_PIN_SIZE + 1);
+        }
+        if('E' == in || 'e' == in)
+        {
+            break;
+        }
+    }
+
+    StopOCProcessThread();
+#else
+    struct timespec timeout;
+    timeout.tv_sec  = 0;
+    timeout.tv_nsec = 100000000L;
+
     while (!gQuitFlag)
     {
         if (OCProcess() != OC_STACK_OK)
@@ -465,6 +518,7 @@ int main()
         }
         nanosleep(&timeout, NULL);
     }
+#endif //_ENABLE_MULTIPLE_OWNER_
 
     OIC_LOG(INFO, TAG, "Exiting ocserver main loop...");
 
diff --git a/resource/csdk/security/provisioning/sample/subownerclient.c b/resource/csdk/security/provisioning/sample/subownerclient.c
new file mode 100644 (file)
index 0000000..308a1a4
--- /dev/null
@@ -0,0 +1,1019 @@
+/******************************************************************
+ *
+ * Copyright 2016 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 "iotivity_config.h"
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "platform_features.h"
+#include "utlist.h"
+#include "logger.h"
+#include "oic_malloc.h"
+#include "oic_string.h"
+#include "ocprovisioningmanager.h"
+#include "oxmjustworks.h"
+#include "oxmrandompin.h"
+#include "securevirtualresourcetypes.h"
+#include "srmutility.h"
+#include "pmtypes.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif //__cplusplus
+
+// declaration(s) for provisioning client using C-level provisioning API
+// user input definition for main loop on provisioning client
+#define _10_DISCOV_MOT_ENABLED_DEV_         10
+#define _11_DISCOV_MULTIPLE_OWNED_DEV_         11
+#define _20_PERFORM_MOT_        20
+#define _30_GET_LED_RESOURCE_  30
+#define _31_PUT_LED_RESOURCE_  31
+#define _40_PROVISION_ACL_  40
+#define _41_PROVISION_CRED_  41
+#define _99_EXIT_PRVN_CLT_          99
+
+#define ACL_RESRC_MAX_NUM   16
+#define ACL_RESRC_ARRAY_SIZE   3 //This value is used only for sample (not OCF spec)
+#define ACL_RESRC_MAX_LEN   128
+#define ACL_PEMISN_CNT      5
+#define DISCOVERY_TIMEOUT   5  // 5 sec
+#define CALLBACK_TIMEOUT    60  // 1 min
+#define TAG "subownerclient"
+
+static const char* SVR_DB_FILE_NAME = "oic_svr_db_subowner_client.dat";
+        // '_' for separaing from the same constant variable in |srmresourcestrings.c|
+static const char* PRVN_DB_FILE_NAME = "oic_pdm_subowner.db";
+static const OicSecPrm_t  SUPPORTED_PRMS[1] =
+{
+    PRM_PRE_CONFIGURED,
+};
+
+// |g_ctx| means provision manager application context and
+// the following, includes |un/own_list|, could be variables, which |g_ctx| has,
+// for accessing all function(s) for these, they are declared on global domain
+static const char* g_ctx = "SubOwner Client Application Context";
+static char* g_svr_fname;
+static char* g_prvn_fname;
+static OCProvisionDev_t* g_own_list;
+static OCProvisionDev_t* g_unown_list;
+static OCProvisionDev_t* g_motdev_list;
+static OCProvisionDev_t* g_mowned_list;
+static int g_own_cnt;
+static int g_unown_cnt;
+static int g_motdev_cnt;
+static int g_mowned_cnt;
+static bool g_doneCB;
+
+// function declaration(s) for calling them before implementing
+static OCProvisionDev_t* getDevInst(const OCProvisionDev_t*, const int);
+static int printDevList(const OCProvisionDev_t*);
+static size_t printUuidList(const OCUuidList_t*);
+static int printResultList(const OCProvisionResult_t*, const int);
+static void printUuid(const OicUuid_t*);
+static FILE* fopen_prvnMng(const char*, const char*);
+static int waitCallbackRet(void);
+static int selectTwoDiffNum(int*, int*, const int, const char*);
+
+// callback function(s) for provisioning client using C-level provisioning API
+static void multipleOwnershipTransferCB(void* ctx, int nOfRes, OCProvisionResult_t* arr, bool hasError)
+{
+    if(!hasError)
+    {
+        OIC_LOG_V(INFO, TAG, "Multiple Ownership Transfer SUCCEEDED - ctx: %s", (char*) ctx);
+    }
+    else
+    {
+        OIC_LOG_V(ERROR, TAG, "Multiple Ownership Transfer FAILED - ctx: %s", (char*) ctx);
+        printResultList((const OCProvisionResult_t*) arr, nOfRes);
+    }
+    g_doneCB = true;
+}
+
+// callback function(s) for provisioning client using C-level provisioning API
+static void ownershipTransferCB(void* ctx, int nOfRes, OCProvisionResult_t* arr, bool hasError)
+{
+    if(!hasError)
+    {
+        OIC_LOG_V(INFO, TAG, "Ownership Transfer SUCCEEDED - ctx: %s", (char*) ctx);
+    }
+    else
+    {
+        OIC_LOG_V(ERROR, TAG, "Ownership Transfer FAILED - ctx: %s", (char*) ctx);
+        printResultList((const OCProvisionResult_t*) arr, nOfRes);
+    }
+    g_doneCB = true;
+}
+
+static void updateDoxmForMOTCB(void* ctx, int nOfRes, OCProvisionResult_t* arr, bool hasError)
+{
+    if(!hasError)
+    {
+        OIC_LOG_V(INFO, TAG, "POST 'doxm' SUCCEEDED - ctx: %s", (char*) ctx);
+    }
+    else
+    {
+        OIC_LOG_V(ERROR, TAG, "POST 'doxm'  FAILED - ctx: %s", (char*) ctx);
+        printResultList((const OCProvisionResult_t*) arr, nOfRes);
+    }
+    g_doneCB = true;
+}
+
+static void provisionCredCB(void* ctx, int nOfRes, OCProvisionResult_t* arr, bool hasError)
+{
+    if(!hasError)
+    {
+        OIC_LOG_V(INFO, TAG, "Provision Credential SUCCEEDED - ctx: %s", (char*) ctx);
+    }
+    else
+    {
+        OIC_LOG_V(ERROR, TAG, "Provision Credential FAILED - ctx: %s", (char*) ctx);
+        printResultList((const OCProvisionResult_t*) arr, nOfRes);
+    }
+    g_doneCB = true;
+}
+
+static void provisionAclCB(void* ctx, int nOfRes, OCProvisionResult_t* arr, bool hasError)
+{
+    if(!hasError)
+    {
+        OIC_LOG_V(INFO, TAG, "Provision ACL SUCCEEDED - ctx: %s", (char*) ctx);
+    }
+    else
+    {
+        OIC_LOG_V(ERROR, TAG, "Provision ACL FAILED - ctx: %s", (char*) ctx);
+        printResultList((const OCProvisionResult_t*) arr, nOfRes);
+    }
+    g_doneCB = true;
+}
+
+// response handler for LED requests.
+static void LedCB(void *ctx, OCDoHandle UNUSED,
+                                                    OCClientResponse *clientResponse)
+{
+    if(clientResponse)
+    {
+        if(clientResponse->result == OC_STACK_OK)
+        {
+            printf("Get OC_STACK_OK from server\n");
+            if(clientResponse->payload)
+            {
+                printf("Response ===================> %s\n", clientResponse->payload);
+            }
+        }
+        else
+        {
+            printf("Error in response : %d\n", clientResponse->result);
+        }
+    }
+    else
+    {
+        printf("Hit the response callback but can not find response data\n");
+    }
+
+    g_doneCB = true;
+}
+
+static void inputPinCB(char* pin, size_t len)
+{
+    if(!pin || OXM_RANDOM_PIN_SIZE>=len)
+    {
+        OIC_LOG(ERROR, TAG, "inputPinCB invalid parameters");
+        return;
+    }
+
+    printf("   > INPUT PIN: ");
+    for(int ret=0; 1!=ret; )
+    {
+        ret = scanf("%8s", pin);
+        for( ; 0x20<=getchar(); );  // for removing overflow garbages
+                                    // '0x20<=code' is character region
+    }
+}
+
+// function(s) for provisioning client using C-level provisioning API
+static int initProvisionClient(void)
+{
+    // initialize persistent storage for SVR DB
+    static OCPersistentStorage ps = {fopen_prvnMng, fread, fwrite, fclose, unlink};
+    if(OC_STACK_OK != OCRegisterPersistentStorageHandler(&ps))
+    {
+        OIC_LOG(ERROR, TAG, "OCRegisterPersistentStorageHandler error");
+        return -1;
+    }
+
+    // initialize OC stack and provisioning manager
+    if(OC_STACK_OK != OCInit(NULL, 0, OC_CLIENT_SERVER))
+    {
+        OIC_LOG(ERROR, TAG, "OCStack init error");
+        return -1;
+    }
+
+    if (access(PRVN_DB_FILE_NAME, F_OK) != -1)
+    {
+        printf("************************************************************\n");
+        printf("************Provisioning DB file already exists.************\n");
+        printf("************************************************************\n");
+    }
+    else
+    {
+        printf("*************************************************************\n");
+        printf("************No provisioning DB file, creating new************\n");
+        printf("*************************************************************\n");
+    }
+
+    if(OC_STACK_OK != OCInitPM(PRVN_DB_FILE_NAME))
+    {
+        OIC_LOG(ERROR, TAG, "OC_PM init error");
+        return -1;
+    }
+
+    SetInputPinCB(inputPinCB);
+
+    return 0;
+}
+
+static int discoverMotSupportedDevices(void)
+{
+    // delete un/owned device lists before updating them
+    if(g_motdev_list)
+    {
+        OCDeleteDiscoveredDevices(g_motdev_list);
+        g_motdev_list = NULL;
+    }
+
+    // call |OCDiscoverMultipleOwnerEnabledDevices| API actually
+    printf("   Discovering Multiple Ownership Transfer enabled Devices on Network..\n");
+    if(OC_STACK_OK != OCDiscoverMultipleOwnerEnabledDevices(DISCOVERY_TIMEOUT, &g_motdev_list))
+    {
+        OIC_LOG(ERROR, TAG, "OCDiscoverMultipleOwnerEnalbedDevices API error");
+        return -1;
+    }
+
+    // display the discovered device lists
+    printf("   > Discovered Multiple Ownership Transfer Enabled Devices\n");
+    g_motdev_cnt = printDevList(g_motdev_list);
+
+    return 0;
+}
+
+static int discoverSubOwnerDevices()
+{
+    // delete un/owned device lists before updating them
+    if(g_mowned_list)
+    {
+        OCDeleteDiscoveredDevices(g_mowned_list);
+        g_mowned_list = NULL;
+    }
+
+    // call |OCDiscoverMultipleOwnedDevices| API actually
+    printf("   Discovering Multiple Owned Devices on Network..\n");
+    if(OC_STACK_OK != OCDiscoverMultipleOwnedDevices(DISCOVERY_TIMEOUT, &g_mowned_list))
+    {
+        OIC_LOG(ERROR, TAG, "OCDiscoverMultipleOwnerEnabledDevices API error");
+        return -1;
+    }
+
+    // display the discovered device lists
+    printf("   > Discovered Multiple Owned Devices\n");
+    g_mowned_cnt = printDevList(g_mowned_list);
+
+    return 0;
+}
+
+static int multipleOwnershipTransfer(void)
+{
+    // check |unown_list| for registering devices
+    if(!g_motdev_list || 0 >=g_motdev_cnt)
+    {
+        printf("   > MultipleOwnershipTransfer Enabled Device List is Empty\n");
+        printf("   > Please Discover Devices first, with [10] Menu\n");
+        return 0;  // normal case
+    }
+
+    // call |getDevInst| API actually
+    // calling this API with callback actually acts like blocking
+    // for error checking, the return value saved and printed
+    g_doneCB = false;
+
+#ifdef _ENABLE_MULTIPLE_OWNER_
+    OCProvisionDev_t* dev = NULL;
+    LL_FOREACH(g_motdev_list, dev)
+    {
+        if(OIC_PRECONFIG_PIN == dev->doxm->oxmSel)
+        {
+            //Pre-Configured PIN initialization
+            if(OC_STACK_OK != OCAddPreconfigPIN(dev, "12341234", OXM_PRECONFIG_PIN_SIZE))
+            {
+                printf("\n\n\n*** %60s ***\n", "WARNNING : Failed to save the pre-configured PIN");
+                printf("*** %60s ***\n\n\n", "WARNNING : You can't use the pre-configured PIN OxM for MOT");
+                return -1;
+            }
+        }
+    }
+#endif //_ENABLE_MULTIPLE_OWNER_
+
+    if(OC_STACK_OK != OCDoMultipleOwnershipTransfer(g_ctx, g_motdev_list, multipleOwnershipTransferCB))
+    {
+        OIC_LOG(ERROR, TAG, "_20_PERFORM_MOT_: error");
+        return -1;
+    }
+
+    if(waitCallbackRet())  // input |g_doneCB| flag implicitly
+    {
+        OIC_LOG(ERROR, TAG, "OCProvisionCredentials callback error");
+        return -1;
+    }
+
+    // display the registered result
+    printf("   > Registered Discovered Devices\n");
+
+    return 0;
+}
+
+static int sendGetLed()
+{
+    int selDevNum;
+    char query[256] = {0};
+    OCCallbackData cbData;
+    cbData.cb = &LedCB;
+    cbData.context = NULL;
+    cbData.cd = NULL;
+
+    printDevList(g_mowned_list);
+
+    // select device for provisioning access control list
+    for( ; ; )
+    {
+        printf("   > Enter Device Number, for sending GET LED request: ");
+        for(int ret=0; 1!=ret; )
+        {
+            ret = scanf("%d", &selDevNum);
+            for( ; 0x20<=getchar(); );  // for removing overflow garbages
+                                        // '0x20<=code' is character region
+        }
+        if(0<selDevNum && g_mowned_cnt>=selDevNum)
+        {
+            break;
+        }
+        printf("     Entered Wrong Number. Please Enter Again\n");
+    }
+
+    OCProvisionDev_t* selDev = getDevInst(g_mowned_list, selDevNum);
+    if(NULL == selDev)
+    {
+        printf("Failed to getDevInst()\n");
+        return -1;
+    }
+
+    g_doneCB = false;
+    snprintf(query, MAX_URI_LENGTH, "coaps://%s:%d/a/led", selDev->endpoint.addr, selDev->securePort);
+    printf("query=%s\n", query);
+    if(OC_STACK_OK != OCDoResource(NULL, OC_REST_GET, query, NULL, NULL, selDev->connType, OC_HIGH_QOS, &cbData, NULL, 0))
+    {
+        printf("********************************\n");
+        printf("Failed to send GET request to %s\n", query);
+        printf("********************************\n");
+        g_doneCB = true;
+        return -1;
+    }
+
+    waitCallbackRet();
+
+    return 0;
+}
+
+static int sendPutLed()
+{
+    int selDevNum;
+    char query[256] = {0};
+    OCCallbackData cbData;
+    cbData.cb = &LedCB;
+    cbData.context = NULL;
+    cbData.cd = NULL;
+
+    printDevList(g_mowned_list);
+    // select device for provisioning access control list
+    for( ; ; )
+    {
+        printf("   > Enter Device Number, for sending PUT LED request: ");
+        for(int ret=0; 1!=ret; )
+        {
+            ret = scanf("%d", &selDevNum);
+            for( ; 0x20<=getchar(); );  // for removing overflow garbages
+                                        // '0x20<=code' is character region
+        }
+        if(0<selDevNum && g_mowned_cnt>=selDevNum)
+        {
+            break;
+        }
+        printf("     Entered Wrong Number. Please Enter Again\n");
+    }
+
+    OCProvisionDev_t* selDev = getDevInst(g_mowned_list, selDevNum);
+    if(NULL == selDev)
+    {
+        printf("Failed to getDevInst()\n");
+        return -1;
+    }
+
+    g_doneCB = false;
+    snprintf(query, MAX_URI_LENGTH, "coaps://%s:%d/a/led", selDev->endpoint.addr, selDev->securePort);
+    if(OC_STACK_OK != OCDoResource(NULL, OC_REST_PUT, query, NULL, NULL, selDev->connType, OC_LOW_QOS, &cbData, NULL, 0))
+    {
+        printf("********************************\n");
+        printf("Failed to send PUT request to %s\n", query);
+        printf("********************************\n");
+        g_doneCB = true;
+        return -1;
+    }
+
+    waitCallbackRet();
+
+    return 0;
+}
+
+
+static OicSecAcl_t* createAclForLEDAccess(const OicUuid_t* subject)
+{
+    if(NULL == subject)
+    {
+        OIC_LOG(ERROR, TAG, "createAcl: Invalid paramters");
+        return NULL;
+    }
+    // allocate memory for |acl| struct
+    OicSecAcl_t* acl = (OicSecAcl_t*) OICCalloc(1, sizeof(OicSecAcl_t));
+    if(!acl)
+    {
+        OIC_LOG(ERROR, TAG, "createAcl: OICCalloc error return");
+        return NULL;  // not need to 'goto' |ERROR| before allocating |acl|
+    }
+    OicSecAce_t* ace = (OicSecAce_t*) OICCalloc(1, sizeof(OicSecAce_t));
+    if(!ace)
+    {
+        OIC_LOG(ERROR, TAG, "createAcl: OICCalloc error return");
+        return NULL;  // not need to 'goto' |ERROR| before allocating |acl|
+    }
+    LL_APPEND(acl->aces, ace);
+    memcpy(ace->subjectuuid.id, subject->id, sizeof(subject->id));
+
+    // fill the href
+    char* rsrc_in = "/a/led";  // '1' for null termination
+    OicSecRsrc_t* rsrc = (OicSecRsrc_t*)OICCalloc(1, sizeof(OicSecRsrc_t));
+    if(!rsrc)
+    {
+        OIC_LOG(ERROR, TAG, "createAcl: OICCalloc error return");
+        goto CRACL_ERROR;
+    }
+
+    size_t len = strlen(rsrc_in)+1;  // '1' for null termination
+    rsrc->href = (char*) OICCalloc(len, sizeof(char));
+    if(!rsrc->href)
+    {
+        OIC_LOG(ERROR, TAG, "createAcl: OICCalloc error return");
+        goto CRACL_ERROR;
+    }
+    OICStrcpy(rsrc->href, len, rsrc_in);
+
+    //fill the resource type (rt)
+    rsrc->typeLen = 1;
+    rsrc->types = (char**)OICCalloc(1, sizeof(char*));
+    if(!rsrc->types)
+    {
+        OIC_LOG(ERROR, TAG, "createAcl: OICCalloc error return");
+        goto CRACL_ERROR;
+    }
+    rsrc->types[0] = OICStrdup("oic.r.core");
+    if(!rsrc->types[0])
+    {
+        OIC_LOG(ERROR, TAG, "createAcl: OICStrdup error return");
+        goto CRACL_ERROR;
+    }
+
+    //fill the interface (if)
+    rsrc->interfaceLen = 1;
+    rsrc->interfaces = (char**)OICCalloc(1, sizeof(char*));
+    if(!rsrc->interfaces)
+    {
+        OIC_LOG(ERROR, TAG, "createAcl: OICCalloc error return");
+        goto CRACL_ERROR;
+    }
+    rsrc->interfaces[0] = OICStrdup("oic.if.baseline");
+    if(!rsrc->interfaces[0])
+    {
+        OIC_LOG(ERROR, TAG, "createAcl: OICStrdup error return");
+        goto CRACL_ERROR;
+    }
+
+    LL_APPEND(ace->resources, rsrc);
+
+    // full permission for /a/led
+    ace->permission = PERMISSION_FULL_CONTROL;
+
+    ace->eownerID = (OicUuid_t*)OICCalloc(1, sizeof(OicUuid_t));
+    if(NULL == ace->eownerID)
+    {
+        OIC_LOG(ERROR, TAG, "createAcl: OICCalloc error return");
+        goto CRACL_ERROR;
+    }
+
+    //fill the eowner id as my deviceID.
+    OicUuid_t myUuid = {.id={0}};
+    if(OC_STACK_OK != GetDoxmDeviceID(&myUuid))
+    {
+        OIC_LOG(ERROR, TAG, "createAcl: GetDoxmDeviceID error return");
+        goto CRACL_ERROR;
+    }
+    memcpy(ace->eownerID->id, myUuid.id, sizeof(myUuid.id));
+
+    return acl;
+
+CRACL_ERROR:
+    OCDeleteACLList(acl);  // after here |acl| points nothing
+    return NULL;
+}
+
+static int provisionAclForLed()
+{
+    OicSecAcl_t* acl = NULL;
+
+    // check |own_list| for provisioning access control list
+    if(!g_mowned_list || 1> g_mowned_cnt)
+    {
+        printf("   > MOT Device List is Empty\n");
+        printf("   > Please Perform MOT first, with [12|21] Menu\n");
+        return 0;  // normal case
+    }
+
+    // display the MOT dev list
+    printf("   > MOT Devices\n");
+    g_mowned_cnt = printDevList(g_mowned_list);
+
+    // select device for provisioning access control list
+    int dev_num = 0;
+    for( ; ; )
+    {
+        printf("   > Enter Device Number, for Provisioning LED's ACL: ");
+        for(int ret=0; 1!=ret; )
+        {
+            ret = scanf("%d", &dev_num);
+            for( ; 0x20<=getchar(); );  // for removing overflow garbages
+                                        // '0x20<=code' is character region
+        }
+        if(0<dev_num && g_mowned_list>=dev_num)
+        {
+            break;
+        }
+        printf("     Entered Wrong Number. Please Enter Again\n");
+    }
+
+    g_doneCB = false;
+    printf("   Provisioning Selected ACL..\n");
+    OCProvisionDev_t* dev = getDevInst((const OCProvisionDev_t*) g_mowned_list, dev_num);
+    if(!dev)
+    {
+        OIC_LOG(ERROR, TAG, "provisionAcl: device instance empty");
+        goto PVACL_ERROR;
+    }
+
+    OicUuid_t subjectUuid;
+    OCStackResult rst = GetDoxmDeviceID(&subjectUuid);
+    if(OC_STACK_OK != rst)
+    {
+        OIC_LOG_V(ERROR, TAG, "GetDoxmDeviceID API error: %d", rst);
+        goto PVACL_ERROR;
+    }
+
+    acl = createAclForLEDAccess(&subjectUuid);
+    if(NULL == acl)
+    {
+        OIC_LOG(ERROR, TAG, "provisionAcl: Failed to create ACL for LED");
+        return -1;
+    }
+
+    rst = OCProvisionACL((void*) g_ctx, dev, acl, provisionAclCB);
+    if(OC_STACK_OK != rst)
+    {
+        OIC_LOG_V(ERROR, TAG, "OCProvisionACL API error: %d", rst);
+        goto PVACL_ERROR;
+    }
+    if(waitCallbackRet())  // input |g_doneCB| flag implicitly
+    {
+        OIC_LOG(ERROR, TAG, "OCProvisionCredentials callback error");
+        goto PVACL_ERROR;
+    }
+    // display the ACL-provisioned result
+    printf("   > Provisioned Selected ACL\n");
+
+    OCDeleteACLList(acl);  // after here |acl| points nothing
+    return 0;
+
+PVACL_ERROR:
+    OCDeleteACLList(acl);
+    return -1;
+}
+
+static int provisionCred()
+{
+    // check |unown_list| for registering devices
+    if(!g_mowned_list|| 0 >=g_mowned_cnt)
+    {
+        printf("   > Multiple Owned Device List is Empty\n");
+        printf("   > Please Discover Devices first, with [13] Menu\n");
+        return 0;  // normal case
+    }
+
+    // display the MOT dev list
+    printf("   > Multiple Owned Devices\n");
+    g_mowned_cnt = printDevList(g_mowned_list);
+
+    int dev_num = 0;
+    for( ; ; )
+    {
+        printf("   > Enter Multiple Owned Device Number to link : ");
+        for(int ret=0; 1!=ret; )
+        {
+            ret = scanf("%d", &dev_num);
+            for( ; 0x20<=getchar(); );  // for removing overflow garbages
+                                        // '0x20<=code' is character region
+        }
+        if(0<dev_num && g_mowned_cnt>=dev_num)
+        {
+            break;
+        }
+        printf("     Entered Wrong Number. Please Enter Again\n");
+    }
+
+    OCProvisionDev_t* motDev = getDevInst(g_mowned_list, dev_num);
+    if(NULL == motDev)
+    {
+        OIC_LOG(ERROR, TAG, "Failed to getDevInst()");
+        return -1;
+    }
+
+    // display the MOT dev list
+    printf("   > Owned Devices\n");
+    g_own_cnt = printDevList(g_own_list);
+
+    for( ; ; )
+    {
+        printf("   > Enter Owned Device Number to link : ");
+        for(int ret=0; 1!=ret; )
+        {
+            ret = scanf("%d", &dev_num);
+            for( ; 0x20<=getchar(); );  // for removing overflow garbages
+                                        // '0x20<=code' is character region
+        }
+        if(0<dev_num && g_own_cnt>=dev_num)
+        {
+            break;
+        }
+        printf("     Entered Wrong Number. Please Enter Again\n");
+    }
+
+    OCProvisionDev_t* ownDev = getDevInst(g_own_list, dev_num);
+    if(NULL == ownDev)
+    {
+        OIC_LOG(ERROR, TAG, "Failed to getDevInst()");
+        return -1;
+    }
+
+    // call |OCProvisionCredentials| API actually
+    // calling this API with callback actually acts like blocking
+    // for error checking, the return value saved and printed
+    g_doneCB = false;
+    printf("   Provisioning Selected Pairwise Devices..\n");
+    OCStackResult rst = OCProvisionCredentials((void*) g_ctx,
+                    SYMMETRIC_PAIR_WISE_KEY, OWNER_PSK_LENGTH_128,
+                    ownDev, motDev, provisionCredCB);
+    if(OC_STACK_OK != rst)
+    {
+        OIC_LOG_V(ERROR, TAG, "OCProvisionPairwiseDevices API error: %d", rst);
+        goto PVPWS_ERROR;
+    }
+    if(waitCallbackRet())  // input |g_doneCB| flag implicitly
+    {
+        OIC_LOG(ERROR, TAG, "OCProvisionCredentials callback error");
+        goto PVPWS_ERROR;
+    }
+
+    // display the pairwise-provisioned result
+    printf("   > Provisioned Selected Pairwise Devices\n");
+
+    return 0;
+
+PVPWS_ERROR:
+    return -1;
+}
+
+static OCProvisionDev_t* getDevInst(const OCProvisionDev_t* dev_lst, const int dev_num)
+{
+    if(!dev_lst || 0>=dev_num)
+    {
+        printf("     Device List is Empty..\n");
+        return NULL;
+    }
+
+    OCProvisionDev_t* lst = (OCProvisionDev_t*) dev_lst;
+    for(int i=0; lst; )
+    {
+        if(dev_num == ++i)
+        {
+            return lst;
+        }
+        lst = lst->next;
+    }
+
+    return NULL;  // in here |lst| is always |NULL|
+}
+
+static int printDevList(const OCProvisionDev_t* dev_lst)
+{
+    if(!dev_lst)
+    {
+        printf("     Device List is Empty..\n\n");
+        return 0;
+    }
+
+    OCProvisionDev_t* lst = (OCProvisionDev_t*) dev_lst;
+    int lst_cnt = 0;
+    for( ; lst; )
+    {
+        printf("     [%d] ", ++lst_cnt);
+        printUuid((const OicUuid_t*) &lst->doxm->deviceID);
+        printf("\n");
+        lst = lst->next;
+    }
+    printf("\n");
+
+    return lst_cnt;
+}
+
+static size_t printUuidList(const OCUuidList_t* uid_lst)
+{
+    if(!uid_lst)
+    {
+        printf("     Device List is Empty..\n\n");
+        return 0;
+    }
+
+    OCUuidList_t* lst = (OCUuidList_t*) uid_lst;
+    size_t lst_cnt = 0;
+    for( ; lst; )
+    {
+        printf("     [%zu] ", ++lst_cnt);
+        printUuid((const OicUuid_t*) &lst->dev);
+        printf("\n");
+        lst = lst->next;
+    }
+    printf("\n");
+
+    return lst_cnt;
+}
+
+static int printResultList(const OCProvisionResult_t* rslt_lst, const int rslt_cnt)
+{
+    if(!rslt_lst || 0>=rslt_cnt)
+    {
+        printf("     Device List is Empty..\n\n");
+        return 0;
+    }
+
+    int lst_cnt = 0;
+    for( ; rslt_cnt>lst_cnt; ++lst_cnt)
+    {
+        printf("     [%d] ", lst_cnt+1);
+        printUuid((const OicUuid_t*) &rslt_lst[lst_cnt].deviceId);
+        printf(" - result: %d\n", rslt_lst[lst_cnt].res);
+    }
+    printf("\n");
+
+    return lst_cnt;
+}
+
+static void printUuid(const OicUuid_t* uid)
+{
+    for(int i=0; i<UUID_LENGTH; )
+    {
+        printf("%02X", (*uid).id[i++]);
+        if(i==4 || i==6 || i==8 || i==10)  // canonical format for UUID has '8-4-4-4-12'
+        {
+            printf("-");
+        }
+    }
+}
+
+static FILE* fopen_prvnMng(const char* path, const char* mode)
+{
+    (void)path;  // unused |path| parameter
+
+    // input |g_svr_db_fname| internally by force, not using |path| parameter
+    // because |OCPersistentStorage::open| is called |OCPersistentStorage| internally
+    // with its own |SVR_DB_FILE_NAME|
+    return fopen(SVR_DB_FILE_NAME, mode);
+}
+
+static int waitCallbackRet(void)
+{
+    for(int i=0; !g_doneCB && CALLBACK_TIMEOUT>i; ++i)
+    {
+        sleep(1);
+        if(OC_STACK_OK != OCProcess())
+        {
+            OIC_LOG(ERROR, TAG, "OCStack process error");
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+static int selectTwoDiffNum(int* a, int* b, const int max, const char* str)
+{
+    if(!a || !b || 2>max || !str)
+    {
+        return -1;
+    }
+
+    for( ; ; )
+    {
+        for(int i=0; 2>i; ++i)
+        {
+            int* num = 0==i?a:b;
+            for( ; ; )
+            {
+                printf("   > Enter Device[%d] Number, %s: ", i+1, str);
+                for(int ret=0; 1!=ret; )
+                {
+                    ret = scanf("%d", num);
+                    for( ; 0x20<=getchar(); );  // for removing overflow garbages
+                                                // '0x20<=code' is character region
+                }
+                if(0<*num && max>=*num)
+                {
+                    break;
+                }
+                printf("     Entered Wrong Number. Please Enter Again\n");
+            }
+        }
+        if(*a != *b)
+        {
+            printf("\n");
+            return 0;
+        }
+    }
+
+    return -1;
+}
+
+static void printMenu(void)
+{
+    printf("************************************************************\n");
+    printf("****** OIC Provisioning Client with using C-level API ******\n");
+    printf("************************************************************\n\n");
+
+    printf("** [A] DISCOVER DEVICES ON NETWORK\n");
+    printf("** 10. Discover Multiple Ownership Transfer Enabled Devices on Network\n");
+    printf("** 11. Discover Multiple Owned Devices on Network\n\n");
+
+    printf("** [B] PERFORM MULTIPLE OWNERSHIP TRANSFER\n");
+    printf("** 20. Perform the Multiple Ownership Transfer for ALL discovered dievices\n\n");
+
+    printf("** [C] Get/Put Request for APPLICATION RESOURCE\n");
+    printf("** 30. Get LED resource\n");
+    printf("** 31. Put LED resource\n\n");
+
+    printf("** [D] LINK DEVICES\n");
+    printf("** 40. Provision ACL for LED Resource\n");
+    printf("** 41. Provison Credential\n\n");
+
+    printf("** [F] EXIT PROVISIONING CLIENT\n");
+    printf("** 99. Exit Provisionong Client\n\n");
+
+    printf("************************************************************\n\n");
+}
+
+// main function for provisioning client using C-level provisioning API
+int main()
+{
+    // initialize provisioning client
+    if(initProvisionClient())
+    {
+        OIC_LOG(ERROR, TAG, "ProvisionClient init error");
+        goto PMCLT_ERROR;
+    }
+
+    // main loop for provisioning manager
+    int mnNum = 0;
+    int selDevNum = 0;
+    for( ; ; )
+    {
+        printf("\n");
+        printMenu();
+        printf(">> Enter Menu Number: ");
+        for(int ret=0; 1!=ret; )
+        {
+            ret = scanf("%d", &mnNum);
+            for( ; 0x20<=getchar(); );  // for removing overflow garbages
+                                        // '0x20<=code' is character region
+        }
+        printf("\n");
+        switch(mnNum)
+        {
+        case _10_DISCOV_MOT_ENABLED_DEV_:
+            if(discoverMotSupportedDevices())
+            {
+                OIC_LOG(ERROR, TAG, "_12_MOT_DISCOV_DEV_: error");
+            }
+            break;
+        case _11_DISCOV_MULTIPLE_OWNED_DEV_:
+            if(discoverSubOwnerDevices())
+            {
+                OIC_LOG(ERROR, TAG, "_13_DISCOV_MULTIPLE_OWNED_DEV_: error");
+            }
+            break;
+        case _20_PERFORM_MOT_:
+            if(multipleOwnershipTransfer())
+            {
+                OIC_LOG(ERROR, TAG, "_21_PERFORM_MOT_: error");
+            }
+            break;
+        case _30_GET_LED_RESOURCE_:
+            if(sendGetLed())
+            {
+                OIC_LOG(ERROR, TAG, "_30_GET_LED_RESOURCE_: error");
+            }
+            break;
+        case _31_PUT_LED_RESOURCE_:
+            if(sendPutLed())
+            {
+                OIC_LOG(ERROR, TAG, "_31_PUT_LED_RESOURCE_: error");
+            }
+            break;
+        case _40_PROVISION_ACL_:
+            if(provisionAclForLed())
+            {
+                OIC_LOG(ERROR, TAG, "_40_PROVISION_ACL_: error");
+            }
+            break;
+        case _41_PROVISION_CRED_:
+            OIC_LOG(ERROR, TAG, "NOT SUPPORTED YET.");
+            break;
+            /*
+            if(provisionCred())
+            {
+                OIC_LOG(ERROR, TAG, "_41_PROVISION_CRED_: error");
+            }
+            break;
+            */
+        case _99_EXIT_PRVN_CLT_:
+            goto PMCLT_ERROR;
+        default:
+            printf(">> Entered Wrong Number. Please Enter Again\n\n");
+            break;
+        }
+    }
+
+PMCLT_ERROR:
+    if(OC_STACK_OK != OCStop())
+    {
+        OIC_LOG(ERROR, TAG, "OCStack stop error");
+    }
+    OCDeleteDiscoveredDevices(g_own_list);  // after here |g_own_list| points nothing
+    OCDeleteDiscoveredDevices(g_unown_list);  // after here |g_unown_list| points nothing
+    OCDeleteDiscoveredDevices(g_motdev_list);  // after here |g_motdev_list| points nothing
+
+    if(g_svr_fname)
+    {
+        OICFree(g_svr_fname);  // after here |g_svr_fname| points nothing
+    }
+    if(g_prvn_fname)
+    {
+        OICFree(g_prvn_fname);  // after here |g_prvn_fname| points nothing
+    }
+    return 0;  // always return normal case
+}
+
+#ifdef __cplusplus
+}
+#endif //__cplusplus
index 5db39c7..cc39080 100644 (file)
@@ -60,11 +60,11 @@ OCStackResult PMGeneratePairWiseCredentials(OicSecCredType_t type, size_t keySiz
     OCFillRandomMem(privData, privDataKeySize);
 
     // TODO: currently owner array is 1. only provisioning tool's id.
-    tempFirstCred =  GenerateCredential(secondDeviceId, type, NULL, &privKey, ptDeviceId);
+    tempFirstCred =  GenerateCredential(secondDeviceId, type, NULL, &privKey, ptDeviceId, NULL);
     VERIFY_NON_NULL(TAG, tempFirstCred, ERROR);
 
     // TODO: currently owner array is 1. only provisioning tool's id.
-    tempSecondCred =  GenerateCredential(firstDeviceId, type, NULL, &privKey, ptDeviceId);
+    tempSecondCred =  GenerateCredential(firstDeviceId, type, NULL, &privKey, ptDeviceId, NULL);
     VERIFY_NON_NULL(TAG, tempSecondCred, ERROR);
 
     *firstCred = tempFirstCred;
diff --git a/resource/csdk/security/provisioning/src/multipleownershiptransfermanager.c b/resource/csdk/security/provisioning/src/multipleownershiptransfermanager.c
new file mode 100644 (file)
index 0000000..0c95021
--- /dev/null
@@ -0,0 +1,1122 @@
+/* *****************************************************************
+ *
+ * Copyright 2016 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.
+ *
+ * *****************************************************************/
+
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <stdbool.h>
+#include <string.h>
+
+#include "utlist.h"
+#include "logger.h"
+#include "oic_malloc.h"
+#include "oic_string.h"
+#include "cacommon.h"
+#include "cainterface.h"
+#include "base64.h"
+#include "cJSON.h"
+#include "global.h"
+
+#include "srmresourcestrings.h"
+#include "doxmresource.h"
+#include "pstatresource.h"
+#include "credresource.h"
+#include "aclresource.h"
+#include "ownershiptransfermanager.h"
+#include "securevirtualresourcetypes.h"
+#include "oxmjustworks.h"
+#include "pmtypes.h"
+#include "pmutility.h"
+#include "srmutility.h"
+#include "provisioningdatabasemanager.h"
+#include "oxmrandompin.h"
+#include "ocpayload.h"
+#include "payload_logging.h"
+#include "oxmjustworks.h"
+#include "oxmpreconfpin.h"
+#include "oxmrandompin.h"
+
+#define TAG "MULTIPLE_OTM"
+
+/**********************************************************************
+ * API for Super Owner
+ **********************************************************************/
+
+/**
+ * Structure to carry SuperOwner's multiple ownership transfer API data to callback.
+ */
+typedef struct MOTContext MOTContext_t;
+struct MOTContext
+{
+    void *ctx;                                  /**< Pointer to user context.**/
+    const OCProvisionDev_t *deviceInfo;         /**< Pointer to OCProvisionDev_t.**/
+    OCProvisionResultCB resultCallback;         /**< Pointer to result callback.**/
+    OCProvisionResult_t *resArr;                /**< Result array.**/
+    int numOfResults;                           /**< Number of results in result array.**/
+    bool hasError;                              /**< Does MOT API have any error.. **/
+};
+
+/**
+ * Callback handler of security resource's POST request.
+ *
+ * @param[in] ctx             ctx value passed to callback from calling function.
+ * @param[in] UNUSED          handle to an invocation
+ * @param[in] clientResponse  Response from queries to remote servers.
+ * @return  OC_STACK_DELETE_TRANSACTION to delete the transaction
+ *          and  OC_STACK_KEEP_TRANSACTION to keep it.
+ */
+static OCStackApplicationResult MOTUpdateSecurityResourceCB(void *ctx, OCDoHandle UNUSED,
+                                                OCClientResponse *clientResponse)
+{
+    OIC_LOG_V(INFO, TAG, "Inside MOTUpdateMomCB.");
+    (void)UNUSED;
+    MOTContext_t *motCtx = (MOTContext_t*)ctx;
+    VERIFY_NON_NULL(TAG, motCtx, ERROR);
+    VERIFY_NON_NULL(TAG, motCtx->resultCallback, ERROR);
+    VERIFY_NON_NULL(TAG, motCtx->resArr, ERROR);
+
+    if(clientResponse)
+    {
+        memcpy(motCtx->resArr[0].deviceId.id, motCtx->deviceInfo->doxm->deviceID.id, sizeof(OicUuid_t));
+        motCtx->resArr[0].res = clientResponse->result;
+
+        if(OC_STACK_RESOURCE_CHANGED == clientResponse->result)
+        {
+            motCtx->hasError = false;
+        }
+        else
+        {
+            motCtx->hasError = true;
+        }
+    }
+    else
+    {
+        OIC_LOG_V(ERROR, TAG, "SRPGetACLResourceCB received Null clientResponse");
+        motCtx->resArr[0].res = OC_STACK_ERROR;
+        motCtx->hasError = true;
+    }
+
+    motCtx->resultCallback(motCtx->ctx, motCtx->numOfResults, motCtx->resArr, motCtx->hasError);
+
+exit:
+    if(motCtx)
+    {
+        OICFree(motCtx->resArr);
+        OICFree(motCtx);
+    }
+    return OC_STACK_DELETE_TRANSACTION;
+}
+
+/**
+ * Internal API to send POST doxm request
+ */
+static OCStackResult MOTSendPostDoxm(void *ctx,
+                                     const OCProvisionDev_t *targetDeviceInfo,
+                                     OCProvisionResultCB resultCallback,
+                                     const OicSecDoxm_t* doxm)
+{
+    OCStackResult postMomRes = OC_STACK_ERROR;
+    OCSecurityPayload* secPayload = NULL;
+    MOTContext_t *motCtx = NULL;
+    bool freeFlag = true;
+
+    OIC_LOG(DEBUG, TAG, "IN MOTSendPostDoxm");
+
+    //Generate the security payload using updated doxm
+    secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
+    VERIFY_NON_NULL(TAG, secPayload, ERROR);
+    secPayload->base.type = PAYLOAD_TYPE_SECURITY;
+
+    postMomRes = DoxmToCBORPayload(doxm, &secPayload->securityData, &secPayload->payloadSize, true);
+    VERIFY_SUCCESS(TAG, (OC_STACK_OK == postMomRes), ERROR);
+
+    OIC_LOG(DEBUG, TAG, "Created doxm payload to update doxm:");
+    OIC_LOG_BUFFER(DEBUG, TAG, secPayload->securityData, secPayload->payloadSize);
+
+    char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
+    bool queryGenRes = PMGenerateQuery(true,
+                                       targetDeviceInfo->endpoint.addr,
+                                       targetDeviceInfo->securePort,
+                                       targetDeviceInfo->connType,
+                                       query, sizeof(query), OIC_RSRC_DOXM_URI);
+    VERIFY_SUCCESS(TAG, (true == queryGenRes), ERROR);
+    OIC_LOG_V(DEBUG, TAG, "Query=%s", query);
+
+    //Create the MOT Context to handle the response message
+    motCtx = (MOTContext_t*)OICCalloc(1, sizeof(MOTContext_t));
+    VERIFY_NON_NULL(TAG, motCtx, ERROR);
+    motCtx->deviceInfo = targetDeviceInfo;
+    motCtx->resultCallback = resultCallback;
+    motCtx->numOfResults=1;
+    motCtx->hasError = false;
+    motCtx->ctx = ctx;
+    motCtx->resArr = (OCProvisionResult_t*)OICCalloc(1, sizeof(OCProvisionResult_t));
+    VERIFY_NON_NULL(TAG, motCtx->resArr, ERROR);
+
+    //Send POST request
+    OCCallbackData cbData =  {.context=NULL, .cb=NULL, .cd=NULL};
+    cbData.cb = &MOTUpdateSecurityResourceCB;
+    cbData.context = (void *)motCtx;
+    OIC_LOG(DEBUG, TAG, "Sending POST 'doxm' request to resource server");
+    postMomRes = OCDoResource(NULL, OC_REST_POST, query,
+                              &targetDeviceInfo->endpoint, (OCPayload*)secPayload,
+                              targetDeviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0);
+    VERIFY_SUCCESS(TAG, (OC_STACK_OK == postMomRes), ERROR);
+
+    freeFlag = false;
+
+    OIC_LOG(DEBUG, TAG, "OUT MOTSendPostDoxm");
+
+exit:
+    //If POST request successfully sent, motCtx will be cleaned from response handler.
+    if(freeFlag && motCtx)
+    {
+        OICFree(motCtx->resArr);
+        OICFree(motCtx);
+    }
+
+    return postMomRes;
+}
+
+/**
+ * API to update 'doxm.mom' to resource server.
+ *
+ * @param[in] targetDeviceInfo Selected target device.
+ * @param[in] momType Mode of multiple ownership transfer (ref. oic.sec.mom)
+ * @param[in] resultCallback callback provided by API user, callback will be called when
+ *            POST 'mom' request recieves a response from resource server.
+ * @return OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult MOTChangeMode(void *ctx, const OCProvisionDev_t *targetDeviceInfo,
+                            const OicSecMomType_t momType, OCProvisionResultCB resultCallback)
+{
+    OCStackResult postMomRes = OC_STACK_INVALID_PARAM;
+    OicSecDoxm_t* doxm = NULL;
+    uint8_t* doxmPayload = NULL;
+    size_t doxmPayloadLen = 0;
+
+    OIC_LOG(DEBUG, TAG, "IN MOTChangeMode");
+
+    VERIFY_NON_NULL(TAG, targetDeviceInfo, ERROR);
+    VERIFY_NON_NULL(TAG, resultCallback, ERROR);
+
+    //Dulpicate doxm resource to update the 'mom' property
+    postMomRes = DoxmToCBORPayload(targetDeviceInfo->doxm, &doxmPayload, &doxmPayloadLen, false);
+    VERIFY_SUCCESS(TAG, (OC_STACK_OK == postMomRes), ERROR);
+
+    postMomRes = CBORPayloadToDoxm(doxmPayload, doxmPayloadLen, &doxm);
+    VERIFY_SUCCESS(TAG, (OC_STACK_OK == postMomRes), ERROR);
+    VERIFY_NON_NULL(TAG, doxm, ERROR);
+
+    if(NULL == doxm->mom)
+    {
+        doxm->mom = (OicSecMom_t*)OICCalloc(1, sizeof(OicSecMom_t));
+        VERIFY_NON_NULL(TAG, (doxm->mom), ERROR);
+    }
+    doxm->mom->mode = momType;
+
+    //Send POST reuqest for update doxm
+    postMomRes = MOTSendPostDoxm(ctx, targetDeviceInfo, resultCallback, doxm);
+    VERIFY_SUCCESS(TAG, (OC_STACK_OK == postMomRes), ERROR);
+
+    OIC_LOG(DEBUG, TAG, "OUT MOTChangeMode");
+
+exit:
+    OICFree(doxmPayload);
+    DeleteDoxmBinData(doxm);
+    return postMomRes;
+}
+
+/**
+ * API to add 'doxm.oxms' to resource server.
+ *
+ * @param[in] targetDeviceInfo Selected target device.
+ * @param[in] newOxm  OxMs to be added (ref. oic.sec.oxm)
+ * @param[in] resultCallback callback provided by API user, callback will be called when
+ *            POST 'oxms' request recieves a response from resource server.
+ * @return OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult MOTAddMOTMethod(void *ctx, OCProvisionDev_t *targetDeviceInfo,
+                                 const OicSecOxm_t newOxm, OCProvisionResultCB resultCallback)
+{
+    OCStackResult postOxmRes = OC_STACK_INVALID_PARAM;
+    OicSecOxm_t* newOxms = NULL;
+    uint8_t* doxmPayload = NULL;
+    size_t doxmPayloadLen = 0;
+
+    OIC_LOG(DEBUG, TAG, "IN MOTAddMOTMethod");
+
+    VERIFY_NON_NULL(TAG, targetDeviceInfo, ERROR);
+    VERIFY_NON_NULL(TAG, resultCallback, ERROR);
+
+    for(size_t i = 0; i < targetDeviceInfo->doxm->oxmLen; i++)
+    {
+        if(targetDeviceInfo->doxm->oxm[i] == newOxm)
+        {
+            OIC_LOG_V(INFO, TAG, "[%d] OxM already supported", (int)newOxm);
+
+            OCProvisionResult_t* resArr = (OCProvisionResult_t*)OICCalloc(1, sizeof(OCProvisionResult_t));
+            resArr->res = OC_STACK_OK;
+            memcpy(resArr->deviceId.id, targetDeviceInfo->doxm->deviceID.id, sizeof(resArr->deviceId.id));
+            resultCallback(ctx, 1, resArr, false);
+
+            return OC_STACK_OK;
+        }
+    }
+
+    newOxms = (OicSecOxm_t*)OICMalloc(sizeof(OicSecOxm_t) * (targetDeviceInfo->doxm->oxmLen + 1));
+    VERIFY_NON_NULL(TAG, newOxms , ERROR);
+
+    for(size_t i = 0; i < targetDeviceInfo->doxm->oxmLen; i++)
+    {
+        newOxms[i] = targetDeviceInfo->doxm->oxm[i];
+    }
+    newOxms[targetDeviceInfo->doxm->oxmLen] = newOxm;
+    targetDeviceInfo->doxm->oxmLen++;
+    OICFree(targetDeviceInfo->doxm->oxm);
+    targetDeviceInfo->doxm->oxm = newOxms;
+
+    //Send POST reuqest for update doxm
+    postOxmRes = MOTSendPostDoxm(ctx, targetDeviceInfo, resultCallback, targetDeviceInfo->doxm);
+    VERIFY_SUCCESS(TAG, (OC_STACK_OK == postOxmRes), ERROR);
+
+    OIC_LOG(DEBUG, TAG, "OUT MOTAddMOTMethod");
+
+exit:
+    OICFree(doxmPayload);
+    return postOxmRes;
+}
+
+/**
+ * API to update 'doxm.oxmsel' to resource server.
+ *
+ * @param[in] targetDeviceInfo Selected target device.
+  * @param[in] oxmSelValue Method of multiple ownership transfer (ref. oic.sec.oxm)
+ * @param[in] resultCallback callback provided by API user, callback will be called when
+ *            POST 'oxmsel' request recieves a response from resource server.
+ * @return OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult MOTSelectMOTMethod(void *ctx, const OCProvisionDev_t *targetDeviceInfo,
+                                 const OicSecOxm_t oxmSelValue, OCProvisionResultCB resultCallback)
+{
+    OCStackResult postMomRes = OC_STACK_INVALID_PARAM;
+    OicSecDoxm_t* doxm = NULL;
+    uint8_t* doxmPayload = NULL;
+    size_t doxmPayloadLen = 0;
+
+    OIC_LOG(DEBUG, TAG, "IN MOTSelectOTMethod");
+
+    VERIFY_NON_NULL(TAG, targetDeviceInfo, ERROR);
+    VERIFY_NON_NULL(TAG, resultCallback, ERROR);
+
+    bool isValidOxmsel = false;
+    for(size_t i = 0; i < targetDeviceInfo->doxm->oxmLen; i++)
+    {
+        if(targetDeviceInfo->doxm->oxm[i] == oxmSelValue)
+        {
+            isValidOxmsel = true;
+            break;
+        }
+    }
+    VERIFY_SUCCESS(TAG, isValidOxmsel, ERROR);
+
+    //Dulpicate doxm resource to update the 'oxmsel' property
+    postMomRes = DoxmToCBORPayload(targetDeviceInfo->doxm, &doxmPayload, &doxmPayloadLen, false);
+    VERIFY_SUCCESS(TAG, (OC_STACK_OK == postMomRes), ERROR);
+
+    postMomRes = CBORPayloadToDoxm(doxmPayload, doxmPayloadLen, &doxm);
+    VERIFY_SUCCESS(TAG, (OC_STACK_OK == postMomRes), ERROR);
+    VERIFY_NON_NULL(TAG, doxm, ERROR);
+
+    doxm->oxmSel = oxmSelValue;
+
+    //Send POST reuqest for update doxm
+    postMomRes = MOTSendPostDoxm(ctx, targetDeviceInfo, resultCallback, doxm);
+    VERIFY_SUCCESS(TAG, (OC_STACK_OK == postMomRes), ERROR);
+
+    OIC_LOG(DEBUG, TAG, "OUT MOTSelectOTMethod");
+
+exit:
+    OICFree(doxmPayload);
+    DeleteDoxmBinData(doxm);
+    return postMomRes;
+}
+
+/**
+ * API to provision preconfigured PIN to resource server.
+ *
+ * @param[in] targetDeviceInfo Selected target device.
+ * @param[in] preconfPIN Preconfig PIN which is used while multiple owner authentication
+ * @param[in] preconfPINLen Byte length of preconfig PIN
+ * @param[in] resultCallback callback provided by API user, callback will be called when
+ *            POST credential request recieves a response from resource server.
+ * @return OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult MOTProvisionPreconfigPIN(void *ctx, const OCProvisionDev_t *targetDeviceInfo,
+                                 const char* preconfPIN, size_t preconfPINLen, OCProvisionResultCB resultCallback)
+{
+    OCStackResult postCredRes = OC_STACK_INVALID_PARAM;
+    bool freeFlag = true;
+    OCSecurityPayload* secPayload = NULL;
+    MOTContext_t *motCtx = NULL;
+    OicSecCred_t* pinCred = NULL;
+
+    OIC_LOG(DEBUG, TAG, "IN MOTProvisionPreconfigPIN");
+
+    VERIFY_NON_NULL(TAG, targetDeviceInfo, ERROR);
+    VERIFY_NON_NULL(TAG, resultCallback, ERROR);
+    VERIFY_NON_NULL(TAG, preconfPIN, ERROR);
+    VERIFY_SUCCESS(TAG, (0 != preconfPINLen), ERROR);
+    VERIFY_SUCCESS(TAG, (0 != preconfPINLen && OXM_PRECONFIG_PIN_SIZE >= preconfPINLen), ERROR);
+
+    postCredRes = OC_STACK_NO_MEMORY;
+    //Generate PIN based credential
+    pinCred = (OicSecCred_t*)OICCalloc(1, sizeof(OicSecCred_t));
+    VERIFY_NON_NULL(TAG, pinCred, ERROR);
+
+    pinCred->privateData.data = (uint8_t*)OICMalloc(preconfPINLen + 1);
+    VERIFY_NON_NULL(TAG, pinCred->privateData.data, ERROR);
+
+    memcpy(pinCred->privateData.data, preconfPIN, preconfPINLen);
+    pinCred->privateData.data[preconfPINLen] = '\0';
+    pinCred->privateData.len = preconfPINLen;
+    pinCred->privateData.encoding = OIC_ENCODING_RAW;
+    pinCred->credType = PIN_PASSWORD;
+    OICStrcpy(pinCred->subject.id, sizeof(pinCred->subject.id), WILDCARD_SUBJECT_ID.id);
+
+    //Generate the security payload using updated doxm
+    secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
+    VERIFY_NON_NULL(TAG, secPayload, ERROR);
+    secPayload->base.type = PAYLOAD_TYPE_SECURITY;
+
+    postCredRes = CredToCBORPayload(pinCred, &secPayload->securityData, &secPayload->payloadSize, false);
+    VERIFY_SUCCESS(TAG, (OC_STACK_OK == postCredRes), ERROR);
+
+    OIC_LOG(DEBUG, TAG, "Created Credential payload to register PIN credential:");
+    OIC_LOG_BUFFER(DEBUG, TAG, secPayload->securityData, secPayload->payloadSize);
+
+    char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
+    bool queryGenRes = PMGenerateQuery(true,
+                                       targetDeviceInfo->endpoint.addr,
+                                       targetDeviceInfo->securePort,
+                                       targetDeviceInfo->connType,
+                                       query, sizeof(query), OIC_RSRC_CRED_URI);
+    VERIFY_SUCCESS(TAG, (true == queryGenRes), ERROR);
+    OIC_LOG_V(DEBUG, TAG, "Query=%s", query);
+
+    //Create the MOT Context to handle the response message
+    motCtx = (MOTContext_t*)OICCalloc(1, sizeof(MOTContext_t));
+    VERIFY_NON_NULL(TAG, motCtx, ERROR);
+    motCtx->deviceInfo = targetDeviceInfo;
+    motCtx->resultCallback = resultCallback;
+    motCtx->numOfResults=1;
+    motCtx->hasError = false;
+    motCtx->ctx = ctx;
+    motCtx->resArr = (OCProvisionResult_t*)OICCalloc(1, sizeof(OCProvisionResult_t));
+    VERIFY_NON_NULL(TAG, motCtx->resArr, ERROR);
+
+    //Send POST request
+    OCCallbackData cbData =  {.context=NULL, .cb=NULL, .cd=NULL};
+    cbData.cb = &MOTUpdateSecurityResourceCB;
+    cbData.context = (void *)motCtx;
+    OIC_LOG(DEBUG, TAG, "Sending POST Preconfiged PIN credenatial request to resource server");
+    postCredRes = OCDoResource(NULL, OC_REST_POST, query,
+                              &targetDeviceInfo->endpoint, (OCPayload*)secPayload,
+                              targetDeviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0);
+    VERIFY_SUCCESS(TAG, (OC_STACK_OK == postCredRes), ERROR);
+
+    freeFlag = false;
+
+    OIC_LOG(DEBUG, TAG, "OUT MOTProvisionPreconfigPIN");
+
+    return postCredRes;
+
+exit:
+    //If POST request successfully sent, motCtx will be cleaned from response handler.
+    if(freeFlag && motCtx)
+    {
+        OICFree(motCtx->resArr);
+        OICFree(motCtx);
+    }
+    if(pinCred)
+    {
+        OICFree(pinCred->privateData.data);
+        OICFree(pinCred);
+    }
+    return postCredRes;
+}
+
+
+/**********************************************************************
+ * API for Sub Owner
+ **********************************************************************/
+
+static OCStackResult StartMultipleOwnershipTransfer(OTMContext_t* motCtx,
+                                                    OCProvisionDev_t* selectedDevice);
+
+/**
+ * Array to store the callbacks for each owner transfer method.
+ */
+static OTMCallbackData_t g_MOTCbDatas[OIC_OXM_COUNT] = {
+        //Just works
+        {.loadSecretCB = LoadSecretJustWorksCallback,
+          .createSecureSessionCB = CreateSecureSessionJustWorksCallback,
+          .createSelectOxmPayloadCB = NULL,
+          .createOwnerTransferPayloadCB = NULL},
+
+          //Random PIN
+        {.loadSecretCB = InputPinCodeCallback,
+          .createSecureSessionCB = CreateSecureSessionRandomPinCallback,
+          .createSelectOxmPayloadCB = NULL,
+          .createOwnerTransferPayloadCB = NULL},
+
+        //Manufacturer Cert
+        {.loadSecretCB = NULL,
+          .createSecureSessionCB = NULL,
+          .createSelectOxmPayloadCB = NULL,
+          .createOwnerTransferPayloadCB = NULL},
+
+          //Preconfig PIN
+        {.loadSecretCB = LoadPreconfPinCodeCallback,
+          .createSecureSessionCB = CreateSecureSessionPreconfPinCallback,
+          .createSelectOxmPayloadCB = NULL,
+          .createOwnerTransferPayloadCB = NULL},
+};
+
+static OTMContext_t* g_MotCtx = NULL;
+
+static bool IsComplete(OTMContext_t* otmCtx)
+{
+    for(size_t i = 0; i < otmCtx->ctxResultArraySize; i++)
+    {
+        if(OC_STACK_CONTINUE == otmCtx->ctxResultArray[i].res)
+        {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+/**
+ * Function to save the result of multiple ownership transfer.
+ *
+ * @param[in,out] motCtx   Context instance of multiple ownership transfer.
+ * @param[in] res   result of multiple ownership transfer.
+ */
+static void SetMOTResult(OTMContext_t* motCtx, const OCStackResult res)
+{
+    OIC_LOG_V(DEBUG, TAG, "IN SetMOTResult : %d ", res);
+
+    VERIFY_NON_NULL(TAG, motCtx, ERROR);
+
+    if(motCtx->selectedDeviceInfo)
+    {
+        //Revert psk_info callback in case of random PIN OxM
+        if(OIC_RANDOM_DEVICE_PIN == motCtx->selectedDeviceInfo->doxm->oxmSel ||
+           OIC_PRECONFIG_PIN == motCtx->selectedDeviceInfo->doxm->oxmSel)
+        {
+            if(CA_STATUS_OK != CAregisterPskCredentialsHandler(GetDtlsPskCredentials))
+            {
+                OIC_LOG(WARNING, TAG, "Failed to revert the DTLS credential handler.");
+            }
+            OicUuid_t emptyUuid = { .id={0}};
+            SetUuidForPinBasedOxm(&emptyUuid);
+        }
+
+        for(size_t i = 0; i < motCtx->ctxResultArraySize; i++)
+        {
+            if(memcmp(motCtx->selectedDeviceInfo->doxm->deviceID.id,
+                      motCtx->ctxResultArray[i].deviceId.id, UUID_LENGTH) == 0)
+            {
+                motCtx->ctxResultArray[i].res = res;
+                if(OC_STACK_OK != res)
+                {
+                    motCtx->ctxHasError = true;
+                }
+            }
+        }
+
+        g_MotCtx = NULL;
+
+        //If all request is completed, invoke the user callback.
+        if(IsComplete(motCtx))
+        {
+            motCtx->ctxResultCallback(motCtx->userCtx, motCtx->ctxResultArraySize,
+                                       motCtx->ctxResultArray, motCtx->ctxHasError);
+
+            OICFree(motCtx->ctxResultArray);
+            OICFree(motCtx);
+        }
+        else
+        {
+            if(OC_STACK_OK != StartMultipleOwnershipTransfer(motCtx,
+                                                     motCtx->selectedDeviceInfo->next))
+            {
+                OIC_LOG(ERROR, TAG, "Failed to StartMultipleOwnershipTransfer");
+            }
+        }
+    }
+
+exit:
+    OIC_LOG(DEBUG, TAG, "OUT SetMOTResult");
+}
+
+/**
+ * API to add preconfigured PIN to local SVR DB.
+ *
+ * @param[in] targetDeviceInfo Selected target device.
+ * @param[in] preconfPIN Preconfig PIN which is used while multiple owner authentication
+ * @param[in] preconfPINLen Byte length of preconfig PIN
+ * @param[in] resultCallback callback provided by API user, callback will be called when
+ *            POST credential request recieves a response from resource server.
+ * @return OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult MOTAddPreconfigPIN(const OCProvisionDev_t *targetDeviceInfo,
+                                 const char* preconfPIN, size_t preconfPINLen)
+{
+    OCStackResult addCredRes = OC_STACK_INVALID_PARAM;
+    OicSecCred_t* pinCred = NULL;
+    bool freeFlag = true;
+
+    OIC_LOG(DEBUG, TAG, "IN MOTAddPreconfigPIN");
+
+    VERIFY_NON_NULL(TAG, targetDeviceInfo, ERROR);
+    VERIFY_NON_NULL(TAG, preconfPIN, ERROR);
+    VERIFY_SUCCESS(TAG, (0 != preconfPINLen), ERROR);
+    VERIFY_SUCCESS(TAG, (0 != preconfPINLen && OXM_PRECONFIG_PIN_SIZE >= preconfPINLen), ERROR);
+
+    OicSecCred_t* prevCred = GetCredResourceData(&targetDeviceInfo->doxm->deviceID);
+    if(NULL != prevCred)
+    {
+        OIC_LOG(INFO, TAG, "PIN/PW Credential already exist!");
+        return OC_STACK_OK;
+    }
+
+    addCredRes = OC_STACK_NO_MEMORY;
+    //Generate PIN based credential
+    pinCred = (OicSecCred_t*)OICCalloc(1, sizeof(OicSecCred_t));
+    VERIFY_NON_NULL(TAG, pinCred, ERROR);
+
+    pinCred->privateData.data = (uint8_t*)OICMalloc(preconfPINLen + 1);
+    VERIFY_NON_NULL(TAG, pinCred->privateData.data, ERROR);
+
+    memcpy(pinCred->privateData.data, preconfPIN, preconfPINLen);
+    pinCred->privateData.data[preconfPINLen] = '\0';
+    pinCred->privateData.len = preconfPINLen;
+    pinCred->privateData.encoding = OIC_ENCODING_RAW;
+    pinCred->credType = PIN_PASSWORD;
+    memcpy(pinCred->subject.id, targetDeviceInfo->doxm->deviceID.id, sizeof(pinCred->subject.id));
+
+    addCredRes = AddCredential(pinCred);
+    VERIFY_SUCCESS(TAG, (OC_STACK_OK == addCredRes), ERROR);
+
+    OIC_LOG(DEBUG, TAG, "OUT MOTAddPreconfigPIN");
+
+    return addCredRes;
+
+exit:
+    if(pinCred)
+    {
+        OICFree(pinCred->privateData.data);
+        OICFree(pinCred);
+    }
+    return addCredRes;
+}
+
+/**
+ * Function to save the SubOwner PSK.
+ *
+ * @param[in] selectedDeviceInfo   selected device information to performing provisioning.
+ * @return  OC_STACK_OK on success
+ */
+static OCStackResult SaveSubOwnerPSK(OCProvisionDev_t *selectedDeviceInfo)
+{
+    OIC_LOG(DEBUG, TAG, "IN SaveSubOwnerPSK");
+
+    OCStackResult res = OC_STACK_ERROR;
+
+    CAEndpoint_t endpoint;
+    memset(&endpoint, 0x00, sizeof(CAEndpoint_t));
+    OICStrcpy(endpoint.addr, MAX_ADDR_STR_SIZE_CA, selectedDeviceInfo->endpoint.addr);
+    endpoint.addr[MAX_ADDR_STR_SIZE_CA - 1] = '\0';
+    endpoint.port = selectedDeviceInfo->securePort;
+    endpoint.adapter = selectedDeviceInfo->endpoint.adapter;
+
+    OicUuid_t ownerDeviceID = {.id={0}};
+    if (OC_STACK_OK != GetDoxmDeviceID(&ownerDeviceID))
+    {
+        OIC_LOG(ERROR, TAG, "Error while retrieving SubOwner's device ID");
+        return res;
+    }
+
+    uint8_t ownerPSK[OWNER_PSK_LENGTH_128] = {0};
+    OicSecKey_t ownerKey = {ownerPSK, OWNER_PSK_LENGTH_128};
+
+    //Generating SubOwnerPSK
+    CAResult_t pskRet = CAGenerateOwnerPSK(&endpoint,
+            (uint8_t *)GetOxmString(selectedDeviceInfo->doxm->oxmSel),
+            strlen(GetOxmString(selectedDeviceInfo->doxm->oxmSel)),
+            ownerDeviceID.id, sizeof(ownerDeviceID.id),
+            selectedDeviceInfo->doxm->deviceID.id, sizeof(selectedDeviceInfo->doxm->deviceID.id),
+            ownerPSK, OWNER_PSK_LENGTH_128);
+
+    if (CA_STATUS_OK == pskRet)
+    {
+        OIC_LOG(INFO, TAG, "SubOwner PSK dump:");
+        OIC_LOG_BUFFER(INFO, TAG, ownerPSK, OWNER_PSK_LENGTH_128);
+        //Generating new credential for provisioning tool
+        OicSecCred_t *cred = GenerateCredential(&selectedDeviceInfo->doxm->deviceID,
+                                      SYMMETRIC_PAIR_WISE_KEY, NULL,
+                                      &ownerKey, &ownerDeviceID, &ownerDeviceID);
+        VERIFY_NON_NULL(TAG, cred, ERROR);
+
+        uint32_t outSize = 0;
+        size_t b64BufSize = B64ENCODE_OUT_SAFESIZE((OWNER_PSK_LENGTH_128 + 1));
+        char* b64Buf = (uint8_t *)OICCalloc(1, b64BufSize);
+        VERIFY_NON_NULL(TAG, b64Buf, ERROR);
+        b64Encode(cred->privateData.data, cred->privateData.len, b64Buf, b64BufSize, &outSize);
+
+        OICFree( cred->privateData.data );
+        cred->privateData.data = (uint8_t *)OICCalloc(1, outSize + 1);
+        VERIFY_NON_NULL(TAG, cred->privateData.data, ERROR);
+
+        strncpy(cred->privateData.data, b64Buf, outSize);
+        cred->privateData.data[outSize] = '\0';
+        cred->privateData.encoding = OIC_ENCODING_BASE64;
+        cred->privateData.len = outSize;
+        OICFree(b64Buf);
+
+        //Add SubOwnerPSK
+        res = AddCredential(cred);
+        if(res != OC_STACK_OK)
+        {
+            DeleteCredList(cred);
+            return res;
+        }
+    }
+    else
+    {
+        OIC_LOG(ERROR, TAG, "CAGenerateOwnerPSK failed");
+    }
+
+    OIC_LOG(DEBUG, TAG, "OUT SaveSubOwnerPSK");
+exit:
+    return res;
+}
+
+
+/**
+ * Response handler for update subowner crendetial request.
+ *
+ * @param[in] ctx             ctx value passed to callback from calling function.
+ * @param[in] UNUSED          handle to an invocation
+ * @param[in] clientResponse  Response from queries to remote servers.
+ * @return  OC_STACK_DELETE_TRANSACTION to delete the transaction
+ *          and  OC_STACK_KEEP_TRANSACTION to keep it.
+ */
+static OCStackApplicationResult SubOwnerCredentialHandler(void *ctx, OCDoHandle UNUSED,
+                                OCClientResponse *clientResponse)
+{
+    VERIFY_NON_NULL(TAG, clientResponse, WARNING);
+    VERIFY_NON_NULL(TAG, ctx, WARNING);
+
+    OIC_LOG(DEBUG, TAG, "IN SubOwnerCredentialHandler");
+    (void)UNUSED;
+    OCStackResult res = OC_STACK_ERROR;
+    OTMContext_t* motCtx = (OTMContext_t*)ctx;
+
+    if(OC_STACK_RESOURCE_CHANGED == clientResponse->result)
+    {
+        if(motCtx && motCtx->selectedDeviceInfo)
+        {
+            //Close the temporal secure session to verify the owner credential
+            CAEndpoint_t* endpoint = (CAEndpoint_t *)&motCtx->selectedDeviceInfo->endpoint;
+            endpoint->port = motCtx->selectedDeviceInfo->securePort;
+            CAResult_t caResult = CAcloseSslSession(endpoint);
+            if(CA_STATUS_OK != caResult)
+            {
+                OIC_LOG(ERROR, TAG, "Failed to close DTLS session");
+                SetMOTResult(motCtx, OC_STACK_ERROR);
+                return OC_STACK_DELETE_TRANSACTION;
+            }
+
+            // TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256 = 0xC037, /**< see RFC 5489 */
+            caResult = CASelectCipherSuite(0xC037, endpoint->adapter);
+            if(CA_STATUS_OK != caResult)
+            {
+                OIC_LOG(ERROR, TAG, "Failed to select TLS_NULL_WITH_NULL_NULL");
+                SetMOTResult(motCtx, OC_STACK_ERROR);
+                return OC_STACK_DELETE_TRANSACTION;
+            }
+
+            res = PDMAddDevice(&motCtx->selectedDeviceInfo->doxm->deviceID);
+             if (OC_STACK_OK == res)
+             {
+                    OIC_LOG_V(INFO, TAG, "Add device's UUID in PDM_DB");
+             }
+              else
+             {
+                  OIC_LOG(ERROR, TAG, "MOT is complete but adding information to DB is failed.");
+             }
+
+            SetMOTResult(motCtx, res);
+        }
+    }
+    else
+    {
+        res = clientResponse->result;
+        OIC_LOG_V(ERROR, TAG, "SubOwnerCredentialHandler : Unexpected result %d", res);
+        SetMOTResult(motCtx, res);
+    }
+
+    OIC_LOG(DEBUG, TAG, "OUT SubOwnerCredentialHandler");
+
+exit:
+    return  OC_STACK_DELETE_TRANSACTION;
+}
+
+
+static OCStackResult PostSubOwnerCredential(OTMContext_t* motCtx)
+{
+    OIC_LOG(DEBUG, TAG, "IN PostSubOwnerCredential");
+
+    if(!motCtx || !motCtx->selectedDeviceInfo)
+    {
+        OIC_LOG(ERROR, TAG, "Invalid parameters");
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    OCProvisionDev_t* deviceInfo = motCtx->selectedDeviceInfo;
+    char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
+
+    if(!PMGenerateQuery(true,
+                        deviceInfo->endpoint.addr, deviceInfo->securePort,
+                        deviceInfo->connType,
+                        query, sizeof(query), OIC_RSRC_CRED_URI))
+    {
+        OIC_LOG(ERROR, TAG, "PostSubOwnerCredential : Failed to generate query");
+        return OC_STACK_ERROR;
+    }
+    OIC_LOG_V(DEBUG, TAG, "Query=%s", query);
+    OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
+    if(!secPayload)
+    {
+        OIC_LOG(ERROR, TAG, "Failed to memory allocation");
+        return OC_STACK_NO_MEMORY;
+    }
+
+    //Generate sub-owner credential for new device
+    secPayload->base.type = PAYLOAD_TYPE_SECURITY;
+    const OicSecCred_t* ownerCredential = GetCredResourceData(&(deviceInfo->doxm->deviceID));
+    if(!ownerCredential)
+    {
+        OIC_LOG(ERROR, TAG, "Can not find SubOwnerPSK.");
+        return OC_STACK_NO_RESOURCE;
+    }
+
+    OicUuid_t ownerId = {.id={0}};
+    if(OC_STACK_OK == GetDoxmDeviceID(&ownerId))
+    {
+        OicSecCred_t newCredential;
+        memcpy(&newCredential, ownerCredential, sizeof(OicSecCred_t));
+        newCredential.next = NULL;
+
+        //Set subject ID as SubOwner's ID
+        memcpy(&(newCredential.subject), &ownerId, sizeof(OicUuid_t));
+
+        //Set eowner ID as SubOwner's ID
+        if(NULL == newCredential.eownerID)
+        {
+            newCredential.eownerID = OICCalloc(1, sizeof(OicUuid_t));
+            if(NULL == newCredential.eownerID)
+            {
+                return OC_STACK_NO_MEMORY;
+            }
+        }
+        memcpy(newCredential.eownerID->id, ownerId.id, sizeof(ownerId.id));
+
+        //Fill private data as empty string
+        newCredential.privateData.data = "";
+        newCredential.privateData.len = 0;
+        newCredential.privateData.encoding = ownerCredential->privateData.encoding;
+#ifdef __WITH_X509__
+        newCredential.publicData.data = NULL;
+        newCredential.publicData.len = 0;
+#endif
+        //Send owner credential to new device : POST /oic/sec/cred [ owner credential ]
+        if (OC_STACK_OK != CredToCBORPayload(&newCredential, &secPayload->securityData,
+                                        &secPayload->payloadSize, 0))
+        {
+            OICFree(secPayload);
+            OIC_LOG(ERROR, TAG, "Error while converting bin to cbor.");
+            return OC_STACK_ERROR;
+        }
+        OIC_LOG(DEBUG, TAG, "Cred Payload:");
+        OIC_LOG_BUFFER(DEBUG, TAG, secPayload->securityData, secPayload->payloadSize);
+
+        OCCallbackData cbData;
+        cbData.cb = &SubOwnerCredentialHandler;
+        cbData.context = (void *)motCtx;
+        cbData.cd = NULL;
+        OCStackResult res = OCDoResource(NULL, OC_REST_POST, query,
+                                         &deviceInfo->endpoint, (OCPayload*)secPayload,
+                                         deviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0);
+        if (res != OC_STACK_OK)
+        {
+            OIC_LOG(ERROR, TAG, "OCStack resource error");
+        }
+    }
+    else
+    {
+        OIC_LOG(ERROR, TAG, "Failed to read DOXM device ID.");
+        return OC_STACK_NO_RESOURCE;
+    }
+
+    OIC_LOG(DEBUG, TAG, "OUT PostSubOwnerCredential");
+
+    return OC_STACK_OK;
+}
+
+
+/**
+ * Function to handle the handshake result in MOT.
+ * This function will be invoked after DTLS handshake
+ * @param   endPoint  [IN] The remote endpoint.
+ * @param   errorInfo [IN] Error information from the endpoint.
+ * @return  NONE
+ */
+static void MOTDtlsHandshakeCB(const CAEndpoint_t *endpoint, const CAErrorInfo_t *info)
+{
+    if(NULL != g_MotCtx && NULL != g_MotCtx->selectedDeviceInfo &&
+       NULL != endpoint && NULL != info)
+    {
+        OIC_LOG_V(INFO, TAG, "Received status from remote device(%s:%d) : %d",
+                 endpoint->addr, endpoint->port, info->result);
+
+        OicSecDoxm_t* newDevDoxm = g_MotCtx->selectedDeviceInfo->doxm;
+
+        if(NULL != newDevDoxm)
+        {
+            OicUuid_t emptyUuid = {.id={0}};
+
+            //Make sure the address matches.
+            if(strncmp(g_MotCtx->selectedDeviceInfo->endpoint.addr,
+               endpoint->addr,
+               sizeof(endpoint->addr)) == 0 &&
+               g_MotCtx->selectedDeviceInfo->securePort == endpoint->port)
+            {
+                OCStackResult res = OC_STACK_ERROR;
+
+                //If temporal secure sesstion established successfully
+                if(CA_STATUS_OK == info->result)
+                {
+                    //Delete previous credential such as preconfigured-pin
+                    RemoveCredential(&(g_MotCtx->selectedDeviceInfo->doxm->deviceID));
+
+                    res = SaveSubOwnerPSK(g_MotCtx->selectedDeviceInfo);
+                    if(OC_STACK_OK == res)
+                    {
+                        //POST sub owner credential to new device.
+                        res = PostSubOwnerCredential(g_MotCtx);
+                        if(OC_STACK_OK != res)
+                        {
+                            OIC_LOG(ERROR, TAG,
+                                    "Failed to send POST request for SubOwner Credential");
+                            SetMOTResult(g_MotCtx, res);
+                        }
+                    }
+                    else
+                    {
+                        OIC_LOG(ERROR, TAG, "Failed to save the SubOwner PSK.");
+                        SetMOTResult(g_MotCtx, res);
+                    }
+                }
+                //In case of authentication failure
+                else if(CA_DTLS_AUTHENTICATION_FAILURE == info->result)
+                {
+                    //in case of error from wrong PIN, re-start the ownership transfer
+                    if(OIC_RANDOM_DEVICE_PIN == newDevDoxm->oxmSel)
+                    {
+                        OIC_LOG(ERROR, TAG, "The PIN number may incorrect.");
+
+                        g_MotCtx->attemptCnt++;
+
+                        if(WRONG_PIN_MAX_ATTEMP > g_MotCtx->attemptCnt)
+                        {
+                            res = StartMultipleOwnershipTransfer(g_MotCtx, g_MotCtx->selectedDeviceInfo);
+                            if(OC_STACK_OK != res)
+                            {
+                                SetMOTResult(g_MotCtx, res);
+                                OIC_LOG(ERROR, TAG, "Failed to Re-StartOwnershipTransfer");
+                            }
+                        }
+                        else
+                        {
+                            OIC_LOG(ERROR, TAG, "User has exceeded the number of authentication attempts.");
+                            SetMOTResult(g_MotCtx, OC_STACK_AUTHENTICATION_FAILURE);
+                        }
+                    }
+                    else
+                    {
+                        OIC_LOG(ERROR, TAG, "Failed to establish DTLS session.");
+                        SetMOTResult(g_MotCtx, OC_STACK_AUTHENTICATION_FAILURE);
+                    }
+                }
+            }
+        }
+    }
+}
+
+static OCStackResult StartMultipleOwnershipTransfer(OTMContext_t* motCtx,
+                                                    OCProvisionDev_t* selectedDevice)
+{
+    OIC_LOG(INFO, TAG, "IN StartMultipleOwnershipTransfer");
+    OCStackResult res = OC_STACK_INVALID_PARAM;
+
+    VERIFY_NON_NULL(TAG, selectedDevice, ERROR);
+    VERIFY_NON_NULL(TAG, selectedDevice->doxm, ERROR);
+
+    motCtx->selectedDeviceInfo = selectedDevice;
+
+    //Register DTLS event handler to catch the dtls event while handshake
+    if(CA_STATUS_OK != CAregisterSslHandshakeCallback(MOTDtlsHandshakeCB))
+    {
+        OIC_LOG(WARNING, TAG, "StartOwnershipTransfer : Failed to register DTLS handshake callback.");
+    }
+
+    size_t oxmSel = (size_t)(selectedDevice->doxm->oxmSel);
+    OIC_LOG_V(DEBUG, TAG, "Multiple Ownership Transfer method = %d", selectedDevice->doxm->oxmSel);
+
+    if(OIC_PRECONFIG_PIN != oxmSel && OIC_RANDOM_DEVICE_PIN != oxmSel)
+    {
+        OIC_LOG(ERROR, TAG, "Unsupported OxM");
+        return OC_STACK_ERROR;
+    }
+
+    if(OIC_RANDOM_DEVICE_PIN == selectedDevice->doxm->oxmSel)
+    {
+        if(CA_STATUS_OK != CAregisterPskCredentialsHandler(GetDtlsPskForRandomPinOxm))
+        {
+            OIC_LOG(ERROR, TAG, "Failed to register DTLS credential handler for Random PIN OxM.");
+        }
+    }
+
+    res = g_MOTCbDatas[oxmSel].loadSecretCB(motCtx);
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == res, ERROR);
+
+    //Save the current context instance to use on the dtls handshake callback
+    g_MotCtx = motCtx;
+
+    res = g_MOTCbDatas[oxmSel].createSecureSessionCB(motCtx);
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == res, ERROR);
+
+    OIC_LOG(INFO, TAG, "OUT StartMultipleOwnershipTransfer");
+
+exit:
+    return res;
+}
+
+OCStackResult MOTDoOwnershipTransfer(void* ctx,
+                                     OCProvisionDev_t *selectedDevicelist,
+                                     OCProvisionResultCB resultCallback)
+{
+    OIC_LOG(DEBUG, TAG, "IN MOTDoOwnershipTransfer");
+    OCStackResult res = OC_STACK_INVALID_PARAM;
+    OTMContext_t* motCtx = NULL;
+    OCProvisionDev_t* pCurDev = NULL;
+
+    VERIFY_NON_NULL(TAG, selectedDevicelist, ERROR);
+    VERIFY_NON_NULL(TAG, resultCallback, ERROR);
+
+    res = OC_STACK_NO_MEMORY;
+    motCtx = (OTMContext_t*)OICCalloc(1,sizeof(OTMContext_t));
+    VERIFY_NON_NULL(TAG, motCtx, ERROR);
+
+    motCtx->ctxResultCallback = resultCallback;
+    motCtx->ctxHasError = false;
+    motCtx->userCtx = ctx;
+    motCtx->ctxResultArraySize = 0;
+    LL_FOREACH(selectedDevicelist, pCurDev)
+    {
+        motCtx->ctxResultArraySize++;
+    }
+
+    motCtx->ctxResultArray =
+        (OCProvisionResult_t*)OICCalloc(motCtx->ctxResultArraySize, sizeof(OCProvisionResult_t));
+    VERIFY_NON_NULL(TAG, motCtx->ctxResultArray, ERROR);
+
+    //Fill the device UUID for result array.
+    size_t devIdx = 0;
+    res = OC_STACK_OK;
+    pCurDev = NULL;
+    LL_FOREACH(selectedDevicelist, pCurDev)
+    {
+        //Checking duplication of Device ID.
+        bool isDuplicate = true;
+        res = PDMIsDuplicateDevice(&pCurDev->doxm->deviceID, &isDuplicate);
+        VERIFY_SUCCESS(TAG, OC_STACK_OK == res, ERROR);
+
+        if (isDuplicate)
+        {
+            bool isStale = false;
+            res = PDMIsDeviceStale(&pCurDev->doxm->deviceID, &isStale);
+            VERIFY_SUCCESS(TAG, OC_STACK_OK == res, ERROR);
+            VERIFY_SUCCESS(TAG, isStale, ERROR);
+
+            if(isStale)
+            {
+                OIC_LOG(INFO, TAG, "Detected duplicated UUID in stale status, "\
+                                   "this UUID will be removed from PDM");
+
+                res = PDMDeleteDevice(&pCurDev->doxm->deviceID);
+                VERIFY_SUCCESS(TAG, OC_STACK_OK == res, ERROR);
+            }
+        }
+
+        memcpy(motCtx->ctxResultArray[devIdx].deviceId.id,
+               pCurDev->doxm->deviceID.id,
+               UUID_LENGTH);
+        motCtx->ctxResultArray[devIdx].res = OC_STACK_CONTINUE;
+        devIdx++;
+    }
+
+    res = StartMultipleOwnershipTransfer(motCtx, selectedDevicelist);
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == res, ERROR);
+
+    OIC_LOG(DEBUG, TAG, "OUT MOTDoOwnershipTransfer");
+
+exit:
+    if(OC_STACK_OK != res)
+    {
+        if(motCtx)
+        {
+            OICFree(motCtx->ctxResultArray);
+            OICFree(motCtx);
+        }
+    }
+    return res;
+}
index 60dc0a3..efc4072 100755 (executable)
@@ -24,6 +24,9 @@
 #include "pmutility.h"
 #include "srmutility.h"
 #include "ownershiptransfermanager.h"
+#ifdef _ENABLE_MULTIPLE_OWNER_
+#include "multipleownershiptransfermanager.h"
+#endif //_ENABLE_MULTIPLE_OWNER_
 #include "oic_malloc.h"
 #include "logger.h"
 #include "secureresourceprovider.h"
@@ -50,6 +53,18 @@ struct Linkdata
 
 };
 
+#ifdef _ENABLE_MULTIPLE_OWNER_
+typedef struct ProvPreconfPINCtx ProvPreconfPINCtx_t;
+struct ProvPreconfPINCtx
+{
+    void *ctx;
+    const OCProvisionDev_t *devInfo;
+    const char* pin;
+    size_t pinLen;
+    OCProvisionResultCB resultCallback;
+};
+#endif //_ENABLE_MULTIPLE_OWNER_
+
 /**
  * The function is responsible for initializaton of the provisioning manager. It will load
  * provisioning database which have owned device's list and their linked status.
@@ -125,6 +140,78 @@ OCStackResult OCDiscoverOwnedDevices(unsigned short timeout, OCProvisionDev_t **
     return PMDeviceDiscovery(timeout, true, ppList);
 }
 
+#ifdef _ENABLE_MULTIPLE_OWNER_
+/**
+ * The function is responsible for discovery of MOT enabled device is current subnet.
+ *
+ * @param[in] timeout Timeout in seconds, value till which function will listen to responses from
+ *                    server before returning the list of devices.
+ * @param[out] ppList List of MOT enabled devices.
+ * @return OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult OCDiscoverMultipleOwnerEnabledDevices(unsigned short timeout, OCProvisionDev_t **ppList)
+{
+    if( ppList == NULL || *ppList != NULL || 0 == timeout)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    return PMMultipleOwnerDeviceDiscovery(timeout, false, ppList);
+}
+
+/**
+ * The function is responsible for discovery of Multiple Owned device is current subnet.
+ *
+ * @param[in] timeout Timeout in seconds, value till which function will listen to responses from
+ *                    server before returning the list of devices.
+ * @param[out] ppList List of Multiple Owned devices.
+ * @return OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult OCDiscoverMultipleOwnedDevices(unsigned short timeout, OCProvisionDev_t **ppList)
+{
+    if( ppList == NULL || *ppList != NULL || 0 == timeout)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    return PMMultipleOwnerDeviceDiscovery(timeout, true, ppList);
+}
+
+
+/**
+ * API to add preconfigured PIN to local SVR DB.
+ *
+ * @param[in] targetDeviceInfo Selected target device.
+ * @param[in] preconfPIN Preconfig PIN which is used while multiple owner authentication
+ * @param[in] preconfPINLen Byte length of preconfig PIN
+ *
+ * @return OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult OCAddPreconfigPIN(const OCProvisionDev_t *targetDeviceInfo,
+                                 const char* preconfPIN, size_t preconfPINLen)
+{
+    return MOTAddPreconfigPIN( targetDeviceInfo, preconfPIN, preconfPINLen);
+}
+
+
+OCStackResult OCDoMultipleOwnershipTransfer(void* ctx,
+                                      OCProvisionDev_t *targetDevices,
+                                      OCProvisionResultCB resultCallback)
+{
+    if( NULL == targetDevices )
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+    if (NULL == resultCallback)
+    {
+        OIC_LOG(INFO, TAG, "OCDoOwnershipTransfer : NULL Callback");
+        return OC_STACK_INVALID_CALLBACK;
+    }
+    return MOTDoOwnershipTransfer(ctx, targetDevices, resultCallback);
+}
+
+#endif //_ENABLE_MULTIPLE_OWNER_
+
 /**
  * API to register for particular OxM.
  *
@@ -251,6 +338,57 @@ OCStackResult OCProvisionDirectPairing(void* ctx, const OCProvisionDev_t *select
     return SRPProvisionDirectPairing(ctx, selectedDeviceInfo, pconf, resultCallback);
 }
 
+#ifdef _ENABLE_MULTIPLE_OWNER_
+static void AddPreconfPinOxMCB(void* ctx, int nOfRes, OCProvisionResult_t *arr, bool hasError)
+{
+    ProvPreconfPINCtx_t* provCtx = (ProvPreconfPINCtx_t*)ctx;
+    if(provCtx)
+    {
+        OCStackResult res = MOTProvisionPreconfigPIN(provCtx->ctx, provCtx->devInfo, provCtx->pin, provCtx->pinLen, provCtx->resultCallback);
+        if(OC_STACK_OK != res)
+        {
+            arr->res = res;
+            provCtx->resultCallback(provCtx->ctx, nOfRes, arr, true);
+        }
+    }
+}
+
+OCStackResult OCProvisionPreconfPin(void* ctx,
+                                               OCProvisionDev_t *targetDeviceInfo,
+                                               const char * preconfPin, size_t preconfPinLen,
+                                               OCProvisionResultCB resultCallback)
+{
+    if( NULL == targetDeviceInfo )
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+    if (NULL == resultCallback)
+    {
+        OIC_LOG(INFO, TAG, "OCProvisionPreconfPINCredential : NULL Callback");
+        return OC_STACK_INVALID_CALLBACK;
+    }
+
+    ProvPreconfPINCtx_t* provCtx = (ProvPreconfPINCtx_t*)OICCalloc(1, sizeof(ProvPreconfPINCtx_t));
+    if(NULL == provCtx)
+    {
+        return OC_STACK_NO_MEMORY;
+    }
+    provCtx->ctx = ctx;
+    provCtx->devInfo = targetDeviceInfo;
+    provCtx->pin = preconfPin;
+    provCtx->pinLen = preconfPinLen;
+    provCtx->resultCallback = resultCallback;
+    /*
+     * First of all, update OxMs to support preconfigured PIN OxM.
+     * In case of Preconfigured PIN OxM already supported on the server side,
+     * MOTAddMOTMethod API will be send POST Cred request.
+     * In case of Preconfigure PIN OxM not exist on the server side,
+     * the MOTAddMOTMethod API will be send POST doxm request to update OxMs and then send POST Cred request.
+     */
+    return MOTAddMOTMethod((void*)provCtx, targetDeviceInfo, OIC_PRECONFIG_PIN, AddPreconfPinOxMCB);
+}
+#endif //_ENABLE_MULTIPLE_OWNER_
+
 /*
 * Function to unlink devices.
 * This function will remove the credential & relationship between the two devices.
@@ -1044,6 +1182,39 @@ void OCDeletePdAclList(OicSecPdAcl_t* pPdAcl)
 {
     FreePdAclList(pPdAcl);
 }
+
+#ifdef _ENABLE_MULTIPLE_OWNER_
+/**
+ * API to update 'doxm.mom' to resource server.
+ *
+ * @param[in] targetDeviceInfo Selected target device.
+ * @param[in] momType Mode of multiple ownership transfer (ref. oic.sec.mom)
+ * @param[in] resultCallback callback provided by API user, callback will be called when
+ *            POST 'mom' request recieves a response from resource server.
+ * @return OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult OCChangeMOTMode(void *ctx, const OCProvisionDev_t *targetDeviceInfo,
+                            const OicSecMomType_t momType, OCProvisionResultCB resultCallback)
+{
+    return MOTChangeMode(ctx, targetDeviceInfo, momType, resultCallback);
+}
+
+/**
+ * API to update 'doxm.oxmsel' to resource server.
+ *
+ * @param[in] targetDeviceInfo Selected target device.
+  * @param[in] oxmSelValue Method of multiple ownership transfer (ref. oic.sec.oxm)
+ * @param[in] resultCallback callback provided by API user, callback will be called when
+ *            POST 'oxmsel' request recieves a response from resource server.
+ * @return OC_STACK_OK in case of success and other value otherwise.
+ */
+OCStackResult OCSelectMOTMethod(void *ctx, const OCProvisionDev_t *targetDeviceInfo,
+                                 const OicSecOxm_t oxmSelValue, OCProvisionResultCB resultCallback)
+{
+    return MOTSelectMOTMethod(ctx, targetDeviceInfo, oxmSelValue, resultCallback);
+}
+#endif //_ENABLE_MULTIPLE_OWNER_
+
 #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
 /**
  * function to provision Trust certificate chain to devices.
@@ -1063,6 +1234,7 @@ OCStackResult OCProvisionTrustCertChain(void *ctx, OicSecCredType_t type, uint16
     return SRPProvisionTrustCertChain(ctx, type, credId,
                                       selectedDeviceInfo, resultCallback);
 }
+
 /**
  * function to save Trust certificate chain into Cred of SVR.
  *
index 4a6eca9..977a732 100644 (file)
 #include "ownershiptransfermanager.h"
 #include "securevirtualresourcetypes.h"
 #include "oxmjustworks.h"
+#ifdef _ENABLE_MULTIPLE_OWNER_
+#include "oxmrandompin.h"
+#include "oxmpreconfpin.h"
+#endif //_ENABLE_MULTIPLE_OWNER_
 #include "pmtypes.h"
 #include "pmutility.h"
 #include "srmutility.h"
 /**
  * Array to store the callbacks for each owner transfer method.
  */
-static OTMCallbackData_t g_OTMDatas[OIC_OXM_COUNT];
+static OTMCallbackData_t g_OTMCbDatas[OIC_OXM_COUNT] = {
+        //Just works
+        {.loadSecretCB = LoadSecretJustWorksCallback,
+          .createSecureSessionCB = CreateSecureSessionJustWorksCallback,
+          .createSelectOxmPayloadCB = CreateJustWorksSelectOxmPayload,
+          .createOwnerTransferPayloadCB = CreateJustWorksOwnerTransferPayload},
+
+          //Random PIN
+        {.loadSecretCB = InputPinCodeCallback,
+          .createSecureSessionCB = CreateSecureSessionRandomPinCallback,
+          .createSelectOxmPayloadCB = CreatePinBasedSelectOxmPayload,
+          .createOwnerTransferPayloadCB = CreatePinBasedOwnerTransferPayload},
+
+        //Manufacturer Cert
+        {.loadSecretCB = NULL,
+          .createSecureSessionCB = NULL,
+          .createSelectOxmPayloadCB = NULL,
+          .createOwnerTransferPayloadCB = NULL},
+
+#ifdef _ENABLE_MULTIPLE_OWNER_
+          //Preconfig PIN
+        {.loadSecretCB = LoadPreconfPinCodeCallback,
+          .createSecureSessionCB = CreateSecureSessionPreconfPinCallback,
+          .createSelectOxmPayloadCB = CreatePreconfPinBasedSelectOxmPayload,
+          .createOwnerTransferPayloadCB = CreatePreconfPinBasedOwnerTransferPayload},
+#endif //_ENABLE_MULTIPLE_OWNER_
+};
 
 /**
  * Variables for pointing the OTMContext to be used in the DTLS handshake result callback.
@@ -109,6 +139,17 @@ static OCStackResult SelectProvisioningMethod(const OicSecOxm_t *supportedMethod
         }
     }
 
+    if(NULL == g_OTMCbDatas[(*selectedMethod)].loadSecretCB ||
+       NULL == g_OTMCbDatas[(*selectedMethod)].createSecureSessionCB ||
+       NULL == g_OTMCbDatas[(*selectedMethod)].createSelectOxmPayloadCB ||
+       NULL == g_OTMCbDatas[(*selectedMethod)].createOwnerTransferPayloadCB)
+    {
+        OIC_LOG_V(ERROR, TAG, "Please make sure the OxM(%d)'s callback registration", (int)(*selectedMethod));
+        return OC_STACK_INVALID_CALLBACK;
+    }
+
+    OIC_LOG(DEBUG, TAG, "OUT SelectProvisioningMethod");
+
     return OC_STACK_OK;
 }
 
@@ -258,7 +299,7 @@ static void SetResult(OTMContext_t* otmCtx, const OCStackResult res)
                 OIC_LOG(WARNING, TAG, "Failed to revert  is DTLS credential handler.");
             }
             OicUuid_t emptyUuid = { .id={0}};
-            SetUuidForRandomPinOxm(&emptyUuid);
+            SetUuidForPinBasedOxm(&emptyUuid);
         }
 
         for(size_t i = 0; i < otmCtx->ctxResultArraySize; i++)
@@ -390,7 +431,7 @@ void DTLSHandshakeCB(const CAEndpoint_t *endpoint, const CAErrorInfo_t *info)
 }
 
 /**
- * Function to save ownerPSK at provisioning tool end.
+ * Function to save the Owner/SubOwner PSK.
  *
  * @param[in] selectedDeviceInfo   selected device information to performing provisioning.
  * @return  OC_STACK_OK on success
@@ -408,10 +449,10 @@ static OCStackResult SaveOwnerPSK(OCProvisionDev_t *selectedDeviceInfo)
     endpoint.port = selectedDeviceInfo->securePort;
     endpoint.adapter = selectedDeviceInfo->endpoint.adapter;
 
-    OicUuid_t ptDeviceID = {.id={0}};
-    if (OC_STACK_OK != GetDoxmDeviceID(&ptDeviceID))
+    OicUuid_t ownerDeviceID = {.id={0}};
+    if (OC_STACK_OK != GetDoxmDeviceID(&ownerDeviceID))
     {
-        OIC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
+        OIC_LOG(ERROR, TAG, "Error while retrieving Owner's device ID");
         return res;
     }
 
@@ -422,18 +463,18 @@ static OCStackResult SaveOwnerPSK(OCProvisionDev_t *selectedDeviceInfo)
     CAResult_t pskRet = CAGenerateOwnerPSK(&endpoint,
             (uint8_t *)GetOxmString(selectedDeviceInfo->doxm->oxmSel),
             strlen(GetOxmString(selectedDeviceInfo->doxm->oxmSel)),
-            ptDeviceID.id, sizeof(ptDeviceID.id),
+            ownerDeviceID.id, sizeof(ownerDeviceID.id),
             selectedDeviceInfo->doxm->deviceID.id, sizeof(selectedDeviceInfo->doxm->deviceID.id),
             ownerPSK, OWNER_PSK_LENGTH_128);
 
     if (CA_STATUS_OK == pskRet)
     {
-        OIC_LOG(INFO, TAG,"ownerPSK dump:\n");
+        OIC_LOG(INFO, TAG,"Owner PSK dump:\n");
         OIC_LOG_BUFFER(INFO, TAG,ownerPSK, OWNER_PSK_LENGTH_128);
         //Generating new credential for provisioning tool
         OicSecCred_t *cred = GenerateCredential(&selectedDeviceInfo->doxm->deviceID,
-                SYMMETRIC_PAIR_WISE_KEY, NULL,
-                &ownerKey, &ptDeviceID);
+                                  SYMMETRIC_PAIR_WISE_KEY, NULL,
+                                  &ownerKey, &ownerDeviceID, NULL);
         VERIFY_NON_NULL(TAG, cred, ERROR);
 
         // TODO: Added as workaround. Will be replaced soon.
@@ -708,11 +749,12 @@ static OCStackApplicationResult OperationModeUpdateHandler(void *ctx, OCDoHandle
     {
         OCStackResult res = OC_STACK_ERROR;
         OicSecOxm_t selOxm = otmCtx->selectedDeviceInfo->doxm->oxmSel;
+
         //DTLS Handshake
         //Load secret for temporal secure session.
-        if(g_OTMDatas[selOxm].loadSecretCB)
+        if(g_OTMCbDatas[selOxm].loadSecretCB)
         {
-            res = g_OTMDatas[selOxm].loadSecretCB(otmCtx);
+            res = g_OTMCbDatas[selOxm].loadSecretCB(otmCtx);
             if(OC_STACK_OK != res)
             {
                 OIC_LOG(ERROR, TAG, "OperationModeUpdate : Failed to load secret");
@@ -725,9 +767,9 @@ static OCStackApplicationResult OperationModeUpdateHandler(void *ctx, OCDoHandle
         g_otmCtx = otmCtx;
 
         //Try DTLS handshake to generate secure session
-        if(g_OTMDatas[selOxm].createSecureSessionCB)
+        if(g_OTMCbDatas[selOxm].createSecureSessionCB)
         {
-            res = g_OTMDatas[selOxm].createSecureSessionCB(otmCtx);
+            res = g_OTMCbDatas[selOxm].createSecureSessionCB(otmCtx);
             if(OC_STACK_OK != res)
             {
                 OIC_LOG(ERROR, TAG, "OperationModeUpdate : Failed to create DTLS session");
@@ -806,7 +848,7 @@ static OCStackApplicationResult OwnerCredentialHandler(void *ctx, OCDoHandle UNU
             if(OIC_RANDOM_DEVICE_PIN == otmCtx->selectedDeviceInfo->doxm->oxmSel)
             {
                 OicUuid_t emptyUuid = { .id={0}};
-                SetUuidForRandomPinOxm(&emptyUuid);
+                SetUuidForPinBasedOxm(&emptyUuid);
 
                 caResult = CAregisterPskCredentialsHandler(GetDtlsPskCredentials);
 
@@ -1200,9 +1242,6 @@ error:
 static OCStackResult PostOwnerAcl(OTMContext_t* otmCtx)
 {
     OCStackResult res = OC_STACK_ERROR;
-    OCProvisionDev_t* deviceInfo = otmCtx->selectedDeviceInfo;
-    char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
-    OicSecAcl_t* ownerAcl = NULL;
 
     OIC_LOG(DEBUG, TAG, "IN PostOwnerAcl");
 
@@ -1212,6 +1251,10 @@ static OCStackResult PostOwnerAcl(OTMContext_t* otmCtx)
         return OC_STACK_INVALID_PARAM;
     }
 
+    OCProvisionDev_t* deviceInfo = otmCtx->selectedDeviceInfo;
+    char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
+    OicSecAcl_t* ownerAcl = NULL;
+
     if(!PMGenerateQuery(true,
                         deviceInfo->endpoint.addr, deviceInfo->securePort,
                         deviceInfo->connType,
@@ -1311,7 +1354,7 @@ static OCStackResult PostOwnerTransferModeToResource(OTMContext_t* otmCtx)
         return OC_STACK_NO_MEMORY;
     }
     secPayload->base.type = PAYLOAD_TYPE_SECURITY;
-    OCStackResult res = g_OTMDatas[selectedOxm].createSelectOxmPayloadCB(otmCtx,
+    OCStackResult res = g_OTMCbDatas[selectedOxm].createSelectOxmPayloadCB(otmCtx,
             &secPayload->securityData, &secPayload->payloadSize);
     if (OC_STACK_OK != res && NULL == secPayload->securityData)
     {
@@ -1405,7 +1448,7 @@ static OCStackResult PostOwnerUuid(OTMContext_t* otmCtx)
         return OC_STACK_NO_MEMORY;
     }
     secPayload->base.type = PAYLOAD_TYPE_SECURITY;
-    OCStackResult res =  g_OTMDatas[deviceInfo->doxm->oxmSel].createOwnerTransferPayloadCB(
+    OCStackResult res =  g_OTMCbDatas[deviceInfo->doxm->oxmSel].createOwnerTransferPayloadCB(
             otmCtx, &secPayload->securityData, &secPayload->payloadSize);
     if (OC_STACK_OK != res && NULL == secPayload->securityData)
     {
@@ -1547,13 +1590,18 @@ static OCStackResult PostUpdateOperationMode(OTMContext_t* otmCtx)
 static OCStackResult StartOwnershipTransfer(void* ctx, OCProvisionDev_t* selectedDevice)
 {
     OIC_LOG(INFO, TAG, "IN StartOwnershipTransfer");
+    OCStackResult res = OC_STACK_INVALID_PARAM;
+
+    VERIFY_NON_NULL(TAG, selectedDevice, ERROR);
+    VERIFY_NON_NULL(TAG, selectedDevice->doxm, ERROR);
+
     OTMContext_t* otmCtx = (OTMContext_t*)ctx;
     otmCtx->selectedDeviceInfo = selectedDevice;
 
     //Set to the lowest level OxM, and then find more higher level OxM.
-    OCStackResult res = SelectProvisioningMethod(selectedDevice->doxm->oxm,
-                                                 selectedDevice->doxm->oxmLen,
-                                                 &selectedDevice->doxm->oxmSel);
+    res = SelectProvisioningMethod(selectedDevice->doxm->oxm,
+                                   selectedDevice->doxm->oxmLen,
+                                   &selectedDevice->doxm->oxmSel);
     if(OC_STACK_OK != res)
     {
         OIC_LOG(ERROR, TAG, "Failed to select the provisioning method");
@@ -1562,7 +1610,7 @@ static OCStackResult StartOwnershipTransfer(void* ctx, OCProvisionDev_t* selecte
     }
     OIC_LOG_V(DEBUG, TAG, "Selected provisoning method = %d", selectedDevice->doxm->oxmSel);
 
-    //Send Req: POST /oic/sec/doxm [{..."OxmSel" :g_OTMDatas[Index of Selected OxM].OXMString,...}]
+    //Send Req: POST /oic/sec/doxm [{..."OxmSel" :g_OTMCbDatas[Index of Selected OxM].OXMString,...}]
     res = PostOwnerTransferModeToResource(otmCtx);
     if(OC_STACK_OK != res)
     {
@@ -1580,8 +1628,8 @@ static OCStackResult StartOwnershipTransfer(void* ctx, OCProvisionDev_t* selecte
 #endif // __WITH_DTLS__ or __WITH_TLS__
     OIC_LOG(INFO, TAG, "OUT StartOwnershipTransfer");
 
+exit:
     return res;
-
 }
 
 OCStackResult OTMSetOwnershipTransferCallbackData(OicSecOxm_t oxmType, OTMCallbackData_t* data)
@@ -1599,10 +1647,10 @@ OCStackResult OTMSetOwnershipTransferCallbackData(OicSecOxm_t oxmType, OTMCallba
         return OC_STACK_INVALID_PARAM;
     }
 
-    g_OTMDatas[oxmType].loadSecretCB= data->loadSecretCB;
-    g_OTMDatas[oxmType].createSecureSessionCB = data->createSecureSessionCB;
-    g_OTMDatas[oxmType].createSelectOxmPayloadCB = data->createSelectOxmPayloadCB;
-    g_OTMDatas[oxmType].createOwnerTransferPayloadCB = data->createOwnerTransferPayloadCB;
+    g_OTMCbDatas[oxmType].loadSecretCB= data->loadSecretCB;
+    g_OTMCbDatas[oxmType].createSecureSessionCB = data->createSecureSessionCB;
+    g_OTMCbDatas[oxmType].createSelectOxmPayloadCB = data->createSelectOxmPayloadCB;
+    g_OTMCbDatas[oxmType].createOwnerTransferPayloadCB = data->createOwnerTransferPayloadCB;
 
     OIC_LOG(DEBUG, TAG, "OUT OTMSetOwnerTransferCallbackData");
 
diff --git a/resource/csdk/security/provisioning/src/oxmpreconfpin.c b/resource/csdk/security/provisioning/src/oxmpreconfpin.c
new file mode 100644 (file)
index 0000000..7083834
--- /dev/null
@@ -0,0 +1,215 @@
+/* *****************************************************************
+ *
+ * Copyright 2016 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 <memory.h>
+
+#include "ocstack.h"
+#include "securevirtualresourcetypes.h"
+#include "doxmresource.h"
+#include "credresource.h"
+#include "cacommon.h"
+#include "cainterface.h"
+#include "ocrandom.h"
+#include "oic_malloc.h"
+#include "logger.h"
+#include "pbkdf2.h"
+#include "global.h"
+#include "base64.h"
+#include "oxmpreconfpin.h"
+#include "ownershiptransfermanager.h"
+#include "pinoxmcommon.h"
+#include "srmresourcestrings.h"
+
+#define TAG "OXM_PreconfigPIN"
+
+OCStackResult CreatePreconfPinBasedSelectOxmPayload(OTMContext_t* otmCtx, uint8_t **payload, size_t *size)
+{
+    if(!otmCtx || !otmCtx->selectedDeviceInfo || !payload || *payload || !size)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    otmCtx->selectedDeviceInfo->doxm->oxmSel = OIC_PRECONFIG_PIN;
+
+    return DoxmToCBORPayload(otmCtx->selectedDeviceInfo->doxm, payload, size, true);
+}
+
+OCStackResult CreatePreconfPinBasedOwnerTransferPayload(OTMContext_t* otmCtx, uint8_t **payload, size_t *size)
+{
+    if(!otmCtx || !otmCtx->selectedDeviceInfo || !payload || *payload || !size)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    OicUuid_t uuidPT = {.id={0}};
+    *payload = NULL;
+    *size = 0;
+
+    if (OC_STACK_OK != GetDoxmDeviceID(&uuidPT))
+    {
+        OIC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
+        return OC_STACK_ERROR;
+    }
+    memcpy(otmCtx->selectedDeviceInfo->doxm->owner.id, uuidPT.id , UUID_LENGTH);
+
+    return DoxmToCBORPayload(otmCtx->selectedDeviceInfo->doxm, payload, size, true);
+}
+
+OCStackResult LoadPreconfPinCodeCallback(OTMContext_t *otmCtx)
+{
+    OIC_LOG(INFO, TAG, "IN LoadPreconfPinCodeCallback");
+    OCStackResult res = OC_STACK_ERROR;
+    OicSecCred_t* cred = GetCredResourceData(&otmCtx->selectedDeviceInfo->doxm->deviceID);
+    if(NULL == cred)
+    {
+        OicUuid_t uuid = {.id={0}};
+        OICStrcpy(uuid.id, sizeof(uuid.id), WILDCARD_SUBJECT_ID.id);
+        cred = GetCredResourceData(&uuid);
+        if(NULL == cred)
+        {
+            OIC_LOG(ERROR, TAG, "Can not find the Credential for MOT");
+            OIC_LOG(ERROR, TAG, "Please make sure the preconfigured PIN");
+            return OC_STACK_ERROR;
+        }
+    }
+
+    uint8_t* pinBuffer = NULL;
+    size_t pinBufLen = 0;
+    if(OIC_ENCODING_BASE64 == cred->privateData.encoding)
+    {
+        //In case of 'preconfig PIN', secret data(PIN) already exist.
+        pinBufLen = B64DECODE_OUT_SAFESIZE(cred->privateData.len + 1);
+        pinBuffer = (uint8_t*)OICCalloc(1, pinBufLen);
+        if(NULL == pinBuffer)
+        {
+            OIC_LOG(ERROR, TAG, "Failed to memory allocation.");
+            return OC_STACK_NO_MEMORY;
+        }
+        uint32_t pinLen = 0;
+        if(B64_OK != b64Decode(cred->privateData.data, cred->privateData.len, pinBuffer, pinBufLen, &pinLen))
+        {
+            OIC_LOG(ERROR, TAG, "Failed to base64 deconding for preconfig PIN");
+            OICFree(pinBuffer);
+            return OC_STACK_ERROR;
+        }
+        pinBufLen = pinLen;
+    }
+    else if(OIC_ENCODING_RAW == cred->privateData.encoding)
+    {
+        pinBuffer = (uint8_t*)OICMalloc(cred->privateData.len + 1);
+        if(NULL == pinBuffer)
+        {
+            OIC_LOG(ERROR, TAG, "Failed to memory allocation.");
+            return OC_STACK_NO_MEMORY;
+        }
+        memcpy(pinBuffer, cred->privateData.data, cred->privateData.len);
+        pinBuffer[cred->privateData.len] = '\0';
+        pinBufLen = cred->privateData.len;
+    }
+    else
+    {
+        OIC_LOG(ERROR, TAG, "Unknown encoding type for PreConfigured PIN credential");
+        return OC_STACK_ERROR;
+    }
+
+    res = SetPreconfigPin((char*)pinBuffer, pinBufLen);
+    OICFree(pinBuffer);
+    if(OC_STACK_OK != res)
+    {
+        OIC_LOG_V(ERROR, TAG, "Failed to save the preconfig PIN : %d", res);
+        return res;
+    }
+
+    //in case of OTM
+    if(false == otmCtx->selectedDeviceInfo->doxm->owned)
+    {
+        if(CA_STATUS_OK != CAregisterPskCredentialsHandler(GetDtlsPskForPreconfPinOxm))
+        {
+            OIC_LOG(ERROR, TAG, "Failed to register DTLS credentials handler for random PIN OxM.");
+            res = OC_STACK_ERROR;
+        }
+    }
+#ifdef _ENABLE_MULTIPLE_OWNER_
+    //in case of MOT
+    else if(true == otmCtx->selectedDeviceInfo->doxm->owned &&
+            otmCtx->selectedDeviceInfo->doxm->mom &&
+            OIC_MULTIPLE_OWNER_DISABLE != otmCtx->selectedDeviceInfo->doxm->mom->mode)
+    {
+        if(CA_STATUS_OK != CAregisterPskCredentialsHandler(GetDtlsPskForMotPreconfPinOxm))
+        {
+            OIC_LOG(ERROR, TAG, "Failed to register DTLS credentials handler for random PIN OxM.");
+            res = OC_STACK_ERROR;
+        }
+    }
+#endif //_ENABLE_MULTIPLE_OWNER_
+
+    //Set the device id to derive temporal PSK
+    SetUuidForPinBasedOxm(&(otmCtx->selectedDeviceInfo->doxm->deviceID));
+
+    OIC_LOG(INFO, TAG, "OUT LoadPreconfPinCodeCallback");
+
+    return res;
+}
+
+OCStackResult CreateSecureSessionPreconfPinCallback(OTMContext_t* otmCtx)
+{
+    OIC_LOG(INFO, TAG, "IN CreateSecureSessionPreconfPinCallback");
+
+    if (!otmCtx || !otmCtx->selectedDeviceInfo)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    CAResult_t caresult = CAEnableAnonECDHCipherSuite(false);
+    if (CA_STATUS_OK != caresult)
+    {
+        OIC_LOG_V(ERROR, TAG, "Unable to disable anon cipher suite");
+        return OC_STACK_ERROR;
+    }
+    OIC_LOG(INFO, TAG, "Anonymous cipher suite disabled.");
+
+    caresult  = CASelectCipherSuite(TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256, otmCtx->selectedDeviceInfo->endpoint.adapter);
+    if (CA_STATUS_OK != caresult)
+    {
+        OIC_LOG_V(ERROR, TAG, "Failed to select TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256");
+        return OC_STACK_ERROR;
+    }
+    OIC_LOG(INFO, TAG, "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256 cipher suite selected.");
+
+    OCProvisionDev_t* selDevInfo = otmCtx->selectedDeviceInfo;
+    CAEndpoint_t *endpoint = (CAEndpoint_t *)OICCalloc(1, sizeof (CAEndpoint_t));
+    if (NULL == endpoint)
+    {
+        return OC_STACK_NO_MEMORY;
+    }
+    memcpy(endpoint,&selDevInfo->endpoint,sizeof(CAEndpoint_t));
+    endpoint->port = selDevInfo->securePort;
+    caresult = CAInitiateHandshake(endpoint);
+    OICFree(endpoint);
+    if (CA_STATUS_OK != caresult)
+    {
+        OIC_LOG_V(ERROR, TAG, "DTLS handshake failure.");
+        return OC_STACK_ERROR;
+    }
+
+    OIC_LOG(INFO, TAG, "OUT CreateSecureSessionPreconfPinCallback");
+
+    return OC_STACK_OK;
+}
index 0faa8e7..48afcf2 100644 (file)
@@ -92,15 +92,31 @@ OCStackResult InputPinCodeCallback(OTMContext_t *otmCtx)
      * Credential should not be saved into SVR.
      * For this reason, We will use a temporary get_psk_info callback to random PIN OxM.
      */
-
-    if(CA_STATUS_OK != CAregisterPskCredentialsHandler(GetDtlsPskForRandomPinOxm))
+    //in case of OTM
+    if(!(otmCtx->selectedDeviceInfo->doxm->owned))
+    {
+        if(CA_STATUS_OK != CAregisterPskCredentialsHandler(GetDtlsPskForRandomPinOxm))
+        {
+            OIC_LOG(ERROR, TAG, "Failed to register DTLS credentials handler for random PIN OxM.");
+            res = OC_STACK_ERROR;
+        }
+    }
+#ifdef _ENABLE_MULTIPLE_OWNER_
+    //in case of MOT
+    else if(otmCtx->selectedDeviceInfo->doxm->owned &&
+            otmCtx->selectedDeviceInfo->doxm->mom &&
+            OIC_MULTIPLE_OWNER_DISABLE != otmCtx->selectedDeviceInfo->doxm->mom->mode)
     {
-        OIC_LOG(ERROR, TAG, "Failed to register TLS credentials handler for random PIN OxM.");
-        res = OC_STACK_ERROR;
+        if(CA_STATUS_OK != CAregisterPskCredentialsHandler(GetDtlsPskForMotRandomPinOxm))
+        {
+            OIC_LOG(ERROR, TAG, "Failed to register TLS credentials handler for random PIN OxM.");
+            res = OC_STACK_ERROR;
+        }
     }
+#endif //_ENABLE_MULTIPLE_OWNER_
 
     //Set the device id to derive temporal PSK
-    SetUuidForRandomPinOxm(&(otmCtx->selectedDeviceInfo->doxm->deviceID));
+    SetUuidForPinBasedOxm(&(otmCtx->selectedDeviceInfo->doxm->deviceID));
 
     return res;
 }
old mode 100755 (executable)
new mode 100644 (file)
index b8c053c..101b214
@@ -960,6 +960,240 @@ OCStackResult PMDeviceDiscovery(unsigned short waittime, bool isOwned, OCProvisi
     return res;
 }
 
+#ifdef _ENABLE_MULTIPLE_OWNER_
+static OCStackApplicationResult MOTDeviceDiscoveryHandler(void *ctx, OCDoHandle UNUSED,
+                                OCClientResponse *clientResponse)
+{
+    if (ctx == NULL)
+    {
+        OIC_LOG(ERROR, TAG, "Lost List of device information");
+        return OC_STACK_KEEP_TRANSACTION;
+    }
+    (void)UNUSED;
+    if (clientResponse)
+    {
+        if  (NULL == clientResponse->payload)
+        {
+            OIC_LOG(INFO, TAG, "Skipping Null payload");
+            return OC_STACK_KEEP_TRANSACTION;
+        }
+        if (OC_STACK_OK != clientResponse->result)
+        {
+            OIC_LOG(INFO, TAG, "Error in response");
+            return OC_STACK_KEEP_TRANSACTION;
+        }
+        else
+        {
+            if (PAYLOAD_TYPE_SECURITY != clientResponse->payload->type)
+            {
+                OIC_LOG(INFO, TAG, "Unknown payload type");
+                return OC_STACK_KEEP_TRANSACTION;
+            }
+
+            OicSecDoxm_t *ptrDoxm = NULL;
+            uint8_t *payload = ((OCSecurityPayload*)clientResponse->payload)->securityData;
+            size_t size = ((OCSecurityPayload*)clientResponse->payload)->payloadSize;
+
+            OCStackResult res = CBORPayloadToDoxm(payload, size, &ptrDoxm);
+            if ((NULL == ptrDoxm) || (OC_STACK_OK != res))
+            {
+                OIC_LOG(INFO, TAG, "Ignoring malformed CBOR");
+                return OC_STACK_KEEP_TRANSACTION;
+            }
+            else
+            {
+                OIC_LOG(DEBUG, TAG, "Successfully converted doxm cbor to bin.");
+
+                //If this is owend device discovery we have to filter out the responses.
+                DiscoveryInfo* pDInfo = (DiscoveryInfo*)ctx;
+                OCProvisionDev_t **ppDevicesList = pDInfo->ppDevicesList;
+
+                // Get my device ID from doxm resource
+                OicUuid_t myId;
+                memset(&myId, 0, sizeof(myId));
+                OCStackResult res = GetDoxmDevOwnerId(&myId);
+                if(OC_STACK_OK != res)
+                {
+                    OIC_LOG(ERROR, TAG, "Error while getting my device ID.");
+                    DeleteDoxmBinData(ptrDoxm);
+                    return OC_STACK_KEEP_TRANSACTION;
+                }
+
+                res = GetDoxmDeviceID(&myId);
+                if(OC_STACK_OK != res)
+                {
+                    OIC_LOG(ERROR, TAG, "Error while getting my UUID.");
+                    DeleteDoxmBinData(ptrDoxm);
+                    return OC_STACK_KEEP_TRANSACTION;
+                }
+                //if this is owned discovery and this is PT's reply, discard it
+                if((pDInfo->isOwnedDiscovery) &&
+                        (0 == memcmp(&ptrDoxm->deviceID.id, &myId.id, sizeof(myId.id))) )
+                {
+                    OIC_LOG(DEBUG, TAG, "discarding provision tool's reply");
+                    DeleteDoxmBinData(ptrDoxm);
+                    return OC_STACK_KEEP_TRANSACTION;
+                }
+
+                if(pDInfo->isOwnedDiscovery)
+                {
+                    OicSecSubOwner_t* subOwner = NULL;
+                    LL_FOREACH(ptrDoxm->subOwners, subOwner)
+                    {
+                        if(memcmp(myId.id, subOwner->uuid.id, sizeof(myId.id)) == 0)
+                        {
+                            break;
+                        }
+                    }
+
+                    if(subOwner)
+                    {
+                        res = AddDevice(ppDevicesList, &clientResponse->devAddr,
+                                clientResponse->connType, ptrDoxm);
+                        if (OC_STACK_OK != res)
+                        {
+                            OIC_LOG(ERROR, TAG, "Error while adding data to linkedlist.");
+                            DeleteDoxmBinData(ptrDoxm);
+                            return OC_STACK_KEEP_TRANSACTION;
+                        }
+
+                        res = SecurePortDiscovery(pDInfo, clientResponse);
+                        if(OC_STACK_OK != res)
+                        {
+                            OIC_LOG(ERROR, TAG, "Failed to SecurePortDiscovery");
+                            DeleteDoxmBinData(ptrDoxm);
+                            return OC_STACK_KEEP_TRANSACTION;
+                        }
+                    }
+                    else
+                    {
+                        OIC_LOG(ERROR, TAG, "discarding device's reply, because not a SubOwner.");
+                        DeleteDoxmBinData(ptrDoxm);
+                        return OC_STACK_KEEP_TRANSACTION;
+                    }
+                }
+                else
+                {
+                    if(ptrDoxm->mom && OIC_MULTIPLE_OWNER_DISABLE != ptrDoxm->mom->mode)
+                    {
+                        res = AddDevice(ppDevicesList, &clientResponse->devAddr,
+                                clientResponse->connType, ptrDoxm);
+                        if (OC_STACK_OK != res)
+                        {
+                            OIC_LOG(ERROR, TAG, "Error while adding data to linkedlist.");
+                            DeleteDoxmBinData(ptrDoxm);
+                            return OC_STACK_KEEP_TRANSACTION;
+                        }
+
+                        res = SecurePortDiscovery(pDInfo, clientResponse);
+                        if(OC_STACK_OK != res)
+                        {
+                            OIC_LOG(ERROR, TAG, "Failed to SecurePortDiscovery");
+                            DeleteDoxmBinData(ptrDoxm);
+                            return OC_STACK_KEEP_TRANSACTION;
+                        }
+                    }
+                    else
+                    {
+                        OIC_LOG(ERROR, TAG, "discarding mom disabled device's reply");
+                        DeleteDoxmBinData(ptrDoxm);
+                        return OC_STACK_KEEP_TRANSACTION;
+                    }
+                }
+
+                OIC_LOG(INFO, TAG, "Exiting ProvisionDiscoveryHandler.");
+            }
+
+            return  OC_STACK_KEEP_TRANSACTION;
+        }
+    }
+    else
+    {
+        OIC_LOG(INFO, TAG, "Skiping Null response");
+        return OC_STACK_KEEP_TRANSACTION;
+    }
+
+    return  OC_STACK_DELETE_TRANSACTION;
+}
+
+
+/**
+ * Discover multiple OTM enabled devices in the same IP subnet.
+ *
+ * @param[in] waittime      Timeout in seconds.
+ * @param[in] ppDevicesList        List of OCProvisionDev_t.
+ *
+ * @return OC_STACK_OK on success otherwise error.
+ */
+OCStackResult PMMultipleOwnerDeviceDiscovery(unsigned short waittime, bool isMultipleOwned, OCProvisionDev_t **ppDevicesList)
+{
+    OIC_LOG(DEBUG, TAG, "IN PMMultipleOwnerEnabledDeviceDiscovery");
+
+    if (NULL != *ppDevicesList)
+    {
+        OIC_LOG(ERROR, TAG, "List is not null can cause memory leak");
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    const char *DOXM_MOM_ENABLE_MULTICAST_QUERY = "/oic/sec/doxm?mom!=0&owned=TRUE";
+    const char *DOXM_MULTIPLE_OWNED_MULTICAST_QUERY = "/oic/sec/doxm?owned=TRUE";
+
+    DiscoveryInfo *pDInfo = OICCalloc(1, sizeof(DiscoveryInfo));
+    if(NULL == pDInfo)
+    {
+        OIC_LOG(ERROR, TAG, "PMDeviceDiscovery : Memory allocation failed.");
+        return OC_STACK_NO_MEMORY;
+    }
+
+    pDInfo->ppDevicesList = ppDevicesList;
+    pDInfo->isOwnedDiscovery = isMultipleOwned;
+
+    OCCallbackData cbData;
+    cbData.cb = &MOTDeviceDiscoveryHandler;
+    cbData.context = (void *)pDInfo;
+    cbData.cd = NULL;
+    OCStackResult res = OC_STACK_ERROR;
+
+    const char* query = isMultipleOwned ? DOXM_MULTIPLE_OWNED_MULTICAST_QUERY :
+                                          DOXM_MOM_ENABLE_MULTICAST_QUERY;
+
+    OCDoHandle handle = NULL;
+    res = OCDoResource(&handle, OC_REST_DISCOVER, query, 0, 0,
+                                     CT_DEFAULT, OC_HIGH_QOS, &cbData, NULL, 0);
+    if (res != OC_STACK_OK)
+    {
+        OIC_LOG(ERROR, TAG, "OCStack resource error");
+        OICFree(pDInfo);
+        return res;
+    }
+
+    //Waiting for each response.
+    res = PMTimeout(waittime, true);
+    if(OC_STACK_OK != res)
+    {
+        OIC_LOG(ERROR, TAG, "Failed to wait response for secure discovery.");
+        OICFree(pDInfo);
+        OCStackResult resCancel = OCCancel(handle, OC_HIGH_QOS, NULL, 0);
+        if(OC_STACK_OK !=  resCancel)
+        {
+            OIC_LOG(ERROR, TAG, "Failed to remove registered callback");
+        }
+        return res;
+    }
+    res = OCCancel(handle,OC_HIGH_QOS,NULL,0);
+    if (OC_STACK_OK != res)
+    {
+        OIC_LOG(ERROR, TAG, "Failed to remove registered callback");
+        OICFree(pDInfo);
+        return res;
+    }
+    OIC_LOG(DEBUG, TAG, "OUT PMMultipleOwnerEnabledDeviceDiscovery");
+    OICFree(pDInfo);
+    return res;
+}
+
+#endif //_ENABLE_MULTIPLE_OWNER_
+
 static OCStackResult SecurePortDiscovery(DiscoveryInfo* discoveryInfo,
                                          const OCClientResponse *clientResponse)
 {
index 602c93a..e8dc524 100644 (file)
@@ -75,6 +75,9 @@ if sptest_env.get('SECURED') == '1':
 if not sptest_env.get('RELEASE'):
        sptest_env.AppendUnique(CPPDEFINES = ['TB_LOG'])
 
+if sptest_env.get('MULTIPLE_OWNER') == '1':
+       sptest_env.AppendUnique(CPPDEFINES=['_ENABLE_MULTIPLE_OWNER_'])
+
 if target_os in ['msys_nt', 'windows']:
     sptest_env.AppendUnique(LINKFLAGS = ['/subsystem:CONSOLE'])
     sptest_env.AppendUnique(LIBS = ['ws2_32',
old mode 100755 (executable)
new mode 100644 (file)
index 8040646..78ba0e0
@@ -31,6 +31,9 @@
 #include "oxmrandompin.h"
 #include "securevirtualresourcetypes.h"
 #include "provisioningdatabasemanager.h"
+#ifdef _ENABLE_MULTIPLE_OWNER_
+#include "multipleownershiptransfermanager.h"
+#endif //_ENABLE_MULTIPLE_OWNER_
 #include "srmutility.h"
 #include "doxmresource.h"
 #include "pmtypes.h"
@@ -202,6 +205,10 @@ static pid_t g_myPID2;
 static const char* g_otmCtx = "Test User Context";
 static OCProvisionDev_t* g_unownedDevices = NULL;
 static OCProvisionDev_t* g_ownedDevices = NULL;
+#ifdef _ENABLE_MULTIPLE_OWNER_
+static OCProvisionDev_t* g_motEnabledDevices = NULL;
+static OCProvisionDev_t* g_multiplOwnedDevices = NULL;
+#endif //_ENABLE_MULTIPLE_OWNER_
 
 static void GetCurrentWorkingDirectory(char* buf, size_t bufsize)
 {
@@ -261,6 +268,35 @@ static void ownershipTransferCB(void* ctx, int UNUSED1, OCProvisionResult_t* UNU
     g_doneCB = true;
 }
 
+#ifdef _ENABLE_MULTIPLE_OWNER_
+static void updateDoxmForMOTCB(void* ctx, int nOfRes, OCProvisionResult_t* arr, bool hasError)
+{
+    if(!hasError)
+    {
+        OIC_LOG_V(INFO, TAG, "POST 'doxm' SUCCEEDED - ctx: %s", (char*) ctx);
+    }
+    else
+    {
+        OIC_LOG_V(ERROR, TAG, "POST 'doxm'  FAILED - ctx: %s", (char*) ctx);
+    }
+    g_callbackResult = !hasError;
+    g_doneCB = true;
+}
+
+static void provisionPreconfiguredPinCB(void* ctx, int nOfRes, OCProvisionResult_t* arr, bool hasError)
+{
+    if(!hasError)
+    {
+        OIC_LOG_V(INFO, TAG, "Provision Preconfigured-PIN SUCCEEDED - ctx: %s", (char*) ctx);
+    }
+    else
+    {
+        OIC_LOG_V(ERROR, TAG, "Provision Preconfigured-PIN FAILED - ctx: %s", (char*) ctx);
+    }
+    g_callbackResult = !hasError;
+    g_doneCB = true;
+}
+#endif //_ENABLE_MULTIPLE_OWNER_
 
 // callback function(s) for provisioning client using C-level provisioning API
 static void removeDeviceCB(void* ctx, int UNUSED1, OCProvisionResult_t* UNUSED2, bool hasError)
@@ -575,6 +611,121 @@ TEST(PerformUnlinkDevices, NullParam)
     EXPECT_EQ(OC_STACK_OK, result);
 }
 
+#ifdef _ENABLE_MULTIPLE_OWNER_
+TEST(RegisterPreconfiguredPIN, NullParam)
+{
+    OCStackResult result = SetPreconfigPin("12341234", strlen("12341234"));
+    EXPECT_EQ(OC_STACK_OK, result);
+}
+
+TEST(EnableMOT, NullParam)
+{
+    OCStackResult result = OC_STACK_OK;
+
+    if(NULL == g_ownedDevices)
+    {
+        OIC_LOG(INFO, TAG, "Discovering Only Owned Devices on Network..\n");
+        result = OCDiscoverOwnedDevices(DISCOVERY_TIMEOUT, &g_ownedDevices);
+        EXPECT_EQ(OC_STACK_OK, result);
+        RemoveUnknownDeviceFromDevList(g_ownedDevices);
+    }
+    EXPECT_NE((OCProvisionDev_t*)NULL, g_ownedDevices);
+
+    g_doneCB = false;
+    result = MOTChangeMode(NULL, g_ownedDevices, OIC_MULTIPLE_OWNER_ENABLE, updateDoxmForMOTCB);
+    EXPECT_EQ(OC_STACK_OK, result);
+    if(waitCallbackRet())  // input |g_doneCB| flag implicitly
+    {
+        OIC_LOG(ERROR, TAG, "OCChangeMOTMode callback error");
+        return;
+    }
+
+    EXPECT_TRUE(g_callbackResult);
+}
+
+TEST(DiscoverMOTEnabledDevices, NullParam)
+{
+    OCStackResult result = OC_STACK_OK;
+
+    if(g_motEnabledDevices)
+    {
+        PMDeleteDeviceList(g_motEnabledDevices);
+    }
+
+    OIC_LOG(INFO, TAG, "Discovering MOT Enabled Devices on Network..\n");
+    result = OCDiscoverMultipleOwnerEnabledDevices(DISCOVERY_TIMEOUT, &g_motEnabledDevices);
+    EXPECT_EQ(OC_STACK_OK, result);
+    RemoveUnknownDeviceFromDevList(g_motEnabledDevices);
+    EXPECT_NE((OCProvisionDev_t*)NULL, g_motEnabledDevices);
+}
+
+TEST(ProvisonPreconfiguredPIN, NullParam)
+{
+    OCStackResult result = OC_STACK_OK;
+
+    g_doneCB = false;
+    result = OCProvisionPreconfPin(NULL, g_motEnabledDevices, "12341234", strlen("12341234"), provisionPreconfiguredPinCB);
+    EXPECT_EQ(OC_STACK_OK, result);
+    if(waitCallbackRet())  // input |g_doneCB| flag implicitly
+    {
+        OIC_LOG(ERROR, TAG, "OCProvisionPreconfPin callback error");
+        return;
+    }
+
+    EXPECT_EQ(true, g_callbackResult);
+}
+
+TEST(SelectMOTMethod, NullParam)
+{
+    OCStackResult result = OC_STACK_OK;
+
+    g_doneCB = false;
+    result = MOTSelectMOTMethod(NULL, g_motEnabledDevices, OIC_PRECONFIG_PIN, updateDoxmForMOTCB);
+    EXPECT_EQ(OC_STACK_OK, result);
+    if(waitCallbackRet())  // input |g_doneCB| flag implicitly
+    {
+        OIC_LOG(ERROR, TAG, "OCSelectMOTMethod callback error");
+        return;
+    }
+
+    EXPECT_EQ(true, g_callbackResult);
+}
+
+// TODO: Need to new server to perform MOT
+/*
+TEST(PerformMOT, NullParam)
+{
+    OCStackResult result = OC_STACK_OK;
+
+    g_doneCB = false;
+    result = OCDoMultipleOwnershipTransfer(NULL, g_motEnabledDevices, ownershipTransferCB);
+    EXPECT_EQ(OC_STACK_OK, result);
+    if(waitCallbackRet())  // input |g_doneCB| flag implicitly
+    {
+        OIC_LOG(ERROR, TAG, "OCDoMultipleOwnershipTransfer callback error");
+        return;
+    }
+    EXPECT_EQ(true, g_callbackResult);
+}
+
+TEST(DiscoverMultipleOwnedDevices, NullParam)
+{
+    OCStackResult result = OC_STACK_OK;
+
+    if(g_multiplOwnedDevices)
+    {
+        PMDeleteDeviceList(g_multiplOwnedDevices);
+    }
+
+    OIC_LOG(INFO, TAG, "Discovering MOT Enabled Devices on Network..\n");
+    result = OCDiscoverMultipleOwnedDevices(DISCOVERY_TIMEOUT, &g_multiplOwnedDevices);
+    EXPECT_EQ(OC_STACK_OK, result);
+    RemoveUnknownDeviceFromDevList(g_multiplOwnedDevices);
+    EXPECT_TRUE(NULL != g_multiplOwnedDevices);
+}*/
+
+#endif //_ENABLE_MULTIPLE_OWNER_
+
 TEST(PerformRemoveDevice, NullParam)
 {
     OicUuid_t myUuid;
index 0018be0..bf61273 100644 (file)
@@ -348,6 +348,13 @@ OCStackResult AclToCBORPayload(const OicSecAcl_t *secAcl, uint8_t **payload, siz
             }
         }
 
+#ifdef _ENABLE_MULTIPLE_OWNER_
+        if(ace->eownerID)
+        {
+            aclMapSize++;
+        }
+#endif //_ENABLE_MULTIPLE_OWNER_
+
         cborEncoderResult = cbor_encoder_create_map(&acesArray, &oicSecAclMap, aclMapSize);
         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Creating ACES Map");
 
@@ -538,6 +545,22 @@ OCStackResult AclToCBORPayload(const OicSecAcl_t *secAcl, uint8_t **payload, siz
             VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing Validities Array.");
         }
 
+#ifdef _ENABLE_MULTIPLE_OWNER_
+        // Eownerid -- Not Mandatory
+        if(ace->eownerID)
+        {
+            char *eowner = NULL;
+            cborEncoderResult = cbor_encode_text_string(&oicSecAclMap, OIC_JSON_EOWNERID_NAME,
+                strlen(OIC_JSON_EOWNERID_NAME));
+            VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding eownerId Name Tag.");
+            ret = ConvertUuidToStr(ace->eownerID, &eowner);
+            VERIFY_SUCCESS(TAG, ret == OC_STACK_OK, ERROR);
+            cborEncoderResult = cbor_encode_text_string(&oicSecAclMap, eowner, strlen(eowner));
+            OICFree(eowner);
+            VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding eownerId Value.");
+        }
+#endif //_ENABLE_MULTIPLE_OWNER_
+
         cborEncoderResult = cbor_encoder_close_container(&acesArray, &oicSecAclMap);
         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing ACES Map.");
     }
@@ -948,15 +971,17 @@ OicSecAcl_t* CBORPayloadToAcl(const uint8_t *cborPayload, const size_t size)
         return NULL;
     }
     OCStackResult ret = OC_STACK_ERROR;
+    CborValue aclMap = { .parser = NULL, .ptr = NULL, .remaining = 0, .extra = 0, .type = 0, .flags = 0 };
     CborValue aclCbor = { .parser = NULL };
     CborParser parser = { .end = NULL };
     CborError cborFindResult = CborNoError;
+
     cbor_parser_init(cborPayload, size, 0, &parser, &aclCbor);
 
     OicSecAcl_t *acl = (OicSecAcl_t *) OICCalloc(1, sizeof(OicSecAcl_t));
+    VERIFY_NON_NULL(TAG, acl, ERROR);
 
     // Enter ACL Map
-    CborValue aclMap = { .parser = NULL, .ptr = NULL, .remaining = 0, .extra = 0, .type = 0, .flags = 0 };
     cborFindResult = cbor_value_enter_container(&aclCbor, &aclMap);
     VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Entering ACL Map.");
 
@@ -981,7 +1006,6 @@ OicSecAcl_t* CBORPayloadToAcl(const uint8_t *cborPayload, const size_t size)
                 cborFindResult = cbor_value_enter_container(&aclMap, &aclistMap);
                 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Entering ACLIST Map.");
 
-
                 while (cbor_value_is_valid(&aclistMap))
                 {
                     char* acName = NULL;
@@ -1017,8 +1041,6 @@ OicSecAcl_t* CBORPayloadToAcl(const uint8_t *cborPayload, const size_t size)
                                 VERIFY_NON_NULL(TAG, ace, ERROR);
                                 LL_APPEND(acl->aces, ace);
 
-                                VERIFY_NON_NULL(TAG, acl, ERROR);
-
                                 while (cbor_value_is_valid(&aceMap))
                                 {
                                     char* name = NULL;
@@ -1215,6 +1237,24 @@ OicSecAcl_t* CBORPayloadToAcl(const uint8_t *cborPayload, const size_t size)
                                                 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Advancing a validities Array.");
                                             }
                                         }
+
+#ifdef _ENABLE_MULTIPLE_OWNER_
+                                        // eowner uuid -- Not Mandatory
+                                        if (strcmp(name, OIC_JSON_EOWNERID_NAME)  == 0)
+                                        {
+                                            char *eowner = NULL;
+                                            cborFindResult = cbor_value_dup_text_string(&aceMap, &eowner, &len, NULL);
+                                            VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding eownerId Value.");
+                                            if(NULL == ace->eownerID)
+                                            {
+                                                ace->eownerID = (OicUuid_t*)OICCalloc(1, sizeof(OicUuid_t));
+                                                VERIFY_NON_NULL(TAG, ace->eownerID, ERROR);
+                                            }
+                                            ret = ConvertStrToUuid(eowner, ace->eownerID);
+                                            OICFree(eowner);
+                                            VERIFY_SUCCESS(TAG, OC_STACK_OK == ret , ERROR);
+                                        }
+#endif //_ENABLE_MULTIPLE_OWNER_
                                         OICFree(name);
                                     }
 
@@ -1277,6 +1317,48 @@ exit:
     return acl;
 }
 
+#ifdef _ENABLE_MULTIPLE_OWNER_
+bool IsValidAclAccessForSubOwner(const OicUuid_t* uuid, const uint8_t *cborPayload, const size_t size)
+{
+    bool retValue = false;
+    OicSecAcl_t* acl = NULL;
+
+    VERIFY_NON_NULL(TAG, uuid, ERROR);
+    VERIFY_NON_NULL(TAG, cborPayload, ERROR);
+    VERIFY_SUCCESS(TAG, 0 != size, ERROR);
+
+    acl = CBORPayloadToAcl(cborPayload, size);
+    VERIFY_NON_NULL(TAG, acl, ERROR);
+
+    OicSecAce_t* ace = NULL;
+    OicSecAce_t* tempAce = NULL;
+    LL_FOREACH_SAFE(acl->aces, ace, tempAce)
+    {
+        OicSecRsrc_t* rsrc = NULL;
+        OicSecRsrc_t* tempRsrc = NULL;
+
+        VERIFY_NON_NULL(TAG, ace->eownerID, ERROR);
+        VERIFY_SUCCESS(TAG, memcmp(ace->eownerID->id, uuid->id, sizeof(uuid->id)) == 0, ERROR);
+
+        LL_FOREACH_SAFE(ace->resources, rsrc, tempRsrc)
+        {
+            VERIFY_SUCCESS(TAG, strcmp(rsrc->href, OIC_RSRC_TYPE_SEC_DOXM) != 0, ERROR);
+            VERIFY_SUCCESS(TAG, strcmp(rsrc->href, OIC_RSRC_TYPE_SEC_CRED) != 0, ERROR);
+            VERIFY_SUCCESS(TAG, strcmp(rsrc->href, OIC_RSRC_TYPE_SEC_ACL) != 0, ERROR);
+            VERIFY_SUCCESS(TAG, strcmp(rsrc->href, OIC_RSRC_TYPE_SEC_PSTAT) != 0, ERROR);
+            VERIFY_SUCCESS(TAG, strcmp(rsrc->href, OIC_RSRC_TYPE_SEC_CRL) != 0, ERROR);
+        }
+    }
+
+    retValue = true;
+
+exit:
+    DeleteACLList(acl);
+
+    return retValue;
+}
+#endif //_ENABLE_MULTIPLE_OWNER_
+
 /**
  * This method removes ACE for the subject and resource from the ACL
  *
index b32d9dc..f973e44 100644 (file)
@@ -118,6 +118,11 @@ static void FreeCred(OicSecCred_t *cred)
     //Clean Period
     OICFree(cred->period);
 
+#ifdef _ENABLE_MULTIPLE_OWNER_
+    //Clean eowner
+    OICFree(cred->eownerID);
+#endif
+
     //Clean Cred node itself
     OICFree(cred);
 }
@@ -224,7 +229,15 @@ OCStackResult CredToCBORPayload(const OicSecCred_t *credS, uint8_t **cborPayload
         {
             mapSize++;
         }
+
 #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
+#ifdef _ENABLE_MULTIPLE_OWNER_
+        if(cred->eownerID)
+        {
+            mapSize++;
+        }
+#endif //_ENABLE_MULTIPLE_OWNER_
+
         if (SIGNED_ASYMMETRIC_KEY == cred->credType && cred->publicData.data)
         {
             mapSize++;
@@ -393,7 +406,7 @@ OCStackResult CredToCBORPayload(const OicSecCred_t *credS, uint8_t **cborPayload
             }
             else
             {
-                OIC_LOG(ERROR, TAG, "Unknow encoding type for optional data.");
+                OIC_LOG(ERROR, TAG, "Unknown encoding type for optional data.");
                 VERIFY_CBOR_SUCCESS(TAG, CborErrorUnknownType, "Failed Adding optional Encoding Value.");
             }
 
@@ -476,7 +489,7 @@ OCStackResult CredToCBORPayload(const OicSecCred_t *credS, uint8_t **cborPayload
             }
             else
             {
-                OIC_LOG(ERROR, TAG, "Unknow encoding type for private data.");
+                OIC_LOG(ERROR, TAG, "Unknown encoding type for private data.");
                 VERIFY_CBOR_SUCCESS(TAG, CborErrorUnknownType, "Failed Adding Private Encoding Value.");
             }
 
@@ -495,6 +508,21 @@ OCStackResult CredToCBORPayload(const OicSecCred_t *credS, uint8_t **cborPayload
             VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Period Name Value.");
         }
 
+#ifdef _ENABLE_MULTIPLE_OWNER_
+        // Eownerid -- Not Mandatory
+        if(cred->eownerID)
+        {
+            char *eowner = NULL;
+            cborEncoderResult = cbor_encode_text_string(&credMap, OIC_JSON_EOWNERID_NAME,
+                strlen(OIC_JSON_EOWNERID_NAME));
+            VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding eownerId Name Tag.");
+            ret = ConvertUuidToStr(cred->eownerID, &eowner);
+            VERIFY_SUCCESS(TAG, ret == OC_STACK_OK, ERROR);
+            cborEncoderResult = cbor_encode_text_string(&credMap, eowner, strlen(eowner));
+            VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding eownerId Value.");
+            OICFree(eowner);
+        }
+#endif //_ENABLE_MULTIPLE_OWNER_
 
         cborEncoderResult = cbor_encoder_close_container(&credArray, &credMap);
         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing Cred Map.");
@@ -742,7 +770,7 @@ OCStackResult CBORPayloadToCred(const uint8_t *cborPayload, size_t size,
                                             else
                                             {
                                                 cborFindResult = CborErrorUnknownType;
-                                                OIC_LOG(ERROR, TAG, "Unknow type for private data.");
+                                                OIC_LOG(ERROR, TAG, "Unknown type for private data.");
                                             }
                                             VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding PrivateData.");
                                         }
@@ -767,7 +795,7 @@ OCStackResult CBORPayloadToCred(const uint8_t *cborPayload, size_t size,
                                             {
                                                 //For unit test
                                                 cred->privateData.encoding = OIC_ENCODING_RAW;
-                                                OIC_LOG(WARNING, TAG, "Unknow encoding type dectected for private data.");
+                                                OIC_LOG(WARNING, TAG, "Unknown encoding type dectected for private data.");
                                             }
 
                                             OICFree(strEncoding);
@@ -860,7 +888,7 @@ OCStackResult CBORPayloadToCred(const uint8_t *cborPayload, size_t size,
                                             else
                                             {
                                                 cborFindResult = CborErrorUnknownType;
-                                                OIC_LOG(ERROR, TAG, "Unknow type for optional data.");
+                                                OIC_LOG(ERROR, TAG, "Unknown type for optional data.");
                                             }
                                             VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding OptionalData.");
                                         }
@@ -893,7 +921,7 @@ OCStackResult CBORPayloadToCred(const uint8_t *cborPayload, size_t size,
                                             {
                                                 //For unit test
                                                 cred->optionalData.encoding = OIC_ENCODING_RAW;
-                                                OIC_LOG(WARNING, TAG, "Unknow encoding type dectected for optional data.");
+                                                OIC_LOG(WARNING, TAG, "Unknown encoding type dectected for optional data.");
                                             }
                                             OICFree(strEncoding);
                                         }
@@ -920,6 +948,24 @@ OCStackResult CBORPayloadToCred(const uint8_t *cborPayload, size_t size,
                                 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding Period.");
                             }
 
+#ifdef _ENABLE_MULTIPLE_OWNER_
+                            // Eowner uuid -- Not Mandatory
+                            if (strcmp(OIC_JSON_EOWNERID_NAME, name)  == 0 && cbor_value_is_text_string(&credMap))
+                            {
+                                char *eowner = NULL;
+                                cborFindResult = cbor_value_dup_text_string(&credMap, &eowner, &len, NULL);
+                                VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding eownerId Value.");
+                                if(NULL == cred->eownerID)
+                                {
+                                    cred->eownerID = (OicUuid_t*)OICCalloc(1, sizeof(OicUuid_t));
+                                    VERIFY_NON_NULL(TAG, cred->eownerID, ERROR);
+                                }
+                                ret = ConvertStrToUuid(eowner, cred->eownerID);
+                                OICFree(eowner);
+                                VERIFY_SUCCESS(TAG, OC_STACK_OK == ret , ERROR);
+                            }
+#endif //_ENABLE_MULTIPLE_OWNER_
+
                             if (cbor_value_is_valid(&credMap))
                             {
                                 cborFindResult = cbor_value_advance(&credMap);
@@ -976,9 +1022,35 @@ exit:
     return ret;
 }
 
+#ifdef _ENABLE_MULTIPLE_OWNER_
+bool IsValidCredentialAccessForSubOwner(const OicUuid_t* uuid, const uint8_t *cborPayload, size_t size)
+{
+    OicSecCred_t* cred = NULL;
+    bool isValidCred = false;
+
+    OIC_LOG_BUFFER(DEBUG, TAG, cborPayload, size);
+
+    VERIFY_NON_NULL(TAG, uuid, ERROR);
+    VERIFY_NON_NULL(TAG, cborPayload, ERROR);
+    VERIFY_SUCCESS(TAG, 0 != size, ERROR);
+    VERIFY_SUCCESS(TAG, OC_STACK_OK == CBORPayloadToCred(cborPayload, size, &cred), ERROR);
+    VERIFY_NON_NULL(TAG, cred, ERROR);
+    VERIFY_NON_NULL(TAG, cred->eownerID, ERROR);
+    VERIFY_SUCCESS(TAG, (memcmp(cred->eownerID->id, uuid->id, sizeof(uuid->id)) == 0), ERROR);
+
+    isValidCred = true;
+
+exit:
+    DeleteCredList(cred);
+
+    return isValidCred;
+
+}
+#endif //_ENABLE_MULTIPLE_OWNER_
+
 OicSecCred_t * GenerateCredential(const OicUuid_t * subject, OicSecCredType_t credType,
                                   const OicSecCert_t * publicData, const OicSecKey_t* privateData,
-                                  const OicUuid_t * rownerID)
+                                  const OicUuid_t * rownerID, const OicUuid_t * eownerID)
 {
     (void)publicData;
     OCStackResult ret = OC_STACK_ERROR;
@@ -1040,6 +1112,15 @@ OicSecCred_t * GenerateCredential(const OicUuid_t * subject, OicSecCredType_t cr
     VERIFY_NON_NULL(TAG, rownerID, ERROR);
     memcpy(&cred->rownerID, rownerID, sizeof(OicUuid_t));
 
+#ifdef _ENABLE_MULTIPLE_OWNER_
+    if(eownerID)
+    {
+        cred->eownerID = (OicUuid_t*)OICCalloc(1, sizeof(OicUuid_t));
+        VERIFY_NON_NULL(TAG, cred->eownerID, ERROR);
+        memcpy(cred->eownerID->id, eownerID->id, sizeof(eownerID->id));
+    }
+#endif //_ENABLE_MULTIPLE_OWNER_
+
     ret = OC_STACK_OK;
 exit:
     if (OC_STACK_OK != ret)
@@ -1058,9 +1139,10 @@ static bool UpdatePersistentStorage(const OicSecCred_t *cred)
     if (cred)
     {
         uint8_t *payload = NULL;
-        // This added '256' is arbitrary value that is added to cover the name of the resource, map addition and ending
+        // This added '512' is arbitrary value that is added to cover the name of the resource, map addition and ending
         size_t size = GetCredKeyDataSize(cred);
-        size += (256 * OicSecCredCount(cred));
+        size += (512 * OicSecCredCount(cred));
+
         int secureFlag = 0;
         OCStackResult res = CredToCBORPayload(cred, &payload, &size, secureFlag);
         if ((OC_STACK_OK == res) && payload)
@@ -1477,7 +1559,6 @@ static bool FillPrivateDataOfOwnerPSK(OicSecCred_t* receviedCred, const CAEndpoi
     }
     else
     {
-        // TODO: error
         VERIFY_SUCCESS(TAG, OIC_ENCODING_UNKNOW, ERROR);
     }
 
@@ -1491,6 +1572,79 @@ exit:
     return false;
 }
 
+
+#ifdef _ENABLE_MULTIPLE_OWNER_
+/**
+ * Internal function to fill private data of SubOwner PSK.
+ *
+ * @param receviedCred recevied owner credential from SubOwner
+ * @param ownerAdd address of SubOwner
+ * @param doxm current device's doxm resource
+ *
+ * @return
+ *     true successfully done and valid subower psk information
+ *     false Invalid subowner psk information or failed to subowner psk generation
+ */
+static bool FillPrivateDataOfSubOwnerPSK(OicSecCred_t* receivedCred, const CAEndpoint_t* ownerAddr,
+                           const OicSecDoxm_t* doxm, const OicUuid_t* subOwner)
+{
+    char* b64Buf = NULL;
+    //Derive OwnerPSK locally
+    const char* oxmLabel = GetOxmString(doxm->oxmSel);
+    VERIFY_NON_NULL(TAG, oxmLabel, ERROR);
+
+    uint8_t subOwnerPSK[OWNER_PSK_LENGTH_128] = {0};
+    CAResult_t pskRet = CAGenerateOwnerPSK(ownerAddr,
+        (uint8_t*)oxmLabel, strlen(oxmLabel),
+        subOwner->id, sizeof(subOwner->id),
+        doxm->deviceID.id, sizeof(doxm->deviceID.id),
+        subOwnerPSK, OWNER_PSK_LENGTH_128);
+    VERIFY_SUCCESS(TAG, pskRet == CA_STATUS_OK, ERROR);
+
+    OIC_LOG(DEBUG, TAG, "SubOwnerPSK dump :");
+    OIC_LOG_BUFFER(DEBUG, TAG, subOwnerPSK, OWNER_PSK_LENGTH_128);
+
+    //Generate owner credential based on received credential information
+
+    if(OIC_ENCODING_RAW == receivedCred->privateData.encoding)
+    {
+        receivedCred->privateData.data = (uint8_t *)OICCalloc(1, OWNER_PSK_LENGTH_128);
+        VERIFY_NON_NULL(TAG, receivedCred->privateData.data, ERROR);
+        receivedCred->privateData.len = OWNER_PSK_LENGTH_128;
+        memcpy(receivedCred->privateData.data, subOwnerPSK, OWNER_PSK_LENGTH_128);
+    }
+    else if(OIC_ENCODING_BASE64 == receivedCred->privateData.encoding)
+    {
+        uint32_t b64OutSize = 0;
+        size_t b64BufSize = B64ENCODE_OUT_SAFESIZE((OWNER_PSK_LENGTH_128 + 1));
+        b64Buf = OICCalloc(1, b64BufSize);
+        VERIFY_NON_NULL(TAG, b64Buf, ERROR);
+
+        VERIFY_SUCCESS(TAG, \
+                       B64_OK == b64Encode(subOwnerPSK, OWNER_PSK_LENGTH_128, b64Buf, b64BufSize, &b64OutSize), \
+                       ERROR);
+
+        receivedCred->privateData.data = (uint8_t *)OICCalloc(1, b64OutSize + 1);
+        VERIFY_NON_NULL(TAG, receivedCred->privateData.data, ERROR);
+        receivedCred->privateData.len = b64OutSize;
+        strncpy((char*)receivedCred->privateData.data, b64Buf, b64OutSize);
+        receivedCred->privateData.data[b64OutSize] = '\0';
+    }
+    else
+    {
+        OIC_LOG(INFO, TAG, "Unknown credential encoding type.");
+        VERIFY_SUCCESS(TAG, OIC_ENCODING_UNKNOW, ERROR);
+    }
+
+    OIC_LOG(INFO, TAG, "PrivateData of SubOwnerPSK was calculated successfully");
+    OICFree(b64Buf);
+    return true;
+exit:
+    //receivedCred->privateData.data will be deallocated when deleting credential.
+    OICFree(b64Buf);
+    return false;
+}
+#endif //_ENABLE_MULTIPLE_OWNER_
 #endif // __WITH_DTLS__ or __WITH_TLS__
 
 static OCEntityHandlerResult HandlePostRequest(const OCEntityHandlerRequest * ehRequest)
@@ -1551,7 +1705,7 @@ static OCEntityHandlerResult HandlePostRequest(const OCEntityHandlerRequest * eh
                         if(OIC_RANDOM_DEVICE_PIN == doxm->oxmSel)
                         {
                             OicUuid_t emptyUuid = { .id={0}};
-                            SetUuidForRandomPinOxm(&emptyUuid);
+                            SetUuidForPinBasedOxm(&emptyUuid);
 
 #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
                             if(CA_STATUS_OK != CAregisterPskCredentialsHandler(GetDtlsPskCredentials))
@@ -1596,7 +1750,7 @@ static OCEntityHandlerResult HandlePostRequest(const OCEntityHandlerRequest * eh
                 }
                 default:
                 {
-                    OIC_LOG(WARNING, TAG, "Unknow credential type for owner credential.");
+                    OIC_LOG(WARNING, TAG, "Unknown credential type for owner credential.");
                     ret = OC_EH_ERROR;
                     break;
                 }
@@ -1625,6 +1779,62 @@ static OCEntityHandlerResult HandlePostRequest(const OCEntityHandlerRequest * eh
                 }
             }
         }
+#ifdef _ENABLE_MULTIPLE_OWNER_
+        // In case SubOwner Credential
+        else if(doxm && doxm->owned && doxm->mom &&
+                OIC_MULTIPLE_OWNER_DISABLE != doxm->mom->mode &&
+                0 == cred->privateData.len)
+        {
+            switch(cred->credType)
+            {
+                case SYMMETRIC_PAIR_WISE_KEY:
+                {
+                    OCServerRequest *request = (OCServerRequest *)ehRequest->requestHandle;
+                    if(FillPrivateDataOfSubOwnerPSK(cred, (CAEndpoint_t *)&request->devAddr, doxm, &cred->subject))
+                    {
+                        if(OC_STACK_RESOURCE_DELETED == RemoveCredential(&cred->subject))
+                        {
+                            OIC_LOG(WARNING, TAG, "The credential with the same subject ID was detected!");
+                        }
+
+                        OIC_LOG(ERROR, TAG, "SubOwnerPSK was generated successfully.");
+                        if(OC_STACK_OK == AddCredential(cred))
+                        {
+                            ret = OC_EH_CHANGED;
+                        }
+                        else
+                        {
+                            OIC_LOG(ERROR, TAG, "Failed to save the SubOwnerPSK as cred resource");
+                            ret = OC_EH_ERROR;
+                        }
+                    }
+                    else
+                    {
+                        OIC_LOG(ERROR, TAG, "Failed to verify receviced SubOwner PSK.");
+                        ret = OC_EH_ERROR;
+                    }
+                }
+                break;
+
+                case SYMMETRIC_GROUP_KEY:
+                case ASYMMETRIC_KEY:
+                case SIGNED_ASYMMETRIC_KEY:
+                case PIN_PASSWORD:
+                case ASYMMETRIC_ENCRYPTION_KEY:
+                {
+                    OIC_LOG(WARNING, TAG, "Unsupported credential type for SubOwner credential.");
+                    ret = OC_EH_ERROR;
+                    break;
+                }
+                default:
+                {
+                    OIC_LOG(WARNING, TAG, "Unknown credential type for SubOwner credential.");
+                    ret = OC_EH_ERROR;
+                    break;
+                }
+            }
+        }
+#endif //_ENABLE_MULTIPLE_OWNER_
         else
         {
             /*
@@ -1857,8 +2067,7 @@ const OicSecCred_t* GetCredList()
 OicSecCred_t* GetCredResourceDataByCredId(const uint16_t credId)
 {
     OicSecCred_t *cred = NULL;
-
-   if ( 1 > credId)
+    if ( 1 > credId)
     {
        return NULL;
     }
@@ -1948,7 +2157,7 @@ int32_t GetDtlsPskCredentials(CADtlsPskCredType_t type,
                             uint32_t outKeySize;
                             if(NULL == outKey)
                             {
-                                OIC_LOG (ERROR, TAG, "Failed to memoray allocation.");
+                                OIC_LOG (ERROR, TAG, "Failed to allocate memory.");
                                 return ret;
                             }
 
@@ -1968,6 +2177,105 @@ int32_t GetDtlsPskCredentials(CADtlsPskCredType_t type,
                         return ret;
                     }
                 }
+                OIC_LOG(DEBUG, TAG, "Can not find subject matched credential.");
+
+#ifdef _ENABLE_MULTIPLE_OWNER_
+                const OicSecDoxm_t* doxm = GetDoxmResourceData();
+                if(doxm && doxm->mom && OIC_MULTIPLE_OWNER_DISABLE != doxm->mom->mode)
+                {
+                    // in case of multiple owner transfer authentication
+                    if(OIC_PRECONFIG_PIN == doxm->oxmSel)
+                    {
+                        OicSecCred_t* wildCardCred = GetCredResourceData(&WILDCARD_SUBJECT_ID);
+                        if(wildCardCred)
+                        {
+                            OIC_LOG(DEBUG, TAG, "Detected wildcard credential.");
+                            if(PIN_PASSWORD == wildCardCred->credType)
+                            {
+                                //Read PIN/PW
+                                char* pinBuffer = NULL;
+                                uint32_t pinLength = 0;
+                                if(OIC_ENCODING_RAW == wildCardCred->privateData.encoding)
+                                {
+                                    pinBuffer = OICCalloc(1, wildCardCred->privateData.len + 1);
+                                    if(NULL == pinBuffer)
+                                    {
+                                        OIC_LOG (ERROR, TAG, "Failed to allocate memory.");
+                                        return ret;
+                                    }
+                                    pinLength = wildCardCred->privateData.len;
+                                    memcpy(pinBuffer, wildCardCred->privateData.data, pinLength);
+                                }
+                                else if(OIC_ENCODING_BASE64 == wildCardCred->privateData.encoding)
+                                {
+                                    size_t pinBufSize = B64DECODE_OUT_SAFESIZE((wildCardCred->privateData.len + 1));
+                                    pinBuffer = OICCalloc(1, pinBufSize);
+                                    if(NULL == pinBuffer)
+                                    {
+                                        OIC_LOG (ERROR, TAG, "Failed to allocate memory.");
+                                        return ret;
+                                    }
+
+                                    if(B64_OK != b64Decode((char*)wildCardCred->privateData.data, wildCardCred->privateData.len, pinBuffer, pinBufSize, &pinLength))
+                                    {
+                                        OIC_LOG (ERROR, TAG, "Failed to base64 decoding.");
+                                        return ret;
+                                    }
+                                }
+                                else
+                                {
+                                    OIC_LOG(ERROR, TAG, "Unknown encoding type of PIN/PW credential.");
+                                    return ret;
+                                }
+
+                                //Set the PIN/PW to derive PSK
+                                if(OC_STACK_OK != SetPreconfigPin(pinBuffer, pinLength))
+                                {
+                                    OICFree(pinBuffer);
+                                    OIC_LOG(ERROR, TAG, "Failed to load PIN data.");
+                                    return ret;
+                                }
+                                OICFree(pinBuffer);
+
+                                OicUuid_t myUuid;
+                                if(OC_STACK_OK != GetDoxmDeviceID(&myUuid))
+                                {
+                                    OIC_LOG(ERROR, TAG, "Failed to read device ID");
+                                    return ret;
+                                }
+                                SetUuidForPinBasedOxm(&myUuid);
+
+                                //Calculate PSK using PIN/PW
+                                if(0 == DerivePSKUsingPIN((uint8_t*)result))
+                                {
+                                    ret = OWNER_PSK_LENGTH_128;
+                                }
+                                else
+                                {
+                                    OIC_LOG_V(ERROR, TAG, "Failed to derive crypto key from PIN");
+                                }
+
+                                if(CA_STATUS_OK != CAregisterSslHandshakeCallback(MultipleOwnerDTLSHandshakeCB))
+                                {
+                                    OIC_LOG(WARNING, TAG, "Error while bind the DTLS Handshake Callback.");
+                                }
+                            }
+                        }
+                    }
+                    else if(OIC_RANDOM_DEVICE_PIN == doxm->oxmSel)
+                    {
+                        if(0 == DerivePSKUsingPIN((uint8_t*)result))
+                        {
+                            ret = OWNER_PSK_LENGTH_128;
+                        }
+                        else
+                        {
+                            OIC_LOG_V(ERROR, TAG, "Failed to derive crypto key from PIN : result");
+                            ret = -1;
+                        }
+                    }
+                }
+#endif //_ENABLE_MULTIPLE_OWNER_
             }
             break;
     }
@@ -2008,7 +2316,7 @@ OCStackResult AddTmpPskWithPIN(const OicUuid_t* tmpSubject, OicSecCredType_t cre
     VERIFY_SUCCESS(TAG, (0 == dtlsRes) , ERROR);
 
     cred = GenerateCredential(tmpSubject, credType, NULL,
-                              &privKey, rownerID);
+                              &privKey, rownerID, NULL);
     if(NULL == cred)
     {
         OIC_LOG(ERROR, TAG, "GeneratePskWithPIN() : Failed to generate credential");
@@ -2214,6 +2522,12 @@ void InitCipherSuiteList(bool * list)
     {
         switch (temp->credType)
         {
+            case PIN_PASSWORD:
+            {
+                list[0] = true;
+                OIC_LOG(DEBUG, TAG, "PIN_PASSWORD found");
+                break;
+            }
             case SYMMETRIC_PAIR_WISE_KEY:
             {
                 list[0] = true;
@@ -2228,7 +2542,6 @@ void InitCipherSuiteList(bool * list)
             }
             case SYMMETRIC_GROUP_KEY:
             case ASYMMETRIC_KEY:
-            case PIN_PASSWORD:
             case ASYMMETRIC_ENCRYPTION_KEY:
             {
                 OIC_LOG(WARNING, TAG, "Unsupported credential type for TLS.");
@@ -2236,7 +2549,7 @@ void InitCipherSuiteList(bool * list)
             }
             default:
             {
-                OIC_LOG(WARNING, TAG, "Unknow credential type for TLS.");
+                OIC_LOG(WARNING, TAG, "Unknown credential type for TLS.");
                 break;
             }
         }
index 080450a..fdcb7de 100644 (file)
@@ -52,6 +52,7 @@
 #include "pinoxmcommon.h"
 
 #define TAG  "SRM-DOXM"
+#define CHAR_ZERO ('0')
 
 /** Default cbor payload size. This value is increased in case of CborErrorOutOfMemory.
  * The value of payload size is increased until reaching belox max cbor size. */
@@ -76,6 +77,10 @@ static OicSecDoxm_t gDefaultDoxm =
     {.id = {0}},            /* OicUuid_t deviceID */
     false,                  /* bool dpc */
     {.id = {0}},            /* OicUuid_t owner */
+#ifdef _ENABLE_MULTIPLE_OWNER_
+    NULL,                   /* OicSecSubOwner_t sub-owner list */
+    NULL,                   /* OicSecMomType_t multiple owner mode */
+#endif //_ENABLE_MULTIPLE_OWNER_
     {.id = {0}},            /* OicUuid_t rownerID */
 };
 
@@ -101,6 +106,23 @@ void DeleteDoxmBinData(OicSecDoxm_t* doxm)
         //clean oxm
         OICFree(doxm->oxm);
 
+#ifdef _ENABLE_MULTIPLE_OWNER_
+        //clean mom
+        OICFree(doxm->mom);
+
+        //clean sub-owner list
+        if(NULL != doxm->subOwners)
+        {
+            OicSecSubOwner_t* subowner = NULL;
+            OicSecSubOwner_t* temp = NULL;
+            LL_FOREACH_SAFE(doxm->subOwners, subowner, temp)
+            {
+                LL_DELETE(doxm->subOwners, subowner);
+                OICFree(subowner);
+            }
+        }
+#endif //_ENABLE_MULTIPLE_OWNER_
+
         //Clean doxm itself
         OICFree(doxm);
     }
@@ -213,6 +235,49 @@ OCStackResult DoxmToCBORPayload(const OicSecDoxm_t *doxm, uint8_t **payload, siz
         strUuid = NULL;
     }
 
+#ifdef _ENABLE_MULTIPLE_OWNER_
+    //Device SubOwnerID -- Not Mandatory
+    if(doxm->subOwners)
+    {
+        size_t subOwnerLen = 0;
+        OicSecSubOwner_t* subOwner = NULL;
+        LL_FOREACH(doxm->subOwners, subOwner)
+        {
+            subOwnerLen++;
+        }
+
+        CborEncoder subOwners;
+        cborEncoderResult = cbor_encode_text_string(&doxmMap, OIC_JSON_SUBOWNERID_NAME,
+            strlen(OIC_JSON_SUBOWNERID_NAME));
+        VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding SubOwnerId Tag.");
+        cborEncoderResult = cbor_encoder_create_array(&doxmMap, &subOwners, subOwnerLen);
+        VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding SubOwner Array.");
+
+        subOwner = NULL;
+        LL_FOREACH(doxm->subOwners, subOwner)
+        {
+            char* strUuid = NULL;
+            ret = ConvertUuidToStr(&subOwner->uuid, &strUuid);
+            VERIFY_SUCCESS(TAG, OC_STACK_OK == ret , ERROR);
+            cborEncoderResult = cbor_encode_text_string(&subOwners, strUuid, strlen(strUuid));
+            OICFree(strUuid);
+            VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding SubOwnerId Value");
+        }
+        cborEncoderResult = cbor_encoder_close_container(&doxmMap, &subOwners);
+        VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing SubOwnerId.");
+    }
+
+    //Multiple Owner Mode -- Not Mandatory
+    if(doxm->mom)
+    {
+        cborEncoderResult = cbor_encode_text_string(&doxmMap, OIC_JSON_MOM_NAME,
+            strlen(OIC_JSON_MOM_NAME));
+        VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding mom Tag");
+        cborEncoderResult = cbor_encode_int(&doxmMap, (int64_t)doxm->mom->mode);
+        VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding mom Value.");
+    }
+#endif //_ENABLE_MULTIPLE_OWNER_
+
     //devownerid -- Mandatory
     cborEncoderResult = cbor_encode_text_string(&doxmMap, OIC_JSON_DEVOWNERID_NAME,
         strlen(OIC_JSON_DEVOWNERID_NAME));
@@ -344,7 +409,7 @@ static OCStackResult CBORPayloadToDoxmBin(const uint8_t *cborPayload, size_t siz
         CborValue oxmType;
 
         cborFindResult = cbor_value_get_array_length(&doxmMap, &doxm->oxmTypeLen);
-        VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding oxmTypeLen.")
+        VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding oxmTypeLen.");
         VERIFY_SUCCESS(TAG, doxm->oxmTypeLen != 0, ERROR);
 
         doxm->oxmType = (OicUrn_t *)OICCalloc(doxm->oxmTypeLen, sizeof(*doxm->oxmType));
@@ -359,9 +424,9 @@ static OCStackResult CBORPayloadToDoxmBin(const uint8_t *cborPayload, size_t siz
         {
             cborFindResult = cbor_value_dup_text_string(&oxmType, &doxm->oxmType[i++],
                                                         &len, NULL);
-            VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding omxType text string.")
+            VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding omxType text string.");
             cborFindResult = cbor_value_advance(&oxmType);
-            VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Advancing oxmType.")
+            VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Advancing oxmType.");
         }
     }
 
@@ -371,7 +436,7 @@ static OCStackResult CBORPayloadToDoxmBin(const uint8_t *cborPayload, size_t siz
     {
         CborValue oxm;
         cborFindResult = cbor_value_get_array_length(&doxmMap, &doxm->oxmLen);
-        VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding oxmName array Length.")
+        VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding oxmName array Length.");
         VERIFY_SUCCESS(TAG, doxm->oxmLen != 0, ERROR);
 
         doxm->oxm = (OicSecOxm_t *)OICCalloc(doxm->oxmLen, sizeof(*doxm->oxm));
@@ -505,6 +570,82 @@ static OCStackResult CBORPayloadToDoxmBin(const uint8_t *cborPayload, size_t siz
         memcpy(doxm->owner.id, gDoxm->owner.id, sizeof(doxm->owner.id));
     }
 
+#ifdef _ENABLE_MULTIPLE_OWNER_
+    cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_MOM_NAME, &doxmMap);
+    if(CborNoError == cborFindResult && cbor_value_is_integer(&doxmMap))
+    {
+        int mode = 0;
+        cborFindResult = cbor_value_get_int(&doxmMap, &mode);
+        VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding mom Name Value.")
+        if(NULL == doxm->mom)
+        {
+            doxm->mom = (OicSecMom_t*)OICCalloc(1, sizeof(OicSecMom_t));
+            VERIFY_NON_NULL(TAG, doxm->mom, ERROR);
+        }
+        doxm->mom->mode = (OicSecMomType_t)mode;
+    }
+    else if(NULL != gDoxm && NULL != gDoxm->mom)
+    {
+        // PUT/POST JSON may not have 'mom' so set it to the gDomx->mom
+        if(NULL == doxm->mom)
+        {
+            doxm->mom = (OicSecMom_t*)OICCalloc(1, sizeof(OicSecMom_t));
+            VERIFY_NON_NULL(TAG, doxm->mom, ERROR);
+        }
+        doxm->mom->mode = gDoxm->mom->mode;
+    }
+
+    cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_SUBOWNERID_NAME, &doxmMap);
+    if(CborNoError == cborFindResult && cbor_value_is_array(&doxmMap))
+    {
+        size_t subOwnerLen = 0;
+        CborValue subOwnerCbor;
+        cborFindResult = cbor_value_get_array_length(&doxmMap, &subOwnerLen);
+        VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding SubOwner array Length.");
+        VERIFY_SUCCESS(TAG, 0 != subOwnerLen, ERROR);
+
+        cborFindResult = cbor_value_enter_container(&doxmMap, &subOwnerCbor);
+        VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Entering SubOwner Array.")
+
+        while (cbor_value_is_valid(&subOwnerCbor) && cbor_value_is_text_string(&subOwnerCbor))
+        {
+            OCStackResult convertRes = OC_STACK_ERROR;
+            OicSecSubOwner_t* subOwner = NULL;
+            char* strUuid = NULL;
+            size_t uuidLen = 0;
+
+            cborFindResult = cbor_value_dup_text_string(&subOwnerCbor, &strUuid, &uuidLen, NULL);
+            VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding SubOwnerId Value");
+
+            subOwner = (OicSecSubOwner_t*)OICCalloc(1, sizeof(OicSecSubOwner_t));
+            VERIFY_NON_NULL(TAG, subOwner, ERROR);
+
+            convertRes = ConvertStrToUuid(strUuid, &subOwner->uuid);
+            VERIFY_SUCCESS(TAG, OC_STACK_OK == convertRes, ERROR);
+            subOwner->status = MOT_STATUS_DONE;
+            LL_APPEND(doxm->subOwners, subOwner);
+
+            cborFindResult = cbor_value_advance(&subOwnerCbor);
+            VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Advancing SubOwnerId.")
+        }
+    }
+    else if(NULL != gDoxm && NULL != gDoxm->subOwners)
+    {
+        // PUT/POST JSON may not have 'subOwners' so set it to the gDomx->subOwners
+        OicSecSubOwner_t* subOwnerItor = NULL;
+        LL_FOREACH(gDoxm->subOwners, subOwnerItor)
+        {
+            OicSecSubOwner_t* subOwnerId = (OicSecSubOwner_t*)OICCalloc(1, sizeof(OicSecSubOwner_t));
+            VERIFY_NON_NULL(TAG, subOwnerId, ERROR);
+
+            memcpy(&subOwnerId->uuid, &subOwnerItor->uuid, sizeof(OicUuid_t));
+            subOwnerId->status = MOT_STATUS_DONE;
+
+            LL_APPEND(doxm->subOwners, subOwnerId);
+        }
+    }
+#endif //_ENABLE_MULTIPLE_OWNER_
+
     cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_ROWNERID_NAME, &doxmMap);
     if (CborNoError == cborFindResult && cbor_value_is_text_string(&doxmMap))
     {
@@ -590,6 +731,10 @@ static bool ValidateQuery(const char * query)
     bool bDeviceIDMatch = false;    // does 'deviceid' query matches with doxm.deviceid ?
     bool bInterfaceQry = false;      // does querystring contains 'if' query ?
     bool bInterfaceMatch = false;    // does 'if' query matches with oic.if.baseline ?
+#ifdef _ENABLE_MULTIPLE_OWNER_
+    bool bMotQry = false;         // does querystring contains 'mom' and 'owned' query ?
+    bool bMotMatch = false;       // does 'mom' query value is not '0' && does query value matches with doxm.owned status?
+#endif //_ENABLE_MULTIPLE_OWNER_
 
     OicParseQueryIter_t parseIter = {.attrPos = NULL};
 
@@ -612,6 +757,29 @@ static bool ValidateQuery(const char * query)
             }
         }
 
+#ifdef _ENABLE_MULTIPLE_OWNER_
+        if (strncasecmp((char *)parseIter.attrPos, OIC_JSON_MOM_NAME, strlen(OIC_JSON_MOM_NAME)) == 0)
+        {
+            bMotQry = true;
+            OicSecMomType_t momMode = (OicSecMomType_t)(parseIter.valPos[0] - CHAR_ZERO);
+            if(NULL != gDoxm->mom && momMode != gDoxm->mom->mode)
+            {
+                if(GetNextQuery(&parseIter))
+                {
+                    if (strncasecmp((char *)parseIter.attrPos, OIC_JSON_OWNED_NAME, parseIter.attrLen) == 0)
+                    {
+                        if ((strncasecmp((char *)parseIter.valPos, OIC_SEC_TRUE, parseIter.valLen) == 0) &&
+                                (gDoxm->owned))
+                        {
+                            bMotMatch = true;
+                        }
+                    }
+                }
+            }
+            return bMotMatch;
+        }
+#endif //_ENABLE_MULTIPLE_OWNER_
+
         if (strncasecmp((char *)parseIter.attrPos, OIC_JSON_DEVICE_ID_NAME, parseIter.attrLen) == 0)
         {
             bDeviceIDQry = true;
@@ -635,7 +803,14 @@ static bool ValidateQuery(const char * query)
         }
     }
 
-    return ((bOwnedQry ? bOwnedMatch : true) && (bDeviceIDQry ? bDeviceIDMatch : true));
+#ifdef _ENABLE_MULTIPLE_OWNER_
+    return ((bOwnedQry ? bOwnedMatch : true) &&
+            (bDeviceIDQry ? bDeviceIDMatch : true) &&
+            (bMotQry ? bMotMatch : true));
+#else
+    return ((bOwnedQry ? bOwnedMatch : true) &&
+            (bDeviceIDQry ? bDeviceIDMatch : true));
+#endif //_ENABLE_MULTIPLE_OWNER_
 }
 
 static OCEntityHandlerResult HandleDoxmGetRequest (const OCEntityHandlerRequest * ehRequest)
@@ -684,6 +859,100 @@ static OCEntityHandlerResult HandleDoxmGetRequest (const OCEntityHandlerRequest
     return ehRet;
 }
 
+static void updateWriteableProperty(const OicSecDoxm_t* src, OicSecDoxm_t* dst)
+{
+    if(src && dst)
+   {
+        // update oxmsel
+        dst->oxmSel = src->oxmSel;
+
+        //update owner
+        memcpy(&(dst->owner), &(src->owner), sizeof(OicUuid_t));
+
+        //update rowner
+        memcpy(&(dst->rownerID), &(src->rownerID), sizeof(OicUuid_t));
+
+        //Update owned status
+        if(dst->owned != src->owned)
+        {
+            dst->owned = src->owned;
+        }
+
+        //update oxms
+        if(0 < src->oxmLen)
+        {
+            OicSecOxm_t* tempOxm = (OicSecOxm_t*)OICMalloc(sizeof(OicSecOxm_t) * src->oxmLen);
+            if(NULL != tempOxm)
+            {
+                for(size_t i = 0; i < src->oxmLen; i++)
+                {
+                    tempOxm[i] = src->oxm[i];
+                }
+                OICFree(dst->oxm);
+
+                dst->oxm = tempOxm;
+                dst->oxmLen = src->oxmLen;
+            }
+        }
+
+#ifdef _ENABLE_MULTIPLE_OWNER_
+        if(src->mom)
+        {
+            OIC_LOG(DEBUG, TAG, "dectected 'mom' property");
+            if(NULL == dst->mom)
+            {
+                dst->mom = (OicSecMom_t*)OICCalloc(1, sizeof(OicSecMom_t));
+                if(NULL != dst->mom)
+                {
+                    dst->mom->mode = src->mom->mode;
+                }
+            }
+        }
+#endif //_ENABLE_MULTIPLE_OWNER_
+    }
+}
+
+#if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
+#ifdef _ENABLE_MULTIPLE_OWNER_
+/**
+ * Callback function to handle MOT DTLS handshake result.
+ * @param[out]   object           remote device information.
+ * @param[out]   errorInfo        CA Error information.
+ */
+void MultipleOwnerDTLSHandshakeCB(const CAEndpoint_t *object,
+                                const CAErrorInfo_t *errorInfo)
+{
+    OIC_LOG(DEBUG, TAG, "IN MultipleOwnerDTLSHandshakeCB");
+
+    if(CA_STATUS_OK == errorInfo->result)
+    {
+        const CASecureEndpoint_t* authenticatedSubOwnerInfo = CAGetSecureEndpointData(object);
+        if(authenticatedSubOwnerInfo)
+        {
+            OicSecSubOwner_t* subOwnerInst = (OicSecSubOwner_t*)OICMalloc(sizeof(OicSecSubOwner_t));
+            if(subOwnerInst)
+            {
+                OIC_LOG(DEBUG, TAG, "Adding New SubOwner");
+                memcpy(subOwnerInst->uuid.id, authenticatedSubOwnerInfo->identity.id, authenticatedSubOwnerInfo->identity.id_length);
+                LL_APPEND(gDoxm->subOwners, subOwnerInst);
+                if(!UpdatePersistentStorage(gDoxm))
+                {
+                    OIC_LOG(ERROR, TAG, "Failed to register SubOwner UUID into Doxm");
+                }
+            }
+        }
+    }
+
+    if(CA_STATUS_OK != CAregisterPskCredentialsHandler(GetDtlsPskCredentials))
+    {
+        OIC_LOG(WARNING, TAG, "Failed to revert the DTLS credential handler");
+    }
+
+    OIC_LOG(DEBUG, TAG, "OUT MultipleOwnerDTLSHandshakeCB");
+}
+#endif //_ENABLE_MULTIPLE_OWNER_
+#endif // defined(__WITH_DTLS__) || defined (__WITH_TLS__)
+
 static OCEntityHandlerResult HandleDoxmPostRequest(const OCEntityHandlerRequest * ehRequest)
 {
     OIC_LOG (DEBUG, TAG, "Doxm EntityHandle  processing POST request");
@@ -716,15 +985,73 @@ static OCEntityHandlerResult HandleDoxmPostRequest(const OCEntityHandlerRequest
             // in owned state
             if (true == gDoxm->owned)
             {
-                // update writable properties
-                gDoxm->oxmSel = newDoxm->oxmSel;
-                memcpy(&(gDoxm->owner), &(newDoxm->owner), sizeof(OicUuid_t));
-                memcpy(&(gDoxm->rownerID), &(newDoxm->rownerID), sizeof(OicUuid_t));
+                //Update gDoxm based on newDoxm
+                updateWriteableProperty(newDoxm, gDoxm);
+
+#if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
+#ifdef _ENABLE_MULTIPLE_OWNER_
+                //handle mom
+                if(gDoxm->mom)
+                {
+                    if(OIC_MULTIPLE_OWNER_DISABLE != gDoxm->mom->mode)
+                    {
+                        CAResult_t caRes = CA_STATUS_FAILED;
+                        if(OIC_PRECONFIG_PIN == gDoxm->oxmSel || OIC_RANDOM_DEVICE_PIN == gDoxm->oxmSel)
+                        {
+                            caRes = CAEnableAnonECDHCipherSuite(false);
+                            VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
+                            OIC_LOG(INFO, TAG, "ECDH_ANON CipherSuite is DISABLED");
+
+                            caRes = CASelectCipherSuite((uint16_t)TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256, ehRequest->devAddr.adapter);
+                            VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
+                            OIC_LOG(INFO, TAG, "ECDHE_PSK CipherSuite will be used for MOT");
+
+                            //Set the device id to derive temporal PSK
+                            SetUuidForPinBasedOxm(&gDoxm->deviceID);
+                        }
+                        else
+                        {
+                            OIC_LOG(WARNING, TAG, "Unsupported OxM for Multiple Ownership Transfer.");
+                        }
+
+                        CAregisterSslHandshakeCallback(MultipleOwnerDTLSHandshakeCB);
+                    }
+                    else
+                    {
+                        //if MOM is disabled, revert the DTLS handshake callback
+                        if(CA_STATUS_OK != CAregisterSslHandshakeCallback(NULL))
+                        {
+                            OIC_LOG(WARNING, TAG, "Error while revert the DTLS Handshake Callback.");
+                        }
+                    }
+                }
 
-                if(gDoxm->owned != newDoxm->owned)
+                if(newDoxm->subOwners)
                 {
-                    gDoxm->owned = newDoxm->owned;
+                    OicSecSubOwner_t* subowner = NULL;
+                    OicSecSubOwner_t* temp = NULL;
+
+                    OIC_LOG(DEBUG, TAG, "dectected 'subowners' property");
+
+                    if(gDoxm->subOwners)
+                    {
+                        LL_FOREACH_SAFE(gDoxm->subOwners, subowner, temp)
+                        {
+                            LL_DELETE(gDoxm->subOwners, subowner);
+                            OICFree(subowner);
+                        }
+                    }
+
+                    subowner = NULL;
+                    temp = NULL;
+                    LL_FOREACH_SAFE(newDoxm->subOwners, subowner, temp)
+                    {
+                        LL_DELETE(newDoxm->subOwners, subowner);
+                        LL_APPEND(gDoxm->subOwners, subowner);
+                    }
                 }
+#endif //_ENABLE_MULTIPLE_OWNER_
+#endif // defined(__WITH_DTLS__) || defined (__WITH_TLS__)
 
                 //Update new state in persistent storage
                 if (UpdatePersistentStorage(gDoxm) == true)
@@ -825,7 +1152,7 @@ static OCEntityHandlerResult HandleDoxmPostRequest(const OCEntityHandlerRequest
                             if(OC_STACK_OK == GeneratePin(ranPin, OXM_RANDOM_PIN_SIZE + 1))
                             {
                                 //Set the device id to derive temporal PSK
-                                SetUuidForRandomPinOxm(&gDoxm->deviceID);
+                                SetUuidForPinBasedOxm(&gDoxm->deviceID);
 
                                 /**
                                  * Since PSK will be used directly by DTLS layer while PIN based ownership transfer,
@@ -842,21 +1169,19 @@ static OCEntityHandlerResult HandleDoxmPostRequest(const OCEntityHandlerRequest
                                 ehRet = OC_EH_ERROR;
                             }
                         }
-                        else
+                        else if(previousMsgId != ehRequest->messageID)
                         {
                             if(OC_STACK_OK == GeneratePin(ranPin, OXM_RANDOM_PIN_SIZE + 1))
                             {
                                 //Set the device id to derive temporal PSK
-                                SetUuidForRandomPinOxm(&gDoxm->deviceID);
+                                SetUuidForPinBasedOxm(&gDoxm->deviceID);
 
                                 /**
                                  * Since PSK will be used directly by DTLS layer while PIN based ownership transfer,
                                  * Credential should not be saved into SVR.
                                  * For this reason, use a temporary get_psk_info callback to random PIN OxM.
                                  */
-#ifdef __WITH_TLS__
                                 caRes = CAregisterPskCredentialsHandler(GetDtlsPskForRandomPinOxm);
-#endif
                                 VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
                                 ehRet = OC_EH_OK;
                             }
@@ -869,9 +1194,9 @@ static OCEntityHandlerResult HandleDoxmPostRequest(const OCEntityHandlerRequest
                         }
 #endif // __WITH_DTLS__ or __WITH_TLS__
                     }
+#if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
                     else
                     {
-#if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
                         //Save the owner's UUID to derive owner credential
                         memcpy(&(gDoxm->owner), &(newDoxm->owner), sizeof(OicUuid_t));
 
@@ -885,8 +1210,8 @@ static OCEntityHandlerResult HandleDoxmPostRequest(const OCEntityHandlerRequest
                             OIC_LOG(ERROR, TAG, "Failed to update DOXM in persistent storage");
                             ehRet = OC_EH_ERROR;
                         }
-#endif // __WITH_DTLS__ or __WITH_TLS__
                     }
+#endif // __WITH_DTLS__ or __WITH_TLS__
                 }
             }
 
@@ -1110,6 +1435,54 @@ const OicSecDoxm_t* GetDoxmResourceData()
     return gDoxm;
 }
 
+#if defined(__WITH_DTLS__) && defined(_ENABLE_MULTIPLE_OWNER_)
+/**
+ * Internal API to prepare MOT
+ */
+static void PrepareMOT(const OicSecDoxm_t* doxm)
+{
+    OIC_LOG(INFO, TAG, "IN PrepareMOT");
+    VERIFY_NON_NULL(TAG, doxm, ERROR);
+
+    if(true == doxm->owned && NULL != doxm->mom && OIC_MULTIPLE_OWNER_DISABLE != doxm->mom->mode)
+    {
+        CAResult_t caRes = CA_STATUS_FAILED;
+
+        OIC_LOG(INFO, TAG, "Multiple Ownership Transfer Enabled!");
+
+        if(OIC_PRECONFIG_PIN == doxm->oxmSel)
+        {
+            caRes = CAEnableAnonECDHCipherSuite(false);
+            VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
+            OIC_LOG(INFO, TAG, "ECDH_ANON CipherSuite is DISABLED");
+
+            caRes = CASelectCipherSuite((uint16_t)TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256, CA_ADAPTER_IP);
+            VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
+#ifdef __WITH_TLS__
+            caRes = CASelectCipherSuite((uint16_t)TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256, CA_ADAPTER_TCP);
+            VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
+#endif
+            OIC_LOG(INFO, TAG, "ECDHE_PSK CipherSuite will be used for MOT");
+
+            //Set the device id to derive temporal PSK
+            SetUuidForPinBasedOxm(&doxm->deviceID);
+        }
+        else
+        {
+            OIC_LOG(ERROR, TAG, "Unsupported OxM for Multiple Ownership Transfer.");
+            return;
+        }
+
+        CAregisterSslHandshakeCallback(MultipleOwnerDTLSHandshakeCB);
+    }
+
+    OIC_LOG(INFO, TAG, "OUT PrepareMOT");
+    return;
+exit:
+    OIC_LOG(WARNING, TAG, "Error in PrepareMOT");
+}
+#endif //defined(__WITH_DTLS__) && defined(_ENABLE_MULTIPLE_OWNER_)
+
 OCStackResult InitDoxmResource()
 {
     OCStackResult ret = OC_STACK_ERROR;
@@ -1157,6 +1530,15 @@ OCStackResult InitDoxmResource()
         OIC_LOG (ERROR, TAG, "CheckDeviceID failed");
     }
     OICFree(data);
+
+#if defined(__WITH_DTLS__) && defined(_ENABLE_MULTIPLE_OWNER_)
+    //if MOT is enabled, MOT should be prepared.
+    if(gDoxm && gDoxm->owned)
+    {
+        PrepareMOT(gDoxm);
+    }
+#endif // defined(__WITH_DTLS__) && defined(_ENABLE_MULTIPLE_OWNER_)
+
     return ret;
 }
 
@@ -1284,6 +1666,38 @@ OCStackResult GetDoxmRownerId(OicUuid_t *rowneruuid)
     return retVal;
 }
 
+#ifdef _ENABLE_MULTIPLE_OWNER_
+/**
+ * Compare the UUID to SubOwner.
+ *
+ * @param[in] uuid device UUID
+ *
+ * @return true if context->subjectId exist subowner list, else false.
+ */
+bool IsSubOwner(const OicUuid_t* uuid)
+{
+    bool retVal = false;
+
+    if(NULL == uuid)
+    {
+        return retVal;
+    }
+
+    if (gDoxm && gDoxm->subOwners)
+    {
+        OicSecSubOwner_t* subOwner = NULL;
+        LL_FOREACH(gDoxm->subOwners, subOwner)
+        {
+            if(memcmp(subOwner->uuid.id, uuid->id, sizeof(uuid->id)) == 0)
+            {
+                return true;
+            }
+        }
+    }
+    return retVal;
+}
+#endif //_ENABLE_MULTIPLE_OWNER_
+
 /**
  * Function to restore doxm resurce to initial status.
  * This function will use in case of error while ownership transfer
index 53b8fd6..cc02e21 100644 (file)
@@ -153,7 +153,7 @@ OCStackResult SavePairingPSK(OCDevAddr *endpoint,
 
         OicSecCred_t *cred = GenerateCredential(peerDevID,
                 SYMMETRIC_PAIR_WISE_KEY, NULL,
-                &pairingKey, owner);
+                &pairingKey, owner, NULL);
         VERIFY_NON_NULL(TAG, cred, ERROR);
 
         res = AddCredential(cred);
index 5e6b650..569b7d1 100644 (file)
 #include "logger.h"
 #include "pinoxmcommon.h"
 #include "pbkdf2.h"
+#include "base64.h"
 #include "securevirtualresourcetypes.h"
+#include "srmresourcestrings.h"
+#include "doxmresource.h"
+#include "credresource.h"
+#include "cainterface.h"
 
 #define TAG "PIN_OXM_COMMON"
 
@@ -93,10 +98,31 @@ OCStackResult GeneratePin(char* pinBuffer, size_t bufferSize)
         return OC_STACK_ERROR;
     }
 
+    OicUuid_t deviceID;
+    if(OC_STACK_OK == GetDoxmDeviceID(&deviceID))
+    {
+        //Set the device id to derive temporal PSK
+        SetUuidForPinBasedOxm(&deviceID);
+
+        /**
+         * Since PSK will be used directly by DTLS layer while PIN based ownership transfer,
+         * Credential should not be saved into SVR.
+         * For this reason, use a temporary get_psk_info callback to random PIN OxM.
+         */
+        if(CA_STATUS_OK != CAregisterPskCredentialsHandler(GetDtlsPskForRandomPinOxm))
+        {
+            OIC_LOG(ERROR, TAG, "Failed to register DTLS credential handler for Random PIN OxM.");
+        }
+    }
+    else
+    {
+        OIC_LOG(ERROR, TAG, "Failed to read device ID");
+        return OC_STACK_ERROR;
+    }
+
     return OC_STACK_OK;
 }
 
-
 OCStackResult InputPin(char* pinBuffer, size_t bufferSize)
 {
     if(!pinBuffer)
@@ -119,16 +145,31 @@ OCStackResult InputPin(char* pinBuffer, size_t bufferSize)
     else
     {
         OIC_LOG(ERROR, TAG, "Invoke PIN callback failed!");
-        OIC_LOG(ERROR, TAG, "Callback for input PIN should be registered to use PIN based OxM.");
+        OIC_LOG(ERROR, TAG, "Callback for input PIN should be registered to use Random PIN based OxM.");
         return OC_STACK_ERROR;
     }
 
     return OC_STACK_OK;
 }
 
-#if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
+#ifdef _ENABLE_MULTIPLE_OWNER_
+OCStackResult SetPreconfigPin(const char* pinBuffer, size_t pinLength)
+{
+    if(NULL == pinBuffer || OXM_PRECONFIG_PIN_SIZE < pinLength)
+    {
+        return OC_STACK_INVALID_PARAM;
+    }
+
+    memcpy(g_PinOxmData.pinData, pinBuffer, pinLength);
+    g_PinOxmData.pinData[pinLength] = '\0';
 
-void SetUuidForRandomPinOxm(const OicUuid_t* uuid)
+    return OC_STACK_OK;
+}
+#endif //_ENABLE_MULTIPLE_OWNER_
+
+#ifdef __WITH_DTLS__
+
+void SetUuidForPinBasedOxm(const OicUuid_t* uuid)
 {
     if(NULL != uuid)
     {
@@ -136,6 +177,23 @@ void SetUuidForRandomPinOxm(const OicUuid_t* uuid)
     }
 }
 
+int DerivePSKUsingPIN(uint8_t* result)
+{
+    int dtlsRes = DeriveCryptoKeyFromPassword(
+                                              (const unsigned char *)g_PinOxmData.pinData,
+                                              OXM_RANDOM_PIN_SIZE,
+                                              g_PinOxmData.newDevice.id,
+                                              UUID_LENGTH, PBKDF_ITERATIONS,
+                                              OWNER_PSK_LENGTH_128, result);
+
+    OIC_LOG_V(DEBUG, TAG, "DeriveCryptoKeyFromPassword Completed (%d)", dtlsRes);
+    OIC_LOG_V(DEBUG, TAG, "PIN : %s", g_PinOxmData.pinData);
+    OIC_LOG(DEBUG, TAG, "UUID : ");
+    OIC_LOG_BUFFER(DEBUG, TAG, g_PinOxmData.newDevice.id, UUID_LENGTH);
+
+    return dtlsRes;
+}
+
 int32_t GetDtlsPskForRandomPinOxm( CADtlsPskCredType_t type,
               const unsigned char *UNUSED1, size_t UNUSED2,
               unsigned char *result, size_t result_length)
@@ -154,40 +212,30 @@ int32_t GetDtlsPskForRandomPinOxm( CADtlsPskCredType_t type,
     {
         case CA_DTLS_PSK_HINT:
         case CA_DTLS_PSK_IDENTITY:
-            /**
-             * The server will provide PSK hint to identify PSK according to RFC 4589 and RFC 4279.
-             *
-             * At this point, The server generate random hint and
-             * provide it to client through server key exchange message.
-             */
-            OCFillRandomMem(result, result_length);
-            ret = result_length;
-
-            OIC_LOG(DEBUG, TAG, "PSK HINT : ");
-            OIC_LOG_BUFFER(DEBUG, TAG, result, result_length);
+            {
+                /**
+                 * The server will provide PSK hint to identify PSK according to RFC 4589 and RFC 4279.
+                 *
+                 * At this point, The server generate random hint and
+                 * provide it to client through server key exchange message.
+                 */
+                OCFillRandomMem(result, result_length);
+                ret = result_length;
+
+                OIC_LOG(DEBUG, TAG, "PSK HINT : ");
+                OIC_LOG_BUFFER(DEBUG, TAG, result, result_length);
+            }
             break;
 
         case CA_DTLS_PSK_KEY:
             {
-                int dtlsRes = DeriveCryptoKeyFromPassword(
-                                                          (const unsigned char *)g_PinOxmData.pinData,
-                                                          OXM_RANDOM_PIN_SIZE,
-                                                          g_PinOxmData.newDevice.id,
-                                                          UUID_LENGTH, PBKDF_ITERATIONS,
-                                                          OWNER_PSK_LENGTH_128, (uint8_t*)result);
-
-                OIC_LOG_V(DEBUG, TAG, "DeriveCryptoKeyFromPassword Completed (%d)", dtlsRes);
-                OIC_LOG_V(DEBUG, TAG, "PIN : %s", g_PinOxmData.pinData);
-                OIC_LOG(DEBUG, TAG, "UUID : ");
-                OIC_LOG_BUFFER(DEBUG, TAG, g_PinOxmData.newDevice.id, UUID_LENGTH);
-
-                if(0 == dtlsRes)
+                if(0 == DerivePSKUsingPIN((uint8_t*)result))
                 {
                     ret = OWNER_PSK_LENGTH_128;
                 }
                 else
                 {
-                    OIC_LOG_V(ERROR, TAG, "Failed to derive crypto key from PIN : result=%d", dtlsRes);
+                    OIC_LOG_V(ERROR, TAG, "Failed to derive crypto key from PIN");
                     ret = -1;
                 }
             }
@@ -203,4 +251,270 @@ int32_t GetDtlsPskForRandomPinOxm( CADtlsPskCredType_t type,
 
     return ret;
 }
-#endif // __WITH_DTLS__ or __WITH_TLS__
+
+#ifdef _ENABLE_MULTIPLE_OWNER_
+int32_t GetDtlsPskForMotRandomPinOxm( CADtlsPskCredType_t type,
+              const unsigned char *UNUSED1, size_t UNUSED2,
+              unsigned char *result, size_t result_length)
+{
+    int32_t ret = -1;
+
+    (void)UNUSED1;
+    (void)UNUSED2;
+
+    if (NULL == result || result_length < OWNER_PSK_LENGTH_128)
+    {
+        return ret;
+    }
+
+    const OicSecDoxm_t* doxm = GetDoxmResourceData();
+    if(doxm)
+    {
+        switch (type)
+        {
+            case CA_DTLS_PSK_HINT:
+            case CA_DTLS_PSK_IDENTITY:
+                {
+                    memcpy(result, doxm->deviceID.id, sizeof(doxm->deviceID.id));
+                    return (sizeof(doxm->deviceID.id));
+                }
+                break;
+
+            case CA_DTLS_PSK_KEY:
+                {
+                    if(0 == DerivePSKUsingPIN((uint8_t*)result))
+                    {
+                        ret = OWNER_PSK_LENGTH_128;
+                    }
+                    else
+                    {
+                        OIC_LOG_V(ERROR, TAG, "Failed to derive crypto key from PIN : result");
+                        ret = -1;
+                    }
+                }
+                break;
+
+            default:
+                {
+                    OIC_LOG (ERROR, TAG, "Wrong value passed for CADtlsPskCredType_t.");
+                    ret = -1;
+                }
+                break;
+        }
+    }
+
+    return ret;
+}
+
+
+int32_t GetDtlsPskForPreconfPinOxm( CADtlsPskCredType_t type,
+              const unsigned char *UNUSED1, size_t UNUSED2,
+              unsigned char *result, size_t result_length)
+{
+    int32_t ret = -1;
+
+    (void)UNUSED1;
+    (void)UNUSED2;
+
+    if (NULL == result || result_length < OWNER_PSK_LENGTH_128)
+    {
+        return ret;
+    }
+
+    const OicSecDoxm_t* doxm = GetDoxmResourceData();
+    if(doxm)
+    {
+        switch (type)
+        {
+            case CA_DTLS_PSK_HINT:
+            case CA_DTLS_PSK_IDENTITY:
+                {
+                    /**
+                     * The server will provide PSK hint to identify PSK according to RFC 4589 and RFC 4279.
+                     *
+                     * At this point, The server generate random hint and
+                     * provide it to client through server key exchange message.
+                     */
+                    OCFillRandomMem(result, result_length);
+                    ret = result_length;
+
+                    OIC_LOG(DEBUG, TAG, "PSK HINT : ");
+                    OIC_LOG_BUFFER(DEBUG, TAG, result, result_length);
+                }
+                break;
+
+            case CA_DTLS_PSK_KEY:
+                {
+                    OicUuid_t uuid;
+                    memset(&uuid, 0x00, sizeof(uuid));
+                    OICStrcpy(uuid.id, sizeof(uuid.id), WILDCARD_SUBJECT_ID.id);
+
+                    //Load PreConfigured-PIN
+                    const OicSecCred_t* cred = GetCredResourceData(&uuid);
+                    if(cred)
+                    {
+                        char* pinBuffer = NULL;
+                        uint32_t pinLength = 0;
+                        if(OIC_ENCODING_RAW == cred->privateData.encoding)
+                        {
+                            pinBuffer = OICCalloc(1, cred->privateData.len + 1);
+                            if(NULL == pinBuffer)
+                            {
+                                OIC_LOG (ERROR, TAG, "Failed to allocate memory");
+                                return ret;
+                            }
+                            pinLength = cred->privateData.len;
+                            memcpy(pinBuffer, cred->privateData.data, pinLength);
+                        }
+                        else if(OIC_ENCODING_BASE64 == cred->privateData.encoding)
+                        {
+                            size_t pinBufSize = B64DECODE_OUT_SAFESIZE((cred->privateData.len + 1));
+                            pinBuffer = OICCalloc(1, pinBufSize);
+                            if(NULL == pinBuffer)
+                            {
+                                OIC_LOG (ERROR, TAG, "Failed to allocate memory");
+                                return ret;
+                            }
+
+                            if(B64_OK != b64Decode((char*)cred->privateData.data, cred->privateData.len, pinBuffer, pinBufSize, &pinLength))
+                            {
+                                OIC_LOG (ERROR, TAG, "Failed to base64 decoding.");
+                                return ret;
+                            }
+                        }
+                        else
+                        {
+                            OIC_LOG(ERROR, TAG, "Unknown encoding type of PIN/PW credential.");
+                            return ret;
+                        }
+
+                        memcpy(g_PinOxmData.pinData, pinBuffer, pinLength);
+                        OICFree(pinBuffer);
+                    }
+
+                    if(0 == DerivePSKUsingPIN((uint8_t*)result))
+                    {
+                        ret = OWNER_PSK_LENGTH_128;
+                    }
+                    else
+                    {
+                        OIC_LOG_V(ERROR, TAG, "Failed to derive crypto key from PIN : result");
+                        ret = -1;
+                    }
+                }
+                break;
+
+            default:
+                {
+                    OIC_LOG (ERROR, TAG, "Wrong value passed for CADtlsPskCredType_t.");
+                    ret = -1;
+                }
+                break;
+        }
+    }
+
+    return ret;
+}
+
+
+int32_t GetDtlsPskForMotPreconfPinOxm( CADtlsPskCredType_t type,
+              const unsigned char *UNUSED1, size_t UNUSED2,
+              unsigned char *result, size_t result_length)
+{
+    int32_t ret = -1;
+
+    (void)UNUSED1;
+    (void)UNUSED2;
+
+    if (NULL == result || result_length < OWNER_PSK_LENGTH_128)
+    {
+        return ret;
+    }
+
+    const OicSecDoxm_t* doxm = GetDoxmResourceData();
+    if(doxm)
+    {
+        switch (type)
+        {
+            case CA_DTLS_PSK_HINT:
+            case CA_DTLS_PSK_IDENTITY:
+                {
+                    memcpy(result, doxm->deviceID.id, sizeof(doxm->deviceID.id));
+                    return (sizeof(doxm->deviceID.id));
+                }
+                break;
+            case CA_DTLS_PSK_KEY:
+                {
+                    OicUuid_t uuid;
+                    memset(&uuid, 0x00, sizeof(uuid));
+                    OICStrcpy(uuid.id, sizeof(uuid.id), WILDCARD_SUBJECT_ID.id);
+
+                    //Load PreConfigured-PIN
+                    const OicSecCred_t* cred = GetCredResourceData(&uuid);
+                    if(cred)
+                    {
+                        char* pinBuffer = NULL;
+                        uint32_t pinLength = 0;
+                        if(OIC_ENCODING_RAW == cred->privateData.encoding)
+                        {
+                            pinBuffer = OICCalloc(1, cred->privateData.len + 1);
+                            if(NULL == pinBuffer)
+                            {
+                                OIC_LOG (ERROR, TAG, "Failed to allocate memory");
+                                return ret;
+                            }
+                            pinLength = cred->privateData.len;
+                            memcpy(pinBuffer, cred->privateData.data, pinLength);
+                        }
+                        else if(OIC_ENCODING_BASE64 == cred->privateData.encoding)
+                        {
+                            size_t pinBufSize = B64DECODE_OUT_SAFESIZE((cred->privateData.len + 1));
+                            pinBuffer = OICCalloc(1, pinBufSize);
+                            if(NULL == pinBuffer)
+                            {
+                                OIC_LOG (ERROR, TAG, "Failed to allocate memory");
+                                return ret;
+                            }
+
+                            if(B64_OK != b64Decode((char*)cred->privateData.data, cred->privateData.len, pinBuffer, pinBufSize, &pinLength))
+                            {
+                                OIC_LOG (ERROR, TAG, "Failed to base64 decoding.");
+                                return ret;
+                            }
+                        }
+                        else
+                        {
+                            OIC_LOG(ERROR, TAG, "Unknown encoding type of PIN/PW credential.");
+                            return ret;
+                        }
+
+                        memcpy(g_PinOxmData.pinData, pinBuffer, pinLength);
+                        OICFree(pinBuffer);
+                    }
+
+                    if(0 == DerivePSKUsingPIN((uint8_t*)result))
+                    {
+                        ret = OWNER_PSK_LENGTH_128;
+                    }
+                    else
+                    {
+                        OIC_LOG_V(ERROR, TAG, "Failed to derive crypto key from PIN : result");
+                        ret = -1;
+                    }
+                }
+                break;
+
+            default:
+                {
+                    OIC_LOG (ERROR, TAG, "Wrong value passed for CADtlsPskCredType_t.");
+                    ret = -1;
+                }
+                break;
+        }
+    }
+
+    return ret;
+}
+#endif //_ENABLE_MULTIPLE_OWNER_
+
+#endif //__WITH_DTLS__
old mode 100644 (file)
new mode 100755 (executable)
index c3f0734..8c60682
@@ -147,6 +147,95 @@ static bool IsRequestFromDevOwner(PEContext_t *context)
     return retVal;
 }
 
+
+#ifdef _ENABLE_MULTIPLE_OWNER_
+/**
+ * Compare the request's subject to SubOwner.
+ *
+ * @return true if context->subjectId exist subowner list, else false.
+ */
+static bool IsRequestFromSubOwner(PEContext_t *context)
+{
+    bool retVal = false;
+
+    if(NULL == context)
+    {
+        return retVal;
+    }
+
+    if(IsSubOwner(&context->subject))
+    {
+        retVal = true;
+    }
+
+    if(true == retVal)
+    {
+        OIC_LOG(INFO, TAG, "PE.IsRequestFromSubOwner(): returning true");
+    }
+    else
+    {
+        OIC_LOG(INFO, TAG, "PE.IsRequestFromSubOwner(): returning false");
+    }
+
+    return retVal;
+}
+
+
+/**
+ * Verify the SubOwner's request.
+ *
+ * @return true if request is valid, else false.
+ */
+static bool IsValidRequestFromSubOwner(PEContext_t *context)
+{
+    bool isValidRequest = false;
+
+    if(NULL == context)
+    {
+        return isValidRequest;
+    }
+
+    switch(context->resourceType)
+    {
+        case OIC_R_DOXM_TYPE:
+            //SubOwner has READ permission only for DOXM
+            if(PERMISSION_READ == context->permission)
+            {
+                isValidRequest = true;
+            }
+            break;
+        case OIC_R_PSTAT_TYPE:
+            //SubOwner has full permsion for PSTAT
+            isValidRequest = true;
+            break;
+        case OIC_R_CRED_TYPE:
+            //SubOwner can only access the credential which is registered as the eowner.
+            isValidRequest = IsValidCredentialAccessForSubOwner(&context->subject, context->payload, context->payloadSize);
+            break;
+        case OIC_R_ACL_TYPE:
+            //SubOwner can only access the ACL which is registered as the eowner.
+            isValidRequest = IsValidAclAccessForSubOwner(&context->subject, context->payload, context->payloadSize);
+            break;
+        default:
+            //SubOwner has full permission for all resource except the security resource
+            isValidRequest = true;
+            break;
+    }
+
+    if(isValidRequest)
+    {
+        OIC_LOG(INFO, TAG, "PE.IsValidRequestFromSubOwner(): returning true");
+    }
+    else
+    {
+        OIC_LOG(INFO, TAG, "PE.IsValidRequestFromSubOwner(): returning false");
+    }
+
+    return isValidRequest;
+}
+#endif //_ENABLE_MULTIPLE_OWNER_
+
+
 // TODO - remove these function placeholders as they are implemented
 // in the resource entity handler code.
 // Note that because many SVRs do not have a rowner, in those cases we
@@ -495,7 +584,17 @@ SRMAccessResponse_t CheckPermission(PEContext_t     *context,
         {
             context->retVal = ACCESS_GRANTED;
         }
-        // If not granted via DevOwner status,
+#ifdef _ENABLE_MULTIPLE_OWNER_
+        //Then check if request from SubOwner
+        else if(IsRequestFromSubOwner(context))
+        {
+            if(IsValidRequestFromSubOwner(context))
+            {
+                context->retVal = ACCESS_GRANTED;
+            }
+        }
+#endif //_ENABLE_MULTIPLE_OWNER_
+        // If not granted via DevOwner status and not a subowner,
         // then check if request is for a SVR and coming from rowner
         else if (IsRequestFromResourceOwner(context))
         {
index 0dcb503..96b81ba 100644 (file)
@@ -203,6 +203,14 @@ void SRMRequestHandler(const CAEndpoint_t *endPoint, const CARequestInfo_t *requ
             }
         }
     }
+#ifdef _ENABLE_MULTIPLE_OWNER_
+    /*
+     * In case of ACL and CRED, The payload required to verify the payload.
+     * Payload information will be used for subowner's permission verification.
+     */
+    g_policyEngineContext.payload = (uint8_t*)requestInfo->info.payload;
+    g_policyEngineContext.payloadSize = requestInfo->info.payloadSize;
+#endif //_ENABLE_MULTIPLE_OWNER_
 
     //New request are only processed if the policy engine state is AWAITING_REQUEST.
     if (AWAITING_REQUEST == g_policyEngineContext.state)
index 4dcea24..df6cf5a 100644 (file)
@@ -94,9 +94,15 @@ const char * OIC_JSON_PERMISSION_NAME = "permission";
 const char * OIC_JSON_OWNERS_NAME = "ownrs";
 const char * OIC_JSON_OWNER_NAME = "ownr";
 const char * OIC_JSON_DEVOWNERID_NAME = "devowneruuid";
+#ifdef _ENABLE_MULTIPLE_OWNER_
+const char * OIC_JSON_SUBOWNERID_NAME = "x.org.iotivity.subowneruuid";
+#endif //_ENABLE_MULTIPLE_OWNER_
 const char * OIC_JSON_OWNED_NAME = "owned";
 const char * OIC_JSON_OXM_NAME = "oxm";
 const char * OIC_JSON_OXMS_NAME = "oxms";
+#ifdef _ENABLE_MULTIPLE_OWNER_
+const char * OIC_JSON_MOM_NAME = "x.org.iotivity.mom";
+#endif //_ENABLE_MULTIPLE_OWNER_
 const char * OIC_JSON_OXM_TYPE_NAME = "oxmtype";
 const char * OIC_JSON_OXM_SEL_NAME = "oxmsel";
 const char * OIC_JSON_DEVICE_ID_FORMAT_NAME = "didformat";
@@ -140,6 +146,9 @@ const char * OIC_JSON_REL_NAME = OC_RSRVD_REL;
 const char * OIC_JSON_RT_NAME = OC_RSRVD_RESOURCE_TYPE;
 const char * OIC_JSON_IF_NAME = OC_RSRVD_INTERFACE;
 const char * OIC_JSON_ROWNERID_NAME = "rowneruuid";
+#ifdef _ENABLE_MULTIPLE_OWNER_
+const char * OIC_JSON_EOWNERID_NAME = "x.org.iotivity.eowneruuid";
+#endif //_ENABLE_MULTIPLE_OWNER_
 const char * OIC_JSON_ENCODING_NAME = "encoding";
 const char * OIC_JSON_DATA_NAME = "data";
 const char * OIC_JSON_SEC_V_NAME = "secv";
@@ -159,6 +168,9 @@ const char * WILDCARD_RESOURCE_URI = "*";
 const char * OXM_JUST_WORKS = "oic.sec.doxm.jw";
 const char * OXM_RANDOM_DEVICE_PIN = "oic.sec.doxm.rdp";
 const char * OXM_MANUFACTURER_CERTIFICATE = "oic.sec.doxm.mfgcert";
+#ifdef _ENABLE_MULTIPLE_OWNER_
+const char * OXM_PRECONF_PIN = "oic.sec.doxm.pcp";
+#endif //_ENABLE_MULTIPLE_OWNER_
 
 //Credential data encoding methods
 const char * OIC_SEC_ENCODING_BASE64 = "oic.sec.encoding.base64";
index dd56ded..3131e13 100644 (file)
@@ -133,6 +133,10 @@ const char* GetOxmString(OicSecOxm_t oxmType)
             return OXM_RANDOM_DEVICE_PIN;
         case OIC_MANUFACTURER_CERTIFICATE:
             return OXM_MANUFACTURER_CERTIFICATE;
+#ifdef _ENABLE_MULTIPLE_OWNER_
+        case OIC_PRECONFIG_PIN:
+            return OXM_PRECONF_PIN;
+#endif //_ENABLE_MULTIPLE_OWNER_
         default:
             return NULL;
     }
index 46ee4b3..40dc5f9 100644 (file)
@@ -616,6 +616,18 @@ OicSecDoxm_t* JSONToDoxmBin(const char * jsonStr)
         doxm->dpc = jsonObj->valueint;
     }
 
+#ifdef _ENABLE_MULTIPLE_OWNER_
+    //mom -- Not Mandatory
+    jsonObj = cJSON_GetObjectItem(jsonDoxm, OIC_JSON_MOM_NAME);
+    if (jsonObj)
+    {
+        VERIFY_SUCCESS(TAG, (cJSON_Number == jsonObj->type), ERROR);
+        doxm->mom = (OicSecMom_t*)OICCalloc(1, sizeof(OicSecMom_t));
+        VERIFY_NON_NULL(TAG, doxm->mom, ERROR);
+        doxm->mom->mode = (OicSecMomType_t)jsonObj->valueint;
+    }
+#endif //_ENABLE_MULTIPLE_OWNER_
+
     //DeviceId -- Mandatory
     jsonObj = cJSON_GetObjectItem(jsonDoxm, OIC_JSON_DEVICE_ID_NAME);
     if (jsonObj)
index 435ec60..6df16cf 100644 (file)
@@ -67,6 +67,9 @@ if srmtest_env.get('SECURED') == '1':
 if srmtest_env.get('LOGGING') == '1':
        srmtest_env.AppendUnique(CPPDEFINES = ['TB_LOG'])
 
+if srmtest_env.get('MULTIPLE_OWNER') == '1':
+       srmtest_env.AppendUnique(CPPDEFINES=['_ENABLE_MULTIPLE_OWNER_'])
+
 if target_os == 'windows':
        srmtest_env.AppendUnique(LINKFLAGS = ['/subsystem:CONSOLE'])
        srmtest_env.AppendUnique(LIBS = ['advapi32', 'bcrypt', 'kernel32', 'ws2_32', 'iphlpapi', 'octbstack_static'])
@@ -119,7 +122,7 @@ srmtest_env.Alias("install", srmtest_env.Install( unittest_build_dir,
     unittest_src_dir + 'oic_svr_db_prov.dat'))
 srmtest_env.Alias("install", srmtest_env.Install( unittest_build_dir,
     unittest_src_dir + 'oic_svr_db.dat'))
-    
+
 srmtest_env.AppendTarget('test')
 if srmtest_env.get('TEST') == '1':
        if target_os in ['linux', 'windows']:
index 191cc67..762352d 100644 (file)
@@ -337,7 +337,7 @@ TEST(CredResourceTest, GenerateCredentialValidInput)
 
     OicSecCred_t * cred  = NULL;
     cred = GenerateCredential(&subject, SYMMETRIC_PAIR_WISE_KEY, NULL,
-                              &key, &rownerID);
+                              &key, &rownerID, NULL);
     printCred(cred);
 
     ASSERT_TRUE(NULL != cred);
@@ -359,7 +359,7 @@ TEST(CredResourceTest, GenerateAndAddCredentialValidInput)
     OicSecCred_t *headCred = NULL;
 
     cred1 = GenerateCredential(&subject, SYMMETRIC_PAIR_WISE_KEY, NULL,
-                               &key, &rownerID);
+                               &key, &rownerID, NULL);
 
     EXPECT_EQ(OC_STACK_OK, AddCredential(cred1));
     headCred = cred1;
@@ -367,13 +367,13 @@ TEST(CredResourceTest, GenerateAndAddCredentialValidInput)
     OICStrcpy((char *)rownerID.id, sizeof(rownerID.id), "ownersId22");
     OICStrcpy((char *)subject.id, sizeof(subject.id), "subject22");
     cred1 = GenerateCredential(&subject, SYMMETRIC_PAIR_WISE_KEY, NULL,
-                               &key, &rownerID);
+                               &key, &rownerID, NULL);
     EXPECT_EQ(OC_STACK_OK, AddCredential(cred1));
 
     OICStrcpy((char *)rownerID.id, sizeof(rownerID.id), "ownersId33");
     OICStrcpy((char *)subject.id, sizeof(subject.id), "subject33");
     cred1 = GenerateCredential(&subject, SYMMETRIC_PAIR_WISE_KEY, NULL,
-                               &key, &rownerID);
+                               &key, &rownerID, NULL);
     EXPECT_EQ(OC_STACK_OK, AddCredential(cred1));
 
     const OicSecCred_t* credList = GetCredResourceData(&headCred->subject);
index 317539a..93325b3 100644 (file)
@@ -289,7 +289,7 @@ static void userRequests(void *data)
 
         int request = 0;
         scanf("%d", &request);
-        getchar();
+        for( ; 0x20<=getchar(); );
 
         switch (request)
         {