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