]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/mips/cavium/cryptocteon/cryptocteon.c
Update Apache Serf to 1.3.9 to support OpenSSL 1.1.1.
[FreeBSD/FreeBSD.git] / sys / mips / cavium / cryptocteon / cryptocteon.c
1 /*
2  * Octeon Crypto for OCF
3  *
4  * Written by David McCullough <david_mccullough@securecomputing.com>
5  * Copyright (C) 2009 David McCullough
6  *
7  * LICENSE TERMS
8  *
9  * The free distribution and use of this software in both source and binary
10  * form is allowed (with or without changes) provided that:
11  *
12  *   1. distributions of this source code include the above copyright
13  *      notice, this list of conditions and the following disclaimer;
14  *
15  *   2. distributions in binary form include the above copyright
16  *      notice, this list of conditions and the following disclaimer
17  *      in the documentation and/or other associated materials;
18  *
19  *   3. the copyright holder's name is not used to endorse products
20  *      built using this software without specific written permission.
21  *
22  * DISCLAIMER
23  *
24  * This software is provided 'as is' with no explicit or implied warranties
25  * in respect of its properties, including, but not limited to, correctness
26  * and/or fitness for purpose.
27  * ---------------------------------------------------------------------------
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/bus.h>
36 #include <sys/kernel.h>
37 #include <sys/module.h>
38 #include <sys/malloc.h>
39 #include <sys/mbuf.h>
40 #include <sys/uio.h>
41
42 #include <opencrypto/cryptodev.h>
43
44 #include <contrib/octeon-sdk/cvmx.h>
45
46 #include <mips/cavium/cryptocteon/cryptocteonvar.h>
47
48 #include "cryptodev_if.h"
49
50 struct cryptocteon_softc {
51         int32_t                 sc_cid;         /* opencrypto id */
52 };
53
54 int cryptocteon_debug = 0;
55 TUNABLE_INT("hw.cryptocteon.debug", &cryptocteon_debug);
56
57 static void cryptocteon_identify(driver_t *, device_t);
58 static int cryptocteon_probe(device_t);
59 static int cryptocteon_attach(device_t);
60
61 static int cryptocteon_process(device_t, struct cryptop *, int);
62 static int cryptocteon_newsession(device_t, crypto_session_t, struct cryptoini *);
63
64 static void
65 cryptocteon_identify(driver_t *drv, device_t parent)
66 {
67         if (octeon_has_feature(OCTEON_FEATURE_CRYPTO))
68                 BUS_ADD_CHILD(parent, 0, "cryptocteon", 0);
69 }
70
71 static int
72 cryptocteon_probe(device_t dev)
73 {
74         device_set_desc(dev, "Octeon Secure Coprocessor");
75         return (0);
76 }
77
78 static int
79 cryptocteon_attach(device_t dev)
80 {
81         struct cryptocteon_softc *sc;
82
83         sc = device_get_softc(dev);
84
85         sc->sc_cid = crypto_get_driverid(dev, sizeof(struct octo_sess),
86             CRYPTOCAP_F_HARDWARE | CRYPTOCAP_F_SYNC);
87         if (sc->sc_cid < 0) {
88                 device_printf(dev, "crypto_get_driverid ret %d\n", sc->sc_cid);
89                 return (ENXIO);
90         }
91
92         crypto_register(sc->sc_cid, CRYPTO_MD5_HMAC, 0, 0);
93         crypto_register(sc->sc_cid, CRYPTO_SHA1_HMAC, 0, 0);
94         crypto_register(sc->sc_cid, CRYPTO_DES_CBC, 0, 0);
95         crypto_register(sc->sc_cid, CRYPTO_3DES_CBC, 0, 0);
96         crypto_register(sc->sc_cid, CRYPTO_AES_CBC, 0, 0);
97
98         return (0);
99 }
100
101 /*
102  * Generate a new octo session.  We artifically limit it to a single
103  * hash/cipher or hash-cipher combo just to make it easier, most callers
104  * do not expect more than this anyway.
105  */
106 static int
107 cryptocteon_newsession(device_t dev, crypto_session_t cses,
108     struct cryptoini *cri)
109 {
110         struct cryptoini *c, *encini = NULL, *macini = NULL;
111         struct cryptocteon_softc *sc;
112         struct octo_sess *ocd;
113         int i;
114
115         sc = device_get_softc(dev);
116
117         if (cri == NULL || sc == NULL)
118                 return (EINVAL);
119
120         /*
121          * To keep it simple, we only handle hash, cipher or hash/cipher in a
122          * session,  you cannot currently do multiple ciphers/hashes in one
123          * session even though it would be possibel to code this driver to
124          * handle it.
125          */
126         for (i = 0, c = cri; c && i < 2; i++) {
127                 if (c->cri_alg == CRYPTO_MD5_HMAC ||
128                     c->cri_alg == CRYPTO_SHA1_HMAC ||
129                     c->cri_alg == CRYPTO_NULL_HMAC) {
130                         if (macini) {
131                                 break;
132                         }
133                         macini = c;
134                 }
135                 if (c->cri_alg == CRYPTO_DES_CBC ||
136                     c->cri_alg == CRYPTO_3DES_CBC ||
137                     c->cri_alg == CRYPTO_AES_CBC ||
138                     c->cri_alg == CRYPTO_NULL_CBC) {
139                         if (encini) {
140                                 break;
141                         }
142                         encini = c;
143                 }
144                 c = c->cri_next;
145         }
146         if (!macini && !encini) {
147                 dprintf("%s,%d - EINVAL bad cipher/hash or combination\n",
148                                 __FILE__, __LINE__);
149                 return EINVAL;
150         }
151         if (c) {
152                 dprintf("%s,%d - EINVAL cannot handle chained cipher/hash combos\n",
153                                 __FILE__, __LINE__);
154                 return EINVAL;
155         }
156
157         /*
158          * So we have something we can do, lets setup the session
159          */
160         ocd = crypto_get_driver_session(cses);
161
162         if (encini && encini->cri_key) {
163                 ocd->octo_encklen = (encini->cri_klen + 7) / 8;
164                 memcpy(ocd->octo_enckey, encini->cri_key, ocd->octo_encklen);
165         }
166
167         if (macini && macini->cri_key) {
168                 ocd->octo_macklen = (macini->cri_klen + 7) / 8;
169                 memcpy(ocd->octo_mackey, macini->cri_key, ocd->octo_macklen);
170         }
171
172         ocd->octo_mlen = 0;
173         if (encini && encini->cri_mlen)
174                 ocd->octo_mlen = encini->cri_mlen;
175         else if (macini && macini->cri_mlen)
176                 ocd->octo_mlen = macini->cri_mlen;
177         else
178                 ocd->octo_mlen = 12;
179
180         /*
181          * point c at the enc if it exists, otherwise the mac
182          */
183         c = encini ? encini : macini;
184
185         switch (c->cri_alg) {
186         case CRYPTO_DES_CBC:
187         case CRYPTO_3DES_CBC:
188                 ocd->octo_ivsize  = 8;
189                 switch (macini ? macini->cri_alg : -1) {
190                 case CRYPTO_MD5_HMAC:
191                         ocd->octo_encrypt = octo_des_cbc_md5_encrypt;
192                         ocd->octo_decrypt = octo_des_cbc_md5_decrypt;
193                         octo_calc_hash(0, macini->cri_key, ocd->octo_hminner,
194                                         ocd->octo_hmouter);
195                         break;
196                 case CRYPTO_SHA1_HMAC:
197                         ocd->octo_encrypt = octo_des_cbc_sha1_encrypt;
198                         ocd->octo_decrypt = octo_des_cbc_sha1_encrypt;
199                         octo_calc_hash(1, macini->cri_key, ocd->octo_hminner,
200                                         ocd->octo_hmouter);
201                         break;
202                 case -1:
203                         ocd->octo_encrypt = octo_des_cbc_encrypt;
204                         ocd->octo_decrypt = octo_des_cbc_decrypt;
205                         break;
206                 default:
207                         dprintf("%s,%d: EINVALn", __FILE__, __LINE__);
208                         return EINVAL;
209                 }
210                 break;
211         case CRYPTO_AES_CBC:
212                 ocd->octo_ivsize  = 16;
213                 switch (macini ? macini->cri_alg : -1) {
214                 case CRYPTO_MD5_HMAC:
215                         ocd->octo_encrypt = octo_aes_cbc_md5_encrypt;
216                         ocd->octo_decrypt = octo_aes_cbc_md5_decrypt;
217                         octo_calc_hash(0, macini->cri_key, ocd->octo_hminner,
218                                         ocd->octo_hmouter);
219                         break;
220                 case CRYPTO_SHA1_HMAC:
221                         ocd->octo_encrypt = octo_aes_cbc_sha1_encrypt;
222                         ocd->octo_decrypt = octo_aes_cbc_sha1_decrypt;
223                         octo_calc_hash(1, macini->cri_key, ocd->octo_hminner,
224                                         ocd->octo_hmouter);
225                         break;
226                 case -1:
227                         ocd->octo_encrypt = octo_aes_cbc_encrypt;
228                         ocd->octo_decrypt = octo_aes_cbc_decrypt;
229                         break;
230                 default:
231                         dprintf("%s,%d: EINVALn", __FILE__, __LINE__);
232                         return EINVAL;
233                 }
234                 break;
235         case CRYPTO_MD5_HMAC:
236                 ocd->octo_encrypt = octo_null_md5_encrypt;
237                 ocd->octo_decrypt = octo_null_md5_encrypt;
238                 octo_calc_hash(0, macini->cri_key, ocd->octo_hminner,
239                                 ocd->octo_hmouter);
240                 break;
241         case CRYPTO_SHA1_HMAC:
242                 ocd->octo_encrypt = octo_null_sha1_encrypt;
243                 ocd->octo_decrypt = octo_null_sha1_encrypt;
244                 octo_calc_hash(1, macini->cri_key, ocd->octo_hminner,
245                                 ocd->octo_hmouter);
246                 break;
247         default:
248                 dprintf("%s,%d: EINVALn", __FILE__, __LINE__);
249                 return EINVAL;
250         }
251
252         ocd->octo_encalg = encini ? encini->cri_alg : -1;
253         ocd->octo_macalg = macini ? macini->cri_alg : -1;
254
255         return (0);
256 }
257
258 /*
259  * Process a request.
260  */
261 static int
262 cryptocteon_process(device_t dev, struct cryptop *crp, int hint)
263 {
264         struct cryptodesc *crd;
265         struct octo_sess *od;
266         size_t iovcnt, iovlen;
267         struct mbuf *m = NULL;
268         struct uio *uiop = NULL;
269         struct cryptodesc *enccrd = NULL, *maccrd = NULL;
270         unsigned char *ivp = NULL;
271         unsigned char iv_data[HASH_MAX_LEN];
272         int auth_off = 0, auth_len = 0, crypt_off = 0, crypt_len = 0, icv_off = 0;
273         struct cryptocteon_softc *sc;
274
275         sc = device_get_softc(dev);
276
277         if (sc == NULL || crp == NULL)
278                 return EINVAL;
279
280         crp->crp_etype = 0;
281
282         if (crp->crp_desc == NULL || crp->crp_buf == NULL) {
283                 dprintf("%s,%d: EINVAL\n", __FILE__, __LINE__);
284                 crp->crp_etype = EINVAL;
285                 goto done;
286         }
287
288         od = crypto_get_driver_session(crp->crp_session);
289
290         /*
291          * do some error checking outside of the loop for m and IOV processing
292          * this leaves us with valid m or uiop pointers for later
293          */
294         if (crp->crp_flags & CRYPTO_F_IMBUF) {
295                 unsigned frags;
296
297                 m = (struct mbuf *) crp->crp_buf;
298                 for (frags = 0; m != NULL; frags++)
299                         m = m->m_next;
300
301                 if (frags >= UIO_MAXIOV) {
302                         printf("%s,%d: %d frags > UIO_MAXIOV", __FILE__, __LINE__, frags);
303                         goto done;
304                 }
305
306                 m = (struct mbuf *) crp->crp_buf;
307         } else if (crp->crp_flags & CRYPTO_F_IOV) {
308                 uiop = (struct uio *) crp->crp_buf;
309                 if (uiop->uio_iovcnt > UIO_MAXIOV) {
310                         printf("%s,%d: %d uio_iovcnt > UIO_MAXIOV", __FILE__, __LINE__,
311                                uiop->uio_iovcnt);
312                         goto done;
313                 }
314         }
315
316         /* point our enccrd and maccrd appropriately */
317         crd = crp->crp_desc;
318         if (crd->crd_alg == od->octo_encalg)
319                 enccrd = crd;
320         if (crd->crd_alg == od->octo_macalg)
321                 maccrd = crd;
322         crd = crd->crd_next;
323         if (crd) {
324                 if (crd->crd_alg == od->octo_encalg)
325                         enccrd = crd;
326                 if (crd->crd_alg == od->octo_macalg)
327                         maccrd = crd;
328                 crd = crd->crd_next;
329         }
330         if (crd) {
331                 crp->crp_etype = EINVAL;
332                 dprintf("%s,%d: ENOENT - descriptors do not match session\n",
333                                 __FILE__, __LINE__);
334                 goto done;
335         }
336
337         if (enccrd) {
338                 if (enccrd->crd_flags & CRD_F_IV_EXPLICIT) {
339                         ivp = enccrd->crd_iv;
340                 } else {
341                         ivp = iv_data;
342                         crypto_copydata(crp->crp_flags, crp->crp_buf,
343                                         enccrd->crd_inject, od->octo_ivsize, (caddr_t) ivp);
344                 }
345
346                 if (maccrd) {
347                         auth_off = maccrd->crd_skip;
348                         auth_len = maccrd->crd_len;
349                         icv_off  = maccrd->crd_inject;
350                 }
351
352                 crypt_off = enccrd->crd_skip;
353                 crypt_len = enccrd->crd_len;
354         } else { /* if (maccrd) */
355                 auth_off = maccrd->crd_skip;
356                 auth_len = maccrd->crd_len;
357                 icv_off  = maccrd->crd_inject;
358         }
359
360         /*
361          * setup the I/O vector to cover the buffer
362          */
363         if (crp->crp_flags & CRYPTO_F_IMBUF) {
364                 iovcnt = 0;
365                 iovlen = 0;
366
367                 while (m != NULL) {
368                         od->octo_iov[iovcnt].iov_base = mtod(m, void *);
369                         od->octo_iov[iovcnt].iov_len = m->m_len;
370
371                         m = m->m_next;
372                         iovlen += od->octo_iov[iovcnt++].iov_len;
373                 }
374         } else if (crp->crp_flags & CRYPTO_F_IOV) {
375                 iovlen = 0;
376                 for (iovcnt = 0; iovcnt < uiop->uio_iovcnt; iovcnt++) {
377                         od->octo_iov[iovcnt].iov_base = uiop->uio_iov[iovcnt].iov_base;
378                         od->octo_iov[iovcnt].iov_len = uiop->uio_iov[iovcnt].iov_len;
379
380                         iovlen += od->octo_iov[iovcnt].iov_len;
381                 }
382         } else {
383                 iovlen = crp->crp_ilen;
384                 od->octo_iov[0].iov_base = crp->crp_buf;
385                 od->octo_iov[0].iov_len = crp->crp_ilen;
386                 iovcnt = 1;
387         }
388
389
390         /*
391          * setup a new explicit key
392          */
393         if (enccrd) {
394                 if (enccrd->crd_flags & CRD_F_KEY_EXPLICIT) {
395                         od->octo_encklen = (enccrd->crd_klen + 7) / 8;
396                         memcpy(od->octo_enckey, enccrd->crd_key, od->octo_encklen);
397                 }
398         }
399         if (maccrd) {
400                 if (maccrd->crd_flags & CRD_F_KEY_EXPLICIT) {
401                         od->octo_macklen = (maccrd->crd_klen + 7) / 8;
402                         memcpy(od->octo_mackey, maccrd->crd_key, od->octo_macklen);
403                         od->octo_mackey_set = 0;
404                 }
405                 if (!od->octo_mackey_set) {
406                         octo_calc_hash(maccrd->crd_alg == CRYPTO_MD5_HMAC ? 0 : 1,
407                                 maccrd->crd_key, od->octo_hminner, od->octo_hmouter);
408                         od->octo_mackey_set = 1;
409                 }
410         }
411
412
413         if (!enccrd || (enccrd->crd_flags & CRD_F_ENCRYPT))
414                 (*od->octo_encrypt)(od, od->octo_iov, iovcnt, iovlen,
415                                 auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp);
416         else
417                 (*od->octo_decrypt)(od, od->octo_iov, iovcnt, iovlen,
418                                 auth_off, auth_len, crypt_off, crypt_len, icv_off, ivp);
419
420 done:
421         crypto_done(crp);
422         return (0);
423 }
424
425 static device_method_t cryptocteon_methods[] = {
426         /* device methods */
427         DEVMETHOD(device_identify,      cryptocteon_identify),
428         DEVMETHOD(device_probe,         cryptocteon_probe),
429         DEVMETHOD(device_attach,        cryptocteon_attach),
430
431         /* crypto device methods */
432         DEVMETHOD(cryptodev_newsession, cryptocteon_newsession),
433         DEVMETHOD(cryptodev_process,    cryptocteon_process),
434
435         { 0, 0 }
436 };
437
438 static driver_t cryptocteon_driver = {
439         "cryptocteon",
440         cryptocteon_methods,
441         sizeof (struct cryptocteon_softc),
442 };
443 static devclass_t cryptocteon_devclass;
444 DRIVER_MODULE(cryptocteon, nexus, cryptocteon_driver, cryptocteon_devclass, 0, 0);