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