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