1 /*-
2 * Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3 * Copyright (c) 2004 Mark R V Murray
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 /* $OpenBSD: via.c,v 1.3 2004/06/15 23:36:55 deraadt Exp $ */
29 /*-
30 * Copyright (c) 2003 Jason Wright
31 * Copyright (c) 2003, 2004 Theo de Raadt
32 * All rights reserved.
33 *
34 * Permission to use, copy, modify, and distribute this software for any
35 * purpose with or without fee is hereby granted, provided that the above
36 * copyright notice and this permission notice appear in all copies.
37 *
38 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
39 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
40 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
41 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
42 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
43 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
44 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
45 */
46
47 #include <sys/cdefs.h>
48 __FBSDID("$FreeBSD: releng/6.0/sys/crypto/via/padlock.c 149621 2005-08-30 14:56:02Z pjd $");
49
50 #include <sys/param.h>
51 #include <sys/systm.h>
52 #include <sys/kernel.h>
53 #include <sys/module.h>
54 #include <sys/lock.h>
55 #include <sys/mutex.h>
56 #include <sys/malloc.h>
57 #include <sys/libkern.h>
58 #include <sys/mbuf.h>
59 #include <sys/uio.h>
60 #if defined(__i386__) && !defined(PC98)
61 #include <machine/cpufunc.h>
62 #include <machine/cputypes.h>
63 #endif
64
65 #include <opencrypto/cryptodev.h>
66 #include <crypto/rijndael/rijndael.h>
67
68
69 #define PADLOCK_ROUND_COUNT_AES128 10
70 #define PADLOCK_ROUND_COUNT_AES192 12
71 #define PADLOCK_ROUND_COUNT_AES256 14
72
73 #define PADLOCK_ALGORITHM_TYPE_AES 0
74
75 #define PADLOCK_KEY_GENERATION_HW 0
76 #define PADLOCK_KEY_GENERATION_SW 1
77
78 #define PADLOCK_DIRECTION_ENCRYPT 0
79 #define PADLOCK_DIRECTION_DECRYPT 1
80
81 #define PADLOCK_KEY_SIZE_128 0
82 #define PADLOCK_KEY_SIZE_192 1
83 #define PADLOCK_KEY_SIZE_256 2
84
85 union padlock_cw {
86 uint64_t raw;
87 struct {
88 u_int round_count : 4;
89 u_int algorithm_type : 3;
90 u_int key_generation : 1;
91 u_int intermediate : 1;
92 u_int direction : 1;
93 u_int key_size : 2;
94 u_int filler0 : 20;
95 u_int filler1 : 32;
96 u_int filler2 : 32;
97 u_int filler3 : 32;
98 } __field;
99 };
100 #define cw_round_count __field.round_count
101 #define cw_algorithm_type __field.algorithm_type
102 #define cw_key_generation __field.key_generation
103 #define cw_intermediate __field.intermediate
104 #define cw_direction __field.direction
105 #define cw_key_size __field.key_size
106 #define cw_filler0 __field.filler0
107 #define cw_filler1 __field.filler1
108 #define cw_filler2 __field.filler2
109 #define cw_filler3 __field.filler3
110
111 struct padlock_session {
112 union padlock_cw ses_cw __aligned(16);
113 uint32_t ses_ekey[4 * (RIJNDAEL_MAXNR + 1) + 4] __aligned(16); /* 128 bit aligned */
114 uint32_t ses_dkey[4 * (RIJNDAEL_MAXNR + 1) + 4] __aligned(16); /* 128 bit aligned */
115 uint8_t ses_iv[16] __aligned(16); /* 128 bit aligned */
116 int ses_used;
117 uint32_t ses_id;
118 TAILQ_ENTRY(padlock_session) ses_next;
119 };
120
121 struct padlock_softc {
122 int32_t sc_cid;
123 uint32_t sc_sid;
124 TAILQ_HEAD(, padlock_session) sc_sessions;
125 struct mtx sc_sessions_mtx;
126 };
127
128 static struct padlock_softc *padlock_sc;
129
130 static int padlock_newsession(void *arg __unused, uint32_t *sidp,
131 struct cryptoini *cri);
132 static int padlock_freesession(void *arg __unused, uint64_t tid);
133 static int padlock_process(void *arg __unused, struct cryptop *crp,
134 int hint __unused);
135
136 static __inline void
137 padlock_cbc(void *in, void *out, size_t count, void *key, union padlock_cw *cw,
138 void *iv)
139 {
140 #ifdef __GNUCLIKE_ASM
141 /* The .byte line is really VIA C3 "xcrypt-cbc" instruction */
142 __asm __volatile(
143 "pushf \n\t"
144 "popf \n\t"
145 "rep \n\t"
146 ".byte 0x0f, 0xa7, 0xd0"
147 : "+a" (iv), "+c" (count), "+D" (out), "+S" (in)
148 : "b" (key), "d" (cw)
149 : "cc", "memory"
150 );
151 #endif
152 }
153
154 static int
155 padlock_init(void)
156 {
157 struct padlock_softc *sc;
158 #if defined(__i386__) && !defined(PC98)
159 u_int regs[4];
160 int has_ace = 0;
161
162 if (cpu_class < CPUCLASS_586)
163 return (EINVAL);
164 do_cpuid(1, regs);
165 if ((regs[0] & 0xf) >= 3) {
166 do_cpuid(0xc0000000, regs);
167 if (regs[0] == 0xc0000001) {
168 do_cpuid(0xc0000001, regs);
169 if ((regs[3] & 0xc0) == 0xc0)
170 has_ace = 1;
171 }
172 }
173 if (!has_ace) {
174 printf("PADLOCK: No ACE support.\n");
175 return (EINVAL);
176 }
177 #else
178 return (EINVAL);
179 #endif
180
181 padlock_sc = sc = malloc(sizeof(*padlock_sc), M_DEVBUF,
182 M_NOWAIT | M_ZERO);
183 if (padlock_sc == NULL) {
184 printf("PADLOCK: Could not allocate memory.\n");
185 return (ENOMEM);
186 }
187 TAILQ_INIT(&sc->sc_sessions);
188 sc->sc_sid = 1;
189
190 sc->sc_cid = crypto_get_driverid(0);
191 if (sc->sc_cid < 0) {
192 printf("PADLOCK: Could not get crypto driver id.\n");
193 free(padlock_sc, M_DEVBUF);
194 padlock_sc = NULL;
195 return (ENOMEM);
196 }
197
198 mtx_init(&sc->sc_sessions_mtx, "padlock_mtx", NULL, MTX_DEF);
199 crypto_register(sc->sc_cid, CRYPTO_AES_CBC, 0, 0, padlock_newsession,
200 padlock_freesession, padlock_process, NULL);
201 return (0);
202 }
203
204 static int
205 padlock_destroy(void)
206 {
207 struct padlock_softc *sc = padlock_sc;
208 struct padlock_session *ses;
209 u_int active = 0;
210
211 if (sc == NULL)
212 return (0);
213 mtx_lock(&sc->sc_sessions_mtx);
214 TAILQ_FOREACH(ses, &sc->sc_sessions, ses_next) {
215 if (ses->ses_used)
216 active++;
217 }
218 if (active > 0) {
219 mtx_unlock(&sc->sc_sessions_mtx);
220 printf("PADLOCK: Cannot destroy, %u sessions active.\n",
221 active);
222 return (EBUSY);
223 }
224 padlock_sc = NULL;
225 for (ses = TAILQ_FIRST(&sc->sc_sessions); ses != NULL;
226 ses = TAILQ_FIRST(&sc->sc_sessions)) {
227 TAILQ_REMOVE(&sc->sc_sessions, ses, ses_next);
228 free(ses, M_DEVBUF);
229 }
230 mtx_destroy(&sc->sc_sessions_mtx);
231 crypto_unregister_all(sc->sc_cid);
232 free(sc, M_DEVBUF);
233 return (0);
234 }
235
236 static int
237 padlock_newsession(void *arg __unused, uint32_t *sidp, struct cryptoini *cri)
238 {
239 struct padlock_softc *sc = padlock_sc;
240 struct padlock_session *ses = NULL;
241 union padlock_cw *cw;
242 int i;
243
244 if (sc == NULL || sidp == NULL || cri == NULL ||
245 cri->cri_next != NULL || cri->cri_alg != CRYPTO_AES_CBC) {
246 return (EINVAL);
247 }
248 if (cri->cri_klen != 128 && cri->cri_klen != 192 &&
249 cri->cri_klen != 256) {
250 return (EINVAL);
251 }
252
253 /*
254 * Let's look for a free session structure.
255 */
256 mtx_lock(&sc->sc_sessions_mtx);
257 /*
258 * Free sessions goes first, so if first session is used, we need to
259 * allocate one.
260 */
261 ses = TAILQ_FIRST(&sc->sc_sessions);
262 if (ses == NULL || ses->ses_used)
263 ses = NULL;
264 else {
265 TAILQ_REMOVE(&sc->sc_sessions, ses, ses_next);
266 ses->ses_used = 1;
267 TAILQ_INSERT_TAIL(&sc->sc_sessions, ses, ses_next);
268 }
269 mtx_unlock(&sc->sc_sessions_mtx);
270 if (ses == NULL) {
271 ses = malloc(sizeof(*ses), M_DEVBUF, M_NOWAIT | M_ZERO);
272 if (ses == NULL)
273 return (ENOMEM);
274 ses->ses_used = 1;
275 mtx_lock(&sc->sc_sessions_mtx);
276 ses->ses_id = sc->sc_sid++;
277 TAILQ_INSERT_TAIL(&sc->sc_sessions, ses, ses_next);
278 mtx_unlock(&sc->sc_sessions_mtx);
279 }
280
281 cw = &ses->ses_cw;
282 bzero(cw, sizeof(*cw));
283 cw->cw_algorithm_type = PADLOCK_ALGORITHM_TYPE_AES;
284 cw->cw_key_generation = PADLOCK_KEY_GENERATION_SW;
285 cw->cw_intermediate = 0;
286 switch (cri->cri_klen) {
287 case 128:
288 cw->cw_round_count = PADLOCK_ROUND_COUNT_AES128;
289 cw->cw_key_size = PADLOCK_KEY_SIZE_128;
290 #ifdef HW_KEY_GENERATION
291 /* This doesn't buy us much, that's why it is commented out. */
292 cw->cw_key_generation = PADLOCK_KEY_GENERATION_HW;
293 #endif
294 break;
295 case 192:
296 cw->cw_round_count = PADLOCK_ROUND_COUNT_AES192;
297 cw->cw_key_size = PADLOCK_KEY_SIZE_192;
298 break;
299 case 256:
300 cw->cw_round_count = PADLOCK_ROUND_COUNT_AES256;
301 cw->cw_key_size = PADLOCK_KEY_SIZE_256;
302 break;
303 }
304
305 arc4rand(ses->ses_iv, sizeof(ses->ses_iv), 0);
306
307 if (cw->cw_key_generation == PADLOCK_KEY_GENERATION_SW) {
308 /* Build expanded keys for both directions */
309 rijndaelKeySetupEnc(ses->ses_ekey, cri->cri_key, cri->cri_klen);
310 rijndaelKeySetupDec(ses->ses_dkey, cri->cri_key, cri->cri_klen);
311 for (i = 0; i < 4 * (RIJNDAEL_MAXNR + 1); i++) {
312 ses->ses_ekey[i] = ntohl(ses->ses_ekey[i]);
313 ses->ses_dkey[i] = ntohl(ses->ses_dkey[i]);
314 }
315 } else {
316 bcopy(cri->cri_key, ses->ses_ekey, cri->cri_klen);
317 bcopy(cri->cri_key, ses->ses_dkey, cri->cri_klen);
318 }
319
320 *sidp = ses->ses_id;
321 return (0);
322 }
323
324 static int
325 padlock_freesession(void *arg __unused, uint64_t tid)
326 {
327 struct padlock_softc *sc = padlock_sc;
328 struct padlock_session *ses;
329 uint32_t sid = ((uint32_t)tid) & 0xffffffff;
330
331 if (sc == NULL)
332 return (EINVAL);
333 mtx_lock(&sc->sc_sessions_mtx);
334 TAILQ_FOREACH(ses, &sc->sc_sessions, ses_next) {
335 if (ses->ses_id == sid)
336 break;
337 }
338 if (ses == NULL) {
339 mtx_unlock(&sc->sc_sessions_mtx);
340 return (EINVAL);
341 }
342 TAILQ_REMOVE(&sc->sc_sessions, ses, ses_next);
343 bzero(ses, sizeof(ses));
344 ses->ses_used = 0;
345 TAILQ_INSERT_TAIL(&sc->sc_sessions, ses, ses_next);
346 mtx_unlock(&sc->sc_sessions_mtx);
347 return (0);
348 }
349
350 static int
351 padlock_process(void *arg __unused, struct cryptop *crp, int hint __unused)
352 {
353 struct padlock_softc *sc = padlock_sc;
354 struct padlock_session *ses;
355 union padlock_cw *cw;
356 struct cryptodesc *crd = NULL;
357 uint32_t *key;
358 u_char *buf, *abuf;
359 int err = 0;
360
361 buf = NULL;
362 if (crp == NULL || crp->crp_callback == NULL) {
363 err = EINVAL;
364 goto out;
365 }
366 crd = crp->crp_desc;
367 if (crd == NULL || crd->crd_next != NULL ||
368 crd->crd_alg != CRYPTO_AES_CBC ||
369 (crd->crd_len % 16) != 0) {
370 err = EINVAL;
371 goto out;
372 }
373
374 mtx_lock(&sc->sc_sessions_mtx);
375 TAILQ_FOREACH(ses, &sc->sc_sessions, ses_next) {
376 if (ses->ses_id == (crp->crp_sid & 0xffffffff))
377 break;
378 }
379 mtx_unlock(&sc->sc_sessions_mtx);
380 if (ses == NULL) {
381 err = EINVAL;
382 goto out;
383 }
384
385 buf = malloc(crd->crd_len + 16, M_DEVBUF, M_NOWAIT);
386 if (buf == NULL) {
387 err = ENOMEM;
388 goto out;
389 }
390 abuf = buf + 16 - ((uintptr_t)buf % 16);
391
392 cw = &ses->ses_cw;
393 cw->cw_filler0 = 0;
394 cw->cw_filler1 = 0;
395 cw->cw_filler2 = 0;
396 cw->cw_filler3 = 0;
397 if ((crd->crd_flags & CRD_F_ENCRYPT) != 0) {
398 cw->cw_direction = PADLOCK_DIRECTION_ENCRYPT;
399 key = ses->ses_ekey;
400 if ((crd->crd_flags & CRD_F_IV_EXPLICIT) != 0)
401 bcopy(crd->crd_iv, ses->ses_iv, 16);
402
403 if ((crd->crd_flags & CRD_F_IV_PRESENT) == 0) {
404 if ((crp->crp_flags & CRYPTO_F_IMBUF) != 0) {
405 m_copyback((struct mbuf *)crp->crp_buf,
406 crd->crd_inject, 16, ses->ses_iv);
407 } else if ((crp->crp_flags & CRYPTO_F_IOV) != 0) {
408 cuio_copyback((struct uio *)crp->crp_buf,
409 crd->crd_inject, 16, ses->ses_iv);
410 } else {
411 bcopy(ses->ses_iv,
412 crp->crp_buf + crd->crd_inject, 16);
413 }
414 }
415 } else {
416 cw->cw_direction = PADLOCK_DIRECTION_DECRYPT;
417 key = ses->ses_dkey;
418 if ((crd->crd_flags & CRD_F_IV_EXPLICIT) != 0)
419 bcopy(crd->crd_iv, ses->ses_iv, 16);
420 else {
421 if ((crp->crp_flags & CRYPTO_F_IMBUF) != 0) {
422 m_copydata((struct mbuf *)crp->crp_buf,
423 crd->crd_inject, 16, ses->ses_iv);
424 } else if ((crp->crp_flags & CRYPTO_F_IOV) != 0) {
425 cuio_copydata((struct uio *)crp->crp_buf,
426 crd->crd_inject, 16, ses->ses_iv);
427 } else {
428 bcopy(crp->crp_buf + crd->crd_inject,
429 ses->ses_iv, 16);
430 }
431 }
432 }
433
434 if ((crp->crp_flags & CRYPTO_F_IMBUF) != 0) {
435 m_copydata((struct mbuf *)crp->crp_buf, crd->crd_skip,
436 crd->crd_len, abuf);
437 } else if ((crp->crp_flags & CRYPTO_F_IOV) != 0) {
438 cuio_copydata((struct uio *)crp->crp_buf, crd->crd_skip,
439 crd->crd_len, abuf);
440 } else {
441 bcopy(crp->crp_buf + crd->crd_skip, abuf, crd->crd_len);
442 }
443
444 padlock_cbc(abuf, abuf, crd->crd_len / 16, key, cw, ses->ses_iv);
445
446 if ((crp->crp_flags & CRYPTO_F_IMBUF) != 0) {
447 m_copyback((struct mbuf *)crp->crp_buf, crd->crd_skip,
448 crd->crd_len, abuf);
449 } else if ((crp->crp_flags & CRYPTO_F_IOV) != 0) {
450 cuio_copyback((struct uio *)crp->crp_buf, crd->crd_skip,
451 crd->crd_len, abuf);
452 } else {
453 bcopy(abuf, crp->crp_buf + crd->crd_skip, crd->crd_len);
454 }
455
456 /* copy out last block for use as next session IV */
457 if ((crd->crd_flags & CRD_F_ENCRYPT) != 0) {
458 if ((crp->crp_flags & CRYPTO_F_IMBUF) != 0) {
459 m_copydata((struct mbuf *)crp->crp_buf,
460 crd->crd_skip + crd->crd_len - 16, 16, ses->ses_iv);
461 } else if ((crp->crp_flags & CRYPTO_F_IOV) != 0) {
462 cuio_copydata((struct uio *)crp->crp_buf,
463 crd->crd_skip + crd->crd_len - 16, 16, ses->ses_iv);
464 } else {
465 bcopy(crp->crp_buf + crd->crd_skip + crd->crd_len - 16,
466 ses->ses_iv, 16);
467 }
468 }
469
470 out:
471 if (buf != NULL) {
472 bzero(buf, crd->crd_len + 16);
473 free(buf, M_DEVBUF);
474 }
475 crp->crp_etype = err;
476 crypto_done(crp);
477 return (err);
478 }
479
480 static int
481 padlock_modevent(module_t mod, int type, void *unused __unused)
482 {
483 int error;
484
485 error = EOPNOTSUPP;
486 switch (type) {
487 case MOD_LOAD:
488 error = padlock_init();
489 break;
490 case MOD_UNLOAD:
491 error = padlock_destroy();
492 break;
493 }
494 return (error);
495 }
496
497 static moduledata_t padlock_mod = {
498 "padlock",
499 padlock_modevent,
500 0
501 };
502 DECLARE_MODULE(padlock, padlock_mod, SI_SUB_DRIVERS, SI_ORDER_ANY);
503 MODULE_VERSION(padlock, 1);
504 MODULE_DEPEND(padlock, crypto, 1, 1, 1);
Cache object: c2acc0e6439895cea69f24d0654a397a
|