1 /* $NetBSD: h_thread.c,v 1.2 2026/05/19 15:57:51 riastradh Exp $ */ 2 3 /*- 4 * Copyright (c) 2026 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/ioctl.h> 30 #include <sys/signal.h> 31 #include <sys/time.h> 32 33 #include <err.h> 34 #include <errno.h> 35 #include <fcntl.h> 36 #include <pthread.h> 37 #include <stdatomic.h> 38 #include <stdbool.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <unistd.h> 43 44 #include <crypto/cryptodev.h> 45 46 #define atomic_load_acquire(p) atomic_load_explicit(p, memory_order_acquire) 47 #define atomic_load_relaxed(p) atomic_load_explicit(p, memory_order_relaxed) 48 #define atomic_store_relaxed(p, v) \ 49 atomic_store_explicit(p, v, memory_order_relaxed) 50 #define atomic_store_release(p, v) \ 51 atomic_store_explicit(p, v, memory_order_release) 52 53 /* Test vectors from RFC1321 */ 54 55 const struct { 56 size_t len; 57 unsigned char plaintx[80]; 58 unsigned char digest[16]; 59 } tests[] = { 60 { 0, "", 61 { 0xd4, 0x1d, 0x8c, 0xd9, 0x8f, 0x00, 0xb2, 0x04, 62 0xe9, 0x80, 0x09, 0x98, 0xec, 0xf8, 0x42, 0x7e } }, 63 { 1, "a", 64 { 0x0c, 0xc1, 0x75, 0xb9, 0xc0, 0xf1, 0xb6, 0xa8, 65 0x31, 0xc3, 0x99, 0xe2, 0x69, 0x77, 0x26, 0x61 } }, 66 { 3, "abc", 67 { 0x90, 0x01, 0x50, 0x98, 0x3c, 0xd2, 0x4f, 0xb0, 68 0xd6, 0x96, 0x3f, 0x7d, 0x28, 0xe1, 0x7f, 0x72 } }, 69 { 14, "message digest", 70 { 0xf9, 0x6b, 0x69, 0x7d, 0x7c, 0xb7, 0x93, 0x8d, 71 0x52, 0x5a, 0x2f, 0x31, 0xaa, 0xf1, 0x61, 0xd0 } }, 72 { 26, "abcdefghijklmnopqrstuvwxyz", 73 { 0xc3, 0xfc, 0xd3, 0xd7, 0x61, 0x92, 0xe4, 0x00, 74 0x7d, 0xfb, 0x49, 0x6c, 0xca, 0x67, 0xe1, 0x3b } }, 75 { 62, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 76 { 0xd1, 0x74, 0xab, 0x98, 0xd2, 0x77, 0xd9, 0xf5, 77 0xa5, 0x61, 0x1c, 0x2c, 0x9f, 0x41, 0x9d, 0x9f } }, 78 { 80, "123456789012345678901234567890123456789012345678901234567890" 79 "12345678901234567890", 80 { 0x57, 0xed, 0xf4, 0xa2, 0x2b, 0xe3, 0xc9, 0x55, 81 0xac, 0x49, 0xda, 0x2e, 0x21, 0x07, 0xb6, 0x7a } }, 82 }; 83 84 struct arg { 85 char msg; 86 }; 87 88 static int fd; 89 static atomic_bool done = false; 90 static atomic_uint_fast32_t ses = 0; 91 static timer_t timer; 92 93 static void * 94 t_openclose(void *v) 95 { 96 struct arg *a = v; 97 98 while (!atomic_load_relaxed(&done)) { 99 struct session_op cs; 100 101 memset(&cs, 0, sizeof(cs)); 102 cs.mac = CRYPTO_MD5; 103 if (ioctl(fd, CIOCGSESSION, &cs) == -1) 104 err(EXIT_FAILURE, "CIOCGSESSION"); 105 106 atomic_store_release(&ses, cs.ses); 107 sched_yield(); 108 atomic_store_relaxed(&ses, 0); 109 110 while (ioctl(fd, CIOCFSESSION, &cs.ses) == -1) { 111 if (errno != EBUSY) 112 err(EXIT_FAILURE, "CIOCFSESSION"); 113 } 114 115 fprintf(stderr, "%c", a->msg); 116 } 117 118 return NULL; 119 } 120 121 static void * 122 t_encrypt(void *v) 123 { 124 struct crypt_op co; 125 unsigned char buf[16]; 126 struct arg *a = v; 127 128 while (!atomic_load_relaxed(&done)) { 129 for (size_t i = 0; i < __arraycount(tests); i++) { 130 memset(&co, 0, sizeof(co)); 131 memset(&buf, 0, sizeof(buf)); 132 while ((co.ses = atomic_load_acquire(&ses)) == 0) { 133 if (atomic_load_relaxed(&done)) 134 goto out; 135 continue; 136 } 137 co.op = COP_ENCRYPT; 138 co.len = tests[i].len; 139 co.src = __UNCONST(&tests[i].plaintx); 140 co.mac = buf; 141 if (ioctl(fd, CIOCCRYPT, &co) == -1) { 142 if (atomic_load_relaxed(&ses) == co.ses) 143 err(EXIT_FAILURE, "CIOCCRYPT"); 144 continue; 145 } 146 if (memcmp(co.mac, tests[i].digest, sizeof(tests[i].digest))) 147 errx(1, "verification failed test %zu", i); 148 fprintf(stderr, "%c", a->msg); 149 } 150 } 151 out: 152 return NULL; 153 } 154 155 static void 156 abortalarm(unsigned sec) 157 { 158 struct sigevent sigev; 159 160 memset(&sigev, 0, sizeof(sigev)); 161 sigev.sigev_notify = SIGEV_SIGNAL; 162 sigev.sigev_signo = SIGABRT; 163 164 if (timer_create(CLOCK_MONOTONIC, &sigev, &timer) == -1) 165 err(EXIT_FAILURE, "timer_create"); 166 if (timer_settime(timer, TIMER_RELTIME, 167 &(const struct itimerspec) { .it_value = {sec, 0} }, 168 NULL) == -1) 169 err(EXIT_FAILURE, "timer_settime"); 170 } 171 172 int 173 main(void) 174 { 175 pthread_t ta, tb, tc; 176 struct arg a, b, c; 177 int error; 178 179 if ((fd = open("/dev/crypto", O_RDWR, 0)) == -1) 180 err(EXIT_FAILURE, "open /dev/crypto"); 181 182 a.msg = '/'; 183 error = pthread_create(&ta, NULL, t_openclose, &a); 184 if (error) 185 errc(EXIT_FAILURE, error, "pthread_create A"); 186 187 b = a; 188 b.msg = '-'; 189 error = pthread_create(&tb, NULL, t_encrypt, &b); 190 if (error) 191 errc(EXIT_FAILURE, error, "pthread_create B"); 192 c = a; 193 c.msg = '+'; 194 error = pthread_create(&tc, NULL, t_encrypt, &c); 195 if (error) 196 errc(EXIT_FAILURE, error, "pthread_create C"); 197 198 sleep(5); 199 fprintf(stderr, "|"); 200 atomic_store_relaxed(&done, true); 201 abortalarm(1); 202 error = pthread_join(ta, NULL); 203 if (error) 204 errc(EXIT_FAILURE, error, "pthread_join A"); 205 error = pthread_join(tb, NULL); 206 if (error) 207 errc(EXIT_FAILURE, error, "pthread_join B"); 208 error = pthread_join(tc, NULL); 209 if (error) 210 errc(EXIT_FAILURE, error, "pthread_join C"); 211 212 if (ioctl(fd, CIOCFSESSION, &ses) != -1) 213 errx(EXIT_FAILURE, "CIOCFSESSION failed to fail"); 214 if (errno != EINVAL) 215 err(EXIT_FAILURE, "CIOCFSESSION"); 216 return EXIT_SUCCESS; 217 } 218