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