xref: /spdk/test/unit/lib/keyring/keyring.c/keyring_ut.c (revision 4b88d7425fd0a9eaaba6485e48fb8c24819c9f65)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright (c) 2024 Intel Corporation.  All rights reserved.
3  */
4 #include "spdk_internal/cunit.h"
5 #include "spdk_internal/mock.h"
6 #include "spdk/util.h"
7 
8 #include "keyring/keyring.c"
9 
10 #include "unit/lib/json_mock.c"
11 
12 struct ut_key {
13 #define UT_KEY_SIZE 64
14 	char buf[UT_KEY_SIZE];
15 	int len;
16 };
17 
18 struct ut_key_opts {
19 	char *buf;
20 	int len;
21 };
22 
23 static int g_add_status;
24 
25 static int
26 ut_keyring_add_key(struct spdk_key *key, void *ctx)
27 {
28 	struct ut_key_opts *opts = ctx;
29 	struct ut_key *utkey = spdk_key_get_ctx(key);
30 
31 	if (g_add_status) {
32 		return g_add_status;
33 	}
34 
35 	SPDK_CU_ASSERT_FATAL(opts != NULL);
36 
37 	/* Use spdk_json_val's start/len to pass a buffer with the key */
38 	memcpy(utkey->buf, opts->buf, opts->len);
39 	utkey->len = opts->len;
40 
41 	return 0;
42 }
43 
44 static bool g_remove_called;
45 
46 static void
47 ut_keyring_remove_key(struct spdk_key *key)
48 {
49 	struct ut_key *utkey = spdk_key_get_ctx(key);
50 
51 	memset(utkey->buf, 0, utkey->len);
52 	g_remove_called = true;
53 }
54 
55 static int
56 ut_keyring_get_key(struct spdk_key *key, void *buf, int len)
57 {
58 	struct ut_key *utkey = spdk_key_get_ctx(key);
59 
60 	memcpy(buf, utkey->buf, utkey->len);
61 
62 	return utkey->len;
63 }
64 
65 static size_t
66 ut_keyring_get_ctx_size(void)
67 {
68 	return sizeof(struct ut_key);
69 }
70 
71 static struct spdk_keyring_module g_module = {
72 	.name = "ut",
73 	.add_key = ut_keyring_add_key,
74 	.remove_key = ut_keyring_remove_key,
75 	.get_key = ut_keyring_get_key,
76 	.get_ctx_size = ut_keyring_get_ctx_size,
77 };
78 
79 SPDK_KEYRING_REGISTER_MODULE(ut, &g_module);
80 
81 static void
82 test_keyring_add_remove(void)
83 {
84 	struct spdk_key_opts opts = {};
85 	struct spdk_key *key;
86 	char keybuf[UT_KEY_SIZE] = {}, rcvbuf[UT_KEY_SIZE] = {};
87 	struct ut_key_opts uopts = { .buf = keybuf, .len = UT_KEY_SIZE };
88 	struct spdk_keyring_module module2 = { .name = "ut2" };
89 	int rc;
90 
91 	/* Add a key */
92 	memset(keybuf, 0xa5, UT_KEY_SIZE);
93 	opts.size = SPDK_SIZEOF(&opts, ctx);
94 	opts.name = "key0";
95 	opts.module = &g_module;
96 	opts.ctx = &uopts;
97 	rc = spdk_keyring_add_key(&opts);
98 	CU_ASSERT_EQUAL(rc, 0);
99 
100 	/* Get a reference to that key */
101 	key = spdk_keyring_get_key("key0");
102 	CU_ASSERT_PTR_NOT_NULL(key);
103 
104 	/* Get its keying material */
105 	rc = spdk_key_get_key(key, rcvbuf, UT_KEY_SIZE);
106 	CU_ASSERT_EQUAL(rc, UT_KEY_SIZE)
107 	CU_ASSERT_EQUAL(memcmp(rcvbuf, keybuf, UT_KEY_SIZE), 0);
108 
109 	/* Remove it and try to get another reference */
110 	spdk_keyring_remove_key("key0", &g_module);
111 	CU_ASSERT_PTR_NULL(spdk_keyring_get_key("key0"));
112 
113 	/* Now that the key has been remove spdk_key_get_key() should result in an -ENOKEY error */
114 	rc = spdk_key_get_key(key, rcvbuf, UT_KEY_SIZE);
115 	CU_ASSERT_EQUAL(rc, -ENOKEY);
116 
117 	/* Finally, release the reference */
118 	spdk_keyring_put_key(key);
119 
120 	/* Explicitly specify global keyring */
121 	rc = spdk_keyring_add_key(&opts);
122 	CU_ASSERT_EQUAL(rc, 0);
123 	key = spdk_keyring_get_key(":key0");
124 	CU_ASSERT_PTR_NOT_NULL(key);
125 
126 	memset(rcvbuf, 0, UT_KEY_SIZE);
127 	rc = spdk_key_get_key(key, rcvbuf, UT_KEY_SIZE);
128 	CU_ASSERT_EQUAL(rc, UT_KEY_SIZE)
129 	CU_ASSERT_EQUAL(memcmp(rcvbuf, keybuf, UT_KEY_SIZE), 0);
130 
131 	spdk_keyring_put_key(key);
132 
133 	/* Remove the key without explicitly specifying global keyring */
134 	spdk_keyring_remove_key("key0", &g_module);
135 	CU_ASSERT_PTR_NULL(spdk_keyring_get_key("key0"));
136 	CU_ASSERT_PTR_NULL(spdk_keyring_get_key(":key0"));
137 
138 	/* Try to create a key with the same name twice */
139 	opts.size = SPDK_SIZEOF(&opts, ctx);
140 	opts.name = "key0";
141 	opts.module = &g_module;
142 	opts.ctx = &uopts;
143 	rc = spdk_keyring_add_key(&opts);
144 	CU_ASSERT_EQUAL(rc, 0);
145 	rc = spdk_keyring_add_key(&opts);
146 	CU_ASSERT_EQUAL(rc, -EEXIST);
147 
148 	/* Explicitly specify global keyring */
149 	opts.name = ":key0";
150 	rc = spdk_keyring_add_key(&opts);
151 	CU_ASSERT_EQUAL(rc, -EEXIST);
152 
153 	/* Try to remove a key owned by a different module */
154 	spdk_keyring_remove_key("key0", &module2);
155 	CU_ASSERT_PTR_NOT_NULL(spdk_keyring_get_key("key0"));
156 	CU_ASSERT_PTR_NOT_NULL(spdk_keyring_get_key(":key0"));
157 
158 	spdk_keyring_remove_key(":key0", &g_module);
159 	CU_ASSERT_PTR_NULL(spdk_keyring_get_key("key0"));
160 	CU_ASSERT_PTR_NULL(spdk_keyring_get_key(":key0"));
161 	CU_ASSERT(g_remove_called);
162 	g_remove_called = false;
163 
164 	/* Remove an already removed key */
165 	spdk_keyring_remove_key("key0", &g_module);
166 	spdk_keyring_remove_key(":key0", &g_module);
167 	CU_ASSERT(!g_remove_called);
168 
169 	/* Check that an error from module's add_key() results in failure */
170 	g_add_status = -EIO;
171 	opts.size = SPDK_SIZEOF(&opts, ctx);
172 	opts.name = "key0";
173 	opts.module = &g_module;
174 	opts.ctx = &uopts;
175 	rc = spdk_keyring_add_key(&opts);
176 	CU_ASSERT_EQUAL(rc, -EIO);
177 	CU_ASSERT_PTR_NULL(spdk_keyring_get_key("key0"));
178 	g_add_status = 0;
179 }
180 
181 static void
182 test_keyring_get_put(void)
183 {
184 	struct spdk_key_opts opts = {};
185 	struct spdk_key *key, *tmp;
186 	char keybuf[UT_KEY_SIZE] = {};
187 	struct ut_key_opts uopts = { .buf = keybuf, .len = UT_KEY_SIZE };
188 	int rc, i;
189 
190 	opts.size = SPDK_SIZEOF(&opts, ctx);
191 	opts.name = "key0";
192 	opts.module = &g_module;
193 	opts.ctx = &uopts;
194 	rc = spdk_keyring_add_key(&opts);
195 	CU_ASSERT_EQUAL(rc, 0);
196 
197 	/* Get multiple references to the same key */
198 	key = spdk_keyring_get_key("key0");
199 	CU_ASSERT_PTR_NOT_NULL(key);
200 #define UT_KEY_REFS 8
201 	for (i = 0; i < UT_KEY_REFS; ++i) {
202 		tmp = spdk_keyring_get_key("key0");
203 		CU_ASSERT_PTR_EQUAL(key, tmp);
204 	}
205 
206 	/* Remove the key and verify (relying on the address sanitizer to catch any use-after-free
207 	 * errors) that the reference is still valid
208 	 */
209 	spdk_keyring_remove_key("key0", &g_module);
210 	CU_ASSERT_EQUAL(strcmp(spdk_key_get_name(key), "key0"), 0);
211 
212 	/* Release all but one reference and verify that it's still valid (again, relying on the
213 	 * address sanitizer)
214 	 */
215 	for (i = 0; i < UT_KEY_REFS; ++i) {
216 		spdk_keyring_put_key(key);
217 		CU_ASSERT_EQUAL(strcmp(spdk_key_get_name(key), "key0"), 0);
218 	}
219 
220 	/* Release the last reference - this should also free the key */
221 	spdk_keyring_put_key(key);
222 }
223 
224 int
225 main(int argc, char **argv)
226 {
227 	CU_pSuite suite;
228 	unsigned int num_failures;
229 
230 	CU_initialize_registry();
231 
232 	suite = CU_add_suite("keyring", NULL, NULL);
233 	CU_ADD_TEST(suite, test_keyring_add_remove);
234 	CU_ADD_TEST(suite, test_keyring_get_put);
235 
236 	num_failures = spdk_ut_run_tests(argc, argv, NULL);
237 	CU_cleanup_registry();
238 
239 	return num_failures;
240 }
241