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 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
21 #define __STDC_LIMIT_MACROS
31 #include "cainterface.h"
32 #include "payload_logging.h"
36 #include "ocserverrequest.h"
37 #include "oic_malloc.h"
38 #include "ocpayload.h"
40 #include "credresource.h"
41 #include "doxmresource.h"
42 #include "pstatresource.h"
43 #include "iotvticalendar.h"
45 #include "resourcemanager.h"
46 #include "srmresourcestrings.h"
47 #include "srmutility.h"
48 #include "psinterface.h"
49 #include "pinoxmcommon.h"
55 #define TAG "SRM-CREDL"
57 /** Default cbor payload size. This value is increased in case of CborErrorOutOfMemory.
58 * The value of payload size is increased until reaching belox max cbor size. */
59 static const uint16_t CBOR_SIZE = 2048;
61 /** Max cbor size payload. */
62 static const uint16_t CBOR_MAX_SIZE = 4400;
64 /** CRED size - Number of mandatory items. */
65 static const uint8_t CRED_ROOT_MAP_SIZE = 2;
66 static const uint8_t CRED_MAP_SIZE = 3;
69 static OicSecCred_t *gCred = NULL;
70 static OCResourceHandle gCredHandle = NULL;
73 * This function frees OicSecCred_t object's fields and object itself.
75 static void FreeCred(OicSecCred_t *cred)
79 OIC_LOG(ERROR, TAG, "Invalid Parameter");
82 //Note: Need further clarification on roleID data type
85 OICFree(cred->roleIds);
90 OICFree(cred->publicData.data);
94 OICFree(cred->privateData.data);
97 OICFree(cred->period);
100 OICFree(cred->owners);
102 //Clean Cred node itself
106 void DeleteCredList(OicSecCred_t* cred)
110 OicSecCred_t *credTmp1 = NULL, *credTmp2 = NULL;
111 LL_FOREACH_SAFE(cred, credTmp1, credTmp2)
113 LL_DELETE(cred, credTmp1);
119 static size_t OicSecCredCount(const OicSecCred_t *secCred)
122 for (const OicSecCred_t *cred = secCred; cred; cred = cred->next)
129 OCStackResult CredToCBORPayload(const OicSecCred_t *credS, uint8_t **cborPayload,
132 if (NULL == credS || NULL == cborPayload || NULL != *cborPayload || NULL == cborSize)
134 return OC_STACK_INVALID_PARAM;
137 OCStackResult ret = OC_STACK_ERROR;
139 CborError cborEncoderResult = CborNoError;
140 uint8_t *outPayload = NULL;
141 size_t cborLen = *cborSize;
144 const OicSecCred_t *cred = credS;
145 CborEncoder encoder = { {.ptr = NULL }, .end = 0 };
146 CborEncoder credArray = { {.ptr = NULL }, .end = 0 };
147 CborEncoder credRootMap = { {.ptr = NULL }, .end = 0 };
154 outPayload = (uint8_t *)OICCalloc(1, cborLen);
155 VERIFY_NON_NULL(TAG, outPayload, ERROR);
156 cbor_encoder_init(&encoder, outPayload, cborLen, 0);
158 // Create CRED Root Map (creds, rownerid)
159 cborEncoderResult = cbor_encoder_create_map(&encoder, &credRootMap, CRED_ROOT_MAP_SIZE);
160 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Cred Root Map");
163 cborEncoderResult = cbor_encode_text_string(&credRootMap, OIC_JSON_CREDS_NAME,
164 strlen(OIC_JSON_CREDS_NAME));
165 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding creds Name Tag.");
168 cborEncoderResult = cbor_encoder_create_array(&credRootMap, &credArray, OicSecCredCount(cred));
169 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Cred Array.");
173 CborEncoder credMap = { {.ptr = NULL }, .end = 0, .added = 0, .flags = 0 };
174 size_t mapSize = CRED_MAP_SIZE;
175 char *subject = NULL;
181 if (cred->publicData.data)
185 #endif /* __WITH_X509__ */
186 if (cred->privateData.data)
190 cborEncoderResult = cbor_encoder_create_map(&credArray, &credMap, mapSize);
191 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Cred Map");
193 //CredID -- Mandatory
194 cborEncoderResult = cbor_encode_text_string(&credMap, OIC_JSON_CREDID_NAME,
195 strlen(OIC_JSON_CREDID_NAME));
196 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Cred Id Tag. ");
197 cborEncoderResult = cbor_encode_int(&credMap, cred->credId);
198 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Cred Id Value.");
200 //Subject -- Mandatory
201 cborEncoderResult = cbor_encode_text_string(&credMap, OIC_JSON_SUBJECTID_NAME,
202 strlen(OIC_JSON_SUBJECTID_NAME));
203 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Subject Tag.");
204 ret = ConvertUuidToStr(&cred->subject, &subject);
205 VERIFY_SUCCESS(TAG, ret == OC_STACK_OK, ERROR);
206 cborEncoderResult = cbor_encode_text_string(&credMap, subject, strlen(subject));
207 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding Subject Id Value.");
210 //CredType -- Mandatory
211 cborEncoderResult = cbor_encode_text_string(&credMap, OIC_JSON_CREDTYPE_NAME,
212 strlen(OIC_JSON_CREDTYPE_NAME));
213 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Cred Type Tag.");
214 cborEncoderResult = cbor_encode_int(&credMap, cred->credType);
215 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Cred Type Value.");
218 //PublicData -- Not Mandatory
219 if (cred->publicData.data)
221 CborEncoder publicMap = { {.ptr = NULL }, .end = 0, .added = 0, .flags = 0 };
222 const size_t publicMapSize = 2;
224 cborEncoderResult = cbor_encode_text_string(&credMap, OIC_JSON_PUBLICDATA_NAME,
225 strlen(OIC_JSON_PUBLICDATA_NAME));
226 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding PublicData Tag.");
228 cborEncoderResult = cbor_encoder_create_map(&credMap, &publicMap, publicMapSize);
229 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding PublicData Map");
231 cborEncoderResult = cbor_encode_text_string(&publicMap, OIC_JSON_PUBDATA_NAME,
232 strlen(OIC_JSON_PUBDATA_NAME));
233 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Pub Data Tag.");
234 cborEncoderResult = cbor_encode_byte_string(&publicMap, cred->publicData.data,
235 cred->publicData.len);
236 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Pub Value.");
238 // TODO: Need to data strucure modification for OicSecCert_t.
239 cborEncoderResult = cbor_encode_text_string(&publicMap, OIC_JSON_ENCODING_NAME,
240 strlen(OIC_JSON_ENCODING_NAME));
241 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Public Encoding Tag.");
242 cborEncoderResult = cbor_encode_text_string(&publicMap, OIC_SEC_ENCODING_BYTESTREAM,
243 strlen(OIC_SEC_ENCODING_BYTESTREAM));
244 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Public Encoding Value.");
246 cborEncoderResult = cbor_encoder_close_container(&credMap, &publicMap);
247 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing PublicData Map.");
249 #endif /*__WITH_X509__*/
250 //PrivateData -- Not Mandatory
251 if(cred->privateData.data)
253 CborEncoder privateMap = { {.ptr = NULL }, .end = 0, .added = 0, .flags = 0 };
254 const size_t privateMapSize = 2;
256 cborEncoderResult = cbor_encode_text_string(&credMap, OIC_JSON_PRIVATEDATA_NAME,
257 strlen(OIC_JSON_PRIVATEDATA_NAME));
258 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding PrivateData Tag.");
260 cborEncoderResult = cbor_encoder_create_map(&credMap, &privateMap, privateMapSize);
261 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding PrivateData Map");
263 cborEncoderResult = cbor_encode_text_string(&privateMap, OIC_JSON_PRIVDATA_NAME,
264 strlen(OIC_JSON_PRIVDATA_NAME));
265 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Priv Tag.");
266 cborEncoderResult = cbor_encode_byte_string(&privateMap, cred->privateData.data,
267 cred->privateData.len);
268 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Priv Value.");
270 // TODO: Need to data strucure modification for OicSecKey_t.
271 cborEncoderResult = cbor_encode_text_string(&privateMap, OIC_JSON_ENCODING_NAME,
272 strlen(OIC_JSON_ENCODING_NAME));
273 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Private Encoding Tag.");
274 cborEncoderResult = cbor_encode_text_string(&privateMap, OIC_SEC_ENCODING_BYTESTREAM,
275 strlen(OIC_SEC_ENCODING_BYTESTREAM));
276 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Private Encoding Value.");
278 cborEncoderResult = cbor_encoder_close_container(&credMap, &privateMap);
279 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing PrivateData Map.");
282 //Period -- Not Mandatory
285 cborEncoderResult = cbor_encode_text_string(&credMap, OIC_JSON_PERIOD_NAME,
286 strlen(OIC_JSON_PERIOD_NAME));
287 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Period Name Tag.");
288 cborEncoderResult = cbor_encode_text_string(&credMap, cred->period,
289 strlen(cred->period));
290 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding Period Name Value.");
294 cborEncoderResult = cbor_encoder_close_container(&credArray, &credMap);
295 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing Cred Map.");
299 cborEncoderResult = cbor_encoder_close_container(&credRootMap, &credArray);
300 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing Cred Array.");
303 // TODO : Need to modify cred->owners[0] to cred->rownerid based on RAML spec.
305 if(cred->owners && cred->ownersLen > 0)
308 cborEncoderResult = cbor_encode_text_string(&credRootMap, OIC_JSON_ROWNERID_NAME,
309 strlen(OIC_JSON_ROWNERID_NAME));
310 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding rownerid Name.");
311 ret = ConvertUuidToStr(&cred->owners[0], &rowner);
312 VERIFY_SUCCESS(TAG, ret == OC_STACK_OK, ERROR);
313 cborEncoderResult = cbor_encode_text_string(&credRootMap, rowner, strlen(rowner));
314 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding rownerid Value.");
318 // Close CRED Root Map
319 cborEncoderResult = cbor_encoder_close_container(&encoder, &credRootMap);
320 VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing CRED Root Map.");
322 if (CborNoError == cborEncoderResult)
324 OIC_LOG(DEBUG, TAG, "CredToCBORPayload Successed");
325 *cborPayload = outPayload;
326 *cborSize = encoder.ptr - outPayload;
329 OIC_LOG(DEBUG, TAG, "CredToCBORPayload OUT");
331 if (CborErrorOutOfMemory == cborEncoderResult)
333 OIC_LOG(DEBUG, TAG, "CredToCBORPayload:CborErrorOutOfMemory : retry with more memory");
334 // reallocate and try again!
336 // Since the allocated initial memory failed, double the memory.
337 cborLen += encoder.ptr - encoder.end;
338 cborEncoderResult = CborNoError;
339 ret = CredToCBORPayload(credS, cborPayload, &cborLen);
343 if (CborNoError != cborEncoderResult)
345 OIC_LOG(ERROR, TAG, "Failed to CredToCBORPayload");
350 ret = OC_STACK_ERROR;
356 OCStackResult CBORPayloadToCred(const uint8_t *cborPayload, size_t size,
357 OicSecCred_t **secCred)
359 if (NULL == cborPayload || NULL == secCred || NULL != *secCred)
361 return OC_STACK_INVALID_PARAM;
364 OCStackResult ret = OC_STACK_ERROR;
365 CborValue credCbor = { .parser = NULL };
366 CborParser parser = { .end = NULL };
367 CborError cborFindResult = CborNoError;
368 cbor_parser_init(cborPayload, size, 0, &parser, &credCbor);
370 OicSecCred_t *headCred = (OicSecCred_t *) OICCalloc(1, sizeof(OicSecCred_t));
372 // Enter CRED Root Map
373 CborValue CredRootMap = { .parser = NULL, .ptr = NULL, .remaining = 0, .extra = 0, .type = 0, .flags = 0 };
374 cborFindResult = cbor_value_enter_container(&credCbor, &CredRootMap);
375 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Entering CRED Root Map.");
377 while (cbor_value_is_valid(&CredRootMap))
379 char* tagName = NULL;
381 CborType type = cbor_value_get_type(&CredRootMap);
382 if (type == CborTextStringType)
384 cborFindResult = cbor_value_dup_text_string(&CredRootMap, &tagName, &len, NULL);
385 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding Name in CRED Root Map.");
386 cborFindResult = cbor_value_advance(&CredRootMap);
387 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Advancing Value in CRED Root Map.");
391 if (strcmp(tagName, OIC_JSON_CREDS_NAME) == 0)
396 CborValue credArray = { .parser = NULL, .ptr = NULL, .remaining = 0, .extra = 0, .type = 0, .flags = 0 };
397 cborFindResult = cbor_value_enter_container(&CredRootMap, &credArray);
398 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding Cred Array.");
400 while (cbor_value_is_valid(&credArray))
403 //CredId -- Mandatory
404 CborValue credMap = { .parser = NULL, .ptr = NULL, .remaining = 0, .extra = 0, .type = 0, .flags = 0 };
405 cborFindResult = cbor_value_enter_container(&credArray, &credMap);
406 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding Cred Map.");
407 OicSecCred_t *cred = NULL;
415 cred = (OicSecCred_t *) OICCalloc(1, sizeof(OicSecCred_t));
416 OicSecCred_t *temp = headCred;
424 VERIFY_NON_NULL(TAG, cred, ERROR);
426 while(cbor_value_is_valid(&credMap))
429 CborType type = cbor_value_get_type(&credMap);
430 if (type == CborTextStringType)
432 cborFindResult = cbor_value_dup_text_string(&credMap, &name, &len, NULL);
433 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding Name in CRED Map.");
434 cborFindResult = cbor_value_advance(&credMap);
435 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Advancing Value in CRED Map.");
440 if (strcmp(name, OIC_JSON_CREDID_NAME) == 0)
442 cborFindResult = cbor_value_get_uint64(&credMap, (uint64_t *) &cred->credId);
443 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding CredId.");
446 if (strcmp(name, OIC_JSON_SUBJECTID_NAME) == 0)
448 char *subjectid = NULL;
449 cborFindResult = cbor_value_dup_text_string(&credMap, &subjectid, &len, NULL);
450 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding subjectid Value.");
451 ret = ConvertStrToUuid(subjectid, &cred->subject);
452 VERIFY_SUCCESS(TAG, ret == OC_STACK_OK, ERROR);
456 if (strcmp(name, OIC_JSON_CREDTYPE_NAME) == 0)
458 cborFindResult = cbor_value_get_uint64(&credMap, (uint64_t *) &cred->credType);
459 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding CredType.");
462 if (strcmp(name, OIC_JSON_PRIVATEDATA_NAME) == 0)
464 CborValue privateMap = { .parser = NULL };
465 cborFindResult = cbor_value_enter_container(&credMap, &privateMap);
467 while (cbor_value_is_valid(&privateMap))
469 char* privname = NULL;
470 CborType type = cbor_value_get_type(&privateMap);
471 if (type == CborTextStringType)
473 cborFindResult = cbor_value_dup_text_string(&privateMap, &privname,
475 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed to get text");
476 cborFindResult = cbor_value_advance(&privateMap);
477 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed to advance value");
481 // PrivateData::privdata -- Mandatory
482 if (strcmp(privname, OIC_JSON_PRIVDATA_NAME) == 0)
484 cborFindResult = cbor_value_dup_byte_string(&privateMap, &cred->privateData.data,
485 &cred->privateData.len, NULL);
486 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding PrivateData.");
488 // PrivateData::encoding -- Mandatory
489 if (strcmp(privname, OIC_JSON_ENCODING_NAME) == 0)
491 // TODO: Need to update data structure, just ignore encoding value now.
494 if (cbor_value_is_valid(&privateMap))
496 cborFindResult = cbor_value_advance(&privateMap);
497 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Advancing privatedata Map.");
504 if (strcmp(name, OIC_JSON_PUBLICDATA_NAME) == 0)
506 CborValue pubMap = { .parser = NULL };
507 cborFindResult = cbor_value_enter_container(&credMap, &pubMap);
509 while (cbor_value_is_valid(&pubMap))
511 char* pubname = NULL;
512 CborType type = cbor_value_get_type(&pubMap);
513 if (type == CborTextStringType)
515 cborFindResult = cbor_value_dup_text_string(&pubMap, &pubname,
517 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed to get text");
518 cborFindResult = cbor_value_advance(&pubMap);
519 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed to advance value");
523 // PrivateData::privdata -- Mandatory
524 if (strcmp(pubname, OIC_JSON_PUBDATA_NAME) == 0)
526 cborFindResult = cbor_value_dup_byte_string(&pubMap, &cred->publicData.data,
527 &cred->publicData.len, NULL);
528 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding PubData.");
530 // PublicData::encoding -- Mandatory
531 if (strcmp(pubname, OIC_JSON_ENCODING_NAME) == 0)
533 // TODO: Need to update data structure, just ignore encoding value now.
536 if (cbor_value_is_valid(&pubMap))
538 cborFindResult = cbor_value_advance(&pubMap);
539 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Advancing publicdata Map.");
544 #endif //__WITH_X509__
546 if (0 == strcmp(OIC_JSON_PERIOD_NAME, name))
548 cborFindResult = cbor_value_dup_text_string(&credMap, &cred->period, &len, NULL);
549 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding Period.");
552 if (cbor_value_is_valid(&credMap))
554 cborFindResult = cbor_value_advance(&credMap);
555 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Advancing CRED Map.");
561 if (cbor_value_is_valid(&credArray))
563 cborFindResult = cbor_value_advance(&credArray);
564 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Advancing CRED Array.");
569 // TODO : Need to modify headCred->owners[0].id to headCred->rowner based on RAML spec.
570 if (strcmp(tagName, OIC_JSON_ROWNERID_NAME) == 0)
572 char *stRowner = NULL;
573 cborFindResult = cbor_value_dup_text_string(&CredRootMap, &stRowner, &len, NULL);
574 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Finding Rownerid Value.");
575 headCred->ownersLen = 1;
576 headCred->owners = (OicUuid_t *)OICCalloc(headCred->ownersLen, sizeof(*headCred->owners));
577 VERIFY_NON_NULL(TAG, headCred->owners, ERROR);
578 ret = ConvertStrToUuid(stRowner, &headCred->owners[0]);
579 VERIFY_SUCCESS(TAG, ret == OC_STACK_OK, ERROR);
584 if (cbor_value_is_valid(&CredRootMap))
586 cborFindResult = cbor_value_advance(&CredRootMap);
587 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Advancing CRED Root Map.");
595 if (CborNoError != cborFindResult)
597 DeleteCredList(headCred);
600 ret = OC_STACK_ERROR;
606 OicSecCred_t * GenerateCredential(const OicUuid_t * subject, OicSecCredType_t credType,
607 const OicSecCert_t * publicData, const OicSecKey_t* privateData,
608 size_t ownersLen, const OicUuid_t * owners)
611 OCStackResult ret = OC_STACK_ERROR;
613 OicSecCred_t *cred = (OicSecCred_t *)OICCalloc(1, sizeof(*cred));
614 VERIFY_NON_NULL(TAG, cred, ERROR);
616 //CredId is assigned before appending new cred to the existing
617 //credential list and updating svr database in AddCredential().
620 VERIFY_NON_NULL(TAG, subject, ERROR);
621 memcpy(cred->subject.id, subject->id , sizeof(cred->subject.id));
623 VERIFY_SUCCESS(TAG, credType < (NO_SECURITY_MODE | SYMMETRIC_PAIR_WISE_KEY |
624 SYMMETRIC_GROUP_KEY | ASYMMETRIC_KEY | SIGNED_ASYMMETRIC_KEY | PIN_PASSWORD), ERROR);
625 cred->credType = credType;
628 if (publicData && publicData->data)
630 cred->publicData.data = (uint8_t *)OICCalloc(1, publicData->len);
631 VERIFY_NON_NULL(TAG, cred->publicData.data, ERROR);
632 memcpy(cred->publicData.data, publicData->data, publicData->len);
633 cred->publicData.len = publicData->len;
635 #endif // __WITH_X509__
637 if (privateData && privateData->data)
639 cred->privateData.data = (uint8_t *)OICCalloc(1, privateData->len);
640 VERIFY_NON_NULL(TAG, cred->privateData.data, ERROR);
641 memcpy(cred->privateData.data, privateData->data, privateData->len);
642 cred->privateData.len = privateData->len;
645 VERIFY_SUCCESS(TAG, ownersLen > 0, ERROR);
646 cred->ownersLen = ownersLen;
648 cred->owners = (OicUuid_t *)OICCalloc(cred->ownersLen, sizeof(*cred->owners));
649 VERIFY_NON_NULL(TAG, cred->owners, ERROR);
650 for (size_t i = 0; i < cred->ownersLen; i++)
652 memcpy(cred->owners[i].id, owners[i].id, sizeof(cred->owners[i].id));
657 if (OC_STACK_OK != ret)
659 DeleteCredList(cred);
665 static bool UpdatePersistentStorage(const OicSecCred_t *cred)
669 // Convert Cred data into JSON for update to persistent storage
672 uint8_t *payload = NULL;
674 OCStackResult res = CredToCBORPayload(cred, &payload, &size);
675 if ((OC_STACK_OK == res) && payload)
677 if (OC_STACK_OK == UpdateSecureResourceInPS(OIC_JSON_CRED_NAME, payload, size))
684 else //Empty cred list
686 if (OC_STACK_OK == UpdateSecureResourceInPS(OIC_JSON_CRED_NAME, NULL, 0))
695 * Compare function used LL_SORT for sorting credentials.
697 * @param first pointer to OicSecCred_t struct.
698 * @param second pointer to OicSecCred_t struct.
700 *@return -1, if credId of first is less than credId of second.
701 * 0, if credId of first is equal to credId of second.
702 * 1, if credId of first is greater than credId of second.
704 static int CmpCredId(const OicSecCred_t * first, const OicSecCred_t *second)
706 if (first->credId < second->credId)
710 else if (first->credId > second->credId)
719 * GetCredId goes through the cred list and returns the next
720 * available credId. The next credId could be the credId that is
721 * available due deletion of OicSecCred_t object or one more than
722 * credId of last credential in the list.
724 * @return next available credId if successful, else 0 for error.
726 static uint16_t GetCredId()
728 //Sorts credential list in incremental order of credId
729 LL_SORT(gCred, CmpCredId);
731 OicSecCred_t *currentCred = NULL, *credTmp = NULL;
732 uint16_t nextCredId = 1;
734 LL_FOREACH_SAFE(gCred, currentCred, credTmp)
736 if (currentCred->credId == nextCredId)
746 VERIFY_SUCCESS(TAG, nextCredId < UINT16_MAX, ERROR);
754 * Get the default value.
756 * @return NULL for now.
758 static OicSecCred_t* GetCredDefault()
760 // TODO:Update it when we finalize the default info.
764 OCStackResult AddCredential(OicSecCred_t * newCred)
766 OCStackResult ret = OC_STACK_ERROR;
767 VERIFY_SUCCESS(TAG, NULL != newCred, ERROR);
769 //Assigning credId to the newCred
770 newCred->credId = GetCredId();
771 VERIFY_SUCCESS(TAG, newCred->credId != 0, ERROR);
773 //Append the new Cred to existing list
774 LL_APPEND(gCred, newCred);
776 if (UpdatePersistentStorage(gCred))
785 OCStackResult RemoveCredential(const OicUuid_t *subject)
787 OCStackResult ret = OC_STACK_ERROR;
788 OicSecCred_t *cred = NULL;
789 OicSecCred_t *tempCred = NULL;
790 bool deleteFlag = false;
792 LL_FOREACH_SAFE(gCred, cred, tempCred)
794 if (memcmp(cred->subject.id, subject->id, sizeof(subject->id)) == 0)
796 LL_DELETE(gCred, cred);
804 if (UpdatePersistentStorage(gCred))
806 ret = OC_STACK_RESOURCE_DELETED;
814 * Remove all credential data on credential resource and persistent storage
817 * OC_STACK_OK - no errors
818 * OC_STACK_ERROR - stack process error
820 OCStackResult RemoveAllCredentials(void)
822 DeleteCredList(gCred);
823 gCred = GetCredDefault();
825 if (!UpdatePersistentStorage(gCred))
827 return OC_STACK_ERROR;
834 * Internal function to fill private data of owner PSK.
836 * @param receviedCred recevied owner credential from OBT(PT)
837 * @param ownerAdd address of OBT(PT)
838 * @param doxm current device's doxm resource
841 * true successfully done and valid ower psk information
842 * false Invalid owner psk information or failed to owner psk generation
844 static bool FillPrivateDataOfOwnerPSK(OicSecCred_t* receviedCred, const CAEndpoint_t* ownerAddr,
845 const OicSecDoxm_t* doxm)
847 //Derive OwnerPSK locally
848 const char* oxmLabel = GetOxmString(doxm->oxmSel);
849 VERIFY_NON_NULL(TAG, oxmLabel, ERROR);
851 uint8_t ownerPSK[OWNER_PSK_LENGTH_128] = {0};
852 CAResult_t pskRet = CAGenerateOwnerPSK(ownerAddr,
853 (uint8_t*)oxmLabel, strlen(oxmLabel),
854 doxm->owner.id, sizeof(doxm->owner.id),
855 doxm->deviceID.id, sizeof(doxm->deviceID.id),
856 ownerPSK, OWNER_PSK_LENGTH_128);
857 VERIFY_SUCCESS(TAG, pskRet == CA_STATUS_OK, ERROR);
859 OIC_LOG(DEBUG, TAG, "OwnerPSK dump :");
860 OIC_LOG_BUFFER(DEBUG, TAG, ownerPSK, OWNER_PSK_LENGTH_128);
862 //Generate owner credential based on recevied credential information
863 receviedCred->privateData.data = (uint8_t *)OICCalloc(1, OWNER_PSK_LENGTH_128);
864 VERIFY_NON_NULL(TAG, receviedCred->privateData.data, ERROR);
865 receviedCred->privateData.len = OWNER_PSK_LENGTH_128;
866 memcpy(receviedCred->privateData.data, ownerPSK, OWNER_PSK_LENGTH_128);
868 OIC_LOG(INFO, TAG, "PrivateData of OwnerPSK was calculated successfully");
870 //Verify OwnerPSK information
871 return (memcmp(&(receviedCred->subject), &(doxm->owner), sizeof(OicUuid_t)) == 0 &&
872 receviedCred->credType == SYMMETRIC_PAIR_WISE_KEY);
874 //receviedCred->privateData.data will be deallocated when deleting credential.
878 #endif //__WITH_DTLS__
880 static OCEntityHandlerResult HandlePutRequest(const OCEntityHandlerRequest * ehRequest)
882 OCEntityHandlerResult ret = OC_EH_ERROR;
883 OIC_LOG(DEBUG, TAG, "HandleCREDPutRequest IN");
885 //Get binary representation of cbor
886 OicSecCred_t *cred = NULL;
887 uint8_t *payload = (((OCSecurityPayload*)ehRequest->payload)->securityData1);
888 size_t size = (((OCSecurityPayload*)ehRequest->payload)->payloadSize);
889 OCStackResult res = CBORPayloadToCred(payload, size, &cred);
890 if (res == OC_STACK_OK)
893 OicUuid_t emptyUuid = {.id={0}};
894 const OicSecDoxm_t* doxm = GetDoxmResourceData();
895 if(false == doxm->owned && memcmp(&(doxm->owner), &emptyUuid, sizeof(OicUuid_t)) != 0)
897 //in case of owner PSK
898 switch(cred->credType)
900 case SYMMETRIC_PAIR_WISE_KEY:
902 OCServerRequest *request = (OCServerRequest *)ehRequest->requestHandle;
903 if(FillPrivateDataOfOwnerPSK(cred, (CAEndpoint_t *)&request->devAddr, doxm))
905 if(OC_STACK_RESOURCE_DELETED == RemoveCredential(&cred->subject))
907 OIC_LOG(WARNING, TAG, "The credential with the same subject ID was detected!");
910 OIC_LOG(ERROR, TAG, "OwnerPSK was generated successfully.");
911 if(OC_STACK_OK == AddCredential(cred))
913 ret = OC_EH_RESOURCE_CREATED;
917 OIC_LOG(ERROR, TAG, "Failed to save the OwnerPSK as cred resource");
923 OIC_LOG(ERROR, TAG, "Failed to verify receviced OwnerPKS.");
927 if(OC_EH_RESOURCE_CREATED == ret)
930 * in case of random PIN based OxM,
931 * revert get_psk_info callback of tinyDTLS to use owner credential.
933 if(OIC_RANDOM_DEVICE_PIN == doxm->oxmSel)
935 OicUuid_t emptyUuid = { .id={0}};
936 SetUuidForRandomPinOxm(&emptyUuid);
938 if(CA_STATUS_OK != CARegisterDTLSCredentialsHandler(GetDtlsPskCredentials))
940 OIC_LOG(ERROR, TAG, "Failed to revert DTLS credential handler.");
946 //Select cipher suite to use owner PSK
947 if(CA_STATUS_OK != CAEnableAnonECDHCipherSuite(false))
949 OIC_LOG(ERROR, TAG, "Failed to disable anonymous cipher suite");
954 OIC_LOG(INFO, TAG, "Anonymous cipher suite is DISABLED");
958 CASelectCipherSuite(TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA_256))
960 OIC_LOG(ERROR, TAG, "Failed to select cipher suite");
967 case SYMMETRIC_GROUP_KEY:
969 case SIGNED_ASYMMETRIC_KEY:
971 case ASYMMETRIC_ENCRYPTION_KEY:
973 OIC_LOG(WARNING, TAG, "Unsupported credential type for owner credential.");
979 OIC_LOG(WARNING, TAG, "Unknow credential type for owner credential.");
985 if(OC_EH_RESOURCE_CREATED != ret)
988 * If some error is occured while ownership transfer,
989 * ownership transfer related resource should be revert back to initial status.
991 RestoreDoxmToInitState();
992 RestorePstatToInitState();
998 * If the post request credential has credId, it will be
999 * discarded and the next available credId will be assigned
1000 * to it before getting appended to the existing credential
1001 * list and updating svr database.
1003 ret = (OC_STACK_OK == AddCredential(cred))? OC_EH_RESOURCE_CREATED : OC_EH_ERROR;
1005 #else //not __WITH_DTLS__
1007 * If the post request credential has credId, it will be
1008 * discarded and the next available credId will be assigned
1009 * to it before getting appended to the existing credential
1010 * list and updating svr database.
1012 ret = (OC_STACK_OK == AddCredential(cred))? OC_EH_RESOURCE_CREATED : OC_EH_ERROR;
1013 #endif//__WITH_DTLS__
1016 if (OC_EH_RESOURCE_CREATED != ret)
1018 if(OC_STACK_OK != RemoveCredential(&cred->subject))
1020 OIC_LOG(WARNING, TAG, "Failed to remove the invalid credential");
1024 OIC_LOG(DEBUG, TAG, "HandleCREDPutRequest OUT");
1028 static OCEntityHandlerResult HandlePostRequest(const OCEntityHandlerRequest * ehRequest)
1030 OCEntityHandlerResult ret = OC_EH_ERROR;
1032 //Get binary representation of CBOR
1033 OicSecCred_t *cred = NULL;
1034 uint8_t *payload = ((OCSecurityPayload*)ehRequest->payload)->securityData1;
1035 size_t size = ((OCSecurityPayload*)ehRequest->payload)->payloadSize;
1036 OCStackResult res = CBORPayloadToCred(payload, size, &cred);
1037 if ((OC_STACK_OK == res) && cred)
1039 //If the Post request credential has credId, it will be
1040 //discarded and the next available credId will be assigned
1041 //to it before getting appended to the existing credential
1042 //list and updating svr database.
1043 ret = (OC_STACK_OK == AddCredential(cred))? OC_EH_RESOURCE_CREATED : OC_EH_ERROR;
1049 static OCEntityHandlerResult HandleDeleteRequest(const OCEntityHandlerRequest *ehRequest)
1051 OIC_LOG(DEBUG, TAG, "Processing CredDeleteRequest");
1053 OCEntityHandlerResult ehRet = OC_EH_ERROR;
1055 unsigned char base64Buff[sizeof(((OicUuid_t*)0)->id)] = {};
1056 B64Result b64Ret = B64_OK;
1057 uint32_t outLen = 0;
1059 if (NULL == ehRequest->query)
1064 OicParseQueryIter_t parseIter = { .attrPos=NULL };
1065 OicUuid_t subject = {.id={0}};
1067 //Parsing REST query to get the subject
1068 ParseQueryIterInit((unsigned char *)ehRequest->query, &parseIter);
1069 while (GetNextQuery(&parseIter))
1071 if (strncasecmp((char *)parseIter.attrPos, OIC_JSON_SUBJECT_NAME,
1072 parseIter.attrLen) == 0)
1074 b64Ret = b64Decode((char*)parseIter.valPos, parseIter.valLen, base64Buff,
1075 sizeof(base64Buff), &outLen);
1076 VERIFY_SUCCESS(TAG, (b64Ret == B64_OK && outLen <= sizeof(subject.id)), ERROR);
1077 memcpy(subject.id, base64Buff, outLen);
1081 if (OC_STACK_RESOURCE_DELETED == RemoveCredential(&subject))
1083 ehRet = OC_EH_RESOURCE_DELETED;
1090 OCEntityHandlerResult CredEntityHandler(OCEntityHandlerFlag flag,
1091 OCEntityHandlerRequest * ehRequest,
1092 void* callbackParameter)
1094 (void)callbackParameter;
1095 OCEntityHandlerResult ret = OC_EH_ERROR;
1101 if (flag & OC_REQUEST_FLAG)
1103 OIC_LOG (DEBUG, TAG, "Flag includes OC_REQUEST_FLAG");
1104 //TODO : Handle PUT/DEL methods
1105 switch (ehRequest->method)
1108 ret = OC_EH_FORBIDDEN;
1111 ret = HandlePutRequest(ehRequest);
1114 ret = HandlePostRequest(ehRequest);
1116 case OC_REST_DELETE:
1117 ret = HandleDeleteRequest(ehRequest);
1125 //Send payload to request originator
1126 ret = (SendSRMCBORResponse(ehRequest, ret, NULL, 0) == OC_STACK_OK) ?
1132 OCStackResult CreateCredResource()
1134 OCStackResult ret = OCCreateResource(&gCredHandle,
1135 OIC_RSRC_TYPE_SEC_CRED,
1142 if (OC_STACK_OK != ret)
1144 OIC_LOG (FATAL, TAG, "Unable to instantiate Cred resource");
1145 DeInitCredResource();
1150 OCStackResult InitCredResource()
1152 OCStackResult ret = OC_STACK_ERROR;
1154 //Read Cred resource from PS
1155 uint8_t *data = NULL;
1157 ret = GetSecureVirtualDatabaseFromPS(OIC_JSON_CRED_NAME, &data, &size);
1158 // If database read failed
1159 if (ret != OC_STACK_OK)
1161 OIC_LOG (DEBUG, TAG, "ReadSVDataFromPS failed");
1165 // Read ACL resource from PS
1166 ret = CBORPayloadToCred(data, size, &gCred);
1170 * If SVR database in persistent storage got corrupted or
1171 * is not available for some reason, a default Cred is created
1172 * which allows user to initiate Cred provisioning again.
1174 if (ret != OC_STACK_OK || !data || !gCred)
1176 gCred = GetCredDefault();
1178 //Instantiate 'oic.sec.cred'
1179 ret = CreateCredResource();
1184 OCStackResult DeInitCredResource()
1186 OCStackResult result = OCDeleteResource(gCredHandle);
1187 DeleteCredList(gCred);
1192 const OicSecCred_t* GetCredResourceData(const OicUuid_t* subject)
1194 OicSecCred_t *cred = NULL;
1196 if ( NULL == subject)
1201 LL_FOREACH(gCred, cred)
1203 if(memcmp(cred->subject.id, subject->id, sizeof(subject->id)) == 0)
1212 #if defined(__WITH_DTLS__)
1213 int32_t GetDtlsPskCredentials(CADtlsPskCredType_t type,
1214 const uint8_t *desc, size_t desc_len,
1215 uint8_t *result, size_t result_length)
1226 case CA_DTLS_PSK_HINT:
1227 case CA_DTLS_PSK_IDENTITY:
1229 OicUuid_t deviceID = {.id={}};
1230 // Retrieve Device ID from doxm resource
1231 if ( OC_STACK_OK != GetDoxmDeviceID(&deviceID) )
1233 OIC_LOG (ERROR, TAG, "Unable to retrieve doxm Device ID");
1237 if (result_length < sizeof(deviceID.id))
1239 OIC_LOG (ERROR, TAG, "Wrong value for result_length");
1242 memcpy(result, deviceID.id, sizeof(deviceID.id));
1243 return (sizeof(deviceID.id));
1247 case CA_DTLS_PSK_KEY:
1249 OicSecCred_t *cred = NULL;
1250 LL_FOREACH(gCred, cred)
1252 if (cred->credType != SYMMETRIC_PAIR_WISE_KEY)
1257 if ((desc_len == sizeof(cred->subject.id)) &&
1258 (memcmp(desc, cred->subject.id, sizeof(cred->subject.id)) == 0))
1261 * If the credentials are valid for limited time,
1262 * check their expiry.
1266 if(IOTVTICAL_VALID_ACCESS != IsRequestWithinValidTime(cred->period, NULL))
1268 OIC_LOG (INFO, TAG, "Credentials are expired.");
1275 result_length = cred->privateData.len;
1276 memcpy(result, cred->privateData.data, result_length);
1277 return result_length;
1285 OIC_LOG (ERROR, TAG, "Wrong value passed for CADtlsPskCredType_t.");
1295 * Add temporal PSK to PIN based OxM
1297 * @param[in] tmpSubject UUID of target device
1298 * @param[in] credType Type of credential to be added
1299 * @param[in] pin numeric characters
1300 * @param[in] pinSize length of 'pin'
1301 * @param[in] ownersLen Number of owners
1302 * @param[in] owners Array of owners
1303 * @param[out] tmpCredSubject Generated credential's subject.
1305 * @return OC_STACK_OK for success and errorcode otherwise.
1307 OCStackResult AddTmpPskWithPIN(const OicUuid_t* tmpSubject, OicSecCredType_t credType,
1308 const char * pin, size_t pinSize,
1309 size_t ownersLen, const OicUuid_t * owners, OicUuid_t* tmpCredSubject)
1311 OCStackResult ret = OC_STACK_ERROR;
1312 OIC_LOG(DEBUG, TAG, "AddTmpPskWithPIN IN");
1314 if(NULL == tmpSubject || NULL == pin || 0 == pinSize || NULL == tmpCredSubject)
1316 return OC_STACK_INVALID_PARAM;
1319 uint8_t privData[OWNER_PSK_LENGTH_128] = {0,};
1320 OicSecKey_t privKey = {privData, OWNER_PSK_LENGTH_128};
1321 OicSecCred_t* cred = NULL;
1322 int dtlsRes = DeriveCryptoKeyFromPassword((const unsigned char *)pin, pinSize, owners->id,
1323 UUID_LENGTH, PBKDF_ITERATIONS,
1324 OWNER_PSK_LENGTH_128, privData);
1325 VERIFY_SUCCESS(TAG, (0 == dtlsRes) , ERROR);
1327 cred = GenerateCredential(tmpSubject, credType, NULL,
1328 &privKey, ownersLen, owners);
1331 OIC_LOG(ERROR, TAG, "GeneratePskWithPIN() : Failed to generate credential");
1332 return OC_STACK_ERROR;
1335 memcpy(tmpCredSubject->id, cred->subject.id, UUID_LENGTH);
1337 ret = AddCredential(cred);
1338 if( OC_STACK_OK != ret)
1340 RemoveCredential(tmpSubject);
1341 OIC_LOG(ERROR, TAG, "GeneratePskWithPIN() : Failed to add credential");
1343 OIC_LOG(DEBUG, TAG, "AddTmpPskWithPIN OUT");
1349 #endif /* __WITH_DTLS__ */
1350 #ifdef __WITH_X509__
1351 #define CERT_LEN_PREFIX (3)
1352 #define BYTE_SIZE (8) //bits
1353 #define PUB_KEY_X_COORD ("x")
1354 #define PUB_KEY_Y_COORD ("y")
1355 #define CERTIFICATE ("x5c")
1356 #define PRIVATE_KEY ("d")
1358 static uint32_t parseCertPrefix(uint8_t *prefix)
1363 for (int i = 0; i < CERT_LEN_PREFIX; ++i)
1365 res |= (((uint32_t) prefix[i]) << ((CERT_LEN_PREFIX - 1 -i) * BYTE_SIZE));
1371 static OCStackResult GetCAPublicKeyData(CADtlsX509Creds_t *credInfo)
1373 OCStackResult ret = OC_STACK_ERROR;
1374 uint8_t *ccPtr = credInfo->certificateChain;
1375 for (uint8_t i = 0; i < credInfo->chainLen - 1; ++i)
1377 ccPtr += CERT_LEN_PREFIX + parseCertPrefix(ccPtr);
1380 ByteArray cert = { .data = ccPtr + CERT_LEN_PREFIX, .len = parseCertPrefix(ccPtr) };
1381 CertificateX509 certStruct;
1383 VERIFY_SUCCESS(TAG, PKI_SUCCESS == DecodeCertificate(cert, &certStruct), ERROR);
1385 INC_BYTE_ARRAY(certStruct.pubKey, 2);
1387 memcpy(credInfo->rootPublicKeyX, certStruct.pubKey.data, PUBLIC_KEY_SIZE / 2);
1388 memcpy(credInfo->rootPublicKeyY, certStruct.pubKey.data + PUBLIC_KEY_SIZE / 2, PUBLIC_KEY_SIZE / 2);
1395 int GetDtlsX509Credentials(CADtlsX509Creds_t *credInfo)
1398 VERIFY_NON_NULL(TAG, credInfo, ERROR);
1401 VERIFY_SUCCESS(TAG, OC_STACK_OK == InitCredResource(), ERROR);
1404 OicSecCred_t *cred = NULL;
1405 LL_SEARCH_SCALAR(gCred, cred, credType, SIGNED_ASYMMETRIC_KEY);
1406 VERIFY_NON_NULL(TAG, cred, ERROR);
1408 if (cred->publicData.len > MAX_CERT_MESSAGE_LEN || cred->privateData.len > PRIVATE_KEY_SIZE)
1412 memcpy(credInfo->certificateChain, cred->publicData.data, cred->publicData.len);
1413 memcpy(credInfo->devicePrivateKey, cred->privateData.data, cred->privateData.len);
1414 credInfo->certificateChainLen = parseCertPrefix(cred->publicData.data);
1415 GetCAPublicKeyData(credInfo);
1421 #undef CERT_LEN_PREFIX
1422 #endif /* __WITH_X509__ */