1 /* *****************************************************************
3 * Copyright 2015 Samsung Electronics All Rights Reserved.
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 * *****************************************************************/
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
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
30 #ifndef _POSIX_C_SOURCE
31 #define _POSIX_C_SOURCE 200809L
41 #include "ocpayload.h"
42 #include "ocpayloadcbor.h"
43 #include "oic_malloc.h"
46 #include "cainterface.h"
47 #include "provisioningmanager.h"
48 #include "credentialgenerator.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"
62 SP_DISCOVERY_STARTED = (0x1 << 1),
63 SP_DISCOVERY_ERROR = (0x1 << 2),
64 SP_DISCOVERY_DONE = (0x1 << 3),
65 SP_SEC_RES_INFO_STARTED = (0x1 << 4),
66 SP_SEC_RES_INFO_ERROR = (0x1 << 5),
67 SP_SEC_RES_INFO_DONE = (0x1 << 6),
68 SP_UP_OWN_TR_METH_STARTED = (0x1 << 7),
69 SP_UP_OWN_TR_METH_ERROR = (0x1 << 8),
70 SP_UP_OWN_TR_METH_DONE = (0x1 << 9),
71 SP_LIST_METHODS_STARTED = (0x1 << 10),
72 SP_LIST_METHODS_ERROR = (0x1 << 11),
73 SP_LIST_METHODS_DONE = (0x1 << 12),
74 SP_UPDATE_OP_MODE_STARTED = (0x1 << 13),
75 SP_UPDATE_OP_MODE_ERROR = (0x1 << 14),
76 SP_UPDATE_OP_MODE_DONE = (0x1 << 15),
77 SP_UPDATE_OWNER_STARTED = (0x1 << 16),
78 SP_UPDATE_OWNER_ERROR = (0x1 << 17),
79 SP_UPDATE_OWNER_DONE = (0x1 << 18),
80 SP_PROV_ACL_STARTED = (0x1 << 19),
81 SP_PROV_ACL_ERROR = (0x1 << 20),
82 SP_PROV_ACL_DONE = (0x1 << 21),
83 SP_UP_HASH_STARTED = (0x1 << 22),
84 SP_UP_HASH_ERROR = (0x1 << 23),
85 SP_UP_HASH_DONE = (0x1 << 24),
86 SP_PROV_CRED_STARTED = (0x1 << 25),
87 SP_PROV_CRED_ERROR = (0x1 << 26),
88 SP_PROV_CRED_DONE = (0x1 << 27)
89 } SPProvisioningStates;
91 #define SP_MAX_BUF_LEN 1024
92 #define TAG "SPProvisionAPI"
93 #define COAP_QUERY "coap://%s:%d%s"
94 #define COAPS_QUERY "coaps://%s:%d%s"
96 bool (*handler)(const CAEndpoint_t *, const CAResponseInfo_t *);
99 * CA token to keep track of response.
101 static CAToken_t gToken = NULL;
104 * start pointer for discovered device linked list.
106 static SPTargetDeviceInfo_t *gStartOfDiscoveredDevices = NULL;
109 * current pointer of device linked list.
111 static SPTargetDeviceInfo_t *gCurrent = NULL;
114 * Variable to keep track of various request.
116 static uint32_t gStateManager = 0;
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.
123 static OicSecDpom_t gProvisioningToolCapability[] = { SINGLE_SERVICE_CLIENT_DRIVEN };
126 * Number of supported provisioning methods
127 * current version supports only one.
129 static int gNumOfProvisioningMethodsPT = 1;
132 * Global variable to save pstat.
134 static OicSecPstat_t *gPstat = NULL;
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.
142 static inline char *SPStringCopy(char *destination, const char *source, size_t num)
144 if (strncpy(destination, source, num))
146 destination[num - 1] = '\0';
153 * Function to convert CA result code to SP result code.
155 * @return result code of SP corresponding to that of CA.
157 static SPResult convertCAResultToSPResult(CAResult_t caResult)
163 return SP_RESULT_SUCCESS;
165 case CA_STATUS_INVALID_PARAM:
167 return SP_RESULT_CONN_INVALID_PARAM;
169 case CA_ADAPTER_NOT_ENABLED:
171 return SP_RESULT_CONN_SERVER_STARTED_ALREADY;
173 case CA_SERVER_STARTED_ALREADY:
175 return SP_RESULT_CONN_SERVER_STARTED_ALREADY;
177 case CA_SERVER_NOT_STARTED:
179 return SP_RESULT_CONN_SERVER_NOT_STARTED;
181 case CA_DESTINATION_NOT_REACHABLE:
183 return SP_RESULT_CONN_DESTINATION_NOT_REACHABLE;
185 case CA_SOCKET_OPERATION_FAILED:
187 return SP_RESULT_CONN_SOCKET_OPERATION_FAILED;
191 return SP_RESULT_CONN_SEND_FAILED;
193 case CA_RECEIVE_FAILED:
195 return SP_RESULT_CONN_RECEIVE_FAILED;
197 case CA_MEMORY_ALLOC_FAILED:
199 return SP_RESULT_CONN_MEMORY_ALLOC_FAILED;
201 case CA_REQUEST_TIMEOUT:
203 return SP_RESULT_CONN_REQUEST_TIMEOUT;
205 case CA_DESTINATION_DISCONNECTED:
207 return SP_RESULT_CONN_DESTINATION_DISCONNECTED;
209 case CA_STATUS_FAILED:
211 return SP_RESULT_CONN_STATUS_FAILED;
213 case CA_NOT_SUPPORTED:
215 return SP_RESULT_CONN_NOT_SUPPORTED;
219 return SP_RESULT_INTERNAL_ERROR;
225 * Function to delete memory allocated to linked list.
228 static void deleteList()
230 SPTargetDeviceInfo_t *current = gStartOfDiscoveredDevices;
234 SPTargetDeviceInfo_t *next = current->next;
235 DeleteDoxmBinData(current->doxm);
236 DeletePstatBinData(current->pstat);
240 gStartOfDiscoveredDevices = NULL;
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.
249 static SPResult SPTimeout(unsigned short timeout, uint32_t mask)
251 struct timespec startTime = {};
252 struct timespec currTime = {};
254 CAResult_t res = SP_RESULT_SUCCESS;
255 #ifdef _POSIX_MONOTONIC_CLOCK
256 int clock_res = clock_gettime(CLOCK_MONOTONIC, &startTime);
258 int clock_res = clock_gettime(CLOCK_REALTIME, &startTime);
262 return SP_RESULT_INTERNAL_ERROR;
264 while (CA_STATUS_OK == res)
266 res = CAHandleRequestResponse();
267 #ifdef _POSIX_MONOTONIC_CLOCK
268 clock_res = clock_gettime(CLOCK_MONOTONIC, &currTime);
270 clock_res = clock_gettime(CLOCK_REALTIME, &currTime);
274 return SP_RESULT_INTERNAL_ERROR;
276 long elapsed = (currTime.tv_sec - startTime.tv_sec);
277 if (SP_NO_MASK == mask)
279 if (elapsed > timeout)
281 return SP_RESULT_SUCCESS;
286 if (gStateManager & mask)
288 return SP_RESULT_SUCCESS;
290 if ((elapsed > timeout) && timeout)
292 return SP_RESULT_INTERNAL_ERROR;
296 return convertCAResultToSPResult(res);
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.
310 static CAResult_t sendCARequest(CAMethod_t method,
311 const OCDevAddr *devAddr,
312 OCTransportFlags secure,
313 const char *resourceUri,
314 char *payload, int payloadLen)
316 if (payload && '\0' != (*(payload + payloadLen)))
318 OC_LOG(ERROR, TAG, "Payload not properly terminated.");
319 return CA_STATUS_INVALID_PARAM;
322 if (CA_STATUS_OK != CAGenerateToken(&gToken, CA_MAX_TOKEN_LEN))
324 OC_LOG(ERROR, TAG, "Error while generating token");
325 return CA_MEMORY_ALLOC_FAILED;
328 CAEndpoint_t *endpoint = NULL;
329 if (CA_STATUS_OK != CACreateEndpoint(devAddr->flags | (CATransportFlags_t)secure,
330 devAddr->adapter, devAddr->addr,
331 devAddr->port, &endpoint))
333 OC_LOG(ERROR, TAG, "Failed to create remote endpoint");
334 CADestroyEndpoint(endpoint);
335 return CA_STATUS_FAILED;
338 OCSecurityPayload secPayload = {};
339 secPayload.securityData = payload;
340 secPayload.base.type = PAYLOAD_TYPE_SECURITY;
342 CARequestInfo_t requestInfo = {};
343 requestInfo.method = method;
344 requestInfo.isMulticast = false;
345 OCConvertPayload((OCPayload*)(&secPayload), &requestInfo.info.payload,
346 &requestInfo.info.payloadSize);
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;
353 CAResult_t caResult = CA_STATUS_OK;
354 caResult = CASendRequest(endpoint, &requestInfo);
355 if (CA_STATUS_OK != caResult)
357 OC_LOG(ERROR, TAG, "Send Request Error !!");
359 CADestroyEndpoint(endpoint);
366 * @param[in] endpoint Endpoint information
367 * @param[in] doxm pointer to doxm instance.
368 * @return SP_RESULT_SUCCESS for success and errorcode otherwise.
370 static SPResult addDevice(const CAEndpoint_t *endpoint, OicSecDoxm_t* doxm)
372 if (NULL == endpoint)
374 return SP_RESULT_INVALID_PARAM;
376 SPTargetDeviceInfo_t *ptr = (SPTargetDeviceInfo_t *)OICCalloc(1, sizeof (SPTargetDeviceInfo_t));
379 OC_LOG(ERROR, TAG, "Error while allocating memory for linkedlist node !!");
380 return SP_RESULT_MEM_ALLOCATION_FAIL;
383 memcpy(&(ptr->endpoint), endpoint, sizeof(CAEndpoint_t));
388 if (NULL == gStartOfDiscoveredDevices)
390 gStartOfDiscoveredDevices = ptr;
395 gCurrent->next = ptr;
398 return SP_RESULT_SUCCESS;
402 * updateDevice to update resource info for the endpoint.
404 * @param[in] endpoint Endpoint information
405 * @param[in] port secure port.
406 * @return SP_RESULT_SUCCESS for success and errorcode otherwise.
409 static SPResult updateDevice(const CAEndpoint_t *endpoint, uint16_t port)
411 if (NULL == endpoint)
413 return SP_RESULT_INVALID_PARAM;
415 SPTargetDeviceInfo_t *ptr = gStartOfDiscoveredDevices;
418 if(0 == strcmp(ptr->endpoint.addr, endpoint->addr) &&
419 ptr->endpoint.port == endpoint->port)
421 ptr->securePort = port;
422 return SP_RESULT_SUCCESS;
426 return SP_RESULT_INTERNAL_ERROR;
430 * Function to provide timeframe in which response can be received.
432 * @param[in] timeout Timeout in seconds.
433 * @return SP_RESULT_SUCCESS on success , otherwise error code.
435 static SPResult SPWaitForResponse(unsigned short timeout)
437 return SPTimeout(timeout, SP_NO_MASK);
441 * Function to select appropriate provisioning method.
443 * @param[in] supportedMethodsList List of supported methods
444 * @param[out] selectedMethod Selected methods
445 * @return SP_SUCCESS on success
447 static SPResult selectProvisioningMethod(OicSecOxm_t *supportedMethods, size_t numberOfMethods,
448 OicSecOxm_t *selectedMethod)
451 TODO Logic to find appropiate method and assign it to out param
452 for beachhead release method at index 0 will be returned.
454 *selectedMethod = supportedMethods[0];
455 return SP_RESULT_SUCCESS;
459 * Response handler for discovery.
461 * @param[in] object Remote endpoint object
462 * @param[in] requestInfo Datastructure containing request information.
463 * @return true is CA token matches request token, false otherwise.
465 static bool ProvisionDiscoveryHandler(const CAEndpoint_t *object,
466 const CAResponseInfo_t *responseInfo)
468 if ((gStateManager & SP_DISCOVERY_STARTED) && gToken)
470 // Response handler for discovery.
471 if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
473 OC_LOG(INFO, TAG, "Inside ProvisionDiscoveryHandler.");
474 if (NULL == responseInfo->info.payload)
476 OC_LOG(INFO, TAG, "Skiping Null payload");
480 OCPayload* payload = NULL;
481 OCStackResult result = OCParsePayload(&payload, responseInfo->info.payload,
482 responseInfo->info.payloadSize);
484 OicSecDoxm_t *ptrDoxm = NULL;
486 if(result == OC_STACK_OK && payload->type == PAYLOAD_TYPE_SECURITY)
488 ptrDoxm = JSONToDoxmBin(((OCSecurityPayload*)payload)->securityData);
491 OCPayloadDestroy(payload);
495 OC_LOG(INFO, TAG, "Ignoring malformed JSON");
499 OC_LOG(DEBUG, TAG, "Successfully converted doxm json to bin.");
501 SPResult res = addDevice(object, ptrDoxm);
502 if (SP_RESULT_SUCCESS != res)
504 OC_LOG(ERROR, TAG, "Error while adding data to linkedlist.");
505 gStateManager = gStateManager | SP_DISCOVERY_ERROR;
506 DeleteDoxmBinData(ptrDoxm);
509 OC_LOG(INFO, TAG, "Exiting ProvisionDiscoveryHandler.");
510 gStateManager |= SP_DISCOVERY_DONE;
520 * Response handler for discovery.
522 * @param[in] object Remote endpoint object
523 * @param[in] requestInfo Datastructure containing request information.
524 * @return true is CA token matches request token, false otherwise.
527 static bool ProvisionSecureResourceInfoHandler(const CAEndpoint_t *object,
528 const CAResponseInfo_t *responseInfo)
530 if (!object || !responseInfo)
535 if ((gStateManager & SP_SEC_RES_INFO_STARTED) && gToken)
537 // Response handler for discovery.
538 if (0 == memcmp(gToken, responseInfo->info.token, CA_MAX_TOKEN_LEN))
540 OC_LOG(INFO, TAG, "Inside ProvisionSecureResourceInfoHandler.");
541 if (NULL == responseInfo->info.payload)
543 OC_LOG(ERROR, TAG, "Exiting ProvisionSecureResourceInfoHandler.");
544 gStateManager |= SP_SEC_RES_INFO_ERROR;
548 OCPayload* payload = NULL;
549 OCStackResult result = OCParsePayload(&payload, responseInfo->info.payload,
550 responseInfo->info.payloadSize);
552 OCDiscoveryPayload* discover = (OCDiscoveryPayload*) payload;
553 // Discovered secure resource payload contains secure port; update the device
554 // with the secure port using endpoint.
555 if (result == OC_STACK_OK && discover)
557 if (updateDevice(object, discover->resources->port) == SP_RESULT_SUCCESS)
559 gStateManager |= SP_SEC_RES_INFO_DONE;
563 gStateManager |= SP_SEC_RES_INFO_ERROR;
565 OC_LOG(INFO, TAG, "Exiting ProvisionSecureResourceInfoHandler.");
568 OCPayloadDestroy(payload);
574 OC_LOG(ERROR, TAG, "Error in ProvisionSecureResourceInfoHandler.");
575 gStateManager |= SP_SEC_RES_INFO_ERROR;
583 * Response handler ownership transfer.
585 * @param[in] object Remote endpoint object
586 * @param[in] requestInfo Datastructure containing request information.
587 * @return true is CA token matches request token, false otherwise.
589 static bool OwnerShipTransferModeHandler(const CAEndpoint_t *object,
590 const CAResponseInfo_t *responseInfo)
592 if ((gStateManager & SP_UP_OWN_TR_METH_STARTED) && gToken)
594 // response handler for ownership tranfer
595 OC_LOG(INFO, TAG, "Inside OwnerShipTransferModeHandler.");
596 if (memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength) == 0)
598 OC_LOG_V(DEBUG, TAG, "Response result for OwnerShipTransferMode: %d", responseInfo->result);
599 if (CA_SUCCESS == responseInfo->result)
601 gStateManager |= SP_UP_OWN_TR_METH_DONE;
602 OC_LOG(INFO, TAG, "Exiting OwnerShipTransferModeHandler.");
606 gStateManager |= SP_UP_OWN_TR_METH_ERROR;
607 OC_LOG(ERROR, TAG, "Error in OwnerShipTransferModeHandler.");
616 * Response handler list methods.
618 * @param[in] object Remote endpoint object
619 * @param[in] requestInfo Datastructure containing request information.
620 * @return true is CA token matches request token, false otherwise.
622 static bool ListMethodsHandler(const CAEndpoint_t *object,
623 const CAResponseInfo_t *responseInfo)
625 if ((gStateManager & SP_LIST_METHODS_STARTED) && gToken)
627 OC_LOG(INFO, TAG, "Inside ListMethodsHandler.");
628 if (memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength) == 0)
630 OC_LOG_V(DEBUG, TAG, "Response result for ListMethodsHandler: %d", responseInfo->result);
631 if (CA_SUCCESS == responseInfo->result)
633 OC_LOG_V (DEBUG, TAG, "Response Payload: %s", responseInfo->info.payload);
634 // Temp logic to trim oc attribute from json
635 // JSONToPstatBin should handle OC in JSON.
636 if (NULL == responseInfo->info.payload)
638 OC_LOG(ERROR, TAG, "response payload is null.");
639 gStateManager |= SP_LIST_METHODS_ERROR;
643 OCPayload* payload = NULL;
644 OCStackResult result = OCParsePayload(&payload, responseInfo->info.payload,
645 responseInfo->info.payloadSize);
647 OicSecPstat_t *pstat = NULL;
649 if(result == OC_STACK_OK && payload->type == PAYLOAD_TYPE_SECURITY)
651 pstat = JSONToPstatBin(((OCSecurityPayload*)payload)->securityData);
654 OCPayloadDestroy(payload);
658 OC_LOG(ERROR, TAG, "Error while converting json to pstat bin");
659 gStateManager |= SP_LIST_METHODS_ERROR;
662 DeletePstatBinData(gPstat);
665 gStateManager |= SP_LIST_METHODS_DONE;
667 OC_LOG(INFO, TAG, "Exiting ListMethodsHandler.");
676 * Response handler for update operation mode.
678 * @param[in] object Remote endpoint object
679 * @param[in] requestInfo Datastructure containing request information.
680 * @return true is CA token matches request token, false otherwise.
682 static bool OperationModeUpdateHandler(const CAEndpoint_t *object,
683 const CAResponseInfo_t *responseInfo)
685 if ((gStateManager & SP_UPDATE_OP_MODE_STARTED) && gToken)
687 if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
689 OC_LOG(INFO, TAG, "Inside OperationModeUpdateHandler.");
690 OC_LOG_V(DEBUG, TAG, "Response result for OperationModeUpdateHandler: %d", responseInfo->result);
691 if (CA_SUCCESS == responseInfo->result)
693 gStateManager |= SP_UPDATE_OP_MODE_DONE;
694 OC_LOG(INFO, TAG, "Exiting OperationModeUpdateHandler.");
698 gStateManager |= SP_UPDATE_OP_MODE_ERROR;
699 OC_LOG(ERROR, TAG, "Error in OperationModeUpdateHandler.");
708 * Response handler for ownership transfer.
710 * @param[in] object Remote endpoint object
711 * @param[in] requestInfo Datastructure containing request information.
712 * @return true is CA token matches request token, false otherwise.
714 static bool OwnerShipUpdateHandler(const CAEndpoint_t *object,
715 const CAResponseInfo_t *responseInfo)
717 if ((gStateManager & SP_UPDATE_OWNER_STARTED) && gToken)
719 // response handler for ownership tranfer
720 if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
722 OC_LOG(INFO, TAG, "Inside OwnerShipUpdateHandler.");
723 OC_LOG_V(DEBUG, TAG, "Response result for OwnerShipUpdateHandler: %d", responseInfo->result);
724 if (CA_SUCCESS == responseInfo->result)
726 gStateManager |= SP_UPDATE_OWNER_DONE;
727 OC_LOG(INFO, TAG, "Exiting OwnerShipUpdateHandler.");
731 gStateManager |= SP_UPDATE_OWNER_ERROR;
732 OC_LOG(ERROR, TAG, "Error in OwnerShipUpdateHandler.");
741 * Response handler for ACL provisioning.
743 * @param[in] object Remote endpoint object
744 * @param[in] requestInfo Datastructure containing request information.
745 * @return true is CA token matches request token, false otherwise.
747 static bool ACLProvisioningHandler(const CAEndpoint_t *object,
748 const CAResponseInfo_t *responseInfo)
750 if ((gStateManager & SP_PROV_ACL_STARTED) && gToken)
753 // response handler for ACL provisioning.
754 if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
756 OC_LOG(INFO, TAG, "Inside ACLProvisioningHandler.");
757 OC_LOG_V(DEBUG, TAG, "Response result for ACLProvisioningHandler: %d", responseInfo->result);
758 if (CA_CREATED == responseInfo->result)
760 OC_LOG(INFO, TAG, "Exiting ACLProvisioningHandler.");
761 gStateManager |= SP_PROV_ACL_DONE;
765 OC_LOG(ERROR, TAG, "Error in ACLProvisioningHandler.");
766 gStateManager |= SP_PROV_ACL_ERROR;
775 * Response handler for provisioning finalization.
777 * @param[in] object Remote endpoint object
778 * @param[in] requestInfo Datastructure containing request information.
779 * @return true is CA token matches request token, false otherwise.
781 static bool FinalizeProvisioningHandler(const CAEndpoint_t *object,
782 const CAResponseInfo_t *responseInfo)
784 if ((gStateManager & SP_UP_HASH_STARTED) && gToken)
786 // response handler for finalize provisioning.
787 if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
789 OC_LOG(INFO, TAG, "Inside FinalizeProvisioningHandler.");
790 OC_LOG_V(DEBUG, TAG, "Response result for FinalizeProvisioningHandler: %d", responseInfo->result);
791 if (CA_SUCCESS == responseInfo->result)
793 gStateManager |= SP_UP_HASH_DONE;
794 OC_LOG(INFO, TAG, "Exiting FinalizeProvisioningHandler.");
798 gStateManager |= SP_UP_HASH_ERROR;
799 OC_LOG(ERROR, TAG, "Error in FinalizeProvisioningHandler.");
808 * Response handler for Credential provisioning.
810 * @param[in] object Remote endpoint object
811 * @param[in] requestInfo Datastructure containing request information.
812 * @return true is CA token matches request token, false otherwise.
814 static bool CredProvisioningHandler(const CAEndpoint_t *object,
815 const CAResponseInfo_t *responseInfo)
817 if ((gStateManager & SP_PROV_CRED_STARTED) && gToken)
819 // response handler for CRED provisioning.
820 OC_LOG(INFO, TAG, "Inside CredProvisioningHandler.");
821 OC_LOG_V(DEBUG, TAG, "Response result for CredProvisioningHandler: %d", responseInfo->result);
822 if (0 == memcmp(gToken, responseInfo->info.token, responseInfo->info.tokenLength))
824 if (CA_CREATED == responseInfo->result)
826 gStateManager |= SP_PROV_CRED_DONE;
827 OC_LOG(INFO, TAG, "Exiting CredProvisioningHandler.");
831 gStateManager |= SP_PROV_CRED_ERROR;
832 OC_LOG(ERROR, TAG, "Error in CredProvisioningHandler.");
843 * @param[in] object Remote endpoint object
844 * @param[in] responseInfo Datastructure containing response information.
845 * @return true if received response is for provisioning API false otherwise.
847 static bool SPResponseHandler(const CAEndpoint_t *object,
848 const CAResponseInfo_t *responseInfo)
850 bool isProvResponse = false;
851 if ((NULL != responseInfo) && (NULL != responseInfo->info.token))
853 isProvResponse = handler(object, responseInfo);
855 return isProvResponse;
859 * Function to find the resources using multicast discovery.
861 * @param[in] timeout timeout in secs
862 * @return SP_RESULT_SUCCESS normally otherwise error code.
864 static SPResult findResource(unsigned short timeout)
866 static char DOXM_OWNED_FALSE_MULTICAST_QUERY[] = "/oic/sec/doxm?Owned=FALSE";
867 CAResult_t res = CAGenerateToken(&gToken, CA_MAX_TOKEN_LEN);
868 if (CA_STATUS_OK != res)
870 OC_LOG(ERROR, TAG, "Error while generating token.");
871 return SP_RESULT_INTERNAL_ERROR;
874 CAEndpoint_t endpoint = {};
876 // Only IP is supported currently for provisioning and ownership transfer
877 endpoint.adapter = CA_ADAPTER_IP;
878 endpoint.flags = CA_IPV4 | CA_IPV6 | CA_SCOPE_LINK;
880 CAMessageType_t msgType = CA_MSG_NONCONFIRM;
881 CAInfo_t requestData = { 0 };
882 requestData.token = gToken;
883 requestData.tokenLength = CA_MAX_TOKEN_LEN;
884 requestData.payload = NULL;
885 requestData.payloadSize = 0;
886 requestData.type = msgType;
887 requestData.resourceUri = DOXM_OWNED_FALSE_MULTICAST_QUERY;
888 CARequestInfo_t requestInfo = { 0 };
889 requestInfo.method = CA_GET;
890 requestInfo.info = requestData;
891 requestInfo.isMulticast = true;
892 res = CASendRequest(&endpoint, &requestInfo);
894 handler = &ProvisionDiscoveryHandler;
895 gStateManager |= SP_DISCOVERY_STARTED;
896 if (CA_STATUS_OK != res)
898 OC_LOG(ERROR, TAG, "Error while finding resource.");
899 return convertCAResultToSPResult(res);
903 OC_LOG(INFO, TAG, "Discovery Request sent successfully");
905 return SPWaitForResponse(timeout);
909 * Function to get the secure resource info.
911 * @param[in] devAddr Device address for the destination
912 * @param[in] timeout timeout in secs
913 * @return SP_RESULT_SUCCESS normally otherwise error code.
915 static SPResult getSecureResourceInfo(OCDevAddr *devAddr, unsigned short timeout)
917 char OIC_UNICAST_SEC_QUERY[] = "/oic/res?rt=oic.sec.doxm";
918 CAResult_t res = CAGenerateToken(&gToken, CA_MAX_TOKEN_LEN);
919 if (CA_STATUS_OK != res)
921 OC_LOG(ERROR, TAG, "Error while generating token.");
922 return SP_RESULT_INTERNAL_ERROR;
925 CAInfo_t requestData = {};
926 requestData.token = gToken;
927 requestData.tokenLength = CA_MAX_TOKEN_LEN;
928 requestData.payload = NULL;
929 requestData.payloadSize = 0;
930 requestData.type = CA_MSG_NONCONFIRM;
931 requestData.resourceUri = OIC_UNICAST_SEC_QUERY;
932 CARequestInfo_t requestInfo = { 0 };
933 requestInfo.method = CA_GET;
934 requestInfo.info = requestData;
935 requestInfo.isMulticast = false;
936 handler = &ProvisionSecureResourceInfoHandler;
937 res = CASendRequest((CAEndpoint_t*)devAddr, &requestInfo);
939 gStateManager |= SP_SEC_RES_INFO_STARTED;
940 if (CA_STATUS_OK != res)
942 OC_LOG(ERROR, TAG, "Error while finding secure resource.");
943 return convertCAResultToSPResult(res);
947 OC_LOG(INFO, TAG, "Secure resource info request sent successfully");
949 return SPWaitForResponse(timeout);
953 * Function to update the operation mode. As per the spec. Operation mode in client driven
954 * single service provisioning it will be updated to 0x3
956 * @param[in] timeout timeout for operation.
957 * @param[in] deviceInfo Device Info.
958 * @return SP_SUCCESS on success
960 static SPResult updateOwnerTransferModeToResource(unsigned short timeout,
961 SPTargetDeviceInfo_t *deviceInfo, OicSecOxm_t selectedMethod)
963 SPResult res = SP_RESULT_INTERNAL_ERROR;
965 deviceInfo->doxm->oxmSel = selectedMethod;
966 char *payload = BinToDoxmJSON(deviceInfo->doxm);
969 OC_LOG(ERROR, TAG, "Error while converting bin to json");
970 return SP_RESULT_INTERNAL_ERROR;
972 OC_LOG_V(DEBUG, TAG, "Payload: %s", payload);
973 int payloadLen = strlen(payload);
975 handler = &OwnerShipTransferModeHandler;
976 gStateManager |= SP_UP_OWN_TR_METH_STARTED;
978 CAResult_t result = sendCARequest(CA_PUT,
979 &deviceInfo->endpoint,
982 payload, payloadLen);
984 if (CA_STATUS_OK != result)
986 OC_LOG(ERROR, TAG, "Error while sending request.");
987 CADestroyToken(gToken);
988 return convertCAResultToSPResult(result);
990 res = SPTimeout(timeout, SP_UP_OWN_TR_METH_DONE);
991 if (SP_RESULT_SUCCESS != res)
993 OC_LOG(ERROR, TAG, "Internal Error occured");
994 CADestroyToken(gToken);
995 return SP_RESULT_TIMEOUT;
997 CADestroyToken(gToken);
998 return SP_RESULT_SUCCESS;
1002 * Function to send request to resource to get its pstat resource information.
1004 * @param[in] timeout timeout for operation.
1005 * @param[in] deviceInfo Device Info.
1006 * @return SP_SUCCESS on success
1008 static SPResult getProvisioningStatusResource(unsigned short timeout,
1009 SPTargetDeviceInfo_t *deviceInfo)
1011 handler = &ListMethodsHandler;
1012 gStateManager |= SP_LIST_METHODS_STARTED;
1014 CAResult_t result = sendCARequest(CA_GET,
1015 &deviceInfo->endpoint,
1019 if (CA_STATUS_OK != result)
1021 OC_LOG(ERROR, TAG, "Failure while sending request.");
1022 CADestroyToken(gToken);
1023 return convertCAResultToSPResult(result);
1025 SPResult res = SPTimeout(timeout, SP_LIST_METHODS_DONE);
1026 if (SP_RESULT_SUCCESS != res)
1028 OC_LOG(ERROR, TAG, "Timeout while getting method list.");
1029 CADestroyToken(gToken);
1030 return SP_RESULT_TIMEOUT;
1032 if (gStateManager && SP_LIST_METHODS_DONE)
1034 deviceInfo->pstat = gPstat;
1035 CADestroyToken(gToken);
1036 OC_LOG(DEBUG, TAG, "getProvisioningStatusResource completed.");
1037 return SP_RESULT_SUCCESS;
1039 CADestroyToken(gToken);
1040 return SP_RESULT_INTERNAL_ERROR;
1044 * Function to update the operation mode. As per the spec. Operation mode in client driven
1045 * single service provisioning it will be updated to 0x3
1047 * @param[in] timeout timeout for operation.
1048 * @param[in] deviceInfo Device Info.
1049 * @return SP_SUCCESS on success
1051 static SPResult updateOperationMode(unsigned short timeout,
1052 SPTargetDeviceInfo_t *deviceInfo,
1053 OicSecDpom_t selectedOperationMode)
1056 SPResult res = SP_RESULT_INTERNAL_ERROR;
1058 deviceInfo->pstat->om = selectedOperationMode;
1060 char *payloadBuffer = BinToPstatJSON(deviceInfo->pstat);
1061 if (NULL == payloadBuffer)
1063 OC_LOG(ERROR, TAG, "Error while converting pstat bin to json");
1064 return SP_RESULT_INTERNAL_ERROR;
1067 size_t payloadLen = strlen(payloadBuffer);
1068 handler = &OperationModeUpdateHandler;
1069 gStateManager |= SP_UPDATE_OP_MODE_STARTED;
1071 CAResult_t result = sendCARequest(CA_PUT,
1072 &deviceInfo->endpoint,
1075 payloadBuffer, payloadLen);
1076 if (CA_STATUS_OK != result)
1078 OC_LOG(ERROR, TAG, "Error while sending request.");
1079 CADestroyToken(gToken);
1080 OICFree(payloadBuffer);
1081 return convertCAResultToSPResult(result);
1083 res = SPTimeout(timeout, SP_UPDATE_OP_MODE_DONE);
1084 if (SP_RESULT_SUCCESS != res)
1086 OC_LOG(ERROR, TAG, "Internal Error occured");
1087 CADestroyToken(gToken);
1088 OICFree(payloadBuffer);
1089 return SP_RESULT_TIMEOUT;
1091 CADestroyToken(gToken);
1092 OICFree(payloadBuffer);
1094 if (gStateManager & SP_UPDATE_OP_MODE_DONE)
1096 return SP_RESULT_SUCCESS;
1098 return SP_RESULT_INTERNAL_ERROR;
1102 * Function to initiate DTLS handshake.
1104 * @param[in] deviceInfo Provisioning context
1105 * @return SP_SUCCESS on success
1107 static SPResult initiateDtlsHandshake(const CAEndpoint_t *endpoint)
1109 CAResult_t caresult = CAEnableAnonECDHCipherSuite(true);
1110 if (CA_STATUS_OK != caresult)
1112 OC_LOG_V(ERROR, TAG, "Unable to enable anon cipher suite");
1113 return SP_RESULT_INTERNAL_ERROR;
1115 OC_LOG(INFO, TAG, "Anonymous cipher suite Enabled.");
1117 caresult = CAInitiateHandshake(endpoint);
1118 if (CA_STATUS_OK != caresult)
1120 OC_LOG_V(ERROR, TAG, "DTLS handshake failure.");
1123 return SP_RESULT_SUCCESS;
1127 * Function to send ownerShip info. This function would update Owned as true and
1128 * owner as UUID for provisioning tool
1130 * @param[in] timeout timeout value for the operation.
1131 * @param[in] deviceInfo provisioning context.
1132 * @return SP_SUCCESS on success
1134 static SPResult sendOwnershipInfo(unsigned short timeout,
1135 SPTargetDeviceInfo_t *selectedDeviceInfo)
1137 OicUuid_t provTooldeviceID = {};
1139 if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID))
1141 OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
1142 return SP_RESULT_INTERNAL_ERROR;
1144 memcpy(selectedDeviceInfo->doxm->owner.id, provTooldeviceID.id , UUID_LENGTH);
1146 selectedDeviceInfo->doxm->owned = true;
1148 char *payloadBuffer = BinToDoxmJSON(selectedDeviceInfo->doxm);
1149 if (NULL == payloadBuffer)
1151 OC_LOG(ERROR, TAG, "Error while converting doxm bin to json");
1152 return SP_RESULT_INTERNAL_ERROR;
1154 int payloadLen = strlen(payloadBuffer);
1156 handler = &OwnerShipUpdateHandler;
1157 gStateManager |= SP_UPDATE_OWNER_STARTED;
1159 CAResult_t result = sendCARequest(CA_PUT,
1160 &selectedDeviceInfo->endpoint,
1163 payloadBuffer, payloadLen);
1164 if (CA_STATUS_OK != result)
1166 OC_LOG(ERROR, TAG, "Error while sending request.");
1167 CADestroyToken(gToken);
1168 OICFree(payloadBuffer);
1169 return convertCAResultToSPResult(result);
1171 SPResult res = SPTimeout(timeout, SP_UPDATE_OWNER_DONE);
1172 if (SP_RESULT_SUCCESS != res)
1174 OC_LOG(ERROR, TAG, "Internal Error occured");
1175 CADestroyToken(gToken);
1176 OICFree(payloadBuffer);
1177 return SP_RESULT_TIMEOUT;
1179 CADestroyToken(gToken);
1180 OICFree(payloadBuffer);
1181 return SP_RESULT_SUCCESS;
1185 * Function to save ownerPSK at provisioning tool end.
1187 * @return SP_SUCCESS on success
1189 static SPResult saveOwnerPSK(SPTargetDeviceInfo_t *selectedDeviceInfo)
1191 SPResult result = SP_RESULT_INTERNAL_ERROR;
1193 CAEndpoint_t endpoint = {};
1194 OICStrcpy(endpoint.addr, MAX_ADDR_STR_SIZE_CA, selectedDeviceInfo->endpoint.addr);
1195 endpoint.port = selectedDeviceInfo->securePort;
1197 OicUuid_t provTooldeviceID = {};
1198 if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID))
1200 OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
1204 uint8_t ownerPSK[OWNER_PSK_LENGTH_128] = {};
1206 //Generating OwnerPSK
1207 CAResult_t pskRet = CAGenerateOwnerPSK(&endpoint,
1208 (uint8_t *)OXM_JUST_WORKS, strlen(OXM_JUST_WORKS), provTooldeviceID.id,
1209 sizeof(provTooldeviceID.id), selectedDeviceInfo->doxm->deviceID.id,
1210 sizeof(selectedDeviceInfo->doxm->deviceID.id), ownerPSK,
1211 OWNER_PSK_LENGTH_128);
1213 if (CA_STATUS_OK == pskRet)
1215 OC_LOG(INFO, TAG,"ownerPSK dump:\n");
1216 OC_LOG_BUFFER(INFO, TAG,ownerPSK, OWNER_PSK_LENGTH_128);
1217 //Generating new credential for provisioning tool
1219 uint32_t outLen = 0;
1221 char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(ownerPSK)) + 1] = {};
1222 B64Result b64Ret = b64Encode(ownerPSK, sizeof(ownerPSK), base64Buff, sizeof(base64Buff),
1224 if (B64_OK == b64Ret)
1226 OicSecCred_t *cred = GenerateCredential(&selectedDeviceInfo->doxm->deviceID,
1227 SYMMETRIC_PAIR_WISE_KEY, NULL,
1228 base64Buff, ownLen, &provTooldeviceID);
1231 //Update the SVR database.
1232 if (OC_STACK_OK == AddCredential(cred))
1234 result = SP_RESULT_SUCCESS;
1238 OC_LOG(ERROR, TAG, "AddCredential failed");
1243 OC_LOG(ERROR, TAG, "GenerateCredential failed");
1248 OC_LOG(ERROR, TAG, "b64Encode failed");
1253 OC_LOG(ERROR, TAG, "CAGenerateOwnerPSK failed");
1259 * Function to select operation mode.This function will return most secure common operation mode.
1261 * @param[out] selectedMode selected operation mode
1262 * @return SP_SUCCESS on success
1264 static void selectOperationMode(const SPTargetDeviceInfo_t *selectedDeviceInfo,
1265 OicSecDpom_t **selectedMode)
1269 while (i < gNumOfProvisioningMethodsPT && j < selectedDeviceInfo->pstat->smLen)
1271 if (gProvisioningToolCapability[i] < selectedDeviceInfo->pstat->sm[j])
1275 else if (selectedDeviceInfo->pstat->sm[j] < gProvisioningToolCapability[i])
1279 else /* if gProvisioningToolCapability[i] == deviceSupportedMethods[j] */
1281 *selectedMode = &(gProvisioningToolCapability[j]);
1288 * Function to perform onwership tranfer based to ownership transfer mode.
1290 * @param[in] timeout timeout in secs to perform operation. 0 timeout means
1291 function will wait forever.
1292 * @param[in] selectedDeviceInfo instance of SPTargetDeviceInfo_t structure.
1293 * @return SP_SUCCESS on success
1295 static SPResult doOwnerShipTransfer(unsigned short timeout,
1296 SPTargetDeviceInfo_t *selectedDeviceInfo)
1298 OicSecDpom_t *selectedOperationMode = NULL;
1299 selectOperationMode(selectedDeviceInfo, &selectedOperationMode);
1301 SPResult res = updateOperationMode(timeout, selectedDeviceInfo, *selectedOperationMode);
1302 if (SP_RESULT_SUCCESS != res)
1304 OC_LOG(ERROR, TAG, "Error while updating operation mode.");
1305 return SP_RESULT_INTERNAL_ERROR;
1307 if (*selectedOperationMode == SINGLE_SERVICE_CLIENT_DRIVEN)
1309 CAEndpoint_t endpoint = {0};
1310 OICStrcpy(endpoint.addr, MAX_ADDR_STR_SIZE_CA, selectedDeviceInfo->endpoint.addr);
1311 endpoint.port = selectedDeviceInfo->securePort;
1313 res = initiateDtlsHandshake(&endpoint);
1314 if (SP_RESULT_SUCCESS == res)
1316 selectedDeviceInfo->endpoint.port = selectedDeviceInfo->securePort;
1317 res = sendOwnershipInfo(timeout, selectedDeviceInfo);
1318 if (SP_RESULT_SUCCESS != res)
1320 OC_LOG(ERROR, TAG, "Error while updating ownership information.");
1322 res = saveOwnerPSK(selectedDeviceInfo);
1324 //Close temporal DTLS session
1325 if(CA_STATUS_OK != CACloseDtlsSession(&endpoint))
1327 OC_LOG(WARNING, TAG, "doOwnerShipTransfer() : failed to close the dtls session");
1332 OC_LOG(ERROR, TAG, "Error during initiating DTLS handshake.");
1335 //Disable Anonymous ECDH cipher suite before leaving this method
1336 if(CA_STATUS_OK != CAEnableAnonECDHCipherSuite(false))
1338 OC_LOG(WARNING, TAG, "doOwnerShipTransfer() : failed to disable Anon ECDH cipher suite");
1341 return (res != SP_RESULT_SUCCESS) ? SP_RESULT_INTERNAL_ERROR : SP_RESULT_SUCCESS;
1345 * The function is responsible for discovering secure resources(such as, /oic/sec/doxm etc) with
1346 * OC_EXPLICIT_DISCOVERABLE on a OIC device which needs to be provisioned.
1348 * @param[in] timeout Timeout in seconds, value till which function will listen to responses from
1349 * client before returning the list of devices.
1350 * @param[in] selectedDeviceInfo Device information.
1351 * @return SP_SUCCESS in case of success and other value otherwise.
1353 static SPResult discoverSecureResource(unsigned short timeout,
1354 SPTargetDeviceInfo_t *selectedDeviceInfo)
1356 if (NULL == selectedDeviceInfo)
1358 OC_LOG(ERROR, TAG, "List is not null can cause memory leak");
1359 return SP_RESULT_INVALID_PARAM;
1361 SPResult smResponse = SP_RESULT_SUCCESS;
1362 smResponse = getSecureResourceInfo(&selectedDeviceInfo->endpoint, timeout);
1363 if (SP_RESULT_SUCCESS != smResponse)
1365 return SP_RESULT_INTERNAL_ERROR;
1367 if (gStateManager & SP_SEC_RES_INFO_DONE)
1369 if (gStateManager & SP_SEC_RES_INFO_ERROR)
1371 return SP_RESULT_INTERNAL_ERROR;
1373 return SP_RESULT_SUCCESS;
1375 return SP_RESULT_INTERNAL_ERROR;
1379 * Function to provision credentials to specific device.
1381 * @param[in] timeout timeout in secs to perform operation. 0 timeout means function will
1383 * @param[in] cred credential to be provisioned.
1384 * @param[in] deviceInfo Instance of SPDevInfo_t structure. Representing a selected device for
1386 * @return SP_SUCCESS on success
1388 SPResult provisionCredentials(unsigned short timeout, const OicSecCred_t *cred,
1389 const SPDevInfo_t *deviceInfo)
1391 char *credJson = NULL;
1392 credJson = BinToCredJSON(cred);
1393 if (NULL == credJson)
1395 OC_LOG(ERROR, TAG, "Memory allocation problem");
1396 return SP_RESULT_MEM_ALLOCATION_FAIL;
1399 int payloadLen = strlen(credJson);
1400 handler = &CredProvisioningHandler;
1401 gStateManager |= SP_PROV_CRED_STARTED;
1403 CAResult_t result = sendCARequest(CA_POST,
1404 &deviceInfo->endpoint,
1407 credJson, payloadLen);
1409 if (CA_STATUS_OK != result)
1411 OC_LOG(ERROR, TAG, "Internal Error while sending Credentials.");
1412 CADestroyToken(gToken);
1413 return convertCAResultToSPResult(result);
1416 SPResult res = SPTimeout(timeout, SP_PROV_CRED_DONE);
1417 if (SP_RESULT_SUCCESS != res)
1419 OC_LOG(ERROR, TAG, "Internal Error occured");
1420 CADestroyToken(gToken);
1421 return SP_RESULT_TIMEOUT;
1423 CADestroyToken(gToken);
1428 SPResult SPProvisioningDiscovery(unsigned short timeout,
1429 SPTargetDeviceInfo_t **list)
1433 OC_LOG(ERROR, TAG, "List is not null can cause memory leak");
1434 return SP_RESULT_INVALID_PARAM;
1436 SRMRegisterProvisioningResponseHandler(SPResponseHandler);
1437 SPResult smResponse = SP_RESULT_SUCCESS;
1438 smResponse = findResource(timeout);
1439 if (SP_RESULT_SUCCESS != smResponse)
1441 return SP_RESULT_INTERNAL_ERROR;
1443 if (gStateManager & SP_DISCOVERY_DONE)
1445 if (gStateManager & SP_DISCOVERY_ERROR)
1447 return SP_RESULT_INTERNAL_ERROR;
1449 *list = gStartOfDiscoveredDevices;
1450 return SP_RESULT_SUCCESS;
1452 return SP_RESULT_INTERNAL_ERROR;
1455 SPResult SPInitProvisionContext(unsigned short timeout,
1456 SPTargetDeviceInfo_t *selectedDeviceInfo)
1458 if (NULL == selectedDeviceInfo )
1460 return SP_RESULT_INVALID_PARAM;
1462 SPResult res = SP_RESULT_SUCCESS;
1464 //Discover secure resource and update the device info.
1465 res = discoverSecureResource(timeout, selectedDeviceInfo);
1466 if (SP_RESULT_SUCCESS != res)
1468 OC_LOG(ERROR, TAG, "Error in discoverSecureResource");
1469 return SP_RESULT_INTERNAL_ERROR;
1472 OicSecOxm_t selectedMethod = OIC_JUST_WORKS;
1474 selectProvisioningMethod(selectedDeviceInfo->doxm->oxm, selectedDeviceInfo->doxm->oxmLen,
1476 OC_LOG_V(DEBUG, TAG, "Selected method %d:", selectedMethod);
1477 res = updateOwnerTransferModeToResource(timeout, selectedDeviceInfo, selectedMethod);
1479 if (SP_RESULT_SUCCESS != res)
1481 OC_LOG(ERROR, TAG, "Error while updating owner transfer mode.");
1482 return SP_RESULT_INTERNAL_ERROR;
1485 res = getProvisioningStatusResource(timeout, selectedDeviceInfo);
1486 if (SP_RESULT_SUCCESS != res)
1488 OC_LOG(ERROR, TAG, "Error while getting provisioning status.");
1489 return SP_RESULT_INTERNAL_ERROR;
1491 OC_LOG(INFO, TAG, "Starting ownership transfer");
1492 return doOwnerShipTransfer(timeout, selectedDeviceInfo);
1496 SPResult SPProvisionACL(unsigned short timeout, const SPTargetDeviceInfo_t *selectedDeviceInfo,
1499 if (NULL == selectedDeviceInfo || NULL == acl)
1501 return SP_RESULT_INVALID_PARAM;
1503 char *aclString = NULL;
1504 aclString = BinToAclJSON(acl);
1506 if (NULL == aclString)
1508 OC_LOG(ERROR, TAG, "Memory allocation problem");
1509 return SP_RESULT_MEM_ALLOCATION_FAIL;
1512 int payloadLen = strlen(aclString);
1513 handler = &ACLProvisioningHandler;
1514 gStateManager |= SP_PROV_ACL_STARTED;
1516 CAResult_t result = sendCARequest(CA_POST,
1517 &selectedDeviceInfo->endpoint,
1520 aclString, payloadLen);
1522 if (CA_STATUS_OK != result)
1524 OC_LOG(ERROR, TAG, "Internal Error while sending ACL.");
1525 CADestroyToken(gToken);
1526 return convertCAResultToSPResult(result);
1529 SPResult res = SPTimeout(timeout, SP_PROV_ACL_DONE);
1530 if (SP_RESULT_SUCCESS != res)
1532 OC_LOG(ERROR, TAG, "Internal Error occured");
1533 CADestroyToken(gToken);
1534 return SP_RESULT_TIMEOUT;
1536 CADestroyToken(gToken);
1540 SPResult SPProvisionCredentials(unsigned short timeout, OicSecCredType_t type,
1541 const SPDevInfo_t *pDevList)
1543 if (NULL == pDevList)
1545 return SP_RESULT_INVALID_PARAM;
1547 const SPDevInfo_t *curr = pDevList;
1548 OicUuid_t provTooldeviceID = {};
1549 if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID))
1551 OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
1552 return SP_RESULT_INTERNAL_ERROR;
1554 //TODO Need to support other key types in future.
1557 case SYMMETRIC_PAIR_WISE_KEY:
1559 if (NULL == curr->next)
1561 return SP_RESULT_INVALID_PARAM;
1563 // Devices if present after second node will not be considered.
1564 // in scenario-2. 2 devices are provisioned with credentials.
1565 const SPDevInfo_t *firstDevice = curr;
1566 const SPDevInfo_t *secondDevice = curr->next;
1568 OicSecCred_t *firstCred = NULL;
1569 OicSecCred_t *secondCred = NULL;
1571 SPResult res = SPGeneratePairWiseCredentials(type, &provTooldeviceID,
1572 &firstDevice->deviceId, &secondDevice->deviceId,
1573 &firstCred, &secondCred);
1574 if (res != SP_RESULT_SUCCESS)
1576 OC_LOG(ERROR, TAG, "error while generating credentials");
1577 return SP_RESULT_INTERNAL_ERROR;
1579 res = provisionCredentials(timeout, firstCred, firstDevice);
1580 if (SP_RESULT_SUCCESS != res)
1582 OC_LOG_V(ERROR, TAG, "Credentials provisioning Error");
1583 DeleteCredList(firstCred);
1584 DeleteCredList(secondCred);
1585 return SP_RESULT_INTERNAL_ERROR;
1587 res = provisionCredentials(timeout, secondCred, secondDevice);
1588 if (SP_RESULT_SUCCESS != res)
1590 OC_LOG_V(ERROR, TAG, "Credentials provisioning Error");
1591 DeleteCredList(firstCred);
1592 DeleteCredList(secondCred);
1593 return SP_RESULT_INTERNAL_ERROR;
1595 DeleteCredList(firstCred);
1596 DeleteCredList(secondCred);
1597 return SP_RESULT_SUCCESS;
1601 OC_LOG(ERROR, TAG, "Invalid option.");
1602 return SP_RESULT_INVALID_PARAM;
1604 return SP_RESULT_INTERNAL_ERROR;
1608 SPResult SPFinalizeProvisioning(unsigned short timeout,
1609 SPTargetDeviceInfo_t *selectedDeviceInfo)
1612 if (NULL == selectedDeviceInfo)
1614 OC_LOG(ERROR, TAG, "Target device Info is NULL.");
1615 return SP_RESULT_INVALID_PARAM;
1618 uint16_t aclHash = 0; // value for beachhead version.
1619 selectedDeviceInfo->pstat->commitHash = aclHash;
1620 selectedDeviceInfo->pstat->tm = NORMAL;
1621 char *payloadBuffer = BinToPstatJSON(selectedDeviceInfo->pstat);
1622 if (NULL == payloadBuffer)
1624 OC_LOG(ERROR, TAG, "Error while converting pstat bin to json");
1625 return SP_RESULT_INTERNAL_ERROR;
1627 int payloadLen = strlen(payloadBuffer);
1629 handler = &FinalizeProvisioningHandler;
1630 gStateManager |= SP_UP_HASH_STARTED;
1632 CAResult_t result = sendCARequest(CA_PUT,
1633 &selectedDeviceInfo->endpoint,
1636 payloadBuffer, payloadLen);
1637 OICFree(payloadBuffer);
1638 if (CA_STATUS_OK != result)
1640 OC_LOG(ERROR, TAG, "Internal Error occured");
1641 CADestroyToken(gToken);
1642 return convertCAResultToSPResult(result);
1645 SPResult res = SPTimeout(timeout, SP_UP_HASH_DONE);
1646 if (SP_RESULT_SUCCESS != res)
1648 OC_LOG(ERROR, TAG, "Internal Error occured");
1649 CADestroyToken(gToken);
1650 return SP_RESULT_TIMEOUT;
1653 result = CACloseDtlsSession((CAEndpoint_t*)&selectedDeviceInfo->endpoint);
1654 if (CA_STATUS_OK != result)
1656 OC_LOG(WARNING, TAG, "Failed to close the DTLS session.");
1659 CADestroyToken(gToken);
1665 SPResult SPTerminateProvisioning()
1668 return SP_RESULT_SUCCESS;;