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 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
23 #include "oic_malloc.h"
25 #include "resourcemanager.h"
26 #include "pstatresource.h"
27 #include "doxmresource.h"
28 #include "psinterface.h"
31 #include "srmresourcestrings.h"
32 #include "srmutility.h"
36 #define TAG "SRM-PSTAT"
38 static OicSecDpom_t gSm = SINGLE_SERVICE_CLIENT_DRIVEN;
39 static OicSecPstat_t gDefaultPstat =
41 false, // bool isOwned
42 (OicSecDpm_t)(TAKE_OWNER | BOOTSTRAP_SERVICE | SECURITY_MANAGEMENT_SERVICES |
43 PROVISION_CREDENTIALS | PROVISION_ACLS), // OicSecDpm_t cm
44 (OicSecDpm_t)(TAKE_OWNER | BOOTSTRAP_SERVICE | SECURITY_MANAGEMENT_SERVICES |
45 PROVISION_CREDENTIALS | PROVISION_ACLS), // OicSecDpm_t tm
46 {.id = {0}}, // OicUuid_t deviceID
47 SINGLE_SERVICE_CLIENT_DRIVEN, // OicSecDpom_t om */
48 1, // the number of elts in Sms
49 &gSm, // OicSecDpom_t *sm
50 0, // uint16_t commitHash
53 static OicSecPstat_t *gPstat = NULL;
55 static OCResourceHandle gPstatHandle = NULL;
57 void DeletePstatBinData(OicSecPstat_t* pstat)
61 //Clean 'supported modes' field
69 char * BinToPstatJSON(const OicSecPstat_t * pstat)
76 cJSON *jsonPstat = NULL;
78 cJSON *jsonSmArray = NULL;
79 char base64Buff[B64ENCODE_OUT_SAFESIZE(sizeof(((OicUuid_t*) 0)->id)) + 1] = {};
81 B64Result b64Ret = B64_OK;
83 cJSON *jsonRoot = cJSON_CreateObject();
84 VERIFY_NON_NULL(TAG, jsonRoot, INFO);
86 cJSON_AddItemToObject(jsonRoot, OIC_JSON_PSTAT_NAME, jsonPstat=cJSON_CreateObject());
87 cJSON_AddBoolToObject(jsonPstat, OIC_JSON_ISOP_NAME, pstat->isOp);
89 b64Ret = b64Encode(pstat->deviceID.id,
90 sizeof(pstat->deviceID.id), base64Buff, sizeof(base64Buff), &outLen);
91 VERIFY_SUCCESS(TAG, b64Ret == B64_OK, ERROR);
93 cJSON_AddStringToObject(jsonPstat, OIC_JSON_DEVICE_ID_NAME, base64Buff);
94 cJSON_AddNumberToObject(jsonPstat, OIC_JSON_COMMIT_HASH_NAME, pstat->commitHash);
95 cJSON_AddNumberToObject(jsonPstat, OIC_JSON_CM_NAME, (int)pstat->cm);
96 cJSON_AddNumberToObject(jsonPstat, OIC_JSON_TM_NAME, (int)pstat->tm);
97 cJSON_AddNumberToObject(jsonPstat, OIC_JSON_OM_NAME, (int)pstat->om);
99 cJSON_AddItemToObject(jsonPstat, OIC_JSON_SM_NAME, jsonSmArray = cJSON_CreateArray());
100 VERIFY_NON_NULL(TAG, jsonSmArray, INFO);
101 for (size_t i = 0; i < pstat->smLen; i++)
103 cJSON_AddItemToArray(jsonSmArray, cJSON_CreateNumber((int )pstat->sm[i]));
105 jsonStr = cJSON_Print(jsonRoot);
110 cJSON_Delete(jsonRoot);
115 OicSecPstat_t * JSONToPstatBin(const char * jsonStr)
122 OCStackResult ret = OC_STACK_ERROR;
123 OicSecPstat_t *pstat = NULL;
124 cJSON *jsonPstat = NULL;
125 cJSON *jsonObj = NULL;
127 unsigned char base64Buff[sizeof(((OicUuid_t*) 0)->id)] = {};
129 B64Result b64Ret = B64_OK;
131 cJSON *jsonRoot = cJSON_Parse(jsonStr);
132 VERIFY_NON_NULL(TAG, jsonRoot, INFO);
134 jsonPstat = cJSON_GetObjectItem(jsonRoot, OIC_JSON_PSTAT_NAME);
135 VERIFY_NON_NULL(TAG, jsonPstat, INFO);
137 pstat = (OicSecPstat_t*)OICCalloc(1, sizeof(OicSecPstat_t));
138 VERIFY_NON_NULL(TAG, pstat, INFO);
139 jsonObj = cJSON_GetObjectItem(jsonPstat, OIC_JSON_ISOP_NAME);
140 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
141 VERIFY_SUCCESS(TAG, (cJSON_True == jsonObj->type || cJSON_False == jsonObj->type) , ERROR);
142 pstat->isOp = jsonObj->valueint;
144 jsonObj = cJSON_GetObjectItem(jsonPstat, OIC_JSON_DEVICE_ID_NAME);
145 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
146 VERIFY_SUCCESS(TAG, cJSON_String == jsonObj->type, ERROR);
147 b64Ret = b64Decode(jsonObj->valuestring, strlen(jsonObj->valuestring), base64Buff,
148 sizeof(base64Buff), &outLen);
149 VERIFY_SUCCESS(TAG, (b64Ret == B64_OK && outLen <= sizeof(pstat->deviceID.id)), ERROR);
150 memcpy(pstat->deviceID.id, base64Buff, outLen);
152 jsonObj = cJSON_GetObjectItem(jsonPstat, OIC_JSON_COMMIT_HASH_NAME);
153 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
154 VERIFY_SUCCESS(TAG, cJSON_Number == jsonObj->type, ERROR);
155 pstat->commitHash = jsonObj->valueint;
157 jsonObj = cJSON_GetObjectItem(jsonPstat, OIC_JSON_CM_NAME);
158 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
159 VERIFY_SUCCESS(TAG, cJSON_Number == jsonObj->type, ERROR);
160 pstat->cm = (OicSecDpm_t)jsonObj->valueint;
162 jsonObj = cJSON_GetObjectItem(jsonPstat, OIC_JSON_OM_NAME);
163 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
164 VERIFY_SUCCESS(TAG, cJSON_Number == jsonObj->type, ERROR);
165 pstat->om = (OicSecDpom_t)jsonObj->valueint;
167 jsonObj = cJSON_GetObjectItem(jsonPstat, OIC_JSON_SM_NAME);
168 VERIFY_NON_NULL(TAG, jsonObj, ERROR);
169 if (cJSON_Array == jsonObj->type)
171 pstat->smLen = cJSON_GetArraySize(jsonObj);
173 VERIFY_SUCCESS(TAG, pstat->smLen != 0, ERROR);
174 pstat->sm = (OicSecDpom_t*)OICCalloc(pstat->smLen, sizeof(OicSecDpom_t));
175 VERIFY_NON_NULL(TAG, pstat->sm, ERROR);
178 cJSON *jsonSm = cJSON_GetArrayItem(jsonObj, idxx);
179 VERIFY_NON_NULL(TAG, jsonSm, ERROR);
180 pstat->sm[idxx] = (OicSecDpom_t)jsonSm->valueint;
181 }while ( ++idxx < pstat->smLen);
186 cJSON_Delete(jsonRoot);
187 if (OC_STACK_OK != ret)
189 OIC_LOG (ERROR, TAG, "JSONToPstatBin failed");
190 DeletePstatBinData(pstat);
197 * Function to update persistent storage
199 static bool UpdatePersistentStorage(OicSecPstat_t * pstat)
205 // Convert pstat data into JSON for update to persistent storage
206 char *jsonStr = BinToPstatJSON(pstat);
209 cJSON *jsonPstat = cJSON_Parse(jsonStr);
213 (OC_STACK_OK == UpdateSVRDatabase(OIC_JSON_PSTAT_NAME, jsonPstat)))
217 cJSON_Delete(jsonPstat);
226 * The entity handler determines how to process a GET request.
228 static OCEntityHandlerResult HandlePstatGetRequest (const OCEntityHandlerRequest * ehRequest)
230 OIC_LOG (INFO, TAG, "HandlePstatGetRequest processing GET request");
231 // Convert ACL data into JSON for transmission
232 char* jsonStr = BinToPstatJSON(gPstat);
234 // A device should always have a default pstat. Therefore, jsonStr should never be NULL.
235 OCEntityHandlerResult ehRet = (jsonStr ? OC_EH_OK : OC_EH_ERROR);
237 // Send response payload to request originator
238 SendSRMResponse(ehRequest, ehRet, jsonStr);
244 * The entity handler determines how to process a POST request.
245 * Per the REST paradigm, POST can also be used to update representation of existing
246 * resource or create a new resource.
247 * For pstat, it updates only tm and om.
249 static OCEntityHandlerResult HandlePstatPutRequest(const OCEntityHandlerRequest *ehRequest)
251 OCEntityHandlerResult ehRet = OC_EH_ERROR;
252 cJSON *postJson = NULL;
253 OIC_LOG (INFO, TAG, "HandlePstatPutRequest processing PUT request");
255 if (ehRequest->resource)
257 postJson = cJSON_Parse(((OCSecurityPayload*)ehRequest->payload)->securityData);
258 VERIFY_NON_NULL(TAG, postJson, INFO);
259 cJSON *jsonPstat = cJSON_GetObjectItem(postJson, OIC_JSON_PSTAT_NAME);
260 VERIFY_NON_NULL(TAG, jsonPstat, INFO);
261 cJSON *commitHashJson = cJSON_GetObjectItem(jsonPstat, OIC_JSON_COMMIT_HASH_NAME);
262 uint16_t commitHash = 0;
265 commitHash = commitHashJson->valueint;
267 cJSON *tmJson = cJSON_GetObjectItem(jsonPstat, OIC_JSON_TM_NAME);
268 if (tmJson && gPstat)
270 gPstat->tm = (OicSecDpm_t)tmJson->valueint;
271 if(0 == tmJson->valueint && gPstat->commitHash == commitHash)
275 OIC_LOG (INFO, TAG, "CommitHash is valid and isOp is TRUE");
279 OIC_LOG (INFO, TAG, "CommitHash is not valid");
282 cJSON *omJson = cJSON_GetObjectItem(jsonPstat, OIC_JSON_OM_NAME);
283 if (omJson && gPstat)
286 * Check if the operation mode is in the supported provisioning services
287 * operation mode list.
289 for(size_t i=0; i< gPstat->smLen; i++)
291 if(gPstat->sm[i] == (unsigned int)omJson->valueint)
293 gPstat->om = (OicSecDpom_t)omJson->valueint;
298 // Convert pstat data into JSON for update to persistent storage
299 if(UpdatePersistentStorage(gPstat))
305 if(OC_EH_OK != ehRet)
308 * If some error is occured while ownership transfer,
309 * ownership transfer related resource should be revert back to initial status.
311 RestoreDoxmToInitState();
312 RestorePstatToInitState();
315 //Send payload to request originator
316 if(OC_STACK_OK != SendSRMResponse(ehRequest, ehRet, NULL))
318 OIC_LOG (ERROR, TAG, "SendSRMResponse failed in HandlePstatPostRequest");
320 cJSON_Delete(postJson);
325 * This internal method is the entity handler for pstat resources.
327 OCEntityHandlerResult PstatEntityHandler(OCEntityHandlerFlag flag,
328 OCEntityHandlerRequest * ehRequest,
332 OCEntityHandlerResult ehRet = OC_EH_ERROR;
333 // This method will handle REST request (GET/POST) for /oic/sec/pstat
334 if (flag & OC_REQUEST_FLAG)
336 OIC_LOG (INFO, TAG, "Flag includes OC_REQUEST_FLAG");
337 switch (ehRequest->method)
340 ehRet = HandlePstatGetRequest(ehRequest);
343 ehRet = HandlePstatPutRequest(ehRequest);
347 SendSRMResponse(ehRequest, ehRet, NULL);
355 * This internal method is used to create '/oic/sec/pstat' resource.
357 OCStackResult CreatePstatResource()
361 ret = OCCreateResource(&gPstatHandle,
362 OIC_RSRC_TYPE_SEC_PSTAT,
369 if (ret != OC_STACK_OK)
371 OIC_LOG (FATAL, TAG, "Unable to instantiate pstat resource");
372 DeInitPstatResource();
378 * Post ACL hander update the commitHash during ACL provisioning.
380 void SetCommitHash(uint16_t commitHash)
382 gPstat->commitHash = commitHash;
386 * Get the default value
387 * @retval the gDefaultPstat pointer
389 static OicSecPstat_t* GetPstatDefault()
391 return &gDefaultPstat;
395 * Initialize pstat resource by loading data from persistent storage.
397 * @retval OC_STACK_OK for Success, otherwise some error value
399 OCStackResult InitPstatResource()
401 OCStackResult ret = OC_STACK_ERROR;
403 // Read Pstat resource from PS
404 char* jsonSVRDatabase = GetSVRDatabase();
407 // Convert JSON Pstat into binary format
408 gPstat = JSONToPstatBin(jsonSVRDatabase);
411 * If SVR database in persistent storage got corrupted or
412 * is not available for some reason, a default pstat is created
413 * which allows user to initiate pstat provisioning again.
415 if(!jsonSVRDatabase || !gPstat)
417 gPstat = GetPstatDefault();
420 // Instantiate 'oic.sec.pstat'
421 ret = CreatePstatResource();
423 OICFree(jsonSVRDatabase);
428 * Perform cleanup for pstat resources.
430 * @retval OC_STACK_OK for Success, otherwise some error value
432 OCStackResult DeInitPstatResource()
434 if(gPstat != &gDefaultPstat)
436 DeletePstatBinData(gPstat);
439 return OCDeleteResource(gPstatHandle);
444 * Function to restore pstat resurce to initial status.
445 * This function will use in case of error while ownership transfer
447 void RestorePstatToInitState()
451 OIC_LOG(INFO, TAG, "PSTAT resource will revert back to initial status.");
455 gPstat->om = SINGLE_SERVICE_CLIENT_DRIVEN;
456 if(gPstat->sm && 0 < gPstat->smLen)
458 gPstat->sm[0] = SINGLE_SERVICE_CLIENT_DRIVEN;
461 if(!UpdatePersistentStorage(gPstat))
463 OIC_LOG(ERROR, TAG, "Failed to revert DOXM in persistent storage");