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