805c5e7085f9a7820e5562c27cc21adf7f689e28
[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 "iotivity_config.h"
21 #include "iotivity_debug.h"
22 #include <stdlib.h>
23 #include <string.h>
24
25 #ifdef HAVE_STRINGS_H
26 #include <strings.h>
27 #endif
28
29 #include "ocstack.h"
30 #include "oic_malloc.h"
31 #include "payload_logging.h"
32 #include "utlist.h"
33 #include "ocrandom.h"
34 #include "ocpayload.h"
35 #include "ocpayloadcbor.h"
36 #include "cainterface.h"
37 #include "ocserverrequest.h"
38 #include "resourcemanager.h"
39 #include "doxmresource.h"
40 #include "pstatresource.h"
41 #include "aclresource.h"
42 #include "amaclresource.h"
43 #include "pconfresource.h"
44 #include "dpairingresource.h"
45 #include "psinterface.h"
46 #include "srmresourcestrings.h"
47 #include "securevirtualresourcetypes.h"
48 #include "credresource.h"
49 #include "srmutility.h"
50 #include "pinoxmcommon.h"
51 #include "oxmverifycommon.h"
52 #if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
53 #include <mbedtls/ssl_ciphersuites.h>
54 #include <mbedtls/md.h>
55 #include "pkix_interface.h"
56 #endif
57
58 #define TAG  "OIC_SRM_DOXM"
59 #define CHAR_ZERO ('0')
60
61 /** Default cbor payload size. This value is increased in case of CborErrorOutOfMemory.
62  * The value of payload size is increased until reaching belox max cbor size. */
63 static const uint16_t CBOR_SIZE = 512;
64
65 /** Max cbor size payload. */
66 static const uint16_t CBOR_MAX_SIZE = 4400;
67
68 #if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
69 /** MAX uuid seed size */
70 #define MAX_UUID_SEED_SIZE (64)
71 /** MIN uuid seed size */
72 #define MIN_UUID_SEED_SIZE (8)
73
74 /** Buffer to save the seed of device UUID */
75 static uint8_t gUuidSeed[MAX_UUID_SEED_SIZE];
76 static size_t gUuidSeedSize = 0;
77 #endif
78
79 static OicSecDoxm_t        *gDoxm = NULL;
80 static OCResourceHandle    gDoxmHandle = NULL;
81
82 static OicSecOxm_t gDoxmDefaultOxm = OIC_RANDOM_DEVICE_PIN;
83 static OicSecDoxm_t gDefaultDoxm =
84 {
85     NULL,                   /* OicUrn_t *oxmType */
86     0,                      /* size_t oxmTypeLen */
87     &gDoxmDefaultOxm,       /* uint16_t *oxm */
88     1,                      /* size_t oxmLen */
89     OIC_RANDOM_DEVICE_PIN,  /* uint16_t oxmSel */
90     SYMMETRIC_PAIR_WISE_KEY,/* OicSecCredType_t sct */
91     false,                  /* bool owned */
92     {.id = {0}},            /* OicUuid_t deviceID */
93     false,                  /* bool dpc */
94     {.id = {0}},            /* OicUuid_t owner */
95 #ifdef MULTIPLE_OWNER
96     NULL,                   /* OicSecSubOwner_t sub-owner list */
97     NULL,                   /* OicSecMomType_t multiple owner mode */
98 #endif //MULTIPLE_OWNER
99     {.id = {0}},            /* OicUuid_t rownerID */
100 };
101
102 /**
103  * This method is internal method.
104  * the param roParsed is optionally used to know whether cborPayload has
105  * at least read only property value or not.
106  */
107 static OCStackResult CBORPayloadToDoxmBin(const uint8_t *cborPayload, size_t size,
108                                 OicSecDoxm_t **doxm, bool *roParsed);
109
110 void DeleteDoxmBinData(OicSecDoxm_t* doxm)
111 {
112     if (doxm)
113     {
114         //Clean oxmType
115         for (size_t i = 0; i < doxm->oxmTypeLen; i++)
116         {
117             OICFree(doxm->oxmType[i]);
118         }
119         OICFree(doxm->oxmType);
120
121         //clean oxm
122         OICFree(doxm->oxm);
123
124 #ifdef MULTIPLE_OWNER
125         //clean mom
126         OICFree(doxm->mom);
127
128         //clean sub-owner list
129         if(NULL != doxm->subOwners)
130         {
131             OicSecSubOwner_t* subowner = NULL;
132             OicSecSubOwner_t* temp = NULL;
133             LL_FOREACH_SAFE(doxm->subOwners, subowner, temp)
134             {
135                 LL_DELETE(doxm->subOwners, subowner);
136                 OICFree(subowner);
137             }
138         }
139 #endif //MULTIPLE_OWNER
140
141         //Clean doxm itself
142         OICFree(doxm);
143     }
144 }
145
146 OCStackResult DoxmToCBORPayload(const OicSecDoxm_t *doxm, uint8_t **payload, size_t *size,
147                                 bool rwOnly)
148 {
149     if (NULL == doxm || NULL == payload || NULL != *payload || NULL == size)
150     {
151         return OC_STACK_INVALID_PARAM;
152     }
153     size_t cborLen = *size;
154     if (0 == cborLen)
155     {
156         cborLen = CBOR_SIZE;
157     }
158     *payload = NULL;
159     *size = 0;
160
161     OCStackResult ret = OC_STACK_ERROR;
162
163     CborEncoder encoder;
164     CborEncoder doxmMap;
165     char* strUuid = NULL;
166
167     int64_t cborEncoderResult = CborNoError;
168
169     uint8_t *outPayload = (uint8_t *)OICCalloc(1, cborLen);
170     VERIFY_NOT_NULL_RETURN(TAG, outPayload, ERROR, OC_STACK_ERROR);
171
172     cbor_encoder_init(&encoder, outPayload, cborLen, 0);
173
174     cborEncoderResult = cbor_encoder_create_map(&encoder, &doxmMap, CborIndefiniteLength);
175     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Doxm Map.");
176
177     //OxmType -- Not Mandatory
178     if (doxm->oxmTypeLen > 0)
179     {
180         CborEncoder oxmType;
181         cborEncoderResult = cbor_encode_text_string(&doxmMap, OIC_JSON_OXM_TYPE_NAME,
182             strlen(OIC_JSON_OXM_TYPE_NAME));
183         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding oxmType Tag.");
184         cborEncoderResult = cbor_encoder_create_array(&doxmMap, &oxmType, doxm->oxmTypeLen);
185         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding oxmType Array.");
186
187         for (size_t i = 0; i < doxm->oxmTypeLen; i++)
188         {
189             cborEncoderResult = cbor_encode_text_string(&oxmType, doxm->oxmType[i],
190                 strlen(doxm->oxmType[i]));
191             VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding oxmType Value.");
192         }
193         cborEncoderResult = cbor_encoder_close_container(&doxmMap, &oxmType);
194         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing oxmType.");
195     }
196
197     //Oxm -- Not Mandatory
198     if (doxm->oxmLen > 0 && false == rwOnly)
199     {
200         CborEncoder oxm;
201         cborEncoderResult = cbor_encode_text_string(&doxmMap, OIC_JSON_OXMS_NAME,
202             strlen(OIC_JSON_OXMS_NAME));
203         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding oxmName Tag.");
204         cborEncoderResult = cbor_encoder_create_array(&doxmMap, &oxm, doxm->oxmLen);
205         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding oxmName Array.");
206
207         for (size_t i = 0; i < doxm->oxmLen; i++)
208         {
209             cborEncoderResult = cbor_encode_int(&oxm, doxm->oxm[i]);
210             VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding oxmName Value");
211         }
212         cborEncoderResult = cbor_encoder_close_container(&doxmMap, &oxm);
213         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing oxmName.");
214     }
215
216     //OxmSel -- Mandatory
217     cborEncoderResult = cbor_encode_text_string(&doxmMap, OIC_JSON_OXM_SEL_NAME,
218         strlen(OIC_JSON_OXM_SEL_NAME));
219     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Sel Tag.");
220     cborEncoderResult = cbor_encode_int(&doxmMap, doxm->oxmSel);
221     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Sel Value.");
222
223     //sct -- Mandatory
224     if (false == rwOnly)
225     {
226         cborEncoderResult = cbor_encode_text_string(&doxmMap, OIC_JSON_SUPPORTED_CRED_TYPE_NAME,
227             strlen(OIC_JSON_SUPPORTED_CRED_TYPE_NAME));
228         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Cred Type Tag");
229         cborEncoderResult = cbor_encode_int(&doxmMap, doxm->sct);
230         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Cred Type Value.");
231     }
232
233     //Owned -- Mandatory
234     cborEncoderResult = cbor_encode_text_string(&doxmMap, OIC_JSON_OWNED_NAME,
235         strlen(OIC_JSON_OWNED_NAME));
236     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Owned Tag.");
237     cborEncoderResult = cbor_encode_boolean(&doxmMap, doxm->owned);
238     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Owned Value.");
239
240     if (false == rwOnly)
241     {
242         //DeviceId -- Mandatory
243         cborEncoderResult = cbor_encode_text_string(&doxmMap, OIC_JSON_DEVICE_ID_NAME,
244             strlen(OIC_JSON_DEVICE_ID_NAME));
245         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Device Id Tag.");
246         ret = ConvertUuidToStr(&doxm->deviceID, &strUuid);
247         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret , ERROR);
248         cborEncoderResult = cbor_encode_text_string(&doxmMap, strUuid, strlen(strUuid));
249         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Device Id Value.");
250         OICFree(strUuid);
251         strUuid = NULL;
252     }
253
254 #ifdef MULTIPLE_OWNER
255     //Device SubOwnerID -- Not Mandatory
256     if(doxm->subOwners)
257     {
258         size_t subOwnerLen = 0;
259         OicSecSubOwner_t* subOwner = NULL;
260         LL_FOREACH(doxm->subOwners, subOwner)
261         {
262             subOwnerLen++;
263         }
264
265         CborEncoder subOwners;
266         cborEncoderResult = cbor_encode_text_string(&doxmMap, OIC_JSON_SUBOWNERID_NAME,
267             strlen(OIC_JSON_SUBOWNERID_NAME));
268         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding SubOwnerId Tag.");
269         cborEncoderResult = cbor_encoder_create_array(&doxmMap, &subOwners, subOwnerLen);
270         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding SubOwner Array.");
271
272         subOwner = NULL;
273         LL_FOREACH(doxm->subOwners, subOwner)
274         {
275             char* strSubOwnerUuid = NULL;
276             ret = ConvertUuidToStr(&subOwner->uuid, &strSubOwnerUuid);
277             VERIFY_SUCCESS(TAG, OC_STACK_OK == ret , ERROR);
278             cborEncoderResult = cbor_encode_text_string(&subOwners, strSubOwnerUuid, strlen(strSubOwnerUuid));
279             OICFree(strSubOwnerUuid);
280             VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding SubOwnerId Value");
281         }
282         cborEncoderResult = cbor_encoder_close_container(&doxmMap, &subOwners);
283         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing SubOwnerId.");
284     }
285
286     //Multiple Owner Mode -- Not Mandatory
287     if(doxm->mom)
288     {
289         cborEncoderResult = cbor_encode_text_string(&doxmMap, OIC_JSON_MOM_NAME,
290             strlen(OIC_JSON_MOM_NAME));
291         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding mom Tag");
292         cborEncoderResult = cbor_encode_int(&doxmMap, (int64_t)doxm->mom->mode);
293         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding mom Value.");
294     }
295 #endif //MULTIPLE_OWNER
296
297     //devownerid -- Mandatory
298     cborEncoderResult = cbor_encode_text_string(&doxmMap, OIC_JSON_DEVOWNERID_NAME,
299         strlen(OIC_JSON_DEVOWNERID_NAME));
300     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Owner Id Tag.");
301     ret = ConvertUuidToStr(&doxm->owner, &strUuid);
302     VERIFY_SUCCESS(TAG, OC_STACK_OK == ret , ERROR);
303     cborEncoderResult = cbor_encode_text_string(&doxmMap, strUuid, strlen(strUuid));
304     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Owner Id Value.");
305     OICFree(strUuid);
306     strUuid = NULL;
307
308     //ROwner -- Mandatory
309     cborEncoderResult = cbor_encode_text_string(&doxmMap, OIC_JSON_ROWNERID_NAME,
310         strlen(OIC_JSON_ROWNERID_NAME));
311     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ROwner Id Tag.");
312     ret = ConvertUuidToStr(&doxm->rownerID, &strUuid);
313     VERIFY_SUCCESS(TAG, OC_STACK_OK == ret , ERROR);
314     cborEncoderResult = cbor_encode_text_string(&doxmMap, strUuid, strlen(strUuid));
315     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ROwner Id Value.");
316     OICFree(strUuid);
317     strUuid = NULL;
318
319     //RT -- Mandatory
320     CborEncoder rtArray;
321     cborEncoderResult = cbor_encode_text_string(&doxmMap, OIC_JSON_RT_NAME,
322             strlen(OIC_JSON_RT_NAME));
323     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding RT Name Tag.");
324     cborEncoderResult = cbor_encoder_create_array(&doxmMap, &rtArray, 1);
325     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding RT Value.");
326     for (size_t i = 0; i < 1; i++)
327     {
328         cborEncoderResult = cbor_encode_text_string(&rtArray, OIC_RSRC_TYPE_SEC_DOXM,
329                 strlen(OIC_RSRC_TYPE_SEC_DOXM));
330         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding RT Value.");
331     }
332     cborEncoderResult = cbor_encoder_close_container(&doxmMap, &rtArray);
333     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing RT.");
334
335     //IF-- Mandatory
336      CborEncoder ifArray;
337      cborEncoderResult = cbor_encode_text_string(&doxmMap, OIC_JSON_IF_NAME,
338              strlen(OIC_JSON_IF_NAME));
339      VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding IF Name Tag.");
340      cborEncoderResult = cbor_encoder_create_array(&doxmMap, &ifArray, 1);
341      VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding IF Value.");
342     for (size_t i = 0; i < 1; i++)
343     {
344         cborEncoderResult = cbor_encode_text_string(&ifArray, OC_RSRVD_INTERFACE_DEFAULT,
345                 strlen(OC_RSRVD_INTERFACE_DEFAULT));
346         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding IF Value.");
347     }
348     cborEncoderResult = cbor_encoder_close_container(&doxmMap, &ifArray);
349     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing IF.");
350
351     cborEncoderResult = cbor_encoder_close_container(&encoder, &doxmMap);
352     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing DoxmMap.");
353
354     if (CborNoError == cborEncoderResult)
355     {
356         *size = cbor_encoder_get_buffer_size(&encoder, outPayload);
357         *payload = outPayload;
358         ret = OC_STACK_OK;
359     }
360 exit:
361     if ((CborErrorOutOfMemory == cborEncoderResult) && (cborLen < CBOR_MAX_SIZE))
362     {
363         OIC_LOG(DEBUG, TAG, "Memory getting reallocated.");
364         // reallocate and try again!
365         OICFree(outPayload);
366         outPayload = NULL;
367         // Since the allocated initial memory failed, double the memory.
368         cborLen += cbor_encoder_get_buffer_size(&encoder, encoder.end);
369         OIC_LOG_V(DEBUG, TAG, "Doxm reallocation size : %zd.", cborLen);
370         cborEncoderResult = CborNoError;
371         ret = DoxmToCBORPayload(doxm, payload, &cborLen, rwOnly);
372         *size = cborLen;
373     }
374
375     if ((CborNoError != cborEncoderResult) || (OC_STACK_OK != ret))
376     {
377        OICFree(outPayload);
378        outPayload = NULL;
379        *payload = NULL;
380        *size = 0;
381        ret = OC_STACK_ERROR;
382     }
383
384     return ret;
385 }
386
387 OCStackResult CBORPayloadToDoxm(const uint8_t *cborPayload, size_t size,
388                                 OicSecDoxm_t **secDoxm)
389 {
390     return CBORPayloadToDoxmBin(cborPayload, size, secDoxm, NULL);
391 }
392
393 static OCStackResult CBORPayloadToDoxmBin(const uint8_t *cborPayload, size_t size,
394                                 OicSecDoxm_t **secDoxm, bool *roParsed)
395 {
396     if (NULL == cborPayload || NULL == secDoxm || NULL != *secDoxm || 0 == size)
397     {
398         return OC_STACK_INVALID_PARAM;
399     }
400
401     OCStackResult ret = OC_STACK_ERROR;
402     *secDoxm = NULL;
403
404     CborParser parser;
405     CborError cborFindResult = CborNoError;
406     char* strUuid = NULL;
407     size_t len = 0;
408     CborValue doxmCbor;
409
410     cbor_parser_init(cborPayload, size, 0, &parser, &doxmCbor);
411     CborValue doxmMap;
412     OicSecDoxm_t *doxm = (OicSecDoxm_t *)OICCalloc(1, sizeof(*doxm));
413     VERIFY_NOT_NULL(TAG, doxm, ERROR);
414
415     cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_OXM_TYPE_NAME, &doxmMap);
416     //OxmType -- not Mandatory
417     if (CborNoError == cborFindResult && cbor_value_is_array(&doxmMap))
418     {
419         CborValue oxmType;
420
421         cborFindResult = cbor_value_get_array_length(&doxmMap, &doxm->oxmTypeLen);
422         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding oxmTypeLen.");
423         VERIFY_SUCCESS(TAG, doxm->oxmTypeLen != 0, ERROR);
424
425         doxm->oxmType = (OicUrn_t *)OICCalloc(doxm->oxmTypeLen, sizeof(*doxm->oxmType));
426         VERIFY_NOT_NULL(TAG, doxm->oxmType, ERROR);
427
428         cborFindResult = cbor_value_enter_container(&doxmMap, &oxmType);
429         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Entering oxmType Array.")
430
431         int i = 0;
432         size_t oxmTypeStrlen = 0;
433         while (cbor_value_is_valid(&oxmType) && cbor_value_is_text_string(&oxmType))
434         {
435             cborFindResult = cbor_value_dup_text_string(&oxmType, &doxm->oxmType[i++],
436                                                         &oxmTypeStrlen, NULL);
437             VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding omxType text string.");
438             cborFindResult = cbor_value_advance(&oxmType);
439             VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Advancing oxmType.");
440         }
441     }
442
443     cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_OXMS_NAME, &doxmMap);
444     //Oxm -- not Mandatory
445     if (CborNoError == cborFindResult && cbor_value_is_array(&doxmMap))
446     {
447         CborValue oxm;
448         cborFindResult = cbor_value_get_array_length(&doxmMap, &doxm->oxmLen);
449         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding oxmName array Length.");
450         VERIFY_SUCCESS(TAG, doxm->oxmLen != 0, ERROR);
451
452         doxm->oxm = (OicSecOxm_t *)OICCalloc(doxm->oxmLen, sizeof(*doxm->oxm));
453         VERIFY_NOT_NULL(TAG, doxm->oxm, ERROR);
454
455         cborFindResult = cbor_value_enter_container(&doxmMap, &oxm);
456         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Entering oxmName Array.")
457
458         int i = 0;
459         while (cbor_value_is_valid(&oxm) && cbor_value_is_integer(&oxm))
460         {
461             int tmp;
462
463             cborFindResult = cbor_value_get_int(&oxm, &tmp);
464             VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding oxmName Value")
465             doxm->oxm[i++] = (OicSecOxm_t)tmp;
466             cborFindResult = cbor_value_advance(&oxm);
467             VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Advancing oxmName.")
468         }
469
470         if (roParsed)
471         {
472             *roParsed = true;
473         }
474     }
475     else
476     {
477         VERIFY_NOT_NULL(TAG, gDoxm, ERROR);
478         doxm->oxm = (OicSecOxm_t *) OICCalloc(gDoxm->oxmLen, sizeof(*doxm->oxm));
479         VERIFY_NOT_NULL(TAG, doxm->oxm, ERROR);
480         doxm->oxmLen = gDoxm->oxmLen;
481         for (size_t i = 0; i < gDoxm->oxmLen; i++)
482         {
483             doxm->oxm[i] = gDoxm->oxm[i];
484         }
485     }
486
487     cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_OXM_SEL_NAME, &doxmMap);
488     if (CborNoError == cborFindResult && cbor_value_is_integer(&doxmMap))
489     {
490         int oxmSel;
491
492         cborFindResult = cbor_value_get_int(&doxmMap, &oxmSel);
493         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding Sel Name Value.")
494         doxm->oxmSel = (OicSecOxm_t)oxmSel;
495     }
496     else // PUT/POST JSON may not have oxmsel so set it to the gDoxm->oxmSel
497     {
498         VERIFY_NOT_NULL(TAG, gDoxm, ERROR);
499         doxm->oxmSel = gDoxm->oxmSel;
500     }
501
502     cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_SUPPORTED_CRED_TYPE_NAME, &doxmMap);
503     if (CborNoError == cborFindResult && cbor_value_is_integer(&doxmMap))
504     {
505         int sct;
506
507         cborFindResult = cbor_value_get_int(&doxmMap, &sct);
508         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding Sct Name Value.")
509         doxm->sct = (OicSecCredType_t)sct;
510
511         if (roParsed)
512         {
513             *roParsed = true;
514         }
515     }
516     else // PUT/POST JSON may not have sct so set it to the gDoxm->sct
517     {
518         VERIFY_NOT_NULL(TAG, gDoxm, ERROR);
519         doxm->sct = gDoxm->sct;
520     }
521
522     cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_OWNED_NAME, &doxmMap);
523     if (CborNoError == cborFindResult && cbor_value_is_boolean(&doxmMap))
524     {
525         cborFindResult = cbor_value_get_boolean(&doxmMap, &doxm->owned);
526         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding Owned Value.")
527     }
528     else // PUT/POST JSON may not have owned so set it to the gDomx->owned
529     {
530         VERIFY_NOT_NULL(TAG, gDoxm, ERROR);
531         doxm->owned = gDoxm->owned;
532     }
533
534     cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_DEVICE_ID_NAME, &doxmMap);
535     if (CborNoError == cborFindResult && cbor_value_is_text_string(&doxmMap))
536     {
537         cborFindResult = cbor_value_dup_text_string(&doxmMap, &strUuid , &len, NULL);
538         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding Device Id Value.");
539         ret = ConvertStrToUuid(strUuid , &doxm->deviceID);
540         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
541         OICFree(strUuid);
542         strUuid  = NULL;
543     }
544     else
545     {
546         VERIFY_NOT_NULL(TAG, gDoxm, ERROR);
547         memcpy(doxm->deviceID.id, &gDoxm->deviceID.id, sizeof(doxm->deviceID.id));
548     }
549
550     cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_DEVOWNERID_NAME, &doxmMap);
551     if (CborNoError == cborFindResult && cbor_value_is_text_string(&doxmMap))
552     {
553         cborFindResult = cbor_value_dup_text_string(&doxmMap, &strUuid , &len, NULL);
554         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding Owner Value.");
555         ret = ConvertStrToUuid(strUuid , &doxm->owner);
556         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
557         OICFree(strUuid);
558         strUuid  = NULL;
559     }
560     else
561     {
562         VERIFY_NOT_NULL(TAG, gDoxm, ERROR);
563         memcpy(doxm->owner.id, gDoxm->owner.id, sizeof(doxm->owner.id));
564     }
565
566 #ifdef MULTIPLE_OWNER
567     cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_MOM_NAME, &doxmMap);
568     if(CborNoError == cborFindResult && cbor_value_is_integer(&doxmMap))
569     {
570         int mode = 0;
571         cborFindResult = cbor_value_get_int(&doxmMap, &mode);
572         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding mom Name Value.")
573         if(NULL == doxm->mom)
574         {
575             doxm->mom = (OicSecMom_t*)OICCalloc(1, sizeof(OicSecMom_t));
576             VERIFY_NOT_NULL(TAG, doxm->mom, ERROR);
577         }
578         doxm->mom->mode = (OicSecMomType_t)mode;
579     }
580     else if(NULL != gDoxm && NULL != gDoxm->mom)
581     {
582         // PUT/POST JSON may not have 'mom' so set it to the gDomx->mom
583         if(NULL == doxm->mom)
584         {
585             doxm->mom = (OicSecMom_t*)OICCalloc(1, sizeof(OicSecMom_t));
586             VERIFY_NOT_NULL(TAG, doxm->mom, ERROR);
587         }
588         doxm->mom->mode = gDoxm->mom->mode;
589     }
590
591     cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_SUBOWNERID_NAME, &doxmMap);
592     if(CborNoError == cborFindResult && cbor_value_is_array(&doxmMap))
593     {
594         size_t subOwnerLen = 0;
595         CborValue subOwnerCbor;
596         cborFindResult = cbor_value_get_array_length(&doxmMap, &subOwnerLen);
597         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding SubOwner array Length.");
598         VERIFY_SUCCESS(TAG, 0 != subOwnerLen, ERROR);
599
600         cborFindResult = cbor_value_enter_container(&doxmMap, &subOwnerCbor);
601         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Entering SubOwner Array.")
602
603         while (cbor_value_is_valid(&subOwnerCbor) && cbor_value_is_text_string(&subOwnerCbor))
604         {
605             OCStackResult convertRes = OC_STACK_ERROR;
606             OicSecSubOwner_t* subOwner = NULL;
607             char* strSubOwnerUuid = NULL;
608             size_t uuidLen = 0;
609
610             cborFindResult = cbor_value_dup_text_string(&subOwnerCbor, &strSubOwnerUuid, &uuidLen, NULL);
611             VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding SubOwnerId Value");
612
613             subOwner = (OicSecSubOwner_t*)OICCalloc(1, sizeof(OicSecSubOwner_t));
614             VERIFY_NOT_NULL(TAG, subOwner, ERROR);
615
616             convertRes = ConvertStrToUuid(strSubOwnerUuid, &subOwner->uuid);
617             VERIFY_SUCCESS(TAG, OC_STACK_OK == convertRes, ERROR);
618             subOwner->status = MOT_STATUS_DONE;
619             LL_APPEND(doxm->subOwners, subOwner);
620
621             cborFindResult = cbor_value_advance(&subOwnerCbor);
622             VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Advancing SubOwnerId.")
623         }
624     }
625     else if(NULL != gDoxm && NULL != gDoxm->subOwners)
626     {
627         // PUT/POST JSON may not have 'subOwners' so set it to the gDomx->subOwners
628         OicSecSubOwner_t* subOwnerItor = NULL;
629         LL_FOREACH(gDoxm->subOwners, subOwnerItor)
630         {
631             OicSecSubOwner_t* subOwnerId = (OicSecSubOwner_t*)OICCalloc(1, sizeof(OicSecSubOwner_t));
632             VERIFY_NOT_NULL(TAG, subOwnerId, ERROR);
633
634             memcpy(&subOwnerId->uuid, &subOwnerItor->uuid, sizeof(OicUuid_t));
635             subOwnerId->status = MOT_STATUS_DONE;
636
637             LL_APPEND(doxm->subOwners, subOwnerId);
638         }
639     }
640 #endif //MULTIPLE_OWNER
641
642     cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_ROWNERID_NAME, &doxmMap);
643     if (CborNoError == cborFindResult && cbor_value_is_text_string(&doxmMap))
644     {
645         cborFindResult = cbor_value_dup_text_string(&doxmMap, &strUuid , &len, NULL);
646         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding ROwner Value.");
647         ret = ConvertStrToUuid(strUuid , &doxm->rownerID);
648         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
649         OICFree(strUuid);
650         strUuid  = NULL;
651     }
652     else
653     {
654         VERIFY_NOT_NULL(TAG, gDoxm, ERROR);
655         memcpy(doxm->rownerID.id, gDoxm->rownerID.id, sizeof(doxm->rownerID.id));
656     }
657
658     *secDoxm = doxm;
659     ret = OC_STACK_OK;
660
661 exit:
662     if (CborNoError != cborFindResult)
663     {
664         OIC_LOG (ERROR, TAG, "CBORPayloadToDoxm failed!!!");
665         DeleteDoxmBinData(doxm);
666         doxm = NULL;
667         *secDoxm = NULL;
668         ret = OC_STACK_ERROR;
669     }
670     return ret;
671 }
672
673 /**
674  * @todo document this function including why code might need to call this.
675  * The current suspicion is that it's not being called as much as it should.
676  */
677 static bool UpdatePersistentStorage(OicSecDoxm_t * doxm)
678 {
679     bool bRet = false;
680
681     if (NULL != doxm)
682     {
683         // Convert Doxm data into CBOR for update to persistent storage
684         uint8_t *payload = NULL;
685         size_t size = 0;
686         OCStackResult res = DoxmToCBORPayload(doxm, &payload, &size, false);
687         if (payload && (OC_STACK_OK == res)
688             && (OC_STACK_OK == UpdateSecureResourceInPS(OIC_JSON_DOXM_NAME, payload, size)))
689         {
690                 bRet = true;
691         }
692         OICFree(payload);
693     }
694     else
695     {
696         if (OC_STACK_OK == UpdateSecureResourceInPS(OIC_JSON_DOXM_NAME, NULL, 0))
697         {
698                 bRet = true;
699         }
700     }
701
702     return bRet;
703 }
704
705 static bool ValidateQuery(const char * query)
706 {
707     // Send doxm resource data if the state of doxm resource
708     // matches with the query parameters.
709     // else send doxm resource data as NULL
710     // TODO Remove this check and rely on Policy Engine
711     // and Provisioning Mode to enforce provisioning-state
712     // access rules. Eventually, the PE and PM code will
713     // not send a request to the /doxm Entity Handler at all
714     // if it should not respond.
715     OIC_LOG (DEBUG, TAG, "In ValidateQuery");
716     if(NULL == gDoxm)
717     {
718         return false;
719     }
720
721     bool bOwnedQry = false;         // does querystring contains 'owned' query ?
722     bool bOwnedMatch = false;       // does 'owned' query value matches with doxm.owned status?
723     bool bDeviceIDQry = false;      // does querystring contains 'deviceid' query ?
724     bool bDeviceIDMatch = false;    // does 'deviceid' query matches with doxm.deviceid ?
725     bool bInterfaceQry = false;      // does querystring contains 'if' query ?
726     bool bInterfaceMatch = false;    // does 'if' query matches with oic.if.baseline ?
727 #ifdef MULTIPLE_OWNER
728     bool bMotMatch = false;       // does 'mom' query value is not '0' && does query value matches with doxm.owned status?
729 #endif //MULTIPLE_OWNER
730
731     OicParseQueryIter_t parseIter = {.attrPos = NULL};
732
733     ParseQueryIterInit((unsigned char*)query, &parseIter);
734
735     while (GetNextQuery(&parseIter))
736     {
737         if (strncasecmp((char *)parseIter.attrPos, OIC_JSON_OWNED_NAME, parseIter.attrLen) == 0)
738         {
739             bOwnedQry = true;
740             if ((strncasecmp((char *)parseIter.valPos, OIC_SEC_TRUE, parseIter.valLen) == 0) &&
741                     (gDoxm->owned))
742             {
743                 bOwnedMatch = true;
744             }
745             else if ((strncasecmp((char *)parseIter.valPos, OIC_SEC_FALSE, parseIter.valLen) == 0)
746                     && (!gDoxm->owned))
747             {
748                 bOwnedMatch = true;
749             }
750         }
751
752 #ifdef MULTIPLE_OWNER
753         if (strncasecmp((char *)parseIter.attrPos, OIC_JSON_MOM_NAME, strlen(OIC_JSON_MOM_NAME)) == 0)
754         {
755             OicSecMomType_t momMode = (OicSecMomType_t)(parseIter.valPos[0] - CHAR_ZERO);
756             if(NULL != gDoxm->mom && momMode != gDoxm->mom->mode)
757             {
758                 if(GetNextQuery(&parseIter))
759                 {
760                     if (strncasecmp((char *)parseIter.attrPos, OIC_JSON_OWNED_NAME, parseIter.attrLen) == 0)
761                     {
762                         if ((strncasecmp((char *)parseIter.valPos, OIC_SEC_TRUE, parseIter.valLen) == 0) &&
763                                 (gDoxm->owned))
764                         {
765                             bMotMatch = true;
766                         }
767                     }
768                 }
769             }
770             return bMotMatch;
771         }
772 #endif //MULTIPLE_OWNER
773
774         if (strncasecmp((char *)parseIter.attrPos, OIC_JSON_DEVICE_ID_NAME, parseIter.attrLen) == 0)
775         {
776             bDeviceIDQry = true;
777             OicUuid_t subject = {.id={0}};
778
779             memcpy(subject.id, parseIter.valPos, parseIter.valLen);
780             if (0 == memcmp(&gDoxm->deviceID.id, &subject.id, sizeof(gDoxm->deviceID.id)))
781             {
782                 bDeviceIDMatch = true;
783             }
784         }
785
786         if (strncasecmp((char *)parseIter.attrPos, OC_RSRVD_INTERFACE, parseIter.attrLen) == 0)
787         {
788             bInterfaceQry = true;
789             if ((strncasecmp((char *)parseIter.valPos, OC_RSRVD_INTERFACE_DEFAULT, parseIter.valLen) == 0))
790             {
791                 bInterfaceMatch = true;
792             }
793             return (bInterfaceQry ? bInterfaceMatch: true);
794         }
795     }
796
797     return ((bOwnedQry ? bOwnedMatch : true) &&
798             (bDeviceIDQry ? bDeviceIDMatch : true));
799 }
800
801 static OCEntityHandlerResult HandleDoxmGetRequest (const OCEntityHandlerRequest * ehRequest)
802 {
803     OCEntityHandlerResult ehRet = OC_EH_OK;
804
805     OIC_LOG(DEBUG, TAG, "Doxm EntityHandle processing GET request");
806
807     //Checking if Get request is a query.
808     if (ehRequest->query)
809     {
810         OIC_LOG_V(DEBUG,TAG,"query:%s",ehRequest->query);
811         OIC_LOG(DEBUG, TAG, "HandleDoxmGetRequest processing query");
812         if (!ValidateQuery(ehRequest->query))
813         {
814             ehRet = OC_EH_ERROR;
815         }
816     }
817
818     /*
819      * For GET or Valid Query request return doxm resource CBOR payload.
820      * For non-valid query return NULL json payload.
821      * A device will 'always' have a default Doxm, so DoxmToCBORPayload will
822      * return valid doxm resource json.
823      */
824     uint8_t *payload = NULL;
825     size_t size = 0;
826
827     if (ehRet == OC_EH_OK)
828     {
829         if (OC_STACK_OK != DoxmToCBORPayload(gDoxm, &payload, &size, false))
830         {
831             OIC_LOG(WARNING, TAG, "DoxmToCBORPayload failed in HandleDoxmGetRequest");
832         }
833     }
834
835     OIC_LOG(DEBUG, TAG, "Send payload for doxm GET request");
836     OIC_LOG_BUFFER(DEBUG, TAG, payload, size);
837
838     // Send response payload to request originator
839     ehRet = ((SendSRMResponse(ehRequest, ehRet, payload, size)) == OC_STACK_OK) ?
840                    OC_EH_OK : OC_EH_ERROR;
841
842     OICFree(payload);
843
844     return ehRet;
845 }
846
847 OCStackResult DoxmUpdateWriteableProperty(const OicSecDoxm_t* src, OicSecDoxm_t* dst)
848 {
849     OCStackResult result = OC_STACK_OK;
850
851     if(src && dst)
852     {
853         // Update oxmsel
854         dst->oxmSel = src->oxmSel;
855
856         // Update owner
857         memcpy(&(dst->owner), &(src->owner), sizeof(OicUuid_t));
858
859         // Update rowner
860         memcpy(&(dst->rownerID), &(src->rownerID), sizeof(OicUuid_t));
861
862         // Update deviceuuid
863         memcpy(&(dst->deviceID), &(src->deviceID), sizeof(OicUuid_t));
864
865         // Update owned status
866         if(dst->owned != src->owned)
867         {
868             dst->owned = src->owned;
869         }
870
871 #ifdef MULTIPLE_OWNER
872         if(src->mom)
873         {
874             OIC_LOG(DEBUG, TAG, "Detected 'mom' property");
875             if(NULL == dst->mom)
876             {
877                 dst->mom = (OicSecMom_t*)OICCalloc(1, sizeof(OicSecMom_t));
878                 if (NULL == dst->mom)
879                 {
880                     result = OC_STACK_NO_MEMORY;
881                 }
882             }
883
884             if (NULL != dst->mom)
885             {
886                 dst->mom->mode = src->mom->mode;
887             }
888         }
889 #endif //MULTIPLE_OWNER
890     }
891
892     return result;
893 }
894
895 #if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
896 #ifdef MULTIPLE_OWNER
897 /**
898  * Callback function to handle MOT DTLS handshake result.
899  * @param[out]   object           remote device information.
900  * @param[out]   errorInfo        CA Error information.
901  */
902 void MultipleOwnerDTLSHandshakeCB(const CAEndpoint_t *object,
903                                 const CAErrorInfo_t *errorInfo)
904 {
905     OIC_LOG(DEBUG, TAG, "IN MultipleOwnerDTLSHandshakeCB");
906
907     if(CA_STATUS_OK == errorInfo->result)
908     {
909         CASecureEndpoint_t authenticationSubOwnerInfo;
910         CAResult_t caRes = CAGetSecureEndpointData(object, &authenticationSubOwnerInfo);
911         if (CA_STATUS_OK == caRes)
912         {
913             if (0 == memcmp(authenticationSubOwnerInfo.identity.id, gDoxm->owner.id,
914                             authenticationSubOwnerInfo.identity.id_length))
915             {
916                 OIC_LOG(WARNING, TAG, "Super owner tried MOT, this request will be ignored.");
917                 return;
918             }
919
920             OicSecSubOwner_t* subOwnerInst = NULL;
921             LL_FOREACH(gDoxm->subOwners, subOwnerInst)
922             {
923                 if(0 == memcmp(subOwnerInst->uuid.id,
924                                authenticationSubOwnerInfo.identity.id,
925                                authenticationSubOwnerInfo.identity.id_length))
926                 {
927                     break;
928                 }
929             }
930
931             if(NULL == subOwnerInst)
932             {
933                 subOwnerInst = (OicSecSubOwner_t*)OICCalloc(1, sizeof(OicSecSubOwner_t));
934                 if(subOwnerInst)
935                 {
936                     char* strUuid = NULL;
937                     memcpy(subOwnerInst->uuid.id, authenticationSubOwnerInfo.identity.id,
938                            authenticationSubOwnerInfo.identity.id_length);
939                     if(OC_STACK_OK != ConvertUuidToStr(&subOwnerInst->uuid, &strUuid))
940                     {
941                         OIC_LOG(ERROR, TAG, "Failed to allocate memory.");
942                         return;
943                     }
944                     OIC_LOG_V(DEBUG, TAG, "Adding New SubOwner(%s)", strUuid);
945                     OICFree(strUuid);
946                     LL_APPEND(gDoxm->subOwners, subOwnerInst);
947                     if(!UpdatePersistentStorage(gDoxm))
948                     {
949                         OIC_LOG(ERROR, TAG, "Failed to register SubOwner UUID into Doxm");
950                     }
951                 }
952             }
953         }
954         else
955         {
956             OIC_LOG_V(ERROR, TAG, "Could not CAGetSecureEndpointData: %d", caRes);
957         }
958     }
959
960     if(CA_STATUS_OK != CAregisterPskCredentialsHandler(GetDtlsPskCredentials))
961     {
962         OIC_LOG(WARNING, TAG, "Failed to revert the DTLS credential handler");
963     }
964
965     OIC_LOG(DEBUG, TAG, "OUT MultipleOwnerDTLSHandshakeCB");
966 }
967 #endif //MULTIPLE_OWNER
968 #endif // defined(__WITH_DTLS__) || defined (__WITH_TLS__)
969
970 /**
971  * Function to validate oxmsel with oxms.
972  *
973  * @param[in] supportedMethods   Array of supported methods
974  * @param[in] numberOfMethods   number of supported methods
975  * @param[out]  selectedMethod         Selected methods
976  * @return  TRUE on success
977  */
978 static bool ValidateOxmsel(const OicSecOxm_t *supportedMethods,
979         size_t numberOfMethods, OicSecOxm_t *selectedMethod)
980 {
981     bool isValidOxmsel = false;
982
983     OIC_LOG(DEBUG, TAG, "IN ValidateOxmsel");
984     if (numberOfMethods == 0 || !supportedMethods)
985     {
986         OIC_LOG(WARNING, TAG, "Could not find a supported OxM.");
987         return isValidOxmsel;
988     }
989
990     for (size_t i = 0; i < numberOfMethods; i++)
991     {
992             if (*selectedMethod  == supportedMethods[i])
993             {
994                 isValidOxmsel = true;
995                 break;
996             }
997     }
998     if (!isValidOxmsel)
999     {
1000         OIC_LOG(ERROR, TAG, "Not allowed Oxmsel.");
1001         return isValidOxmsel;
1002     }
1003
1004     OIC_LOG(DEBUG, TAG, "OUT ValidateOxmsel");
1005
1006     return isValidOxmsel;
1007 }
1008
1009 #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
1010 static void DoxmDTLSHandshakeCB(const CAEndpoint_t *endpoint, const CAErrorInfo_t *info)
1011 {
1012     OIC_LOG_V(DEBUG, TAG, "In %s(%p, %p)", __func__, endpoint, info);
1013
1014     if ((NULL != endpoint) && (NULL != info) && (CA_STATUS_OK == info->result))
1015     {
1016         /*
1017          * Allow this OBT endpoint to bypass ACE checks for SVRs, while this
1018          * device is not yet owned.
1019          */
1020         OC_VERIFY(CASetSecureEndpointAttribute(endpoint,
1021             CA_SECURE_ENDPOINT_ATTRIBUTE_ADMINISTRATOR));
1022     }
1023
1024     OIC_LOG_V(DEBUG, TAG, "Out %s(%p, %p)", __func__, endpoint, info);
1025 }
1026
1027 static void RegisterOTMSslHandshakeCallback(CAErrorCallback callback)
1028 {
1029     OC_VERIFY(CA_STATUS_OK == CAregisterSslHandshakeCallback(callback));
1030 }
1031 #endif // __WITH_DTLS__ or __WITH_TLS__
1032
1033 static OCEntityHandlerResult HandleDoxmPostRequest(OCEntityHandlerRequest * ehRequest)
1034 {
1035     OIC_LOG (DEBUG, TAG, "Doxm EntityHandle  processing POST request");
1036     OCEntityHandlerResult ehRet = OC_EH_ERROR;
1037     OicUuid_t emptyOwner = {.id = {0} };
1038     static uint16_t previousMsgId = 0;
1039     bool isDuplicatedMsg = false;
1040
1041     /*
1042      * Convert CBOR Doxm data into binary. This will also validate
1043      * the Doxm data received.
1044      */
1045     OicSecDoxm_t *newDoxm = NULL;
1046
1047     if (ehRequest->payload)
1048     {
1049         uint8_t *payload = ((OCSecurityPayload *)ehRequest->payload)->securityData;
1050         size_t size = ((OCSecurityPayload *)ehRequest->payload)->payloadSize;
1051         bool roParsed = false;
1052         OCStackResult res = CBORPayloadToDoxmBin(payload, size, &newDoxm, &roParsed);
1053         if (newDoxm && OC_STACK_OK == res)
1054         {
1055             /*
1056              * message ID is supported for CoAP over UDP only according to RFC 7252
1057              * So we should check message ID to prevent duplicate request handling in case of OC_ADAPTER_IP.
1058              * In case of other transport adapter, duplicate message check is not required.
1059              */
1060             if (OC_ADAPTER_IP == ehRequest->devAddr.adapter &&
1061                  previousMsgId == ehRequest->messageID)
1062             {
1063                 isDuplicatedMsg = true;
1064             }
1065
1066             // Check request on RO property
1067             if (true == roParsed)
1068             {
1069                 OIC_LOG(ERROR, TAG, "Not acceptable request because of read-only propertys");
1070                 ehRet = OC_EH_NOT_ACCEPTABLE;
1071                 goto exit;
1072             }
1073
1074             // in owned state
1075             if (true == gDoxm->owned)
1076             {
1077                 if (false == ValidateOxmsel(gDoxm->oxm, gDoxm->oxmLen, &newDoxm->oxmSel))
1078                 {
1079                     OIC_LOG(ERROR, TAG, "Not acceptable request because oxmsel does not support on Server");
1080                     ehRet = OC_EH_NOT_ACCEPTABLE;
1081                     goto exit;
1082                 }
1083
1084                 // Update gDoxm based on newDoxm
1085                 res = DoxmUpdateWriteableProperty(newDoxm, gDoxm);
1086                 if (OC_STACK_OK != res)
1087                 {
1088                     OIC_LOG(ERROR, TAG, "gDoxm properties were not able to be updated so we cannot handle the request.");
1089                     ehRet = OC_EH_ERROR;
1090                     goto exit;
1091                 }
1092
1093 #if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
1094 #ifdef MULTIPLE_OWNER
1095                 //handle mom
1096                 if(gDoxm->mom)
1097                 {
1098                     if(OIC_MULTIPLE_OWNER_DISABLE != gDoxm->mom->mode)
1099                     {
1100                         CAResult_t caRes = CA_STATUS_FAILED;
1101                         if(OIC_PRECONFIG_PIN == gDoxm->oxmSel || OIC_RANDOM_DEVICE_PIN == gDoxm->oxmSel)
1102                         {
1103                             caRes = CAEnableAnonECDHCipherSuite(false);
1104                             VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
1105                             OIC_LOG(INFO, TAG, "ECDH_ANON CipherSuite is DISABLED");
1106
1107                             RegisterOTMSslHandshakeCallback(DoxmDTLSHandshakeCB);
1108                             caRes = CASelectCipherSuite((uint16_t)MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256, ehRequest->devAddr.adapter);
1109                             VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
1110                             OIC_LOG(INFO, TAG, "ECDHE_PSK CipherSuite will be used for MOT");
1111
1112                             //Set the device id to derive temporal PSK
1113                             SetUuidForPinBasedOxm(&gDoxm->deviceID);
1114                         }
1115                         else
1116                         {
1117                             OIC_LOG(WARNING, TAG, "Unsupported OxM for Multiple Ownership Transfer.");
1118                         }
1119
1120                         CAregisterSslHandshakeCallback(MultipleOwnerDTLSHandshakeCB);
1121                     }
1122                     else
1123                     {
1124                         //if MOM is disabled, revert the DTLS handshake callback
1125                         if(CA_STATUS_OK != CAregisterSslHandshakeCallback(NULL))
1126                         {
1127                             OIC_LOG(WARNING, TAG, "Error while revert the DTLS Handshake Callback.");
1128                         }
1129                     }
1130                 }
1131
1132                 if(newDoxm->subOwners)
1133                 {
1134                     OicSecSubOwner_t* subowner = NULL;
1135                     OicSecSubOwner_t* temp = NULL;
1136
1137                     OIC_LOG(DEBUG, TAG, "dectected 'subowners' property");
1138
1139                     if(gDoxm->subOwners)
1140                     {
1141                         LL_FOREACH_SAFE(gDoxm->subOwners, subowner, temp)
1142                         {
1143                             LL_DELETE(gDoxm->subOwners, subowner);
1144                             OICFree(subowner);
1145                         }
1146                     }
1147
1148                     subowner = NULL;
1149                     temp = NULL;
1150                     LL_FOREACH_SAFE(newDoxm->subOwners, subowner, temp)
1151                     {
1152                         LL_DELETE(newDoxm->subOwners, subowner);
1153                         LL_APPEND(gDoxm->subOwners, subowner);
1154                     }
1155                 }
1156 #endif //MULTIPLE_OWNER
1157 #endif // defined(__WITH_DTLS__) || defined (__WITH_TLS__)
1158
1159                 //Update new state in persistent storage
1160                 if (UpdatePersistentStorage(gDoxm) == true)
1161                 {
1162                     ehRet = OC_EH_OK;
1163                 }
1164                 else
1165                 {
1166                     OIC_LOG(ERROR, TAG, "Failed to update DOXM in persistent storage");
1167                     ehRet = OC_EH_ERROR;
1168                 }
1169                 goto exit;
1170             }
1171
1172             // in unowned state
1173             if ((false == gDoxm->owned) && (false == newDoxm->owned))
1174             {
1175                 if (false == ValidateOxmsel(gDoxm->oxm, gDoxm->oxmLen, &newDoxm->oxmSel))
1176                 {
1177                     OIC_LOG(ERROR, TAG, "Not acceptable request because oxmsel does not support on Server");
1178                     ehRet = OC_EH_NOT_ACCEPTABLE;
1179                     goto exit;
1180                 }
1181
1182                 if (OIC_JUST_WORKS == newDoxm->oxmSel || OIC_MV_JUST_WORKS == newDoxm->oxmSel)
1183                 {
1184                     /*
1185                      * If current state of the device is un-owned, enable
1186                      * anonymous ECDH cipher in tinyDTLS so that Provisioning
1187                      * tool can initiate JUST_WORKS ownership transfer process.
1188                      */
1189                     if (memcmp(&(newDoxm->owner), &emptyOwner, sizeof(OicUuid_t)) == 0)
1190                     {
1191                         gDoxm->oxmSel = newDoxm->oxmSel;
1192                         //Update new state in persistent storage
1193                         if ((UpdatePersistentStorage(gDoxm) == true))
1194                         {
1195                             ehRet = OC_EH_OK;
1196                         }
1197                         else
1198                         {
1199                             OIC_LOG(WARNING, TAG, "Failed to update DOXM in persistent storage");
1200                             ehRet = OC_EH_ERROR;
1201                             goto exit;
1202                         }
1203 #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
1204                         RegisterOTMSslHandshakeCallback(DoxmDTLSHandshakeCB);
1205                         OIC_LOG(INFO, TAG, "Doxm EntityHandle  enabling AnonECDHCipherSuite");
1206                         ehRet = (CAEnableAnonECDHCipherSuite(true) == CA_STATUS_OK) ? OC_EH_OK : OC_EH_ERROR;
1207 #endif // __WITH_DTLS__ or __WITH_TLS__
1208                         goto exit;
1209                     }
1210                     else
1211                     {
1212 #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
1213                         //Save the owner's UUID to derive owner credential
1214                         memcpy(&(gDoxm->owner), &(newDoxm->owner), sizeof(OicUuid_t));
1215
1216                         // Update new state in persistent storage
1217                         if (true == UpdatePersistentStorage(gDoxm))
1218                         {
1219                             ehRet = OC_EH_OK;
1220                         }
1221                         else
1222                         {
1223                             OIC_LOG(ERROR, TAG, "Failed to update DOXM in persistent storage");
1224                             ehRet = OC_EH_ERROR;
1225                             goto exit;
1226                         }
1227
1228                         /*
1229                          * Disable anonymous ECDH cipher in tinyDTLS since device is now
1230                          * in owned state.
1231                          */
1232                         RegisterOTMSslHandshakeCallback(NULL);
1233                         CAResult_t caRes = CA_STATUS_OK;
1234                         caRes = CAEnableAnonECDHCipherSuite(false);
1235                         VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
1236                         OIC_LOG(INFO, TAG, "ECDH_ANON CipherSuite is DISABLED");
1237
1238                         //In case of Mutual Verified Just-Works, verify mutualVerifNum
1239                         if (OIC_MV_JUST_WORKS == newDoxm->oxmSel && false == newDoxm->owned &&
1240                             false == isDuplicatedMsg)
1241                         {
1242                             uint8_t preMutualVerifNum[OWNER_PSK_LENGTH_128] = {0};
1243                             uint8_t mutualVerifNum[MUTUAL_VERIF_NUM_LEN] = {0};
1244                             OicUuid_t deviceID = {.id = {0}};
1245
1246                             //Generate mutualVerifNum
1247                             OCServerRequest * request = GetServerRequestUsingHandle(ehRequest->requestHandle);
1248
1249                             char label[LABEL_LEN] = {0};
1250                             snprintf(label, LABEL_LEN, "%s%s", MUTUAL_VERIF_NUM, OXM_MV_JUST_WORKS);
1251                             if (OC_STACK_OK != GetDoxmDeviceID(&deviceID))
1252                             {
1253                                 OIC_LOG(ERROR, TAG, "Error while retrieving Owner's device ID");
1254                                 ehRet = OC_EH_ERROR;
1255                                 goto exit;
1256
1257                             }
1258
1259                             CAResult_t pskRet = CAGenerateOwnerPSK((CAEndpoint_t *)&request->devAddr,
1260                                     (uint8_t *)label,
1261                                     strlen(label),
1262                                     gDoxm->owner.id, sizeof(gDoxm->owner.id),
1263                                     gDoxm->deviceID.id, sizeof(gDoxm->deviceID.id),
1264                                     preMutualVerifNum, OWNER_PSK_LENGTH_128);
1265                             if (CA_STATUS_OK != pskRet)
1266                             {
1267                                 OIC_LOG(WARNING, TAG, "Failed to remove the invaild owner credential");
1268                                 ehRet = OC_EH_ERROR;
1269                                 goto exit;
1270
1271                             }
1272
1273                             memcpy(mutualVerifNum, preMutualVerifNum + OWNER_PSK_LENGTH_128 - sizeof(mutualVerifNum),
1274                                     sizeof(mutualVerifNum));
1275
1276                             //Wait for user confirmation
1277                             if (OC_STACK_OK != VerifyOwnershipTransfer(mutualVerifNum, DISPLAY_NUM | USER_CONFIRM))
1278                             {
1279                                 ehRet = OC_EH_NOT_ACCEPTABLE;
1280                             }
1281                             else
1282                             {
1283                                 ehRet = OC_EH_OK;
1284                             }
1285                         }
1286
1287 #endif // __WITH_DTLS__ or __WITH_TLS__
1288                     }
1289                 }
1290                 else if (OIC_RANDOM_DEVICE_PIN == newDoxm->oxmSel)
1291                 {
1292                     /*
1293                      * If current state of the device is un-owned, enable
1294                      * ECDHE_PSK cipher so that the Provisioning tool can
1295                      * initiate the ownership transfer.
1296                      */
1297                     if(memcmp(&(newDoxm->owner), &emptyOwner, sizeof(OicUuid_t)) == 0)
1298                     {
1299                         gDoxm->oxmSel = newDoxm->oxmSel;
1300                         //Update new state in persistent storage
1301                         if ((UpdatePersistentStorage(gDoxm) == true))
1302                         {
1303                             ehRet = OC_EH_OK;
1304                         }
1305                         else
1306                         {
1307                             OIC_LOG(WARNING, TAG, "Failed to update DOXM in persistent storage");
1308                             ehRet = OC_EH_ERROR;
1309                         }
1310
1311 #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
1312                         CAResult_t caRes = CAEnableAnonECDHCipherSuite(false);
1313                         VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
1314                         OIC_LOG(INFO, TAG, "ECDH_ANON CipherSuite is DISABLED");
1315
1316                         RegisterOTMSslHandshakeCallback(DoxmDTLSHandshakeCB);
1317                         caRes = CASelectCipherSuite(MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256,
1318                                                     ehRequest->devAddr.adapter);
1319                         VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
1320
1321                         if (!isDuplicatedMsg)
1322                         {
1323                             char ranPin[OXM_RANDOM_PIN_MAX_SIZE + 1] = {0};
1324                             if (OC_STACK_OK == GeneratePin(ranPin, sizeof(ranPin)))
1325                             {
1326                                 //Set the device id to derive temporal PSK
1327                                 SetUuidForPinBasedOxm(&gDoxm->deviceID);
1328
1329                                 /**
1330                                  * Since PSK will be used directly by DTLS layer while PIN based ownership transfer,
1331                                  * Credential should not be saved into SVR.
1332                                  * For this reason, use a temporary get_psk_info callback to random PIN OxM.
1333                                  */
1334                                 caRes = CAregisterPskCredentialsHandler(GetDtlsPskForRandomPinOxm);
1335                                 VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
1336                                 ehRet = OC_EH_OK;
1337                             }
1338                             else
1339                             {
1340                                 OIC_LOG(ERROR, TAG, "Failed to generate random PIN");
1341                                 ehRet = OC_EH_ERROR;
1342                             }
1343                         }
1344 #endif // __WITH_DTLS__ or __WITH_TLS__
1345                     }
1346 #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
1347                     else
1348                     {
1349                         //Save the owner's UUID to derive owner credential
1350                         memcpy(&(gDoxm->owner), &(newDoxm->owner), sizeof(OicUuid_t));
1351
1352                         // In case of random-pin based OTM, close the PIN display if callback is registered.
1353                         if (!isDuplicatedMsg)
1354                         {
1355                             ClosePinDisplay();
1356                         }
1357
1358                         //Update new state in persistent storage
1359                         if (UpdatePersistentStorage(gDoxm) == true)
1360                         {
1361                             ehRet = OC_EH_OK;
1362                         }
1363                         else
1364                         {
1365                             OIC_LOG(ERROR, TAG, "Failed to update DOXM in persistent storage");
1366                             ehRet = OC_EH_ERROR;
1367                         }
1368                     }
1369 #endif // __WITH_DTLS__ or __WITH_TLS__
1370                 }
1371 #if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
1372                 else if (OIC_MANUFACTURER_CERTIFICATE ==  newDoxm->oxmSel || OIC_CON_MFG_CERT == newDoxm->oxmSel)
1373                 {
1374                     //In case of Confirm Manufacturer Cert, get user confirmation
1375                     if (OIC_CON_MFG_CERT == newDoxm->oxmSel && false == newDoxm->owned &&
1376                         false == isDuplicatedMsg &&
1377                         memcmp(&(newDoxm->owner), &emptyOwner, sizeof(OicUuid_t)) != 0)
1378                     {
1379                         if (OC_STACK_OK != VerifyOwnershipTransfer(NULL, USER_CONFIRM))
1380                         {
1381                             ehRet = OC_EH_NOT_ACCEPTABLE;
1382                             goto exit;
1383                         }
1384                         else
1385                         {
1386                             ehRet = OC_EH_OK;
1387                         }
1388                     }
1389
1390                     //Save the owner's UUID to derive owner credential
1391                     memcpy(&(gDoxm->owner), &(newDoxm->owner), sizeof(OicUuid_t));
1392                     gDoxm->oxmSel = newDoxm->oxmSel;
1393                     //Update new state in persistent storage
1394                     if (UpdatePersistentStorage(gDoxm))
1395                     {
1396                         ehRet = OC_EH_OK;
1397                     }
1398                     else
1399                     {
1400                         OIC_LOG(WARNING, TAG, "Failed to update DOXM in persistent storage");
1401                         ehRet = OC_EH_ERROR;
1402                     }
1403
1404                     RegisterOTMSslHandshakeCallback(NULL);
1405                     CAResult_t caRes = CAEnableAnonECDHCipherSuite(false);
1406                     VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
1407                     OIC_LOG(INFO, TAG, "ECDH_ANON CipherSuite is DISABLED");
1408
1409                     //Unset pre-selected ciphersuite, if any
1410                     caRes = CASelectCipherSuite(0, ehRequest->devAddr.adapter);
1411                     VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
1412                     OIC_LOG(DEBUG, TAG, "No ciphersuite preferred");
1413
1414                     VERIFY_SUCCESS(TAG, CA_STATUS_OK == CAregisterPkixInfoHandler(GetManufacturerPkixInfo), ERROR);
1415                     VERIFY_SUCCESS(TAG, CA_STATUS_OK == CAregisterGetCredentialTypesHandler(InitManufacturerCipherSuiteList), ERROR);
1416                 }
1417 #endif // __WITH_DTLS__ or __WITH_TLS__
1418             }
1419
1420             /*
1421              * When current state of the device is un-owned and Provisioning
1422              * Tool is attempting to change the state to 'Owned' with a
1423              * qualified value for the field 'Owner'
1424              */
1425             if ((false == gDoxm->owned) && (true == newDoxm->owned) &&
1426                     (memcmp(&(gDoxm->owner), &(newDoxm->owner), sizeof(OicUuid_t)) == 0))
1427             {
1428                 //Change the SVR's resource owner as owner device.
1429                 OCStackResult ownerRes = SetAclRownerId(&gDoxm->owner);
1430                 if(OC_STACK_OK != ownerRes && OC_STACK_NO_RESOURCE != ownerRes)
1431                 {
1432                     ehRet = OC_EH_ERROR;
1433                     goto exit;
1434                 }
1435                 ownerRes = SetCredRownerId(&gDoxm->owner);
1436                 if(OC_STACK_OK != ownerRes && OC_STACK_NO_RESOURCE != ownerRes)
1437                 {
1438                     ehRet = OC_EH_ERROR;
1439                     goto exit;
1440                 }
1441                 ownerRes = SetPstatRownerId(&gDoxm->owner);
1442                 if(OC_STACK_OK != ownerRes && OC_STACK_NO_RESOURCE != ownerRes)
1443                 {
1444                     ehRet = OC_EH_ERROR;
1445                     goto exit;
1446                 }
1447                 ownerRes = SetDpairingRownerId(&gDoxm->owner);
1448                 if(OC_STACK_OK != ownerRes && OC_STACK_NO_RESOURCE != ownerRes)
1449                 {
1450                     ehRet = OC_EH_ERROR;
1451                     goto exit;
1452                 }
1453                 ownerRes = SetPconfRownerId(&gDoxm->owner);
1454                 if(OC_STACK_OK != ownerRes && OC_STACK_NO_RESOURCE != ownerRes)
1455                 {
1456                     ehRet = OC_EH_ERROR;
1457                     goto exit;
1458                 }
1459
1460                 gDoxm->owned = true;
1461                 memcpy(&gDoxm->rownerID, &gDoxm->owner, sizeof(OicUuid_t));
1462
1463                 // Update new state in persistent storage
1464                 if (UpdatePersistentStorage(gDoxm))
1465                 {
1466                     //Update default ACE of security resource to prevent anonymous user access.
1467                     if(OC_STACK_OK == UpdateDefaultSecProvACE())
1468                     {
1469                         ehRet = OC_EH_OK;
1470                     }
1471                     else
1472                     {
1473                         OIC_LOG(ERROR, TAG, "Failed to remove default ACL for security provisioning");
1474                         ehRet = OC_EH_ERROR;
1475                     }
1476                 }
1477                 else
1478                 {
1479                     OIC_LOG(ERROR, TAG, "Failed to update DOXM in persistent storage");
1480                     ehRet = OC_EH_ERROR;
1481                 }
1482 #if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
1483                 if (OIC_MANUFACTURER_CERTIFICATE == gDoxm->oxmSel ||
1484                                             OIC_CON_MFG_CERT== gDoxm->oxmSel)
1485                 {
1486                     CAregisterPkixInfoHandler(GetPkixInfo);
1487                     CAregisterGetCredentialTypesHandler(InitCipherSuiteList);
1488                 }
1489 #endif // __WITH_DTLS__ or __WITH_TLS__
1490             }
1491         }
1492     }
1493
1494 exit:
1495     if(OC_EH_OK != ehRet)
1496     {
1497
1498         /*
1499          * If some error is occured while ownership transfer,
1500          * ownership transfer related resource should be revert back to initial status.
1501         */
1502         if(gDoxm)
1503         {
1504             if(!gDoxm->owned)
1505             {
1506                 OIC_LOG(WARNING, TAG, "The operation failed during handle DOXM request");
1507
1508                 if (!isDuplicatedMsg)
1509                 {
1510                     RestoreDoxmToInitState();
1511                     RestorePstatToInitState();
1512                     OIC_LOG(WARNING, TAG, "DOXM will be reverted.");
1513                 }
1514             }
1515         }
1516         else
1517         {
1518             OIC_LOG(ERROR, TAG, "Invalid DOXM resource.");
1519         }
1520     }
1521     else
1522     {
1523         previousMsgId = ehRequest->messageID;
1524     }
1525
1526     //Send payload to request originator
1527     ehRet = ((SendSRMResponse(ehRequest, ehRet, NULL, 0)) == OC_STACK_OK) ?
1528                    OC_EH_OK : OC_EH_ERROR;
1529
1530     DeleteDoxmBinData(newDoxm);
1531
1532     return ehRet;
1533 }
1534
1535 OCEntityHandlerResult DoxmEntityHandler(OCEntityHandlerFlag flag,
1536                                         OCEntityHandlerRequest * ehRequest,
1537                                         void* callbackParam)
1538 {
1539     (void)callbackParam;
1540     OCEntityHandlerResult ehRet = OC_EH_ERROR;
1541
1542     if(NULL == ehRequest)
1543     {
1544         return ehRet;
1545     }
1546
1547     if (flag & OC_REQUEST_FLAG)
1548     {
1549         OIC_LOG(DEBUG, TAG, "Flag includes OC_REQUEST_FLAG");
1550
1551         switch (ehRequest->method)
1552         {
1553             case OC_REST_GET:
1554                 ehRet = HandleDoxmGetRequest(ehRequest);
1555                 break;
1556
1557             case OC_REST_POST:
1558                 ehRet = HandleDoxmPostRequest(ehRequest);
1559                 break;
1560
1561             default:
1562                 ehRet = ((SendSRMResponse(ehRequest, ehRet, NULL, 0)) == OC_STACK_OK) ?
1563                                OC_EH_OK : OC_EH_ERROR;
1564                 break;
1565         }
1566     }
1567
1568     return ehRet;
1569 }
1570
1571 OCStackResult CreateDoxmResource()
1572 {
1573     OCStackResult ret = OCCreateResource(&gDoxmHandle,
1574                                          OIC_RSRC_TYPE_SEC_DOXM,
1575                                          OC_RSRVD_INTERFACE_DEFAULT,
1576                                          OIC_RSRC_DOXM_URI,
1577                                          DoxmEntityHandler,
1578                                          NULL,
1579                                          OC_SECURE |
1580                                          OC_DISCOVERABLE);
1581
1582     if (OC_STACK_OK != ret)
1583     {
1584         OIC_LOG (FATAL, TAG, "Unable to instantiate Doxm resource");
1585         DeInitDoxmResource();
1586     }
1587     return ret;
1588 }
1589
1590 /**
1591  * Checks if DeviceID is generated during provisioning for the new device.
1592  * If DeviceID is NULL then generates the new DeviceID.
1593  * Once DeviceID is assigned to the device it does not change for the lifetime of the device.
1594  */
1595 static OCStackResult CheckDeviceID()
1596 {
1597     OCStackResult ret = OC_STACK_ERROR;
1598     bool validId = false;
1599
1600     for (uint8_t i = 0; i < UUID_LENGTH; i++)
1601     {
1602         if (gDoxm->deviceID.id[i] != 0)
1603         {
1604             validId = true;
1605             break;
1606         }
1607     }
1608
1609     if (!validId)
1610     {
1611         char* strUuid = NULL;
1612 #if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
1613         //If seed value is exists, generate UUID using seed with SHA256
1614         if (0 != gUuidSeedSize)
1615         {
1616             uint8_t hashVal[MBEDTLS_MD_MAX_SIZE] = {0};
1617             int mbedret = 0;
1618
1619             OIC_LOG(DEBUG, TAG, "UUID will be generated using seed w/ SHA256");
1620             OIC_LOG(DEBUG, TAG, "Seed value : ");
1621             OIC_LOG_BUFFER(DEBUG, TAG, gUuidSeed, gUuidSeedSize);
1622
1623             mbedret = mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA256),
1624                                  gUuidSeed, gUuidSeedSize, hashVal);
1625             if(0 == mbedret)
1626             {
1627                 memcpy(gDoxm->deviceID.id, hashVal, sizeof(gDoxm->deviceID.id));
1628                 ret = OC_STACK_OK;
1629             }
1630             else
1631             {
1632                 OIC_LOG_V(ERROR, TAG, "mbedtls_md error : %d", mbedret);
1633                 ret = OC_STACK_ERROR;
1634             }
1635         }
1636         else
1637         {
1638             if (!OCGenerateUuid(gDoxm->deviceID.id))
1639             {
1640                 OIC_LOG(FATAL, TAG, "Generate UUID for Server Instance failed!");
1641                 ret = OC_STACK_ERROR;
1642             }
1643             else
1644             {
1645                 ret = OC_STACK_OK;
1646             }
1647         }
1648 #else
1649         if (!OCGenerateUuid(gDoxm->deviceID.id))
1650         {
1651             OIC_LOG(FATAL, TAG, "Generate UUID for Server Instance failed!");
1652             ret = OC_STACK_ERROR;
1653         }
1654         else
1655         {
1656             ret = OC_STACK_OK;
1657         }
1658 #endif
1659
1660         if (OC_STACK_OK == ConvertUuidToStr(&gDoxm->deviceID, &strUuid))
1661         {
1662             OIC_LOG_V(DEBUG, TAG, "Generated device UUID is [%s]", strUuid);
1663             OICFree(strUuid);
1664         }
1665         else
1666         {
1667             OIC_LOG(WARNING, TAG, "Failed to convert UUID to string");
1668         }
1669
1670
1671         if (!UpdatePersistentStorage(gDoxm))
1672         {
1673             //TODO: After registering PSI handler in all samples, do ret = OC_STACK_OK here.
1674             OIC_LOG(FATAL, TAG, "UpdatePersistentStorage failed!");
1675         }
1676     }
1677     else
1678     {
1679         ret = OC_STACK_OK;
1680     }
1681
1682     return ret;
1683 }
1684
1685 /**
1686  * Get the default value.
1687  *
1688  * @return the default value of doxm, @ref OicSecDoxm_t.
1689  */
1690 static OicSecDoxm_t* GetDoxmDefault()
1691 {
1692     OIC_LOG(DEBUG, TAG, "GetDoxmToDefault");
1693     return &gDefaultDoxm;
1694 }
1695
1696 const OicSecDoxm_t* GetDoxmResourceData()
1697 {
1698     return gDoxm;
1699 }
1700
1701 #if defined(__WITH_DTLS__) && defined(MULTIPLE_OWNER)
1702 /**
1703  * Internal API to prepare MOT
1704  */
1705 static void PrepareMOT(const OicSecDoxm_t* doxm)
1706 {
1707     OIC_LOG(INFO, TAG, "IN PrepareMOT");
1708     VERIFY_NOT_NULL(TAG, doxm, ERROR);
1709
1710     if(true == doxm->owned && NULL != doxm->mom && OIC_MULTIPLE_OWNER_DISABLE != doxm->mom->mode)
1711     {
1712         CAResult_t caRes = CA_STATUS_FAILED;
1713
1714         OIC_LOG(INFO, TAG, "Multiple Ownership Transfer Enabled!");
1715
1716         if(OIC_PRECONFIG_PIN == doxm->oxmSel)
1717         {
1718             caRes = CAEnableAnonECDHCipherSuite(false);
1719             VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
1720             OIC_LOG(INFO, TAG, "ECDH_ANON CipherSuite is DISABLED");
1721
1722             RegisterOTMSslHandshakeCallback(DoxmDTLSHandshakeCB);
1723             caRes = CASelectCipherSuite((uint16_t)MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256, CA_ADAPTER_IP);
1724             VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
1725 #ifdef __WITH_TLS__
1726             caRes = CASelectCipherSuite((uint16_t)MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256, CA_ADAPTER_TCP);
1727             VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
1728 #endif
1729             OIC_LOG(INFO, TAG, "ECDHE_PSK CipherSuite will be used for MOT");
1730
1731             //Set the device id to derive temporal PSK
1732             SetUuidForPinBasedOxm(&doxm->deviceID);
1733         }
1734         else
1735         {
1736             OIC_LOG(ERROR, TAG, "Unsupported OxM for Multiple Ownership Transfer.");
1737             return;
1738         }
1739
1740         CAregisterSslHandshakeCallback(MultipleOwnerDTLSHandshakeCB);
1741     }
1742
1743     OIC_LOG(INFO, TAG, "OUT PrepareMOT");
1744     return;
1745 exit:
1746     OIC_LOG(WARNING, TAG, "Error in PrepareMOT");
1747 }
1748 #endif //defined(__WITH_DTLS__) && defined(MULTIPLE_OWNER)
1749
1750 OCStackResult InitDoxmResource()
1751 {
1752     OCStackResult ret = OC_STACK_ERROR;
1753
1754     //Read DOXM resource from PS
1755     uint8_t *data = NULL;
1756     size_t size = 0;
1757     ret = GetSecureVirtualDatabaseFromPS(OIC_JSON_DOXM_NAME, &data, &size);
1758     // If database read failed
1759     if (OC_STACK_OK != ret)
1760     {
1761        OIC_LOG (DEBUG, TAG, "ReadSVDataFromPS failed");
1762     }
1763     if (data)
1764     {
1765        // Read DOXM resource from PS
1766        ret = CBORPayloadToDoxm(data, size, &gDoxm);
1767     }
1768     /*
1769      * If SVR database in persistent storage got corrupted or
1770      * is not available for some reason, a default doxm is created
1771      * which allows user to initiate doxm provisioning again.
1772      */
1773      if ((OC_STACK_OK != ret) || !data || !gDoxm)
1774     {
1775         gDoxm = GetDoxmDefault();
1776     }
1777
1778     //In case of the server is shut down unintentionally, we should initialize the owner
1779     if(gDoxm && (false == gDoxm->owned))
1780     {
1781         OicUuid_t emptyUuid = {.id={0}};
1782         memcpy(&gDoxm->owner, &emptyUuid, sizeof(OicUuid_t));
1783     }
1784
1785     ret = CheckDeviceID();
1786     if (ret == OC_STACK_OK)
1787     {
1788         OIC_LOG_V(DEBUG, TAG, "Initial Doxm Owned = %d", gDoxm->owned);
1789         //Instantiate 'oic.sec.doxm'
1790         ret = CreateDoxmResource();
1791     }
1792     else
1793     {
1794         OIC_LOG (ERROR, TAG, "CheckDeviceID failed");
1795     }
1796     OICFree(data);
1797
1798 #if defined(__WITH_DTLS__) && defined(MULTIPLE_OWNER)
1799     //if MOT is enabled, MOT should be prepared.
1800     if(gDoxm && gDoxm->owned)
1801     {
1802         PrepareMOT(gDoxm);
1803     }
1804 #endif // defined(__WITH_DTLS__) && defined(MULTIPLE_OWNER)
1805
1806     return ret;
1807 }
1808
1809 OCStackResult DeInitDoxmResource()
1810 {
1811     OCStackResult ret = OCDeleteResource(gDoxmHandle);
1812     if (gDoxm  != &gDefaultDoxm)
1813     {
1814         DeleteDoxmBinData(gDoxm);
1815     }
1816     gDoxm = NULL;
1817
1818     if (OC_STACK_OK == ret)
1819     {
1820         return OC_STACK_OK;
1821     }
1822     else
1823     {
1824         return OC_STACK_ERROR;
1825     }
1826 }
1827
1828 OCStackResult GetDoxmDeviceID(OicUuid_t *deviceID)
1829 {
1830     if (deviceID && gDoxm)
1831     {
1832        *deviceID = gDoxm->deviceID;
1833         return OC_STACK_OK;
1834     }
1835     return OC_STACK_ERROR;
1836 }
1837
1838 OCStackResult GetDoxmIsOwned(bool *isOwned)
1839 {
1840     if (isOwned && gDoxm)
1841     {
1842        *isOwned = gDoxm->owned;
1843         return OC_STACK_OK;
1844     }
1845     return OC_STACK_ERROR;
1846 }
1847
1848 #if defined(__WITH_DTLS__) || defined (__WITH_TLS__)
1849 OCStackResult SetDoxmDeviceIDSeed(const uint8_t* seed, size_t seedSize)
1850 {
1851     OIC_LOG_V(INFO, TAG, "In %s", __func__);
1852
1853     if (NULL == seed)
1854     {
1855         return OC_STACK_INVALID_PARAM;
1856     }
1857     if (MAX_UUID_SEED_SIZE < seedSize)
1858     {
1859         OIC_LOG_V(ERROR, TAG, "Seed size is too long (MAX size is %d bytes)", MAX_UUID_SEED_SIZE);
1860         return OC_STACK_INVALID_PARAM;
1861     }
1862     if (MIN_UUID_SEED_SIZE > seedSize)
1863     {
1864         OIC_LOG_V(ERROR, TAG, "Seed size is too small (MIN size is %d bytes)", MIN_UUID_SEED_SIZE);
1865         return OC_STACK_INVALID_PARAM;
1866     }
1867
1868     memset(gUuidSeed, 0x00, sizeof(gUuidSeed));
1869     memcpy(gUuidSeed, seed, seedSize);
1870     gUuidSeedSize = seedSize;
1871
1872     OIC_LOG_V(INFO, TAG, "Out %s", __func__);
1873
1874     return OC_STACK_OK;
1875 }
1876 #endif
1877
1878 OCStackResult SetDoxmDeviceID(const OicUuid_t *deviceID)
1879 {
1880     bool isOwnerUpdated = false;
1881     bool isRownerUpdated = false;
1882     if (NULL == deviceID)
1883     {
1884         return OC_STACK_INVALID_PARAM;
1885     }
1886     if (NULL == gDoxm)
1887     {
1888         OIC_LOG(ERROR, TAG, "Doxm resource is not initialized.");
1889         return OC_STACK_NO_RESOURCE;
1890     }
1891
1892 #ifdef __WITH_DTLS__
1893     //for normal device.
1894     if (true == gDoxm->owned &&
1895         memcmp(gDoxm->deviceID.id, gDoxm->owner.id, sizeof(gDoxm->owner.id)) != 0)
1896     {
1897         OIC_LOG(ERROR, TAG, "This device owned by owner's device.");
1898         OIC_LOG(ERROR, TAG, "Device UUID cannot be changed to guarantee the reliability of the connection.");
1899         return OC_STACK_ERROR;
1900     }
1901 #endif //__WITH_DTLS
1902
1903     //Save the previous UUID
1904     OicUuid_t prevUuid;
1905     memcpy(prevUuid.id, gDoxm->deviceID.id, sizeof(prevUuid.id));
1906
1907     //Change the device UUID
1908     memcpy(gDoxm->deviceID.id, deviceID->id, sizeof(deviceID->id));
1909
1910     //Change the owner ID if necessary
1911     if (memcmp(gDoxm->owner.id, prevUuid.id, sizeof(prevUuid.id)) == 0)
1912     {
1913         memcpy(gDoxm->owner.id, deviceID->id, sizeof(deviceID->id));
1914         isOwnerUpdated = true;
1915     }
1916     //Change the resource owner ID if necessary
1917     if (memcmp(gDoxm->rownerID.id, prevUuid.id, sizeof(prevUuid.id)) == 0)
1918     {
1919         memcpy(gDoxm->rownerID.id, deviceID->id, sizeof(deviceID->id));
1920         isRownerUpdated = true;
1921     }
1922     // TODO: T.B.D Change resource owner for pstat, acl and cred
1923
1924     //Update PS
1925     if (!UpdatePersistentStorage(gDoxm))
1926     {
1927         //revert UUID in case of PSI error
1928         memcpy(gDoxm->deviceID.id, prevUuid.id, sizeof(prevUuid.id));
1929         if (isOwnerUpdated)
1930         {
1931             memcpy(gDoxm->owner.id, prevUuid.id, sizeof(prevUuid.id));
1932         }
1933         if (isRownerUpdated)
1934         {
1935             memcpy(gDoxm->rownerID.id, prevUuid.id, sizeof(prevUuid.id));
1936         }
1937         // TODO: T.B.D Revert resource owner for pstat, acl and cred
1938
1939         OIC_LOG(ERROR, TAG, "Failed to update persistent storage");
1940         return OC_STACK_ERROR;
1941     }
1942     return OC_STACK_OK;
1943 }
1944
1945 OCStackResult GetDoxmDevOwnerId(OicUuid_t *devownerid)
1946 {
1947     OCStackResult retVal = OC_STACK_ERROR;
1948     if (gDoxm)
1949     {
1950         OIC_LOG_V(DEBUG, TAG, "GetDoxmDevOwnerId(): gDoxm owned =  %d.", \
1951             gDoxm->owned);
1952         if (gDoxm->owned)
1953         {
1954             *devownerid = gDoxm->owner;
1955             retVal = OC_STACK_OK;
1956         }
1957     }
1958     return retVal;
1959 }
1960
1961 OCStackResult GetDoxmRownerId(OicUuid_t *rowneruuid)
1962 {
1963     OCStackResult retVal = OC_STACK_ERROR;
1964     if (gDoxm)
1965     {
1966         if( gDoxm->owned )
1967         {
1968             *rowneruuid = gDoxm->rownerID;
1969                     retVal = OC_STACK_OK;
1970         }
1971     }
1972     return retVal;
1973 }
1974
1975 #ifdef MULTIPLE_OWNER
1976 /**
1977  * Compare the UUID to SubOwner.
1978  *
1979  * @param[in] uuid device UUID
1980  *
1981  * @return true if context->subjectId exist subowner list, else false.
1982  */
1983 bool IsSubOwner(const OicUuid_t* uuid)
1984 {
1985     bool retVal = false;
1986
1987     if (NULL == uuid)
1988     {
1989         return retVal;
1990     }
1991
1992     if (gDoxm && gDoxm->subOwners)
1993     {
1994         if (memcmp(gDoxm->owner.id, uuid->id, sizeof(gDoxm->owner.id)) == 0)
1995         {
1996             return false;
1997         }
1998
1999         OicSecSubOwner_t* subOwner = NULL;
2000         LL_FOREACH(gDoxm->subOwners, subOwner)
2001         {
2002             if (memcmp(subOwner->uuid.id, uuid->id, sizeof(uuid->id)) == 0)
2003             {
2004                 return true;
2005             }
2006         }
2007     }
2008     return retVal;
2009 }
2010
2011 OCStackResult SetMOTStatus(bool enable)
2012 {
2013     OCStackResult ret = OC_STACK_NO_MEMORY;
2014     uint8_t *cborPayload = NULL;
2015     size_t size = 0;
2016     bool isDeallocateRequired = false;
2017
2018     OIC_LOG_V(DEBUG, TAG, "In %s", __func__);
2019
2020     if (NULL == gDoxm->mom && !enable)
2021     {
2022         OIC_LOG_V(DEBUG, TAG, "Out %s", __func__);
2023         return OC_STACK_OK;
2024     }
2025
2026     if (NULL == gDoxm->mom)
2027     {
2028         gDoxm->mom = (OicSecMom_t*)OICCalloc(1, sizeof(OicSecMom_t));
2029         VERIFY_NOT_NULL(TAG, gDoxm->mom, ERROR);
2030         isDeallocateRequired = true;
2031     }
2032
2033     gDoxm->mom->mode = (enable ? OIC_MULTIPLE_OWNER_ENABLE : OIC_MULTIPLE_OWNER_DISABLE);
2034
2035     ret = DoxmToCBORPayload(gDoxm, &cborPayload, &size, false);
2036     VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
2037
2038     ret = UpdateSecureResourceInPS(OIC_JSON_DOXM_NAME, cborPayload, size);
2039     VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
2040
2041     isDeallocateRequired = false;
2042
2043 exit:
2044     if (isDeallocateRequired)
2045     {
2046         OICFree(gDoxm->mom);
2047     }
2048     OICFree(cborPayload);
2049     OIC_LOG_V(DEBUG, TAG, "Out %s : %d", __func__, ret);
2050     return ret;
2051 }
2052
2053 #endif //MULTIPLE_OWNER
2054
2055 /**
2056  * Function to restore doxm resurce to initial status.
2057  * This function will use in case of error while ownership transfer
2058  */
2059 void RestoreDoxmToInitState()
2060 {
2061     if(gDoxm)
2062     {
2063         OIC_LOG(INFO, TAG, "DOXM resource will revert back to initial status.");
2064
2065         OicUuid_t emptyUuid = {.id={0}};
2066         memcpy(&(gDoxm->owner), &emptyUuid, sizeof(OicUuid_t));
2067         gDoxm->owned = false;
2068         gDoxm->oxmSel = OIC_JUST_WORKS;
2069
2070         if(!UpdatePersistentStorage(gDoxm))
2071         {
2072             OIC_LOG(ERROR, TAG, "Failed to revert DOXM in persistent storage");
2073         }
2074     }
2075 }
2076
2077 OCStackResult SetDoxmSelfOwnership(const OicUuid_t* newROwner)
2078 {
2079     OCStackResult ret = OC_STACK_ERROR;
2080     uint8_t *cborPayload = NULL;
2081     size_t size = 0;
2082
2083     if(NULL == gDoxm)
2084     {
2085         ret = OC_STACK_NO_RESOURCE;
2086         return ret;
2087     }
2088
2089     if( newROwner && (false == gDoxm->owned) )
2090     {
2091         gDoxm->owned = true;
2092         memcpy(gDoxm->owner.id, newROwner->id, sizeof(newROwner->id));
2093         memcpy(gDoxm->rownerID.id, newROwner->id, sizeof(newROwner->id));
2094
2095         ret = DoxmToCBORPayload(gDoxm, &cborPayload, &size, false);
2096         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
2097
2098         ret = UpdateSecureResourceInPS(OIC_JSON_DOXM_NAME, cborPayload, size);
2099         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
2100
2101         OICFree(cborPayload);
2102     }
2103
2104     return ret;
2105
2106 exit:
2107     OICFree(cborPayload);
2108     return ret;
2109 }
2110
2111 #ifdef MULTIPLE_OWNER
2112 /** This function checks if two sets of /oic/sec/doxm MOT-specific properties are identical.
2113  *
2114  * @param doxm1 is a pointer to the first @ref OicSecDoxm_t data.
2115  * @param doxm2 is a pointer to the second @ref OicSecDoxm_t data.
2116  *
2117  * @return true if all of the properties are identical, else false.
2118  */
2119 static bool AreDoxmBinMOTPropertyValuesEqual(OicSecDoxm_t* doxm1, OicSecDoxm_t* doxm2)
2120 {
2121     //Compare the subOwners lists.
2122     OicSecSubOwner_t* subOwner1 = doxm1->subOwners;
2123     OicSecSubOwner_t* subOwner2 = doxm2->subOwners;
2124
2125     for (;;)
2126     {
2127         if ((NULL == subOwner1) && (NULL == subOwner2))
2128         {
2129             //Reached the end of both lists, so the two lists were identical.
2130             break;
2131         }
2132
2133         if ((NULL != subOwner1) && (NULL != subOwner2))
2134         {
2135             if (0 != memcmp(&subOwner1->uuid, &subOwner2->uuid, sizeof(subOwner1->uuid)))
2136             {
2137                 OIC_LOG_V(ERROR, TAG, "%s: subOwner uuid mismatch", __func__);
2138                 return false;
2139             }
2140
2141             if (subOwner1->status != subOwner2->status)
2142             {
2143                 OIC_LOG_V(ERROR, TAG, "%s: subOwner status mismatch: (%u, %u)",
2144                     __func__, (uint32_t)subOwner1->status, (uint32_t)subOwner2->status);
2145                 return false;
2146             }
2147
2148             //Go to the next elements from the two lists.
2149             subOwner1 = subOwner1->next;
2150             subOwner2 = subOwner2->next;
2151             continue;
2152         }
2153
2154         OIC_LOG_V(ERROR, TAG, "%s: subOwner list length mismatch", __func__);
2155         return false;
2156     }
2157
2158     // Compare the mom values.
2159     if (NULL == doxm1->mom)
2160     {
2161         if (NULL != doxm2->mom)
2162         {
2163             OIC_LOG_V(ERROR, TAG, "%s: doxm1->mom is NULL", __func__);
2164             return false;
2165         }
2166
2167         return true;
2168     }
2169
2170     if (NULL == doxm2->mom)
2171     {
2172         OIC_LOG_V(ERROR, TAG, "%s: doxm2->mom is NULL", __func__);
2173         return false;
2174     }
2175
2176     if (doxm1->mom->mode != doxm2->mom->mode)
2177     {
2178         OIC_LOG_V(ERROR, TAG, "%s: mom->mode mismatch: (%u, %u)",
2179             __func__, (uint32_t)doxm1->mom->mode, (uint32_t)doxm2->mom->mode);
2180         return false;
2181     }
2182
2183     return true;
2184 }
2185 #endif //#ifdef MULTIPLE_OWNER
2186
2187 bool AreDoxmBinPropertyValuesEqual(OicSecDoxm_t* doxm1, OicSecDoxm_t* doxm2)
2188 {
2189     if (NULL == doxm1 || NULL == doxm2)
2190     {
2191         OIC_LOG_V(ERROR, TAG, "%s: unxpected NULL doxm pointer", __func__);
2192         return false;
2193     }
2194
2195     //Compare the contents of the oxmType array and its length oxmTypeLen.
2196     size_t arrayLength = doxm1->oxmTypeLen;
2197
2198     if (arrayLength != doxm2->oxmTypeLen)
2199     {
2200         OIC_LOG_V(ERROR, TAG, "%s: oxmTypeLen mismatch: (%" PRIuPTR ", %" PRIuPTR ")",
2201             __func__, arrayLength, doxm2->oxmTypeLen);
2202         return false;
2203     }
2204
2205     for (size_t i = 0; i < arrayLength; i++)
2206     {
2207         if (NULL == doxm1->oxmType[i] || NULL == doxm2->oxmType[i])
2208         {
2209             OIC_LOG_V(ERROR, TAG, "%s: unexpected NULL found in the oxmType array",
2210                 __func__);
2211             return false;
2212         }
2213
2214         if (0 != strcmp(doxm1->oxmType[i], doxm2->oxmType[i]))
2215         {
2216             OIC_LOG_V(ERROR, TAG, "%s: oxmType mismatch: (%s, %s)",
2217                 __func__, doxm1->oxmType[i], doxm2->oxmType[i]);
2218             return false;
2219         }
2220     }
2221
2222     //Compare the contents of the oxm array and its length oxmLen.
2223     arrayLength = doxm1->oxmLen;
2224
2225     if (arrayLength != doxm2->oxmLen)
2226     {
2227         OIC_LOG_V(ERROR, TAG, "%s: oxmLen mismatch: (%" PRIuPTR ", %" PRIuPTR ")",
2228             __func__, arrayLength, doxm2->oxmLen);
2229         return false;
2230     }
2231
2232     for (size_t i = 0; i < arrayLength; i++)
2233     {
2234         if (doxm1->oxm[i] != doxm2->oxm[i])
2235         {
2236             OIC_LOG_V(ERROR, TAG, "%s: oxmType mismatch: (%u, %u)",
2237                 __func__, (uint32_t)doxm1->oxm[i], (uint32_t)doxm2->oxm[i]);
2238             return false;
2239         }
2240     }
2241
2242     //Compare the remaining property values.
2243     if (doxm1->oxmSel != doxm2->oxmSel)
2244     {
2245         OIC_LOG_V(ERROR, TAG, "%s: oxmSel mismatch: (%u, %u)",
2246             __func__, (uint32_t)doxm1->oxmSel, (uint32_t)doxm2->oxmSel);
2247         return false;
2248     }
2249
2250     if (doxm1->sct != doxm2->sct)
2251     {
2252         OIC_LOG_V(ERROR, TAG, "%s: sct mismatch: (%u, %u)",
2253             __func__, (uint32_t)doxm1->sct, (uint32_t)doxm2->sct);
2254         return false;
2255     }
2256
2257     if (doxm1->owned != doxm2->owned)
2258     {
2259         OIC_LOG_V(ERROR, TAG, "%s: owned mismatch: (%u, %u)",
2260             __func__, (uint32_t)doxm1->owned, (uint32_t)doxm2->owned);
2261         return false;
2262     }
2263
2264     if (0 != memcmp(&doxm1->deviceID, &doxm2->deviceID, sizeof(doxm1->deviceID)))
2265     {
2266         OIC_LOG_V(ERROR, TAG, "%s: deviceID mismatch", __func__);
2267         return false;
2268     }
2269
2270     if (doxm1->dpc != doxm2->dpc)
2271     {
2272         OIC_LOG_V(ERROR, TAG, "%s: dpc mismatch: (%u, %u)",
2273             __func__, (uint32_t)doxm1->dpc, (uint32_t)doxm2->dpc);
2274         return false;
2275     }
2276
2277     if (0 != memcmp(&doxm1->owner, &doxm2->owner, sizeof(doxm1->owner)))
2278     {
2279         OIC_LOG_V(ERROR, TAG, "%s: owner mismatch", __func__);
2280         return false;
2281     }
2282
2283     if (0 != memcmp(&doxm1->rownerID, &doxm2->rownerID, sizeof(doxm1->rownerID)))
2284     {
2285         OIC_LOG_V(ERROR, TAG, "%s: rownerID mismatch", __func__);
2286         return false;
2287     }
2288
2289 #ifdef MULTIPLE_OWNER
2290     return AreDoxmBinMOTPropertyValuesEqual(doxm1, doxm2);
2291 #else
2292     return true;
2293 #endif
2294 }