|
| 1 | +/* |
| 2 | + * Copyright (c) 2025 Nordic Semiconductor ASA |
| 3 | + * |
| 4 | + * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause |
| 5 | + */ |
| 6 | + |
| 7 | +#include <zephyr/ztest.h> |
| 8 | +#include <stdbool.h> |
| 9 | +#include <stdlib.h> |
| 10 | +#include <string.h> |
| 11 | +#include <zephyr/kernel.h> |
| 12 | +#include <zephyr/device.h> |
| 13 | + |
| 14 | +#include <modem/modem_key_mgmt.h> |
| 15 | + |
| 16 | +#include <zephyr/fff.h> |
| 17 | + |
| 18 | +#include <nrf_modem_at.h> |
| 19 | +#include <nrf_errno.h> |
| 20 | + |
| 21 | +DEFINE_FFF_GLOBALS; |
| 22 | + |
| 23 | +FAKE_VOID_FUNC(key_list_cb, nrf_sec_tag_t, enum modem_key_mgmt_cred_type); |
| 24 | +FAKE_VALUE_FUNC_VARARG(int, nrf_modem_at_printf, const char *, ...); |
| 25 | +FAKE_VALUE_FUNC_VARARG(int, nrf_modem_at_scanf, const char *, const char *, ...); |
| 26 | +FAKE_VALUE_FUNC_VARARG(int, nrf_modem_at_cmd, void *, size_t, const char *, ...); |
| 27 | + |
| 28 | +static const char test_cmee_enabled[] = "+CMEE: 1"; |
| 29 | +static const char *test_data_empty_list = "OK\r\n"; |
| 30 | + |
| 31 | +static int nrf_modem_at_scanf_test_digest_empty(const char *cmd, const char *fmt, va_list args) |
| 32 | +{ |
| 33 | + switch (nrf_modem_at_scanf_fake.call_count) { |
| 34 | + case 1: |
| 35 | + /* For the purpose of this test, simplify by having the cmee already enabled. */ |
| 36 | + return vsscanf(test_cmee_enabled, fmt, args); |
| 37 | + case 2: |
| 38 | + zassert_equal(0, strcmp("AT%CMNG=1,0,0", cmd)); |
| 39 | + return vsscanf(test_data_empty_list, fmt, args); |
| 40 | + default: |
| 41 | + zassert_true(false); |
| 42 | + } |
| 43 | + |
| 44 | + return 0; |
| 45 | +} |
| 46 | + |
| 47 | +ZTEST(suite_modem_key_mgmt, test_digest_no_entry) |
| 48 | +{ |
| 49 | + char digest_buf[32]; |
| 50 | + int err; |
| 51 | + |
| 52 | + nrf_modem_at_scanf_fake.custom_fake = nrf_modem_at_scanf_test_digest_empty; |
| 53 | + |
| 54 | + err = modem_key_mgmt_digest(0, MODEM_KEY_MGMT_CRED_TYPE_CA_CHAIN, |
| 55 | + digest_buf, sizeof(digest_buf)); |
| 56 | + zassert_equal(err, -ENOENT); |
| 57 | +} |
| 58 | + |
| 59 | +ZTEST(suite_modem_key_mgmt, test_digest_size_too_small) |
| 60 | +{ |
| 61 | + char digest_buf[32]; |
| 62 | + int err; |
| 63 | + |
| 64 | + err = modem_key_mgmt_digest(0, MODEM_KEY_MGMT_CRED_TYPE_CA_CHAIN, |
| 65 | + digest_buf, sizeof(digest_buf) - 1); |
| 66 | + zassert_equal(err, -ENOMEM); |
| 67 | +} |
| 68 | + |
| 69 | +static const char *test_data_digest = |
| 70 | +"%CMNG: 16842753,1,\"B9BAC15641653CAE2B5151DCBD0C40DDCDF19125950FA2475977437EA35F7A45\"\r\n" |
| 71 | +"OK\r\n"; |
| 72 | + |
| 73 | +static const uint8_t expected_digest[] = { |
| 74 | + 0xB9, 0xBA, 0xC1, 0x56, 0x41, 0x65, 0x3C, 0xAE, |
| 75 | + 0x2B, 0x51, 0x51, 0xDC, 0xBD, 0x0C, 0x40, 0xDD, |
| 76 | + 0xCD, 0xF1, 0x91, 0x25, 0x95, 0x0F, 0xA2, 0x47, |
| 77 | + 0x59, 0x77, 0x43, 0x7E, 0xA3, 0x5F, 0x7A, 0x45 |
| 78 | +}; |
| 79 | + |
| 80 | +static int nrf_modem_at_scanf_test_digest(const char *cmd, const char *fmt, va_list args) |
| 81 | +{ |
| 82 | + switch (nrf_modem_at_scanf_fake.call_count) { |
| 83 | + case 1: |
| 84 | + /* For the purpose of this test, simplify by having the cmee already enabled. */ |
| 85 | + return vsscanf(test_cmee_enabled, fmt, args); |
| 86 | + case 2: |
| 87 | + zassert_equal(0, strcmp("AT%CMNG=1,16842753,1", cmd)); |
| 88 | + return vsscanf(test_data_digest, fmt, args); |
| 89 | + default: |
| 90 | + zassert_true(false); |
| 91 | + } |
| 92 | + |
| 93 | + return 0; |
| 94 | +} |
| 95 | + |
| 96 | +ZTEST(suite_modem_key_mgmt, test_digest_public_cert) |
| 97 | +{ |
| 98 | + char digest_buf[32]; |
| 99 | + int err; |
| 100 | + |
| 101 | + nrf_modem_at_scanf_fake.custom_fake = nrf_modem_at_scanf_test_digest; |
| 102 | + |
| 103 | + err = modem_key_mgmt_digest(16842753, MODEM_KEY_MGMT_CRED_TYPE_PUBLIC_CERT, |
| 104 | + digest_buf, sizeof(digest_buf)); |
| 105 | + zassert_ok(err); |
| 106 | + zassert_mem_equal(digest_buf, expected_digest, sizeof(expected_digest)); |
| 107 | +} |
| 108 | + |
| 109 | +/* Invalid because the digest is one byte short. */ |
| 110 | +static const char *test_data_invalid_digest = |
| 111 | +"%CMNG: 16842753,1,\"B9BAC15641653CAE2B5151DCBD0C40DDCDF19125950FA2475977437EA35F7A\"\r\n" |
| 112 | +"OK\r\n"; |
| 113 | + |
| 114 | +static int nrf_modem_at_scanf_test_invalid_digest(const char *cmd, const char *fmt, va_list args) |
| 115 | +{ |
| 116 | + switch (nrf_modem_at_scanf_fake.call_count) { |
| 117 | + case 1: |
| 118 | + /* For the purpose of this test, simplify by having the cmee already enabled. */ |
| 119 | + return vsscanf(test_cmee_enabled, fmt, args); |
| 120 | + case 2: |
| 121 | + zassert_equal(0, strcmp("AT%CMNG=1,16842753,1", cmd)); |
| 122 | + return vsscanf(test_data_invalid_digest, fmt, args); |
| 123 | + default: |
| 124 | + zassert_true(false); |
| 125 | + } |
| 126 | + |
| 127 | + return 0; |
| 128 | +} |
| 129 | + |
| 130 | +ZTEST(suite_modem_key_mgmt, test_digest_invalid_response) |
| 131 | +{ |
| 132 | + char digest_buf[32]; |
| 133 | + int err; |
| 134 | + |
| 135 | + nrf_modem_at_scanf_fake.custom_fake = nrf_modem_at_scanf_test_invalid_digest; |
| 136 | + |
| 137 | + err = modem_key_mgmt_digest(16842753, MODEM_KEY_MGMT_CRED_TYPE_PUBLIC_CERT, |
| 138 | + digest_buf, sizeof(digest_buf)); |
| 139 | + zassert_equal(err, -EINVAL); |
| 140 | +} |
| 141 | + |
| 142 | + |
| 143 | +ZTEST(suite_modem_key_mgmt, test_list_response_too_big) |
| 144 | +{ |
| 145 | + int err; |
| 146 | + |
| 147 | + nrf_modem_at_cmd_fake.return_val = -ENOBUFS; |
| 148 | + |
| 149 | + err = modem_key_mgmt_list(key_list_cb); |
| 150 | + zassert_equal(err, -ENOBUFS); |
| 151 | + |
| 152 | + zassert_equal(nrf_modem_at_cmd_fake.call_count, 1); |
| 153 | + zassert_equal(key_list_cb_fake.call_count, 0); |
| 154 | +} |
| 155 | + |
| 156 | +static int nrf_modem_at_cmd_test_list_empty(void *buf, size_t len, const char *cmd, va_list args) |
| 157 | +{ |
| 158 | + char formatted_cmd[20]; |
| 159 | + |
| 160 | + vsnprintk(formatted_cmd, sizeof(formatted_cmd), cmd, args); |
| 161 | + zassert_equal(0, strcmp("AT%CMNG=1", formatted_cmd)); |
| 162 | + |
| 163 | + zassert_true(len > strlen(test_data_empty_list)); |
| 164 | + strcpy(buf, test_data_empty_list); |
| 165 | + |
| 166 | + return 0; |
| 167 | +} |
| 168 | + |
| 169 | +ZTEST(suite_modem_key_mgmt, test_list_empty) |
| 170 | +{ |
| 171 | + int err; |
| 172 | + |
| 173 | + nrf_modem_at_cmd_fake.custom_fake = nrf_modem_at_cmd_test_list_empty; |
| 174 | + |
| 175 | + err = modem_key_mgmt_list(key_list_cb); |
| 176 | + zassert_ok(err); |
| 177 | + |
| 178 | + zassert_equal(nrf_modem_at_cmd_fake.call_count, 1); |
| 179 | + |
| 180 | + zassert_equal(key_list_cb_fake.call_count, 0); |
| 181 | +} |
| 182 | + |
| 183 | +static const char *test_data_list = |
| 184 | +"%CMNG: 42,0,\"2C43952EE9E000FF2ACC4E2ED0897C0A72AD5FA72C3D934E81741CBD54F05BD1\"\r\n" |
| 185 | +"%CMNG: 1001,0,\"39FDCF28AEFFE08D03251FCCAF645E3C5DE19FA4EBBAFC89B4EDE2A422148BAB\"\r\n" |
| 186 | +"%CMNG: 16842753,0,\"2C43952EE9E000FF2ACC4E2ED0897C0A72AD5FA72C3D934E81741CBD54F05BD1\"\r\n" |
| 187 | +"%CMNG: 16842753,1,\"B9BAC15641653CAE2B5151DCBD0C40DDCDF19125950FA2475977437EA35F7A45\"\r\n" |
| 188 | +"%CMNG: 16842753,2,\"3EB33ABEB054A64578ED0ACF2BC13D570557FDEB413566D3D4678A2B89F65695\"\r\n" |
| 189 | +"%CMNG: 4294967293,10,\"2C43952EE9E000FF2ACC4E2ED0897C0A72AD5FA72C3D934E81741CBD54F05BD1\"\r\n" |
| 190 | +"%CMNG: 4294967294,6,\"A3CC4121A62D4BB103AE92F70A77A456886AE3CD5B2D156A200A1B90D9E92E05\"\r\n" |
| 191 | +"%CMNG: 4294967292,11,\"2027C4699EAA90A414D33FA81B975C0FDEDEFB04A19CEA1ED43A8876CAD31E89\"\r\n" |
| 192 | +"OK\r\n"; |
| 193 | + |
| 194 | +static int nrf_modem_at_cmd_test_list(void *buf, size_t len, const char *cmd, va_list args) |
| 195 | +{ |
| 196 | + char formatted_cmd[20]; |
| 197 | + |
| 198 | + vsnprintk(formatted_cmd, sizeof(formatted_cmd), cmd, args); |
| 199 | + zassert_equal(0, strcmp("AT%CMNG=1", formatted_cmd)); |
| 200 | + |
| 201 | + zassert_true(len > strlen(test_data_list)); |
| 202 | + strcpy(buf, test_data_list); |
| 203 | + |
| 204 | + return 0; |
| 205 | +} |
| 206 | + |
| 207 | +ZTEST(suite_modem_key_mgmt, test_list_multiple_entries) |
| 208 | +{ |
| 209 | + int err; |
| 210 | + |
| 211 | + nrf_modem_at_cmd_fake.custom_fake = nrf_modem_at_cmd_test_list; |
| 212 | + |
| 213 | + err = modem_key_mgmt_list(key_list_cb); |
| 214 | + zassert_ok(err); |
| 215 | + |
| 216 | + zassert_equal(nrf_modem_at_cmd_fake.call_count, 1); |
| 217 | + |
| 218 | + zassert_equal(key_list_cb_fake.call_count, 5); |
| 219 | + |
| 220 | + zassert_equal(key_list_cb_fake.arg0_history[0], 42); |
| 221 | + zassert_equal(key_list_cb_fake.arg1_history[0], MODEM_KEY_MGMT_CRED_TYPE_CA_CHAIN); |
| 222 | + |
| 223 | + zassert_equal(key_list_cb_fake.arg0_history[1], 1001); |
| 224 | + zassert_equal(key_list_cb_fake.arg1_history[1], MODEM_KEY_MGMT_CRED_TYPE_CA_CHAIN); |
| 225 | + |
| 226 | + zassert_equal(key_list_cb_fake.arg0_history[2], 16842753); |
| 227 | + zassert_equal(key_list_cb_fake.arg1_history[2], MODEM_KEY_MGMT_CRED_TYPE_CA_CHAIN); |
| 228 | + |
| 229 | + zassert_equal(key_list_cb_fake.arg0_history[3], 16842753); |
| 230 | + zassert_equal(key_list_cb_fake.arg1_history[3], MODEM_KEY_MGMT_CRED_TYPE_PUBLIC_CERT); |
| 231 | + |
| 232 | + zassert_equal(key_list_cb_fake.arg0_history[4], 16842753); |
| 233 | + zassert_equal(key_list_cb_fake.arg1_history[4], MODEM_KEY_MGMT_CRED_TYPE_PRIVATE_CERT); |
| 234 | +} |
| 235 | + |
| 236 | +static void _test_setup(void *fixture) |
| 237 | +{ |
| 238 | + RESET_FAKE(nrf_modem_at_printf); |
| 239 | + RESET_FAKE(nrf_modem_at_scanf); |
| 240 | + RESET_FAKE(nrf_modem_at_cmd); |
| 241 | + RESET_FAKE(key_list_cb); |
| 242 | +} |
| 243 | + |
| 244 | +ZTEST_SUITE(suite_modem_key_mgmt, NULL, NULL, _test_setup, NULL, NULL); |
0 commit comments