Modify to update rowner as PT's UUID when ownership transfer is done.
[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 = { {.ptr = NULL }, .end = 0 };
120     CborEncoder doxmMap = { {.ptr = NULL }, .end = 0 };
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 = { {.ptr = NULL }, .end = 0, .added = 0, .flags = 0 };
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 = { {.ptr = NULL }, .end = 0, .added = 0, .flags = 0 };
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)
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     int cborLen = (size == 0) ? CBOR_SIZE : size;
290     char* strUuid = NULL;
291     size_t len = 0;
292     CborValue doxmCbor;
293     cbor_parser_init(cborPayload, cborLen, 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 != SendSRMCBORResponse(ehRequest, ehRet, payload, size))
572     {
573         OIC_LOG(ERROR, TAG, "SendSRMCBORResponse failed in HandleDoxmGetRequest");
574     }
575
576     OICFree(payload);
577
578     return ehRet;
579 }
580
581 static OCEntityHandlerResult HandleDoxmPutRequest(const OCEntityHandlerRequest * ehRequest)
582 {
583     OIC_LOG (DEBUG, TAG, "Doxm EntityHandle  processing PUT request");
584     OCEntityHandlerResult ehRet = OC_EH_ERROR;
585     OicUuid_t emptyOwner = {.id = {0} };
586
587     /*
588      * Convert CBOR Doxm data into binary. This will also validate
589      * the Doxm data received.
590      */
591     OicSecDoxm_t *newDoxm = NULL;
592
593     if (ehRequest->payload)
594     {
595         uint8_t *payload = ((OCSecurityPayload *)ehRequest->payload)->securityData1;
596         size_t size = ((OCSecurityPayload *)ehRequest->payload)->payloadSize;
597         OCStackResult res = CBORPayloadToDoxm(payload, size, &newDoxm);
598
599         if (newDoxm && OC_STACK_OK == res)
600         {
601             if (OIC_JUST_WORKS == newDoxm->oxmSel)
602             {
603                 if ((false == gDoxm->owned) && (false == newDoxm->owned))
604                 {
605                     /*
606                      * If current state of the device is un-owned, enable
607                      * anonymous ECDH cipher in tinyDTLS so that Provisioning
608                      * tool can initiate JUST_WORKS ownership transfer process.
609                      */
610                     if (memcmp(&(newDoxm->owner), &emptyOwner, sizeof(OicUuid_t)) == 0)
611                     {
612                         OIC_LOG (INFO, TAG, "Doxm EntityHandle  enabling AnonECDHCipherSuite");
613 #ifdef __WITH_DTLS__
614                         ehRet = (CAEnableAnonECDHCipherSuite(true) == CA_STATUS_OK) ? OC_EH_OK : OC_EH_ERROR;
615 #endif //__WITH_DTLS__
616                         goto exit;
617                     }
618                     else
619                     {
620 #ifdef __WITH_DTLS__
621                         //Save the owner's UUID to derive owner credential
622                         memcpy(&(gDoxm->owner), &(newDoxm->owner), sizeof(OicUuid_t));
623
624                         // Update new state in persistent storage
625                         if (true == UpdatePersistentStorage(gDoxm))
626                         {
627                             ehRet = OC_EH_OK;
628                         }
629                         else
630                         {
631                             OIC_LOG(ERROR, TAG, "Failed to update DOXM in persistent storage");
632                             ehRet = OC_EH_ERROR;
633                         }
634
635                         /*
636                          * Disable anonymous ECDH cipher in tinyDTLS since device is now
637                          * in owned state.
638                          */
639                         CAResult_t caRes = CA_STATUS_OK;
640                         caRes = CAEnableAnonECDHCipherSuite(false);
641                         VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
642                         OIC_LOG(INFO, TAG, "ECDH_ANON CipherSuite is DISABLED");
643
644 #ifdef __WITH_X509__
645 #define TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 0xC0AE
646                         CASelectCipherSuite(TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8);
647 #endif //__WITH_X509__
648 #endif //__WITH_DTLS__
649                     }
650                 }
651             }
652             else if (OIC_RANDOM_DEVICE_PIN == newDoxm->oxmSel)
653             {
654                 if ((false == gDoxm->owned) && (false == newDoxm->owned))
655                 {
656                     /*
657                      * If current state of the device is un-owned, enable
658                      * anonymous ECDH cipher in tinyDTLS so that Provisioning
659                      * tool can initiate JUST_WORKS ownership transfer process.
660                      */
661                     if(memcmp(&(newDoxm->owner), &emptyOwner, sizeof(OicUuid_t)) == 0)
662                     {
663                         gDoxm->oxmSel = newDoxm->oxmSel;
664                         //Update new state in persistent storage
665                         if ((UpdatePersistentStorage(gDoxm) == true))
666                         {
667                             ehRet = OC_EH_OK;
668                         }
669                         else
670                         {
671                             OIC_LOG(WARNING, TAG, "Failed to update DOXM in persistent storage");
672                             ehRet = OC_EH_ERROR;
673                         }
674
675 #ifdef __WITH_DTLS__
676                         CAResult_t caRes = CA_STATUS_OK;
677
678                         caRes = CAEnableAnonECDHCipherSuite(false);
679                         VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
680                         OIC_LOG(INFO, TAG, "ECDH_ANON CipherSuite is DISABLED");
681
682                         caRes = CASelectCipherSuite(TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256);
683                         VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
684
685                         char ranPin[OXM_RANDOM_PIN_SIZE + 1] = {0,};
686                         if(OC_STACK_OK == GeneratePin(ranPin, OXM_RANDOM_PIN_SIZE + 1))
687                         {
688                             //Set the device id to derive temporal PSK
689                             SetUuidForRandomPinOxm(&gDoxm->deviceID);
690
691                             /**
692                              * Since PSK will be used directly by DTLS layer while PIN based ownership transfer,
693                              * Credential should not be saved into SVR.
694                              * For this reason, use a temporary get_psk_info callback to random PIN OxM.
695                              */
696                             caRes = CARegisterDTLSCredentialsHandler(GetDtlsPskForRandomPinOxm);
697                             VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
698                             ehRet = OC_EH_OK;
699                         }
700                         else
701                         {
702                             OIC_LOG(ERROR, TAG, "Failed to generate random PIN");
703                             ehRet = OC_EH_ERROR;
704                         }
705 #endif //__WITH_DTLS__
706                     }
707                     else
708                     {
709 #ifdef __WITH_DTLS__
710                         //Save the owner's UUID to derive owner credential
711                         memcpy(&(gDoxm->owner), &(newDoxm->owner), sizeof(OicUuid_t));
712
713                         //Update new state in persistent storage
714                         if (UpdatePersistentStorage(gDoxm) == true)
715                         {
716                             ehRet = OC_EH_OK;
717                         }
718                         else
719                         {
720                             OIC_LOG(ERROR, TAG, "Failed to update DOXM in persistent storage");
721                             ehRet = OC_EH_ERROR;
722                         }
723 #endif
724                     }
725                 }
726             }
727
728             /*
729              * When current state of the device is un-owned and Provisioning
730              * Tool is attempting to change the state to 'Owned' with a
731              * qualified value for the field 'Owner'
732              */
733             if ((false == gDoxm->owned) && (true == newDoxm->owned) &&
734                     (memcmp(&(gDoxm->owner), &(newDoxm->owner), sizeof(OicUuid_t)) == 0))
735             {
736                 //Change the SVR's resource owner as owner device.
737                 OCStackResult ownerRes = SetAclRownerId(&gDoxm->owner);
738                 if(OC_STACK_OK != ownerRes && OC_STACK_NO_RESOURCE != ownerRes)
739                 {
740                     ehRet = OC_EH_ERROR;
741                     goto exit;
742                 }
743                 ownerRes = SetAmaclRownerId(&gDoxm->owner);
744                 if(OC_STACK_OK != ownerRes && OC_STACK_NO_RESOURCE != ownerRes)
745                 {
746                     ehRet = OC_EH_ERROR;
747                     goto exit;
748                 }
749                 ownerRes = SetCredRownerId(&gDoxm->owner);
750                 if(OC_STACK_OK != ownerRes && OC_STACK_NO_RESOURCE != ownerRes)
751                 {
752                     ehRet = OC_EH_ERROR;
753                     goto exit;
754                 }
755                 ownerRes = SetPstatRownerId(&gDoxm->owner);
756                 if(OC_STACK_OK != ownerRes && OC_STACK_NO_RESOURCE != ownerRes)
757                 {
758                     ehRet = OC_EH_ERROR;
759                     goto exit;
760                 }
761                 ownerRes = SetDpairingRownerId(&gDoxm->owner);
762                 if(OC_STACK_OK != ownerRes && OC_STACK_NO_RESOURCE != ownerRes)
763                 {
764                     ehRet = OC_EH_ERROR;
765                     goto exit;
766                 }
767                 ownerRes = SetPconfRownerId(&gDoxm->owner);
768                 if(OC_STACK_OK != ownerRes && OC_STACK_NO_RESOURCE != ownerRes)
769                 {
770                     ehRet = OC_EH_ERROR;
771                     goto exit;
772                 }
773
774                 gDoxm->owned = true;
775                 memcpy(&gDoxm->rownerID, &gDoxm->owner, sizeof(OicUuid_t));
776
777                 // Update new state in persistent storage
778                 if (UpdatePersistentStorage(gDoxm))
779                 {
780                     //Update default ACL of security resource to prevent anonymous user access.
781                     if(OC_STACK_OK == UpdateDefaultSecProvACL())
782                     {
783                         ehRet = OC_EH_OK;
784                     }
785                     else
786                     {
787                         OIC_LOG(ERROR, TAG, "Failed to remove default ACL for security provisioning");
788                         ehRet = OC_EH_ERROR;
789                     }
790                 }
791                 else
792                 {
793                     OIC_LOG(ERROR, TAG, "Failed to update DOXM in persistent storage");
794                     ehRet = OC_EH_ERROR;
795                 }
796             }
797         }
798     }
799
800 exit:
801     if(OC_EH_OK != ehRet)
802     {
803         OIC_LOG(WARNING, TAG, "The operation failed during handle DOXM request,"\
804                             "DOXM will be reverted.");
805
806         /*
807          * If some error is occured while ownership transfer,
808          * ownership transfer related resource should be revert back to initial status.
809          */
810         RestoreDoxmToInitState();
811         RestorePstatToInitState();
812     }
813
814     //Send payload to request originator
815     if (OC_STACK_OK != SendSRMCBORResponse(ehRequest, ehRet, NULL, 0))
816     {
817         OIC_LOG(ERROR, TAG, "SendSRMCBORResponse failed in HandleDoxmPostRequest");
818     }
819     DeleteDoxmBinData(newDoxm);
820
821     return ehRet;
822 }
823
824 OCEntityHandlerResult DoxmEntityHandler(OCEntityHandlerFlag flag,
825                                         OCEntityHandlerRequest * ehRequest,
826                                         void* callbackParam)
827 {
828     (void)callbackParam;
829     OCEntityHandlerResult ehRet = OC_EH_ERROR;
830
831     if(NULL == ehRequest)
832     {
833         return ehRet;
834     }
835
836     if (flag & OC_REQUEST_FLAG)
837     {
838         OIC_LOG(DEBUG, TAG, "Flag includes OC_REQUEST_FLAG");
839
840         switch (ehRequest->method)
841         {
842             case OC_REST_GET:
843                 ehRet = HandleDoxmGetRequest(ehRequest);
844                 break;
845
846             case OC_REST_PUT:
847                 ehRet = HandleDoxmPutRequest(ehRequest);
848                 break;
849
850             default:
851                 ehRet = OC_EH_ERROR;
852                 SendSRMCBORResponse(ehRequest, ehRet, NULL, 0);
853                 break;
854         }
855     }
856
857     return ehRet;
858 }
859
860 OCStackResult CreateDoxmResource()
861 {
862     OCStackResult ret = OCCreateResource(&gDoxmHandle,
863                                          OIC_RSRC_TYPE_SEC_DOXM,
864                                          OIC_MI_DEF,
865                                          OIC_RSRC_DOXM_URI,
866                                          DoxmEntityHandler,
867                                          NULL,
868                                          OC_OBSERVABLE | OC_SECURE |
869                                          OC_EXPLICIT_DISCOVERABLE);
870
871     if (OC_STACK_OK != ret)
872     {
873         OIC_LOG (FATAL, TAG, "Unable to instantiate Doxm resource");
874         DeInitDoxmResource();
875     }
876     return ret;
877 }
878
879 /**
880  * Checks if DeviceID is generated during provisioning for the new device.
881  * If DeviceID is NULL then generates the new DeviceID.
882  * Once DeviceID is assigned to the device it does not change for the lifetime of the device.
883  */
884 static OCStackResult CheckDeviceID()
885 {
886     OCStackResult ret = OC_STACK_ERROR;
887     bool validId = false;
888     for (uint8_t i = 0; i < UUID_LENGTH; i++)
889     {
890         if (gDoxm->deviceID.id[i] != 0)
891         {
892             validId = true;
893             break;
894         }
895     }
896
897     if (!validId)
898     {
899         if (OCGenerateUuid(gDoxm->deviceID.id) != RAND_UUID_OK)
900         {
901             OIC_LOG(FATAL, TAG, "Generate UUID for Server Instance failed!");
902             return ret;
903         }
904         ret = OC_STACK_OK;
905
906         if (!UpdatePersistentStorage(gDoxm))
907         {
908             //TODO: After registering PSI handler in all samples, do ret = OC_STACK_OK here.
909             OIC_LOG(FATAL, TAG, "UpdatePersistentStorage failed!");
910         }
911     }
912     else
913     {
914         ret = OC_STACK_OK;
915     }
916     return ret;
917 }
918
919 /**
920  * Get the default value.
921  *
922  * @return the default value of doxm, @ref OicSecDoxm_t.
923  */
924 static OicSecDoxm_t* GetDoxmDefault()
925 {
926     OIC_LOG(DEBUG, TAG, "GetDoxmToDefault");
927     return &gDefaultDoxm;
928 }
929
930 const OicSecDoxm_t* GetDoxmResourceData()
931 {
932     return gDoxm;
933 }
934
935 OCStackResult InitDoxmResource()
936 {
937     OCStackResult ret = OC_STACK_ERROR;
938
939     //Read DOXM resource from PS
940     uint8_t *data = NULL;
941     size_t size = 0;
942     ret = GetSecureVirtualDatabaseFromPS(OIC_JSON_DOXM_NAME, &data, &size);
943     // If database read failed
944     if (OC_STACK_OK != ret)
945     {
946        OIC_LOG (DEBUG, TAG, "ReadSVDataFromPS failed");
947     }
948     if (data)
949     {
950        // Read DOXM resource from PS
951        ret = CBORPayloadToDoxm(data, size, &gDoxm);
952     }
953     /*
954      * If SVR database in persistent storage got corrupted or
955      * is not available for some reason, a default doxm is created
956      * which allows user to initiate doxm provisioning again.
957      */
958      if ((OC_STACK_OK != ret) || !data || !gDoxm)
959     {
960         gDoxm = GetDoxmDefault();
961     }
962
963     //In case of the server is shut down unintentionally, we should initialize the owner
964     if(false == gDoxm->owned)
965     {
966         OicUuid_t emptyUuid = {.id={0}};
967         memcpy(&gDoxm->owner, &emptyUuid, sizeof(OicUuid_t));
968     }
969
970     ret = CheckDeviceID();
971     if (ret == OC_STACK_OK)
972     {
973         OIC_LOG_V(DEBUG, TAG, "Initial Doxm Owned = %d", gDoxm->owned);
974         //Instantiate 'oic.sec.doxm'
975         ret = CreateDoxmResource();
976     }
977     else
978     {
979         OIC_LOG (ERROR, TAG, "CheckDeviceID failed");
980     }
981     OICFree(data);
982     return ret;
983 }
984
985 OCStackResult DeInitDoxmResource()
986 {
987     OCStackResult ret = OCDeleteResource(gDoxmHandle);
988     if (gDoxm  != &gDefaultDoxm)
989     {
990         DeleteDoxmBinData(gDoxm);
991     }
992     gDoxm = NULL;
993
994     if (OC_STACK_OK == ret)
995     {
996         return OC_STACK_OK;
997     }
998     else
999     {
1000         return OC_STACK_ERROR;
1001     }
1002 }
1003
1004 OCStackResult GetDoxmDeviceID(OicUuid_t *deviceID)
1005 {
1006     if (deviceID && gDoxm)
1007     {
1008        *deviceID = gDoxm->deviceID;
1009         return OC_STACK_OK;
1010     }
1011     return OC_STACK_ERROR;
1012 }
1013
1014 OCStackResult GetDoxmDevOwnerId(OicUuid_t *devOwner)
1015 {
1016     OCStackResult retVal = OC_STACK_ERROR;
1017     if (gDoxm)
1018     {
1019         OIC_LOG_V(DEBUG, TAG, "gDoxm owned =  %d.", gDoxm->owned);
1020         if (gDoxm->owned)
1021         {
1022             *devOwner = gDoxm->owner; // TODO change to devOwner when available
1023             retVal = OC_STACK_OK;
1024         }
1025     }
1026     return retVal;
1027 }
1028
1029 /**
1030  * Function to restore doxm resurce to initial status.
1031  * This function will use in case of error while ownership transfer
1032  */
1033 void RestoreDoxmToInitState()
1034 {
1035     if(gDoxm)
1036     {
1037         OIC_LOG(INFO, TAG, "DOXM resource will revert back to initial status.");
1038
1039         OicUuid_t emptyUuid = {.id={0}};
1040         memcpy(&(gDoxm->owner), &emptyUuid, sizeof(OicUuid_t));
1041         gDoxm->owned = false;
1042         gDoxm->oxmSel = OIC_JUST_WORKS;
1043
1044         if(!UpdatePersistentStorage(gDoxm))
1045         {
1046             OIC_LOG(ERROR, TAG, "Failed to revert DOXM in persistent storage");
1047         }
1048     }
1049 }