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