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