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