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