h_ioctl.c revision 1.6 1 1.6 riastrad /* $NetBSD: h_ioctl.c,v 1.6 2023/08/05 13:29:57 riastradh Exp $ */
2 1.1 knakahar
3 1.1 knakahar /*-
4 1.1 knakahar * Copyright (c) 2017 Internet Initiative Japan Inc.
5 1.1 knakahar * All rights reserved.
6 1.1 knakahar *
7 1.1 knakahar * Redistribution and use in source and binary forms, with or without
8 1.1 knakahar * modification, are permitted provided that the following conditions
9 1.1 knakahar * are met:
10 1.1 knakahar * 1. Redistributions of source code must retain the above copyright
11 1.1 knakahar * notice, this list of conditions and the following disclaimer.
12 1.1 knakahar * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 knakahar * notice, this list of conditions and the following disclaimer in the
14 1.1 knakahar * documentation and/or other materials provided with the distribution.
15 1.1 knakahar *
16 1.1 knakahar * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 1.1 knakahar * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 1.1 knakahar * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 1.1 knakahar * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 1.1 knakahar * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 1.1 knakahar * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 1.1 knakahar * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 1.1 knakahar * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 1.1 knakahar * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 1.1 knakahar * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 1.1 knakahar * POSSIBILITY OF SUCH DAMAGE.
27 1.1 knakahar */
28 1.1 knakahar
29 1.1 knakahar #include <err.h>
30 1.1 knakahar #include <errno.h>
31 1.1 knakahar #include <fcntl.h>
32 1.5 riastrad #include <poll.h>
33 1.1 knakahar #include <stdio.h>
34 1.1 knakahar #include <string.h>
35 1.6 riastrad #include <unistd.h>
36 1.1 knakahar
37 1.1 knakahar #include <sys/errno.h>
38 1.1 knakahar #include <sys/ioctl.h>
39 1.1 knakahar #include <sys/sysctl.h>
40 1.1 knakahar
41 1.1 knakahar #include <crypto/cryptodev.h>
42 1.1 knakahar
43 1.1 knakahar /* copy from h_aescbc.c */
44 1.1 knakahar #define AES_KEY_LEN 16
45 1.1 knakahar unsigned char aes_key[AES_KEY_LEN] =
46 1.1 knakahar { 0x06, 0xa9, 0x21, 0x40, 0x36, 0xb8, 0xa1, 0x5b,
47 1.1 knakahar 0x51, 0x2e, 0x03, 0xd5, 0x34, 0x12, 0x00, 0x06, };
48 1.1 knakahar
49 1.1 knakahar #define AES_IV_LEN 16
50 1.1 knakahar unsigned char aes_iv[AES_IV_LEN] =
51 1.1 knakahar { 0x3d, 0xaf, 0xba, 0x42, 0x9d, 0x9e, 0xb4, 0x30,
52 1.1 knakahar 0xb4, 0x22, 0xda, 0x80, 0x2c, 0x9f, 0xac, 0x41, };
53 1.1 knakahar
54 1.1 knakahar #define AES_PLAINTX_LEN 64
55 1.1 knakahar unsigned char aes_plaintx[AES_PLAINTX_LEN] = "Single block msg";
56 1.1 knakahar
57 1.1 knakahar #define AES_CIPHER_LEN 64
58 1.1 knakahar unsigned char aes_cipher[AES_CIPHER_LEN] =
59 1.1 knakahar { 0xe3, 0x53, 0x77, 0x9c, 0x10, 0x79, 0xae, 0xb8,
60 1.1 knakahar 0x27, 0x08, 0x94, 0x2d, 0xbe, 0x77, 0x18, 0x1a, };
61 1.1 knakahar
62 1.3 christos #define COUNT 2
63 1.3 christos
64 1.5 riastrad static int
65 1.5 riastrad wait_for_read(int fd)
66 1.5 riastrad {
67 1.5 riastrad struct pollfd pfd = { .fd = fd, .events = POLLIN };
68 1.5 riastrad int nfd;
69 1.5 riastrad
70 1.5 riastrad nfd = poll(&pfd, 1, 5000);
71 1.5 riastrad if (nfd == -1) {
72 1.5 riastrad warn("failed: poll");
73 1.5 riastrad return -1;
74 1.5 riastrad }
75 1.5 riastrad if (nfd == 0) {
76 1.5 riastrad warnx("failed: timeout");
77 1.5 riastrad errno = ETIMEDOUT;
78 1.5 riastrad return -1;
79 1.5 riastrad }
80 1.5 riastrad if (nfd != 1 || (pfd.revents & POLLIN) == 0) {
81 1.5 riastrad warnx("failed: invalid poll: %d", nfd);
82 1.5 riastrad errno = EIO;
83 1.5 riastrad return -1;
84 1.5 riastrad }
85 1.5 riastrad return 0;
86 1.5 riastrad }
87 1.5 riastrad
88 1.1 knakahar /*
89 1.1 knakahar * CRIOGET is deprecated.
90 1.1 knakahar */
91 1.1 knakahar
92 1.1 knakahar /*
93 1.1 knakahar * CIOCNGSESSION
94 1.1 knakahar * Hmm, who uses? (1)
95 1.1 knakahar */
96 1.1 knakahar static int
97 1.1 knakahar test_ngsession(int fd)
98 1.1 knakahar {
99 1.1 knakahar int ret;
100 1.1 knakahar struct crypt_sgop sg;
101 1.3 christos struct session_n_op css[COUNT];
102 1.1 knakahar
103 1.3 christos for (size_t i = 0; i < COUNT; i++) {
104 1.1 knakahar struct session_n_op *cs = &css[i];
105 1.1 knakahar
106 1.1 knakahar memset(cs, 0, sizeof(*cs));
107 1.1 knakahar cs->cipher = CRYPTO_AES_CBC;
108 1.1 knakahar cs->keylen = AES_KEY_LEN;
109 1.1 knakahar cs->key = __UNCONST(&aes_key);
110 1.1 knakahar }
111 1.1 knakahar memset(&sg, 0, sizeof(sg));
112 1.3 christos sg.count = COUNT;
113 1.1 knakahar sg.sessions = css;
114 1.1 knakahar
115 1.1 knakahar ret = ioctl(fd, CIOCNGSESSION, &sg);
116 1.1 knakahar if (ret < 0)
117 1.4 riastrad warn("failed: CIOCNGSESSION");
118 1.1 knakahar
119 1.1 knakahar return ret;
120 1.1 knakahar }
121 1.1 knakahar
122 1.1 knakahar /*
123 1.1 knakahar * CIOCNFSESSION
124 1.1 knakahar * Hmm, who uses? (2)
125 1.1 knakahar */
126 1.1 knakahar static int
127 1.1 knakahar test_nfsession(int fd)
128 1.1 knakahar {
129 1.1 knakahar int ret;
130 1.1 knakahar struct crypt_sfop sf;
131 1.3 christos u_int32_t sids[COUNT];
132 1.1 knakahar
133 1.1 knakahar memset(sids, 0, sizeof(sids));
134 1.1 knakahar memset(&sf, 0, sizeof(sf));
135 1.3 christos sf.count = COUNT;
136 1.1 knakahar sf.sesid = sids;
137 1.1 knakahar
138 1.1 knakahar ret = ioctl(fd, CIOCNFSESSION, &sf);
139 1.1 knakahar if (ret < 0)
140 1.4 riastrad warn("failed: CIOCNFSESSION");
141 1.1 knakahar
142 1.1 knakahar return ret;
143 1.1 knakahar }
144 1.1 knakahar
145 1.1 knakahar /*
146 1.1 knakahar * CIOCNCRYPTM
147 1.1 knakahar * Hmm, who uses? (3)
148 1.1 knakahar */
149 1.1 knakahar static int
150 1.1 knakahar test_ncryptm(int fd)
151 1.1 knakahar {
152 1.1 knakahar int ret;
153 1.1 knakahar struct crypt_mop mop;
154 1.3 christos struct crypt_n_op css[COUNT];
155 1.1 knakahar
156 1.3 christos for (size_t i = 0; i < COUNT; i++) {
157 1.1 knakahar struct crypt_n_op *cs;
158 1.1 knakahar cs = &css[i];
159 1.1 knakahar
160 1.1 knakahar memset(cs, 0, sizeof(*cs));
161 1.1 knakahar cs->ses = 0; /* session id */
162 1.1 knakahar cs->op = COP_ENCRYPT;
163 1.1 knakahar /* XXX */
164 1.1 knakahar }
165 1.1 knakahar
166 1.1 knakahar memset(&mop, 0, sizeof(mop));
167 1.3 christos mop.count = COUNT;
168 1.1 knakahar mop.reqs = css;
169 1.1 knakahar
170 1.1 knakahar ret = ioctl(fd, CIOCNCRYPTM, &mop);
171 1.1 knakahar if (ret < 0)
172 1.4 riastrad warn("failed: CIOCNCRYPTM");
173 1.1 knakahar
174 1.1 knakahar return ret;
175 1.1 knakahar }
176 1.1 knakahar
177 1.1 knakahar /*
178 1.1 knakahar * CIOCNCRYPTRETM
179 1.1 knakahar * Hmm, who uses? (4)
180 1.1 knakahar */
181 1.1 knakahar static int
182 1.1 knakahar test_ncryptretm(int fd)
183 1.1 knakahar {
184 1.1 knakahar int ret;
185 1.1 knakahar struct session_op cs;
186 1.1 knakahar
187 1.1 knakahar struct crypt_mop mop;
188 1.3 christos struct crypt_n_op cnos[COUNT];
189 1.3 christos unsigned char cno_dst[COUNT][AES_CIPHER_LEN];
190 1.1 knakahar struct cryptret cret;
191 1.3 christos struct crypt_result crs[COUNT];
192 1.1 knakahar
193 1.1 knakahar memset(&cs, 0, sizeof(cs));
194 1.1 knakahar cs.cipher = CRYPTO_AES_CBC;
195 1.1 knakahar cs.keylen = AES_KEY_LEN;
196 1.1 knakahar cs.key = __UNCONST(&aes_key);
197 1.1 knakahar ret = ioctl(fd, CIOCGSESSION, &cs);
198 1.1 knakahar if (ret < 0) {
199 1.4 riastrad warn("failed: CIOCGSESSION");
200 1.1 knakahar return ret;
201 1.1 knakahar }
202 1.1 knakahar
203 1.3 christos for (size_t i = 0; i < COUNT; i++) {
204 1.1 knakahar struct crypt_n_op *cno = &cnos[i];
205 1.1 knakahar
206 1.1 knakahar memset(cno, 0, sizeof(*cno));
207 1.1 knakahar cno->ses = cs.ses;
208 1.1 knakahar cno->op = COP_ENCRYPT;
209 1.1 knakahar cno->len = AES_PLAINTX_LEN;
210 1.1 knakahar cno->src = aes_plaintx;
211 1.1 knakahar cno->dst_len = AES_CIPHER_LEN;
212 1.1 knakahar cno->dst = cno_dst[i];
213 1.1 knakahar }
214 1.1 knakahar
215 1.1 knakahar memset(&mop, 0, sizeof(mop));
216 1.3 christos mop.count = COUNT;
217 1.1 knakahar mop.reqs = cnos;
218 1.1 knakahar ret = ioctl(fd, CIOCNCRYPTM, &mop);
219 1.5 riastrad if (ret < 0) {
220 1.4 riastrad warn("failed: CIOCNCRYPTM");
221 1.5 riastrad return ret;
222 1.5 riastrad }
223 1.1 knakahar
224 1.3 christos for (size_t i = 0; i < COUNT; i++) {
225 1.1 knakahar struct crypt_result *cr = &crs[i];
226 1.1 knakahar
227 1.1 knakahar memset(cr, 0, sizeof(*cr));
228 1.1 knakahar cr->reqid = cnos[i].reqid;
229 1.1 knakahar }
230 1.1 knakahar
231 1.1 knakahar memset(&cret, 0, sizeof(cret));
232 1.3 christos cret.count = COUNT;
233 1.1 knakahar cret.results = crs;
234 1.1 knakahar ret = ioctl(fd, CIOCNCRYPTRETM, &cret);
235 1.5 riastrad if (ret < 0) {
236 1.5 riastrad if (errno != EINPROGRESS) {
237 1.5 riastrad warn("failed: CIOCNCRYPTRETM");
238 1.5 riastrad return ret;
239 1.5 riastrad }
240 1.5 riastrad
241 1.5 riastrad ret = wait_for_read(fd);
242 1.5 riastrad if (ret < 0)
243 1.5 riastrad return ret;
244 1.5 riastrad
245 1.5 riastrad cret.count = COUNT;
246 1.5 riastrad cret.results = crs;
247 1.5 riastrad ret = ioctl(fd, CIOCNCRYPTRETM, &cret);
248 1.5 riastrad if (ret < 0) {
249 1.5 riastrad warn("failed: CIOCNCRYPTRET");
250 1.5 riastrad return ret;
251 1.5 riastrad }
252 1.5 riastrad }
253 1.1 knakahar
254 1.1 knakahar return ret;
255 1.1 knakahar }
256 1.1 knakahar
257 1.1 knakahar /*
258 1.1 knakahar * CIOCNCRYPTRET
259 1.1 knakahar * Hmm, who uses? (5)
260 1.1 knakahar */
261 1.1 knakahar /* test when it does not request yet. */
262 1.1 knakahar static int
263 1.1 knakahar test_ncryptret_noent(int fd)
264 1.1 knakahar {
265 1.1 knakahar int ret;
266 1.1 knakahar struct crypt_result cr;
267 1.1 knakahar
268 1.1 knakahar memset(&cr, 0, sizeof(cr));
269 1.1 knakahar
270 1.1 knakahar ret = ioctl(fd, CIOCNCRYPTRET, &cr);
271 1.1 knakahar if (ret == 0) {
272 1.4 riastrad warn("failed: CIOCNCRYPTRET unexpected success when no entry");
273 1.1 knakahar ret = -1;
274 1.1 knakahar } else if (errno == EINPROGRESS) {
275 1.1 knakahar /* expected fail */
276 1.1 knakahar ret = 0;
277 1.1 knakahar }
278 1.1 knakahar
279 1.1 knakahar return ret;
280 1.1 knakahar }
281 1.1 knakahar
282 1.1 knakahar static int
283 1.1 knakahar test_ncryptret_ent(int fd)
284 1.1 knakahar {
285 1.1 knakahar int ret;
286 1.1 knakahar struct session_op cs;
287 1.1 knakahar
288 1.1 knakahar struct crypt_mop mop;
289 1.1 knakahar struct crypt_n_op cno;
290 1.1 knakahar unsigned char cno_dst[AES_CIPHER_LEN];
291 1.1 knakahar
292 1.1 knakahar struct crypt_result cr;
293 1.1 knakahar
294 1.1 knakahar memset(&cs, 0, sizeof(cs));
295 1.1 knakahar cs.cipher = CRYPTO_AES_CBC;
296 1.1 knakahar cs.keylen = AES_KEY_LEN;
297 1.1 knakahar cs.key = __UNCONST(&aes_key);
298 1.1 knakahar ret = ioctl(fd, CIOCGSESSION, &cs);
299 1.1 knakahar if (ret < 0) {
300 1.4 riastrad warn("failed: CIOCGSESSION");
301 1.1 knakahar return ret;
302 1.1 knakahar }
303 1.1 knakahar
304 1.1 knakahar memset(&cno, 0, sizeof(cno));
305 1.1 knakahar cno.ses = cs.ses;
306 1.1 knakahar cno.op = COP_ENCRYPT;
307 1.1 knakahar cno.len = AES_PLAINTX_LEN;
308 1.1 knakahar cno.src = aes_plaintx;
309 1.1 knakahar cno.dst_len = AES_CIPHER_LEN;
310 1.1 knakahar cno.dst = cno_dst;
311 1.1 knakahar
312 1.1 knakahar memset(&mop, 0, sizeof(mop));
313 1.1 knakahar mop.count = 1;
314 1.1 knakahar mop.reqs = &cno;
315 1.1 knakahar ret = ioctl(fd, CIOCNCRYPTM, &mop);
316 1.5 riastrad if (ret < 0) {
317 1.4 riastrad warn("failed: CIOCNCRYPTM");
318 1.5 riastrad return ret;
319 1.5 riastrad }
320 1.1 knakahar
321 1.1 knakahar memset(&cr, 0, sizeof(cr));
322 1.1 knakahar cr.reqid = cno.reqid;
323 1.1 knakahar
324 1.1 knakahar ret = ioctl(fd, CIOCNCRYPTRET, &cr);
325 1.5 riastrad if (ret < 0) {
326 1.5 riastrad if (errno != EINPROGRESS) {
327 1.5 riastrad warn("failed: CIOCNCRYPTRET");
328 1.5 riastrad return ret;
329 1.5 riastrad }
330 1.5 riastrad
331 1.5 riastrad ret = wait_for_read(fd);
332 1.5 riastrad if (ret < 0)
333 1.5 riastrad return ret;
334 1.5 riastrad ret = ioctl(fd, CIOCNCRYPTRET, &cr);
335 1.5 riastrad if (ret < 0) {
336 1.5 riastrad warn("failed: CIOCNCRYPTRET");
337 1.5 riastrad return ret;
338 1.5 riastrad }
339 1.5 riastrad return 0;
340 1.5 riastrad }
341 1.1 knakahar
342 1.1 knakahar return ret;
343 1.1 knakahar }
344 1.1 knakahar
345 1.1 knakahar static int
346 1.1 knakahar test_ncryptret(int fd)
347 1.1 knakahar {
348 1.1 knakahar int ret;
349 1.1 knakahar
350 1.1 knakahar ret = test_ncryptret_noent(fd);
351 1.1 knakahar if (ret < 0)
352 1.1 knakahar return ret;
353 1.1 knakahar
354 1.1 knakahar ret = test_ncryptret_ent(fd);
355 1.1 knakahar if (ret < 0)
356 1.1 knakahar return ret;
357 1.1 knakahar
358 1.1 knakahar return ret;
359 1.1 knakahar }
360 1.1 knakahar
361 1.1 knakahar /*
362 1.1 knakahar * CIOCASYMFEAT
363 1.1 knakahar */
364 1.1 knakahar static int
365 1.1 knakahar set_userasymcrypto(int new, int *old)
366 1.1 knakahar {
367 1.1 knakahar int ret;
368 1.1 knakahar
369 1.1 knakahar ret = sysctlbyname("kern.userasymcrypto", NULL, NULL, &new, sizeof(new));
370 1.1 knakahar if (ret < 0) {
371 1.4 riastrad warn("failed: kern.userasymcrypto=%d", new);
372 1.1 knakahar return ret;
373 1.1 knakahar }
374 1.1 knakahar
375 1.1 knakahar if (old != NULL)
376 1.1 knakahar *old = new;
377 1.1 knakahar
378 1.1 knakahar return ret;
379 1.1 knakahar }
380 1.1 knakahar
381 1.1 knakahar static int
382 1.1 knakahar test_asymfeat_each(int fd, u_int32_t *asymfeat, int userasym)
383 1.1 knakahar {
384 1.1 knakahar int ret;
385 1.1 knakahar
386 1.1 knakahar ret = ioctl(fd, CIOCASYMFEAT, asymfeat);
387 1.1 knakahar if (ret < 0)
388 1.4 riastrad warn("failed: CIOCASYMFEAT when userasym=%d", userasym);
389 1.1 knakahar
390 1.1 knakahar return ret;
391 1.1 knakahar }
392 1.1 knakahar
393 1.1 knakahar static int
394 1.1 knakahar test_asymfeat(int fd)
395 1.1 knakahar {
396 1.1 knakahar int ret, new, orig;
397 1.1 knakahar u_int32_t asymfeat = 0;
398 1.1 knakahar
399 1.1 knakahar /* test for kern.userasymcrypto=1 */
400 1.1 knakahar new = 1;
401 1.1 knakahar ret = set_userasymcrypto(new, &orig);
402 1.1 knakahar if (ret < 0)
403 1.1 knakahar return ret;
404 1.1 knakahar ret = test_asymfeat_each(fd, &asymfeat, new);
405 1.1 knakahar if (ret < 0)
406 1.1 knakahar return ret;
407 1.1 knakahar
408 1.1 knakahar /* test for kern.userasymcrypto=0 */
409 1.1 knakahar new = 0;
410 1.1 knakahar ret = set_userasymcrypto(new, NULL);
411 1.1 knakahar if (ret < 0)
412 1.1 knakahar return ret;
413 1.1 knakahar ret = test_asymfeat_each(fd, &asymfeat, new);
414 1.1 knakahar if (ret < 0)
415 1.1 knakahar return ret;
416 1.1 knakahar
417 1.1 knakahar /* cleanup */
418 1.1 knakahar ret = set_userasymcrypto(orig, NULL);
419 1.1 knakahar if (ret < 0)
420 1.4 riastrad warnx("failed: cleanup kern.userasymcrypto");
421 1.1 knakahar
422 1.1 knakahar return ret;
423 1.1 knakahar }
424 1.1 knakahar
425 1.1 knakahar int
426 1.1 knakahar main(void)
427 1.1 knakahar {
428 1.1 knakahar int fd, ret;
429 1.1 knakahar
430 1.1 knakahar fd = open("/dev/crypto", O_RDWR, 0);
431 1.1 knakahar if (fd < 0)
432 1.1 knakahar err(1, "open");
433 1.1 knakahar
434 1.1 knakahar ret = test_ngsession(fd);
435 1.1 knakahar if (ret < 0)
436 1.1 knakahar err(1, "test_ngsession");
437 1.1 knakahar
438 1.1 knakahar ret = test_nfsession(fd);
439 1.1 knakahar if (ret < 0)
440 1.1 knakahar err(1, "test_ngsession");
441 1.1 knakahar
442 1.1 knakahar ret = test_ncryptm(fd);
443 1.1 knakahar if (ret < 0)
444 1.1 knakahar err(1, "test_ncryptm");
445 1.1 knakahar
446 1.1 knakahar test_ncryptretm(fd);
447 1.1 knakahar if (ret < 0)
448 1.1 knakahar err(1, "test_ncryptretm");
449 1.1 knakahar
450 1.1 knakahar ret = test_ncryptret(fd);
451 1.1 knakahar if (ret < 0)
452 1.1 knakahar err(1, "test_ncryptret");
453 1.1 knakahar
454 1.6 riastrad if (getuid() == 0) {
455 1.6 riastrad ret = test_asymfeat(fd);
456 1.6 riastrad if (ret < 0)
457 1.6 riastrad err(1, "test_asymfeat");
458 1.6 riastrad }
459 1.1 knakahar
460 1.1 knakahar return 0;
461 1.1 knakahar }
462