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