Add gPstat null check
[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         VERIFY_NON_NULL(TAG, gPstat, ERROR);
295         pstat->isOp = gPstat->isOp;
296         cborFindResult = CborNoError;
297     }
298
299     cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_DEVICE_ID_NAME, &pstatMap);
300     if (CborNoError == cborFindResult && cbor_value_is_text_string(&pstatMap))
301     {
302         cborFindResult = cbor_value_dup_text_string(&pstatMap, &strUuid , &len, NULL);
303         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding Device Id Value.");
304         ret = ConvertStrToUuid(strUuid , &pstat->deviceID);
305         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
306         OICFree(strUuid );
307         strUuid  = NULL;
308
309     }
310     else
311     {
312         VERIFY_NON_NULL(TAG, gPstat, ERROR);
313         memcpy(&pstat->deviceID, &gPstat->deviceID, sizeof(OicUuid_t));
314         cborFindResult = CborNoError;
315     }
316
317     cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_CM_NAME, &pstatMap);
318     if (CborNoError == cborFindResult && cbor_value_is_integer(&pstatMap))
319     {
320         int cm;
321
322         cborFindResult = cbor_value_get_int(&pstatMap, &cm);
323         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding CM.");
324         pstat->cm = (OicSecDpm_t)cm;
325     }
326     else
327     {
328         VERIFY_NON_NULL(TAG, gPstat, ERROR);
329         pstat->cm = gPstat->cm;
330         cborFindResult = CborNoError;
331     }
332
333     cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_TM_NAME, &pstatMap);
334     if (CborNoError == cborFindResult && cbor_value_is_integer(&pstatMap))
335     {
336         int tm;
337
338         cborFindResult = cbor_value_get_int(&pstatMap, &tm);
339         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding TM.");
340         pstat->tm = (OicSecDpm_t)tm;
341     }
342     else
343     {
344         VERIFY_NON_NULL(TAG, gPstat, ERROR);
345         pstat->tm = gPstat->tm;
346         cborFindResult = CborNoError;
347     }
348
349     cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_OM_NAME, &pstatMap);
350     if (CborNoError == cborFindResult && cbor_value_is_integer(&pstatMap))
351     {
352         int om;
353
354         cborFindResult = cbor_value_get_int(&pstatMap, &om);
355         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding OM.");
356         pstat->om = (OicSecDpom_t)om;
357     }
358     else
359     {
360         VERIFY_NON_NULL(TAG, gPstat, ERROR);
361         pstat->om = gPstat->om;
362         cborFindResult = CborNoError;
363     }
364
365     cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_SM_NAME, &pstatMap);
366     if (CborNoError == cborFindResult && cbor_value_is_integer(&pstatMap))
367     {
368         int sm;
369
370         pstat->smLen = 1;
371         pstat->sm = (OicSecDpom_t*)OICCalloc(pstat->smLen, sizeof(OicSecDpom_t));
372         VERIFY_NON_NULL(TAG, pstat->sm, ERROR);
373         cborFindResult = cbor_value_get_int(&pstatMap, &sm);
374         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding SM.");
375         pstat->sm[0] = (OicSecDpom_t)sm;
376
377         if (roParsed)
378         {
379             *roParsed = true;
380         }
381     }
382     else
383     {
384         VERIFY_NON_NULL(TAG, gPstat, ERROR);
385         pstat->smLen = gPstat->smLen;
386         pstat->sm = (OicSecDpom_t*)OICCalloc(pstat->smLen, sizeof(OicSecDpom_t));
387         VERIFY_NON_NULL(TAG, pstat->sm, ERROR);
388         *pstat->sm = *gPstat->sm;
389         cborFindResult = CborNoError;
390     }
391
392     cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_ROWNERID_NAME, &pstatMap);
393     if (CborNoError == cborFindResult && cbor_value_is_text_string(&pstatMap))
394     {
395         cborFindResult = cbor_value_dup_text_string(&pstatMap, &strUuid , &len, NULL);
396         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding ROwner Id Value.");
397         ret = ConvertStrToUuid(strUuid , &pstat->rownerID);
398         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
399         OICFree(strUuid );
400         strUuid  = NULL;
401     }
402     else
403     {
404         VERIFY_NON_NULL(TAG, gPstat, ERROR);
405         memcpy(pstat->rownerID.id, gPstat->rownerID.id, sizeof(gPstat->rownerID.id));
406         cborFindResult = CborNoError;
407     }
408
409     *secPstat = pstat;
410     ret = OC_STACK_OK;
411
412 exit:
413     if (CborNoError != cborFindResult)
414     {
415         OIC_LOG(ERROR, TAG, "CBORPayloadToPstat failed");
416         DeletePstatBinData(pstat);
417         pstat = NULL;
418         *secPstat = NULL;
419         ret = OC_STACK_ERROR;
420     }
421
422     return ret;
423 }
424
425 /**
426  * Function to update persistent storage
427  */
428 static bool UpdatePersistentStorage(OicSecPstat_t *pstat)
429 {
430     bool bRet = false;
431
432     size_t size = 0;
433     uint8_t *cborPayload = NULL;
434     OCStackResult ret = PstatToCBORPayload(pstat, &cborPayload, &size, false);
435     if (OC_STACK_OK == ret)
436     {
437         if (OC_STACK_OK == UpdateSecureResourceInPS(OIC_JSON_PSTAT_NAME, cborPayload, size))
438         {
439             bRet = true;
440         }
441         OICFree(cborPayload);
442     }
443
444     return bRet;
445 }
446
447 static bool ValidateQuery(const char * query)
448 {
449     OIC_LOG (DEBUG, TAG, "In ValidateQuery");
450     if(NULL == gPstat)
451     {
452         return false;
453     }
454
455     bool bInterfaceQry = false;      // does querystring contains 'if' query ?
456     bool bInterfaceMatch = false;    // does 'if' query matches with oic.if.baseline ?
457
458     OicParseQueryIter_t parseIter = {.attrPos = NULL};
459
460     ParseQueryIterInit((unsigned char*)query, &parseIter);
461
462     while (GetNextQuery(&parseIter))
463     {
464         if (strncasecmp((char *)parseIter.attrPos, OC_RSRVD_INTERFACE, parseIter.attrLen) == 0)
465         {
466             bInterfaceQry = true;
467             if ((strncasecmp((char *)parseIter.valPos, OC_RSRVD_INTERFACE_DEFAULT, parseIter.valLen) == 0))
468             {
469                 bInterfaceMatch = true;
470             }
471         }
472     }
473     return (bInterfaceQry ? bInterfaceMatch: true);
474 }
475
476 #ifdef MULTIPLE_OWNER
477 bool IsValidPstatAccessForSubOwner(const uint8_t *cborPayload, size_t size)
478 {
479     OicSecPstat_t* pstat = NULL;
480     bool isValidPstat = true;
481
482     OIC_LOG_BUFFER(DEBUG, TAG, cborPayload, size);
483     VERIFY_NON_NULL(TAG, cborPayload, ERROR);
484     VERIFY_SUCCESS(TAG, 0 != size, ERROR);
485     VERIFY_SUCCESS(TAG, OC_STACK_OK == CBORPayloadToPstat(cborPayload, size, &pstat), ERROR);
486     VERIFY_NON_NULL(TAG, pstat, ERROR);
487
488     if (RESET & pstat->cm)
489     {
490         OIC_LOG(ERROR, TAG, "SubOwner can't reset the server.");
491         isValidPstat = false;
492     }
493
494 exit:
495     DeletePstatBinData(pstat);
496     return isValidPstat;
497 }
498 #endif //MULTIPLE_OWNER
499
500 /**
501  * The entity handler determines how to process a GET request.
502  */
503 static OCEntityHandlerResult HandlePstatGetRequest (const OCEntityHandlerRequest * ehRequest)
504 {
505     OCEntityHandlerResult ehRet = OC_EH_OK;
506
507     OIC_LOG(INFO, TAG, "HandlePstatGetRequest  processing GET request");
508
509     //Checking if Get request is a query.
510     if (ehRequest->query)
511     {
512         OIC_LOG_V(DEBUG,TAG,"query:%s",ehRequest->query);
513         OIC_LOG(DEBUG, TAG, "HandlePstatGetRequest processing query");
514         if (!ValidateQuery(ehRequest->query))
515         {
516             ehRet = OC_EH_ERROR;
517         }
518     }
519
520     /*
521      * For GET or Valid Query request return doxm resource CBOR payload.
522      * For non-valid query return NULL json payload.
523      * A device will 'always' have a default Pstat, so PstatToCBORPayload will
524      * return valid pstat resource json.
525      */
526     size_t size = 0;
527     uint8_t *payload = NULL;
528     if (ehRet == OC_EH_OK)
529     {
530         if(OC_STACK_OK != PstatToCBORPayload(gPstat, &payload, &size, false))
531         {
532             OIC_LOG(WARNING, TAG, "PstatToCBORPayload failed in HandlePstatGetRequest");
533         }
534     }
535
536     // Send response payload to request originator
537     ehRet = ((SendSRMResponse(ehRequest, ehRet, payload, size)) == OC_STACK_OK) ?
538                    OC_EH_OK : OC_EH_ERROR;
539     OICFree(payload);
540     return ehRet;
541 }
542
543 /**
544  * Checks if device can change state to Ready for Normal Operation.
545  */
546 static OCEntityHandlerResult ValidateReadyForNOP(const OicSecPstat_t *pstat)
547 {
548     OIC_LOG_V(DEBUG, TAG, "%s: IN", __func__);
549
550     const OicSecDoxm_t *doxm = GetDoxmResourceData();
551     OicUuid_t rowneruuid;
552
553     if (!doxm)
554     {
555         OIC_LOG(WARNING, TAG, "DOXM is NULL");
556         return OC_EH_NOT_ACCEPTABLE;
557     }
558
559     if (!doxm->owned)
560     {
561         OIC_LOG(WARNING, TAG, "Can't change state to Ready for Normal Operation: the device is unowned");
562         return OC_EH_NOT_ACCEPTABLE;
563     }
564
565     if (IsNilUuid(&doxm->owner))
566     {
567         OIC_LOG(WARNING, TAG, "Can't change state to Ready for Normal Operation: the device owner is NIL");
568         return OC_EH_INTERNAL_SERVER_ERROR;
569     }
570
571     if (IsNilUuid(&doxm->deviceID))
572     {
573         OIC_LOG(WARNING, TAG,
574                 "Can't change state to Ready for Normal Operation: the device owner ID is NIL");
575         return OC_EH_INTERNAL_SERVER_ERROR;
576     }
577
578     if (IsNilUuid(&doxm->rownerID))
579     {
580         OIC_LOG(WARNING, TAG, "Can't change state to Ready for Normal Operation: the doxm rowner is NIL");
581         return OC_EH_INTERNAL_SERVER_ERROR;
582     }
583
584
585     if (IsNilUuid(&pstat->rownerID))
586     {
587         OIC_LOG(WARNING, TAG, "Can't change state to Ready for Normal Operation: the pstat rowner is NIL");
588         return OC_EH_INTERNAL_SERVER_ERROR;
589     }
590
591     memset(&rowneruuid, 0, sizeof(OicUuid_t));
592     if (OC_STACK_OK != GetAclRownerId(&rowneruuid))
593     {
594         OIC_LOG(WARNING, TAG, "Can't change state to Ready for Normal Operation: can't get acl");
595         return OC_EH_INTERNAL_SERVER_ERROR;
596     }
597
598     if (IsNilUuid(&rowneruuid))
599     {
600         OIC_LOG(WARNING, TAG, "Can't change state to Ready for Normal Operation: the acl rowner is NIL");
601         return OC_EH_INTERNAL_SERVER_ERROR;
602     }
603
604     memset(&rowneruuid, 0, sizeof(OicUuid_t));
605     if (OC_STACK_OK != GetCredRownerId(&rowneruuid))
606     {
607         OIC_LOG(WARNING, TAG, "Can't change state to Ready for Normal Operation: can't get cred");
608         return OC_EH_INTERNAL_SERVER_ERROR;
609     }
610
611     if (IsNilUuid(&rowneruuid))
612     {
613         OIC_LOG(WARNING, TAG, "Can't change state to Ready for Normal Operation: the cred rowner is NIL");
614         return OC_EH_INTERNAL_SERVER_ERROR;
615     }
616
617     OIC_LOG_V(DEBUG, TAG, "%s: OUT", __func__);
618
619     return OC_EH_OK;
620
621 }
622
623 /**
624  * The entity handler determines how to process a POST request.
625  * Per the REST paradigm, POST can also be used to update representation of existing
626  * resource or create a new resource.
627  * For pstat, it updates only tm and om.
628  */
629 static OCEntityHandlerResult HandlePstatPostRequest(OCEntityHandlerRequest *ehRequest)
630 {
631     OCEntityHandlerResult ehRet = OC_EH_ERROR;
632     OIC_LOG(INFO, TAG, "HandlePstatPostRequest  processing POST request");
633     OicSecPstat_t *pstat = NULL;
634     static uint16_t previousMsgId = 0;
635     bool isDuplicatedMsg = false;
636
637     if (ehRequest->payload && NULL != gPstat)
638     {
639         uint8_t *payload = ((OCSecurityPayload *) ehRequest->payload)->securityData;
640         size_t size = ((OCSecurityPayload *) ehRequest->payload)->payloadSize;
641         VERIFY_NON_NULL(TAG, payload, ERROR);
642
643         bool roParsed = false;
644         OCStackResult ret = CBORPayloadToPstatBin(payload, size, &pstat, &roParsed);
645         VERIFY_NON_NULL(TAG, pstat, ERROR);
646         if (OC_STACK_OK == ret)
647         {
648             bool validReq = false;
649
650             /*
651              * message ID is supported for CoAP over UDP only according to RFC 7252
652              * So we should check message ID to prevent duplicate request handling in case of OC_ADAPTER_IP.
653              * In case of other transport adapter, duplicate message check is not required.
654              */
655             if (OC_ADAPTER_IP == ehRequest->devAddr.adapter &&
656                  previousMsgId == ehRequest->messageID)
657             {
658                 isDuplicatedMsg = true;
659             }
660
661             if (true == roParsed)
662             {
663                     OIC_LOG(ERROR, TAG, "Not acceptable request because of read-only properties");
664                     ehRet = OC_EH_NOT_ACCEPTABLE;
665                     goto exit;
666             }
667
668             //operation mode(om) should be one of supported modes(sm)
669             for(size_t i = 0; i < gPstat->smLen; i++)
670             {
671                 if(gPstat->sm[i] == pstat->om)
672                 {
673                     validReq = true;
674                     break;
675                 }
676             }
677
678             if(!validReq)
679             {
680                 OIC_LOG_V(ERROR, TAG, "%d is unsupported Operation Mode", (int) pstat->om);
681                 ehRet = OC_EH_BAD_REQ;
682                 goto exit;
683             }
684             validReq = false;
685
686             //Currently, IoTivity only supports Single Service Client Directed provisioning
687             if (pstat->om == SINGLE_SERVICE_CLIENT_DRIVEN)
688             {
689                 if ((pstat->cm & RESET) && false == pstat->isOp)
690                 {
691                     validReq = true;
692                     OIC_LOG(INFO, TAG, "State changed to Ready for Reset");
693                 }
694                 else if ((pstat->cm & TAKE_OWNER) && false == pstat->isOp)
695                 {
696                     validReq = true;
697                     OIC_LOG (INFO, TAG, "State changed to Ready for Ownership transfer");
698                 }
699                 else if (false == (pstat->cm & TAKE_OWNER) && false == pstat->isOp)
700                 {
701                     validReq = true;
702                     OIC_LOG(INFO, TAG, "State changed to Ready for Provisioning");
703                 }
704                 else if (false == (pstat->cm & TAKE_OWNER) && true == pstat->isOp)
705                 {
706                     ehRet = ValidateReadyForNOP(pstat);
707                     if(OC_EH_OK != ehRet)
708                     {
709                         goto exit;
710                     }
711                     validReq = true;
712                     OIC_LOG (INFO, TAG, "State changed to Ready for Normal Operation");
713                 }
714                 else
715                 {
716                     OIC_LOG(DEBUG, TAG, "Invalid Device provisionig state");
717                     OIC_LOG_BUFFER(DEBUG, TAG, payload, size);
718                     ehRet = OC_EH_BAD_REQ;
719                     goto exit;
720                 }
721             }
722
723             if (!validReq)
724             {
725                 OIC_LOG(DEBUG, TAG, "Bad request for PSTAT");
726                 ehRet = OC_EH_BAD_REQ;
727                 goto exit;
728             }
729
730             gPstat->isOp = pstat->isOp;
731             gPstat->om = pstat->om;
732             gPstat->tm = pstat->tm;
733             gPstat->cm = pstat->cm;
734             memcpy(&(gPstat->deviceID), &(pstat->deviceID), sizeof(OicUuid_t));
735             memcpy(&(gPstat->rownerID), &(pstat->rownerID), sizeof(OicUuid_t));
736
737             // Convert pstat data into CBOR for update to persistent storage
738             if (UpdatePersistentStorage(gPstat))
739             {
740                 ehRet = OC_EH_OK;
741             }
742             if (true == (pstat->cm & RESET))
743             {
744                 if (OC_STACK_OK != SendSRMResponse(ehRequest, ehRet, NULL, 0))
745                 {
746                     ehRet = OC_EH_ERROR;
747                     OIC_LOG(ERROR, TAG, "SendSRMResponse failed in HandlePstatPostRequest");
748                     DeletePstatBinData(pstat);
749                     return ehRet;
750                 }
751                 ret = ResetSecureResourceInPS();
752                 if (OC_STACK_OK == ret)
753                 {
754                     ehRet = OC_EH_OK;
755                 }
756                 DeletePstatBinData(pstat);
757                 return ehRet;
758             }
759         }
760     }
761  exit:
762
763      if(OC_EH_OK != ehRet)
764      {
765          /*
766            * If some error is occured while ownership transfer,
767            * ownership transfer related resource should be revert back to initial status.
768            */
769          const OicSecDoxm_t* doxm = GetDoxmResourceData();
770          if(doxm && !doxm->owned)
771          {
772             OIC_LOG(WARNING, TAG, "The operation failed during handle DOXM request");
773
774             if (!isDuplicatedMsg)
775             {
776 #if defined (__WITH_TLS__) || defined(__WITH_DTLS__)
777                 InvokeOtmEventHandler(ehRequest->devAddr.addr, ehRequest->devAddr.port,
778                                           NULL, OIC_OTM_ERROR);
779 #endif
780                 ResetSecureResourceInPS();
781                 OIC_LOG(INFO, TAG, "DOXM will be reverted.");
782             }
783          }
784          else
785          {
786              OIC_LOG(ERROR, TAG, "Invalid DOXM resource.");
787              ResetSecureResourceInPS();
788          }
789      }
790      else
791      {
792         if(ehRequest->devAddr.adapter == OC_ADAPTER_IP)
793         {
794             previousMsgId = ehRequest->messageID;
795         }
796      }
797
798     // Send response payload to request originator
799     ehRet = ((SendSRMResponse(ehRequest, ehRet, NULL, 0)) == OC_STACK_OK) ?
800                    OC_EH_OK : OC_EH_ERROR;
801
802     DeletePstatBinData(pstat);
803     return ehRet;
804 }
805
806 /**
807  * This internal method is the entity handler for pstat resources.
808  */
809  OCEntityHandlerResult PstatEntityHandler(OCEntityHandlerFlag flag,
810                                           OCEntityHandlerRequest * ehRequest,
811                                           void *callbackParam)
812 {
813     (void)callbackParam;
814     OCEntityHandlerResult ehRet = OC_EH_ERROR;
815     // This method will handle REST request (GET/POST) for /oic/sec/pstat
816     if (flag & OC_REQUEST_FLAG)
817     {
818         OIC_LOG(INFO, TAG, "Flag includes OC_REQUEST_FLAG");
819         switch (ehRequest->method)
820         {
821             case OC_REST_GET:
822                 ehRet = HandlePstatGetRequest(ehRequest);
823                 break;
824             case OC_REST_POST:
825                 ehRet = HandlePstatPostRequest(ehRequest);
826                 break;
827             default:
828                 ehRet = ((SendSRMResponse(ehRequest, ehRet, NULL, 0)) == OC_STACK_OK) ?
829                                OC_EH_OK : OC_EH_ERROR;
830                 break;
831         }
832     }
833     return ehRet;
834 }
835
836 /**
837  * This internal method is used to create '/oic/sec/pstat' resource.
838  */
839  OCStackResult CreatePstatResource()
840 {
841     OCStackResult ret = OCCreateResource(&gPstatHandle,
842                                          OIC_RSRC_TYPE_SEC_PSTAT,
843                                          OC_RSRVD_INTERFACE_DEFAULT,
844                                          OIC_RSRC_PSTAT_URI,
845                                          PstatEntityHandler,
846                                          NULL,
847                                          OC_SECURE |
848                                          OC_DISCOVERABLE);
849
850     if (OC_STACK_OK != ret)
851     {
852         OIC_LOG(FATAL, TAG, "Unable to instantiate pstat resource");
853         DeInitPstatResource();
854     }
855     return ret;
856 }
857
858 /**
859  * Get the default value.
860  *
861  * @return the gDefaultPstat pointer.
862  */
863 static OicSecPstat_t* GetPstatDefault()
864 {
865     return &gDefaultPstat;
866 }
867
868 OCStackResult InitPstatResource()
869 {
870     OCStackResult ret = OC_STACK_ERROR;
871
872     // Read Pstat resource from PS
873     uint8_t *data = NULL;
874     size_t size = 0;
875     OicUuid_t emptyUuid = {.id={0}};
876     ret = GetSecureVirtualDatabaseFromPS(OIC_JSON_PSTAT_NAME, &data, &size);
877     // If database read failed
878     if (OC_STACK_OK != ret)
879     {
880         OIC_LOG (DEBUG, TAG, "ReadSVDataFromPS failed");
881     }
882     if (data)
883     {
884         // Read ACL resource from PS
885         ret = CBORPayloadToPstat(data, size, &gPstat);
886         OICFree(data);
887     }
888     /*
889      * If SVR database in persistent storage got corrupted or
890      * is not available for some reason, a default pstat is created
891      * which allows user to initiate pstat provisioning again.
892      */
893     if ((OC_STACK_OK != ret) || !gPstat)
894     {
895         gPstat = GetPstatDefault();
896     }
897     VERIFY_NON_NULL(TAG, gPstat, FATAL);
898
899     //In case of Pstat's device id is empty, fill the device id as doxm's device id.
900     if(0 == memcmp(&gPstat->deviceID, &emptyUuid, sizeof(OicUuid_t)))
901     {
902         OicUuid_t doxmUuid = {.id={0}};
903         if(OC_STACK_OK == GetDoxmDeviceID(&doxmUuid))
904         {
905             memcpy(&gPstat->deviceID, &doxmUuid, sizeof(OicUuid_t));
906         }
907     }
908
909     // Instantiate 'oic.sec.pstat'
910     ret = CreatePstatResource();
911
912 exit:
913     if (OC_STACK_OK != ret)
914     {
915         DeInitPstatResource();
916     }
917     return ret;
918 }
919
920 OCStackResult DeInitPstatResource()
921 {
922     if (gPstat != &gDefaultPstat)
923     {
924         DeletePstatBinData(gPstat);
925         gPstat = NULL;
926     }
927     return OCDeleteResource(gPstatHandle);
928 }
929
930 /**
931  * Function to restore pstat resurce to initial status.
932  * This function will use in case of error while ownership transfer
933  */
934 void RestorePstatToInitState()
935 {
936     if(gPstat)
937     {
938         OIC_LOG(INFO, TAG, "PSTAT resource will revert back to initial status.");
939
940         gPstat->cm = (OicSecDpm_t)(gPstat->cm | TAKE_OWNER);
941         gPstat->tm = (OicSecDpm_t)(gPstat->tm & (~TAKE_OWNER));
942         gPstat->om = SINGLE_SERVICE_CLIENT_DRIVEN;
943         if(gPstat->sm && 0 < gPstat->smLen)
944         {
945             gPstat->sm[0] = SINGLE_SERVICE_CLIENT_DRIVEN;
946         }
947
948         if (!UpdatePersistentStorage(gPstat))
949         {
950             OIC_LOG(ERROR, TAG, "Failed to revert PSTAT in persistent storage");
951         }
952     }
953 }
954
955 OCStackResult SetPstatRownerId(const OicUuid_t* newROwner)
956 {
957     OCStackResult ret = OC_STACK_ERROR;
958     uint8_t *cborPayload = NULL;
959     size_t size = 0;
960     OicUuid_t prevId = {.id={0}};
961
962     if(NULL == newROwner)
963     {
964         ret = OC_STACK_INVALID_PARAM;
965     }
966     if(NULL == gPstat)
967     {
968         ret = OC_STACK_NO_RESOURCE;
969     }
970
971     if(newROwner && gPstat)
972     {
973         memcpy(prevId.id, gPstat->rownerID.id, sizeof(prevId.id));
974         memcpy(gPstat->rownerID.id, newROwner->id, sizeof(newROwner->id));
975
976         ret = PstatToCBORPayload(gPstat, &cborPayload, &size, false);
977         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
978
979         ret = UpdateSecureResourceInPS(OIC_JSON_PSTAT_NAME, cborPayload, size);
980         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
981
982         OICFree(cborPayload);
983     }
984
985     return ret;
986
987 exit:
988     OICFree(cborPayload);
989     memcpy(gPstat->rownerID.id, prevId.id, sizeof(prevId.id));
990     return ret;
991 }
992
993 /**
994  * This function returns the "isop" status of the device.
995  *
996  * @return true iff pstat.isop == 1, else false
997  */
998 bool GetPstatIsop()
999 {
1000     if(NULL != gPstat)
1001     {
1002         return gPstat->isOp;
1003     }
1004     else
1005     {
1006         //In case of gPstat is NULL
1007         return false;
1008     }
1009 }
1010
1011 OCStackResult GetPstatRownerId(OicUuid_t *rowneruuid)
1012 {
1013     OCStackResult retVal = OC_STACK_ERROR;
1014     if (gPstat)
1015     {
1016         *rowneruuid = gPstat->rownerID;
1017         retVal = OC_STACK_OK;
1018     }
1019     return retVal;
1020 }
1021
1022 OCStackResult SetPstatSelfOwnership(const OicUuid_t* newROwner)
1023 {
1024     OCStackResult ret = OC_STACK_ERROR;
1025     uint8_t *cborPayload = NULL;
1026     size_t size = 0;
1027
1028     if(NULL == gPstat)
1029     {
1030         ret = OC_STACK_NO_RESOURCE;
1031         return ret;
1032     }
1033
1034     if( newROwner && (false == gPstat->isOp) && (true == (TAKE_OWNER && gPstat->cm)) )
1035     {
1036         gPstat->cm = (OicSecDpm_t)(gPstat->cm & (~TAKE_OWNER));
1037         gPstat->isOp = true;
1038
1039         memcpy(gPstat->deviceID.id, newROwner->id, sizeof(newROwner->id));
1040         memcpy(gPstat->rownerID.id, newROwner->id, sizeof(newROwner->id));
1041
1042         ret = PstatToCBORPayload(gPstat, &cborPayload, &size, false);
1043         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
1044
1045         ret = UpdateSecureResourceInPS(OIC_JSON_PSTAT_NAME, cborPayload, size);
1046         VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
1047
1048         OICFree(cborPayload);
1049     }
1050     else
1051     {
1052         OIC_LOG(ERROR, TAG, "The state of PSTAT is not Ready For OTM");
1053     }
1054
1055     return ret;
1056
1057 exit:
1058     OICFree(cborPayload);
1059     return ret;
1060 }
1061