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 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
32 #include "oic_malloc.h"
33 #include "payload_logging.h"
36 #include "ocpayload.h"
37 #include "cainterface.h"
38 #include "ocserverrequest.h"
39 #include "resourcemanager.h"
40 #include "doxmresource.h"
41 #include "pstatresource.h"
42 #include "aclresource.h"
43 #include "psinterface.h"
44 #include "srmresourcestrings.h"
45 #include "securevirtualresourcetypes.h"
46 #include "credresource.h"
47 #include "srmutility.h"
48 #include "pinoxmcommon.h"
50 #define TAG "SRM-DOXM"
52 /** Default cbor payload size. This value is increased in case of CborErrorOutOfMemory.
53 * The value of payload size is increased until reaching belox max cbor size. */
54 static const uint8_t CBOR_SIZE = 255;
56 /** Max cbor size payload. */
57 static const uint16_t CBOR_MAX_SIZE = 4400;
59 /** DOXM Map size - Number of mandatory items. */
60 static const uint8_t DOXM_MAP_SIZE = 6;
62 static OicSecDoxm_t *gDoxm = NULL;
63 static OCResourceHandle gDoxmHandle = NULL;
65 static OicSecOxm_t gOicSecDoxmJustWorks = OIC_JUST_WORKS;
66 static OicSecDoxm_t gDefaultDoxm =
68 NULL, /* OicUrn_t *oxmType */
69 0, /* size_t oxmTypeLen */
70 &gOicSecDoxmJustWorks, /* uint16_t *oxm */
71 1, /* size_t oxmLen */
72 OIC_JUST_WORKS, /* uint16_t oxmSel */
73 SYMMETRIC_PAIR_WISE_KEY,/* OicSecCredType_t sct */
74 false, /* bool owned */
75 {.id = {0}}, /* OicUuid_t deviceID */
77 {.id = {0}}, /* OicUuid_t owner */
80 void DeleteDoxmBinData(OicSecDoxm_t* doxm)
85 for (size_t i = 0; i < doxm->oxmTypeLen; i++)
87 OICFree(doxm->oxmType[i]);
89 OICFree(doxm->oxmType);
99 OCStackResult DoxmToCBORPayload(const OicSecDoxm_t *doxm, uint8_t **payload, size_t *size)
101 if (NULL == doxm || NULL == payload || NULL != *payload || NULL == size)
103 return OC_STACK_INVALID_PARAM;
105 size_t cborLen = *size;
113 OCStackResult ret = OC_STACK_ERROR;
115 CborEncoder encoder = { {.ptr = NULL }, .end = 0 };
116 CborEncoder doxmMap = { {.ptr = NULL }, .end = 0 };
118 int64_t cborEncoderResult = CborNoError;
119 uint8_t mapSize = DOXM_MAP_SIZE;
120 if (doxm->oxmTypeLen > 0)
124 if (doxm->oxmLen > 0)
129 uint8_t *outPayload = (uint8_t *)OICCalloc(1, cborLen);
130 VERIFY_NON_NULL(TAG, outPayload, ERROR);
131 cbor_encoder_init(&encoder, outPayload, cborLen, 0);
133 cborEncoderResult |= cbor_encoder_create_map(&encoder, &doxmMap, mapSize);
134 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Doxm Map.");
136 //OxmType -- Not Mandatory
137 if (doxm->oxmTypeLen > 0)
139 cborEncoderResult |= cbor_encode_text_string(&doxmMap, OIC_JSON_OXM_TYPE_NAME,
140 strlen(OIC_JSON_OXM_TYPE_NAME));
141 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding oxmType Tag.");
143 cborEncoderResult |= cbor_encoder_create_array(&doxmMap, &oxmType, doxm->oxmTypeLen);
144 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding oxmType Array.");
146 for (size_t i = 0; i < doxm->oxmTypeLen; i++)
148 cborEncoderResult |= cbor_encode_text_string(&oxmType, doxm->oxmType[i],
149 strlen(doxm->oxmType[i]));
150 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding oxmType Value.");
152 cborEncoderResult |= cbor_encoder_close_container(&doxmMap, &oxmType);
153 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing oxmType.");
156 //Oxm -- Not Mandatory
157 if (doxm->oxmLen > 0)
159 cborEncoderResult |= cbor_encode_text_string(&doxmMap, OIC_JSON_OXM_NAME,
160 strlen(OIC_JSON_OXM_NAME));
161 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding oxmName Tag.");
163 cborEncoderResult |= cbor_encoder_create_array(&doxmMap, &oxm, doxm->oxmLen);
164 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding oxmName Array.");
166 for (size_t i = 0; i < doxm->oxmLen; i++)
168 cborEncoderResult |= cbor_encode_int(&oxm, doxm->oxm[i]);
169 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding oxmName Value");
171 cborEncoderResult |= cbor_encoder_close_container(&doxmMap, &oxm);
172 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing oxmName.");
175 //OxmSel -- Mandatory
176 cborEncoderResult |= cbor_encode_text_string(&doxmMap, OIC_JSON_OXM_SEL_NAME,
177 strlen(OIC_JSON_OXM_SEL_NAME));
178 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Sel Tag.");
179 cborEncoderResult |= cbor_encode_int(&doxmMap, doxm->oxmSel);
180 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Sel Value.");
183 cborEncoderResult |= cbor_encode_text_string(&doxmMap, OIC_JSON_SUPPORTED_CRED_TYPE_NAME,
184 strlen(OIC_JSON_SUPPORTED_CRED_TYPE_NAME));
185 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Cred Type Tag");
186 cborEncoderResult |= cbor_encode_int(&doxmMap, doxm->sct);
187 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Cred Type Value.");
190 cborEncoderResult |= cbor_encode_text_string(&doxmMap, OIC_JSON_OWNED_NAME,
191 strlen(OIC_JSON_OWNED_NAME));
192 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Owned Tag.");
193 cborEncoderResult |= cbor_encode_boolean(&doxmMap, doxm->owned);
194 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Owned Value.");
196 //TODO: Need more clarification on deviceIDFormat field type.
198 //DeviceIdFormat -- Mandatory
199 cJSON_AddNumberToObject(jsonDoxm, OIC_JSON_DEVICE_ID_FORMAT_NAME, doxm->deviceIDFormat);
202 //DeviceId -- Mandatory
203 cborEncoderResult |= cbor_encode_text_string(&doxmMap, OIC_JSON_DEVICE_ID_NAME,
204 strlen(OIC_JSON_DEVICE_ID_NAME));
205 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Device Id Tag.");
206 cborEncoderResult |= cbor_encode_byte_string(&doxmMap, doxm->deviceID.id,
207 sizeof(doxm->deviceID.id));
208 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Device Id Value.");
211 cborEncoderResult |= cbor_encode_text_string(&doxmMap, OIC_JSON_DPC_NAME,
212 strlen(OIC_JSON_DPC_NAME));
213 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding DPC Tag.");
214 cborEncoderResult |= cbor_encode_boolean(&doxmMap, doxm->dpc);
215 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding DPC Value.");
218 cborEncoderResult |= cbor_encode_text_string(&doxmMap, OIC_JSON_OWNER_NAME,
219 strlen(OIC_JSON_OWNER_NAME));
220 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Owner tag.");
221 cborEncoderResult |= cbor_encode_byte_string(&doxmMap, doxm->owner.id,
222 sizeof(doxm->owner.id));
223 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Owner Value");
225 cborEncoderResult |= cbor_encoder_close_container(&encoder, &doxmMap);
226 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing DoxmMap.");
228 if (CborNoError == cborEncoderResult)
230 *size = encoder.ptr - outPayload;
231 *payload = outPayload;
235 if ((CborErrorOutOfMemory == cborEncoderResult) && (cborLen < CBOR_MAX_SIZE))
237 OIC_LOG(DEBUG, TAG, "Memory getting reallocated.");
238 // reallocate and try again!
240 // Since the allocated initial memory failed, double the memory.
241 cborLen += encoder.ptr - encoder.end;
242 OIC_LOG_V(DEBUG, TAG, "Doxm reallocation size : %zd.", cborLen);
243 cborEncoderResult = CborNoError;
244 ret = DoxmToCBORPayload(doxm, payload, &cborLen);
248 if ((CborNoError != cborEncoderResult) || (OC_STACK_OK != ret))
254 ret = OC_STACK_ERROR;
260 OCStackResult CBORPayloadToDoxm(const uint8_t *cborPayload, size_t size,
261 OicSecDoxm_t **secDoxm)
263 if (NULL == cborPayload || NULL == secDoxm || NULL != *secDoxm)
265 return OC_STACK_INVALID_PARAM;
268 OCStackResult ret = OC_STACK_ERROR;
272 CborError cborFindResult = CborNoError;
273 int cborLen = (size == 0) ? CBOR_SIZE : size;
276 cbor_parser_init(cborPayload, cborLen, 0, &parser, &doxmCbor);
278 OicSecDoxm_t *doxm = (OicSecDoxm_t *)OICCalloc(1, sizeof(*doxm));
279 VERIFY_NON_NULL(TAG, doxm, ERROR);
281 cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_OXM_TYPE_NAME, &doxmMap);
282 //OxmType -- not Mandatory
283 if (CborNoError == cborFindResult && cbor_value_is_array(&doxmMap))
287 cborFindResult = cbor_value_get_array_length(&doxmMap, &doxm->oxmTypeLen);
288 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding oxmTypeLen.")
289 VERIFY_SUCCESS(TAG, doxm->oxmTypeLen != 0, ERROR);
291 doxm->oxmType = (OicUrn_t *)OICCalloc(doxm->oxmTypeLen, sizeof(*doxm->oxmType));
292 VERIFY_NON_NULL(TAG, doxm->oxmType, ERROR);
294 cborFindResult = cbor_value_enter_container(&doxmMap, &oxmType);
295 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Entering oxmType Array.")
299 while (cbor_value_is_valid(&oxmType))
301 cborFindResult = cbor_value_dup_text_string(&oxmType, &doxm->oxmType[i++],
303 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding omxType text string.")
304 cborFindResult = cbor_value_advance(&oxmType);
305 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Advancing oxmType.")
309 cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_OXM_NAME, &doxmMap);
310 //Oxm -- not Mandatory
311 if (CborNoError == cborFindResult && cbor_value_is_array(&doxmMap))
314 cborFindResult = cbor_value_get_array_length(&doxmMap, &doxm->oxmLen);
315 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding oxmName array Length.")
316 VERIFY_SUCCESS(TAG, doxm->oxmLen != 0, ERROR);
318 doxm->oxm = (OicSecOxm_t *)OICCalloc(doxm->oxmLen, sizeof(*doxm->oxm));
319 VERIFY_NON_NULL(TAG, doxm->oxm, ERROR);
321 cborFindResult = cbor_value_enter_container(&doxmMap, &oxm);
322 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Entering oxmName Array.")
325 while (cbor_value_is_valid(&oxm))
327 cborFindResult = cbor_value_get_int(&oxm, (int *) &doxm->oxm[i++]);
328 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding oxmName Value")
329 cborFindResult = cbor_value_advance(&oxm);
330 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Advancing oxmName.")
334 cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_OXM_SEL_NAME, &doxmMap);
335 if (CborNoError == cborFindResult && cbor_value_is_integer(&doxmMap))
337 cborFindResult = cbor_value_get_int(&doxmMap, (int *) &doxm->oxmSel);
338 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding Sel Name Value.")
340 else // PUT/POST JSON may not have oxmsel so set it to the gDoxm->oxmSel
342 VERIFY_NON_NULL(TAG, gDoxm, ERROR);
343 doxm->oxmSel = gDoxm->oxmSel;
346 cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_SUPPORTED_CRED_TYPE_NAME, &doxmMap);
347 if (CborNoError == cborFindResult && cbor_value_is_integer(&doxmMap))
349 cborFindResult = cbor_value_get_int(&doxmMap, (int *) &doxm->sct);
350 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding Sct Name Value.")
352 else // PUT/POST JSON may not have sct so set it to the gDoxm->sct
354 VERIFY_NON_NULL(TAG, gDoxm, ERROR);
355 doxm->sct = gDoxm->sct;
358 cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_OWNED_NAME, &doxmMap);
359 if (CborNoError == cborFindResult && cbor_value_is_boolean(&doxmMap))
361 cborFindResult = cbor_value_get_boolean(&doxmMap, &doxm->owned);
362 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding Owned Value.")
364 else // PUT/POST JSON may not have owned so set it to the gDomx->owned
366 VERIFY_NON_NULL(TAG, gDoxm, ERROR);
367 doxm->owned = gDoxm->owned;
370 cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_DPC_NAME, &doxmMap);
371 if (CborNoError == cborFindResult && cbor_value_is_boolean(&doxmMap))
373 cborFindResult = cbor_value_get_boolean(&doxmMap, &doxm->dpc);
374 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding DPC Value.")
376 else // PUT/POST JSON may not have owned so set it to the gDomx->owned
378 VERIFY_NON_NULL(TAG, gDoxm, ERROR);
382 cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_DEVICE_ID_NAME, &doxmMap);
383 if (CborNoError == cborFindResult && cbor_value_is_byte_string(&doxmMap))
386 cborFindResult = cbor_value_dup_byte_string(&doxmMap, &id, &len, NULL);
387 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding DeviceId Value.")
388 memcpy(doxm->deviceID.id, id, len);
391 cborFindResult = cbor_value_map_find_value(&doxmCbor, OIC_JSON_OWNER_NAME, &doxmMap);
392 if (CborNoError == cborFindResult && cbor_value_is_byte_string(&doxmMap))
395 cborFindResult = cbor_value_dup_byte_string(&doxmMap, &id , &len, NULL);
396 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding Owner Name Value.")
397 memcpy(doxm->owner.id, id, len);
405 if (CborNoError != cborFindResult)
407 OIC_LOG (ERROR, TAG, "CBORPayloadToDoxm failed!!!");
408 DeleteDoxmBinData(doxm);
410 ret = OC_STACK_ERROR;
416 * @todo document this function including why code might need to call this.
417 * The current suspicion is that it's not being called as much as it should.
419 static bool UpdatePersistentStorage(OicSecDoxm_t * doxm)
425 // Convert Doxm data into CBOR for update to persistent storage
426 uint8_t *payload = NULL;
428 OCStackResult res = DoxmToCBORPayload(doxm, &payload, &size);
429 if (payload && (OC_STACK_OK == res)
430 && (OC_STACK_OK == UpdateSecureResourceInPS(OIC_JSON_DOXM_NAME, payload, size)))
438 if (OC_STACK_OK == UpdateSecureResourceInPS(OIC_JSON_DOXM_NAME, NULL, 0))
447 static bool ValidateQuery(const char * query)
449 // Send doxm resource data if the state of doxm resource
450 // matches with the query parameters.
451 // else send doxm resource data as NULL
452 // TODO Remove this check and rely on Policy Engine
453 // and Provisioning Mode to enforce provisioning-state
454 // access rules. Eventually, the PE and PM code will
455 // not send a request to the /doxm Entity Handler at all
456 // if it should not respond.
457 OIC_LOG (DEBUG, TAG, "In ValidateQuery");
463 bool bOwnedQry = false; // does querystring contains 'owned' query ?
464 bool bOwnedMatch = false; // does 'owned' query value matches with doxm.owned status?
465 bool bDeviceIDQry = false; // does querystring contains 'deviceid' query ?
466 bool bDeviceIDMatch = false; // does 'deviceid' query matches with doxm.deviceid ?
468 OicParseQueryIter_t parseIter = {.attrPos = NULL};
470 ParseQueryIterInit((unsigned char*)query, &parseIter);
472 while (GetNextQuery(&parseIter))
474 if (strncasecmp((char *)parseIter.attrPos, OIC_JSON_OWNED_NAME, parseIter.attrLen) == 0)
477 if ((strncasecmp((char *)parseIter.valPos, OIC_SEC_TRUE, parseIter.valLen) == 0) &&
482 else if ((strncasecmp((char *)parseIter.valPos, OIC_SEC_FALSE, parseIter.valLen) == 0)
489 if (strncasecmp((char *)parseIter.attrPos, OIC_JSON_DEVICE_ID_NAME, parseIter.attrLen) == 0)
492 OicUuid_t subject = {.id={0}};
494 memcpy(subject.id, parseIter.valPos, parseIter.valLen);
495 if (0 == memcmp(&gDoxm->deviceID.id, &subject.id, sizeof(gDoxm->deviceID.id)))
497 bDeviceIDMatch = true;
502 return ((bOwnedQry ? bOwnedMatch : true) && (bDeviceIDQry ? bDeviceIDMatch : true));
505 static OCEntityHandlerResult HandleDoxmGetRequest (const OCEntityHandlerRequest * ehRequest)
507 OCEntityHandlerResult ehRet = OC_EH_OK;
509 OIC_LOG(DEBUG, TAG, "Doxm EntityHandle processing GET request");
511 //Checking if Get request is a query.
512 if (ehRequest->query)
514 OIC_LOG(DEBUG, TAG, "HandleDoxmGetRequest processing query");
515 if (!ValidateQuery(ehRequest->query))
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 Doxm, so DoxmToCBORPayload will
525 * return valid doxm resource json.
527 uint8_t *payload = NULL;
530 if (ehRet == OC_EH_OK)
532 if (OC_STACK_OK != DoxmToCBORPayload(gDoxm, &payload, &size))
538 // Send response payload to request originator
539 if (OC_STACK_OK != SendSRMCBORResponse(ehRequest, ehRet, payload, size))
541 OIC_LOG(ERROR, TAG, "SendSRMCBORResponse failed in HandleDoxmGetRequest");
549 static OCEntityHandlerResult HandleDoxmPutRequest(const OCEntityHandlerRequest * ehRequest)
551 OIC_LOG (DEBUG, TAG, "Doxm EntityHandle processing PUT request");
552 OCEntityHandlerResult ehRet = OC_EH_ERROR;
553 OicUuid_t emptyOwner = {.id = {0} };
556 * Convert CBOR Doxm data into binary. This will also validate
557 * the Doxm data received.
559 OicSecDoxm_t *newDoxm = NULL;
561 if (ehRequest->payload)
563 uint8_t *payload = ((OCSecurityPayload *)ehRequest->payload)->securityData1;
564 size_t size = ((OCSecurityPayload *)ehRequest->payload)->payloadSize;
565 OCStackResult res = CBORPayloadToDoxm(payload, size, &newDoxm);
567 if (newDoxm && OC_STACK_OK == res)
569 if (OIC_JUST_WORKS == newDoxm->oxmSel)
571 if ((false == gDoxm->owned) && (false == newDoxm->owned))
574 * If current state of the device is un-owned, enable
575 * anonymous ECDH cipher in tinyDTLS so that Provisioning
576 * tool can initiate JUST_WORKS ownership transfer process.
578 if (memcmp(&(newDoxm->owner), &emptyOwner, sizeof(OicUuid_t)) == 0)
580 OIC_LOG (INFO, TAG, "Doxm EntityHandle enabling AnonECDHCipherSuite");
582 ehRet = (CAEnableAnonECDHCipherSuite(true) == CA_STATUS_OK) ? OC_EH_OK : OC_EH_ERROR;
583 #endif //__WITH_DTLS__
589 //Save the owner's UUID to derive owner credential
590 memcpy(&(gDoxm->owner), &(newDoxm->owner), sizeof(OicUuid_t));
592 // OCServerRequest *request = (OCServerRequest *)ehRequest->requestHandle;
593 // Generating OwnerPSK
594 // OIC_LOG (INFO, TAG, "Doxm EntityHandle generating OwnerPSK");
595 // Generate new credential for provisioning tool
596 // ehRet = AddOwnerPSK((CAEndpoint_t *)&request->devAddr, newDoxm,
597 // (uint8_t*) OXM_JUST_WORKS, strlen(OXM_JUST_WORKS));
598 // VERIFY_SUCCESS(TAG, OC_EH_OK == ehRet, ERROR);
600 // Update new state in persistent storage
601 if (true == UpdatePersistentStorage(gDoxm))
607 OIC_LOG(ERROR, TAG, "Failed to update DOXM in persistent storage");
612 * Disable anonymous ECDH cipher in tinyDTLS since device is now
615 CAResult_t caRes = CA_STATUS_OK;
616 caRes = CAEnableAnonECDHCipherSuite(false);
617 VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
618 OIC_LOG(INFO, TAG, "ECDH_ANON CipherSuite is DISABLED");
621 #define TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 0xC0AE
622 CASelectCipherSuite(TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8);
623 #endif //__WITH_X509__
624 #endif //__WITH_DTLS__
628 else if (OIC_RANDOM_DEVICE_PIN == newDoxm->oxmSel)
630 if ((false == gDoxm->owned) && (false == newDoxm->owned))
633 * If current state of the device is un-owned, enable
634 * anonymous ECDH cipher in tinyDTLS so that Provisioning
635 * tool can initiate JUST_WORKS ownership transfer process.
637 if(memcmp(&(newDoxm->owner), &emptyOwner, sizeof(OicUuid_t)) == 0)
639 gDoxm->oxmSel = newDoxm->oxmSel;
640 //Update new state in persistent storage
641 if ((UpdatePersistentStorage(gDoxm) == true))
647 OIC_LOG(WARNING, TAG, "Failed to update DOXM in persistent storage");
652 CAResult_t caRes = CA_STATUS_OK;
654 caRes = CAEnableAnonECDHCipherSuite(false);
655 VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
656 OIC_LOG(INFO, TAG, "ECDH_ANON CipherSuite is DISABLED");
658 caRes = CASelectCipherSuite(TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256);
659 VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
661 char ranPin[OXM_RANDOM_PIN_SIZE + 1] = {0,};
662 if(OC_STACK_OK == GeneratePin(ranPin, OXM_RANDOM_PIN_SIZE + 1))
664 //Set the device id to derive temporal PSK
665 SetUuidForRandomPinOxm(&gDoxm->deviceID);
668 * Since PSK will be used directly by DTLS layer while PIN based ownership transfer,
669 * Credential should not be saved into SVR.
670 * For this reason, use a temporary get_psk_info callback to random PIN OxM.
672 caRes = CARegisterDTLSCredentialsHandler(GetDtlsPskForRandomPinOxm);
673 VERIFY_SUCCESS(TAG, caRes == CA_STATUS_OK, ERROR);
678 OIC_LOG(ERROR, TAG, "Failed to generate random PIN");
681 #endif //__WITH_DTLS__
686 //Save the owner's UUID to derive owner credential
687 memcpy(&(gDoxm->owner), &(newDoxm->owner), sizeof(OicUuid_t));
689 //Update new state in persistent storage
690 if (UpdatePersistentStorage(gDoxm) == true)
696 OIC_LOG(ERROR, TAG, "Failed to update DOXM in persistent storage");
705 * When current state of the device is un-owned and Provisioning
706 * Tool is attempting to change the state to 'Owned' with a
707 * qualified value for the field 'Owner'
709 if ((false == gDoxm->owned) && (true == newDoxm->owned) &&
710 (memcmp(&(gDoxm->owner), &(newDoxm->owner), sizeof(OicUuid_t)) == 0))
713 // Update new state in persistent storage
714 if (UpdatePersistentStorage(gDoxm))
716 //Update default ACL of security resource to prevent anonymous user access.
717 if(OC_STACK_OK == UpdateDefaultSecProvACL())
723 OIC_LOG(ERROR, TAG, "Failed to remove default ACL for security provisioning");
729 OIC_LOG(ERROR, TAG, "Failed to update DOXM in persistent storage");
737 if(OC_EH_OK != ehRet)
739 OIC_LOG(WARNING, TAG, "The operation failed during handle DOXM request,"\
740 "DOXM will be reverted.");
743 * If some error is occured while ownership transfer,
744 * ownership transfer related resource should be revert back to initial status.
746 RestoreDoxmToInitState();
747 RestorePstatToInitState();
750 //Send payload to request originator
751 if (OC_STACK_OK != SendSRMCBORResponse(ehRequest, ehRet, NULL, 0))
753 OIC_LOG(ERROR, TAG, "SendSRMCBORResponse failed in HandleDoxmPostRequest");
755 DeleteDoxmBinData(newDoxm);
760 OCEntityHandlerResult DoxmEntityHandler(OCEntityHandlerFlag flag,
761 OCEntityHandlerRequest * ehRequest,
765 OCEntityHandlerResult ehRet = OC_EH_ERROR;
767 if(NULL == ehRequest)
772 if (flag & OC_REQUEST_FLAG)
774 OIC_LOG(DEBUG, TAG, "Flag includes OC_REQUEST_FLAG");
776 switch (ehRequest->method)
779 ehRet = HandleDoxmGetRequest(ehRequest);
783 ehRet = HandleDoxmPutRequest(ehRequest);
788 SendSRMCBORResponse(ehRequest, ehRet, NULL, 0);
796 OCStackResult CreateDoxmResource()
798 OCStackResult ret = OCCreateResource(&gDoxmHandle,
799 OIC_RSRC_TYPE_SEC_DOXM,
804 OC_OBSERVABLE | OC_SECURE |
805 OC_EXPLICIT_DISCOVERABLE);
807 if (OC_STACK_OK != ret)
809 OIC_LOG (FATAL, TAG, "Unable to instantiate Doxm resource");
810 DeInitDoxmResource();
816 * Checks if DeviceID is generated during provisioning for the new device.
817 * If DeviceID is NULL then generates the new DeviceID.
818 * Once DeviceID is assigned to the device it does not change for the lifetime of the device.
820 static OCStackResult CheckDeviceID()
822 OCStackResult ret = OC_STACK_ERROR;
823 bool validId = false;
824 for (uint8_t i = 0; i < UUID_LENGTH; i++)
826 if (gDoxm->deviceID.id[i] != 0)
835 if (OCGenerateUuid(gDoxm->deviceID.id) != RAND_UUID_OK)
837 OIC_LOG(FATAL, TAG, "Generate UUID for Server Instance failed!");
842 if (!UpdatePersistentStorage(gDoxm))
844 //TODO: After registering PSI handler in all samples, do ret = OC_STACK_OK here.
845 OIC_LOG(FATAL, TAG, "UpdatePersistentStorage failed!");
856 * Get the default value.
858 * @return the default value of doxm, @ref OicSecDoxm_t.
860 static OicSecDoxm_t* GetDoxmDefault()
862 OIC_LOG(DEBUG, TAG, "GetDoxmToDefault");
863 return &gDefaultDoxm;
866 const OicSecDoxm_t* GetDoxmResourceData()
871 OCStackResult InitDoxmResource()
873 OCStackResult ret = OC_STACK_ERROR;
875 //Read DOXM resource from PS
876 uint8_t *data = NULL;
878 ret = GetSecureVirtualDatabaseFromPS(OIC_JSON_DOXM_NAME, &data, &size);
879 // If database read failed
880 if (OC_STACK_OK != ret)
882 OIC_LOG (DEBUG, TAG, "ReadSVDataFromPS failed");
886 // Read DOXM resource from PS
887 ret = CBORPayloadToDoxm(data, size, &gDoxm);
890 * If SVR database in persistent storage got corrupted or
891 * is not available for some reason, a default doxm is created
892 * which allows user to initiate doxm provisioning again.
894 if ((OC_STACK_OK != ret) || !data || !gDoxm)
896 gDoxm = GetDoxmDefault();
899 //In case of the server is shut down unintentionally, we should initialize the owner
900 if(false == gDoxm->owned)
902 OicUuid_t emptyUuid = {.id={0}};
903 memcpy(&gDoxm->owner, &emptyUuid, sizeof(OicUuid_t));
906 ret = CheckDeviceID();
907 if (ret == OC_STACK_OK)
909 OIC_LOG_V(DEBUG, TAG, "Initial Doxm Owned = %d", gDoxm->owned);
910 //Instantiate 'oic.sec.doxm'
911 ret = CreateDoxmResource();
915 OIC_LOG (ERROR, TAG, "CheckDeviceID failed");
921 OCStackResult DeInitDoxmResource()
923 OCStackResult ret = OCDeleteResource(gDoxmHandle);
924 if (gDoxm != &gDefaultDoxm)
926 DeleteDoxmBinData(gDoxm);
930 if (OC_STACK_OK == ret)
936 return OC_STACK_ERROR;
940 OCStackResult GetDoxmDeviceID(OicUuid_t *deviceID)
942 if (deviceID && gDoxm)
944 *deviceID = gDoxm->deviceID;
947 return OC_STACK_ERROR;
950 OCStackResult GetDoxmDevOwnerId(OicUuid_t *devOwner)
952 OCStackResult retVal = OC_STACK_ERROR;
955 OIC_LOG_V(DEBUG, TAG, "gDoxm owned = %d.", gDoxm->owned);
958 *devOwner = gDoxm->owner; // TODO change to devOwner when available
959 retVal = OC_STACK_OK;
966 * Function to restore doxm resurce to initial status.
967 * This function will use in case of error while ownership transfer
969 void RestoreDoxmToInitState()
973 OIC_LOG(INFO, TAG, "DOXM resource will revert back to initial status.");
975 OicUuid_t emptyUuid = {.id={0}};
976 memcpy(&(gDoxm->owner), &emptyUuid, sizeof(OicUuid_t));
977 gDoxm->owned = false;
978 gDoxm->oxmSel = OIC_JUST_WORKS;
980 if(!UpdatePersistentStorage(gDoxm))
982 OIC_LOG(ERROR, TAG, "Failed to revert DOXM in persistent storage");