CBOR rebase onto master for merge/review
[iotivity.git] / resource / csdk / security / src / doxmresource.c
1 //******************************************************************
2 //
3 // Copyright 2015 Intel Mobile Communications GmbH 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 "ocstack.h"
22 #include "logger.h"
23 #include "oic_malloc.h"
24 #include "cJSON.h"
25 #include "resourcemanager.h"
26 #include "doxmresource.h"
27 #include "psinterface.h"
28 #include "utlist.h"
29 #include "srmresourcestrings.h"
30 #include "securevirtualresourcetypes.h"
31 #include "base64.h"
32 #include "ocrandom.h"
33 #include "cainterface.h"
34 #include "credresource.h"
35 #include "ocserverrequest.h"
36 #include "srmutility.h"
37 #include <stdlib.h>
38 #include <string.h>
39
40 #if HAVE_STRINGS_H
41 #include <strings.h>
42 #endif
43
44 #define TAG  PCF("SRM-DOXM")
45
46 static OicSecDoxm_t        *gDoxm = NULL;
47 static OCResourceHandle    gDoxmHandle = NULL;
48
49 static OicSecOxm_t gOicSecDoxmJustWorks = OIC_JUST_WORKS;
50 static OicSecDoxm_t gDefaultDoxm =
51 {
52     NULL,                   /* OicUrn_t *oxmType */
53     0,                      /* size_t oxmTypeLen */
54     &gOicSecDoxmJustWorks,  /* uint16_t *oxm */
55     1,                      /* size_t oxmLen */
56     OIC_JUST_WORKS,         /* uint16_t oxmSel */
57     false,                  /* bool owned */
58     {},                     /* OicUuid_t deviceID */
59     {},                     /* OicUuid_t owner */
60 };
61
62 void DeleteDoxmBinData(OicSecDoxm_t* doxm)
63 {
64     if (doxm)
65     {
66         //Clean oxmType
67         for(int i = 0; i < doxm->oxmTypeLen; i++)
68         {
69             OICFree(doxm->oxmType[i]);
70         }
71         OICFree(doxm->oxmType);
72
73         //clean oxm
74         OICFree(doxm->oxm);
75
76         //Clean doxm itself
77         OICFree(doxm);
78     }
79 }
80
81 char * BinToDoxmJSON(const OicSecDoxm_t * doxm)
82 {
83     if (NULL == doxm)
84     {
85         return NULL;
86     }
87
88     char *jsonStr = NULL;
89     cJSON *jsonDoxm = NULL;
90     char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(((OicUuid_t*)0)->id)) + 1] = {};
91     uint32_t outLen = 0;
92     B64Result b64Ret = B64_OK;
93
94     cJSON *jsonRoot = cJSON_CreateObject();
95     VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
96
97     jsonDoxm = cJSON_CreateObject();
98     VERIFY_NON_NULL(TAG, jsonDoxm, ERROR);
99     cJSON_AddItemToObject(jsonRoot, OIC_JSON_DOXM_NAME, jsonDoxm );
100
101     //OxmType -- Not Mandatory
102     if(doxm->oxmTypeLen > 0)
103     {
104         cJSON *jsonOxmTyArray = cJSON_CreateArray();
105         VERIFY_NON_NULL(TAG, jsonOxmTyArray, ERROR);
106         cJSON_AddItemToObject (jsonDoxm, OIC_JSON_OXM_TYPE_NAME, jsonOxmTyArray );
107         for (size_t i = 0; i < doxm->oxmTypeLen; i++)
108         {
109             cJSON_AddItemToArray (jsonOxmTyArray, cJSON_CreateString(doxm->oxmType[i]));
110         }
111     }
112
113     //Oxm -- Not Mandatory
114     if(doxm->oxmLen > 0)
115     {
116         cJSON *jsonOxmArray = cJSON_CreateArray();
117         VERIFY_NON_NULL(TAG, jsonOxmArray, ERROR);
118         cJSON_AddItemToObject (jsonDoxm, OIC_JSON_OXM_NAME,jsonOxmArray );
119         for (size_t i = 0; i < doxm->oxmLen; i++)
120         {
121             cJSON_AddItemToArray (jsonOxmArray, cJSON_CreateNumber(doxm->oxm[i]));
122         }
123     }
124
125     //OxmSel -- Mandatory
126     cJSON_AddNumberToObject(jsonDoxm, OIC_JSON_OXM_SEL_NAME, (int)doxm->oxmSel);
127
128     //Owned -- Mandatory
129     cJSON_AddBoolToObject(jsonDoxm, OIC_JSON_OWNED_NAME, doxm->owned);
130
131     //TODO: Need more clarification on deviceIDFormat field type.
132 #if 0
133     //DeviceIdFormat -- Mandatory
134     cJSON_AddNumberToObject(jsonDoxm, OIC_JSON_DEVICE_ID_FORMAT_NAME, doxm->deviceIDFormat);
135 #endif
136
137     //DeviceId -- Mandatory
138     outLen = 0;
139     b64Ret = b64Encode(doxm->deviceID.id, sizeof(doxm->deviceID.id), base64Buff,
140                     sizeof(base64Buff), &outLen);
141     VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
142     cJSON_AddStringToObject(jsonDoxm, OIC_JSON_DEVICE_ID_NAME, base64Buff);
143
144     //Owner -- Mandatory
145     outLen = 0;
146     b64Ret = b64Encode(doxm->owner.id, sizeof(doxm->owner.id), base64Buff,
147                     sizeof(base64Buff), &outLen);
148     VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
149     cJSON_AddStringToObject(jsonDoxm, OIC_JSON_OWNER_NAME, base64Buff);
150
151     jsonStr = cJSON_PrintUnformatted(jsonRoot);
152
153 exit:
154     if (jsonRoot)
155     {
156         cJSON_Delete(jsonRoot);
157     }
158     return jsonStr;
159 }
160
161 OicSecDoxm_t * JSONToDoxmBin(const char * jsonStr)
162 {
163
164     if (NULL == jsonStr)
165     {
166         return NULL;
167     }
168
169     OCStackResult ret = OC_STACK_ERROR;
170     OicSecDoxm_t *doxm =  NULL;
171     cJSON *jsonDoxm = NULL;
172     cJSON *jsonObj = NULL;
173
174     size_t jsonObjLen = 0;
175     unsigned char base64Buff[sizeof(((OicUuid_t*)0)->id)] = {};
176     uint32_t outLen = 0;
177     B64Result b64Ret = B64_OK;
178
179     cJSON *jsonRoot = cJSON_Parse(jsonStr);
180     VERIFY_NON_NULL(TAG, jsonRoot, ERROR);
181
182     jsonDoxm = cJSON_GetObjectItem(jsonRoot, OIC_JSON_DOXM_NAME);
183     VERIFY_NON_NULL(TAG, jsonDoxm, ERROR);
184
185     doxm = (OicSecDoxm_t*)OICCalloc(1, sizeof(OicSecDoxm_t));
186     VERIFY_NON_NULL(TAG, doxm, ERROR);
187
188     //OxmType -- not Mandatory
189     jsonObj = cJSON_GetObjectItem(jsonDoxm, OIC_JSON_OXM_TYPE_NAME);
190     if ((jsonObj) && (cJSON_Array == jsonObj->type))
191     {
192         doxm->oxmTypeLen = cJSON_GetArraySize(jsonObj);
193         VERIFY_SUCCESS(TAG, doxm->oxmTypeLen > 0, ERROR);
194
195         doxm->oxmType = (OicUrn_t *)OICCalloc(doxm->oxmTypeLen, sizeof(char *));
196         VERIFY_NON_NULL(TAG, (doxm->oxmType), ERROR);
197
198         for(int i  = 0; i < doxm->oxmTypeLen ; i++)
199         {
200             cJSON *jsonOxmTy = cJSON_GetArrayItem(jsonObj, i);
201             VERIFY_NON_NULL(TAG, jsonOxmTy, ERROR);
202
203             jsonObjLen = strlen(jsonOxmTy->valuestring) + 1;
204             doxm->oxmType[i] = (char*)OICMalloc(jsonObjLen);
205             VERIFY_NON_NULL(TAG, doxm->oxmType[i], ERROR);
206             strncpy((char *)doxm->oxmType[i], (char *)jsonOxmTy->valuestring, jsonObjLen);
207         }
208     }
209
210     //Oxm -- not Mandatory
211     jsonObj = cJSON_GetObjectItem(jsonDoxm, OIC_JSON_OXM_NAME);
212     if (jsonObj && cJSON_Array == jsonObj->type)
213     {
214         doxm->oxmLen = cJSON_GetArraySize(jsonObj);
215         VERIFY_SUCCESS(TAG, doxm->oxmLen > 0, ERROR);
216
217         doxm->oxm = (OicSecOxm_t*)OICCalloc(doxm->oxmLen, sizeof(short));
218         VERIFY_NON_NULL(TAG, doxm->oxm, ERROR);
219
220         for(int i  = 0; i < doxm->oxmLen ; i++)
221         {
222             cJSON *jsonOxm = cJSON_GetArrayItem(jsonObj, i);
223             VERIFY_NON_NULL(TAG, jsonOxm, ERROR);
224             doxm->oxm[i] = (OicSecOxm_t)jsonOxm->valueint;
225         }
226     }
227
228     //OxmSel -- Mandatory
229     jsonObj = cJSON_GetObjectItem(jsonDoxm, OIC_JSON_OXM_SEL_NAME);
230     if(jsonObj)
231     {
232         VERIFY_SUCCESS(TAG, cJSON_Number == jsonObj->type, ERROR)
233         doxm->oxmSel = (OicSecOxm_t)jsonObj->valueint;
234     }
235     else // PUT/POST JSON may not have oxmsel so set it to the gDoxm->oxmSel
236     {
237         VERIFY_NON_NULL(TAG, gDoxm, ERROR);
238         doxm->oxmSel = gDoxm->oxmSel;
239     }
240
241     //Owned -- Mandatory
242     jsonObj = cJSON_GetObjectItem(jsonDoxm, OIC_JSON_OWNED_NAME);
243     if(jsonObj)
244     {
245         VERIFY_SUCCESS(TAG, (cJSON_True == jsonObj->type || cJSON_False == jsonObj->type), ERROR)
246         doxm->owned = jsonObj->valueint;
247     }
248     else // PUT/POST JSON may not have owned so set it to the gDomx->owned
249     {
250         VERIFY_NON_NULL(TAG, gDoxm, ERROR);
251         doxm->owned = gDoxm->owned;
252     }
253
254     //DeviceId -- Mandatory
255     jsonObj = cJSON_GetObjectItem(jsonDoxm, OIC_JSON_DEVICE_ID_NAME);
256     if(jsonObj)
257     {
258         VERIFY_SUCCESS(TAG, cJSON_String == jsonObj->type, ERROR);
259         if(cJSON_String == jsonObj->type)
260         {
261             //Check for empty string, in case DeviceId field has not been set yet
262             if (jsonObj->valuestring[0])
263             {
264                 outLen = 0;
265                 b64Ret = b64Decode(jsonObj->valuestring, strlen(jsonObj->valuestring), base64Buff,
266                         sizeof(base64Buff), &outLen);
267                 VERIFY_SUCCESS(TAG, (b64Ret == B64_OK && outLen <= sizeof(doxm->deviceID.id)),
268                                 ERROR);
269                 memcpy(doxm->deviceID.id, base64Buff, outLen);
270             }
271         }
272     }
273     else // PUT/POST JSON will not have deviceID so set it to the gDoxm->deviceID.id
274     {
275         VERIFY_NON_NULL(TAG, gDoxm, ERROR);
276         VERIFY_SUCCESS(TAG, strcmp((char *)gDoxm->deviceID.id, "") != 0, ERROR);
277         strncpy((char *)doxm->deviceID.id, (char *)gDoxm->deviceID.id, sizeof(doxm->deviceID.id));
278     }
279
280     // Owner -- will be empty when device state is unowned.
281     if (true == doxm->owned)
282     {
283         jsonObj = cJSON_GetObjectItem(jsonDoxm, OIC_JSON_OWNER_NAME);
284         VERIFY_NON_NULL(TAG, jsonObj, ERROR);
285         VERIFY_SUCCESS(TAG, cJSON_String == jsonObj->type, ERROR)
286             outLen = 0;
287         b64Ret = b64Decode(jsonObj->valuestring, strlen(jsonObj->valuestring), base64Buff,
288                 sizeof(base64Buff), &outLen);
289         VERIFY_SUCCESS(TAG, (b64Ret == B64_OK && outLen <= sizeof(doxm->owner.id)), ERROR);
290         memcpy(doxm->owner.id, base64Buff, outLen);
291     }
292
293     ret = OC_STACK_OK;
294
295 exit:
296     cJSON_Delete(jsonRoot);
297     if (OC_STACK_OK != ret)
298     {
299         DeleteDoxmBinData(doxm);
300         doxm = NULL;
301     }
302
303     return doxm;
304 }
305
306 /**
307  * @todo document this function including why code might need to call this.
308  * The current suspicion is that it's not being called as much as it should.
309  */
310 static bool UpdatePersistentStorage(OicSecDoxm_t * doxm)
311 {
312     bool bRet = false;
313
314     if (NULL != doxm)
315     {
316         // Convert Doxm data into JSON for update to persistent storage
317         char *jsonStr = BinToDoxmJSON(doxm);
318         if (jsonStr)
319         {
320             cJSON *jsonDoxm = cJSON_Parse(jsonStr);
321             OICFree(jsonStr);
322
323             if (jsonDoxm &&
324                     (OC_STACK_OK == UpdateSVRDatabase(OIC_JSON_DOXM_NAME, jsonDoxm)))
325             {
326                 bRet = true;
327             }
328             cJSON_Delete(jsonDoxm);
329         }
330     }
331
332     return bRet;
333 }
334
335 static bool ValidateQuery(unsigned char * query)
336 {
337     // Send doxm resource data if the state of doxm resource
338     // matches with the query parameters.
339     // else send doxm resource data as NULL
340     // TODO Remove this check and rely on Policy Engine
341     // and Provisioning Mode to enforce provisioning-state
342     // access rules. Eventually, the PE and PM code will
343     // not send a request to the /doxm Entity Handler at all
344     // if it should not respond.
345     OC_LOG (INFO, TAG, PCF("In ValidateQuery"));
346     if(NULL == gDoxm)
347     {
348         return false;
349     }
350
351     OicParseQueryIter_t parseIter = {};
352
353     ParseQueryIterInit(query, &parseIter);
354
355     while(GetNextQuery(&parseIter))
356     {
357         if(strncasecmp((char *)parseIter.attrPos, OIC_JSON_OWNED_NAME, parseIter.attrLen) == 0)
358         {
359             if((strncasecmp((char *)parseIter.valPos, OIC_SEC_TRUE, parseIter.valLen) == 0) &&
360                     (gDoxm->owned))
361             {
362                 return true;
363             }
364             else if((strncasecmp((char *)parseIter.valPos, OIC_SEC_FALSE, parseIter.valLen) == 0)
365                     && (!gDoxm->owned))
366             {
367                 return true;
368             }
369         }
370     }
371     return false;
372 }
373
374 static OCEntityHandlerResult HandleDoxmGetRequest (const OCEntityHandlerRequest * ehRequest)
375 {
376     char* jsonStr = NULL;
377     OCEntityHandlerResult ehRet = OC_EH_OK;
378
379     OC_LOG (INFO, TAG, PCF("Doxm EntityHandle processing GET request"));
380
381     //Checking if Get request is a query.
382     if(ehRequest->query)
383     {
384         OC_LOG (INFO, TAG, PCF("HandleDoxmGetRequest processing query"));
385         if(!ValidateQuery((unsigned char *)ehRequest->query))
386         {
387             ehRet = OC_EH_ERROR;
388         }
389     }
390
391     /*
392      * For GET or Valid Query request return doxm resource json payload.
393      * For non-valid query return NULL json payload.
394      * A device will 'always' have a default Doxm, so BinToDoxmJSON will
395      * return valid doxm resource json.
396      */
397
398     jsonStr = (ehRet == OC_EH_OK) ? BinToDoxmJSON(gDoxm) : NULL;
399
400     // Send response payload to request originator
401     if(OC_STACK_OK != SendSRMResponse(ehRequest, ehRet, jsonStr))
402     {
403         OC_LOG (ERROR, TAG, PCF("SendSRMResponse failed in HandleDoxmGetRequest"));
404     }
405
406     OICFree(jsonStr);
407
408     return ehRet;
409 }
410
411
412 static OCEntityHandlerResult HandleDoxmPutRequest (const OCEntityHandlerRequest * ehRequest)
413 {
414     OC_LOG (INFO, TAG, PCF("Doxm EntityHandle  processing PUT request"));
415     OCEntityHandlerResult ehRet = OC_EH_ERROR;
416     OicUuid_t emptyOwner = {};
417
418     /*
419      * Convert JSON Doxm data into binary. This will also validate
420      * the Doxm data received.
421      */
422     OicSecDoxm_t* newDoxm = JSONToDoxmBin(((OCSecurityPayload*)ehRequest->payload)->securityData);
423
424     if (newDoxm)
425     {
426         // Iotivity SRM ONLY supports OIC_JUST_WORKS now
427         if (OIC_JUST_WORKS == newDoxm->oxmSel)
428         {
429             /*
430              * If current state of the device is un-owned, enable
431              * anonymous ECDH cipher in tinyDTLS so that Provisioning
432              * tool can initiate JUST_WORKS ownership transfer process.
433              */
434             if ((false == gDoxm->owned) && (false == newDoxm->owned))
435             {
436                 OC_LOG (INFO, TAG, PCF("Doxm EntityHandle  enabling AnonECDHCipherSuite"));
437 #ifdef __WITH_DTLS__
438                 ehRet = (CAEnableAnonECDHCipherSuite(true) == CA_STATUS_OK) ? OC_EH_OK : OC_EH_ERROR;
439 #endif //__WITH_DTLS__
440                 goto exit;
441             }
442
443             /*
444              * When current state of the device is un-owned and Provisioning
445              * Tool is attempting to change the state to 'Owned' with a
446              * qualified value for the field 'Owner'
447              */
448             if ((false == gDoxm->owned) && (true == newDoxm->owned) &&
449                 (memcmp(&(newDoxm->owner), &emptyOwner, sizeof(OicUuid_t)) != 0))
450             {
451                 /*
452                  * Generate OwnerPSK and create credential for Provisioning
453                  * tool with the generated OwnerPSK.
454                  * Update persistent storage and disable anonymous ECDH cipher
455                  *
456                  */
457 #ifdef __WITH_DTLS__
458                 CAResult_t pskRet;
459
460                 OCServerRequest *request = (OCServerRequest *)ehRequest->requestHandle;
461                 uint8_t ownerPSK[OWNER_PSK_LENGTH_128] = {};
462
463                 //Generating OwnerPSK
464                 OC_LOG (INFO, TAG, PCF("Doxm EntityHandle  generating OwnerPSK"));
465                 pskRet = CAGenerateOwnerPSK((CAEndpoint_t *)&request->devAddr,
466                         (uint8_t*) OXM_JUST_WORKS, strlen(OXM_JUST_WORKS),
467                         newDoxm->owner.id, sizeof(newDoxm->owner.id),
468                         gDoxm->deviceID.id, sizeof(gDoxm->deviceID.id),
469                         ownerPSK, OWNER_PSK_LENGTH_128);
470
471                 VERIFY_SUCCESS(TAG, pskRet == CA_STATUS_OK, ERROR);
472
473                 //Generating new credential for provisioning tool
474                 size_t ownLen = 1;
475                 uint32_t outLen = 0;
476
477                 char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(ownerPSK)) + 1] = {};
478                 B64Result b64Ret = b64Encode(ownerPSK, sizeof(ownerPSK), base64Buff,
479                                 sizeof(base64Buff), &outLen);
480                 VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
481
482                 OC_LOG (INFO, TAG, PCF("Doxm EntityHandle  generating Credential"));
483                 OicSecCred_t *cred = GenerateCredential(&newDoxm->owner, SYMMETRIC_PAIR_WISE_KEY,
484                                         NULL, base64Buff, ownLen, &newDoxm->owner);
485                 VERIFY_NON_NULL(TAG, cred, ERROR);
486
487                 //Adding provisioning tool credential to cred Resource.
488                 VERIFY_SUCCESS(TAG, OC_STACK_OK == AddCredential(cred), ERROR);
489
490                 gDoxm->owned = true;
491                 memcpy(&(gDoxm->owner), &(newDoxm->owner), sizeof(OicUuid_t));
492
493                 // Update new state in persistent storage
494                 if (true == UpdatePersistentStorage(gDoxm))
495                 {
496                     ehRet = OC_EH_OK;
497                 }
498                 else
499                 {
500                     ehRet = OC_EH_ERROR;
501
502                     /*
503                      * If persistent storage update failed, revert back the state
504                      * for global variable.
505                      */
506                     gDoxm->owned = false;
507                     memset(&(gDoxm->owner), 0, sizeof(OicUuid_t));
508                 }
509
510                 /*
511                  * Disable anonymous ECDH cipher in tinyDTLS since device is now
512                  * in owned state.
513                  */
514                 CAEnableAnonECDHCipherSuite(false);
515 #endif //__WITH_DTLS__
516             }
517         }
518     }
519
520 exit:
521
522     //Send payload to request originator
523     if(OC_STACK_OK != SendSRMResponse(ehRequest, ehRet, NULL))
524     {
525         OC_LOG (ERROR, TAG, PCF("SendSRMResponse failed in HandlePstatPostRequest"));
526     }
527     DeleteDoxmBinData(newDoxm);
528
529     return ehRet;
530 }
531
532 /*
533  * This internal method is the entity handler for DOXM resources.
534  */
535 OCEntityHandlerResult DoxmEntityHandler (OCEntityHandlerFlag flag,
536                                         OCEntityHandlerRequest * ehRequest,
537                                         void* callbackParam)
538 {
539     OCEntityHandlerResult ehRet = OC_EH_ERROR;
540
541     if(NULL == ehRequest)
542     {
543         return ehRet;
544     }
545
546
547     if (flag & OC_REQUEST_FLAG)
548     {
549         OC_LOG (INFO, TAG, PCF("Flag includes OC_REQUEST_FLAG"));
550         switch (ehRequest->method)
551         {
552             case OC_REST_GET:
553                 ehRet = HandleDoxmGetRequest(ehRequest);
554                 break;
555
556             case OC_REST_PUT:
557                 ehRet = HandleDoxmPutRequest(ehRequest);
558                 break;
559
560             default:
561                 ehRet = OC_EH_ERROR;
562                 SendSRMResponse(ehRequest, ehRet, NULL);
563                 break;
564         }
565     }
566
567     return ehRet;
568 }
569
570 /*
571  * This internal method is used to create '/oic/sec/doxm' resource.
572  */
573 OCStackResult CreateDoxmResource()
574 {
575     OCStackResult ret;
576
577     ret = OCCreateResource(&gDoxmHandle,
578                            OIC_RSRC_TYPE_SEC_DOXM,
579                            OIC_MI_DEF,
580                            OIC_RSRC_DOXM_URI,
581                            DoxmEntityHandler,
582                            NULL,
583                            OC_OBSERVABLE);
584
585     if (OC_STACK_OK != ret)
586     {
587         OC_LOG (FATAL, TAG, PCF("Unable to instantiate Doxm resource"));
588         DeInitDoxmResource();
589     }
590     return ret;
591 }
592
593 /**
594  * Checks if DeviceID is generated during provisioning for the new device.
595  * If DeviceID is NULL then generates the new DeviceID.
596  * Once DeviceID is assigned to the device it does not change for the lifetime of the device.
597  *
598  */
599 void CheckDeviceID()
600 {
601     if(strcmp((char *)gDoxm->deviceID.id, "") == 0 )
602     {
603         OCFillRandomMem(gDoxm->deviceID.id, sizeof(gDoxm->deviceID.id));
604         UpdatePersistentStorage(gDoxm);
605     }
606 }
607
608 /**
609  * Get the default value.
610  * @retval  the gDefaultDoxm pointer;
611  */
612 static OicSecDoxm_t* GetDoxmDefault()
613 {
614     OC_LOG (INFO, TAG, PCF("GetDoxmToDefault"));
615     return &gDefaultDoxm;
616 }
617
618 /**
619  * This method is used by SRM to retrieve DOXM resource data.
620  *
621  * @retval  reference to @ref OicSecDoxm_t, binary format of Doxm resource data
622  */
623 const OicSecDoxm_t* GetDoxmResourceData()
624 {
625     return gDoxm;
626 }
627
628 /**
629  * Initialize DOXM resource by loading data from persistent storage.
630  *
631  * @retval  OC_STACK_OK for Success, otherwise some error value
632  */
633 OCStackResult InitDoxmResource()
634 {
635     OCStackResult ret = OC_STACK_ERROR;
636
637     //Read DOXM resource from PS
638     char* jsonSVRDatabase = GetSVRDatabase();
639     if(jsonSVRDatabase)
640     {
641         //Convert JSON DOXM into binary format
642         gDoxm = JSONToDoxmBin(jsonSVRDatabase);
643     }
644     /*
645      * If SVR database in persistent storage got corrupted or
646      * is not available for some reason, a default doxm is created
647      * which allows user to initiate doxm provisioning again.
648      */
649     if(!jsonSVRDatabase || !gDoxm)
650     {
651         gDoxm = GetDoxmDefault();
652     }
653     CheckDeviceID();
654     //Instantiate 'oic.sec.doxm'
655     ret = CreateDoxmResource();
656     OICFree(jsonSVRDatabase);
657     return ret;
658 }
659
660 /**
661  * Perform cleanup for DOXM resources.
662  *
663  * @return
664  * OC_STACK_OK    - no error
665  * OC_STACK_ERROR - stack process error
666  *
667  */
668 OCStackResult DeInitDoxmResource()
669 {
670     OCStackResult ret = OCDeleteResource(gDoxmHandle);
671     if(gDoxm  != &gDefaultDoxm)
672     {
673         DeleteDoxmBinData(gDoxm);
674     }
675     gDoxm = NULL;
676
677     if(OC_STACK_OK == ret)
678     {
679         return OC_STACK_OK;
680     }
681     else
682     {
683         return OC_STACK_ERROR;
684     }
685 }
686
687
688 /**
689  * This method returns the SRM device ID for this device.
690  *
691  * @retval  OC_STACK_OK for Success, otherwise some error value
692  */
693 OCStackResult GetDoxmDeviceID(OicUuid_t *deviceID)
694 {
695     if(deviceID && gDoxm)
696     {
697        *deviceID = gDoxm->deviceID;
698         return OC_STACK_OK;
699     }
700     return OC_STACK_ERROR;
701 }
702
703 /**
704  * @brief Gets the OicUuid_t value for the owner of this device.
705  *
706  * @return OC_STACK_OK if devOwner is a valid UUID, otherwise OC_STACK_ERROR.
707  */
708 OCStackResult GetDoxmDevOwnerId(OicUuid_t *devOwner)
709 {
710     OCStackResult retVal = OC_STACK_ERROR;
711     if(gDoxm)
712     {
713         if(gDoxm->owned) {
714             *devOwner = gDoxm->owner; // TODO change to devOwner when available
715             retVal = OC_STACK_OK;
716         }
717     }
718     return retVal;
719 }