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