xref: /freebsd/sys/crypto/aesni/aesni.c (revision fcb560670601b2a4d87bb31d7531c8dcc37ee71b)
1 /*-
2  * Copyright (c) 2005-2008 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3  * Copyright (c) 2010 Konstantin Belousov <kib@FreeBSD.org>
4  * Copyright (c) 2014 The FreeBSD Foundation
5  * All rights reserved.
6  *
7  * Portions of this software were developed by John-Mark Gurney
8  * under sponsorship of the FreeBSD Foundation and
9  * Rubicon Communications, LLC (Netgate).
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
35 
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/kobj.h>
40 #include <sys/libkern.h>
41 #include <sys/lock.h>
42 #include <sys/module.h>
43 #include <sys/malloc.h>
44 #include <sys/rwlock.h>
45 #include <sys/bus.h>
46 #include <sys/uio.h>
47 #include <sys/mbuf.h>
48 #include <crypto/aesni/aesni.h>
49 #include <cryptodev_if.h>
50 #include <opencrypto/gmac.h>
51 
52 struct aesni_softc {
53 	int32_t cid;
54 	uint32_t sid;
55 	TAILQ_HEAD(aesni_sessions_head, aesni_session) sessions;
56 	struct rwlock lock;
57 };
58 
59 static int aesni_newsession(device_t, uint32_t *sidp, struct cryptoini *cri);
60 static int aesni_freesession(device_t, uint64_t tid);
61 static void aesni_freesession_locked(struct aesni_softc *sc,
62     struct aesni_session *ses);
63 static int aesni_cipher_setup(struct aesni_session *ses,
64     struct cryptoini *encini);
65 static int aesni_cipher_process(struct aesni_session *ses,
66     struct cryptodesc *enccrd, struct cryptodesc *authcrd, struct cryptop *crp);
67 
68 MALLOC_DEFINE(M_AESNI, "aesni_data", "AESNI Data");
69 
70 static void
71 aesni_identify(driver_t *drv, device_t parent)
72 {
73 
74 	/* NB: order 10 is so we get attached after h/w devices */
75 	if (device_find_child(parent, "aesni", -1) == NULL &&
76 	    BUS_ADD_CHILD(parent, 10, "aesni", -1) == 0)
77 		panic("aesni: could not attach");
78 }
79 
80 static int
81 aesni_probe(device_t dev)
82 {
83 
84 	if ((cpu_feature2 & CPUID2_AESNI) == 0) {
85 		device_printf(dev, "No AESNI support.\n");
86 		return (EINVAL);
87 	}
88 
89 	if ((cpu_feature2 & CPUID2_SSE41) == 0) {
90 		device_printf(dev, "No SSE4.1 support.\n");
91 		return (EINVAL);
92 	}
93 
94 	device_set_desc_copy(dev, "AES-CBC,AES-XTS,AES-GCM,AES-ICM");
95 	return (0);
96 }
97 
98 static int
99 aesni_attach(device_t dev)
100 {
101 	struct aesni_softc *sc;
102 
103 	sc = device_get_softc(dev);
104 	TAILQ_INIT(&sc->sessions);
105 	sc->sid = 1;
106 	sc->cid = crypto_get_driverid(dev, CRYPTOCAP_F_HARDWARE |
107 	    CRYPTOCAP_F_SYNC);
108 	if (sc->cid < 0) {
109 		device_printf(dev, "Could not get crypto driver id.\n");
110 		return (ENOMEM);
111 	}
112 
113 	rw_init(&sc->lock, "aesni_lock");
114 	crypto_register(sc->cid, CRYPTO_AES_CBC, 0, 0);
115 	crypto_register(sc->cid, CRYPTO_AES_ICM, 0, 0);
116 	crypto_register(sc->cid, CRYPTO_AES_NIST_GCM_16, 0, 0);
117 	crypto_register(sc->cid, CRYPTO_AES_128_NIST_GMAC, 0, 0);
118 	crypto_register(sc->cid, CRYPTO_AES_192_NIST_GMAC, 0, 0);
119 	crypto_register(sc->cid, CRYPTO_AES_256_NIST_GMAC, 0, 0);
120 	crypto_register(sc->cid, CRYPTO_AES_XTS, 0, 0);
121 	return (0);
122 }
123 
124 static int
125 aesni_detach(device_t dev)
126 {
127 	struct aesni_softc *sc;
128 	struct aesni_session *ses;
129 
130 	sc = device_get_softc(dev);
131 	rw_wlock(&sc->lock);
132 	TAILQ_FOREACH(ses, &sc->sessions, next) {
133 		if (ses->used) {
134 			rw_wunlock(&sc->lock);
135 			device_printf(dev,
136 			    "Cannot detach, sessions still active.\n");
137 			return (EBUSY);
138 		}
139 	}
140 	while ((ses = TAILQ_FIRST(&sc->sessions)) != NULL) {
141 		TAILQ_REMOVE(&sc->sessions, ses, next);
142 		fpu_kern_free_ctx(ses->fpu_ctx);
143 		free(ses, M_AESNI);
144 	}
145 	rw_wunlock(&sc->lock);
146 	rw_destroy(&sc->lock);
147 	crypto_unregister_all(sc->cid);
148 	return (0);
149 }
150 
151 static int
152 aesni_newsession(device_t dev, uint32_t *sidp, struct cryptoini *cri)
153 {
154 	struct aesni_softc *sc;
155 	struct aesni_session *ses;
156 	struct cryptoini *encini;
157 	int error;
158 
159 	if (sidp == NULL || cri == NULL) {
160 		CRYPTDEB("no sidp or cri");
161 		return (EINVAL);
162 	}
163 
164 	sc = device_get_softc(dev);
165 	ses = NULL;
166 	encini = NULL;
167 	for (; cri != NULL; cri = cri->cri_next) {
168 		switch (cri->cri_alg) {
169 		case CRYPTO_AES_CBC:
170 		case CRYPTO_AES_ICM:
171 		case CRYPTO_AES_XTS:
172 		case CRYPTO_AES_NIST_GCM_16:
173 			if (encini != NULL) {
174 				CRYPTDEB("encini already set");
175 				return (EINVAL);
176 			}
177 			encini = cri;
178 			break;
179 		case CRYPTO_AES_128_NIST_GMAC:
180 		case CRYPTO_AES_192_NIST_GMAC:
181 		case CRYPTO_AES_256_NIST_GMAC:
182 			/*
183 			 * nothing to do here, maybe in the future cache some
184 			 * values for GHASH
185 			 */
186 			break;
187 		default:
188 			CRYPTDEB("unhandled algorithm");
189 			return (EINVAL);
190 		}
191 	}
192 	if (encini == NULL) {
193 		CRYPTDEB("no cipher");
194 		return (EINVAL);
195 	}
196 
197 	rw_wlock(&sc->lock);
198 	/*
199 	 * Free sessions goes first, so if first session is used, we need to
200 	 * allocate one.
201 	 */
202 	ses = TAILQ_FIRST(&sc->sessions);
203 	if (ses == NULL || ses->used) {
204 		ses = malloc(sizeof(*ses), M_AESNI, M_NOWAIT | M_ZERO);
205 		if (ses == NULL) {
206 			rw_wunlock(&sc->lock);
207 			return (ENOMEM);
208 		}
209 		ses->fpu_ctx = fpu_kern_alloc_ctx(FPU_KERN_NORMAL |
210 		    FPU_KERN_NOWAIT);
211 		if (ses->fpu_ctx == NULL) {
212 			free(ses, M_AESNI);
213 			rw_wunlock(&sc->lock);
214 			return (ENOMEM);
215 		}
216 		ses->id = sc->sid++;
217 	} else {
218 		TAILQ_REMOVE(&sc->sessions, ses, next);
219 	}
220 	ses->used = 1;
221 	TAILQ_INSERT_TAIL(&sc->sessions, ses, next);
222 	rw_wunlock(&sc->lock);
223 	ses->algo = encini->cri_alg;
224 
225 	error = aesni_cipher_setup(ses, encini);
226 	if (error != 0) {
227 		CRYPTDEB("setup failed");
228 		rw_wlock(&sc->lock);
229 		aesni_freesession_locked(sc, ses);
230 		rw_wunlock(&sc->lock);
231 		return (error);
232 	}
233 
234 	*sidp = ses->id;
235 	return (0);
236 }
237 
238 static void
239 aesni_freesession_locked(struct aesni_softc *sc, struct aesni_session *ses)
240 {
241 	struct fpu_kern_ctx *ctx;
242 	uint32_t sid;
243 
244 	sid = ses->id;
245 	TAILQ_REMOVE(&sc->sessions, ses, next);
246 	ctx = ses->fpu_ctx;
247 	*ses = (struct aesni_session){};
248 	ses->id = sid;
249 	ses->fpu_ctx = ctx;
250 	TAILQ_INSERT_HEAD(&sc->sessions, ses, next);
251 }
252 
253 static int
254 aesni_freesession(device_t dev, uint64_t tid)
255 {
256 	struct aesni_softc *sc;
257 	struct aesni_session *ses;
258 	uint32_t sid;
259 
260 	sc = device_get_softc(dev);
261 	sid = ((uint32_t)tid) & 0xffffffff;
262 	rw_wlock(&sc->lock);
263 	TAILQ_FOREACH_REVERSE(ses, &sc->sessions, aesni_sessions_head, next) {
264 		if (ses->id == sid)
265 			break;
266 	}
267 	if (ses == NULL) {
268 		rw_wunlock(&sc->lock);
269 		return (EINVAL);
270 	}
271 	aesni_freesession_locked(sc, ses);
272 	rw_wunlock(&sc->lock);
273 	return (0);
274 }
275 
276 static int
277 aesni_process(device_t dev, struct cryptop *crp, int hint __unused)
278 {
279 	struct aesni_softc *sc = device_get_softc(dev);
280 	struct aesni_session *ses = NULL;
281 	struct cryptodesc *crd, *enccrd, *authcrd;
282 	int error, needauth;
283 
284 	error = 0;
285 	enccrd = NULL;
286 	authcrd = NULL;
287 	needauth = 0;
288 
289 	/* Sanity check. */
290 	if (crp == NULL)
291 		return (EINVAL);
292 
293 	if (crp->crp_callback == NULL || crp->crp_desc == NULL) {
294 		error = EINVAL;
295 		goto out;
296 	}
297 
298 	for (crd = crp->crp_desc; crd != NULL; crd = crd->crd_next) {
299 		switch (crd->crd_alg) {
300 		case CRYPTO_AES_CBC:
301 		case CRYPTO_AES_ICM:
302 		case CRYPTO_AES_XTS:
303 			if (enccrd != NULL) {
304 				error = EINVAL;
305 				goto out;
306 			}
307 			enccrd = crd;
308 			break;
309 
310 		case CRYPTO_AES_NIST_GCM_16:
311 			if (enccrd != NULL) {
312 				error = EINVAL;
313 				goto out;
314 			}
315 			enccrd = crd;
316 			needauth = 1;
317 			break;
318 
319 		case CRYPTO_AES_128_NIST_GMAC:
320 		case CRYPTO_AES_192_NIST_GMAC:
321 		case CRYPTO_AES_256_NIST_GMAC:
322 			if (authcrd != NULL) {
323 				error = EINVAL;
324 				goto out;
325 			}
326 			authcrd = crd;
327 			needauth = 1;
328 			break;
329 
330 		default:
331 			error = EINVAL;
332 			goto out;
333 		}
334 	}
335 
336 	if (enccrd == NULL || (needauth && authcrd == NULL)) {
337 		error = EINVAL;
338 		goto out;
339 	}
340 
341 	/* CBC & XTS can only handle full blocks for now */
342 	if ((enccrd->crd_alg == CRYPTO_AES_CBC || enccrd->crd_alg ==
343 	    CRYPTO_AES_XTS) && (enccrd->crd_len % AES_BLOCK_LEN) != 0) {
344 		error = EINVAL;
345 		goto out;
346 	}
347 
348 	rw_rlock(&sc->lock);
349 	TAILQ_FOREACH_REVERSE(ses, &sc->sessions, aesni_sessions_head, next) {
350 		if (ses->id == (crp->crp_sid & 0xffffffff))
351 			break;
352 	}
353 	rw_runlock(&sc->lock);
354 	if (ses == NULL) {
355 		error = EINVAL;
356 		goto out;
357 	}
358 
359 	error = aesni_cipher_process(ses, enccrd, authcrd, crp);
360 	if (error != 0)
361 		goto out;
362 
363 out:
364 	crp->crp_etype = error;
365 	crypto_done(crp);
366 	return (error);
367 }
368 
369 uint8_t *
370 aesni_cipher_alloc(struct cryptodesc *enccrd, struct cryptop *crp,
371     int *allocated)
372 {
373 	struct mbuf *m;
374 	struct uio *uio;
375 	struct iovec *iov;
376 	uint8_t *addr;
377 
378 	if (crp->crp_flags & CRYPTO_F_IMBUF) {
379 		m = (struct mbuf *)crp->crp_buf;
380 		if (m->m_next != NULL)
381 			goto alloc;
382 		addr = mtod(m, uint8_t *);
383 	} else if (crp->crp_flags & CRYPTO_F_IOV) {
384 		uio = (struct uio *)crp->crp_buf;
385 		if (uio->uio_iovcnt != 1)
386 			goto alloc;
387 		iov = uio->uio_iov;
388 		addr = (uint8_t *)iov->iov_base;
389 	} else
390 		addr = (uint8_t *)crp->crp_buf;
391 	*allocated = 0;
392 	addr += enccrd->crd_skip;
393 	return (addr);
394 
395 alloc:
396 	addr = malloc(enccrd->crd_len, M_AESNI, M_NOWAIT);
397 	if (addr != NULL) {
398 		*allocated = 1;
399 		crypto_copydata(crp->crp_flags, crp->crp_buf, enccrd->crd_skip,
400 		    enccrd->crd_len, addr);
401 	} else
402 		*allocated = 0;
403 	return (addr);
404 }
405 
406 static device_method_t aesni_methods[] = {
407 	DEVMETHOD(device_identify, aesni_identify),
408 	DEVMETHOD(device_probe, aesni_probe),
409 	DEVMETHOD(device_attach, aesni_attach),
410 	DEVMETHOD(device_detach, aesni_detach),
411 
412 	DEVMETHOD(cryptodev_newsession, aesni_newsession),
413 	DEVMETHOD(cryptodev_freesession, aesni_freesession),
414 	DEVMETHOD(cryptodev_process, aesni_process),
415 
416 	{0, 0},
417 };
418 
419 static driver_t aesni_driver = {
420 	"aesni",
421 	aesni_methods,
422 	sizeof(struct aesni_softc),
423 };
424 static devclass_t aesni_devclass;
425 
426 DRIVER_MODULE(aesni, nexus, aesni_driver, aesni_devclass, 0, 0);
427 MODULE_VERSION(aesni, 1);
428 MODULE_DEPEND(aesni, crypto, 1, 1, 1);
429 
430 static int
431 aesni_cipher_setup(struct aesni_session *ses, struct cryptoini *encini)
432 {
433 	struct thread *td;
434 	int error;
435 
436 	td = curthread;
437 	error = fpu_kern_enter(td, ses->fpu_ctx, FPU_KERN_NORMAL |
438 	    FPU_KERN_KTHR);
439 	if (error != 0)
440 		return (error);
441 	error = aesni_cipher_setup_common(ses, encini->cri_key,
442 	    encini->cri_klen);
443 	fpu_kern_leave(td, ses->fpu_ctx);
444 	return (error);
445 }
446 
447 /*
448  * authcrd contains the associated date.
449  */
450 static int
451 aesni_cipher_process(struct aesni_session *ses, struct cryptodesc *enccrd,
452     struct cryptodesc *authcrd, struct cryptop *crp)
453 {
454 	uint8_t tag[GMAC_DIGEST_LEN];
455 	struct thread *td;
456 	uint8_t *buf, *authbuf;
457 	int error, allocated, authallocated;
458 	int ivlen, encflag;
459 
460 	encflag = (enccrd->crd_flags & CRD_F_ENCRYPT) == CRD_F_ENCRYPT;
461 
462 	if ((enccrd->crd_alg == CRYPTO_AES_ICM ||
463 	    enccrd->crd_alg == CRYPTO_AES_NIST_GCM_16) &&
464 	    (enccrd->crd_flags & CRD_F_IV_EXPLICIT) == 0)
465 		return (EINVAL);
466 
467 	buf = aesni_cipher_alloc(enccrd, crp, &allocated);
468 	if (buf == NULL)
469 		return (ENOMEM);
470 
471 	authbuf = NULL;
472 	authallocated = 0;
473 	if (authcrd != NULL) {
474 		authbuf = aesni_cipher_alloc(authcrd, crp, &authallocated);
475 		if (authbuf == NULL) {
476 			error = ENOMEM;
477 			goto out1;
478 		}
479 	}
480 
481 	td = curthread;
482 	error = fpu_kern_enter(td, ses->fpu_ctx, FPU_KERN_NORMAL |
483 	    FPU_KERN_KTHR);
484 	if (error != 0)
485 		goto out1;
486 
487 	if ((enccrd->crd_flags & CRD_F_KEY_EXPLICIT) != 0) {
488 		error = aesni_cipher_setup_common(ses, enccrd->crd_key,
489 		    enccrd->crd_klen);
490 		if (error != 0)
491 			goto out;
492 	}
493 
494 	/* XXX - validate that enccrd and authcrd have/use same key? */
495 	switch (enccrd->crd_alg) {
496 	case CRYPTO_AES_CBC:
497 	case CRYPTO_AES_ICM:
498 		ivlen = AES_BLOCK_LEN;
499 		break;
500 	case CRYPTO_AES_XTS:
501 		ivlen = 8;
502 		break;
503 	case CRYPTO_AES_NIST_GCM_16:
504 		ivlen = 12;	/* should support arbitarily larger */
505 		break;
506 	}
507 
508 	/* Setup ses->iv */
509 	bzero(ses->iv, sizeof ses->iv);
510 	if ((enccrd->crd_flags & CRD_F_IV_EXPLICIT) != 0)
511 		bcopy(enccrd->crd_iv, ses->iv, ivlen);
512 	else if (encflag && ((enccrd->crd_flags & CRD_F_IV_PRESENT) != 0))
513 		arc4rand(ses->iv, ivlen, 0);
514 	else
515 		crypto_copydata(crp->crp_flags, crp->crp_buf,
516 		    enccrd->crd_inject, ivlen, ses->iv);
517 
518 	if (authcrd != NULL && !encflag)
519 		crypto_copydata(crp->crp_flags, crp->crp_buf,
520 		    authcrd->crd_inject, GMAC_DIGEST_LEN, tag);
521 	else
522 		bzero(tag, sizeof tag);
523 
524 	/* Do work */
525 	switch (ses->algo) {
526 	case CRYPTO_AES_CBC:
527 		if (encflag)
528 			aesni_encrypt_cbc(ses->rounds, ses->enc_schedule,
529 			    enccrd->crd_len, buf, buf, ses->iv);
530 		else
531 			aesni_decrypt_cbc(ses->rounds, ses->dec_schedule,
532 			    enccrd->crd_len, buf, ses->iv);
533 		break;
534 	case CRYPTO_AES_ICM:
535 		/* encryption & decryption are the same */
536 		aesni_encrypt_icm(ses->rounds, ses->enc_schedule,
537 		    enccrd->crd_len, buf, buf, ses->iv);
538 		break;
539 	case CRYPTO_AES_XTS:
540 		if (encflag)
541 			aesni_encrypt_xts(ses->rounds, ses->enc_schedule,
542 			    ses->xts_schedule, enccrd->crd_len, buf, buf,
543 			    ses->iv);
544 		else
545 			aesni_decrypt_xts(ses->rounds, ses->dec_schedule,
546 			    ses->xts_schedule, enccrd->crd_len, buf, buf,
547 			    ses->iv);
548 		break;
549 	case CRYPTO_AES_NIST_GCM_16:
550 		if (encflag)
551 			AES_GCM_encrypt(buf, buf, authbuf, ses->iv, tag,
552 			    enccrd->crd_len, authcrd->crd_len, ivlen,
553 			    ses->enc_schedule, ses->rounds);
554 		else {
555 			if (!AES_GCM_decrypt(buf, buf, authbuf, ses->iv, tag,
556 			    enccrd->crd_len, authcrd->crd_len, ivlen,
557 			    ses->enc_schedule, ses->rounds))
558 				error = EBADMSG;
559 		}
560 		break;
561 	}
562 
563 	if (allocated)
564 		crypto_copyback(crp->crp_flags, crp->crp_buf, enccrd->crd_skip,
565 		    enccrd->crd_len, buf);
566 
567 	/*
568 	 * OpenBSD doesn't copy this back.  This primes the IV for the next
569 	 * chain.  Why do we not do it for decrypt?
570 	 */
571 	if (encflag && enccrd->crd_alg == CRYPTO_AES_CBC)
572 		bcopy(buf + enccrd->crd_len - AES_BLOCK_LEN, ses->iv, AES_BLOCK_LEN);
573 
574 	if (!error && authcrd != NULL) {
575 		crypto_copyback(crp->crp_flags, crp->crp_buf,
576 		    authcrd->crd_inject, GMAC_DIGEST_LEN, tag);
577 	}
578 
579 out:
580 	fpu_kern_leave(td, ses->fpu_ctx);
581 out1:
582 	if (allocated) {
583 		bzero(buf, enccrd->crd_len);
584 		free(buf, M_AESNI);
585 	}
586 	if (authallocated)
587 		free(authbuf, M_AESNI);
588 	return (error);
589 }
590