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