Merge branch 'master' into extended-easysetup
[platform/upstream/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 #include <stdlib.h>
21 #include <string.h>
22
23 #if HAVE_STRINGS_H
24 #include <strings.h>
25 #endif
26
27 #ifdef __WITH_DTLS__
28 #include "global.h"
29 #endif
30
31 #include "ocstack.h"
32 #include "oic_malloc.h"
33 #include "payload_logging.h"
34 #include "utlist.h"
35 #include "ocrandom.h"
36 #include "ocpayload.h"
37 #include "cainterface.h"
38 #include "ocserverrequest.h"
39 #include "resourcemanager.h"
40 #include "doxmresource.h"
41 #include "pstatresource.h"
42 #include "aclresource.h"
43 #include "amaclresource.h"
44 #include "pconfresource.h"
45 #include "dpairingresource.h"
46 #include "psinterface.h"
47 #include "srmresourcestrings.h"
48 #include "securevirtualresourcetypes.h"
49 #include "credresource.h"
50 #include "srmutility.h"
51 #include "pinoxmcommon.h"
52
53 #define TAG  "SRM-DOXM"
54
55 /** Default cbor payload size. This value is increased in case of CborErrorOutOfMemory.
56  * The value of payload size is increased until reaching belox max cbor size. */
57 static const uint16_t CBOR_SIZE = 512;
58
59 /** Max cbor size payload. */
60 static const uint16_t CBOR_MAX_SIZE = 4400;
61
62 /** DOXM Map size - Number of mandatory items. */
63 static const uint8_t DOXM_MAP_SIZE = 9;
64
65 static OicSecDoxm_t        *gDoxm = NULL;
66 static OCResourceHandle    gDoxmHandle = NULL;
67
68 static OicSecOxm_t gOicSecDoxmJustWorks = OIC_JUST_WORKS;
69 static OicSecDoxm_t gDefaultDoxm =
70 {
71     NULL,                   /* OicUrn_t *oxmType */
72     0,                      /* size_t oxmTypeLen */
73     &gOicSecDoxmJustWorks,  /* uint16_t *oxm */
74     1,                      /* size_t oxmLen */
75     OIC_JUST_WORKS,         /* uint16_t oxmSel */
76     SYMMETRIC_PAIR_WISE_KEY,/* OicSecCredType_t sct */
77     false,                  /* bool owned */
78     {.id = {0}},            /* OicUuid_t deviceID */
79     false,                  /* bool dpc */
80     {.id = {0}},            /* OicUuid_t owner */
81     {.id = {0}},            /* OicUuid_t rownerID */
82 };
83
84 void DeleteDoxmBinData(OicSecDoxm_t* doxm)
85 {
86     if (doxm)
87     {
88         //Clean oxmType
89         for (size_t i = 0; i < doxm->oxmTypeLen; i++)
90         {
91             OICFree(doxm->oxmType[i]);
92         }
93         OICFree(doxm->oxmType);
94
95         //clean oxm
96         OICFree(doxm->oxm);
97
98         //Clean doxm itself
99         OICFree(doxm);
100     }
101 }
102
103 OCStackResult DoxmToCBORPayload(const OicSecDoxm_t *doxm, uint8_t **payload, size_t *size)
104 {
105     if (NULL == doxm || NULL == payload || NULL != *payload || NULL == size)
106     {
107         return OC_STACK_INVALID_PARAM;
108     }
109     size_t cborLen = *size;
110     if (0 == cborLen)
111     {
112         cborLen = CBOR_SIZE;
113     }
114     *payload = NULL;
115     *size = 0;
116
117     OCStackResult ret = OC_STACK_ERROR;
118
119     CborEncoder encoder;
120     CborEncoder doxmMap;
121     char* strUuid = NULL;
122
123     int64_t cborEncoderResult = CborNoError;
124     uint8_t mapSize = DOXM_MAP_SIZE;
125     if (doxm->oxmTypeLen > 0)
126     {
127         mapSize++;
128     }
129     if (doxm->oxmLen > 0)
130     {
131         mapSize++;
132     }
133
134     uint8_t *outPayload = (uint8_t *)OICCalloc(1, cborLen);
135     VERIFY_NON_NULL(TAG, outPayload, ERROR);
136     cbor_encoder_init(&encoder, outPayload, cborLen, 0);
137
138     cborEncoderResult = cbor_encoder_create_map(&encoder, &doxmMap, mapSize);
139     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Doxm Map.");
140
141     //OxmType -- Not Mandatory
142     if (doxm->oxmTypeLen > 0)
143     {
144         CborEncoder oxmType;
145         cborEncoderResult = cbor_encode_text_string(&doxmMap, OIC_JSON_OXM_TYPE_NAME,
146             strlen(OIC_JSON_OXM_TYPE_NAME));
147         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding oxmType Tag.");
148         cborEncoderResult = cbor_encoder_create_array(&doxmMap, &oxmType, doxm->oxmTypeLen);
149         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding oxmType Array.");
150
151         for (size_t i = 0; i < doxm->oxmTypeLen; i++)
152         {
153             cborEncoderResult = cbor_encode_text_string(&oxmType, doxm->oxmType[i],
154                 strlen(doxm->oxmType[i]));
155             VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding oxmType Value.");
156         }
157         cborEncoderResult = cbor_encoder_close_container(&doxmMap, &oxmType);
158         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing oxmType.");
159     }
160
161     //Oxm -- Not Mandatory
162     if (doxm->oxmLen > 0)
163     {
164         CborEncoder oxm;
165         cborEncoderResult = cbor_encode_text_string(&doxmMap, OIC_JSON_OXMS_NAME,
166             strlen(OIC_JSON_OXMS_NAME));
167         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding oxmName Tag.");
168         cborEncoderResult = cbor_encoder_create_array(&doxmMap, &oxm, doxm->oxmLen);
169         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding oxmName Array.");
170
171         for (size_t i = 0; i < doxm->oxmLen; i++)
172         {
173             cborEncoderResult = cbor_encode_int(&oxm, doxm->oxm[i]);
174             VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding oxmName Value");
175         }
176         cborEncoderResult = cbor_encoder_close_container(&doxmMap, &oxm);
177         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing oxmName.");
178     }
179
180     //OxmSel -- Mandatory
181     cborEncoderResult = cbor_encode_text_string(&doxmMap, OIC_JSON_OXM_SEL_NAME,
182         strlen(OIC_JSON_OXM_SEL_NAME));
183     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Sel Tag.");
184     cborEncoderResult = cbor_encode_int(&doxmMap, doxm->oxmSel);
185     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Sel Value.");
186
187     //sct -- Mandatory
188     cborEncoderResult = cbor_encode_text_string(&doxmMap, OIC_JSON_SUPPORTED_CRED_TYPE_NAME,
189         strlen(OIC_JSON_SUPPORTED_CRED_TYPE_NAME));
190     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Cred Type Tag");
191     cborEncoderResult = cbor_encode_int(&doxmMap, doxm->sct);
192     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Cred Type Value.");
193
194     //Owned -- Mandatory
195     cborEncoderResult = cbor_encode_text_string(&doxmMap, OIC_JSON_OWNED_NAME,
196         strlen(OIC_JSON_OWNED_NAME));
197     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Owned Tag.");
198     cborEncoderResult = cbor_encode_boolean(&doxmMap, doxm->owned);
199     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Owned Value.");
200
201     //DeviceId -- Mandatory
202     cborEncoderResult = cbor_encode_text_string(&doxmMap, OIC_JSON_DEVICE_ID_NAME,
203         strlen(OIC_JSON_DEVICE_ID_NAME));
204     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Device Id Tag.");
205     ret = ConvertUuidToStr(&doxm->deviceID, &strUuid);
206     VERIFY_SUCCESS(TAG, OC_STACK_OK == ret , ERROR);
207     cborEncoderResult = cbor_encode_text_string(&doxmMap, strUuid, strlen(strUuid));
208     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Device Id Value.");
209     OICFree(strUuid);
210     strUuid = NULL;
211
212     //devownerid -- Mandatory
213     cborEncoderResult = cbor_encode_text_string(&doxmMap, OIC_JSON_DEVOWNERID_NAME,
214         strlen(OIC_JSON_DEVOWNERID_NAME));
215     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Owner Id Tag.");
216     ret = ConvertUuidToStr(&doxm->owner, &strUuid);
217     VERIFY_SUCCESS(TAG, OC_STACK_OK == ret , ERROR);
218     cborEncoderResult = cbor_encode_text_string(&doxmMap, strUuid, strlen(strUuid));
219     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Owner Id Value.");
220     OICFree(strUuid);
221     strUuid = NULL;
222
223     //ROwner -- Mandatory
224     cborEncoderResult = cbor_encode_text_string(&doxmMap, OIC_JSON_ROWNERID_NAME,
225         strlen(OIC_JSON_ROWNERID_NAME));
226     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ROwner Id Tag.");
227     ret = ConvertUuidToStr(&doxm->rownerID, &strUuid);
228     VERIFY_SUCCESS(TAG, OC_STACK_OK == ret , ERROR);
229     cborEncoderResult = cbor_encode_text_string(&doxmMap, strUuid, strlen(strUuid));
230     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ROwner Id Value.");
231     OICFree(strUuid);
232     strUuid = NULL;
233
234     //x.com.samsung.dpc -- not Mandatory(vendor-specific), but this type is boolean, so instance always has a value.
235     cborEncoderResult = cbor_encode_text_string(&doxmMap, OIC_JSON_DPC_NAME,
236         strlen(OIC_JSON_DPC_NAME));
237     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding DPC Tag.");
238     cborEncoderResult = cbor_encode_boolean(&doxmMap, doxm->dpc);
239     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding DPC Value.");
240
241     //RT -- Mandatory
242     CborEncoder rtArray;
243     cborEncoderResult = cbor_encode_text_string(&doxmMap, OIC_JSON_RT_NAME,
244             strlen(OIC_JSON_RT_NAME));
245     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding RT Name Tag.");
246     cborEncoderResult = cbor_encoder_create_array(&doxmMap, &rtArray, 1);
247     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding RT Value.");
248     for (size_t i = 0; i < 1; i++)
249     {
250         cborEncoderResult = cbor_encode_text_string(&rtArray, OIC_RSRC_TYPE_SEC_DOXM,
251                 strlen(OIC_RSRC_TYPE_SEC_DOXM));
252         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding RT Value.");
253     }
254     cborEncoderResult = cbor_encoder_close_container(&doxmMap, &rtArray);
255     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing RT.");
256
257     //IF-- Mandatory
258      CborEncoder ifArray;
259      cborEncoderResult = cbor_encode_text_string(&doxmMap, OIC_JSON_IF_NAME,
260              strlen(OIC_JSON_IF_NAME));
261      VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding IF Name Tag.");
262      cborEncoderResult = cbor_encoder_create_array(&doxmMap, &ifArray, 1);
263      VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding IF Value.");
264     for (size_t i = 0; i < 1; i++)
265     {
266         cborEncoderResult = cbor_encode_text_string(&ifArray, OC_RSRVD_INTERFACE_DEFAULT,
267                 strlen(OC_RSRVD_INTERFACE_DEFAULT));
268         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding IF Value.");
269     }
270     cborEncoderResult = cbor_encoder_close_container(&doxmMap, &ifArray);
271     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing IF.");
272
273     cborEncoderResult = cbor_encoder_close_container(&encoder, &doxmMap);
274     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing DoxmMap.");
275
276     if (CborNoError == cborEncoderResult)
277     {
278         *size = encoder.ptr - outPayload;
279         *payload = outPayload;
280         ret = OC_STACK_OK;
281     }
282 exit:
283     if ((CborErrorOutOfMemory == cborEncoderResult) && (cborLen < CBOR_MAX_SIZE))
284     {
285         OIC_LOG(DEBUG, TAG, "Memory getting reallocated.");
286         // reallocate and try again!
287         OICFree(outPayload);
288         // Since the allocated initial memory failed, double the memory.
289         cborLen += encoder.ptr - encoder.end;
290         OIC_LOG_V(DEBUG, TAG, "Doxm reallocation size : %zd.", cborLen);
291         cborEncoderResult = CborNoError;
292         ret = DoxmToCBORPayload(doxm, payload, &cborLen);
293         *size = cborLen;
294     }
295
296     if ((CborNoError != cborEncoderResult) || (OC_STACK_OK != ret))
297     {
298        OICFree(outPayload);
299        outPayload = NULL;
300        *payload = NULL;
301        *size = 0;
302        ret = OC_STACK_ERROR;
303     }
304
305     return ret;
306 }
307
308 OCStackResult CBORPayloadToDoxm(const uint8_t *cborPayload, size_t size,
309                                 OicSecDoxm_t **secDoxm)
310 {
311     if (NULL == cborPayload || NULL == secDoxm || NULL != *secDoxm || 0 == size)
312     {
313         return OC_STACK_INVALID_PARAM;
314     }
315
316     OCStackResult ret = OC_STACK_ERROR;
317     *secDoxm = NULL;
318
319     CborParser parser;
320     CborError cborFindResult = CborNoError;
321     char* strUuid = NULL;
322     size_t len = 0;
323     CborValue doxmCbor;
324
325     cbor_parser_init(cborPayload, size, 0, &parser, &doxmCbor);
326     CborValue doxmMap;
327     OicSecDoxm_t *doxm = (OicSecDoxm_t *)OICCalloc(1, sizeof(*doxm));
328     VERIFY_NON_NULL(TAG, doxm, ERROR);
329
330     cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_OXM_TYPE_NAME, &doxmMap);
331     //OxmType -- not Mandatory
332     if (CborNoError == cborFindResult && cbor_value_is_array(&doxmMap))
333     {
334         CborValue oxmType;
335
336         cborFindResult = cbor_value_get_array_length(&doxmMap, &doxm->oxmTypeLen);
337         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding oxmTypeLen.")
338         VERIFY_SUCCESS(TAG, doxm->oxmTypeLen != 0, ERROR);
339
340         doxm->oxmType = (OicUrn_t *)OICCalloc(doxm->oxmTypeLen, sizeof(*doxm->oxmType));
341         VERIFY_NON_NULL(TAG, doxm->oxmType, ERROR);
342
343         cborFindResult = cbor_value_enter_container(&doxmMap, &oxmType);
344         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Entering oxmType Array.")
345
346         int i = 0;
347         size_t len = 0;
348         while (cbor_value_is_valid(&oxmType) && cbor_value_is_text_string(&oxmType))
349         {
350             cborFindResult = cbor_value_dup_text_string(&oxmType, &doxm->oxmType[i++],
351                                                         &len, NULL);
352             VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding omxType text string.")
353             cborFindResult = cbor_value_advance(&oxmType);
354             VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Advancing oxmType.")
355         }
356     }
357
358     cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_OXMS_NAME, &doxmMap);
359     //Oxm -- not Mandatory
360     if (CborNoError == cborFindResult && cbor_value_is_array(&doxmMap))
361     {
362         CborValue oxm;
363         cborFindResult = cbor_value_get_array_length(&doxmMap, &doxm->oxmLen);
364         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding oxmName array Length.")
365         VERIFY_SUCCESS(TAG, doxm->oxmLen != 0, ERROR);
366
367         doxm->oxm = (OicSecOxm_t *)OICCalloc(doxm->oxmLen, sizeof(*doxm->oxm));
368         VERIFY_NON_NULL(TAG, doxm->oxm, ERROR);
369
370         cborFindResult = cbor_value_enter_container(&doxmMap, &oxm);
371         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Entering oxmName Array.")
372
373         int i = 0;
374         while (cbor_value_is_valid(&oxm) && cbor_value_is_integer(&oxm))
375         {
376             cborFindResult = cbor_value_get_int(&oxm, (int *) &doxm->oxm[i++]);
377             VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding oxmName Value")
378             cborFindResult = cbor_value_advance(&oxm);
379             VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Advancing oxmName.")
380         }
381     }
382
383     cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_OXM_SEL_NAME, &doxmMap);
384     if (CborNoError == cborFindResult && cbor_value_is_integer(&doxmMap))
385     {
386         cborFindResult = cbor_value_get_int(&doxmMap, (int *) &doxm->oxmSel);
387         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding Sel Name Value.")
388     }
389     else // PUT/POST JSON may not have oxmsel so set it to the gDoxm->oxmSel
390     {
391         VERIFY_NON_NULL(TAG, gDoxm, ERROR);
392         doxm->oxmSel = gDoxm->oxmSel;
393     }
394
395     cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_SUPPORTED_CRED_TYPE_NAME, &doxmMap);
396     if (CborNoError == cborFindResult && cbor_value_is_integer(&doxmMap))
397     {
398         cborFindResult = cbor_value_get_int(&doxmMap, (int *) &doxm->sct);
399         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding Sct Name Value.")
400     }
401     else // PUT/POST JSON may not have sct so set it to the gDoxm->sct
402     {
403         VERIFY_NON_NULL(TAG, gDoxm, ERROR);
404         doxm->sct = gDoxm->sct;
405     }
406
407     cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_OWNED_NAME, &doxmMap);
408     if (CborNoError == cborFindResult && cbor_value_is_boolean(&doxmMap))
409     {
410         cborFindResult = cbor_value_get_boolean(&doxmMap, &doxm->owned);
411         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding Owned Value.")
412     }
413     else // PUT/POST JSON may not have owned so set it to the gDomx->owned
414     {
415         VERIFY_NON_NULL(TAG, gDoxm, ERROR);
416         doxm->owned = gDoxm->owned;
417     }
418
419     cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_DPC_NAME, &doxmMap);
420     if (CborNoError == cborFindResult && cbor_value_is_boolean(&doxmMap))
421     {
422         cborFindResult = cbor_value_get_boolean(&doxmMap, &doxm->dpc);
423         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding DPC Value.")
424     }
425     else // PUT/POST JSON may not have dpc so set it to the gDomx->dpc
426     {
427         VERIFY_NON_NULL(TAG, gDoxm, ERROR);
428         doxm->dpc = gDoxm->dpc;
429     }
430
431     cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_DEVICE_ID_NAME, &doxmMap);
432     if (CborNoError == cborFindResult && cbor_value_is_text_string(&doxmMap))
433     {
434         cborFindResult = cbor_value_dup_text_string(&doxmMap, &strUuid , &len, NULL);
435         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding Device Id Value.");
436         ret = ConvertStrToUuid(strUuid , &doxm->deviceID);
437         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
438         OICFree(strUuid);
439         strUuid  = NULL;
440     }
441
442     cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_DEVOWNERID_NAME, &doxmMap);
443     if (CborNoError == cborFindResult && cbor_value_is_text_string(&doxmMap))
444     {
445         cborFindResult = cbor_value_dup_text_string(&doxmMap, &strUuid , &len, NULL);
446         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding Owner Value.");
447         ret = ConvertStrToUuid(strUuid , &doxm->owner);
448         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
449         OICFree(strUuid);
450         strUuid  = NULL;
451     }
452
453     cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_ROWNERID_NAME, &doxmMap);
454     if (CborNoError == cborFindResult && cbor_value_is_text_string(&doxmMap))
455     {
456         cborFindResult = cbor_value_dup_text_string(&doxmMap, &strUuid , &len, NULL);
457         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding ROwner Value.");
458         ret = ConvertStrToUuid(strUuid , &doxm->rownerID);
459         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
460         OICFree(strUuid);
461         strUuid  = NULL;
462     }
463
464     *secDoxm = doxm;
465     ret = OC_STACK_OK;
466
467 exit:
468     if (CborNoError != cborFindResult)
469     {
470         OIC_LOG (ERROR, TAG, "CBORPayloadToDoxm failed!!!");
471         DeleteDoxmBinData(doxm);
472         doxm = NULL;
473         *secDoxm = NULL;
474         ret = OC_STACK_ERROR;
475     }
476     return ret;
477 }
478
479 /**
480  * @todo document this function including why code might need to call this.
481  * The current suspicion is that it's not being called as much as it should.
482  */
483 static bool UpdatePersistentStorage(OicSecDoxm_t * doxm)
484 {
485     bool bRet = false;
486
487     if (NULL != doxm)
488     {
489         // Convert Doxm data into CBOR for update to persistent storage
490         uint8_t *payload = NULL;
491         size_t size = 0;
492         OCStackResult res = DoxmToCBORPayload(doxm, &payload, &size);
493         if (payload && (OC_STACK_OK == res)
494             && (OC_STACK_OK == UpdateSecureResourceInPS(OIC_JSON_DOXM_NAME, payload, size)))
495         {
496                 bRet = true;
497         }
498         OICFree(payload);
499     }
500     else
501     {
502         if (OC_STACK_OK == UpdateSecureResourceInPS(OIC_JSON_DOXM_NAME, NULL, 0))
503         {
504                 bRet = true;
505         }
506     }
507
508     return bRet;
509 }
510
511 static bool ValidateQuery(const char * query)
512 {
513     // Send doxm resource data if the state of doxm resource
514     // matches with the query parameters.
515     // else send doxm resource data as NULL
516     // TODO Remove this check and rely on Policy Engine
517     // and Provisioning Mode to enforce provisioning-state
518     // access rules. Eventually, the PE and PM code will
519     // not send a request to the /doxm Entity Handler at all
520     // if it should not respond.
521     OIC_LOG (DEBUG, TAG, "In ValidateQuery");
522     if(NULL == gDoxm)
523     {
524         return false;
525     }
526
527     bool bOwnedQry = false;         // does querystring contains 'owned' query ?
528     bool bOwnedMatch = false;       // does 'owned' query value matches with doxm.owned status?
529     bool bDeviceIDQry = false;      // does querystring contains 'deviceid' query ?
530     bool bDeviceIDMatch = false;    // does 'deviceid' query matches with doxm.deviceid ?
531     bool bInterfaceQry = false;      // does querystring contains 'if' query ?
532     bool bInterfaceMatch = false;    // does 'if' query matches with oic.if.baseline ?
533
534     OicParseQueryIter_t parseIter = {.attrPos = NULL};
535
536     ParseQueryIterInit((unsigned char*)query, &parseIter);
537
538     while (GetNextQuery(&parseIter))
539     {
540         if (strncasecmp((char *)parseIter.attrPos, OIC_JSON_OWNED_NAME, parseIter.attrLen) == 0)
541         {
542             bOwnedQry = true;
543             if ((strncasecmp((char *)parseIter.valPos, OIC_SEC_TRUE, parseIter.valLen) == 0) &&
544                     (gDoxm->owned))
545             {
546                 bOwnedMatch = true;
547             }
548             else if ((strncasecmp((char *)parseIter.valPos, OIC_SEC_FALSE, parseIter.valLen) == 0)
549                     && (!gDoxm->owned))
550             {
551                 bOwnedMatch = true;
552             }
553         }
554
555         if (strncasecmp((char *)parseIter.attrPos, OIC_JSON_DEVICE_ID_NAME, parseIter.attrLen) == 0)
556         {
557             bDeviceIDQry = true;
558             OicUuid_t subject = {.id={0}};
559
560             memcpy(subject.id, parseIter.valPos, parseIter.valLen);
561             if (0 == memcmp(&gDoxm->deviceID.id, &subject.id, sizeof(gDoxm->deviceID.id)))
562             {
563                 bDeviceIDMatch = true;
564             }
565         }
566
567         if (strncasecmp((char *)parseIter.attrPos, OC_RSRVD_INTERFACE, parseIter.attrLen) == 0)
568         {
569             bInterfaceQry = true;
570             if ((strncasecmp((char *)parseIter.valPos, OC_RSRVD_INTERFACE_DEFAULT, parseIter.valLen) == 0))
571             {
572                 bInterfaceMatch = true;
573             }
574             return (bInterfaceQry ? bInterfaceMatch: true);
575         }
576     }
577
578     return ((bOwnedQry ? bOwnedMatch : true) && (bDeviceIDQry ? bDeviceIDMatch : true));
579 }
580
581 static OCEntityHandlerResult HandleDoxmGetRequest (const OCEntityHandlerRequest * ehRequest)
582 {
583     OCEntityHandlerResult ehRet = OC_EH_OK;
584
585     OIC_LOG(DEBUG, TAG, "Doxm EntityHandle processing GET request");
586
587     //Checking if Get request is a query.
588     if (ehRequest->query)
589     {
590         OIC_LOG_V(DEBUG,TAG,"query:%s",ehRequest->query);
591         OIC_LOG(DEBUG, TAG, "HandleDoxmGetRequest processing query");
592         if (!ValidateQuery(ehRequest->query))
593         {
594             ehRet = OC_EH_ERROR;
595         }
596     }
597
598     /*
599      * For GET or Valid Query request return doxm resource CBOR payload.
600      * For non-valid query return NULL json payload.
601      * A device will 'always' have a default Doxm, so DoxmToCBORPayload will
602      * return valid doxm resource json.
603      */
604     uint8_t *payload = NULL;
605     size_t size = 0;
606
607     if (ehRet == OC_EH_OK)
608     {
609         if (OC_STACK_OK != DoxmToCBORPayload(gDoxm, &payload, &size))
610         {
611             OIC_LOG(WARNING, TAG, "DoxmToCBORPayload failed in HandleDoxmGetRequest");
612         }
613     }
614
615     OIC_LOG(DEBUG, TAG, "Send payload for doxm GET request");
616     OIC_LOG_BUFFER(DEBUG, TAG, payload, size);
617
618     // Send response payload to request originator
619     ehRet = ((SendSRMResponse(ehRequest, ehRet, payload, size)) == OC_STACK_OK) ?
620                    OC_EH_OK : OC_EH_ERROR;
621
622     OICFree(payload);
623
624     return ehRet;
625 }
626
627 static OCEntityHandlerResult HandleDoxmPostRequest(const OCEntityHandlerRequest * ehRequest)
628 {
629     OIC_LOG (DEBUG, TAG, "Doxm EntityHandle  processing POST request");
630     OCEntityHandlerResult ehRet = OC_EH_ERROR;
631     OicUuid_t emptyOwner = {.id = {0} };
632     static uint16_t previousMsgId = 0;
633
634     /*
635      * Convert CBOR Doxm data into binary. This will also validate
636      * the Doxm data received.
637      */
638     OicSecDoxm_t *newDoxm = NULL;
639
640     if (ehRequest->payload)
641     {
642         uint8_t *payload = ((OCSecurityPayload *)ehRequest->payload)->securityData;
643         size_t size = ((OCSecurityPayload *)ehRequest->payload)->payloadSize;
644         OCStackResult res = CBORPayloadToDoxm(payload, size, &newDoxm);
645
646         if (newDoxm && OC_STACK_OK == res)
647         {
648             if (OIC_JUST_WORKS == newDoxm->oxmSel)
649             {
650                 if ((false == gDoxm->owned) && (false == newDoxm->owned))
651                 {
652                     /*
653                      * If current state of the device is un-owned, enable
654                      * anonymous ECDH cipher in tinyDTLS so that Provisioning
655                      * tool can initiate JUST_WORKS ownership transfer process.
656                      */
657                     if (memcmp(&(newDoxm->owner), &emptyOwner, sizeof(OicUuid_t)) == 0)
658                     {
659                         OIC_LOG (INFO, TAG, "Doxm EntityHandle  enabling AnonECDHCipherSuite");
660 #ifdef __WITH_DTLS__
661                         ehRet = (CAEnableAnonECDHCipherSuite(true) == CA_STATUS_OK) ? OC_EH_OK : OC_EH_ERROR;
662 #endif //__WITH_DTLS__
663                         goto exit;
664                     }
665                     else
666                     {
667 #ifdef __WITH_DTLS__
668                         //Save the owner's UUID to derive owner credential
669                         memcpy(&(gDoxm->owner), &(newDoxm->owner), sizeof(OicUuid_t));
670
671                         // Update new state in persistent storage
672                         if (true == UpdatePersistentStorage(gDoxm))
673                         {
674                             ehRet = OC_EH_OK;
675                         }
676                         else
677                         {
678                             OIC_LOG(ERROR, TAG, "Failed to update DOXM in persistent storage");
679                             ehRet = OC_EH_ERROR;
680                         }
681
682                         /*
683                          * Disable anonymous ECDH cipher in tinyDTLS since device is now
684                          * in owned state.
685                          */
686                         CAResult_t caRes = CA_STATUS_OK;
687                         caRes = CAEnableAnonECDHCipherSuite(false);
688                         VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
689                         OIC_LOG(INFO, TAG, "ECDH_ANON CipherSuite is DISABLED");
690
691 #ifdef __WITH_X509__
692 #define TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 0xC0AE
693                         CASelectCipherSuite(TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8);
694 #endif //__WITH_X509__
695 #endif //__WITH_DTLS__
696                     }
697                 }
698             }
699             else if (OIC_RANDOM_DEVICE_PIN == newDoxm->oxmSel)
700             {
701                 if ((false == gDoxm->owned) && (false == newDoxm->owned))
702                 {
703                     /*
704                      * If current state of the device is un-owned, enable
705                      * anonymous ECDH cipher in tinyDTLS so that Provisioning
706                      * tool can initiate JUST_WORKS ownership transfer process.
707                      */
708                     if(memcmp(&(newDoxm->owner), &emptyOwner, sizeof(OicUuid_t)) == 0)
709                     {
710                         gDoxm->oxmSel = newDoxm->oxmSel;
711                         //Update new state in persistent storage
712                         if ((UpdatePersistentStorage(gDoxm) == true))
713                         {
714                             ehRet = OC_EH_OK;
715                         }
716                         else
717                         {
718                             OIC_LOG(WARNING, TAG, "Failed to update DOXM in persistent storage");
719                             ehRet = OC_EH_ERROR;
720                         }
721
722 #ifdef __WITH_DTLS__
723                         CAResult_t caRes = CA_STATUS_OK;
724
725                         caRes = CAEnableAnonECDHCipherSuite(false);
726                         VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
727                         OIC_LOG(INFO, TAG, "ECDH_ANON CipherSuite is DISABLED");
728
729                         caRes = CASelectCipherSuite(TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256);
730                         VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
731
732                         if(previousMsgId != ehRequest->messageID)
733                         {
734                             char ranPin[OXM_RANDOM_PIN_SIZE + 1] = {0,};
735                             if(OC_STACK_OK == GeneratePin(ranPin, OXM_RANDOM_PIN_SIZE + 1))
736                             {
737                                 //Set the device id to derive temporal PSK
738                                 SetUuidForRandomPinOxm(&gDoxm->deviceID);
739
740                                 /**
741                                  * Since PSK will be used directly by DTLS layer while PIN based ownership transfer,
742                                  * Credential should not be saved into SVR.
743                                  * For this reason, use a temporary get_psk_info callback to random PIN OxM.
744                                  */
745                                 caRes = CARegisterDTLSCredentialsHandler(GetDtlsPskForRandomPinOxm);
746                                 VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
747                                 ehRet = OC_EH_OK;
748                             }
749                             else
750                             {
751                                 OIC_LOG(ERROR, TAG, "Failed to generate random PIN");
752                                 ehRet = OC_EH_ERROR;
753                             }
754                         }
755 #endif //__WITH_DTLS__
756                     }
757                     else
758                     {
759 #ifdef __WITH_DTLS__
760                         //Save the owner's UUID to derive owner credential
761                         memcpy(&(gDoxm->owner), &(newDoxm->owner), sizeof(OicUuid_t));
762
763                         //Update new state in persistent storage
764                         if (UpdatePersistentStorage(gDoxm) == true)
765                         {
766                             ehRet = OC_EH_OK;
767                         }
768                         else
769                         {
770                             OIC_LOG(ERROR, TAG, "Failed to update DOXM in persistent storage");
771                             ehRet = OC_EH_ERROR;
772                         }
773 #endif
774                     }
775                 }
776             }
777
778             /*
779              * When current state of the device is un-owned and Provisioning
780              * Tool is attempting to change the state to 'Owned' with a
781              * qualified value for the field 'Owner'
782              */
783             if ((false == gDoxm->owned) && (true == newDoxm->owned) &&
784                     (memcmp(&(gDoxm->owner), &(newDoxm->owner), sizeof(OicUuid_t)) == 0))
785             {
786                 //Change the SVR's resource owner as owner device.
787                 OCStackResult ownerRes = SetAclRownerId(&gDoxm->owner);
788                 if(OC_STACK_OK != ownerRes && OC_STACK_NO_RESOURCE != ownerRes)
789                 {
790                     ehRet = OC_EH_ERROR;
791                     goto exit;
792                 }
793                 ownerRes = SetAmaclRownerId(&gDoxm->owner);
794                 if(OC_STACK_OK != ownerRes && OC_STACK_NO_RESOURCE != ownerRes)
795                 {
796                     ehRet = OC_EH_ERROR;
797                     goto exit;
798                 }
799                 ownerRes = SetCredRownerId(&gDoxm->owner);
800                 if(OC_STACK_OK != ownerRes && OC_STACK_NO_RESOURCE != ownerRes)
801                 {
802                     ehRet = OC_EH_ERROR;
803                     goto exit;
804                 }
805                 ownerRes = SetPstatRownerId(&gDoxm->owner);
806                 if(OC_STACK_OK != ownerRes && OC_STACK_NO_RESOURCE != ownerRes)
807                 {
808                     ehRet = OC_EH_ERROR;
809                     goto exit;
810                 }
811                 ownerRes = SetDpairingRownerId(&gDoxm->owner);
812                 if(OC_STACK_OK != ownerRes && OC_STACK_NO_RESOURCE != ownerRes)
813                 {
814                     ehRet = OC_EH_ERROR;
815                     goto exit;
816                 }
817                 ownerRes = SetPconfRownerId(&gDoxm->owner);
818                 if(OC_STACK_OK != ownerRes && OC_STACK_NO_RESOURCE != ownerRes)
819                 {
820                     ehRet = OC_EH_ERROR;
821                     goto exit;
822                 }
823
824                 gDoxm->owned = true;
825                 memcpy(&gDoxm->rownerID, &gDoxm->owner, sizeof(OicUuid_t));
826
827                 // Update new state in persistent storage
828                 if (UpdatePersistentStorage(gDoxm))
829                 {
830                     //Update default ACE of security resource to prevent anonymous user access.
831                     if(OC_STACK_OK == UpdateDefaultSecProvACE())
832                     {
833                         ehRet = OC_EH_OK;
834                     }
835                     else
836                     {
837                         OIC_LOG(ERROR, TAG, "Failed to remove default ACL for security provisioning");
838                         ehRet = OC_EH_ERROR;
839                     }
840                 }
841                 else
842                 {
843                     OIC_LOG(ERROR, TAG, "Failed to update DOXM in persistent storage");
844                     ehRet = OC_EH_ERROR;
845                 }
846             }
847         }
848     }
849
850 exit:
851     if(OC_EH_OK != ehRet)
852     {
853
854         /*
855          * If some error is occured while ownership transfer,
856          * ownership transfer related resource should be revert back to initial status.
857         */
858         if(gDoxm)
859         {
860             if(!gDoxm->owned && previousMsgId != ehRequest->messageID)
861             {
862                 RestoreDoxmToInitState();
863                 RestorePstatToInitState();
864             }
865         }
866         else
867         {
868             OIC_LOG(ERROR, TAG, "Invalid DOXM resource.");
869         }
870     }
871     else
872     {
873         previousMsgId = ehRequest->messageID;
874     }
875
876     //Send payload to request originator
877     ehRet = ((SendSRMResponse(ehRequest, ehRet, NULL, 0)) == OC_STACK_OK) ?
878                    OC_EH_OK : OC_EH_ERROR;
879
880     DeleteDoxmBinData(newDoxm);
881
882     return ehRet;
883 }
884
885 OCEntityHandlerResult DoxmEntityHandler(OCEntityHandlerFlag flag,
886                                         OCEntityHandlerRequest * ehRequest,
887                                         void* callbackParam)
888 {
889     (void)callbackParam;
890     OCEntityHandlerResult ehRet = OC_EH_ERROR;
891
892     if(NULL == ehRequest)
893     {
894         return ehRet;
895     }
896
897     if (flag & OC_REQUEST_FLAG)
898     {
899         OIC_LOG(DEBUG, TAG, "Flag includes OC_REQUEST_FLAG");
900
901         switch (ehRequest->method)
902         {
903             case OC_REST_GET:
904                 ehRet = HandleDoxmGetRequest(ehRequest);
905                 break;
906
907             case OC_REST_POST:
908                 ehRet = HandleDoxmPostRequest(ehRequest);
909                 break;
910
911             default:
912                 ehRet = ((SendSRMResponse(ehRequest, ehRet, NULL, 0)) == OC_STACK_OK) ?
913                                OC_EH_OK : OC_EH_ERROR;
914                 break;
915         }
916     }
917
918     return ehRet;
919 }
920
921 OCStackResult CreateDoxmResource()
922 {
923     OCStackResult ret = OCCreateResource(&gDoxmHandle,
924                                          OIC_RSRC_TYPE_SEC_DOXM,
925                                          OC_RSRVD_INTERFACE_DEFAULT,
926                                          OIC_RSRC_DOXM_URI,
927                                          DoxmEntityHandler,
928                                          NULL,
929                                          OC_SECURE |
930                                          OC_DISCOVERABLE);
931
932     if (OC_STACK_OK != ret)
933     {
934         OIC_LOG (FATAL, TAG, "Unable to instantiate Doxm resource");
935         DeInitDoxmResource();
936     }
937     return ret;
938 }
939
940 /**
941  * Checks if DeviceID is generated during provisioning for the new device.
942  * If DeviceID is NULL then generates the new DeviceID.
943  * Once DeviceID is assigned to the device it does not change for the lifetime of the device.
944  */
945 static OCStackResult CheckDeviceID()
946 {
947     OCStackResult ret = OC_STACK_ERROR;
948     bool validId = false;
949     for (uint8_t i = 0; i < UUID_LENGTH; i++)
950     {
951         if (gDoxm->deviceID.id[i] != 0)
952         {
953             validId = true;
954             break;
955         }
956     }
957
958     if (!validId)
959     {
960         if (OCGenerateUuid(gDoxm->deviceID.id) != RAND_UUID_OK)
961         {
962             OIC_LOG(FATAL, TAG, "Generate UUID for Server Instance failed!");
963             return ret;
964         }
965         ret = OC_STACK_OK;
966
967         if (!UpdatePersistentStorage(gDoxm))
968         {
969             //TODO: After registering PSI handler in all samples, do ret = OC_STACK_OK here.
970             OIC_LOG(FATAL, TAG, "UpdatePersistentStorage failed!");
971         }
972     }
973     else
974     {
975         ret = OC_STACK_OK;
976     }
977     return ret;
978 }
979
980 /**
981  * Get the default value.
982  *
983  * @return the default value of doxm, @ref OicSecDoxm_t.
984  */
985 static OicSecDoxm_t* GetDoxmDefault()
986 {
987     OIC_LOG(DEBUG, TAG, "GetDoxmToDefault");
988     return &gDefaultDoxm;
989 }
990
991 const OicSecDoxm_t* GetDoxmResourceData()
992 {
993     return gDoxm;
994 }
995
996 OCStackResult InitDoxmResource()
997 {
998     OCStackResult ret = OC_STACK_ERROR;
999
1000     //Read DOXM resource from PS
1001     uint8_t *data = NULL;
1002     size_t size = 0;
1003     ret = GetSecureVirtualDatabaseFromPS(OIC_JSON_DOXM_NAME, &data, &size);
1004     // If database read failed
1005     if (OC_STACK_OK != ret)
1006     {
1007        OIC_LOG (DEBUG, TAG, "ReadSVDataFromPS failed");
1008     }
1009     if (data)
1010     {
1011        // Read DOXM resource from PS
1012        ret = CBORPayloadToDoxm(data, size, &gDoxm);
1013     }
1014     /*
1015      * If SVR database in persistent storage got corrupted or
1016      * is not available for some reason, a default doxm is created
1017      * which allows user to initiate doxm provisioning again.
1018      */
1019      if ((OC_STACK_OK != ret) || !data || !gDoxm)
1020     {
1021         gDoxm = GetDoxmDefault();
1022     }
1023
1024     //In case of the server is shut down unintentionally, we should initialize the owner
1025     if(false == gDoxm->owned)
1026     {
1027         OicUuid_t emptyUuid = {.id={0}};
1028         memcpy(&gDoxm->owner, &emptyUuid, sizeof(OicUuid_t));
1029     }
1030
1031     ret = CheckDeviceID();
1032     if (ret == OC_STACK_OK)
1033     {
1034         OIC_LOG_V(DEBUG, TAG, "Initial Doxm Owned = %d", gDoxm->owned);
1035         //Instantiate 'oic.sec.doxm'
1036         ret = CreateDoxmResource();
1037     }
1038     else
1039     {
1040         OIC_LOG (ERROR, TAG, "CheckDeviceID failed");
1041     }
1042     OICFree(data);
1043     return ret;
1044 }
1045
1046 OCStackResult DeInitDoxmResource()
1047 {
1048     OCStackResult ret = OCDeleteResource(gDoxmHandle);
1049     if (gDoxm  != &gDefaultDoxm)
1050     {
1051         DeleteDoxmBinData(gDoxm);
1052     }
1053     gDoxm = NULL;
1054
1055     if (OC_STACK_OK == ret)
1056     {
1057         return OC_STACK_OK;
1058     }
1059     else
1060     {
1061         return OC_STACK_ERROR;
1062     }
1063 }
1064
1065 OCStackResult GetDoxmDeviceID(OicUuid_t *deviceID)
1066 {
1067     if (deviceID && gDoxm)
1068     {
1069        *deviceID = gDoxm->deviceID;
1070         return OC_STACK_OK;
1071     }
1072     return OC_STACK_ERROR;
1073 }
1074
1075 OCStackResult GetDoxmDevOwnerId(OicUuid_t *devownerid)
1076 {
1077     OCStackResult retVal = OC_STACK_ERROR;
1078     if (gDoxm)
1079     {
1080         OIC_LOG_V(DEBUG, TAG, "GetDoxmDevOwnerId(): gDoxm owned =  %d.", \
1081             gDoxm->owned);
1082         if (gDoxm->owned)
1083         {
1084             *devownerid = gDoxm->owner;
1085             retVal = OC_STACK_OK;
1086         }
1087     }
1088     return retVal;
1089 }
1090
1091 OCStackResult GetDoxmRownerId(OicUuid_t *rowneruuid)
1092 {
1093     OCStackResult retVal = OC_STACK_ERROR;
1094     if (gDoxm)
1095     {
1096         if( gDoxm->owned )
1097         {
1098             *rowneruuid = gDoxm->rownerID;
1099                     retVal = OC_STACK_OK;
1100         }
1101     }
1102     return retVal;
1103 }
1104
1105 /**
1106  * Function to restore doxm resurce to initial status.
1107  * This function will use in case of error while ownership transfer
1108  */
1109 void RestoreDoxmToInitState()
1110 {
1111     if(gDoxm)
1112     {
1113         OIC_LOG(INFO, TAG, "DOXM resource will revert back to initial status.");
1114
1115         OicUuid_t emptyUuid = {.id={0}};
1116         memcpy(&(gDoxm->owner), &emptyUuid, sizeof(OicUuid_t));
1117         gDoxm->owned = false;
1118         gDoxm->oxmSel = OIC_JUST_WORKS;
1119
1120         if(!UpdatePersistentStorage(gDoxm))
1121         {
1122             OIC_LOG(ERROR, TAG, "Failed to revert DOXM in persistent storage");
1123         }
1124     }
1125 }