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);
Cache object: 693a798d4b831e2c513619141ec90e52
|