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