xref: /netbsd-src/tests/crypto/opencrypto/h_ioctl.c (revision 82d56013d7b633d116a93943de88e08335357a7c)
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