zephyr/subsys/net/lib/tls_credentials/tls_credentials.c
Robert Lubos d09cbcaf6f net: tls: Add credential management subsystem
Add TLS credential management subsystem that enables to register TLS
credentials in the system. Once specific credentials are registered in
the system, they will be available for TLS secure sockets to use.

To use a TLS credential with a socket, the following steps have to be
taken:
1. TLS credential has to be registered in a system-wide pool, using the
API provided in "net/tls_credentials.h" header file.
2. TLS credential (and other TLS parameters) should be set on a socket
using setsockopt().

Note, that there is no need to repeat step 1 for different sockets using
the same credentials. Once TLS credential is registered in the system,
it can be used with mulitple sockets, as long as it's not deleted.

Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no>
2018-07-26 12:13:15 -04:00

168 lines
3.0 KiB
C

/*
* Copyright (c) 2018 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <init.h>
#include <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(struct device *unused)
{
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;
}
memset(credential, 0, sizeof(struct tls_credential));
credential->type = TLS_CREDENTIAL_NONE;
exit:
credentials_unlock();
return ret;
}