aesni.c revision 285216
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: head/sys/crypto/aesni/aesni.c 285216 2015-07-06 19:30:29Z jmg $");
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
52struct 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
59static int aesni_newsession(device_t, uint32_t *sidp, struct cryptoini *cri);
60static int aesni_freesession(device_t, uint64_t tid);
61static void aesni_freesession_locked(struct aesni_softc *sc,
62    struct aesni_session *ses);
63static int aesni_cipher_setup(struct aesni_session *ses,
64    struct cryptoini *encini);
65static int aesni_cipher_process(struct aesni_session *ses,
66    struct cryptodesc *enccrd, struct cryptodesc *authcrd, struct cryptop *crp);
67
68MALLOC_DEFINE(M_AESNI, "aesni_data", "AESNI Data");
69
70static void
71aesni_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
80static int
81aesni_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
98static int
99aesni_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
124static int
125aesni_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
151static int
152aesni_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
237static void
238aesni_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
252static int
253aesni_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
275static int
276aesni_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
362out:
363	crp->crp_etype = error;
364	crypto_done(crp);
365	return (error);
366}
367
368uint8_t *
369aesni_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
394alloc:
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
405static 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
418static driver_t aesni_driver = {
419	"aesni",
420	aesni_methods,
421	sizeof(struct aesni_softc),
422};
423static devclass_t aesni_devclass;
424
425DRIVER_MODULE(aesni, nexus, aesni_driver, aesni_devclass, 0, 0);
426MODULE_VERSION(aesni, 1);
427MODULE_DEPEND(aesni, crypto, 1, 1, 1);
428
429static int
430aesni_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 */
449static int
450aesni_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
580out:
581	fpu_kern_leave(td, ses->fpu_ctx);
582out1:
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