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 * *****************************************************************/
25 #include "ocprovisioningmanager.h"
26 #include "secureresourceprovider.h"
28 #include "oic_malloc.h"
29 #include "aclresource.h"
30 #include "pstatresource.h"
31 #include "srmresourcestrings.h"
32 #include "credresource.h"
33 #include "doxmresource.h"
34 #include "credentialgenerator.h"
35 #include "cainterface.h"
38 #include "pmutility.h"
40 #define SRP_MAX_URI_LENGTH 512
44 * Macro to verify argument is not equal to NULL.
45 * eg: VERIFY_NON_NULL(TAG, ptrData, ERROR,OC_STACK_ERROR);
47 #define VERIFY_NON_NULL(tag, arg, logLevel, retValue) { if (NULL == (arg)) \
48 { OC_LOG((logLevel), tag, (#arg " is NULL")); return retValue; } }
51 * Macro to verify success of operation.
52 * eg: VERIFY_SUCCESS(TAG, OC_STACK_OK == foo(), ERROR, OC_STACK_ERROR);
54 #define VERIFY_SUCCESS(tag, op, logLevel, retValue) { if (!(op)) \
55 {OC_LOG((logLevel), tag, (#op " failed!!")); return retValue;} }
58 * Structure to carry credential data to callback.
60 typedef struct CredentialData CredentialData_t;
63 void *ctx; /**< Pointer to user context.**/
64 const OCProvisionDev_t *deviceInfo1; /**< Pointer to OCProvisionDev_t.**/
65 const OCProvisionDev_t *deviceInfo2; /**< Pointer to OCProvisionDev_t.**/
66 OicSecCred_t *credInfo; /**< Pointer to OicSecCred_t.**/
67 OicSecCred_t *credInfoFirst; /**< Pointer to OicSecCred_t.**/
68 OCProvisionResultCB resultCallback; /**< Pointer to result callback.**/
69 OCProvisionResult_t *resArr; /**< Result array.**/
70 int numOfResults; /**< Number of results in result array.**/
74 * Structure to carry ACL provision API data to callback.
76 typedef struct ACLData ACLData_t;
79 void *ctx; /**< Pointer to user context.**/
80 const OCProvisionDev_t *deviceInfo; /**< Pointer to PMDevInfo_t.**/
81 OCProvisionResultCB resultCallback; /**< Pointer to result callback.**/
82 OCProvisionResult_t *resArr; /**< Result array.**/
83 int numOfResults; /**< Number of results in result array.**/
89 static OCStackResult provisionCredentials(const OicSecCred_t *cred,
90 const OCProvisionDev_t *deviceInfo, CredentialData_t *credData,
91 OCClientResponseHandler responseHandler);
95 * Internal function to update result in result array.
97 static void registerResultForCredProvisioning(CredentialData_t *credData,
98 OCStackResult stackresult, int cause)
101 OC_LOG_V(INFO,TAG,"value of credData->numOfResults is %d",credData->numOfResults);
104 memcpy(credData->resArr[(credData->numOfResults)].deviceId.id,
105 credData->deviceInfo1->doxm->deviceID.id,UUID_LENGTH);
109 memcpy(credData->resArr[(credData->numOfResults)].deviceId.id,
110 credData->deviceInfo2->doxm->deviceID.id,UUID_LENGTH);
112 credData->resArr[(credData->numOfResults)].res = stackresult;
113 ++(credData->numOfResults);
117 * Callback handler for handling callback of provisioning device 2.
119 * @param[in] ctx ctx value passed to callback from calling function.
120 * @param[in] UNUSED handle to an invocation
121 * @param[in] clientResponse Response from queries to remote servers.
122 * @return OC_STACK_DELETE_TRANSACTION to delete the transaction
123 * and OC_STACK_KEEP_TRANSACTION to keep it.
125 static OCStackApplicationResult provisionCredentialCB2(void *ctx, OCDoHandle UNUSED,
126 OCClientResponse *clientResponse)
128 VERIFY_NON_NULL(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
129 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] UNUSED 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 UNUSED,
168 OCClientResponse *clientResponse)
170 VERIFY_NON_NULL(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
172 CredentialData_t* credData = (CredentialData_t*) ctx;
173 OICFree(credData->credInfoFirst);
174 const OCProvisionDev_t *deviceInfo = credData->deviceInfo2;
175 OicSecCred_t *credInfo = credData->credInfo;
176 const OCProvisionResultCB resultCallback = credData->resultCallback;
179 if (OC_STACK_RESOURCE_CREATED == clientResponse->result)
181 // send credentials to second device
182 registerResultForCredProvisioning(credData, OC_STACK_RESOURCE_CREATED,1);
183 OCStackResult res = provisionCredentials(credInfo, deviceInfo, credData,
184 provisionCredentialCB2);
185 DeleteCredList(credInfo);
186 if (OC_STACK_OK != res)
188 registerResultForCredProvisioning(credData, res,2);
189 ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
192 OICFree(credData->resArr);
199 registerResultForCredProvisioning(credData, OC_STACK_ERROR,1);
200 ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
203 OICFree(credData->resArr);
210 OC_LOG(INFO, TAG, "provisionCredentialCB received Null clientResponse for first device");
211 registerResultForCredProvisioning(credData, OC_STACK_ERROR,1);
212 ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
215 DeleteCredList(credInfo);
216 OICFree(credData->resArr);
220 return OC_STACK_DELETE_TRANSACTION;
226 * Internal function for handling credential generation and sending credential to resource server.
228 * @param[in] cred Instance of cred resource.
229 * @param[in] deviceInfo information about device to which credential is to be provisioned.
230 * @param[in] responseHandler callbak called by OC stack when request API receives response.
231 * @return OC_STACK_OK in case of success and other value otherwise.
233 static OCStackResult provisionCredentials(const OicSecCred_t *cred,
234 const OCProvisionDev_t *deviceInfo, CredentialData_t *credData,
235 OCClientResponseHandler responseHandler)
237 OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
240 OC_LOG(ERROR, TAG, "Failed to memory allocation");
241 return OC_STACK_NO_MEMORY;
243 secPayload->base.type = PAYLOAD_TYPE_SECURITY;
244 secPayload->securityData = BinToCredJSON(cred);
245 if(NULL == secPayload->securityData)
248 OC_LOG(ERROR, TAG, "Failed to BinToCredJSON");
249 return OC_STACK_NO_MEMORY;
252 OC_LOG_V(INFO, TAG, "Credential for provisioning : %s",secPayload->securityData);
253 char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
254 if(!PMGenerateQuery(true,
255 deviceInfo->endpoint.addr,
256 deviceInfo->securePort,
257 deviceInfo->connType,
258 query, sizeof(query), OIC_RSRC_CRED_URI))
260 OC_LOG(ERROR, TAG, "DeviceDiscoveryHandler : Failed to generate query");
261 return OC_STACK_ERROR;
263 OC_LOG_V(DEBUG, TAG, "Query=%s", query);
265 OCCallbackData cbData = {.context=NULL, .cb=NULL, .cd=NULL};
266 cbData.cb = responseHandler;
267 cbData.context = (void *) credData;
270 OCDoHandle handle = NULL;
271 OCMethod method = OC_REST_POST;
272 OCStackResult ret = OCDoResource(&handle, method, query, 0, (OCPayload*)secPayload,
273 deviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0);
274 OC_LOG_V(INFO, TAG, "OCDoResource::Credential provisioning returned : %d",ret);
275 if (ret != OC_STACK_OK)
277 OC_LOG(ERROR, TAG, "OCStack resource error");
283 OCStackResult SRPProvisionCredentials(void *ctx, OicSecCredType_t type, size_t keySize,
284 const OCProvisionDev_t *pDev1,
285 const OCProvisionDev_t *pDev2,
286 OCProvisionResultCB resultCallback)
288 VERIFY_NON_NULL(TAG, pDev1, ERROR, OC_STACK_INVALID_PARAM);
289 VERIFY_NON_NULL(TAG, pDev2, ERROR, OC_STACK_INVALID_PARAM);
290 VERIFY_NON_NULL(TAG, resultCallback, ERROR, OC_STACK_INVALID_CALLBACK);
292 if (!(keySize == OWNER_PSK_LENGTH_128 || keySize == OWNER_PSK_LENGTH_256))
294 OC_LOG(INFO, TAG, "Invalid key size");
295 return OC_STACK_INVALID_PARAM;
298 OC_LOG(INFO, TAG, "In SRPProvisionCredentials");
300 OicUuid_t provTooldeviceID = {{0,}};
301 if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID))
303 OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
304 return OC_STACK_ERROR;
306 OC_LOG(INFO, TAG, "retrieved deviceid");
309 case SYMMETRIC_PAIR_WISE_KEY:
311 const OCProvisionDev_t *firstDevice = pDev1;
312 const OCProvisionDev_t *secondDevice = pDev2;
314 OicSecCred_t *firstCred = NULL;
315 OicSecCred_t *secondCred = NULL;
316 OCStackResult res = PMGeneratePairWiseCredentials(type, keySize, &provTooldeviceID,
317 &firstDevice->doxm->deviceID, &secondDevice->doxm->deviceID,
318 &firstCred, &secondCred);
319 VERIFY_SUCCESS(TAG, (res==OC_STACK_OK), ERROR, OC_STACK_ERROR);
320 OC_LOG(INFO, TAG, "Credentials generated successfully");
321 CredentialData_t *credData = (CredentialData_t *) OICMalloc(sizeof(CredentialData_t));
322 if (NULL == credData)
324 OC_LOG(ERROR, TAG, "Memory allocation problem");
325 return OC_STACK_NO_MEMORY;
327 memset(credData, 0x00, sizeof(CredentialData_t));
328 credData->deviceInfo1 = firstDevice;
329 credData->deviceInfo2 = secondDevice;
330 credData->credInfo = secondCred;
332 credData->credInfoFirst = firstCred;
333 credData->numOfResults = 0;
334 credData->resultCallback = resultCallback;
335 // first call to provision creds to device1.
336 // second call to provision creds to device2.
339 (OCProvisionResult_t*)OICMalloc(sizeof(OCProvisionResult_t) * noOfRiCalls);
340 if (NULL == credData->resArr)
342 OC_LOG(ERROR, TAG, "Memory allocation problem");
343 return OC_STACK_NO_MEMORY;
345 memset(credData->resArr, 0x00, sizeof(sizeof(OCProvisionResult_t)*noOfRiCalls));
346 res = provisionCredentials(firstCred, firstDevice, credData, &provisionCredentialCB1);
347 if (OC_STACK_OK != res)
349 DeleteCredList(firstCred);
350 DeleteCredList(secondCred);
351 OICFree(credData->resArr);
354 OC_LOG_V(INFO, TAG, "provisionCredentials returned: %d",res);
355 VERIFY_SUCCESS(TAG, (res==OC_STACK_OK), ERROR, OC_STACK_ERROR);
360 OC_LOG(ERROR, TAG, "Invalid option.");
361 return OC_STACK_INVALID_PARAM;
364 return OC_STACK_ERROR;
368 * Internal Function to store results in result array during ACL provisioning.
370 static void registerResultForACLProvisioning(ACLData_t *aclData,
371 OCStackResult stackresult)
373 OC_LOG_V(INFO, TAG, "Inside registerResultForACLProvisioning aclData->numOfResults is %d\n",
374 aclData->numOfResults);
375 memcpy(aclData->resArr[(aclData->numOfResults)].deviceId.id,
376 aclData->deviceInfo->doxm->deviceID.id, UUID_LENGTH);
377 aclData->resArr[(aclData->numOfResults)].res = stackresult;
378 ++(aclData->numOfResults);
382 * Callback handler of SRPProvisionACL.
384 * @param[in] ctx ctx value passed to callback from calling function.
385 * @param[in] UNUSED handle to an invocation
386 * @param[in] clientResponse Response from queries to remote servers.
387 * @return OC_STACK_DELETE_TRANSACTION to delete the transaction
388 * and OC_STACK_KEEP_TRANSACTION to keep it.
390 static OCStackApplicationResult SRPProvisionACLCB(void *ctx, OCDoHandle UNUSED,
391 OCClientResponse *clientResponse)
393 OC_LOG_V(INFO, TAG, "Inside SRPProvisionACLCB.");
395 VERIFY_NON_NULL(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
396 ACLData_t *aclData = (ACLData_t*)ctx;
397 OCProvisionResultCB resultCallback = aclData->resultCallback;
401 if(OC_STACK_RESOURCE_CREATED == clientResponse->result)
403 registerResultForACLProvisioning(aclData, OC_STACK_RESOURCE_CREATED);
404 ((OCProvisionResultCB)(resultCallback))(aclData->ctx, aclData->numOfResults,
407 OICFree(aclData->resArr);
409 return OC_STACK_DELETE_TRANSACTION;
412 registerResultForACLProvisioning(aclData, OC_STACK_ERROR);
413 ((OCProvisionResultCB)(resultCallback))(aclData->ctx, aclData->numOfResults,
416 OC_LOG_V(ERROR, TAG, "SRPProvisionACLCB received Null clientResponse");
417 OICFree(aclData->resArr);
419 return OC_STACK_DELETE_TRANSACTION;
422 OCStackResult SRPProvisionACL(void *ctx, const OCProvisionDev_t *selectedDeviceInfo,
423 OicSecAcl_t *acl, OCProvisionResultCB resultCallback)
425 VERIFY_NON_NULL(TAG, selectedDeviceInfo, ERROR, OC_STACK_INVALID_PARAM);
426 VERIFY_NON_NULL(TAG, acl, ERROR, OC_STACK_INVALID_PARAM);
427 VERIFY_NON_NULL(TAG, resultCallback, ERROR, OC_STACK_INVALID_CALLBACK);
429 OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
432 OC_LOG(ERROR, TAG, "Failed to memory allocation");
433 return OC_STACK_NO_MEMORY;
435 secPayload->base.type = PAYLOAD_TYPE_SECURITY;
436 secPayload->securityData = BinToAclJSON(acl);
437 if(NULL == secPayload->securityData)
440 OC_LOG(ERROR, TAG, "Failed to BinToAclJSON");
441 return OC_STACK_NO_MEMORY;
443 OC_LOG_V(INFO, TAG, "ACL : %s", secPayload->securityData);
445 char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
446 if(!PMGenerateQuery(true,
447 selectedDeviceInfo->endpoint.addr,
448 selectedDeviceInfo->securePort,
449 selectedDeviceInfo->connType,
450 query, sizeof(query), OIC_RSRC_ACL_URI))
452 OC_LOG(ERROR, TAG, "DeviceDiscoveryHandler : Failed to generate query");
453 return OC_STACK_ERROR;
455 OC_LOG_V(DEBUG, TAG, "Query=%s", query);
457 OCCallbackData cbData = {.context=NULL, .cb=NULL, .cd=NULL};
458 cbData.cb = &SRPProvisionACLCB;
459 ACLData_t *aclData = (ACLData_t *) OICMalloc(sizeof(ACLData_t));
463 OC_LOG(ERROR, TAG, "Unable to allocate memory");
464 return OC_STACK_NO_MEMORY;
466 memset(aclData, 0x00, sizeof(ACLData_t));
467 aclData->deviceInfo = selectedDeviceInfo;
468 aclData->resultCallback = resultCallback;
469 aclData->numOfResults=0;
471 // call to provision ACL to device1.
473 aclData->resArr = (OCProvisionResult_t*)OICMalloc(sizeof(OCProvisionResult_t)*noOfRiCalls);
474 if (aclData->resArr == NULL)
477 OC_LOG(ERROR, TAG, "Unable to allocate memory");
478 return OC_STACK_NO_MEMORY;
480 memset(aclData->resArr, 0x00, sizeof(sizeof(OCProvisionResult_t)*noOfRiCalls));
481 cbData.context = (void *)aclData;
483 OCMethod method = OC_REST_POST;
484 OCDoHandle handle = NULL;
485 OC_LOG(DEBUG, TAG, "Sending ACL info to resource server");
486 OCStackResult ret = OCDoResource(&handle, method, query,
487 &selectedDeviceInfo->endpoint, (OCPayload*)secPayload,
488 selectedDeviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0);
489 if (ret != OC_STACK_OK)
491 OICFree(aclData->resArr);
494 VERIFY_SUCCESS(TAG, (OC_STACK_OK == ret), ERROR, OC_STACK_ERROR);