Merge branch 'master' into ra.to.merge
[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
40 #define SRP_MAX_URI_LENGTH 512
41 #define TAG "SRPAPI"
42
43 /**
44  * Macro to verify argument is not equal to NULL.
45  * eg: VERIFY_NON_NULL(TAG, ptrData, ERROR,OC_STACK_ERROR);
46  */
47 #define VERIFY_NON_NULL(tag, arg, logLevel, retValue) { if (NULL == (arg)) \
48             { OC_LOG((logLevel), tag, (#arg " is NULL")); return retValue; } }
49
50 /**
51  * Macro to verify success of operation.
52  * eg: VERIFY_SUCCESS(TAG, OC_STACK_OK == foo(), ERROR, OC_STACK_ERROR);
53  */
54 #define VERIFY_SUCCESS(tag, op, logLevel, retValue) { if (!(op)) \
55             {OC_LOG((logLevel), tag, (#op " failed!!")); return retValue;} }
56
57 /**
58  * Structure to carry credential data to callback.
59  */
60 typedef struct CredentialData CredentialData_t;
61 struct CredentialData
62 {
63     void *ctx;                                  /**< Pointer to user context.**/
64     const OCProvisionDev_t *deviceInfo1;        /**< Pointer to OCProvisionDev_t.**/
65     const OCProvisionDev_t *deviceInfo2;        /**< Pointer to OCProvisionDev_t.**/
66     OicSecCred_t *credInfo;                     /**< Pointer to OicSecCred_t.**/
67     OicSecCred_t *credInfoFirst;                /**< Pointer to OicSecCred_t.**/
68     OCProvisionResultCB resultCallback;         /**< Pointer to result callback.**/
69     OCProvisionResult_t *resArr;                /**< Result array.**/
70     int numOfResults;                           /**< Number of results in result array.**/
71 };
72
73 /**
74  * Structure to carry ACL provision API data to callback.
75  */
76 typedef struct ACLData ACLData_t;
77 struct ACLData
78 {
79     void *ctx;                                  /**< Pointer to user context.**/
80     const OCProvisionDev_t *deviceInfo;         /**< Pointer to PMDevInfo_t.**/
81     OCProvisionResultCB resultCallback;         /**< Pointer to result callback.**/
82     OCProvisionResult_t *resArr;                /**< Result array.**/
83     int numOfResults;                           /**< Number of results in result array.**/
84 };
85
86 /**
87  * Function prototype
88  */
89 static OCStackResult provisionCredentials(const OicSecCred_t *cred,
90         const OCProvisionDev_t *deviceInfo, CredentialData_t *credData,
91         OCClientResponseHandler responseHandler);
92
93
94 /**
95  * Internal function to update result in result array.
96  */
97 static void registerResultForCredProvisioning(CredentialData_t *credData,
98                                               OCStackResult stackresult, int cause)
99 {
100
101    OC_LOG_V(INFO,TAG,"value of credData->numOfResults is %d",credData->numOfResults);
102    if(1 == cause)
103    {
104        memcpy(credData->resArr[(credData->numOfResults)].deviceId.id,
105               credData->deviceInfo1->doxm->deviceID.id,UUID_LENGTH);
106    }
107    else
108    {
109        memcpy(credData->resArr[(credData->numOfResults)].deviceId.id,
110               credData->deviceInfo2->doxm->deviceID.id,UUID_LENGTH);
111    }
112    credData->resArr[(credData->numOfResults)].res = stackresult;
113    ++(credData->numOfResults);
114 }
115
116 /**
117  * Callback handler for handling callback of provisioning device 2.
118  *
119  * @param[in] ctx             ctx value passed to callback from calling function.
120  * @param[in] UNUSED          handle to an invocation
121  * @param[in] clientResponse  Response from queries to remote servers.
122  * @return  OC_STACK_DELETE_TRANSACTION to delete the transaction
123  *          and  OC_STACK_KEEP_TRANSACTION to keep it.
124  */
125 static OCStackApplicationResult provisionCredentialCB2(void *ctx, OCDoHandle UNUSED,
126                                                        OCClientResponse *clientResponse)
127 {
128     VERIFY_NON_NULL(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
129     CredentialData_t *credData = (CredentialData_t *) ctx;
130     (void)UNUSED;
131
132     OCProvisionResultCB resultCallback = credData->resultCallback;
133     OC_LOG(INFO, TAG, "provisionCredentialCB2 called");
134     if (clientResponse)
135     {
136         if(OC_STACK_RESOURCE_CREATED == clientResponse->result)
137         {
138             registerResultForCredProvisioning(credData, OC_STACK_RESOURCE_CREATED, 2);
139             ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
140                                                     credData->resArr,
141                                                     false);
142              OICFree(credData->resArr);
143              OICFree(credData);
144              return OC_STACK_DELETE_TRANSACTION;
145         }
146
147     }
148     OC_LOG(INFO, TAG, "provisionCredentialCB2 received Null clientResponse");
149     registerResultForCredProvisioning(credData, OC_STACK_ERROR, 2);
150     ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
151                                             credData->resArr,
152                                             true);
153     OICFree(credData->resArr);
154     OICFree(credData);
155     return OC_STACK_DELETE_TRANSACTION;
156 }
157
158 /**
159  * Callback handler for handling callback of provisioning device 1.
160  *
161  * @param[in] ctx             ctx value passed to callback from calling function.
162  * @param[in] UNUSED          handle to an invocation
163  * @param[in] clientResponse  Response from queries to remote servers.
164  * @return  OC_STACK_DELETE_TRANSACTION to delete the transaction
165  *          and  OC_STACK_KEEP_TRANSACTION to keep it.
166  */
167 static OCStackApplicationResult provisionCredentialCB1(void *ctx, OCDoHandle UNUSED,
168                                                        OCClientResponse *clientResponse)
169 {
170     VERIFY_NON_NULL(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
171     (void)UNUSED;
172     CredentialData_t* credData = (CredentialData_t*) ctx;
173     OICFree(credData->credInfoFirst);
174     const OCProvisionDev_t *deviceInfo = credData->deviceInfo2;
175     OicSecCred_t *credInfo = credData->credInfo;
176     const OCProvisionResultCB resultCallback = credData->resultCallback;
177     if (clientResponse)
178     {
179         if (OC_STACK_RESOURCE_CREATED == clientResponse->result)
180         {
181             // send credentials to second device
182             registerResultForCredProvisioning(credData, OC_STACK_RESOURCE_CREATED,1);
183             OCStackResult res = provisionCredentials(credInfo, deviceInfo, credData,
184                     provisionCredentialCB2);
185             DeleteCredList(credInfo);
186             if (OC_STACK_OK != res)
187             {
188                 registerResultForCredProvisioning(credData, res,2);
189                 ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
190                                                         credData->resArr,
191                                                         true);
192                 OICFree(credData->resArr);
193                 OICFree(credData);
194                 credData = NULL;
195             }
196         }
197         else
198         {
199             registerResultForCredProvisioning(credData, OC_STACK_ERROR,1);
200             ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
201                                                     credData->resArr,
202                                                     true);
203             OICFree(credData->resArr);
204             OICFree(credData);
205             credData = NULL;
206         }
207     }
208     else
209     {
210         OC_LOG(INFO, TAG, "provisionCredentialCB received Null clientResponse for first device");
211         registerResultForCredProvisioning(credData, OC_STACK_ERROR,1);
212        ((OCProvisionResultCB)(resultCallback))(credData->ctx, credData->numOfResults,
213                                                      credData->resArr,
214                                                      true);
215         DeleteCredList(credInfo);
216         OICFree(credData->resArr);
217         OICFree(credData);
218         credData = NULL;
219     }
220     return OC_STACK_DELETE_TRANSACTION;
221 }
222
223
224
225 /**
226  * Internal function for handling credential generation and sending credential to resource server.
227  *
228  * @param[in] cred Instance of cred resource.
229  * @param[in] deviceInfo information about device to which credential is to be provisioned.
230  * @param[in] responseHandler callbak called by OC stack when request API receives response.
231  * @return  OC_STACK_OK in case of success and other value otherwise.
232  */
233 static OCStackResult provisionCredentials(const OicSecCred_t *cred,
234         const OCProvisionDev_t *deviceInfo, CredentialData_t *credData,
235         OCClientResponseHandler responseHandler)
236 {
237     OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
238     if(!secPayload)
239     {
240         OC_LOG(ERROR, TAG, "Failed to memory allocation");
241         return OC_STACK_NO_MEMORY;
242     }
243     secPayload->base.type = PAYLOAD_TYPE_SECURITY;
244     secPayload->securityData = BinToCredJSON(cred);
245     if(NULL == secPayload->securityData)
246     {
247         OICFree(secPayload);
248         OC_LOG(ERROR, TAG, "Failed to BinToCredJSON");
249         return OC_STACK_NO_MEMORY;
250     }
251
252     OC_LOG_V(INFO, TAG, "Credential for provisioning : %s",secPayload->securityData);
253     char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
254     if(!PMGenerateQuery(true,
255                         deviceInfo->endpoint.addr,
256                         deviceInfo->securePort,
257                         deviceInfo->connType,
258                         query, sizeof(query), OIC_RSRC_CRED_URI))
259     {
260         OC_LOG(ERROR, TAG, "DeviceDiscoveryHandler : Failed to generate query");
261         return OC_STACK_ERROR;
262     }
263     OC_LOG_V(DEBUG, TAG, "Query=%s", query);
264
265     OCCallbackData cbData = {.context=NULL, .cb=NULL, .cd=NULL};
266     cbData.cb = responseHandler;
267     cbData.context = (void *) credData;
268     cbData.cd = NULL;
269
270     OCDoHandle handle = NULL;
271     OCMethod method = OC_REST_POST;
272     OCStackResult ret = OCDoResource(&handle, method, query, 0, (OCPayload*)secPayload,
273             deviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0);
274     OC_LOG_V(INFO, TAG, "OCDoResource::Credential provisioning returned : %d",ret);
275     if (ret != OC_STACK_OK)
276     {
277         OC_LOG(ERROR, TAG, "OCStack resource error");
278         return ret;
279     }
280     return OC_STACK_OK;
281 }
282
283 OCStackResult SRPProvisionCredentials(void *ctx, OicSecCredType_t type, size_t keySize,
284                                       const OCProvisionDev_t *pDev1,
285                                       const OCProvisionDev_t *pDev2,
286                                       OCProvisionResultCB resultCallback)
287 {
288     VERIFY_NON_NULL(TAG, pDev1, ERROR,  OC_STACK_INVALID_PARAM);
289     VERIFY_NON_NULL(TAG, pDev2, ERROR,  OC_STACK_INVALID_PARAM);
290     VERIFY_NON_NULL(TAG, resultCallback, ERROR,  OC_STACK_INVALID_CALLBACK);
291
292     if (!(keySize == OWNER_PSK_LENGTH_128 || keySize == OWNER_PSK_LENGTH_256))
293     {
294         OC_LOG(INFO, TAG, "Invalid key size");
295         return OC_STACK_INVALID_PARAM;
296     }
297
298     OC_LOG(INFO, TAG, "In SRPProvisionCredentials");
299
300     OicUuid_t provTooldeviceID =   {{0,}};
301     if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID))
302     {
303         OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
304         return OC_STACK_ERROR;
305     }
306     OC_LOG(INFO, TAG, "retrieved deviceid");
307     switch (type)
308     {
309         case SYMMETRIC_PAIR_WISE_KEY:
310         {
311             const OCProvisionDev_t *firstDevice = pDev1;
312             const OCProvisionDev_t *secondDevice = pDev2;
313
314             OicSecCred_t *firstCred = NULL;
315             OicSecCred_t *secondCred = NULL;
316             OCStackResult res = PMGeneratePairWiseCredentials(type, keySize, &provTooldeviceID,
317                     &firstDevice->doxm->deviceID, &secondDevice->doxm->deviceID,
318                     &firstCred, &secondCred);
319             VERIFY_SUCCESS(TAG, (res==OC_STACK_OK), ERROR, OC_STACK_ERROR);
320             OC_LOG(INFO, TAG, "Credentials generated successfully");
321             CredentialData_t *credData = (CredentialData_t *) OICMalloc(sizeof(CredentialData_t));
322             if (NULL == credData)
323             {
324                 OC_LOG(ERROR, TAG, "Memory allocation problem");
325                 return OC_STACK_NO_MEMORY;
326             }
327             memset(credData, 0x00, sizeof(CredentialData_t));
328             credData->deviceInfo1 = firstDevice;
329             credData->deviceInfo2 = secondDevice;
330             credData->credInfo = secondCred;
331             credData->ctx = ctx;
332             credData->credInfoFirst = firstCred;
333             credData->numOfResults = 0;
334             credData->resultCallback = resultCallback;
335             // first call to provision creds to device1.
336             // second call to provision creds to device2.
337             int noOfRiCalls = 2;
338             credData->resArr =
339                 (OCProvisionResult_t*)OICMalloc(sizeof(OCProvisionResult_t) * noOfRiCalls);
340             if (NULL == credData->resArr)
341             {
342                 OC_LOG(ERROR, TAG, "Memory allocation problem");
343                 return OC_STACK_NO_MEMORY;
344             }
345             memset(credData->resArr, 0x00, sizeof(sizeof(OCProvisionResult_t)*noOfRiCalls));
346             res = provisionCredentials(firstCred, firstDevice, credData, &provisionCredentialCB1);
347             if (OC_STACK_OK != res)
348             {
349                 DeleteCredList(firstCred);
350                 DeleteCredList(secondCred);
351                 OICFree(credData->resArr);
352                 OICFree(credData);
353             }
354             OC_LOG_V(INFO, TAG, "provisionCredentials returned: %d",res);
355             VERIFY_SUCCESS(TAG, (res==OC_STACK_OK), ERROR, OC_STACK_ERROR);
356             return res;
357         }
358         default:
359         {
360             OC_LOG(ERROR, TAG, "Invalid option.");
361             return OC_STACK_INVALID_PARAM;
362         }
363     }
364     return OC_STACK_ERROR;
365 }
366
367 /**
368  * Internal Function to store results in result array during ACL provisioning.
369  */
370 static void registerResultForACLProvisioning(ACLData_t *aclData,
371                                              OCStackResult stackresult)
372 {
373    OC_LOG_V(INFO, TAG, "Inside registerResultForACLProvisioning aclData->numOfResults is %d\n",
374                        aclData->numOfResults);
375    memcpy(aclData->resArr[(aclData->numOfResults)].deviceId.id,
376           aclData->deviceInfo->doxm->deviceID.id, UUID_LENGTH);
377    aclData->resArr[(aclData->numOfResults)].res = stackresult;
378    ++(aclData->numOfResults);
379 }
380
381 /**
382  * Callback handler of SRPProvisionACL.
383  *
384  * @param[in] ctx             ctx value passed to callback from calling function.
385  * @param[in] UNUSED          handle to an invocation
386  * @param[in] clientResponse  Response from queries to remote servers.
387  * @return  OC_STACK_DELETE_TRANSACTION to delete the transaction
388  *          and  OC_STACK_KEEP_TRANSACTION to keep it.
389  */
390 static OCStackApplicationResult SRPProvisionACLCB(void *ctx, OCDoHandle UNUSED,
391                                                   OCClientResponse *clientResponse)
392 {
393     OC_LOG_V(INFO, TAG, "Inside SRPProvisionACLCB.");
394     (void)UNUSED;
395     VERIFY_NON_NULL(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
396     ACLData_t *aclData = (ACLData_t*)ctx;
397     OCProvisionResultCB resultCallback = aclData->resultCallback;
398
399     if (clientResponse)
400     {
401         if(OC_STACK_RESOURCE_CREATED == clientResponse->result)
402         {
403             registerResultForACLProvisioning(aclData, OC_STACK_RESOURCE_CREATED);
404             ((OCProvisionResultCB)(resultCallback))(aclData->ctx, aclData->numOfResults,
405                                                     aclData->resArr,
406                                                     false);
407              OICFree(aclData->resArr);
408              OICFree(aclData);
409              return OC_STACK_DELETE_TRANSACTION;
410         }
411     }
412     registerResultForACLProvisioning(aclData, OC_STACK_ERROR);
413     ((OCProvisionResultCB)(resultCallback))(aclData->ctx, aclData->numOfResults,
414                                             aclData->resArr,
415                                             true);
416     OC_LOG_V(ERROR, TAG, "SRPProvisionACLCB received Null clientResponse");
417     OICFree(aclData->resArr);
418     OICFree(aclData);
419     return OC_STACK_DELETE_TRANSACTION;
420 }
421
422 OCStackResult SRPProvisionACL(void *ctx, const OCProvisionDev_t *selectedDeviceInfo,
423         OicSecAcl_t *acl, OCProvisionResultCB resultCallback)
424 {
425     VERIFY_NON_NULL(TAG, selectedDeviceInfo, ERROR,  OC_STACK_INVALID_PARAM);
426     VERIFY_NON_NULL(TAG, acl, ERROR,  OC_STACK_INVALID_PARAM);
427     VERIFY_NON_NULL(TAG, resultCallback, ERROR,  OC_STACK_INVALID_CALLBACK);
428
429     OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
430     if(!secPayload)
431     {
432         OC_LOG(ERROR, TAG, "Failed to memory allocation");
433         return OC_STACK_NO_MEMORY;
434     }
435     secPayload->base.type = PAYLOAD_TYPE_SECURITY;
436     secPayload->securityData = BinToAclJSON(acl);
437     if(NULL == secPayload->securityData)
438     {
439         OICFree(secPayload);
440         OC_LOG(ERROR, TAG, "Failed to BinToAclJSON");
441         return OC_STACK_NO_MEMORY;
442     }
443     OC_LOG_V(INFO, TAG, "ACL : %s", secPayload->securityData);
444
445     char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = {0};
446     if(!PMGenerateQuery(true,
447                         selectedDeviceInfo->endpoint.addr,
448                         selectedDeviceInfo->securePort,
449                         selectedDeviceInfo->connType,
450                         query, sizeof(query), OIC_RSRC_ACL_URI))
451     {
452         OC_LOG(ERROR, TAG, "DeviceDiscoveryHandler : Failed to generate query");
453         return OC_STACK_ERROR;
454     }
455     OC_LOG_V(DEBUG, TAG, "Query=%s", query);
456
457     OCCallbackData cbData =  {.context=NULL, .cb=NULL, .cd=NULL};
458     cbData.cb = &SRPProvisionACLCB;
459     ACLData_t *aclData = (ACLData_t *) OICMalloc(sizeof(ACLData_t));
460     if (aclData == NULL)
461     {
462         OICFree(secPayload);
463         OC_LOG(ERROR, TAG, "Unable to allocate memory");
464         return OC_STACK_NO_MEMORY;
465     }
466     memset(aclData, 0x00, sizeof(ACLData_t));
467     aclData->deviceInfo = selectedDeviceInfo;
468     aclData->resultCallback = resultCallback;
469     aclData->numOfResults=0;
470     aclData->ctx = ctx;
471     // call to provision ACL to device1.
472     int noOfRiCalls = 1;
473     aclData->resArr = (OCProvisionResult_t*)OICMalloc(sizeof(OCProvisionResult_t)*noOfRiCalls);
474     if (aclData->resArr == NULL)
475     {
476         OICFree(secPayload);
477         OC_LOG(ERROR, TAG, "Unable to allocate memory");
478         return OC_STACK_NO_MEMORY;
479     }
480     memset(aclData->resArr, 0x00, sizeof(sizeof(OCProvisionResult_t)*noOfRiCalls));
481     cbData.context = (void *)aclData;
482     cbData.cd = NULL;
483     OCMethod method = OC_REST_POST;
484     OCDoHandle handle = NULL;
485     OC_LOG(DEBUG, TAG, "Sending ACL info to resource server");
486     OCStackResult ret = OCDoResource(&handle, method, query,
487             &selectedDeviceInfo->endpoint, (OCPayload*)secPayload,
488             selectedDeviceInfo->connType, OC_HIGH_QOS, &cbData, NULL, 0);
489     if (ret != OC_STACK_OK)
490     {
491         OICFree(aclData->resArr);
492         OICFree(aclData);
493     }
494     VERIFY_SUCCESS(TAG, (OC_STACK_OK == ret), ERROR, OC_STACK_ERROR);
495     return OC_STACK_OK;
496 }