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