blob: 94f4d9c5cd5a90a46bb021ade6f1776387572bd7 [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"
#include "tls_credentials_digest_raw.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(void)
{
(void)memset(credentials, 0, sizeof(credentials));
k_mutex_init(&credential_lock);
return 0;
}
SYS_INIT(credentials_init, POST_KERNEL, 0);
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;
}
sec_tag_t credential_next_tag_get(sec_tag_t iter)
{
int i;
sec_tag_t lowest = TLS_SEC_TAG_NONE;
/* Scan all slots and find lowest sectag greater than iter */
for (i = 0; i < ARRAY_SIZE(credentials); i++) {
/* Skip empty slots. */
if (credentials[i].type == TLS_CREDENTIAL_NONE) {
continue;
}
/* Skip any slots containing sectags not greater than iter */
if (credentials[i].tag <= iter && iter != TLS_SEC_TAG_NONE) {
continue;
}
/* Find the lowest of such slots */
if (lowest == TLS_SEC_TAG_NONE || credentials[i].tag < lowest) {
lowest = credentials[i].tag;
}
}
return lowest;
}
int credential_digest(struct tls_credential *credential, void *dest, size_t *len)
{
return credential_digest_raw(credential, dest, len);
}
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;
}