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