merge master code to build iotivity
[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 uri[SRP_MAX_URI_LENGTH] = { 0 };
254
255     size_t uriLen = sizeof(uri);
256     snprintf(uri, uriLen - 1, COAPS_QUERY, deviceInfo->endpoint.addr, deviceInfo->securePort,
257             OIC_RSRC_CRED_URI);
258
259     uri[uriLen - 1] = '\0';
260     OC_LOG_V(INFO, TAG, "URI for Credential provisioning : %s",uri);
261     OCCallbackData cbData = {.context=NULL, .cb=NULL, .cd=NULL};
262     cbData.cb = responseHandler;
263     cbData.context = (void *) credData;
264     cbData.cd = NULL;
265
266     OCDoHandle handle = NULL;
267     OCMethod method = OC_REST_POST;
268     // TODO replace CT_ADAPTER_IP with value from discovery
269     OCStackResult ret = OCDoResource(&handle, method, uri, 0, (OCPayload*)secPayload,
270             CT_ADAPTER_IP, OC_HIGH_QOS, &cbData, NULL, 0);
271     OC_LOG_V(INFO, TAG, "OCDoResource::Credential provisioning returned : %d",ret);
272     if (ret != OC_STACK_OK)
273     {
274         OC_LOG(ERROR, TAG, "OCStack resource error");
275         return ret;
276     }
277     return OC_STACK_OK;
278 }
279
280 OCStackResult SRPProvisionCredentials(void *ctx, OicSecCredType_t type, size_t keySize,
281                                       const OCProvisionDev_t *pDev1,
282                                       const OCProvisionDev_t *pDev2,
283                                       OCProvisionResultCB resultCallback)
284 {
285     VERIFY_NON_NULL(TAG, pDev1, ERROR,  OC_STACK_INVALID_PARAM);
286     VERIFY_NON_NULL(TAG, pDev2, ERROR,  OC_STACK_INVALID_PARAM);
287     VERIFY_NON_NULL(TAG, resultCallback, ERROR,  OC_STACK_INVALID_CALLBACK);
288
289     if (!(keySize == OWNER_PSK_LENGTH_128 || keySize == OWNER_PSK_LENGTH_256))
290     {
291         OC_LOG(INFO, TAG, "Invalid key size");
292         return OC_STACK_INVALID_PARAM;
293     }
294
295     OC_LOG(INFO, TAG, "In SRPProvisionCredentials");
296
297     OicUuid_t provTooldeviceID =   {{0,}};
298     if (OC_STACK_OK != GetDoxmDeviceID(&provTooldeviceID))
299     {
300         OC_LOG(ERROR, TAG, "Error while retrieving provisioning tool's device ID");
301         return OC_STACK_ERROR;
302     }
303     OC_LOG(INFO, TAG, "retrieved deviceid");
304     switch (type)
305     {
306         case SYMMETRIC_PAIR_WISE_KEY:
307         {
308             const OCProvisionDev_t *firstDevice = pDev1;
309             const OCProvisionDev_t *secondDevice = pDev2;
310
311             OicSecCred_t *firstCred = NULL;
312             OicSecCred_t *secondCred = NULL;
313             OCStackResult res = PMGeneratePairWiseCredentials(type, keySize, &provTooldeviceID,
314                     &firstDevice->doxm->deviceID, &secondDevice->doxm->deviceID,
315                     &firstCred, &secondCred);
316             VERIFY_SUCCESS(TAG, (res==OC_STACK_OK), ERROR, OC_STACK_ERROR);
317             OC_LOG(INFO, TAG, "Credentials generated successfully");
318             CredentialData_t *credData = (CredentialData_t *) OICMalloc(sizeof(CredentialData_t));
319             if (NULL == credData)
320             {
321                 OC_LOG(ERROR, TAG, "Memory allocation problem");
322                 return OC_STACK_NO_MEMORY;
323             }
324             memset(credData, 0x00, sizeof(CredentialData_t));
325             credData->deviceInfo1 = firstDevice;
326             credData->deviceInfo2 = secondDevice;
327             credData->credInfo = secondCred;
328             credData->ctx = ctx;
329             credData->credInfoFirst = firstCred;
330             credData->numOfResults = 0;
331             credData->resultCallback = resultCallback;
332             // first call to provision creds to device1.
333             // second call to provision creds to device2.
334             int noOfRiCalls = 2;
335             credData->resArr =
336                 (OCProvisionResult_t*)OICMalloc(sizeof(OCProvisionResult_t) * noOfRiCalls);
337             if (NULL == credData->resArr)
338             {
339                 OC_LOG(ERROR, TAG, "Memory allocation problem");
340                 return OC_STACK_NO_MEMORY;
341             }
342             memset(credData->resArr, 0x00, sizeof(sizeof(OCProvisionResult_t)*noOfRiCalls));
343             res = provisionCredentials(firstCred, firstDevice, credData, &provisionCredentialCB1);
344             if (OC_STACK_OK != res)
345             {
346                 DeleteCredList(firstCred);
347                 DeleteCredList(secondCred);
348                 OICFree(credData->resArr);
349                 OICFree(credData);
350             }
351             OC_LOG_V(INFO, TAG, "provisionCredentials returned: %d",res);
352             VERIFY_SUCCESS(TAG, (res==OC_STACK_OK), ERROR, OC_STACK_ERROR);
353             return res;
354         }
355         default:
356         {
357             OC_LOG(ERROR, TAG, "Invalid option.");
358             return OC_STACK_INVALID_PARAM;
359         }
360     }
361     return OC_STACK_ERROR;
362 }
363
364 /**
365  * Internal Function to store results in result array during ACL provisioning.
366  */
367 static void registerResultForACLProvisioning(ACLData_t *aclData,
368                                              OCStackResult stackresult)
369 {
370    OC_LOG_V(INFO, TAG, "Inside registerResultForACLProvisioning aclData->numOfResults is %d\n",
371                        aclData->numOfResults);
372    memcpy(aclData->resArr[(aclData->numOfResults)].deviceId.id,
373           aclData->deviceInfo->doxm->deviceID.id, UUID_LENGTH);
374    aclData->resArr[(aclData->numOfResults)].res = stackresult;
375    ++(aclData->numOfResults);
376 }
377
378 /**
379  * Callback handler of SRPProvisionACL.
380  *
381  * @param[in] ctx             ctx value passed to callback from calling function.
382  * @param[in] UNUSED          handle to an invocation
383  * @param[in] clientResponse  Response from queries to remote servers.
384  * @return  OC_STACK_DELETE_TRANSACTION to delete the transaction
385  *          and  OC_STACK_KEEP_TRANSACTION to keep it.
386  */
387 static OCStackApplicationResult SRPProvisionACLCB(void *ctx, OCDoHandle UNUSED,
388                                                   OCClientResponse *clientResponse)
389 {
390     OC_LOG_V(INFO, TAG, "Inside SRPProvisionACLCB.");
391     (void)UNUSED;
392     VERIFY_NON_NULL(TAG, ctx, ERROR, OC_STACK_DELETE_TRANSACTION);
393     ACLData_t *aclData = (ACLData_t*)ctx;
394     OCProvisionResultCB resultCallback = aclData->resultCallback;
395
396     if (clientResponse)
397     {
398         if(OC_STACK_RESOURCE_CREATED == clientResponse->result)
399         {
400             registerResultForACLProvisioning(aclData, OC_STACK_RESOURCE_CREATED);
401             ((OCProvisionResultCB)(resultCallback))(aclData->ctx, aclData->numOfResults,
402                                                     aclData->resArr,
403                                                     false);
404              OICFree(aclData->resArr);
405              OICFree(aclData);
406              return OC_STACK_DELETE_TRANSACTION;
407         }
408     }
409     registerResultForACLProvisioning(aclData, OC_STACK_ERROR);
410     ((OCProvisionResultCB)(resultCallback))(aclData->ctx, aclData->numOfResults,
411                                             aclData->resArr,
412                                             true);
413     OC_LOG_V(ERROR, TAG, "SRPProvisionACLCB received Null clientResponse");
414     OICFree(aclData->resArr);
415     OICFree(aclData);
416     return OC_STACK_DELETE_TRANSACTION;
417 }
418
419 OCStackResult SRPProvisionACL(void *ctx, const OCProvisionDev_t *selectedDeviceInfo,
420         OicSecAcl_t *acl, OCProvisionResultCB resultCallback)
421 {
422     VERIFY_NON_NULL(TAG, selectedDeviceInfo, ERROR,  OC_STACK_INVALID_PARAM);
423     VERIFY_NON_NULL(TAG, acl, ERROR,  OC_STACK_INVALID_PARAM);
424     VERIFY_NON_NULL(TAG, resultCallback, ERROR,  OC_STACK_INVALID_CALLBACK);
425
426     OCSecurityPayload* secPayload = (OCSecurityPayload*)OICCalloc(1, sizeof(OCSecurityPayload));
427     if(!secPayload)
428     {
429         OC_LOG(ERROR, TAG, "Failed to memory allocation");
430         return OC_STACK_NO_MEMORY;
431     }
432     secPayload->base.type = PAYLOAD_TYPE_SECURITY;
433     secPayload->securityData = BinToAclJSON(acl);
434     if(NULL == secPayload->securityData)
435     {
436         OICFree(secPayload);
437         OC_LOG(ERROR, TAG, "Failed to BinToAclJSON");
438         return OC_STACK_NO_MEMORY;
439     }
440     OC_LOG_V(INFO, TAG, "ACL : %s", secPayload->securityData);
441
442     char uri[SRP_MAX_URI_LENGTH] = {0};
443     size_t uriLen = sizeof(uri);
444
445     snprintf(uri, uriLen - 1, COAPS_QUERY, selectedDeviceInfo->endpoint.addr,
446             selectedDeviceInfo->securePort, OIC_RSRC_ACL_URI);
447     uri[uriLen - 1] = '\0';
448
449     OC_LOG_V(INFO, TAG, "URI : %s", uri);
450     OCCallbackData cbData =  {.context=NULL, .cb=NULL, .cd=NULL};
451     cbData.cb = &SRPProvisionACLCB;
452     ACLData_t *aclData = (ACLData_t *) OICMalloc(sizeof(ACLData_t));
453     if (aclData == NULL)
454     {
455         OICFree(secPayload);
456         OC_LOG(ERROR, TAG, "Unable to allocate memory");
457         return OC_STACK_NO_MEMORY;
458     }
459     memset(aclData, 0x00, sizeof(ACLData_t));
460     aclData->deviceInfo = selectedDeviceInfo;
461     aclData->resultCallback = resultCallback;
462     aclData->numOfResults=0;
463     aclData->ctx = ctx;
464     // call to provision ACL to device1.
465     int noOfRiCalls = 1;
466     aclData->resArr = (OCProvisionResult_t*)OICMalloc(sizeof(OCProvisionResult_t)*noOfRiCalls);
467     if (aclData->resArr == NULL)
468     {
469         OICFree(secPayload);
470         OC_LOG(ERROR, TAG, "Unable to allocate memory");
471         return OC_STACK_NO_MEMORY;
472     }
473     memset(aclData->resArr, 0x00, sizeof(sizeof(OCProvisionResult_t)*noOfRiCalls));
474     cbData.context = (void *)aclData;
475     cbData.cd = NULL;
476     OCMethod method = OC_REST_POST;
477     OCDoHandle handle = NULL;
478     OC_LOG(DEBUG, TAG, "Sending ACL info to resource server");
479     // TODO replace CT_ADAPTER_IP with value from discovery
480
481     OCStackResult ret = OCDoResource(&handle, method, uri,
482             &selectedDeviceInfo->endpoint, (OCPayload*)secPayload,
483             CT_ADAPTER_IP, OC_HIGH_QOS, &cbData, NULL, 0);
484     if (ret != OC_STACK_OK)
485     {
486         OICFree(aclData->resArr);
487         OICFree(aclData);
488     }
489     VERIFY_SUCCESS(TAG, (OC_STACK_OK == ret), ERROR, OC_STACK_ERROR);
490     return OC_STACK_OK;
491 }