diff --git a/sys/Makefile b/sys/Makefile index 9f94ead66e..058697f249 100644 --- a/sys/Makefile +++ b/sys/Makefile @@ -148,6 +148,9 @@ endif ifneq (,$(filter usbus usbus_%,$(USEMODULE))) DIRS += usb/usbus endif +ifneq (,$(filter credman,$(USEMODULE))) + DIRS += net/credman +endif DIRS += $(dir $(wildcard $(addsuffix /Makefile, $(USEMODULE)))) diff --git a/sys/include/net/credman.h b/sys/include/net/credman.h new file mode 100644 index 0000000000..931bdef8c9 --- /dev/null +++ b/sys/include/net/credman.h @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2019 HAW Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @defgroup net_credman (D)TLS Credential Manager + * @ingroup net + * @brief Credentials management module for (D)TLS + * + * @{ + * + * @file + * @brief (D)TLS credentials management module definitions + * + * @note This module DOES NOT copy the credentials into the system. It + * just holds the pointers to the credentials given by the user. + * The user must make sure that these pointers are valid during the + * lifetime of the application. + * + * @author Aiman Ismail + */ + +#ifndef NET_CREDMAN_H +#define NET_CREDMAN_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Maximum number of credentials in credential pool + */ +#ifndef CREDMAN_MAX_CREDENTIALS +#define CREDMAN_MAX_CREDENTIALS (2) +#endif + +/** + * @brief Buffer of the credential + */ +typedef struct { + void *s; /**< Pointer to the buffer */ + size_t len; /**< Length of credman_buffer_t::s */ +} credman_buffer_t; + +/** + * @brief PSK parameters + */ +typedef struct { + credman_buffer_t key; /**< Key buffer */ + credman_buffer_t id; /**< ID buffer */ + credman_buffer_t hint; /**< Hint buffer */ +} psk_params_t; + +/** + * @brief ECDSA public keys + */ +typedef struct { + const void *x; /**< X part of the public key */ + const void *y; /**< Y part of the public key */ +} ecdsa_public_key_t; + +/** + * @brief ECDSA parameters + */ +typedef struct { + const void *private_key; /**< Pointer to the private key */ + ecdsa_public_key_t public_key; /**< Public key */ + ecdsa_public_key_t *client_keys; /**< Array of clients public keys */ + size_t client_keys_size; /**< Size of ecdsa_params_t::clients_keys */ +} ecdsa_params_t; + +/** + * @brief Tag of the credential. + */ +typedef uint16_t credman_tag_t; + +/** + * @brief Used to signal empty/no tag + */ +#define CREDMAN_TAG_EMPTY (0) + +/** + * @brief Credential types + */ +typedef enum { + CREDMAN_TYPE_EMPTY = 0, + CREDMAN_TYPE_PSK = 1, + CREDMAN_TYPE_ECDSA = 2, +} credman_type_t; + +/** + * @brief Credential information + */ +typedef struct { + credman_type_t type; /**< Type of the credential */ + credman_tag_t tag; /**< Tag of the credential */ + union { + psk_params_t psk; /**< PSK credential parameters */ + ecdsa_params_t ecdsa; /**< ECDSA credential parameters */ + } params; /**< Credential parameters */ +} credman_credential_t; + +/** + * @brief Return values + */ +enum { + CREDMAN_OK = 0, /**< No error */ + CREDMAN_EXIST = -1, /**< Credential already exist in system pool */ + CREDMAN_NO_SPACE = -2, /**< No space in system pool for new credential */ + CREDMAN_NOT_FOUND = -3, /**< Credential not found in the system pool */ + CREDMAN_INVALID = -4, /**< Invalid input parameter(s) */ + CREDMAN_TYPE_UNKNOWN = -5, /**< Unknown credential type */ + CREDMAN_ERROR = -6, /**< Other errors */ +}; + +/** + * @brief Adds a credential to the credential pool + * + * @param[in] credential Credential to add. + * + * @return CREDMAN_OK on success + * @return CREDMAN_EXIST if credential of @p tag and @p type already exist + * @return CREDMAN_NO_SPACE if credential pool is full + * @return CREDMAN_TYPE_UNKNOWN if @p credential has unknown + * credman_credential_t::type + * @return CREDMAN_INVALID if @p credential has + * @return CREDMAN_INVALID credman_credential_t::tag with the value of + * CREDMAN_TAG_EMPTY + * @return CREDMAN_INVALID credman_credential_t::type with the value of + * CREDMAN_TYPE_EMPTY + * @return CREDMAN_INVALID credman_credential_t::params with invalid credential + * parameters i.e. the key points to NULL or has a length of 0 + * @return CREDMAN_ERROR on other errors + */ +int credman_add(const credman_credential_t *credential); + +/** + * @brief Gets a credential from credential pool + * + * @param[out] credential Found credential + * @param[in] tag Tag of credential to get + * @param[in] type Type of credential to get + * + * @return CREDMAN_OK on success + * @return CREDMAN_NOT_FOUND if no credential with @p tag and @p type found + * @return CREDMAN_ERROR on other errors + */ +int credman_get(credman_credential_t *credential, credman_tag_t tag, + credman_type_t type); + +/** + * @brief Delete a credential from the credential pool. Does nothing if + * credential with credman_credential_t::tag @p tag and + * credman_credential_t::type @p type is not found. + * + * @param[in] tag Tag of the credential + * @param[in] type Type of the credential + */ +void credman_delete(credman_tag_t tag, credman_type_t type); + +/** + * @brief Gets the number of credentials currently in the credential pool + * + * Maximum number of allowed credentials is defined by CREDMAN_MAX_CREDENTIALS + * + * @return number of credentials currently in the credential pool + */ +int credman_get_used_count(void); + +#ifdef TEST_SUITES +/** + * @brief Empties the credential pool + */ +void credman_reset(void); +#endif /*TEST_SUITES */ + +#ifdef __cplusplus +} +#endif + +#endif /* NET_CREDMAN_H */ +/** @} */ diff --git a/sys/net/credman/Makefile b/sys/net/credman/Makefile new file mode 100644 index 0000000000..0d87f48179 --- /dev/null +++ b/sys/net/credman/Makefile @@ -0,0 +1,2 @@ +MODULE = credman +include $(RIOTBASE)/Makefile.base diff --git a/sys/net/credman/credman.c b/sys/net/credman/credman.c new file mode 100644 index 0000000000..7694d83503 --- /dev/null +++ b/sys/net/credman/credman.c @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2019 HAW Hamburg + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup net_credman + * @{ + * + * @file + * @brief (D)TLS Credentials management module implementation + * + * @author Aiman Ismail + */ + +#include "net/credman.h" +#include "mutex.h" + +#include + +#define ENABLE_DEBUG (0) +#include "debug.h" + +static mutex_t _mutex = MUTEX_INIT; + +static credman_credential_t credentials[CREDMAN_MAX_CREDENTIALS]; +static unsigned used = 0; + +static int _find_credential_pos(credman_tag_t tag, credman_type_t type, + credman_credential_t **empty); + +int credman_add(const credman_credential_t *credential) +{ + credman_credential_t *entry = NULL; + assert(credential); + mutex_lock(&_mutex); + int pos = -1; + int ret = CREDMAN_ERROR; + + if ((credential->type == CREDMAN_TYPE_EMPTY) || + (credential->tag == CREDMAN_TAG_EMPTY)) { + DEBUG("credman: invalid credential type/tag\n"); + ret = CREDMAN_INVALID; + goto end; + } + switch (credential->type) { + case CREDMAN_TYPE_PSK: + if ((credential->params.psk.key.s == NULL) || + (credential->params.psk.key.len == 0)) { + DEBUG("credman: invalid PSK parameters\n"); + ret = CREDMAN_INVALID; + goto end; + } + break; + case CREDMAN_TYPE_ECDSA: + if ((credential->params.ecdsa.private_key == NULL) || + (credential->params.ecdsa.public_key.x == NULL) || + (credential->params.ecdsa.public_key.y == NULL)) { + DEBUG("credman: invalid ECDSA parameters\n"); + ret = CREDMAN_INVALID; + goto end; + } + break; + default: + ret = CREDMAN_TYPE_UNKNOWN; + goto end; + } + + pos = _find_credential_pos(credential->tag, credential->type, &entry); + if (pos >= 0) { + DEBUG("credman: credential with tag %d and type %d already exist\n", + credential->tag, credential->type); + ret = CREDMAN_EXIST; + } + else if (entry == NULL) { + DEBUG("credman: no space for new credential\n"); + ret = CREDMAN_NO_SPACE; + } + else { + *entry = *credential; + used++; + ret = CREDMAN_OK; + } +end: + mutex_unlock(&_mutex); + return ret; +} + +int credman_get(credman_credential_t *credential, credman_tag_t tag, + credman_type_t type) +{ + assert(credential); + mutex_lock(&_mutex); + int ret = CREDMAN_ERROR; + + int pos = _find_credential_pos(tag, type, NULL); + if (pos < 0) { + DEBUG("credman: credential with tag %d and type %d not found\n", + tag, type); + ret = CREDMAN_NOT_FOUND; + } + else { + memcpy(credential, &credentials[pos], sizeof(credman_credential_t)); + ret = CREDMAN_OK; + } + mutex_unlock(&_mutex); + return ret; +} + +void credman_delete(credman_tag_t tag, credman_type_t type) +{ + mutex_lock(&_mutex); + int pos = _find_credential_pos(tag, type, NULL); + if (pos >= 0) { + memset(&credentials[pos], 0, sizeof(credman_credential_t)); + used--; + } + mutex_unlock(&_mutex); +} + +int credman_get_used_count(void) +{ + return used; +} + +static int _find_credential_pos(credman_tag_t tag, credman_type_t type, + credman_credential_t **empty) +{ + for (unsigned i = 0; i < CREDMAN_MAX_CREDENTIALS; i++) { + credman_credential_t *c = &credentials[i]; + if ((c->tag == tag) && (c->type == type)) { + return i; + } + /* only check until empty position found */ + if ((empty) && (*empty == NULL) && + (c->tag == CREDMAN_TAG_EMPTY) && (c->type == CREDMAN_TYPE_EMPTY)) { + *empty = c; + } + } + return -1; +} + +#ifdef TEST_SUITES +void credman_reset(void) +{ + mutex_lock(&_mutex); + memset(credentials, 0, + sizeof(credman_credential_t) * CREDMAN_MAX_CREDENTIALS); + used = 0; + mutex_unlock(&_mutex); +} +#endif /* TEST_SUITES */