[IOT-1473] Modify the return value of MOT related API.
[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_SUCCESS(TAG, (OIC_NUMBER_OF_MOM_TYPE > momType), ERROR);
224     VERIFY_NON_NULL(TAG, targetDeviceInfo, ERROR);
225     postMomRes = OC_STACK_INVALID_CALLBACK;
226     VERIFY_NON_NULL(TAG, resultCallback, ERROR);
227
228     //Dulpicate doxm resource to update the 'mom' property
229     postMomRes = DoxmToCBORPayload(targetDeviceInfo->doxm, &doxmPayload, &doxmPayloadLen, false);
230     VERIFY_SUCCESS(TAG, (OC_STACK_OK == postMomRes), ERROR);
231
232     postMomRes = CBORPayloadToDoxm(doxmPayload, doxmPayloadLen, &doxm);
233     VERIFY_SUCCESS(TAG, (OC_STACK_OK == postMomRes), ERROR);
234     VERIFY_NON_NULL(TAG, doxm, ERROR);
235
236     if(NULL == doxm->mom)
237     {
238         postMomRes = OC_STACK_NO_MEMORY;
239         doxm->mom = (OicSecMom_t*)OICCalloc(1, sizeof(OicSecMom_t));
240         VERIFY_NON_NULL(TAG, (doxm->mom), ERROR);
241     }
242     doxm->mom->mode = momType;
243
244     //Send POST reuqest for update doxm
245     postMomRes = MOTSendPostDoxm(ctx, targetDeviceInfo, resultCallback, doxm);
246     VERIFY_SUCCESS(TAG, (OC_STACK_OK == postMomRes), ERROR);
247
248     OIC_LOG(DEBUG, TAG, "OUT MOTChangeMode");
249
250 exit:
251     OICFree(doxmPayload);
252     DeleteDoxmBinData(doxm);
253     return postMomRes;
254 }
255
256 /**
257  * API to add 'doxm.oxms' to resource server.
258  *
259  * @param[in] targetDeviceInfo Selected target device.
260  * @param[in] newOxm  OxMs to be added (ref. oic.sec.oxm)
261  * @param[in] resultCallback callback provided by API user, callback will be called when
262  *            POST 'oxms' request recieves a response from resource server.
263  * @return OC_STACK_OK in case of success and other value otherwise.
264  */
265 OCStackResult MOTAddMOTMethod(void *ctx, OCProvisionDev_t *targetDeviceInfo,
266                                  const OicSecOxm_t newOxm, OCProvisionResultCB resultCallback)
267 {
268     OCStackResult postOxmRes = OC_STACK_INVALID_PARAM;
269     OicSecOxm_t* newOxms = NULL;
270     uint8_t* doxmPayload = NULL;
271     size_t doxmPayloadLen = 0;
272
273     OIC_LOG(DEBUG, TAG, "IN MOTAddMOTMethod");
274
275     VERIFY_SUCCESS(TAG, (OIC_OXM_COUNT > newOxm), ERROR);
276     VERIFY_NON_NULL(TAG, targetDeviceInfo, ERROR);
277     postOxmRes = OC_STACK_INVALID_CALLBACK;
278     VERIFY_NON_NULL(TAG, resultCallback, ERROR);
279     postOxmRes = OC_STACK_NO_MEMORY;
280
281     for(size_t i = 0; i < targetDeviceInfo->doxm->oxmLen; i++)
282     {
283         if(targetDeviceInfo->doxm->oxm[i] == newOxm)
284         {
285             OIC_LOG_V(INFO, TAG, "[%d] OxM already supported", (int)newOxm);
286             OCProvisionResult_t* resArr = (OCProvisionResult_t*)OICCalloc(1, sizeof(OCProvisionResult_t));
287             VERIFY_NON_NULL(TAG, resArr, ERROR);
288             resArr->res = OC_STACK_OK;
289             memcpy(resArr->deviceId.id, targetDeviceInfo->doxm->deviceID.id, sizeof(resArr->deviceId.id));
290             resultCallback(ctx, 1, resArr, false);
291             return OC_STACK_OK;
292         }
293     }
294
295     newOxms = (OicSecOxm_t*)OICMalloc(sizeof(OicSecOxm_t) * (targetDeviceInfo->doxm->oxmLen + 1));
296     VERIFY_NON_NULL(TAG, newOxms , ERROR);
297
298     for(size_t i = 0; i < targetDeviceInfo->doxm->oxmLen; i++)
299     {
300         newOxms[i] = targetDeviceInfo->doxm->oxm[i];
301     }
302     newOxms[targetDeviceInfo->doxm->oxmLen] = newOxm;
303     targetDeviceInfo->doxm->oxmLen++;
304     OICFree(targetDeviceInfo->doxm->oxm);
305     targetDeviceInfo->doxm->oxm = newOxms;
306
307     //Send POST reuqest for update doxm
308     postOxmRes = MOTSendPostDoxm(ctx, targetDeviceInfo, resultCallback, targetDeviceInfo->doxm);
309     VERIFY_SUCCESS(TAG, (OC_STACK_OK == postOxmRes), ERROR);
310
311     OIC_LOG(DEBUG, TAG, "OUT MOTAddMOTMethod");
312
313 exit:
314     OICFree(doxmPayload);
315     return postOxmRes;
316 }
317
318 /**
319  * API to update 'doxm.oxmsel' to resource server.
320  *
321  * @param[in] targetDeviceInfo Selected target device.
322   * @param[in] oxmSelValue Method of multiple ownership transfer (ref. oic.sec.oxm)
323  * @param[in] resultCallback callback provided by API user, callback will be called when
324  *            POST 'oxmsel' request recieves a response from resource server.
325  * @return OC_STACK_OK in case of success and other value otherwise.
326  */
327 OCStackResult MOTSelectMOTMethod(void *ctx, const OCProvisionDev_t *targetDeviceInfo,
328                                  const OicSecOxm_t oxmSelValue, OCProvisionResultCB resultCallback)
329 {
330     OCStackResult postMomRes = OC_STACK_INVALID_CALLBACK;
331     OicSecDoxm_t* doxm = NULL;
332     uint8_t* doxmPayload = NULL;
333     size_t doxmPayloadLen = 0;
334
335     OIC_LOG(DEBUG, TAG, "IN MOTSelectOTMethod");
336
337     VERIFY_NON_NULL(TAG, resultCallback, ERROR);
338     postMomRes = OC_STACK_INVALID_PARAM;
339     VERIFY_NON_NULL(TAG, targetDeviceInfo, ERROR);
340
341     bool isValidOxmsel = false;
342     for(size_t i = 0; i < targetDeviceInfo->doxm->oxmLen; i++)
343     {
344         if(targetDeviceInfo->doxm->oxm[i] == oxmSelValue)
345         {
346             isValidOxmsel = true;
347             break;
348         }
349     }
350     VERIFY_SUCCESS(TAG, isValidOxmsel, ERROR);
351
352     //Dulpicate doxm resource to update the 'oxmsel' property
353     postMomRes = DoxmToCBORPayload(targetDeviceInfo->doxm, &doxmPayload, &doxmPayloadLen, false);
354     VERIFY_SUCCESS(TAG, (OC_STACK_OK == postMomRes), ERROR);
355
356     postMomRes = CBORPayloadToDoxm(doxmPayload, doxmPayloadLen, &doxm);
357     VERIFY_SUCCESS(TAG, (OC_STACK_OK == postMomRes), ERROR);
358     VERIFY_NON_NULL(TAG, doxm, ERROR);
359
360     doxm->oxmSel = oxmSelValue;
361
362     //Send POST reuqest for update doxm
363     postMomRes = MOTSendPostDoxm(ctx, targetDeviceInfo, resultCallback, doxm);
364     VERIFY_SUCCESS(TAG, (OC_STACK_OK == postMomRes), ERROR);
365
366     OIC_LOG(DEBUG, TAG, "OUT MOTSelectOTMethod");
367
368 exit:
369     OICFree(doxmPayload);
370     DeleteDoxmBinData(doxm);
371     return postMomRes;
372 }
373
374 /**
375  * API to provision preconfigured PIN to resource server.
376  *
377  * @param[in] targetDeviceInfo Selected target device.
378  * @param[in] preconfPIN Preconfig PIN which is used while multiple owner authentication
379  * @param[in] preconfPINLen Byte length of preconfig PIN
380  * @param[in] resultCallback callback provided by API user, callback will be called when
381  *            POST credential request recieves a response from resource server.
382  * @return OC_STACK_OK in case of success and other value otherwise.
383  */
384 OCStackResult MOTProvisionPreconfigPIN(void *ctx, const OCProvisionDev_t *targetDeviceInfo,
385                                  const char* preconfPIN, size_t preconfPINLen, OCProvisionResultCB resultCallback)
386 {
387     OCStackResult postCredRes = OC_STACK_INVALID_CALLBACK;
388     bool freeFlag = true;
389     OCSecurityPayload* secPayload = NULL;
390     MOTContext_t *motCtx = NULL;
391     OicSecCred_t* pinCred = NULL;
392
393     OIC_LOG(DEBUG, TAG, "IN MOTProvisionPreconfigPIN");
394
395     VERIFY_NON_NULL(TAG, resultCallback, ERROR);
396     postCredRes = OC_STACK_INVALID_PARAM;
397     VERIFY_NON_NULL(TAG, targetDeviceInfo, ERROR);
398     VERIFY_NON_NULL(TAG, preconfPIN, ERROR);
399     VERIFY_SUCCESS(TAG, (0 != preconfPINLen), ERROR);
400     VERIFY_SUCCESS(TAG, (0 != preconfPINLen && OXM_PRECONFIG_PIN_SIZE >= preconfPINLen), ERROR);
401
402     postCredRes = OC_STACK_NO_MEMORY;
403     //Generate PIN based credential
404     pinCred = (OicSecCred_t*)OICCalloc(1, sizeof(OicSecCred_t));
405     VERIFY_NON_NULL(TAG, pinCred, ERROR);
406
407     pinCred->privateData.data = (uint8_t*)OICMalloc(preconfPINLen + 1);
408     VERIFY_NON_NULL(TAG, pinCred->privateData.data, ERROR);
409
410     memcpy(pinCred->privateData.data, preconfPIN, preconfPINLen);
411     pinCred->privateData.data[preconfPINLen] = '\0';
412     pinCred->privateData.len = preconfPINLen;
413     pinCred->privateData.encoding = OIC_ENCODING_RAW;
414     pinCred->credType = PIN_PASSWORD;
415     OICStrcpy(pinCred->subject.id, sizeof(pinCred->subject.id), WILDCARD_SUBJECT_ID.id);
416
417     //Generate the security payload using updated doxm
418     secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
419     VERIFY_NON_NULL(TAG, secPayload, ERROR);
420     secPayload->base.type = PAYLOAD_TYPE_SECURITY;
421
422     postCredRes = CredToCBORPayload(pinCred, &secPayload->securityData, &secPayload->payloadSize, false);
423     VERIFY_SUCCESS(TAG, (OC_STACK_OK == postCredRes), ERROR);
424
425     OIC_LOG(DEBUG, TAG, "Created Credential payload to register PIN credential:");
426     OIC_LOG_BUFFER(DEBUG, TAG, secPayload->securityData, secPayload->payloadSize);
427
428     char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
429     bool queryGenRes = PMGenerateQuery(true,
430                                        targetDeviceInfo->endpoint.addr,
431                                        targetDeviceInfo->securePort,
432                                        targetDeviceInfo->connType,
433                                        query, sizeof(query), OIC_RSRC_CRED_URI);
434     VERIFY_SUCCESS(TAG, (true == queryGenRes), ERROR);
435     OIC_LOG_V(DEBUG, TAG, "Query=%s", query);
436
437     //Create the MOT Context to handle the response message
438     motCtx = (MOTContext_t*)OICCalloc(1, sizeof(MOTContext_t));
439     VERIFY_NON_NULL(TAG, motCtx, ERROR);
440     motCtx->deviceInfo = targetDeviceInfo;
441     motCtx->resultCallback = resultCallback;
442     motCtx->numOfResults=1;
443     motCtx->hasError = false;
444     motCtx->ctx = ctx;
445     motCtx->resArr = (OCProvisionResult_t*)OICCalloc(1, sizeof(OCProvisionResult_t));
446     VERIFY_NON_NULL(TAG, motCtx->resArr, ERROR);
447
448     //Send POST request
449     OCCallbackData cbData =  {.context=NULL, .cb=NULL, .cd=NULL};
450     cbData.cb = &MOTUpdateSecurityResourceCB;
451     cbData.context = (void *)motCtx;
452     OIC_LOG(DEBUG, TAG, "Sending POST Preconfiged PIN credenatial request to resource server");
453     postCredRes = OCDoResource(NULL, OC_REST_POST, query,
454                               &targetDeviceInfo->endpoint, (OCPayload*)secPayload,
455                               targetDeviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0);
456     VERIFY_SUCCESS(TAG, (OC_STACK_OK == postCredRes), ERROR);
457
458     freeFlag = false;
459
460     OIC_LOG(DEBUG, TAG, "OUT MOTProvisionPreconfigPIN");
461
462     return postCredRes;
463
464 exit:
465     //If POST request successfully sent, motCtx will be cleaned from response handler.
466     if(freeFlag && motCtx)
467     {
468         OICFree(motCtx->resArr);
469         OICFree(motCtx);
470     }
471     if(pinCred)
472     {
473         OICFree(pinCred->privateData.data);
474         OICFree(pinCred);
475     }
476     return postCredRes;
477 }
478
479
480 /**********************************************************************
481  * API for Sub Owner
482  **********************************************************************/
483
484 static OCStackResult StartMultipleOwnershipTransfer(OTMContext_t* motCtx,
485                                                     OCProvisionDev_t* selectedDevice);
486
487 /**
488  * Array to store the callbacks for each owner transfer method.
489  */
490 static OTMCallbackData_t g_MOTCbDatas[OIC_OXM_COUNT] = {
491         //Just works
492         {.loadSecretCB = LoadSecretJustWorksCallback,
493           .createSecureSessionCB = CreateSecureSessionJustWorksCallback,
494           .createSelectOxmPayloadCB = NULL,
495           .createOwnerTransferPayloadCB = NULL},
496
497           //Random PIN
498         {.loadSecretCB = InputPinCodeCallback,
499           .createSecureSessionCB = CreateSecureSessionRandomPinCallback,
500           .createSelectOxmPayloadCB = NULL,
501           .createOwnerTransferPayloadCB = NULL},
502
503         //Manufacturer Cert
504         {.loadSecretCB = NULL,
505           .createSecureSessionCB = NULL,
506           .createSelectOxmPayloadCB = NULL,
507           .createOwnerTransferPayloadCB = NULL},
508
509           //Preconfig PIN
510         {.loadSecretCB = LoadPreconfPinCodeCallback,
511           .createSecureSessionCB = CreateSecureSessionPreconfPinCallback,
512           .createSelectOxmPayloadCB = NULL,
513           .createOwnerTransferPayloadCB = NULL},
514 };
515
516 static OTMContext_t* g_MotCtx = NULL;
517
518 static bool IsComplete(OTMContext_t* otmCtx)
519 {
520     for(size_t i = 0; i < otmCtx->ctxResultArraySize; i++)
521     {
522         if(OC_STACK_CONTINUE == otmCtx->ctxResultArray[i].res)
523         {
524             return false;
525         }
526     }
527
528     return true;
529 }
530
531 /**
532  * Function to save the result of multiple ownership transfer.
533  *
534  * @param[in,out] motCtx   Context instance of multiple ownership transfer.
535  * @param[in] res   result of multiple ownership transfer.
536  */
537 static void SetMOTResult(OTMContext_t* motCtx, const OCStackResult res)
538 {
539     OIC_LOG_V(DEBUG, TAG, "IN SetMOTResult : %d ", res);
540
541     VERIFY_NON_NULL(TAG, motCtx, ERROR);
542
543     if(motCtx->selectedDeviceInfo)
544     {
545         //Revert psk_info callback in case of random PIN OxM
546         if(OIC_RANDOM_DEVICE_PIN == motCtx->selectedDeviceInfo->doxm->oxmSel ||
547            OIC_PRECONFIG_PIN == motCtx->selectedDeviceInfo->doxm->oxmSel)
548         {
549             if(CA_STATUS_OK != CAregisterPskCredentialsHandler(GetDtlsPskCredentials))
550             {
551                 OIC_LOG(WARNING, TAG, "Failed to revert the DTLS credential handler.");
552             }
553             OicUuid_t emptyUuid = { .id={0}};
554             SetUuidForPinBasedOxm(&emptyUuid);
555         }
556
557         for(size_t i = 0; i < motCtx->ctxResultArraySize; i++)
558         {
559             if(memcmp(motCtx->selectedDeviceInfo->doxm->deviceID.id,
560                       motCtx->ctxResultArray[i].deviceId.id, UUID_LENGTH) == 0)
561             {
562                 motCtx->ctxResultArray[i].res = res;
563                 if(OC_STACK_OK != res)
564                 {
565                     motCtx->ctxHasError = true;
566                 }
567             }
568         }
569
570         g_MotCtx = NULL;
571
572         //If all request is completed, invoke the user callback.
573         if(IsComplete(motCtx))
574         {
575             motCtx->ctxResultCallback(motCtx->userCtx, motCtx->ctxResultArraySize,
576                                        motCtx->ctxResultArray, motCtx->ctxHasError);
577
578             OICFree(motCtx->ctxResultArray);
579             OICFree(motCtx);
580         }
581         else
582         {
583             if(OC_STACK_OK != StartMultipleOwnershipTransfer(motCtx,
584                                                      motCtx->selectedDeviceInfo->next))
585             {
586                 OIC_LOG(ERROR, TAG, "Failed to StartMultipleOwnershipTransfer");
587             }
588         }
589     }
590
591 exit:
592     OIC_LOG(DEBUG, TAG, "OUT SetMOTResult");
593 }
594
595 /**
596  * API to add preconfigured PIN to local SVR DB.
597  *
598  * @param[in] targetDeviceInfo Selected target device.
599  * @param[in] preconfPIN Preconfig PIN which is used while multiple owner authentication
600  * @param[in] preconfPINLen Byte length of preconfig PIN
601  * @param[in] resultCallback callback provided by API user, callback will be called when
602  *            POST credential request recieves a response from resource server.
603  * @return OC_STACK_OK in case of success and other value otherwise.
604  */
605 OCStackResult MOTAddPreconfigPIN(const OCProvisionDev_t *targetDeviceInfo,
606                                  const char* preconfPIN, size_t preconfPINLen)
607 {
608     OCStackResult addCredRes = OC_STACK_INVALID_PARAM;
609     OicSecCred_t* pinCred = NULL;
610     bool freeFlag = true;
611
612     OIC_LOG(DEBUG, TAG, "IN MOTAddPreconfigPIN");
613
614     VERIFY_NON_NULL(TAG, targetDeviceInfo, ERROR);
615     VERIFY_NON_NULL(TAG, preconfPIN, ERROR);
616     VERIFY_SUCCESS(TAG, (0 != preconfPINLen), ERROR);
617     VERIFY_SUCCESS(TAG, (0 != preconfPINLen && OXM_PRECONFIG_PIN_SIZE >= preconfPINLen), ERROR);
618
619     OicSecCred_t* prevCred = GetCredResourceData(&targetDeviceInfo->doxm->deviceID);
620     if(NULL != prevCred)
621     {
622         OIC_LOG(INFO, TAG, "PIN/PW Credential already exist!");
623         return OC_STACK_OK;
624     }
625
626     addCredRes = OC_STACK_NO_MEMORY;
627     //Generate PIN based credential
628     pinCred = (OicSecCred_t*)OICCalloc(1, sizeof(OicSecCred_t));
629     VERIFY_NON_NULL(TAG, pinCred, ERROR);
630
631     pinCred->privateData.data = (uint8_t*)OICMalloc(preconfPINLen + 1);
632     VERIFY_NON_NULL(TAG, pinCred->privateData.data, ERROR);
633
634     memcpy(pinCred->privateData.data, preconfPIN, preconfPINLen);
635     pinCred->privateData.data[preconfPINLen] = '\0';
636     pinCred->privateData.len = preconfPINLen;
637     pinCred->privateData.encoding = OIC_ENCODING_RAW;
638     pinCred->credType = PIN_PASSWORD;
639     memcpy(pinCred->subject.id, targetDeviceInfo->doxm->deviceID.id, sizeof(pinCred->subject.id));
640
641     addCredRes = AddCredential(pinCred);
642     VERIFY_SUCCESS(TAG, (OC_STACK_OK == addCredRes), ERROR);
643
644     OIC_LOG(DEBUG, TAG, "OUT MOTAddPreconfigPIN");
645
646     return addCredRes;
647
648 exit:
649     if(pinCred)
650     {
651         OICFree(pinCred->privateData.data);
652         OICFree(pinCred);
653     }
654     return addCredRes;
655 }
656
657 /**
658  * Function to save the SubOwner PSK.
659  *
660  * @param[in] selectedDeviceInfo   selected device information to performing provisioning.
661  * @return  OC_STACK_OK on success
662  */
663 static OCStackResult SaveSubOwnerPSK(OCProvisionDev_t *selectedDeviceInfo)
664 {
665     OIC_LOG(DEBUG, TAG, "IN SaveSubOwnerPSK");
666
667     OCStackResult res = OC_STACK_ERROR;
668
669     CAEndpoint_t endpoint;
670     memset(&endpoint, 0x00, sizeof(CAEndpoint_t));
671     OICStrcpy(endpoint.addr, MAX_ADDR_STR_SIZE_CA, selectedDeviceInfo->endpoint.addr);
672     endpoint.addr[MAX_ADDR_STR_SIZE_CA - 1] = '\0';
673     endpoint.port = selectedDeviceInfo->securePort;
674     endpoint.adapter = selectedDeviceInfo->endpoint.adapter;
675
676     OicUuid_t ownerDeviceID = {.id={0}};
677     if (OC_STACK_OK != GetDoxmDeviceID(&ownerDeviceID))
678     {
679         OIC_LOG(ERROR, TAG, "Error while retrieving SubOwner's device ID");
680         return res;
681     }
682
683     uint8_t ownerPSK[OWNER_PSK_LENGTH_128] = {0};
684     OicSecKey_t ownerKey = {ownerPSK, OWNER_PSK_LENGTH_128};
685
686     //Generating SubOwnerPSK
687     CAResult_t pskRet = CAGenerateOwnerPSK(&endpoint,
688             (uint8_t *)GetOxmString(selectedDeviceInfo->doxm->oxmSel),
689             strlen(GetOxmString(selectedDeviceInfo->doxm->oxmSel)),
690             ownerDeviceID.id, sizeof(ownerDeviceID.id),
691             selectedDeviceInfo->doxm->deviceID.id, sizeof(selectedDeviceInfo->doxm->deviceID.id),
692             ownerPSK, OWNER_PSK_LENGTH_128);
693
694     if (CA_STATUS_OK == pskRet)
695     {
696         OIC_LOG(INFO, TAG, "SubOwner PSK dump:");
697         OIC_LOG_BUFFER(INFO, TAG, ownerPSK, OWNER_PSK_LENGTH_128);
698         //Generating new credential for provisioning tool
699         OicSecCred_t *cred = GenerateCredential(&selectedDeviceInfo->doxm->deviceID,
700                                       SYMMETRIC_PAIR_WISE_KEY, NULL,
701                                       &ownerKey, &ownerDeviceID, &ownerDeviceID);
702         VERIFY_NON_NULL(TAG, cred, ERROR);
703
704         uint32_t outSize = 0;
705         size_t b64BufSize = B64ENCODE_OUT_SAFESIZE((OWNER_PSK_LENGTH_128 + 1));
706         char* b64Buf = (uint8_t *)OICCalloc(1, b64BufSize);
707         VERIFY_NON_NULL(TAG, b64Buf, ERROR);
708         b64Encode(cred->privateData.data, cred->privateData.len, b64Buf, b64BufSize, &outSize);
709
710         OICFree( cred->privateData.data );
711         cred->privateData.data = (uint8_t *)OICCalloc(1, outSize + 1);
712         VERIFY_NON_NULL(TAG, cred->privateData.data, ERROR);
713
714         strncpy(cred->privateData.data, b64Buf, outSize);
715         cred->privateData.data[outSize] = '\0';
716         cred->privateData.encoding = OIC_ENCODING_BASE64;
717         cred->privateData.len = outSize;
718         OICFree(b64Buf);
719
720         //Add SubOwnerPSK
721         res = AddCredential(cred);
722         if(res != OC_STACK_OK)
723         {
724             DeleteCredList(cred);
725             return res;
726         }
727     }
728     else
729     {
730         OIC_LOG(ERROR, TAG, "CAGenerateOwnerPSK failed");
731     }
732
733     OIC_LOG(DEBUG, TAG, "OUT SaveSubOwnerPSK");
734 exit:
735     return res;
736 }
737
738
739 /**
740  * Response handler for update subowner crendetial request.
741  *
742  * @param[in] ctx             ctx value passed to callback from calling function.
743  * @param[in] UNUSED          handle to an invocation
744  * @param[in] clientResponse  Response from queries to remote servers.
745  * @return  OC_STACK_DELETE_TRANSACTION to delete the transaction
746  *          and  OC_STACK_KEEP_TRANSACTION to keep it.
747  */
748 static OCStackApplicationResult SubOwnerCredentialHandler(void *ctx, OCDoHandle UNUSED,
749                                 OCClientResponse *clientResponse)
750 {
751     VERIFY_NON_NULL(TAG, clientResponse, WARNING);
752     VERIFY_NON_NULL(TAG, ctx, WARNING);
753
754     OIC_LOG(DEBUG, TAG, "IN SubOwnerCredentialHandler");
755     (void)UNUSED;
756     OCStackResult res = OC_STACK_ERROR;
757     OTMContext_t* motCtx = (OTMContext_t*)ctx;
758
759     if(OC_STACK_RESOURCE_CHANGED == clientResponse->result)
760     {
761         if(motCtx && motCtx->selectedDeviceInfo)
762         {
763             //Close the temporal secure session to verify the owner credential
764             CAEndpoint_t* endpoint = (CAEndpoint_t *)&motCtx->selectedDeviceInfo->endpoint;
765             endpoint->port = motCtx->selectedDeviceInfo->securePort;
766             CAResult_t caResult = CAcloseSslSession(endpoint);
767             if(CA_STATUS_OK != caResult)
768             {
769                 OIC_LOG(ERROR, TAG, "Failed to close DTLS session");
770                 SetMOTResult(motCtx, OC_STACK_ERROR);
771                 return OC_STACK_DELETE_TRANSACTION;
772             }
773
774             // TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256 = 0xC037, /**< see RFC 5489 */
775             caResult = CASelectCipherSuite(0xC037, endpoint->adapter);
776             if(CA_STATUS_OK != caResult)
777             {
778                 OIC_LOG(ERROR, TAG, "Failed to select TLS_NULL_WITH_NULL_NULL");
779                 SetMOTResult(motCtx, OC_STACK_ERROR);
780                 return OC_STACK_DELETE_TRANSACTION;
781             }
782
783             res = PDMAddDevice(&motCtx->selectedDeviceInfo->doxm->deviceID);
784              if (OC_STACK_OK == res)
785              {
786                     OIC_LOG_V(INFO, TAG, "Add device's UUID in PDM_DB");
787              }
788               else
789              {
790                   OIC_LOG(ERROR, TAG, "MOT is complete but adding information to DB is failed.");
791              }
792
793             SetMOTResult(motCtx, res);
794         }
795     }
796     else
797     {
798         res = clientResponse->result;
799         OIC_LOG_V(ERROR, TAG, "SubOwnerCredentialHandler : Unexpected result %d", res);
800         SetMOTResult(motCtx, res);
801     }
802
803     OIC_LOG(DEBUG, TAG, "OUT SubOwnerCredentialHandler");
804
805 exit:
806     return  OC_STACK_DELETE_TRANSACTION;
807 }
808
809
810 static OCStackResult PostSubOwnerCredential(OTMContext_t* motCtx)
811 {
812     OIC_LOG(DEBUG, TAG, "IN PostSubOwnerCredential");
813
814     if(!motCtx || !motCtx->selectedDeviceInfo)
815     {
816         OIC_LOG(ERROR, TAG, "Invalid parameters");
817         return OC_STACK_INVALID_PARAM;
818     }
819
820     OCProvisionDev_t* deviceInfo = motCtx->selectedDeviceInfo;
821     char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
822
823     if(!PMGenerateQuery(true,
824                         deviceInfo->endpoint.addr, deviceInfo->securePort,
825                         deviceInfo->connType,
826                         query, sizeof(query), OIC_RSRC_CRED_URI))
827     {
828         OIC_LOG(ERROR, TAG, "PostSubOwnerCredential : Failed to generate query");
829         return OC_STACK_ERROR;
830     }
831     OIC_LOG_V(DEBUG, TAG, "Query=%s", query);
832     OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
833     if(!secPayload)
834     {
835         OIC_LOG(ERROR, TAG, "Failed to memory allocation");
836         return OC_STACK_NO_MEMORY;
837     }
838
839     //Generate sub-owner credential for new device
840     secPayload->base.type = PAYLOAD_TYPE_SECURITY;
841     const OicSecCred_t* ownerCredential = GetCredResourceData(&(deviceInfo->doxm->deviceID));
842     if(!ownerCredential)
843     {
844         OIC_LOG(ERROR, TAG, "Can not find SubOwnerPSK.");
845         return OC_STACK_NO_RESOURCE;
846     }
847
848     OicUuid_t ownerId = {.id={0}};
849     if(OC_STACK_OK == GetDoxmDeviceID(&ownerId))
850     {
851         OicSecCred_t newCredential;
852         memcpy(&newCredential, ownerCredential, sizeof(OicSecCred_t));
853         newCredential.next = NULL;
854
855         //Set subject ID as SubOwner's ID
856         memcpy(&(newCredential.subject), &ownerId, sizeof(OicUuid_t));
857
858         //Set eowner ID as SubOwner's ID
859         if(NULL == newCredential.eownerID)
860         {
861             newCredential.eownerID = OICCalloc(1, sizeof(OicUuid_t));
862             if(NULL == newCredential.eownerID)
863             {
864                 return OC_STACK_NO_MEMORY;
865             }
866         }
867         memcpy(newCredential.eownerID->id, ownerId.id, sizeof(ownerId.id));
868
869         //Fill private data as empty string
870         newCredential.privateData.data = "";
871         newCredential.privateData.len = 0;
872         newCredential.privateData.encoding = ownerCredential->privateData.encoding;
873 #ifdef __WITH_X509__
874         newCredential.publicData.data = NULL;
875         newCredential.publicData.len = 0;
876 #endif
877         //Send owner credential to new device : POST /oic/sec/cred [ owner credential ]
878         if (OC_STACK_OK != CredToCBORPayload(&newCredential, &secPayload->securityData,
879                                         &secPayload->payloadSize, 0))
880         {
881             OICFree(secPayload);
882             OIC_LOG(ERROR, TAG, "Error while converting bin to cbor.");
883             return OC_STACK_ERROR;
884         }
885         OIC_LOG(DEBUG, TAG, "Cred Payload:");
886         OIC_LOG_BUFFER(DEBUG, TAG, secPayload->securityData, secPayload->payloadSize);
887
888         OCCallbackData cbData;
889         cbData.cb = &SubOwnerCredentialHandler;
890         cbData.context = (void *)motCtx;
891         cbData.cd = NULL;
892         OCStackResult res = OCDoResource(NULL, OC_REST_POST, query,
893                                          &deviceInfo->endpoint, (OCPayload*)secPayload,
894                                          deviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0);
895         if (res != OC_STACK_OK)
896         {
897             OIC_LOG(ERROR, TAG, "OCStack resource error");
898         }
899     }
900     else
901     {
902         OIC_LOG(ERROR, TAG, "Failed to read DOXM device ID.");
903         return OC_STACK_NO_RESOURCE;
904     }
905
906     OIC_LOG(DEBUG, TAG, "OUT PostSubOwnerCredential");
907
908     return OC_STACK_OK;
909 }
910
911
912 /**
913  * Function to handle the handshake result in MOT.
914  * This function will be invoked after DTLS handshake
915  * @param   endPoint  [IN] The remote endpoint.
916  * @param   errorInfo [IN] Error information from the endpoint.
917  * @return  NONE
918  */
919 static void MOTDtlsHandshakeCB(const CAEndpoint_t *endpoint, const CAErrorInfo_t *info)
920 {
921     if(NULL != g_MotCtx && NULL != g_MotCtx->selectedDeviceInfo &&
922        NULL != endpoint && NULL != info)
923     {
924         OIC_LOG_V(INFO, TAG, "Received status from remote device(%s:%d) : %d",
925                  endpoint->addr, endpoint->port, info->result);
926
927         OicSecDoxm_t* newDevDoxm = g_MotCtx->selectedDeviceInfo->doxm;
928
929         if(NULL != newDevDoxm)
930         {
931             OicUuid_t emptyUuid = {.id={0}};
932
933             //Make sure the address matches.
934             if(strncmp(g_MotCtx->selectedDeviceInfo->endpoint.addr,
935                endpoint->addr,
936                sizeof(endpoint->addr)) == 0 &&
937                g_MotCtx->selectedDeviceInfo->securePort == endpoint->port)
938             {
939                 OCStackResult res = OC_STACK_ERROR;
940
941                 //If temporal secure sesstion established successfully
942                 if(CA_STATUS_OK == info->result)
943                 {
944                     //Delete previous credential such as preconfigured-pin
945                     RemoveCredential(&(g_MotCtx->selectedDeviceInfo->doxm->deviceID));
946
947                     res = SaveSubOwnerPSK(g_MotCtx->selectedDeviceInfo);
948                     if(OC_STACK_OK == res)
949                     {
950                         //POST sub owner credential to new device.
951                         res = PostSubOwnerCredential(g_MotCtx);
952                         if(OC_STACK_OK != res)
953                         {
954                             OIC_LOG(ERROR, TAG,
955                                     "Failed to send POST request for SubOwner Credential");
956                             SetMOTResult(g_MotCtx, res);
957                         }
958                     }
959                     else
960                     {
961                         OIC_LOG(ERROR, TAG, "Failed to save the SubOwner PSK.");
962                         SetMOTResult(g_MotCtx, res);
963                     }
964                 }
965                 //In case of authentication failure
966                 else if(CA_DTLS_AUTHENTICATION_FAILURE == info->result)
967                 {
968                     //in case of error from wrong PIN, re-start the ownership transfer
969                     if(OIC_RANDOM_DEVICE_PIN == newDevDoxm->oxmSel)
970                     {
971                         OIC_LOG(ERROR, TAG, "The PIN number may incorrect.");
972
973                         g_MotCtx->attemptCnt++;
974
975                         if(WRONG_PIN_MAX_ATTEMP > g_MotCtx->attemptCnt)
976                         {
977                             res = StartMultipleOwnershipTransfer(g_MotCtx, g_MotCtx->selectedDeviceInfo);
978                             if(OC_STACK_OK != res)
979                             {
980                                 SetMOTResult(g_MotCtx, res);
981                                 OIC_LOG(ERROR, TAG, "Failed to Re-StartOwnershipTransfer");
982                             }
983                         }
984                         else
985                         {
986                             OIC_LOG(ERROR, TAG, "User has exceeded the number of authentication attempts.");
987                             SetMOTResult(g_MotCtx, OC_STACK_AUTHENTICATION_FAILURE);
988                         }
989                     }
990                     else
991                     {
992                         OIC_LOG(ERROR, TAG, "Failed to establish DTLS session.");
993                         SetMOTResult(g_MotCtx, OC_STACK_AUTHENTICATION_FAILURE);
994                     }
995                 }
996             }
997         }
998     }
999 }
1000
1001 static OCStackResult StartMultipleOwnershipTransfer(OTMContext_t* motCtx,
1002                                                     OCProvisionDev_t* selectedDevice)
1003 {
1004     OIC_LOG(INFO, TAG, "IN StartMultipleOwnershipTransfer");
1005     OCStackResult res = OC_STACK_INVALID_PARAM;
1006
1007     VERIFY_NON_NULL(TAG, selectedDevice, ERROR);
1008     VERIFY_NON_NULL(TAG, selectedDevice->doxm, ERROR);
1009
1010     motCtx->selectedDeviceInfo = selectedDevice;
1011
1012     //Register DTLS event handler to catch the dtls event while handshake
1013     if(CA_STATUS_OK != CAregisterSslHandshakeCallback(MOTDtlsHandshakeCB))
1014     {
1015         OIC_LOG(WARNING, TAG, "StartOwnershipTransfer : Failed to register DTLS handshake callback.");
1016     }
1017
1018     size_t oxmSel = (size_t)(selectedDevice->doxm->oxmSel);
1019     OIC_LOG_V(DEBUG, TAG, "Multiple Ownership Transfer method = %d", selectedDevice->doxm->oxmSel);
1020
1021     if(OIC_PRECONFIG_PIN != oxmSel && OIC_RANDOM_DEVICE_PIN != oxmSel)
1022     {
1023         OIC_LOG(ERROR, TAG, "Unsupported OxM");
1024         return OC_STACK_ERROR;
1025     }
1026
1027     if(OIC_RANDOM_DEVICE_PIN == selectedDevice->doxm->oxmSel)
1028     {
1029         if(CA_STATUS_OK != CAregisterPskCredentialsHandler(GetDtlsPskForRandomPinOxm))
1030         {
1031             OIC_LOG(ERROR, TAG, "Failed to register DTLS credential handler for Random PIN OxM.");
1032         }
1033     }
1034
1035     res = g_MOTCbDatas[oxmSel].loadSecretCB(motCtx);
1036     VERIFY_SUCCESS(TAG, OC_STACK_OK == res, ERROR);
1037
1038     //Save the current context instance to use on the dtls handshake callback
1039     g_MotCtx = motCtx;
1040
1041     res = g_MOTCbDatas[oxmSel].createSecureSessionCB(motCtx);
1042     VERIFY_SUCCESS(TAG, OC_STACK_OK == res, ERROR);
1043
1044     OIC_LOG(INFO, TAG, "OUT StartMultipleOwnershipTransfer");
1045
1046 exit:
1047     return res;
1048 }
1049
1050 OCStackResult MOTDoOwnershipTransfer(void* ctx,
1051                                      OCProvisionDev_t *selectedDevicelist,
1052                                      OCProvisionResultCB resultCallback)
1053 {
1054     OIC_LOG(DEBUG, TAG, "IN MOTDoOwnershipTransfer");
1055     OCStackResult res = OC_STACK_INVALID_PARAM;
1056     OTMContext_t* motCtx = NULL;
1057     OCProvisionDev_t* pCurDev = NULL;
1058
1059     VERIFY_NON_NULL(TAG, selectedDevicelist, ERROR);
1060     VERIFY_NON_NULL(TAG, resultCallback, ERROR);
1061
1062     res = OC_STACK_NO_MEMORY;
1063     motCtx = (OTMContext_t*)OICCalloc(1,sizeof(OTMContext_t));
1064     VERIFY_NON_NULL(TAG, motCtx, ERROR);
1065
1066     motCtx->ctxResultCallback = resultCallback;
1067     motCtx->ctxHasError = false;
1068     motCtx->userCtx = ctx;
1069     motCtx->ctxResultArraySize = 0;
1070     LL_FOREACH(selectedDevicelist, pCurDev)
1071     {
1072         motCtx->ctxResultArraySize++;
1073     }
1074
1075     motCtx->ctxResultArray =
1076         (OCProvisionResult_t*)OICCalloc(motCtx->ctxResultArraySize, sizeof(OCProvisionResult_t));
1077     VERIFY_NON_NULL(TAG, motCtx->ctxResultArray, ERROR);
1078
1079     //Fill the device UUID for result array.
1080     size_t devIdx = 0;
1081     res = OC_STACK_OK;
1082     pCurDev = NULL;
1083     LL_FOREACH(selectedDevicelist, pCurDev)
1084     {
1085         //Checking duplication of Device ID.
1086         bool isDuplicate = true;
1087         res = PDMIsDuplicateDevice(&pCurDev->doxm->deviceID, &isDuplicate);
1088         VERIFY_SUCCESS(TAG, OC_STACK_OK == res, ERROR);
1089
1090         if (isDuplicate)
1091         {
1092             bool isStale = false;
1093             res = PDMIsDeviceStale(&pCurDev->doxm->deviceID, &isStale);
1094             VERIFY_SUCCESS(TAG, OC_STACK_OK == res, ERROR);
1095             VERIFY_SUCCESS(TAG, isStale, ERROR);
1096
1097             if(isStale)
1098             {
1099                 OIC_LOG(INFO, TAG, "Detected duplicated UUID in stale status, "\
1100                                    "this UUID will be removed from PDM");
1101
1102                 res = PDMDeleteDevice(&pCurDev->doxm->deviceID);
1103                 VERIFY_SUCCESS(TAG, OC_STACK_OK == res, ERROR);
1104             }
1105         }
1106
1107         memcpy(motCtx->ctxResultArray[devIdx].deviceId.id,
1108                pCurDev->doxm->deviceID.id,
1109                UUID_LENGTH);
1110         motCtx->ctxResultArray[devIdx].res = OC_STACK_CONTINUE;
1111         devIdx++;
1112     }
1113
1114     res = StartMultipleOwnershipTransfer(motCtx, selectedDevicelist);
1115     VERIFY_SUCCESS(TAG, OC_STACK_OK == res, ERROR);
1116
1117     OIC_LOG(DEBUG, TAG, "OUT MOTDoOwnershipTransfer");
1118
1119 exit:
1120     if(OC_STACK_OK != res)
1121     {
1122         if(motCtx)
1123         {
1124             OICFree(motCtx->ctxResultArray);
1125             OICFree(motCtx);
1126         }
1127     }
1128     return res;
1129 }