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