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