Merge branch 'security-CKM' into 'master'
[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     VERIFY_NON_NULL(TAG, pDev2, ERROR,  OC_STACK_INVALID_PARAM);
622     VERIFY_NON_NULL(TAG, resultCallback, ERROR,  OC_STACK_INVALID_CALLBACK);
623
624     if (!(keySize == OWNER_PSK_LENGTH_128 || keySize == OWNER_PSK_LENGTH_256))
625     {
626         OC_LOG(INFO, TAG, "Invalid key size");
627         return OC_STACK_INVALID_PARAM;
628     }
629
630     OC_LOG(INFO, TAG, "In SRPProvisionCredentials");
631
632     OicUuid_t provTooldeviceID =   {{0,}};
633     if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID))
634     {
635         OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
636         return OC_STACK_ERROR;
637     }
638     OC_LOG(INFO, TAG, "retrieved deviceid");
639     switch (type)
640     {
641         case SYMMETRIC_PAIR_WISE_KEY:
642         {
643             const OCProvisionDev_t *firstDevice = pDev1;
644             const OCProvisionDev_t *secondDevice = pDev2;
645
646             OicSecCred_t *firstCred = NULL;
647             OicSecCred_t *secondCred = NULL;
648             OCStackResult res = PMGeneratePairWiseCredentials(type, keySize, &provTooldeviceID,
649                     &firstDevice->doxm->deviceID, &secondDevice->doxm->deviceID,
650                     &firstCred, &secondCred);
651             VERIFY_SUCCESS(TAG, (res==OC_STACK_OK), ERROR, OC_STACK_ERROR);
652             OC_LOG(INFO, TAG, "Credentials generated successfully");
653             CredentialData_t *credData = (CredentialData_t *) OICMalloc(sizeof(CredentialData_t));
654             if (NULL == credData)
655             {
656                 OC_LOG(ERROR, TAG, "Memory allocation problem");
657                 return OC_STACK_NO_MEMORY;
658             }
659             memset(credData, 0x00, sizeof(CredentialData_t));
660             credData->deviceInfo1 = firstDevice;
661             credData->deviceInfo2 = secondDevice;
662             credData->credInfo = secondCred;
663             credData->ctx = ctx;
664             credData->credInfoFirst = firstCred;
665             credData->numOfResults = 0;
666             credData->resultCallback = resultCallback;
667             // first call to provision creds to device1.
668             // second call to provision creds to device2.
669             int noOfRiCalls = 2;
670             credData->resArr =
671                 (OCProvisionResult_t*)OICMalloc(sizeof(OCProvisionResult_t) * noOfRiCalls);
672             if (NULL == credData->resArr)
673             {
674                 OC_LOG(ERROR, TAG, "Memory allocation problem");
675                 return OC_STACK_NO_MEMORY;
676             }
677             memset(credData->resArr, 0x00, sizeof(sizeof(OCProvisionResult_t)*noOfRiCalls));
678             res = provisionCredentials(firstCred, firstDevice, credData, &provisionCredentialCB1);
679             if (OC_STACK_OK != res)
680             {
681                 DeleteCredList(firstCred);
682                 DeleteCredList(secondCred);
683                 OICFree(credData->resArr);
684                 OICFree(credData);
685             }
686             OC_LOG_V(INFO, TAG, "provisionCredentials returned: %d",res);
687             VERIFY_SUCCESS(TAG, (res==OC_STACK_OK), ERROR, OC_STACK_ERROR);
688             return res;
689         }
690 #ifdef __WITH_X509__
691         case SIGNED_ASYMMETRIC_KEY:
692         {
693             const OCProvisionDev_t *firstDevice = pDev1;
694             OicSecCred_t *cred = NULL;
695             OCStackResult res = PMGenerateCertificateCredentials(&provTooldeviceID,
696                                                                 &firstDevice->doxm->deviceID,&cred);
697             VERIFY_SUCCESS(TAG, (res==OC_STACK_OK), ERROR, OC_STACK_ERROR);
698             OC_LOG(INFO, TAG, "Certificate credentials generated successfully");
699             CertData_t *certData = (CertData_t *) OICCalloc(1, sizeof(CertData_t));
700             if (NULL == certData)
701             {
702                 OC_LOG(ERROR, TAG, "Memory allocation problem");
703                 return OC_STACK_NO_MEMORY;
704             }
705
706             certData->deviceInfo = firstDevice;
707             certData->ctx = ctx;
708             certData->credInfo = cred;
709             certData->numOfResults = 0;
710             certData->resultCallback = resultCallback;
711
712             certData->resArr = (OCProvisionResult_t*)OICCalloc(1, sizeof(OCProvisionResult_t));
713             if (NULL == certData->resArr)
714             {
715                 DeleteCredList(cred);
716                 OICFree(certData);
717                 OC_LOG(ERROR, TAG, "Memory allocation problem");
718                 return OC_STACK_NO_MEMORY;
719             }
720
721             res = provisionCertCred(cred, firstDevice, certData, &provisionCertCB);
722             if (OC_STACK_OK != res)
723             {
724                 OICFree(certData->resArr);
725                 OICFree(certData);
726             }
727             DeleteCredList(cred);
728             OC_LOG_V(INFO, TAG, "provisionCertCredentials returned: %d",res);
729
730             return res;
731         }
732 #endif
733         default:
734         {
735             OC_LOG(ERROR, TAG, "Invalid option.");
736             return OC_STACK_INVALID_PARAM;
737         }
738     }
739     return OC_STACK_ERROR;
740 }
741
742 /**
743  * Internal Function to store results in result array during ACL provisioning.
744  */
745 static void registerResultForACLProvisioning(ACLData_t *aclData,
746                                              OCStackResult stackresult)
747 {
748    OC_LOG_V(INFO, TAG, "Inside registerResultForACLProvisioning aclData->numOfResults is %d\n",
749                        aclData->numOfResults);
750    memcpy(aclData->resArr[(aclData->numOfResults)].deviceId.id,
751           aclData->deviceInfo->doxm->deviceID.id, UUID_LENGTH);
752    aclData->resArr[(aclData->numOfResults)].res = stackresult;
753    ++(aclData->numOfResults);
754 }
755
756 /**
757  * Callback handler of SRPProvisionACL.
758  *
759  * @param[in] ctx             ctx value passed to callback from calling function.
760  * @param[in] UNUSED          handle to an invocation
761  * @param[in] clientResponse  Response from queries to remote servers.
762  * @return  OC_STACK_DELETE_TRANSACTION to delete the transaction
763  *          and  OC_STACK_KEEP_TRANSACTION to keep it.
764  */
765 static OCStackApplicationResult SRPProvisionACLCB(void *ctx, OCDoHandle UNUSED,
766                                                   OCClientResponse *clientResponse)
767 {
768     OC_LOG_V(INFO, TAG, "Inside SRPProvisionACLCB.");
769     (void)UNUSED;
770     VERIFY_NON_NULL(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
771     ACLData_t *aclData = (ACLData_t*)ctx;
772     OCProvisionResultCB resultCallback = aclData->resultCallback;
773
774     if (clientResponse)
775     {
776         if(OC_STACK_RESOURCE_CREATED == clientResponse->result)
777         {
778             registerResultForACLProvisioning(aclData, OC_STACK_RESOURCE_CREATED);
779             ((OCProvisionResultCB)(resultCallback))(aclData->ctx, aclData->numOfResults,
780                                                     aclData->resArr,
781                                                     false);
782              OICFree(aclData->resArr);
783              OICFree(aclData);
784              return OC_STACK_DELETE_TRANSACTION;
785         }
786     }
787     registerResultForACLProvisioning(aclData, OC_STACK_ERROR);
788     ((OCProvisionResultCB)(resultCallback))(aclData->ctx, aclData->numOfResults,
789                                             aclData->resArr,
790                                             true);
791     OC_LOG_V(ERROR, TAG, "SRPProvisionACLCB received Null clientResponse");
792     OICFree(aclData->resArr);
793     OICFree(aclData);
794     return OC_STACK_DELETE_TRANSACTION;
795 }
796
797 OCStackResult SRPProvisionACL(void *ctx, const OCProvisionDev_t *selectedDeviceInfo,
798         OicSecAcl_t *acl, OCProvisionResultCB resultCallback)
799 {
800     VERIFY_NON_NULL(TAG, selectedDeviceInfo, ERROR,  OC_STACK_INVALID_PARAM);
801     VERIFY_NON_NULL(TAG, acl, ERROR,  OC_STACK_INVALID_PARAM);
802     VERIFY_NON_NULL(TAG, resultCallback, ERROR,  OC_STACK_INVALID_CALLBACK);
803
804     OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
805     if(!secPayload)
806     {
807         OC_LOG(ERROR, TAG, "Failed to memory allocation");
808         return OC_STACK_NO_MEMORY;
809     }
810     secPayload->base.type = PAYLOAD_TYPE_SECURITY;
811     secPayload->securityData = BinToAclJSON(acl);
812     if(NULL == secPayload->securityData)
813     {
814         OICFree(secPayload);
815         OC_LOG(ERROR, TAG, "Failed to BinToAclJSON");
816         return OC_STACK_NO_MEMORY;
817     }
818     OC_LOG_V(INFO, TAG, "ACL : %s", secPayload->securityData);
819
820     char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
821     if(!PMGenerateQuery(true,
822                         selectedDeviceInfo->endpoint.addr,
823                         selectedDeviceInfo->securePort,
824                         selectedDeviceInfo->connType,
825                         query, sizeof(query), OIC_RSRC_ACL_URI))
826     {
827         OC_LOG(ERROR, TAG, "DeviceDiscoveryHandler : Failed to generate query");
828         return OC_STACK_ERROR;
829     }
830     OC_LOG_V(DEBUG, TAG, "Query=%s", query);
831
832     OCCallbackData cbData =  {.context=NULL, .cb=NULL, .cd=NULL};
833     cbData.cb = &SRPProvisionACLCB;
834     ACLData_t *aclData = (ACLData_t *) OICMalloc(sizeof(ACLData_t));
835     if (aclData == NULL)
836     {
837         OICFree(secPayload);
838         OC_LOG(ERROR, TAG, "Unable to allocate memory");
839         return OC_STACK_NO_MEMORY;
840     }
841     memset(aclData, 0x00, sizeof(ACLData_t));
842     aclData->deviceInfo = selectedDeviceInfo;
843     aclData->resultCallback = resultCallback;
844     aclData->numOfResults=0;
845     aclData->ctx = ctx;
846     // call to provision ACL to device1.
847     int noOfRiCalls = 1;
848     aclData->resArr = (OCProvisionResult_t*)OICMalloc(sizeof(OCProvisionResult_t)*noOfRiCalls);
849     if (aclData->resArr == NULL)
850     {
851         OICFree(secPayload);
852         OC_LOG(ERROR, TAG, "Unable to allocate memory");
853         return OC_STACK_NO_MEMORY;
854     }
855     memset(aclData->resArr, 0x00, sizeof(sizeof(OCProvisionResult_t)*noOfRiCalls));
856     cbData.context = (void *)aclData;
857     cbData.cd = NULL;
858     OCMethod method = OC_REST_POST;
859     OCDoHandle handle = NULL;
860     OC_LOG(DEBUG, TAG, "Sending ACL info to resource server");
861     OCStackResult ret = OCDoResource(&handle, method, query,
862             &selectedDeviceInfo->endpoint, (OCPayload*)secPayload,
863             selectedDeviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0);
864     if (ret != OC_STACK_OK)
865     {
866         OICFree(aclData->resArr);
867         OICFree(aclData);
868     }
869     VERIFY_SUCCESS(TAG, (OC_STACK_OK == ret), ERROR, OC_STACK_ERROR);
870     return OC_STACK_OK;
871 }
872
873 static void DeleteUnlinkData_t(UnlinkData_t *unlinkData)
874 {
875     if (unlinkData)
876     {
877         OICFree(unlinkData->unlinkDev);
878         OICFree(unlinkData->unlinkRes);
879         OICFree(unlinkData);
880     }
881 }
882
883 static void registerResultForUnlinkDevices(UnlinkData_t *unlinkData, OCStackResult stackresult,
884                                            IdxUnlinkRes_t idx)
885 {
886     if (NULL != unlinkData)
887     {
888         OC_LOG_V(INFO, TAG, "Inside registerResultForUnlinkDevices unlinkData->numOfResults is %d\n",
889                             unlinkData->numOfResults);
890         OC_LOG_V(INFO, TAG, "Stack result :: %d", stackresult);
891
892         OicUuid_t *pUuid = &unlinkData->unlinkRes[(unlinkData->numOfResults)].deviceId;
893
894         // Set result in the result array according to the position (devNum).
895         if (idx != IDX_DB_UPDATE_RES)
896         {
897             memcpy(pUuid->id, unlinkData->unlinkDev[idx].doxm->deviceID.id, sizeof(pUuid->id));
898         }
899         else
900         {   // When deivce ID is 000... this means it's the result of database update.
901             memset(pUuid->id, 0, sizeof(pUuid->id));
902         }
903         unlinkData->unlinkRes[(unlinkData->numOfResults)].res = stackresult;
904         ++(unlinkData->numOfResults);
905         OC_LOG (INFO, TAG, "Out registerResultForUnlinkDevices");
906     }
907 }
908
909 static OCStackResult SendDeleteCredentialRequest(void* ctx,
910                                                  OCClientResponseHandler respHandler,
911                                                  const OCProvisionDev_t* revokedDev,
912                                                  const OCProvisionDev_t* destDev)
913 {
914     OC_LOG(DEBUG, TAG, "IN SendDeleteCredentialRequest");
915
916     if (NULL == ctx || NULL == respHandler || NULL == revokedDev || NULL == destDev)
917     {
918         return OC_STACK_INVALID_PARAM;
919     }
920
921     char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(revokedDev->doxm->deviceID.id)) + 1] = {};
922     uint32_t base64Len = 0;
923     if (B64_OK != b64Encode(revokedDev->doxm->deviceID.id, sizeof(revokedDev->doxm->deviceID.id),
924                            base64Buff, sizeof(base64Buff), &base64Len))
925     {
926         OC_LOG(ERROR, TAG, "SendDeleteCredentialRequest : Failed to base64 encoding");
927         return OC_STACK_ERROR;
928     }
929
930     char reqBuf[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
931     int snRet = 0;
932                     //coaps://0.0.0.0:5684/oic/sec/cred?sub=(BASE64 ENCODED UUID)
933     snRet = snprintf(reqBuf, sizeof(reqBuf), SRP_FORM_DELETE_CREDENTIAL, destDev->endpoint.addr,
934                      destDev->securePort, OIC_RSRC_CRED_URI, OIC_JSON_SUBJECT_NAME, base64Buff);
935     if (snRet < 0)
936     {
937         OC_LOG_V(ERROR, TAG, "SendDeleteCredentialRequest : Error (snprintf) %d\n", snRet);
938         return OC_STACK_ERROR;
939     }
940     else if ((size_t)snRet >= sizeof(reqBuf))
941     {
942         OC_LOG_V(ERROR, TAG, "SendDeleteCredentialRequest : Truncated (snprintf) %d\n", snRet);
943         return OC_STACK_ERROR;
944     }
945
946     OCCallbackData cbData;
947     memset(&cbData, 0, sizeof(cbData));
948     cbData.context = ctx;
949     cbData.cb = respHandler;
950     cbData.cd = NULL;
951     OC_LOG_V(INFO, TAG, "URI: %s",reqBuf);
952
953     OC_LOG(DEBUG, TAG, "Sending remove credential request to resource server");
954
955     OCStackResult ret = OCDoResource(NULL, OC_REST_DELETE, reqBuf,
956                                      &destDev->endpoint, NULL,
957                                      CT_ADAPTER_IP, OC_HIGH_QOS, &cbData, NULL, 0);
958     if (OC_STACK_OK != ret)
959     {
960         OC_LOG_V(ERROR, TAG, "SendDeleteCredentialRequest : Error in OCDoResource %d", ret);
961     }
962     OC_LOG(DEBUG, TAG, "OUT SendDeleteCredentialRequest");
963
964     return ret;
965 }
966
967 /**
968  * Callback handler of unlink second device.
969  *
970  * @param[in] ctx             ctx value passed to callback from calling function.
971  * @param[in] handle          handle to an invocation
972  * @param[in] clientResponse  Response from queries to remote servers.
973  * @return  OC_STACK_DELETE_TRANSACTION to delete the transaction and
974  *          OC_STACK_KEEP_TRANSACTION to keep it.
975  */
976 static OCStackApplicationResult SRPUnlinkDevice2CB(void *unlinkCtx, OCDoHandle handle,
977         OCClientResponse *clientResponse)
978 {
979     (void) handle;
980     OC_LOG(DEBUG, TAG, "IN SRPUnlinkDevice2CB");
981     VERIFY_NON_NULL(TAG, unlinkCtx, ERROR, OC_STACK_DELETE_TRANSACTION);
982     UnlinkData_t* unlinkData = (UnlinkData_t*)unlinkCtx;
983
984     if (clientResponse)
985     {
986         OC_LOG(DEBUG, TAG, "Valid client response for device 2");
987         registerResultForUnlinkDevices(unlinkData, clientResponse->result, IDX_SECOND_DEVICE_RES);
988
989         if (OC_STACK_RESOURCE_DELETED == clientResponse->result)
990         {
991             OC_LOG(DEBUG, TAG, "Credential of device2 revoked");
992         }
993         else
994         {
995             OC_LOG(ERROR, TAG, "Unable to delete credential information from device 2");
996             unlinkData->resultCallback(unlinkData->ctx,
997                                        unlinkData->numOfResults, unlinkData->unlinkRes, true);
998             goto error;
999         }
1000     }
1001     else
1002     {
1003         registerResultForUnlinkDevices(unlinkData, OC_STACK_INVALID_REQUEST_HANDLE,
1004                                        IDX_SECOND_DEVICE_RES);
1005         unlinkData->resultCallback(unlinkData->ctx,
1006                                    unlinkData->numOfResults, unlinkData->unlinkRes, true);
1007         OC_LOG(ERROR, TAG, "SRPUnlinkDevice2CB received Null clientResponse");
1008         goto error;
1009     }
1010
1011     //Update provisioning DB when succes case.
1012     if (OC_STACK_OK != PDMUnlinkDevices(&unlinkData->unlinkDev[0].doxm->deviceID,
1013                                        &unlinkData->unlinkDev[1].doxm->deviceID))
1014     {
1015         OC_LOG(FATAL, TAG, "All requests are successfully done but update provisioning DB FAILED.");
1016         registerResultForUnlinkDevices(unlinkData, OC_STACK_INCONSISTENT_DB, IDX_DB_UPDATE_RES);
1017         unlinkData->resultCallback(unlinkData->ctx,
1018                                    unlinkData->numOfResults, unlinkData->unlinkRes, true);
1019         goto error;
1020     }
1021     unlinkData->resultCallback(unlinkData->ctx, unlinkData->numOfResults, unlinkData->unlinkRes,
1022                                false);
1023
1024 error:
1025     DeleteUnlinkData_t(unlinkData);
1026     OC_LOG(DEBUG, TAG, "OUT SRPUnlinkDevice2CB");
1027     return OC_STACK_DELETE_TRANSACTION;
1028
1029 }
1030
1031 /**
1032  * Callback handler of unlink first device.
1033  *
1034  * @param[in] ctx             ctx value passed to callback from calling function.
1035  * @param[in] handle          handle to an invocation
1036  * @param[in] clientResponse  Response from queries to remote servers.
1037  * @return  OC_STACK_DELETE_TRANSACTION to delete the transaction and
1038  *          OC_STACK_KEEP_TRANSACTION to keep it.
1039  */
1040 static OCStackApplicationResult SRPUnlinkDevice1CB(void *unlinkCtx, OCDoHandle handle,
1041         OCClientResponse *clientResponse)
1042 {
1043     OC_LOG_V(INFO, TAG, "Inside SRPUnlinkDevice1CB ");
1044     VERIFY_NON_NULL(TAG, unlinkCtx, ERROR, OC_STACK_DELETE_TRANSACTION);
1045     UnlinkData_t* unlinkData = (UnlinkData_t*)unlinkCtx;
1046     (void) handle;
1047
1048     if (clientResponse)
1049     {
1050         OC_LOG(DEBUG, TAG, "Valid client response for device 1");
1051         registerResultForUnlinkDevices(unlinkData, clientResponse->result, IDX_FIRST_DEVICE_RES);
1052
1053         if (OC_STACK_RESOURCE_DELETED == clientResponse->result)
1054         {
1055             OC_LOG(DEBUG, TAG, "Credential of device 1 is revoked");
1056
1057             // Second revocation request to second device.
1058             OCStackResult res = SendDeleteCredentialRequest((void*)unlinkData, &SRPUnlinkDevice2CB,
1059                                                     &unlinkData->unlinkDev[0],
1060                                                     &unlinkData->unlinkDev[1] /*Dest*/);
1061             OC_LOG_V(DEBUG, TAG, "Credential revocation request device 2, result :: %d",res);
1062             if (OC_STACK_OK != res)
1063             {
1064                  OC_LOG(ERROR, TAG, "Error while sending revocation request for device 2");
1065                  registerResultForUnlinkDevices(unlinkData, OC_STACK_INVALID_REQUEST_HANDLE,
1066                                                 IDX_SECOND_DEVICE_RES);
1067                  unlinkData->resultCallback(unlinkData->ctx,
1068                                             unlinkData->numOfResults, unlinkData->unlinkRes, true);
1069                  goto error;
1070             }
1071             else
1072             {
1073                 OC_LOG(DEBUG, TAG, "Request for credential revocation successfully sent");
1074                 return OC_STACK_DELETE_TRANSACTION;
1075             }
1076         }
1077         else
1078         {
1079             OC_LOG(ERROR, TAG, "Unable to delete credential information from device 1");
1080
1081             unlinkData->resultCallback(unlinkData->ctx, unlinkData->numOfResults,
1082                                             unlinkData->unlinkRes, true);
1083             goto error;
1084         }
1085     }
1086     else
1087     {
1088         OC_LOG(DEBUG, TAG, "Invalid response from server");
1089         registerResultForUnlinkDevices(unlinkData, OC_STACK_INVALID_REQUEST_HANDLE,
1090                                        IDX_FIRST_DEVICE_RES );
1091         unlinkData->resultCallback(unlinkData->ctx,
1092                                    unlinkData->numOfResults, unlinkData->unlinkRes,
1093                                    true);
1094         OC_LOG(ERROR, TAG, "SRPUnlinkDevice1CB received Null clientResponse");
1095     }
1096
1097 error:
1098     OC_LOG_V(INFO, TAG, "Out SRPUnlinkDevice1CB");
1099     DeleteUnlinkData_t(unlinkData);
1100     return OC_STACK_DELETE_TRANSACTION;
1101 }
1102
1103 /*
1104 * Function to unlink devices.
1105 * This function will remove the credential & relationship between the two devices.
1106 *
1107 * @param[in] ctx Application context would be returned in result callback
1108 * @param[in] pTargetDev1 first device information to be unlinked.
1109 * @param[in] pTargetDev2 second device information to be unlinked.
1110 * @param[in] resultCallback callback provided by API user, callback will be called when
1111 *            device unlink is finished.
1112  * @return  OC_STACK_OK in case of success and other value otherwise.
1113 */
1114 OCStackResult SRPUnlinkDevices(void* ctx,
1115                                const OCProvisionDev_t* pTargetDev1,
1116                                const OCProvisionDev_t* pTargetDev2,
1117                                OCProvisionResultCB resultCallback)
1118 {
1119     OC_LOG(INFO, TAG, "IN SRPUnlinkDevices");
1120
1121     if (!pTargetDev1 || !pTargetDev2 || !resultCallback)
1122     {
1123         OC_LOG(INFO, TAG, "SRPUnlinkDevices : NULL parameters");
1124         return OC_STACK_INVALID_PARAM;
1125     }
1126     OC_LOG(INFO, TAG, "Unlinking following devices: ");
1127     PMPrintOCProvisionDev(pTargetDev1);
1128     PMPrintOCProvisionDev(pTargetDev2);
1129
1130     // Mark the link status stale
1131     OCStackResult res = PDMSetLinkStale(&pTargetDev1->doxm->deviceID, &pTargetDev2->doxm->deviceID);
1132     if (OC_STACK_OK != res)
1133     {
1134         OC_LOG(FATAL, TAG, "unable to update DB. Try again.");
1135         return res;
1136     }
1137
1138     UnlinkData_t* unlinkData = (UnlinkData_t*)OICCalloc(1, sizeof(UnlinkData_t));
1139     VERIFY_NON_NULL(TAG, unlinkData, ERROR, OC_STACK_NO_MEMORY);
1140
1141     //Initialize unlink data
1142     unlinkData->ctx = ctx;
1143     unlinkData->unlinkDev = (OCProvisionDev_t*)OICCalloc(2, sizeof(OCProvisionDev_t));
1144     if (NULL == unlinkData->unlinkDev)
1145     {
1146         OC_LOG(ERROR, TAG, "Memory allocation failed");
1147         res = OC_STACK_NO_MEMORY;
1148         goto error;
1149     }
1150
1151     unlinkData->unlinkRes = (OCProvisionResult_t*)OICCalloc(3, sizeof(OCProvisionResult_t));
1152     if (NULL == unlinkData->unlinkRes)
1153     {
1154         OC_LOG(ERROR, TAG, "Memory allocation failed");
1155         res = OC_STACK_NO_MEMORY;
1156         goto error;
1157     }
1158
1159     memcpy(&unlinkData->unlinkDev[0], pTargetDev1, sizeof(OCProvisionDev_t));
1160     memcpy(&unlinkData->unlinkDev[1], pTargetDev2, sizeof(OCProvisionDev_t));
1161
1162     unlinkData->numOfResults = 0;
1163     unlinkData->resultCallback = resultCallback;
1164
1165     res = SendDeleteCredentialRequest((void*)unlinkData, &SRPUnlinkDevice1CB,
1166                                        &unlinkData->unlinkDev[1], &unlinkData->unlinkDev[0]);
1167     if (OC_STACK_OK != res)
1168     {
1169         OC_LOG(ERROR, TAG, "SRPUnlinkDevices : SendDeleteCredentialRequest failed");
1170         goto error;
1171     }
1172
1173     return res;
1174
1175 error:
1176     OC_LOG(INFO, TAG, "OUT SRPUnlinkDevices");
1177     DeleteUnlinkData_t(unlinkData);
1178     return res;
1179 }
1180
1181 static void DeleteRemoveData_t(RemoveData_t* pRemoveData)
1182 {
1183     if (pRemoveData)
1184     {
1185         OICFree(pRemoveData->revokeTargetDev);
1186         OCDeleteDiscoveredDevices(pRemoveData->linkedDevList);
1187         OICFree(pRemoveData->removeRes);
1188         OICFree(pRemoveData);
1189     }
1190 }
1191
1192 static void registerResultForRemoveDevice(RemoveData_t *removeData, OicUuid_t *pLinkedDevId,
1193                                           OCStackResult stackresult, bool hasError)
1194 {
1195     OC_LOG_V(INFO, TAG, "Inside registerResultForRemoveDevice removeData->numOfResults is %d\n",
1196                          removeData->numOfResults + 1);
1197     if (pLinkedDevId)
1198     {
1199         memcpy(removeData->removeRes[(removeData->numOfResults)].deviceId.id,
1200                &pLinkedDevId->id, sizeof(pLinkedDevId->id));
1201     }
1202     else
1203     {
1204         memset(removeData->removeRes[(removeData->numOfResults)].deviceId.id,
1205                0, sizeof(pLinkedDevId->id) );
1206     }
1207     removeData->removeRes[(removeData->numOfResults)].res = stackresult;
1208     removeData->hasError = hasError;
1209     ++(removeData->numOfResults);
1210
1211     // If we get suffcient result from linked devices, we have to call user callback and do free
1212     if (removeData->sizeOfResArray == removeData->numOfResults)
1213     {
1214         removeData->resultCallback(removeData->ctx, removeData->numOfResults, removeData->removeRes,
1215                                    removeData->hasError);
1216         DeleteRemoveData_t(removeData);
1217     }
1218  }
1219
1220 /**
1221  * Callback handler of unlink first device.
1222  *
1223  * @param[in] ctx             ctx value passed to callback from calling function.
1224  * @param[in] handle          handle to an invocation
1225  * @param[in] clientResponse  Response from queries to remote servers.
1226  * @return  OC_STACK_DELETE_TRANSACTION to delete the transaction
1227  *          and  OC_STACK_KEEP_TRANSACTION to keep it.
1228  */
1229 static OCStackApplicationResult SRPRemoveDeviceCB(void *delDevCtx, OCDoHandle handle,
1230         OCClientResponse *clientResponse)
1231 {
1232     //Update the delete credential into delete device context
1233     //Save the deleted status in delDevCtx
1234     (void)handle;
1235     OC_LOG_V(INFO, TAG, "Inside SRPRemoveDeviceCB.");
1236     VERIFY_NON_NULL(TAG, delDevCtx, ERROR, OC_STACK_DELETE_TRANSACTION);
1237     OCStackResult res = OC_STACK_ERROR;
1238
1239     RemoveData_t* removeData = (RemoveData_t*)delDevCtx;
1240     if (clientResponse)
1241     {
1242         // If we can get device's UUID from OCClientResponse, it'd be good to use it in here
1243         // but OCIdentity in OCClientResponse is emtpy now.
1244         // It seems that we can set identity to CAData_t *cadata in CAPrepareSendData() API
1245         // but CA doesn't have deviceID yet.
1246         //
1247         //TODO: Get OCIdentity from OCClientResponse and use it for 'registerResultForRemoveDevice'
1248         //      If we can't complete this task, Provisioning Database has always stale link status
1249         //      when Remove device is called.
1250
1251         if (OC_STACK_RESOURCE_DELETED == clientResponse->result)
1252         {
1253             res = PDMUnlinkDevices(&removeData->revokeTargetDev->doxm->deviceID,
1254                                    NULL /*TODO: Replace NULL to uuid from OCClientResponse*/);
1255             if (OC_STACK_OK != res)
1256             {
1257                 OC_LOG(FATAL, TAG, "PDMSetLinkStale() FAIL: PDB is an obsolete one.");
1258                 registerResultForRemoveDevice(removeData,
1259                                           NULL /*TODO: Replace NULL to uuid from OCClientResponse*/,
1260                                           OC_STACK_INCONSISTENT_DB, true);
1261                 return OC_STACK_DELETE_TRANSACTION;
1262             }
1263             registerResultForRemoveDevice(removeData,
1264                                           NULL /*TODO: Replace NULL to uuid from OCClientResponse*/,
1265                                           OC_STACK_RESOURCE_DELETED, false);
1266         }
1267         else
1268         {
1269             registerResultForRemoveDevice(removeData,
1270                                           NULL /*TODO: Replace NULL to uuid from OCClientResponse*/,
1271                                           clientResponse->result, true);
1272             OC_LOG(ERROR, TAG, "Unexpected result from DELETE credential request!");
1273         }
1274     }
1275     else
1276     {
1277         registerResultForRemoveDevice(removeData, NULL, OC_STACK_ERROR, true);
1278         OC_LOG(ERROR, TAG, "SRPRemoveDevices received Null clientResponse");
1279     }
1280
1281     return OC_STACK_DELETE_TRANSACTION;
1282 }
1283
1284 static OCStackResult GetListofDevToReqDeleteCred(const OCProvisionDev_t* pRevokeTargetDev,
1285                                                  OCProvisionDev_t* pOwnedDevList,
1286                                                  OCUuidList_t* pLinkedUuidList,
1287                                                  OCProvisionDev_t** ppLinkedDevList,
1288                                                  size_t *numOfLinkedDev)
1289 {
1290     // pOwnedDevList could be NULL. It means no alived and owned device now.
1291     if (pRevokeTargetDev == NULL || pLinkedUuidList == NULL ||\
1292         ppLinkedDevList == NULL || numOfLinkedDev == NULL)
1293     {
1294         return OC_STACK_INVALID_PARAM;
1295     }
1296
1297     size_t cnt = 0;
1298     OCUuidList_t *curUuid = NULL, *tmpUuid = NULL;
1299     LL_FOREACH_SAFE(pLinkedUuidList, curUuid, tmpUuid)
1300     {
1301         // Mark the link status stale.
1302         OCStackResult res = PDMSetLinkStale(&curUuid->dev, &pRevokeTargetDev->doxm->deviceID);
1303         if (OC_STACK_OK != res)
1304         {
1305             OC_LOG(FATAL, TAG, "PDMSetLinkStale() FAIL: PDB is an obsolete one.");
1306             return OC_STACK_INCONSISTENT_DB;
1307         }
1308
1309         if (pOwnedDevList)
1310         {
1311             // If this linked device is alive (power-on), add the deivce to the list.
1312             OCProvisionDev_t *curDev = NULL, *tmpDev = NULL;
1313             LL_FOREACH_SAFE(pOwnedDevList, curDev, tmpDev)
1314             {
1315                 if (memcmp(curDev->doxm->deviceID.id, curUuid->dev.id, sizeof(curUuid->dev.id)) == 0)
1316                 {
1317                     OCProvisionDev_t* targetDev = PMCloneOCProvisionDev(curDev);
1318                     if (NULL == targetDev)
1319                     {
1320                         OC_LOG(ERROR, TAG, "SRPRemoveDevice : Cloning OCProvisionDev_t Failed.");
1321                         return OC_STACK_NO_MEMORY;
1322                     }
1323
1324                     LL_PREPEND(*ppLinkedDevList, targetDev);
1325                     cnt++;
1326                     break;
1327                 }
1328             }
1329         }
1330     }
1331     *numOfLinkedDev = cnt;
1332     return OC_STACK_OK;
1333 }
1334
1335 /*
1336 * Function to device revocation
1337 * This function will remove credential of target device from all devices in subnet.
1338 *
1339 * @param[in] ctx Application context would be returned in result callback
1340 * @param[in] waitTimeForOwnedDeviceDiscovery Maximum wait time for owned device discovery.(seconds)
1341 * @param[in] pTargetDev Device information to be revoked.
1342 * @param[in] resultCallback callback provided by API user, callback will be called when
1343 *            credential revocation is finished.
1344 * @return  OC_STACK_OK in case of success and other value otherwise.
1345 *          If OC_STACK_OK is returned, the caller of this API should wait for callback.
1346 *          OC_STACK_CONTINUE means operation is success but no request is need to be initiated.
1347 */
1348 OCStackResult SRPRemoveDevice(void* ctx, unsigned short waitTimeForOwnedDeviceDiscovery,
1349                              const OCProvisionDev_t* pTargetDev, OCProvisionResultCB resultCallback)
1350 {
1351     OC_LOG(INFO, TAG, "IN SRPRemoveDevice");
1352
1353     if (!pTargetDev || !resultCallback || 0 == waitTimeForOwnedDeviceDiscovery)
1354     {
1355         OC_LOG(INFO, TAG, "SRPRemoveDevice : NULL parameters");
1356         return OC_STACK_INVALID_PARAM;
1357     }
1358
1359     // Declare variables in here to handle error cases with goto statement.
1360     OCProvisionDev_t* pOwnedDevList = NULL;
1361     OCProvisionDev_t* pLinkedDevList = NULL;
1362     RemoveData_t* removeData = NULL;
1363
1364     //1. Find all devices that has a credential of the revoked device
1365     OCUuidList_t* pLinkedUuidList = NULL;
1366     size_t numOfDevices = 0;
1367     OCStackResult res = OC_STACK_ERROR;
1368     res = PDMGetLinkedDevices(&pTargetDev->doxm->deviceID, &pLinkedUuidList, &numOfDevices);
1369     if (OC_STACK_OK != res)
1370     {
1371         OC_LOG(ERROR, TAG, "SRPRemoveDevice : Failed to get linked devices information");
1372         return res;
1373     }
1374     // if there is no related device, we can skip further process.
1375     if (0 == numOfDevices)
1376     {
1377         OC_LOG(DEBUG, TAG, "SRPRemoveDevice : No linked device found.");
1378         res = OC_STACK_CONTINUE;
1379         goto error;
1380     }
1381
1382     //2. Find owned device from the network
1383     res = PMDeviceDiscovery(waitTimeForOwnedDeviceDiscovery, true, &pOwnedDevList);
1384     if (OC_STACK_OK != res)
1385     {
1386         OC_LOG(ERROR, TAG, "SRPRemoveDevice : Failed to PMDeviceDiscovery");
1387         goto error;
1388     }
1389
1390     //3. Make a list of devices to send DELETE credential request
1391     //   by comparing owned devices from provisioning database with mutlicast discovery result.
1392     size_t numOfLinkedDev = 0;
1393     res = GetListofDevToReqDeleteCred(pTargetDev, pOwnedDevList, pLinkedUuidList,
1394                                       &pLinkedDevList, &numOfLinkedDev);
1395     if (OC_STACK_OK != res)
1396     {
1397         OC_LOG(ERROR, TAG, "SRPRemoveDevice : GetListofDevToReqDeleteCred() failed");
1398         goto error;
1399     }
1400     if (0 == numOfLinkedDev) // This case means, there is linked device but it's not alive now.
1401     {                       // So we don't have to send request message.
1402         OC_LOG(DEBUG, TAG, "SRPRemoveDevice : No alived & linked device found.");
1403         res = OC_STACK_CONTINUE;
1404         goto error;
1405     }
1406
1407     // 4. Prepare RemoveData Context data.
1408     removeData = (RemoveData_t*)OICCalloc(1, sizeof(RemoveData_t));
1409     if (!removeData)
1410     {
1411         OC_LOG(ERROR, TAG, "SRPRemoveDevices : Failed to memory allocation");
1412         res = OC_STACK_NO_MEMORY;
1413         goto error;
1414     }
1415
1416     removeData->revokeTargetDev = PMCloneOCProvisionDev(pTargetDev);
1417     if (!removeData->revokeTargetDev)
1418     {
1419         OC_LOG(ERROR, TAG, "SRPRemoveDevices : PMCloneOCProvisionDev Failed");
1420         res = OC_STACK_NO_MEMORY;
1421         goto error;
1422     }
1423
1424     removeData->removeRes =
1425         (OCProvisionResult_t*)OICCalloc(numOfLinkedDev, sizeof(OCProvisionResult_t));
1426     if (!removeData->removeRes)
1427     {
1428         OC_LOG(ERROR, TAG, "SRPRemoveDevices : Failed to memory allocation");
1429         res = OC_STACK_NO_MEMORY;
1430         goto error;
1431     }
1432
1433     removeData->ctx = ctx;
1434     removeData->linkedDevList = pLinkedDevList;
1435     removeData->resultCallback = resultCallback;
1436     removeData->numOfResults = 0;
1437     removeData->sizeOfResArray = numOfLinkedDev;
1438     removeData->hasError = false;
1439
1440     // 5. Send DELETE credential request to linked devices.
1441     OCProvisionDev_t *curDev = NULL, *tmpDev = NULL;
1442     OCStackResult totalRes = OC_STACK_ERROR;  /* variable for checking request is sent or not */
1443     LL_FOREACH_SAFE(pLinkedDevList, curDev, tmpDev)
1444     {
1445         res = SendDeleteCredentialRequest((void*)removeData, &SRPRemoveDeviceCB,
1446                                            removeData->revokeTargetDev, curDev);
1447         if (OC_STACK_OK != res)
1448         {
1449             OC_LOG_V(ERROR, TAG, "SRPRemoveDevice : Fail to send the DELETE credential request to\
1450                      %s:%u", curDev->endpoint.addr, curDev->endpoint.port);
1451         }
1452         else
1453         {
1454             totalRes = OC_STACK_OK; // This means at least one request is successfully sent.
1455         }
1456     }
1457
1458     PDMDestoryOicUuidLinkList(pLinkedUuidList); //TODO: Modify API name to have unified convention.
1459     PMDeleteDeviceList(pOwnedDevList);
1460     OC_LOG(INFO, TAG, "OUT SRPRemoveDevice");
1461
1462     return totalRes; // Caller of this API should wait callback if totalRes == OC_STACK_OK.
1463
1464 error:
1465     PDMDestoryOicUuidLinkList(pLinkedUuidList);
1466     PMDeleteDeviceList(pOwnedDevList);
1467     PMDeleteDeviceList(pLinkedDevList);
1468     if (removeData)
1469     {
1470         OICFree(removeData->revokeTargetDev);
1471         OICFree(removeData->removeRes);
1472         OICFree(removeData);
1473     }
1474     OC_LOG(INFO, TAG, "OUT ERROR case SRPRemoveDevice");
1475     return res;
1476 }