]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/crypto/aesni/aesni.c
MFV r285191: tcpdump 4.7.4.
[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_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 }