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