Add PIN based OxM for security provisioning
[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     Linkdata_t *link = (Linkdata_t*)ctx;
194     OCProvisionResultCB resultCallback = link->resultCallback;
195
196
197     if(hasError)
198     {
199         UpdateLinkResults(link, 2,arr[0].res);
200         OC_LOG(ERROR,TAG,"Error occured while ACL provisioning device 1");
201         ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults,
202                                                 link->resArr,
203                                                 true);
204         OICFree(link->resArr);
205         OICFree(link) ;
206         return;
207     }
208     UpdateLinkResults(link, 2, arr[0].res);
209    ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults,
210                                            link->resArr,
211                                            false);
212     OICFree(link->resArr);
213     OICFree(link);
214     return;
215 }
216
217 /**
218  * Callback to handle ACL provisioning for device 1
219  */
220 static void AclProv1CB(void* ctx, int nOfRes, OCProvisionResult_t *arr, bool hasError)
221 {
222
223     if (NULL == ctx)
224     {
225         OC_LOG(ERROR,TAG,"Context is Null in ACLProv1");
226         return;
227     }
228     Linkdata_t *link = (Linkdata_t*)ctx;
229     OCProvisionResultCB resultCallback = link->resultCallback;
230
231     if(hasError)
232     {
233         OC_LOG(ERROR,TAG,"Error occured while ACL provisioning device 1");
234         UpdateLinkResults(link, 1, arr[0].res);
235         ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults,
236                                                 link->resArr,
237                                                 true);
238         OICFree(link->resArr);
239         OICFree(link);
240         return;
241     }
242     UpdateLinkResults(link, 1, arr[0].res);
243     if (NULL != link->pDev2Acl)
244     {
245         OCStackResult res =  SRPProvisionACL(ctx, link->pDev2, link->pDev2Acl, &AclProv2CB);
246         if (OC_STACK_OK!=res)
247         {
248              UpdateLinkResults(link, 2, res);
249              ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults,
250                                                      link->resArr,
251                                                      true);
252
253         }
254     }
255     else
256     {
257         ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults,
258                                                 link->resArr,
259                                                 false);
260         OICFree(link->resArr);
261         OICFree(link);
262     }
263
264     return;
265 }
266
267 /**
268  * Callback to handle credential provisioning.
269  */
270 static void ProvisionCredsCB(void* ctx, int nOfRes, OCProvisionResult_t *arr, bool hasError)
271 {
272     if (NULL == ctx)
273     {
274         OC_LOG(ERROR,TAG,"Error occured while credential provisioning");
275         return;
276     }
277     Linkdata_t *link = (Linkdata_t*)ctx;
278     OCProvisionResultCB resultCallback = link->resultCallback;
279     OC_LOG_V(INFO, TAG, "has error returned %d",hasError);
280     UpdateLinkResults(link, 1, arr[0].res);
281     UpdateLinkResults(link, 2, arr[1].res);
282     if (hasError)
283     {
284         OC_LOG(ERROR,TAG,"Error occured while credential provisioning");
285         ((OCProvisionResultCB)(resultCallback))(link->ctx, nOfRes,
286                                                 link->resArr,
287                                                 true);
288          OICFree(link->resArr);
289          OICFree(link);
290          return;
291     }
292     if (NULL != link->pDev1Acl)
293     {
294
295         OCStackResult res =  SRPProvisionACL(ctx, link->pDev1, link->pDev1Acl, &AclProv1CB);
296         if (OC_STACK_OK!=res)
297         {
298              OC_LOG(ERROR, TAG, "Error while provisioning ACL for device 1");
299              UpdateLinkResults(link, 1, res);
300              ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults,
301                                                      link->resArr,
302                                                      true);
303               OICFree(link->resArr);
304               OICFree(link);
305         }
306     }
307     else if (NULL!=link->pDev2Acl)
308     {
309         OC_LOG(ERROR, TAG, "ACL for device 1 is NULL");
310         OCStackResult res =  SRPProvisionACL(ctx, link->pDev2, link->pDev2Acl, &AclProv2CB);
311         if (OC_STACK_OK!=res)
312         {
313              OC_LOG(ERROR, TAG, "Error while provisioning ACL for device 2");
314               UpdateLinkResults(link, 2, res);
315              ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults,
316                                                      link->resArr,
317                                                      true);
318               OICFree(link->resArr);
319               OICFree(link);
320         }
321
322     }
323     else
324     {
325         OC_LOG(INFO, TAG, "ACLs of both devices are NULL");
326         ((OCProvisionResultCB)(resultCallback))(link->ctx, link->currentCountResults,
327                                                 link->resArr,
328                                                 false);
329         OICFree(link->resArr);
330         OICFree(link);
331     }
332     return;
333 }
334 /**
335  * function to provision credentials between two devices and ACLs for the devices who act as a server.
336  *
337  * @param[in] ctx Application context would be returned in result callback.
338  * @param[in] type Type of credentials to be provisioned to the device.
339  * @param[in] pDev1 Pointer to OCProvisionDev_t instance,respresenting resource to be provsioned.
340  * @param[in] acl ACL for device 1. If this is not required set NULL.
341  * @param[in] pDev2 Pointer to OCProvisionDev_t instance,respresenting resource to be provsioned.
342  * @param[in] acl ACL for device 2. If this is not required set NULL.
343  * @param[in] resultCallback callback provided by API user, callback will be called when
344  *            provisioning request recieves a response from first resource server.
345  * @return  OC_STACK_OK in case of success and other value otherwise.
346  */
347 OCStackResult OCProvisionPairwiseDevices(void* ctx, OicSecCredType_t type, size_t keySize,
348                                          const OCProvisionDev_t *pDev1, OicSecAcl_t *pDev1Acl,
349                                          const OCProvisionDev_t *pDev2, OicSecAcl_t *pDev2Acl,
350                                          OCProvisionResultCB resultCallback)
351 {
352
353     if(!pDev1 || !pDev2 || !resultCallback)
354     {
355         OC_LOG(ERROR, TAG, "OCProvisionPairwiseDevices : Invalid parameters");
356         return OC_STACK_INVALID_PARAM;
357     }
358     if (!(keySize == OWNER_PSK_LENGTH_128 || keySize == OWNER_PSK_LENGTH_256))
359     {
360         OC_LOG(INFO, TAG, "OCProvisionPairwiseDevices : Invalid key size");
361         return OC_STACK_INVALID_PARAM;
362     }
363     int noOfResults = 2; // Initial Value
364     if (NULL!=pDev1Acl)
365     {
366         ++noOfResults;
367     }
368     if(NULL!=pDev2Acl)
369     {
370        ++noOfResults;
371     }
372     Linkdata_t *link = (Linkdata_t*) OICMalloc(sizeof(Linkdata_t));
373     if(!link)
374     {
375         OC_LOG(ERROR, TAG, "Failed to memory allocation");
376         return OC_STACK_NO_MEMORY;
377     }
378     OC_LOG_V(INFO,TAG, "Maximum no od results %d",noOfResults);
379
380     link->pDev1 = pDev1;
381     link->pDev1Acl = pDev1Acl;
382     link->pDev2 = pDev2;
383     link->pDev2Acl = pDev2Acl;
384     link->ctx = ctx;
385     // 1 call for each device for credential provisioning. implict call by SRPProvisioning credential
386     // 1 call for ACL provisioning for device 1 and 1 call for ACL provisioning for device 2.
387     link->numOfResults = noOfResults;
388     link->resultCallback = resultCallback;
389     link->currentCountResults = 0;
390     link->resArr = (OCProvisionResult_t*) OICMalloc(sizeof(OCProvisionResult_t)*noOfResults);
391     OCStackResult res = SRPProvisionCredentials(link, type, keySize,
392                                      pDev1, pDev2, &ProvisionCredsCB);
393     if (res != OC_STACK_OK)
394     {
395         OICFree(link->resArr);
396         OICFree(link);
397     }
398     return res;
399
400 }