In case of Just works provisioning,
[platform/upstream/iotivity.git] / resource / csdk / security / provisioning / src / provisioningmanager.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
30 #ifndef _POSIX_C_SOURCE
31 #define _POSIX_C_SOURCE 200809L
32 #endif
33
34 #include <string.h>
35 #include <time.h>
36 #include <unistd.h>
37 #include <sys/time.h>
38 #include <stdbool.h>
39
40 #include "cJSON.h"
41 #include "oic_malloc.h"
42 #include "logger.h"
43 #include "cacommon.h"
44 #include "cainterface.h"
45 #include "provisioningmanager.h"
46 #include "credentialgenerator.h"
47 #include "global.h"
48 #include "base64.h"
49 #include "aclresource.h"
50 #include "doxmresource.h"
51 #include "pstatresource.h"
52 #include "srmresourcestrings.h"
53 #include "credresource.h"
54 #include "oic_string.h"
55
56 typedef enum
57 {
58     SP_NO_MASK                = (0       ),
59     SP_DISCOVERY_STARTED      = (0x1 << 1),
60     SP_DISCOVERY_ERROR        = (0x1 << 2),
61     SP_DISCOVERY_DONE         = (0x1 << 3),
62     SP_UP_OWN_TR_METH_STARTED = (0x1 << 4),
63     SP_UP_OWN_TR_METH_ERROR   = (0x1 << 5),
64     SP_UP_OWN_TR_METH_DONE    = (0x1 << 6),
65     SP_LIST_METHODS_STARTED   = (0x1 << 7),
66     SP_LIST_METHODS_ERROR     = (0x1 << 8),
67     SP_LIST_METHODS_DONE      = (0x1 << 9),
68     SP_UPDATE_OP_MODE_STARTED = (0x1 << 10),
69     SP_UPDATE_OP_MODE_ERROR   = (0x1 << 11),
70     SP_UPDATE_OP_MODE_DONE    = (0x1 << 12),
71     SP_UPDATE_OWNER_STARTED   = (0x1 << 13),
72     SP_UPDATE_OWNER_ERROR     = (0x1 << 14),
73     SP_UPDATE_OWNER_DONE      = (0x1 << 15),
74     SP_PROV_ACL_STARTED       = (0x1 << 16),
75     SP_PROV_ACL_ERROR         = (0x1 << 17),
76     SP_PROV_ACL_DONE          = (0x1 << 18),
77     SP_UP_HASH_STARTED        = (0x1 << 19),
78     SP_UP_HASH_ERROR          = (0x1 << 20),
79     SP_UP_HASH_DONE           = (0x1 << 21),
80     SP_PROV_CRED_STARTED      = (0x1 << 22),
81     SP_PROV_CRED_ERROR        = (0x1 << 23),
82     SP_PROV_CRED_DONE         = (0x1 << 24)
83
84 } SPProvisioningStates;
85
86 #define SP_MAX_BUF_LEN 1024
87 #define TAG "SPProvisionAPI"
88 #define COAP_QUERY "coap://%s:%d%s"
89 #define COAPS_QUERY "coaps://%s:%d%s"
90 #define CA_SECURE_PORT   5684
91
92 void (*handler)(const CAEndpoint_t *, const CAResponseInfo_t *);
93
94 /**
95  * CA token to keep track of response.
96  */
97 static CAToken_t gToken = NULL;
98
99 /**
100  * start pointer for discovered device linked list.
101  */
102 static SPTargetDeviceInfo_t *gStartOfDiscoveredDevices = NULL;
103
104 /**
105  * current pointer of device linked list.
106  */
107 static SPTargetDeviceInfo_t *gCurrent = NULL;
108
109 /**
110  * Variable to keep track of various request.
111  */
112 static uint32_t gStateManager = 0;
113
114 /**
115  * Variable for storing provisioning tool's provisioning capabilities
116  * Must be in decreasing order of preference. More prefered method should
117  * have lower array index.
118  */
119 static OicSecDpom_t gProvisioningToolCapability[] = { SINGLE_SERVICE_CLIENT_DRIVEN };
120
121 /**
122  * Number of supported provisioning methods
123  * current version supports only one.
124  */
125 static int gNumOfProvisioningMethodsPT = 1;
126
127 /**
128  * Global variable to save pstat.
129  */
130 static OicSecPstat_t *gPstat = NULL;
131
132 /**
133  * Secure String copy function
134  * @param[in] destination  Pointer to destination string.
135  * @param[in] source       Pointer to source string.
136  * @return pointer to destination string, NULL in case of error.
137  */
138 static inline char *SPStringCopy(char *destination, const char *source, size_t num)
139 {
140     if (strncpy(destination, source, num))
141     {
142         destination[num - 1] = '\0';
143         return destination;
144     }
145     return NULL;
146 }
147
148 /**
149  * Function to convert CA result code to SP result code.
150  *
151  * @return result code of SP corresponding to that of CA.
152  */
153 static SPResult convertCAResultToSPResult(CAResult_t caResult)
154 {
155     switch (caResult)
156     {
157         case CA_STATUS_OK:
158             {
159                 return SP_RESULT_SUCCESS;
160             }
161         case CA_STATUS_INVALID_PARAM:
162             {
163                 return SP_RESULT_CONN_INVALID_PARAM;
164             }
165         case CA_ADAPTER_NOT_ENABLED:
166             {
167                 return SP_RESULT_CONN_SERVER_STARTED_ALREADY;
168             }
169         case CA_SERVER_STARTED_ALREADY:
170             {
171                 return SP_RESULT_CONN_SERVER_STARTED_ALREADY;
172             }
173         case CA_SERVER_NOT_STARTED:
174             {
175                 return SP_RESULT_CONN_SERVER_NOT_STARTED;
176             }
177         case CA_DESTINATION_NOT_REACHABLE:
178             {
179                 return SP_RESULT_CONN_DESTINATION_NOT_REACHABLE;
180             }
181         case CA_SOCKET_OPERATION_FAILED:
182             {
183                 return SP_RESULT_CONN_SOCKET_OPERATION_FAILED;
184             }
185         case CA_SEND_FAILED:
186             {
187                 return SP_RESULT_CONN_SEND_FAILED;
188             }
189         case CA_RECEIVE_FAILED:
190             {
191                 return SP_RESULT_CONN_RECEIVE_FAILED;
192             }
193         case CA_MEMORY_ALLOC_FAILED:
194             {
195                 return SP_RESULT_CONN_MEMORY_ALLOC_FAILED;
196             }
197         case CA_REQUEST_TIMEOUT:
198             {
199                 return SP_RESULT_CONN_REQUEST_TIMEOUT;
200             }
201         case CA_DESTINATION_DISCONNECTED:
202             {
203                 return SP_RESULT_CONN_DESTINATION_DISCONNECTED;
204             }
205         case CA_STATUS_FAILED:
206             {
207                 return SP_RESULT_CONN_STATUS_FAILED;
208             }
209         case CA_NOT_SUPPORTED:
210             {
211                 return SP_RESULT_CONN_NOT_SUPPORTED;
212             }
213         default:
214             {
215                 return SP_RESULT_INTERNAL_ERROR;
216             }
217     }
218 }
219
220 /**
221  * Function to delete memory allocated to linked list.
222  *
223  */
224 static void deleteList()
225 {
226     SPTargetDeviceInfo_t *current = gStartOfDiscoveredDevices;
227
228     while (current)
229     {
230         SPTargetDeviceInfo_t *next = current->next;
231         DeleteDoxmBinData(current->doxm);
232         DeletePstatBinData(current->pstat);
233         OICFree(current);
234         current = next;
235     }
236     gStartOfDiscoveredDevices = NULL;
237 }
238
239 /**
240  * Timeout implementation.
241  * @param[in]  timeout  Timeout in seconds. with 0 it will wait forever for success.
242  * @param[in]  mask     Mask of operation and 0 for no mask.
243  * @return SP_RESULT_SUCCESS on success otherwise error.
244  */
245 static SPResult SPTimeout(unsigned short timeout, uint32_t mask)
246 {
247     struct timespec startTime = {};
248     struct timespec currTime  = {};
249
250     CAResult_t res = SP_RESULT_SUCCESS;
251 #ifdef _POSIX_MONOTONIC_CLOCK
252     int clock_res = clock_gettime(CLOCK_MONOTONIC, &startTime);
253 #else
254     int clock_res = clock_gettime(CLOCK_REALTIME, &startTime);
255 #endif
256     if (0 != clock_res)
257     {
258         return SP_RESULT_INTERNAL_ERROR;
259     }
260     while (CA_STATUS_OK == res)
261     {
262         res = CAHandleRequestResponse();
263 #ifdef _POSIX_MONOTONIC_CLOCK
264         clock_res = clock_gettime(CLOCK_MONOTONIC, &currTime);
265 #else
266         clock_res = clock_gettime(CLOCK_REALTIME, &currTime);
267 #endif
268         if (0 != clock_res)
269         {
270             return SP_RESULT_INTERNAL_ERROR;
271         }
272         long elapsed = (currTime.tv_sec - startTime.tv_sec);
273         if (SP_NO_MASK == mask)
274         {
275             if (elapsed > timeout)
276             {
277                 return SP_RESULT_SUCCESS;
278             }
279         }
280         else
281         {
282             if (gStateManager & mask)
283             {
284                 return SP_RESULT_SUCCESS;
285             }
286             if ((elapsed > timeout) && timeout)
287             {
288                 return SP_RESULT_INTERNAL_ERROR;
289             }
290         }
291     }
292     return convertCAResultToSPResult(res);
293 }
294
295 /**
296  * Function to send request to resource server.
297  * @param[in] method          method to be used for sending rquest.
298  * @param[in] endpoint        endpoint address
299  * @param[in] secure          use secure connection
300  * @param[in] resourceUri     resourceUri token.
301  * @param[in] payload         Payload to be sent with data. NULL is case message
302  *                            doesn't have payload.
303  * @param[in] payloadLen      Size of data to be sent.
304  * @return  CA_STATUS_OK on success, otherwise error code.
305  */
306 static CAResult_t sendCARequest(CAMethod_t method,
307                                 const OCDevAddr *devAddr,
308                                 OCTransportFlags secure,
309                                 const char *resourceUri,
310                                 char *payload, int payloadLen)
311 {
312     if (CA_STATUS_OK != CAGenerateToken(&gToken, CA_MAX_TOKEN_LEN))
313     {
314         OC_LOG(ERROR, TAG, "Error while generating token");
315         return CA_MEMORY_ALLOC_FAILED;
316     }
317
318     CAEndpoint_t *endpoint = NULL;
319     if (CA_STATUS_OK != CACreateEndpoint((CATransportFlags_t)secure,
320                                          devAddr->adapter, devAddr->addr,
321                                          devAddr->port, &endpoint))
322     {
323         OC_LOG(ERROR, TAG, "Failed to create remote endpoint");
324         CADestroyEndpoint(endpoint);
325         return CA_STATUS_FAILED;
326     }
327     CAMessageType_t msgType = CA_MSG_CONFIRM;
328     CAInfo_t requestData = { 0 };
329     requestData.token = gToken;
330     requestData.tokenLength  = CA_MAX_TOKEN_LEN;
331     if (payload && '\0' != (*(payload + payloadLen)))
332     {
333         OC_LOG(ERROR, TAG, "Payload not properly terminated.");
334         CADestroyEndpoint(endpoint);
335         return CA_STATUS_INVALID_PARAM;
336     }
337     requestData.payload = payload;
338     requestData.type = msgType;
339     requestData.resourceUri = (CAURI_t)resourceUri;
340
341     CARequestInfo_t requestInfo = { 0 };
342     requestInfo.method = method;
343     requestInfo.info = requestData;
344     requestInfo.isMulticast = false;
345     CAResult_t caResult = CA_STATUS_OK;
346     caResult = CASendRequest(endpoint, &requestInfo);
347     if (CA_STATUS_OK != caResult)
348     {
349         OC_LOG(ERROR, TAG, "Send Request Error !!");
350     }
351     CADestroyEndpoint(endpoint);
352     return caResult;
353 }
354
355 /**
356  * addDevice to list.
357  *
358  * @param[in] endpoint   Endpoint information
359  * @param[in] doxm   pointer to doxm instance.
360  * @return SP_RESULT_SUCCESS for success and errorcode otherwise.
361  */
362 static SPResult addDevice(const CAEndpoint_t *endpoint, OicSecDoxm_t* doxm)
363 {
364     if (NULL == endpoint)
365     {
366         return SP_RESULT_INVALID_PARAM;
367     }
368     SPTargetDeviceInfo_t *ptr = (SPTargetDeviceInfo_t *)OICCalloc(1, sizeof (SPTargetDeviceInfo_t));
369     if (NULL == ptr)
370     {
371         OC_LOG(ERROR, TAG, "Error while allocating memory for linkedlist node !!");
372         return SP_RESULT_MEM_ALLOCATION_FAIL;
373     }
374
375     memcpy(&(ptr->endpoint), endpoint, sizeof(CAEndpoint_t));
376     ptr->doxm = doxm;
377     ptr->next = NULL;
378
379     if (NULL == gStartOfDiscoveredDevices)
380     {
381         gStartOfDiscoveredDevices = ptr;
382         gCurrent = ptr;
383     }
384     else
385     {
386         gCurrent->next = ptr;
387         gCurrent = ptr;
388     }
389     return SP_RESULT_SUCCESS;
390 }
391
392 /**
393  * Function to provide timeframe in which response can be received.
394  *
395  * @param[in]  timeout   Timeout in seconds.
396  * @return  SP_RESULT_SUCCESS on success , otherwise error code.
397  */
398 static SPResult SPWaitForResponse(unsigned short timeout)
399 {
400     return SPTimeout(timeout, SP_NO_MASK);
401 }
402
403 /**
404  * Function to select appropriate  provisioning method.
405  *
406  * @param[in]   supportedMethodsList   List of supported methods
407  * @param[out]  selectedMethod         Selected methods
408  * @return  SP_SUCCESS on success
409  */
410 static SPResult selectProvisioningMethod(OicSecOxm_t *supportedMethods, size_t numberOfMethods,
411         OicSecOxm_t *selectedMethod)
412 {
413     /*
414      TODO Logic to find appropiate method and assign it to out param
415      for beachhead release method at index 0 will be returned.
416      */
417     *selectedMethod = supportedMethods[0];
418     return SP_RESULT_SUCCESS;
419 }
420
421 /**
422  * Response handler for discovery.
423  *
424  * @param[in] object       Remote endpoint object
425  * @param[in] requestInfo  Datastructure containing request information.
426  */
427 static void ProvisionDiscoveryHandler(const CAEndpoint_t *object,
428                                       const CAResponseInfo_t *responseInfo)
429 {
430     if ((gStateManager & SP_DISCOVERY_STARTED) && gToken)
431     {
432         // Response handler for discovery.
433         if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
434         {
435             OC_LOG(INFO, TAG, "Inside ProvisionDiscoveryHandler.");
436             if (NULL == responseInfo->info.payload)
437             {
438                 OC_LOG(INFO, TAG, "Skiping Null payload");
439             }
440             else
441             {
442                 // temp logic for trimming oc attribute from the json.
443                 // JSONToBin should handle oc attribute.
444                 char *pTempPayload = (char *)OICMalloc(strlen(responseInfo->info.payload));
445                 if (NULL == pTempPayload)
446                 {
447                     OC_LOG(ERROR, TAG, "Error while Memory allocation.");
448                     gStateManager = gStateManager | SP_DISCOVERY_ERROR;
449                     return;
450                 }
451
452                 strcpy(pTempPayload, responseInfo->info.payload + 8);
453                 pTempPayload[strlen(pTempPayload) - 2] = '\0';
454                 OC_LOG_V(DEBUG, TAG, "Trimmed payload: %s", pTempPayload);
455                 OicSecDoxm_t *ptrDoxm = JSONToDoxmBin(pTempPayload);
456                 OICFree(pTempPayload);
457
458                 if (NULL == ptrDoxm)
459                 {
460                     OC_LOG(INFO, TAG, "Ignoring malformed JSON");
461                 }
462                 else
463                 {
464                     OC_LOG(DEBUG, TAG, "Successfully converted doxm json to bin.");
465
466                     SPResult res = addDevice(object, ptrDoxm);
467                     if (SP_RESULT_SUCCESS != res)
468                     {
469                         OC_LOG(ERROR, TAG, "Error while adding data to linkedlist.");
470                         gStateManager = gStateManager | SP_DISCOVERY_ERROR;
471                         DeleteDoxmBinData(ptrDoxm);
472                         return;
473                     }
474                     OC_LOG(INFO, TAG, "Exiting ProvisionDiscoveryHandler.");
475                     gStateManager |= SP_DISCOVERY_DONE;
476                 }
477             }
478         }
479     }
480 }
481
482 /**
483  * Response handler ownership transfer.
484  *
485  * @param[in] object       Remote endpoint object
486  * @param[in] requestInfo  Datastructure containing request information.
487  */
488 static void OwnerShipTransferModeHandler(const CAEndpoint_t *object,
489         const CAResponseInfo_t *responseInfo)
490 {
491     if ((gStateManager & SP_UP_OWN_TR_METH_STARTED) && gToken)
492     {
493         // response handler for ownership tranfer
494         OC_LOG(INFO, TAG, "Inside OwnerShipTransferModeHandler.");
495         if (memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength) == 0)
496         {
497             OC_LOG_V(DEBUG, TAG, "Response result for OwnerShipTransferMode: %d", responseInfo->result);
498             if (CA_SUCCESS == responseInfo->result)
499             {
500                 gStateManager |= SP_UP_OWN_TR_METH_DONE;
501                 OC_LOG(INFO, TAG, "Exiting OwnerShipTransferModeHandler.");
502             }
503             else
504             {
505                 gStateManager |= SP_UP_OWN_TR_METH_ERROR;
506                 OC_LOG(ERROR, TAG, "Error in OwnerShipTransferModeHandler.");
507             }
508         }
509     }
510 }
511
512 /**
513  * Response handler list methods.
514  *
515  * @param[in] object       Remote endpoint object
516  * @param[in] requestInfo  Datastructure containing request information.
517  */
518 static void ListMethodsHandler(const CAEndpoint_t *object,
519                                const CAResponseInfo_t *responseInfo)
520 {
521     if ((gStateManager & SP_LIST_METHODS_STARTED) && gToken)
522     {
523         OC_LOG(INFO, TAG, "Inside ListMethodsHandler.");
524         if (memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength) == 0)
525         {
526             OC_LOG_V(DEBUG, TAG, "Response result for ListMethodsHandler: %d", responseInfo->result);
527             if (CA_SUCCESS == responseInfo->result)
528             {
529                 OC_LOG_V (DEBUG, TAG, "Response Payload: %s", responseInfo->info.payload);
530                 // Temp logic to trim oc attribute from json
531                 // JSONToPstatBin should handle OC in JSON.
532                 if (NULL == responseInfo->info.payload)
533                 {
534                     OC_LOG(ERROR, TAG, "response payload is null.");
535                     gStateManager |= SP_LIST_METHODS_ERROR;
536                     return;
537                 }
538
539                 char *pTempPayload = (char *)OICMalloc(strlen(responseInfo->info.payload));
540                 if (NULL == pTempPayload)
541                 {
542                     OC_LOG(ERROR, TAG, "Error in memory allocation.");
543                     gStateManager |= SP_LIST_METHODS_ERROR;
544                     return;
545                 }
546
547                 strcpy(pTempPayload, responseInfo->info.payload + 8);
548                 pTempPayload[strlen(pTempPayload) - 2] = '\0';
549
550                 OicSecPstat_t *pstat =  JSONToPstatBin(pTempPayload);
551                 if (NULL == pstat)
552                 {
553                     OC_LOG(ERROR, TAG, "Error while converting json to pstat bin");
554                     OICFree(pTempPayload);
555                     gStateManager |= SP_LIST_METHODS_ERROR;
556                     return;
557                 }
558                 OICFree(pTempPayload);
559                 DeletePstatBinData(gPstat);
560
561                 gPstat = pstat;
562                 gStateManager |= SP_LIST_METHODS_DONE;
563
564                 OC_LOG(INFO, TAG, "Exiting ListMethodsHandler.");
565             }
566         }
567     }
568 }
569
570 /**
571  * Response handler for update operation mode.
572  *
573  * @param[in] object       Remote endpoint object
574  * @param[in] requestInfo  Datastructure containing request information.
575  */
576 static void OperationModeUpdateHandler(const CAEndpoint_t *object,
577                                        const CAResponseInfo_t *responseInfo)
578 {
579     if ((gStateManager & SP_UPDATE_OP_MODE_STARTED) && gToken)
580     {
581         if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
582         {
583             OC_LOG(INFO, TAG, "Inside OperationModeUpdateHandler.");
584             OC_LOG_V(DEBUG, TAG, "Response result for OperationModeUpdateHandler: %d", responseInfo->result);
585             if (CA_SUCCESS == responseInfo->result)
586             {
587                 gStateManager |= SP_UPDATE_OP_MODE_DONE;
588                 OC_LOG(INFO, TAG, "Exiting OperationModeUpdateHandler.");
589             }
590             else
591             {
592                 gStateManager |= SP_UPDATE_OP_MODE_ERROR;
593                 OC_LOG(ERROR, TAG, "Error in OperationModeUpdateHandler.");
594             }
595         }
596     }
597 }
598
599 /**
600  * Response handler for ownership transfer.
601  *
602  * @param[in] object       Remote endpoint object
603  * @param[in] requestInfo  Datastructure containing request information.
604  */
605 static void OwnerShipUpdateHandler(const CAEndpoint_t *object,
606                                    const CAResponseInfo_t *responseInfo)
607 {
608     if ((gStateManager & SP_UPDATE_OWNER_STARTED) && gToken)
609     {
610         // response handler for ownership tranfer
611         if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
612         {
613             OC_LOG(INFO, TAG, "Inside OwnerShipUpdateHandler.");
614             OC_LOG_V(DEBUG, TAG, "Response result for OwnerShipUpdateHandler: %d", responseInfo->result);
615             if (CA_SUCCESS == responseInfo->result)
616             {
617                 gStateManager |= SP_UPDATE_OWNER_DONE;
618                 OC_LOG(INFO, TAG, "Exiting OwnerShipUpdateHandler.");
619             }
620             else
621             {
622                 gStateManager |= SP_UPDATE_OWNER_ERROR;
623                 OC_LOG(ERROR, TAG, "Error in OwnerShipUpdateHandler.");
624             }
625         }
626     }
627 }
628
629 /**
630  * Response handler for ACL provisioning.
631  *
632  * @param[in] object       Remote endpoint object
633  * @param[in] requestInfo  Datastructure containing request information.
634  */
635 static void ACLProvisioningHandler(const CAEndpoint_t *object,
636                                    const CAResponseInfo_t *responseInfo)
637 {
638     if ((gStateManager & SP_PROV_ACL_STARTED) && gToken)
639     {
640
641         // response handler for ACL provisioning.
642         if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
643         {
644             OC_LOG(INFO, TAG, "Inside ACLProvisioningHandler.");
645             OC_LOG_V(DEBUG, TAG, "Response result for ACLProvisioningHandler: %d", responseInfo->result);
646             if (CA_CREATED == responseInfo->result)
647             {
648                 OC_LOG(INFO, TAG, "Exiting ACLProvisioningHandler.");
649                 gStateManager |= SP_PROV_ACL_DONE;
650             }
651             else
652             {
653                 OC_LOG(ERROR, TAG, "Error in ACLProvisioningHandler.");
654                 gStateManager |= SP_PROV_ACL_ERROR;
655             }
656         }
657     }
658 }
659
660 /**
661  * Response handler for provisioning finalization.
662  *
663  * @param[in] object       Remote endpoint object
664  * @param[in] requestInfo  Datastructure containing request information.
665  */
666 static void FinalizeProvisioningHandler(const CAEndpoint_t *object,
667                                         const CAResponseInfo_t *responseInfo)
668 {
669     if ((gStateManager & SP_UP_HASH_STARTED) && gToken)
670     {
671         // response handler for finalize provisioning.
672         if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
673         {
674             OC_LOG(INFO, TAG, "Inside FinalizeProvisioningHandler.");
675             OC_LOG_V(DEBUG, TAG, "Response result for FinalizeProvisioningHandler: %d", responseInfo->result);
676             if (CA_SUCCESS == responseInfo->result)
677             {
678                 gStateManager |= SP_UP_HASH_DONE;
679                 OC_LOG(INFO, TAG, "Exiting FinalizeProvisioningHandler.");
680             }
681             else
682             {
683                 gStateManager |= SP_UP_HASH_ERROR;
684                 OC_LOG(ERROR, TAG, "Error in FinalizeProvisioningHandler.");
685             }
686         }
687     }
688 }
689
690 /**
691  * Response handler for Credential provisioning.
692  *
693  * @param[in] object        Remote endpoint object
694  * @param[in] requestInfo   Datastructure containing request information.
695  */
696 static void CredProvisioningHandler(const CAEndpoint_t *object,
697                                     const CAResponseInfo_t *responseInfo)
698 {
699     if ((gStateManager & SP_PROV_CRED_STARTED) && gToken)
700     {
701         // response handler for CRED provisioning.
702         OC_LOG(INFO, TAG, "Inside CredProvisioningHandler.");
703         OC_LOG_V(DEBUG, TAG, "Response result for CredProvisioningHandler: %d", responseInfo->result);
704         if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
705         {
706             if (CA_CREATED == responseInfo->result)
707             {
708                 gStateManager |= SP_PROV_CRED_DONE;
709                 OC_LOG(INFO, TAG, "Exiting CredProvisioningHandler.");
710             }
711             else
712             {
713                 gStateManager |= SP_PROV_CRED_ERROR;
714                 OC_LOG(ERROR, TAG, "Error in CredProvisioningHandler.");
715             }
716         }
717     }
718 }
719
720 /**
721  * Response Handler
722  *
723  * @param[in] object        Remote endpoint object
724  * @param[in] responseInfo  Datastructure containing response information.
725  */
726 static void SPResponseHandler(const CAEndpoint_t *object,
727                               const CAResponseInfo_t *responseInfo)
728 {
729     if ((NULL != responseInfo) && (NULL != responseInfo->info.token))
730     {
731         handler(object, responseInfo);
732     }
733 }
734
735 /**
736  * Error Handler
737  *
738  * @param[in] object     Remote endpoint object
739  * @param[in] errorInfo  Datastructure containing error information.
740  */
741 static void SPErrorHandler(const CAEndpoint_t *object,
742                            const CAErrorInfo_t *errorInfo)
743 {
744     OC_LOG(INFO, TAG, "Error Handler.");
745 }
746
747 /**
748  * Request Handler
749  *
750  * @param[in] object       Remote endpoint object
751  * @param[in] requestInfo  Datastructure containing request information.
752  */
753 static void SPRequestHandler(const CAEndpoint_t *object, const CARequestInfo_t *requestInfo)
754 {
755     OC_LOG(INFO, TAG, "Request Handler.");
756 }
757
758 /**
759  * Function to find the resources using multicast discovery.
760  *
761  * @param[in]   timeout     timeout in secs
762  * @return  SP_RESULT_SUCCESS normally otherwise error code.
763  */
764 static SPResult findResource(unsigned short timeout)
765 {
766     static char DOXM_OWNED_FALSE_MULTICAST_QUERY[] = "/oic/sec/doxm?Owned=FALSE";
767     CAResult_t res = CAGenerateToken(&gToken, CA_MAX_TOKEN_LEN);
768     if (CA_STATUS_OK != res)
769     {
770         OC_LOG(ERROR, TAG, "Error while generating token.");
771         return SP_RESULT_INTERNAL_ERROR;
772     }
773
774     CAEndpoint_t endpoint = { CA_DEFAULT_FLAGS };
775
776     CAMessageType_t msgType = CA_MSG_NONCONFIRM;
777     CAInfo_t requestData = { 0 };
778     requestData.token = gToken;
779     requestData.tokenLength  = CA_MAX_TOKEN_LEN;
780     requestData.payload = NULL;
781     requestData.type = msgType;
782     requestData.resourceUri = DOXM_OWNED_FALSE_MULTICAST_QUERY;
783     CARequestInfo_t requestInfo = { 0 };
784     requestInfo.method = CA_GET;
785     requestInfo.info = requestData;
786     requestInfo.isMulticast = true;
787     res = CASendRequest(&endpoint, &requestInfo);
788
789     handler = &ProvisionDiscoveryHandler;
790     gStateManager |= SP_DISCOVERY_STARTED;
791     if (CA_STATUS_OK != res)
792     {
793         OC_LOG(ERROR, TAG, "Error while finding resource.");
794         return convertCAResultToSPResult(res);
795     }
796     else
797     {
798         OC_LOG(INFO, TAG, "Discovery Request sent successfully");
799     }
800     return SPWaitForResponse(timeout);
801 }
802
803 /**
804  * Function to update the operation mode. As per the spec. Operation mode in client driven
805  * single service provisioning it will be updated to 0x3
806  *
807  * @param[in]  timeout     timeout for operation.
808  * @param[in]  deviceInfo  Device Info.
809  * @return  SP_SUCCESS on success
810  */
811 static SPResult updateOwnerTransferModeToResource(unsigned short timeout,
812         SPTargetDeviceInfo_t *deviceInfo, OicSecOxm_t selectedMethod)
813 {
814     SPResult res = SP_RESULT_INTERNAL_ERROR;
815
816     deviceInfo->doxm->oxmSel = selectedMethod;
817     char *payload = BinToDoxmJSON(deviceInfo->doxm);
818     if (NULL == payload)
819     {
820         OC_LOG(ERROR, TAG, "Error while converting bin to json");
821         return SP_RESULT_INTERNAL_ERROR;
822     }
823     OC_LOG_V(DEBUG, TAG, "Payload: %s", payload);
824     int payloadLen = strlen(payload);
825
826     handler = &OwnerShipTransferModeHandler;
827     gStateManager |= SP_UP_OWN_TR_METH_STARTED;
828
829     CAResult_t result = sendCARequest(CA_PUT,
830                                       &deviceInfo->endpoint,
831                                       OC_DEFAULT_FLAGS,
832                                       OIC_RSRC_DOXM_URI,
833                                       payload, payloadLen);
834     OICFree(payload);
835     if (CA_STATUS_OK != result)
836     {
837         OC_LOG(ERROR, TAG, "Error while sending request.");
838         CADestroyToken(gToken);
839         return convertCAResultToSPResult(result);
840     }
841     res = SPTimeout(timeout, SP_UP_OWN_TR_METH_DONE);
842     if (SP_RESULT_SUCCESS != res)
843     {
844         OC_LOG(ERROR, TAG, "Internal Error occured");
845         CADestroyToken(gToken);
846         return SP_RESULT_TIMEOUT;
847     }
848     CADestroyToken(gToken);
849     return SP_RESULT_SUCCESS;
850 }
851
852 /**
853  * Function to send request to resource to get its pstat resource information.
854  *
855  * @param[in]  timeout     timeout for operation.
856  * @param[in]  deviceInfo  Device Info.
857  * @return  SP_SUCCESS on success
858  */
859 static SPResult getProvisioningStatusResource(unsigned short timeout,
860                                               SPTargetDeviceInfo_t *deviceInfo)
861 {
862     handler = &ListMethodsHandler;
863     gStateManager |= SP_LIST_METHODS_STARTED;
864
865     CAResult_t result = sendCARequest(CA_GET,
866                                       &deviceInfo->endpoint,
867                                       OC_DEFAULT_FLAGS,
868                                       OIC_RSRC_PSTAT_URI,
869                                       NULL, 0);
870     if (CA_STATUS_OK != result)
871     {
872         OC_LOG(ERROR, TAG, "Failure while sending request.");
873         CADestroyToken(gToken);
874         return convertCAResultToSPResult(result);
875     }
876     SPResult res = SPTimeout(timeout, SP_LIST_METHODS_DONE);
877     if (SP_RESULT_SUCCESS != res)
878     {
879         OC_LOG(ERROR, TAG, "Timeout while getting method list.");
880         CADestroyToken(gToken);
881         return SP_RESULT_TIMEOUT;
882     }
883     if (gStateManager && SP_LIST_METHODS_DONE)
884     {
885         deviceInfo->pstat = gPstat;
886         CADestroyToken(gToken);
887         OC_LOG(DEBUG, TAG, "getProvisioningStatusResource completed.");
888         return SP_RESULT_SUCCESS;
889     }
890     CADestroyToken(gToken);
891     return SP_RESULT_INTERNAL_ERROR;
892 }
893
894 /**
895  * Function to update the operation mode. As per the spec. Operation mode in client driven
896  * single service provisioning it will be updated to 0x3
897  *
898  * @param[in]  timeout     timeout for operation.
899  * @param[in]  deviceInfo  Device Info.
900  * @return  SP_SUCCESS on success
901  */
902 static SPResult updateOperationMode(unsigned short timeout,
903                                     SPTargetDeviceInfo_t *deviceInfo,
904                                     OicSecDpom_t selectedOperationMode)
905 {
906
907     SPResult res = SP_RESULT_INTERNAL_ERROR;
908
909     deviceInfo->pstat->om = selectedOperationMode;
910
911     char *payloadBuffer = BinToPstatJSON(deviceInfo->pstat);
912     if (NULL == payloadBuffer)
913     {
914         OC_LOG(ERROR, TAG, "Error while converting pstat bin to json");
915         return SP_RESULT_INTERNAL_ERROR;
916     }
917
918     size_t payloadLen = strlen(payloadBuffer);
919     handler = &OperationModeUpdateHandler;
920     gStateManager |= SP_UPDATE_OP_MODE_STARTED;
921
922     CAResult_t result = sendCARequest(CA_PUT,
923                                       &deviceInfo->endpoint,
924                                       OC_DEFAULT_FLAGS,
925                                       OIC_RSRC_PSTAT_URI,
926                                       payloadBuffer, payloadLen);
927     if (CA_STATUS_OK != result)
928     {
929         OC_LOG(ERROR, TAG, "Error while sending request.");
930         CADestroyToken(gToken);
931         OICFree(payloadBuffer);
932         return convertCAResultToSPResult(result);
933     }
934     res = SPTimeout(timeout, SP_UPDATE_OP_MODE_DONE);
935     if (SP_RESULT_SUCCESS != res)
936     {
937         OC_LOG(ERROR, TAG, "Internal Error occured");
938         CADestroyToken(gToken);
939         OICFree(payloadBuffer);
940         return SP_RESULT_TIMEOUT;
941     }
942     CADestroyToken(gToken);
943     OICFree(payloadBuffer);
944
945     if (gStateManager & SP_UPDATE_OP_MODE_DONE)
946     {
947         return SP_RESULT_SUCCESS;
948     }
949     return SP_RESULT_INTERNAL_ERROR;
950 }
951
952 /**
953  * Function to initiate DTLS handshake.
954  *
955  * @param[in]  deviceInfo  Provisioning context
956  * @return SP_SUCCESS on success
957  */
958 static SPResult initiateDtlsHandshake(const CAEndpoint_t *endpoint)
959 {
960     CAResult_t caresult = CAEnableAnonECDHCipherSuite(true);
961     if (CA_STATUS_OK != caresult)
962     {
963         OC_LOG_V(ERROR, TAG, "Unable to enable anon cipher suite");
964         return SP_RESULT_INTERNAL_ERROR;
965     }
966     OC_LOG(INFO, TAG, "Anonymous cipher suite Enabled.");
967
968     caresult = CAInitiateHandshake(endpoint);
969     if (CA_STATUS_OK != caresult)
970     {
971         OC_LOG_V(ERROR, TAG, "DTLS handshake failure.");
972     }
973
974     return SP_RESULT_SUCCESS;
975 }
976
977 /**
978  * Function to send ownerShip info. This function would update Owned as true and
979  * owner as UUID for provisioning tool
980  *
981  * @param[in]  timeout     timeout value for the operation.
982  * @param[in]  deviceInfo  provisioning context.
983  * @return  SP_SUCCESS on success
984  */
985 static SPResult sendOwnershipInfo(unsigned short timeout,
986                                   SPTargetDeviceInfo_t *selectedDeviceInfo)
987 {
988     OicUuid_t provTooldeviceID = {};
989
990     if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID))
991     {
992         OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
993         return SP_RESULT_INTERNAL_ERROR;
994     }
995     memcpy(selectedDeviceInfo->doxm->owner.id, provTooldeviceID.id , UUID_LENGTH);
996
997     selectedDeviceInfo->doxm->owned = true;
998
999     char *payloadBuffer =  BinToDoxmJSON(selectedDeviceInfo->doxm);
1000     if (NULL == payloadBuffer)
1001     {
1002         OC_LOG(ERROR, TAG, "Error while converting doxm bin to json");
1003         return SP_RESULT_INTERNAL_ERROR;
1004     }
1005     int payloadLen = strlen(payloadBuffer);
1006
1007     handler = &OwnerShipUpdateHandler;
1008     gStateManager |= SP_UPDATE_OWNER_STARTED;
1009
1010     CAResult_t result = sendCARequest(CA_PUT,
1011                                       &selectedDeviceInfo->endpoint,
1012                                       OC_FLAG_SECURE,
1013                                       OIC_RSRC_DOXM_URI,
1014                                       payloadBuffer, payloadLen);
1015     if (CA_STATUS_OK != result)
1016     {
1017         OC_LOG(ERROR, TAG, "Error while sending request.");
1018         CADestroyToken(gToken);
1019         OICFree(payloadBuffer);
1020         return convertCAResultToSPResult(result);
1021     }
1022     SPResult res = SPTimeout(timeout, SP_UPDATE_OWNER_DONE);
1023     if (SP_RESULT_SUCCESS != res)
1024     {
1025         OC_LOG(ERROR, TAG, "Internal Error occured");
1026         CADestroyToken(gToken);
1027         OICFree(payloadBuffer);
1028         return SP_RESULT_TIMEOUT;
1029     }
1030     CADestroyToken(gToken);
1031     OICFree(payloadBuffer);
1032     return SP_RESULT_SUCCESS;
1033 }
1034
1035 /**
1036  * Function to save ownerPSK at provisioning tool end.
1037  *
1038  * @return  SP_SUCCESS on success
1039  */
1040 static SPResult saveOwnerPSK(SPTargetDeviceInfo_t *selectedDeviceInfo)
1041 {
1042     SPResult result = SP_RESULT_INTERNAL_ERROR;
1043
1044     CAEndpoint_t endpoint = {};
1045     OICStrcpy(endpoint.addr, MAX_ADDR_STR_SIZE_CA, selectedDeviceInfo->endpoint.addr);
1046     endpoint.port = CA_SECURE_PORT;
1047
1048     OicUuid_t provTooldeviceID = {};
1049     if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID))
1050     {
1051         OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
1052         return result;
1053     }
1054
1055     uint8_t ownerPSK[OWNER_PSK_LENGTH_128] = {};
1056
1057     //Generating OwnerPSK
1058     CAResult_t pskRet = CAGenerateOwnerPSK(&endpoint,
1059             (uint8_t *)OXM_JUST_WORKS, strlen(OXM_JUST_WORKS), provTooldeviceID.id,
1060             sizeof(provTooldeviceID.id), selectedDeviceInfo->doxm->deviceID.id,
1061             sizeof(selectedDeviceInfo->doxm->deviceID.id), ownerPSK,
1062             OWNER_PSK_LENGTH_128);
1063
1064     if (CA_STATUS_OK == pskRet)
1065     {
1066         OC_LOG(INFO, TAG,"ownerPSK dump:\n");
1067         OC_LOG_BUFFER(INFO, TAG,ownerPSK, OWNER_PSK_LENGTH_128);
1068         //Generating new credential for provisioning tool
1069         size_t ownLen = 1;
1070         uint32_t outLen = 0;
1071
1072         char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(ownerPSK)) + 1] = {};
1073         B64Result b64Ret = b64Encode(ownerPSK, sizeof(ownerPSK), base64Buff, sizeof(base64Buff),
1074                 &outLen);
1075         if (B64_OK == b64Ret)
1076         {
1077             OicSecCred_t *cred = GenerateCredential(&selectedDeviceInfo->doxm->deviceID,
1078                     SYMMETRIC_PAIR_WISE_KEY, NULL,
1079                     base64Buff, ownLen, &provTooldeviceID);
1080             if (cred)
1081             {
1082                 //Update the SVR database.
1083                 if (OC_STACK_OK == AddCredential(cred))
1084                 {
1085                     result = SP_RESULT_SUCCESS;
1086                 }
1087                 else
1088                 {
1089                     OC_LOG(ERROR, TAG, "AddCredential failed");
1090                 }
1091             }
1092             else
1093             {
1094                 OC_LOG(ERROR, TAG, "GenerateCredential failed");
1095             }
1096         }
1097         else
1098         {
1099             OC_LOG(ERROR, TAG, "b64Encode failed");
1100         }
1101     }
1102     else
1103     {
1104         OC_LOG(ERROR, TAG, "CAGenerateOwnerPSK failed");
1105     }
1106     return result;
1107 }
1108
1109 /**
1110  * Function to select operation mode.This function will return most secure common operation mode.
1111  *
1112  * @param[out]   selectedMode   selected operation mode
1113  * @return  SP_SUCCESS on success
1114  */
1115 static void selectOperationMode(const SPTargetDeviceInfo_t *selectedDeviceInfo,
1116                                 OicSecDpom_t **selectedMode)
1117 {
1118     int i = 0;
1119     int j = 0;
1120     while (i < gNumOfProvisioningMethodsPT && j < selectedDeviceInfo->pstat->smLen)
1121     {
1122         if (gProvisioningToolCapability[i] < selectedDeviceInfo->pstat->sm[j])
1123         {
1124             i++;
1125         }
1126         else if (selectedDeviceInfo->pstat->sm[j] < gProvisioningToolCapability[i])
1127         {
1128             j++;
1129         }
1130         else /* if gProvisioningToolCapability[i] == deviceSupportedMethods[j] */
1131         {
1132             *selectedMode = &(gProvisioningToolCapability[j]);
1133             break;
1134         }
1135     }
1136 }
1137
1138 /**
1139  * Function to perform onwership tranfer based to ownership transfer mode.
1140  *
1141  * @param[in]  timeout            timeout in secs to perform operation. 0 timeout means
1142                                   function will wait forever.
1143  * @param[in]  selectedDeviceInfo instance of SPTargetDeviceInfo_t structure.
1144  * @return  SP_SUCCESS on success
1145  */
1146 static SPResult doOwnerShipTransfer(unsigned short timeout,
1147                                     SPTargetDeviceInfo_t *selectedDeviceInfo)
1148 {
1149     OicSecDpom_t *selectedOperationMode = NULL;
1150     selectOperationMode(selectedDeviceInfo, &selectedOperationMode);
1151
1152     SPResult res = updateOperationMode(timeout, selectedDeviceInfo, *selectedOperationMode);
1153     if (SP_RESULT_SUCCESS != res)
1154     {
1155         OC_LOG(ERROR, TAG, "Error while updating operation mode.");
1156         return SP_RESULT_INTERNAL_ERROR;
1157     }
1158     if (*selectedOperationMode == SINGLE_SERVICE_CLIENT_DRIVEN)
1159     {
1160         CAEndpoint_t endpoint = {0};
1161         OICStrcpy(endpoint.addr, MAX_ADDR_STR_SIZE_CA, selectedDeviceInfo->endpoint.addr);
1162         endpoint.port = CA_SECURE_PORT;
1163
1164         res = initiateDtlsHandshake(&endpoint);
1165         if (SP_RESULT_SUCCESS == res)
1166         {
1167             selectedDeviceInfo->endpoint.port = CA_SECURE_PORT;
1168             res = sendOwnershipInfo(timeout, selectedDeviceInfo);
1169             if (SP_RESULT_SUCCESS != res)
1170             {
1171                 OC_LOG(ERROR, TAG, "Error while updating ownership information.");
1172             }
1173             res = saveOwnerPSK(selectedDeviceInfo);
1174
1175             //Close temporal DTLS session
1176             if(CA_STATUS_OK != CACloseDtlsSession(&endpoint))
1177             {
1178                 OC_LOG(WARNING, TAG, "doOwnerShipTransfer() : failed to close the dtls session");
1179             }
1180         }
1181         else
1182         {
1183             OC_LOG(ERROR, TAG, "Error during initiating DTLS handshake.");
1184         }
1185
1186         //Disable Anonymous ECDH cipher suite before leaving this method
1187         if(CA_STATUS_OK != CAEnableAnonECDHCipherSuite(false))
1188         {
1189             OC_LOG(WARNING, TAG, "doOwnerShipTransfer() : failed to disable Anon ECDH cipher suite");
1190         }
1191     }
1192     return (res != SP_RESULT_SUCCESS) ? SP_RESULT_INTERNAL_ERROR : SP_RESULT_SUCCESS;
1193
1194 }
1195
1196 /**
1197  * Function to provision credentials to specific device.
1198  *
1199  * @param[in] timeout     timeout in secs to perform operation. 0 timeout means function will
1200                           wait till success.
1201  * @param[in] cred        credential to be provisioned.
1202  * @param[in] deviceInfo  Instance of SPDevInfo_t structure. Representing a selected device for
1203                           provisioning.
1204  * @return  SP_SUCCESS on success
1205  */
1206 SPResult provisionCredentials(unsigned short timeout, const OicSecCred_t *cred,
1207                               const SPDevInfo_t *deviceInfo)
1208 {
1209     char *credJson = NULL;
1210     credJson = BinToCredJSON(cred);
1211     if (NULL == credJson)
1212     {
1213         OC_LOG(ERROR, TAG, "Memory allocation problem");
1214         return SP_RESULT_MEM_ALLOCATION_FAIL;
1215     }
1216
1217     int payloadLen = strlen(credJson);
1218     handler = &CredProvisioningHandler;
1219     gStateManager |= SP_PROV_CRED_STARTED;
1220
1221     CAResult_t result = sendCARequest(CA_POST,
1222                                       &deviceInfo->endpoint,
1223                                       OC_FLAG_SECURE,
1224                                       OIC_RSRC_CRED_URI,
1225                                       credJson, payloadLen);
1226     OICFree(credJson);
1227     if (CA_STATUS_OK != result)
1228     {
1229         OC_LOG(ERROR, TAG, "Internal Error while sending Credentials.");
1230         CADestroyToken(gToken);
1231         return convertCAResultToSPResult(result);
1232     }
1233
1234     SPResult res = SPTimeout(timeout, SP_PROV_CRED_DONE);
1235     if (SP_RESULT_SUCCESS != res)
1236     {
1237         OC_LOG(ERROR, TAG, "Internal Error occured");
1238         CADestroyToken(gToken);
1239         return SP_RESULT_TIMEOUT;
1240     }
1241     CADestroyToken(gToken);
1242     gStateManager = 0;
1243     return res;
1244 }
1245
1246 SPResult SPProvisioningDiscovery(unsigned short timeout,
1247                                  SPTargetDeviceInfo_t **list)
1248 {
1249     if (NULL != *list)
1250     {
1251         OC_LOG(ERROR, TAG, "List is not null can cause memory leak");
1252         return SP_RESULT_INVALID_PARAM;
1253     }
1254
1255     CARegisterHandler(SPRequestHandler, SPResponseHandler, SPErrorHandler);
1256     SPResult smResponse = SP_RESULT_SUCCESS;
1257     smResponse = findResource(timeout);
1258     if (SP_RESULT_SUCCESS != smResponse)
1259     {
1260         return SP_RESULT_INTERNAL_ERROR;
1261     }
1262     if (gStateManager & SP_DISCOVERY_DONE)
1263     {
1264         if (gStateManager & SP_DISCOVERY_ERROR)
1265         {
1266             return SP_RESULT_INTERNAL_ERROR;
1267         }
1268         *list = gStartOfDiscoveredDevices;
1269         return SP_RESULT_SUCCESS;
1270     }
1271     return SP_RESULT_INTERNAL_ERROR;
1272 }
1273
1274 SPResult SPInitProvisionContext(unsigned short timeout,
1275                                 SPTargetDeviceInfo_t *selectedDeviceInfo)
1276 {
1277     if (NULL == selectedDeviceInfo )
1278     {
1279         return SP_RESULT_INVALID_PARAM;
1280     }
1281
1282     SPResult res = SP_RESULT_SUCCESS;
1283     OicSecOxm_t selectedMethod = OIC_JUST_WORKS;
1284
1285     selectProvisioningMethod(selectedDeviceInfo->doxm->oxm, selectedDeviceInfo->doxm->oxmLen,
1286                              &selectedMethod);
1287     OC_LOG_V(DEBUG, TAG, "Selected method %d:", selectedMethod);
1288     res = updateOwnerTransferModeToResource(timeout, selectedDeviceInfo, selectedMethod);
1289
1290     if (SP_RESULT_SUCCESS != res)
1291     {
1292         OC_LOG(ERROR, TAG, "Error while updating owner transfer mode.");
1293         return SP_RESULT_INTERNAL_ERROR;
1294     }
1295
1296     res = getProvisioningStatusResource(timeout, selectedDeviceInfo);
1297     if (SP_RESULT_SUCCESS != res)
1298     {
1299         OC_LOG(ERROR, TAG, "Error while getting provisioning status.");
1300         return SP_RESULT_INTERNAL_ERROR;
1301     }
1302     OC_LOG(INFO, TAG, "Starting ownership transfer");
1303     return doOwnerShipTransfer(timeout, selectedDeviceInfo);
1304
1305 }
1306
1307 SPResult SPProvisionACL(unsigned short timeout, const SPTargetDeviceInfo_t *selectedDeviceInfo,
1308                         OicSecAcl_t *acl)
1309 {
1310     if (NULL == selectedDeviceInfo || NULL == acl)
1311     {
1312         return SP_RESULT_INVALID_PARAM;
1313     }
1314     char *aclString = NULL;
1315     aclString = BinToAclJSON(acl);
1316
1317     if (NULL == aclString)
1318     {
1319         OC_LOG(ERROR, TAG, "Memory allocation problem");
1320         return SP_RESULT_MEM_ALLOCATION_FAIL;
1321     }
1322
1323     int payloadLen = strlen(aclString);
1324     handler = &ACLProvisioningHandler;
1325     gStateManager |= SP_PROV_ACL_STARTED;
1326
1327     CAResult_t result = sendCARequest(CA_POST,
1328                                       &selectedDeviceInfo->endpoint,
1329                                       OC_FLAG_SECURE,
1330                                       OIC_RSRC_ACL_URI,
1331                                       aclString, payloadLen);
1332     OICFree(aclString);
1333     if (CA_STATUS_OK != result)
1334     {
1335         OC_LOG(ERROR, TAG, "Internal Error while sending ACL.");
1336         CADestroyToken(gToken);
1337         return convertCAResultToSPResult(result);
1338     }
1339
1340     SPResult res = SPTimeout(timeout, SP_PROV_ACL_DONE);
1341     if (SP_RESULT_SUCCESS != res)
1342     {
1343         OC_LOG(ERROR, TAG, "Internal Error occured");
1344         CADestroyToken(gToken);
1345         return SP_RESULT_TIMEOUT;
1346     }
1347     CADestroyToken(gToken);
1348     return res;
1349 }
1350
1351 SPResult SPProvisionCredentials(unsigned short timeout, OicSecCredType_t type,
1352                                 const SPDevInfo_t *pDevList)
1353 {
1354     if (NULL == pDevList)
1355     {
1356         return SP_RESULT_INVALID_PARAM;
1357     }
1358     const SPDevInfo_t *curr = pDevList;
1359     OicUuid_t provTooldeviceID = {};
1360     if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID))
1361     {
1362         OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
1363         return SP_RESULT_INTERNAL_ERROR;
1364     }
1365     //TODO Need to support other key types in future.
1366     switch (type)
1367     {
1368         case SYMMETRIC_PAIR_WISE_KEY:
1369             {
1370                 if (NULL == curr->next)
1371                 {
1372                     return SP_RESULT_INVALID_PARAM;
1373                 }
1374                 // Devices if present after second node will not be considered.
1375                 // in scenario-2. 2 devices are provisioned with credentials.
1376                 const SPDevInfo_t *firstDevice = curr;
1377                 const SPDevInfo_t *secondDevice = curr->next;
1378
1379                 OicSecCred_t *firstCred = NULL;
1380                 OicSecCred_t *secondCred = NULL;
1381
1382                 SPResult res = SPGeneratePairWiseCredentials(type, &provTooldeviceID,
1383                                &firstDevice->deviceId, &secondDevice->deviceId,
1384                                &firstCred, &secondCred);
1385                 if (res != SP_RESULT_SUCCESS)
1386                 {
1387                     OC_LOG(ERROR, TAG, "error while generating credentials");
1388                     return SP_RESULT_INTERNAL_ERROR;
1389                 }
1390                 res = provisionCredentials(timeout, firstCred, firstDevice);
1391                 if (SP_RESULT_SUCCESS != res)
1392                 {
1393                     OC_LOG_V(ERROR, TAG, "Credentials provisioning Error");
1394                     DeleteCredList(firstCred);
1395                     DeleteCredList(secondCred);
1396                     return SP_RESULT_INTERNAL_ERROR;
1397                 }
1398                 res = provisionCredentials(timeout, secondCred, secondDevice);
1399                 if (SP_RESULT_SUCCESS != res)
1400                 {
1401                     OC_LOG_V(ERROR, TAG, "Credentials provisioning Error");
1402                     DeleteCredList(firstCred);
1403                     DeleteCredList(secondCred);
1404                     return SP_RESULT_INTERNAL_ERROR;
1405                 }
1406                 DeleteCredList(firstCred);
1407                 DeleteCredList(secondCred);
1408                 return SP_RESULT_SUCCESS;
1409             }
1410         default:
1411             {
1412                 OC_LOG(ERROR, TAG, "Invalid option.");
1413                 return SP_RESULT_INVALID_PARAM;
1414             }
1415             return SP_RESULT_INTERNAL_ERROR;
1416     }
1417 }
1418
1419 SPResult SPFinalizeProvisioning(unsigned short timeout,
1420                                 SPTargetDeviceInfo_t *selectedDeviceInfo)
1421 {
1422     // TODO
1423     if (NULL == selectedDeviceInfo)
1424     {
1425         OC_LOG(ERROR, TAG, "Target device Info is NULL.");
1426         return SP_RESULT_INVALID_PARAM;
1427     }
1428
1429     uint16_t aclHash = 0; // value for beachhead version.
1430     selectedDeviceInfo->pstat->commitHash = aclHash;
1431     selectedDeviceInfo->pstat->tm = NORMAL;
1432     char *payloadBuffer = BinToPstatJSON(selectedDeviceInfo->pstat);
1433     if (NULL == payloadBuffer)
1434     {
1435         OC_LOG(ERROR, TAG, "Error while converting pstat bin to json");
1436         return SP_RESULT_INTERNAL_ERROR;
1437     }
1438     int payloadLen = strlen(payloadBuffer);
1439
1440     handler = &FinalizeProvisioningHandler;
1441     gStateManager |= SP_UP_HASH_STARTED;
1442
1443     CAResult_t result = sendCARequest(CA_PUT,
1444                                       &selectedDeviceInfo->endpoint,
1445                                       OC_FLAG_SECURE,
1446                                       OIC_RSRC_PSTAT_URI,
1447                                       payloadBuffer, payloadLen);
1448     OICFree(payloadBuffer);
1449     if (CA_STATUS_OK != result)
1450     {
1451         OC_LOG(ERROR, TAG, "Internal Error occured");
1452         CADestroyToken(gToken);
1453         return convertCAResultToSPResult(result);
1454     }
1455
1456     SPResult res = SPTimeout(timeout, SP_UP_HASH_DONE);
1457     if (SP_RESULT_SUCCESS != res)
1458     {
1459         OC_LOG(ERROR, TAG, "Internal Error occured");
1460         CADestroyToken(gToken);
1461         return SP_RESULT_TIMEOUT;
1462     }
1463
1464     CAEndpoint_t endpoint = {};
1465     OICStrcpy(endpoint.addr, MAX_ADDR_STR_SIZE_CA, selectedDeviceInfo->endpoint.addr);
1466     endpoint.port = CA_SECURE_PORT;
1467
1468     result = CACloseDtlsSession(&endpoint);
1469     if (CA_STATUS_OK != result)
1470     {
1471         OC_LOG(WARNING, TAG, "Failed to close the DTLS session.");
1472     }
1473
1474     CADestroyToken(gToken);
1475     gStateManager = 0;
1476     gPstat = NULL;
1477     return res;
1478 }
1479
1480 SPResult SPTerminateProvisioning()
1481 {
1482     deleteList();
1483     return SP_RESULT_SUCCESS;;
1484 }