149bf4e42f8f992604ab7addf9e1d984cb9ccd08
[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 "srmresourcestrings.h"
41 #include "doxmresource.h"
42 #include "pstatresource.h"
43 #include "credresource.h"
44 #include "aclresource.h"
45 #include "ownershiptransfermanager.h"
46 #include "securevirtualresourcetypes.h"
47 #include "oxmjustworks.h"
48 #include "pmtypes.h"
49 #include "pmutility.h"
50 #include "pmutilityinternal.h"
51 #include "srmutility.h"
52 #include "provisioningdatabasemanager.h"
53 #include "oxmrandompin.h"
54 #include "ocpayload.h"
55 #include "payload_logging.h"
56 #include "oxmjustworks.h"
57 #include "oxmpreconfpin.h"
58 #include "oxmrandompin.h"
59 #include "otmcontextlist.h"
60 #include "ocstackinternal.h"
61 #include "mbedtls/ssl_ciphersuites.h"
62 #include "ocrandom.h"
63
64 #define TAG "OIC_MULTIPLE_OTM"
65
66 /**********************************************************************
67  * API for Super Owner
68  **********************************************************************/
69
70 /**
71  * Callback handler of security resource's POST request.
72  *
73  * @param[in] ctx             ctx value passed to callback from calling function.
74  * @param[in] UNUSED          handle to an invocation
75  * @param[in] clientResponse  Response from queries to remote servers.
76  * @return  OC_STACK_DELETE_TRANSACTION to delete the transaction
77  *          and  OC_STACK_KEEP_TRANSACTION to keep it.
78  */
79 static OCStackApplicationResult MOTUpdateSecurityResourceCB(void *ctx, OCDoHandle UNUSED,
80                                                 OCClientResponse *clientResponse)
81 {
82     OIC_LOG_V(INFO, TAG, "Inside MOTUpdateMomCB.");
83     (void)UNUSED;
84     OTMContext_t *motCtx = (OTMContext_t*)ctx;
85     VERIFY_NOT_NULL(TAG, motCtx, ERROR);
86     VERIFY_NOT_NULL(TAG, motCtx->ctxResultCallback, ERROR);
87     VERIFY_NOT_NULL(TAG, motCtx->ctxResultArray, ERROR);
88
89     if(clientResponse)
90     {
91         memcpy(motCtx->ctxResultArray[0].deviceId.id,
92                motCtx->selectedDeviceInfo->doxm->deviceID.id,
93                sizeof(OicUuid_t));
94         motCtx->ctxResultArray[0].res = clientResponse->result;
95
96         if(OC_STACK_RESOURCE_CHANGED == clientResponse->result)
97         {
98             motCtx->ctxHasError = false;
99         }
100         else
101         {
102             motCtx->ctxHasError = true;
103         }
104     }
105     else
106     {
107         OIC_LOG_V(ERROR, TAG, "SRPGetACLResourceCB received Null clientResponse");
108         motCtx->ctxResultArray[0].res = OC_STACK_ERROR;
109         motCtx->ctxHasError = true;
110     }
111
112     motCtx->ctxResultCallback(motCtx->userCtx, motCtx->ctxResultArraySize,
113                               motCtx->ctxResultArray, motCtx->ctxHasError);
114
115 exit:
116     if(motCtx)
117     {
118         PMDeleteDeviceList(motCtx->selectedDeviceInfo);
119         OICFree(motCtx->ctxResultArray);
120         OICFree(motCtx);
121     }
122     return OC_STACK_DELETE_TRANSACTION;
123 }
124
125 /**
126  * Internal API to send POST doxm request
127  */
128 static OCStackResult MOTSendPostDoxm(void *ctx,
129                                      const OCProvisionDev_t *targetDeviceInfo,
130                                      OCProvisionResultCB resultCallback,
131                                      const OicSecDoxm_t* doxm)
132 {
133     OCStackResult postMomRes = OC_STACK_ERROR;
134     OCSecurityPayload* secPayload = NULL;
135     OTMContext_t *motCtx = NULL;
136     OCProvisionDev_t *localTargetDeviceInfo = NULL;
137     bool freeFlag = true;
138
139     OIC_LOG(DEBUG, TAG, "IN MOTSendPostDoxm");
140
141     //Generate the security payload using updated doxm
142     secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
143     VERIFY_NOT_NULL(TAG, secPayload, ERROR);
144     secPayload->base.type = PAYLOAD_TYPE_SECURITY;
145
146     postMomRes = DoxmToCBORPayload(doxm, &secPayload->securityData, &secPayload->payloadSize, true);
147     VERIFY_SUCCESS(TAG, (OC_STACK_OK == postMomRes), ERROR);
148
149     OIC_LOG(DEBUG, TAG, "Created doxm payload to update doxm:");
150     OIC_LOG_BUFFER(DEBUG, TAG, secPayload->securityData, secPayload->payloadSize);
151
152     char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
153     bool queryGenRes = PMGenerateQuery(true,
154                                        targetDeviceInfo->endpoint.addr,
155                                        targetDeviceInfo->securePort,
156                                        targetDeviceInfo->connType,
157                                        query, sizeof(query), OIC_RSRC_DOXM_URI);
158     VERIFY_SUCCESS(TAG, (true == queryGenRes), ERROR);
159     OIC_LOG_V(DEBUG, TAG, "Query=%s", query);
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
165     localTargetDeviceInfo = PMCloneOCProvisionDevList(targetDeviceInfo);
166     VERIFY_NOT_NULL(TAG, localTargetDeviceInfo, ERROR);
167
168     motCtx->selectedDeviceInfo = localTargetDeviceInfo;
169     motCtx->ctxResultCallback = resultCallback;
170     motCtx->ctxResultArraySize = 1;
171     motCtx->ctxHasError = false;
172     motCtx->userCtx = ctx;
173     motCtx->ctxResultArray= (OCProvisionResult_t*)OICCalloc(1, sizeof(OCProvisionResult_t));
174     VERIFY_NOT_NULL(TAG, motCtx->ctxResultArray, ERROR);
175
176     //Send POST request
177     OCCallbackData cbData;
178     memset(&cbData, 0, sizeof(cbData));
179     cbData.cb = &MOTUpdateSecurityResourceCB;
180     cbData.context = (void *)motCtx;
181     OIC_LOG(DEBUG, TAG, "Sending POST 'doxm' request to resource server");
182     postMomRes = OCDoResource(NULL, OC_REST_POST, query,
183                               &targetDeviceInfo->endpoint, (OCPayload*)secPayload,
184                               targetDeviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0);
185     VERIFY_SUCCESS(TAG, (OC_STACK_OK == postMomRes), ERROR);
186
187     freeFlag = false;
188
189     OIC_LOG(DEBUG, TAG, "OUT MOTSendPostDoxm");
190
191 exit:
192     //If POST request successfully sent, motCtx will be cleaned from response handler.
193     if(freeFlag && motCtx)
194     {
195         PMDeleteDeviceList(motCtx->selectedDeviceInfo);
196         OICFree(motCtx->ctxResultArray);
197         OICFree(motCtx);
198     }
199
200     return postMomRes;
201 }
202
203 /**
204  * API to update 'doxm.mom' to resource server.
205  *
206  * @param[in] targetDeviceInfo Selected target device.
207  * @param[in] momType Mode of multiple ownership transfer (ref. oic.sec.mom)
208  * @param[in] resultCallback callback provided by API user, callback will be called when
209  *            POST 'mom' request recieves a response from resource server.
210  * @return OC_STACK_OK in case of success and other value otherwise.
211  */
212 OCStackResult MOTChangeMode(void *ctx, const OCProvisionDev_t *targetDeviceInfo,
213                             const OicSecMomType_t momType, OCProvisionResultCB resultCallback)
214 {
215     OCStackResult postMomRes = OC_STACK_INVALID_PARAM;
216     OicSecDoxm_t* doxm = NULL;
217     uint8_t* doxmPayload = NULL;
218     size_t doxmPayloadLen = 0;
219
220     OIC_LOG(DEBUG, TAG, "IN MOTChangeMode");
221
222     VERIFY_SUCCESS(TAG, (OIC_NUMBER_OF_MOM_TYPE > momType), ERROR);
223     VERIFY_NOT_NULL(TAG, targetDeviceInfo, ERROR);
224     postMomRes = OC_STACK_INVALID_CALLBACK;
225     VERIFY_NOT_NULL(TAG, resultCallback, ERROR);
226
227     //Dulpicate doxm resource to update the 'mom' property
228     postMomRes = DoxmToCBORPayload(targetDeviceInfo->doxm, &doxmPayload, &doxmPayloadLen, false);
229     VERIFY_SUCCESS(TAG, (OC_STACK_OK == postMomRes), ERROR);
230
231     postMomRes = CBORPayloadToDoxm(doxmPayload, doxmPayloadLen, &doxm);
232     VERIFY_SUCCESS(TAG, (OC_STACK_OK == postMomRes), ERROR);
233     VERIFY_NOT_NULL(TAG, doxm, ERROR);
234
235     if(NULL == doxm->mom)
236     {
237         postMomRes = OC_STACK_NO_MEMORY;
238         doxm->mom = (OicSecMom_t*)OICCalloc(1, sizeof(OicSecMom_t));
239         VERIFY_NOT_NULL(TAG, (doxm->mom), ERROR);
240     }
241     doxm->mom->mode = momType;
242
243     //Send POST reuqest for update doxm
244     postMomRes = MOTSendPostDoxm(ctx, targetDeviceInfo, resultCallback, doxm);
245     VERIFY_SUCCESS(TAG, (OC_STACK_OK == postMomRes), ERROR);
246
247     OIC_LOG(DEBUG, TAG, "OUT MOTChangeMode");
248
249 exit:
250     OICFree(doxmPayload);
251     DeleteDoxmBinData(doxm);
252     return postMomRes;
253 }
254
255 /**
256  * API to add 'doxm.oxms' to resource server.
257  *
258  * @param[in] targetDeviceInfo Selected target device.
259  * @param[in] newOxm  OxMs to be added (ref. oic.sec.doxmtype)
260  * @param[in] resultCallback callback provided by API user, callback will be called when
261  *            POST 'oxms' request recieves a response from resource server.
262  * @return OC_STACK_OK in case of success and other value otherwise.
263  */
264 OCStackResult MOTAddMOTMethod(void *ctx, OCProvisionDev_t *targetDeviceInfo,
265                                  const OicSecOxm_t newOxm, OCProvisionResultCB resultCallback)
266 {
267     OCStackResult postOxmRes = OC_STACK_INVALID_PARAM;
268     OicSecOxm_t* newOxms = NULL;
269     uint8_t* doxmPayload = NULL;
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.doxmtype)
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     memcpy(&pinCred->subject, &WILDCARD_SUBJECT_ID, sizeof(OicUuid_t));
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     //Create the MOT Context to handle the response message
437     motCtx = (OTMContext_t*)OICCalloc(1, sizeof(OTMContext_t));
438     VERIFY_NOT_NULL(TAG, motCtx, ERROR);
439
440     localTargetDeviceInfo = PMCloneOCProvisionDevList(targetDeviceInfo);
441     VERIFY_NOT_NULL(TAG, localTargetDeviceInfo, ERROR);
442
443     motCtx->selectedDeviceInfo= localTargetDeviceInfo;
444     motCtx->ctxResultCallback = resultCallback;
445     motCtx->ctxResultArraySize =1;
446     motCtx->ctxHasError = false;
447     motCtx->userCtx = ctx;
448     motCtx->ctxResultArray = (OCProvisionResult_t*)OICCalloc(1, sizeof(OCProvisionResult_t));
449     VERIFY_NOT_NULL(TAG, motCtx->ctxResultArray, ERROR);
450
451     //Send POST request
452     OCCallbackData cbData;
453     memset(&cbData, 0, sizeof(cbData));
454     cbData.cb = &MOTUpdateSecurityResourceCB;
455     cbData.context = (void *)motCtx;
456     OIC_LOG(DEBUG, TAG, "Sending POST Preconfiged PIN credenatial request to resource server");
457     postCredRes = OCDoResource(NULL, OC_REST_POST, query,
458                               &targetDeviceInfo->endpoint, (OCPayload*)secPayload,
459                               targetDeviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0);
460     VERIFY_SUCCESS(TAG, (OC_STACK_OK == postCredRes), ERROR);
461
462     freeFlag = false;
463
464     OIC_LOG(DEBUG, TAG, "OUT MOTProvisionPreconfigPIN");
465
466     return postCredRes;
467
468 exit:
469     //If POST request successfully sent, motCtx will be cleaned from response handler.
470     if(freeFlag && motCtx)
471     {
472         PMDeleteDeviceList(motCtx->selectedDeviceInfo);
473         OICFree(motCtx->ctxResultArray);
474         OICFree(motCtx);
475     }
476
477     if(pinCred)
478     {
479         OICFree(pinCred->privateData.data);
480         OICFree(pinCred);
481     }
482
483     return postCredRes;
484 }
485
486
487 /**********************************************************************
488  * API for Sub Owner
489  **********************************************************************/
490
491 static OCStackResult StartMultipleOwnershipTransfer(OTMContext_t* motCtx,
492                                                     OCProvisionDev_t* selectedDevice);
493
494 static OTMContext_t* g_MotCtx = NULL;
495
496 static bool IsComplete(OTMContext_t* otmCtx)
497 {
498     for(size_t i = 0; i < otmCtx->ctxResultArraySize; i++)
499     {
500         if(OC_STACK_CONTINUE == otmCtx->ctxResultArray[i].res)
501         {
502             return false;
503         }
504     }
505
506     return true;
507 }
508
509 /**
510  * Function to save the result of multiple ownership transfer.
511  *
512  * @param[in,out] motCtx   Context instance of multiple ownership transfer.
513  * @param[in] res   result of multiple ownership transfer.
514  */
515 static void SetMOTResult(OTMContext_t* motCtx, const OCStackResult res)
516 {
517     OIC_LOG_V(DEBUG, TAG, "IN SetMOTResult : %d ", res);
518     VERIFY_NOT_NULL(TAG, motCtx, ERROR);
519
520     if(motCtx->selectedDeviceInfo)
521     {
522         //Revert psk_info callback in case of random PIN OxM
523         if(OIC_RANDOM_DEVICE_PIN == motCtx->selectedDeviceInfo->doxm->oxmSel ||
524            OIC_PRECONFIG_PIN == motCtx->selectedDeviceInfo->doxm->oxmSel)
525         {
526             if(CA_STATUS_OK != CAregisterPskCredentialsHandler(GetDtlsPskCredentials))
527             {
528                 OIC_LOG(WARNING, TAG, "Failed to revert the DTLS credential handler.");
529             }
530             OicUuid_t emptyUuid = { .id={0}};
531             SetUuidForPinBasedOxm(&emptyUuid);
532         }
533
534         OCStackResult pdmRetVal = PDMSetDeviceState(&motCtx->selectedDeviceInfo->doxm->deviceID,
535                                                     PDM_DEVICE_ACTIVE);
536         if (OC_STACK_OK != pdmRetVal)
537         {
538             OIC_LOG_V(ERROR, TAG, "Failed to add device information into PDM_DB : %d", res);
539         }
540
541         for(size_t i = 0; i < motCtx->ctxResultArraySize; i++)
542         {
543             if(memcmp(motCtx->selectedDeviceInfo->doxm->deviceID.id,
544                       motCtx->ctxResultArray[i].deviceId.id, UUID_LENGTH) == 0)
545             {
546                 motCtx->ctxResultArray[i].res = res;
547                 if(OC_STACK_OK != res)
548                 {
549                     motCtx->ctxHasError = true;
550                 }
551             }
552         }
553
554         //Remove the current OTM Context from OTM queue
555         RemoveOTMContext(motCtx->selectedDeviceInfo->endpoint.addr,
556                          motCtx->selectedDeviceInfo->securePort);
557
558         //If there is a request being performed, cancel it to prevent retransmission.
559         if(motCtx->ocDoHandle)
560         {
561             if (OC_STACK_OK !=  OCCancel(motCtx->ocDoHandle, OC_HIGH_QOS, NULL, 0))
562             {
563                 OIC_LOG(ERROR, TAG, "Failed to remove registered callback");
564             }
565             motCtx->ocDoHandle = NULL;
566         }
567
568         //If all request is completed, invoke the user callback.
569         if(IsComplete(motCtx))
570         {
571             motCtx->ctxResultCallback(motCtx->userCtx, motCtx->ctxResultArraySize,
572                                        motCtx->ctxResultArray, motCtx->ctxHasError);
573
574             OICFree(motCtx->ctxResultArray);
575             OICFree(motCtx);
576             motCtx = NULL;
577         }
578         else
579         {
580             if(OC_STACK_OK != StartMultipleOwnershipTransfer(motCtx,
581                                                      motCtx->selectedDeviceInfo->next))
582             {
583                 OIC_LOG(ERROR, TAG, "Failed to StartMultipleOwnershipTransfer");
584             }
585         }
586     }
587
588 exit:
589     OIC_LOG(DEBUG, TAG, "OUT SetMOTResult");
590 }
591
592 /**
593  * API to add preconfigured PIN to local SVR DB.
594  *
595  * @param[in] targetDeviceInfo Selected target device.
596  * @param[in] preconfPIN Preconfig PIN which is used while multiple owner authentication
597  * @param[in] preconfPINLen Byte length of preconfig PIN
598  * @param[in] resultCallback callback provided by API user, callback will be called when
599  *            POST credential request recieves a response from resource server.
600  * @return OC_STACK_OK in case of success and other value otherwise.
601  */
602 OCStackResult MOTAddPreconfigPIN(const OCProvisionDev_t *targetDeviceInfo,
603                                  const char* preconfPIN, size_t preconfPINLen)
604 {
605     OCStackResult addCredRes = OC_STACK_INVALID_PARAM;
606     OicSecCred_t* pinCred = NULL;
607
608     OIC_LOG(DEBUG, TAG, "IN MOTAddPreconfigPIN");
609
610     VERIFY_NOT_NULL(TAG, targetDeviceInfo, ERROR);
611     VERIFY_NOT_NULL(TAG, preconfPIN, ERROR);
612     VERIFY_SUCCESS(TAG, (0 != preconfPINLen), ERROR);
613     VERIFY_SUCCESS(TAG, (0 != preconfPINLen && OXM_PRECONFIG_PIN_MAX_SIZE >= preconfPINLen), ERROR);
614
615     OicSecCred_t* prevCred = GetCredResourceData(&targetDeviceInfo->doxm->deviceID);
616     if(NULL != prevCred)
617     {
618         OIC_LOG(INFO, TAG, "PIN/PW Credential already exist!");
619         return OC_STACK_OK;
620     }
621
622     addCredRes = OC_STACK_NO_MEMORY;
623     //Generate PIN based credential
624     pinCred = (OicSecCred_t*)OICCalloc(1, sizeof(OicSecCred_t));
625     VERIFY_NOT_NULL(TAG, pinCred, ERROR);
626
627     pinCred->privateData.data = (uint8_t*)OICMalloc(preconfPINLen + 1);
628     VERIFY_NOT_NULL(TAG, pinCred->privateData.data, ERROR);
629
630     memcpy(pinCred->privateData.data, preconfPIN, preconfPINLen);
631     pinCred->privateData.data[preconfPINLen] = '\0';
632     pinCred->privateData.len = preconfPINLen;
633     pinCred->privateData.encoding = OIC_ENCODING_RAW;
634     pinCred->credType = PIN_PASSWORD;
635     memcpy(pinCred->subject.id, targetDeviceInfo->doxm->deviceID.id, sizeof(pinCred->subject.id));
636
637     addCredRes = AddCredential(pinCred);
638     VERIFY_SUCCESS(TAG, (OC_STACK_OK == addCredRes), ERROR);
639
640     OIC_LOG(DEBUG, TAG, "OUT MOTAddPreconfigPIN");
641
642     return addCredRes;
643
644 exit:
645     if(pinCred)
646     {
647         OICFree(pinCred->privateData.data);
648         OICFree(pinCred);
649     }
650     return addCredRes;
651 }
652
653 /**
654  * Function to save the SubOwner PSK.
655  *
656  * @param[in] selectedDeviceInfo   selected device information to performing provisioning.
657  * @return  OC_STACK_OK on success
658  */
659 static OCStackResult SaveSubOwnerPSK(OCProvisionDev_t *selectedDeviceInfo)
660 {
661     OIC_LOG(DEBUG, TAG, "IN SaveSubOwnerPSK");
662
663     OCStackResult res = OC_STACK_ERROR;
664
665     CAEndpoint_t endpoint;
666     CopyDevAddrToEndpoint(&selectedDeviceInfo->endpoint, &endpoint);
667
668     if (CA_ADAPTER_IP == endpoint.adapter)
669     {
670         endpoint.port = selectedDeviceInfo->securePort;
671     }
672 #ifdef WITH_TCP
673     else if (CA_ADAPTER_TCP == endpoint.adapter)
674     {
675         endpoint.port = selectedDeviceInfo->tcpPort;
676     }
677 #endif
678
679     OicUuid_t ownerDeviceID = {.id={0}};
680     if (OC_STACK_OK != GetDoxmDeviceID(&ownerDeviceID))
681     {
682         OIC_LOG(ERROR, TAG, "Error while retrieving SubOwner's device ID");
683         return res;
684     }
685
686     uint8_t ownerPSK[OWNER_PSK_LENGTH_128] = {0};
687     OicSecKey_t ownerKey;
688     memset(&ownerKey, 0, sizeof(ownerKey));
689     ownerKey.data = ownerPSK;
690     ownerKey.len = OWNER_PSK_LENGTH_128;
691     ownerKey.encoding = OIC_ENCODING_RAW;
692
693     //Generating SubOwnerPSK
694     CAResult_t pskRet = CAGenerateOwnerPSK(&endpoint,
695             (uint8_t *)GetOxmString(selectedDeviceInfo->doxm->oxmSel),
696             strlen(GetOxmString(selectedDeviceInfo->doxm->oxmSel)),
697             ownerDeviceID.id, sizeof(ownerDeviceID.id),
698             selectedDeviceInfo->doxm->deviceID.id, sizeof(selectedDeviceInfo->doxm->deviceID.id),
699             ownerPSK, OWNER_PSK_LENGTH_128);
700
701     if (CA_STATUS_OK == pskRet)
702     {
703         OIC_LOG(DEBUG, TAG, "SubOwner PSK dump:");
704         OIC_LOG_BUFFER(DEBUG, TAG, ownerPSK, OWNER_PSK_LENGTH_128);
705         //Generating new credential for provisioning tool
706         OicSecCred_t *cred = GenerateCredential(&selectedDeviceInfo->doxm->deviceID,
707                                       SYMMETRIC_PAIR_WISE_KEY, NULL,
708                                       &ownerKey, &ownerDeviceID, &ownerDeviceID);
709         VERIFY_NOT_NULL(TAG, cred, ERROR);
710
711         size_t outSize = 0;
712         size_t b64BufSize = B64ENCODE_OUT_SAFESIZE((OWNER_PSK_LENGTH_128 + 1));
713         char* b64Buf = (char*)OICCalloc(1, b64BufSize);
714         VERIFY_NOT_NULL(TAG, b64Buf, ERROR);
715         b64Encode(cred->privateData.data, cred->privateData.len, b64Buf, b64BufSize, &outSize);
716
717         OICFree(cred->privateData.data);
718         cred->privateData.data = (uint8_t *)OICCalloc(1, outSize + 1);
719         VERIFY_NOT_NULL(TAG, cred->privateData.data, ERROR);
720
721         strncpy((char*)(cred->privateData.data), b64Buf, outSize);
722         cred->privateData.data[outSize] = '\0';
723         cred->privateData.encoding = OIC_ENCODING_BASE64;
724         cred->privateData.len = outSize;
725         OICFree(b64Buf);
726
727         //Add SubOwnerPSK
728         res = AddCredential(cred);
729         if(res != OC_STACK_OK)
730         {
731             DeleteCredList(cred);
732             return res;
733         }
734     }
735     else
736     {
737         OIC_LOG(ERROR, TAG, "CAGenerateOwnerPSK failed");
738     }
739
740     OIC_LOG(DEBUG, TAG, "OUT SaveSubOwnerPSK");
741 exit:
742     return res;
743 }
744
745
746 /**
747  * Response handler for update subowner crendetial request.
748  *
749  * @param[in] ctx             ctx value passed to callback from calling function.
750  * @param[in] UNUSED          handle to an invocation
751  * @param[in] clientResponse  Response from queries to remote servers.
752  * @return  OC_STACK_DELETE_TRANSACTION to delete the transaction
753  *          and  OC_STACK_KEEP_TRANSACTION to keep it.
754  */
755 static OCStackApplicationResult SubOwnerCredentialHandler(void *ctx, OCDoHandle UNUSED,
756                                 OCClientResponse *clientResponse)
757 {
758     VERIFY_NOT_NULL(TAG, clientResponse, WARNING);
759     VERIFY_NOT_NULL(TAG, ctx, WARNING);
760
761     OIC_LOG(DEBUG, TAG, "IN SubOwnerCredentialHandler");
762     (void)UNUSED;
763     OTMContext_t* motCtx = (OTMContext_t*)ctx;
764
765     if(OC_STACK_RESOURCE_CHANGED == clientResponse->result)
766     {
767         if(motCtx && motCtx->selectedDeviceInfo)
768         {
769             //Close the temporal secure session to verify the owner credential
770             CAEndpoint_t* endpoint = (CAEndpoint_t *)&motCtx->selectedDeviceInfo->endpoint;
771             endpoint->port = motCtx->selectedDeviceInfo->securePort;
772             CAResult_t caResult = CAcloseSslSession(endpoint);
773             if(CA_STATUS_OK != caResult)
774             {
775                 OIC_LOG(ERROR, TAG, "Failed to close DTLS session");
776                 SetMOTResult(motCtx, OC_STACK_ERROR);
777                 return OC_STACK_DELETE_TRANSACTION;
778             }
779
780             caResult = CASelectCipherSuite(MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256, endpoint->adapter);
781             if(CA_STATUS_OK != caResult)
782             {
783                 OIC_LOG(ERROR, TAG, "Failed to select TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256");
784                 SetMOTResult(motCtx, OC_STACK_ERROR);
785                 return OC_STACK_DELETE_TRANSACTION;
786             }
787
788             SetMOTResult(motCtx, OC_STACK_OK);
789         }
790     }
791     else
792     {
793         OIC_LOG_V(ERROR, TAG, "SubOwnerCredentialHandler : Unexpected result %d",
794                   clientResponse->result);
795         SetMOTResult(motCtx, clientResponse->result);
796     }
797
798     OIC_LOG(DEBUG, TAG, "OUT SubOwnerCredentialHandler");
799
800 exit:
801     return  OC_STACK_DELETE_TRANSACTION;
802 }
803
804
805 static OCStackResult PostSubOwnerCredential(OTMContext_t* motCtx)
806 {
807     OIC_LOG(DEBUG, TAG, "IN PostSubOwnerCredential");
808
809     if(!motCtx || !motCtx->selectedDeviceInfo)
810     {
811         OIC_LOG(ERROR, TAG, "Invalid parameters");
812         return OC_STACK_INVALID_PARAM;
813     }
814
815     OCProvisionDev_t* deviceInfo = motCtx->selectedDeviceInfo;
816     char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
817
818     if(!PMGenerateQuery(true,
819                         deviceInfo->endpoint.addr, deviceInfo->securePort,
820                         deviceInfo->connType,
821                         query, sizeof(query), OIC_RSRC_CRED_URI))
822     {
823         OIC_LOG(ERROR, TAG, "PostSubOwnerCredential : Failed to generate query");
824         return OC_STACK_ERROR;
825     }
826     OIC_LOG_V(DEBUG, TAG, "Query=%s", query);
827     OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
828     if(!secPayload)
829     {
830         OIC_LOG(ERROR, TAG, "Failed to memory allocation");
831         return OC_STACK_NO_MEMORY;
832     }
833
834     //Generate sub-owner credential for new device
835     secPayload->base.type = PAYLOAD_TYPE_SECURITY;
836     const OicSecCred_t* ownerCredential = GetCredResourceData(&(deviceInfo->doxm->deviceID));
837     if(!ownerCredential)
838     {
839         OIC_LOG(ERROR, TAG, "Can not find SubOwnerPSK.");
840         return OC_STACK_NO_RESOURCE;
841     }
842
843     OicUuid_t ownerId = {.id={0}};
844     if(OC_STACK_OK == GetDoxmDeviceID(&ownerId))
845     {
846         OicSecCred_t newCredential;
847         memcpy(&newCredential, ownerCredential, sizeof(OicSecCred_t));
848         newCredential.next = NULL;
849
850         //Set subject ID as SubOwner's ID
851         memcpy(&(newCredential.subject), &ownerId, sizeof(OicUuid_t));
852
853         //Set eowner ID as SubOwner's ID
854         if(NULL == newCredential.eownerID)
855         {
856             newCredential.eownerID = OICCalloc(1, sizeof(OicUuid_t));
857             if(NULL == newCredential.eownerID)
858             {
859                 return OC_STACK_NO_MEMORY;
860             }
861         }
862         memcpy(newCredential.eownerID->id, ownerId.id, sizeof(ownerId.id));
863
864         //Fill private data as empty string
865         newCredential.privateData.data = (uint8_t*)"";
866         newCredential.privateData.len = 0;
867         newCredential.privateData.encoding = ownerCredential->privateData.encoding;
868
869 #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
870         newCredential.publicData.data = NULL;
871         newCredential.publicData.len = 0;
872         newCredential.publicData.encoding = ownerCredential->publicData.encoding;
873 #endif
874         //Send owner credential to new device : POST /oic/sec/cred [ owner credential ]
875         if (OC_STACK_OK != CredToCBORPayload(&newCredential, &secPayload->securityData,
876                                         &secPayload->payloadSize, 0))
877         {
878             OICFree(secPayload);
879             OIC_LOG(ERROR, TAG, "Error while converting bin to cbor.");
880             return OC_STACK_ERROR;
881         }
882         OIC_LOG(DEBUG, TAG, "Cred Payload:");
883         OIC_LOG_BUFFER(DEBUG, TAG, secPayload->securityData, secPayload->payloadSize);
884
885         OCCallbackData cbData;
886         cbData.cb = &SubOwnerCredentialHandler;
887         cbData.context = (void *)motCtx;
888         cbData.cd = NULL;
889         OCStackResult res = OCDoResource(NULL, OC_REST_POST, query,
890                                          &deviceInfo->endpoint, (OCPayload*)secPayload,
891                                          deviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0);
892         if (res != OC_STACK_OK)
893         {
894             OIC_LOG(ERROR, TAG, "OCStack resource error");
895         }
896     }
897     else
898     {
899         OIC_LOG(ERROR, TAG, "Failed to read DOXM device ID.");
900         return OC_STACK_NO_RESOURCE;
901     }
902
903     OIC_LOG(DEBUG, TAG, "OUT PostSubOwnerCredential");
904
905     return OC_STACK_OK;
906 }
907
908 static void MOTSessionEstablished(const CAEndpoint_t *endpoint, OicSecDoxm_t *newDevDoxm, OTMContext_t *motCtx)
909 {
910     OC_UNUSED(endpoint);
911     OC_UNUSED(newDevDoxm);
912
913     OIC_LOG_V(DEBUG, TAG, "IN %s", __func__);
914
915     // Delete previous credential such as preconfigured-pin
916     OCStackResult res = RemoveCredential(&(motCtx->selectedDeviceInfo->doxm->deviceID));
917     if (OC_STACK_RESOURCE_DELETED != res)
918     {
919         OIC_LOG(WARNING, TAG, "Cannot find credential.");
920     }
921
922     res = SaveSubOwnerPSK(motCtx->selectedDeviceInfo);
923     if (OC_STACK_OK == res)
924     {
925         // POST sub owner credential to new device.
926         res = PostSubOwnerCredential(motCtx);
927         if (OC_STACK_OK != res)
928         {
929             OIC_LOG(ERROR, TAG, "Failed to send POST request for SubOwner Credential");
930             SetMOTResult(motCtx, res);
931         }
932     }
933     else
934     {
935         OIC_LOG(ERROR, TAG, "Failed to save the SubOwner PSK.");
936         SetMOTResult(motCtx, res);
937     }    
938
939     OIC_LOG_V(DEBUG, TAG, "OUT %s", __func__);
940 }
941
942 static void MOTSessionFailed(const CAEndpoint_t *endpoint, const CAErrorInfo_t *info, OicSecDoxm_t *newDevDoxm, OTMContext_t *motCtx)
943 {
944     OC_UNUSED(endpoint);
945
946     OIC_LOG_V(DEBUG, TAG, "IN %s", __func__);
947
948     if (CA_DTLS_AUTHENTICATION_FAILURE != info->result)
949     {
950         OIC_LOG_V(ERROR, TAG, "Ownership Transfer session establishment failed, error %u", info->result);
951         goto exit;
952     }
953
954     // Reset for the next attempt
955     RemoveOTMContext(motCtx->selectedDeviceInfo->endpoint.addr, motCtx->selectedDeviceInfo->securePort);
956
957     OCStackResult res = PDMDeleteDevice(&(motCtx->selectedDeviceInfo->doxm->deviceID));
958     if (OC_STACK_OK != res)
959     {
960         OIC_LOG(ERROR, TAG, "PDMDeleteDevice failed");
961         SetMOTResult(motCtx, res);
962         goto exit;
963     }
964
965     if (OIC_RANDOM_DEVICE_PIN == newDevDoxm->oxmSel)
966     {
967         OIC_LOG(DEBUG, TAG, "The PIN may be incorrect.");
968
969         motCtx->attemptCnt++;
970         
971         if (WRONG_PIN_MAX_ATTEMP > motCtx->attemptCnt)
972         {
973             res = StartMultipleOwnershipTransfer(motCtx, motCtx->selectedDeviceInfo);
974             if (OC_STACK_OK != res)
975             {
976                 OIC_LOG(ERROR, TAG, "Failed to Re-StartMultipleOwnershipTransfer");
977                 SetMOTResult(motCtx, res);
978             }
979         }
980         else
981         {
982             OIC_LOG(ERROR, TAG, "User has exceeded the number of authentication attempts.");
983             SetMOTResult(motCtx, OC_STACK_AUTHENTICATION_FAILURE);
984         }
985     }
986     else if (OIC_PRECONFIG_PIN == newDevDoxm->oxmSel)
987     {
988         OIC_LOG(DEBUG, TAG, "The PIN may be incorrect.");
989
990         // Delete previous credential
991         res = RemoveCredential(&(motCtx->selectedDeviceInfo->doxm->deviceID));
992         if (OC_STACK_RESOURCE_DELETED != res)
993         {
994             OIC_LOG(WARNING, TAG, "Cannot find credential.");
995         }
996
997         SetMOTResult(motCtx, OC_STACK_AUTHENTICATION_FAILURE);
998     }
999     else
1000     {
1001         OIC_LOG(ERROR, TAG, "Failed to establish secure session.");
1002         SetMOTResult(motCtx, OC_STACK_AUTHENTICATION_FAILURE);
1003     }
1004
1005 exit:
1006     OIC_LOG_V(DEBUG, TAG, "OUT %s", __func__);
1007 }
1008
1009 /**
1010  * Function to handle the handshake result in MOT.
1011  * This function will be invoked after DTLS handshake
1012  * @param   endPoint  [IN] The remote endpoint.
1013  * @param   errorInfo [IN] Error information from the endpoint.
1014  * @return  NONE
1015  */
1016 static void MOTDtlsHandshakeCB(const CAEndpoint_t *endpoint, const CAErrorInfo_t *info)
1017 {
1018     OIC_LOG_V(INFO, TAG, "In %s(endpoint = %p, info = %p)", __func__, endpoint, info);
1019
1020     if (!endpoint || !info)
1021     {
1022         goto exit;
1023     }
1024
1025     OIC_LOG_V(INFO, TAG, "Received status from remote device(%s:%d) : %d",
1026               endpoint->addr, endpoint->port, info->result);
1027
1028     OTMContext_t* motCtx = GetOTMContext(endpoint->addr, endpoint->port);
1029     if (!motCtx)
1030     {
1031         OIC_LOG(ERROR, TAG, "MOT context not found!");
1032         goto exit;
1033     }
1034
1035     OicSecDoxm_t* newDevDoxm = motCtx->selectedDeviceInfo->doxm;
1036     if (!newDevDoxm)
1037     {
1038         OIC_LOG(ERROR, TAG, "New device doxm not found!");
1039         goto exit;
1040     }
1041
1042     // Make sure the address matches.
1043     if ((0 != strncmp(motCtx->selectedDeviceInfo->endpoint.addr, endpoint->addr, sizeof(endpoint->addr))) ||
1044         (motCtx->selectedDeviceInfo->securePort != endpoint->port))
1045     {
1046         OIC_LOG_V(ERROR, TAG, "Mismatched: expected address %s:%u",
1047                   motCtx->selectedDeviceInfo->endpoint.addr, motCtx->selectedDeviceInfo->securePort);
1048         goto exit;
1049     }
1050
1051     // If temporal secure session established successfully
1052     if (CA_STATUS_OK == info->result)
1053     {
1054         MOTSessionEstablished(endpoint, newDevDoxm, motCtx);
1055     }
1056     else
1057     {
1058         MOTSessionFailed(endpoint, info, newDevDoxm, motCtx);
1059     }
1060
1061 exit:
1062     OIC_LOG_V(INFO, TAG, "Out %s", __func__);
1063 }
1064
1065 /**
1066  * Function to add a device to the provisioning database via the 
1067  * Provisioning Database Manager (PDM).
1068  * @param  selectedDevice [IN] Device to add to the provisioning database.
1069  * @return OC_STACK_OK in case of success and other values otherwise.
1070  */
1071 static OCStackResult SetupMOTPDM(OCProvisionDev_t* selectedDevice)
1072 {
1073     OIC_LOG_V(DEBUG, TAG, "IN %s", __func__);
1074    
1075     OCStackResult res = OC_STACK_INVALID_PARAM;
1076     PdmDeviceState_t pdmState = PDM_DEVICE_UNKNOWN;
1077     char deviceId[UUID_STRING_SIZE];
1078     bool isSubowner = false;
1079     bool isDuplicate = true;
1080
1081     VERIFY_NOT_NULL(TAG, selectedDevice, ERROR);
1082     VERIFY_NOT_NULL(TAG, selectedDevice->doxm, ERROR);
1083
1084     res = PMIsSubownerOfDevice(selectedDevice, &isSubowner);
1085     if (OC_STACK_OK != res)
1086     {
1087         OIC_LOG_V(ERROR, TAG, "Internal error in PMIsSubownerOfDevice : %d", res);
1088         return res;
1089     }
1090     
1091     res = PDMGetDeviceState(&selectedDevice->doxm->deviceID, &pdmState);
1092     if (OC_STACK_OK != res)
1093     {
1094         OIC_LOG_V(ERROR, TAG, "Internal error in PDMGetDeviceState : %d", res);
1095         return res;
1096     }
1097
1098     if (!OCConvertUuidToString(selectedDevice->doxm->deviceID.id, deviceId))
1099     {
1100         OIC_LOG(WARNING, TAG, "Failed to covert uuid to string");
1101         return OC_STACK_ERROR;
1102     }
1103
1104     if ((PDM_DEVICE_ACTIVE == pdmState) && !isSubowner)
1105     {
1106         OIC_LOG_V(WARNING, TAG, "Not a subowner for device[%s] dectected in PDM.", deviceId);
1107         OIC_LOG_V(WARNING, TAG, "[%s] will be removed from PDM.", deviceId);
1108
1109         res = PDMDeleteDevice(&selectedDevice->doxm->deviceID);
1110         if (OC_STACK_OK != res)
1111         {
1112             OIC_LOG_V(ERROR, TAG, "Failed to remove [%s] information from PDM.", deviceId);
1113             goto exit;
1114         }
1115     }
1116
1117     // Checking duplication of Device ID.
1118     res = PDMIsDuplicateDevice(&selectedDevice->doxm->deviceID, &isDuplicate);
1119     if (OC_STACK_OK != res)
1120     {
1121         OIC_LOG_V(ERROR, TAG, "Internal error in PDMIsDuplicateDevice : %d", res);
1122         goto exit;
1123     }
1124
1125     if (isDuplicate)
1126     {
1127         if (PDM_DEVICE_STALE == pdmState)
1128         {
1129             OIC_LOG(INFO, TAG, "Detected duplicated UUID in stale status, "
1130                 "device status will revert back to initial status.");
1131             res = PDMSetDeviceState(&selectedDevice->doxm->deviceID, PDM_DEVICE_INIT);
1132             if (OC_STACK_OK != res)
1133             {
1134                 OIC_LOG_V(ERROR, TAG, "Internal error in PDMSetDeviceState : %d", res);
1135                 goto exit;
1136             }
1137         }
1138         else if (PDM_DEVICE_INIT == pdmState)
1139         {
1140             OIC_LOG_V(ERROR, TAG, "[%s]'s ownership transfer process is already started.", deviceId);
1141             res = OC_STACK_DUPLICATE_REQUEST;
1142             goto exit;
1143         }
1144         else
1145         {
1146             OIC_LOG(ERROR, TAG, "Unknown device status while OTM.");
1147             res = OC_STACK_ERROR;
1148             goto exit;
1149         }
1150     }
1151     else
1152     {
1153         res = PDMAddDevice(&selectedDevice->doxm->deviceID);
1154         if (OC_STACK_OK != res)
1155         {
1156             OIC_LOG_V(ERROR, TAG, "Internal error in PDMAddDevice : %d", res);
1157             goto exit;
1158         }
1159     }
1160
1161 exit:
1162     OIC_LOG_V(DEBUG, TAG, "OUT %s", __func__);
1163     return res;
1164 }
1165
1166 static OCStackResult StartMultipleOwnershipTransfer(OTMContext_t* motCtx,
1167                                                     OCProvisionDev_t* selectedDevice)
1168 {
1169     OIC_LOG(INFO, TAG, "IN StartMultipleOwnershipTransfer");
1170
1171     OCStackResult res = OC_STACK_INVALID_PARAM;
1172     OicUuid_t myUuid = {.id={0}};
1173
1174     VERIFY_NOT_NULL(TAG, motCtx, ERROR);
1175     VERIFY_NOT_NULL(TAG, selectedDevice, ERROR);
1176     VERIFY_NOT_NULL(TAG, selectedDevice->doxm, ERROR);
1177     motCtx->selectedDeviceInfo = selectedDevice;
1178
1179     res = GetDoxmDeviceID(&myUuid);
1180     if(OC_STACK_OK != res)
1181     {
1182         OIC_LOG(ERROR, TAG, "Failed to GetDoxmDeviceID");
1183         SetMOTResult(motCtx, res);
1184         return res;
1185     }
1186
1187     if(memcmp(selectedDevice->doxm->owner.id, myUuid.id, sizeof(myUuid.id)) == 0)
1188     {
1189         res = OC_STACK_INVALID_DEVICE_INFO;
1190         OIC_LOG(ERROR, TAG, "Owner cannot be registered as sub-owner.");
1191         SetMOTResult(motCtx, res);
1192         return res;
1193     }
1194
1195     if ((NULL == selectedDevice->doxm->mom) ||
1196         (selectedDevice->doxm->mom &&
1197         (OIC_MULTIPLE_OWNER_DISABLE == selectedDevice->doxm->mom->mode)))
1198     {
1199         res = OC_STACK_NOT_ACCEPTABLE;
1200         OIC_LOG(ERROR, TAG, "MOT is disabled for the selected device.");
1201         SetMOTResult(motCtx, res);
1202         return res;
1203     }
1204
1205     // Setup PDM to perform the MOT, PDM will be cleanup if necessary.
1206     res = SetupMOTPDM(selectedDevice);
1207     if (OC_STACK_OK != res)
1208     {
1209         OIC_LOG_V(ERROR, TAG, "SetupMOTPDM error : %d", res);
1210         SetMOTResult(motCtx, res);
1211         return res;
1212     }
1213
1214     // Register DTLS event handler to catch the dtls event while handshake
1215     if(CA_STATUS_OK != CAregisterSslHandshakeCallback(MOTDtlsHandshakeCB))
1216     {
1217         OIC_LOG(WARNING, TAG, "StartOwnershipTransfer : Failed to register DTLS handshake callback.");
1218     }
1219
1220     OicSecOxm_t oxmSel = selectedDevice->doxm->oxmSel;
1221     OIC_LOG_V(DEBUG, TAG, "Multiple Ownership Transfer method = %d", (int)oxmSel);
1222
1223     if((OIC_PRECONFIG_PIN != oxmSel) && (OIC_RANDOM_DEVICE_PIN != oxmSel))
1224     {
1225         OIC_LOG(ERROR, TAG, "Unsupported OxM");
1226         return OC_STACK_ERROR;
1227     }
1228
1229     res = OTMSetOTCallback(selectedDevice->doxm->oxmSel, &motCtx->otmCallback);
1230     if(OC_STACK_OK != res)
1231     {
1232         OIC_LOG_V(ERROR, TAG, "Error in OTMSetOTCallback : %d", res);
1233         return res;
1234     }
1235
1236     // Only two functions required for MOT
1237     VERIFY_NOT_NULL(TAG, motCtx->otmCallback.loadSecretCB, ERROR);
1238     VERIFY_NOT_NULL(TAG, motCtx->otmCallback.createSecureSessionCB, ERROR);
1239
1240     if(OIC_RANDOM_DEVICE_PIN == oxmSel)
1241     {
1242         if(CA_STATUS_OK != CAregisterPskCredentialsHandler(GetDtlsPskForRandomPinOxm))
1243         {
1244             OIC_LOG(ERROR, TAG, "Failed to register DTLS credential handler for Random PIN OxM.");
1245         }
1246     }
1247
1248     // Save the current context instance to use on the dtls handshake callback
1249     res = AddOTMContext(motCtx, selectedDevice->endpoint.addr, selectedDevice->securePort);
1250     VERIFY_SUCCESS(TAG, OC_STACK_OK == res, ERROR);
1251
1252     res = motCtx->otmCallback.loadSecretCB(motCtx);
1253     VERIFY_SUCCESS(TAG, OC_STACK_OK == res, ERROR);
1254
1255     res = motCtx->otmCallback.createSecureSessionCB(motCtx);
1256     VERIFY_SUCCESS(TAG, OC_STACK_OK == res, ERROR);
1257
1258     OIC_LOG(INFO, TAG, "OUT StartMultipleOwnershipTransfer");
1259
1260 exit:
1261     return res;
1262 }
1263
1264 OCStackResult MOTDoOwnershipTransfer(void* ctx,
1265                                      OCProvisionDev_t *selectedDevicelist,
1266                                      OCProvisionResultCB resultCallback)
1267 {
1268     OIC_LOG(DEBUG, TAG, "IN MOTDoOwnershipTransfer");
1269     OCStackResult res = OC_STACK_INVALID_PARAM;
1270     OTMContext_t* motCtx = NULL;
1271     OCProvisionDev_t* pCurDev = NULL;
1272
1273     VERIFY_NOT_NULL(TAG, selectedDevicelist, ERROR);
1274     VERIFY_NOT_NULL(TAG, resultCallback, ERROR);
1275
1276     res = OC_STACK_NO_MEMORY;
1277     motCtx = (OTMContext_t*)OICCalloc(1,sizeof(OTMContext_t));
1278     VERIFY_NOT_NULL(TAG, motCtx, ERROR);
1279
1280     motCtx->ctxResultCallback = resultCallback;
1281     motCtx->ctxHasError = false;
1282     motCtx->userCtx = ctx;
1283     motCtx->ctxResultArraySize = 0;
1284     LL_FOREACH(selectedDevicelist, pCurDev)
1285     {
1286         motCtx->ctxResultArraySize++;
1287     }
1288
1289     motCtx->ctxResultArray =
1290         (OCProvisionResult_t*)OICCalloc(motCtx->ctxResultArraySize, sizeof(OCProvisionResult_t));
1291     VERIFY_NOT_NULL(TAG, motCtx->ctxResultArray, ERROR);
1292
1293     //Fill the device UUID for result array.
1294     size_t devIdx = 0;
1295     pCurDev = NULL;
1296     LL_FOREACH(selectedDevicelist, pCurDev)
1297     {
1298         memcpy(motCtx->ctxResultArray[devIdx].deviceId.id,
1299                pCurDev->doxm->deviceID.id,
1300                UUID_LENGTH);
1301         motCtx->ctxResultArray[devIdx].res = OC_STACK_CONTINUE;
1302         devIdx++;
1303     }
1304
1305     motCtx->selectedDeviceInfo = selectedDevicelist;
1306     res = StartMultipleOwnershipTransfer(motCtx, selectedDevicelist);
1307
1308     OIC_LOG(DEBUG, TAG, "OUT MOTDoOwnershipTransfer");
1309     return res;
1310 exit:
1311     if(OC_STACK_OK != res)
1312     {
1313         if(motCtx)
1314         {
1315             OICFree(motCtx->ctxResultArray);
1316             OICFree(motCtx);
1317         }
1318     }
1319     return res;
1320 }