fix many format errors
[platform/upstream/iotivity.git] / resource / csdk / security / provisioning / src / secureresourceprovider.c
1 /* *****************************************************************
2  *
3  * Copyright 2015 Samsung Electronics All Rights Reserved.
4  *
5  *
6  *
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
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
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.
18  *
19  * *****************************************************************/
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdint.h>
23 #include <unistd.h>
24
25 #include "ocprovisioningmanager.h"
26 #include "secureresourceprovider.h"
27 #include "logger.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"
36 #include "cJSON.h"
37 #include "pmtypes.h"
38 #include "pmutility.h"
39 #include "provisioningdatabasemanager.h"
40 #include "base64.h"
41 #include "utlist.h"
42
43 #ifdef __WITH_X509__
44 #include "crlresource.h"
45 #endif // WITH_X509__
46
47 #define TAG "SRPAPI"
48
49 /**
50  * Macro to verify argument is not equal to NULL.
51  * eg: VERIFY_NON_NULL(TAG, ptrData, ERROR,OC_STACK_ERROR);
52  */
53 #define VERIFY_NON_NULL(tag, arg, logLevel, retValue) { if (NULL == (arg)) \
54             { OC_LOG((logLevel), tag, #arg " is NULL"); return retValue; } }
55
56 /**
57  * Macro to verify success of operation.
58  * eg: VERIFY_SUCCESS(TAG, OC_STACK_OK == foo(), ERROR, OC_STACK_ERROR);
59  */
60 #define VERIFY_SUCCESS(tag, op, logLevel, retValue) { if (!(op)) \
61             {OC_LOG((logLevel), tag, #op " failed!!"); return retValue;} }
62
63 /**
64  * Structure to carry credential data to callback.
65  */
66 typedef struct CredentialData CredentialData_t;
67 struct CredentialData
68 {
69     void *ctx;                                  /**< Pointer to user context.**/
70     const OCProvisionDev_t *deviceInfo1;        /**< Pointer to OCProvisionDev_t.**/
71     const OCProvisionDev_t *deviceInfo2;        /**< Pointer to OCProvisionDev_t.**/
72     OicSecCred_t *credInfo;                     /**< Pointer to OicSecCred_t.**/
73     OicSecCred_t *credInfoFirst;                /**< Pointer to OicSecCred_t.**/
74     OCProvisionResultCB resultCallback;         /**< Pointer to result callback.**/
75     OCProvisionResult_t *resArr;                /**< Result array.**/
76     int numOfResults;                           /**< Number of results in result array.**/
77 };
78
79 /**
80  * Structure to carry ACL provision API data to callback.
81  */
82 typedef struct ACLData ACLData_t;
83 struct ACLData
84 {
85     void *ctx;                                  /**< Pointer to user context.**/
86     const OCProvisionDev_t *deviceInfo;         /**< Pointer to PMDevInfo_t.**/
87     OCProvisionResultCB resultCallback;         /**< Pointer to result callback.**/
88     OCProvisionResult_t *resArr;                /**< Result array.**/
89     int numOfResults;                           /**< Number of results in result array.**/
90 };
91
92 // Enum type index for unlink callback.
93 typedef enum {
94     IDX_FIRST_DEVICE_RES = 0, // index for resulf of the first device
95     IDX_SECOND_DEVICE_RES,    // index for result of the second device
96     IDX_DB_UPDATE_RES         // index for result of updating provisioning database.
97 } IdxUnlinkRes_t;
98
99 // Structure to carry unlink APIs data to callback.
100 typedef struct UnlinkData UnlinkData_t;
101 struct UnlinkData {
102     void *ctx;
103     OCProvisionDev_t* unlinkDev;             /**< Pointer to OCProvisionDev_t to be unlinked.**/
104     OCProvisionResult_t* unlinkRes;          /**< Result array.**/
105     OCProvisionResultCB resultCallback;      /**< Pointer to result callback.**/
106     int numOfResults;                        /**< Number of results in result array.**/
107 };
108
109 //Example of DELETE cred request -> coaps://0.0.0.0:5684/oic/sec/cred?sub=(BASE64 ENCODED UUID)
110 const char * SRP_FORM_DELETE_CREDENTIAL = "coaps://[%s]:%d%s?%s=%s";
111
112 // Structure to carry remove APIs data to callback.
113 typedef struct RemoveData RemoveData_t;
114 struct RemoveData {
115     void *ctx;
116     OCProvisionDev_t* revokeTargetDev;      /**< Device which is going to be revoked..**/
117     OCProvisionDev_t* linkedDevList;        /**< A list of devices which have invalid credential.**/
118     OCProvisionResult_t* removeRes;         /**< Result array.**/
119     OCProvisionResultCB resultCallback;     /**< Pointer to result callback.**/
120     size_t numOfResults;                    /**< Number of results in result array.**/
121     size_t sizeOfResArray;
122     bool hasError;
123 };
124
125 /**
126  * Function prototype
127  */
128 static OCStackResult provisionCredentials(const OicSecCred_t *cred,
129         const OCProvisionDev_t *deviceInfo, CredentialData_t *credData,
130         OCClientResponseHandler responseHandler);
131
132
133 /**
134  * Internal function to update result in result array.
135  */
136 static void registerResultForCredProvisioning(CredentialData_t *credData,
137                                               OCStackResult stackresult, int cause)
138 {
139
140    OC_LOG_V(INFO,TAG,"value of credData->numOfResults is %d",credData->numOfResults);
141    if(1 == cause)
142    {
143        memcpy(credData->resArr[(credData->numOfResults)].deviceId.id,
144               credData->deviceInfo1->doxm->deviceID.id,UUID_LENGTH);
145    }
146    else
147    {
148        memcpy(credData->resArr[(credData->numOfResults)].deviceId.id,
149               credData->deviceInfo2->doxm->deviceID.id,UUID_LENGTH);
150    }
151    credData->resArr[(credData->numOfResults)].res = stackresult;
152    ++(credData->numOfResults);
153 }
154
155 /**
156  * Callback handler for handling callback of provisioning device 2.
157  *
158  * @param[in] ctx             ctx value passed to callback from calling function.
159  * @param[in] UNUSED          handle to an invocation
160  * @param[in] clientResponse  Response from queries to remote servers.
161  * @return  OC_STACK_DELETE_TRANSACTION to delete the transaction
162  *          and  OC_STACK_KEEP_TRANSACTION to keep it.
163  */
164 static OCStackApplicationResult provisionCredentialCB2(void *ctx, OCDoHandle UNUSED,
165                                                        OCClientResponse *clientResponse)
166 {
167     VERIFY_NON_NULL(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
168     CredentialData_t *credData = (CredentialData_t *) ctx;
169     (void)UNUSED;
170
171     OCProvisionResultCB resultCallback = credData->resultCallback;
172     OC_LOG(INFO, TAG, "provisionCredentialCB2 called");
173     if (clientResponse)
174     {
175         if(OC_STACK_RESOURCE_CREATED == clientResponse->result)
176         {
177             registerResultForCredProvisioning(credData, OC_STACK_RESOURCE_CREATED, 2);
178             OCStackResult res =  PDMLinkDevices(&credData->deviceInfo1->doxm->deviceID,
179                     &credData->deviceInfo2->doxm->deviceID);
180             if (OC_STACK_OK != res)
181             {
182                 OC_LOG(ERROR, TAG, "Error occured on PDMLinkDevices");
183                 return OC_STACK_DELETE_TRANSACTION;
184             }
185             OC_LOG(INFO, TAG, "Link created successfully");
186
187             ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
188                                                     credData->resArr,
189                                                     false);
190              OICFree(credData->resArr);
191              OICFree(credData);
192              return OC_STACK_DELETE_TRANSACTION;
193         }
194
195     }
196     OC_LOG(INFO, TAG, "provisionCredentialCB2 received Null clientResponse");
197     registerResultForCredProvisioning(credData, OC_STACK_ERROR, 2);
198     ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
199                                             credData->resArr,
200                                             true);
201     OICFree(credData->resArr);
202     OICFree(credData);
203     return OC_STACK_DELETE_TRANSACTION;
204 }
205
206 /**
207  * Callback handler for handling callback of provisioning device 1.
208  *
209  * @param[in] ctx             ctx value passed to callback from calling function.
210  * @param[in] UNUSED          handle to an invocation
211  * @param[in] clientResponse  Response from queries to remote servers.
212  * @return  OC_STACK_DELETE_TRANSACTION to delete the transaction
213  *          and  OC_STACK_KEEP_TRANSACTION to keep it.
214  */
215 static OCStackApplicationResult provisionCredentialCB1(void *ctx, OCDoHandle UNUSED,
216                                                        OCClientResponse *clientResponse)
217 {
218     VERIFY_NON_NULL(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
219     (void)UNUSED;
220     CredentialData_t* credData = (CredentialData_t*) ctx;
221     OICFree(credData->credInfoFirst);
222     const OCProvisionDev_t *deviceInfo = credData->deviceInfo2;
223     OicSecCred_t *credInfo = credData->credInfo;
224     const OCProvisionResultCB resultCallback = credData->resultCallback;
225     if (clientResponse)
226     {
227         if (OC_STACK_RESOURCE_CREATED == clientResponse->result)
228         {
229             // send credentials to second device
230             registerResultForCredProvisioning(credData, OC_STACK_RESOURCE_CREATED,1);
231             OCStackResult res = provisionCredentials(credInfo, deviceInfo, credData,
232                     provisionCredentialCB2);
233             DeleteCredList(credInfo);
234             if (OC_STACK_OK != res)
235             {
236                 registerResultForCredProvisioning(credData, res,2);
237                 ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
238                                                         credData->resArr,
239                                                         true);
240                 OICFree(credData->resArr);
241                 OICFree(credData);
242                 credData = NULL;
243             }
244         }
245         else
246         {
247             registerResultForCredProvisioning(credData, OC_STACK_ERROR,1);
248             ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
249                                                     credData->resArr,
250                                                     true);
251             OICFree(credData->resArr);
252             OICFree(credData);
253             credData = NULL;
254         }
255     }
256     else
257     {
258         OC_LOG(INFO, TAG, "provisionCredentialCB received Null clientResponse for first device");
259         registerResultForCredProvisioning(credData, OC_STACK_ERROR,1);
260        ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
261                                                      credData->resArr,
262                                                      true);
263         DeleteCredList(credInfo);
264         OICFree(credData->resArr);
265         OICFree(credData);
266         credData = NULL;
267     }
268     return OC_STACK_DELETE_TRANSACTION;
269 }
270
271
272
273 /**
274  * Internal function for handling credential generation and sending credential to resource server.
275  *
276  * @param[in] cred Instance of cred resource.
277  * @param[in] deviceInfo information about device to which credential is to be provisioned.
278  * @param[in] responseHandler callbak called by OC stack when request API receives response.
279  * @return  OC_STACK_OK in case of success and other value otherwise.
280  */
281 static OCStackResult provisionCredentials(const OicSecCred_t *cred,
282         const OCProvisionDev_t *deviceInfo, CredentialData_t *credData,
283         OCClientResponseHandler responseHandler)
284 {
285     OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
286     if(!secPayload)
287     {
288         OC_LOG(ERROR, TAG, "Failed to memory allocation");
289         return OC_STACK_NO_MEMORY;
290     }
291     secPayload->base.type = PAYLOAD_TYPE_SECURITY;
292     secPayload->securityData = BinToCredJSON(cred);
293     if(NULL == secPayload->securityData)
294     {
295         OICFree(secPayload);
296         OC_LOG(ERROR, TAG, "Failed to BinToCredJSON");
297         return OC_STACK_NO_MEMORY;
298     }
299
300     OC_LOG_V(INFO, TAG, "Credential for provisioning : %s",secPayload->securityData);
301     char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
302     if(!PMGenerateQuery(true,
303                         deviceInfo->endpoint.addr,
304                         deviceInfo->securePort,
305                         deviceInfo->connType,
306                         query, sizeof(query), OIC_RSRC_CRED_URI))
307     {
308         OC_LOG(ERROR, TAG, "DeviceDiscoveryHandler : Failed to generate query");
309         return OC_STACK_ERROR;
310     }
311     OC_LOG_V(DEBUG, TAG, "Query=%s", query);
312
313     OCCallbackData cbData = {.context=NULL, .cb=NULL, .cd=NULL};
314     cbData.cb = responseHandler;
315     cbData.context = (void *) credData;
316     cbData.cd = NULL;
317
318     OCDoHandle handle = NULL;
319     OCMethod method = OC_REST_POST;
320     OCStackResult ret = OCDoResource(&handle, method, query, 0, (OCPayload*)secPayload,
321             deviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0);
322     OC_LOG_V(INFO, TAG, "OCDoResource::Credential provisioning returned : %d",ret);
323     if (ret != OC_STACK_OK)
324     {
325         OC_LOG(ERROR, TAG, "OCStack resource error");
326         return ret;
327     }
328     return OC_STACK_OK;
329 }
330
331 #ifdef __WITH_X509__
332 /**
333  * Structure to carry certificate data to callback.
334  */
335 typedef struct CertificateData CertData_t;
336 struct CertificateData
337 {
338     void *ctx;                                  /**< Pointer to user context.**/
339     const OCProvisionDev_t *deviceInfo;        /**< Pointer to OCProvisionDev_t.**/
340     OicSecCred_t *credInfo;                     /**< Pointer to OicSecCred_t.**/
341     OCProvisionResultCB resultCallback;         /**< Pointer to result callback.**/
342     OCProvisionResult_t *resArr;                /**< Result array.**/
343     int numOfResults;                           /**< Number of results in result array.**/
344 };
345
346 /**
347  * Structure to carry CRL provision API data to callback.
348  */
349 typedef struct CRLData CRLData_t;
350 struct CRLData
351 {
352     void *ctx;                                  /**< Pointer to user context.**/
353     const OCProvisionDev_t *deviceInfo;         /**< Pointer to PMDevInfo_t.**/
354     OCProvisionResultCB resultCallback;         /**< Pointer to result callback.**/
355     OCProvisionResult_t *resArr;                /**< Result array.**/
356     int numOfResults;                           /**< Number of results in result array.**/
357 };
358
359 /**
360  * Internal function to update result in result array.
361  */
362 static void registerResultForCertProvisioning(CertData_t *certData,
363                                               OCStackResult stackresult)
364 {
365
366    OC_LOG_V(INFO,TAG,"value of credData->numOfResults is %d",certData->numOfResults);
367    memcpy(certData->resArr[(certData->numOfResults)].deviceId.id,
368           certData->deviceInfo->doxm->deviceID.id,UUID_LENGTH);
369    certData->resArr[(certData->numOfResults)].res = stackresult;
370    ++(certData->numOfResults);
371 }
372
373 /**
374  * Internal Function to store results in result array during ACL provisioning.
375  */
376 static void registerResultForCRLProvisioning(CRLData_t *crlData,
377                                              OCStackResult stackresult)
378 {
379    OC_LOG_V(INFO, TAG, "Inside registerResultForCRLProvisioning crlData->numOfResults is %d\n",
380                        crlData->numOfResults);
381    memcpy(crlData->resArr[(crlData->numOfResults)].deviceId.id,
382           crlData->deviceInfo->doxm->deviceID.id, UUID_LENGTH);
383    crlData->resArr[(crlData->numOfResults)].res = stackresult;
384    ++(crlData->numOfResults);
385 }
386
387
388 /**
389  * Callback handler of SRPProvisionCRL.
390  *
391  * @param[in] ctx             ctx value passed to callback from calling function.
392  * @param[in] UNUSED          handle to an invocation
393  * @param[in] clientResponse  Response from queries to remote servers.
394  * @return  OC_STACK_DELETE_TRANSACTION to delete the transaction
395  *          and  OC_STACK_KEEP_TRANSACTION to keep it.
396  */
397 static OCStackApplicationResult SRPProvisionCRLCB(void *ctx, OCDoHandle UNUSED,
398                                                   OCClientResponse *clientResponse)
399 {
400     OC_LOG_V(INFO, TAG, "Inside SRPProvisionCRLCB.");
401     (void)UNUSED;
402     VERIFY_NON_NULL(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
403     CRLData_t *crlData = (CRLData_t*)ctx;
404     OCProvisionResultCB resultCallback = crlData->resultCallback;
405
406     if (clientResponse)
407     {
408         if(OC_STACK_RESOURCE_CREATED == clientResponse->result)
409         {
410             registerResultForCRLProvisioning(crlData, OC_STACK_RESOURCE_CREATED);
411             ((OCProvisionResultCB)(resultCallback))(crlData->ctx, crlData->numOfResults,
412                                                     crlData->resArr,
413                                                     false);
414              OICFree(crlData->resArr);
415              OICFree(crlData);
416              return OC_STACK_DELETE_TRANSACTION;
417         }
418     }
419     registerResultForCRLProvisioning(crlData, OC_STACK_ERROR);
420     ((OCProvisionResultCB)(resultCallback))(crlData->ctx, crlData->numOfResults,
421                                             crlData->resArr,
422                                             true);
423     OC_LOG_V(ERROR, TAG, "SRPProvisionCRLCB received Null clientResponse");
424     OICFree(crlData->resArr);
425     OICFree(crlData);
426     return OC_STACK_DELETE_TRANSACTION;
427 }
428
429 OCStackResult SRPProvisionCRL(void *ctx, const OCProvisionDev_t *selectedDeviceInfo,
430         OicSecCrl_t *crl, OCProvisionResultCB resultCallback)
431 {
432     VERIFY_NON_NULL(TAG, selectedDeviceInfo, ERROR,  OC_STACK_INVALID_PARAM);
433     VERIFY_NON_NULL(TAG, crl, ERROR,  OC_STACK_INVALID_PARAM);
434     VERIFY_NON_NULL(TAG, resultCallback, ERROR,  OC_STACK_INVALID_CALLBACK);
435
436     OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
437     if (!secPayload)
438     {
439         OC_LOG(ERROR, TAG, "Failed to memory allocation");
440         return OC_STACK_NO_MEMORY;
441     }
442
443     secPayload->base.type = PAYLOAD_TYPE_SECURITY;
444     secPayload->securityData = BinToCrlJSON(crl);
445     if (NULL == secPayload->securityData)
446     {
447         OICFree(secPayload);
448         OC_LOG(ERROR, TAG, "Failed to BinToCrlJSON");
449         return OC_STACK_NO_MEMORY;
450     }
451     OC_LOG_V(INFO, TAG, "CRL : %s", secPayload->securityData);
452
453     char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
454     if(!PMGenerateQuery(true,
455                         selectedDeviceInfo->endpoint.addr,
456                         selectedDeviceInfo->securePort,
457                         selectedDeviceInfo->connType,
458                         query, sizeof(query), OIC_RSRC_CRL_URI))
459     {
460         OC_LOG(ERROR, TAG, "DeviceDiscoveryHandler : Failed to generate query");
461         OICFree(secPayload->securityData);
462         OICFree(secPayload);
463         return OC_STACK_ERROR;
464     }
465     OC_LOG_V(DEBUG, TAG, "Query=%s", query);
466
467     OCCallbackData cbData =  {.context=NULL, .cb=NULL, .cd=NULL};
468     cbData.cb = &SRPProvisionCRLCB;
469     CRLData_t *crlData = (CRLData_t *) OICCalloc(1, sizeof(CRLData_t));
470     if (crlData == NULL)
471     {
472         OICFree(secPayload->securityData);
473         OICFree(secPayload);
474         OC_LOG(ERROR, TAG, "Unable to allocate memory");
475         return OC_STACK_NO_MEMORY;
476     }
477
478     crlData->deviceInfo = selectedDeviceInfo;
479     crlData->resultCallback = resultCallback;
480     crlData->numOfResults=0;
481     crlData->ctx = ctx;
482
483     crlData->resArr = (OCProvisionResult_t*)OICCalloc(1, sizeof(OCProvisionResult_t));
484     if (crlData->resArr == NULL)
485     {
486         OICFree(secPayload->securityData);
487         OICFree(secPayload);
488         OC_LOG(ERROR, TAG, "Unable to allocate memory");
489         return OC_STACK_NO_MEMORY;
490     }
491
492     cbData.context = (void *)crlData;
493     cbData.cd = NULL;
494     OCMethod method = OC_REST_POST;
495     OCDoHandle handle = NULL;
496     OC_LOG(DEBUG, TAG, "Sending CRL info to resource server");
497
498     OCStackResult ret = OCDoResource(&handle, method, query,
499             &selectedDeviceInfo->endpoint, (OCPayload*)secPayload,
500             selectedDeviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0);
501
502     if (ret != OC_STACK_OK)
503     {
504         OICFree(crlData->resArr);
505         OICFree(crlData);
506     }
507
508     return ret;
509 }
510
511 /**
512  * Internal function for handling credential generation and sending cretificate credential.
513  *
514  * @param[in] cred Instance of cred resource.
515  * @param[in] deviceInfo information about device to which credential is to be provisioned.
516  * @param[in] responseHandler callbak called by OC stack when request API receives response.
517  * @return  OC_STACK_OK in case of success and other value otherwise.
518  */
519 static OCStackResult provisionCertCred(const OicSecCred_t *cred,
520         const OCProvisionDev_t *deviceInfo, CertData_t *certData,
521         OCClientResponseHandler responseHandler)
522 {
523     OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
524     if(!secPayload)
525     {
526         OC_LOG(ERROR, TAG, "Failed to memory allocation");
527         return OC_STACK_NO_MEMORY;
528     }
529     secPayload->base.type = PAYLOAD_TYPE_SECURITY;
530     secPayload->securityData = BinToCredJSON(cred);
531
532     if (NULL == secPayload->securityData)
533     {
534         OICFree(secPayload);
535         OC_LOG(ERROR, TAG, "Failed to BinToCredJSON");
536         return OC_STACK_NO_MEMORY;
537     }
538
539     OC_LOG_V(INFO, TAG, "Credential for provisioning : %s",secPayload->securityData);
540     char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
541     if(!PMGenerateQuery(true,
542                         deviceInfo->endpoint.addr,
543                         deviceInfo->securePort,
544                         deviceInfo->connType,
545                         query, sizeof(query), OIC_RSRC_CRED_URI))
546     {
547         OC_LOG(ERROR, TAG, "DeviceDiscoveryHandler : Failed to generate query");
548         OICFree(secPayload->securityData);
549         OICFree(secPayload);
550         return OC_STACK_ERROR;
551     }
552     OC_LOG_V(DEBUG, TAG, "Query=%s", query);
553
554     OCCallbackData cbData = {.context=NULL, .cb=NULL, .cd=NULL};
555     cbData.cb = responseHandler;
556     cbData.context = (void *) certData;
557     cbData.cd = NULL;
558
559     OCDoHandle handle = NULL;
560     OCMethod method = OC_REST_POST;
561     OCStackResult ret = OCDoResource(&handle, method, query, 0, (OCPayload*)secPayload,
562             deviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0);
563     OC_LOG_V(INFO, TAG, "OCDoResource::Certificate provisioning returned : %d",ret);
564     if (ret != OC_STACK_OK)
565     {
566         OC_LOG(ERROR, TAG, "OCStack resource error");
567     }
568
569     return ret;
570 }
571
572 /**
573  * Callback handler for handling callback of certificate provisioning device.
574  *
575  * @param[in] ctx             ctx value passed to callback from calling function.
576  * @param[in] UNUSED          handle to an invocation
577  * @param[in] clientResponse  Response from queries to remote servers.
578  * @return  OC_STACK_DELETE_TRANSACTION to delete the transaction
579  *          and  OC_STACK_KEEP_TRANSACTION to keep it.
580  */
581 static OCStackApplicationResult provisionCertCB(void *ctx, OCDoHandle UNUSED,
582                                                        OCClientResponse *clientResponse)
583 {
584     VERIFY_NON_NULL(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
585     CertData_t *certData = (CertData_t *) ctx;
586     (void)UNUSED;
587
588     OCProvisionResultCB resultCallback = certData->resultCallback;
589     OC_LOG(INFO, TAG, "provisionCertCred called");
590     if (clientResponse)
591     {
592         if(OC_STACK_RESOURCE_CREATED == clientResponse->result)
593         {
594             registerResultForCertProvisioning(certData, OC_STACK_RESOURCE_CREATED);
595             ((OCProvisionResultCB)(resultCallback))(certData->ctx, certData->numOfResults,
596                                                     certData->resArr,
597                                                     false);
598              OICFree(certData->resArr);
599              OICFree(certData);
600              return OC_STACK_DELETE_TRANSACTION;
601         }
602
603     }
604     OC_LOG(INFO, TAG, "provisionCertCredCB received Null clientResponse");
605     registerResultForCertProvisioning(certData, OC_STACK_ERROR);
606     ((OCProvisionResultCB)(resultCallback))(certData->ctx, certData->numOfResults,
607                                             certData->resArr,
608                                             true);
609     OICFree(certData->resArr);
610     OICFree(certData);
611     return OC_STACK_DELETE_TRANSACTION;
612 }
613 #endif // __WITH_X509__
614
615 OCStackResult SRPProvisionCredentials(void *ctx, OicSecCredType_t type, size_t keySize,
616                                       const OCProvisionDev_t *pDev1,
617                                       const OCProvisionDev_t *pDev2,
618                                       OCProvisionResultCB resultCallback)
619 {
620     VERIFY_NON_NULL(TAG, pDev1, ERROR,  OC_STACK_INVALID_PARAM);
621     if (SYMMETRIC_PAIR_WISE_KEY == type)
622     {
623         VERIFY_NON_NULL(TAG, pDev2, ERROR,  OC_STACK_INVALID_PARAM);
624     }
625     VERIFY_NON_NULL(TAG, resultCallback, ERROR,  OC_STACK_INVALID_CALLBACK);
626
627     if (SYMMETRIC_PAIR_WISE_KEY == type &&
628        !(OWNER_PSK_LENGTH_128 == keySize || OWNER_PSK_LENGTH_256 == keySize))
629     {
630         OC_LOG(INFO, TAG, "Invalid key size");
631         return OC_STACK_INVALID_PARAM;
632     }
633
634     OC_LOG(INFO, TAG, "In SRPProvisionCredentials");
635
636     if (SYMMETRIC_PAIR_WISE_KEY == type)
637     {
638         bool linkExisits = true;
639         OCStackResult res = PDMIsLinkExists(&pDev1->doxm->deviceID, &pDev2->doxm->deviceID, &linkExisits);
640
641         if (res != OC_STACK_OK)
642         {
643             OC_LOG(ERROR, TAG, "Internal error occured");
644             return res;
645         }
646         if (linkExisits)
647         {
648             OC_LOG(ERROR, TAG, "Link already exists");
649             return OC_STACK_INVALID_PARAM;
650         }
651     }
652
653     OicUuid_t provTooldeviceID =   {{0,}};
654     if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID))
655     {
656         OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
657         return OC_STACK_ERROR;
658     }
659     OC_LOG(INFO, TAG, "retrieved deviceid");
660     switch (type)
661     {
662         case SYMMETRIC_PAIR_WISE_KEY:
663         {
664             const OCProvisionDev_t *firstDevice = pDev1;
665             const OCProvisionDev_t *secondDevice = pDev2;
666
667             OicSecCred_t *firstCred = NULL;
668             OicSecCred_t *secondCred = NULL;
669             OCStackResult res = PMGeneratePairWiseCredentials(type, keySize, &provTooldeviceID,
670                     &firstDevice->doxm->deviceID, &secondDevice->doxm->deviceID,
671                     &firstCred, &secondCred);
672             VERIFY_SUCCESS(TAG, (res==OC_STACK_OK), ERROR, OC_STACK_ERROR);
673             OC_LOG(INFO, TAG, "Credentials generated successfully");
674             CredentialData_t *credData =
675                 (CredentialData_t *) OICCalloc(1, sizeof(CredentialData_t));
676             if (NULL == credData)
677             {
678                 OICFree(firstCred);
679                 OICFree(secondCred);
680                 OC_LOG(ERROR, TAG, "Memory allocation problem");
681                 return OC_STACK_NO_MEMORY;
682             }
683             credData->deviceInfo1 = firstDevice;
684             credData->deviceInfo2 = secondDevice;
685             credData->credInfo = secondCred;
686             credData->ctx = ctx;
687             credData->credInfoFirst = firstCred;
688             credData->numOfResults = 0;
689             credData->resultCallback = resultCallback;
690             // first call to provision creds to device1.
691             // second call to provision creds to device2.
692             int noOfRiCalls = 2;
693             credData->resArr =
694                 (OCProvisionResult_t*)OICCalloc(noOfRiCalls, sizeof(OCProvisionResult_t));
695             if (NULL == credData->resArr)
696             {
697                 OICFree(firstCred);
698                 OICFree(secondCred);
699                 OICFree(credData);
700                 OC_LOG(ERROR, TAG, "Memory allocation problem");
701                 return OC_STACK_NO_MEMORY;
702             }
703             res = provisionCredentials(firstCred, firstDevice, credData, &provisionCredentialCB1);
704             if (OC_STACK_OK != res)
705             {
706                 DeleteCredList(firstCred);
707                 DeleteCredList(secondCred);
708                 OICFree(credData->resArr);
709                 OICFree(credData);
710             }
711             OC_LOG_V(INFO, TAG, "provisionCredentials returned: %d",res);
712             VERIFY_SUCCESS(TAG, (res==OC_STACK_OK), ERROR, OC_STACK_ERROR);
713             return res;
714         }
715 #ifdef __WITH_X509__
716         case SIGNED_ASYMMETRIC_KEY:
717         {
718             const OCProvisionDev_t *firstDevice = pDev1;
719             OicSecCred_t *cred = NULL;
720             OCStackResult res = PMGenerateCertificateCredentials(&provTooldeviceID,
721                                                                 &firstDevice->doxm->deviceID,&cred);
722             VERIFY_SUCCESS(TAG, (res==OC_STACK_OK), ERROR, OC_STACK_ERROR);
723             OC_LOG(INFO, TAG, "Certificate credentials generated successfully");
724             CertData_t *certData = (CertData_t *) OICCalloc(1, sizeof(CertData_t));
725             if (NULL == certData)
726             {
727                 OICFree(cred);
728                 OC_LOG(ERROR, TAG, "Memory allocation problem");
729                 return OC_STACK_NO_MEMORY;
730             }
731
732             certData->deviceInfo = firstDevice;
733             certData->ctx = ctx;
734             certData->credInfo = cred;
735             certData->numOfResults = 0;
736             certData->resultCallback = resultCallback;
737
738             certData->resArr = (OCProvisionResult_t*)OICCalloc(1, sizeof(OCProvisionResult_t));
739             if (NULL == certData->resArr)
740             {
741                 DeleteCredList(cred);
742                 OICFree(certData);
743                 OC_LOG(ERROR, TAG, "Memory allocation problem");
744                 return OC_STACK_NO_MEMORY;
745             }
746
747             res = provisionCertCred(cred, firstDevice, certData, &provisionCertCB);
748             if (OC_STACK_OK != res)
749             {
750                 OICFree(certData->resArr);
751                 OICFree(certData);
752             }
753             DeleteCredList(cred);
754             OC_LOG_V(INFO, TAG, "provisionCertCredentials returned: %d",res);
755
756             return res;
757         }
758 #endif
759         default:
760         {
761             OC_LOG(ERROR, TAG, "Invalid option.");
762             return OC_STACK_INVALID_PARAM;
763         }
764     }
765     return OC_STACK_ERROR;
766 }
767
768 /**
769  * Internal Function to store results in result array during ACL provisioning.
770  */
771 static void registerResultForACLProvisioning(ACLData_t *aclData,
772                                              OCStackResult stackresult)
773 {
774    OC_LOG_V(INFO, TAG, "Inside registerResultForACLProvisioning aclData->numOfResults is %d\n",
775                        aclData->numOfResults);
776    memcpy(aclData->resArr[(aclData->numOfResults)].deviceId.id,
777           aclData->deviceInfo->doxm->deviceID.id, UUID_LENGTH);
778    aclData->resArr[(aclData->numOfResults)].res = stackresult;
779    ++(aclData->numOfResults);
780 }
781
782 /**
783  * Callback handler of SRPProvisionACL.
784  *
785  * @param[in] ctx             ctx value passed to callback from calling function.
786  * @param[in] UNUSED          handle to an invocation
787  * @param[in] clientResponse  Response from queries to remote servers.
788  * @return  OC_STACK_DELETE_TRANSACTION to delete the transaction
789  *          and  OC_STACK_KEEP_TRANSACTION to keep it.
790  */
791 static OCStackApplicationResult SRPProvisionACLCB(void *ctx, OCDoHandle UNUSED,
792                                                   OCClientResponse *clientResponse)
793 {
794     OC_LOG_V(INFO, TAG, "Inside SRPProvisionACLCB.");
795     (void)UNUSED;
796     VERIFY_NON_NULL(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
797     ACLData_t *aclData = (ACLData_t*)ctx;
798     OCProvisionResultCB resultCallback = aclData->resultCallback;
799
800     if (clientResponse)
801     {
802         if(OC_STACK_RESOURCE_CREATED == clientResponse->result)
803         {
804             registerResultForACLProvisioning(aclData, OC_STACK_RESOURCE_CREATED);
805             ((OCProvisionResultCB)(resultCallback))(aclData->ctx, aclData->numOfResults,
806                                                     aclData->resArr,
807                                                     false);
808              OICFree(aclData->resArr);
809              OICFree(aclData);
810              return OC_STACK_DELETE_TRANSACTION;
811         }
812     }
813     registerResultForACLProvisioning(aclData, OC_STACK_ERROR);
814     ((OCProvisionResultCB)(resultCallback))(aclData->ctx, aclData->numOfResults,
815                                             aclData->resArr,
816                                             true);
817     OC_LOG_V(ERROR, TAG, "SRPProvisionACLCB received Null clientResponse");
818     OICFree(aclData->resArr);
819     OICFree(aclData);
820     return OC_STACK_DELETE_TRANSACTION;
821 }
822
823 OCStackResult SRPProvisionACL(void *ctx, const OCProvisionDev_t *selectedDeviceInfo,
824         OicSecAcl_t *acl, OCProvisionResultCB resultCallback)
825 {
826     VERIFY_NON_NULL(TAG, selectedDeviceInfo, ERROR,  OC_STACK_INVALID_PARAM);
827     VERIFY_NON_NULL(TAG, acl, ERROR,  OC_STACK_INVALID_PARAM);
828     VERIFY_NON_NULL(TAG, resultCallback, ERROR,  OC_STACK_INVALID_CALLBACK);
829
830     OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
831     if(!secPayload)
832     {
833         OC_LOG(ERROR, TAG, "Failed to memory allocation");
834         return OC_STACK_NO_MEMORY;
835     }
836     secPayload->base.type = PAYLOAD_TYPE_SECURITY;
837     secPayload->securityData = BinToAclJSON(acl);
838     if(NULL == secPayload->securityData)
839     {
840         OICFree(secPayload);
841         OC_LOG(ERROR, TAG, "Failed to BinToAclJSON");
842         return OC_STACK_NO_MEMORY;
843     }
844     OC_LOG_V(INFO, TAG, "ACL : %s", secPayload->securityData);
845
846     char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
847     if(!PMGenerateQuery(true,
848                         selectedDeviceInfo->endpoint.addr,
849                         selectedDeviceInfo->securePort,
850                         selectedDeviceInfo->connType,
851                         query, sizeof(query), OIC_RSRC_ACL_URI))
852     {
853         OC_LOG(ERROR, TAG, "DeviceDiscoveryHandler : Failed to generate query");
854         return OC_STACK_ERROR;
855     }
856     OC_LOG_V(DEBUG, TAG, "Query=%s", query);
857
858     OCCallbackData cbData =  {.context=NULL, .cb=NULL, .cd=NULL};
859     cbData.cb = &SRPProvisionACLCB;
860     ACLData_t *aclData = (ACLData_t *) OICCalloc(1, sizeof(ACLData_t));
861     if (aclData == NULL)
862     {
863         OICFree(secPayload->securityData);
864         OICFree(secPayload);
865         OC_LOG(ERROR, TAG, "Unable to allocate memory");
866         return OC_STACK_NO_MEMORY;
867     }
868     aclData->deviceInfo = selectedDeviceInfo;
869     aclData->resultCallback = resultCallback;
870     aclData->numOfResults=0;
871     aclData->ctx = ctx;
872     // call to provision ACL to device1.
873     int noOfRiCalls = 1;
874     aclData->resArr = (OCProvisionResult_t*)OICCalloc(noOfRiCalls, sizeof(OCProvisionResult_t));
875     if (aclData->resArr == NULL)
876     {
877         OICFree(aclData);
878         OICFree(secPayload->securityData);
879         OICFree(secPayload);
880         OC_LOG(ERROR, TAG, "Unable to allocate memory");
881         return OC_STACK_NO_MEMORY;
882     }
883     cbData.context = (void *)aclData;
884     cbData.cd = NULL;
885     OCMethod method = OC_REST_POST;
886     OCDoHandle handle = NULL;
887     OC_LOG(DEBUG, TAG, "Sending ACL info to resource server");
888     OCStackResult ret = OCDoResource(&handle, method, query,
889             &selectedDeviceInfo->endpoint, (OCPayload*)secPayload,
890             selectedDeviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0);
891     if (ret != OC_STACK_OK)
892     {
893         OICFree(aclData->resArr);
894         OICFree(aclData);
895     }
896     VERIFY_SUCCESS(TAG, (OC_STACK_OK == ret), ERROR, OC_STACK_ERROR);
897     return OC_STACK_OK;
898 }
899
900 static void DeleteUnlinkData_t(UnlinkData_t *unlinkData)
901 {
902     if (unlinkData)
903     {
904         OICFree(unlinkData->unlinkDev);
905         OICFree(unlinkData->unlinkRes);
906         OICFree(unlinkData);
907     }
908 }
909
910 static void registerResultForUnlinkDevices(UnlinkData_t *unlinkData, OCStackResult stackresult,
911                                            IdxUnlinkRes_t idx)
912 {
913     if (NULL != unlinkData)
914     {
915         OC_LOG_V(INFO, TAG, "Inside registerResultForUnlinkDevices unlinkData->numOfResults is %d\n",
916                             unlinkData->numOfResults);
917         OC_LOG_V(INFO, TAG, "Stack result :: %d", stackresult);
918
919         OicUuid_t *pUuid = &unlinkData->unlinkRes[(unlinkData->numOfResults)].deviceId;
920
921         // Set result in the result array according to the position (devNum).
922         if (idx != IDX_DB_UPDATE_RES)
923         {
924             memcpy(pUuid->id, unlinkData->unlinkDev[idx].doxm->deviceID.id, sizeof(pUuid->id));
925         }
926         else
927         {   // When deivce ID is 000... this means it's the result of database update.
928             memset(pUuid->id, 0, sizeof(pUuid->id));
929         }
930         unlinkData->unlinkRes[(unlinkData->numOfResults)].res = stackresult;
931         ++(unlinkData->numOfResults);
932         OC_LOG (INFO, TAG, "Out registerResultForUnlinkDevices");
933     }
934 }
935
936 static OCStackResult SendDeleteCredentialRequest(void* ctx,
937                                                  OCClientResponseHandler respHandler,
938                                                  const OCProvisionDev_t* revokedDev,
939                                                  const OCProvisionDev_t* destDev)
940 {
941     OC_LOG(DEBUG, TAG, "IN SendDeleteCredentialRequest");
942
943     if (NULL == ctx || NULL == respHandler || NULL == revokedDev || NULL == destDev)
944     {
945         return OC_STACK_INVALID_PARAM;
946     }
947
948     char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(revokedDev->doxm->deviceID.id)) + 1] = {};
949     uint32_t base64Len = 0;
950     if (B64_OK != b64Encode(revokedDev->doxm->deviceID.id, sizeof(revokedDev->doxm->deviceID.id),
951                            base64Buff, sizeof(base64Buff), &base64Len))
952     {
953         OC_LOG(ERROR, TAG, "SendDeleteCredentialRequest : Failed to base64 encoding");
954         return OC_STACK_ERROR;
955     }
956
957     char reqBuf[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
958     int snRet = 0;
959                     //coaps://0.0.0.0:5684/oic/sec/cred?sub=(BASE64 ENCODED UUID)
960     snRet = snprintf(reqBuf, sizeof(reqBuf), SRP_FORM_DELETE_CREDENTIAL, destDev->endpoint.addr,
961                      destDev->securePort, OIC_RSRC_CRED_URI, OIC_JSON_SUBJECT_NAME, base64Buff);
962     if (snRet < 0)
963     {
964         OC_LOG_V(ERROR, TAG, "SendDeleteCredentialRequest : Error (snprintf) %d\n", snRet);
965         return OC_STACK_ERROR;
966     }
967     else if ((size_t)snRet >= sizeof(reqBuf))
968     {
969         OC_LOG_V(ERROR, TAG, "SendDeleteCredentialRequest : Truncated (snprintf) %d\n", snRet);
970         return OC_STACK_ERROR;
971     }
972
973     OCCallbackData cbData;
974     memset(&cbData, 0, sizeof(cbData));
975     cbData.context = ctx;
976     cbData.cb = respHandler;
977     cbData.cd = NULL;
978     OC_LOG_V(INFO, TAG, "URI: %s",reqBuf);
979
980     OC_LOG(DEBUG, TAG, "Sending remove credential request to resource server");
981
982     OCStackResult ret = OCDoResource(NULL, OC_REST_DELETE, reqBuf,
983                                      &destDev->endpoint, NULL,
984                                      CT_ADAPTER_IP, OC_HIGH_QOS, &cbData, NULL, 0);
985     if (OC_STACK_OK != ret)
986     {
987         OC_LOG_V(ERROR, TAG, "SendDeleteCredentialRequest : Error in OCDoResource %d", ret);
988     }
989     OC_LOG(DEBUG, TAG, "OUT SendDeleteCredentialRequest");
990
991     return ret;
992 }
993
994 /**
995  * Callback handler of unlink second device.
996  *
997  * @param[in] ctx             ctx value passed to callback from calling function.
998  * @param[in] handle          handle to an invocation
999  * @param[in] clientResponse  Response from queries to remote servers.
1000  * @return  OC_STACK_DELETE_TRANSACTION to delete the transaction and
1001  *          OC_STACK_KEEP_TRANSACTION to keep it.
1002  */
1003 static OCStackApplicationResult SRPUnlinkDevice2CB(void *unlinkCtx, OCDoHandle handle,
1004         OCClientResponse *clientResponse)
1005 {
1006     (void) handle;
1007     OC_LOG(DEBUG, TAG, "IN SRPUnlinkDevice2CB");
1008     VERIFY_NON_NULL(TAG, unlinkCtx, ERROR, OC_STACK_DELETE_TRANSACTION);
1009     UnlinkData_t* unlinkData = (UnlinkData_t*)unlinkCtx;
1010
1011     if (clientResponse)
1012     {
1013         OC_LOG(DEBUG, TAG, "Valid client response for device 2");
1014         registerResultForUnlinkDevices(unlinkData, clientResponse->result, IDX_SECOND_DEVICE_RES);
1015
1016         if (OC_STACK_RESOURCE_DELETED == clientResponse->result)
1017         {
1018             OC_LOG(DEBUG, TAG, "Credential of device2 revoked");
1019         }
1020         else
1021         {
1022             OC_LOG(ERROR, TAG, "Unable to delete credential information from device 2");
1023             unlinkData->resultCallback(unlinkData->ctx,
1024                                        unlinkData->numOfResults, unlinkData->unlinkRes, true);
1025             goto error;
1026         }
1027     }
1028     else
1029     {
1030         registerResultForUnlinkDevices(unlinkData, OC_STACK_INVALID_REQUEST_HANDLE,
1031                                        IDX_SECOND_DEVICE_RES);
1032         unlinkData->resultCallback(unlinkData->ctx,
1033                                    unlinkData->numOfResults, unlinkData->unlinkRes, true);
1034         OC_LOG(ERROR, TAG, "SRPUnlinkDevice2CB received Null clientResponse");
1035         goto error;
1036     }
1037
1038     //Update provisioning DB when succes case.
1039     if (OC_STACK_OK != PDMUnlinkDevices(&unlinkData->unlinkDev[0].doxm->deviceID,
1040                                        &unlinkData->unlinkDev[1].doxm->deviceID))
1041     {
1042         OC_LOG(FATAL, TAG, "All requests are successfully done but update provisioning DB FAILED.");
1043         registerResultForUnlinkDevices(unlinkData, OC_STACK_INCONSISTENT_DB, IDX_DB_UPDATE_RES);
1044         unlinkData->resultCallback(unlinkData->ctx,
1045                                    unlinkData->numOfResults, unlinkData->unlinkRes, true);
1046         goto error;
1047     }
1048     unlinkData->resultCallback(unlinkData->ctx, unlinkData->numOfResults, unlinkData->unlinkRes,
1049                                false);
1050
1051 error:
1052     DeleteUnlinkData_t(unlinkData);
1053     OC_LOG(DEBUG, TAG, "OUT SRPUnlinkDevice2CB");
1054     return OC_STACK_DELETE_TRANSACTION;
1055
1056 }
1057
1058 /**
1059  * Callback handler of unlink first device.
1060  *
1061  * @param[in] ctx             ctx value passed to callback from calling function.
1062  * @param[in] handle          handle to an invocation
1063  * @param[in] clientResponse  Response from queries to remote servers.
1064  * @return  OC_STACK_DELETE_TRANSACTION to delete the transaction and
1065  *          OC_STACK_KEEP_TRANSACTION to keep it.
1066  */
1067 static OCStackApplicationResult SRPUnlinkDevice1CB(void *unlinkCtx, OCDoHandle handle,
1068         OCClientResponse *clientResponse)
1069 {
1070     OC_LOG_V(INFO, TAG, "Inside SRPUnlinkDevice1CB ");
1071     VERIFY_NON_NULL(TAG, unlinkCtx, ERROR, OC_STACK_DELETE_TRANSACTION);
1072     UnlinkData_t* unlinkData = (UnlinkData_t*)unlinkCtx;
1073     (void) handle;
1074
1075     if (clientResponse)
1076     {
1077         OC_LOG(DEBUG, TAG, "Valid client response for device 1");
1078         registerResultForUnlinkDevices(unlinkData, clientResponse->result, IDX_FIRST_DEVICE_RES);
1079
1080         if (OC_STACK_RESOURCE_DELETED == clientResponse->result)
1081         {
1082             OC_LOG(DEBUG, TAG, "Credential of device 1 is revoked");
1083
1084             // Second revocation request to second device.
1085             OCStackResult res = SendDeleteCredentialRequest((void*)unlinkData, &SRPUnlinkDevice2CB,
1086                                                     &unlinkData->unlinkDev[0],
1087                                                     &unlinkData->unlinkDev[1] /*Dest*/);
1088             OC_LOG_V(DEBUG, TAG, "Credential revocation request device 2, result :: %d",res);
1089             if (OC_STACK_OK != res)
1090             {
1091                  OC_LOG(ERROR, TAG, "Error while sending revocation request for device 2");
1092                  registerResultForUnlinkDevices(unlinkData, OC_STACK_INVALID_REQUEST_HANDLE,
1093                                                 IDX_SECOND_DEVICE_RES);
1094                  unlinkData->resultCallback(unlinkData->ctx,
1095                                             unlinkData->numOfResults, unlinkData->unlinkRes, true);
1096                  goto error;
1097             }
1098             else
1099             {
1100                 OC_LOG(DEBUG, TAG, "Request for credential revocation successfully sent");
1101                 return OC_STACK_DELETE_TRANSACTION;
1102             }
1103         }
1104         else
1105         {
1106             OC_LOG(ERROR, TAG, "Unable to delete credential information from device 1");
1107
1108             unlinkData->resultCallback(unlinkData->ctx, unlinkData->numOfResults,
1109                                             unlinkData->unlinkRes, true);
1110             goto error;
1111         }
1112     }
1113     else
1114     {
1115         OC_LOG(DEBUG, TAG, "Invalid response from server");
1116         registerResultForUnlinkDevices(unlinkData, OC_STACK_INVALID_REQUEST_HANDLE,
1117                                        IDX_FIRST_DEVICE_RES );
1118         unlinkData->resultCallback(unlinkData->ctx,
1119                                    unlinkData->numOfResults, unlinkData->unlinkRes,
1120                                    true);
1121         OC_LOG(ERROR, TAG, "SRPUnlinkDevice1CB received Null clientResponse");
1122     }
1123
1124 error:
1125     OC_LOG_V(INFO, TAG, "Out SRPUnlinkDevice1CB");
1126     DeleteUnlinkData_t(unlinkData);
1127     return OC_STACK_DELETE_TRANSACTION;
1128 }
1129
1130 /*
1131 * Function to unlink devices.
1132 * This function will remove the credential & relationship between the two devices.
1133 *
1134 * @param[in] ctx Application context would be returned in result callback
1135 * @param[in] pTargetDev1 first device information to be unlinked.
1136 * @param[in] pTargetDev2 second device information to be unlinked.
1137 * @param[in] resultCallback callback provided by API user, callback will be called when
1138 *            device unlink is finished.
1139  * @return  OC_STACK_OK in case of success and other value otherwise.
1140 */
1141 OCStackResult SRPUnlinkDevices(void* ctx,
1142                                const OCProvisionDev_t* pTargetDev1,
1143                                const OCProvisionDev_t* pTargetDev2,
1144                                OCProvisionResultCB resultCallback)
1145 {
1146     OC_LOG(INFO, TAG, "IN SRPUnlinkDevices");
1147
1148     if (!pTargetDev1 || !pTargetDev2 || !resultCallback)
1149     {
1150         OC_LOG(INFO, TAG, "SRPUnlinkDevices : NULL parameters");
1151         return OC_STACK_INVALID_PARAM;
1152     }
1153     OC_LOG(INFO, TAG, "Unlinking following devices: ");
1154     PMPrintOCProvisionDev(pTargetDev1);
1155     PMPrintOCProvisionDev(pTargetDev2);
1156
1157     // Mark the link status stale
1158     OCStackResult res = PDMSetLinkStale(&pTargetDev1->doxm->deviceID, &pTargetDev2->doxm->deviceID);
1159     if (OC_STACK_OK != res)
1160     {
1161         OC_LOG(FATAL, TAG, "unable to update DB. Try again.");
1162         return res;
1163     }
1164
1165     UnlinkData_t* unlinkData = (UnlinkData_t*)OICCalloc(1, sizeof(UnlinkData_t));
1166     VERIFY_NON_NULL(TAG, unlinkData, ERROR, OC_STACK_NO_MEMORY);
1167
1168     //Initialize unlink data
1169     unlinkData->ctx = ctx;
1170     unlinkData->unlinkDev = (OCProvisionDev_t*)OICCalloc(2, sizeof(OCProvisionDev_t));
1171     if (NULL == unlinkData->unlinkDev)
1172     {
1173         OC_LOG(ERROR, TAG, "Memory allocation failed");
1174         res = OC_STACK_NO_MEMORY;
1175         goto error;
1176     }
1177
1178     unlinkData->unlinkRes = (OCProvisionResult_t*)OICCalloc(3, sizeof(OCProvisionResult_t));
1179     if (NULL == unlinkData->unlinkRes)
1180     {
1181         OC_LOG(ERROR, TAG, "Memory allocation failed");
1182         res = OC_STACK_NO_MEMORY;
1183         goto error;
1184     }
1185
1186     memcpy(&unlinkData->unlinkDev[0], pTargetDev1, sizeof(OCProvisionDev_t));
1187     memcpy(&unlinkData->unlinkDev[1], pTargetDev2, sizeof(OCProvisionDev_t));
1188
1189     unlinkData->numOfResults = 0;
1190     unlinkData->resultCallback = resultCallback;
1191
1192     res = SendDeleteCredentialRequest((void*)unlinkData, &SRPUnlinkDevice1CB,
1193                                        &unlinkData->unlinkDev[1], &unlinkData->unlinkDev[0]);
1194     if (OC_STACK_OK != res)
1195     {
1196         OC_LOG(ERROR, TAG, "SRPUnlinkDevices : SendDeleteCredentialRequest failed");
1197         goto error;
1198     }
1199
1200     return res;
1201
1202 error:
1203     OC_LOG(INFO, TAG, "OUT SRPUnlinkDevices");
1204     DeleteUnlinkData_t(unlinkData);
1205     return res;
1206 }
1207
1208 static void DeleteRemoveData_t(RemoveData_t* pRemoveData)
1209 {
1210     if (pRemoveData)
1211     {
1212         OICFree(pRemoveData->revokeTargetDev);
1213         OCDeleteDiscoveredDevices(pRemoveData->linkedDevList);
1214         OICFree(pRemoveData->removeRes);
1215         OICFree(pRemoveData);
1216     }
1217 }
1218
1219 static void registerResultForRemoveDevice(RemoveData_t *removeData, OicUuid_t *pLinkedDevId,
1220                                           OCStackResult stackresult, bool hasError)
1221 {
1222     OC_LOG_V(INFO, TAG, "Inside registerResultForRemoveDevice removeData->numOfResults is %zu\n",
1223                          removeData->numOfResults + 1);
1224     if (pLinkedDevId)
1225     {
1226         memcpy(removeData->removeRes[(removeData->numOfResults)].deviceId.id,
1227                &pLinkedDevId->id, sizeof(pLinkedDevId->id));
1228     }
1229     else
1230     {
1231         memset(removeData->removeRes[(removeData->numOfResults)].deviceId.id,
1232                0, sizeof(pLinkedDevId->id) );
1233     }
1234     removeData->removeRes[(removeData->numOfResults)].res = stackresult;
1235     removeData->hasError = hasError;
1236     ++(removeData->numOfResults);
1237
1238     // If we get suffcient result from linked devices, we have to call user callback and do free
1239     if (removeData->sizeOfResArray == removeData->numOfResults)
1240     {
1241         removeData->resultCallback(removeData->ctx, removeData->numOfResults, removeData->removeRes,
1242                                    removeData->hasError);
1243         DeleteRemoveData_t(removeData);
1244     }
1245  }
1246
1247 /**
1248  * Callback handler of unlink first device.
1249  *
1250  * @param[in] ctx             ctx value passed to callback from calling function.
1251  * @param[in] handle          handle to an invocation
1252  * @param[in] clientResponse  Response from queries to remote servers.
1253  * @return  OC_STACK_DELETE_TRANSACTION to delete the transaction
1254  *          and  OC_STACK_KEEP_TRANSACTION to keep it.
1255  */
1256 static OCStackApplicationResult SRPRemoveDeviceCB(void *delDevCtx, OCDoHandle handle,
1257         OCClientResponse *clientResponse)
1258 {
1259     //Update the delete credential into delete device context
1260     //Save the deleted status in delDevCtx
1261     (void)handle;
1262     OC_LOG_V(INFO, TAG, "Inside SRPRemoveDeviceCB.");
1263     VERIFY_NON_NULL(TAG, delDevCtx, ERROR, OC_STACK_DELETE_TRANSACTION);
1264     OCStackResult res = OC_STACK_ERROR;
1265
1266     RemoveData_t* removeData = (RemoveData_t*)delDevCtx;
1267     if (clientResponse)
1268     {
1269         // If we can get device's UUID from OCClientResponse, it'd be good to use it in here
1270         // but OCIdentity in OCClientResponse is emtpy now.
1271         // It seems that we can set identity to CAData_t *cadata in CAPrepareSendData() API
1272         // but CA doesn't have deviceID yet.
1273         //
1274         //TODO: Get OCIdentity from OCClientResponse and use it for 'registerResultForRemoveDevice'
1275         //      If we can't complete this task, Provisioning Database has always stale link status
1276         //      when Remove device is called.
1277
1278         if (OC_STACK_RESOURCE_DELETED == clientResponse->result)
1279         {
1280             res = PDMUnlinkDevices(&removeData->revokeTargetDev->doxm->deviceID,
1281                                    NULL /*TODO: Replace NULL to uuid from OCClientResponse*/);
1282             if (OC_STACK_OK != res)
1283             {
1284                 OC_LOG(FATAL, TAG, "PDMSetLinkStale() FAIL: PDB is an obsolete one.");
1285                 registerResultForRemoveDevice(removeData,
1286                                           NULL /*TODO: Replace NULL to uuid from OCClientResponse*/,
1287                                           OC_STACK_INCONSISTENT_DB, true);
1288                 return OC_STACK_DELETE_TRANSACTION;
1289             }
1290             registerResultForRemoveDevice(removeData,
1291                                           NULL /*TODO: Replace NULL to uuid from OCClientResponse*/,
1292                                           OC_STACK_RESOURCE_DELETED, false);
1293         }
1294         else
1295         {
1296             registerResultForRemoveDevice(removeData,
1297                                           NULL /*TODO: Replace NULL to uuid from OCClientResponse*/,
1298                                           clientResponse->result, true);
1299             OC_LOG(ERROR, TAG, "Unexpected result from DELETE credential request!");
1300         }
1301     }
1302     else
1303     {
1304         registerResultForRemoveDevice(removeData, NULL, OC_STACK_ERROR, true);
1305         OC_LOG(ERROR, TAG, "SRPRemoveDevices received Null clientResponse");
1306     }
1307
1308     return OC_STACK_DELETE_TRANSACTION;
1309 }
1310
1311 static OCStackResult GetListofDevToReqDeleteCred(const OCProvisionDev_t* pRevokeTargetDev,
1312                                                  OCProvisionDev_t* pOwnedDevList,
1313                                                  OCUuidList_t* pLinkedUuidList,
1314                                                  OCProvisionDev_t** ppLinkedDevList,
1315                                                  size_t *numOfLinkedDev)
1316 {
1317     // pOwnedDevList could be NULL. It means no alived and owned device now.
1318     if (pRevokeTargetDev == NULL || pLinkedUuidList == NULL ||\
1319         ppLinkedDevList == NULL || numOfLinkedDev == NULL)
1320     {
1321         return OC_STACK_INVALID_PARAM;
1322     }
1323
1324     size_t cnt = 0;
1325     OCUuidList_t *curUuid = NULL, *tmpUuid = NULL;
1326     LL_FOREACH_SAFE(pLinkedUuidList, curUuid, tmpUuid)
1327     {
1328         // Mark the link status stale.
1329         OCStackResult res = PDMSetLinkStale(&curUuid->dev, &pRevokeTargetDev->doxm->deviceID);
1330         if (OC_STACK_OK != res)
1331         {
1332             OC_LOG(FATAL, TAG, "PDMSetLinkStale() FAIL: PDB is an obsolete one.");
1333             return OC_STACK_INCONSISTENT_DB;
1334         }
1335
1336         if (pOwnedDevList)
1337         {
1338             // If this linked device is alive (power-on), add the deivce to the list.
1339             OCProvisionDev_t *curDev = NULL, *tmpDev = NULL;
1340             LL_FOREACH_SAFE(pOwnedDevList, curDev, tmpDev)
1341             {
1342                 if (memcmp(curDev->doxm->deviceID.id, curUuid->dev.id, sizeof(curUuid->dev.id)) == 0)
1343                 {
1344                     OCProvisionDev_t* targetDev = PMCloneOCProvisionDev(curDev);
1345                     if (NULL == targetDev)
1346                     {
1347                         OC_LOG(ERROR, TAG, "SRPRemoveDevice : Cloning OCProvisionDev_t Failed.");
1348                         return OC_STACK_NO_MEMORY;
1349                     }
1350
1351                     LL_PREPEND(*ppLinkedDevList, targetDev);
1352                     cnt++;
1353                     break;
1354                 }
1355             }
1356         }
1357     }
1358     *numOfLinkedDev = cnt;
1359     return OC_STACK_OK;
1360 }
1361
1362 /*
1363 * Function to device revocation
1364 * This function will remove credential of target device from all devices in subnet.
1365 *
1366 * @param[in] ctx Application context would be returned in result callback
1367 * @param[in] waitTimeForOwnedDeviceDiscovery Maximum wait time for owned device discovery.(seconds)
1368 * @param[in] pTargetDev Device information to be revoked.
1369 * @param[in] resultCallback callback provided by API user, callback will be called when
1370 *            credential revocation is finished.
1371 * @return  OC_STACK_OK in case of success and other value otherwise.
1372 *          If OC_STACK_OK is returned, the caller of this API should wait for callback.
1373 *          OC_STACK_CONTINUE means operation is success but no request is need to be initiated.
1374 */
1375 OCStackResult SRPRemoveDevice(void* ctx, unsigned short waitTimeForOwnedDeviceDiscovery,
1376                              const OCProvisionDev_t* pTargetDev, OCProvisionResultCB resultCallback)
1377 {
1378     OC_LOG(INFO, TAG, "IN SRPRemoveDevice");
1379
1380     if (!pTargetDev || !resultCallback || 0 == waitTimeForOwnedDeviceDiscovery)
1381     {
1382         OC_LOG(INFO, TAG, "SRPRemoveDevice : NULL parameters");
1383         return OC_STACK_INVALID_PARAM;
1384     }
1385
1386     // Declare variables in here to handle error cases with goto statement.
1387     OCProvisionDev_t* pOwnedDevList = NULL;
1388     OCProvisionDev_t* pLinkedDevList = NULL;
1389     RemoveData_t* removeData = NULL;
1390
1391     //1. Find all devices that has a credential of the revoked device
1392     OCUuidList_t* pLinkedUuidList = NULL;
1393     size_t numOfDevices = 0;
1394     OCStackResult res = OC_STACK_ERROR;
1395     res = PDMGetLinkedDevices(&pTargetDev->doxm->deviceID, &pLinkedUuidList, &numOfDevices);
1396     if (OC_STACK_OK != res)
1397     {
1398         OC_LOG(ERROR, TAG, "SRPRemoveDevice : Failed to get linked devices information");
1399         return res;
1400     }
1401     // if there is no related device, we can skip further process.
1402     if (0 == numOfDevices)
1403     {
1404         OC_LOG(DEBUG, TAG, "SRPRemoveDevice : No linked device found.");
1405         res = OC_STACK_CONTINUE;
1406         goto error;
1407     }
1408
1409     //2. Find owned device from the network
1410     res = PMDeviceDiscovery(waitTimeForOwnedDeviceDiscovery, true, &pOwnedDevList);
1411     if (OC_STACK_OK != res)
1412     {
1413         OC_LOG(ERROR, TAG, "SRPRemoveDevice : Failed to PMDeviceDiscovery");
1414         goto error;
1415     }
1416
1417     //3. Make a list of devices to send DELETE credential request
1418     //   by comparing owned devices from provisioning database with mutlicast discovery result.
1419     size_t numOfLinkedDev = 0;
1420     res = GetListofDevToReqDeleteCred(pTargetDev, pOwnedDevList, pLinkedUuidList,
1421                                       &pLinkedDevList, &numOfLinkedDev);
1422     if (OC_STACK_OK != res)
1423     {
1424         OC_LOG(ERROR, TAG, "SRPRemoveDevice : GetListofDevToReqDeleteCred() failed");
1425         goto error;
1426     }
1427     if (0 == numOfLinkedDev) // This case means, there is linked device but it's not alive now.
1428     {                       // So we don't have to send request message.
1429         OC_LOG(DEBUG, TAG, "SRPRemoveDevice : No alived & linked device found.");
1430         res = OC_STACK_CONTINUE;
1431         goto error;
1432     }
1433
1434     // 4. Prepare RemoveData Context data.
1435     removeData = (RemoveData_t*)OICCalloc(1, sizeof(RemoveData_t));
1436     if (!removeData)
1437     {
1438         OC_LOG(ERROR, TAG, "SRPRemoveDevices : Failed to memory allocation");
1439         res = OC_STACK_NO_MEMORY;
1440         goto error;
1441     }
1442
1443     removeData->revokeTargetDev = PMCloneOCProvisionDev(pTargetDev);
1444     if (!removeData->revokeTargetDev)
1445     {
1446         OC_LOG(ERROR, TAG, "SRPRemoveDevices : PMCloneOCProvisionDev Failed");
1447         res = OC_STACK_NO_MEMORY;
1448         goto error;
1449     }
1450
1451     removeData->removeRes =
1452         (OCProvisionResult_t*)OICCalloc(numOfLinkedDev, sizeof(OCProvisionResult_t));
1453     if (!removeData->removeRes)
1454     {
1455         OC_LOG(ERROR, TAG, "SRPRemoveDevices : Failed to memory allocation");
1456         res = OC_STACK_NO_MEMORY;
1457         goto error;
1458     }
1459
1460     removeData->ctx = ctx;
1461     removeData->linkedDevList = pLinkedDevList;
1462     removeData->resultCallback = resultCallback;
1463     removeData->numOfResults = 0;
1464     removeData->sizeOfResArray = numOfLinkedDev;
1465     removeData->hasError = false;
1466
1467     // 5. Send DELETE credential request to linked devices.
1468     OCProvisionDev_t *curDev = NULL, *tmpDev = NULL;
1469     OCStackResult totalRes = OC_STACK_ERROR;  /* variable for checking request is sent or not */
1470     LL_FOREACH_SAFE(pLinkedDevList, curDev, tmpDev)
1471     {
1472         res = SendDeleteCredentialRequest((void*)removeData, &SRPRemoveDeviceCB,
1473                                            removeData->revokeTargetDev, curDev);
1474         if (OC_STACK_OK != res)
1475         {
1476             OC_LOG_V(ERROR, TAG, "SRPRemoveDevice : Fail to send the DELETE credential request to\
1477                      %s:%u", curDev->endpoint.addr, curDev->endpoint.port);
1478         }
1479         else
1480         {
1481             totalRes = OC_STACK_OK; // This means at least one request is successfully sent.
1482         }
1483     }
1484
1485     PDMDestoryOicUuidLinkList(pLinkedUuidList); //TODO: Modify API name to have unified convention.
1486     PMDeleteDeviceList(pOwnedDevList);
1487     OC_LOG(INFO, TAG, "OUT SRPRemoveDevice");
1488
1489     return totalRes; // Caller of this API should wait callback if totalRes == OC_STACK_OK.
1490
1491 error:
1492     PDMDestoryOicUuidLinkList(pLinkedUuidList);
1493     PMDeleteDeviceList(pOwnedDevList);
1494     PMDeleteDeviceList(pLinkedDevList);
1495     if (removeData)
1496     {
1497         OICFree(removeData->revokeTargetDev);
1498         OICFree(removeData->removeRes);
1499         OICFree(removeData);
1500     }
1501     OC_LOG(INFO, TAG, "OUT ERROR case SRPRemoveDevice");
1502     return res;
1503 }