92e7579c7295e5dbf124231683d499b9a3872f49
[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                 RestoreDoxmToInitState();
776                 RestorePstatToInitState();
777                 OIC_LOG(WARNING, TAG, "DOXM will be reverted.");
778             }
779          }
780          else
781          {
782              OIC_LOG(ERROR, TAG, "Invalid DOXM resource.");
783              ResetSecureResourceInPS();
784          }
785      }
786      else
787      {
788         if(ehRequest->devAddr.adapter == OC_ADAPTER_IP)
789         {
790             previousMsgId = ehRequest->messageID;
791         }
792      }
793
794     // Send response payload to request originator
795     ehRet = ((SendSRMResponse(ehRequest, ehRet, NULL, 0)) == OC_STACK_OK) ?
796                    OC_EH_OK : OC_EH_ERROR;
797
798     DeletePstatBinData(pstat);
799     return ehRet;
800 }
801
802 /**
803  * This internal method is the entity handler for pstat resources.
804  */
805  OCEntityHandlerResult PstatEntityHandler(OCEntityHandlerFlag flag,
806                                           OCEntityHandlerRequest * ehRequest,
807                                           void *callbackParam)
808 {
809     (void)callbackParam;
810     OCEntityHandlerResult ehRet = OC_EH_ERROR;
811     // This method will handle REST request (GET/POST) for /oic/sec/pstat
812     if (flag & OC_REQUEST_FLAG)
813     {
814         OIC_LOG(INFO, TAG, "Flag includes OC_REQUEST_FLAG");
815         switch (ehRequest->method)
816         {
817             case OC_REST_GET:
818                 ehRet = HandlePstatGetRequest(ehRequest);
819                 break;
820             case OC_REST_POST:
821                 ehRet = HandlePstatPostRequest(ehRequest);
822                 break;
823             default:
824                 ehRet = ((SendSRMResponse(ehRequest, ehRet, NULL, 0)) == OC_STACK_OK) ?
825                                OC_EH_OK : OC_EH_ERROR;
826                 break;
827         }
828     }
829     return ehRet;
830 }
831
832 /**
833  * This internal method is used to create '/oic/sec/pstat' resource.
834  */
835  OCStackResult CreatePstatResource()
836 {
837     OCStackResult ret = OCCreateResource(&gPstatHandle,
838                                          OIC_RSRC_TYPE_SEC_PSTAT,
839                                          OC_RSRVD_INTERFACE_DEFAULT,
840                                          OIC_RSRC_PSTAT_URI,
841                                          PstatEntityHandler,
842                                          NULL,
843                                          OC_SECURE |
844                                          OC_DISCOVERABLE);
845
846     if (OC_STACK_OK != ret)
847     {
848         OIC_LOG(FATAL, TAG, "Unable to instantiate pstat resource");
849         DeInitPstatResource();
850     }
851     return ret;
852 }
853
854 /**
855  * Get the default value.
856  *
857  * @return the gDefaultPstat pointer.
858  */
859 static OicSecPstat_t* GetPstatDefault()
860 {
861     return &gDefaultPstat;
862 }
863
864 OCStackResult InitPstatResource()
865 {
866     OCStackResult ret = OC_STACK_ERROR;
867
868     // Read Pstat resource from PS
869     uint8_t *data = NULL;
870     size_t size = 0;
871     OicUuid_t emptyUuid = {.id={0}};
872     ret = GetSecureVirtualDatabaseFromPS(OIC_JSON_PSTAT_NAME, &data, &size);
873     // If database read failed
874     if (OC_STACK_OK != ret)
875     {
876         OIC_LOG (DEBUG, TAG, "ReadSVDataFromPS failed");
877     }
878     if (data)
879     {
880         // Read ACL resource from PS
881         ret = CBORPayloadToPstat(data, size, &gPstat);
882         OICFree(data);
883     }
884     /*
885      * If SVR database in persistent storage got corrupted or
886      * is not available for some reason, a default pstat is created
887      * which allows user to initiate pstat provisioning again.
888      */
889     if ((OC_STACK_OK != ret) || !gPstat)
890     {
891         gPstat = GetPstatDefault();
892     }
893     VERIFY_NON_NULL(TAG, gPstat, FATAL);
894
895     //In case of Pstat's device id is empty, fill the device id as doxm's device id.
896     if(0 == memcmp(&gPstat->deviceID, &emptyUuid, sizeof(OicUuid_t)))
897     {
898         OicUuid_t doxmUuid = {.id={0}};
899         if(OC_STACK_OK == GetDoxmDeviceID(&doxmUuid))
900         {
901             memcpy(&gPstat->deviceID, &doxmUuid, sizeof(OicUuid_t));
902         }
903     }
904
905     // Instantiate 'oic.sec.pstat'
906     ret = CreatePstatResource();
907
908 exit:
909     if (OC_STACK_OK != ret)
910     {
911         DeInitPstatResource();
912     }
913     return ret;
914 }
915
916 OCStackResult DeInitPstatResource()
917 {
918     if (gPstat != &gDefaultPstat)
919     {
920         DeletePstatBinData(gPstat);
921         gPstat = NULL;
922     }
923     return OCDeleteResource(gPstatHandle);
924 }
925
926 /**
927  * Function to restore pstat resurce to initial status.
928  * This function will use in case of error while ownership transfer
929  */
930 void RestorePstatToInitState()
931 {
932     if(gPstat)
933     {
934         OIC_LOG(INFO, TAG, "PSTAT resource will revert back to initial status.");
935
936         gPstat->cm = (OicSecDpm_t)(gPstat->cm | TAKE_OWNER);
937         gPstat->tm = (OicSecDpm_t)(gPstat->tm & (~TAKE_OWNER));
938         gPstat->om = SINGLE_SERVICE_CLIENT_DRIVEN;
939         if(gPstat->sm && 0 < gPstat->smLen)
940         {
941             gPstat->sm[0] = SINGLE_SERVICE_CLIENT_DRIVEN;
942         }
943
944         if (!UpdatePersistentStorage(gPstat))
945         {
946             OIC_LOG(ERROR, TAG, "Failed to revert PSTAT in persistent storage");
947         }
948     }
949 }
950
951 OCStackResult SetPstatRownerId(const OicUuid_t* newROwner)
952 {
953     OCStackResult ret = OC_STACK_ERROR;
954     uint8_t *cborPayload = NULL;
955     size_t size = 0;
956     OicUuid_t prevId = {.id={0}};
957
958     if(NULL == newROwner)
959     {
960         ret = OC_STACK_INVALID_PARAM;
961     }
962     if(NULL == gPstat)
963     {
964         ret = OC_STACK_NO_RESOURCE;
965     }
966
967     if(newROwner && gPstat)
968     {
969         memcpy(prevId.id, gPstat->rownerID.id, sizeof(prevId.id));
970         memcpy(gPstat->rownerID.id, newROwner->id, sizeof(newROwner->id));
971
972         ret = PstatToCBORPayload(gPstat, &cborPayload, &size, false);
973         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
974
975         ret = UpdateSecureResourceInPS(OIC_JSON_PSTAT_NAME, cborPayload, size);
976         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
977
978         OICFree(cborPayload);
979     }
980
981     return ret;
982
983 exit:
984     OICFree(cborPayload);
985     memcpy(gPstat->rownerID.id, prevId.id, sizeof(prevId.id));
986     return ret;
987 }
988
989 /**
990  * This function returns the "isop" status of the device.
991  *
992  * @return true iff pstat.isop == 1, else false
993  */
994 bool GetPstatIsop()
995 {
996     if(NULL != gPstat)
997     {
998         return gPstat->isOp;
999     }
1000     else
1001     {
1002         //In case of gPstat is NULL
1003         return false;
1004     }
1005 }
1006
1007 OCStackResult GetPstatRownerId(OicUuid_t *rowneruuid)
1008 {
1009     OCStackResult retVal = OC_STACK_ERROR;
1010     if (gPstat)
1011     {
1012         *rowneruuid = gPstat->rownerID;
1013         retVal = OC_STACK_OK;
1014     }
1015     return retVal;
1016 }
1017
1018 OCStackResult SetPstatSelfOwnership(const OicUuid_t* newROwner)
1019 {
1020     OCStackResult ret = OC_STACK_ERROR;
1021     uint8_t *cborPayload = NULL;
1022     size_t size = 0;
1023
1024     if(NULL == gPstat)
1025     {
1026         ret = OC_STACK_NO_RESOURCE;
1027         return ret;
1028     }
1029
1030     if( newROwner && (false == gPstat->isOp) && (true == (TAKE_OWNER && gPstat->cm)) )
1031     {
1032         gPstat->cm = (OicSecDpm_t)(gPstat->cm & (~TAKE_OWNER));
1033         gPstat->isOp = true;
1034
1035         memcpy(gPstat->deviceID.id, newROwner->id, sizeof(newROwner->id));
1036         memcpy(gPstat->rownerID.id, newROwner->id, sizeof(newROwner->id));
1037
1038         ret = PstatToCBORPayload(gPstat, &cborPayload, &size, false);
1039         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
1040
1041         ret = UpdateSecureResourceInPS(OIC_JSON_PSTAT_NAME, cborPayload, size);
1042         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
1043
1044         OICFree(cborPayload);
1045     }
1046     else
1047     {
1048         OIC_LOG(ERROR, TAG, "The state of PSTAT is not Ready For OTM");
1049     }
1050
1051     return ret;
1052
1053 exit:
1054     OICFree(cborPayload);
1055     return ret;
1056 }
1057