]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/crypto/aesni/aesni.c
MFV r276759: libpcap 1.6.2.
[FreeBSD/FreeBSD.git] / sys / crypto / aesni / aesni.c
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 }