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