IOT-2539 Cleanup -Wformat= warnings
[iotivity.git] / resource / csdk / security / src / rolesresource.c
1 //******************************************************************
2 //
3 // Copyright 2017 Microsoft
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
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
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
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.
18 //
19 //******************************************************************
20
21 #if defined(__WITH_DTLS__) || defined(__WITH_TLS__)
22 #include "iotivity_config.h"
23 #include <stdlib.h>
24 #ifdef HAVE_STRING_H
25 #include <string.h>
26 #endif
27 #ifdef HAVE_STRINGS_H
28 #include <strings.h>
29 #endif
30 #include <stdint.h>
31 #include <stdbool.h>
32 #include <inttypes.h>
33 #include "oic_string.h"
34 #include "cainterface.h"
35 #include "payload_logging.h"
36 #include "ocstack.h"
37 #include "ocrandom.h"
38 #include "cacommon.h"
39 #include "srmresourcestrings.h"
40 #include "ocpayload.h"
41 #include "ocpayloadcbor.h"
42 #include "credresource.h"
43 #include "doxmresource.h"
44 #include "srmutility.h"
45 #include "certhelpers.h"
46 #include "resourcemanager.h"
47 #include "utlist.h"
48 #include "ca_adapter_net_ssl.h"
49 #include "ocstackinternal.h"
50 #include "rolesresource.h"
51 #include "secureresourcemanager.h"
52
53 #define TAG  "OIC_SRM_ROLES"
54
55 typedef struct RolesEntry {
56     uint8_t                 *publicKey;         /**< DER-encoded public key */
57     size_t                  publicKeyLength;    /**< length of publicKey */
58     RoleCertChain_t         *chains;            /**< stored certificates */
59
60     struct tm               cacheValidUntil;    /**< Cache valid until time; use 0 if cache is not yet set */
61     OicSecRole_t            *cachedRoles;       /**< Cached roles; must free with OICFree */
62     size_t                  cachedRolesLength;  /**< Length of cachedRoles array */
63
64     struct RolesEntry       *next;
65 } RolesEntry_t;
66
67 typedef struct SymmetricRoleEntry {
68     OicUuid_t                 subject;          /**< Subject of the symmetric credential */
69     OicSecRole_t              role;             /**< Role of the symmetric credential */
70
71     struct SymmetricRoleEntry *next;
72 } SymmetricRoleEntry_t;
73
74 static OCResourceHandle     gRolesHandle        = NULL;
75 static RolesEntry_t         *gRoles             = NULL;
76 static SymmetricRoleEntry_t *gSymmetricRoles    = NULL;
77 static uint32_t             gIdCounter          = 1;
78
79 /**
80  * Default cbor payload size. This value is increased in case of CborErrorOutOfMemory.
81  * The value of payload size is increased until reaching max cbor size.
82  */
83 static const uint16_t CBOR_SIZE = 2048;
84
85 /**
86  * Zero subject UUID.
87  */
88 static const char EMPTY_UUID[] = "00000000-0000-0000-0000-000000000000";
89
90 /**
91  * Mandatory parts of a role map cred entry: 4 key/value pairs: credId, subject, publicData, and credType.
92  */
93 static const uint8_t ROLE_MAP_SIZE = 4;
94
95 static void InvalidateRoleCache(RolesEntry_t *entry)
96 {
97     memset(&entry->cacheValidUntil, 0, sizeof(entry->cacheValidUntil));
98     OICFree(entry->cachedRoles);
99     entry->cachedRoles = NULL;
100     entry->cachedRolesLength = 0;
101 }
102
103 /* Caller must call OICFree on publicKey when finished. */
104 static OCStackResult GetPeerPublicKeyFromEndpoint(const CAEndpoint_t *endpoint,
105                                                   uint8_t **publicKey,
106                                                   size_t *publicKeyLength)
107 {
108     CASecureEndpoint_t sep;
109     CAResult_t res = GetCASecureEndpointData(endpoint, &sep);
110     if (CA_STATUS_OK != res)
111     {
112         OIC_LOG_V(ERROR, TAG, "%s: Failed to GetCASecureEndpointData: %d", __func__, res);
113         return OC_STACK_INVALID_PARAM;
114     }
115
116     if ((NULL == sep.publicKey) || (0 == sep.publicKeyLength))
117     {
118         OIC_LOG_V(WARNING, TAG, "%s: Peer did not have a public key", __func__);
119         return OC_STACK_NO_RESOURCE;
120     }
121
122     *publicKey = OICCalloc(1, sep.publicKeyLength);
123     if (NULL == *publicKey)
124     {
125         OIC_LOG_V(ERROR, TAG, "%s: No memory for publicKey", __func__);
126         return OC_STACK_NO_MEMORY;
127     }
128
129     memcpy(*publicKey, sep.publicKey, sep.publicKeyLength);
130     *publicKeyLength = sep.publicKeyLength;
131
132     return OC_STACK_OK;
133 }
134
135 /* Caller must call OICFree on publicKey when finished. */
136 static OCStackResult GetPeerPublicKey(const OCDevAddr *peer, uint8_t **publicKey, size_t *publicKeyLength)
137 {
138     CAEndpoint_t endpoint;
139     CopyDevAddrToEndpoint(peer, &endpoint);
140
141     return GetPeerPublicKeyFromEndpoint(&endpoint, publicKey, publicKeyLength);
142 }
143
144 static void FreeRoleCertChain(RoleCertChain_t *roleCert)
145 {
146     if (NULL == roleCert)
147     {
148         return;
149     }
150
151     OICFree(roleCert->optData.data);
152     OICFree(roleCert->certificate.data);
153     OICFree(roleCert);
154 }
155
156 void FreeRoleCertChainList(RoleCertChain_t *roleCertList)
157 {
158     if (NULL == roleCertList)
159     {
160         return;
161     }
162
163     RoleCertChain_t *certTmp1 = NULL;
164     RoleCertChain_t *certTmp2 = NULL;
165     LL_FOREACH_SAFE(roleCertList, certTmp1, certTmp2)
166     {
167         LL_DELETE(roleCertList, certTmp1);
168         FreeRoleCertChain(certTmp1);
169     }
170 }
171
172 static void FreeRolesEntry(RolesEntry_t *rolesEntry)
173 {
174     if (NULL == rolesEntry)
175     {
176         return;
177     }
178
179     FreeRoleCertChainList(rolesEntry->chains);
180     OICFree(rolesEntry->publicKey);
181     OICFree(rolesEntry->cachedRoles);
182     OICFree(rolesEntry);
183 }
184
185 static void FreeRolesList(RolesEntry_t *roles)
186 {
187     if (NULL != roles)
188     {
189         RolesEntry_t *entryTmp1 = NULL;
190         RolesEntry_t *entryTmp2 = NULL;
191         LL_FOREACH_SAFE(roles, entryTmp1, entryTmp2)
192         {
193             LL_DELETE(roles, entryTmp1);
194             FreeRolesEntry(entryTmp1);
195         }
196     }
197 }
198
199 static void FreeSymmetricRoleEntry(SymmetricRoleEntry_t *symRoleEntry)
200 {
201     OICFree(symRoleEntry);
202 }
203
204 static void FreeSymmetricRolesList(SymmetricRoleEntry_t *head)
205 {
206     if (NULL != head)
207     {
208         SymmetricRoleEntry_t *entryTmp1 = NULL;
209         SymmetricRoleEntry_t *entryTmp2 = NULL;
210
211         LL_FOREACH_SAFE(head, entryTmp1, entryTmp2)
212         {
213             LL_DELETE(head, entryTmp1);
214             FreeSymmetricRoleEntry(entryTmp1);
215         }
216     }
217 }
218
219 OCStackResult RegisterSymmetricCredentialRole(const OicSecCred_t *cred)
220 {
221     VERIFY_NON_NULL_RET(cred, TAG, "Parameter cred is NULL", OC_STACK_INVALID_PARAM);
222     VERIFY_SUCCESS_RETURN(TAG, (SYMMETRIC_PAIR_WISE_KEY == cred->credType), ERROR, OC_STACK_INVALID_PARAM);
223
224     SymmetricRoleEntry_t *curr = NULL;
225
226     LL_FOREACH(gSymmetricRoles, curr)
227     {
228         if (0 == memcmp(&cred->subject, &curr->subject, sizeof(curr->subject)))
229         {
230             if (!IsNonEmptyRole(&cred->roleId))
231             {
232                 LL_DELETE(gSymmetricRoles, curr);
233             }
234             else
235             {
236                 curr->role = cred->roleId;
237             }
238
239             return OC_STACK_OK;
240         }
241     }
242
243     /* No entry found; add a new one if we're setting a role. */
244     if (IsNonEmptyRole(&cred->roleId))
245     {
246         curr = (SymmetricRoleEntry_t *)OICCalloc(1, sizeof(SymmetricRoleEntry_t));
247         if (NULL == curr)
248         {
249             OIC_LOG(ERROR, TAG, "No memory allocating new symmetric role entry");
250             return OC_STACK_NO_MEMORY;
251         }
252         LL_APPEND(gSymmetricRoles, curr);
253         curr->subject = cred->subject;
254         curr->role = cred->roleId;
255     }
256
257     return OC_STACK_OK;
258 }
259
260 static OCStackResult DuplicateRoleCertChain(const RoleCertChain_t *roleCert, RoleCertChain_t **duplicate)
261 {
262     OIC_LOG(DEBUG, TAG, "DuplicateRoleCertChain IN");
263
264     OCStackResult res = OC_STACK_ERROR;
265     RoleCertChain_t *tmp = NULL;
266
267     if ((NULL == roleCert) || (NULL == duplicate))
268     {
269         res = OC_STACK_INVALID_PARAM;
270         goto exit;
271     }
272
273     tmp = (RoleCertChain_t *)OICCalloc(1, sizeof(RoleCertChain_t));
274     if (NULL == tmp)
275     {
276         OIC_LOG(ERROR, TAG, "No memory for tmp");
277         res = OC_STACK_NO_MEMORY;
278         goto exit;
279     }
280
281     tmp->certificate.data = (uint8_t *)OICCalloc(1, roleCert->certificate.len);
282     if (NULL == tmp->certificate.data)
283     {
284         OIC_LOG(ERROR, TAG, "No memory for certificate data");
285         res = OC_STACK_NO_MEMORY;
286         goto exit;
287     }
288     tmp->credId = roleCert->credId;
289     tmp->certificate.len = roleCert->certificate.len;
290     tmp->certificate.encoding = roleCert->certificate.encoding;
291     memcpy(tmp->certificate.data, roleCert->certificate.data, roleCert->certificate.len);
292
293     if (NULL != roleCert->optData.data)
294     {
295         tmp->optData.data = (uint8_t *)OICCalloc(1, roleCert->optData.len);
296         if (NULL == tmp->optData.data)
297         {
298             OIC_LOG(ERROR, TAG, "No memory for optional data");
299             res = OC_STACK_NO_MEMORY;
300             goto exit;
301         }
302         tmp->optData.len = roleCert->optData.len;
303         tmp->optData.encoding = roleCert->optData.encoding;
304         tmp->optData.revstat = roleCert->optData.revstat;
305         memcpy(tmp->optData.data, roleCert->optData.data, roleCert->optData.len);
306     }
307
308     *duplicate = tmp;
309     res = OC_STACK_OK;
310
311 exit:
312
313     OIC_LOG_V(DEBUG, TAG, "DuplicateRoleCertChain OUT: %d", res);
314
315     if (OC_STACK_OK != res)
316     {
317         FreeRoleCertChain(tmp);
318     }
319
320     return res;
321 }
322
323 static bool RoleCertChainContains(RoleCertChain_t *chain, const RoleCertChain_t* roleCert)
324 {
325     RoleCertChain_t *temp = NULL;
326
327     LL_FOREACH(chain, temp)
328     {
329         if (IsSameSecKey(&temp->certificate, &roleCert->certificate) &&
330             IsSameSecOpt(&temp->optData, &roleCert->optData))
331         {
332             return true;
333         }
334     }
335
336     return false;
337 }
338
339 static OCStackResult AddRoleCertificate(const RoleCertChain_t *roleCert, const uint8_t *pubKey, size_t pubKeyLength)
340 {
341     OCStackResult res = OC_STACK_ERROR;
342     RolesEntry_t *targetEntry = NULL;
343     RoleCertChain_t *copy = NULL;
344
345     OIC_LOG(DEBUG, TAG, "AddRoleCertificate IN");
346
347     if ((NULL == pubKey) || (0 == pubKeyLength))
348     {
349         assert(!"AddRoleCertificate called with no public key");
350         res = OC_STACK_INVALID_PARAM;
351         goto exit;
352     }
353
354     for (targetEntry = gRoles; NULL != targetEntry; targetEntry = targetEntry->next)
355     {
356         if ((targetEntry->publicKeyLength == pubKeyLength) &&
357             (0 == memcmp(targetEntry->publicKey, pubKey, pubKeyLength)))
358         {
359             break;
360         }
361     }
362
363     if (NULL != targetEntry)
364     {
365         InvalidateRoleCache(targetEntry);
366     }
367     else
368     {
369         /* We haven't seen this public key before and need a new entry. */
370         targetEntry = (RolesEntry_t *)OICCalloc(1, sizeof(RolesEntry_t));
371         if (NULL == targetEntry)
372         {
373             OIC_LOG(ERROR, TAG, "No memory for new targetEntry");
374             res = OC_STACK_NO_MEMORY;
375             goto exit;
376         }
377         targetEntry->publicKey = (uint8_t *)OICCalloc(1, pubKeyLength);
378         if (NULL == targetEntry->publicKey)
379         {
380             OIC_LOG(ERROR, TAG, "No memory for new targetEntry public key");
381             OICFree(targetEntry);
382             res = OC_STACK_NO_MEMORY;
383             goto exit;
384         }
385         targetEntry->publicKeyLength = pubKeyLength;
386         memcpy(targetEntry->publicKey, pubKey, pubKeyLength);
387
388         LL_PREPEND(gRoles, targetEntry);
389     }
390
391     if (!RoleCertChainContains(targetEntry->chains, roleCert))
392     {
393         res = DuplicateRoleCertChain(roleCert, &copy);
394         if (OC_STACK_OK != res)
395         {
396             OIC_LOG_V(ERROR, TAG, "%s: Could not duplicate role cert chain: %d", __func__, res);
397             goto exit;
398         }
399
400         // Assign our own credId.
401         copy->credId = gIdCounter++;
402         LL_APPEND(targetEntry->chains, copy);
403     }
404     else
405     {
406         OIC_LOG_V(DEBUG, TAG, "%s: Role cert chain already present, not going to add it again", __func__);
407     }
408
409     res = OC_STACK_OK;
410
411 exit:
412
413     if (OC_STACK_OK != res)
414     {
415         FreeRoleCertChain(copy);
416     }
417
418     OIC_LOG_V(DEBUG, TAG, "AddRoleCertificate Out: %d", res);
419
420     return res;
421 }
422
423 OCStackResult RolesToCBORPayload(const RoleCertChain_t *roles, uint8_t **cborPayload,
424                                         size_t *cborSize)
425 {
426     OCStackResult ret = OC_STACK_OK;
427
428     CborError cborEncoderResult = CborNoError;
429     uint8_t *outPayload = NULL;
430     CborEncoder encoder;
431     CborEncoder rolesRootMap;
432     CborEncoder rolesArray;
433     size_t roleCount = 0;
434     const RoleCertChain_t *currChain = NULL;
435
436     VERIFY_NOT_NULL_RETURN(TAG, cborPayload, ERROR, OC_STACK_INVALID_PARAM);
437     VERIFY_NOT_NULL_RETURN(TAG, cborSize, ERROR, OC_STACK_INVALID_PARAM);
438
439     size_t cborLen = *cborSize;
440     *cborSize = 0;
441     *cborPayload = NULL;
442
443     if (0 == cborLen)
444     {
445         cborLen = CBOR_SIZE;
446     }
447
448     outPayload = (uint8_t *)OICCalloc(1, cborLen);
449     VERIFY_NOT_NULL_RETURN(TAG, outPayload, ERROR, OC_STACK_NO_MEMORY);
450     cbor_encoder_init(&encoder, outPayload, cborLen, 0);
451
452     // Create roles root map (roles, rt, if)
453     cborEncoderResult = cbor_encoder_create_map(&encoder, &rolesRootMap, 3);
454     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding roles root map");
455
456     // Roles array
457     cborEncoderResult = cbor_encode_text_string(&rolesRootMap, OIC_JSON_ROLES_NAME, strlen(OIC_JSON_ROLES_NAME));
458     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding roles name tag");
459
460     // If roles is NULL, the "roles" array will be empty
461     for (currChain = roles; NULL != currChain; currChain = currChain->next)
462     {
463         roleCount++;
464     }
465
466     cborEncoderResult = cbor_encoder_create_array(&rolesRootMap, &rolesArray, roleCount);
467     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding roles array");
468
469     for (currChain = roles; NULL != currChain; currChain = currChain->next)
470     {
471         CborEncoder roleMap;
472         size_t mapSize = ROLE_MAP_SIZE;
473
474         if (NULL != currChain->optData.data)
475         {
476             mapSize++;
477         }
478
479         cborEncoderResult = cbor_encoder_create_map(&rolesArray, &roleMap, mapSize);
480         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding role map");
481
482         // credId - mandatory
483         cborEncoderResult = cbor_encode_text_string(&roleMap, OIC_JSON_CREDID_NAME, strlen(OIC_JSON_CREDID_NAME));
484         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding credId tag");
485         cborEncoderResult = cbor_encode_int(&roleMap, currChain->credId);
486         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding credId value");
487
488         // subjectuuid - mandatory - always zero for role certificates
489         cborEncoderResult = cbor_encode_text_string(&roleMap, OIC_JSON_SUBJECTID_NAME, strlen(OIC_JSON_SUBJECTID_NAME));
490         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding subject tag");
491         cborEncoderResult = cbor_encode_text_string(&roleMap, EMPTY_UUID, sizeof(EMPTY_UUID) - 1);
492         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding subject value");
493
494         // publicData - mandatory
495         cborEncoderResult = SerializeEncodingToCbor(&roleMap, OIC_JSON_PUBLICDATA_NAME, &currChain->certificate);
496         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding publicData");
497
498         // optionalData
499         if (NULL != currChain->optData.data)
500         {
501             cborEncoderResult = SerializeSecOptToCbor(&roleMap, OIC_JSON_OPTDATA_NAME, &currChain->optData);
502             VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding optional data");
503         }
504
505         // credType - mandatory
506         cborEncoderResult = cbor_encode_text_string(&roleMap, OIC_JSON_CREDTYPE_NAME, strlen(OIC_JSON_CREDTYPE_NAME));
507         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding credType tag");
508         // Per security spec, only SIGNED_ASYMMETRIC_KEY is supported here.
509         cborEncoderResult = cbor_encode_int(&roleMap, SIGNED_ASYMMETRIC_KEY);
510         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed adding credType value");
511
512         cborEncoderResult = cbor_encoder_close_container(&rolesArray, &roleMap);
513         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed closing role map");
514     }
515
516     cborEncoderResult = cbor_encoder_close_container(&rolesRootMap, &rolesArray);
517     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed closing roles array");
518
519     // RT -- Mandatory
520     CborEncoder rtArray;
521     cborEncoderResult = cbor_encode_text_string(&rolesRootMap, OIC_JSON_RT_NAME,
522         strlen(OIC_JSON_RT_NAME));
523     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding RT Name Tag.");
524     cborEncoderResult = cbor_encoder_create_array(&rolesRootMap, &rtArray, 1);
525     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding RT Value.");
526     for (size_t i = 0; i < 1; i++)
527     {
528         cborEncoderResult = cbor_encode_text_string(&rtArray, OIC_RSRC_TYPE_SEC_ROLES,
529             strlen(OIC_RSRC_TYPE_SEC_ROLES));
530         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding RT Value.");
531     }
532     cborEncoderResult = cbor_encoder_close_container(&rolesRootMap, &rtArray);
533     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing RT.");
534
535     // IF-- Mandatory
536     CborEncoder ifArray;
537     cborEncoderResult = cbor_encode_text_string(&rolesRootMap, OIC_JSON_IF_NAME,
538         strlen(OIC_JSON_IF_NAME));
539     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding IF Name Tag.");
540     cborEncoderResult = cbor_encoder_create_array(&rolesRootMap, &ifArray, 1);
541     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Addding IF Value.");
542     for (size_t i = 0; i < 1; i++)
543     {
544         cborEncoderResult = cbor_encode_text_string(&ifArray, OC_RSRVD_INTERFACE_DEFAULT,
545             strlen(OC_RSRVD_INTERFACE_DEFAULT));
546         VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Adding IF Value.");
547     }
548     cborEncoderResult = cbor_encoder_close_container(&rolesRootMap, &ifArray);
549     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed Closing IF.");
550
551     // Close roles root map
552     cborEncoderResult = cbor_encoder_close_container(&encoder, &rolesRootMap);
553     VERIFY_CBOR_SUCCESS(TAG, cborEncoderResult, "Failed closing roles root map");
554
555     *cborSize = cbor_encoder_get_buffer_size(&encoder, outPayload);
556     *cborPayload = outPayload;
557
558 exit:
559     if (CborErrorOutOfMemory == cborEncoderResult)
560     {
561         OIC_LOG(DEBUG, TAG, "RolesToCBORPayload:CborErrorOutOfMemory : retry with more memory");
562
563         // reallocate and try again!
564         OICFree(outPayload);
565         // Since the initially-allocated memory failed, double the memory.
566         cborLen += cbor_encoder_get_buffer_size(&encoder, encoder.end);
567         ret = RolesToCBORPayload(roles, cborPayload, cborSize);
568         *cborSize = cborLen;
569     }
570     else if (cborEncoderResult != CborNoError)
571     {
572         OIC_LOG(ERROR, TAG, "Failed to RolesToCBORPayload");
573         OICFree(outPayload);
574         *cborSize = 0;
575         *cborPayload = NULL;
576         ret = OC_STACK_ERROR;
577     }
578
579     return ret;
580 }
581
582 /* Caller must call FreeRoleCertChainList on roleEntries when finished. */
583 OCStackResult CBORPayloadToRoles(const uint8_t *cborPayload, size_t size, RoleCertChain_t **roleEntries)
584 {
585     if (NULL == cborPayload || 0 == size || NULL == roleEntries)
586     {
587         return OC_STACK_INVALID_PARAM;
588     }
589
590     CborValue rolesCbor = { .parser = NULL };
591     CborParser parser = { .end = NULL };
592     CborError cborFindResult = CborNoError;
593     RoleCertChain_t *headRoleCertChain = NULL;
594     char* tagName = NULL;
595     size_t len = 0;
596
597     cborFindResult = cbor_parser_init(cborPayload, size, 0, &parser, &rolesCbor);
598     VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed to initialize parser.");
599
600     if (!cbor_value_is_container(&rolesCbor))
601     {
602         return OC_STACK_ERROR;
603     }
604
605     // Enter roles Root Map
606     CborValue rolesRootMap;
607     memset(&rolesRootMap, 0, sizeof(rolesRootMap));
608     cborFindResult = cbor_value_enter_container(&rolesCbor, &rolesRootMap);
609     VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed Entering roles Root Map.");
610
611     while (cbor_value_is_valid(&rolesRootMap))
612     {
613         if (NULL != tagName)
614         {
615             free(tagName);
616             tagName = NULL;
617         }
618         len = 0;
619         CborType type = cbor_value_get_type(&rolesRootMap);
620         if (type == CborTextStringType && cbor_value_is_text_string(&rolesRootMap))
621         {
622             cborFindResult = cbor_value_dup_text_string(&rolesRootMap, &tagName, &len, NULL);
623             VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed finding name in roles Root Map.");
624             cborFindResult = cbor_value_advance(&rolesRootMap);
625             VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed advancing value in roles Root Map.");
626         }
627         else
628         {
629             OIC_LOG_V(WARNING, TAG, "Value is not of type string, but of type %x", type);
630         }
631
632         if (NULL != tagName)
633         {
634             if (strcmp(tagName, OIC_JSON_ROLES_NAME) == 0)
635             {
636                 // Enter role array
637                 int roleCount = 0;
638                 RoleCertChain_t *currEntry = NULL;
639                 CborValue roleArray;
640                 memset(&roleArray, 0, sizeof(roleArray));
641
642                 cborFindResult = cbor_value_enter_container(&rolesRootMap, &roleArray);
643                 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed entering role array.");
644
645                 while (cbor_value_is_valid(&roleArray))
646                 {
647                     roleCount++;
648                     CborValue roleMap;
649                     memset(&roleMap, 0, sizeof(roleMap));
650                     cborFindResult = cbor_value_enter_container(&roleArray, &roleMap);
651                     VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed entering role map.");
652
653                     if (NULL == currEntry)
654                     {
655                         assert(NULL == headRoleCertChain);
656                         headRoleCertChain = currEntry = (RoleCertChain_t *)OICCalloc(1, sizeof(RoleCertChain_t));
657                         VERIFY_NOT_NULL(TAG, currEntry, ERROR);
658                     }
659                     else
660                     {
661                         assert(NULL != headRoleCertChain);
662                         currEntry->next = (RoleCertChain_t *)OICCalloc(1, sizeof(RoleCertChain_t));
663                         VERIFY_NOT_NULL(TAG, currEntry->next, ERROR);
664                         currEntry = currEntry->next;
665                     }
666
667                     while (cbor_value_is_valid(&roleMap))
668                     {
669                         free(tagName);
670                         tagName = NULL;
671                         CborType innerType = cbor_value_get_type(&roleMap);
672                         if (innerType == CborTextStringType)
673                         {
674                             cborFindResult = cbor_value_dup_text_string(&roleMap, &tagName, &len, NULL);
675                             VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed finding name in role map.");
676                             cborFindResult = cbor_value_advance(&roleMap);
677                             VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed advancing value in role map.");
678                         }
679                         if (NULL != tagName)
680                         {
681                             //credid
682                             if (strcmp(tagName, OIC_JSON_CREDID_NAME) == 0)
683                             {
684                                 uint64_t credId64 = 0;
685                                 cborFindResult = cbor_value_get_uint64(&roleMap, &credId64);
686                                 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed retrieving credId.");
687                                 if (UINT32_MAX < credId64)
688                                 {
689                                     cborFindResult = CborUnknownError;
690                                     VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "credId was too large.");
691                                 }
692                                 currEntry->credId = (uint32_t)credId64;
693                             }
694                             else if (strcmp(tagName, OIC_JSON_PUBLICDATA_NAME) == 0)
695                             {
696                                 cborFindResult = DeserializeEncodingFromCbor(&roleMap, &currEntry->certificate);
697                                 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed to read publicData");
698                             }
699                             else if (strcmp(tagName, OIC_JSON_OPTDATA_NAME) == 0)
700                             {
701                                 cborFindResult = DeserializeSecOptFromCbor(&roleMap, &currEntry->optData);
702                                 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed to read optionalData");
703                             }
704                             else if (strcmp(tagName, OIC_JSON_CREDTYPE_NAME) == 0)
705                             {
706                                 uint64_t credType = 0;
707                                 cborFindResult = cbor_value_get_uint64(&roleMap, &credType);
708                                 VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed retrieving credType.");
709                                 /* Only SIGNED_ASYMMETRIC_KEY is supported. */
710                                 if (SIGNED_ASYMMETRIC_KEY != (OicSecCredType_t)credType)
711                                 {
712                                     OIC_LOG_V(ERROR, TAG, "Unsupported role credential type: %lu", credType);
713                                     goto exit;
714                                 }
715                             }
716                             // Silently ignore subject field; log anything else.
717                             else if (strcmp(tagName, OIC_JSON_SUBJECTID_NAME) != 0)
718                             {
719                                 OIC_LOG_V(WARNING, TAG, "Unknown role map tag: %s", tagName);
720                             }
721                         }
722
723                         if (cbor_value_is_valid(&roleMap))
724                         {
725                             cborFindResult = cbor_value_advance(&roleMap);
726                             VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed advancing role map.");
727                         }
728                     }
729
730                     if (NULL == currEntry->certificate.data)
731                     {
732                         OIC_LOG(ERROR, TAG, "Role credential did not have publicData");
733                         goto exit;
734                     }
735
736                     if (cbor_value_is_valid(&roleArray))
737                     {
738                         cborFindResult = cbor_value_advance(&roleArray);
739                         VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed advancing role array.");
740                     }
741                 }
742             }
743             else
744             {
745                 // Ignore any other tag type for now.
746                 OIC_LOG_V(WARNING, TAG, "Unknown role root map tag %s", tagName);
747             }
748
749         }
750         if (cbor_value_is_valid(&rolesRootMap))
751         {
752             cborFindResult = cbor_value_advance(&rolesRootMap);
753             VERIFY_CBOR_SUCCESS(TAG, cborFindResult, "Failed advancing CSR Root Map");
754         }
755     }
756
757     *roleEntries = headRoleCertChain;
758
759 exit:
760     if (NULL != tagName)
761     {
762         free(tagName);
763     }
764
765     if (CborNoError != cborFindResult)
766     {
767         if (NULL != headRoleCertChain)
768         {
769             FreeRoleCertChainList(headRoleCertChain);
770         }
771         return OC_STACK_ERROR;
772     }
773     else
774     {
775         return OC_STACK_OK;
776     }
777 }
778
779 static OCEntityHandlerResult HandleGetRequest(OCEntityHandlerRequest *ehRequest)
780 {
781     OIC_LOG(DEBUG, TAG, "Roles HandleGetRequest IN");
782
783     OCStackResult res = OC_STACK_ERROR;
784     OCEntityHandlerResult ehRet = OC_EH_ERROR;
785     size_t size = 0;
786     uint8_t *payload = NULL;
787     const RoleCertChain_t *roles = NULL;
788     uint8_t *publicKey = NULL;
789     size_t publicKeyLength = 0;
790
791     res = GetPeerPublicKey(&ehRequest->devAddr, &publicKey, &publicKeyLength);
792     // OC_STACK_NO_RESOURCE means that the Peer doesn't have a Public Key.
793     if ((OC_STACK_OK != res) && (OC_STACK_NO_RESOURCE != res))
794     {
795         OIC_LOG_V(ERROR, TAG, "Could not get remote peer's public key: %d", res);
796         ehRet = OC_EH_ERROR;
797         goto exit;
798     }
799
800     if (NULL != publicKey)
801     {
802         for (const RolesEntry_t *entry = gRoles; NULL != entry; entry = entry->next)
803         {
804             if ((entry->publicKeyLength == publicKeyLength) &&
805                 (0 == memcmp(entry->publicKey, publicKey, publicKeyLength)))
806             {
807                 roles = entry->chains;
808                 break;
809             }
810         }
811     }
812
813     // If roles is NULL, we will return success with an empty "roles" array
814     res = RolesToCBORPayload(roles, &payload, &size);
815     ehRet = (OC_STACK_OK == res) ? OC_EH_OK : OC_EH_ERROR;
816
817 exit:
818
819     ehRet = ((SendSRMResponse(ehRequest, ehRet, payload, size)) == OC_STACK_OK) ? OC_EH_OK : OC_EH_ERROR;
820
821     OICFree(payload);
822     OICFree(publicKey);
823
824     OIC_LOG(DEBUG, TAG, "Roles HandleGetRequest OUT");
825     return ehRet;
826 }
827
828 static OCEntityHandlerResult HandlePostRequest(OCEntityHandlerRequest *ehRequest)
829 {
830     OCEntityHandlerResult ehRet = OC_EH_ERROR;
831     uint8_t *pubKey = NULL;
832     size_t pubKeyLength = 0;
833     uint8_t *peerPubKey = NULL;
834     size_t peerPubKeyLen = 0;
835
836     OIC_LOG(DEBUG, TAG, "Roles HandlePostRequest IN");
837
838     RoleCertChain_t *chains = NULL;
839     uint8_t *payload = (((OCSecurityPayload*)ehRequest->payload)->securityData);
840     size_t size = (((OCSecurityPayload*)ehRequest->payload)->payloadSize);
841
842     OCStackResult res = GetPeerPublicKey(&ehRequest->devAddr, &peerPubKey, &peerPubKeyLen);
843     if (OC_STACK_OK != res)
844     {
845         OIC_LOG_V(ERROR, TAG, "Could not get peer's public key: %d", res);
846         ehRet = OC_EH_ERROR;
847         goto exit;
848     }
849
850     res = CBORPayloadToRoles(payload, size, &chains);
851     if (OC_STACK_OK == res)
852     {
853         RoleCertChain_t *curr;
854
855         for (curr = chains; NULL != curr; curr = curr->next)
856         {
857             if (NULL != curr->optData.data)
858             {
859                 if (OC_STACK_OK != OCInternalIsValidCertChain(curr->optData.data, curr->optData.len))
860                 {
861                     OIC_LOG(ERROR, TAG, "Optional data is not a valid cert chain");
862                     ehRet = OC_EH_ERROR;
863                     goto exit;
864                 }
865             }
866
867             if (OC_STACK_OK != OCInternalIsValidRoleCertificate(curr->certificate.data, curr->certificate.len,
868                 &pubKey, &pubKeyLength))
869             {
870                 OIC_LOG(ERROR, TAG, "Could not verify certificate is a valid role certificate");
871                 ehRet = OC_EH_ERROR;
872                 goto exit;
873             }
874
875             if ((pubKeyLength != peerPubKeyLen) ||
876                 (0 != memcmp(pubKey, peerPubKey, pubKeyLength)))
877             {
878                 OIC_LOG(ERROR, TAG, "Peer sent us certificate not for its public key");
879                 continue;
880             }
881
882             if (OC_STACK_OK != AddRoleCertificate(curr, pubKey, pubKeyLength))
883             {
884                 OIC_LOG(ERROR, TAG, "Could not AddRoleCertificate");
885                 ehRet = OC_EH_ERROR;
886                 goto exit;
887             }
888         }
889
890         ehRet = OC_EH_OK;
891     }
892
893 exit:
894
895     ehRet = (SendSRMResponse(ehRequest, ehRet, NULL, 0) == OC_STACK_OK) ? OC_EH_OK : OC_EH_ERROR;
896
897     FreeRoleCertChainList(chains);
898     OICFree(pubKey);
899     OICFree(peerPubKey);
900
901     OIC_LOG(DEBUG, TAG, "Roles HandlePostRequest OUT");
902
903     return ehRet;
904 }
905
906 static OCEntityHandlerResult HandleDeleteRequest(OCEntityHandlerRequest *ehRequest)
907 {
908     OIC_LOG(DEBUG, TAG, "Roles HandleDeleteRequest IN");
909
910     OCEntityHandlerResult ehRet = OC_EH_ERROR;
911     uint8_t *peerPubKey = NULL;
912     size_t peerPubKeyLen = 0;
913     OicParseQueryIter_t parseIter = { .attrPos = NULL };
914     uint32_t credId = 0;
915
916     if (NULL == ehRequest->query)
917     {
918         return ehRet;
919     }
920
921     // Parsing REST query to get the credId
922     ParseQueryIterInit((unsigned char *)ehRequest->query, &parseIter);
923     while (GetNextQuery(&parseIter))
924     {
925         if (strncasecmp((const char *)parseIter.attrPos, OIC_JSON_CREDID_NAME,
926             parseIter.attrLen) == 0)
927         {
928             int ret = sscanf((const char *)parseIter.valPos, "%u", &credId);
929             if (1 > ret)
930             {
931                 OIC_LOG_V(ERROR, TAG, "credId was not valid: %s", parseIter.valPos);
932                 ehRet = OC_EH_ERROR;
933                 goto exit;
934             }
935         }
936         else
937         {
938             OIC_LOG_V(DEBUG, TAG, "Unexpected in query string: %s=%s", parseIter.attrPos, parseIter.valPos);
939         }
940     }
941
942     OCStackResult res = GetPeerPublicKey(&ehRequest->devAddr, &peerPubKey, &peerPubKeyLen);
943     if (OC_STACK_OK != res)
944     {
945         OIC_LOG_V(ERROR, TAG, "Could not get peer's public key: %d", res);
946         ehRet = OC_EH_ERROR;
947         goto exit;
948     }
949
950     RolesEntry_t *entry = NULL;
951     for (entry = gRoles; NULL != entry; entry = entry->next)
952     {
953         assert((0 < entry->publicKeyLength) && (NULL != entry->publicKey));
954         if ((entry->publicKeyLength == peerPubKeyLen) &&
955             (0 == memcmp(entry->publicKey, peerPubKey, peerPubKeyLen)))
956         {
957             break;
958         }
959     }
960
961     if (NULL == entry)
962     {
963         /* No entry for this peer. */
964         OIC_LOG(ERROR, TAG, "No entry for this peer's public key");
965         ehRet = OC_EH_ERROR;
966         goto exit;
967     }
968
969     InvalidateRoleCache(entry);
970
971     RoleCertChain_t *curr1 = NULL;
972     RoleCertChain_t *curr2 = NULL;
973     LL_FOREACH_SAFE(entry->chains, curr1, curr2)
974     {
975         // credId of zero means delete all creds; we never assign zero as a credId.
976         if ((0 == credId) || (curr1->credId == credId))
977         {
978             LL_DELETE(entry->chains, curr1);
979             FreeRoleCertChain(curr1);
980             ehRet = OC_EH_OK;
981             break;
982         }
983     }
984
985 exit:
986
987     ehRet = ((SendSRMResponse(ehRequest, ehRet, NULL, 0)) == OC_STACK_OK) ? OC_EH_OK : OC_EH_ERROR;
988
989     OIC_LOG(DEBUG, TAG, "Roles HandleDeleteRequest OUT");
990     OICFree(peerPubKey);
991
992     return ehRet;
993 }
994
995 static OCEntityHandlerResult RolesEntityHandler(OCEntityHandlerFlag flag,
996                                                 OCEntityHandlerRequest * ehRequest,
997                                                 void* callbackParameter)
998 {
999     OCEntityHandlerResult ehRet = OC_EH_ERROR;
1000
1001     OC_UNUSED(callbackParameter);
1002
1003     if (!ehRequest)
1004     {
1005         return OC_EH_ERROR;
1006     }
1007
1008     if (flag & OC_REQUEST_FLAG)
1009     {
1010         OIC_LOG(DEBUG, TAG, "Flag includes OC_REQUEST_FLAG");
1011         switch (ehRequest->method)
1012         {
1013         case OC_REST_GET:
1014             ehRet = HandleGetRequest(ehRequest);
1015             break;
1016         case OC_REST_PUT:
1017         case OC_REST_POST:
1018             ehRet = HandlePostRequest(ehRequest);
1019             break;
1020         case OC_REST_DELETE:
1021             ehRet = HandleDeleteRequest(ehRequest);
1022             break;
1023         default:
1024             ehRet = ((SendSRMResponse(ehRequest, OC_EH_ERROR, NULL, 0)) == OC_STACK_OK) ?
1025                 OC_EH_OK : OC_EH_ERROR;
1026             break;
1027         }
1028     }
1029
1030     return ehRet;
1031 }
1032
1033 OCStackResult InitRolesResource()
1034 {
1035     OCStackResult res = OCCreateResource(&gRolesHandle,
1036         OIC_RSRC_TYPE_SEC_ROLES,
1037         OC_RSRVD_INTERFACE_DEFAULT,
1038         OIC_RSRC_ROLES_URI,
1039         RolesEntityHandler,
1040         NULL,
1041         OC_SECURE |
1042         OC_DISCOVERABLE);
1043
1044     if (OC_STACK_OK != res)
1045     {
1046         OIC_LOG_V(FATAL, TAG, "Unable to instantiate roles resource: %d", res);
1047     }
1048
1049     return res;
1050 }
1051
1052 OCStackResult DeInitRolesResource()
1053 {
1054     OCStackResult res = OCDeleteResource(gRolesHandle);
1055
1056     if (OC_STACK_OK != res)
1057     {
1058         OIC_LOG_V(ERROR, TAG, "Failed to delete roles resource: %d", res);
1059     }
1060
1061     gRolesHandle = NULL;
1062
1063     FreeRolesList(gRoles);
1064     FreeSymmetricRolesList(gSymmetricRoles);
1065
1066     gRoles = NULL;
1067
1068     return res;
1069 }
1070
1071 /*
1072  * true if before < after, false if before >= after
1073  */
1074 static bool IsBefore(const struct tm *before, const struct tm *after)
1075 {
1076     if (before->tm_year > after->tm_year)
1077     {
1078         return false;
1079     }
1080
1081     if (before->tm_year == after->tm_year)
1082     {
1083         if (before->tm_mon > after->tm_mon)
1084         {
1085             return false;
1086         }
1087
1088         if (before->tm_mon == after->tm_mon)
1089         {
1090             if (before->tm_mday > after->tm_mday)
1091             {
1092                 return false;
1093             }
1094
1095             if (before->tm_mday == after->tm_mday)
1096             {
1097                 if (before->tm_hour > after->tm_hour)
1098                 {
1099                     return false;
1100                 }
1101
1102                 if (before->tm_hour == after->tm_hour)
1103                 {
1104                     if (before->tm_min > after->tm_min)
1105                     {
1106                         return false;
1107                     }
1108
1109                     if (before->tm_min == after->tm_min)
1110                     {
1111                         return (before->tm_sec < after->tm_sec);
1112                     }
1113                 }
1114             }
1115         }
1116     }
1117
1118     return true;
1119 }
1120
1121 OCStackResult GetEndpointRoles(const CAEndpoint_t *endpoint, OicSecRole_t **roles, size_t *roleCount)
1122 {
1123     VERIFY_NOT_NULL_RETURN(TAG, endpoint, ERROR, OC_STACK_INVALID_PARAM);
1124     VERIFY_NOT_NULL_RETURN(TAG, roles, ERROR, OC_STACK_INVALID_PARAM);
1125     VERIFY_NOT_NULL_RETURN(TAG, roleCount, ERROR, OC_STACK_INVALID_PARAM);
1126
1127     uint8_t *publicKey = NULL;
1128     size_t publicKeyLength = 0;
1129     RolesEntry_t *targetEntry = NULL;
1130     OicSecRole_t *rolesToReturn = NULL;
1131     size_t rolesToReturnCount = 0;
1132     ByteArray_t trustedCaCerts;
1133     memset(&trustedCaCerts, 0, sizeof(trustedCaCerts));
1134
1135     OCStackResult res = GetPeerPublicKeyFromEndpoint(endpoint, &publicKey, &publicKeyLength);
1136     if (OC_STACK_INVALID_PARAM == res)
1137     {
1138         /*
1139          * OC_STACK_INVALID_PARAM means the endpoint didn't authenticate with a certificate.
1140          * Look for a symmetric key-based role and return that if present.
1141          */
1142         CASecureEndpoint_t sep;
1143         CAResult_t caRes = GetCASecureEndpointData(endpoint, &sep);
1144         if (CA_STATUS_OK != caRes)
1145         {
1146             *roles = NULL;
1147             *roleCount = 0;
1148             return OC_STACK_OK;
1149         }
1150
1151         SymmetricRoleEntry_t *curr = NULL;
1152         LL_FOREACH(gSymmetricRoles, curr)
1153         {
1154             if ((UUID_LENGTH == sep.identity.id_length) &&
1155                 (0 == memcmp(curr->subject.id, sep.identity.id, sizeof(curr->subject.id))))
1156             {
1157                 *roles = (OicSecRole_t *)OICCalloc(1, sizeof(OicSecRole_t));
1158                 if (NULL == *roles)
1159                 {
1160                     OIC_LOG(ERROR, TAG, "No memory allocating roles for symmetric credential");
1161                     return OC_STACK_NO_MEMORY;
1162                 }
1163
1164                 (*roles)[0] = curr->role;
1165                 *roleCount = 1;
1166                 return OC_STACK_OK;
1167             }
1168         }
1169
1170         /* No symmetric role found. Return empty list. */
1171         *roles = NULL;
1172         *roleCount = 0;
1173         return OC_STACK_OK;
1174     }
1175     else if (OC_STACK_OK != res)
1176     {
1177         /* Any other error is a fatal error. */
1178         OIC_LOG_V(ERROR, TAG, "Could not GetPeerPublicKeyFromEndpoint: %d", res);
1179         return res;
1180     }
1181
1182     for (targetEntry = gRoles; NULL != targetEntry; targetEntry = targetEntry->next)
1183     {
1184         if ((targetEntry->publicKeyLength == publicKeyLength) &&
1185             (0 == memcmp(targetEntry->publicKey, publicKey, publicKeyLength)))
1186         {
1187             break;
1188         }
1189     }
1190
1191     if (NULL == targetEntry)
1192     {
1193         /* No roles for this peer. */
1194         *roles = NULL;
1195         *roleCount = 0;
1196         OICFree(publicKey);
1197         return OC_STACK_OK;
1198     }
1199
1200     /* Is the cache still valid? */
1201     struct tm now;
1202     memset(&now, 0, sizeof(now));
1203 #ifndef WITH_ARDUINO /* No reliable time on Arduino, so assume the cache is valid if present. */
1204     time_t nowTimeT = 0;
1205     nowTimeT = time(NULL);
1206     /* If we failed to get the current time, assume the cache is valid if present. */
1207     if ((time_t)-1 != nowTimeT)
1208     {
1209         /* gmtime_{s,r} should not ever fail. */
1210 #ifdef HAVE_WINDOWS_H
1211         if (0 != gmtime_s(&now, &nowTimeT))
1212         {
1213             assert(!"gmtime_s failed");
1214             OIC_LOG(WARNING, TAG, "gmtime_s failed; assuming role cache is valid");
1215             memset(&now, 0, sizeof(now));
1216         }
1217 #else
1218         if (NULL == gmtime_r(&nowTimeT, &now))
1219         {
1220             assert(!"gmtime_r failed");
1221             OIC_LOG(WARNING, TAG, "gmtime_r failed; assuming role cache is valid");
1222             memset(&now, 0, sizeof(now));
1223         }
1224 #endif
1225     }
1226 #endif /* WITH_ARDUINO */
1227
1228     if (IsBefore(&now, &targetEntry->cacheValidUntil))
1229     {
1230         /* now < cacheValidUntil: provide caller with a copy of the cached roles */
1231         *roles = (OicSecRole_t *)OICCalloc(targetEntry->cachedRolesLength, sizeof(OicSecRole_t));
1232         if (NULL == *roles)
1233         {
1234             OICFree(publicKey);
1235             return OC_STACK_NO_MEMORY;
1236         }
1237         memcpy(*roles, targetEntry->cachedRoles, (targetEntry->cachedRolesLength * sizeof(OicSecRole_t)));
1238         *roleCount = targetEntry->cachedRolesLength;
1239
1240         OICFree(publicKey);
1241         return OC_STACK_OK;
1242     }
1243
1244     InvalidateRoleCache(targetEntry);
1245
1246     /* Retrieve the current set of trusted CAs from the cred resource. */
1247     res = GetPemCaCert(&trustedCaCerts, TRUST_CA);
1248     if (OC_STACK_OK != res)
1249     {
1250         OIC_LOG_V(ERROR, TAG, "Could not get CA certs: %d", res);
1251         OICFree(publicKey);
1252         return res;
1253     }
1254
1255     for (RoleCertChain_t *chain = targetEntry->chains; NULL != chain; chain = chain->next)
1256     {
1257         OicSecRole_t *currCertRoles = NULL;
1258         size_t currCertRolesCount = 0;
1259         struct tm notValidAfter;
1260         memset(&notValidAfter, 0, sizeof(notValidAfter));
1261
1262         res = OCInternalVerifyRoleCertificate(&chain->certificate, &chain->optData,
1263                                               trustedCaCerts.data, trustedCaCerts.len,
1264                                               &currCertRoles, &currCertRolesCount,
1265                                               &notValidAfter);
1266
1267         if (OC_STACK_OK != res)
1268         {
1269             OIC_LOG_V(ERROR, TAG, "Failed to verify a role certificate: %d", res);
1270             /* Remove the invalid cert chain, but don't exit; try all certificates presented. */
1271             LL_DELETE(targetEntry->chains, chain);
1272             FreeRoleCertChain(chain);
1273         }
1274         else
1275         {
1276             /* Add returned roles to current list. */
1277             OicSecRole_t *savePtr = rolesToReturn;
1278             rolesToReturn = (OicSecRole_t *)OICRealloc(rolesToReturn,
1279                 sizeof(rolesToReturn[0]) * (rolesToReturnCount + currCertRolesCount));
1280             if (NULL == rolesToReturn)
1281             {
1282                 OIC_LOG(ERROR, TAG, "No memory reallocating rolesToReturn");
1283                 memset(&targetEntry->cacheValidUntil, 0, sizeof(targetEntry->cacheValidUntil));
1284                 OICFree(trustedCaCerts.data);
1285                 OICFree(savePtr);
1286                 OICFree(currCertRoles);
1287                 OICFree(publicKey);
1288                 return OC_STACK_NO_MEMORY;
1289             }
1290             memcpy(rolesToReturn + (rolesToReturnCount * sizeof(rolesToReturn[0])),
1291                 currCertRoles,
1292                 currCertRolesCount * sizeof(currCertRoles[0]));
1293             rolesToReturnCount += currCertRolesCount;
1294             OICFree(currCertRoles);
1295         }
1296
1297         /*
1298          * Set the cacheValidUntil value to be the earliest notValidUntil date amongst
1299          * all the certificates.
1300          *
1301          * Assumption is that if tm_year is zero, the cacheValidUntil is all zero, and so the
1302          * cacheValidUntil value hasn't yet been set. tm_year of 0 means the year 1900, and we
1303          * should never see this value in a certificate.
1304          */
1305         if ((0 == targetEntry->cacheValidUntil.tm_year) ||
1306             IsBefore(&notValidAfter, &targetEntry->cacheValidUntil))
1307         {
1308             memcpy(&targetEntry->cacheValidUntil, &notValidAfter, sizeof(targetEntry->cacheValidUntil));
1309         }
1310     }
1311
1312     targetEntry->cachedRoles = rolesToReturn;
1313     targetEntry->cachedRolesLength = rolesToReturnCount;
1314
1315     /* Make a copy for the caller. */
1316     *roles = (OicSecRole_t *)OICCalloc(targetEntry->cachedRolesLength, sizeof(OicSecRole_t));
1317     if (NULL == *roles)
1318     {
1319         OICFree(publicKey);
1320         OICFree(trustedCaCerts.data);
1321         return OC_STACK_NO_MEMORY;
1322     }
1323     memcpy(*roles, targetEntry->cachedRoles, (targetEntry->cachedRolesLength * sizeof(OicSecRole_t)));
1324     *roleCount = targetEntry->cachedRolesLength;
1325
1326     OICFree(publicKey);
1327     OICFree(trustedCaCerts.data);
1328     return OC_STACK_OK;
1329 }
1330
1331 #endif /* defined(__WITH_DTLS__) || defined(__WITH_TLS__) */