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