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 * *****************************************************************/
26 #include "ocprovisioningmanager.h"
27 #include "secureresourceprovider.h"
29 #include "oic_malloc.h"
30 #include "aclresource.h"
31 #include "pstatresource.h"
32 #include "srmresourcestrings.h"
33 #include "credresource.h"
34 #include "doxmresource.h"
35 #include "credentialgenerator.h"
36 #include "cainterface.h"
39 #include "pmutility.h"
41 #define SRP_MAX_URI_LENGTH 512
45 * Macro to verify argument is not equal to NULL.
46 * eg: VERIFY_NON_NULL(TAG, ptrData, ERROR,OC_STACK_ERROR);
48 #define VERIFY_NON_NULL(tag, arg, logLevel, retValue) { if (NULL == (arg)) \
49 { OC_LOG((logLevel), tag, (#arg " is NULL")); return retValue; } }
52 * Macro to verify success of operation.
53 * eg: VERIFY_SUCCESS(TAG, OC_STACK_OK == foo(), ERROR, OC_STACK_ERROR);
55 #define VERIFY_SUCCESS(tag, op, logLevel, retValue) { if (!(op)) \
56 {OC_LOG((logLevel), tag, (#op " failed!!")); return retValue;} }
59 * Structure to carry credential data to callback.
61 typedef struct CredentialData CredentialData_t;
64 void *ctx; /**< Pointer to user context.**/
65 const OCProvisionDev_t *deviceInfo1; /**< Pointer to OCProvisionDev_t.**/
66 const OCProvisionDev_t *deviceInfo2; /**< Pointer to OCProvisionDev_t.**/
67 OicSecCred_t *credInfo; /**< Pointer to OicSecCred_t.**/
68 OicSecCred_t *credInfoFirst; /**< Pointer to OicSecCred_t.**/
69 OCProvisionResultCB resultCallback; /**< Pointer to result callback.**/
70 OCProvisionResult_t *resArr; /**< Result array.**/
71 int numOfResults; /**< Number of results in result array.**/
75 * Structure to carry ACL provision API data to callback.
77 typedef struct ACLData ACLData_t;
80 void *ctx; /**< Pointer to user context.**/
81 const OCProvisionDev_t *deviceInfo; /**< Pointer to PMDevInfo_t.**/
82 OCProvisionResultCB resultCallback; /**< Pointer to result callback.**/
83 OCProvisionResult_t *resArr; /**< Result array.**/
84 int numOfResults; /**< Number of results in result array.**/
90 static OCStackResult provisionCredentials(const OicSecCred_t *cred,
91 const OCProvisionDev_t *deviceInfo, CredentialData_t *credData,
92 OCClientResponseHandler responseHandler);
96 * Internal function to update result in result array.
98 static void registerResultForCredProvisioning(CredentialData_t *credData,
99 OCStackResult stackresult, int cause)
102 OC_LOG_V(INFO,TAG,"value of credData->numOfResults is %d",credData->numOfResults);
105 memcpy(credData->resArr[(credData->numOfResults)].deviceId.id,
106 credData->deviceInfo1->doxm->deviceID.id,UUID_LENGTH);
110 memcpy(credData->resArr[(credData->numOfResults)].deviceId.id,
111 credData->deviceInfo2->doxm->deviceID.id,UUID_LENGTH);
113 credData->resArr[(credData->numOfResults)].res = stackresult;
114 ++(credData->numOfResults);
118 * Callback handler for handling callback of provisioning device 2.
120 * @param[in] ctx ctx value passed to callback from calling function.
121 * @param[in] handle handle to an invocation
122 * @param[in] clientResponse Response from queries to remote servers.
123 * @return OC_STACK_DELETE_TRANSACTION to delete the transaction
124 * and OC_STACK_KEEP_TRANSACTION to keep it.
126 static OCStackApplicationResult provisionCredentialCB2(void *ctx, OCDoHandle handle,
127 OCClientResponse *clientResponse)
129 VERIFY_NON_NULL(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
130 CredentialData_t *credData = (CredentialData_t *) ctx;
132 OCProvisionResultCB resultCallback = credData->resultCallback;
133 OC_LOG(INFO, TAG, "provisionCredentialCB2 called");
136 if(OC_STACK_RESOURCE_CREATED == clientResponse->result)
138 registerResultForCredProvisioning(credData, OC_STACK_RESOURCE_CREATED, 2);
139 ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
142 OICFree(credData->resArr);
144 return OC_STACK_DELETE_TRANSACTION;
148 OC_LOG(INFO, TAG, "provisionCredentialCB2 received Null clientResponse");
149 registerResultForCredProvisioning(credData, OC_STACK_ERROR, 2);
150 ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
153 OICFree(credData->resArr);
155 return OC_STACK_DELETE_TRANSACTION;
159 * Callback handler for handling callback of provisioning device 1.
161 * @param[in] ctx ctx value passed to callback from calling function.
162 * @param[in] handle handle to an invocation
163 * @param[in] clientResponse Response from queries to remote servers.
164 * @return OC_STACK_DELETE_TRANSACTION to delete the transaction
165 * and OC_STACK_KEEP_TRANSACTION to keep it.
167 static OCStackApplicationResult provisionCredentialCB1(void *ctx, OCDoHandle handle,
168 OCClientResponse *clientResponse)
170 VERIFY_NON_NULL(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
171 CredentialData_t* credData = (CredentialData_t*) ctx;
172 OICFree(credData->credInfoFirst);
173 const OCProvisionDev_t *deviceInfo = credData->deviceInfo2;
174 OicSecCred_t *credInfo = credData->credInfo;
175 const OCProvisionResultCB resultCallback = credData->resultCallback;
178 if (OC_STACK_RESOURCE_CREATED == clientResponse->result)
180 // send credentials to second device
181 registerResultForCredProvisioning(credData, OC_STACK_RESOURCE_CREATED,1);
182 OCStackResult res = provisionCredentials(credInfo, deviceInfo, credData,
183 provisionCredentialCB2);
184 DeleteCredList(credInfo);
185 if (OC_STACK_OK != res)
187 registerResultForCredProvisioning(credData, res,2);
188 ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
191 OICFree(credData->resArr);
198 registerResultForCredProvisioning(credData, OC_STACK_ERROR,1);
199 ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
202 OICFree(credData->resArr);
209 OC_LOG(INFO, TAG, "provisionCredentialCB received Null clientResponse for first device");
210 registerResultForCredProvisioning(credData, OC_STACK_ERROR,1);
211 ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
214 DeleteCredList(credInfo);
215 OICFree(credData->resArr);
219 return OC_STACK_DELETE_TRANSACTION;
225 * Internal function for handling credential generation and sending credential to resource server.
227 * @param[in] cred Instance of cred resource.
228 * @param[in] deviceInfo information about device to which credential is to be provisioned.
229 * @param[in] responseHandler callbak called by OC stack when request API receives response.
230 * @return OC_STACK_OK in case of success and other value otherwise.
232 static OCStackResult provisionCredentials(const OicSecCred_t *cred,
233 const OCProvisionDev_t *deviceInfo, CredentialData_t *credData,
234 OCClientResponseHandler responseHandler)
236 OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
239 OC_LOG(ERROR, TAG, "Failed to memory allocation");
240 return OC_STACK_NO_MEMORY;
242 secPayload->base.type = PAYLOAD_TYPE_SECURITY;
243 secPayload->securityData = BinToCredJSON(cred);
244 VERIFY_NON_NULL(TAG, secPayload->securityData, ERROR, OC_STACK_NO_MEMORY);
245 OC_LOG_V(INFO, TAG, "Credential for provisioning : %s",secPayload->securityData);
246 char uri[SRP_MAX_URI_LENGTH] = { 0 };
248 size_t uriLen = sizeof(uri);
249 snprintf(uri, uriLen - 1, COAPS_QUERY, deviceInfo->endpoint.addr, deviceInfo->securePort,
252 uri[uriLen - 1] = '\0';
253 OC_LOG_V(INFO, TAG, "URI for Credential provisioning : %s",uri);
254 OCCallbackData cbData = { };
255 cbData.cb = responseHandler;
256 cbData.context = (void *) credData;
259 OCDoHandle handle = NULL;
260 OCMethod method = OC_REST_POST;
261 // TODO replace CT_ADAPTER_IP with value from discovery
262 OCStackResult ret = OCDoResource(&handle, method, uri, 0, secPayload,
263 CT_ADAPTER_IP, OC_HIGH_QOS, &cbData, NULL, 0);
264 OC_LOG_V(INFO, TAG, "OCDoResource::Credential provisioning returned : %d",ret);
265 if (ret != OC_STACK_OK)
267 OC_LOG(ERROR, TAG, "OCStack resource error");
273 OCStackResult SRPProvisionCredentials(void *ctx, OicSecCredType_t type, size_t keySize,
274 const OCProvisionDev_t *pDev1,
275 const OCProvisionDev_t *pDev2,
276 OCProvisionResultCB resultCallback)
278 VERIFY_NON_NULL(TAG, pDev1, ERROR, OC_STACK_INVALID_PARAM);
279 VERIFY_NON_NULL(TAG, pDev2, ERROR, OC_STACK_INVALID_PARAM);
280 VERIFY_NON_NULL(TAG, resultCallback, ERROR, OC_STACK_INVALID_CALLBACK);
282 if (!(keySize == OWNER_PSK_LENGTH_128 || keySize == OWNER_PSK_LENGTH_256))
284 OC_LOG(INFO, TAG, "Invalid key size");
285 return OC_STACK_INVALID_PARAM;
288 OC_LOG(INFO, TAG, "In SRPProvisionCredentials");
290 OicUuid_t provTooldeviceID = {{0,}};
291 if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID))
293 OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
294 return OC_STACK_ERROR;
296 OC_LOG(INFO, TAG, "retrieved deviceid");
299 case SYMMETRIC_PAIR_WISE_KEY:
301 const OCProvisionDev_t *firstDevice = pDev1;
302 const OCProvisionDev_t *secondDevice = pDev2;
304 OicSecCred_t *firstCred = NULL;
305 OicSecCred_t *secondCred = NULL;
306 OCStackResult res = PMGeneratePairWiseCredentials(type, keySize, &provTooldeviceID,
307 &firstDevice->doxm->deviceID, &secondDevice->doxm->deviceID,
308 &firstCred, &secondCred);
309 VERIFY_SUCCESS(TAG, (res==OC_STACK_OK), ERROR, OC_STACK_ERROR);
310 OC_LOG(INFO, TAG, "Credentials generated successfully");
311 CredentialData_t *credData = (CredentialData_t *) OICMalloc(sizeof(CredentialData_t));
312 if (NULL == credData)
314 OC_LOG(ERROR, TAG, "Memory allocation problem");
315 return OC_STACK_NO_MEMORY;
317 memset(credData, 0x00, sizeof(CredentialData_t));
318 credData->deviceInfo1 = firstDevice;
319 credData->deviceInfo2 = secondDevice;
320 credData->credInfo = secondCred;
322 credData->credInfoFirst = firstCred;
323 credData->numOfResults = 0;
324 credData->resultCallback = resultCallback;
325 // first call to provision creds to device1.
326 // second call to provision creds to device2.
329 (OCProvisionResult_t*)OICMalloc(sizeof(OCProvisionResult_t) * noOfRiCalls);
330 if (NULL == credData->resArr)
332 OC_LOG(ERROR, TAG, "Memory allocation problem");
333 return OC_STACK_NO_MEMORY;
335 memset(credData->resArr, 0x00, sizeof(sizeof(OCProvisionResult_t)*noOfRiCalls));
336 res = provisionCredentials(firstCred, firstDevice, credData, &provisionCredentialCB1);
337 if (OC_STACK_OK != res)
339 DeleteCredList(firstCred);
340 DeleteCredList(secondCred);
341 OICFree(credData->resArr);
344 OC_LOG_V(INFO, TAG, "provisionCredentials returned: %d",res);
345 VERIFY_SUCCESS(TAG, (res==OC_STACK_OK), ERROR, OC_STACK_ERROR);
350 OC_LOG(ERROR, TAG, "Invalid option.");
351 return OC_STACK_INVALID_PARAM;
354 return OC_STACK_ERROR;
358 * Internal Function to store results in result array during ACL provisioning.
360 static void registerResultForACLProvisioning(ACLData_t *aclData,
361 OCStackResult stackresult)
363 OC_LOG_V(INFO, TAG, "Inside registerResultForACLProvisioning aclData->numOfResults is %d\n",
364 aclData->numOfResults);
365 memcpy(aclData->resArr[(aclData->numOfResults)].deviceId.id,
366 aclData->deviceInfo->doxm->deviceID.id, UUID_LENGTH);
367 aclData->resArr[(aclData->numOfResults)].res = stackresult;
368 ++(aclData->numOfResults);
372 * Callback handler of SRPProvisionACL.
374 * @param[in] ctx ctx value passed to callback from calling function.
375 * @param[in] handle handle to an invocation
376 * @param[in] clientResponse Response from queries to remote servers.
377 * @return OC_STACK_DELETE_TRANSACTION to delete the transaction
378 * and OC_STACK_KEEP_TRANSACTION to keep it.
380 static OCStackApplicationResult SRPProvisionACLCB(void *ctx, OCDoHandle handle,
381 OCClientResponse *clientResponse)
383 OC_LOG_V(INFO, TAG, "Inside SRPProvisionACLCB.");
384 VERIFY_NON_NULL(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
385 ACLData_t *aclData = (ACLData_t*)ctx;
386 OCProvisionResultCB resultCallback = aclData->resultCallback;
390 if(OC_STACK_RESOURCE_CREATED == clientResponse->result)
392 registerResultForACLProvisioning(aclData, OC_STACK_RESOURCE_CREATED);
393 ((OCProvisionResultCB)(resultCallback))(aclData->ctx, aclData->numOfResults,
396 OICFree(aclData->resArr);
398 return OC_STACK_DELETE_TRANSACTION;
401 registerResultForACLProvisioning(aclData, OC_STACK_ERROR);
402 ((OCProvisionResultCB)(resultCallback))(aclData->ctx, aclData->numOfResults,
405 OC_LOG_V(ERROR, TAG, "SRPProvisionACLCB received Null clientResponse");
406 OICFree(aclData->resArr);
408 return OC_STACK_DELETE_TRANSACTION;
411 OCStackResult SRPProvisionACL(void *ctx, const OCProvisionDev_t *selectedDeviceInfo,
412 OicSecAcl_t *acl, OCProvisionResultCB resultCallback)
414 VERIFY_NON_NULL(TAG, selectedDeviceInfo, ERROR, OC_STACK_INVALID_PARAM);
415 VERIFY_NON_NULL(TAG, acl, ERROR, OC_STACK_INVALID_PARAM);
416 VERIFY_NON_NULL(TAG, resultCallback, ERROR, OC_STACK_INVALID_CALLBACK);
418 OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
421 OC_LOG(ERROR, TAG, "Failed to memory allocation");
422 return OC_STACK_NO_MEMORY;
424 secPayload->base.type = PAYLOAD_TYPE_SECURITY;
425 secPayload->securityData = BinToAclJSON(acl);
426 VERIFY_NON_NULL(TAG, secPayload->securityData, ERROR, OC_STACK_NO_MEMORY);
427 OC_LOG_V(INFO, TAG, "ACL : %s", secPayload->securityData);
429 char uri[SRP_MAX_URI_LENGTH] = {0};
430 size_t uriLen = sizeof(uri);
432 snprintf(uri, uriLen - 1, COAPS_QUERY, selectedDeviceInfo->endpoint.addr,
433 selectedDeviceInfo->securePort, OIC_RSRC_ACL_URI);
434 uri[uriLen - 1] = '\0';
436 OC_LOG_V(INFO, TAG, "URI : %s", uri);
437 OCCallbackData cbData = {0,};
438 cbData.cb = &SRPProvisionACLCB;
439 ACLData_t *aclData = (ACLData_t *) OICMalloc(sizeof(ACLData_t));
442 OC_LOG(ERROR, TAG, "Unable to allocate memory");
443 return OC_STACK_NO_MEMORY;
445 memset(aclData, 0x00, sizeof(ACLData_t));
446 aclData->deviceInfo = selectedDeviceInfo;
447 aclData->resultCallback = resultCallback;
448 aclData->numOfResults=0;
450 // call to provision ACL to device1.
452 aclData->resArr = (OCProvisionResult_t*)OICMalloc(sizeof(OCProvisionResult_t)*noOfRiCalls);
453 if (aclData->resArr == NULL)
455 OC_LOG(ERROR, TAG, "Unable to allocate memory");
456 return OC_STACK_NO_MEMORY;
458 memset(aclData->resArr, 0x00, sizeof(sizeof(OCProvisionResult_t)*noOfRiCalls));
459 cbData.context = (void *)aclData;
461 OCMethod method = OC_REST_POST;
462 OCDoHandle handle = NULL;
463 OC_LOG(DEBUG, TAG, "Sending ACL info to resource server");
464 // TODO replace CT_ADAPTER_IP with value from discovery
466 OCStackResult ret = OCDoResource(&handle, method, uri,
467 &selectedDeviceInfo->endpoint, secPayload,
468 CT_ADAPTER_IP, OC_HIGH_QOS, &cbData, NULL, 0);
470 if (ret != OC_STACK_OK)
472 OICFree(aclData->resArr);
475 VERIFY_SUCCESS(TAG, (OC_STACK_OK == ret), ERROR, OC_STACK_ERROR);