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