Commit 607319ee authored by Kishen Maloor's avatar Kishen Maloor

oc_roles:support /oic/sec/roles & role assertion

This change adds support for the /oic/sec/roles resource on Servers
for role-based access-control using role certificates, as well as Client
hooks and APIs to assert roles provisioned to it.

As /oic/sec/roles shares its schema in large part with /oic/sec/cred,
oc_cred has been updated so its GET/POST/DELETE handlers may also be
used to service requests to /oic/sec/roles. With an awareness of which
of the two resources is being currently handled, some logic
has been added to oc_cred to perform the appropriate actions for each
resource type. This enables reuse of existing code and flows for parsing
requests to /oic/sec/cred for /oic/sec/roles, and checking for credid
uniqueness, while accounting for minor behavioral differences.

oc_sec_cred_t objects are however recorded separately for the two
resources and oc_roles stores all roles (in oc_sec_cred_t objects) asserted
via requests to /oic/sec/roles. Also, the encoding function for the
/oic/sec/roles response representation is separate from that of /oic/sec/cred.

oc_roles provides internal APIs for managing role assertions
on the Server-side and to help assert roles on the Client-side.

On the Server-side, all roles asserted by various Clients are
indexed by (D)TLS session in oc_roles. As all asserted roles must be valid
when they're used for role-based access-control, the Server-side
stores a parsed role certificate for each role asserted in an
associated mbedTLS object in memory which may be directly queried for
a validity check by the access-control flow at the time of handling a
Client request to a resource. A new void* parameter has been added to
oc_sec_cred_t to store a handle to this mbedtls_x509_crt object.
oc_roles automatically frees these mbedtls_x509_crt objects
for role certificates when the role is freed.

On the Client-side, oc_roles tracks all roles provisioned to
the Client in its /oic/sec/cred resource by the OBT/CMS for its use. It
provides APIs for a Client to list all roles available to it, and for
asserting a role to a Server via a request to /oic/sec/roles.

