Skip to content

Commit

Permalink
feat: move mbedtls sockets into its own layer under connection
Browse files Browse the repository at this point in the history
  • Loading branch information
XavierChanth committed Dec 13, 2024
1 parent 6feea2e commit 535d367
Show file tree
Hide file tree
Showing 19 changed files with 888 additions and 388 deletions.
1 change: 1 addition & 0 deletions generators/arduino/atsdk/generate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ overrides() {
echo '#define PRIu64 "llu"'
echo "#define ATCHOPS_TARGET_ARDUINO"
echo "#define ATCHOPS_MBEDTLS_VERSION_2"
echo "#define ATCLIENT_NET_SOCKET_PROVIDER_EXTERNAL"
} >>$src_base/atchops/platform.h
}

Expand Down
2 changes: 2 additions & 0 deletions packages/atclient/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ set(
${CMAKE_CURRENT_LIST_DIR}/src/atnotification.c
${CMAKE_CURRENT_LIST_DIR}/src/connection_hooks.c
${CMAKE_CURRENT_LIST_DIR}/src/connection.c
${CMAKE_CURRENT_LIST_DIR}/src/socket.c
${CMAKE_CURRENT_LIST_DIR}/src/socket_mbedtls.c
${CMAKE_CURRENT_LIST_DIR}/src/encryption_key_helpers.c
${CMAKE_CURRENT_LIST_DIR}/src/metadata.c
${CMAKE_CURRENT_LIST_DIR}/src/monitor.c
Expand Down
24 changes: 15 additions & 9 deletions packages/atclient/include/atclient/connection.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
/*
*
* The connection family of types and methods represents a single connection to
* if you want a pure socket representation see net_socket.h.
*
* At the moment _socket represents a singular tcp socket, but in the future it may be altered
* to be a union of different connection types, such as a websocket or other construct.
* It is considered an internal construct and is subject to breaking changes across
* minor releases, especially while at_c remains in beta status.
*
*/
#ifndef ATCLIENT_CONNECTION_H
#define ATCLIENT_CONNECTION_H
#include "atclient/socket.h"
#ifdef __cplusplus
extern "C" {
#endif

#include "atchops/mbedtls.h"
#include "atclient/connection_hooks.h"
#include <atchops/platform.h> // IWYU pragma: keep
#include <stdbool.h>
Expand All @@ -31,12 +42,8 @@ typedef struct atclient_connection {
// _is_connection_enabled also serves as an internal boolean to check if the following mbedlts contexts have been
// initialized and need to be freed at the end
bool _is_connection_enabled : 1;
mbedtls_net_context net;
mbedtls_ssl_context ssl;
mbedtls_ssl_config ssl_config;
mbedtls_x509_crt cacert;
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;

struct atclient_tls_socket _socket;

bool _is_hooks_enabled : 1;
atclient_connection_hooks *hooks;
Expand Down Expand Up @@ -80,8 +87,7 @@ int atclient_connection_connect(atclient_connection *ctx, const char *host, cons
* @param value_max_len the maximum length of the data to read, setting this to 0 means no limit
* @return int 0 on success
*/
int atclient_connection_read(atclient_connection *ctx, unsigned char **value, size_t *value_len,
const size_t value_max_len);
int atclient_connection_read(atclient_connection *ctx, unsigned char **value, size_t *value_len);

/**
* @brief Write data to the connection
Expand Down
5 changes: 1 addition & 4 deletions packages/atclient/include/atclient/mbedtls.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@
extern "C" {
#endif

#include <atchops/mbedtls.h> // IWYU pragma: export
#include <mbedtls/net_sockets.h> // IWYU pragma: export
#include <mbedtls/ssl.h> // IWYU pragma: export
#include <mbedtls/threading.h> // IWYU pragma: export
#include <atchops/mbedtls.h> // IWYU pragma: export

#ifdef __cplusplus
}
Expand Down
113 changes: 113 additions & 0 deletions packages/atclient/include/atclient/socket.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
#ifndef ATCLIENT_SOCKET_H
#define ATCLIENT_SOCKET_H
#include <atclient/socket_shared.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif

#if defined(ATCLIENT_SOCKET_PROVIDER_EXTERNAL)
// Noop, this indicates an external socket provider will be linked
#else
#define ATCLIENT_SOCKET_PROVIDER_MBEDTLS
#endif

// IWYU pragma: begin_exports

// Export the appropriate platform specific struct implementation
#if defined(ATCLIENT_SOCKET_PROVIDER_MBEDTLS)
#include "socket_mbedtls.h"
#endif

// IWYU pragma: end_exports

/**
* @brief Initializes a raw socket
*
* @param socket The socket structure to initialize
*/
void atclient_raw_socket_init(struct atclient_raw_socket *socket);

/**
* @brief Frees resources associated with a network socket
*
* @param socket The socket structure to free resources from
*/
void atclient_raw_socket_free(struct atclient_raw_socket *socket);

/**
* @brief Initializes a tls socket with the specified parameters
*
* @param socket The socket structure to initialize
*/
void atclient_tls_socket_init(struct atclient_tls_socket *socket);

/**
* @brief Configures the SSL on a TLS socket
*
* @param ca_pem The X.509 CA certificates in pem format (leave NULL to use the provided default certificates)
* @param ca_pem_len Length of the ca_pem, ignored if ca_pem is NULL
*
* @return 0 on success, non-zero on failure
*
* @note Should be called after atclient_tls_socket_init, note that this
* contains the rest of the initialization operations which have potential
* to fail
*/
int atclient_tls_socket_configure(struct atclient_tls_socket *socket, unsigned char *ca_pem, size_t ca_pem_len);

/**
* @brief Frees resources associated with a network socket
*
* @param socket The socket structure to free resources from
*/
void atclient_tls_socket_free(struct atclient_tls_socket *socket);

/**
* @brief Establishes a connection to the specified host and port using the network socket
*
* @param socket Pointer to the initialized network socket structure
* @param host The hostname or IP address to connect to
* @param port The port number to connect to
*
* @return 0 on success, non-zero on failure
*/
int atclient_tls_socket_connect(struct atclient_tls_socket *socket, const char *host, const uint16_t port);

/**
* @brief Disconnects and closes an established network socket connection
*
* @param socket Pointer to the network socket structure to disconnect
*
* @return 0 on success, non-zero on failure
*/
int atclient_tls_socket_disconnect(struct atclient_tls_socket *socket);

/**
* @brief Writes data to an established network socket connection
*
* @param socket Pointer to the network socket structure
* @param value Pointer to the buffer containing data to write
* @param value_len Length of the data to write in bytes
*
* @return 0 on success, non-zero on failure
*/
int atclient_tls_socket_write(struct atclient_tls_socket *socket, const unsigned char *value, size_t value_len);

/**
* @brief Reads data from an established network socket connection
*
* @param socket Pointer to the network socket structure
* @param value Pointer to the buffer where read data will be stored
* @param value_len Pointer to store the length of data read in bytes
* @param options Options which specify the behaviour of reading the data
*
* @return 0 on success, non-zero on failure
*/
int atclient_tls_socket_read(struct atclient_tls_socket *socket, unsigned char **value, size_t *value_len,
const struct atclient_socket_read_options options);

#ifdef __cplusplus
}
#endif
#endif
32 changes: 32 additions & 0 deletions packages/atclient/include/atclient/socket_mbedtls.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// IWYU pragma: private, include "atclient/net_socket.h"
// IWYU pragma: friend "net_socket_mbedtls.*"
#ifndef ATCLIENT_NET_SOCKET_MBEDTLS_H
#define ATCLIENT_NET_SOCKET_MBEDTLS_H
#include <atclient/socket_shared.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/entropy.h>
#include <mbedtls/net_sockets.h>
#include <mbedtls/ssl.h>
#include <mbedtls/threading.h>
#ifdef __cplusplus
extern "C" {
#endif

// Make this type more portable to consume later
struct atclient_raw_socket {
mbedtls_net_context net;
};

struct atclient_tls_socket {
struct atclient_raw_socket raw;
mbedtls_ssl_context ssl;
mbedtls_ssl_config ssl_config;
mbedtls_x509_crt cacert;
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
};

#ifdef __cplusplus
}
#endif
#endif
57 changes: 57 additions & 0 deletions packages/atclient/include/atclient/socket_shared.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// IWYU pragma: private, include "atclient/net_socket.h"
// IWYU pragma: friend "net_socket_mbedtls.*"
#ifndef ATCLIENT_NET_SOCKET_SHARED_H
#define ATCLIENT_NET_SOCKET_SHARED_H
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif

// Defined later based on platform specific implementation
struct atclient_tls_socket;

// Raw socket is only implemented as an internal construct for now
// In the future it will be a supported standalone socket that can
// be used directly
struct atclient_raw_socket;

enum atclient_socket_read_type {
// ATCLIENT_SOCKET_READ_NUM_BYTES,
ATCLIENT_SOCKET_READ_UNTIL_CHAR,
ATCLIENT_SOCKET_READ_CLEAR_AT_PROMPT,
};

// Define how much we should try to read
struct atclient_socket_read_options {
enum atclient_socket_read_type type;
union {
// size_t num_bytes;
char until_char;
};
};

/**
* @brief Creates read options configured to read until a number of characters have been read
*
* @param bytes The number of characters to try to read
*
* @return struct atclient_socket_read_options Configuration structure for read operation
*/
// struct atclient_socket_read_options atclient_socket_read_num_bytes(size_t bytes);

/**
* @brief Creates read options configured to read until a specific character is encountered
*
* @param read_until The character to read until (delimiter)
*/
struct atclient_socket_read_options atclient_socket_read_until_char(char read_until);

/**
* @brief Creates read options configured to read until a specific character is encountered
*/
struct atclient_socket_read_options atclient_socket_read_clear_at_prompt();

#ifdef __cplusplus
}
#endif
#endif
34 changes: 24 additions & 10 deletions packages/atclient/src/atclient.c
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,12 @@ int atclient_pkam_authenticate(atclient *ctx, const char *atsign, const atclient
char *pkam_cmd = NULL;
char *atsign_with_at = NULL;

bool should_free_atserver_host = false;

// expected result on a successful login
size_t expected_len = 1 + strlen(atsign) + strlen("@data:success");
char expected_buf[expected_len];

/*
* 3. Ensure that the atsign has the @ symbol.
*/
Expand All @@ -249,8 +255,9 @@ int atclient_pkam_authenticate(atclient *ctx, const char *atsign, const atclient
/*
* 4. Get atdirectory_host and atdirectory_port
*/
if(options != NULL && atclient_authenticate_options_is_atdirectory_host_initialized(options) && options->atdirectory_host != NULL &&
atclient_authenticate_options_is_atdirectory_port_initialized(options) && options->atdirectory_port != 0) {
if (options != NULL && atclient_authenticate_options_is_atdirectory_host_initialized(options) &&
options->atdirectory_host != NULL && atclient_authenticate_options_is_atdirectory_port_initialized(options) &&
options->atdirectory_port != 0) {
atdirectory_host = options->atdirectory_host;
atdirectory_port = options->atdirectory_port;
} else {
Expand All @@ -261,7 +268,6 @@ int atclient_pkam_authenticate(atclient *ctx, const char *atsign, const atclient
/*
* 5. Get atserver_host and atserver_port
*/
bool should_free_atserver_host;
if (options != NULL && atclient_authenticate_options_is_atserver_host_initialized(options) &&
options->atserver_host != NULL && atclient_authenticate_options_is_atserver_port_initialized(options) &&
options->atserver_port != 0) {
Expand All @@ -272,9 +278,9 @@ int atclient_pkam_authenticate(atclient *ctx, const char *atsign, const atclient

if (atserver_host == NULL || atserver_port == 0) {
atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_INFO,
"Missing atServer host or port. Using %s:%lu atDirectory to find atServer address\n", atdirectory_host, atdirectory_port);
if ((ret = atclient_utils_find_atserver_address(atdirectory_host,
atdirectory_port, atsign, &atserver_host,
"Missing atServer host or port. Using %s:%lu atDirectory to find atServer address\n", atdirectory_host,
atdirectory_port);
if ((ret = atclient_utils_find_atserver_address(atdirectory_host, atdirectory_port, atsign, &atserver_host,
&atserver_port)) != 0) {
atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atclient_utils_find_atserver_address: %d\n", ret);
goto exit;
Expand Down Expand Up @@ -311,6 +317,14 @@ int atclient_pkam_authenticate(atclient *ctx, const char *atsign, const atclient
goto exit;
}

// We get @data:success when doing pkam auth instead of data:success so read off an '@'
if ((ret = atclient_tls_socket_read(&ctx->atserver_connection._socket, NULL, NULL,
atclient_socket_read_until_char('@'))) != 0) {

atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atclient_connection_send: %d\n", ret);
goto exit;
}

char *str_with_data_prefix = NULL;
if (atclient_string_utils_get_substring_position((char *)recv, ATCLIENT_DATA_TOKEN, &str_with_data_prefix) != 0) {
ret = 1;
Expand Down Expand Up @@ -446,15 +460,16 @@ int atclient_cram_authenticate(atclient *ctx, const char *atsign, const char *cr

unsigned char digest[SHA_512_DIGEST_SIZE];
memset(digest, 0, sizeof(unsigned char) * SHA_512_DIGEST_SIZE);

char *atsign_without_at = NULL;
bool should_free_atserver_host = false;
/*
* 3. Ensure that the atsign has the @ symbol.
*/
if ((ret = atclient_string_utils_atsign_with_at(atsign, &atsign_with_at)) != 0) {
atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "atclient_string_utils_atsign_with_at: %d\n", ret);
goto exit;
}
char *atsign_without_at = malloc(sizeof(char) * strlen(atsign_with_at) + 1);
atsign_without_at = malloc(sizeof(char) * strlen(atsign_with_at) + 1);
if (atsign_without_at == NULL) {
atlogger_log(TAG, ATLOGGER_LOGGING_LEVEL_ERROR, "Could not allocate memory for atsign_without_at");
ret = -1;
Expand All @@ -466,7 +481,6 @@ int atclient_cram_authenticate(atclient *ctx, const char *atsign, const char *cr
/*
* 4. Get atserver_host and atserver_port
*/
bool should_free_atserver_host = false;
if (options != NULL) {
if (atclient_authenticate_options_is_atdirectory_host_initialized(options) &&
atclient_authenticate_options_is_atdirectory_port_initialized(options)) {
Expand Down Expand Up @@ -701,7 +715,7 @@ exit: {
bool atclient_is_connected(atclient *ctx) { return atclient_connection_is_connected(&(ctx->atserver_connection)); }

void atclient_set_read_timeout(atclient *ctx, const int timeout_ms) {
mbedtls_ssl_conf_read_timeout(&ctx->atserver_connection.ssl_config, timeout_ms);
mbedtls_ssl_conf_read_timeout(&ctx->atserver_connection._socket.ssl_config, timeout_ms);
}

static void atclient_set_atsign_initialized(atclient *ctx, const bool initialized) {
Expand Down
2 changes: 1 addition & 1 deletion packages/atclient/src/atclient_get_atkeys.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ int atclient_get_atkeys(atclient *atclient, atclient_atkey **atkey, size_t *outp

char scan_cmd[scan_cmd_size];

const size_t recv_size = 8192; // TODO change using atclient_connection_read which will handle realloc
const size_t recv_size = 16384; // TODO change using atclient_connection_read which will handle realloc
unsigned char recv[recv_size];
size_t recv_len = 0;

Expand Down
Loading

0 comments on commit 535d367

Please sign in to comment.