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