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