tests: net: lib: wifi_credentials: add tests

This patch adds tests for the wifi_credentials library.

Both the main functions and the backend implementations are tested.

Signed-off-by: Maximilian Deubel <maximilian.deubel@nordicsemi.no>
This commit is contained in:
Maximilian Deubel 2024-09-06 14:56:19 +02:00 committed by Anas Nashif
commit a441492c7d
13 changed files with 990 additions and 0 deletions

View file

@ -0,0 +1,28 @@
#
# Copyright (c) 2024 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: Apache-2.0
#
cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(wifi_credentials_test)
FILE(GLOB app_sources src/*.c)
target_sources(app PRIVATE ${app_sources})
target_sources(app
PRIVATE
${ZEPHYR_BASE}/subsys/net/lib/wifi_credentials/wifi_credentials.c
)
zephyr_include_directories(${ZEPHYR_BASE}/subsys/testsuite/include)
zephyr_include_directories(${ZEPHYR_BASE}/subsys/net/lib/wifi_credentials/)
target_compile_options(app
PRIVATE
-DCONFIG_WIFI_CREDENTIALS_MAX_ENTRIES=2
-DCONFIG_WIFI_CREDENTIALS_SAE_PASSWORD_LENGTH=128
-DCONFIG_WIFI_CREDENTIALS_LOG_LEVEL=4
)

View file

@ -0,0 +1,8 @@
#
# Copyright (c) 2024 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
#
CONFIG_ZTEST=y
CONFIG_LOG=y

View file

@ -0,0 +1,354 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <zephyr/kernel.h>
#include <zephyr/ztest.h>
#include <zephyr/fff.h>
#include <zephyr/net/wifi_credentials.h>
#include "wifi_credentials_internal.h"
DEFINE_FFF_GLOBALS;
FAKE_VALUE_FUNC(int, wifi_credentials_store_entry, size_t, const void *, size_t)
FAKE_VALUE_FUNC(int, wifi_credentials_load_entry, size_t, void *, size_t)
FAKE_VALUE_FUNC(int, wifi_credentials_delete_entry, size_t)
FAKE_VALUE_FUNC(int, wifi_credentials_backend_init)
uint8_t fake_settings_buf[CONFIG_WIFI_CREDENTIALS_MAX_ENTRIES][ENTRY_MAX_LEN];
int custom_wifi_credentials_store_entry(size_t idx, const void *buf, size_t buf_len)
{
zassert_true(idx < CONFIG_WIFI_CREDENTIALS_MAX_ENTRIES, "Index out of bounds");
memcpy(fake_settings_buf[idx], buf, MIN(ENTRY_MAX_LEN, buf_len));
return 0;
}
int custom_wifi_credentials_load_entry(size_t idx, void *buf, size_t buf_len)
{
zassert_true(idx < CONFIG_WIFI_CREDENTIALS_MAX_ENTRIES, "Index out of bounds");
memcpy(buf, fake_settings_buf[idx], MIN(ENTRY_MAX_LEN, buf_len));
return 0;
}
#define SSID1 "test1"
#define PSK1 "super secret"
#define SECURITY1 WIFI_SECURITY_TYPE_PSK
#define BSSID1 "abcdef"
#define FLAGS1 WIFI_CREDENTIALS_FLAG_BSSID
#define CHANNEL1 1
#define SSID2 "test2"
#define SECURITY2 WIFI_SECURITY_TYPE_NONE
#define FLAGS2 0
#define CHANNEL2 2
#define SSID3 "test3"
#define PSK3 "extremely secret"
#define SECURITY3 WIFI_SECURITY_TYPE_SAE
#define FLAGS3 0
#define CHANNEL3 3
#define SSID4 "\0what's\0null\0termination\0anyway"
#define PSK4 PSK1
#define SECURITY4 SECURITY1
#define BSSID4 BSSID1
#define FLAGS4 FLAGS1
#define CHANNEL4 4
static void wifi_credentials_setup(void *unused)
{
RESET_FAKE(wifi_credentials_store_entry);
RESET_FAKE(wifi_credentials_load_entry);
RESET_FAKE(wifi_credentials_delete_entry);
wifi_credentials_store_entry_fake.custom_fake = custom_wifi_credentials_store_entry;
wifi_credentials_load_entry_fake.custom_fake = custom_wifi_credentials_load_entry;
}
static void wifi_credentials_teardown(void *unused)
{
wifi_credentials_delete_by_ssid(SSID1, ARRAY_SIZE(SSID1));
wifi_credentials_delete_by_ssid(SSID2, ARRAY_SIZE(SSID2));
wifi_credentials_delete_by_ssid(SSID3, ARRAY_SIZE(SSID3));
wifi_credentials_delete_by_ssid(SSID4, ARRAY_SIZE(SSID4));
wifi_credentials_delete_by_ssid("", 0);
}
/* Verify that attempting to retrieve a non-existent credentials entry raises -ENOENT. */
ZTEST(wifi_credentials, test_get_non_existing)
{
int err;
enum wifi_security_type security = -1;
uint8_t bssid_buf[WIFI_MAC_ADDR_LEN] = "";
char psk_buf[WIFI_CREDENTIALS_MAX_PASSWORD_LEN] = "";
size_t psk_len = 0;
uint32_t flags = 0;
uint8_t channel = 0;
uint32_t timeout = 0;
err = wifi_credentials_get_by_ssid_personal(
SSID1, sizeof(SSID1), &security, bssid_buf, ARRAY_SIZE(bssid_buf), psk_buf,
ARRAY_SIZE(psk_buf), &psk_len, &flags, &channel, &timeout);
zassert_equal(err, -ENOENT, "Expected -ENOENT, got %d", err);
}
/* Verify that we can successfully set/get a network without a specified BSSID. */
ZTEST(wifi_credentials, test_single_no_bssid)
{
int err;
/* set network credentials without BSSID */
err = wifi_credentials_set_personal(SSID1, sizeof(SSID1), SECURITY1, NULL, 0, PSK1,
sizeof(PSK1), 0, 0, 0);
zassert_equal(err, EXIT_SUCCESS, "Expected EXIT_SUCCESS, got %d", err);
enum wifi_security_type security = -1;
uint8_t bssid_buf[WIFI_MAC_ADDR_LEN] = "";
char psk_buf[WIFI_CREDENTIALS_MAX_PASSWORD_LEN] = "";
size_t psk_len = 0;
uint32_t flags = 0;
uint8_t channel = 0;
uint32_t timeout = 0;
/* retrieve network credentials without BSSID */
err = wifi_credentials_get_by_ssid_personal(
SSID1, sizeof(SSID1), &security, bssid_buf, ARRAY_SIZE(bssid_buf), psk_buf,
ARRAY_SIZE(psk_buf), &psk_len, &flags, &channel, &timeout);
zassert_equal(err, EXIT_SUCCESS, "Expected EXIT_SUCCESS, got %d", err);
zassert_equal(strncmp(PSK1, psk_buf, ARRAY_SIZE(psk_buf)), 0, "PSK mismatch");
zassert_equal(flags, 0, "Flags mismatch");
zassert_equal(channel, 0, "Channel mismatch");
zassert_equal(security, SECURITY1, "Security type mismatch");
err = wifi_credentials_delete_by_ssid(SSID1, sizeof(SSID1));
zassert_equal(err, EXIT_SUCCESS, "Expected EXIT_SUCCESS, got %d", err);
}
/* Verify that we can successfully set/get a network with a fixed BSSID. */
ZTEST(wifi_credentials, test_single_with_bssid)
{
int err;
/* set network credentials with BSSID */
err = wifi_credentials_set_personal(SSID1, sizeof(SSID1), SECURITY1, BSSID1, 6, PSK1,
sizeof(PSK1), FLAGS1, CHANNEL1, 0);
zassert_equal(err, EXIT_SUCCESS, "Expected EXIT_SUCCESS, got %d", err);
enum wifi_security_type security = -1;
uint8_t bssid_buf[WIFI_MAC_ADDR_LEN] = "";
char psk_buf[WIFI_CREDENTIALS_MAX_PASSWORD_LEN] = "";
size_t psk_len = 0;
uint32_t flags = 0;
uint8_t channel = 0;
uint32_t timeout = 0;
/* retrieve network credentials with BSSID */
err = wifi_credentials_get_by_ssid_personal(
SSID1, sizeof(SSID1), &security, bssid_buf, ARRAY_SIZE(bssid_buf), psk_buf,
ARRAY_SIZE(psk_buf), &psk_len, &flags, &channel, &timeout);
zassert_equal(err, EXIT_SUCCESS, "Expected EXIT_SUCCESS, got %d", err);
zassert_equal(strncmp(PSK1, psk_buf, ARRAY_SIZE(psk_buf)), 0, "PSK mismatch");
zassert_equal(psk_len, sizeof(PSK1), "PSK length mismatch");
zassert_equal(strncmp(BSSID1, bssid_buf, ARRAY_SIZE(bssid_buf)), 0, "BSSID mismatch");
zassert_equal(flags, WIFI_CREDENTIALS_FLAG_BSSID, "Flags mismatch");
zassert_equal(channel, CHANNEL1, "Channel mismatch");
zassert_equal(security, SECURITY1, "Security type mismatch");
err = wifi_credentials_delete_by_ssid(SSID1, sizeof(SSID1));
zassert_equal(err, EXIT_SUCCESS, "Expected EXIT_SUCCESS, got %d", err);
}
/* Verify that we can successfully set/get an open network. */
ZTEST(wifi_credentials, test_single_without_psk)
{
int err;
/* set network credentials without PSK/BSSID */
err = wifi_credentials_set_personal(SSID2, sizeof(SSID2), SECURITY2, NULL, 6, NULL, 0,
FLAGS2, CHANNEL2, 0);
zassert_equal(err, EXIT_SUCCESS, "Expected EXIT_SUCCESS, got %d", err);
enum wifi_security_type security = -1;
uint8_t bssid_buf[WIFI_MAC_ADDR_LEN] = "";
char psk_buf[WIFI_CREDENTIALS_MAX_PASSWORD_LEN] = "";
size_t psk_len = 0;
uint32_t flags = 0;
uint8_t channel = 0;
uint32_t timeout = 0;
/* retrieve network credentials without PSK/BSSID */
err = wifi_credentials_get_by_ssid_personal(
SSID2, sizeof(SSID2), &security, bssid_buf, ARRAY_SIZE(bssid_buf), psk_buf,
ARRAY_SIZE(psk_buf), &psk_len, &flags, &channel, &timeout);
zassert_equal(err, EXIT_SUCCESS, "Expected EXIT_SUCCESS, got %d", err);
zassert_equal(psk_len, 0, "PSK length mismatch");
zassert_equal(flags, 0, "Flags mismatch");
zassert_equal(channel, CHANNEL2, "Channel mismatch");
err = wifi_credentials_delete_by_ssid(SSID2, sizeof(SSID2));
zassert_equal(err, EXIT_SUCCESS, "Expected EXIT_SUCCESS, got %d", err);
}
/* Verify that we can set/get a network that is only identified by a BSSID. */
ZTEST(wifi_credentials, test_single_without_ssid)
{
int err;
err = wifi_credentials_set_personal("", 0, SECURITY1, BSSID1, 6, PSK1, sizeof(PSK1), FLAGS1,
CHANNEL1, 0);
zassert_equal(err, -EINVAL, "Expected -EINVAL, got %d", err);
enum wifi_security_type security = -1;
uint8_t bssid_buf[WIFI_MAC_ADDR_LEN] = "";
char psk_buf[WIFI_CREDENTIALS_MAX_PASSWORD_LEN] = "";
size_t psk_len = 0;
uint32_t flags = 0;
uint8_t channel = 0;
uint32_t timeout = 0;
err = wifi_credentials_get_by_ssid_personal(
"", 0, &security, bssid_buf, ARRAY_SIZE(bssid_buf), psk_buf, ARRAY_SIZE(psk_buf),
&psk_len, &flags, &channel, &timeout);
zassert_equal(err, -EINVAL, "Expected -EINVAL, got %d", err);
err = wifi_credentials_delete_by_ssid("", 0);
zassert_equal(err, -EINVAL, "Expected -EINVAL, got %d", err);
}
/* Verify that we can handle SSIDs that contain NULL characters. */
ZTEST(wifi_credentials, test_single_garbled_ssid)
{
int err;
err = wifi_credentials_set_personal(SSID4, sizeof(SSID4), SECURITY4, BSSID4, 6, PSK4,
sizeof(PSK4), FLAGS4, CHANNEL4, 0);
zassert_equal(err, EXIT_SUCCESS, "Expected EXIT_SUCCESS, got %d", err);
enum wifi_security_type security = -1;
uint8_t bssid_buf[WIFI_MAC_ADDR_LEN] = "";
char psk_buf[WIFI_CREDENTIALS_MAX_PASSWORD_LEN] = "";
size_t psk_len = 0;
uint32_t flags = 0;
uint8_t channel = 0;
uint32_t timeout = 0;
err = wifi_credentials_get_by_ssid_personal(
SSID4, sizeof(SSID4), &security, bssid_buf, ARRAY_SIZE(bssid_buf), psk_buf,
ARRAY_SIZE(psk_buf), &psk_len, &flags, &channel, &timeout);
zassert_equal(err, EXIT_SUCCESS, "Expected EXIT_SUCCESS, got %d", err);
zassert_equal(strncmp(PSK4, psk_buf, ARRAY_SIZE(psk_buf)), 0, "PSK mismatch");
zassert_equal(psk_len, sizeof(PSK4), "PSK length mismatch");
zassert_equal(strncmp(BSSID4, bssid_buf, ARRAY_SIZE(bssid_buf)), 0, "BSSID mismatch");
zassert_equal(security, SECURITY4, "Security type mismatch");
zassert_equal(flags, FLAGS4, "Flags mismatch");
zassert_equal(channel, CHANNEL4, "Channel mismatch");
err = wifi_credentials_delete_by_ssid(SSID4, sizeof(SSID4));
zassert_equal(err, EXIT_SUCCESS, "Expected EXIT_SUCCESS, got %d", err);
}
/* Helper function for test_set_storage_limit, making sure that the SSID cache is correct. */
void verify_ssid_cache_cb(void *cb_arg, const char *ssid, size_t ssid_len)
{
static int call_count;
static const char *const ssids[] = {SSID3, SSID2};
zassert_equal(strncmp(ssids[call_count++], ssid, ssid_len), 0, "SSID cache mismatch");
zassert_is_null(cb_arg, "Callback argument is not NULL");
}
/* Verify that wifi_credentials behaves correctly when the storage limit is reached. */
ZTEST(wifi_credentials, test_storage_limit)
{
int err;
/* Set two networks */
err = wifi_credentials_set_personal(SSID1, sizeof(SSID1), SECURITY1, BSSID1, 6, PSK1,
sizeof(PSK1), FLAGS1, CHANNEL1, 0);
zassert_equal(err, EXIT_SUCCESS, "Expected EXIT_SUCCESS, got %d", err);
err = wifi_credentials_set_personal(SSID2, sizeof(SSID2), SECURITY2, NULL, 6, NULL, 0,
FLAGS2, CHANNEL2, 0);
zassert_equal(err, EXIT_SUCCESS, "Expected EXIT_SUCCESS, got %d", err);
enum wifi_security_type security = -1;
uint8_t bssid_buf[WIFI_MAC_ADDR_LEN] = "";
char psk_buf[WIFI_CREDENTIALS_MAX_PASSWORD_LEN] = "";
size_t psk_len = 0;
uint32_t flags = 0;
uint8_t channel = 0;
uint32_t timeout = 0;
/* Get two networks */
err = wifi_credentials_get_by_ssid_personal(
SSID1, sizeof(SSID1), &security, bssid_buf, ARRAY_SIZE(bssid_buf), psk_buf,
ARRAY_SIZE(psk_buf), &psk_len, &flags, &channel, &timeout);
zassert_equal(err, EXIT_SUCCESS, "Expected EXIT_SUCCESS, got %d", err);
zassert_equal(strncmp(PSK1, psk_buf, ARRAY_SIZE(psk_buf)), 0, "PSK mismatch");
zassert_equal(psk_len, sizeof(PSK1), "PSK length mismatch");
zassert_equal(strncmp(BSSID1, bssid_buf, ARRAY_SIZE(bssid_buf)), 0, "BSSID mismatch");
zassert_equal(security, SECURITY1, "Security type mismatch");
zassert_equal(flags, FLAGS1, "Flags mismatch");
zassert_equal(channel, CHANNEL1, "Channel mismatch");
err = wifi_credentials_get_by_ssid_personal(
SSID2, sizeof(SSID2), &security, bssid_buf, ARRAY_SIZE(bssid_buf), psk_buf,
ARRAY_SIZE(psk_buf), &psk_len, &flags, &channel, &timeout);
zassert_equal(err, EXIT_SUCCESS, "Expected EXIT_SUCCESS, got %d", err);
zassert_equal(security, SECURITY2, "Security type mismatch");
zassert_equal(flags, FLAGS2, "Flags mismatch");
zassert_equal(channel, CHANNEL2, "Channel mismatch");
/* Set third network */
err = wifi_credentials_set_personal(SSID3, sizeof(SSID3), SECURITY3, NULL, 6, PSK3,
sizeof(PSK3), FLAGS3, CHANNEL3, 0);
zassert_equal(err, -ENOBUFS, "Expected -ENOBUFS, got %d", err);
/* Not enough space? Delete the first one. */
wifi_credentials_delete_by_ssid(SSID1, ARRAY_SIZE(SSID1));
err = wifi_credentials_set_personal(SSID3, sizeof(SSID3), SECURITY3, NULL, 6, PSK3,
sizeof(PSK3), FLAGS3, CHANNEL3, 0);
zassert_equal(err, EXIT_SUCCESS, "Expected EXIT_SUCCESS, got %d", err);
err = wifi_credentials_get_by_ssid_personal(
SSID3, sizeof(SSID3), &security, bssid_buf, ARRAY_SIZE(bssid_buf), psk_buf,
ARRAY_SIZE(psk_buf), &psk_len, &flags, &channel, &timeout);
zassert_equal(err, EXIT_SUCCESS, "Expected EXIT_SUCCESS, got %d", err);
zassert_equal(security, SECURITY3, "Security type mismatch");
zassert_equal(psk_len, sizeof(PSK3), "PSK length mismatch");
zassert_equal(strncmp(PSK3, psk_buf, ARRAY_SIZE(psk_buf)), 0, "PSK mismatch");
zassert_equal(flags, FLAGS3, "Flags mismatch");
zassert_equal(channel, CHANNEL3, "Channel mismatch");
wifi_credentials_for_each_ssid(verify_ssid_cache_cb, NULL);
}
/* Verify that all entries are deleted. */
ZTEST(wifi_credentials, test_delete_all_entries)
{
/* Set two networks */
int err = wifi_credentials_set_personal(SSID1, sizeof(SSID1), SECURITY1, BSSID1, 6, PSK1,
sizeof(PSK1), FLAGS1, CHANNEL1, 0);
zassert_equal(err, EXIT_SUCCESS, "Expected EXIT_SUCCESS, got %d", err);
err = wifi_credentials_set_personal(SSID2, sizeof(SSID2), SECURITY2, NULL, 6, NULL, 0,
FLAGS2, CHANNEL2, 0);
zassert_equal(err, EXIT_SUCCESS, "Expected EXIT_SUCCESS, got %d", err);
/* Delete all networks */
err = wifi_credentials_delete_all();
zassert_equal(err, EXIT_SUCCESS, "Expected EXIT_SUCCESS, got %d", err);
/* Verify that the storage is empty */
zassert_true(wifi_credentials_is_empty(), "Storage is not empty");
}
ZTEST_SUITE(wifi_credentials, NULL, NULL, wifi_credentials_setup, wifi_credentials_teardown, NULL);

View file

@ -0,0 +1,6 @@
tests:
net.wifi_credentials:
tags:
- net
integration_platforms:
- native_sim

View file

@ -0,0 +1,36 @@
#
# Copyright (c) 2024 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: Apache-2.0
#
cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(wifi_credentials_test)
FILE(GLOB app_sources src/*.c)
target_sources(app PRIVATE ${app_sources})
target_sources(app
PRIVATE
${ZEPHYR_BASE}/subsys/net/lib/wifi_credentials/wifi_credentials_backend_psa.c
)
zephyr_include_directories(${ZEPHYR_BASE}/subsys/testsuite/include)
zephyr_include_directories(${ZEPHYR_BASE}/subsys/net/lib/wifi_credentials/)
zephyr_include_directories(${ZEPHYR_TRUSTED_FIRMWARE_M_MODULE_DIR}/interface/include/)
zephyr_include_directories(${ZEPHYR_BASE}/../modules/crypto/mbedtls/include/)
target_compile_options(app
PRIVATE
-DCONFIG_WIFI_CREDENTIALS_MAX_ENTRIES=2
-DCONFIG_WIFI_CREDENTIALS_SAE_PASSWORD_LENGTH=128
-DCONFIG_WIFI_CREDENTIALS_LOG_LEVEL=4
-DCONFIG_WIFI_CREDENTIALS_BACKEND_PSA_OFFSET=5
)
set_property(
SOURCE ${ZEPHYR_BASE}/subsys/net/lib/wifi_credentials/wifi_credentials_backend_psa.c
PROPERTY COMPILE_FLAGS "-include ${CMAKE_CURRENT_SOURCE_DIR}/src/normalized_crypto.h"
)

View file

@ -0,0 +1,8 @@
#
# Copyright (c) 2024 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: Apache-2.0
#
CONFIG_ZTEST=y
CONFIG_LOG=y

View file

@ -0,0 +1,224 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/ztest.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <zephyr/kernel.h>
#include <zephyr/init.h>
#include <zephyr/fff.h>
#include <zephyr/net/wifi_credentials.h>
#include "wifi_credentials_internal.h"
#include "psa/crypto_types.h"
#include "psa/crypto_values.h"
#define SSID1 "test1"
#define PSK1 "super secret"
#define SECURITY1 WIFI_SECURITY_TYPE_PSK
#define BSSID1 "abcdef"
#define FLAGS1 WIFI_CREDENTIALS_FLAG_BSSID
#define SSID2 "test2"
#define PSK2 NULL
#define SECURITY2 WIFI_SECURITY_TYPE_NONE
#define BSSID2 NULL
#define FLAGS2 0
#define WIFI_CREDENTIALS_BACKEND_PSA_KEY_ID_USER_MIN \
(PSA_KEY_ID_USER_MIN + CONFIG_WIFI_CREDENTIALS_BACKEND_PSA_OFFSET)
DEFINE_FFF_GLOBALS;
K_MUTEX_DEFINE(wifi_credentials_mutex);
FAKE_VOID_FUNC(wifi_credentials_cache_ssid, size_t, const struct wifi_credentials_header *);
FAKE_VALUE_FUNC(psa_status_t, psa_export_key, mbedtls_svc_key_id_t, uint8_t *, size_t, size_t *);
FAKE_VALUE_FUNC(psa_status_t, psa_import_key, psa_key_attributes_t *, uint8_t *, size_t,
mbedtls_svc_key_id_t *);
FAKE_VALUE_FUNC(psa_status_t, psa_destroy_key, mbedtls_svc_key_id_t);
FAKE_VOID_FUNC(psa_set_key_id, psa_key_attributes_t *, uint32_t);
FAKE_VOID_FUNC(psa_set_key_usage_flags, psa_key_attributes_t *, psa_key_usage_t);
FAKE_VOID_FUNC(psa_set_key_lifetime, psa_key_attributes_t *, psa_key_lifetime_t);
FAKE_VOID_FUNC(psa_set_key_algorithm, psa_key_attributes_t *, psa_algorithm_t);
FAKE_VOID_FUNC(psa_set_key_type, psa_key_attributes_t *, psa_key_type_t);
FAKE_VOID_FUNC(psa_set_key_bits, psa_key_attributes_t *, size_t);
static const struct wifi_credentials_personal example1 = {
.header = {
.ssid = SSID1,
.ssid_len = strlen(SSID1),
.type = SECURITY1,
.bssid = BSSID1,
.flags = FLAGS1,
},
.password = PSK1,
.password_len = strlen(PSK1),
};
static const struct wifi_credentials_personal example2 = {
.header = {
.ssid = SSID2,
.ssid_len = strlen(SSID2),
.type = SECURITY2,
.flags = FLAGS2,
},
};
static size_t idx;
psa_status_t custom_psa_export_key(mbedtls_svc_key_id_t key, uint8_t *data, size_t data_size,
size_t *data_length)
{
/* confirm that we read the requested amount of data */
*data_length = data_size;
return PSA_SUCCESS;
}
static void custom_psa_set_key_id(psa_key_attributes_t *attributes, mbedtls_svc_key_id_t key)
{
zassert_equal(idx + WIFI_CREDENTIALS_BACKEND_PSA_KEY_ID_USER_MIN, key, "Key ID mismatch");
}
void custom_psa_set_key_bits(psa_key_attributes_t *attributes, size_t bits)
{
zassert_equal(sizeof(struct wifi_credentials_personal) * 8, bits, "Key bits mismatch");
}
void custom_psa_set_key_type(psa_key_attributes_t *attributes, psa_key_type_t type)
{
zassert_equal(PSA_KEY_TYPE_RAW_DATA, type, "Key type mismatch");
}
void custom_psa_set_key_algorithm(psa_key_attributes_t *attributes, psa_algorithm_t alg)
{
zassert_equal(PSA_ALG_NONE, alg, "Key algorithm mismatch");
}
void custom_psa_set_key_lifetime(psa_key_attributes_t *attributes, psa_key_lifetime_t lifetime)
{
zassert_equal(PSA_KEY_LIFETIME_PERSISTENT, lifetime, "Key lifetime mismatch");
}
void custom_psa_set_key_usage_flags(psa_key_attributes_t *attributes, psa_key_usage_t usage_flags)
{
zassert_equal(PSA_KEY_USAGE_EXPORT, usage_flags, "Key usage flags mismatch");
}
static void wifi_credentials_backend_psa_setup(void *_unused)
{
RESET_FAKE(wifi_credentials_cache_ssid);
RESET_FAKE(psa_export_key);
RESET_FAKE(psa_import_key);
RESET_FAKE(psa_destroy_key);
psa_export_key_fake.custom_fake = custom_psa_export_key;
psa_set_key_id_fake.custom_fake = custom_psa_set_key_id;
psa_set_key_usage_flags_fake.custom_fake = custom_psa_set_key_usage_flags;
psa_set_key_lifetime_fake.custom_fake = custom_psa_set_key_lifetime;
psa_set_key_algorithm_fake.custom_fake = custom_psa_set_key_algorithm;
psa_set_key_type_fake.custom_fake = custom_psa_set_key_type;
psa_set_key_bits_fake.custom_fake = custom_psa_set_key_bits;
idx = 0;
}
ZTEST(wifi_credentials_backend_psa, test_init)
{
int ret;
ret = wifi_credentials_backend_init();
zassert_equal(0, ret, "Initialization failed");
zassert_equal(psa_export_key_fake.call_count, CONFIG_WIFI_CREDENTIALS_MAX_ENTRIES,
"Export key call count mismatch");
zassert_equal(wifi_credentials_cache_ssid_fake.call_count,
CONFIG_WIFI_CREDENTIALS_MAX_ENTRIES, "Cache SSID call count mismatch");
}
ZTEST(wifi_credentials_backend_psa, test_add)
{
int ret = wifi_credentials_store_entry(idx, &example1,
sizeof(struct wifi_credentials_personal));
zassert_equal(0, ret, "Store entry failed");
zassert_equal_ptr(psa_import_key_fake.arg1_val, &example1, "Import key arg1 mismatch");
zassert_equal(psa_import_key_fake.arg2_val, sizeof(struct wifi_credentials_personal),
"Import key arg2 mismatch");
idx++;
ret = wifi_credentials_store_entry(idx, &example2,
sizeof(struct wifi_credentials_personal));
zassert_equal(0, ret, "Store entry failed");
zassert_equal_ptr(psa_import_key_fake.arg1_val, &example2, "Import key arg1 mismatch");
zassert_equal(psa_import_key_fake.arg2_val, sizeof(struct wifi_credentials_personal),
"Import key arg2 mismatch");
zassert_equal(psa_import_key_fake.call_count, 2, "Import key call count mismatch");
zassert_equal(psa_set_key_id_fake.call_count, 2, "Set key ID call count mismatch");
zassert_equal(psa_set_key_usage_flags_fake.call_count, 2,
"Set key usage flags call count mismatch");
zassert_equal(psa_set_key_lifetime_fake.call_count, 2,
"Set key lifetime call count mismatch");
zassert_equal(psa_set_key_algorithm_fake.call_count, 2,
"Set key algorithm call count mismatch");
zassert_equal(psa_set_key_type_fake.call_count, 2, "Set key type call count mismatch");
zassert_equal(psa_set_key_bits_fake.call_count, 2, "Set key bits call count mismatch");
}
ZTEST(wifi_credentials_backend_psa, test_get)
{
int ret;
psa_key_id_t key_id = idx + WIFI_CREDENTIALS_BACKEND_PSA_KEY_ID_USER_MIN;
uint8_t buf[ENTRY_MAX_LEN];
ret = wifi_credentials_load_entry(idx, buf, ARRAY_SIZE(buf));
zassert_equal(0, ret, "Load entry failed");
zassert_equal(psa_export_key_fake.arg0_val, key_id, "Export key arg0 mismatch");
zassert_equal_ptr(psa_export_key_fake.arg1_val, buf, "Export key arg1 mismatch");
zassert_equal(psa_export_key_fake.arg2_val, ARRAY_SIZE(buf), "Export key arg2 mismatch");
idx++;
key_id = idx + WIFI_CREDENTIALS_BACKEND_PSA_KEY_ID_USER_MIN;
ret = wifi_credentials_load_entry(idx, buf, ARRAY_SIZE(buf));
zassert_equal(0, ret, "Load entry failed");
zassert_equal(psa_export_key_fake.arg0_val, key_id, "Export key arg0 mismatch");
zassert_equal_ptr(psa_export_key_fake.arg1_val, buf, "Export key arg1 mismatch");
zassert_equal(psa_export_key_fake.arg2_val, ARRAY_SIZE(buf), "Export key arg2 mismatch");
zassert_equal(psa_export_key_fake.call_count, 2, "Export key call count mismatch");
}
ZTEST(wifi_credentials_backend_psa, test_delete)
{
int ret;
ret = wifi_credentials_delete_entry(idx);
zassert_equal(0, ret, "Delete entry failed");
zassert_equal(psa_destroy_key_fake.arg0_val, WIFI_CREDENTIALS_BACKEND_PSA_KEY_ID_USER_MIN,
"Destroy key arg0 mismatch");
idx++;
ret = wifi_credentials_delete_entry(1);
zassert_equal(0, ret, "Delete entry failed");
zassert_equal(psa_destroy_key_fake.arg0_val,
idx + WIFI_CREDENTIALS_BACKEND_PSA_KEY_ID_USER_MIN,
"Destroy key arg0 mismatch");
zassert_equal(psa_destroy_key_fake.call_count, 2, "Destroy key call count mismatch");
}
ZTEST_SUITE(wifi_credentials_backend_psa, NULL, NULL, wifi_credentials_backend_psa_setup, NULL,
NULL);

View file

@ -0,0 +1,44 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef PSA_CRYPTO_H
#define PSA_CRYPTO_H
#include "zephyr/types.h"
#include "psa/crypto_types.h"
#include "psa/crypto_values.h"
struct psa_client_key_attributes_s {
uint16_t type;
uint16_t bits;
uint32_t lifetime;
psa_key_id_t id;
uint32_t usage;
uint32_t alg;
};
struct psa_key_attributes_s {
struct psa_client_key_attributes_s client;
};
typedef struct psa_key_attributes_s psa_key_attributes_t;
psa_status_t psa_import_key(const psa_key_attributes_t *attributes, const uint8_t *data,
size_t data_length, mbedtls_svc_key_id_t *key);
psa_status_t psa_export_key(mbedtls_svc_key_id_t key, uint8_t *data, size_t data_size,
size_t *data_length);
psa_status_t psa_destroy_key(mbedtls_svc_key_id_t key);
void psa_set_key_id(psa_key_attributes_t *attributes, mbedtls_svc_key_id_t key);
void psa_set_key_bits(psa_key_attributes_t *attributes, size_t bits);
void psa_set_key_type(psa_key_attributes_t *attributes, psa_key_type_t type);
void psa_set_key_algorithm(psa_key_attributes_t *attributes, psa_algorithm_t alg);
void psa_set_key_lifetime(psa_key_attributes_t *attributes, psa_key_lifetime_t lifetime);
psa_status_t psa_destroy_key(mbedtls_svc_key_id_t key);
void psa_set_key_usage_flags(psa_key_attributes_t *attributes, psa_key_usage_t usage_flags);
#endif

View file

@ -0,0 +1,6 @@
tests:
net.wifi_credentials_backend_psa:
tags:
- net
integration_platforms:
- native_sim

View file

@ -0,0 +1,28 @@
#
# Copyright (c) 2024 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: Apache-2.0
#
cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(wifi_credentials_test)
FILE(GLOB app_sources src/*.c)
target_sources(app PRIVATE ${app_sources})
target_sources(app
PRIVATE
${ZEPHYR_BASE}/subsys/net/lib/wifi_credentials/wifi_credentials_backend_settings.c
)
zephyr_include_directories(${ZEPHYR_BASE}/subsys/testsuite/include)
zephyr_include_directories(${ZEPHYR_BASE}/subsys/net/lib/wifi_credentials/)
target_compile_options(app
PRIVATE
-DCONFIG_WIFI_CREDENTIALS_MAX_ENTRIES=2
-DCONFIG_WIFI_CREDENTIALS_SAE_PASSWORD_LENGTH=128
-DCONFIG_WIFI_CREDENTIALS_LOG_LEVEL=4
)

View file

@ -0,0 +1,8 @@
#
# Copyright (c) 2024 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: Apache-2.0
#
CONFIG_ZTEST=y
CONFIG_LOG=y

View file

@ -0,0 +1,234 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/ztest.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <zephyr/kernel.h>
#include <zephyr/settings/settings.h>
#include <zephyr/fff.h>
#include <zephyr/net/wifi_credentials.h>
#include "wifi_credentials_internal.h"
#define MAX_KEY_LEN 16
#define SSID1 "test1"
#define PSK1 "super secret"
#define SECURITY1 WIFI_SECURITY_TYPE_PSK
#define BSSID1 "abcdef"
#define FLAGS1 WIFI_CREDENTIALS_FLAG_BSSID
#define SSID2 "test2"
#define PSK2 NULL
#define SECURITY2 WIFI_SECURITY_TYPE_NONE
#define BSSID2 NULL
#define FLAGS2 0
DEFINE_FFF_GLOBALS;
K_MUTEX_DEFINE(wifi_credentials_mutex);
FAKE_VALUE_FUNC(int, settings_subsys_init);
FAKE_VALUE_FUNC(int, settings_save_one, const char *, const void *, size_t);
FAKE_VALUE_FUNC(int, settings_delete, const char *);
FAKE_VALUE_FUNC(int, settings_load_subtree_direct, const char *, settings_load_direct_cb, void *);
FAKE_VOID_FUNC(wifi_credentials_cache_ssid, size_t, const struct wifi_credentials_header *);
static uint8_t fake_settings_buf[CONFIG_WIFI_CREDENTIALS_MAX_ENTRIES][ENTRY_MAX_LEN];
static char fake_settings_buf_keys[CONFIG_WIFI_CREDENTIALS_MAX_ENTRIES][MAX_KEY_LEN];
static size_t fake_settings_buf_lens[CONFIG_WIFI_CREDENTIALS_MAX_ENTRIES];
typedef int (*settings_set_cb)(const char *key, size_t len, settings_read_cb read_cb, void *cb_arg);
static const struct wifi_credentials_personal example1 = {
.header = {
.ssid = SSID1,
.ssid_len = strlen(SSID1),
.type = SECURITY1,
.bssid = BSSID1,
.flags = FLAGS1,
},
.password = PSK1,
.password_len = strlen(PSK1),
};
static const struct wifi_credentials_personal example2 = {
.header = {
.ssid = SSID2,
.ssid_len = strlen(SSID2),
.type = SECURITY2,
.flags = FLAGS2,
},
};
/**
* @brief load content of given settings index to given buffer
*
* @param cb_arg size_t *idx
* @param data destination
* @param len length
* @return ssize_t MIN(length, length_available)
*/
ssize_t custom_settings_read_cb(void *cb_arg, void *data, size_t len)
{
size_t *idx = cb_arg;
zassert_true(len <= ENTRY_MAX_LEN, "Length exceeds ENTRY_MAX_LEN");
memcpy(data, fake_settings_buf[*idx], len);
return len;
}
static int custom_settings_save_one(const char *name, const void *value, size_t val_len)
{
zassert_true(strlen(name) < MAX_KEY_LEN, "Name length exceeds MAX_KEY_LEN");
zassert_true(val_len <= ENTRY_MAX_LEN, "Value length exceeds ENTRY_MAX_LEN");
for (size_t i = 0; i < CONFIG_WIFI_CREDENTIALS_MAX_ENTRIES; ++i) {
if (strlen(fake_settings_buf_keys[i]) == 0 ||
strcmp(name, fake_settings_buf_keys[i]) == 0) {
strcpy(fake_settings_buf_keys[i], name);
memcpy(fake_settings_buf[i], value, val_len);
fake_settings_buf_lens[i] = val_len;
return 0;
}
}
return -ENOBUFS;
}
static int custom_settings_delete(const char *name)
{
zassert_true(strlen(name) < MAX_KEY_LEN, "Name length exceeds MAX_KEY_LEN");
for (size_t i = 0; i < CONFIG_WIFI_CREDENTIALS_MAX_ENTRIES; ++i) {
if (strcmp(name, fake_settings_buf_keys[i]) == 0) {
memset(fake_settings_buf_keys[i], 0, MAX_KEY_LEN);
memset(fake_settings_buf[i], 0, ENTRY_MAX_LEN);
fake_settings_buf_lens[i] = 0;
return 0;
}
}
return -ENOENT;
}
static int custom_settings_load_subtree_direct(const char *subtree, settings_load_direct_cb cb,
void *param)
{
size_t subtree_len = strlen(subtree);
zassert_true(subtree_len < MAX_KEY_LEN, "Subtree length exceeds MAX_KEY_LEN");
for (size_t i = 0; i < CONFIG_WIFI_CREDENTIALS_MAX_ENTRIES; ++i) {
if (strncmp(subtree, fake_settings_buf_keys[i], subtree_len) == 0) {
const char *key = fake_settings_buf_keys[i] + subtree_len + 1;
cb(key, fake_settings_buf_lens[i], custom_settings_read_cb, &i, param);
}
}
return 0;
}
static void custom_wifi_credentials_cache_ssid(size_t idx,
const struct wifi_credentials_header *buf)
{
char name[16] = "";
snprintk(name, ARRAY_SIZE(name), "wifi_cred/%d", idx);
for (size_t i = 0; i < CONFIG_WIFI_CREDENTIALS_MAX_ENTRIES; ++i) {
if (strcmp(name, fake_settings_buf_keys[i]) == 0) {
zassert_equal(memcmp(buf, &fake_settings_buf[i],
sizeof(struct wifi_credentials_header)),
0, "Buffer mismatch");
return;
}
}
zassert_true(false, "SSID not found in cache");
}
static void wifi_credentials_backend_settings_setup(void *_unused)
{
RESET_FAKE(settings_save_one);
RESET_FAKE(settings_delete);
RESET_FAKE(settings_load_subtree_direct);
RESET_FAKE(wifi_credentials_cache_ssid);
settings_save_one_fake.custom_fake = custom_settings_save_one;
settings_delete_fake.custom_fake = custom_settings_delete;
settings_load_subtree_direct_fake.custom_fake = custom_settings_load_subtree_direct;
wifi_credentials_cache_ssid_fake.custom_fake = custom_wifi_credentials_cache_ssid;
memset(fake_settings_buf_lens, 0, ARRAY_SIZE(fake_settings_buf_lens) * sizeof(size_t));
memset(fake_settings_buf_keys, 0, CONFIG_WIFI_CREDENTIALS_MAX_ENTRIES * MAX_KEY_LEN);
memset(fake_settings_buf, 0, CONFIG_WIFI_CREDENTIALS_MAX_ENTRIES * ENTRY_MAX_LEN);
}
ZTEST(wifi_credentials_backend_settings, test_init)
{
int ret;
ret = wifi_credentials_store_entry(0, &example1, sizeof(struct wifi_credentials_personal));
zassert_equal(ret, 0, "Failed to store entry 0");
ret = wifi_credentials_store_entry(1, &example2, sizeof(struct wifi_credentials_personal));
zassert_equal(ret, 0, "Failed to store entry 1");
ret = wifi_credentials_backend_init();
zassert_equal(ret, 0, "Backend init failed");
zassert_equal(settings_subsys_init_fake.call_count, 1,
"settings_subsys_init call count mismatch");
zassert_equal(wifi_credentials_cache_ssid_fake.call_count, 2,
"wifi_credentials_cache_ssid call count mismatch");
zassert_equal(wifi_credentials_cache_ssid_fake.arg0_history[0], 0,
"First cache SSID index mismatch");
zassert_equal(wifi_credentials_cache_ssid_fake.arg0_history[1], 1,
"Second cache SSID index mismatch");
}
ZTEST(wifi_credentials_backend_settings, test_add)
{
int ret = wifi_credentials_store_entry(0, "abc", 3);
zassert_equal(ret, 0, "Failed to add entry");
zassert_equal(settings_save_one_fake.call_count, 1,
"settings_save_one call count mismatch");
zassert_equal(strcmp(fake_settings_buf_keys[0], "wifi_cred/0"), 0, "Key mismatch");
zassert_equal(strcmp(fake_settings_buf[0], "abc"), 0, "Value mismatch");
zassert_equal(fake_settings_buf_lens[0], 3, "Length mismatch");
}
ZTEST(wifi_credentials_backend_settings, test_get)
{
int ret;
ret = wifi_credentials_store_entry(0, &example1, sizeof(struct wifi_credentials_personal));
zassert_equal(ret, 0, "Failed to store entry 0");
ret = wifi_credentials_store_entry(1, &example2, sizeof(struct wifi_credentials_personal));
zassert_equal(ret, 0, "Failed to store entry 1");
char buf[ENTRY_MAX_LEN] = {0};
ret = wifi_credentials_load_entry(0, buf, ARRAY_SIZE(buf));
zassert_equal(ret, 0, "Failed to load entry 0");
zassert_equal(memcmp(&example1, buf, ARRAY_SIZE(buf)), 0, "Entry 0 data mismatch");
ret = wifi_credentials_load_entry(1, buf, ARRAY_SIZE(buf));
zassert_equal(ret, 0, "Failed to load entry 1");
zassert_equal(memcmp(&example2, buf, ARRAY_SIZE(buf)), 0, "Entry 1 data mismatch");
}
ZTEST(wifi_credentials_backend_settings, test_delete)
{
int ret;
ret = wifi_credentials_store_entry(0, "abc", 3);
zassert_equal(ret, 0, "Failed to store entry");
ret = wifi_credentials_delete_entry(0);
zassert_equal(ret, 0, "Failed to delete entry");
zassert_equal(settings_delete_fake.call_count, 1, "settings_delete call count mismatch");
}
ZTEST_SUITE(wifi_credentials_backend_settings, NULL, NULL, wifi_credentials_backend_settings_setup,
NULL, NULL);

View file

@ -0,0 +1,6 @@
tests:
net.wifi_credentials_backend_settings:
tags:
- net
integration_platforms:
- native_sim