1e8d5446a966588bf31f6fb4b9e3a879626848c1
[platform/upstream/iotivity.git] / resource / csdk / security / src / pstatresource.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 <stdlib.h>
22 #include <string.h>
23
24 #include "ocstack.h"
25 #include "oic_malloc.h"
26 #include "ocpayload.h"
27 #include "ocpayloadcbor.h"
28 #include "payload_logging.h"
29 #include "resourcemanager.h"
30 #include "pstatresource.h"
31 #include "doxmresource.h"
32 #include "psinterface.h"
33 #include "srmresourcestrings.h"
34 #include "srmutility.h"
35 #include "aclresource.h"
36 #include "credresource.h"
37 #include "ocprovisioningmanager.h"
38
39 #define TAG  "OIC_SRM_PSTAT"
40
41 /** Default cbor payload size. This value is increased in case of CborErrorOutOfMemory.
42  * The value of payload size is increased until reaching below max cbor size. */
43 static const uint16_t CBOR_SIZE = 512;
44
45 // Max cbor size payload.
46 static const uint16_t CBOR_MAX_SIZE = 4400;
47
48 // PSTAT Map size - Number of mandatory items
49 static const uint8_t PSTAT_MAP_SIZE = 6;
50
51 // Number of writeable property
52 static const uint8_t WRITEABLE_PROPERTY_SIZE = 3;
53
54 static OicSecDpom_t gSm = SINGLE_SERVICE_CLIENT_DRIVEN;
55 static OicSecPstat_t gDefaultPstat =
56 {
57     false,                                    // bool isop
58     (OicSecDpm_t)(BOOTSTRAP_SERVICE | SECURITY_MANAGEMENT_SERVICES |
59     PROVISION_CREDENTIALS | PROVISION_ACLS),   // OicSecDpm_t cm
60     (OicSecDpm_t)(TAKE_OWNER | BOOTSTRAP_SERVICE | SECURITY_MANAGEMENT_SERVICES |
61     PROVISION_CREDENTIALS | PROVISION_ACLS),   // OicSecDpm_t tm
62     {.id = {0}},                              // OicUuid_t deviceID
63     SINGLE_SERVICE_CLIENT_DRIVEN,             // OicSecDpom_t om */
64     1,                                        // the number of elts in Sms
65     &gSm,                                     // OicSecDpom_t *sm
66     0,                                        // uint16_t commitHash
67     {.id = {0}},                              // OicUuid_t rownerID
68 };
69
70 static OicSecPstat_t    *gPstat = NULL;
71
72 static OCResourceHandle gPstatHandle = NULL;
73
74 /**
75  * This method is internal method.
76  * the param roParsed is optionally used to know whether cborPayload has
77  * at least read only property value or not.
78  */
79 static OCStackResult CBORPayloadToPstatBin(const uint8_t *cborPayload, const size_t size,
80                                  OicSecPstat_t **secPstat, bool *roParsed);
81
82 void DeletePstatBinData(OicSecPstat_t* pstat)
83 {
84     if (pstat)
85     {
86         //Clean 'supported modes' field
87         OICFree(pstat->sm);
88
89         //Clean pstat itself
90         OICFree(pstat);
91     }
92 }
93
94 OCStackResult PstatToCBORPayload(const OicSecPstat_t *pstat, uint8_t **payload, size_t *size,
95                                  bool writableOnly)
96 {
97     if (NULL == pstat || NULL == payload || NULL != *payload || NULL == size)
98     {
99         return OC_STACK_INVALID_PARAM;
100     }
101
102     size_t cborLen = *size;
103     if (0 == cborLen)
104     {
105         cborLen = CBOR_SIZE;
106     }
107
108     *payload = NULL;
109     *size = 0;
110
111     OCStackResult ret = OC_STACK_ERROR;
112     size_t pstatMapSize = PSTAT_MAP_SIZE;
113     CborEncoder encoder;
114     CborEncoder pstatMap;
115     char* strUuid = NULL;
116
117     int64_t cborEncoderResult = CborNoError;
118
119     uint8_t *outPayload = (uint8_t *)OICCalloc(1, cborLen);
120     VERIFY_NON_NULL(TAG, outPayload, ERROR);
121     cbor_encoder_init(&encoder, outPayload, cborLen, 0);
122
123     if (false == writableOnly)
124     {
125         pstatMapSize += WRITEABLE_PROPERTY_SIZE;
126     }
127
128     cborEncoderResult = cbor_encoder_create_map(&encoder, &pstatMap, pstatMapSize);
129     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Pstat Map.");
130
131     cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_ISOP_NAME,
132         strlen(OIC_JSON_ISOP_NAME));
133     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ISOP Name Tag.");
134     cborEncoderResult = cbor_encode_boolean(&pstatMap, pstat->isOp);
135     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ISOP Name Value.");
136
137     cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_CM_NAME,
138         strlen(OIC_JSON_CM_NAME));
139     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding CM Name Tag.");
140     cborEncoderResult = cbor_encode_int(&pstatMap, pstat->cm);
141     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding CM Name Value.");
142
143     cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_TM_NAME,
144         strlen(OIC_JSON_TM_NAME));
145     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding TM Name Tag.");
146     cborEncoderResult = cbor_encode_int(&pstatMap, pstat->tm);
147     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding TM Name Value.");
148
149     cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_OM_NAME,
150         strlen(OIC_JSON_OM_NAME));
151     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding OM Name Tag.");
152     cborEncoderResult = cbor_encode_int(&pstatMap, pstat->om);
153     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding OM Name Value.");
154
155     if (false == writableOnly)
156     {
157         cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_SM_NAME,
158             strlen(OIC_JSON_SM_NAME));
159         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding SM Name Tag.");
160         cborEncoderResult = cbor_encode_int(&pstatMap, pstat->sm[0]);
161         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding SM Name Value.");
162
163         cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_DEVICE_ID_NAME,
164             strlen(OIC_JSON_DEVICE_ID_NAME));
165         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Device Id Tag.");
166         ret = ConvertUuidToStr(&pstat->deviceID, &strUuid);
167         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret , ERROR);
168         cborEncoderResult = cbor_encode_text_string(&pstatMap, strUuid, strlen(strUuid));
169         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Device Id Value.");
170         OICFree(strUuid);
171         strUuid = NULL;
172
173         cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_ROWNERID_NAME,
174             strlen(OIC_JSON_ROWNERID_NAME));
175         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ROwner Id Tag.");
176         ret = ConvertUuidToStr(&pstat->rownerID, &strUuid);
177         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret , ERROR);
178         cborEncoderResult = cbor_encode_text_string(&pstatMap, strUuid, strlen(strUuid));
179         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ROwner Id Value.");
180         OICFree(strUuid);
181         strUuid = NULL;
182     }
183
184     //RT -- Mandatory
185     CborEncoder rtArray;
186     cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_RT_NAME,
187             strlen(OIC_JSON_RT_NAME));
188     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding RT Name Tag.");
189     cborEncoderResult = cbor_encoder_create_array(&pstatMap, &rtArray, 1);
190     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding RT Value.");
191     for (size_t i = 0; i < 1; i++)
192     {
193         cborEncoderResult = cbor_encode_text_string(&rtArray, OIC_RSRC_TYPE_SEC_PSTAT,
194                 strlen(OIC_RSRC_TYPE_SEC_PSTAT));
195         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding RT Value.");
196     }
197     cborEncoderResult = cbor_encoder_close_container(&pstatMap, &rtArray);
198     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing RT.");
199
200     //IF-- Mandatory
201      CborEncoder ifArray;
202      cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_IF_NAME,
203              strlen(OIC_JSON_IF_NAME));
204      VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding IF Name Tag.");
205      cborEncoderResult = cbor_encoder_create_array(&pstatMap, &ifArray, 1);
206      VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding IF Value.");
207     for (size_t i = 0; i < 1; i++)
208     {
209         cborEncoderResult = cbor_encode_text_string(&ifArray, OC_RSRVD_INTERFACE_DEFAULT,
210                 strlen(OC_RSRVD_INTERFACE_DEFAULT));
211         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding IF Value.");
212     }
213     cborEncoderResult = cbor_encoder_close_container(&pstatMap, &ifArray);
214     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing IF.");
215
216     cborEncoderResult = cbor_encoder_close_container(&encoder, &pstatMap);
217     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Closing PSTAT Map.");
218
219     if (CborNoError == cborEncoderResult)
220     {
221         *size = cbor_encoder_get_buffer_size(&encoder, outPayload);
222         *payload = outPayload;
223         ret = OC_STACK_OK;
224     }
225 exit:
226     if ((CborErrorOutOfMemory == cborEncoderResult) && (cborLen < CBOR_MAX_SIZE))
227     {
228         // reallocate and try again!
229         OICFree(outPayload);
230         outPayload = NULL;
231         // Since the allocated initial memory failed, double the memory.
232         cborLen += cbor_encoder_get_buffer_size(&encoder, encoder.end);
233         cborEncoderResult = CborNoError;
234         ret = PstatToCBORPayload(pstat, payload, &cborLen, writableOnly);
235         if (OC_STACK_OK == ret)
236         {
237             *size = cborLen;
238         }
239     }
240
241     if ((CborNoError != cborEncoderResult) || (OC_STACK_OK != ret))
242     {
243         OICFree(outPayload);
244         outPayload = NULL;
245         *payload = NULL;
246         *size = 0;
247         ret = OC_STACK_ERROR;
248     }
249
250     return ret;
251 }
252
253 OCStackResult CBORPayloadToPstat(const uint8_t *cborPayload, const size_t size,
254                                  OicSecPstat_t **secPstat)
255 {
256     return CBORPayloadToPstatBin(cborPayload, size, secPstat, NULL);
257 }
258
259 static OCStackResult CBORPayloadToPstatBin(const uint8_t *cborPayload, const size_t size,
260                                  OicSecPstat_t **secPstat, bool *roParsed)
261 {
262     if (NULL == cborPayload || NULL == secPstat || NULL != *secPstat || 0 == size)
263     {
264         return OC_STACK_INVALID_PARAM;
265     }
266
267     OCStackResult ret = OC_STACK_ERROR;
268     *secPstat = NULL;
269
270     CborValue pstatCbor;
271     CborParser parser;
272     CborError cborFindResult = CborNoError;
273     char *strUuid = NULL;
274     size_t len = 0;
275
276     cbor_parser_init(cborPayload, size, 0, &parser, &pstatCbor);
277     CborValue pstatMap = { .parser = NULL };
278
279     OicSecPstat_t *pstat = NULL;
280     cborFindResult = cbor_value_enter_container(&pstatCbor, &pstatMap);
281     VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding PSTAT Map.");
282
283     pstat = (OicSecPstat_t *)OICCalloc(1, sizeof(OicSecPstat_t));
284     VERIFY_NON_NULL(TAG, pstat, ERROR);
285
286     cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_ISOP_NAME, &pstatMap);
287     if (CborNoError == cborFindResult && cbor_value_is_boolean(&pstatMap))
288     {
289         cborFindResult = cbor_value_get_boolean(&pstatMap, &pstat->isOp);
290         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding isOp Value.");
291     }
292     else
293     {
294         pstat->isOp = gPstat->isOp;
295         cborFindResult = CborNoError;
296     }
297
298     cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_DEVICE_ID_NAME, &pstatMap);
299     if (CborNoError == cborFindResult && cbor_value_is_text_string(&pstatMap))
300     {
301         cborFindResult = cbor_value_dup_text_string(&pstatMap, &strUuid , &len, NULL);
302         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding Device Id Value.");
303         ret = ConvertStrToUuid(strUuid , &pstat->deviceID);
304         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
305         OICFree(strUuid );
306         strUuid  = NULL;
307
308     }
309     else
310     {
311         memcpy(&pstat->deviceID, &gPstat->deviceID, sizeof(OicUuid_t));
312         cborFindResult = CborNoError;
313     }
314
315     cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_CM_NAME, &pstatMap);
316     if (CborNoError == cborFindResult && cbor_value_is_integer(&pstatMap))
317     {
318         int cm;
319
320         cborFindResult = cbor_value_get_int(&pstatMap, &cm);
321         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding CM.");
322         pstat->cm = (OicSecDpm_t)cm;
323     }
324     else
325     {
326         pstat->cm = gPstat->cm;
327         cborFindResult = CborNoError;
328     }
329
330     cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_TM_NAME, &pstatMap);
331     if (CborNoError == cborFindResult && cbor_value_is_integer(&pstatMap))
332     {
333         int tm;
334
335         cborFindResult = cbor_value_get_int(&pstatMap, &tm);
336         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding TM.");
337         pstat->tm = (OicSecDpm_t)tm;
338     }
339     else
340     {
341         pstat->tm = gPstat->tm;
342         cborFindResult = CborNoError;
343     }
344
345     cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_OM_NAME, &pstatMap);
346     if (CborNoError == cborFindResult && cbor_value_is_integer(&pstatMap))
347     {
348         int om;
349
350         cborFindResult = cbor_value_get_int(&pstatMap, &om);
351         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding OM.");
352         pstat->om = (OicSecDpom_t)om;
353     }
354     else
355     {
356         pstat->om = gPstat->om;
357         cborFindResult = CborNoError;
358     }
359
360     cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_SM_NAME, &pstatMap);
361     if (CborNoError == cborFindResult && cbor_value_is_integer(&pstatMap))
362     {
363         int sm;
364
365         pstat->smLen = 1;
366         pstat->sm = (OicSecDpom_t*)OICCalloc(pstat->smLen, sizeof(OicSecDpom_t));
367         VERIFY_NON_NULL(TAG, pstat->sm, ERROR);
368         cborFindResult = cbor_value_get_int(&pstatMap, &sm);
369         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding SM.");
370         pstat->sm[0] = (OicSecDpom_t)sm;
371
372         if (roParsed)
373         {
374             *roParsed = true;
375         }
376     }
377     else
378     {
379         VERIFY_NON_NULL(TAG, gPstat, ERROR);
380         pstat->smLen = gPstat->smLen;
381         pstat->sm = (OicSecDpom_t*)OICCalloc(pstat->smLen, sizeof(OicSecDpom_t));
382         VERIFY_NON_NULL(TAG, pstat->sm, ERROR);
383         *pstat->sm = *gPstat->sm;
384         cborFindResult = CborNoError;
385     }
386
387     cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_ROWNERID_NAME, &pstatMap);
388     if (CborNoError == cborFindResult && cbor_value_is_text_string(&pstatMap))
389     {
390         cborFindResult = cbor_value_dup_text_string(&pstatMap, &strUuid , &len, NULL);
391         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding ROwner Id Value.");
392         ret = ConvertStrToUuid(strUuid , &pstat->rownerID);
393         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
394         OICFree(strUuid );
395         strUuid  = NULL;
396     }
397     else
398     {
399         VERIFY_NON_NULL(TAG, gPstat, ERROR);
400         memcpy(pstat->rownerID.id, gPstat->rownerID.id, sizeof(gPstat->rownerID.id));
401         cborFindResult = CborNoError;
402     }
403
404     *secPstat = pstat;
405     ret = OC_STACK_OK;
406
407 exit:
408     if (CborNoError != cborFindResult)
409     {
410         OIC_LOG(ERROR, TAG, "CBORPayloadToPstat failed");
411         DeletePstatBinData(pstat);
412         pstat = NULL;
413         *secPstat = NULL;
414         ret = OC_STACK_ERROR;
415     }
416
417     return ret;
418 }
419
420 /**
421  * Function to update persistent storage
422  */
423 static bool UpdatePersistentStorage(OicSecPstat_t *pstat)
424 {
425     bool bRet = false;
426
427     size_t size = 0;
428     uint8_t *cborPayload = NULL;
429     OCStackResult ret = PstatToCBORPayload(pstat, &cborPayload, &size, false);
430     if (OC_STACK_OK == ret)
431     {
432         if (OC_STACK_OK == UpdateSecureResourceInPS(OIC_JSON_PSTAT_NAME, cborPayload, size))
433         {
434             bRet = true;
435         }
436         OICFree(cborPayload);
437     }
438
439     return bRet;
440 }
441
442 static bool ValidateQuery(const char * query)
443 {
444     OIC_LOG (DEBUG, TAG, "In ValidateQuery");
445     if(NULL == gPstat)
446     {
447         return false;
448     }
449
450     bool bInterfaceQry = false;      // does querystring contains 'if' query ?
451     bool bInterfaceMatch = false;    // does 'if' query matches with oic.if.baseline ?
452
453     OicParseQueryIter_t parseIter = {.attrPos = NULL};
454
455     ParseQueryIterInit((unsigned char*)query, &parseIter);
456
457     while (GetNextQuery(&parseIter))
458     {
459         if (strncasecmp((char *)parseIter.attrPos, OC_RSRVD_INTERFACE, parseIter.attrLen) == 0)
460         {
461             bInterfaceQry = true;
462             if ((strncasecmp((char *)parseIter.valPos, OC_RSRVD_INTERFACE_DEFAULT, parseIter.valLen) == 0))
463             {
464                 bInterfaceMatch = true;
465             }
466         }
467     }
468     return (bInterfaceQry ? bInterfaceMatch: true);
469 }
470
471 #ifdef MULTIPLE_OWNER
472 bool IsValidPstatAccessForSubOwner(const uint8_t *cborPayload, size_t size)
473 {
474     OicSecPstat_t* pstat = NULL;
475     bool isValidPstat = true;
476
477     OIC_LOG_BUFFER(DEBUG, TAG, cborPayload, size);
478     VERIFY_NON_NULL(TAG, cborPayload, ERROR);
479     VERIFY_SUCCESS(TAG, 0 != size, ERROR);
480     VERIFY_SUCCESS(TAG, OC_STACK_OK == CBORPayloadToPstat(cborPayload, size, &pstat), ERROR);
481     VERIFY_NON_NULL(TAG, pstat, ERROR);
482
483     if (RESET & pstat->cm)
484     {
485         OIC_LOG(ERROR, TAG, "SubOwner can't reset the server.");
486         isValidPstat = false;
487     }
488
489 exit:
490     DeletePstatBinData(pstat);
491     return isValidPstat;
492 }
493 #endif //MULTIPLE_OWNER
494
495 /**
496  * The entity handler determines how to process a GET request.
497  */
498 static OCEntityHandlerResult HandlePstatGetRequest (const OCEntityHandlerRequest * ehRequest)
499 {
500     OCEntityHandlerResult ehRet = OC_EH_OK;
501
502     OIC_LOG(INFO, TAG, "HandlePstatGetRequest  processing GET request");
503
504     //Checking if Get request is a query.
505     if (ehRequest->query)
506     {
507         OIC_LOG_V(DEBUG,TAG,"query:%s",ehRequest->query);
508         OIC_LOG(DEBUG, TAG, "HandlePstatGetRequest processing query");
509         if (!ValidateQuery(ehRequest->query))
510         {
511             ehRet = OC_EH_ERROR;
512         }
513     }
514
515     /*
516      * For GET or Valid Query request return doxm resource CBOR payload.
517      * For non-valid query return NULL json payload.
518      * A device will 'always' have a default Pstat, so PstatToCBORPayload will
519      * return valid pstat resource json.
520      */
521     size_t size = 0;
522     uint8_t *payload = NULL;
523     if (ehRet == OC_EH_OK)
524     {
525         if(OC_STACK_OK != PstatToCBORPayload(gPstat, &payload, &size, false))
526         {
527             OIC_LOG(WARNING, TAG, "PstatToCBORPayload failed in HandlePstatGetRequest");
528         }
529     }
530
531     // Send response payload to request originator
532     ehRet = ((SendSRMResponse(ehRequest, ehRet, payload, size)) == OC_STACK_OK) ?
533                    OC_EH_OK : OC_EH_ERROR;
534     OICFree(payload);
535     return ehRet;
536 }
537
538 /**
539  * Checks if device can change state to Ready for Normal Operation.
540  */
541 static OCEntityHandlerResult ValidateReadyForNOP(const OicSecPstat_t *pstat)
542 {
543     OIC_LOG_V(DEBUG, TAG, "%s: IN", __func__);
544
545     const OicSecDoxm_t *doxm = GetDoxmResourceData();
546     OicUuid_t rowneruuid;
547
548     if (!doxm)
549     {
550         OIC_LOG(WARNING, TAG, "DOXM is NULL");
551         return OC_EH_NOT_ACCEPTABLE;
552     }
553
554     if (!doxm->owned)
555     {
556         OIC_LOG(WARNING, TAG, "Can't change state to Ready for Normal Operation: the device is unowned");
557         return OC_EH_NOT_ACCEPTABLE;
558     }
559
560     if (IsNilUuid(&doxm->owner))
561     {
562         OIC_LOG(WARNING, TAG, "Can't change state to Ready for Normal Operation: the device owner is NIL");
563         return OC_EH_INTERNAL_SERVER_ERROR;
564     }
565
566     if (IsNilUuid(&doxm->deviceID))
567     {
568         OIC_LOG(WARNING, TAG,
569                 "Can't change state to Ready for Normal Operation: the device owner ID is NIL");
570         return OC_EH_INTERNAL_SERVER_ERROR;
571     }
572
573     if (IsNilUuid(&doxm->rownerID))
574     {
575         OIC_LOG(WARNING, TAG, "Can't change state to Ready for Normal Operation: the doxm rowner is NIL");
576         return OC_EH_INTERNAL_SERVER_ERROR;
577     }
578
579
580     if (IsNilUuid(&pstat->rownerID))
581     {
582         OIC_LOG(WARNING, TAG, "Can't change state to Ready for Normal Operation: the pstat rowner is NIL");
583         return OC_EH_INTERNAL_SERVER_ERROR;
584     }
585
586     memset(&rowneruuid, 0, sizeof(OicUuid_t));
587     if (OC_STACK_OK != GetAclRownerId(&rowneruuid))
588     {
589         OIC_LOG(WARNING, TAG, "Can't change state to Ready for Normal Operation: can't get acl");
590         return OC_EH_INTERNAL_SERVER_ERROR;
591     }
592
593     if (IsNilUuid(&rowneruuid))
594     {
595         OIC_LOG(WARNING, TAG, "Can't change state to Ready for Normal Operation: the acl rowner is NIL");
596         return OC_EH_INTERNAL_SERVER_ERROR;
597     }
598
599     memset(&rowneruuid, 0, sizeof(OicUuid_t));
600     if (OC_STACK_OK != GetCredRownerId(&rowneruuid))
601     {
602         OIC_LOG(WARNING, TAG, "Can't change state to Ready for Normal Operation: can't get cred");
603         return OC_EH_INTERNAL_SERVER_ERROR;
604     }
605
606     if (IsNilUuid(&rowneruuid))
607     {
608         OIC_LOG(WARNING, TAG, "Can't change state to Ready for Normal Operation: the cred rowner is NIL");
609         return OC_EH_INTERNAL_SERVER_ERROR;
610     }
611
612     OIC_LOG_V(DEBUG, TAG, "%s: OUT", __func__);
613
614     return OC_EH_OK;
615
616 }
617
618 /**
619  * The entity handler determines how to process a POST request.
620  * Per the REST paradigm, POST can also be used to update representation of existing
621  * resource or create a new resource.
622  * For pstat, it updates only tm and om.
623  */
624 static OCEntityHandlerResult HandlePstatPostRequest(OCEntityHandlerRequest *ehRequest)
625 {
626     OCEntityHandlerResult ehRet = OC_EH_ERROR;
627     OIC_LOG(INFO, TAG, "HandlePstatPostRequest  processing POST request");
628     OicSecPstat_t *pstat = NULL;
629     static uint16_t previousMsgId = 0;
630     bool isDuplicatedMsg = false;
631
632     if (ehRequest->payload && NULL != gPstat)
633     {
634         uint8_t *payload = ((OCSecurityPayload *) ehRequest->payload)->securityData;
635         size_t size = ((OCSecurityPayload *) ehRequest->payload)->payloadSize;
636         VERIFY_NON_NULL(TAG, payload, ERROR);
637
638         bool roParsed = false;
639         OCStackResult ret = CBORPayloadToPstatBin(payload, size, &pstat, &roParsed);
640         VERIFY_NON_NULL(TAG, pstat, ERROR);
641         if (OC_STACK_OK == ret)
642         {
643             bool validReq = false;
644
645             /*
646              * message ID is supported for CoAP over UDP only according to RFC 7252
647              * So we should check message ID to prevent duplicate request handling in case of OC_ADAPTER_IP.
648              * In case of other transport adapter, duplicate message check is not required.
649              */
650             if (OC_ADAPTER_IP == ehRequest->devAddr.adapter &&
651                  previousMsgId == ehRequest->messageID)
652             {
653                 isDuplicatedMsg = true;
654             }
655
656             if (true == roParsed)
657             {
658                     OIC_LOG(ERROR, TAG, "Not acceptable request because of read-only properties");
659                     ehRet = OC_EH_NOT_ACCEPTABLE;
660                     goto exit;
661             }
662
663             //operation mode(om) should be one of supported modes(sm)
664             for(size_t i = 0; i < gPstat->smLen; i++)
665             {
666                 if(gPstat->sm[i] == pstat->om)
667                 {
668                     validReq = true;
669                     break;
670                 }
671             }
672
673             if(!validReq)
674             {
675                 OIC_LOG_V(ERROR, TAG, "%d is unsupported Operation Mode", (int) pstat->om);
676                 ehRet = OC_EH_BAD_REQ;
677                 goto exit;
678             }
679             validReq = false;
680
681             //Currently, IoTivity only supports Single Service Client Directed provisioning
682             if (pstat->om == SINGLE_SERVICE_CLIENT_DRIVEN)
683             {
684                 if ((pstat->cm & RESET) && false == pstat->isOp)
685                 {
686                     validReq = true;
687                     OIC_LOG(INFO, TAG, "State changed to Ready for Reset");
688                 }
689                 else if ((pstat->cm & TAKE_OWNER) && false == pstat->isOp)
690                 {
691                     validReq = true;
692                     OIC_LOG (INFO, TAG, "State changed to Ready for Ownership transfer");
693                 }
694                 else if (false == (pstat->cm & TAKE_OWNER) && false == pstat->isOp)
695                 {
696                     validReq = true;
697                     OIC_LOG(INFO, TAG, "State changed to Ready for Provisioning");
698                 }
699                 else if (false == (pstat->cm & TAKE_OWNER) && true == pstat->isOp)
700                 {
701                     ehRet = ValidateReadyForNOP(pstat);
702                     if(OC_EH_OK != ehRet)
703                     {
704                         goto exit;
705                     }
706                     validReq = true;
707                     OIC_LOG (INFO, TAG, "State changed to Ready for Normal Operation");
708                 }
709                 else
710                 {
711                     OIC_LOG(DEBUG, TAG, "Invalid Device provisionig state");
712                     OIC_LOG_BUFFER(DEBUG, TAG, payload, size);
713                     ehRet = OC_EH_BAD_REQ;
714                     goto exit;
715                 }
716             }
717
718             if (!validReq)
719             {
720                 OIC_LOG(DEBUG, TAG, "Bad request for PSTAT");
721                 ehRet = OC_EH_BAD_REQ;
722                 goto exit;
723             }
724
725             gPstat->isOp = pstat->isOp;
726             gPstat->om = pstat->om;
727             gPstat->tm = pstat->tm;
728             gPstat->cm = pstat->cm;
729             memcpy(&(gPstat->deviceID), &(pstat->deviceID), sizeof(OicUuid_t));
730             memcpy(&(gPstat->rownerID), &(pstat->rownerID), sizeof(OicUuid_t));
731
732             // Convert pstat data into CBOR for update to persistent storage
733             if (UpdatePersistentStorage(gPstat))
734             {
735                 ehRet = OC_EH_OK;
736             }
737             if (true == (pstat->cm & RESET))
738             {
739                 if (OC_STACK_OK != SendSRMResponse(ehRequest, ehRet, NULL, 0))
740                 {
741                     ehRet = OC_EH_ERROR;
742                     OIC_LOG(ERROR, TAG, "SendSRMResponse failed in HandlePstatPostRequest");
743                     DeletePstatBinData(pstat);
744                     return ehRet;
745                 }
746                 ret = ResetSecureResourceInPS();
747                 if (OC_STACK_OK == ret)
748                 {
749                     ehRet = OC_EH_OK;
750                 }
751                 DeletePstatBinData(pstat);
752                 return ehRet;
753             }
754         }
755     }
756  exit:
757
758      if(OC_EH_OK != ehRet)
759      {
760          /*
761            * If some error is occured while ownership transfer,
762            * ownership transfer related resource should be revert back to initial status.
763            */
764          const OicSecDoxm_t* doxm = GetDoxmResourceData();
765          if(doxm && !doxm->owned)
766          {
767             OIC_LOG(WARNING, TAG, "The operation failed during handle DOXM request");
768
769             if (!isDuplicatedMsg)
770             {
771 #if defined (__WITH_TLS__) || defined(__WITH_DTLS__)
772                 InvokeOtmEventHandler(ehRequest->devAddr.addr, ehRequest->devAddr.port,
773                                           NULL, OIC_OTM_ERROR);
774 #endif
775                 ResetSecureResourceInPS();
776                 OIC_LOG(INFO, TAG, "DOXM will be reverted.");
777             }
778          }
779          else
780          {
781              OIC_LOG(ERROR, TAG, "Invalid DOXM resource.");
782              ResetSecureResourceInPS();
783          }
784      }
785      else
786      {
787         if(ehRequest->devAddr.adapter == OC_ADAPTER_IP)
788         {
789             previousMsgId = ehRequest->messageID;
790         }
791      }
792
793     // Send response payload to request originator
794     ehRet = ((SendSRMResponse(ehRequest, ehRet, NULL, 0)) == OC_STACK_OK) ?
795                    OC_EH_OK : OC_EH_ERROR;
796
797     DeletePstatBinData(pstat);
798     return ehRet;
799 }
800
801 /**
802  * This internal method is the entity handler for pstat resources.
803  */
804  OCEntityHandlerResult PstatEntityHandler(OCEntityHandlerFlag flag,
805                                           OCEntityHandlerRequest * ehRequest,
806                                           void *callbackParam)
807 {
808     (void)callbackParam;
809     OCEntityHandlerResult ehRet = OC_EH_ERROR;
810     // This method will handle REST request (GET/POST) for /oic/sec/pstat
811     if (flag & OC_REQUEST_FLAG)
812     {
813         OIC_LOG(INFO, TAG, "Flag includes OC_REQUEST_FLAG");
814         switch (ehRequest->method)
815         {
816             case OC_REST_GET:
817                 ehRet = HandlePstatGetRequest(ehRequest);
818                 break;
819             case OC_REST_POST:
820                 ehRet = HandlePstatPostRequest(ehRequest);
821                 break;
822             default:
823                 ehRet = ((SendSRMResponse(ehRequest, ehRet, NULL, 0)) == OC_STACK_OK) ?
824                                OC_EH_OK : OC_EH_ERROR;
825                 break;
826         }
827     }
828     return ehRet;
829 }
830
831 /**
832  * This internal method is used to create '/oic/sec/pstat' resource.
833  */
834  OCStackResult CreatePstatResource()
835 {
836     OCStackResult ret = OCCreateResource(&gPstatHandle,
837                                          OIC_RSRC_TYPE_SEC_PSTAT,
838                                          OC_RSRVD_INTERFACE_DEFAULT,
839                                          OIC_RSRC_PSTAT_URI,
840                                          PstatEntityHandler,
841                                          NULL,
842                                          OC_SECURE |
843                                          OC_DISCOVERABLE);
844
845     if (OC_STACK_OK != ret)
846     {
847         OIC_LOG(FATAL, TAG, "Unable to instantiate pstat resource");
848         DeInitPstatResource();
849     }
850     return ret;
851 }
852
853 /**
854  * Get the default value.
855  *
856  * @return the gDefaultPstat pointer.
857  */
858 static OicSecPstat_t* GetPstatDefault()
859 {
860     return &gDefaultPstat;
861 }
862
863 OCStackResult InitPstatResource()
864 {
865     OCStackResult ret = OC_STACK_ERROR;
866
867     // Read Pstat resource from PS
868     uint8_t *data = NULL;
869     size_t size = 0;
870     OicUuid_t emptyUuid = {.id={0}};
871     ret = GetSecureVirtualDatabaseFromPS(OIC_JSON_PSTAT_NAME, &data, &size);
872     // If database read failed
873     if (OC_STACK_OK != ret)
874     {
875         OIC_LOG (DEBUG, TAG, "ReadSVDataFromPS failed");
876     }
877     if (data)
878     {
879         // Read ACL resource from PS
880         ret = CBORPayloadToPstat(data, size, &gPstat);
881         OICFree(data);
882     }
883     /*
884      * If SVR database in persistent storage got corrupted or
885      * is not available for some reason, a default pstat is created
886      * which allows user to initiate pstat provisioning again.
887      */
888     if ((OC_STACK_OK != ret) || !gPstat)
889     {
890         gPstat = GetPstatDefault();
891     }
892     VERIFY_NON_NULL(TAG, gPstat, FATAL);
893
894     //In case of Pstat's device id is empty, fill the device id as doxm's device id.
895     if(0 == memcmp(&gPstat->deviceID, &emptyUuid, sizeof(OicUuid_t)))
896     {
897         OicUuid_t doxmUuid = {.id={0}};
898         if(OC_STACK_OK == GetDoxmDeviceID(&doxmUuid))
899         {
900             memcpy(&gPstat->deviceID, &doxmUuid, sizeof(OicUuid_t));
901         }
902     }
903
904     // Instantiate 'oic.sec.pstat'
905     ret = CreatePstatResource();
906
907 exit:
908     if (OC_STACK_OK != ret)
909     {
910         DeInitPstatResource();
911     }
912     return ret;
913 }
914
915 OCStackResult DeInitPstatResource()
916 {
917     if (gPstat != &gDefaultPstat)
918     {
919         DeletePstatBinData(gPstat);
920         gPstat = NULL;
921     }
922     return OCDeleteResource(gPstatHandle);
923 }
924
925 /**
926  * Function to restore pstat resurce to initial status.
927  * This function will use in case of error while ownership transfer
928  */
929 void RestorePstatToInitState()
930 {
931     if(gPstat)
932     {
933         OIC_LOG(INFO, TAG, "PSTAT resource will revert back to initial status.");
934
935         gPstat->cm = (OicSecDpm_t)(gPstat->cm | TAKE_OWNER);
936         gPstat->tm = (OicSecDpm_t)(gPstat->tm & (~TAKE_OWNER));
937         gPstat->om = SINGLE_SERVICE_CLIENT_DRIVEN;
938         if(gPstat->sm && 0 < gPstat->smLen)
939         {
940             gPstat->sm[0] = SINGLE_SERVICE_CLIENT_DRIVEN;
941         }
942
943         if (!UpdatePersistentStorage(gPstat))
944         {
945             OIC_LOG(ERROR, TAG, "Failed to revert PSTAT in persistent storage");
946         }
947     }
948 }
949
950 OCStackResult SetPstatRownerId(const OicUuid_t* newROwner)
951 {
952     OCStackResult ret = OC_STACK_ERROR;
953     uint8_t *cborPayload = NULL;
954     size_t size = 0;
955     OicUuid_t prevId = {.id={0}};
956
957     if(NULL == newROwner)
958     {
959         ret = OC_STACK_INVALID_PARAM;
960     }
961     if(NULL == gPstat)
962     {
963         ret = OC_STACK_NO_RESOURCE;
964     }
965
966     if(newROwner && gPstat)
967     {
968         memcpy(prevId.id, gPstat->rownerID.id, sizeof(prevId.id));
969         memcpy(gPstat->rownerID.id, newROwner->id, sizeof(newROwner->id));
970
971         ret = PstatToCBORPayload(gPstat, &cborPayload, &size, false);
972         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
973
974         ret = UpdateSecureResourceInPS(OIC_JSON_PSTAT_NAME, cborPayload, size);
975         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
976
977         OICFree(cborPayload);
978     }
979
980     return ret;
981
982 exit:
983     OICFree(cborPayload);
984     memcpy(gPstat->rownerID.id, prevId.id, sizeof(prevId.id));
985     return ret;
986 }
987
988 /**
989  * This function returns the "isop" status of the device.
990  *
991  * @return true iff pstat.isop == 1, else false
992  */
993 bool GetPstatIsop()
994 {
995     if(NULL != gPstat)
996     {
997         return gPstat->isOp;
998     }
999     else
1000     {
1001         //In case of gPstat is NULL
1002         return false;
1003     }
1004 }
1005
1006 OCStackResult GetPstatRownerId(OicUuid_t *rowneruuid)
1007 {
1008     OCStackResult retVal = OC_STACK_ERROR;
1009     if (gPstat)
1010     {
1011         *rowneruuid = gPstat->rownerID;
1012         retVal = OC_STACK_OK;
1013     }
1014     return retVal;
1015 }
1016
1017 OCStackResult SetPstatSelfOwnership(const OicUuid_t* newROwner)
1018 {
1019     OCStackResult ret = OC_STACK_ERROR;
1020     uint8_t *cborPayload = NULL;
1021     size_t size = 0;
1022
1023     if(NULL == gPstat)
1024     {
1025         ret = OC_STACK_NO_RESOURCE;
1026         return ret;
1027     }
1028
1029     if( newROwner && (false == gPstat->isOp) && (true == (TAKE_OWNER && gPstat->cm)) )
1030     {
1031         gPstat->cm = (OicSecDpm_t)(gPstat->cm & (~TAKE_OWNER));
1032         gPstat->isOp = true;
1033
1034         memcpy(gPstat->deviceID.id, newROwner->id, sizeof(newROwner->id));
1035         memcpy(gPstat->rownerID.id, newROwner->id, sizeof(newROwner->id));
1036
1037         ret = PstatToCBORPayload(gPstat, &cborPayload, &size, false);
1038         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
1039
1040         ret = UpdateSecureResourceInPS(OIC_JSON_PSTAT_NAME, cborPayload, size);
1041         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
1042
1043         OICFree(cborPayload);
1044     }
1045     else
1046     {
1047         OIC_LOG(ERROR, TAG, "The state of PSTAT is not Ready For OTM");
1048     }
1049
1050     return ret;
1051
1052 exit:
1053     OICFree(cborPayload);
1054     return ret;
1055 }
1056