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 uint8_t CBOR_SIZE = 255;
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)(TAKE_OWNER | 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
62 static OicSecPstat_t *gPstat = NULL;
64 static OCResourceHandle gPstatHandle = NULL;
66 void DeletePstatBinData(OicSecPstat_t* pstat)
70 //Clean 'supported modes' field
78 OCStackResult PstatToCBORPayload(const OicSecPstat_t *pstat, uint8_t **payload, size_t *size)
80 if (NULL == pstat || NULL == payload || NULL != *payload || NULL == size)
82 return OC_STACK_INVALID_PARAM;
85 size_t cborLen = *size;
94 OCStackResult ret = OC_STACK_ERROR;
96 CborEncoder encoder = { {.ptr = NULL }, .end = 0 };
97 CborEncoder pstatMap = { {.ptr = NULL }, .end = 0 };
99 CborError cborEncoderResult = CborNoError;
101 uint8_t *outPayload = (uint8_t *)OICCalloc(1, cborLen);
102 VERIFY_NON_NULL(TAG, outPayload, ERROR);
103 cbor_encoder_init(&encoder, outPayload, cborLen, 0);
105 cborEncoderResult = cbor_encoder_create_map(&encoder, &pstatMap, PSTAT_MAP_SIZE);
106 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Pstat Map.");
108 cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_ISOP_NAME,
109 strlen(OIC_JSON_ISOP_NAME));
110 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ISOP Name Tag.");
111 cborEncoderResult = cbor_encode_boolean(&pstatMap, pstat->isOp);
112 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding ISOP Name Value.");
114 cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_DEVICE_ID_NAME,
115 strlen(OIC_JSON_DEVICE_ID_NAME));
116 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Device Id Tag.");
117 cborEncoderResult = cbor_encode_byte_string(&pstatMap, (uint8_t *)pstat->deviceID.id,
118 sizeof(pstat->deviceID.id));
119 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Device Id Value.");
121 cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_COMMIT_HASH_NAME,
122 strlen(OIC_JSON_COMMIT_HASH_NAME));
123 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Commit Hash Tag.");
124 cborEncoderResult = cbor_encode_int(&pstatMap, pstat->commitHash);
125 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Commit Hash Value.");
127 cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_CM_NAME,
128 strlen(OIC_JSON_CM_NAME));
129 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding CM Name Tag.");
130 cborEncoderResult = cbor_encode_int(&pstatMap, pstat->cm);
131 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding CM Name Value.");
133 cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_TM_NAME,
134 strlen(OIC_JSON_TM_NAME));
135 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding TM Name Tag.");
136 cborEncoderResult = cbor_encode_int(&pstatMap, pstat->tm);
137 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding TM Name Value.");
139 cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_OM_NAME,
140 strlen(OIC_JSON_OM_NAME));
141 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding OM Name Tag.");
142 cborEncoderResult = cbor_encode_int(&pstatMap, pstat->om);
143 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding OM Name Value.");
145 cborEncoderResult = cbor_encode_text_string(&pstatMap, OIC_JSON_SM_NAME,
146 strlen(OIC_JSON_SM_NAME));
147 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding SM Name Tag.");
149 CborEncoder sm = { {.ptr = NULL }, .end = 0 };
150 cborEncoderResult = cbor_encoder_create_array(&pstatMap, &sm, pstat->smLen);
151 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding SM Array.");
153 for (size_t i = 0; i < pstat->smLen; i++)
155 cborEncoderResult = cbor_encode_int(&sm, pstat->sm[i]);
156 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding SM Value in Array.");
158 cborEncoderResult = cbor_encoder_close_container(&pstatMap, &sm);
159 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing SM Array.");
161 cborEncoderResult = cbor_encoder_close_container(&encoder, &pstatMap);
162 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Closing PSTAT Map.");
164 *size = encoder.ptr - outPayload;
165 *payload = outPayload;
169 if ((CborErrorOutOfMemory == cborEncoderResult) && (cborLen < CBOR_MAX_SIZE))
171 // reallocate and try again!
173 // Since the allocated initial memory failed, double the memory.
174 cborLen += encoder.ptr - encoder.end;
175 cborEncoderResult = CborNoError;
176 ret = PstatToCBORPayload(pstat, payload, &cborLen);
179 if ((CborNoError != cborEncoderResult) || (OC_STACK_OK != ret))
185 ret = OC_STACK_ERROR;
191 OCStackResult CBORPayloadToPstat(const uint8_t *cborPayload, const size_t size,
192 OicSecPstat_t **secPstat)
194 if (NULL == cborPayload || NULL == secPstat || NULL != *secPstat)
196 return OC_STACK_INVALID_PARAM;
199 OCStackResult ret = OC_STACK_ERROR;
202 CborValue pstatCbor = { .parser = NULL };
203 CborParser parser = { .end = NULL };
204 CborError cborFindResult = CborNoError;
210 cbor_parser_init(cborPayload, cborLen, 0, &parser, &pstatCbor);
211 CborValue pstatMap = { .parser = NULL } ;
212 OicSecPstat_t *pstat = NULL;
214 cborFindResult = cbor_value_enter_container(&pstatCbor, &pstatMap);
215 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding PSTAT Map.");
217 pstat = (OicSecPstat_t *)OICCalloc(1, sizeof(OicSecPstat_t));
218 VERIFY_NON_NULL(TAG, pstat, ERROR);
220 while (cbor_value_is_valid(&pstatMap))
223 cborFindResult = cbor_value_dup_text_string(&pstatMap, &name, &len, NULL);
224 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding PSTAT Name Value.");
225 cborFindResult = cbor_value_advance(&pstatMap);
226 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Advancing PSTAT MAP.");
228 CborType type = cbor_value_get_type(&pstatMap);
230 if (0 == strcmp(OIC_JSON_ISOP_NAME, name))
232 cborFindResult = cbor_value_get_boolean(&pstatMap, &pstat->isOp);
233 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding ISOP Name.");
236 if (0 == strcmp(OIC_JSON_DEVICE_ID_NAME, name))
238 uint8_t *subjectId = NULL;
239 cborFindResult = cbor_value_dup_byte_string(&pstatMap, &subjectId, &len, NULL);
240 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding SubjectId.");
241 memcpy(pstat->deviceID.id, subjectId, len);
245 if (0 == strcmp(OIC_JSON_COMMIT_HASH_NAME, name))
247 cborFindResult = cbor_value_get_int(&pstatMap, (int *) &pstat->commitHash);
248 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding CommitHash.");
251 if (0 == strcmp(OIC_JSON_CM_NAME, name))
253 cborFindResult = cbor_value_get_int(&pstatMap, (int *) &pstat->cm);
254 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding CM Name.");
257 if (0 == strcmp(OIC_JSON_OM_NAME, name))
259 cborFindResult = cbor_value_get_int(&pstatMap, (int *) &pstat->om);
260 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding OM Name.");
263 if (0 == strcmp(OIC_JSON_SM_NAME, name))
265 CborValue sm = { .parser = NULL };
267 cborFindResult = cbor_value_get_array_length(&pstatMap, &pstat->smLen);
268 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding SM Len Array.");
269 VERIFY_SUCCESS(TAG, pstat->smLen != 0, ERROR);
271 pstat->sm = (OicSecDpom_t *)OICCalloc(pstat->smLen, sizeof(OicSecDpom_t));
272 VERIFY_NON_NULL(TAG, pstat->sm, ERROR);
274 cborFindResult = cbor_value_enter_container(&pstatMap, &sm);
275 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding SM Container.");
278 while (cbor_value_is_valid(&sm))
280 cborFindResult = cbor_value_get_int(&sm, (int *)&pstat->sm[i++]);
281 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding SM Value.");
282 cborFindResult = cbor_value_advance(&sm);
283 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding SM Array.");
286 if (CborMapType != type && cbor_value_is_valid(&pstatMap))
288 cborFindResult = cbor_value_advance(&pstatMap);
289 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding PSTAT MAP.");
299 if (CborNoError != cborFindResult)
301 OIC_LOG(ERROR, TAG, "CBORPayloadToPstat failed");
302 DeletePstatBinData(pstat);
304 ret = OC_STACK_ERROR;
314 * Function to update persistent storage
316 static bool UpdatePersistentStorage(OicSecPstat_t *pstat)
321 uint8_t *cborPayload = NULL;
322 OCStackResult ret = PstatToCBORPayload(pstat, &cborPayload, &size);
323 if (OC_STACK_OK == ret)
325 if (OC_STACK_OK == UpdateSecureResourceInPS(OIC_JSON_PSTAT_NAME, cborPayload, size))
329 OICFree(cborPayload);
337 * The entity handler determines how to process a GET request.
339 static OCEntityHandlerResult HandlePstatGetRequest (const OCEntityHandlerRequest * ehRequest)
341 OIC_LOG(INFO, TAG, "HandlePstatGetRequest processing GET request");
343 // Convert ACL data into CBOR for transmission
345 uint8_t *payload = NULL;
346 OCStackResult res = PstatToCBORPayload(gPstat, &payload, &size);
348 // A device should always have a default pstat. Therefore, payload should never be NULL.
349 OCEntityHandlerResult ehRet = (res == OC_STACK_OK) ? OC_EH_OK : OC_EH_ERROR;
351 // Send response payload to request originator
352 SendSRMCBORResponse(ehRequest, ehRet, payload);
358 * The entity handler determines how to process a POST request.
359 * Per the REST paradigm, POST can also be used to update representation of existing
360 * resource or create a new resource.
361 * For pstat, it updates only tm and om.
363 static OCEntityHandlerResult HandlePstatPutRequest(const OCEntityHandlerRequest *ehRequest)
365 OCEntityHandlerResult ehRet = OC_EH_ERROR;
366 OIC_LOG(INFO, TAG, "HandlePstatPutRequest processing PUT request");
367 OicSecPstat_t *pstat = NULL;
369 if (ehRequest->resource)
371 uint8_t *payload = ((OCSecurityPayload *) ehRequest->payload)->securityData1;
372 VERIFY_NON_NULL(TAG, payload, ERROR);
374 OCStackResult ret = CBORPayloadToPstat(payload, CBOR_SIZE, &pstat);
376 VERIFY_NON_NULL(TAG, pstat, ERROR);
377 if (OC_STACK_OK == ret)
381 gPstat->tm = pstat->tm;
382 if(0 == pstat->tm && gPstat->commitHash == pstat->commitHash)
386 OIC_LOG (INFO, TAG, "CommitHash is valid and isOp is TRUE");
390 OIC_LOG(DEBUG, TAG, "CommitHash is not valid");
393 if (pstat->om && gPstat)
396 * Check if the operation mode is in the supported provisioning services
397 * operation mode list.
399 for(size_t i=0; i< gPstat->smLen; i++)
401 if(gPstat->sm[i] == pstat->om)
403 gPstat->om = pstat->om;
408 // Convert pstat data into CBOR for update to persistent storage
409 if(UpdatePersistentStorage(gPstat))
418 if(OC_EH_OK != ehRet)
421 * If some error is occured while ownership transfer,
422 * ownership transfer related resource should be revert back to initial status.
424 RestoreDoxmToInitState();
425 RestorePstatToInitState();
428 //Send payload to request originator
429 if(OC_STACK_OK != SendSRMCBORResponse(ehRequest, ehRet, NULL))
431 OIC_LOG (ERROR, TAG, "SendSRMResponse failed in HandlePstatPostRequest");
433 DeletePstatBinData(pstat);
438 * This internal method is the entity handler for pstat resources.
440 OCEntityHandlerResult PstatEntityHandler(OCEntityHandlerFlag flag,
441 OCEntityHandlerRequest * ehRequest,
445 OCEntityHandlerResult ehRet = OC_EH_ERROR;
446 // This method will handle REST request (GET/POST) for /oic/sec/pstat
447 if (flag & OC_REQUEST_FLAG)
449 OIC_LOG(INFO, TAG, "Flag includes OC_REQUEST_FLAG");
450 switch (ehRequest->method)
453 ehRet = HandlePstatGetRequest(ehRequest);
456 ehRet = HandlePstatPutRequest(ehRequest);
460 SendSRMCBORResponse(ehRequest, ehRet, NULL);
468 * This internal method is used to create '/oic/sec/pstat' resource.
470 OCStackResult CreatePstatResource()
472 OCStackResult ret = OCCreateResource(&gPstatHandle,
473 OIC_RSRC_TYPE_SEC_PSTAT,
480 if (OC_STACK_OK != ret)
482 OIC_LOG(FATAL, TAG, "Unable to instantiate pstat resource");
483 DeInitPstatResource();
489 * Get the default value.
491 * @return the gDefaultPstat pointer.
493 static OicSecPstat_t* GetPstatDefault()
495 return &gDefaultPstat;
498 OCStackResult InitPstatResource()
500 OCStackResult ret = OC_STACK_ERROR;
502 // Read Pstat resource from PS
503 uint8_t *data = NULL;
505 ret = GetSecureVirtualDatabaseFromPS(OIC_JSON_PSTAT_NAME, &data, &size);
506 // If database read failed
507 if (OC_STACK_OK != ret)
509 OIC_LOG (DEBUG, TAG, "ReadSVDataFromPS failed");
513 // Read ACL resource from PS
514 ret = CBORPayloadToPstat(data, size, &gPstat);
517 * If SVR database in persistent storage got corrupted or
518 * is not available for some reason, a default pstat is created
519 * which allows user to initiate pstat provisioning again.
521 if ((OC_STACK_OK != ret) || !data || !gPstat)
523 gPstat = GetPstatDefault();
525 VERIFY_NON_NULL(TAG, gPstat, FATAL);
527 // Instantiate 'oic.sec.pstat'
528 ret = CreatePstatResource();
532 if (OC_STACK_OK != ret)
534 DeInitPstatResource();
540 * Perform cleanup for pstat resources.
542 * @retval OC_STACK_OK for Success, otherwise some error value
544 OCStackResult DeInitPstatResource()
546 if(gPstat != &gDefaultPstat)
548 DeletePstatBinData(gPstat);
551 return OCDeleteResource(gPstatHandle);
555 * Function to restore pstat resurce to initial status.
556 * This function will use in case of error while ownership transfer
558 void RestorePstatToInitState()
562 OIC_LOG(INFO, TAG, "PSTAT resource will revert back to initial status.");
566 gPstat->om = SINGLE_SERVICE_CLIENT_DRIVEN;
567 if(gPstat->sm && 0 < gPstat->smLen)
569 gPstat->sm[0] = SINGLE_SERVICE_CLIENT_DRIVEN;
572 if (!UpdatePersistentStorage(gPstat))
574 OIC_LOG(ERROR, TAG, "Failed to revert DOXM in persistent storage");