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 "pconfresource.h"
35 #include "credentialgenerator.h"
36 #include "cainterface.h"
39 #include "pmutility.h"
40 #include "provisioningdatabasemanager.h"
45 #include "crlresource.h"
51 * Macro to verify argument is not equal to NULL.
52 * eg: VERIFY_NON_NULL(TAG, ptrData, ERROR,OC_STACK_ERROR);
54 #define VERIFY_NON_NULL(tag, arg, logLevel, retValue) { if (NULL == (arg)) \
55 { OIC_LOG((logLevel), tag, #arg " is NULL"); return retValue; } }
58 * Macro to verify success of operation.
59 * eg: VERIFY_SUCCESS(TAG, OC_STACK_OK == foo(), ERROR, OC_STACK_ERROR);
61 #define VERIFY_SUCCESS(tag, op, logLevel, retValue) { if (!(op)) \
62 {OIC_LOG((logLevel), tag, #op " failed!!"); return retValue;} }
65 * Structure to carry credential data to callback.
67 typedef struct CredentialData CredentialData_t;
70 void *ctx; /**< Pointer to user context.**/
71 const OCProvisionDev_t *deviceInfo1; /**< Pointer to OCProvisionDev_t.**/
72 const OCProvisionDev_t *deviceInfo2; /**< Pointer to OCProvisionDev_t.**/
73 OicSecCred_t *credInfo; /**< Pointer to OicSecCred_t.**/
74 OicSecCred_t *credInfoFirst; /**< Pointer to OicSecCred_t.**/
75 OCProvisionResultCB resultCallback; /**< Pointer to result callback.**/
76 OCProvisionResult_t *resArr; /**< Result array.**/
77 int numOfResults; /**< Number of results in result array.**/
81 * Structure to carry ACL provision API data to callback.
83 typedef struct ACLData ACLData_t;
86 void *ctx; /**< Pointer to user context.**/
87 const OCProvisionDev_t *deviceInfo; /**< Pointer to PMDevInfo_t.**/
88 OCProvisionResultCB resultCallback; /**< Pointer to result callback.**/
89 OCProvisionResult_t *resArr; /**< Result array.**/
90 int numOfResults; /**< Number of results in result array.**/
94 * Structure to carry PCONF provision API data to callback.
96 typedef struct PconfData PconfData_t;
99 void *ctx; /**< Pointer to user context.**/
100 const OCProvisionDev_t *deviceInfo; /**< Pointer to PMDevInfo_t.**/
101 OCProvisionResultCB resultCallback; /**< Pointer to result callback.**/
102 OCProvisionResult_t *resArr; /**< Result array.**/
103 int numOfResults; /**< Number of results in result array.**/
106 // Enum type index for unlink callback.
108 IDX_FIRST_DEVICE_RES = 0, // index for resulf of the first device
109 IDX_SECOND_DEVICE_RES, // index for result of the second device
110 IDX_DB_UPDATE_RES // index for result of updating provisioning database.
113 // Structure to carry unlink APIs data to callback.
114 typedef struct UnlinkData UnlinkData_t;
117 OCProvisionDev_t* unlinkDev; /**< Pointer to OCProvisionDev_t to be unlinked.**/
118 OCProvisionResult_t* unlinkRes; /**< Result array.**/
119 OCProvisionResultCB resultCallback; /**< Pointer to result callback.**/
120 int numOfResults; /**< Number of results in result array.**/
123 //Example of DELETE cred request -> coaps://0.0.0.0:5684/oic/sec/cred?sub=(BASE64 ENCODED UUID)
124 const char * SRP_FORM_DELETE_CREDENTIAL = "coaps://[%s]:%d%s?%s=%s";
126 // Structure to carry remove APIs data to callback.
127 typedef struct RemoveData RemoveData_t;
130 OCProvisionDev_t* revokeTargetDev; /**< Device which is going to be revoked..**/
131 OCProvisionDev_t* linkedDevList; /**< A list of devices which have invalid credential.**/
132 OCProvisionResult_t* removeRes; /**< Result array.**/
133 OCProvisionResultCB resultCallback; /**< Pointer to result callback.**/
134 size_t numOfResults; /**< Number of results in result array.**/
135 size_t sizeOfResArray;
142 static OCStackResult provisionCredentials(const OicSecCred_t *cred,
143 const OCProvisionDev_t *deviceInfo, CredentialData_t *credData,
144 OCClientResponseHandler responseHandler);
148 * Internal function to update result in result array.
150 static void registerResultForCredProvisioning(CredentialData_t *credData,
151 OCStackResult stackresult, int cause)
154 OIC_LOG_V(INFO,TAG,"value of credData->numOfResults is %d",credData->numOfResults);
157 memcpy(credData->resArr[(credData->numOfResults)].deviceId.id,
158 credData->deviceInfo1->doxm->deviceID.id,UUID_LENGTH);
162 memcpy(credData->resArr[(credData->numOfResults)].deviceId.id,
163 credData->deviceInfo2->doxm->deviceID.id,UUID_LENGTH);
165 credData->resArr[(credData->numOfResults)].res = stackresult;
166 ++(credData->numOfResults);
170 * Callback handler for handling callback of provisioning device 2.
172 * @param[in] ctx ctx value passed to callback from calling function.
173 * @param[in] UNUSED handle to an invocation
174 * @param[in] clientResponse Response from queries to remote servers.
175 * @return OC_STACK_DELETE_TRANSACTION to delete the transaction
176 * and OC_STACK_KEEP_TRANSACTION to keep it.
178 static OCStackApplicationResult provisionCredentialCB2(void *ctx, OCDoHandle UNUSED,
179 OCClientResponse *clientResponse)
181 VERIFY_NON_NULL(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
182 CredentialData_t *credData = (CredentialData_t *) ctx;
185 OCProvisionResultCB resultCallback = credData->resultCallback;
186 OIC_LOG(INFO, TAG, "provisionCredentialCB2 called");
189 if(OC_STACK_RESOURCE_CREATED == clientResponse->result)
191 registerResultForCredProvisioning(credData, OC_STACK_RESOURCE_CREATED, 2);
192 OCStackResult res = PDMLinkDevices(&credData->deviceInfo1->doxm->deviceID,
193 &credData->deviceInfo2->doxm->deviceID);
194 if (OC_STACK_OK != res)
196 OIC_LOG(ERROR, TAG, "Error occured on PDMLinkDevices");
197 return OC_STACK_DELETE_TRANSACTION;
199 OIC_LOG(INFO, TAG, "Link created successfully");
201 ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
204 OICFree(credData->resArr);
206 return OC_STACK_DELETE_TRANSACTION;
210 OIC_LOG(INFO, TAG, "provisionCredentialCB2 received Null clientResponse");
211 registerResultForCredProvisioning(credData, OC_STACK_ERROR, 2);
212 ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
215 OICFree(credData->resArr);
217 return OC_STACK_DELETE_TRANSACTION;
221 * Callback handler for handling callback of provisioning device 1.
223 * @param[in] ctx ctx value passed to callback from calling function.
224 * @param[in] UNUSED handle to an invocation
225 * @param[in] clientResponse Response from queries to remote servers.
226 * @return OC_STACK_DELETE_TRANSACTION to delete the transaction
227 * and OC_STACK_KEEP_TRANSACTION to keep it.
229 static OCStackApplicationResult provisionCredentialCB1(void *ctx, OCDoHandle UNUSED,
230 OCClientResponse *clientResponse)
232 VERIFY_NON_NULL(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
234 CredentialData_t* credData = (CredentialData_t*) ctx;
235 OICFree(credData->credInfoFirst);
236 const OCProvisionDev_t *deviceInfo = credData->deviceInfo2;
237 OicSecCred_t *credInfo = credData->credInfo;
238 const OCProvisionResultCB resultCallback = credData->resultCallback;
241 if (OC_STACK_RESOURCE_CREATED == clientResponse->result)
243 // send credentials to second device
244 registerResultForCredProvisioning(credData, OC_STACK_RESOURCE_CREATED,1);
245 OCStackResult res = provisionCredentials(credInfo, deviceInfo, credData,
246 provisionCredentialCB2);
247 DeleteCredList(credInfo);
248 if (OC_STACK_OK != res)
250 registerResultForCredProvisioning(credData, res,2);
251 ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
254 OICFree(credData->resArr);
261 registerResultForCredProvisioning(credData, OC_STACK_ERROR,1);
262 ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
265 OICFree(credData->resArr);
272 OIC_LOG(INFO, TAG, "provisionCredentialCB received Null clientResponse for first device");
273 registerResultForCredProvisioning(credData, OC_STACK_ERROR,1);
274 ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
277 DeleteCredList(credInfo);
278 OICFree(credData->resArr);
282 return OC_STACK_DELETE_TRANSACTION;
288 * Internal function for handling credential generation and sending credential to resource server.
290 * @param[in] cred Instance of cred resource.
291 * @param[in] deviceInfo information about device to which credential is to be provisioned.
292 * @param[in] responseHandler callbak called by OC stack when request API receives response.
293 * @return OC_STACK_OK in case of success and other value otherwise.
295 static OCStackResult provisionCredentials(const OicSecCred_t *cred,
296 const OCProvisionDev_t *deviceInfo, CredentialData_t *credData,
297 OCClientResponseHandler responseHandler)
299 OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
302 OIC_LOG(ERROR, TAG, "Failed to memory allocation");
303 return OC_STACK_NO_MEMORY;
305 secPayload->base.type = PAYLOAD_TYPE_SECURITY;
306 secPayload->securityData = BinToCredJSON(cred);
307 if(NULL == secPayload->securityData)
310 OIC_LOG(ERROR, TAG, "Failed to BinToCredJSON");
311 return OC_STACK_NO_MEMORY;
314 OIC_LOG_V(INFO, TAG, "Credential for provisioning : %s",secPayload->securityData);
315 char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
316 if(!PMGenerateQuery(true,
317 deviceInfo->endpoint.addr,
318 deviceInfo->securePort,
319 deviceInfo->connType,
320 query, sizeof(query), OIC_RSRC_CRED_URI))
322 OIC_LOG(ERROR, TAG, "DeviceDiscoveryHandler : Failed to generate query");
323 return OC_STACK_ERROR;
325 OIC_LOG_V(DEBUG, TAG, "Query=%s", query);
327 OCCallbackData cbData = {.context=NULL, .cb=NULL, .cd=NULL};
328 cbData.cb = responseHandler;
329 cbData.context = (void *) credData;
332 OCDoHandle handle = NULL;
333 OCMethod method = OC_REST_POST;
334 OCStackResult ret = OCDoResource(&handle, method, query, 0, (OCPayload*)secPayload,
335 deviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0);
336 OIC_LOG_V(INFO, TAG, "OCDoResource::Credential provisioning returned : %d",ret);
337 if (ret != OC_STACK_OK)
339 OIC_LOG(ERROR, TAG, "OCStack resource error");
347 * Structure to carry certificate data to callback.
349 typedef struct CertificateData CertData_t;
350 struct CertificateData
352 void *ctx; /**< Pointer to user context.**/
353 const OCProvisionDev_t *deviceInfo; /**< Pointer to OCProvisionDev_t.**/
354 OicSecCred_t *credInfo; /**< Pointer to OicSecCred_t.**/
355 OCProvisionResultCB resultCallback; /**< Pointer to result callback.**/
356 OCProvisionResult_t *resArr; /**< Result array.**/
357 int numOfResults; /**< Number of results in result array.**/
361 * Structure to carry CRL provision API data to callback.
363 typedef struct CRLData CRLData_t;
366 void *ctx; /**< Pointer to user context.**/
367 const OCProvisionDev_t *deviceInfo; /**< Pointer to PMDevInfo_t.**/
368 OCProvisionResultCB resultCallback; /**< Pointer to result callback.**/
369 OCProvisionResult_t *resArr; /**< Result array.**/
370 int numOfResults; /**< Number of results in result array.**/
374 * Internal function to update result in result array.
376 static void registerResultForCertProvisioning(CertData_t *certData,
377 OCStackResult stackresult)
380 OIC_LOG_V(INFO,TAG,"value of credData->numOfResults is %d",certData->numOfResults);
381 memcpy(certData->resArr[(certData->numOfResults)].deviceId.id,
382 certData->deviceInfo->doxm->deviceID.id,UUID_LENGTH);
383 certData->resArr[(certData->numOfResults)].res = stackresult;
384 ++(certData->numOfResults);
388 * Internal Function to store results in result array during ACL provisioning.
390 static void registerResultForCRLProvisioning(CRLData_t *crlData,
391 OCStackResult stackresult)
393 OIC_LOG_V(INFO, TAG, "Inside registerResultForCRLProvisioning crlData->numOfResults is %d\n",
394 crlData->numOfResults);
395 memcpy(crlData->resArr[(crlData->numOfResults)].deviceId.id,
396 crlData->deviceInfo->doxm->deviceID.id, UUID_LENGTH);
397 crlData->resArr[(crlData->numOfResults)].res = stackresult;
398 ++(crlData->numOfResults);
403 * Callback handler of SRPProvisionCRL.
405 * @param[in] ctx ctx value passed to callback from calling function.
406 * @param[in] UNUSED handle to an invocation
407 * @param[in] clientResponse Response from queries to remote servers.
408 * @return OC_STACK_DELETE_TRANSACTION to delete the transaction
409 * and OC_STACK_KEEP_TRANSACTION to keep it.
411 static OCStackApplicationResult SRPProvisionCRLCB(void *ctx, OCDoHandle UNUSED,
412 OCClientResponse *clientResponse)
414 OIC_LOG_V(INFO, TAG, "Inside SRPProvisionCRLCB.");
416 VERIFY_NON_NULL(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
417 CRLData_t *crlData = (CRLData_t*)ctx;
418 OCProvisionResultCB resultCallback = crlData->resultCallback;
422 if(OC_STACK_RESOURCE_CREATED == clientResponse->result)
424 registerResultForCRLProvisioning(crlData, OC_STACK_RESOURCE_CREATED);
425 ((OCProvisionResultCB)(resultCallback))(crlData->ctx, crlData->numOfResults,
428 OICFree(crlData->resArr);
430 return OC_STACK_DELETE_TRANSACTION;
433 registerResultForCRLProvisioning(crlData, OC_STACK_ERROR);
434 ((OCProvisionResultCB)(resultCallback))(crlData->ctx, crlData->numOfResults,
437 OIC_LOG_V(ERROR, TAG, "SRPProvisionCRLCB received Null clientResponse");
438 OICFree(crlData->resArr);
440 return OC_STACK_DELETE_TRANSACTION;
443 OCStackResult SRPProvisionCRL(void *ctx, const OCProvisionDev_t *selectedDeviceInfo,
444 OicSecCrl_t *crl, OCProvisionResultCB resultCallback)
446 VERIFY_NON_NULL(TAG, selectedDeviceInfo, ERROR, OC_STACK_INVALID_PARAM);
447 VERIFY_NON_NULL(TAG, crl, ERROR, OC_STACK_INVALID_PARAM);
448 VERIFY_NON_NULL(TAG, resultCallback, ERROR, OC_STACK_INVALID_CALLBACK);
450 OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
453 OIC_LOG(ERROR, TAG, "Failed to memory allocation");
454 return OC_STACK_NO_MEMORY;
457 secPayload->base.type = PAYLOAD_TYPE_SECURITY;
458 secPayload->securityData = BinToCrlJSON(crl);
459 if (NULL == secPayload->securityData)
462 OIC_LOG(ERROR, TAG, "Failed to BinToCrlJSON");
463 return OC_STACK_NO_MEMORY;
465 OIC_LOG_V(INFO, TAG, "CRL : %s", secPayload->securityData);
467 char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
468 if(!PMGenerateQuery(true,
469 selectedDeviceInfo->endpoint.addr,
470 selectedDeviceInfo->securePort,
471 selectedDeviceInfo->connType,
472 query, sizeof(query), OIC_RSRC_CRL_URI))
474 OIC_LOG(ERROR, TAG, "DeviceDiscoveryHandler : Failed to generate query");
475 OICFree(secPayload->securityData);
477 return OC_STACK_ERROR;
479 OIC_LOG_V(DEBUG, TAG, "Query=%s", query);
481 OCCallbackData cbData = {.context=NULL, .cb=NULL, .cd=NULL};
482 cbData.cb = &SRPProvisionCRLCB;
483 CRLData_t *crlData = (CRLData_t *) OICCalloc(1, sizeof(CRLData_t));
486 OICFree(secPayload->securityData);
488 OIC_LOG(ERROR, TAG, "Unable to allocate memory");
489 return OC_STACK_NO_MEMORY;
492 crlData->deviceInfo = selectedDeviceInfo;
493 crlData->resultCallback = resultCallback;
494 crlData->numOfResults=0;
497 crlData->resArr = (OCProvisionResult_t*)OICCalloc(1, sizeof(OCProvisionResult_t));
498 if (crlData->resArr == NULL)
500 OICFree(secPayload->securityData);
502 OIC_LOG(ERROR, TAG, "Unable to allocate memory");
503 return OC_STACK_NO_MEMORY;
506 cbData.context = (void *)crlData;
508 OCMethod method = OC_REST_POST;
509 OCDoHandle handle = NULL;
510 OIC_LOG(DEBUG, TAG, "Sending CRL info to resource server");
512 OCStackResult ret = OCDoResource(&handle, method, query,
513 &selectedDeviceInfo->endpoint, (OCPayload*)secPayload,
514 selectedDeviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0);
516 if (ret != OC_STACK_OK)
518 OICFree(crlData->resArr);
526 * Internal function for handling credential generation and sending cretificate credential.
528 * @param[in] cred Instance of cred resource.
529 * @param[in] deviceInfo information about device to which credential is to be provisioned.
530 * @param[in] responseHandler callbak called by OC stack when request API receives response.
531 * @return OC_STACK_OK in case of success and other value otherwise.
533 static OCStackResult provisionCertCred(const OicSecCred_t *cred,
534 const OCProvisionDev_t *deviceInfo, CertData_t *certData,
535 OCClientResponseHandler responseHandler)
537 OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
540 OIC_LOG(ERROR, TAG, "Failed to memory allocation");
541 return OC_STACK_NO_MEMORY;
543 secPayload->base.type = PAYLOAD_TYPE_SECURITY;
544 secPayload->securityData = BinToCredJSON(cred);
546 if (NULL == secPayload->securityData)
549 OIC_LOG(ERROR, TAG, "Failed to BinToCredJSON");
550 return OC_STACK_NO_MEMORY;
553 OIC_LOG_V(INFO, TAG, "Credential for provisioning : %s",secPayload->securityData);
554 char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
555 if(!PMGenerateQuery(true,
556 deviceInfo->endpoint.addr,
557 deviceInfo->securePort,
558 deviceInfo->connType,
559 query, sizeof(query), OIC_RSRC_CRED_URI))
561 OIC_LOG(ERROR, TAG, "DeviceDiscoveryHandler : Failed to generate query");
562 OICFree(secPayload->securityData);
564 return OC_STACK_ERROR;
566 OIC_LOG_V(DEBUG, TAG, "Query=%s", query);
568 OCCallbackData cbData = {.context=NULL, .cb=NULL, .cd=NULL};
569 cbData.cb = responseHandler;
570 cbData.context = (void *) certData;
573 OCDoHandle handle = NULL;
574 OCMethod method = OC_REST_POST;
575 OCStackResult ret = OCDoResource(&handle, method, query, 0, (OCPayload*)secPayload,
576 deviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0);
577 OIC_LOG_V(INFO, TAG, "OCDoResource::Certificate provisioning returned : %d",ret);
578 if (ret != OC_STACK_OK)
580 OIC_LOG(ERROR, TAG, "OCStack resource error");
587 * Callback handler for handling callback of certificate provisioning device.
589 * @param[in] ctx ctx value passed to callback from calling function.
590 * @param[in] UNUSED handle to an invocation
591 * @param[in] clientResponse Response from queries to remote servers.
592 * @return OC_STACK_DELETE_TRANSACTION to delete the transaction
593 * and OC_STACK_KEEP_TRANSACTION to keep it.
595 static OCStackApplicationResult provisionCertCB(void *ctx, OCDoHandle UNUSED,
596 OCClientResponse *clientResponse)
598 VERIFY_NON_NULL(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
599 CertData_t *certData = (CertData_t *) ctx;
602 OCProvisionResultCB resultCallback = certData->resultCallback;
603 OIC_LOG(INFO, TAG, "provisionCertCred called");
606 if(OC_STACK_RESOURCE_CREATED == clientResponse->result)
608 registerResultForCertProvisioning(certData, OC_STACK_RESOURCE_CREATED);
609 ((OCProvisionResultCB)(resultCallback))(certData->ctx, certData->numOfResults,
612 OICFree(certData->resArr);
614 return OC_STACK_DELETE_TRANSACTION;
618 OIC_LOG(INFO, TAG, "provisionCertCredCB received Null clientResponse");
619 registerResultForCertProvisioning(certData, OC_STACK_ERROR);
620 ((OCProvisionResultCB)(resultCallback))(certData->ctx, certData->numOfResults,
623 OICFree(certData->resArr);
625 return OC_STACK_DELETE_TRANSACTION;
627 #endif // __WITH_X509__
629 OCStackResult SRPProvisionCredentials(void *ctx, OicSecCredType_t type, size_t keySize,
630 const OCProvisionDev_t *pDev1,
631 const OCProvisionDev_t *pDev2,
632 OCProvisionResultCB resultCallback)
634 VERIFY_NON_NULL(TAG, pDev1, ERROR, OC_STACK_INVALID_PARAM);
635 if (SYMMETRIC_PAIR_WISE_KEY == type)
637 VERIFY_NON_NULL(TAG, pDev2, ERROR, OC_STACK_INVALID_PARAM);
639 VERIFY_NON_NULL(TAG, resultCallback, ERROR, OC_STACK_INVALID_CALLBACK);
641 if (SYMMETRIC_PAIR_WISE_KEY == type &&
642 !(OWNER_PSK_LENGTH_128 == keySize || OWNER_PSK_LENGTH_256 == keySize))
644 OIC_LOG(INFO, TAG, "Invalid key size");
645 return OC_STACK_INVALID_PARAM;
648 OIC_LOG(INFO, TAG, "In SRPProvisionCredentials");
650 if (SYMMETRIC_PAIR_WISE_KEY == type)
652 bool linkExisits = true;
653 OCStackResult res = PDMIsLinkExists(&pDev1->doxm->deviceID, &pDev2->doxm->deviceID, &linkExisits);
655 if (res != OC_STACK_OK)
657 OIC_LOG(ERROR, TAG, "Internal error occured");
662 OIC_LOG(ERROR, TAG, "Link already exists");
663 return OC_STACK_INVALID_PARAM;
667 OicUuid_t provTooldeviceID = {{0,}};
668 if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID))
670 OIC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
671 return OC_STACK_ERROR;
673 OIC_LOG(INFO, TAG, "retrieved deviceid");
676 case SYMMETRIC_PAIR_WISE_KEY:
678 const OCProvisionDev_t *firstDevice = pDev1;
679 const OCProvisionDev_t *secondDevice = pDev2;
681 OicSecCred_t *firstCred = NULL;
682 OicSecCred_t *secondCred = NULL;
683 OCStackResult res = PMGeneratePairWiseCredentials(type, keySize, &provTooldeviceID,
684 &firstDevice->doxm->deviceID, &secondDevice->doxm->deviceID,
685 &firstCred, &secondCred);
686 VERIFY_SUCCESS(TAG, (res==OC_STACK_OK), ERROR, OC_STACK_ERROR);
687 OIC_LOG(INFO, TAG, "Credentials generated successfully");
688 CredentialData_t *credData =
689 (CredentialData_t *) OICCalloc(1, sizeof(CredentialData_t));
690 if (NULL == credData)
694 OIC_LOG(ERROR, TAG, "Memory allocation problem");
695 return OC_STACK_NO_MEMORY;
697 credData->deviceInfo1 = firstDevice;
698 credData->deviceInfo2 = secondDevice;
699 credData->credInfo = secondCred;
701 credData->credInfoFirst = firstCred;
702 credData->numOfResults = 0;
703 credData->resultCallback = resultCallback;
704 // first call to provision creds to device1.
705 // second call to provision creds to device2.
708 (OCProvisionResult_t*)OICCalloc(noOfRiCalls, sizeof(OCProvisionResult_t));
709 if (NULL == credData->resArr)
714 OIC_LOG(ERROR, TAG, "Memory allocation problem");
715 return OC_STACK_NO_MEMORY;
717 res = provisionCredentials(firstCred, firstDevice, credData, &provisionCredentialCB1);
718 if (OC_STACK_OK != res)
720 DeleteCredList(firstCred);
721 DeleteCredList(secondCred);
722 OICFree(credData->resArr);
725 OIC_LOG_V(INFO, TAG, "provisionCredentials returned: %d",res);
726 VERIFY_SUCCESS(TAG, (res==OC_STACK_OK), ERROR, OC_STACK_ERROR);
730 case SIGNED_ASYMMETRIC_KEY:
732 const OCProvisionDev_t *firstDevice = pDev1;
733 OicSecCred_t *cred = NULL;
734 OCStackResult res = PMGenerateCertificateCredentials(&provTooldeviceID,
735 &firstDevice->doxm->deviceID,&cred);
736 VERIFY_SUCCESS(TAG, (res==OC_STACK_OK), ERROR, OC_STACK_ERROR);
737 OIC_LOG(INFO, TAG, "Certificate credentials generated successfully");
738 CertData_t *certData = (CertData_t *) OICCalloc(1, sizeof(CertData_t));
739 if (NULL == certData)
742 OIC_LOG(ERROR, TAG, "Memory allocation problem");
743 return OC_STACK_NO_MEMORY;
746 certData->deviceInfo = firstDevice;
748 certData->credInfo = cred;
749 certData->numOfResults = 0;
750 certData->resultCallback = resultCallback;
752 certData->resArr = (OCProvisionResult_t*)OICCalloc(1, sizeof(OCProvisionResult_t));
753 if (NULL == certData->resArr)
755 DeleteCredList(cred);
757 OIC_LOG(ERROR, TAG, "Memory allocation problem");
758 return OC_STACK_NO_MEMORY;
761 res = provisionCertCred(cred, firstDevice, certData, &provisionCertCB);
762 if (OC_STACK_OK != res)
764 OICFree(certData->resArr);
767 DeleteCredList(cred);
768 OIC_LOG_V(INFO, TAG, "provisionCertCredentials returned: %d",res);
775 OIC_LOG(ERROR, TAG, "Invalid option.");
776 return OC_STACK_INVALID_PARAM;
779 return OC_STACK_ERROR;
783 * Internal Function to store results in result array during ACL provisioning.
785 static void registerResultForACLProvisioning(ACLData_t *aclData,
786 OCStackResult stackresult)
788 OIC_LOG_V(INFO, TAG, "Inside registerResultForACLProvisioning aclData->numOfResults is %d\n",
789 aclData->numOfResults);
790 memcpy(aclData->resArr[(aclData->numOfResults)].deviceId.id,
791 aclData->deviceInfo->doxm->deviceID.id, UUID_LENGTH);
792 aclData->resArr[(aclData->numOfResults)].res = stackresult;
793 ++(aclData->numOfResults);
797 * Callback handler of SRPProvisionACL.
799 * @param[in] ctx ctx value passed to callback from calling function.
800 * @param[in] UNUSED handle to an invocation
801 * @param[in] clientResponse Response from queries to remote servers.
802 * @return OC_STACK_DELETE_TRANSACTION to delete the transaction
803 * and OC_STACK_KEEP_TRANSACTION to keep it.
805 static OCStackApplicationResult SRPProvisionACLCB(void *ctx, OCDoHandle UNUSED,
806 OCClientResponse *clientResponse)
808 OIC_LOG_V(INFO, TAG, "Inside SRPProvisionACLCB.");
810 VERIFY_NON_NULL(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
811 ACLData_t *aclData = (ACLData_t*)ctx;
812 OCProvisionResultCB resultCallback = aclData->resultCallback;
816 if(OC_STACK_RESOURCE_CREATED == clientResponse->result)
818 registerResultForACLProvisioning(aclData, OC_STACK_RESOURCE_CREATED);
819 ((OCProvisionResultCB)(resultCallback))(aclData->ctx, aclData->numOfResults,
822 OICFree(aclData->resArr);
824 return OC_STACK_DELETE_TRANSACTION;
827 registerResultForACLProvisioning(aclData, OC_STACK_ERROR);
828 ((OCProvisionResultCB)(resultCallback))(aclData->ctx, aclData->numOfResults,
831 OIC_LOG_V(ERROR, TAG, "SRPProvisionACLCB received Null clientResponse");
832 OICFree(aclData->resArr);
834 return OC_STACK_DELETE_TRANSACTION;
837 OCStackResult SRPProvisionACL(void *ctx, const OCProvisionDev_t *selectedDeviceInfo,
838 OicSecAcl_t *acl, OCProvisionResultCB resultCallback)
840 VERIFY_NON_NULL(TAG, selectedDeviceInfo, ERROR, OC_STACK_INVALID_PARAM);
841 VERIFY_NON_NULL(TAG, acl, ERROR, OC_STACK_INVALID_PARAM);
842 VERIFY_NON_NULL(TAG, resultCallback, ERROR, OC_STACK_INVALID_CALLBACK);
844 OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
847 OIC_LOG(ERROR, TAG, "Failed to memory allocation");
848 return OC_STACK_NO_MEMORY;
850 secPayload->base.type = PAYLOAD_TYPE_SECURITY;
851 secPayload->securityData = BinToAclJSON(acl);
852 if(NULL == secPayload->securityData)
855 OIC_LOG(ERROR, TAG, "Failed to BinToAclJSON");
856 return OC_STACK_NO_MEMORY;
858 OIC_LOG_V(INFO, TAG, "ACL : %s", secPayload->securityData);
860 char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
861 if(!PMGenerateQuery(true,
862 selectedDeviceInfo->endpoint.addr,
863 selectedDeviceInfo->securePort,
864 selectedDeviceInfo->connType,
865 query, sizeof(query), OIC_RSRC_ACL_URI))
867 OIC_LOG(ERROR, TAG, "DeviceDiscoveryHandler : Failed to generate query");
868 return OC_STACK_ERROR;
870 OIC_LOG_V(DEBUG, TAG, "Query=%s", query);
872 OCCallbackData cbData = {.context=NULL, .cb=NULL, .cd=NULL};
873 cbData.cb = &SRPProvisionACLCB;
874 ACLData_t *aclData = (ACLData_t *) OICCalloc(1, sizeof(ACLData_t));
877 OICFree(secPayload->securityData);
879 OIC_LOG(ERROR, TAG, "Unable to allocate memory");
880 return OC_STACK_NO_MEMORY;
882 aclData->deviceInfo = selectedDeviceInfo;
883 aclData->resultCallback = resultCallback;
884 aclData->numOfResults=0;
886 // call to provision ACL to device1.
888 aclData->resArr = (OCProvisionResult_t*)OICCalloc(noOfRiCalls, sizeof(OCProvisionResult_t));
889 if (aclData->resArr == NULL)
892 OICFree(secPayload->securityData);
894 OIC_LOG(ERROR, TAG, "Unable to allocate memory");
895 return OC_STACK_NO_MEMORY;
897 cbData.context = (void *)aclData;
899 OCMethod method = OC_REST_POST;
900 OCDoHandle handle = NULL;
901 OIC_LOG(DEBUG, TAG, "Sending ACL info to resource server");
902 OCStackResult ret = OCDoResource(&handle, method, query,
903 &selectedDeviceInfo->endpoint, (OCPayload*)secPayload,
904 selectedDeviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0);
905 if (ret != OC_STACK_OK)
907 OICFree(aclData->resArr);
910 VERIFY_SUCCESS(TAG, (OC_STACK_OK == ret), ERROR, OC_STACK_ERROR);
915 * Internal Function to store results in result array during Direct-Pairing provisioning.
917 static void registerResultForDirectPairingProvisioning(PconfData_t *pconfData,
918 OCStackResult stackresult)
920 OIC_LOG_V(INFO, TAG, "Inside registerResultForDirectPairingProvisioning pconfData->numOfResults is %d\n",
921 pconfData->numOfResults);
922 memcpy(pconfData->resArr[(pconfData->numOfResults)].deviceId.id,
923 pconfData->deviceInfo->doxm->deviceID.id, UUID_LENGTH);
924 pconfData->resArr[(pconfData->numOfResults)].res = stackresult;
925 ++(pconfData->numOfResults);
929 * Callback handler of SRPProvisionDirectPairing.
931 * @param[in] ctx ctx value passed to callback from calling function.
932 * @param[in] UNUSED handle to an invocation
933 * @param[in] clientResponse Response from queries to remote servers.
934 * @return OC_STACK_DELETE_TRANSACTION to delete the transaction
935 * and OC_STACK_KEEP_TRANSACTION to keep it.
937 static OCStackApplicationResult SRPProvisionDirectPairingCB(void *ctx, OCDoHandle UNUSED,
938 OCClientResponse *clientResponse)
940 OIC_LOG_V(INFO, TAG, "Inside SRPProvisionDirectPairingCB.");
942 VERIFY_NON_NULL(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
943 PconfData_t *pconfData = (PconfData_t*)ctx;
944 OCProvisionResultCB resultCallback = pconfData->resultCallback;
948 if(OC_STACK_RESOURCE_CREATED == clientResponse->result)
950 registerResultForDirectPairingProvisioning(pconfData, OC_STACK_RESOURCE_CREATED);
951 ((OCProvisionResultCB)(resultCallback))(pconfData->ctx, pconfData->numOfResults,
954 OICFree(pconfData->resArr);
956 return OC_STACK_DELETE_TRANSACTION;
959 registerResultForDirectPairingProvisioning(pconfData, OC_STACK_ERROR);
960 ((OCProvisionResultCB)(resultCallback))(pconfData->ctx, pconfData->numOfResults,
963 OIC_LOG_V(ERROR, TAG, "SRPProvisionDirectPairingCB received Null clientResponse");
964 OICFree(pconfData->resArr);
966 return OC_STACK_DELETE_TRANSACTION;
969 OCStackResult SRPProvisionDirectPairing(void *ctx, const OCProvisionDev_t *selectedDeviceInfo,
970 OicSecPconf_t *pconf, OCProvisionResultCB resultCallback)
972 VERIFY_NON_NULL(TAG, selectedDeviceInfo, ERROR, OC_STACK_INVALID_PARAM);
973 VERIFY_NON_NULL(TAG, pconf, ERROR, OC_STACK_INVALID_PARAM);
974 VERIFY_NON_NULL(TAG, resultCallback, ERROR, OC_STACK_INVALID_CALLBACK);
976 // check direct-pairing capability
977 if (true != selectedDeviceInfo->doxm->dpc)
979 OIC_LOG(ERROR, TAG, "Resouce server does not have Direct-Pairing Capability ");
980 return OC_STACK_UNAUTHORIZED_REQ;
983 OicUuid_t provTooldeviceID = {.id={0}};
984 if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID))
986 OIC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
987 return OC_STACK_ERROR;
989 memcpy(&pconf->rowner, &provTooldeviceID, sizeof(OicUuid_t));
991 OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
994 OIC_LOG(ERROR, TAG, "Failed to memory allocation");
995 return OC_STACK_NO_MEMORY;
997 secPayload->base.type = PAYLOAD_TYPE_SECURITY;
998 secPayload->securityData = BinToPconfJSON(pconf);
999 if(NULL == secPayload->securityData)
1001 OICFree(secPayload);
1002 OIC_LOG(ERROR, TAG, "Failed to BinToPconfJSON");
1003 return OC_STACK_NO_MEMORY;
1005 OIC_LOG_V(INFO, TAG, "PCONF : %s", secPayload->securityData);
1007 char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
1008 if(!PMGenerateQuery(true,
1009 selectedDeviceInfo->endpoint.addr,
1010 selectedDeviceInfo->securePort,
1011 selectedDeviceInfo->connType,
1012 query, sizeof(query), OIC_RSRC_PCONF_URI))
1014 OIC_LOG(ERROR, TAG, "SRPProvisionDirectPairing : Failed to generate query");
1015 return OC_STACK_ERROR;
1017 OIC_LOG_V(DEBUG, TAG, "Query=%s", query);
1019 OCCallbackData cbData = {.context=NULL, .cb=NULL, .cd=NULL};
1020 cbData.cb = &SRPProvisionDirectPairingCB;
1021 PconfData_t *pconfData = (PconfData_t *) OICCalloc(1, sizeof(PconfData_t));
1022 if (NULL == pconfData)
1024 OICFree(secPayload->securityData);
1025 OICFree(secPayload);
1026 OIC_LOG(ERROR, TAG, "Unable to allocate memory");
1027 return OC_STACK_NO_MEMORY;
1029 pconfData->deviceInfo = selectedDeviceInfo;
1030 pconfData->resultCallback = resultCallback;
1031 pconfData->numOfResults=0;
1032 pconfData->ctx = ctx;
1033 // call to provision PCONF to device1.
1034 int noOfRiCalls = 1;
1035 pconfData->resArr = (OCProvisionResult_t*)OICCalloc(noOfRiCalls, sizeof(OCProvisionResult_t));
1036 if (NULL == pconfData->resArr)
1039 OICFree(secPayload->securityData);
1040 OICFree(secPayload);
1041 OIC_LOG(ERROR, TAG, "Unable to allocate memory");
1042 return OC_STACK_NO_MEMORY;
1044 cbData.context = (void *)pconfData;
1046 OCMethod method = OC_REST_POST;
1047 OCDoHandle handle = NULL;
1048 OIC_LOG(DEBUG, TAG, "Sending PCONF info to resource server");
1049 OCStackResult ret = OCDoResource(&handle, method, query,
1050 &selectedDeviceInfo->endpoint, (OCPayload*)secPayload,
1051 selectedDeviceInfo->connType, OC_LOW_QOS, &cbData, NULL, 0);
1052 if (OC_STACK_OK != ret)
1054 OICFree(pconfData->resArr);
1057 VERIFY_SUCCESS(TAG, (OC_STACK_OK == ret), ERROR, OC_STACK_ERROR);
1061 static void DeleteUnlinkData_t(UnlinkData_t *unlinkData)
1065 OICFree(unlinkData->unlinkDev);
1066 OICFree(unlinkData->unlinkRes);
1067 OICFree(unlinkData);
1071 static void registerResultForUnlinkDevices(UnlinkData_t *unlinkData, OCStackResult stackresult,
1074 if (NULL != unlinkData)
1076 OIC_LOG_V(INFO, TAG, "Inside registerResultForUnlinkDevices unlinkData->numOfResults is %d\n",
1077 unlinkData->numOfResults);
1078 OIC_LOG_V(INFO, TAG, "Stack result :: %d", stackresult);
1080 OicUuid_t *pUuid = &unlinkData->unlinkRes[(unlinkData->numOfResults)].deviceId;
1082 // Set result in the result array according to the position (devNum).
1083 if (idx != IDX_DB_UPDATE_RES)
1085 memcpy(pUuid->id, unlinkData->unlinkDev[idx].doxm->deviceID.id, sizeof(pUuid->id));
1088 { // When deivce ID is 000... this means it's the result of database update.
1089 memset(pUuid->id, 0, sizeof(pUuid->id));
1091 unlinkData->unlinkRes[(unlinkData->numOfResults)].res = stackresult;
1092 ++(unlinkData->numOfResults);
1093 OIC_LOG (INFO, TAG, "Out registerResultForUnlinkDevices");
1097 static OCStackResult SendDeleteCredentialRequest(void* ctx,
1098 OCClientResponseHandler respHandler,
1099 const OCProvisionDev_t* revokedDev,
1100 const OCProvisionDev_t* destDev)
1102 OIC_LOG(DEBUG, TAG, "IN SendDeleteCredentialRequest");
1104 if (NULL == ctx || NULL == respHandler || NULL == revokedDev || NULL == destDev)
1106 return OC_STACK_INVALID_PARAM;
1109 char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(revokedDev->doxm->deviceID.id)) + 1] = {};
1110 uint32_t base64Len = 0;
1111 if (B64_OK != b64Encode(revokedDev->doxm->deviceID.id, sizeof(revokedDev->doxm->deviceID.id),
1112 base64Buff, sizeof(base64Buff), &base64Len))
1114 OIC_LOG(ERROR, TAG, "SendDeleteCredentialRequest : Failed to base64 encoding");
1115 return OC_STACK_ERROR;
1118 char reqBuf[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
1120 //coaps://0.0.0.0:5684/oic/sec/cred?sub=(BASE64 ENCODED UUID)
1121 snRet = snprintf(reqBuf, sizeof(reqBuf), SRP_FORM_DELETE_CREDENTIAL, destDev->endpoint.addr,
1122 destDev->securePort, OIC_RSRC_CRED_URI, OIC_JSON_SUBJECT_NAME, base64Buff);
1125 OIC_LOG_V(ERROR, TAG, "SendDeleteCredentialRequest : Error (snprintf) %d\n", snRet);
1126 return OC_STACK_ERROR;
1128 else if ((size_t)snRet >= sizeof(reqBuf))
1130 OIC_LOG_V(ERROR, TAG, "SendDeleteCredentialRequest : Truncated (snprintf) %d\n", snRet);
1131 return OC_STACK_ERROR;
1134 OCCallbackData cbData;
1135 memset(&cbData, 0, sizeof(cbData));
1136 cbData.context = ctx;
1137 cbData.cb = respHandler;
1139 OIC_LOG_V(INFO, TAG, "URI: %s",reqBuf);
1141 OIC_LOG(DEBUG, TAG, "Sending remove credential request to resource server");
1143 OCStackResult ret = OCDoResource(NULL, OC_REST_DELETE, reqBuf,
1144 &destDev->endpoint, NULL,
1145 CT_ADAPTER_IP, OC_HIGH_QOS, &cbData, NULL, 0);
1146 if (OC_STACK_OK != ret)
1148 OIC_LOG_V(ERROR, TAG, "SendDeleteCredentialRequest : Error in OCDoResource %d", ret);
1150 OIC_LOG(DEBUG, TAG, "OUT SendDeleteCredentialRequest");
1156 * Callback handler of unlink second device.
1158 * @param[in] ctx ctx value passed to callback from calling function.
1159 * @param[in] handle handle to an invocation
1160 * @param[in] clientResponse Response from queries to remote servers.
1161 * @return OC_STACK_DELETE_TRANSACTION to delete the transaction and
1162 * OC_STACK_KEEP_TRANSACTION to keep it.
1164 static OCStackApplicationResult SRPUnlinkDevice2CB(void *unlinkCtx, OCDoHandle handle,
1165 OCClientResponse *clientResponse)
1168 OIC_LOG(DEBUG, TAG, "IN SRPUnlinkDevice2CB");
1169 VERIFY_NON_NULL(TAG, unlinkCtx, ERROR, OC_STACK_DELETE_TRANSACTION);
1170 UnlinkData_t* unlinkData = (UnlinkData_t*)unlinkCtx;
1174 OIC_LOG(DEBUG, TAG, "Valid client response for device 2");
1175 registerResultForUnlinkDevices(unlinkData, clientResponse->result, IDX_SECOND_DEVICE_RES);
1177 if (OC_STACK_RESOURCE_DELETED == clientResponse->result)
1179 OIC_LOG(DEBUG, TAG, "Credential of device2 revoked");
1183 OIC_LOG(ERROR, TAG, "Unable to delete credential information from device 2");
1184 unlinkData->resultCallback(unlinkData->ctx,
1185 unlinkData->numOfResults, unlinkData->unlinkRes, true);
1191 registerResultForUnlinkDevices(unlinkData, OC_STACK_INVALID_REQUEST_HANDLE,
1192 IDX_SECOND_DEVICE_RES);
1193 unlinkData->resultCallback(unlinkData->ctx,
1194 unlinkData->numOfResults, unlinkData->unlinkRes, true);
1195 OIC_LOG(ERROR, TAG, "SRPUnlinkDevice2CB received Null clientResponse");
1199 //Update provisioning DB when succes case.
1200 if (OC_STACK_OK != PDMUnlinkDevices(&unlinkData->unlinkDev[0].doxm->deviceID,
1201 &unlinkData->unlinkDev[1].doxm->deviceID))
1203 OIC_LOG(FATAL, TAG, "All requests are successfully done but update provisioning DB FAILED.");
1204 registerResultForUnlinkDevices(unlinkData, OC_STACK_INCONSISTENT_DB, IDX_DB_UPDATE_RES);
1205 unlinkData->resultCallback(unlinkData->ctx,
1206 unlinkData->numOfResults, unlinkData->unlinkRes, true);
1209 unlinkData->resultCallback(unlinkData->ctx, unlinkData->numOfResults, unlinkData->unlinkRes,
1213 DeleteUnlinkData_t(unlinkData);
1214 OIC_LOG(DEBUG, TAG, "OUT SRPUnlinkDevice2CB");
1215 return OC_STACK_DELETE_TRANSACTION;
1220 * Callback handler of unlink first device.
1222 * @param[in] ctx ctx value passed to callback from calling function.
1223 * @param[in] handle handle to an invocation
1224 * @param[in] clientResponse Response from queries to remote servers.
1225 * @return OC_STACK_DELETE_TRANSACTION to delete the transaction and
1226 * OC_STACK_KEEP_TRANSACTION to keep it.
1228 static OCStackApplicationResult SRPUnlinkDevice1CB(void *unlinkCtx, OCDoHandle handle,
1229 OCClientResponse *clientResponse)
1231 OIC_LOG_V(INFO, TAG, "Inside SRPUnlinkDevice1CB ");
1232 VERIFY_NON_NULL(TAG, unlinkCtx, ERROR, OC_STACK_DELETE_TRANSACTION);
1233 UnlinkData_t* unlinkData = (UnlinkData_t*)unlinkCtx;
1238 OIC_LOG(DEBUG, TAG, "Valid client response for device 1");
1239 registerResultForUnlinkDevices(unlinkData, clientResponse->result, IDX_FIRST_DEVICE_RES);
1241 if (OC_STACK_RESOURCE_DELETED == clientResponse->result)
1243 OIC_LOG(DEBUG, TAG, "Credential of device 1 is revoked");
1245 // Second revocation request to second device.
1246 OCStackResult res = SendDeleteCredentialRequest((void*)unlinkData, &SRPUnlinkDevice2CB,
1247 &unlinkData->unlinkDev[0],
1248 &unlinkData->unlinkDev[1] /*Dest*/);
1249 OIC_LOG_V(DEBUG, TAG, "Credential revocation request device 2, result :: %d",res);
1250 if (OC_STACK_OK != res)
1252 OIC_LOG(ERROR, TAG, "Error while sending revocation request for device 2");
1253 registerResultForUnlinkDevices(unlinkData, OC_STACK_INVALID_REQUEST_HANDLE,
1254 IDX_SECOND_DEVICE_RES);
1255 unlinkData->resultCallback(unlinkData->ctx,
1256 unlinkData->numOfResults, unlinkData->unlinkRes, true);
1261 OIC_LOG(DEBUG, TAG, "Request for credential revocation successfully sent");
1262 return OC_STACK_DELETE_TRANSACTION;
1267 OIC_LOG(ERROR, TAG, "Unable to delete credential information from device 1");
1269 unlinkData->resultCallback(unlinkData->ctx, unlinkData->numOfResults,
1270 unlinkData->unlinkRes, true);
1276 OIC_LOG(DEBUG, TAG, "Invalid response from server");
1277 registerResultForUnlinkDevices(unlinkData, OC_STACK_INVALID_REQUEST_HANDLE,
1278 IDX_FIRST_DEVICE_RES );
1279 unlinkData->resultCallback(unlinkData->ctx,
1280 unlinkData->numOfResults, unlinkData->unlinkRes,
1282 OIC_LOG(ERROR, TAG, "SRPUnlinkDevice1CB received Null clientResponse");
1286 OIC_LOG_V(INFO, TAG, "Out SRPUnlinkDevice1CB");
1287 DeleteUnlinkData_t(unlinkData);
1288 return OC_STACK_DELETE_TRANSACTION;
1292 * Function to unlink devices.
1293 * This function will remove the credential & relationship between the two devices.
1295 * @param[in] ctx Application context would be returned in result callback
1296 * @param[in] pTargetDev1 first device information to be unlinked.
1297 * @param[in] pTargetDev2 second device information to be unlinked.
1298 * @param[in] resultCallback callback provided by API user, callback will be called when
1299 * device unlink is finished.
1300 * @return OC_STACK_OK in case of success and other value otherwise.
1302 OCStackResult SRPUnlinkDevices(void* ctx,
1303 const OCProvisionDev_t* pTargetDev1,
1304 const OCProvisionDev_t* pTargetDev2,
1305 OCProvisionResultCB resultCallback)
1307 OIC_LOG(INFO, TAG, "IN SRPUnlinkDevices");
1309 if (!pTargetDev1 || !pTargetDev2 || !resultCallback)
1311 OIC_LOG(INFO, TAG, "SRPUnlinkDevices : NULL parameters");
1312 return OC_STACK_INVALID_PARAM;
1314 OIC_LOG(INFO, TAG, "Unlinking following devices: ");
1315 PMPrintOCProvisionDev(pTargetDev1);
1316 PMPrintOCProvisionDev(pTargetDev2);
1318 // Mark the link status stale
1319 OCStackResult res = PDMSetLinkStale(&pTargetDev1->doxm->deviceID, &pTargetDev2->doxm->deviceID);
1320 if (OC_STACK_OK != res)
1322 OIC_LOG(FATAL, TAG, "unable to update DB. Try again.");
1326 UnlinkData_t* unlinkData = (UnlinkData_t*)OICCalloc(1, sizeof(UnlinkData_t));
1327 VERIFY_NON_NULL(TAG, unlinkData, ERROR, OC_STACK_NO_MEMORY);
1329 //Initialize unlink data
1330 unlinkData->ctx = ctx;
1331 unlinkData->unlinkDev = (OCProvisionDev_t*)OICCalloc(2, sizeof(OCProvisionDev_t));
1332 if (NULL == unlinkData->unlinkDev)
1334 OIC_LOG(ERROR, TAG, "Memory allocation failed");
1335 res = OC_STACK_NO_MEMORY;
1339 unlinkData->unlinkRes = (OCProvisionResult_t*)OICCalloc(3, sizeof(OCProvisionResult_t));
1340 if (NULL == unlinkData->unlinkRes)
1342 OIC_LOG(ERROR, TAG, "Memory allocation failed");
1343 res = OC_STACK_NO_MEMORY;
1347 memcpy(&unlinkData->unlinkDev[0], pTargetDev1, sizeof(OCProvisionDev_t));
1348 memcpy(&unlinkData->unlinkDev[1], pTargetDev2, sizeof(OCProvisionDev_t));
1350 unlinkData->numOfResults = 0;
1351 unlinkData->resultCallback = resultCallback;
1353 res = SendDeleteCredentialRequest((void*)unlinkData, &SRPUnlinkDevice1CB,
1354 &unlinkData->unlinkDev[1], &unlinkData->unlinkDev[0]);
1355 if (OC_STACK_OK != res)
1357 OIC_LOG(ERROR, TAG, "SRPUnlinkDevices : SendDeleteCredentialRequest failed");
1364 OIC_LOG(INFO, TAG, "OUT SRPUnlinkDevices");
1365 DeleteUnlinkData_t(unlinkData);
1369 static void DeleteRemoveData_t(RemoveData_t* pRemoveData)
1373 OICFree(pRemoveData->revokeTargetDev);
1374 OCDeleteDiscoveredDevices(pRemoveData->linkedDevList);
1375 OICFree(pRemoveData->removeRes);
1376 OICFree(pRemoveData);
1380 static void registerResultForRemoveDevice(RemoveData_t *removeData, OicUuid_t *pLinkedDevId,
1381 OCStackResult stackresult, bool hasError)
1383 OIC_LOG_V(INFO, TAG, "Inside registerResultForRemoveDevice removeData->numOfResults is %zu\n",
1384 removeData->numOfResults + 1);
1387 memcpy(removeData->removeRes[(removeData->numOfResults)].deviceId.id,
1388 &pLinkedDevId->id, sizeof(pLinkedDevId->id));
1392 memset(removeData->removeRes[(removeData->numOfResults)].deviceId.id,
1393 0, sizeof(pLinkedDevId->id) );
1395 removeData->removeRes[(removeData->numOfResults)].res = stackresult;
1396 removeData->hasError = hasError;
1397 ++(removeData->numOfResults);
1399 // If we get suffcient result from linked devices, we have to call user callback and do free
1400 if (removeData->sizeOfResArray == removeData->numOfResults)
1402 if(!removeData->hasError)
1404 // Remove device info from prvisioning database
1405 if (OC_STACK_OK != PDMDeleteDevice(&removeData->revokeTargetDev->doxm->deviceID))
1407 OIC_LOG(ERROR, TAG, "ResultForRemoveDevice : Failed to remove device in PDM.");
1408 removeData->hasError = true;
1411 removeData->resultCallback(removeData->ctx, removeData->numOfResults, removeData->removeRes,
1412 removeData->hasError);
1413 DeleteRemoveData_t(removeData);
1418 * Callback handler of unlink first device.
1420 * @param[in] ctx ctx value passed to callback from calling function.
1421 * @param[in] handle handle to an invocation
1422 * @param[in] clientResponse Response from queries to remote servers.
1423 * @return OC_STACK_DELETE_TRANSACTION to delete the transaction
1424 * and OC_STACK_KEEP_TRANSACTION to keep it.
1426 static OCStackApplicationResult SRPRemoveDeviceCB(void *delDevCtx, OCDoHandle handle,
1427 OCClientResponse *clientResponse)
1429 //Update the delete credential into delete device context
1430 //Save the deleted status in delDevCtx
1432 OIC_LOG_V(INFO, TAG, "Inside SRPRemoveDeviceCB.");
1433 VERIFY_NON_NULL(TAG, delDevCtx, ERROR, OC_STACK_DELETE_TRANSACTION);
1434 OCStackResult res = OC_STACK_ERROR;
1436 RemoveData_t* removeData = (RemoveData_t*)delDevCtx;
1441 OicUuid_t revDevUuid = {.id={0}};
1442 if(UUID_LENGTH == clientResponse->identity.id_length)
1444 memcpy(revDevUuid.id, clientResponse->identity.id, sizeof(revDevUuid.id));
1445 if (OC_STACK_RESOURCE_DELETED == clientResponse->result)
1447 res = PDMUnlinkDevices(&removeData->revokeTargetDev->doxm->deviceID, &revDevUuid);
1448 if (OC_STACK_OK != res)
1450 OIC_LOG(ERROR, TAG, "PDMSetLinkStale() FAIL: PDB is an obsolete one.");
1451 registerResultForRemoveDevice(removeData, &revDevUuid,
1452 OC_STACK_INCONSISTENT_DB, true);
1454 return OC_STACK_DELETE_TRANSACTION;
1457 registerResultForRemoveDevice(removeData, &revDevUuid,
1458 OC_STACK_RESOURCE_DELETED, false);
1462 registerResultForRemoveDevice(removeData, &revDevUuid,
1463 clientResponse->result, true);
1464 OIC_LOG(ERROR, TAG, "Unexpected result from DELETE credential request!");
1469 OIC_LOG_V(WARNING, TAG, "Incorrect length of device UUID was sent from %s:%d",
1470 clientResponse->devAddr.addr, clientResponse->devAddr.port);
1472 if (OC_STACK_RESOURCE_DELETED == clientResponse->result)
1475 * Since server's credential was deleted,
1476 * register result as OC_STACK_INCONSISTENT_DB with NULL UUID.
1479 OIC_LOG_V(ERROR, TAG, "But server's credential was deleted.");
1480 registerResultForRemoveDevice(removeData, NULL, OC_STACK_INCONSISTENT_DB, true);
1484 registerResultForRemoveDevice(removeData, NULL, clientResponse->result, true);
1490 registerResultForRemoveDevice(removeData, NULL, OC_STACK_ERROR, true);
1491 OIC_LOG(ERROR, TAG, "SRPRemoveDevices received Null clientResponse");
1496 OIC_LOG(WARNING, TAG, "SRPRemoveDevices received null context");
1499 return OC_STACK_DELETE_TRANSACTION;
1502 static OCStackResult GetListofDevToReqDeleteCred(const OCProvisionDev_t* pRevokeTargetDev,
1503 OCProvisionDev_t* pOwnedDevList,
1504 OCUuidList_t* pLinkedUuidList,
1505 OCProvisionDev_t** ppLinkedDevList,
1506 size_t *numOfLinkedDev)
1508 // pOwnedDevList could be NULL. It means no alived and owned device now.
1509 if (pRevokeTargetDev == NULL || pLinkedUuidList == NULL ||\
1510 ppLinkedDevList == NULL || numOfLinkedDev == NULL)
1512 return OC_STACK_INVALID_PARAM;
1516 OCUuidList_t *curUuid = NULL, *tmpUuid = NULL;
1517 LL_FOREACH_SAFE(pLinkedUuidList, curUuid, tmpUuid)
1519 // Mark the link status stale.
1520 OCStackResult res = PDMSetLinkStale(&curUuid->dev, &pRevokeTargetDev->doxm->deviceID);
1521 if (OC_STACK_OK != res)
1523 OIC_LOG(FATAL, TAG, "PDMSetLinkStale() FAIL: PDB is an obsolete one.");
1524 return OC_STACK_INCONSISTENT_DB;
1529 // If this linked device is alive (power-on), add the deivce to the list.
1530 OCProvisionDev_t *curDev = NULL, *tmpDev = NULL;
1531 LL_FOREACH_SAFE(pOwnedDevList, curDev, tmpDev)
1533 if (memcmp(curDev->doxm->deviceID.id, curUuid->dev.id, sizeof(curUuid->dev.id)) == 0)
1535 OCProvisionDev_t* targetDev = PMCloneOCProvisionDev(curDev);
1536 if (NULL == targetDev)
1538 OIC_LOG(ERROR, TAG, "SRPRemoveDevice : Cloning OCProvisionDev_t Failed.");
1539 return OC_STACK_NO_MEMORY;
1542 LL_PREPEND(*ppLinkedDevList, targetDev);
1549 *numOfLinkedDev = cnt;
1554 * Function to device revocation
1555 * This function will remove credential of target device from all devices in subnet.
1557 * @param[in] ctx Application context would be returned in result callback
1558 * @param[in] waitTimeForOwnedDeviceDiscovery Maximum wait time for owned device discovery.(seconds)
1559 * @param[in] pTargetDev Device information to be revoked.
1560 * @param[in] resultCallback callback provided by API user, callback will be called when
1561 * credential revocation is finished.
1562 * @return OC_STACK_OK in case of success and other value otherwise.
1563 * If OC_STACK_OK is returned, the caller of this API should wait for callback.
1564 * OC_STACK_CONTINUE means operation is success but no request is need to be initiated.
1566 OCStackResult SRPRemoveDevice(void* ctx, unsigned short waitTimeForOwnedDeviceDiscovery,
1567 const OCProvisionDev_t* pTargetDev, OCProvisionResultCB resultCallback)
1569 OIC_LOG(INFO, TAG, "IN SRPRemoveDevice");
1571 if (!pTargetDev || !resultCallback || 0 == waitTimeForOwnedDeviceDiscovery)
1573 OIC_LOG(INFO, TAG, "SRPRemoveDevice : NULL parameters");
1574 return OC_STACK_INVALID_PARAM;
1577 // Declare variables in here to handle error cases with goto statement.
1578 OCProvisionDev_t* pOwnedDevList = NULL;
1579 OCProvisionDev_t* pLinkedDevList = NULL;
1580 RemoveData_t* removeData = NULL;
1582 //1. Find all devices that has a credential of the revoked device
1583 OCUuidList_t* pLinkedUuidList = NULL;
1584 size_t numOfDevices = 0;
1585 OCStackResult res = OC_STACK_ERROR;
1586 res = PDMGetLinkedDevices(&pTargetDev->doxm->deviceID, &pLinkedUuidList, &numOfDevices);
1587 if (OC_STACK_OK != res)
1589 OIC_LOG(ERROR, TAG, "SRPRemoveDevice : Failed to get linked devices information");
1592 // if there is no related device, we can skip further process.
1593 if (0 == numOfDevices)
1595 OIC_LOG(DEBUG, TAG, "SRPRemoveDevice : No linked device found.");
1596 res = OC_STACK_CONTINUE;
1600 //2. Find owned device from the network
1601 res = PMDeviceDiscovery(waitTimeForOwnedDeviceDiscovery, true, &pOwnedDevList);
1602 if (OC_STACK_OK != res)
1604 OIC_LOG(ERROR, TAG, "SRPRemoveDevice : Failed to PMDeviceDiscovery");
1608 //3. Make a list of devices to send DELETE credential request
1609 // by comparing owned devices from provisioning database with mutlicast discovery result.
1610 size_t numOfLinkedDev = 0;
1611 res = GetListofDevToReqDeleteCred(pTargetDev, pOwnedDevList, pLinkedUuidList,
1612 &pLinkedDevList, &numOfLinkedDev);
1613 if (OC_STACK_OK != res)
1615 OIC_LOG(ERROR, TAG, "SRPRemoveDevice : GetListofDevToReqDeleteCred() failed");
1618 if (0 == numOfLinkedDev) // This case means, there is linked device but it's not alive now.
1619 { // So we don't have to send request message.
1620 OIC_LOG(DEBUG, TAG, "SRPRemoveDevice : No alived & linked device found.");
1621 res = OC_STACK_CONTINUE;
1625 // 4. Prepare RemoveData Context data.
1626 removeData = (RemoveData_t*)OICCalloc(1, sizeof(RemoveData_t));
1629 OIC_LOG(ERROR, TAG, "SRPRemoveDevices : Failed to memory allocation");
1630 res = OC_STACK_NO_MEMORY;
1634 removeData->revokeTargetDev = PMCloneOCProvisionDev(pTargetDev);
1635 if (!removeData->revokeTargetDev)
1637 OIC_LOG(ERROR, TAG, "SRPRemoveDevices : PMCloneOCProvisionDev Failed");
1638 res = OC_STACK_NO_MEMORY;
1642 removeData->removeRes =
1643 (OCProvisionResult_t*)OICCalloc(numOfLinkedDev, sizeof(OCProvisionResult_t));
1644 if (!removeData->removeRes)
1646 OIC_LOG(ERROR, TAG, "SRPRemoveDevices : Failed to memory allocation");
1647 res = OC_STACK_NO_MEMORY;
1651 removeData->ctx = ctx;
1652 removeData->linkedDevList = pLinkedDevList;
1653 removeData->resultCallback = resultCallback;
1654 removeData->numOfResults = 0;
1655 removeData->sizeOfResArray = numOfLinkedDev;
1656 removeData->hasError = false;
1658 // 5. Send DELETE credential request to linked devices.
1659 OCProvisionDev_t *curDev = NULL, *tmpDev = NULL;
1660 OCStackResult totalRes = OC_STACK_ERROR; /* variable for checking request is sent or not */
1661 LL_FOREACH_SAFE(pLinkedDevList, curDev, tmpDev)
1663 res = SendDeleteCredentialRequest((void*)removeData, &SRPRemoveDeviceCB,
1664 removeData->revokeTargetDev, curDev);
1665 if (OC_STACK_OK != res)
1667 OIC_LOG_V(ERROR, TAG, "SRPRemoveDevice : Fail to send the DELETE credential request to\
1668 %s:%u", curDev->endpoint.addr, curDev->endpoint.port);
1672 totalRes = OC_STACK_OK; // This means at least one request is successfully sent.
1676 PDMDestoryOicUuidLinkList(pLinkedUuidList); //TODO: Modify API name to have unified convention.
1677 PMDeleteDeviceList(pOwnedDevList);
1678 OIC_LOG(INFO, TAG, "OUT SRPRemoveDevice");
1680 return totalRes; // Caller of this API should wait callback if totalRes == OC_STACK_OK.
1683 PDMDestoryOicUuidLinkList(pLinkedUuidList);
1684 PMDeleteDeviceList(pOwnedDevList);
1685 PMDeleteDeviceList(pLinkedDevList);
1688 OICFree(removeData->revokeTargetDev);
1689 OICFree(removeData->removeRes);
1690 OICFree(removeData);
1692 OIC_LOG(INFO, TAG, "OUT ERROR case SRPRemoveDevice");