xref: /spdk/test/unit/lib/keyring/keyring.c/keyring_ut.c (revision c6c1234de9e0015e670dd0b51bf6ce39ee0e07bd)
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 	int rc;
89 
90 	/* Add a key */
91 	memset(keybuf, 0xa5, UT_KEY_SIZE);
92 	opts.size = SPDK_SIZEOF(&opts, ctx);
93 	opts.name = "key0";
94 	opts.module = &g_module;
95 	opts.ctx = &uopts;
96 	rc = spdk_keyring_add_key(&opts);
97 	CU_ASSERT_EQUAL(rc, 0);
98 
99 	/* Get a reference to that key */
100 	key = spdk_keyring_get_key("key0");
101 	CU_ASSERT_PTR_NOT_NULL(key);
102 
103 	/* Get its keying material */
104 	rc = spdk_key_get_key(key, rcvbuf, UT_KEY_SIZE);
105 	CU_ASSERT_EQUAL(rc, UT_KEY_SIZE)
106 	CU_ASSERT_EQUAL(memcmp(rcvbuf, keybuf, UT_KEY_SIZE), 0);
107 
108 	/* Remove it and try to get another reference */
109 	spdk_keyring_remove_key("key0");
110 	CU_ASSERT_PTR_NULL(spdk_keyring_get_key("key0"));
111 
112 	/* Now that the key has been remove spdk_key_get_key() should result in an -ENOKEY error */
113 	rc = spdk_key_get_key(key, rcvbuf, UT_KEY_SIZE);
114 	CU_ASSERT_EQUAL(rc, -ENOKEY);
115 
116 	/* Finally, release the reference */
117 	spdk_keyring_put_key(key);
118 
119 	/* Explicitly specify global keyring */
120 	rc = spdk_keyring_add_key(&opts);
121 	CU_ASSERT_EQUAL(rc, 0);
122 	key = spdk_keyring_get_key(":key0");
123 	CU_ASSERT_PTR_NOT_NULL(key);
124 
125 	memset(rcvbuf, 0, UT_KEY_SIZE);
126 	rc = spdk_key_get_key(key, rcvbuf, UT_KEY_SIZE);
127 	CU_ASSERT_EQUAL(rc, UT_KEY_SIZE)
128 	CU_ASSERT_EQUAL(memcmp(rcvbuf, keybuf, UT_KEY_SIZE), 0);
129 
130 	spdk_keyring_put_key(key);
131 
132 	/* Remove the key without explicitly specifying global keyring */
133 	spdk_keyring_remove_key("key0");
134 	CU_ASSERT_PTR_NULL(spdk_keyring_get_key("key0"));
135 	CU_ASSERT_PTR_NULL(spdk_keyring_get_key(":key0"));
136 
137 	/* Try to create a key with the same name twice */
138 	opts.size = SPDK_SIZEOF(&opts, ctx);
139 	opts.name = "key0";
140 	opts.module = &g_module;
141 	opts.ctx = &uopts;
142 	rc = spdk_keyring_add_key(&opts);
143 	CU_ASSERT_EQUAL(rc, 0);
144 	rc = spdk_keyring_add_key(&opts);
145 	CU_ASSERT_EQUAL(rc, -EEXIST);
146 
147 	/* Explicitly specify global keyring */
148 	opts.name = ":key0";
149 	rc = spdk_keyring_add_key(&opts);
150 	CU_ASSERT_EQUAL(rc, -EEXIST);
151 
152 	spdk_keyring_remove_key(":key0");
153 	CU_ASSERT_PTR_NULL(spdk_keyring_get_key("key0"));
154 	CU_ASSERT_PTR_NULL(spdk_keyring_get_key(":key0"));
155 	CU_ASSERT(g_remove_called);
156 	g_remove_called = false;
157 
158 	/* Remove an already removed key */
159 	spdk_keyring_remove_key("key0");
160 	spdk_keyring_remove_key(":key0");
161 	CU_ASSERT(!g_remove_called);
162 
163 	/* Check that an error from module's add_key() results in failure */
164 	g_add_status = -EIO;
165 	opts.size = SPDK_SIZEOF(&opts, ctx);
166 	opts.name = "key0";
167 	opts.module = &g_module;
168 	opts.ctx = &uopts;
169 	rc = spdk_keyring_add_key(&opts);
170 	CU_ASSERT_EQUAL(rc, -EIO);
171 	CU_ASSERT_PTR_NULL(spdk_keyring_get_key("key0"));
172 	g_add_status = 0;
173 }
174 
175 static void
176 test_keyring_get_put(void)
177 {
178 	struct spdk_key_opts opts = {};
179 	struct spdk_key *key, *tmp;
180 	char keybuf[UT_KEY_SIZE] = {};
181 	struct ut_key_opts uopts = { .buf = keybuf, .len = UT_KEY_SIZE };
182 	int rc, i;
183 
184 	opts.size = SPDK_SIZEOF(&opts, ctx);
185 	opts.name = "key0";
186 	opts.module = &g_module;
187 	opts.ctx = &uopts;
188 	rc = spdk_keyring_add_key(&opts);
189 	CU_ASSERT_EQUAL(rc, 0);
190 
191 	/* Get multiple references to the same key */
192 	key = spdk_keyring_get_key("key0");
193 	CU_ASSERT_PTR_NOT_NULL(key);
194 #define UT_KEY_REFS 8
195 	for (i = 0; i < UT_KEY_REFS; ++i) {
196 		tmp = spdk_keyring_get_key("key0");
197 		CU_ASSERT_PTR_EQUAL(key, tmp);
198 	}
199 
200 	/* Remove the key and verify (relying on the address sanitizer to catch any use-after-free
201 	 * errors) that the reference is still valid
202 	 */
203 	spdk_keyring_remove_key("key0");
204 	CU_ASSERT_EQUAL(strcmp(spdk_key_get_name(key), "key0"), 0);
205 
206 	/* Release all but one reference and verify that it's still valid (again, relying on the
207 	 * address sanitizer)
208 	 */
209 	for (i = 0; i < UT_KEY_REFS; ++i) {
210 		spdk_keyring_put_key(key);
211 		CU_ASSERT_EQUAL(strcmp(spdk_key_get_name(key), "key0"), 0);
212 	}
213 
214 	/* Release the last reference - this should also free the key */
215 	spdk_keyring_put_key(key);
216 }
217 
218 int
219 main(int argc, char **argv)
220 {
221 	CU_pSuite suite;
222 	unsigned int num_failures;
223 
224 	CU_initialize_registry();
225 
226 	suite = CU_add_suite("keyring", NULL, NULL);
227 	CU_ADD_TEST(suite, test_keyring_add_remove);
228 	CU_ADD_TEST(suite, test_keyring_get_put);
229 
230 	num_failures = spdk_ut_run_tests(argc, argv, NULL);
231 	CU_cleanup_registry();
232 
233 	return num_failures;
234 }
235