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