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;
131 OCProvisionResultCB resultCallback = credData->resultCallback;
132 OC_LOG(INFO, TAG, "provisionCredentialCB2 called");
135 if(OC_STACK_RESOURCE_CREATED == clientResponse->result)
137 registerResultForCredProvisioning(credData, OC_STACK_RESOURCE_CREATED, 2);
138 ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
141 OICFree(credData->resArr);
143 return OC_STACK_DELETE_TRANSACTION;
147 OC_LOG(INFO, TAG, "provisionCredentialCB2 received Null clientResponse");
148 registerResultForCredProvisioning(credData, OC_STACK_ERROR, 2);
149 ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
152 OICFree(credData->resArr);
154 return OC_STACK_DELETE_TRANSACTION;
158 * Callback handler for handling callback of provisioning device 1.
160 * @param[in] ctx ctx value passed to callback from calling function.
161 * @param[in] UNUSED handle to an invocation
162 * @param[in] clientResponse Response from queries to remote servers.
163 * @return OC_STACK_DELETE_TRANSACTION to delete the transaction
164 * and OC_STACK_KEEP_TRANSACTION to keep it.
166 static OCStackApplicationResult provisionCredentialCB1(void *ctx, OCDoHandle UNUSED,
167 OCClientResponse *clientResponse)
169 VERIFY_NON_NULL(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
170 CredentialData_t* credData = (CredentialData_t*) ctx;
171 OICFree(credData->credInfoFirst);
172 const OCProvisionDev_t *deviceInfo = credData->deviceInfo2;
173 OicSecCred_t *credInfo = credData->credInfo;
174 const OCProvisionResultCB resultCallback = credData->resultCallback;
177 if (OC_STACK_RESOURCE_CREATED == clientResponse->result)
179 // send credentials to second device
180 registerResultForCredProvisioning(credData, OC_STACK_RESOURCE_CREATED,1);
181 OCStackResult res = provisionCredentials(credInfo, deviceInfo, credData,
182 provisionCredentialCB2);
183 DeleteCredList(credInfo);
184 if (OC_STACK_OK != res)
186 registerResultForCredProvisioning(credData, res,2);
187 ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
190 OICFree(credData->resArr);
197 registerResultForCredProvisioning(credData, OC_STACK_ERROR,1);
198 ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
201 OICFree(credData->resArr);
208 OC_LOG(INFO, TAG, "provisionCredentialCB received Null clientResponse for first device");
209 registerResultForCredProvisioning(credData, OC_STACK_ERROR,1);
210 ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
213 DeleteCredList(credInfo);
214 OICFree(credData->resArr);
218 return OC_STACK_DELETE_TRANSACTION;
224 * Internal function for handling credential generation and sending credential to resource server.
226 * @param[in] cred Instance of cred resource.
227 * @param[in] deviceInfo information about device to which credential is to be provisioned.
228 * @param[in] responseHandler callbak called by OC stack when request API receives response.
229 * @return OC_STACK_OK in case of success and other value otherwise.
231 static OCStackResult provisionCredentials(const OicSecCred_t *cred,
232 const OCProvisionDev_t *deviceInfo, CredentialData_t *credData,
233 OCClientResponseHandler responseHandler)
235 OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
238 OC_LOG(ERROR, TAG, "Failed to memory allocation");
239 return OC_STACK_NO_MEMORY;
241 secPayload->base.type = PAYLOAD_TYPE_SECURITY;
242 secPayload->securityData = BinToCredJSON(cred);
243 if(NULL == secPayload->securityData)
246 OC_LOG(ERROR, TAG, "Failed to BinToCredJSON");
247 return OC_STACK_NO_MEMORY;
250 OC_LOG_V(INFO, TAG, "Credential for provisioning : %s",secPayload->securityData);
251 char uri[SRP_MAX_URI_LENGTH] = { 0 };
253 size_t uriLen = sizeof(uri);
254 snprintf(uri, uriLen - 1, COAPS_QUERY, deviceInfo->endpoint.addr, deviceInfo->securePort,
257 uri[uriLen - 1] = '\0';
258 OC_LOG_V(INFO, TAG, "URI for Credential provisioning : %s",uri);
259 OCCallbackData cbData = {.context=NULL, .cb=NULL, .cd=NULL};
260 cbData.cb = responseHandler;
261 cbData.context = (void *) credData;
264 OCDoHandle handle = NULL;
265 OCMethod method = OC_REST_POST;
266 // TODO replace CT_ADAPTER_IP with value from discovery
267 OCStackResult ret = OCDoResource(&handle, method, uri, 0, (OCPayload*)secPayload,
268 CT_ADAPTER_IP, OC_HIGH_QOS, &cbData, NULL, 0);
269 OC_LOG_V(INFO, TAG, "OCDoResource::Credential provisioning returned : %d",ret);
270 if (ret != OC_STACK_OK)
272 OC_LOG(ERROR, TAG, "OCStack resource error");
278 OCStackResult SRPProvisionCredentials(void *ctx, OicSecCredType_t type, size_t keySize,
279 const OCProvisionDev_t *pDev1,
280 const OCProvisionDev_t *pDev2,
281 OCProvisionResultCB resultCallback)
283 VERIFY_NON_NULL(TAG, pDev1, ERROR, OC_STACK_INVALID_PARAM);
284 VERIFY_NON_NULL(TAG, pDev2, ERROR, OC_STACK_INVALID_PARAM);
285 VERIFY_NON_NULL(TAG, resultCallback, ERROR, OC_STACK_INVALID_CALLBACK);
287 if (!(keySize == OWNER_PSK_LENGTH_128 || keySize == OWNER_PSK_LENGTH_256))
289 OC_LOG(INFO, TAG, "Invalid key size");
290 return OC_STACK_INVALID_PARAM;
293 OC_LOG(INFO, TAG, "In SRPProvisionCredentials");
295 OicUuid_t provTooldeviceID = {{0,}};
296 if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID))
298 OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
299 return OC_STACK_ERROR;
301 OC_LOG(INFO, TAG, "retrieved deviceid");
304 case SYMMETRIC_PAIR_WISE_KEY:
306 const OCProvisionDev_t *firstDevice = pDev1;
307 const OCProvisionDev_t *secondDevice = pDev2;
309 OicSecCred_t *firstCred = NULL;
310 OicSecCred_t *secondCred = NULL;
311 OCStackResult res = PMGeneratePairWiseCredentials(type, keySize, &provTooldeviceID,
312 &firstDevice->doxm->deviceID, &secondDevice->doxm->deviceID,
313 &firstCred, &secondCred);
314 VERIFY_SUCCESS(TAG, (res==OC_STACK_OK), ERROR, OC_STACK_ERROR);
315 OC_LOG(INFO, TAG, "Credentials generated successfully");
316 CredentialData_t *credData = (CredentialData_t *) OICMalloc(sizeof(CredentialData_t));
317 if (NULL == credData)
319 OC_LOG(ERROR, TAG, "Memory allocation problem");
320 return OC_STACK_NO_MEMORY;
322 memset(credData, 0x00, sizeof(CredentialData_t));
323 credData->deviceInfo1 = firstDevice;
324 credData->deviceInfo2 = secondDevice;
325 credData->credInfo = secondCred;
327 credData->credInfoFirst = firstCred;
328 credData->numOfResults = 0;
329 credData->resultCallback = resultCallback;
330 // first call to provision creds to device1.
331 // second call to provision creds to device2.
334 (OCProvisionResult_t*)OICMalloc(sizeof(OCProvisionResult_t) * noOfRiCalls);
335 if (NULL == credData->resArr)
337 OC_LOG(ERROR, TAG, "Memory allocation problem");
338 return OC_STACK_NO_MEMORY;
340 memset(credData->resArr, 0x00, sizeof(sizeof(OCProvisionResult_t)*noOfRiCalls));
341 res = provisionCredentials(firstCred, firstDevice, credData, &provisionCredentialCB1);
342 if (OC_STACK_OK != res)
344 DeleteCredList(firstCred);
345 DeleteCredList(secondCred);
346 OICFree(credData->resArr);
349 OC_LOG_V(INFO, TAG, "provisionCredentials returned: %d",res);
350 VERIFY_SUCCESS(TAG, (res==OC_STACK_OK), ERROR, OC_STACK_ERROR);
355 OC_LOG(ERROR, TAG, "Invalid option.");
356 return OC_STACK_INVALID_PARAM;
359 return OC_STACK_ERROR;
363 * Internal Function to store results in result array during ACL provisioning.
365 static void registerResultForACLProvisioning(ACLData_t *aclData,
366 OCStackResult stackresult)
368 OC_LOG_V(INFO, TAG, "Inside registerResultForACLProvisioning aclData->numOfResults is %d\n",
369 aclData->numOfResults);
370 memcpy(aclData->resArr[(aclData->numOfResults)].deviceId.id,
371 aclData->deviceInfo->doxm->deviceID.id, UUID_LENGTH);
372 aclData->resArr[(aclData->numOfResults)].res = stackresult;
373 ++(aclData->numOfResults);
377 * Callback handler of SRPProvisionACL.
379 * @param[in] ctx ctx value passed to callback from calling function.
380 * @param[in] UNUSED handle to an invocation
381 * @param[in] clientResponse Response from queries to remote servers.
382 * @return OC_STACK_DELETE_TRANSACTION to delete the transaction
383 * and OC_STACK_KEEP_TRANSACTION to keep it.
385 static OCStackApplicationResult SRPProvisionACLCB(void *ctx, OCDoHandle UNUSED,
386 OCClientResponse *clientResponse)
388 OC_LOG_V(INFO, TAG, "Inside SRPProvisionACLCB.");
389 VERIFY_NON_NULL(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
390 ACLData_t *aclData = (ACLData_t*)ctx;
391 OCProvisionResultCB resultCallback = aclData->resultCallback;
395 if(OC_STACK_RESOURCE_CREATED == clientResponse->result)
397 registerResultForACLProvisioning(aclData, OC_STACK_RESOURCE_CREATED);
398 ((OCProvisionResultCB)(resultCallback))(aclData->ctx, aclData->numOfResults,
401 OICFree(aclData->resArr);
403 return OC_STACK_DELETE_TRANSACTION;
406 registerResultForACLProvisioning(aclData, OC_STACK_ERROR);
407 ((OCProvisionResultCB)(resultCallback))(aclData->ctx, aclData->numOfResults,
410 OC_LOG_V(ERROR, TAG, "SRPProvisionACLCB received Null clientResponse");
411 OICFree(aclData->resArr);
413 return OC_STACK_DELETE_TRANSACTION;
416 OCStackResult SRPProvisionACL(void *ctx, const OCProvisionDev_t *selectedDeviceInfo,
417 OicSecAcl_t *acl, OCProvisionResultCB resultCallback)
419 VERIFY_NON_NULL(TAG, selectedDeviceInfo, ERROR, OC_STACK_INVALID_PARAM);
420 VERIFY_NON_NULL(TAG, acl, ERROR, OC_STACK_INVALID_PARAM);
421 VERIFY_NON_NULL(TAG, resultCallback, ERROR, OC_STACK_INVALID_CALLBACK);
423 OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
426 OC_LOG(ERROR, TAG, "Failed to memory allocation");
427 return OC_STACK_NO_MEMORY;
429 secPayload->base.type = PAYLOAD_TYPE_SECURITY;
430 secPayload->securityData = BinToAclJSON(acl);
431 if(NULL == secPayload->securityData)
434 OC_LOG(ERROR, TAG, "Failed to BinToAclJSON");
435 return OC_STACK_NO_MEMORY;
437 OC_LOG_V(INFO, TAG, "ACL : %s", secPayload->securityData);
439 char uri[SRP_MAX_URI_LENGTH] = {0};
440 size_t uriLen = sizeof(uri);
442 snprintf(uri, uriLen - 1, COAPS_QUERY, selectedDeviceInfo->endpoint.addr,
443 selectedDeviceInfo->securePort, OIC_RSRC_ACL_URI);
444 uri[uriLen - 1] = '\0';
446 OC_LOG_V(INFO, TAG, "URI : %s", uri);
447 OCCallbackData cbData = {.context=NULL, .cb=NULL, .cd=NULL};
448 cbData.cb = &SRPProvisionACLCB;
449 ACLData_t *aclData = (ACLData_t *) OICMalloc(sizeof(ACLData_t));
453 OC_LOG(ERROR, TAG, "Unable to allocate memory");
454 return OC_STACK_NO_MEMORY;
456 memset(aclData, 0x00, sizeof(ACLData_t));
457 aclData->deviceInfo = selectedDeviceInfo;
458 aclData->resultCallback = resultCallback;
459 aclData->numOfResults=0;
461 // call to provision ACL to device1.
463 aclData->resArr = (OCProvisionResult_t*)OICMalloc(sizeof(OCProvisionResult_t)*noOfRiCalls);
464 if (aclData->resArr == NULL)
467 OC_LOG(ERROR, TAG, "Unable to allocate memory");
468 return OC_STACK_NO_MEMORY;
470 memset(aclData->resArr, 0x00, sizeof(sizeof(OCProvisionResult_t)*noOfRiCalls));
471 cbData.context = (void *)aclData;
473 OCMethod method = OC_REST_POST;
474 OCDoHandle handle = NULL;
475 OC_LOG(DEBUG, TAG, "Sending ACL info to resource server");
476 // TODO replace CT_ADAPTER_IP with value from discovery
478 OCStackResult ret = OCDoResource(&handle, method, uri,
479 &selectedDeviceInfo->endpoint, (OCPayload*)secPayload,
480 CT_ADAPTER_IP, OC_HIGH_QOS, &cbData, NULL, 0);
481 if (ret != OC_STACK_OK)
483 OICFree(aclData->resArr);
486 VERIFY_SUCCESS(TAG, (OC_STACK_OK == ret), ERROR, OC_STACK_ERROR);