1 /* $OpenBSD: exdata_test.c,v 1.3 2024/10/02 14:12:21 jsing Exp $ */
2 /*
3  * Copyright (c) 2023 Joel Sing <jsing@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <stdio.h>
19 #include <string.h>
20 
21 #include <openssl/crypto.h>
22 
23 static int ex_new_calls;
24 static int ex_free_calls;
25 static int ex_dup_calls;
26 
27 static int
ex_new(void * parent,void * ptr,CRYPTO_EX_DATA * ad,int idx,long argl,void * argp)28 ex_new(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx, long argl,
29     void *argp)
30 {
31 	long *arg = argp;
32 
33 	if (ptr != NULL) {
34 		fprintf(stderr, "FAIL: ex_new() called with ptr != NULL\n");
35 		return 0;
36 	}
37 	if (argl != 1234 || *arg != 1234) {
38 		fprintf(stderr, "FAIL: ex_new() with bad arguments\n");
39 		return 0;
40 	}
41 
42 	ex_new_calls++;
43 
44 	return 1;
45 }
46 
47 static int
ex_dup(CRYPTO_EX_DATA * to,CRYPTO_EX_DATA * from,void * from_d,int idx,long argl,void * argp)48 ex_dup(CRYPTO_EX_DATA *to, CRYPTO_EX_DATA *from, void *from_d,
49     int idx, long argl, void *argp)
50 {
51 	long *arg = argp;
52 
53 	if (argl != 1234 || *arg != 1234) {
54 		fprintf(stderr, "FAIL: ex_dup() with bad arguments\n");
55 		return 0;
56 	}
57 
58 	ex_dup_calls++;
59 
60 	return 1;
61 }
62 
63 static void
ex_free(void * parent,void * ptr,CRYPTO_EX_DATA * ad,int idx,long argl,void * argp)64 ex_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx,
65     long argl, void *argp)
66 {
67 	long *arg = argp;
68 
69 	if (argl != 1234 || *arg != 1234) {
70 		fprintf(stderr, "FAIL: ex_free() with bad arguments\n");
71 		return;
72 	}
73 
74 	ex_free_calls++;
75 }
76 
77 struct exdata {
78 	CRYPTO_EX_DATA exdata;
79 	int val;
80 };
81 
82 static int
ex_data_test(void)83 ex_data_test(void)
84 {
85 	struct exdata exdata1, exdata2, exdata3, exdata4;
86 	void *argp;
87 	long argl;
88 	int idx1, idx2;
89 	int failed = 1;
90 
91 	memset(&exdata1, 0, sizeof(exdata1));
92 	memset(&exdata2, 0, sizeof(exdata2));
93 	memset(&exdata3, 0, sizeof(exdata3));
94 	memset(&exdata4, 0, sizeof(exdata4));
95 
96 	argl = 1234;
97 	argp = &argl;
98 
99 	if ((idx1 = CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_RSA, argl, argp,
100 	    ex_new, ex_dup, ex_free)) < 0) {
101 		fprintf(stderr, "FAIL: CRYPTO_get_ex_new_index failed\n");
102 		goto failure;
103 	}
104 	if (idx1 == 0) {
105 		fprintf(stderr, "FAIL: CRYPTO_get_ex_new_index() returned 0 "
106 		    "(reserved for internal use)\n");
107 		goto failure;
108 	}
109 
110 	if ((idx2 = CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_RSA, 0, NULL,
111 	    NULL, NULL, NULL)) < 0) {
112 		fprintf(stderr, "FAIL: CRYPTO_get_ex_new_index failed\n");
113 		goto failure;
114 	}
115 	if (idx1 == idx2) {
116 		fprintf(stderr, "FAIL: CRYPTO_get_ex_new_index() returned the "
117 		    "same value\n");
118 		goto failure;
119 	}
120 	if (idx2 < idx1) {
121 		fprintf(stderr, "FAIL: CRYPTO_get_ex_new_index() returned "
122 		    "idx2 < idx1\n");
123 		goto failure;
124 	}
125 
126 	if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_RSA, &exdata1, &exdata1.exdata)) {
127 		fprintf(stderr, "FAIL: CRYPTO_new_ex_data() failed\n");
128 		goto failure;
129 	}
130 
131 	if (!CRYPTO_set_ex_data(&exdata1.exdata, idx2, &idx2)) {
132 		fprintf(stderr, "FAIL: CRYPTO_set_ex_data() failed with index 2\n");
133 		goto failure;
134 	}
135 	if (!CRYPTO_set_ex_data(&exdata1.exdata, idx1, &idx1)) {
136 		fprintf(stderr, "FAIL: CRYPTO_set_ex_data() failed with index 1\n");
137 		goto failure;
138 	}
139 	if (CRYPTO_get_ex_data(&exdata1.exdata, idx1) != &idx1) {
140 		fprintf(stderr, "FAIL: CRYPTO_get_ex_data() failed with index 1\n");
141 		goto failure;
142 	}
143 	if (CRYPTO_get_ex_data(&exdata1.exdata, idx2) != &idx2) {
144 		fprintf(stderr, "FAIL: CRYPTO_get_ex_data() failed with index 2\n");
145 		goto failure;
146 	}
147 
148 	if (!CRYPTO_dup_ex_data(CRYPTO_EX_INDEX_RSA, &exdata2.exdata,
149 	    &exdata1.exdata)) {
150 		fprintf(stderr, "FAIL: CRYPTO_dup_ex_data() failed\n");
151 		goto failure;
152 	}
153 	if (CRYPTO_get_ex_data(&exdata2.exdata, idx1) != &idx1) {
154 		fprintf(stderr, "FAIL: CRYPTO_get_ex_data() failed after dup\n");
155 		goto failure;
156 	}
157 	if (CRYPTO_get_ex_data(&exdata2.exdata, idx2) != &idx2) {
158 		fprintf(stderr, "FAIL: CRYPTO_get_ex_data() failed after dup\n");
159 		goto failure;
160 	}
161 
162 	CRYPTO_free_ex_data(CRYPTO_EX_INDEX_RSA, &exdata1, &exdata1.exdata);
163 	CRYPTO_free_ex_data(CRYPTO_EX_INDEX_RSA, &exdata2, &exdata2.exdata);
164 
165 	if (ex_new_calls != 1) {
166 		fprintf(stderr, "FAIL: got %d ex_new calls, want %d\n",
167 		    ex_new_calls, 1);
168 		goto failure;
169 	}
170 	if (ex_dup_calls != 1) {
171 		fprintf(stderr, "FAIL: got %d ex_dup calls, want %d\n",
172 		    ex_dup_calls, 1);
173 		goto failure;
174 	}
175 	if (ex_free_calls != 2) {
176 		fprintf(stderr, "FAIL: got %d ex_free calls, want %d\n",
177 		    ex_free_calls, 2);
178 		goto failure;
179 	}
180 
181 	/* The current implementation allows for data to be set without new. */
182 	if (!CRYPTO_set_ex_data(&exdata3.exdata, idx1, &idx1)) {
183 		fprintf(stderr, "FAIL: CRYPTO_set_ex_data() failed with index "
184 		    "1 (without new)\n");
185 		goto failure;
186 	}
187 	if (CRYPTO_get_ex_data(&exdata3.exdata, idx1) != &idx1) {
188 		fprintf(stderr, "FAIL: CRYPTO_get_ex_data() failed with index "
189 		    "1 (without new)\n");
190 		goto failure;
191 	}
192 
193 	/* And indexes can be used without allocation. */
194 	if (!CRYPTO_set_ex_data(&exdata3.exdata, idx2 + 1, &idx2)) {
195 		fprintf(stderr, "FAIL: CRYPTO_set_ex_data() failed with index "
196 		    "%d (unallocated)\n", idx2 + 1);
197 		goto failure;
198 	}
199 	if (CRYPTO_get_ex_data(&exdata3.exdata, idx2 + 1) != &idx2) {
200 		fprintf(stderr, "FAIL: CRYPTO_get_ex_data() failed with index "
201 		    "%d\n", idx2 + 1);
202 		goto failure;
203 	}
204 
205 	/* And new can be called without getting any index first. */
206 	if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_BIO, &exdata4, &exdata4.exdata)) {
207 		fprintf(stderr, "FAIL: CRYPTO_new_ex_data() failed with "
208 		    "uninitialised index\n");
209 		goto failure;
210 	}
211 
212 	/* And dup can be called after new or without new... */
213 	if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_RSA, &exdata1, &exdata1.exdata)) {
214 		fprintf(stderr, "FAIL: CRYPTO_new_ex_data() failed\n");
215 		goto failure;
216 	}
217 	if (!CRYPTO_dup_ex_data(CRYPTO_EX_INDEX_RSA, &exdata2.exdata,
218 	    &exdata1.exdata)) {
219 		fprintf(stderr, "FAIL: CRYPTO_dup_ex_data() after new failed\n");
220 		goto failure;
221 	}
222 
223 	failed = 0;
224 
225  failure:
226 	CRYPTO_free_ex_data(CRYPTO_EX_INDEX_RSA, &exdata1, &exdata1.exdata);
227 	CRYPTO_free_ex_data(CRYPTO_EX_INDEX_RSA, &exdata2, &exdata2.exdata);
228 	CRYPTO_free_ex_data(CRYPTO_EX_INDEX_RSA, &exdata3, &exdata3.exdata);
229 	CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, &exdata4, &exdata4.exdata);
230 
231 	return failed;
232 }
233 
234 static int
ex_new_index_test(void)235 ex_new_index_test(void)
236 {
237 	int failed = 1;
238 	int idx;
239 
240 	if ((idx = CRYPTO_get_ex_new_index(-1, 0, NULL, NULL, NULL,
241 	    NULL)) > 0) {
242 		fprintf(stderr, "FAIL: CRYPTO_get_ex_new_index() succeeded with "
243 		    "negative class\n");
244 		goto failure;
245 	}
246 	if ((idx = CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX__COUNT, 0,
247 	    NULL, NULL, NULL, NULL)) > 0) {
248 		fprintf(stderr, "FAIL: CRYPTO_get_ex_new_index() succeeded with "
249 		    "class exceeding maximum\n");
250 		goto failure;
251 	}
252 
253 	failed = 0;
254 
255  failure:
256 	return failed;
257 }
258 
259 int
main(int argc,char ** argv)260 main(int argc, char **argv)
261 {
262 	int failed = 0;
263 
264 	failed |= ex_data_test();
265 	failed |= ex_new_index_test();
266 
267 	/* Force a clean up. */
268 	CRYPTO_cleanup_all_ex_data();
269 
270 	return failed;
271 }
272