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