blob: 89be0a9e0fb046f2ff14fe4456d7cc160e07304e [file] [log] [blame]
/*
* Copyright (c) 2018 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <zephyr/init.h>
#include <zephyr/kernel.h>
#include "tls_internal.h"
/* Global pool of credentials shared among TLS contexts. */
static struct tls_credential credentials[CONFIG_TLS_MAX_CREDENTIALS_NUMBER];
/* A mutex for protecting access to the credentials array. */
static struct k_mutex credential_lock;
static int credentials_init(const struct device *unused)
{
(void)memset(credentials, 0, sizeof(credentials));
k_mutex_init(&credential_lock);
return 0;
}
SYS_INIT(credentials_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
static struct tls_credential *unused_credential_get(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(credentials); i++) {
if (credentials[i].type == TLS_CREDENTIAL_NONE) {
return &credentials[i];
}
}
return NULL;
}
struct tls_credential *credential_get(sec_tag_t tag,
enum tls_credential_type type)
{
int i;
for (i = 0; i < ARRAY_SIZE(credentials); i++) {
if (credentials[i].type == type && credentials[i].tag == tag) {
return &credentials[i];
}
}
return NULL;
}
struct tls_credential *credential_next_get(sec_tag_t tag,
struct tls_credential *iter)
{
int i;
if (!iter) {
iter = credentials;
} else {
iter++;
}
for (i = iter - credentials; i < ARRAY_SIZE(credentials); i++) {
if (credentials[i].type != TLS_CREDENTIAL_NONE &&
credentials[i].tag == tag) {
return &credentials[i];
}
}
return NULL;
}
void credentials_lock(void)
{
k_mutex_lock(&credential_lock, K_FOREVER);
}
void credentials_unlock(void)
{
k_mutex_unlock(&credential_lock);
}
int tls_credential_add(sec_tag_t tag, enum tls_credential_type type,
const void *cred, size_t credlen)
{
struct tls_credential *credential;
int ret = 0;
credentials_lock();
credential = credential_get(tag, type);
if (credential != NULL) {
ret = -EEXIST;
goto exit;
}
credential = unused_credential_get();
if (credential == NULL) {
ret = -ENOMEM;
goto exit;
}
credential->tag = tag;
credential->type = type;
credential->buf = cred;
credential->len = credlen;
exit:
credentials_unlock();
return ret;
}
int tls_credential_get(sec_tag_t tag, enum tls_credential_type type,
void *cred, size_t *credlen)
{
struct tls_credential *credential;
int ret = 0;
credentials_lock();
credential = credential_get(tag, type);
if (credential == NULL) {
ret = -ENOENT;
goto exit;
}
if (credential->len > *credlen) {
ret = -EFBIG;
goto exit;
}
*credlen = credential->len;
memcpy(cred, credential->buf, credential->len);
exit:
credentials_unlock();
return ret;
}
int tls_credential_delete(sec_tag_t tag, enum tls_credential_type type)
{
struct tls_credential *credential;
int ret = 0;
credentials_lock();
credential = credential_get(tag, type);
if (!credential) {
ret = -ENOENT;
goto exit;
}
(void)memset(credential, 0, sizeof(struct tls_credential));
credential->type = TLS_CREDENTIAL_NONE;
exit:
credentials_unlock();
return ret;
}