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 uri[SRP_MAX_URI_LENGTH] = { 0 };
255 size_t uriLen = sizeof(uri);
256 snprintf(uri, uriLen - 1, COAPS_QUERY, deviceInfo->endpoint.addr, deviceInfo->securePort,
259 uri[uriLen - 1] = '\0';
260 OC_LOG_V(INFO, TAG, "URI for Credential provisioning : %s",uri);
261 OCCallbackData cbData = {.context=NULL, .cb=NULL, .cd=NULL};
262 cbData.cb = responseHandler;
263 cbData.context = (void *) credData;
266 OCDoHandle handle = NULL;
267 OCMethod method = OC_REST_POST;
268 // TODO replace CT_ADAPTER_IP with value from discovery
269 OCStackResult ret = OCDoResource(&handle, method, uri, 0, (OCPayload*)secPayload,
270 CT_ADAPTER_IP, OC_HIGH_QOS, &cbData, NULL, 0);
271 OC_LOG_V(INFO, TAG, "OCDoResource::Credential provisioning returned : %d",ret);
272 if (ret != OC_STACK_OK)
274 OC_LOG(ERROR, TAG, "OCStack resource error");
280 OCStackResult SRPProvisionCredentials(void *ctx, OicSecCredType_t type, size_t keySize,
281 const OCProvisionDev_t *pDev1,
282 const OCProvisionDev_t *pDev2,
283 OCProvisionResultCB resultCallback)
285 VERIFY_NON_NULL(TAG, pDev1, ERROR, OC_STACK_INVALID_PARAM);
286 VERIFY_NON_NULL(TAG, pDev2, ERROR, OC_STACK_INVALID_PARAM);
287 VERIFY_NON_NULL(TAG, resultCallback, ERROR, OC_STACK_INVALID_CALLBACK);
289 if (!(keySize == OWNER_PSK_LENGTH_128 || keySize == OWNER_PSK_LENGTH_256))
291 OC_LOG(INFO, TAG, "Invalid key size");
292 return OC_STACK_INVALID_PARAM;
295 OC_LOG(INFO, TAG, "In SRPProvisionCredentials");
297 OicUuid_t provTooldeviceID = {{0,}};
298 if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID))
300 OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
301 return OC_STACK_ERROR;
303 OC_LOG(INFO, TAG, "retrieved deviceid");
306 case SYMMETRIC_PAIR_WISE_KEY:
308 const OCProvisionDev_t *firstDevice = pDev1;
309 const OCProvisionDev_t *secondDevice = pDev2;
311 OicSecCred_t *firstCred = NULL;
312 OicSecCred_t *secondCred = NULL;
313 OCStackResult res = PMGeneratePairWiseCredentials(type, keySize, &provTooldeviceID,
314 &firstDevice->doxm->deviceID, &secondDevice->doxm->deviceID,
315 &firstCred, &secondCred);
316 VERIFY_SUCCESS(TAG, (res==OC_STACK_OK), ERROR, OC_STACK_ERROR);
317 OC_LOG(INFO, TAG, "Credentials generated successfully");
318 CredentialData_t *credData = (CredentialData_t *) OICMalloc(sizeof(CredentialData_t));
319 if (NULL == credData)
321 OC_LOG(ERROR, TAG, "Memory allocation problem");
322 return OC_STACK_NO_MEMORY;
324 memset(credData, 0x00, sizeof(CredentialData_t));
325 credData->deviceInfo1 = firstDevice;
326 credData->deviceInfo2 = secondDevice;
327 credData->credInfo = secondCred;
329 credData->credInfoFirst = firstCred;
330 credData->numOfResults = 0;
331 credData->resultCallback = resultCallback;
332 // first call to provision creds to device1.
333 // second call to provision creds to device2.
336 (OCProvisionResult_t*)OICMalloc(sizeof(OCProvisionResult_t) * noOfRiCalls);
337 if (NULL == credData->resArr)
339 OC_LOG(ERROR, TAG, "Memory allocation problem");
340 return OC_STACK_NO_MEMORY;
342 memset(credData->resArr, 0x00, sizeof(sizeof(OCProvisionResult_t)*noOfRiCalls));
343 res = provisionCredentials(firstCred, firstDevice, credData, &provisionCredentialCB1);
344 if (OC_STACK_OK != res)
346 DeleteCredList(firstCred);
347 DeleteCredList(secondCred);
348 OICFree(credData->resArr);
351 OC_LOG_V(INFO, TAG, "provisionCredentials returned: %d",res);
352 VERIFY_SUCCESS(TAG, (res==OC_STACK_OK), ERROR, OC_STACK_ERROR);
357 OC_LOG(ERROR, TAG, "Invalid option.");
358 return OC_STACK_INVALID_PARAM;
361 return OC_STACK_ERROR;
365 * Internal Function to store results in result array during ACL provisioning.
367 static void registerResultForACLProvisioning(ACLData_t *aclData,
368 OCStackResult stackresult)
370 OC_LOG_V(INFO, TAG, "Inside registerResultForACLProvisioning aclData->numOfResults is %d\n",
371 aclData->numOfResults);
372 memcpy(aclData->resArr[(aclData->numOfResults)].deviceId.id,
373 aclData->deviceInfo->doxm->deviceID.id, UUID_LENGTH);
374 aclData->resArr[(aclData->numOfResults)].res = stackresult;
375 ++(aclData->numOfResults);
379 * Callback handler of SRPProvisionACL.
381 * @param[in] ctx ctx value passed to callback from calling function.
382 * @param[in] UNUSED handle to an invocation
383 * @param[in] clientResponse Response from queries to remote servers.
384 * @return OC_STACK_DELETE_TRANSACTION to delete the transaction
385 * and OC_STACK_KEEP_TRANSACTION to keep it.
387 static OCStackApplicationResult SRPProvisionACLCB(void *ctx, OCDoHandle UNUSED,
388 OCClientResponse *clientResponse)
390 OC_LOG_V(INFO, TAG, "Inside SRPProvisionACLCB.");
392 VERIFY_NON_NULL(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
393 ACLData_t *aclData = (ACLData_t*)ctx;
394 OCProvisionResultCB resultCallback = aclData->resultCallback;
398 if(OC_STACK_RESOURCE_CREATED == clientResponse->result)
400 registerResultForACLProvisioning(aclData, OC_STACK_RESOURCE_CREATED);
401 ((OCProvisionResultCB)(resultCallback))(aclData->ctx, aclData->numOfResults,
404 OICFree(aclData->resArr);
406 return OC_STACK_DELETE_TRANSACTION;
409 registerResultForACLProvisioning(aclData, OC_STACK_ERROR);
410 ((OCProvisionResultCB)(resultCallback))(aclData->ctx, aclData->numOfResults,
413 OC_LOG_V(ERROR, TAG, "SRPProvisionACLCB received Null clientResponse");
414 OICFree(aclData->resArr);
416 return OC_STACK_DELETE_TRANSACTION;
419 OCStackResult SRPProvisionACL(void *ctx, const OCProvisionDev_t *selectedDeviceInfo,
420 OicSecAcl_t *acl, OCProvisionResultCB resultCallback)
422 VERIFY_NON_NULL(TAG, selectedDeviceInfo, ERROR, OC_STACK_INVALID_PARAM);
423 VERIFY_NON_NULL(TAG, acl, ERROR, OC_STACK_INVALID_PARAM);
424 VERIFY_NON_NULL(TAG, resultCallback, ERROR, OC_STACK_INVALID_CALLBACK);
426 OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
429 OC_LOG(ERROR, TAG, "Failed to memory allocation");
430 return OC_STACK_NO_MEMORY;
432 secPayload->base.type = PAYLOAD_TYPE_SECURITY;
433 secPayload->securityData = BinToAclJSON(acl);
434 if(NULL == secPayload->securityData)
437 OC_LOG(ERROR, TAG, "Failed to BinToAclJSON");
438 return OC_STACK_NO_MEMORY;
440 OC_LOG_V(INFO, TAG, "ACL : %s", secPayload->securityData);
442 char uri[SRP_MAX_URI_LENGTH] = {0};
443 size_t uriLen = sizeof(uri);
445 snprintf(uri, uriLen - 1, COAPS_QUERY, selectedDeviceInfo->endpoint.addr,
446 selectedDeviceInfo->securePort, OIC_RSRC_ACL_URI);
447 uri[uriLen - 1] = '\0';
449 OC_LOG_V(INFO, TAG, "URI : %s", uri);
450 OCCallbackData cbData = {.context=NULL, .cb=NULL, .cd=NULL};
451 cbData.cb = &SRPProvisionACLCB;
452 ACLData_t *aclData = (ACLData_t *) OICMalloc(sizeof(ACLData_t));
456 OC_LOG(ERROR, TAG, "Unable to allocate memory");
457 return OC_STACK_NO_MEMORY;
459 memset(aclData, 0x00, sizeof(ACLData_t));
460 aclData->deviceInfo = selectedDeviceInfo;
461 aclData->resultCallback = resultCallback;
462 aclData->numOfResults=0;
464 // call to provision ACL to device1.
466 aclData->resArr = (OCProvisionResult_t*)OICMalloc(sizeof(OCProvisionResult_t)*noOfRiCalls);
467 if (aclData->resArr == NULL)
470 OC_LOG(ERROR, TAG, "Unable to allocate memory");
471 return OC_STACK_NO_MEMORY;
473 memset(aclData->resArr, 0x00, sizeof(sizeof(OCProvisionResult_t)*noOfRiCalls));
474 cbData.context = (void *)aclData;
476 OCMethod method = OC_REST_POST;
477 OCDoHandle handle = NULL;
478 OC_LOG(DEBUG, TAG, "Sending ACL info to resource server");
479 // TODO replace CT_ADAPTER_IP with value from discovery
481 OCStackResult ret = OCDoResource(&handle, method, uri,
482 &selectedDeviceInfo->endpoint, (OCPayload*)secPayload,
483 CT_ADAPTER_IP, OC_HIGH_QOS, &cbData, NULL, 0);
484 if (ret != OC_STACK_OK)
486 OICFree(aclData->resArr);
489 VERIFY_SUCCESS(TAG, (OC_STACK_OK == ret), ERROR, OC_STACK_ERROR);