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