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