Add PIN based OxM for security provisioning
[platform/upstream/iotivity.git] / resource / csdk / security / provisioning / sample / provisioningclient.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 <unistd.h>
24
25 #include "logger.h"
26 #include "oic_malloc.h"
27 #include "utlist.h"
28 #include "ocprovisioningmanager.h"
29 #include "secureresourceprovider.h"
30 #include "oxmjustworks.h"
31 #include "oxmrandompin.h"
32 #include "pinoxmcommon.h"
33 #include "oic_string.h"
34
35 #define MAX_URI_LENGTH (64)
36 #define MAX_PERMISSION_LENGTH (5)
37 #define CREATE (1)
38 #define READ (2)
39 #define UPDATE (4)
40 #define DELETE (8)
41 #define NOTIFY (16)
42 #define DASH '-'
43 #define PREDEFINED_TIMEOUT (10)
44 #define MAX_OWNED_DEVICE (10)
45 #define TAG  "provisioningclient"
46
47 static char CRED_FILE[] = "oic_svr_db_client.json";
48 static OicSecAcl_t        *gAcl1 = NULL;
49 static OicSecAcl_t        *gAcl2 = NULL;
50 static int gOwnershipState = 0;
51
52 typedef enum
53 {
54     ownershipDone = 1 << 1,
55     finalizeDone = 1 << 2,
56     provisionCredDone = 1 << 3,
57     provisionAclDone = 1 << 4
58 } StateManager;
59
60
61 /**
62  * Perform cleanup for ACL
63  * @param[in]    ACL
64  */
65 static void deleteACL(OicSecAcl_t *acl)
66 {
67     if (acl)
68     {
69         /* Clean Resources */
70         for (size_t i = 0; i < (acl)->resourcesLen; i++)
71         {
72             OICFree((acl)->resources[i]);
73         }
74         OICFree((acl)->resources);
75
76         /* Clean Owners */
77         OICFree((acl)->owners);
78
79         /* Clean ACL node itself */
80         OICFree((acl));
81
82         acl = NULL;
83     }
84 }
85
86 /**
87  * Calculate ACL permission from string to bit
88  *
89  * @param[in] temp_psm    Input data of ACL permission string
90  * @param[in,out] pms    The pointer of ACL permission value
91  * @return  0 on success otherwise -1.
92  */
93 static int CalculateAclPermission(const char *temp_pms, uint16_t *pms)
94 {
95     int i = 0;
96
97     if (NULL == temp_pms || NULL == pms)
98     {
99         return -1;
100     }
101     *pms = 0;
102     while (temp_pms[i] != '\0')
103     {
104         switch (temp_pms[i])
105         {
106             case 'C':
107                 {
108                     *pms += CREATE;
109                     i++;
110                     break;
111                 }
112             case 'R':
113                 {
114                     *pms += READ;
115                     i++;
116                     break;
117                 }
118             case 'U':
119                 {
120                     *pms += UPDATE;
121                     i++;
122                     break;
123                 }
124             case 'D':
125                 {
126                     *pms += DELETE;
127                     i++;
128                     break;
129                 }
130             case 'N':
131                 {
132                     *pms += NOTIFY;
133                     i++;
134                     break;
135                 }
136             case '_':
137                 {
138                     i++;
139                     break;
140                 }
141             default:
142                 {
143                     return -1;
144                 }
145         }
146     }
147     return 0;
148 }
149
150 /**
151  * Get the ACL property from user
152  *
153  * @param[in]    ACL Datastructure to save user inputs
154  * @return  0 on success otherwise -1.
155  */
156 static int InputACL(OicSecAcl_t *acl)
157 {
158     int unused __attribute__((unused));
159     char temp_id [UUID_LENGTH + 4] = {0,};
160     char temp_rsc[MAX_URI_LENGTH + 1] = {0,};
161     char temp_pms[MAX_PERMISSION_LENGTH + 1] = {0,};
162     printf("******************************************************************************\n");
163     printf("-Set ACL policy for target device\n");
164     printf("******************************************************************************\n");
165     //Set Subject.
166     printf("-URN identifying the subject\n");
167     printf("ex) 1111-1111-1111-1111 (16 Numbers except to '-')\n");
168     printf("Subject : ");
169     unused = scanf("%19s", temp_id);
170     int j = 0;
171     for (int i = 0; temp_id[i] != '\0'; i++)
172     {
173         if (DASH != temp_id[i])
174             acl->subject.id[j++] = temp_id[i];
175     }
176
177     //Set Resource.
178     printf("Num. of Resource : ");
179     unused = scanf("%zu", &acl->resourcesLen);
180     printf("-URI of resource\n");
181     printf("ex)/oic/sh/temp/0 (Max_URI_Length: 64 Byte )\n");
182     acl->resources = (char **)OICMalloc(acl->resourcesLen * sizeof(char *));
183     if (NULL == acl->resources)
184     {
185         OC_LOG(ERROR, TAG, "Error while memory allocation");
186         return -1;
187     }
188     for (size_t i = 0; i < acl->resourcesLen; i++)
189     {
190         printf("[%zu]Resource : ", i + 1);
191         unused = scanf("%64s", temp_rsc);
192         acl->resources[i] = OICStrdup(temp_rsc);
193
194         if (NULL == acl->resources[i])
195         {
196             OC_LOG(ERROR, TAG, "Error while memory allocation");
197             return -1;
198         }
199         strncpy(acl->resources[i], temp_rsc, strlen(temp_rsc));
200         acl->resources[i][strlen(temp_rsc)] = '\0';
201     }
202     // Set Permission
203     do
204     {
205         printf("-Set the permission(C,R,U,D,N)\n");
206         printf("ex) CRUDN, CRU_N,..(5 Charaters)\n");
207         printf("Permission : ");
208         unused = scanf("%5s", temp_pms);
209     }
210     while (0 != CalculateAclPermission(temp_pms, &(acl->permission)) );
211     // Set Rowner
212     printf("Num. of Rowner : ");
213     unused = scanf("%zu", &acl->ownersLen);
214     printf("-URN identifying the rowner\n");
215     printf("ex) 1111-1111-1111-1111 (16 Numbers except to '-')\n");
216     acl->owners = (OicUuid_t *)OICCalloc(acl->ownersLen, sizeof(OicUuid_t));
217     if (NULL == acl->owners)
218     {
219         OC_LOG(ERROR, TAG, "Error while memory allocation");
220         return -1;
221     }
222     for (size_t i = 0; i < acl->ownersLen; i++)
223     {
224         printf("[%zu]Rowner : ", i + 1);
225         unused = scanf("%19s", temp_id);
226         j = 0;
227         for (int k = 0; temp_id[k] != '\0'; k++)
228         {
229             if (DASH != temp_id[k])
230             {
231                 acl->owners[i].id[j++] = temp_id[k];
232             }
233         }
234     }
235     return 0;
236 }
237
238
239 //FILE *client_fopen(const char *path, const char *mode)
240 FILE *client_fopen(const char *UNUSED_PARAM, const char *mode)
241 {
242     return fopen(CRED_FILE, mode);
243 }
244
245 void PrintfResult(const char* procName, void* ctx, int nOfRes, OCProvisionResult_t *arr, bool hasError)
246 {
247     printf("-----------------------------------------------------------\n");
248     if(!hasError)
249     {
250         printf("%s was successfully done.\n", procName);
251     }
252     else
253     {
254         for(int i = 0; i < nOfRes; i++)
255         {
256             printf("UUID : ");
257             for(int j = 0; j < UUID_LENGTH; i++)
258             {
259                 printf("%c", arr[i].deviceId.id[j]);
260             }
261             printf("\t");
262             printf("Result=%d\n", arr[i].res);
263         }
264     }
265
266     if(ctx)
267     {
268         printf("Context is %s\n", (char*)ctx);
269     }
270     printf("-----------------------------------------------------------\n");
271 }
272
273 void ProvisionCredCB(void* ctx, int nOfRes, OCProvisionResult_t *arr, bool hasError)
274 {
275     if(!hasError)
276     {
277         gOwnershipState = 1;
278         PrintfResult("Provision Credential", ctx, nOfRes, arr, hasError);
279     }
280 }
281
282 void ProvisionAclCB(void* ctx, int nOfRes, OCProvisionResult_t *arr, bool hasError)
283 {
284     if(!hasError)
285     {
286         gOwnershipState = 1;
287         PrintfResult("Provision ACL", ctx, nOfRes, arr, hasError);
288     }
289 }
290
291 void ProvisionPairwiseCB(void* ctx, int nOfRes, OCProvisionResult_t *arr, bool hasError)
292 {
293     if(!hasError)
294     {
295         gOwnershipState = 1;
296         PrintfResult("Provision Pairwise Credential", ctx, nOfRes, arr, hasError);
297     }
298 }
299
300 void OwnershipTransferCB(void* ctx, int nOfRes, OCProvisionResult_t *arr, bool hasError)
301 {
302     if(!hasError)
303     {
304         gOwnershipState = 1;
305         PrintfResult("Ownership transfer", ctx, nOfRes, arr, hasError);
306     }
307 }
308
309 void InputPinCB(char* pinBuf, size_t bufSize)
310 {
311     if(pinBuf)
312     {
313         printf("INPUT PIN : ");
314         int unused = scanf("%s", pinBuf);
315         pinBuf[bufSize - 1] = '\0';
316     }
317 }
318
319 /**
320  * Provisioning client sample using ProvisioningAPI
321  */
322 int main(int argc, char **argv)
323 {
324     OCStackResult res = OC_STACK_OK;
325     int unused __attribute__((unused));
326
327     gAcl1 = (OicSecAcl_t *)OICMalloc(sizeof(OicSecAcl_t));
328     if (NULL == gAcl1)
329     {
330         OC_LOG(ERROR, TAG, "Error while memory allocation");
331         goto error;
332     }
333
334     // Initialize Persistent Storage for SVR database
335     OCPersistentStorage ps = { .open = NULL,
336                                .read = NULL,
337                                .write = NULL,
338                                .close = NULL,
339                                .unlink = NULL };
340     ps.open = client_fopen;
341     ps.read = fread;
342     ps.write = fwrite;
343     ps.close = fclose;
344     ps.unlink = unlink;
345     OCRegisterPersistentStorageHandler(&ps);
346
347     if (OC_STACK_OK != OCInit(NULL, 0, OC_CLIENT_SERVER))
348     {
349         OC_LOG(ERROR, TAG, "OCStack init error");
350         goto error;
351     }
352
353     OCProvisionDev_t* pDeviceList = NULL;
354     res = OCDiscoverUnownedDevices(PREDEFINED_TIMEOUT, &pDeviceList);
355     if(OC_STACK_OK != res)
356     {
357         OC_LOG_V(ERROR, TAG, "Failed to PMDeviceDiscovery : %d", res);
358         goto error;
359     }
360
361     OCProvisionDev_t* pCurDev = pDeviceList;
362     int i;
363     while(pCurDev !=NULL)
364     {
365         for(i = 0; i < UUID_LENGTH; i++)
366             printf("%c", pCurDev->doxm->deviceID.id[i]);
367         printf("\n");
368         pCurDev = pCurDev->next;
369     }
370
371     //Register callback function to each OxM
372     OTMCallbackData_t justWorksCBData = {.loadSecretCB=NULL,
373                                          .createSecureSessionCB=NULL,
374                                          .createSelectOxmPayloadCB=NULL,
375                                          .createOwnerTransferPayloadCB=NULL};
376     justWorksCBData.loadSecretCB = LoadSecretJustWorksCallback;
377     justWorksCBData.createSecureSessionCB = CreateSecureSessionJustWorksCallback;
378     justWorksCBData.createSelectOxmPayloadCB = CreateJustWorksSelectOxmPayload;
379     justWorksCBData.createOwnerTransferPayloadCB = CreateJustWorksOwnerTransferPayload;
380     OTMSetOwnershipTransferCallbackData(OIC_JUST_WORKS, &justWorksCBData);
381
382     OTMCallbackData_t pinBasedCBData = {.loadSecretCB=NULL,
383                                          .createSecureSessionCB=NULL,
384                                          .createSelectOxmPayloadCB=NULL,
385                                          .createOwnerTransferPayloadCB=NULL};
386     pinBasedCBData.loadSecretCB = InputPinCodeCallback;
387     pinBasedCBData.createSecureSessionCB = CreateSecureSessionRandomPinCallbak;
388     pinBasedCBData.createSelectOxmPayloadCB = CreatePinBasedSelectOxmPayload;
389     pinBasedCBData.createOwnerTransferPayloadCB = CreatePinBasedOwnerTransferPayload;
390     OTMSetOwnershipTransferCallbackData(OIC_RANDOM_DEVICE_PIN, &pinBasedCBData);
391
392     SetInputPinCB(&InputPinCB);
393
394     char* myContext = "OTM Context";
395     //Perform ownership transfer
396     res = OCDoOwnershipTransfer((void*)myContext, pDeviceList, OwnershipTransferCB);
397     if(OC_STACK_OK == res)
398     {
399         OC_LOG(INFO, TAG, "Request for ownership transfer is sent successfully.");
400     }
401     else
402     {
403         OC_LOG_V(ERROR, TAG, "Failed to OCDoOwnershipTransfer : %d", res);
404     }
405
406     gOwnershipState = 0;
407     while ( gOwnershipState == 0 )
408     {
409         if (OCProcess() != OC_STACK_OK)
410         {
411             OC_LOG(ERROR, TAG, "OCStack process error");
412             goto error;
413         }
414         sleep(1);
415     }
416
417 // Credential & ACL provisioning between two devices.
418
419     OCProvisionDev_t *pOwnedList = NULL;
420     OCProvisionDev_t *pOwnedDevices [MAX_OWNED_DEVICE] = {0,};
421     int nOwnedDevice = 0;
422
423     res = OCDiscoverOwnedDevices(PREDEFINED_TIMEOUT, &pOwnedList);
424     if (OC_STACK_OK == res)
425     {
426         printf("################## Owned Device List #######################\n");
427         while (pOwnedList != NULL)
428         {
429             nOwnedDevice ++;
430             printf(" %d : ", nOwnedDevice);
431             for (int i = 0; i < UUID_LENGTH; i++)
432             {
433                 printf("%c", pOwnedList->doxm->deviceID.id[i]);
434             }
435             printf("\n");
436             pOwnedDevices[nOwnedDevice] = pOwnedList;
437             pOwnedList = pOwnedList->next;
438         }
439     }
440     else
441     {
442         OC_LOG(ERROR, TAG, "Error while Owned Device Discovery");
443     }
444
445     int Device1 = 0;
446     int Device2 = 0;
447
448     printf("Select 2 devices for Credential & ACL provisioning\n");
449     printf("Device 1: ");
450     unused = scanf("%d", &Device1);
451     printf("Device 2: ");
452     unused = scanf("%d", &Device2);
453
454
455     gAcl1 = (OicSecAcl_t *)OICMalloc(sizeof(OicSecAcl_t));
456     if (NULL == gAcl1)
457     {
458         OC_LOG(ERROR, TAG, "Error while memory allocation");
459         goto error;
460     }
461     memset(gAcl1, 0x00, sizeof(OicSecAcl_t));
462
463     gAcl2 = (OicSecAcl_t *)OICMalloc(sizeof(OicSecAcl_t));
464     if (NULL == gAcl2)
465     {
466         OC_LOG(ERROR, TAG, "Error while memory allocation");
467         goto error;
468     }
469     memset(gAcl2, 0x00, sizeof(OicSecAcl_t));
470
471     printf("Input ACL for Device1\n");
472     if ( 0 == InputACL(gAcl1))
473     {
474         printf("Success Input ACL\n");
475     }
476     else
477     {
478         OC_LOG(ERROR, TAG, "InputACL error");
479         goto error;
480     }
481
482     printf("Input ACL for Device2\n");
483     if (0 == InputACL(gAcl2))
484     {
485         printf("Success Input ACL\n");
486     }
487     else
488     {
489         OC_LOG(ERROR, TAG, "InputACL error");
490         goto error;
491     }
492     char *ctx = "DUMMY";
493     OCProvisionPairwiseDevices(ctx,SYMMETRIC_PAIR_WISE_KEY, OWNER_PSK_LENGTH_128, pOwnedDevices[Device1],
494                            gAcl1, pOwnedDevices[Device2], gAcl2, ProvisionPairwiseCB);
495
496     gOwnershipState = 0;
497     while ( gOwnershipState == 0 )
498     {
499         if (OCProcess() != OC_STACK_OK)
500         {
501             OC_LOG(ERROR, TAG, "OCStack process error");
502             goto error;
503         }
504         sleep(1);
505     }
506
507     if (OCStop() != OC_STACK_OK)
508     {
509         OC_LOG(ERROR, TAG, "OCStack process error");
510         goto error;
511     }
512
513 error:
514     deleteACL(gAcl1);
515     deleteACL(gAcl2);
516     OCDeleteDiscoveredDevices(&pDeviceList);
517     OCDeleteDiscoveredDevices(&pOwnedList);
518
519     return 0;
520 }