xref: /freebsd/sys/crypto/aesni/aesni.c (revision fe3ff217dd5c53ef0b0a5cd7a1142095ba4ecf63)
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_NOWAIT);
210 		if (ses->fpu_ctx == NULL) {
211 			free(ses, M_AESNI);
212 			rw_wunlock(&sc->lock);
213 			return (ENOMEM);
214 		}
215 		ses->id = sc->sid++;
216 	} else {
217 		TAILQ_REMOVE(&sc->sessions, ses, next);
218 	}
219 	ses->used = 1;
220 	TAILQ_INSERT_TAIL(&sc->sessions, ses, next);
221 	rw_wunlock(&sc->lock);
222 	ses->algo = encini->cri_alg;
223 
224 	error = aesni_cipher_setup(ses, encini);
225 	if (error != 0) {
226 		CRYPTDEB("setup failed");
227 		rw_wlock(&sc->lock);
228 		aesni_freesession_locked(sc, ses);
229 		rw_wunlock(&sc->lock);
230 		return (error);
231 	}
232 
233 	*sidp = ses->id;
234 	return (0);
235 }
236 
237 static void
238 aesni_freesession_locked(struct aesni_softc *sc, struct aesni_session *ses)
239 {
240 	struct fpu_kern_ctx *ctx;
241 	uint32_t sid;
242 
243 	sid = ses->id;
244 	TAILQ_REMOVE(&sc->sessions, ses, next);
245 	ctx = ses->fpu_ctx;
246 	*ses = (struct aesni_session){};
247 	ses->id = sid;
248 	ses->fpu_ctx = ctx;
249 	TAILQ_INSERT_HEAD(&sc->sessions, ses, next);
250 }
251 
252 static int
253 aesni_freesession(device_t dev, uint64_t tid)
254 {
255 	struct aesni_softc *sc;
256 	struct aesni_session *ses;
257 	uint32_t sid;
258 
259 	sc = device_get_softc(dev);
260 	sid = ((uint32_t)tid) & 0xffffffff;
261 	rw_wlock(&sc->lock);
262 	TAILQ_FOREACH_REVERSE(ses, &sc->sessions, aesni_sessions_head, next) {
263 		if (ses->id == sid)
264 			break;
265 	}
266 	if (ses == NULL) {
267 		rw_wunlock(&sc->lock);
268 		return (EINVAL);
269 	}
270 	aesni_freesession_locked(sc, ses);
271 	rw_wunlock(&sc->lock);
272 	return (0);
273 }
274 
275 static int
276 aesni_process(device_t dev, struct cryptop *crp, int hint __unused)
277 {
278 	struct aesni_softc *sc = device_get_softc(dev);
279 	struct aesni_session *ses = NULL;
280 	struct cryptodesc *crd, *enccrd, *authcrd;
281 	int error, needauth;
282 
283 	error = 0;
284 	enccrd = NULL;
285 	authcrd = NULL;
286 	needauth = 0;
287 
288 	/* Sanity check. */
289 	if (crp == NULL)
290 		return (EINVAL);
291 
292 	if (crp->crp_callback == NULL || crp->crp_desc == NULL) {
293 		error = EINVAL;
294 		goto out;
295 	}
296 
297 	for (crd = crp->crp_desc; crd != NULL; crd = crd->crd_next) {
298 		switch (crd->crd_alg) {
299 		case CRYPTO_AES_CBC:
300 		case CRYPTO_AES_ICM:
301 		case CRYPTO_AES_XTS:
302 			if (enccrd != NULL) {
303 				error = EINVAL;
304 				goto out;
305 			}
306 			enccrd = crd;
307 			break;
308 
309 		case CRYPTO_AES_NIST_GCM_16:
310 			if (enccrd != NULL) {
311 				error = EINVAL;
312 				goto out;
313 			}
314 			enccrd = crd;
315 			needauth = 1;
316 			break;
317 
318 		case CRYPTO_AES_128_NIST_GMAC:
319 		case CRYPTO_AES_192_NIST_GMAC:
320 		case CRYPTO_AES_256_NIST_GMAC:
321 			if (authcrd != NULL) {
322 				error = EINVAL;
323 				goto out;
324 			}
325 			authcrd = crd;
326 			needauth = 1;
327 			break;
328 
329 		default:
330 			error = EINVAL;
331 			goto out;
332 		}
333 	}
334 
335 	if (enccrd == NULL || (needauth && authcrd == NULL)) {
336 		error = EINVAL;
337 		goto out;
338 	}
339 
340 	/* CBC & XTS can only handle full blocks for now */
341 	if ((enccrd->crd_alg == CRYPTO_AES_CBC || enccrd->crd_alg ==
342 	    CRYPTO_AES_XTS) && (enccrd->crd_len % AES_BLOCK_LEN) != 0) {
343 		error = EINVAL;
344 		goto out;
345 	}
346 
347 	rw_rlock(&sc->lock);
348 	TAILQ_FOREACH_REVERSE(ses, &sc->sessions, aesni_sessions_head, next) {
349 		if (ses->id == (crp->crp_sid & 0xffffffff))
350 			break;
351 	}
352 	rw_runlock(&sc->lock);
353 	if (ses == NULL) {
354 		error = EINVAL;
355 		goto out;
356 	}
357 
358 	error = aesni_cipher_process(ses, enccrd, authcrd, crp);
359 	if (error != 0)
360 		goto out;
361 
362 out:
363 	crp->crp_etype = error;
364 	crypto_done(crp);
365 	return (error);
366 }
367 
368 uint8_t *
369 aesni_cipher_alloc(struct cryptodesc *enccrd, struct cryptop *crp,
370     int *allocated)
371 {
372 	struct mbuf *m;
373 	struct uio *uio;
374 	struct iovec *iov;
375 	uint8_t *addr;
376 
377 	if (crp->crp_flags & CRYPTO_F_IMBUF) {
378 		m = (struct mbuf *)crp->crp_buf;
379 		if (m->m_next != NULL)
380 			goto alloc;
381 		addr = mtod(m, uint8_t *);
382 	} else if (crp->crp_flags & CRYPTO_F_IOV) {
383 		uio = (struct uio *)crp->crp_buf;
384 		if (uio->uio_iovcnt != 1)
385 			goto alloc;
386 		iov = uio->uio_iov;
387 		addr = (uint8_t *)iov->iov_base;
388 	} else
389 		addr = (uint8_t *)crp->crp_buf;
390 	*allocated = 0;
391 	addr += enccrd->crd_skip;
392 	return (addr);
393 
394 alloc:
395 	addr = malloc(enccrd->crd_len, M_AESNI, M_NOWAIT);
396 	if (addr != NULL) {
397 		*allocated = 1;
398 		crypto_copydata(crp->crp_flags, crp->crp_buf, enccrd->crd_skip,
399 		    enccrd->crd_len, addr);
400 	} else
401 		*allocated = 0;
402 	return (addr);
403 }
404 
405 static device_method_t aesni_methods[] = {
406 	DEVMETHOD(device_identify, aesni_identify),
407 	DEVMETHOD(device_probe, aesni_probe),
408 	DEVMETHOD(device_attach, aesni_attach),
409 	DEVMETHOD(device_detach, aesni_detach),
410 
411 	DEVMETHOD(cryptodev_newsession, aesni_newsession),
412 	DEVMETHOD(cryptodev_freesession, aesni_freesession),
413 	DEVMETHOD(cryptodev_process, aesni_process),
414 
415 	{0, 0},
416 };
417 
418 static driver_t aesni_driver = {
419 	"aesni",
420 	aesni_methods,
421 	sizeof(struct aesni_softc),
422 };
423 static devclass_t aesni_devclass;
424 
425 DRIVER_MODULE(aesni, nexus, aesni_driver, aesni_devclass, 0, 0);
426 MODULE_VERSION(aesni, 1);
427 MODULE_DEPEND(aesni, crypto, 1, 1, 1);
428 
429 static int
430 aesni_cipher_setup(struct aesni_session *ses, struct cryptoini *encini)
431 {
432 	struct thread *td;
433 	int error;
434 
435 	td = curthread;
436 	error = fpu_kern_enter(td, ses->fpu_ctx, FPU_KERN_NORMAL |
437 	    FPU_KERN_KTHR);
438 	if (error != 0)
439 		return (error);
440 	error = aesni_cipher_setup_common(ses, encini->cri_key,
441 	    encini->cri_klen);
442 	fpu_kern_leave(td, ses->fpu_ctx);
443 	return (error);
444 }
445 
446 /*
447  * authcrd contains the associated date.
448  */
449 static int
450 aesni_cipher_process(struct aesni_session *ses, struct cryptodesc *enccrd,
451     struct cryptodesc *authcrd, struct cryptop *crp)
452 {
453 	uint8_t iv[AES_BLOCK_LEN];
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 iv */
509 	if (encflag) {
510 		if ((enccrd->crd_flags & CRD_F_IV_EXPLICIT) != 0)
511 			bcopy(enccrd->crd_iv, iv, ivlen);
512 		else
513 			arc4rand(iv, ivlen, 0);
514 
515 		if ((enccrd->crd_flags & CRD_F_IV_PRESENT) == 0)
516 			crypto_copyback(crp->crp_flags, crp->crp_buf,
517 			    enccrd->crd_inject, ivlen, iv);
518 	} else {
519 		if ((enccrd->crd_flags & CRD_F_IV_EXPLICIT) != 0)
520 			bcopy(enccrd->crd_iv, iv, ivlen);
521 		else
522 			crypto_copydata(crp->crp_flags, crp->crp_buf,
523 			    enccrd->crd_inject, ivlen, iv);
524 	}
525 
526 	if (authcrd != NULL && !encflag)
527 		crypto_copydata(crp->crp_flags, crp->crp_buf,
528 		    authcrd->crd_inject, GMAC_DIGEST_LEN, tag);
529 	else
530 		bzero(tag, sizeof tag);
531 
532 	/* Do work */
533 	switch (ses->algo) {
534 	case CRYPTO_AES_CBC:
535 		if (encflag)
536 			aesni_encrypt_cbc(ses->rounds, ses->enc_schedule,
537 			    enccrd->crd_len, buf, buf, iv);
538 		else
539 			aesni_decrypt_cbc(ses->rounds, ses->dec_schedule,
540 			    enccrd->crd_len, buf, iv);
541 		break;
542 	case CRYPTO_AES_ICM:
543 		/* encryption & decryption are the same */
544 		aesni_encrypt_icm(ses->rounds, ses->enc_schedule,
545 		    enccrd->crd_len, buf, buf, iv);
546 		break;
547 	case CRYPTO_AES_XTS:
548 		if (encflag)
549 			aesni_encrypt_xts(ses->rounds, ses->enc_schedule,
550 			    ses->xts_schedule, enccrd->crd_len, buf, buf,
551 			    iv);
552 		else
553 			aesni_decrypt_xts(ses->rounds, ses->dec_schedule,
554 			    ses->xts_schedule, enccrd->crd_len, buf, buf,
555 			    iv);
556 		break;
557 	case CRYPTO_AES_NIST_GCM_16:
558 		if (encflag)
559 			AES_GCM_encrypt(buf, buf, authbuf, iv, tag,
560 			    enccrd->crd_len, authcrd->crd_len, ivlen,
561 			    ses->enc_schedule, ses->rounds);
562 		else {
563 			if (!AES_GCM_decrypt(buf, buf, authbuf, iv, tag,
564 			    enccrd->crd_len, authcrd->crd_len, ivlen,
565 			    ses->enc_schedule, ses->rounds))
566 				error = EBADMSG;
567 		}
568 		break;
569 	}
570 
571 	if (allocated)
572 		crypto_copyback(crp->crp_flags, crp->crp_buf, enccrd->crd_skip,
573 		    enccrd->crd_len, buf);
574 
575 	if (!error && authcrd != NULL) {
576 		crypto_copyback(crp->crp_flags, crp->crp_buf,
577 		    authcrd->crd_inject, GMAC_DIGEST_LEN, tag);
578 	}
579 
580 out:
581 	fpu_kern_leave(td, ses->fpu_ctx);
582 out1:
583 	if (allocated) {
584 		bzero(buf, enccrd->crd_len);
585 		free(buf, M_AESNI);
586 	}
587 	if (authallocated)
588 		free(authbuf, M_AESNI);
589 	return (error);
590 }
591