Change-Id: Id25dbc767141da06f65a46fad1a740da2633d15e
Signed-off-by: Kishen Maloor's avatarKishen Maloor <kishen.maloor@intel.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/27802
parent 1cefb4bf
......@@ -19,6 +19,9 @@
#include "oc_api.h"
#ifdef OC_SECURITY
#include "security/oc_tls.h"
#ifdef OC_PKI
#include "security/oc_roles.h"
#endif /* OC_PKI */
#endif /* OC_SECURITY */
#ifdef OC_CLIENT
......@@ -509,4 +512,59 @@ oc_close_session(oc_endpoint_t *endpoint)
}
}
#if defined(OC_SECURITY) && defined(OC_PKI)
oc_role_t *
oc_get_all_roles(void)
{
return oc_sec_get_role_creds();
}
bool
oc_assert_role(const char *role, const char *authority, oc_endpoint_t *endpoint,
oc_response_handler_t handler)
{
oc_sec_cred_t *cr = oc_sec_find_role_cred(role, authority);
if (cr) {
if (oc_init_post("/oic/sec/roles", endpoint, NULL, handler, HIGH_QOS,
NULL)) {
oc_rep_start_root_object();
oc_rep_set_array(root, roles);
oc_rep_object_array_start_item(roles);
/* credid */
oc_rep_set_int(roles, credid, cr->credid);
/* credtype */
oc_rep_set_int(roles, credtype, cr->credtype);
/* roleid */
if (oc_string_len(cr->role.role) > 0) {
oc_rep_set_object(roles, roleid);
oc_rep_set_text_string(roleid, role, oc_string(cr->role.role));
if (oc_string_len(cr->role.authority) > 0) {
oc_rep_set_text_string(roleid, authority,
oc_string(cr->role.authority));
}
oc_rep_close_object(roles, roleid);
}
/* credusage */
oc_rep_set_text_string(roles, credusage, "oic.sec.cred.rolecert");
/* publicdata */
if (oc_string_len(cr->publicdata.data) > 0) {
oc_rep_set_object(roles, publicdata);
oc_rep_set_text_string(publicdata, data,
oc_string(cr->publicdata.data));
oc_rep_set_text_string(publicdata, encoding, "oic.sec.encoding.pem");
oc_rep_close_object(roles, publicdata);
}
oc_rep_object_array_end_item(roles);
oc_rep_close_array(root, roles);
oc_rep_end_root_object();
if (!oc_do_post()) {
return false;
}
}
}
return false;
}
#endif /* OC_SECURITY && OC_PKI */
#endif /* OC_CLIENT */
......@@ -544,6 +544,9 @@ oc_core_get_resource_by_uri(const char *uri, size_t device)
} else if ((strlen(uri) - skip) == 11 &&
strncmp(uri + skip, "oic/sec/csr", 11) == 0) {
type = OCF_SEC_CSR;
} else if ((strlen(uri) - skip) == 13 &&
strncmp(uri + skip, "oic/sec/roles", 13) == 0) {
type = OCF_SEC_ROLES;
}
#endif /* OC_PKI */
#endif /* OC_SECURITY */
......
......@@ -148,6 +148,21 @@ process_device_resources(CborEncoder *links, oc_request_t *request,
if (filter_resource(oc_core_get_resource_by_index(OCF_SEC_CRED, device_index),
request, oc_string(anchor), links))
matches++;
#ifdef OC_PKI
if (filter_resource(oc_core_get_resource_by_index(OCF_SEC_SP, device_index),
request, oc_string(anchor), links))
matches++;
if (filter_resource(oc_core_get_resource_by_index(OCF_SEC_CSR, device_index),
request, oc_string(anchor), links))
matches++;
if (filter_resource(
oc_core_get_resource_by_index(OCF_SEC_ROLES, device_index), request,
oc_string(anchor), links))
matches++;
#endif /* OC_PKI */
#endif /* OC_SECURITY */
#ifdef OC_SERVER
......@@ -351,6 +366,21 @@ process_oic_1_1_device_object(CborEncoder *device, oc_request_t *request,
oc_core_get_resource_by_index(OCF_SEC_ACL, device_num), request,
oc_rep_array(links)))
matches++;
#ifdef OC_PKI
if (filter_oic_1_1_resource(
oc_core_get_resource_by_index(OCF_SEC_SP, device_num), request,
oc_rep_array(links)))
matches++;
if (filter_oic_1_1_resource(
oc_core_get_resource_by_index(OCF_SEC_CSR, device_num), request,
oc_rep_array(links)))
matches++;
if (filter_oic_1_1_resource(
oc_core_get_resource_by_index(OCF_SEC_ROLES, device_num), request,
oc_rep_array(links)))
matches++;
#endif /* OC_PKI */
#endif
if (filter_oic_1_1_resource(
......
......@@ -367,6 +367,19 @@ void oc_free_server_endpoints(oc_endpoint_t *endpoint);
void oc_close_session(oc_endpoint_t *endpoint);
/** Asserting roles */
typedef struct oc_role_t
{
struct oc_role_t *next;
oc_string_t role;
oc_string_t authority;
} oc_role_t;
oc_role_t *oc_get_all_roles(void);
bool oc_assert_role(const char *role, const char *authority,
oc_endpoint_t *endpoint, oc_response_handler_t handler);
/** Common operations */
void oc_set_delayed_callback(void *cb_data, oc_trigger_t callback,
......
......@@ -96,6 +96,7 @@ typedef enum {
#ifdef OC_PKI
OCF_SEC_SP,
OCF_SEC_CSR,
OCF_SEC_ROLES,
#endif /* OC_PKI */
#endif /* OC_SECURITY */
OCF_D
......
......@@ -110,7 +110,7 @@ ifeq ($(DYNAMIC),1)
endif
ifneq ($(SECURE),0)
SRC += $(addprefix ../../security/,oc_acl.c oc_cred.c oc_doxm.c oc_pstat.c oc_tls.c oc_svr.c oc_store.c oc_pki.c oc_certs.c oc_sp.c oc_keypair.c oc_csr.c)
SRC += $(addprefix ../../security/,oc_acl.c oc_cred.c oc_doxm.c oc_pstat.c oc_tls.c oc_svr.c oc_store.c oc_pki.c oc_certs.c oc_sp.c oc_keypair.c oc_csr.c oc_roles.c)
SRC_COMMON += $(addprefix $(MBEDTLS_DIR)/library/,${DTLS})
MBEDTLS_PATCH_FILE := $(MBEDTLS_DIR)/patched.txt
ifeq ($(DYNAMIC),1)
......
......@@ -19,11 +19,13 @@
#include "oc_cred.h"
#include "oc_api.h"
#include "oc_base64.h"
#include "oc_certs.h"
#include "oc_config.h"
#include "oc_core_res.h"
#include "oc_doxm.h"
#include "oc_keypair.h"
#include "oc_pstat.h"
#include "oc_roles.h"
#include "oc_store.h"
#include "oc_tls.h"
#include "port/oc_log.h"
......@@ -78,9 +80,20 @@ oc_sec_get_cred_by_credid(int credid, size_t device)
}
static bool
unique_credid(int credid, size_t device)
unique_credid(int credid, bool roles_resource, oc_tls_peer_t *client,
size_t device)
{
oc_sec_cred_t *cred = oc_list_head(devices[device].creds);
oc_sec_cred_t *cred = NULL;
(void)client;
if (!roles_resource) {
cred = (oc_sec_cred_t *)oc_list_head(devices[device].creds);
}
#ifdef OC_PKI
else {
cred = oc_sec_get_roles(client);
}
#endif /* OC_PKI */
while (cred != NULL) {
if (cred->credid == credid)
return false;
......@@ -89,13 +102,40 @@ unique_credid(int credid, size_t device)
return true;
}
#if defined(OC_CLIENT) && defined(OC_PKI)
oc_sec_cred_t *
oc_sec_find_role_cred(const char *role, const char *authority)
{
/* Checking only the 0th logical device for Clients */
oc_sec_cred_t *creds = (oc_sec_cred_t *)oc_list_head(devices[0].creds);
size_t role_len = strlen(role);
size_t authority_len = strlen(authority);
while (creds) {
if (creds->credtype == OC_CREDTYPE_CERT &&
creds->credusage == OC_CREDUSAGE_ROLE_CERT) {
if ((role_len == oc_string_len(creds->role.role)) &&
(memcmp(role, oc_string(creds->role.role), role_len) == 0)) {
if ((authority_len == oc_string_len(creds->role.authority)) &&
(memcmp(authority, oc_string(creds->role.authority),
authority_len) == 0)) {
return creds;
}
}
}
creds = creds->next;
}
return NULL;
}
#endif /* OC_CLIENT && OC_PKI */
static int
get_new_credid(size_t device)
get_new_credid(bool roles_resource, oc_tls_peer_t *client, size_t device)
{
int credid;
do {
credid = oc_random_value() >> 1;
} while (!unique_credid(credid, device));
} while (!unique_credid(credid, roles_resource, client, device));
return credid;
}
......@@ -104,6 +144,10 @@ oc_sec_remove_cred(oc_sec_cred_t *cred, size_t device)
{
oc_list_remove(devices[device].creds, cred);
if (oc_string_len(cred->role.role) > 0) {
#if defined(OC_PKI) && defined(OC_CLIENT)
oc_sec_remove_role_cred(oc_string(cred->role.role),
oc_string(cred->role.authority));
#endif /* OC_PKI && OC_CLIENT */
oc_free_string(&cred->role.role);
if (oc_string_len(cred->role.authority) > 0) {
oc_free_string(&cred->role.authority);
......@@ -249,7 +293,8 @@ oc_sec_allocate_cred(oc_uuid_t *subjectuuid, oc_sec_credtype_t credtype,
}
int
oc_sec_add_new_cred(size_t device, int credid, oc_sec_credtype_t credtype,
oc_sec_add_new_cred(size_t device, bool roles_resource, oc_tls_peer_t *client,
int credid, oc_sec_credtype_t credtype,
oc_sec_credusage_t credusage, const char *subjectuuid,
oc_sec_encoding_t privatedata_encoding,
size_t privatedata_size, const uint8_t *privatedata,
......@@ -260,17 +305,39 @@ oc_sec_add_new_cred(size_t device, int credid, oc_sec_credtype_t credtype,
(void)publicdata_encoding;
(void)publicdata_size;
(void)publicdata;
(void)roles_resource;
if (!subjectuuid) {
return -1;
#ifdef OC_PKI
if (roles_resource) {
if (credusage != OC_CREDUSAGE_ROLE_CERT) {
return -1;
}
uint8_t public_key[OC_KEYPAIR_PUBKEY_SIZE];
if (oc_certs_parse_public_key(publicdata, publicdata_size + 1, public_key) <
0) {
return -1;
}
if (memcmp(public_key, client->public_key, OC_KEYPAIR_PUBKEY_SIZE) != 0) {
return -1;
}
}
#endif /* OC_PKI */
oc_uuid_t subject;
if (subjectuuid[0] == '*') {
memset(&subject, 0, sizeof(oc_uuid_t));
subject.id[0] = '*';
memset(&subject, 0, sizeof(oc_uuid_t));
if (!subjectuuid) {
if (credusage != OC_CREDUSAGE_ROLE_CERT) {
return -1;
} else {
subject.id[0] = '*';
}
} else {
oc_str_to_uuid(subjectuuid, &subject);
if (subjectuuid[0] == '*') {
subject.id[0] = '*';
} else {
oc_str_to_uuid(subjectuuid, &subject);
}
}
#ifdef OC_PKI
......@@ -288,49 +355,79 @@ oc_sec_add_new_cred(size_t device, int credid, oc_sec_credtype_t credtype,
}
#endif /* OC_PKI */
/* remove duplicate cred, if one exists. */
if (!unique_credid(credid, device)) {
oc_sec_remove_cred_by_credid(credid, device);
if (!unique_credid(credid, roles_resource, client, device)) {
if (!roles_resource) {
/* remove duplicate cred, if one exists. */
oc_sec_remove_cred_by_credid(credid, device);
}
#ifdef OC_PKI
else {
credid = -1;
}
#endif /* OC_PKI */
}
#ifdef OC_PKI
oc_sec_cred_t *chain = NULL;
#endif /* OC_PKI */
oc_sec_cred_t *cred = NULL;
do {
cred = oc_sec_find_creds_for_subject(&subject, cred, device);
if (cred) {
if (cred->credtype == credtype) {
/* Exit this block if we're modifying an existing cred entry */
if (cred->credid == credid) {
oc_sec_remove_cred(cred, device);
break;
}
#ifdef OC_PKI
if (credtype == OC_CREDTYPE_CERT && cred->credusage == credusage) {
/* Trying to add a duplicate certificate chain, so ignore */
if (publicdata_size > 0 &&
publicdata_size == oc_string_len(cred->publicdata.data) &&
memcmp(publicdata, oc_string(cred->publicdata.data),
publicdata_size) == 0) {
return cred->credid;
} else if (cred->credusage != OC_CREDUSAGE_TRUSTCA &&
cred->credusage != OC_CREDUSAGE_MFG_TRUSTCA) {
/* Trying to record a new cert in a cert chain via a
separate cred entry. Store a pointer to the existing
cred entry for linking to two below. */
chain = cred;
if (!roles_resource) {
do {
cred = oc_sec_find_creds_for_subject(&subject, cred, device);
if (cred) {
if (cred->credtype == credtype) {
/* Exit this block if we're modifying an existing cred entry */
if (cred->credid == credid) {
oc_sec_remove_cred(cred, device);
break;
}
}
#ifdef OC_PKI
if (credtype == OC_CREDTYPE_CERT && cred->credusage == credusage) {
/* Trying to add a duplicate certificate chain, so ignore */
if (publicdata_size > 0 &&
publicdata_size == oc_string_len(cred->publicdata.data) &&
memcmp(publicdata, oc_string(cred->publicdata.data),
publicdata_size) == 0) {
return cred->credid;
} else if (cred->credusage != OC_CREDUSAGE_TRUSTCA &&
cred->credusage != OC_CREDUSAGE_MFG_TRUSTCA) {
/* Trying to record a new cert in a cert chain via a
* separate cred entry. Store a pointer to the existing
* cred entry for linking to two below.
*/
chain = cred;
break;
}
}
#endif /* OC_PKI */
}
cred = cred->next;
}
cred = cred->next;
} while (cred);
}
#ifdef OC_PKI
else {
oc_sec_cred_t *roles = oc_sec_get_roles(client);
while (roles) {
if ((oc_string_len(roles->publicdata.data) == publicdata_size) &&
memcmp(oc_string(roles->publicdata.data), publicdata,
publicdata_size) == 0) {
return roles->credid;
}
roles = roles->next;
}
} while (cred);
}
#endif /* OC_PKI */
cred = oc_sec_allocate_cred(&subject, credtype, credusage, device);
#ifdef OC_PKI
if (roles_resource && credusage == OC_CREDUSAGE_ROLE_CERT) {
cred = oc_sec_allocate_role(client, device);
} else if (!roles_resource)
#endif /* OC_PKI */
{
cred = oc_sec_allocate_cred(&subject, credtype, credusage, device);
}
if (!cred) {
return -1;
}
......@@ -352,11 +449,19 @@ oc_sec_add_new_cred(size_t device, int credid, oc_sec_credtype_t credtype,
return -1;
}
}
if (roles_resource) {
if (oc_certs_parse_role_certificate(publicdata, publicdata_size + 1, cred) <
0) {
oc_sec_free_role(cred, client);
return -1;
}
}
#endif /* OC_PKI */
/* if a credid wasn't provided in the request, pick a suitable one */
if (credid == -1) {
credid = get_new_credid(device);
credid = get_new_credid(roles_resource, client, device);
}
/* credid */
......@@ -396,7 +501,7 @@ oc_sec_add_new_cred(size_t device, int credid, oc_sec_credtype_t credtype,
#endif /* OC_PKI */
/* roleid */
if (role) {
if (!roles_resource && role) {
oc_new_string(&cred->role.role, role, strlen(role));
if (authority) {
oc_new_string(&cred->role.authority, authority, strlen(authority));
......@@ -425,6 +530,11 @@ oc_sec_add_new_cred(size_t device, int credid, oc_sec_credtype_t credtype,
cred->credusage == OC_CREDUSAGE_TRUSTCA) {
oc_tls_refresh_trust_anchors();
}
#if defined(OC_PKI) && defined(OC_CLIENT)
if (!roles_resource && credusage == OC_CREDUSAGE_ROLE_CERT) {
oc_sec_add_role_cred(role, authority);
}
#endif /* OC_PKI && OC_CLIENT */
}
#endif /* OC_PKI */
......@@ -474,6 +584,62 @@ return_encoding_string(oc_sec_encoding_t encoding)
return NULL;
}
#ifdef OC_PKI
static void
oc_sec_encode_roles(oc_tls_peer_t *client, size_t device)
{
oc_sec_cred_t *cr = oc_sec_get_roles(client);
oc_rep_start_root_object();
oc_process_baseline_interface(
oc_core_get_resource_by_index(OCF_SEC_ROLES, device));
oc_rep_set_array(root, roles);
while (cr != NULL) {
oc_rep_object_array_start_item(roles);
/* credid */
oc_rep_set_int(roles, credid, cr->credid);
/* credtype */
oc_rep_set_int(roles, credtype, cr->credtype);
/* roleid */
if (oc_string_len(cr->role.role) > 0) {
oc_rep_set_object(roles, roleid);
oc_rep_set_text_string(roleid, role, oc_string(cr->role.role));
if (oc_string_len(cr->role.authority) > 0) {
oc_rep_set_text_string(roleid, authority,
oc_string(cr->role.authority));
}
oc_rep_close_object(roles, roleid);
}
/* credusage */
const char *credusage_string = return_credusage_string(cr->credusage);
if (credusage_string) {
oc_rep_set_text_string(roles, credusage, credusage_string);
}
/* publicdata */
if (oc_string_len(cr->publicdata.data) > 0) {
oc_rep_set_object(roles, publicdata);
if (cr->publicdata.encoding == OC_ENCODING_PEM) {
oc_rep_set_text_string(publicdata, data,
oc_string(cr->publicdata.data));
} else {
oc_rep_set_byte_string(publicdata, data,
oc_cast(cr->publicdata.data, const uint8_t),
oc_string_len(cr->publicdata.data));
}
const char *encoding_string =
return_encoding_string(cr->publicdata.encoding);
if (encoding_string) {
oc_rep_set_text_string(publicdata, encoding, encoding_string);
}
oc_rep_close_object(roles, publicdata);
}
oc_rep_object_array_end_item(roles);
cr = cr->next;
}
oc_rep_close_array(root, roles);
oc_rep_end_root_object();
}
#endif /* OC_PKI */
void
oc_sec_encode_cred(bool persist, size_t device)
{
......@@ -519,8 +685,13 @@ oc_sec_encode_cred(bool persist, size_t device)
oc_string(cr->privatedata.data));
}
} else {
oc_rep_set_byte_string(privatedata, data,
oc_cast(cr->privatedata.data, const uint8_t), 0);
if (cr->privatedata.encoding == OC_ENCODING_RAW ||
cr->privatedata.encoding == OC_ENCODING_DER) {
oc_rep_set_byte_string(privatedata, data,
oc_cast(cr->privatedata.data, const uint8_t), 0);
} else {
oc_rep_set_text_string(privatedata, data, "");
}
}
const char *encoding_string =
return_encoding_string(cr->privatedata.encoding);
......@@ -620,34 +791,37 @@ parse_encoding_property(oc_string_t *encoding_string)
bool
oc_sec_decode_cred(oc_rep_t *rep, oc_sec_cred_t **owner, bool from_storage,
size_t device)
bool roles_resource, oc_tls_peer_t *client, size_t device)
{
oc_sec_pstat_t *ps = oc_sec_get_pstat(device);
oc_rep_t *t = rep;
size_t len = 0;
while (t != NULL) {
len = oc_string_len(t->name);
switch (t->type) {
case OC_REP_STRING:
if (len == 10 && memcmp(oc_string(t->name), "rowneruuid", 10) == 0) {
if (!from_storage && ps->s != OC_DOS_RFOTM && ps->s != OC_DOS_SRESET) {
OC_ERR("oc_cred: Can set rowneruuid only in RFOTM/SRESET");
if (!roles_resource) {
while (t != NULL) {
len = oc_string_len(t->name);
switch (t->type) {
case OC_REP_STRING:
if (len == 10 && memcmp(oc_string(t->name), "rowneruuid", 10) == 0) {
if (!from_storage && ps->s != OC_DOS_RFOTM &&
ps->s != OC_DOS_SRESET) {
OC_ERR("oc_cred: Can set rowneruuid only in RFOTM/SRESET");
return false;
}
}
break;
case OC_REP_OBJECT_ARRAY: {
if (!from_storage && ps->s != OC_DOS_RFOTM && ps->s != OC_DOS_SRESET &&
ps->s != OC_DOS_RFPRO) {
OC_ERR("oc_cred: Can set cred only in RFOTM/SRESET/RFPRO");
return false;
}
} break;
default:
break;
}
break;
case OC_REP_OBJECT_ARRAY: {
if (!from_storage && ps->s != OC_DOS_RFOTM && ps->s != OC_DOS_SRESET &&
ps->s != OC_DOS_RFPRO) {
OC_ERR("oc_cred: Can set cred only in RFOTM/SRESET/RFPRO");
return false;
}
} break;
default:
break;
t = t->next;
}
t = t->next;
}
while (rep != NULL) {
......@@ -662,7 +836,8 @@ oc_sec_decode_cred(oc_rep_t *rep, oc_sec_cred_t **owner, bool from_storage,
break;
/* creds */
case OC_REP_OBJECT_ARRAY: {
if (len == 5 && memcmp(oc_string(rep->name), "creds", 5) == 0) {
if (len == 5 && (memcmp(oc_string(rep->name), "creds", 5) == 0 ||
memcmp(oc_string(rep->name), "roles", 5) == 0)) {
oc_rep_t *creds_array = rep->value.object_array;
/* array of oic.sec.cred */
while (creds_array != NULL) {
......@@ -790,7 +965,7 @@ oc_sec_decode_cred(oc_rep_t *rep, oc_sec_cred_t **owner, bool from_storage,
if (non_empty) {
credid = oc_sec_add_new_cred(
device, credid, credtype,
device, roles_resource, client, credid, credtype,
#ifdef OC_PKI
credusage,
#else /* OC_PKI */
......@@ -809,7 +984,8 @@ oc_sec_decode_cred(oc_rep_t *rep, oc_sec_cred_t **owner, bool from_storage,
return false;
}
/* privatedata */
/* Obtain a handle to the owner credential entry where that applies
*/
if (credtype == OC_CREDTYPE_PSK && privatedata_size == 0 && owner) {
*owner = oc_sec_get_cred_by_credid(credid, device);
}
......@@ -831,7 +1007,23 @@ get_cred(oc_request_t *request, oc_interface_mask_t interface, void *data)
{
(void)interface;
(void)data;
oc_sec_encode_cred(false, request->resource->device);
bool roles_resource = false;
#ifdef OC_PKI
oc_tls_peer_t *client = NULL;
if (oc_string_len(request->resource->uri) == 14 &&
memcmp(oc_string(request->resource->uri), "/oic/sec/roles", 14) == 0) {
roles_resource = true;
}
#endif /* OC_PKI */
if (!roles_resource) {
oc_sec_encode_cred(false, request->resource->device);
}
#ifdef OC_PKI
else {
client = oc_tls_get_peer(request->origin);
oc_sec_encode_roles(client, request->resource->device);
}
#endif /* OC_PKI */
oc_send_response(request, OC_STATUS_OK);