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