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