0c950218060117d2935ea5077a7f620fd5abf41d
[platform/upstream/iotivity.git] / resource / csdk / security / provisioning / src / multipleownershiptransfermanager.c
1 /* *****************************************************************
2  *
3  * Copyright 2016 Samsung Electronics All Rights Reserved.
4  *
5  *
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  * *****************************************************************/
20
21 #ifdef HAVE_TIME_H
22 #include <time.h>
23 #endif
24 #ifdef HAVE_UNISTD_H
25 #include <unistd.h>
26 #endif
27 #ifdef HAVE_SYS_TIME_H
28 #include <sys/time.h>
29 #endif
30 #include <stdbool.h>
31 #include <string.h>
32
33 #include "utlist.h"
34 #include "logger.h"
35 #include "oic_malloc.h"
36 #include "oic_string.h"
37 #include "cacommon.h"
38 #include "cainterface.h"
39 #include "base64.h"
40 #include "cJSON.h"
41 #include "global.h"
42
43 #include "srmresourcestrings.h"
44 #include "doxmresource.h"
45 #include "pstatresource.h"
46 #include "credresource.h"
47 #include "aclresource.h"
48 #include "ownershiptransfermanager.h"
49 #include "securevirtualresourcetypes.h"
50 #include "oxmjustworks.h"
51 #include "pmtypes.h"
52 #include "pmutility.h"
53 #include "srmutility.h"
54 #include "provisioningdatabasemanager.h"
55 #include "oxmrandompin.h"
56 #include "ocpayload.h"
57 #include "payload_logging.h"
58 #include "oxmjustworks.h"
59 #include "oxmpreconfpin.h"
60 #include "oxmrandompin.h"
61
62 #define TAG "MULTIPLE_OTM"
63
64 /**********************************************************************
65  * API for Super Owner
66  **********************************************************************/
67
68 /**
69  * Structure to carry SuperOwner's multiple ownership transfer API data to callback.
70  */
71 typedef struct MOTContext MOTContext_t;
72 struct MOTContext
73 {
74     void *ctx;                                  /**< Pointer to user context.**/
75     const OCProvisionDev_t *deviceInfo;         /**< Pointer to OCProvisionDev_t.**/
76     OCProvisionResultCB resultCallback;         /**< Pointer to result callback.**/
77     OCProvisionResult_t *resArr;                /**< Result array.**/
78     int numOfResults;                           /**< Number of results in result array.**/
79     bool hasError;                              /**< Does MOT API have any error.. **/
80 };
81
82 /**
83  * Callback handler of security resource's POST request.
84  *
85  * @param[in] ctx             ctx value passed to callback from calling function.
86  * @param[in] UNUSED          handle to an invocation
87  * @param[in] clientResponse  Response from queries to remote servers.
88  * @return  OC_STACK_DELETE_TRANSACTION to delete the transaction
89  *          and  OC_STACK_KEEP_TRANSACTION to keep it.
90  */
91 static OCStackApplicationResult MOTUpdateSecurityResourceCB(void *ctx, OCDoHandle UNUSED,
92                                                 OCClientResponse *clientResponse)
93 {
94     OIC_LOG_V(INFO, TAG, "Inside MOTUpdateMomCB.");
95     (void)UNUSED;
96     MOTContext_t *motCtx = (MOTContext_t*)ctx;
97     VERIFY_NON_NULL(TAG, motCtx, ERROR);
98     VERIFY_NON_NULL(TAG, motCtx->resultCallback, ERROR);
99     VERIFY_NON_NULL(TAG, motCtx->resArr, ERROR);
100
101     if(clientResponse)
102     {
103         memcpy(motCtx->resArr[0].deviceId.id, motCtx->deviceInfo->doxm->deviceID.id, sizeof(OicUuid_t));
104         motCtx->resArr[0].res = clientResponse->result;
105
106         if(OC_STACK_RESOURCE_CHANGED == clientResponse->result)
107         {
108             motCtx->hasError = false;
109         }
110         else
111         {
112             motCtx->hasError = true;
113         }
114     }
115     else
116     {
117         OIC_LOG_V(ERROR, TAG, "SRPGetACLResourceCB received Null clientResponse");
118         motCtx->resArr[0].res = OC_STACK_ERROR;
119         motCtx->hasError = true;
120     }
121
122     motCtx->resultCallback(motCtx->ctx, motCtx->numOfResults, motCtx->resArr, motCtx->hasError);
123
124 exit:
125     if(motCtx)
126     {
127         OICFree(motCtx->resArr);
128         OICFree(motCtx);
129     }
130     return OC_STACK_DELETE_TRANSACTION;
131 }
132
133 /**
134  * Internal API to send POST doxm request
135  */
136 static OCStackResult MOTSendPostDoxm(void *ctx,
137                                      const OCProvisionDev_t *targetDeviceInfo,
138                                      OCProvisionResultCB resultCallback,
139                                      const OicSecDoxm_t* doxm)
140 {
141     OCStackResult postMomRes = OC_STACK_ERROR;
142     OCSecurityPayload* secPayload = NULL;
143     MOTContext_t *motCtx = NULL;
144     bool freeFlag = true;
145
146     OIC_LOG(DEBUG, TAG, "IN MOTSendPostDoxm");
147
148     //Generate the security payload using updated doxm
149     secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
150     VERIFY_NON_NULL(TAG, secPayload, ERROR);
151     secPayload->base.type = PAYLOAD_TYPE_SECURITY;
152
153     postMomRes = DoxmToCBORPayload(doxm, &secPayload->securityData, &secPayload->payloadSize, true);
154     VERIFY_SUCCESS(TAG, (OC_STACK_OK == postMomRes), ERROR);
155
156     OIC_LOG(DEBUG, TAG, "Created doxm payload to update doxm:");
157     OIC_LOG_BUFFER(DEBUG, TAG, secPayload->securityData, secPayload->payloadSize);
158
159     char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
160     bool queryGenRes = PMGenerateQuery(true,
161                                        targetDeviceInfo->endpoint.addr,
162                                        targetDeviceInfo->securePort,
163                                        targetDeviceInfo->connType,
164                                        query, sizeof(query), OIC_RSRC_DOXM_URI);
165     VERIFY_SUCCESS(TAG, (true == queryGenRes), ERROR);
166     OIC_LOG_V(DEBUG, TAG, "Query=%s", query);
167
168     //Create the MOT Context to handle the response message
169     motCtx = (MOTContext_t*)OICCalloc(1, sizeof(MOTContext_t));
170     VERIFY_NON_NULL(TAG, motCtx, ERROR);
171     motCtx->deviceInfo = targetDeviceInfo;
172     motCtx->resultCallback = resultCallback;
173     motCtx->numOfResults=1;
174     motCtx->hasError = false;
175     motCtx->ctx = ctx;
176     motCtx->resArr = (OCProvisionResult_t*)OICCalloc(1, sizeof(OCProvisionResult_t));
177     VERIFY_NON_NULL(TAG, motCtx->resArr, ERROR);
178
179     //Send POST request
180     OCCallbackData cbData =  {.context=NULL, .cb=NULL, .cd=NULL};
181     cbData.cb = &MOTUpdateSecurityResourceCB;
182     cbData.context = (void *)motCtx;
183     OIC_LOG(DEBUG, TAG, "Sending POST 'doxm' request to resource server");
184     postMomRes = OCDoResource(NULL, OC_REST_POST, query,
185                               &targetDeviceInfo->endpoint, (OCPayload*)secPayload,
186                               targetDeviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0);
187     VERIFY_SUCCESS(TAG, (OC_STACK_OK == postMomRes), ERROR);
188
189     freeFlag = false;
190
191     OIC_LOG(DEBUG, TAG, "OUT MOTSendPostDoxm");
192
193 exit:
194     //If POST request successfully sent, motCtx will be cleaned from response handler.
195     if(freeFlag && motCtx)
196     {
197         OICFree(motCtx->resArr);
198         OICFree(motCtx);
199     }
200
201     return postMomRes;
202 }
203
204 /**
205  * API to update 'doxm.mom' to resource server.
206  *
207  * @param[in] targetDeviceInfo Selected target device.
208  * @param[in] momType Mode of multiple ownership transfer (ref. oic.sec.mom)
209  * @param[in] resultCallback callback provided by API user, callback will be called when
210  *            POST 'mom' request recieves a response from resource server.
211  * @return OC_STACK_OK in case of success and other value otherwise.
212  */
213 OCStackResult MOTChangeMode(void *ctx, const OCProvisionDev_t *targetDeviceInfo,
214                             const OicSecMomType_t momType, OCProvisionResultCB resultCallback)
215 {
216     OCStackResult postMomRes = OC_STACK_INVALID_PARAM;
217     OicSecDoxm_t* doxm = NULL;
218     uint8_t* doxmPayload = NULL;
219     size_t doxmPayloadLen = 0;
220
221     OIC_LOG(DEBUG, TAG, "IN MOTChangeMode");
222
223     VERIFY_NON_NULL(TAG, targetDeviceInfo, ERROR);
224     VERIFY_NON_NULL(TAG, resultCallback, ERROR);
225
226     //Dulpicate doxm resource to update the 'mom' property
227     postMomRes = DoxmToCBORPayload(targetDeviceInfo->doxm, &doxmPayload, &doxmPayloadLen, false);
228     VERIFY_SUCCESS(TAG, (OC_STACK_OK == postMomRes), ERROR);
229
230     postMomRes = CBORPayloadToDoxm(doxmPayload, doxmPayloadLen, &doxm);
231     VERIFY_SUCCESS(TAG, (OC_STACK_OK == postMomRes), ERROR);
232     VERIFY_NON_NULL(TAG, doxm, ERROR);
233
234     if(NULL == doxm->mom)
235     {
236         doxm->mom = (OicSecMom_t*)OICCalloc(1, sizeof(OicSecMom_t));
237         VERIFY_NON_NULL(TAG, (doxm->mom), ERROR);
238     }
239     doxm->mom->mode = momType;
240
241     //Send POST reuqest for update doxm
242     postMomRes = MOTSendPostDoxm(ctx, targetDeviceInfo, resultCallback, doxm);
243     VERIFY_SUCCESS(TAG, (OC_STACK_OK == postMomRes), ERROR);
244
245     OIC_LOG(DEBUG, TAG, "OUT MOTChangeMode");
246
247 exit:
248     OICFree(doxmPayload);
249     DeleteDoxmBinData(doxm);
250     return postMomRes;
251 }
252
253 /**
254  * API to add 'doxm.oxms' to resource server.
255  *
256  * @param[in] targetDeviceInfo Selected target device.
257  * @param[in] newOxm  OxMs to be added (ref. oic.sec.oxm)
258  * @param[in] resultCallback callback provided by API user, callback will be called when
259  *            POST 'oxms' request recieves a response from resource server.
260  * @return OC_STACK_OK in case of success and other value otherwise.
261  */
262 OCStackResult MOTAddMOTMethod(void *ctx, OCProvisionDev_t *targetDeviceInfo,
263                                  const OicSecOxm_t newOxm, OCProvisionResultCB resultCallback)
264 {
265     OCStackResult postOxmRes = OC_STACK_INVALID_PARAM;
266     OicSecOxm_t* newOxms = NULL;
267     uint8_t* doxmPayload = NULL;
268     size_t doxmPayloadLen = 0;
269
270     OIC_LOG(DEBUG, TAG, "IN MOTAddMOTMethod");
271
272     VERIFY_NON_NULL(TAG, targetDeviceInfo, ERROR);
273     VERIFY_NON_NULL(TAG, resultCallback, ERROR);
274
275     for(size_t i = 0; i < targetDeviceInfo->doxm->oxmLen; i++)
276     {
277         if(targetDeviceInfo->doxm->oxm[i] == newOxm)
278         {
279             OIC_LOG_V(INFO, TAG, "[%d] OxM already supported", (int)newOxm);
280
281             OCProvisionResult_t* resArr = (OCProvisionResult_t*)OICCalloc(1, sizeof(OCProvisionResult_t));
282             resArr->res = OC_STACK_OK;
283             memcpy(resArr->deviceId.id, targetDeviceInfo->doxm->deviceID.id, sizeof(resArr->deviceId.id));
284             resultCallback(ctx, 1, resArr, false);
285
286             return OC_STACK_OK;
287         }
288     }
289
290     newOxms = (OicSecOxm_t*)OICMalloc(sizeof(OicSecOxm_t) * (targetDeviceInfo->doxm->oxmLen + 1));
291     VERIFY_NON_NULL(TAG, newOxms , ERROR);
292
293     for(size_t i = 0; i < targetDeviceInfo->doxm->oxmLen; i++)
294     {
295         newOxms[i] = targetDeviceInfo->doxm->oxm[i];
296     }
297     newOxms[targetDeviceInfo->doxm->oxmLen] = newOxm;
298     targetDeviceInfo->doxm->oxmLen++;
299     OICFree(targetDeviceInfo->doxm->oxm);
300     targetDeviceInfo->doxm->oxm = newOxms;
301
302     //Send POST reuqest for update doxm
303     postOxmRes = MOTSendPostDoxm(ctx, targetDeviceInfo, resultCallback, targetDeviceInfo->doxm);
304     VERIFY_SUCCESS(TAG, (OC_STACK_OK == postOxmRes), ERROR);
305
306     OIC_LOG(DEBUG, TAG, "OUT MOTAddMOTMethod");
307
308 exit:
309     OICFree(doxmPayload);
310     return postOxmRes;
311 }
312
313 /**
314  * API to update 'doxm.oxmsel' to resource server.
315  *
316  * @param[in] targetDeviceInfo Selected target device.
317   * @param[in] oxmSelValue Method of multiple ownership transfer (ref. oic.sec.oxm)
318  * @param[in] resultCallback callback provided by API user, callback will be called when
319  *            POST 'oxmsel' request recieves a response from resource server.
320  * @return OC_STACK_OK in case of success and other value otherwise.
321  */
322 OCStackResult MOTSelectMOTMethod(void *ctx, const OCProvisionDev_t *targetDeviceInfo,
323                                  const OicSecOxm_t oxmSelValue, OCProvisionResultCB resultCallback)
324 {
325     OCStackResult postMomRes = OC_STACK_INVALID_PARAM;
326     OicSecDoxm_t* doxm = NULL;
327     uint8_t* doxmPayload = NULL;
328     size_t doxmPayloadLen = 0;
329
330     OIC_LOG(DEBUG, TAG, "IN MOTSelectOTMethod");
331
332     VERIFY_NON_NULL(TAG, targetDeviceInfo, ERROR);
333     VERIFY_NON_NULL(TAG, resultCallback, ERROR);
334
335     bool isValidOxmsel = false;
336     for(size_t i = 0; i < targetDeviceInfo->doxm->oxmLen; i++)
337     {
338         if(targetDeviceInfo->doxm->oxm[i] == oxmSelValue)
339         {
340             isValidOxmsel = true;
341             break;
342         }
343     }
344     VERIFY_SUCCESS(TAG, isValidOxmsel, ERROR);
345
346     //Dulpicate doxm resource to update the 'oxmsel' property
347     postMomRes = DoxmToCBORPayload(targetDeviceInfo->doxm, &doxmPayload, &doxmPayloadLen, false);
348     VERIFY_SUCCESS(TAG, (OC_STACK_OK == postMomRes), ERROR);
349
350     postMomRes = CBORPayloadToDoxm(doxmPayload, doxmPayloadLen, &doxm);
351     VERIFY_SUCCESS(TAG, (OC_STACK_OK == postMomRes), ERROR);
352     VERIFY_NON_NULL(TAG, doxm, ERROR);
353
354     doxm->oxmSel = oxmSelValue;
355
356     //Send POST reuqest for update doxm
357     postMomRes = MOTSendPostDoxm(ctx, targetDeviceInfo, resultCallback, doxm);
358     VERIFY_SUCCESS(TAG, (OC_STACK_OK == postMomRes), ERROR);
359
360     OIC_LOG(DEBUG, TAG, "OUT MOTSelectOTMethod");
361
362 exit:
363     OICFree(doxmPayload);
364     DeleteDoxmBinData(doxm);
365     return postMomRes;
366 }
367
368 /**
369  * API to provision preconfigured PIN to resource server.
370  *
371  * @param[in] targetDeviceInfo Selected target device.
372  * @param[in] preconfPIN Preconfig PIN which is used while multiple owner authentication
373  * @param[in] preconfPINLen Byte length of preconfig PIN
374  * @param[in] resultCallback callback provided by API user, callback will be called when
375  *            POST credential request recieves a response from resource server.
376  * @return OC_STACK_OK in case of success and other value otherwise.
377  */
378 OCStackResult MOTProvisionPreconfigPIN(void *ctx, const OCProvisionDev_t *targetDeviceInfo,
379                                  const char* preconfPIN, size_t preconfPINLen, OCProvisionResultCB resultCallback)
380 {
381     OCStackResult postCredRes = OC_STACK_INVALID_PARAM;
382     bool freeFlag = true;
383     OCSecurityPayload* secPayload = NULL;
384     MOTContext_t *motCtx = NULL;
385     OicSecCred_t* pinCred = NULL;
386
387     OIC_LOG(DEBUG, TAG, "IN MOTProvisionPreconfigPIN");
388
389     VERIFY_NON_NULL(TAG, targetDeviceInfo, ERROR);
390     VERIFY_NON_NULL(TAG, resultCallback, ERROR);
391     VERIFY_NON_NULL(TAG, preconfPIN, ERROR);
392     VERIFY_SUCCESS(TAG, (0 != preconfPINLen), ERROR);
393     VERIFY_SUCCESS(TAG, (0 != preconfPINLen && OXM_PRECONFIG_PIN_SIZE >= preconfPINLen), ERROR);
394
395     postCredRes = OC_STACK_NO_MEMORY;
396     //Generate PIN based credential
397     pinCred = (OicSecCred_t*)OICCalloc(1, sizeof(OicSecCred_t));
398     VERIFY_NON_NULL(TAG, pinCred, ERROR);
399
400     pinCred->privateData.data = (uint8_t*)OICMalloc(preconfPINLen + 1);
401     VERIFY_NON_NULL(TAG, pinCred->privateData.data, ERROR);
402
403     memcpy(pinCred->privateData.data, preconfPIN, preconfPINLen);
404     pinCred->privateData.data[preconfPINLen] = '\0';
405     pinCred->privateData.len = preconfPINLen;
406     pinCred->privateData.encoding = OIC_ENCODING_RAW;
407     pinCred->credType = PIN_PASSWORD;
408     OICStrcpy(pinCred->subject.id, sizeof(pinCred->subject.id), WILDCARD_SUBJECT_ID.id);
409
410     //Generate the security payload using updated doxm
411     secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
412     VERIFY_NON_NULL(TAG, secPayload, ERROR);
413     secPayload->base.type = PAYLOAD_TYPE_SECURITY;
414
415     postCredRes = CredToCBORPayload(pinCred, &secPayload->securityData, &secPayload->payloadSize, false);
416     VERIFY_SUCCESS(TAG, (OC_STACK_OK == postCredRes), ERROR);
417
418     OIC_LOG(DEBUG, TAG, "Created Credential payload to register PIN credential:");
419     OIC_LOG_BUFFER(DEBUG, TAG, secPayload->securityData, secPayload->payloadSize);
420
421     char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
422     bool queryGenRes = PMGenerateQuery(true,
423                                        targetDeviceInfo->endpoint.addr,
424                                        targetDeviceInfo->securePort,
425                                        targetDeviceInfo->connType,
426                                        query, sizeof(query), OIC_RSRC_CRED_URI);
427     VERIFY_SUCCESS(TAG, (true == queryGenRes), ERROR);
428     OIC_LOG_V(DEBUG, TAG, "Query=%s", query);
429
430     //Create the MOT Context to handle the response message
431     motCtx = (MOTContext_t*)OICCalloc(1, sizeof(MOTContext_t));
432     VERIFY_NON_NULL(TAG, motCtx, ERROR);
433     motCtx->deviceInfo = targetDeviceInfo;
434     motCtx->resultCallback = resultCallback;
435     motCtx->numOfResults=1;
436     motCtx->hasError = false;
437     motCtx->ctx = ctx;
438     motCtx->resArr = (OCProvisionResult_t*)OICCalloc(1, sizeof(OCProvisionResult_t));
439     VERIFY_NON_NULL(TAG, motCtx->resArr, ERROR);
440
441     //Send POST request
442     OCCallbackData cbData =  {.context=NULL, .cb=NULL, .cd=NULL};
443     cbData.cb = &MOTUpdateSecurityResourceCB;
444     cbData.context = (void *)motCtx;
445     OIC_LOG(DEBUG, TAG, "Sending POST Preconfiged PIN credenatial request to resource server");
446     postCredRes = OCDoResource(NULL, OC_REST_POST, query,
447                               &targetDeviceInfo->endpoint, (OCPayload*)secPayload,
448                               targetDeviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0);
449     VERIFY_SUCCESS(TAG, (OC_STACK_OK == postCredRes), ERROR);
450
451     freeFlag = false;
452
453     OIC_LOG(DEBUG, TAG, "OUT MOTProvisionPreconfigPIN");
454
455     return postCredRes;
456
457 exit:
458     //If POST request successfully sent, motCtx will be cleaned from response handler.
459     if(freeFlag && motCtx)
460     {
461         OICFree(motCtx->resArr);
462         OICFree(motCtx);
463     }
464     if(pinCred)
465     {
466         OICFree(pinCred->privateData.data);
467         OICFree(pinCred);
468     }
469     return postCredRes;
470 }
471
472
473 /**********************************************************************
474  * API for Sub Owner
475  **********************************************************************/
476
477 static OCStackResult StartMultipleOwnershipTransfer(OTMContext_t* motCtx,
478                                                     OCProvisionDev_t* selectedDevice);
479
480 /**
481  * Array to store the callbacks for each owner transfer method.
482  */
483 static OTMCallbackData_t g_MOTCbDatas[OIC_OXM_COUNT] = {
484         //Just works
485         {.loadSecretCB = LoadSecretJustWorksCallback,
486           .createSecureSessionCB = CreateSecureSessionJustWorksCallback,
487           .createSelectOxmPayloadCB = NULL,
488           .createOwnerTransferPayloadCB = NULL},
489
490           //Random PIN
491         {.loadSecretCB = InputPinCodeCallback,
492           .createSecureSessionCB = CreateSecureSessionRandomPinCallback,
493           .createSelectOxmPayloadCB = NULL,
494           .createOwnerTransferPayloadCB = NULL},
495
496         //Manufacturer Cert
497         {.loadSecretCB = NULL,
498           .createSecureSessionCB = NULL,
499           .createSelectOxmPayloadCB = NULL,
500           .createOwnerTransferPayloadCB = NULL},
501
502           //Preconfig PIN
503         {.loadSecretCB = LoadPreconfPinCodeCallback,
504           .createSecureSessionCB = CreateSecureSessionPreconfPinCallback,
505           .createSelectOxmPayloadCB = NULL,
506           .createOwnerTransferPayloadCB = NULL},
507 };
508
509 static OTMContext_t* g_MotCtx = NULL;
510
511 static bool IsComplete(OTMContext_t* otmCtx)
512 {
513     for(size_t i = 0; i < otmCtx->ctxResultArraySize; i++)
514     {
515         if(OC_STACK_CONTINUE == otmCtx->ctxResultArray[i].res)
516         {
517             return false;
518         }
519     }
520
521     return true;
522 }
523
524 /**
525  * Function to save the result of multiple ownership transfer.
526  *
527  * @param[in,out] motCtx   Context instance of multiple ownership transfer.
528  * @param[in] res   result of multiple ownership transfer.
529  */
530 static void SetMOTResult(OTMContext_t* motCtx, const OCStackResult res)
531 {
532     OIC_LOG_V(DEBUG, TAG, "IN SetMOTResult : %d ", res);
533
534     VERIFY_NON_NULL(TAG, motCtx, ERROR);
535
536     if(motCtx->selectedDeviceInfo)
537     {
538         //Revert psk_info callback in case of random PIN OxM
539         if(OIC_RANDOM_DEVICE_PIN == motCtx->selectedDeviceInfo->doxm->oxmSel ||
540            OIC_PRECONFIG_PIN == motCtx->selectedDeviceInfo->doxm->oxmSel)
541         {
542             if(CA_STATUS_OK != CAregisterPskCredentialsHandler(GetDtlsPskCredentials))
543             {
544                 OIC_LOG(WARNING, TAG, "Failed to revert the DTLS credential handler.");
545             }
546             OicUuid_t emptyUuid = { .id={0}};
547             SetUuidForPinBasedOxm(&emptyUuid);
548         }
549
550         for(size_t i = 0; i < motCtx->ctxResultArraySize; i++)
551         {
552             if(memcmp(motCtx->selectedDeviceInfo->doxm->deviceID.id,
553                       motCtx->ctxResultArray[i].deviceId.id, UUID_LENGTH) == 0)
554             {
555                 motCtx->ctxResultArray[i].res = res;
556                 if(OC_STACK_OK != res)
557                 {
558                     motCtx->ctxHasError = true;
559                 }
560             }
561         }
562
563         g_MotCtx = NULL;
564
565         //If all request is completed, invoke the user callback.
566         if(IsComplete(motCtx))
567         {
568             motCtx->ctxResultCallback(motCtx->userCtx, motCtx->ctxResultArraySize,
569                                        motCtx->ctxResultArray, motCtx->ctxHasError);
570
571             OICFree(motCtx->ctxResultArray);
572             OICFree(motCtx);
573         }
574         else
575         {
576             if(OC_STACK_OK != StartMultipleOwnershipTransfer(motCtx,
577                                                      motCtx->selectedDeviceInfo->next))
578             {
579                 OIC_LOG(ERROR, TAG, "Failed to StartMultipleOwnershipTransfer");
580             }
581         }
582     }
583
584 exit:
585     OIC_LOG(DEBUG, TAG, "OUT SetMOTResult");
586 }
587
588 /**
589  * API to add preconfigured PIN to local SVR DB.
590  *
591  * @param[in] targetDeviceInfo Selected target device.
592  * @param[in] preconfPIN Preconfig PIN which is used while multiple owner authentication
593  * @param[in] preconfPINLen Byte length of preconfig PIN
594  * @param[in] resultCallback callback provided by API user, callback will be called when
595  *            POST credential request recieves a response from resource server.
596  * @return OC_STACK_OK in case of success and other value otherwise.
597  */
598 OCStackResult MOTAddPreconfigPIN(const OCProvisionDev_t *targetDeviceInfo,
599                                  const char* preconfPIN, size_t preconfPINLen)
600 {
601     OCStackResult addCredRes = OC_STACK_INVALID_PARAM;
602     OicSecCred_t* pinCred = NULL;
603     bool freeFlag = true;
604
605     OIC_LOG(DEBUG, TAG, "IN MOTAddPreconfigPIN");
606
607     VERIFY_NON_NULL(TAG, targetDeviceInfo, ERROR);
608     VERIFY_NON_NULL(TAG, preconfPIN, ERROR);
609     VERIFY_SUCCESS(TAG, (0 != preconfPINLen), ERROR);
610     VERIFY_SUCCESS(TAG, (0 != preconfPINLen && OXM_PRECONFIG_PIN_SIZE >= preconfPINLen), ERROR);
611
612     OicSecCred_t* prevCred = GetCredResourceData(&targetDeviceInfo->doxm->deviceID);
613     if(NULL != prevCred)
614     {
615         OIC_LOG(INFO, TAG, "PIN/PW Credential already exist!");
616         return OC_STACK_OK;
617     }
618
619     addCredRes = OC_STACK_NO_MEMORY;
620     //Generate PIN based credential
621     pinCred = (OicSecCred_t*)OICCalloc(1, sizeof(OicSecCred_t));
622     VERIFY_NON_NULL(TAG, pinCred, ERROR);
623
624     pinCred->privateData.data = (uint8_t*)OICMalloc(preconfPINLen + 1);
625     VERIFY_NON_NULL(TAG, pinCred->privateData.data, ERROR);
626
627     memcpy(pinCred->privateData.data, preconfPIN, preconfPINLen);
628     pinCred->privateData.data[preconfPINLen] = '\0';
629     pinCred->privateData.len = preconfPINLen;
630     pinCred->privateData.encoding = OIC_ENCODING_RAW;
631     pinCred->credType = PIN_PASSWORD;
632     memcpy(pinCred->subject.id, targetDeviceInfo->doxm->deviceID.id, sizeof(pinCred->subject.id));
633
634     addCredRes = AddCredential(pinCred);
635     VERIFY_SUCCESS(TAG, (OC_STACK_OK == addCredRes), ERROR);
636
637     OIC_LOG(DEBUG, TAG, "OUT MOTAddPreconfigPIN");
638
639     return addCredRes;
640
641 exit:
642     if(pinCred)
643     {
644         OICFree(pinCred->privateData.data);
645         OICFree(pinCred);
646     }
647     return addCredRes;
648 }
649
650 /**
651  * Function to save the SubOwner PSK.
652  *
653  * @param[in] selectedDeviceInfo   selected device information to performing provisioning.
654  * @return  OC_STACK_OK on success
655  */
656 static OCStackResult SaveSubOwnerPSK(OCProvisionDev_t *selectedDeviceInfo)
657 {
658     OIC_LOG(DEBUG, TAG, "IN SaveSubOwnerPSK");
659
660     OCStackResult res = OC_STACK_ERROR;
661
662     CAEndpoint_t endpoint;
663     memset(&endpoint, 0x00, sizeof(CAEndpoint_t));
664     OICStrcpy(endpoint.addr, MAX_ADDR_STR_SIZE_CA, selectedDeviceInfo->endpoint.addr);
665     endpoint.addr[MAX_ADDR_STR_SIZE_CA - 1] = '\0';
666     endpoint.port = selectedDeviceInfo->securePort;
667     endpoint.adapter = selectedDeviceInfo->endpoint.adapter;
668
669     OicUuid_t ownerDeviceID = {.id={0}};
670     if (OC_STACK_OK != GetDoxmDeviceID(&ownerDeviceID))
671     {
672         OIC_LOG(ERROR, TAG, "Error while retrieving SubOwner's device ID");
673         return res;
674     }
675
676     uint8_t ownerPSK[OWNER_PSK_LENGTH_128] = {0};
677     OicSecKey_t ownerKey = {ownerPSK, OWNER_PSK_LENGTH_128};
678
679     //Generating SubOwnerPSK
680     CAResult_t pskRet = CAGenerateOwnerPSK(&endpoint,
681             (uint8_t *)GetOxmString(selectedDeviceInfo->doxm->oxmSel),
682             strlen(GetOxmString(selectedDeviceInfo->doxm->oxmSel)),
683             ownerDeviceID.id, sizeof(ownerDeviceID.id),
684             selectedDeviceInfo->doxm->deviceID.id, sizeof(selectedDeviceInfo->doxm->deviceID.id),
685             ownerPSK, OWNER_PSK_LENGTH_128);
686
687     if (CA_STATUS_OK == pskRet)
688     {
689         OIC_LOG(INFO, TAG, "SubOwner PSK dump:");
690         OIC_LOG_BUFFER(INFO, TAG, ownerPSK, OWNER_PSK_LENGTH_128);
691         //Generating new credential for provisioning tool
692         OicSecCred_t *cred = GenerateCredential(&selectedDeviceInfo->doxm->deviceID,
693                                       SYMMETRIC_PAIR_WISE_KEY, NULL,
694                                       &ownerKey, &ownerDeviceID, &ownerDeviceID);
695         VERIFY_NON_NULL(TAG, cred, ERROR);
696
697         uint32_t outSize = 0;
698         size_t b64BufSize = B64ENCODE_OUT_SAFESIZE((OWNER_PSK_LENGTH_128 + 1));
699         char* b64Buf = (uint8_t *)OICCalloc(1, b64BufSize);
700         VERIFY_NON_NULL(TAG, b64Buf, ERROR);
701         b64Encode(cred->privateData.data, cred->privateData.len, b64Buf, b64BufSize, &outSize);
702
703         OICFree( cred->privateData.data );
704         cred->privateData.data = (uint8_t *)OICCalloc(1, outSize + 1);
705         VERIFY_NON_NULL(TAG, cred->privateData.data, ERROR);
706
707         strncpy(cred->privateData.data, b64Buf, outSize);
708         cred->privateData.data[outSize] = '\0';
709         cred->privateData.encoding = OIC_ENCODING_BASE64;
710         cred->privateData.len = outSize;
711         OICFree(b64Buf);
712
713         //Add SubOwnerPSK
714         res = AddCredential(cred);
715         if(res != OC_STACK_OK)
716         {
717             DeleteCredList(cred);
718             return res;
719         }
720     }
721     else
722     {
723         OIC_LOG(ERROR, TAG, "CAGenerateOwnerPSK failed");
724     }
725
726     OIC_LOG(DEBUG, TAG, "OUT SaveSubOwnerPSK");
727 exit:
728     return res;
729 }
730
731
732 /**
733  * Response handler for update subowner crendetial request.
734  *
735  * @param[in] ctx             ctx value passed to callback from calling function.
736  * @param[in] UNUSED          handle to an invocation
737  * @param[in] clientResponse  Response from queries to remote servers.
738  * @return  OC_STACK_DELETE_TRANSACTION to delete the transaction
739  *          and  OC_STACK_KEEP_TRANSACTION to keep it.
740  */
741 static OCStackApplicationResult SubOwnerCredentialHandler(void *ctx, OCDoHandle UNUSED,
742                                 OCClientResponse *clientResponse)
743 {
744     VERIFY_NON_NULL(TAG, clientResponse, WARNING);
745     VERIFY_NON_NULL(TAG, ctx, WARNING);
746
747     OIC_LOG(DEBUG, TAG, "IN SubOwnerCredentialHandler");
748     (void)UNUSED;
749     OCStackResult res = OC_STACK_ERROR;
750     OTMContext_t* motCtx = (OTMContext_t*)ctx;
751
752     if(OC_STACK_RESOURCE_CHANGED == clientResponse->result)
753     {
754         if(motCtx && motCtx->selectedDeviceInfo)
755         {
756             //Close the temporal secure session to verify the owner credential
757             CAEndpoint_t* endpoint = (CAEndpoint_t *)&motCtx->selectedDeviceInfo->endpoint;
758             endpoint->port = motCtx->selectedDeviceInfo->securePort;
759             CAResult_t caResult = CAcloseSslSession(endpoint);
760             if(CA_STATUS_OK != caResult)
761             {
762                 OIC_LOG(ERROR, TAG, "Failed to close DTLS session");
763                 SetMOTResult(motCtx, OC_STACK_ERROR);
764                 return OC_STACK_DELETE_TRANSACTION;
765             }
766
767             // TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256 = 0xC037, /**< see RFC 5489 */
768             caResult = CASelectCipherSuite(0xC037, endpoint->adapter);
769             if(CA_STATUS_OK != caResult)
770             {
771                 OIC_LOG(ERROR, TAG, "Failed to select TLS_NULL_WITH_NULL_NULL");
772                 SetMOTResult(motCtx, OC_STACK_ERROR);
773                 return OC_STACK_DELETE_TRANSACTION;
774             }
775
776             res = PDMAddDevice(&motCtx->selectedDeviceInfo->doxm->deviceID);
777              if (OC_STACK_OK == res)
778              {
779                     OIC_LOG_V(INFO, TAG, "Add device's UUID in PDM_DB");
780              }
781               else
782              {
783                   OIC_LOG(ERROR, TAG, "MOT is complete but adding information to DB is failed.");
784              }
785
786             SetMOTResult(motCtx, res);
787         }
788     }
789     else
790     {
791         res = clientResponse->result;
792         OIC_LOG_V(ERROR, TAG, "SubOwnerCredentialHandler : Unexpected result %d", res);
793         SetMOTResult(motCtx, res);
794     }
795
796     OIC_LOG(DEBUG, TAG, "OUT SubOwnerCredentialHandler");
797
798 exit:
799     return  OC_STACK_DELETE_TRANSACTION;
800 }
801
802
803 static OCStackResult PostSubOwnerCredential(OTMContext_t* motCtx)
804 {
805     OIC_LOG(DEBUG, TAG, "IN PostSubOwnerCredential");
806
807     if(!motCtx || !motCtx->selectedDeviceInfo)
808     {
809         OIC_LOG(ERROR, TAG, "Invalid parameters");
810         return OC_STACK_INVALID_PARAM;
811     }
812
813     OCProvisionDev_t* deviceInfo = motCtx->selectedDeviceInfo;
814     char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
815
816     if(!PMGenerateQuery(true,
817                         deviceInfo->endpoint.addr, deviceInfo->securePort,
818                         deviceInfo->connType,
819                         query, sizeof(query), OIC_RSRC_CRED_URI))
820     {
821         OIC_LOG(ERROR, TAG, "PostSubOwnerCredential : Failed to generate query");
822         return OC_STACK_ERROR;
823     }
824     OIC_LOG_V(DEBUG, TAG, "Query=%s", query);
825     OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
826     if(!secPayload)
827     {
828         OIC_LOG(ERROR, TAG, "Failed to memory allocation");
829         return OC_STACK_NO_MEMORY;
830     }
831
832     //Generate sub-owner credential for new device
833     secPayload->base.type = PAYLOAD_TYPE_SECURITY;
834     const OicSecCred_t* ownerCredential = GetCredResourceData(&(deviceInfo->doxm->deviceID));
835     if(!ownerCredential)
836     {
837         OIC_LOG(ERROR, TAG, "Can not find SubOwnerPSK.");
838         return OC_STACK_NO_RESOURCE;
839     }
840
841     OicUuid_t ownerId = {.id={0}};
842     if(OC_STACK_OK == GetDoxmDeviceID(&ownerId))
843     {
844         OicSecCred_t newCredential;
845         memcpy(&newCredential, ownerCredential, sizeof(OicSecCred_t));
846         newCredential.next = NULL;
847
848         //Set subject ID as SubOwner's ID
849         memcpy(&(newCredential.subject), &ownerId, sizeof(OicUuid_t));
850
851         //Set eowner ID as SubOwner's ID
852         if(NULL == newCredential.eownerID)
853         {
854             newCredential.eownerID = OICCalloc(1, sizeof(OicUuid_t));
855             if(NULL == newCredential.eownerID)
856             {
857                 return OC_STACK_NO_MEMORY;
858             }
859         }
860         memcpy(newCredential.eownerID->id, ownerId.id, sizeof(ownerId.id));
861
862         //Fill private data as empty string
863         newCredential.privateData.data = "";
864         newCredential.privateData.len = 0;
865         newCredential.privateData.encoding = ownerCredential->privateData.encoding;
866 #ifdef __WITH_X509__
867         newCredential.publicData.data = NULL;
868         newCredential.publicData.len = 0;
869 #endif
870         //Send owner credential to new device : POST /oic/sec/cred [ owner credential ]
871         if (OC_STACK_OK != CredToCBORPayload(&newCredential, &secPayload->securityData,
872                                         &secPayload->payloadSize, 0))
873         {
874             OICFree(secPayload);
875             OIC_LOG(ERROR, TAG, "Error while converting bin to cbor.");
876             return OC_STACK_ERROR;
877         }
878         OIC_LOG(DEBUG, TAG, "Cred Payload:");
879         OIC_LOG_BUFFER(DEBUG, TAG, secPayload->securityData, secPayload->payloadSize);
880
881         OCCallbackData cbData;
882         cbData.cb = &SubOwnerCredentialHandler;
883         cbData.context = (void *)motCtx;
884         cbData.cd = NULL;
885         OCStackResult res = OCDoResource(NULL, OC_REST_POST, query,
886                                          &deviceInfo->endpoint, (OCPayload*)secPayload,
887                                          deviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0);
888         if (res != OC_STACK_OK)
889         {
890             OIC_LOG(ERROR, TAG, "OCStack resource error");
891         }
892     }
893     else
894     {
895         OIC_LOG(ERROR, TAG, "Failed to read DOXM device ID.");
896         return OC_STACK_NO_RESOURCE;
897     }
898
899     OIC_LOG(DEBUG, TAG, "OUT PostSubOwnerCredential");
900
901     return OC_STACK_OK;
902 }
903
904
905 /**
906  * Function to handle the handshake result in MOT.
907  * This function will be invoked after DTLS handshake
908  * @param   endPoint  [IN] The remote endpoint.
909  * @param   errorInfo [IN] Error information from the endpoint.
910  * @return  NONE
911  */
912 static void MOTDtlsHandshakeCB(const CAEndpoint_t *endpoint, const CAErrorInfo_t *info)
913 {
914     if(NULL != g_MotCtx && NULL != g_MotCtx->selectedDeviceInfo &&
915        NULL != endpoint && NULL != info)
916     {
917         OIC_LOG_V(INFO, TAG, "Received status from remote device(%s:%d) : %d",
918                  endpoint->addr, endpoint->port, info->result);
919
920         OicSecDoxm_t* newDevDoxm = g_MotCtx->selectedDeviceInfo->doxm;
921
922         if(NULL != newDevDoxm)
923         {
924             OicUuid_t emptyUuid = {.id={0}};
925
926             //Make sure the address matches.
927             if(strncmp(g_MotCtx->selectedDeviceInfo->endpoint.addr,
928                endpoint->addr,
929                sizeof(endpoint->addr)) == 0 &&
930                g_MotCtx->selectedDeviceInfo->securePort == endpoint->port)
931             {
932                 OCStackResult res = OC_STACK_ERROR;
933
934                 //If temporal secure sesstion established successfully
935                 if(CA_STATUS_OK == info->result)
936                 {
937                     //Delete previous credential such as preconfigured-pin
938                     RemoveCredential(&(g_MotCtx->selectedDeviceInfo->doxm->deviceID));
939
940                     res = SaveSubOwnerPSK(g_MotCtx->selectedDeviceInfo);
941                     if(OC_STACK_OK == res)
942                     {
943                         //POST sub owner credential to new device.
944                         res = PostSubOwnerCredential(g_MotCtx);
945                         if(OC_STACK_OK != res)
946                         {
947                             OIC_LOG(ERROR, TAG,
948                                     "Failed to send POST request for SubOwner Credential");
949                             SetMOTResult(g_MotCtx, res);
950                         }
951                     }
952                     else
953                     {
954                         OIC_LOG(ERROR, TAG, "Failed to save the SubOwner PSK.");
955                         SetMOTResult(g_MotCtx, res);
956                     }
957                 }
958                 //In case of authentication failure
959                 else if(CA_DTLS_AUTHENTICATION_FAILURE == info->result)
960                 {
961                     //in case of error from wrong PIN, re-start the ownership transfer
962                     if(OIC_RANDOM_DEVICE_PIN == newDevDoxm->oxmSel)
963                     {
964                         OIC_LOG(ERROR, TAG, "The PIN number may incorrect.");
965
966                         g_MotCtx->attemptCnt++;
967
968                         if(WRONG_PIN_MAX_ATTEMP > g_MotCtx->attemptCnt)
969                         {
970                             res = StartMultipleOwnershipTransfer(g_MotCtx, g_MotCtx->selectedDeviceInfo);
971                             if(OC_STACK_OK != res)
972                             {
973                                 SetMOTResult(g_MotCtx, res);
974                                 OIC_LOG(ERROR, TAG, "Failed to Re-StartOwnershipTransfer");
975                             }
976                         }
977                         else
978                         {
979                             OIC_LOG(ERROR, TAG, "User has exceeded the number of authentication attempts.");
980                             SetMOTResult(g_MotCtx, OC_STACK_AUTHENTICATION_FAILURE);
981                         }
982                     }
983                     else
984                     {
985                         OIC_LOG(ERROR, TAG, "Failed to establish DTLS session.");
986                         SetMOTResult(g_MotCtx, OC_STACK_AUTHENTICATION_FAILURE);
987                     }
988                 }
989             }
990         }
991     }
992 }
993
994 static OCStackResult StartMultipleOwnershipTransfer(OTMContext_t* motCtx,
995                                                     OCProvisionDev_t* selectedDevice)
996 {
997     OIC_LOG(INFO, TAG, "IN StartMultipleOwnershipTransfer");
998     OCStackResult res = OC_STACK_INVALID_PARAM;
999
1000     VERIFY_NON_NULL(TAG, selectedDevice, ERROR);
1001     VERIFY_NON_NULL(TAG, selectedDevice->doxm, ERROR);
1002
1003     motCtx->selectedDeviceInfo = selectedDevice;
1004
1005     //Register DTLS event handler to catch the dtls event while handshake
1006     if(CA_STATUS_OK != CAregisterSslHandshakeCallback(MOTDtlsHandshakeCB))
1007     {
1008         OIC_LOG(WARNING, TAG, "StartOwnershipTransfer : Failed to register DTLS handshake callback.");
1009     }
1010
1011     size_t oxmSel = (size_t)(selectedDevice->doxm->oxmSel);
1012     OIC_LOG_V(DEBUG, TAG, "Multiple Ownership Transfer method = %d", selectedDevice->doxm->oxmSel);
1013
1014     if(OIC_PRECONFIG_PIN != oxmSel && OIC_RANDOM_DEVICE_PIN != oxmSel)
1015     {
1016         OIC_LOG(ERROR, TAG, "Unsupported OxM");
1017         return OC_STACK_ERROR;
1018     }
1019
1020     if(OIC_RANDOM_DEVICE_PIN == selectedDevice->doxm->oxmSel)
1021     {
1022         if(CA_STATUS_OK != CAregisterPskCredentialsHandler(GetDtlsPskForRandomPinOxm))
1023         {
1024             OIC_LOG(ERROR, TAG, "Failed to register DTLS credential handler for Random PIN OxM.");
1025         }
1026     }
1027
1028     res = g_MOTCbDatas[oxmSel].loadSecretCB(motCtx);
1029     VERIFY_SUCCESS(TAG, OC_STACK_OK == res, ERROR);
1030
1031     //Save the current context instance to use on the dtls handshake callback
1032     g_MotCtx = motCtx;
1033
1034     res = g_MOTCbDatas[oxmSel].createSecureSessionCB(motCtx);
1035     VERIFY_SUCCESS(TAG, OC_STACK_OK == res, ERROR);
1036
1037     OIC_LOG(INFO, TAG, "OUT StartMultipleOwnershipTransfer");
1038
1039 exit:
1040     return res;
1041 }
1042
1043 OCStackResult MOTDoOwnershipTransfer(void* ctx,
1044                                      OCProvisionDev_t *selectedDevicelist,
1045                                      OCProvisionResultCB resultCallback)
1046 {
1047     OIC_LOG(DEBUG, TAG, "IN MOTDoOwnershipTransfer");
1048     OCStackResult res = OC_STACK_INVALID_PARAM;
1049     OTMContext_t* motCtx = NULL;
1050     OCProvisionDev_t* pCurDev = NULL;
1051
1052     VERIFY_NON_NULL(TAG, selectedDevicelist, ERROR);
1053     VERIFY_NON_NULL(TAG, resultCallback, ERROR);
1054
1055     res = OC_STACK_NO_MEMORY;
1056     motCtx = (OTMContext_t*)OICCalloc(1,sizeof(OTMContext_t));
1057     VERIFY_NON_NULL(TAG, motCtx, ERROR);
1058
1059     motCtx->ctxResultCallback = resultCallback;
1060     motCtx->ctxHasError = false;
1061     motCtx->userCtx = ctx;
1062     motCtx->ctxResultArraySize = 0;
1063     LL_FOREACH(selectedDevicelist, pCurDev)
1064     {
1065         motCtx->ctxResultArraySize++;
1066     }
1067
1068     motCtx->ctxResultArray =
1069         (OCProvisionResult_t*)OICCalloc(motCtx->ctxResultArraySize, sizeof(OCProvisionResult_t));
1070     VERIFY_NON_NULL(TAG, motCtx->ctxResultArray, ERROR);
1071
1072     //Fill the device UUID for result array.
1073     size_t devIdx = 0;
1074     res = OC_STACK_OK;
1075     pCurDev = NULL;
1076     LL_FOREACH(selectedDevicelist, pCurDev)
1077     {
1078         //Checking duplication of Device ID.
1079         bool isDuplicate = true;
1080         res = PDMIsDuplicateDevice(&pCurDev->doxm->deviceID, &isDuplicate);
1081         VERIFY_SUCCESS(TAG, OC_STACK_OK == res, ERROR);
1082
1083         if (isDuplicate)
1084         {
1085             bool isStale = false;
1086             res = PDMIsDeviceStale(&pCurDev->doxm->deviceID, &isStale);
1087             VERIFY_SUCCESS(TAG, OC_STACK_OK == res, ERROR);
1088             VERIFY_SUCCESS(TAG, isStale, ERROR);
1089
1090             if(isStale)
1091             {
1092                 OIC_LOG(INFO, TAG, "Detected duplicated UUID in stale status, "\
1093                                    "this UUID will be removed from PDM");
1094
1095                 res = PDMDeleteDevice(&pCurDev->doxm->deviceID);
1096                 VERIFY_SUCCESS(TAG, OC_STACK_OK == res, ERROR);
1097             }
1098         }
1099
1100         memcpy(motCtx->ctxResultArray[devIdx].deviceId.id,
1101                pCurDev->doxm->deviceID.id,
1102                UUID_LENGTH);
1103         motCtx->ctxResultArray[devIdx].res = OC_STACK_CONTINUE;
1104         devIdx++;
1105     }
1106
1107     res = StartMultipleOwnershipTransfer(motCtx, selectedDevicelist);
1108     VERIFY_SUCCESS(TAG, OC_STACK_OK == res, ERROR);
1109
1110     OIC_LOG(DEBUG, TAG, "OUT MOTDoOwnershipTransfer");
1111
1112 exit:
1113     if(OC_STACK_OK != res)
1114     {
1115         if(motCtx)
1116         {
1117             OICFree(motCtx->ctxResultArray);
1118             OICFree(motCtx);
1119         }
1120     }
1121     return res;
1122 }