1 /*
2  * Copyright 2015-2022 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License 2.0 (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9 
10 #ifdef _WIN32
11 # include <windows.h>
12 #endif
13 
14 #include <stdio.h>
15 #include <string.h>
16 #include <openssl/async.h>
17 #include <openssl/crypto.h>
18 
19 static int ctr = 0;
20 static ASYNC_JOB *currjob = NULL;
21 
only_pause(void * args)22 static int only_pause(void *args)
23 {
24     ASYNC_pause_job();
25 
26     return 1;
27 }
28 
add_two(void * args)29 static int add_two(void *args)
30 {
31     ctr++;
32     ASYNC_pause_job();
33     ctr++;
34 
35     return 2;
36 }
37 
save_current(void * args)38 static int save_current(void *args)
39 {
40     currjob = ASYNC_get_current_job();
41     ASYNC_pause_job();
42 
43     return 1;
44 }
45 
change_deflt_libctx(void * args)46 static int change_deflt_libctx(void *args)
47 {
48     OSSL_LIB_CTX *libctx = OSSL_LIB_CTX_new();
49     OSSL_LIB_CTX *oldctx, *tmpctx;
50     int ret = 0;
51 
52     if (libctx == NULL)
53         return 0;
54 
55     oldctx = OSSL_LIB_CTX_set0_default(libctx);
56     ASYNC_pause_job();
57 
58     /* Check the libctx is set up as we expect */
59     tmpctx = OSSL_LIB_CTX_set0_default(oldctx);
60     if (tmpctx != libctx)
61         goto err;
62 
63     /* Set it back again to continue to use our own libctx */
64     oldctx = OSSL_LIB_CTX_set0_default(libctx);
65     ASYNC_pause_job();
66 
67     /* Check the libctx is set up as we expect */
68     tmpctx = OSSL_LIB_CTX_set0_default(oldctx);
69     if (tmpctx != libctx)
70         goto err;
71 
72     ret = 1;
73  err:
74     OSSL_LIB_CTX_free(libctx);
75     return ret;
76 }
77 
78 
79 #define MAGIC_WAIT_FD   ((OSSL_ASYNC_FD)99)
waitfd(void * args)80 static int waitfd(void *args)
81 {
82     ASYNC_JOB *job;
83     ASYNC_WAIT_CTX *waitctx;
84     job = ASYNC_get_current_job();
85     if (job == NULL)
86         return 0;
87     waitctx = ASYNC_get_wait_ctx(job);
88     if (waitctx == NULL)
89         return 0;
90 
91     /* First case: no fd added or removed */
92     ASYNC_pause_job();
93 
94     /* Second case: one fd added */
95     if (!ASYNC_WAIT_CTX_set_wait_fd(waitctx, waitctx, MAGIC_WAIT_FD, NULL, NULL))
96         return 0;
97     ASYNC_pause_job();
98 
99     /* Third case: all fd removed */
100     if (!ASYNC_WAIT_CTX_clear_fd(waitctx, waitctx))
101         return 0;
102     ASYNC_pause_job();
103 
104     /* Last case: fd added and immediately removed */
105     if (!ASYNC_WAIT_CTX_set_wait_fd(waitctx, waitctx, MAGIC_WAIT_FD, NULL, NULL))
106         return 0;
107     if (!ASYNC_WAIT_CTX_clear_fd(waitctx, waitctx))
108         return 0;
109 
110     return 1;
111 }
112 
blockpause(void * args)113 static int blockpause(void *args)
114 {
115     ASYNC_block_pause();
116     ASYNC_pause_job();
117     ASYNC_unblock_pause();
118     ASYNC_pause_job();
119 
120     return 1;
121 }
122 
test_ASYNC_init_thread(void)123 static int test_ASYNC_init_thread(void)
124 {
125     ASYNC_JOB *job1 = NULL, *job2 = NULL, *job3 = NULL;
126     int funcret1, funcret2, funcret3;
127     ASYNC_WAIT_CTX *waitctx = NULL;
128 
129     if (       !ASYNC_init_thread(2, 0)
130             || (waitctx = ASYNC_WAIT_CTX_new()) == NULL
131             || ASYNC_start_job(&job1, waitctx, &funcret1, only_pause, NULL, 0)
132                 != ASYNC_PAUSE
133             || ASYNC_start_job(&job2, waitctx, &funcret2, only_pause, NULL, 0)
134                 != ASYNC_PAUSE
135             || ASYNC_start_job(&job3, waitctx, &funcret3, only_pause, NULL, 0)
136                 != ASYNC_NO_JOBS
137             || ASYNC_start_job(&job1, waitctx, &funcret1, only_pause, NULL, 0)
138                 != ASYNC_FINISH
139             || ASYNC_start_job(&job3, waitctx, &funcret3, only_pause, NULL, 0)
140                 != ASYNC_PAUSE
141             || ASYNC_start_job(&job2, waitctx, &funcret2, only_pause, NULL, 0)
142                 != ASYNC_FINISH
143             || ASYNC_start_job(&job3, waitctx, &funcret3, only_pause, NULL, 0)
144                 != ASYNC_FINISH
145             || funcret1 != 1
146             || funcret2 != 1
147             || funcret3 != 1) {
148         fprintf(stderr, "test_ASYNC_init_thread() failed\n");
149         ASYNC_WAIT_CTX_free(waitctx);
150         ASYNC_cleanup_thread();
151         return 0;
152     }
153 
154     ASYNC_WAIT_CTX_free(waitctx);
155     ASYNC_cleanup_thread();
156     return 1;
157 }
158 
test_callback(void * arg)159 static int test_callback(void *arg)
160 {
161     printf("callback test pass\n");
162     return 1;
163 }
164 
test_ASYNC_callback_status(void)165 static int test_ASYNC_callback_status(void)
166 {
167     ASYNC_WAIT_CTX *waitctx = NULL;
168     int set_arg = 100;
169     ASYNC_callback_fn get_callback;
170     void *get_arg;
171     int set_status = 1;
172 
173     if (       !ASYNC_init_thread(1, 0)
174             || (waitctx = ASYNC_WAIT_CTX_new()) == NULL
175             || ASYNC_WAIT_CTX_set_callback(waitctx, test_callback, (void*)&set_arg)
176                != 1
177             || ASYNC_WAIT_CTX_get_callback(waitctx, &get_callback, &get_arg)
178                != 1
179             || test_callback != get_callback
180             || get_arg != (void*)&set_arg
181             || (*get_callback)(get_arg) != 1
182             || ASYNC_WAIT_CTX_set_status(waitctx, set_status) != 1
183             || set_status != ASYNC_WAIT_CTX_get_status(waitctx)) {
184         fprintf(stderr, "test_ASYNC_callback_status() failed\n");
185         ASYNC_WAIT_CTX_free(waitctx);
186         ASYNC_cleanup_thread();
187         return 0;
188     }
189 
190     ASYNC_WAIT_CTX_free(waitctx);
191     ASYNC_cleanup_thread();
192     return 1;
193 
194 }
195 
test_ASYNC_start_job(void)196 static int test_ASYNC_start_job(void)
197 {
198     ASYNC_JOB *job = NULL;
199     int funcret;
200     ASYNC_WAIT_CTX *waitctx = NULL;
201 
202     ctr = 0;
203 
204     if (       !ASYNC_init_thread(1, 0)
205             || (waitctx = ASYNC_WAIT_CTX_new()) == NULL
206             || ASYNC_start_job(&job, waitctx, &funcret, add_two, NULL, 0)
207                != ASYNC_PAUSE
208             || ctr != 1
209             || ASYNC_start_job(&job, waitctx, &funcret, add_two, NULL, 0)
210                != ASYNC_FINISH
211             || ctr != 2
212             || funcret != 2) {
213         fprintf(stderr, "test_ASYNC_start_job() failed\n");
214         ASYNC_WAIT_CTX_free(waitctx);
215         ASYNC_cleanup_thread();
216         return 0;
217     }
218 
219     ASYNC_WAIT_CTX_free(waitctx);
220     ASYNC_cleanup_thread();
221     return 1;
222 }
223 
test_ASYNC_get_current_job(void)224 static int test_ASYNC_get_current_job(void)
225 {
226     ASYNC_JOB *job = NULL;
227     int funcret;
228     ASYNC_WAIT_CTX *waitctx = NULL;
229 
230     currjob = NULL;
231 
232     if (       !ASYNC_init_thread(1, 0)
233             || (waitctx = ASYNC_WAIT_CTX_new()) == NULL
234             || ASYNC_start_job(&job, waitctx, &funcret, save_current, NULL, 0)
235                 != ASYNC_PAUSE
236             || currjob != job
237             || ASYNC_start_job(&job, waitctx, &funcret, save_current, NULL, 0)
238                 != ASYNC_FINISH
239             || funcret != 1) {
240         fprintf(stderr, "test_ASYNC_get_current_job() failed\n");
241         ASYNC_WAIT_CTX_free(waitctx);
242         ASYNC_cleanup_thread();
243         return 0;
244     }
245 
246     ASYNC_WAIT_CTX_free(waitctx);
247     ASYNC_cleanup_thread();
248     return 1;
249 }
250 
test_ASYNC_WAIT_CTX_get_all_fds(void)251 static int test_ASYNC_WAIT_CTX_get_all_fds(void)
252 {
253     ASYNC_JOB *job = NULL;
254     int funcret;
255     ASYNC_WAIT_CTX *waitctx = NULL;
256     OSSL_ASYNC_FD fd = OSSL_BAD_ASYNC_FD, delfd = OSSL_BAD_ASYNC_FD;
257     size_t numfds, numdelfds;
258 
259     if (       !ASYNC_init_thread(1, 0)
260             || (waitctx = ASYNC_WAIT_CTX_new()) == NULL
261                /* On first run we're not expecting any wait fds */
262             || ASYNC_start_job(&job, waitctx, &funcret, waitfd, NULL, 0)
263                 != ASYNC_PAUSE
264             || !ASYNC_WAIT_CTX_get_all_fds(waitctx, NULL, &numfds)
265             || numfds != 0
266             || !ASYNC_WAIT_CTX_get_changed_fds(waitctx, NULL, &numfds, NULL,
267                                                &numdelfds)
268             || numfds != 0
269             || numdelfds != 0
270                /* On second run we're expecting one added fd */
271             || ASYNC_start_job(&job, waitctx, &funcret, waitfd, NULL, 0)
272                 != ASYNC_PAUSE
273             || !ASYNC_WAIT_CTX_get_all_fds(waitctx, NULL, &numfds)
274             || numfds != 1
275             || !ASYNC_WAIT_CTX_get_all_fds(waitctx, &fd, &numfds)
276             || fd != MAGIC_WAIT_FD
277             || (fd = OSSL_BAD_ASYNC_FD, 0) /* Assign to something else */
278             || !ASYNC_WAIT_CTX_get_changed_fds(waitctx, NULL, &numfds, NULL,
279                                                &numdelfds)
280             || numfds != 1
281             || numdelfds != 0
282             || !ASYNC_WAIT_CTX_get_changed_fds(waitctx, &fd, &numfds, NULL,
283                                                &numdelfds)
284             || fd != MAGIC_WAIT_FD
285                /* On third run we expect one deleted fd */
286             || ASYNC_start_job(&job, waitctx, &funcret, waitfd, NULL, 0)
287                 != ASYNC_PAUSE
288             || !ASYNC_WAIT_CTX_get_all_fds(waitctx, NULL, &numfds)
289             || numfds != 0
290             || !ASYNC_WAIT_CTX_get_changed_fds(waitctx, NULL, &numfds, NULL,
291                                                &numdelfds)
292             || numfds != 0
293             || numdelfds != 1
294             || !ASYNC_WAIT_CTX_get_changed_fds(waitctx, NULL, &numfds, &delfd,
295                                                &numdelfds)
296             || delfd != MAGIC_WAIT_FD
297             /* On last run we are not expecting any wait fd */
298             || ASYNC_start_job(&job, waitctx, &funcret, waitfd, NULL, 0)
299                 != ASYNC_FINISH
300             || !ASYNC_WAIT_CTX_get_all_fds(waitctx, NULL, &numfds)
301             || numfds != 0
302             || !ASYNC_WAIT_CTX_get_changed_fds(waitctx, NULL, &numfds, NULL,
303                                                &numdelfds)
304             || numfds != 0
305             || numdelfds != 0
306             || funcret != 1) {
307         fprintf(stderr, "test_ASYNC_get_wait_fd() failed\n");
308         ASYNC_WAIT_CTX_free(waitctx);
309         ASYNC_cleanup_thread();
310         return 0;
311     }
312 
313     ASYNC_WAIT_CTX_free(waitctx);
314     ASYNC_cleanup_thread();
315     return 1;
316 }
317 
test_ASYNC_block_pause(void)318 static int test_ASYNC_block_pause(void)
319 {
320     ASYNC_JOB *job = NULL;
321     int funcret;
322     ASYNC_WAIT_CTX *waitctx = NULL;
323 
324     if (       !ASYNC_init_thread(1, 0)
325             || (waitctx = ASYNC_WAIT_CTX_new()) == NULL
326             || ASYNC_start_job(&job, waitctx, &funcret, blockpause, NULL, 0)
327                 != ASYNC_PAUSE
328             || ASYNC_start_job(&job, waitctx, &funcret, blockpause, NULL, 0)
329                 != ASYNC_FINISH
330             || funcret != 1) {
331         fprintf(stderr, "test_ASYNC_block_pause() failed\n");
332         ASYNC_WAIT_CTX_free(waitctx);
333         ASYNC_cleanup_thread();
334         return 0;
335     }
336 
337     ASYNC_WAIT_CTX_free(waitctx);
338     ASYNC_cleanup_thread();
339     return 1;
340 }
341 
test_ASYNC_start_job_ex(void)342 static int test_ASYNC_start_job_ex(void)
343 {
344     ASYNC_JOB *job = NULL;
345     int funcret;
346     ASYNC_WAIT_CTX *waitctx = NULL;
347     OSSL_LIB_CTX *libctx = OSSL_LIB_CTX_new();
348     OSSL_LIB_CTX *oldctx, *tmpctx, *globalctx;
349     int ret = 0;
350 
351     if (libctx == NULL) {
352         fprintf(stderr,
353                 "test_ASYNC_start_job_ex() failed to create libctx\n");
354         goto err;
355     }
356 
357     globalctx = oldctx = OSSL_LIB_CTX_set0_default(libctx);
358 
359     if ((waitctx = ASYNC_WAIT_CTX_new()) == NULL
360             || ASYNC_start_job(&job, waitctx, &funcret, change_deflt_libctx,
361                                NULL, 0)
362                != ASYNC_PAUSE) {
363         fprintf(stderr,
364                 "test_ASYNC_start_job_ex() failed to start job\n");
365         goto err;
366     }
367 
368     /* Reset the libctx temporarily to find out what it is*/
369     tmpctx = OSSL_LIB_CTX_set0_default(oldctx);
370     oldctx = OSSL_LIB_CTX_set0_default(tmpctx);
371     if (tmpctx != libctx) {
372         fprintf(stderr,
373                 "test_ASYNC_start_job_ex() failed - unexpected libctx\n");
374         goto err;
375     }
376 
377     if (ASYNC_start_job(&job, waitctx, &funcret, change_deflt_libctx, NULL, 0)
378                != ASYNC_PAUSE) {
379         fprintf(stderr,
380                 "test_ASYNC_start_job_ex() - restarting job failed\n");
381         goto err;
382     }
383 
384     /* Reset the libctx and continue with the global default libctx */
385     tmpctx = OSSL_LIB_CTX_set0_default(oldctx);
386     if (tmpctx != libctx) {
387         fprintf(stderr,
388                 "test_ASYNC_start_job_ex() failed - unexpected libctx\n");
389         goto err;
390     }
391 
392     if (ASYNC_start_job(&job, waitctx, &funcret, change_deflt_libctx, NULL, 0)
393                != ASYNC_FINISH
394                 || funcret != 1) {
395         fprintf(stderr,
396                 "test_ASYNC_start_job_ex() - finishing job failed\n");
397         goto err;
398     }
399 
400     /* Reset the libctx temporarily to find out what it is*/
401     tmpctx = OSSL_LIB_CTX_set0_default(libctx);
402     OSSL_LIB_CTX_set0_default(tmpctx);
403     if (tmpctx != globalctx) {
404         fprintf(stderr,
405                 "test_ASYNC_start_job_ex() failed - global libctx check failed\n");
406         goto err;
407     }
408 
409     ret = 1;
410  err:
411     ASYNC_WAIT_CTX_free(waitctx);
412     ASYNC_cleanup_thread();
413     OSSL_LIB_CTX_free(libctx);
414     return ret;
415 }
416 
main(int argc,char ** argv)417 int main(int argc, char **argv)
418 {
419     if (!ASYNC_is_capable()) {
420         fprintf(stderr,
421                 "OpenSSL build is not ASYNC capable - skipping async tests\n");
422     } else {
423         if (!test_ASYNC_init_thread()
424                 || !test_ASYNC_callback_status()
425                 || !test_ASYNC_start_job()
426                 || !test_ASYNC_get_current_job()
427                 || !test_ASYNC_WAIT_CTX_get_all_fds()
428                 || !test_ASYNC_block_pause()
429                 || !test_ASYNC_start_job_ex()) {
430             return 1;
431         }
432     }
433     printf("PASS\n");
434     return 0;
435 }
436