Correct the ENUM value of OTM according to spec.
[platform/upstream/iotivity.git] / resource / csdk / security / provisioning / src / ownershiptransfermanager.c
1 /* *****************************************************************
2  *
3  * Copyright 2015 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 // Defining _POSIX_C_SOURCE macro with 199309L (or greater) as value
22 // causes header files to expose definitions
23 // corresponding to the POSIX.1b, Real-time extensions
24 // (IEEE Std 1003.1b-1993) specification
25 //
26 // For this specific file, see use of clock_gettime,
27 // Refer to http://pubs.opengroup.org/stage7tc1/functions/clock_gettime.html
28 // and to http://man7.org/linux/man-pages/man2/clock_gettime.2.html
29 #ifndef _POSIX_C_SOURCE
30 #define _POSIX_C_SOURCE 200809L
31 #endif
32
33 #include <time.h>
34 #include <unistd.h>
35 #include <sys/time.h>
36 #include <stdbool.h>
37 #include <string.h>
38
39 #include "logger.h"
40 #include "oic_malloc.h"
41 #include "oic_string.h"
42 #include "cacommon.h"
43 #include "cainterface.h"
44 #include "base64.h"
45 #include "cJSON.h"
46 #include "global.h"
47
48 #include "srmresourcestrings.h"
49 #include "doxmresource.h"
50 #include "pstatresource.h"
51 #include "credresource.h"
52 #include "aclresource.h"
53 #include "ownershiptransfermanager.h"
54 #include "securevirtualresourcetypes.h"
55 #include "oxmjustworks.h"
56 #include "pmtypes.h"
57 #include "pmutility.h"
58 #include "srmutility.h"
59 #include "provisioningdatabasemanager.h"
60 #include "oxmrandompin.h"
61
62 #define TAG "OTM"
63
64 /**
65  * Array to store the callbacks for each owner transfer method.
66  */
67 static OTMCallbackData_t g_OTMDatas[OIC_OXM_COUNT];
68
69 /**
70  * Variable for storing provisioning tool's provisioning capabilities
71  * Must be in decreasing order of preference. More prefered method should
72  * have lower array index.
73  */
74 static OicSecDpom_t gProvisioningToolCapability[] = { SINGLE_SERVICE_CLIENT_DRIVEN };
75
76 /**
77  * Number of supported provisioning methods
78  * current version supports only one.
79  */
80 static size_t gNumOfProvisioningMethodsPT = 1;
81
82 /**
83  * Function to getting string of ownership transfer method
84  */
85 static const char* GetOxmString(OicSecOxm_t oxmType)
86 {
87     switch(oxmType)
88     {
89         case OIC_JUST_WORKS:
90             return OXM_JUST_WORKS;
91         case OIC_RANDOM_DEVICE_PIN:
92             return OXM_RANDOM_DEVICE_PIN;
93         case OIC_MANUFACTURER_CERTIFICATE:
94             return OXM_MANUFACTURER_CERTIFICATE;
95         default:
96             return NULL;
97     }
98 }
99
100 /**
101  * Function to select appropriate  provisioning method.
102  *
103  * @param[in] supportedMethods   Array of supported methods
104  * @param[in] numberOfMethods   number of supported methods
105  * @param[out]  selectedMethod         Selected methods
106  * @return  OC_STACK_OK on success
107  */
108 static OCStackResult SelectProvisioningMethod(const OicSecOxm_t *supportedMethods,
109                                                             size_t numberOfMethods,
110                                                             OicSecOxm_t *selectedMethod)
111 {
112     OC_LOG(DEBUG, TAG, "IN SelectProvisioningMethod");
113
114     if(numberOfMethods == 0 || !supportedMethods)
115     {
116         OC_LOG(WARNING, TAG, "Could not find a supported OxM.");
117         return OC_STACK_ERROR;
118     }
119
120     *selectedMethod  = supportedMethods[0];
121     for(size_t i = 0; i < numberOfMethods; i++)
122     {
123         if(*selectedMethod < supportedMethods[i])
124         {
125             *selectedMethod =  supportedMethods[i];
126         }
127     }
128
129     return OC_STACK_OK;
130 }
131
132 /**
133  * Function to select operation mode.This function will return most secure common operation mode.
134  *
135  * @param[in] selectedDeviceInfo   selected device information to performing provisioning.
136  * @param[out]   selectedMode   selected operation mode
137  * @return  OC_STACK_OK on success
138  */
139 static void SelectOperationMode(const OCProvisionDev_t *selectedDeviceInfo,
140                                 OicSecDpom_t *selectedMode)
141 {
142     OC_LOG(DEBUG, TAG, "IN SelectOperationMode");
143
144     size_t i = 0;
145     size_t j = 0;
146
147     while (i < gNumOfProvisioningMethodsPT && j < selectedDeviceInfo->pstat->smLen)
148     {
149         if (gProvisioningToolCapability[i] < selectedDeviceInfo->pstat->sm[j])
150         {
151             i++;
152         }
153         else if (selectedDeviceInfo->pstat->sm[j] < gProvisioningToolCapability[i])
154         {
155             j++;
156         }
157         else /* if gProvisioningToolCapability[i] == deviceSupportedMethods[j] */
158         {
159             *selectedMode = gProvisioningToolCapability[j];
160             break;
161         }
162     }
163     OC_LOG(DEBUG, TAG, "OUT SelectOperationMode");
164 }
165
166 /**
167  * Function to update owner transfer mode
168  *
169  * @param[in]  otmCtx  Context value of ownership transfer.
170  * @return  OC_STACK_OK on success
171  */
172 static OCStackResult PutOwnerTransferModeToResource(OTMContext_t* otmCtx);
173
174 /**
175  * Function to send request to resource to get its pstat resource information.
176  *
177  * @param[in]  otmCtx  Context value of ownership transfer.
178  * @return  OC_STACK_OK on success
179  */
180 static OCStackResult GetProvisioningStatusResource(OTMContext_t* otmCtx);
181
182
183 /**
184  * Function to send ownerShip info. This function would update Owned as true and
185  * owner as UUID for provisioning tool
186  *
187  * @param[in]  otmCtx  Context value of ownership transfer.
188  * @return  OC_STACK_OK on success
189  */
190 static OCStackResult PutOwnershipInformation(OTMContext_t* otmCtx);
191
192 /**
193  * Function to update the operation mode. As per the spec. Operation mode in client driven
194  * single service provisioning it will be updated to 0x3
195  *
196  * @param[in]  otmCtx  Context value of ownership transfer.
197  * @param[in] selectedOperationMode selected operation mode
198  * @return  OC_STACK_OK on success
199  */
200 static OCStackResult PutUpdateOperationMode(OTMContext_t* otmCtx,
201                                     OicSecDpom_t selectedOperationMode);
202
203 /**
204  * Function to start ownership transfer.
205  * This function will send the first request for provisioning,
206  * The next request message is sent from the response handler for this request.
207  *
208  * @param[in] ctx   context value passed to callback from calling function.
209  * @param[in] selectedDevice   selected device information to performing provisioning.
210  * @return  OC_STACK_OK on success
211  */
212 static OCStackResult StartOwnershipTransfer(void* ctx, OCProvisionDev_t* selectedDevice);
213
214 /*
215  * Function to finalize provisioning.
216  * This function will send default ACL and commit hash.
217  *
218  * @param[in] otmCtx   Context value of ownership transfer.
219  * @return  OC_STACK_OK on success
220  */
221 static OCStackResult FinalizeProvisioning(OTMContext_t* otmCtx);
222
223
224 static bool IsComplete(OTMContext_t* otmCtx)
225 {
226     for(size_t i = 0; i < otmCtx->ctxResultArraySize; i++)
227     {
228         if(OC_STACK_CONTINUE == otmCtx->ctxResultArray[i].res)
229         {
230             return false;
231         }
232     }
233
234     return true;
235 }
236
237 /**
238  * Function to save the result of provisioning.
239  *
240  * @param[in,out] otmCtx   Context value of ownership transfer.
241  * @param[in] res   result of provisioning
242  */
243 static void SetResult(OTMContext_t* otmCtx, const OCStackResult res)
244 {
245     OC_LOG(DEBUG, TAG, "IN SetResult");
246
247     if(!otmCtx)
248     {
249         OC_LOG(WARNING, TAG, "OTMContext is NULL");
250         return;
251     }
252
253     if(otmCtx->selectedDeviceInfo)
254     {
255         for(size_t i = 0; i < otmCtx->ctxResultArraySize; i++)
256         {
257             if(memcmp(otmCtx->selectedDeviceInfo->doxm->deviceID.id,
258                       otmCtx->ctxResultArray[i].deviceId.id, UUID_LENGTH) == 0)
259             {
260                 otmCtx->ctxResultArray[i].res = res;
261                 if(OC_STACK_OK != res)
262                 {
263                     otmCtx->ctxHasError = true;
264                 }
265             }
266         }
267
268         //If all request is completed, invoke the user callback.
269         if(IsComplete(otmCtx))
270         {
271             otmCtx->ctxResultCallback(otmCtx->userCtx, otmCtx->ctxResultArraySize,
272                                        otmCtx->ctxResultArray, otmCtx->ctxHasError);
273             OICFree(otmCtx->ctxResultArray);
274             OICFree(otmCtx);
275         }
276         else
277         {
278             if(OC_STACK_OK != StartOwnershipTransfer(otmCtx,
279                                                      otmCtx->selectedDeviceInfo->next))
280             {
281                 OC_LOG(ERROR, TAG, "Failed to StartOwnershipTransfer");
282             }
283         }
284     }
285
286     OC_LOG(DEBUG, TAG, "OUT SetResult");
287 }
288
289
290 /**
291  * Function to save ownerPSK at provisioning tool end.
292  *
293  * @param[in] selectedDeviceInfo   selected device information to performing provisioning.
294  * @return  OC_STACK_OK on success
295  */
296 static OCStackResult SaveOwnerPSK(OCProvisionDev_t *selectedDeviceInfo)
297 {
298     OC_LOG(DEBUG, TAG, "IN SaveOwnerPSK");
299
300     OCStackResult res = OC_STACK_ERROR;
301
302     CAEndpoint_t endpoint;
303     memset(&endpoint, 0x00, sizeof(CAEndpoint_t));
304     OICStrcpy(endpoint.addr, MAX_ADDR_STR_SIZE_CA, selectedDeviceInfo->endpoint.addr);
305     endpoint.addr[MAX_ADDR_STR_SIZE_CA - 1] = '\0';
306     endpoint.port = selectedDeviceInfo->securePort;
307
308     OicUuid_t ptDeviceID = {.id={0}};
309     if (OC_STACK_OK != GetDoxmDeviceID(&ptDeviceID))
310     {
311         OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
312         return res;
313     }
314
315     uint8_t ownerPSK[OWNER_PSK_LENGTH_128] = {0};
316
317     //Generating OwnerPSK
318     CAResult_t pskRet = CAGenerateOwnerPSK(&endpoint,
319             (uint8_t *)GetOxmString(selectedDeviceInfo->doxm->oxmSel),
320             strlen(GetOxmString(selectedDeviceInfo->doxm->oxmSel)), ptDeviceID.id,
321             sizeof(ptDeviceID.id), selectedDeviceInfo->doxm->deviceID.id,
322             sizeof(selectedDeviceInfo->doxm->deviceID.id), ownerPSK,
323             OWNER_PSK_LENGTH_128);
324
325     if (CA_STATUS_OK == pskRet)
326     {
327         OC_LOG(INFO, TAG,"ownerPSK dump:\n");
328         OC_LOG_BUFFER(INFO, TAG,ownerPSK, OWNER_PSK_LENGTH_128);
329         //Generating new credential for provisioning tool
330         size_t ownLen = 1;
331         uint32_t outLen = 0;
332
333         char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(ownerPSK)) + 1] = {};
334         B64Result b64Ret = b64Encode(ownerPSK, sizeof(ownerPSK), base64Buff, sizeof(base64Buff),
335                 &outLen);
336         VERIFY_SUCCESS(TAG, B64_OK == b64Ret, ERROR);
337
338         OicSecCred_t *cred = GenerateCredential(&selectedDeviceInfo->doxm->deviceID,
339                 SYMMETRIC_PAIR_WISE_KEY, NULL,
340                 base64Buff, ownLen, &ptDeviceID);
341         VERIFY_NON_NULL(TAG, cred, ERROR);
342
343         res = AddCredential(cred);
344         if(res != OC_STACK_OK)
345         {
346             DeleteCredList(cred);
347             return res;
348         }
349     }
350     else
351     {
352         OC_LOG(ERROR, TAG, "CAGenerateOwnerPSK failed");
353     }
354
355     OC_LOG(DEBUG, TAG, "OUT SaveOwnerPSK");
356 exit:
357     return res;
358 }
359
360 /**
361  * Callback handler for OwnerShipTransferModeHandler API.
362  *
363  * @param[in] ctx             ctx value passed to callback from calling function.
364  * @param[in] UNUSED          handle to an invocation
365  * @param[in] clientResponse  Response from queries to remote servers.
366  * @return  OC_STACK_DELETE_TRANSACTION to delete the transaction
367  *          and  OC_STACK_KEEP_TRANSACTION to keep it.
368  */
369 static OCStackApplicationResult OwnerTransferModeHandler(void *ctx, OCDoHandle UNUSED,
370                                                          OCClientResponse *clientResponse)
371 {
372     OC_LOG(DEBUG, TAG, "IN OwnerTransferModeHandler");
373
374     VERIFY_NON_NULL(TAG, clientResponse, WARNING);
375     VERIFY_NON_NULL(TAG, ctx, WARNING);
376
377     OTMContext_t* otmCtx = (OTMContext_t*)ctx;
378     (void)UNUSED;
379     if(clientResponse->result == OC_STACK_OK)
380     {
381         OC_LOG(INFO, TAG, "OwnerTransferModeHandler : response result = OC_STACK_OK");
382         //Send request : GET /oic/sec/pstat
383         OCStackResult res = GetProvisioningStatusResource(otmCtx);
384         if(OC_STACK_OK != res)
385         {
386             OC_LOG(WARNING, TAG, "Failed to get pstat information");
387             SetResult(otmCtx, res);
388         }
389     }
390     else
391     {
392         OC_LOG_V(WARNING, TAG, "OwnerTransferModeHandler : Client response is incorrect : %d",
393         clientResponse->result);
394         SetResult(otmCtx, clientResponse->result);
395     }
396
397     OC_LOG(DEBUG, TAG, "OUT OwnerTransferModeHandler");
398
399 exit:
400     return  OC_STACK_DELETE_TRANSACTION;
401 }
402
403 /**
404  * Callback handler for ProvisioningStatusResouceHandler API.
405  *
406  * @param[in] ctx             ctx value passed to callback from calling function.
407  * @param[in] UNUSED          handle to an invocation
408  * @param[in] clientResponse  Response from queries to remote servers.
409  * @return  OC_STACK_DELETE_TRANSACTION to delete the transaction
410  *          and  OC_STACK_KEEP_TRANSACTION to keep it.
411  */
412 static OCStackApplicationResult ListMethodsHandler(void *ctx, OCDoHandle UNUSED,
413                                                     OCClientResponse *clientResponse)
414 {
415     OC_LOG(DEBUG, TAG, "IN ListMethodsHandler");
416
417     VERIFY_NON_NULL(TAG, clientResponse, WARNING);
418     VERIFY_NON_NULL(TAG, ctx, WARNING);
419
420     OTMContext_t* otmCtx = (OTMContext_t*)ctx;
421     (void)UNUSED;
422     if  (OC_STACK_OK == clientResponse->result)
423     {
424         if  (NULL == clientResponse->payload)
425         {
426             OC_LOG(INFO, TAG, "Skiping Null payload");
427             SetResult(otmCtx, OC_STACK_ERROR);
428             return OC_STACK_DELETE_TRANSACTION;
429         }
430
431         if (PAYLOAD_TYPE_SECURITY != clientResponse->payload->type)
432         {
433             OC_LOG(INFO, TAG, "Unknown payload type");
434             SetResult(otmCtx, OC_STACK_ERROR);
435             return OC_STACK_DELETE_TRANSACTION;
436         }
437
438         OicSecPstat_t* pstat = JSONToPstatBin(
439                 ((OCSecurityPayload*)clientResponse->payload)->securityData);
440         if(NULL == pstat)
441         {
442             OC_LOG(ERROR, TAG, "Error while converting json to pstat bin");
443             SetResult(otmCtx, OC_STACK_ERROR);
444             return OC_STACK_DELETE_TRANSACTION;
445         }
446         otmCtx->selectedDeviceInfo->pstat = pstat;
447
448         //Select operation mode (Currently supported SINGLE_SERVICE_CLIENT_DRIVEN only)
449         OicSecDpom_t selectedOperationMode;
450         SelectOperationMode(otmCtx->selectedDeviceInfo, &selectedOperationMode);
451
452         //Send request : PUT /oic/sec/pstat [{"OM":"0x11", .. }]
453         OCStackResult res = PutUpdateOperationMode(otmCtx, selectedOperationMode);
454         if (OC_STACK_OK != res)
455         {
456             OC_LOG(ERROR, TAG, "Error while updating operation mode.");
457             SetResult(otmCtx, res);
458         }
459     }
460     else
461     {
462         OC_LOG_V(WARNING, TAG, "ListMethodsHandler : Client response is incorrect : %d",
463             clientResponse->result);
464         SetResult(otmCtx, clientResponse->result);
465     }
466
467     OC_LOG(DEBUG, TAG, "OUT ListMethodsHandler");
468 exit:
469     return  OC_STACK_DELETE_TRANSACTION;
470 }
471
472 /**
473  * Callback handler for OwnershipInformationHandler API.
474  *
475  * @param[in] ctx             ctx value passed to callback from calling function.
476  * @param[in] UNUSED          handle to an invocation
477  * @param[in] clientResponse  Response from queries to remote servers.
478  * @return  OC_STACK_DELETE_TRANSACTION to delete the transaction
479  *          and  OC_STACK_KEEP_TRANSACTION to keep it.
480  */
481 static OCStackApplicationResult OwnershipInformationHandler(void *ctx, OCDoHandle UNUSED,
482                                 OCClientResponse *clientResponse)
483 {
484     VERIFY_NON_NULL(TAG, clientResponse, WARNING);
485     VERIFY_NON_NULL(TAG, ctx, WARNING);
486
487     OC_LOG(DEBUG, TAG, "IN OwnershipInformationHandler");
488     (void)UNUSED;
489     OCStackResult res = OC_STACK_OK;
490     OTMContext_t* otmCtx = (OTMContext_t*)ctx;
491     if  (OC_STACK_OK == clientResponse->result)
492     {
493         if(OIC_RANDOM_DEVICE_PIN == otmCtx->selectedDeviceInfo->doxm->oxmSel)
494         {
495             res = RemoveCredential(&otmCtx->subIdForPinOxm);
496             if(OC_STACK_RESOURCE_DELETED != res)
497             {
498                 OC_LOG_V(ERROR, TAG, "Failed to remove temporal PSK : %d", res);
499                 return OC_STACK_DELETE_TRANSACTION;
500             }
501         }
502
503         res = SaveOwnerPSK(otmCtx->selectedDeviceInfo);
504         if(OC_STACK_OK != res)
505         {
506             OC_LOG(ERROR, TAG, "OperationModeUpdate : Failed to owner PSK generation");
507             SetResult(otmCtx, res);
508             return OC_STACK_DELETE_TRANSACTION;
509         }
510
511         CAEndpoint_t* endpoint = (CAEndpoint_t *)&otmCtx->selectedDeviceInfo->endpoint;
512         endpoint->port = otmCtx->selectedDeviceInfo->securePort;
513         CAResult_t caResult = CACloseDtlsSession(endpoint);
514         if(CA_STATUS_OK != caResult)
515         {
516             OC_LOG(ERROR, TAG, "Failed to close DTLS session");
517             SetResult(otmCtx, caResult);
518             return OC_STACK_DELETE_TRANSACTION;
519         }
520
521         /**
522          * If we select NULL cipher,
523          * client will select appropriate cipher suite according to server's cipher-suite list.
524          */
525         caResult = CASelectCipherSuite(TLS_NULL_WITH_NULL_NULL);
526         if(CA_STATUS_OK != caResult)
527         {
528             OC_LOG(ERROR, TAG, "Failed to select TLS_NULL_WITH_NULL_NULL");
529             SetResult(otmCtx, caResult);
530             return OC_STACK_DELETE_TRANSACTION;
531         }
532
533         OC_LOG(INFO, TAG, "Ownership transfer was successfully completed.");
534         OC_LOG(INFO, TAG, "Start defualt ACL & commit-hash provisioning.");
535
536         res = FinalizeProvisioning(otmCtx);
537         if(OC_STACK_OK != res)
538         {
539             SetResult(otmCtx, res);
540         }
541     }
542     else
543     {
544         res = clientResponse->result;
545     }
546
547     OC_LOG(DEBUG, TAG, "OUT OwnershipInformationHandler");
548
549 exit:
550     return  OC_STACK_DELETE_TRANSACTION;
551 }
552
553 /**
554  * Response handler for update operation mode.
555  *
556  * @param[in] ctx             ctx value passed to callback from calling function.
557  * @param[in] UNUSED          handle to an invocation
558  * @param[in] clientResponse  Response from queries to remote servers.
559  * @return  OC_STACK_DELETE_TRANSACTION to delete the transaction
560  *          and  OC_STACK_KEEP_TRANSACTION to keep it.
561  */
562 static OCStackApplicationResult OperationModeUpdateHandler(void *ctx, OCDoHandle UNUSED,
563                                 OCClientResponse *clientResponse)
564 {
565     OC_LOG(DEBUG, TAG, "IN OperationModeUpdateHandler");
566
567     VERIFY_NON_NULL(TAG, clientResponse, WARNING);
568     VERIFY_NON_NULL(TAG, ctx, WARNING);
569
570     OTMContext_t* otmCtx = (OTMContext_t*)ctx;
571     (void) UNUSED;
572     if  (OC_STACK_OK == clientResponse->result)
573     {
574         OCStackResult res = OC_STACK_ERROR;
575         OicSecOxm_t selOxm = otmCtx->selectedDeviceInfo->doxm->oxmSel;
576         //DTLS Handshake
577         //Load secret for temporal secure session.
578         if(g_OTMDatas[selOxm].loadSecretCB)
579         {
580             res = g_OTMDatas[selOxm].loadSecretCB(otmCtx);
581             if(OC_STACK_OK != res)
582             {
583                 OC_LOG(ERROR, TAG, "OperationModeUpdate : Failed to load secret");
584                 SetResult(otmCtx, res);
585                 return  OC_STACK_DELETE_TRANSACTION;
586             }
587         }
588
589         //Try DTLS handshake to generate secure session
590         if(g_OTMDatas[selOxm].createSecureSessionCB)
591         {
592             res = g_OTMDatas[selOxm].createSecureSessionCB(otmCtx);
593             if(OC_STACK_OK != res)
594             {
595                 OC_LOG(ERROR, TAG, "OperationModeUpdate : Failed to create DTLS session");
596                 SetResult(otmCtx, res);
597                 return OC_STACK_DELETE_TRANSACTION;
598             }
599         }
600
601         //Send request : PUT /oic/sec/doxm [{"Owned":"True", .. , "Owner":"PT's UUID"}]
602         res = PutOwnershipInformation(otmCtx);
603         if(OC_STACK_OK != res)
604         {
605             OC_LOG(ERROR, TAG, "OperationModeUpdate : Failed to send owner information");
606             SetResult(otmCtx, res);
607         }
608     }
609     else
610     {
611         OC_LOG(ERROR, TAG, "Error while update operation mode");
612         SetResult(otmCtx, clientResponse->result);
613     }
614
615     OC_LOG(DEBUG, TAG, "OUT OperationModeUpdateHandler");
616
617 exit:
618     return  OC_STACK_DELETE_TRANSACTION;
619 }
620
621
622 static OCStackResult PutOwnerTransferModeToResource(OTMContext_t* otmCtx)
623 {
624     OC_LOG(DEBUG, TAG, "IN PutOwnerTransferModeToResource");
625
626     if(!otmCtx || !otmCtx->selectedDeviceInfo)
627     {
628         OC_LOG(ERROR, TAG, "Invalid parameters");
629         return OC_STACK_INVALID_PARAM;
630     }
631
632     OCProvisionDev_t* deviceInfo = otmCtx->selectedDeviceInfo;
633     OicSecOxm_t selectedOxm = deviceInfo->doxm->oxmSel;
634     char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
635
636     if(!PMGenerateQuery(false,
637                         deviceInfo->endpoint.addr, deviceInfo->endpoint.port,
638                         deviceInfo->connType,
639                         query, sizeof(query), OIC_RSRC_DOXM_URI))
640     {
641         OC_LOG(ERROR, TAG, "PutOwnerTransferModeToResource : Failed to generate query");
642         return OC_STACK_ERROR;
643     }
644     OC_LOG_V(DEBUG, TAG, "Query=%s", query);
645     OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
646     if(!secPayload)
647     {
648         OC_LOG(ERROR, TAG, "Failed to memory allocation");
649         return OC_STACK_NO_MEMORY;
650     }
651     secPayload->base.type = PAYLOAD_TYPE_SECURITY;
652     secPayload->securityData = g_OTMDatas[selectedOxm].createSelectOxmPayloadCB(otmCtx);
653     if (NULL == secPayload->securityData)
654     {
655         OICFree(secPayload);
656         OC_LOG(ERROR, TAG, "Error while converting bin to json");
657         return OC_STACK_ERROR;
658     }
659     OC_LOG_V(DEBUG, TAG, "Payload : %s", secPayload->securityData);
660
661     OCCallbackData cbData;
662     cbData.cb = &OwnerTransferModeHandler;
663     cbData.context = (void *)otmCtx;
664     cbData.cd = NULL;
665     OCStackResult res = OCDoResource(NULL, OC_REST_PUT, query,
666                                      &deviceInfo->endpoint, (OCPayload*)secPayload,
667                                      deviceInfo->connType, OC_LOW_QOS, &cbData, NULL, 0);
668     if (res != OC_STACK_OK)
669     {
670         OC_LOG(ERROR, TAG, "OCStack resource error");
671     }
672
673     OC_LOG(DEBUG, TAG, "OUT PutOwnerTransferModeToResource");
674
675     return res;
676 }
677
678 static OCStackResult GetProvisioningStatusResource(OTMContext_t* otmCtx)
679 {
680     OC_LOG(DEBUG, TAG, "IN GetProvisioningStatusResource");
681
682     if(!otmCtx || !otmCtx->selectedDeviceInfo)
683     {
684         OC_LOG(ERROR, TAG, "Invailed parameters");
685         return OC_STACK_INVALID_PARAM;
686     }
687
688     OCProvisionDev_t* deviceInfo = otmCtx->selectedDeviceInfo;
689     char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
690     if(!PMGenerateQuery(false,
691                         deviceInfo->endpoint.addr, deviceInfo->endpoint.port,
692                         deviceInfo->connType,
693                         query, sizeof(query), OIC_RSRC_PSTAT_URI))
694     {
695         OC_LOG(ERROR, TAG, "GetProvisioningStatusResource : Failed to generate query");
696         return OC_STACK_ERROR;
697     }
698     OC_LOG_V(DEBUG, TAG, "Query=%s", query);
699
700     OCCallbackData cbData;
701     cbData.cb = &ListMethodsHandler;
702     cbData.context = (void *)otmCtx;
703     cbData.cd = NULL;
704     OCStackResult res = OCDoResource(NULL, OC_REST_GET, query, NULL, NULL,
705                                      deviceInfo->connType, OC_LOW_QOS, &cbData, NULL, 0);
706     if (res != OC_STACK_OK)
707     {
708         OC_LOG(ERROR, TAG, "OCStack resource error");
709     }
710
711     OC_LOG(DEBUG, TAG, "OUT GetProvisioningStatusResource");
712
713     return res;
714 }
715
716
717 static OCStackResult PutOwnershipInformation(OTMContext_t* otmCtx)
718 {
719     OC_LOG(DEBUG, TAG, "IN PutOwnershipInformation");
720
721     if(!otmCtx || !otmCtx->selectedDeviceInfo)
722     {
723         OC_LOG(ERROR, TAG, "Invailed parameters");
724         return OC_STACK_INVALID_PARAM;
725     }
726
727     OCProvisionDev_t* deviceInfo = otmCtx->selectedDeviceInfo;
728     char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
729     if(!PMGenerateQuery(true,
730                         deviceInfo->endpoint.addr, deviceInfo->securePort,
731                         deviceInfo->connType,
732                         query, sizeof(query), OIC_RSRC_DOXM_URI))
733     {
734         OC_LOG(ERROR, TAG, "PutOwnershipInformation : Failed to generate query");
735         return OC_STACK_ERROR;
736     }
737     OC_LOG_V(DEBUG, TAG, "Query=%s", query);
738
739     //OwnershipInformationHandler
740     OicSecOxm_t selOxm = deviceInfo->doxm->oxmSel;
741     OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
742     if(!secPayload)
743     {
744         OC_LOG(ERROR, TAG, "Failed to memory allocation");
745         return OC_STACK_NO_MEMORY;
746     }
747     secPayload->base.type = PAYLOAD_TYPE_SECURITY;
748     secPayload->securityData = g_OTMDatas[selOxm].createOwnerTransferPayloadCB(otmCtx);
749     if (NULL == secPayload->securityData)
750     {
751         OICFree(secPayload);
752         OC_LOG(ERROR, TAG, "Error while converting doxm bin to json");
753         return OC_STACK_INVALID_PARAM;
754     }
755
756     OCCallbackData cbData;
757     cbData.cb = &OwnershipInformationHandler;
758     cbData.context = (void *)otmCtx;
759     cbData.cd = NULL;
760     OCStackResult res = OCDoResource(NULL, OC_REST_PUT, query, 0, (OCPayload*)secPayload,
761                                      deviceInfo->connType, OC_LOW_QOS, &cbData, NULL, 0);
762     if (res != OC_STACK_OK)
763     {
764         OC_LOG(ERROR, TAG, "OCStack resource error");
765     }
766
767     OC_LOG(DEBUG, TAG, "OUT PutOwnershipInformation");
768
769     return res;
770 }
771
772 static OCStackResult PutUpdateOperationMode(OTMContext_t* otmCtx,
773                                     OicSecDpom_t selectedOperationMode)
774 {
775     OC_LOG(DEBUG, TAG, "IN PutUpdateOperationMode");
776
777     if(!otmCtx || !otmCtx->selectedDeviceInfo)
778     {
779         return OC_STACK_INVALID_PARAM;
780     }
781
782     OCProvisionDev_t* deviceInfo = otmCtx->selectedDeviceInfo;
783     char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
784     if(!PMGenerateQuery(false,
785                         deviceInfo->endpoint.addr, deviceInfo->endpoint.port,
786                         deviceInfo->connType,
787                         query, sizeof(query), OIC_RSRC_PSTAT_URI))
788     {
789         OC_LOG(ERROR, TAG, "PutUpdateOperationMode : Failed to generate query");
790         return OC_STACK_ERROR;
791     }
792     OC_LOG_V(DEBUG, TAG, "Query=%s", query);
793
794     deviceInfo->pstat->om = selectedOperationMode;
795
796     OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
797     if(!secPayload)
798     {
799         OC_LOG(ERROR, TAG, "Failed to memory allocation");
800         return OC_STACK_NO_MEMORY;
801     }
802     secPayload->base.type = PAYLOAD_TYPE_SECURITY;
803     secPayload->securityData = BinToPstatJSON(deviceInfo->pstat);
804     if (NULL == secPayload->securityData)
805     {
806         OICFree(secPayload);
807         OC_LOG(ERROR, TAG, "Error while converting pstat bin to json");
808         return OC_STACK_INVALID_PARAM;
809     }
810
811     OCCallbackData cbData;
812     cbData.cb = &OperationModeUpdateHandler;
813     cbData.context = (void *)otmCtx;
814     cbData.cd = NULL;
815     OCStackResult res = OCDoResource(NULL, OC_REST_PUT, query, 0, (OCPayload*)secPayload,
816                                      deviceInfo->connType, OC_LOW_QOS, &cbData, NULL, 0);
817     if (res != OC_STACK_OK)
818     {
819         OC_LOG(ERROR, TAG, "OCStack resource error");
820     }
821
822     OC_LOG(DEBUG, TAG, "OUT PutUpdateOperationMode");
823
824     return res;
825 }
826
827 static OCStackResult StartOwnershipTransfer(void* ctx, OCProvisionDev_t* selectedDevice)
828 {
829     OC_LOG(INFO, TAG, "IN StartOwnershipTransfer");
830     OTMContext_t* otmCtx = (OTMContext_t*)ctx;
831     otmCtx->selectedDeviceInfo = selectedDevice;
832
833     //Set to the lowest level OxM, and then find more higher level OxM.
834     OCStackResult res = SelectProvisioningMethod(selectedDevice->doxm->oxm,
835                                                  selectedDevice->doxm->oxmLen,
836                                                  &selectedDevice->doxm->oxmSel);
837     if(OC_STACK_OK != res)
838     {
839         OC_LOG(ERROR, TAG, "Failed to select the provisioning method");
840         SetResult(otmCtx, res);
841         return res;
842     }
843     OC_LOG_V(DEBUG, TAG, "Selected provisoning method = %d", selectedDevice->doxm->oxmSel);
844
845     //Send Req: PUT /oic/sec/doxm [{..."OxmSel" :g_OTMDatas[Index of Selected OxM].OXMString,...}]
846     res = PutOwnerTransferModeToResource(otmCtx);
847     if(OC_STACK_OK != res)
848     {
849         OC_LOG(WARNING, TAG, "Failed to select the provisioning method");
850         SetResult(otmCtx, res);
851         return res;
852     }
853
854     OC_LOG(INFO, TAG, "OUT StartOwnershipTransfer");
855
856     return res;
857
858 }
859
860 OCStackResult OTMSetOwnershipTransferCallbackData(OicSecOxm_t oxmType, OTMCallbackData_t* data)
861 {
862     OC_LOG(DEBUG, TAG, "IN OTMSetOwnerTransferCallbackData");
863
864     if(!data)
865     {
866         OC_LOG(ERROR, TAG, "OTMSetOwnershipTransferCallbackData : Invalid parameters");
867         return OC_STACK_INVALID_PARAM;
868     }
869     if(oxmType >= OIC_OXM_COUNT)
870     {
871         OC_LOG(INFO, TAG, "Unknow ownership transfer method");
872         return OC_STACK_INVALID_PARAM;
873     }
874
875     g_OTMDatas[oxmType].loadSecretCB= data->loadSecretCB;
876     g_OTMDatas[oxmType].createSecureSessionCB = data->createSecureSessionCB;
877     g_OTMDatas[oxmType].createSelectOxmPayloadCB = data->createSelectOxmPayloadCB;
878     g_OTMDatas[oxmType].createOwnerTransferPayloadCB = data->createOwnerTransferPayloadCB;
879
880     OC_LOG(DEBUG, TAG, "OUT OTMSetOwnerTransferCallbackData");
881
882     return OC_STACK_OK;
883 }
884
885 /**
886  * NOTE : Unowned discovery should be done before performing OTMDoOwnershipTransfer
887  */
888 OCStackResult OTMDoOwnershipTransfer(void* ctx,
889                                      OCProvisionDev_t *selectedDevicelist,
890                                      OCProvisionResultCB resultCallback)
891 {
892     OC_LOG(DEBUG, TAG, "IN OTMDoOwnershipTransfer");
893
894     if (NULL == selectedDevicelist || NULL == resultCallback )
895     {
896         return OC_STACK_INVALID_PARAM;
897     }
898
899     OTMContext_t* otmCtx = (OTMContext_t*)OICCalloc(1,sizeof(OTMContext_t));
900     if(!otmCtx)
901     {
902         OC_LOG(ERROR, TAG, "Failed to create OTM Context");
903         return OC_STACK_NO_MEMORY;
904     }
905     otmCtx->ctxResultCallback = resultCallback;
906     otmCtx->ctxHasError = false;
907     otmCtx->userCtx = ctx;
908     OCProvisionDev_t* pCurDev = selectedDevicelist;
909
910     //Counting number of selected devices.
911     otmCtx->ctxResultArraySize = 0;
912     while(NULL != pCurDev)
913     {
914         otmCtx->ctxResultArraySize++;
915         pCurDev = pCurDev->next;
916     }
917
918     otmCtx->ctxResultArray =
919         (OCProvisionResult_t*)OICCalloc(otmCtx->ctxResultArraySize, sizeof(OCProvisionResult_t));
920     if(NULL == otmCtx->ctxResultArray)
921     {
922         OC_LOG(ERROR, TAG, "OTMDoOwnershipTransfer : Failed to memory allocation");
923         OICFree(otmCtx);
924         return OC_STACK_NO_MEMORY;
925     }
926     pCurDev = selectedDevicelist;
927
928     //Fill the device UUID for result array.
929     for(size_t devIdx = 0; devIdx < otmCtx->ctxResultArraySize; devIdx++)
930     {
931         //Checking duplication of Device ID.
932         bool isDuplicate = true;
933         OCStackResult res = PDMIsDuplicateDevice(&pCurDev->doxm->deviceID, &isDuplicate);
934         if (OC_STACK_OK != res)
935         {
936             OICFree(otmCtx->ctxResultArray);
937             OICFree(otmCtx);
938             return res;
939         }
940         if (isDuplicate)
941         {
942             OC_LOG(ERROR, TAG, "OTMDoOwnershipTransfer : Device ID is duplicated");
943             OICFree(otmCtx->ctxResultArray);
944             OICFree(otmCtx);
945             return OC_STACK_INVALID_PARAM;
946         }
947         memcpy(otmCtx->ctxResultArray[devIdx].deviceId.id,
948                pCurDev->doxm->deviceID.id,
949                UUID_LENGTH);
950         otmCtx->ctxResultArray[devIdx].res = OC_STACK_CONTINUE;
951         pCurDev = pCurDev->next;
952     }
953     StartOwnershipTransfer(otmCtx, selectedDevicelist);
954
955     OC_LOG(DEBUG, TAG, "OUT OTMDoOwnershipTransfer");
956     return OC_STACK_OK;
957 }
958
959 /**
960  * Callback handler of SRPFinalizeProvisioning.
961  *
962  * @param[in] ctx             ctx value passed to callback from calling function.
963  * @param[in] UNUSED          handle to an invocation
964  * @param[in] clientResponse  Response from queries to remote servers.
965  * @return  OC_STACK_DELETE_TRANSACTION to delete the transaction
966  *          and OC_STACK_KEEP_TRANSACTION to keep it.
967  */
968 static OCStackApplicationResult FinalizeProvisioningCB(void *ctx, OCDoHandle UNUSED,
969                                                        OCClientResponse *clientResponse)
970 {
971     OC_LOG_V(INFO, TAG, "IN FinalizeProvisioningCB.");
972
973     VERIFY_NON_NULL(TAG, clientResponse, ERROR);
974     VERIFY_NON_NULL(TAG, ctx, ERROR);
975
976     OTMContext_t* otmCtx = (OTMContext_t*)ctx;
977     (void)UNUSED;
978     if(OC_STACK_OK == clientResponse->result)
979     {
980         OCStackResult res = PDMAddDevice(&otmCtx->selectedDeviceInfo->doxm->deviceID);
981
982          if (OC_STACK_OK == res)
983          {
984                 OC_LOG_V(INFO, TAG, "Add device's UUID in PDM_DB");
985                 SetResult(otmCtx, OC_STACK_OK);
986                 return OC_STACK_DELETE_TRANSACTION;
987          }
988          else
989          {
990               OC_LOG(ERROR, TAG, "Ownership transfer is complete but adding information to DB is failed.");
991          }
992     }
993 exit:
994     return OC_STACK_DELETE_TRANSACTION;
995 }
996
997 /**
998  * Callback handler of default ACL provisioning.
999  *
1000  * @param[in] ctx             ctx value passed to callback from calling function.
1001  * @param[in] UNUSED          handle to an invocation
1002  * @param[in] clientResponse  Response from queries to remote servers.
1003  * @return  OC_STACK_DELETE_TRANSACTION to delete the transaction
1004  *          and OC_STACK_KEEP_TRANSACTION to keep it.
1005  */
1006 static OCStackApplicationResult ProvisionDefaultACLCB(void *ctx, OCDoHandle UNUSED,
1007                                                        OCClientResponse *clientResponse)
1008 {
1009     OC_LOG_V(INFO, TAG, "IN ProvisionDefaultACLCB.");
1010
1011     VERIFY_NON_NULL(TAG, clientResponse, ERROR);
1012     VERIFY_NON_NULL(TAG, ctx, ERROR);
1013
1014     OTMContext_t* otmCtx = (OTMContext_t*) ctx;
1015     (void)UNUSED;
1016
1017     if (OC_STACK_RESOURCE_CREATED == clientResponse->result)
1018     {
1019         OC_LOG_V(INFO, TAG, "Staring commit hash task.");
1020         // TODO hash currently have fixed value 0.
1021         uint16_t aclHash = 0;
1022         otmCtx->selectedDeviceInfo->pstat->commitHash = aclHash;
1023         otmCtx->selectedDeviceInfo->pstat->tm = NORMAL;
1024         OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
1025         if(!secPayload)
1026         {
1027             OC_LOG(ERROR, TAG, "Failed to memory allocation");
1028             return OC_STACK_NO_MEMORY;
1029         }
1030         secPayload->base.type = PAYLOAD_TYPE_SECURITY;
1031         secPayload->securityData = BinToPstatJSON(otmCtx->selectedDeviceInfo->pstat);
1032         if (NULL == secPayload->securityData)
1033         {
1034             OICFree(secPayload);
1035             SetResult(otmCtx, OC_STACK_INVALID_JSON);
1036             return OC_STACK_DELETE_TRANSACTION;
1037         }
1038         OC_LOG_V(INFO, TAG, "Created payload for commit hash: %s",secPayload->securityData);
1039
1040         char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
1041         if(!PMGenerateQuery(true,
1042                             otmCtx->selectedDeviceInfo->endpoint.addr,
1043                             otmCtx->selectedDeviceInfo->securePort,
1044                             otmCtx->selectedDeviceInfo->connType,
1045                             query, sizeof(query), OIC_RSRC_PSTAT_URI))
1046         {
1047             OC_LOG(ERROR, TAG, "ProvisionDefaultACLCB : Failed to generate query");
1048             return OC_STACK_ERROR;
1049         }
1050         OC_LOG_V(DEBUG, TAG, "Query=%s", query);
1051
1052         OCCallbackData cbData = {.context=NULL, .cb=NULL, .cd=NULL};
1053         cbData.cb = &FinalizeProvisioningCB;
1054         cbData.context = (void*)otmCtx;
1055         cbData.cd = NULL;
1056         OCStackResult ret = OCDoResource(NULL, OC_REST_PUT, query, 0, (OCPayload*)secPayload,
1057                 otmCtx->selectedDeviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0);
1058         OC_LOG_V(INFO, TAG, "OCDoResource returned: %d",ret);
1059         if (ret != OC_STACK_OK)
1060         {
1061             OC_LOG(ERROR, TAG, "OCStack resource error");
1062             SetResult(otmCtx, ret);
1063         }
1064     }
1065     else
1066     {
1067         OC_LOG_V(INFO, TAG, "Error occured in provisionDefaultACLCB :: %d\n",
1068                             clientResponse->result);
1069         SetResult(otmCtx, clientResponse->result);
1070     }
1071 exit:
1072     return OC_STACK_DELETE_TRANSACTION;
1073 }
1074
1075
1076 OCStackResult FinalizeProvisioning(OTMContext_t* otmCtx)
1077 {
1078     OC_LOG(INFO, TAG, "IN FinalizeProvisioning");
1079
1080     if(!otmCtx)
1081     {
1082         OC_LOG(ERROR, TAG, "OTMContext is NULL");
1083         return OC_STACK_INVALID_PARAM;
1084     }
1085     if(!otmCtx->selectedDeviceInfo)
1086     {
1087         OC_LOG(ERROR, TAG, "Can't find device information in OTMContext");
1088         OICFree(otmCtx);
1089         return OC_STACK_INVALID_PARAM;
1090     }
1091     // Provision Default ACL to device
1092     OicSecAcl_t defaultAcl =
1093     { {.id={0}},
1094         1,
1095         NULL,
1096         0x001F,
1097         0,
1098         NULL,
1099         NULL,
1100         1,
1101         NULL,
1102         NULL,
1103     };
1104
1105     OicUuid_t provTooldeviceID = {.id={0}};
1106     if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID))
1107     {
1108         OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
1109         SetResult(otmCtx, OC_STACK_ERROR);
1110         return OC_STACK_ERROR;
1111     }
1112     OC_LOG(INFO, TAG, "Retieved deviceID");
1113     memcpy(defaultAcl.subject.id, provTooldeviceID.id, sizeof(defaultAcl.subject.id));
1114     char *wildCardResource = "*";
1115     defaultAcl.resources = &wildCardResource;
1116
1117     defaultAcl.owners = (OicUuid_t *) OICCalloc(1, UUID_LENGTH);
1118     if(!defaultAcl.owners)
1119     {
1120         OC_LOG(ERROR, TAG, "Failed to memory allocation for default ACL");
1121         SetResult(otmCtx, OC_STACK_NO_MEMORY);
1122         return OC_STACK_NO_MEMORY;
1123     }
1124     memcpy(defaultAcl.owners->id, provTooldeviceID.id, UUID_LENGTH);
1125     OC_LOG(INFO, TAG, "Provisioning default ACL");
1126
1127     OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
1128     if(!secPayload)
1129     {
1130         OC_LOG(ERROR, TAG, "Failed to memory allocation");
1131         return OC_STACK_NO_MEMORY;
1132     }
1133     secPayload->base.type = PAYLOAD_TYPE_SECURITY;
1134     secPayload->securityData = BinToAclJSON(&defaultAcl);
1135     OICFree(defaultAcl.owners);
1136     if(!secPayload->securityData)
1137     {
1138         OICFree(secPayload);
1139         OC_LOG(INFO, TAG, "FinalizeProvisioning : Failed to BinToAclJSON");
1140         SetResult(otmCtx, OC_STACK_ERROR);
1141         return OC_STACK_ERROR;
1142     }
1143     OC_LOG_V(INFO, TAG, "Provisioning default ACL : %s",secPayload->securityData);
1144
1145     char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
1146     if(!PMGenerateQuery(true,
1147                         otmCtx->selectedDeviceInfo->endpoint.addr,
1148                         otmCtx->selectedDeviceInfo->securePort,
1149                         otmCtx->selectedDeviceInfo->connType,
1150                         query, sizeof(query), OIC_RSRC_ACL_URI))
1151     {
1152         OC_LOG(ERROR, TAG, "FinalizeProvisioning : Failed to generate query");
1153         return OC_STACK_ERROR;
1154     }
1155     OC_LOG_V(DEBUG, TAG, "Query=%s", query);
1156
1157     OC_LOG_V(INFO, TAG, "Request URI for Provisioning default ACL : %s", query);
1158
1159     OCCallbackData cbData =  {.context=NULL, .cb=NULL, .cd=NULL};
1160     cbData.cb = &ProvisionDefaultACLCB;
1161     cbData.context = (void *)otmCtx;
1162     cbData.cd = NULL;
1163     OCStackResult ret = OCDoResource(NULL, OC_REST_POST, query,
1164             &otmCtx->selectedDeviceInfo->endpoint, (OCPayload*)secPayload,
1165             otmCtx->selectedDeviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0);
1166     if (OC_STACK_OK != ret)
1167     {
1168         SetResult(otmCtx, ret);
1169         return ret;
1170     }
1171
1172     OC_LOG(INFO, TAG, "OUT FinalizeProvisioning");
1173
1174     return ret;
1175
1176 }
1177