1 //******************************************************************
3 // Copyright 2015 Intel Mobile Communications GmbH All Rights Reserved.
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
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
11 // http://www.apache.org/licenses/LICENSE-2.0
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.
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
25 #include "oic_malloc.h"
26 #include "ocpayload.h"
27 #include "payload_logging.h"
28 #include "resourcemanager.h"
29 #include "pstatresource.h"
30 #include "doxmresource.h"
31 #include "psinterface.h"
32 #include "srmresourcestrings.h"
33 #include "srmutility.h"
35 #define TAG "SRM-PSTAT"
37 /** Default cbor payload size. This value is increased in case of CborErrorOutOfMemory.
38 * The value of payload size is increased until reaching below max cbor size. */
39 static const uint16_t CBOR_SIZE = 512;
41 // Max cbor size payload.
42 static const uint16_t CBOR_MAX_SIZE = 4400;
44 // PSTAT Map size - Number of mandatory items
45 static const uint8_t PSTAT_MAP_SIZE = 7;
47 static OicSecDpom_t gSm = SINGLE_SERVICE_CLIENT_DRIVEN;
48 static OicSecPstat_t gDefaultPstat =
50 false, // bool isOwned
51 (OicSecDpm_t)(BOOTSTRAP_SERVICE | SECURITY_MANAGEMENT_SERVICES |
52 PROVISION_CREDENTIALS | PROVISION_ACLS), // OicSecDpm_t cm
53 (OicSecDpm_t)(TAKE_OWNER | BOOTSTRAP_SERVICE | SECURITY_MANAGEMENT_SERVICES |
54 PROVISION_CREDENTIALS | PROVISION_ACLS), // OicSecDpm_t tm
55 {.id = {0}}, // OicUuid_t deviceID
56 SINGLE_SERVICE_CLIENT_DRIVEN, // OicSecDpom_t om */
57 1, // the number of elts in Sms
58 &gSm, // OicSecDpom_t *sm
59 0, // uint16_t commitHash
60 {.id = {0}}, // OicUuid_t rownerID
63 static OicSecPstat_t *gPstat = NULL;
65 static OCResourceHandle gPstatHandle = NULL;
67 void DeletePstatBinData(OicSecPstat_t* pstat)
71 //Clean 'supported modes' field
79 OCStackResult PstatToCBORPayload(const OicSecPstat_t *pstat, uint8_t **payload, size_t *size)
81 if (NULL == pstat || NULL == payload || NULL != *payload || NULL == size)
83 return OC_STACK_INVALID_PARAM;
86 size_t cborLen = *size;
95 OCStackResult ret = OC_STACK_ERROR;
97 CborEncoder encoder = { {.ptr = NULL }, .end = 0 };
98 CborEncoder pstatMap = { {.ptr = NULL }, .end = 0 };
101 int64_t cborEncoderResult = CborNoError;
103 uint8_t *outPayload = (uint8_t *)OICCalloc(1, cborLen);
104 VERIFY_NON_NULL(TAG, outPayload, ERROR);
105 cbor_encoder_init(&encoder, outPayload, cborLen, 0);
107 cborEncoderResult = cbor_encoder_create_map(&encoder, &pstatMap, PSTAT_MAP_SIZE);
108 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Pstat Map.");
110 cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_ISOP_NAME,
111 strlen(OIC_JSON_ISOP_NAME));
112 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ISOP Name Tag.");
113 cborEncoderResult = cbor_encode_boolean(&pstatMap, pstat->isOp);
114 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ISOP Name Value.");
116 cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_DEVICE_ID_NAME,
117 strlen(OIC_JSON_DEVICE_ID_NAME));
118 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Device Id Tag.");
119 ret = ConvertUuidToStr(&pstat->deviceID, &strUuid);
120 VERIFY_SUCCESS(TAG, OC_STACK_OK == ret , ERROR);
121 cborEncoderResult = cbor_encode_text_string(&pstatMap, strUuid, strlen(strUuid));
122 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Device Id Value.");
126 cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_CM_NAME,
127 strlen(OIC_JSON_CM_NAME));
128 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding CM Name Tag.");
129 cborEncoderResult = cbor_encode_int(&pstatMap, pstat->cm);
130 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding CM Name Value.");
132 cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_TM_NAME,
133 strlen(OIC_JSON_TM_NAME));
134 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding TM Name Tag.");
135 cborEncoderResult = cbor_encode_int(&pstatMap, pstat->tm);
136 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding TM Name Value.");
138 cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_OM_NAME,
139 strlen(OIC_JSON_OM_NAME));
140 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding OM Name Tag.");
141 cborEncoderResult = cbor_encode_int(&pstatMap, pstat->om);
142 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding OM Name Value.");
144 cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_SM_NAME,
145 strlen(OIC_JSON_SM_NAME));
146 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding SM Name Tag.");
148 CborEncoder sm = {{.ptr = NULL }, .end = 0 };
149 cborEncoderResult = cbor_encoder_create_array(&pstatMap, &sm, pstat->smLen);
150 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding SM Array.");
152 for (size_t i = 0; i < pstat->smLen; i++)
154 cborEncoderResult = cbor_encode_int(&sm, pstat->sm[i]);
155 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding SM Value in Array.");
157 cborEncoderResult = cbor_encoder_close_container(&pstatMap, &sm);
158 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing SM Array.");
161 cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_ROWNERID_NAME,
162 strlen(OIC_JSON_ROWNERID_NAME));
163 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ROwner Id Tag.");
164 ret = ConvertUuidToStr(&pstat->rownerID, &strUuid);
165 VERIFY_SUCCESS(TAG, OC_STACK_OK == ret , ERROR);
166 cborEncoderResult = cbor_encode_text_string(&pstatMap, strUuid, strlen(strUuid));
167 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ROwner Id Value.");
171 cborEncoderResult = cbor_encoder_close_container(&encoder, &pstatMap);
172 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Closing PSTAT Map.");
174 if (CborNoError == cborEncoderResult)
176 *size = encoder.ptr - outPayload;
177 *payload = outPayload;
181 if ((CborErrorOutOfMemory == cborEncoderResult) && (cborLen < CBOR_MAX_SIZE))
183 // reallocate and try again!
185 // Since the allocated initial memory failed, double the memory.
186 cborLen += encoder.ptr - encoder.end;
187 cborEncoderResult = CborNoError;
188 ret = PstatToCBORPayload(pstat, payload, &cborLen);
189 if (OC_STACK_OK == ret)
195 if ((CborNoError != cborEncoderResult) || (OC_STACK_OK != ret))
201 ret = OC_STACK_ERROR;
207 OCStackResult CBORPayloadToPstat(const uint8_t *cborPayload, const size_t size,
208 OicSecPstat_t **secPstat)
210 if (NULL == cborPayload || NULL == secPstat || NULL != *secPstat)
212 return OC_STACK_INVALID_PARAM;
215 OCStackResult ret = OC_STACK_ERROR;
220 CborError cborFindResult = CborNoError;
221 char *strUuid = NULL;
228 cbor_parser_init(cborPayload, cborLen, 0, &parser, &pstatCbor);
229 CborValue pstatMap = { .parser = NULL };
231 OicSecPstat_t *pstat = NULL;
232 cborFindResult = cbor_value_enter_container(&pstatCbor, &pstatMap);
233 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding PSTAT Map.");
235 pstat = (OicSecPstat_t *)OICCalloc(1, sizeof(OicSecPstat_t));
236 VERIFY_NON_NULL(TAG, pstat, ERROR);
238 cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_ISOP_NAME, &pstatMap);
239 if (CborNoError == cborFindResult && cbor_value_is_boolean(&pstatMap))
241 cborFindResult = cbor_value_get_boolean(&pstatMap, &pstat->isOp);
242 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding isOp Value.");
245 cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_DEVICE_ID_NAME, &pstatMap);
246 if (CborNoError == cborFindResult && cbor_value_is_text_string(&pstatMap))
248 cborFindResult = cbor_value_dup_text_string(&pstatMap, &strUuid , &len, NULL);
249 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding Device Id Value.");
250 ret = ConvertStrToUuid(strUuid , &pstat->deviceID);
251 VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
256 cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_CM_NAME, &pstatMap);
257 if (CborNoError == cborFindResult && cbor_value_is_integer(&pstatMap))
259 cborFindResult = cbor_value_get_int(&pstatMap, (int *) &pstat->cm);
260 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding CM.");
263 cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_TM_NAME, &pstatMap);
264 if (CborNoError == cborFindResult && cbor_value_is_integer(&pstatMap))
266 cborFindResult = cbor_value_get_int(&pstatMap, (int *) &pstat->tm);
267 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding TM.");
270 cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_OM_NAME, &pstatMap);
271 if (CborNoError == cborFindResult && cbor_value_is_integer(&pstatMap))
273 cborFindResult = cbor_value_get_int(&pstatMap, (int *) &pstat->om);
274 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding OM.");
277 cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_SM_NAME, &pstatMap);
278 if (CborNoError == cborFindResult && cbor_value_is_array(&pstatMap))
280 CborValue sm = { .parser = NULL };
281 cborFindResult = cbor_value_get_array_length(&pstatMap, &pstat->smLen);
282 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding Array Len.");
284 pstat->sm = (OicSecDpom_t *)OICCalloc(pstat->smLen, sizeof(OicSecDpom_t));
285 VERIFY_NON_NULL(TAG, pstat->sm, ERROR);
287 cborFindResult = cbor_value_enter_container(&pstatMap, &sm);
288 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Entering SM.");
291 while (cbor_value_is_valid(&sm))
293 cborFindResult = cbor_value_get_int(&sm, (int *)&pstat->sm[i++]);
294 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding SM.");
295 cborFindResult = cbor_value_advance(&sm);
296 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Closing SM.");
300 cborFindResult = cbor_value_map_find_value(&pstatCbor, OIC_JSON_ROWNERID_NAME, &pstatMap);
301 if (CborNoError == cborFindResult && cbor_value_is_text_string(&pstatMap))
303 cborFindResult = cbor_value_dup_text_string(&pstatMap, &strUuid , &len, NULL);
304 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding ROwner Id Value.");
305 ret = ConvertStrToUuid(strUuid , &pstat->rownerID);
306 VERIFY_SUCCESS(TAG, OC_STACK_OK == ret, ERROR);
315 if (CborNoError != cborFindResult)
317 OIC_LOG(ERROR, TAG, "CBORPayloadToPstat failed");
318 DeletePstatBinData(pstat);
321 ret = OC_STACK_ERROR;
328 * Function to update persistent storage
330 static bool UpdatePersistentStorage(OicSecPstat_t *pstat)
335 uint8_t *cborPayload = NULL;
336 OCStackResult ret = PstatToCBORPayload(pstat, &cborPayload, &size);
337 if (OC_STACK_OK == ret)
339 if (OC_STACK_OK == UpdateSecureResourceInPS(OIC_JSON_PSTAT_NAME, cborPayload, size))
343 OICFree(cborPayload);
351 * The entity handler determines how to process a GET request.
353 static OCEntityHandlerResult HandlePstatGetRequest (const OCEntityHandlerRequest * ehRequest)
355 OIC_LOG(INFO, TAG, "HandlePstatGetRequest processing GET request");
357 // Convert ACL data into CBOR for transmission
359 uint8_t *payload = NULL;
360 OCStackResult res = PstatToCBORPayload(gPstat, &payload, &size);
362 // A device should always have a default pstat. Therefore, payload should never be NULL.
363 OCEntityHandlerResult ehRet = (res == OC_STACK_OK) ? OC_EH_OK : OC_EH_ERROR;
365 // Send response payload to request originator
366 SendSRMCBORResponse(ehRequest, ehRet, payload, size);
372 * The entity handler determines how to process a POST request.
373 * Per the REST paradigm, POST can also be used to update representation of existing
374 * resource or create a new resource.
375 * For pstat, it updates only tm and om.
377 static OCEntityHandlerResult HandlePstatPutRequest(const OCEntityHandlerRequest *ehRequest)
379 OCEntityHandlerResult ehRet = OC_EH_ERROR;
380 OIC_LOG(INFO, TAG, "HandlePstatPutRequest processing PUT request");
381 OicSecPstat_t *pstat = NULL;
383 if (ehRequest->resource)
385 uint8_t *payload = ((OCSecurityPayload *) ehRequest->payload)->securityData1;
386 size_t size = ((OCSecurityPayload *) ehRequest->payload)->payloadSize;
387 VERIFY_NON_NULL(TAG, payload, ERROR);
389 OCStackResult ret = CBORPayloadToPstat(payload, size, &pstat);
391 VERIFY_NON_NULL(TAG, pstat, ERROR);
392 if (OC_STACK_OK == ret)
394 if (false == (pstat->cm & TAKE_OWNER))
397 gPstat->cm = pstat->cm;
398 OIC_LOG (INFO, TAG, "Taken owner succeed and isOp is TRUE");
402 OIC_LOG(DEBUG, TAG, "Taken owner failed");
404 if (pstat->om != MULTIPLE_SERVICE_SERVER_DRIVEN && gPstat)
407 * Check if the operation mode is in the supported provisioning services
408 * operation mode list.
410 for (size_t i=0; i< gPstat->smLen; i++)
412 if(gPstat->sm[i] == pstat->om)
414 gPstat->om = pstat->om;
419 // Convert pstat data into CBOR for update to persistent storage
420 if (UpdatePersistentStorage(gPstat))
427 if(OC_EH_OK != ehRet)
430 * If some error is occured while ownership transfer,
431 * ownership transfer related resource should be revert back to initial status.
433 RestoreDoxmToInitState();
434 RestorePstatToInitState();
437 //Send payload to request originator
438 if(OC_STACK_OK != SendSRMCBORResponse(ehRequest, ehRet, NULL, 0))
440 OIC_LOG (ERROR, TAG, "SendSRMResponse failed in HandlePstatPostRequest");
442 DeletePstatBinData(pstat);
447 * This internal method is the entity handler for pstat resources.
449 OCEntityHandlerResult PstatEntityHandler(OCEntityHandlerFlag flag,
450 OCEntityHandlerRequest * ehRequest,
454 OCEntityHandlerResult ehRet = OC_EH_ERROR;
455 // This method will handle REST request (GET/POST) for /oic/sec/pstat
456 if (flag & OC_REQUEST_FLAG)
458 OIC_LOG(INFO, TAG, "Flag includes OC_REQUEST_FLAG");
459 switch (ehRequest->method)
462 ehRet = HandlePstatGetRequest(ehRequest);
465 ehRet = HandlePstatPutRequest(ehRequest);
469 SendSRMCBORResponse(ehRequest, ehRet, NULL, 0);
477 * This internal method is used to create '/oic/sec/pstat' resource.
479 OCStackResult CreatePstatResource()
481 OCStackResult ret = OCCreateResource(&gPstatHandle,
482 OIC_RSRC_TYPE_SEC_PSTAT,
489 if (OC_STACK_OK != ret)
491 OIC_LOG(FATAL, TAG, "Unable to instantiate pstat resource");
492 DeInitPstatResource();
498 * Get the default value.
500 * @return the gDefaultPstat pointer.
502 static OicSecPstat_t* GetPstatDefault()
504 return &gDefaultPstat;
507 OCStackResult InitPstatResource()
509 OCStackResult ret = OC_STACK_ERROR;
511 // Read Pstat resource from PS
512 uint8_t *data = NULL;
514 ret = GetSecureVirtualDatabaseFromPS(OIC_JSON_PSTAT_NAME, &data, &size);
515 // If database read failed
516 if (OC_STACK_OK != ret)
518 OIC_LOG (DEBUG, TAG, "ReadSVDataFromPS failed");
522 // Read ACL resource from PS
523 ret = CBORPayloadToPstat(data, size, &gPstat);
527 * If SVR database in persistent storage got corrupted or
528 * is not available for some reason, a default pstat is created
529 * which allows user to initiate pstat provisioning again.
531 if ((OC_STACK_OK != ret) || !gPstat)
533 gPstat = GetPstatDefault();
535 VERIFY_NON_NULL(TAG, gPstat, FATAL);
537 // Instantiate 'oic.sec.pstat'
538 ret = CreatePstatResource();
541 if (OC_STACK_OK != ret)
543 DeInitPstatResource();
548 OCStackResult DeInitPstatResource()
550 if (gPstat != &gDefaultPstat)
552 DeletePstatBinData(gPstat);
555 return OCDeleteResource(gPstatHandle);
559 * Function to restore pstat resurce to initial status.
560 * This function will use in case of error while ownership transfer
562 void RestorePstatToInitState()
566 OIC_LOG(INFO, TAG, "PSTAT resource will revert back to initial status.");
568 gPstat->cm = (OicSecDpm_t)(gPstat->cm | TAKE_OWNER);
569 gPstat->tm = (OicSecDpm_t)(gPstat->tm & (~TAKE_OWNER));
570 gPstat->om = SINGLE_SERVICE_CLIENT_DRIVEN;
571 if(gPstat->sm && 0 < gPstat->smLen)
573 gPstat->sm[0] = SINGLE_SERVICE_CLIENT_DRIVEN;
576 if (!UpdatePersistentStorage(gPstat))
578 OIC_LOG(ERROR, TAG, "Failed to revert PSTAT in persistent storage");