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