Merge branch 'master' into 'security-CKM' branch
[platform/upstream/iotivity.git] / resource / csdk / security / provisioning / src / ocprovisioningmanager.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 <stdint.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include "ocprovisioningmanager.h"
24 #include "pmutility.h"
25 #include "ownershiptransfermanager.h"
26 #include "oic_malloc.h"
27 #include "logger.h"
28 #include "secureresourceprovider.h"
29
30 #define TAG "OCPMAPI"
31
32 typedef struct Linkdata Linkdata_t;
33 struct Linkdata
34 {
35     void *ctx;
36     const OCProvisionDev_t *pDev1;
37     OicSecAcl_t *pDev1Acl;
38     const OCProvisionDev_t *pDev2;
39     OicSecAcl_t *pDev2Acl;
40     OCProvisionResult_t *resArr;
41     int numOfResults;
42     int currentCountResults;
43     OCProvisionResultCB resultCallback;
44
45 };
46
47 /**
48  * The function is responsible for discovery of device is current subnet. It will list
49  * all the device in subnet which are not yet owned. Please call OCInit with OC_CLIENT_SERVER as
50  * OCMode.
51  *
52  * @param[in] timeout Timeout in seconds, value till which function will listen to responses from
53  *                    client before returning the list of devices.
54  * @param[out] ppList List of candidate devices to be provisioned
55  * @return OTM_SUCCESS in case of success and other value otherwise.
56  */
57 OCStackResult OCDiscoverUnownedDevices(unsigned short timeout, OCProvisionDev_t **ppList)
58 {
59     if( ppList == NULL || *ppList != NULL)
60     {
61         return OC_STACK_INVALID_PARAM;
62     }
63
64     return PMDeviceDiscovery(timeout, false, ppList);
65 }
66
67 /**
68  * The function is responsible for discovery of owned device is current subnet. It will list
69  * all the device in subnet which are owned by calling provisioning client.
70  *
71  * @param[in] timeout Timeout in seconds, value till which function will listen to responses from
72  *                    client before returning the list of devices.
73  * @param[out] ppList List of device owned by provisioning tool.
74  * @return OTM_SUCCESS in case of success and other value otherwise.
75  */
76 OCStackResult OCDiscoverOwnedDevices(unsigned short timeout, OCProvisionDev_t **ppList)
77 {
78     if( ppList == NULL || *ppList != NULL)
79     {
80         return OC_STACK_INVALID_PARAM;
81     }
82
83     return PMDeviceDiscovery(timeout, true, ppList);
84 }
85
86 /**
87  * API to register for particular OxM.
88  *
89  * @param[in] Ownership transfer method.
90  * @param[in] Implementation of callback functions for owership transfer.
91  * @return  OC_STACK_OK in case of success and other value otherwise.
92  */
93 OCStackResult OCSetOwnerTransferCallbackData(OicSecOxm_t oxm, OTMCallbackData_t* callbackData)
94 {
95     if(NULL == callbackData)
96     {
97         return OC_STACK_INVALID_PARAM;
98     }
99
100     return OTMSetOwnershipTransferCallbackData(oxm, callbackData);
101 }
102
103 OCStackResult OCDoOwnershipTransfer(void* ctx,
104                                       OCProvisionDev_t *targetDevices,
105                                       OCProvisionResultCB resultCallback)
106 {
107     if( NULL == targetDevices )
108     {
109         return OC_STACK_INVALID_PARAM;
110     }
111
112     return OTMDoOwnershipTransfer(ctx, targetDevices, resultCallback);
113 }
114
115 /**
116  * This function deletes memory allocated to linked list created by OCDiscover_XXX_Devices API.
117  *
118  * @param[in] pList Pointer to OCProvisionDev_t which should be deleted.
119  */
120 void OCDeleteDiscoveredDevices(OCProvisionDev_t **ppList)
121 {
122     DeleteDeviceList(ppList);
123 }
124
125 /**
126  * this function sends ACL information to resource.
127  *
128  * @param[in] ctx Application context would be returned in result callback.
129  * @param[in] selectedDeviceInfo Selected target device.
130  * @param[in] acl ACL to provision.
131  * @param[in] resultCallback callback provided by API user, callback will be called when provisioning
132               request recieves a response from resource server.
133  * @return  OC_STACK_OK in case of success and other value otherwise.
134  */
135 OCStackResult OCProvisionACL(void* ctx, const OCProvisionDev_t *selectedDeviceInfo, OicSecAcl_t *acl,
136                              OCProvisionResultCB resultCallback)
137 {
138     return SRPProvisionACL(ctx, selectedDeviceInfo, acl, resultCallback);
139 }
140
141 /**
142  * function to provision credential to devices.
143  *
144  * @param[in] ctx Application context would be returned in result callback.
145  * @param[in] type Type of credentials to be provisioned to the device.
146  * @param[in] pDev1 Pointer to OCProvisionDev_t instance,respresenting resource to be provsioned.
147    @param[in] pDev2 Pointer to OCProvisionDev_t instance,respresenting resource to be provsioned.
148  * @param[in] resultCallback callback provided by API user, callback will be called when
149  *            provisioning request recieves a response from first resource server.
150  * @return  OC_STACK_OK in case of success and other value otherwise.
151  */
152 OCStackResult OCProvisionCredentials(void *ctx, OicSecCredType_t type, size_t keySize,
153                                       const OCProvisionDev_t *pDev1,
154                                       const OCProvisionDev_t *pDev2,
155                                       OCProvisionResultCB resultCallback)
156 {
157     return SRPProvisionCredentials(ctx, type, keySize,
158                                       pDev1, pDev2, resultCallback);
159
160 }
161
162 /**
163  * Internal Function to update result in link result array.
164  */
165 static void UpdateLinkResults(Linkdata_t *link, int device, OCStackResult stackresult)
166 {
167
168     OC_LOG_V(INFO,TAG,"value of link->currentCountResults is %d",link->currentCountResults);
169     if(1 == device)
170     {
171         memcpy(link->resArr[(link->currentCountResults)].deviceId.id, link->pDev1->doxm->deviceID.id,UUID_LENGTH);
172     }
173     else
174     {
175         memcpy(link->resArr[(link->currentCountResults)].deviceId.id, link->pDev2->doxm->deviceID.id,UUID_LENGTH);
176     }
177     link->resArr[(link->currentCountResults)].res = stackresult;
178     ++(link->currentCountResults);
179
180 }
181
182 /**
183  * Callback to handle ACL provisioning for device 2.
184  */
185 static void AclProv2CB(void* ctx, int nOfRes, OCProvisionResult_t *arr, bool hasError)
186 {
187
188     if (NULL == ctx)
189     {
190         OC_LOG(ERROR,TAG,"Context is Null in ACLProv 2");
191         return;
192     }
193     (void)nOfRes;
194     Linkdata_t *link = (Linkdata_t*)ctx;
195     OCProvisionResultCB resultCallback = link->resultCallback;
196
197
198     if(hasError)
199     {
200         UpdateLinkResults(link, 2,arr[0].res);
201         OC_LOG(ERROR,TAG,"Error occured while ACL provisioning device 1");
202         ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults,
203                                                 link->resArr,
204                                                 true);
205         OICFree(link->resArr);
206         OICFree(link) ;
207         return;
208     }
209     UpdateLinkResults(link, 2, arr[0].res);
210    ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults,
211                                            link->resArr,
212                                            false);
213     OICFree(link->resArr);
214     OICFree(link);
215     return;
216 }
217
218 /**
219  * Callback to handle ACL provisioning for device 1
220  */
221 static void AclProv1CB(void* ctx, int nOfRes, OCProvisionResult_t *arr, bool hasError)
222 {
223
224     if (NULL == ctx)
225     {
226         OC_LOG(ERROR,TAG,"Context is Null in ACLProv1");
227         return;
228     }
229     (void)nOfRes;
230     Linkdata_t *link = (Linkdata_t*)ctx;
231     OCProvisionResultCB resultCallback = link->resultCallback;
232
233     if(hasError)
234     {
235         OC_LOG(ERROR,TAG,"Error occured while ACL provisioning device 1");
236         UpdateLinkResults(link, 1, arr[0].res);
237         ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults,
238                                                 link->resArr,
239                                                 true);
240         OICFree(link->resArr);
241         OICFree(link);
242         return;
243     }
244     UpdateLinkResults(link, 1, arr[0].res);
245     if (NULL != link->pDev2Acl)
246     {
247         OCStackResult res =  SRPProvisionACL(ctx, link->pDev2, link->pDev2Acl, &AclProv2CB);
248         if (OC_STACK_OK!=res)
249         {
250              UpdateLinkResults(link, 2, res);
251              ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults,
252                                                      link->resArr,
253                                                      true);
254
255         }
256     }
257     else
258     {
259         ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults,
260                                                 link->resArr,
261                                                 false);
262         OICFree(link->resArr);
263         OICFree(link);
264     }
265
266     return;
267 }
268
269 /**
270  * Callback to handle credential provisioning.
271  */
272 static void ProvisionCredsCB(void* ctx, int nOfRes, OCProvisionResult_t *arr, bool hasError)
273 {
274     if (NULL == ctx)
275     {
276         OC_LOG(ERROR,TAG,"Error occured while credential provisioning");
277         return;
278     }
279     Linkdata_t *link = (Linkdata_t*)ctx;
280     OCProvisionResultCB resultCallback = link->resultCallback;
281     OC_LOG_V(INFO, TAG, "has error returned %d",hasError);
282     UpdateLinkResults(link, 1, arr[0].res);
283     UpdateLinkResults(link, 2, arr[1].res);
284     if (hasError)
285     {
286         OC_LOG(ERROR,TAG,"Error occured while credential provisioning");
287         ((OCProvisionResultCB)(resultCallback))(link->ctx, nOfRes,
288                                                 link->resArr,
289                                                 true);
290          OICFree(link->resArr);
291          OICFree(link);
292          return;
293     }
294     if (NULL != link->pDev1Acl)
295     {
296
297         OCStackResult res =  SRPProvisionACL(ctx, link->pDev1, link->pDev1Acl, &AclProv1CB);
298         if (OC_STACK_OK!=res)
299         {
300              OC_LOG(ERROR, TAG, "Error while provisioning ACL for device 1");
301              UpdateLinkResults(link, 1, res);
302              ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults,
303                                                      link->resArr,
304                                                      true);
305               OICFree(link->resArr);
306               OICFree(link);
307         }
308     }
309     else if (NULL!=link->pDev2Acl)
310     {
311         OC_LOG(ERROR, TAG, "ACL for device 1 is NULL");
312         OCStackResult res =  SRPProvisionACL(ctx, link->pDev2, link->pDev2Acl, &AclProv2CB);
313         if (OC_STACK_OK!=res)
314         {
315              OC_LOG(ERROR, TAG, "Error while provisioning ACL for device 2");
316               UpdateLinkResults(link, 2, res);
317              ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults,
318                                                      link->resArr,
319                                                      true);
320               OICFree(link->resArr);
321               OICFree(link);
322         }
323
324     }
325     else
326     {
327         OC_LOG(INFO, TAG, "ACLs of both devices are NULL");
328         ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults,
329                                                 link->resArr,
330                                                 false);
331         OICFree(link->resArr);
332         OICFree(link);
333     }
334     return;
335 }
336 /**
337  * function to provision credentials between two devices and ACLs for the devices who act as a server.
338  *
339  * @param[in] ctx Application context would be returned in result callback.
340  * @param[in] type Type of credentials to be provisioned to the device.
341  * @param[in] pDev1 Pointer to OCProvisionDev_t instance,respresenting resource to be provsioned.
342  * @param[in] acl ACL for device 1. If this is not required set NULL.
343  * @param[in] pDev2 Pointer to OCProvisionDev_t instance,respresenting resource to be provsioned.
344  * @param[in] acl ACL for device 2. If this is not required set NULL.
345  * @param[in] resultCallback callback provided by API user, callback will be called when
346  *            provisioning request recieves a response from first resource server.
347  * @return  OC_STACK_OK in case of success and other value otherwise.
348  */
349 OCStackResult OCProvisionPairwiseDevices(void* ctx, OicSecCredType_t type, size_t keySize,
350                                          const OCProvisionDev_t *pDev1, OicSecAcl_t *pDev1Acl,
351                                          const OCProvisionDev_t *pDev2, OicSecAcl_t *pDev2Acl,
352                                          OCProvisionResultCB resultCallback)
353 {
354
355     if(!pDev1 || !pDev2 || !resultCallback)
356     {
357         OC_LOG(ERROR, TAG, "OCProvisionPairwiseDevices : Invalid parameters");
358         return OC_STACK_INVALID_PARAM;
359     }
360     if (!(keySize == OWNER_PSK_LENGTH_128 || keySize == OWNER_PSK_LENGTH_256))
361     {
362         OC_LOG(INFO, TAG, "OCProvisionPairwiseDevices : Invalid key size");
363         return OC_STACK_INVALID_PARAM;
364     }
365     int noOfResults = 2; // Initial Value
366     if (NULL!=pDev1Acl)
367     {
368         ++noOfResults;
369     }
370     if(NULL!=pDev2Acl)
371     {
372        ++noOfResults;
373     }
374     Linkdata_t *link = (Linkdata_t*) OICMalloc(sizeof(Linkdata_t));
375     if(!link)
376     {
377         OC_LOG(ERROR, TAG, "Failed to memory allocation");
378         return OC_STACK_NO_MEMORY;
379     }
380     OC_LOG_V(INFO,TAG, "Maximum no od results %d",noOfResults);
381
382     link->pDev1 = pDev1;
383     link->pDev1Acl = pDev1Acl;
384     link->pDev2 = pDev2;
385     link->pDev2Acl = pDev2Acl;
386     link->ctx = ctx;
387     // 1 call for each device for credential provisioning. implict call by SRPProvisioning credential
388     // 1 call for ACL provisioning for device 1 and 1 call for ACL provisioning for device 2.
389     link->numOfResults = noOfResults;
390     link->resultCallback = resultCallback;
391     link->currentCountResults = 0;
392     link->resArr = (OCProvisionResult_t*) OICMalloc(sizeof(OCProvisionResult_t)*noOfResults);
393     OCStackResult res = SRPProvisionCredentials(link, type, keySize,
394                                      pDev1, pDev2, &ProvisionCredsCB);
395     if (res != OC_STACK_OK)
396     {
397         OICFree(link->resArr);
398         OICFree(link);
399     }
400     return res;
401
402 }