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