cc1plus: all warnings being treated as errors fix
[iotivity.git] / resource / csdk / security / provisioning / sample / autoprovisioningclient.c
1 /******************************************************************
2  *
3  * Copyright 2017 Microsoft. 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 /*
22  * This file is derived from iotivity\resource\csdk\security\provisioning\sample\provisioningclient.c
23  * That program is interactive, and requires user input to perform provisioning
24  * steps, while this version takes input on the command line and executes a
25  * sequence of provisioning operations automatically, then exists, reporting
26  * whether the sequence succeeded.  This is so that we can script provisioning
27  * for testing.
28  */
29
30 #include "iotivity_config.h"
31
32 #include <stdio.h>
33 #include <string.h>
34 #include <stdint.h>
35 #ifdef HAVE_UNISTD_H
36 #include <unistd.h>
37 #endif
38 #include "utlist.h"
39 #include "oic_malloc.h"
40 #include "oic_string.h"
41 #include "ocprovisioningmanager.h"
42 #include "oxmjustworks.h"
43 #include "oxmrandompin.h"
44 #include "srmutility.h"
45 #include "pmtypes.h"
46 #include "oxmverifycommon.h"
47 #include "occertutility.h"
48 #include "ocsecurity.h"
49 #include "ocstackinternal.h"
50 #include "pmutility.h"
51
52 #ifdef _MSC_VER
53 #include <io.h>
54
55 #define F_OK 0
56 #define access _access_s
57 #endif
58
59 /// This example is using experimental API, so there is no guarantee of support for future release,
60 /// nor any there any guarantee that breaking changes will not occur across releases.
61 #include "experimental/logger.h"
62 #include "experimental/payload_logging.h"
63 #include "experimental/ocrandom.h"
64
65 #ifdef __cplusplus
66 extern "C"
67 {
68 #endif //__cplusplus
69
70 #define DISCOVERY_TIMEOUT   3  // 3 sec
71 #define CALLBACK_TIMEOUT    60  // 1 min
72 #define TAG "autoprovisioningclient"
73
74 static const char* SVR_DB_FILE_NAME = "oic_svr_db_client.dat";
75         // '_' for separaing from the same constant variable in |srmresourcestrings.c|
76 static const char* PRVN_DB_FILE_NAME = "oic_autoprvn_mng.db";
77
78 static const char* TEST_CERT_NOT_BEFORE = "20170101000000"; // Not before field for certificates, in format YYYYMMDDhhmmss
79 static const char* TEST_CERT_NOT_AFTER = "20270101000000";  // + ten years
80 static const char* TEST_CERT_ROLE1 = "IoTivity-test-role1";
81 static const char* TEST_CERT_ROLE2 = "IoTivity-test-role2";
82 static const char* TEST_CERT_AUTHORITY = "IoTivity-test-OBT-authority-name";
83
84 // |g_ctx| means provision manager application context and
85 // the following, includes |un/own_list|, could be variables, which |g_ctx| has,
86 // for accessing all function(s) for these, they are declared on global domain
87 static char* g_ctx = "Provision Manager Client Application Context";
88 static char* g_svr_fname;
89 static char* g_prvn_fname;
90 static OCProvisionDev_t* g_own_list;
91 static OCProvisionDev_t* g_unown_list;
92 static int g_own_cnt;
93 static int g_unown_cnt;
94 static char* g_csr;    /* Certificate signing request from device */
95 static OicUuid_t g_uuidDev1;
96 static char* g_idPublicKey = NULL;
97
98 static volatile bool g_doneCB;    /* Set to true by the callback to indicate it completed. */
99 static bool g_successCB; /* Set to true by the callback to indicate success. */
100
101 // function declaration(s) for calling them before implementing
102 static OCProvisionDev_t* getDevInst(const OCProvisionDev_t*, const int);
103 static int printDevList(const OCProvisionDev_t*);
104 static size_t printResultList(const OCProvisionResult_t*, const size_t);
105 static void printUuid(const OicUuid_t*);
106 static int saveUuid(const OCProvisionResult_t* rslt_lst, const size_t rslt_cnt);
107 static FILE* fopen_prvnMng(const char*, const char*);
108 static int waitCallbackRet(void);
109
110 /*
111  * Test CA key and certificate created with
112  * iotivity/resource/csdk/security/scripts/test_cert_generation.sh
113  */
114 static const char* g_caCertPem = "-----BEGIN CERTIFICATE-----\n"
115 "MIIBfjCCASSgAwIBAgIJAPQXoGTceaW5MAoGCCqGSM49BAMCMBkxFzAVBgNVBAoM\n"
116 "DklvVGl2aXR5VGVzdENBMB4XDTE3MDMxNTAwNTExOVoXDTMwMTEyMjAwNTExOVow\n"
117 "GTEXMBUGA1UECgwOSW9UaXZpdHlUZXN0Q0EwWTATBgcqhkjOPQIBBggqhkjOPQMB\n"
118 "BwNCAARvYPdt+LjqASlHoc2zrjo3hHGjZsI31c+bg9AwINW5TuRZsE03w/Ejotza\n"
119 "y4VDLImMlDhGP+K/f6OmKD3FNHhKo1UwUzAhBgNVHSUEGjAYBgorBgEEAYLefAEG\n"
120 "BgorBgEEAYLefAEHMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNw+hm69Rxb5\n"
121 "UpclERf5r85g1nwmMAoGCCqGSM49BAMCA0gAMEUCIQDbvNLA3ZkwEzuoH6XUR6JS\n"
122 "UzZTVgsDgnJcOqtqOg0qEAIgUJR2g8XlMxqiuXP7JdwALdtnvCQTlJQbuD1gu+Jy\n"
123 "AdQ=\n"
124 "-----END CERTIFICATE-----\n";
125
126 static const char* g_caKeyPem = "-----BEGIN EC PRIVATE KEY-----\n"
127 "MHcCAQEEILx9VOHDrMYuan6SXN4CQIHHXNq6SjzanaDFDgIaOaXloAoGCCqGSM49\n"
128 "AwEHoUQDQgAEb2D3bfi46gEpR6HNs646N4Rxo2bCN9XPm4PQMCDVuU7kWbBNN8Px\n"
129 "I6Lc2suFQyyJjJQ4Rj/iv3+jpig9xTR4Sg==\n"
130 "-----END EC PRIVATE KEY-----\n";
131
132
133 /* At a few places in this file, warning 4028 is incorrectly produced, disable it for the whole file. */
134 #ifdef _MSC_VER
135 #pragma warning( disable : 4028)
136 #endif
137
138 // callback function(s) for provisioning client using C-level provisioning API
139 static void ownershipTransferCB(void* ctx, size_t nOfRes, OCProvisionResult_t* arr, bool hasError)
140 {
141     g_successCB = false;
142     if(!hasError)
143     {
144         OIC_LOG_V(INFO, TAG, "Ownership Transfer SUCCEEDED - ctx: %s", (char*) ctx);
145         if (saveUuid((const OCProvisionResult_t*)arr, nOfRes) == 0)
146         {
147             g_successCB = true;
148         }
149     }
150     else
151     {
152         OIC_LOG_V(ERROR, TAG, "Ownership Transfer FAILED - ctx: %s", (char*) ctx);
153         printResultList((const OCProvisionResult_t*) arr, nOfRes);
154         g_successCB = false;
155     }
156     g_doneCB = true;
157 }
158
159 static void provisionCredCB(void* ctx, size_t nOfRes, OCProvisionResult_t* arr, bool hasError)
160 {
161     if(!hasError)
162     {
163         OIC_LOG_V(INFO, TAG, "Provision Credential SUCCEEDED - ctx: %s", (char*) ctx);
164         g_successCB = true;
165     }
166     else
167     {
168         OIC_LOG_V(ERROR, TAG, "Provision Credential FAILED - ctx: %s", (char*) ctx);
169         printResultList((const OCProvisionResult_t*) arr, nOfRes);
170         g_successCB = false;
171     }
172     g_doneCB = true;
173 }
174
175 /* Function of type OCProvisionResultCB from \resource\csdk\security\provisioning\include\pmtypes.h */
176 void provisionTrustChainCB(void* ctx, size_t nOfRes, OCProvisionResult_t *arr, bool hasError)
177 {
178     if(!hasError)
179     {
180         OIC_LOG_V(INFO, TAG, "Provision Credential SUCCEEDED - ctx: %s", (char*)ctx);
181         g_successCB = true;
182     }
183     else
184     {
185         OIC_LOG_V(ERROR, TAG, "Provision Credential FAILED - ctx: %s", (char*)ctx);
186         printResultList((const OCProvisionResult_t*)arr, nOfRes);
187         g_successCB = false;
188     }
189     g_doneCB = true;
190 }
191
192 static void getCsrForCertProvCB(void* ctx, size_t nOfRes, OCPMGetCsrResult_t* arr, bool hasError)
193 {
194     g_successCB = false;
195
196     if (!hasError)
197     {
198         if (nOfRes != 1)
199         {
200             OIC_LOG_V(ERROR, TAG, "getCsrForCertProvCB FAILED - ctx: %s", (char*)ctx);
201             goto exit;
202         }
203
204         if (arr[0].encoding == OIC_ENCODING_DER)
205         {
206             OCStackResult res = OCConvertDerCSRToPem((char*)arr[0].csr, arr[0].csrLen, &g_csr);
207             if (res != OC_STACK_OK)
208             {
209                 OIC_LOG_V(ERROR, TAG, "getCsrForCertProvCB FAILED (CSR re-encoding failed) - error: %d, ctx: %s", res, (char*)ctx);
210                 goto exit;
211             }
212             g_successCB = true;
213         }
214         else if (arr[0].encoding == OIC_ENCODING_PEM)
215         {
216             g_csr = (char*)OICCalloc(1, arr[0].csrLen);
217             if (g_csr == NULL)
218             {
219                 OIC_LOG_V(ERROR, TAG, "getCsrForCertProvCB FAILED (memory allocation) - ctx: %s", (char*)ctx);
220                 goto exit;
221             }
222
223             memcpy(g_csr, arr[0].csr, arr[0].csrLen);
224
225             OIC_LOG(INFO, TAG, "getCsrForCertProvCB success");
226             g_successCB = true;
227         }
228         else
229         {
230             OIC_LOG_V(ERROR, TAG, "getCsrForCertProvCB FAILED (unknown encoding) - ctx: %s", (char*)ctx);
231             goto exit;
232         }
233     }
234     else
235     {
236         OIC_LOG_V(ERROR, TAG, "getCsrForCertProvCB FAILED - ctx: %s", (char*)ctx);
237     }
238
239 exit:
240     g_doneCB = true;
241 }
242
243 OCStackApplicationResult getReqCB(void* ctx, OCDoHandle handle,
244     OCClientResponse* clientResponse)
245 {
246     OC_UNUSED(ctx);
247     OC_UNUSED(handle);
248
249     g_doneCB = true;
250     g_successCB = false;
251
252     if (clientResponse == NULL)
253     {
254         OIC_LOG(ERROR, TAG, "getReqCB received NULL clientResponse");
255         return OC_STACK_DELETE_TRANSACTION;
256     }
257
258     if (clientResponse->result != OC_STACK_OK)
259     {
260         OIC_LOG_V(ERROR, TAG, "getReqCB response %d", clientResponse->result);
261         return OC_STACK_DELETE_TRANSACTION;
262     }
263
264     g_successCB = true;
265
266     return OC_STACK_DELETE_TRANSACTION;
267 }
268
269 static void provisionAclCB(void* ctx, size_t nOfRes, OCProvisionResult_t* arr, bool hasError)
270 {
271     if (!hasError)
272     {
273         OIC_LOG_V(INFO, TAG, "Provision ACL SUCCEEDED - ctx: %s", (char*)ctx);
274         g_successCB = true;
275     }
276     else
277     {
278         OIC_LOG_V(ERROR, TAG, "Provision ACL FAILED - ctx: %s", (char*)ctx);
279         printResultList((const OCProvisionResult_t*)arr, nOfRes);
280         g_successCB = false;
281     }
282     g_doneCB = true;
283 }
284
285 static void assertRolesCB(void* ctx, bool hasError)
286 {
287     OC_UNUSED(ctx); // unused in release builds
288
289     if (!hasError)
290     {
291         OIC_LOG_V(INFO, TAG, "%s: Asserting roles SUCCEEDED - ctx: %s", __func__, (char*)ctx);
292         g_successCB = true;
293     }
294     else
295     {
296         OIC_LOG_V(DEBUG, TAG, "%s: Asserting roles FAILED - ctx: %s", __func__, (char*)ctx);
297         g_successCB = false;
298     }
299     g_doneCB = true;
300 }
301
302 // function(s) for provisioning client using C-level provisioning API
303 static int initProvisionClient(void)
304 {
305     // initialize persistent storage for SVR DB
306     static OCPersistentStorage pstStr =
307     {
308         .open = fopen_prvnMng,
309         .read = fread,
310         .write = fwrite,
311         .close = fclose,
312         .unlink = remove
313     };
314     if (OC_STACK_OK != OCRegisterPersistentStorageHandler(&pstStr))
315     {
316         OIC_LOG(ERROR, TAG, "OCRegisterPersistentStorageHandler error");
317         return -1;
318     }
319
320     // initialize OC stack and provisioning manager
321     if (OC_STACK_OK != OCInit(NULL, 0, OC_CLIENT_SERVER))
322     {
323         OIC_LOG(ERROR, TAG, "OCStack init error");
324         return -1;
325     }
326
327     if (access(PRVN_DB_FILE_NAME, F_OK) == 0)
328     {
329         printf("************************************************************\n");
330         printf("************Provisioning DB file already exists.************\n");
331         printf("************************************************************\n");
332     }
333     else
334     {
335         printf("*************************************************************\n");
336         printf("************No provisioning DB file, creating new************\n");
337         printf("*************************************************************\n");
338     }
339
340     if (OC_STACK_OK != OCInitPM(PRVN_DB_FILE_NAME))
341     {
342         OIC_LOG(ERROR, TAG, "OC_PM init error");
343         return -1;
344     }
345
346     return 0;
347 }
348
349 /* In some tests we need to close existing sessions after making a change
350  * in order for the effect of the change to take effect. This function shuts
351  * down the OC stack and restarts it.
352  */
353 static int closeAllSessions(void)
354 {
355     if (OC_STACK_OK != OCStop())
356     {
357         OIC_LOG_V(ERROR, TAG, "%s: OCStack stop error", __func__);
358         return -1;
359     }
360
361     if (OC_STACK_OK != OCInit(NULL, 0, OC_CLIENT_SERVER))
362     {
363         OIC_LOG_V(ERROR, TAG, "%s: OCStack init error", __func__);
364         return -1;
365     }
366
367     return 0;
368 }
369
370 static int discoverAllDevices(void)
371 {
372     // delete un/owned device lists before updating them
373     if(g_own_list)
374     {
375         OCDeleteDiscoveredDevices(g_own_list);
376         g_own_list = NULL;
377     }
378     if(g_unown_list)
379     {
380         OCDeleteDiscoveredDevices(g_unown_list);
381         g_unown_list = NULL;
382     }
383
384     // call |OCGetDevInfoFromNetwork| API
385     printf("   Discovering All Un/Owned Devices on Network..\n");
386     if(OC_STACK_OK != OCGetDevInfoFromNetwork(DISCOVERY_TIMEOUT, &g_own_list, &g_unown_list))
387     {
388         OIC_LOG(ERROR, TAG, "OCGetDevInfoFromNetwork API error");
389         return -1;
390     }
391
392     // display the discovered un/owned lists
393     printf("   > Discovered Owned Devices\n");
394     g_own_cnt = printDevList(g_own_list);
395     printf("   > Discovered Unowned Devices\n");
396     g_unown_cnt = printDevList(g_unown_list);
397
398     return 0;
399 }
400
401 static int registerDevices(void)
402 {
403     // check |unown_list| for registering devices
404     if(!g_unown_list || 0>=g_unown_cnt)
405     {
406         OIC_LOG(ERROR, TAG, "Unowned device list empty, must discover unowned devices first");
407         return -1;  // Error, we should have registered unowned devices already
408     }
409
410     // call |OCDoOwnershipTransfer| API
411     // calling this API with callback actually acts like blocking
412     // for error checking, the return value saved and printed
413     g_doneCB = false;
414     printf("   Registering All Discovered Unowned Devices..\n");
415     OCStackResult rst = OCDoOwnershipTransfer((void*) g_ctx, g_unown_list, ownershipTransferCB);
416     if(OC_STACK_OK != rst)
417     {
418         OIC_LOG_V(ERROR, TAG, "OCDoOwnershipTransfer API error: %d", rst);
419         return -1;
420     }
421     if(waitCallbackRet())  // input |g_doneCB| flag implicitly
422     {
423         OIC_LOG(ERROR, TAG, "OCDoOwnershipTransfer callback error");
424         return -1;
425     }
426
427     if(!g_successCB)
428     {
429         OIC_LOG(ERROR, TAG, "OCDoOwnershipTransfer callback failed");
430         return -1;
431     }
432
433     // display the registered result
434     printf("   > Registered Discovered Unowned Devices\n");
435
436     return 0;
437 }
438
439 static int provisionTrustAnchor(int dev_num)
440 {
441     OCProvisionDev_t* targetDevice = getDevInst((const OCProvisionDev_t*)g_own_list, dev_num);
442     if(targetDevice == NULL)
443     {
444         OIC_LOG(ERROR, TAG, "Error, invalid device %d");
445         return -1;
446     }
447
448     // Install the CA trust anchor locally
449     uint16_t caCredId = 0;
450     OCStackResult rst = OCSaveTrustCertChain((const uint8_t*)g_caCertPem, strlen(g_caCertPem) + 1,
451         OIC_ENCODING_PEM, &caCredId);
452     if (OC_STACK_OK != rst)
453     {
454         OIC_LOG_V(ERROR, TAG, "OCSaveTrustCertChain error: %d", rst);
455         return -1;
456     }
457
458     // Provision the CA root cert to the target device
459     printf("   > Saving root certificate (trust anchor) to selected device..\n");
460     g_doneCB = false;
461     OicSecCredType_t type = SIGNED_ASYMMETRIC_KEY;
462
463     rst = OCProvisionTrustCertChain((void*)g_ctx, type, caCredId, targetDevice, (OCProvisionResultCB)&provisionTrustChainCB);
464     if(OC_STACK_OK != rst)
465     {
466         OIC_LOG_V(ERROR, TAG, "OCProvisionTrustCertChain returned error: %d", rst);
467         return -1;
468     }
469
470     if(waitCallbackRet())  // input |g_doneCB| flag implicitly
471     {
472         OIC_LOG(ERROR, TAG, "OCProvisionTrustCertChain callback error");
473         return -1;
474     }
475     if(!g_successCB)
476     {
477         return -1;
478     }
479
480     printf("   > Provisioned certificate trust anchor\n");
481
482     return 0;
483
484 }
485
486 /* If csr is not null, a copy will be made, and the caller must free it with OICFree. */
487 static int getCsr(int dev_num, char** csr)
488 {
489     OCProvisionDev_t* dev = getDevInst((const OCProvisionDev_t*) g_own_list, dev_num);
490     if(!dev)
491     {
492         OIC_LOG(ERROR, TAG, "getDevInst: device instance empty");
493         goto GETCSR_ERROR;
494     }
495
496     g_doneCB = false;
497     OCStackResult rst = OCGetCSRResource((void*) g_ctx, dev, getCsrForCertProvCB);
498     if(OC_STACK_OK != rst)
499     {
500         OIC_LOG_V(ERROR, TAG, "OCGetCSRResource API error: %d", rst);
501
502         goto GETCSR_ERROR;
503     }
504     if(waitCallbackRet())  // input |g_doneCB| flag implicitly
505     {
506         OIC_LOG(ERROR, TAG, "OCGetCSRResource callback error");
507         goto GETCSR_ERROR;
508     }
509     if(!g_successCB)
510     {
511         return -1;
512     }
513
514     rst = OCVerifyCSRSignature(g_csr);
515     if(rst != OC_STACK_OK)
516     {
517         OIC_LOG(ERROR, TAG, "Failed to validate CSR signature");
518         OICFreeAndSetToNull((void**)&g_csr);
519         return -1;
520     }
521
522     if (csr != NULL)
523     {
524         *csr = OICStrdup(g_csr);
525         if (*csr == NULL)
526         {
527             OIC_LOG(ERROR, TAG, "OICStrdup failed");
528             OICFreeAndSetToNull((void**)&g_csr);
529             return -1;
530         }
531     }
532
533     OICFreeAndSetToNull((void**)&g_csr);
534
535     printf("   > Get CSR SUCCEEDED\n");
536
537     return 0;
538
539 GETCSR_ERROR:
540     printf("   > Get CSR FAILED\n");
541     return -1;
542 }
543
544 static int doGetRequest(const char* uri, int dev_num)
545 {
546     OCStackResult res;
547     OCCallbackData cbData;
548     OCDoHandle handle;
549     OCProvisionDev_t *device = NULL;
550
551     device = getDevInst(g_own_list, dev_num);
552     if (!device)
553     {
554         OIC_LOG(ERROR, TAG, "Selected device does not exist");
555         return -1;
556     }
557     cbData.context = NULL;
558     cbData.cd = NULL;
559     cbData.cb = &getReqCB;
560     OIC_LOG_V(INFO, TAG, "Performing GET on %s", uri);
561     g_doneCB = false;
562
563     char query[MAX_URI_LENGTH + MAX_QUERY_LENGTH] = { 0 };
564     if (!PMGenerateQuery(true,
565         device->endpoint.addr,
566         device->securePort,
567         device->connType,
568         query, sizeof(query), uri))
569     {
570         OIC_LOG_V(ERROR, TAG, "%s : Failed to generate query", __func__);
571         return -1;
572     }
573
574     /*
575      * Make sure the OCDevAddr passed to OCDoRequest contains the remote peer's UUID,
576      * so that PSK lookup succeeds.
577      */
578     if (!OCConvertUuidToString(device->doxm->deviceID.id, device->endpoint.remoteId))
579     {
580         OIC_LOG_V(ERROR, TAG, "%s : Failed to copy or convert UUID", __func__);
581         return -1;
582     }
583
584     res = OCDoRequest(&handle, OC_REST_GET, query, &device->endpoint, NULL,
585         device->connType, OC_HIGH_QOS, &cbData, NULL, 0);
586     if (res != OC_STACK_OK)
587     {
588         OIC_LOG_V(ERROR, TAG, "OCDoRequest returned error %d with method", res);
589     }
590     if (waitCallbackRet())  // input |g_doneCB| flag implicitly
591     {
592         OIC_LOG_V(ERROR, TAG, "%s callback error", __func__);
593     }
594     if (g_successCB)
595     {
596         return 0;
597     }
598
599     return -1;
600 }
601
602 static int provisionCert(int dev_num, char* cert)
603 {
604     OCProvisionDev_t* dev = getDevInst((const OCProvisionDev_t*)g_own_list, dev_num);
605     if (!dev)
606     {
607         OIC_LOG(ERROR, TAG, "getDevInst: device instance empty");
608         return -1;
609     }
610
611     printf("   > Provisioning certificate credential to selected device..\n");
612     g_doneCB = false;
613     OCStackResult rst = OCProvisionCertificate((void *)g_ctx, dev, cert, provisionCredCB);
614     if (OC_STACK_OK != rst)
615     {
616         OIC_LOG_V(ERROR, TAG, "OCProvisionCertificate returned error: %d", rst);
617         return -1;
618     }
619     if (waitCallbackRet())
620     {
621         OIC_LOG_V(ERROR, TAG, "%s failed waiting for callback", __func__);
622         return -1;
623     }
624     if (!g_successCB)
625     {
626         OIC_LOG_V(ERROR, TAG, "%s callback completed, but failed", __func__);
627         return -1;
628     }
629
630     printf("   > Provision cert SUCCEEDED\n");
631
632     return 0;
633 }
634
635 /*
636  * Create a role or identity certificate for a device, based on the information in its CSR.
637  * Assumes the CSR has already been validated wtih OCVerifyCSRSignature.
638  * If role is not NULL, a role certificate is created, otherwise an identity certificate
639  * is created.
640  */
641 static int createCertFromCSR(const char* caKeyPem, const char* caCertPem, char* csr,
642     const char* role, const char* authority, char** deviceCert)
643 {
644     char* publicKey = NULL;
645     char* serial = NULL;
646     size_t serialLen;
647     OicUuid_t uuid = { 0 };
648     OCStackResult res = OC_STACK_ERROR;
649
650     res = OCGetUuidFromCSR(csr, &uuid);
651     if (res != OC_STACK_OK)
652     {
653         OIC_LOG_V(ERROR, TAG, "Failed to get UUID from CSR, error: %d", res);
654         goto exit;
655     }
656     /* Note: a real OBT must make sure the UUID isn't already in use on the network. */
657
658     res = OCGetPublicKeyFromCSR(csr, &publicKey);
659     if (res != OC_STACK_OK)
660     {
661         OIC_LOG_V(ERROR, TAG, "Failed to get public key from CSR, error: %d", res);
662         goto exit;
663     }
664
665     res = OCGenerateRandomSerialNumber(&serial, &serialLen);
666     if (res != OC_STACK_OK)
667     {
668         OIC_LOG_V(ERROR, TAG, "OCGenerateRandomSerialNumber failed, error: %d", res);
669         goto exit;
670     }
671
672     size_t deviceCertLen;
673     if (role != NULL)
674     {
675         res = OCGenerateRoleCertificate(
676             &uuid,
677             publicKey,
678             caCertPem,
679             caKeyPem,
680             serial,
681             TEST_CERT_NOT_BEFORE,
682             TEST_CERT_NOT_AFTER,
683             role,
684             authority,
685             deviceCert,
686             &deviceCertLen);
687     }
688     else
689     {
690         res = OCGenerateIdentityCertificate(
691             &uuid,
692             publicKey,
693             caCertPem,
694             caKeyPem,
695             serial,
696             TEST_CERT_NOT_BEFORE,
697             TEST_CERT_NOT_AFTER,
698             deviceCert,
699             &deviceCertLen);
700     }
701     if (res != OC_STACK_OK)
702     {
703         OIC_LOG_V(ERROR, TAG, "Failed generating certificate, error: %d", res);
704         goto exit;
705     }
706
707 exit:
708     OICFree(publicKey);
709     OICFree(serial);
710
711     return (res == OC_STACK_OK) ? 0 : -1;
712 }
713
714 static int setupOwnCert(OicUuid_t* inputUuid)
715 {
716     OCUUIdentity deviceId = { 0 };
717     uint16_t caCredId;
718     char* serial = NULL;
719     size_t serialLen = 0;
720     size_t idPublicKeyLen = 0;
721     char* idKey = NULL;
722     size_t idKeyLen = 0;
723     char* idCert = NULL;
724     size_t idCertLen = 0;
725
726     OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
727
728     /* Set our own trust anchor so that we trust certs we've issued. */
729     OCStackResult res = OCSaveTrustCertChain((const uint8_t*)g_caCertPem, strlen(g_caCertPem)+1, OIC_ENCODING_PEM, &caCredId);
730     if (OC_STACK_OK != res)
731     {
732         OIC_LOG_V(ERROR, TAG, "OCSaveTrustCertChain error: %d", res);
733         goto exit;
734     }
735
736     /* Create identity certificate for use by the CA. */
737     res = OCGenerateKeyPair(&g_idPublicKey, &idPublicKeyLen, &idKey, &idKeyLen);
738     if (res != OC_STACK_OK)
739     {
740         OIC_LOG_V(ERROR, TAG, "OCGenerateKeyPair failed, error: %d", res);
741         goto exit;
742     }
743
744     res = OCGenerateRandomSerialNumber(&serial, &serialLen);
745     if (res != OC_STACK_OK)
746     {
747         OIC_LOG_V(ERROR, TAG, "OCGenerateRandomSerialNumber failed, error: %d", res);
748         goto exit;
749     }
750
751     OicUuid_t* uuidForCert = inputUuid;
752     OicUuid_t uuid = { 0 };
753     if (inputUuid == NULL)
754     {
755         res = OCGetDeviceId(&deviceId);
756         if (res != OC_STACK_OK)
757         {
758             OIC_LOG_V(ERROR, TAG, "Failed to get own UUID, error: %d", res);
759             goto exit;
760         }
761         memcpy(uuid.id, deviceId.id, sizeof(uuid.id));
762         uuidForCert = &uuid;
763     }
764
765     OIC_LOG(DEBUG, TAG, "Creating own cert with UUID:");
766     printUuid(uuidForCert);
767
768     res = OCGenerateIdentityCertificate(
769         uuidForCert,
770         g_idPublicKey,
771         g_caCertPem,
772         g_caKeyPem,
773         serial,
774         TEST_CERT_NOT_BEFORE,
775         TEST_CERT_NOT_AFTER,
776         &idCert,
777         &idCertLen);
778     if (res != OC_STACK_OK)
779     {
780         OIC_LOG_V(ERROR, TAG, "Failed to create identity cert for CA, error: %d", res);
781         goto exit;
782     }
783
784     uint16_t idCertCredId = 0;
785     res = OCSaveOwnCertChain(idCert, idKey, &idCertCredId);
786     if (res != OC_STACK_OK)
787     {
788         OIC_LOG_V(ERROR, TAG, "Failed to save CA's identity cert & key, error: %d", res);
789         goto exit;
790     }
791
792 exit:
793     OICFree(serial);
794     if (idKey != NULL)
795     {
796         OICClearMemory(idKey, idKeyLen);
797         OICFree(idKey);
798     }
799     OICFree(idCert);
800
801     OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
802
803     return (res == OC_STACK_OK) ? 0 : -1;
804 }
805
806 static int setupOwnRoleCert(OicUuid_t* inputUuid, const char* role, const char* authority)
807 {
808     OCUUIdentity deviceId = { 0 };
809     char* serial = NULL;
810     size_t serialLen = 0;
811     char* roleCert = NULL;
812     size_t roleCertLen = 0;
813
814     OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
815
816     if (g_idPublicKey == NULL)
817     {
818         OIC_LOG_V(ERROR, TAG, "%s failed because own public key is NULL, has setupOwnCert been called?", __func__);
819         return -1;
820     }
821
822     /* Create role certificate. */
823     OCStackResult res = OCGenerateRandomSerialNumber(&serial, &serialLen);
824     if (res != OC_STACK_OK)
825     {
826         OIC_LOG_V(ERROR, TAG, "OCGenerateRandomSerialNumber failed, error: %d", res);
827         goto exit;
828     }
829
830     OicUuid_t* uuidForCert = inputUuid;
831     OicUuid_t uuid = { 0 };
832     if (inputUuid == NULL)
833     {
834         res = OCGetDeviceId(&deviceId);
835         if (res != OC_STACK_OK)
836         {
837             OIC_LOG_V(ERROR, TAG, "Failed to get own UUID, error: %d", res);
838             goto exit;
839         }
840         memcpy(uuid.id, deviceId.id, sizeof(uuid.id));
841         uuidForCert = &uuid;
842     }
843
844     OIC_LOG(DEBUG, TAG, "Creating own role cert with UUID:");
845     printUuid(uuidForCert);
846
847     res = OCGenerateRoleCertificate(
848         uuidForCert,
849         g_idPublicKey,
850         g_caCertPem,
851         g_caKeyPem,
852         serial,
853         TEST_CERT_NOT_BEFORE,
854         TEST_CERT_NOT_AFTER,
855         role,
856         authority,
857         &roleCert,
858         &roleCertLen);
859     if (res != OC_STACK_OK)
860     {
861         OIC_LOG_V(ERROR, TAG, "Failed to create role cert, error: %d", res);
862         goto exit;
863     }
864
865     uint16_t roleCertCredId = 0;
866     res = OCSaveOwnRoleCert(roleCert, &roleCertCredId);
867     if (res != OC_STACK_OK)
868     {
869         OIC_LOG_V(ERROR, TAG, "Failed to save role cert, error: %d", res);
870         goto exit;
871     }
872
873 exit:
874     OICFree(serial);
875     OICFree(roleCert);
876
877     OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
878
879     return (res == OC_STACK_OK) ? 0 : -1;
880 }
881
882 /*
883  * Create an ACL for the /a/led resource.
884  * Caller must call OCDeleteACLList(newAcl).
885  * The role and authority parameters are optional.  If role is not NULL, a
886  * role-based ACL will be created. Otherwise a subject-based ACL is created.
887  */
888 static int createLedAcl(OicSecAcl_t** newAcl, const char* role, const char* authority)
889 {
890     int ret = -1;
891     OCUUIdentity ownUuid = { 0 };
892     OicSecAcl_t* acl = NULL;
893     OicSecAce_t* ace = NULL;
894     OicSecRsrc_t* rsrc = NULL;
895     const char* resource = "/a/led";
896     const char* resource_type = "core.led";
897     const char* resource_interface = "oic.if.baseline";
898     uint16_t perms = PERMISSION_FULL_CONTROL;
899
900     /* Create an ACL with one ACE */
901     acl = (OicSecAcl_t*)OICCalloc(1, sizeof(OicSecAcl_t));
902     if (!acl)
903     {
904         OIC_LOG_V(ERROR, TAG, "%s: OICCalloc failed (acl)", __func__);
905         goto exit;
906     }
907     ace = (OicSecAce_t*)OICCalloc(1, sizeof(OicSecAce_t));
908     if (!ace)
909     {
910         OIC_LOG_V(ERROR, TAG, "%s: OICCalloc failed (ace)", __func__);
911         goto exit;
912     }
913     LL_APPEND(acl->aces, ace);
914
915     if (role != NULL)    /* Create a role-based ACL */
916     {
917         ace->subjectType = OicSecAceRoleSubject;
918         assert(strlen(role) + 1 < ROLEID_LENGTH);
919         memcpy(ace->subjectRole.id, role, strlen(role) + 1);
920
921         if (authority != NULL)
922         {
923             assert(strlen(authority) + 1 < ROLEAUTHORITY_LENGTH);
924             memcpy(ace->subjectRole.authority, role, strlen(authority) + 1);
925         }
926         OIC_LOG_V(DEBUG, TAG, "Creating ACE with role id = %s, authority = %s:", ace->subjectRole.id, ace->subjectRole.authority);
927     }
928     else /* Create a subject based ACL */
929     {
930         /* Set uuid to our own */
931         OCStackResult res = OCGetDeviceId(&ownUuid);
932         if (res != OC_STACK_OK)
933         {
934             OIC_LOG_V(ERROR, TAG, "Failed to get own UUID, error: %d", res);
935             goto exit;
936         }
937         ace->subjectType = OicSecAceUuidSubject;
938         memcpy(ace->subjectuuid.id, ownUuid.id, sizeof(ace->subjectuuid.id));
939
940         OicUuid_t uuid = { 0 };
941         memcpy(uuid.id, ownUuid.id, sizeof(uuid.id));
942         OIC_LOG(DEBUG, TAG, "Creating ACE with UUID:");
943         printUuid(&uuid);
944     }
945
946     /* Add a resource (e.g. '/a/led') to the ACE */
947     rsrc = (OicSecRsrc_t*)OICCalloc(1, sizeof(OicSecRsrc_t));
948     if (!rsrc)
949     {
950         OIC_LOG_V(ERROR, TAG, "%s: OICCalloc failed (rsrc)", __func__);
951         goto exit;
952     }
953     LL_APPEND(ace->resources, rsrc);
954     rsrc->href = OICStrdup(resource);
955
956     /* Set resource type, e.g., 'core.led' */
957     rsrc->typeLen = 1;
958     rsrc->types = (char**)OICCalloc(rsrc->typeLen, sizeof(char*));
959     if (!rsrc->types)
960     {
961         OIC_LOG_V(ERROR, TAG, "%s: OICCalloc failed (rsrc->types)", __func__);
962         goto exit;
963     }
964     rsrc->types[0] = OICStrdup(resource_type);
965
966     /* Set interface, e.g., 'oic.if.baseline' */
967     rsrc->interfaceLen = 1;
968     rsrc->interfaces = (char**)OICCalloc(rsrc->interfaceLen, sizeof(char*));
969     if (!rsrc->interfaces)
970     {
971         OIC_LOG_V(ERROR, TAG, "%s: OICCalloc failed (rsrc->interfaces)", __func__);
972         goto exit;
973     }
974     rsrc->interfaces[0] = OICStrdup(resource_interface);
975
976     if (!rsrc->href || !rsrc->types[0] || !rsrc->interfaces[0])
977     {
978         OIC_LOG_V(ERROR, TAG, "%s: OICStrdup failed", __func__);
979         goto exit;
980     }
981
982     /* Set permission for the ACE */
983     ace->permission = perms;
984
985     ret = 0; /* success */
986     *newAcl = acl;
987
988 exit:
989
990     if (ret != 0)
991     {
992         *newAcl = NULL;
993         OCDeleteACLList(acl);
994     }
995
996     return ret;
997 }
998
999 static int provisionAcl(int dev_num, OicSecAcl_t* acl)
1000 {
1001     OCStackResult res = OC_STACK_ERROR;
1002
1003     OCProvisionDev_t* dev = getDevInst((const OCProvisionDev_t*)g_own_list, dev_num);
1004     if (!dev)
1005     {
1006         OIC_LOG(ERROR, TAG, "getDevInst: device instance empty");
1007         goto exit;
1008     }
1009
1010     g_doneCB = false;
1011     res = OCProvisionACL((void*)g_ctx, dev, acl, provisionAclCB);
1012     if (OC_STACK_OK != res)
1013     {
1014         OIC_LOG_V(ERROR, TAG, "OCProvisionACL API error: %d", res);
1015         goto exit;
1016     }
1017     if (waitCallbackRet())
1018     {
1019         OIC_LOG(ERROR, TAG, "OCProvisionACL callback error");
1020         goto exit;
1021     }
1022     if (!g_successCB)
1023     {
1024         OIC_LOG_V(ERROR, TAG, "%s callback completed, but failed", __func__);
1025         goto exit;
1026     }
1027
1028 exit:
1029
1030     return (res == OC_STACK_OK) ? 0 : -1;
1031 }
1032
1033 /* Function to work around IOT-1927.  The ocrandom.h include is only required for the workaround.
1034  * @todo: when IOT-1927 is resolved remove this function
1035  */
1036 int workAroundBug()
1037 {
1038     /* Remove credential for 31313131-3131-3131-3131-313131313131 */
1039     const char* uuidStr = "31313131-3131-3131-3131-313131313131";
1040     OicUuid_t uuid = { 0 };
1041     if (!OCConvertStringToUuid(uuidStr, uuid.id))
1042     {
1043         OIC_LOG(ERROR, TAG, "UUID conversion failed - caller bug, or the .dat file not longer contains a cred for this UUID. ");
1044         return -1;
1045     }
1046
1047     OCStackResult res = OCRemoveCredential(&uuid);
1048     if (res != OC_STACK_RESOURCE_DELETED)
1049     {
1050         OIC_LOG_V(ERROR, TAG, "%s failed to remove credential for subject UUID: ", __func__);
1051         OIC_LOG_BUFFER(DEBUG, TAG, uuid.id, UUID_LENGTH);
1052         return -1;
1053     }
1054
1055     return 0;
1056 }
1057
1058 static int testCertUse(int dev_num)
1059 {
1060     char* csr = NULL;
1061     char* deviceCert = NULL;
1062     const char* uri = "/a/led";
1063     OicSecAcl_t* acl = NULL;
1064
1065     // Make sure we own at least one device to provision
1066     if (!g_own_list || (g_own_cnt == 0))
1067     {
1068         OIC_LOG(ERROR, TAG, "Owned device list empty, must discover unowned devices first");
1069         return -1;  // Error, we should have registered unowned devices already
1070     }
1071
1072     /* Provision the device with the CA root, and issue it a cert. */
1073     if (provisionTrustAnchor(dev_num) != 0)
1074     {
1075         return -1;
1076     }
1077
1078     if (getCsr(dev_num, &csr) != 0)
1079     {
1080         return -1;
1081     }
1082
1083     int ret = createCertFromCSR(g_caKeyPem, g_caCertPem, csr, NULL, NULL, &deviceCert);
1084     if (ret != 0)
1085     {
1086         OIC_LOG_V(ERROR, TAG, "%s Failed to create identity certificate", __func__);
1087         goto exit;
1088     }
1089
1090     ret = provisionCert(dev_num, deviceCert);
1091     if (ret != 0)
1092     {
1093         OIC_LOG_V(ERROR, TAG, "%s Failed to provision certificate", __func__);
1094         goto exit;
1095     }
1096
1097     /* Try a GET request, expecting success because the owner credential is used.*/
1098     ret = doGetRequest(uri, dev_num);
1099     if (ret != 0)
1100     {
1101         OIC_LOG_V(ERROR, TAG, "%s failed when requesting %s", __func__, uri);
1102         goto exit;
1103     }
1104
1105     ret = createLedAcl(&acl, NULL, NULL);
1106     if (ret != 0)
1107     {
1108         OIC_LOG_V(ERROR, TAG, "%s failed to create ACL", __func__);
1109         goto exit;
1110     }
1111
1112     /* Provision an ACL on the server, allowing us to access '/a/led' with our cert. */
1113     ret = provisionAcl(dev_num, acl);
1114     if (ret != 0)
1115     {
1116         OIC_LOG_V(ERROR, TAG, "%s failed to provision ACL", __func__);
1117         goto exit;
1118     }
1119
1120     /* Remove the owner credential */
1121     OCStackResult res = OCRemoveCredential(&g_uuidDev1);
1122     if (res != OC_STACK_RESOURCE_DELETED)
1123     {
1124         OIC_LOG_V(ERROR, TAG, "%s failed to remove owner credential for subject UUID: ", __func__);
1125         OIC_LOG_BUFFER(DEBUG, TAG, g_uuidDev1.id, UUID_LENGTH);
1126         ret = -1;
1127         goto exit;
1128     }
1129
1130     /*
1131      * Work around bug IOT-1927
1132      * @todo: When that bug is resolved, remove this call and the function workAroundBug
1133      */
1134     if (workAroundBug() != 0)
1135     {
1136         OIC_LOG_V(ERROR, TAG, "%s bug workaround failed: ", __func__);
1137         ret = -1;
1138         goto exit;
1139     }
1140
1141     /* Close all secure sessions, so that we don't re-use a cached session */
1142     if (closeAllSessions() != 0)
1143     {
1144         OIC_LOG_V(ERROR, TAG, "%s Failed to close sessions", __func__);
1145         ret = -1;
1146         goto exit;
1147     }
1148
1149     /* Try a GET request, expect failure, we don't share a credential. */
1150     ret = doGetRequest(uri, dev_num);
1151     if (ret == 0)
1152     {
1153         OIC_LOG_V(ERROR, TAG, "%s Get request to %s succeeded, but should have failed", __func__, uri);
1154         goto exit;
1155     }
1156
1157     /* Provision ourself a valid certificate credential */
1158     ret = setupOwnCert(NULL);
1159     if (ret != 0)
1160     {
1161         OIC_LOG_V(ERROR, TAG, "%s Failed to self-provision a key/certificate", __func__);
1162         goto exit;
1163     }
1164
1165     /* Close all secure sessions again */
1166     if (closeAllSessions() != 0)
1167     {
1168         OIC_LOG_V(ERROR, TAG, "%s Failed to close sessions", __func__);
1169         ret = -1;
1170         goto exit;
1171     }
1172
1173     /* Try a get request, expect success */
1174     ret = doGetRequest(uri, dev_num);
1175     if (ret != 0)
1176     {
1177         OIC_LOG_V(ERROR, TAG, "%s Get request to %s failed, but should have succeeded", __func__, uri);
1178         goto exit;
1179     }
1180
1181 exit:
1182
1183     OICFree(csr);
1184     OICFree(deviceCert);
1185     OCDeleteACLList(acl);
1186
1187     return ret;
1188 }
1189
1190 static int testRoleProvisioning(int dev_num)
1191 {
1192     char* csr = NULL;
1193     char* idCert = NULL;
1194     char* roleCert = NULL;
1195
1196     // Make sure we own at least one device to provision
1197     if (!g_own_list || (g_own_cnt == 0))
1198     {
1199         OIC_LOG(ERROR, TAG, "Owned device list empty, must discover unowned devices first");
1200         return -1;  // Error, we should have registered unowned devices already
1201     }
1202
1203     /* Provision the device with the CA root, and issue it a role and identity cert. */
1204     if (provisionTrustAnchor(dev_num) != 0)
1205     {
1206         return -1;
1207     }
1208
1209     if (getCsr(dev_num, &csr) != 0)
1210     {
1211         return -1;
1212     }
1213
1214     int ret = createCertFromCSR(g_caKeyPem, g_caCertPem, csr, NULL, NULL, &idCert);
1215     if (ret != 0)
1216     {
1217         OIC_LOG_V(ERROR, TAG, "%s Failed to create identity certificate", __func__);
1218         goto exit;
1219     }
1220
1221     ret = provisionCert(dev_num, idCert);
1222     if (ret != 0)
1223     {
1224         OIC_LOG_V(ERROR, TAG, "%s Failed to provision id certificate", __func__);
1225         goto exit;
1226     }
1227
1228     /* The first role cert will have no authority field (it's optional) */
1229     ret = createCertFromCSR(g_caKeyPem, g_caCertPem, csr, TEST_CERT_ROLE1, NULL, &roleCert);
1230     if (ret != 0)
1231     {
1232         OIC_LOG_V(ERROR, TAG, "%s Failed to create role certificate", __func__);
1233         goto exit;
1234     }
1235
1236     ret = provisionCert(dev_num, roleCert);
1237     if (ret != 0)
1238     {
1239         OIC_LOG_V(ERROR, TAG, "%s Failed to provision role certificate", __func__);
1240         goto exit;
1241     }
1242     OICFreeAndSetToNull((void**)&roleCert);
1243
1244     /* The second will have the authority field set */
1245     ret = createCertFromCSR(g_caKeyPem, g_caCertPem, csr, TEST_CERT_ROLE2, TEST_CERT_AUTHORITY, &roleCert);
1246     if (ret != 0)
1247     {
1248         OIC_LOG_V(ERROR, TAG, "%s Failed to create role certificate", __func__);
1249         goto exit;
1250     }
1251
1252     ret = provisionCert(dev_num, roleCert);
1253     if (ret != 0)
1254     {
1255         OIC_LOG_V(ERROR, TAG, "%s Failed to provision role certificate", __func__);
1256         goto exit;
1257     }
1258
1259 exit:
1260
1261     OICFree(csr);
1262     OICFree(idCert);
1263     OICFree(roleCert);
1264
1265     return ret;
1266 }
1267
1268 static int testRoleAssertion(int dev_num)
1269 {
1270     char* csr = NULL;
1271     char* idCert = NULL;
1272     char* roleCert = NULL;
1273     OicSecAcl_t* acl = NULL;
1274
1275     /* Make sure we own at least one device to provision */
1276     if (!g_own_list || (g_own_cnt == 0))
1277     {
1278         OIC_LOG(ERROR, TAG, "Owned device list empty, must discover unowned devices first");
1279         return -1;  // Error, we should have registered unowned devices already
1280     }
1281
1282     /* Provision the device with the CA root, and issue it an identity cert. */
1283     if (provisionTrustAnchor(dev_num) != 0)
1284     {
1285         return -1;
1286     }
1287
1288     if (getCsr(dev_num, &csr) != 0)
1289     {
1290         return -1;
1291     }
1292
1293     int ret = createCertFromCSR(g_caKeyPem, g_caCertPem, csr, NULL, NULL, &idCert);
1294     if (ret != 0)
1295     {
1296         OIC_LOG_V(ERROR, TAG, "%s Failed to create identity certificate", __func__);
1297         goto exit;
1298     }
1299
1300     ret = provisionCert(dev_num, idCert);
1301     if (ret != 0)
1302     {
1303         OIC_LOG_V(ERROR, TAG, "%s Failed to provision id certificate", __func__);
1304         goto exit;
1305     }
1306
1307     /* Create and provision a role-based ACL allowing ROLE1 to access '/a/led'. */
1308     ret = createLedAcl(&acl, TEST_CERT_ROLE1, NULL);
1309     if (ret != 0)
1310     {
1311         OIC_LOG_V(ERROR, TAG, "%s failed to create led ACL", __func__);
1312         goto exit;
1313     }
1314
1315     ret = provisionAcl(dev_num, acl);
1316     if (ret != 0)
1317     {
1318         OIC_LOG_V(ERROR, TAG, "%s failed to provision led ACL", __func__);
1319         goto exit;
1320     }
1321
1322     /* Provision ourselves an identity and role cert.
1323      * For the identity cert we use a random UUID, since the server has an ACE granting our UUID
1324      * access to everything (as owner). We don't want to remove this ACE because it would lock
1325      * us out. Using another UUID makes us appear as another device on the network.
1326      */
1327     OicUuid_t notOurUuid;
1328     (void)OCGenerateUuid(notOurUuid.id);
1329     ret = setupOwnCert(&notOurUuid);
1330     if (ret != 0)
1331     {
1332         OIC_LOG_V(ERROR, TAG, "%s Failed to self-provision a key/certificate", __func__);
1333         goto exit;
1334     }
1335
1336     ret = setupOwnRoleCert(NULL, TEST_CERT_ROLE1, NULL);
1337     if (ret != 0)
1338     {
1339         OIC_LOG_V(ERROR, TAG, "%s Failed to self-provision a key/certificate", __func__);
1340         goto exit;
1341     }
1342
1343     /* Remove the owner credential so that we don't use it when asserting role certs. */
1344     OCStackResult res = OCRemoveCredential(&g_uuidDev1);
1345     if (res != OC_STACK_RESOURCE_DELETED)
1346     {
1347         OIC_LOG_V(ERROR, TAG, "%s failed to remove owner credential for subject UUID: ", __func__);
1348         OIC_LOG_BUFFER(DEBUG, TAG, g_uuidDev1.id, UUID_LENGTH);
1349         ret = -1;
1350         goto exit;
1351     }
1352
1353     /*
1354      * Work around bug IOT-1927
1355      * @todo: When that bug is resolved, remove this call and the function workAroundBug
1356      */
1357     if (workAroundBug() != 0)
1358     {
1359         OIC_LOG_V(ERROR, TAG, "%s bug workaround failed: ", __func__);
1360         ret = -1;
1361         goto exit;
1362     }
1363
1364     /* Close all secure sessions */
1365     if (closeAllSessions() != 0)
1366     {
1367         OIC_LOG_V(ERROR, TAG, "%s Failed to close sessions", __func__);
1368         ret = -1;
1369         goto exit;
1370     }
1371
1372     /* Assert role certificate */
1373     OCProvisionDev_t *device = NULL;
1374     device = getDevInst(g_own_list, dev_num);
1375     if (!device)
1376     {
1377         OIC_LOG(ERROR, TAG, "Selected device does not exist");
1378         ret = -1;
1379         goto exit;
1380     }
1381
1382     OCDevAddr devAddr = device->endpoint;
1383     devAddr.port = device->securePort;
1384
1385     g_doneCB = false;
1386     res = OCAssertRoles(g_ctx, &devAddr, assertRolesCB);
1387     if (res != OC_STACK_OK)
1388     {
1389         OIC_LOG_V(ERROR, TAG, "OCAssertRoles returned error %d with method", res);
1390         ret = -1;
1391         goto exit;
1392     }
1393     if (waitCallbackRet())
1394     {
1395         OIC_LOG_V(ERROR, TAG, "%s callback error", __func__);
1396     }
1397     if (!g_successCB)
1398     {
1399         ret = -1;
1400         goto exit;
1401     }
1402
1403 exit:
1404     OICFree(csr);
1405     OICFree(idCert);
1406     OICFree(roleCert);
1407     OCDeleteACLList(acl);
1408
1409     return ret;
1410 }
1411
1412 static int testRoleAssertionAndUse(int dev_num)
1413 {
1414     char* csr = NULL;
1415     char* idCert = NULL;
1416     char* roleCert = NULL;
1417     const char* uri = "/a/led";
1418     OicSecAcl_t* acl = NULL;
1419
1420     // Make sure we own at least one device to provision
1421     if (!g_own_list || (g_own_cnt == 0))
1422     {
1423         OIC_LOG(ERROR, TAG, "Owned device list empty, must discover unowned devices first");
1424         return -1;  // Error, we should have registered unowned devices already
1425     }
1426
1427     /* Provision the device with the CA root, and issue it an identity cert. */
1428     if (provisionTrustAnchor(dev_num) != 0)
1429     {
1430         return -1;
1431     }
1432
1433     if (getCsr(dev_num, &csr) != 0)
1434     {
1435         return -1;
1436     }
1437
1438     int ret = createCertFromCSR(g_caKeyPem, g_caCertPem, csr, NULL, NULL, &idCert);
1439     if (ret != 0)
1440     {
1441         OIC_LOG_V(ERROR, TAG, "%s Failed to create identity certificate", __func__);
1442         goto exit;
1443     }
1444
1445     ret = provisionCert(dev_num, idCert);
1446     if (ret != 0)
1447     {
1448         OIC_LOG_V(ERROR, TAG, "%s Failed to provision id certificate", __func__);
1449         goto exit;
1450     }
1451
1452     /* Create and provision a role-based ACL allowing ROLE1 to access '/a/led'. */
1453     ret = createLedAcl(&acl, TEST_CERT_ROLE1, NULL);
1454     if (ret != 0)
1455     {
1456         OIC_LOG_V(ERROR, TAG, "%s failed to create led ACL", __func__);
1457         goto exit;
1458     }
1459
1460     ret = provisionAcl(dev_num, acl);
1461     if (ret != 0)
1462     {
1463         OIC_LOG_V(ERROR, TAG, "%s failed to provision led ACL", __func__);
1464         goto exit;
1465     }
1466
1467     /* Provision ourselves an identity and role cert.
1468      * For the identity cert we use a random UUID, since the server has an ACE granting our UUID
1469      * access to everything (as owner). We don't want to remove this ACE because it would lock
1470      * us out. Using another UUID makes us appear as another device on the network.
1471      */
1472     OicUuid_t notOurUuid;
1473     (void) OCGenerateUuid(notOurUuid.id);
1474     ret = setupOwnCert(&notOurUuid);
1475     if (ret != 0)
1476     {
1477         OIC_LOG_V(ERROR, TAG, "%s Failed to self-provision a key/certificate", __func__);
1478         goto exit;
1479     }
1480
1481     ret = setupOwnRoleCert(NULL, TEST_CERT_ROLE1, NULL);
1482     if (ret != 0)
1483     {
1484         OIC_LOG_V(ERROR, TAG, "%s Failed to self-provision a key/certificate", __func__);
1485         goto exit;
1486     }
1487
1488     /* Remove the owner credential so that we don't use it when asserting role certs. */
1489     OCStackResult res = OCRemoveCredential(&g_uuidDev1);
1490     if (res != OC_STACK_RESOURCE_DELETED)
1491     {
1492         OIC_LOG_V(ERROR, TAG, "%s failed to remove owner credential for subject UUID: ", __func__);
1493         OIC_LOG_BUFFER(DEBUG, TAG, g_uuidDev1.id, UUID_LENGTH);
1494         ret = -1;
1495         goto exit;
1496     }
1497
1498     /*
1499     * Work around bug IOT-1927
1500     * @todo: When that bug is resolved, remove this call and the function workAroundBug
1501     */
1502     if (workAroundBug() != 0)
1503     {
1504         OIC_LOG_V(ERROR, TAG, "%s bug workaround failed: ", __func__);
1505         ret = -1;
1506         goto exit;
1507     }
1508
1509     /* Close all secure sessions */
1510     if (closeAllSessions() != 0)
1511     {
1512         OIC_LOG_V(ERROR, TAG, "%s Failed to close sessions", __func__);
1513         ret = -1;
1514         goto exit;
1515     }
1516
1517     /* Try a get request, expect success, role certificate will be automatically asserted */
1518     ret = doGetRequest(uri, dev_num);
1519     if (ret != 0)
1520     {
1521         OIC_LOG_V(ERROR, TAG, "%s Get request to %s failed, but should have succeeded", __func__, uri);
1522         goto exit;
1523     }
1524
1525 exit:
1526     OICFree(csr);
1527     OICFree(idCert);
1528     OICFree(roleCert);
1529     OCDeleteACLList(acl);
1530
1531     return ret;
1532 }
1533
1534 static int provisionSymmetricRoleCred(int dev_num)
1535 {
1536     OicSecRole_t role;
1537     memset(&role, 0, sizeof(role));
1538     OICStrcpy(role.id, sizeof(role.id), TEST_CERT_ROLE1);
1539
1540     // call |OCProvisionCredentials| API
1541     // calling this API with callback actually acts like blocking
1542     // for error checking, the return value saved and printed
1543     g_doneCB = false;
1544     OCStackResult rst =
1545         OCProvisionSymmetricRoleCredentials((void*) g_ctx,
1546                     SYMMETRIC_PAIR_WISE_KEY, OWNER_PSK_LENGTH_128,
1547                     getDevInst((const OCProvisionDev_t*) g_own_list, dev_num),
1548                     NULL, NULL, &role,
1549                     provisionCredCB);
1550     if (OC_STACK_OK != rst)
1551     {
1552         OIC_LOG_V(ERROR, TAG, "OCProvisionCredentials API error: %d", rst);
1553         return -1;
1554     }
1555     if (waitCallbackRet())  // input |g_doneCB| flag implicitly
1556     {
1557         OIC_LOG(ERROR, TAG, "OCProvisionCredentials callback error");
1558         return -1;
1559     }
1560
1561     return 0;
1562 }
1563
1564 static int testSymmetricRoleUse(int dev_num)
1565 {
1566     const char* uri = "/a/led";
1567     OicSecAcl_t* acl = NULL;
1568
1569     // Make sure we own at least one device to provision
1570     if (!g_own_list || (g_own_cnt == 0))
1571     {
1572         OIC_LOG(ERROR, TAG, "Owned device list empty, must discover unowned devices first");
1573         return -1;  // Error, we should have registered unowned devices already
1574     }
1575
1576     /* Create and provision a role-based ACL allowing ROLE1 to access '/a/led'. */
1577     int ret = createLedAcl(&acl, TEST_CERT_ROLE1, NULL);
1578     if (ret != 0)
1579     {
1580         OIC_LOG_V(ERROR, TAG, "%s failed to create led ACL", __func__);
1581         return ret;
1582     }
1583
1584     ret = provisionAcl(dev_num, acl);
1585     if (ret != 0)
1586     {
1587         OIC_LOG_V(ERROR, TAG, "%s failed to provision led ACL", __func__);
1588         goto exit;
1589     }
1590
1591     /* Remove the owner credential so that we don't use it when asserting role certs. */
1592     OCStackResult res = OCRemoveCredential(&g_uuidDev1);
1593     if (res != OC_STACK_RESOURCE_DELETED)
1594     {
1595         OIC_LOG_V(ERROR, TAG, "%s failed to remove owner credential for subject UUID: ", __func__);
1596         OIC_LOG_BUFFER(DEBUG, TAG, g_uuidDev1.id, UUID_LENGTH);
1597         ret = -1;
1598         goto exit;
1599     }
1600
1601     /* The server has an owner PSK associated with our GUID. Change our GUID to something else,
1602      * which will both be used to generate the role credential and for the later connection.
1603      */
1604     const OCUUIdentity newIdentity = { .id = { 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46 } };
1605     if (OC_STACK_OK != OCSetDeviceId(&newIdentity))
1606     {
1607         OIC_LOG_V(ERROR, TAG, "%s failed to set device ID", __func__);
1608         ret = -1;
1609         goto exit;
1610     }
1611
1612     /* Create a new symmetric credential with the role. */
1613     ret = provisionSymmetricRoleCred(dev_num);
1614     if (ret != 0)
1615     {
1616         OIC_LOG_V(ERROR, TAG, "%s failed to provision symmetric role pair-wise keys", __func__);
1617         goto exit;
1618     }
1619
1620     /* Close all secure sessions */
1621     if (closeAllSessions() != 0)
1622     {
1623         OIC_LOG_V(ERROR, TAG, "%s Failed to close sessions", __func__);
1624         ret = -1;
1625         goto exit;
1626     }
1627
1628     /* Try a get request, expect success */
1629     ret = doGetRequest(uri, dev_num);
1630     if (ret != 0)
1631     {
1632         OIC_LOG_V(ERROR, TAG, "%s Get request to %s failed, but should have succeeded", __func__, uri);
1633         goto exit;
1634     }
1635
1636 exit:
1637
1638     OCDeleteACLList(acl);
1639
1640     return ret;
1641 }
1642
1643 /* Get a specific device from the provided device list. The devices in the list
1644  * are numbered starting from 1.
1645  */
1646 static OCProvisionDev_t* getDevInst(const OCProvisionDev_t* dev_lst, const int dev_num)
1647 {
1648     if (!dev_lst || 0 >= dev_num)
1649     {
1650         printf("     Device List is Empty..\n");
1651         return NULL;
1652     }
1653
1654     OCProvisionDev_t* lst = (OCProvisionDev_t*)dev_lst;
1655     for (int i = 0; lst; )
1656     {
1657         if (dev_num == ++i)
1658         {
1659             return lst;
1660         }
1661         lst = lst->next;
1662     }
1663
1664     OIC_LOG_V(ERROR, TAG, "%s failed, requested device not found in list (does the device need to be discovered or owned first?)", __func__);
1665     return NULL;  // in here |lst| is always |NULL|
1666 }
1667
1668 static int printDevList(const OCProvisionDev_t* dev_lst)
1669 {
1670     if (!dev_lst)
1671     {
1672         printf("     Device List is Empty..\n\n");
1673         return 0;
1674     }
1675
1676     OCProvisionDev_t* lst = (OCProvisionDev_t*)dev_lst;
1677     int lst_cnt = 0;
1678     for (; lst; )
1679     {
1680         printf("     [%d] ", ++lst_cnt);
1681         printUuid((const OicUuid_t*)&lst->doxm->deviceID);
1682         printf("\n");
1683         lst = lst->next;
1684     }
1685     printf("\n");
1686
1687     return lst_cnt;
1688 }
1689
1690 static size_t printResultList(const OCProvisionResult_t* rslt_lst, const size_t rslt_cnt)
1691 {
1692     if (!rslt_lst || (0 == rslt_cnt))
1693     {
1694         printf("     Device List is Empty..\n\n");
1695         return 0;
1696     }
1697
1698     size_t lst_cnt = 0;
1699     for (; rslt_cnt > lst_cnt; ++lst_cnt)
1700     {
1701         printf("     [%" PRIuPTR "] ", lst_cnt + 1);
1702         printUuid((const OicUuid_t*)&rslt_lst[lst_cnt].deviceId);
1703         printf(" - result: %d\n", rslt_lst[lst_cnt].res);
1704     }
1705     printf("\n");
1706
1707     return lst_cnt;
1708 }
1709
1710 static int saveUuid(const OCProvisionResult_t* rslt_lst, const size_t rslt_cnt)
1711 {
1712     if (!rslt_lst || (rslt_cnt != 1))
1713     {
1714         OIC_LOG_V(ERROR, TAG, "%s: expected only one device", __func__);
1715         return -1;
1716     }
1717
1718     memcpy(&g_uuidDev1, &rslt_lst[0].deviceId, sizeof(OicUuid_t));
1719
1720     return 0;
1721 }
1722
1723 static void printUuid(const OicUuid_t* uid)
1724 {
1725     for (int i = 0; i<UUID_LENGTH; )
1726     {
1727         printf("%02X", (*uid).id[i++]);
1728         if (i == 4 || i == 6 || i == 8 || i == 10)  // canonical format for UUID has '8-4-4-4-12'
1729         {
1730             printf("-");
1731         }
1732     }
1733     printf("\n");
1734 }
1735
1736 static FILE* fopen_prvnMng(const char* path, const char* mode)
1737 {
1738     if (0 == strncmp(path, OC_SECURITY_DB_DAT_FILE_NAME, strlen(OC_SECURITY_DB_DAT_FILE_NAME)))
1739     {
1740         // input |g_svr_db_fname| internally by force, not using |path| parameter
1741         // because |OCPersistentStorage::open| is called |OCPersistentStorage| internally
1742         // with its own |SVR_DB_FILE_NAME|
1743         return fopen(SVR_DB_FILE_NAME, mode);
1744     }
1745     else
1746     {
1747         return fopen(path, mode);
1748     }
1749 }
1750
1751 static int waitCallbackRet(void)
1752 {
1753     for(int i = 0; !g_doneCB; ++i)
1754     {
1755         if(OC_STACK_OK != OCProcess())
1756         {
1757             OIC_LOG(ERROR, TAG, "OCStack process error");
1758             return -1;
1759         }
1760
1761         if (i == CALLBACK_TIMEOUT)
1762         {
1763             return -1;
1764         }
1765
1766         sleep(1);
1767     }
1768
1769     return 0;
1770 }
1771
1772 void shutdownProvisionClient(void)
1773 {
1774     if(OC_STACK_OK != OCStop())
1775     {
1776         OIC_LOG(ERROR, TAG, "OCStack stop error");
1777     }
1778     OCDeleteDiscoveredDevices(g_own_list);  // after here |g_own_list| points to nothing
1779     OCDeleteDiscoveredDevices(g_unown_list);  // after here |g_unown_list| points to nothing
1780
1781     OICFreeAndSetToNull((void**)&g_svr_fname);
1782     OICFreeAndSetToNull((void**)&g_prvn_fname);
1783 }
1784
1785 static int initDiscoverRegisterAllDevices(void)
1786 {
1787     if(initProvisionClient())
1788     {
1789         OIC_LOG_V(ERROR, TAG, "%s: ProvisionClient init error", __func__);
1790         return -1;
1791     }
1792
1793     if(discoverAllDevices())
1794     {
1795         OIC_LOG_V(ERROR, TAG, "%s: Discovery failed", __func__);
1796         return -1;
1797     }
1798
1799     if(registerDevices())
1800     {
1801         OIC_LOG_V(ERROR, TAG, "%s: Failed to onboard devices", __func__);
1802         return -1;
1803     }
1804
1805     if(discoverAllDevices())
1806     {
1807         OIC_LOG_V(ERROR, TAG, "%s: Re-discovery failed after registerDevices", __func__);
1808         return -1;
1809     }
1810
1811     return 0;
1812
1813 }
1814
1815 int TestTrustAnchorProvisioning(void)
1816 {
1817     int ret = -1;
1818
1819     OIC_LOG_V(ERROR, TAG, "Running %s", __func__);
1820
1821     if(initDiscoverRegisterAllDevices())
1822     {
1823         OIC_LOG_V(ERROR, TAG, "%s: Failed to discover and provision devices", __func__);
1824         goto exit;
1825     }
1826
1827     /* There should be one owned device with number 1. */
1828     if(provisionTrustAnchor(1))
1829     {
1830         OIC_LOG_V(ERROR, TAG, "%s: Failed to provision trust anchor to device", __func__);
1831         goto exit;
1832     }
1833
1834     ret = 0;
1835
1836 exit:
1837
1838     shutdownProvisionClient();
1839
1840     return ret;
1841 }
1842
1843 int TestCSRResource(void)
1844 {
1845     int ret = -1;
1846
1847     OIC_LOG_V(ERROR, TAG, "Running %s", __func__);
1848
1849     if(initDiscoverRegisterAllDevices())
1850     {
1851         OIC_LOG_V(ERROR, TAG, "%s: Failed to discover and provision devices", __func__);
1852         goto exit;
1853     }
1854
1855     /* There should be one owned device with number 1. */
1856     if(getCsr(1, NULL))
1857     {
1858         OIC_LOG(ERROR, TAG, "Failed to get CSR from device");
1859         goto exit;
1860     }
1861
1862     ret = 0;
1863
1864 exit:
1865
1866     shutdownProvisionClient();
1867
1868     return ret;
1869 }
1870
1871 int TestCertUse(void)
1872 {
1873     int ret = -1;
1874
1875     OIC_LOG_V(ERROR, TAG, "Running %s", __func__);
1876
1877     if (initDiscoverRegisterAllDevices())
1878     {
1879         OIC_LOG_V(ERROR, TAG, "%s: Failed to discover and provision devices", __func__);
1880         goto exit;
1881     }
1882
1883     /* There should be one owned device with number 1. */
1884     if (testCertUse(1))
1885     {
1886         OIC_LOG(ERROR, TAG, "Failed to authenticate to device with certificate");
1887         goto exit;
1888     }
1889
1890     ret = 0;
1891
1892 exit:
1893
1894     shutdownProvisionClient();
1895
1896     return ret;
1897 }
1898
1899 int TestRoleProvisioning(void)
1900 {
1901     int ret = -1;
1902
1903     OIC_LOG_V(ERROR, TAG, "Running %s", __func__);
1904
1905     if (initDiscoverRegisterAllDevices())
1906     {
1907         OIC_LOG_V(ERROR, TAG, "%s: Failed to discover and provision devices", __func__);
1908         goto exit;
1909     }
1910
1911     /* There should be one owned device with number 1. */
1912     if (testRoleProvisioning(1))
1913     {
1914         OIC_LOG(ERROR, TAG, "Failed to provision roles to device");
1915         goto exit;
1916     }
1917
1918     ret = 0;
1919
1920 exit:
1921
1922     shutdownProvisionClient();
1923
1924     return ret;
1925 }
1926
1927 int TestRoleAssertion(void)
1928 {
1929     int ret = -1;
1930
1931     OIC_LOG_V(ERROR, TAG, "Running %s", __func__);
1932
1933     if (initDiscoverRegisterAllDevices())
1934     {
1935         OIC_LOG_V(ERROR, TAG, "%s: Failed to discover and provision devices", __func__);
1936         goto exit;
1937     }
1938
1939     /* There should be one owned device with number 1. */
1940     if (testRoleAssertion(1))
1941     {
1942         OIC_LOG(ERROR, TAG, "Failed to assert roles");
1943         goto exit;
1944     }
1945
1946     ret = 0;
1947
1948 exit:
1949
1950     shutdownProvisionClient();
1951
1952     return ret;
1953 }
1954
1955 int TestRoleAssertionAndUse(void)
1956 {
1957     int ret = -1;
1958
1959     OIC_LOG_V(ERROR, TAG, "Running %s", __func__);
1960
1961     if (initDiscoverRegisterAllDevices())
1962     {
1963         OIC_LOG_V(ERROR, TAG, "%s: Failed to discover and provision devices", __func__);
1964         goto exit;
1965     }
1966
1967     /* There should be one owned device with number 1. */
1968     if (testRoleAssertionAndUse(1))
1969     {
1970         OIC_LOG(ERROR, TAG, "Failed to assert and use roles");
1971         goto exit;
1972     }
1973
1974     ret = 0;
1975
1976 exit:
1977
1978     shutdownProvisionClient();
1979
1980     return ret;
1981 }
1982
1983 int TestSymmetricRoleUse(void)
1984 {
1985     int ret = -1;
1986
1987     OIC_LOG_V(ERROR, TAG, "Running %s", __func__);
1988
1989     if (initDiscoverRegisterAllDevices())
1990     {
1991         OIC_LOG_V(ERROR, TAG, "%s: Failed to discover and provision devices", __func__);
1992         goto exit;
1993     }
1994
1995     /* There should be one owned device with number 1. */
1996     if (testSymmetricRoleUse(1))
1997     {
1998         OIC_LOG(ERROR, TAG, "Failed to use symmetric key role");
1999         goto exit;
2000     }
2001
2002     ret = 0;
2003
2004 exit:
2005
2006     shutdownProvisionClient();
2007
2008     return ret;
2009 }
2010
2011 // main function for provisioning client using C-level provisioning API
2012 int main(int argc, char** argv)
2013 {
2014     if(argc != 2)
2015     {
2016         printf("%s: No test number provided (argc = %d)\n", argv[0], argc);
2017         return 1;
2018     }
2019
2020     unsigned int testNumber = strtoul(argv[1], NULL, 10);
2021     switch (testNumber)
2022     {
2023         case 1:
2024             return TestTrustAnchorProvisioning();
2025         case 2:
2026             return TestCSRResource();
2027         case 3:
2028             return TestCertUse();
2029         case 4:
2030             return TestRoleProvisioning();
2031         case 5:
2032             return TestRoleAssertion();
2033         case 6:
2034             return TestRoleAssertionAndUse();
2035         case 7:
2036             return TestSymmetricRoleUse();
2037         default:
2038             printf("%s: Invalid test number\n", argv[0]);
2039             return 1;
2040
2041         /* Note: when adding a new test, update NUM_TESTS in provisioningTest.py */
2042     }
2043
2044 }
2045
2046 #ifdef __cplusplus
2047 }
2048 #endif //__cplusplus