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