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